Jump to content
43oh

tripwire

Members
  • Content Count

    193
  • Joined

  • Last visited

  • Days Won

    14

Reputation Activity

  1. Like
    tripwire got a reaction from cde in Stupidest Thing you had to Troubleshoot?   
    I used sprintf on CC2650 and it smashed the stack
     
    When I was looking at my code in the debugger the SP was about 2/3 of the way down into the stack, and beyond that the memory all appeared unused. Eventually I spotted a few bytes had been written right at the limit of the stack. Apparently sprintf needs a 510 byte buffer to format the string version of numbers from %d etc. I only wanted to convert a 32 bit value to a hexadecimal string!
     
    I think I was spoiled by MSP430 which defaults to "minimal" (s)printf using a tiny internal formatting buffer. It only breaks the C standard, not the stack limit!
     

    Me too! Sometimes I use the MSP432 or FR5969 launchpads to energytrace another launchpad. When the time comes to reprogram the target I always forget to remove the external VCC/GND jumper wires and reconnect the target to its emulator.
  2. Like
    tripwire got a reaction from zeke in My time with FreeRTOS on the TM4C   
    At the moment the code is using basic DMA transfer mode, which means the CPU has to wake up to prepare the next DMA transfer.
     
    The ARM uDMA also offers ping-pong mode, where it automatically kicks off a second transfer once the first is completed. Meanwhile the CPU wakes up to set the inactive DMA control structure up for the next transfer. This double buffering means the DMA is kept active and doesn't have to wait on the CPU.
     
    Finally there's scatter/gather mode, where the DMA module writes its own control structure(s), allowing up to 256 pre-planned transfers. That one's the most fun
     
     
    I'm curious about that too. I'm wondering why SPI_CLK has pauses between bytes in the latest zoomed in scope trace. What with the TX FIFO and DMA feeding the SSI I'd have hoped the Tiva would manage continuous output at 8MHz.
  3. Like
    tripwire reacted to yyrkoon in Embedded_Printf   
    I would like to point out that there has been extensive talk about printf() on these forums, and there is a version that compiled down into 106 bytes if I remember correctly. Which can grow even more rapidly the more functionality you require.
     
    http://forum.43oh.com/topic/1289-tiny-printf-c-version/
     
    I was rather fond of a version Rickta59 wrote, but I think it was based on the original code from the above post.
  4. Like
    tripwire reacted to agaelema in Embedded_Printf   
    I would like to share with you this library. Is an embedded version of the famous "printf ( )".
    - https://github.com/agaelema/Embedded_Printf
     

     
    The start point was this post in the e2e where an user share a code.
    - http://e2e.ti.com/support/development_tools/code_composer_studio/f/81/p/30479/107146
     
    I modified the code inserting new functions as binary notation, float notation, scientific notation, functions to convert numbers into strings and strings into numbers.
     
    The user can enable some #define enabling/disabling functions to use just what is useful.
     
    This is an resume comparison between the CCS native "printf" and this library (using th Launchpad EXP430FR6989 at 1MHz).
    - http://processors.wiki.ti.com/index.php/Printf_support_for_MSP430_CCSTUDIO_compiler
     

     
    To facilitate the port to other devices there is a separated file. Currently there are two ports: MSP430G2553 and MSP430FR6989.
     
    I hope it is useful.
  5. Like
    tripwire reacted to spirilis in My time with FreeRTOS on the TM4C   
    Turns out that was only part of what I was missing.
     
    Also forgot this piece:
    MAP_uDMAChannelAssign( UDMA_CH13_SSI2TX ); Yeah that might be important.  This configures the UDMACHMAPx registers to assign a particular DMA channel to a particular peripheral trigger that it supports.
     
    Then we get beautiful, tight, SPI output:

     

     
    Note the PF_2 waveform at the bottom, i.e. logic analyzer channel #2.  It transitions up or down every time an IRQ occurs.  Notice how infrequently that is.. relative to the sheer amount of data passing over the wire.  That's the value of DMA.
    In between those IRQ firings, other tasks may run - the SPI gatekeeper task isn't spinning CPU cycles polling the MAP_SSI_Busy() function.  This is implemented by the SPI Gatekeeper task pending on its own task-ISR binary semaphore (which makes the task sleep).  The real "running thread" for SPI I/O is inside dedicated hardware, separate from the Cortex-M4 CPU and separate from FreeRTOS control, that of the UDMA controller itself.
  6. Like
    tripwire reacted to zeke in The Marquee Clock   
    Here's a brief update.
     
    I've been working on the layout for the display board.
     

     
    I rearranged the LEDs so that they could be properly soldered by hand (if that is needed).
     

     
    Now, I must make some design decisions:
    - Should I include an on-board buck power supply on this Alpha design?
    - Should I include an on-board CPU on this Alpha design?
    - Should I include an off-board interface (set of pins) for an off-board CPU daughter board?
     
    To overcome my decision fatigue, I might have to include everything, test it, delete from the design all that doesn't make sense then create a Beta PCB design.
     
    Oh, also, it was a challenge but I managed to procure an adequate supply of LEDs for the prototypes that need to be assembled.

     
    How many do you see here?

     
     
  7. Like
    tripwire got a reaction from abecedarian in MSP430FR5969 standby current 0.4uA is it possible.   
    That's setting all the GPIO ports to output low.
  8. Like
    tripwire reacted to spirilis in My time with FreeRTOS on the TM4C   
    Okay, taking my first crack at uDMA...
     
    I do not have the time to properly document everything in this post, I'll follow up later with each and every decision along with what the datasheet and TivaWare Peripheral Driver Library documentation told me.
     
    For right now, I'll post main.c and explain why I *believe* I DIDN'T see any traffic on the SPI bus-
    /* * main.c */ #include <FreeRTOS.h> #include <task.h> #include <semphr.h> #include <queue.h> #include <stdint.h> #include <stdbool.h> #include "inc/hw_types.h" #include "inc/hw_ints.h" #include "inc/hw_memmap.h" #include "inc/hw_gpio.h" #include "inc/tm4c123gh6pm.h" #include "driverlib/gpio.h" #include "driverlib/pin_map.h" #include "driverlib/rom.h" #include "driverlib/rom_map.h" #include "driverlib/sysctl.h" #include "driverlib/ssi.h" // for SPI #include "driverlib/udma.h" #include <string.h> // for strlen() #include "datastructs.h" // Declaring the space for these inside main() causes corruption, so make them global? spiTaskParams task1_Params, task2_Params; void Task_SPI_Transfer(void *); void Tiva_SPI_DMA_Gatekeeper_Init(void); void Tiva_SPI_DMA_Gatekeeper(void *); int main(void) { MAP_SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN); MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI2); // SSI2 on PB4/PB6/PB7 MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB); // Need this to configure PB for SSI usage MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA); // uDMA controller while (!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_SSI2)) ; while (!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOB)) ; while (!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_UDMA)); // Configure PB4, PB6, PB7 as SSI pins MAP_GPIOPinTypeSSI(GPIO_PORTB_BASE, (GPIO_PIN_4 | GPIO_PIN_6 | GPIO_PIN_7) ); MAP_GPIOPinConfigure(GPIO_PB4_SSI2CLK); MAP_GPIOPinConfigure(GPIO_PB6_SSI2RX); MAP_GPIOPinConfigure(GPIO_PB7_SSI2TX); // Init SSI2 MAP_SSIClockSourceSet(SSI2_BASE, SSI_CLOCK_SYSTEM); // System CPU clock used MAP_SSIConfigSetExpClk(SSI2_BASE, MAP_SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 8000000, 8); // 8MHz SPI, mode 0, 8 bits MAP_SSIEnable(SSI2_BASE); // SPI peripheral is now live. // Configure PF_1, PF_2 for visual feedback of DMA processes MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); while (!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOF)) ; MAP_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1 | GPIO_PIN_2); MAP_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1 | GPIO_PIN_2, 0); // Gatekeeper task request queue xQueueHandle spiGatekeeperRequestQueue; spiGatekeeperRequestQueue = xQueueCreate(4, sizeof(spiRequest_t)); // Up to 4 asynchronously pending SPI requests at a time. task1_Params.spiQueue = spiGatekeeperRequestQueue; task1_Params.str = "The quick brown fox"; task1_Params.delay = 0; xTaskCreate(Task_SPI_Transfer, "Task1", 48, (void *)&task1_Params, 4, NULL); task2_Params.spiQueue = spiGatekeeperRequestQueue; task2_Params.str = "bluehash runs a great forum"; task2_Params.delay = 5; xTaskCreate(Task_SPI_Transfer, "Task2", 48, (void *)&task2_Params, 5, NULL); // Higher priority // Create SPI gatekeeper task Tiva_SPI_DMA_Gatekeeper_Init(); // Initializes uDMA xTaskCreate(Tiva_SPI_DMA_Gatekeeper, "SPI_GK", 64, (void *)spiGatekeeperRequestQueue, 7, NULL); // High priority vTaskStartScheduler(); // Start FreeRTOS! while(1) ; // Shouldn't get here. return 0; } void Task_SPI_Transfer(void *pvParameters) { spiTaskParams *params = (spiTaskParams *)pvParameters; const char *str = params->str; const size_t slen = strlen(str); xQueueHandle spiQ = params->spiQueue; spiRequest_t request; // Don't have it generate a new semaphore with every request - FaultISR() eventually triggers, maybe out of memory? request.complete = xSemaphoreCreateBinary(); while (1) { request.dataout = (const void *)str; request.length = slen; request.datain = NULL; // Send-only SPI request, so datain = NULL to signal no reading required // Submit SPI request to gatekeeper task, blocking if queue full xQueueSendToBack(spiQ, &request, portMAX_DELAY); // Block waiting for request.complete to signal SPI request has been fulfilled xSemaphoreTake(request.complete, portMAX_DELAY); /* If we had other work to do while waiting for our SPI request to be serviced, we could instead use: * if (xSemaphoreTake(request.complete, 0) != pdPASS) { * // ... do work ... * } * * However, keep in mind the SPI gatekeeper task needs CPU cycles to run too, and of particular note is how * its priority is below ours, so we'd be starving it of CPU until we try the xSemaphoreTake with a >0 delay value. * One alternative would be to run the SPI GK at a substantially higher priority (say 7 or 8), but have it Interrupt Driven * where an SSI hardware interrupt would trigger upon completing the current FIFO of SPI data so the high priority * SPI gatekeeper task isn't hogging CPU all the time, as it's spending most of its time waiting on its IRQ synchronization * binary semaphore (there'd be a binary semaphore between the gatekeeper task and its Interrupt Service Routine). */ if (params->delay != 0) { vTaskDelay(params->delay / portTICK_PERIOD_MS); // Task blocks for specified amount of time } } } /* uDMA-enabled Gatekeeper task. There's a lot of pieces to this... */ // DMA Control Structure table must be aligned on 1024-byte boundaries. // #define DMA_MAX_SUPPORTED_CHANNELS defined in datastruct.h volatile uint32_t DMA_Control[4 * DMA_MAX_SUPPORTED_CHANNELS] __attribute__((aligned(1024))); volatile xSemaphoreHandle ssi2_udma_notify; const uint32_t udma_ch13_mask = 1 << 13; void Tiva_SPI_DMA_Gatekeeper_Init(void) { // Init DMA MAP_uDMAEnable(); MAP_uDMAControlBaseSet( (void *) &DMA_Control ); // All writes to DMA_Control happen via driverlib calls // Using channel #13 (SSI2_Tx) MAP_uDMAChannelAttributeEnable( 13, UDMA_ATTR_REQMASK ); // Mask SSI2TX IRQ for uDMA's purposes MAP_uDMAChannelControlSet( (13 | UDMA_PRI_SELECT), (UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_8) ); // Tell SSI to allow DMA MAP_SSIDMAEnable(SSI2_BASE, SSI_DMA_TX); ssi2_udma_notify = xSemaphoreCreateBinary(); MAP_IntEnable(INT_UDMAERR_TM4C123); MAP_IntEnable(INT_SSI2_TM4C123); MAP_IntPrioritySet( INT_UDMAERR_TM4C123, 7 ); // low priority MAP_IntPrioritySet( INT_SSI2_TM4C123, 1 ); // high priority, max supported while using FreeRTOS syscalls } volatile uint8_t periph_irq_toggle; void Tiva_SPI_DMA_Gatekeeper_IRQ_Handler(void) { // This must be registered for SSI2 Tx BaseType_t xHigherPriorityTaskWoken = false; // Visually indicate IRQ (also examinable via logic analyzer for timing) periph_irq_toggle ^= GPIO_PIN_2; MAP_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, periph_irq_toggle); // Check uDMA to see if it's a uDMA request completion that triggered this if (MAP_uDMAIntStatus() & udma_ch13_mask) { MAP_uDMAIntClear(udma_ch13_mask); // Signal ssi2_udma_notify if we're done writing xSemaphoreGiveFromISR( ssi2_udma_notify, &xHigherPriorityTaskWoken ); } portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); } volatile uint32_t _last_udma_error; void Tiva_uDMA_Master_IRQ_Handler(void) { _last_udma_error = MAP_uDMAErrorStatusGet(); if (_last_udma_error) { MAP_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, GPIO_PIN_1); MAP_uDMAErrorStatusClear(); } } volatile bool did_binsem_take_before_udmachanenable_work; void Tiva_SPI_DMA_Gatekeeper(void *pvParameters) { xQueueHandle spiRequestQueue = (xQueueHandle)pvParameters; // Using SSI2 hardcoded for this example, so no need to provide the SSIx_BASE in pvParameters... spiRequest_t currentReq; portBASE_TYPE qRT; // xQueueReceive return value // SSI2 Tx FIFO ingress const volatile void * ssi2_Tx_FIFO_WRITEREG = &SSI2_DR_R; // from tm4c123gh6pm.h while (1) { qRT = xQueueReceive(spiRequestQueue, &currentReq, portMAX_DELAY); // Wait for incoming request // Service request: // Note something we never did implement in previous SPI examples: READING. We won't implement it here either. Exercise for the reader. // Any thorough "gatekeeper task" for a comms peripheral does need to implement everything it can do or reasonably expect the user to want, however. if (pdPASS == qRT) { if (currentReq.dataout != NULL) { // Set up uDMA to begin transfer MAP_uDMAChannelTransferSet( 13, \ UDMA_MODE_BASIC, \ (void *) currentReq.dataout, \ (void *) ssi2_Tx_FIFO_WRITEREG, \ currentReq.length); // Clear semaphore in case it was given by the last IRQ firing if (pdFAIL != xSemaphoreTake(ssi2_udma_notify, 0)) { did_binsem_take_before_udmachanenable_work = true; } else { did_binsem_take_before_udmachanenable_work = false; } MAP_uDMAChannelEnable(13); // BOOM! Off to the races. // Pend on binary semaphore for SSI2Tx IRQ to signal uDMA completion xSemaphoreTake(ssi2_udma_notify, portMAX_DELAY); } // Done; signal binary semaphore currentReq.complete xSemaphoreGive(currentReq.complete); } } } // Stack overflow protection volatile signed char *stackovf_ptrs[8]; void vApplicationStackOverflowHook(TaskHandle_t *pxTask, signed char *pcTaskName) { int i=0; MAP_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, GPIO_PIN_1); for (i=0; i < 8; i++) { if (stackovf_ptrs[i] == NULL || stackovf_ptrs[i] == pcTaskName) { // ensure we record a task only once (return; is important) stackovf_ptrs[i] = pcTaskName; // pointer to task name string, which should be easy to identify in the debugger return; } } } The problem becomes evident when you look at the debugger window:

     
    The uDMA Control Structure format is four 32-bit entries:
    Pointer to Source Address
    Pointer to Destination Address
    Control word (config for this channel)
    Unused
     
    The pointer to dest is in the peripheral space, specifically SSI2_DR (the correct write location for SSI2's TX FIFO).  But look at the source location:
     
    0x000018CC
     
    That's in Flash space.  Guess where uDMA can't touch ... It has no bus access to the Flash memory, only SRAM (and peripherals).  Next up, once I have more time, moving those SPI transfer strings into an in-SRAM memory buffer and trying it again.  This should only require modification of main() (along with a global SRAM buffer) and modifying the pointer provided to the pvParameters->str entry for the Task_SPI_Transfer tasks.
  9. Like
    tripwire reacted to chicken in Serial monitor communication to LCD via I2C cuts out after about 3 seconds   
    I just checked documentation on Energia.nu and it looks like Serial.read does return -1 if there's no input.
     
    With that, you also should add a if(character != -1) around the I2C commands.
  10. Like
    tripwire reacted to spirilis in My time with FreeRTOS on the TM4C   
    Allrighty... got a handle on things here.
     
    Indeed it was insufficient memory, and FreeRTOS's options for investigating these matters is decent enough.
     
    They mostly reside around a hook function you can define (vApplicationStackOverflowHook()) which is required based on the value of #define configCHECK_FOR_STACK_OVERFLOW in your FreeRTOSConfig.h:
     
    ================
    #define configCHECK_FOR_STACK_OVERFLOW (1 or 2)   Executes vApplicationStackOverflowHook( TaskHandle_t *pxTask, signed char *pcTaskName ) - supplied by the user   Method 1 (#define set to 1):   A task's entire execution context is saved onto its stack each time it gets swapped out.  It is likely that this will be the time at which stack usage reaches its peak.  When configCHECK_FOR_STACK_OVERFLOW is set to 1, the kernel checks that the stack pointer remains within the valid stack space after the context has been saved.  The stack overflow hook is called if the stack pointer is found to be outside its valid range.   Method 1 is quick to execute, but can miss stack overflows that occur between context switches.   Method 2 (#define set to 2):   When a task is created, its stack is filled with a known pattern.  Method 2 tests the last valid 20* bytes of the task stack space to verify that this pattern has not been overwritten.  The stack overflow hook function is called if any of the 20 bytes have changed from their expected values.   Method 2 is not as quick to execute as method 1, but is still relatively fast, as only 20 bytes are tested.  Most likely, it will catch all stack overflows; however, it is possible (but highly improbable) that some overflows will be missed.   * - per include/StackMacros.h, it's actually 16 bytes, not 20? ================   My stack size assigned to all 3 tasks was initially 32.  As it turns out, the value needs to be 39 at the minimum (for task1/task2, GK task needs less) to satisfy all tasks' needs.  I'll show you how I discovered (please copy this function all you want):  
    volatile signed char *stackovf_ptrs[8]; void vApplicationStackOverflowHook(TaskHandle_t *pxTask, signed char *pcTaskName) { int i=0; MAP_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, GPIO_PIN_1); // red LED comes on indicating stack overflow for (i=0; i < 8; i++) { if (stackovf_ptrs[i] == NULL || stackovf_ptrs[i] == pcTaskName) { // ensure we record a task only once (return; is important) stackovf_ptrs[i] = pcTaskName; // pointer to task name string, which should be easy to identify in the debugger return; } } } For quick reference, here's what actually happens during context switch with configCHECK_FOR_STACK_SIZE == 1, from FreeRTOS/include/StackMacros.h:
    #if( ( configCHECK_FOR_STACK_OVERFLOW == 1 ) && ( portSTACK_GROWTH < 0 ) ) /* Only the current stack state is to be checked. */ #define taskCHECK_FOR_STACK_OVERFLOW() \ { \ /* Is the currently saved stack pointer within the stack limit? */ \ if( pxCurrentTCB->pxTopOfStack <= pxCurrentTCB->pxStack ) \ { \ vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ } \ } #endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */ and for configCHECK_FOR_STACK_OVERFLOW == 2:
    #if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH < 0 ) ) #define taskCHECK_FOR_STACK_OVERFLOW() \ { \ const uint32_t * const pulStack = ( uint32_t * ) pxCurrentTCB->pxStack; \ const uint32_t ulCheckValue = ( uint32_t ) 0xa5a5a5a5; \ \ if( ( pulStack[ 0 ] != ulCheckValue ) || \ ( pulStack[ 1 ] != ulCheckValue ) || \ ( pulStack[ 2 ] != ulCheckValue ) || \ ( pulStack[ 3 ] != ulCheckValue ) ) \ { \ vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ } \ } #endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */ Method #2 is a stack coloration technique albeit using a single byte, not a pattern, but that's obviously easier to implement (and probably cheaper on CPU) at context-switch time.  I find it odd that Richard's book (the FreeRTOS maintainer) says it requires 20 bytes yet the code clearly only compares four 32-bit integers... so I assume it only needs 16 bytes.
     
    Using method#2, I've set all 3 tasks (task1 The quick brown fox, task2 bluehash runs a great forum, and the Gatekeeper task) to 36 (words), which would be the original value of 32 plus 4 words to account for the required 16-byte (4-word) buffer in the stack coloration:
     
    Debugger showing that all three tasks overran their stack:   Incidentally, despite overrunning their stack, 36 words is enough to make the SPI traffic look correct:   Method #2 for stack analysis is rather nice I would say since it lets you detect stack overrun with a margin of error and correctly ascertain between-context-switch limits.   Using a value of 37 for all 3 of the tasks:  
    All three tasks ran within or over 16 bytes of their stack.
     
    Value 38:

     
    Value 39:

     
    Jumped ahead, the gatekeeper task quit overrunning at 41:

     
    Finally the main SPI transfer tasks quit at 43:

     

     
    So technically the gatekeeper task requires (41-4 =) 37 words of stack space, and client transfer tasks require (43-4 =) 39 words.
     
    Testing that with method #1, which doesn't color the stack and doesn't require a margin... everything looks good.
     
    As a quick tip, when going from configCHECK_FOR_STACK_SIZE 2 to 1, it registered stack violation with sizes 37 and 39 (for GK and transfer tasks).  I forgot to Rebuild Project - thus any time you modify FreeRTOSConfig.h be sure to rebuild the whole project instead of just hitting the build button.  After rebuilding the project it ran cleanly with no red LED (and no entries in stackovf_ptrs).
  11. Like
    tripwire reacted to spirilis in MSP430FR5969 LPM3 stops tick on RTC_B demo   
    For a consistently reliable 2-4 hour alarm that runs in perpetuity, I would recommend basing it on a 1-second periodic tick interrupt.  The problem with using attachScheduledInterrupt is you constantly have to advance the day counter and that may vary based on what month it is (it won't "roll over" properly if you, say, add 1 day to the 30th or 31st, it'll clamp it at 31 if applicable).
     
    Example:
    volatile uint16_t _4hr_ticker = 0; volatile boolean dostuff_every_4hr = false; void flagFourHourTick() { _4hr_ticker++; if (_4hr_ticker >= (4 * 60*60)) { _4hr_ticker = 0; dostuff_every_4hr = true; wakeup(); } and up in setup() perhaps:
    rtc.attachPeriodicInterrupt(1, flagFourHourTick); and your loop() might have a:
    if (dostuff_every_4hr) { // .... }  That flagFourHourTick can be as complicated as you need it to be.  If you do have more complex scheduling needs, the attachPeriodicInterrupt() might run a master function which runs several others which all manage their own counters and flag other stuff (e.g. their own dostuff_every_xx)
    Any one of those can run wakeup() to wake the CPU.  The CPU wakes up once the initial handler function (the one passed to attachPeriodicInterrupt) exits.
  12. Like
    tripwire reacted to veryalive in My F5529 LaunchPad is back from 2 weeks vacation   
    a question ....
     
     
    WHAT IS YOUR 5529 LP BOARD REV ???
     
     
    Rev 1.4 had weird problems with a kind of power switch driven by the emulator side.
     
    I had such problems with the Rev 1.4 board which I resolved by reflashing the EZ FET.   At TI'er on the E2E Forum helped me; this was about 2 years ago.
     
    In Rev 1.5   5529 LP, those power switches were removed....
     
     
    o
  13. Like
    tripwire reacted to pine in My F5529 LaunchPad is back from 2 weeks vacation   
    2 years ago I had a small project using a F5529 LP with TMP006 sensor booster pack, connecting to an OpenWRT router using serial to send data to ti.exosite.com, and also a 16x2 LCD readout.
     
    Last month it suddenly stopped sending data. Trouble shooting confirmed the problem is at the serial part on the LP. The LP also refused being re-programmed during the trouble shooting tests. The F5529, TMP006, and OpenWRT are all confirmed working flawlessly. Another lost feature is the ability to show time on the LCD which it retrieves from exosite everytime data is sent successfully. A nice clock also really.
     
    Today, after two weeks, it suddenly come back to life! Hurray!
     

     

  14. Like
    tripwire reacted to spirilis in My F5529 LaunchPad is back from 2 weeks vacation   
    Weird ... any idea what happened?  Was it exposed to the elements?
     
    Fun fact- I showcased a Lightning Sensor project one time at the NY Maker Faire (@@bluehash got 43oh a table that year), and I stored the board stack inside one of the TI booth's cabinets overnight.  Next day it wouldn't work... eventually figured out condensation got to it and the LFXT crystal in particular wasn't working right.  Soldering iron helped temporarily (touching all the pads I could see), but it wasn't until I got home and hit the FR5969 launchpad with a sustained blast from a heat gun that it resolved itself perfectly.
  15. Like
    tripwire got a reaction from spirilis in MSP430FR5969 standby current 0.4uA is it possible.   
    That's setting all the GPIO ports to output low.
  16. Like
    tripwire reacted to spirilis in My time with FreeRTOS on the TM4C   
    Well, one minor detail I know now:
     
    Instead of using:
    vSemaphoreCreateBinary(request.complete); xSemaphoreTake(request.complete, 0); // Semaphore is "given" by default, must take once so it'll block to create a binary semaphore, the new canonical way is:
    request.complete = xSemaphoreCreateBinary(); which creates the semaphore in a non-given state.  I found this out by source code:
    /** * semphr. h * <pre>vSemaphoreCreateBinary( SemaphoreHandle_t xSemaphore )</pre> * * This old vSemaphoreCreateBinary() macro is now deprecated in favour of the * xSemaphoreCreateBinary() function. Note that binary semaphores created using * the vSemaphoreCreateBinary() macro are created in a state such that the * first call to 'take' the semaphore would pass, whereas binary semaphores * created using xSemaphoreCreateBinary() are created in a state such that the * the semaphore must first be 'given' before it can be 'taken'. edit: forgot a minor detail first time around, the xSemaphoreCreateBinary returns a sem and takes no arguments.
  17. Like
    tripwire reacted to spirilis in MSP430FR5969 standby current 0.4uA is it possible.   
    Definitely remove all the eZFET jumper blocks, though I've mentioned that already...
     
    Energia does initialize the LFXT, on MSP430G2 chips with no LFXT that has resulted in folks coming onto the forum and complaining about a 2 second startup time (drawing a lot of current in the process) since it'll wait up to 2 seconds for the LFXT to be stable.  It should be using the LFXT too in LPM3 modes (e.g. Energia's own sleep(), sleepSeconds() functions)
     
    edit: If you intend to use the eZFET to power the chip, just connect the GND and 3.3V (Vcc) shunts and nothing else.
  18. Like
    tripwire reacted to spirilis in MSP430FR5969 standby current 0.4uA is it possible.   
    How/where are you measuring it?  Could there be parasitic losses from the eZFET section at the top of the launchpad skewing your numbers?  Have the eZFET jumper block shunts all been pulled?
  19. Like
    tripwire reacted to spirilis in My time with FreeRTOS on the TM4C   
    Moving along...
     
    SPI Gatekeeper Task.  To simplify the data structure definitions (important, IMO, because RTOS queues involve sending arbitrary data types of a predetermined length and often that requires creating custom-purpose struct's for different queue usage scenarios) I've extracted the struct's out to datastructs.h:
     
    datastructs.h:
    /* Data structures used by SPI Gatekeeper tasks et al */ #ifndef DATASTRUCTS_H #define DATASTRUCTS_H // Data structure featuring a string and SPI queue handle for arbitrating SPI I/O. typedef struct { xQueueHandle spiQueue; char * str; unsigned int delay; } spiTaskParams; // Data structure which is sent across the SPI gatekeeper task queue typedef struct { xSemaphoreHandle complete; // binary semaphore must be created by client before passing across the queue const void * dataout; void * datain; size_t length; } spiRequest_t; #endif /* DATASTRUCTS_H */ The gatekeeper task-oriented implementation will involve tasks sending the GK task a copy of everything it needs to perform a contiguous SPI "request" on its behalf. (FreeRTOS xQueueSendToFront/Back receives a pointer to the data type but it physically makes a copy of it inside the queue, however any pointers inside the queue will remain unmodified pointing to a certain task's memory space)
     
    Well, almost everything.  I'm not specifying any sort of SPI Chip Select lines in here.  A real production-worthy SPI gatekeeper task should have provisions for toggling GPIO's for SPI Chip Select. (It'd also be nice to implement SPI Read support, with the NULL-or-not-NULL state of datain vs. dataout being the signal which indicates which mode the gatekeeper task is supposed to operate)
     
    Also, this clearly could not function with FreeRTOS+MPU, since tasks have hardware-enforced boundaries on memory space and the GK task needs to be able to view memory belonging to another task.  The "complete" binary mutex in the spiRequest_t could be thought of as a "Client task, don't touch any of your provided buffers until I've given this mutex!" signal.
     
    (note- I haven't looked too deep into FreeRTOS+MPU, it might have a provision for sharing memory among tasks.)
     
    So my first main.c implementation:
    /* * main.c */ #include <FreeRTOS.h> #include <task.h> #include <semphr.h> #include <queue.h> #include <stdint.h> #include <stdbool.h> #include "inc/hw_types.h" #include "inc/hw_ints.h" #include "inc/hw_memmap.h" #include "inc/hw_gpio.h" #include "driverlib/gpio.h" #include "driverlib/pin_map.h" #include "driverlib/rom.h" #include "driverlib/rom_map.h" #include "driverlib/sysctl.h" #include "driverlib/ssi.h" // for SPI #include <string.h> // for strlen() #include "datastructs.h" // Declaring the space for these inside main() causes corruption, so make them global? spiTaskParams task1_Params, task2_Params; void Task_SPI_Transfer(void *); void Tiva_SPI_Gatekeeper(void *); int main(void) { MAP_SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN); MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI2); // SSI2 on PB4/PB6/PB7 MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB); // Need this to configure PB for SSI usage while (!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_SSI2)) ; while (!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOB)) ; // Configure PB4, PB6, PB7 as SSI pins MAP_GPIOPinTypeSSI(GPIO_PORTB_BASE, (GPIO_PIN_4 | GPIO_PIN_6 | GPIO_PIN_7) ); MAP_GPIOPinConfigure(GPIO_PB4_SSI2CLK); MAP_GPIOPinConfigure(GPIO_PB6_SSI2RX); MAP_GPIOPinConfigure(GPIO_PB7_SSI2TX); // Init SSI2 MAP_SSIClockSourceSet(SSI2_BASE, SSI_CLOCK_SYSTEM); // System CPU clock used MAP_SSIConfigSetExpClk(SSI2_BASE, MAP_SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 8000000, 8); // 8MHz SPI, mode 0, 8 bits MAP_SSIEnable(SSI2_BASE); // SPI peripheral is now live. // Gatekeeper task request queue xQueueHandle spiGatekeeperRequestQueue; spiGatekeeperRequestQueue = xQueueCreate(4, sizeof(spiRequest_t)); // Up to 4 asynchronously pending SPI requests at a time. task1_Params.spiQueue = spiGatekeeperRequestQueue; task1_Params.str = "The quick brown fox"; task1_Params.delay = 0; xTaskCreate(Task_SPI_Transfer, "Task1", 32, (void *)&task1_Params, 4, NULL); task2_Params.spiQueue = spiGatekeeperRequestQueue; task2_Params.str = "bluehash runs a great forum"; task2_Params.delay = 5; xTaskCreate(Task_SPI_Transfer, "Task2", 32, (void *)&task2_Params, 5, NULL); // Higher priority // Create SPI gatekeeper task xTaskCreate(Tiva_SPI_Gatekeeper, "SPI_GK", 32, (void *)spiGatekeeperRequestQueue, 2, NULL); // Low priority vTaskStartScheduler(); // Start FreeRTOS! while(1) ; // Shouldn't get here. return 0; } void Task_SPI_Transfer(void *pvParameters) { spiTaskParams *params = (spiTaskParams *)pvParameters; const char *str = params->str; const size_t slen = strlen(str); xQueueHandle spiQ = params->spiQueue; spiRequest_t request; while (1) { vSemaphoreCreateBinary(request.complete); xSemaphoreTake(request.complete, 0); // Semaphore is "given" by default, must take once so it'll block request.dataout = (const void *)str; request.length = slen; request.datain = NULL; // Send-only SPI request, so datain = NULL to signal no reading required // Submit SPI request to gatekeeper task, blocking if queue full xQueueSendToBack(spiQ, &request, portMAX_DELAY); // Block waiting for request.complete to signal SPI request has been fulfilled xSemaphoreTake(request.complete, portMAX_DELAY); /* If we had other work to do while waiting for our SPI request to be serviced, we could instead use: * if (xSemaphoreTake(request.complete, 0) != pdPASS) { * // ... do work ... * } * * However, keep in mind the SPI gatekeeper task needs CPU cycles to run too, and of particular note is how * its priority is below ours, so we'd be starving it of CPU until we try the xSemaphoreTake with a >0 delay value. * One alternative would be to run the SPI GK at a substantially higher priority (say 7 or 8), but have it Interrupt Driven * where an SSI hardware interrupt would trigger upon completing the current FIFO of SPI data so the high priority * SPI gatekeeper task isn't hogging CPU all the time, as it's spending most of its time waiting on its IRQ synchronization * binary semaphore (there'd be a binary semaphore between the gatekeeper task and its Interrupt Service Routine). */ if (params->delay != 0) { vTaskDelay(params->delay / portTICK_PERIOD_MS); // Task blocks for specified amount of time } } } void Tiva_SPI_Gatekeeper(void *pvParameters) { xQueueHandle spiRequestQueue = (xQueueHandle)pvParameters; // Using SSI2 hardcoded for this example, so no need to provide the SSIx_BASE in pvParameters... spiRequest_t currentReq; size_t i = 0; while (1) { xQueueReceive(spiRequestQueue, &currentReq, portMAX_DELAY); // Wait for incoming request // Service request: // Note something we never did implement in previous SPI examples: READING. We won't implement it here either. Exercise for the reader. // Any thorough "gatekeeper task" for a comms peripheral does need to implement everything it can do or reasonably expect the user to want, however. if (currentReq.dataout != NULL) { i = 0; while (i < currentReq.length) { while (MAP_SSIBusy(SSI2_BASE)) ; while (MAP_SSIDataPutNonBlocking(SSI2_BASE, ((const uint8_t *)(currentReq.dataout))[i]) > 0) { i++; if (i >= currentReq.length) { break; } } } } // Done; signal binary semaphore currentReq.complete xSemaphoreGive(currentReq.complete); } } As I soon found out, this didn't run.  What's weird is tracing the code with step-into/etc ... it seemed to run, but if I hit the Play button and left it to its own devices, it always ended up in FaultISR().
     
    I believe what happened was, FreeRTOS was allocating memory every time I did this:
    while (1) { vSemaphoreCreateBinary(request.complete); xSemaphoreTake(request.complete, 0); // Semaphore is "given" by default, must take once so it'll block specifically the vSemaphoreCreateBinary() piece.  Since that happens every time the string-writer (client task) tries to make a request, and it's not exactly "garbage collected" by the RTOS, that will overrun RAM very fast.
     
    Since the binary mutex (simple synchronization primitive often used between ISRs and their software handler tasks, think Swi's in TI-RTOS lingo) is only used by each task once during an iteration of its SPI write attempt, it would make sense to allocate it once and reuse it:
    void Task_SPI_Transfer(void *pvParameters) { spiTaskParams *params = (spiTaskParams *)pvParameters; const char *str = params->str; const size_t slen = strlen(str); xQueueHandle spiQ = params->spiQueue; spiRequest_t request; // Don't have it generate a new semaphore with every request - FaultISR() eventually triggers, maybe out of memory? vSemaphoreCreateBinary(request.complete); xSemaphoreTake(request.complete, 0); // Semaphore is "given" by default, must take once so it'll block while (1) { request.dataout = (const void *)str; request.length = slen; request.datain = NULL; // Send-only SPI request, so datain = NULL to signal no reading required That runs just peachy.
     
    Indeed the SPI output is done contiguously with no overlaps as I found with my logic analyzer.  Here's the first fraction of a millisecond of traffic:

     
    Note the lag between each SPI request.  That's a combination of FreeRTOS context switch lag and managing the queues/mutex operations.  Notably slower overall than the pure-mutex solution from earlier (don't have a waveform handy but IIRC it was buttoned up much tighter).
     
    Something weird is going on that I need to figure out, because while the higher priority task runs at the beginning and the lower priority task runs repetitively afterward, the next run of the high-priority task ("bluehash runs a great forum") results in the lower priority task being perpetually dead:
     

  20. Like
    tripwire reacted to jamjam in New launchpad msp-exp430fr5994 with microSD   
    Looks like TI have launched a new part, 256KB FRAM and 4 UART's a dream for me.
    Is Energia support available at launch? Happy to help out if not.
     
    http://www.ti.com/tool/msp-exp430fr5994
     
    Great news or a very cruel April fool!
     
     
  21. Like
    tripwire reacted to spirilis in Reply comment window resize glitch   
    This glitch only seems to happen when resizing the quick reply comment window at the bottom of a thread...
     
    Confirmed using Chrome (49.0.2623.110 m) on Windows 10.
     

     
    Notice how the page "jump-scrolls" the moment I click & try to drag the resize handle.  Very glitchy-feeling.
  22. Like
    tripwire reacted to bluehash in Reply comment window resize glitch   
    I have this too. I'll look if there is a fix for this. 
  23. Like
    tripwire reacted to spirilis in My time with FreeRTOS on the TM4C   
    So far, a few changes:
     
    1. FreeRTOSConfig.h has a whole lot more options than I had listed, some of which you need in order to use mutexes/queues/etc.  A mutex is just a queue underneath the hood FYI.
    /* Per-Project FreeRTOS Configuration */ /* * Check all the required application specific macros have been defined. * These macros are application specific and (as downloaded) are defined * within FreeRTOSConfig.h. */ // Mandatory #define configMINIMAL_STACK_SIZE 32 // Idle task stack (in 32-bit words) #define configMAX_PRIORITIES 8 // Adjustable but I kept it at 8 for kicks. #define configUSE_PREEMPTION 1 #define configUSE_IDLE_HOOK 0 #define configUSE_TICK_HOOK 0 #define INCLUDE_vTaskPrioritySet 0 #define INCLUDE_uxTaskPriorityGet 0 #define INCLUDE_vTaskDelete 1 #define INCLUDE_vTaskSuspend 1 #define INCLUDE_vTaskDelayUntil 0 #define INCLUDE_vTaskDelay 1 #define configUSE_16_BIT_TICKS 0 // not sure what this is #define configKERNEL_INTERRUPT_PRIORITY (7 << 5) // Lowest priority for RTOS periodic interrupts #define configMAX_SYSCALL_INTERRUPT_PRIORITY (1 << 5) // Leaves IRQ priority 0 for any non-RTOS Real Time interrupts #define configTOTAL_HEAP_SIZE (24 * 1024) // Adjustable - TM4C123 should support at least 24KB heap #define configCPU_CLOCK_HZ 80000000UL // Full 80MHz clock #define configTICK_RATE_HZ 1000 // 1ms SysTick ticker // Optional stuff #define configUSE_MUTEXES 1 // #define configUSE_RECURSIVE_MUTEXES 0 // #define configUSE_COUNTING_SEMAPHORES 0 // #define configUSE_QUEUE_SETS 0 // #define configUSE_TIMERS 0 // #define configUSE_ALTERNATIVE_API 0 // #define configUSE_TRACE_FACILITY 0 // #define configUSE_CO_ROUTINES 0 // #define configUSE_STATS_FORMATTING_FUNCTIONS 0 // #define configUSE_TICKLESS_IDLE 0 // #define configUSE_APPLICATION_TASK_TAG 0 // #define configNUM_THREAD_LOCAL_STORAGE_POINTERS 0 // #define configGENERATE_RUN_TIME_STATS 0 // #define configUSE_NEWLIB_REENTRANT 0 // #define configUSE_TASK_NOTIFICATIONS 0 // #define configUSE_PORT_OPTIMIZED_TASK_SELECTION 0 // #define configCHECK_FOR_STACK_OVERFLOW 0 // #define configIDLE_SHOULD_YIELD 0 // #define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 0 // #define configMAX_TASK_NAME_LEN 0 // #define configTIMER_TASK_STACK_DEPTH 0 // #define configTIMER_TASK_PRIORITY 0 // #define configTIMER_QUEUE_LENGTH 0 // #define INCLUDE_xTimerPendFunctionCall 1 // #define INCLUDE_xTaskGetSchedulerState 1 // #define INCLUDE_xSemaphoreGetMutexHolder 1 // #define INCLUDE_xTaskGetIdleTaskHandle 1 // #define INCLUDE_eTaskGetState 1 // #define INCLUDE_xTaskResumeFromISR 1 // #define INCLUDE_xTaskGetIdleTaskHandle 1 // #define INCLUDE_pcTaskGetTaskName 1 // #define INCLUDE_uxTaskGetStackHighWaterMark 1 // #define INCLUDE_xTaskGetCurrentTaskHandle 1 // #define INCLUDE_xTaskGetSchedulerState 1 // #define INCLUDE_xTimerGetTimerDaemonTaskHandle 1 2. Here's my main.c, doctored up to utilize a mutex:
    /* * main.c */ #include <FreeRTOS.h> #include <task.h> #include <semphr.h> #include <queue.h> #include <stdint.h> #include <stdbool.h> #include "inc/hw_types.h" #include "inc/hw_ints.h" #include "inc/hw_memmap.h" #include "inc/hw_gpio.h" #include "driverlib/gpio.h" #include "driverlib/pin_map.h" #include "driverlib/rom.h" #include "driverlib/rom_map.h" #include "driverlib/sysctl.h" #include "driverlib/ssi.h" // for SPI #include <string.h> // for strlen() // Data structure featuring a string and mutex for arbitrating SPI I/O. typedef struct { xSemaphoreHandle spiMutex; // this is just a pointer FYI. char * str; } spiTaskParams; // Declaring the space for these inside main() causes corruption, so make them global? spiTaskParams task1_Params, task2_Params; void Task_SPI_Transfer(void *); int main(void) { MAP_SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN); MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI2); // SSI2 on PB4/PB6/PB7 MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB); // Need this to configure PB for SSI usage while (!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_SSI2)) ; while (!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOB)) ; // Configure PB4, PB6, PB7 as SSI pins MAP_GPIOPinTypeSSI(GPIO_PORTB_BASE, (GPIO_PIN_4 | GPIO_PIN_6 | GPIO_PIN_7) ); MAP_GPIOPinConfigure(GPIO_PB4_SSI2CLK); MAP_GPIOPinConfigure(GPIO_PB6_SSI2RX); MAP_GPIOPinConfigure(GPIO_PB7_SSI2TX); // Init SSI2 MAP_SSIClockSourceSet(SSI2_BASE, SSI_CLOCK_SYSTEM); // System CPU clock used MAP_SSIConfigSetExpClk(SSI2_BASE, MAP_SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 8000000, 8); // 8MHz SPI, mode 0, 8 bits MAP_SSIEnable(SSI2_BASE); // SPI peripheral is now live. xSemaphoreHandle spiMutex; spiMutex = xSemaphoreCreateMutex(); task1_Params.spiMutex = spiMutex; task1_Params.str = "The quick brown fox"; xTaskCreate(Task_SPI_Transfer, "Task1", 32, (void *)&task1_Params, 4, NULL); task2_Params.spiMutex = spiMutex; task2_Params.str = "bluehash runs a great forum"; xTaskCreate(Task_SPI_Transfer, "Task2", 32, (void *)&task2_Params, 4, NULL); vTaskStartScheduler(); // Start FreeRTOS! while(1) ; // Shouldn't get here. return 0; } void Task_SPI_Transfer(void *pvParameters) { spiTaskParams *params = (spiTaskParams *)pvParameters; const char *str = params->str; const size_t slen = strlen(str); size_t i = 0; xSemaphoreHandle spiMutex = params->spiMutex; while (1) { xSemaphoreTake(spiMutex, portMAX_DELAY); // Suspend this task indefinitely until the mutex is available { // braces not necessary but makes the code between the mutex take/give easy to identify // Wait for SPI peripheral to stop transmitting while (MAP_SSIBusy(SSI2_BASE)) ; // Stuff the FIFO full while (MAP_SSIDataPutNonBlocking(SSI2_BASE, str[i]) > 0) { i++; // Note: do not be tempted to use "str[i++]" in the while() statement for this. It will increment 'i' even if the call fails. if (i >= slen) { i = 0; } } } xSemaphoreGive(spiMutex); } } Quick discussion:
    The pvParameters given to the task is no longer a simple data type - it's now a struct containing 2 members, an xSemaphoreHandle (which is ultimately just a void * pointer that points to a queue structure) and a char * pointer to the string this task will send over SPI.  Since this is a struct, it must have some memory allocated to it.  I've declared the struct's for both tasks global because when I declared them inside main(), the pointers got corrupted!  Not sure why.
     
    In any case, both tasks are receiving separate parameter structures but the spiMutex members are set to the same mutex, so they should be able to exclude one another.
     
    Here's the output, with an interesting observation!
    b l u e h a s h ' r u n s ' a ' g r e a t ' f o r u m b l u e h a s h ' r u n s ' a ' g r e a t ' f o r u m b l u e h a s h ' r u n s ' a ' g r e a t ' f o r u m b l u e h a s h ' r u n s ' a ' g r e a t ' f o r u m b l u e h a s h ' r u n s ' a ' g r e a t ' f o r u m b l u e h a s h ' r u n s ' a ' g r e a t ' f o r u m b l u e h a s h ' r u n s ' a ' g r e a t ' f o r u m b l u e h a s h ' r u n s ' a ' g r e a t ' f o r u m b l u e h a s h ' r u n s ' a ' g r e a t ' f o r u m b l u e h a s h ' r u n s ' a ' g r e a t ' f o r u m b l u e h a s h ' r u n s ' a ' g r e a t ' f o r u m b l u e h a s h ' r u n s ' a ' g r e a t ' f o r u m b l u e h a s h ' r u n s ' a ' g r e a t ' f o r u m b l u e h a s h ' r u n s ' a ' g r e a t ' f o r u m b l u e h a s h ' r u n s ' a ' g r e a t ' f o r u m b l u e h a s h ' r u n s ' a ' g r e a t ' f o r u m b l u e h a s h ' r u n s ' a ' g r e a t ' f o r u m b l u e h a s h ' r u n s ' a ' g r e a t ' f o r u m b l u e h a s h ' r The first task to run (which appears to be task#2) succeeds in holding the mutex continuously for 500ms worth of sampling (RTOS tick is 1ms btw).  Since the take/give is so tight, apparently FreeRTOS isn't bothering to let the other task run.  So an xSemaphoreGive() does not automatically invoke a context switch.
     
    So we're going to make it voluntarily give up control with taskYIELD() ...
    void Task_SPI_Transfer(void *pvParameters) { spiTaskParams *params = (spiTaskParams *)pvParameters; const char *str = params->str; const size_t slen = strlen(str); size_t i = 0; xSemaphoreHandle spiMutex = params->spiMutex; while (1) { xSemaphoreTake(spiMutex, portMAX_DELAY); // Suspend this task indefinitely until the mutex is available { // braces not necessary but makes the code between the mutex take/give easy to identify // Wait for SPI peripheral to stop transmitting while (MAP_SSIBusy(SSI2_BASE)) ; // Stuff the FIFO full while (MAP_SSIDataPutNonBlocking(SSI2_BASE, str[i]) > 0) { i++; // Note: do not be tempted to use "str[i++]" in the while() statement for this. It will increment 'i' even if the call fails. if (i >= slen) { i = 0; } } } xSemaphoreGive(spiMutex); taskYIELD(); } } And here's the output:
    b l u e h a s h ' r u n s T h e ' q u i c k ' b r o ' a ' g r e a t ' f o r u w n ' f o x T h e ' q u i m b l u e h a s h ' r u n c k ' b r o w n ' f o x T s That's odd, the two are stepping on each other pretty quickly.  What gives?
    Oh right.... I'm only holding the semaphore until I've successfully stuffed the SSI hardware FIFO buffer, then giving it up.  That's what.  Notably, the writer task seems to change every 13 bytes consistently.
    Time for a shift in logic.  We want to keep going until i == slen before giving up the mutex:
    void Task_SPI_Transfer(void *pvParameters) { spiTaskParams *params = (spiTaskParams *)pvParameters; const char *str = params->str; const size_t slen = strlen(str); size_t i = 0; xSemaphoreHandle spiMutex = params->spiMutex; while (1) { xSemaphoreTake(spiMutex, portMAX_DELAY); // Suspend this task indefinitely until the mutex is available { // Transmit the whole string before giving up the mutex i = 0; while (i < slen) { // Wait for SPI peripheral to stop transmitting while (MAP_SSIBusy(SSI2_BASE)) ; while (MAP_SSIDataPutNonBlocking(SSI2_BASE, str[i]) > 0) { i++; if (i >= slen) { break; // Quit stuffing FIFO once we're done } } } } xSemaphoreGive(spiMutex); taskYIELD(); } } Now THAT looks correct:
    b l u e h a s h ' r u n s ' a ' g r e a t ' f o r u m T h e ' q u i c k ' b r o w n ' f o x b l u e h a s h ' r u n s ' a ' g r e a t ' f o r u m T h e ' q u i c k ' b r o w n ' f o x b l u e h a s h ' r u n s ' a ' g r e a t ' f o r u m T h e ' q u i c k ' b r o w n ' f o x
  24. Like
    tripwire got a reaction from zeke in My time with FreeRTOS on the TM4C   
    This is where it gets really interesting! Any RTOS can turn out a clean-looking led blinking program. The true test is how it deals with shared resources. I'm looking forward to the next few posts!
  25. Like
    tripwire reacted to jazz in GPIO state when programming with SBW   
    If SBW / JTAG master execute target device RESET (SBW / JTAG command, not related to changing RESET pin state) then all pins (except SBW / JTAG) will have after device RESET state (input without pulling).
     
    SBW / JTAG master also can put target device under SBW / JTAG control and execute target device flashing without RESET command. In this case pin states will be untouched.
×
×
  • Create New...