Project

General

Profile

Statistics
| Branch: | Revision:

root / scout_avr / bom / bom.c @ 5f7a1707

History | View | Annotate | Download (3.93 KB)

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

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

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

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

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

    
32
static void bom_init(void) {
33

    
34
  SET_BIT(DDRB, EMIT);
35

    
36
  init_detect();
37

    
38
  init_timer1();
39

    
40
  sei();
41
}
42

    
43
////////////////////////////////// Receiving ///////////////////////////////////
44

    
45
static void init_detect(void) {
46
  TCCR0A |= _BV(WGM01);    // enable reset on compare A
47
  TIMSK  |= _BV(OCIE0A);   // enable timer0 compare match A
48
  OCR0A   = TIME_US(1000); // trigger every 1ms
49

    
50
  GIFR   |= _BV(PCIF);   // Clear any previous detections
51
  GIMSK  |= _BV(PCIE);   // Enable pin change interrupt for detection
52
  PCMSK  |= _BV(PCINT_DETECT); // Enable interrupt on detect pin
53
}
54

    
55
// Disables the interrupt that begins the detect process while it is running
56
static void disable_detect_interrupt(void) {
57
  PCMSK &= ~_BV(PCINT_DETECT);
58
}
59

    
60
static void start_timer0(void) {
61
  TCNT0 = 0; // Reset timer 0 count to 0
62
  TCCR0B |= _BV(CS01);     // setup clkio and start the timer
63
}
64

    
65
static void start_detect(void) {
66
  disable_detect_interrupt();
67
  data = 0;
68
  count = 0;
69
  last_bit = 1;
70
  _delay_us(160);
71
  start_timer0();
72
}
73

    
74
static void restart_detect(void) {
75
  TCCR0B &= ~0x07; // Stop timer0
76
  PCMSK  |= _BV(PCINT_DETECT); // Enable interrupt on detect pin
77
}
78

    
79
ISR(PCINT0_vect) {
80
  start_detect();
81
}
82

    
83
ISR(TIMER0_COMPA_vect) {
84

    
85
  char this_bit = READ_BIT(PINB, DETECT);
86
  smb_send_data((uint8_t*)&this_bit, 1);
87

    
88
  if (this_bit == 1) {
89
    if (last_bit == 1) {
90
      restart_detect();
91
    }
92
  } else {
93
    data = data << 1 | (last_bit & 1);
94
    count++;
95
  }
96

    
97
  last_bit = this_bit;
98

    
99
  if (count == 15) {
100
    restart_detect();
101
    smb_send_data((uint8_t*) &data, sizeof(data));
102
  }
103
}
104

    
105
////////////////////////////////////////////////////////////////////////////////
106

    
107
//////////////////////////////////// Sending ///////////////////////////////////
108

    
109
static void start_timer1() {
110
  TCNT1 = 0; // Reset timer 1 count to 0
111
  TCCR1 |= _BV(CS12); // Set prescalar to 8 and start timer1
112
}
113

    
114
static void stop_timer1() {
115
  TCCR1 &= ~0x0F; // Stop the timer without clearing CTC1
116
}
117

    
118
static void init_timer1() {
119
  OCR1B = TIME_US(320); // Set match b to fire every 320 us
120
  TIMSK |= _BV(OCIE1A) | _BV(OCIE1B); // Enable interrupt for match a and b
121
  TCCR1 |= _BV(CTC1);   // Enables resetting timer1 after matches match c
122
}
123

    
124
static void send_data(uint16_t data) {
125
  sending_data = data;
126
  sending_counter = 0;
127
  currently_sending = 1;
128
  SET_BIT(PORTB, EMIT);
129

    
130
  start_timer1();
131
  send_next_bit();
132
}
133

    
134
static void send_next_bit() {
135
  char next_bit = sending_data >> (14 - sending_counter) & 1;
136
  char ocr_temp = next_bit ? TIME_US(2000-40) : TIME_US(1000-20);
137
  OCR1A = ocr_temp; // Compare A - Turns on transmitter
138
  OCR1C = ocr_temp; // Reset the timer when match a fires
139
}
140

    
141
// Compare A - Turns on transmitter
142
ISR(TIMER1_COMPA_vect) {
143
  SET_BIT(PORTB, EMIT); 
144
  sending_counter++;
145
  send_next_bit();
146
}
147

    
148
// Compare B - Turns off transmitter after 320us
149
ISR(TIMER1_COMPB_vect) {
150
  CLEAR_BIT(PORTB, EMIT);
151
  if (sending_counter >= 15) {
152
    currently_sending = 0;
153
    stop_timer1();
154
  }
155
}
156

    
157
////////////////////////////////////////////////////////////////////////////////
158

    
159

    
160
static void slave_rx(uint8_t *buf, int len) {
161
  if (len >= 3) {
162
    switch (buf[0]) {
163
      case BOM_I2C_SEND:
164
        if (!currently_sending) send_data((uint16_t) buf[1] << 8 | buf[2]);  
165
        break;
166
    }
167
  }
168
}
169

    
170

    
171

    
172
int main() {
173
  bom_init();
174
  smb_init(slave_rx);
175
  smb_set_address(ADDRESS);
176
  for (;;);;;;;;;;;;;;;;;;; 
177
}