Skip to content
Snippets Groups Projects
Commit 80c56ffc authored by Sam Calisch's avatar Sam Calisch
Browse files

fix relative link

parent 69c3bb52
Branches
Tags
No related merge requests found
Pipeline #
......@@ -45,7 +45,7 @@ done
</pre>
<p><a href='../index.html'>Back</a></p>
<p><a href='../../index.html'>Back</a></p>
</body>
......
......@@ -69,7 +69,7 @@ int main(int argc, char **argv)
<p>Note: This test was run on a RPiZero W, instead of the baseline version (without wifi).</p>
<p><a href='../index.html'>Back</a></p>
<p><a href='../../index.html'>Back</a></p>
</body>
......
......@@ -33,7 +33,7 @@ while(1){rpio.write(3, 1-rpio.read(5) ); }
<p>Note: This test was run on a RPiZero W, instead of the baseline version (without wifi).</p>
<p><a href='../index.html'>Back</a></p>
<p><a href='../../index.html'>Back</a></p>
</body>
......
......@@ -65,7 +65,7 @@ void loop() {
</code>
</pre>
<p><a href='../index.html'>Back</a></p>
<p><a href='../../index.html'>Back</a></p>
</body>
......
......@@ -51,6 +51,7 @@ function make_graph(div_id,json_key,axis_labels,use_khz){
height = 600 - margin.top - margin.bottom;
var x = d3.scale.linear().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
//var y = d3.scale.log().range([height, 0]);
var color = d3.scale.category10();
var xAxis = d3.svg.axis().scale(x).orient("bottom").tickSize(-height,0);
var yAxis = d3.svg.axis().scale(y).orient("left").tickSize(-width,0);
......@@ -76,8 +77,12 @@ function make_graph(div_id,json_key,axis_labels,use_khz){
else return 1/p;
}
//for linear
x.domain([0,d3.max(data, function(d) { return 1.1*d.dev_board_price; })]).nice();
y.domain([0,d3.max(data, function(d) { return 1.1*period_to_freq(d.ring_period); })]).nice();
//for log
//x.domain(d3.extent(data, function(d) { return 1.1*d.dev_board_price; })).nice();
//y.domain(d3.extent(data, function(d) { return 1.1*period_to_freq(d.ring_period); })).nice();
var node = svg.selectAll("g").data(data).enter().append("g").append("a")
.attr("xlink:href", function(d) { return d.subdirectory_path; });
......
<html>
<head>
<style>
pre code {
background-color: #eee;
border: 1px solid #999;
display: block;
padding: 20px;
}
figure{
text-align: center
}
</style>
</head>
<body>
<h1>NRF24L01</h1>
<figure>
<img src='ring.png' width=50%>
<figcaption>RF Ring oscillator with NRF24L01. Note: the cursors are measuring half a cycle.</figcaption>
</figure>
<p>This RF ring oscillator runs on the NRF24L01 using an Xmega 8E5 microcontroller running at 32 MHz. C code is available in the linked files (<a href='nrf-ftdi-ring.c'>nrf-ftdi-ring.c</a>, <a href='nrf-ftdi-ring.make'>nrf-ftdi-ring.make</a>, <a href='serial.h'>serial.h</a>), or visible below.</p>
<pre>
<code>
#ifndef F_CPU
#define F_CPU 32000000UL
#endif
#include "serial.h"
#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#define SS_BM PIN4_bm
#define CE_BM PIN0_bm
#define IRQ_BM PIN2_bm
//NRF24L01 registers
//https://www.nordicsemi.com/eng/content/download/2726/34069/file/nrf24L01P_Product_Specification_1_0.pdf
//Every new command must be started by a high to low transition on CSN.
const uint8_t CONFIG = 0x00;
const uint8_t EN_AA = 0x01;
const uint8_t EN_RXADDR = 0x02;
const uint8_t SETUP_AW = 0x03;
const uint8_t SETUP_RETR = 0x04;
const uint8_t RF_CH = 0x05;
const uint8_t RF_SETUP = 0x06;
const uint8_t STATUS = 0x07;
const uint8_t OBSERVE_TX = 0x08;
const uint8_t RPD = 0x09;
const uint8_t RX_ADDR_P0 = 0x0A;
const uint8_t RX_ADDR_P1 = 0x0B;
const uint8_t RX_ADDR_P2 = 0x0C;
const uint8_t RX_ADDR_P3 = 0x0D;
const uint8_t RX_ADDR_P4 = 0x0E;
const uint8_t RX_ADDR_P5 = 0x0F;
const uint8_t TX_ADDR = 0x10;
const uint8_t RX_PW_P0 = 0x11;
const uint8_t RX_PW_P1 = 0x12;
const uint8_t RX_PW_P2 = 0x13;
const uint8_t RX_PW_P3 = 0x14;
const uint8_t RX_PW_P4 = 0x15;
const uint8_t RX_PW_P5 = 0x16;
const uint8_t FIFO_STATUS = 0x17;
const uint8_t DYNPD = 0x1C;
const uint8_t FEATURE = 0x1D;
const uint8_t PWR_UP = 1 << 1;
const uint8_t PRIM_RX = 1 << 0;
const uint8_t R_REGISTER = 0;
const uint8_t W_REGISTER = 1<<5;
const uint8_t R_RX_PAYLOAD = (1<<6) | (1<<5) | 1;
const uint8_t W_TX_PAYLOAD = (1<<7) | (1<<5);
const uint8_t FLUSH_TX = (1<<7) | (1<<6) | (1<<5) | 1;
const uint8_t FLUSH_RX = (1<<7) | (1<<6) | (1<<5) | (1<<1);
const uint8_t MAX_RT = 1<<4;
const uint8_t TX_DS = 1<<5; //tx data sent interrupt
const uint8_t RX_DR = 1<<6; //rx data ready interrupt
uint8_t read_register(uint8_t reg){
PORTC.OUTCLR = SS_BM; //SS low
_delay_us(1); //give time after ss low
SPIC.DATA = R_REGISTER | reg; while(!(SPIC.STATUS & SPI_IF_bm)) {};
SPIC.DATA = 0; while(!(SPIC.STATUS & SPI_IF_bm)) {};
uint8_t temp = SPIC.DATA;
PORTC.OUTSET = SS_BM; //SS high
_delay_us(1); //give time after ss high
return temp;
}
void write_register(uint8_t reg, uint8_t val){
//must be in standby mode before calling this function!
PORTC.OUTCLR = SS_BM; //SS low
_delay_us(1);
SPIC.DATA = W_REGISTER | reg; while(!(SPIC.STATUS & SPI_IF_bm)) {};
SPIC.DATA = val ; while(!(SPIC.STATUS & SPI_IF_bm)) {};
PORTC.OUTSET = SS_BM; //SS high
_delay_us(1);
}
USART_data_t USART_data;
uint8_t token = 0; //token to pass
uint8_t tempval = 0;
const int pll_delay_us = 130;
const int ce_delay_us = 10;
void check_registers(uint8_t id){
//for debug only
//enter standby so we can write to configuration register.
PORTC.OUTCLR = CE_BM;
_delay_us(ce_delay_us);
PORTC.OUTCLR = SS_BM; //SS low
_delay_us(10);
SPIC.DATA = R_REGISTER | CONFIG; while(!(SPIC.STATUS & SPI_IF_bm)) {};
uint8_t status = SPIC.DATA;
SPIC.DATA = 0; while(!(SPIC.STATUS & SPI_IF_bm)) {}; //read
uint8_t config = SPIC.DATA;
PORTC.OUTSET = SS_BM; //SS high
_delay_us(10);
usart_send_byte(&USART_data,id);
usart_send_byte(&USART_data,status);
usart_send_byte(&USART_data,config);
usart_send_byte(&USART_data,token);
usart_send_byte(&USART_data,10);
}
void rx_from_standby(){
//call this from standby to enter rx mode
//tempval = read_register(CONFIG);
//write_register(CONFIG, tempval | PRIM_RX);
write_register(CONFIG, 0x13); //replaces the spi read
//set CE for at least 10 us
PORTC.OUTSET = CE_BM;
//_delay_us(ce_delay_us); //is this necessary?
//wait for pll to settle
_delay_us(pll_delay_us);
}
void setup(){
// set up clock
OSC.CTRL = OSC_RC32MEN_bm; // enable 32MHz clock
while (!(OSC.STATUS & OSC_RC32MRDY_bm)); // wait for clock to be ready
CCP = CCP_IOREG_gc; // enable protected register change
CLK.CTRL = CLK_SCLKSEL_RC32M_gc; // switch to 32MHz clock
//set up usart
PORTD.DIRSET = PIN3_bm; //TXD0
PORTD.DIRCLR = PIN2_bm; //RXD0
USART_InterruptDriver_Initialize(&USART_data, &USARTD0, USART_DREINTLVL_LO_gc);
USART_Format_Set(USART_data.usart, USART_CHSIZE_8BIT_gc,
USART_PMODE_DISABLED_gc, 0);
USART_RxdInterruptLevel_Set(USART_data.usart, USART_RXCINTLVL_LO_gc);
//take f_sysclk/(BSEL+1) ~= f_baud*16 with zero scale. See manual or spreadsheet for scale defs
USART_Baudrate_Set(&USARTD0, 123 , -4); //230400 baud with .08% error
USART_Rx_Enable(USART_data.usart);
USART_Tx_Enable(USART_data.usart);
//enable interrupts
PMIC.CTRL |= PMIC_LOLVLEX_bm;
PORTC.DIRSET = SS_BM; //set up SS pin on PC4
PORTC.PIN4CTRL = PORT_OPC_WIREDANDPULL_gc; //wired AND and pull-up on SS
PORTC.PIN2CTRL = PORT_OPC_PULLUP_gc; //pull-up on IRQ
PORTC.DIRSET = CE_BM; //set up CE pin on PC0
//set up spic.ctrl
SPIC.CTRL = SPI_PRESCALER_DIV4_gc | /* SPI prescaler. */
(1 ? SPI_CLK2X_bm : 0) | /* SPI Clock double. */
SPI_ENABLE_bm | /* Enable SPI module. */
SPI_MASTER_bm | /* SPI master. */
SPI_MODE_0_gc; //bits driven at falling edge, sampled at rising edge
SPIC.INTCTRL = SPI_INTLVL_OFF_gc;
PORTC.DIRSET = PIN5_bm | PIN7_bm; //mosi and sck as outputs
PORTC.OUTSET = SS_BM; //SS high
_delay_ms(5); //warm up
//nrf config
//turn off auto-retransmit
write_register(SETUP_RETR,0);
//turn off disable auto-acknowledge
write_register(EN_AA,0);
//set the PWR_UP bit in the CONFIG register to 1 to enter standby mode
write_register(CONFIG,PWR_UP);
_delay_ms(3);
//set up data pipe 0
write_register(EN_RXADDR,1);
//set data pipe 0 payload length to 1
write_register(RX_PW_P0,1);
//set data rate to 2 Mbps with high power
//I think there may be a typo in the data sheet here.
write_register(RF_SETUP,(0<<5) | (1<<3) | (1<<2) | (1<<1));
//flush tx
PORTC.OUTCLR = SS_BM; //SS low
SPIC.DATA = FLUSH_TX; while(!(SPIC.STATUS & SPI_IF_bm)) {};
PORTC.OUTSET = SS_BM; //SS high
_delay_ms(1); //give time to start up
//flush rx
PORTC.OUTCLR = SS_BM; //SS low
SPIC.DATA = FLUSH_RX; while(!(SPIC.STATUS & SPI_IF_bm)) {};
PORTC.OUTSET = SS_BM; //SS high
_delay_ms(1); //give time to start up
// and mask MAX_RT interrupts on IRQ
tempval = read_register(CONFIG);
write_register(CONFIG,tempval | MAX_RT);
//clear all interrupts
tempval = read_register(STATUS);
write_register(STATUS,tempval | MAX_RT | RX_DR | TX_DS);
_delay_ms(1);
sei();
//enter standby so we can write to configuration register.
PORTC.OUTCLR = CE_BM;
_delay_us(ce_delay_us);
rx_from_standby(); //enter rx mode
}
void send_token(){
//call this from standby1
//put token in tx fifo
PORTC.OUTCLR = SS_BM; //SS low
_delay_us(1);
SPIC.DATA = W_TX_PAYLOAD; while(!(SPIC.STATUS & SPI_IF_bm)) {};
tempval = SPIC.DATA; //get status while we have it
SPIC.DATA = 0; while(!(SPIC.STATUS & SPI_IF_bm)) {};
PORTC.OUTSET = SS_BM; //SS high
_delay_us(1);
//tempval = read_register(CONFIG);
write_register(CONFIG, tempval & (~PRIM_RX));
//pulse CE
PORTC.OUTSET = CE_BM; _delay_us(ce_delay_us); PORTC.OUTCLR = CE_BM;
//wait for pll to settle
_delay_us(pll_delay_us);
//wait until transmit complete
while( PORTC.IN & IRQ_BM ){}
//clear IRQ -- need to be in standby.
tempval = read_register(STATUS);
write_register(STATUS, tempval | TX_DS);
//enter standby so we can write to configuration register.
rx_from_standby(); //return to RX mode
}
void read_token(){
//call this from rx
//get token from rx fifo
PORTC.OUTCLR = SS_BM; //SS low
_delay_us(1);
SPIC.DATA = R_RX_PAYLOAD; while(!(SPIC.STATUS & SPI_IF_bm)) {};
tempval = SPIC.DATA; //get status while we have it
SPIC.DATA = 0; while(!(SPIC.STATUS & SPI_IF_bm)) {};
token = SPIC.DATA;
PORTC.OUTSET = SS_BM; //SS high
_delay_us(1);
//transition from RX to standby1 (CE=0)
PORTC.OUTCLR = CE_BM;
_delay_us(ce_delay_us);
//clear IRQ
write_register(STATUS, tempval | RX_DR);
//check_registers(66);
}
int main(void) {
setup();
while(1){
if ( !(PORTC.IN & IRQ_BM)){
read_token(); //in standby
token += 1; //increment token
//check_registers(65);
send_token();
}
//we use a signal on the usart to start the oscillation.
if (USART_RXBufferData_Available(&USART_data)) {
USART_RXBuffer_GetByte(&USART_data); //clear usart buffer so we only fire once.
//transition from RX to standby1 (CE=0)
PORTC.OUTCLR = CE_BM;
_delay_us(ce_delay_us);
send_token();
//check_registers(64);
}
//_delay_ms(10);
}
}
ISR(USARTD0_RXC_vect){USART_RXComplete(&USART_data);}
ISR(USARTD0_DRE_vect){USART_DataRegEmpty(&USART_data);}
</code>
</pre>
<p>Most of the time is spent switching between TX and RX (one switch takes 130 us).</p>
<figure>
<img src='nrf24-state-diagram.png' width=80%>
<figcaption>NRF24 Radio Modes.</figcaption>
</figure>
<p><a href='../../index.html'>Back</a></p>
</body>
</html>
\ No newline at end of file
......@@ -132,7 +132,7 @@ void loop() {}
<p><a href='../index.html'>Back</a></p>
<p><a href='../../index.html'>Back</a></p>
</body>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment