Saturday, August 29, 2020

0000 0000 0011 1110

LM358 Single Rail OpAmp Square Wave Oscillator

Slightly obsessed with the idea of a square wave oscillator as a timer, I have found many circuits which use an OpAmp to generate a square wave. Having tried a few, I settled on the LM358 datasheet version (p. 17, Figure 27) as follows.

There's a nice explanation of the theory and calculations for this type of circuit found on this site. Rather than the values for R1 etc,. shown in the datasheet, however, I used the following slight variation.



The changes were made mainly so that I could vary the oscillations (R4), and also I added an LED because if it's not blinking then it's not really electronics...


Here it is "in the flesh", and the video contains the all important blinking stuff.





Saturday, August 22, 2020

0000 0000 0011 1101

FreePDK Padauk Programmer - Part Two

On the last blog I wrote about the torturous road taken in soldering up an open source PCB designed (reverse engineered) to program the most intriguing Padauk microcontrollers.

After tens of hours of tears, sweat and the odd expletive - the fourth version I attempted actually worked. So now I take a closer look at the programming of these little chips.


It's worth noting that the toolchain for the factory supported IDE is entirely different to the open source version, and at this stage it seems you must choose one or the other.

With that in mind, I firstly installed dfu-util, and using the following code was able to successfully install the programming firmware onto the STM32 as per the instructions.

dfu-util -d 0483:df11 -a "@Internal Flash  /0x08000000/064*0002Kg" \
   --dfuse-address 0x08000000 -D EASYPDKPROG.dfu

   dfu-util 0.9
   ...
   Opening DFU capable USB device...
   ID 0483:df11
   Run-time device DFU version 011a
   Claiming USB DFU Interface...
   Setting Alternate Setting #0 ...
   Determining device status: state = dfuERROR, status = 10
   dfuERROR, clearing status
   Determining device status: state = dfuIDLE, status = 0
   dfuIDLE, continuing
   DFU mode device DFU version 011a
   Device returned transfer size 2048
   DfuSe interface name: "Internal Flash  "
   Downloading to address = 0x08000000, size = 29068
   Download  [=========================] 100%        29068 bytes
   Download done.
   File downloaded successfully

All went smoothly and so next it was a tough choice to select the first guinea pig IC. I think that of all the Padauk chips that I have ordered, the one showing the most potential for the types of projects that I like to get involved with is the PFS154-S08 available from LCSC.

Into the cradle went the chip and then I wanted a simple method of checking if the programming side of things worked. The obvious choice was of course a blinking LED - the "Hello World" of microcontroller programming.

/*
  BlinkLEDs

  Flicks on and off two LEDs attached to PA4 and PA3 of the PFS154-S08 chip.
  Uses a timing loop for delays.

*/

#include <pdk/device.h>
#include "auto_sysclock.h"
#include "delay.h"

// LEDs are placed on the PA3 and PA4 pins
#define LED1 4
#define LED2 3

// LED is active low (current sink), so define helpers for better readability below
#define turnGLedOn()   PA &= ~(1 << LED1)
#define turnGLedOff()  PA |= (1 << LED1)
#define turnBLedOn()   PA &= ~(1 << LED2)
#define turnBLedOff()  PA |= (1 << LED2)

// Main program
void main() {

  // Initialize hardware
  PAC |= (1 << LED1);          // Set LED as output (all pins are input by default)
  PAC |= (1 << LED2);          // Set LED as output (all pins are input by default)
  turnGLedOff();
  turnBLedOff();

  // Main processing loop
  while (1) {
    turnGLedOn();
    _delay_ms(250);
    turnGLedOff();
    _delay_ms(250);
    turnBLedOn();
    _delay_ms(250);
    turnBLedOff();
    _delay_ms(250);
  }
}

// Startup code
unsigned char _sdcc_external_startup(void) {
  AUTO_INIT_SYSCLOCK();
  AUTO_CALIBRATE_SYSCLOCK(TARGET_VDD_MV);
  return 0;
}

---------------

