Demo
This was the very first step in this project that shows how machines talk to each other in a way humans could perceive :
- Broadcast use case
Firmware
WS2812B bitbanging
- The challenge here was to make an 16MHz 8bit microcontroller namely the 1$ STM8S bread board talk to a WS2812B where the full fledged ones have to be using tricks and DMAs and timers and complex stuff.
- As you might know there Smart RGB Leds are controlled with pulses that generate the 24bits of reg green blue, the problem is that every bit a pulse short or long for 0 or 1, and the Time for the high pulse of a zero as an example is 400 ns, well at 16MHz, every intruction is 62,5 nano second, that leave us with 6 instruction for looping and deciding which bit to bang the next.
- The hack here was to jump down to assambler, yes in this world of javascript, if you really want to hack stuff that's the ultimate way.
- Let's first have a look at a piece of the code
void rgb_SendArray()
{
BYTE int_state = __get_interrupt_state();
__disable_interrupt();
asm(
"lb_intiLoop: \n"
"LDW X, #0xFFFF \n"// set -1 in X, so that first inc gets 0, as inc has to be in the beginning of the loop
"LDW Y, L:nbLedsBytes \n"//2
"lb_begin_loop: \n"
//---------------------------------------------------------------
//--------------- bit 0 -----------------------------------------
"INCW X \n"// L t+2
"lb_start_bit0: \n"//
"LD A, (L:LedsArray,X)\n"//
RGBLedPin_Set
"AND A, #0x80 \n"// H t2
"JREQ L:lb_bit0_Send_0 \n"// H0 t3 t4 : 2 jump to Zero, 1 Stay in One + next nop
"lb_bit0_Send_1: \n"//------Send 1 : 800ns High, 450ns Low (12,8) 750ns,500ns
"nop \n"// H1 t5
"nop \n"// H1 t6
"nop \n"// H1 t7
"nop \n"// H1 t8
"nop \n"// H1 t9
"nop \n"// H1 t10
"nop \n"// H1 t11
"nop \n"// H1 t12
RGBLedPin_ReSet // L1 t1
"nop \n"// L1 t2
"JRA L:lb_start_bit1 \n"// L1 JRA:2 t4
// L1 NextBitTest:4 t8
"lb_bit0_Send_0: \n"//------Send 0 : 400ns High, 850ns Low (7,13) 375ns,875ns
// H0 t4
RGBLedPin_ReSet // L0 t1
"nop \n"// L0 t1
"nop \n"// L0 t2
- rgb_sendArray is a C function, that starts by disabling the interrupts after saving the interrupts state to restitute them later on.
- of course any interrupt here would corrupt the bit banging, so expect a latency on your interrupts handling.
- The trick to have a multi line assembler that looks nice was to add the end line inside the asembler text.
- This function can bag as many LEDs as you have RAM, unfortunately with the STM8S I could not compile more than ~ 220 bytes of continuous memory, which is more than enough for series of Leds.
- The trick is to start by setting a PIO, which is a macro, as the pin is configurable, I did not manage to have text confurable variable inside the assembler, so that was the trick.
- You always have to set a PIO high either it is a zero or a one, then as they have different timings, if it is not a zero then keep some more nops to make the one pulse longer, otherwise jump directly to the reset instruction to make the pulse shorter.
- Now the problem was that looping instructions were not fast enough to cover all cases of second half of bit timings, that means that if we have to send the first bit, then loop, test and start sending the second bit, the loop would be so slow that it is not possible to set the new pulse soon enough. The only way to solve this was to unroll the complete 8 bits, yes unroll which means writing the same code 8 times, for bit one, bit two, bit three. I admit that sounds completely stupid from advanced programming perspective, but if anyone else could hold the challenge of banging WS2812B with the STM8S differently, I'd be very interested.
- Any way, it's working, it's not very much code consuming, and it is very memory friendly as every bit to send take only one bit out of the memory, so that we save the RGB values in memory first as three consecutive bytes.
Full source code part of the STM8S driver : github IoT_Frameworks WS2812B.c
Color Flashing
- Not much is left to flash colors, first the needed color is written in memory, then the assembler rgb_SendArray function is called.
- Now, I added additional routines to make more advanced functions easier, such as providing a counter, and making the color stick to the counter level. It is color shading.
void rgb_FlashColors(BYTE delay, RGBColor_t Color)
{
for(int iCount=0;iCount<255;iCount++)//0-10
{
RGBColor_t Ci = rgb_ColorScale(iCount,255,BLACK,Color);
rgb_SendColors(Ci);
delay_ms(delay);
}
for(int iCount=0;iCount<255;iCount++)//0-10
{
RGBColor_t Ci = rgb_ColorScale(iCount,255,Color,BLACK);
rgb_SendColors(Ci);
delay_ms(delay);
}
rgb_SwitchOff();
}
- So this is only following counter and scaling colors to them to go first up in the first loop and then down
- Note the color passed as argument is scaled between Black and the color itself to fade it in and then out, but the same function could be used to shade a temperature between cold and warm for example.
- The last magic step is the color scaling which is a simple interpolation of the R, G and B values, not worth showing here refer in the same driver source for details.
- So only important to keep in mind, you first create the colors in memory with any time consuming operation, shading, scaling, and then bit banging with the assembler function every new intermediate color, doing so consecutively show the result in the video above how LEDs flash slowly and nicely and not only stick on a new color.
RF Broadcast
- The rest is a simple broadcast and listen.
- The master flashes the color before sending the RF signals
- The slaves flash of course after reception, which give a better visual effect of slaves submission.
- The RF broadcast is not of significant importance here as more work has been done on the mesh protocol, but that'll be in posts to follow.
Voltage levels
- This is a weak spot of the design I'm struggling with, the WS2812B is not really TTL compliant and as the STM8S is running on 3.3V as per PCB design is required for the nRF24L01, the LEDs sometimes do not like the timing as they would not get the full pulse but a shorter top of it. In one LED, that's not a problem, but with a long LED series, there might be some issues, I'm trying some level shifters but high speed level shifting is more critical.
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.
please share circuit diagram of STM8S rf node and STM8L mobile Node
thx
Are you sure? yes | no
The PCB design in eagle are already shared in this github repo : https://github.com/HomeSmartMesh/STM8_IoT_Boards/tree/master/IoT_Node_Mobile_v2
Are you sure? yes | no
Here is the latest generation that I recommend more powerful than the STM8 https://github.com/nRFMesh/nRF52_Mesh
Are you sure? yes | no
https://github.com/HomeSmartMesh/IoT_STM8 Is rdb_leds project using mash network mode ? I am not able understand how its work like how 1st receive code for 2nd node that client of 1 st node
thx
Avtar
Are you sure? yes | no
Hi, see the protocol in https://www.homesmartmesh.com/mesh/
byte2 is source id, the node that sent the packet, and byte3 is dest, the node that shall use the packet, other nodes that receive the same message but have different id shall ignore the packet.
Please note that the IoT_STM8 is no longer maintained, the currently supported platform is the the nRF52840.
Let me know if you have more questions.
Are you sure? yes | no
Hi
I trying to compile rgb_leds but in libs error rfi_header_size,rf_pid_0xDF_retransmit and rfi_payload_offset is undefined ,How to compile
Are you sure? yes | no
Hi, I spotted some duplications of the same comment :)
Hi, yes, thank you for your finding, I fixed these compilation errors in the commit I made today just for maintenance
541ae723d424edbea4a077d8590023a95d9712cb
make sure you're using the repo https://github.com/HomeSmartMesh/IoT_STM8
But actually, the STM8 was the very first version of the mesh HW and I stopped working with it, that is why they are deprecated, and at the time, I did not had a good project share with submodules to prevent update of shared libs without breaking other projects.
Since then, I moved to the STM32 for bridges and continuously powered devices, I implemented also a driver for the WS2812B there. https://github.com/HomeSmartMesh/IoT_Frameworks/tree/master/stm32_rf_dongle/rf_bridge
And after the STM32, I switched to the nRF52 for which I found nice small USB dongles that I reflash with nRF firmware. I see you also followed my project #nRF52 Sensors Mesh Network , thank you for your interest, that is the project I am currently actively working on, so if you have questions or require support for that project I will be able to help much easier.
Are you sure? yes | no