• Main Page
  • Data Structures
  • Files
  • File List
  • Globals

main.c

Go to the documentation of this file.
00001 
00299 #include <avr/io.h>
00300 #include <avr/interrupt.h>
00301 #include <avr/wdt.h>
00302 #include <util/delay.h>
00303 #include <avr/pgmspace.h>    // keeping constants in program memory
00304 
00305 #include "usiTwiSlave.h"     // i2c-routines by Donald R. Blake
00306 
00307 #define TWI_SLA       0x10  
00309 #define CHANNEL_COUNT 13    
00310 #define PORT_COUNT    2     
00312 #define OUTPORT0      PORTB 
00313 #define OUTDDR0       DDRB  
00314 #define OUTMASK0      0x5F  
00316 #define OUTPORT1      PORTD 
00317 #define OUTDDR1       DDRD  
00318 #define OUTMASK1      0x7F  
00326 const uint8_t channel_port[CHANNEL_COUNT] PROGMEM = {
00327        0,    0,    0,    0,    0,    0,
00328        1,    1,    1,    1,    1,    1,    1 };
00330 const uint8_t channel_pin[CHANNEL_COUNT] PROGMEM = {
00331     0x01, 0x02, 0x04, 0x08, 0x10, 0x40,
00332     0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40 };
00333 
00334 /*
00335  * This is a special treatment for the states lasting very long. If you simply
00336  * double the times for each state, you eventually end up having long pauses in
00337  * the modulation. We try to suppress this effect by not waiting for 8192
00338  * cycles but better performing the shorter 4096-cycle twice.
00339  */
00340 #define STATE_COUNT       14 
00341 #define STATE_START_COUNT 2  
00343 const uint16_t switch_timer[STATE_COUNT] PROGMEM = {
00344     1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 4096 };
00346 const uint8_t switch_timer_index[STATE_START_COUNT]= { 13, 0 };
00347 
00349 uint8_t switch_state[STATE_COUNT][PORT_COUNT];
00350 
00351 uint8_t switch_state_new[STATE_COUNT][PORT_COUNT];
00356 typedef enum {
00357     WAIT_FOR_ADDRESS,     
00358     WAIT_FOR_VALUE_LOW,   
00359     WAIT_FOR_VALUE_HIGH,  
00360 } ReadCommandState;
00361 
00367 typedef struct {
00368     uint8_t address;         
00370     uint16_t value;          
00372     ReadCommandState state;  
00373 } Command;
00374 
00376 Command command = {0, 0, WAIT_FOR_ADDRESS};
00377 
00381 void timer_start() {
00382     TCCR1A = 0x00;  // no hardware-pwm
00383     /* CS12, CS11, CS10 (clock select bits)
00384      *  0     1     0       cpu-clock / 8
00385      */
00386     TCCR1B = (0 << WGM13) | (0 << WGM12) | (0 << CS12) | (1 << CS11) | (0 << CS10); // WGM1=4
00387     sei();
00388 }
00389 
00395 void set_brightness(uint8_t channel, uint16_t brightness){
00396     uint8_t i;
00397     // read port mask and port for this channel from program memory
00398     uint8_t mask= pgm_read_word(&channel_pin[channel]);
00399     uint8_t port= pgm_read_word(&channel_port[channel]);
00400     // set the bits in the output-states according to the brightness
00401     for (i= 0; i < STATE_COUNT; i++){
00402         // walk through all states...
00403         if (brightness & 1) {
00404             // set the bit if it needs to be set in this state
00405             switch_state_new[i][port] |= mask;
00406         } else {
00407             // clear it otherwise
00408             switch_state_new[i][port] &= ~mask;
00409         }
00410         // shift the value to look at the next bit
00411         brightness >>= 1;
00412     }
00413 }
00414 
00418 void init_ports(void){
00419     OUTDDR0  |=  OUTMASK0;
00420     OUTPORT0 &= ~OUTMASK0; // clear all masked bits
00421 
00422     OUTDDR1  |=  OUTMASK1;
00423     OUTPORT1 &= ~OUTMASK1; // clear all masked bits
00424 }
00425 
00431 void set_port(int port, uint8_t state){
00432     switch(port){
00433         case 0:
00434             OUTPORT0 |= (state &  OUTMASK0); // set bits
00435             OUTPORT0 &= (state | ~OUTMASK0); // clear bits
00436             break;
00437         case 1:
00438             OUTPORT1 |= (state &  OUTMASK1); // set bits
00439             OUTPORT1 &= (state | ~OUTMASK1); // clear bits
00440             break;
00441     }
00442 }
00443 
00449 void evaluate_i2c_input(void) {
00450     uint8_t byte_received = 0;
00451     if (usiTwiDataInReceiveBuffer()) {
00452         // we have input
00453         byte_received = usiTwiReceiveByte();
00454         switch(command.state){
00455             case WAIT_FOR_ADDRESS:
00456                 if (byte_received & 0x80) {
00457                     // bit 7 is set -> address received
00458                     command.address = (byte_received & 0x7f);
00459                     command.state = WAIT_FOR_VALUE_LOW;
00460                 }
00461                 // do nothing if this byte didn't look like an address
00462                 break;
00463             case WAIT_FOR_VALUE_LOW:
00464                 if (!(byte_received & 0x80)) {
00465                     // bit 7 is not set -> could be a value
00466                     command.value = byte_received;
00467                     command.state = WAIT_FOR_VALUE_HIGH;
00468                 } else {
00469                     // seems to be an address
00470                     command.address = byte_received;
00471                     command.state = WAIT_FOR_VALUE_LOW;
00472                 }
00473                 break;
00474             case WAIT_FOR_VALUE_HIGH:
00475                 if (!(byte_received & 0x80)) {
00476                     // bit 7 is not set -> could be a value
00477                     command.value += (byte_received << 7);
00478                     command.state = WAIT_FOR_ADDRESS;
00479                     // we have a complete command
00480                     set_brightness(command.address, command.value);
00481                 } else {
00482                     // seems to be an address
00483                     command.address = byte_received;
00484                     command.state = WAIT_FOR_VALUE_LOW;
00485                 }
00486                 break;
00487         }
00488     }
00489 }
00490 
00496 int main(void) {
00497     uint8_t state_number = 0;
00498     uint8_t state_start = 0;
00499     uint8_t port = 0;
00500     uint16_t timer = 0;
00501 
00502     // initialize output ports
00503     init_ports();
00504     // set all channels to 0
00505     uint8_t i;
00506     for(i= 0; i < CHANNEL_COUNT; i++) {
00507         set_brightness(i, 0);
00508     }
00509 
00510     // own TWI slave address
00511     usiTwiSlaveInit(TWI_SLA);
00512 
00513     // start timer
00514     timer_start();
00515 
00516     // init watchdog
00517     wdt_enable(WDTO_15MS); // 15ms watchdog
00518 
00519     while (1) {
00520         // loop forever
00521         for (state_start = 0; state_start < STATE_START_COUNT; state_start++) {
00522             // treat state groups...
00523             for (state_number = switch_timer_index[state_start]; state_number < STATE_COUNT; state_number++) {
00524                 // cycle through all steps...
00525                 for (port = 0; port < PORT_COUNT; port++) {
00526                     // set all output ports according to the current step...
00527                     set_port(port, switch_state[state_number][port]);
00528                 }
00529                 // determine how long to wait for the next step
00530                 timer = pgm_read_word(&switch_timer[state_number]);
00531                 // restart timer
00532                 TCNT1 = 0;
00533                 while (timer > TCNT1) {
00534                     // wait for the next step... meanwhile...
00535                     wdt_reset();          // feed the watchdog
00536                     evaluate_i2c_input(); // read i2c commands
00537                 }
00538             }
00539         }
00540         for(state_number= 0; state_number < STATE_COUNT; state_number++) {
00541             for(port= 0; port < PORT_COUNT; port++) {
00542                 switch_state[state_number][port]=
00543                     switch_state_new[state_number][port];
00544             }
00545         }
00546     }
00547     return 0;
00548 }

Generated on Sat Dec 10 2011 12:16:43 for I2C-Dimmer by  doxygen 1.7.2