]> jspc29.x-matter.uni-frankfurt.de Git - electronics.git/commitdiff
new version of power switch firmware with more features
authorJan Michel <j.michel@gsi.de>
Fri, 25 Jul 2014 13:24:41 +0000 (15:24 +0200)
committerJan Michel <j.michel@gsi.de>
Fri, 25 Jul 2014 13:24:41 +0000 (15:24 +0200)
Power/firmware/Makefile
Power/firmware/PowerSwitch.c

index 34364fc75d4853a2f4d66d7ec95775a52a9df9c2..143fc012e74dad39e9f0d74081059c8c2fe0f337 100644 (file)
@@ -7,7 +7,7 @@
 
 MCU = attiny441
 FORMAT = ihex
-TARGET = main
+TARGET = PowerSwitch
 SRC = $(TARGET).c
 ASRC = 
 OPT = s
index 0c54c6fd4641db88b14b74102db8679bc81ea698..1f414d9e7c0a93ae7bcee979fa836a8780690a24 100755 (executable)
@@ -2,11 +2,11 @@
 \r
 #include <avr/interrupt.h>\r
 #include <util/delay.h>\r
-// #include <avr/sleep.h>\r
-// #include <stdint.h>\r
 #include <avr/io.h>\r
+#include <avr/eeprom.h>\r
 #include <string.h>\r
 \r
+#define FIRMWARE_VERSION 0x010\r
 \r
 //A0 Aref    In\r
 //A1 Adc2    In  (ADC1)\r
 //Scc(0|1|/)   -- switch channel off/on/toggle\r
 //Scc?         -- read channel status - 2nd char: 'e' in case of overcurrent, 3rd char: enable 1/0\r
 //Ccc?         -- read current\r
+//Dcc?         -- read averaged current\r
 //Lccxxx       -- set current limit (hex)\r
 //Lcc?         -- read current limit\r
 //Axxx         -- answer - three hex digits or chars\r
+//Occ(0|1|2|3) -- switch ADC & set max scale:  off|2.2Vref|4.1Vref|VCCref (one setting for both ports)\r
+//Pcc(0|1)     -- Do a automatic power cycle (2 seconds long)\r
+//Rcc?         -- read ADC measurement of internal 1.1V reference (one register)\r
+//Icc?         -- Firmware Info\r
 \r
 #define STARTTX(i) txcnt = (i);UCSR1B |= (1<< UDRIE1)\r
-#define ISMYADDR() (rxbuf[1] == '0' && (rxbuf[2] == '0' || rxbuf[2] == '1'))\r
+#define ISMYADDR() (rxbuf[1] == '0' && (rxbuf[2] == '0' || rxbuf[2] == '1') )\r
 \r
 volatile uint8_t settings_changed = 0;\r
 uint8_t  output_enable = 0x3;\r
 uint8_t  output_error = 0;\r
+uint8_t  adc_enable = 1;\r
 uint16_t adc[2];\r
 uint16_t avgadc[2] = {0,0};\r
+uint8_t  countdown[2] = {0,0};\r
+uint16_t adc_reference = 0;\r
 \r
 uint8_t rxcnt = 0, txcnt = 0, txpoint = 0;\r
 uint8_t rxbuf[7];\r
 uint8_t txbuf[7];\r
 uint16_t limit[2] = {0x0800,0x0800};\r
 \r
