Leaving Lepidoptera
A quick(ish) video about modifying a little butterfly toy. Just to make a nice change from all the coding!
I hope that you enjoy the change of pace - regular programming will resume shortly!
Each week I will feature a circuit based on one or more of the electronic parts I have ordered then forgotten about over the years.
A quick(ish) video about modifying a little butterfly toy. Just to make a nice change from all the coding!
I hope that you enjoy the change of pace - regular programming will resume shortly!
I have been tinkering with Solar Power and WiFi for a while now - and the arrival of some new solar panels and the tiny Seeed Studio ESP32-C6 prompted me to put together a prototype for testing.
I also decided to (briefly) use an IP2312 charging module - but as you will see in the video below it didn't really work out for me - more exploration required at this point!
Another snag was that the little board needed a software coded switch to activate the external antenna, and so I had to insert that code into the project, and ended up creating my own github folder with the tweaks, including compiled binary files if you want to just lock and load the code.
// Added by OneCircuit (and Gemini AI) on Tue 12 Aug 2025 14:49:14 AEST // https://www.youtube.com/@onecircuit-as #include "driver/gpio.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" // Define GPIO pin numbers #define ESP32C6_WIFI_ENABLE_PIN GPIO_NUM_3 #define ESP32C6_WIFI_ANT_CONFIG_PIN GPIO_NUM_14 void initialise_ext_antenna(void) { // Configure GPIO pins as outputs gpio_reset_pin(ESP32C6_WIFI_ENABLE_PIN); gpio_set_direction(ESP32C6_WIFI_ENABLE_PIN, GPIO_MODE_OUTPUT); gpio_reset_pin(ESP32C6_WIFI_ANT_CONFIG_PIN); gpio_set_direction(ESP32C6_WIFI_ANT_CONFIG_PIN, GPIO_MODE_OUTPUT); // Set pin levels gpio_set_level(ESP32C6_WIFI_ENABLE_PIN, 0); // Activate RF switch control (LOW) // Delay vTaskDelay(pdMS_TO_TICKS(100)); // Use a FreeRTOS delay function gpio_set_level(ESP32C6_WIFI_ANT_CONFIG_PIN, 1); // Use external antenna (HIGH) }
This is a version of the ESP32 router code found at:
https://github.com/dchristl/esp32_nat_router_extended, which in turn is a version of the code found here:
https://github.com/martin-ger/esp32_nat_router
I also slightly modified the partitions csv file to work with the ESP32C6, and added a file of the commands I used to load the binaries using esptool.py
Also thanks to Gemini AI who came in after three days of me banging me head against a wall trying to merge two coding platforms and sorted out the last little hiccups in my code.
Finally, for LOLS, I moved from the Arduino IDE to Visual Code Studio with PlatformIO and ESP-IDF extensions running - it's own little adventure in the end.
The whole project taught me a great deal about all of these components - hardware, software, tweaking and even some antenna rabbit holes!
Enjoy and please leave a comment if you have a moment!
It's funny how you can do something for so long without realising that it's a bit kooky!
For years I've been making various flavours of the "candle project" and each time I spend W-A-Y too long poking about in the cupboard for all the components (and swearing a bit as well).
Recently I took delivery of a new "super capacitor" PCB (gerbers available here) based version of this project, and I was once again contemplating gathering all the components when...it suddenly occurred to me to make up a specific project box.
Game changer!
So the video below is both a testament to my stupidity and a nod to the concept of project file boxes. Enjoy - it's a long one so go get your favourite beverage before clicking!
Last time we looked at the RV2 it was for LOLS, but I would really like to have a screen and 'puter in the lab/work area for music, internet, conferencing, video capture, etc., - so in this video I house the beast in a case and sling it up on the wall in front of my workbench.
Short story 'tis true - but another great addition to the channel workflow. Check it out in the video below.
Well it's 2025 and apart from craziness erupting all over the planet the big news is RISCV continues to impress the punters with it's speed, reliability and efficiency.
Orange Pi are now officially on the RISCV bandwagon which means of course so am I, with a delivery recently of the RV2 single board computer.
It's a lovely piece of kit and in the video below I take it for a spin and hook it up to a touch screen via the Ubuntu sanctioned OS image.
Only one hiccup - the EMMC card needs to be loaded via the OS, not from the image itself. It's a minor issue that I was easily able to solve (in fact I over complicated the whole thing a bit - as usual).
Sit back and enjoy - and please like and subscribe!
It's 0000 0001 0000 0000, or in other words a momentous binary moment of 256 videos for this channel, and...
After around 5 years of development I'm so happy to report that one of my long term projects has been converted from the energy source of a rechargeable (NiMH) battery to a super capacitor.
It seemed unlikely at the outset of this endeavour as there were four major miracles that needed to happen.
1. How to charge a super capacitor to 3.8V from a QX5252 that is used to charging a 1.2V NiMH battery? See this video for the - partial - solution.
2. Is it possible for a super capacitor to run a micro-controller for any significant length of time? See this video for the answer.
3. How does a micro-controller with no ADC determine if there is no sunshine about? See this video for the answer.
4. And finally - putting all of these components together in a fake "candle"? Will that even work? Well, see the video linked below.
Here is the final(ish) code:
/* Super Capacitor Candle with Three PWM Pseudo-random flickering to simulate a candle. Output is via 3xPWM channels, variables can be changed to alter the simulation. Code includes checking to see if there is light and sleeping during the day while the capacitor is charging. Tue 27 May 2025 14:13:42 AEST DEVICE = PFS154 F_CPU = 50000 Hz TARGET_VDD = 3.8 V _________ / | 1--|VCC GND|--8 2--|PA7 PA0|--7 3--|PA6 PA4|--6 4--|PA5 PA3|--5 |__________| PAC = 0b00000000 all inputs as standard output off on pullup ------ --- -- ------ pin 2 PA7 PAC = 0b10000000, PA = 0b10000000, PA = 0b00000000, PAPH = 0b10000000 pin 3 PA6 PAC = 0b01000000, PA = 0b01000000, PA = 0b00000000, PAPH = 0b01000000 pin 4 PA5 PAC = 0b00100000, PA = 0b00100000, PA = 0b00000000, PAPH = 0b00100000 pin 5 PA3 PAC = 0b00001000, PA = 0b00001000, PA = 0b00000000, PAPH = 0b00001000 pin 6 PA4 PAC = 0b00010000, PA = 0b00010000, PA = 0b00000000, PAPH = 0b00010000 pin 7 PA0 PAC = 0b00000001, PA = 0b00000001, PA = 0b00000000, PAPH = 0b00000001 */ // libraries needed #include <stdbool.h> #include <stdint.h> #include <stdlib.h> #include "../auto_sysclock.h" #include "../delay.h" #include "../device.h" #include "../easy-pdk/calibrate.h" uint16_t myrand = 2901; // happy birthday // initialise variables uint8_t slowcounter = 0; uint8_t medcounter = 0; uint8_t fastcounter = 0; uint8_t slowstart = 0; uint8_t slowend = 0; uint8_t medstart = 0; uint8_t medend = 0; uint8_t faststart = 0; uint8_t fastend = 0; uint8_t faster = 0; // variables for different types of flicker - change to suit! const uint8_t percentnormal = 82; // cutoff for normal/calm const uint8_t percentsputter = 20; // cutoff for sputtering/normal uint8_t flickdelay = 40; // initial speed of flicker const uint8_t flickdelaysputter = 9; // "sputtering" activity const uint8_t flickdelaynormal = 40; // "normal" activity const uint8_t flickdelaycalm = 95; // "calm" activity uint8_t choosearray = 1; // normal waves uint8_t delaycounter = 50; uint8_t delaydelay = 20; bool sunshine = false; // is the sun shining? // can change these too if you want to play with the candle uint8_t waves[9][4] = { {4, 6, 40, 50}, // sputter flicker waveslow {6, 8, 50, 80}, // sputter flicker wavemed {8, 10, 110, 130}, // sputter flicker wavefast {15, 25, 60, 100}, // normal flicker waveslow {10, 25, 110, 140}, // normal flicker wavemed {20, 25, 100, 120}, // normal flicker wavefast {40, 60, 100, 140}, // calm flicker waveslow {50, 70, 120, 160}, // calm flicker wavemed {70, 80, 140, 180} // calm flicker wavefast }; bool fastup = true; bool slowup = true; bool medup = true; void mydelay(uint8_t counter) { for (uint8_t thiscount = 0; thiscount <= counter; thiscount++) { _delay_us(1); } } // my random routine that hasn't changed for years! uint16_t gimmerand(uint16_t small, uint16_t big) { myrand ^= (myrand << 13); myrand ^= (myrand >> 9); myrand ^= (myrand << 7); if (abs(myrand) % 13 == 0) { myrand = myrand - 23; } if (abs(myrand) % 17 == 0) { myrand = myrand + 11; } return abs(myrand) % 23 * (big - small) / 23 + small; } void getnewslow(uint8_t whicharray) { slowstart = gimmerand(waves[whicharray][0], waves[whicharray][1]); slowend = gimmerand(waves[whicharray][2], waves[whicharray][3]); } void getnewmed(uint8_t whicharray) { medstart = gimmerand(waves[whicharray + 1][0], waves[whicharray + 1][1]); medend = gimmerand(waves[whicharray + 1][2], waves[whicharray + 1][3]); } void getnewfast(uint8_t whicharray) { faststart = gimmerand(waves[whicharray + 2][0], waves[whicharray + 2][1]); fastend = gimmerand(waves[whicharray + 2][2], waves[whicharray + 2][3]); faster = gimmerand(2, 6); } // interrupt triggered when the sun goes away, voltage of small // capacitor is drained void Interrupt(void) { __disgint(); // disable global interrupts INTEN = 0; // disable all interrupts INTRQ = 0; sunshine = false; __engint(); // enable global interrupts } // compares the cap voltage with the internal voltage bool checksolar(void) { uint8_t compresult = 0; // initially a byte compresult = GPCC & 0b01000000; // mask the result output compresult = compresult >> 6; // shift it to the least significant bit sunshine = (bool)compresult; // cast result as a boolean return sunshine; } void candlingon() { PAC = 0b00110001; PA = 0b00000000; // see datasheet PWMG1DTL = 0x00; PWMG1DTH = 0x00; PWMG1CUBL = 0xff; PWMG1CUBH = 0xff; PWMG1C = 0b10100110; PWMG1S = 0b00000000; PWMG0DTL = 0x00; PWMG0DTH = 0x00; PWMG0CUBL = 0xff; PWMG0CUBH = 0xff; PWMG0C = 0b10100110; PWMG0S = 0b00000000; PWMG2DTL = 0x00; PWMG2DTH = 0x00; PWMG2CUBL = 0xff; PWMG2CUBH = 0xff; PWMG2C = 0b10101010; PWMG2S = 0b00000000; getnewfast(choosearray); getnewslow(choosearray); getnewmed(choosearray); slowcounter = slowstart; fastcounter = faststart; medcounter = medstart; while (!sunshine) { // ramp up slow if (slowup) { slowcounter++; if (slowcounter > slowend) { // ramp finished so switch boolean slowup = !slowup; } } else { // ramp down slow slowcounter--; if (slowcounter < slowstart) { // ramp finished so switch boolean slowup = !slowup; getnewslow(choosearray); } } // ramp up med if (medup) { medcounter++; if (medcounter > medend) { // ramp finished so switch boolean medup = !medup; } } else { // ramp down med medcounter--; if (medcounter < medstart) { // ramp finished so switch boolean medup = !medup; getnewmed(choosearray); } } // ramp up fast if (fastup) { fastcounter = fastcounter + faster; if (fastcounter > fastend) { // ramp finished so switch boolean fastup = !fastup; } } else { // ramp down fast fastcounter = fastcounter - faster; if (fastcounter < faststart) { // ramp finished so switch boolean fastup = !fastup; getnewfast(choosearray); } } // delay + a re-purposed random for ramp speeds mydelay(flickdelay + faster); delaycounter = delaycounter - 1; if (delaycounter == 0) { delaycounter = gimmerand(1, 100); if (delaycounter > percentnormal) { // calm flickdelay = flickdelaycalm; choosearray = 6; delaycounter = 100 - delaycounter; } else if (delaycounter > percentsputter) { // "normal" flickdelay = flickdelaynormal; choosearray = 3; } else { // sputtering flickdelay = flickdelaysputter; choosearray = 0; } sunshine = (bool)checksolar(); delaycounter = delaycounter * delaydelay; } // finally the actual PWM output PWMG2DTL = slowcounter & 255; PWMG2DTH = slowcounter; PWMG0DTL = fastcounter & 255; PWMG0DTH = fastcounter; PWMG1DTL = medcounter & 255; PWMG1DTH = medcounter; } } // close down void candlingoff() { PWMG2DTL = 0; PWMG2DTH = 0; PWMG0DTL = 0; PWMG0DTH = 0; PWMG1DTL = 0; PWMG1DTH = 0; PWMG0C = 0b00100000; PWMG1C = 0b00100000; PWMG2C = 0b00100000; } // here is where the uC goes to sleep void sleepnow() { __disgint(); // disable global interrupts MISC |= MISC_FAST_WAKEUP_ENABLE; // fast wakeup PAC = 0; PA = 0; PAPH = 0xFF; PBDIER = 0; // there is no port B on the -S08 package, // without setting this to 0 the uC will wake unexpectedly INTEN = 0b00010000; // enable comparator interrupt INTRQ = 0b00010000; __engint(); // enable global interrupts __stopsys(); // go to sleep } void main() { // page 66 datasheet GPCC = 0b10010000; GPCS = 0b00000011; // sensitivity is affected by bit 0-3 _delay_ms(100); // small settle time delay while (1) { if (!sunshine) { candlingon(); // it's dark, start candling action } else { candlingoff(); sleepnow(); // it's light, go to sleep __reset(); // seems harsh but helps with the flickering anew } } } // Startup code - Setup/calibrate system clock unsigned char _sdcc_external_startup(void) { /* Set the system clock note it is necessary to enable IHRC clock while updating clock settings or CPU will hang */ PDK_USE_ILRC_SYSCLOCK(); /* use ILRC 55kHz clock as sysclock */ PDK_DISABLE_IHRC(); /* disable IHRC to save power */ EASY_PDK_CALIBRATE_ILRC(F_CPU, TARGET_VDD_MV); // Makefile has these values /* DEVICE = PFS154 F_CPU = 50000 TARGET_VDD_MV = 3800 TARGET_VDD = 3.8 */ return 0; // Return 0 to inform SDCC to continue with normal initialization. }
Apologies for the non-standard circuit diagram rendered by hand!
And here is a picture of the final product.
If you think this is awesome - like I do - please share widely as feedback on this sort of breakthrough is a really important part of the development of these ideas into future projects.
Well here is another insight into the harmful nature of late night 'under-the-influence' online shopping, although I still enjoyed some of the tasty morsels that arrived here in "downtown Tasmania" this round - there are potentially some great projects ahead.
Also I'm very chuffed to have a legit RISCV OPi in my hands after this video!
Enjoy the video, brought to you for the first time from TWO different angles!