Ajout initial

This commit is contained in:
Arnaud 2016-04-29 11:30:56 +02:00
commit aad2cc40d4
27 changed files with 2321 additions and 0 deletions

228
Makefile Normal file
View file

@ -0,0 +1,228 @@
# Arduino makefile
#
# This makefile allows you to build sketches from the command line
# without the Arduino environment (or Java).
#
# The Arduino environment does preliminary processing on a sketch before
# compiling it. If you're using this makefile instead, you'll need to do
# a few things differently:
#
# - Give your program's file a .cpp extension (e.g. foo.cpp).
#
# - Put this line at top of your code: #include <WProgram.h>
#
# - Write prototypes for all your functions (or define them before you
# call them). A prototype declares the types of parameters a
# function will take and what type of value it will return. This
# means that you can have a call to a function before the definition
# of the function. A function prototype looks like the first line of
# the function, with a semi-colon at the end. For example:
# int digitalRead(int pin);
#
# Instructions for using the makefile:
#
# 1. Copy this file into the folder with your sketch.
#
# 2. Below, modify the line containing "TARGET" to refer to the name of
# of your program's file without an extension (e.g. TARGET = foo).
#
# 3. Modify the line containg "ARDUINO" to point the directory that
# contains the Arduino core (for normal Arduino installations, this
# is the lib/targets/arduino sub-directory).
#
# 4. Modify the line containing "PORT" to refer to the filename
# representing the USB or serial connection to your Arduino board
# (e.g. PORT = /dev/tty.USB0). If the exact name of this file
# changes, you can use * as a wildcard (e.g. PORT = /dev/tty.USB*).
#
# 5. At the command line, change to the directory containing your
# program's file and the makefile.
#
# 6. Type "make" and press enter to compile/verify your program.
#
# 7. Type "make upload", reset your Arduino board, and press enter to
# upload your program to the Arduino board.
#
# $Id$
#Bootloader Port
PORT = /dev/ttyU0
# /dev/serial/by-id/usb-Arduino_LLC_Arduino_Micro-if00
#Device Port (for autoreset)
RESETPORT = /dev/ttyU0
#/dev/serial/by-id/usb-Loupiottes.fr_DMXv3_Micro-if00
TARGET = sonde
SRC = main.c debug.c analog.c rf24.c spi.c lib/Hamming.c lib/HammingCalculateParitySmallAndFast.c onewire.c
CXXSRC =
ASRC = uart.S
MCU = attiny84a
F_CPU = 8000000L
FORMAT = ihex
UPLOAD_RATE = 20000
# Name of this Makefile (used for "make depend").
MAKEFILE = Makefile
# Debugging format.
# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2.
# AVR (extended) COFF requires stabs, plus an avr-objcopy run.
DEBUG = stabs
OPT = s -ffunction-sections -fdata-sections -finline-functions -finline-functions-called-once -finline-small-functions -fmerge-constants -fomit-frame-pointer
# Place -D or -U options here
CDEFS = -DF_CPU=$(F_CPU)
CXXDEFS = -DF_CPU=$(F_CPU)
# Place -I options here
CINCS = -Ilib
CXXINCS = -Ilib
# Compiler flag to set the C Standard level.
# c89 - "ANSI" C
# gnu89 - c89 plus GCC extensions
# c99 - ISO C99 standard (not yet fully implemented)
# gnu99 - c99 plus GCC extensions
CSTANDARD = -std=gnu99
CDEBUG = -g$(DEBUG)
CWARN = -Wall
CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
#CEXTRA = -Wa,-adhlns=$(<:.c=.lst)
CFLAGS = $(CDEFS) $(CINCS) -O$(OPT) $(CWARN) $(CSTANDARD) $(CEXTRA)
CXXFLAGS = $(CDEFS) $(CINCS) -O$(OPT) -fno-exceptions
#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs
LDFLAGS = -lm -Wl,--gc-sections
# Programming support using avrdude. Settings and variables.
AVRDUDE_PROGRAMMER = linuxspi
AVRDUDE_PORT = /dev/spidev0.0
AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex:i
AVRDUDE_FLAGS = -F -pattiny84 -P$(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) -b $(UPLOAD_RATE)
# Program settings
CC = avr-gcc
CXX = avr-g++
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
SIZE = avr-size
NM = avr-nm
AVRDUDE = avrdude
REMOVE = rm -f
MV = mv -f
OPATH = /tmp/sbuild
# Define all object files.
OBJ = $(SRC:%.c=$(OPATH)/%.c.o) $(CXXSRC:.cpp=$(OPATH)/%.cpp.o) $(ASRC:%.S=$(OPATH)/%.S.o)
# Define all listing files.
LST = $(ASRC:.S=.lst) $(CXXSRC:.cpp=.lst) $(SRC:.c=.lst)
# Combine all necessary flags and optional flags.
# Add target processor to flags.
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS)
ALL_CXXFLAGS = -mmcu=$(MCU) -I. $(CXXFLAGS)
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
# Default target.
all: $(OPATH) $(OPATH)/lib build
build: elf hex eep
elf: $(TARGET).elf
hex: $(TARGET).hex
eep: $(TARGET).eep
lss: $(TARGET).lss
sym: $(TARGET).sym
# Program the device.
upload: $(TARGET).hex $(TARGET).eep
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH)
# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
COFFCONVERT=$(OBJCOPY) --debugging \
--change-section-address .data-0x800000 \
--change-section-address .bss-0x800000 \
--change-section-address .noinit-0x800000 \
--change-section-address .eeprom-0x810000
coff: $(TARGET).elf
$(COFFCONVERT) -O coff-avr $(TARGET).elf $(TARGET).cof
extcoff: $(TARGET).elf
$(COFFCONVERT) -O coff-ext-avr $(TARGET).elf $(TARGET).cof
.SUFFIXES: .elf .hex .eep .lss .sym
.elf.hex:
$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@
.elf.eep:
-$(OBJCOPY) -O $(FORMAT) -j .eeprom --set-section-flags=.eeprom=alloc,load \
--no-change-warnings --change-section-lma .eeprom=0 $< $@
# Create extended listing file from ELF output file.
.elf.lss:
$(OBJDUMP) -h -S $< > $@
# Create a symbol table from ELF output file.
.elf.sym:
$(NM) -n $< > $@
# Link: create ELF output file from object files.
$(TARGET).elf: $(OBJ)
$(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS)
$(SIZE) -C --mcu=$(MCU) $@
# Compile: create object files from C++ source files.
$(OPATH)/%.cpp.o: %.cpp
$(CXX) -c -g $(ALL_CXXFLAGS) $< -o $@
# Compile: create object files from C source files.
$(OPATH)/%.c.o: %.c
$(CC) -c -g $(ALL_CFLAGS) $< -o $@
# Compile: create assembler files from C source files.
%.c.s: %.c
$(CC) -S $(ALL_CFLAGS) $< -o $@
# Assemble: create object files from assembler source files.
$(OPATH)/%.S.o: %.S
$(CC) -c $(ALL_ASFLAGS) $< -o $@
$(OPATH) $(OPATH)/lib:
@mkdir -p $@
# Target: clean project.
clean:
$(REMOVE) $(TARGET).hex $(TARGET).eep $(TARGET).cof $(TARGET).elf \
$(TARGET).map $(TARGET).sym $(TARGET).lss \
$(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d)
depend:
if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \
then \
sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \
$(MAKEFILE).$$$$ && \
$(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \
fi
echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \
>> $(MAKEFILE); \
$(CC) -M -mmcu=$(MCU) $(CDEFS) $(CINCS) $(SRC) $(ASRC) >> $(MAKEFILE)
.PHONY: all build elf hex eep lss sym program coff extcoff clean depend

87
analog.c Normal file
View file

@ -0,0 +1,87 @@
#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/eeprom.h>
#include "analog.h"
#define EE_Ref 1 // 4395600L;
unsigned long refval =0;// = 4395600L;
void initADC(){
bitClear(PRR,PRADC); // clearing the ADC Power Reduction bit
// bitSet(ADCSRA,ADEN);
ADCSRA = _BV(ADEN)|_BV(ADPS2)|_BV(ADPS1)|_BV(ADPS0);
}
void stopADC(){
bitClear(ADCSRA,ADEN);
bitSet(PRR,PRADC);
}
static volatile byte ADC_complete;
ISR(ADC_vect) { ADC_complete = true; }
long readADC(){
set_sleep_mode(SLEEP_MODE_ADC);
ADCSRA |= _BV(ADIE);
ADC_complete=false;
sleep_enable();
while(!ADC_complete){sei(); sleep_cpu(); }
sleep_disable();
return ADC;
}
void readref(){
refval = eeprom_read_dword((const uint32_t *)EE_Ref);
}
long readVcc() {
if(refval==0) readref();
long result = 0;
// Read 1.1V reference against AVcc
ADMUX = _BV(MUX5) | _BV(MUX0);
_delay_ms(1); // Wait for Vref to settle
uint8_t i=16 ;
while(i--) result += readADC();
result >>= 2;
//result = 4418850L / result; // Back-calculate AVcc in mV
result = refval / result;
return result;
}
long readtemp(){
// Temp at ADC2, TempVcc at PA3
// switch PA3 on
bitSet(TEMP_SENSOR_VCC_DDR,TEMP_SENSOR_VCC_BIT);
bitSet(TEMP_SENSOR_VCC_PORT,TEMP_SENSOR_VCC_BIT);
long vref=readVcc();
ADMUX = TEMP_SENSOR_ADMUX;
//_delay_ms(1); // Wait for LTM86 to settle
readADC();
long res =0;
uint8_t cpt =16;
while (cpt--) res+= readADC();
res >>= 2;
long temp = vref * res / 4096 ;
// temp = (sqrt(118.548544+0.01388*(1777.3-temp))-10.888)*144.09221902 + 30;
// Serial.print("TEMP ");Serial.println(temp);
// digitalWrite(tempvcc,HIGH);
// Stop Sensor
bitClear(TEMP_SENSOR_VCC_PORT,TEMP_SENSOR_VCC_BIT);
// bitClear(TEMP_SENSOR_VCC_DDR,TEMP_SENSOR_VCC_BIT);
return temp;
}
float calctemp(long t){
return (sqrt(118.548544+0.01388*(1777.3-t))-10.888)*144.09221902 + 30;
}

25
analog.h Normal file
View file

@ -0,0 +1,25 @@
#include "defines.h"
#ifdef __cplusplus
extern "C"{
#endif
#define TEMP_SENSOR_VCC_DDR DDRB
#define TEMP_SENSOR_VCC_PORT PORTB
#define TEMP_SENSOR_VCC_BIT PB1
#define TEMP_SENSOR_ADMUX ( _BV(MUX1) | _BV(MUX0) ) // ADC3 / PA3
void initADC();
void stopADC();
long readADC();
long readVcc();
long readtemp();
float calctemp(long t);
#ifdef __cplusplus
} // extern "C"
#endif

17
crc8.h Normal file
View file

@ -0,0 +1,17 @@
static __inline__ uint8_t
_crc8_ccitt_update(uint8_t __crc, uint8_t __data)
{
uint8_t __i, __pattern;
__asm__ __volatile__ (
" eor %0, %4" "\n\t"
" ldi %1, 8" "\n\t"
" ldi %2, 0x07" "\n\t"
"1: lsl %0" "\n\t"
" brcc 2f" "\n\t"
" eor %0, %2" "\n\t"
"2: dec %1" "\n\t"
" brne 1b" "\n\t"
: "=r" (__crc), "=d" (__i), "=d" (__pattern)
: "0" (__crc), "r" (__data));
return __crc;
}

16
debug.c Normal file
View file

@ -0,0 +1,16 @@
#include "debug.h"
void debug (char* ptr) {
while (*ptr) SerialPutChar(*(ptr++));
}
void debughex (char* ptr,uint8_t len) {
while (len--) {
uint8_t c = *(ptr++);
uint8_t ch= c>>4;
c &= 0x0F;
SerialPutChar(ch>9?ch+'A'-10:ch+'0');
SerialPutChar(c>9?c+'A'-10:c+'0');
}
}

7
debug.h Normal file
View file

@ -0,0 +1,7 @@
#include "uart.h"
#include <stdint.h>
#define DEBUG 1
void debug (char* ptr);
void debughex (char* ptr,uint8_t len);

47
defines.h Normal file
View file

@ -0,0 +1,47 @@
#ifndef defines_h
#define defines_h
#include <stdbool.h>
typedef unsigned int word;
#define bit(b) (1UL << (b))
typedef uint8_t boolean;
typedef uint8_t byte;
#define HIGH 0x1
#define LOW 0x0
#define PI 3.1415926535897932384626433832795
#define HALF_PI 1.5707963267948966192313216916398
#define TWO_PI 6.283185307179586476925286766559
#define DEG_TO_RAD 0.017453292519943295769236907684886
#define RAD_TO_DEG 57.295779513082320876798154814105
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
//#define abs(x) ((x)>0?(x):-(x))
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
#define radians(deg) ((deg)*DEG_TO_RAD)
#define degrees(rad) ((rad)*RAD_TO_DEG)
#define sq(x) ((x)*(x))
#define interrupts() sei()
#define noInterrupts() cli()
#define lowByte(w) ((uint8_t) ((w) & 0xff))
#define highByte(w) ((uint8_t) ((w) >> 8))
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
void setup(void);
void loop(void);
#endif

79
dht11.c Normal file
View file

@ -0,0 +1,79 @@
#include "dht11.h"
#include <inttypes.h>
#include <avr/io.h>
#include <util/delay.h>
#include "defines.h"
int dht11_humidity;
int dht11_temperature;
int dht11_read(){
// Init Timer1 for timekeeping
TIMSK1=0; // no interrupt
TCNT1 = 0; // start at 0
TCCR1A = 0; // nothing to do w timer
TCCR1B = _BV(CS11); // start w 1us tick
// BUFFER TO RECEIVE
uint8_t bits[5];
uint8_t cnt = 7;
uint8_t idx = 0;
// EMPTY BUFFER
for (int i=0; i< 5; i++) bits[i] = 0;
// REQUEST SAMPLE
bitSet(DHT11_DDDR,DHT11_DBIT); //pinMode(pin, OUTPUT);
bitSet(DHT11_DPORT,DHT11_DBIT); // digitalWrite(pin, HIGH);
_delay_ms(30);
bitClear(DHT11_DPORT,DHT11_DBIT); //digitalWrite(pin, LOW);
_delay_ms(18);
bitSet(DHT11_DPORT,DHT11_DBIT); // digitalWrite(pin, HIGH);
_delay_us(20);
bitClear(DHT11_DDDR,DHT11_DBIT); //pinMode(pin, INPUT);
bitSet(DHT11_DPORT,DHT11_DBIT);
// ACKNOWLEDGE or TIMEOUT
unsigned int loopCnt = 10000;
while( bitRead(DHT11_DPIN,DHT11_DBIT) == LOW)
if (loopCnt-- == 0) return DHT11_ERROR_TIMEOUT2;
loopCnt = 10000;
while( bitRead(DHT11_DPIN,DHT11_DBIT) == HIGH)
if (loopCnt-- == 0) return DHT11_ERROR_TIMEOUT2;
// READ OUTPUT - 40 BITS => 5 BYTES or TIMEOUT
for (int i=0; i<40; i++)
{
loopCnt = 10000;
while(bitRead(DHT11_DPIN,DHT11_DBIT) == LOW)
if (loopCnt-- == 0) return DHT11_ERROR_TIMEOUT;
unsigned long t = TCNT1;
loopCnt = 10000;
while(bitRead(DHT11_DPIN,DHT11_DBIT) == HIGH)
if (loopCnt-- == 0) return DHT11_ERROR_TIMEOUT;
unsigned long t2 = TCNT1;
if ((t2 - t) > 40) bits[idx] |= (1 << cnt);
if (cnt == 0) // next byte?
{
cnt = 7; // restart at MSB
idx++; // next byte!
}
else cnt--;
}
// WRITE TO RIGHT VARS
// as bits[1] and bits[3] are allways zero they are omitted in formulas.
dht11_humidity = bits[0];
dht11_temperature = bits[2];
uint8_t sum = bits[0] + bits[2];
if (bits[4] != sum) return DHT11_ERROR_CHECKSUM;
return DHT11_OK;
}

22
dht11.h Normal file
View file

@ -0,0 +1,22 @@
#define DHT11_OK 0
#define DHT11_ERROR_CHECKSUM -1
#define DHT11_ERROR_TIMEOUT -2
#define DHT11_ERROR_TIMEOUT2 -3
#define DHT11_DPIN PINB
#define DHT11_DDDR DDRB
#define DHT11_DPORT PORTB
#define DHT11_DBIT PB2
#ifdef __cplusplus
extern "C"{
#endif
extern int dht11_humidity;
extern int dht11_temperature;
int dht11_read();
#ifdef __cplusplus
} // extern "C"
#endif

1
eeprom Normal file
View file

@ -0,0 +1 @@
0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff

BIN
eeprom.bin Normal file

Binary file not shown.

174
lib/Hamming.c Normal file
View file

@ -0,0 +1,174 @@
/*
Hamming Error-Correcting Code (ECC)
Optimized for avr-gcc 4.8.1 in Atmel AVR Studio 6.2
August 12, 2014
You should include Hamming.c, Hamming.h, and only one of the other Hamming files in your project.
The other Hamming files implement the same methods in different ways, that may be better or worse for your needs.
This was created for LoFi in the TheHackadayPrize contest.
http://hackaday.io/project/1552-LoFi
Copyright 2014 David Cook
RobotRoom.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include <avr/pgmspace.h>
#include "Hamming.h"
/****************************/
/* */
/* Constants and structures */
/* */
/****************************/
#ifndef null
#define null ((void*) 0)
#endif
// If transmitting/writing only, you don't need to include this file.
// If receiving/reading, then this provides the methods to correct bit errors.
#define UNCORRECTABLE 0xFF
#define ERROR_IN_PARITY 0xFE
#define NO_ERROR 0x00
/****************************/
/* */
/* Global variables */
/* */
/****************************/
// Private table. Faster and more compact than multiple if statements.
static const byte _hammingCorrect128Syndrome[16] PROGMEM =
{
NO_ERROR, // 0
ERROR_IN_PARITY, // 1
ERROR_IN_PARITY, // 2
0x01, // 3
ERROR_IN_PARITY, // 4
0x02, // 5
0x04, // 6
0x08, // 7
ERROR_IN_PARITY, // 8
0x10, // 9
0x20, // 10
0x40, // 11
0x80, // 12
UNCORRECTABLE, // 13
UNCORRECTABLE, // 14
UNCORRECTABLE, // 15
};
/****************************/
/* */
/* Private methods */
/* */
/****************************/
// Give a pointer to a received byte,
// and given a nibble difference in parity (parity ^ calculated parity)
// this will correct the received byte value if possible.
// It returns the number of bits corrected:
// 0 means no errors
// 1 means one corrected error
// 3 means corrections not possible
static byte HammingCorrect128Syndrome(byte* value, byte syndrome)
{
// Using only the lower nibble (& 0x0F), look up the bit
// to correct in a table
byte correction = pgm_read_byte(&(_hammingCorrect128Syndrome[syndrome & 0x0F]));
if (correction != NO_ERROR)
{
if (correction == UNCORRECTABLE || value == null)
{
return 3; // Non-recoverable error
}
else
{
if ( correction != ERROR_IN_PARITY)
{
*value ^= correction;
}
return 1; // 1-bit recoverable error;
}
}
return 0; // No errors
}
/****************************/
/* */
/* Public methods */
/* */
/****************************/
// Given a pointer to a received byte and the received parity (as a lower nibble),
// this calculates what the parity should be and fixes the received value if needed.
// It returns the number of bits corrected:
// 0 means no errors
// 1 means one corrected error
// 3 means corrections not possible
byte HammingCorrect128(byte* value, nibble parity)
{
byte syndrome;
if (value == null)
{
return 3; // Non-recoverable error
}
syndrome = HammingCalculateParity128(*value) ^ parity;
if (syndrome != 0)
{
return HammingCorrect128Syndrome(value, syndrome);
}
return 0; // No errors
}
// Given a pointer to a first value and a pointer to a second value and
// their combined given parity (lower nibble first parity, upper nibble second parity),
// this calculates what the parity should be and fixes the values if needed.
// It returns the number of bits corrected:
// 0 means no errors
// 1 means one corrected error
// 2 means two corrected errors
// 3 means corrections not possible
byte HammingCorrect2416(byte* first, byte* second, byte parity)
{
byte syndrome;
if (first == null || second == null)
{
return 3; // Non-recoverable error
}
syndrome = HammingCalculateParity2416(*first, *second) ^ parity;
if (syndrome != 0)
{
return HammingCorrect128Syndrome(first, syndrome) + HammingCorrect128Syndrome(second, syndrome >> 4);
}
return 0; // No errors
}

68
lib/Hamming.h Normal file
View file

@ -0,0 +1,68 @@
/*
Hamming Error-Correcting Code (ECC)
Optimized for avr-gcc 4.8.1 in Atmel AVR Studio 6.2
August 12, 2014
You should include Hamming.c, Hamming.h, and only one of the other Hamming files in your project.
The other Hamming files implement the same methods in different ways, that may be better or worse for your needs.
This was created for LoFi in the TheHackadayPrize contest.
http://hackaday.io/project/1552-LoFi
Copyright 2014 David Cook
RobotRoom.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef _HAMMING_H
#define _HAMMING_H
#ifndef _AVR_H
typedef unsigned char byte;
typedef unsigned char nibble;
#endif
/**** These are needed to transmit and receive ****/
// Given a byte to transmit, this returns the parity as a nibble
nibble HammingCalculateParity128(byte value);
// Given two bytes to transmit, this returns the parity
// as a byte with the lower nibble being for the first byte,
// and the upper nibble being for the second byte.
byte HammingCalculateParity2416(byte first, byte second);
/**** These are needed only to receive ****/
// Given a pointer to a received byte and the received parity (as a lower nibble),
// this calculates what the parity should be and fixes the received value if needed.
// It returns the number of bits corrected:
// 0 means no errors
// 1 means one corrected error
// 3 means corrections not possible
byte HammingCorrect128(byte* value, nibble parity);
// Given a pointer to a first value and a pointer to a second value and
// their combined given parity (lower nibble first parity, upper nibble second parity),
// this calculates what the parity should be and fixes the values if needed.
// It returns the number of bits corrected:
// 0 means no errors
// 1 means one corrected error
// 2 means two corrected errors
// 3 means corrections not possible
byte HammingCorrect2416(byte* first, byte* second, byte parity);
#endif // _HAMMING_H

View file

@ -0,0 +1,67 @@
/*
Hamming Error-Correcting Code (ECC)
Optimized for avr-gcc 4.8.1 in Atmel AVR Studio 6.2
August 12, 2014
You should include Hamming.c, Hamming.h, and only one of the other Hamming files in your project.
The other Hamming files implement the same methods in different ways, that may be better or worse for your needs.
This was created for LoFi in the TheHackadayPrize contest.
http://hackaday.io/project/1552-LoFi
Copyright 2014 David Cook
RobotRoom.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include <avr/pgmspace.h>
#include "Hamming.h"
// This contains all of the precalculated parity values for a byte (8 bits).
// This is very fast, but takes up more program space than calculating on the fly.
static const byte _hammingCalculateParityFast128[256] PROGMEM =
{
0, 3, 5, 6, 6, 5, 3, 0, 7, 4, 2, 1, 1, 2, 4, 7,
9, 10, 12, 15, 15, 12, 10, 9, 14, 13, 11, 8, 8, 11, 13, 14,
10, 9, 15, 12, 12, 15, 9, 10, 13, 14, 8, 11, 11, 8, 14, 13,
3, 0, 6, 5, 5, 6, 0, 3, 4, 7, 1, 2, 2, 1, 7, 4,
11, 8, 14, 13, 13, 14, 8, 11, 12, 15, 9, 10, 10, 9, 15, 12,
2, 1, 7, 4, 4, 7, 1, 2, 5, 6, 0, 3, 3, 0, 6, 5,
1, 2, 4, 7, 7, 4, 2, 1, 6, 5, 3, 0, 0, 3, 5, 6,
8, 11, 13, 14, 14, 13, 11, 8, 15, 12, 10, 9, 9, 10, 12, 15,
12, 15, 9, 10, 10, 9, 15, 12, 11, 8, 14, 13, 13, 14, 8, 11,
5, 6, 0, 3, 3, 0, 6, 5, 2, 1, 7, 4, 4, 7, 1, 2,
6, 5, 3, 0, 0, 3, 5, 6, 1, 2, 4, 7, 7, 4, 2, 1,
15, 12, 10, 9, 9, 10, 12, 15, 8, 11, 13, 14, 14, 13, 11, 8,
7, 4, 2, 1, 1, 2, 4, 7, 0, 3, 5, 6, 6, 5, 3, 0,
14, 13, 11, 8, 8, 11, 13, 14, 9, 10, 12, 15, 15, 12, 10, 9,
13, 14, 8, 11, 11, 8, 14, 13, 10, 9, 15, 12, 12, 15, 9, 10,
4, 7, 1, 2, 2, 1, 7, 4, 3, 0, 6, 5, 5, 6, 0, 3,
};
// Given a byte to transmit, this returns the parity as a nibble
nibble HammingCalculateParity128(byte value)
{
return pgm_read_byte(&(_hammingCalculateParityFast128[value]));
}
// Given two bytes to transmit, this returns the parity
// as a byte with the lower nibble being for the first byte,
// and the upper nibble being for the second byte.
byte HammingCalculateParity2416(byte first, byte second)
{
return (pgm_read_byte(&(_hammingCalculateParityFast128[second]))<<4) | pgm_read_byte(&(_hammingCalculateParityFast128[first]));
}

View file

@ -0,0 +1,99 @@
/*
Hamming Error-Correcting Code (ECC)
Optimized for avr-gcc 4.8.1 in Atmel AVR Studio 6.2
August 12, 2014
You should include Hamming.c, Hamming.h, and only one of the other Hamming files in your project.
The other Hamming files implement the same methods in different ways, that may be better or worse for your needs.
This was created for LoFi in the TheHackadayPrize contest.
http://hackaday.io/project/1552-LoFi
Copyright 2014 David Cook
RobotRoom.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "Hamming.h"
/****************************/
/* */
/* Public methods */
/* */
/****************************/
// This is slower than using a table, but faster than
// using the textbook method.
// Given a byte to transmit, this returns the parity as a nibble
nibble HammingCalculateParity128(byte value)
{
// Exclusive OR is associative and commutative, so order of operations and values does not matter.
nibble parity;
if ( ( value & 1 ) != 0 )
{
parity = 0x3;
}
else
{
parity = 0x0;
}
if ( ( value & 2 ) != 0 )
{
parity ^= 0x5;
}
if ( ( value & 4 ) != 0 )
{
parity ^= 0x6;
}
if ( ( value & 8 ) != 0 )
{
parity ^= 0x7;
}
if ( ( value & 16 ) != 0 )
{
parity ^= 0x9;
}
if ( ( value & 32 ) != 0 )
{
parity ^= 0xA;
}
if ( ( value & 64 ) != 0 )
{
parity ^= 0xB;
}
if ( ( value & 128 ) != 0 )
{
parity ^= 0xC;
}
return parity;
}
// Given two bytes to transmit, this returns the parity
// as a byte with the lower nibble being for the first byte,
// and the upper nibble being for the second byte.
byte HammingCalculateParity2416(byte first, byte second)
{
return (HammingCalculateParity128(second) << 4) | HammingCalculateParity128(first);
}

View file

@ -0,0 +1,64 @@
/*
Hamming Error-Correcting Code (ECC)
Optimized for avr-gcc 4.8.1 in Atmel AVR Studio 6.2
August 12, 2014
You should include Hamming.c, Hamming.h, and only one of the other Hamming files in your project.
The other Hamming files implement the same methods in different ways, that may be better or worse for your needs.
This was created for LoFi in the TheHackadayPrize contest.
http://hackaday.io/project/1552-LoFi
Copyright 2014 David Cook
RobotRoom.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include <avr/pgmspace.h>
#include "Hamming.h"
/****************************/
/* */
/* Global variables */
/* */
/****************************/
// This contains all of the precalculated parity values for a nibble (4 bits).
static const byte _hammingCalculateParityLowNibble[] PROGMEM =
{ 0, 3, 5, 6, 6, 5, 3, 0, 7, 4, 2, 1, 1, 2, 4, 7 };
static const byte _hammingCalculateParityHighNibble[] PROGMEM =
{ 0, 9, 10, 3, 11, 2, 1, 8, 12, 5, 6, 15, 7, 14, 13, 4 };
/****************************/
/* */
/* Public methods */
/* */
/****************************/
// Given a byte to transmit, this returns the parity as a nibble
nibble HammingCalculateParity128(byte value)
{
return pgm_read_byte(&(_hammingCalculateParityLowNibble[value&0x0F])) ^ pgm_read_byte(&(_hammingCalculateParityHighNibble[value >> 4]));
}
// Given two bytes to transmit, this returns the parity
// as a byte with the lower nibble being for the first byte,
// and the upper nibble being for the second byte.
byte HammingCalculateParity2416(byte first, byte second)
{
return HammingCalculateParity128(second) << 4 | HammingCalculateParity128(first);
}

View file

@ -0,0 +1,100 @@
/*
Hamming Error-Correcting Code (ECC)
Optimized for avr-gcc 4.8.1 in Atmel AVR Studio 6.2
August 12, 2014
You should include Hamming.c, Hamming.h, and only one of the other Hamming files in your project.
The other Hamming files implement the same methods in different ways, that may be better or worse for your needs.
This was created for LoFi in the TheHackadayPrize contest.
http://hackaday.io/project/1552-LoFi
Copyright 2014 David Cook
RobotRoom.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "Hamming.h"
// This performs poorly on a processor that can't do multiple shifts in one instruction
#define BitToBool(byte, n) ((byte>>(n-1)) & 1)
// This is a private method that calculates half the parity
// while shifting over any previously calculated parity for another byte.
// This was designed for processors that cannot shift more than one bit place at a time
nibble HammingCalculateParity2416Half(byte value, byte paritySoFar)
{
// Calculate the most significant bit
paritySoFar |= BitToBool(value, 5) ^ BitToBool(value, 6) ^ BitToBool(value, 7) ^ BitToBool(value, 8);
// Shift it over
paritySoFar <<= 1;
// Calculate the next most significant bit
paritySoFar |= BitToBool(value, 2) ^ BitToBool(value, 3) ^ BitToBool(value, 4) ^ BitToBool(value, 8);
// Shift it over, as well as the previously calculated bit
paritySoFar <<= 1;
// Calculate the next most significant bit
paritySoFar |= BitToBool(value, 1) ^ BitToBool(value, 3) ^ BitToBool(value, 4) ^ BitToBool(value, 6) ^ BitToBool(value, 7);
// Shift it over, as well as the previously calculated bits
paritySoFar <<= 1;
// Calculate the least significant bit
paritySoFar |= BitToBool(value, 1) ^ BitToBool(value, 2) ^ BitToBool(value, 4) ^ BitToBool(value, 5) ^ BitToBool(value, 7);
return paritySoFar;
}
// Given a byte to transmit, this returns the parity as a nibble
nibble HammingCalculateParity128(byte value)
{
return HammingCalculateParity2416Half(value, 0);
}
// If your processor can shift multiple bit places in a single instruction, then set this to 1.
// It will be twice as fast.
// If your processor cannot, then set this to 0, otherwise it will be slow and large.
#define CPU_HAS_MULTIPLE_SHIFT_INSTRUCTION 0
#if CPU_HAS_MULTIPLE_SHIFT_INSTRUCTION
// Given two bytes to transmit, this returns the parity
// as a byte with the lower nibble being for the first byte,
// and the upper nibble being for the second byte.
byte HammingCalculateParity2416(byte first, byte second)
{
// This is the textbook way to calculate hamming parity.
return ((BitToBool(first, 1) ^ BitToBool(first, 2) ^ BitToBool(first, 4) ^ BitToBool(first, 5) ^ BitToBool(first, 7))) +
((BitToBool(first, 1) ^ BitToBool(first, 3) ^ BitToBool(first, 4) ^ BitToBool(first, 6) ^ BitToBool(first, 7))<<1) +
((BitToBool(first, 2) ^ BitToBool(first, 3) ^ BitToBool(first, 4) ^ BitToBool(first, 8))<<2) +
((BitToBool(first, 5) ^ BitToBool(first, 6) ^ BitToBool(first, 7) ^ BitToBool(first, 8))<<3) +
((BitToBool(second, 1) ^ BitToBool(second, 2) ^ BitToBool(second, 4) ^ BitToBool(second, 5) ^ BitToBool(second, 7))<<4) +
((BitToBool(second, 1) ^ BitToBool(second, 3) ^ BitToBool(second, 4) ^ BitToBool(second, 6) ^ BitToBool(second, 7))<<5) +
((BitToBool(second, 2) ^ BitToBool(second, 3) ^ BitToBool(second, 4) ^ BitToBool(second, 8))<<6) +
((BitToBool(second, 5) ^ BitToBool(second, 6) ^ BitToBool(second, 7) ^ BitToBool(second, 8))<<7);
}
#else
// Given two bytes to transmit, this returns the parity
// as a byte with the lower nibble being for the first byte,
// and the upper nibble being for the second byte.
byte HammingCalculateParity2416(byte first, byte second)
{
// This makes two calls, one for each byte.
// It passes the result of the second byte into the calculation for the first
// such that the four shift instructions and the 'or' instruction are free.
return HammingCalculateParity2416Half(first, HammingCalculateParity2416Half(second, 0) << 1);
}
#endif

277
main.c Normal file
View file

@ -0,0 +1,277 @@
#include <avr/io.h>
#include <avr/sleep.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>
#include <avr/power.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
#include <util/delay.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#include "debug.h"
#include "analog.h"
//#include "dht11.h"
#include "rf24.h"
#include "lib/Hamming.h"
#include "crc8.h"
#include "onewire.h"
#define EE_Num 0
uint8_t ADDR[5]={0xE7,0xE7,0xE7,0xE7,0xE7}; //{0xE7,0xE7,0xE7,0xE7,0xE7}; //
#define PKTLEN 24
#define CMD_DATA 0x20
#define CMD_BIN 0x30
#ifdef DEBUG
char debugbuf[32];
uint16_t totaltime;
#endif
char buffer[18];
char* text = buffer +4;
uint8_t sendbuffer[24];
uint8_t id;
uint8_t pid=0;
volatile bool wdt_flag=false;
volatile bool pcint_flag=false;
ISR(WATCHDOG_vect){
wdt_flag=true;
}
ISR(PCINT0_vect){
pcint_flag = true;
}
void sleep(){
#ifdef DEBUG
uint16_t time = TCNT1;
totaltime +=time;
//debughex(&time,2);
#endif
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
cli();
sleep_enable();
//sleep_bod_disable();
sei();
sleep_cpu();
sleep_disable();
#ifdef DEBUG
TCCR1A =0;
TCCR1C =0;
TCNT1 = 0;
TCCR1B = 2;
#endif
}
void wait_for_next(){
int cnt=6;
#ifdef DEBUG
cnt=2;
#endif
while (cnt--){
wdt_enable(WDTO_8S);
WDTCSR |= _BV(WDIE);
sleep();
}
cnt = rand()%6;
while (cnt--){
wdt_enable(WDTO_1S);
WDTCSR |= _BV(WDIE);
sleep();
}
#ifdef DEBUG
debughex(&totaltime,2);
totaltime=0;
debug("\r");
#endif
}
void power_down(){
stopADC();
power_all_disable();
}
void wait_for_radio(){
wdt_enable(WDTO_120MS);
wdt_flag=false;
pcint_flag = false;
cli();
// Sleep until radio ready or wdt 60ms
while (bit_is_set(PINA,PA7) || (!wdt_flag) ){
WDTCSR |= _BV(WDIE);
sleep();
cli(); // disable interrupts before testing wdt_flag
}
// disable radio -> low power until next tx
rf24_powerDown();
if(!wdt_flag) // radio ok... wait until 60ms
{
WDTCSR |= _BV(WDIE); // reenable wdt interrupt
sleep();
}
return;
}
void setupRadio(){
// Static values in ram.
rf24_CONFIG = 0;
rf24_RF_CH = 90;
rf24_RF_SETUP = 0x26;
rf24_FEATURE = 0;//_BV(EN_DPL)|_BV(EN_ACK_PAY)|_BV(EN_DYN_ACK);
rf24_DYNPD = 0x00;
rf24_RX_PW[0]=PKTLEN;
rf24_RX_PW[1]=PKTLEN;
rf24_SETUP_RETR = 0x00;
rf24_EN_AA = 0x00;
}
void initRadio(){
power_usi_enable();
rf24_init();
rf24_writeRegister(RX_ADDR_P0,(uint8_t*)ADDR,5);
rf24_writeRegister(TX_ADDR,(uint8_t*)ADDR,5);
}
void txData(){
uint8_t crc,cpt,a,b,len;
uint8_t *in, *out;
// Pkt ID
buffer[1] = id;
buffer[2] = pid++;
len = buffer[0] & 0x0F;
#ifdef DEBUG
debughex(buffer,len);
debug("\r");
#endif
// CRC Calc
buffer[3] = 0; // CRC =0 in crc calc;
crc=0; cpt= len; in=(uint8_t*)buffer;
while(cpt--) crc = _crc8_ccitt_update(crc,*(in++));
buffer[3] = crc;
// Hamming compute
cpt= len ;
if(cpt & 1) buffer[cpt++]=0; // odd number => add one 0
cpt/=2; in=(uint8_t*)buffer; out = sendbuffer;
while(cpt--){
a = *(out++)= *(in++);
b = *(out++)= *(in++);
*(out++) = HammingCalculateParity2416(a,b);
}
cpt=4;
while (cpt--){
rf24_send(sendbuffer,PKTLEN);
wait_for_radio();
}
}
int main(void)
{
#ifdef DEBUG
DDRB |= _BV(PB0);
debug("Sonde Start \r");
#endif
uint8_t rvcc=0;
int vcc;
// Setup
power_down();
setupRadio();
id = eeprom_read_byte((const uint8_t*)EE_Num);
// random seed
initADC();
srand((int)readVcc() * id );
DDRB |= _BV(PB1) ;
PORTB &= ~_BV(PB1);
while(1){
if(!(rvcc--)){
initADC();
// Read VCC
vcc = readVcc();
stopADC();
rvcc=4;
}
// Do 8 temp reads over 4s
/* int i = 7;
long lt=readtemp();
while(i--){
power_down();
wdt_enable(WDTO_500MS);
WDTCSR |= _BV(WDIE);
sleep();
power_up();
initADC();
lt += readtemp();
}
wdt_enable(WDTO_8S);
float temp = calctemp(lt / 8);*/
w1_start();
wdt_enable(WDTO_15MS);
WDTCSR |= _BV(WDIE);
sleep();
start_meas();
wdt_enable(WDTO_1S);
WDTCSR |= _BV(WDIE);
sleep();
uint16_t t_i = read_meas();//=temp*100;
w1_stop();
// Send data
initRadio();
buffer[0] = 0x0A | CMD_BIN; // 10 octets :
*(uint16_t*)(buffer+4) = 0x0002; // BIN v2 = vcc+tempDS
*(uint16_t*)(buffer+6) = vcc; // 2 o
*(uint16_t*)(buffer+8) = t_i; // 2 o
txData(buffer);
//radio off
rf24_powerDown();
power_down();
wait_for_next();
}
}

