summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ports/stm32/dma.c23
-rw-r--r--ports/stm32/dma.h14
-rw-r--r--ports/stm32/stm32_it.c65
-rw-r--r--ports/stm32/storage.c19
-rw-r--r--ports/stm32/storage.h4
-rw-r--r--ports/stm32/systick.c33
-rw-r--r--ports/stm32/systick.h16
7 files changed, 88 insertions, 86 deletions
diff --git a/ports/stm32/dma.c b/ports/stm32/dma.c
index 9817bf6c1..b17c46068 100644
--- a/ports/stm32/dma.c
+++ b/ports/stm32/dma.c
@@ -29,9 +29,16 @@
#include <stdint.h>
#include "py/obj.h"
+#include "systick.h"
#include "dma.h"
#include "irq.h"
+#define DMA_IDLE_ENABLED() (dma_idle.enabled != 0)
+#define DMA_SYSTICK_LOG2 (3)
+#define DMA_SYSTICK_MASK ((1 << DMA_SYSTICK_LOG2) - 1)
+#define DMA_IDLE_TICK_MAX (8) // 8*8 = 64 msec
+#define DMA_IDLE_TICK(tick) (((tick) & ~(SYSTICK_DISPATCH_NUM_SLOTS - 1) & DMA_SYSTICK_MASK) == 0)
+
typedef enum {
dma_id_not_defined=-1,
dma_id_0,
@@ -52,6 +59,11 @@ typedef enum {
dma_id_15,
} dma_id_t;
+typedef union {
+ uint16_t enabled; // Used to test if both counters are == 0
+ uint8_t counter[2];
+} dma_idle_count_t;
+
struct _dma_descr_t {
#if defined(STM32F4) || defined(STM32F7) || defined(STM32H7)
DMA_Stream_TypeDef *instance;
@@ -530,9 +542,12 @@ void DMA2_Channel7_IRQHandler(void) { IRQ_ENTER(DMA2_Channel7_IRQn); if (dma_han
#endif
+static void dma_idle_handler(uint32_t tick);
+
// Resets the idle counter for the DMA controller associated with dma_id.
static void dma_tickle(dma_id_t dma_id) {
dma_idle.counter[(dma_id < NSTREAMS_PER_CONTROLLER) ? 0 : 1] = 1;
+ systick_enable_dispatch(SYSTICK_DISPATCH_DMA, dma_idle_handler);
}
static void dma_enable_clock(dma_id_t dma_id) {
@@ -681,12 +696,16 @@ void dma_invalidate_channel(const dma_descr_t *dma_descr) {
// Called from the SysTick handler
// We use LSB of tick to select which controller to process
-void dma_idle_handler(int tick) {
+static void dma_idle_handler(uint32_t tick) {
+ if (!DMA_IDLE_ENABLED() || !DMA_IDLE_TICK(tick)) {
+ return;
+ }
+
static const uint32_t controller_mask[] = {
DMA1_ENABLE_MASK, DMA2_ENABLE_MASK
};
{
- int controller = tick & 1;
+ int controller = (tick >> DMA_SYSTICK_LOG2) & 1;
if (dma_idle.counter[controller] == 0) {
return;
}
diff --git a/ports/stm32/dma.h b/ports/stm32/dma.h
index 84875374b..73cb9c328 100644
--- a/ports/stm32/dma.h
+++ b/ports/stm32/dma.h
@@ -81,23 +81,9 @@ extern const dma_descr_t dma_SDIO_0;
#endif
-typedef union {
- uint16_t enabled; // Used to test if both counters are == 0
- uint8_t counter[2];
-} dma_idle_count_t;
-extern volatile dma_idle_count_t dma_idle;
-#define DMA_IDLE_ENABLED() (dma_idle.enabled != 0)
-
-#define DMA_SYSTICK_MASK 0x0e
-#define DMA_MSECS_PER_SYSTICK (DMA_SYSTICK_MASK + 1)
-#define DMA_IDLE_TICK_MAX (8) // 128 msec
-#define DMA_IDLE_TICK(tick) (((tick) & DMA_SYSTICK_MASK) == 0)
-
-
void dma_init(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, uint32_t dir, void *data);
void dma_init_handle(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, uint32_t dir, void *data);
void dma_deinit(const dma_descr_t *dma_descr);
void dma_invalidate_channel(const dma_descr_t *dma_descr);
-void dma_idle_handler(int controller);
#endif // MICROPY_INCLUDED_STM32_DMA_H
diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c
index 026082eb9..49b8ff1a8 100644
--- a/ports/stm32/stm32_it.c
+++ b/ports/stm32/stm32_it.c
@@ -299,54 +299,6 @@ void PendSV_Handler(void) {
pendsv_isr_handler();
}
-/**
- * @brief This function handles SysTick Handler.
- * @param None
- * @retval None
- */
-void SysTick_Handler(void) {
- // Instead of calling HAL_IncTick we do the increment here of the counter.
- // This is purely for efficiency, since SysTick is called 1000 times per
- // second at the highest interrupt priority.
- // Note: we don't need uwTick to be declared volatile here because this is
- // the only place where it can be modified, and the code is more efficient
- // without the volatile specifier.
- extern uint32_t uwTick;
- uwTick += 1;
-
- // Read the systick control regster. This has the side effect of clearing
- // the COUNTFLAG bit, which makes the logic in mp_hal_ticks_us
- // work properly.
- SysTick->CTRL;
-
- // Right now we have the storage and DMA controllers to process during
- // this interrupt and we use custom dispatch handlers. If this needs to
- // be generalised in the future then a dispatch table can be used as
- // follows: ((void(*)(void))(systick_dispatch[uwTick & 0xf]))();
-
- #if MICROPY_HW_ENABLE_STORAGE
- if (STORAGE_IDLE_TICK(uwTick)) {
- NVIC->STIR = FLASH_IRQn;
- }
- #endif
-
- if (DMA_IDLE_ENABLED() && DMA_IDLE_TICK(uwTick)) {
- dma_idle_handler(uwTick);
- }
-
- #if MICROPY_PY_THREAD
- if (pyb_thread_enabled) {
- if (pyb_thread_cur->timeslice == 0) {
- if (pyb_thread_cur->run_next != pyb_thread_cur) {
- SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
- }
- } else {
- --pyb_thread_cur->timeslice;
- }
- }
- #endif
-}
-
/******************************************************************************/
/* STM32F4xx Peripherals Interrupt Handlers */
/* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */
@@ -465,23 +417,6 @@ void OTG_HS_WKUP_IRQHandler(void) {
{
}*/
-// Handle a flash (erase/program) interrupt.
-void FLASH_IRQHandler(void) {
- IRQ_ENTER(FLASH_IRQn);
- // This calls the real flash IRQ handler, if needed
- /*
- uint32_t flash_cr = FLASH->CR;
- if ((flash_cr & FLASH_IT_EOP) || (flash_cr & FLASH_IT_ERR)) {
- HAL_FLASH_IRQHandler();
- }
- */
- #if MICROPY_HW_ENABLE_STORAGE
- // This call the storage IRQ handler, to check if the flash cache needs flushing
- storage_irq_handler();
- #endif
- IRQ_EXIT(FLASH_IRQn);
-}
-
/**
* @brief These functions handle the EXTI interrupt requests.
* @param None
diff --git a/ports/stm32/storage.c b/ports/stm32/storage.c
index 7724ae0f4..b150d7376 100644
--- a/ports/stm32/storage.c
+++ b/ports/stm32/storage.c
@@ -30,12 +30,16 @@
#include "py/runtime.h"
#include "extmod/vfs_fat.h"
+#include "systick.h"
#include "led.h"
#include "storage.h"
#include "irq.h"
#if MICROPY_HW_ENABLE_STORAGE
+#define STORAGE_SYSTICK_MASK (0x1ff) // 512ms
+#define STORAGE_IDLE_TICK(tick) (((tick) & ~(SYSTICK_DISPATCH_NUM_SLOTS - 1) & STORAGE_SYSTICK_MASK) == 0)
+
#define FLASH_PART1_START_BLOCK (0x100)
#if defined(MICROPY_HW_BDEV2_IOCTL)
@@ -44,10 +48,14 @@
static bool storage_is_initialised = false;
+static void storage_systick_callback(uint32_t ticks_ms);
+
void storage_init(void) {
if (!storage_is_initialised) {
storage_is_initialised = true;
+ systick_enable_dispatch(SYSTICK_DISPATCH_STORAGE, storage_systick_callback);
+
MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_INIT, 0);
#if defined(MICROPY_HW_BDEV2_IOCTL)
@@ -73,11 +81,20 @@ uint32_t storage_get_block_count(void) {
#endif
}
-void storage_irq_handler(void) {
+static void storage_systick_callback(uint32_t ticks_ms) {
+ if (STORAGE_IDLE_TICK(ticks_ms)) {
+ // Trigger a FLASH IRQ to execute at a lower priority
+ NVIC->STIR = FLASH_IRQn;
+ }
+}
+
+void FLASH_IRQHandler(void) {
+ IRQ_ENTER(FLASH_IRQn);
MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_IRQ_HANDLER, 0);
#if defined(MICROPY_HW_BDEV2_IOCTL)
MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_IRQ_HANDLER, 0);
#endif
+ IRQ_EXIT(FLASH_IRQn);
}
void storage_flush(void) {
diff --git a/ports/stm32/storage.h b/ports/stm32/storage.h
index 7250b6dbf..826b465a6 100644
--- a/ports/stm32/storage.h
+++ b/ports/stm32/storage.h
@@ -30,9 +30,6 @@
#define FLASH_BLOCK_SIZE (512)
-#define STORAGE_SYSTICK_MASK (0x1ff) // 512ms
-#define STORAGE_IDLE_TICK(tick) (((tick) & STORAGE_SYSTICK_MASK) == 2)
-
// Try to match Python-level VFS block protocol where possible for these constants
enum {
BDEV_IOCTL_INIT = 1,
@@ -44,7 +41,6 @@ enum {
void storage_init(void);
uint32_t storage_get_block_size(void);
uint32_t storage_get_block_count(void);
-void storage_irq_handler(void);
void storage_flush(void);
bool storage_read_block(uint8_t *dest, uint32_t block);
bool storage_write_block(const uint8_t *src, uint32_t block);
diff --git a/ports/stm32/systick.c b/ports/stm32/systick.c
index 8b5efe057..d92f9d75d 100644
--- a/ports/stm32/systick.c
+++ b/ports/stm32/systick.c
@@ -32,6 +32,39 @@
extern __IO uint32_t uwTick;
+systick_dispatch_t systick_dispatch_table[SYSTICK_DISPATCH_NUM_SLOTS];
+
+void SysTick_Handler(void) {
+ // Instead of calling HAL_IncTick we do the increment here of the counter.
+ // This is purely for efficiency, since SysTick is called 1000 times per
+ // second at the highest interrupt priority.
+ uint32_t uw_tick = uwTick + 1;
+ uwTick = uw_tick;
+
+ // Read the systick control regster. This has the side effect of clearing
+ // the COUNTFLAG bit, which makes the logic in mp_hal_ticks_us
+ // work properly.
+ SysTick->CTRL;
+
+ // Dispatch to any registered handlers in a cycle
+ systick_dispatch_t f = systick_dispatch_table[uw_tick & (SYSTICK_DISPATCH_NUM_SLOTS - 1)];
+ if (f != NULL) {
+ f(uw_tick);
+ }
+
+ #if MICROPY_PY_THREAD
+ if (pyb_thread_enabled) {
+ if (pyb_thread_cur->timeslice == 0) {
+ if (pyb_thread_cur->run_next != pyb_thread_cur) {
+ SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
+ }
+ } else {
+ --pyb_thread_cur->timeslice;
+ }
+ }
+ #endif
+}
+
// We provide our own version of HAL_Delay that calls __WFI while waiting,
// and works when interrupts are disabled. This function is intended to be
// used only by the ST HAL functions.
diff --git a/ports/stm32/systick.h b/ports/stm32/systick.h
index abb8729f5..d1b59c574 100644
--- a/ports/stm32/systick.h
+++ b/ports/stm32/systick.h
@@ -26,6 +26,22 @@
#ifndef MICROPY_INCLUDED_STM32_SYSTICK_H
#define MICROPY_INCLUDED_STM32_SYSTICK_H
+#define SYSTICK_DISPATCH_NUM_SLOTS (2)
+#define SYSTICK_DISPATCH_DMA (0)
+#define SYSTICK_DISPATCH_STORAGE (1)
+
+typedef void (*systick_dispatch_t)(uint32_t);
+
+extern systick_dispatch_t systick_dispatch_table[SYSTICK_DISPATCH_NUM_SLOTS];
+
+static inline void systick_enable_dispatch(size_t slot, systick_dispatch_t f) {
+ systick_dispatch_table[slot] = f;
+}
+
+static inline void systick_disable_dispatch(size_t slot) {
+ systick_dispatch_table[slot] = NULL;
+}
+
void systick_wait_at_least(uint32_t stc, uint32_t delay_ms);
bool systick_has_passed(uint32_t stc, uint32_t delay_ms);