Anna, The Elkhorn Creek Kentucky Great Horned Owl

This article definitely goes in the miscellaneous category.  On Wednesday night my children, Anna and Nicholas, went out canoeing on Anna’s last night home before heading to College.  They had not been gone very long when Anna came running in saying that there was an Owl (a Kentucky Great Horned Owl) on the creek bank.  We all ran out to see it… because hey,  Owls are awesome.  And sure enough.  There was an Owl on the other side of the creek, specifically a Kentucky Great Horned Owl.

We went back to the house and I started calling around to the various bird recuse organizations in Kentucky.  I finally got a really nice guy who said that it was probably a fledgling and that we should just leave it alone… which always seems to be the best course of action.  The next morning, Anna said that we should go see if the Owl was still gone.  I agreed and we went to the creek.  We didnt see it on the other side of the creek… but thought, maybe we will just canoe over there and make sure.  Once we got to the other side of the creek, we still didnt see it.  Right before we were going to go back, Anna said “Ill get out and look one time just to make sure”.  The bank is super steep on that side of the creek.  As soon as she got out she found her face to face with the Owl… who immediately went tumbling down… splash into the creek.  I am pretty sure that a Kentucky Great Horned Owl shouldn’t be swimming in the Creek.

Kentucky Great Horned Owl - they can swim

Kentucky Great Horned Owl

Kentucky Great Horned Owl

We were not exactly sure what to do next.  So I started calling Raptor Rescues… but I couldn’t get in touch with anyone.  It was clear that the bird was not nearly strong enough to do anything.  I knew that it could bite off my finger… or claw off my hand… so I threw my shirt over the bird, then scooped it into the Canoe.  The bird was clearly in a bad way, so we took it up to the house, put a hot towel over him, and tried to dry him off.

Finally, a person from the Broadbent Wildlife Sanctuary called me back.  They are Meade County Kentucky… which is a long way from my house.  But, they were sending someone to Lexington to pick up some abandoned bunny rabbits (which I thought might make a nice snack for the Owl).  She said they would come get him.  I left him covered up in a trashcan on the front porch and hoped for the best.  It definitely didn’t look good though.

Kentucky Great Horned Owl

A few hours later I got a text message from a super nice lady named Lydia who had him and was taking him to the Vet at the Broadbent Wildlife sanctuary.  She was rushing back to the hospital and hoped he would survive.

Kentucky Great Horned Owl

Friday: I was really afraid that he was dead… and almost didn’t want to know.  But I finally sent Lydia a text.  She responded that he was still alive and they had been giving him IV fluids and a feeding tube.  This was a huge relief … I asked if there anything I could do?  Money?  She said yes… this is a mostly volunteer 501-c3 organization … so I sent them a good size donation… In the name of “Anna the Elkhorn Creek Kentucky Great Horned Owl”.  Which is officially his name in honor of Anna the Kentucky college student who fished him out of the creek.  If you are rooting for him as well please send a donation to the Broadbent Wildlife Sanctuary.

Saturday:  Lydia sent me an updated picture… he still looks pretty damn bad… but hopefully he is improving.  Please cross your fingers.

Kentucky Great Horned Owl

Saturday Afternoon:  Lydia just sent me a text.  She just fed Anna the Elkhorn Creek Kentucky Horned Owl and he stood up…

Percepio Tracealyzer – Running on PSoC6

Summary

I have been having an excellent experience with Percepio Tracealyzer on PSoC4, so now, the next question is, “Will it work on PSoC6?”  The answer is yes, but it takes a few gyrations.  In the next two Articles I will show you how to use Tracealyzer on PSoC6 with:

  1. JLINK and Snapshot mode
  2. JLINK and Segger RTT in Streaming Mode
  3. A PSoC6 DMA –> UART Streaming Mode

In order to make these work you need to

  1. Make a new project and integrate the Trace Recorder Library
  2. Modify trcConfig.h
  3. Install the JLINK
  4. Build the project & test

Create a new PSoC6 project & Integrate the Trace Recorder Library

The process of integrating the TraceRecorder library is very similar to PSoC 4.  You need to add the include directories into your project.  Right click the project and pick “Build Settings…”

Click on the “Additional Include Directories”

Then add the two TraceRecorder include directory and the StreamPort include directory.

Next you should copy the configuration header files into your project so that you can edit them.  You can copy-paste them in Windows Explorer from “TraceRecorder/config” into your project

Next add the TraceRecoder .c and .h files into your project by right clicking “Add –>Existing Item..”

You need the .c and .h files from

  • yourproject/{trcConfig.h, trcSnapshotConfig.h, trcStreamingConfig.h}
  • TraceRecorder/*.c
  • TraceRecorder/include/*.h
  • TraceRecorder/streamports/Jlink_RTT/include/*.h
  • TraceRecorder/streamports/Jlink_RTT/*.c

  

Modify FreeRTOSConfig.h & trcConfig.h

The next step is to modify FreeRTOSConfig.h to include the trace recorder header.   Copy this block of code into the bottom for FreeRTOSConfig.h

#if ( configUSE_TRACE_FACILITY == 1 )
#include "trcRecorder.h"
#endif

Update the FreeRTOSConfig.h to turn on tracing.

#define configUSE_TRACE_FACILITY                1

Then modify trcConfig.h to include the CMSIS Core headers.

/******************************************************************************
 * Include of processor header file
 * 
 * Here you may need to include the header file for your processor. This is 
 * required at least for the ARM Cortex-M port, that uses the ARM CMSIS API.
 * Try that in case of build problems. Otherwise, remove the #error line below.
 *****************************************************************************/
//#error "Trace Recorder: Please include your processor's header file here and remove this line."

#include "cy8c6347bzi_bld53.h"

The first time that I did this, I tried just #include <project.h> but if you do that you will end up with hundreds of errors and hours and hours of trying to figure out what is going on.  It turns out that the FreeRTOS is picky about the order in which files are included.  And when PSoC Creator makes the project.h it assumes that the order of includes doesn’t matter.  I fixed this by just including the “cy8c6347bzi_bld53.h” header which just? has the CMSIS files.

After fixing that mess, I modify the trcConfig to specify that I am using a Cortex-M processor (actually two of them)

/*******************************************************************************
 * Configuration Macro: TRC_CFG_HARDWARE_PORT
 *
 * Specify what hardware port to use (i.e., the "timestamping driver").
 *
 * All ARM Cortex-M MCUs are supported by "TRC_HARDWARE_PORT_ARM_Cortex_M".
 * This port uses the DWT cycle counter for Cortex-M3/M4/M7 devices, which is
 * available on most such devices. In case your device don't have DWT support,
 * you will get an error message opening the trace. In that case, you may 
 * force the recorder to use SysTick timestamping instead, using this define:
 *
 * #define TRC_CFG_ARM_CM_USE_SYSTICK
 *
 * For ARM Cortex-M0/M0+ devices, SysTick mode is used automatically.
 *
 * See trcHardwarePort.h for available ports and information on how to 
 * define your own port, if not already present.
 ******************************************************************************/
//#define TRC_CFG_HARDWARE_PORT TRC_HARDWARE_PORT_NOT_SET
#define TRC_CFG_HARDWARE_PORT TRC_HARDWARE_PORT_ARM_Cortex_M

Ill start the project just using Snapshot mode

/*******************************************************************************
 * Configuration Macro: TRC_CFG_RECORDER_MODE
 *
 * Specify what recording mode to use. Snapshot means that the data is saved in
 * an internal RAM buffer, for later upload. Streaming means that the data is
 * transferred continuously to the host PC. 
 *
 * For more information, see http://percepio.com/2016/10/05/rtos-tracing/
 * and the Tracealyzer User Manual.
 *
 * Values:
 * TRC_RECORDER_MODE_SNAPSHOT
 * TRC_RECORDER_MODE_STREAMING
 ******************************************************************************/
#define TRC_CFG_RECORDER_MODE TRC_RECORDER_MODE_SNAPSHOT
//#define TRC_CFG_RECORDER_MODE TRC_RECORDER_MODE_STREAMING

To start the testing I created a really simple, single task blinked led program in main_cm4.c. The only thing that you have to add is the “vTraceEnable(TRC_START)” to turn on the TraceRecorder.

#include "project.h"

void ledTask(void *arg)
{
    (void)arg;
    while(1)
    {
        Cy_GPIO_Inv(RED_PORT,RED_NUM);
        vTaskDelay(500);
    }
}

int main(void)
{
    __enable_irq(); /* Enable global interrupts. */

    vTraceEnable(TRC_START);
    xTaskCreate(ledTask,"LED Task",configMINIMAL_STACK_SIZE,0,1,0);
    vTaskStartScheduler();
}

Testing Percepio Tracealyzer

To start with I setup snapshot mode.  I wasn’t sure exactly what the memory map was for the new PSoC6.  But I did know that PSoC Creator copied in a linker file (actually 3 linker files) and that if I looked in the file I would find the memory map.

When I opened the GCC linker file “cy8c6xx7_cm4_dual.ld” I found the memory map for the chip.

MEMORY
{
    flash       (rx)    : ORIGIN = 0x10080000, LENGTH = 0x80000
    wflash            (rx)    : ORIGIN = 0x14000000, LENGTH = 0x8000          /*  32 KB */
    sflash_user_data  (rx)    : ORIGIN = 0x16000800, LENGTH = 0x800
    sflash_nar        (rx)    : ORIGIN = 0x16001A00, LENGTH = 0x200
    sflash_public_key (rx)    : ORIGIN = 0x16005A00, LENGTH = 0xC00
    sflash_toc_2      (rx)    : ORIGIN = 0x16007C00, LENGTH = 0x400
    xip               (rx)    : ORIGIN = 0x18000000, LENGTH = 0x8000000       /* 128 MB */
    efuse             (r)     : ORIGIN = 0x90700000, LENGTH = 0x100000        /*   1 MB */
    ram   (rwx) : ORIGIN = 0x08024000, LENGTH = 0x23800
}

To make read the Percepio Tracealyzer snapshot you need to select “JLink -> Read Trace (Snapshot)”.  When you do that, it asks you where the RAM is on that device.  I simply copy from the linker file the start and length of the RAM

After that I get the trace.

The next thing to do is modify the trcConfig.h to switch to streaming mode:

/*******************************************************************************
 * Configuration Macro: TRC_CFG_RECORDER_MODE
 *
 * Specify what recording mode to use. Snapshot means that the data is saved in
 * an internal RAM buffer, for later upload. Streaming means that the data is
 * transferred continuously to the host PC. 
 *
 * For more information, see http://percepio.com/2016/10/05/rtos-tracing/
 * and the Tracealyzer User Manual.
 *
 * Values:
 * TRC_RECORDER_MODE_SNAPSHOT
 * TRC_RECORDER_MODE_STREAMING
 ******************************************************************************/
//#define TRC_CFG_RECORDER_MODE TRC_RECORDER_MODE_SNAPSHOT
#define TRC_CFG_RECORDER_MODE TRC_RECORDER_MODE_STREAMING

After I reprogram my CY8CKIT-062 BLE, then “File->Connect to Target System” I end up with a nice stream of data.

And when I look at the stream it says that things are working just as expected.

Im not sure what its next.  Maybe I will make a DMA/UART version so as not to require the JLKINK.

As always you can find all of these projects on the IotExpert GitHub site or git@github.com:iotexpert/PSoC-Tracelyzer.git

Article Description
Percepio Tracealyzer & PSoC An Introduction to Percepio Tracealyzer on the Cypress PSoC
Percepio Tracealyzer RTT Streamport - PSoC4200M Make the JLINK RTT Library work with Tracealyzer
Percepio Tracealyzer PSoC UART Streamport Creating a UART Streamport
Percepio Tracealyzer - Analyzing the PSoC Tracealyzer Streamport Figure out what is broken in the UART Streamport
Percepio Tracealyzer - Using PSoC DMA to Fix the UART Streamport Implementing PSoC DMA to improve the CPU Utilization
Percepio Tracealyzer - Running on PSoC6 Porting the Percepio Tracealyzer to PSoC6

Percepio Tracealyzer: A PSoC DMA Streamport

Summary

In the last Article I analyzed the performance problems of my firmware based PSoC Tracealyzer Streamport … which was terrible.  Although it has been a long time since I used the PSoC4M DMA engine, I knew that it would solve my problem.  In this article Ill show how to use the PSoC DMA, then Ill build and analyze a PSoC DMA Streamport for Tracealyzer.

PSoC4 UART DMA

The DMA block that shows up in the PSoC4200M, PSoC 4200L and PSoC4BLE is pretty amazing.  It can do a bunch of stuff.  Here is a snapshot that I took out of the TRM.  This block sits on the main AHB bus inside of the PSoC.  It can act as a master (see the block that says Master I/F) and read and write any of things in the ARM address space including the Flash, SRAM, and all of the peripherals.  It has an incoming trigger which can get the transfers going and when it is done it can trigger an interrupt or another DMA channel.  The Slave I/F allows the CPU to program the block.  The device has 8-channels with each channel having 2 descriptors (so it can ping pong).

PSoC4 DMA

Before I tried to make the PSoC DMA Streamport I started by looking at the example projects by pressing “File->Code Example”

PSoC Creator Example

Then filtering for DMA

PSoC Creator Example Project - DMA

Finally creating project.  This project uses two DMA channels, one for the UART receive and one for the UART Transfer.  It lets you type characters into the UART, it saves them in one of the RAM buffers, then when you have typed 8, it DMAs them back into the Transmit channel of the UART.  This example ping-pings back and forth between two RAM buffers.

PSoC Creator DMA Example

I decided that it would be best to build a bare metal DMA project called “test-uart” to prove that I understood.  This project will DMA transfer an array of characters to the UART when the user presses the switch on the board or a “s” on the keyboard.  The first thing to do is build the schematic with a UART, a DMA block,  two output pins, and input pin and an interrupt.

PSoC DMA Streamport

Place an SCB UART. then configure it (change the name, but accept all of the defaults)

PSoC Creator UART

Then click on the advanced tab.  Turn on the DMA for Transfer (TX Output) and set the “FIFO Level” to 7.  This will cause the UART to assert DMA signal anytime the transmit FIFO has less than 7 bytes.  In  other words … FEED ME!!!

After configuring the UART, Set the PINs

PSoC DMA Streamport Pin Assignment

Next configure the DMA.  The memory array that I have will be “uint8_t” aka “char”.  So the input needs to be “bytes”.  The UART FIFO hold Words… aka 4 bytes.  So I need to configure the transfers to do “Byte to Word”.  After the DMA transfer is done, I setup the DMA to create an interrupt (so that I can reset everything in the CPU) and to invalidate the descriptor.

PSoC DMA Streamport

In the firmware works by

  • Turning on the UART
  • Enabling the DMA
  • Setting up the channel with the address of the buffer that I am going to write to (aka the TX FIFO) and asking for an interrupt

Then looping:

  • When the User presses “s” or the switch, I set myFlag to be 1.
  • If it is 1 and the channel is inactive, then initialize the “source” address, setup the number of transfer elements to be the number in my array, validate the descriptor, and turn on the channel.

When the channel turns on, the Tx fifo will be empty so it will assert the Tx Out, which will make the DMA keep triggering and copying 1 byte at a time into the FIFO.  While this is happening, the UART will try to empty the fifo by sending the bytes.  Finally when the DMA reaches the end of the RAM buffer, it will stop, and at some point the TX FIFO will finish emptying.  The DMA will trigger the interrupt to toggle the BLUE LED.  And the whole process can start again.

#include "project.h"
#include <stdio.h>

// A flag to trigger the DMA
volatile int myFlag=0;
  
static const char myArray[]="asdf1234asdfadsfasdfadsfqwerasdfqwerqwer9\n";

CY_ISR(sw_handler)
{
    myFlag = 1;
    SW_ClearInterrupt();
}

// This is called TWICE at the end of the DMA transaction
CY_ISR(myDMA)
{
    BLUE_Write(~BLUE_Read());
}
int main(void)
{
    CyIntEnable(CYDMA_INTR_NUMBER);
    CyGlobalIntEnable; /* Enable global interrupts. */

    char c;
    
    UART_Start();
    UART_UartPutString("Started\n");
  
    isr_1_StartEx(sw_handler);
  
    CyDmaEnable();
    
    DMA_Init();
    DMA_SetDstAddress(0, (void *)UART_TX_FIFO_WR_PTR);
    DMA_SetInterruptCallback(myDMA);

    while(1)
    {
        c = UART_UartGetChar();
        switch(c)
        {       
            case 's':
                myFlag = 1;
            break;
        }
        
        // This turns on the DMA so that the string will go to the UART.
        if(myFlag && CyDmaGetActiveChannels() == 0)
        {
            DMA_SetSrcAddress(0, (void *)myArray);
            DMA_SetNumDataElements(0,strlen(myArray)-1);
            DMA_ValidateDescriptor(0);
            DMA_ChEnable();
            myFlag=0;
        }
    }
}

PSoC DMA Streamport

Now that I understand how to use the DMA, I can create the PSoC DMA Streamport by copying the project “1-BlionkingLED_UART_TRACE” project and calling it “1-BlinkingLED_UART_TRCE_DMA”.  Next, add the DMA and modify the UART.

PSoC DMA Streamport

Configure the UART

PSoC DMA Streamport - UART Configuration

Turn on the UART DMA and set the level to 7

Configure the DMA Block

PSoC DMA Streamport Configuration

Make byte transfers and byte –> word.

PSoC DMA Streamport - DMA Configuration

Finally modify the trcStreamingPort.c – AKA the PSoC DMA Streamport file.  Specifically you need to fix up the PSoC_Transmit to send out the data when the TraceRecorder buffer is full.

  • If the DMA is busy… then wait until the previous transaction is done.
  • Then setup the DMA and let it rip.
int32_t PSoC_Transmit(void* data, uint32_t size, int32_t *numOfBytesSent )
{
    
    while( CyDmaGetActiveChannels()& DMA_CHANNEL_MASK);
    DMA_SetSrcAddress(0, (void *)data);
    DMA_SetNumDataElements(0,size);
    DMA_ValidateDescriptor(0);
    DMA_ChEnable();

    *numOfBytesSent=size;
    
    return 0; // Doesnt matter what you return... i dont think that it is checked
}

The only other thing that needs to happen is configure the DMA in main.c

    CyDmaEnable();
    DMA_Init();
    DMA_SetDstAddress(0, (void *)UART_TX_FIFO_WR_PTR);

Testing the PSoC DMA Streamport

Now when I startup the Tracealyzer, here is what I get:

PSoC DMA Streamport - New CPU Load

It looks like I solved my problem because that is way way better than:

PSoC DMA Streamport - Terrible Performance

As always you can find all of these projects on the IotExpert GitHub site or git@github.com:iotexpert/PSoC-Tracelyzer.git

Article Description
Percepio Tracealyzer & PSoC An Introduction to Percepio Tracealyzer on the Cypress PSoC
Percepio Tracealyzer RTT Streamport - PSoC4200M Make the JLINK RTT Library work with Tracealyzer
Percepio Tracealyzer PSoC UART Streamport Creating a UART Streamport
Percepio Tracealyzer - Analyzing the PSoC Tracealyzer Streamport Figure out what is broken in the UART Streamport
Percepio Tracealyzer - Using PSoC DMA to Fix the UART Streamport Implementing PSoC DMA to improve the CPU Utilization
Percepio Tracealyzer - Running on PSoC6 Porting the Percepio Tracealyzer to PSoC6

Percepio Tracealyzer – Analyzing the PSoC Tracealyzer Streamport

Summary

In the previous article I showed you how to make a PSoC Tracealyzer Streamport using the SCB based UART on a PSoC 4200M.  It didn’t take long for me to realize that 115200 baud was not going to cut it.   That realization lead me to figure out that the KitProg on the CY8CKIT-044 was limited to 115200, which I worked around by using the Cypress USB Serial Bridge that I got from the CY8CKIT-049.  But when I look at the CPU graph I found out that it took 50% of the CPU to support streaming the data.  So now what?  In this Article lets analyze the data, both old school with a logic analyzer, and new school with PSoC Tracealyzer.

Analyzing the PSoC Tracealyzer Data

While I was capturing the streaming data from PSoC Tracealyzer I could see that the CPU was burning about 50% of the time just running the TzCntrl and blinking LED thread.  That isn’t good.

PSoC Tracelyzer

When you look at the PSoC Tracealyzer trace viewing you can see the problem is the TzCtrl task.  This task is running for 83 milliseconds and using 57.6% of the CPU.

PSoC Tracelyzer - analyzing the CPU Usage

If you look at the data transmit function called “PSoC_Transmit”, there isn’t much going on.  Just a call to UART_SpiUartPutArray.  But if you look at the UART documentation you will find that SpiUartPutArray is a blocking function, meaning it doesn’t return until it is done.  If you calculate the time to transfer a block of 1024 bytes at 8bits/byte and 230400 baud you will find that just sending the data takes 35ms.

int32_t PSoC_Transmit(void* data, uint32_t size, int32_t *numOfBytesSent )
{
    timing_Write(1);
    UART_SpiUartPutArray((uint8_t *)data,size);
    *numOfBytesSent=size;
    timing_Write(0);
    return 0; // Doesnt matter what you return... i dont think that it is checked
}

I was not very sure why the task was taking 83 milliseconds to run when the data transfer was only taking 40ms.  To figure this out I added a toggle pin to the data write routine, just to make sure.  What I found is the data write routine is getting called about every 70ms takes ~30ms to run.

Old school with Salae Logic

How is that possible, the calculation says that it should take 35ms.  It turns out that I configured the UART to have a 64 byte buffer.

PSoC Creator SCB Configuration

When you remove the 64 bytes from the calculation you end up with 32ish milliseconds.  The other thing that this chart shows is that the TzCntrl task is calling the PSoC_Transmit function more frequently that I thought, at least twice per cycle.  You can also see from the plot that function is taking 30/70=42.8% of the CPU by itself.  Not good, but we are starting to understand what is going on.

As I typed this part of the Article I realized that toggling a GPIO probably wasn’t the best way to figure out what was happening.  In fact, that is the whole point of Tracealyzer, that is analyzing the performance of your program.  When I looked at the Tracealyzer documentation (I always hate doing that), I found a nice function called vTracePrintf.  I added a “toggle” aka printing a 0 and printing a 1 into trace channel 0.

int32_t PSoC_Transmit(void* data, uint32_t size, int32_t *numOfBytesSent )
{
    timing_Write(1);
    vTracePrintF(0,"1");
    UART_SpiUartPutArray((uint8_t *)data,size);
    vTracePrintF(0,"0");
    timing_Write(0);
    *numOfBytesSent=size;
    
    return 0; // Doesnt matter what you return... i dont think that it is checked
}

After running another trace, look what I get.  You can see the “1” printing at the start and the 0 printing at the end.

PSoC Tracelyzer - Analyzing the CPU Usage with vTaskPrintF

Even better, when I double clicked on the “[Default Channel] 0” it took me to this nice screen which shows when the events occurred.  The one that I clicked on started at 8.136.039 and ended at 8.176.176, in other words it took about 40ms

PSoC Tracelyzer - User Events from Tracelyzer

After hand calculating the time, I realized that once again I should have done something even more obvious, let the ARM calculate the time.  the vTracePrintf will let you specify the output format, in this case a %d

int32_t PSoC_Transmit(void* data, uint32_t size, int32_t *numOfBytesSent )
{
    TickType_t time;
    
    timing_Write(1);
    
    time = xTaskGetTickCount();
    UART_SpiUartPutArray((uint8_t *)data,size);
    time = xTaskGetTickCount() - time;
    vTracePrintF(0,"%d",time);
    timing_Write(0);
    *numOfBytesSent=size;
    
    return 0; // Doesnt matter what you return... i dont think that it is checked
}

When you look at the trace, you need to click on the “User Events” to see the print outs from the trace.

PSoC Tracelyzer - CPU Usage

Now that we have a pretty good feel for what is going on, how do we fix it?  Simple, use the PSoC DMA take the CPU mostly out of the UART transmission path, which is the topic of the next Article.

As always you can find all of these projects on the IotExpert GitHub site or git@github.com:iotexpert/PSoC-Tracelyzer.git

Article Description
Percepio Tracealyzer & PSoC An Introduction to Percepio Tracealyzer on the Cypress PSoC
Percepio Tracealyzer RTT Streamport - PSoC4200M Make the JLINK RTT Library work with Tracealyzer
Percepio Tracealyzer PSoC UART Streamport Creating a UART Streamport
Percepio Tracealyzer - Analyzing the PSoC Tracealyzer Streamport Figure out what is broken in the UART Streamport
Percepio Tracealyzer - Using PSoC DMA to Fix the UART Streamport Implementing PSoC DMA to improve the CPU Utilization
Percepio Tracealyzer - Running on PSoC6 Porting the Percepio Tracealyzer to PSoC6

Percepio Tracealyzer PSoC UART Streamport

Summary

In the last Article I showed you how to use the JLINK RTT Streamport to make Tracealyzer work.  When I did that port I didn’t really like having to use a JLink, it seemed like a pain to have another box.  I knew that it was possible to make a UART based Streamport.  So, that is what I am going to do, create a Tracealyzer PSoC Streamport.  This Article is going to be broken up into two parts.  In Part 1 I will show you a software based port and the problems that it creates.  In Part 2 I will show you how to use DMA to hopefully (as I haven’t done the work yet) make it work much better.  I was hoping this morning when I started working on this Article that it would only take me a couple of hours, but that did not turn out to be the case as I ran into a PSoC Creator bug which made it hard to figure out what was going on.

Cypress USB Serial Bridge & CY8CKIT-049

If you remember from the last article, the Tracealyzer needs to stream about 20KBs.  That is a big B as in Bytes.  Which means that a 115200 Kbs (aka 14.4 KBs) UART probably won’t do the trick.  That is OK as the PSoC SCB UART can run at up to 921600 aka 115.2 KBs.  The problem is the Kitprog bridge on my development kit is limited to 115200 (I’m not sure why)  I didn’t realize that limitation this morning when I started working on this problem.  But it turns out that the CY8CKIT-049 has a Cypress USB Serial Bridge.which is used to boatload the PSoC4200.  And… it is designed to break off the kit.

CY8CKIT-049

So I broke it off and gave it to my lab assistant to solder (he isn’t normally that grumpy, but he stayed up all night at a birthday party)

Nicholas the Lab Tech

Now I have two wires which I can use to talk to the CY8CKIT-044 UART.

Cypress USB Serial Bridge

After I got the wires on the bridge, I installed the USB Serial Configuration Utility and set the chip up to be 921600 baud.  To do this, run the utility.

USB Serial Configuration Utility

Connect to your bridge, in this case the CY7C65211-24LTXI

USB Serial Configuration Utility

Then pick the SCB (which stands for Serial Communication Block)

USB Serial Configuration Utility

Click the configure, then set the baud to 921600.

USB Serial Configuration Utility

Now, I wire the two kits together (the Jlink is just sitting there)

Percepio Tracelyzer PSoC Setup

Creating a Tracealyzer PSoC UART Streamport

The first thing to do is modify the previous project to also have a UART.

PSoC Creator

Then connect the UART to Pins P3[0] & P3[1]

PSoC Creator

To make the Tracealyzer PSoC Streamport work I make a copy of the TraceRecorder/streamports/USB_CDC and called it PSoC_UART.  After I cut all all of the ST USB crap, I realized that all I need to provide is a

  • A function to receive bytes … called PSoC_Receive
  • A function to transmit bytes… called PSoC_Transmit

Next you need to modify these 10 CPP Macros to support the Tracealyzer PSoC Streamport.   (I only had to modify INIT, READ and SEND)

  • TRC_STREAM_PORT_ALLOCATE_FIELDS
  • TRC_STREAM_PORT_MALLOC
  • TRC_STREAM_PORT_INIT
  • TRC_STREAM_PORT_ALLOCATE_EVENT
  • TRC_STREAM_PORT_ALLOCATE_DYNAMIC_EVENT
  • TRC_STREAM_PORT_COMMIT_EVENT
  • TRC_STREAM_PORT_READ_DATA
  • TRC_STREAM_PORT_PERIODIC_SEND_DATA
  • TRC_STREAM_PORT_ON_TRACE_BEGIN
  • TRC_STREAM_PORT_ON_TRACE_END

In addition I provide function prototypes for PSoC_Receive and PSoC_Transmit which are called by TRC_STREAM_PORT_READ_DATA and TRC_STREAM_PORT_PERIODIC_SEND_DATA

// An Adaption of the Percepio CDC Library to PSoC SCB UART
#include <project.h>

#ifndef TRC_STREAMING_PORT_H
#define TRC_STREAMING_PORT_H

