Project

General

Profile

Statistics
| Branch: | Revision:

root / scout_avr / bom / bom.c @ 1b05b4cc

History | View | Annotate | Download (3.71 KB)

1
#include <stdint.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include "tiny-twi.h"
5
#include "bomi2c.h"
6

    
7
char last_bit;
8
char count;
9
uint16_t data;
10
volatile char currently_sending;
11
char sending_counter;
12
uint16_t sending_data;
13

    
14
#define READ_BIT(pin, bit) (((pin) >> bit) & 1)
15
#define SET_BIT(pin, bit) ((pin) |= (1 << (bit)))
16
#define CLEAR_BIT(pin, bit) ((pin) &= ~(1 << (bit)))
17
#define PRESCALAR 8
18
#define TIME_US(us) (F_CPU * (us) / 1000000 / PRESCALAR)
19

    
20
#define ADDRESS 0x3 
21
#define DETECT PB3
22
#define EMIT PB4
23

    
24
#if DETECT == PB3
25
  #define PCINT_DETECT PCINT3
26
#endif
27
#if DETECT == PB4
28
  #define PCINT_DETECT PCINT4
29
#endif
30

    
31
static void bom_init(void) {
32
  init_detect();
33

    
34
  init_timer1();
35

    
36
  sei();
37
}
38

    
39
////////////////////////////////// Receiving ///////////////////////////////////
40

    
41
static void init_detect(void) {
42
  TCCROA |= _BV(WGM01);    // enable reset on compare A
43
  TIMSK  |= _BV(OCIE0A);   // enable timer0 compare match A
44

    
45
  GIMSK  |= _BV(PCIE);   // Enable pin change interrupt for detection
46
  PCMSK  |= _BV(PCINT_DETECT); // Enable interrupt on detect pin
47
}
48

    
49
// Disables the interrupt that begins the detect process while it is running
50
static void disable_detect_interrupt(void) {
51
  PCMSK &= ~_BV(PCINT_DETECT);
52
}
53

    
54
static void start_timer0(void) {
55
  TCNT0 = 0; // Reset timer 0 count to 0
56
  TCCR0B |= _BV(CS01);     // setup clkio and start the timer
57
}
58

    
59
static void start_detect(void) {
60
  disable_detect_interrupt();
61
  data = 0;
62
  count = 0;
63
  last_bit = 1;
64
  start_timer0();
65
}
66

    
67
static void restart_detect(void) {
68
  TCCR0B &= ~0x07; // Stop timer0
69
  PCMSK  |= _BV(PCINT_DETECT); // Enable interrupt on detect pin
70
}
71

    
72
ISR(PCINT0_vect) {
73
  start_detect();
74
}
75

    
76
ISR(TIMER0_COMPA_vect) {
77

    
78
  char this_bit = READ_BIT(PINB, DETECT);
79

    
80
  if (this_bit == 0) {
81
    if (last_bit == 0) {
82
      restart_detect();
83
    }
84
  } else {
85
    data = data << 1 | (~last_bit & 1);
86
    count++;
87
  }
88

    
89
  last_bit = this_bit;
90

    
91
  if (count == 15) {
92
    restart_detect();
93
    smb_send_data(&data, sizeof(data));
94
  }
95
}
96

    
97
////////////////////////////////////////////////////////////////////////////////
98

    
99
//////////////////////////////////// Sending ///////////////////////////////////
100

    
101
static void start_timer1() {
102
  TCNT1 = 0; // Reset timer 1 count to 0
103
  TCCR1 |= _BV(CS12) // Set prescalar to 8 and start timer1
104
}
105

    
106
static void stop_timer1() {
107
  TCCR1 &= ~0x0F; // Stop the timer without clearing CTC1
108
}
109

    
110
static void init_timer1() {
111
  OCR1B = TIME_US(320); // Set match b to fire every 320 us
112
  TIMSK |= _BV(OCIE1A) | _BV(OCIE1B); // Enable interrupt for match a and b
113
  TCCR1 |= _BV(CTC1);   // Enables resetting timer1 after matches match c
114
}
115

    
116
static void send_data(uint16_t data) {
117
  sending_data = data;
118
  sending_counter = 0;
119
  currently_sending = 1;
120
  SET_BIT(PORTB, EMIT);
121

    
122
  start_timer1();
123
  send_next_bit();
124
}
125

    
126
static void send_next_bit() {
127
  char next_bit = sending_data >> (14 - sending_counter) & 1;
128
  char ocr_temp = next_bit ? TIME_US(2000-40) : TIME_US(1000-20);
129
  OCR1A = ocr_temp; // Compare A - Turns on transmitter
130
  OCR1C = ocr_temp; // Reset the timer when match a fires
131
}
132

    
133
// Compare A - Turns on transmitter
134
ISR(TIMER1_COMPA_vect) {
135
  SET_BIT(PORTB, EMIT); 
136
  sending_counter++;
137
  send_next_bit();
138
}
139

    
140
// Compare B - Turns off transmitter after 320us
141
ISR(TIMER1_COMPB_vect) {
142
  CLEAR_BIT(PORTB, EMIT);
143
  if (sending_counter >= 15) {
144
    currently_sending = 0;
145
    stop_timer1();
146
  }
147
}
148

    
149
////////////////////////////////////////////////////////////////////////////////
150

    
151

    
152
static void slave_rx(uint8_t *buf, int len) {
153
  if (len >= 3) {
154
    switch (buf[0]) {
155
      case BOM_I2C_SEND:
156
        if (!currently_sending) send_data((uint16_t) buf[1] << 8 | buf[2]);  
157
        break;
158
    }
159
  }
160
}
161

    
162

    
163

    
164
int main() {
165
  bom_init();
166
  smb_init(slave_rx);
167
  smb_set_address(ADDRESS);
168
  for (;;);;;;;;;;;;;;;;;;; 
169
}