Bitbanging serial data stream at controlled frequency.

Moderators: TomKerekes, dynomotion

Post Reply
steveastrouk
Posts: 8
Joined: Thu Sep 26, 2019 5:07 pm

Bitbanging serial data stream at controlled frequency.

Post by steveastrouk » Mon Oct 19, 2020 10:47 pm

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

User avatar
TomKerekes
Posts: 2540
Joined: Mon Dec 04, 2017 1:49 am

Re: Bitbanging serial data stream at controlled frequency.

Post by TomKerekes » Tue Oct 20, 2020 5:51 pm

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);
}
Regards,

Tom Kerekes
Dynomotion, Inc.

steveastrouk
Posts: 8
Joined: Thu Sep 26, 2019 5:07 pm

Re: Bitbanging serial data stream at controlled frequency.

Post by steveastrouk » Tue Oct 20, 2020 10:04 pm

Thanks for the ideas Tom ! Yes, I'll get them tried and tested with our scopes.

I really appreciate the help.

Steve

steveastrouk
Posts: 8
Joined: Thu Sep 26, 2019 5:07 pm

Re: Bitbanging serial data stream at controlled frequency.

Post by steveastrouk » Tue Oct 20, 2020 10:39 pm

Can I inject NOP statements using inline assembler with TCC to create delays ?

Steve

User avatar
TomKerekes
Posts: 2540
Joined: Mon Dec 04, 2017 1:49 am

Re: Bitbanging serial data stream at controlled frequency.

Post by TomKerekes » Tue Oct 20, 2020 11:17 pm

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
Regards,

Tom Kerekes
Dynomotion, Inc.

hufster
Posts: 3
Joined: Wed Oct 02, 2019 4:12 am

Re: Bitbanging serial data stream at controlled frequency.

Post by hufster » Fri Jan 08, 2021 3:12 pm

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.

User avatar
TomKerekes
Posts: 2540
Joined: Mon Dec 04, 2017 1:49 am

Re: Bitbanging serial data stream at controlled frequency.

Post by TomKerekes » Fri Jan 08, 2021 4:39 pm

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.
Regards,

Tom Kerekes
Dynomotion, Inc.

Post Reply