#ifdef __cplusplus
extern "C" {
#endif

/*******************************************************************************
 * Implement the below macros to define your own stream port. If your transfer 
 * method uses RTOS functions, you should not send the data directly but use 
 * the recorder's internal buffer to store the trace data, for later transfer by
 * the TzCtrl task. Check the predefined stream ports for examples on how to use 
 * the internal buffer (e.g., TCP/IP, UART or USB CDC).
 *
 * Read more at http://percepio.com/2016/10/05/rtos-tracing/  
 ******************************************************************************/

int32_t PSoC_Receive(void *data, uint32_t size, int32_t *numOfBytesReceived);
int32_t PSoC_Transmit(void *data, uint32_t size, int32_t *numOfBytesSent );

#if TRC_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_STATIC
#define TRC_STREAM_PORT_ALLOCATE_FIELDS() static char _TzTraceData[TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT * TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE];       /* Static allocation. */
#define TRC_STREAM_PORT_MALLOC() /* Static allocation. Not used. */
#else
#define TRC_STREAM_PORT_ALLOCATE_FIELDS() static char* _TzTraceData = NULL;     /* Dynamic allocation. */
#define TRC_STREAM_PORT_MALLOC() _TzTraceData = TRC_PORT_MALLOC(TRC_PAGED_EVENT_BUFFER_PAGE_COUNT * TRC_PAGED_EVENT_BUFFER_PAGE_SIZE);
#endif

#define TRC_STREAM_PORT_INIT() \
        UART_Start(); \
        TRC_STREAM_PORT_MALLOC(); /*Dynamic allocation or empty if static */

#define TRC_STREAM_PORT_ALLOCATE_EVENT(_type, _ptrData, _size) _type* _ptrData; _ptrData = (_type*)prvPagedEventBufferGetWritePointer(_size);
#define TRC_STREAM_PORT_ALLOCATE_DYNAMIC_EVENT(_type, _ptrData, _size) TRC_STREAM_PORT_ALLOCATE_EVENT(_type, _ptrData, _size) /* We do the same thing as for non-dynamic event sizes */
#define TRC_STREAM_PORT_COMMIT_EVENT(_ptrData, _size) /* Not needed since we write immediately into the buffer received above by TRC_STREAM_PORT_ALLOCATE_EVENT, and the TRC_STREAM_PORT_PERIODIC_SEND_DATA defined below will take care of the actual trace transfer. */
#define TRC_STREAM_PORT_READ_DATA(_ptrData, _size, _ptrBytesRead) PSoC_Receive(_ptrData, _size, _ptrBytesRead);
#define TRC_STREAM_PORT_PERIODIC_SEND_DATA(_ptrBytesSent) prvPagedEventBufferTransfer(PSoC_Transmit, _ptrBytesSent);
#define TRC_STREAM_PORT_ON_TRACE_BEGIN() { prvPagedEventBufferInit(_TzTraceData); }
#define TRC_STREAM_PORT_ON_TRACE_END() /* Do nothing */

#ifdef __cplusplus
}
#endif

#endif /* TRC_STREAMING_PORT_H */

The last thing to make this work is provide the C function to read and write the UART by modifying trcStreamingPort.c

// An adataption of the Percepio USB_CDC Port to PSoC Serial
#include "trcRecorder.h"

#if (TRC_USE_TRACEALYZER_RECORDER == 1)
#if(TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)

#include "stdint.h"

int32_t PSoC_Receive(void *data, uint32_t size, int32_t *numOfBytesReceived)
{
  
    uint8_t *myData= (uint8_t *)data;
    
    *numOfBytesReceived = 0;
    while( (*numOfBytesReceived < (int32_t)size) && UART_SpiUartGetRxBufferSize())
    {
            myData[*numOfBytesReceived] = UART_SpiUartReadRxData();
            *numOfBytesReceived += 1;
    }
	return 0; // Doesnt matter what you return... i dont think that it is checked
}

int32_t PSoC_Transmit(void* data, uint32_t size, int32_t *numOfBytesSent )
{
    UART_SpiUartPutArray((uint8_t *)data,size);
    *numOfBytesSent=size;
    
    return 0; // Doesnt matter what you return... i dont think that it is checked
}

#endif	/*(TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)*/
#endif  /*(TRC_USE_TRACEALYZER_RECORDER == 1)*/

There at two things that are a bit goofy.

  • The return values for both of these function is not used by the calling functions… and is not defined what it means.
  • The 3rd parameter of both functions is defined as int32_t, but in the TraceRecorder library it is defined as int.  This makes a warning, which I got rid of by fixing the bug in the Percepio code.

Testing

To test this you need to change the Tracealyzer settings from JLink to Serial and fix the COM port and baud rate.

Percepio Tracelyzer PSoC Setup

When I built this code originally, I tried 115200 baud.  But it didn’t work at all (it locked up FreeRTOS).  Then I tried 921600 which locked up the Tracealyzer.  I am running Tracealyzer and PSoC Creator on a Mac in a VMWare Fusion Windows 7 box and I am pretty sure that there is a USB bridging problem (I am going to try it on a Windows box).  After grinding for a while I found out that both 230400 and 460800 both worked but both showed something very funny, look at the data:

230400 Baud

Percepio Tracelyzer PSoC - Streaming Data Percepio Tracelyzer PSoC - Streaming Data

460800 Baud

Percepio Tracelyzer PSoC - Streaming Data

Percepio Tracelyzer PSoC - Streaming Data

I knew that my implementation of the Percepio Tracealyzer PSoC Streamport would be demanding on the CPU, but I did not predict that it would take 30-50% of the CPU.  This is definitely a problem as the JLink RTT Streamport only takes 0.4% of the CPU.  To fix this I am going to try using the PSoC4200M DMA to automatically transfer the buffers to the UART.  Hopefully that will make my Tracealyzer PSoC streamport better.  But that is for the next Article.

As always you can find all of these projects on the IotExpert GitHub site or git@github.com:iotexpert/PSoC-Tracelyzer.git

Article Description
Percepio Tracealyzer & PSoC An Introduction to Percepio Tracealyzer on the Cypress PSoC
Percepio Tracealyzer RTT Streamport - PSoC4200M Make the JLINK RTT Library work with Tracealyzer
Percepio Tracealyzer PSoC UART Streamport Creating a UART Streamport
Percepio Tracealyzer - Analyzing the PSoC Tracealyzer Streamport Figure out what is broken in the UART Streamport
Percepio Tracealyzer - Using PSoC DMA to Fix the UART Streamport Implementing PSoC DMA to improve the CPU Utilization
Percepio Tracealyzer - Running on PSoC6 Porting the Percepio Tracealyzer to PSoC6

Percepio Tracealyzer RTT Streamport – PSoC4200M

Summary

In the last article I showed you how to install the Percepio Tracealyzer into your PSoC FreeRTOS project using snapshot mode.   This mode is very convenient as it has little CPU impact and does not require a communication interface.  But your trace it is limited in record time by how much RAM you are willing to dedicate to the trace.   For me, this was not very much because I am using a small PSoC with limited RAM.  In this article I am going to show you how to use the Segger JLink RTT library to support the Tracealyzer RTT Streamport.  With this library built in, the RTOS events will be sent in real-time to the Pecepio Tracealyzer for analysis.

JLink Real Time Transfer (RTT) Library

The engineers at Segger had a great idea.  Really great.  Given that they had direct access to the memory of the ARM M0 (for programming) that could be read and written without CPU intervention via the Coresite Debug Access Port, wouldn’t it be nice if there was a simple way to “send” and “receive” data without using another communication peripheral on the device.

So they built the Segger Real Time Transfer (RTT) Library which works with their JLink.  Here is a picture which I got from their website.

Segger JLink RTT

I will talk more about this library in a future article.

Installing the Percepio Tracealyzer RTT Streamport

I decided to use a copy of the blinking led project (called 1-BlinkingLED) to start the new project.  To copy the project just use CTRL-C and CTRL-V then rename the project to 1-BlinkingLED_RTT.

To make all of this work you need to add the streaming include files for the Tracealyzer RTT Streamport by right clicking “Add–>Exiting Item…”

PSoC Creator Add Existing

Then selecting “TraceRecorder–>streamports–>Jlink_RTT_include”

PSoC Creator Add Existing

Next you need to update the include path for the project by right clicking on the project and selecting “Build Settings”

PSoC Creator Change Build Settings

Then add the path to the TraceRecorder\streamports\JLink_RTT\include

PSoC Creator Update Include Path for Tracelyzer RTT Streamport

Next, add the .c files for the RTT library.

PSoC Creator - Add Tracelyzer RTT Streamport Library

Now that all of the required files are part of your project, you need to modify the “trcConfig.h” to switch to the stream recording mode (line 102).

/*******************************************************************************
 * Configuration Macro: TRC_CFG_RECORDER_MODE
 *
 * Specify what recording mode to use. Snapshot means that the data is saved in
 * an internal RAM buffer, for later upload. Streaming means that the data is
 * transferred continuously to the host PC. 
 *
 * For more information, see http://percepio.com/2016/10/05/rtos-tracing/
 * and the Tracealyzer User Manual.
 *
 * Values:
 * TRC_RECORDER_MODE_SNAPSHOT
 * TRC_RECORDER_MODE_STREAMING
 ******************************************************************************/
//#define TRC_CFG_RECORDER_MODE TRC_RECORDER_MODE_SNAPSHOT
#define TRC_CFG_RECORDER_MODE TRC_RECORDER_MODE_STREAMING

My PSoC 4M only has 16K of SRAM.  So, I reduce the memory footprint of the streaming buffer by changing it to 1000 byte from 5000 bytes in trcStreamingPort.h.

/*******************************************************************************
 * Configuration Macro: TRC_CFG_RTT_BUFFER_SIZE_UP
 *
 * Defines the size of the "up" RTT buffer (target -> host) to use for writing
 * the trace data, for RTT buffer 1 or higher.
 *
 * This setting is ignored for RTT buffer 0, which can't be reconfigured
 * in runtime and therefore hard-coded to use the defines in SEGGER_RTT_Conf.h.
 *
 * Default buffer size for Tracealyzer is 5000 bytes. 
 *
 * If you have a stand-alone J-Link probe, the can be decreased to around 1 KB.
 * But integrated J-Link OB interfaces are slower and needs about 5-10 KB, 
 * depending on the amount of data produced.
 ******************************************************************************/
//#define TRC_CFG_RTT_BUFFER_SIZE_UP 5000
#define TRC_CFG_RTT_BUFFER_SIZE_UP 1000

Run Tracealyzer

After the project is updated for the Tracealyzer RTT Streamport, I can program it into my CY8CKIT-044 development kit.  The next step is to start the Tracealyzer.  If you have previously run the program it will use your previous J-Link settings.  If you have not run it before then you need to setup the J-Link Settings

Percepio Tracelyzer

I am using a CY8CKIT-044 which has a CY8C4247xxx PSoC 4200M MCU onboard.

Configure JLink for Tracelyzer RTT Streamport

I use the default settings for the Segger RTT.

Tracelyzer RTT Streamport Stream Trace Settings

Once things are setup you can “Connect to Target System…”

Percepio Tracelyzer

Then click “Start Recording”

Percepio Tracelyzer

As you are recording the Tracealyzer shows the CPU usage.  In this case it is very close to 0% as all the program does is blink the LED and then sleep for 500ms.

Percepio Tracelyzer Recording

After I stop recording I can look at the trace.   The first thing to notice in this trace is that I can look at quite a bit more data.  In this case I recorded for about 22 seconds.

Percepio Tracelyzer

In the next article I am planning on doing a Streamport based on the PSoC UART which means I will not need to use a JLink.

As always you can find all of these projects on the IotExpert GitHub site or git@github.com:iotexpert/PSoC-Tracelyzer.git

Article Description
Percepio Tracealyzer & PSoC An Introduction to Percepio Tracealyzer on the Cypress PSoC
Percepio Tracealyzer RTT Streamport - PSoC4200M Make the JLINK RTT Library work with Tracealyzer
Percepio Tracealyzer PSoC UART Streamport Creating a UART Streamport
Percepio Tracealyzer - Analyzing the PSoC Tracealyzer Streamport Figure out what is broken in the UART Streamport
Percepio Tracealyzer - Using PSoC DMA to Fix the UART Streamport Implementing PSoC DMA to improve the CPU Utilization
Percepio Tracealyzer - Running on PSoC6 Porting the Percepio Tracealyzer to PSoC6

PSoC Creator Projects

Summary

When building a PSoC Creator project there are a number of “sources” of “source code” including:

  • Cypress PSoC Component Code from the Cypress Component Library (which end up in the Generated_Source directory)
  • Your C Source code files .h/.c e.g main.c
  • Your Components from your Component Library (which end up in the Generated Source Source directory)
  • Other Libraries of code (e.g. FreeRTOS or Percepio Tracelyzer)

There are (at least) five tools which need to “know” about where the source code for your project resides including:

  • Workspace Explorer (so you can browse the files and open the code in an editor)
  • PSoC Creator Code Editor (so Intellisense works correctly)
  • GCC Compiler
  • Linker
  • Debugger

Here is a video where I talk about the files structure of PSoC Creator Projects:

PSoC Creator takes care of so many of these details automatically for you, so I have not put much thought into how these things work.  But, in the last few months, I have been building projects that use FreeRTOS, which has made me contemplate how things go together.  This is the genesis of this Article.

Lets start with a blank project (which I created for the CY8CKIT-044).  When you make this project you can see that you get:

  • A Workspace (called Workspace07) that contains one project.  The name is just a default name + a number that Creator made for you.
  • A Project (called Design01)
  • A Schematic (called TopDesign.cysch)
  • Design Wide Resources (called Design01.cydwr)
  • A folder for Header Files which contains a file called cyapicallbacks.h
  • A folder for Source Files that contains main.c

PSoC Creator Blank Project

When you look at the disk you will see a directory at the top level called “Workspace07”.  This directory contains:

  • The workspace file called Workspace07.cywrk and a user specific settings file called Workspace07.cywrk.arh (the .arh is my windows login).  This binary file contains references to all of the projects that are part of the Workspace.  Plus other Workspace configuration.
  • A directory called “Design01.cydsn”.  This directory contains everything required for the project.

PSoC Creator files in Windows Explorer

When I look in the directory called “Design01.cydsn” I see

  • Design01.cyprj (an xml file that contains all of the information about the project)
  • Design01.cydwr (an xml file that contains all of the Design Wide Resource settings)
  • The two source files main.c and cyapicallbacks.h
  • A directory called “TopDesign”

PSoC Creator - Project Directory

In the TopDesign directory you will find the TopDesign.cysch which is the binary file of the schematic.

PSoC Creator - Top Design Directory

Now that we have accounted for all of the “basic” project stuff.  I will run “Generate Application” from the build menu.

Cypress PSoC Creator Components

