Wednesday, April 6, 2022

Driving NeoPixel type ARGB LEDs with PIC

 I have ordered 10 pcs of addressable LED from Aliexpress some time ago and tested them with my Arduino boards and the library from Adafruit and they work as expected. But of course I am more a PIC guy, so I start to thinker with some PIC microcontrollers trying to drive these LEDs. And it is not easy! So the major difference between 8-bit PIC micro and a ATMEGA 328P is that the ATMEGA command rate of ATMEGA is the same as clock rate, so it has 16 MHz clock frequency and 16 MHz command rate but the PICs have command rate 4 times slower than clock frequency. So a PIC clocked at 16 MHz will have 4 MHz command rate and 32 MHz PIC will have 8 MHz command rate. In order to achieve similar performance as ATMEGA, the PIC must be clocked at 64 MHz. 

The difficulty comes from the very high frequency and the format of the output signal. The frequency of NeoPixel signal is ≈800 kHz and the "1" have 800 ns high followed by 400 ns low. The "0" is 400 ns high followed by 800 ns low. And 1 instruction of 32 MHz PIC microcontroller take 125 ns to execute. It is impossible to write a C code that can create such signal in 9-10 instructions. This is achievable only with carefully written Assembler. I had success with PIC16F1847 clocked at 32 MHz.

It was pain in the a**, because there are very little info and tutorials about writing mixed code (C and assembler) for xc8. For example I couldn't find a way to declare a variable in BANK0 in assembly code because the variables in C code evidently take precedence and occupy all the free space in BANK0 first. And it is important the variables to in the same memory bank as PORTB, because changing banks takes one additional instruction. So I has to declare the variables in the C code specifying the exact address... 

The above code has two subroutines _sendByteASM and _sendByteASM2. The first one use a cycle to check and send the bits to the serial output pin (in this case RB4). The best timing I was able to achieve this way was "0" - 375ns/875ns, "1" - 875ns/500ns. And it worked.

The second subroutine check and send every bit separately and there I was able to achieve timing much closer to the required. "0" - 375ns/875ns, "1" - 875ns/375ns. 

Then I got a more modern PIC - PIC16F15344, which have 4 very interesting modules: Configurable Logic Cell (CLC) each of which can be set as 4-input AND, AND-OR, D-type flip flop, J-K flip flop and couple of other types. Also I saw a video from the great Ben Heck where he is using the SPI output from ESP32 with some external logical chips to form the output signal compatible with NeoPixel. 

My thought was to feed the color bytes to the SPI module (configured to work at 800 kHz) and the output (clock and data) to use somehow to form impulses with different length and then combine them with CLC. The following screenshots are the settings of different modules used in this project.

The CLC1 is configured as AND-OR and the signal from the SPI is directly routed to the output. This will be needed later. 

For creating the waveforms of "0" and "1" I used the Complementary Waveform Generator (CWG). This module is used to create a signal for driving half-bridge or full bridge circuits and among other setting there can be set a dead time. So I fed the signal from CLC1 (which is a copy of SCK signal and have 50% duty cycle or 600 ns high) to the CWG module and set the dead time of the rising edge to be about 400 ns and when inverted this will be the "0". The dead time of the falling edge is set to be around 200 ns increasing low time to 800 ns and when inverted form the "1" waveform.

CLC2 is configured as 4-input AND. There I combine the inverted output from CWG1A, CLC1 and SDO from SPI to create the "0" signal:

Finally, all is combined at CLC3 which is set as AND-OR cell:

Here the inverted signal from CWG1B is "AND"-ed with the SDO signal to produce the "1" signal. Then both "0" (from CLC2) and "1" are "OR"-ed to form the final output signal which is routed to one of the pins - in my case RC4/pin6. 

Here some scope screenshots:

The timing here is much better and the beauty of this solution is that there is no interrupts, no assembler code. All of the above is just setup of registers. I am using MPLAB Code Configurator to generate all the code and the actual work is done by the hardware modules and for sending a single byte to the NeoPixels are needed only 2 lines of code. Here is the function to send the 3 bytes for red, green and blue:

Bellow is a video demonstration how it work with the assembler code. I adapted some of Adafruit library functions for this demo: rainbow, their table for gama8 function and the function for HSV color. 

Tuesday, February 15, 2022

HV rescue shield for Microchip ATmega series 8-bit microcontrollers

These days I decided to play a little with ATmega328P microcontroller and it was a total disaster. I used a PICkit 4 programmer and MPLAB X + XC8 for the code writing and compiling. Then I came to the brilliant idea to use MCC (MPLAB Code Configurator) which supposedly is easy way to configure and use the different modules inside the chip. And after setting the wrong fuses for the clock source the chip was effectively bricked. It worked, but only if I put a watch crystal at 32.768 kHz as a clock source. And the programmer cannot communicate at that low frequency.

Why these chips are designed this way? The ICSP interface in PIC microcontrollers have a dedicated clock line, so the programming of the chip is independent of the his internal configuration. I start digging for solutions in the web and tried all sorts of things. Most recommended solution was to attach external clock source to XTAL1 pin. I have signal generator and tried this with different frequencies but without success.

Finally I found this excellent page ARDUINO-BASED AVR HIGH VOLTAGE PROGRAMMER and following the latest schematic I put the ATmega328Pchip on a breadboard and connected a million jumper wires to the Arduino. It worked and the chip was rescued. Of course I connected it again to the PICkit 4 and successfully bricked it again!

So in order to avoid dealing with jumper wires on the breadboard I get the original schematic, removed all other interfaces except the ATmega and replaced a dual PNP+NPN transistor array with discrete transistors. Also I removed the DC-DC voltage convertor because I can connect external voltage source for the 12V line. Here is the modified schematic:

And here is the finished shield for Arduino:

It worked perfectly, the chip was saved and I am ready for another bricking :)

The board was edited with EasyEDA. You can download the project files from HERE. Inside are included Gerber files. Use these on your own responsibility. The Arduino sketch for this project you can download from the original project page HERE.

Tuesday, January 25, 2022

Driving 4 digit 7-segments TM1637 display module with PIC microcontroller

TM1637 display modules are cheap chinese modules that are offered in different colors, with digital dots or with colon. Usually these are 4 digit, but there are 6 digit modules also. I bought mine for 1.84 USD delivered. 

Tuesday, September 8, 2020

Power supply replacement for FY6900 function generator

Recently I bought an function generator from Banggood. I chose the FeelElec FY6900-60M. In the internet I found many projects for replacing the original switching power supply. The benefits are questionable, but I thought it will be fun little project to make. 

Monday, July 6, 2020

100 MHz third overtone crystal oscillator

Couple of years ago I purchased from a local store 100 MHz crystal resonator and tried several times to make a working schematic on breadboard using standard circuits I found on the internet. It never worked good enough, usually oscillating at 33.3 MHz instead of 100 MHz. Finally, I found that the crystal is third overtone type. Here some documents, that were useful for this project:

I used as a base the schematic from first document and here what I design:

Wednesday, March 20, 2019

Simple Digital Clock with PIC16F628A and DS1307 and 7-Segment LED display

In this new project I am again using PIC16F628A microcontroller. The goal is simple digital clock with 7-segment LED display and the clock will have no additional functionality - no alarm, no seconds digits, no date. The latter can be added in the software though. For the RTC chip I chose DS1307. For the LED display I used Kingbright CC56-21SRWA.