mp_uint_t sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) { // check that src pointer is aligned on a 4-byte boundary if (((uint32_t)src & 3) != 0) { return SD_ERROR; } // check that SD card is initialised if (sd_handle.Instance == NULL) { return SD_ERROR; } HAL_SD_ErrorTypedef err = SD_OK; if (query_irq() == IRQ_STATE_ENABLED) { dma_init(&sd_tx_dma, DMA_STREAM_SDIO_TX, &dma_init_struct_sdio, DMA_CHANNEL_SDIO_TX, DMA_MEMORY_TO_PERIPH, &sd_handle); sd_handle.hdmatx = &sd_tx_dma; err = HAL_SD_WriteBlocks_BlockNumber_DMA(&sd_handle, (uint32_t*)src, block_num, SDCARD_BLOCK_SIZE, num_blocks); if (err == SD_OK) { // wait for DMA transfer to finish, with a large timeout err = HAL_SD_CheckWriteOperation(&sd_handle, 100000000); } dma_deinit(sd_handle.hdmatx); sd_handle.hdmatx = NULL; } else { err = HAL_SD_WriteBlocks_BlockNumber(&sd_handle, (uint32_t*)src, block_num, SDCARD_BLOCK_SIZE, num_blocks); } return err; }
// Always write all of the data to the device tx buffer, even if the // device is not connected, or if the buffer is full. Has a small timeout // to wait for the buffer to be drained, in the case the device is connected. void usbd_cdc_tx_always(usbd_cdc_itf_t *cdc, const uint8_t *buf, uint32_t len) { for (int i = 0; i < len; i++) { // If the CDC device is not connected to the host then we don't have anyone to receive our data. // The device may become connected in the future, so we should at least try to fill the buffer // and hope that it doesn't overflow by the time the device connects. // If the device is not connected then we should go ahead and fill the buffer straight away, // ignoring overflow. Otherwise, we should make sure that we have enough room in the buffer. if (cdc->connect_state != USBD_CDC_CONNECT_STATE_DISCONNECTED) { // If the buffer is full, wait until it gets drained, with a timeout of 500ms // (wraparound of tick is taken care of by 2's complement arithmetic). uint32_t start = HAL_GetTick(); while (((cdc->tx_buf_ptr_in + 1) & (USBD_CDC_TX_DATA_SIZE - 1)) == cdc->tx_buf_ptr_out && HAL_GetTick() - start <= 500) { usbd_cdc_try_tx(cdc); if (query_irq() == IRQ_STATE_DISABLED) { // IRQs disabled so buffer will never be drained; exit loop break; } __WFI(); // enter sleep mode, waiting for interrupt } } cdc->tx_buf[cdc->tx_buf_ptr_in] = buf[i]; cdc->tx_buf_ptr_in = (cdc->tx_buf_ptr_in + 1) & (USBD_CDC_TX_DATA_SIZE - 1); } usbd_cdc_try_tx(cdc); }
// timout in milliseconds. // Returns number of bytes written to the device. int USBD_CDC_Tx(const uint8_t *buf, uint32_t len, uint32_t timeout) { for (uint32_t i = 0; i < len; i++) { // Wait until the device is connected and the buffer has space, with a given timeout uint32_t start = HAL_GetTick(); while (!dev_is_connected || ((UserTxBufPtrIn + 1) & (APP_TX_DATA_SIZE - 1)) == UserTxBufPtrOut) { // Wraparound of tick is taken care of by 2's complement arithmetic. if (HAL_GetTick() - start >= timeout) { // timeout return i; } if (query_irq() == IRQ_STATE_DISABLED) { // IRQs disabled so buffer will never be drained; return immediately return i; } __WFI(); // enter sleep mode, waiting for interrupt } // Write data to device buffer UserTxBuffer[UserTxBufPtrIn] = buf[i]; UserTxBufPtrIn = (UserTxBufPtrIn + 1) & (APP_TX_DATA_SIZE - 1); } // Success, return number of bytes read return len; }
bool ets_loop_iter(void) { if (query_irq() != 0) { return false; } //static unsigned cnt; bool progress = false; for (volatile struct task_entry *t = emu_tasks; t < &emu_tasks[MP_ARRAY_SIZE(emu_tasks)]; t++) { system_soft_wdt_feed(); ets_intr_lock(); //printf("etc_loop_iter: "); dump_task(t - emu_tasks + FIRST_PRIO, t); if (t->i_get != t->i_put) { progress = true; //printf("#%d Calling task %d(%p) (%x, %x)\n", cnt++, // t - emu_tasks + FIRST_PRIO, t->task, t->queue[t->i_get].sig, t->queue[t->i_get].par); int idx = t->i_get; if (t->i_put == -1) { t->i_put = t->i_get; } if (++t->i_get == t->qlen) { t->i_get = 0; } //ets_intr_unlock(); t->task(&t->queue[idx]); //ets_intr_lock(); //printf("Done calling task %d\n", t - emu_tasks + FIRST_PRIO); } ets_intr_unlock(); } return progress; }
// timout in milliseconds. // Returns number of bytes read from the device. int USBD_CDC_Rx(uint8_t *buf, uint32_t len, uint32_t timeout) { // loop to read bytes for (uint32_t i = 0; i < len; i++) { // Wait until we have at least 1 byte to read uint32_t start = HAL_GetTick(); while (UserRxBufLen == UserRxBufCur) { // Wraparound of tick is taken care of by 2's complement arithmetic. if (HAL_GetTick() - start >= timeout) { // timeout return i; } if (query_irq() == IRQ_STATE_DISABLED) { // IRQs disabled so buffer will never be filled; return immediately return i; } __WFI(); // enter sleep mode, waiting for interrupt } // Copy byte from device to user buffer buf[i] = UserRxBuffer[UserRxBufCur++]; } // Success, return number of bytes read return len; }
// timout in milliseconds. // Returns number of bytes written to the device. int usbd_cdc_tx(usbd_cdc_itf_t *cdc, const uint8_t *buf, uint32_t len, uint32_t timeout) { for (uint32_t i = 0; i < len; i++) { // Wait until the device is connected and the buffer has space, with a given timeout uint32_t start = HAL_GetTick(); while (cdc->connect_state == USBD_CDC_CONNECT_STATE_DISCONNECTED || ((cdc->tx_buf_ptr_in + 1) & (USBD_CDC_TX_DATA_SIZE - 1)) == cdc->tx_buf_ptr_out) { usbd_cdc_try_tx(cdc); // Wraparound of tick is taken care of by 2's complement arithmetic. if (HAL_GetTick() - start >= timeout) { // timeout return i; } if (query_irq() == IRQ_STATE_DISABLED) { // IRQs disabled so buffer will never be drained; return immediately return i; } __WFI(); // enter sleep mode, waiting for interrupt } // Write data to device buffer cdc->tx_buf[cdc->tx_buf_ptr_in] = buf[i]; cdc->tx_buf_ptr_in = (cdc->tx_buf_ptr_in + 1) & (USBD_CDC_TX_DATA_SIZE - 1); } usbd_cdc_try_tx(cdc); // Success, return number of bytes read return len; }
// timout in milliseconds. // Returns number of bytes read from the device. int usbd_cdc_rx(usbd_cdc_itf_t *cdc, uint8_t *buf, uint32_t len, uint32_t timeout) { // loop to read bytes for (uint32_t i = 0; i < len; i++) { // Wait until we have at least 1 byte to read uint32_t start = HAL_GetTick(); while (cdc->rx_buf_put == cdc->rx_buf_get) { // Wraparound of tick is taken care of by 2's complement arithmetic. if (HAL_GetTick() - start >= timeout) { // timeout return i; } if (query_irq() == IRQ_STATE_DISABLED) { // IRQs disabled so buffer will never be filled; return immediately return i; } usbd_cdc_rx_check_resume(cdc); __WFI(); // enter sleep mode, waiting for interrupt } // Copy byte from device to user buffer buf[i] = cdc->rx_user_buf[cdc->rx_buf_get]; cdc->rx_buf_get = (cdc->rx_buf_get + 1) & (USBD_CDC_RX_DATA_SIZE - 1); } usbd_cdc_rx_check_resume(cdc); // Success, return number of bytes read return len; }
mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) { // check that SD card is initialised if (sd_handle.Instance == NULL) { return SD_ERROR; } HAL_SD_ErrorTypedef err = SD_OK; // check that dest pointer is aligned on a 4-byte boundary uint8_t *orig_dest = NULL; uint32_t saved_word; if (((uint32_t)dest & 3) != 0) { // Pointer is not aligned so it needs fixing. // We could allocate a temporary block of RAM (as sdcard_write_blocks // does) but instead we are going to use the dest buffer inplace. We // are going to align the pointer, save the initial word at the aligned // location, read into the aligned memory, move the memory back to the // unaligned location, then restore the initial bytes at the aligned // location. We should have no trouble doing this as those initial // bytes at the aligned location should be able to be changed for the // duration of this function call. orig_dest = dest; dest = (uint8_t*)((uint32_t)dest & ~3); saved_word = *(uint32_t*)dest; } if (query_irq() == IRQ_STATE_ENABLED) { // we must disable USB irqs to prevent MSC contention with SD card uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); dma_init(&sd_rx_dma, &SDMMC_RX_DMA, &sd_handle); sd_handle.hdmarx = &sd_rx_dma; // make sure cache is flushed and invalidated so when DMA updates the RAM // from reading the peripheral the CPU then reads the new data MP_HAL_CLEANINVALIDATE_DCACHE(dest, num_blocks * SDCARD_BLOCK_SIZE); err = HAL_SD_ReadBlocks_BlockNumber_DMA(&sd_handle, (uint32_t*)dest, block_num, SDCARD_BLOCK_SIZE, num_blocks); if (err == SD_OK) { // wait for DMA transfer to finish, with a large timeout err = HAL_SD_CheckReadOperation(&sd_handle, 100000000); } dma_deinit(&SDMMC_RX_DMA); sd_handle.hdmarx = NULL; restore_irq_pri(basepri); } else { err = HAL_SD_ReadBlocks_BlockNumber(&sd_handle, (uint32_t*)dest, block_num, SDCARD_BLOCK_SIZE, num_blocks); } if (orig_dest != NULL) { // move the read data to the non-aligned position, and restore the initial bytes memmove(orig_dest, dest, num_blocks * SDCARD_BLOCK_SIZE); memcpy(dest, &saved_word, orig_dest - dest); } return err; }
int mp_thread_mutex_lock(mp_thread_mutex_t *mutex, int wait) { if ((HAL_NVIC_INT_CTRL_REG & HAL_VECTACTIVE_MASK) == 0 && query_irq() == IRQ_STATE_ENABLED) { int ret = xSemaphoreTake(mutex->handle, wait ? portMAX_DELAY : 0); return ret == pdTRUE; } else { return 1; } }
mp_uint_t sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) { // check that SD card is initialised if (sd_handle.Instance == NULL) { return HAL_ERROR; } HAL_StatusTypeDef err = HAL_OK; // check that src pointer is aligned on a 4-byte boundary if (((uint32_t)src & 3) != 0) { // pointer is not aligned, so allocate a temporary block to do the write uint8_t *src_aligned = m_new_maybe(uint8_t, SDCARD_BLOCK_SIZE); if (src_aligned == NULL) { return HAL_ERROR; } for (size_t i = 0; i < num_blocks; ++i) { memcpy(src_aligned, src + i * SDCARD_BLOCK_SIZE, SDCARD_BLOCK_SIZE); err = sdcard_write_blocks(src_aligned, block_num + i, 1); if (err != HAL_OK) { break; } } m_del(uint8_t, src_aligned, SDCARD_BLOCK_SIZE); return err; } if (query_irq() == IRQ_STATE_ENABLED) { // we must disable USB irqs to prevent MSC contention with SD card uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); #if SDIO_USE_GPDMA dma_init(&sd_tx_dma, &SDMMC_TX_DMA, &sd_handle); sd_handle.hdmatx = &sd_tx_dma; #endif // make sure cache is flushed to RAM so the DMA can read the correct data MP_HAL_CLEAN_DCACHE(src, num_blocks * SDCARD_BLOCK_SIZE); err = HAL_SD_WriteBlocks_DMA(&sd_handle, (uint8_t*)src, block_num, num_blocks); if (err == HAL_OK) { err = sdcard_wait_finished(&sd_handle, 60000); } #if SDIO_USE_GPDMA dma_deinit(&SDMMC_TX_DMA); sd_handle.hdmatx = NULL; #endif restore_irq_pri(basepri); } else { err = HAL_SD_WriteBlocks(&sd_handle, (uint8_t*)src, block_num, num_blocks, 60000); if (err == HAL_OK) { err = sdcard_wait_finished(&sd_handle, 60000); } } return err; }
// delay for given number of microseconds void sys_tick_udelay(uint32_t usec) { if (query_irq() == IRQ_STATE_ENABLED) { // IRQs enabled, so can use systick counter to do the delay uint32_t start = sys_tick_get_microseconds(); while (sys_tick_get_microseconds() - start < usec) { } } else { // IRQs disabled, so need to use a busy loop for the delay // sys freq is always a multiple of 2MHz, so division here won't lose precision const uint32_t ucount = HAL_RCC_GetSysClockFreq() / 2000000 * usec / 2; for (uint32_t count = 0; ++count <= ucount;) { } } }
mp_uint_t sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) { // check that SD card is initialised if (sd_handle.Instance == NULL) { return SD_ERROR; } HAL_SD_ErrorTypedef err = SD_OK; // check that src pointer is aligned on a 4-byte boundary if (((uint32_t)src & 3) != 0) { // pointer is not aligned, so allocate a temporary block to do the write uint8_t *src_aligned = m_new_maybe(uint8_t, SDCARD_BLOCK_SIZE); if (src_aligned == NULL) { return SD_ERROR; } for (size_t i = 0; i < num_blocks; ++i) { memcpy(src_aligned, src + i * SDCARD_BLOCK_SIZE, SDCARD_BLOCK_SIZE); err = sdcard_write_blocks(src_aligned, block_num + i, 1); if (err != SD_OK) { break; } } m_del(uint8_t, src_aligned, SDCARD_BLOCK_SIZE); return err; } if (query_irq() == IRQ_STATE_ENABLED) { // we must disable USB irqs to prevent MSC contention with SD card uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); dma_init(&sd_tx_dma, &dma_SDIO_0_TX, &sd_handle); sd_handle.hdmatx = &sd_tx_dma; err = HAL_SD_WriteBlocks_BlockNumber_DMA(&sd_handle, (uint32_t*)src, block_num, SDCARD_BLOCK_SIZE, num_blocks); if (err == SD_OK) { // wait for DMA transfer to finish, with a large timeout err = HAL_SD_CheckWriteOperation(&sd_handle, 100000000); } dma_deinit(&dma_SDIO_0_TX); sd_handle.hdmatx = NULL; restore_irq_pri(basepri); } else { err = HAL_SD_WriteBlocks_BlockNumber(&sd_handle, (uint32_t*)src, block_num, SDCARD_BLOCK_SIZE, num_blocks); } return err; }
static bool telnet_send_with_retries (int16_t sd, const void *pBuf, int16_t len) { int32_t retries = 0; uint32_t delay = TELNET_WAIT_TIME_MS; // only if we are not within interrupt context and interrupts are enabled if ((HAL_NVIC_INT_CTRL_REG & HAL_VECTACTIVE_MASK) == 0 && query_irq() == IRQ_STATE_ENABLED) { do { _i16 result = sl_Send(sd, pBuf, len, 0); if (result > 0) { return true; } else if (SL_EAGAIN != result) { return false; } // start with the default delay and increment it on each retry mp_hal_delay_ms(delay++); } while (++retries <= TELNET_TX_RETRIES_MAX); } return false; }
// Always write all of the data to the device tx buffer, even if the // device is not connected, or if the buffer is full. Has a small timeout // to wait for the buffer to be drained, in the case the device is connected. void USBD_CDC_TxAlways(const uint8_t *buf, uint32_t len) { for (int i = 0; i < len; i++) { // If the CDC device is not connected to the host then we don't have anyone to receive our data. // The device may become connected in the future, so we should at least try to fill the buffer // and hope that it doesn't overflow by the time the device connects. // If the device is not connected then we should go ahead and fill the buffer straight away, // ignoring overflow. Otherwise, we should make sure that we have enough room in the buffer. if (dev_is_connected) { // If the buffer is full, wait until it gets drained, with a timeout of 500ms // (wraparound of tick is taken care of by 2's complement arithmetic). uint32_t start = HAL_GetTick(); while (((UserTxBufPtrIn + 1) & (APP_TX_DATA_SIZE - 1)) == UserTxBufPtrOut && HAL_GetTick() - start <= 500) { if (query_irq() == IRQ_STATE_DISABLED) { // IRQs disabled so buffer will never be drained; exit loop break; } __WFI(); // enter sleep mode, waiting for interrupt } // Some unused code that makes sure the low-level USB buffer is drained. // Waiting for low-level is handled in HAL_PCD_SOFCallback. /* start = HAL_GetTick(); PCD_HandleTypeDef *hpcd = hUSBDDevice.pData; if (hpcd->IN_ep[0x83 & 0x7f].is_in) { //volatile uint32_t *xfer_count = &hpcd->IN_ep[0x83 & 0x7f].xfer_count; //volatile uint32_t *xfer_len = &hpcd->IN_ep[0x83 & 0x7f].xfer_len; USB_OTG_GlobalTypeDef *USBx = hpcd->Instance; while ( // *xfer_count < *xfer_len // using this works // (USBx_INEP(3)->DIEPTSIZ & USB_OTG_DIEPTSIZ_XFRSIZ) // using this works && HAL_GetTick() - start <= 2000) { __WFI(); // enter sleep mode, waiting for interrupt } } */ } UserTxBuffer[UserTxBufPtrIn] = buf[i]; UserTxBufPtrIn = (UserTxBufPtrIn + 1) & (APP_TX_DATA_SIZE - 1); } }
// We provide our own version of HAL_Delay that calls __WFI while waiting, in // order to reduce power consumption. void HAL_Delay(uint32_t Delay) { if (query_irq() == IRQ_STATE_ENABLED) { // IRQs enabled, so can use systick counter to do the delay extern __IO uint32_t uwTick; uint32_t start = uwTick; // Wraparound of tick is taken care of by 2's complement arithmetic. while (uwTick - start < Delay) { // Enter sleep mode, waiting for (at least) the SysTick interrupt. __WFI(); } } else { // IRQs disabled, so need to use a busy loop for the delay. // To prevent possible overflow of the counter we use a double loop. const uint32_t count_1ms = HAL_RCC_GetSysClockFreq() / 4000; for (int i = 0; i < Delay; i++) { for (uint32_t count = 0; ++count <= count_1ms;) { } } } }
mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) { // check that dest pointer is aligned on a 4-byte boundary if (((uint32_t)dest & 3) != 0) { return SD_ERROR; } // check that SD card is initialised if (sd_handle.Instance == NULL) { return SD_ERROR; } HAL_SD_ErrorTypedef err = SD_OK; if (query_irq() == IRQ_STATE_ENABLED) { // we must disable USB irqs to prevent MSC contention with SD card uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); dma_init(&sd_rx_dma, DMA_STREAM_SDIO_RX, &dma_init_struct_sdio, DMA_CHANNEL_SDIO_RX, DMA_PERIPH_TO_MEMORY, &sd_handle); sd_handle.hdmarx = &sd_rx_dma; err = HAL_SD_ReadBlocks_BlockNumber_DMA(&sd_handle, (uint32_t*)dest, block_num, SDCARD_BLOCK_SIZE, num_blocks); if (err == SD_OK) { // wait for DMA transfer to finish, with a large timeout err = HAL_SD_CheckReadOperation(&sd_handle, 100000000); } dma_deinit(sd_handle.hdmarx); sd_handle.hdmarx = NULL; restore_irq_pri(basepri); } else { err = HAL_SD_ReadBlocks_BlockNumber(&sd_handle, (uint32_t*)dest, block_num, SDCARD_BLOCK_SIZE, num_blocks); } return err; }
int pyexec_friendly_repl(void) { vstr_t line; vstr_init(&line, 32); #if defined(USE_HOST_MODE) && MICROPY_HW_HAS_LCD // in host mode, we enable the LCD for the repl mp_obj_t lcd_o = mp_call_function_0(mp_load_name(qstr_from_str("LCD"))); mp_call_function_1(mp_load_attr(lcd_o, qstr_from_str("light")), mp_const_true); #endif friendly_repl_reset: mp_hal_stdout_tx_str("MicroPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME "\r\n"); #if MICROPY_PY_BUILTINS_HELP mp_hal_stdout_tx_str("Type \"help()\" for more information.\r\n"); #endif // to test ctrl-C /* { uint32_t x[4] = {0x424242, 0xdeaddead, 0x242424, 0xdeadbeef}; for (;;) { nlr_buf_t nlr; printf("pyexec_repl: %p\n", x); mp_hal_set_interrupt_char(CHAR_CTRL_C); if (nlr_push(&nlr) == 0) { for (;;) { } } else { printf("break\n"); } } } */ for (;;) { input_restart: #if defined(USE_DEVICE_MODE) if (usb_vcp_is_enabled()) { // If the user gets to here and interrupts are disabled then // they'll never see the prompt, traceback etc. The USB REPL needs // interrupts to be enabled or no transfers occur. So we try to // do the user a favor and reenable interrupts. if (query_irq() == IRQ_STATE_DISABLED) { enable_irq(IRQ_STATE_ENABLED); mp_hal_stdout_tx_str("PYB: enabling IRQs\r\n"); } } #endif vstr_reset(&line); int ret = readline(&line, ">>> "); mp_parse_input_kind_t parse_input_kind = MP_PARSE_SINGLE_INPUT; if (ret == CHAR_CTRL_A) { // change to raw REPL mp_hal_stdout_tx_str("\r\n"); vstr_clear(&line); pyexec_mode_kind = PYEXEC_MODE_RAW_REPL; return 0; } else if (ret == CHAR_CTRL_B) { // reset friendly REPL mp_hal_stdout_tx_str("\r\n"); goto friendly_repl_reset; } else if (ret == CHAR_CTRL_C) { // break mp_hal_stdout_tx_str("\r\n"); continue; } else if (ret == CHAR_CTRL_D) { // exit for a soft reset mp_hal_stdout_tx_str("\r\n"); vstr_clear(&line); return PYEXEC_FORCED_EXIT; } else if (ret == CHAR_CTRL_E) { // paste mode mp_hal_stdout_tx_str("\r\npaste mode; Ctrl-C to cancel, Ctrl-D to finish\r\n=== "); vstr_reset(&line); for (;;) { char c = mp_hal_stdin_rx_chr(); if (c == CHAR_CTRL_C) { // cancel everything mp_hal_stdout_tx_str("\r\n"); goto input_restart; } else if (c == CHAR_CTRL_D) { // end of input mp_hal_stdout_tx_str("\r\n"); break; } else { // add char to buffer and echo vstr_add_byte(&line, c); if (c == '\r') { mp_hal_stdout_tx_str("\r\n=== "); } else { mp_hal_stdout_tx_strn(&c, 1); } } } parse_input_kind = MP_PARSE_FILE_INPUT; } else if (vstr_len(&line) == 0) { continue; } else { // got a line with non-zero length, see if it needs continuing while (mp_repl_continue_with_input(vstr_null_terminated_str(&line))) { vstr_add_byte(&line, '\n'); ret = readline(&line, "... "); if (ret == CHAR_CTRL_C) { // cancel everything mp_hal_stdout_tx_str("\r\n"); goto input_restart; } else if (ret == CHAR_CTRL_D) { // stop entering compound statement break; } } } ret = parse_compile_execute(&line, parse_input_kind, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL | EXEC_FLAG_SOURCE_IS_VSTR); if (ret & PYEXEC_FORCED_EXIT) { return ret; } } }
void mp_thread_mutex_unlock(mp_thread_mutex_t *mutex) { if ((HAL_NVIC_INT_CTRL_REG & HAL_VECTACTIVE_MASK) == 0 && query_irq() == IRQ_STATE_ENABLED) { xSemaphoreGive(mutex->handle); // TODO check return value } }