From 3e7e8e21f2bb823cb6e74c73d0feddbc3a891107 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 29 Aug 2012 11:23:13 -0700 Subject: [PATCH] altos: SPI radio - use 1->0 for 'done' and 0->1 for 'ready' This changes how the SPI radio protocol uses the interrupt line. Instead of a pulse indicating operation done, this now uses a 0 value for done and a 1 value for ready. The key distinction is that the master can tell when the slave is waiting for the next command instead of hoping that it got done 'soon enough'. Signed-off-by: Keith Packard --- src/drivers/ao_radio_master.c | 112 ++++++++++++++++++---------------- src/drivers/ao_radio_slave.c | 90 +++++++++++++-------------- 2 files changed, 101 insertions(+), 101 deletions(-) diff --git a/src/drivers/ao_radio_master.c b/src/drivers/ao_radio_master.c index bfbcb1f8..73ac3c03 100644 --- a/src/drivers/ao_radio_master.c +++ b/src/drivers/ao_radio_master.c @@ -22,13 +22,16 @@ static __xdata struct ao_radio_spi_reply ao_radio_spi_reply; static __xdata struct ao_radio_spi_request ao_radio_spi_request; -static volatile __xdata uint8_t ao_radio_done = 1; +static volatile __xdata uint8_t ao_radio_wait_mode; +static volatile __xdata uint8_t ao_radio_done = 0; +static volatile __xdata uint8_t ao_radio_ready = 1; static __xdata uint8_t ao_radio_mutex; +static __xdata uint8_t ao_radio_aes_seq; __xdata int8_t ao_radio_cmac_rssi; #if 0 -#define PRINTD(...) do { printf ("\r%s: ", __func__); printf(__VA_ARGS__); flush(); } while(0) +#define PRINTD(...) do { printf ("\r%5u %s: ", ao_tick_count, __func__); printf(__VA_ARGS__); flush(); } while(0) #else #define PRINTD(...) #endif @@ -36,24 +39,18 @@ __xdata int8_t ao_radio_cmac_rssi; static void ao_radio_isr(void) { - ao_exti_disable(AO_RADIO_INT_PORT, AO_RADIO_INT_PIN); - ao_radio_done = 1; - ao_wakeup((void *) &ao_radio_done); -} - -static void -ao_radio_master_delay(void) -{ -// uint16_t i; -// for (i = 0; i < 1000; i++) -// ao_arch_nop(); - ao_delay(1); + if (ao_gpio_get(AO_RADIO_INT_PORT, AO_RADIO_INT_PIN, AO_RADIO_INT)) { + ao_radio_ready = 1; + ao_wakeup((void *) &ao_radio_ready); + } else { + ao_radio_done = 1; + ao_wakeup((void *) &ao_radio_done); + } } static void ao_radio_master_start(void) { - ao_radio_master_delay(); ao_spi_get_bit(AO_RADIO_CS_PORT, AO_RADIO_CS_PIN, AO_RADIO_CS, AO_RADIO_SPI_BUS, AO_SPI_SPEED_200kHz); @@ -64,32 +61,50 @@ ao_radio_master_stop(void) { ao_spi_put_bit(AO_RADIO_CS_PORT, AO_RADIO_CS_PIN, AO_RADIO_CS, AO_RADIO_SPI_BUS); -// ao_delay(1); } static uint8_t ao_radio_master_send(void) { - if (!ao_radio_done) - printf ("radio not done in ao_radio_master_send\n"); + uint8_t ret; + PRINTD("send %d\n", ao_radio_spi_request.len); ao_radio_done = 0; - ao_exti_enable(AO_RADIO_INT_PORT, AO_RADIO_INT_PIN); + + /* Wait for radio chip to be ready for a command + */ + + PRINTD("Waiting radio ready\n"); + cli(); + ao_radio_ready = ao_gpio_get(AO_RADIO_INT_PORT, + AO_RADIO_INT_PIN, AO_RADIO_INT); + ret = 0; + while (!ao_radio_ready) { + ret = ao_sleep((void *) &ao_radio_ready); + if (ret) + break; + } + sei(); + if (ret) + return 0; + + PRINTD("radio_ready %d radio_done %d\n", ao_radio_ready, ao_radio_done); + + /* Send the command + */ + ao_radio_wait_mode = 0; ao_radio_master_start(); ao_spi_send(&ao_radio_spi_request, ao_radio_spi_request.len, AO_RADIO_SPI_BUS); ao_radio_master_stop(); + PRINTD("waiting for send done %d\n", ao_radio_done); cli(); while (!ao_radio_done) - if (ao_sleep((void *) &ao_radio_done)) { - printf ("ao_radio_master awoken\n"); + if (ao_sleep((void *) &ao_radio_done)) break; - } sei(); - PRINTD ("sent, radio done %d\n", ao_radio_done); - if (!ao_radio_done) - printf ("radio didn't finish after ao_radio_master_send\n"); + PRINTD ("sent, radio done %d isr_0 %d isr_1 %d\n", ao_radio_done, isr_0_count, isr_1_count); return ao_radio_done; } @@ -112,15 +127,6 @@ ao_radio_put(void) static void ao_radio_get_data(__xdata void *d, uint8_t size) { - uint8_t ret; - - PRINTD ("send fetch req\n"); - ao_radio_spi_request.len = AO_RADIO_SPI_REQUEST_HEADER_LEN; - ao_radio_spi_request.request = AO_RADIO_SPI_RECV_FETCH; - ao_radio_spi_request.recv_len = size; - ret = ao_radio_master_send(); - PRINTD ("fetch req sent %d\n", ret); - PRINTD ("fetch\n"); ao_radio_master_start(); ao_spi_recv(&ao_radio_spi_reply, @@ -167,21 +173,17 @@ ao_radio_recv(__xdata void *d, uint8_t size) return 0; } ao_radio_get_data(d, size); - recv = ao_radio_spi_reply.status; - ao_radio_put(); return recv; } -int8_t -ao_radio_cmac_send(__xdata void *packet, uint8_t len) __reentrant +static void +ao_radio_cmac_set_key(void) { - if (len > AO_CMAC_MAX_LEN) - return AO_RADIO_CMAC_LEN_ERROR; - - PRINTD ("cmac_send: send %d\n", len); + if (ao_radio_aes_seq == ao_config_aes_seq) + return; /* Set the key. */ PRINTD ("set key\n"); @@ -190,6 +192,18 @@ ao_radio_cmac_send(__xdata void *packet, uint8_t len) __reentrant ao_radio_master_send(); ao_radio_put(); PRINTD ("key set\n"); + ao_radio_aes_seq = ao_config_aes_seq; +} + +int8_t +ao_radio_cmac_send(__xdata void *packet, uint8_t len) __reentrant +{ + if (len > AO_CMAC_MAX_LEN) + return AO_RADIO_CMAC_LEN_ERROR; + + ao_radio_cmac_set_key(); + + PRINTD ("cmac_send: send %d\n", len); /* Send the data */ @@ -212,21 +226,14 @@ ao_radio_cmac_recv(__xdata void *packet, uint8_t len, uint16_t timeout) __reentr if (len > AO_CMAC_MAX_LEN) return AO_RADIO_CMAC_LEN_ERROR; - /* Set the key. - */ - PRINTD ("setting key\n"); - ao_radio_get(AO_RADIO_SPI_CMAC_KEY, AO_AES_LEN); - ao_radio_spi_request.timeout = timeout; - ao_xmemcpy(&ao_radio_spi_request.payload, &ao_config.aes_key, AO_AES_LEN); - recv = ao_radio_master_send(); - ao_radio_put(); - PRINTD ("key set: %d\n", recv); + ao_radio_cmac_set_key(); /* Recv the data */ PRINTD ("queuing recv\n"); ao_radio_get(AO_RADIO_SPI_CMAC_RECV, 0); ao_radio_spi_request.recv_len = len; + ao_radio_spi_request.timeout = timeout; recv = ao_radio_master_send(); PRINTD ("recv queued: %d\n", recv); if (!recv) { @@ -300,7 +307,8 @@ ao_radio_init(void) ao_enable_port(AO_RADIO_INT_PORT); ao_exti_setup(AO_RADIO_INT_PORT, AO_RADIO_INT_PIN, - AO_EXTI_MODE_FALLING, + AO_EXTI_MODE_RISING|AO_EXTI_MODE_FALLING, ao_radio_isr); + ao_exti_enable(AO_RADIO_INT_PORT, AO_RADIO_INT_PIN); ao_cmd_register(&ao_radio_cmds[0]); } diff --git a/src/drivers/ao_radio_slave.c b/src/drivers/ao_radio_slave.c index ab23894f..9a01bbfa 100644 --- a/src/drivers/ao_radio_slave.c +++ b/src/drivers/ao_radio_slave.c @@ -23,54 +23,69 @@ static __xdata struct ao_radio_spi_reply ao_radio_spi_reply; static __xdata struct ao_radio_spi_request ao_radio_spi_request; -static __xdata uint8_t ao_radio_spi_recv_request; -static __xdata uint8_t ao_radio_spi_recv_len; -static __xdata uint16_t ao_radio_spi_recv_timeout; +static __xdata uint8_t slave_state; static void -ao_radio_slave_signal(void) +ao_radio_slave_low(void) { + uint16_t i; + + if (slave_state != 1) + ao_panic(1); + ao_led_toggle(AO_LED_GREEN); ao_gpio_set(AO_RADIO_SLAVE_INT_PORT, AO_RADIO_SLAVE_INT_BIT, AO_RADIO_SLAVE_INT_PIN, 0); - ao_arch_nop(); - ao_arch_nop(); - ao_arch_nop(); + for (i = 0; i < 1000; i++) + ao_arch_nop(); + slave_state = 0; +} + +static void +ao_radio_slave_high(void) +{ + if (slave_state != 0) + ao_panic(2); + ao_led_toggle(AO_LED_RED); ao_gpio_set(AO_RADIO_SLAVE_INT_PORT, AO_RADIO_SLAVE_INT_BIT, AO_RADIO_SLAVE_INT_PIN, 1); + slave_state = 1; } static void ao_radio_slave_spi(void) { - uint8_t need_signal = 0; - ao_spi_get_slave(AO_RADIO_SLAVE_BUS); for (;;) { ao_spi_recv(&ao_radio_spi_request, (2 << 13) | sizeof (ao_radio_spi_request), AO_RADIO_SLAVE_BUS); - if (need_signal) { - ao_radio_slave_signal(); - need_signal = 0; - } + ao_radio_slave_high(); ao_spi_recv_wait(); switch (ao_radio_spi_request.request) { case AO_RADIO_SPI_RECV: - case AO_RADIO_SPI_CMAC_RECV: + + /* XXX monitor CS to interrupt the receive */ + ao_config.radio_setting = ao_radio_spi_request.setting; - ao_radio_spi_recv_request = ao_radio_spi_request.request; - ao_radio_spi_recv_len = ao_radio_spi_request.recv_len; - ao_radio_spi_recv_timeout = ao_radio_spi_request.timeout; - ao_wakeup(&ao_radio_spi_recv_len); + ao_radio_spi_reply.status = ao_radio_recv(&ao_radio_spi_reply.payload, + ao_radio_spi_request.recv_len); + ao_radio_spi_reply.rssi = 0; + ao_spi_send(&ao_radio_spi_reply, + AO_RADIO_SPI_REPLY_HEADER_LEN + ao_radio_spi_request.recv_len, + AO_RADIO_SLAVE_BUS); + ao_radio_slave_low(); + ao_spi_send_wait(); continue; - case AO_RADIO_SPI_RECV_FETCH: + case AO_RADIO_SPI_CMAC_RECV: + ao_config.radio_setting = ao_radio_spi_request.setting; + ao_radio_spi_reply.status = ao_radio_cmac_recv(&ao_radio_spi_reply.payload, + ao_radio_spi_request.recv_len, + ao_radio_spi_request.timeout); + ao_radio_spi_reply.rssi = ao_radio_cmac_rssi; ao_spi_send(&ao_radio_spi_reply, - ao_radio_spi_request.recv_len, + AO_RADIO_SPI_REPLY_HEADER_LEN + ao_radio_spi_request.recv_len, AO_RADIO_SLAVE_BUS); - ao_radio_slave_signal(); + ao_radio_slave_low(); ao_spi_send_wait(); continue; - case AO_RADIO_SPI_RECV_ABORT: - ao_radio_recv_abort(); - break; case AO_RADIO_SPI_SEND: ao_config.radio_setting = ao_radio_spi_request.setting; ao_radio_send(&ao_radio_spi_request.payload, @@ -96,38 +111,15 @@ ao_radio_slave_spi(void) ao_radio_test(0); break; } - need_signal = 1; - } -} - -static void -ao_radio_slave_recv(void) -{ - uint8_t len; - for (;;) { - while (!ao_radio_spi_recv_len) - ao_sleep(&ao_radio_spi_recv_len); - len = ao_radio_spi_recv_len; - ao_radio_spi_recv_len = 0; - if (ao_radio_spi_recv_request == AO_RADIO_SPI_RECV) { - ao_radio_spi_reply.status = ao_radio_recv(&ao_radio_spi_reply.payload, len); - ao_radio_spi_reply.rssi = 0; - } else { - ao_radio_spi_reply.status = ao_radio_cmac_recv(&ao_radio_spi_reply.payload, len, - ao_radio_spi_recv_timeout); - ao_radio_spi_reply.rssi = ao_radio_cmac_rssi; - } - ao_radio_slave_signal(); + ao_radio_slave_low(); } } static __xdata struct ao_task ao_radio_slave_spi_task; -static __xdata struct ao_task ao_radio_slave_recv_task; void ao_radio_slave_init(void) { ao_add_task(&ao_radio_slave_spi_task, ao_radio_slave_spi, "radio_spi"); - ao_add_task(&ao_radio_slave_recv_task, ao_radio_slave_recv, "radio_recv"); - ao_enable_output(AO_RADIO_SLAVE_INT_PORT, AO_RADIO_SLAVE_INT_BIT, AO_RADIO_SLAVE_INT_PIN, 1); + ao_enable_output(AO_RADIO_SLAVE_INT_PORT, AO_RADIO_SLAVE_INT_BIT, AO_RADIO_SLAVE_INT_PIN, 0); } -- 2.30.2