altos: Rework packet receive for cc1120
authorKeith Packard <keithp@keithp.com>
Sat, 5 Jul 2014 07:04:06 +0000 (00:04 -0700)
committerKeith Packard <keithp@keithp.com>
Sat, 5 Jul 2014 07:38:10 +0000 (00:38 -0700)
Instead of blocking on PQT, just set up the receiver to start going
and when the first bit interrupt comes in, grab the SPI bus if
possible and configure it for reception. This improves sensitivity in
the radio by a significant amount while making the code conceptually a
bit nicer.

Signed-off-by: Keith Packard <keithp@keithp.com>
src/cc1111/ao_pins.h
src/drivers/ao_cc1120.c
src/kernel/ao.h
src/kernel/ao_mutex.c
src/lpc/ao_arch_funcs.h
src/stm/ao_arch_funcs.h
src/stm/ao_spi_stm.c

index 83a3c774a3732ad50ee9f957e41b21b51c3e5d4f..1bc3d716004503bc4d0e2ad4f463cb53824c1b6c 100644 (file)
@@ -58,6 +58,7 @@
        #define HAS_MONITOR             0
        #define HAS_TELEMETRY           1
        #define HAS_RADIO_RATE          0       /* not enough space for this */
        #define HAS_MONITOR             0
        #define HAS_TELEMETRY           1
        #define HAS_RADIO_RATE          0       /* not enough space for this */
+       #define HAS_MUTEX_TRY           0
 #endif
 
 #if defined(TELEMETRUM_V_1_1)
 #endif
 
 #if defined(TELEMETRUM_V_1_1)
        #define HAS_MONITOR             0
        #define HAS_TELEMETRY           1
        #define HAS_RADIO_RATE          0       /* not enough space for this */
        #define HAS_MONITOR             0
        #define HAS_TELEMETRY           1
        #define HAS_RADIO_RATE          0       /* not enough space for this */
+       #define HAS_MUTEX_TRY           0
 #endif
 
 #if defined(TELEMETRUM_V_1_2)
 #endif
 
 #if defined(TELEMETRUM_V_1_2)
        #define HAS_MONITOR             0
        #define HAS_TELEMETRY           1
        #define HAS_RADIO_RATE          0       /* not enough space for this */
        #define HAS_MONITOR             0
        #define HAS_TELEMETRY           1
        #define HAS_RADIO_RATE          0       /* not enough space for this */
+       #define HAS_MUTEX_TRY           0
 #endif
 
 #if defined(TELEDONGLE_V_0_2)
 #endif
 
 #if defined(TELEDONGLE_V_0_2)
index 5d51fbcd518a51df934ae649849cdfe364eacb32..1b907940f6f1d5104c13fa43da120f9dfc1b882e 100644 (file)
@@ -41,8 +41,10 @@ extern const uint32_t        ao_radio_cal;
 
 #define FOSC   32000000
 
 
 #define FOSC   32000000
 
+#define ao_radio_try_select(task_id)   ao_spi_try_get_mask(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN),AO_CC1120_SPI_BUS,AO_SPI_SPEED_4MHz, task_id)
 #define ao_radio_select()      ao_spi_get_mask(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN),AO_CC1120_SPI_BUS,AO_SPI_SPEED_4MHz)
 #define ao_radio_deselect()    ao_spi_put_mask(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN),AO_CC1120_SPI_BUS)
 #define ao_radio_select()      ao_spi_get_mask(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN),AO_CC1120_SPI_BUS,AO_SPI_SPEED_4MHz)
 #define ao_radio_deselect()    ao_spi_put_mask(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN),AO_CC1120_SPI_BUS)
+#define ao_radio_spi_send_sync(d,l)    ao_spi_send_sync((d), (l), AO_CC1120_SPI_BUS)
 #define ao_radio_spi_send(d,l) ao_spi_send((d), (l), AO_CC1120_SPI_BUS)
 #define ao_radio_spi_send_fixed(d,l) ao_spi_send_fixed((d), (l), AO_CC1120_SPI_BUS)
 #define ao_radio_spi_recv(d,l) ao_spi_recv((d), (l), AO_CC1120_SPI_BUS)
 #define ao_radio_spi_send(d,l) ao_spi_send((d), (l), AO_CC1120_SPI_BUS)
 #define ao_radio_spi_send_fixed(d,l) ao_spi_send_fixed((d), (l), AO_CC1120_SPI_BUS)
 #define ao_radio_spi_recv(d,l) ao_spi_recv((d), (l), AO_CC1120_SPI_BUS)
