This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Counting DMA loops - UART to SD Card

Other Parts Discussed in Thread: MSP430F5529

Hi everybody,

I'm working on a project involving the MSP430F5529.

Our goal is to record data incoming with a RS232 link on a UART, and put them in some text files on a SD Card.

Problem is that we use custom baudrates on the RS232 link (1.25Mbps), and that the SD transfer part is quite long because of the FAT management with our driver.

For the acquisition part, we would like to use a DMA to fetch bytes incoming on the UART and store them in a buffer of 4*512B=2048B.

Then, we would transfer 512B blocks from the buffer to the SD Card.

The 2048B buffer size has been defined so that we can have time to transfer 512B blocks without losing any data that should be read by the DMA.

My question is : is there a way to let the DMA write in loops in the 2048B area (DMAxSZ = 2048, Repeated Single Transfer Mode) while counting how many bytes have been put in the buffer, so that I know when a 512B block of the buffer is ready to be transfered?

Thanks for your interest

  • What you (uC firmware) do when 2048 bytes are transferred? Transfer ends and it's done?

  • When 2048B are transferred, it all goes back to the beginning, as long as we have data to record.

    With some drawings, it would be :

    STEP 1:

    RAM
    0.........511 | 512.....1023 | 1024........1535 | 1536......2047 (bytes)
    XXXXX______________________________________ 

    => Nothing to be transferred

    STEP 2 :

    RAM
    0.........511 | 512.....1023 | 1024........1535 | 1536......2047 (bytes)
    XXXXXXXX   YYYY______________________________ 

    => The first block [0.....511] is full and can be transferred to the SD Card, meanwhile the DMA is still writing in the 2048B area

    STEP 3 :

    RAM
    0.........511 | 512.....1023 | 1024........1535 | 1536......2047 (bytes)
    YYY_____________________________XXXXXXXXXXX 

    => Blocks [0....511], [512...1023], [1024....1535] should have been transferred to the SD, the DMA just completed the last block, and is looping on the 2048B area. Thus going back to step 1.

    Basically I want to detect when a 512B is full and ready to be transferred.

  • You cannot automatically trigger an interrupt after a partial execution of the DMA. (The DTC unit of the ADC10 on devices without DMA offered a double-buffering mechanism, triggering an interupt after 1/2 of the transfer)
    You can poll by software the current 'write pointer' of the DMA controller. You may set up a timer to trigger an ISR when a block is expected to be full. Of course this only works if the rate at which dat acomes in is known. Else you'll need to check more often (up to a busy-waiting loop), to not miss the right point.

  • Maxime Alay-Eddine said:
    When 2048B are transferred, it all goes back to the beginning, as long as we have data to record.

    Then there's no big difference between 2048bytes DMA transfer with interrupts each 512bytes and just 512byte DMA transfers using multiple buffers. Two buffers shall be sufficient. So you will save 1KB of memory in addition :D

  • Thank you for your interest!

    @

    => I'm thinking about polling the DMAxSZ value which is decremented after every byte, but it seems that the DMAxDA value is copied in a temporary variable for updates, which isn't accessible.

    I didn't find how to access the Temporary Destination Address (current destination pointer) in the documentation. Do I have to use the DMAxSZ or did I miss something?

    @

    => By multiple buffers, do you mean two DMA channels? Or two different memory areas which would be set in DMAxDA one after each other?

  • Maxime Alay-Eddine said:
    Or two different memory areas which would be set in DMAxDA one after each other?

    Exactly. Swapping two (A/B) buffers. When you got DMA complete IRQ filling buffer A, immediately start new DMA transfer using same channel to (free) B buffer, after that write A buffer into flash same time waiting for B buffer complete and so on. Hopefully flash write is faster than DMA receive :D

  • Maxime Alay-Eddine said:

    Problem is that we use custom baudrates on the RS232 link (1.25Mbps), and that the SD transfer part is quite long because of the FAT management with our driver.

    For the acquisition part, we would like to use a DMA to fetch bytes incoming on the UART and store them in a buffer of 4*512B=2048B.

    Then, we would transfer 512B blocks from the buffer to the SD Card.

    The 2048B buffer size has been defined so that we can have time to transfer 512B blocks without losing any data that should be read by the DMA.

    This can be done without DMA, with UART RX ISR. My MSP430F550x based UART-USB bridge (up to 4 Mbps) is working on this way, without DMA. It is storing data received from UART in circular buffer (2 KB), giving some time at the beginning for USB sending to accelerate.

    http://forum.43oh.com/topic/3350-msp430f550x-based-usb-uart-bridge

  • Maxime Alay-Eddine said:

    => I'm thinking about polling the DMAxSZ value which is decremented after every byte, but it seems that the DMAxDA value is copied in a temporary variable for updates, which isn't accessible.

    I didn't find how to access the Temporary Destination Address (current destination pointer) in the documentation. Do I have to use the DMAxSZ or did I miss something?

    You can play (change) DmaDstAdr (00516h) in DMADT_5 mode, under DMA enabled state. My USB stack is based on this mechanism.

  • Thanks everyone for your help.

    The multiple buffer solution sounds quite cool, but there is a last thing. The whole program turns on a RTOS (embOS). Thus, wouldn't using IRQ be a problem for the system, delaying some periodical tasks?

  • zrno soli said:
    This can be done without DMA

    Yes. Inevitably causing very high CPU load. DMA approach will free some CPU clocks for flash writes and possibly other jobs.

    Maxime Alay-Eddine said:
    The whole program turns on a RTOS (embOS). Thus, wouldn't using IRQ be a problem for the system, delaying some periodical tasks?

    Sure it will. That's why it is better to have one IRQ per buffer of bytes than one IRQ per single byte.

  • Ilmars said:

    Yes. Inevitably causing very high CPU load. DMA approach will free some CPU clocks for flash writes and possibly other jobs.

    I am referring for using DMA on UART RX side, when number of receiving bytes is unknown in in advance. In this case there will not be any advance in using DMA. Been there, tested DMA ISR vs UART RX ISR, and at the end decide to go with UART RX ISR, not DMA.

  • zrno soli said:
    tested DMA ISR vs UART RX ISR, and at the end decide to go with UART RX ISR, not DMA.

    That's because most probably you did not care about CPU load but transmission speed only. I know your application and I would chose same solution as you did. This one is different, especially taking RTOS in account.

  • Thank you so much for your help! I have now a better idea of how to handle the whole process.

    My boss doesn't want me to use any IRQ generated by the DMA in order to keep viable periodical tasks on our RTOS.

    Sounds like I'll have to poll the current address of the DMADestination to know which blocks I can transfer.

  • Maxime Alay-Eddine said:
    My boss doesn't want me to use any IRQ generated by the DMA in order to keep viable periodical tasks on our RTOS.

    How to say...  To poll DMA complete, you shall do it with IRQ's disabled including task scheduling/switching timer IRQ meaning you effectively disable ANY tasks. Is this what your boss want?

  • We use 4 tasks with these periods: 1kHz, 100Hz, 10Hz, 1Hz (decreasing priorities).

    Based on the answers of this topic, my boss said I must use the 1kHz task to poll the DmaDstAdr and transfer every ready 512B block from the 2048B buffer.

    Thus we would keep scheduling/switching timer IRQ, without having DMA IRQ which might interfer with the RTOS.

    Your message sounds like you would rather use DMA IRQ. Would that be really better for the program?

  • Maxime Alay-Eddine said:
    Thus we would keep scheduling/switching timer IRQ, without having DMA IRQ which might interfer with the RTOS.

    Using such [I will not comment to avoid banning here] approach you easily can miss at least 1milisecond of data, at 1.25 Mbps it is 1250 bits :) How's that?

  • Well.. Perhaps your boss did not get idea that DMA IRQ ISR just starts new DMA transfer, put signal in the flashwriter task queue and immediately exit. Most probably it will take less CPU time than task switch itself.

  • Ilmars said:
    Then there's no big difference between 2048bytes DMA transfer with interrupts each 512bytes and just 512byte DMA transfers using multiple buffers.

    Depends on communicaitons peed and CPU load.
    The DMA with multiple interrupts will continue seamlessly, whiel the multiple-DMA approach requires teh filling of a buffer being handled before the next data byte comes in.
    If this is not a problem, then you're right :)

    That's right, if you can't process one buffer before the second is filled, you're in trouble even with 4 buffers. Unless, of course, you know that you will always have a longer gap within one full buffer cycle (e.g. you get 2k bursts with a long delay before the next burst, but want to send the data ASAP and not just after one burs tis complete)

  • Jens-Michael Gross said:
    The DMA with multiple interrupts will continue seamlessly, whiel the multiple-DMA approach requires teh filling of a buffer being handled before the next data byte comes in.

    You talk about "repeated DMA block transfer"? LOL... Now I got it. Crucial error of mine to miss this info in very first post of thread.

    Then yes - polling of DMAxSZ each 1ms for 1.25Mbit means you can miss ~156 bytes which is safe enough to have just 1024byte "circular" DMA buffer for 512byte flash writes. Apologies to boss :D

  • No actually it's more a "Repeated Single Transfer" mode, as we don't know the size of data to record (transmitted byte by byte).

    We just know its baudrate, and we want to store them on a SD Card, for which we have to write 512B blocks of data at once for optimization.

  • Maxime Alay-Eddine said:
    No actually it's more a "Repeated Single Transfer" mode, as we don't know the size of data to record (transmitted byte by byte).

    There's some confusion about the terms to use.

    Single transfer means that all bytes of a transfer block are triggered by a separate trigger (e.g. RXIFG). So yes, your applicaiton is a repeated single transfer.
    However, the 'repeated block' term was referring to automatically repeating the whole operation from beginning when done. In an endless circle. It did not mean block or burst transfer mode.

  • Maxime Alay-Eddine said:
    We use 4 tasks with these periods: 1kHz, 100Hz, 10Hz, 1Hz (decreasing priorities).

    Normally, tasks are either executing or waiting for an event.

    It is rather uncommon (and not very effective) to execute tasks on a scheduled basis. That's the domain of timer ISRs. I don't say it is impossible, but it isn't very effective. And depending on the OS and the scheduling mechanism, and the priority handling and... the outcome can be quite different.

    Personally, I'd put things (as long as they aren't time-consuming) into the time rISR and count a variable for each thread. 1kHz on every ISR call, 100Hz on ever 10th etc.
    I do something similar: on every 1ms tiemr interrupt I update the ms counter and call the task scheduler (for waking up sleeping threads), also, i call the fucniton to update the LED outputs (a thread may set 'LED on for 100ms, then off'). Every 1000th interrupt, I call the function for every 1s execution (if any). Only one timer register needed. Works fine.

    Maxime Alay-Eddine said:
    my boss said I must use the 1kHz task to poll the DmaDstAdr and transfer every ready 512B block from the 2048B buffer.

    Well, depending on your baudrate, you must check the DMA count in less time than it takes minimum to receive 512 bytes. The 1ms interrupt would be good for <4MBd baudrate.
    But you shouldn't perform the write inside the tiemr ISR. You should just wake the SD card write thread and let it do the job. Outside the ISR.

  • Thanks again everybody for your help.

    I implemented a solution based on the answers I got here, and I tested it for low rates (115 200 bauds) with success.

    I have now to try it with the limit of 1,25Mbauds.

    My question has definitely been answered, and this subject can be closed by any moderator.

**Attention** This is a public forum