Friday, October 14, 2022

0000 0000 1010 1011

SuperCap II - the low low clock speed

"I'm always chasing rainbows!" - nice lyrics from Thomas Joseph McCarthy and in my case it could be better phrased as "I'm always chasing low clock speeds and energy requirements!"

It's a little fruitless and frustrating at times but I'm a big fan of Thomas Edison who said a couple of things that resonate in these strange pursuits:

1.  "Opportunity is missed by most people because it is dressed in overalls and looks like work.", and

2. "I have not failed 10,000 times. I have successfully found 10,000 ways that will not work."

So in this project the plan was to take a successful light design and change out the NiMH battery for a super-capacitor. The reason is that NiMH batteries have a much smaller cycle lifetime compared to super capacitors.

As well I want to wind down the clock speed on the Padauk PFS154 and see how low it can go. 

Also I will be using the 5050 Leds that I've used before to minimise the energy requirements.

The super-capacitor used in the last video was a "paltry" 4 Farads. The current version is 2x30 Farad capacitors, and I have some bigger ones coming - er, because see 2nd quote from Edison above!

The code side was where the big gains have been made - I was able to successfully wind down the clock to around 17000Hz (!) and still run the "candle".

/*
  Candle with Three PWM

  Pseudo-random flickering to simulate a candle. Output is
  via 3xPWM channels, variables can be changed to 
  alter the simulation

  Wed 12 Oct 2022 20:46:06 AEDT

*/

#include <stdint.h>
#include <stdlib.h>
#include "../device.h"
#include "../easy-pdk/calibrate.h"
#include "../auto_sysclock.h"
#include "../delay.h"
#include <stdbool.h>

#define LED4_BIT 4
#define LED0_BIT 0
#define LED3_BIT 3

uint16_t myrand = 2901;  // happy birthday

// global variables randomised later for flickering, using the
// "waveslow" and "wavefast" arrays
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;

uint8_t waveslow[] = {50, 100, 170, 200}; // 1 leds on PA4
uint8_t wavemed[] = {40, 120, 140, 220};  // 1 led on PA3
uint8_t wavefast[] = {40, 80, 150, 240};  // 1 led on PA0

// booleans to keep track of "fading up" or "fading down"
// in each of the slow and fast cycles
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);
  }

}

uint16_t gimmerand(uint16_t small, uint16_t big) {
  myrand ^= (myrand << 13);
  myrand ^= (myrand >> 9);
  myrand ^= (myrand << 7);
  return abs(myrand) % 23 * (big - small) / 23 + small;
}

void getnewslow() {
  slowstart = gimmerand(waveslow[0], waveslow[1]);
  slowend = gimmerand(waveslow[2], waveslow[3]);
}

void getnewmed() {
  medstart = gimmerand(wavemed[0], wavemed[1]);
  medend = gimmerand(wavemed[2], wavemed[3]);
}

// initialise a new fast cycle including the new speed of cycle
void getnewfast() {
  faststart = gimmerand(wavefast[0], wavefast[1]);
  fastend = gimmerand(wavefast[2], wavefast[3]);
  faster =  gimmerand(1, 8);
}

// Main program
void main() {

  // Initialize hardware
  // Set LED as output (all pins are input by default)
  PAC |= (1 << LED4_BIT) | (1 << LED0_BIT) | (1 << LED3_BIT);

  PWMG1DTL = 0x00;                // Clear the LED PWM duty value
  PWMG1DTH = 0x00;
  PWMG1CUBL = 0xff; // set PWM counter upper bound to 0xffff
  PWMG1CUBH = 0xff;
  PWMG1C = 0x87;
  PWMG1S = 0b00000000; // prescaler=4, divider=1, no interrupt

  PWMG0DTL = 0x00;                // Clear the LED PWM duty value
  PWMG0DTH = 0x00;
  PWMG0CUBL = 0xff; // set PWM counter upper bound to 0xffff
  PWMG0CUBH = 0xff;
  // PWMG0C = (uint8_t)(PWMG0C_ENABLE | PWMG0C_INVERT_OUT | PWMG0C_OUT_PA0 | PWMG0C_CLK_IHRC);
  PWMG0C = 0x87;
  PWMG0S = 0b00000000; // prescaler=4, divider=1, no interrupt

  PWMG2DTL = 0x00;                // Clear the LED PWM duty value
  PWMG2DTH = 0x00;
  PWMG2CUBL = 0xff; // set PWM counter upper bound to 0xffff
  PWMG2CUBH = 0xff;
  PWMG2C = 0x87;
  PWMG2S = 0b00000000; // prescaler=4, divider=1, no interrupt

  getnewfast();
  getnewslow();
  getnewmed();
  slowcounter = slowstart;
  fastcounter = faststart;
  medcounter = medstart;

  // Main processing loop
  while (1) {

    // 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();
      }
    }

    // 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();
      }
    }

    // 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();
      }
    }
    // delay + a re-purposed random for ramp speeds
    mydelay(3+faster);

    PWMG1DTL = slowcounter & 255;
    PWMG1DTH = slowcounter;
    PWMG0DTL = fastcounter & 255;
    PWMG0DTH = fastcounter;
    PWMG2DTL = medcounter & 255;
    PWMG2DTH = medcounter;

  }
}