@@ -107,7 +109,7 @@ ao_radio_reg_write(uint16_t addr, uint8_t value)
 }
 
 static void
 }
 
 static void
-ao_radio_burst_read_start (uint16_t addr)
+_ao_radio_burst_read_start (uint16_t addr)
 {
        uint8_t data[2];
        uint8_t d;
 {
        uint8_t data[2];
        uint8_t d;
@@ -124,8 +126,8 @@ ao_radio_burst_read_start (uint16_t addr)
                           addr);
                d = 1;
        }
                           addr);
                d = 1;
        }
-       ao_radio_select();
-       ao_radio_spi_send(data, d);
+
+       ao_radio_spi_send_sync(data, d);
 }
 
 static void
 }
 
 static void
@@ -209,7 +211,7 @@ ao_radio_tx_fifo_space(void)
        return CC1120_FIFO_SIZE - ao_radio_reg_read(CC1120_NUM_TXBYTES);
 }
 
        return CC1120_FIFO_SIZE - ao_radio_reg_read(CC1120_NUM_TXBYTES);
 }
 
-#if 0
+#if CC1120_DEBUG
 static uint8_t
 ao_radio_status(void)
 {
 static uint8_t
 ao_radio_status(void)
 {
@@ -275,11 +277,13 @@ static void
 ao_radio_idle(void)
 {
        for (;;) {
 ao_radio_idle(void)
 {
        for (;;) {
-               uint8_t state = ao_radio_strobe(CC1120_SIDLE);
-               if ((state >> CC1120_STATUS_STATE) == CC1120_STATUS_STATE_IDLE)
+               uint8_t state = (ao_radio_strobe(CC1120_SIDLE) >> CC1120_STATUS_STATE) & CC1120_STATUS_STATE_MASK;
+               if (state == CC1120_STATUS_STATE_IDLE)
                        break;
                        break;
-               if ((state >> CC1120_STATUS_STATE) == CC1120_STATUS_STATE_TX_FIFO_ERROR)
+               if (state == CC1120_STATUS_STATE_TX_FIFO_ERROR)
                        ao_radio_strobe(CC1120_SFTX);
                        ao_radio_strobe(CC1120_SFTX);
+               if (state == CC1120_STATUS_STATE_RX_FIFO_ERROR)
+                       ao_radio_strobe(CC1120_SFRX);
        }
        /* Flush any pending TX bytes */
        ao_radio_strobe(CC1120_SFTX);
        }
        /* Flush any pending TX bytes */
        ao_radio_strobe(CC1120_SFTX);
@@ -948,6 +952,11 @@ static uint16_t    rx_data_consumed;
 static uint16_t rx_data_cur;
 static uint8_t rx_ignore;
 static uint8_t rx_waiting;
 static uint16_t rx_data_cur;
 static uint8_t rx_ignore;
 static uint8_t rx_waiting;
+static uint8_t rx_starting;
+static uint8_t rx_task_id;
+static uint32_t        rx_fast_start;
+static uint32_t rx_slow_start;
+static uint32_t        rx_missed;
 
 #if AO_PROFILE
 static uint32_t        rx_start_tick, rx_packet_tick, rx_done_tick, rx_last_done_tick;
 
 #if AO_PROFILE
 static uint32_t        rx_start_tick, rx_packet_tick, rx_done_tick, rx_last_done_tick;
@@ -962,13 +971,34 @@ ao_radio_rx_isr(void)
 {
        uint8_t d;
 
 {
        uint8_t d;
 
+       if (rx_task_id) {
+               if (ao_radio_try_select(rx_task_id)) {
+                       ++rx_fast_start;
+                       rx_task_id = 0;
+                       _ao_radio_burst_read_start(CC1120_SOFT_RX_DATA_OUT);
+               } else {
+                       if (rx_ignore)
+                               --rx_ignore;
+                       else {
+                               ao_radio_abort = 1;
+                               rx_missed++;
+                       }
+                       return;
+               }
+       }
+       if (rx_starting) {
+               rx_starting = 0;
+               ao_wakeup(&ao_radio_wake);
+       }
        d = AO_CC1120_SPI.dr;
        AO_CC1120_SPI.dr = 0;
        if (rx_ignore == 0) {
        d = AO_CC1120_SPI.dr;
        AO_CC1120_SPI.dr = 0;
        if (rx_ignore == 0) {
-               if (rx_data_cur >= rx_data_count)
-                       ao_exti_disable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
-               else
+               if (rx_data_cur < rx_data_count)
                        rx_data[rx_data_cur++] = d;
                        rx_data[rx_data_cur++] = d;
+               if (rx_data_cur >= rx_data_count) {
+                       ao_spi_clr_cs(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN));
+                       ao_exti_disable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
+               }
                if (rx_waiting && rx_data_cur - rx_data_consumed >= AO_FEC_DECODE_BLOCK) {
 #if AO_PROFILE
                        if (!rx_packet_tick)
                if (rx_waiting && rx_data_cur - rx_data_consumed >= AO_FEC_DECODE_BLOCK) {
 #if AO_PROFILE
                        if (!rx_packet_tick)
@@ -987,24 +1017,20 @@ ao_radio_rx_isr(void)
 static uint16_t
 ao_radio_rx_wait(void)
 {
 static uint16_t
 ao_radio_rx_wait(void)
 {
-       do {
-               if (ao_radio_mcu_wake)
-                       ao_radio_check_marc_status();
-               ao_alarm(AO_MS_TO_TICKS(100));
-               ao_arch_block_interrupts();
-               rx_waiting = 1;
-               while (rx_data_cur - rx_data_consumed < AO_FEC_DECODE_BLOCK &&
-                      !ao_radio_abort &&
-                      !ao_radio_mcu_wake)
-               {
-                       if (ao_sleep(&ao_radio_wake))
-                               ao_radio_abort = 1;
-               }
-               rx_waiting = 0;
-               ao_arch_release_interrupts();
-               ao_clear_alarm();
-       } while (ao_radio_mcu_wake);
-       if (ao_radio_abort)
+       ao_alarm(AO_MS_TO_TICKS(100));
+       ao_arch_block_interrupts();
+       rx_waiting = 1;
+       while (rx_data_cur - rx_data_consumed < AO_FEC_DECODE_BLOCK &&
+              !ao_radio_abort &&
+              !ao_radio_mcu_wake)
+       {
+               if (ao_sleep(&ao_radio_wake))
+                       ao_radio_abort = 1;
+       }
+       rx_waiting = 0;
+       ao_arch_release_interrupts();
+       ao_clear_alarm();
+       if (ao_radio_abort || ao_radio_mcu_wake)
                return 0;
        rx_data_consumed += AO_FEC_DECODE_BLOCK;
 #if AO_PROFILE
                return 0;
        rx_data_consumed += AO_FEC_DECODE_BLOCK;
 #if AO_PROFILE
@@ -1044,48 +1070,67 @@ ao_radio_recv(__xdata void *d, uint8_t size, uint8_t timeout)
         */
        ao_radio_abort = 0;
 
         */
        ao_radio_abort = 0;
 
-       /* configure interrupt pin */
        ao_radio_get(len);
        ao_radio_get(len);
-       ao_radio_set_mode(AO_RADIO_MODE_PACKET_RX);
 
        ao_radio_wake = 0;
        ao_radio_mcu_wake = 0;
 
 
        ao_radio_wake = 0;
        ao_radio_mcu_wake = 0;
 
-       AO_CC1120_SPI.cr2 = 0;
-
-       /* clear any RXNE */
-       (void) AO_CC1120_SPI.dr;
+       ao_radio_set_mode(AO_RADIO_MODE_PACKET_RX);
 
 
-       /* Have the radio signal when the preamble quality goes high */
-       ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_PQT_REACHED);
+       /* configure interrupt pin */
+       ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_CLKEN_SOFT);
        ao_exti_set_mode(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN,
        ao_exti_set_mode(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN,
-                        AO_EXTI_MODE_RISING|AO_EXTI_PRIORITY_HIGH);
-       ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_isr);
+                        AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH);
+
+       ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_rx_isr);
        ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
        ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
-       ao_exti_enable(AO_CC1120_MCU_WAKEUP_PORT, AO_CC1120_MCU_WAKEUP_PIN);
+
+       rx_starting = 1;
+       rx_task_id = ao_cur_task->task_id;
 
        ao_radio_strobe(CC1120_SRX);
 
 
        ao_radio_strobe(CC1120_SRX);
 
-       /* Wait for the preamble to appear */
-       ao_radio_wait_isr(timeout);
+       if (timeout)
+               ao_alarm(timeout);
+       ao_arch_block_interrupts();
+       while (rx_starting && !ao_radio_abort) {
+               if (ao_sleep(&ao_radio_wake))
+                       ao_radio_abort = 1;
+       }
+       uint8_t rx_task_id_save = rx_task_id;
+       rx_task_id = 0;
+       rx_starting = 0;
+       ao_arch_release_interrupts();
+       if (timeout)
+               ao_clear_alarm();
+
        if (ao_radio_abort) {
                ret = 0;
        if (ao_radio_abort) {
                ret = 0;
+               rx_task_id = 0;
                goto abort;
        }
 
                goto abort;
        }
 
-       ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_CLKEN_SOFT);
-       ao_exti_set_mode(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN,
-                        AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH);
-
-       ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_rx_isr);
-       ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
-
-       ao_radio_burst_read_start(CC1120_SOFT_RX_DATA_OUT);
+       if (rx_task_id_save) {
+               ++rx_slow_start;
+               ao_radio_select();
+               _ao_radio_burst_read_start(CC1120_SOFT_RX_DATA_OUT);
+               if (rx_ignore) {
+                       uint8_t ignore = AO_CC1120_SPI.dr;
+                       (void) ignore;
+                       AO_CC1120_SPI.dr = 0;
+                       --rx_ignore;
+               }
+       }
 
        ret = ao_fec_decode(rx_data, rx_data_count, d, size + 2, ao_radio_rx_wait);
 
        ao_radio_burst_read_stop();
 
 
        ret = ao_fec_decode(rx_data, rx_data_count, d, size + 2, ao_radio_rx_wait);
 
        ao_radio_burst_read_stop();
 
+       if (ao_radio_mcu_wake)
+               ao_radio_check_marc_status();
+       if (ao_radio_abort)
+               ret = 0;
+
 abort:
        /* Convert from 'real' rssi to cc1111-style values */
 
 abort:
        /* Convert from 'real' rssi to cc1111-style values */
 
@@ -1100,7 +1145,7 @@ abort:
                radio_rssi = AO_RADIO_FROM_RSSI (rssi);
        }
 
                radio_rssi = AO_RADIO_FROM_RSSI (rssi);
        }
 
-       ao_radio_strobe(CC1120_SIDLE);
+       ao_radio_idle();
 
        ao_radio_put();
 
 
        ao_radio_put();
 
@@ -1139,7 +1184,7 @@ struct ao_cc1120_reg {
        char            *name;
 };
 
        char            *name;
 };
 
-const static struct ao_cc1120_reg ao_cc1120_reg[] = {
+static const struct ao_cc1120_reg ao_cc1120_reg[] = {
        { .addr = CC1120_IOCFG3,        .name = "IOCFG3" },
        { .addr = CC1120_IOCFG2,        .name = "IOCFG2" },
        { .addr = CC1120_IOCFG1,        .name = "IOCFG1" },
        { .addr = CC1120_IOCFG3,        .name = "IOCFG3" },
        { .addr = CC1120_IOCFG2,        .name = "IOCFG2" },
        { .addr = CC1120_IOCFG1,        .name = "IOCFG1" },
@@ -1320,7 +1365,7 @@ const static struct ao_cc1120_reg ao_cc1120_reg[] = {
 
 static void ao_radio_show(void) {
        uint8_t status = ao_radio_status();
 
 static void ao_radio_show(void) {
        uint8_t status = ao_radio_status();
-       int     i;
+       unsigned int    i;
 
        ao_radio_get(0xff);
        status = ao_radio_status();
 
        ao_radio_get(0xff);
        status = ao_radio_status();
@@ -1331,6 +1376,10 @@ static void ao_radio_show(void) {
 
        for (i = 0; i < AO_NUM_CC1120_REG; i++)
                printf ("\t%02x %-20.20s\n", ao_radio_reg_read(ao_cc1120_reg[i].addr), ao_cc1120_reg[i].name);
 
        for (i = 0; i < AO_NUM_CC1120_REG; i++)
                printf ("\t%02x %-20.20s\n", ao_radio_reg_read(ao_cc1120_reg[i].addr), ao_cc1120_reg[i].name);
+
+       printf("RX fast start: %u\n", rx_fast_start);
+       printf("RX slow start: %u\n", rx_slow_start);
+       printf("RX missed:     %u\n", rx_missed);
        ao_radio_put();
 }
 
        ao_radio_put();
 }
 
@@ -1354,12 +1403,12 @@ static void ao_radio_packet(void) {
 }
 
 void
 }
 
 void
-ao_radio_test_recv()
+ao_radio_test_recv(void)
 {
        uint8_t bytes[34];
        uint8_t b;
 
 {
        uint8_t bytes[34];
        uint8_t b;
 
-       if (ao_radio_recv(bytes, 34)) {
+       if (ao_radio_recv(bytes, 34, 0)) {
                if (bytes[33] & 0x80)
                        printf ("CRC OK");
                else
                if (bytes[33] & 0x80)
                        printf ("CRC OK");
                else
@@ -1375,13 +1424,12 @@ ao_radio_test_recv()
 #include <ao_aprs.h>
 
 static void
 #include <ao_aprs.h>
 
 static void
-ao_radio_aprs()
+ao_radio_aprs(void)
 {
        ao_packet_slave_stop();
        ao_aprs_send();
 }
 #endif
 {
        ao_packet_slave_stop();
        ao_aprs_send();
 }
 #endif
-
 #endif
 
 static const struct ao_cmds ao_radio_cmds[] = {
 #endif
 
 static const struct ao_cmds ao_radio_cmds[] = {
index c11aa028a4e2896231ac5037b1d5a2ca6f70d665..a225bc4aca9d81eac96e3f77bc04bc92f5323039 100644 (file)
@@ -132,6 +132,9 @@ ao_clock_init(void);
  */
 
 #ifndef ao_mutex_get
  */
 
 #ifndef ao_mutex_get
+uint8_t
+ao_mutex_try(__xdata uint8_t *ao_mutex, uint8_t task_id) __reentrant;
+
 void
 ao_mutex_get(__xdata uint8_t *ao_mutex) __reentrant;
 
 void
 ao_mutex_get(__xdata uint8_t *ao_mutex) __reentrant;
 
index 952ff46214a69db9b3e293992ee4f2e602576f46..a36fe93940906efdefaa37e616e0fa762f9daa88 100644 (file)
 
 #include "ao.h"
 
 
 #include "ao.h"
 
+#ifndef HAS_MUTEX_TRY
+#define HAS_MUTEX_TRY 1
+#endif
+
+#if HAS_MUTEX_TRY
+
+uint8_t
+ao_mutex_try(__xdata uint8_t *mutex, uint8_t task_id) __reentrant
+{
+       uint8_t ret;
+       if (*mutex == task_id)
+               ao_panic(AO_PANIC_MUTEX);
+       ao_arch_critical(
+               if (*mutex)
+                       ret = 0;
+               else {
+                       *mutex = task_id;
+                       ret = 1;
+               });
+       return ret;
+}
+#endif
+
 void
 ao_mutex_get(__xdata uint8_t *mutex) __reentrant
 {
 void
 ao_mutex_get(__xdata uint8_t *mutex) __reentrant
 {
index 0891903ea5f00cb2adae5dbf57506fcdcb81a5c5..21a7a8e5702f779fd2ddce6e164e89a8bf77ab9e 100644 (file)
@@ -161,16 +161,17 @@ static inline void ao_arch_restore_stack(void) {
 
 #endif /* HAS_TASK */
 
 
 #endif /* HAS_TASK */
 
-#define ao_arch_wait_interrupt() do {                  \
-               asm(".global ao_idle_loc\n\twfi\nao_idle_loc:");        \
-               ao_arch_release_interrupts();                           \
-               ao_arch_block_interrupts();                             \
+#define ao_arch_wait_interrupt() do {                          \
+               asm("\twfi\n");                                 \
+               ao_arch_release_interrupts();                   \
+               asm(".global ao_idle_loc\n\nao_idle_loc:");     \
+               ao_arch_block_interrupts();                     \
        } while (0)
 
        } while (0)
 
-#define ao_arch_critical(b) do {                               \
-               ao_arch_block_interrupts();                     \
-               do { b } while (0);                             \
-               ao_arch_release_interrupts();                   \
+#define ao_arch_critical(b) do {                       \
+               uint32_t __mask = ao_arch_irqsave();    \
+               do { b } while (0);                     \
+               ao_arch_irqrestore(__mask);             \
        } while (0)
 
 /*
        } while (0)
 
 /*
index b461cd3fbf81dd9f32dac82894ea96d7c5bdaad7..7ad3b4b8d97cffd47bac2cf83484d9942cafb892 100644 (file)
@@ -64,6 +64,9 @@
 #define AO_SPI_INDEX(id)       ((id) & AO_SPI_INDEX_MASK)
 #define AO_SPI_CONFIG(id)      ((id) & AO_SPI_CONFIG_MASK)
 
 #define AO_SPI_INDEX(id)       ((id) & AO_SPI_INDEX_MASK)
 #define AO_SPI_CONFIG(id)      ((id) & AO_SPI_CONFIG_MASK)
 
+uint8_t
+ao_spi_try_get(uint8_t spi_index, uint32_t speed, uint8_t task_id);
+
 void
 ao_spi_get(uint8_t spi_index, uint32_t speed);
 
 void
 ao_spi_get(uint8_t spi_index, uint32_t speed);
 
@@ -76,6 +79,9 @@ ao_spi_send(void *block, uint16_t len, uint8_t spi_index);
 void
 ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index);
 
 void
 ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index);
 
+void
+ao_spi_send_sync(void *block, uint16_t len, uint8_t spi_index);
+
 void
 ao_spi_recv(void *block, uint16_t len, uint8_t spi_index);
 
 void
 ao_spi_recv(void *block, uint16_t len, uint8_t spi_index);
 
@@ -95,6 +101,15 @@ ao_spi_init(void);
                ao_spi_set_cs(reg,mask);                        \
        } while (0)
 
                ao_spi_set_cs(reg,mask);                        \
        } while (0)
 
+static inline uint8_t
+ao_spi_try_get_mask(struct stm_gpio *reg, uint16_t mask, uint8_t bus, uint32_t speed, uint8_t task_id)
+{
+       if (!ao_spi_try_get(bus, speed, task_id))
+               return 0;
+       ao_spi_set_cs(reg, mask);
+       return 1;
+}
+
 #define ao_spi_put_mask(reg,mask,bus) do {     \
                ao_spi_clr_cs(reg,mask);        \
                ao_spi_put(bus);                \
 #define ao_spi_put_mask(reg,mask,bus) do {     \
                ao_spi_clr_cs(reg,mask);        \
                ao_spi_put(bus);                \
@@ -252,6 +267,8 @@ extern struct ao_stm_usart  ao_stm_usart3;
 
 #define ARM_PUSH32(stack, val) (*(--(stack)) = (val))
 
 
 #define ARM_PUSH32(stack, val) (*(--(stack)) = (val))
 
+typedef uint32_t       ao_arch_irq_t;
+
 static inline uint32_t
 ao_arch_irqsave(void) {
        uint32_t        primask;
 static inline uint32_t
 ao_arch_irqsave(void) {
        uint32_t        primask;
@@ -369,10 +386,10 @@ static inline void ao_arch_start_scheduler(void) {
                ao_arch_block_interrupts();                     \
        } while (0)
 
                ao_arch_block_interrupts();                     \
        } while (0)
 
-#define ao_arch_critical(b) do {                               \
-               ao_arch_block_interrupts();                     \
-               do { b } while (0);                             \
-               ao_arch_release_interrupts();                   \
+#define ao_arch_critical(b) do {                       \
+               uint32_t __mask = ao_arch_irqsave();    \
+               do { b } while (0);                     \
+               ao_arch_irqrestore(__mask);             \
        } while (0)
 
 #endif /* _AO_ARCH_FUNCS_H_ */
        } while (0)
 
 #endif /* _AO_ARCH_FUNCS_H_ */
index 56329c2446c43f6188a6f29dc3ae4d596a93c0df..885af54466a8f41567604f336fce8da0bcf03477 100644 (file)
@@ -153,6 +153,28 @@ ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index)
        ao_dma_done_transfer(miso_dma_index);
 }
 
        ao_dma_done_transfer(miso_dma_index);
 }
 
+void
+ao_spi_send_sync(void *block, uint16_t len, uint8_t spi_index)
+{
+       uint8_t         *b = block;
+       struct stm_spi  *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
+
+       stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
+                       (0 << STM_SPI_CR2_RXNEIE) |
+                       (0 << STM_SPI_CR2_ERRIE) |
+                       (0 << STM_SPI_CR2_SSOE) |
+                       (0 << STM_SPI_CR2_TXDMAEN) |
+                       (0 << STM_SPI_CR2_RXDMAEN));
+
+       /* Clear RXNE */
+       (void) stm_spi->dr;
+
+       while (len--) {
+               while (!(stm_spi->sr & (1 << STM_SPI_SR_TXE)));
+               stm_spi->dr = *b++;
+       }
+}
+
 void
 ao_spi_recv(void *block, uint16_t len, uint8_t spi_index)
 {
 void
 ao_spi_recv(void *block, uint16_t len, uint8_t spi_index)
 {
@@ -356,13 +378,11 @@ ao_spi_enable_index(uint8_t spi_index)
        }
 }
 
        }
 }
 
-void
-ao_spi_get(uint8_t spi_index, uint32_t speed)
+static void
+ao_spi_config(uint8_t spi_index, uint32_t speed)
 {
        uint8_t         id = AO_SPI_INDEX(spi_index);
        struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
 {
        uint8_t         id = AO_SPI_INDEX(spi_index);
        struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
-
-       ao_mutex_get(&ao_spi_mutex[id]);
        stm_spi->cr1 = ((0 << STM_SPI_CR1_BIDIMODE) |                   /* Three wire mode */
                        (0 << STM_SPI_CR1_BIDIOE) |
                        (0 << STM_SPI_CR1_CRCEN) |                      /* CRC disabled */
        stm_spi->cr1 = ((0 << STM_SPI_CR1_BIDIMODE) |                   /* Three wire mode */
                        (0 << STM_SPI_CR1_BIDIOE) |
                        (0 << STM_SPI_CR1_CRCEN) |                      /* CRC disabled */
@@ -378,7 +398,7 @@ ao_spi_get(uint8_t spi_index, uint32_t speed)
                        (0 << STM_SPI_CR1_CPOL) |                       /* Format 0 */
                        (0 << STM_SPI_CR1_CPHA));
        if (spi_index != ao_spi_index[id]) {
                        (0 << STM_SPI_CR1_CPOL) |                       /* Format 0 */
                        (0 << STM_SPI_CR1_CPHA));
        if (spi_index != ao_spi_index[id]) {
-               
+
                /* Disable old config
                 */
                ao_spi_disable_index(ao_spi_index[id]);
                /* Disable old config
                 */
                ao_spi_disable_index(ao_spi_index[id]);
@@ -386,13 +406,32 @@ ao_spi_get(uint8_t spi_index, uint32_t speed)
                /* Enable new config
                 */
                ao_spi_enable_index(spi_index);
                /* Enable new config
                 */
                ao_spi_enable_index(spi_index);
-               
+
                /* Remember current config
                 */
                ao_spi_index[id] = spi_index;
        }
 }
 
                /* Remember current config
                 */
                ao_spi_index[id] = spi_index;
        }
 }
 
+uint8_t
+ao_spi_try_get(uint8_t spi_index, uint32_t speed, uint8_t task_id)
+{
+       uint8_t         id = AO_SPI_INDEX(spi_index);
+
+       if (!ao_mutex_try(&ao_spi_mutex[id], task_id))
+               return 0;
+       ao_spi_config(spi_index, speed);
+       return 1;
+}
+
+void
+ao_spi_get(uint8_t spi_index, uint32_t speed)
+{
+       uint8_t         id = AO_SPI_INDEX(spi_index);
+       ao_mutex_get(&ao_spi_mutex[id]);
+       ao_spi_config(spi_index, speed);
+}
+
 void
 ao_spi_put(uint8_t spi_index)
 {
 void
 ao_spi_put(uint8_t spi_index)
 {