News:

Let's find out together what makes a PIC Tick!

Main Menu

12f1840 ile WS2812

Started by Mustafa_cmbz, Jan 06, 2024, 09:08 PM

Previous topic - Next topic

Mustafa_cmbz

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

 

Maxi

I wonder if there is any new progress or solution to this issue?

top204

#2
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.

top204

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:

John Lawton

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

top204

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.

RGV250

Hi Les,
I assume the step using this will always be +1 or -1.

Bob

top204

#7
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.

keytapper

#8
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.
Ignorance comes with a cost

keytapper

BTW, out of the thread....
What Heap does? I've looked at the assembler and nothing vary for mid-range enhanced.
Ignorance comes with a cost