Jump to content
43oh

zeke

Members
  • Content Count

    1,782
  • Joined

  • Last visited

  • Days Won

    102

Reputation Activity

  1. Like
    zeke reacted to spirilis in My time with FreeRTOS on the TM4C   
    Wrapping it together, here's our full main.c:
    /* * main.c */ #include <FreeRTOS.h> #include <task.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" void NullTaskFunc(void *); // prototype so we can include it in main while the code is underneath void BlinkMyLED(void *); int main(void) { MAP_SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN); // Prototype for xTaskCreate: // // BaseType_t xTaskCreate( TaskFunction_t pvTaskCode, // const char * const pcName, // uint16_t usStackDepth, // void *pvParameters, // UBaseType_t uxPriority, // TaskHandle_t *pvCreatedTask); if (pdTRUE != xTaskCreate(NullTaskFunc, "Null Task", 32, NULL, 4, NULL)) { while (1) ; // Oh no! Must not have had enough memory to create the task. } // For LED blinky task - initialize GPIO port F and then pin #1 (red) for output: MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); // activate internal bus clocking for GPIO port F while (!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOF)) ; // busy-wait until GPIOF's bus clock is ready MAP_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1); // PF_1 as output // doesn't need too much drive strength as the RGB LEDs on the TM4C123 launchpad are switched via N-type transistors MAP_GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_1, GPIO_STRENGTH_4MA, GPIO_PIN_TYPE_STD); MAP_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, 0); // off by default if (pdTRUE != xTaskCreate(BlinkMyLED, "Blinker", 32, (void *)1, 4, NULL)) { // (void *)1 is our pvParameters for our task func specifying PF_1 while (1) ; // error creating task, out of memory? } vTaskStartScheduler(); // Start FreeRTOS! // Should never get here since the RTOS should never "exit". while(1) ; return 0; } // Our RTOS "task" - does absolute jack squat void NullTaskFunc(void *pvParameters) { while (1) { vTaskDelay(10000); // With this task always delaying, the RTOS Idle Task runs almost all the time. } } // The time-honored blinky. void BlinkMyLED(void *pvParameters) { unsigned int whichLed = (unsigned int)pvParameters; /* While pvParameters is technically a pointer, a pointer is nothing * more than an unsigned integer of size equal to the architecture's * memory address bus width, which is 32-bits in ARM. We're abusing * the parameter then to hold a simple integer value. Could also have * used this as a pointer to a memory location holding the value, but * our method uses less memory. */ const uint8_t whichBit = 1 << whichLed; // TivaWare GPIO calls require the pin# as a binary bitmask, not a simple number. // Alternately, we could have passed the bitmask into pvParameters instead of a simple number. uint8_t currentValue = 0; while (1) { currentValue ^= whichBit; // XOR keeps flipping the bit on / off alternately each time this runs. MAP_GPIOPinWrite(GPIO_PORTF_BASE, whichBit, currentValue); vTaskDelay(125 / portTICK_RATE_MS); // Suspend this task (so others may run) for 125ms or as close as we can get with the current RTOS tick setting. } // No way to kill this blinky task unless another task has an xTaskHandle reference to it and can use vTaskDelete() to purge it. } Built:

     
    Project running:

     
    Video:

     
     
    Saleae Logic16 sample:

  2. Like
    zeke reacted to spirilis in My time with FreeRTOS on the TM4C   
    Just realized I had my clock off by a factor of 2, it should be SYSCTL_SYSDIV_2_5 not SYSCTL_SYSDIV_5.  Updating the examples above...
     
    And now our blinky example...
     
    Building off main.c above, we'll add some GPIO init inside main():
    // For LED blinky task - initialize GPIO port F and then pin #1 (red) for output: MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); // activate internal bus clocking for GPIO port F while (!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOF)) ; // busy-wait until GPIOF's bus clock is ready MAP_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1); // PF_1 as output // doesn't need too much drive strength as the RGB LEDs on the TM4C123 launchpad are switched via N-type transistors MAP_GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_1, GPIO_STRENGTH_4MA, GPIO_PIN_TYPE_STD); MAP_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, 0); // off by default Then, code for an example task (this is outside of main()):
    // The time-honored blinky. void BlinkMyLED(void *pvParameters) { unsigned int whichLed = (unsigned int)pvParameters; /* While pvParameters is technically a pointer, a pointer is nothing * more than an unsigned integer of size equal to the architecture's * memory address bus width, which is 32-bits in ARM. We're abusing * the parameter then to hold a simple integer value. Could also have * used this as a pointer to a memory location holding the value, but * our method uses less memory. */ const uint8_t whichBit = 1 << whichLed; // TivaWare GPIO calls require the pin# as a binary bitmask, not a simple number. // Alternately, we could have passed the bitmask into pvParameters instead of a simple number. uint8_t currentValue = 0; while (1) { currentValue ^= whichBit; // XOR keeps flipping the bit on / off alternately each time this runs. MAP_GPIOPinWrite(GPIO_PORTF_BASE, whichBit, currentValue); vTaskDelay(125 / portTICK_RATE_MS); // Suspend this task (so others may run) for 125ms or as close as we can get with the current RTOS tick setting. } // No way to kill this blinky task unless another task has an xTaskHandle reference to it and can use vTaskDelete() to purge it. } Finally, back inside main(), we'll create our LED blinker task, pointing it to LED #1 (the task is already hardcoded to use GPIO_PORTF_BASE so that's not changeable but in theory, we could run multiple blinker tasks operating on different LEDs):
    if (pdTRUE != xTaskCreate(BlinkMyLED, "Blinker", 32, (void *)1, 4, NULL)) { // (void *)1 is our pvParameters for our task func specifying PF_1 while (1) ; // error creating task, out of memory? }
  3. Like
    zeke reacted to spirilis in My time with FreeRTOS on the TM4C   
    TivaWare examples usually have a lot of #include's.  This looks like a decent minimal list for doing sysctl configuration (e.g. system clock and enabling peripherals) and GPIO:

     
    The TARGET_IS_TM4C123_RB1 #define we put in the project's symbols enables correct use of the MAP_ and ROM_ version of the various driverlib calls.  Proof is in driverlib/rom.h:
    //***************************************************************************** // // Macros for calling ROM functions in the ADC API. // //***************************************************************************** #if defined(TARGET_IS_TM4C123_RA1) || \ defined(TARGET_IS_TM4C123_RA3) || \ defined(TARGET_IS_TM4C123_RB1) || \ defined(TARGET_IS_TM4C123_RB2) || \ defined(TARGET_IS_TM4C129_RA0) || \ defined(TARGET_IS_TM4C129_RA1) || \ defined(TARGET_IS_TM4C129_RA2) #define ROM_ADCSequenceDataGet \ ((int32_t (*)(uint32_t ui32Base, \ uint32_t ui32SequenceNum, \ uint32_t *pui32Buffer))ROM_ADCTABLE[0]) #endif #if defined(TARGET_IS_TM4C123_RA1) || \ defined(TARGET_IS_TM4C123_RA3) || \ defined(TARGET_IS_TM4C123_RB1) || \ defined(TARGET_IS_TM4C123_RB2) || \ defined(TARGET_IS_TM4C129_RA0) || \ defined(TARGET_IS_TM4C129_RA1) || \ defined(TARGET_IS_TM4C129_RA2) #define ROM_ADCIntDisable \ ((void (*)(uint32_t ui32Base, \ uint32_t ui32SequenceNum))ROM_ADCTABLE[1]) #endif rom_map.h wraps those calls in MAP_ prefixes so that if it's discovered that a certain Tiva silicon release had a bug in its ROM driver code, updated TivaWare editions may choose to use a source-compiled version of the driverlib function instead of the ROM_ version.  We'll use MAP_ for all our driverlib calls.  There is one exception IIRC, I think it's IntRegister(), that can never use the ROM version but we aren't going to touch it during this example.
     
    Note that the exact TARGET define, e.g. TARGET_IS_TM4C123_RB1, should actually be doctored to coincide with the exact silicon you're using.  RB2 is the very latest revision as of March 2016, but if you're building this for an earlier release of the Tiva chip, it might be prudent to investigate the actual CPU revision you're running (see the chip's datasheet - should be gleaned from reading the markings on the chip but you can figure this out programmatically) and use the correct TARGET_IS_TM4C123_Rxy setting.  (I actually think mine is older than RB1, but it's not a big problem for this example).  Anyway, the available versions can be found by examining driverlib/rom.h and then look at the Tiva chip's datasheet + errata sheet for more details on versions, bugs, etc.
     
    Here's our original main.c, reworked to use TivaWare just to properly configure the CPU clock:
    /* * main.c */ #include <FreeRTOS.h> #include <task.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" void NullTaskFunc(void *); // prototype so we can include it in main while the code is underneath int main(void) { MAP_SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN); // Prototype for xTaskCreate: // // BaseType_t xTaskCreate( TaskFunction_t pvTaskCode, // const char * const pcName, // uint16_t usStackDepth, // void *pvParameters, // UBaseType_t uxPriority, // TaskHandle_t *pvCreatedTask); if (pdTRUE != xTaskCreate(NullTaskFunc, "Null Task", 32, NULL, 4, NULL)) { while (1) ; // Oh no! Must not have had enough memory to create the task. } vTaskStartScheduler(); // Start FreeRTOS! // Should never get here since the RTOS should never "exit". while(1) ; return 0; } // Our RTOS "task" - does absolute jack squat void NullTaskFunc(void *pvParameters) { while (1) { vTaskDelay(10000); // With this task always delaying, the RTOS Idle Task runs almost all the time. } } This configures the PLL with correct crystal speed, enabling the crystal oscillator, to land us at 80MHz.
     
    Note that in main.c, if you forgot to include stdbool.h, some of the driverlib .h files will complain:

     
    Also, driverlib imports a file called "epi_workaround_ccs.s" which won't compile under GCC, so we should delete it:

     

     
    Now it builds correctly:

     
    Our FreeRTOS project thus far doesn't do anything visibly different from the last time we built it, besides the CPU clock running at the correct frequency, so we'll skip running it for now.  Next, we're going to create another task that blinks an LED, and I'll include logic analyzer output validating the cadence of the blink.
  4. Like
    zeke reacted to spirilis in My time with FreeRTOS on the TM4C   
    Importing TivaWare-
     
    Right-click on the project, go Import > Import... and then File System.  Browse to your TivaWare install (C:\ti\TivaWare_C_Series-2.1.2.111 in my case):

     
    We are going to import the "inc" and "driverlib" directories and this time, we WILL have "Create top level folder" checked:

     
    After inc is imported, go back through the project right-click > Import > Import... file system, TivaWare, and import driverlib, but don't include any of its sub-folders:

     
    At this point you have inc and driverlib:

     
    Now, TivaWare examples typically have you doing #include "inc/tm4c123gh6pm.h" or #include "driverlib/can.h" or whatever.  In order for that to work correctly, our workspace's main directory needs to be in the GNU Compiler's Include path.
     
    Back to our old friend, the Preferences (Alt+Enter or right-click project and hit "Properties"):

     
    Add a new entry, selecting Workspace, then our project's name (nothing underneath):

     
    Hit OK, it fills in the variable path to the project:

     
    And here's our final include directory list:

     
    For the sake of completeness, you COULD do the same thing we did with the FreeRTOS source files - create a "TivaWare" folder under the project, right-click on that and import inc/ and driverlib/ into that folder, then add <project location>/TivaWare to the GNU Compiler Include directory paths instead of the main project folder (or in addition to, since it shouldn't hurt).  That way TivaWare and all its components are compartmentalized into their own folder which can make the project easier to inspect if you add any more TivaWare features to it (usblib, nfclib, etc).  We won't do that for this simple example though.
  5. Like
    zeke reacted to spirilis in My time with FreeRTOS on the TM4C   
    Running the RTOS project:

     
    CCS Debug mode should initialize the ICDI debugger and upload the code, then immediately try running the firmware while breakpointing at main():

     
    Go ahead and hit the play button to continue running (without stepping):

     
    Then after a second or two, try interrupting it to see where it ends up stopped:

     

    And voila, we ended up in the middle of one of its internal cleanup functions spawned off the idle task.  At least we're not off in lala land or FaultISR(), instead we're running a validly configured RTOS.  Now this completes the basic FreeRTOS setup, in the next installment (to be continued soon), I'll import TivaWare's driverlib and start doing something useful.  Note that at this stage, FreeRTOS still thinks it's SysTick'ing off an 80MHz clock (due to our current FreeRTOSConfig.h contents) but it's doing no such thing because the CPU is running at the default power-on speed, which is something like 16MHz or 4MHz or whatever.  So all vTaskDelay's are woefully inaccurate right now.  This will be remedied once we use TivaWare driverlib to configure the main clock.
  6. Like
    zeke reacted to spirilis in My time with FreeRTOS on the TM4C   
    To get FreeRTOS into a state where we can compile it, a "FreeRTOSConfig.h" file is required and it looks for it.  We'll create it inside the FreeRTOS/include folder just since we have that folder in our include path already:
     

     
    A reasonable minimum FreeRTOSConfig.h file should include:
    /* 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. */ #define configMINIMAL_STACK_SIZE 128 // 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 (8 * 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 After writing that out to FreeRTOS/include/FreeRTOSConfig.h, let's try a mock build:

     
    With any luck, it'll build cleanly.  It won't do anything of course since our main() has no references to FreeRTOS but at least the FreeRTOS source files themselves build cleanly with our current configuration.
  7. Like
    zeke reacted to spirilis in My time with FreeRTOS on the TM4C   
    With FreeRTOS in our project, we need to make sure the C/C++ compiler is configured to properly search the include and portable folders since FreeRTOS (and our project, soon) depend on it.
     
    First, right-click on the project name and go to Properties (Alt+Enter is the shortcut).  In CCS Build > GNU Compiler, let's have a look at the Directories:

     
    By default the only folder searched for #include's is the toolchain's own include directory.  Let's add the FreeRTOS stuff (click the document icon with green plus sign, then click the "Workspace" button on the new popup):

     
    With our workspace's FreeRTOS/include folder selected, hit OK to commit it to the listing.

     
    Then let's add the portable/GCC/ARM_CM4F folder (portmacro.h needs to be in the search path too):

     
    While we're in here, there's a few GCC options we're going to tune.
     
    In the GNU Compiler > Optimization section... Optimize for space rather than speed, ensure the "Place each function into its own section" and "Place data items into their own section" is checked (it was by default for me), then for kicks add "Convert floating point constants to single-precision constants" since our Cortex-M4F only has hardware support for single-precision float's anyhow:

     
    Under GNU Compiler > Symbols, these are project-wide #define's that will automatically be defined for each source file as it's built.  While FreeRTOS doesn't need any of these, we will need these 2 new symbols later when we try using the TivaWare driver libraries:

    "gcc" is required to make TivaWare's SysCtlDelay() compile and TARGET_IS_TM4C123_RB1 enables us access to the ROM version of the various TivaWare driverlib calls.  We will get to TivaWare later, but while we're in here it's good to add the symbols ahead of time.
     
    Under GNU Linker > Basic, we will enable "garbage collection" for unused sections:

     
    This, in combination with the "Place each function" and "Place data items" into their own section parameter, will substantially reduce the size of our compiled firmware to only include that which is truly needed.
     
    The compiler and linker internally produce a tree of symbol links and references, from the ResetISR and main() on down - any functions or data symbols specifically called out or referenced by the code (and referenced by code referenced by that, etc) or linker script will be included in the final code output, and anything not referenced will be "garbage collected" so it doesn't end up in the final firmware binary.
  8. Like
    zeke reacted to spirilis in My time with FreeRTOS on the TM4C   
    Picking this forum for a blog thread on learning the "ropes" of FreeRTOS.  TM4C123 launchpad is my learning board for now, using CCSv6 under Windows, latest FreeRTOS and the GNU GCC compiler that ships with CCS (Linaro).
     
    From a fresh download of FreeRTOS, I finally have a working example (not relying on "importing" a CCS example and modifying it - you learn more this way).  Here's main.cpp with all the init + task code:
    /* * main.c */ #include <FreeRTOS.h> #include <task.h> #include <timers.h> #include <stdint.h> #include <stdbool.h> #include "inc/hw_memmap.h" #include "inc/hw_types.h" #include "inc/hw_ints.h" #include "inc/hw_gpio.h" #include "driverlib/gpio.h" #include "driverlib/interrupt.h" #include "driverlib/pin_map.h" #include "driverlib/rom.h" #include "driverlib/rom_map.h" #include "driverlib/sysctl.h" void UsrSW1_Monitor(void *); int main(void) { MAP_SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN); MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); while (!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOF)) ; MAP_GPIOPinTypeGPIOInput(GPIO_PORTF_BASE, GPIO_PIN_0 | GPIO_PIN_4); MAP_GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_0 | GPIO_PIN_4, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU); MAP_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3); MAP_GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3, GPIO_STRENGTH_4MA, GPIO_PIN_TYPE_STD); if (pdTRUE != xTaskCreate(UsrSW1_Monitor, "Pushbutton_Monitor", 48, NULL, 3, NULL)) { // Crash due to insufficient heap memory? MAP_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3, GPIO_PIN_1 | GPIO_PIN_2); // Illuminate R+B for purple while(1) ; } //xTaskCreate(NullTask, "Nothing", 48, (void *)1, 4, NULL); vTaskStartScheduler(); // If FreeRTOS ever exits, illuminate orange (R+G) MAP_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3, GPIO_PIN_1 | GPIO_PIN_3); while(1) ; return 0; } void BlinkyTask_LEDBlink(void *pvParams) { unsigned int whichLed = (unsigned int)pvParams; uint8_t whichBit = 1 << whichLed; uint8_t currentValue = 0; while (1) { currentValue ^= whichBit; MAP_GPIOPinWrite(GPIO_PORTF_BASE, whichBit, currentValue); vTaskDelay(250 / portTICK_RATE_MS); } } void UsrSW1_Monitor(void *pvParams) { uint16_t inputShifter = 0; bool inputLatched = false; const uint32_t USR_SW1 = GPIO_PIN_4; // PF4 uint8_t whichLed = 1; xTaskHandle blinkerTask; // Start blinker task with current whichLed value. if (pdTRUE != xTaskCreate(BlinkyTask_LEDBlink, "Blinker", 32, (void*)whichLed, 4, &blinkerTask)) { // Crash due to insufficient heap memory? Halt scheduler and hold all RGB LEDs to white. vTaskSuspendAll(); MAP_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3); while(1) ; } while (1) { // Poll USR_SW1 GPIO - active LOW if (MAP_GPIOPinRead(GPIO_PORTF_BASE, USR_SW1)) { inputShifter <<= 1; } else { inputShifter <<= 1; inputShifter |= 1; } // Test if button has been pressed or released if ( !inputLatched && (inputShifter & 0xF0) == 0xF0 ) { // Rotate LED whichLed++; if (whichLed > 3) { whichLed = 1; } // Kill blinker task vTaskDelete(blinkerTask); // Switch off all LEDs MAP_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3, 0); // Start new blinker task with new whichLed value. if (pdTRUE != xTaskCreate(BlinkyTask_LEDBlink, "Blinker", 32, (void*)whichLed, 4, &blinkerTask)) { // Crash due to insufficient heap memory? Halt scheduler and hold all RGB LEDs to white. vTaskSuspendAll(); MAP_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3); while(1) ; } // Latch button press so we don't re-trigger until button has been released inputLatched = true; } if ( inputLatched && (inputShifter & 0xFF) == 0 ) { inputLatched = false; // un-latch USR_SW1 } // Wait 10ms before checking again vTaskDelay(10 / portTICK_RATE_MS); } } Result: Red LED blinks, left pushbutton toggles to blue & green and back to red.  Pressing & holding the pushbutton switches the LED but only once, as the pushbutton task "latches" it.
     
    The technique of debouncing a pushbutton using periodic polling + bit shifts and logic tests was something I saw on hackaday recently - http://hackaday.com/2015/12/10/embed-with-elliot-debounce-your-noisy-buttons-part-ii/
    I didn't use the same test values but it doesn't matter...
     
    Using polling instead of interrupt for the pushbutton is definitely one of those things that is easy & practical only if using an RTOS.
  9. Like
    zeke reacted to spirilis in My time with FreeRTOS on the TM4C   
    Ok, diversion into a small project.  Getting FreeRTOS working in CCS on a TM4C123 LaunchPad from ground zero.  With screenshots.  More of a noob guide or hand-holding for folks using CCS who want to get started quickly.
     
    Step 1: Create a new CCS project using the GNU GCC compiler.  Ours is called "rtosnull"

     
    With the project created, we are now going to import FreeRTOS first.  Right-click on the project, and make a New folder:

     
    Call it "FreeRTOS".  Now we'll import the necessary FreeRTOS files into this folder:
     
    Right-click on the new FreeRTOS folder, then go Import > Import...

     
    Use Import from File System:

     
    Navigate to your unzipped copy of the latest FreeRTOS source code:

     
    Selecting "Source" and hit OK, you can now peruse the directory structure and choose which files you want to import.  Supposedly "co-routines" aren't used much and we don't need readme.txt, so deselect them.  It's not a problem if you include them though.  On the left side, underneath Source, be sure the entire "include" directory is selected - although you can go in there and uncheck the croutine.h file too.  Or not, it won't hurt anything.

     
    Expand "Source" on the left pane though, and start walking the directory structure down.  In particular we need to choose which of the "portable" folder contents we want - the Memory Manager (Source / portable / MemMang) and the main "port" (Source / portable / GCC / ARM_CM4F in our case).  Within MemMang we're going to select heap_2.c which is a reasonable malloc/free manager for our purposes:

     
    Underneath Source / portable / GCC, go into ARM_CM4F and choose everything (it's only 2 files):

     
    Make sure to UN-CHECK the "Create top-level folder" option in this window, then hit Finish to import all your FreeRTOS files.
     
    The FreeRTOS files should now be in your project under that FreeRTOS directory:

  10. Like
    zeke reacted to yyrkoon in I'm struggling with the CC3200   
    So i guess the big question about this whole situation, would be. What is the driver situation on the FreeRTOS side of things ? IS there an actual SDK like with the AM335x processors, or         . . . ?
  11. Like
    zeke reacted to spirilis in I'm struggling with the CC3200   
    On this subject - I admit I am not sure why someone would use a CC3200 either.  I don't find it particularly attractive.  Its MCU is a jack-of-few-trades-master-of-absolutely-none Cortex-M4 implementation, the analog integration sucks (see @@Rei Vilo 's complaints about the ADC's max voltage and burning out I/O pins), its memory implementation is an odd mix of MCU addressable memory (SRAM) and non-addressable flash (external Serial SPI flash) unlike other MCUs with on-board flash... I don't like it.  I do use the CC3100 from time to time even though it's expensive but that's because frankly I think it's a better chip than the ESP8266 in that it has firmware-built-in webserver, mDNS, SSL (server-socket or client-socket).  The CC3200 is basically "oh, I don't need much, just something functional as a basic MCU so I don't need to pull another one in to connect to the CC3100 which is the whole point of what I'm after".  It is expensive though.  Not a big deal for one-off projects.
     
    Or maybe I should say, ESP8266 changed the game by making cheap MCU WiFi possible *at all*, and now that pandora's box is open, the entire market sentiment has shifted.  Bear in mind before TI's CC3xxx series, the only options were things like Wiznet's WiFi which had a group buy here ... and IIRC the per-chip price was something like $25 or $35 right?  So TI's CC3100/3200 is best viewed as a (superior featured) contender stuck in the paradigm of >$20 wifi MCU modules right at the cusp of ESP8266's disruptive onslaught.  So now with the upcoming ESP32 leapfrogging all the competing vendors' next step, it'll be interesting to see how TI responds.
  12. Like
    zeke reacted to Rei Vilo in I'm struggling with the CC3200   
    I hope Espressif is going to improved the documentation dramatically for the ESP32.
     
    I gave up the ESP8266 because of the lack of documentation, until makers provided it at ESP8266.com. 
     
    I'm using both the ESP8266 and the CC3200/CC3100 (CC3100 mostly). ESP8266 requires more power and connection is less stable. I really like the functions provided in ROM for the CC3200/CC3100, and the clear documentation.
     
    Now, what is going to be response from TI to the ESP32?
  13. Like
    zeke reacted to spirilis in I'm struggling with the CC3200   
    Varies.  FreeRTOS doesn't exactly provide drivers for a chip's peripherals, what they do provide are validated "ports" for various processors (in the Demo section and Source/portable sections of their download).  This provides the "portable" sections that target a particular arch, which includes the Scheduling, Interrupt handling and Memory Management primitives.  The vendor might provide drivers though.  TI does seem to have an "osi" abstraction library for use with their CC3200 and possibly others which intends to provide RTOS-or-non-RTOS agnostic abstraction of certain functions, but I don't know a whole lot about it.  I do know BLE-Stack uses it for the CC26xx devices (even the older CC2540 8051-based BLE chip used it in its code).
     
    For TI Hercules, HALCoGen provides the drivers for you as a customizable driverlib.
     
    So it varies.  The FreeRTOS folks don't take on this responsibility themselves though.
  14. Like
    zeke got a reaction from yyrkoon in I'm struggling with the CC3200   
    @@yyrkoon
     
    You're not derailing the conversation at all!  Keep it up!
     
    From my point of view, there's little reason to develop a commercial product based upon the esp8266 because it is a risky product. 
     
    The esp8266 suffers from supply chain risk.
     
    The CC3200 does not suffer from supply chain risk.
  15. Like
    zeke reacted to yyrkoon in I'm struggling with the CC3200   
    @@spirilis
     
    I've actually watched and read all the material available on TI-RTOS back before that is what it was called. It was called SYS/BIOS, which now i guess that is in reference to the kernel. But at that point it seemed like a really cool thing, and I really wanted to use it - Just never got around to it. Now days, knowing what I know, I have a hard time imagining any situation where I would need an RTOS period. But I would like to pick apart an RTOS to see how one is built, and what possible advantage one could offer over a good tight event loop.
     
    EDIT:
     
    Also, I'm wondering why I would even bother with one of these CC32xx boards. Here, I'm not looking for an argument, but discussion as to why these boards, and processor being so expensive. Why are they worth our money, time, and effort. When there are other more affordable options out there. For instance, TI sent me an email today, or yesterday, using an CC32xx. But this board was a reference board for UART to WIFI bridge . . . So why would i use on of these in that situation when I can just use an ESP8266 for less than 2 bux ?
     
    Oh and @@zeke if you feel I'm derailing your discussion here, I do not mind starting my own topic, but figured I'd ask here since it's semi relevant.
  16. Like
    zeke reacted to spirilis in I'm struggling with the CC3200   
    @@zeke I'm over halfway through the standard Cortex-M3 book (printed out), which is similar to my RX600 copy I bought years ago... It's a fairly light introduction to the RTOS features and some of the gotchas, actually quite concise for an intro I think.
     
    Perusing the prerelease of the Mastering the FreeRTOS Real Time Kernel book - it's a rewrite of the prior book's generic version but with what appears to be more conceptual depth.  Also a new feature "Event Groups" I don't think was covered by the prior book (although I'm not all the way through it yet, maybe it was).  Kinda nice seeing a walkthrough on how to get a new project started - either from an existing demo (i.e. what you should remove), or from scratch with the source files (and what each source file is for).
  17. Like
    zeke reacted to spirilis in I'm struggling with the CC3200   
    Also in general RTOS terms, while TI-RTOS and FreeRTOS appear to be the only ones supported by TI's examples for the CC3200, there are others out there that are probably more general purpose (not necessarily sporting CC3200 ports but potentially portable)... Micrium makes an expensive but well-known RTOS, the uC/OS series which have "everything and the kitchen sink" drivers supposedly but it's not at all for hobbyists, with licenses costing at least $50K if I'm not mistaken.
     
    I just learned recently about RTEMS, which is open source and used by a lot of serious NASA stuff along with who knows what else (started as a DoD project IIRC)... I learned about this from Elecia White's embedded.fm podcast where she once featured the maintainer for a long discussion of it.  http://www.rtems.com/node/66
    RTEMS supports some Cortex-M stuff like STM32 if my memory of the podcast serves, so it's probably portable to TI's ARM Cortex-M stuff.
     
    RTEMS actually sounds really cool, possibly resume-building project to get involved in
     
    Ah yes, there's also Contiki, and I think someone pulled in CC3200 support for that too.
  18. Like
    zeke reacted to spirilis in I'm struggling with the CC3200   
    I take FreeRTOS as a "blank canvas".  It provides a scheduler, and synchronization/message-passing primitives, plus it requires (and thus provides as a standard interface) heap allocation mechanisms so you have a malloc/free type of setup.
     
    Thus, it can be sculpted into whatever you want it to be ..... or it can be a source of frustration if you would prefer to have all your RTOS-aware drivers written for you.  TI-RTOS does, for the most part or "in theory" might be a better term, provide the latter (at least for some stuff TI-related like MCU peripherals and network stacks like CC32xx/31xx SimpleLink WiFi in native RTOS-compatible form).  So I can see where someone would talk about FreeRTOS being "not up to par", but it's a double-edged sword.
     
    For someone who's thinking about this topic in the context of making a product that might become commercialized - that is to say really, of what "foundation" one should commit their time into learning with the purpose of conserving one's time and energy yet maximizing utility, one has a couple schools of thought they can choose from.  TI-RTOS is supported by TI, the vendor, and has device drivers supported by the vendor.  But the build process so far as I've seen seems a bit complicated and difficult to trace and so if you have problems with the drivers, you are kind've beholden to TI to fix them or help you figure out how you're using them wrong/etc.  I guess at some point folks become XDC maestros and experts in the subject but I can't imagine willingly committing a lot of time to getting there when there are other things to spend your time on... as I may have said earlier, XDC appears to be an esoteric attempt to replicate C++'s features in C using a domain-specific language to glue everything together.  Still though, some people like committing trust into a "partner" like TI to provide everything they need, and at some level it's an arbitrary decision.
     
    But if you have adequate driver support by other means -- say, the driverlib that comes with most 32-bit ARM MCUs by TI and other vendors, and you have a good idea of how complicated driver implementation & use-cases needs to get to make them RTOS-native/aware (possibly writing special driver tasks and RTOS-message-passing-oriented APIs to wrap them), and/or you are fully willing to write or port your own external peripheral drivers (which you may have to do with TI-RTOS too since it doesn't support every IC on the planet), FreeRTOS is a very transparent RTOS system that you can use as your base.  It's also commercially supportable and well known (supports multiple vendors), seeing as even TI provides FreeRTOS examples in many of its chip lines and driverlib suites (TivaWare, HALCoGen coming to mind).  It's the more DIY option, but some might take comfort in knowing they wrote the most important interfaces from scratch and should understand where things could go wrong.
     
    Anyway, that's my 2 cents with my current state of knowledge.  Ask me again once I've digested all those TI-RTOS training videos... (though presently I am digesting the FreeRTOS Cortex-M3 book I printed out)
  19. Like
    zeke got a reaction from tripwire in I'm struggling with the CC3200   
    @@yyrkoon
     
    Yeah, I did find that page. Thanks.
     
    Did you notice how much detail is (or isn't) on that page? It's just enough to prove to yourself that you can get it to run. 
     
     
    The reason for me shifting my focus to freeRTOS is this page:
    http://processors.wiki.ti.com/index.php/CC32xx_SDK_Sample_Applications
     
    I looked through the list and noted how many times the OS Support column said freeRTOS versus TI-RTOS. There's not much TI-RTOS in that list but there is plenty of freeRTOS mentions.
     
    If the people who compose the example programs choose freeRTOS rather than TI-RTOS then there's something there.
     
    So, I take that as an omen about TI-RTOS:
     Abandon all hope, ye who enter here. - Dante's Inferno
     
  20. Like
    zeke reacted to spirilis in I'm struggling with the CC3200   
    I don't think we're saying they are selling boards with no TI-RTOS support.What we're saying is TI-RTOS is a pain in the ass to get started with.
  21. Like
    zeke reacted to spirilis in I'm struggling with the CC3200   
    Fwiw the FreeRTOS books still come as a password protected PDF but when you buy the printable PDF the print feature is allowed in the DRM. Not sure if a commercial printer can work with that so I printed the Cortex-M3 book last night on my laser printer doing separate odd/even prints for double sided..... that was interesting. Paper was hot coming out after the 20th page or so. But it's printed, bound via binder clips
  22. Like
    zeke got a reaction from tripwire in I'm struggling with the CC3200   
    I found the answer.  It's a debugger based on the FTDI chip.
     
    I followed these instructions to get me onto the right path:
    http://www.ti.com/lit/ug/swru376d/swru376d.pdf
  23. Like
    zeke reacted to spirilis in I'm struggling with the CC3200   
    Got the basic freertos_demo for ek-tm4c123gxl (example from TivaWare found via TI Resource Explorer) running on my TM4C123G launchpad.  That codebase still looks a bit "busy" but some of the concepts are coming back to me.  It just blinks the RGB LED and the left pushbutton changes color, while the right pushbutton changes the cadence.
     
    Attaching a few pictures for kicks.
     

     
     
    Main function in freertos_demo.c which gets the party started:

     
    Just going to paste the actual code for the ledtask_init and switchtask_init stuff:
     
    LEDTaskInit (called from main):
    //***************************************************************************** // // Initializes the LED task. // //***************************************************************************** uint32_t LEDTaskInit(void) { // // Initialize the GPIOs and Timers that drive the three LEDs. // RGBInit(1); RGBIntensitySet(0.3f); // // Turn on the Green LED // g_ui8ColorsIndx = 0; g_pui32Colors[g_ui8ColorsIndx] = 0x8000; RGBColorSet(g_pui32Colors); // // Print the current loggling LED and frequency. // UARTprintf("\nLed %d is blinking. [R, G, B]\n", g_ui8ColorsIndx); UARTprintf("Led blinking frequency is %d ms.\n", (LED_TOGGLE_DELAY * 2)); // // Create a queue for sending messages to the LED task. // g_pLEDQueue = xQueueCreate(LED_QUEUE_SIZE, LED_ITEM_SIZE); // // Create the LED task. // if(xTaskCreate(LEDTask, (const portCHAR *)"LED", LEDTASKSTACKSIZE, NULL, tskIDLE_PRIORITY + PRIORITY_LED_TASK, NULL) != pdTRUE) { return(1); } // // Success. // return(0); } SwitchTaskInit (called in main):
    //***************************************************************************** // // Initializes the switch task. // //***************************************************************************** uint32_t SwitchTaskInit(void) { // // Unlock the GPIO LOCK register for Right button to work. // HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY; HWREG(GPIO_PORTF_BASE + GPIO_O_CR) = 0xFF; // // Initialize the buttons // ButtonsInit(); // // Create the switch task. // if(xTaskCreate(SwitchTask, (const portCHAR *)"Switch", SWITCHTASKSTACKSIZE, NULL, tskIDLE_PRIORITY + PRIORITY_SWITCH_TASK, NULL) != pdTRUE) { return(1); } // // Success. // return(0); } So xTaskCreate is used to register tasks with the RTOS before the scheduler begins (via vTaskStartScheduler()).
    In theory, all of that init crap could be stuffed into main() just before vTaskStartScheduler, but doing it this way "encapsulates" the code a bit.  Note that led_task.c and switch_task.c have respective .h files, but those just register the blahblahTaskInit functions as extern so freertos_demo.c (where main() is located) can see them:
    extern uint32_t SwitchTaskInit(void); Also this example has TI's "anti-viral open source" stuff in it.  Luckily, the FreeRTOS stuff, including the critical piece - the "third_party/FreeRTOS/Source/portable/CCS/ARM_CM4F/port.c" and portasm.asm files do NOT have this "anti-viral open source" license applied to them, rightfully so since FreeRTOS requires any modifications to the RTOS to be open-source.  Which makes me wonder why TI's included their "anti-viral open source" wording in conjunction with such a "viral" open-source product... (sketchy from a legal standpoint but none of us geeks give a crap, including TI's own developers apparently).
  24. Like
    zeke reacted to spirilis in I'm struggling with the CC3200   
    As I understand it, the critical piece that needs to be implemented per-platform are:
     

     
    The scheduler and dynamic memory-management (malloc/free et al) functionality.  port.c includes a lot of scheduler, interrupt, NVIC type of crap ... portasm.asm includes more interrupt and scheduler crap, and if I'm not mistaken the stock FreeRTOS distribution includes three different "heap handlers" of which this TI example only includes heap_2.c - it only needs to implement the various heap-related FreeRTOS calls, but it's in the "portable" section since it may vary from project to project and platform to platform.
  25. Like
    zeke reacted to spirilis in I'm struggling with the CC3200   
    Oh yeah, here's an example of my (possibly over-engineered) LCD driver implementation for Hercules TMS570LS04 + HALCoGen + FreeRTOS:
     
    https://github.com/spirilis/herc1202
     
    The os_mpu_wrappers was an oddball thing I had to do to fix the Hercules FreeRTOS project generator, maybe they've patched that up since, but that's my most sophisticated codebase with any FreeRTOS involvement so far.
×
×
  • Create New...