125
nRF24L01.h Normal file
View file

@ -0,0 +1,125 @@
/*
Copyright (c) 2007 Stefan Engelke <mbox@stefanengelke.de>
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.
*/
/* Memory Map */
#define CONFIG 0x00
#define EN_AA 0x01
#define EN_RXADDR 0x02
#define SETUP_AW 0x03
#define SETUP_RETR 0x04
#define RF_CH 0x05
#define RF_SETUP 0x06
#define STATUS 0x07
#define OBSERVE_TX 0x08
#define CD 0x09
#define RX_ADDR_P0 0x0A
#define RX_ADDR_P1 0x0B
#define RX_ADDR_P2 0x0C
#define RX_ADDR_P3 0x0D
#define RX_ADDR_P4 0x0E
#define RX_ADDR_P5 0x0F
#define TX_ADDR 0x10
#define RX_PW_P0 0x11
#define RX_PW_P1 0x12
#define RX_PW_P2 0x13
#define RX_PW_P3 0x14
#define RX_PW_P4 0x15
#define RX_PW_P5 0x16
#define FIFO_STATUS 0x17
#define DYNPD 0x1C
#define FEATURE 0x1D
/* Bit Mnemonics */
#define MASK_RX_DR 6
#define MASK_TX_DS 5
#define MASK_MAX_RT 4
#define EN_CRC 3
#define CRCO 2
#define PWR_UP 1
#define PRIM_RX 0
#define ENAA_P5 5
#define ENAA_P4 4
#define ENAA_P3 3
#define ENAA_P2 2
#define ENAA_P1 1
#define ENAA_P0 0
#define ERX_P5 5
#define ERX_P4 4
#define ERX_P3 3
#define ERX_P2 2
#define ERX_P1 1
#define ERX_P0 0
#define AW 0
#define ARD 4
#define ARC 0
#define PLL_LOCK 4
#define RF_DR 3
#define RF_PWR 6
#define RX_DR 6
#define TX_DS 5
#define MAX_RT 4
#define RX_P_NO 1
#define TX_FULL 0
#define PLOS_CNT 4
#define ARC_CNT 0
#define TX_REUSE 6
#define FIFO_FULL 5
#define TX_EMPTY 4
#define RX_FULL 1
#define RX_EMPTY 0
#define DPL_P5 5
#define DPL_P4 4
#define DPL_P3 3
#define DPL_P2 2
#define DPL_P1 1
#define DPL_P0 0
#define EN_DPL 2
#define EN_ACK_PAY 1
#define EN_DYN_ACK 0
/* Instruction Mnemonics */
#define R_REGISTER 0x00
#define W_REGISTER 0x20
#define REGISTER_MASK 0x1F
#define ACTIVATE 0x50
#define R_RX_PL_WID 0x60
#define R_RX_PAYLOAD 0x61
#define W_TX_PAYLOAD 0xA0
#define W_ACK_PAYLOAD 0xA8
#define FLUSH_TX 0xE1
#define FLUSH_RX 0xE2
#define REUSE_TX_PL 0xE3
#define NOP 0xFF
/* Non-P omissions */
#define LNA_HCURR 0
/* P model memory Map */
#define RPD 0x09
/* P model bit Mnemonics */
#define RF_DR_LOW 5
#define RF_DR_HIGH 3
#define RF_PWR_LOW 1
#define RF_PWR_HIGH 2

