From c3657fff2fe3f98d118bb4cd260f80f1c99b10a5 Mon Sep 17 00:00:00 2001 From: Michael Ruppe <73618042+CoreProduction@users.noreply.github.com> Date: Tue, 7 Feb 2023 13:31:48 +1100 Subject: [PATCH 1/3] v20 code candidate with updated examples --- .../Firmware-PiicoDev-Buzzer.ino | 32 +++++++++---------- Firmware-PiicoDev-Buzzer/commands.ino | 13 +++----- PiicoDev_Buzzer.py | 17 +++++++--- examples/melody.py | 31 +++++++++--------- examples/software_address.py | 11 +++++++ main.py | 7 ++-- 6 files changed, 63 insertions(+), 48 deletions(-) create mode 100644 examples/software_address.py diff --git a/Firmware-PiicoDev-Buzzer/Firmware-PiicoDev-Buzzer.ino b/Firmware-PiicoDev-Buzzer/Firmware-PiicoDev-Buzzer.ino index 14298a8..1d78af8 100644 --- a/Firmware-PiicoDev-Buzzer/Firmware-PiicoDev-Buzzer.ino +++ b/Firmware-PiicoDev-Buzzer/Firmware-PiicoDev-Buzzer.ino @@ -1,12 +1,16 @@ /* - * PiicoDev 3x RGB LED Module Firmware + * PiicoDev Buzzer Module Firmware * Written by Michael Ruppe @ Core Electronics * Based off the Qwiic Button Project https://github.com/sparkfun/Qwiic_Button - * Date: NOV 2021 - * An I2C based LED module that allows control of 3x GlowBit (WS2812) LEDs + * Date: FEB 2023 + * An I2C based buzzer module that allows tone and timing control * * Feel like supporting PiicoDev? Buy a module here: https://core-electronics.com.au/catalog/product/view/sku/CE07910 * + * Changes in v2.0 + * The new v20 hardware has a louder buzzer and does not support volume control. Volume funcitons are still provisioned here but do nothing. + * Pinout has changed significantly to facilitate routing the v20 hardware. + * * Changes in v1.1 * Default address is now not shared with other smart modules * hardware address switches select from the same shared pool of addresses for smart modules @@ -20,8 +24,8 @@ #include // For sleep_mode #include // For powering-down peripherals such as ADC and Timers -#define FIRMWARE_MAJOR 0x01 -#define FIRMWARE_MINOR 0x01 +#define FIRMWARE_MAJOR 0x02 +#define FIRMWARE_MINOR 0x00 #define DEVICE_ID 0x51 #define DEFAULT_I2C_ADDRESS 0x5C // The default address when all switches are off @@ -38,16 +42,14 @@ enum eepromLocations { uint8_t oldAddress; // Hardware Connectins -#if defined(__AVR_ATtiny806__) || defined(__AVR_ATtiny816__) || defined(__AVR_ATtiny1606__) || defined(__AVR_ATtiny1616__) -const uint8_t powerLedPin = PIN_PC2; -const uint16_t buzzerPins[] = {PIN_PA3, PIN_PA1, PIN_PA2}; // In ascending order of loudness -const uint16_t buzzerCommon = PIN_PA4; // provision for push-pull drive. Unused for now... +#if defined(__AVR_ATtiny806__) || defined(__AVR_ATtiny816__) || defined(__AVR_ATtiny1606__) || defined(__AVR_ATtiny1616__) || defined(__AVR_ATtiny3217__) +const uint8_t powerLedPin = PIN_PA3; uint16_t buzzerPin = PIN_PA2; -const uint8_t addressPin1 = PIN_PA7; -const uint8_t addressPin2 = PIN_PB5; -const uint8_t addressPin3 = PIN_PA5; -const uint8_t addressPin4 = PIN_PB2; +const uint8_t addressPin1 = PIN_PA6; +const uint8_t addressPin2 = PIN_PA7; +const uint8_t addressPin3 = PIN_PB5; +const uint8_t addressPin4 = PIN_PB4; #endif // Prototyping with Arduino Uno @@ -105,7 +107,7 @@ const memoryMap registerMap = { .i2cAddress = 0x04, .tone = 0x05, .volume = 0x06, - .led = 0x07, + .led = 0x07 }; volatile memoryMap valueMap = { @@ -155,8 +157,6 @@ void setup() { Serial.println("Begin"); #endif - pinMode(buzzerCommon, OUTPUT); digitalWrite(buzzerCommon, LOW); - // Pull up address pins pinMode(addressPin1, INPUT_PULLUP); pinMode(addressPin2, INPUT_PULLUP); diff --git a/Firmware-PiicoDev-Buzzer/commands.ino b/Firmware-PiicoDev-Buzzer/commands.ino index b9d8dcd..9ea417b 100644 --- a/Firmware-PiicoDev-Buzzer/commands.ino +++ b/Firmware-PiicoDev-Buzzer/commands.ino @@ -24,18 +24,13 @@ void playTone(uint16_t frequency, uint16_t duration) { } void setVolume(char *data) { - uint8_t vol = data[0]; - if (vol >=0 && vol < COUNT_OF(buzzerPins)) volume(uint8_t(data[0])); + // This function is deprecated in v2.0 firmware + return; } void volume(uint8_t vol) { - // Reset all buzzer pins - for (uint8_t i = 0; i < COUNT_OF(buzzerPins); i++) { - pinMode(buzzerPins[i], INPUT); - } - // Select the desired pin to use - buzzerPin = buzzerPins[vol]; - pinMode(buzzerPin, OUTPUT); + // This function is deprecated in v2.0 firmware + return; } diff --git a/PiicoDev_Buzzer.py b/PiicoDev_Buzzer.py index 5329591..5a155e2 100644 --- a/PiicoDev_Buzzer.py +++ b/PiicoDev_Buzzer.py @@ -22,10 +22,12 @@ def noTone(self): r=self.tone(0); return r def volume(self, vol): - _v = int(vol); assert _v >=0 and _v <=2,"volume must be 0, 1 or 2" - v = vol.to_bytes(1,'big') + if self.whoami[0] != 1: + print("Warning: Volume not implemented on this hardware revision") + return + assert vol in [0,1,2],"volume must be 0, 1 or 2" try: - self.i2c.writeto_mem(self.addr, _regVolume, v) + self.i2c.writeto_mem(self.addr, _regVolume, vol.to_bytes(1,'big')) sleep_ms(5); return 0 except: print(i2c_err_str.format(self.addr)); return 1 @@ -45,8 +47,12 @@ def readFirmware(self): try: v[1]=self.i2c.readfrom_mem(self.addr, _regFirmMaj, 1) v[0]=self.i2c.readfrom_mem(self.addr, _regFirmMin, 1) - return (v[1],v[0]) + return (int.from_bytes(v[1],'big'), int.from_bytes(v[0],'big')) except: return(0,0) + + @property + def whoami(self): + return self.readFirmware() def readStatus(self): sts=self.i2c.readfrom_mem(self.addr, _regStatus,1) @@ -72,7 +78,8 @@ def __init__(self, bus=None, freq=None, sda=None, scl=None, addr=_baseAddr, id=N except Exception as e: print(i2c_err_str.format(self.addr)) raise e - self.volume(volume) + if self.whoami[0] < 2: # volume deprecated in v20 design + self.volume(volume) # TODO: Check device ID - seems to timeout on Raspberry Pi (clock stretching not implemented) # try: # if self.readID() != _DevID: diff --git a/examples/melody.py b/examples/melody.py index 1e06d9e..844e5f1 100644 --- a/examples/melody.py +++ b/examples/melody.py @@ -4,30 +4,31 @@ from PiicoDev_Unified import sleep_ms # Define some note-frequency pairs -notes = {'C4':262, - 'Db':277, - 'D' :294, - 'Eb':311, - 'E' :330, - 'F' :349, - 'Gb':370, - 'G' :392, - 'Ab':415, - 'A' :440, - 'Bb':466, - 'B' :494, - 'C5':523, +octave = 2 +notes = {'C' : octave * 262, + 'Db' : octave * 277, + 'D' : octave * 294, + 'Eb' : octave * 311, + 'E' : octave * 330, + 'F' : octave * 349, + 'Gb' : octave * 370, + 'G' : octave * 392, + 'Ab' : octave * 415, + 'A' : octave * 440, + 'Bb' : octave * 466, + 'B' : octave * 494, + 'Chi': octave * 523, 'rest':0, # zero Hertz is the same as no tone at all } # define a melody - two-dimensional list of notes and note-duration (ms) melody = [['E', 500], ['D', 500], - ['C4', 500], + ['C', 500], ['rest', 500], ['E', 500], ['D', 500], - ['C4', 500], + ['C', 500], ['rest', 500], ['G', 500], ['F', 250], diff --git a/examples/software_address.py b/examples/software_address.py new file mode 100644 index 0000000..bd7d551 --- /dev/null +++ b/examples/software_address.py @@ -0,0 +1,11 @@ +# PiicoDev Buzzer example. Set a software address +# requires all ID switches to be OFF + +from PiicoDev_Buzzer import PiicoDev_Buzzer +from PiicoDev_Unified import sleep_ms + +buzz = PiicoDev_Buzzer() +buzz.setI2Caddr(0x64) + +buzz.tone(800, 500) +sleep_ms(500) diff --git a/main.py b/main.py index 46f951d..b5488f7 100644 --- a/main.py +++ b/main.py @@ -1,18 +1,19 @@ -# PiicoDev Buzzer example. Play tones and change the volume. +# PiicoDev Buzzer example. Play simple tones from PiicoDev_Buzzer import PiicoDev_Buzzer from PiicoDev_Unified import sleep_ms -buzz = PiicoDev_Buzzer(volume=2) # volume may be 0, 1 or 2 (loudest) +buzz = PiicoDev_Buzzer() +# Play tones for a set duration buzz.tone(800, 500) # high tone (800Hz for 500ms) sleep_ms(500) buzz.tone(400, 500) # low tone (400Hz for 500ms) sleep_ms(1500) -buzz.volume(0) # low volume +# Play tones and stop them manually buzz.tone(800) # high tone - continuous sleep_ms(500) buzz.noTone() # stop playing From 4ccdee87cbbc559dd6bd363e7f240ef21dff185b Mon Sep 17 00:00:00 2001 From: Michael Ruppe <73618042+CoreProduction@users.noreply.github.com> Date: Mon, 3 Apr 2023 16:38:39 +1000 Subject: [PATCH 2/3] v20 candidate with self-test function --- .../Firmware-PiicoDev-Buzzer.ino | 10 +++- Firmware-PiicoDev-Buzzer/commands.ino | 54 +++++++++++++++++++ 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/Firmware-PiicoDev-Buzzer/Firmware-PiicoDev-Buzzer.ino b/Firmware-PiicoDev-Buzzer/Firmware-PiicoDev-Buzzer.ino index 1d78af8..e79142a 100644 --- a/Firmware-PiicoDev-Buzzer/Firmware-PiicoDev-Buzzer.ino +++ b/Firmware-PiicoDev-Buzzer/Firmware-PiicoDev-Buzzer.ino @@ -10,6 +10,7 @@ * Changes in v2.0 * The new v20 hardware has a louder buzzer and does not support volume control. Volume funcitons are still provisioned here but do nothing. * Pinout has changed significantly to facilitate routing the v20 hardware. + * There is also a self-test utility that checks address pins are not shorted together during PCBA * * Changes in v1.1 * Default address is now not shared with other smart modules @@ -96,6 +97,7 @@ struct memoryMap { uint16_t tone; uint8_t volume; uint8_t led; + uint8_t selfTestResult; }; // Register addresses. @@ -107,7 +109,8 @@ const memoryMap registerMap = { .i2cAddress = 0x04, .tone = 0x05, .volume = 0x06, - .led = 0x07 + .led = 0x07, + .selfTestResult = 0x09 }; volatile memoryMap valueMap = { @@ -118,7 +121,8 @@ volatile memoryMap valueMap = { .i2cAddress = DEFAULT_I2C_ADDRESS, .tone = 0x00, .volume = 0x00, - .led = 0x01 + .led = 0x01, + .selfTestResult = 0x00 }; uint8_t currentRegisterNumber; @@ -136,6 +140,7 @@ void setAddress(char *data); void setTone(char *data); void setVolume(char *data); void setPowerLed(char *data); +void getSelfTest(char *data); functionMap functions[] = { {registerMap.id, idReturn}, @@ -146,6 +151,7 @@ functionMap functions[] = { {registerMap.tone, setTone}, {registerMap.volume, setVolume}, {registerMap.led, setPowerLed}, + {registerMap.selfTestResult, getSelfTest}, }; diff --git a/Firmware-PiicoDev-Buzzer/commands.ino b/Firmware-PiicoDev-Buzzer/commands.ino index 9ea417b..354194e 100644 --- a/Firmware-PiicoDev-Buzzer/commands.ino +++ b/Firmware-PiicoDev-Buzzer/commands.ino @@ -84,6 +84,60 @@ void setAddress(char *data) { } +void getSelfTest(char *data) { + runSelfTest(); + loadArray(valueMap.selfTestResult); +} + +void runSelfTest(void){ + const bool FAIL = false; + const bool PASS = true; + bool state = PASS; + + // Check for shorts between address pins + uint8_t numPins = 4; + uint16_t pins[] = {addressPin1, addressPin2, addressPin3, addressPin4}; + + // Set all pins as input with pullup + for (uint8_t i=0; i Date: Mon, 3 Apr 2023 16:50:34 +1000 Subject: [PATCH 3/3] add self test to python API --- PiicoDev_Buzzer.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/PiicoDev_Buzzer.py b/PiicoDev_Buzzer.py index 5a155e2..09e4103 100644 --- a/PiicoDev_Buzzer.py +++ b/PiicoDev_Buzzer.py @@ -9,6 +9,7 @@ _regTone=0x05 _regVolume=0x06 _regLED=0x07 +_regSelfTest = 0x09 class PiicoDev_Buzzer(object): def tone(self, freq, dur=0): @@ -53,6 +54,12 @@ def readFirmware(self): @property def whoami(self): return self.readFirmware() + + @property + def self_test(self): + """Returns the result of the self-test""" + result = self.i2c.readfrom_mem(self.addr, _regSelfTest, 1) + return int.from_bytes(result,'big') def readStatus(self): sts=self.i2c.readfrom_mem(self.addr, _regStatus,1) @@ -65,7 +72,7 @@ def readID(self): def pwrLED(self, x): try: self.i2c.writeto_mem(self.addr, _regLED, bytes([x])); return 0 except: print(i2c_err_str.format(self.addr)); return 1 - + def __init__(self, bus=None, freq=None, sda=None, scl=None, addr=_baseAddr, id=None, volume=2): self.i2c = create_unified_i2c(bus=bus, freq=freq, sda=sda, scl=scl) a=addr