Move master branch from from mios git repo
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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(¤t);
|
||||
*/
|
||||
#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
|
||||
@@ -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(¤t);
|
||||
|
||||
// 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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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(¤t);
|
||||
*/
|
||||
#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
|
||||
@@ -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.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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(¤t);
|
||||
|
||||
// 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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user