Jump to content
Forum sending old emails Read more... ×
spirilis

My time with FreeRTOS on the TM4C

Recommended Posts

Okay, whatever this problem is, it's an odd one.  The SSI2 IRQ isn't firing.  From what I can gather, the uDMA is doing its thang seeing as the control structure's source address appears to be advanced to the end by the time I pause the debugger and look, but the SSI2 FIFO is empty.  I have the SSI2 peripheral configured to send TX info to the uDMA so I don't know what's wrong.  The uDMA CHIS register is still 0 so maybe that's why the IRQ didn't fire.  But my logic analyzer isn't seeing any change in levels either.

 

So I'm stumped.  I'm sure it's a software issue since my previous example (pre-C++) worked, but, reverse engineering what's happened here is taking some patience.

Share this post


Link to post
Share on other sites

Ahh, but the uDMA control word's XFERMODE was still set to BASIC.  uDMA is supposed to set that to NONE when it's completed.

So it's not completed, but clearly it has advanced?  So maybe the SSI peripheral is frozen... but I'm still not sure what I did wrong there.  More digging

Share this post


Link to post
Share on other sites

Ahhh...

 

From page 965 of the TM4C123GH6PM manual:

15.4 Initialization and Configuration

To enable and initialize the SSI, the following steps are necessary:

... blah blah ...

For each of the frame formats, the SSI is configured using the following steps:

1. Ensure that the SSE bit in the SSICR1 register is clear before making any configuration changes.

The problem here is I was running MAP_SSIEnable(SSI2_BASE) in main() (which sets SSICR1.SSE), but my gatekeeper task does custom reconfiguration of the SSI peripheral for each request to configure which DMA request lines it cares about (TX but only optionally RX), along with what speed & bitrate will be used.  Removing that and doing:

                MAP_SSIEnable(spi_base);
                MAP_uDMAChannelEnable(udma_tx_chan);  // BOOM! Off to the races.
                // Pend on binary semaphore for SSITx IRQ to signal uDMA completion
                xSemaphoreTake(irq_swi_trigger, portMAX_DELAY);
                // Deactivate GPIO CS
                if (do_gpiocs) {
                    MAP_GPIOPinWrite(currentReq.cs_gpio_base, currentReq.cs_gpio_pin, currentReq.cs_gpio_pin);
                }
                MAP_SSIDisable(spi_base);

inside the gatekeeper task's main loop instead solves it.  Only "SSIEnable" the peripheral when we're ready to roll, then disable it after.  Got a working waveform on a TX-only test so far, will test TX/RX later.

 

In my previous (non-C++) example, the SPI speed was never modified by the gatekeeper i.e. the client tasks could never "request" a different speed or bitrate so that was configured before the init function's MAP_SSIEnable() call.  That's what changed here.

Share this post


Link to post
Share on other sites

Loved the edX/UT Austin RTOS & Bluetooth course (mostly about RTOS, one token lab on bluetooth by dipping your toes into the TI NPI protocol for configuring a CC2650 running a special network processor firmware from afar, but not terribly deep into bluetooth or BLE itself)

 

For the most part, RTOS's aren't rocket science (although I guess they are used in a lot of rockets), the main criticism I have is TI's TI-RTOS is a convoluted pain in the ass due to its superstructure being based on that "XDC" stuff which adds layer upon layer upon layer upon layer of crap.  Definitely over-engineered beyond comprehension.  Like anything though, you can live with it if you put enough time in...

 

An RTOS at a high level involves several key features:

 

