Saturday, October 26, 2024

0000 0000 1111 0110

The last impossible thing

I've been working in the background on replacing the NiMH battery in the candle project with a supercapacitor. It's been quite the journey and at times I definitely did not believe that it would ever happen.

There is a great benefit when you are a mad pioneer in being ignorant of what is conventionally regarded as not possible, so I just assumed in my usual trial and error, and error, and error method of experimentation that the problem would eventually be solved.

Three impossible things needed to happen for this project to be completed:

1. A supercapacitor needed to be able to run a microcontroller (just ticking over anaemically at a very low clock rate) for a useful amount of time (e.g. overnight) - done

2. A microcontroller (e.g. the PADAUK PFS154) needed to be able to detect when it was night time just from the charge profile of a capacitor - done

3. A circuit designed to have at it's heart a NiMH battery would need to be fooled and use a collection of passives instead

The final result needs more polishing, but all three miracles have occurred and now the candle project will be re-imagined as a supercapacitor project. Done?

Magic!




Sunday, October 13, 2024

0000 0000 1111 0101

Mailbag #44 - some nice modules

The usual responsible grab-bag of goodies from AliExpress - including some great little modules.

The ESP32-S3 (dual core) which may be pressed into service as a toddler clock (!), and a CH32X035F8 module with some impressive stats!

Enjoy!




Monday, October 7, 2024

0000 0000 1111 0100

CH32v003 Serial and SWIO Communication Clash

The SOP8 version of the CH32v003 is pretty amazing, and one "feature" is the ability to remap many functions/protocols to the same pins.

This is fine up to the point where there might be a clash. For instance, just look how busy pin 8 is - overloaded including the function that allows it to be programmed and reprogrammed (the one-wire SWIO "single wire" protocol) that for some reason is on the same pin as serial TX.

So...what if you have engaged serial communication AND want to reprogram the chip?

Disaster! But, there are a few ways I have found to get around the problem.

1. Use the minichlink program as we saw in a previous blog and video.
2. Only open up Serial when you need it, and then the chances of interrupting the program to "reprogram" are increased (dodgy I know)
3. Use a mysterious function on a mysterious piece of software to somehow use the one-wire protocol to "printf" from pin 8.

4. Re-map the pins! (see below)
5. Buy the version with more pins you cheapskate!

Now the deep deep deep dive into pin re-allocation took me through many websites, forums and configurations files, but here is what you need to do:

a) find the files PeripheralPins.c and variant_CH32V003F4.h in the core directory as follows:

b) Make the following config file edits to re-map the pins:

1. in the file PeripheralPins.c

//*** UART ***
#ifdef UART_MODULE_ENABLED
WEAK const PinMap PinMap_UART_TX[] = {
  {PD_6, USART1, CH_PIN_DATA(CH_MODE_OUTPUT_50MHz, CH_CNF_OUTPUT_AFPP, 0, AFIO_NONE)}, // from PD_5
  {NC,   NP,     0}
};
#endif

#ifdef UART_MODULE_ENABLED
WEAK const PinMap PinMap_UART_RX[] = {
  {PC_1, USART1, CH_PIN_DATA(CH_MODE_INPUT, CH_CNF_INPUT_PUPD, PULLUP, AFIO_NONE)}, // from PD_6
  {NC,    NP,     0}
};
#endif

2. in the file variant_CH32V003F4.h

// UART Definitions
#ifndef SERIAL_UART_INSTANCE
  #define SERIAL_UART_INSTANCE  1
#endif
// Default pin used for generic 'Serial' instance
// Mandatory for Firmata
#ifndef PIN_SERIAL_RX
  #define PIN_SERIAL_RX         PC1 // from PD6
#endif
#ifndef PIN_SERIAL_TX
  #define PIN_SERIAL_TX         PD6 // from PD5
#endif

c) add the following lines to your setup() code in your Arduino IDE sketch:

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_USART1 | RCC_APB2Periph_AFIO, ENABLE);
  GPIO_PinRemapConfig(GPIO_PartialRemap2_USART1, ENABLE);
  Serial.begin(115200);

Full code:

#define ledpin PC4
int counter = 0;

