/** * @brief USB suspend routine. * @details This function must be invoked when an USB bus suspend condition is * detected. * * @param[in] usbp pointer to the @p USBDriver object * * @notapi */ void _usb_suspend(USBDriver *usbp) { /* No state change, suspend always returns to previous state. */ /* State transition.*/ usbp->saved_state = usbp->state; usbp->state = USB_SUSPENDED; /* Notification of suspend event.*/ _usb_isr_invoke_event_cb(usbp, USB_EVENT_SUSPEND); /* Signaling the event to threads waiting on endpoints.*/ #if USB_USE_WAIT == TRUE { unsigned i; for (i = 0; i <= (unsigned)USB_MAX_ENDPOINTS; i++) { if (usbp->epc[i] != NULL) { osalSysLockFromISR(); if (usbp->epc[i]->in_state != NULL) { osalThreadResumeI(&usbp->epc[i]->in_state->thread, MSG_RESET); } if (usbp->epc[i]->out_state != NULL) { osalThreadResumeI(&usbp->epc[i]->out_state->thread, MSG_RESET); } osalSysUnlockFromISR(); } } } #endif }
/** * @brief Disables all the active endpoints. * @details This function disables all the active endpoints except the * endpoint zero. * @note This function must be invoked in response of a SET_CONFIGURATION * message with configuration number zero. * * @param[in] usbp pointer to the @p USBDriver object * * @iclass */ void usbDisableEndpointsI(USBDriver *usbp) { unsigned i; osalDbgCheckClassI(); osalDbgCheck(usbp != NULL); osalDbgAssert(usbp->state == USB_ACTIVE, "invalid state"); usbp->transmitting &= 1U; usbp->receiving &= 1U; for (i = 1; i <= (unsigned)USB_MAX_ENDPOINTS; i++) { #if USB_USE_WAIT == TRUE /* Signaling the event to threads waiting on endpoints.*/ if (usbp->epc[i] != NULL) { osalSysLockFromISR(); if (usbp->epc[i]->in_state != NULL) { osalThreadResumeI(&usbp->epc[i]->in_state->thread, MSG_RESET); } if (usbp->epc[i]->out_state != NULL) { osalThreadResumeI(&usbp->epc[i]->out_state->thread, MSG_RESET); } osalSysUnlockFromISR(); } #endif usbp->epc[i] = NULL; } /* Low level endpoints deactivation.*/ usb_lld_disable_endpoints(usbp); }
/** * @brief Deactivates the USB peripheral. * * @param[in] usbp pointer to the @p USBDriver object * * @api */ void usbStop(USBDriver *usbp) { unsigned i; osalDbgCheck(usbp != NULL); osalSysLock(); osalDbgAssert((usbp->state == USB_STOP) || (usbp->state == USB_READY) || (usbp->state == USB_SELECTED) || (usbp->state == USB_ACTIVE) || (usbp->state == USB_SUSPENDED), "invalid state"); usb_lld_stop(usbp); usbp->config = NULL; usbp->state = USB_STOP; /* Resetting all ongoing synchronous operations.*/ for (i = 0; i <= (unsigned)USB_MAX_ENDPOINTS; i++) { #if USB_USE_WAIT == TRUE if (usbp->epc[i] != NULL) { if (usbp->epc[i]->in_state != NULL) { osalThreadResumeI(&usbp->epc[i]->in_state->thread, MSG_RESET); } if (usbp->epc[i]->out_state != NULL) { osalThreadResumeI(&usbp->epc[i]->out_state->thread, MSG_RESET); } } #endif usbp->epc[i] = NULL; } osalOsRescheduleS(); osalSysUnlock(); }
/** * @brief 1-wire read bit callback. * @note Must be called from PWM's ISR. * * @param[in] pwmp pointer to the @p PWMDriver object * @param[in] owp pointer to the @p onewireDriver object * * @notapi */ static void ow_read_bit_cb(PWMDriver *pwmp, onewireDriver *owp) { if (true == owp->reg.final_timeslot) { osalSysLockFromISR(); pwmDisableChannelI(pwmp, owp->config->sample_channel); osalThreadResumeI(&owp->thread, MSG_OK); osalSysUnlockFromISR(); return; } else { *owp->buf |= ow_read_bit(owp) << owp->reg.bit; owp->reg.bit++; if (8 == owp->reg.bit) { owp->reg.bit = 0; owp->buf++; owp->reg.bytes--; if (0 == owp->reg.bytes) { owp->reg.final_timeslot = true; osalSysLockFromISR(); /* Only master channel must be stopped here. Sample channel will be stopped in next ISR call. It is still needed to generate final interrupt. */ pwmDisableChannelI(pwmp, owp->config->master_channel); osalSysUnlockFromISR(); } } } }
/** * @brief 1-wire reset pulse callback. * @note Must be called from PWM's ISR. * * @param[in] pwmp pointer to the @p PWMDriver object * @param[in] owp pointer to the @p onewireDriver object * * @notapi */ static void ow_reset_cb(PWMDriver *pwmp, onewireDriver *owp) { owp->reg.slave_present = (PAL_LOW == ow_read_bit(owp)); osalSysLockFromISR(); pwmDisableChannelI(pwmp, owp->config->sample_channel); osalThreadResumeI(&owp->thread, MSG_OK); osalSysUnlockFromISR(); }
/** * @brief USB reset routine. * @details This function must be invoked when an USB bus reset condition is * detected. * * @param[in] usbp pointer to the @p USBDriver object * * @notapi */ void _usb_reset(USBDriver *usbp) { unsigned i; /* State transition.*/ usbp->state = USB_READY; /* Resetting internal state.*/ usbp->status = 0; usbp->address = 0; usbp->configuration = 0; usbp->transmitting = 0; usbp->receiving = 0; /* Invalidates all endpoints into the USBDriver structure.*/ for (i = 0; i <= (unsigned)USB_MAX_ENDPOINTS; i++) { #if USB_USE_WAIT == TRUE /* Signaling the event to threads waiting on endpoints.*/ if (usbp->epc[i] != NULL) { osalSysLockFromISR(); if (usbp->epc[i]->in_state != NULL) { osalThreadResumeI(&usbp->epc[i]->in_state->thread, MSG_RESET); } if (usbp->epc[i]->out_state != NULL) { osalThreadResumeI(&usbp->epc[i]->out_state->thread, MSG_RESET); } osalSysUnlockFromISR(); } #endif usbp->epc[i] = NULL; } /* EP0 state machine initialization.*/ usbp->ep0state = USB_EP0_WAITING_SETUP; /* Low level reset.*/ usb_lld_reset(usbp); /* Notification of reset event.*/ _usb_isr_invoke_event_cb(usbp, USB_EVENT_RESET); }
/** * @brief Aborts the ongoing SPI operation. * * @param[in] spip pointer to the @p SPIDriver object * * @iclass */ void spiAbortI(SPIDriver *spip) { osalDbgCheckClassI(); osalDbgCheck(spip != NULL); osalDbgAssert((spip->state == SPI_ACTIVE) || (spip->state == SPI_COMPLETE), "invalid state"); spi_lld_abort(spip); spip->state = SPI_READY; #if SPI_USE_WAIT == TRUE osalThreadResumeI(&spip->thread, MSG_OK); #endif }
/** * @brief Generic endpoint IN handler. * * @param[in] usbp pointer to the @p USBDriver object * @param[in] ep endpoint number * * @notapi */ static void otg_epin_handler(USBDriver *usbp, usbep_t ep) { stm32_otg_t *otgp = usbp->otg; uint32_t epint = otgp->ie[ep].DIEPINT; otgp->ie[ep].DIEPINT = epint; if (epint & DIEPINT_TOC) { /* Timeouts not handled yet, not sure how to handle.*/ } if ((epint & DIEPINT_XFRC) && (otgp->DIEPMSK & DIEPMSK_XFRCM)) { /* Transmit transfer complete.*/ USBInEndpointState *isp = usbp->epc[ep]->in_state; if (isp->txsize < isp->totsize) { /* In case the transaction covered only part of the total transfer then another transaction is immediately started in order to cover the remaining.*/ isp->txsize = isp->totsize - isp->txsize; isp->txcnt = 0; usb_lld_prepare_transmit(usbp, ep); osalSysLockFromISR(); usb_lld_start_in(usbp, ep); osalSysUnlockFromISR(); } else { /* End on IN transfer.*/ _usb_isr_invoke_in_cb(usbp, ep); } } if ((epint & DIEPINT_TXFE) && (otgp->DIEPEMPMSK & DIEPEMPMSK_INEPTXFEM(ep))) { /* The thread is made ready, it will be scheduled on ISR exit.*/ osalSysLockFromISR(); usbp->txpending |= (1 << ep); otgp->DIEPEMPMSK &= ~(1 << ep); osalThreadResumeI(&usbp->wait, MSG_OK); osalSysUnlockFromISR(); } }
/** * @brief 1-wire bit transmission callback. * @note Must be called from PWM's ISR. * * @param[in] pwmp pointer to the @p PWMDriver object * @param[in] owp pointer to the @p onewireDriver object * * @notapi */ static void ow_write_bit_cb(PWMDriver *pwmp, onewireDriver *owp) { if (8 == owp->reg.bit) { owp->buf++; owp->reg.bit = 0; owp->reg.bytes--; if (0 == owp->reg.bytes) { osalSysLockFromISR(); pwmDisableChannelI(pwmp, owp->config->master_channel); osalSysUnlockFromISR(); /* used to prevent premature timer stop from userspace */ owp->reg.final_timeslot = true; return; } } /* wait until timer generate last pulse */ if (true == owp->reg.final_timeslot) { #if ONEWIRE_USE_STRONG_PULLUP if (owp->reg.need_pullup) { owp->reg.state = ONEWIRE_PULL_UP; owp->config->pullup_assert(); owp->reg.need_pullup = false; } #endif osalSysLockFromISR(); osalThreadResumeI(&owp->thread, MSG_OK); osalSysUnlockFromISR(); return; } ow_write_bit_I(owp, (*owp->buf >> owp->reg.bit) & 1); owp->reg.bit++; }
/** * @brief OTG shared ISR. * * @param[in] usbp pointer to the @p USBDriver object * * @notapi */ static void usb_lld_serve_interrupt(USBDriver *usbp) { stm32_otg_t *otgp = usbp->otg; uint32_t sts, src; sts = otgp->GINTSTS & otgp->GINTMSK; otgp->GINTSTS = sts; /* Reset interrupt handling.*/ if (sts & GINTSTS_USBRST) { _usb_reset(usbp); _usb_isr_invoke_event_cb(usbp, USB_EVENT_RESET); } /* Enumeration done.*/ if (sts & GINTSTS_ENUMDNE) { (void)otgp->DSTS; } /* SOF interrupt handling.*/ if (sts & GINTSTS_SOF) { _usb_isr_invoke_sof_cb(usbp); } /* RX FIFO not empty handling.*/ if (sts & GINTSTS_RXFLVL) { /* The interrupt is masked while the thread has control or it would be triggered again.*/ osalSysLockFromISR(); otgp->GINTMSK &= ~GINTMSK_RXFLVLM; osalThreadResumeI(&usbp->wait, MSG_OK); osalSysUnlockFromISR(); } /* IN/OUT endpoints event handling.*/ src = otgp->DAINT; if (sts & GINTSTS_IEPINT) { if (src & (1 << 0)) otg_epin_handler(usbp, 0); if (src & (1 << 1)) otg_epin_handler(usbp, 1); if (src & (1 << 2)) otg_epin_handler(usbp, 2); if (src & (1 << 3)) otg_epin_handler(usbp, 3); #if STM32_USB_USE_OTG2 if (src & (1 << 4)) otg_epin_handler(usbp, 4); if (src & (1 << 5)) otg_epin_handler(usbp, 5); #endif } if (sts & GINTSTS_OEPINT) { if (src & (1 << 16)) otg_epout_handler(usbp, 0); if (src & (1 << 17)) otg_epout_handler(usbp, 1); if (src & (1 << 18)) otg_epout_handler(usbp, 2); if (src & (1 << 19)) otg_epout_handler(usbp, 3); #if STM32_USB_USE_OTG2 if (src & (1 << 20)) otg_epout_handler(usbp, 4); if (src & (1 << 21)) otg_epout_handler(usbp, 5); #endif } }
/** * @brief Wakes up the waiting thread. * * @param[in] nandp pointer to the @p NANDDriver object * @param[in] msg wakeup message * * @notapi */ static void wakeup_isr(NANDDriver *nandp) { osalDbgCheck(nandp->thread != NULL); osalThreadResumeI(&nandp->thread, MSG_OK); }
/** * @brief 1-wire search ROM callback. * @note Must be called from PWM's ISR. * * @param[in] pwmp pointer to the @p PWMDriver object * @param[in] owp pointer to the @p onewireDriver object * * @notapi */ static void ow_search_rom_cb(PWMDriver *pwmp, onewireDriver *owp) { onewire_search_rom_t *sr = &owp->search_rom; if (0 == sr->reg.bit_step) { /* read direct bit */ sr->reg.bit_buf |= ow_read_bit(owp); sr->reg.bit_step++; } else if (1 == sr->reg.bit_step) { /* read complement bit */ sr->reg.bit_buf |= ow_read_bit(owp) << 1; sr->reg.bit_step++; switch(sr->reg.bit_buf){ case 0b11: /* no one device on bus or any other fail happened */ sr->reg.result = ONEWIRE_SEARCH_ROM_ERROR; goto THE_END; break; case 0b01: /* all slaves have 1 in this position */ store_bit(sr, 1); ow_write_bit_I(owp, 1); break; case 0b10: /* all slaves have 0 in this position */ store_bit(sr, 0); ow_write_bit_I(owp, 0); break; case 0b00: /* collision */ sr->reg.single_device = false; ow_write_bit_I(owp, collision_handler(sr)); break; } } else { /* start next step */ #if !ONEWIRE_SYNTH_SEARCH_TEST ow_write_bit_I(owp, 1); #endif sr->reg.bit_step = 0; sr->reg.bit_buf = 0; } /* one ROM successfully discovered */ if (64 == sr->reg.rombit) { sr->reg.devices_found++; sr->reg.search_iter = ONEWIRE_SEARCH_ROM_NEXT; if (true == sr->reg.single_device) sr->reg.result = ONEWIRE_SEARCH_ROM_LAST; goto THE_END; } return; /* next search bit iteration */ THE_END: #if ONEWIRE_SYNTH_SEARCH_TEST (void)pwmp; return; #else osalSysLockFromISR(); pwmDisableChannelI(pwmp, owp->config->master_channel); pwmDisableChannelI(pwmp, owp->config->sample_channel); osalThreadResumeI(&(owp)->thread, MSG_OK); osalSysUnlockFromISR(); #endif }