231
onewire.c Normal file
View file

@ -0,0 +1,231 @@
/*
Access Dallas 1-Wire Devices with ATMEL AVRs
Author of the initial code: Peter Dannegger (danni(at)specs.de)
modified by Martin Thomas (mthomas(at)rhrk.uni-kl.de)
9/2004 - use of delay.h, optional bus configuration at runtime
10/2009 - additional delay in ow_bit_io for recovery
5/2010 - timing modifcations, additonal config-values and comments,
use of atomic.h macros, internal pull-up support
7/2010 - added method to skip recovery time after last bit transfered
via ow_command_skip_last_recovery
*/
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "onewire.h"
#define NULL 0
inline void OUT_LOW(void){
W1_DDR |= _BV(W1_PIN); // OUT
W1_OUT &= ~(_BV(W1_PIN)); // LOW
}
inline void OUT_HIGH(void){
W1_DDR |= _BV(W1_PIN); // OUT
W1_OUT |= _BV(W1_PIN); // HIGH
}
inline void PULL_UP(void){
W1_DDR &= ~(_BV(W1_PIN));
W1_OUT |= _BV(W1_PIN); // pull up
}
uint8_t w1_reset(void)
{
uint8_t err;
OUT_LOW();
_delay_us(480);
cli();
PULL_UP();
_delay_us(66);
err = bit_is_set(W1_IN,W1_PIN); // no presence detect
sei();
_delay_us(414); // 480 - 66
if( bit_is_clear(W1_IN,W1_PIN)) // short circuit
err = 1;
OUT_HIGH();
return err;
}
uint8_t w1_bit_io(uint8_t b)
{
cli();
OUT_LOW();
_delay_us(1);
if( b ){
PULL_UP();
}
_delay_us(14); // 15 - 1
if( bit_is_clear(W1_IN,W1_PIN))
b = 0;
_delay_us(45); // 60 - 15
OUT_HIGH();
sei();
return b;
}
uint8_t w1_byte_wr(uint8_t b)
{
uint8_t i = 8, j;
do{
j = w1_bit_io( b & 1 );
b >>= 1;
if( j )
b |= 0x80;
}while( --i );
return b;
}
uint8_t w1_byte_rd(void)
{
return w1_byte_wr( 0xFF );
}
uint8_t w1_rom_search(uint8_t diff, uint8_t* id)
{
uint8_t i, j, next_diff;
uint8_t b;
if( w1_reset() )
return PRESENCE_ERR; // error, no device found
w1_byte_wr( SEARCH_ROM ); // ROM search command
next_diff = LAST_DEVICE; // unchanged on last device
i = 8 * 8; // 8 bytes
do{
j = 8; // 8 bits
do{
b = w1_bit_io( 1 ); // read bit
if( w1_bit_io( 1 ) ){ // read complement bit
if( b ) // 11
return DATA_ERR; // data error
}else{
if( !b ){ // 00 = 2 devices
if( diff > i ||
((*id & 1) && diff != i) ){
b = 1; // now 1
next_diff = i; // next pass 0
}
}
}
w1_bit_io( b ); // write bit
*id >>= 1;
if( b ) // store bit
*id |= 0x80;
i--;
}while( --j );
id++; // next byte
}while( i );
return next_diff; // to continue search
}
void w1_stop()
{
//W1_DDR |= 1<<W1_PIN; // Output
W1_OUT &= ~(_BV(W1_PIN));
W1_DDR &= ~(_BV(W1_PIN));
}
void w1_start()
{
OUT_HIGH();
}
void w1_command(uint8_t command, uint8_t* id)
{
uint8_t i;
w1_reset();
if( id ){
w1_byte_wr( MATCH_ROM ); // to a single device
i = 8;
do{
w1_byte_wr( *id );
id++;
}while( --i );
}else{
w1_byte_wr( SKIP_ROM ); // to all devices
}
w1_byte_wr( command );
}
void start_meas(void)
{
if (bit_is_set(W1_IN,W1_PIN)) {
w1_command( CONVERT_T, NULL );
OUT_HIGH();
}
}
uint16_t read_meas(void)
{
/* uint8_t id[8], diff;
//uint8_t s[30];
uint8_t i;*/
uint16_t temp = 0;
/*for( diff = SEARCH_FIRST; diff != LAST_DEVICE; ){
diff = w1_rom_search( diff, id );
if( diff == PRESENCE_ERR ){
//uputsnl( "No Sensor found" );
return -1;
}
if( diff == DATA_ERR ){
//uputsnl( "Bus Error" );
return -2;
}
if( id[0] == 0x28 || id[0] == 0x10 ){ // temperature sensor
//uputs( "ID: " );
for( i = 0; i < 8; i++ ){
//sprintf( s, "%02X ", id[i] );
//uputs( s );
}
w1_byte_wr( READ ); // read command
temp = w1_byte_rd(); // low byte
temp |= (uint16_t)w1_byte_rd() << 8; // high byte
if( id[0] == 0x10 ) // 9 -> 12 bit
temp <<= 3;
//sprintf( s, " T: %04X = ", temp ); // hex value
//uputs( s );
//sprintf( s, "%4d.%01d¯C", temp >> 4, (temp << 12) / 6553 ); // 0.1¯C
//uputsnl( s );
}
}*/
//uputsnl( "" );
if(w1_reset()) return -1;
//w1_command(SKIP_ROM,NULL);
w1_byte_wr( SKIP_ROM );
w1_byte_wr( READ );
temp = w1_byte_rd();
temp |= (uint16_t)w1_byte_rd() << 8;
// temp <<= 3;
return temp ;//(temp >> 4) * 100 + ((temp << 12) / 6553) * 10;
//return temp >> 4;
}