void setup() {
  pinMode(ledpin, OUTPUT);
  // Must enable clock for AFIO
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_USART1 | RCC_APB2Periph_AFIO, ENABLE);
  GPIO_PinRemapConfig(GPIO_PartialRemap2_USART1, ENABLE);
  Serial.begin(115200);
}

void loop() {
  digitalWrite(ledpin, HIGH);
  delay(80);
  counter++;
  digitalWrite(ledpin, LOW);
  delay(300);
  Serial.print("blink ");
  Serial.println(counter);
}

After that the only "gotcha" is to remember to switch the connections as follows:

Then you can reprogram at your leisure and enjoy serial communication as well. Speaking of enjoyment, please see the video below and let me know if any of these workarounds did the trick for you as well.



Saturday, September 28, 2024

0000 0000 1111 0011

AO3400 Super Transistor!

Looking to power a fan to keep an Orange Pi 3B cool inside it's enclosure, I turned to a "power" mosfet I hadn't worked with before, the super little guy AO3400.

Rated to 30V and a fanciful 5.8A it seemed to be perfect for the job because it could "open the gate" at around 1.1V.

I designed a suitable circuit, soldered the little bits together on a SOP8 to DIP8 adapter (!!) as per below:

The design seemed to work for an LED circuit, so I boxed it up and ran it from the 5V rail of the OPi 3B.

See the result below. Please add comments on YT below the video, especially if you have a view on fan orientation!



Saturday, September 21, 2024

0000 0000 1111 0010

Mailbag #43 - many nice parcels!

Here we are at 43 and so many lovely parcels flowing in - including some incredible chips that play around with voltage like they were born to do it!

If you would like to build the circuits for the MAX1044 check out the datasheet.

Enjoy the video!




Monday, September 9, 2024

0000 0000 1111 0001

Un-bricking the CH32v003

Newbies with cool tech like me are prone to "bricking" chips which basically means you can't program the things anymore.

Different chips react differently in these circumstances. Once upon a time I invested in a High Voltage AVR Programmer for reviving ATTiny85 chips that I had unwittingly fried with poor code. And it worked a treat!


The CH32v003 peeps in their wisdom have fortunately included in their one-wire communication protocol the ability to reset and therefore un-brick a chip.

There's a little VCC dancing to make it happen, but...well, take a look...



Thursday, September 5, 2024

0000 0000 1111 0000

Pimped OPi 3B

I've had great success with the Orange Pi range over the years. I will say that I've always bought the cheap(est) option and even now I'm not sure if I'd take the plunge on an OPi 5 with all the fruit - that's a lot of dollarydoos

In the meantime I have an OPi 3 LTS chugging away in the background on both PiHole duties as well as a Media Server - and it works great!

But recently I grabbed hold of the holy money belt and shook like crazy to purchase the following pack of goodies.

I think that this machine might end up being the new NAS and Pi-hole combo. The first thing to do is roll-my-own Armbian. I did start off with a community version of Ubuntu, which booted fine, but I had trouble copying the system over to the EMMC module - so roll your own Armbian it is!

The addition of a 1Tb NVME solid state drive should give a few options for video and music streaming - time will tell. It's my impression from reading that you could use this fast SSD option to preload or buffer video and audio from a larger HDD and thus smooth out some rough edges that occasionally appear.

Here are the stats on this little beauty - I still think it's cheap for the power and the potential, a nice mix of stats and options making it one of the more versatile units in this range.

And the video? I've tried to show the whole process from unpacking to running the desktop on the device.

Click below:



Friday, August 30, 2024

0000 0000 1110 1111

More CH32v003

Straight after playing around with the CH32v003 as a SOP-20 on a module in the last video, I saw a plea from the #socials about running a SOP-8 version on a breadboard.

So I soldered up a little beast and started to play!

Here are your links:

https://github.com/openwch/arduino_core_ch32

https://wchofficialstore.aliexpress.com/store/1100367542

...and here's your "blinky" (and "fadey") goodness via the video. 

 


Enjoy, and please leave a comment on YouTube if you thought it was useful.


Sunday, August 4, 2024

0000 0000 1110 1110

A monster mailbag - with RPi5 and CH32v003

