Page 1 of 1
Bitbanging serial data stream at controlled frequency.
Posted: Mon Oct 19, 2020 10:47 pm
by steveastrouk
I have a peripheral that we need to run off a Kflop with a serial bitstream at 400kHz (+/-25kHz). I read the bitbanging example SPIv6.C, and see that that is working "full throttle" to deliver 450kHz or so - outside my limit. Is there a timing function to accomplish the fine timing, or a NOP we can use in our code to make one ? My timing is essentially a 2.5 uSec clock, with a 20% on/80% off conveying a zero, and a 40% on /60% off conveying a one. There are 24 "bits" in the sequence, which we only need to transmit about once every 10 seconds.
Thanks
Steve
Re: Bitbanging serial data stream at controlled frequency.
Posted: Tue Oct 20, 2020 5:51 pm
by TomKerekes
Hi Steve,
I'm not sure if you will be able to do this in software. The nice thing about SPI is that clock rate is not critical. What are you interfacing to? Can it tolerate an extended low or high period?
To clock 24 bits @ 400KHz will require 60us of uninterrupted execution time. KFLOP Thread slice times vary from about 40~80us depending on how many Axes are enabled and how they are configured. If your configuration provides less than 60us it won't work without a large (>100us) pause in the clock. There is an example Measure IRQ.c to display the Thread slice times.
I ran the code below that does 10 clocks while also waiting for a specific time. The times are set small so should not wait at all. it printed.
Time = 13.280000
So each clock edge takes 0.664us
400KHz corresponds to 2.5us and 20% of that is only 0.5us. Without any timing check at all it might be close to 0.5us. I removed the waits and it shows:
Time = 6.280000 which would be 0.314us. Maybe add something to add a small fixed delay and verify with an oscope.
Code: Select all
#pragma TI_COMPILER(3)
#include "KMotionDef.h"
#define pMOSI 0
#define pSS 1
#define pMISO 2
#define pSCK 3
void main()
{
double T0,T1;
WaitNextTimeSlice();
T0 = Time_sec();
FPGA(BIT_SET+(pMOSI>>3)) = 1<<(pMOSI&7);
WaitUntil(T0 + 0.1e-6);
FPGA(BIT_CLR+(pMOSI>>3)) = ~(1<<(pMOSI&7));
WaitUntil(T0 + 0.1e-6);
FPGA(BIT_SET+(pMOSI>>3)) = 1<<(pMOSI&7);
WaitUntil(T0 + 0.1e-6);
FPGA(BIT_CLR+(pMOSI>>3)) = ~(1<<(pMOSI&7));
WaitUntil(T0 + 0.1e-6);
FPGA(BIT_SET+(pMOSI>>3)) = 1<<(pMOSI&7);
WaitUntil(T0 + 0.1e-6);
FPGA(BIT_CLR+(pMOSI>>3)) = ~(1<<(pMOSI&7));
WaitUntil(T0 + 0.1e-6);
FPGA(BIT_SET+(pMOSI>>3)) = 1<<(pMOSI&7);
WaitUntil(T0 + 0.1e-6);
FPGA(BIT_CLR+(pMOSI>>3)) = ~(1<<(pMOSI&7));
WaitUntil(T0 + 0.1e-6);
FPGA(BIT_SET+(pMOSI>>3)) = 1<<(pMOSI&7);
WaitUntil(T0 + 0.1e-6);
FPGA(BIT_CLR+(pMOSI>>3)) = ~(1<<(pMOSI&7));
WaitUntil(T0 + 0.1e-6);
FPGA(BIT_SET+(pMOSI>>3)) = 1<<(pMOSI&7);
WaitUntil(T0 + 0.1e-6);
FPGA(BIT_CLR+(pMOSI>>3)) = ~(1<<(pMOSI&7));
WaitUntil(T0 + 0.1e-6);
FPGA(BIT_SET+(pMOSI>>3)) = 1<<(pMOSI&7);
WaitUntil(T0 + 0.1e-6);
FPGA(BIT_CLR+(pMOSI>>3)) = ~(1<<(pMOSI&7));
WaitUntil(T0 + 0.1e-6);
FPGA(BIT_SET+(pMOSI>>3)) = 1<<(pMOSI&7);
WaitUntil(T0 + 0.1e-6);
FPGA(BIT_CLR+(pMOSI>>3)) = ~(1<<(pMOSI&7));
WaitUntil(T0 + 0.1e-6);
FPGA(BIT_SET+(pMOSI>>3)) = 1<<(pMOSI&7);
WaitUntil(T0 + 0.1e-6);
FPGA(BIT_CLR+(pMOSI>>3)) = ~(1<<(pMOSI&7));
WaitUntil(T0 + 0.1e-6);
FPGA(BIT_SET+(pMOSI>>3)) = 1<<(pMOSI&7);
WaitUntil(T0 + 0.1e-6);
FPGA(BIT_CLR+(pMOSI>>3)) = ~(1<<(pMOSI&7));
WaitUntil(T0 + 0.1e-6);
T1 = Time_sec();
printf("Time = %f\n", (T1-T0)*1e6);
}
Here is a possible approach:
Code: Select all
#pragma TI_COMPILER(3)
#include "KMotionDef.h"
#define pSCK 3
void Send(int i);
void main(void)
{
Send(0x555555);
}
void Send(int i)
{
int k;
double T,T0,T1;
WaitNextTimeSlice();
T=Time_sec()+1.0e-6; // set to begin in 1us
T0=Time_sec();
for (k=0x800000; k!=0; k>>=1)
{
WaitUntil(T);
if (i&1)
{
// minimum on time for zero
FPGA(BIT_SET+(pSCK>>3)) = 1<<(pSCK&7);
// add 0.1us delay here
FPGA(BIT_CLR+(pSCK>>3)) = ~(1<<(pSCK&7));
}
else
{
// 40% of 2.5us on
FPGA(BIT_SET+(pSCK>>3)) = 1<<(pSCK&7);
WaitUntil(T0 + 1.0e-6);
FPGA(BIT_CLR+(pSCK>>3)) = ~(1<<(pSCK&7));
}
i>>=1; // shift data right
T+=2.4e-6;
}
T1=Time_sec();
printf("Time = %f\n", (T1-T0)*1e6);
}
Re: Bitbanging serial data stream at controlled frequency.
Posted: Tue Oct 20, 2020 10:04 pm
by steveastrouk
Thanks for the ideas Tom ! Yes, I'll get them tried and tested with our scopes.
I really appreciate the help.
Steve
Re: Bitbanging serial data stream at controlled frequency.
Posted: Tue Oct 20, 2020 10:39 pm
by steveastrouk
Can I inject NOP statements using inline assembler with TCC to create delays ?
Steve
Re: Bitbanging serial data stream at controlled frequency.
Posted: Tue Oct 20, 2020 11:17 pm
by TomKerekes
Hi Steve,
No. But the TI Compiler (as with my example) should accept:
asm(" NOP 9");
where the 9 can be a number 1-9.
HTH
Re: Bitbanging serial data stream at controlled frequency.
Posted: Fri Jan 08, 2021 3:12 pm
by hufster
Hello,
I am trying to use the asm(" NOP 9") command in our c program, but we get Error 109 when we try to add that line of code when we compile.
Also, we are seeing the first high signal take longer than the rest of the signals. After reading the documentation and watching the TI Compiler Optimization video, it looks like we may need to run our program in IRAM. We used :
#pragma CODE_SECTION(main, "IRAM")
Despite this we still can't replicate the consistent first pulse as show in the code example in the video.
Re: Bitbanging serial data stream at controlled frequency.
Posted: Fri Jan 08, 2021 4:39 pm
by TomKerekes
Hi hufster,
What version are you running? There were some issues with mapping code to IRAM. Please try V4.35f and check the .map file to see what memory your code is linked into. Addresses 100xxxxx would be IRAM. Addresses 8xxxxxxx would be SDRAM.