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.

MSP432P4111: Continuous reading from UART using TI Drivers and FreeRTOS

Part Number: MSP432P4111
Other Parts Discussed in Thread: CC3135

Hello,

The setup:

Versions:

- simplelink_msp432p4_sdk_3_30_00_13

- simplelink_sdk_wifi_plugin_2_40_00_22

- FreeRTOSv10.2.1

- CCS  9.0.1.00004 

I have a project that consists of multiple boards communicating with each other using multiprocessor UART.

All of these boards have the MSP432P4111 on them.

FreeRTOS is used as the OS without the posix layer.

Peripherals are used through the driverlib API.

There is 1 main board that sends out various queries to all the other boards sequentially through UART.

Each of the boards are responding through UART one by one.

On the main board (also on the other boards) a DMA channel is used to receive bytes one by one and store it in a StreamBuffer_t (from FreeRTOS)

An interrupt is fired whenever the DMA finishes the 1 byte read.

In this interrupt handler the received byte is sent using the StreamBuffer_t's "xStreamBufferSendFromISR" method, then the DMA is re-enabled with the same settings (to receive 1 byte from UARTRX)

This setup is working fine, without problems.

The problem:

But, I have to add wireless connectivity to it.

I have chosen the CC3135 BOOSTXL board.

By looking at the examples for the MSP432, it seems that they are using the SPI TI Driver to communicate with the CC board.

I have decided to migrate my driverlib implementation to TI Drivers to make the whole application at least a little bit more cross-platform between TI devices, also, I planned on making the application as power efficient as possible using various policies.

My problem is:

As far as I can tell, there is no way to set up UART the way I used it through driverlib:

1. Multiprocessor API is completely missing from TI Drivers implementation

This I have solved by using CS pins to separately enable and open UART on the desired board, then close it when all data exchange is finished.

2. I cant find way to be able to read continuously from UART as I was able to using the DMA, because:

The closest I came is to set up a read callback for UART and prepare it to receive 1 byte and planned to do it every time a byte is received and processed, but the documentation warns that I can not call UART_read() from its own callback function:

* @warning Do not call %UART_read() from its own callback function when in
*  #UART_MODE_CALLBACK.

At this point I don't see how I would be able to achieve the same functionality as it was with UART + DMA (receive a byte, process it, prepare for an other byte <- this all in the interrupt handler)

Now, there is a chance, that I just leave the driverlib implementation as is, and don't touch that EUSCI preipheral in the TI Driver setup, but in the long run, I don't want workarounds, and I also know from experience, that using a peripheral through driverlib AND using the TI Driver's power saving functionality (which I plan to) causes problems.

So, what I need is to achieve the same UART functionality with TI Drivers as I did with driverlib

Any help would be appreciated.

NOTE:

I need to read byte by byte from UART, because various requests and responses are of a different length.

The one by one byte read makes sure, that I always receive everything from all boards into the same buffer that will be handled later without and blocking calls and without any timeout handling.

Thank you,