I got a little carried away with this one - but if you want to configure a Raspberry Pi 5 from scratch, or talk to the CH32v003, then this long long video might just be what you need.

Grab a tea, coffee or other libation and settle in for a procession of treats from AliExpress (and one annoying local offering).

Oh and if you want to 3D print the breadboard jumper maker: click this link.




Thursday, July 25, 2024

0000 0000 1110 1101

Audiophiles look away now

In the 1970s an uncle of mine spent t-h-o-u-s-a-n-d-s of dollars on audio equipment. High end speakers, valve amplifiers, turntables, tape decks, etc., etc.

I was in awe, and the sound was so amazing as to be akin to a religious experience. He was so into it that he paid for an audio engineer to come in and "ping" his lounge room so that the speakers could be precisely placed in the exact spots to eliminate any dead zones.

Of course his wife shifted them that afternoon due to her interior design concerns. They are not married anymore - coincidence?

Fast forward to 2024 and his nephew (that's me!) has just bought a TDA7297 based amplifier from AliExpress coming in at the princely sum of AU$2.57. Embarrassing - and even more so because it doesn't seem to work.

Or does it?

Also, a colleague at work handed over some ear pod thingies that weren't going the distance in terms of charging - I have no idea what to do to help, and there is now video evidence of that fact!



Friday, July 19, 2024

0000 0000 1110 1100

Mailbag #41 - Droning on and a noisy dog

This is an unusual mailbag in that in amongst some electronics there is the odd drone accessory.

We don't know why.  Enjoy!



Tuesday, July 16, 2024

0000 0000 1110 1011

Primed for discovery

This is not electronics but a weird combination of coding and mathematics! Young children look away now.

Some time ago I thought it might be useful to look for patterns in primes because, well, it's like a mountain to climb! If it's there then you gotta do it.

Also there has been a LOT of work done in this field before.

Here's some light reading:

https://www.nature.com/articles/nature.2016.19550

https://www.scirp.org/journal/paperinformation?paperid=74345

https://www.youtube.com/watch?v=EK32jo7i5LQ

So during a lull in my holidays (?), and after attending a math conference recently, I decided to start a coding journey that examines the position of primes in geometric patterns for both squares and hexagons.

Here's the square version:

from math import sqrt
from turtle import *

xrow = 10
ycol = 11
count = 2
squaresize = 4

tracer(False)
speed("fastest")

pendown()

def isPrime(n):
    for i in range(2,int(n**0.5)+1):
        if n%i==0:
            return False
    return True

def makesq():
    forward(squaresize)
    right(90)
    forward(squaresize)
    right(90)
    forward(squaresize)
    right(90)
    forward(squaresize)
    right(90)
    forward(squaresize)
    return    

def turn():
    right(90)
    forward(squaresize)
    return    

fillcolor("red")

begin_fill()
makesq() # 1 is not prime
end_fill()

fillcolor("blue")

while(count < 25000):
    for laying in range(1,xrow):
        if(isPrime(count)):
            begin_fill()
        makesq()
        end_fill()
        count = count + 1
    turn()
    for laying in range(1,ycol):
        if(isPrime(count)):
            begin_fill()
        makesq()
        end_fill()
        count = count + 1
    turn()
    xrow=xrow+1
    ycol=ycol+1

update()

And here is the more interesting hexagon version.

from math import sqrt
from turtle import *
import os
from turtle import Screen, Turtle

height = 900
width = 900
screen = Screen()
screen.setup(width, height)

short = 1

global count
count = 1
hexsize = 10

turnarray = [4,3,3,3,3,2,3]

#tracer(False)
speed("fastest")

pendown()

def isPrime(n):
    for i in range(2,int(n**0.5)+1):
        if n%i==0:
            return False
    return True

def makehex(sides):
    for making in range(0,sides):
        forward(hexsize)
        right(60)
    return    

fillcolor("red")

begin_fill()
makehex(6) # 1 is not prime
end_fill()
makehex(2) # 1 is not prime
left(120)
count = count + 1

fillcolor("blue")

def turn():
    global count
    if(isPrime(count)):
        begin_fill()
    makehex(6)
    end_fill()
    makehex(3)
    left(120)
    count = count + 1
    return

def straight(numhex):
    global count
    for length in range(0,numhex):
        if(isPrime(count)):
            begin_fill()
        makehex(6)
        end_fill()
        makehex(2)
        left(120)
        count = count + 1
    return

while(count < 9):
    if(isPrime(count)):
        begin_fill()
    makehex(6)
    end_fill()
    makehex(turnarray[count-2])
    left(120)
    count = count + 1

for layer in range(1,65):
    for sides in range(0,4):
        turn()
        straight(layer)
    turn()
    straight(layer+1)
    turn()
    straight(layer)


update()

Now I'm keen to "fold" the shapes and have a look at the 3D possibilities - anyone with me?



 

Monday, July 15, 2024

0000 0000 1110 1010

All night long

The next phase of the NiMH replacement project is to test if a Super Capacitor can power a PFS154 through the night - pumping out candley goodness via it's three PWM channels.

Since the last video and blog I have continued to work on the code - a subscriber picked up a SNAFU from the last video, and as well I am not yet convinced that the PFS154 is sleeping.

Here's the video - suggestions welcome!



Thursday, June 20, 2024

0000 0000 1110 1001

The third impossible thing (first)

I have an idea to move the candle project from a AA NiMH rechargeable battery to a supercapacitor. There are issues!

In previous incarnations of this dream/nightmare  (one and two) I failed due to not being able to drive the candle for more than a few hours overnight - and charging was an issue. The QX5252 outputs 1.3V and the supercap I'm experimenting with is rated 3.8V.

So I've set myself three impossible things to solve for this project to be supercap based:

a) "Boost" the voltage output of the QX5252 to match the supercap
b) Figure out a way to extend the overnight life of the candle
c) Work out some way of making the PFS154 (missing an ADC) pretend it's got an ADC and can therefore react to voltage changes (ideally via interrupts)

