Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

RFM70 - working example code for ATmega88 (no interrupts yet)

1,638 views
Skip to first unread message

wzab

unread,
Jan 6, 2011, 4:30:21 PM1/6/11
to
Archive-name: avr_rfm70

Below are the sources of sample code for RFM70 module
( http://www.hoperf.com/rf_fsk/rfm70.htm )
connected to the ATmega88 processor working with
internal RC oscillator (ca. 8MHz)
According to the datasheet the inputs of RFM70 are
5V tolerant, so I've tested the code with both:
3.3V powered ATmega88 and with 5.0V powered ATmega88.
The RFM70 was powered from 3.3V in both cases.

The module is connected as follows:
RFM ATmega88
IRQ -
MISO (PCINT16/RXD) PD0 [pin2]
MOSI (PCINT17/TXD) PD1 [pin3]
SCK (PCINT20/XCK/T0) PD4 [pin6]
CSN (PCINT19/OC2B/INT1) PD3 [pin5]
CE (PCINT21/OC0B/T1) PD5 [pin11]

Additionally the beeper with oscillator should be connected
to pin 13 (PCINT23/AIN1) PD7 - to present the state of the
system. You can also connect a LED diode instead.

To pin 14 (PCINT0/CLK0/ICP1) PB0 you can connect another LED
which state toggles after any packet is sent in the TX mode.

The pin 12 (PCINT22/OC0A/AIN0) PD6 is used to select either
the transmitter or receiver operation.

If PD6 is shorted to the ground, the module enters the
transmitter mode, and sends a packet roughly every second.
If PD6 is open, the module enters the receiver mode.

If a packet is received, beepers beeps "*_*__*__".
If no packets are received, beeper emits only short beeps
"*________".
Another pattern "*_*_***_" (both in RX and TX mode) informs
about problems with SPI communication between RFM70 and
ATmega88.

The code is based on the demo PIC code provided by HOPE.
My additions are published as PUBLIC DOMAIN.

Generally the translation to AVR was trivial. The only
real problem was with USART working in the SPI mode.

If you use the sending routine proposed by Atmel
(page 194 of the datasheet) and set the CS line high
right after the RXC0 flag is set in UCSR0A, the RFM70
will receive corrupte SPI frame.
You have to wait until TXC0 flag is set !

I hope, that the attached code will be useful for somebody.
Wojciech M. Zabolotny <wzab AT ise.pw.edu.pl>

#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.9).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `#!/bin/sh' line above, then type `sh FILE'.
#
lock_dir=_sh17806
# Made on 2011-01-06 22:16 CET by <wzab@wzab>.
# Source directory was `/tmp/rfm_avr'.
#
# Existing files will *not* be overwritten, unless `-c' is specified.
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 1758 -rw-r--r-- Makefile
# 6658 -rw-r--r-- rfm70.c
# 730 -rw-r--r-- rfm70.h
# 1173 -rw-r--r-- usart_spi_atmega88.h
#
MD5SUM=${MD5SUM-md5sum}
f=`${MD5SUM} --version | egrep '^md5sum .*(core|text)utils'`
test -n "${f}" && md5check=true || md5check=false
${md5check} || \
echo 'Note: not verifying md5sums. Consider installing GNU coreutils.'
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=FAILED
locale_dir=FAILED
first_param="$1"
for dir in $PATH
do
if test "$gettext_dir" = FAILED && test -f $dir/gettext \
&& ($dir/gettext --version >/dev/null 2>&1)
then
case `$dir/gettext --version 2>&1 | sed 1q` in
*GNU*) gettext_dir=$dir ;;
esac
fi
if test "$locale_dir" = FAILED && test -f $dir/shar \
&& ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
then
locale_dir=`$dir/shar --print-text-domain-dir`
fi
done
IFS="$save_IFS"
if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED
then
echo=echo
else
TEXTDOMAINDIR=$locale_dir
export TEXTDOMAINDIR
TEXTDOMAIN=sharutils
export TEXTDOMAIN
echo="$gettext_dir/gettext -s"
fi
if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null
then if (echo -n test; echo 1,2,3) | grep n >/dev/null
then shar_n= shar_c='
'
else shar_n=-n shar_c= ; fi
else shar_n= shar_c='\c' ; fi
f=shar-touch.$$
st1=200112312359.59
st2=123123592001.59
st2tr=123123592001.5 # old SysV 14-char limit
st3=1231235901