make clean program
rm -r -f .build .output
sdcc -mpdk14 -c --std-sdcc11 --opt-code-size -DPFS154 -DF_CPU=1000000 -DTARGET_VDD_MV=4000 -I. -I../include -o .build/main.rel main.c
sdar -rc .build/lib.lib 
sdcc -mpdk14 --out-fmt-ihx -o .output/BlinkLED_PFS154.ihx .build/main.rel .build/lib.lib
makebin -p .output/BlinkLED_PFS154.ihx .output/BlinkLED_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    00000007 =           7. bytes (REL,CON)
HOME                                00000022    00000002 =           2. bytes (REL,CON)
GSINIT                              00000024    00000014 =          20. bytes (REL,CON)
GSFINAL                             00000038    00000002 =           2. bytes (REL,CON)
CODE                                0000003A    00000094 =         148. bytes (REL,CON)
SSEG                                FFFFFFFF    00000001 =           1. bytes (REL,CON)
------------------------------
Size of BlinkLED_PFS154.bin: 206 bytes
easypdkprog -n PFS154 write .output/BlinkLED_PFS154.ihx
Erasing IC... done.
Writing IC (103 words)... done.
Calibrating IC
* IHRC SYSCLK=1000000Hz @ 4.00V ... calibration result: 999229Hz (0x7D)  done.


Nervously I transferred the programmed chip to a breadboard set up with the requisite connections and LEDs, turned on the power and was overjoyed to be greeted with blinking as required.


The next journey is to look at how this code works, then hopefully a repetition of the code in assembler. Looking ahead I would like to replace the ATTiny13 in the candle project with my own home grown Padauk assembler code. That should keep me a bit busy.

Thank you EEVBlog community, PCBWay and all those subscribers to the channel for your support, advice, encouragement and good will.



Saturday, August 15, 2020

0000 0000 0011 1100

FreePDK Padauk Programmer - Part One

A journey of 1000 miles begins with one step. Around a year ago I became aware that Dave Jones of EEVBlog fame was singing the praises of a technically capable but obscure microcontroller available for around 3 cents each in bulk. 

Who wouldn't want a capable microcontroller for just a few cents? The downsides of procuring this chip for use by your average home hobbyist include:

  1. Non-English datasheets (slowly starting to change)
  2. No way to program them (unless you want to buy an expensive - almost bespoke - programmer)
  3. "Interesting" IDE
  4. Non-standard language
  5. Little or no online support
But that didn't stop the EEVBlog community from reverse engineering the programmer and making a PCB that is capable of transferring the required binary sequences and getting a result from these chips. The work has been amazing and about 6 months ago I decided to have a go at making one of these open source wonders.


After the usual 2020 difficulties with freight and supply I found myself in the garage at the bench with the requisite bits and pieces and a hot soldering iron. Thank you to PCBWay who manufactured and sent the PCBs all the way to Tasmania to be melted by my incompetence.

Several swearing hours later I had a mostly fused PCB that at best might be useful for shoehorning a recalcitrant foot into a tiny boot - but way short of the digital magic required to unlock an inscrutable chip!



If MKI was a mess, then MKII was even worse! Fried components, mountains of congealed flux, ripped tracks and general mayhem ensued BUT I was able to connect and program the firmware onto the STM32F072C8T6 chip. This small success was great timing because at that stage I was ready to abandon the project and admit defeat.


I've never solved a problem by giving up, and now with a sniff of success I spent a careful week, an hour here and there, putting together MKIII - which....did not work at all!


The dreaded USB connector seemed OK (after a few tries), but who knows in among that mess if any connections are actually in place - certainly the voltage checks I did seem to point to an entirely different circuit!

So with a heavy heart I reluctantly started the MKIV version. Was this going to be another waste of time? Careful soldering, careful checking and many hours later I plugged it in - and...nothing!

In the depths of despair I had a sudden flash of inspiration (or desperation) and desoldered the STM32 from the failed (but talkative) MKII board and swapped it in on the MKIV board. Hilariously I blew several components together with the hot air gun (and melted some plastic) which took a bit of sorting out.


But...success! I now have a working opensource free-pdk.github.io PCB that can load the firmware, recognise a Padauk chip AND program it to blink like a champion. What a journey. In the next blog I'll look at the programming side of this circus, er...circuit.



 

Saturday, August 8, 2020