Working backwards on these issues (why not?) I have been torturing a PFS154 on the breadboard, trying out a weird internal comparator feeding an interrupt signal to turn on...why an LED of course!

Enjoy the journey - next in line is the second impossible thing - extending the life of the supercap for overnight light.

Late Mail! Due to an online suggestion via the comments section underneath the video below, here is the updated code which is working well! Thank you to @ivolol


/*
    "Alice laughed: "There's no use trying," she said; "one can't believe
    impossible things." "I daresay you haven't had much practice," said the Queen.
    "When I was younger, I always did it for half an hour a day. Why, sometimes
    I've believed as many as six impossible things before breakfast."
                                                                    Lewis Carroll

    This particular impossible thing is a PFS154 sleeping "stopsys()" and being
    woken up by the comparator which is using PA3 as the negative input and the
    internal reference voltage as the positive input.

    Also impossible?
    F_CPU = 10000 (that's Hz!)

  PFS154 pinout
                      +-\/-+
                VDD  1|    |8  GND
             PA7/X1  2|    |7  PA0/AD10/CO/INT0/PG0PWM
             PA6/X2  3|    |6  PA4/AD9/CIN+/CIN1-/INT1/PG1PWM
   PA5/PRSTB/PG2PWM  4|    |5  PA3/AD8/CIN0-/TM2PWM/PG2PWM
                      +----+

  Mon 03 Jun 2024 22:05:27 AEST

  https://www.youtube.com/c/onecircuit-as
  https://onecircuit.blogspot.com/

*/

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

bool sunshine = false; // is the sun shining?

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

// this is where the candle code will go - for now, turn on LED
void candlingon() {
  PAC = 0b00010000;
  PA = 0b00010000;
}

// here is where the uC goes to sleep
void sleepnow() {

  __disgint();  // disable global interrupts

  PA = 0b00000000; // turn off LED

  MISC |= MISC_FAST_WAKEUP_ENABLE;  // fast wakeup

  INTEN = 0b00010000;  // enable comparator interrupt
  INTRQ = 0b00010000; 

  __engint();   // enable global interrupts
  __stopsys();  // go to sleep
}

