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.

FreeRTOS port for C2000 TMS320F28xxx

Other Parts Discussed in Thread: TMS320F28377S, TMS320F28034, TMS320F28035

Hi,

I recently finished my FreeRTOS port to C2000's C28x core.

Developed and tested on TMS320F28377S (LAUNCHXL-F28377S board) and TMS320F28034. Works with and without FPU.

Available on Github: https://github.com/IvanZuy/freertos_c28x

  • Hello IvanZuy,

    I took a quick look - just a comment - the timerISR could be a little more efficient since you don't want to check all the time if that's the first time it was run; keep in mind that is running all the time basically (but you know this already). (context save check)

    I have worked on a port of my own; all of that code is in assembly. I have done a port for the 'C55x family also - that works but I still need to make some edits. That one gets a little trickier since the 'C5x architecture has two stacks you have to deal with.

    But it looks like the port is good - I thought you had to save and restore more registers during the context switching; but maybe I'm wrong.

    Regards,
    John W.
  • Hi John,

    Thanks for feedback.

    Yes, the check for first run is not necessary so I removed it.


    I intentionally didn't do context save/restore in assembly to make compiler do most of the job. As I can see half of the registers is being saved while entering into interrupt and the rest by compiler inserted instruction at the beginning of ISR. That's why in assembly I only have to take care of SP and IEF. I do realize that it's possible for future compiler version to change the way how ISR is being compiled. After testing a while I'll switch to assembly version of context manipulation to avoid dependency on compiler.

  • Hi Ivan,


    I did my own port for FreeRTOS 5.1.1. (2009) but in the end we went with OSless solution so it was not thoroughly tested. As a new project coming along might require one I checked if there were any available ports and I found yours. I did a quick comparison, but the ports handle some things differently.


    I have a couple of questions/suggestions:

    1. Isn't task parameters pointer "pvParameters" passed on XAR4 instead on ACC? The compiler might have changed in this time, but I doubt it.

    2. You can handle FPU and non-FPU version in assembler using assembler preprocessor (e.g. ".if     .TMS320C2800_FPU32 = 1"), thus having only one .asm file.

    3. TI compiler sets FPU rounding mode to nearest (RND32 bit in STF is 1). The way you set task stack you set RND32 to 0. Is this intended?

    4. Does your port support configuration without preemption (configUSE_PREEMPTION=0)?

    I'll probably dig deeper in the following weeks, so I might have a few follow up posts.

  • Hi Mitja,

    1. As I remember my compiler uses ACC for passing "pvParameters" but I'll double check it.
    2. That is exactly what I was looking for. Thank you for hint, I'll switch to single .asm file.
    3. I never worked with TI FPU so I initialized FPU registers to zero just to let task context switching work. If you know how the correct initialization for FPU registers should look like I'll be happy to update port. I definitely need some simple test to be sure that FPU is working correctly.
    4. I haven't tried cooperative mode yet. But I believe it should work with no or little changes.
  • Quick follow up

    I like your idea using INT14 as a timer tick interrupt and for "portYIELD" and "portYIELD_FROM_ISR". I've used INT14 only for timer tick and instead used USER trap for "portYIELD" and "portYIELD_FROM_ISR"

    5. Why do you need to call "vPortYield" on "portYIELD"? You could do the same as for "portYIELD_FROM_ISR", but unconditionaly. You get rid of one call/return pair.
    6. You could probably get rid of "bYield" and test the CpuTimer0Regs.TCR.bit.TIF bit.
    7. Do you think there is a way to disable only INT14 with "portDISABLE_INTERRUPTS"? I have an interrupt in INT2 group, which does not use any RTOS services and I would require as fast response as possible. One could only mask INT3 and higher with "portDISABLE_INTERRUPTS". Obviously "portSET_INTERRUPT_MASK_FROM_ISR" macros should also be defined. Any thoughts on the issue?
  • Thanks for reviewing my work. It really very helpful.

    1. You're right. Compiler uses XAR4 to pass "pvParameters". Fixed.
    2. Fixed.
    3. Also fixed but not tested yet. Will be merged soon.
    4. In TODO list but with low priority.

    5. Looks like this is the leftover from previous version where I was doing more work in vPortYield(). I'll switch to doing "portYIELD_FROM_ISR" unconditionally.

    6. My initial idea was to make port independent on the timer which is being used for context switching. That is why I have "vApplicationSetupTimerInterrupt()" which is defined in user code. "bYield" is the attempt to follow that idea. But unfortunately I couldn't find the way how to get rid of hard coding interrupt number in port code. Since now port can only work with Timer2 I should probably move timer initialization into port code and get rid of "bYield".

    7. This is in my TODO list. Unfortunately TMS320 CPUs have predefined interrupt priorities which makes impossible approach similar to CortexM. Most likely I'll introduce additional configuration parameter to let user define which interrupt groups should be under the control of RTOS.
  • 6. It is in my opinion easier to bind the port to specific timer especially in C2000 as interrupt priorities are fixed. Same goes for Cortex-M3, where RTOS tick is bound to SysTick interrupt and it has fixed priority. Having a Systick and context switch with lowest priority is the common practice in RTOS implementation. So moving the timer initialization and interrupt into port code is also what I've done.

    7. While I agree that having interrupt priorities done in HW makes things a bit easier if you look at C2000 priority scheme and if you consider what the C2000 family is intended for (power conversion) in most cases fixed priorities are set up properly.
    Using INT14 for systick and for task switch enables that even unmasked interrupt can even request task switch. If RTOS was interrupted within critical section, INT14 will remain pending until current interrupt returns and RTOS finishes with critical section. But that is probably the only API you can call from unmasked interrupt. I don't know yet if this is usable at all.

    On the other hand using INT14 only for systick and user interrupt for task switching solves the bYield issue, and you don't even have to check for CpuTimer0Regs.TCR.bit.TIF flag. But user interrupt is not maskable. It worked for me at the time, but now I am not certain which solution is better.
  • Hi IvanZuy,
    Thanks for your contribution.

    I have been using the Piccolo TMS320F28035 to sample 5 ADC ´s channels at 20Khz and processing them implementing a control Loop. It would be very useful to do this under the FreeRtos in order to manage communications keyboard and display with different priorities. But I don't think that using the xQueueSendFromISR to push the data obtained would be a good idea. The micro will be switcing Context every 50uS. What should be the better way to implement this in this DSP?

    Best Regards and thank in advance.
  • Hi Fernando,

    If you need to run real time control loop at 20KHz I don't see any other option besides doing it directly in interrupt context.

    Best regards,

    Ivan