summary |
shortlog |
log |
commit | commitdiff |
tree
raw |
patch |
inline | side by side (from parent 1:
b119e19)
sdcc offers __critical as a machine-independent way to block
interrupts, but as gcc doesn't, we need to use a compiler-independent
construct instead. ao_arch_critical has been around since the AVR
port, but some old __critical usages remained.
This fixes a bunch of random hangs when communicating with MM over USB
or the radio as the various stdio loops were running without
interrupts blocked between the test and the sleep.
Signed-off-by: Keith Packard <keithp@keithp.com>
12 files changed:
/* Set the ADC interval */
void
/* Set the ADC interval */
void
-ao_timer_set_adc_interval(uint8_t interval) __critical;
+ao_timer_set_adc_interval(uint8_t interval);
/* Timer interrupt */
void
/* Timer interrupt */
void
__xdata struct ao_ignition ao_ignition[2];
void
__xdata struct ao_ignition ao_ignition[2];
void
-ao_ignite(enum ao_igniter igniter) __critical
+ao_ignite(enum ao_igniter igniter)
ao_ignition[igniter].request = 1;
ao_wakeup(&ao_ignition);
ao_ignition[igniter].request = 1;
ao_wakeup(&ao_ignition);
}
#ifndef AO_SENSE_DROGUE
}
#ifndef AO_SENSE_DROGUE
__pdata int16_t value;
__pdata uint8_t request, firing, fired;
__pdata int16_t value;
__pdata uint8_t request, firing, fired;
ao_data_get(&packet);
request = ao_ignition[igniter].request;
fired = ao_ignition[igniter].fired;
firing = ao_ignition[igniter].firing;
ao_data_get(&packet);
request = ao_ignition[igniter].request;
fired = ao_ignition[igniter].fired;
firing = ao_ignition[igniter].firing;
if (firing || (request && !fired))
return ao_igniter_active;
if (firing || (request && !fired))
return ao_igniter_active;
-ao_igniter_fire(enum ao_igniter igniter) __critical
+ao_igniter_fire(enum ao_igniter igniter)
{
ao_ignition[igniter].firing = 1;
switch(ao_config.ignite_mode) {
{
ao_ignition[igniter].firing = 1;
switch(ao_config.ignite_mode) {
{
if (*mutex == ao_cur_task->task_id)
ao_panic(AO_PANIC_MUTEX);
{
if (*mutex == ao_cur_task->task_id)
ao_panic(AO_PANIC_MUTEX);
while (*mutex)
ao_sleep(mutex);
*mutex = ao_cur_task->task_id;
while (*mutex)
ao_sleep(mutex);
*mutex = ao_cur_task->task_id;
{
if (*mutex != ao_cur_task->task_id)
ao_panic(AO_PANIC_MUTEX);
{
if (*mutex != ao_cur_task->task_id)
ao_panic(AO_PANIC_MUTEX);
*mutex = 0;
ao_wakeup(mutex);
*mutex = 0;
ao_wakeup(mutex);
ao_packet_putchar(char c) __reentrant;
char
ao_packet_putchar(char c) __reentrant;
char
-ao_packet_pollchar(void) __critical;
+ao_packet_pollchar(void);
#if PACKET_HAS_MASTER
/* ao_packet_master.c */
#if PACKET_HAS_MASTER
/* ao_packet_master.c */
ao_cur_task = NULL;
printf ("panic %d\n", reason);
#endif
ao_cur_task = NULL;
printf ("panic %d\n", reason);
#endif
+ ao_arch_block_interrupts();
+ for (;;) {
ao_panic_delay(20);
for (n = 0; n < 5; n++) {
ao_led_on(AO_LED_PANIC);
ao_panic_delay(20);
for (n = 0; n < 5; n++) {
ao_led_on(AO_LED_PANIC);
__xdata uint8_t ao_stdin_ready;
char
__xdata uint8_t ao_stdin_ready;
char
-getchar(void) __reentrant __critical
+getchar(void) __reentrant
- int8_t stdio = ao_cur_stdio;
+ ao_arch_critical(
+ int8_t stdio = ao_cur_stdio;
- for (;;) {
- c = ao_stdios[stdio].pollchar();
- if (c != AO_READ_AGAIN)
- break;
- if (++stdio == ao_num_stdios)
- stdio = 0;
- if (stdio == ao_cur_stdio)
- ao_sleep(&ao_stdin_ready);
- }
- ao_cur_stdio = stdio;
+ for (;;) {
+ c = ao_stdios[stdio].pollchar();
+ if (c != AO_READ_AGAIN)
+ break;
+ if (++stdio == ao_num_stdios)
+ stdio = 0;
+ if (stdio == ao_cur_stdio)
+ ao_sleep(&ao_stdin_ready);
+ }
+ ao_cur_stdio = stdio;
+ );
-ao_btm_check_link() __critical
- /* Check the pin and configure the interrupt detector to wait for the
- * pin to flip the other way
- */
- if (BT_LINK_PIN) {
- ao_btm_connected = 0;
- PICTL |= BT_PICTL_ICON;
- } else {
- ao_btm_connected = 1;
- PICTL &= ~BT_PICTL_ICON;
- }
+ ao_arch_critical(
+ /* Check the pin and configure the interrupt detector to wait for the
+ * pin to flip the other way
+ */
+ if (BT_LINK_PIN) {
+ ao_btm_connected = 0;
+ PICTL |= BT_PICTL_ICON;
+ } else {
+ ao_btm_connected = 1;
+ PICTL &= ~BT_PICTL_ICON;
+ }
+ );
void
ao_packet_putchar(char c) __reentrant
{
void
ao_packet_putchar(char c) __reentrant
{
+ /* No need to block interrupts, all variables here
+ * are only manipulated in task context
+ */
while (ao_packet_tx_used == AO_PACKET_MAX && ao_packet_enable) {
#if PACKET_HAS_MASTER
ao_packet_flush();
while (ao_packet_tx_used == AO_PACKET_MAX && ao_packet_enable) {
#if PACKET_HAS_MASTER
ao_packet_flush();
-ao_packet_pollchar(void) __critical
+ao_packet_pollchar(void)
+ /* No need to block interrupts, all variables here
+ * are only manipulated in task context
+ */
if (!ao_packet_enable)
return AO_READ_AGAIN;
if (!ao_packet_enable)
return AO_READ_AGAIN;
#include "ao.h"
static char
#include "ao.h"
static char
-ao_packet_getchar(void) __critical
{
char c;
while ((c = ao_packet_pollchar()) == AO_READ_AGAIN) {
{
char c;
while ((c = ao_packet_pollchar()) == AO_READ_AGAIN) {
#define __xdata
#define __code const
#define __reentrant
#define __xdata
#define __code const
#define __reentrant
#define __interrupt(n)
#define __at(n)
#define __interrupt(n)
#define __at(n)
#define ao_arch_task_members\
uint32_t *sp; /* saved stack pointer */
#define ao_arch_task_members\
uint32_t *sp; /* saved stack pointer */
-#define cli() asm("cpsid i")
-#define sei() asm("cpsie i")
+#define ao_arch_block_interrupts() asm("cpsid i")
+#define ao_arch_release_interrupts() asm("cpsie i")
+
+#define cli() ao_arch_block_interrupts()
+#define sei() ao_arch_release_interrupts()
+
+static uint32_t
+ao_arch_irqsave(void) {
+ uint32_t primask;
+ asm("mrs %0,primask" : "=&r" (primask));
+ ao_arch_block_interrupts();
+ return primask;
+}
+
+static void
+ao_arch_irqrestore(uint32_t primask) {
+ asm("msr primask,%0" : : "r" (primask));
+}
+
+static void
+ao_arch_memory_barrier() {
+ asm volatile("" ::: "memory");
+}
#define ao_arch_init_stack(task, start) do { \
uint32_t *sp = (uint32_t *) (task->stack + AO_STACK_SIZE); \
#define ao_arch_init_stack(task, start) do { \
uint32_t *sp = (uint32_t *) (task->stack + AO_STACK_SIZE); \
-ao_timer_set_adc_interval(uint8_t interval) __critical
+ao_timer_set_adc_interval(uint8_t interval)
- ao_data_interval = interval;
- ao_data_count = 0;
+ ao_arch_critical(
+ ao_data_interval = interval;
+ ao_data_count = 0;
+ );
-/* Wait for a free IN buffer */
+/* Wait for a free IN buffer. Interrupts are blocked */
{
for (;;) {
/* Check if the current buffer is writable */
if (ao_usb_tx_count < AO_USB_IN_SIZE)
break;
{
for (;;) {
/* Check if the current buffer is writable */
if (ao_usb_tx_count < AO_USB_IN_SIZE)
break;
/* Wait for an IN buffer to be ready */
while (ao_usb_in_pending)
ao_sleep(&ao_usb_in_pending);
/* Wait for an IN buffer to be ready */
while (ao_usb_in_pending)
ao_sleep(&ao_usb_in_pending);
-ao_usb_flush(void) __critical
{
if (!ao_usb_running)
return;
{
if (!ao_usb_running)
return;
* packet was full, in which case we now
* want to send an empty packet
*/
* packet was full, in which case we now
* want to send an empty packet
*/
+ ao_arch_block_interrupts();
if (!ao_usb_in_flushed) {
ao_usb_in_flushed = 1;
if (!ao_usb_in_flushed) {
ao_usb_in_flushed = 1;
/* Wait for an IN buffer to be ready */
while (ao_usb_in_pending)
ao_sleep(&ao_usb_in_pending);
/* Wait for an IN buffer to be ready */
while (ao_usb_in_pending)
ao_sleep(&ao_usb_in_pending);
+ ao_arch_release_interrupts();
-ao_usb_putchar(char c) __critical __reentrant
{
if (!ao_usb_running)
return;
{
if (!ao_usb_running)
return;
+ ao_arch_block_interrupts();
+ _ao_usb_in_wait();
ao_usb_in_flushed = 0;
ao_usb_tx_buffer[ao_usb_tx_count++] = (uint8_t) c;
ao_usb_in_flushed = 0;
ao_usb_tx_buffer[ao_usb_tx_count++] = (uint8_t) c;
/* Send the packet when full */
if (ao_usb_tx_count == AO_USB_IN_SIZE)
ao_usb_in_send();
/* Send the packet when full */
if (ao_usb_tx_count == AO_USB_IN_SIZE)
ao_usb_in_send();
+ ao_arch_release_interrupts();
/* Check to see if a packet has arrived */
if (!ao_usb_out_avail)
return AO_READ_AGAIN;
/* Check to see if a packet has arrived */
if (!ao_usb_out_avail)
return AO_READ_AGAIN;
}
/* Pull a character out of the fifo */
}
/* Pull a character out of the fifo */
ao_usb_pollchar(void)
{
char c;
ao_usb_pollchar(void)
{
char c;
+ ao_arch_block_interrupts();
+ ao_arch_release_interrupts();
-ao_usb_getchar(void) __critical
+ ao_arch_block_interrupts();
while ((c = _ao_usb_pollchar()) == AO_READ_AGAIN)
ao_sleep(&ao_stdin_ready);
while ((c = _ao_usb_pollchar()) == AO_READ_AGAIN)
ao_sleep(&ao_stdin_ready);
+ ao_arch_release_interrupts();
return c;
}
void
ao_usb_disable(void)
{
return c;
}
void
ao_usb_disable(void)
{
+ ao_arch_block_interrupts();
stm_usb.cntr = (1 << STM_USB_CNTR_FRES);
stm_usb.istr = 0;
stm_usb.cntr = (1 << STM_USB_CNTR_FRES);
stm_usb.istr = 0;
/* Disable the interface */
stm_rcc.apb1enr &+ ~(1 << STM_RCC_APB1ENR_USBEN);
/* Disable the interface */
stm_rcc.apb1enr &+ ~(1 << STM_RCC_APB1ENR_USBEN);
+ ao_arch_release_interrupts();
* pulled low and doesn't work at all
*/
* pulled low and doesn't work at all
*/
+ ao_arch_block_interrupts();
+
/* Route interrupts */
stm_nvic_set_priority(STM_ISR_USB_LP_POS, 3);
stm_nvic_set_enable(STM_ISR_USB_LP_POS);
/* Route interrupts */
stm_nvic_set_priority(STM_ISR_USB_LP_POS, 3);
stm_nvic_set_enable(STM_ISR_USB_LP_POS);
(0 << STM_USB_CNTR_PDWN) |
(0 << STM_USB_CNTR_FRES));
(0 << STM_USB_CNTR_PDWN) |
(0 << STM_USB_CNTR_FRES));
+ ao_arch_release_interrupts();
+
for (t = 0; t < 1000; t++)
ao_arch_nop();
/* Enable USB pull-up */
for (t = 0; t < 1000; t++)
ao_arch_nop();
/* Enable USB pull-up */