0000 0000 0011 1011

LM386N-4 Amplifier

Earlier on this blog and the associated YouTube channel I made an amplifier based on the remarkable LM386 OpAmp. The circuit was from this website, the prototype worked great, and I was inspired to design a PCB based on this success using EasyEDA. Then the project languished for a few months while I did some other stuff (Ibid.)




Then, for some reason I can't quite fathom, PCBWay reached out and requested to sponsor some of my work. The amplifier PCB came screaming off the "bench" and into the game and a few weeks later some bright shiny PCBs appeared. The build quality was great, even if there was an obvious shortcoming with my design!

Middle space too small - Crowded House Music?

So the actual PCB works fine, and the build is a very simple and fast one. The music is non-copyright and the end result is quite pleasing - thanks PCBWay!



Saturday, August 1, 2020

0000 0000 0011 1010

Monster Mailbag (Part Two)


Only for the dedicated, here is part two of the "Monster Mailbag". Feedback welcome!

Next week I return to making stuff, in this case an LM386 amplifier with a bit of blog history - and a new partnership as well.





Saturday, July 25, 2020

0000 0000 0011 1001

Tripping the light - fantastic!


After some gentle (?) banter regarding the size and number of buckets of electronics about the place, it was suggested to me by a long time collaborator that the door at the bottom of the staircase into the garage could use some incidental lighting (e.g. before the main lights at the wall are flicked on).

A normal person presumably would go to a hardware store and spend $20 and 15 minutes to fix the problem. Clearly I'm not normal, and so I started a project which could either be labelled:
  1. Lighting the garage upon detecting a human presence, or
  2. Justification (in part) for the many buckets of electronics clogging up the place
The first order of business was planning the physical elements of the project (see video) and then a quick (and dirty) circuit diagram showing the relevant parts orchestrated to achieve the desired outcome.


At the heart of the project is an ATTiny13 (of course) which is asleep. If the door from the stairwell is opened then a hall effect sensor is tripped and the μC wakes up and brings up the LED strip via a transistor. Alternatively from the opposite direction if a warm humanoid stands in front of a PIR then the μC also trips and provides light. I've chosen components that use very little current and so overall the circuit consumes around 500μA when "asleep".


AM312 Mini-PIR at ~15μA

Hall Effect sensor at ~1μA

Voltage regulator at ~1μA 

I then mocked up a prototype, wrote some code and soldered up the "PCB of Goodness".



// -----------------------------------------------------------------
// Description: A strip of Leds connected to a transistor controlled
// by an Attiny13. The μC sleeps most of the time, but is interrupted
// by a PIR on PCINT1, or a Hall Effect sensor on PCINT2. It will then
// light the leds, hold for a bit and and then fade out.
//
// Author: OneCircuit      Date: Thursday 16 July 11:48:26 AEST 2020
// www.onecircuit.blogspot.com
// www.youtube.com/channel/UCTm3eCrN6wk-Ozt9ymyKIIg
// -----------------------------------------------------------------
//
// ATMEL ATTINY13 μC
//
//                                   +-\/-+
//  RESET--ACD0--5/A0--PCINT5--PB5  1|    |8  VCC
//   CLKI--ACD3--3/A3--PCINT3--PB3  2|    |7  PB2--PCINT2--2/A1--SCK--ADC1
//         ACD2--4/A2--PCINT4--PB4  3|    |6  PB1--PCINT1---1---MISO--OCOB--INT0*
//                             GND  4|    |5  PB0--PCINT0---0---MOSI--OCOA*
//                                   +----+
//  * indicates PWM port
//

#include <avr/pgmspace.h>            // for reading the progmem values
#include <avr/interrupt.h>           // for interrupt routines
#include <avr/sleep.h>               // the sleep routines

#define StripLED PB0                 // pwm pin
#define HEPin PCINT2                 // Magnetic interrupt pin
#define PIRPin PCINT1                // PIR interrupt pin

volatile boolean triggered = false;  // boolean for keeping track of interrupts

// The led strip will fade exponentially to compensate for human perception,
// which is not linear. You can calculate as a curve, but float values will blow
// the little Attiny13 out of the water, so a lookup table in progmem makes more
// sense for saving memory.