Akos

  • Hi,

    I have forwarded your question to the team. It will be a few days before they can get back.

    Appreciate your patience.

    Regards

  • Hi Akos,

    If I understand correctly, all you want to know is how to read UART byte by byte using TI drivers. Please confirm. If so, this could be achieved by specifying a size of 1 on the UART_read API in TI drivers.

    Jesu

  • Hello Jesu,

    The answer is yes, but you need to know a little bit of a background, to completely understand my problem.

    I have an application, that uses FreeRTOS.

    This application has a cycle time of 1 ms.

    This application has to receive data from an other device continuously, without knowing the amount of data that is to be received. then every cycle, data (in a custom ring-buffer) is checked for header(s), footer(s) and processed.

    Without TI-Drivers:

    I have set up UART DMA to receive 1 byte to a specific location (custom ring-buffer),

    also, the DMA Completion interrupt was set up, in which I just re-enabled the DMA with the same source address and with the manually incremented destination address.

    I have had to start the read process only once, and from this point all I had to do, was to handle the data that was received (if any) and put into the ring-buffer from the task context.

    With TI-Drivers:

    I planned to achieve the same functionality with UART_read() with the UART being in CALLBACK mode.

    I wanted to call UART_read(ownHandle, &ringBuffer[currentWritePosition], 1U) at the start of the application, then in every callback.

    This would be the perfect solution, since it would work the same way as my previous non TI-Driver implementation, but I have found this comment in UART.h (simplelink_msp432p4_sdk_3_30_00_13)

     *  @warning Do not call %UART_read() from its own callback function when in
     *  #UART_MODE_CALLBACK.

    So, now that I know, that I can not use UART_read() from its own callback, I would need to call UART_read() from the cyclic task that has an 1ms cycle time, which leads to huge data losses while the UART_read() is not called after receiving a byte.

    The real problem why this solution was the best for me, is because, I can not know, that how much data (if any) is being sent by the other device, yet, I have to respond as soon as possible, when a full message is received.

    So this is what I would like to achieve.

    I hope this clears up the background of my question.

    Thank you for the help.

    Akos

  • Hi Akos,

    Why don't you increase buffer size? This is more efficient as you will have more processing time between reads and with an appropriately sized buffer you won't lose any data. Using DMA for 1 byte defeats the purpose of using one in the first place. I agree, for portability it is best to leave the drivers as they are. 

    Jesu

  • Hello Jesu,

    My issue with the increased buffer size is that I don't know how many data I am going to receive in a given time-frame, it can be anything from 0 bytes to 500+ bytes (this is how the device works and unfortunately I can not change it's behavior):

    For example, I set the amount of required data that I wait for with UART_read() to the theoretical maximum ~1000 bytes (I made this number up, just for the sake of the example) during a cycle.

    In the UART callback I set a flag, that data is received so that I can call UART_read() again from my main cycle.

    There are 2 problems with this approach:

    1. There will be cycles, when I wont be able to handle any data, because the device sent only 100 bytes, yet it is already received, but the callback is not called yet, so for the application layer, data is not available. Yet, I would already need to handle the received data and respond to it.

    2. If 1000 bytes are received right after the main cycle ended, all data that I should receive during the call to the callback and between the main cycle start would be lost, because I can only call UART_read() again from a task environment, and not from the callback itself.

    I do understand that using DMA to read byte by byte is sort of defying its purpose, but it solved the problem that I had, I could have done the same thing without DMA using only UART interrupts to. But I cant seem to be able to solve it using TI-Drivers.

    How I solved the problem is that I used data from the protocol header that describes the amount of data that is to be received as payload.

    This now works, but I had to make my own HAL layer (in my case, the layer that handles calls to the TI-Drivers) protocol aware, which I really wanted to avoid. All data handling, parsing and distribution was handled on a functional layer before, while the HAL layer was just simply receiving data and pushed it into a ring-buffer without having to know anything about it (here I mean, that amount that is to be received).

    This solution is basically a workaround, not a real solution for a problem, but it works. So for now I can move on with development, but my question still stands:

    Is there a possibility with TI-Drivers to continuously receive data through UART byte by byte without any external interaction from the application layer (meaning, that there is no need to call UART_read from task context)?

    Or (just an idea), is there a possibility to access TI-Drivers internal buffers? Lets say, I set up UART_read() to wait for 1000 bytes, is there a possibility to check if there is any data received and get that data before the callback is called?

    So, as I stated before, I have already made a workaround, that sort of works (needs a little bit of a polish here and there, but works), so it is not a problem if there is no solution for my question, at this point I just want to know if there is a possibility or not to use TI-Drivers for UART as I described.

    Thank you again,

    Akos

  • Hi Akos,

    What you're asking for is not possible through TI drivers. I'm not sure if not knowing how much data you'll receive is good reason to take this non-standard approach using UART. You should establish some pattern in your data where you have some message terminating character to indicate the end of a complete message. 

    As you discovered, you're free to modify the drivers to get the behavior you want but I believe this is more of a design issue than a lack of a features in TI drivers.

    Jesu

  • Hello Jesu,

    I came to the same conclusion. The protocol that is used wraps the payload with a header-footer, where the header has the size of the payload, so I'll just continue with the approach where I always wait for the exact amount of data. I wont edit the drivers, because one of my plans to move to TI-Drivers was compatibility through MCUs that have simplelink support.

    Anyways, thank you for taking your time and helping me.

    Best regards,

    Akos

**Attention** This is a public forum