This is an old revision of the document!
Table of Contents
AVR radio project (by Laurenceb)
This is designed for data downlink in flight, and based on rocketboys pulse shaping technique. The plan is to use the pwm output of an avr to modulate aradiometrix ntx2 module. This technique has previously been demonstrated to have a range in excess of 200Km using a pulse shaping modulation technique.
Hardware design
The nxt2 module has an enable pin, that can be used by the avr to save power whilst not transmitting
This apparently takes 3v logic levels, but there is nothing said about a TTL or 5v enable input, only that the voltage on any pin must not exceed vcc, so, for good measure theres a resistor between the avr and the EN pin. One nice feature of the nxt2 is the fact that there appears to be no schmitt trigger on the data input, allowing it to be driven with analogue signal levels. However, the behaviour when subjected to high frequency pwm input has not been examined, so filtering on the pwm will be needed, using an LCR or RC filter. At 300 baud downlink, the frequency of our desired modulation will be in the 150Hz or less range, whereas at 16Mhz clock, the pwm fundamental frequency is 62Khz, so filtering is a fairly easy job.
T1 and T2 are 20K and 40K trimpots respectively, C2 and C5 are 100nF, and R2 R5 are 1K. C4 and C5 should be 20pF other values are not critical
The pcb is designed to fit onto the bottom of an NTX2 module, with a board edge SMA connector from Johnson components (part no 142-0711-821) providing an easy to use antenna connection.
AVR code
The code has not been tested with anything other than an led as yet, the next aim is to try with a voltage controlled oscillator, and truetty. It will run on a mega48 at 16 or 20Mhz. The RBAUD, CBAUD and F_CPU constants, along with the target uc and all important settings are located at the top of the makefile. The lookup table is then generated by tabletool and stored in program space. You will need the procyon avrlib code timerx8.c, uart.c, and buffer.c to get this to work, but remember to edit the uart code correctly first - see here for more information on procyon
Main sourcecode
Note that this includes printf debug statements and has inverted enable pin output when debug is defined, to allow an led to go between B.1 and B.2
#include "Radiopulseshaper.h" //#define RBAUD x - use the makefile for these //#define CBAUD x //#define pulse_res (F_CPU/256/RBAUD) //<-- RBAUD with clkdiv=1 #ifdef debug int get_char0(FILE* stream) { int c=-1; while(c==-1) {c=uartGetByte();} //getchar gets the stream, loop until we get something return (u08) c; } int put_char0(char c, FILE *stream) { if(uartReadyTx || !uartBufferedTx ) //if buffer is empty or we arent buffered {uartSendByte(c); //sends directly to uart return 0; } else { //while(!bufferAddToEnd(Txbuff0,c)); //send the character to buffer if(uartAddToTxBuffer(c)) {return 0;} else {return -1;} } } #endif void overflow() { static u08 bufone; timer1PWMASet(bufone); timer1overflows++; if(radioout) { if(position<pulse_res_minus2) {position++;} } else { if(position) {position--;} } bufone=pgm_read_byte(&sin_l[position]); } void send(unsigned char c) { u08 n; radioout=0; //start bit timer1overflows=0; while(timer1overflows<pulse_res); #ifdef debug printf("send\r\n"); #endif for(n=0;n<=7;n++) //byte { radioout=c&(1<<n); timer1overflows=0; while(timer1overflows<pulse_res){}; #ifdef debug printf("n= %d p= %d\r\n", (int) n, (int) position ); #endif } radioout=1; //stop bit timer1overflows=0; while(timer1overflows<pulse_res); #ifdef debug printf("exit\r\n"); #endif } void tuneup() { radioout=0; timer1overflows=0; while(timer1overflows<(unsigned int)(pulse_res)); #ifdef debug cbi(PORTB,2); // allow output to stabilise before turn on #else sbi(PORTB,2); #endif while(timer1overflows<(unsigned int)(2*RBAUD*pulse_res)); // 2 second normally radioout=1; timer1overflows=0; while(timer1overflows<(unsigned int)(2*RBAUD*pulse_res)); //2 seconds with altered definition at top } int main() { int c; u08 radio=1,lenght=0,nodata=0; DDRB=0b00000110; cbi(PORTB,2); //note inverted enable pin uartInit(); uartSetBaudRate(CBAUD); #ifdef debug FILE mystdio0 = FDEV_SETUP_STREAM(put_char0, get_char0, _FDEV_SETUP_RW); //so we can printf to the radio stdout = &mystdio0; //set our stdio out function stdin = &mystdio0; // set our stdio in funciton #endif sei(); timerInit(); timer1SetPrescaler(TIMER_CLK_DIV1); timer1PWMInitICR(255); timer1PWMAOn(); timerAttach(1,overflow); tuneup(); #ifdef debug printf("setup ok\r\n"); #endif while(1) { c=uartGetByte(); if(c!=-1) //there was something in the buffer { #ifdef debug printf("Got %c\r\n",(char) c); #endif if(lenght>120 || !radio) { radio=1; //cbi(PORTB,2); tuneup(); lenght=0; } #ifdef debug printf("sending now, lenght= %d\r\n",(int) lenght); #endif send((unsigned char) c); lenght++; nodata=0; } else { radio=0; #ifdef debug sbi(PORTB,2); printf("waiting...%d\r\n",(int) nodata); #else cbi(PORTB,2); #endif for(c=0;c<100;c++) {_delay_ms(5);} nodata++; if(nodata>20) { radio=1; //cbi(PORTB,2); tuneup(); radio=0; #ifdef debug sbi(PORTB,2); #else cbi(PORTB,2); #endif nodata=0; } } } return 0; }
Header file
#include <avr/interrupt.h> #include <stdio.h> #include <avr/io.h> #include <stdlib.h> #include <util/delay.h> #include <avr/pgmspace.h> #include "global.h" #include "uart.h" #include "buffer.h" #include "avrlibtypes.h" #include "avrlibdefs.h" #include "timerx8.h" #include "default\table.h" #define pulse_res_minus2 pulse_res-2 //#define debug //uncomment for debugging void overflow(void); void tuneup(void); #ifdef debug int put_char0(char c, FILE *stream); int get_char0(FILE *stream); FILE mystdio0; #endif volatile unsigned int timer1overflows; u08 radioout=1; volatile int position;
Changes to uart.h
#ifndef UART_TX_BUFFER_SIZE //! Number of bytes for uart transmit buffer. /// Do not change this value in uart.h, but rather override /// it with the desired value defined in your project's global.h #ifdef debug #define UART_TX_BUFFER_SIZE 0x00FF #else #define UART_TX_BUFFER_SIZE 0x0000 #endif #endif
Change to uart.c
comment out line 244 as so
//uartBufferedTx = FALSE;
Compile time code
Tabletool source
#include <stdio.h> #include <stdlib.h> #include <math.h> #include <string.h> int main(int argc, char *argv[]) { long F_CPU=(long) atoi(argv[argc-3]); int RBAUD=(int) atoi(argv[argc-2]); int CBAUD=(int) atoi(argv[argc-1]); int pulse_res=(F_CPU/256/RBAUD); float c; FILE *fone; printf("Tabletool by Laurenceb\n configuring radio to use:\n //F_CPU=%d\n //RBAUD=%d\n //CBAUD=%d\n //pulse_res=%d\n",F_CPU,RBAUD,CBAUD,pulse_res); fone = fopen("table.h","w+"); fprintf(fone,"//Lookup table \n// F_CPU=%d\n// RBAUD=%d\n// pulse_res=%d\n",F_CPU,RBAUD,pulse_res); fprintf(fone,"#define pulse_res %d\n",pulse_res); fprintf(fone,"const uint8_t sin_l[%d] PROGMEM={",pulse_res); for(c=0;c<pulse_res;c++) { fprintf(fone,"%.0f,", 255.0*(1.0-cos(M_PI*c/pulse_res))/2.0); } fprintf(fone,"};\n"); fclose(fone); //system("PAUSE"); return 0; }
Makefile
############################################################################### # Makefile for the project Radiopulseshaper ############################################################################### ## General Flags - change F_CPU and RBAUD to suit your project ## Begin user editable section PROJECT = Radiopulseshaper MCU = atmega168 TARGET = Radiopulseshaper.elf CC = avr-gcc.exe F_CPU=16000000UL RBAUD=300 CBAUD=4800 ## programmer configuration programmer=avrdude programmerinstallation=$(path) programmerarguments=-p m168 -b 19200 -c avr911 -e -P com7 -U flash:w:./Radiopulseshaper.hex:i -v ## For other programmers change the -c flag and the -P flag ## End user editable section ## Options common to compile, link and assembly rules COMMON = -mmcu=$(MCU) ## Compile options common for all C compilation units. CFLAGS = $(COMMON) CFLAGS += -Wall -gdwarf-2 -DF_CPU=${F_CPU} -DRBAUD=${RBAUD} -DCBAUD=${CBAUD} -Os -funsigned-char -funsigned-bitfields CFLAGS += -MD -MP -MT $(*F).o -MF dep/$(@F).d ## Assembly specific flags ASMFLAGS = $(COMMON) ASMFLAGS += $(CFLAGS) ASMFLAGS += -x assembler-with-cpp -Wa,-gdwarf2 ## Linker flags LDFLAGS = $(COMMON) LDFLAGS += -Wl,-Map=radio.map ## Intel Hex file production flags HEX_FLASH_FLAGS = -R .eeprom HEX_EEPROM_FLAGS = -j .eeprom HEX_EEPROM_FLAGS += --set-section-flags=.eeprom="alloc,load" HEX_EEPROM_FLAGS += --change-section-lma .eeprom=0 --no-change-warnings ## Libraries LIBS = -lc -lm -lprintf_flt -lprintf_min -lscanf_flt -lscanf_min ## Objects that must be built in order to link OBJECTS = Radiopulseshaper.o buffer.o timerx8.o uart.o ## Objects explicitly added by the user LINKONLYOBJECTS = ## Build all: $(TARGET) Radiopulseshaper.hex Radiopulseshaper.eep Radiopulseshaper.lss size ${programmerinstallation}${programmer}${programmerarguments} ## Header production code table.h: tabletool ${F_CPU} ${RBAUD} ${CBAUD} ## Compile Radiopulseshaper.o: ../Radiopulseshaper.c table.h $(CC) $(INCLUDES) $(CFLAGS) -c $< buffer.o: ../buffer.c $(CC) $(INCLUDES) $(CFLAGS) -c $< timerx8.o: ../timerx8.c $(CC) $(INCLUDES) $(CFLAGS) -c $< uart.o: ../uart.c $(CC) $(INCLUDES) $(CFLAGS) -c $< ##Link $(TARGET): $(OBJECTS) $(CC) $(LDFLAGS) $(OBJECTS) $(LINKONLYOBJECTS) $(LIBDIRS) $(LIBS) -o $(TARGET) %.hex: $(TARGET) avr-objcopy -O ihex $(HEX_FLASH_FLAGS) $< $@ %.eep: $(TARGET) -avr-objcopy $(HEX_EEPROM_FLAGS) -O ihex $< $@ || exit 0 %.lss: $(TARGET) avr-objdump -h -S $< > $@ size: ${TARGET} @echo @avr-size -C --mcu=${MCU} ${TARGET} ## Clean target .PHONY: clean clean: -rm -rf $(OBJECTS) Radiopulseshaper.elf dep/* Radiopulseshaper.hex Radiopulseshaper.eep Radiopulseshaper.lss Radiopulseshaper.map table.h ## Other dependencies -include $(shell mkdir dep 2>/dev/null) $(wildcard dep/*)