1. Multiple managed stacks which delineate separate threads of execution (since registers are pushed onto the stack using native instructions, and return addresses also get stored on the stack, the stack is the essence of the logical concept of a "thread").  From here on "task" refers to a thread (which has its own stack and a Task Control Block (TCB) entry in the scheduler's linked list).

 

2. The multiple tasks are switched between in a preemptive manner, not cooperative--cooperative multitasking is possible of course but does not support the "real time" nature of a system, i.e. it does not support guaranteed minimum latency & jitter constraints for specific operations--this preemptive task switching typically involves a timer but can also involve innate operations, e.g. "posting" a semaphore is an event that might make a real-time constrained task eligible for execution thus it should run code that checks whether the scheduler should be executed to preempt the current task which posted the semaphore.  Generally hardware interrupts of some type drive the context switch, that is, the act of "halting" the current thread and finding another thread to execute.

 

3. OS-managed semaphores, the exact data structure is not necessarily provided by the OS but there must be a "post" and "pend" function where, at some point, an attempt to "pend" on a semaphore puts the task doing the pending into a blocked state.  The edX RTOS course had an "OS_Signal" (post) and "OS_Wait" (pend) function which took a pointer to an int32_t, any time the semaphore value went negative, the current task was blocked (in its Task Control Block, we had a field "blocked" which was a pointer to the exact int32_t semaphore that blocked us).  When OS_Signal was run from another running task, if the semaphore became <=0 after incrementing it, a code routine would check all the Task Control Blocks to see if anyone was pending on it, and if so, unblock it & perform a context switch.  Only 1 would be unblocked for any 1 run of OS_Signal, and it was first-come first serve.  There are probably other considerations that needed to be made here.

 

4. Priority system for tasks.  Real-time constraints necessarily requires that certain tasks have precedence over others, such that a scheduler can make a simple and deterministic decision to execute a real-time task exactly when it becomes eligible for execution, to the exclusion of lower-priority tasks without any ambiguity.  A common idiom is that a hardware interrupt might either handle some of the real-time execution itself (interrupts are, in a sense, impromptu "tasks" borrowing the current stack temporarily) but usually it just posts a semaphore that the real-time handler task is waiting on; after the interrupt completes the context switch will be forced right away, ensuring the high-priority now-eligible-for-execution real time task is switched to without any intermission by the previous task that was running before the interrupt occurred.

 

5. A "softer" but typical requirement is that tasks must be able to sleep, that is, become ineligible for execution for some time.  This sleep operation causes immediate preemption (context switch) with a timer in the system maintaining the countdown for each sleeping thread and making it eligible for execution when a sleeping thread's timer reaches 0.  The alternative to such a managed sleep is to busy-wait until the timeslice finishes; this may be satisfactory but it's fundamentally a waste of CPU resources.

 

Beyond this, an RTOS may provide other facilities as needed e.g. File systems, Network drivers, coherent date & time with timezone interpretation, logging, whatever.  The basic RTOS task concept provides a neat platform for assembling more complex software layers and since the semaphore system is used to synchronize tasks in an ad-hoc manner, a variety of complex communication methods can arise e.g. managed FIFO ring buffers, mailboxes & queues, etc.  It's important to logically separate the "core RTOS" features from the "extras and/or fluff" that any particular RTOS solution offers.  FreeRTOS for the most part is a barebones RTOS without the fluff, so that you may implement the fluff from scratch in a manner appropriate to your specific platform.  Obviously there are pros & cons with that approach.

 

An interesting idiom we learned in the edX course is the concept of circular DSP signal buffers.  This is a type of ring buffer where the "head" pointer location is only updated by the producer, e.g. the hardware interrupt collecting ADC data or whatever, and the whole buffer is read by any other tasks as needed.  Sort've a dynamic write-once, read-many concept where the buffer is read in its entirety each time it's "consumed"--as would be the case with many DSP algorithms (FIR, IIR filters et al).  DSP-optimized processors typically include hardware supported circular buffers to make the addressing within these extremely simple, otherwise a number of CPU cycles are expended every time the circular buffer is written to which can affect the amount of CPU time available to process the data.

 

Anyway, lots more to talk about, for now I am diving into CC1310 work to get a personal star network IoT system up and running (now that I have 5 end nodes built + a Raspberry Pi CC1310 hat), but eventually I'd like to tinker with some more FreeRTOS examples for the purpose of this thread.

Share this post


Link to post
Share on other sites

As an addendum, I suspect the MSP430's interrupt features such as the ability to determine return LPM status (__bic_SR_register_on_exit()) and its small size firmly plants the MSP430 in the realm of that which doesn't need an RTOS and where an RTOS is probably not desirable.  Its small size and specific feature sets make it optimal for simpler systems where "real time constraints" are enforced either by peripheral features or by individual interrupts, and the main execution thread is the lowest-priority "idle" task.  The use of volatile variable flags (semaphores if you will) to synchronize features inside your main execution thread can be used to run background post-processing operations off a while() loop inside your main(), after which an LPM mode is entered to save power.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×