void main() {

  // PA4 is output, all GPIOs low
  PAC = 0b00010000;
  PA = 0b00000000;


  // page 66 datasheet
  GPCC = 0b10000000;
  // bit 7 enable comparator
  // bit 6 plus input < minus input
  // bit 5 result output NOT sampled by TM2_CLK
  // bit 4 polarity is NOT inversed
  // bit 3-1 000 : PA3 selected as -ve input
  // bit 0 internal voltage set as +ve input

  GPCS = 0b10000110;
  // bit 7 output to PA0 disabled
  // bit 6 reserved
  // bit 5 high range selected
  // bit 4 low range selected
  // bit 3-0 Selection the internal reference voltage level of comparator 
  // 0000 (lowest) ~ 1111 (highest) as a fraction of vdd

  _delay_ms(20);  // small settle time delay


  while (1) {

    _delay_ms(200);  // small loop delay
    sunshine = (bool)checksolar(); // check the sunshine

    if (!sunshine) {
      candlingon();  // it's dark, start candling action
    }
    else
    {
      sleepnow();    // it's light, go to sleep
    }
  }
}

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

  AUTO_INIT_SYSCLOCK();
  AUTO_CALIBRATE_SYSCLOCK(TARGET_VDD_MV);

  return 0;
}



Saturday, June 15, 2024

0000 0000 1110 1000

Mailbag #40 - solid generosity

There's generosity and then there's Steve. He contacted me a couple of months ago and asked if I'd like an old oscilloscope he wasn't using - plus a few other things.

Well the oscilloscope is lovely and the "few other things" turned out to be a treasure trove. Steve you little beauty!

Enjoy the riches:  




Saturday, May 18, 2024

0000 0000 1110 0111

Mailbag #39 - including RISC-V

A lovely collection of items from AliExpress - in particular the CH32V203 20 pin microcontrollers from Nanjing Qinheng Microelectronics.

Check out the video below, and leave a like and comment if it floats yer boat!



Thursday, April 25, 2024

0000 0000 1110 0110

SOP8 WARS!

Recently Atul Ravi of PICUNO fame asked me why I "switched" from ATtiny13 to the PFS154. I haven't really - in fact the ATtiny13 is still near and dear to my heart, not least because I spent six months writing assembly code snippets for this little microcomputer. You can read all about it by clicking on this link.

However, I do use the PFS154 for the candle project (among others) for the following reasons:

  • Exotic new tech interests me
  • Lower power requirements
  • "Free" programmer (which cost me months of pain)
  • Three PWM channels, versus two
  • Ability to wind down the voltage and current requirements by running the IC as low as 15kHz!
  • Challenging to learn a new toolchain

In the great comparison, here is what ChatGPT had to say (usual caveats apply):

It's not all beer and skittles though, and one missing feature that rankled was the lack of an analogue to digital converter (ADC) on the PFS154. I mean - why!? It's such a basic requirement to take an analogue signal (e.g. distance from object using an ultrasonic signal).

Anyway, I'm not bitter at all.

And so enter stage left the previously shelved PFS173, on the bench at 14 cents each from LCSC ordered in June 2020 (now discontinued for some reason).

Originally I just wanted to talk to it (e.g. blinky), but in the end not only did I get some PWM action, but also the ADC - this in itself is interesting as to date I have not seen any code available for linking ADC to PWM on this chip. See for instance the github site for examples for these chips:

I do have one embarrassing admission despite the win. My final code does not use interrupts but rather gallops along around 100kHz and checks every single time it loops for the ADC conversion, and the "time" for the LED to blink. It's positively neanderthal, but nonetheless effective.

I will aim to find out more about the PFS173 interrupt landscape and update this travesty in the future. In the meantime, here is the code for the blink and PWM version.

/*
  Test Code for PFS173 Blink and PWM

                      +-\/-+
                VDD  1|    |8  GND
             PA7/X1  2|    |7  PA0/AD10/CO/INT0/PG0PWM
             PA6/X2  3|    |6  PA4/AD9/CIN+/CIN1-/INT1/PG1PWM
   PA5/PRSTB/PG2PWM  4|    |5  PA3/AD8/CIN0-/TM2PWM/PG2PWM
                      +----+

  Tue 23 Apr 2024 17:35:37 AES

  https://www.youtube.com/c/onecircuit-as
  https://onecircuit.blogspot.com/

*/

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