if touch -am -t ${st1} ${f} >/dev/null 2>&1 && \
test ! -f ${st1} && test -f ${f}; then
shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'

elif touch -am ${st2} ${f} >/dev/null 2>&1 && \
test ! -f ${st2} && test ! -f ${st2tr} && test -f ${f}; then
shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'

elif touch -am ${st3} ${f} >/dev/null 2>&1 && \
test ! -f ${st3} && test -f ${f}; then
shar_touch='touch -am $3$4$5$6$2 "$8"'

else
shar_touch=:
echo
${echo} 'WARNING: not restoring timestamps. Consider getting and
installing GNU `touch'\'', distributed in GNU coreutils...'
echo
fi
rm -f ${st1} ${st2} ${st2tr} ${st3} ${f}
#
if test ! -d ${lock_dir} ; then :
else ${echo} "lock directory ${lock_dir} exists"
exit 1
fi
if mkdir ${lock_dir}
then ${echo} "x - created lock directory ${lock_dir}."
else ${echo} "x - failed to create lock directory ${lock_dir}."
exit 1
fi
# ============= Makefile ==============
if test -f 'Makefile' && test "$first_param" != -c; then
${echo} "x - SKIPPING Makefile (file already exists)"
else
${echo} "x - extracting Makefile (text)"
sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
PRG = rfm
OBJ = rfm70.o
MCU_TARGET = atmega88
OPTIMIZE = -Os
X
DEFS =
LIBS =
X
# You should not have to change anything below here.
X
CC = avr-gcc
X
CFLAGS = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) $(DEFS)
LDFLAGS = -Wl,-Map,$(PRG).map
X
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
X
all: $(PRG).elf lst text eeprom
X
$(PRG).elf: $(OBJ)
X $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
X
clean:
X rm -rf *.o $(PRG).elf *.eps *.png *.pdf *.bak
X rm -rf *.lst *.map $(EXTRA_CLEAN_FILES)
X
lst: $(PRG).lst
X
%.lst: %.elf
X $(OBJDUMP) -h -S $< > $@
X
# Rules for building the .text rom images
X
text: hex bin srec
X
hex: $(PRG).hex
bin: $(PRG).bin
srec: $(PRG).srec
X
%.hex: %.elf
X $(OBJCOPY) -j .text -j .data -O ihex $< $@
X
%.srec: %.elf
X $(OBJCOPY) -j .text -j .data -O srec $< $@
X
%.bin: %.elf
X $(OBJCOPY) -j .text -j .data -O binary $< $@
X
# Rules for building the .eeprom rom images
X
eeprom: ehex ebin esrec
X
ehex: $(PRG)_eeprom.hex
ebin: $(PRG)_eeprom.bin
esrec: $(PRG)_eeprom.srec
X
%_eeprom.hex: %.elf
X $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@
X
%_eeprom.srec: %.elf
X $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O srec $< $@
X
%_eeprom.bin: %.elf
X $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O binary $< $@
X
# Every thing below here is used by avr-libc's build system and can be ignored
# by the casual user.
X
JPEGFILES = stdiodemo-setup.jpg
X
JPEG2PNM = jpegtopnm
PNM2EPS = pnmtops
JPEGRESOLUTION = 180
EXTRA_CLEAN_FILES = *.hex *.bin *.srec *.eps
X
dox: ${JPEGFILES:.jpg=.eps}
X
%.eps: %.jpg
X $(JPEG2PNM) $< |\
X $(PNM2EPS) -noturn -dpi $(JPEGRESOLUTION) -equalpixels \
X > $@
SHAR_EOF
(set 20 11 01 04 22 28 07 'Makefile'
eval "${shar_touch}") && \
chmod 0644 'Makefile'
if test $? -ne 0
then ${echo} "restore of Makefile failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'Makefile': 'MD5 check failed'
) << \SHAR_EOF
e3769cb37d47678f864b72b4f8c72e9e Makefile
SHAR_EOF
else
test `LC_ALL=C wc -c < 'Makefile'` -ne 1758 && \
${echo} "restoration warning: size of 'Makefile' is not 1758"
fi
fi
# ============= rfm70.c ==============
if test -f 'rfm70.c' && test "$first_param" != -c; then
${echo} "x - SKIPPING rfm70.c (file already exists)"
else
${echo} "x - extracting rfm70.c (text)"
sed 's/^X//' << 'SHAR_EOF' > 'rfm70.c' &&
#include "rfm70.h"
static PROGMEM uint8_t set1[][4]={
X {0x40, 0x4b, 0x01, 0xe2},
X {0xc0, 0x4b, 0x00, 0x00},
X {0xd0, 0xfc, 0x8c, 0x02},
X {0x99, 0x00, 0x39, 0x41},
X {0xd9, 0x9e, 0x86, 0x0b},// #?? d9 czy f9?
X {0x24, 0x06, 0x7f, 0xa6},
X {0x00, 0x00, 0x00, 0x00},
X {0x00, 0x00, 0x00, 0x00},
X {0x00, 0x00, 0x00, 0x00},
X {0x00, 0x00, 0x00, 0x00},
X {0x00, 0x00, 0x00, 0x00},
X {0x00, 0x00, 0x00, 0x00},
X {0x00, 0x12, 0x73, 0x00},
X {0x36, 0xB4, 0x80, 0x00},
};
static PROGMEM uint8_t set1_14[]={0x41,0x20,0x08,0x04,0x81,0x20,0xCF,0xF7,0xFE,0xFF,0xFF};
static PROGMEM uint8_t set0[][2]={
X {0,0x0F}, //reflect RX_DR\TX_DS\MAX_RT,Enable CRC ,2byte,POWER UP,PRX
X {1,0x3F}, //Enable auto acknowledgement data pipe5\4\3\2\1\0
X {2,0x3F}, //Enable RX Addresses pipe5\4\3\2\1\0
X {3,0x03}, //RX/TX address field width 5byte
X {4,0xff}, //auto retransmission dalay (4000us),auto retransmission count(15)
X {5,0x80}, //(5,0x17), #23 channel
X {6,0x3f}, //6,0x17), #air data rate-1M,out power 0dbm,setup LNA gain
X {7,0x07}, //
X {8,0x00}, //
X {9,0x00}, //
X {12,0xc3},// only LSB Receive address data pipe 2, MSB bytes is equal to RX_ADDR_P1[39:8]
X {13,0xc4},// only LSB Receive address data pipe 3, MSB bytes is equal to RX_ADDR_P1[39:8]
X {14,0xc5},// only LSB Receive address data pipe 4, MSB bytes is equal to RX_ADDR_P1[39:8]
X {15,0xc6},// only LSB Receive address data pipe 5, MSB bytes is equal to RX_ADDR_P1[39:8]
X {17,0x20},// Number of bytes in RX payload in data pipe0(32 byte)
X {18,0x20},// Number of bytes in RX payload in data pipe1(32 byte)
X {19,0x20},// Number of bytes in RX payload in data pipe2(32 byte)
X {20,0x20},// Number of bytes in RX payload in data pipe3(32 byte)
X {21,0x20},// Number of bytes in RX payload in data pipe4(32 byte)
X {22,0x20},// Number of bytes in RX payload in data pipe5(32 byte)
X {23,0x00},// fifo status
X {28,0x3F},// Enable dynamic payload length data pipe5\4\3\2\1\0
X {29,0x07},// Enables Dynamic Payload Length,Enables Payload with ACK,Enables the W_TX_PAYLOAD_NOACK command
};
static PROGMEM uint8_t cmd_activate[]={0x50,0x73};
static PROGMEM uint8_t cmd_tog1[]={0xd9 | 0x06, 0x9e, 0x86, 0x0b}; //assosciated with set1[4]!
static PROGMEM uint8_t cmd_tog2[]={0xd9 & ~0x06, 0x9e, 0x86, 0x0b};
static PROGMEM uint8_t cmd_flush_rx[]={0xe2,0x00};
static PROGMEM uint8_t cmd_flush_tx[]={0xe1,0x00};
static PROGMEM uint8_t cmd_switch_cfg[]={0x50,0x53};
static PROGMEM uint8_t adr0[]={0x32,0x33,0x10,0x11,0x12};
static PROGMEM uint8_t adr1[]={0x32,0x33,0x10,0x12,0x12};
X
uint8_t SPI_Transfer(uint8_t c);
X
X
uint8_t read_reg(uint8_t reg)
{
X uint8_t res;
X set_cs(1);
X set_cs(0);
X SPI_Transfer(reg);
X res=SPI_Transfer(0);
X set_cs(1);
X return res;
}
X
void write_pcmd(uint8_t * cmd, uint8_t len)
{
X set_cs(1);
X set_cs(0);
X while(len--) {
X SPI_Transfer(pgm_read_byte(cmd++));
X };
X set_cs(1);
}
X
void write_reg(uint8_t reg, uint8_t val)
{
X set_cs(1);
X set_cs(0);
X SPI_Transfer(reg | 0x20);
X SPI_Transfer(val);
X set_cs(1);
}
X
void switch_cfg(uint8_t cnum)
{
X uint8_t tmp = read_reg(0x07) & 0x80;
X if(cnum) {
X if(!tmp)
X write_pcmd(cmd_switch_cfg,sizeof(cmd_switch_cfg));
X } else {
X if(tmp)
X write_pcmd(cmd_switch_cfg,sizeof(cmd_switch_cfg));
X }
}
X
void switch_to_rx_mode(void)
{
X uint8_t val;
X write_pcmd(cmd_flush_rx,sizeof(cmd_flush_rx));
X val = read_reg(0x07);
X write_reg(0x07,val);
X set_ce(0);
X val=read_reg(0x00);
X val |= 0x01;
X write_reg(0x00,val);
X set_ce(1);
}
X
void switch_to_tx_mode(void)
{
X uint8_t val;
X write_pcmd(cmd_flush_tx,sizeof(cmd_flush_tx));
X set_ce(0);
X val=read_reg(0x00);
X val &= ~0x01;
X write_reg(0x00,val);
X set_ce(1);
}
X
void set_channel(uint8_t cnum)
{
X write_reg(5, cnum);
}
X
X
void write_reg_pbuf(uint8_t reg, uint8_t * buf, uint8_t len)
{
X set_cs(1);
X set_cs(0);
X SPI_Transfer(reg | 0x20);
X while(len--)
X SPI_Transfer(pgm_read_byte(buf++));
X set_cs(1);
}
X
uint8_t send_packet(uint8_t * data, uint8_t len)
{
X uint8_t status;
X switch_to_tx_mode();
X status = read_reg(0x17); //FIFO_STATUS
X if (status & 0x20) return 0xff; //Error?
X set_cs(0);
X SPI_Transfer(0xb0);
X while(len--) {
X SPI_Transfer(*(data++));
X }
X set_cs(1);
X return 0;
}
X
void beep(uint8_t msg)
{
X uint8_t mask;
X DDRD |= 0x80;
X {
X mask=0x80;
X while(mask) {
X if(mask & msg)
X PORTD |= 0x80;
X else
X PORTD &= ~(0x80);
X _delay_ms(200);
X mask >>= 1;
X }
X PORTD &= ~(0x80);
X _delay_ms(400);
X }
}
X
X
void receive_packet(void)
{
X uint8_t sta;
X sta = read_reg(0x07);
X if (sta & 0x40) {
X while(1) {
X uint8_t fifo_sta;
X uint8_t len = read_reg(0x60);
X while(len--) read_reg(0x61);
X fifo_sta = read_reg(0x17);
X if (fifo_sta & 0x01) break;
X }
X write_reg(0x07,sta);
X beep(0xa4);
X } else {
X beep(2);
X }
}
X
void show_error(uint8_t msg)
{
X uint8_t mask;
X DDRD |= 0x80;
X while(1) {
X mask=0x80;
X while(mask) {
X if(mask & msg)
X PORTD |= 0x80;
X else
X PORTD &= ~(0x80);
X _delay_ms(200);
X mask >>= 1;
X }
X PORTD &= ~(0x80);
X _delay_ms(400);
X }
}
X
void rfm70_init()
{
X uint8_t i;
X _delay_ms(2000);
X switch_cfg(0);
X for(i=0;i<20;i++) {
X write_reg(pgm_read_byte(&set0[i][0]),pgm_read_byte(&set0[i][1]));
X }
X write_reg_pbuf(10,adr0,sizeof(adr0));
X write_reg_pbuf(11,adr1,sizeof(adr1));
X write_reg_pbuf(16,adr1,sizeof(adr1));
X if(!read_reg(29))
X write_pcmd(cmd_activate,sizeof(cmd_activate));
X write_reg(pgm_read_byte(&set0[22][0]),pgm_read_byte(&set0[22][1]));
X write_reg(pgm_read_byte(&set0[21][0]),pgm_read_byte(&set0[21][1]));
X switch_cfg(1);
X for(i=0;i<14;i++) {
X write_reg_pbuf(i,set1[i],sizeof(set1[i]));
X }
X write_reg_pbuf(14,set1_14,sizeof(set1_14));
X write_reg_pbuf(4,cmd_tog1,sizeof(cmd_tog1));
X write_reg_pbuf(4,cmd_tog2,sizeof(cmd_tog2));
X //delay 50 ms
X _delay_ms(50);
X //Check the ChipID
X //if (read_reg(8) != 0x63) show_error(0xaa);
X switch_cfg(0);
X switch_to_rx_mode();
}
X
uint8_t pakiet[]="0123456789012345678901234567";
X
int main()
{
X //Disable watchdog!
X uint8_t b1,b2;
X MCUSR &= ~(1 << WDRF);
X wdt_disable();
X clock_prescale_set(clock_div_1);
X
X DDRB = 1;
X USART_SPI_Init(10);
X rfm70_hw_setup();
X set_ce(1);
X set_cs(1);
X b1=read_reg(0x07);
X write_pcmd(cmd_switch_cfg,sizeof(cmd_switch_cfg));
X b2=read_reg(0x07);
X if ((b1 ^ b2) != 0x80) show_error(0xae);
X rfm70_init();
X PORTD |= 0x40 ; //Activate the pullup pin selecting Rx/Tx
X _delay_ms(100);
X if(PIND & (1<<6))
X while(1)
X receive_packet();
X switch_to_tx_mode();
X while(1) {
X PORTB = PORTB ^ 1;
X send_packet(pakiet, sizeof(pakiet));
X _delay_ms(1000);
X }
}
SHAR_EOF
(set 20 11 01 06 22 12 29 'rfm70.c'
eval "${shar_touch}") && \
chmod 0644 'rfm70.c'
if test $? -ne 0
then ${echo} "restore of rfm70.c failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'rfm70.c': 'MD5 check failed'
) << \SHAR_EOF
44b301a70e1a75eb64a1499a9d618c9c rfm70.c
SHAR_EOF
else
test `LC_ALL=C wc -c < 'rfm70.c'` -ne 6658 && \
${echo} "restoration warning: size of 'rfm70.c' is not 6658"
fi
fi
# ============= rfm70.h ==============
if test -f 'rfm70.h' && test "$first_param" != -c; then
${echo} "x - SKIPPING rfm70.h (file already exists)"
else
${echo} "x - extracting rfm70.h (text)"
sed 's/^X//' << 'SHAR_EOF' > 'rfm70.h' &&
#ifndef _RFM70_H_
#define _RFM70_H_
X
#define F_CPU 8000000
X
X
/* Includes: */
#include <ctype.h>
#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/power.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include "usart_spi_atmega88.h"
X
#define PORT_CS PORTD
#define DDR_CS DDRD
#define PIN_CS 3
#define PORT_CE PORTD
#define DDR_CE DDRD
#define PIN_CE 5
X
static inline void set_cs(uint8_t val)
{
X if(val)
X PORT_CS |= (1<<PIN_CS);
X else
X PORT_CS &= ~(1<<PIN_CS);
}
X
static inline void set_ce(uint8_t val)
{
X if(val)
X PORT_CE |= (1<<PIN_CE);
X else
X PORT_CE &= ~(1<<PIN_CE);
}
X
static inline void rfm70_hw_setup(void)
{
X DDR_CS |= (1<<PIN_CS);
X DDR_CE |= (1<<PIN_CE);
}
X
X
#endif
SHAR_EOF
(set 20 11 01 05 17 56 45 'rfm70.h'
eval "${shar_touch}") && \
chmod 0644 'rfm70.h'
if test $? -ne 0
then ${echo} "restore of rfm70.h failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'rfm70.h': 'MD5 check failed'
) << \SHAR_EOF
2b7654ebbcfc7c4e4286344907c91009 rfm70.h
SHAR_EOF
else
test `LC_ALL=C wc -c < 'rfm70.h'` -ne 730 && \
${echo} "restoration warning: size of 'rfm70.h' is not 730"
fi
fi
# ============= usart_spi_atmega88.h ==============
if test -f 'usart_spi_atmega88.h' && test "$first_param" != -c; then
${echo} "x - SKIPPING usart_spi_atmega88.h (file already exists)"
else
${echo} "x - extracting usart_spi_atmega88.h (text)"
sed 's/^X//' << 'SHAR_EOF' > 'usart_spi_atmega88.h' &&
static inline uint8_t SPI_Transfer(uint8_t c)
{
X const uint8_t status_mask=((1<<RXC0) | (1<<TXC0));
X /* Wait for empty transmit buffer */
X while ( !( UCSR0A & (1<<UDRE0)) );
X /* Put data into buffer, sends the data */
X UDR0 = c;
X /* Wait for data to be received and transmission completed
X Please note, that it is not enough to wait for availability
X of received data (RXC0), if you set SS high right after
X SS is set, you'll experience SPI frame error in the RFM70!
X I've lost quite a long time trying to debug this problem!!!
X */
X while ( (UCSR0A & status_mask) != status_mask );
X /* Get and return received data from buffer */
X return UDR0;
}
X
static inline void USART_SPI_Init( unsigned int baud )
{
X UBRR0 = 0;
X /* Setting the XCKn port pin as output, enables master mode. */
X DDRD |= (1 << 4); // XCK1_DDR |= (1<<XCK1);
X /* Set MSPI mode of operation and SPI data mode 0. */
X UCSR0C = (1<<UMSEL01)|(1<<UMSEL00)|(0<<UCPHA0)|(0<<UCPOL0);
X /* Enable receiver and transmitter. */
X UCSR0B = (1<<RXEN0)|(1<<TXEN0);
X /* Set baud rate. */
X /* IMPORTANT: The Baud Rate must be set after the transmitter is enabled
X */
X UBRR0 = baud;
}
X
SHAR_EOF
(set 20 11 01 06 20 14 04 'usart_spi_atmega88.h'
eval "${shar_touch}") && \
chmod 0644 'usart_spi_atmega88.h'
if test $? -ne 0
then ${echo} "restore of usart_spi_atmega88.h failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'usart_spi_atmega88.h': 'MD5 check failed'
) << \SHAR_EOF
c673dcc339b5ef512bd7b21cacd9661d usart_spi_atmega88.h
SHAR_EOF
else
test `LC_ALL=C wc -c < 'usart_spi_atmega88.h'` -ne 1173 && \
${echo} "restoration warning: size of 'usart_spi_atmega88.h' is not 1173"
fi
fi
if rm -fr ${lock_dir}
then ${echo} "x - removed lock directory ${lock_dir}."
else ${echo} "x - failed to remove lock directory ${lock_dir}."
exit 1
fi
exit 0

wzab

unread,
Jan 8, 2011, 2:04:28 PM1/8/11
to
Ooops, it seems, that the TXC0 flag is not so easy to use. It is
cleared only after interrupt or after writing "1" to it (in polling
mode).
So the function USART_SPI_Transfer must be slightly modified!

static inline uint8_t USART_SPI_Transfer(uint8_t c)
{


const uint8_t status_mask=((1<<RXC0) | (1<<TXC0));

/* Wait for empty transmit buffer */

while ( !( UCSR0A & (1<<UDRE0)) ){};


/* Put data into buffer, sends the data */

cli();
UDR0 = c;
UCSR0A = (1<<TXC0); //Clear the completed transfer flag (possibly
set by previous transfers)!
sei();


/* Wait for data to be received and transmission completed

Please note, that it is not enough to wait for availability

of received data (RXC0), if you set SS high right after

SS is set, you'll experience SPI frame error in the RFM70!

I've lost quite a long time trying to debug this problem!!!

*/
while ( (UCSR0A & status_mask) != status_mask ){};


/* Get and return received data from buffer */

return UDR0;

wzab

unread,
Feb 13, 2011, 7:00:11 AM2/13/11
to
Use of USART in SPI mode is yet copmplicated by the fact, that USART
receiver is equipped with
FIFO. So if you ignore received data, you need to read the UDR0
register more than one time to clear
all received data.
The code below provides improved implementation of USART_SPI routines.
USART_SPI_Transfer lets you to transmit a byte and returns the
received byte
USART_SPI_Fast_Transfer lets you to transmit a byte without waiting
until it's really transmitted
You may call USART_SPI_Transfer a few times consecutively if you are
not interested in the received bytes.
After the last byte you should call USART_SPI_End_Fast_Transfer, which
waits until transmission is
finished and discards all received bytes stored in USART's FIFO.

I've used this improves code in my Wireless Guitar System available
at:
http://www.ise.pw.edu.pl/~wzab/wireless_guitar_system/

/*
The code below is published as PUBLIC DOMAIN as Wojciech M.
Zabolotny
( wzab<at>ise.pw.edu.pl ) 2011.01.11
No warranty of any kind is provided! Use at your own risk!
*/

static inline uint8_t USART_SPI_Transfer(uint8_t c)
{
const uint8_t status_mask=((1<<RXC0) | (1<<TXC0));
/* Wait for empty transmit buffer */
while ( !( UCSR0A & (1<<UDRE0)) ){};
/* Put data into buffer, sends the data */
cli();
UDR0 = c;

UCSR0A = (1<<TXC0); //Clear the completed transfer flag!


sei();
/* Wait for data to be received and transmission completed
Please note, that it is not enough to wait for availability
of received data (RXC0), if you set SS high right after
SS is set, you'll experience SPI frame error in the RFM70!
I've lost quite a long time trying to debug this problem!!!
*/
while ( (UCSR0A & status_mask) != status_mask ){};
/* Get and return received data from buffer */
return UDR0;
}

static inline void USART_SPI_Fast_Transfer(uint8_t c)
{


/* Wait for empty transmit buffer */
while ( !( UCSR0A & (1<<UDRE0)) );
/* Put data into buffer, sends the data */

UDR0 = c;
}

static inline uint8_t USART_SPI_End_Fast_Transfer(void)
{
uint8_t dummy;


const uint8_t status_mask=((1<<RXC0) | (1<<TXC0));

/* Wait for data to be received and transmission completed
Please note, that it is not enough to wait for availability
of received data (RXC0), if you set SS high right after
SS is set, you'll experience SPI frame error in the RFM70!
I've lost quite a long time trying to debug this problem!!!
*/
while ( (UCSR0A & status_mask) != status_mask ){};

/* Flush received data from buffer */
while (UCSR0A & (1<<RXC0)) dummy=UDR0;
}

static inline void USART_SPI_Init( unsigned int baud )
{

UBRR0 = 0;


/* Setting the XCKn port pin as output, enables master mode. */

DDRD |= (1 << 4); // XCK1_DDR |= (1<<XCK1);

/* Set MSPI mode of operation and SPI data mode 0. */

UCSR0C = (1<<UMSEL01)|(1<<UMSEL00)|(0<<UCPHA0)|(0<<UCPOL0);

/* Enable receiver and transmitter. */

UCSR0B = (1<<RXEN0)|(1<<TXEN0);

/* Set baud rate. */

/* IMPORTANT: The Baud Rate must be set after the transmitter is
enabled

*/
UBRR0 = baud;
}

0 new messages