After the Application Generation is done you will see a bunch of more stuff in the Workspace Explorer.  Specifically a new folder called “Generated_Source”.  In that folder you will see a folder called “PSoC4” that contains a bunch of files plus some more folders.  These folders are created by the application generation process to hold the source code for components including cy_boot, cy_dmac, and cy_lfclk.  But you say, “I didn’t place any components”, and that is true,  but PSoC Creator did this automatically for you when you made the project.  These source files are used to get the PSoC booted, the linker setup, the CMSIS core definitions etc.

PSoC Creator Workspace Explorer

When you look on the disk, you will see a completely different hierarchy than you see in the Workspace Explorer.  In fact you will see all of these files in a directory called “Generated_Source/PSoC4”.  This tells us something important.  The workspace explorer gives you hierarchy so that you can see the different files grouped together logically.  BUT this hierarchy is completely unrelated to how the build process works (more on this in a minute) or how the files reside on the disk.  DANGER DANGER WILL ROGERS!!!  (these Folders are actually called “Filter Folders” and you can read about them in the PSoC Help Topic “Creating Folders”)

PSoC Creator - Workspace Explorer Generated_Source

When you place a component in the schematic (e.g. a UART) and run the build again you will find more folders & files in the Generated_Source section of the Workspace Explorer

PSoC Creator - Workspace Explorer

But when you look in Generated_Source directory on the disk, you will find ALL of those files in one directory.

PSoC Creator - Generated_Source Directory

When you place a component, PSoC Creator takes the API from the Component Library, processes it, names it correctly, adds it to your “.cyprj” file so that the Workspace Explorer can see it, then copies the code into your Generated_Source directory.  You could edit it there, but if you do, you are at risk to having it overwritten the next time you build the project.  All of the configuration you do to a component gets turned into c-source that resides in the Generated_Source directory

When you delete a component, the related generated source code (e.g., UART_1.*) won’t be visible in Workspace Explorer, but IT STILL LIVES ON DISK. This is a consequence of our legacy “merge region” support.  The user may have edited the file and PSoC Creator doesn’t want to destroy those edits.  This can cause inconsistencies between what Workspace Explorer shows the user and what the compiler actually sees:

  • PSoC Creator will NOT compile any irrelevant .c files present in the file system.
  • However, the compiler WILL see any stale .h files that happen to be lying around when it processes #includes.

So, what is a merge region?  When PSoC Creator was originally created, it was recognized that there was occasionally need for a user to put code into a generated file e.g. an interrupt handler.  And we also wanted PSoC Creator to be able to regenerate that file.  If you look around in Generated_Source files, you will find sections of code that look like lines 27-30.  If you put code between those funny looking comments, it will not be blown away when you regenerate your application.  In other words PSoC Creator preserves all of the code in merge regions.  This mode has mostly be supplanted by the use of the “cyapicallbacks.h” functionality.

/*******************************************************************************
* Function Name: isr_1_Interrupt
********************************************************************************
*
* Summary:
*   The default Interrupt Service Routine for isr_1.
*
*   Add custom code between the START and END comments to keep the next version
*   of this file from over-writing your code.
*
*   Note You may use either the default ISR by using this API, or you may define
*   your own separate ISR through ISR_StartEx().
*
* Parameters:  
*   None
*
* Return:
*   None
*
*******************************************************************************/
CY_ISR(isr_1_Interrupt)
{
    #ifdef isr_1_INTERRUPT_INTERRUPT_CALLBACK
        isr_1_Interrupt_InterruptCallback();
    #endif /* isr_1_INTERRUPT_INTERRUPT_CALLBACK */ 

    /*  Place your Interrupt code here. */
    /* `#START isr_1_Interrupt` */

    /* `#END` */
}

Your Code in C Source Files (.h/.c)

All of the files in “Header Files” and “Source Files” are considered to be owned by you.  In other words, PSoC Creator will never make changes to those files.  PSoC Creator starts by giving you copies of two template files, main.c and cyapicallbacks.h.  These files are yours to edit and you are responsible for the contents.

If you are making a project that is to big to logically fit into just main.c you may want to split it up into multiple .c and .h file.  You can do this by adding .c and .h source files to your project.  Right click the “Header Files” folder (or “Source Files”) and select “New Item”

PSoC Creator - Add Existing Item

Then enter the name of the file and select the FileType (in this case I did “blahblah.h”)

PSoC Creator - Add New Item

After doing that I will have a new file in the Workspace Explorer

PSoC Creator - Workspace Explorer Header Files

Plus I will have the same file in the Design01.cydsn directory

PSoC Creator - Windows Explorer Top Project Directory

All of the files that I add by doing “New Item” will end up in the “right” folder and reside in the project directory on the disk.

Your Components

In PSoC Creator, it is possible to create your own Components.  You can read or watch videos about this process

After you have a library with Custom Components, you can add it as a dependency to your project by right clicking on the project and selecting “Dependencies …”  Then navigating to the .cyprj file with your components.  In this case I added the IoTExpert_PSoC_Components library

PSoC Creator - Add Existing

You can see that the “IoTExpert_Components” shows up in the User Dependencies

PSoC Creator - Project Dependencies

Once this is done you will see the new Component Libraries in the Component Catalog.

PSoC Creator - Custom Component Catalog

Components from your custom libraries act exactly the same as the Cypress Components.  Specifically, after you place a custom component in your schematic, when you build the project, it will process the source code, copy it into the “Generated_Source” directory, add the files to your WorkSpace Explorer etc.

A custom component is a good way to easily add a library of source code to your project.

3rd Party Libraries

The last class of source code comes from 3rd Party Libraries.  Classically, these libraries have one more more directories with .c, .h and .a (static libraries) files.  There are some of the files which you might want to modify to configure your version of the library, there are other files that you just need to be compiled into your project.  This situation leaves you with some choices.

  • You can copy all of the library files into your project directory (then add existing item)
  • You can copy some of the library files into your project directory and leave some of the files in the library directory
  • You can add references to the library files into your project

The main issue that you need to consider is Source Code Control – Version Management of your project.  If you copy the library files into your project directories, then you are sure that they won’t change out from underneath you.  BUT, if the library has a bug fix, then you won’t automatically get it.  It is often considered a best practice to have a “single source of truth”.  When you copy files into your project, you violate that principal.  This is a choice that you will need to grapple with.

This is probably best explained with a real example, FreeRTOS.  I have been using the hybrid model.  Specifically I copy the configuration files into my project, but leave the rest of FreeRTOS in my downloaded directory and use references in my PSoC Creator Project.  The process is:

  • In the Windows Explorer copy FreeRTOSConfig.h into my project directory
  • Right click the project and “Add Existing Item”

PSoC Creator - Add FreeRTOS

Then select “FreeRTOSConfig.h” from my project directory

PSoC Creator - Add FreeRTOS

After that you can see that “FreeRTOSConfig.h” is part of my project in the “Header Files” section

PSoC Creator - Project Explorer

I like the rest of the FreeRTOS Files to be part of the project but not actually copied into my project directory.  To do this, I add the required C-Files using the same technique of “Add Existing”  To make FreeRTOS work you need to add all of the C-Files and H-Files in:

  • FreeRTOS/Source/portable/GCC/ARM_CM0
  • FreeRTOS/Source/include
  • FreeRTOS/Source/
  • FreeRTOS/Source/portable/MemMang/heap_1.c

PSoC Creator will automatically take care of telling the compiler where to get the C-Files.  However, it will not take care of the H-Files.  In order to do this you need to change the build settings to add the path to all of the H-Files that you use.  Modify the build settings by right-clicking the project and selecting “Build Settings …”

PSoC Creator - Add FreeRTOS

Then selecting the “…” on Design01 –> Arm GCC … –> Compiler –> Additional Include Directories

\PSoC Creator - Add FreeRTOS Include Directories

Then press the “New” and then the “…” to browse to the directory you want to add.

PSoC Creator - Include Directories

Finally you will end up with a window that looks like this:

PSoC Creator - FreeRTOS Include Path

And when you look at the build options you will see the “-I..\..\..\FreeRTOSv9.0.0\FreeRTOS\Source\include” is added to the compiler options (look at the little window at the bottom)

PSoC Creator - Build Settings

Thank you to Nick from the PSoC Creator Team for reviewing my Article.  He is one of the lead technical genius’ that made PSoC Creator the bad-ass software that it is.

Percepio Tracealyzer & PSoC 4200M

Summary

As you have probably noticed, I have spent a significant amount of time in the last few months doing FreeRTOS projects.  One thing that I have been continuously frustrated about is a lack of analysis tools.  How much memory am I using?  How much stack and heap are free?  How long are tasks taking?  How do you get the priorities set right?  And on and on.  A couple of weeks ago I got an email from the guys at Percepio asking me if I wanted to try out the Percepio Tracealyzer.  I said yes… but that I was really busy and it was going to take a while for me to get to it.  So now I have… and this is the first article about the Percepio Tracealyzer.  Unfortunately the story involves me burning myself with a soldering iron but I suppose that isn’t their fault.

In this series of article’s I will instrument the FreeRTOS projects that I have been showing you with the Percepio Tracealyzer Recorder Library, then run the tool to see what is going on.  In this specific Article I will show you how to get the most basic Tracealyzer functionality going on a PSoC4200M.

Percepio Tracealyzer

The way that Percepio Tracelzer works is that you install a bit of code into your project called the Tracealyzer Recorder Library.   In streaming mode, the code creates a new task in FreeRTOS called “TzCtrl” which interacts with the FreeRTOS kernel to record all of the running task information into a communication link (e.g UART, SPI, JLINK RTT, etc.)  In snapshot mode, the kernel information is just written to an SRAM buffer inside of the PSoC.

This is the architecture picture from the Percepio website:

Percepio Tracelyzer Architecture

Updating CY8CKIT-044 PSoC4200M Development Kit

To make the Percepio Tracealyzer work you need to turn the “Snapshot or streaming” line from the picture above into a real connection.  In snapshot mode there are two ways (I think) that you can do it.

  1. You can stop the processor with the debugger, then write the region of memory with the trace buffer into an “.hex” or a “.bin” file.  Then read that file into Percepio Tracealyzer.  Unfortunately the debugger in PSoC Creator cannot create binary output files of regions of memory like that… so plan 1 is out the window
  2. You can attach a Segger JLINK to the PSoC via SWD.  Then, Tracealyzer knows how to talk to the JLink to read the memory.  This is what I am going to do for this Article.

One feature that is very cool about the Snapshot methodology is that Tracealyzer can search the output file and find the trace buffer.  The trace buffer data structure is marked by something that Tracealyzer can find.

When our very good devkit team team in India built the CY8CKIT-044 (which I have used and written about quite a bit), they installed a built in debugger/programmer called “KitProg“.  But they also understood that someone might want to connect some third part debugger like the JLINK.  So… they put the footprint for a 10-pin ARM debugging port onto the board. (see it in the lower left).  Actually if you look at the board, you can see two 10-pin footprints, the one at the top is connected to the PSoC5 (which serves as the KitProg).

CY8CKIT-044 PSoC 4200M Development Kit

Before I can use a JLINK I needed to do this … which unfortunately ended with me burning myself with the soldering iron… bad Alan.

CY8CKIT-044 PSoC 4200M Development Kit

Tracealyzer Snapshot Mode on Blinking LED Project

In a previous article I talked about the organization of PSoC Creator projects, specifically how to handle the situation where you want to include .h/.c files into your project but you don’t want to modify them.  This is exactly what I will do with the Percepio Tracealyzer Recorder Library.  The library has some files which I will want to leave intact and I will just make references to them in my project including trcKernelPort.h, trcPortDefines.h etc.  And there are some files which I will want to modify, which I will copy out of the Trace Recorder Library into my project for editing trcConfig.h, trcSnapShotConfig.h and trcStreamingConfig.h

To start the first Percepio Tracealyzer example I will use the basic “Snapshot Mode”.  There is good documentation on the Percepio Tracealyzer documentation website.  I will start by copying the PSoC Creator Workspace from the FreeRTOS articles from GitHub.  It has 9 projects in it, starting with the blinking led, going to a more complicated multi-thread project.  The next step is to download the FreeRTOS Tracealyzer library from the Perceio website into a parallel directory called “TraceRecorder”.

Make a new folder for the non-changing include files called “TraceRecorder” (for the files that I don’t want to change)

PSoC Creator Project Configuration

Next I will add the files that I don’t want to change to the project so that I can see them (meaning they are just referenced by PSoC Creator)

PSoC Creator Project Configuration - Add External Files

They reside in the directory TraceRecorder/include

PSoC Creator Project Configuration - Add External Files

Once I have the unchanging .h’s into my project, I need to add their directory to the include path.  To do this right-click on the project and select “Build Settings …”

PSoC Creator Project Configuration - Add External Files

Then click “Compiler” and then the “…” on the “Additional Include Directories” line

PSoC Creator Project Configuration - Compiler Options

Navigate until you get to TraceRecoder/include then press “Select Folder”

PSoC Creator Project Configuration - Update include path

Now your include path should look like this:

PSoC Creator Project Configuration - Include Path

Next, I want to copy the configuration files in the Windows Explorer to my project directory so that they become a changeable part of they project.  They reside in TraceRecorder/config (I just did a Ctrl-C to copy)

PSoC Creator Project Configuration - Add Trace Recorder Library

You want to paste them into your project directory

PSoC Creator Project Configuration - Add External Files

Then you need to add them to the project so that you can easily edit them by right clicking on the “Header Files” folder and selecting “Add–>Existing Item”

PSoC Creator Project Configuration - Add External Files

Then selecting them out of your project directory.

PSoC Creator Project Configuration - Add External Files

Now we need to add references to all of the .c files.  Start by making a new folder for the c-files called “TraceRecorder”

PSoC Creator Project Configuration - Add TraceRecorder

Then “Add–>Existing Item…”

PSoC Creator Project Configuration - Add External Files

Select the files from the TraceRecorder directory

PSoC Creator Project Configuration - Add TraceRecorder Files

Now your project should look like this

PSoC Creator Project Configuration - Project Configuration

Your project now has all of the necessary body parts so you next will modify the source files.  Start with modifying FreeRTOSConfig.h to include the TraceRecorder Library stuff.

/* Integrates the Tracealyzer recorder with FreeRTOS */
#if ( configUSE_TRACE_FACILITY == 1 )
#include "trcRecorder.h"
#endif

Then modify the trcConfig.h so that it has access to all of the CMSIS header files.

/******************************************************************************
 * Include of processor header file
 * 
 * Here you may need to include the header file for your processor. This is 
 * required at least for the ARM Cortex-M port, that uses the ARM CMSIS API.
 * Try that in case of build problems. Otherwise, remove the #error line below.
 *****************************************************************************/