57
onewire.h Normal file
View file

@ -0,0 +1,57 @@
/*
Access Dallas 1-Wire Devices with ATMEL AVRs
Author of the initial code: Peter Dannegger (danni(at)specs.de)
modified by Martin Thomas (mthomas(at)rhrk.uni-kl.de)
9/2004 - use of delay.h, optional bus configuration at runtime
10/2009 - additional delay in ow_bit_io for recovery
5/2010 - timing modifcations, additonal config-values and comments,
use of atomic.h macros, internal pull-up support
7/2010 - added method to skip recovery time after last bit transfered
via ow_command_skip_last_recovery
*/
#ifndef ONEWIRE_H__
#define ONEWIRE_H__
#define W1_PIN PA0
#define W1_IN PINA
#define W1_OUT PORTA
#define W1_DDR DDRA
#define MATCH_ROM 0x55
#define SKIP_ROM 0xCC
#define SEARCH_ROM 0xF0
#define CONVERT_T 0x44 // DS1820 commands
#define READ 0xBE
#define WRITE 0x4E
#define EE_WRITE 0x48
#define EE_RECALL 0xB8
#define SEARCH_FIRST 0xFF // start new search
#define PRESENCE_ERR 0xFF
#define DATA_ERR 0xFE
#define LAST_DEVICE 0x00 // last device found
// 0x01 ... 0x40: continue searching
uint8_t w1_reset(void);
uint8_t w1_byte_wr(uint8_t b);
uint8_t w1_byte_rd(void);
uint8_t w1_rom_search(uint8_t diff, uint8_t* id);
void w1_stop();
void w1_start();
void w1_command(uint8_t command, uint8_t* id);
// temperature
void start_meas(void);
uint16_t read_meas(void);
#endif // ONEWIRE_H__

