logo elektroda
logo elektroda
X
logo elektroda

WS2812 Christmas animations on PIC12F683 - how many LEDs will 128 bytes of RAM handle?

p.kaczmarek2 2043 29
ADVERTISEMENT
Treść została przetłumaczona polish » english Zobacz oryginalną wersję tematu
📢 Listen (AI):
  • WS2812 LED strip powered by a microcontroller, waveform shown on a RIGOL oscilloscope.
    Can the tiny eight-bit PIC12F683 microcontroller handle the dynamic colour animation on the WS2812 LEDs? The MCU used here has just 2048 bytes of Flash memory, 128 bytes of RAM and is clocked at up to 20 MHz (8 MHz for the internal oscillator). Is this enough? Let's find out!

    The idea came from the fact that I have a dozen or so of these types of PICs left over from older projects and I decided to try to give them new life. Perhaps something for Christmas. We'll see if I still have time. At the time of publishing the first part (of this topic) I have only just started the second part.

    Here I will describe the first part of the adventure, that is, getting the WS2812 up and running and the limitations of this microcontroller.

    This topic is part of my series on PIC microcontrollers and the SDCC compiler. For other parts, please see the topics below:
    Part 1 - Setting up the operating environment
    https://www.elektroda.pl/rtvforum/topic3635522.html#18304424
    Part 2 - Blink LED, IO pins, digital inputs and outputs
    https://www.elektroda.pl/rtvforum/topic3647884.html#18389188
    Part 3 - Oscillator settings. Internal oscillator, external oscillator, quartz resonator, PLL
    https://www.elektroda.pl/rtvforum/topic3657704.html
    Part 4 - Timers, interrupts
    https://www.elektroda.pl/rtvforum/topic3676645.html#18580858
    Part 5 - Seven-segment display operation
    https://www.elektroda.pl/rtvforum/topic3676650.html#18580877
    Part 6 - MM5450 LED display driver
    https://www.elektroda.pl/rtvforum/topic3845301.html
    Related topic about PIC12F:
    PIC12F683 and SDCC - tutorial - we create a simple dimmer (read catalogue notes)


    Specification of WS2812
    The WS2812 is an individually addressable, colour LED that combines an RGB LED and a controller in a single housing. This allows each module to be controlled independently, enabling the creation of lighting effects, animations and dynamic colour changes in LED strips, arrays or DIY projects. The WS2812 uses a single-line protocol for data transfer, allowing multiple LEDs to be easily connected in series with minimal wiring. The way it works is that the WS2812s are connected in series - the DOUT input of one is connected to the DIN of the other, and their controllers themselves cleverly pass on the signal, taking only their colour described by three bytes.
    Data transmission and cascade connection diagram for WS2812 LEDs
    The bytes are encoded as a high state - low state pair, where the timing of a given state must meet a specification.
    Data transfer timing table for WS2812 LED, showing TH and TL durations.
    According to the table - we must be able to generate T0H (0.4 us) and T1H (0.8 us) times with a margin of error of up to 0.15 us (in practice slightly more).

    First attempts and instruction timing
    The first PIC that caught my eye was the PIC12F675, lying right next to the eponymous PIC12F683. However, it had even less RAM, at a mere 64 bytes:
    Comparison of PIC12F629 and PIC12F675 microcontroller specifications
    I then compared the notes and decided that the PIC12F683 was the better option after all:
    Specification table of the PIC12F683 microcontroller
    It's a tiny 8-bit MCU in a DIP8 enclosure, but it's more likely to be enough here?
    USB connector next to a PIC12F675 DIP8 microcontroller on a white background
    To start with, I got the PIC up and running. PICKIT2 sees it without external components:
    Breadboard with connected PICKIT2 programmer and DIP8 microcontroller
    For the PIC to work, however, you need a 10 kΩ resistor on the MCLR (pull up to the power supply) and you also need to give a 100 nF decoupling capacitor between power supply and ground.
    I started by trying the built-in oscillator - 8 MHz, faster is not possible. This is set in the OSCCON register:
    OSCCON register table from PIC12F683 datasheet showing oscillator frequency settings
    I wanted to illustrate how long it takes to do the GPIO state setting. This can of course be counted (from the Fosc/4 formula), but it is worthwhile to verify the result anyway. Example code:
    Code: C / C++
    Log in, to see the code

    We are interested here in the timing of the high state, because after the low state there is still a jump to the start of the loop, and this is also an instruction:
    Oscilloscope waveform showing a 520 ns pulse measured on Rigol screen
    It comes out 500 ns... and we need 400 ns - 800 ns, a bit low.


    Migrating to an external oscillator
    8 MHz is rather too slow. You need to switch to an external oscillator:
    Clock source block diagram of a PIC microcontroller with external oscillator highlighted
    I have just such a 20 MHz one:
    20 MHz quartz resonator held with tweezers, background box with other components
    All you need to do is connect it on the right pins:
    Pin diagram of PIC12F683 microcontroller in 8-pin PDIP/SOIC package
    You also need to enable it in the configuration word.
    Configuration word register of PIC12F with FOSC field highlighted in red
    New code - we are testing:
    Code: C / C++
    Log in, to see the code

    We are interested here in the timing of the low state, as there is still a spike after the high state:
    Rigol DS1054Z oscilloscope screen showing square wave data signal for LED
    It is better, 360 ns some, maybe less.


    First colours
    Since the time of one command is about 360 ns, two commands will give us about 720 ns. The second command can be completed with the command nop - processor passivity.
    The zeros and ones times with the WS2812 are not critical, you can deviate to some extent from the expected timings and the diodes can still potentially work. For this reason, I was hoping that simple bit-checking wouldn't fully mess up communication. Similarly with my WS_HIGH and WS_LOW macros, which I'm not sure about - you'd have to check in the generated listing what the compiler converts them to.
    Code: C / C++
    Log in, to see the code

    In the worst case scenario, I was planning to expand the byte send so that there is no loop, or write the whole bit in assembler. Another interesting trick is to load the whole byte into a GPIO register and shift it by one bit so as to expose its bits to a given pin sequentially. I have seen this done in the past with a PAL signal generator, but here it was not needed.
    The rest of the code speaks for itself - I rigidly prepared three pixels, or nine bytes. The colours in turn separately.
    Code: C / C++
    Log in, to see the code

    I then connected the LED strip to the chosen GPIO. Both the PIC and WS2812 run on 5 V, so no power supply problems. The LED strip has a separate data, power and ground line, so you don't have to worry about the current capacity of the PIC pin.
    Effect:
    WS2812 LED strip glowing in three colors with Pickit 2 programmer and DIP IC on white surface
    It appears to work, that the times obtained are within the WS2812 tolerances, but are we sure?


    Pseudo-animation - colour swapping
    To verify the operation, I prepared the simplest animation - a colour swap. Two arrays of data displayed with a gap so that you can see the change.
    Code: C / C++
    Log in, to see the code

    It appears that the transfer works reliably enough and alternates the two sets of colours displayed. No data is lost:
    Three glowing WS2812 LEDs in red, blue, and green colors


    First animation
    The next step is already authentic animation - just what kind? Maybe some smooth colour transitions based on a sine function. You can get a different coloured effect this way, as long as you introduce some offset between the numerical values of red, green and blue. For simplicity, I have introduced an array of sine values (in byte form), although this is largely a disastrous approach - I lose as much as 32 bytes for it alone!
    Code: C / C++
    Log in, to see the code

    The effect works, but there is one problem:
    Colorful WS2812 LEDs driven by microcontroller, oscilloscope in background
    No more pixels can be added because there is not enough RAM.
    Compilation error log for PIC12F683 showing relocation and memory allocation issues


    Optimisations and limitations
    I've tried various approaches, but even switching to dynamically counted values doesn't change much either - SDCC needs memory for them too, as it creates helper functions for them when the operation is not supported by the processor:
    warning: Relocation symbol "_cinit" [0x0022] has no section. (pass 0)
    warning: Relocation of section "UDL__moduint_0" failed, relocating to a shared memory location.
    error: No target memory available for section "UDL__moduint_0".
    error: Error while writing hex file.

    warning: Relocation of section "IDD_idata_0" failed, relocating to a shared memory location.
    error: No target memory available for section "IDD_idata_0".
    error: Error while writing hex file.

    warning: Relocation of section "UDL__mulint_0" failed, relocating to a shared memory location.
    error: No target memory available for section "UDL__mulint_0".
    error: Error while writing hex file.

    For best performance this would need to be written in assembler and limited to types that fit in registers, maybe then a bit more bytes could be racked up.
    The version below supports up to about 20 LEDs, so 60 bytes are allocated to pixels. This is less than 50% of the available RAM, as there are 128 bytes in total.
    Code: C / C++
    Log in, to see the code

    End result:



    Now you can implement already other animations, knight rider, chasing fireflies, fireworks, rainbows, of course in a given firmware compilation there will probably be only one of them, depends how much computation is required.

    Summary
    On the PIC12F683 we have a total of 128 bytes of RAM. One RGB pixel is classically assumed to be 3 bytes, so assuming half the RAM goes to pixels (because there are still variables, etc) then we have 64/3 = about 21 pixels. In practice I was able to run up to 20 pixels, although the code could probably still be slimmed down considerably.
    Potentially you could try to optimise this, but I don't see many options here:
    - there are unlikely to be any peripherals on the PIC12F, such as hardware SPI, that could send these bytes
    - The PIC12F is rather too slow to generate these bytes on the fly
    - an interesting idea would be to pack the pixels in fewer bytes, but then the animation and decoding of the results itself gets complicated
    Probably rewriting the whole thing to the assembler would help a bit, but at this stage I find that those 128 bytes of RAM are however largely an impassable obstacle in terms of animating more LEDs.
    The PIC12F is capable of controlling the WS2812, but only short strings, even more so if you want to add something else to it - button control or different modes there.
    Follow up in a separate topic.
    I am attaching the project (code + bat script for SDCC)
    Attachments:

    Cool? Ranking DIY
    Helpful post? Buy me a coffee.
    About Author
    p.kaczmarek2
    Moderator Smart Home
    Offline 
    p.kaczmarek2 wrote 13978 posts with rating 11765, helped 631 times. Been with us since 2014 year.
  • ADVERTISEMENT
  • #2 21785710
    TechEkspert
    Editor
    An interesting Christmas surprise! Such optimisations may seem like logic puzzles that can be bypassed by using a more powerful microcontroller. However, I personally think it is worth overcoming such challenges in practice, they can come in handy where further increases in resources are not possible.
  • #3 21785718
    p.kaczmarek2
    Moderator Smart Home
    I was also a bit taken aback by these optimisations. As I gave up on that lookup table for the sine function and tried to rewrite the effect to count on the fly, I quickly started to run into more problems. Dividing? Can't do it, requires extra memory. Modulo? Also no - No target memory available for section "UDL__moduint_0". . Multiplication of type int? Also no: No target memory available for section "UDL__mulint_0". .

    I guess seriously in the long run I'll have to write this in assembler, with full care to perform those operations that can be done by single instructions on this PIC. I just don't know how much I'll be able to count some nice effects in assembler. The good thing is at least that the ICSP is there and PICKIT2 has an "auto detect and write" function, so with each compilation of the batch PICKIT2 reloads it to the PIC itself. You can iterate fairly quickly.

    Up to 24 LEDs would be useful, as I have such rings:
    Colorful RGB LED ring with 24 WS2812 diodes arranged in a circle

    Ew. You can cheat the fun slightly, as I still found such a PIC:
    Three Microchip PIC microcontrollers on currency pattern, 12F1840 pointed by tweezers
    PIC12F1840
    Specification table of PIC12F1840 and PIC12LF1840 MCUs with 256-byte SRAM highlighted
    But again, I tested once, and my PICKIT2 doesn't seem to want to recognise it, despite the new Device File. I'd have to dust off the PICKIT3, I have one too, just where.
    Helpful post? Buy me a coffee.
  • #4 21785727
    TechEkspert
    Editor
    These rings allow you to generate nice effects more easily to give the impression of movement and cyclicity of the effect. Perhaps if linear changes were used instead of a sine, such increments would be easier, while I am not sure they would be similarly visually appealing. These rings can easily draw 500mA at higher brightness. What else would be unusual to use? An external PSRAM or EEPROM would be rather difficult to use due to the transmission times required to the WS2812. The advantage is that once the data is sent, the neopixel holds the settings, i.e. calculations can be performed between successive 'frames'. Perhaps for longer strings several synchronised PICs could be used and each would control its own WS2812 group.



  • #5 21785747
    p.kaczmarek2
    Moderator Smart Home
    Yes, this holding of settings is useful, you don't have to "refresh non-stop every frame" as with, for example, PAL image generation, or there images for monitors in general, VGA the same.

    For the time being, I don't see the option to combine anything during the display, so RAM is limiting, you have to have the data already before the transmission starts. You can calculate to your heart's content, rather the frame rate (between successive frames) is not an issue here.

    What if two strips were connected to the PIC pin and somehow benefit from having two copies of the "mirror" effect?

    WS2812s in general have been discussed quite extensively on the forum already, but there is plenty to discuss as the effects are really good. Here are a handful of related topics from me:
    PIC18F45K50 as WS2812 LED strip driver (theory+library)
    ESP32 and Remote Control Transceiver (RMT) - tutorial, first steps, WS2812 control
    Controlling WS2812 diodes via SPI with DMA - using MOSI to generate timings
    Animations of OpenBeken WS2812B - new HTTP panel integration, PixelAnim driver
    An interesting alternative to the WS2812:
    LED strip with RS485 interface? DMX512 protocol - TM512C4 RGBW 24V
    How to compile and configure WLED to support DMX on LilyGo T-CAN485 ESP32?
    DIY on WS2812:
    House-built 7-segment colour display based on WS2812B
    Intelligent workshop organiser - WS2812B - illuminated drawers with database


    And your YT presentation mentioned (topic for discussion):
    WS2812B NeoPixel - #29 edu electroda.co.uk
    Helpful post? Buy me a coffee.
  • ADVERTISEMENT
  • #7 21785779
    p.kaczmarek2
    Moderator Smart Home
    512 bytes of RAM the author had:
    ATtiny85 microcontroller specs with 512 bytes of RAM and 8 KB program memory
    Helpful post? Buy me a coffee.
  • #8 21786133
    Andrzej_Tomaszewski
    Level 13  
    Hi!
    When I saw this circle with 24 WSs I was immediately reminded of how I managed to "figure out" these pixels in a BASCOM AVR environment almost 10 years ago. The main idea was to use an 8-leg uC and an internal 8MHz RC oscillator. I remember to this day my joy when I managed to light each diode in the circle with the colour I wanted, statically, without any animation yet. Later that evening I already did some animations. And this is my prototype at the time, ehh it was a fun time ;)


  • ADVERTISEMENT
  • #9 21786195
    _ACeK_
    Level 14  
    :smile: Julian Ilett showed on his video that even 4 MHz
    :idea: But to turn on - off you need more Mega Herts :wink:



    :arrow: Programme from film :razz:

    
    #include "p12F675"
    
    __CONFIG _INTRC_OSC_NOCLKOUT & _WDT_OFF
    
        org 0x00
        
    setup
        bsf     STATUS,RP0 ;select upper register bank
        clrf    TRISIO     ;make all GP outpits
        bcf     STATUS,RP0 ;select lower register bank
        clrf    GPIO
        
    loop
        bsf GPIO,2
        bcf GPIO,2
        goto    loop
        
        end
    
  • #10 21786291
    TechEkspert
    Editor
    PIC, AVR, C, Arduino, Bascom AVR, assembler you can see that in such combinations, engineering creativity is the most important thing and the tool is less important. The tool and the platform can always be changed.

    The RP2040 and PIO could be an interesting multi-channel controller at a price of 20£. The RP2350 has even more PIO so could potentially have more WS2812 control channels.
  • ADVERTISEMENT
  • #11 21786345
    p.kaczmarek2
    Moderator Smart Home
    And remember the days when the WS2812 didn't exist yet?
    Interesting topic: A strip of individually controlled RGB LEDs


    Quote:

    As near as we can tell, the popular WS2812 individually addressable RGB LED was released to the world sometime around the last half of 2013. This wasn't long ago, or maybe it was an eternity; the ESP8266, the WiFi microcontroller we all know and love was only released a year or so later. If you call these things "Neopixels", there's a good reason: Adafruit introduced the WS28212 to the maker community, with no small effort expended on software support, and branding.

    https://hackaday.com/2019/03/26/can-you-live-without-the-ws2812/
    Helpful post? Buy me a coffee.
  • #12 21786358
    Andrzej_Tomaszewski
    Level 13  
    p.kaczmarek2 wrote:
    512 bytes of RAM the author had:


    Yes, but this number of bytes of RAM is in my case just an unnecessary addition because I wanted to have as much program memory as possible in an 8-legged uC in order to fit as many effects as possible in a chip with as few legs as possible using the internal RC oscillator. This is why the ATTINY85 fell into place. In my designs, the data to send to the WSs is an array of RAM. The number of bytes is the number of WSs x3 i.e. for a caster with 24 WSs it is 24x3 i.e. an array of 72 bytes. Creating effects are operations on the array. Each time the data in the array is changed, the data from the array is sent to the caster. One such send is one frame of animation. The sending of data to the WSs is handled by a sub-procedure that I wrote in the form of an ASM insert. It analyses each bit and byte of the array and sets the state of any uC pin for the required time. No uC peripherals are needed. I don't think it can be any simpler.
  • #13 21786367
    p.kaczmarek2
    Moderator Smart Home
    Well, it's exactly like mine, except that I, with 128 bytes of RAM and with the extra operations/changes, was already struggling to fit 24 LEDs, although 21 managed to fit. I'd have to do a bit more thinking.

    And do you know how much of that RAM your program ultimately used?
    Helpful post? Buy me a coffee.
  • #14 21786378
    TechEkspert
    Editor
    This changes the situation, 72 bytes of RAM were needed for the ring and 192 bytes of RAM for the star.
    In the second case, this is already more than the title PIC12F683 has.
    That is, we have an optimisation in the form of a RAM buffer equal in size to the amount of data that needs to be transferred to the WS2812 chain. Subsequent frames are generated by transformations on the buffer.
    I remember that BASCOM used to tell us after compilation how much flash and RAM it took up.

    Further on, one could think of an algorithm that generates values for successive pixels on the fly without using the RAM buffer, but in such an approach the effects are unlikely to be arbitrary ( in practice severely limited) and one would have to stick very closely to time limits, almost like in PAL signal generation on 8 bit computers....
  • #15 21786426
    p.kaczmarek2
    Moderator Smart Home
    TechEkspert wrote:

    Further, one could think of an algorithm that generates values for successive pixels on the fly without using a RAM buffer, but in such an approach the effects are unlikely to be arbitrary ( in practice severely limited) and one would have to stick very closely to time limits, almost like in PAL signal generation on 8 bit computers...

    I don't have a reliable source in front of me at the moment, but on these PICs one instruction is 4 clock cycles (I guess the exception is jumps - they take two instruction cycles), so at 20 MHz one instruction takes 0.2µs or 200 ns. T0H is supposed to be 0.4µs +- 0.15µs so you're not going to fit any meaningful calculations in there, there's barely enough time for a bit check, and these WSs are probably operating at their tolerance limits anyway. I'd have to check what waveforms eventually came out at my place.

    Unless the WS2812 has even more latency tolerance than I thought and you can do something between sending each bit.

    Ahh, and of course you also have to remember that one C line can be multiple commands. I didn't go that deep into it, best to check the listing of the generated instructions, then you'll see.
    Helpful post? Buy me a coffee.
  • #16 21786504
    TechEkspert
    Editor
    Ok actually it is in-flight unrealisable. For that the RP2040 and RP2350 has tempting and paralleled hardware support in this area.
  • #17 21787036
    Andrzej_Tomaszewski
    Level 13  
    p.kaczmarek2 wrote:
    And do you know how much of that RAM your program ultimately used?


    Here is the compilation report.


    Screenshot of BASCOM-AVR compile report showing memory usage and variable definitions

    Cd details of the variables used.


    Screenshot of compilation report showing variable names, types, and memory addresses.

    At the bottom starting with WS2812DATA (the aforementioned 72 byte array) are the declarations of my variables. I could still dispense with a few of them as part of the optimisation, but then this large area of available SRAM makes me a bit lazy :)

    Added after 17 [minutes]:

    TechEkspert wrote:
    Further thought could be given to an algorithm that generates values for consecutive pixels on the fly without using a RAM buffer, but in such an approach the effects are unlikely to be arbitrary


    Oh rather yes. I wouldn't have a clue how to write an algorithm that modulates "on the fly" in PWM increments (because that's basically what communication with these diodes looks like) of an 800kHz waveform, sends out a certain number of pulses, the number bored by the number of diodes in the chain times 24, and finally the lighting effect would have to be as expected. Sending a static pattern would already be a challenge for me and creating an animation would be a massacre. In my opinion, an array of variables is the only sensible solution. By changing the values in this array, the expected effect is already created in my mind, which is then confirmed on the LEDs. As far as the circle is concerned, spinning effects are the easiest to achieve. We fill the array with the pattern of e.g. a comet/meteoroche, and then e.g. every 50ms we swap the data with places and after each such swap we send the data to the wheel.

    Added after 23 [minutes]:

    p.kaczmarek2 wrote:
    I don't have a reliable source in front of me at the moment, but on these PICs one instruction is 4 clock cycles (I guess the exception is jumps - they take two instruction cycles), so at 20 MHz one instruction takes 0.2µs or 200 ns. T0H is supposed to be 0.4µs +- 0.15µs so you're not going to fit any meaningful calculations in there, there's barely enough time for a bit check, and these WSs are probably operating at their tolerance limits anyway. I'd have to check what waveforms eventually came out at my place.


    I remember being determined to figure out communication with the WS2812 in BASCOM AVR. I knew that transmission using BASCOM commands wouldn't work because it wasn't known how many clock cycles these commands took, certainly more than the minimum required, and then I figured I needed to refresh my knowledge of assembler, which I'd had a lot of in high school. I bought the book "The art of programming AVR microcontrollers". There was only assembler in there. And it was already known how many clock ticks a given ASM command takes. Assuming the use of the internal 8MHz oscillator, and knowing that the transmission to the WSs takes place at 800kHz, I only have 10 clock ticks to analyse a given bit in a given byte of the data table. The ASM insert contains commands that take either 1 or 2 clock ticks, and even a few NOPs to delay :) The calculations for the effect for the next frame are done between data transmissions, and relatively speaking there is a lot of time for these calculations, thanks of course to the fact that the diodes after the transmission are still displaying the next frame until they get the next data. Well, if this were not the case and the LEDs, after sending the previous frame, would go off by themselves after a while, it would be unmanageable.
  • #18 21787164
    p.kaczmarek2
    Moderator Smart Home
    That RAM would go along with my estimate.... thanks for posting the screenshots.

    However, now I am thinking about one more issue. How much does one instruction last on this ATTINY85 in your case? Personally I skipped AVRs in favour of PICs (because I wanted something more difficult), but in the PIC from the topic there is this Fosc/4 rule, but on the ATTINY85? It seems to me that there most instructions last 1 clock cycle.

    Andrzej_Tomaszewski wrote:
    using the internal RC oscillator.

    So, one can conclude that if we compare my PIC 12F with the internal oscillator, and this ATTINY85, with me the instructions are 4 times slower to execute.... so it's not surprising that I didn't manage with the INTOSC option, while with you it started.
    Helpful post? Buy me a coffee.
  • #19 21787325
    TechEkspert
    Editor
    This would agree PIC most instructions 4 bars, some instructions 8 clock bars (e.g. jumps).
    Avr most instructions one clock bar, some 2 bars (e.g. jumps, multiplications), there are also instructions taking 4 bars (e.g. call, ret).
  • #20 21787334
    p.kaczmarek2
    Moderator Smart Home
    I would still be curious about one thing. How much would it be possible to overclock this PIC of mine. It is known that this should not be done for production, because who will guarantee that it will work stably, but DIY is governed by other laws. As if to give there a 24 MHz oscillator instead of 20 MHz, would it animate stably....

    Related: https://www.edaboard.com/threads/overclocking-pic16f877a-why-not.23379/

    Except that in the current form of the project I've hit a RAM barrier rather than a clock barrier, so this won't do much for me.
    Helpful post? Buy me a coffee.
  • #21 21787556
    Andrzej_Tomaszewski
    Level 13  
    p.kaczmarek2 wrote:
    How long does one instruction last on this ATTINY85 on you?


    Please find below a piece of documentation with instructions for the ATTINY85 in ASM plus durations. Most instructions take 1 or two cycles, much less often 3 or 4 cycles. Conditional instructions may take 1 or 2 cycles depending on the result of the check, i.e. condition met or not met. Isn't there sometimes a clock frequency prescaler programmable via fusebits in the PIC? Because the Fosc/4 is a bit of a waste....


    Instruction set summary for ATtiny25/45/85 with clock cycle counts


    Assembly instruction table for ATtiny25/45/85 with descriptions, flags, and clock cycles.
  • #22 21787560
    p.kaczmarek2
    Moderator Smart Home
    There are not many options on the PIC12F683. You can only select the frequency of the internal oscillator (31 kHz to 8 MHz) or switch to a different oscillator mode:
    Table of oscillator operating modes for PIC12F683 microcontroller
    PIC microcontroller clock source block diagram with oscillators and multiplexer

    On the other hand, I once created a separate topic about clock settings on the PIC18F2550:
    Tutorial PIC18F2550 + SDCC - Part 3 - Oscillator settings, clock, PLL
    Helpful post? Buy me a coffee.
  • #23 21787568
    kulmar
    Level 32  



    And this effect?

    Added after 1 [minute]:

    Unfortunately the mp4 does not work.
  • #24 21787581
    Andrzej_Tomaszewski
    Level 13  
    Well, I must admit that it looks strange. Looking at the schematic of the PIC's structure, it is enough to write values into the appropriate registers (controlling the MUXes) to allow the clock signal to be sent further without splitting.
  • #25 21787589
    p.kaczmarek2
    Moderator Smart Home
    @kulmar at me the video works, cool effect, what MCU? Why single colour? That's a rather far more difficult task than what we're discussing in this topic. I would rather implement this by sending continuous low resolution screenshots from the PC to the MCU controlling the LEDs, although it might also be possible to do it based on PAL or VGA.


    @Andrzej_Tomaszewski but note that even in this diagram the System Clock arrow comes out, and the Instruction Clock is System Clock / 4
    Text explaining the difference between instruction clock and oscillator in PIC MCUs
    https://developerhelp.microchip.com/xwiki/bin...products/mcu-mpu/8bit-pic/oscillator-options/
    The PIC12F does not have a PLL. In my opinion you will not do anything.
    Helpful post? Buy me a coffee.
  • #26 21787623
    kulmar
    Level 32  
    p.kaczmarek2 wrote:
    @kulmar at me the video works, nice effect, what MCU? Why the single colour? That's a rather far more difficult task than what we are discussing in this topic. I would rather implement it by sending continuous low-resolution screenshots from the PC to the MCU controlling the LEDs, although it might also be possible to do it based on PAL or VGA.

    No processor there - this design is a dozen years old. Mono - because the control signal is the Composite video signal from the player. 50 frames per second.
  • #27 21790082
    acctr
    Level 39  
    p.kaczmarek2 wrote:
    For simplicity's sake, I've introduced an array of sine values (in byte form), although this is largely a disastrous approach - I lose up to 32 bytes for it alone!

    You can declare the array in program memory (Flash) using e.g. __code
    Code: C / C++
    Log in, to see the code

    p.kaczmarek2 wrote:
    even in this diagram the System Clock arrow comes out, and the Instruction Clock is System Clock / 4

    One difference between AVR and PIC is the pipeline - in AVR most instructions are one instruction per clock cycle, in PIC it is 1/4.
    That's still not bad compared to, say, '51, where one machine cycle is 12 clock cycles, and there are instructions taking up 4 machine cycles, or 48 clock cycles.
    Interestingly, AVRs are microcontrollers belonging to RISC, i.e. reduced number of instructions and such a 2313 has 89 instructions and its counterpart (memory, GPIO) from the MCS 51 family belonging to CISC 89C2051, has 44 mnemonics :D
    In PICs, which are also RISC, it already looks better because their number is 35 for 16F627. That's why, for me, writing in assembler is more pleasant with PICs than with AVRmi despite the worse performance (although nowadays you can cheaply buy a PIC with fclk=32MHz and 28kB flash, cheaper than the legendary 16F84, so it's not bad with performance).
    Helpful post? Buy me a coffee.
  • #28 21790101
    TechEkspert
    Editor
    You surprised me with the number of commands for MCS'51 less than in AVR I never thought about it even though I used asm for both families. the 8 bit PIC16 has even fewer commands than the '51.

    the 12 clock command cycle in '51 was not very attractive with a 12MHz resonator you were getting 1MHz on instructions. Although there were some DS80C320 inventions running at 33MHz and they had a shortened command cycle. the '51 is still active https://www.silabs.com/mcu/8-bit-microcontrollers

    It is a stretch to say that compared to the 12-bar MCS51: the AVR is single-bar and the PIC is 4-bar, of course it is a different type of architecture and there are also 8-bar instructions for the PIC and 2 and 4-bar instructions in the AVR.
  • #29 21792749
    _ACeK_
    Level 14  
    :smile: Following the video Julian from my earlier post :idea: I made an assembler version of the program on ATtiny13 which runs on an internal clock 9.6MHz :evil: This CPU is so fast that I had to insert some nop orders to meet the time requirements NeoPixels :wink:

    
    ;************************************************
    ;* From 12F675 Neopixel Driver  by Julian Ilett *
    ;*            to ATtiny13 at 9.6 MHz            *
    ;************************************************
    
    .nolist
    .include "tn13def.inc"
    .list
    
    .def    acc     = r16
    .def    count   = r17
    .def    d_count = r18
    .equ    count_  = 65535
    .cseg 
    
    .org 0x0000
    ;----------------------------
        rjmp    Reset           ; Reset vector
        reti                    ; INT0
        reti                    ; PCINT0
        reti                    ; TIM0_OVF
        reti                    ; EE_RDY
        reti                    ; ANA_COMP
        reti                    ; TIM0_COMPA
        reti                    ; TIM0_COMPB
        reti                    ; WDT
        reti                    ; ADC
    ;----------------------------
    Reset:
        ldi     acc,Low(RAMEND) ; Init stack
        out     SPL,acc         ; RAMEND to SPL
    setup:
        ldi     acc,0b000_0010  ; Init ports
        out     DdrB,acc        ; In PortB bit 1 as output
    ;----------------------------    
    loop:
        rcall   led_off         ; set
        rcall   led_off         ; first
        rcall   led_on          ; Led to blue
    
        rcall   led_off         ; set
        rcall   led_on          ; second
        rcall   led_off         ; Led to red
    
        rcall   led_on          ; set
        rcall   led_off         ; third
        rcall   led_off         ; Led to green
    
        rcall   delay_32        ; send reset
    
        rcall   led_off         ; clear
        rcall   led_off         ; first
        rcall   led_off         ; Led 
        
        rcall   led_off         ; clear
        rcall   led_off         ; second
        rcall   led_off         ; Led
        
        rcall   led_off         ; clear
        rcall   led_off         ; third
        rcall   led_off         ; Led
    
        rcall   delay_16        ; send reset
    
        rjmp    loop            ; start again
    ;----------------------------
    led_on:                     ;
        ldi     acc,0x08        ; loop
        mov     count,acc       ; to
    ledn:                       ; send
        sbi     PortB,1         ; 8
        nop                     ; bits
        nop                     ; on
        nop                     ; neopixel
        nop                     ; at
        cbi     PortB,1         ; pin
        nop                     ; 1
        nop                     ; of
        nop                     ; portb
        nop                     ;
        nop                     ;
        nop                     ;
        dec     count           ; 
        brne    ledn            ; retern
        ret                     ; loop
    ;----------------------------
    led_off:                    ; loop
        ldi     acc,0x08        ; to
        mov     count,acc       ; send
    ledf:                       ; 8
        sbi     PortB,1         ; bits
        nop                     ; on
        cbi     PortB,1         ; neopixel
        dec     count           ; at
        nop                     ; pin
        nop                     ; 1
        nop                     ; of
        nop                     ; portb
        brne    ledf            ; retern
        ret                     ; loop
    ;----------------------------
    delay_16:                   ; do
        ldi     d_count,16      ; delay
        rcall   delay           ; 16
        ret                     ; times
    ;----------------------------
    delay_32:                   ; do
        ldi     d_count,32      ; delay
        rcall   delay           ; 32
        ret                     ; times
    ;----------------------------
    delay:                      ;
    d_c:                        ; 16 or 32
        ldi     Xl,low (count_) ;
        ldi     Xh,high(count_) ;
    del_count:                  ;
        sbiw    Xh:Xl,1         ; 65535 - 1
        brne    del_count       ; and
        dec     d_count         ; so
        brne    d_c             ; on
        ret                     ; return from delay
    ;----------------------------
    .exit
    

    
    :020000020000FC
    :1000000009C018951895189518951895189518956C
    :10001000189518950FE90DBF02E007BB25D024D035
    :1000200012D022D010D020D00ED01ED01DD02BD078
    :100030001BD01AD019D018D017D016D015D014D084
    :1000400013D01ED0EBCF08E0102FC19A00000000A3
    :1000500000000000C1980000000000000000000047
    :1000600000001A9591F7089508E0102FC19A00003A
    :10007000C1981A950000000000000000B9F708952B
    :1000800020E104D0089520E201D00895AFEFBFEF42
    :0A0090001197F1F72A95D1F70895B2
    :00000001FF
    



  • #30 21792753
    p.kaczmarek2
    Moderator Smart Home
    @acctr I had a moment and checked what you wrote. After checking I come to the conclusion that I was also wrong before.

    With const byte sine_table[32] the memory is missing from NUM_PIXELS 20. With __code const byte sine_table[32] it is.... the same. Also the same with :
    
    __code __at (0x200) const byte sine_table[32] = {
      128,152,176,198,218,234,246,254,
      255,254,246,234,218,198,176,152,
      128,104, 80, 58, 38, 22, 10, 2,
        1, 2, 10, 22, 38, 58, 80,104
    };

    I think I see that it's a bit different than we think, though. The const itself makes this array in flash:
    
    
                                               ;--------------------------------------------------------
                                               ; initialized data
                                               ;--------------------------------------------------------
    
                                               IDC_pic12f683_ws_0	code
                                               _sine_table
    0002e0   3480     retlw   0x80             	retlw 0x80	; 128
    0002e1   3498     retlw   0x98             	retlw 0x98	; 152
    0002e2   34b0     retlw   0xb0             	retlw 0xb0	; 176
    0002e3   34c6     retlw   0xc6             	retlw 0xc6	; 198
    0002e4   34da     retlw   0xda             	retlw 0xda	; 218
    0002e5   34ea     retlw   0xea             	retlw 0xea	; 234
    0002e6   34f6     retlw   0xf6             	retlw 0xf6	; 246
    0002e7   34fe     retlw   0xfe             	retlw 0xfe	; 254
    0002e8   34ff     retlw   0xff             	retlw 0xff	; 255
    0002e9   34fe     retlw   0xfe             	retlw 0xfe	; 254
    0002ea   34f6     retlw   0xf6             	retlw 0xf6	; 246
    0002eb   34ea     retlw   0xea             	retlw 0xea	; 234
    0002ec   34da     retlw   0xda             	retlw 0xda	; 218
    0002ed   34c6     retlw   0xc6             	retlw 0xc6	; 198
    

    Then there's the data access:
    Code: text
    Log in, to see the code

    And this is probably how it has been since the beginning. It seems that this board is not the culprit after all.
    Helpful post? Buy me a coffee.
📢 Listen (AI):
ADVERTISEMENT