diff --git a/gpio/CHIP_pro/index.html b/gpio/CHIP_pro/index.html index 0753d55fe2e77691eda26c31210664f1a82a6414..cf6979ff42e5fa7a3163731f845bf74fc75cc93a 100644 --- a/gpio/CHIP_pro/index.html +++ b/gpio/CHIP_pro/index.html @@ -45,7 +45,7 @@ done </pre> -<p><a href='../index.html'>Back</a></p> +<p><a href='../../index.html'>Back</a></p> </body> diff --git a/gpio/RaspberryPiZero_bcm2835/index.html b/gpio/RaspberryPiZero_bcm2835/index.html index c6c0036e688bda4f9884a41ca792b7147d509803..b54dff59547898c0f44aa6834434b7859e715d3c 100644 --- a/gpio/RaspberryPiZero_bcm2835/index.html +++ b/gpio/RaspberryPiZero_bcm2835/index.html @@ -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> diff --git a/gpio/RaspberryPiZero_node_rpio/index.html b/gpio/RaspberryPiZero_node_rpio/index.html index b28591320ae13770bd6856062eba6b94628705c7..d582c55977c82714503db02333cc7e8052bcd554 100644 --- a/gpio/RaspberryPiZero_node_rpio/index.html +++ b/gpio/RaspberryPiZero_node_rpio/index.html @@ -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> diff --git a/gpio/nrf52/index.html b/gpio/nrf52/index.html index 3524d92abc385d1f8800dcacf0b43f3012ad04df..0908ddb4e9090857e752b549d8243e14527f2278 100644 --- a/gpio/nrf52/index.html +++ b/gpio/nrf52/index.html @@ -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> diff --git a/index.html b/index.html index 44ab69d7b49ba2ecb24ca52aff2d4ccfbfdf6f7e..d20497bbe80e65247b48643df81868c83c2d5faa 100644 --- a/index.html +++ b/index.html @@ -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; }); diff --git a/rf/nrf24L01/index.html b/rf/nrf24L01/index.html new file mode 100644 index 0000000000000000000000000000000000000000..14dbd325a787e8f0e294b864b328ab6c544ee5e6 --- /dev/null +++ b/rf/nrf24L01/index.html @@ -0,0 +1,313 @@ +<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 diff --git a/rf/nrf52832/index.html b/rf/nrf52832/index.html index d6fdaaa8e794a5ae08224f72597bb0afefa09b93..b67c2f9c8a44b13b13ac23c3e1a8db957f01dbbd 100644 --- a/rf/nrf52832/index.html +++ b/rf/nrf52832/index.html @@ -132,7 +132,7 @@ void loop() {} -<p><a href='../index.html'>Back</a></p> +<p><a href='../../index.html'>Back</a></p> </body>