Jump to content
43oh

spirilis

Members
  • Content Count

    3,399
  • Joined

  • Last visited

  • Days Won

    146

Reputation Activity

  1. Like
    spirilis got a reaction from tripwire in My time with FreeRTOS on the TM4C   
    Elaborating, what I meant was the SSI peripheral may have this as a built-in thing... a quick way to find out may be to test different bitrates.  I have this configured for 8MHz presently but I'll try 500KHz, 1MHz, then 20MHz (I think it can do that).
     
    First, at 8MHz (also it appears it can't do a clean perfect 8MHz since it's dividing binary from 80MHz), the width between bytes is 0.24uS (just checked with the saleae)
     
    Now, 500KHz:

     
    1MHz:

     
    20MHz:

     
    (forget the "f" frequency for those last 2, the Saleae software is making the assumption that the space between bytes is part of the waveform)
     
    The timing between bytes is proportional to the speed, so it's probably a constant # of SPI clock cycles that it uses as a delay.  Unfortunately this does not appear to be configurable.
     
    You can do up to 32-bit SPI comms with this peripheral, which should provide a constant 32-bit waveform, but I would imagine each 32-bit word would then be spaced by a similarly speed-proportionate amount of time.
  2. Like
    spirilis got a reaction from energia in Changing Heap/Stack   
    IIRC it puts stack at top of SRAM so it grows down, while heap begins at start of SRAM and grows up. So I'm not sure they can be "adjusted" per se but it definitely doesn't do stack the default TI way (where stack is an array basically allocated inside the heap).
  3. Like
    spirilis got a reaction from abecedarian in Putting a While Loop within a While Loops   
    Well I don't see anything glaring wrong with the code (edit: other than using float's, although if it doesn't need blistering performance that might still be OK), but I should add if this is MSP430 there's a glitch in the way analogWrite() works where it will do short-cut updates to the PWM registers (without waiting for the period to reset) when you repeatedly analogWrite a port.  The result is glitchy garbage.  What chip (or launchpad) are you using?
  4. Like
    spirilis got a reaction from bluehash in Avnet - Free shipping thru 4/22 or $15 discount on carrier International   
    Email I received:
     
    "It's here - visit Avnet's new digital portal and receive free shipping!"
    ...
    "To help you get started, visit the new site today.  As a token of our appreciation for your continued support and for your business, we're offering free 2 Day Air shipping** on orders placed through April 22nd!
    ...
    **Note: Free 2 Day Air shipping is for orders delivered in North America only.  International orders will receive a $15 discount on preferred shipping carrier.  See details.  Promotion valid April 11 to April 22.  Offer ends 11:59 p.m. April 22, 2016."
     
    (link appears to be http://products.avnet.com/ and I don't see any "code" to redeem the shipping offer.)
  5. Like
    spirilis got a reaction from tripwire in Putting a While Loop within a While Loops   
    what is "++10" or "--10"?  never seen that notation
     
    usually it's += 10 or -= 10
     
    also can you please indent the code correctly?  It's hard to ascertain what right-braces "}" corresponds to which loop the way it's formatted here.
  6. Like
    spirilis reacted to roadrunner84 in Stupidest Thing you had to Troubleshoot?   
    printf and friends are very hungry beasts, for integer to hex string and vice versa I prefer manual conversions.
    const char *const hex = "0123456789ABCDEF"; unsigned long input = 10; char output[9]; char *result = output; for(unsigned int ctr = 28; ctr; ctr -= 4) *result++ = hex[(input >> ctr) & 0xF]; *result = '\0'; something like this.
  7. Like
    spirilis got a reaction from tripwire 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.
  8. Like
    spirilis got a reaction from zeke 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.
  9. Like
    spirilis got a reaction from solipso in My time with FreeRTOS on the TM4C   
    Let's revisit that taskYIELD thing.  So we know if we use taskYIELD, it guarantees a context switch if there's another runnable thread.  But these two tasks are running at the same priority.  What if they weren't?  Perhaps xSemaphoreGive will perform a context switch if the semaphore makes a higher priority task runnable (theoretically this is known as a "priority inversion" when a lower-priority task can lock a higher priority one, so we will experiment to see that xSemaphoreGive does indeed context switch.)
     
    First thing I'll do is add another parameter to the spiTaskParams struct - an unsigned int indicating how many milliseconds to pause between semaphore give and take.  One task will have 0 (no delay), the other (higher priority task) will wait 5ms.
     
    main.c code (showing the new parameter inside spiTaskParams and removal of taskYIELD):
    /* * 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; unsigned int delay; } 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"; task1_Params.delay = 0; xTaskCreate(Task_SPI_Transfer, "Task1", 32, (void *)&task1_Params, 4, NULL); task2_Params.spiMutex = spiMutex; 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 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 { // 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); if (params->delay != 0) { vTaskDelay(params->delay / portTICK_PERIOD_MS); // Suspend for a parameter-specified delay } } } Yep, as suspected.  When xSemaphoreGive runs, if this makes a higher priority task runnable, it will context switch.
     
    Start of program:
    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 T h e ' q u i c k ' b r o w n ' f o x T h e ' q u i c k ' b r o w n ' f o x T h e ' q u i c k ' b r o w n ' f o x T h e ' q u i c k ' b r o w n ' f o x T h e ' q u i c k ' b r o w n ' f o x Somewhere in the middle (every 5ms, in fact; note up above in main() for task2 we used task2_Params.delay = 5, and task2 runs at priority 5 vs. task1 running at priority 4):
    T h e ' q u i c k ' b r o w n ' f o x T h e ' q u i c k ' b r o w n ' f o x T h e ' q u i c k ' b r o w n ' f o x 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 T h e ' q u i c k ' b r o w n ' f o x T h e ' q u i c k ' b r o w n ' f o x You can tell the SSIBusy delays, and the context switches, based on the timing:

  10. Like
    spirilis reacted to energia in CC1310 radio library   
    We do have plans to provide a library for the radio. It will be very similar to the one for the CC110L BoosterPack.
  11. Like
    spirilis got a reaction from lilyhack in Where is Energia Library in Mac   
    For more clarification, the old Stellaris stuff was named by the original company that made it - Luminary Micro - which was acquired by TI.  So Tiva was probably a name to improve its pronunciation (IIRC a former TI'er on here mentioned TI's sales teams had trouble selling it in Asia due to pronunciation) and also introduce the letters "TI" into the product name.
     
    http://investor.ti.com/releasedetail.cfm?ReleaseID=384225
  12. Like
    spirilis reacted to monsonite in New Project with MSP430FR4133 and MSP430i2xxx   
    One month later - and I have the MSP430i2041  running my Simplex code  - reading a strain gauge loadcell and measuring force through the 24bit ADC.
     
    Here's the prototype on a breadboard.   The MSP430i2041 is mounted on the "Schmartboard" carrier, and the 8 pin chip to the left is a 128K x 8 SRAM   - Microchip  23LC1024
     
    The MSP430i2041 has 4 separate 24bit SD-ADC channels with built in programmable gain amplifiers with differential inputs.  Ideal for strain-gauge type sensors - with almost no external components needed for interfacing.
     
    You can have UART to PC and SPI and a couple of LEDs on Port 1, and still have all 8 bits of Port 2  for other purposes  - such as a set of switches, character LCD  etc.
     
    This is a really cheap way of getting a a "Smart"  24bit ADC    - about $2 in volume.
     
     
    The second part of the project is the display controller  - to drive a segment type LCD.  This will use either MSP430FR4133 for segment LCD  or MSP430FR6989  for  full graphic LCD - both of which can be done using Launchpads to act as the target hardware.
     
     
    Here's the photo
     

     
     
     
    Next week the plan is to design a small pcb, in a Boosterpack format - that will allow the MSP430i2041 & SRAM to be added to a  '4133 or '6989 Launchpad.  This will make a more stable integrated unit, and having a quad 24 bit SD-ADC for a Launchpad - has to be useful?? 
  13. Like
    spirilis reacted to JasonP in Is there a way in Energia to access the LPM's?   
    Hello everyone,
     
    I just wanted to post an update on my MSP432 project.  Today after a few hours of messing around trying to get RTC interrupts working properly I gave up.  I did have a calendar based event trigger an interrupt but afterwards I was in no mans land.  All code execution stopped and I wasn't quite sure were I was ending up.  I suppose thats where the power of CCS comes in?  
     
    Anyways, I have seen the comment posted several times "when the processor is in an idle, it automagically enters a low power state".  A few days ago this was the first thing I tried, but it didn't seem to change the power consumption much.  I assumed it was entering LPM0 or LPM1 because during the delay state I was still up around 4.5mA.  After failing miserably with the RTC interrupt I figured I would re-explore this. 
     
    Huge thanks to @@dubnet for posting this
     
     
    The key words in there are long delays.  After I added delay(10000); in each of my loops I saw the current all the way down to 2.5uA!!!!  The trick to get this low of current is to make sure to end Serial if it is used.... Serial.end(); Otherwise I could never get below 1.5mA.  Thank you @@energia for this awesome MT platform!  I can now use interrupt based code with delays() in my loops and achieve my power budget goals. 
     
    I really only wished I had paid more attention to what was right in front of me or someone had spelled it out clearer.  
     
    LONG DELAYS = LOW POWER!
     
    IF YOU HAVE A MULTIPLE SKETCHES, ALL LOOPS MUST DELAY TO ENTER THIS LOW POWER STATE.  A FREE SPINNING LOOP IS NOT IDLE. 
     
     
    Cheers!
  14. Like
    spirilis reacted to veryalive in MSP430-GCC v4.0.1.0 with code composer studio   
    ......    and from the ccs wiki  .....
     
    http://processors.wiki.ti.com/index.php/Compiler_Installation_and_Selection
     
     
    MSP GCC 5.x not seen by CCSMSP GCC compilers have an installation issue with CCS v6.1.2 and earlier where it will not properly register the 5.x msp gcc release. The 4.9 release will properly register and show as an available compiler version.
    In order to fix this issue, save below xml file, MSP430_GNU_5.0.xml, to this location: <ccs>\ccsv6\eclipse\plugins\com.ti.ccstudio.buildDefinitions.GNU_6.1.1.201512151800\resources\buildDefinitions\msp430\
    File:MSP430 GNU 5.0.zip
    Restart CCS.
    From your CCS project, update the compiler on the General tab to point to the new 5.x msp gcc release. Click ok. You should now see both msp gcc compiler versions as available choices.
    The issue will be fixed in CCS 6.1.3 and CCS 6.2
  15. Like
    spirilis got a reaction from tripwire 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.
  16. Like
    spirilis got a reaction from zeke 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).
  17. Like
    spirilis got a reaction from tripwire 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).
  18. Like
    spirilis got a reaction from tripwire 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.
  19. Like
    spirilis got a reaction from tripwire 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.
  20. Like
    spirilis got a reaction from jimpx225 in MSP430FR5969 LPM3 stops tick on RTC_B demo   
    That feature isn't really documented properly so I will add it. I wrote the RTC_B library FYI.
  21. Like
    spirilis got a reaction from energia in Mac address to IP generation   
    Office network isn't running DHCP on their network routers or servers?
    That would seem a little odd to me, but, maybe not totally out of the question depending on what kind of environment your office is.  Our datacenters at work don't have DHCP enabled on any of the production networks, but the corporate desktop & VoIP phone networks use DHCP.
  22. Like
    spirilis reacted to tripwire in MSP430FR5969 standby current 0.4uA is it possible.   
    That's setting all the GPIO ports to output low.
  23. Like
    spirilis got a reaction from pine 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.
  24. Like
    spirilis got a reaction from tripwire 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.
  25. Like
    spirilis got a reaction from tripwire 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.
×
×
  • Create New...