//#error "Trace Recorder: Please include your processor's header file here and remove this line."
#include <project.h>

Then tell the TraceRecorder that we are using an ARM Cortex-M

/*******************************************************************************
 * Configuration Macro: TRC_CFG_HARDWARE_PORT
 *
 * Specify what hardware port to use (i.e., the "timestamping driver").
 *
 * All ARM Cortex-M MCUs are supported by "TRC_HARDWARE_PORT_ARM_Cortex_M".
 * This port uses the DWT cycle counter for Cortex-M3/M4/M7 devices, which is
 * available on most such devices. In case your device don't have DWT support,
 * you will get an error message opening the trace. In that case, you may 
 * force the recorder to use SysTick timestamping instead, using this define:
 *
 * #define TRC_CFG_ARM_CM_USE_SYSTICK
 *
 * For ARM Cortex-M0/M0+ devices, SysTick mode is used automatically.
 *
 * See trcHardwarePort.h for available ports and information on how to 
 * define your own port, if not already present.
 ******************************************************************************/
//#define TRC_CFG_HARDWARE_PORT TRC_HARDWARE_PORT_NOT_SET
#define TRC_CFG_HARDWARE_PORT TRC_HARDWARE_PORT_ARM_Cortex_M

Now, you need to modify the project’s stack and heap size setup

PSoC Creator Project Configuration - Design Wide Resources

The default snapshot buffer is to big to fit into PSoC SRAM, so I change the size to 400 records

/*******************************************************************************
 * TRC_CFG_EVENT_BUFFER_SIZE
 *
 * Macro which should be defined as an integer value.
 *
 * This defines the capacity of the event buffer, i.e., the number of records
 * it may store. Most events use one record (4 byte), although some events 
 * require multiple 4-byte records. You should adjust this to the amount of RAM
 * available in the target system.
 * 
 * Default value is 1000, which means that 4000 bytes is allocated for the
 * event buffer.
 ******************************************************************************/
#define TRC_CFG_EVENT_BUFFER_SIZE 400

Finally modify main to start the Trace Recorder (vTraceEnable on line 40)

int main(void)
{
    CyGlobalIntEnable; /* Enable global interrupts. */
    
    setupFreeRTOS();
    vTraceEnable(TRC_START);

    /* Create LED task, which will blink the RED LED */
    xTaskCreate(
        LED_Task,       /* Task function */
        "LED Blink",    /* Task name (string) */
        200,            /* Task stack, allocated from heap */
        0,              /* No param passed to task function */
        1,              /* Low priority */
        0 );            /* Not using the task handle */
      
    vTaskStartScheduler();
    while(1); // get rid of the stupid warning
}

Testing the Output

After all of the setup is done you can build and program the development kit.

PSoC Creator Program Project

Plug in the Segger J-Link

CY8CKIT-044 + JLINK

Start Tracealyzer then setup the J-Link (click on J-Link Settings…)

Percepio Tracelyzer

Select “Select Device…”

Percepio Tracelyzer - JLINK Settings

Filter the list to “cypress” then choose the “CY8C4247xxx” (which is the chip that is on the C8CKIT-044)

Percepio Tracelyzer - JLINK Settings Select Device

Then Select “Jink->Read Trace”

Percepio Tracelyzer - Read Trace

Accept the defaults (this window only is only brought up the first time)

Percepio Tracelyzer - JLINK Memory Region

Then you will end up with a screen like this.  Each stripe of white/gray is 1 second in time.  The yellow line is where the startup occurred.  The red lines are where the “LED Blink” task was running.  This seems to make sense as you get a tiny red line 2x/second (remember in the source code we have a 500ms delay so that makes sense).

Percepio Tracelyzer - Console

Next I press the reset button on the devkit and re-run the trace.  Then I click on the second red line and the window on the right gives me information about that task.  You can see that the task ran for 53uS and took 23uS to start (time taken up in the FreeRTOS scheduler and Percepio Tracealyzer Recorder Library)

Percepio Tracelyzer - Console

Conclusion

Obviously the snapshot mode is limited by the size of the RAM buffer that you allocate but it saves you the hardware resources and timing constraints that are required to stream FreeRTOS data.  In the next several articles I will show you how to:

  • Use Segger JLINK RTT streaming
  • Make a streaming port
  • Use some of the other screens in the Percepio Tracealyzer

As always you can find all of these projects on the IotExpert GitHub site or git@github.com:iotexpert/PSoC-Tracelyzer.git

Article Description
Percepio Tracealyzer & PSoC An Introduction to Percepio Tracealyzer on the Cypress PSoC
Percepio Tracealyzer RTT Streamport - PSoC4200M Make the JLINK RTT Library work with Tracealyzer
Percepio Tracealyzer PSoC UART Streamport Creating a UART Streamport
Percepio Tracealyzer - Analyzing the PSoC Tracealyzer Streamport Figure out what is broken in the UART Streamport
Percepio Tracealyzer - Using PSoC DMA to Fix the UART Streamport Implementing PSoC DMA to improve the CPU Utilization
Percepio Tracealyzer - Running on PSoC6 Porting the Percepio Tracealyzer to PSoC6

IoT Bar

Its not really IoT… but good for the soul.  Have patience… I have some good stuff coming next week.

PSoC FreeRTOS & Kionix KXTJ2 Accelerometer

Summary

In the previous PSoC FreeRTOS article I showed you a scheme for sharing the I2C between multiple tasks by sending “I2C Transactions” to a single I2C Master thread.  In this article I will modify the Accelerometer task to use the hardware interrupt pin from the KXTJ2-1009 to only read data when there is new data to be read (i.e. stop polling).  I will also modify the project to use “kxtj2.h” a header file which I downloaded from Rohm’s website with all of the register definitions.

Updates to the PSoC FreeRTOS Project Schematics

When I was looking at the schematics for the CY8CKIT-044 I noticed that the KXTJ2-1009 had one of the pins attached to the PSoC P1[6].  Even better that pin was labeled “INT”.  In the original PSoC FreeRTOS project I polled the values from the accelerometer, which is almost always a bad idea.

 

CY8CKIT-044 Schematic

Then when you look in the data sheet you see that you ask for an interrupt when the data is ready “DRDYE”

KTXJ2-1009 Datasheet

And you can program the INT pin to behave how you want.  I chose:

  • IEN=1 (Enable interrupts)
  • IEA=1 (Make the interrupt active high)
  • IEL=1 (Pulse the pin)

KTXJ2-1009 Datasheet

After I figured all of that out, I modify the PSoC FreeRTOS Creator schematic to have the accel_int_pin (aka P1[6]) attached to an interrupt.

PSoC FreeRTOS Schematic

Then I write an ISR to handle the interrupt, which just resets the pin interrupt and sets a semaphore.

CY_ISR(accelIntHandler)
{
    accel_int_pin_ClearInterrupt();
    xSemaphoreGiveFromISR(accelIntSemaphore,NULL);
}

Finally register the interrupt and the start the semaphore

   accelIntSemaphore = xSemaphoreCreateBinary(); // Signal from the Accel that it is ready
   accel_int_StartEx(accelIntHandler);

Using the “kxtj2.h” Header File

When I looked on the Kionix website for the KXTJ2-1009 datasheet I noticed that there was a download link… which I assumed would take me to a place where I could download the datasheet.

KTXJ2-1009 Datasheet

But when I go to the download page I got the  pleasant surprise of finding a bunch of driver files… but even better there was a “Register Definitions .h/.py”

KTXJ2-1009 Datasheet Download

This file had a bunch of #defines for the registers in the chip.

/* registers */
// output register x
#define KXTJ2_OUTX_L 0x06
#define KXTJ2_OUTX_H 0x07
// output register y
#define KXTJ2_OUTY_L 0x08
#define KXTJ2_OUTY_H 0x09
// output register z
#define KXTJ2_OUTZ_L 0x0A
#define KXTJ2_OUTZ_H 0x0B
// This register can be used to verify proper integrated circuit functionality
#define KXTJ2_DCST_RESP 0x0C
// This register can be used for supplier recognition, as it can be factory written to a known byte value.
#define KXTJ2_WHO_AM_I 0x0F
// This register reports which function caused an interrupt.
#define KXTJ2_INT_SOURCE1 0x16
// This register reports the axis and direction of detected motion
#define KXTJ2_INT_SOURCE2 0x17
// This register reports the status of the interrupt

In addition it has the the bit fields for the registers

// 12.5Hz
#define KXTJ2_DATA_CTRL_REG_OSA_12P5 (0x00 << 0)
// 25Hz
#define KXTJ2_DATA_CTRL_REG_OSA_25 (0x01 << 0)
// 50Hz
#define KXTJ2_DATA_CTRL_REG_OSA_50 (0x02 << 0)
// 100Hz
#define KXTJ2_DATA_CTRL_REG_OSA_100 (0x03 << 0)
// 200Hz
#define KXTJ2_DATA_CTRL_REG_OSA_200 (0x04 << 0)
// 400Hz
#define KXTJ2_DATA_CTRL_REG_OSA_400 (0x05 << 0)
// 800Hz
#define KXTJ2_DATA_CTRL_REG_OSA_800 (0x06 << 0)
// 1600Hz
#define KXTJ2_DATA_CTRL_REG_OSA_1600 (0x07 << 0)
// 0.78Hz
#define KXTJ2_DATA_CTRL_REG_OSA_0P781 (0x08 << 0)
// 1.563Hz
#define KXTJ2_DATA_CTRL_REG_OSA_1P563 (0x09 << 0)
// 3.125Hz
#define KXTJ2_DATA_CTRL_REG_OSA_3P125 (0x0A << 0)
// 6.25Hz
#define KXTJ2_DATA_CTRL_REG_OSA_6P25 (0x0B << 0)

To use it all I did was add it to my project by right clicking on Header Files and selecting “Add–>Existing Item”

Add header file to PSoC FreeRTOS Project

Then I add the include “ktxk2.h” to the includes

#include "kxtj2.h"

Finally I can use the #define names instead of the hardcoded values for example to reset the chip you can write to the KXTJ2_CTRL_REG with the value  KXTJ2_CTRL_REG _SRST

    setupData[0] = KXTJ2_CTRL_REG2_SRST; // Software reset
    mytransaction.i2cm_register = KXTJ2_CTRL_REG2; 

Updates to the Accelerometer Task

With all of the updates in place I can now make the modifications to the PSoC FreeRTOS accel_Task to use the new interrupt structure.  The first thing to do is write into the reset register to force a software reboot.  The datasheet says that you need to:

  • Write 0x00 into the CTRL_REG1
  • Write KXTJ2_CTRL_REG2_SRST into KXTJ2_CTRL_REG2
  • Then WAIT until the value in KXTJ2_CTRL_REG2 is 0x0
    // Setup for initialization
    uint8_t setupData[1];
    mytransaction.i2cm_method = I2CM_WRITE;
    mytransaction.i2cm_byteNum = 1;
    mytransaction.i2cm_doneSemaphore = mySemaphore;
    mytransaction.i2cm_bytes = setupData;
    
    // reset the accelerometer
    setupData[0] = 0b00000000; 
    mytransaction.i2cm_register = KXTJ2_CTRL_REG1; 
    i2cm_runTransaction(&mytransaction);
  
    setupData[0] = KXTJ2_CTRL_REG2_SRST; // Software reset
    mytransaction.i2cm_register = KXTJ2_CTRL_REG2; 
    i2cm_runTransaction(&mytransaction);

    vTaskDelay(10); // From the datasheet power up time

    while(1) // delay until the accelerometer is reset
    {
        mytransaction.i2cm_method = I2CM_READ;  
        mytransaction.i2cm_register = KXTJ2_CTRL_REG2;
        i2cm_runTransaction(&mytransaction);
        
        if(setupData[0] & KXTJ2_CTRL_REG2_SRST)
        {
            vTaskDelay(10); // backup 10 ms
        }
        else
            break;  
    }
    

After the accelerometer chip is reset, then initialize the chip

    // initialize the interrupt 
    setupData[0] = KXTJ2_INT_CTRL_REG1_IEN | KXTJ2_INT_CTRL_REG1_IEA | KXTJ2_INT_CTRL_REG1_IEL;
    mytransaction.i2cm_register = KXTJ2_INT_CTRL_REG1; 
    i2cm_runTransaction(&mytransaction);
  
    // initialize the  DATA_CTRL_REG
    setupData[0] = KXTJ2_DATA_CTRL_REG_OSA_12P5;      
    mytransaction.i2cm_register = KXTJ2_DATA_CTRL_REG; 
    i2cm_runTransaction(&mytransaction);
 
    // Initalize the acceleromter CTRL_REG_1
    setupData[0] =   KXTJ2_CTRL_REG1_PC | KXTJ2_CTRL_REG1_RES | KXTJ2_CTRL_REG1_DRDYE | KXTJ2_CTRL_REG1_GSEL_2G  ; 
    mytransaction.i2cm_register = KXTJ2_CTRL_REG1; 
    i2cm_runTransaction(&mytransaction);
    
    // Setup for repeated reads
    mytransaction.i2cm_method = I2CM_READ;
    mytransaction.i2cm_register = 0x06;
    mytransaction.i2cm_byteNum = sizeof(myData);
    mytransaction.i2cm_doneSemaphore = mySemaphore;
    mytransaction.i2cm_bytes = (uint8_t *)&myData;

After that you can wait for the semaphore, then get the data

    while(1)  // Run the same transaction over and over
    {
        xSemaphoreTake(accelIntSemaphore,portMAX_DELAY);
        
        i2cm_runTransaction(&mytransaction);
        myData.x /= 16;  // The KXTJ2 Datasheet say lower 4 bits are X
        myData.y /= 16;  // The KXTJ2 Datasheet say lower 4 bits are X
        myData.z /= 16;  // The KXTJ2 Datasheet say lower 4 bits are X
        xs = (myData.x < 0? -1:1);  // Find the XSign
        ys = (myData.y < 0? -1:1);  // Find the YSign
        zs = (myData.z < 0? -1:1);  // Find the ZSign
            
        // The 1024 is a hardcode based on the range of the acceleromter
        x = (int)((float)myData.x / 1024.0 * 10.0) * xs; // Turn it into integer G * 10
        y = (int)((float)myData.y / 1024.0 * 10.0) * ys; // Turn it into integer G * 10
        z = (int)((float)myData.z / 1024.0 * 10.0) * zs; // Turn it into integer G * 10
       
        // Format data in x.x  
        sprintf(buff,"x=%s%d.%dg\ty=%s%d.%dg\tz=%s%d.%dg\n",(xs<0?"-":""),x/10,x%10,(ys<0?"-":""),y/10,y%10,(zs<0?"-":""),z/10,z%10);
        UART_UartPutString(buff); 
    }

