From 593a81ca1ef0588598a2277aece165ed01abf52f Mon Sep 17 00:00:00 2001 From: Stuart Pittaway <1201909+stuartpittaway@users.noreply.github.com> Date: Wed, 24 Feb 2021 12:57:50 +0000 Subject: [PATCH] Support for V440 module hardware --- ATTINYCellModule/include/defines.h | 2 +- ATTINYCellModule/include/diybms_attiny841.h | 72 +++++++++++++++----- ATTINYCellModule/platformio.ini | 28 +++++++- ATTINYCellModule/src/diybms_attiny841.cpp | 75 +++++++++++++++------ ATTINYCellModule/src/main.cpp | 49 ++++++-------- 5 files changed, 159 insertions(+), 67 deletions(-) diff --git a/ATTINYCellModule/include/defines.h b/ATTINYCellModule/include/defines.h index eaeaed3..416dc6b 100644 --- a/ATTINYCellModule/include/defines.h +++ b/ATTINYCellModule/include/defines.h @@ -22,7 +22,7 @@ Attribution-NonCommercial-ShareAlike 2.0 UK: England & Wales (CC BY-NC-SA 2.0 UK #error You need to specify the DIYBMSMODULEVERSION define #endif -#if defined(DIYBMSMODULEVERSION) && DIYBMSMODULEVERSION > 430 +#if defined(DIYBMSMODULEVERSION) && DIYBMSMODULEVERSION > 440 #error Incorrect value for DIYBMSMODULEVERSION #endif diff --git a/ATTINYCellModule/include/diybms_attiny841.h b/ATTINYCellModule/include/diybms_attiny841.h index 63dfe38..52a0901 100644 --- a/ATTINYCellModule/include/diybms_attiny841.h +++ b/ATTINYCellModule/include/diybms_attiny841.h @@ -32,7 +32,6 @@ class DiyBMSATTiny841 //Switch OFF Bit 1 – OCIE1A: Timer/Counter, Output Compare A Match Interrupt Enable TIMSK1 &= (~_BV(OCIE1A)); } - static void StartTimer1() { //Normal port operation, OC1A/OC1B disconnected @@ -50,7 +49,7 @@ class DiyBMSATTiny841 // Prescaler 8Mhz/64 = 125000 counts per second, call ISR 1000 times per second // Prescaler 2Mhz/64 = 31250 counts per second, call ISR 1000 times per second - roughly, as rounding error of 31.25 - OCR1A = (F_CPU/64)/1000; + OCR1A = (F_CPU / 64) / 1000; ResumePWM(); } @@ -61,14 +60,39 @@ class DiyBMSATTiny841 DumpLoadOff(); } + static void SetPrescaler() + { + //Boot up will be in 1Mhz CKDIV8 mode, swap to /4 to change speed to 2Mhz + byte oldSREG = SREG; + cli(); + /*atomic code, as its time sensitive*/; + //CCP – Configuration Change Protection Register + CCP = 0xD8; + //CLKPR – Clock Prescale Register + CLKPR = _BV(CLKPS1); + SREG = oldSREG; + } + static void DumpLoadOn() { +#if defined(DIYBMSMODULEVERSION) && DIYBMSMODULEVERSION < 440 + //Pre 4.4 board PORTA |= _BV(PORTA3); +#else + //4.4 board + PORTB |= _BV(PORTB2); +#endif } static void DumpLoadOff() { +#if defined(DIYBMSMODULEVERSION) && DIYBMSMODULEVERSION < 440 + //Pre 4.4 board PORTA &= (~_BV(PORTA3)); +#else + //4.4 board + PORTB &= (~_BV(PORTB2)); +#endif } static void ReferenceVoltageOn() @@ -83,17 +107,17 @@ class DiyBMSATTiny841 PORTA &= (~_BV(PORTA7)); } - static void GreenLedOn() + static void NotificationLedOn() { PORTA |= _BV(PORTA6); } - static void GreenLedOff() + static void NotificationLedOff() { PORTA &= (~_BV(PORTA6)); } -#if defined(DIYBMSMODULEVERSION) && DIYBMSMODULEVERSION < 430 +#if defined(DIYBMSMODULEVERSION) && DIYBMSMODULEVERSION < 440 static void SparePinOn() { PORTB |= _BV(PORTB1); @@ -105,7 +129,7 @@ class DiyBMSATTiny841 } #endif -#if defined(DIYBMSMODULEVERSION) && DIYBMSMODULEVERSION < 430 +#if defined(DIYBMSMODULEVERSION) && DIYBMSMODULEVERSION < 440 static void BlueLedOn() { PORTA |= _BV(PORTA5); @@ -179,10 +203,23 @@ class DiyBMSATTiny841 static void SelectCellVoltageChannel() { +#if defined(DIYBMSMODULEVERSION) && DIYBMSMODULEVERSION < 440 + //Pre 4.4 board //PB2 = ADC8 PIN 5 ARDUINO PIN 2/A8 = VOLTAGE reading //ADMUXA – ADC Multiplexer Selection Register A //ADC8 (single end) MUX[5:0] 00 1000 - ADMUXA = (0 << MUX5) | (0 << MUX4) | (1 << MUX3) | (0 << MUX2) | (0 << MUX1) | (0 << MUX0); + //ADMUXA = (0 << MUX5) | (0 << MUX4) | (1 << MUX3) | (0 << MUX2) | (0 << MUX1) | (0 << MUX0); + ADMUXA = B00001000; + +#else + //4.4 board + + //PA3 = ADC3 PIN 10 = VOLTAGE READING + //See Page 144 in the datasheet for information + //ADMUXA = (0 << MUX5) | (0 << MUX4) | (0 << MUX3) | (0 << MUX2) | (1 << MUX1) | (1 << MUX0); + ADMUXA = B00000011; + +#endif } static void SelectInternalTemperatureChannel() @@ -190,25 +227,28 @@ class DiyBMSATTiny841 //PA4 //ADMUXA – ADC Multiplexer Selection Register A //ADC4 (single end) MUX[5:0] 00 0100 - ADMUXA = (0 << MUX5) | (0 << MUX4) | (0 << MUX3) | (1 << MUX2) | (0 << MUX1) | (0 << MUX0); + //ADMUXA = (0 << MUX5) | (0 << MUX4) | (0 << MUX3) | (1 << MUX2) | (0 << MUX1) | (0 << MUX0); + ADMUXA = B00000100; } static void SelectExternalTemperatureChannel() { - //External sensor - //ADMUXA – ADC Multiplexer Selection Register A +//External sensor +//ADMUXA – ADC Multiplexer Selection Register A -#if defined(DIYBMSMODULEVERSION) && DIYBMSMODULEVERSION < 430 +#if defined(DIYBMSMODULEVERSION) && DIYBMSMODULEVERSION < 440 //ADC11 (single end) MUX[5:0] 00 1011 - ADMUXA = (0 << MUX5) | (0 << MUX4) | (1 << MUX3) | (0 << MUX2) | (1 << MUX1) | (1 << MUX0); + //ADMUXA = (0 << MUX5) | (0 << MUX4) | (1 << MUX3) | (0 << MUX2) | (1 << MUX1) | (1 << MUX0); + ADMUXA = B00001011; #else - //V4.3 boards ADC5 (single end) MUX[5:0] 00 0101 - ADMUXA = (0 << MUX5) | (0 << MUX4) | (0 << MUX3) | (1 << MUX2) | (0 << MUX1) | (1 << MUX0); + //V4.4 boards ADC5 (single end) MUX[5:0] 00 0101 + //ADMUXA = (0 << MUX5) | (0 << MUX4) | (0 << MUX3) | (1 << MUX2) | (0 << MUX1) | (1 << MUX0); + ADMUXA = B00000101; #endif } - static void double_tap_green_led(); -#if defined(DIYBMSMODULEVERSION) && DIYBMSMODULEVERSION < 430 + static void double_tap_Notification_led(); +#if defined(DIYBMSMODULEVERSION) && DIYBMSMODULEVERSION < 440 static void double_tap_blue_led(); #endif }; diff --git a/ATTINYCellModule/platformio.ini b/ATTINYCellModule/platformio.ini index 25cb28e..86f59ad 100644 --- a/ATTINYCellModule/platformio.ini +++ b/ATTINYCellModule/platformio.ini @@ -28,7 +28,7 @@ ; [Blue LED removed, resetable fuse fitted] ;** DO NOT FLASH V430 TO AN OLDER BOARD - THE ATTINY WILL BECOME UNUSABLE ** [platformio] -default_envs = V400, V410, V420, V420_SWAPR19R20, V421, V421_LTO +default_envs = V400, V410, V420, V420_SWAPR19R20, V421, V421_LTO, V440 description=DIYBMS Cell monitoring module code [env] @@ -61,7 +61,7 @@ upload_flags = -Pusb -Ulfuse:w:0b01100010:m -Uhfuse:w:0b11010110:m - -Uefuse:w:0b11110100:m + -Uefuse:w:0b11110100:m [env:V400] ; 8 balance resistors marked 2R2 @@ -88,3 +88,27 @@ build_flags=-DDIYBMSMODULEVERSION=421 -DMV_PER_ADC=2.00 -DINT_BCOEFFICIENT=4050 ;Round PCB with bolt hole. 10 balance resistors marked 6.2OHM ;Uses resistor divider circuit of 18.2K/13K ohms = 1.24V output for 3.00V input build_flags=-DDIYBMSMODULEVERSION=421 -DMV_PER_ADC=1.00 -DINT_BCOEFFICIENT=3950 -DEXT_BCOEFFICIENT=3950 -DLOAD_RESISTANCE=2.48 -DBAUD=2400 + +[env:V440] +;DIYBMS V4.40 - DO NOT USE THIS SETTING WITH OLDER BOARDS THEY +; WILL BE RENDERED USELESS (CLOCK FUSE CHANGES) +;Almost completely different pin mapping compared to previous modules +;Single LED and external crystal (8Mhz), has breakaway thermistor sub pcb board +;Has fuse and TVS diode on inputs and uses AZ432ANTR-E1 voltage reference +;PA0/PA6/PA4/PA7 are same purpose as previous boards +;PB2 = DUMP LOAD ENABLE, PA3 = VOLTAGE ADC, PA5 = EXT THERMISTOR ADC +;BLUE LED DOES NOT EXIST ON V440 (Well it does, but the green has been replaced with blue!) +build_flags=-DDIYBMSMODULEVERSION=440 -DMV_PER_ADC=2.00 -DINT_BCOEFFICIENT=3950 -DEXT_BCOEFFICIENT=3950 -DLOAD_RESISTANCE=3.30 -DBAUD=2400 +; Fuses E:F4, H:D6, L:62 +; lfuse = 0110 0010 = CKDIV8 (enabled) & Calibrated Internal 8MHz Oscillator +; hfuse = 1101 0110 = EESAVE & 1.8V BOD detection level +; efuse = 1111 0100 = Enables SPM instruction +board_fuses.lfuse = 0b01101100 +board_fuses.hfuse = 0b11010110 +board_fuses.efuse = 0b11110100 +;-B16 option needed for my USBASP programmer to slow it down! +upload_flags = + -Pusb + -Ulfuse:w:0b01101100:m + -Uhfuse:w:0b11010110:m + -Uefuse:w:0b11110100:m diff --git a/ATTINYCellModule/src/diybms_attiny841.cpp b/ATTINYCellModule/src/diybms_attiny841.cpp index e2711a9..4366be9 100644 --- a/ATTINYCellModule/src/diybms_attiny841.cpp +++ b/ATTINYCellModule/src/diybms_attiny841.cpp @@ -38,7 +38,7 @@ FOR MODULE VERSION 400,410,420,421.... PA3 = DUMP LOAD ENABLE / PIN 10 / ARDUINO PIN 7/A3 / TOCC2 PA4 = ADC4 PIN 9 ARDUINO PIN 6/A4 = ON BOARD TEMP sensor PA5 = SERIAL PORT 1 TXD1 - NOT USED (BLUE LED ON =430) - PA6 = GREEN_LED / PIN 7 / ARDUINO PIN 4/A6 + PA6 = Notification LED / PIN 7 / ARDUINO PIN 4/A6 PA7 = ADC7 = PIN 6 = ARDUINO PIN 3/A7 = 2.048V REFERENCE ENABLE PB2 = ADC8 PIN 5 ARDUINO PIN 2/A8 = VOLTAGE reading PB0 = ADC11 PIN 2 ARDUINO PIN 0/A11 = REMOTE TEMP sensor = XTAL @@ -46,22 +46,34 @@ FOR MODULE VERSION 400,410,420,421.... ATTiny841 data sheet http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-8495-8-bit-AVR-Microcontrollers-ATtiny441-ATtiny841_Datasheet.pdf + +V440 pin mappings +PA0 = EXT REFERENCE +PA6 = Notification LED +PA4 = INT THERMISTOR ADC +PA7 = ENABLE + +PB2 = DUMP LOAD ENABLE +PA3 = VOLTAGE ADC +PA5 = EXT THERMISTOR ADC + +BLUE LED DOES NOT EXIST ON V440 (Well it does, but the green has been replaced with blue!) */ #include "diybms_attiny841.h" -void DiyBMSATTiny841::double_tap_green_led() +void DiyBMSATTiny841::double_tap_Notification_led() { - GreenLedOn(); + NotificationLedOn(); delay(50); - GreenLedOff(); + NotificationLedOff(); delay(50); - GreenLedOn(); + NotificationLedOn(); delay(50); - GreenLedOff(); + NotificationLedOff(); } -#if defined(DIYBMSMODULEVERSION) && DIYBMSMODULEVERSION < 430 +#if defined(DIYBMSMODULEVERSION) && DIYBMSMODULEVERSION < 440 void DiyBMSATTiny841::double_tap_blue_led() { BlueLedOn(); @@ -81,17 +93,35 @@ void DiyBMSATTiny841::ConfigurePorts() //PUEB – Port B Pull-Up Enable Control Register (All disabled) PUEB = 0; - //DDRA – Port A Data Direction Register - //When DDAn is set, the pin PAn is configured as an output. When DDAn is cleared, the pin is configured as an input -#if defined(DIYBMSMODULEVERSION) && DIYBMSMODULEVERSION < 430 - DDRA |= _BV(DDA3) | _BV(DDA6) | _BV(DDA7) | _BV(DDA5); -#else - //4.3 boards dont have blue led, so don't configure DA5 - DDRA |= _BV(DDA3) | _BV(DDA6) | _BV(DDA7); -#endif +//DDRA – Port A Data Direction Register +//When DDAn is set, the pin PAn is configured as an output. When DDAn is cleared, the pin is configured as an input +#if defined(DIYBMSMODULEVERSION) && DIYBMSMODULEVERSION < 440 + //PA3 = dump load enable + //PA6 = Notification LED (green) + //PA7 = enable + //PA5 = BLUE + DDRA = _BV(DDA3) | _BV(DDA6) | _BV(DDA7) | _BV(DDA5); //DDRB – Port B Data Direction Register //Spare pin is output - DDRB |= _BV(DDB1); + DDRB = _BV(DDB1); + + //Digital Input Disable Register 0 + //PA4 (ADC4), PB2 (ADC8) and PB0 (ADC11) analog inputs, so disable digital pins to save power + DIDR0 = _BV(ADC4D); + DIDR1 = _BV(ADC8D) |_BV(ADC11D); + +#else + //4.4 boards don't have blue led + //PB2 = DUMP LOAD ENABLE + //PA6 = Notification LED (BLUE) + //PA7 = ENABLE + DDRA = _BV(DDA6) | _BV(DDA7); + DDRB = _BV(DDB2); + + //Digital Input Disable Register 0 + //PA3 (ADC3), PA4 (ADC4) and PA5 (ADC5) are analog inputs, so disable digital pins to save power + DIDR0 = _BV(ADC3D) | _BV(ADC4D) |_BV(ADC5D); +#endif //Set the extra high sink capability of pin PA7 is enabled. PHDE |= _BV(PHDEA1); @@ -100,10 +130,11 @@ void DiyBMSATTiny841::ConfigurePorts() DumpLoadOff(); ReferenceVoltageOff(); -#if defined(DIYBMSMODULEVERSION) && DIYBMSMODULEVERSION < 430 +#if defined(DIYBMSMODULEVERSION) && DIYBMSMODULEVERSION < 440 BlueLedOff(); #endif - GreenLedOff(); + + NotificationLedOff(); } void DiyBMSATTiny841::SetWatchdog8sec() @@ -140,18 +171,20 @@ void DiyBMSATTiny841::BeginADCReading() //ADCSRA – ADC Control and Status Register A //Consider ADC sleep conversion mode? + /* #if !(F_CPU == 8000000) //prescaler of 64 = 8MHz/64 = 125KHz. ADCSRA |= _BV(ADPS2) | _BV(ADPS1); // | _BV(ADPS0); #endif #if !(F_CPU == 2000000) +*/ + //prescaler of 16 = 2MHz/16 = 125000. ADCSRA |= _BV(ADPS2); -#endif + //#endif - //adc_enable(); //Bit 4 – ADIF: ADC Interrupt Flag //Bit 7 – ADEN: ADC Enable ADCSRA |= _BV(ADEN) | _BV(ADIF); // enable ADC, turn off any pending interrupt @@ -189,7 +222,7 @@ void DiyBMSATTiny841::Sleep() // disable ADC ADCSRA = 0; -#if defined(DIYBMSMODULEVERSION) && DIYBMSMODULEVERSION < 430 +#if defined(DIYBMSMODULEVERSION) && DIYBMSMODULEVERSION < 440 set_sleep_mode(SLEEP_MODE_PWR_DOWN); #else //Using an external crystal so keep it awake - consumes more power (about 0.97mA vs 0.78mA) but module wakes quicker (6 clock cycles) diff --git a/ATTINYCellModule/src/main.cpp b/ATTINYCellModule/src/main.cpp index 24ff476..7e9e44c 100644 --- a/ATTINYCellModule/src/main.cpp +++ b/ATTINYCellModule/src/main.cpp @@ -49,7 +49,6 @@ ATTINY chip frequency dropped to 2Mhz to comply with datasheet at low voltages ( #error Expected BAUD define #endif - //Our project code includes #include "defines.h" #include "settings.h" @@ -83,8 +82,8 @@ void DefaultConfig() //About 2.2007 seems about right myConfig.Calibration = 2.2007; - //2mV per ADC resolution - //myConfig.mVPerADC = 2.0; //2048.0/1024.0; +//2mV per ADC resolution +//myConfig.mVPerADC = 2.0; //2048.0/1024.0; #if defined(DIYBMSMODULEVERSION) && (DIYBMSMODULEVERSION == 420 && !defined(SWAPR19R20)) //Keep temperature low for modules with R19 and R20 not swapped @@ -132,8 +131,8 @@ void onPacketReceived() //A data packet has just arrived, process it and forward the results to the next module if (PP.onPacketReceived((PacketStruct *)SerialPacketReceiveBuffer)) { - //Only light green if packet is good - DiyBMSATTiny841::GreenLedOn(); + //Only light Notification if packet is good + DiyBMSATTiny841::NotificationLedOn(); } //Send the packet (fixed length!) (even if it was invalid so controller can count crc errors) @@ -143,7 +142,7 @@ void onPacketReceived() //Therefore we use 1.4.1 which has the correct code to wait until the buffer is empty. DiyBMSATTiny841::FlushSerial0(); - DiyBMSATTiny841::GreenLedOff(); + DiyBMSATTiny841::NotificationLedOff(); //PacketProcessed = true; } @@ -205,11 +204,7 @@ void setup() wdt_disable(); wdt_reset(); - //Boot up will be in 1Mhz CKDIV8 mode, swap to /4 to change speed to 2Mhz - //CCP – Configuration Change Protection Register - CCP = 0xD8; - //CLKPR – Clock Prescale Register - CLKPR = _BV(CLKPS1); + DiyBMSATTiny841::SetPrescaler(); //below 2Mhz is required for running ATTINY at low voltages (less than 2V) @@ -234,7 +229,7 @@ void setup() ValidateConfiguration(); - DiyBMSATTiny841::double_tap_green_led(); + DiyBMSATTiny841::double_tap_Notification_led(); #if defined(DIYBMSMODULEVERSION) && DIYBMSMODULEVERSION < 430 DiyBMSATTiny841::double_tap_blue_led(); @@ -311,7 +306,7 @@ inline void identifyModule() { if (PP.identifyModule > 0) { - DiyBMSATTiny841::GreenLedOn(); + DiyBMSATTiny841::NotificationLedOn(); #if defined(DIYBMSMODULEVERSION) && DIYBMSMODULEVERSION < 430 DiyBMSATTiny841::BlueLedOn(); #endif @@ -319,7 +314,7 @@ inline void identifyModule() if (PP.identifyModule == 0) { - DiyBMSATTiny841::GreenLedOff(); + DiyBMSATTiny841::NotificationLedOff(); #if defined(DIYBMSMODULEVERSION) && DIYBMSMODULEVERSION < 430 DiyBMSATTiny841::BlueLedOff(); #endif @@ -360,12 +355,12 @@ void loop() if (wdt_triggered) { -#if defined(DIYBMSMODULEVERSION) && DIYBMSMODULEVERSION < 430 +#if defined(DIYBMSMODULEVERSION) && DIYBMSMODULEVERSION < 440 //Flash blue LED twice after a watchdog wake up DiyBMSATTiny841::double_tap_blue_led(); #else - //Flash green LED twice after a watchdog wake up - DiyBMSATTiny841::double_tap_green_led(); + //Flash Notification LED twice after a watchdog wake up + DiyBMSATTiny841::double_tap_Notification_led(); #endif //If we have just woken up, we shouldn't be in balance safety check that we are not @@ -389,10 +384,10 @@ void loop() //this causes the voltage and temperature to "freeze" during bypass cycles if (PP.bypassCountDown == 0) { -//Just for debug purposes, shows when voltage is read -//#if defined(DIYBMSMODULEVERSION) && DIYBMSMODULEVERSION < 430 -// DiyBMSATTiny841::BlueLedOn(); -//#endif + //Just for debug purposes, shows when voltage is read + //#if defined(DIYBMSMODULEVERSION) && DIYBMSMODULEVERSION < 430 + // DiyBMSATTiny841::BlueLedOn(); + //#endif //External temperature PP.TakeAnAnalogueReading(ADC_EXTERNAL_TEMP); @@ -400,9 +395,9 @@ void loop() //Do voltage reading last to give as much time for voltage to settle PP.TakeAnAnalogueReading(ADC_CELL_VOLTAGE); -//#if defined(DIYBMSMODULEVERSION) && DIYBMSMODULEVERSION < 430 -// DiyBMSATTiny841::BlueLedOff(); -//#endif + //#if defined(DIYBMSMODULEVERSION) && DIYBMSMODULEVERSION < 430 + // DiyBMSATTiny841::BlueLedOff(); + //#endif } //Switch balance PWM back on if needed @@ -486,7 +481,7 @@ void loop() //Clear the error and stop balancing myPID.clear(); StopBalance(); - //Just for debug... +//Just for debug... #if defined(DIYBMSMODULEVERSION) && DIYBMSMODULEVERSION < 430 DiyBMSATTiny841::BlueLedOn(); #endif @@ -512,7 +507,7 @@ void loop() PP.bypassHasJustFinished--; } -/* + /* if (PP.bypassCountDown > 0) { //If we are trying to drain the cell/balance, then we need @@ -528,5 +523,5 @@ void loop() i--; } } -*/ +*/ }