cancel
Showing results for 
Search instead for 
Did you mean: 

Generating four synchronised Signals with Timer, PWM, and DMA (XY2-100)

CObri.1
Associate III

Hi everyone,

I'm encountering a problem with PWM generation using timers and DMA on the STM32F723.

I've worked through some examples from ST and Controllerstech, such as this one:
https://controllerstech.com/pwm-with-dma-in-stm32/
I managed to get this example running, but now I need to develop something more advanced.

We want to develop a protocol called XY2-100. Here's a description of the protocol:
https://dvd.ilphotonics.com/Ray-Motion%20-%20galvanometers%20-%201D-2D-3D%20scanners/Motion%20Control%20-%20Optomechanics/Interface%20XY2-100.pdf

The protocol consists of four signals: Clock, ChannelX, ChannelY, Sync.

  • The data of each axis consist of 20-bit words.The first 3 bits are used as a control word(C2-C0).The next 16 bits are data information(D15-D0, offset binary) and the last bit is a parity bit(P, even parity).
  • The clock signal runs at a frequency of 2 MHz.When it goes high,the data bit changes.When it goes low,the data bit is sampled by the deflection system. 
  • The transfer of data is synchronised using a synchronisation signal.The SYNC bit goes high when the first bit can be sent. It remains high for 19 bits and goes low when the parity can be sent.


CObri1_0-1708965451543.png

We would like to generate these signals as efficiently as possible. Thus, I attempted to implement these signals using the same Timer 3. Here's how the "pseudocode" looks:

 

 

	HAL_TIM_PWM_Start_DMA(&htim3, TIM_CHANNEL_1,(uint32_t *)dataClk, 20);
	HAL_TIM_PWM_Start_DMA(&htim3, TIM_CHANNEL_2,(uint32_t *)dataSync, 20);
	HAL_TIM_PWM_Start_DMA(&htim3, TIM_CHANNEL_3,(uint32_t *)dataX, 20);
	HAL_TIM_PWM_Start_DMA(&htim3, TIM_CHANNEL_4,(uint32_t *)dataY, 20);

 

 

Initially, I successfully generated the clock of 2MHz with the following function:

 

 

void startScannerClk(void){
	 TIM3->CCR3 = 27;
	 HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_3);
}

 

 


Then, I attempted to try this function:

 

 

void send_Scanner_CHX(void){
	HAL_TIM_PWM_Start_DMA(&htim3, TIM_CHANNEL_3,(uint32_t *)chx_buf, 32);
	HAL_TIM_PWM_Start_DMA(&htim3, TIM_CHANNEL_4,(uint32_t *)chy_buf, 32);
}

 

 

The chx_buf and chy_buf contain the same data and are initialized like this:

 

 

#define DMA_Scanner_BUFFER_SIZE 50
uint16_t chx_buf[DMA_Scanner_BUFFER_SIZE];
uint16_t chy_buf[DMA_Scanner_BUFFER_SIZE];

 

 

I observed these signals:: red TIM_CHANNEL_3; blue TIM_CHANNEL_4

CObri1_0-1708971007888.png

 

The clock of 20 periods, which is what is stored in chx_buf, works perfectly and the channel_4 generates the same signals but it starts around 2ns later, which would be a problem.

So my questions are:

  1. Is it possible to generate the XY2-100 protocol with timers, PWM_DMA, and synchronization as described in the definition?CObri1_0-1708965451543.png
  2. If yes, do I have to use 4 different timers, or can I use one timer with 4 channels, as I did in my test?
  3. Is there an example of generating more than one signal and synchronizing these signals?
  4. Would it make more sense to "bitbang" the protocol (using all the CPU power)?

Best regards, Corsin

5 REPLIES 5

For serial protocol, why don't you use a peripheral intended for serial protocols, such as SPI and SAI?

JW

Yeah, No

If you want to generate complex patterns, use a pattern buffer with all the pins you want to manipulate synchronously.

Have them on the same GPIO bank, and DMA the patterns to GPIO->BSRR or GPIO->ODR (if all 16 pins on the bank). Use the clock to generate the time base, and use that to trigger the DMA (memory-to-memory)

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Hi @waclawek.jan ,
There is no peripheral which would fit the XY2-100 protocol.
CO

Hi,@Tesla DeLorean 

Thank you for your response.

I've never used a pattern buffer before. Do you have an example in mind that you could share?

Best regards, Corsin

 

 

Hi Corsin,

> There is no peripheral which would fit the XY2-100 protocol.

Why do you think so?

You can use two SPIs clocked from a timer connected externally (wich would generate the "index" pulse) set to 10 bits.

SAI is most probably flexible enough to generate the entire set of signals itself.

The advantage of this solution is, that the SPI/SAI provides the deserialization, so there is significantly less processing needed from the processor.

The drawback is, that there's no ready-made Cube/CubeMX support for these.

JW