Move master branch from from mios git repo

This commit is contained in:
hek
2014-01-23 00:23:15 +01:00
commit 609d9e5be9
352 changed files with 53418 additions and 0 deletions
+63
View File
@@ -0,0 +1,63 @@
/*
* Copyright (c) 2009 Andrew Smallbone <andrew@rocketnumbernine.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <ds1305.h>
#ifdef __cplusplus
extern "C"{
#endif
unsigned char ds1305_transfer(unsigned char address, unsigned char data)
{
select_ds1305();
send_spi(address);
unsigned char out = send_spi(data);
deselect_ds1305();
return out;
}
void ds1305_write_block(unsigned char address, unsigned char *data, int length)
{
select_ds1305();
send_spi(address+DS1305_WRITE);
int i;
for (i=0; i<length; i++) {
send_spi(*data++);
}
deselect_ds1305();
}
void ds1305_read_block(unsigned char address, unsigned char *data, int length)
{
select_ds1305();
send_spi(address);
int i;
for (i=0; i<length; i++) {
*(data+i) = send_spi(0xFF);
}
deselect_ds1305();
}
#ifdef __cplusplus
} // extern "C"
#endif
+115
View File
@@ -0,0 +1,115 @@
/*
* Copyright (c) 2009 Andrew Smallbone <andrew@rocketnumbernine.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef _ds1305_h__
#define _ds1305_h__
#include <spi.h>
#ifdef __cplusplus
extern "C"{
#endif
// these should be defined to the operation used to select/deselect the DS1305
void select_ds1305(void);
void deselect_ds1305(void);
#define DS1305_WRITE 0x80
#define DS1305_TIME 0x00
#define DS1305_ALARM0 0x07
#define DS1305_ALARM1 0x0B
#define DS1305_CONTROL 0x0F
#define DS1305_STATUS 0x010
#define DS1305_CHARGER 0x11
#define DS1305_USERRAM 0x20
#define DS1305_ALARM_SET 0x80
// send the address and a byte and returns the byte returned by the DS1305
unsigned char ds1305_transfer(unsigned char address, unsigned char data);
// write a block of bytes - will add 0x80 to the address
void ds1305_write_block(unsigned char address, unsigned char *data, int length);
// read a block of bytes
void ds1305_read_block(unsigned char address, unsigned char *data, int length);
typedef struct _DS1305_DATETIME
{
unsigned char seconds;
unsigned char minutes;
unsigned char hours;
unsigned char dayofweek;
unsigned char date;
unsigned char month;
unsigned char year;
} DS1305_DATETIME;
/* set/get the current time/date passed the address of a DS1305_DATETIME struct
To set the current time/date to "20:11:32 Sunday 29/07/2009"
DS1305_DATETIME current = {0x32, 0x11, 0x20, 0x01, 0x29, 0x05, 0x09};
set_time(&current);
*/
#define set_time(datetime) ds1305_write_block(DS1305_TIME, (unsigned char *)datetime, 7)
#define get_time(datetime) ds1305_read_block(DS1305_TIME, (unsigned char *)datetime, 7)
/* set/get the time of alarm0/alarm1 passed the address of a DS1305_DATETIME struct,
although only the seconds/minutes/hours/dayofweek are sent/received
*/
#define set_alarm0(time) ds1305_write_block(DS1305_ALARM0, (unsigned char *)time, 4)
#define get_alarm0(time) ds1305_read_block(DS1305_ALARM0, (unsigned char *)time, 4)
#define set_alarm1(time) ds1305_write_block(DS1305_ALARM1, (unsigned char *)time, 4)
#define get_alarm1(time) ds1305_read_block(DS1305_ALARM1, (unsigned char *)time, 4)
// flags used in set_control/get_control
#define DS1305_EOSC 0x80 // enable oscillator, note this is inverse of ^EOSC bit value on chip
#define DS1305_WP 0x40 // write protect
#define DS1305_INTCN 0x04 // enable interrupts
#define DS1305_AIE1 0x02 // alarm0 interrupt enable
#define DS1305_AIE0 0x01 // alarm1 interrupt enable
/* get/set the control register. To enable the oscillator, turn on write protection
and enable all interrupts the following would be used:
set_control(DS1305_EOSC | DS1305_WP | DS1305_INTCN | DS1305_AIE1 | DS1305_AIE0);
*/
#define set_control(data) ds1305_transfer(DS1305_CONTROL+DS1305_WRITE, (data) ^ DS1305_EOSC)
#define get_control(data) (ds1305_transfer(DS1305_CONTROL, 0xFF) ^ DS1305_EOSC)
// flags used in get_status
#define DS1305_IRQF0 0x01 // interrupt 0 request flag - current time has matched alarm 0
#define DS1305_IRQF1 0x02 // interrupt 1 request flag - current time has matched alarm 1
#define get_status(data) ds1305_transfer(DS1305_STATUS, 0xFF)
// flags used in set_charger/get_charger
#define DS1305_CHARGER_OFF 0x5C // no charge - don't combine with other values
#define DS1305_CHARGER_1D2K 0xA5 // 1 diode 2K resistor
#define DS1305_CHARGER_1D4K 0xA6 // 1 diode 4K resistor
#define DS1305_CHARGER_1D8K 0xA7 // 1 diode 8K resistor
#define DS1305_CHARGER_2D2K 0xA1 // 2 diode 2K resistor
#define DS1305_CHARGER_2D4K 0xA2 // 2 diode 4K resistor
#define DS1305_CHARGER_2D8K 0xA3 // 2 diode 8K resistor
/* get/set the charger register */
#define set_charger(data) ds1305_transfer(DS1305_CHARGE+DS1305_WRITE, data)
#define get_charger(data) ds1305_transfer(DS1305_CHARGE, 0xFF)
#ifdef __cplusplus
} // extern "C"
#endif
#endif
+53
View File
@@ -0,0 +1,53 @@
#######################################
# Syntax Coloring Map For SPI
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
DS1305_DATETIME KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
select_ds1305 KEYWORD2
deselect_ds1305 KEYWORD2
set_time KEYWORD2
get_time KEYWORD2
set_control KEYWORD2
get_control KEYWORD2
set_charger KEYWORD2
get_charger KEYWORD2
get_alarm0 KEYWORD2
set_alarm1 KEYWORD2
get_alarm1 KEYWORD2
get_status KEYWORD2
#######################################
# Constants KEYWORD2
#######################################
DS1305_WRITE LITERAL1
DS1305_TIME LITERAL1
DS1305_ALARM0 LITERAL1
DS1305_ALARM1 LITERAL1
DS1305_CONTROL LITERAL1
DS1305_STATUS LITERAL1
DS1305_CHARGER LITERAL1
DS1305_USERRAM LITERAL1
DS1305_ALARM_SET LITERAL1
DS1305_EOSC LITERAL1
DS1305_WP LITERAL1
DS1305_INTCN LITERAL1
DS1305_AIE1 LITERAL1
DS1305_AIE0 LITERAL1
DS1305_IRQF0 LITERAL1
DS1305_IRQF1 LITERAL1
DS1305_CHARGER_OFF LITERAL1
DS1305_CHARGER_1D2K LITERAL1
DS1305_CHARGER_1D4K LITERAL1
DS1305_CHARGER_1D8K LITERAL1
DS1305_CHARGER_2D2K LITERAL1
DS1305_CHARGER_2D4K LITERAL1
DS1305_CHARGER_2D8K LITERAL1
@@ -0,0 +1,79 @@
#include <spi.h>
#include <ds1305.h>
#define DS1305_PIN 4
#define LED_PIN 3
// following two methods required by DS1305 library to select/deselect device
void select_ds1305(void)
{
digitalWrite(DS1305_PIN, HIGH);
}
void deselect_ds1305(void)
{
digitalWrite(DS1305_PIN, LOW);
}
// flash led that's connected to pin 3
void flash_led(void)
{
pinMode(LED_PIN, OUTPUT);
for (int i=0; i<10; i++) {
digitalWrite(LED_PIN, i%2==0);
delay(50);
}
}
// called when pin INT0 goes from 1 to 0
ISR(INT0_vect)
{
// get alarm value to clear alarm interrupt flag on DS1305
DS1305_DATETIME alarm;
get_alarm0(&alarm);
flash_led();
}
void setup()
{
// flash LED at start to indicate were about to start
flash_led();
flash_led();
// pin used to enable DS1305
pinMode(DS1305_PIN, OUTPUT);
// Make sure ADC is unselected and setup spi
deselect_ds1305();
setup_spi(SPI_MODE_1, SPI_MSB, SPI_NO_INTERRUPT, SPI_MSTR_CLK16);
set_control(0);
// set current date/time to Thursday 06/05/09 20:32:30
DS1305_DATETIME current = {0x30, 0x32, 0x20, 0x05, 0x06, 0x05, 0x09};
set_time(&current);
// change the value of alarm to the required time/granularity:
// raise alarm every day (at 20:32:00):
// DS1305_DATETIME alarm = {0x00, 0x32, 0x20, 0x00 | DS1305_ALARM_SET};
// raise alarm every minute (when seconds = 00):
// DS1305_DATETIME alarm = {0x00, 0x32 | DS1305_ALARM_SET,
// 0x20 | DS1305_ALARM_SET, 0x05 | DS1305_ALARM_SET};
// raise alarm every second:
DS1305_DATETIME alarm = {0x55 | DS1305_ALARM_SET, 0x32 | DS1305_ALARM_SET,
0x20 | DS1305_ALARM_SET, 0x05 | DS1305_ALARM_SET};
set_alarm0(&alarm);
// turn on timer and make alarm0 lower INT0 pin when alarm is triggered
set_control(DS1305_EOSC | DS1305_INTCN | DS1305_AIE0);
// raise interrupt when INT0 pin falls (pin PD0 at AT90usbXXX, pin PD2 on ATmegaXXX (arduino pin 2))
// the code in ISR(INT0_vect) above will be called
EICRA = (1<<ISC01) | (0<<ISC00);
// enable interrupts
EIMSK = (1<<INT0);
sei();
}
void loop()
{
// do nothing - all action happens in interrupt
}
@@ -0,0 +1,38 @@
#include <spi.h>
// MAX6675 connected to pin D9
#define MAX6675_SELECT_PIN 8
#define DESELECT_MAX6675 digitalWrite(MAX6675_SELECT_PIN, HIGH)
#define SELECT_MAX6675 digitalWrite(MAX6675_SELECT_PIN, LOW)
void setup()
{
pinMode(MAX6675_SELECT_PIN, OUTPUT);
DESELECT_MAX6675;
setup_spi(SPI_MODE_1, SPI_MSB, SPI_NO_INTERRUPT, SPI_MSTR_CLK8);
Serial.begin(19200);
}
void loop()
{
delay(500);
// select the device, wait > 100nS, read two bytes, deselect
SELECT_MAX6675;
delayMicroseconds(1);
unsigned char highByte = send_spi(0);
unsigned char lowByte = send_spi(0);
DESELECT_MAX6675;
// if bit 3 is high thermocouple is unconnected
if (lowByte & (1<<2)) {
Serial.print("Not connected ");
Serial.print(highByte, HEX); Serial.print(" ");
Serial.println(lowByte, HEX);
} else {
// temperature value is in bits 6-0 of highByte and 7-2 of lowByte
short value = (highByte << 5 | lowByte>>3);
// 1 bit is 0.25 degree 'divide' by 4 to show degrees
Serial.print(value/4); Serial.print("."); Serial.println(value%4 *25);
}
}
@@ -0,0 +1,32 @@
#include <spi.h>
#define SELECT_ADC digitalWrite(8, LOW);
#define DESELECT_ADC digitalWrite(8, HIGH);
unsigned short read_adc(void)
{
// select ADC wait 100microseconds then read two bytes
SELECT_ADC;
unsigned char one = send_spi(0xFF);
unsigned char two = send_spi(0xFF);
DESELECT_ADC;
// 12 bits of ADC value is bottom 5 bits of first
// byte and top 7 bits of second, move into 16 bit int
return ((0x1F & one) << 7) | (two >> 1);
}
void setup()
{
pinMode(8, OUTPUT);
Serial.begin(19200);
// make sure ADC is not selected and setup spi
DESELECT_ADC;
setup_spi(SPI_MODE_0, SPI_MSB, SPI_NO_INTERRUPT, SPI_MSTR_CLK16);
}
void loop()
{
unsigned short num = read_adc();
Serial.println(num);
delay(1000);
}
@@ -0,0 +1,91 @@
#include <spi.h>
#include <util/delay.h>
#define BUTTON_PIN 2
#define LED_PIN 3
#define FLASH_LED_COMMAND 0x01
#define OTHER_SELECT_PIN 7
#define SELECT_OTHER digitalWrite(OTHER_SELECT_PIN, LOW);
#define DESELECT_OTHER digitalWrite(OTHER_SELECT_PIN, HIGH);
#define BUFSIZE 20
volatile unsigned char incoming[BUFSIZE];
volatile short int received=0;
// flash led that's connected to pin PD7
void flash_led(int count)
{
pinMode(LED_PIN, OUTPUT);
for (int i=0; i<count*2; i++) {
digitalWrite(LED_PIN, i%2==0);
_delay_ms(75);
}
}
// send a SPI message to the other device - 3 bytes then go back into
// slave mode
void send_message()
{
setup_spi(SPI_MODE_1, SPI_MSB, SPI_NO_INTERRUPT, SPI_MSTR_CLK8);
if (SPCR & (1<<MSTR)) { // if we are still in master mode
SELECT_OTHER; // tell other device to flash LED twice
send_spi(FLASH_LED_COMMAND); send_spi(0x02); send_spi(0x00);
DESELECT_OTHER;
}
setup_spi(SPI_MODE_1, SPI_MSB, SPI_INTERRUPT, SPI_SLAVE);
}
// called when button pushed and pin INT0 goes from 1 to 0
void button_pressed()
{
send_message();
_delay_ms(500); // 'debounce'
}
// parse the data received from the other device
// currently just knows about the FLASH_LED_COMMAND
void parse_message()
{
switch(incoming[0]) {
case FLASH_LED_COMMAND:
flash_led(incoming[1]);
break;
default:
flash_led(20);
}
}
// called by the SPI system when there is data ready.
// Just store the incoming data in a buffer, when we receive a
// terminating byte (0x00) call parse_message to process the data received
ISR(SPI_STC_vect)
{
incoming[received++] = received_from_spi(0x00);
if (received == BUFSIZE || incoming[received-1] == 0x00) {
parse_message();
received = 0;
}
}
void setup()
{
// make sure other device is unselected (pin is HIGH) and setup spi
DESELECT_OTHER;
pinMode(OTHER_SELECT_PIN, OUTPUT);
setup_spi(SPI_MODE_1, SPI_MSB, SPI_INTERRUPT, SPI_SLAVE);
// raise interrupt when INT0 pin falls (arduino pin 2))
// the function button_pressed will be called
attachInterrupt(0, button_pressed, FALLING);
// flash LED at start to indicate were ready
flash_led(1);
}
void loop()
{
// do nothing
}
@@ -0,0 +1,62 @@
/**
* First stab at a test suite for spi lib.
*/
#include <spi.h>
void reportError(int line, char *message, uint8_t expected, uint8_t actual)
{
Serial.print("Test "); Serial.print(message);
Serial.print(" failed at line "); Serial.print(line-3);
Serial.print(", expected="); Serial.print(expected, BIN);
Serial.print(", actual="); Serial.println(actual, BIN);
}
#define assertEquals(message, expected, actual) \
if (expected != actual) { reportError(__LINE__, message, expected, actual); return; }
#define test_setup_spi(message, eSPCR, eSPSR, mode, dord, interrupt, clock) \
setup_spi(mode, dord, interrupt, clock); \
assertEquals(message, eSPCR, SPCR); \
assertEquals(message, eSPSR, SPSR & 0x01);
void test_registers()
{
// top 4 bits of SPCR - enabled, interrupt, lsb/msb, master/slave
disable_spi();
assertEquals("0", 0x00, SPCR);
test_setup_spi("1", 0xE0, 0x00, SPI_MODE_0, SPI_LSB, SPI_INTERRUPT, SPI_SLAVE);
test_setup_spi("2", 0x60, 0x00, SPI_MODE_0, SPI_LSB, SPI_NO_INTERRUPT, SPI_SLAVE);
test_setup_spi("3", 0x40, 0x00, SPI_MODE_0, SPI_MSB, SPI_NO_INTERRUPT, SPI_SLAVE);
// CPOL/CPHA bits - timing mode
test_setup_spi("4", 0x40, 0x00, SPI_MODE_0, SPI_MSB, SPI_NO_INTERRUPT, SPI_SLAVE);
test_setup_spi("5", 0x44, 0x00, SPI_MODE_1, SPI_MSB, SPI_NO_INTERRUPT, SPI_SLAVE);
test_setup_spi("6", 0x48, 0x00, SPI_MODE_2, SPI_MSB, SPI_NO_INTERRUPT, SPI_SLAVE);
test_setup_spi("7", 0x4C, 0x00, SPI_MODE_3, SPI_MSB, SPI_NO_INTERRUPT, SPI_SLAVE);
// clock
test_setup_spi("9", 0xE0, 1, SPI_MODE_0, SPI_LSB, SPI_INTERRUPT, SPI_MSTR_CLK2);
test_setup_spi("10", 0xE0, 0, SPI_MODE_0, SPI_LSB, SPI_INTERRUPT, SPI_MSTR_CLK4);
test_setup_spi("11", 0xE1, 1, SPI_MODE_0, SPI_LSB, SPI_INTERRUPT, SPI_MSTR_CLK8);
test_setup_spi("12", 0xE1, 0, SPI_MODE_0, SPI_LSB, SPI_INTERRUPT, SPI_MSTR_CLK16);
test_setup_spi("13", 0xE2, 1, SPI_MODE_0, SPI_LSB, SPI_INTERRUPT, SPI_MSTR_CLK32);
test_setup_spi("14", 0xE2, 0, SPI_MODE_0, SPI_LSB, SPI_INTERRUPT, SPI_MSTR_CLK64);
test_setup_spi("15", 0xE3, 0, SPI_MODE_0, SPI_LSB, SPI_INTERRUPT, SPI_MSTR_CLK128);
}
void setup()
{
Serial.begin(19200);
}
void loop()
{
delay(5000);
Serial.println("Running tests");
test_registers();
Serial.println("Run tests");
while(true);
}
+39
View File
@@ -0,0 +1,39 @@
#######################################
# Syntax Coloring Map For SPI
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
#######################################
# Methods and Functions (KEYWORD2)
#######################################
setup_spi KEYWORD2
disable_spi KEYWORD2
send_spi KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
SPI_SS_PIN LITERAL1
SPI_SCK_PIN LITERAL1
SPI_MOSI_PIN LITERAL1
SPI_MISO_PIN LITERAL1
SPI_MODE_0 LITERAL1
SPI_MODE_1 LITERAL1
SPI_MODE_2 LITERAL1
SPI_MODE_3 LITERAL1
SPI_LSB LITERAL1
SPI_MSB LITERAL1
SPI_NO_INTERRUPT LITERAL1
SPI_INTERRUPT LITERAL1
SPI_SLAVE LITERAL1
SPI_MSTR_CLK2 LITERAL1
SPI_MSTR_CLK4 LITERAL1
SPI_MSTR_CLK8 LITERAL1
SPI_MSTR_CLK16 LITERAL1
SPI_MSTR_CLK32 LITERAL1
SPI_MSTR_CLK64 LITERAL1
SPI_MSTR_CLK128 LITERAL1
+74
View File
@@ -0,0 +1,74 @@
/*
* Copyright (c) 2009 Andrew Smallbone <andrew@rocketnumbernine.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <spi.h>
#ifdef __cplusplus
extern "C"{
#endif
#ifdef __ARDUINO__
#include <wiring.h>
#endif
void setup_spi(uint8_t mode, int dord, int interrupt, uint8_t clock)
{
// specify pin directions for SPI pins on port B
if (clock == SPI_SLAVE) { // if slave SS and SCK is input
DDRB &= ~(1<<SPI_MOSI_PIN); // input
DDRB |= (1<<SPI_MISO_PIN); // output
DDRB &= ~(1<<SPI_SS_PIN); // input
DDRB &= ~(1<<SPI_SCK_PIN);// input
} else {
DDRB |= (1<<SPI_MOSI_PIN); // output
DDRB &= ~(1<<SPI_MISO_PIN); // input
DDRB |= (1<<SPI_SCK_PIN);// output
DDRB |= (1<<SPI_SS_PIN);// output
}
SPCR = ((interrupt ? 1 : 0)<<SPIE) // interrupt enabled
| (1<<SPE) // enable SPI
| (dord<<DORD) // LSB or MSB
| (((clock != SPI_SLAVE) ? 1 : 0) <<MSTR) // Slave or Master
| (((mode & 0x02) == 2) << CPOL) // clock timing mode CPOL
| (((mode & 0x01)) << CPHA) // clock timing mode CPHA
| (((clock & 0x02) == 2) << SPR1) // cpu clock divisor SPR1
| ((clock & 0x01) << SPR0); // cpu clock divisor SPR0
SPSR = (((clock & 0x04) == 4) << SPI2X); // clock divisor SPI2X
}
void disable_spi()
{
SPCR = 0;
}
uint8_t send_spi(uint8_t out)
{
SPDR = out;
while (!(SPSR & (1<<SPIF)));
return SPDR;
}
uint8_t received_from_spi(uint8_t data)
{
SPDR = data;
return SPDR;
}
+94
View File
@@ -0,0 +1,94 @@
/*
* Copyright (c) 2009 Andrew Smallbone <andrew@rocketnumbernine.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef _spi_h__
#define _spi_h__
#include <avr/io.h>
#ifdef __cplusplus
extern "C"{
#endif
// create alias for the different SPI chip pins - code assumes all on port B
#if (defined(__AVR_AT90USB82__) || defined(__AVR_AT90USB162__))
#define SPI_SS_PIN PORTB0
#define SPI_SCK_PIN PORTB1
#define SPI_MOSI_PIN PORTB2
#define SPI_MISO_PIN PORTB3
#elif (defined(__AVR_ATmega48__) || defined(_AVR_ATmega88__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__))
#define SPI_SS_PIN PORTB2
#define SPI_SCK_PIN PORTB5
#define SPI_MOSI_PIN PORTB3
#define SPI_MISO_PIN PORTB4
#else
#error unknown processor - add to spi.h
#endif
// SPI clock modes
#define SPI_MODE_0 0x00 /* Sample (Rising) Setup (Falling) CPOL=0, CPHA=0 */
#define SPI_MODE_1 0x01 /* Setup (Rising) Sample (Falling) CPOL=0, CPHA=1 */
#define SPI_MODE_2 0x02 /* Sample (Falling) Setup (Rising) CPOL=1, CPHA=0 */
#define SPI_MODE_3 0x03 /* Setup (Falling) Sample (Rising) CPOL=1, CPHA=1 */
// data direction
#define SPI_LSB 1 /* send least significant bit (bit 0) first */
#define SPI_MSB 0 /* send most significant bit (bit 7) first */
// whether to raise interrupt when data received (SPIF bit received)
#define SPI_NO_INTERRUPT 0
#define SPI_INTERRUPT 1
// slave or master with clock diviser
#define SPI_SLAVE 0xF0
#define SPI_MSTR_CLK4 0x00 /* chip clock/4 */
#define SPI_MSTR_CLK16 0x01 /* chip clock/16 */
#define SPI_MSTR_CLK64 0x02 /* chip clock/64 */
#define SPI_MSTR_CLK128 0x03 /* chip clock/128 */
#define SPI_MSTR_CLK2 0x04 /* chip clock/2 */
#define SPI_MSTR_CLK8 0x05 /* chip clock/8 */
#define SPI_MSTR_CLK32 0x06 /* chip clock/32 */
// setup spi
void setup_spi(uint8_t mode, // timing mode SPI_MODE[0-4]
int dord, // data direction SPI_LSB|SPI_MSB
int interrupt, // whether to raise interrupt on recieve
uint8_t clock); // clock diviser
// disable spi
void disable_spi(void);
// send and receive a byte of data (master mode)
uint8_t send_spi(uint8_t out);
// receive the byte of data waiting on the SPI buffer and
// set the next byte to transfer - for use in slave mode
// when interrupts are enabled.
uint8_t received_from_spi(uint8_t out);
#ifdef __cplusplus
} // extern "C"
#endif
#endif
+17
View File
@@ -0,0 +1,17 @@
# -*- makefile -*-
#TARGET = spi-test-adc
#TARGET = spi-test-rtc
TARGET = spi-test-masterslave
OBJECTS = $(TARGET).o spi.o
CFLAGS = -I../libs
include ./Makefile.mf
DEVICE = at90usb162
CLOCK = 16000000
examples:
make -k TARGET=spi-test-adc clean all
make -k TARGET=spi-test-rtc OBJECTS="spi-test-rtc.o spi.o ds1305.o" clean all
make -k TARGET=spi-test-masterslave clean all
+109
View File
@@ -0,0 +1,109 @@
# Name: Makefile
# This is a prototype Makefile. Modify it according to your needs.
# You should at least check the settings for
# DEVICE ....... The AVR device you compile for
# CLOCK ........ Target AVR clock rate in Hertz
# OBJECTS ...... The object files created from your source files. This list is
# usually the same as the list of source files with suffix ".o".
# PROGRAMMER ... Options to avrdude which define the hardware you use for
# uploading to the AVR and the interface where this hardware
# is connected.
# FUSES ........ Parameters for avrdude to flash the fuses appropriately.
DEVICE = at90usb162
CLOCK = 16000000
PROGRAMMER = -c stk500v2 -P avrdoper
#OBJECTS = $(TARGET).o
FUSES = -U hfuse:w:0xd9:m -U lfuse:w:0x24:m
# ATMega8 fuse bits (fuse bits for other devices are different!):
# Example for 8 MHz internal oscillator
# Fuse high byte:
# 0xd9 = 1 1 0 1 1 0 0 1 <-- BOOTRST (boot reset vector at 0x0000)
# ^ ^ ^ ^ ^ ^ ^------ BOOTSZ0
# | | | | | +-------- BOOTSZ1
# | | | | +---------- EESAVE (set to 0 to preserve EEPROM over chip erase)
# | | | +-------------- CKOPT (clock option, depends on oscillator type)
# | | +---------------- SPIEN (if set to 1, serial programming is disabled)
# | +------------------ WDTON (if set to 0, watchdog is always on)
# +-------------------- RSTDISBL (if set to 0, RESET pin is disabled)
# Fuse low byte:
# 0x24 = 0 0 1 0 0 1 0 0
# ^ ^ \ / \--+--/
# | | | +------- CKSEL 3..0 (8M internal RC)
# | | +--------------- SUT 1..0 (slowly rising power)
# | +------------------ BODEN (if 0, brown-out detector is enabled)
# +-------------------- BODLEVEL (if 0: 4V, if 1: 2.7V)
# Example for 12 MHz external crystal:
# Fuse high byte:
# 0xc9 = 1 1 0 0 1 0 0 1 <-- BOOTRST (boot reset vector at 0x0000)
# ^ ^ ^ ^ ^ ^ ^------ BOOTSZ0
# | | | | | +-------- BOOTSZ1
# | | | | +---------- EESAVE (set to 0 to preserve EEPROM over chip erase)
# | | | +-------------- CKOPT (clock option, depends on oscillator type)
# | | +---------------- SPIEN (if set to 1, serial programming is disabled)
# | +------------------ WDTON (if set to 0, watchdog is always on)
# +-------------------- RSTDISBL (if set to 0, RESET pin is disabled)
# Fuse low byte:
# 0x9f = 1 0 0 1 1 1 1 1
# ^ ^ \ / \--+--/
# | | | +------- CKSEL 3..0 (external >8M crystal)
# | | +--------------- SUT 1..0 (crystal osc, BOD enabled)
# | +------------------ BODEN (if 0, brown-out detector is enabled)
# +-------------------- BODLEVEL (if 0: 4V, if 1: 2.7V)
# Tune the lines below only if you know what you are doing:
AVRDUDE = avrdude $(PROGRAMMER) -p $(DEVICE)
COMPILE = avr-gcc $(CFLAGS) -Wall -std=gnu99 -funsigned-char -funsigned-bitfields -ffunction-sections -fpack-struct -fshort-enums -I. -Os -DF_CPU=$(CLOCK) -mmcu=$(DEVICE)
# symbolic targets:
all: $(TARGET).hex
.c.o:
$(COMPILE) -c $< -o $@
.S.o:
$(COMPILE) -x assembler-with-cpp -c $< -o $@
# "-x assembler-with-cpp" should not be necessary since this is the default
# file type for the .S (with capital S) extension. However, upper case
# characters are not always preserved on Windows. To ensure WinAVR
# compatibility define the file type manually.
.c.s:
$(COMPILE) -S $< -o $@
flash: all
$(AVRDUDE) -U flash:w:$(TARGET).hex:i
fuse:
$(AVRDUDE) $(FUSES)
# Xcode uses the Makefile targets "", "clean" and "install"
install: flash fuse
# if you use a bootloader, change the command below appropriately:
load: all
bootloadHID $(TARGET).hex
clean:
rm -f $(TARGET).hex $(TARGET).elf $(OBJECTS)
# file targets:
$(TARGET).elf: $(OBJECTS)
$(COMPILE) -o $(TARGET).elf $(OBJECTS)
$(TARGET).hex: $(TARGET).elf
rm -f $(TARGET).hex
avr-objcopy -j .text -j .data -O ihex $(TARGET).elf $(TARGET).hex
# If you have an EEPROM section, you must also create a hex file for the
# EEPROM and add it to the "flash" target.
# Targets for code debugging and analysis:
disasm: $(TARGET).elf
avr-objdump -d $(TARGET).elf
cpp:
$(COMPILE) -E $(TARGET).c
+63
View File
@@ -0,0 +1,63 @@
/*
* Copyright (c) 2009 Andrew Smallbone <andrew@rocketnumbernine.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <ds1305.h>
#ifdef __cplusplus
extern "C"{
#endif
unsigned char ds1305_transfer(unsigned char address, unsigned char data)
{
select_ds1305();
send_spi(address);
unsigned char out = send_spi(data);
deselect_ds1305();
return out;
}
void ds1305_write_block(unsigned char address, unsigned char *data, int length)
{
select_ds1305();
send_spi(address+DS1305_WRITE);
int i;
for (i=0; i<length; i++) {
send_spi(*data++);
}
deselect_ds1305();
}
void ds1305_read_block(unsigned char address, unsigned char *data, int length)
{
select_ds1305();
send_spi(address);
int i;
for (i=0; i<length; i++) {
*(data+i) = send_spi(0xFF);
}
deselect_ds1305();
}
#ifdef __cplusplus
} // extern "C"
#endif
+115
View File
@@ -0,0 +1,115 @@
/*
* Copyright (c) 2009 Andrew Smallbone <andrew@rocketnumbernine.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef _ds1305_h__
#define _ds1305_h__
#include <spi.h>
#ifdef __cplusplus
extern "C"{
#endif
// these should be defined to the operation used to select/deselect the DS1305
void select_ds1305(void);
void deselect_ds1305(void);
#define DS1305_WRITE 0x80
#define DS1305_TIME 0x00
#define DS1305_ALARM0 0x07
#define DS1305_ALARM1 0x0B
#define DS1305_CONTROL 0x0F
#define DS1305_STATUS 0x010
#define DS1305_CHARGER 0x11
#define DS1305_USERRAM 0x20
#define DS1305_ALARM_SET 0x80
// send the address and a byte and returns the byte returned by the DS1305
unsigned char ds1305_transfer(unsigned char address, unsigned char data);
// write a block of bytes - will add 0x80 to the address
void ds1305_write_block(unsigned char address, unsigned char *data, int length);
// read a block of bytes
void ds1305_read_block(unsigned char address, unsigned char *data, int length);
typedef struct _DS1305_DATETIME
{
unsigned char seconds;
unsigned char minutes;
unsigned char hours;
unsigned char dayofweek;
unsigned char date;
unsigned char month;
unsigned char year;
} DS1305_DATETIME;
/* set/get the current time/date passed the address of a DS1305_DATETIME struct
To set the current time/date to "20:11:32 Sunday 29/07/2009"
DS1305_DATETIME current = {0x32, 0x11, 0x20, 0x01, 0x29, 0x05, 0x09};
set_time(&current);
*/
#define set_time(datetime) ds1305_write_block(DS1305_TIME, (unsigned char *)datetime, 7)
#define get_time(datetime) ds1305_read_block(DS1305_TIME, (unsigned char *)datetime, 7)
/* set/get the time of alarm0/alarm1 passed the address of a DS1305_DATETIME struct,
although only the seconds/minutes/hours/dayofweek are sent/received
*/
#define set_alarm0(time) ds1305_write_block(DS1305_ALARM0, (unsigned char *)time, 4)
#define get_alarm0(time) ds1305_read_block(DS1305_ALARM0, (unsigned char *)time, 4)
#define set_alarm1(time) ds1305_write_block(DS1305_ALARM1, (unsigned char *)time, 4)
#define get_alarm1(time) ds1305_read_block(DS1305_ALARM1, (unsigned char *)time, 4)
// flags used in set_control/get_control
#define DS1305_EOSC 0x80 // enable oscillator, note this is inverse of ^EOSC bit value on chip
#define DS1305_WP 0x40 // write protect
#define DS1305_INTCN 0x04 // enable interrupts
#define DS1305_AIE1 0x02 // alarm0 interrupt enable
#define DS1305_AIE0 0x01 // alarm1 interrupt enable
/* get/set the control register. To enable the oscillator, turn on write protection
and enable all interrupts the following would be used:
set_control(DS1305_EOSC | DS1305_WP | DS1305_INTCN | DS1305_AIE1 | DS1305_AIE0);
*/
#define set_control(data) ds1305_transfer(DS1305_CONTROL+DS1305_WRITE, (data) ^ DS1305_EOSC)
#define get_control(data) (ds1305_transfer(DS1305_CONTROL, 0xFF) ^ DS1305_EOSC)
// flags used in get_status
#define DS1305_IRQF0 0x01 // interrupt 0 request flag - current time has matched alarm 0
#define DS1305_IRQF1 0x02 // interrupt 1 request flag - current time has matched alarm 1
#define get_status(data) ds1305_transfer(DS1305_STATUS, 0xFF)
// flags used in set_charger/get_charger
#define DS1305_CHARGER_OFF 0x5C // no charge - don't combine with other values
#define DS1305_CHARGER_1D2K 0xA5 // 1 diode 2K resistor
#define DS1305_CHARGER_1D4K 0xA6 // 1 diode 4K resistor
#define DS1305_CHARGER_1D8K 0xA7 // 1 diode 8K resistor
#define DS1305_CHARGER_2D2K 0xA1 // 2 diode 2K resistor
#define DS1305_CHARGER_2D4K 0xA2 // 2 diode 4K resistor
#define DS1305_CHARGER_2D8K 0xA3 // 2 diode 8K resistor
/* get/set the charger register */
#define set_charger(data) ds1305_transfer(DS1305_CHARGE+DS1305_WRITE, data)
#define get_charger(data) ds1305_transfer(DS1305_CHARGE, 0xFF)
#ifdef __cplusplus
} // extern "C"
#endif
#endif
+111
View File
@@ -0,0 +1,111 @@
This directory contains a simple AVR spi helper library that should
run on most AVR microcontrollers which support SPI.
The code is further described at:
http://www.rocketnumbernine.com/2009/04/26/using-spi-on-an-avr-1/ (basics & ADC)
http://www.rocketnumbernine.com/2009/05/12/using-spi-on-an-avr-2/ (RTC)
Any comments/questions to <andrew@rocketnumbernine.com>
Make sure viewing this text in a fixed width font for the tables and diagrams
----------------------------------
Arduino
----------------------------------
The Arduino Directory contains all code required to run on the Arduino.
Simply copy the Arduino/SPI and Arduino/DS1305 directories to the
"hardware/libraries" directory of your Arduino IDE installation and
restart the Arduino IDE. Once restarted there should be
"Sketch->Import Library->SPI" and "Sketch->Import Library->DS1305" menu
entries which can be used to include the spi header files into your project.
"File->Sketchbook->Examples->Library SPI" contains 3 example projects
----------------------------------
AVR GCC
----------------------------------
To use, just copy spi.h and spi.c (and ds1305.c and ds1305.h if using
the DS1305 Real Time Clock chip) to your own project and compile.
Makefile.mf - 'standard' generated make file from AVR GCC
Makefile - Makefile "make examples" will make example programs below:
spi-test-adc.c MC3201 Analogue to Digital convertor example
spi-test-rtc.c DS1305 - Real-Time-Clock/Alarm example
spi-test-masterslave.c Master/Slave communication example
----------------------------------
PINS
----------------------------------
Following are the AVR pins used in the circuits below
ATmegaXXX Arduino AT90usbXXX
MISO PB4 12 PB3
MOSI PB3 11 PB2
SCK PB5 13 PB1
SS PB2 10 PB0
INT0 PD2 2 PD0
----------------------------------
MC3201 12-bit ADC Circuit
----------------------------------
See http://ww1.microchip.com/downloads/en/DeviceDoc/21290D.pdf for full details.
+-----------------+
| MC3201 |
+5V [| Vref Vdd |] +5V
| |
Analogue In [| IN+ CLK |] AVR SCK
| |
Ground [| IN- Dout |] AVR MOSI
| |
Ground [| Vss ^CS |] AVR CE
+-----------------+
For testing purposes "Analogue In" can be connected to the middle wire
of a potentiometer with one outer wire being connected to +5 and the
other to Ground. A 1uF Capacitor should be placed between the analogue
input and ground, and +5V and ground as close to the chip as possible,
but in a pinch the circuit will likely work without.
MOSI/SLCK/CE to the relevant pin on the AVR (MISO is not used) - see above.
----------------------------------
DS1305 Real Time Clock Circuit
----------------------------------
See http://datasheets.maxim-ic.com/en/ds/DS1305.pdf for full details.
Without a battery the following connections can be used:
+-----------------+
| DS1305 |
Ground [| Vcc2 Vcc1 |] +5V
| |
Ground [| Vbat ^PF |] Not Connected
| |
Crystal [| X1 Vccif |] +5V
| |
Crystal [| X2 SDO |] AVR MISO
| |
Not Connected [| N.C. SDI |] AVR MOSI
| |
AVR INT0 [| INT0 SLCK |] AVR SLCK
| |
Not Connected [| INT1 CE |] AVR CE
| |
Ground [| GND SERMODE |] +5V
+-----------------+
MISO/MOSI/SLCK/CE/INT0 to the relevant pin on the AVR - see above.
+61
View File
@@ -0,0 +1,61 @@
/*
* Copyright (c) 2009 Andrew Smallbone <andrew@rocketnumbernine.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <avr/io.h>
#include <util/delay.h>
#include <spi.h>
#define SELECT_ADC PORTB &= ~(1<<PB4)
#define DESELECT_ADC PORTB |= (1<<PB4)
unsigned short read_adc(void)
{
// select ADC wait 100 microseconds then read two bytes
SELECT_ADC;
_delay_us(100);
unsigned char one = send_spi(0xFF);
_delay_us(100);
unsigned char two = send_spi(0xFF);
DESELECT_ADC;
// 12 bits of ADC value is bottom 5 bits of first
// byte and top 7 bits of second, move into 16 bit int
return ((0x1F & one) << 7) | (two >> 1);
}
int main(void)
{
DDRB |= (1<<PB4); // chip select for ADC
// use port D for leds
DDRD = 0xFF;
PORTD = 0x00;
// make sure ADC is unselected and setup spi
SELECT_ADC;
setup_spi(SPI_MODE_0, SPI_MSB, SPI_NO_INTERRUPT, SPI_MSTR_CLK16);
while (1) {
unsigned int num = read_adc();
PORTD = (1<< (num >> 9)); // use the top 3 bytes to turn on LED
_delay_ms(1);
}
}
+88
View File
@@ -0,0 +1,88 @@
#include <avr/interrupt.h>
#include <util/delay.h>
#include <spi.h>
#define FLASH_LED_COMMAND 0x01
#define OTHER_SELECT_PIN PB6
#define SELECT_OTHER PORTB &= ~(1<<OTHER_SELECT_PIN)
#define DESELECT_OTHER PORTB |= (1<<OTHER_SELECT_PIN)
#define BUFSIZE 20
volatile unsigned char incoming[BUFSIZE];
volatile short int received=0;
// flash led that's connected to pin PD7
void flash_led(int count)
{
DDRD |= (1<<PD7);
for (int i=0; i<count*2; i++) {
PORTD ^= (1<<PD7);
_delay_ms(75);
}
}
// send a SPI message to the other device - 3 bytes then go back into
// slave mode
void send_message()
{
setup_spi(SPI_MODE_1, SPI_MSB, SPI_NO_INTERRUPT, SPI_MSTR_CLK8);
if (SPCR & (1<<MSTR)) { // if we are still in master mode
SELECT_OTHER; // tell other device to flash LED twice
send_spi(FLASH_LED_COMMAND); send_spi(0x02); send_spi(0x00);
DESELECT_OTHER;
}
setup_spi(SPI_MODE_1, SPI_MSB, SPI_INTERRUPT, SPI_SLAVE);
}
// called when the button pushed and pin INT0 goes from 1 to 0
ISR(INT0_vect)
{
send_message();
_delay_ms(500); // 'debounce'
}
// parse the data received from the other device
// currently just knows about the FLASH_LED_COMMAND
void parse_message()
{
switch(incoming[0]) {
case FLASH_LED_COMMAND:
flash_led(incoming[1]);
break;
default:
flash_led(20);
}
}
// called by the SPI system when there is data ready.
// Just store the incoming data in a buffer, when we receive a
// terminating byte (0x00) call parse_message to process the data received
ISR(SPI_STC_vect)
{
incoming[received++] = received_from_spi(0x00);
if (received >= BUFSIZE || incoming[received-1] == 0x00) {
parse_message();
received = 0;
}
}
int main(void)
{
// make sure other device is unselected (pin is HIGH) and setup spi
DESELECT_OTHER;
DDRB |= (1<<OTHER_SELECT_PIN);
setup_spi(SPI_MODE_1, SPI_MSB, SPI_INTERRUPT, SPI_SLAVE);
// raise interrupt when the button is pushed and INT0 pin goes
// from 1 to 0 (pin PD0 at AT90usbXXX, pin PD2 on ATmegaXXX,
// arduino pin 2)). The code in ISR(INT0_vect) above will be called
EICRB = (1<<ISC01) | (0<<ISC00);
EIMSK |= (1<<INT0);
sei();
// flash LED at start to indicate were ready
flash_led(1);
while (1); // do nothing
}
+99
View File
@@ -0,0 +1,99 @@
/*
* Copyright (c) 2009 Andrew Smallbone <andrew@rocketnumbernine.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <util/delay.h>
#include <ds1305.h>
// following two methods required by DS1305 library to select/deselect device
void select_ds1305(void)
{
PORTD |= (1<<PD4);
}
void deselect_ds1305(void)
{
PORTD &= ~(1<<PD4);
}
// flash led that's connected to pin PD1
void flash_led(void)
{
DDRD |= (1<<PD1);
for (int i=0; i<10; i++) {
PORTD ^= (1<<PD1);
_delay_ms(50);
}
}
// called when pin INT0 goes from 1 to 0
ISR(INT0_vect)
{
// get alarm value to clear alarm interrupt flag on DS1305
DS1305_DATETIME alarm;
get_alarm0(&alarm);
flash_led();
}
int main(void)
{
// flash LED at start to indicate were about to start
flash_led();
flash_led();
// pin used to enable DS1305
DDRD = (1<<PD4);
// Make sure ADC is unselected and setup spi
deselect_ds1305();
setup_spi(SPI_MODE_1, SPI_MSB, SPI_NO_INTERRUPT, SPI_MSTR_CLK16);
set_control(0);
// set current date/time to Thursday 06/05/09 20:32:30
DS1305_DATETIME current = {0x30, 0x32, 0x20, 0x05, 0x06, 0x05, 0x09};
set_time(&current);
// change the value of alarm to the required time/granularity:
// raise alarm every day (at 20:32:00):
// DS1305_DATETIME alarm = {0x00, 0x32, 0x20, 0x00 | DS1305_ALARM_SET};
// raise alarm every minute (when seconds = 00):
// DS1305_DATETIME alarm = {0x00, 0x32 | DS1305_ALARM_SET,
// 0x20 | DS1305_ALARM_SET, 0x05 | DS1305_ALARM_SET};
// raise alarm every second:
DS1305_DATETIME alarm = {0x55 | DS1305_ALARM_SET, 0x32 | DS1305_ALARM_SET,
0x20 | DS1305_ALARM_SET, 0x05 | DS1305_ALARM_SET};
set_alarm0(&alarm);
// turn on timer and make alarm0 lower INT0 pin when alarm is triggered
set_control(DS1305_EOSC | DS1305_INTCN | DS1305_AIE0);
// raise interrupt when INT0 pin falls (pin PD0 at AT90usbXXX, pin PD2 on ATmegaXXX (arduino pin 2))
// the code in ISR(INT0_vect) above will be called
EICRA = (1<<ISC01) | (0<<ISC00);
// enable interrupts
EIMSK = (1<<INT0);
sei();
while(1);
}
+151
View File
@@ -0,0 +1,151 @@
/*
* Copyright (c) 2009 Andrew Smallbone <andrew@rocketnumbernine.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "spi.h"
#ifdef __cplusplus
extern "C"{
#endif
#ifdef __ARDUINO__
#include <wiring.h>
#endif
#ifndef SPI_SOFT_DRIVER
// hardware driver
void setup_spi(uint8_t mode, int dord, int interrupt, uint8_t clock)
{
// specify pin directions for SPI pins on port B
if (clock == SPI_SLAVE) { // if slave SS and SCK is input
DDRB &= ~(1<<SPI_MOSI_PIN); // input
DDRB |= (1<<SPI_MISO_PIN); // output
DDRB &= ~(1<<SPI_SS_PIN); // input
DDRB &= ~(1<<SPI_SCK_PIN);// input
} else {
DDRB |= (1<<SPI_MOSI_PIN); // output
DDRB &= ~(1<<SPI_MISO_PIN); // input
DDRB |= (1<<SPI_SCK_PIN);// output
DDRB |= (1<<SPI_SS_PIN);// output
}
SPCR = ((interrupt ? 1 : 0)<<SPIE) // interrupt enabled
| (1<<SPE) // enable SPI
| (dord<<DORD) // LSB or MSB
| (((clock != SPI_SLAVE) ? 1 : 0) <<MSTR) // Slave or Master
| (((mode & 0x02) == 2) << CPOL) // clock timing mode CPOL
| (((mode & 0x01)) << CPHA) // clock timing mode CPHA
| (((clock & 0x02) == 2) << SPR1) // cpu clock divisor SPR1
| ((clock & 0x01) << SPR0); // cpu clock divisor SPR0
SPSR = (((clock & 0x04) == 4) << SPI2X); // clock divisor SPI2X
}
void disable_spi()
{
SPCR = 0;
}
uint8_t send_spi(uint8_t out)
{
SPDR = out;
while (!(SPSR & (1<<SPIF)));
return SPDR;
}
uint8_t received_from_spi(uint8_t data)
{
SPDR = data;
return SPDR;
}
#else
// software driver
void setup_spi(uint8_t mode, int dord, int interrupt, uint8_t clock)
{
if(mode) if(dord) if (interrupt) if(clock) {}
// specify pin directions for SPI pins on port B
if (clock == SPI_SLAVE) { // if slave SS and SCK is input
SPI_DDR &= ~(1<<SPI_MOSI_PIN); // input
SPI_DDR |= (1<<SPI_MISO_PIN); // output
// SPI_DDR &= ~(1<<SPI_SS_PIN); // input
SPI_DDR &= ~(1<<SPI_SCK_PIN);// input
} else {
SPI_DDR |= (1<<SPI_MOSI_PIN); // output
SPI_DDR &= ~(1<<SPI_MISO_PIN); // input
SPI_DDR |= (1<<SPI_SCK_PIN);// output
// SPI_DDR |= (1<<SPI_SS_PIN);// output
}
}
void disable_spi()
{
}
uint8_t send_spi(uint8_t tx)
{
uint8_t i = 0;
uint8_t rx = 0;
SPI_PORT &= ~(1 << SPI_SCK_PIN);
_delay_us(50);
//nrf24_sck_digitalWrite(LOW);
for(i=0;i<8;i++)
{
if(tx & (1<<(7-i)))
{
SPI_PORT |= (1 << SPI_MOSI_PIN);
//nrf24_mosi_digitalWrite(HIGH);
}
else
{
SPI_PORT &= ~(1 << SPI_MOSI_PIN);
//nrf24_mosi_digitalWrite(LOW);
}
SPI_PORT |= (1 << SPI_SCK_PIN);
//nrf24_sck_digitalWrite(HIGH);
_delay_us(50);
rx = rx << 1;
if(SPI_PIN & (1 << SPI_MISO_PIN))
//if(nrf24_miso_digitalRead())
{
rx |= 0x01;
}
//nrf24_sck_digitalWrite(LOW);
SPI_PORT &= ~(1 << SPI_SCK_PIN);
}
_delay_us(50);
return rx;
}
//uint8_t received_from_spi(uint8_t data)
//{
//}
#endif
+101
View File
@@ -0,0 +1,101 @@
/*
* Copyright (c) 2009 Andrew Smallbone <andrew@rocketnumbernine.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef _spi_h__
#define _spi_h__
#include <avr/io.h>
#ifdef __cplusplus
extern "C"{
#endif
// create alias for the different SPI chip pins - code assumes all on port B
#if (defined(__AVR_AT90USB82__) || defined(__AVR_AT90USB162__))
#define SPI_SS_PIN PORTB0
#define SPI_SCK_PIN PORTB1
#define SPI_MOSI_PIN PORTB2
#define SPI_MISO_PIN PORTB3
#elif (defined(__AVR_ATmega48__) || defined(_AVR_ATmega88__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__)) \
|| defined(__AVR_ATmega168PA__) || defined(__AVR_ATmega8A__)
#define SPI_PORT PORTB
#define SPI_PIN PINB
#define SPI_DDR DDRB
#define SPI_SS_PIN PORTB2
#define SPI_SCK_PIN PORTB5
#define SPI_MOSI_PIN PORTB3
#define SPI_MISO_PIN PORTB4
#else
#error unknown processor - add to spi.h
#endif
// SPI clock modes
#define SPI_MODE_0 0x00 /* Sample (Rising) Setup (Falling) CPOL=0, CPHA=0 */
#define SPI_MODE_1 0x01 /* Setup (Rising) Sample (Falling) CPOL=0, CPHA=1 */
#define SPI_MODE_2 0x02 /* Sample (Falling) Setup (Rising) CPOL=1, CPHA=0 */
#define SPI_MODE_3 0x03 /* Setup (Falling) Sample (Rising) CPOL=1, CPHA=1 */
// data direction
#define SPI_LSB 1 /* send least significant bit (bit 0) first */
#define SPI_MSB 0 /* send most significant bit (bit 7) first */
// whether to raise interrupt when data received (SPIF bit received)
#define SPI_NO_INTERRUPT 0
#define SPI_INTERRUPT 1
// slave or master with clock diviser
#define SPI_SLAVE 0xF0
#define SPI_MSTR_CLK4 0x00 /* chip clock/4 */
#define SPI_MSTR_CLK16 0x01 /* chip clock/16 */
#define SPI_MSTR_CLK64 0x02 /* chip clock/64 */
#define SPI_MSTR_CLK128 0x03 /* chip clock/128 */
#define SPI_MSTR_CLK2 0x04 /* chip clock/2 */
#define SPI_MSTR_CLK8 0x05 /* chip clock/8 */
#define SPI_MSTR_CLK32 0x06 /* chip clock/32 */
// setup spi
void setup_spi(uint8_t mode, // timing mode SPI_MODE[0-4]
int dord, // data direction SPI_LSB|SPI_MSB
int interrupt, // whether to raise interrupt on recieve
uint8_t clock); // clock diviser
// disable spi
void disable_spi(void);
// send and receive a byte of data (master mode)
uint8_t send_spi(uint8_t out);
// receive the byte of data waiting on the SPI buffer and
// set the next byte to transfer - for use in slave mode
// when interrupts are enabled.
uint8_t received_from_spi(uint8_t out);
#ifdef __cplusplus
} // extern "C"
#endif
#include "spi.c"
#endif