const uint8_t PROGMEM gamma8[] = {
  0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4,
  5, 5, 6, 6, 7, 8, 8, 9, 9, 10, 11, 11, 12, 13, 14, 14, 15,
  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
  30, 31, 32, 34, 35, 36, 37, 39, 40, 41, 43, 44, 46, 47,
  48, 50, 51, 53, 54, 56, 58, 59, 61, 63, 64, 66, 68, 69,
  71, 73, 75, 77, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96,
  98, 100, 102, 105, 107, 109, 111, 113, 116, 118, 120,
  123, 125, 127, 130, 132, 134, 137, 139, 142, 144, 147,
  150, 152, 155, 157, 160, 163, 165, 168, 171, 174, 176,
  179, 182, 185, 188, 191, 194, 197, 200, 203, 206, 209,
  212, 215, 218, 221, 224, 227, 230, 234, 237, 240, 243, 247, 250
};

void slowfade(boolean fadein) {

  if (fadein) {
    for (uint8_t lighting = 0; lighting < 150; lighting++) {    // 150 steps
      analogWrite(StripLED, pgm_read_byte(&gamma8[lighting]));  // read from the lookup table
      delay(6);                                                 // increase for a slower fade
    }
  }
  else {
    for (uint8_t lighting = 150; lighting > 0; lighting--) {    // count backwards
      analogWrite(StripLED, pgm_read_byte(&gamma8[lighting]));  // from the lookup table
      delay(80);                                                // increase for a slower fade
    }
  }
}

void powerDown(void)
{
  GIMSK |= (1 << PCIE);                   // activate Pin change interrupts
  PCMSK |= ((1 << HEPin)|(1 << PIRPin));  // sets the Pin change interrupt mask
  ADCSRA &= ~(1 << ADEN);                 // turn off ADC
  ACSR |= (1 << ACD);                     // turn off Analog comparator.
  sei();                                  // enable global interrupts
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);    // sleep deeply little one
  sleep_enable();                         // enable sleep mode
  sleep_mode();                           // system sleeps here

  sleep_disable();                        // ISR routine returns here so wake up
  GIMSK &= ~(1 << PCIE);                  // deactivate Pin change interrupts
  ADCSRA |= (1 << ADEN);                  // turn on ADC
  ACSR = (0 << ACD);                      // turn on Analog comparator.
  delay(100);                             // settle time after waking up
  
}

ISR(PCINT0_vect)
{
  triggered = true;
}

void setup ()
{
  pinMode(HEPin, INPUT_PULLUP);    // configure interrupt pin as input
  pinMode(PIRPin, INPUT_PULLUP);   // configure interrupt pin as input
  pinMode(StripLED, INPUT);        // LED pin input to start

}  // end of setup

void loop () {
  if (!triggered) {
    powerDown(); // call the function that sleeps
  }
  else {
    pinMode(StripLED, OUTPUT);    // LED pin is now output
    slowfade(true);               // fade in
    delay(60000);                 // hold that thought for 1 minute
    slowfade(false);              // fade out
    pinMode (StripLED, INPUT);    // configure transistor pin as input, saves power
    delay(1000);                  // one second before re-trigger
    triggered = false;            // reset boolean
  }
}  // end of code

Finally after testing the new device was installed and currently it lights up when either the door is swung open, or a human is detected via PIR. Mission 1 outlined above - accomplished. Mission 2 - ongoing...



Saturday, July 18, 2020

0000 0000 0011 1000

Monster Mailbag (Part One)


After very little action in the mailbox for weeks (thanks "Pandemania"), and after going away for a week on holidays on our world-wide tour of Tasmania - the postbox was uncharacteristically bursting with mail upon return!

It seems that the freight lines from China are back in action - or maybe the local lines are unclogged after lockdown, but either way we are seeing some items ordered back in March suddenly arriving. I have stopped instigating disputes in AliExpress on the assumption that most stuff will turn up at some time - hopefully before I forget what I was thinking when I pressed the big red "ORDER" button! 

Here is the list of items covered in the video:


There were way too many packages for one video, so here is "Part One" and I'll post the second part in a couple of weeks.