This is an update for Christmas - We attempt to make some twinkling Christmas lights with 3 NesoPixel strips on a CH583 microcontroller.

In this project we will take a deeper dive into the small but powerful CH583 RISC-V MCU. The under the hood dive will reveal how we use alternate pins and DMA to drive 3 NEOpixel strips. My original intent was to allow 4 strips but none of the CH5xx MCUs offers sufficient resources. The secret to achieving this small miracle is using alternate I/O pins for the SPI peripherals.  For example, even with the CH582F (or 592), we could drive 2 strips by connecting one to the MOSI pin and the other to the alternate MOSI_ pin on the single SPI.  We then proceed to alternately send one buffer of colour data to SPI0 and then change the pin assignment and send a different buffer to the same SPI0.  As a bonus we will look at using the CHIP ID register to appropriately configure the SPI at power-up.

 My grateful thanks to JLCPCB for making the process of designing and fabrication/assembly of my RISC-V boards so easy.

I have chosen to use the CH583M for this project because it has 2 SPI peripherals.  Unfortunately it does not offer alternate pins on SPI1 so we can only drive 3 strips total.  SPI1 also does not support DMA.

ChipID:

In this project we are using Serial Output on UART1 (Tx = A9). A Welcome message as well as possible status and error messages are displayed using printf(). Before we display the Welcome message we read the R8_CHIP_ID register into the ChipID variable which will be used to make setup decisions. This register contains the last 2 digits of the chip's part number in HEX (0x83) which we incorporate into the Welcome message..

SPI Setup:

The SPIsetup( ) routine in hardware.c sets up the SPIs, controlled by #define NUM_STRIPS in NEO.h as well as the #define DMA directive. Invalid configs may generate a compile error and/or a report via printf(). The numbering scheme we use has Strip0 using SPI0, then Strip1 using SPI0 with MOSI assigned to use it's alternate pin. We note that the naming convention for alternate pins has an underscore after the name, eg: MOSI0_.  Strip2 (if we are using a 583) uses SPI1. The other SPI pins are not used although you will see where I used SCS0 as trigger for the logic analyzer. It is not necessary for the operation of the NEOstrips.

We will be using the code examples provided here in the Files section.  Follow the Moun River setup given in my previous project and then add/replace these files into the src subdirectory. We will probably need to do a refresh at this point.

Simple usage:

To just light up a strip we don't need to get into the animations. All of the strips are automatically cleared by our software at boot time.  This is, of course, necessary because the strips act as memories and will remember the previously illuminated pixels.

To set a strip to one of the example colour arrays included at the top of Neo.c we can set up the strips structure as follows:

Strips[0].pixels = Strip;  //  will display the colours contained in the Strip array
Strips[0].len = 15;         //  here we assume the 1st strip has 15 pixels

The Show() function call will display each of the configured strips in turn.  The DelayUs call tells the strips that we are done loading pixel data. The mstTick++ and DelayMs routine is used to create animation timing. Show() is where we switch between standard and alternate pins. For example we switch to the alternate SPI0 pin set using the following command.

if( curStrip == 1 ) { R16_PIN_ALTERNATE |= RB_PIN_SPI0;  }      //  switch to alternate pins

if( curStrip == 0 ) { R16_PIN_ALTERNATE &= ~RB_PIN_SPI0; }  //  switch to standard pins

Show() also selects between 2 and 3 bit compression depending on the DMA setting.

There are several #defines in the NEO.h header file that may need to be adjusted to your specific situation. 

We need to set the DMA to TRUE or FALSE depending on our preference - Note that the DMA is not available on SPI1 so this define is ignored on our 3rd strip. DMA may also be slower due to the fact we cannot use it with my 3-bit compression routine. Observation with the Logic Analyzer show that the 3 bit compression routine gives us the expected 33% increase in speed of transmission of each individual strip compared to the 2-bit routine.

NUM_STRIPS should be self explanatory, likewise MAX_LEN.

Animations:

I have included several animation as examples of how we can enjoy our NEOpixel strips on the CH5xx series of MCUs.

Most of the animations can be constrained to segments within individual strips.  Before running an animation we need to set up the corresponding strip and segment structures.

For most any animations longer than about 15 pixels we need to dynamically create a buffer of the desired length to hold our pixel data. The included arrays are examples, but are not very long.

The Create_pStrip( ... ) routine performs this function as well as initializing the array to all one colour ???

 pStrip1 = Create_pStrip( 28, BLK, NULL );  will create a Black (blank) buffer 28 pixels long on which we can draw our animations.  We set up the 1st strip with:

Strips[0].pixels = pStrip1;  //  attach the dynamic array we just created
Strips[0].len = 28;            //  it is 28pixels long

We then fill segment 0 with Magenta pixels using:

 fillSeg( 0, 0, MAG, NULL );

before adding  moveSeg( 0, 0, FWD, 8  );  inside of the endless loop.  This will invoke the moveSeg animation specified on strip 0, segment 0, every 8 times the milliSeconds specified in the delay given at the end of the loop.

We should see a magenta snake repeatedly crawling up our NEOpixel strip!!

Try experimenting by changing some parameter to your liking and see if they make sense to you.  The NULL parameter can be replaced with an existing array of colours BUT we need to make sure it is at least as long as the segment we are using.  For instance, if we wanted a multi coloured snake we can call

 fillSeg( 0, 0, -1, Strip );  where Strip is the predefined array from Neo.c

Christmas Lights - this is a quick demo of the random rndSeg() animation I did for Xmas. There is a

#define XMAS_ANIM to enable this in the NEO.h header file. The strip structures are set up in the main function and then rndSeg( 0, 0, 2 ); is called 6 times ( 1 for each of 2 segments times 3 strips ) in the endless loop.  The LEDs will twinkle with random colours selected from the Xmas array.


Stay tuned for one more animation examples from this adventure.  I also hope to add BlueTooth remote Control.

If you have any suggestion for a simple Android app to use please be so kind as to let us know.  Hopefully one that just uses the BlueTooth serial interface, and/or has source code for using it (save me the trouble of trying to hack it).

I couldn't make these boards without the assistance of:

JLCPCB - Trusted by 5.4M Engineers Worldwide! Get High-quality PCB Prototypes for Just $2! Sign up to Get $80 Coupons

They make SMD/SMT a breeze.

Happy Pixels!!