As always you can git this PSoC FreeRTOS project at the IoT Expert GitHub site or git@github.com:iotexpert/PSoC-FreeRTOS-Examples.git The project name is “8-Shared-I2C_Interrupt”

Topic Description
FreeRTOS: A PSoC4 FreeRTOS Port An introduction to making FreeRTOS work on PSoC 4
FreeRTOS PSoC Examples Using multiple tasks in FreeRTOS
FreeRTOS Queue Example Using a queue to communicate between tasks
PSoC 6 FreeRTOS - The First Example Booting FreeRTOS on PSoC 6
FreeRTOS Binary Semaphore An first example of a binary semaphore
FreeRTOS Binary Semaphore (Part 2) Removing polling in the UART Task
FreeRTOS Counting Semaphore An example using a counting semaphore
PSoC FreeRTOS Reading I2C Sensors with a shared I2C Bus
PSoC FreeRTOS Task Notify A light weight scheme to replace Semaphores
PSoC FreeRTOS Task Notification Values A very light weight method to transfer one word of information into a task

Leviton HomeKit D15S Light Switch – WICED WiFi

Summary

A couple of week ago I was in San Jose teaching a WICED WiFi programming class.  One of the bad-ass WICED Applications Engineers told me that Leviton was shipping a new Leviton HomeKit Light Switch that used WICED WiFi and Bluetooth called the Leviton DS15.  What was even cooler was the he had done a decent amount of the design with them.  So, I ordered a few of them from amazon.com to try out.  This started my normal spectacle of house-wiring that is a spiral of me shocking myself, bleeding, cussing and worst of all spilling my beer.  You would think that a guy with a degree from Georgia Tech and 25 years as a practicing engineer would know better… but props to those electricians out there as they have mad wiring skills.

The Panel

I know that it should be obvious.  Really, I do know.  But every time I start working on wiring in my house I think… “Oh I just have 1 or 2 things to do I don’t need to turn off the breaker.”  And literally every damn time, I shock the piss out of myself.  So, today I decided to turn over a new leaf and turn off the breaker.  What was interesting this time was I also decided to use my meter to make sure that the breaker was off… and today I discovered that the label on the panel in my barn is wrong.  Damn that electrician… I take back everything nice I said about electricians.  (That ugly handwriting is mine fixing the label)

electric panel

Installing the Leviton HomeKit Light Switch

I bought a bunch of the the Leviton HomeKit Decora switches from Amazon.com.  They are a normal looking paddle light switches, but they come with WiFi and Bluetooth and are compatible with Apple HomeKit.  This means you don’t need a special app on your phone to use them, and hopefully that means that the wife-factor is low enough.  (A hint for all you guys out there… if the lights don’t come on when your wife clicks them… you had better have a good couch).   Originally I had installed ZWave Light Switches in the barn as my son always leaves the stupid lights on, but I wanted to try a product that had chips in it that I work on.  Here we go:

Leviton HomeKit Light Switch

When you open the box you get the normal book worth of instructions, in 5 languages (or something).  You also get a cream colored faceplate.  The paper on the upper left of the picture shows the serial number that you scan in with the camera in the Leviton app to attach to your device to HomeKit.

Leviton HomeKit inside the box

Here is a zoom in on just the light switch.

Leviton HomeKit Light Switch

Here is a picture of the light switches in the box.  One of the things that I always struggle with is getting all of the wires to fit neatly in the box.  This box was originally done old school (only switching the hot)… which doesn’t work with these light switches.

Leviton HomeKit Light Switch Installed

Once you have the switches installed, you turn the breaker back on and run the Leviton App. The App will let you add the switch to HomeKit by scanning the numbers with your camera.

Leviton HomeKit Decora App

Once paired you can control them with the Leviton App.

Leviton HomeKit Decora App

Or with the HomeKit App.

Apple Homekit App

I did notice that there is now two generations of light switches 6 inches from where they were originally installed.   I suppose I should have cleaned that up.

Installation Aftermath

Finally… dont cry over spilled beer (actually do.. as it is a really good West 6th IPA)

West 6th IPA

 

PSoC FreeRTOS – Sharing the I2C Bus

Summary

I have gotten quite a few questions about my PSoC FreeRTOS series of Articles.  One question was: “I have a bunch of different I2C sensors, what is a good PSoC FreeRTOS scheme to share the I2C bus?”  When I thought about this question there were a number of possible firmware architectures that could be used:

  1. Each sensor has a thread, and there is a global Mutex to lock/unlock the I2C bus
  2. There is single thread that reads and writes to all of the sensors (oh…wait… that looks like the old bare metal while(1); )
  3. There is a single I2C thread that can take requests execute them, and then feed data back to the calling thread

After thinking about it a bit, I decided to use the 3rd scheme as it allows me to

  • Reuse the I2C interface code (all the sensors have a register map that you read/write)
  • Handle all of the timing issues in one place (instead of duplicated)
  • Isolate the I2C interface from all of the threads (could be replaced with SPI or something else later)

In this article I will show you:

  • The register based I2C interface that is in common use with sensors
  • The design of the PSoC FreeRTOS firmware with a single I2C interface thread
  • The PSoC FreeRTOS firmware implementation
  • A test case using the CY8CKIT-044

Interfacing with I2C Sensor Registers using PSoC FreeRTOS

The CY8CKIT-044 (on of my favorite Cypress kits) has two devices attached to the I2C bus, so it made a perfect test platform.  On the front there is a Cypress FM24V10 FRAM and a Kionix KXTJ2-1009 I2C Accelerometer.

CY8CKIT-044 Development Kit Front

And on the back there is a nice little picture on the silkscreen that gives the FRAM I2C Address as 0x50, the I2C Address of the Accelerometer as 0X0F and the I2C pins as P4.0/P4.1 CY8CKIT-044 Development Kit Back

When I probe the I2C Bus using the bridge control panel I see that three I2C devices respond, 0x0F (the KXTJ2-1009), 0x50/0x51 (the FRAM.)

Bridge control panel probing I2C bus on CY8CKIT-044

So, how do you talk to the devices?  It turns out that both of these devices respond to the very common I2C device scheme which is called “EZI2C” inside of Cypress.  The scheme goes like this:

  • The chip is organized into registers
  • Each register has an address
  • Addresses are either 8-bits or 16-bits
  • To write an address you can send a string of bytes like:  I2C Start, I2C Address + W, Register Address,  Value to write, Stop
  • To read an address you can send a string of bytes like:  I2C Start, I2C Address + W, Register Address, Restart, Read, Stop

A simplification is that you can keep writing (or reading) and it will automatically goes to the next address without you having to send the next address. The easiest thing to do is show an example with the FRAM.

The FRAM has 128K addresses so it uses 16-bit addresses.  For example to save the values 5,6,7,8 into the register 0x0123 you would send:

  • 0x50, W, 0x01, 0x02, 0x05, 0x06, 0x07, 0x08, Stop  (in the bridge control panel the command is W 50 1 2 5 6 7 8 p)

To read back those addresses you would send

  • 0x50, W, 0x01, 0x02, restart, read read read read Stop  (in the bridge control panel the command is W 50 1 2 R 50 x x x x p)

Writing to Cypress FRAM using Bridge Control Panel

The interface is similar for the Kionix KXTJ2-1009.  When you look at the datasheet you will see on page 17 their description of the EZI2C protocol:

Kionix KXTJ2-1009 Datasheet

Then on page 20 they start describing the registers, and on page 21 they describe two registers (called DCST_RESP and WHO_AM_I) that will always respond with known values.

Kionix KXTJ2-1009 Datasheet

To verify the operation I send read commands using the Bridge Control panel to those registers, which respond with 55 and 9 just like the datasheet says that they should.

Reading from Kionix KXTJ2-1009 Using Bridge Control Panel

Designing PSoC FreeRTOS FW for I2C Register Based Sensors

From the previous section(s) we know that

  1. Two totally different devices, a memory and an accelerometer, can be accessed using exactly the same protocol
  2. It may take a while to complete I2C transactions (4 bytes @ 400kb/s = 87.5uS).
  3. The I2C master is a “shared” interface on the board, but multiple threads may want to perform transactions

These facts lead up to the conclusion that it would be nice to:

  • Have a standard software interface to I2C devices that use the EZI2C protocol
  • Have a non-blocking thread to run the interface
  • Share the I2C
  • Use PSoC FreeRTOS (the whole point)

With all of that in mind I created “i2cmaster.h”, the public interface to a PSoC FreeRTOS thread that will run the EZI2C protocol.  It defines two public functions

  • i2cm_Task – The thread that will need to be started to run all of the transactions
  • i2cm_runTransaction – The thread safe public interface which will send the transaction to the i2cm_Task

To run a transaction you need to have a transaction.  I defined a new type called “i2cm_transaction”.  This type is a structure that contains all of the information that is required to perform a transaction.  The input is split into three sections:

  • The I2C Address, the Register Address (and type 8-bit or 16-bit), and if the transaction is a Read or a Write
  • The number of bytes you want to read/write and a pointer to the data
  • The number of bytes that were processed (an output of the task)… plus an optional semaphore that will be given if you want a blocking transaction
#include <project.h>
#include "FreeRTOS.h"
#include "semphr.h"

#ifndef I2C_MASTER_H
#define I2C_MASTER_H

    
typedef enum i2cm_transactionMethod {
    I2CM_READ,
    I2CM_WRITE
} i2cm_transactionMethod_t;

typedef enum i2cm_registerAddresType {
    I2CM_BIT8,
    I2CM_BIT16
 
} i2cm_registerAddressType_t;


typedef struct i2cm_transaction {
    i2cm_transactionMethod_t i2cm_method;        // I2CM_READ or I2CM_WRITE
    uint8_t i2cm_address;                        // The I2C Address of the slave
    i2cm_registerAddressType_t i2cm_regType;     // I2CM_8BIT or I2CM_16BIT
    uint16_t i2cm_register;                      // The register in the slave
    
    uint8_t *i2cm_bytes;                         // A pointer to the data to be written (or a place to save the data)
    int i2cm_byteNum;                            // How many bytes are in the request

    int *i2cm_bytesProcessed;                    // A return value with the number of bytes written 
    SemaphoreHandle_t i2cm_doneSemaphore;        // If you want a semaphore flaging that the transaction is done
 
} i2cm_transaction_t;

void i2m_Task(void *arg);                  // The main thread function... you should start it in the RTOS

void i2cm_runTransaction(i2cm_transaction_t *i2cm_Transaction); // The public interface

#endif

With the public interface setup you will be able to run code that does exactly the same thing as you did in the bridge control panel.  For instance you can query the accelerometer “WHO_AM_I” register:

                    mytransaction.i2cm_method = I2CM_READ;
                    mytransaction.i2cm_address = 0x0F;            // Acelleromter I2C Address
                    mytransaction.i2cm_regType = I2CM_BIT8;       // 8-bit addressing
                    mytransaction.i2cm_register = 0x0F;           // WHO_AM_I Register
               
                    mytransaction.i2cm_byteNum = 1;               // One byte
                    mytransaction.i2cm_bytes = data;
               
                    mytransaction.i2cm_bytesProcessed = &byteCount;
                    mytransaction.i2cm_doneSemaphore = mySemaphore;
                    i2cm_runTransaction(&mytransaction);
                    
                    sprintf(buff,"Bytes=%d WHO_AM_I=0x%02X\n",byteCount,data[0]);
                    UART_UartPutString(buff);          

Which will yield exactly the same result as the bridge control panel did:

PSoC FreeRTOS: I2C Thread output from Kionix KXTJ2-1009

Implementing a PSoC FreeRTOS I2C Master Library

From the previous section we know the public interface.  But how does it work?  When the PSoC FreeRTOS i2cm_Task starts it:

  • Starts up the hardware I2C block
  • It makes a queue.  The queue will hold transactions which are waiting to be processed.  This is how multiple processes will put requested transactions into the queue, and the I2C master will deal with them one at a time in the order they were placed in the queue.
  • It starts up the infinite loop and waits for a transaction to be placed in the queue.
