1
votes

I'm programming on a STM32 board and I'm confused on how to use my peripherals : polling, interrupt, DMA, DMA interrupt...

Actually, I coded an UART module which send basics data and it works in polling, interrupt and DMA mode.

But I'd like to be able to send and receive specific frames with variable lengths, for example:


[ START | LGTH | CMD_ID | DATA(LGTH) | CRC ]

I also have sensors and I'd like to interact received DATA in these UART frames with sensors.

So, what I don't understand is:

  • how to program the UART module to work in "frame" mode? (buffer? circular DMA? interrupt? where, when..)

  • when I'm able to send or receive frame with my UART, what is the best way to interact with sensors? (inside a timer interrupt? in a state machine ? with extern variable? ...)

Here is my Libraries tree

In future, the idea is to carry this application in freertos

Thank you!

2
If you have DMA, then the only reason why you would ever use interrupts is when you have hard real-time requirements. Otherwise, avoid them. A circular DMA buffer probably makes most sense for received serial data. You just have to ensure that you read it often enough so that it can never overflow.Lundin
"what is the best way to interact with sensors?" is a very broad question that probably can't be answered. "Best" leads to opinion-based answers.Lundin
UARTs don't work in "frames." They only send characters of some number of data bits, surrounded by a start bit and stop bit. It sounds like you have some higher-level protocol that you'd like to use over the UART link, which is just fine. You just break your frames down into the individual characters that constitute them and send them one by one. On the other end, receive them one by one and decode the packet. Your UART driver can be interrupt-driven, pollling, and/or DMA-driven, depending on your application's needs.Jason R
@Lundin: It's pretty common to still use interrupts in concert with DMA, for instance so you know when a DMA finishes so you can reload its source/destination address registers as needed.Jason R
@Lundin: I just wouldn't agree with a blanket statement to "avoid interrupts." They're used all the time, for good reasons, even in non-hard-real-time systems.Jason R

2 Answers

1
votes

Absolutelly in DMA when it is available.

You have one big (good solution is cyclic) buffer and you just write data from one side. If DMA does not already work, you start the DMA with your buffer.

If DMA works, you just write your data to buffer and you wait DMA transfer complete interrupt.

Later in this interrupt you increase read pointer of buffer (as you sent some data already) and check if any data available to send over DMA. Set memory address to DMA and number of bytes in buffer to send.

Again, when DMA TC IRQ happens, do process again.

There is no support for FRAME, but only in plain bytes. It means you have to "invent" your own frame protocol and use it in app.

Later, when you want to send that FRAME over UART, you have to:

  • Write start byte to buffer
  • Write other header bytes
  • Write actual data
  • Write stop bytes/CRC/whatever
  • Check if DMA does not work, if it does not, start it.

Normally, I use this frame concept:


[START, ADDRESS, CMD, LEN, DATA, CRC, STOP]

  • START: Start byte indicating start of frame
  • ADDRESS: Address of device when multiple devices are in use on bus
  • CMD: Command ID
  • LEN: 2 bytes for data length
  • DATA: Actual data in bytes of variable length
  • CRC: 2 bytes for CRC including: address, cmd, len, data
  • STOP: Stop byte indicating end of frame

This is how I do it in every project where necessary. This does not use CPU to send data, just sets DMA and starts transmission.

From app perspective, you just have to create send_send(data, len) function which will create frame and put it to buffer for transmission.

Buffer size must be big enough to fit your requirements:

  • How much data at particular time (is it continues or a lot of data at small time)
  • UART baudrate

For specific question, ask and maybe I can provide some code examples from my libraries as reference.

0
votes

In this case, where you need to implement that protocol, I would probably use plain interrupts and, in the handler, use a byte-by-byte state-machine to parse the incoming bytes into a frame buffer.

Only when a complete, valid frame has been received is it necessary to signal some semaphore/event and requuest a scheduler run, otherwise, you can handle any protocol error as you require - maybe tx some 'error-repeat' message and reset the state-machine to await the nexx start-of-frame buyte.

If you use DMA for this, then the variable frame-length is going to be awkward and you STILL have to iterate the received data to validate you protocol:(

DMA doesn't sound like a good fit for this, to me...

EDIT: if no preemptive multitasker, then forget about all that semaphore gunge above:) Still, it's easier to check a boolean 'validFrameRx' flag than parse DMA block data.