270
rf24.c Normal file
View file

@ -0,0 +1,270 @@
#include "rf24.h"
#include <util/delay.h>
uint8_t PTX=0;
uint8_t rf24_CONFIG = _BV(EN_CRC) | _BV(CRCO);
uint8_t rf24_EN_AA = 0x3F; //ENAA_P0 - ENAA_P5
uint8_t rf24_EN_RXADDR = _BV(ERX_P0)|_BV(ERX_P1);
uint8_t rf24_SETUP_AW = 0x03; // 5 bytes addresses
uint8_t rf24_SETUP_RETR = 0x03;
uint8_t rf24_RF_CH = 0x02; // Channel
uint8_t rf24_RF_SETUP = _BV(RF_DR_HIGH) | _BV(RF_PWR_LOW) | _BV(RF_PWR_HIGH);
uint8_t rf24_FEATURE = 0;
uint8_t rf24_DYNPD= 0;
uint8_t rf24_RX_PW[6] = { 32,32,0,0,0,0 };
void inline rf24_ceHi(){
//CE_PIN_PORT |= _BV(CE_PIN_BIT);
}
void inline rf24_ceLow(){
//CE_PIN_PORT &= ~_BV(CE_PIN_BIT);
}
void inline rf24_csnHi(){
CSN_PIN_PORT |= _BV(CSN_PIN_BIT);
}
void inline rf24_csnLow(){
CSN_PIN_PORT &= ~_BV(CSN_PIN_BIT);
}
void rf24_init()
{
//CE_PIN_DDR |= _BV(CE_PIN_BIT);
CSN_PIN_DDR |= _BV(CSN_PIN_BIT);
rf24_ceLow();
rf24_csnHi();
// Initialize spi module
spi_begin();
_delay_ms(2);
rf24_configure();
}
void inline rf24_transferSync(uint8_t *dataout,uint8_t *datain,uint8_t len){
uint8_t i;
for(i = 0;i < len;i++){
datain[i] = spi_transfer(dataout[i]);
}
}
void inline rf24_transmitSync(uint8_t *dataout,uint8_t len){
uint8_t i;
for(i = 0;i < len;i++){
spi_transfer(dataout[i]);
}
}
void inline rf24_configRegister(uint8_t reg, uint8_t value)
// Clocks only one byte into the given MiRF register
{
rf24_csnLow();
spi_transfer(W_REGISTER | (REGISTER_MASK & reg));
spi_transfer(value);
rf24_csnHi();
}
void inline rf24_readRegister(uint8_t reg, uint8_t * value, uint8_t len)
// Reads an array of bytes from the given start position in the MiRF registers.
{
rf24_csnLow();
spi_transfer(R_REGISTER | (REGISTER_MASK & reg));
rf24_transferSync(value,value,len);
rf24_csnHi();
}
void inline rf24_writeRegister(uint8_t reg, uint8_t * value, uint8_t len)
// Writes an array of bytes into inte the MiRF registers.
{
rf24_csnLow();
spi_transfer(W_REGISTER | (REGISTER_MASK & reg));
rf24_transmitSync(value,len);
rf24_csnHi();
}
void rf24_getData(uint8_t * data,uint8_t len)
{
rf24_csnLow(); // Pull down chip select
spi_transfer( R_RX_PAYLOAD ); // Send cmd to read rx payload
rf24_transferSync(data,data,len); // Read payload
rf24_csnHi(); // Pull up chip select
// NVI: per product spec, p 67, note c:
// "The RX_DR IRQ is asserted by a new packet arrival event. The procedure
// for handling this interrupt should be: 1) read payload through SPI,
// 2) clear RX_DR IRQ, 3) read FIFO_STATUS to check if there are more
// payloads available in RX FIFO, 4) if there are more data in RX FIFO,
// repeat from step 1)."
// So if we're going to clear RX_DR here, we need to check the RX FIFO
// in the dataReady() function
rf24_configRegister(STATUS,(1<<RX_DR)); // Reset status register
}
uint8_t rf24_getDataDL(uint8_t * data,uint8_t len)
// Reads payload bytes into data array
{
uint8_t to_read;
rf24_csnLow(); // Pull down chip select
spi_transfer( R_RX_PL_WID ); // Send cmd to read rx payload len
to_read = spi_transfer(0); // Read payload
rf24_csnHi(); // Pull up chip select
if(len>to_read && to_read>0 ) len=to_read;
rf24_csnLow(); // Pull down chip select
spi_transfer( R_RX_PAYLOAD ); // Send cmd to read rx payload
rf24_transferSync(data,data,len); // Read payload
if(to_read!=len){
to_read-=len;
while((to_read--)>0) // read remaining
spi_transfer(0);
}
rf24_csnHi(); // Pull up chip select
// NVI: per product spec, p 67, note c:
// "The RX_DR IRQ is asserted by a new packet arrival event. The procedure
// for handling this interrupt should be: 1) read payload through SPI,
// 2) clear RX_DR IRQ, 3) read FIFO_STATUS to check if there are more
// payloads available in RX FIFO, 4) if there are more data in RX FIFO,
// repeat from step 1)."
// So if we're going to clear RX_DR here, we need to check the RX FIFO
// in the dataReady() function
rf24_configRegister(STATUS,(1<<RX_DR)); // Reset status register
return to_read;
}
uint8_t inline rf24_dataReady()
// Checks if data is available for reading
{
// See note in getData() function - just checking RX_DR isn't good enough
uint8_t status = rf24_getStatus();
// We can short circuit on RX_DR, but if it's not set, we still need
// to check the FIFO for any pending packets
if ( status & (1 << RX_DR) ) return 1;
return !rf24_rxFifoEmpty();
}
uint8_t inline rf24_rxFifoEmpty(){
uint8_t fifoStatus;
rf24_readRegister(FIFO_STATUS,&fifoStatus,sizeof(fifoStatus));
return (fifoStatus & (1 << RX_EMPTY));
}
void rf24_send(uint8_t * value,uint8_t len)
// Sends a data package to the default address. Be sure to send the correct
// amount of bytes as configured as payload on the receiver.
{
uint8_t status;
status = rf24_getStatus();
if((status & ((1 << TX_DS) | (1 << MAX_RT)))){
rf24_configRegister(STATUS,(1 << TX_DS) | (1 << MAX_RT));
}
rf24_ceLow();
rf24_powerUpTx(); // Set to transmitter mode , Power up
rf24_csnLow(); // Pull down chip select
spi_transfer( FLUSH_TX ); // Write cmd to flush tx fifo
rf24_csnHi(); // Pull up chip select
rf24_csnLow(); // Pull down chip select
spi_transfer( W_TX_PAYLOAD ); // Write cmd to write payload
rf24_transmitSync(value,len); // Write payload
rf24_csnHi(); // Pull up chip select
rf24_ceHi(); // Start transmission
}
uint8_t inline rf24_isSending(){
uint8_t status;
if(PTX){
status = rf24_getStatus();
/*
* if sending successful (TX_DS) or max retries exceded (MAX_RT).
*/
if((status & ((1 << TX_DS) | (1 << MAX_RT)))){
return 0;
}
return 1;
}
return 0;
}
uint8_t inline rf24_getStatus(){
uint8_t rv;
rf24_csnLow();
rv=spi_transfer(NOP);
rf24_csnHi();
return rv;
}
void inline rf24_powerUpRx(){
PTX = 0;
rf24_ceLow();
rf24_configRegister(CONFIG, rf24_CONFIG | ( (1<<PWR_UP) | (1<<PRIM_RX) ) );
rf24_ceHi();
rf24_configRegister(STATUS,(1 << TX_DS) | (1 << MAX_RT));
}
void inline rf24_flushRx(){
rf24_csnLow();
spi_transfer( FLUSH_RX );
rf24_csnHi();
}
void inline rf24_powerUpTx(){
PTX = 1;
rf24_configRegister(CONFIG, rf24_CONFIG | ( (1<<PWR_UP) | (0<<PRIM_RX) ) );
}
void inline rf24_powerDown(){
rf24_ceLow();
rf24_configRegister(CONFIG, rf24_CONFIG );
}
void rf24_configure(){
uint8_t data;
rf24_configRegister(CONFIG,rf24_CONFIG);
rf24_configRegister(FEATURE,rf24_FEATURE);
// Check Feature register ...
rf24_readRegister(FEATURE,&data,1);
if(rf24_FEATURE != data){ // ACTIVATE & retry
rf24_csnLow();
spi_transfer(ACTIVATE);
spi_transfer(0x73);
rf24_csnHi();
rf24_configRegister(FEATURE,rf24_FEATURE);
}
rf24_configRegister(EN_AA,rf24_EN_AA);
rf24_configRegister(EN_RXADDR,rf24_EN_RXADDR);
rf24_configRegister(SETUP_AW,rf24_SETUP_AW);
rf24_configRegister(SETUP_RETR,rf24_SETUP_RETR);
rf24_configRegister(RF_CH,rf24_RF_CH);
rf24_configRegister(RF_SETUP,rf24_RF_SETUP);
rf24_configRegister(DYNPD,rf24_DYNPD);
for(int i=0; i<6;i++)
rf24_configRegister(RX_PW_P0+i,rf24_RX_PW[i]);
}