+\r
 uint8_t nib_to_hex(uint16_t in, uint8_t nib) {\r
   uint8_t t = (in >> (nib*4)) & 0xF;\r
   if (t <= 9) {return t + 0x30;}\r
@@ -69,6 +78,17 @@ void forward_msg(uint8_t i) {
   memcpy ((uint8_t*)txbuf,(uint8_t*)rxbuf,i);\r
   STARTTX(i);\r
   }  \r
+\r
+uint8_t is_my_address(uint8_t s) {\r
+  if (ISMYADDR()) {\r
+    rxbuf[2] -= '0';\r
+    return 1;\r
+    }\r
+  else {\r
+    forward_msg(s);\r
+    return 0;\r
+    }\r
+  }\r
   \r
 void send_answer_hex(uint16_t v) {\r
   txbuf[0]='A';\r
@@ -90,8 +110,10 @@ void send_answer_chars(uint8_t a, uint8_t b, uint8_t c) {
 \r
   \r
 void switchoutput(uint8_t chan, int8_t to) {\r
-  if(to == -1)\r
+  if(to == -1) {\r
     output_enable ^= (1<<chan);\r
+       output_error  &= ~(1<<chan);\r
+    }\r
   else if (to == 0 || to == -2) {\r
     output_enable &= ~(1<<chan);\r
     }\r
@@ -102,31 +124,56 @@ void switchoutput(uint8_t chan, int8_t to) {
 \r
   if(to >= -1) {settings_changed |= 4;}\r
   \r
-  uint8_t en1 = ((output_enable & 1) && !(output_error & 1))?0:1;\r
-  uint8_t en2 = ((output_enable & 2) && !(output_error & 2))?0:1;\r
-  PORTA = (PORTA & ~(3<<2)) | ((en1&1)<<3) | ((en2&1)<<2);\r
+  uint8_t en1 = ((output_enable & 1) && !(output_error & 1))?1:0;  //switched for open drain version\r
+  uint8_t en2 = ((output_enable & 2) && !(output_error & 2))?1:0;\r
+  \r
+  PORTA &= ~((1<<2) | (1<<3));\r
+  DDRA  = (DDRA & ~(3<<2)) | ((en1&1)<<3) | ((en2&1)<<2);\r
+  //PORTA = (PORTA & ~(3<<2)) | ((en1&1)<<3) | ((en2&1)<<2);\r
 \r
   }\r
 \r
+void correct_adc(uint8_t channel) {\r
+    if(adc_enable == 1) return;\r
+    if(adc_enable == 2) {\r
+      adc[channel] = adc[channel]*2 - (adc[channel]>>3);\r
+      }\r
+    }\r
+  \r
 ISR(TIMER0_OVF_vect) {\r
   static uint8_t dwncnt[2] = {0,0};\r
   if(!(PINA & 0x40)) {dwncnt[0]++;} else {dwncnt[0] = 0;}\r
   if(!(PINB & 0x04)) {dwncnt[1]++;} else {dwncnt[1] = 0;}\r
          \r
-  if(dwncnt[0] == 50) {switchoutput(0,-1);}      \r
-  if(dwncnt[1] == 50) {switchoutput(1,-1);}\r
-         \r
-  ADCSRA |= (1<<ADSC);  \r
+       \r
+  for(uint8_t i=0; i<=1;i++) {\r
+    if(dwncnt[i] == 50) {switchoutput(i,-1);}    \r
+    if(countdown[i] != 0) {\r
+      if(countdown[i] == 1) {\r
+        switchoutput(i,-1);\r
+        }\r
+      countdown[i]--;\r
+      }\r
+       }\r
+  \r
+  if(adc_enable) {ADCSRA |= (1<<ADSC);}\r
   asm volatile("wdr");\r
-  }\r
-\r
+  }  \r
+  \r
 ISR(ADC_vect) {\r
   static uint8_t channel = 0;\r
   if(channel == 0) { \r
+    adc_reference = ADC;\r
+    ADMUXA = 7;  \r
+    ADCSRA |= (1<<ADSC); \r
+    channel = 1;\r
+    }\r
+  else if(channel == 1) { \r
     adc[0] = ADC; \r
+    correct_adc(0);\r
     ADMUXA = 1;  \r
     ADCSRA |= (1<<ADSC); \r
-    channel = 1;\r
+    channel = 2;\r
     avgadc[0] -= avgadc[0]/8;\r
     avgadc[0] += adc[0];\r
     if(limit[0]*8<avgadc[0]) {\r
@@ -134,10 +181,10 @@ ISR(ADC_vect) {
       switchoutput(0,-2);\r
       }  \r
     }\r
-  else if(channel == 1) { \r
+  else if(channel == 2) { \r
     adc[1] = ADC; \r
-    ADMUXA = 7;  \r
-//    ADCSRA |= (1<<ADSC); \r
+    correct_adc(1);\r
+    ADMUXA = 0xD;\r
     channel = 0;\r
     avgadc[1] -= avgadc[1]/8;\r
     avgadc[1] += adc[1];\r
@@ -145,7 +192,7 @@ ISR(ADC_vect) {
       output_error |= 2;\r
       switchoutput(1,-2);\r
       }    \r
-    }    \r
+    }\r
   }\r
 \r
 ISR(USART1_UDRE_vect) {\r
@@ -159,123 +206,114 @@ ISR(USART1_UDRE_vect) {
   \r
 ISR(USART1_RX_vect) {\r
   uint8_t buf = UDR1;\r
-  if (rxcnt != 0 || (buf == 'S' || buf == 'A' || buf == 'L' || buf == 'C' || buf == 'D')) {\r
+  if (rxcnt != 0 || (buf == 'S' || buf == 'A' || buf == 'L' || buf == 'C' || buf == 'I'\r
+                                || buf == 'D' || buf == 'O' || buf == 'P' || buf == 'R')) {\r
     rxbuf[rxcnt++] = buf;\r
     }\r
-  //Forward any incoming 4 letter answer\r
   if (buf == '\n' || buf == '\r') {\r
-    // if(rxcnt == 1 && rxbuf[0] == '\n') {\r
-      // txbuf[0] = '\n';\r
-      // STARTTX(1);\r
-      // }\r
-    if(rxcnt == 5) {\r
+\r
+\r
+    if(rxcnt == 5) { //4 letter commands\r
+//Forward any incoming 4 letter answer    \r
       if (rxbuf[0] == 'A') {\r
         memcpy ((uint8_t*)txbuf,(uint8_t*)rxbuf,5);\r
         STARTTX(5);\r
         }\r
-    //Four letter 'switch' command  \r
-      if (rxbuf[0] == 'S') {  \r
-        if (ISMYADDR()) {\r
-          rxbuf[2] -= '0';\r
-          if (rxbuf[3] != '?') {\r
-            switchoutput(rxbuf[2],rxbuf[3]-'0');\r
-            }\r
-          send_answer_chars('0', (output_error  & (1<<rxbuf[2]))?'e':'0', \r
-                                 (output_enable & (1<<rxbuf[2]))?'1':'0');      \r
-          }\r
-        else {\r
-          forward_msg(5);\r
+        \r
+//Switch command  \r
+      if (rxbuf[0] == 'S' && is_my_address(5)) {  \r
+        if (rxbuf[3] != '?') {\r
+          switchoutput(rxbuf[2],rxbuf[3]-'0');\r
           }\r
+        send_answer_chars('0', (output_error  & (1<<rxbuf[2]))?'e':'0', \r
+                               (output_enable & (1<<rxbuf[2]))?'1':'0');      \r
         }\r
-    //Read current command\r
-      if (rxbuf[0] == 'C') { \r
-        if (ISMYADDR()) {\r
-          if (rxbuf[3] == '?')\r
-            send_answer_hex(adc[rxbuf[2]-'0']);\r
-          }\r
-        else {\r
-          forward_msg(5);\r
+\r
+//Power cycle command\r
+      if (rxbuf[0] == 'P' && is_my_address(5)) {  \r
+        if (rxbuf[3] != '?') {\r
+          switchoutput(rxbuf[2],rxbuf[3]-'0');\r
+          countdown[rxbuf[2]] = 200;\r
           }\r
+        send_answer_chars('0', (output_error  & (1<<rxbuf[2]))?'e':'0', \r
+                               (output_enable & (1<<rxbuf[2]))?'1':'0');      \r
         }\r
-    //Read average current command\r
-    if (rxbuf[0] == 'D') {\r
-           if (ISMYADDR()) {\r
-                   if (rxbuf[3] == '?')\r
-                   send_answer_hex(avgadc[rxbuf[2]-'0']/8);\r
-           }\r
-           else {\r
-                   forward_msg(5);\r
-           }\r
-    }\r
-    //Read current limit    \r
-      if (rxbuf[0] == 'L' && rxbuf[3] == '?') {\r
-        if (ISMYADDR()) {\r
-          send_answer_hex(limit[rxbuf[2]-'0']);      \r
-          }\r
-        else {\r
-          forward_msg(5);\r
-          }\r
+        \r
+//Read current command\r
+      if (rxbuf[0] == 'C' && rxbuf[3] == '?' && is_my_address(5)) { \r
+        if(adc_enable == 3) {  send_answer_hex(adc[rxbuf[2]]+0x800);  }\r
+        else                {  send_answer_hex(adc[rxbuf[2]]);        }\r
+        }\r
+        \r
+//Read average current command\r
+      if (rxbuf[0] == 'D' && rxbuf[3] == '?' && is_my_address(5)) {\r
+        if(adc_enable == 3) {  send_answer_hex(avgadc[rxbuf[2]]/8+0x800);  }\r
+        else                {  send_answer_hex(avgadc[rxbuf[2]]/8);        }\r
+        }\r
+\r
+//Read firmware info\r
+      if (rxbuf[0] == 'I' && rxbuf[3] == '?' && is_my_address(5)) {\r
+           send_answer_hex(FIRMWARE_VERSION);\r
+        }\r
+        \r
+//Switch ADC\r
+      if (rxbuf[0] == 'O' && is_my_address(5)) {\r
+               if(rxbuf[3] != '?')\r
+                 adc_enable = rxbuf[3] - '0';\r
+        send_answer_hex(adc_enable);\r
+        settings_changed |= 8;\r
+        if (adc_enable == 1)  ADMUXB = (6 << REFS0);   //2.2V reference, with capacitor\r
+        if (adc_enable == 2)  ADMUXB = (7 << REFS0);   //4.096V as reference\r
+        if (adc_enable == 3)  ADMUXB = (0 << REFS0);   //Vcc as reference\r
+        }\r
+      \r
+//Read current limit    \r
+      if (rxbuf[0] == 'L' && rxbuf[3] == '?' && is_my_address(5)) {\r
+        send_answer_hex(limit[rxbuf[2]]);      \r
+        } \r
+\r
+//Read reference value\r
+      if (rxbuf[0] == 'R' && rxbuf[3] == '?' && is_my_address(5)) {\r
+        send_answer_hex(adc_reference);      \r
         } \r
       }\r
-  //Set current limit\r
-    if (rxcnt == 7 && rxbuf[0] == 'L') {\r
-      if (ISMYADDR()) {\r
-        rxbuf[2] -= '0';\r
-        if(rxbuf[3] != '?') {\r
-          uint16_t lim = hex_to_int(rxbuf[3])*256 + hex_to_int(rxbuf[4])*16 + hex_to_int(rxbuf[5]);\r
-          limit[rxbuf[2]] = lim;\r
-          }\r
-        send_answer_hex(limit[rxbuf[2]]); \r
-        settings_changed |= rxbuf[2]+1;        \r
+      \r
+      \r
+//Set current limit\r
+    if (rxcnt == 7 && rxbuf[0] == 'L' && is_my_address(7)) {\r
+      if(rxbuf[3] != '?') {\r
+        uint16_t lim = hex_to_int(rxbuf[3])*256 + hex_to_int(rxbuf[4])*16 + hex_to_int(rxbuf[5]);\r
+        limit[rxbuf[2]] = lim;\r
         }\r
-      else {\r
-        forward_msg(7);\r
-        }\r
-      } \r
+      send_answer_hex(limit[rxbuf[2]]); \r
+      settings_changed |= rxbuf[2]+1;        \r
+      }\r
     }      \r
     \r
   if (rxcnt >= 7 || buf == '\n' || buf == '\r') { rxcnt = 0; }  \r
     \r
 } \r
 \r
-#define EEPROM_DIS() while(EECR & (1<<EEPE)); EEARL = 0\r
 \r
-void eeprom_write(uint8_t addr, uint8_t data){\r
-  while(EECR & (1<<EEPE));\r
-  EECR = (0<<EEPM0);\r
-  EEARL = addr;\r
-  EEDR = data;\r
-  cli();\r
-  EECR |= (1<<EEMPE);\r
-  EECR |= (1<<EEPE);\r
-  sei();      \r
-  }\r
-\r
-uint8_t eeprom_read(uint8_t addr) {\r
-  while(EECR & (1<<EEPE));\r
-  EEARL = addr;\r
-  EECR |= (1<<EERE);\r
-  return EEDR;\r
-  }\r
   \r
 __attribute__((naked)) int main(void) {\r
        // Configure ports\r
        \r
-  PUEA  = 0b01011100;\r
-  PUEB  = 0b00001100;\r
-  \r
+  PORTA = 0b00001100;\r
+  PUEA  = 0b01010000;\r
   DDRA  = 0b00101100; \r
-  DDRB  = 0b00000000;\r
   \r
-  PORTA = 0b00001100;\r
+  DDRB  = 0b00000000;\r
+  PUEB  = 0b00001100;\r
   PORTB = 0b00000000;\r
   \r
-  output_enable = eeprom_read(0x14);\r
+  output_enable = eeprom_read_byte((uint8_t*)0x24);\r
   switchoutput(0,-3); \r
-  limit[0]  = eeprom_read(0x11)<<8;\r
-  limit[0] |= eeprom_read(0x10);\r
-  limit[1]  = eeprom_read(0x13)<<8;\r
-  limit[1] |= eeprom_read(0x12);  \r
+  limit[0]   = eeprom_read_byte((uint8_t*)0x21)<<8;\r
+  limit[0]  |= eeprom_read_byte((uint8_t*)0x20);\r
+  limit[1]   = eeprom_read_byte((uint8_t*)0x23)<<8;\r
+  limit[1]  |= eeprom_read_byte((uint8_t*)0x22);  \r
+  adc_enable = eeprom_read_byte((uint8_t*)0x25);\r
   \r
   //CCP = 0xD8;        //allow writing of CLKPR\r
   CLKPR = (0 << CLKPS0); // no prescaler  \r
@@ -286,7 +324,9 @@ __attribute__((naked)) int main(void) {
   TIMSK0 = (1 << TOIE0); //Overflow interrupt`\r
   \r
   ADMUXA = 7;  //(1 (Out2),7 (Out1))\r
-  ADMUXB = (6 << REFS0);   //2.2V reference, with capacitor\r
+  if (adc_enable == 1)  ADMUXB = (6 << REFS0);   //2.2V reference, with capacitor\r
+  if (adc_enable == 2)  ADMUXB = (7 << REFS0);   //4.096V reference\r
+  if (adc_enable == 3)  ADMUXB = (0 << REFS0);   //Vcc reference\r
   ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADIE) | (6 << ADPS0); //enable, start, irq, /128\r
   ADCSRB = 0;\r
   DIDR0  = (1<<ADC1D) | (1<< ADC7D); //disable digital inputs\r
@@ -305,23 +345,26 @@ __attribute__((naked)) int main(void) {
   \r
   \r
   while(1) {\r
-       _delay_ms(3000);  \r
-       if(settings_changed != 0) {\r
-               if (settings_changed & 1) {\r
-                       settings_changed &= ~1;\r
-                       eeprom_write(0x10,limit[0]&0xFF);\r
-                       eeprom_write(0x11,(limit[0]>>8)&0xFF);\r
-               }\r
-               if (settings_changed & 2) {\r
-                       settings_changed &= ~2;\r
-                       eeprom_write(0x12,limit[1]&0xFF);\r
-                       eeprom_write(0x13,(limit[1]>>8)&0xFF);\r
-               }\r
-               if (settings_changed & 4) {\r
-                       settings_changed &= ~4;\r
-                       eeprom_write(0x14,output_enable);\r
-               }\r
-               EEPROM_DIS();\r
-               }\r
+    _delay_ms(3000);  \r
+    if(settings_changed != 0) {\r
+      if (settings_changed & 1) {\r
+        settings_changed &= ~1;\r
+        eeprom_update_byte((uint8_t*)0x20,limit[0]&0xFF);\r
+        eeprom_update_byte((uint8_t*)0x21,(limit[0]>>8)&0xFF);\r
+        }\r
+      if (settings_changed & 2) {\r
+        settings_changed &= ~2;\r
+        eeprom_update_byte((uint8_t*)0x22,limit[1]&0xFF);\r
+        eeprom_update_byte((uint8_t*)0x23,(limit[1]>>8)&0xFF);\r
+        }\r
+      if (settings_changed & 4) {\r
+        settings_changed &= ~4;\r
+        eeprom_update_byte((uint8_t*)0x24,output_enable);\r
+        }\r
+      if (settings_changed & 8) {\r
+        settings_changed &= ~8;\r
+        eeprom_update_byte((uint8_t*)0x25,adc_enable);\r
+        }\r
+      }\r
     }\r
   }
\ No newline at end of file