// Startup code - Setup/calibrate system clock
unsigned char _sdcc_external_startup(void) {

  // Initialize the system clock (CLKMD register) with the IHRC, ILRC, or EOSC clock source and correct divider.
  // The AUTO_INIT_SYSCLOCK() macro uses F_CPU (defined in the Makefile) to choose the IHRC or ILRC clock source and divider.
  // Alternatively, replace this with the more specific PDK_SET_SYSCLOCK(...) macro from pdk/sysclock.h
  
    PDK_SET_SYSCLOCK(SYSCLOCK_ILRC_DIV4);

  // Insert placeholder code to tell EasyPdkProg to calibrate the IHRC or ILRC internal oscillator.
  // The AUTO_CALIBRATE_SYSCLOCK(...) macro uses F_CPU (defined in the Makefile) to choose the IHRC or ILRC oscillator.
  // Alternatively, replace this with the more specific EASY_PDK_CALIBRATE_IHRC(...) or EASY_PDK_CALIBRATE_ILRC(...) macro from easy-pdk/calibrate.h
  
    EASY_PDK_CALIBRATE_ILRC(17000,3000);

  return 0;   // Return 0 to inform SDCC to continue with normal initialization.
}

Compiling was fine and oh so nice to have 2k available instead of the 1k ATTiny13 (although I am still keen to learn Padauk assembler and make this a bit smaller).

$> make program
sdcc -mpdk14 -c --std-sdcc11 --opt-code-size -DPFS154 -DF_CPU=1000000 -DTARGET_VDD_MV=3000 -I. -I../include -o .build/main.rel main.c
sdcc -mpdk14 --out-fmt-ihx -o .output/FadeLED_PFS154.ihx .build/main.rel .build/lib.lib
makebin -p .output/FadeLED_PFS154.ihx .output/FadeLED_PFS154.bin
---------- Segments ----------
.  .ABS.                            00000000    00000000 =           0. bytes (ABS,CON)
.  .ABS.                            00000000    00000000 =           0. bytes (ABS,CON)
HEADER1                             00000000    00000002 =           2. bytes (ABS,CON)
HEADER3                             00000000    00000010 =          16. bytes (ABS,CON)
PREG2                               00000000    00000002 =           2. bytes (ABS,CON)
RSEG0                               00000000    00000002 =           2. bytes (ABS,CON)
DATA                                00000002    00000047 =          71. bytes (REL,CON)
HOME                                00000022    00000002 =           2. bytes (REL,CON)
GSINIT                              00000024    0000006C =         108. bytes (REL,CON)
SSEG                                0000004C    00000001 =           1. bytes (REL,CON)
GSFINAL                             00000090    00000002 =           2. bytes (REL,CON)
CODE                                00000092    000003E6 =         998. bytes (REL,CON)
------------------------------
Size of FadeLED_PFS154.bin: 1144 bytes
easypdkprog -i noblankchk -n PFS154 write .output/FadeLED_PFS154.ihx
Erasing IC... done.
Writing IC (572 words)... done.
Calibrating IC
* ILRC SYSCLK=17000Hz @ 3.00V ... calibration result: 16436Hz (0xF0)  done.

Left to do? Basically I want to keep on "Edisoning" this thing as follows:

a) Change the code to wind back the power of the ramping (e.g. instead of changing PWM from 40 to 220, try 30 to 160 or similar)

b) Upscale the super-caps. At the moment I'm getting around 4 hours of light - I think 6-8 hours is a reasonable goal.

c) Change some or all of the code from C to Assembler. This could be very scary given that assembler programming (which I love) is a pretty good path to madness.

d) Any suggestions??

Here's the video - enjoy!



Friday, October 7, 2022

0000 0000 1010 1010

Mailbag #22

Into the bottom of the world funnels some lovely goodness from 中国.

Ignore the ludicrous attempt to run a 24V probe from a 5V supply. It was late. 😬

Christmas and Father's Day everyday down here - don't tell anyone.  

  • 🤫 


 

Saturday, October 1, 2022

0000 0000 1010 1001

Three for the price of one!

I follow PCBWay on Twitter (@PCBWayOfficial), in part because they follow and support me (@peckmaths)!

A few months ago I saw the following piece of information floating down the information superhighway on one of their posts:


Taste The Code (https://www.tastethecode.com/) had designed an extra tasty Arduino Uno shield that allowed piggybacking of three ATTiny85 chips for simultaneous programming.

It's seemed like an intriguing idea which I'd only seen before in nature.

I ordered the PCB (PCBWay made it easy to order from their site) by following the links and instructions on the blog, and soon had the boards in my hands.

Normally I would do a mailbag video when a package arrives, and then come back to the PCB at some later stage, but these boards looked so nice I wanted to jump straight in and see if it worked.

It was a very straight forward process to solder up the board with a ZIF socket and a couple of other bits and pieces.

There was a bit of crowding on the back of the shield (see possums above), but in the end the board worked fine and the video below shows both ATTiny85s and also ATTiny13s able to be programmed up fine, three at a time! That's a win for me and definitely a win for Taste The Code.



Friday, September 23, 2022

0000 0000 1010 1000

Cooking up a PCB

I have used a cheap oven to reflow solder before, but I was curious if I could use a simple hotplate to attach annoyingly small SMD components to a simple PCB.

Despite the appalling application of solder paste it seemed to work OK!

I do not store my solder paste in a fridge, but full disclosure I do live in a fridge known as Tasmania, so the paste did what it was supposed to do after some heat tickling.

A proper person would do the whole solder temperature ramp profile adherence - but this was a quick and dirty test of the temp rating of the hotplate and also a "proof of concept" experiment should I wish to take this method any further.


If you are looking to do SMD soldering the easy way, including ham-fisted solder paste application - check out this video!



Thursday, September 15, 2022

0000 0000 1010 0111

Mailbag #21

Lovely packages arriving in "downtown Tasmania" including some laser modules. Or as my finance minister says "Why?!"


Saturday, September 10, 2022

0000 0000 1010 0110

A commercial Solar Light

I was clumping through a common staff area the other day and spotted a solar light (with a PIR) for sale through some charity. 

The packet claimed that the unit didn't need electricity, batteries or wires! Free energy?? 

It was only $12 (a great deal cheaper than similar units found in the shops) and I was intrigued to find out what was inside. I suspected that a battery was in there, and I was hoping for a QX5252 based (or similar) circuit whereby I could point and say "Oh, I understand that!"

It was not "to be (or not to be)" as the video below shows - there were surprises...


Saturday, September 3, 2022

0000 0000 1010 0101

D2822 1W Amplifier

There's an IC called a TDA2822 typically rated to drive speakers at around 3W. It's been around so long that on many sites it is listed as obsolete!

It's even used in a few cheap amplifiers available online for very few dollars.


Nonetheless, there is also a facsimile of the chip (I think) to be found called the D2822. It has a separate but similar datasheet - topping out around 1W and also touted for headphones and similar cheap amplifier applications. The pinouts for both chips seem to be the same.

I used the circuit shown in the datasheet and the pinout given as well to make an audio amplifier as follows.

At first I tried rubbish little speakers which were suitably horrible, but then I grabbed a couple of recycled speakers and the sound was actually quite remarkable coming from a tiny little 8-pin "obsolete" chip that barely gets warm as it cranks out the phat beats.

The video is a little loud in places (sorry!) as I have a new phone and keep hitting "volume up" instead of  "volume down" and vice versa!