72
rf24.h Normal file
View file

@ -0,0 +1,72 @@
#include "nRF24L01.h"
#include "spi.h"
#include <avr/io.h>
#include "defines.h"
#ifdef __cplusplus
extern "C"{
#endif
void rf24_init();
void rf24_configRegister(uint8_t reg, uint8_t value);
void rf24_readRegister(uint8_t reg, uint8_t * value, uint8_t len);
void rf24_writeRegister(uint8_t reg, uint8_t * value, uint8_t len);
void rf24_getData(uint8_t * data,uint8_t len);
uint8_t rf24_getDataDL(uint8_t * data,uint8_t len);
uint8_t rf24_dataReady();
uint8_t rf24_rxFifoEmpty();
void rf24_send(uint8_t * value,uint8_t len);
uint8_t rf24_isSending();
uint8_t rf24_getStatus();
void rf24_powerUpRx();
void rf24_powerUpTx();
void rf24_powerDown();
void rf24_flushRx();
void rf24_configure();
extern uint8_t rf24_CONFIG;
extern uint8_t rf24_EN_AA;
extern uint8_t rf24_EN_RXADDR;
extern uint8_t rf24_SETUP_AW;
extern uint8_t rf24_SETUP_RETR;
extern uint8_t rf24_RF_CH;
extern uint8_t rf24_RF_SETUP;
extern uint8_t rf24_FEATURE;
extern uint8_t rf24_DYNPD;
extern uint8_t rf24_RX_PW[6];
#if defined (__AVR_ATtiny84__) || defined (__AVR_ATtiny84A__)
#define CE_PIN_PORT UNDEF
#define CE_PIN_DDR UNDEF
#define CE_PIN_BIT UNDEF
#define CSN_PIN_PORT PORTB
#define CSN_PIN_DDR DDRB
#define CSN_PIN_BIT PB2
#elif defined(__AVR_ATmega32U4__)
#define CE_PIN_PORT PORTD
#define CE_PIN_DDR DDRD
#define CE_PIN_BIT PD4
#define CSN_PIN_PORT PORTC
#define CSN_PIN_DDR DDRC
#define CSN_PIN_BIT PC6
#endif
#ifdef __cplusplus
} // extern "C"
#endif