#define LED4_BIT 4 // PWM
#define LED3_BIT 3 // Blinky

#define turnLedOn()   PA &= ~(1 << LED3_BIT)
#define turnLedOff()  PA |= (1 << LED3_BIT)

bool ledon = true;

// crude timing for blinky
long mytimer = 30;
volatile long counter = 0;

// PFS173 PWM
#define PWM_MAX               255

// check in here to see if LED is on or off
void checkled() {

  counter = counter + 1;
  if (counter > mytimer) {
    counter = 0;
    if (ledon) {
      turnLedOff();
      ledon = false;
    }
    else {
      turnLedOn();
      ledon = true;
    }
  }
}

// Main program
void main() {

  // Initialize hardware
  PAC |= (1 << LED4_BIT); 
  PAC |= (1 << LED3_BIT);

  PWMGCUBL = PWM_MAX << 5;   // Set the PWM upper bound (lower 3 bits)
  PWMGCUBH = PWM_MAX >> 3;   // (upper 5 bits)
  PWMG1DTL = 0x00;           // Clear the LED PWM duty value
  PWMG1DTH = 0x00;
  PWMGCLK = (uint8_t)(PWMGCLK_PWMG_ENABLE | PWMGCLK_CLK_IHRC);
  PWMG1C = (uint8_t)(PWMG1C_INVERT_OUT | PWMG1C_OUT_PWMG1 | PWMG1C_OUT_PA4);

  ledon = false;

  // Main loop
  while (1) {
  
  uint8_t fadeValue;

    // Fade in from min to max in increments of 5
    for (fadeValue = 0; fadeValue < PWM_MAX; fadeValue += 5) {

      PWMG1DTL = fadeValue << 5;  // Set the LED PWM duty value (lower 3 bits)
      PWMG1DTH = fadeValue >> 3;  // (upper 8 bits)
      _delay_ms(30);              // wait for 30 milliseconds to see the dimming effect
      checkled();
    }

    // Fade out from max to min in increments of 5
    for (fadeValue = PWM_MAX; fadeValue > 0; fadeValue -= 5) {

      PWMG1DTL = fadeValue << 5;  // Set the LED PWM duty value (lower 3 bits)
      PWMG1DTH = fadeValue >> 3;  // (upper 8 bits)
      _delay_ms(30);              // wait for 30 milliseconds to see the dimming effect
      checkled();
    }
  }
}

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

  AUTO_INIT_SYSCLOCK();
  AUTO_CALIBRATE_SYSCLOCK(TARGET_VDD_MV);

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

And here is the code which does Blink and ADC linked to PWM (a triumph!):

/*
  Test Code for PFS173 ADC and PWM

                      +-\/-+
                VDD  1|    |8  GND
             PA7/X1  2|    |7  PA0/AD10/CO/INT0/PG0PWM
             PA6/X2  3|    |6  PA4/AD9/CIN+/CIN1-/INT1/PG1PWM
   PA5/PRSTB/PG2PWM  4|    |5  PA3/AD8/CIN0-/TM2PWM/PG2PWM
                      +----+

  Wed 24 Apr 2024 22:38:05 AEST

  https://www.youtube.com/c/onecircuit-as
  https://onecircuit.blogspot.com/

*/

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

#define LED4_BIT 4 // PWM
#define LED3_BIT 3 // Blinky
#define LED0_BIT 0 // ADC


#define turnLedOn()   PA &= ~(1 << LED3_BIT)
#define turnLedOff()  PA |= (1 << LED3_BIT)

bool ledon = true;

// crude timing for blinky
long mytimer = 45;
volatile long counter = 0;

volatile int PWM_MAX = 255; // will be set by ADC

// check in here to see if LED is on or off
void checkled() {

  counter = counter + 1;
  if (counter > mytimer) {
    counter = 0;
    if (ledon) {
      turnLedOff();
      ledon = false;
    }
    else {
      turnLedOn();
      ledon = true;
    }
  }
}

