diff --git a/Firmware-PiicoDev-Buzzer/Firmware-PiicoDev-Buzzer.ino b/Firmware-PiicoDev-Buzzer/Firmware-PiicoDev-Buzzer.ino index 14298a8..e79142a 100644 --- a/Firmware-PiicoDev-Buzzer/Firmware-PiicoDev-Buzzer.ino +++ b/Firmware-PiicoDev-Buzzer/Firmware-PiicoDev-Buzzer.ino @@ -1,12 +1,17 @@ /* - * 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. + * 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 * hardware address switches select from the same shared pool of addresses for smart modules @@ -20,8 +25,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 +43,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 @@ -94,6 +97,7 @@ struct memoryMap { uint16_t tone; uint8_t volume; uint8_t led; + uint8_t selfTestResult; }; // Register addresses. @@ -106,6 +110,7 @@ const memoryMap registerMap = { .tone = 0x05, .volume = 0x06, .led = 0x07, + .selfTestResult = 0x09 }; volatile memoryMap valueMap = { @@ -116,7 +121,8 @@ volatile memoryMap valueMap = { .i2cAddress = DEFAULT_I2C_ADDRESS, .tone = 0x00, .volume = 0x00, - .led = 0x01 + .led = 0x01, + .selfTestResult = 0x00 }; uint8_t currentRegisterNumber; @@ -134,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}, @@ -144,6 +151,7 @@ functionMap functions[] = { {registerMap.tone, setTone}, {registerMap.volume, setVolume}, {registerMap.led, setPowerLed}, + {registerMap.selfTestResult, getSelfTest}, }; @@ -155,8 +163,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..354194e 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; } @@ -89,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=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 +48,18 @@ 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() + + @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) @@ -59,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 @@ -72,7 +85,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