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

PSoC FreeRTOS Binary Semaphore

Summary

In the previous FreeRTOS articles I have shown you how FreeRTOS threads work, and how to use a Queue to communicate data between threads.  In this article I will introduce you to another important RTOS concept, the Semaphore.  The Semaphore or in this case the FreeRTOS Binary Semaphore is a multi-threaded safe mechanism for signaling between threads.  I use the word “signal” because the word “semaphore” is an old-time word for a system of flags that were used to communicate between boats.  Here is a modern example of a flag semaphore, the Cypress Indycar winning finish line checkered flag earlier this year:

In RTOS, a binary semaphore is exactly the same thing as a checkered flag.  It is one thread waving another thread to indicate some specific message.  Specifically, what does the message flag mean?  It means whatever you define it to mean.  In this example, it will mean that a message can be printed on the screen.

In this article I will modify the queue example program from the previous article to add a semaphore that will:

  • Print a message when a specific key on the keyboard is pressed
  • Print a message when a mechanical button on the development kit is pressed

FreeRTOS Binary Semaphore Task

I will start by copying the “3-Queue” example and creating a new project called “4-Binary Semaphore”.  At the top of the program I will add a global variable of type “SemaphoreHandle_t” to hold my semaphore.  I use a global variable so that all of the threads will have access to the handle.

SemaphoreHandle_t switchSemaphore;

Before you can use the semaphore you must set it up.  At the start of main I initialize the semaphore:

switchSemaphore = xSemaphoreCreateBinary();

Now, I will create a new thread that will just sit and wait for the Semaphore flag.  On line 122, the xSemaphoreTake function will put that thread to sleep util one of the other threads has “given” the signal using the xSemaphoreGive function.  When that occurs, I print out the message and then loop back around and wait again.

void semaphore_Task(void *arg)
{
(void)arg;
while(1)
{
xSemaphoreTake(switchSemaphore,portMAX_DELAY);
UART_UartPutString("Taken Switch Semaphore\n");
}
}

Giving the FreeRTOS Binary Semaphore

Inside of the “UART_Task” on line 107, when the ‘s’ key is pressed, wave the FreeRTOS Binary Semaphore Flag… actually “give” the semaphore.  When this happens the “semaphore_Task” wakes up and prints out the message.

            case 's':
xSemaphoreGive(switchSemaphore);
break;

With Semaphores there is an annoying level of inconsistency in the language.  Sometimes (as in FreeRTOS) it is “give/take” in WICED it is “set/get”, but they mean the same thing.

Using a Semaphore: Interrupt Service Routine

It is a very good practice to minimize the amount of work done inside of an interrupt service routine.  The FreeRTOS binary Semaphore is the perfect tool for achieving that objective.  When an interrupt occurs, set the semaphore flag then let the RTOS take care of the rest.  To show this example I add a digital input pin to the schematic and attach it to an interrupt.

FreeRTOS Binary Semaphore Schematic

The pin is configured to trigger the interrupt on a falling edge (the switch on the board is active low).

Digital Input Pin Configuration

Now I create an ISR called “isr_1_Handler”.  All it does is clear the pin interrupt and then give the semaphore.  The only trick is that the FreeRTOS Binary Semaphore has a different give function for use inside of ISR.  In general, the FreeRTOS API adds “FromISR” onto the API to indicate that it is safe to use inside of an ISR.

CY_ISR(isr_1_Handler)
{
SW_ClearInterrupt();
xSemaphoreGiveFromISR(switchSemaphore,NULL);
}

The last thing to add is at the start of main I install the interrupt handler.

   isr_1_StartEx(isr_1_Handler);

Now when you press the mechanical switch on the devkit, you will get the message that the FreeRTOS Binary Semaphore has been set.

In the next article I will show you another type of semaphore, the counting semaphore.

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