// Main program
void main() {

  // Initialize hardware
  PAC |= (1 << LED4_BIT); 
  PAC |= (1 << LED3_BIT);
  PAC |= (0 << LED0_BIT);

  // setup ADC
  PAPH |= (0 << LED0_BIT);
  PADIER |= (0 << LED0_BIT);
  ADCRGC = 0; // VDD is ref
  ADCC = ADCC_ADC_ENABLE | ADCC_CH_AD10_PA0; //enable ADC and use channel 10 (PA0)

  // setup PWM
  PWMGCUBL = PWM_MAX << 5;   // Set the PWM upper bound (lower 3 bits)
  PWMGCUBH = PWM_MAX >> 3;   // (upper 5 bits)
  PWMG1DTL = 0x00;           // Clear the LED PWM duty value
  PWMG1DTH = 0x00;
  PWMGCLK = (uint8_t)(PWMGCLK_PWMG_ENABLE | PWMGCLK_CLK_IHRC);
  PWMG1C = (uint8_t)(PWMG1C_INVERT_OUT | PWMG1C_OUT_PWMG1 | PWMG1C_OUT_PA4);

  ledon = false;

  // Main loop
  while (1) {
  
  ADCC |= ADCC_ADC_CONV_START;  //start ADC conversion
  while( !(ADCC & ADCC_ADC_CONV_COMPLETE) );  
  PWM_MAX = ADCR;               //read the ADC value
  PWMG1DTL = PWM_MAX << 5;      // Set the LED PWM duty value (lower 3 bits)
  PWMG1DTH = PWM_MAX >> 3;      // (upper 8 bits)
  _delay_ms(20);                // little delay for checkled           
  checkled();   
  }
}

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

  AUTO_INIT_SYSCLOCK();
  AUTO_CALIBRATE_SYSCLOCK(TARGET_VDD_MV);

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

Both of these are in a folder as "main.c" with a Makefile that looks like this:

DEVICE = PFS173
F_CPU = 100000
TARGET_VDD_MV = 5000
TARGET_VDD = 5.0

# ---------------------------------------------------------------------

OUTPUT_NAME = BlinkLED_$(DEVICE)

include ../arch-from-device.mk

ROOT_DIR = ..
BUILD_DIR = .build
OUTPUT_DIR = .output

OUTPUT = $(OUTPUT_DIR)/$(OUTPUT_NAME)

SOURCES = main.c
OBJECTS = $(patsubst %.c,$(BUILD_DIR)/%.rel,$(SOURCES))

# http://sdcc.sourceforge.net/doc/sdccman.pdf
COMPILE = sdcc -m$(ARCH) -c --std-sdcc11 --opt-code-size -D$(DEVICE) -DF_CPU=$(F_CPU) -DTARGET_VDD_MV=$(TARGET_VDD_MV) -I. -I$(ROOT_DIR)/include
LINK = sdcc -m$(ARCH)
EASYPDKPROG = easypdkprog

# symbolic targets:
all: size

print-%: ; @echo $* = $($*)

$(BUILD_DIR)/%.rel: %.c
	@mkdir -p $(dir $@)
	$(COMPILE) -o $@ $<

$(OUTPUT).ihx: $(OBJECTS)
	@mkdir -p $(dir $(OUTPUT))
	$(LINK) --out-fmt-ihx -o $(OUTPUT).ihx $(OBJECTS)

$(OUTPUT).bin: $(OUTPUT).ihx
	makebin -p $(OUTPUT).ihx $(OUTPUT).bin

build: $(OUTPUT).bin

size: build
	@echo '---------- Segments ----------'
	@egrep '(ABS,CON)|(REL,CON)' $(OUTPUT).map | gawk --non-decimal-data '{dec = sprintf("%d","0x" $$2); print dec " " $$0}' | /usr/bin/sort -n -k1 | cut -f2- -d' '
	@echo '------------------------------'
	@stat -L --printf "Size of $(OUTPUT_NAME).bin: %s bytes\n" $(OUTPUT).bin

program: size
	$(EASYPDKPROG) -n $(DEVICE) write $(OUTPUT).ihx

run:
	$(EASYPDKPROG) -r $(TARGET_VDD) start

clean:
	rm -r -f $(BUILD_DIR) $(OUTPUT_DIR)

Finally, here is all the blinky, PWM and ADC action that you could possible need as SSOP8 wars comes to a bench near you.