79
spi.c Normal file
View file

@ -0,0 +1,79 @@
#include "spi.h"
#include <util/delay.h>
void spi_begin() {
#if defined(SPCR)
#error to write ...
// Set SS to high so a connected chip will be "deselected" by default
digitalWrite(SS, HIGH);
// When the SS pin is set as OUTPUT, it can be used as
// a general purpose output port (it doesn't influence
// SPI operations).
pinMode(SS, OUTPUT);
// Warning: if the SS pin ever becomes a LOW INPUT then SPI
// automatically switches to Slave, so the data direction of
// the SS pin MUST be kept as OUTPUT.
SPCR |= _BV(MSTR);
SPCR |= _BV(SPE);
// Set direction register for SCK and MOSI pin.
// MISO pin automatically overrides to INPUT.
// By doing this AFTER enabling SPI, we avoid accidentally
// clocking in a single bit since the lines go directly
// from "input" to SPI control.
// http://code.google.com/p/arduino/issues/detail?id=888
pinMode(SCK, OUTPUT);
pinMode(MOSI, OUTPUT);
#else
PRR &= ~(_BV(PRUSI));
USICR = _BV(USIWM0);
USCK_DDR |= _BV(USCK_BIT); //set the USCK pin as output
DO_DDR |= _BV(DO_BIT); //set the DO pin as output
DI_DDR &= ~_BV(DI_BIT); //set the DI pin as input
#endif
}
uint8_t spi_transfer(uint8_t b) {
#if defined(SPCR)
SPDR = b;
while (!(SPSR & _BV(SPIF)));
return SPDR;
#else
USIDR = b;
USISR = _BV(USIOIF);
do {
USICR = _BV(USIWM0) | _BV(USICS1) | _BV(USICLK) | _BV(USITC);
// _delay_ms(1);
}while ((USISR & _BV(USIOIF)) == 0);
return USIDR;
#endif
}
void spi_end() {
#if defined(SPCR)
SPCR &= ~_BV(SPE);
#else
USICR &= ~(_BV(USIWM1) | _BV(USIWM0));
#endif
}
void spi_setBitOrder(uint8_t bitOrder)
{
#if defined(SPCR)
if(bitOrder == LSBFIRST) {
SPCR |= _BV(DORD);
} else {
SPCR &= ~(_BV(DORD));
}
#endif
}
void spi_setDataMode(uint8_t mode)
{
#if defined(SPCR)
SPCR = (SPCR & ~SPI_MODE_MASK) | mode;
#else
#endif
}