void i2cm_Task(void *arg)
{
    
    // The argument is the size of the queue
    uint32_t queueSize = (uint32_t)arg; // cast the arg
    
    I2C_Start(); // turn on the I2C Master
     
    i2cm_transaction_t i2cm_transaction; // A scratch transaction
    i2cm_transactionQueue = xQueueCreate(queueSize, sizeof(i2cm_transaction_t));
    
    uint32_t rval; // all of the I2C functions return a uint32_t
    
    while(1)
    {
        int i;
 
        // Wait until something gets put in the queue
        if(xQueueReceive(i2cm_transactionQueue,&i2cm_transaction,portMAX_DELAY) == pdTRUE)

The public interface to the whole system is i2cm_runTransaction.  It takes the transaction structure and pushes it onto the queue for the main thread to process.  If the user has asked to wait for completion then it also holds until the semaphore is given by the main loop.

// the i2cm_runTransaction function is the public interace to the system
// This function is thread safe (it can be called from any thread)
// It will queue up an I2C tranaction and then wait (if there is a semaphore handle)
void i2cm_runTransaction(i2cm_transaction_t *i2cm_transaction)
{
    if(xQueueSend(i2cm_transactionQueue,i2cm_transaction,portMAX_DELAY) != pdTRUE)
    {
        // Highly bad
        CYASSERT(0); // 
    }
    if(i2cm_transaction->i2cm_doneSemaphore)
        xSemaphoreTake(i2cm_transaction->i2cm_doneSemaphore,portMAX_DELAY);
}

The last part of the system is the main transaction processing loop which:

  • Waits for a transaction
  • Sends a start, then write the I2C address and register address (lines 65-75)
  • If it is a write, then write the bytes (lines 80-85)
  • If it is a read, then read then read bytes (lines 89-102)
  • Send a stop (lines 105-106)
  • If the user asked for a semaphore, give it. (lines 112-113)
        // Wait until something gets put in the queue
        if(xQueueReceive(i2cm_transactionQueue,&i2cm_transaction,portMAX_DELAY) == pdTRUE)
        {
            // Begining of an I2C transaction
            *i2cm_transaction.i2cm_bytesProcessed = 0;
            // First write the register address
            rval = I2C_I2CMasterSendStart(i2cm_transaction.i2cm_address,I2C_I2C_WRITE_XFER_MODE);
            if(rval != I2C_I2C_MSTR_NO_ERROR) goto cleanup;
            
            if(i2cm_transaction.i2cm_regType == I2CM_BIT16) // if a 16 bit register then send the high
            {
                rval = I2C_I2CMasterWriteByte((i2cm_transaction.i2cm_register >> 8) & 0xFF);
                if(rval != I2C_I2C_MSTR_NO_ERROR) goto cleanup;
            }
            rval = I2C_I2CMasterWriteByte((i2cm_transaction.i2cm_register ) & 0xFF); // send the low byte
            if(rval != I2C_I2C_MSTR_NO_ERROR) goto cleanup;
            
            // if w send ...
            switch(i2cm_transaction.i2cm_method) // Look at the type of transaction they want to do...
            {
                case I2CM_WRITE:  // If it is a write... then just send out the bytes
                for(i=0; i < i2cm_transaction.i2cm_byteNum;i++)
                {
                    rval = I2C_I2CMasterWriteByte(i2cm_transaction.i2cm_bytes[i]);
                    if(rval != I2C_I2C_MSTR_NO_ERROR) goto cleanup;
                    *i2cm_transaction.i2cm_bytesProcessed += 1;
                }
                break;
            
                case I2CM_READ: // If it is a read.. then do a restart with READ... then read n-1 bytes
                rval = I2C_I2CMasterSendRestart(i2cm_transaction.i2cm_address,I2C_I2C_READ_XFER_MODE);
                if(rval != I2C_I2C_MSTR_NO_ERROR) goto cleanup;
                for(i=0; i < i2cm_transaction.i2cm_byteNum-1;i++)
                {
                    i2cm_transaction.i2cm_bytes[i] = I2C_I2CMasterReadByte(I2C_I2C_ACK_DATA);
                    if(i2cm_transaction.i2cm_bytes[i] & 0x10000000) goto cleanup;
                    *i2cm_transaction.i2cm_bytesProcessed += 1;
                }
                // Then read the last byte and NAK (saying you are done)
                i2cm_transaction.i2cm_bytes[i2cm_transaction.i2cm_byteNum-1] = I2C_I2CMasterReadByte(I2C_I2C_NAK_DATA);
                if(i2cm_transaction.i2cm_bytes[i2cm_transaction.i2cm_byteNum-1] & 0x10000000) goto cleanup;
                *i2cm_transaction.i2cm_bytesProcessed += 1;
                break;
            }

            rval = I2C_I2CMasterSendStop();
            if(rval != I2C_I2C_MSTR_NO_ERROR) goto cleanup;

            cleanup:
            CYASSERT(rval == 0); // something really bad happend
          
           // If they ask for a semphore when done... then give it
            if(i2cm_transaction.i2cm_doneSemaphore)
                xSemaphoreGive(i2cm_transaction.i2cm_doneSemaphore);     
        }

I2C Sensor Library on the CY8CKIT-044 (FRAM)

In order to test the FRAM  I define a buffer in the RAM of the PSoC called “data”.  Then I setup three commands that can be executed from the UART Thread which will:

  • q – read 4 bytes from register 0x0102 into the data[] array
  • w -write 4 bytes from the data[] array into the FRAM register 0x0102
  • i – increment the values in the data[] array.

The code is simple:

           case 'q':
                    mytransaction.i2cm_address = 0x50;
                    mytransaction.i2cm_regType = I2CM_BIT16;
                    mytransaction.i2cm_byteNum = 4;
                    mytransaction.i2cm_register = 0x0102;
                    mytransaction.i2cm_method = I2CM_READ;
                    mytransaction.i2cm_bytesProcessed = &byteCount;
                    mytransaction.i2cm_bytes = data;
                    mytransaction.i2cm_doneSemaphore = mySemaphore;
                    i2cm_runTransaction(&mytransaction);
                    sprintf(buff,"Bytes=%d 0=%d 1=%d 2=%d 3=%d\n",byteCount,data[0],data[1],data[2],data[3]);
                    UART_UartPutString(buff);                  
            break;
            case 'i': // This will increment the values (that you read presumably from the FRAM
                    data[0] += 1;
                    data[1] += 1;
                    data[2] += 1;
                    data[3] += 1;
                    sprintf(buff,"0=%d 1=%d 2=%d 3=%d\n",data[0],data[1],data[2],data[3]);
                    UART_UartPutString(buff);
            break;
           
            case 'w': //This will write 4 values to register 0 in the FRAM
                    mytransaction.i2cm_address = 0x50;
                    mytransaction.i2cm_regType = I2CM_BIT16;
                    mytransaction.i2cm_byteNum = 4;
                    mytransaction.i2cm_register = 0x0102;
                    mytransaction.i2cm_method = I2CM_WRITE;
                    mytransaction.i2cm_bytesProcessed = &byteCount;
                    mytransaction.i2cm_bytes = data;
                    mytransaction.i2cm_doneSemaphore = mySemaphore;
                    i2cm_runTransaction(&mytransaction);
                    sprintf(buff,"Wrote %d bytes\n",byteCount);
                    UART_UartPutString(buff);
            break;

To test:

  • Press ‘q’ to read from the FRAM into data[]
  • Press ‘i’ to increment the values in data[]
  • Press ‘w’ to write the data[] back into the FRAM
  • Press ‘q’ to make sure that the values were written
  • Use the bridge control panel to read the data to make sure that it is right.

PSoC FreeRTOS: I2C Thread output from Cypress FRAM

Read/Write from Bridge Control Panel to Cypress FRAM

I2C Sensor Library on the CY8CKIT-044 (Accelerometer)

Finally, to test the Accelerometer I create a PSoC FreeRTOS thread which starts up and turns on the Accelerometer.  To turn on the accelerometer you need to write a 0b1000000 to register 0x1b (called the CTRL_REG_1)

// This task manages the accelerometer
// 
void accel_Task(void *arg)
{
    (void)arg;
    SemaphoreHandle_t mySemaphore;
    i2cm_transaction_t mytransaction;
    char buff[128];
    int x,y,z;
    int xs,ys,zs;
    
    int byteCount;
    accel_t myData;
    
    mySemaphore = xSemaphoreCreateBinary();
     
    // True of all read/writes
    mytransaction.i2cm_address = 0x0F;
    mytransaction.i2cm_regType = I2CM_BIT8;
    mytransaction.i2cm_bytesProcessed = &byteCount;
    
    // Initalize the acceleromter
    uint8_t setupData[] = {0b10000000};
    mytransaction.i2cm_method = I2CM_WRITE;
    mytransaction.i2cm_register = 0x1b; // CTRL_REG_1
    mytransaction.i2cm_byteNum = sizeof(setupData);
    mytransaction.i2cm_doneSemaphore = mySemaphore;
    mytransaction.i2cm_bytes = setupData;
    i2cm_runTransaction(&mytransaction);

Once the accelerometer is turned on, it will update 6 registers called XOUT_L/XOUT_H, YOUT_L/YOUT_Z, XOUT_L/ZOUT_H with the current X,Y and Z acceleration.  The data will be in the form of a 12-bit signed integer, left aligned (in other words the 4 least significant bits will be nothing).  I create a structure that I will use to hold the acceleration data.  Notice that I used “CY_PACKED” so that it will be not padded by the compiler.

CY_PACKED typedef struct accel {
    int16_t x;
    int16_t y;
    int16_t z;
} CY_PACKED_ATTR accel_t;

Then I set up a read transaction of those registers, which are conveniently all right next to each other so you can read 6 consecutive bytes.

   // Setup for repeated reads
    mytransaction.i2cm_method = I2CM_READ;
    mytransaction.i2cm_register = 0x06;
    mytransaction.i2cm_byteNum = sizeof(myData);
    mytransaction.i2cm_doneSemaphore = mySemaphore;
    mytransaction.i2cm_bytes = (uint8_t *)&myData;

Finally I repeatedly read the registers and print out the results.  The only trick is that I didn’t enable the floating point output libraries (they are huge), so I manually convert the floats to ints to be printed out.

    while(1)  // Run the same transaction over and over
    {
        i2cm_runTransaction(&mytransaction);
        myData.x /= 16;  // The KXTJ2 Datasheet say lower 4 bits are X
        myData.y /= 16;  // The KXTJ2 Datasheet say lower 4 bits are X
        myData.z /= 16;  // The KXTJ2 Datasheet say lower 4 bits are X
        xs = (myData.x < 0? -1:1);  // Find the XSign
        ys = (myData.y < 0? -1:1);  // Find the YSign
        zs = (myData.z < 0? -1:1);  // Find the ZSign
            
        // The 1024 is a hardcode based on the range of the acceleromter
        x = (int)((float)myData.x / 1024.0 * 10.0) * xs; // Turn it into integer G * 10
        y = (int)((float)myData.y / 1024.0 * 10.0) * ys; // Turn it into integer G * 10
        z = (int)((float)myData.z / 1024.0 * 10.0) * zs; // Turn it into integer G * 10
       
        // Format data in x.x  
        sprintf(buff,"x=%s%d.%dg\ty=%s%d.%dg\tz=%s%d.%dg\n",(xs<0?"-":""),x/10,x%10,(ys<0?"-":""),y/10,y%10,(zs<0?"-":""),z/10,z%10);
        UART_UartPutString(buff);
        vTaskDelay(1000); // delay for 1 second
    }

And here is the screen shot of the output of the PSoC FreeRTOS with the kit sitting on my desk…. the output is about 1G down (which make sense)

PSoC FreeRTOS: Output of Kionix KXTJ2-1009 Accelerometer

As always you can git this PSoC FreeRTOS project at the IoT Expert GitHub site or git@github.com:iotexpert/PSoC-FreeRTOS-Examples.git

Topic Description
FreeRTOS: A PSoC4 FreeRTOS Port An introduction to making FreeRTOS work on PSoC 4
FreeRTOS PSoC Examples Using multiple tasks in FreeRTOS
FreeRTOS Queue Example Using a queue to communicate between tasks
PSoC 6 FreeRTOS - The First Example Booting FreeRTOS on PSoC 6
FreeRTOS Binary Semaphore An first example of a binary semaphore
FreeRTOS Binary Semaphore (Part 2) Removing polling in the UART Task
FreeRTOS Counting Semaphore An example using a counting semaphore
PSoC FreeRTOS Reading I2C Sensors with a shared I2C Bus
PSoC FreeRTOS Task Notify A light weight scheme to replace Semaphores
PSoC FreeRTOS Task Notification Values A very light weight method to transfer one word of information into a task

PSoC FreeRTOS Counting Semaphore

Summary

The FreeRTOS Counting Semaphore is a simple extension of the binary semaphore that I talked about in the last two articles (PSoC Binary Semaphore, PSOC Binary Semaphore Part Two).  Simply put, the semaphore counts up when “set” and counts down when “get”.  When it is 0, the task that tried to “get” it is paused until some other task “set”s it.  There are a number of uses of the the counting semaphore including:

  • One or more producers tasks create events and one or more consumers tasks consume those events.  The semaphore counts the events
  • The semaphore represents one or more identical resources.  When you need that resource you take the flag, use the resource, then give the flag back. (e.g. identical blocks of scratch memory)

As I worked on this article I was looking around the internet for good examples, that would visibly demonstrate the counting semaphore.  There are a number of examples out there including, the dining philosophers, the line of bathrooms, the librarian but they all feel somewhat contrived.  The other thing that I realized as I looked around is that there are a bunch of different names for exactly the same thing, that is getting and setting the semaphore.  Those names include at least:

  • Signal/Wait
  • P/V
  • Give/Take
  • Set/Get

FreeRTOS Counting Semaphore Danger

There are a number of scenarios that can cause you much pain with threaded RTOS programming and semaphores.  Two of those cases are circular deadlocks and priority inversion.

The circular deadlock occurs when A depends on B who depends on C who depends on A.  If your program finds itself in this state, you will have a deadlock, which is almost certainly a highly-not-good thing.  A variation of the circular deadlock occurs when you have multiple threads that are dependent on a pool of shared resources and you end up with the scenario where each threads only has one of the resource that its needs (e.g. it requires 2 of the resources to get a job done).  Each thread is then stopped, and waiting for one of the other threads to release the resource.

The other problem that can occur (and be difficult to debug) is called priority inversion.  This can occur when a lower priority thread gets access to a scarce shared resource.  And, a higher priority thread ends up waiting for that shared resource.  This scenario effectively gives the lower priority task a higher priority.

PSoC FreeRTOS Counting Semaphore Example

My example is simply to have one task (called countingSemaphore)  which is consuming events and multiple places that are creating events.  When there are events available, the countingSemaphore task will just printout the number of events, decrement a.k.a. take the semaphore, then loop back.  I start by copying the project “4-Binary-Semaphore” and creating a new project called “5-Counting-Semaphore”.

To make this work, I first declare a global variable to hold the counting semaphore.

SemaphoreHandle_t countingSemaphore;

Then I initialize it in main

countingSemaphore = xSemaphoreCreateCounting(5,0); // Max=5 - Initial=0

Create the counting semaphore task

    /* To print when the counting semaphore is taken */
    xTaskCreate(
        countingSemaphore_Task,       /* Task function */
        "countsema",          /* Task name (string) */
        0x100,           /* Task stack, allocated from heap */
        0,               /* No param passed to task function */
        1,               /* Low priority */
        0 );

I make the task that will take the semaphore, then print the semaphore count, then start again.

void countingSemaphore_Task(void *arg)
{
   (void)arg;
    char buff[16];
    while(1)
    {
        xSemaphoreTake(countingSemaphore,portMAX_DELAY);
        sprintf(buff,"Count = %d\n",(int)uxSemaphoreGetCount( countingSemaphore ));
        UART_UartPutString(buff);
    }
}

Lastly I add the ability to “create events” by making the 1,2,3 keyboard keys create 1,2,3 events (a.k.a. set the semaphore 1,2,3 times)

         case '1':
                    xSemaphoreGive(countingSemaphore);
            break;
            
            case '2':
                    xSemaphoreGive(countingSemaphore);
                     xSemaphoreGive(countingSemaphore);
            break;

            case '3':
                xSemaphoreGive(countingSemaphore);
                xSemaphoreGive(countingSemaphore);
                xSemaphoreGive(countingSemaphore);
            break;

To test the program, I start up a terminal and:

  • press ‘3’, which gives the semaphore 3 times in a row.  Then the countingSemaphore task consumes the “gives” with “takes” and prints out “2,1,0”
  • press ‘2+’, which gives the semaphore 2 times in a row.  Then the countingSemaphore task consumes the “gives” with “takes” and prints out “1,0”
  • press ‘1’, which gives the semaphore 1 time.  Then the countingSemaphore task consumes the “give” with “take” and prints out “0”

FreeRTOS Counting Semaphore Example

You can find this example on the IoT Expert GitHub website or git@github.com:iotexpert/PSoC-FreeRTOS-Examples.git

Topic Description
FreeRTOS: A PSoC4 FreeRTOS Port An introduction to making FreeRTOS work on PSoC 4
FreeRTOS PSoC Examples Using multiple tasks in FreeRTOS
FreeRTOS Queue Example Using a queue to communicate between tasks
PSoC 6 FreeRTOS - The First Example Booting FreeRTOS on PSoC 6
FreeRTOS Binary Semaphore An first example of a binary semaphore
FreeRTOS Binary Semaphore (Part 2) Removing polling in the UART Task
FreeRTOS Counting Semaphore An example using a counting semaphore
PSoC FreeRTOS Reading I2C Sensors with a shared I2C Bus
PSoC FreeRTOS Task Notify A light weight scheme to replace Semaphores
PSoC FreeRTOS Task Notification Values A very light weight method to transfer one word of information into a task

PSoC FreeRTOS Binary Semaphore (Part 2)

FreeRTOS Binary Semaphore – Update

Last week I taught a class on WICED WiFi programming, which also uses and RTOS.  During that class I yelled at a number of people for not using the RTOS mechanisms that I was showing them.  Which got me thinking, that in all of the versions of the FreeRTOS example program that I have shown you, I have used a polling loop for handling the UART.  This was kind of bugging me (at very least it was inconsistent).  In order to fix this I decided use the FreeRTOS Binary Semaphore to fix the problems by:

  • Modifying the FreeRTOS Binary Semaphore schematic and adding the UART ISR
  • Add a FreeRTOS Binary Semaphore called “uartSemaphore” that I will set in the UART ISR
  • Turn on interrupt handling for the UART when there is one or more characters in the buffer
  • In the ISR turn off interrupts and set the “uartSemaphore”
  • In the UART task, wait for the “uartSemaphore”, then handle all of the characters, then turn the UART interrupt back on

First I copied the “4-BinarySemaphore” project and called it “4a-BinarySemaphore”.  Then I modified the schematic to support the UART ISR.

FreeRTOS Binary Semaphore UART Schematic

Then I create a new global variable called uartSemaphore.

SemaphoreHandle_t uartSemaphore;

In main I initialize the semaphore and install the ISR Handler.

    uartSemaphore = xSemaphoreCreateBinary();
    uart_isr_StartEx(uart_isr_Handler); 

In the ISR Handler, I clear the interrupt from the UART.  Originally I thought that I could just clear the pending interrupt, set the semaphore and return.  However, when I returned from the ISR, there were still characters in the receive FIFO, which made the UART immediately pend the interrupt.  This kept me from ever leaving the ISR.  To fix this I turn off all interrupt sources.  In the UART Task I will turn the interrupts back on when the FIFO is empty again.

CY_ISR(uart_isr_Handler)
{
    uint32_t cause;
    cause = UART_GetRxInterruptSource();
    UART_ClearRxInterruptSource(cause);
    UART_SetRxInterruptMode(0);
    xSemaphoreGiveFromISR(uartSemaphore,NULL);
    
}

Finally I modify the UART Task to

  • Line 77 Wait for  the semaphore (which is set in the ISR)
  • Line 78 Loop until there is nothing left in the FIFO (UARTGetChar() will return 0 when there is nothing left)
  • Line 124: Turn the UART Interrupts back on
void UART_Task(void *arg)
{
    (void)arg;
    static char buff[500];
    UART_Start();
    clearScreen();
    UART_UartPutString("Started UART\n\r");
    char c;
    Color_t tempColor;
    
	while(1) {
        
        xSemaphoreTake(uartSemaphore,portMAX_DELAY);
        while( (c = UART_UartGetChar()) )
        {
            switch(c)
            {
                case 'a':
                UART_UartPutString("Working\n\r");
                break;
                
                case 't':
                    UART_UartPutString("********************************************\n\r");
                    UART_UartPutString("Task          State   Prio    Stack    Num\n\r"); 
                    UART_UartPutString("********************************************\n\r");
                    vTaskList(buff);
                    UART_UartPutString(buff);
                    UART_UartPutString("*********************************************\n\r");
       
                break;
                    
                case 'r':
                    tempColor = RED;
                    if(xQueueSend(colorQueue,&tempColor,0) != pdTRUE)
                        UART_UartPutString("queue error\n\r");
                break;
                    
                case 'b':
                    tempColor = BLUE;
                    if(xQueueSend(colorQueue,&tempColor,0) != pdTRUE)
                        UART_UartPutString("queue error\n\r");
                break;

                case 'g':
                    tempColor = GREEN;
                    if(xQueueSend(colorQueue,&tempColor,0) != pdTRUE)
                        UART_UartPutString("queue error\n\r");
                break;
                        
                case 's':
                        xSemaphoreGive(switchSemaphore);
                break;
                        
                case 'c':
                        clearScreen();
                break;

            }
        }
        UART_SetRxInterruptMode(UART_INTR_RX_NOT_EMPTY);
    }
}

This is a fairly simple modification to my program which will save power (potentially), will save CPU cycles (for sure) and is generally much better inline with the RTOS philosophy.

Topic Description
FreeRTOS: A PSoC4 FreeRTOS Port An introduction to making FreeRTOS work on PSoC 4
FreeRTOS PSoC Examples Using multiple tasks in FreeRTOS
FreeRTOS Queue Example Using a queue to communicate between tasks
PSoC 6 FreeRTOS - The First Example Booting FreeRTOS on PSoC 6
FreeRTOS Binary Semaphore An first example of a binary semaphore
FreeRTOS Binary Semaphore (Part 2) Removing polling in the UART Task
FreeRTOS Counting Semaphore An example using a counting semaphore
PSoC FreeRTOS Reading I2C Sensors with a shared I2C Bus
PSoC FreeRTOS Task Notify A light weight scheme to replace Semaphores
PSoC FreeRTOS Task Notification Values A very light weight method to transfer one word of information into a task

PSoC 4 Flash Write

Summary

Last week I got a question from a customer about how to write into the PSoC 4 Flash.  I sent him a fairly straight forward email message explaining the process in English… but after reflecting a little bit, I decided to write an example project as “C’ is often much clearer.  And yes I know that this article it doesn’t have much to do with IoT, but hopefully it is helpful to someone.  In this article I will explain:

  • The organization of the PSoC 4 Flash
  • The risks and issues of writing to the PSoC 4 Flash
  • A program that demonstrates reading and writing the PSoC 4 Flash
  • How to protect rows of the PSoC 4 Flash

Organization of the PSoC 4 Flash

The PSoC 4 Flash is organized into an array that starts at memory address 0x00 and has 128 byte rows.  Different versions of the chip will have different numbers of rows and possibly two arrays (in the case of PSoC 4 BLE II).  The exact configuration of your part is knowable in the firmware by a set of #defines that are built for you by PSoC Creator.  Here is a snapshot from the PSoC 4 System Reference Guide Chapter 8.

PSoC 4 Flash System Reference Guide

You can use that information along with the System call CySysFlashWriteRow() to write into the flash of your device.

PSoC 4 Flash Write API

Risks and Issues Writing the PSoC 4 Flash

There are several risks that you must take into account when performing a PSoC 4 Flash write (or for that matter writing Flash in any other MCU).

  • You must write a complete row at a time.  In PSoC 4 that is 128 bytes.  So, even if you want to write only 1 byte, you will need to read in all of the data surrounding that byte in the row and make sure you don’t overwrite something important.
  • You can easily write someplace bad and brick your part (e.g. if you overwrite your program, or exception vectors, or …).  You need to be very careful that you are writing in the correct place
  • It takes 20ms, which is a long time in the context of MCU speed, to write a row of flash and the MCU comes to a standstill while that is happening (all of the interrupts are off etc.)
  • The Flash will eventually wear out.  If you look at the data sheet for PSoC 4 you will find that the endurance of the Flash is 100K writes. If you are continually updating a place in the memory, you will eventually wear it out

PSoC 4 Datasheet

A PSoC 4 Flash Write Demo Project

To demonstrate the process of a PSoC 4 Flash write I created a project that:

  • Initializes a 128 byte array in the Flash (aligned to a complete row) with 0’s
  • Lets you read the Flash array into a RAM array by pressing a key on the keyboard
  • Lets you printout the values of the Flash array
  • Lets you printout the values of the RAM array
  • Lets you increment the values of the RAM array
  • Lets you write the RAM array into the Flash

Normally when you declare a variable in C it will be assigned to the RAM somewhere (either on the Stack or in the Data or BSS section of the RAM).  In order to have my array be assigned to the Flash, I declare the array to be “const”.  The first time I did this I did not include the “={0}” in the declaration, and the compiler decided to put the array in the RAM, but when I initialized one of the elements it assigned it to the Flash.  The CY_ALIGN() macro tells the linker to put the start of the “row” array on a 128 byte boundary.  In other words completely aligning to a Flash row.

// Allocate 1 row of flash... make it aligned to the row size
// and initializde it with 0's
// the const keeps it in the flash (not in the data segment)
const uint8_t row[CY_FLASH_SIZEOF_ROW] CY_ALIGN(CY_FLASH_SIZEOF_ROW) = {0};

At the start of main, I declare array called “data” which will reside in the RAM.  I will use this array as a buffer to read Flash data into, then change it, then write it back to the Flash.

We know that the Flash is arranged in rows of 128 bytes (well, actually rows of size CY_FLASH_SIZEOF_ROW).  To calculate the row number of the my array “row”, I use the Address of the row divided by the row size. (the CY_FLASH_BASE is 0x00 because the Flash starts at Address 0x00)

    uint8_t data[CY_FLASH_SIZEOF_ROW];
    int rowNum;
    // calculate which row in the flash that the "row" array resides
    rowNum = ((int)row - CY_FLASH_BASE) / CY_FLASH_SIZEOF_ROW;

To make things a bit easier I create a function called “dump” which just prints the values of a “size “of memory in hex format.  The function just takes an address that you want to start dumping to the screen.

// This function dumps a block of memory into rows of hex ...16 bytes long in hex
void dump(uint8_t *array, int size)
{
    int i,j;
    j=0;
    for(i=0;i<size;i++)
    {
        dbgprintf("%2X ",array[i]);
        j=j+1;
        if(j==16) // 16 values per line
        {
            j = 0;
            dbgprintf("\n");
        }
    }
    UART_UartPutString("\n");
}

In order to test this whole thing I use a UART to read from the keyboard and display to the screen.  The main function is just a loop that reads keys and then does a big “switch”.

When you press ‘f’ it dumps the Flash “row”

When you press ‘r’ it copies the Flash “row” into the array “data” (which resides in the RAM)

When you press ‘i’ it increments the values in the “data” array

When you press “R” it dumps out the values in the “data” array

When you press ‘q’ it prints out information about the rowNumber, row size etc.

   for(;;)
    {
        char c;
        c = UART_UartGetChar();
        switch(c)
        {
            case 'f':
                UART_UartPutString("Dumping Flash\n");
                dump((uint8_t *)row,CY_FLASH_SIZEOF_ROW);
                break;
            case 'r':
                UART_UartPutString("Reading Flash into RAM\n");
                memcpy(data,row,(int)CY_FLASH_SIZEOF_ROW);
            break;
                
            case 'i':
                UART_UartPutString("Incrementing RAM Array\n");
                data[0] = data[0] + 1;
                for(i=1;i<(int)CY_FLASH_SIZEOF_ROW;i++)
                {
                    data[i] = data[i-1]+1;
                }
            break;
            case 'R':
                dbgprintf("Dumping RAM Array\n");
                dump(data,CY_FLASH_SIZEOF_ROW);
            break;    
               
            case 'q':
                dbgprintf("Row Number = %d\n",rowNum);
                dbgprintf("RowSize = %d\n",CY_FLASH_SIZEOF_ROW);
                dbgprintf("Flash Address = %X\n",CY_FLASH_BASE);
                dbgprintf("Row Address = %X\n",(unsigned int)row);
                dbgprintf("Data Address = %X\n",(unsigned int)data);
   
            break;

When you press ‘w’, it writes the “data” array into the “row” array in the Flash using the “CySysFlashWriteRow()” system call

            case 'w':
                dbgprintf("Writing Flash from RAM Buffer\n");            
                rval = CySysFlashWriteRow(rowNum,data);
                if(rval == CY_SYS_FLASH_SUCCESS )
                {
                    dbgprintf("Flash Write Sucess\n");
                }
                else if (rval == CY_SYS_FLASH_INVALID_ADDR)
                {
                    dbgprintf("Flash Write Failed: Invalid Address\n");
                }
                else if (rval == CY_SYS_FLASH_PROTECTED)
                {
                    dbgprintf("Flash Write Failed: Flash Protected\n");
                }
                else {
                    dbgprintf("Flash Write Failed: Unknown\n");
                }
            break;

Testing the Program

After I program the device, I first press “q” to find out the information about the PSoC 4 Flash array.  You can see that my “row” is the 46th row in the Flash and resides at address 0x1700 (as I type this I wish that I hadn’t mixed decimal and hex … and that I had called my “row” variable something other than “row”).  You can also see that the rows are 128 bytes and that the Flash array starts at address 0x0.  All that is good.

PSoC 4 Flash Write Demo

When I press ‘f’ to dump out the Flash array, you can see that my row has all 0’s in it.  Then I press ‘R’ to dump out my RAM array and you can see that it has garbly-gook in it (which makes sense as I didn’t initialize the array)

PSoC 4 Flash Write Demo

Next, I press ‘r’ to copy the PSoC 4 Flash array into the RAM buffer.  Then I press “i” to increment the values in the RAM array, then I dump it out.  Lastly, I press ‘w’ to write it to the PSoC 4 Flash.

PSoC 4 Flash Write Demo

Then I hit reset on the board and press ‘f’ to printout the PSoC 4 Flash array.  And I see success, the values were retained in the PSoC 4 Flash even after resetting the device. (or for that matter power cycling it)

PSoC 4 Flash Write Demo

Protecting Rows of the PSoC 4 Flash

One cool feature of the PSoC 4 Flash is that you can write protect it on a row by row basis.  Meaning that you can make it so that the PSoC 4 Flash writing hardware will not overwrite rows.  You do this by going to the “Flash Security” tab of the Design Wide Resources.  Then you have 1 box for each row in the flash where you can pick “W” for Full Protection and “U” for Writable.  In the screen show below you can see me changing the row “ox1700” to Write protection.  This is the row where my Flash array resides.

PSoC 4 Flash Security

After reprogramming my device I try to press ‘w’ and you can see that the Write fails.

PSoC 4 Flash Write Fail

As always my projects are available on the IoT Expert GitHub site git@github.com:iotexpert/PSoC4-Flash-Write-Example.git