aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--Makefile4
-rw-r--r--i2c.c252
-rw-r--r--i2c.h51
-rw-r--r--main.c327
-rw-r--r--uart.c46
-rw-r--r--uart.h7
7 files changed, 367 insertions, 323 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..99b6aae
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+*.sw?
+sanduhr.elf
+sanduhr.hex
diff --git a/Makefile b/Makefile
index 452e05e..1863525 100644
--- a/Makefile
+++ b/Makefile
@@ -2,8 +2,8 @@ MCU = atmega88
all: sanduhr.hex
-sanduhr.elf: main.c
- avr-gcc -std=gnu99 -mmcu=$(MCU) -Os -o $@ $<
+sanduhr.elf: main.c i2c.c i2c.h uart.c
+ avr-gcc -std=gnu99 -mmcu=$(MCU) -Os -o $@ $^
sanduhr.hex: sanduhr.elf
avr-objcopy -O ihex -R .eeprom $< $@
diff --git a/i2c.c b/i2c.c
new file mode 100644
index 0000000..4368158
--- /dev/null
+++ b/i2c.c
@@ -0,0 +1,252 @@
+#include <stdio.h>
+#include <util/twi.h>
+#include <avr/interrupt.h>
+
+#include "i2c.h"
+
+volatile twReq twr;
+
+static void twStartRaw () {
+ /* disable stop, enable interrupt, reset twint, enable start, enable i2c */
+ TWCR = (TWCR & ~(1 << TWSTO)) | (1 << TWIE) | (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);
+}
+
+static void twStopRaw () {
+ /* disable start, enable interrupt, reset twint, enable stop, enable i2c */
+ TWCR = (TWCR & ~(1 << TWSTA)) | (1 << TWIE) | (1 << TWINT) | (1 << TWSTO) | (1 << TWEN);
+}
+
+static void twFlushRaw () {
+ /* disable start/stop, enable interrupt, reset twint, enable i2c */
+ TWCR = (TWCR & ~((1 << TWSTA) | (1 << TWSTO) | (1 << TWEA))) | (1 << TWIE) | (1 << TWINT) | (1 << TWEN);
+}
+
+/* flush and send master ack */
+static void twFlushContRaw () {
+ /* disable start/stop, enable interrupt, reset twint, enable i2c, send master ack */
+ TWCR = (TWCR & ~((1 << TWSTA) | (1 << TWSTO))) | (1 << TWIE) | (1 << TWINT) | (1 << TWEN) | (1 << TWEA);
+}
+
+static void twWaitRaw () {
+ while (!(TWCR & (1 << TWINT)));
+}
+
+static bool twWriteRaw (const uint8_t data) {
+ TWDR = data;
+ if (TWCR & (1 << TWWC)) {
+ printf("write collision\n");
+ return false;
+ } else {
+ return true;
+ }
+}
+
+void twInit () {
+ /* set scl to 3.6 kHz (at 1Mhz CPU speed)*/
+ TWBR = 2;
+ TWSR |= 0x3; /* set prescaler to 64 */
+
+ twr.mode = TWM_INVALID;
+ twr.status = TWST_ERR;
+}
+
+/* high-level write
+ */
+bool twWrite (const uint8_t address, const uint8_t subaddress,
+ const uint8_t data) {
+ /* do not start if request is pending */
+ if (twr.status == TWST_WAIT) {
+ return false;
+ }
+
+ twr.mode = TWM_WRITE;
+ twr.address = address;
+ twr.subaddress = subaddress;
+ twr.data = data;
+ twr.step = 0;
+ twr.status = TWST_WAIT;
+ /* wait for stop finish */
+ while (TW_STATUS != 0xf8);
+ twStartRaw ();
+
+ return true;
+}
+
+/* high-level read for multiple bytes/addresses
+ */
+bool twReadMulti (const uint8_t address, const uint8_t subaddress,
+ uint8_t * const retData, const uint8_t count) {
+ /* do not start if request is pending */
+ if (twr.status == TWST_WAIT) {
+ return false;
+ }
+
+ twr.mode = TWM_READ_MULTI;
+ twr.address = address;
+ twr.subaddress = subaddress;
+ twr.retData = retData;
+ twr.count = count;
+ twr.i = 0;
+ twr.step = 0;
+ twr.status = TWST_WAIT;
+ /* wait for stop finish */
+ while (TW_STATUS != 0xf8);
+ twStartRaw ();
+
+ return true;
+}
+
+/* handle interrupt, write request
+ */
+static void twIntWrite () {
+ switch (twr.step) {
+ case 0:
+ if (TW_STATUS == TW_START) {
+ twWriteRaw (twr.address | TW_WRITE);
+ twFlushRaw ();
+ } else {
+ twr.status = TWST_ERR;
+ }
+ break;
+
+ case 1:
+ if (TW_STATUS == TW_MT_SLA_ACK) {
+ twWriteRaw (twr.subaddress);
+ twFlushRaw ();
+ } else {
+ twr.status = TWST_ERR;
+ }
+ break;
+
+ case 2:
+ if (TW_STATUS == TW_MT_DATA_ACK) {
+ twWriteRaw (twr.data);
+ twFlushRaw ();
+ } else {
+ twr.status = TWST_ERR;
+ }
+ break;
+
+ case 3:
+ if (TW_STATUS == TW_MT_DATA_ACK) {
+ twStopRaw ();
+ twr.status = TWST_OK;
+ } else {
+ twr.status = TWST_ERR;
+ }
+ break;
+
+ default:
+ printf ("nope\n");
+ break;
+ }
+ ++twr.step;
+}
+
+/* handle interrupt, read request
+ */
+static void twIntReadMulti () {
+ switch (twr.step) {
+ case 0:
+ if (TW_STATUS == TW_START) {
+ /* write device address */
+ twWriteRaw (twr.address | TW_WRITE);
+ twFlushRaw ();
+ ++twr.step;
+ } else {
+ twr.status = TWST_ERR;
+ }
+ break;
+
+ case 1:
+ if (TW_STATUS == TW_MT_SLA_ACK) {
+ /* write subaddress, enable auto-increment */
+ twWriteRaw ((1 << 7) | twr.subaddress);
+ twFlushRaw ();
+ ++twr.step;
+ } else {
+ twr.status = TWST_ERR;
+ }
+ break;
+
+ case 2:
+ if (TW_STATUS == TW_MT_DATA_ACK) {
+ /* send repeated start */
+ twStartRaw ();
+ ++twr.step;
+ } else {
+ twr.status = TWST_ERR;
+ }
+ break;
+
+ case 3:
+ if (TW_STATUS == TW_REP_START) {
+ /* now start the actual read request */
+ twWriteRaw (twr.address | TW_READ);
+ twFlushRaw ();
+ ++twr.step;
+ } else {
+ twr.status = TWST_ERR;
+ }
+ break;
+
+ case 4:
+ if (TW_STATUS == TW_MR_SLA_ACK) {
+ /* send master ack if next data block is received */
+ twFlushContRaw ();
+ ++twr.step;
+ } else {
+ twr.status = TWST_ERR;
+ }
+
+ case 5:
+ if (TW_STATUS == TW_MR_DATA_ACK) {
+ twr.retData[twr.i] = TWDR;
+ ++twr.i;
+ if (twr.i < twr.count-1) {
+ /* read another byte, not the last one */
+ twFlushContRaw ();
+ /* step stays the same */
+ } else {
+ /* read last byte, send master nack */
+ twFlushRaw ();
+ ++twr.step;
+ }
+ } else {
+ twr.status = TWST_ERR;
+ }
+ break;
+
+ case 6:
+ if (TW_STATUS == TW_MR_DATA_NACK) {
+ /* receive final byte, send stop */
+ twr.retData[twr.i] = TWDR;
+ twStopRaw ();
+ twr.status = TWST_OK;
+ } else {
+ twr.status = TWST_ERR;
+ }
+ break;
+
+ default:
+ printf ("twIntReadMulti: nope\n");
+ break;
+ }
+}
+
+ISR(TWI_vect) {
+ switch (twr.mode) {
+ case TWM_WRITE:
+ twIntWrite ();
+ break;
+
+ case TWM_READ_MULTI:
+ twIntReadMulti ();
+ break;
+
+ default:
+ printf ("nope\n");
+ break;
+ }
+}
+
diff --git a/i2c.h b/i2c.h
new file mode 100644
index 0000000..1381663
--- /dev/null
+++ b/i2c.h
@@ -0,0 +1,51 @@
+#ifndef TW_H
+#define TW_H
+
+typedef enum {
+ TWM_INVALID = 0,
+ TWM_WRITE,
+ TWM_READ_MULTI,
+} twMode;
+
+typedef enum {
+ TWST_WAIT = 0,
+ TWST_OK = 1,
+ TWST_ERR = 2,
+} twStatus;
+
+#include <stdint.h>
+
+typedef struct {
+ twMode mode;
+ uint8_t address;
+ uint8_t subaddress;
+ uint8_t data;
+ uint8_t step;
+ /* read data store */
+ uint8_t *retData;
+ /* number of bytes to be read */
+ uint8_t count;
+ /* current byte */
+ uint8_t i;
+ twStatus status;
+} twReq;
+
+extern volatile twReq twr;
+
+/* i2c device addresses */
+#define L3GD20 0b11010100
+#define L3GD20_WHOAMI 0xf
+#define L3GD20_CTRLREG1 0x20
+#define LIS302DL 0b00111000
+#define LIS302DL_WHOAMI 0xf
+#define LIS302DL_CTRLREG1 0x20
+
+#include <stdbool.h>
+
+void twInit ();
+bool twWrite (const uint8_t address, const uint8_t subaddress,
+ const uint8_t data);
+bool twReadMulti (const uint8_t address, const uint8_t subaddress,
+ uint8_t * const retData, const uint8_t count);
+
+#endif /* TW_H */
diff --git a/main.c b/main.c
index 62e10d3..6bda270 100644
--- a/main.c
+++ b/main.c
@@ -5,135 +5,13 @@
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <util/delay.h>
-#include <util/twi.h>
#include <stdio.h>
#include <stdbool.h>
-/* i2c device addresses */
-#define L3GD20 0b11010100
-#define L3GD20_WHOAMI 0xf
-#define L3GD20_CTRLREG1 0x20
-#define LIS302DL 0b00111000
-#define LIS302DL_WHOAMI 0xf
-#define LIS302DL_CTRLREG1 0x20
+#include "i2c.h"
+#include "uart.h"
-typedef enum {
- TWM_INVALID = 0,
- TWM_WRITE,
- TWM_READ_MULTI,
-} twMode;
-
-typedef enum {
- TWST_WAIT = 0,
- TWST_OK = 1,
- TWST_ERR = 2,
-} twStatus;
-
-typedef struct {
- twMode mode;
- uint8_t address;
- uint8_t subaddress;
- uint8_t data;
- uint8_t step;
- /* read data store */
- uint8_t *retData;
- /* number of bytes to be read */
- uint8_t count;
- /* current byte */
- uint8_t i;
- twStatus status;
-} twReq;
-
-volatile twReq twr;
-
-void twStartRaw () {
- /* disable stop, enable interrupt, reset twint, enable start, enable i2c */
- TWCR = (TWCR & ~(1 << TWSTO)) | (1 << TWIE) | (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);
-}
-
-void twStopRaw () {
- /* disable start, enable interrupt, reset twint, enable stop, enable i2c */
- TWCR = (TWCR & ~(1 << TWSTA)) | (1 << TWIE) | (1 << TWINT) | (1 << TWSTO) | (1 << TWEN);
-}
-
-void twFlushRaw () {
- /* disable start/stop, enable interrupt, reset twint, enable i2c */
- TWCR = (TWCR & ~((1 << TWSTA) | (1 << TWSTO) | (1 << TWEA))) | (1 << TWIE) | (1 << TWINT) | (1 << TWEN);
-}
-
-/* flush and send master ack */
-void twFlushContRaw () {
- /* disable start/stop, enable interrupt, reset twint, enable i2c, send master ack */
- TWCR = (TWCR & ~((1 << TWSTA) | (1 << TWSTO))) | (1 << TWIE) | (1 << TWINT) | (1 << TWEN) | (1 << TWEA);
-}
-
-void twWaitRaw () {
- while (!(TWCR & (1 << TWINT)));
-}
-
-bool twWriteRaw (uint8_t data) {
- TWDR = data;
- if (TWCR & (1 << TWWC)) {
- printf("write collision\n");
- return false;
- } else {
- return true;
- }
-}
-
-void twInit () {
- /* set scl to 3.6 kHz (at 1Mhz CPU speed)*/
- TWBR = 2;
- TWSR |= 0x3; /* set prescaler to 64 */
-
- twr.mode = TWM_INVALID;
- twr.status = TWST_ERR;
-}
-
-/* high-level write
- */
-static bool twWrite (uint8_t address, uint8_t subaddress, uint8_t data) {
- /* do not start if request is pending */
- if (twr.status == TWST_WAIT) {
- return false;
- }
-
- twr.mode = TWM_WRITE;
- twr.address = address;
- twr.subaddress = subaddress;
- twr.data = data;
- twr.step = 0;
- twr.status = TWST_WAIT;
- /* wait for stop finish */
- while (TW_STATUS != 0xf8);
- twStartRaw ();
-
- return true;
-}
-
-static bool twReadMulti (uint8_t address, uint8_t subaddress,
- uint8_t *retData, uint8_t count) {
- /* do not start if request is pending */
- if (twr.status == TWST_WAIT) {
- return false;
- }
-
- twr.mode = TWM_READ_MULTI;
- twr.address = address;
- twr.subaddress = subaddress;
- twr.retData = retData;
- twr.count = count;
- twr.i = 0;
- twr.step = 0;
- twr.status = TWST_WAIT;
- /* wait for stop finish */
- while (TW_STATUS != 0xf8);
- twStartRaw ();
-
- return true;
-}
-
-void ledInit () {
+static void ledInit () {
/* set led1,led2 to output */
DDRB |= (1 << PB6) | (1 << PB7);
/* set led3,led4,led5,led6 to output */
@@ -141,208 +19,18 @@ void ledInit () {
}
/* show data with leds */
-void ledShow (unsigned char val) {
+static void ledShow (const unsigned char val) {
PORTB = (PORTB & ~((1 << PB6) | (1 << PB7))) | ((val & 0x3) << PB6);
PORTD = (PORTD & ~((1 << PD2) | (1 << PD3) | (1 << PD4) | (1 << PD5))) | (((val >> 2) & 0xf) << PD2);
}
-void uartInit () {
- /* Set baud rate (9600, double speed, at 1mhz) */
- UBRR0H = 0;
- UBRR0L = 12;
- /* enable double speed mode */
- UCSR0A = (1 << U2X0);
- /* Enable receiver and transmitter */
- UCSR0B = (1<<RXEN0)|(1<<TXEN0);
- /* Set frame format: 8 data, 1 stop bit, even parity */
- UCSR0C = (1<<UPM01) | (0 << UPM00) | (0<<USBS0)|(3<<UCSZ00);
-}
-
-/* blocking uart send
- */
-void uartSend (unsigned char data) {
- /* Wait for empty transmit buffer */
- while (!( UCSR0A & (1<<UDRE0)));
- /* Put data into buffer, sends the data */
- UDR0 = data;
-}
-
-int uartPutc (char c, FILE *stream) {
- if (c == '\n') {
- uartSend ('\r');
- }
- uartSend (c);
- return 0;
-}
-
-static FILE mystdout = FDEV_SETUP_STREAM (uartPutc, NULL, _FDEV_SETUP_WRITE);
-
-unsigned char uartReceive () {
- /* Wait for data to be received */
- while ( !(UCSR0A & (1<<RXC0)) );
- /* Get and return received data from buffer */
- return UDR0;
-}
-
-void cpuInit () {
+static void cpuInit () {
/* enter change prescaler mode */
CLKPR = CLKPCE << 1;
/* write new prescaler = 8 (i.e. 1Mhz clock frequency) */
CLKPR = 0b00000011;
}
-/* handle interrupt, write request
- */
-static void twIntWrite () {
- switch (twr.step) {
- case 0:
- if (TW_STATUS == TW_START) {
- twWriteRaw (twr.address | TW_WRITE);
- twFlushRaw ();
- } else {
- twr.status = TWST_ERR;
- }
- break;
-
- case 1:
- if (TW_STATUS == TW_MT_SLA_ACK) {
- twWriteRaw (twr.subaddress);
- twFlushRaw ();
- } else {
- twr.status = TWST_ERR;
- }
- break;
-
- case 2:
- if (TW_STATUS == TW_MT_DATA_ACK) {
- twWriteRaw (twr.data);
- twFlushRaw ();
- } else {
- twr.status = TWST_ERR;
- }
- break;
-
- case 3:
- if (TW_STATUS == TW_MT_DATA_ACK) {
- twStopRaw ();
- twr.status = TWST_OK;
- } else {
- twr.status = TWST_ERR;
- }
- break;
-
- default:
- printf ("nope\n");
- break;
- }
- ++twr.step;
-}
-
-static void twIntReadMulti () {
- switch (twr.step) {
- case 0:
- if (TW_STATUS == TW_START) {
- /* write device address */
- twWriteRaw (twr.address | TW_WRITE);
- twFlushRaw ();
- ++twr.step;
- } else {
- twr.status = TWST_ERR;
- }
- break;
-
- case 1:
- if (TW_STATUS == TW_MT_SLA_ACK) {
- /* write subaddress, enable auto-increment */
- twWriteRaw ((1 << 7) | twr.subaddress);
- twFlushRaw ();
- ++twr.step;
- } else {
- twr.status = TWST_ERR;
- }
- break;
-
- case 2:
- if (TW_STATUS == TW_MT_DATA_ACK) {
- /* send repeated start */
- twStartRaw ();
- ++twr.step;
- } else {
- twr.status = TWST_ERR;
- }
- break;
-
- case 3:
- if (TW_STATUS == TW_REP_START) {
- /* now start the actual read request */
- twWriteRaw (twr.address | TW_READ);
- twFlushRaw ();
- ++twr.step;
- } else {
- twr.status = TWST_ERR;
- }
- break;
-
- case 4:
- if (TW_STATUS == TW_MR_SLA_ACK) {
- /* send master ack if next data block is received */
- twFlushContRaw ();
- ++twr.step;
- } else {
- twr.status = TWST_ERR;
- }
-
- case 5:
- if (TW_STATUS == TW_MR_DATA_ACK) {
- twr.retData[twr.i] = TWDR;
- ++twr.i;
- if (twr.i < twr.count-1) {
- /* read another byte, not the last one */
- twFlushContRaw ();
- /* step stays the same */
- } else {
- /* read last byte, send master nack */
- twFlushRaw ();
- ++twr.step;
- }
- } else {
- twr.status = TWST_ERR;
- }
- break;
-
- case 6:
- if (TW_STATUS == TW_MR_DATA_NACK) {
- /* receive final byte, send stop */
- twr.retData[twr.i] = TWDR;
- twStopRaw ();
- twr.status = TWST_OK;
- } else {
- twr.status = TWST_ERR;
- }
- break;
-
- default:
- printf ("twIntReadMulti: nope\n");
- break;
- }
-}
-
-ISR(TWI_vect) {
- switch (twr.mode) {
- case TWM_WRITE:
- twIntWrite ();
- break;
-
- case TWM_READ_MULTI:
- twIntReadMulti ();
- break;
-
- default:
- printf ("nope\n");
- break;
- }
-}
-
volatile unsigned char count;
ISR(TIMER0_OVF_vect) {
@@ -355,16 +43,13 @@ ISR(TIMER0_OVF_vect) {
while (cond) { sleep_cpu (); } \
sleep_disable ();
-int main(void) {
+int main () {
cpuInit ();
ledInit ();
twInit ();
uartInit ();
set_sleep_mode (SLEEP_MODE_IDLE);
- /* redirect stdout */
- stdout = &mystdout;
-
printf ("initialization done\n");
/* global interrupt enable */
diff --git a/uart.c b/uart.c
new file mode 100644
index 0000000..4b7ca39
--- /dev/null
+++ b/uart.c
@@ -0,0 +1,46 @@
+#include <stdio.h>
+#include <avr/io.h>
+
+#include "uart.h"
+
+/* blocking uart send
+ */
+static void uartSend (unsigned char data) {
+ /* Wait for empty transmit buffer */
+ while (!( UCSR0A & (1<<UDRE0)));
+ /* Put data into buffer, sends the data */
+ UDR0 = data;
+}
+
+static int uartPutc (char c, FILE *stream) {
+ if (c == '\n') {
+ uartSend ('\r');
+ }
+ uartSend (c);
+ return 0;
+}
+
+static FILE mystdout = FDEV_SETUP_STREAM (uartPutc, NULL, _FDEV_SETUP_WRITE);
+
+void uartInit () {
+ /* Set baud rate (9600, double speed, at 1mhz) */
+ UBRR0H = 0;
+ UBRR0L = 12;
+ /* enable double speed mode */
+ UCSR0A = (1 << U2X0);
+ /* Enable receiver and transmitter */
+ UCSR0B = (1<<RXEN0)|(1<<TXEN0);
+ /* Set frame format: 8 data, 1 stop bit, even parity */
+ UCSR0C = (1<<UPM01) | (0 << UPM00) | (0<<USBS0)|(3<<UCSZ00);
+
+ /* redirect stdout */
+ stdout = &mystdout;
+}
+
+static unsigned char uartReceive () {
+ /* Wait for data to be received */
+ while ( !(UCSR0A & (1<<RXC0)) );
+ /* Get and return received data from buffer */
+ return UDR0;
+}
+
diff --git a/uart.h b/uart.h
new file mode 100644
index 0000000..179f582
--- /dev/null
+++ b/uart.h
@@ -0,0 +1,7 @@
+#ifndef UART_H
+#define UART_H
+
+void uartInit ();
+
+#endif /* UART_H */
+