29
spi.h Normal file
View file

@ -0,0 +1,29 @@
#ifndef tinySPI_h
#define tinySPI_h
#include <stdint.h>
#include <avr/io.h>
#include <util/atomic.h>
#ifdef __cplusplus
extern "C"{
#endif
//SPI data modes
#define SPI_MODE0 0x00
#define SPI_MODE1 0x04
void spi_begin(void);
void spi_setDataMode(uint8_t spiDataMode);
uint8_t spi_transfer(uint8_t spiData);
void spi_end(void);
#ifdef __cplusplus
} // extern "C"
#endif
#endif

76
uart.S Normal file
View file

@ -0,0 +1,76 @@
//UART Functions per AVR Application Note #305
#include <avr/io.h>
//#include "uLogTimer.h"
//
//half bit delay
//
//#define b 31 //38400 bps@8MHz with 0.3% error
#define b 66 //19200 bps@8MHz with 0.6% error
UARTDelay:
ldi r17, b
UARTDelay1:
dec r17
brne UARTDelay1
ret
//
//asynchronous 8n1 serial transmit byte
//
#define TX_PIN 6 //TX pin is PA6
.global SerialPutChar
SerialPutChar:
push r16
push r17
ldi r16, 10 ;1 start + 8 data + 1 stop bits (bit count)
com r24 ;Invert it (r24 = xmit byte)
sec ;Start bit
putchar0:
brcc putchar1 ;If carry set
cbi _SFR_IO_ADDR(PORTB), PB0 ;send a '0'
rjmp putchar2 ;else
putchar1:
sbi _SFR_IO_ADDR(PORTB), PB0 ;send a '1'
nop
putchar2:
rcall UARTDelay ;1/2 bit delay +
rcall UARTDelay ;1/2 bit delay = 1bit delay
lsr r24 ;Get next bit
dec r16 ;If not all bits sent
brne putchar0 ;send next
;else
pop r17
pop r16
ret ;return
//
//asynchronous 8n1 serial receive byte
//
#define RX_PIN 5 //RX pin is PA5
.global SerialGetChar
SerialGetChar:
push r16
push r17
ldi r16, 9 ;8 data bits + 1 stop bit
getchar1:
sbic _SFR_IO_ADDR(PINB), PB1 ;Wait for start bit
rjmp getchar1
rcall UARTDelay ;1.5bit delay after start bit edge
getchar2:
rcall UARTDelay ;1 bit delay from here
rcall UARTDelay
clc ;clear carry
sbic _SFR_IO_ADDR(PINB), PB1 ;if RX pin high
sec ;
dec r16 ;If bit is stop bit
breq getchar3 ; return
;else
ror r24 ; shift bit into r24 (rec'd byte)
rjmp getchar2 ; go get next
getchar3:
ldi r25, 0x00 ;zero extend r24:r25 for return
pop r17
pop r16
ret

4
uart.h Normal file
View file

@ -0,0 +1,4 @@
//asynchronous 8n1 serial transmission per AVR AppNote #305
void SerialPutChar (char);
char SerialGetChar(void);