Hello..
I want to use WS2812 with 12f1840, but I could not run it with the codes below. I wonder where my mistake is?
Device = 12F1840
Declare Xtal = 16
Config1 FCMEN_OFF, IESO_OFF, CLKOUTEN_OFF, BOREN_OFF, CPD_OFF, CP_OFF, MCLRE_OFF, PWRTE_ON, WDTE_OFF, FOSC_INTOSC
Config2 LVP_OFF, BORV_19, STVREN_OFF, PLLEN_On, WRT_OFF
Declare All_Digital= true
$define WS2812B_Pin PORTA.0 ' The pin that the WS2812B strip is connected too
$define WS2812B_Amount 16 ' The amount of WS2812B devices to control
Include "WS2812B.inc" ' Load the WS2812B library into the program
Dim LED_SIRASI As Byte
LED_SIRASI = 0
'------------------------------------------------------------------------------------
' The main program starts here
'
Main:
Setup() ' Setup the program
AA: ' Create a loop
LED_GONDER($FF0000) ' Yes. So set the corresponding block of LEDs to red
'LED_GONDER(0, $00FF00) ' Yes. So set the corresponding block of LEDs to green
'LED_GONDER(0, $FFFF00) ' Illuminate the corresponding LED block yellow
DelayMS 1000
LED_SONDUR()
DelayMS 1000
GoTo AA
'------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------
' LED RENK GONDERME :
Proc LED_GONDER(pColour As Long)
WS2812B_Colour(LED_SIRASI ,pColour.Byte2, pColour.Byte1, pColour.Byte0)
EndProc
'------------------------------------------------------------------------------------
'
Proc LED_SONDUR()
WS2812B_Colour(0, 0, 0, 0)
EndProc
'------------------------------------------------------------------------------------
' Setup the program
' Input : None
' Output : None
' Notes : None
'
Proc Setup()
Osc_16MHz()
WS2812B_Setup()
EndProc
'--------------------------------------------------------------------
Proc Osc_16MHz()
OSCCON = $7A ' 16MHz_HF
OSCTUNE = $00
BORCON = $00
EndProc
I wonder if there is any new progress or solution to this issue?
The WS2812B devices use a very fast async data stream for 1s and 0s, so the microcontroller needs to run fast so it can create the tiny delays between the pin being brought high and low. The WS2812B.inc library was written for 18F devices, so it will not run, as is, on enhanced 14-bit core devices. I'll add a $if statement to give an error if a none 18F device is use with the library code. I will also see if I can get the library to work with an enhanced 14-bit core device operating at 16MHz and over.
If you view the "WS2812B.inc" code, you will see that I had to use DelayCs commands for the delays because they are so fast so it has to actually delay in clock cycles, and with some enhanced 14-bit core devices, with their fragmented RAM, even changing RAM bank to Clear or Set a pin between pulses will alter the timing for the WS2812B's very fast async data requirements.
I made a big, big mistake, and it is something I have advised others on the forum not to do, so my apologies. I used the proteus simulator to see if the "WS2812B.inc" library also worked with enhanced 14-bit core devices, and it failed to operate. So I, stupidly, assumed it was a fault of the library's source code and went through it with a fine tooth comb. But, Oh No it wasn't the library code's fault!.... It was the proteus simulator failing 'yet again' to simulate a simple program correctly.
I made the mistake because the same code works in the simulator when operating on an 18F device and at the same frequency and using the same pin, so I foolishly assumed it would also work with an enhanced 14-bit core device because all the code is doing is toggling a pin fast in particular patterns for the colours. But it failed, and works perfectly on a real enhanced 14-bit core device, namely the PIC16F18857, which is a bog-standard device, and the code operates when the device is running at 16MHz, and upwards. So it will work on any enhanced 14-bit core device that has enough RAM. However, there are a few changes I will make to the library's code for enhanced 14-bit core devices. Some enhanced 14-bit core devices have the PORT and TRIS in RAM bank 0, and some have them in higher RAM banks, and the compiler uses the LAT SFR when using the commands PinSet or PinClear and all other commands that alter pins on devices that have a LAT, because of the "Read, Modify, Write" problem they have. So this causes the need for a RAM bank change mnemonic to be added when the pin is being pulsed, and it will slow it down by 1 clock cycle.
This does not make a huge difference, but better to make a change that could help, rather than leave a known, possible, issue with lower device operating speeds. :-)
The code listing below is the demonstration of twenty four WS2812B devices being manipulated so they look like the scanning red bar at the front of the KIT car in the 1970s TV show 'Night Rider', and it shows the library code operating perfectly on an enhanced 14-bit core device running at 16MHz:
'
' /\\\\\\\\\
' /\\\///////\\\
' \/\\\ \/\\\ /\\\ /\\\
' \/\\\\\\\\\\\/ /\\\\\ /\\\\\\\\\\ /\\\\\\\\ /\\\\\\\\\\\ /\\\\\\\\\\\ /\\\\\\\\\
' \/\\\//////\\\ /\\\///\\\ \/\\\////// /\\\/////\\\ \////\\\//// \////\\\//// \////////\\\
' \/\\\ \//\\\ /\\\ \//\\\ \/\\\\\\\\\\ /\\\\\\\\\\\ \/\\\ \/\\\ /\\\\\\\\\\
' \/\\\ \//\\\ \//\\\ /\\\ \////////\\\ \//\\/////// \/\\\ /\\ \/\\\ /\\ /\\\/////\\\
' \/\\\ \//\\\ \///\\\\\/ /\\\\\\\\\\ \//\\\\\\\\\\ \//\\\\\ \//\\\\\ \//\\\\\\\\/\\
' \/// \/// \///// \////////// \////////// \///// \///// \////////\//
' Let's find out together what makes a PIC Tick!
'
' WS2812B RGB Interface to scan a line of LEDs with illumination of the lagging LEDs decreasing gradually.
' Much like the front scanner on the KIT car of the TV program Night Rider.
'
' Written by Les Johnson for the Positron8 BASIC Compiler.
'
Device = 16F18857 ' Tell the compiler what device to compile for
Declare Xtal = 16 ' Tell the compiler what frequency the device is operating at (in MHz)
$define WS2812B_Pin PORTC.0 ' The pin used for the WS2812B chips
$define WS2812B_Amount 24 ' The amount of WS2812B chips to control
$define cRedBar 0 ' Make a scanning bar of colour Red
$define cGreenBar 1 ' Make a scanning bar of colour Green
$define cBlueBar 2 ' Make a scanning bar of colour Blue
Include "WS2812B.inc" ' Load the RGB WS2812B routines into the program
'
' Create global variables for the demo here
'
Dim bChipNumber As Byte ' Holds the WS2812B being communicated with
Dim IllumArray[WS2812B_Amount] As Byte Heap ' Holds the bar's LED colours and brightness'
'---------------------------------------------------------------------------------------------
' The main program starts here
' Move a bar of LEDs from left to right, then right to left.
' With the LEDs behind the fully illuminated LED gradually dimming in brightness
'
Main:
Setup() ' Setup the program and any peripherals
Clear IllumArray ' Set all the elements of IllumArray to 0
Do
'
' Move the LED bar right to left
'
For bChipNumber = 0 To cWS2812B_IndexAmount ' Create a forward loop for the amount of LEDs available
IlluminateBar(bChipNumber, cRedBar) ' Light up the bar of LEDs
DelayMS 40 ' Add a delay to see things moving, otherwise the compiler's code is too fast and it is a blur
Next
'
' Move the LED bar left to right
'
For bChipNumber = cWS2812B_IndexAmount DownTo 0 ' Create a reverse loop for the amount of LEDs available
IlluminateBar(bChipNumber, cRedBar) ' Light up the bar of LEDs
DelayMS 40 ' Add a delay to see things moving, otherwise the compiler' code is too fast and it is a blur
Next
Loop
'---------------------------------------------------------------------------------------------
' Setup the program and any peripherals
' Input : None
' Output : None
' Notes : None
'
Proc Setup()
Oscillator_16MHz() ' Set the device to operate at 16MHz using the internal oscillator
WS2812B_Setup() ' Setup to communicate with the WS2812B devices
EndProc
'---------------------------------------------------------------------------------------------
' Gradually Dim a specific WS2812B chip
' Input : pIndex holds the WS2818B to examine for the dimming
' : pColour chooses cRed, cGreen or cBlue for the colour of the scanning bar
' Output : None
' Notes : None
'
Proc IlluminateBar(pIndex As Byte, pColour As Byte)
Dim bChip As Byte
Dim bColStore As Byte
For bChip = cWS2812B_IndexAmount DownTo 0 ' Scan all the WS2812B devices available
If pIndex = bChip Then ' Are we at the specific LED chip?
IllumArray[bChip] = 255 ' Yes. So illuminate the LED fully
Else ' Otherwise...
IllumArray[bChip] = IllumArray[bChip] / 2 ' Divide its value to dim the LED gradually
EndIf
bColStore = IllumArray[bChip] ' Store the contents of the array's element
If pColour = cRedBar Then ' Do we want a red scanning bar?
WS2812B_Colour(bChip, bColStore, 0, 0) ' Yes. So illuminate the Red LED of the WS2812B chip
ElseIf pColour = cGreenBar Then ' Do we want a green scanning bar?
WS2812B_Colour(bChip, 0, bColStore, 0) ' Yes. So illuminate the Green LED of the WS2812B chip
Else ' Otherwise... A blue scanning bar
WS2812B_Colour(bChip, 0, 0, bColStore) ' So illuminate the Blue LED of the WS2812B chip
EndIf
Next
EndProc
'---------------------------------------------------------------------------------------------
' Set the microcontroller to 16MHz operation using its internal oscillator
' Input : None
' Output : None
' Notes : For use with a PIC16F18857 device
'
Proc Oscillator_16MHz()
OSCCON1 = %01100000
OSCCON3 = $00
OSCEN = $00
OSCFRQ = %00000101 ' HFFRQ set for 16MHz
OSCTUNE = $00
DelayMs 100
EndProc
'---------------------------------------------------------------------------------------------
' Set the microcontroller to 32MHz operation using its internal oscillator
' Input : None
' Output : None
' Notes : For use with a PIC16F18857 device
'
Proc Oscillator_32MHz()
OSCCON1 = %01100000
OSCCON3 = $00
OSCEN = $00
OSCFRQ = %00000110 ' HFFRQ set for 32MHz
OSCTUNE = $00
DelayMs 100
EndProc
'---------------------------------------------------------------------------------------------
' Setup the fuses to use the internal oscillator on a PIC16F8857 device.
' The OSC pins are general purpose I/O pins.
'
Config1 FEXTOSC_OFF,_ ' External Oscillator not enabled
RSTOSC_HFINT1,_ ' Power-up default value for COSC is 1MHz
CLKOUTEN_OFF,_ ' CLKOUT function is disabled. I/O function on OSC2
CSWEN_ON,_ ' Writing to NOSC and NDIV is allowed
FCMEN_ON ' Fail-Safe Clock Monitor Enable bit->FSCM timer enabled
Config2 MCLRE_ON,_ ' MCLR pin is Master Clear function
PWRTE_OFF,_ ' Power-up Timer disabled
LPBOREN_OFF,_ ' Low-Power BOR disabled
BOREN_ON,_ ' Brown-out Reset Enabled, SBOREN bit is ignored
BORV_LO,_ ' Brown-out Reset Voltage (VBOR) set to 1.9V on LF, and 2.45V on F Devices
ZCD_OFF,_ ' Zero-cross detect circuit is disabled at POR.
PPS1WAY_OFF,_ ' The PPSLOCK bit can be cleared and set multiple times in software
STVREN_ON,_ ' Stack Overflow or Underflow will cause a reset
DEBUG_OFF ' Background Debugger disabled
Config3 WDTCPS_WDTCPS_31,_ ' WDT Divider ratio 1:65536. Software control of WDTPS
WDTE_OFF,_ ' WDT Disabled, SWDTEN is ignored
WDTCWS_WDTCWS_7,_ ' WDT window always open (100%); software control. keyed access not required
WDTCCS_SC ' WDT input clock is Software Control
Config4 WRT_OFF,_ ' User NVM Write protection off
SCANE_NOT_AVAILABLE,_ ' Scanner module is off
LVP_OFF ' High Voltage on MCLR/Vpp must be used for programming
Config5 CP_OFF,_ ' User NVM Program memory code protection disabled
CPD_OFF ' Data NVM code protection disabled
Below is a video I took of the above program operating on an Amicus18 board that has a PIC16F18857 plugged into it and using its internal oscillator at 16MHz:
Hi Les,
good stuff. I notice that the syntax for the For .. Next statement uses this
For x = y Downto 0
.....
Next
It appears to be the same as using Step -1 but this isn't documented in the manual, although it is used in an example on page 45.
Secret sauce?
John
Whoooops. Sorry John, I was sure I had added DownTo and UpTo to the manual a few months ago. Hopefully, I have not over-written the manual Word version with the DownTo and UpTo in it, otherwise, I will write it again.
DownTo will make an automatic negative Step and UpTo will make an automatic positive Step, (just like a standard To). I think it actually makes code more understandable. To is still usable and so is Step - or + Value.
I'll add them ASAP.
Hi Les,
I assume the step using this will always be +1 or -1.
Bob
The Step value can be positive or negative, but the DownTo directive will always treat it as a negative step value. For example:
For MyByte = 255 DownTo 0 Step 8
Will step backwards by eight with each loop iteration. The same with UpTo, but positive steps only.
Some time ago I wrote one routine for WS2812. Something is not my brainchild but I found that one of the example, included in the compiler, couldn't accomplish the results, unless using 64 MHz MCUs. This is working with 12F18xx or other 32 MCU at 32 MHz clock.
Dim MAXCANDLEcnt 32 ' any used LED number (not in the include)
Symbol TRUE 1
Symbol FALSE 0
'------------------------------------------------------------------------------
Dim candlecntr, Var0, Var1, Var2 As Byte
All_Leds_Change:
For candlecntr = 0 To MAXCANDLEcnt
Green[candlecntr] = Var0
Red[candlecntr] = Var1
Blue[candlecntr] = Var2
Next candlecntr
WriteLeds: 'Sub Routine to write data to Neopixel 24 Ring
'-------Timing is important. here don't change anything-------
For candlecntr = 0 To MAXCANDLEcnt 'Controlling 24 leds
Var0 = Red[candlecntr]
Var1 = Green[candlecntr]
Var2 = Blue[candlecntr]
Clear GIE
If Var0.7 = 0 Then LowBit :Else: Highbit
If Var0.6 = 0 Then LowBit :Else: Highbit
If Var0.5 = 0 Then LowBit :Else: Highbit
If Var0.4 = 0 Then LowBit :Else: Highbit
If Var0.3 = 0 Then LowBit :Else: Highbit
If Var0.2 = 0 Then LowBit :Else: Highbit
If Var0.1 = 0 Then LowBit :Else: Highbit
If Var0.0 = 0 Then LowBit :Else: Highbit
If Var1.7 = 0 Then LowBit :Else: Highbit
If Var1.6 = 0 Then LowBit :Else: Highbit
If Var1.5 = 0 Then LowBit :Else: Highbit
If Var1.4 = 0 Then LowBit :Else: Highbit
If Var1.3 = 0 Then LowBit :Else: Highbit
If Var1.2 = 0 Then LowBit :Else: Highbit
If Var1.1 = 0 Then LowBit :Else: Highbit
If Var1.0 = 0 Then LowBit :Else: Highbit
If Var2.7 = 0 Then LowBit :Else: Highbit
If Var2.6 = 0 Then LowBit :Else: Highbit
If Var2.5 = 0 Then LowBit :Else: Highbit
If Var2.4 = 0 Then LowBit :Else: Highbit
If Var2.3 = 0 Then LowBit :Else: Highbit
If Var2.2 = 0 Then LowBit :Else: Highbit
If Var2.1 = 0 Then LowBit :Else: Highbit
If Var2.0 = 0 Then LowBit :Else: Highbit
Set GIE
Next candlecntr
Return
'************************************************* ****************************
'SUB-ROUTINES
'************************************************* ****************************
'High Bit timing routine
Sub Highbit()
OutLEDs = TRUE
@NOP
@NOP
@NOP
@NOP
@NOP
@NOP
OutLEDs = FALSE
EndSub
Sub LowBit()
OutLEDs = TRUE
@NOP
@NOP
OutLEDs = FALSE
@NOP
@NOP
EndSub
Maybe the timing needs some tuning, by adding a NOP or two...
Also OutLEDs, TRUE and FALSE should be defined on the main program.
BTW, out of the thread....
What Heap does? I've looked at the assembler and nothing vary for mid-range enhanced.