From aad2cc40d4e2dfc6e4ec86595f5d7dcdc7533f36 Mon Sep 17 00:00:00 2001 From: Arnaud Date: Fri, 29 Apr 2016 11:30:56 +0200 Subject: [PATCH] Ajout initial --- Makefile | 228 +++++++++++++++++++ analog.c | 87 +++++++ analog.h | 25 ++ crc8.h | 17 ++ debug.c | 16 ++ debug.h | 7 + defines.h | 47 ++++ dht11.c | 79 +++++++ dht11.h | 22 ++ eeprom | 1 + eeprom.bin | Bin 0 -> 5 bytes lib/Hamming.c | 174 ++++++++++++++ lib/Hamming.h | 68 ++++++ lib/HammingCalculateParityFast.c | 67 ++++++ lib/HammingCalculateParitySmall.c | 99 ++++++++ lib/HammingCalculateParitySmallAndFast.c | 64 ++++++ lib/HammingCalculateParityTextbook.c | 100 ++++++++ main.c | 277 +++++++++++++++++++++++ nRF24L01.h | 125 ++++++++++ onewire.c | 231 +++++++++++++++++++ onewire.h | 57 +++++ rf24.c | 270 ++++++++++++++++++++++ rf24.h | 72 ++++++ spi.c | 79 +++++++ spi.h | 29 +++ uart.S | 76 +++++++ uart.h | 4 + 27 files changed, 2321 insertions(+) create mode 100644 Makefile create mode 100644 analog.c create mode 100644 analog.h create mode 100644 crc8.h create mode 100644 debug.c create mode 100644 debug.h create mode 100644 defines.h create mode 100644 dht11.c create mode 100644 dht11.h create mode 100644 eeprom create mode 100644 eeprom.bin create mode 100644 lib/Hamming.c create mode 100644 lib/Hamming.h create mode 100644 lib/HammingCalculateParityFast.c create mode 100644 lib/HammingCalculateParitySmall.c create mode 100644 lib/HammingCalculateParitySmallAndFast.c create mode 100644 lib/HammingCalculateParityTextbook.c create mode 100644 main.c create mode 100644 nRF24L01.h create mode 100644 onewire.c create mode 100644 onewire.h create mode 100644 rf24.c create mode 100644 rf24.h create mode 100644 spi.c create mode 100644 spi.h create mode 100644 uart.S create mode 100644 uart.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a36911e --- /dev/null +++ b/Makefile @@ -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 +# +# - 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 diff --git a/analog.c b/analog.c new file mode 100644 index 0000000..a851376 --- /dev/null +++ b/analog.c @@ -0,0 +1,87 @@ +#include +#include +#include +#include +#include +#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; +} diff --git a/analog.h b/analog.h new file mode 100644 index 0000000..cbc8ae1 --- /dev/null +++ b/analog.h @@ -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 diff --git a/crc8.h b/crc8.h new file mode 100644 index 0000000..64011ba --- /dev/null +++ b/crc8.h @@ -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; +} diff --git a/debug.c b/debug.c new file mode 100644 index 0000000..5a378db --- /dev/null +++ b/debug.c @@ -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'); + } +} diff --git a/debug.h b/debug.h new file mode 100644 index 0000000..eaaca0e --- /dev/null +++ b/debug.h @@ -0,0 +1,7 @@ +#include "uart.h" +#include +#define DEBUG 1 + + +void debug (char* ptr); +void debughex (char* ptr,uint8_t len); diff --git a/defines.h b/defines.h new file mode 100644 index 0000000..1a30381 --- /dev/null +++ b/defines.h @@ -0,0 +1,47 @@ +#ifndef defines_h +#define defines_h + +#include +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 diff --git a/dht11.c b/dht11.c new file mode 100644 index 0000000..fb1a2f4 --- /dev/null +++ b/dht11.c @@ -0,0 +1,79 @@ +#include "dht11.h" +#include +#include +#include +#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; +} diff --git a/dht11.h b/dht11.h new file mode 100644 index 0000000..94f8d1a --- /dev/null +++ b/dht11.h @@ -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 diff --git a/eeprom b/eeprom new file mode 100644 index 0000000..44a49a3 --- /dev/null +++ b/eeprom @@ -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 diff --git a/eeprom.bin b/eeprom.bin new file mode 100644 index 0000000000000000000000000000000000000000..28037ecfa6c4eb0068f267a8df78effbad36c760 GIT binary patch literal 5 McmZQ#5OQV!007GXSO5S3 literal 0 HcmV?d00001 diff --git a/lib/Hamming.c b/lib/Hamming.c new file mode 100644 index 0000000..cb1fba3 --- /dev/null +++ b/lib/Hamming.c @@ -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 + +#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 +} diff --git a/lib/Hamming.h b/lib/Hamming.h new file mode 100644 index 0000000..7778a59 --- /dev/null +++ b/lib/Hamming.h @@ -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 diff --git a/lib/HammingCalculateParityFast.c b/lib/HammingCalculateParityFast.c new file mode 100644 index 0000000..6cc5df6 --- /dev/null +++ b/lib/HammingCalculateParityFast.c @@ -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 + +#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])); +} diff --git a/lib/HammingCalculateParitySmall.c b/lib/HammingCalculateParitySmall.c new file mode 100644 index 0000000..d446f8f --- /dev/null +++ b/lib/HammingCalculateParitySmall.c @@ -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); +} + diff --git a/lib/HammingCalculateParitySmallAndFast.c b/lib/HammingCalculateParitySmallAndFast.c new file mode 100644 index 0000000..ad27bf8 --- /dev/null +++ b/lib/HammingCalculateParitySmallAndFast.c @@ -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 + +#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); +} diff --git a/lib/HammingCalculateParityTextbook.c b/lib/HammingCalculateParityTextbook.c new file mode 100644 index 0000000..08e5cca --- /dev/null +++ b/lib/HammingCalculateParityTextbook.c @@ -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 + + diff --git a/main.c b/main.c new file mode 100644 index 0000000..ba4b47e --- /dev/null +++ b/main.c @@ -0,0 +1,277 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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(); + } +} + diff --git a/nRF24L01.h b/nRF24L01.h new file mode 100644 index 0000000..2012ce6 --- /dev/null +++ b/nRF24L01.h @@ -0,0 +1,125 @@ +/* + Copyright (c) 2007 Stefan Engelke + + 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 diff --git a/onewire.c b/onewire.c new file mode 100644 index 0000000..74d81bc --- /dev/null +++ b/onewire.c @@ -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 +#include +#include +#include + +#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< 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; +} diff --git a/onewire.h b/onewire.h new file mode 100644 index 0000000..5b497fe --- /dev/null +++ b/onewire.h @@ -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__ diff --git a/rf24.c b/rf24.c new file mode 100644 index 0000000..69f4150 --- /dev/null +++ b/rf24.c @@ -0,0 +1,270 @@ + +#include "rf24.h" +#include + + +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<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< +#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 + diff --git a/spi.c b/spi.c new file mode 100644 index 0000000..cb4a1b8 --- /dev/null +++ b/spi.c @@ -0,0 +1,79 @@ +#include "spi.h" +#include + + +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 +} + diff --git a/spi.h b/spi.h new file mode 100644 index 0000000..eabdb91 --- /dev/null +++ b/spi.h @@ -0,0 +1,29 @@ +#ifndef tinySPI_h +#define tinySPI_h + +#include +#include +#include + +#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 + + diff --git a/uart.S b/uart.S new file mode 100644 index 0000000..c8e59ee --- /dev/null +++ b/uart.S @@ -0,0 +1,76 @@ +//UART Functions per AVR Application Note #305 +#include +//#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 diff --git a/uart.h b/uart.h new file mode 100644 index 0000000..4c42557 --- /dev/null +++ b/uart.h @@ -0,0 +1,4 @@ +//asynchronous 8n1 serial transmission per AVR AppNote #305 +void SerialPutChar (char); +char SerialGetChar(void); +