PSoC4 Boot Sequence (Part 4) – Linker trickery with __attribute_((constructor(101)))

Summary

In the previous articles I took you through the first part of the PSoC4 Boot Sequence, then I showed you how the exception vectors got into the flash, lastly I showed you the Start_C() function and how it initializes your program variables.  After that your main() should start, right?  But wait, when does the PSoC get initialized?  Is it magic?  This article answers that question and explains the evil linker trickery __attribute_((constructor(101)) that is used to call the “initialize_psoc()” function.

For many many reasons, one of my heroes is Brian Kernighan.  He just gets “it” and even better, he can explain “it” beautifully.  One of my favorite Kernighan quotes is “Everyone knows that debugging is twice as hard as writing a program in the first place. So if you’re as clever as you can be when you write it, how will you ever debug it?”  Our business is hard, really hard and there is absolutely no call for doing things  that make it harder.  Don’t be deluded, obfuscation is not elegance.

Start_c()

As discussed previously, the Reset() function just calls Start_C() whose role in life is to get the C program initialized (the previous article).  Then it calls the function “__libc_init_array” (line 346) and finally it calls main (line 347).  The first time I saw this I thought, wow that is simple.  Then I started wondering, how and when does PSoC become PSoC?  When I look around in the Cm0Start.c file I see a function called “initialize_psoc” (which I will talk about in the next article).  But, there does not appear to be a call to “initialize_psoc()”.  Did I miss it?  Is it even run?

void Start_c(void)
{
    #ifdef CY_BOOT_START_C_CALLBACK
        CyBoot_Start_c_Callback();
    #else
        unsigned regions = __cy_region_num;
        const struct __cy_region *rptr = __cy_regions;

        /* Initialize memory */
        for (regions = __cy_region_num; regions != 0u; regions--)
        {
            uint32 *src = (uint32 *)rptr->init;
            uint32 *dst = (uint32 *)rptr->data;
            unsigned limit = rptr->init_size;
            unsigned count;

            for (count = 0u; count != limit; count += sizeof (uint32))
            {
                *dst = *src;
                dst++;
                src++;
            }
            limit = rptr->zero_size;
            for (count = 0u; count != limit; count += sizeof (uint32))
            {
                *dst = 0u;
                dst++;
            }

            rptr++;
        }

        /* Invoke static objects constructors */
        __libc_init_array();
        (void) main();

        while (1)
        {
            /* If main returns, make sure we don't return. */
        }

    #endif /* CY_BOOT_START_C_CALLBACK */
}

Debugging to initialize_psoc()

To answer the question, “where is initialize_psoc()” called, I put a breakpoint at that function.  When I run the debugger, you can see that it stops at the right place, and you can see in the call stack that the function is called by the function “__libc_init_array()”.  This is the point where things started to get really difficult in my life.

initialize_psoc function

__libc_init_array()

What in the world is this “__libc_init_array()”.  If you look in “Cm0Start.c” on line 219 you will see this block of code.  That means it is somewhere in some library (and not in this file).

/* The static objects constructors initializer */
extern void __libc_init_array(void);

My first thought was that it had something to do with initializing variables, but I realized that we had already done that.  So, what does it do? And how in the world does it call “initialize_psoc()” and where does it come from?  I started the search by right clicking on it and having PSoC Creator take me to the definition.  But, no luck, for some reason we didn’t include the source code for that function.  So, what does the function do?

Well, start by running the debugger and placing a breakpoint at “__libc_init_array”.  When you do that, you can look at the assembly language.  This is the place that I ended up spending a bunch of time as I had never written ARM assembly, and in fact the last time that I wrote any material amount of assembly was at Georgia Tech 26 years ago.

As I often do, I started by reading a few books and a Cypress application note.  Then I spent a few days writing simple C, compiling it, and looking at the results.  Specifically

Finally I was ready to dig back into this crazy code.  This function has three sections:

  • 0x0620 –> 0x0x0630 is a loop that loads an array of function pointers, then makes the function call to each one (line 0x0636)
  • 0x063c is a call to a function called “_init” (which I don’t know what it does)
  • 0x0640 –> 0x0x0658 is a loop that loads an array of function pointers, then makes the call to each one (line 0x0654)
0x00000620 <__libc_init_array>:
0x00000620 ldr	r3, [pc, #38]	; (65c <__libc_init_array+0x3c>)
0x00000622 push	{r4, r5, r6, lr}
0x00000624 movs	r5, #0
0x00000626 adds	r6, r3, #0
0x00000628 ldr	r4, [pc, #34]	; (660 <__libc_init_array+0x40>)
0x0000062A subs	r4, r4, r3
0x0000062C asrs	r4, r4, #2
0x0000062E cmp	r5, r4
0x00000630 beq.n	63c <__libc_init_array+0x1c>
0x00000632 lsls	r3, r5, #2
0x00000634 ldr	r3, [r6, r3]
0x00000636 blx	r3
0x00000638 adds	r5, #1
0x0000063A b.n	62e <__libc_init_array+0xe>
0x0000063C bl	6d8 <_init>
0x00000640 ldr	r3, [pc, #20]	; (664 <__libc_init_array+0x44>)
0x00000642 movs	r5, #0
0x00000644 adds	r6, r3, #0
0x00000646 ldr	r4, [pc, #20]	; (668 <__libc_init_array+0x48>)
0x00000648 subs	r4, r4, r3
0x0000064A asrs	r4, r4, #2
0x0000064C cmp	r5, r4
0x0000064E beq.n	65a <__libc_init_array+0x3a>
0x00000650 lsls	r3, r5, #2
0x00000652 ldr	r3, [r6, r3]
0x00000654 blx	r3
0x00000656 adds	r5, #1
0x00000658 b.n	64c <__libc_init_array+0x2c>
0x0000065A pop	{r4, r5, r6, pc}
0x0000065C .word	0x000006e4
0x00000660 .word	0x000006e4
0x00000664 .word	0x000006e4
0x00000668 .word	0x000006ec

What all of this means is that there are two arrays of function pointers.  The first array starts a 0x06e4 and ends at 0x6e4 (in other words it is empty).  The second array starts at 0x06e4 and ends at 0x06ec which means there are two function pointers.

When I look at the memory location 0x06e4 –> 0x06ec you see that there are two address 0x0129 and 0x01bc. (look at the memory window in the picture below).  When I scroll the assembly window to location 0x01bc, look what I find, “initialize_psoc”.

PSoC4 Boot Sequence - initialize_psoc

After all of that, I did what I probably should have done originally.  I googled “__libc_init_array source”.  One of the first few google hits was a link to the source code from CodeSourcery.  And it is indeed what I said it was:

  • A loop (lines 32-34) with function pointer calls
  • A call to “_init” (line 36)
  • Another loop (lines 38-40) with function pointer calls
/*                                             
 * Copyright (C) 2004 CodeSourcery, LLC                        
 *                                                            
 * Permission to use, copy, modify, and distribute this file   
 * for any purpose is hereby granted without fee, provided that
 * the above copyright notice and this notice appears in all            
 * copies.                                          
 * This file is distributed WITHOUT ANY WARRANTY; without even the implied 
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 */

/* Handle ELF .{pre_init,init,fini}_array sections.  */
#include <sys/types.h>

#ifdef HAVE_INITFINI_ARRAY

/* These magic symbols are provided by the linker.  */
extern void (*__preinit_array_start []) (void) __attribute__((weak));
extern void (*__preinit_array_end []) (void) __attribute__((weak));
extern void (*__init_array_start []) (void) __attribute__((weak));
extern void (*__init_array_end []) (void) __attribute__((weak));

extern void _init (void);

/* Iterate over all the init routines.  */
void
__libc_init_array (void)
{
  size_t count;
  size_t i;

  count = __preinit_array_end - __preinit_array_start;
  for (i = 0; i < count; i++)
    __preinit_array_start[i] ();

  _init ();

  count = __init_array_end - __init_array_start;
  for (i = 0; i < count; i++)
    __init_array_start[i] ();
}
#endif

Now I need to figure out how the address of the function “initialize_psoc” got into the memory in the table.

__attribute_((constructor(101)))

In the function “_libc_init_array” (above) it iterates through all of the function pointers that are in the array that starts at “__init_array_start” and ends at “__init_array_end”.  If you look at the linker script you will see that it puts the address of every function that is in the section ending with “.init_array.*”  That is cool but how does “intialize_psoc” get in that section?

      . = ALIGN(4);
      KEEP(*(.init))

      . = ALIGN(4);
      __preinit_array_start = .;
      KEEP (*(.preinit_array))
      __preinit_array_end = .;

      . = ALIGN(4);
      __init_array_start = .;
      KEEP (*(SORT(.init_array.*)))
      KEEP (*(.init_array))
      __init_array_end = .;

      . = ALIGN(4);
      KEEP(*(.fini))

      . = ALIGN(4);
      __fini_array_start = .;
      KEEP (*(.fini_array))
      KEEP (*(SORT(.fini_array.*)))
      __fini_array_end = .;

Well… if you look at the “initialize_psoc” function in Cm0Start.c you see a bunch of compiler garbly-gook.  It says if you are using the GNU compiler that you should add the attribute “constructor(101)” to the function.

/*******************************************************************************
* Function Name: initialize_psoc
****************************************************************************//**
*
* This function is used to initialize the PSoC chip before calling main.
*
*******************************************************************************/
#if(defined(__GNUC__) && !defined(__ARMCC_VERSION))
__attribute__ ((constructor(101)))
#endif  /* (defined(__GNUC__) && !defined(__ARMCC_VERSION)) */
void initialize_psoc(void)
{

But what does the “constructor” attribute do?  The answer to that can be found in the ARM Information Center.  Basically it says that it will call all functions with that attribute before main in the order of the attribute value (in this case 101).  The compiler achieves this objective by putting the function in the “.init_array” section.  Then the linker does its magic.

As I said earlier in this post I am really not a fan.  There is absolutely no reason why we should not have just called “initialize_psoc” right before we call “main”.   This would have greatly simplified this file as there must be a similar trick going on with IAR and MDK (but I am not going to go figure it out).  In addition hardcoding that 101 means that someone else might slam into it unexpectedly.

Oh well.  In the next article I will talk about what initialize_psoc actually does.

 

PSoC4 Boot Sequence (Part 3) – Preinitializing Variables before main()

PSoC4 Boot Sequence: Examine memory using debugger

Summary

In the previous articles, I took you through the first part of the PSoC4 Boot Sequence.  I traced from the power on of the chip to the beginning of the “Reset()” function.  Then in the 2nd article I showed you how the exception vectors were placed into the ROM (Flash).  In this article I will show you the steps taken to initialize the system so that your C program runs correctly.

PSoC4 Boot Sequence: Initialize C Global Variables

RAM is a volatile storage area, meaning that when the chip turns on it is in an indeterminate state.  But, what happens when you define a global variable that resides in the RAM, because it can change, and is also initialized.  Consider this block of code:

PSoC4 main.c

We know that when this program starts that the variable “aGlobal” has the value of 10.  But aGlobal can change, so it must be in the RAM and everything in the RAM is scrambled when the PSoC4 is Reset.  We are left with the question: How does the variable aGlobal get to be 10?  Lets start with the listing file for main (which as I discussed in the previous article is called main.lst and can be seen in the Results tab inside of folder “Listing Files”.  Here is the section of code that is material to the definition of aGlobal.

PSoC4 Assembly Listing File Global Variable

Line 87 is creates an assembler label called “aGlobal” (which matches our variable name).  Then line 88 inserts 4-bytes (aka the size of an integer) with the value (0x0000000A) [dont forget that it is little endian] into the current segment.  Line 82 defines the current segment to be “.data”.  Now lets look at the linker map file where you can see that the final address of “aGlobal” is 0x200000c4.

PSoC4 Linker Map File

If you run the debugger you can see that by examining the memory at 0x200000c4

PSoC4 Boot Sequence: Examine memory using debugger

But that address is in the RAM (not the flash).  So how does that address end up with the value of 0x0A like we assigned in the program?

PSoC4 Boot Sequence: Start_c()

It turns out that the only function called by the Reset() function is the Start_c() function. This function does four things

  • Initializes the memory (as it says on line 321)
  • Invoke static objects constructors (as it says on line 345)… what in the world does this mean? (the subject of the next two articles)
  • Calls main() a.k.a the start of your program
  • If something bad happens and you return from main then it does an infinite while(1); loop (lines 349-351)

PSoC4 Boot Sequence: Start_C() Function

PSoC4 Boot Sequence: Initialize the Memory

To answer the question how does 0x0A get into 0x200000c4 the first thing to do is look at the linker script.  After looking around in the linker script I find that .data section on lines 214-237.  On line 237 it has a tricky little command, specifically “>ram AT>rom”.  This tells the linker to assign addresses in the RAM region, but to load the data in ROM region.

PSoC4 Boot Sequence: The Linker File - .data Segment

For the purposes of initializing the memory, a __cy_region is a block of memory that has an initialized part (aka a .data section) and a part that is initialized to 0 (aka .bss section).  You can see this in the definition of the __cy_region structure which is declared on line 224 of Cm0Start.c

PSoC4 Boot Sequence: __cy_region structure

On line 322 of the function Start_C() you can see that there is a loop over all of the __cy_regions.  On lines 329-334 it copies from the ROM to the RAM.  The on lines 336-340 it initializes the BSS to 0.

After all of that we are left with is figuring out how an array of __cy_region structures get into the Flash and how the symbols __cy_regions and __cy_region_num are set.  For the answer to that question we are back to the linker script.  All of these symbols we have met earlier in this article.

PSoC4 Boot Sequence: linker script definition of __cy_regions array

Finally, __cy_region_num is defined on line 62.  This calculation works by calculating the size of the __cy_regions array and dividing it by a hardcoded value for the sizeof(__cy_region) (remember it is a pointer, pointer, int, int which are all 4bytes).  I am not a giant fan of this as if someone changed the structure definition in Cm0Start.c the hardcoded 16 will break.

PSoC4 Boot Sequence: _cy_region_num definition

The __cy_regions was made as an array to future proof the system.  I do not believe that there is ever more than one region initialized by this method.

In this next article I will answer the question “What in the world is that __libc_init_array() function?”

 

PSoC4 Boot Sequence (Part 2) – Creating the Exception Table using the Linker

Summary of the PSoC4 Boot Sequence

In the previous post I took you through the first part of the PSoC4 Boot Sequence.  I traced from the power on of the chip to the beginning of the “Reset()” function.  In this post I will trace the steps that were required to get the reset vector and stack pointer set and programmed into the flash of the PSoC4 at the right place.

We know that you program the chip with a hex file which is essentially a file with a list of addresses and values.  But how to you get a hex file?  And how do you get the Reset Vector and Stack Pointer into the hex file?  In order to create a hex file there are several steps required.

  1. Compile C –> Assembly Listing File then Assemble listing –> Objectfiles
  2. Link object files –> into ELF file
  3. Convert ELF –> Hex file

PSoC4 Boot Sequence: Compile and Assemble Program

Each C file in your project is turned into an ARM assembly language program by the compiler.  You can see the ARM assembly language programs in “.lst” files.  You can find your project listing files by clicking on the “Results” tab in the workplace explorer then selecting the “listing files” folder under your project.  In the screenshot below I am showing you the “Cm0Start.lst” which is the ARM assembly language file from the Cm0Start.c.  You will notice that there is one listing file for each of the C files in your project.

PSoC4 Boot Sequence: ARM Assembly Language

The next step in the process is for the Assembler to turns the listing files into object files.  Each object file has the hex bytes that represent your program and data.  It also defines which “section” that the code and data belong too.  The .0 also has a list of symbols that it doesn’t know the address of e.g. the address of functions and data in other files.  In order to see the object files you need to use the windows explorer (we don’t attach them to the workplace explorer)

PSoC4 Boot Sequence: Linker Configuration

The linker is responsible for:

  1. Combining all of the .o files into one file
  2. Assigning actual addresses for all of the symbols e.g. variables and functions

In order for the linker to do its job, it needs a linker script.  Cypress supports three toolchains: GCC, ARM MDK and IAR.  Each one of the toolchains has different syntax, form etc. for the linker script.  This is painful, but it is made worse by the fact that the linker script language is rather esoteric.  PSoC Creator makes a linker script for all three of the tool chains.  You can find those files called “cm0gcc.ld” (the GCC linker file), Cm0Iar.icf (the IAR linker file) and Cm0RealView.scat (the MDK linker file) in the workspace explorer under Generated_Source–>PSoC4–>cy_boot

PSoC4 Boot Sequence: Linker File

There is quite a bit going on in the linker file.  In fact the GCC linker file for PSoC4M is 470 lines long.  However, there are two basic commands in the linker file.

The “Memory” command which defines the address and size of the different types of memory in the system.  Each block of memory is sometimes called a “region”, but the Linker words “region” and “section” and “segment” are used somewhat erratically in the parlance.  In this PSoC4M there is 128K of Flash that starts at address 0x00000000 and 16K of RAM which starts at address 0x20000000.  You can see the “Memory” command on lines 29-33 of the GCC linker script.

PSoC4 Boot Sequence: Memory Layout

The second big command in the linker file is “SECTIONS”.  After the sections command there is a list of [input] section names and where they belong (aka their address).   When you look around on the internet you will find that sometimes the word “section” is used interchangeably with the word “segment”.  Unfortunately there does not appear to be a canonical definition of either of these words. There are three main section/segments

  • bss – this section contains variables which should be initialized to zero before main starts
  • data – this section contains variables which need to be initialized to some specific value
  • text – this section contains your program

Here is a screenshot of the part of the GCC linker file that includes the definition of where the PSoC4 ARM exception vectors are located.  This starts on line 72 where the “SECTIONS” command is issued.

PSoC4 Boot Sequence: Linker Section Table

The section command defines the a list of sections and the address of the sections.  Inside of the linker there is an “address pointer” which keeps track the current address in the system.  As it loads sections into the program it increments the address pointer so that it knows the final address of symbols.

In the above listing you see on line 87 that a section called “.text” belongs starting at address “appl_start”.  The linker code on lines 75–>80 is used to support bootloading programs with multiple application.  However, in this case we have only one application and no bootloader.  As a result nothing is loaded and “appl_start” is set to 0x00000000 which is also known as the first location in Flash.  Line 92 tells the linker to put the code in the section “*.romvectors” next.  Now we need to find the code that is marked in some .c file as belonging to the section “romvectors”.  I will come back to the linker script in a later article.

Cm0Start.c the Heart of the PSoC4 Boot Sequence

After digging through the beginning of the linker script and putting a breakpoint on the reset vector we know that the vector table is in a section named “romvectors” and we know that the 2nd entry in the table is the address of the function “Reset()”.  So that leaves us with the question:  Where are the “romvectors” defined?  After using the PSoC Creator search functionality I find this block of code.

PSoC4 Boot Sequence: Exception Vector Table

That nested mess of #defines and #ifdefs is a bit intimidating… but it was all put there to support the three different compilers.  If you boil it down, the first thing you will see is line 462 tells the compiler to put the next block of code into the “.romvectors” section.  Bingo! that is exactly what we were looking for.  Then on line 464 you can see that we define an array of type “cysisraddress”.  It turns out that “cyisraddress” is just a function pointer.  OK.

Now dig a little bit more and you can see that line 467 defines the address of the initial stack pointer as CY_SYS_INITIAL_STACK_POINTER.  This address is the last location in the RAM.  Then on line 471 we put the address of the Reset() function, then we put in two entries for the NMI and hard fault handers.  The “IntDefaultHandler” is an infinite while(1){} which hangs the processor.  This function is also in the Cm0Start.c file.

PSoC4 Boot Sequence: Default Exception Handler

Stack Pointer

Earlier I said “.. the address of the initial stack pointer.  This address is the last location in the RAM.”  How does that get to be?  Well if you hover over CY_SYS_INITIAL_STACK_POINTER you will find that it is a #define for the symbol “__cy_stack”.  Then when you look in the linker script you will find:

PSoC4 Boot Sequence: Stack Pointer Configuration

You can also see that the end of the heap is defined as the address of __cy_stack – 0x800.   The 0x800 must be the size of the stack… and it is… you define it in on the system resources tab of the “design wide resources”

PSoC4 Boot Sequence: Stack and Heap Configuration

The final thing to look at with regards to the stack is linker file definition of the stack (and heap).  On line 258 you can see that the stack starts at the address __cystack – 0x800.  This address is also known as the end of the RAM minus the size of the stack (remember that in ARM the stack builds down towards lower addresses)

PSoC4 Boot Sequence: Stack and Heap Linker Configuration

Test1.map

The last link in the chain is the linker map file.  You can find that file in the Test1–>CortexM0–>ARM_GCC_541–>Debug–>Listing Files directory.  The map file is message output file of the linker.  You can see the final resting place of all of the symbols. In the screenshot below you can see that the “.romvectors” segment started at address 0x0 and ended at address 0x10.  This makes sense as there are 4x 4 byte addresses (stack pointer, reset vector, NMI vector, Hard Fault vector)

PSoC4 Boot Sequence: Linker Map File

And the stack landed at 0x200038000 and ends at 0x20004000 which makes sense as we have 16K of SRAM aka 0x4000 bytes.

PSoC4 Boot Sequence: Linker Map for Stack

In the next post we will follow through the “Reset()” function and the initialization of the BSS&Data section as well as the C-Standard library.

 

PSoC4 Boot Sequence (Part 1) – Debugging to the Reset Vector

PSoC4 Boot Sequence: Examine memory using debugger

Summary

Recently I have been working on RTOSs.  While I was completing the port of FreeRTOS, I ran into something that I just didn’t understand.  So, I called a close friend who is a remarkable programmer.  Instead of telling me the answer, he said “I could tell you, or you could set a breakpoint on the reset vector and find out for yourself”.  This simple statement sent me into weeks of single stepping ARM assembly language, reading linker scripts, reading application notes and crawling through boot source code to figure out what is really happening during the PSoC4 Boot Sequence.

So, what happens when power is applied to a PSoC4?  I suppose that I could tell you to “Set a breakpoint on the reset vector and find out for yourself.”  Which would be a good thing for you to do, but it would’nt make for very interesting reading.  It also wouldn’t tell the whole story as what I am going to show you is what happens after the initial supervisory part of the boot occurs.

In this series posts I will take you through the process.

  1. Using the debugger: Setting a breakpoint on the reset vector of PSoC4 Boot Sequence
  2. Creating the Exception Table using the Linker
  3. Generated Source & cy_boot & Cm0Start.c
  4. RAM Vectors –> RAM Vectors
  5. Start_c
  6. initialize_psoc
  7. Solving the mystery of  __libc_init_array & a GCC trick

The whole process relies heavily on the linker script to get all of the code and vectors into the right place.  If you have never dug through a linker script, it can be a bit overwhelming, but don’t despair as I will explain the parts required to make this work.

All that being said, the PSoC4 Boot Sequence must:

  1. Move the Flash based exception vector table to the RAM (so that it can be changed)
  2. Startup the C Standard library environment
  3. Initialize the C-variables (from the Data segment) and zero the ones in the BSS segment.
  4. Move the table of PSoC flash based register settings into the appropriate volatile latches (make the PSoC a PSoC)

Using the debugger: Setting a breakpoint in the reset vector of PSoC4 Boot Sequence

The first thing that I did was create a blank PSoC4 M project with a blinking LED.  I then clicked the debug button which built the project, programmed it into the board, then started the debugger.  When you do that, here is what you will see.  You can see that the debugger by default boots the chip and runs until the first line in main (which is beyond the reset vector)

PSoC4 Debugger

But I want to break on the reset the vector.  I didn’t even know what function Cypress had setup for the reset vector or exactly where to look for it.  I knew that  I needed to figure out where the reset vector is located in the CM0 so that I could put a breakpoint on that location. Start by googling “arm cortex m0 reset vector”  The first google hit is an ARM page that shows the layout of all of the exception vectors:

Cortex-M0 Exception Vector Table

The reset vector is at address 0x04.  Now examine the memory in the debugger to find the address (which you can see is 0x00000011 – don’t forget that this processor is little endian). You can examine the memory by clicking the “Memory 1” tab at the bottom of the debugger.

PSoC4 Memory Dump of Exception Table

Create an address based breakpoint by using the debug->New Breakpoint menu.

PSoC4 Boot Sequence - Set Reset Breakpoint

Then press the reset button (which I highlighted in Red) on the debugger.  This will cause a reset of the chip, the PSoC4 ARM Cortex-M0 will load the program counter (PC) and start running. You will end up on a screen that looks like this:

PSoC4 Boot Sequence - Halt at Reset Vector

That is a pretty convenient place to stop.  The function is called “Reset” which makes good sense, and it is in a file called “Cm0Start.c”.  When I saw this, I thought that the whole exercise was going to be a cakewalk, little did I know that I was about to fall into a rabbit hole, that was going to take a few weeks to descend out of.

In the next post I will show you where the reset vector came from and how it and stack pointer got into the flash.

 

PSoC4 Watch Dog Timer

Summary

I recently was working on a project that had a line of code that sometimes caused the system to hang.  One of the several possible fixes to my problem was to use a Watch Dog Timer (WDT).  I “knew” about the PSoC4 Watch Dog Timer(s) in the PSoC4 family but had never used them.  My experiments are the subject of this article.  I will address the following areas.

  • PSoC4 Watch Dog Timer: Introduction
  • PSoC4 Watch Dog Timer: Basic Usage
  • PSoC4 Watch Dog Timer: Callback
  • PSoC4 Watch Dog Timer: Custom ISR

All of these projects are available on my GitHub website of you can “git@github.com:iotexpert/PSoC4-WDTExamples.git”

PSoC4 Watch Dog Timer: Introduction

Inside of most of the PSoC4 family there are two 16-bit timers Timer0-1/WDT0-1 and one 32-bit timer called Timer2/WDT2.  These timers are driven by the Low Frequency Clock (LFCLK). In addition, they can be cascaded together to form a larger timer (I’m not sure why you would need a 64-bit timer) or they can be used in isolation as general purpose or WDTs.  You can configure these timers either through software or on the clocks tab of the design wide resources (DWR).  For some reason, which I don’t understand, Cypress choose not to use the optional ARM Cortex-M family Watchdog Timer.

I started this article by creating a PSoC4M project called “4MBlank.  In the screenshot below you can see that I have clicked the “Clocks” button in the DWR.  On the 2-3-4 line you can see the Watch Dog Timers.  To edit the low frequency clocks press the “Edit Clock” button. (as shown on the 2nd screen shot)

PSoC4 Watch Dog Timer: Edit Clocks

In the PSoC4M it is possible to drive the LFCLK with two different oscillators, the Internal Low-speed Oscillator (ILO) which is a very inaccurate RC Oscillator or with an external Watch Crystal Oscillator (WCO) which is very accurate.  The CY8CKIT-044 has the WCO on the board so I will be able to use it as the LFCLK source for my projects.  To select the LFCLK source use the dropdown menu (currently set on ILO).  Each of the timers can be put into one of four modes (from the LFCLK Datasheet)

  • Free Running Timer – Does not generate an interrupt or reset. You can read the counter and set an interrupt in the firmware to generate occasional timing loops.
  • Periodic Timer – Generates an interrupt on a match event but no reset. The timer wraps at the set divider value.
  • Watchdog – Generates a reset on a match event (counter should be cleared before reaching a match event to prevent a reset).
  • Watchdog (w/interrupts) – Generates an interrupt on a match event and generates a reset on a 3rd unserviced interrupt.

In addition it is possible to cascade the timers (to make large timer), however, this must be done through the APIs.  I will explain the “Timer ISR” box in the last example project.  To enable a Timer click the little box in the upper left hand corner.  (in the picture you can see Timer0 and Timer1 are enabled).  When you configure the timer you can select its function as well as its divider which sets how often it is triggered based on the frequency of the input source.

PSoC4 Watch Dog Timer: Configure Low Frequency Clocks

All of the documentation is available on the Help–>System Reference Guide.  Then click the “PSoC4 Low Frequency Clock” link.

PSoC4 Low Frequency Clock Documentation

PSoC4 Watch Dog Timer: Basic Usage

The first project shows the use of the WDT to reset the chip.  This project starts by configuring the WDT to use the WCO as its source clock and to have a period of about 1 second.  With this configuration if you don’t “feed” the WDT it will cause a chip reset in 3 seconds.

PSoC4 Watch Dog Timer: Basic Example

When the PSoC4 chip is reset you can find the cause of the reset by using the API “CySysGetResetReason”.  This will return the cause of the last reset

  • CY_SYS_RESET_WDT       – WDT caused a reset
  • CY_SYS_RESET_PROTFAULT – Occured protection violation that requires reset
  • CY_SYS_RESET_SW        – Cortex-M0 requested a system reset.

My program looks for a WDT Reset, and if that happens it turns on the Red LED and hangs the program with an infinite while loop.  If it was a normal (XRES or Power up) boot of the chip it will just run the infinite for loop.

In the main loop of the program you can see that it blinks the Blue LED quickly (5 Hz)… then if you don’t feed the WDT it resets the chip.  If you uncomment the “CySysWatchDogFeed” the chip will continue to blink the Blue LED until the end of time.

#include "project.h"

int main(void)
{
    CyGlobalIntEnable; /* Enable global interrupts. */
    
    if(CySysGetResetReason(CY_SYS_RESET_WDT) == CY_SYS_RESET_WDT )
    {
        CySysWdtDisable(CY_SYS_WDT_COUNTER0_MASK);
        red_Write(0); // turn on the red LED
        while(1);     // hang
    }

    for(;;)
    {
        blue_Write(~blue_Read());
        // If dont feed the WDT it will cause a reset in ~3 seconds
        //CySysWatchdogFeed(CY_SYS_WDT_COUNTER0);
        CyDelay(100);
          
    }
}

PSoC4 Watch Dog Timer: Callback

Instead of just reseting the chip on the 3rd match of the WDT timer, you can ask to be called via an interrupt when the match occurs.  To accomplish this, start by configuring one or more of the WDT Timers to a “Watchdog (w/ Interrupt)”.  When you select “w/Interrupt” you can either use an ISR that Cypress provides or you can create your own ISR.

PSoC4 Watch Dog Timer: CallBack Example

The ISR that Cypress provides does two basic things.  First, if you have registered your interest in being called back, it calls your callback subroutine.  After the three callbacks are done, it resets the counters and clears the WDT.  In the block of code below you can see on Line 20 that I register my call back.  The routine “wdtInterruptCallback()” is then called each time that WDT Timer expires, A.K.A about 1/second.  This makes the Blue LED bink on/off.  The other interesting thing in this code is that I show that the chip can be put into deep sleep and the WDT will continue to run.

#include "project.h"

void wdtInterruptCallback()
{
    blue_Write(~blue_Read());   
}


int main(void)
{
    CyGlobalIntEnable; 
    
    if(CySysGetResetReason(CY_SYS_RESET_WDT) == CY_SYS_RESET_WDT )
    {
        CySysWdtDisable(CY_SYS_WDT_COUNTER0_MASK); // Disable the WDT
        red_Write(0); // Turn on the red LED
        while(1);     // Hang
    }
 
    CySysWdtSetInterruptCallback(CY_SYS_WDT_COUNTER0,wdtInterruptCallback);

    for(;;)
    {
        CySysPmDeepSleep(); // Put the chip into deep sleep.       
    }
}

PSoC4 Watch Dog Timer: Custom ISR

If you do not want to use the Cypress provided ISR you can create your own.  In order to do this you need to add the ISR and Global Signal components to your schematic:

PSoC4 Watch Dog Timer: Custom ISR Schematic

This will attach the WDT Interrupt Signal to the NVIC.  In your source code you will need to provide the handler function for isr_1.  My custom ISR is called “wdtInterruptHandler”.  All it does is toggle the Blue LED, then clear the WDT Interrupt.

#include "project.h"

void wdtInterruptHandler()
{
    blue_Write(~blue_Read());
    CySysWdtClearInterrupt(CY_SYS_WDT_COUNTER0_INT);
    
}


int main(void)
{
    
    if(CySysGetResetReason(CY_SYS_RESET_WDT) == CY_SYS_RESET_WDT )
    {
        red_Write(0); // turn on the red LED
        while(1);     // hang
    }
    
    CyGlobalIntEnable; /* Enable global interrupts. */
  
    
    isr_1_StartEx(wdtInterruptHandler);
    
    CySysWdtEnable(CY_SYS_WDT_COUNTER0);
   
    for(;;)
    {
        CySysPmDeepSleep();
          
    }
}

PSoC4 Watch Dog Timer: Watch Dog Reset

As I was reading all of the documentation I started thinking about how I could write a program that could show that three unserviced interrupts would cause the reset.  I originally thought that I could put a counter in the ISR and then reset the the WDT on the 3rd call, however, that does not work because when you return from the ISR, the WDT Interrupt is still pending.  When the interrupt is still pending it just jumps right back into the ISR.  In order to show the three unserviced calls, I created the program below which starts toggling a pin as fast as possible when the ISR is called.  This loop ends only when the chip is reset.

#include "project.h"

void wdtInterruptHandler()
{
    while(1) WDTSignal1_Write(~WDTSignal1_Read());
}

int main(void)
{
  
    WDTSignal0_Write(1);
  
    if(CySysGetResetReason(CY_SYS_RESET_WDT) == CY_SYS_RESET_WDT )
    {
        CySysWdtDisable(CY_SYS_WDT_COUNTER0_MASK);
        red_Write(0); // turn on the red LED
        while(1);     // hang
    }
    
    isr_1_StartEx(wdtInterruptHandler);
    
    CySysWdtEnable(CY_SYS_WDT_COUNTER0);
    CyGlobalIntEnable; /* Enable global interrupts. */
    
    for(;;)
    {
    }
}

I configured the period for the WDT to be ~3ms.  The yellow trace labeled “1” is a pin that is written to 1 by the main loop when the chip starts main().  You can see that the time from main starting until the ISR starts toggling is about 3ms.

PSoC4 Reset Example (start to ISR)

Then inside of the ISR you can see that the toggling goes on for about 6ms (a.k.a two WDT periods)

PSoC4 Reset Example

Finally, you can see the chip reset, then reboot, which takes about 2ms.  You do not see the rising edge in main on the last picture because it takes about 500ms for the WCO to stabilize and main to start.

PSoC4 Reset Example

FreeRTOS: A PSoC4 FreeRTOS Port

Summary

In my work life, I am working on some systems that will require more complicated firmware architectures built using real time operating systems.  As I need to get more familiar with RTOSs, I thought that I would go ahead and start using them in my PSoC 4 projects.  The logical one to start with is FreeRTOS.  In this article I will take you through the steps to create a PSoC4 FreeRTOS port.

  1. Introduce FreeRTOS
  2. Execute a PSoC4 FreeRTOS Port
  3. Create a PSoC4 FreeRTOS Test Project (the blinking LED)

FreeRTOS Background

FreeRTOS is a light weight, open-source, real time operating systems for embedded systems that was developed by RealTime Engineers.  Their basic business plan is to sell consulting and support services to semiconductor companies their customers.  All of the source code is available (mostly in plain C) and easy to use.  In addition there are ports to 35 MCUs (including all of the Cypress ARM chips).  FreeRTOS is frequently cited as the most popular embedded RTOS which is easy to understand as I have found it easy to use and very stable.

Execute a PSoC4 FreeRTOS Port

The port of FreeRTOS to PSoC4 is actually pretty trivial, once you figure it out.  But I suppose that is how things often go.  FreeRTOS comes preconfigured with a GCC version of an ARM Cortex-M0 port.  All that needs to be done is to hook the basic port to the correct PSoC4 systems.  There are generic porting instruction on the FreeRTOS site but these are my PSoC specific steps:

    1. Download FreeRTOS V9.0.0
    2. Add the include directories “FreeRTOS/Source/include” and “FreeRTOS/Source/portable/GCC/ARM_CM0” to your project by right clicking on the project and editing “Build Settings…”  You should add those directories to the “Additional Include Directories”Configuring the PSoC 4 FreeRTOS build settings
    3. Right click on the project and “Add Existing Item” so that you can add the .c & .h files from FreeRTOS/Source/portable/GCC/ARM_CM0  to your projectAdd the PSoC4 FreeRTOS Files to Project
    4. Add the .c files from FreeRTOS/Source/ to your project
    5. Add the .h files from FreeRTOS/Source/include to your project
    6. Add “heap_1.c” (or which ever memory manager you want) from FreeRTOS/Source/portable/MemMang
    7. Create the “setupFreeRTOS” function to install the Interrupt Service vectors required by FreeRTOS.
extern void xPortPendSVHandler(void);
extern void xPortSysTickHandler(void);
extern void vPortSVCHandler(void);
#define CORTEX_INTERRUPT_BASE          (16)
void setupFreeRTOS()
{
    /* Handler for Cortex Supervisor Call (SVC, formerly SWI) - address 11 */
    CyIntSetSysVector( CORTEX_INTERRUPT_BASE + SVCall_IRQn,
        (cyisraddress)vPortSVCHandler );
 
    /* Handler for Cortex PendSV Call - address 14 */
	CyIntSetSysVector( CORTEX_INTERRUPT_BASE + PendSV_IRQn,
        (cyisraddress)xPortPendSVHandler );    
 
    /* Handler for Cortex SYSTICK - address 15 */
	CyIntSetSysVector( CORTEX_INTERRUPT_BASE + SysTick_IRQn,
        (cyisraddress)xPortSysTickHandler );
}

8. Create the FreeRTOSConfig.h First, add a new file called FreeRTOSConfig.h file to the project (right click on the project and “add new item”.  This file contains a bunch of CPP macros to setup FreeRTOS.  You can get this file by copy/pasting from the the linked website into your blank FreeRTOSConfig.h file.
9. Modify FreeRTOSConfig.h I made the following changes to the default configuration file:

// Add the PSOC Creator Macros for the PSoC4 Registers 
#include "project.h"
// PSoC Creator creates a #define macro for the clock settings from the DWR
#define configCPU_CLOCK_HZ ( ( unsigned long ) CYDEV_BCLK__SYSCLK__HZ )
// SysTick Defaults to 1ms
#define configTICK_RATE_HZ                      1000
#define configSUPPORT_STATIC_ALLOCATION   0
#define configSUPPORT_DYNAMIC_ALLOCATION  1
#define configTOTAL_HEAP_SIZE               10240
#define configAPPLICATION_ALLOCATED_HEAP 0
// During an assert just put into a busy wait
#define configASSERT ( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); }

Create a PSoC4 FreeRTOS Test Project

The example project is a simple blinked LED.  It starts with a “Task” function which I call LED_Task.  This just reads the current value of the RED Led pin, inverts it, and writes it back.  Then it does and RTOS delay of 500 ms.  The main look just turns on the interrupt system, initializes the RTOS, Creates the LED Task, then starts the scheduler.  The Scheduler will never return.

void LED_Task(void *arg)
{
    (void)arg;
 
        while(1) {
        RED_Write(~RED_Read());
        vTaskDelay(500);
        }
}
 
int main(void)
{
    CyGlobalIntEnable; /* Enable global interrupts. */
 
    setupFreeRTOS();
 
    /* Create LED task, which will control the intensity of the LEDs */
    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();
}

ThingSoC: Four I2C OLED Displays with PSoC4L

Pattern Agents are running a crowd funding effort for ThingSoC TSoC4L … help them here

Summary

In the previous ThingSoC post I took you through building the firmware to make the PSoC4L drive the ThingSoC I2C hub.  Now what?  When originally looking around I saw a picture with 4x LCDs connected to the I2C hub, which I thought was cool. In this post Ill show you how to do the same thing with PSoC and the U8G2 library which I talked about in this article. To do this I will:

  1. Create New PSoC4L Project + Integrate the U8G2 Library
  2. Update the PSoC4L Firmware
  3. Test the PSoC4L Firmware

Here is the picture:

4 I2C Displays, Inspiration

Create New PSOC4L Project + Integrate the U8G2 Library

Maybe it should have been obvious, but for some reason it never occurred to me to do a copy/paste to duplicate a project.  I guess that I’m slow that way.  To do this right click on a project in the workspace explorer and then do paste.

PSoC Creator Edit Build Settings

The next step is to integrate the firmware from the U8G2 Library. Start by “gitting” with “git@github.com:olikraus/u8g2.git”.  Then you need to add the directory to your project by right clicking the project and selecting “Build Settings”.  You need to add U8G2 Library to the additional include directories.

Add the U8G2 Library

Add the all of the .h and .c files by right clicking the project and selection “Add->Existing Item”

copy the u8g2 files into the PSoC4L project

Navigate to the U8G2 library and add all of the .c and .h files.  The last thing you need is to bring in the HAL that I wrote for PSoC and described in this post.  Specifically you need to bring in the two functions

  • psoc_gpio_and_delay_cb
  • u8x8_byte_hw_i2c

I suppose that I should package the whole thing up in a component.  But, Ill leave that as an exercise for the reader.

Update the PSoC4L Firmware

The cool thing about the whole setup with the I2CHUB is that it allows you to have 4 devices with the same I2C address attached to one PSoC SCB at the same time.  To get going with the firmware, I start by defining an array of u8x8_t structures to represent the 4 different displays attaches to the 4 different ports on the I2C hub. (line 186).  Then I create a function called setupDisplay that initializes the display etc. (lines 199-203).  The only trick in the firmware is that Dennis Ritchie defined arrays to run from 0-3 but the I2C busses are labeled 1-4,  this is the reason for subtracting 1 from the input lcd number.

PSoC4L Firmware to initialize the U8G2 Display

The next step is modifying command processors in the main loop.  Specifically, I will add the commands q,w,e,r to startup the displays on I2C ports 1,2,3,4.  And, I will add those commands to the help print out.

Modifying the PSoC4L CLI

Test the PSoC4L Firmware

In order to make a connection from the Grove 4-pin connectors to my breadboard I used Switch Doc Labs connectors which I bought from Amazon.com.  For some reason you can’t purchase them from the Switch Doc Labs website or the SeeedStudio website, but they are very handy.  As an unrelated side note I had never seen (or in fact ever heard of) Switch Doc Labs.  But their website has a bunch of tutorials about the Raspberry Pi and Grove ecosystem boards for use with IoT-ifying house plants.  Seemed pretty cool.

Grove to Breadboard Switch Doc Labs Breakout Cable

Now when I press “qwer” in my command console I get this:

PSoC4L Driving 4 OLED LCDs

You can find all of the projects in the TSoC Series at my GitHub ThingSoC repository git@github.com:iotexpert/ThingSoC.git

Index Description
ThingSoc: TSoC PSoC4L Development Kit from PatternAgents Introduction to ThingSoC
ThingSoC PSoC4L: Using & Debugging the PSoC4 Clock Debugging a beta firmware problem
ThingSoC: The TSoC GROVEY I2CHUB : I2C Hub/Switch Evaluating the ThingSoC I2C Hub
ThingSoC: Multiple I2C Displays Using the I2CHUB and U8X8 Library A project using ThingSoC I2C Hub & 4 OLED Displays

ThingSoC: The TSoC GROVEY I2CHUB : I2C Hub/Switch

Pattern Agents are running a crowd funding effort for ThingSoC TSoC4L … help them here

Summary

One of the boards that the Pattern Agents guys sent me was a TSOC GROVEY I2CHUB : I2C Hub/Switch.  In this post I will take you through the process that I went through to evaluate the board and build an interface to the ThingSoc TSoC 4L base board.

  1. Introduction to the TSoC Grovey I2CHUB
  2. Discussion of PCA9546A I2C
  3. Using the MiniProg-3 to interact with the PCA9546A
  4. Building a Command Line Interface (CLI) using the USB/UART
  5. Adding firmware to mimic the MiniProg-3 I2C list to the CLI
  6. Adding a “port change” feature to the CLI firmware

Introduction to the TSoC Grovey I2CHUB

The ThingSoC I2C Hub is a ThingSoC Compatible (not Compliant) board that serves as a bridge from the base board to 4 separate programmable I2C busses using an NXP/TI 9546A bridge chip.  Each of the I2C busses is attached via a SeeedStudio Grove connector.  Grove is an ecosystem of sensors (Humidity, Temperature etc.) that are all? mostly? I2C connected.

ThingSoC I2CHub

Discussion of PCA9546A I2C

The PCA9546A is made by TI and NXP (or whatever they are calling themselves these days) and can be purchased for about $0.70 from Digikey, Mouser, or Arrow.  The chip is pretty cool.  It will let you connect your I2C master to 1 of 4 I2C busses.  It will actually let you connect more than one bus at a time.  This chip enables you to connect multiple slaves with the same address to your I2C master.

Here is a simplified picture from TIs datasheet.

PCA9546A Block Diagram

To control the system you just need to write into the control register with a bit mask.  The bit masks contains which slaves busses you want switched on.  Here is a screen shot from NXPs datasheet:

PCA9546A Control Register

Using the MiniProg-3 to interact with the PCA9546A

I start the whole firmware journey by using a MiniProg-3 as an I2C<–>USB bridge.  This allows me to type I2C commands in the Bridge Control Panel which go directly to the chip (without writing firmware).  In the picture below you can see that I have the MiniProg-3 attached to the ThingSoC board using jumper wires.  I also use the MiniProg-3 to power the board.

Using a MiniProg-3 to Probe the ThingSoC I2C Hub

When I press “List”, the Bridge Control Panel probes all of the I2C addresses.  If a device ACKs, it prints out that fact in the output window.  In the picture below you can see that PCA9546A is attached at address 0x73.  I then read and write the control register, which also works as expected.

Bridge Control Panel

The address 0x73 makes sense as you can see that (in the picture above) there is a blob of solder on “A2” which pulls it low (instead of the default high).  Here is that part of the schematic:

ThingSoC Schematic for PCA9546A Address Selection

Building a Command Line Interface (CLI) over the USB/UART

Now I am  ready to build a command line interface using the USB <–> UART Bridge.  First, I make a schematic with the USB-FS (Full Speed), LED and I2C components.  Notice that the USBFS is setup as a USBUART.  The I2C is configured as a Master.

PSoC Creator Schematic for ThingSoC I2C Hub Firmware

The Pins are selected as:

PSoC Creator Pin Selection

Next is a helper function to printout text via the CDC UART:

PSoC Creator Firmware PrintBuff Helper Function

Then I write a little bit of firmware for the CLI.  The function just reads from the UART and, if the user has pressed a button, then it issues that command.

Lines 99-103 get the USBUART going, and deal with changes (e.g. unplug events).

The only thing that you might not have seen is the “Clear Screen”.  I just send out the escape sequence (old school) for clear screen and move home from the VT100 Escape Codes.

PSoC Creator Main Command Line Interface

Adding firmware to mimic the MiniProg-3 I2C list to the CLI

When you press “List” in the Bridge Control Panel, what happens?  Although I have been using the Bridge Control Panel for years I wasn’t exactly sure.  To find the answer, I plugged in my Saleae Logic 16 and watched the output.

Probing using MiniProg-3 and Saleae Logic-16

In this screenshot from the Saleae Logic output screen,  you can see that the Bridge Control Panel sends out a “Read 0x15” which was NAKed.

Saleae Logic 16 address 0x15 NAK

In this screen shot you can see that when the “Read 0x73” occurs, that the PCA9456A ACKs which tells the Bridge Control Panel that the device is there.

Saleae Logic 16 0x73 ACK

While I was writing the entry, I looked around at several implementations.  It appears that sometimes people send “Write Address” instead of “Read Address”.  I wasn’t sure exactly what was right, so I consulted Dr. Zwave.  He really should go by Dr. I2C since that is what he did at Cypress.  Anyway, he pointed out that you will hang the I2C bus if you try a Read and then don’t read the next byte.  With a write you don’t actually need to keep writing.  I decided to follow his instructions.

I have always liked the output of the Raspberry Pi I2CDetect command.  Here is a screen shot from one of my Raspberry Pi’s where a PSoC4 is attached on I2C Address 0x8.  I am not totally sure why the command does not probe addresses 0x00-0x02 (comment with the answer and Ill send you a devkit)

Raspberry Pi I2CDetect

The implementation of i2c_detect on the PSoC4L is pretty simple.  All I need to do is iterate through all of the addresses from 0->0x7F.  Then attempt to write.  If a device ACKs then printout the address, otherwise move on.  Instead of  one big loop, I split it up into two loops to make the printing a little bit simpler.  Here is the code:

PSoC Creator I2C Detect Firmware

Now, when I press “l” on the CLI, it probes all of the legal addresses on the I2C bus from the PSoC4L.  You can see that only the PCA9546A at address 0x73 is active.  How cool is that?

PSoC Creator Firmware I2CDetect

Adding a “port change” feature to the CLI firmware

The last block of code adds three functions which let me control the PCA9546A control register.

PSoC Creator PCA9546A Control Firmware

To test the whole thing, I attach the Saleae Logic Analzer to I2C Port1.  Then I probe to make sure that I can attach and unattached the bus.

Test Jig for PSoC Creator Firmware

You can find all of the projects in the TSoC Series at my GitHub ThingSoC repository git@github.com:iotexpert/ThingSoC.git

Index Description
ThingSoc: TSoC PSoC4L Development Kit from PatternAgents Introduction to ThingSoC
ThingSoC PSoC4L: Using & Debugging the PSoC4 Clock Debugging a beta firmware problem
ThingSoC: The TSoC GROVEY I2CHUB : I2C Hub/Switch Evaluating the ThingSoC I2C Hub
ThingSoC: Multiple I2C Displays Using the I2CHUB and U8X8 Library A project using ThingSoC I2C Hub & 4 OLED Displays

Pinball: Driving the OLED using the U8G2 Library

In the previous Pinball post, I wrote about getting the OLED going and getting the footprint onto my printed circuit board.  Now I need to make PSoC firmware to drive the display.  I turns out that there are a number of different driver chips out there including at least SSD1306, SH1106, LD7032, SSD1325, and ST7920 that handle multiplexing the columns/rows, managing frame buffers, power management, etc.  To make matters more fun, these chips support I2C, 3&4 wire SPI and a couple of different parallel interfaces (6800, 8080).  I certainly didn’t want to go down the rathole of building up a complete driver library.  But I didn’t have to, as it turns out that that Oliver Kraus built and open-sourced a very nice library that you can get at www.github.com/olikraus/u8g2.  This library (and its predecessor u8glib) seem to be in pretty wide use in Arduino and Raspberry Pi.

In order to make the library work with the PSoC I had to do several things

  1. Download it from GitHub (git clone git@github.com:olikraus/u8g2.git)
  2. Created a new PSoC4200M project for the CY8CKIT-044 (which was the devkit that I happened to have sitting next to my computer)
  3. Change the build settings (right click on the project and select building settings) then add the directory in “Additional Include Directories” and include the “u8g2/csrc” directory.
  4. Add the header files to the project by right clicking and selecting “Add->Existing item” so that the project can f
  5. Add the U8G2 C-Files to the project (same as step 4 but add the C files)
  6. Build a schematic which has an I2C (for the display) and a debugging UART.  The I2C is configured as a master with 400kbs data rate.  The UART uses the default configuration.
  7. Assign the pins

Now I am ready to build some firmware that will drive the display.  In order to use the library with a PSoC I need to create two functions for the U8G2 HAL to use as an interface to the PSoC hardware.  You initialize the U8G2 system with a call to the u8x8_Setup function.  In that call you need to provide function pointers too the two HAL functions

  1. The GPIO and Delay Interface
  2. The byte oriented communication interface

This is an example of the setup required:

The GPIO and Delay interface is used by the byte oriented communication functions to read/write the GPIOs and provide delays.  This function provides the underpinnings of a bit-banged I2C, UART, SPI etc.  Because I am only going to use PSoC Hardware to provide the I2C interface I will only respond to the delay messages.  All of the delay functions are implemented as busy wait loops, which I am not a big fan of.  The input to the function is a “message” that is one of a sprawling list of #defines in the file u8x8.h.  I believe that I found all of the possible cases, but I am not sure.

The first message, UX8X8_MSG_GPIO_AND_DELAY_INIT doesnt need to do anything because the GPIOs are configured correctly by the default.

I did not respond to the messages of the form U8X8_MSG_GPIO_X which are the read and write of the GPIOs as I am not going to use the bit-banged interface.

The other function that needs to be provided is the byte-oriented communication function.  This function needs to respond to the messages to start, send, and end communication.  I just mapped those messages onto the PSoC hardware APIs.  While I was trying to understand what was happening with the system I implemented a debugging UART which you can see in the #ifdef DEBUG_UART sections.

You can find all of the source code and files at the IOTEXPERT site on github.

Index Description
Pinball: Newton's Attic Pinball An introduction to the project and the goals
Pinball: Lotsa Blinking LEDs Everyone needs a bunch of LEDs on their Pinball Machine
Pinball: Matrix LEDs (Part 1) Saving PSoC pins by using a matrix scheme
Pinball: Matrix LEDs (Part 2) Solving some problems with the matrix
Pinball: Matrix LEDs Component How to turn the Matrix LED into a component
Pinball: A Switch Matrix Implementing a bunch of switches
Pinball: Switch Matrix Component (Part 1) The switch matrix component implementation
Pinball: Switch Matrix Component (Part 2) The firmware for matrix component
Pinball: Switch Matrix Component (Part 3) Test firmware for the matrix component
Pinball: The Music Player (Part 1) The schematic and symbol for a Music Player component
Pinball: The Music Player (Part 2) The Public API for the Music Player component
Pinball: The Music Player (Part 3) The firmware to make the sweet sweet music
Pinball: The Music Player (Part 4) The test program for the music player
Pinball: The Motors + HBridge Using an Bridge to control DC Motors
Pinball: The Eagle Schematic All of the circuits into an Eagle schematic
Pinball: The Printed Circuit Board 1.0 The first Eagle PCB layout of the printed circuit board
Pinball: The PCB Version 1.0 Fail Problems with the first version of the Eagle PCB layout
Pinball: PCB Layout 1.2 Updates using Eagle Fixing the errors on the first two versions of the Eagle PCB
Pinball: Assemble and Reflow the 1.2 PCB Assembling the Eagle PCB
Pinball: Testing the Eagle PCB Firmware to test the newly built Pinball printed circuit board
Pinball: Debugging the Motor Driver Fixing the motor driver PSoC project
Pinball: Hot-Air Reworking the Accelerometer Solder Using a Hot-Air Rework tool to reflow a QFN
Pinball: Debugging the LM317 Power Supply- A Tale of Getting Lucky Debugging the LM317/LM117 power supply

ThingSoC PSoC4L: Using & Debugging the PSoC4 Clock

Pattern Agents are running a crowd funding effort for TSoC … here

Summary

In the previous post I told you that I immediately blew away the factory firmware on the TSoC4L board.  I’m like that sometimes :-).  In this post I am going to take you through the entire process of getting and reprogramming the factory firmware, then finding and debugging a PSoC4 clock problem.  The rest of this post is:

  1. Getting the correct firmware back on the TSoC4L Board
  2. Running into a bug in the beta version of the firmware
  3. Using the debugger to find the bug
  4. Explaining the functionality of Low Frequency Clocks and the Watch Dog Timer
  5. The Pattern Agents bug fix

Factory Firmware

Getting things going again starts with “git”ing the firmware.  This can be done by “git clone git@github.com:PatternAgents/TSOC_PSoC4L.git”.  Once you have the repo cloned you will find a bunch of good stuff including:

  1. datasheets: All the datasheets
  2. documentation: The PatternAgents documentation (quick start)
  3. drivers: The windows USB <-> UART drivers
  4. eagleUp: JPG renderings of the PCB
  5. firmware: The PSoC Creator Project
  6. hardware: gerbers, boms etc
  7. images: renderings of the board, photos of the board etc
  8. revisions: old revisions of the Eagle project files
  9. The Eagle PCB Project including schematic and layout

TSoC4 L Files from GitHub

When you open the PSoC Creator Workspace you will find two projects

  1. A USB Bootloader – called “USBFS_Bootloader”
  2. The TSoC RSVP Firmware – called “rspvsis_4l_typ”

The system is supposed to

  1. Start the USB HID bootloader (so you could get new firmware).  Wait for 10 seconds for a bootloader host to start then if it doesnt … then start
  2. The RSVP Firmware

When you plug in the board you will see the TSoC4L enumerate as “Cypress ThingSoc Bootloader”.  Then, after 10 seconds, you should see it reboot, then enumerate as “Cypress USB UART”.  But, this was not happening for me.  Why?  I wasn’t sure.  The first thing that I did was add a blinking LED circuit that looked like this:

Blinking LED

But the LED was not blinking.  That meant that the firmware was not even getting to main i.e. it was hanging BEFORE main in the PSoC boot code.  But where and why?

Using the Debugger to Find the Bug

How do you figure out where the system is stuck if you can’t even use the “blinking LED” or “printf” debug?  Simple.  Use the debugger.  Start by programming the PSoC with your firmware.  Then click “Debug->Attach to running target”.

Starting the PSoC Debugger

The debugger will start.  Then you will be able to press the “Pause” button. which will take you to a screen that looks like this:

PSoC4 Clock Busy Wait Loop

The chip is stuck on line 234.  What does line 234 do?  That is a busy wait loop.  It is waiting for the Watch Dog Control Register to clear.  To explain that, I will need to take you through the PSoC4 Low Frequency Clocks.  First you should notice that the file we are in is named “cyfitter_cfg.c”.  What is this file?  If you look at the top, this is what PSoC Creator says.

This means that the “cyfitter_cfg.c” file is synthesized by PSoC Creator when you do a build based on what you configured when you setup your project.  This file contains a bunch of the startup code including the code that gets the clock systems going.  Line 234 is inside of a function called “ClockSetup”.  All of this code is called BEFORE you get to main().

The PSoC4 Clock(s)

To explain why we are stuck there you first need to double click on the “Clocks” tab in the Design Wide Resources.  When you do that it will take you to this screen which contains a bunch of information about the clocking system in the PSoC.

PSoC4 Clock Setup

In the screen above, you can see that there are three Timers in the Watch Dog Timer system (WDT) that are clocked (i.e. have a Source Clock of) by the Low Frequency Clock (LFCLK).  The LFCLK has its source as the Watch Crystal Oscillator (WCO).  If you double click the WCO line it will take you to a screen that is much easier to see what is going on, specifically the “Configure System Clocks” screen:

PSoC4 Clock - Low Frequency

In the screen above you can see that the LFCLK has two choices of oscillator sources, the “ILO” or the “WCO”.  ILO stands for Internal Low Speed Oscillator.  The ILO is a fairly inaccurate (+- 60%) RC oscillator that is built inside of the chip.   It is designed to be very low power which is why it is so inaccurate.  If you need a more accurate oscillator, then you should use an external oscillator, specifically a Watch Crystal Oscillator or WCO.  A WCO is a 32.768KHz crystal oscillator.  These watch crystal oscillators give you very precise clocks that can be used to drive real time clocks accurately.

The next thing to see is there are three Watch Dog Timers (WDT) numbered 0-2.  These times are driven by the “LFCLK”.  Here is a picture from the PSoC Technical Reference Manual.


PSoC4 Clock - WDT Block Diagram

So what is the “CYREG_WDT_CONTROL”?  You can find that by looking in the PSoC4 Registers TRM.

PSoC4 Clock WDT Control Register

The busy wait loop is waiting for bits 19,11,3 to be cleared.  Those bits are “WDT_RESETx”  They become 0 when the three WDT timers are cleared which happens “several LFCLK cycles” after the reset.  As a reminder, here is that block of code:

This still leaves us with the question, “What is the problem?”.  If you look on the back of the ThingSoC4L board you will see there is no Crystal populated on this board. (the blank footprint on the right side of the back).  The WCO is an optional feature from Pattern Agents.  If you need the more accurate timing, you need to solder on your own Crystal.

Backside of ThingSoC4L PCB

If there is no WCO crystal, then the WDT timer reset will never happen because LFCLK isn’t doing anything.  And, the busy wait loop will never end.  Mystery solved.

The Pattern Agents Bug Fix

To fix the startup problem, the Pattern Agents guys changed the clock configuration to

  1. Turn off the WDTs
  2. Use the ILO as the source of the LFCLK

PSoC4 Clock - Low Frequency Setup

You can find all of the projects in the TSoC Series at my GitHub ThingSoC repository git@github.com:iotexpert/ThingSoC.git

Index Description
ThingSoc: TSoC PSoC4L Development Kit from PatternAgents Introduction to ThingSoC
ThingSoC PSoC4L: Using & Debugging the PSoC4 Clock Debugging a beta firmware problem
ThingSoC: The TSoC GROVEY I2CHUB : I2C Hub/Switch Evaluating the ThingSoC I2C Hub
ThingSoC: Multiple I2C Displays Using the I2CHUB and U8X8 Library A project using ThingSoC I2C Hub & 4 OLED Displays

ThingSoC: TSoC PSoC4L Development Kit from PatternAgents

Pattern Agents are running a crowd funding effort for ThingSoC TSoC4L … help them here

Summary

Last week I got a box in the mail from my friend Tom Moxon in Oregon.  He runs a company called Pattern Agents.  I was excited when I saw the box because I love new development kits.  I was even more happy when I opened the box and found a ThingSoC PSoC4L kit.

Tom sent me three boards

  1. A ThingSoC PSoC4L
  2. A MiniProg Adaptor
  3. A ThingSoC I2C Hub

ThingSoC PSoC 4L Packaging

ThingSoC PSoC4L

The ThingSoC complies to a new open source stackable footprint called the ThingSoC Open Source Socket.  This ThingSoC board is driven by a PSoC4L.  The PSoC4L is the largest and most capable of the PSoC4 family.  This chip “completed” the high end of the PSoC4 family by adding more IOs, more Flash, more RAM and a USB controller.  The PSoC4L serves as the base MCU in the stack as well as providing a bridge to the PC via a USB <–> UART Connection.  The board also has a connection for a 3.7V LiPo battery to power the system.  In the picture below you can see the base board (on the left) with the programmer attachment (on the right).  The programmer attachment lets you attach a MiniProg-3 or a Uart Bridge or an ISSP connection (like a MiniProg-1).

thingsoc 4200l

Here is a picture of the backs of the boards.  On the back of the ThingSoC PSoC4L board you can see a place to solder a Cypress NVSRAM as well as a footprint for a Watch Crystal.

The backs of the ThingSoC PSoC4L

The Blinking LED

The first thing I did with the board (and no, reading the instructions wasn’t the first thing) was program the chip to blink the LED.  Obviously with a PSoC the best thing to do was make a schematic with a PWM driving the USER LED pin:

I used the default clock of 12MHZ, then I used the PWM pre divider to get the frequency down to something that I could see.

Lastly, I wrote a tiny bit of firmware to get things going.  Notice that I use the CySysPmSleep to put the CPU to sleep.  It never wakes up from this sleep (because there are no interrupt sources to wake it up).  But, if it did, it would go right back to sleep because of the loop.

After programming the board, the LED started right up.  That is good as it means everything makes sense.

When I programmed the Blinking LED project I overwrote Tom’s default firmware which is called “RISC”.  In the next post Ill talk more about the architecture of the ThingSoC PSoC4L.

You can find all of the projects in the TSoC Series at my GitHub ThingSoC repository git@github.com:iotexpert/ThingSoC.git

Index Description
ThingSoc: TSoC PSoC4L Development Kit from PatternAgents Introduction to ThingSoC
ThingSoC PSoC4L: Using & Debugging the PSoC4 Clock Debugging a beta firmware problem
ThingSoC: The TSoC GROVEY I2CHUB : I2C Hub/Switch Evaluating the ThingSoC I2C Hub
ThingSoC: Multiple I2C Displays Using the I2CHUB and U8X8 Library A project using ThingSoC I2C Hub & 4 OLED Displays

Pinball: The Music Player (Part 1)

After a few days off (Im sorry) I am back to it.  Every Pinball machine does lots of beeping, buzzing and music playing as will this one.  A very inexpensive way to make sound is to use a piezo-electric buzzer.  To make it “buzz”, you just drive a 50% duty cycle square wave into it at the frequency you want.  This is a perfect task for the PSoC4 BLE Timer Counter Pulse Width Modulator (TCPWM).  There are obviously limitations with this scheme, starting with you can only play one note at a time, and the notes can only be square (real sound has a much more complex waveforms).  But all of that is OK because the buzzer work OK and, as I said… they are cheap.  On the Pinball printed circuit board I have placed two buzzers, my thought was one would be used for buzzing and one would be used to play a song.

To make things easier for the main firmware I will build a component just like I did for the LEDs and the Switches.  Start by creating a new component by:

  • Click on the components tab
  • Right click on the “Pinball Component” library project and select “Add Component Item…”
  • Select “Symbol Wizard”, give the component the name “MusicPlayer” (exactly like I did in the LED and Switches components)

I thought that it would be nice for the MusicPlayer component to be able to select if it is a one or two channel player.  So, right click on the blank part of the symbol editor canvas and select “Symbol Parameters”.  Next add a bool parameter called “TwoChannels”

screen-shot-2016-09-20-at-6-28-32-am

To put the component in the correct place in the Component Browser right click the blank canvas, select “edit properties”, edit the”Doc.CatalogPlacement” and enter the placement of “Pinball/MusicPlayer/”

screen-shot-2016-09-20-at-6-43-51-am

Next, you need to create the schematic for the music player.  You do this by right-clicking on the “Pinball Component” project and adding a “Schematic” implementation.  Then add the default clocks, the TCPWMs and the pins.

screen-shot-2016-09-20-at-6-26-40-am

Earlier I added a component parameter called “TwoChannels”.  When this parameter is false, I want to remove the extra components.  With the help of the Cypress component manager I found out how to do this.  And it is simple.  Just add an expression to the TCPWM, Pin and Clock “CY_REMOVE” Parameter.  This parameter shows up on the “Built-in” tab for these three components (in fact all Cypress components).  When the value is “true” the component magically disappears.

screen-shot-2016-09-20-at-6-27-55-am

Next, I configure the TCPWM to have the prescaler turned on (which divides the input clock).  This is used to reduce the default 12MHz clock down to an easier to control 93.75Khz.

screen-shot-2016-09-20-at-6-27-11-am

In the next post Ill show you the firmware.

You can find all of the source code and files at the IOTEXPERT site on github.

Index Description
Pinball: Newton's Attic Pinball An introduction to the project and the goals
Pinball: Lotsa Blinking LEDs Everyone needs a bunch of LEDs on their Pinball Machine
Pinball: Matrix LEDs (Part 1) Saving PSoC pins by using a matrix scheme
Pinball: Matrix LEDs (Part 2) Solving some problems with the matrix
Pinball: Matrix LEDs Component How to turn the Matrix LED into a component
Pinball: A Switch Matrix Implementing a bunch of switches
Pinball: Switch Matrix Component (Part 1) The switch matrix component implementation
Pinball: Switch Matrix Component (Part 2) The firmware for matrix component
Pinball: Switch Matrix Component (Part 3) Test firmware for the matrix component
Pinball: The Music Player (Part 1) The schematic and symbol for a Music Player component
Pinball: The Music Player (Part 2) The Public API for the Music Player component
Pinball: The Music Player (Part 3) The firmware to make the sweet sweet music
Pinball: The Music Player (Part 4) The test program for the music player
Pinball: The Motors + HBridge Using an Bridge to control DC Motors
Pinball: The Eagle Schematic All of the circuits into an Eagle schematic
Pinball: The Printed Circuit Board 1.0 The first Eagle PCB layout of the printed circuit board
Pinball: The PCB Version 1.0 Fail Problems with the first version of the Eagle PCB layout
Pinball: PCB Layout 1.2 Updates using Eagle Fixing the errors on the first two versions of the Eagle PCB
Pinball: Assemble and Reflow the 1.2 PCB Assembling the Eagle PCB
Pinball: Testing the Eagle PCB Firmware to test the newly built Pinball printed circuit board
Pinball: Debugging the Motor Driver Fixing the motor driver PSoC project
Pinball: Hot-Air Reworking the Accelerometer Solder Using a Hot-Air Rework tool to reflow a QFN
Pinball: Debugging the LM317 Power Supply- A Tale of Getting Lucky Debugging the LM317/LM117 power supply

The Creek: PSoC 4 Creator Schematic + Firmware

In this post I will describe the PSoC Creator schematic and firmware that I built to run the PSoC4.  You can find the project on github.  After you open the project in PSoC Creator you will find two projects in the workspace explorer:

  1. p4ardino-creek: This project starts running 10 seconds after the chip powers up.  It uses PSoC Analog to Digital Convertor to read the pressure sensor and the temperature sensor.  It then convert the data to a readable form and stores it into the EZI2C buffer to be read by the Raspberry PI.
  2. p4bootloader: This project runs for 10 seconds when the chip is rebooted.  If it detects the Raspberry Pi host trying to load new firmware it will “bootload”.  If after 10 seconds it doesn’t hear anything, it will run the p4arduino-creek application.  I will describe how the bootloader works in the next post.

CreekWorkspace

p4ardunio-creek

The schematic for this project contains four sections

  1. The Analog to Digital convertor and the “external” schematic of the pressure current loop.  The elements in blue are external to the PSoC and are there just for documentation.
  2. The Red and Blue LED pins and the clock that drives the Red LED to blink
  3. The EZI2C which serves as the I2C Slave for the Raspberry Pi to read
  4. The Bootloadable component which allows this project to be boot loaded.

The configuration of each of elements is show below.

Creek Schematic

The ADC is configured to run as slowly as possible (1000 SPS).  I have also enabled the averaging which automatically averages 256 samples.  This effectively makes a low pass filter to remove noise.  This is possible because the pressure and temperature move very slowly as compared to the speed at which they are sampled.  The SAR ADC in the PSoC is inherently differential, I tell the ADC that I want the negative channel to be connected to a stable VREF.  This allows me to measure between 0V and 2*vref = 2.048 volts.

ADC Configuration 1

On the ADC channels TAB I enable two channels, both single ended, both with averaging turned on.  Channel 0 is connected to the pressure sensor (on Arduino pin A0 = PSoC Pin P2[0]) and channel 1 is connected to the TMP036 (on Arduino pin A1 = PSoC Pin P2[1])

ADC Configuration Screen 2

For this design I setup the PSoC4 to act as an EZI2C slave.  EZI2C means that the chip follows the EEPROM protocol which many many I2C masters understand.  The only thing that I configure in this case is to use the slave address of 0X08.

CreekEzI2C

For this project to be compatible with a bootloader it needs the bootloadble component instantiated.  In this case I use all of the default configurations.  When I make changes to the firmware in the future I will up-rev the version numbers.  These settings are here to prevent you from accidentally overwriting and newer rev of the firmware or putting in the wrong application type.

CreekBootLoadableConfig

In order for the bootloadable to work I need to tell it where its  “bootloader” image resides.  Remember from above that I put both projects in the same workspace.  So, what I need to do is browse through the directory hierarchy into the bootloader project and selects its ELF and HEX files.  If you want to read more about PSoC4 Bootloading you can read AN86526 entitled “PSoC 4 I2C Bootloader”

BootloableDependencies

One of the unique features of a PSoC is its ability to do hardware based design.  In this design I want a slowly blinking LED to indicate that the system is running.  For this task I have to configure the pin to let one of the internal clocks drive it.  To make this work you need to selected the output mode as “Clock”.

redLedPin

And you need to selected the “Out clock” as external.

redLedClock

Now, I want to turn off the Blue LED.  As the LED is active Low, to turn it off you write a 1 to the pin.  I do this as part of the setup of the pin by setting the initial drive state to high.

blueLED

The last step in the device configuration is to select the proper pins on the Design Wide Resources (DWR) pins tab.  Not setting the pins correctly is one of the most frequent errors that users make with PSoC Creator.

creekFirmwarePins

The firmware for the project is simple.  In the first section (lines 3-8) I define a packed structure to serve as the I2C buffer.  The __attribute__((packed)) tells the compiler to put all of the members of the structure in contiguous bytes.  In the structure I defined below, if I had not marked it is packed, it is likely that the compiler would have put two bytes of padding after the pressureCounts and two bytes after the centiTemp.  It would have done this to work align those datatypes to make the memory access more efficient.

The next section (lines 17-23) I initialize the system and start the components.

The the main body of the program (lines 27-43) I ask the ADC if it is done reading the voltages,  if not go on, if so then calculate the different values and store them in the I2C buffer.  The “CyEnterCriticalSection” prevents an I2C interrupt from reading the buffer before the data is completely written to prevent a partial read of the data.

CreekFirmwareMainC

In the next post I will explain boot loading and the p4bootloader project.

Index Description
The Creek: IOT for the Elkhorn Creek Introduction
The Creek: Solution Architecture 1.0 Overall architecture
The Creek: Creek Board 1.1 Eagle layout of the board
The Creek: Creek Board 1.0 – RCCA A discussion of the errors in the 1.0 board
The Creek: CYPI, a Raspberry Pi to Arduino Bridge PSoC4 <--> Raspberry Pi Bridge Board
The Creek: PSoC4 Creator Schematic and Firmware Firmware to interface with the temperature and pressure sensors
The Creek: Testing the Firmware Using tools to verify that the PSoC 4 Firmware is working correctly
The Creek: Testing the Bootloader Make sure that you can load new firmware into the PSoC
The Creek: Software Architecture All of the Raspberry Pi software connections
The Creek: Install MySql Instruction to configure MySql
The Creek: Install Tomcat Instruction to configure Tomcat JSP Server
The Creek: Data Collection Java (Part 1) The Java program that reads the I2C and saves it in the database
The Creek: Data Collection Java (Part 2) The Java program that reads the I2C and saves it in the database
The Creek: Create the Chart with JFreeChart Using open source Java charting software to create plots of the Creek Depth
The Creek: Flood Event Data Processor A batch program to create analyze the database and create a table of flood events
The Creek: Flood Event Web Page A batch program to create the flood event web page
The Creek: Creek Server 1.1 Updates to all of the back off server programs to integrate charts
The Creek: JSP Web Page for www.elkhorn-creek.org The JSP program to make the table and display the website
The Creek: Raspberry Pi Clock Stretching Sorting out a bug in the system having to do with the Broadcomm Raspberry Pi Master not functioning well with clock stretching
The Creek: Creek Server 1.2 Caching the web pages to make them faster

 

PSoC4000s & The SmartIO – Part 5

This is my last post on the SmartIO.  This time, I am going to describe how to use the SmartIO to trigger an interrupt.  For this project I will start from the “SmartIOCountUp” project.  That project is a 3-bit counter.  I thought that I would choose one of the states (000) and trigger an interrupt when that state is hit, then toggle the P25 user led.  I will keep data4, and gpio 3,6,7 exactly the same.  I will use gpio 2 to trigger the interrupt, which can be accomplished by setting it up as an output.  Here is the SmartIO configuration:

smart-io-config

The next step is to use LUT2 to look for the “000” state and to create a rising edge.  The other states will be 0.

lut-p22

After making the modification to the SmartIO the next step is to fix the schematic.  To do this I add a pin for P22, its configuration is on the next screen.  In addition I move the P25 (aka the BlueLED on the master board) to pin by itself.

interrupt-schematic

To configure the P22 pin.  There is a trick that is required to make the pin be both an output, so that it can be connected to the SmartIO LUT as well as an Input, so that it can be connected to the Port 2 interrupt.

pin-config

After setting up the pin to be both an Input and an Output you need to configure the pin to have an interrupt on the rising edge.

int-pin

Then I assign the pins.

interrput-pin-assignment

The last step is to make the firmware.

  • Lines 4-9 create an interrupt service routine
  • Line 18 registers the interrupt service routine to be called with the Port2 interrupt is triggered
  • The rest is the same as before

int-mainc

When I run this, I see the Blue LED toggle each time it gets to state 000 (which is all three LEDs on as they are active low).

You can find this PSoC Creator workspace on github in the directory called “SmartIO”.  This project is called “SmartIOInterrupt”.

Index Description
PSoC4000s & The SmartIO – Part 1 An introduction to the SmartIO and first project
PSoC4000s & CSX Mutual CapSense Buttons Part 1 Using mutual capacitance
PSoC4000s & CSX Mutual CapSense Buttons Part 2 Using the CapSense tuner
PSoC4000s & The SmartIO – Part 2 A 3 input XOR logic gate
PSoC4000s & The SmartIO – Part 3 A 3 bit up counter state machine
PSoC4000s & The SmartIO – Part 4 Using an external clock with the Smart IO
PSoC4000s & The SmartIO – Part 5 Triggering an interrupt

PSoC4000s & The SmartIO – Part 4

In the previous post I built a 3-bit counter that is clocked by the PWM.  In this example I will show you how to make the same design work with an external clock.  It seems like it would be cool to use the CapSense Button to provide the clock.  I will start by copying SmartIOCountUp to a new project called SmartIOCountUpExtClock.

First, I delete the clock and PWM.  Then add a new digital output pin (P20) that I can toggle from the CapSense handler and a digital Input pin (P21) to clock the SmartIO.  I add a wire between them on the female header on the board.

The next step is to modify the SmartIO.  I change data4 and data5 to bypass.  Then make gpio1 an input and then set the Clock to gpio1.  Here is what the new SmartIO configuration looks like:

smart-io-config

And the schematic.

smart-io-schematic

Assign the pins.

smart-io-dwr

I need to update the main.c write the CapSense button to P20 to be a clock source for the SmartIO

mainc

After I program the board, I can “clock” my statemachine with CapSense Button2.  Cool.  Obviously this example is a bit contrived in that I am running a wire on the outside of the chip, but you could imagine that you might have a “real” example that uses an onboard clock source.

You can find this PSoC Creator workspace on github in the directory called “SmartIO”.  This project is called “SmartIOCountUpExtClock”.

Index Description
PSoC4000s & The SmartIO – Part 1 An introduction to the SmartIO and first project
PSoC4000s & CSX Mutual CapSense Buttons Part 1 Using mutual capacitance
PSoC4000s & CSX Mutual CapSense Buttons Part 2 Using the CapSense tuner
PSoC4000s & The SmartIO – Part 2 A 3 input XOR logic gate
PSoC4000s & The SmartIO – Part 3 A 3 bit up counter state machine
PSoC4000s & The SmartIO – Part 4 Using an external clock with the Smart IO
PSoC4000s & The SmartIO – Part 5 Triggering an interrupt