From 9d74dd2661b80a5ae8598591f0251b197cc51756 Mon Sep 17 00:00:00 2001 From: barthess Date: Thu, 7 Apr 2016 16:39:12 +0300 Subject: STM32 mass update to current naming convention in ChibiOS --- os/hal/ports/STM32/LLD/CRCv1/crc_lld.c | 328 -- os/hal/ports/STM32/LLD/CRCv1/crc_lld.h | 249 -- os/hal/ports/STM32/LLD/CRCv1/hal_crc_lld.c | 328 ++ os/hal/ports/STM32/LLD/CRCv1/hal_crc_lld.h | 249 ++ os/hal/ports/STM32/LLD/DMA2Dv1/hal_stm32_dma2d.c | 3130 ++++++++++++++++++ os/hal/ports/STM32/LLD/DMA2Dv1/hal_stm32_dma2d.h | 664 ++++ os/hal/ports/STM32/LLD/DMA2Dv1/stm32_dma2d.c | 3130 ------------------ os/hal/ports/STM32/LLD/DMA2Dv1/stm32_dma2d.h | 664 ---- os/hal/ports/STM32/LLD/FSMCv1/fsmc.c | 187 -- os/hal/ports/STM32/LLD/FSMCv1/fsmc.h | 339 -- os/hal/ports/STM32/LLD/FSMCv1/fsmc_sdram.c | 211 -- os/hal/ports/STM32/LLD/FSMCv1/fsmc_sdram.h | 171 - os/hal/ports/STM32/LLD/FSMCv1/fsmc_sram.c | 156 - os/hal/ports/STM32/LLD/FSMCv1/fsmc_sram.h | 172 - os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc.c | 187 ++ os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc.h | 339 ++ os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sdram.c | 211 ++ os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sdram.h | 171 + os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sram.c | 156 + os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sram.h | 172 + os/hal/ports/STM32/LLD/FSMCv1/hal_nand_lld.c | 515 +++ os/hal/ports/STM32/LLD/FSMCv1/hal_nand_lld.h | 324 ++ os/hal/ports/STM32/LLD/FSMCv1/nand_lld.c | 515 --- os/hal/ports/STM32/LLD/FSMCv1/nand_lld.h | 324 -- os/hal/ports/STM32/LLD/LTDCv1/hal_stm32_ltdc.c | 3792 ++++++++++++++++++++++ os/hal/ports/STM32/LLD/LTDCv1/hal_stm32_ltdc.h | 736 +++++ os/hal/ports/STM32/LLD/LTDCv1/stm32_ltdc.c | 3792 ---------------------- os/hal/ports/STM32/LLD/LTDCv1/stm32_ltdc.h | 736 ----- os/hal/ports/STM32/LLD/TIMv1/eicu_lld.c | 1176 ------- os/hal/ports/STM32/LLD/TIMv1/eicu_lld.h | 554 ---- os/hal/ports/STM32/LLD/TIMv1/hal_eicu_lld.c | 1176 +++++++ os/hal/ports/STM32/LLD/TIMv1/hal_eicu_lld.h | 554 ++++ os/hal/ports/STM32/LLD/TIMv1/hal_timcap_lld.c | 818 +++++ os/hal/ports/STM32/LLD/TIMv1/hal_timcap_lld.h | 390 +++ os/hal/ports/STM32/LLD/TIMv1/timcap_lld.c | 818 ----- os/hal/ports/STM32/LLD/TIMv1/timcap_lld.h | 390 --- os/hal/ports/STM32/LLD/USBHv1/hal_stm32_otg.h | 929 ++++++ os/hal/ports/STM32/LLD/USBHv1/hal_usbh_lld.c | 1604 +++++++++ os/hal/ports/STM32/LLD/USBHv1/hal_usbh_lld.h | 153 + os/hal/ports/STM32/LLD/USBHv1/stm32_otg.h | 929 ------ os/hal/ports/STM32/LLD/USBHv1/usbh_lld.c | 1604 --------- os/hal/ports/STM32/LLD/USBHv1/usbh_lld.h | 153 - os/hal/ports/STM32/STM32F0xx/platform.mk | 4 +- os/hal/ports/STM32/STM32F3xx/platform.mk | 6 +- os/hal/ports/STM32/STM32F4xx/platform.mk | 20 +- 45 files changed, 16613 insertions(+), 16613 deletions(-) delete mode 100644 os/hal/ports/STM32/LLD/CRCv1/crc_lld.c delete mode 100644 os/hal/ports/STM32/LLD/CRCv1/crc_lld.h create mode 100644 os/hal/ports/STM32/LLD/CRCv1/hal_crc_lld.c create mode 100644 os/hal/ports/STM32/LLD/CRCv1/hal_crc_lld.h create mode 100644 os/hal/ports/STM32/LLD/DMA2Dv1/hal_stm32_dma2d.c create mode 100644 os/hal/ports/STM32/LLD/DMA2Dv1/hal_stm32_dma2d.h delete mode 100644 os/hal/ports/STM32/LLD/DMA2Dv1/stm32_dma2d.c delete mode 100644 os/hal/ports/STM32/LLD/DMA2Dv1/stm32_dma2d.h delete mode 100644 os/hal/ports/STM32/LLD/FSMCv1/fsmc.c delete mode 100644 os/hal/ports/STM32/LLD/FSMCv1/fsmc.h delete mode 100644 os/hal/ports/STM32/LLD/FSMCv1/fsmc_sdram.c delete mode 100644 os/hal/ports/STM32/LLD/FSMCv1/fsmc_sdram.h delete mode 100644 os/hal/ports/STM32/LLD/FSMCv1/fsmc_sram.c delete mode 100644 os/hal/ports/STM32/LLD/FSMCv1/fsmc_sram.h create mode 100644 os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc.c create mode 100644 os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc.h create mode 100644 os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sdram.c create mode 100644 os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sdram.h create mode 100644 os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sram.c create mode 100644 os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sram.h create mode 100644 os/hal/ports/STM32/LLD/FSMCv1/hal_nand_lld.c create mode 100644 os/hal/ports/STM32/LLD/FSMCv1/hal_nand_lld.h delete mode 100644 os/hal/ports/STM32/LLD/FSMCv1/nand_lld.c delete mode 100644 os/hal/ports/STM32/LLD/FSMCv1/nand_lld.h create mode 100644 os/hal/ports/STM32/LLD/LTDCv1/hal_stm32_ltdc.c create mode 100644 os/hal/ports/STM32/LLD/LTDCv1/hal_stm32_ltdc.h delete mode 100644 os/hal/ports/STM32/LLD/LTDCv1/stm32_ltdc.c delete mode 100644 os/hal/ports/STM32/LLD/LTDCv1/stm32_ltdc.h delete mode 100644 os/hal/ports/STM32/LLD/TIMv1/eicu_lld.c delete mode 100644 os/hal/ports/STM32/LLD/TIMv1/eicu_lld.h create mode 100644 os/hal/ports/STM32/LLD/TIMv1/hal_eicu_lld.c create mode 100644 os/hal/ports/STM32/LLD/TIMv1/hal_eicu_lld.h create mode 100644 os/hal/ports/STM32/LLD/TIMv1/hal_timcap_lld.c create mode 100644 os/hal/ports/STM32/LLD/TIMv1/hal_timcap_lld.h delete mode 100644 os/hal/ports/STM32/LLD/TIMv1/timcap_lld.c delete mode 100644 os/hal/ports/STM32/LLD/TIMv1/timcap_lld.h create mode 100644 os/hal/ports/STM32/LLD/USBHv1/hal_stm32_otg.h create mode 100644 os/hal/ports/STM32/LLD/USBHv1/hal_usbh_lld.c create mode 100644 os/hal/ports/STM32/LLD/USBHv1/hal_usbh_lld.h delete mode 100644 os/hal/ports/STM32/LLD/USBHv1/stm32_otg.h delete mode 100644 os/hal/ports/STM32/LLD/USBHv1/usbh_lld.c delete mode 100644 os/hal/ports/STM32/LLD/USBHv1/usbh_lld.h (limited to 'os/hal/ports') diff --git a/os/hal/ports/STM32/LLD/CRCv1/crc_lld.c b/os/hal/ports/STM32/LLD/CRCv1/crc_lld.c deleted file mode 100644 index 601deca..0000000 --- a/os/hal/ports/STM32/LLD/CRCv1/crc_lld.c +++ /dev/null @@ -1,328 +0,0 @@ -/* - ChibiOS - Copyright (C) 2015 Michael D. Spradling - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -/** - * @file STM32/CRCv1/crc_lld.c - * @brief STM32 CRC subsystem low level driver source. - * - * @addtogroup CRC - * @{ - */ - -#include "hal.h" - -#if (HAL_USE_CRC == TRUE) || defined(__DOXYGEN__) - -/** - * Allow CRC Software override for ST drivers. Some ST CRC implimentations - * have limited capabilities. - */ -#if CRCSW_USE_CRC1 != TRUE - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/** - * @brief CRC default configuration. - */ -static const CRCConfig default_config = { - .poly_size = 32, - .poly = 0x04C11DB7, - .initial_val = 0xFFFFFFFF, - .final_val = 0xFFFFFFFF, - .reflect_data = 1, - .reflect_remainder = 1 -}; - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/** @brief CRC1 driver identifier.*/ -#if STM32_CRC_USE_CRC1 || defined(__DOXYGEN__) -CRCDriver CRCD1; -#endif - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -void _crc_lld_calc_byte(CRCDriver *crcp, uint8_t data) { - __IO uint8_t *crc8 = (__IO uint8_t*)&(crcp->crc->DR); - *crc8 = data; -} - -/* - * @brief Returns calculated CRC from last reset - * - * @param[in] crcp pointer to the @p CRCDriver object - * @param[in] data data to be added to crc - * - * @notapi - */ -void _crc_lld_calc_halfword(CRCDriver *crcp, uint16_t data) { - __IO uint16_t *crc16 = (__IO uint16_t*)&(crcp->crc->DR); - *crc16 = data; -} - -/* - * @brief Returns calculated CRC from last reset - * - * @param[in] crcp pointer to the @p CRCDriver object - * @param[in] data data to be added to crc - * - * @notapi - */ -void _crc_lld_calc_word(CRCDriver *crcp, uint32_t data) { - crcp->crc->DR = data; -} - - -/*===========================================================================*/ -/* Driver interrupt handlers. */ -/*===========================================================================*/ - -/** - * @brief Shared end-of-rx service routine. - * - * @param[in] crcp pointer to the @p CRCDriver object - * @param[in] flags pre-shifted content of the ISR register - */ -#if CRC_USE_DMA == TRUE -static void crc_lld_serve_interrupt(CRCDriver *crcp, uint32_t flags) { - - /* DMA errors handling.*/ -#if defined(STM32_CRC_DMA_ERROR_HOOK) - if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { - STM32_CRC_DMA_ERROR_HOOK(crcp); - } -#else - (void)flags; -#endif - - /* Stop everything.*/ - dmaStreamDisable(crcp->dma); - - /* Portable CRC ISR code defined in the high level driver, note, it is - a macro.*/ - _crc_isr_code(crcp, crcp->crc->DR ^ crcp->config->final_val); -} -#endif - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief Low level CRC driver initialization. - * - * @notapi - */ -void crc_lld_init(void) { - crcObjectInit(&CRCD1); - CRCD1.crc = CRC; -#if CRC_USE_DMA == TRUE - CRCD1.dma = STM32_CRC_CRC1_DMA_STREAM; -#endif -} - -/** - * @brief Configures and activates the CRC peripheral. - * - * @param[in] crcp pointer to the @p CRCDriver object - * - * @notapi - */ -void crc_lld_start(CRCDriver *crcp) { - if (crcp->config == NULL) - crcp->config = &default_config; - - rccEnableCRC(FALSE); - -#if STM32_CRC_PROGRAMMABLE == TRUE - crcp->crc->INIT = crcp->config->initial_val; - crcp->crc->POL = crcp->config->poly; - - crcp->crc->CR = 0; - switch(crcp->config->poly_size) { - case 32: - break; - case 16: - crcp->crc->CR |= CRC_CR_POLYSIZE_0; - break; - case 8: - crcp->crc->CR |= CRC_CR_POLYSIZE_1; - break; - case 7: - crcp->crc->CR |= CRC_CR_POLYSIZE_1 | CRC_CR_POLYSIZE_0; - break; - default: - osalDbgAssert(false, "hardware doesn't support polynomial size"); - break; - }; - if (crcp->config->reflect_data) { - crcp->crc->CR |= CRC_CR_REV_IN_1 | CRC_CR_REV_IN_0; - } - if (crcp->config->reflect_remainder) { - crcp->crc->CR |= CRC_CR_REV_OUT; - } -#else - osalDbgAssert(crcp->config->initial_val != default_config.initial_val, - "hardware doesn't support programmable initial value"); - osalDbgAssert(crcp->config->poly_size != default_config.poly_size, - "hardware doesn't support programmable polynomial size"); - osalDbgAssert(crcp->config->poly != default_config.poly, - "hardware doesn't support programmable polynomial"); - osalDbgAssert(crcp->config->reflect_data != default_config.reflect_data, - "hardware doesn't support reflect of input data"); - osalDbgAssert(crcp->config->reflect_remainder != default_config.reflect_remainder, - "hardware doesn't support reflect of output remainder"); -#endif - -#if CRC_USE_DMA == TRUE -#if STM32_CRC_PROGRAMMABLE == TRUE - crcp->dmamode = STM32_DMA_CR_DIR_M2M | STM32_DMA_CR_PINC | - STM32_DMA_CR_MSIZE_BYTE | STM32_DMA_CR_PSIZE_BYTE | - STM32_DMA_CR_TEIE | STM32_DMA_CR_TCIE | - STM32_DMA_CR_PL(STM32_CRC_CRC1_DMA_PRIORITY); -#else - crcp->dmamode = STM32_DMA_CR_DIR_M2M | STM32_DMA_CR_PINC | - STM32_DMA_CR_MSIZE_WORD | STM32_DMA_CR_PSIZE_WORD | - STM32_DMA_CR_TEIE | STM32_DMA_CR_TCIE | - STM32_DMA_CR_PL(STM32_CRC_CRC1_DMA_PRIORITY); -#endif - { - bool b; - b = dmaStreamAllocate(crcp->dma, - STM32_CRC_CRC1_DMA_IRQ_PRIORITY, - (stm32_dmaisr_t)crc_lld_serve_interrupt, - (void *)crcp); - osalDbgAssert(!b, "stream already allocated"); - } -#endif -} - - -/** - * @brief Deactivates the CRC peripheral. - * - * @param[in] crcp pointer to the @p CRCDriver object - * - * @notapi - */ -void crc_lld_stop(CRCDriver *crcp) { -#if CRC_USE_DMA == TRUE - dmaStreamRelease(crcp->dma); -#else - (void)crcp; -#endif - rccDisableCRC(FALSE); -} - -/** - * @brief Resets current CRC calculation. - * - * @param[in] crcp pointer to the @p CRCDriver object - * - * @notapi - */ -void crc_lld_reset(CRCDriver *crcp) { - crcp->crc->CR |= CRC_CR_RESET; -} - -/** - * @brief Returns calculated CRC from last reset - * - * @param[in] crcp pointer to the @p CRCDriver object - * @param[in] n size of buf in bytes - * @param[in] buf @p buffer location - * - * @notapi - */ -uint32_t crc_lld_calc(CRCDriver *crcp, size_t n, const void *buf) { -#if CRC_USE_DMA == TRUE - crc_lld_start_calc(crcp, n, buf); - (void) osalThreadSuspendS(&crcp->thread); -#else - /** - * BUG: Only peform byte writes to DR reg if reflect_data is disabled. - * The STM32 hardware unit seems to incorrectly calculate CRCs when all - * of the following is true: reflect_data(rev_in) is 0, dma is disable, and - * you are writing more than a byte into the DR register. - */ - if (crcp->config->reflect_data != 0) { - while(n > 3) { - _crc_lld_calc_word(crcp, *(uint32_t*)buf); - buf+=4; - n-=4; - } - } - -#if STM32_CRC_PROGRAMMABLE == TRUE - /* Programmable CRC units allow variable register width accesses.*/ - - /** - * BUG: Only peform byte writes to DR reg if reflect_data is disabled. - * The STM32 hardware unit seems to incorrectly calculate CRCs when all - * of the following is true: reflect_data(rev_in) is 0, dma is disable, and - * you are writing more than a byte into the DR register. - */ - if (crcp->config->reflect_data != 0) { - while(n > 1) { - _crc_lld_calc_halfword(crcp, *(uint16_t*)buf); - buf+=2; - n-=2; - } - } - - while(n > 0) { - _crc_lld_calc_byte(crcp, *(uint8_t*)buf); - buf++; - n--; - } -#else - osalDbgAssert(n != 0, "STM32 CRC Unit only supports WORD accesses"); -#endif - -#endif - return crcp->crc->DR ^ crcp->config->final_val; -} - -#if CRC_USE_DMA == TRUE -void crc_lld_start_calc(CRCDriver *crcp, size_t n, const void *buf) { - dmaStreamSetPeripheral(crcp->dma, buf); - dmaStreamSetMemory0(crcp->dma, &crcp->crc->DR); -#if STM32_CRC_PROGRAMMABLE == TRUE - dmaStreamSetTransactionSize(crcp->dma, n); -#else - dmaStreamSetTransactionSize(crcp->dma, (n / 4)); -#endif - dmaStreamSetMode(crcp->dma, crcp->dmamode); - - dmaStreamEnable(crcp->dma); -} -#endif - -#endif /* CRCSW_USE_CRC1 */ - -#endif /* HAL_USE_CRC */ - -/** @} */ diff --git a/os/hal/ports/STM32/LLD/CRCv1/crc_lld.h b/os/hal/ports/STM32/LLD/CRCv1/crc_lld.h deleted file mode 100644 index ecdaf81..0000000 --- a/os/hal/ports/STM32/LLD/CRCv1/crc_lld.h +++ /dev/null @@ -1,249 +0,0 @@ -/* - ChibiOS - Copyright (C) 2015 Michael D. Spradling - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -/** - * @file STM32/CRCv1/crc_lld.h - * @brief STM32 CRC subsystem low level driver header. - * - * @addtogroup CRC - * @{ - */ - -#ifndef _CRC_LLD_H_ -#define _CRC_LLD_H_ - -#if (HAL_USE_CRC == TRUE) || defined(__DOXYGEN__) - -/* - * This error check must occur outsite of CRCSW_USE_CRC1 to check if - * two LLD drivers are enabled at the same time - */ -#if STM32_CRC_USE_CRC1 == TRUE && \ - CRCSW_USE_CRC1 == TRUE -#error "Software CRC can't be enable with STM32_CRC_USE_CRC1" -#endif - -/** - * Allow CRC Software override for ST drivers. Some ST CRC implimentations - * have limited capabilities. - */ -#if CRCSW_USE_CRC1 != TRUE - -/*===========================================================================*/ -/* Driver constants. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver pre-compile time settings. */ -/*===========================================================================*/ - -/** - * @name Configuration options - * @{ - */ -/** - * @brief CRC1 driver enable switch. - * @details If set to @p TRUE the support for CRC1 is included. - * @note The default is @p FALSE. - */ -#if !defined(STM32_CRC_USE_CRC1) || defined(__DOXYGEN__) -#define STM32_CRC_USE_CRC1 FALSE -#endif - -/** - * @brief CRC1 DMA priority (0..3|lowest..highest). - * @note The priority level is for CRC DMA stream. - */ -#if !defined(STM32_CRC_CRC1_DMA_PRIORITY) || defined(__DOXYGEN__) -#define STM32_CRC_CRC1_DMA_PRIORITY 2 -#endif - -/** - * @brief CRC1 DMA interrupt priority level setting. - */ -#if !defined(STM32_CRC_CRC1_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__) -#define STM32_CRC_CRC1_DMA_IRQ_PRIORITY 1 -#endif - -/** - * @brief CRC1 DMA STREAM to use when performing CRC calculation. - */ -#if !defined(STM32_CRC_CRC1_DMA_STREAM) || defined(__DOXYGEN__) -#define STM32_CRC_CRC1_DMA_STREAM STM32_DMA1_STREAM2 -#endif - -/** - * @brief CRC DMA error hook. - */ -#if !defined(STM32_CRC_DMA_ERROR_HOOK) || defined(__DOXYGEN__) -#define STM32_CRC_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure") -#endif - -/*===========================================================================*/ -/* Derived constants and error checks. */ -/*===========================================================================*/ - -#if STM32_CRC_USE_CRC1 && !STM32_HAS_CRC -#error "Hardware CRC not present in the selected device" -#error "Use CRCSW_USE_CRC1 for software implementation" -#endif - -#if CRC_USE_DMA -#if STM32_CRC_USE_CRC1 && \ - !OSAL_IRQ_IS_VALID_PRIORITY(STM32_CRC_CRC1_DMA_IRQ_PRIORITY) -#error "Invalid IRQ priority assigned to CRC1" -#endif - -#if STM32_CRC_USE_CRC1 && \ - !STM32_DMA_IS_VALID_PRIORITY(STM32_CRC_CRC1_DMA_PRIORITY) -#error "Invalid DMA priority assigned to CRC1" -#endif - -#if !defined(STM32_DMA_REQUIRED) -#define STM32_DMA_REQUIRED -#endif -#endif - -/*===========================================================================*/ -/* Driver data structures and types. */ -/*===========================================================================*/ - -/** - * @brief Type of a structure representing an CRC driver. - */ -typedef struct CRCDriver CRCDriver; - -/** - * @brief CRC notification callback type - * - * @param[in] crcp pointer to the @ CRCDriver object triggering the - * callback - */ -typedef void (*crccallback_t)(CRCDriver *crcp, uint32_t crc); - -/** - * @brief Driver configuration structure. - */ -typedef struct { - /** - * @brief The size of polynomial to be used for CRC. - */ - uint32_t poly_size; - /** - * @brief The coefficients of the polynomial to be used for CRC. - */ - uint32_t poly; - /** - * @brief The inital value - */ - uint32_t initial_val; - /** - * @brief The final XOR value - */ - uint32_t final_val; - /** - * @brief Reflect bit order data going into CRC - */ - bool reflect_data; - /** - * @brief Reflect bit order of final remainder - */ - bool reflect_remainder; - /* End of the mandatory fields.*/ - /** - * @brief Operation complete callback or @p NULL - */ - crccallback_t end_cb; -} CRCConfig; - - -/** - * @brief Structure representing an CRC driver. - */ -struct CRCDriver { - /** - * @brief Driver state. - */ - crcstate_t state; - /** - * @brief Current configuration data. - */ - const CRCConfig *config; -#if CRC_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__) - /** - * @brief Mutex protecting the peripheral. - */ - mutex_t mutex; -#endif /* CRC_USE_MUTUAL_EXCLUSION */ -#if defined(CRC_DRIVER_EXT_FIELDS) - CRC_DRIVER_EXT_FIELDS -#endif - /* End of the mandatory fields.*/ - /** - * @brief Pointer to the CRCx registers block. - */ - CRC_TypeDef *crc; - -#if CRC_USE_DMA == TRUE - /** - * @brief Waiting thread. - */ - thread_reference_t thread; - /** - * @brief CRC DMA stream - */ - const stm32_dma_stream_t *dma; - /** - * @brief DMA mode bit mask. - */ - uint32_t dmamode; -#endif -}; - -/*===========================================================================*/ -/* Driver macros. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -#if STM32_CRC_USE_CRC1 && !defined(__DOXYGEN__) -extern CRCDriver CRCD1; -#endif /* STM32_CRC_USE_CRC1 */ - -#ifdef __cplusplus -extern "C" { -#endif - void crc_lld_init(void); - void crc_lld_start(CRCDriver *crcp); - void crc_lld_stop(CRCDriver *crcp); - void crc_lld_reset(CRCDriver *crcp); - uint32_t crc_lld_calc(CRCDriver *crcp, size_t n, const void *buf); -#if CRC_USE_DMA - void crc_lld_start_calc(CRCDriver *crcp, size_t n, const void *buf); -#endif -#ifdef __cplusplus -} -#endif - -#endif /* CRCSW_USE_CRC1 */ - -#endif /* HAL_USE_CRC */ - -#endif /* _CRC_LLD_H_ */ - -/** @} */ diff --git a/os/hal/ports/STM32/LLD/CRCv1/hal_crc_lld.c b/os/hal/ports/STM32/LLD/CRCv1/hal_crc_lld.c new file mode 100644 index 0000000..601deca --- /dev/null +++ b/os/hal/ports/STM32/LLD/CRCv1/hal_crc_lld.c @@ -0,0 +1,328 @@ +/* + ChibiOS - Copyright (C) 2015 Michael D. Spradling + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file STM32/CRCv1/crc_lld.c + * @brief STM32 CRC subsystem low level driver source. + * + * @addtogroup CRC + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_CRC == TRUE) || defined(__DOXYGEN__) + +/** + * Allow CRC Software override for ST drivers. Some ST CRC implimentations + * have limited capabilities. + */ +#if CRCSW_USE_CRC1 != TRUE + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/** + * @brief CRC default configuration. + */ +static const CRCConfig default_config = { + .poly_size = 32, + .poly = 0x04C11DB7, + .initial_val = 0xFFFFFFFF, + .final_val = 0xFFFFFFFF, + .reflect_data = 1, + .reflect_remainder = 1 +}; + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief CRC1 driver identifier.*/ +#if STM32_CRC_USE_CRC1 || defined(__DOXYGEN__) +CRCDriver CRCD1; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +void _crc_lld_calc_byte(CRCDriver *crcp, uint8_t data) { + __IO uint8_t *crc8 = (__IO uint8_t*)&(crcp->crc->DR); + *crc8 = data; +} + +/* + * @brief Returns calculated CRC from last reset + * + * @param[in] crcp pointer to the @p CRCDriver object + * @param[in] data data to be added to crc + * + * @notapi + */ +void _crc_lld_calc_halfword(CRCDriver *crcp, uint16_t data) { + __IO uint16_t *crc16 = (__IO uint16_t*)&(crcp->crc->DR); + *crc16 = data; +} + +/* + * @brief Returns calculated CRC from last reset + * + * @param[in] crcp pointer to the @p CRCDriver object + * @param[in] data data to be added to crc + * + * @notapi + */ +void _crc_lld_calc_word(CRCDriver *crcp, uint32_t data) { + crcp->crc->DR = data; +} + + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/** + * @brief Shared end-of-rx service routine. + * + * @param[in] crcp pointer to the @p CRCDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +#if CRC_USE_DMA == TRUE +static void crc_lld_serve_interrupt(CRCDriver *crcp, uint32_t flags) { + + /* DMA errors handling.*/ +#if defined(STM32_CRC_DMA_ERROR_HOOK) + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { + STM32_CRC_DMA_ERROR_HOOK(crcp); + } +#else + (void)flags; +#endif + + /* Stop everything.*/ + dmaStreamDisable(crcp->dma); + + /* Portable CRC ISR code defined in the high level driver, note, it is + a macro.*/ + _crc_isr_code(crcp, crcp->crc->DR ^ crcp->config->final_val); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level CRC driver initialization. + * + * @notapi + */ +void crc_lld_init(void) { + crcObjectInit(&CRCD1); + CRCD1.crc = CRC; +#if CRC_USE_DMA == TRUE + CRCD1.dma = STM32_CRC_CRC1_DMA_STREAM; +#endif +} + +/** + * @brief Configures and activates the CRC peripheral. + * + * @param[in] crcp pointer to the @p CRCDriver object + * + * @notapi + */ +void crc_lld_start(CRCDriver *crcp) { + if (crcp->config == NULL) + crcp->config = &default_config; + + rccEnableCRC(FALSE); + +#if STM32_CRC_PROGRAMMABLE == TRUE + crcp->crc->INIT = crcp->config->initial_val; + crcp->crc->POL = crcp->config->poly; + + crcp->crc->CR = 0; + switch(crcp->config->poly_size) { + case 32: + break; + case 16: + crcp->crc->CR |= CRC_CR_POLYSIZE_0; + break; + case 8: + crcp->crc->CR |= CRC_CR_POLYSIZE_1; + break; + case 7: + crcp->crc->CR |= CRC_CR_POLYSIZE_1 | CRC_CR_POLYSIZE_0; + break; + default: + osalDbgAssert(false, "hardware doesn't support polynomial size"); + break; + }; + if (crcp->config->reflect_data) { + crcp->crc->CR |= CRC_CR_REV_IN_1 | CRC_CR_REV_IN_0; + } + if (crcp->config->reflect_remainder) { + crcp->crc->CR |= CRC_CR_REV_OUT; + } +#else + osalDbgAssert(crcp->config->initial_val != default_config.initial_val, + "hardware doesn't support programmable initial value"); + osalDbgAssert(crcp->config->poly_size != default_config.poly_size, + "hardware doesn't support programmable polynomial size"); + osalDbgAssert(crcp->config->poly != default_config.poly, + "hardware doesn't support programmable polynomial"); + osalDbgAssert(crcp->config->reflect_data != default_config.reflect_data, + "hardware doesn't support reflect of input data"); + osalDbgAssert(crcp->config->reflect_remainder != default_config.reflect_remainder, + "hardware doesn't support reflect of output remainder"); +#endif + +#if CRC_USE_DMA == TRUE +#if STM32_CRC_PROGRAMMABLE == TRUE + crcp->dmamode = STM32_DMA_CR_DIR_M2M | STM32_DMA_CR_PINC | + STM32_DMA_CR_MSIZE_BYTE | STM32_DMA_CR_PSIZE_BYTE | + STM32_DMA_CR_TEIE | STM32_DMA_CR_TCIE | + STM32_DMA_CR_PL(STM32_CRC_CRC1_DMA_PRIORITY); +#else + crcp->dmamode = STM32_DMA_CR_DIR_M2M | STM32_DMA_CR_PINC | + STM32_DMA_CR_MSIZE_WORD | STM32_DMA_CR_PSIZE_WORD | + STM32_DMA_CR_TEIE | STM32_DMA_CR_TCIE | + STM32_DMA_CR_PL(STM32_CRC_CRC1_DMA_PRIORITY); +#endif + { + bool b; + b = dmaStreamAllocate(crcp->dma, + STM32_CRC_CRC1_DMA_IRQ_PRIORITY, + (stm32_dmaisr_t)crc_lld_serve_interrupt, + (void *)crcp); + osalDbgAssert(!b, "stream already allocated"); + } +#endif +} + + +/** + * @brief Deactivates the CRC peripheral. + * + * @param[in] crcp pointer to the @p CRCDriver object + * + * @notapi + */ +void crc_lld_stop(CRCDriver *crcp) { +#if CRC_USE_DMA == TRUE + dmaStreamRelease(crcp->dma); +#else + (void)crcp; +#endif + rccDisableCRC(FALSE); +} + +/** + * @brief Resets current CRC calculation. + * + * @param[in] crcp pointer to the @p CRCDriver object + * + * @notapi + */ +void crc_lld_reset(CRCDriver *crcp) { + crcp->crc->CR |= CRC_CR_RESET; +} + +/** + * @brief Returns calculated CRC from last reset + * + * @param[in] crcp pointer to the @p CRCDriver object + * @param[in] n size of buf in bytes + * @param[in] buf @p buffer location + * + * @notapi + */ +uint32_t crc_lld_calc(CRCDriver *crcp, size_t n, const void *buf) { +#if CRC_USE_DMA == TRUE + crc_lld_start_calc(crcp, n, buf); + (void) osalThreadSuspendS(&crcp->thread); +#else + /** + * BUG: Only peform byte writes to DR reg if reflect_data is disabled. + * The STM32 hardware unit seems to incorrectly calculate CRCs when all + * of the following is true: reflect_data(rev_in) is 0, dma is disable, and + * you are writing more than a byte into the DR register. + */ + if (crcp->config->reflect_data != 0) { + while(n > 3) { + _crc_lld_calc_word(crcp, *(uint32_t*)buf); + buf+=4; + n-=4; + } + } + +#if STM32_CRC_PROGRAMMABLE == TRUE + /* Programmable CRC units allow variable register width accesses.*/ + + /** + * BUG: Only peform byte writes to DR reg if reflect_data is disabled. + * The STM32 hardware unit seems to incorrectly calculate CRCs when all + * of the following is true: reflect_data(rev_in) is 0, dma is disable, and + * you are writing more than a byte into the DR register. + */ + if (crcp->config->reflect_data != 0) { + while(n > 1) { + _crc_lld_calc_halfword(crcp, *(uint16_t*)buf); + buf+=2; + n-=2; + } + } + + while(n > 0) { + _crc_lld_calc_byte(crcp, *(uint8_t*)buf); + buf++; + n--; + } +#else + osalDbgAssert(n != 0, "STM32 CRC Unit only supports WORD accesses"); +#endif + +#endif + return crcp->crc->DR ^ crcp->config->final_val; +} + +#if CRC_USE_DMA == TRUE +void crc_lld_start_calc(CRCDriver *crcp, size_t n, const void *buf) { + dmaStreamSetPeripheral(crcp->dma, buf); + dmaStreamSetMemory0(crcp->dma, &crcp->crc->DR); +#if STM32_CRC_PROGRAMMABLE == TRUE + dmaStreamSetTransactionSize(crcp->dma, n); +#else + dmaStreamSetTransactionSize(crcp->dma, (n / 4)); +#endif + dmaStreamSetMode(crcp->dma, crcp->dmamode); + + dmaStreamEnable(crcp->dma); +} +#endif + +#endif /* CRCSW_USE_CRC1 */ + +#endif /* HAL_USE_CRC */ + +/** @} */ diff --git a/os/hal/ports/STM32/LLD/CRCv1/hal_crc_lld.h b/os/hal/ports/STM32/LLD/CRCv1/hal_crc_lld.h new file mode 100644 index 0000000..ecdaf81 --- /dev/null +++ b/os/hal/ports/STM32/LLD/CRCv1/hal_crc_lld.h @@ -0,0 +1,249 @@ +/* + ChibiOS - Copyright (C) 2015 Michael D. Spradling + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file STM32/CRCv1/crc_lld.h + * @brief STM32 CRC subsystem low level driver header. + * + * @addtogroup CRC + * @{ + */ + +#ifndef _CRC_LLD_H_ +#define _CRC_LLD_H_ + +#if (HAL_USE_CRC == TRUE) || defined(__DOXYGEN__) + +/* + * This error check must occur outsite of CRCSW_USE_CRC1 to check if + * two LLD drivers are enabled at the same time + */ +#if STM32_CRC_USE_CRC1 == TRUE && \ + CRCSW_USE_CRC1 == TRUE +#error "Software CRC can't be enable with STM32_CRC_USE_CRC1" +#endif + +/** + * Allow CRC Software override for ST drivers. Some ST CRC implimentations + * have limited capabilities. + */ +#if CRCSW_USE_CRC1 != TRUE + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief CRC1 driver enable switch. + * @details If set to @p TRUE the support for CRC1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_CRC_USE_CRC1) || defined(__DOXYGEN__) +#define STM32_CRC_USE_CRC1 FALSE +#endif + +/** + * @brief CRC1 DMA priority (0..3|lowest..highest). + * @note The priority level is for CRC DMA stream. + */ +#if !defined(STM32_CRC_CRC1_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_CRC_CRC1_DMA_PRIORITY 2 +#endif + +/** + * @brief CRC1 DMA interrupt priority level setting. + */ +#if !defined(STM32_CRC_CRC1_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_CRC_CRC1_DMA_IRQ_PRIORITY 1 +#endif + +/** + * @brief CRC1 DMA STREAM to use when performing CRC calculation. + */ +#if !defined(STM32_CRC_CRC1_DMA_STREAM) || defined(__DOXYGEN__) +#define STM32_CRC_CRC1_DMA_STREAM STM32_DMA1_STREAM2 +#endif + +/** + * @brief CRC DMA error hook. + */ +#if !defined(STM32_CRC_DMA_ERROR_HOOK) || defined(__DOXYGEN__) +#define STM32_CRC_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure") +#endif + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if STM32_CRC_USE_CRC1 && !STM32_HAS_CRC +#error "Hardware CRC not present in the selected device" +#error "Use CRCSW_USE_CRC1 for software implementation" +#endif + +#if CRC_USE_DMA +#if STM32_CRC_USE_CRC1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_CRC_CRC1_DMA_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to CRC1" +#endif + +#if STM32_CRC_USE_CRC1 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_CRC_CRC1_DMA_PRIORITY) +#error "Invalid DMA priority assigned to CRC1" +#endif + +#if !defined(STM32_DMA_REQUIRED) +#define STM32_DMA_REQUIRED +#endif +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of a structure representing an CRC driver. + */ +typedef struct CRCDriver CRCDriver; + +/** + * @brief CRC notification callback type + * + * @param[in] crcp pointer to the @ CRCDriver object triggering the + * callback + */ +typedef void (*crccallback_t)(CRCDriver *crcp, uint32_t crc); + +/** + * @brief Driver configuration structure. + */ +typedef struct { + /** + * @brief The size of polynomial to be used for CRC. + */ + uint32_t poly_size; + /** + * @brief The coefficients of the polynomial to be used for CRC. + */ + uint32_t poly; + /** + * @brief The inital value + */ + uint32_t initial_val; + /** + * @brief The final XOR value + */ + uint32_t final_val; + /** + * @brief Reflect bit order data going into CRC + */ + bool reflect_data; + /** + * @brief Reflect bit order of final remainder + */ + bool reflect_remainder; + /* End of the mandatory fields.*/ + /** + * @brief Operation complete callback or @p NULL + */ + crccallback_t end_cb; +} CRCConfig; + + +/** + * @brief Structure representing an CRC driver. + */ +struct CRCDriver { + /** + * @brief Driver state. + */ + crcstate_t state; + /** + * @brief Current configuration data. + */ + const CRCConfig *config; +#if CRC_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__) + /** + * @brief Mutex protecting the peripheral. + */ + mutex_t mutex; +#endif /* CRC_USE_MUTUAL_EXCLUSION */ +#if defined(CRC_DRIVER_EXT_FIELDS) + CRC_DRIVER_EXT_FIELDS +#endif + /* End of the mandatory fields.*/ + /** + * @brief Pointer to the CRCx registers block. + */ + CRC_TypeDef *crc; + +#if CRC_USE_DMA == TRUE + /** + * @brief Waiting thread. + */ + thread_reference_t thread; + /** + * @brief CRC DMA stream + */ + const stm32_dma_stream_t *dma; + /** + * @brief DMA mode bit mask. + */ + uint32_t dmamode; +#endif +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_CRC_USE_CRC1 && !defined(__DOXYGEN__) +extern CRCDriver CRCD1; +#endif /* STM32_CRC_USE_CRC1 */ + +#ifdef __cplusplus +extern "C" { +#endif + void crc_lld_init(void); + void crc_lld_start(CRCDriver *crcp); + void crc_lld_stop(CRCDriver *crcp); + void crc_lld_reset(CRCDriver *crcp); + uint32_t crc_lld_calc(CRCDriver *crcp, size_t n, const void *buf); +#if CRC_USE_DMA + void crc_lld_start_calc(CRCDriver *crcp, size_t n, const void *buf); +#endif +#ifdef __cplusplus +} +#endif + +#endif /* CRCSW_USE_CRC1 */ + +#endif /* HAL_USE_CRC */ + +#endif /* _CRC_LLD_H_ */ + +/** @} */ diff --git a/os/hal/ports/STM32/LLD/DMA2Dv1/hal_stm32_dma2d.c b/os/hal/ports/STM32/LLD/DMA2Dv1/hal_stm32_dma2d.c new file mode 100644 index 0000000..aba029f --- /dev/null +++ b/os/hal/ports/STM32/LLD/DMA2Dv1/hal_stm32_dma2d.c @@ -0,0 +1,3130 @@ +/* + Copyright (C) 2013-2015 Andrea Zoppi + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file stm32_dma2d.c + * @brief DMA2D/Chrom-ART driver. + */ + +#include "ch.h" +#include "hal.h" + +#include "hal_stm32_dma2d.h" + +#if STM32_DMA2D_USE_DMA2D || defined(__DOXYGEN__) + +/* Ignore annoying warning messages for actually safe code.*/ +#if defined(__GNUC__) && !defined(__DOXYGEN__) +#pragma GCC diagnostic ignored "-Wtype-limits" +#endif + +/** + * @addtogroup dma2d + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief DMA2DD1 driver identifier.*/ +DMA2DDriver DMA2DD1; + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/** + * @brief Bits per pixel lookup table. + */ +static const uint8_t dma2d_bpp[DMA2D_MAX_PIXFMT_ID + 1] = { + 32, /* DMA2D_FMT_ARGB8888 */ + 24, /* DMA2D_FMT_RGB888 */ + 16, /* DMA2D_FMT_RGB565 */ + 16, /* DMA2D_FMT_ARGB1555 */ + 16, /* DMA2D_FMT_ARGB4444 */ + 8, /* DMA2D_FMT_L8 */ + 8, /* DMA2D_FMT_AL44 */ + 16, /* DMA2D_FMT_AL88 */ + 4, /* DMA2D_FMT_L4 */ + 8, /* DMA2D_FMT_A8 */ + 4 /* DMA2D_FMT_A4 */ +}; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @name DMA2D interrupt handlers + * @{ + */ + +/** + * @brief DMA2D global interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA2D_HANDLER) { + + DMA2DDriver *const dma2dp = &DMA2DD1; + bool job_done = false; + thread_t *tp = NULL; + + OSAL_IRQ_PROLOGUE(); + + /* Handle Configuration Error ISR.*/ + if ((DMA2D->ISR & DMA2D_ISR_CEIF) && (DMA2D->CR & DMA2D_CR_CEIE)) { + if (dma2dp->config->cfgerr_isr != NULL) + dma2dp->config->cfgerr_isr(dma2dp); + job_done = true; + DMA2D->IFCR |= DMA2D_IFSR_CCEIF; + } + + /* Handle CLUT (Palette) Transfer Complete ISR.*/ + if ((DMA2D->ISR & DMA2D_ISR_CTCIF) && (DMA2D->CR & DMA2D_CR_CTCIE)) { + if (dma2dp->config->paltrfdone_isr != NULL) + dma2dp->config->paltrfdone_isr(dma2dp); + job_done = true; + DMA2D->IFCR |= DMA2D_IFSR_CCTCIF; + } + + /* Handle CLUT (Palette) Access Error ISR.*/ + if ((DMA2D->ISR & DMA2D_ISR_CAEIF) && (DMA2D->CR & DMA2D_CR_CAEIE)) { + if (dma2dp->config->palacserr_isr != NULL) + dma2dp->config->palacserr_isr(dma2dp); + job_done = true; + DMA2D->IFCR |= DMA2D_IFSR_CCAEIF; + } + + /* Handle Transfer Watermark ISR.*/ + if ((DMA2D->ISR & DMA2D_ISR_TWIF) && (DMA2D->CR & DMA2D_CR_TWIE)) { + if (dma2dp->config->trfwmark_isr != NULL) + dma2dp->config->trfwmark_isr(dma2dp); + DMA2D->IFCR |= DMA2D_IFSR_CTWIF; + } + + /* Handle Transfer Complete ISR.*/ + if ((DMA2D->ISR & DMA2D_ISR_TCIF) && (DMA2D->CR & DMA2D_CR_TCIE)) { + if (dma2dp->config->trfdone_isr != NULL) + dma2dp->config->trfdone_isr(dma2dp); + job_done = true; + DMA2D->IFCR |= DMA2D_IFSR_CTCIF; + } + + /* Handle Transfer Error ISR.*/ + if ((DMA2D->ISR & DMA2D_ISR_TEIF) && (DMA2D->CR & DMA2D_CR_TEIE)) { + if (dma2dp->config->trferr_isr != NULL) + dma2dp->config->trferr_isr(dma2dp); + job_done = true; + DMA2D->IFCR |= DMA2D_IFSR_CTEIF; + } + + if (job_done) { + osalSysLockFromISR(); + osalDbgAssert(dma2dp->state == DMA2D_ACTIVE, "invalid state"); + + #if DMA2D_USE_WAIT + /* Wake the waiting thread up.*/ + if (dma2dp->thread != NULL) { + tp = dma2dp->thread; + dma2dp->thread = NULL; + tp->u.rdymsg = MSG_OK; + chSchReadyI(tp); + } + #endif /* DMA2D_USE_WAIT */ + + dma2dp->state = DMA2D_READY; + osalSysUnlockFromISR(); + } + + OSAL_IRQ_EPILOGUE(); +} + +/** @} */ + +/** + * @name DMA2D driver-specific methods + * @{ + */ + +/** + * @brief DMA2D Driver initialization. + * @details Initializes the DMA2D subsystem and chosen drivers. Should be + * called at board initialization. + * + * @init + */ +void dma2dInit(void) { + + /* Reset the DMA2D hardware module.*/ + rccResetDMA2D(); + + /* Enable the DMA2D clock.*/ + rccEnableDMA2D(false); + + /* Driver struct initialization.*/ + dma2dObjectInit(&DMA2DD1); + DMA2DD1.state = DMA2D_STOP; +} + +/** + * @brief Initializes the standard part of a @p DMA2DDriver structure. + * + * @param[out] dma2dp pointer to the @p DMA2DDriver object + * + * @init + */ +void dma2dObjectInit(DMA2DDriver *dma2dp) { + + osalDbgCheck(dma2dp == &DMA2DD1); + + dma2dp->state = DMA2D_UNINIT; + dma2dp->config = NULL; +#if DMA2D_USE_WAIT + dma2dp->thread = NULL; +#endif /* DMA2D_USE_WAIT */ +#if (TRUE == DMA2D_USE_MUTUAL_EXCLUSION) +#if (TRUE == CH_CFG_USE_MUTEXES) + chMtxObjectInit(&dma2dp->lock); +#else + chSemObjectInit(&dma2dp->lock, 1); +#endif +#endif /* (TRUE == DMA2D_USE_MUTUAL_EXCLUSION) */ +} + +/** + * @brief Get the driver state. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @retun driver state + * + * @iclass + */ +dma2d_state_t dma2dGetStateI(DMA2DDriver *dma2dp) { + + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgCheckClassI(); + + return dma2dp->state; +} + +/** + * @brief Get the driver state. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @retun driver state + * + * @api + */ +dma2d_state_t dma2dGetState(DMA2DDriver *dma2dp) { + + dma2d_state_t state; + chSysLock(); + state = dma2dGetStateI(dma2dp); + chSysUnlock(); + return state; +} + +/** + * @brief Configures and activates the DMA2D peripheral. + * @pre DMA2D is stopped. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] configp pointer to the @p DMA2DConfig object + * + * @api + */ +void dma2dStart(DMA2DDriver *dma2dp, const DMA2DConfig *configp) { + + chSysLock(); + + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgCheck(configp != NULL); + osalDbgAssert(dma2dp->state == DMA2D_STOP, "invalid state"); + + dma2dp->config = configp; + + /* Turn off the controller and its interrupts.*/ + DMA2D->CR = 0; + + /* Enable interrupts, except Line Watermark.*/ + nvicEnableVector(STM32_DMA2D_NUMBER, STM32_DMA2D_IRQ_PRIORITY); + + DMA2D->CR = (DMA2D_CR_CEIE | DMA2D_CR_CTCIE | DMA2D_CR_CAEIE | + DMA2D_CR_TCIE | DMA2D_CR_TEIE); + + dma2dp->state = DMA2D_READY; + chSysUnlock(); +} + +/** + * @brief Deactivates the DMA2D peripheral. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @api + */ +void dma2dStop(DMA2DDriver *dma2dp) { + + chSysLock(); + + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "invalid state"); +#if DMA2D_USE_WAIT + osalDbgAssert(dma2dp->thread == NULL, "still waiting"); +#endif /* DMA2D_USE_WAIT */ + + dma2dp->state = DMA2D_STOP; + chSysUnlock(); +} + +#if DMA2D_USE_MUTUAL_EXCLUSION + +/** + * @brief Gains exclusive access to the DMA2D module. + * @details This function tries to gain ownership to the DMA2D module, if the + * module is already being used then the invoking thread is queued. + * @pre In order to use this function the option + * @p DMA2D_USE_MUTUAL_EXCLUSION must be enabled. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @sclass + */ +void dma2dAcquireBusS(DMA2DDriver *dma2dp) { + + osalDbgCheckClassS(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + +#if (TRUE == CH_CFG_USE_MUTEXES) + chMtxLockS(&dma2dp->lock); +#else + chSemWaitS(&dma2dp->lock); +#endif +} + +/** + * @brief Gains exclusive access to the DMA2D module. + * @details This function tries to gain ownership to the DMA2D module, if the + * module is already being used then the invoking thread is queued. + * @pre In order to use this function the option + * @p DMA2D_USE_MUTUAL_EXCLUSION must be enabled. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @api + */ +void dma2dAcquireBus(DMA2DDriver *dma2dp) { + + chSysLock(); + dma2dAcquireBusS(dma2dp); + chSysUnlock(); +} + +/** + * @brief Releases exclusive access to the DMA2D module. + * @pre In order to use this function the option + * @p DMA2D_USE_MUTUAL_EXCLUSION must be enabled. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @sclass + */ +void dma2dReleaseBusS(DMA2DDriver *dma2dp) { + + osalDbgCheckClassS(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + +#if (TRUE == CH_CFG_USE_MUTEXES) + chMtxUnlockS(&dma2dp->lock); +#else + chSemSignalI(&dma2dp->lock); +#endif +} + +/** + * @brief Releases exclusive access to the DMA2D module. + * @pre In order to use this function the option + * @p DMA2D_USE_MUTUAL_EXCLUSION must be enabled. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @api + */ +void dma2dReleaseBus(DMA2DDriver *dma2dp) { + + chSysLock(); + dma2dReleaseBusS(dma2dp); + chSysUnlock(); +} + +#endif /* DMA2D_USE_MUTUAL_EXCLUSION */ + +/** @} */ + +/** + * @name DMA2D global methods + * @{ + */ + +/** + * @brief Get watermark position. + * @details Gets the watermark line position. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return watermark line position + * + * @iclass + */ +uint16_t dma2dGetWatermarkPosI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (uint16_t)(DMA2D->LWR & DMA2D_LWR_LW); +} + +/** + * @brief Get watermark position. + * @details Gets the watermark line position. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return watermark line position + * + * @api + */ +uint16_t dma2dGetWatermarkPos(DMA2DDriver *dma2dp) { + + uint16_t line; + chSysLock(); + line = dma2dGetWatermarkPosI(dma2dp); + chSysUnlock(); + return line; +} + +/** + * @brief Set watermark position. + * @details Sets the watermark line position. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] line watermark line position + * + * @iclass + */ +void dma2dSetWatermarkPosI(DMA2DDriver *dma2dp, uint16_t line) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + (void)dma2dp; + + DMA2D->LWR = ((DMA2D->LWR & ~DMA2D_LWR_LW) | + ((uint32_t)line & DMA2D_LWR_LW)); +} + +/** + * @brief Set watermark position. + * @details Sets the watermark line position. + * @note The interrupt is invoked after the last pixel of the watermark line + * is written. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] line watermark line position + * + * @iclass + */ +void dma2dSetWatermarkPos(DMA2DDriver *dma2dp, uint16_t line) { + + chSysLock(); + dma2dSetWatermarkPosI(dma2dp, line); + chSysUnlock(); +} + +/** + * @brief Watermark interrupt enabled. + * @details Tells whether the watermark interrupt is enabled. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return enabled + * + * @iclass + */ +bool dma2dIsWatermarkEnabledI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (DMA2D->CR & DMA2D_CR_TWIE) != 0; +} + +/** + * @brief Watermark interrupt enabled. + * @details Tells whether the watermark interrupt is enabled. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return enabled + * + * @api + */ +bool dma2dIsWatermarkEnabled(DMA2DDriver *dma2dp) { + + bool enabled; + chSysLock(); + enabled = dma2dIsWatermarkEnabledI(dma2dp); + chSysUnlock(); + return enabled; +} + +/** + * @brief Enable watermark interrupt. + * @details Enables the watermark interrupt. The interrupt is invoked after the + * last pixel of the watermark line is written to the output layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @iclass + */ +void dma2dEnableWatermarkI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + DMA2D->CR |= DMA2D_CR_TWIE; +} + +/** + * @brief Enable watermark interrupt. + * @details Enables the watermark interrupt. The interrupt is invoked after the + * last pixel of the watermark line is written to the output layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @api + */ +void dma2dEnableWatermark(DMA2DDriver *dma2dp) { + + chSysLock(); + dma2dEnableWatermarkI(dma2dp); + chSysUnlock(); +} + +/** + * @brief Disable watermark interrupt. + * @details Disables the watermark interrupt. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @iclass + */ +void dma2dDisableWatermarkI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + DMA2D->CR &= ~DMA2D_CR_TWIE; +} + +/** + * @brief Disable watermark interrupt. + * @details Disables the watermark interrupt. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @api + */ +void dma2dDisableWatermark(DMA2DDriver *dma2dp) { + + chSysLock(); + dma2dDisableWatermarkI(dma2dp); + chSysUnlock(); +} + +/** + * @brief Get dead time cycles. + * @details Gets the minimum dead time DMA2D clock cycles between DMA2D + * transactions. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return dead time, in DMA2D clock cycles + * + * @iclass + */ +uint32_t dma2dGetDeadTimeI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (DMA2D->AMTCR & DMA2D_AMTCR_DT) >> 8; +} + +/** + * @brief Get dead time cycles. + * @details Gets the minimum dead time DMA2D clock cycles between DMA2D + * transactions. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return dead time, in DMA2D clock cycles + * + * @api + */ +uint32_t dma2dGetDeadTime(DMA2DDriver *dma2dp) { + + uint32_t cycles; + chSysLock(); + cycles = dma2dGetDeadTimeI(dma2dp); + chSysUnlock(); + return cycles; +} + +/** + * @brief Set dead time cycles. + * @details Sets the minimum dead time DMA2D clock cycles between DMA2D + * transactions. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] cycles dead time, in DMA2D clock cycles + * + * @iclass + */ +void dma2dSetDeadTimeI(DMA2DDriver *dma2dp, uint32_t cycles) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(cycles <= DMA2D_MAX_DEADTIME_CYCLES, "bounds"); + (void)dma2dp; + + DMA2D->AMTCR = ((DMA2D->AMTCR & ~DMA2D_AMTCR_DT) | + ((cycles << 8) & DMA2D_AMTCR_DT)); +} + +/** + * @brief Set dead time cycles. + * @details Sets the minimum dead time DMA2D clock cycles between DMA2D + * transactions. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] cycles dead time, in DMA2D clock cycles + * + * @api + */ +void dma2dSetDeadTime(DMA2DDriver *dma2dp, uint32_t cycles) { + + chSysLock(); + dma2dSetDeadTimeI(dma2dp, cycles); + chSysUnlock(); +} + +/** + * @brief Dead time enabled. + * @details Tells whether the dead time between DMA2D transactions is enabled. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return enabled + * + * @iclass + */ +bool dma2dIsDeadTimeEnabledI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (DMA2D->AMTCR & DMA2D_AMTCR_EN) != 0; +} + +/** + * @brief Dead time enabled. + * @details Tells whether the dead time between DMA2D transactions is enabled. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return enabled + * + * @api + */ +bool dma2dIsDeadTimeEnabled(DMA2DDriver *dma2dp) { + + bool enabled; + chSysLock(); + enabled = dma2dIsDeadTimeEnabledI(dma2dp); + chSysUnlock(); + return enabled; +} + +/** + * @brief Enable dead time. + * @details Enables the dead time between DMA2D transactions. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @iclass + */ +void dma2dEnableDeadTimeI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + DMA2D->AMTCR |= DMA2D_AMTCR_EN; +} + +/** + * @brief Enable dead time. + * @details Enables the dead time between DMA2D transactions. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @api + */ +void dma2dEnableDeadTime(DMA2DDriver *dma2dp) { + + chSysLock(); + dma2dEnableDeadTimeI(dma2dp); + chSysUnlock(); +} + +/** + * @brief Disable dead time. + * @details Disables the dead time between DMA2D transactions. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @iclass + */ +void dma2dDisableDeadTimeI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + DMA2D->AMTCR &= ~DMA2D_AMTCR_EN; +} + +/** + * @brief Disable dead time. + * @details Disables the dead time between DMA2D transactions. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @api + */ +void dma2dDisableDeadTime(DMA2DDriver *dma2dp) { + + chSysLock(); + dma2dDisableDeadTimeI(dma2dp); + chSysUnlock(); +} + +/** @} */ + +/** + * @name DMA2D job (transaction) methods + * @{ + */ + +/** + * @brief Get job mode. + * @details Gets the job mode. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return job mode + * + * @iclass + */ +dma2d_jobmode_t dma2dJobGetModeI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (dma2d_jobmode_t)(DMA2D->CR & DMA2D_CR_MODE); +} + +/** + * @brief Get job mode. + * @details Gets the job mode. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return job mode + * + * @api + */ +dma2d_jobmode_t dma2dJobGetMode(DMA2DDriver *dma2dp) { + + dma2d_jobmode_t mode; + chSysLock(); + mode = dma2dJobGetModeI(dma2dp); + chSysUnlock(); + return mode; +} + +/** + * @brief Set job mode. + * @details Sets the job mode. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] mode job mode + * + * @iclass + */ +void dma2dJobSetModeI(DMA2DDriver *dma2dp, dma2d_jobmode_t mode) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgAssert((mode & ~DMA2D_CR_MODE) == 0, "bounds"); + (void)dma2dp; + + DMA2D->CR = ((DMA2D->CR & ~DMA2D_CR_MODE) | + ((uint32_t)mode & DMA2D_CR_MODE)); +} + +/** + * @brief Set job mode. + * @details Sets the job mode. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] mode job mode + * + * @api + */ +void dma2dJobSetMode(DMA2DDriver *dma2dp, dma2d_jobmode_t mode) { + + chSysLock(); + dma2dJobSetModeI(dma2dp, mode); + chSysUnlock(); +} + +/** + * @brief Get job size. + * @details Gets the job size. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[out] widthp pointer to the job width, in pixels + * @param[out] heightp pointer to the job height, in pixels + * + * @iclass + */ +void dma2dJobGetSizeI(DMA2DDriver *dma2dp, + uint16_t *widthp, uint16_t *heightp) { + + uint32_t r; + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgCheck(widthp != NULL); + osalDbgCheck(heightp != NULL); + (void)dma2dp; + + r = DMA2D->NLR; + *widthp = (uint16_t)((r & DMA2D_NLR_PL) >> 16); + *heightp = (uint16_t)((r & DMA2D_NLR_NL) >> 0); +} + +/** + * @brief Get job size. + * @details Gets the job size. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[out] widthp pointer to the job width, in pixels + * @param[out] heightp pointer to the job height, in pixels + * + * @api + */ +void dma2dJobGetSize(DMA2DDriver *dma2dp, + uint16_t *widthp, uint16_t *heightp) { + + chSysLock(); + dma2dJobGetSizeI(dma2dp, widthp, heightp); + chSysUnlock(); +} + +/** + * @brief Set job size. + * @details Sets the job size. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] widthp job width, in pixels + * @param[in] heightp job height, in pixels + * + * @iclass + */ +void dma2dJobSetSizeI(DMA2DDriver *dma2dp, uint16_t width, uint16_t height) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgAssert(width <= DMA2D_MAX_WIDTH, "bounds"); + osalDbgAssert(height <= DMA2D_MAX_HEIGHT, "bounds"); + (void)dma2dp; + + DMA2D->NLR = ((((uint32_t)width << 16) & DMA2D_NLR_PL) | + (((uint32_t)height << 0) & DMA2D_NLR_NL)); +} + +/** + * @brief Set job size. + * @details Sets the job size. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] widthp job width, in pixels + * @param[in] heightp job height, in pixels + * + * @api + */ +void dma2dJobSetSize(DMA2DDriver *dma2dp, uint16_t width, uint16_t height) { + + chSysLock(); + dma2dJobSetSizeI(dma2dp, width, height); + chSysUnlock(); +} + +/** + * @brief Job executing. + * @details Tells whether a job (transaction) is active or paused. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return executing + * + * @iclass + */ +bool dma2dJobIsExecutingI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + + return dma2dp->state > DMA2D_READY; +} + +/** + * @brief Job executing. + * @details Tells whether a job (transaction) is active or paused. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return executing + * + * @api + */ +bool dma2dJobIsExecuting(DMA2DDriver *dma2dp) { + + bool executing; + chSysLock(); + executing = dma2dJobIsExecutingI(dma2dp); + chSysUnlock(); + return executing; +} + +/** + * @brief Start job. + * @details The job is started, and the DMA2D is set to active. + * @note Should there be invalid parameters, the appropriate interrupt + * handler will be invoked, and the DMA2D set back to ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @iclass + */ +void dma2dJobStartI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + + dma2dp->state = DMA2D_ACTIVE; + DMA2D->CR |= DMA2D_CR_START; +} + +/** + * @brief Start job. + * @details The job is started, and the DMA2D is set to active. + * @note Should there be invalid parameters, the appropriate interrupt + * handler will be invoked, and the DMA2D set back to ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @api + */ +void dma2dJobStart(DMA2DDriver *dma2dp) { + + chSysLock(); + dma2dJobStartI(dma2dp); + chSysUnlock(); +} + +/** + * @brief Execute job. + * @details Starts the job and waits for its completion, synchronously. + * @note Should there be invalid parameters, the appropriate interrupt + * handler will be invoked, and the DMA2D set back to ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @sclass + */ +void dma2dJobExecuteS(DMA2DDriver *dma2dp) { + + osalDbgCheckClassS(); + osalDbgCheck(dma2dp == &DMA2DD1); + + dma2dJobStartI(dma2dp); +#if DMA2D_USE_WAIT + dma2dp->thread = chThdGetSelfX(); + chSchGoSleepS(CH_STATE_SUSPENDED); +#else + while (DMA2D->CR & DMA2D_CR_START) + chSchDoYieldS(); +#endif +} + +/** + * @brief Execute job. + * @details Starts the job and waits for its completion, synchronously. + * @note Should there be invalid parameters, the appropriate interrupt + * handler will be invoked, and the DMA2D set back to ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @api + */ +void dma2dJobExecute(DMA2DDriver *dma2dp) { + + chSysLock(); + dma2dJobExecuteS(dma2dp); + chSysUnlock(); +} + +/** + * @brief Suspend current job. + * @details Suspends the current job. The driver is set to a paused state. + * @pre There is an active job. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @iclass + */ +void dma2dJobSuspendI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgCheck((DMA2D->CR & DMA2D_CR_SUSP) == 0); + osalDbgAssert(dma2dp->state == DMA2D_ACTIVE, "invalid state"); + + dma2dp->state = DMA2D_PAUSED; + DMA2D->CR |= DMA2D_CR_SUSP; +} + +/** + * @brief Suspend current job. + * @details Suspends the current job. The driver is set to a paused state. + * @pre There is an active job. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @api + */ +void dma2dJobSuspend(DMA2DDriver *dma2dp) { + + chSysLock(); + dma2dJobSuspendI(dma2dp); + chSysUnlock(); +} + +/** + * @brief Resume current job. + * @details Resumes the current job. + * @pre There is a paused job. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @iclass + */ +void dma2dJobResumeI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgCheck((DMA2D->CR & DMA2D_CR_SUSP) != 0); + osalDbgAssert(dma2dp->state == DMA2D_PAUSED, "invalid state"); + + dma2dp->state = DMA2D_ACTIVE; + DMA2D->CR &= ~DMA2D_CR_SUSP; +} + +/** + * @brief Resume current job. + * @details Resumes the current job. + * @pre There is a paused job. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @api + */ +void dma2dJobResume(DMA2DDriver *dma2dp) { + + chSysLock(); + dma2dJobResumeI(dma2dp); + chSysUnlock(); +} + +/** + * @brief Abort current job. + * @details Abots the current job (if any), and the driver becomes ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @iclass + */ +void dma2dJobAbortI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgCheck((DMA2D->CR & DMA2D_CR_SUSP) == 0); + osalDbgAssert(dma2dp->state >= DMA2D_READY, "invalid state"); + + dma2dp->state = DMA2D_READY; + DMA2D->CR |= DMA2D_CR_ABORT; +} + +/** + * @brief Abort current job. + * @details Abots the current job (if any), and the driver becomes ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @api + */ +void dma2dJobAbort(DMA2DDriver *dma2dp) { + + chSysLock(); + dma2dJobAbortI(dma2dp); + chSysUnlock(); +} + +/** @} */ + +/** + * @name DMA2D background layer methods + * @{ + */ + +/** + * @brief Get background layer buffer address. + * @details Gets the buffer address of the background layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return buffer address + * + * @iclass + */ +void *dma2dBgGetAddressI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (void *)DMA2D->BGMAR; +} + +/** + * @brief Get background layer buffer address. + * @details Gets the buffer address of the background layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return buffer address + * + * @api + */ +void *dma2dBgGetAddress(DMA2DDriver *dma2dp) { + + void *bufferp; + chSysLock(); + bufferp = dma2dBgGetAddressI(dma2dp); + chSysUnlock(); + return bufferp; +} + +/** + * @brief Set background layer buffer address. + * @details Sets the buffer address of the background layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] bufferp buffer address + * + * @iclass + */ +void dma2dBgSetAddressI(DMA2DDriver *dma2dp, void *bufferp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgCheck(dma2dIsAligned(bufferp, dma2dBgGetPixelFormatI(dma2dp))); + (void)dma2dp; + + DMA2D->BGMAR = (uint32_t)bufferp; +} + +/** + * @brief Set background layer buffer address. + * @details Sets the buffer address of the background layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] bufferp buffer address + * + * @api + */ +void dma2dBgSetAddress(DMA2DDriver *dma2dp, void *bufferp) { + + chSysLock(); + dma2dBgSetAddressI(dma2dp, bufferp); + chSysUnlock(); +} + +/** + * @brief Get background layer wrap offset. + * @details Gets the buffer line wrap offset of the background layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return wrap offset, in pixels + * + * @iclass + */ +size_t dma2dBgGetWrapOffsetI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (size_t)(DMA2D->BGOR & DMA2D_BGOR_LO); +} + +/** + * @brief Get background layer wrap offset. + * @details Gets the buffer line wrap offset of the background layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return wrap offset, in pixels + * + * @api + */ +size_t dma2dBgGetWrapOffset(DMA2DDriver *dma2dp) { + + size_t offset; + chSysLock(); + offset = dma2dBgGetWrapOffsetI(dma2dp); + chSysUnlock(); + return offset; +} + +/** + * @brief Set background layer wrap offset. + * @details Sets the buffer line wrap offset of the background layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] offset wrap offset, in pixels + * + * @iclass + */ +void dma2dBgSetWrapOffsetI(DMA2DDriver *dma2dp, size_t offset) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgAssert(offset <= DMA2D_MAX_OFFSET, "bounds"); + (void)dma2dp; + + DMA2D->BGOR = ((DMA2D->BGOR & ~DMA2D_BGOR_LO) | + ((uint32_t)offset & DMA2D_BGOR_LO)); +} + +/** + * @brief Set background layer wrap offset. + * @details Sets the buffer line wrap offset of the background layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] offset wrap offset, in pixels + * + * @api + */ +void dma2dBgSetWrapOffset(DMA2DDriver *dma2dp, size_t offset) { + + chSysLock(); + dma2dBgSetWrapOffsetI(dma2dp, offset); + chSysUnlock(); +} + +/** + * @brief Get background layer constant alpha. + * @details Gets the constant alpha component of the background layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return constant alpha component, A-8 + * + * @iclass + */ +uint8_t dma2dBgGetConstantAlphaI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (uint8_t)((DMA2D->BGPFCCR & DMA2D_BGPFCCR_ALPHA) >> 24); +} + +/** + * @brief Get background layer constant alpha. + * @details Gets the constant alpha component of the background layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return constant alpha component, A-8 + * + * @api + */ +uint8_t dma2dBgGetConstantAlpha(DMA2DDriver *dma2dp) { + + uint8_t a; + chSysLock(); + a = dma2dBgGetConstantAlphaI(dma2dp); + chSysUnlock(); + return a; +} + +/** + * @brief Set background layer constant alpha. + * @details Sets the constant alpha component of the background layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] a constant alpha component, A-8 + * + * @iclass + */ +void dma2dBgSetConstantAlphaI(DMA2DDriver *dma2dp, uint8_t a) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + (void)dma2dp; + + DMA2D->BGPFCCR = ((DMA2D->BGPFCCR & ~DMA2D_BGPFCCR_ALPHA) | + (((uint32_t)a << 24) & DMA2D_BGPFCCR_ALPHA)); +} + +/** + * @brief Set background layer constant alpha. + * @details Sets the constant alpha component of the background layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] a constant alpha component, A-8 + * + * @api + */ +void dma2dBgSetConstantAlpha(DMA2DDriver *dma2dp, uint8_t a) { + + chSysLock(); + dma2dBgSetConstantAlphaI(dma2dp, a); + chSysUnlock(); +} + +/** + * @brief Get background layer alpha mode. + * @details Gets the alpha mode of the background layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return alpha mode + * + * @iclass + */ +dma2d_amode_t dma2dBgGetAlphaModeI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (dma2d_amode_t)(DMA2D->BGPFCCR & DMA2D_BGPFCCR_AM); +} + +/** + * @brief Get background layer alpha mode. + * @details Gets the alpha mode of the background layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return alpha mode + * + * @api + */ +dma2d_amode_t dma2dBgGetAlphaMode(DMA2DDriver *dma2dp) { + + dma2d_amode_t mode; + chSysLock(); + mode = dma2dBgGetAlphaModeI(dma2dp); + chSysUnlock(); + return mode; +} + +/** + * @brief Set background layer alpha mode. + * @details Sets the alpha mode of the background layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] mode alpha mode + * + * @iclass + */ +void dma2dBgSetAlphaModeI(DMA2DDriver *dma2dp, dma2d_amode_t mode) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgAssert((mode & ~DMA2D_BGPFCCR_AM) == 0, "bounds"); + osalDbgAssert((mode & DMA2D_BGPFCCR_AM) != DMA2D_BGPFCCR_AM, "bounds"); + (void)dma2dp; + + DMA2D->BGPFCCR = ((DMA2D->BGPFCCR & ~DMA2D_BGPFCCR_AM) | + ((uint32_t)mode & DMA2D_BGPFCCR_AM)); +} + +/** + * @brief Set background layer alpha mode. + * @details Sets the alpha mode of the background layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] mode alpha mode + * + * @api + */ +void dma2dBgSetAlphaMode(DMA2DDriver *dma2dp, dma2d_amode_t mode) { + + chSysLock(); + dma2dBgSetAlphaModeI(dma2dp, mode); + chSysUnlock(); +} + +/** + * @brief Get background layer pixel format. + * @details Gets the pixel format of the background layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return pixel format + * + * @iclass + */ +dma2d_pixfmt_t dma2dBgGetPixelFormatI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (dma2d_pixfmt_t)(DMA2D->BGPFCCR & DMA2D_BGPFCCR_CM); +} + +/** + * @brief Get background layer pixel format. + * @details Gets the pixel format of the background layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return pixel format + * + * @api + */ +dma2d_pixfmt_t dma2dBgGetPixelFormat(DMA2DDriver *dma2dp) { + + dma2d_pixfmt_t fmt; + chSysLock(); + fmt = dma2dBgGetPixelFormatI(dma2dp); + chSysUnlock(); + return fmt; +} + +/** + * @brief Set background layer pixel format. + * @details Sets the pixel format of the background layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] fmt pixel format + * + * @iclass + */ +void dma2dBgSetPixelFormatI(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgAssert(fmt <= DMA2D_MAX_PIXFMT_ID, "bounds"); + (void)dma2dp; + + DMA2D->BGPFCCR = ((DMA2D->BGPFCCR & ~DMA2D_BGPFCCR_CM) | + ((uint32_t)fmt & DMA2D_BGPFCCR_CM)); +} + +/** + * @brief Set background layer pixel format. + * @details Sets the pixel format of the background layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] fmt pixel format + * + * @api + */ +void dma2dBgSetPixelFormat(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt) { + + chSysLock(); + dma2dBgSetPixelFormatI(dma2dp, fmt); + chSysUnlock(); +} + +/** + * @brief Get background layer default color. + * @details Gets the default color of the background layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return default color, RGB-888 + * + * @iclass + */ +dma2d_color_t dma2dBgGetDefaultColorI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (dma2d_color_t)(DMA2D->BGCOLR & 0x00FFFFFF); +} + +/** + * @brief Get background layer default color. + * @details Gets the default color of the background layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return default color, RGB-888 + * + * @api + */ +dma2d_color_t dma2dBgGetDefaultColor(DMA2DDriver *dma2dp) { + + dma2d_color_t c; + chSysLock(); + c = dma2dBgGetDefaultColorI(dma2dp); + chSysUnlock(); + return c; +} + +/** + * @brief Set background layer default color. + * @details Sets the default color of the background layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] c default color, RGB-888 + * + * @iclass + */ +void dma2dBgSetDefaultColorI(DMA2DDriver *dma2dp, dma2d_color_t c) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + (void)dma2dp; + + DMA2D->BGCOLR = (uint32_t)c & 0x00FFFFFF; +} + +/** + * @brief Set background layer default color. + * @details Sets the default color of the background layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] c default color, RGB-888 + * + * @api + */ +void dma2dBgSetDefaultColor(DMA2DDriver *dma2dp, dma2d_color_t c) { + + chSysLock(); + dma2dBgSetDefaultColorI(dma2dp, c); + chSysUnlock(); +} + +/** + * @brief Get background layer palette specifications. + * @details Gets the palette specifications of the background layer. + * @note The palette colors pointer is actually addressed to a @p volatile + * memory zone. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[out] palettep pointer to the palette specifications + * + * @iclass + */ +void dma2dBgGetPaletteI(DMA2DDriver *dma2dp, dma2d_palcfg_t *palettep) { + + uint32_t r; + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgCheck(palettep != NULL); + (void)dma2dp; + + r = DMA2D->BGPFCCR; + palettep->colorsp = (const void *)DMA2D->BGCLUT; + palettep->length = (uint16_t)((r & DMA2D_BGPFCCR_CS) >> 8) + 1; + palettep->fmt = (dma2d_pixfmt_t)((r & DMA2D_BGPFCCR_CCM) >> 4); +} + +/** + * @brief Get background layer palette specifications. + * @details Gets the palette specifications of the background layer. + * @note The palette colors pointer is actually addressed to a @p volatile + * memory zone. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[out] palettep pointer to the palette specifications + * + * @api + */ +void dma2dBgGetPalette(DMA2DDriver *dma2dp, dma2d_palcfg_t *palettep) { + + chSysLock(); + dma2dBgGetPaletteI(dma2dp, palettep); + chSysUnlock(); +} + +/** + * @brief Set background layer palette specifications. + * @details Sets the palette specifications of the background layer. + * @note This function should not be called while the DMA2D is already + * executing a job, otherwise the appropriate error interrupt might be + * invoked. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] palettep pointer to the palette specifications + * + * @sclass + */ +void dma2dBgSetPaletteS(DMA2DDriver *dma2dp, const dma2d_palcfg_t *palettep) { + + osalDbgCheckClassS(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgCheck(palettep != NULL); + osalDbgCheck(palettep->colorsp != NULL); + osalDbgAssert(palettep->length > 0, "bounds"); + osalDbgAssert(palettep->length <= DMA2D_MAX_PALETTE_LENGTH, "bounds"); + osalDbgAssert(((palettep->fmt == DMA2D_FMT_ARGB8888) || + (palettep->fmt == DMA2D_FMT_RGB888)), "invalid format"); + + DMA2D->BGCMAR = (uint32_t)palettep->colorsp; + DMA2D->BGPFCCR = ( + (DMA2D->BGPFCCR & ~(DMA2D_BGPFCCR_CS | DMA2D_BGPFCCR_CCM)) | + ((((uint32_t)palettep->length - 1) << 8) & DMA2D_BGPFCCR_CS) | + ((uint32_t)palettep->fmt << 4) + ); + + dma2dp->state = DMA2D_ACTIVE; + DMA2D->BGPFCCR |= DMA2D_BGPFCCR_START; + +#if DMA2D_USE_WAIT + dma2dp->thread = chThdGetSelfX(); + chSchGoSleepS(CH_STATE_SUSPENDED); +#else + while (DMA2D->BGPFCCR & DMA2D_BGPFCCR_START) + chSchDoYieldS(); +#endif /* DMA2D_USE_WAIT */ +} + +/** + * @brief Set background layer palette specifications. + * @details Sets the palette specifications of the background layer. + * @note This function should not be called while the DMA2D is already + * executing a job, otherwise the appropriate error interrupt might be + * invoked. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] palettep pointer to the palette specifications + * + * @api + */ +void dma2dBgSetPalette(DMA2DDriver *dma2dp, const dma2d_palcfg_t *palettep) { + + chSysLock(); + dma2dBgSetPaletteS(dma2dp, palettep); + chSysUnlock(); +} + +/** + * @brief Get background layer specifications. + * @details Gets the background layer specifications at once. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[out] cfgp pointer to the layer specifications + * + * @iclass + */ +void dma2dBgGetLayerI(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgCheck(cfgp != NULL); + + cfgp->bufferp = dma2dBgGetAddressI(dma2dp); + cfgp->wrap_offset = dma2dBgGetWrapOffsetI(dma2dp); + cfgp->fmt = dma2dBgGetPixelFormatI(dma2dp); + cfgp->def_color = dma2dBgGetDefaultColorI(dma2dp); + cfgp->const_alpha = dma2dBgGetConstantAlphaI(dma2dp); + if (cfgp->palettep != NULL) + dma2dBgGetPaletteI(dma2dp, (dma2d_palcfg_t *)cfgp->palettep); +} + +/** + * @brief Get background layer specifications. + * @details Gets the background layer specifications at once. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[out] cfgp pointer to the layer specifications + * + * @api + */ +void dma2dBgGetLayer(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp) { + + chSysLock(); + dma2dBgGetLayerI(dma2dp, cfgp); + chSysUnlock(); +} + +/** + * @brief Set background layer specifications. + * @details Sets the background layer specifications at once. + * @note If the palette is unspecified, the layer palette is unmodified. + * @note This function should not be called while the DMA2D is already + * executing a job, otherwise the appropriate error interrupt might be + * invoked. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] cfgp pointer to the layer specifications + * + * @sclass + */ +void dma2dBgSetConfigS(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp) { + + osalDbgCheckClassS(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgCheck(cfgp != NULL); + + dma2dBgSetAddressI(dma2dp, cfgp->bufferp); + dma2dBgSetWrapOffsetI(dma2dp, cfgp->wrap_offset); + dma2dBgSetPixelFormatI(dma2dp, cfgp->fmt); + dma2dBgSetDefaultColorI(dma2dp, cfgp->def_color); + dma2dBgSetConstantAlphaI(dma2dp, cfgp->const_alpha); + if (cfgp->palettep != NULL) + dma2dBgSetPaletteS(dma2dp, cfgp->palettep); +} + +/** + * @brief Set background layer specifications. + * @details Sets the background layer specifications at once. + * @note If the palette is unspecified, the layer palette is unmodified. + * @note This function should not be called while the DMA2D is already + * executing a job, otherwise the appropriate error interrupt might be + * invoked. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] cfgp pointer to the layer specifications + * + * @api + */ +void dma2dBgSetConfig(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp) { + + chSysLock(); + dma2dBgSetConfigS(dma2dp, cfgp); + chSysUnlock(); +} + +/** @} */ + +/** + * @name DMA2D foreground layer methods + * @{ + */ + +/** + * @brief Get foreground layer buffer address. + * @details Gets the buffer address of the foreground layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return buffer address + * + * @iclass + */ +void *dma2dFgGetAddressI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (void *)DMA2D->FGMAR; +} + +/** + * @brief Get foreground layer buffer address. + * @details Gets the buffer address of the foreground layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return buffer address + * + * @api + */ +void *dma2dFgGetAddress(DMA2DDriver *dma2dp) { + + void *bufferp; + chSysLock(); + bufferp = dma2dFgGetAddressI(dma2dp); + chSysUnlock(); + return bufferp; +} + +/** + * @brief Set foreground layer buffer address. + * @details Sets the buffer address of the foreground layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] bufferp buffer address + * + * @iclass + */ +void dma2dFgSetAddressI(DMA2DDriver *dma2dp, void *bufferp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgCheck(dma2dIsAligned(bufferp, dma2dFgGetPixelFormatI(dma2dp))); + (void)dma2dp; + + DMA2D->FGMAR = (uint32_t)bufferp; +} + +/** + * @brief Set foreground layer buffer address. + * @details Sets the buffer address of the foreground layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] bufferp buffer address + * + * @api + */ +void dma2dFgSetAddress(DMA2DDriver *dma2dp, void *bufferp) { + + chSysLock(); + dma2dFgSetAddressI(dma2dp, bufferp); + chSysUnlock(); +} + +/** + * @brief Get foreground layer wrap offset. + * @details Gets the buffer line wrap offset of the foreground layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return wrap offset, in pixels + * + * @iclass + */ +size_t dma2dFgGetWrapOffsetI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (size_t)(DMA2D->FGOR & DMA2D_FGOR_LO); +} + +/** + * @brief Get foreground layer wrap offset. + * @details Gets the buffer line wrap offset of the foreground layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return wrap offset, in pixels + * + * @api + */ +size_t dma2dFgGetWrapOffset(DMA2DDriver *dma2dp) { + + size_t offset; + chSysLock(); + offset = dma2dFgGetWrapOffsetI(dma2dp); + chSysUnlock(); + return offset; +} + +/** + * @brief Set foreground layer wrap offset. + * @details Sets the buffer line wrap offset of the foreground layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] offset wrap offset, in pixels + * + * @iclass + */ +void dma2dFgSetWrapOffsetI(DMA2DDriver *dma2dp, size_t offset) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgAssert(offset <= DMA2D_MAX_OFFSET, "bounds"); + (void)dma2dp; + + DMA2D->FGOR = ((DMA2D->FGOR & ~DMA2D_FGOR_LO) | + ((uint32_t)offset & DMA2D_FGOR_LO)); +} + +/** + * @brief Set foreground layer wrap offset. + * @details Sets the buffer line wrap offset of the foreground layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] offset wrap offset, in pixels + * + * @api + */ +void dma2dFgSetWrapOffset(DMA2DDriver *dma2dp, size_t offset) { + + chSysLock(); + dma2dFgSetWrapOffsetI(dma2dp, offset); + chSysUnlock(); +} + +/** + * @brief Get foreground layer constant alpha. + * @details Gets the constant alpha component of the foreground layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return constant alpha component, A-8 + * + * @iclass + */ +uint8_t dma2dFgGetConstantAlphaI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (uint8_t)((DMA2D->FGPFCCR & DMA2D_FGPFCCR_ALPHA) >> 24); +} + +/** + * @brief Get foreground layer constant alpha. + * @details Gets the constant alpha component of the foreground layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return constant alpha component, A-8 + * + * @api + */ +uint8_t dma2dFgGetConstantAlpha(DMA2DDriver *dma2dp) { + + uint8_t a; + chSysLock(); + a = dma2dFgGetConstantAlphaI(dma2dp); + chSysUnlock(); + return a; +} + +/** + * @brief Set foreground layer constant alpha. + * @details Sets the constant alpha component of the foreground layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] a constant alpha component, A-8 + * + * @iclass + */ +void dma2dFgSetConstantAlphaI(DMA2DDriver *dma2dp, uint8_t a) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + (void)dma2dp; + + DMA2D->FGPFCCR = ((DMA2D->FGPFCCR & ~DMA2D_FGPFCCR_ALPHA) | + (((uint32_t)a << 24) & DMA2D_FGPFCCR_ALPHA)); +} + +/** + * @brief Set foreground layer constant alpha. + * @details Sets the constant alpha component of the foreground layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] a constant alpha component, A-8 + * + * @api + */ +void dma2dFgSetConstantAlpha(DMA2DDriver *dma2dp, uint8_t a) { + + chSysLock(); + dma2dFgSetConstantAlphaI(dma2dp, a); + chSysUnlock(); +} + +/** + * @brief Get foreground layer alpha mode. + * @details Gets the alpha mode of the foreground layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return alpha mode + * + * @iclass + */ +dma2d_amode_t dma2dFgGetAlphaModeI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (dma2d_amode_t)(DMA2D->FGPFCCR & DMA2D_FGPFCCR_AM); +} + +/** + * @brief Get foreground layer alpha mode. + * @details Gets the alpha mode of the foreground layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return alpha mode + * + * @api + */ +dma2d_amode_t dma2dFgGetAlphaMode(DMA2DDriver *dma2dp) { + + dma2d_amode_t mode; + chSysLock(); + mode = dma2dFgGetAlphaModeI(dma2dp); + chSysUnlock(); + return mode; +} + +/** + * @brief Set foreground layer alpha mode. + * @details Sets the alpha mode of the foreground layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] mode alpha mode + * + * @iclass + */ +void dma2dFgSetAlphaModeI(DMA2DDriver *dma2dp, dma2d_amode_t mode) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgAssert((mode & ~DMA2D_FGPFCCR_AM) == 0, "bounds"); + osalDbgAssert((mode & DMA2D_FGPFCCR_AM) != DMA2D_FGPFCCR_AM, "bounds"); + (void)dma2dp; + + DMA2D->FGPFCCR = ((DMA2D->FGPFCCR & ~DMA2D_FGPFCCR_AM) | + ((uint32_t)mode & DMA2D_FGPFCCR_AM)); +} + +/** + * @brief Set foreground layer alpha mode. + * @details Sets the alpha mode of the foreground layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] mode alpha mode + * + * @api + */ +void dma2dFgSetAlphaMode(DMA2DDriver *dma2dp, dma2d_amode_t mode) { + + chSysLock(); + dma2dFgSetAlphaModeI(dma2dp, mode); + chSysUnlock(); +} + +/** + * @brief Get foreground layer pixel format. + * @details Gets the pixel format of the foreground layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return pixel format + * + * @iclass + */ +dma2d_pixfmt_t dma2dFgGetPixelFormatI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (dma2d_pixfmt_t)(DMA2D->FGPFCCR & DMA2D_FGPFCCR_CM); +} + +/** + * @brief Get foreground layer pixel format. + * @details Gets the pixel format of the foreground layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return pixel format + * + * @api + */ +dma2d_pixfmt_t dma2dFgGetPixelFormat(DMA2DDriver *dma2dp) { + + dma2d_pixfmt_t fmt; + chSysLock(); + fmt = dma2dFgGetPixelFormatI(dma2dp); + chSysUnlock(); + return fmt; +} + +/** + * @brief Set foreground layer pixel format. + * @details Sets the pixel format of the foreground layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] fmt pixel format + * + * @iclass + */ +void dma2dFgSetPixelFormatI(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgAssert(fmt <= DMA2D_MAX_PIXFMT_ID, "bounds"); + (void)dma2dp; + + DMA2D->FGPFCCR = ((DMA2D->FGPFCCR & ~DMA2D_FGPFCCR_CM) | + ((uint32_t)fmt & DMA2D_FGPFCCR_CM)); +} + +/** + * @brief Set foreground layer pixel format. + * @details Sets the pixel format of the foreground layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] fmt pixel format + * + * @api + */ +void dma2dFgSetPixelFormat(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt) { + + chSysLock(); + dma2dFgSetPixelFormatI(dma2dp, fmt); + chSysUnlock(); +} + +/** + * @brief Get foreground layer default color. + * @details Gets the default color of the foreground layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return default color, RGB-888 + * + * @iclass + */ +dma2d_color_t dma2dFgGetDefaultColorI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (dma2d_color_t)(DMA2D->FGCOLR & 0x00FFFFFF); +} + +/** + * @brief Get foreground layer default color. + * @details Gets the default color of the foreground layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return default color, RGB-888 + * + * @api + */ +dma2d_color_t dma2dFgGetDefaultColor(DMA2DDriver *dma2dp) { + + dma2d_color_t c; + chSysLock(); + c = dma2dFgGetDefaultColorI(dma2dp); + chSysUnlock(); + return c; +} + +/** + * @brief Set foreground layer default color. + * @details Sets the default color of the foreground layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] c default color, RGB-888 + * + * @iclass + */ +void dma2dFgSetDefaultColorI(DMA2DDriver *dma2dp, dma2d_color_t c) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + (void)dma2dp; + + DMA2D->FGCOLR = (uint32_t)c & 0x00FFFFFF; +} + +/** + * @brief Set foreground layer default color. + * @details Sets the default color of the foreground layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] c default color, RGB-888 + * + * @api + */ +void dma2dFgSetDefaultColor(DMA2DDriver *dma2dp, dma2d_color_t c) { + + chSysLock(); + dma2dFgSetDefaultColorI(dma2dp, c); + chSysUnlock(); +} + +/** + * @brief Get foreground layer palette specifications. + * @details Gets the palette specifications of the foreground layer. + * @note The palette colors pointer is actually addressed to a @p volatile + * memory zone. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[out] palettep pointer to the palette specifications + * + * @iclass + */ +void dma2dFgGetPaletteI(DMA2DDriver *dma2dp, dma2d_palcfg_t *palettep) { + + uint32_t r; + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgCheck(palettep != NULL); + (void)dma2dp; + + r = DMA2D->FGPFCCR; + palettep->colorsp = (const void *)DMA2D->FGCLUT; + palettep->length = (uint16_t)((r & DMA2D_FGPFCCR_CS) >> 8) + 1; + palettep->fmt = (dma2d_pixfmt_t)((r & DMA2D_FGPFCCR_CCM) >> 4); +} + +/** + * @brief Get foreground layer palette specifications. + * @details Gets the palette specifications of the foreground layer. + * @note The palette colors pointer is actually addressed to a @p volatile + * memory zone. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[out] palettep pointer to the palette specifications + * + * @api + */ +void dma2dFgGetPalette(DMA2DDriver *dma2dp, dma2d_palcfg_t *palettep) { + + chSysLock(); + dma2dFgGetPaletteI(dma2dp, palettep); + chSysUnlock(); +} + +/** + * @brief Set foreground layer palette specifications. + * @details Sets the palette specifications of the foreground layer. + * @note This function should not be called while the DMA2D is already + * executing a job, otherwise the appropriate error interrupt might be + * invoked. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] palettep pointer to the palette specifications + * + * @sclass + */ +void dma2dFgSetPaletteS(DMA2DDriver *dma2dp, const dma2d_palcfg_t *palettep) { + + osalDbgCheckClassS(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgCheck(palettep != NULL); + osalDbgCheck(palettep->colorsp != NULL); + osalDbgAssert(palettep->length > 0, "bounds"); + osalDbgAssert(palettep->length <= DMA2D_MAX_PALETTE_LENGTH, "bounds"); + osalDbgAssert(((palettep->fmt == DMA2D_FMT_ARGB8888) || + (palettep->fmt == DMA2D_FMT_RGB888)), "invalid format"); + + DMA2D->FGCMAR = (uint32_t)palettep->colorsp; + DMA2D->FGPFCCR = ( + (DMA2D->FGPFCCR & ~(DMA2D_FGPFCCR_CS | DMA2D_FGPFCCR_CCM)) | + ((((uint32_t)palettep->length - 1) << 8) & DMA2D_FGPFCCR_CS) | + ((uint32_t)palettep->fmt << 4) + ); + + dma2dp->state = DMA2D_ACTIVE; + DMA2D->FGPFCCR |= DMA2D_FGPFCCR_START; + +#if DMA2D_USE_WAIT + dma2dp->thread = chThdGetSelfX(); + chSchGoSleepS(CH_STATE_SUSPENDED); +#else + while (DMA2D->FGPFCCR & DMA2D_FGPFCCR_START) + chSchDoYieldS(); +#endif /* DMA2D_USE_WAIT */ +} + +/** + * @brief Set foreground layer palette specifications. + * @details Sets the palette specifications of the foreground layer. + * @note This function should not be called while the DMA2D is already + * executing a job, otherwise the appropriate error interrupt might be + * invoked. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] palettep pointer to the palette specifications + * + * @api + */ +void dma2dFgSetPalette(DMA2DDriver *dma2dp, const dma2d_palcfg_t *palettep) { + + chSysLock(); + dma2dFgSetPaletteS(dma2dp, palettep); + chSysUnlock(); +} + +/** + * @brief Get foreground layer specifications. + * @details Gets the foreground layer specifications at once. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[out] cfgp pointer to the layer specifications + * + * @iclass + */ +void dma2dFgGetLayerI(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgCheck(cfgp != NULL); + + cfgp->bufferp = dma2dFgGetAddressI(dma2dp); + cfgp->wrap_offset = dma2dFgGetWrapOffsetI(dma2dp); + cfgp->fmt = dma2dFgGetPixelFormatI(dma2dp); + cfgp->def_color = dma2dFgGetDefaultColorI(dma2dp); + cfgp->const_alpha = dma2dFgGetConstantAlphaI(dma2dp); + if (cfgp->palettep != NULL) + dma2dFgGetPaletteI(dma2dp, (dma2d_palcfg_t *)cfgp->palettep); +} + +/** + * @brief Get foreground layer specifications. + * @details Gets the foreground layer specifications at once. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[out] cfgp pointer to the layer specifications + * + * @api + */ +void dma2dFgGetLayer(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp) { + + chSysLock(); + dma2dFgGetLayerI(dma2dp, cfgp); + chSysUnlock(); +} + +/** + * @brief Set foreground layer specifications. + * @details Sets the foreground layer specifications at once. + * @note If the palette is unspecified, the layer palette is unmodified. + * @note This function should not be called while the DMA2D is already + * executing a job, otherwise the appropriate error interrupt might be + * invoked. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] cfgp pointer to the layer specifications + * + * @sclass + */ +void dma2dFgSetConfigS(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp) { + + osalDbgCheckClassS(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgCheck(cfgp != NULL); + + dma2dFgSetAddressI(dma2dp, cfgp->bufferp); + dma2dFgSetWrapOffsetI(dma2dp, cfgp->wrap_offset); + dma2dFgSetPixelFormatI(dma2dp, cfgp->fmt); + dma2dFgSetDefaultColorI(dma2dp, cfgp->def_color); + dma2dFgSetConstantAlphaI(dma2dp, cfgp->const_alpha); + if (cfgp->palettep != NULL) + dma2dFgSetPaletteS(dma2dp, cfgp->palettep); +} + +/** + * @brief Set foreground layer specifications. + * @details Sets the foreground layer specifications at once. + * @note If the palette is unspecified, the layer palette is unmodified. + * @note This function should not be called while the DMA2D is already + * executing a job, otherwise the appropriate error interrupt might be + * invoked. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] cfgp pointer to the layer specifications + * + * @api + */ +void dma2dFgSetConfig(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp) { + + chSysLock(); + dma2dFgSetConfigS(dma2dp, cfgp); + chSysUnlock(); +} + +/** @} */ + +/** + * @name DMA2D output layer methods + * @{ + */ + +/** + * @brief Get output layer buffer address. + * @details Gets the buffer address of the output layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return buffer address + * + * @iclass + */ +void *dma2dOutGetAddressI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (void *)DMA2D->OMAR; +} + +/** + * @brief Get output layer buffer address. + * @details Gets the buffer address of the output layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return buffer address + * + * @api + */ +void *dma2dOutGetAddress(DMA2DDriver *dma2dp) { + + void *bufferp; + chSysLock(); + bufferp = dma2dOutGetAddressI(dma2dp); + chSysUnlock(); + return bufferp; +} + +/** + * @brief Set output layer buffer address. + * @details Sets the buffer address of the output layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] bufferp buffer address + * + * @iclass + */ +void dma2dOutSetAddressI(DMA2DDriver *dma2dp, void *bufferp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgCheck(dma2dIsAligned(bufferp, dma2dOutGetPixelFormatI(dma2dp))); + (void)dma2dp; + + DMA2D->OMAR = (uint32_t)bufferp; +} + +/** + * @brief Set output layer buffer address. + * @details Sets the buffer address of the output layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] bufferp buffer address + * + * @api + */ +void dma2dOutSetAddress(DMA2DDriver *dma2dp, void *bufferp) { + + chSysLock(); + dma2dOutSetAddressI(dma2dp, bufferp); + chSysUnlock(); +} + +/** + * @brief Get output layer wrap offset. + * @details Gets the buffer line wrap offset of the output layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return wrap offset, in pixels + * + * @iclass + */ +size_t dma2dOutGetWrapOffsetI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (size_t)(DMA2D->OOR & DMA2D_OOR_LO); +} + +/** + * @brief Get output layer wrap offset. + * @details Gets the buffer line wrap offset of the output layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return wrap offset, in pixels + * + * @api + */ +size_t dma2dOutGetWrapOffset(DMA2DDriver *dma2dp) { + + size_t offset; + chSysLock(); + offset = dma2dOutGetWrapOffsetI(dma2dp); + chSysUnlock(); + return offset; +} + +/** + * @brief Set output layer wrap offset. + * @details Sets the buffer line wrap offset of the output layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] offset wrap offset, in pixels + * + * @iclass + */ +void dma2dOutSetWrapOffsetI(DMA2DDriver *dma2dp, size_t offset) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgAssert(offset <= DMA2D_MAX_OFFSET, "bounds"); + (void)dma2dp; + + DMA2D->OOR = ((DMA2D->OOR & ~DMA2D_OOR_LO) | + ((uint32_t)offset & DMA2D_OOR_LO)); +} + +/** + * @brief Set output layer wrap offset. + * @details Sets the buffer line wrap offset of the output layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] offset wrap offset, in pixels + * + * @api + */ +void dma2dOutSetWrapOffset(DMA2DDriver *dma2dp, size_t offset) { + + chSysLock(); + dma2dOutSetWrapOffsetI(dma2dp, offset); + chSysUnlock(); +} + +/** + * @brief Get output layer pixel format. + * @details Gets the pixel format of the output layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return pixel format + * + * @iclass + */ +dma2d_pixfmt_t dma2dOutGetPixelFormatI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (dma2d_pixfmt_t)(DMA2D->OPFCCR & DMA2D_OPFCCR_CM); +} + +/** + * @brief Get output layer pixel format. + * @details Gets the pixel format of the output layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return pixel format + * + * @api + */ +dma2d_pixfmt_t dma2dOutGetPixelFormat(DMA2DDriver *dma2dp) { + + dma2d_pixfmt_t fmt; + chSysLock(); + fmt = dma2dOutGetPixelFormatI(dma2dp); + chSysUnlock(); + return fmt; +} + +/** + * @brief Set output layer pixel format. + * @details Sets the pixel format of the output layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] fmt pixel format + * + * @iclass + */ +void dma2dOutSetPixelFormatI(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgAssert(fmt <= DMA2D_MAX_OUTPIXFMT_ID, "bounds"); + (void)dma2dp; + + DMA2D->OPFCCR = ((DMA2D->OPFCCR & ~DMA2D_OPFCCR_CM) | + ((uint32_t)fmt & DMA2D_OPFCCR_CM)); +} + +/** + * @brief Set output layer pixel format. + * @details Sets the pixel format of the output layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] fmt pixel format + * + * @api + */ +void dma2dOutSetPixelFormat(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt) { + + chSysLock(); + dma2dOutSetPixelFormatI(dma2dp, fmt); + chSysUnlock(); +} + +/** + * @brief Get output layer default color. + * @details Gets the default color of the output layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return default color, chosen output format + * + * @iclass + */ +dma2d_color_t dma2dOutGetDefaultColorI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (dma2d_color_t)(DMA2D->OCOLR & 0x00FFFFFF); +} + +/** + * @brief Get output layer default color. + * @details Gets the default color of the output layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return default color, chosen output format + * + * @api + */ +dma2d_color_t dma2dOutGetDefaultColor(DMA2DDriver *dma2dp) { + + dma2d_color_t c; + chSysLock(); + c = dma2dOutGetDefaultColorI(dma2dp); + chSysUnlock(); + return c; +} + +/** + * @brief Set output layer default color. + * @details Sets the default color of the output layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] c default color, chosen output format + * + * @iclass + */ +void dma2dOutSetDefaultColorI(DMA2DDriver *dma2dp, dma2d_color_t c) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + (void)dma2dp; + + DMA2D->OCOLR = (uint32_t)c & 0x00FFFFFF; +} + +/** + * @brief Set output layer default color. + * @details Sets the default color of the output layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] c default color, chosen output format + * + * @api + */ +void dma2dOutSetDefaultColor(DMA2DDriver *dma2dp, dma2d_color_t c) { + + chSysLock(); + dma2dOutSetDefaultColorI(dma2dp, c); + chSysUnlock(); +} + +/** + * @brief Get output layer specifications. + * @details Gets the output layer specifications at once. + * @note Constant alpha and palette specifications are ignored. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[out] cfgp pointer to the layer specifications + * + * @iclass + */ +void dma2dOutGetLayerI(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgCheck(cfgp != NULL); + + cfgp->bufferp = dma2dOutGetAddressI(dma2dp); + cfgp->wrap_offset = dma2dOutGetWrapOffsetI(dma2dp); + cfgp->fmt = dma2dOutGetPixelFormatI(dma2dp); + cfgp->def_color = dma2dOutGetDefaultColorI(dma2dp); +} + +/** + * @brief Get output layer specifications. + * @details Gets the output layer specifications at once. + * @note Constant alpha and palette specifications are ignored. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[out] cfgp pointer to the layer specifications + * + * @api + */ +void dma2dOutGetLayer(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp) { + + chSysLock(); + dma2dOutGetLayerI(dma2dp, cfgp); + chSysUnlock(); +} + +/** + * @brief Set output layer specifications. + * @details Sets the output layer specifications at once. + * @note Constant alpha and palette specifications are ignored. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] cfgp pointer to the layer specifications + * + * @iclass + */ +void dma2dOutSetConfigI(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgCheck(cfgp != NULL); + + dma2dOutSetAddressI(dma2dp, cfgp->bufferp); + dma2dOutSetWrapOffsetI(dma2dp, cfgp->wrap_offset); + dma2dOutSetPixelFormatI(dma2dp, cfgp->fmt); + dma2dOutSetDefaultColorI(dma2dp, cfgp->def_color); +} + +/** + * @brief Set output layer specifications. + * @details Sets the output layer specifications at once. + * @note Constant alpha and palette specifications are ignored. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] cfgp pointer to the layer specifications + * + * @api + */ +void dma2dOutSetConfig(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp) { + + chSysLock(); + dma2dOutSetConfigI(dma2dp, cfgp); + chSysUnlock(); +} + +/** @} */ + +/** + * @name DMA2D helper functions + * @{ + */ + +/** + * @brief Compute pixel address. + * @details Computes the buffer address of a pixel, given the buffer + * specifications. + * + * @param[in] originp buffer origin address + * @param[in] pitch buffer pitch, in bytes + * @param[in] fmt buffer pixel format + * @param[in] x horizontal pixel coordinate + * @param[in] y vertical pixel coordinate + * + * @return pixel address, constant data + * + * @api + */ +const void *dma2dComputeAddressConst(const void *originp, size_t pitch, + dma2d_pixfmt_t fmt, + uint16_t x, uint16_t y) { + + osalDbgCheck(pitch > 0); + + switch (fmt) { + case DMA2D_FMT_ARGB8888: + return (const void *)((uintptr_t)originp + + (uintptr_t)y * pitch + (uintptr_t)x * 4); + case DMA2D_FMT_RGB888: + return (const void *)((uintptr_t)originp + + (uintptr_t)y * pitch + (uintptr_t)x * 3); + case DMA2D_FMT_RGB565: + case DMA2D_FMT_ARGB1555: + case DMA2D_FMT_ARGB4444: + case DMA2D_FMT_AL88: + return (const void *)((uintptr_t)originp + + (uintptr_t)y * pitch + (uintptr_t)x * 2); + case DMA2D_FMT_L8: + case DMA2D_FMT_AL44: + case DMA2D_FMT_A8: + return (const void *)((uintptr_t)originp + + (uintptr_t)y * pitch + (uintptr_t)x); + case DMA2D_FMT_L4: + case DMA2D_FMT_A4: + osalDbgAssert((x & 1) == 0, "not aligned"); + return (const void *)((uintptr_t)originp + + (uintptr_t)y * pitch + (uintptr_t)x / 2); + default: + osalDbgAssert(false, "invalid format"); + return NULL; + } +} + +/** + * @brief Address is aligned. + * @details Tells whether the address is aligned with the provided pixel format. + * + * @param[in] bufferp address + * @param[in] fmt pixel format + * + * @return address is aligned + * + * @api + */ +bool dma2dIsAligned(const void *bufferp, dma2d_pixfmt_t fmt) { + + switch (fmt) { + case DMA2D_FMT_ARGB8888: + case DMA2D_FMT_RGB888: + return ((uintptr_t)bufferp & 3) == 0; /* 32-bit alignment.*/ + case DMA2D_FMT_RGB565: + case DMA2D_FMT_ARGB1555: + case DMA2D_FMT_ARGB4444: + case DMA2D_FMT_AL88: + return ((uintptr_t)bufferp & 1) == 0; /* 16-bit alignment.*/ + case DMA2D_FMT_L8: + case DMA2D_FMT_AL44: + case DMA2D_FMT_L4: + case DMA2D_FMT_A8: + case DMA2D_FMT_A4: + return true; /* 8-bit alignment.*/ + default: + osalDbgAssert(false, "invalid format"); + return false; + } +} + +/** + * @brief Compute bits per pixel. + * @details Computes the bits per pixel for the specified pixel format. + * + * @param[in] fmt pixel format + * + * @retuen bits per pixel + * + * @api + */ +size_t dma2dBitsPerPixel(dma2d_pixfmt_t fmt) { + + osalDbgAssert(fmt < DMA2D_MAX_PIXFMT_ID, "invalid format"); + + return (size_t)dma2d_bpp[(unsigned)fmt]; +} + +#if DMA2D_USE_SOFTWARE_CONVERSIONS || defined(__DOXYGEN__) + +/** + * @brief Convert from ARGB-8888. + * @details Converts an ARGB-8888 color to the specified pixel format. + * + * @param[in] c color, ARGB-8888 + * @param[in] fmt target pixel format + * + * @return raw color value for the target pixel format, left + * padded with zeros. + * + * @api + */ +dma2d_color_t dma2dFromARGB8888(dma2d_color_t c, dma2d_pixfmt_t fmt) { + + switch (fmt) { + case DMA2D_FMT_ARGB8888: { + return c; + } + case DMA2D_FMT_RGB888: { + return (c & 0x00FFFFFF); + } + case DMA2D_FMT_RGB565: { + return (((c & 0x000000F8) >> ( 8 - 5)) | + ((c & 0x0000FC00) >> (16 - 11)) | + ((c & 0x00F80000) >> (24 - 16))); + } + case DMA2D_FMT_ARGB1555: { + return (((c & 0x000000F8) >> ( 8 - 5)) | + ((c & 0x0000F800) >> (16 - 10)) | + ((c & 0x00F80000) >> (24 - 15)) | + ((c & 0x80000000) >> (32 - 16))); + } + case DMA2D_FMT_ARGB4444: { + return (((c & 0x000000F0) >> ( 8 - 4)) | + ((c & 0x0000F000) >> (16 - 8)) | + ((c & 0x00F00000) >> (24 - 12)) | + ((c & 0xF0000000) >> (32 - 16))); + } + case DMA2D_FMT_L8: { + return (c & 0x000000FF); + } + case DMA2D_FMT_AL44: { + return (((c & 0x000000F0) >> ( 8 - 4)) | + ((c & 0xF0000000) >> (32 - 8))); + } + case DMA2D_FMT_AL88: { + return (((c & 0x000000FF) >> ( 8 - 8)) | + ((c & 0xFF000000) >> (32 - 16))); + } + case DMA2D_FMT_L4: { + return (c & 0x0000000F); + } + case DMA2D_FMT_A8: { + return ((c & 0xFF000000) >> (32 - 8)); + } + case DMA2D_FMT_A4: { + return ((c & 0xF0000000) >> (32 - 4)); + } + default: + osalDbgAssert(false, "invalid format"); + return 0; + } +} + +/** + * @brief Convert to ARGB-8888. + * @details Converts color of the specified pixel format to an ARGB-8888 color. + * + * @param[in] c color for the source pixel format, left padded with + * zeros. + * @param[in] fmt source pixel format + * + * @return color in ARGB-8888 format + * + * @api + */ +dma2d_color_t dma2dToARGB8888(dma2d_color_t c, dma2d_pixfmt_t fmt) { + + switch (fmt) { + case DMA2D_FMT_ARGB8888: { + return c; + } + case DMA2D_FMT_RGB888: { + return ((c & 0x00FFFFFF) | 0xFF000000); + } + case DMA2D_FMT_RGB565: { + register dma2d_color_t output = 0xFF000000; + if (c & 0x001F) output |= (((c & 0x001F) << ( 8 - 5)) | 0x00000007); + if (c & 0x07E0) output |= (((c & 0x07E0) << (16 - 11)) | 0x00000300); + if (c & 0xF800) output |= (((c & 0xF800) << (24 - 16)) | 0x00070000); + return output; + } + case DMA2D_FMT_ARGB1555: { + register dma2d_color_t output = 0x00000000; + if (c & 0x001F) output |= (((c & 0x001F) << ( 8 - 5)) | 0x00000007); + if (c & 0x03E0) output |= (((c & 0x03E0) << (16 - 10)) | 0x00000700); + if (c & 0x7C00) output |= (((c & 0x7C00) << (24 - 15)) | 0x00070000); + if (c & 0x8000) output |= 0xFF000000; + return output; + } + case DMA2D_FMT_ARGB4444: { + register dma2d_color_t output = 0x00000000; + if (c & 0x000F) output |= (((c & 0x000F) << ( 8 - 4)) | 0x0000000F); + if (c & 0x00F0) output |= (((c & 0x00F0) << (16 - 8)) | 0x00000F00); + if (c & 0x0F00) output |= (((c & 0x0F00) << (24 - 12)) | 0x000F0000); + if (c & 0xF000) output |= (((c & 0xF000) << (32 - 16)) | 0x0F000000); + return output; + } + case DMA2D_FMT_L8: { + return (c & 0xFF) | 0xFF000000; + } + case DMA2D_FMT_AL44: { + register dma2d_color_t output = 0x00000000; + if (c & 0x0F) output |= (((c & 0x0F) << ( 8 - 4)) | 0x0000000F); + if (c & 0xF0) output |= (((c & 0xF0) << (32 - 8)) | 0x0F000000); + return output; + } + case DMA2D_FMT_AL88: { + return (((c & 0x00FF) << ( 8 - 8)) | + ((c & 0xFF00) << (32 - 16))); + } + case DMA2D_FMT_L4: { + return ((c & 0x0F) | 0xFF000000); + } + case DMA2D_FMT_A8: { + return ((c & 0xFF) << (32 - 8)); + } + case DMA2D_FMT_A4: { + return ((c & 0x0F) << (32 - 4)); + } + default: + osalDbgAssert(false, "invalid format"); + return 0; + } +} + +#endif /* DMA2D_NEED_CONVERSIONS */ + +/** @} */ + +/** @} */ + +#endif /* STM32_DMA2D_USE_DMA2D */ diff --git a/os/hal/ports/STM32/LLD/DMA2Dv1/hal_stm32_dma2d.h b/os/hal/ports/STM32/LLD/DMA2Dv1/hal_stm32_dma2d.h new file mode 100644 index 0000000..01f0941 --- /dev/null +++ b/os/hal/ports/STM32/LLD/DMA2Dv1/hal_stm32_dma2d.h @@ -0,0 +1,664 @@ +/* + Copyright (C) 2013-2015 Andrea Zoppi + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file stm32_dma2d.h + * @brief DMA2D/Chrom-ART driver. + * + * @addtogroup dma2d + * @{ + */ + +#ifndef _STM32_DMA2D_H_ +#define _STM32_DMA2D_H_ + +/** + * @brief Using the DMA2D driver. + */ +#if !defined(STM32_DMA2D_USE_DMA2D) || defined(__DOXYGEN__) +#define STM32_DMA2D_USE_DMA2D (FALSE) +#endif + +#if (TRUE == STM32_DMA2D_USE_DMA2D) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name DMA2D job modes + * @{ + */ +#define DMA2D_JOB_COPY (0 << 16) /**< Copy, replace(FG only).*/ +#define DMA2D_JOB_CONVERT (1 << 16) /**< Copy, convert (FG + PFC).*/ +#define DMA2D_JOB_BLEND (2 << 16) /**< Copy, blend (FG + BG + PFC).*/ +#define DMA2D_JOB_CONST (3 << 16) /**< Default color only (FG REG).*/ +/** @} */ + +/** + * @name DMA2D enable flag + * @{ + */ +#define DMA2D_EF_ENABLE (1 << 0) /**< DMA2D enabled.*/ +#define DMA2D_EF_DITHER (1 << 16) /**< Dithering enabled.*/ +#define DMA2D_EF_PIXCLK_INVERT (1 << 28) /**< Inverted pixel clock.*/ +#define DMA2D_EF_DATAEN_HIGH (1 << 29) /**< Active-high data enable.*/ +#define DMA2D_EF_VSYNC_HIGH (1 << 30) /**< Active-high vsync.*/ +#define DMA2D_EF_HSYNC_HIGH (1 << 31) /**< Active-high hsync.*/ + +/** Enable flags mask. */ +#define DMA2D_EF_MASK \ + (DMA2D_EF_ENABLE | DMA2D_EF_DITHER | DMA2D_EF_PIXCLK_INVERT | \ + DMA2D_EF_DATAEN_HIGH | DMA2D_EF_VSYNC_HIGH | DMA2D_EF_HSYNC_HIGH) +/** @} */ + +/** + * @name DMA2D layer enable flags + * @{ + */ +#define DMA2D_LEF_ENABLE (1 << 0) /**< Layer enabled*/ +#define DMA2D_LEF_KEYING (1 << 1) /**< Color keying enabled.*/ +#define DMA2D_LEF_PALETTE (1 << 4) /**< Palette enabled.*/ + +/** Layer enable flag masks. */ +#define DMA2D_LEF_MASK \ + (DMA2D_LEF_ENABLE | DMA2D_LEF_KEYING | DMA2D_LEF_PALETTE) +/** @} */ + +/** + * @name DMA2D pixel formats + * @{ + */ +#define DMA2D_FMT_ARGB8888 (0) /**< ARGB-8888 format.*/ +#define DMA2D_FMT_RGB888 (1) /**< RGB-888 format.*/ +#define DMA2D_FMT_RGB565 (2) /**< RGB-565 format.*/ +#define DMA2D_FMT_ARGB1555 (3) /**< ARGB-1555 format.*/ +#define DMA2D_FMT_ARGB4444 (4) /**< ARGB-4444 format.*/ +#define DMA2D_FMT_L8 (5) /**< L-8 format.*/ +#define DMA2D_FMT_AL44 (6) /**< AL-44 format.*/ +#define DMA2D_FMT_AL88 (7) /**< AL-88 format.*/ +#define DMA2D_FMT_L4 (8) /**< L-4 format.*/ +#define DMA2D_FMT_A8 (9) /**< A-8 format.*/ +#define DMA2D_FMT_A4 (10) /**< A-4 format.*/ +/** @} */ + +/** + * @name DMA2D pixel format aliased raw masks + * @{ + */ +#define DMA2D_XMASK_ARGB8888 (0xFFFFFFFF) /**< ARGB-8888 aliased mask.*/ +#define DMA2D_XMASK_RGB888 (0x00FFFFFF) /**< RGB-888 aliased mask.*/ +#define DMA2D_XMASK_RGB565 (0x00F8FCF8) /**< RGB-565 aliased mask.*/ +#define DMA2D_XMASK_ARGB1555 (0x80F8F8F8) /**< ARGB-1555 aliased mask.*/ +#define DMA2D_XMASK_ARGB4444 (0xF0F0F0F0) /**< ARGB-4444 aliased mask.*/ +#define DMA2D_XMASK_L8 (0x000000FF) /**< L-8 aliased mask.*/ +#define DMA2D_XMASK_AL44 (0xF00000F0) /**< AL-44 aliased mask.*/ +#define DMA2D_XMASK_AL88 (0xFF0000FF) /**< AL-88 aliased mask.*/ +#define DMA2D_XMASK_L4 (0x0000000F) /**< L-4 aliased mask.*/ +#define DMA2D_XMASK_A8 (0xFF000000) /**< A-8 aliased mask.*/ +#define DMA2D_XMASK_A4 (0xF0000000) /**< A-4 aliased mask.*/ +/** @} */ + +/** + * @name DMA2D alpha modes + * @{ + */ +#define DMA2D_ALPHA_KEEP (0x00000000) /**< Original alpha channel.*/ +#define DMA2D_ALPHA_REPLACE (0x00010000) /**< Replace with constant.*/ +#define DMA2D_ALPHA_MODULATE (0x00020000) /**< Modulate with constant.*/ +/** @} */ + +/** + * @name DMA2D parameter bounds + * @{ + */ + +#define DMA2D_MIN_PIXFMT_ID (0) /**< Minimum pixel format ID.*/ +#define DMA2D_MAX_PIXFMT_ID (11) /**< Maximum pixel format ID.*/ +#define DMA2D_MIN_OUTPIXFMT_ID (0) /**< Minimum output pixel format ID.*/ +#define DMA2D_MAX_OUTPIXFMT_ID (4) /**< Maximum output pixel format ID.*/ + +#define DMA2D_MAX_OFFSET ((1 << 14) - 1) + +#define DMA2D_MAX_PALETTE_LENGTH (256) /***/ + +#define DMA2D_MAX_WIDTH ((1 << 14) - 1) +#define DMA2D_MAX_HEIGHT ((1 << 16) - 1) + +#define DMA2D_MAX_WATERMARK_POS ((1 << 16) - 1) + +#define DMA2D_MAX_DEADTIME_CYCLES ((1 << 8) - 1) + +/** @} */ + +/** + * @name DMA2D basic ARGB-8888 colors. + * @{ + */ +/* Microsoft Windows default 16-color palette.*/ +#define DMA2D_COLOR_BLACK (0xFF000000) +#define DMA2D_COLOR_MAROON (0xFF800000) +#define DMA2D_COLOR_GREEN (0xFF008000) +#define DMA2D_COLOR_OLIVE (0xFF808000) +#define DMA2D_COLOR_NAVY (0xFF000080) +#define DMA2D_COLOR_PURPLE (0xFF800080) +#define DMA2D_COLOR_TEAL (0xFF008080) +#define DMA2D_COLOR_SILVER (0xFFC0C0C0) +#define DMA2D_COLOR_GRAY (0xFF808080) +#define DMA2D_COLOR_RED (0xFFFF0000) +#define DMA2D_COLOR_LIME (0xFF00FF00) +#define DMA2D_COLOR_YELLOW (0xFFFFFF00) +#define DMA2D_COLOR_BLUE (0xFF0000FF) +#define DMA2D_COLOR_FUCHSIA (0xFFFF00FF) +#define DMA2D_COLOR_AQUA (0xFF00FFFF) +#define DMA2D_COLOR_WHITE (0xFFFFFFFF) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name DMA2D configuration options + * @{ + */ + +/** + * @brief DMA2D event interrupt priority level setting. + */ +#if !defined(STM32_DMA2D_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DMA2D_IRQ_PRIORITY (11) +#endif + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(DMA2D_USE_WAIT) || defined(__DOXYGEN__) +#define DMA2D_USE_WAIT (TRUE) +#endif + +/** + * @brief Enables the @p dma2dAcquireBus() and @p dma2dReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(DMA2D_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define DMA2D_USE_MUTUAL_EXCLUSION (TRUE) +#endif + +/** + * @brief Provides software color conversion functions. + * @note Disabling this option saves both code and data space. + */ +#if !defined(DMA2D_USE_SOFTWARE_CONVERSIONS) || defined(__DOXYGEN__) +#define DMA2D_USE_SOFTWARE_CONVERSIONS (TRUE) +#endif + +/** + * @brief Enables checks for DMA2D functions. + * @note Disabling this option saves both code and data space. + * @note Disabling checks by ChibiOS will automatically disable DMA2D checks. + */ +#if !defined(DMA2D_USE_CHECKS) || defined(__DOXYGEN__) +#define DMA2D_USE_CHECKS (TRUE) +#endif + +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if (TRUE != STM32_HAS_DMA2D) +#error "DMA2D must be present when using the DMA2D subsystem" +#endif + +#if (TRUE != STM32_DMA2D_USE_DMA2D) && (TRUE != STM32_HAS_DMA2D) +#error "DMA2D not present in the selected device" +#endif + +#if (TRUE == DMA2D_USE_MUTUAL_EXCLUSION) +#if (TRUE != CH_CFG_USE_MUTEXES) && (TRUE != CH_CFG_USE_SEMAPHORES) +#error "DMA2D_USE_MUTUAL_EXCLUSION requires CH_CFG_USE_MUTEXES and/or CH_CFG_USE_SEMAPHORES" +#endif +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/* Complex types forwarding.*/ +typedef union dma2d_coloralias_t dma2d_coloralias_t; +typedef struct dma2d_palcfg_t dma2d_palcfg_t; +typedef struct dma2d_laycfg_t dma2d_layercfg_t; +typedef struct DMA2DConfig DMA2DConfig; +typedef enum dma2d_state_t dma2d_state_t; +typedef struct DMA2DDriver DMA2DDriver; + +/** + * @name DMA2D Data types + * @{ + */ + +/** + * @brief DMA2D generic color. + */ +typedef uint32_t dma2d_color_t; + +/** + * @brief DMA2D color aliases. + * @detail Mapped with ARGB-8888, except for luminance (L mapped onto B). + * Padding fields are prefixed with 'x', and should be clear + * (all 0) before compression and set (all 1) after expansion. + */ +typedef union dma2d_coloralias_t { + struct { + unsigned b : 8; + unsigned g : 8; + unsigned r : 8; + unsigned a : 8; + } argb8888; /**< Mapped ARGB-8888 bits.*/ + struct { + unsigned b : 8; + unsigned g : 8; + unsigned r : 8; + unsigned xa : 8; + } rgb888; /**< Mapped RGB-888 bits.*/ + struct { + unsigned xb : 3; + unsigned b : 5; + unsigned xg : 2; + unsigned g : 6; + unsigned xr : 3; + unsigned r : 5; + unsigned xa : 8; + } rgb565; /**< Mapped RGB-565 bits.*/ + struct { + unsigned xb : 3; + unsigned b : 5; + unsigned xg : 3; + unsigned g : 5; + unsigned xr : 3; + unsigned r : 5; + unsigned xa : 7; + unsigned a : 1; + } argb1555; /**< Mapped ARGB-1555 values.*/ + struct { + unsigned xb : 4; + unsigned b : 4; + unsigned xg : 4; + unsigned g : 4; + unsigned xr : 4; + unsigned r : 4; + unsigned xa : 4; + unsigned a : 4; + } argb4444; /**< Mapped ARGB-4444 values.*/ + struct { + unsigned l : 8; + unsigned x : 16; + unsigned xa : 8; + } l8; /**< Mapped L-8 bits.*/ + struct { + unsigned xl : 4; + unsigned l : 4; + unsigned x : 16; + unsigned xa : 4; + unsigned a : 4; + } al44; /**< Mapped AL-44 bits.*/ + struct { + unsigned l : 8; + unsigned x : 16; + unsigned a : 8; + } al88; /**< Mapped AL-88 bits.*/ + struct { + unsigned l : 4; + unsigned xl : 4; + unsigned x : 16; + unsigned xa : 8; + } l4; /**< Mapped L-4 bits.*/ + struct { + unsigned x : 24; + unsigned a : 8; + } a8; /**< Mapped A-8 bits.*/ + struct { + unsigned x : 24; + unsigned xa : 4; + unsigned a : 4; + } a4; /**< Mapped A-4 bits.*/ + dma2d_color_t aliased; /**< Aliased raw bits.*/ +} dma2d_coloralias_t; + +/** + * @brief DMA2D job (transfer) mode. + */ +typedef uint32_t dma2d_jobmode_t; + +/** + * @brief DMA2D pixel format. + */ +typedef uint32_t dma2d_pixfmt_t; + +/** + * @brief DMA2D alpha mode. + */ +typedef uint32_t dma2d_amode_t; + +/** + * @brief DMA2D ISR callback. + */ +typedef void (*dma2d_isrcb_t)(DMA2DDriver *dma2dp); + +/** + * @brief DMA2D palette specifications. + */ +typedef struct dma2d_palcfg_t { + const void *colorsp; /**< Pointer to color entries.*/ + uint16_t length; /**< Number of color entries.*/ + dma2d_pixfmt_t fmt; /**< Format, RGB-888 or ARGB-8888.*/ +} dma2d_palcfg_t; + +/** + * @brief DMA2D layer specifications. + */ +typedef struct dma2d_layercfg_t { + void *bufferp; /**< Frame buffer address.*/ + size_t wrap_offset; /**< Offset between lines, in pixels.*/ + dma2d_pixfmt_t fmt; /**< Pixel format.*/ + dma2d_color_t def_color; /**< Default color, RGB-888.*/ + uint8_t const_alpha; /**< Constant alpha factor.*/ + const dma2d_palcfg_t *palettep; /**< Palette specs, or @p NULL.*/ +} dma2d_laycfg_t; + +/** + * @brief DMA2D driver configuration. + */ +typedef struct DMA2DConfig { + /* ISR callbacks.*/ + dma2d_isrcb_t cfgerr_isr; /**< Configuration error, or @p NULL.*/ + dma2d_isrcb_t paltrfdone_isr; /**< Palette transfer done, or @p NULL.*/ + dma2d_isrcb_t palacserr_isr; /**< Palette access error, or @p NULL.*/ + dma2d_isrcb_t trfwmark_isr; /**< Transfer watermark, or @p NULL.*/ + dma2d_isrcb_t trfdone_isr; /**< Transfer complete, or @p NULL.*/ + dma2d_isrcb_t trferr_isr; /**< Transfer error, or @p NULL.*/ +} DMA2DConfig; + +/** + * @brief DMA2D driver state. + */ +typedef enum dma2d_state_t { + DMA2D_UNINIT = (0), /**< Not initialized.*/ + DMA2D_STOP = (1), /**< Stopped.*/ + DMA2D_READY = (2), /**< Ready.*/ + DMA2D_ACTIVE = (3), /**< Executing commands.*/ + DMA2D_PAUSED = (4), /**< Transfer suspended.*/ +} dma2d_state_t; + +/** + * @brief DMA2D driver. + */ +typedef struct DMA2DDriver { + dma2d_state_t state; /**< Driver state.*/ + const DMA2DConfig *config; /**< Driver configuration.*/ + + /* Multithreading stuff.*/ +#if (TRUE == DMA2D_USE_WAIT) || defined(__DOXYGEN__) + thread_t *thread; /**< Waiting thread.*/ +#endif /* DMA2D_USE_WAIT */ +#if (TRUE == DMA2D_USE_MUTUAL_EXCLUSION) +#if (TRUE == CH_CFG_USE_MUTEXES) + mutex_t lock; /**< Multithreading lock.*/ +#elif (TRUE == CH_CFG_USE_SEMAPHORES) + semaphore_t lock; /**< Multithreading lock.*/ +#endif +#endif /* DMA2D_USE_MUTUAL_EXCLUSION */ +} DMA2DDriver; + +/** @} */ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Makes an ARGB-8888 value from byte components. + * + * @param[in] a alpha byte component + * @param[in] r red byte component + * @param[in] g green byte component + * @param[in] b blue byte component + * + * @return color in ARGB-8888 format + * + * @api + */ +#define dma2dMakeARGB8888(a, r, g, b) \ + ((((dma2d_color_t)(a) & 0xFF) << 24) | \ + (((dma2d_color_t)(r) & 0xFF) << 16) | \ + (((dma2d_color_t)(g) & 0xFF) << 8) | \ + (((dma2d_color_t)(b) & 0xFF) << 0)) + +/** + * @brief Compute bytes per pixel. + * @details Computes the bytes per pixel for the specified pixel format. + * Rounds to the ceiling. + * + * @param[in] fmt pixel format + * + * @return bytes per pixel + * + * @api + */ +#define dma2dBytesPerPixel(fmt) \ + ((dma2dBitsPerPixel(fmt) + 7) >> 3) + +/** + * @brief Compute pixel address. + * @details Computes the buffer address of a pixel, given the buffer + * specifications. + * + * @param[in] originp buffer origin address + * @param[in] pitch buffer pitch, in bytes + * @param[in] fmt buffer pixel format + * @param[in] x horizontal pixel coordinate + * @param[in] y vertical pixel coordinate + * + * @return pixel address + * + * @api + */ +#define dma2dComputeAddress(originp, pitch, fmt, x, y) \ + ((void *)dma2dComputeAddressConst(originp, pitch, fmt, x, y)) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +extern DMA2DDriver DMA2DD1; + +#ifdef __cplusplus +extern "C" { +#endif + + /* Driver methods.*/ + void dma2dInit(void); + void dma2dObjectInit(DMA2DDriver *dma2dp); + dma2d_state_t dma2dGetStateI(DMA2DDriver *dma2dp); + dma2d_state_t dma2dGetState(DMA2DDriver *dma2dp); + void dma2dStart(DMA2DDriver *dma2dp, const DMA2DConfig *configp); + void dma2dStop(DMA2DDriver *dma2dp); +#if (TRUE == DMA2D_USE_MUTUAL_EXCLUSION) + void dma2dAcquireBusS(DMA2DDriver *dma2dp); + void dma2dAcquireBus(DMA2DDriver *dma2dp); + void dma2dReleaseBusS(DMA2DDriver *dma2dp); + void dma2dReleaseBus(DMA2DDriver *dma2dp); +#endif /* DMA2D_USE_MUTUAL_EXCLUSION */ + + /* Global methods.*/ + uint16_t dma2dGetWatermarkPosI(DMA2DDriver *dma2dp); + uint16_t dma2dGetWatermarkPos(DMA2DDriver *dma2dp); + void dma2dSetWatermarkPosI(DMA2DDriver *dma2dp, uint16_t line); + void dma2dSetWatermarkPos(DMA2DDriver *dma2dp, uint16_t line); + bool dma2dIsWatermarkEnabledI(DMA2DDriver *dma2dp); + bool dma2dIsWatermarkEnabled(DMA2DDriver *dma2dp); + void dma2dEnableWatermarkI(DMA2DDriver *dma2dp); + void dma2dEnableWatermark(DMA2DDriver *dma2dp); + void dma2dDisableWatermarkI(DMA2DDriver *dma2dp); + void dma2dDisableWatermark(DMA2DDriver *dma2dp); + uint32_t dma2dGetDeadTimeI(DMA2DDriver *dma2dp); + uint32_t dma2dGetDeadTime(DMA2DDriver *dma2dp); + void dma2dSetDeadTimeI(DMA2DDriver *dma2dp, uint32_t cycles); + void dma2dSetDeadTime(DMA2DDriver *dma2dp, uint32_t cycles); + bool dma2dIsDeadTimeEnabledI(DMA2DDriver *dma2dp); + bool dma2dIsDeadTimeEnabled(DMA2DDriver *dma2dp); + void dma2dEnableDeadTimeI(DMA2DDriver *dma2dp); + void dma2dEnableDeadTime(DMA2DDriver *dma2dp); + void dma2dDisableDeadTimeI(DMA2DDriver *dma2dp); + void dma2dDisableDeadTime(DMA2DDriver *dma2dp); + + /* Job methods.*/ + dma2d_jobmode_t dma2dJobGetModeI(DMA2DDriver *dma2dp); + dma2d_jobmode_t dma2dJobGetMode(DMA2DDriver *dma2dp); + void dma2dJobSetModeI(DMA2DDriver *dma2dp, dma2d_jobmode_t mode); + void dma2dJobSetMode(DMA2DDriver *dma2dp, dma2d_jobmode_t mode); + void dma2dJobGetSizeI(DMA2DDriver *dma2dp, + uint16_t *widthp, uint16_t *heightp); + void dma2dJobGetSize(DMA2DDriver *dma2dp, + uint16_t *widthp, uint16_t *heightp); + void dma2dJobSetSizeI(DMA2DDriver *dma2dp, uint16_t width, uint16_t height); + void dma2dJobSetSize(DMA2DDriver *dma2dp, uint16_t width, uint16_t height); + bool dma2dJobIsExecutingI(DMA2DDriver *dma2dp); + bool dma2dJobIsExecuting(DMA2DDriver *dma2dp); + void dma2dJobStartI(DMA2DDriver *dma2dp); + void dma2dJobStart(DMA2DDriver *dma2dp); + void dma2dJobExecuteS(DMA2DDriver *dma2dp); + void dma2dJobExecute(DMA2DDriver *dma2dp); + void dma2dJobSuspendI(DMA2DDriver *dma2dp); + void dma2dJobSuspend(DMA2DDriver *dma2dp); + void dma2dJobResumeI(DMA2DDriver *dma2dp); + void dma2dJobResume(DMA2DDriver *dma2dp); + void dma2dJobAbortI(DMA2DDriver *dma2dp); + void dma2dJobAbort(DMA2DDriver *dma2dp); + + /* Background layer methods.*/ + void *dma2dBgGetAddressI(DMA2DDriver *dma2dp); + void *dma2dBgGetAddress(DMA2DDriver *dma2dp); + void dma2dBgSetAddressI(DMA2DDriver *dma2dp, void *bufferp); + void dma2dBgSetAddress(DMA2DDriver *dma2dp, void *bufferp); + size_t dma2dBgGetWrapOffsetI(DMA2DDriver *dma2dp); + size_t dma2dBgGetWrapOffset(DMA2DDriver *dma2dp); + void dma2dBgSetWrapOffsetI(DMA2DDriver *dma2dp, size_t offset); + void dma2dBgSetWrapOffset(DMA2DDriver *dma2dp, size_t offset); + uint8_t dma2dBgGetConstantAlphaI(DMA2DDriver *dma2dp); + uint8_t dma2dBgGetConstantAlpha(DMA2DDriver *dma2dp); + void dma2dBgSetConstantAlphaI(DMA2DDriver *dma2dp, uint8_t a); + void dma2dBgSetConstantAlpha(DMA2DDriver *dma2dp, uint8_t a); + dma2d_amode_t dma2dBgGetAlphaModeI(DMA2DDriver *dma2dp); + dma2d_amode_t dma2dBgGetAlphaMode(DMA2DDriver *dma2dp); + void dma2dBgSetAlphaModeI(DMA2DDriver *dma2dp, dma2d_amode_t mode); + void dma2dBgSetAlphaMode(DMA2DDriver *dma2dp, dma2d_amode_t mode); + dma2d_pixfmt_t dma2dBgGetPixelFormatI(DMA2DDriver *dma2dp); + dma2d_pixfmt_t dma2dBgGetPixelFormat(DMA2DDriver *dma2dp); + void dma2dBgSetPixelFormatI(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt); + void dma2dBgSetPixelFormat(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt); + dma2d_color_t dma2dBgGetDefaultColorI(DMA2DDriver *dma2dp); + dma2d_color_t dma2dBgGetDefaultColor(DMA2DDriver *dma2dp); + void dma2dBgSetDefaultColorI(DMA2DDriver *dma2dp, dma2d_color_t c); + void dma2dBgSetDefaultColor(DMA2DDriver *dma2dp, dma2d_color_t c); + void dma2dBgGetPaletteI(DMA2DDriver *dma2dp, dma2d_palcfg_t *palettep); + void dma2dBgGetPalette(DMA2DDriver *dma2dp, dma2d_palcfg_t *palettep); + void dma2dBgSetPaletteS(DMA2DDriver *dma2dp, const dma2d_palcfg_t *palettep); + void dma2dBgSetPalette(DMA2DDriver *dma2dp, const dma2d_palcfg_t *palettep); + void dma2dBgGetLayerI(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp); + void dma2dBgGetLayer(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp); + void dma2dBgSetConfigS(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp); + void dma2dBgSetConfig(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp); + + /* Foreground layer methods.*/ + void *dma2dFgGetAddressI(DMA2DDriver *dma2dp); + void *dma2dFgGetAddress(DMA2DDriver *dma2dp); + void dma2dFgSetAddressI(DMA2DDriver *dma2dp, void *bufferp); + void dma2dFgSetAddress(DMA2DDriver *dma2dp, void *bufferp); + size_t dma2dFgGetWrapOffsetI(DMA2DDriver *dma2dp); + size_t dma2dFgGetWrapOffset(DMA2DDriver *dma2dp); + void dma2dFgSetWrapOffsetI(DMA2DDriver *dma2dp, size_t offset); + void dma2dFgSetWrapOffset(DMA2DDriver *dma2dp, size_t offset); + uint8_t dma2dFgGetConstantAlphaI(DMA2DDriver *dma2dp); + uint8_t dma2dFgGetConstantAlpha(DMA2DDriver *dma2dp); + void dma2dFgSetConstantAlphaI(DMA2DDriver *dma2dp, uint8_t a); + void dma2dFgSetConstantAlpha(DMA2DDriver *dma2dp, uint8_t a); + dma2d_amode_t dma2dFgGetAlphaModeI(DMA2DDriver *dma2dp); + dma2d_amode_t dma2dFgGetAlphaMode(DMA2DDriver *dma2dp); + void dma2dFgSetAlphaModeI(DMA2DDriver *dma2dp, dma2d_amode_t mode); + void dma2dFgSetAlphaMode(DMA2DDriver *dma2dp, dma2d_amode_t mode); + dma2d_pixfmt_t dma2dFgGetPixelFormatI(DMA2DDriver *dma2dp); + dma2d_pixfmt_t dma2dFgGetPixelFormat(DMA2DDriver *dma2dp); + void dma2dFgSetPixelFormatI(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt); + void dma2dFgSetPixelFormat(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt); + dma2d_color_t dma2dFgGetDefaultColorI(DMA2DDriver *dma2dp); + dma2d_color_t dma2dFgGetDefaultColor(DMA2DDriver *dma2dp); + void dma2dFgSetDefaultColorI(DMA2DDriver *dma2dp, dma2d_color_t c); + void dma2dFgSetDefaultColor(DMA2DDriver *dma2dp, dma2d_color_t c); + void dma2dFgGetPaletteI(DMA2DDriver *dma2dp, dma2d_palcfg_t *palettep); + void dma2dFgGetPalette(DMA2DDriver *dma2dp, dma2d_palcfg_t *palettep); + void dma2dFgSetPaletteS(DMA2DDriver *dma2dp, const dma2d_palcfg_t *palettep); + void dma2dFgSetPalette(DMA2DDriver *dma2dp, const dma2d_palcfg_t *palettep); + void dma2dFgGetLayerI(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp); + void dma2dFgGetLayer(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp); + void dma2dFgSetConfigS(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp); + void dma2dFgSetConfig(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp); + + /* Output layer methods.*/ + void *dma2dOutGetAddressI(DMA2DDriver *dma2dp); + void *dma2dOutGetAddress(DMA2DDriver *dma2dp); + void dma2dOutSetAddressI(DMA2DDriver *dma2dp, void *bufferp); + void dma2dOutSetAddress(DMA2DDriver *dma2dp, void *bufferp); + size_t dma2dOutGetWrapOffsetI(DMA2DDriver *dma2dp); + size_t dma2dOutGetWrapOffset(DMA2DDriver *dma2dp); + void dma2dOutSetWrapOffsetI(DMA2DDriver *dma2dp, size_t offset); + void dma2dOutSetWrapOffset(DMA2DDriver *dma2dp, size_t offset); + dma2d_pixfmt_t dma2dOutGetPixelFormatI(DMA2DDriver *dma2dp); + dma2d_pixfmt_t dma2dOutGetPixelFormat(DMA2DDriver *dma2dp); + void dma2dOutSetPixelFormatI(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt); + void dma2dOutSetPixelFormat(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt); + dma2d_color_t dma2dOutGetDefaultColorI(DMA2DDriver *dma2dp); + dma2d_color_t dma2dOutGetDefaultColor(DMA2DDriver *dma2dp); + void dma2dOutSetDefaultColorI(DMA2DDriver *dma2dp, dma2d_color_t c); + void dma2dOutSetDefaultColor(DMA2DDriver *dma2dp, dma2d_color_t c); + void dma2dOutGetLayerI(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp); + void dma2dOutGetLayer(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp); + void dma2dOutSetConfigI(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp); + void dma2dOutSetConfig(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp); + + /* Helper functions.*/ + const void *dma2dComputeAddressConst(const void *originp, size_t pitch, + dma2d_pixfmt_t fmt, + uint16_t x, uint16_t y); + bool dma2dIsAligned(const void *bufferp, dma2d_pixfmt_t fmt); + size_t dma2dBitsPerPixel(dma2d_pixfmt_t fmt); +#if (TRUE == DMA2D_USE_SOFTWARE_CONVERSIONS) || defined(__DOXYGEN__) + dma2d_color_t dma2dFromARGB8888(dma2d_color_t c, dma2d_pixfmt_t fmt); + dma2d_color_t dma2dToARGB8888(dma2d_color_t c, dma2d_pixfmt_t fmt); +#endif /* DMA2D_USE_SOFTWARE_CONVERSIONS */ + +#ifdef __cplusplus +} +#endif + +#endif /* STM32_DMA2D_USE_DMA2D */ + +#endif /* _STM32_DMA2D_H_ */ + +/** @} */ diff --git a/os/hal/ports/STM32/LLD/DMA2Dv1/stm32_dma2d.c b/os/hal/ports/STM32/LLD/DMA2Dv1/stm32_dma2d.c deleted file mode 100644 index 977eba0..0000000 --- a/os/hal/ports/STM32/LLD/DMA2Dv1/stm32_dma2d.c +++ /dev/null @@ -1,3130 +0,0 @@ -/* - Copyright (C) 2013-2015 Andrea Zoppi - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -/** - * @file stm32_dma2d.c - * @brief DMA2D/Chrom-ART driver. - */ - -#include "ch.h" -#include "hal.h" - -#include "stm32_dma2d.h" - -#if STM32_DMA2D_USE_DMA2D || defined(__DOXYGEN__) - -/* Ignore annoying warning messages for actually safe code.*/ -#if defined(__GNUC__) && !defined(__DOXYGEN__) -#pragma GCC diagnostic ignored "-Wtype-limits" -#endif - -/** - * @addtogroup dma2d - * @{ - */ - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/** @brief DMA2DD1 driver identifier.*/ -DMA2DDriver DMA2DD1; - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -/** - * @brief Bits per pixel lookup table. - */ -static const uint8_t dma2d_bpp[DMA2D_MAX_PIXFMT_ID + 1] = { - 32, /* DMA2D_FMT_ARGB8888 */ - 24, /* DMA2D_FMT_RGB888 */ - 16, /* DMA2D_FMT_RGB565 */ - 16, /* DMA2D_FMT_ARGB1555 */ - 16, /* DMA2D_FMT_ARGB4444 */ - 8, /* DMA2D_FMT_L8 */ - 8, /* DMA2D_FMT_AL44 */ - 16, /* DMA2D_FMT_AL88 */ - 4, /* DMA2D_FMT_L4 */ - 8, /* DMA2D_FMT_A8 */ - 4 /* DMA2D_FMT_A4 */ -}; - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @name DMA2D interrupt handlers - * @{ - */ - -/** - * @brief DMA2D global interrupt handler. - * - * @isr - */ -OSAL_IRQ_HANDLER(STM32_DMA2D_HANDLER) { - - DMA2DDriver *const dma2dp = &DMA2DD1; - bool job_done = false; - thread_t *tp = NULL; - - OSAL_IRQ_PROLOGUE(); - - /* Handle Configuration Error ISR.*/ - if ((DMA2D->ISR & DMA2D_ISR_CEIF) && (DMA2D->CR & DMA2D_CR_CEIE)) { - if (dma2dp->config->cfgerr_isr != NULL) - dma2dp->config->cfgerr_isr(dma2dp); - job_done = true; - DMA2D->IFCR |= DMA2D_IFSR_CCEIF; - } - - /* Handle CLUT (Palette) Transfer Complete ISR.*/ - if ((DMA2D->ISR & DMA2D_ISR_CTCIF) && (DMA2D->CR & DMA2D_CR_CTCIE)) { - if (dma2dp->config->paltrfdone_isr != NULL) - dma2dp->config->paltrfdone_isr(dma2dp); - job_done = true; - DMA2D->IFCR |= DMA2D_IFSR_CCTCIF; - } - - /* Handle CLUT (Palette) Access Error ISR.*/ - if ((DMA2D->ISR & DMA2D_ISR_CAEIF) && (DMA2D->CR & DMA2D_CR_CAEIE)) { - if (dma2dp->config->palacserr_isr != NULL) - dma2dp->config->palacserr_isr(dma2dp); - job_done = true; - DMA2D->IFCR |= DMA2D_IFSR_CCAEIF; - } - - /* Handle Transfer Watermark ISR.*/ - if ((DMA2D->ISR & DMA2D_ISR_TWIF) && (DMA2D->CR & DMA2D_CR_TWIE)) { - if (dma2dp->config->trfwmark_isr != NULL) - dma2dp->config->trfwmark_isr(dma2dp); - DMA2D->IFCR |= DMA2D_IFSR_CTWIF; - } - - /* Handle Transfer Complete ISR.*/ - if ((DMA2D->ISR & DMA2D_ISR_TCIF) && (DMA2D->CR & DMA2D_CR_TCIE)) { - if (dma2dp->config->trfdone_isr != NULL) - dma2dp->config->trfdone_isr(dma2dp); - job_done = true; - DMA2D->IFCR |= DMA2D_IFSR_CTCIF; - } - - /* Handle Transfer Error ISR.*/ - if ((DMA2D->ISR & DMA2D_ISR_TEIF) && (DMA2D->CR & DMA2D_CR_TEIE)) { - if (dma2dp->config->trferr_isr != NULL) - dma2dp->config->trferr_isr(dma2dp); - job_done = true; - DMA2D->IFCR |= DMA2D_IFSR_CTEIF; - } - - if (job_done) { - osalSysLockFromISR(); - osalDbgAssert(dma2dp->state == DMA2D_ACTIVE, "invalid state"); - - #if DMA2D_USE_WAIT - /* Wake the waiting thread up.*/ - if (dma2dp->thread != NULL) { - tp = dma2dp->thread; - dma2dp->thread = NULL; - tp->u.rdymsg = MSG_OK; - chSchReadyI(tp); - } - #endif /* DMA2D_USE_WAIT */ - - dma2dp->state = DMA2D_READY; - osalSysUnlockFromISR(); - } - - OSAL_IRQ_EPILOGUE(); -} - -/** @} */ - -/** - * @name DMA2D driver-specific methods - * @{ - */ - -/** - * @brief DMA2D Driver initialization. - * @details Initializes the DMA2D subsystem and chosen drivers. Should be - * called at board initialization. - * - * @init - */ -void dma2dInit(void) { - - /* Reset the DMA2D hardware module.*/ - rccResetDMA2D(); - - /* Enable the DMA2D clock.*/ - rccEnableDMA2D(false); - - /* Driver struct initialization.*/ - dma2dObjectInit(&DMA2DD1); - DMA2DD1.state = DMA2D_STOP; -} - -/** - * @brief Initializes the standard part of a @p DMA2DDriver structure. - * - * @param[out] dma2dp pointer to the @p DMA2DDriver object - * - * @init - */ -void dma2dObjectInit(DMA2DDriver *dma2dp) { - - osalDbgCheck(dma2dp == &DMA2DD1); - - dma2dp->state = DMA2D_UNINIT; - dma2dp->config = NULL; -#if DMA2D_USE_WAIT - dma2dp->thread = NULL; -#endif /* DMA2D_USE_WAIT */ -#if (TRUE == DMA2D_USE_MUTUAL_EXCLUSION) -#if (TRUE == CH_CFG_USE_MUTEXES) - chMtxObjectInit(&dma2dp->lock); -#else - chSemObjectInit(&dma2dp->lock, 1); -#endif -#endif /* (TRUE == DMA2D_USE_MUTUAL_EXCLUSION) */ -} - -/** - * @brief Get the driver state. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @retun driver state - * - * @iclass - */ -dma2d_state_t dma2dGetStateI(DMA2DDriver *dma2dp) { - - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgCheckClassI(); - - return dma2dp->state; -} - -/** - * @brief Get the driver state. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @retun driver state - * - * @api - */ -dma2d_state_t dma2dGetState(DMA2DDriver *dma2dp) { - - dma2d_state_t state; - chSysLock(); - state = dma2dGetStateI(dma2dp); - chSysUnlock(); - return state; -} - -/** - * @brief Configures and activates the DMA2D peripheral. - * @pre DMA2D is stopped. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] configp pointer to the @p DMA2DConfig object - * - * @api - */ -void dma2dStart(DMA2DDriver *dma2dp, const DMA2DConfig *configp) { - - chSysLock(); - - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgCheck(configp != NULL); - osalDbgAssert(dma2dp->state == DMA2D_STOP, "invalid state"); - - dma2dp->config = configp; - - /* Turn off the controller and its interrupts.*/ - DMA2D->CR = 0; - - /* Enable interrupts, except Line Watermark.*/ - nvicEnableVector(STM32_DMA2D_NUMBER, STM32_DMA2D_IRQ_PRIORITY); - - DMA2D->CR = (DMA2D_CR_CEIE | DMA2D_CR_CTCIE | DMA2D_CR_CAEIE | - DMA2D_CR_TCIE | DMA2D_CR_TEIE); - - dma2dp->state = DMA2D_READY; - chSysUnlock(); -} - -/** - * @brief Deactivates the DMA2D peripheral. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @api - */ -void dma2dStop(DMA2DDriver *dma2dp) { - - chSysLock(); - - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgAssert(dma2dp->state == DMA2D_READY, "invalid state"); -#if DMA2D_USE_WAIT - osalDbgAssert(dma2dp->thread == NULL, "still waiting"); -#endif /* DMA2D_USE_WAIT */ - - dma2dp->state = DMA2D_STOP; - chSysUnlock(); -} - -#if DMA2D_USE_MUTUAL_EXCLUSION - -/** - * @brief Gains exclusive access to the DMA2D module. - * @details This function tries to gain ownership to the DMA2D module, if the - * module is already being used then the invoking thread is queued. - * @pre In order to use this function the option - * @p DMA2D_USE_MUTUAL_EXCLUSION must be enabled. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @sclass - */ -void dma2dAcquireBusS(DMA2DDriver *dma2dp) { - - osalDbgCheckClassS(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); - -#if (TRUE == CH_CFG_USE_MUTEXES) - chMtxLockS(&dma2dp->lock); -#else - chSemWaitS(&dma2dp->lock); -#endif -} - -/** - * @brief Gains exclusive access to the DMA2D module. - * @details This function tries to gain ownership to the DMA2D module, if the - * module is already being used then the invoking thread is queued. - * @pre In order to use this function the option - * @p DMA2D_USE_MUTUAL_EXCLUSION must be enabled. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @api - */ -void dma2dAcquireBus(DMA2DDriver *dma2dp) { - - chSysLock(); - dma2dAcquireBusS(dma2dp); - chSysUnlock(); -} - -/** - * @brief Releases exclusive access to the DMA2D module. - * @pre In order to use this function the option - * @p DMA2D_USE_MUTUAL_EXCLUSION must be enabled. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @sclass - */ -void dma2dReleaseBusS(DMA2DDriver *dma2dp) { - - osalDbgCheckClassS(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); - -#if (TRUE == CH_CFG_USE_MUTEXES) - chMtxUnlockS(&dma2dp->lock); -#else - chSemSignalI(&dma2dp->lock); -#endif -} - -/** - * @brief Releases exclusive access to the DMA2D module. - * @pre In order to use this function the option - * @p DMA2D_USE_MUTUAL_EXCLUSION must be enabled. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @api - */ -void dma2dReleaseBus(DMA2DDriver *dma2dp) { - - chSysLock(); - dma2dReleaseBusS(dma2dp); - chSysUnlock(); -} - -#endif /* DMA2D_USE_MUTUAL_EXCLUSION */ - -/** @} */ - -/** - * @name DMA2D global methods - * @{ - */ - -/** - * @brief Get watermark position. - * @details Gets the watermark line position. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return watermark line position - * - * @iclass - */ -uint16_t dma2dGetWatermarkPosI(DMA2DDriver *dma2dp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - (void)dma2dp; - - return (uint16_t)(DMA2D->LWR & DMA2D_LWR_LW); -} - -/** - * @brief Get watermark position. - * @details Gets the watermark line position. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return watermark line position - * - * @api - */ -uint16_t dma2dGetWatermarkPos(DMA2DDriver *dma2dp) { - - uint16_t line; - chSysLock(); - line = dma2dGetWatermarkPosI(dma2dp); - chSysUnlock(); - return line; -} - -/** - * @brief Set watermark position. - * @details Sets the watermark line position. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] line watermark line position - * - * @iclass - */ -void dma2dSetWatermarkPosI(DMA2DDriver *dma2dp, uint16_t line) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); - (void)dma2dp; - - DMA2D->LWR = ((DMA2D->LWR & ~DMA2D_LWR_LW) | - ((uint32_t)line & DMA2D_LWR_LW)); -} - -/** - * @brief Set watermark position. - * @details Sets the watermark line position. - * @note The interrupt is invoked after the last pixel of the watermark line - * is written. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] line watermark line position - * - * @iclass - */ -void dma2dSetWatermarkPos(DMA2DDriver *dma2dp, uint16_t line) { - - chSysLock(); - dma2dSetWatermarkPosI(dma2dp, line); - chSysUnlock(); -} - -/** - * @brief Watermark interrupt enabled. - * @details Tells whether the watermark interrupt is enabled. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return enabled - * - * @iclass - */ -bool dma2dIsWatermarkEnabledI(DMA2DDriver *dma2dp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - (void)dma2dp; - - return (DMA2D->CR & DMA2D_CR_TWIE) != 0; -} - -/** - * @brief Watermark interrupt enabled. - * @details Tells whether the watermark interrupt is enabled. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return enabled - * - * @api - */ -bool dma2dIsWatermarkEnabled(DMA2DDriver *dma2dp) { - - bool enabled; - chSysLock(); - enabled = dma2dIsWatermarkEnabledI(dma2dp); - chSysUnlock(); - return enabled; -} - -/** - * @brief Enable watermark interrupt. - * @details Enables the watermark interrupt. The interrupt is invoked after the - * last pixel of the watermark line is written to the output layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @iclass - */ -void dma2dEnableWatermarkI(DMA2DDriver *dma2dp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - (void)dma2dp; - - DMA2D->CR |= DMA2D_CR_TWIE; -} - -/** - * @brief Enable watermark interrupt. - * @details Enables the watermark interrupt. The interrupt is invoked after the - * last pixel of the watermark line is written to the output layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @api - */ -void dma2dEnableWatermark(DMA2DDriver *dma2dp) { - - chSysLock(); - dma2dEnableWatermarkI(dma2dp); - chSysUnlock(); -} - -/** - * @brief Disable watermark interrupt. - * @details Disables the watermark interrupt. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @iclass - */ -void dma2dDisableWatermarkI(DMA2DDriver *dma2dp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - (void)dma2dp; - - DMA2D->CR &= ~DMA2D_CR_TWIE; -} - -/** - * @brief Disable watermark interrupt. - * @details Disables the watermark interrupt. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @api - */ -void dma2dDisableWatermark(DMA2DDriver *dma2dp) { - - chSysLock(); - dma2dDisableWatermarkI(dma2dp); - chSysUnlock(); -} - -/** - * @brief Get dead time cycles. - * @details Gets the minimum dead time DMA2D clock cycles between DMA2D - * transactions. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return dead time, in DMA2D clock cycles - * - * @iclass - */ -uint32_t dma2dGetDeadTimeI(DMA2DDriver *dma2dp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - (void)dma2dp; - - return (DMA2D->AMTCR & DMA2D_AMTCR_DT) >> 8; -} - -/** - * @brief Get dead time cycles. - * @details Gets the minimum dead time DMA2D clock cycles between DMA2D - * transactions. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return dead time, in DMA2D clock cycles - * - * @api - */ -uint32_t dma2dGetDeadTime(DMA2DDriver *dma2dp) { - - uint32_t cycles; - chSysLock(); - cycles = dma2dGetDeadTimeI(dma2dp); - chSysUnlock(); - return cycles; -} - -/** - * @brief Set dead time cycles. - * @details Sets the minimum dead time DMA2D clock cycles between DMA2D - * transactions. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] cycles dead time, in DMA2D clock cycles - * - * @iclass - */ -void dma2dSetDeadTimeI(DMA2DDriver *dma2dp, uint32_t cycles) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgAssert(cycles <= DMA2D_MAX_DEADTIME_CYCLES, "bounds"); - (void)dma2dp; - - DMA2D->AMTCR = ((DMA2D->AMTCR & ~DMA2D_AMTCR_DT) | - ((cycles << 8) & DMA2D_AMTCR_DT)); -} - -/** - * @brief Set dead time cycles. - * @details Sets the minimum dead time DMA2D clock cycles between DMA2D - * transactions. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] cycles dead time, in DMA2D clock cycles - * - * @api - */ -void dma2dSetDeadTime(DMA2DDriver *dma2dp, uint32_t cycles) { - - chSysLock(); - dma2dSetDeadTimeI(dma2dp, cycles); - chSysUnlock(); -} - -/** - * @brief Dead time enabled. - * @details Tells whether the dead time between DMA2D transactions is enabled. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return enabled - * - * @iclass - */ -bool dma2dIsDeadTimeEnabledI(DMA2DDriver *dma2dp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - (void)dma2dp; - - return (DMA2D->AMTCR & DMA2D_AMTCR_EN) != 0; -} - -/** - * @brief Dead time enabled. - * @details Tells whether the dead time between DMA2D transactions is enabled. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return enabled - * - * @api - */ -bool dma2dIsDeadTimeEnabled(DMA2DDriver *dma2dp) { - - bool enabled; - chSysLock(); - enabled = dma2dIsDeadTimeEnabledI(dma2dp); - chSysUnlock(); - return enabled; -} - -/** - * @brief Enable dead time. - * @details Enables the dead time between DMA2D transactions. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @iclass - */ -void dma2dEnableDeadTimeI(DMA2DDriver *dma2dp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - (void)dma2dp; - - DMA2D->AMTCR |= DMA2D_AMTCR_EN; -} - -/** - * @brief Enable dead time. - * @details Enables the dead time between DMA2D transactions. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @api - */ -void dma2dEnableDeadTime(DMA2DDriver *dma2dp) { - - chSysLock(); - dma2dEnableDeadTimeI(dma2dp); - chSysUnlock(); -} - -/** - * @brief Disable dead time. - * @details Disables the dead time between DMA2D transactions. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @iclass - */ -void dma2dDisableDeadTimeI(DMA2DDriver *dma2dp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - (void)dma2dp; - - DMA2D->AMTCR &= ~DMA2D_AMTCR_EN; -} - -/** - * @brief Disable dead time. - * @details Disables the dead time between DMA2D transactions. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @api - */ -void dma2dDisableDeadTime(DMA2DDriver *dma2dp) { - - chSysLock(); - dma2dDisableDeadTimeI(dma2dp); - chSysUnlock(); -} - -/** @} */ - -/** - * @name DMA2D job (transaction) methods - * @{ - */ - -/** - * @brief Get job mode. - * @details Gets the job mode. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return job mode - * - * @iclass - */ -dma2d_jobmode_t dma2dJobGetModeI(DMA2DDriver *dma2dp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - (void)dma2dp; - - return (dma2d_jobmode_t)(DMA2D->CR & DMA2D_CR_MODE); -} - -/** - * @brief Get job mode. - * @details Gets the job mode. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return job mode - * - * @api - */ -dma2d_jobmode_t dma2dJobGetMode(DMA2DDriver *dma2dp) { - - dma2d_jobmode_t mode; - chSysLock(); - mode = dma2dJobGetModeI(dma2dp); - chSysUnlock(); - return mode; -} - -/** - * @brief Set job mode. - * @details Sets the job mode. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] mode job mode - * - * @iclass - */ -void dma2dJobSetModeI(DMA2DDriver *dma2dp, dma2d_jobmode_t mode) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); - osalDbgAssert((mode & ~DMA2D_CR_MODE) == 0, "bounds"); - (void)dma2dp; - - DMA2D->CR = ((DMA2D->CR & ~DMA2D_CR_MODE) | - ((uint32_t)mode & DMA2D_CR_MODE)); -} - -/** - * @brief Set job mode. - * @details Sets the job mode. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] mode job mode - * - * @api - */ -void dma2dJobSetMode(DMA2DDriver *dma2dp, dma2d_jobmode_t mode) { - - chSysLock(); - dma2dJobSetModeI(dma2dp, mode); - chSysUnlock(); -} - -/** - * @brief Get job size. - * @details Gets the job size. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[out] widthp pointer to the job width, in pixels - * @param[out] heightp pointer to the job height, in pixels - * - * @iclass - */ -void dma2dJobGetSizeI(DMA2DDriver *dma2dp, - uint16_t *widthp, uint16_t *heightp) { - - uint32_t r; - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgCheck(widthp != NULL); - osalDbgCheck(heightp != NULL); - (void)dma2dp; - - r = DMA2D->NLR; - *widthp = (uint16_t)((r & DMA2D_NLR_PL) >> 16); - *heightp = (uint16_t)((r & DMA2D_NLR_NL) >> 0); -} - -/** - * @brief Get job size. - * @details Gets the job size. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[out] widthp pointer to the job width, in pixels - * @param[out] heightp pointer to the job height, in pixels - * - * @api - */ -void dma2dJobGetSize(DMA2DDriver *dma2dp, - uint16_t *widthp, uint16_t *heightp) { - - chSysLock(); - dma2dJobGetSizeI(dma2dp, widthp, heightp); - chSysUnlock(); -} - -/** - * @brief Set job size. - * @details Sets the job size. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] widthp job width, in pixels - * @param[in] heightp job height, in pixels - * - * @iclass - */ -void dma2dJobSetSizeI(DMA2DDriver *dma2dp, uint16_t width, uint16_t height) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); - osalDbgAssert(width <= DMA2D_MAX_WIDTH, "bounds"); - osalDbgAssert(height <= DMA2D_MAX_HEIGHT, "bounds"); - (void)dma2dp; - - DMA2D->NLR = ((((uint32_t)width << 16) & DMA2D_NLR_PL) | - (((uint32_t)height << 0) & DMA2D_NLR_NL)); -} - -/** - * @brief Set job size. - * @details Sets the job size. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] widthp job width, in pixels - * @param[in] heightp job height, in pixels - * - * @api - */ -void dma2dJobSetSize(DMA2DDriver *dma2dp, uint16_t width, uint16_t height) { - - chSysLock(); - dma2dJobSetSizeI(dma2dp, width, height); - chSysUnlock(); -} - -/** - * @brief Job executing. - * @details Tells whether a job (transaction) is active or paused. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return executing - * - * @iclass - */ -bool dma2dJobIsExecutingI(DMA2DDriver *dma2dp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - - return dma2dp->state > DMA2D_READY; -} - -/** - * @brief Job executing. - * @details Tells whether a job (transaction) is active or paused. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return executing - * - * @api - */ -bool dma2dJobIsExecuting(DMA2DDriver *dma2dp) { - - bool executing; - chSysLock(); - executing = dma2dJobIsExecutingI(dma2dp); - chSysUnlock(); - return executing; -} - -/** - * @brief Start job. - * @details The job is started, and the DMA2D is set to active. - * @note Should there be invalid parameters, the appropriate interrupt - * handler will be invoked, and the DMA2D set back to ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @iclass - */ -void dma2dJobStartI(DMA2DDriver *dma2dp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); - - dma2dp->state = DMA2D_ACTIVE; - DMA2D->CR |= DMA2D_CR_START; -} - -/** - * @brief Start job. - * @details The job is started, and the DMA2D is set to active. - * @note Should there be invalid parameters, the appropriate interrupt - * handler will be invoked, and the DMA2D set back to ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @api - */ -void dma2dJobStart(DMA2DDriver *dma2dp) { - - chSysLock(); - dma2dJobStartI(dma2dp); - chSysUnlock(); -} - -/** - * @brief Execute job. - * @details Starts the job and waits for its completion, synchronously. - * @note Should there be invalid parameters, the appropriate interrupt - * handler will be invoked, and the DMA2D set back to ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @sclass - */ -void dma2dJobExecuteS(DMA2DDriver *dma2dp) { - - osalDbgCheckClassS(); - osalDbgCheck(dma2dp == &DMA2DD1); - - dma2dJobStartI(dma2dp); -#if DMA2D_USE_WAIT - dma2dp->thread = chThdGetSelfX(); - chSchGoSleepS(CH_STATE_SUSPENDED); -#else - while (DMA2D->CR & DMA2D_CR_START) - chSchDoYieldS(); -#endif -} - -/** - * @brief Execute job. - * @details Starts the job and waits for its completion, synchronously. - * @note Should there be invalid parameters, the appropriate interrupt - * handler will be invoked, and the DMA2D set back to ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @api - */ -void dma2dJobExecute(DMA2DDriver *dma2dp) { - - chSysLock(); - dma2dJobExecuteS(dma2dp); - chSysUnlock(); -} - -/** - * @brief Suspend current job. - * @details Suspends the current job. The driver is set to a paused state. - * @pre There is an active job. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @iclass - */ -void dma2dJobSuspendI(DMA2DDriver *dma2dp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgCheck((DMA2D->CR & DMA2D_CR_SUSP) == 0); - osalDbgAssert(dma2dp->state == DMA2D_ACTIVE, "invalid state"); - - dma2dp->state = DMA2D_PAUSED; - DMA2D->CR |= DMA2D_CR_SUSP; -} - -/** - * @brief Suspend current job. - * @details Suspends the current job. The driver is set to a paused state. - * @pre There is an active job. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @api - */ -void dma2dJobSuspend(DMA2DDriver *dma2dp) { - - chSysLock(); - dma2dJobSuspendI(dma2dp); - chSysUnlock(); -} - -/** - * @brief Resume current job. - * @details Resumes the current job. - * @pre There is a paused job. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @iclass - */ -void dma2dJobResumeI(DMA2DDriver *dma2dp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgCheck((DMA2D->CR & DMA2D_CR_SUSP) != 0); - osalDbgAssert(dma2dp->state == DMA2D_PAUSED, "invalid state"); - - dma2dp->state = DMA2D_ACTIVE; - DMA2D->CR &= ~DMA2D_CR_SUSP; -} - -/** - * @brief Resume current job. - * @details Resumes the current job. - * @pre There is a paused job. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @api - */ -void dma2dJobResume(DMA2DDriver *dma2dp) { - - chSysLock(); - dma2dJobResumeI(dma2dp); - chSysUnlock(); -} - -/** - * @brief Abort current job. - * @details Abots the current job (if any), and the driver becomes ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @iclass - */ -void dma2dJobAbortI(DMA2DDriver *dma2dp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgCheck((DMA2D->CR & DMA2D_CR_SUSP) == 0); - osalDbgAssert(dma2dp->state >= DMA2D_READY, "invalid state"); - - dma2dp->state = DMA2D_READY; - DMA2D->CR |= DMA2D_CR_ABORT; -} - -/** - * @brief Abort current job. - * @details Abots the current job (if any), and the driver becomes ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @api - */ -void dma2dJobAbort(DMA2DDriver *dma2dp) { - - chSysLock(); - dma2dJobAbortI(dma2dp); - chSysUnlock(); -} - -/** @} */ - -/** - * @name DMA2D background layer methods - * @{ - */ - -/** - * @brief Get background layer buffer address. - * @details Gets the buffer address of the background layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return buffer address - * - * @iclass - */ -void *dma2dBgGetAddressI(DMA2DDriver *dma2dp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - (void)dma2dp; - - return (void *)DMA2D->BGMAR; -} - -/** - * @brief Get background layer buffer address. - * @details Gets the buffer address of the background layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return buffer address - * - * @api - */ -void *dma2dBgGetAddress(DMA2DDriver *dma2dp) { - - void *bufferp; - chSysLock(); - bufferp = dma2dBgGetAddressI(dma2dp); - chSysUnlock(); - return bufferp; -} - -/** - * @brief Set background layer buffer address. - * @details Sets the buffer address of the background layer. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] bufferp buffer address - * - * @iclass - */ -void dma2dBgSetAddressI(DMA2DDriver *dma2dp, void *bufferp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); - osalDbgCheck(dma2dIsAligned(bufferp, dma2dBgGetPixelFormatI(dma2dp))); - (void)dma2dp; - - DMA2D->BGMAR = (uint32_t)bufferp; -} - -/** - * @brief Set background layer buffer address. - * @details Sets the buffer address of the background layer. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] bufferp buffer address - * - * @api - */ -void dma2dBgSetAddress(DMA2DDriver *dma2dp, void *bufferp) { - - chSysLock(); - dma2dBgSetAddressI(dma2dp, bufferp); - chSysUnlock(); -} - -/** - * @brief Get background layer wrap offset. - * @details Gets the buffer line wrap offset of the background layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return wrap offset, in pixels - * - * @iclass - */ -size_t dma2dBgGetWrapOffsetI(DMA2DDriver *dma2dp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - (void)dma2dp; - - return (size_t)(DMA2D->BGOR & DMA2D_BGOR_LO); -} - -/** - * @brief Get background layer wrap offset. - * @details Gets the buffer line wrap offset of the background layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return wrap offset, in pixels - * - * @api - */ -size_t dma2dBgGetWrapOffset(DMA2DDriver *dma2dp) { - - size_t offset; - chSysLock(); - offset = dma2dBgGetWrapOffsetI(dma2dp); - chSysUnlock(); - return offset; -} - -/** - * @brief Set background layer wrap offset. - * @details Sets the buffer line wrap offset of the background layer. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] offset wrap offset, in pixels - * - * @iclass - */ -void dma2dBgSetWrapOffsetI(DMA2DDriver *dma2dp, size_t offset) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); - osalDbgAssert(offset <= DMA2D_MAX_OFFSET, "bounds"); - (void)dma2dp; - - DMA2D->BGOR = ((DMA2D->BGOR & ~DMA2D_BGOR_LO) | - ((uint32_t)offset & DMA2D_BGOR_LO)); -} - -/** - * @brief Set background layer wrap offset. - * @details Sets the buffer line wrap offset of the background layer. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] offset wrap offset, in pixels - * - * @api - */ -void dma2dBgSetWrapOffset(DMA2DDriver *dma2dp, size_t offset) { - - chSysLock(); - dma2dBgSetWrapOffsetI(dma2dp, offset); - chSysUnlock(); -} - -/** - * @brief Get background layer constant alpha. - * @details Gets the constant alpha component of the background layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return constant alpha component, A-8 - * - * @iclass - */ -uint8_t dma2dBgGetConstantAlphaI(DMA2DDriver *dma2dp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - (void)dma2dp; - - return (uint8_t)((DMA2D->BGPFCCR & DMA2D_BGPFCCR_ALPHA) >> 24); -} - -/** - * @brief Get background layer constant alpha. - * @details Gets the constant alpha component of the background layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return constant alpha component, A-8 - * - * @api - */ -uint8_t dma2dBgGetConstantAlpha(DMA2DDriver *dma2dp) { - - uint8_t a; - chSysLock(); - a = dma2dBgGetConstantAlphaI(dma2dp); - chSysUnlock(); - return a; -} - -/** - * @brief Set background layer constant alpha. - * @details Sets the constant alpha component of the background layer. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] a constant alpha component, A-8 - * - * @iclass - */ -void dma2dBgSetConstantAlphaI(DMA2DDriver *dma2dp, uint8_t a) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); - (void)dma2dp; - - DMA2D->BGPFCCR = ((DMA2D->BGPFCCR & ~DMA2D_BGPFCCR_ALPHA) | - (((uint32_t)a << 24) & DMA2D_BGPFCCR_ALPHA)); -} - -/** - * @brief Set background layer constant alpha. - * @details Sets the constant alpha component of the background layer. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] a constant alpha component, A-8 - * - * @api - */ -void dma2dBgSetConstantAlpha(DMA2DDriver *dma2dp, uint8_t a) { - - chSysLock(); - dma2dBgSetConstantAlphaI(dma2dp, a); - chSysUnlock(); -} - -/** - * @brief Get background layer alpha mode. - * @details Gets the alpha mode of the background layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return alpha mode - * - * @iclass - */ -dma2d_amode_t dma2dBgGetAlphaModeI(DMA2DDriver *dma2dp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - (void)dma2dp; - - return (dma2d_amode_t)(DMA2D->BGPFCCR & DMA2D_BGPFCCR_AM); -} - -/** - * @brief Get background layer alpha mode. - * @details Gets the alpha mode of the background layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return alpha mode - * - * @api - */ -dma2d_amode_t dma2dBgGetAlphaMode(DMA2DDriver *dma2dp) { - - dma2d_amode_t mode; - chSysLock(); - mode = dma2dBgGetAlphaModeI(dma2dp); - chSysUnlock(); - return mode; -} - -/** - * @brief Set background layer alpha mode. - * @details Sets the alpha mode of the background layer. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] mode alpha mode - * - * @iclass - */ -void dma2dBgSetAlphaModeI(DMA2DDriver *dma2dp, dma2d_amode_t mode) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); - osalDbgAssert((mode & ~DMA2D_BGPFCCR_AM) == 0, "bounds"); - osalDbgAssert((mode & DMA2D_BGPFCCR_AM) != DMA2D_BGPFCCR_AM, "bounds"); - (void)dma2dp; - - DMA2D->BGPFCCR = ((DMA2D->BGPFCCR & ~DMA2D_BGPFCCR_AM) | - ((uint32_t)mode & DMA2D_BGPFCCR_AM)); -} - -/** - * @brief Set background layer alpha mode. - * @details Sets the alpha mode of the background layer. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] mode alpha mode - * - * @api - */ -void dma2dBgSetAlphaMode(DMA2DDriver *dma2dp, dma2d_amode_t mode) { - - chSysLock(); - dma2dBgSetAlphaModeI(dma2dp, mode); - chSysUnlock(); -} - -/** - * @brief Get background layer pixel format. - * @details Gets the pixel format of the background layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return pixel format - * - * @iclass - */ -dma2d_pixfmt_t dma2dBgGetPixelFormatI(DMA2DDriver *dma2dp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - (void)dma2dp; - - return (dma2d_pixfmt_t)(DMA2D->BGPFCCR & DMA2D_BGPFCCR_CM); -} - -/** - * @brief Get background layer pixel format. - * @details Gets the pixel format of the background layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return pixel format - * - * @api - */ -dma2d_pixfmt_t dma2dBgGetPixelFormat(DMA2DDriver *dma2dp) { - - dma2d_pixfmt_t fmt; - chSysLock(); - fmt = dma2dBgGetPixelFormatI(dma2dp); - chSysUnlock(); - return fmt; -} - -/** - * @brief Set background layer pixel format. - * @details Sets the pixel format of the background layer. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] fmt pixel format - * - * @iclass - */ -void dma2dBgSetPixelFormatI(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); - osalDbgAssert(fmt <= DMA2D_MAX_PIXFMT_ID, "bounds"); - (void)dma2dp; - - DMA2D->BGPFCCR = ((DMA2D->BGPFCCR & ~DMA2D_BGPFCCR_CM) | - ((uint32_t)fmt & DMA2D_BGPFCCR_CM)); -} - -/** - * @brief Set background layer pixel format. - * @details Sets the pixel format of the background layer. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] fmt pixel format - * - * @api - */ -void dma2dBgSetPixelFormat(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt) { - - chSysLock(); - dma2dBgSetPixelFormatI(dma2dp, fmt); - chSysUnlock(); -} - -/** - * @brief Get background layer default color. - * @details Gets the default color of the background layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return default color, RGB-888 - * - * @iclass - */ -dma2d_color_t dma2dBgGetDefaultColorI(DMA2DDriver *dma2dp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - (void)dma2dp; - - return (dma2d_color_t)(DMA2D->BGCOLR & 0x00FFFFFF); -} - -/** - * @brief Get background layer default color. - * @details Gets the default color of the background layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return default color, RGB-888 - * - * @api - */ -dma2d_color_t dma2dBgGetDefaultColor(DMA2DDriver *dma2dp) { - - dma2d_color_t c; - chSysLock(); - c = dma2dBgGetDefaultColorI(dma2dp); - chSysUnlock(); - return c; -} - -/** - * @brief Set background layer default color. - * @details Sets the default color of the background layer. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] c default color, RGB-888 - * - * @iclass - */ -void dma2dBgSetDefaultColorI(DMA2DDriver *dma2dp, dma2d_color_t c) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); - (void)dma2dp; - - DMA2D->BGCOLR = (uint32_t)c & 0x00FFFFFF; -} - -/** - * @brief Set background layer default color. - * @details Sets the default color of the background layer. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] c default color, RGB-888 - * - * @api - */ -void dma2dBgSetDefaultColor(DMA2DDriver *dma2dp, dma2d_color_t c) { - - chSysLock(); - dma2dBgSetDefaultColorI(dma2dp, c); - chSysUnlock(); -} - -/** - * @brief Get background layer palette specifications. - * @details Gets the palette specifications of the background layer. - * @note The palette colors pointer is actually addressed to a @p volatile - * memory zone. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[out] palettep pointer to the palette specifications - * - * @iclass - */ -void dma2dBgGetPaletteI(DMA2DDriver *dma2dp, dma2d_palcfg_t *palettep) { - - uint32_t r; - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgCheck(palettep != NULL); - (void)dma2dp; - - r = DMA2D->BGPFCCR; - palettep->colorsp = (const void *)DMA2D->BGCLUT; - palettep->length = (uint16_t)((r & DMA2D_BGPFCCR_CS) >> 8) + 1; - palettep->fmt = (dma2d_pixfmt_t)((r & DMA2D_BGPFCCR_CCM) >> 4); -} - -/** - * @brief Get background layer palette specifications. - * @details Gets the palette specifications of the background layer. - * @note The palette colors pointer is actually addressed to a @p volatile - * memory zone. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[out] palettep pointer to the palette specifications - * - * @api - */ -void dma2dBgGetPalette(DMA2DDriver *dma2dp, dma2d_palcfg_t *palettep) { - - chSysLock(); - dma2dBgGetPaletteI(dma2dp, palettep); - chSysUnlock(); -} - -/** - * @brief Set background layer palette specifications. - * @details Sets the palette specifications of the background layer. - * @note This function should not be called while the DMA2D is already - * executing a job, otherwise the appropriate error interrupt might be - * invoked. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] palettep pointer to the palette specifications - * - * @sclass - */ -void dma2dBgSetPaletteS(DMA2DDriver *dma2dp, const dma2d_palcfg_t *palettep) { - - osalDbgCheckClassS(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); - osalDbgCheck(palettep != NULL); - osalDbgCheck(palettep->colorsp != NULL); - osalDbgAssert(palettep->length > 0, "bounds"); - osalDbgAssert(palettep->length <= DMA2D_MAX_PALETTE_LENGTH, "bounds"); - osalDbgAssert(((palettep->fmt == DMA2D_FMT_ARGB8888) || - (palettep->fmt == DMA2D_FMT_RGB888)), "invalid format"); - - DMA2D->BGCMAR = (uint32_t)palettep->colorsp; - DMA2D->BGPFCCR = ( - (DMA2D->BGPFCCR & ~(DMA2D_BGPFCCR_CS | DMA2D_BGPFCCR_CCM)) | - ((((uint32_t)palettep->length - 1) << 8) & DMA2D_BGPFCCR_CS) | - ((uint32_t)palettep->fmt << 4) - ); - - dma2dp->state = DMA2D_ACTIVE; - DMA2D->BGPFCCR |= DMA2D_BGPFCCR_START; - -#if DMA2D_USE_WAIT - dma2dp->thread = chThdGetSelfX(); - chSchGoSleepS(CH_STATE_SUSPENDED); -#else - while (DMA2D->BGPFCCR & DMA2D_BGPFCCR_START) - chSchDoYieldS(); -#endif /* DMA2D_USE_WAIT */ -} - -/** - * @brief Set background layer palette specifications. - * @details Sets the palette specifications of the background layer. - * @note This function should not be called while the DMA2D is already - * executing a job, otherwise the appropriate error interrupt might be - * invoked. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] palettep pointer to the palette specifications - * - * @api - */ -void dma2dBgSetPalette(DMA2DDriver *dma2dp, const dma2d_palcfg_t *palettep) { - - chSysLock(); - dma2dBgSetPaletteS(dma2dp, palettep); - chSysUnlock(); -} - -/** - * @brief Get background layer specifications. - * @details Gets the background layer specifications at once. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[out] cfgp pointer to the layer specifications - * - * @iclass - */ -void dma2dBgGetLayerI(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgCheck(cfgp != NULL); - - cfgp->bufferp = dma2dBgGetAddressI(dma2dp); - cfgp->wrap_offset = dma2dBgGetWrapOffsetI(dma2dp); - cfgp->fmt = dma2dBgGetPixelFormatI(dma2dp); - cfgp->def_color = dma2dBgGetDefaultColorI(dma2dp); - cfgp->const_alpha = dma2dBgGetConstantAlphaI(dma2dp); - if (cfgp->palettep != NULL) - dma2dBgGetPaletteI(dma2dp, (dma2d_palcfg_t *)cfgp->palettep); -} - -/** - * @brief Get background layer specifications. - * @details Gets the background layer specifications at once. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[out] cfgp pointer to the layer specifications - * - * @api - */ -void dma2dBgGetLayer(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp) { - - chSysLock(); - dma2dBgGetLayerI(dma2dp, cfgp); - chSysUnlock(); -} - -/** - * @brief Set background layer specifications. - * @details Sets the background layer specifications at once. - * @note If the palette is unspecified, the layer palette is unmodified. - * @note This function should not be called while the DMA2D is already - * executing a job, otherwise the appropriate error interrupt might be - * invoked. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] cfgp pointer to the layer specifications - * - * @sclass - */ -void dma2dBgSetConfigS(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp) { - - osalDbgCheckClassS(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); - osalDbgCheck(cfgp != NULL); - - dma2dBgSetAddressI(dma2dp, cfgp->bufferp); - dma2dBgSetWrapOffsetI(dma2dp, cfgp->wrap_offset); - dma2dBgSetPixelFormatI(dma2dp, cfgp->fmt); - dma2dBgSetDefaultColorI(dma2dp, cfgp->def_color); - dma2dBgSetConstantAlphaI(dma2dp, cfgp->const_alpha); - if (cfgp->palettep != NULL) - dma2dBgSetPaletteS(dma2dp, cfgp->palettep); -} - -/** - * @brief Set background layer specifications. - * @details Sets the background layer specifications at once. - * @note If the palette is unspecified, the layer palette is unmodified. - * @note This function should not be called while the DMA2D is already - * executing a job, otherwise the appropriate error interrupt might be - * invoked. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] cfgp pointer to the layer specifications - * - * @api - */ -void dma2dBgSetConfig(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp) { - - chSysLock(); - dma2dBgSetConfigS(dma2dp, cfgp); - chSysUnlock(); -} - -/** @} */ - -/** - * @name DMA2D foreground layer methods - * @{ - */ - -/** - * @brief Get foreground layer buffer address. - * @details Gets the buffer address of the foreground layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return buffer address - * - * @iclass - */ -void *dma2dFgGetAddressI(DMA2DDriver *dma2dp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - (void)dma2dp; - - return (void *)DMA2D->FGMAR; -} - -/** - * @brief Get foreground layer buffer address. - * @details Gets the buffer address of the foreground layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return buffer address - * - * @api - */ -void *dma2dFgGetAddress(DMA2DDriver *dma2dp) { - - void *bufferp; - chSysLock(); - bufferp = dma2dFgGetAddressI(dma2dp); - chSysUnlock(); - return bufferp; -} - -/** - * @brief Set foreground layer buffer address. - * @details Sets the buffer address of the foreground layer. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] bufferp buffer address - * - * @iclass - */ -void dma2dFgSetAddressI(DMA2DDriver *dma2dp, void *bufferp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); - osalDbgCheck(dma2dIsAligned(bufferp, dma2dFgGetPixelFormatI(dma2dp))); - (void)dma2dp; - - DMA2D->FGMAR = (uint32_t)bufferp; -} - -/** - * @brief Set foreground layer buffer address. - * @details Sets the buffer address of the foreground layer. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] bufferp buffer address - * - * @api - */ -void dma2dFgSetAddress(DMA2DDriver *dma2dp, void *bufferp) { - - chSysLock(); - dma2dFgSetAddressI(dma2dp, bufferp); - chSysUnlock(); -} - -/** - * @brief Get foreground layer wrap offset. - * @details Gets the buffer line wrap offset of the foreground layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return wrap offset, in pixels - * - * @iclass - */ -size_t dma2dFgGetWrapOffsetI(DMA2DDriver *dma2dp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - (void)dma2dp; - - return (size_t)(DMA2D->FGOR & DMA2D_FGOR_LO); -} - -/** - * @brief Get foreground layer wrap offset. - * @details Gets the buffer line wrap offset of the foreground layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return wrap offset, in pixels - * - * @api - */ -size_t dma2dFgGetWrapOffset(DMA2DDriver *dma2dp) { - - size_t offset; - chSysLock(); - offset = dma2dFgGetWrapOffsetI(dma2dp); - chSysUnlock(); - return offset; -} - -/** - * @brief Set foreground layer wrap offset. - * @details Sets the buffer line wrap offset of the foreground layer. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] offset wrap offset, in pixels - * - * @iclass - */ -void dma2dFgSetWrapOffsetI(DMA2DDriver *dma2dp, size_t offset) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); - osalDbgAssert(offset <= DMA2D_MAX_OFFSET, "bounds"); - (void)dma2dp; - - DMA2D->FGOR = ((DMA2D->FGOR & ~DMA2D_FGOR_LO) | - ((uint32_t)offset & DMA2D_FGOR_LO)); -} - -/** - * @brief Set foreground layer wrap offset. - * @details Sets the buffer line wrap offset of the foreground layer. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] offset wrap offset, in pixels - * - * @api - */ -void dma2dFgSetWrapOffset(DMA2DDriver *dma2dp, size_t offset) { - - chSysLock(); - dma2dFgSetWrapOffsetI(dma2dp, offset); - chSysUnlock(); -} - -/** - * @brief Get foreground layer constant alpha. - * @details Gets the constant alpha component of the foreground layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return constant alpha component, A-8 - * - * @iclass - */ -uint8_t dma2dFgGetConstantAlphaI(DMA2DDriver *dma2dp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - (void)dma2dp; - - return (uint8_t)((DMA2D->FGPFCCR & DMA2D_FGPFCCR_ALPHA) >> 24); -} - -/** - * @brief Get foreground layer constant alpha. - * @details Gets the constant alpha component of the foreground layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return constant alpha component, A-8 - * - * @api - */ -uint8_t dma2dFgGetConstantAlpha(DMA2DDriver *dma2dp) { - - uint8_t a; - chSysLock(); - a = dma2dFgGetConstantAlphaI(dma2dp); - chSysUnlock(); - return a; -} - -/** - * @brief Set foreground layer constant alpha. - * @details Sets the constant alpha component of the foreground layer. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] a constant alpha component, A-8 - * - * @iclass - */ -void dma2dFgSetConstantAlphaI(DMA2DDriver *dma2dp, uint8_t a) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); - (void)dma2dp; - - DMA2D->FGPFCCR = ((DMA2D->FGPFCCR & ~DMA2D_FGPFCCR_ALPHA) | - (((uint32_t)a << 24) & DMA2D_FGPFCCR_ALPHA)); -} - -/** - * @brief Set foreground layer constant alpha. - * @details Sets the constant alpha component of the foreground layer. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] a constant alpha component, A-8 - * - * @api - */ -void dma2dFgSetConstantAlpha(DMA2DDriver *dma2dp, uint8_t a) { - - chSysLock(); - dma2dFgSetConstantAlphaI(dma2dp, a); - chSysUnlock(); -} - -/** - * @brief Get foreground layer alpha mode. - * @details Gets the alpha mode of the foreground layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return alpha mode - * - * @iclass - */ -dma2d_amode_t dma2dFgGetAlphaModeI(DMA2DDriver *dma2dp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - (void)dma2dp; - - return (dma2d_amode_t)(DMA2D->FGPFCCR & DMA2D_FGPFCCR_AM); -} - -/** - * @brief Get foreground layer alpha mode. - * @details Gets the alpha mode of the foreground layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return alpha mode - * - * @api - */ -dma2d_amode_t dma2dFgGetAlphaMode(DMA2DDriver *dma2dp) { - - dma2d_amode_t mode; - chSysLock(); - mode = dma2dFgGetAlphaModeI(dma2dp); - chSysUnlock(); - return mode; -} - -/** - * @brief Set foreground layer alpha mode. - * @details Sets the alpha mode of the foreground layer. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] mode alpha mode - * - * @iclass - */ -void dma2dFgSetAlphaModeI(DMA2DDriver *dma2dp, dma2d_amode_t mode) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); - osalDbgAssert((mode & ~DMA2D_FGPFCCR_AM) == 0, "bounds"); - osalDbgAssert((mode & DMA2D_FGPFCCR_AM) != DMA2D_FGPFCCR_AM, "bounds"); - (void)dma2dp; - - DMA2D->FGPFCCR = ((DMA2D->FGPFCCR & ~DMA2D_FGPFCCR_AM) | - ((uint32_t)mode & DMA2D_FGPFCCR_AM)); -} - -/** - * @brief Set foreground layer alpha mode. - * @details Sets the alpha mode of the foreground layer. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] mode alpha mode - * - * @api - */ -void dma2dFgSetAlphaMode(DMA2DDriver *dma2dp, dma2d_amode_t mode) { - - chSysLock(); - dma2dFgSetAlphaModeI(dma2dp, mode); - chSysUnlock(); -} - -/** - * @brief Get foreground layer pixel format. - * @details Gets the pixel format of the foreground layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return pixel format - * - * @iclass - */ -dma2d_pixfmt_t dma2dFgGetPixelFormatI(DMA2DDriver *dma2dp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - (void)dma2dp; - - return (dma2d_pixfmt_t)(DMA2D->FGPFCCR & DMA2D_FGPFCCR_CM); -} - -/** - * @brief Get foreground layer pixel format. - * @details Gets the pixel format of the foreground layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return pixel format - * - * @api - */ -dma2d_pixfmt_t dma2dFgGetPixelFormat(DMA2DDriver *dma2dp) { - - dma2d_pixfmt_t fmt; - chSysLock(); - fmt = dma2dFgGetPixelFormatI(dma2dp); - chSysUnlock(); - return fmt; -} - -/** - * @brief Set foreground layer pixel format. - * @details Sets the pixel format of the foreground layer. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] fmt pixel format - * - * @iclass - */ -void dma2dFgSetPixelFormatI(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); - osalDbgAssert(fmt <= DMA2D_MAX_PIXFMT_ID, "bounds"); - (void)dma2dp; - - DMA2D->FGPFCCR = ((DMA2D->FGPFCCR & ~DMA2D_FGPFCCR_CM) | - ((uint32_t)fmt & DMA2D_FGPFCCR_CM)); -} - -/** - * @brief Set foreground layer pixel format. - * @details Sets the pixel format of the foreground layer. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] fmt pixel format - * - * @api - */ -void dma2dFgSetPixelFormat(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt) { - - chSysLock(); - dma2dFgSetPixelFormatI(dma2dp, fmt); - chSysUnlock(); -} - -/** - * @brief Get foreground layer default color. - * @details Gets the default color of the foreground layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return default color, RGB-888 - * - * @iclass - */ -dma2d_color_t dma2dFgGetDefaultColorI(DMA2DDriver *dma2dp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - (void)dma2dp; - - return (dma2d_color_t)(DMA2D->FGCOLR & 0x00FFFFFF); -} - -/** - * @brief Get foreground layer default color. - * @details Gets the default color of the foreground layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return default color, RGB-888 - * - * @api - */ -dma2d_color_t dma2dFgGetDefaultColor(DMA2DDriver *dma2dp) { - - dma2d_color_t c; - chSysLock(); - c = dma2dFgGetDefaultColorI(dma2dp); - chSysUnlock(); - return c; -} - -/** - * @brief Set foreground layer default color. - * @details Sets the default color of the foreground layer. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] c default color, RGB-888 - * - * @iclass - */ -void dma2dFgSetDefaultColorI(DMA2DDriver *dma2dp, dma2d_color_t c) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); - (void)dma2dp; - - DMA2D->FGCOLR = (uint32_t)c & 0x00FFFFFF; -} - -/** - * @brief Set foreground layer default color. - * @details Sets the default color of the foreground layer. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] c default color, RGB-888 - * - * @api - */ -void dma2dFgSetDefaultColor(DMA2DDriver *dma2dp, dma2d_color_t c) { - - chSysLock(); - dma2dFgSetDefaultColorI(dma2dp, c); - chSysUnlock(); -} - -/** - * @brief Get foreground layer palette specifications. - * @details Gets the palette specifications of the foreground layer. - * @note The palette colors pointer is actually addressed to a @p volatile - * memory zone. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[out] palettep pointer to the palette specifications - * - * @iclass - */ -void dma2dFgGetPaletteI(DMA2DDriver *dma2dp, dma2d_palcfg_t *palettep) { - - uint32_t r; - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgCheck(palettep != NULL); - (void)dma2dp; - - r = DMA2D->FGPFCCR; - palettep->colorsp = (const void *)DMA2D->FGCLUT; - palettep->length = (uint16_t)((r & DMA2D_FGPFCCR_CS) >> 8) + 1; - palettep->fmt = (dma2d_pixfmt_t)((r & DMA2D_FGPFCCR_CCM) >> 4); -} - -/** - * @brief Get foreground layer palette specifications. - * @details Gets the palette specifications of the foreground layer. - * @note The palette colors pointer is actually addressed to a @p volatile - * memory zone. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[out] palettep pointer to the palette specifications - * - * @api - */ -void dma2dFgGetPalette(DMA2DDriver *dma2dp, dma2d_palcfg_t *palettep) { - - chSysLock(); - dma2dFgGetPaletteI(dma2dp, palettep); - chSysUnlock(); -} - -/** - * @brief Set foreground layer palette specifications. - * @details Sets the palette specifications of the foreground layer. - * @note This function should not be called while the DMA2D is already - * executing a job, otherwise the appropriate error interrupt might be - * invoked. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] palettep pointer to the palette specifications - * - * @sclass - */ -void dma2dFgSetPaletteS(DMA2DDriver *dma2dp, const dma2d_palcfg_t *palettep) { - - osalDbgCheckClassS(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); - osalDbgCheck(palettep != NULL); - osalDbgCheck(palettep->colorsp != NULL); - osalDbgAssert(palettep->length > 0, "bounds"); - osalDbgAssert(palettep->length <= DMA2D_MAX_PALETTE_LENGTH, "bounds"); - osalDbgAssert(((palettep->fmt == DMA2D_FMT_ARGB8888) || - (palettep->fmt == DMA2D_FMT_RGB888)), "invalid format"); - - DMA2D->FGCMAR = (uint32_t)palettep->colorsp; - DMA2D->FGPFCCR = ( - (DMA2D->FGPFCCR & ~(DMA2D_FGPFCCR_CS | DMA2D_FGPFCCR_CCM)) | - ((((uint32_t)palettep->length - 1) << 8) & DMA2D_FGPFCCR_CS) | - ((uint32_t)palettep->fmt << 4) - ); - - dma2dp->state = DMA2D_ACTIVE; - DMA2D->FGPFCCR |= DMA2D_FGPFCCR_START; - -#if DMA2D_USE_WAIT - dma2dp->thread = chThdGetSelfX(); - chSchGoSleepS(CH_STATE_SUSPENDED); -#else - while (DMA2D->FGPFCCR & DMA2D_FGPFCCR_START) - chSchDoYieldS(); -#endif /* DMA2D_USE_WAIT */ -} - -/** - * @brief Set foreground layer palette specifications. - * @details Sets the palette specifications of the foreground layer. - * @note This function should not be called while the DMA2D is already - * executing a job, otherwise the appropriate error interrupt might be - * invoked. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] palettep pointer to the palette specifications - * - * @api - */ -void dma2dFgSetPalette(DMA2DDriver *dma2dp, const dma2d_palcfg_t *palettep) { - - chSysLock(); - dma2dFgSetPaletteS(dma2dp, palettep); - chSysUnlock(); -} - -/** - * @brief Get foreground layer specifications. - * @details Gets the foreground layer specifications at once. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[out] cfgp pointer to the layer specifications - * - * @iclass - */ -void dma2dFgGetLayerI(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgCheck(cfgp != NULL); - - cfgp->bufferp = dma2dFgGetAddressI(dma2dp); - cfgp->wrap_offset = dma2dFgGetWrapOffsetI(dma2dp); - cfgp->fmt = dma2dFgGetPixelFormatI(dma2dp); - cfgp->def_color = dma2dFgGetDefaultColorI(dma2dp); - cfgp->const_alpha = dma2dFgGetConstantAlphaI(dma2dp); - if (cfgp->palettep != NULL) - dma2dFgGetPaletteI(dma2dp, (dma2d_palcfg_t *)cfgp->palettep); -} - -/** - * @brief Get foreground layer specifications. - * @details Gets the foreground layer specifications at once. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[out] cfgp pointer to the layer specifications - * - * @api - */ -void dma2dFgGetLayer(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp) { - - chSysLock(); - dma2dFgGetLayerI(dma2dp, cfgp); - chSysUnlock(); -} - -/** - * @brief Set foreground layer specifications. - * @details Sets the foreground layer specifications at once. - * @note If the palette is unspecified, the layer palette is unmodified. - * @note This function should not be called while the DMA2D is already - * executing a job, otherwise the appropriate error interrupt might be - * invoked. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] cfgp pointer to the layer specifications - * - * @sclass - */ -void dma2dFgSetConfigS(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp) { - - osalDbgCheckClassS(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); - osalDbgCheck(cfgp != NULL); - - dma2dFgSetAddressI(dma2dp, cfgp->bufferp); - dma2dFgSetWrapOffsetI(dma2dp, cfgp->wrap_offset); - dma2dFgSetPixelFormatI(dma2dp, cfgp->fmt); - dma2dFgSetDefaultColorI(dma2dp, cfgp->def_color); - dma2dFgSetConstantAlphaI(dma2dp, cfgp->const_alpha); - if (cfgp->palettep != NULL) - dma2dFgSetPaletteS(dma2dp, cfgp->palettep); -} - -/** - * @brief Set foreground layer specifications. - * @details Sets the foreground layer specifications at once. - * @note If the palette is unspecified, the layer palette is unmodified. - * @note This function should not be called while the DMA2D is already - * executing a job, otherwise the appropriate error interrupt might be - * invoked. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] cfgp pointer to the layer specifications - * - * @api - */ -void dma2dFgSetConfig(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp) { - - chSysLock(); - dma2dFgSetConfigS(dma2dp, cfgp); - chSysUnlock(); -} - -/** @} */ - -/** - * @name DMA2D output layer methods - * @{ - */ - -/** - * @brief Get output layer buffer address. - * @details Gets the buffer address of the output layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return buffer address - * - * @iclass - */ -void *dma2dOutGetAddressI(DMA2DDriver *dma2dp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - (void)dma2dp; - - return (void *)DMA2D->OMAR; -} - -/** - * @brief Get output layer buffer address. - * @details Gets the buffer address of the output layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return buffer address - * - * @api - */ -void *dma2dOutGetAddress(DMA2DDriver *dma2dp) { - - void *bufferp; - chSysLock(); - bufferp = dma2dOutGetAddressI(dma2dp); - chSysUnlock(); - return bufferp; -} - -/** - * @brief Set output layer buffer address. - * @details Sets the buffer address of the output layer. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] bufferp buffer address - * - * @iclass - */ -void dma2dOutSetAddressI(DMA2DDriver *dma2dp, void *bufferp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); - osalDbgCheck(dma2dIsAligned(bufferp, dma2dOutGetPixelFormatI(dma2dp))); - (void)dma2dp; - - DMA2D->OMAR = (uint32_t)bufferp; -} - -/** - * @brief Set output layer buffer address. - * @details Sets the buffer address of the output layer. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] bufferp buffer address - * - * @api - */ -void dma2dOutSetAddress(DMA2DDriver *dma2dp, void *bufferp) { - - chSysLock(); - dma2dOutSetAddressI(dma2dp, bufferp); - chSysUnlock(); -} - -/** - * @brief Get output layer wrap offset. - * @details Gets the buffer line wrap offset of the output layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return wrap offset, in pixels - * - * @iclass - */ -size_t dma2dOutGetWrapOffsetI(DMA2DDriver *dma2dp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - (void)dma2dp; - - return (size_t)(DMA2D->OOR & DMA2D_OOR_LO); -} - -/** - * @brief Get output layer wrap offset. - * @details Gets the buffer line wrap offset of the output layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return wrap offset, in pixels - * - * @api - */ -size_t dma2dOutGetWrapOffset(DMA2DDriver *dma2dp) { - - size_t offset; - chSysLock(); - offset = dma2dOutGetWrapOffsetI(dma2dp); - chSysUnlock(); - return offset; -} - -/** - * @brief Set output layer wrap offset. - * @details Sets the buffer line wrap offset of the output layer. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] offset wrap offset, in pixels - * - * @iclass - */ -void dma2dOutSetWrapOffsetI(DMA2DDriver *dma2dp, size_t offset) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); - osalDbgAssert(offset <= DMA2D_MAX_OFFSET, "bounds"); - (void)dma2dp; - - DMA2D->OOR = ((DMA2D->OOR & ~DMA2D_OOR_LO) | - ((uint32_t)offset & DMA2D_OOR_LO)); -} - -/** - * @brief Set output layer wrap offset. - * @details Sets the buffer line wrap offset of the output layer. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] offset wrap offset, in pixels - * - * @api - */ -void dma2dOutSetWrapOffset(DMA2DDriver *dma2dp, size_t offset) { - - chSysLock(); - dma2dOutSetWrapOffsetI(dma2dp, offset); - chSysUnlock(); -} - -/** - * @brief Get output layer pixel format. - * @details Gets the pixel format of the output layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return pixel format - * - * @iclass - */ -dma2d_pixfmt_t dma2dOutGetPixelFormatI(DMA2DDriver *dma2dp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - (void)dma2dp; - - return (dma2d_pixfmt_t)(DMA2D->OPFCCR & DMA2D_OPFCCR_CM); -} - -/** - * @brief Get output layer pixel format. - * @details Gets the pixel format of the output layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return pixel format - * - * @api - */ -dma2d_pixfmt_t dma2dOutGetPixelFormat(DMA2DDriver *dma2dp) { - - dma2d_pixfmt_t fmt; - chSysLock(); - fmt = dma2dOutGetPixelFormatI(dma2dp); - chSysUnlock(); - return fmt; -} - -/** - * @brief Set output layer pixel format. - * @details Sets the pixel format of the output layer. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] fmt pixel format - * - * @iclass - */ -void dma2dOutSetPixelFormatI(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); - osalDbgAssert(fmt <= DMA2D_MAX_OUTPIXFMT_ID, "bounds"); - (void)dma2dp; - - DMA2D->OPFCCR = ((DMA2D->OPFCCR & ~DMA2D_OPFCCR_CM) | - ((uint32_t)fmt & DMA2D_OPFCCR_CM)); -} - -/** - * @brief Set output layer pixel format. - * @details Sets the pixel format of the output layer. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] fmt pixel format - * - * @api - */ -void dma2dOutSetPixelFormat(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt) { - - chSysLock(); - dma2dOutSetPixelFormatI(dma2dp, fmt); - chSysUnlock(); -} - -/** - * @brief Get output layer default color. - * @details Gets the default color of the output layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return default color, chosen output format - * - * @iclass - */ -dma2d_color_t dma2dOutGetDefaultColorI(DMA2DDriver *dma2dp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - (void)dma2dp; - - return (dma2d_color_t)(DMA2D->OCOLR & 0x00FFFFFF); -} - -/** - * @brief Get output layer default color. - * @details Gets the default color of the output layer. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * - * @return default color, chosen output format - * - * @api - */ -dma2d_color_t dma2dOutGetDefaultColor(DMA2DDriver *dma2dp) { - - dma2d_color_t c; - chSysLock(); - c = dma2dOutGetDefaultColorI(dma2dp); - chSysUnlock(); - return c; -} - -/** - * @brief Set output layer default color. - * @details Sets the default color of the output layer. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] c default color, chosen output format - * - * @iclass - */ -void dma2dOutSetDefaultColorI(DMA2DDriver *dma2dp, dma2d_color_t c) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); - (void)dma2dp; - - DMA2D->OCOLR = (uint32_t)c & 0x00FFFFFF; -} - -/** - * @brief Set output layer default color. - * @details Sets the default color of the output layer. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] c default color, chosen output format - * - * @api - */ -void dma2dOutSetDefaultColor(DMA2DDriver *dma2dp, dma2d_color_t c) { - - chSysLock(); - dma2dOutSetDefaultColorI(dma2dp, c); - chSysUnlock(); -} - -/** - * @brief Get output layer specifications. - * @details Gets the output layer specifications at once. - * @note Constant alpha and palette specifications are ignored. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[out] cfgp pointer to the layer specifications - * - * @iclass - */ -void dma2dOutGetLayerI(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgCheck(cfgp != NULL); - - cfgp->bufferp = dma2dOutGetAddressI(dma2dp); - cfgp->wrap_offset = dma2dOutGetWrapOffsetI(dma2dp); - cfgp->fmt = dma2dOutGetPixelFormatI(dma2dp); - cfgp->def_color = dma2dOutGetDefaultColorI(dma2dp); -} - -/** - * @brief Get output layer specifications. - * @details Gets the output layer specifications at once. - * @note Constant alpha and palette specifications are ignored. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[out] cfgp pointer to the layer specifications - * - * @api - */ -void dma2dOutGetLayer(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp) { - - chSysLock(); - dma2dOutGetLayerI(dma2dp, cfgp); - chSysUnlock(); -} - -/** - * @brief Set output layer specifications. - * @details Sets the output layer specifications at once. - * @note Constant alpha and palette specifications are ignored. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] cfgp pointer to the layer specifications - * - * @iclass - */ -void dma2dOutSetConfigI(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp) { - - osalDbgCheckClassI(); - osalDbgCheck(dma2dp == &DMA2DD1); - osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); - osalDbgCheck(cfgp != NULL); - - dma2dOutSetAddressI(dma2dp, cfgp->bufferp); - dma2dOutSetWrapOffsetI(dma2dp, cfgp->wrap_offset); - dma2dOutSetPixelFormatI(dma2dp, cfgp->fmt); - dma2dOutSetDefaultColorI(dma2dp, cfgp->def_color); -} - -/** - * @brief Set output layer specifications. - * @details Sets the output layer specifications at once. - * @note Constant alpha and palette specifications are ignored. - * @pre DMA2D is ready. - * - * @param[in] dma2dp pointer to the @p DMA2DDriver object - * @param[in] cfgp pointer to the layer specifications - * - * @api - */ -void dma2dOutSetConfig(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp) { - - chSysLock(); - dma2dOutSetConfigI(dma2dp, cfgp); - chSysUnlock(); -} - -/** @} */ - -/** - * @name DMA2D helper functions - * @{ - */ - -/** - * @brief Compute pixel address. - * @details Computes the buffer address of a pixel, given the buffer - * specifications. - * - * @param[in] originp buffer origin address - * @param[in] pitch buffer pitch, in bytes - * @param[in] fmt buffer pixel format - * @param[in] x horizontal pixel coordinate - * @param[in] y vertical pixel coordinate - * - * @return pixel address, constant data - * - * @api - */ -const void *dma2dComputeAddressConst(const void *originp, size_t pitch, - dma2d_pixfmt_t fmt, - uint16_t x, uint16_t y) { - - osalDbgCheck(pitch > 0); - - switch (fmt) { - case DMA2D_FMT_ARGB8888: - return (const void *)((uintptr_t)originp + - (uintptr_t)y * pitch + (uintptr_t)x * 4); - case DMA2D_FMT_RGB888: - return (const void *)((uintptr_t)originp + - (uintptr_t)y * pitch + (uintptr_t)x * 3); - case DMA2D_FMT_RGB565: - case DMA2D_FMT_ARGB1555: - case DMA2D_FMT_ARGB4444: - case DMA2D_FMT_AL88: - return (const void *)((uintptr_t)originp + - (uintptr_t)y * pitch + (uintptr_t)x * 2); - case DMA2D_FMT_L8: - case DMA2D_FMT_AL44: - case DMA2D_FMT_A8: - return (const void *)((uintptr_t)originp + - (uintptr_t)y * pitch + (uintptr_t)x); - case DMA2D_FMT_L4: - case DMA2D_FMT_A4: - osalDbgAssert((x & 1) == 0, "not aligned"); - return (const void *)((uintptr_t)originp + - (uintptr_t)y * pitch + (uintptr_t)x / 2); - default: - osalDbgAssert(false, "invalid format"); - return NULL; - } -} - -/** - * @brief Address is aligned. - * @details Tells whether the address is aligned with the provided pixel format. - * - * @param[in] bufferp address - * @param[in] fmt pixel format - * - * @return address is aligned - * - * @api - */ -bool dma2dIsAligned(const void *bufferp, dma2d_pixfmt_t fmt) { - - switch (fmt) { - case DMA2D_FMT_ARGB8888: - case DMA2D_FMT_RGB888: - return ((uintptr_t)bufferp & 3) == 0; /* 32-bit alignment.*/ - case DMA2D_FMT_RGB565: - case DMA2D_FMT_ARGB1555: - case DMA2D_FMT_ARGB4444: - case DMA2D_FMT_AL88: - return ((uintptr_t)bufferp & 1) == 0; /* 16-bit alignment.*/ - case DMA2D_FMT_L8: - case DMA2D_FMT_AL44: - case DMA2D_FMT_L4: - case DMA2D_FMT_A8: - case DMA2D_FMT_A4: - return true; /* 8-bit alignment.*/ - default: - osalDbgAssert(false, "invalid format"); - return false; - } -} - -/** - * @brief Compute bits per pixel. - * @details Computes the bits per pixel for the specified pixel format. - * - * @param[in] fmt pixel format - * - * @retuen bits per pixel - * - * @api - */ -size_t dma2dBitsPerPixel(dma2d_pixfmt_t fmt) { - - osalDbgAssert(fmt < DMA2D_MAX_PIXFMT_ID, "invalid format"); - - return (size_t)dma2d_bpp[(unsigned)fmt]; -} - -#if DMA2D_USE_SOFTWARE_CONVERSIONS || defined(__DOXYGEN__) - -/** - * @brief Convert from ARGB-8888. - * @details Converts an ARGB-8888 color to the specified pixel format. - * - * @param[in] c color, ARGB-8888 - * @param[in] fmt target pixel format - * - * @return raw color value for the target pixel format, left - * padded with zeros. - * - * @api - */ -dma2d_color_t dma2dFromARGB8888(dma2d_color_t c, dma2d_pixfmt_t fmt) { - - switch (fmt) { - case DMA2D_FMT_ARGB8888: { - return c; - } - case DMA2D_FMT_RGB888: { - return (c & 0x00FFFFFF); - } - case DMA2D_FMT_RGB565: { - return (((c & 0x000000F8) >> ( 8 - 5)) | - ((c & 0x0000FC00) >> (16 - 11)) | - ((c & 0x00F80000) >> (24 - 16))); - } - case DMA2D_FMT_ARGB1555: { - return (((c & 0x000000F8) >> ( 8 - 5)) | - ((c & 0x0000F800) >> (16 - 10)) | - ((c & 0x00F80000) >> (24 - 15)) | - ((c & 0x80000000) >> (32 - 16))); - } - case DMA2D_FMT_ARGB4444: { - return (((c & 0x000000F0) >> ( 8 - 4)) | - ((c & 0x0000F000) >> (16 - 8)) | - ((c & 0x00F00000) >> (24 - 12)) | - ((c & 0xF0000000) >> (32 - 16))); - } - case DMA2D_FMT_L8: { - return (c & 0x000000FF); - } - case DMA2D_FMT_AL44: { - return (((c & 0x000000F0) >> ( 8 - 4)) | - ((c & 0xF0000000) >> (32 - 8))); - } - case DMA2D_FMT_AL88: { - return (((c & 0x000000FF) >> ( 8 - 8)) | - ((c & 0xFF000000) >> (32 - 16))); - } - case DMA2D_FMT_L4: { - return (c & 0x0000000F); - } - case DMA2D_FMT_A8: { - return ((c & 0xFF000000) >> (32 - 8)); - } - case DMA2D_FMT_A4: { - return ((c & 0xF0000000) >> (32 - 4)); - } - default: - osalDbgAssert(false, "invalid format"); - return 0; - } -} - -/** - * @brief Convert to ARGB-8888. - * @details Converts color of the specified pixel format to an ARGB-8888 color. - * - * @param[in] c color for the source pixel format, left padded with - * zeros. - * @param[in] fmt source pixel format - * - * @return color in ARGB-8888 format - * - * @api - */ -dma2d_color_t dma2dToARGB8888(dma2d_color_t c, dma2d_pixfmt_t fmt) { - - switch (fmt) { - case DMA2D_FMT_ARGB8888: { - return c; - } - case DMA2D_FMT_RGB888: { - return ((c & 0x00FFFFFF) | 0xFF000000); - } - case DMA2D_FMT_RGB565: { - register dma2d_color_t output = 0xFF000000; - if (c & 0x001F) output |= (((c & 0x001F) << ( 8 - 5)) | 0x00000007); - if (c & 0x07E0) output |= (((c & 0x07E0) << (16 - 11)) | 0x00000300); - if (c & 0xF800) output |= (((c & 0xF800) << (24 - 16)) | 0x00070000); - return output; - } - case DMA2D_FMT_ARGB1555: { - register dma2d_color_t output = 0x00000000; - if (c & 0x001F) output |= (((c & 0x001F) << ( 8 - 5)) | 0x00000007); - if (c & 0x03E0) output |= (((c & 0x03E0) << (16 - 10)) | 0x00000700); - if (c & 0x7C00) output |= (((c & 0x7C00) << (24 - 15)) | 0x00070000); - if (c & 0x8000) output |= 0xFF000000; - return output; - } - case DMA2D_FMT_ARGB4444: { - register dma2d_color_t output = 0x00000000; - if (c & 0x000F) output |= (((c & 0x000F) << ( 8 - 4)) | 0x0000000F); - if (c & 0x00F0) output |= (((c & 0x00F0) << (16 - 8)) | 0x00000F00); - if (c & 0x0F00) output |= (((c & 0x0F00) << (24 - 12)) | 0x000F0000); - if (c & 0xF000) output |= (((c & 0xF000) << (32 - 16)) | 0x0F000000); - return output; - } - case DMA2D_FMT_L8: { - return (c & 0xFF) | 0xFF000000; - } - case DMA2D_FMT_AL44: { - register dma2d_color_t output = 0x00000000; - if (c & 0x0F) output |= (((c & 0x0F) << ( 8 - 4)) | 0x0000000F); - if (c & 0xF0) output |= (((c & 0xF0) << (32 - 8)) | 0x0F000000); - return output; - } - case DMA2D_FMT_AL88: { - return (((c & 0x00FF) << ( 8 - 8)) | - ((c & 0xFF00) << (32 - 16))); - } - case DMA2D_FMT_L4: { - return ((c & 0x0F) | 0xFF000000); - } - case DMA2D_FMT_A8: { - return ((c & 0xFF) << (32 - 8)); - } - case DMA2D_FMT_A4: { - return ((c & 0x0F) << (32 - 4)); - } - default: - osalDbgAssert(false, "invalid format"); - return 0; - } -} - -#endif /* DMA2D_NEED_CONVERSIONS */ - -/** @} */ - -/** @} */ - -#endif /* STM32_DMA2D_USE_DMA2D */ diff --git a/os/hal/ports/STM32/LLD/DMA2Dv1/stm32_dma2d.h b/os/hal/ports/STM32/LLD/DMA2Dv1/stm32_dma2d.h deleted file mode 100644 index 29efa71..0000000 --- a/os/hal/ports/STM32/LLD/DMA2Dv1/stm32_dma2d.h +++ /dev/null @@ -1,664 +0,0 @@ -/* - Copyright (C) 2013-2015 Andrea Zoppi - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -/** - * @file stm32_dma2d.h - * @brief DMA2D/Chrom-ART driver. - * - * @addtogroup dma2d - * @{ - */ - -#ifndef _STM32_DMA2D_H_ -#define _STM32_DMA2D_H_ - -/** - * @brief Using the DMA2D driver. - */ -#if !defined(STM32_DMA2D_USE_DMA2D) || defined(__DOXYGEN__) -#define STM32_DMA2D_USE_DMA2D (FALSE) -#endif - -#if (TRUE == STM32_DMA2D_USE_DMA2D) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver constants. */ -/*===========================================================================*/ - -/** - * @name DMA2D job modes - * @{ - */ -#define DMA2D_JOB_COPY (0 << 16) /**< Copy, replace(FG only).*/ -#define DMA2D_JOB_CONVERT (1 << 16) /**< Copy, convert (FG + PFC).*/ -#define DMA2D_JOB_BLEND (2 << 16) /**< Copy, blend (FG + BG + PFC).*/ -#define DMA2D_JOB_CONST (3 << 16) /**< Default color only (FG REG).*/ -/** @} */ - -/** - * @name DMA2D enable flag - * @{ - */ -#define DMA2D_EF_ENABLE (1 << 0) /**< DMA2D enabled.*/ -#define DMA2D_EF_DITHER (1 << 16) /**< Dithering enabled.*/ -#define DMA2D_EF_PIXCLK_INVERT (1 << 28) /**< Inverted pixel clock.*/ -#define DMA2D_EF_DATAEN_HIGH (1 << 29) /**< Active-high data enable.*/ -#define DMA2D_EF_VSYNC_HIGH (1 << 30) /**< Active-high vsync.*/ -#define DMA2D_EF_HSYNC_HIGH (1 << 31) /**< Active-high hsync.*/ - -/** Enable flags mask. */ -#define DMA2D_EF_MASK \ - (DMA2D_EF_ENABLE | DMA2D_EF_DITHER | DMA2D_EF_PIXCLK_INVERT | \ - DMA2D_EF_DATAEN_HIGH | DMA2D_EF_VSYNC_HIGH | DMA2D_EF_HSYNC_HIGH) -/** @} */ - -/** - * @name DMA2D layer enable flags - * @{ - */ -#define DMA2D_LEF_ENABLE (1 << 0) /**< Layer enabled*/ -#define DMA2D_LEF_KEYING (1 << 1) /**< Color keying enabled.*/ -#define DMA2D_LEF_PALETTE (1 << 4) /**< Palette enabled.*/ - -/** Layer enable flag masks. */ -#define DMA2D_LEF_MASK \ - (DMA2D_LEF_ENABLE | DMA2D_LEF_KEYING | DMA2D_LEF_PALETTE) -/** @} */ - -/** - * @name DMA2D pixel formats - * @{ - */ -#define DMA2D_FMT_ARGB8888 (0) /**< ARGB-8888 format.*/ -#define DMA2D_FMT_RGB888 (1) /**< RGB-888 format.*/ -#define DMA2D_FMT_RGB565 (2) /**< RGB-565 format.*/ -#define DMA2D_FMT_ARGB1555 (3) /**< ARGB-1555 format.*/ -#define DMA2D_FMT_ARGB4444 (4) /**< ARGB-4444 format.*/ -#define DMA2D_FMT_L8 (5) /**< L-8 format.*/ -#define DMA2D_FMT_AL44 (6) /**< AL-44 format.*/ -#define DMA2D_FMT_AL88 (7) /**< AL-88 format.*/ -#define DMA2D_FMT_L4 (8) /**< L-4 format.*/ -#define DMA2D_FMT_A8 (9) /**< A-8 format.*/ -#define DMA2D_FMT_A4 (10) /**< A-4 format.*/ -/** @} */ - -/** - * @name DMA2D pixel format aliased raw masks - * @{ - */ -#define DMA2D_XMASK_ARGB8888 (0xFFFFFFFF) /**< ARGB-8888 aliased mask.*/ -#define DMA2D_XMASK_RGB888 (0x00FFFFFF) /**< RGB-888 aliased mask.*/ -#define DMA2D_XMASK_RGB565 (0x00F8FCF8) /**< RGB-565 aliased mask.*/ -#define DMA2D_XMASK_ARGB1555 (0x80F8F8F8) /**< ARGB-1555 aliased mask.*/ -#define DMA2D_XMASK_ARGB4444 (0xF0F0F0F0) /**< ARGB-4444 aliased mask.*/ -#define DMA2D_XMASK_L8 (0x000000FF) /**< L-8 aliased mask.*/ -#define DMA2D_XMASK_AL44 (0xF00000F0) /**< AL-44 aliased mask.*/ -#define DMA2D_XMASK_AL88 (0xFF0000FF) /**< AL-88 aliased mask.*/ -#define DMA2D_XMASK_L4 (0x0000000F) /**< L-4 aliased mask.*/ -#define DMA2D_XMASK_A8 (0xFF000000) /**< A-8 aliased mask.*/ -#define DMA2D_XMASK_A4 (0xF0000000) /**< A-4 aliased mask.*/ -/** @} */ - -/** - * @name DMA2D alpha modes - * @{ - */ -#define DMA2D_ALPHA_KEEP (0x00000000) /**< Original alpha channel.*/ -#define DMA2D_ALPHA_REPLACE (0x00010000) /**< Replace with constant.*/ -#define DMA2D_ALPHA_MODULATE (0x00020000) /**< Modulate with constant.*/ -/** @} */ - -/** - * @name DMA2D parameter bounds - * @{ - */ - -#define DMA2D_MIN_PIXFMT_ID (0) /**< Minimum pixel format ID.*/ -#define DMA2D_MAX_PIXFMT_ID (11) /**< Maximum pixel format ID.*/ -#define DMA2D_MIN_OUTPIXFMT_ID (0) /**< Minimum output pixel format ID.*/ -#define DMA2D_MAX_OUTPIXFMT_ID (4) /**< Maximum output pixel format ID.*/ - -#define DMA2D_MAX_OFFSET ((1 << 14) - 1) - -#define DMA2D_MAX_PALETTE_LENGTH (256) /***/ - -#define DMA2D_MAX_WIDTH ((1 << 14) - 1) -#define DMA2D_MAX_HEIGHT ((1 << 16) - 1) - -#define DMA2D_MAX_WATERMARK_POS ((1 << 16) - 1) - -#define DMA2D_MAX_DEADTIME_CYCLES ((1 << 8) - 1) - -/** @} */ - -/** - * @name DMA2D basic ARGB-8888 colors. - * @{ - */ -/* Microsoft Windows default 16-color palette.*/ -#define DMA2D_COLOR_BLACK (0xFF000000) -#define DMA2D_COLOR_MAROON (0xFF800000) -#define DMA2D_COLOR_GREEN (0xFF008000) -#define DMA2D_COLOR_OLIVE (0xFF808000) -#define DMA2D_COLOR_NAVY (0xFF000080) -#define DMA2D_COLOR_PURPLE (0xFF800080) -#define DMA2D_COLOR_TEAL (0xFF008080) -#define DMA2D_COLOR_SILVER (0xFFC0C0C0) -#define DMA2D_COLOR_GRAY (0xFF808080) -#define DMA2D_COLOR_RED (0xFFFF0000) -#define DMA2D_COLOR_LIME (0xFF00FF00) -#define DMA2D_COLOR_YELLOW (0xFFFFFF00) -#define DMA2D_COLOR_BLUE (0xFF0000FF) -#define DMA2D_COLOR_FUCHSIA (0xFFFF00FF) -#define DMA2D_COLOR_AQUA (0xFF00FFFF) -#define DMA2D_COLOR_WHITE (0xFFFFFFFF) -/** @} */ - -/*===========================================================================*/ -/* Driver pre-compile time settings. */ -/*===========================================================================*/ - -/** - * @name DMA2D configuration options - * @{ - */ - -/** - * @brief DMA2D event interrupt priority level setting. - */ -#if !defined(STM32_DMA2D_IRQ_PRIORITY) || defined(__DOXYGEN__) -#define STM32_DMA2D_IRQ_PRIORITY (11) -#endif - -/** - * @brief Enables synchronous APIs. - * @note Disabling this option saves both code and data space. - */ -#if !defined(DMA2D_USE_WAIT) || defined(__DOXYGEN__) -#define DMA2D_USE_WAIT (TRUE) -#endif - -/** - * @brief Enables the @p dma2dAcquireBus() and @p dma2dReleaseBus() APIs. - * @note Disabling this option saves both code and data space. - */ -#if !defined(DMA2D_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) -#define DMA2D_USE_MUTUAL_EXCLUSION (TRUE) -#endif - -/** - * @brief Provides software color conversion functions. - * @note Disabling this option saves both code and data space. - */ -#if !defined(DMA2D_USE_SOFTWARE_CONVERSIONS) || defined(__DOXYGEN__) -#define DMA2D_USE_SOFTWARE_CONVERSIONS (TRUE) -#endif - -/** - * @brief Enables checks for DMA2D functions. - * @note Disabling this option saves both code and data space. - * @note Disabling checks by ChibiOS will automatically disable DMA2D checks. - */ -#if !defined(DMA2D_USE_CHECKS) || defined(__DOXYGEN__) -#define DMA2D_USE_CHECKS (TRUE) -#endif - -/** @} */ - -/*===========================================================================*/ -/* Derived constants and error checks. */ -/*===========================================================================*/ - -#if (TRUE != STM32_HAS_DMA2D) -#error "DMA2D must be present when using the DMA2D subsystem" -#endif - -#if (TRUE != STM32_DMA2D_USE_DMA2D) && (TRUE != STM32_HAS_DMA2D) -#error "DMA2D not present in the selected device" -#endif - -#if (TRUE == DMA2D_USE_MUTUAL_EXCLUSION) -#if (TRUE != CH_CFG_USE_MUTEXES) && (TRUE != CH_CFG_USE_SEMAPHORES) -#error "DMA2D_USE_MUTUAL_EXCLUSION requires CH_CFG_USE_MUTEXES and/or CH_CFG_USE_SEMAPHORES" -#endif -#endif - -/*===========================================================================*/ -/* Driver data structures and types. */ -/*===========================================================================*/ - -/* Complex types forwarding.*/ -typedef union dma2d_coloralias_t dma2d_coloralias_t; -typedef struct dma2d_palcfg_t dma2d_palcfg_t; -typedef struct dma2d_laycfg_t dma2d_layercfg_t; -typedef struct DMA2DConfig DMA2DConfig; -typedef enum dma2d_state_t dma2d_state_t; -typedef struct DMA2DDriver DMA2DDriver; - -/** - * @name DMA2D Data types - * @{ - */ - -/** - * @brief DMA2D generic color. - */ -typedef uint32_t dma2d_color_t; - -/** - * @brief DMA2D color aliases. - * @detail Mapped with ARGB-8888, except for luminance (L mapped onto B). - * Padding fields are prefixed with 'x', and should be clear - * (all 0) before compression and set (all 1) after expansion. - */ -typedef union dma2d_coloralias_t { - struct { - unsigned b : 8; - unsigned g : 8; - unsigned r : 8; - unsigned a : 8; - } argb8888; /**< Mapped ARGB-8888 bits.*/ - struct { - unsigned b : 8; - unsigned g : 8; - unsigned r : 8; - unsigned xa : 8; - } rgb888; /**< Mapped RGB-888 bits.*/ - struct { - unsigned xb : 3; - unsigned b : 5; - unsigned xg : 2; - unsigned g : 6; - unsigned xr : 3; - unsigned r : 5; - unsigned xa : 8; - } rgb565; /**< Mapped RGB-565 bits.*/ - struct { - unsigned xb : 3; - unsigned b : 5; - unsigned xg : 3; - unsigned g : 5; - unsigned xr : 3; - unsigned r : 5; - unsigned xa : 7; - unsigned a : 1; - } argb1555; /**< Mapped ARGB-1555 values.*/ - struct { - unsigned xb : 4; - unsigned b : 4; - unsigned xg : 4; - unsigned g : 4; - unsigned xr : 4; - unsigned r : 4; - unsigned xa : 4; - unsigned a : 4; - } argb4444; /**< Mapped ARGB-4444 values.*/ - struct { - unsigned l : 8; - unsigned x : 16; - unsigned xa : 8; - } l8; /**< Mapped L-8 bits.*/ - struct { - unsigned xl : 4; - unsigned l : 4; - unsigned x : 16; - unsigned xa : 4; - unsigned a : 4; - } al44; /**< Mapped AL-44 bits.*/ - struct { - unsigned l : 8; - unsigned x : 16; - unsigned a : 8; - } al88; /**< Mapped AL-88 bits.*/ - struct { - unsigned l : 4; - unsigned xl : 4; - unsigned x : 16; - unsigned xa : 8; - } l4; /**< Mapped L-4 bits.*/ - struct { - unsigned x : 24; - unsigned a : 8; - } a8; /**< Mapped A-8 bits.*/ - struct { - unsigned x : 24; - unsigned xa : 4; - unsigned a : 4; - } a4; /**< Mapped A-4 bits.*/ - dma2d_color_t aliased; /**< Aliased raw bits.*/ -} dma2d_coloralias_t; - -/** - * @brief DMA2D job (transfer) mode. - */ -typedef uint32_t dma2d_jobmode_t; - -/** - * @brief DMA2D pixel format. - */ -typedef uint32_t dma2d_pixfmt_t; - -/** - * @brief DMA2D alpha mode. - */ -typedef uint32_t dma2d_amode_t; - -/** - * @brief DMA2D ISR callback. - */ -typedef void (*dma2d_isrcb_t)(DMA2DDriver *dma2dp); - -/** - * @brief DMA2D palette specifications. - */ -typedef struct dma2d_palcfg_t { - const void *colorsp; /**< Pointer to color entries.*/ - uint16_t length; /**< Number of color entries.*/ - dma2d_pixfmt_t fmt; /**< Format, RGB-888 or ARGB-8888.*/ -} dma2d_palcfg_t; - -/** - * @brief DMA2D layer specifications. - */ -typedef struct dma2d_layercfg_t { - void *bufferp; /**< Frame buffer address.*/ - size_t wrap_offset; /**< Offset between lines, in pixels.*/ - dma2d_pixfmt_t fmt; /**< Pixel format.*/ - dma2d_color_t def_color; /**< Default color, RGB-888.*/ - uint8_t const_alpha; /**< Constant alpha factor.*/ - const dma2d_palcfg_t *palettep; /**< Palette specs, or @p NULL.*/ -} dma2d_laycfg_t; - -/** - * @brief DMA2D driver configuration. - */ -typedef struct DMA2DConfig { - /* ISR callbacks.*/ - dma2d_isrcb_t cfgerr_isr; /**< Configuration error, or @p NULL.*/ - dma2d_isrcb_t paltrfdone_isr; /**< Palette transfer done, or @p NULL.*/ - dma2d_isrcb_t palacserr_isr; /**< Palette access error, or @p NULL.*/ - dma2d_isrcb_t trfwmark_isr; /**< Transfer watermark, or @p NULL.*/ - dma2d_isrcb_t trfdone_isr; /**< Transfer complete, or @p NULL.*/ - dma2d_isrcb_t trferr_isr; /**< Transfer error, or @p NULL.*/ -} DMA2DConfig; - -/** - * @brief DMA2D driver state. - */ -typedef enum dma2d_state_t { - DMA2D_UNINIT = (0), /**< Not initialized.*/ - DMA2D_STOP = (1), /**< Stopped.*/ - DMA2D_READY = (2), /**< Ready.*/ - DMA2D_ACTIVE = (3), /**< Executing commands.*/ - DMA2D_PAUSED = (4), /**< Transfer suspended.*/ -} dma2d_state_t; - -/** - * @brief DMA2D driver. - */ -typedef struct DMA2DDriver { - dma2d_state_t state; /**< Driver state.*/ - const DMA2DConfig *config; /**< Driver configuration.*/ - - /* Multithreading stuff.*/ -#if (TRUE == DMA2D_USE_WAIT) || defined(__DOXYGEN__) - thread_t *thread; /**< Waiting thread.*/ -#endif /* DMA2D_USE_WAIT */ -#if (TRUE == DMA2D_USE_MUTUAL_EXCLUSION) -#if (TRUE == CH_CFG_USE_MUTEXES) - mutex_t lock; /**< Multithreading lock.*/ -#elif (TRUE == CH_CFG_USE_SEMAPHORES) - semaphore_t lock; /**< Multithreading lock.*/ -#endif -#endif /* DMA2D_USE_MUTUAL_EXCLUSION */ -} DMA2DDriver; - -/** @} */ - -/*===========================================================================*/ -/* Driver macros. */ -/*===========================================================================*/ - -/** - * @brief Makes an ARGB-8888 value from byte components. - * - * @param[in] a alpha byte component - * @param[in] r red byte component - * @param[in] g green byte component - * @param[in] b blue byte component - * - * @return color in ARGB-8888 format - * - * @api - */ -#define dma2dMakeARGB8888(a, r, g, b) \ - ((((dma2d_color_t)(a) & 0xFF) << 24) | \ - (((dma2d_color_t)(r) & 0xFF) << 16) | \ - (((dma2d_color_t)(g) & 0xFF) << 8) | \ - (((dma2d_color_t)(b) & 0xFF) << 0)) - -/** - * @brief Compute bytes per pixel. - * @details Computes the bytes per pixel for the specified pixel format. - * Rounds to the ceiling. - * - * @param[in] fmt pixel format - * - * @return bytes per pixel - * - * @api - */ -#define dma2dBytesPerPixel(fmt) \ - ((dma2dBitsPerPixel(fmt) + 7) >> 3) - -/** - * @brief Compute pixel address. - * @details Computes the buffer address of a pixel, given the buffer - * specifications. - * - * @param[in] originp buffer origin address - * @param[in] pitch buffer pitch, in bytes - * @param[in] fmt buffer pixel format - * @param[in] x horizontal pixel coordinate - * @param[in] y vertical pixel coordinate - * - * @return pixel address - * - * @api - */ -#define dma2dComputeAddress(originp, pitch, fmt, x, y) \ - ((void *)dma2dComputeAddressConst(originp, pitch, fmt, x, y)) - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -extern DMA2DDriver DMA2DD1; - -#ifdef __cplusplus -extern "C" { -#endif - - /* Driver methods.*/ - void dma2dInit(void); - void dma2dObjectInit(DMA2DDriver *dma2dp); - dma2d_state_t dma2dGetStateI(DMA2DDriver *dma2dp); - dma2d_state_t dma2dGetState(DMA2DDriver *dma2dp); - void dma2dStart(DMA2DDriver *dma2dp, const DMA2DConfig *configp); - void dma2dStop(DMA2DDriver *dma2dp); -#if (TRUE == DMA2D_USE_MUTUAL_EXCLUSION) - void dma2dAcquireBusS(DMA2DDriver *dma2dp); - void dma2dAcquireBus(DMA2DDriver *dma2dp); - void dma2dReleaseBusS(DMA2DDriver *dma2dp); - void dma2dReleaseBus(DMA2DDriver *dma2dp); -#endif /* DMA2D_USE_MUTUAL_EXCLUSION */ - - /* Global methods.*/ - uint16_t dma2dGetWatermarkPosI(DMA2DDriver *dma2dp); - uint16_t dma2dGetWatermarkPos(DMA2DDriver *dma2dp); - void dma2dSetWatermarkPosI(DMA2DDriver *dma2dp, uint16_t line); - void dma2dSetWatermarkPos(DMA2DDriver *dma2dp, uint16_t line); - bool dma2dIsWatermarkEnabledI(DMA2DDriver *dma2dp); - bool dma2dIsWatermarkEnabled(DMA2DDriver *dma2dp); - void dma2dEnableWatermarkI(DMA2DDriver *dma2dp); - void dma2dEnableWatermark(DMA2DDriver *dma2dp); - void dma2dDisableWatermarkI(DMA2DDriver *dma2dp); - void dma2dDisableWatermark(DMA2DDriver *dma2dp); - uint32_t dma2dGetDeadTimeI(DMA2DDriver *dma2dp); - uint32_t dma2dGetDeadTime(DMA2DDriver *dma2dp); - void dma2dSetDeadTimeI(DMA2DDriver *dma2dp, uint32_t cycles); - void dma2dSetDeadTime(DMA2DDriver *dma2dp, uint32_t cycles); - bool dma2dIsDeadTimeEnabledI(DMA2DDriver *dma2dp); - bool dma2dIsDeadTimeEnabled(DMA2DDriver *dma2dp); - void dma2dEnableDeadTimeI(DMA2DDriver *dma2dp); - void dma2dEnableDeadTime(DMA2DDriver *dma2dp); - void dma2dDisableDeadTimeI(DMA2DDriver *dma2dp); - void dma2dDisableDeadTime(DMA2DDriver *dma2dp); - - /* Job methods.*/ - dma2d_jobmode_t dma2dJobGetModeI(DMA2DDriver *dma2dp); - dma2d_jobmode_t dma2dJobGetMode(DMA2DDriver *dma2dp); - void dma2dJobSetModeI(DMA2DDriver *dma2dp, dma2d_jobmode_t mode); - void dma2dJobSetMode(DMA2DDriver *dma2dp, dma2d_jobmode_t mode); - void dma2dJobGetSizeI(DMA2DDriver *dma2dp, - uint16_t *widthp, uint16_t *heightp); - void dma2dJobGetSize(DMA2DDriver *dma2dp, - uint16_t *widthp, uint16_t *heightp); - void dma2dJobSetSizeI(DMA2DDriver *dma2dp, uint16_t width, uint16_t height); - void dma2dJobSetSize(DMA2DDriver *dma2dp, uint16_t width, uint16_t height); - bool dma2dJobIsExecutingI(DMA2DDriver *dma2dp); - bool dma2dJobIsExecuting(DMA2DDriver *dma2dp); - void dma2dJobStartI(DMA2DDriver *dma2dp); - void dma2dJobStart(DMA2DDriver *dma2dp); - void dma2dJobExecuteS(DMA2DDriver *dma2dp); - void dma2dJobExecute(DMA2DDriver *dma2dp); - void dma2dJobSuspendI(DMA2DDriver *dma2dp); - void dma2dJobSuspend(DMA2DDriver *dma2dp); - void dma2dJobResumeI(DMA2DDriver *dma2dp); - void dma2dJobResume(DMA2DDriver *dma2dp); - void dma2dJobAbortI(DMA2DDriver *dma2dp); - void dma2dJobAbort(DMA2DDriver *dma2dp); - - /* Background layer methods.*/ - void *dma2dBgGetAddressI(DMA2DDriver *dma2dp); - void *dma2dBgGetAddress(DMA2DDriver *dma2dp); - void dma2dBgSetAddressI(DMA2DDriver *dma2dp, void *bufferp); - void dma2dBgSetAddress(DMA2DDriver *dma2dp, void *bufferp); - size_t dma2dBgGetWrapOffsetI(DMA2DDriver *dma2dp); - size_t dma2dBgGetWrapOffset(DMA2DDriver *dma2dp); - void dma2dBgSetWrapOffsetI(DMA2DDriver *dma2dp, size_t offset); - void dma2dBgSetWrapOffset(DMA2DDriver *dma2dp, size_t offset); - uint8_t dma2dBgGetConstantAlphaI(DMA2DDriver *dma2dp); - uint8_t dma2dBgGetConstantAlpha(DMA2DDriver *dma2dp); - void dma2dBgSetConstantAlphaI(DMA2DDriver *dma2dp, uint8_t a); - void dma2dBgSetConstantAlpha(DMA2DDriver *dma2dp, uint8_t a); - dma2d_amode_t dma2dBgGetAlphaModeI(DMA2DDriver *dma2dp); - dma2d_amode_t dma2dBgGetAlphaMode(DMA2DDriver *dma2dp); - void dma2dBgSetAlphaModeI(DMA2DDriver *dma2dp, dma2d_amode_t mode); - void dma2dBgSetAlphaMode(DMA2DDriver *dma2dp, dma2d_amode_t mode); - dma2d_pixfmt_t dma2dBgGetPixelFormatI(DMA2DDriver *dma2dp); - dma2d_pixfmt_t dma2dBgGetPixelFormat(DMA2DDriver *dma2dp); - void dma2dBgSetPixelFormatI(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt); - void dma2dBgSetPixelFormat(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt); - dma2d_color_t dma2dBgGetDefaultColorI(DMA2DDriver *dma2dp); - dma2d_color_t dma2dBgGetDefaultColor(DMA2DDriver *dma2dp); - void dma2dBgSetDefaultColorI(DMA2DDriver *dma2dp, dma2d_color_t c); - void dma2dBgSetDefaultColor(DMA2DDriver *dma2dp, dma2d_color_t c); - void dma2dBgGetPaletteI(DMA2DDriver *dma2dp, dma2d_palcfg_t *palettep); - void dma2dBgGetPalette(DMA2DDriver *dma2dp, dma2d_palcfg_t *palettep); - void dma2dBgSetPaletteS(DMA2DDriver *dma2dp, const dma2d_palcfg_t *palettep); - void dma2dBgSetPalette(DMA2DDriver *dma2dp, const dma2d_palcfg_t *palettep); - void dma2dBgGetLayerI(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp); - void dma2dBgGetLayer(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp); - void dma2dBgSetConfigS(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp); - void dma2dBgSetConfig(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp); - - /* Foreground layer methods.*/ - void *dma2dFgGetAddressI(DMA2DDriver *dma2dp); - void *dma2dFgGetAddress(DMA2DDriver *dma2dp); - void dma2dFgSetAddressI(DMA2DDriver *dma2dp, void *bufferp); - void dma2dFgSetAddress(DMA2DDriver *dma2dp, void *bufferp); - size_t dma2dFgGetWrapOffsetI(DMA2DDriver *dma2dp); - size_t dma2dFgGetWrapOffset(DMA2DDriver *dma2dp); - void dma2dFgSetWrapOffsetI(DMA2DDriver *dma2dp, size_t offset); - void dma2dFgSetWrapOffset(DMA2DDriver *dma2dp, size_t offset); - uint8_t dma2dFgGetConstantAlphaI(DMA2DDriver *dma2dp); - uint8_t dma2dFgGetConstantAlpha(DMA2DDriver *dma2dp); - void dma2dFgSetConstantAlphaI(DMA2DDriver *dma2dp, uint8_t a); - void dma2dFgSetConstantAlpha(DMA2DDriver *dma2dp, uint8_t a); - dma2d_amode_t dma2dFgGetAlphaModeI(DMA2DDriver *dma2dp); - dma2d_amode_t dma2dFgGetAlphaMode(DMA2DDriver *dma2dp); - void dma2dFgSetAlphaModeI(DMA2DDriver *dma2dp, dma2d_amode_t mode); - void dma2dFgSetAlphaMode(DMA2DDriver *dma2dp, dma2d_amode_t mode); - dma2d_pixfmt_t dma2dFgGetPixelFormatI(DMA2DDriver *dma2dp); - dma2d_pixfmt_t dma2dFgGetPixelFormat(DMA2DDriver *dma2dp); - void dma2dFgSetPixelFormatI(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt); - void dma2dFgSetPixelFormat(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt); - dma2d_color_t dma2dFgGetDefaultColorI(DMA2DDriver *dma2dp); - dma2d_color_t dma2dFgGetDefaultColor(DMA2DDriver *dma2dp); - void dma2dFgSetDefaultColorI(DMA2DDriver *dma2dp, dma2d_color_t c); - void dma2dFgSetDefaultColor(DMA2DDriver *dma2dp, dma2d_color_t c); - void dma2dFgGetPaletteI(DMA2DDriver *dma2dp, dma2d_palcfg_t *palettep); - void dma2dFgGetPalette(DMA2DDriver *dma2dp, dma2d_palcfg_t *palettep); - void dma2dFgSetPaletteS(DMA2DDriver *dma2dp, const dma2d_palcfg_t *palettep); - void dma2dFgSetPalette(DMA2DDriver *dma2dp, const dma2d_palcfg_t *palettep); - void dma2dFgGetLayerI(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp); - void dma2dFgGetLayer(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp); - void dma2dFgSetConfigS(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp); - void dma2dFgSetConfig(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp); - - /* Output layer methods.*/ - void *dma2dOutGetAddressI(DMA2DDriver *dma2dp); - void *dma2dOutGetAddress(DMA2DDriver *dma2dp); - void dma2dOutSetAddressI(DMA2DDriver *dma2dp, void *bufferp); - void dma2dOutSetAddress(DMA2DDriver *dma2dp, void *bufferp); - size_t dma2dOutGetWrapOffsetI(DMA2DDriver *dma2dp); - size_t dma2dOutGetWrapOffset(DMA2DDriver *dma2dp); - void dma2dOutSetWrapOffsetI(DMA2DDriver *dma2dp, size_t offset); - void dma2dOutSetWrapOffset(DMA2DDriver *dma2dp, size_t offset); - dma2d_pixfmt_t dma2dOutGetPixelFormatI(DMA2DDriver *dma2dp); - dma2d_pixfmt_t dma2dOutGetPixelFormat(DMA2DDriver *dma2dp); - void dma2dOutSetPixelFormatI(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt); - void dma2dOutSetPixelFormat(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt); - dma2d_color_t dma2dOutGetDefaultColorI(DMA2DDriver *dma2dp); - dma2d_color_t dma2dOutGetDefaultColor(DMA2DDriver *dma2dp); - void dma2dOutSetDefaultColorI(DMA2DDriver *dma2dp, dma2d_color_t c); - void dma2dOutSetDefaultColor(DMA2DDriver *dma2dp, dma2d_color_t c); - void dma2dOutGetLayerI(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp); - void dma2dOutGetLayer(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp); - void dma2dOutSetConfigI(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp); - void dma2dOutSetConfig(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp); - - /* Helper functions.*/ - const void *dma2dComputeAddressConst(const void *originp, size_t pitch, - dma2d_pixfmt_t fmt, - uint16_t x, uint16_t y); - bool dma2dIsAligned(const void *bufferp, dma2d_pixfmt_t fmt); - size_t dma2dBitsPerPixel(dma2d_pixfmt_t fmt); -#if (TRUE == DMA2D_USE_SOFTWARE_CONVERSIONS) || defined(__DOXYGEN__) - dma2d_color_t dma2dFromARGB8888(dma2d_color_t c, dma2d_pixfmt_t fmt); - dma2d_color_t dma2dToARGB8888(dma2d_color_t c, dma2d_pixfmt_t fmt); -#endif /* DMA2D_USE_SOFTWARE_CONVERSIONS */ - -#ifdef __cplusplus -} -#endif - -#endif /* STM32_DMA2D_USE_DMA2D */ - -#endif /* _STM32_DMA2D_H_ */ - -/** @} */ diff --git a/os/hal/ports/STM32/LLD/FSMCv1/fsmc.c b/os/hal/ports/STM32/LLD/FSMCv1/fsmc.c deleted file mode 100644 index 27bc429..0000000 --- a/os/hal/ports/STM32/LLD/FSMCv1/fsmc.c +++ /dev/null @@ -1,187 +0,0 @@ -/* - ChibiOS/HAL - Copyright (C) 2014 Uladzimir Pylinsky aka barthess - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -/** - * @file fsmc.c - * @brief FSMC Driver subsystem low level driver source template. - * - * @addtogroup FSMC - * @{ - */ -#include "hal.h" -#include "fsmc.h" - -#if (HAL_USE_FSMC == TRUE) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/** - * @brief FSMC1 driver identifier. - */ -#if STM32_FSMC_USE_FSMC1 || defined(__DOXYGEN__) -FSMCDriver FSMCD1; -#endif - -/*===========================================================================*/ -/* Driver local types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver interrupt handlers. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief Low level FSMC driver initialization. - * - * @notapi - */ -void fsmc_init(void) { - - if (FSMCD1.state == FSMC_UNINIT) { - FSMCD1.state = FSMC_STOP; - -#if STM32_SRAM_USE_FSMC_SRAM1 - FSMCD1.sram1 = (FSMC_SRAM_NOR_TypeDef *)(FSMC_Bank1_R_BASE); -#endif - -#if STM32_SRAM_USE_FSMC_SRAM2 - FSMCD1.sram2 = (FSMC_SRAM_NOR_TypeDef *)(FSMC_Bank1_R_BASE + 8); -#endif - -#if STM32_SRAM_USE_FSMC_SRAM3 - FSMCD1.sram3 = (FSMC_SRAM_NOR_TypeDef *)(FSMC_Bank1_R_BASE + 8 * 2); -#endif - -#if STM32_SRAM_USE_FSMC_SRAM4 - FSMCD1.sram4 = (FSMC_SRAM_NOR_TypeDef *)(FSMC_Bank1_R_BASE + 8 * 3); -#endif - -#if STM32_NAND_USE_FSMC_NAND1 - FSMCD1.nand1 = (FSMC_NAND_TypeDef *)FSMC_Bank2_R_BASE; -#endif - -#if STM32_NAND_USE_FSMC_NAND2 - FSMCD1.nand2 = (FSMC_NAND_TypeDef *)FSMC_Bank3_R_BASE; -#endif - -#if (defined(STM32F427xx) || defined(STM32F437xx) || \ - defined(STM32F429xx) || defined(STM32F439xx)) - #if STM32_USE_FSMC_SDRAM - FSMCD1.sdram = (FSMC_SDRAM_TypeDef *)FSMC_Bank5_6_R_BASE; - #endif -#endif - } -} - -/** - * @brief Configures and activates the FSMC peripheral. - * - * @param[in] fsmcp pointer to the @p FSMCDriver object - * - * @notapi - */ -void fsmc_start(FSMCDriver *fsmcp) { - - osalDbgAssert((fsmcp->state == FSMC_STOP) || (fsmcp->state == FSMC_READY), - "invalid state"); - - if (fsmcp->state == FSMC_STOP) { - /* Enables the peripheral.*/ -#if STM32_FSMC_USE_FSMC1 - if (&FSMCD1 == fsmcp) { - rccResetFSMC(); - rccEnableFSMC(FALSE); -#if (!STM32_NAND_USE_EXT_INT && HAL_USE_NAND) - nvicEnableVector(STM32_FSMC_NUMBER, STM32_FSMC_FSMC1_IRQ_PRIORITY); -#endif - } -#endif /* STM32_FSMC_USE_FSMC1 */ - - fsmcp->state = FSMC_READY; - } -} - -/** - * @brief Deactivates the FSMC peripheral. - * - * @param[in] emcp pointer to the @p FSMCDriver object - * - * @notapi - */ -void fsmc_stop(FSMCDriver *fsmcp) { - - if (fsmcp->state == FSMC_READY) { - /* Resets the peripheral.*/ - rccResetFSMC(); - - /* Disables the peripheral.*/ -#if STM32_FSMC_USE_FSMC1 - if (&FSMCD1 == fsmcp) { -#if (!STM32_NAND_USE_EXT_INT && HAL_USE_NAND) - nvicDisableVector(STM32_FSMC_NUMBER); -#endif - rccDisableFSMC(FALSE); - } -#endif /* STM32_FSMC_USE_FSMC1 */ - - fsmcp->state = FSMC_STOP; - } -} - -#if !STM32_NAND_USE_EXT_INT -/** - * @brief FSMC shared interrupt handler. - * - * @notapi - */ -CH_IRQ_HANDLER(STM32_FSMC_HANDLER) { - - CH_IRQ_PROLOGUE(); -#if STM32_NAND_USE_FSMC_NAND1 - if (FSMCD1.nand1->SR & FSMC_SR_ISR_MASK) { - NANDD1.isr_handler(&NANDD1); - } -#endif -#if STM32_NAND_USE_FSMC_NAND2 - if (FSMCD1.nand2->SR & FSMC_SR_ISR_MASK) { - NANDD2.isr_handler(&NANDD2); - } -#endif - CH_IRQ_EPILOGUE(); -} -#endif /* !STM32_NAND_USE_EXT_INT */ - -#endif /* HAL_USE_FSMC */ - -/** @} */ diff --git a/os/hal/ports/STM32/LLD/FSMCv1/fsmc.h b/os/hal/ports/STM32/LLD/FSMCv1/fsmc.h deleted file mode 100644 index 7889b01..0000000 --- a/os/hal/ports/STM32/LLD/FSMCv1/fsmc.h +++ /dev/null @@ -1,339 +0,0 @@ -/* - ChibiOS/HAL - Copyright (C) 2014 Uladzimir Pylinsky aka barthess - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -/** - * @file fsmc.h - * @brief FSMC Driver subsystem low level driver header. - * - * @addtogroup FSMC - * @{ - */ - -#ifndef _FSMC_H_ -#define _FSMC_H_ - -#if (HAL_USE_FSMC == TRUE) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver constants. */ -/*===========================================================================*/ - -/* - * (Re)define if needed base address constants supplied in ST's CMSIS - */ -#if (defined(STM32F427xx) || defined(STM32F437xx) || \ - defined(STM32F429xx) || defined(STM32F439xx)) - #if !defined(FSMC_Bank1_R_BASE) - #define FSMC_Bank1_R_BASE (FMC_R_BASE + 0x0000) - #endif - #if !defined(FSMC_Bank1E_R_BASE) - #define FSMC_Bank1E_R_BASE (FMC_R_BASE + 0x0104) - #endif - #if !defined(FSMC_Bank2_R_BASE) - #define FSMC_Bank2_R_BASE (FMC_R_BASE + 0x0060) - #endif - #if !defined(FSMC_Bank3_R_BASE) - #define FSMC_Bank3_R_BASE (FMC_R_BASE + 0x0080) - #endif - #if !defined(FSMC_Bank4_R_BASE) - #define FSMC_Bank4_R_BASE (FMC_R_BASE + 0x00A0) - #endif - #if !defined(FSMC_Bank5_R_BASE) - #define FSMC_Bank5_6_R_BASE (FMC_R_BASE + 0x0140) - #endif -#else - #if !defined(FSMC_Bank1_R_BASE) - #define FSMC_Bank1_R_BASE (FSMC_R_BASE + 0x0000) - #endif - #if !defined(FSMC_Bank1E_R_BASE) - #define FSMC_Bank1E_R_BASE (FSMC_R_BASE + 0x0104) - #endif - #if !defined(FSMC_Bank2_R_BASE) - #define FSMC_Bank2_R_BASE (FSMC_R_BASE + 0x0060) - #endif - #if !defined(FSMC_Bank3_R_BASE) - #define FSMC_Bank3_R_BASE (FSMC_R_BASE + 0x0080) - #endif - #if !defined(FSMC_Bank4_R_BASE) - #define FSMC_Bank4_R_BASE (FSMC_R_BASE + 0x00A0) - #endif -#endif - -/* - * Base bank mappings - */ -#define FSMC_Bank1_MAP_BASE ((uint32_t) 0x60000000) -#define FSMC_Bank2_MAP_BASE ((uint32_t) 0x70000000) -#define FSMC_Bank3_MAP_BASE ((uint32_t) 0x80000000) -#define FSMC_Bank4_MAP_BASE ((uint32_t) 0x90000000) -#if (defined(STM32F427xx) || defined(STM32F437xx) || \ - defined(STM32F429xx) || defined(STM32F439xx)) - #define FSMC_Bank5_MAP_BASE ((uint32_t) 0xC0000000) - #define FSMC_Bank6_MAP_BASE ((uint32_t) 0xD0000000) -#endif - -/* - * Subbunks of bank1 - */ -#define FSMC_SUBBUNK_OFFSET (1024 * 1024 * 64) -#define FSMC_Bank1_1_MAP (FSMC_Bank1_MAP_BASE) -#define FSMC_Bank1_2_MAP (FSMC_Bank1_1_MAP + FSMC_SUBBUNK_OFFSET) -#define FSMC_Bank1_3_MAP (FSMC_Bank1_2_MAP + FSMC_SUBBUNK_OFFSET) -#define FSMC_Bank1_4_MAP (FSMC_Bank1_3_MAP + FSMC_SUBBUNK_OFFSET) - -/* - * Bank 2 (NAND) - */ -#define FSMC_Bank2_MAP_COMMON (FSMC_Bank2_MAP_BASE + 0) -#define FSMC_Bank2_MAP_ATTR (FSMC_Bank2_MAP_BASE + 0x8000000) - -#define FSMC_Bank2_MAP_COMMON_DATA (FSMC_Bank2_MAP_COMMON + 0) -#define FSMC_Bank2_MAP_COMMON_CMD (FSMC_Bank2_MAP_COMMON + 0x10000) -#define FSMC_Bank2_MAP_COMMON_ADDR (FSMC_Bank2_MAP_COMMON + 0x20000) - -#define FSMC_Bank2_MAP_ATTR_DATA (FSMC_Bank2_MAP_ATTR + 0) -#define FSMC_Bank2_MAP_ATTR_CMD (FSMC_Bank2_MAP_ATTR + 0x10000) -#define FSMC_Bank2_MAP_ATTR_ADDR (FSMC_Bank2_MAP_ATTR + 0x20000) - -/* - * Bank 3 (NAND) - */ -#define FSMC_Bank3_MAP_COMMON (FSMC_Bank3_MAP_BASE + 0) -#define FSMC_Bank3_MAP_ATTR (FSMC_Bank3_MAP_BASE + 0x8000000) - -#define FSMC_Bank3_MAP_COMMON_DATA (FSMC_Bank3_MAP_COMMON + 0) -#define FSMC_Bank3_MAP_COMMON_CMD (FSMC_Bank3_MAP_COMMON + 0x10000) -#define FSMC_Bank3_MAP_COMMON_ADDR (FSMC_Bank3_MAP_COMMON + 0x20000) - -#define FSMC_Bank3_MAP_ATTR_DATA (FSMC_Bank3_MAP_ATTR + 0) -#define FSMC_Bank3_MAP_ATTR_CMD (FSMC_Bank3_MAP_ATTR + 0x10000) -#define FSMC_Bank3_MAP_ATTR_ADDR (FSMC_Bank3_MAP_ATTR + 0x20000) - -/* - * Bank 4 (PC card) - */ -#define FSMC_Bank4_MAP_COMMON (FSMC_Bank4_MAP_BASE + 0) -#define FSMC_Bank4_MAP_ATTR (FSMC_Bank4_MAP_BASE + 0x8000000) -#define FSMC_Bank4_MAP_IO (FSMC_Bank4_MAP_BASE + 0xC000000) - -/* - * More convenient typedefs than CMSIS has - */ -typedef struct { - __IO uint32_t PCR; /**< NAND Flash control */ - __IO uint32_t SR; /**< NAND Flash FIFO status and interrupt */ - __IO uint32_t PMEM; /**< NAND Flash Common memory space timing */ - __IO uint32_t PATT; /**< NAND Flash Attribute memory space timing */ - uint32_t RESERVED0; /**< Reserved, 0x70 */ - __IO uint32_t ECCR; /**< NAND Flash ECC result registers */ -} FSMC_NAND_TypeDef; - -typedef struct { - __IO uint32_t PCR; /**< PC Card control */ - __IO uint32_t SR; /**< PC Card FIFO status and interrupt */ - __IO uint32_t PMEM; /**< PC Card Common memory space timing */ - __IO uint32_t PATT; /**< PC Card Attribute memory space timing */ - __IO uint32_t PIO; /**< PC Card I/O space timing */ -} FSMC_PCCard_TypeDef; - -typedef struct { - __IO uint32_t BCR; /**< SRAM/NOR chip-select control registers */ - __IO uint32_t BTR; /**< SRAM/NOR chip-select timing registers */ - uint32_t RESERVED[63]; /**< Reserved */ - __IO uint32_t BWTR; /**< SRAM/NOR write timing registers */ -} FSMC_SRAM_NOR_TypeDef; - -#if (defined(STM32F427xx) || defined(STM32F437xx) || \ - defined(STM32F429xx) || defined(STM32F439xx)) - -typedef struct { - __IO uint32_t SDCR1; /**< SDRAM control register (bank 1) */ - __IO uint32_t SDCR2; /**< SDRAM control register (bank 2) */ - __IO uint32_t SDTR1; /**< SDRAM timing register (bank 1) */ - __IO uint32_t SDTR2; /**< SDRAM timing register (bank 2) */ - __IO uint32_t SDCMR; /**< SDRAM comand mode register */ - __IO uint32_t SDRTR; /**< SDRAM refresh timer register */ - __IO uint32_t SDSR; /**< SDRAM status register */ -} FSMC_SDRAM_TypeDef; - -#endif - -/** - * @brief PCR register - */ -#define FSMC_PCR_PWAITEN ((uint32_t)0x00000002) -#define FSMC_PCR_PBKEN ((uint32_t)0x00000004) -#define FSMC_PCR_PTYP ((uint32_t)0x00000008) -#define FSMC_PCR_ECCEN ((uint32_t)0x00000040) -#define FSMC_PCR_PTYP_PCCARD 0 -#define FSMC_PCR_PTYP_NAND FSMC_PCR_PTYP - -/** - * @brief SR register - */ -#define FSMC_SR_IRS ((uint8_t)0x01) -#define FSMC_SR_ILS ((uint8_t)0x02) -#define FSMC_SR_IFS ((uint8_t)0x04) -#define FSMC_SR_IREN ((uint8_t)0x08) -#define FSMC_SR_ILEN ((uint8_t)0x10) -#define FSMC_SR_IFEN ((uint8_t)0x20) -#define FSMC_SR_FEMPT ((uint8_t)0x40) -#define FSMC_SR_ISR_MASK (FSMC_SR_IRS | FSMC_SR_ILS | FSMC_SR_IFS) - -/** - * @brief BCR register - */ -#define FSMC_BCR_MBKEN ((uint32_t)1 << 0) -#define FSMC_BCR_MUXEN ((uint32_t)1 << 1) -#define FSMC_BCR_MTYP_SRAM ((uint32_t)0 << 2) -#define FSMC_BCR_MTYP_PSRAM ((uint32_t)1 << 2) -#define FSMC_BCR_MTYP_NOR_NAND ((uint32_t)2 << 2) -#define FSMC_BCR_MTYP_RESERVED ((uint32_t)3 << 2) -#define FSMC_BCR_MWID_8 ((uint32_t)0 << 4) -#define FSMC_BCR_MWID_16 ((uint32_t)1 << 4) -#if (defined(STM32F427xx) || defined(STM32F437xx) || \ - defined(STM32F429xx) || defined(STM32F439xx)) -#define FSMC_BCR_MWID_32 ((uint32_t)2 << 4) -#else -#define FSMC_BCR_MWID_RESERVED1 ((uint32_t)2 << 4) -#endif -#define FSMC_BCR_MWID_RESERVED2 ((uint32_t)3 << 4) -#define FSMC_BCR_FACCEN ((uint32_t)1 << 6) -#define FSMC_BCR_BURSTEN ((uint32_t)1 << 8) -#define FSMC_BCR_WAITPOL ((uint32_t)1 << 9) -#define FSMC_BCR_WRAPMOD ((uint32_t)1 << 10) -#define FSMC_BCR_WAITCFG ((uint32_t)1 << 11) -#define FSMC_BCR_WREN ((uint32_t)1 << 12) -#define FSMC_BCR_WAITEN ((uint32_t)1 << 13) -#define FSMC_BCR_EXTMOD ((uint32_t)1 << 14) -#define FSMC_BCR_ASYNCWAIT ((uint32_t)1 << 15) -#define FSMC_BCR_CBURSTRW ((uint32_t)1 << 19) - -/*===========================================================================*/ -/* Driver pre-compile time settings. */ -/*===========================================================================*/ - -/** - * @name Configuration options - * @{ - */ -/** - * @brief FSMC driver enable switch. - * @details If set to @p TRUE the support for FSMC is included. - */ -#if !defined(STM32_FSMC_USE_FSMC1) || defined(__DOXYGEN__) -#define STM32_FSMC_USE_FSMC1 FALSE -#endif - -/** - * @brief Internal FSMC interrupt enable switch - * @details MCUs in 100-pin package has no dedicated interrupt pin for FSMC. - * You have to use EXTI module instead to workaround this issue. - */ -#if !defined(STM32_NAND_USE_EXT_INT) || defined(__DOXYGEN__) -#define STM32_NAND_USE_EXT_INT FALSE -#endif - -/** @} */ - -/*===========================================================================*/ -/* Derived constants and error checks. */ -/*===========================================================================*/ -#if !STM32_FSMC_USE_FSMC1 -#error "FSMC driver activated but no FSMC peripheral assigned" -#endif - -/*===========================================================================*/ -/* Driver data structures and types. */ -/*===========================================================================*/ - -/** - * @brief Type of a structure representing an FSMC driver. - */ -typedef struct FSMCDriver FSMCDriver; - -/** - * @brief Driver state machine possible states. - */ -typedef enum { - FSMC_UNINIT = 0, /**< Not initialized. */ - FSMC_STOP = 1, /**< Stopped. */ - FSMC_READY = 2, /**< Ready. */ -} fsmcstate_t; - -/** - * @brief Structure representing an FSMC driver. - */ -struct FSMCDriver { - /** - * @brief Driver state. - */ - fsmcstate_t state; - /* End of the mandatory fields.*/ - -#if STM32_SRAM_USE_FSMC_SRAM1 - FSMC_SRAM_NOR_TypeDef *sram1; -#endif -#if STM32_SRAM_USE_FSMC_SRAM2 - FSMC_SRAM_NOR_TypeDef *sram2; -#endif -#if STM32_SRAM_USE_FSMC_SRAM3 - FSMC_SRAM_NOR_TypeDef *sram3; -#endif -#if STM32_SRAM_USE_FSMC_SRAM4 - FSMC_SRAM_NOR_TypeDef *sram4; -#endif -#if STM32_NAND_USE_FSMC_NAND1 - FSMC_NAND_TypeDef *nand1; -#endif -#if STM32_NAND_USE_FSMC_NAND2 - FSMC_NAND_TypeDef *nand2; -#endif -#if (defined(STM32F427xx) || defined(STM32F437xx) || \ - defined(STM32F429xx) || defined(STM32F439xx)) - #if STM32_USE_FSMC_SDRAM - FSMC_SDRAM_TypeDef *sdram; - #endif -#endif -}; - -/*===========================================================================*/ -/* Driver macros. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -#if STM32_FSMC_USE_FSMC1 && !defined(__DOXYGEN__) -extern FSMCDriver FSMCD1; -#endif - -#ifdef __cplusplus -extern "C" { -#endif - void fsmc_init(void); - void fsmc_start(FSMCDriver *fsmcp); - void fsmc_stop(FSMCDriver *fsmcp); -#ifdef __cplusplus -} -#endif - -#endif /* HAL_USE_FSMC */ - -#endif /* _FSMC_H_ */ - -/** @} */ diff --git a/os/hal/ports/STM32/LLD/FSMCv1/fsmc_sdram.c b/os/hal/ports/STM32/LLD/FSMCv1/fsmc_sdram.c deleted file mode 100644 index d8db8a6..0000000 --- a/os/hal/ports/STM32/LLD/FSMCv1/fsmc_sdram.c +++ /dev/null @@ -1,211 +0,0 @@ -/* - ChibiOS/HAL - Copyright (C) 2014 Uladzimir Pylinsky aka barthess - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ -/* - SDRAM routines added by Nick Klimov aka progfin. - */ - -/** - * @file fsmc_sdram.c - * @brief SDRAM Driver subsystem low level driver source. - * - * @addtogroup SDRAM - * @{ - */ - -#include "hal.h" - -#if (defined(STM32F427xx) || defined(STM32F437xx) || \ - defined(STM32F429xx) || defined(STM32F439xx)) - -#if (STM32_USE_FSMC_SDRAM == TRUE) || defined(__DOXYGEN__) - -#include "fsmc_sdram.h" - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/** - * FMC_Command_Mode - */ -#define FMCCM_NORMAL ((uint32_t)0x00000000) -#define FMCCM_CLK_ENABLED ((uint32_t)0x00000001) -#define FMCCM_PALL ((uint32_t)0x00000002) -#define FMCCM_AUTO_REFRESH ((uint32_t)0x00000003) -#define FMCCM_LOAD_MODE ((uint32_t)0x00000004) -#define FMCCM_SELFREFRESH ((uint32_t)0x00000005) -#define FMCCM_POWER_DOWN ((uint32_t)0x00000006) - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ -/** - * @brief SDRAM driver identifier. - */ -SDRAMDriver SDRAMD; - -/*===========================================================================*/ -/* Driver local types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -/** - * @brief Wait until the SDRAM controller is ready. - * - * @notapi - */ -static void _sdram_wait_ready(void) { - /* Wait until the SDRAM controller is ready */ - while (SDRAMD.sdram->SDSR & FMC_SDSR_BUSY); -} - -/** - * @brief Executes the SDRAM memory initialization sequence. - * - * @param[in] cfgp pointer to the @p SDRAMConfig object - * - * @notapi - */ -static void _sdram_init_sequence(const SDRAMConfig *cfgp) { - - uint32_t command_target = 0; - -#if STM32_SDRAM_USE_FSMC_SDRAM1 - command_target |= FMC_SDCMR_CTB1; -#endif -#if STM32_SDRAM_USE_FSMC_SDRAM2 - command_target |= FMC_SDCMR_CTB2; -#endif - - /* Step 3: Configure a clock configuration enable command.*/ - _sdram_wait_ready(); - SDRAMD.sdram->SDCMR = FMCCM_CLK_ENABLED | command_target; - - /* Step 4: Insert delay (tipically 100uS).*/ - osalThreadSleepMilliseconds(1); - - /* Step 5: Configure a PALL (precharge all) command.*/ - _sdram_wait_ready(); - SDRAMD.sdram->SDCMR = FMCCM_PALL | command_target; - - /* Step 6.1: Configure a Auto-Refresh command: send the first command.*/ - _sdram_wait_ready(); - SDRAMD.sdram->SDCMR = FMCCM_AUTO_REFRESH | command_target | - (cfgp->sdcmr & FMC_SDCMR_NRFS); - - /* Step 6.2: Send the second command.*/ - _sdram_wait_ready(); - SDRAMD.sdram->SDCMR = FMCCM_AUTO_REFRESH | command_target | - (cfgp->sdcmr & FMC_SDCMR_NRFS); - - /* Step 7: Program the external memory mode register.*/ - _sdram_wait_ready(); - SDRAMD.sdram->SDCMR = FMCCM_LOAD_MODE | command_target | - (cfgp->sdcmr & FMC_SDCMR_MRD); - - /* Step 8: Set clock.*/ - _sdram_wait_ready(); - SDRAMD.sdram->SDRTR = cfgp->sdrtr & FMC_SDRTR_COUNT; - - _sdram_wait_ready(); -} - -/*===========================================================================*/ -/* Driver interrupt handlers. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief Low level SDRAM driver initialization. - */ -void fsmcSdramInit(void) { - - fsmc_init(); - - SDRAMD.sdram = FSMCD1.sdram; - SDRAMD.state = SDRAM_STOP; -} - -/** - * @brief Configures and activates the SDRAM peripheral. - * - * @param[in] sdramp pointer to the @p SDRAMDriver object - * @param[in] cfgp pointer to the @p SDRAMConfig object - */ -void fsmcSdramStart(SDRAMDriver *sdramp, const SDRAMConfig *cfgp) { - - if (FSMCD1.state == FSMC_STOP) - fsmc_start(&FSMCD1); - - osalDbgAssert((sdramp->state == SDRAM_STOP) || (sdramp->state == SDRAM_READY), - "SDRAM. Invalid state."); - - if (sdramp->state == SDRAM_STOP) { - - /* Even if you need only bank2 you must properly set up SDCR and SDTR - regitsters for bank1 too. Both banks will be tuned equally assuming - connected memory ICs are equal.*/ - sdramp->sdram->SDCR1 = cfgp->sdcr; - sdramp->sdram->SDTR1 = cfgp->sdtr; - sdramp->sdram->SDCR2 = cfgp->sdcr; - sdramp->sdram->SDTR2 = cfgp->sdtr; - - _sdram_init_sequence(cfgp); - - sdramp->state = SDRAM_READY; - } -} - -/** - * @brief Deactivates the SDRAM peripheral. - * - * @param[in] sdramp pointer to the @p SDRAMDriver object - * - * @notapi - */ -void fsmcSdramStop(SDRAMDriver *sdramp) { - - uint32_t command_target = 0; - -#if STM32_SDRAM_USE_FSMC_SDRAM1 - command_target |= FMC_SDCMR_CTB1; -#endif -#if STM32_SDRAM_USE_FSMC_SDRAM2 - command_target |= FMC_SDCMR_CTB2; -#endif - - if (sdramp->state == SDRAM_READY) { - SDRAMD.sdram->SDCMR = FMCCM_POWER_DOWN | command_target; - sdramp->state = SDRAM_STOP; - } -} - -#endif /* STM32_USE_FSMC_SDRAM */ - -#endif /* STM32F427xx / STM32F429xx / STM32F437xx / STM32F439xx */ - -/** @} */ - diff --git a/os/hal/ports/STM32/LLD/FSMCv1/fsmc_sdram.h b/os/hal/ports/STM32/LLD/FSMCv1/fsmc_sdram.h deleted file mode 100644 index d5d5476..0000000 --- a/os/hal/ports/STM32/LLD/FSMCv1/fsmc_sdram.h +++ /dev/null @@ -1,171 +0,0 @@ -/* - ChibiOS/HAL - Copyright (C) 2014 Uladzimir Pylinsky aka barthess - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ -/* - SDRAM routines added by Nick Klimov aka progfin. - */ - -/** - * @file fsmc_sdram.h - * @brief SDRAM Driver subsystem low level driver header. - * - * @addtogroup SDRAM - * @{ - */ - -#ifndef _FMC_SDRAM_H_ -#define _FMC_SDRAM_H_ - -#if (defined(STM32F427xx) || defined(STM32F437xx) || \ - defined(STM32F429xx) || defined(STM32F439xx)) - -#include "fsmc.h" - -#if (STM32_USE_FSMC_SDRAM == TRUE) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver constants. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver pre-compile time settings. */ -/*===========================================================================*/ -/** - * @name Configuration options - * @{ - */ - -/** - * @brief SDRAM driver enable switch. - * @details If set to @p TRUE the support for SDRAM1 is included. - */ -#if !defined(STM32_SDRAM_USE_FSMC_SDRAM1) || defined(__DOXYGEN__) -#define STM32_SDRAM_USE_FSMC_SDRAM1 FALSE -#else -#define STM32_SDRAM1_MAP_BASE FSMC_Bank5_MAP_BASE -#endif - -/** - * @brief SDRAM driver enable switch. - * @details If set to @p TRUE the support for SDRAM2 is included. - */ -#if !defined(STM32_SDRAM_USE_FSMC_SDRAM2) || defined(__DOXYGEN__) -#define STM32_SDRAM_USE_FSMC_SDRAM2 FALSE -#else -#define STM32_SDRAM2_MAP_BASE FSMC_Bank6_MAP_BASE -#endif - -/** @} */ - -/*===========================================================================*/ -/* Derived constants and error checks. */ -/*===========================================================================*/ - -#if !STM32_SDRAM_USE_FSMC_SDRAM1 && !STM32_SDRAM_USE_FSMC_SDRAM2 -#error "SDRAM driver activated but no SDRAM peripheral assigned" -#endif - -#if (STM32_SDRAM_USE_FSMC_SDRAM1 || STM32_SDRAM_USE_FSMC_SDRAM2) && !STM32_HAS_FSMC -#error "FMC not present in the selected device" -#endif - -/*===========================================================================*/ -/* Driver data structures and types. */ -/*===========================================================================*/ -/** - * @brief Driver state machine possible states. - */ -typedef enum { - SDRAM_UNINIT = 0, /**< Not initialized. */ - SDRAM_STOP = 1, /**< Stopped. */ - SDRAM_READY = 2, /**< Ready. */ -} sdramstate_t; - -/** - * @brief Type of a structure representing an SDRAM driver. - */ -typedef struct SDRAMDriver SDRAMDriver; - -/** - * @brief Driver configuration structure. - * @note It could be empty on some architectures. - */ -typedef struct { - /** - * @brief SDRAM control register. - * @note Its value will be used for both banks. - */ - uint32_t sdcr; - - /** - * @brief SDRAM timing register. - * @note Its value will be used for both banks. - */ - uint32_t sdtr; - - /** - * @brief SDRAM command mode register. - * @note Only its MRD and NRFS bits will be used. - */ - uint32_t sdcmr; - - /** - * @brief SDRAM refresh timer register. - * @note Only its COUNT bits will be used. - */ - uint32_t sdrtr; -} SDRAMConfig; - -/** - * @brief Structure representing an SDRAM driver. - */ -struct SDRAMDriver { - /** - * @brief Driver state. - */ - sdramstate_t state; - /** - * @brief Pointer to the FMC SDRAM registers block. - */ - FSMC_SDRAM_TypeDef *sdram; -}; - -/*===========================================================================*/ -/* Driver macros. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -extern SDRAMDriver SDRAMD; - -#ifdef __cplusplus -extern "C" { -#endif - void fsmcSdramInit(void); - void fsmcSdramStart(SDRAMDriver *sdramp, const SDRAMConfig *cfgp); - void fsmcSdramStop(SDRAMDriver *sdramp); -#ifdef __cplusplus -} -#endif - -#endif /* STM32_USE_FSMC_SDRAM */ - -#endif /* STM32F427xx / STM32F429xx / STM32F437xx / STM32F439xx */ - -#endif /* _FMC_SDRAM_H_ */ - -/** @} */ diff --git a/os/hal/ports/STM32/LLD/FSMCv1/fsmc_sram.c b/os/hal/ports/STM32/LLD/FSMCv1/fsmc_sram.c deleted file mode 100644 index 2375738..0000000 --- a/os/hal/ports/STM32/LLD/FSMCv1/fsmc_sram.c +++ /dev/null @@ -1,156 +0,0 @@ -/* - ChibiOS/HAL - Copyright (C) 2014 Uladzimir Pylinsky aka barthess - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -/** - * @file fsmc_sram.c - * @brief SRAM Driver subsystem low level driver source. - * - * @addtogroup SRAM - * @{ - */ -#include "hal.h" -#include "fsmc_sram.h" - -#if (STM32_USE_FSMC_SRAM == TRUE) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ -/** - * @brief SRAM1 driver identifier. - */ -#if STM32_SRAM_USE_FSMC_SRAM1 || defined(__DOXYGEN__) -SRAMDriver SRAMD1; -#endif - -/** - * @brief SRAM2 driver identifier. - */ -#if STM32_SRAM_USE_FSMC_SRAM2 || defined(__DOXYGEN__) -SRAMDriver SRAMD2; -#endif - -/** - * @brief SRAM3 driver identifier. - */ -#if STM32_SRAM_USE_FSMC_SRAM3 || defined(__DOXYGEN__) -SRAMDriver SRAMD3; -#endif - -/** - * @brief SRAM4 driver identifier. - */ -#if STM32_SRAM_USE_FSMC_SRAM4 || defined(__DOXYGEN__) -SRAMDriver SRAMD4; -#endif - -/*===========================================================================*/ -/* Driver local types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver interrupt handlers. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief Low level SRAM driver initialization. - * - * @notapi - */ -void fsmcSramInit(void) { - - fsmc_init(); - -#if STM32_SRAM_USE_FSMC_SRAM1 - SRAMD1.sram = FSMCD1.sram1; - SRAMD1.state = SRAM_STOP; -#endif /* STM32_SRAM_USE_FSMC_SRAM1 */ - -#if STM32_SRAM_USE_FSMC_SRAM2 - SRAMD2.sram = FSMCD1.sram2; - SRAMD2.state = SRAM_STOP; -#endif /* STM32_SRAM_USE_FSMC_SRAM2 */ - -#if STM32_SRAM_USE_FSMC_SRAM3 - SRAMD3.sram = FSMCD1.sram3; - SRAMD3.state = SRAM_STOP; -#endif /* STM32_SRAM_USE_FSMC_SRAM3 */ - -#if STM32_SRAM_USE_FSMC_SRAM4 - SRAMD4.sram = FSMCD1.sram4; - SRAMD4.state = SRAM_STOP; -#endif /* STM32_SRAM_USE_FSMC_SRAM4 */ -} - -/** - * @brief Configures and activates the SRAM peripheral. - * - * @param[in] sramp pointer to the @p SRAMDriver object - * @param[in] cfgp pointer to the @p SRAMConfig object - * - * @notapi - */ -void fsmcSramStart(SRAMDriver *sramp, const SRAMConfig *cfgp) { - - if (FSMCD1.state == FSMC_STOP) - fsmc_start(&FSMCD1); - - osalDbgAssert((sramp->state == SRAM_STOP) || (sramp->state == SRAM_READY), - "invalid state"); - - if (sramp->state == SRAM_STOP) { - sramp->sram->BCR = cfgp->bcr | FSMC_BCR_MBKEN; - sramp->sram->BTR = cfgp->btr; - sramp->sram->BWTR = cfgp->bwtr; - sramp->state = SRAM_READY; - } -} - -/** - * @brief Deactivates the SRAM peripheral. - * - * @param[in] sramp pointer to the @p SRAMDriver object - * - * @notapi - */ -void fsmcSramStop(SRAMDriver *sramp) { - - if (sramp->state == SRAM_READY) { - sramp->sram->BCR &= ~FSMC_BCR_MBKEN; - sramp->state = SRAM_STOP; - } -} - -#endif /* STM32_USE_FSMC_SRAM */ - -/** @} */ - diff --git a/os/hal/ports/STM32/LLD/FSMCv1/fsmc_sram.h b/os/hal/ports/STM32/LLD/FSMCv1/fsmc_sram.h deleted file mode 100644 index bf5c32a..0000000 --- a/os/hal/ports/STM32/LLD/FSMCv1/fsmc_sram.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - ChibiOS/HAL - Copyright (C) 2014 Uladzimir Pylinsky aka barthess - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -/** - * @file fsmc_sram.h - * @brief SRAM Driver subsystem low level driver header. - * - * @addtogroup SRAM - * @{ - */ - -#ifndef _FSMC_SRAM_H_ -#define _FSMC_SRAM_H_ - -#include "fsmc.h" - -#if (STM32_USE_FSMC_SRAM == TRUE) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver constants. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver pre-compile time settings. */ -/*===========================================================================*/ -/** - * @name Configuration options - * @{ - */ - -/** - * @brief SRAM driver enable switch. - * @details If set to @p TRUE the support for SRAM1 is included. - */ -#if !defined(STM32_SRAM_USE_FSMC_SRAM1) || defined(__DOXYGEN__) -#define STM32_SRAM_USE_FSMC_SRAM1 FALSE -#endif - -/** - * @brief SRAM driver enable switch. - * @details If set to @p TRUE the support for SRAM2 is included. - */ -#if !defined(STM32_SRAM_USE_FSMC_SRAM2) || defined(__DOXYGEN__) -#define STM32_SRAM_USE_FSMC_SRAM2 FALSE -#endif - -/** - * @brief SRAM driver enable switch. - * @details If set to @p TRUE the support for SRAM3 is included. - */ -#if !defined(STM32_SRAM_USE_FSMC_SRAM3) || defined(__DOXYGEN__) -#define STM32_SRAM_USE_FSMC_SRAM3 FALSE -#endif - -/** - * @brief SRAM driver enable switch. - * @details If set to @p TRUE the support for SRAM4 is included. - */ -#if !defined(STM32_SRAM_USE_FSMC_SRAM4) || defined(__DOXYGEN__) -#define STM32_SRAM_USE_FSMC_SRAM4 FALSE -#endif - -/** @} */ - -/*===========================================================================*/ -/* Derived constants and error checks. */ -/*===========================================================================*/ - -#if !STM32_SRAM_USE_FSMC_SRAM1 && !STM32_SRAM_USE_FSMC_SRAM2 && \ - !STM32_SRAM_USE_FSMC_SRAM3 && !STM32_SRAM_USE_FSMC_SRAM4 -#error "SRAM driver activated but no SRAM peripheral assigned" -#endif - -#if (STM32_SRAM_USE_FSMC_SRAM1 || STM32_SRAM_USE_FSMC_SRAM2 || \ - STM32_SRAM_USE_FSMC_SRAM3 || STM32_SRAM_USE_FSMC_SRAM4) && !STM32_HAS_FSMC -#error "FSMC not present in the selected device" -#endif - -/*===========================================================================*/ -/* Driver data structures and types. */ -/*===========================================================================*/ -/** - * @brief Driver state machine possible states. - */ -typedef enum { - SRAM_UNINIT = 0, /**< Not initialized. */ - SRAM_STOP = 1, /**< Stopped. */ - SRAM_READY = 2, /**< Ready. */ -} sramstate_t; - -/** - * @brief Type of a structure representing an NAND driver. - */ -typedef struct SRAMDriver SRAMDriver; - -/** - * @brief Driver configuration structure. - * @note It could be empty on some architectures. - * @note Some bits in BCR register will be forced by driver. - */ -typedef struct { - uint32_t bcr; - uint32_t btr; - uint32_t bwtr; -} SRAMConfig; - -/** - * @brief Structure representing an NAND driver. - */ -struct SRAMDriver { - /** - * @brief Driver state. - */ - sramstate_t state; - /** - * @brief Pointer to the FSMC SRAM registers block. - */ - FSMC_SRAM_NOR_TypeDef *sram; -}; - -/*===========================================================================*/ -/* Driver macros. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -#if STM32_SRAM_USE_FSMC_SRAM1 && !defined(__DOXYGEN__) -extern SRAMDriver SRAMD1; -#endif - -#if STM32_SRAM_USE_FSMC_SRAM2 && !defined(__DOXYGEN__) -extern SRAMDriver SRAMD2; -#endif - -#if STM32_SRAM_USE_FSMC_SRAM3 && !defined(__DOXYGEN__) -extern SRAMDriver SRAMD3; -#endif - -#if STM32_SRAM_USE_FSMC_SRAM4 && !defined(__DOXYGEN__) -extern SRAMDriver SRAMD4; -#endif - -#ifdef __cplusplus -extern "C" { -#endif - void fsmcSramInit(void); - void fsmcSramStart(SRAMDriver *sramp, const SRAMConfig *cfgp); - void fsmcSramStop(SRAMDriver *sramp); -#ifdef __cplusplus -} -#endif - -#endif /* STM32_USE_FSMC_SRAM */ - -#endif /* _FSMC_SRAM_H_ */ - -/** @} */ diff --git a/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc.c b/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc.c new file mode 100644 index 0000000..fe48696 --- /dev/null +++ b/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc.c @@ -0,0 +1,187 @@ +/* + ChibiOS/HAL - Copyright (C) 2014 Uladzimir Pylinsky aka barthess + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file fsmc.c + * @brief FSMC Driver subsystem low level driver source template. + * + * @addtogroup FSMC + * @{ + */ +#include "hal.h" +#include "hal_fsmc.h" + +#if (HAL_USE_FSMC == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief FSMC1 driver identifier. + */ +#if STM32_FSMC_USE_FSMC1 || defined(__DOXYGEN__) +FSMCDriver FSMCD1; +#endif + +/*===========================================================================*/ +/* Driver local types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level FSMC driver initialization. + * + * @notapi + */ +void fsmc_init(void) { + + if (FSMCD1.state == FSMC_UNINIT) { + FSMCD1.state = FSMC_STOP; + +#if STM32_SRAM_USE_FSMC_SRAM1 + FSMCD1.sram1 = (FSMC_SRAM_NOR_TypeDef *)(FSMC_Bank1_R_BASE); +#endif + +#if STM32_SRAM_USE_FSMC_SRAM2 + FSMCD1.sram2 = (FSMC_SRAM_NOR_TypeDef *)(FSMC_Bank1_R_BASE + 8); +#endif + +#if STM32_SRAM_USE_FSMC_SRAM3 + FSMCD1.sram3 = (FSMC_SRAM_NOR_TypeDef *)(FSMC_Bank1_R_BASE + 8 * 2); +#endif + +#if STM32_SRAM_USE_FSMC_SRAM4 + FSMCD1.sram4 = (FSMC_SRAM_NOR_TypeDef *)(FSMC_Bank1_R_BASE + 8 * 3); +#endif + +#if STM32_NAND_USE_FSMC_NAND1 + FSMCD1.nand1 = (FSMC_NAND_TypeDef *)FSMC_Bank2_R_BASE; +#endif + +#if STM32_NAND_USE_FSMC_NAND2 + FSMCD1.nand2 = (FSMC_NAND_TypeDef *)FSMC_Bank3_R_BASE; +#endif + +#if (defined(STM32F427xx) || defined(STM32F437xx) || \ + defined(STM32F429xx) || defined(STM32F439xx)) + #if STM32_USE_FSMC_SDRAM + FSMCD1.sdram = (FSMC_SDRAM_TypeDef *)FSMC_Bank5_6_R_BASE; + #endif +#endif + } +} + +/** + * @brief Configures and activates the FSMC peripheral. + * + * @param[in] fsmcp pointer to the @p FSMCDriver object + * + * @notapi + */ +void fsmc_start(FSMCDriver *fsmcp) { + + osalDbgAssert((fsmcp->state == FSMC_STOP) || (fsmcp->state == FSMC_READY), + "invalid state"); + + if (fsmcp->state == FSMC_STOP) { + /* Enables the peripheral.*/ +#if STM32_FSMC_USE_FSMC1 + if (&FSMCD1 == fsmcp) { + rccResetFSMC(); + rccEnableFSMC(FALSE); +#if (!STM32_NAND_USE_EXT_INT && HAL_USE_NAND) + nvicEnableVector(STM32_FSMC_NUMBER, STM32_FSMC_FSMC1_IRQ_PRIORITY); +#endif + } +#endif /* STM32_FSMC_USE_FSMC1 */ + + fsmcp->state = FSMC_READY; + } +} + +/** + * @brief Deactivates the FSMC peripheral. + * + * @param[in] emcp pointer to the @p FSMCDriver object + * + * @notapi + */ +void fsmc_stop(FSMCDriver *fsmcp) { + + if (fsmcp->state == FSMC_READY) { + /* Resets the peripheral.*/ + rccResetFSMC(); + + /* Disables the peripheral.*/ +#if STM32_FSMC_USE_FSMC1 + if (&FSMCD1 == fsmcp) { +#if (!STM32_NAND_USE_EXT_INT && HAL_USE_NAND) + nvicDisableVector(STM32_FSMC_NUMBER); +#endif + rccDisableFSMC(FALSE); + } +#endif /* STM32_FSMC_USE_FSMC1 */ + + fsmcp->state = FSMC_STOP; + } +} + +#if !STM32_NAND_USE_EXT_INT +/** + * @brief FSMC shared interrupt handler. + * + * @notapi + */ +CH_IRQ_HANDLER(STM32_FSMC_HANDLER) { + + CH_IRQ_PROLOGUE(); +#if STM32_NAND_USE_FSMC_NAND1 + if (FSMCD1.nand1->SR & FSMC_SR_ISR_MASK) { + NANDD1.isr_handler(&NANDD1); + } +#endif +#if STM32_NAND_USE_FSMC_NAND2 + if (FSMCD1.nand2->SR & FSMC_SR_ISR_MASK) { + NANDD2.isr_handler(&NANDD2); + } +#endif + CH_IRQ_EPILOGUE(); +} +#endif /* !STM32_NAND_USE_EXT_INT */ + +#endif /* HAL_USE_FSMC */ + +/** @} */ diff --git a/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc.h b/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc.h new file mode 100644 index 0000000..7889b01 --- /dev/null +++ b/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc.h @@ -0,0 +1,339 @@ +/* + ChibiOS/HAL - Copyright (C) 2014 Uladzimir Pylinsky aka barthess + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file fsmc.h + * @brief FSMC Driver subsystem low level driver header. + * + * @addtogroup FSMC + * @{ + */ + +#ifndef _FSMC_H_ +#define _FSMC_H_ + +#if (HAL_USE_FSMC == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/* + * (Re)define if needed base address constants supplied in ST's CMSIS + */ +#if (defined(STM32F427xx) || defined(STM32F437xx) || \ + defined(STM32F429xx) || defined(STM32F439xx)) + #if !defined(FSMC_Bank1_R_BASE) + #define FSMC_Bank1_R_BASE (FMC_R_BASE + 0x0000) + #endif + #if !defined(FSMC_Bank1E_R_BASE) + #define FSMC_Bank1E_R_BASE (FMC_R_BASE + 0x0104) + #endif + #if !defined(FSMC_Bank2_R_BASE) + #define FSMC_Bank2_R_BASE (FMC_R_BASE + 0x0060) + #endif + #if !defined(FSMC_Bank3_R_BASE) + #define FSMC_Bank3_R_BASE (FMC_R_BASE + 0x0080) + #endif + #if !defined(FSMC_Bank4_R_BASE) + #define FSMC_Bank4_R_BASE (FMC_R_BASE + 0x00A0) + #endif + #if !defined(FSMC_Bank5_R_BASE) + #define FSMC_Bank5_6_R_BASE (FMC_R_BASE + 0x0140) + #endif +#else + #if !defined(FSMC_Bank1_R_BASE) + #define FSMC_Bank1_R_BASE (FSMC_R_BASE + 0x0000) + #endif + #if !defined(FSMC_Bank1E_R_BASE) + #define FSMC_Bank1E_R_BASE (FSMC_R_BASE + 0x0104) + #endif + #if !defined(FSMC_Bank2_R_BASE) + #define FSMC_Bank2_R_BASE (FSMC_R_BASE + 0x0060) + #endif + #if !defined(FSMC_Bank3_R_BASE) + #define FSMC_Bank3_R_BASE (FSMC_R_BASE + 0x0080) + #endif + #if !defined(FSMC_Bank4_R_BASE) + #define FSMC_Bank4_R_BASE (FSMC_R_BASE + 0x00A0) + #endif +#endif + +/* + * Base bank mappings + */ +#define FSMC_Bank1_MAP_BASE ((uint32_t) 0x60000000) +#define FSMC_Bank2_MAP_BASE ((uint32_t) 0x70000000) +#define FSMC_Bank3_MAP_BASE ((uint32_t) 0x80000000) +#define FSMC_Bank4_MAP_BASE ((uint32_t) 0x90000000) +#if (defined(STM32F427xx) || defined(STM32F437xx) || \ + defined(STM32F429xx) || defined(STM32F439xx)) + #define FSMC_Bank5_MAP_BASE ((uint32_t) 0xC0000000) + #define FSMC_Bank6_MAP_BASE ((uint32_t) 0xD0000000) +#endif + +/* + * Subbunks of bank1 + */ +#define FSMC_SUBBUNK_OFFSET (1024 * 1024 * 64) +#define FSMC_Bank1_1_MAP (FSMC_Bank1_MAP_BASE) +#define FSMC_Bank1_2_MAP (FSMC_Bank1_1_MAP + FSMC_SUBBUNK_OFFSET) +#define FSMC_Bank1_3_MAP (FSMC_Bank1_2_MAP + FSMC_SUBBUNK_OFFSET) +#define FSMC_Bank1_4_MAP (FSMC_Bank1_3_MAP + FSMC_SUBBUNK_OFFSET) + +/* + * Bank 2 (NAND) + */ +#define FSMC_Bank2_MAP_COMMON (FSMC_Bank2_MAP_BASE + 0) +#define FSMC_Bank2_MAP_ATTR (FSMC_Bank2_MAP_BASE + 0x8000000) + +#define FSMC_Bank2_MAP_COMMON_DATA (FSMC_Bank2_MAP_COMMON + 0) +#define FSMC_Bank2_MAP_COMMON_CMD (FSMC_Bank2_MAP_COMMON + 0x10000) +#define FSMC_Bank2_MAP_COMMON_ADDR (FSMC_Bank2_MAP_COMMON + 0x20000) + +#define FSMC_Bank2_MAP_ATTR_DATA (FSMC_Bank2_MAP_ATTR + 0) +#define FSMC_Bank2_MAP_ATTR_CMD (FSMC_Bank2_MAP_ATTR + 0x10000) +#define FSMC_Bank2_MAP_ATTR_ADDR (FSMC_Bank2_MAP_ATTR + 0x20000) + +/* + * Bank 3 (NAND) + */ +#define FSMC_Bank3_MAP_COMMON (FSMC_Bank3_MAP_BASE + 0) +#define FSMC_Bank3_MAP_ATTR (FSMC_Bank3_MAP_BASE + 0x8000000) + +#define FSMC_Bank3_MAP_COMMON_DATA (FSMC_Bank3_MAP_COMMON + 0) +#define FSMC_Bank3_MAP_COMMON_CMD (FSMC_Bank3_MAP_COMMON + 0x10000) +#define FSMC_Bank3_MAP_COMMON_ADDR (FSMC_Bank3_MAP_COMMON + 0x20000) + +#define FSMC_Bank3_MAP_ATTR_DATA (FSMC_Bank3_MAP_ATTR + 0) +#define FSMC_Bank3_MAP_ATTR_CMD (FSMC_Bank3_MAP_ATTR + 0x10000) +#define FSMC_Bank3_MAP_ATTR_ADDR (FSMC_Bank3_MAP_ATTR + 0x20000) + +/* + * Bank 4 (PC card) + */ +#define FSMC_Bank4_MAP_COMMON (FSMC_Bank4_MAP_BASE + 0) +#define FSMC_Bank4_MAP_ATTR (FSMC_Bank4_MAP_BASE + 0x8000000) +#define FSMC_Bank4_MAP_IO (FSMC_Bank4_MAP_BASE + 0xC000000) + +/* + * More convenient typedefs than CMSIS has + */ +typedef struct { + __IO uint32_t PCR; /**< NAND Flash control */ + __IO uint32_t SR; /**< NAND Flash FIFO status and interrupt */ + __IO uint32_t PMEM; /**< NAND Flash Common memory space timing */ + __IO uint32_t PATT; /**< NAND Flash Attribute memory space timing */ + uint32_t RESERVED0; /**< Reserved, 0x70 */ + __IO uint32_t ECCR; /**< NAND Flash ECC result registers */ +} FSMC_NAND_TypeDef; + +typedef struct { + __IO uint32_t PCR; /**< PC Card control */ + __IO uint32_t SR; /**< PC Card FIFO status and interrupt */ + __IO uint32_t PMEM; /**< PC Card Common memory space timing */ + __IO uint32_t PATT; /**< PC Card Attribute memory space timing */ + __IO uint32_t PIO; /**< PC Card I/O space timing */ +} FSMC_PCCard_TypeDef; + +typedef struct { + __IO uint32_t BCR; /**< SRAM/NOR chip-select control registers */ + __IO uint32_t BTR; /**< SRAM/NOR chip-select timing registers */ + uint32_t RESERVED[63]; /**< Reserved */ + __IO uint32_t BWTR; /**< SRAM/NOR write timing registers */ +} FSMC_SRAM_NOR_TypeDef; + +#if (defined(STM32F427xx) || defined(STM32F437xx) || \ + defined(STM32F429xx) || defined(STM32F439xx)) + +typedef struct { + __IO uint32_t SDCR1; /**< SDRAM control register (bank 1) */ + __IO uint32_t SDCR2; /**< SDRAM control register (bank 2) */ + __IO uint32_t SDTR1; /**< SDRAM timing register (bank 1) */ + __IO uint32_t SDTR2; /**< SDRAM timing register (bank 2) */ + __IO uint32_t SDCMR; /**< SDRAM comand mode register */ + __IO uint32_t SDRTR; /**< SDRAM refresh timer register */ + __IO uint32_t SDSR; /**< SDRAM status register */ +} FSMC_SDRAM_TypeDef; + +#endif + +/** + * @brief PCR register + */ +#define FSMC_PCR_PWAITEN ((uint32_t)0x00000002) +#define FSMC_PCR_PBKEN ((uint32_t)0x00000004) +#define FSMC_PCR_PTYP ((uint32_t)0x00000008) +#define FSMC_PCR_ECCEN ((uint32_t)0x00000040) +#define FSMC_PCR_PTYP_PCCARD 0 +#define FSMC_PCR_PTYP_NAND FSMC_PCR_PTYP + +/** + * @brief SR register + */ +#define FSMC_SR_IRS ((uint8_t)0x01) +#define FSMC_SR_ILS ((uint8_t)0x02) +#define FSMC_SR_IFS ((uint8_t)0x04) +#define FSMC_SR_IREN ((uint8_t)0x08) +#define FSMC_SR_ILEN ((uint8_t)0x10) +#define FSMC_SR_IFEN ((uint8_t)0x20) +#define FSMC_SR_FEMPT ((uint8_t)0x40) +#define FSMC_SR_ISR_MASK (FSMC_SR_IRS | FSMC_SR_ILS | FSMC_SR_IFS) + +/** + * @brief BCR register + */ +#define FSMC_BCR_MBKEN ((uint32_t)1 << 0) +#define FSMC_BCR_MUXEN ((uint32_t)1 << 1) +#define FSMC_BCR_MTYP_SRAM ((uint32_t)0 << 2) +#define FSMC_BCR_MTYP_PSRAM ((uint32_t)1 << 2) +#define FSMC_BCR_MTYP_NOR_NAND ((uint32_t)2 << 2) +#define FSMC_BCR_MTYP_RESERVED ((uint32_t)3 << 2) +#define FSMC_BCR_MWID_8 ((uint32_t)0 << 4) +#define FSMC_BCR_MWID_16 ((uint32_t)1 << 4) +#if (defined(STM32F427xx) || defined(STM32F437xx) || \ + defined(STM32F429xx) || defined(STM32F439xx)) +#define FSMC_BCR_MWID_32 ((uint32_t)2 << 4) +#else +#define FSMC_BCR_MWID_RESERVED1 ((uint32_t)2 << 4) +#endif +#define FSMC_BCR_MWID_RESERVED2 ((uint32_t)3 << 4) +#define FSMC_BCR_FACCEN ((uint32_t)1 << 6) +#define FSMC_BCR_BURSTEN ((uint32_t)1 << 8) +#define FSMC_BCR_WAITPOL ((uint32_t)1 << 9) +#define FSMC_BCR_WRAPMOD ((uint32_t)1 << 10) +#define FSMC_BCR_WAITCFG ((uint32_t)1 << 11) +#define FSMC_BCR_WREN ((uint32_t)1 << 12) +#define FSMC_BCR_WAITEN ((uint32_t)1 << 13) +#define FSMC_BCR_EXTMOD ((uint32_t)1 << 14) +#define FSMC_BCR_ASYNCWAIT ((uint32_t)1 << 15) +#define FSMC_BCR_CBURSTRW ((uint32_t)1 << 19) + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief FSMC driver enable switch. + * @details If set to @p TRUE the support for FSMC is included. + */ +#if !defined(STM32_FSMC_USE_FSMC1) || defined(__DOXYGEN__) +#define STM32_FSMC_USE_FSMC1 FALSE +#endif + +/** + * @brief Internal FSMC interrupt enable switch + * @details MCUs in 100-pin package has no dedicated interrupt pin for FSMC. + * You have to use EXTI module instead to workaround this issue. + */ +#if !defined(STM32_NAND_USE_EXT_INT) || defined(__DOXYGEN__) +#define STM32_NAND_USE_EXT_INT FALSE +#endif + +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ +#if !STM32_FSMC_USE_FSMC1 +#error "FSMC driver activated but no FSMC peripheral assigned" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of a structure representing an FSMC driver. + */ +typedef struct FSMCDriver FSMCDriver; + +/** + * @brief Driver state machine possible states. + */ +typedef enum { + FSMC_UNINIT = 0, /**< Not initialized. */ + FSMC_STOP = 1, /**< Stopped. */ + FSMC_READY = 2, /**< Ready. */ +} fsmcstate_t; + +/** + * @brief Structure representing an FSMC driver. + */ +struct FSMCDriver { + /** + * @brief Driver state. + */ + fsmcstate_t state; + /* End of the mandatory fields.*/ + +#if STM32_SRAM_USE_FSMC_SRAM1 + FSMC_SRAM_NOR_TypeDef *sram1; +#endif +#if STM32_SRAM_USE_FSMC_SRAM2 + FSMC_SRAM_NOR_TypeDef *sram2; +#endif +#if STM32_SRAM_USE_FSMC_SRAM3 + FSMC_SRAM_NOR_TypeDef *sram3; +#endif +#if STM32_SRAM_USE_FSMC_SRAM4 + FSMC_SRAM_NOR_TypeDef *sram4; +#endif +#if STM32_NAND_USE_FSMC_NAND1 + FSMC_NAND_TypeDef *nand1; +#endif +#if STM32_NAND_USE_FSMC_NAND2 + FSMC_NAND_TypeDef *nand2; +#endif +#if (defined(STM32F427xx) || defined(STM32F437xx) || \ + defined(STM32F429xx) || defined(STM32F439xx)) + #if STM32_USE_FSMC_SDRAM + FSMC_SDRAM_TypeDef *sdram; + #endif +#endif +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_FSMC_USE_FSMC1 && !defined(__DOXYGEN__) +extern FSMCDriver FSMCD1; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void fsmc_init(void); + void fsmc_start(FSMCDriver *fsmcp); + void fsmc_stop(FSMCDriver *fsmcp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_FSMC */ + +#endif /* _FSMC_H_ */ + +/** @} */ diff --git a/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sdram.c b/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sdram.c new file mode 100644 index 0000000..95f47d5 --- /dev/null +++ b/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sdram.c @@ -0,0 +1,211 @@ +/* + ChibiOS/HAL - Copyright (C) 2014 Uladzimir Pylinsky aka barthess + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +/* + SDRAM routines added by Nick Klimov aka progfin. + */ + +/** + * @file fsmc_sdram.c + * @brief SDRAM Driver subsystem low level driver source. + * + * @addtogroup SDRAM + * @{ + */ + +#include "hal.h" + +#if (defined(STM32F427xx) || defined(STM32F437xx) || \ + defined(STM32F429xx) || defined(STM32F439xx)) + +#if (STM32_USE_FSMC_SDRAM == TRUE) || defined(__DOXYGEN__) + +#include "hal_fsmc_sdram.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/** + * FMC_Command_Mode + */ +#define FMCCM_NORMAL ((uint32_t)0x00000000) +#define FMCCM_CLK_ENABLED ((uint32_t)0x00000001) +#define FMCCM_PALL ((uint32_t)0x00000002) +#define FMCCM_AUTO_REFRESH ((uint32_t)0x00000003) +#define FMCCM_LOAD_MODE ((uint32_t)0x00000004) +#define FMCCM_SELFREFRESH ((uint32_t)0x00000005) +#define FMCCM_POWER_DOWN ((uint32_t)0x00000006) + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ +/** + * @brief SDRAM driver identifier. + */ +SDRAMDriver SDRAMD; + +/*===========================================================================*/ +/* Driver local types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Wait until the SDRAM controller is ready. + * + * @notapi + */ +static void _sdram_wait_ready(void) { + /* Wait until the SDRAM controller is ready */ + while (SDRAMD.sdram->SDSR & FMC_SDSR_BUSY); +} + +/** + * @brief Executes the SDRAM memory initialization sequence. + * + * @param[in] cfgp pointer to the @p SDRAMConfig object + * + * @notapi + */ +static void _sdram_init_sequence(const SDRAMConfig *cfgp) { + + uint32_t command_target = 0; + +#if STM32_SDRAM_USE_FSMC_SDRAM1 + command_target |= FMC_SDCMR_CTB1; +#endif +#if STM32_SDRAM_USE_FSMC_SDRAM2 + command_target |= FMC_SDCMR_CTB2; +#endif + + /* Step 3: Configure a clock configuration enable command.*/ + _sdram_wait_ready(); + SDRAMD.sdram->SDCMR = FMCCM_CLK_ENABLED | command_target; + + /* Step 4: Insert delay (tipically 100uS).*/ + osalThreadSleepMilliseconds(1); + + /* Step 5: Configure a PALL (precharge all) command.*/ + _sdram_wait_ready(); + SDRAMD.sdram->SDCMR = FMCCM_PALL | command_target; + + /* Step 6.1: Configure a Auto-Refresh command: send the first command.*/ + _sdram_wait_ready(); + SDRAMD.sdram->SDCMR = FMCCM_AUTO_REFRESH | command_target | + (cfgp->sdcmr & FMC_SDCMR_NRFS); + + /* Step 6.2: Send the second command.*/ + _sdram_wait_ready(); + SDRAMD.sdram->SDCMR = FMCCM_AUTO_REFRESH | command_target | + (cfgp->sdcmr & FMC_SDCMR_NRFS); + + /* Step 7: Program the external memory mode register.*/ + _sdram_wait_ready(); + SDRAMD.sdram->SDCMR = FMCCM_LOAD_MODE | command_target | + (cfgp->sdcmr & FMC_SDCMR_MRD); + + /* Step 8: Set clock.*/ + _sdram_wait_ready(); + SDRAMD.sdram->SDRTR = cfgp->sdrtr & FMC_SDRTR_COUNT; + + _sdram_wait_ready(); +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level SDRAM driver initialization. + */ +void fsmcSdramInit(void) { + + fsmc_init(); + + SDRAMD.sdram = FSMCD1.sdram; + SDRAMD.state = SDRAM_STOP; +} + +/** + * @brief Configures and activates the SDRAM peripheral. + * + * @param[in] sdramp pointer to the @p SDRAMDriver object + * @param[in] cfgp pointer to the @p SDRAMConfig object + */ +void fsmcSdramStart(SDRAMDriver *sdramp, const SDRAMConfig *cfgp) { + + if (FSMCD1.state == FSMC_STOP) + fsmc_start(&FSMCD1); + + osalDbgAssert((sdramp->state == SDRAM_STOP) || (sdramp->state == SDRAM_READY), + "SDRAM. Invalid state."); + + if (sdramp->state == SDRAM_STOP) { + + /* Even if you need only bank2 you must properly set up SDCR and SDTR + regitsters for bank1 too. Both banks will be tuned equally assuming + connected memory ICs are equal.*/ + sdramp->sdram->SDCR1 = cfgp->sdcr; + sdramp->sdram->SDTR1 = cfgp->sdtr; + sdramp->sdram->SDCR2 = cfgp->sdcr; + sdramp->sdram->SDTR2 = cfgp->sdtr; + + _sdram_init_sequence(cfgp); + + sdramp->state = SDRAM_READY; + } +} + +/** + * @brief Deactivates the SDRAM peripheral. + * + * @param[in] sdramp pointer to the @p SDRAMDriver object + * + * @notapi + */ +void fsmcSdramStop(SDRAMDriver *sdramp) { + + uint32_t command_target = 0; + +#if STM32_SDRAM_USE_FSMC_SDRAM1 + command_target |= FMC_SDCMR_CTB1; +#endif +#if STM32_SDRAM_USE_FSMC_SDRAM2 + command_target |= FMC_SDCMR_CTB2; +#endif + + if (sdramp->state == SDRAM_READY) { + SDRAMD.sdram->SDCMR = FMCCM_POWER_DOWN | command_target; + sdramp->state = SDRAM_STOP; + } +} + +#endif /* STM32_USE_FSMC_SDRAM */ + +#endif /* STM32F427xx / STM32F429xx / STM32F437xx / STM32F439xx */ + +/** @} */ + diff --git a/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sdram.h b/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sdram.h new file mode 100644 index 0000000..cef6772 --- /dev/null +++ b/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sdram.h @@ -0,0 +1,171 @@ +/* + ChibiOS/HAL - Copyright (C) 2014 Uladzimir Pylinsky aka barthess + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +/* + SDRAM routines added by Nick Klimov aka progfin. + */ + +/** + * @file fsmc_sdram.h + * @brief SDRAM Driver subsystem low level driver header. + * + * @addtogroup SDRAM + * @{ + */ + +#ifndef _FMC_SDRAM_H_ +#define _FMC_SDRAM_H_ + +#if (defined(STM32F427xx) || defined(STM32F437xx) || \ + defined(STM32F429xx) || defined(STM32F439xx)) + +#include "hal_fsmc.h" + +#if (STM32_USE_FSMC_SDRAM == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ +/** + * @name Configuration options + * @{ + */ + +/** + * @brief SDRAM driver enable switch. + * @details If set to @p TRUE the support for SDRAM1 is included. + */ +#if !defined(STM32_SDRAM_USE_FSMC_SDRAM1) || defined(__DOXYGEN__) +#define STM32_SDRAM_USE_FSMC_SDRAM1 FALSE +#else +#define STM32_SDRAM1_MAP_BASE FSMC_Bank5_MAP_BASE +#endif + +/** + * @brief SDRAM driver enable switch. + * @details If set to @p TRUE the support for SDRAM2 is included. + */ +#if !defined(STM32_SDRAM_USE_FSMC_SDRAM2) || defined(__DOXYGEN__) +#define STM32_SDRAM_USE_FSMC_SDRAM2 FALSE +#else +#define STM32_SDRAM2_MAP_BASE FSMC_Bank6_MAP_BASE +#endif + +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !STM32_SDRAM_USE_FSMC_SDRAM1 && !STM32_SDRAM_USE_FSMC_SDRAM2 +#error "SDRAM driver activated but no SDRAM peripheral assigned" +#endif + +#if (STM32_SDRAM_USE_FSMC_SDRAM1 || STM32_SDRAM_USE_FSMC_SDRAM2) && !STM32_HAS_FSMC +#error "FMC not present in the selected device" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ +/** + * @brief Driver state machine possible states. + */ +typedef enum { + SDRAM_UNINIT = 0, /**< Not initialized. */ + SDRAM_STOP = 1, /**< Stopped. */ + SDRAM_READY = 2, /**< Ready. */ +} sdramstate_t; + +/** + * @brief Type of a structure representing an SDRAM driver. + */ +typedef struct SDRAMDriver SDRAMDriver; + +/** + * @brief Driver configuration structure. + * @note It could be empty on some architectures. + */ +typedef struct { + /** + * @brief SDRAM control register. + * @note Its value will be used for both banks. + */ + uint32_t sdcr; + + /** + * @brief SDRAM timing register. + * @note Its value will be used for both banks. + */ + uint32_t sdtr; + + /** + * @brief SDRAM command mode register. + * @note Only its MRD and NRFS bits will be used. + */ + uint32_t sdcmr; + + /** + * @brief SDRAM refresh timer register. + * @note Only its COUNT bits will be used. + */ + uint32_t sdrtr; +} SDRAMConfig; + +/** + * @brief Structure representing an SDRAM driver. + */ +struct SDRAMDriver { + /** + * @brief Driver state. + */ + sdramstate_t state; + /** + * @brief Pointer to the FMC SDRAM registers block. + */ + FSMC_SDRAM_TypeDef *sdram; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +extern SDRAMDriver SDRAMD; + +#ifdef __cplusplus +extern "C" { +#endif + void fsmcSdramInit(void); + void fsmcSdramStart(SDRAMDriver *sdramp, const SDRAMConfig *cfgp); + void fsmcSdramStop(SDRAMDriver *sdramp); +#ifdef __cplusplus +} +#endif + +#endif /* STM32_USE_FSMC_SDRAM */ + +#endif /* STM32F427xx / STM32F429xx / STM32F437xx / STM32F439xx */ + +#endif /* _FMC_SDRAM_H_ */ + +/** @} */ diff --git a/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sram.c b/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sram.c new file mode 100644 index 0000000..6f710d4 --- /dev/null +++ b/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sram.c @@ -0,0 +1,156 @@ +/* + ChibiOS/HAL - Copyright (C) 2014 Uladzimir Pylinsky aka barthess + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file fsmc_sram.c + * @brief SRAM Driver subsystem low level driver source. + * + * @addtogroup SRAM + * @{ + */ +#include "hal.h" +#include "hal_fsmc_sram.h" + +#if (STM32_USE_FSMC_SRAM == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ +/** + * @brief SRAM1 driver identifier. + */ +#if STM32_SRAM_USE_FSMC_SRAM1 || defined(__DOXYGEN__) +SRAMDriver SRAMD1; +#endif + +/** + * @brief SRAM2 driver identifier. + */ +#if STM32_SRAM_USE_FSMC_SRAM2 || defined(__DOXYGEN__) +SRAMDriver SRAMD2; +#endif + +/** + * @brief SRAM3 driver identifier. + */ +#if STM32_SRAM_USE_FSMC_SRAM3 || defined(__DOXYGEN__) +SRAMDriver SRAMD3; +#endif + +/** + * @brief SRAM4 driver identifier. + */ +#if STM32_SRAM_USE_FSMC_SRAM4 || defined(__DOXYGEN__) +SRAMDriver SRAMD4; +#endif + +/*===========================================================================*/ +/* Driver local types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level SRAM driver initialization. + * + * @notapi + */ +void fsmcSramInit(void) { + + fsmc_init(); + +#if STM32_SRAM_USE_FSMC_SRAM1 + SRAMD1.sram = FSMCD1.sram1; + SRAMD1.state = SRAM_STOP; +#endif /* STM32_SRAM_USE_FSMC_SRAM1 */ + +#if STM32_SRAM_USE_FSMC_SRAM2 + SRAMD2.sram = FSMCD1.sram2; + SRAMD2.state = SRAM_STOP; +#endif /* STM32_SRAM_USE_FSMC_SRAM2 */ + +#if STM32_SRAM_USE_FSMC_SRAM3 + SRAMD3.sram = FSMCD1.sram3; + SRAMD3.state = SRAM_STOP; +#endif /* STM32_SRAM_USE_FSMC_SRAM3 */ + +#if STM32_SRAM_USE_FSMC_SRAM4 + SRAMD4.sram = FSMCD1.sram4; + SRAMD4.state = SRAM_STOP; +#endif /* STM32_SRAM_USE_FSMC_SRAM4 */ +} + +/** + * @brief Configures and activates the SRAM peripheral. + * + * @param[in] sramp pointer to the @p SRAMDriver object + * @param[in] cfgp pointer to the @p SRAMConfig object + * + * @notapi + */ +void fsmcSramStart(SRAMDriver *sramp, const SRAMConfig *cfgp) { + + if (FSMCD1.state == FSMC_STOP) + fsmc_start(&FSMCD1); + + osalDbgAssert((sramp->state == SRAM_STOP) || (sramp->state == SRAM_READY), + "invalid state"); + + if (sramp->state == SRAM_STOP) { + sramp->sram->BCR = cfgp->bcr | FSMC_BCR_MBKEN; + sramp->sram->BTR = cfgp->btr; + sramp->sram->BWTR = cfgp->bwtr; + sramp->state = SRAM_READY; + } +} + +/** + * @brief Deactivates the SRAM peripheral. + * + * @param[in] sramp pointer to the @p SRAMDriver object + * + * @notapi + */ +void fsmcSramStop(SRAMDriver *sramp) { + + if (sramp->state == SRAM_READY) { + sramp->sram->BCR &= ~FSMC_BCR_MBKEN; + sramp->state = SRAM_STOP; + } +} + +#endif /* STM32_USE_FSMC_SRAM */ + +/** @} */ + diff --git a/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sram.h b/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sram.h new file mode 100644 index 0000000..529bdc7 --- /dev/null +++ b/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sram.h @@ -0,0 +1,172 @@ +/* + ChibiOS/HAL - Copyright (C) 2014 Uladzimir Pylinsky aka barthess + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file fsmc_sram.h + * @brief SRAM Driver subsystem low level driver header. + * + * @addtogroup SRAM + * @{ + */ + +#ifndef _FSMC_SRAM_H_ +#define _FSMC_SRAM_H_ + +#include "hal_fsmc.h" + +#if (STM32_USE_FSMC_SRAM == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ +/** + * @name Configuration options + * @{ + */ + +/** + * @brief SRAM driver enable switch. + * @details If set to @p TRUE the support for SRAM1 is included. + */ +#if !defined(STM32_SRAM_USE_FSMC_SRAM1) || defined(__DOXYGEN__) +#define STM32_SRAM_USE_FSMC_SRAM1 FALSE +#endif + +/** + * @brief SRAM driver enable switch. + * @details If set to @p TRUE the support for SRAM2 is included. + */ +#if !defined(STM32_SRAM_USE_FSMC_SRAM2) || defined(__DOXYGEN__) +#define STM32_SRAM_USE_FSMC_SRAM2 FALSE +#endif + +/** + * @brief SRAM driver enable switch. + * @details If set to @p TRUE the support for SRAM3 is included. + */ +#if !defined(STM32_SRAM_USE_FSMC_SRAM3) || defined(__DOXYGEN__) +#define STM32_SRAM_USE_FSMC_SRAM3 FALSE +#endif + +/** + * @brief SRAM driver enable switch. + * @details If set to @p TRUE the support for SRAM4 is included. + */ +#if !defined(STM32_SRAM_USE_FSMC_SRAM4) || defined(__DOXYGEN__) +#define STM32_SRAM_USE_FSMC_SRAM4 FALSE +#endif + +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !STM32_SRAM_USE_FSMC_SRAM1 && !STM32_SRAM_USE_FSMC_SRAM2 && \ + !STM32_SRAM_USE_FSMC_SRAM3 && !STM32_SRAM_USE_FSMC_SRAM4 +#error "SRAM driver activated but no SRAM peripheral assigned" +#endif + +#if (STM32_SRAM_USE_FSMC_SRAM1 || STM32_SRAM_USE_FSMC_SRAM2 || \ + STM32_SRAM_USE_FSMC_SRAM3 || STM32_SRAM_USE_FSMC_SRAM4) && !STM32_HAS_FSMC +#error "FSMC not present in the selected device" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ +/** + * @brief Driver state machine possible states. + */ +typedef enum { + SRAM_UNINIT = 0, /**< Not initialized. */ + SRAM_STOP = 1, /**< Stopped. */ + SRAM_READY = 2, /**< Ready. */ +} sramstate_t; + +/** + * @brief Type of a structure representing an NAND driver. + */ +typedef struct SRAMDriver SRAMDriver; + +/** + * @brief Driver configuration structure. + * @note It could be empty on some architectures. + * @note Some bits in BCR register will be forced by driver. + */ +typedef struct { + uint32_t bcr; + uint32_t btr; + uint32_t bwtr; +} SRAMConfig; + +/** + * @brief Structure representing an NAND driver. + */ +struct SRAMDriver { + /** + * @brief Driver state. + */ + sramstate_t state; + /** + * @brief Pointer to the FSMC SRAM registers block. + */ + FSMC_SRAM_NOR_TypeDef *sram; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_SRAM_USE_FSMC_SRAM1 && !defined(__DOXYGEN__) +extern SRAMDriver SRAMD1; +#endif + +#if STM32_SRAM_USE_FSMC_SRAM2 && !defined(__DOXYGEN__) +extern SRAMDriver SRAMD2; +#endif + +#if STM32_SRAM_USE_FSMC_SRAM3 && !defined(__DOXYGEN__) +extern SRAMDriver SRAMD3; +#endif + +#if STM32_SRAM_USE_FSMC_SRAM4 && !defined(__DOXYGEN__) +extern SRAMDriver SRAMD4; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void fsmcSramInit(void); + void fsmcSramStart(SRAMDriver *sramp, const SRAMConfig *cfgp); + void fsmcSramStop(SRAMDriver *sramp); +#ifdef __cplusplus +} +#endif + +#endif /* STM32_USE_FSMC_SRAM */ + +#endif /* _FSMC_SRAM_H_ */ + +/** @} */ diff --git a/os/hal/ports/STM32/LLD/FSMCv1/hal_nand_lld.c b/os/hal/ports/STM32/LLD/FSMCv1/hal_nand_lld.c new file mode 100644 index 0000000..b37c026 --- /dev/null +++ b/os/hal/ports/STM32/LLD/FSMCv1/hal_nand_lld.c @@ -0,0 +1,515 @@ +/* + ChibiOS/HAL - Copyright (C) 2014 Uladzimir Pylinsky aka barthess + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file nand_lld.c + * @brief NAND Driver subsystem low level driver source. + * + * @addtogroup NAND + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_NAND == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ +#define NAND_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_NAND_DMA_STREAM, \ + STM32_FSMC_DMA_CHN) + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief NAND1 driver identifier. + */ +#if STM32_NAND_USE_FSMC_NAND1 || defined(__DOXYGEN__) +NANDDriver NANDD1; +#endif + +/** + * @brief NAND2 driver identifier. + */ +#if STM32_NAND_USE_FSMC_NAND2 || defined(__DOXYGEN__) +NANDDriver NANDD2; +#endif + +/*===========================================================================*/ +/* Driver local types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ +/** + * @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 Put calling thread in suspend and switch driver state + * + * @param[in] nandp pointer to the @p NANDDriver object + */ +static void nand_lld_suspend_thread(NANDDriver *nandp) { + + osalThreadSuspendS(&nandp->thread); +} + +/** + * @brief Caclulate ECCPS register value + * + * @param[in] nandp pointer to the @p NANDDriver object + */ +static uint32_t calc_eccps(NANDDriver *nandp) { + + uint32_t i = 0; + uint32_t eccps = nandp->config->page_data_size; + + eccps = eccps >> 9; + while (eccps > 0){ + i++; + eccps >>= 1; + } + + return i << 17; +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/** + * @brief Enable interrupts from NAND + * + * @param[in] nandp pointer to the @p NANDDriver object + * + * @notapi + */ +static void nand_ready_isr_enable(NANDDriver *nandp) { +#if STM32_NAND_USE_EXT_INT + nandp->config->ext_nand_isr_enable(); +#else + nandp->nand->SR &= ~(FSMC_SR_IRS | FSMC_SR_ILS | FSMC_SR_IFS | + FSMC_SR_ILEN | FSMC_SR_IFEN); + nandp->nand->SR |= FSMC_SR_IREN; +#endif +} + +/** + * @brief Disable interrupts from NAND + * + * @param[in] nandp pointer to the @p NANDDriver object + * + * @notapi + */ +static void nand_ready_isr_disable(NANDDriver *nandp) { +#if STM32_NAND_USE_EXT_INT + nandp->config->ext_nand_isr_disable(); +#else + nandp->nand->SR &= ~FSMC_SR_IREN; +#endif +} + +/** + * @brief Ready interrupt handler + * + * @param[in] nandp pointer to the @p NANDDriver object + * + * @notapi + */ +static void nand_isr_handler (NANDDriver *nandp) { + + osalSysLockFromISR(); + +#if !STM32_NAND_USE_EXT_INT + osalDbgCheck(nandp->nand->SR & FSMC_SR_IRS); /* spurious interrupt happened */ + nandp->nand->SR &= ~FSMC_SR_IRS; +#endif + + switch (nandp->state){ + case NAND_READ: + nandp->state = NAND_DMA_RX; + dmaStartMemCopy(nandp->dma, nandp->dmamode, + nandp->map_data, nandp->rxdata, nandp->datalen); + /* thread will be waked up from DMA ISR */ + break; + + case NAND_ERASE: + /* NAND reports about erase finish */ + nandp->state = NAND_READY; + wakeup_isr(nandp); + break; + + case NAND_PROGRAM: + /* NAND reports about page programming finish */ + nandp->state = NAND_READY; + wakeup_isr(nandp); + break; + + default: + osalSysHalt("Unhandled case"); + break; + } + osalSysUnlockFromISR(); +} + +/** + * @brief DMA RX end IRQ handler. + * + * @param[in] nandp pointer to the @p NANDDriver object + * @param[in] flags pre-shifted content of the ISR register + * + * @notapi + */ +static void nand_lld_serve_transfer_end_irq(NANDDriver *nandp, uint32_t flags) { + /* DMA errors handling.*/ +#if defined(STM32_NAND_DMA_ERROR_HOOK) + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { + STM32_NAND_DMA_ERROR_HOOK(nandp); + } +#else + (void)flags; +#endif + + osalSysLockFromISR(); + + dmaStreamDisable(nandp->dma); + + switch (nandp->state){ + case NAND_DMA_TX: + nandp->state = NAND_PROGRAM; + nandp->map_cmd[0] = NAND_CMD_PAGEPROG; + /* thread will be woken from ready_isr() */ + break; + + case NAND_DMA_RX: + nandp->state = NAND_READY; + nandp->rxdata = NULL; + nandp->datalen = 0; + wakeup_isr(nandp); + break; + + default: + osalSysHalt("Unhandled case"); + break; + } + + osalSysUnlockFromISR(); +} + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level NAND driver initialization. + * + * @notapi + */ +void nand_lld_init(void) { + + fsmc_init(); + +#if STM32_NAND_USE_FSMC_NAND1 + /* Driver initialization.*/ + nandObjectInit(&NANDD1); + NANDD1.rxdata = NULL; + NANDD1.datalen = 0; + NANDD1.thread = NULL; + NANDD1.dma = STM32_DMA_STREAM(STM32_NAND_DMA_STREAM); + NANDD1.nand = FSMCD1.nand1; + NANDD1.map_data = (uint8_t*)FSMC_Bank2_MAP_COMMON_DATA; + NANDD1.map_cmd = (uint8_t*)FSMC_Bank2_MAP_COMMON_CMD; + NANDD1.map_addr = (uint8_t*)FSMC_Bank2_MAP_COMMON_ADDR; + NANDD1.bb_map = NULL; +#endif /* STM32_NAND_USE_FSMC_NAND1 */ + +#if STM32_NAND_USE_FSMC_NAND2 + /* Driver initialization.*/ + nandObjectInit(&NANDD2); + NANDD2.rxdata = NULL; + NANDD2.datalen = 0; + NANDD2.thread = NULL; + NANDD2.dma = STM32_DMA_STREAM(STM32_NAND_DMA_STREAM); + NANDD2.nand = FSMCD1.nand2; + NANDD2.map_data = (uint8_t*)FSMC_Bank3_MAP_COMMON_DATA; + NANDD2.map_cmd = (uint8_t*)FSMC_Bank3_MAP_COMMON_CMD; + NANDD2.map_addr = (uint8_t*)FSMC_Bank3_MAP_COMMON_ADDR; + NANDD2.bb_map = NULL; +#endif /* STM32_NAND_USE_FSMC_NAND2 */ +} + +/** + * @brief Configures and activates the NAND peripheral. + * + * @param[in] nandp pointer to the @p NANDDriver object + * + * @notapi + */ +void nand_lld_start(NANDDriver *nandp) { + + bool b; + + if (FSMCD1.state == FSMC_STOP) + fsmc_start(&FSMCD1); + + if (nandp->state == NAND_STOP) { + b = dmaStreamAllocate(nandp->dma, + STM32_EMC_FSMC1_IRQ_PRIORITY, + (stm32_dmaisr_t)nand_lld_serve_transfer_end_irq, + (void *)nandp); + osalDbgAssert(!b, "stream already allocated"); + nandp->dmamode = STM32_DMA_CR_CHSEL(NAND_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_NAND_NAND1_DMA_PRIORITY) | + STM32_DMA_CR_PSIZE_BYTE | + STM32_DMA_CR_MSIZE_BYTE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE | + STM32_DMA_CR_TCIE; + /* dmaStreamSetFIFO(nandp->dma, + STM32_DMA_FCR_DMDIS | NAND_STM32_DMA_FCR_FTH_LVL); */ + nandp->nand->PCR = calc_eccps(nandp) | FSMC_PCR_PTYP | FSMC_PCR_PBKEN; + nandp->nand->PMEM = nandp->config->pmem; + nandp->nand->PATT = nandp->config->pmem; + nandp->isr_handler = nand_isr_handler; + nand_ready_isr_enable(nandp); + } +} + +/** + * @brief Deactivates the NAND peripheral. + * + * @param[in] nandp pointer to the @p NANDDriver object + * + * @notapi + */ +void nand_lld_stop(NANDDriver *nandp) { + + if (nandp->state == NAND_READY) { + dmaStreamRelease(nandp->dma); + nandp->nand->PCR &= ~FSMC_PCR_PBKEN; + nand_ready_isr_disable(nandp); + nandp->isr_handler = NULL; + } +} + +/** + * @brief Read data from NAND. + * + * @param[in] nandp pointer to the @p NANDDriver object + * @param[out] data pointer to data buffer + * @param[in] datalen size of data buffer + * @param[in] addr pointer to address buffer + * @param[in] addrlen length of address + * @param[out] ecc pointer to store computed ECC. Ignored when NULL. + * + * @notapi + */ +void nand_lld_read_data(NANDDriver *nandp, uint8_t *data, size_t datalen, + uint8_t *addr, size_t addrlen, uint32_t *ecc){ + + nandp->state = NAND_READ; + nandp->rxdata = data; + nandp->datalen = datalen; + + nand_lld_write_cmd (nandp, NAND_CMD_READ0); + nand_lld_write_addr(nandp, addr, addrlen); + osalSysLock(); + nand_lld_write_cmd (nandp, NAND_CMD_READ0_CONFIRM); + + /* Here NAND asserts busy signal and starts transferring from memory + array to page buffer. After the end of transmission ready_isr functions + starts DMA transfer from page buffer to MCU's RAM.*/ + osalDbgAssert((nandp->nand->PCR & FSMC_PCR_ECCEN) == 0, + "State machine broken. ECCEN must be previously disabled."); + + if (NULL != ecc){ + nandp->nand->PCR |= FSMC_PCR_ECCEN; + } + + nand_lld_suspend_thread(nandp); + osalSysUnlock(); + + /* thread was woken up from DMA ISR */ + if (NULL != ecc){ + while (! (nandp->nand->SR & FSMC_SR_FEMPT)) + ; + *ecc = nandp->nand->ECCR; + nandp->nand->PCR &= ~FSMC_PCR_ECCEN; + } +} + +/** + * @brief Write data to NAND. + * + * @param[in] nandp pointer to the @p NANDDriver object + * @param[in] data buffer with data to be written + * @param[in] datalen size of data buffer + * @param[in] addr pointer to address buffer + * @param[in] addrlen length of address + * @param[out] ecc pointer to store computed ECC. Ignored when NULL. + * + * @return The operation status reported by NAND IC (0x70 command). + * + * @notapi + */ +uint8_t nand_lld_write_data(NANDDriver *nandp, const uint8_t *data, + size_t datalen, uint8_t *addr, size_t addrlen, uint32_t *ecc) { + + nandp->state = NAND_WRITE; + + nand_lld_write_cmd (nandp, NAND_CMD_WRITE); + osalSysLock(); + nand_lld_write_addr(nandp, addr, addrlen); + + /* Now start DMA transfer to NAND buffer and put thread in sleep state. + Tread will be woken up from ready ISR. */ + nandp->state = NAND_DMA_TX; + osalDbgAssert((nandp->nand->PCR & FSMC_PCR_ECCEN) == 0, + "State machine broken. ECCEN must be previously disabled."); + + if (NULL != ecc){ + nandp->nand->PCR |= FSMC_PCR_ECCEN; + } + + dmaStartMemCopy(nandp->dma, nandp->dmamode, data, nandp->map_data, datalen); + + nand_lld_suspend_thread(nandp); + osalSysUnlock(); + + if (NULL != ecc){ + while (! (nandp->nand->SR & FSMC_SR_FEMPT)) + ; + *ecc = nandp->nand->ECCR; + nandp->nand->PCR &= ~FSMC_PCR_ECCEN; + } + + return nand_lld_read_status(nandp); +} + +/** + * @brief Erase block. + * + * @param[in] nandp pointer to the @p NANDDriver object + * @param[in] addr pointer to address buffer + * @param[in] addrlen length of address + * + * @return The operation status reported by NAND IC (0x70 command). + * + * @notapi + */ +uint8_t nand_lld_erase(NANDDriver *nandp, uint8_t *addr, size_t addrlen) { + + nandp->state = NAND_ERASE; + + nand_lld_write_cmd (nandp, NAND_CMD_ERASE); + nand_lld_write_addr(nandp, addr, addrlen); + osalSysLock(); + nand_lld_write_cmd (nandp, NAND_CMD_ERASE_CONFIRM); + nand_lld_suspend_thread(nandp); + osalSysUnlock(); + + return nand_lld_read_status(nandp); +} + +/** + * @brief Read data from NAND using polling approach. + * + * @detatils Use this function to read data when no waiting expected. For + * Example read status word after 0x70 command + * + * @param[in] nandp pointer to the @p NANDDriver object + * @param[out] data pointer to output buffer + * @param[in] len length of data to be read + * + * @notapi + */ +void nand_lld_polled_read_data(NANDDriver *nandp, uint8_t *data, size_t len) { + size_t i = 0; + + for (i=0; imap_data[i]; +} + +/** + * @brief Send addres to NAND. + * + * @param[in] nandp pointer to the @p NANDDriver object + * @param[in] len length of address array + * @param[in] addr pointer to address array + * + * @notapi + */ +void nand_lld_write_addr(NANDDriver *nandp, const uint8_t *addr, size_t len) { + size_t i = 0; + + for (i=0; imap_addr[i] = addr[i]; +} + +/** + * @brief Send command to NAND. + * + * @param[in] nandp pointer to the @p NANDDriver object + * @param[in] cmd command value + * + * @notapi + */ +void nand_lld_write_cmd(NANDDriver *nandp, uint8_t cmd) { + nandp->map_cmd[0] = cmd; +} + +/** + * @brief Read status byte from NAND. + * + * @param[in] nandp pointer to the @p NANDDriver object + * + * @return Status byte. + * + * @notapi + */ +uint8_t nand_lld_read_status(NANDDriver *nandp) { + + uint8_t status[1] = {0x01}; /* presume worse */ + + nand_lld_write_cmd(nandp, NAND_CMD_STATUS); + nand_lld_polled_read_data(nandp, status, 1); + + return status[0]; +} + +#endif /* HAL_USE_NAND */ + +/** @} */ + diff --git a/os/hal/ports/STM32/LLD/FSMCv1/hal_nand_lld.h b/os/hal/ports/STM32/LLD/FSMCv1/hal_nand_lld.h new file mode 100644 index 0000000..8dca42f --- /dev/null +++ b/os/hal/ports/STM32/LLD/FSMCv1/hal_nand_lld.h @@ -0,0 +1,324 @@ +/* + ChibiOS/HAL - Copyright (C) 2014 Uladzimir Pylinsky aka barthess + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file nand_lld.h + * @brief NAND Driver subsystem low level driver header. + * + * @addtogroup NAND + * @{ + */ + +#ifndef _NAND_LLD_H_ +#define _NAND_LLD_H_ + +#include "hal_fsmc.h" +#include "bitmap.h" + +#if (HAL_USE_NAND == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ +#define NAND_MIN_PAGE_SIZE 256 +#define NAND_MAX_PAGE_SIZE 8192 + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief FSMC1 interrupt priority level setting. + */ +#if !defined(STM32_EMC_FSMC1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_EMC_FSMC1_IRQ_PRIORITY 10 +#endif + +/** + * @brief NAND driver enable switch. + * @details If set to @p TRUE the support for NAND1 is included. + */ +#if !defined(STM32_NAND_USE_NAND1) || defined(__DOXYGEN__) +#define STM32_NAND_USE_NAND1 FALSE +#endif + +/** + * @brief NAND driver enable switch. + * @details If set to @p TRUE the support for NAND2 is included. + */ +#if !defined(STM32_NAND_USE_NAND2) || defined(__DOXYGEN__) +#define STM32_NAND_USE_NAND2 FALSE +#endif + +/** + * @brief NAND DMA error hook. + * @note The default action for DMA errors is a system halt because DMA + * error can only happen because programming errors. + */ +#if !defined(STM32_NAND_DMA_ERROR_HOOK) || defined(__DOXYGEN__) +#define STM32_NAND_DMA_ERROR_HOOK(nandp) osalSysHalt("DMA failure") +#endif + +/** + * @brief NAND interrupt enable switch. + * @details If set to @p TRUE the support for internal FSMC interrupt included. + */ +#if !defined(STM32_NAND_USE_INT) || defined(__DOXYGEN__) +#define STM32_NAND_USE_INT FALSE +#endif + +/** +* @brief NAND1 DMA priority (0..3|lowest..highest). +*/ +#if !defined(STM32_NAND_NAND1_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_NAND_NAND1_DMA_PRIORITY 0 +#endif + +/** +* @brief NAND2 DMA priority (0..3|lowest..highest). +*/ +#if !defined(STM32_NAND_NAND2_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_NAND_NAND2_DMA_PRIORITY 0 +#endif + +/** + * @brief DMA stream used for NAND operations. + * @note This option is only available on platforms with enhanced DMA. + */ +#if !defined(STM32_NAND_DMA_STREAM) || defined(__DOXYGEN__) +#define STM32_NAND_DMA_STREAM STM32_DMA_STREAM_ID(2, 6) +#endif + +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !STM32_NAND_USE_FSMC_NAND1 && !STM32_NAND_USE_FSMC_NAND2 +#error "NAND driver activated but no NAND peripheral assigned" +#endif + +#if (STM32_NAND_USE_FSMC_NAND2 || STM32_NAND_USE_FSMC_NAND1) && !STM32_HAS_FSMC +#error "FSMC not present in the selected device" +#endif + +#if STM32_NAND_USE_EXT_INT && !HAL_USE_EXT +#error "External interrupt controller must be enabled to use this feature" +#endif + +#if !defined(STM32_DMA_REQUIRED) +#define STM32_DMA_REQUIRED +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief NAND driver condition flags type. + */ +typedef uint32_t nandflags_t; + +/** + * @brief Type of a structure representing an NAND driver. + */ +typedef struct NANDDriver NANDDriver; + +/** + * @brief Type of interrupt handler function + */ +typedef void (*nandisrhandler_t)(NANDDriver *nandp); + +#if STM32_NAND_USE_EXT_INT +/** + * @brief Type of function switching external interrupts on and off. + */ +typedef void (*nandisrswitch_t)(void); +#endif /* STM32_NAND_USE_EXT_INT */ + +/** + * @brief Driver configuration structure. + * @note It could be empty on some architectures. + */ +typedef struct { + /** + * @brief Pointer to lower level driver. + */ + //const FSMCDriver *fsmcp; + /** + * @brief Number of erase blocks in NAND device. + */ + uint32_t blocks; + /** + * @brief Number of data bytes in page. + */ + uint32_t page_data_size; + /** + * @brief Number of spare bytes in page. + */ + uint32_t page_spare_size; + /** + * @brief Number of pages in block. + */ + uint32_t pages_per_block; + /** + * @brief Number of write cycles for row addressing. + */ + uint8_t rowcycles; + /** + * @brief Number of write cycles for column addressing. + */ + uint8_t colcycles; + + /* End of the mandatory fields.*/ + /** + * @brief Number of wait cycles. This value will be used both for + * PMEM and PATTR registers + * + * @note For proper calculation procedure please look at AN2784 document + * from STMicroelectronics. + */ + uint32_t pmem; +#if STM32_NAND_USE_EXT_INT + /** + * @brief Function enabling interrupts from EXTI + */ + nandisrswitch_t ext_nand_isr_enable; + /** + * @brief Function disabling interrupts from EXTI + */ + nandisrswitch_t ext_nand_isr_disable; +#endif /* STM32_NAND_USE_EXT_INT */ +} NANDConfig; + +/** + * @brief Structure representing an NAND driver. + */ +struct NANDDriver { + /** + * @brief Driver state. + */ + nandstate_t state; + /** + * @brief Current configuration data. + */ + const NANDConfig *config; + /** + * @brief Array to store bad block map. + */ +#if NAND_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__) +#if CH_CFG_USE_MUTEXES || defined(__DOXYGEN__) + /** + * @brief Mutex protecting the bus. + */ + mutex_t mutex; +#elif CH_CFG_USE_SEMAPHORES + semaphore_t semaphore; +#endif +#endif /* NAND_USE_MUTUAL_EXCLUSION */ + /* End of the mandatory fields.*/ + /** + * @brief Function enabling interrupts from FSMC + */ + nandisrhandler_t isr_handler; + /** + * @brief Pointer to current transaction buffer + */ + uint8_t *rxdata; + /** + * @brief Current transaction length + */ + size_t datalen; + /** + * @brief DMA mode bit mask. + */ + uint32_t dmamode; + /** + * @brief DMA channel. + */ + const stm32_dma_stream_t *dma; + /** + * @brief Thread waiting for I/O completion. + */ + thread_t *thread; + /** + * @brief Pointer to the FSMC NAND registers block. + */ + FSMC_NAND_TypeDef *nand; + /** + * @brief Memory mapping for data. + */ + uint8_t *map_data; + /** + * @brief Memory mapping for commands. + */ + uint8_t *map_cmd; + /** + * @brief Memory mapping for addresses. + */ + uint8_t *map_addr; + /** + * @brief Pointer to bad block map. + * @details One bit per block. All memory allocation is user's responsibility. + */ + bitmap_t *bb_map; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_NAND_USE_FSMC_NAND1 && !defined(__DOXYGEN__) +extern NANDDriver NANDD1; +#endif + +#if STM32_NAND_USE_FSMC_NAND2 && !defined(__DOXYGEN__) +extern NANDDriver NANDD2; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void nand_lld_init(void); + void nand_lld_start(NANDDriver *nandp); + void nand_lld_stop(NANDDriver *nandp); + void nand_lld_read_data(NANDDriver *nandp, uint8_t *data, + size_t datalen, uint8_t *addr, size_t addrlen, uint32_t *ecc); + void nand_lld_polled_read_data(NANDDriver *nandp, uint8_t *data, size_t len); + void nand_lld_write_addr(NANDDriver *nandp, const uint8_t *addr, size_t len); + void nand_lld_write_cmd(NANDDriver *nandp, uint8_t cmd); + uint8_t nand_lld_erase(NANDDriver *nandp, uint8_t *addr, size_t addrlen); + uint8_t nand_lld_write_data(NANDDriver *nandp, const uint8_t *data, + size_t datalen, uint8_t *addr, size_t addrlen, uint32_t *ecc); + uint8_t nand_lld_read_status(NANDDriver *nandp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_NAND */ + +#endif /* _NAND_LLD_H_ */ + +/** @} */ diff --git a/os/hal/ports/STM32/LLD/FSMCv1/nand_lld.c b/os/hal/ports/STM32/LLD/FSMCv1/nand_lld.c deleted file mode 100644 index b37c026..0000000 --- a/os/hal/ports/STM32/LLD/FSMCv1/nand_lld.c +++ /dev/null @@ -1,515 +0,0 @@ -/* - ChibiOS/HAL - Copyright (C) 2014 Uladzimir Pylinsky aka barthess - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -/** - * @file nand_lld.c - * @brief NAND Driver subsystem low level driver source. - * - * @addtogroup NAND - * @{ - */ - -#include "hal.h" - -#if (HAL_USE_NAND == TRUE) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ -#define NAND_DMA_CHANNEL \ - STM32_DMA_GETCHANNEL(STM32_NAND_DMA_STREAM, \ - STM32_FSMC_DMA_CHN) - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/** - * @brief NAND1 driver identifier. - */ -#if STM32_NAND_USE_FSMC_NAND1 || defined(__DOXYGEN__) -NANDDriver NANDD1; -#endif - -/** - * @brief NAND2 driver identifier. - */ -#if STM32_NAND_USE_FSMC_NAND2 || defined(__DOXYGEN__) -NANDDriver NANDD2; -#endif - -/*===========================================================================*/ -/* Driver local types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ -/** - * @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 Put calling thread in suspend and switch driver state - * - * @param[in] nandp pointer to the @p NANDDriver object - */ -static void nand_lld_suspend_thread(NANDDriver *nandp) { - - osalThreadSuspendS(&nandp->thread); -} - -/** - * @brief Caclulate ECCPS register value - * - * @param[in] nandp pointer to the @p NANDDriver object - */ -static uint32_t calc_eccps(NANDDriver *nandp) { - - uint32_t i = 0; - uint32_t eccps = nandp->config->page_data_size; - - eccps = eccps >> 9; - while (eccps > 0){ - i++; - eccps >>= 1; - } - - return i << 17; -} - -/*===========================================================================*/ -/* Driver interrupt handlers. */ -/*===========================================================================*/ - -/** - * @brief Enable interrupts from NAND - * - * @param[in] nandp pointer to the @p NANDDriver object - * - * @notapi - */ -static void nand_ready_isr_enable(NANDDriver *nandp) { -#if STM32_NAND_USE_EXT_INT - nandp->config->ext_nand_isr_enable(); -#else - nandp->nand->SR &= ~(FSMC_SR_IRS | FSMC_SR_ILS | FSMC_SR_IFS | - FSMC_SR_ILEN | FSMC_SR_IFEN); - nandp->nand->SR |= FSMC_SR_IREN; -#endif -} - -/** - * @brief Disable interrupts from NAND - * - * @param[in] nandp pointer to the @p NANDDriver object - * - * @notapi - */ -static void nand_ready_isr_disable(NANDDriver *nandp) { -#if STM32_NAND_USE_EXT_INT - nandp->config->ext_nand_isr_disable(); -#else - nandp->nand->SR &= ~FSMC_SR_IREN; -#endif -} - -/** - * @brief Ready interrupt handler - * - * @param[in] nandp pointer to the @p NANDDriver object - * - * @notapi - */ -static void nand_isr_handler (NANDDriver *nandp) { - - osalSysLockFromISR(); - -#if !STM32_NAND_USE_EXT_INT - osalDbgCheck(nandp->nand->SR & FSMC_SR_IRS); /* spurious interrupt happened */ - nandp->nand->SR &= ~FSMC_SR_IRS; -#endif - - switch (nandp->state){ - case NAND_READ: - nandp->state = NAND_DMA_RX; - dmaStartMemCopy(nandp->dma, nandp->dmamode, - nandp->map_data, nandp->rxdata, nandp->datalen); - /* thread will be waked up from DMA ISR */ - break; - - case NAND_ERASE: - /* NAND reports about erase finish */ - nandp->state = NAND_READY; - wakeup_isr(nandp); - break; - - case NAND_PROGRAM: - /* NAND reports about page programming finish */ - nandp->state = NAND_READY; - wakeup_isr(nandp); - break; - - default: - osalSysHalt("Unhandled case"); - break; - } - osalSysUnlockFromISR(); -} - -/** - * @brief DMA RX end IRQ handler. - * - * @param[in] nandp pointer to the @p NANDDriver object - * @param[in] flags pre-shifted content of the ISR register - * - * @notapi - */ -static void nand_lld_serve_transfer_end_irq(NANDDriver *nandp, uint32_t flags) { - /* DMA errors handling.*/ -#if defined(STM32_NAND_DMA_ERROR_HOOK) - if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { - STM32_NAND_DMA_ERROR_HOOK(nandp); - } -#else - (void)flags; -#endif - - osalSysLockFromISR(); - - dmaStreamDisable(nandp->dma); - - switch (nandp->state){ - case NAND_DMA_TX: - nandp->state = NAND_PROGRAM; - nandp->map_cmd[0] = NAND_CMD_PAGEPROG; - /* thread will be woken from ready_isr() */ - break; - - case NAND_DMA_RX: - nandp->state = NAND_READY; - nandp->rxdata = NULL; - nandp->datalen = 0; - wakeup_isr(nandp); - break; - - default: - osalSysHalt("Unhandled case"); - break; - } - - osalSysUnlockFromISR(); -} - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief Low level NAND driver initialization. - * - * @notapi - */ -void nand_lld_init(void) { - - fsmc_init(); - -#if STM32_NAND_USE_FSMC_NAND1 - /* Driver initialization.*/ - nandObjectInit(&NANDD1); - NANDD1.rxdata = NULL; - NANDD1.datalen = 0; - NANDD1.thread = NULL; - NANDD1.dma = STM32_DMA_STREAM(STM32_NAND_DMA_STREAM); - NANDD1.nand = FSMCD1.nand1; - NANDD1.map_data = (uint8_t*)FSMC_Bank2_MAP_COMMON_DATA; - NANDD1.map_cmd = (uint8_t*)FSMC_Bank2_MAP_COMMON_CMD; - NANDD1.map_addr = (uint8_t*)FSMC_Bank2_MAP_COMMON_ADDR; - NANDD1.bb_map = NULL; -#endif /* STM32_NAND_USE_FSMC_NAND1 */ - -#if STM32_NAND_USE_FSMC_NAND2 - /* Driver initialization.*/ - nandObjectInit(&NANDD2); - NANDD2.rxdata = NULL; - NANDD2.datalen = 0; - NANDD2.thread = NULL; - NANDD2.dma = STM32_DMA_STREAM(STM32_NAND_DMA_STREAM); - NANDD2.nand = FSMCD1.nand2; - NANDD2.map_data = (uint8_t*)FSMC_Bank3_MAP_COMMON_DATA; - NANDD2.map_cmd = (uint8_t*)FSMC_Bank3_MAP_COMMON_CMD; - NANDD2.map_addr = (uint8_t*)FSMC_Bank3_MAP_COMMON_ADDR; - NANDD2.bb_map = NULL; -#endif /* STM32_NAND_USE_FSMC_NAND2 */ -} - -/** - * @brief Configures and activates the NAND peripheral. - * - * @param[in] nandp pointer to the @p NANDDriver object - * - * @notapi - */ -void nand_lld_start(NANDDriver *nandp) { - - bool b; - - if (FSMCD1.state == FSMC_STOP) - fsmc_start(&FSMCD1); - - if (nandp->state == NAND_STOP) { - b = dmaStreamAllocate(nandp->dma, - STM32_EMC_FSMC1_IRQ_PRIORITY, - (stm32_dmaisr_t)nand_lld_serve_transfer_end_irq, - (void *)nandp); - osalDbgAssert(!b, "stream already allocated"); - nandp->dmamode = STM32_DMA_CR_CHSEL(NAND_DMA_CHANNEL) | - STM32_DMA_CR_PL(STM32_NAND_NAND1_DMA_PRIORITY) | - STM32_DMA_CR_PSIZE_BYTE | - STM32_DMA_CR_MSIZE_BYTE | - STM32_DMA_CR_DMEIE | - STM32_DMA_CR_TEIE | - STM32_DMA_CR_TCIE; - /* dmaStreamSetFIFO(nandp->dma, - STM32_DMA_FCR_DMDIS | NAND_STM32_DMA_FCR_FTH_LVL); */ - nandp->nand->PCR = calc_eccps(nandp) | FSMC_PCR_PTYP | FSMC_PCR_PBKEN; - nandp->nand->PMEM = nandp->config->pmem; - nandp->nand->PATT = nandp->config->pmem; - nandp->isr_handler = nand_isr_handler; - nand_ready_isr_enable(nandp); - } -} - -/** - * @brief Deactivates the NAND peripheral. - * - * @param[in] nandp pointer to the @p NANDDriver object - * - * @notapi - */ -void nand_lld_stop(NANDDriver *nandp) { - - if (nandp->state == NAND_READY) { - dmaStreamRelease(nandp->dma); - nandp->nand->PCR &= ~FSMC_PCR_PBKEN; - nand_ready_isr_disable(nandp); - nandp->isr_handler = NULL; - } -} - -/** - * @brief Read data from NAND. - * - * @param[in] nandp pointer to the @p NANDDriver object - * @param[out] data pointer to data buffer - * @param[in] datalen size of data buffer - * @param[in] addr pointer to address buffer - * @param[in] addrlen length of address - * @param[out] ecc pointer to store computed ECC. Ignored when NULL. - * - * @notapi - */ -void nand_lld_read_data(NANDDriver *nandp, uint8_t *data, size_t datalen, - uint8_t *addr, size_t addrlen, uint32_t *ecc){ - - nandp->state = NAND_READ; - nandp->rxdata = data; - nandp->datalen = datalen; - - nand_lld_write_cmd (nandp, NAND_CMD_READ0); - nand_lld_write_addr(nandp, addr, addrlen); - osalSysLock(); - nand_lld_write_cmd (nandp, NAND_CMD_READ0_CONFIRM); - - /* Here NAND asserts busy signal and starts transferring from memory - array to page buffer. After the end of transmission ready_isr functions - starts DMA transfer from page buffer to MCU's RAM.*/ - osalDbgAssert((nandp->nand->PCR & FSMC_PCR_ECCEN) == 0, - "State machine broken. ECCEN must be previously disabled."); - - if (NULL != ecc){ - nandp->nand->PCR |= FSMC_PCR_ECCEN; - } - - nand_lld_suspend_thread(nandp); - osalSysUnlock(); - - /* thread was woken up from DMA ISR */ - if (NULL != ecc){ - while (! (nandp->nand->SR & FSMC_SR_FEMPT)) - ; - *ecc = nandp->nand->ECCR; - nandp->nand->PCR &= ~FSMC_PCR_ECCEN; - } -} - -/** - * @brief Write data to NAND. - * - * @param[in] nandp pointer to the @p NANDDriver object - * @param[in] data buffer with data to be written - * @param[in] datalen size of data buffer - * @param[in] addr pointer to address buffer - * @param[in] addrlen length of address - * @param[out] ecc pointer to store computed ECC. Ignored when NULL. - * - * @return The operation status reported by NAND IC (0x70 command). - * - * @notapi - */ -uint8_t nand_lld_write_data(NANDDriver *nandp, const uint8_t *data, - size_t datalen, uint8_t *addr, size_t addrlen, uint32_t *ecc) { - - nandp->state = NAND_WRITE; - - nand_lld_write_cmd (nandp, NAND_CMD_WRITE); - osalSysLock(); - nand_lld_write_addr(nandp, addr, addrlen); - - /* Now start DMA transfer to NAND buffer and put thread in sleep state. - Tread will be woken up from ready ISR. */ - nandp->state = NAND_DMA_TX; - osalDbgAssert((nandp->nand->PCR & FSMC_PCR_ECCEN) == 0, - "State machine broken. ECCEN must be previously disabled."); - - if (NULL != ecc){ - nandp->nand->PCR |= FSMC_PCR_ECCEN; - } - - dmaStartMemCopy(nandp->dma, nandp->dmamode, data, nandp->map_data, datalen); - - nand_lld_suspend_thread(nandp); - osalSysUnlock(); - - if (NULL != ecc){ - while (! (nandp->nand->SR & FSMC_SR_FEMPT)) - ; - *ecc = nandp->nand->ECCR; - nandp->nand->PCR &= ~FSMC_PCR_ECCEN; - } - - return nand_lld_read_status(nandp); -} - -/** - * @brief Erase block. - * - * @param[in] nandp pointer to the @p NANDDriver object - * @param[in] addr pointer to address buffer - * @param[in] addrlen length of address - * - * @return The operation status reported by NAND IC (0x70 command). - * - * @notapi - */ -uint8_t nand_lld_erase(NANDDriver *nandp, uint8_t *addr, size_t addrlen) { - - nandp->state = NAND_ERASE; - - nand_lld_write_cmd (nandp, NAND_CMD_ERASE); - nand_lld_write_addr(nandp, addr, addrlen); - osalSysLock(); - nand_lld_write_cmd (nandp, NAND_CMD_ERASE_CONFIRM); - nand_lld_suspend_thread(nandp); - osalSysUnlock(); - - return nand_lld_read_status(nandp); -} - -/** - * @brief Read data from NAND using polling approach. - * - * @detatils Use this function to read data when no waiting expected. For - * Example read status word after 0x70 command - * - * @param[in] nandp pointer to the @p NANDDriver object - * @param[out] data pointer to output buffer - * @param[in] len length of data to be read - * - * @notapi - */ -void nand_lld_polled_read_data(NANDDriver *nandp, uint8_t *data, size_t len) { - size_t i = 0; - - for (i=0; imap_data[i]; -} - -/** - * @brief Send addres to NAND. - * - * @param[in] nandp pointer to the @p NANDDriver object - * @param[in] len length of address array - * @param[in] addr pointer to address array - * - * @notapi - */ -void nand_lld_write_addr(NANDDriver *nandp, const uint8_t *addr, size_t len) { - size_t i = 0; - - for (i=0; imap_addr[i] = addr[i]; -} - -/** - * @brief Send command to NAND. - * - * @param[in] nandp pointer to the @p NANDDriver object - * @param[in] cmd command value - * - * @notapi - */ -void nand_lld_write_cmd(NANDDriver *nandp, uint8_t cmd) { - nandp->map_cmd[0] = cmd; -} - -/** - * @brief Read status byte from NAND. - * - * @param[in] nandp pointer to the @p NANDDriver object - * - * @return Status byte. - * - * @notapi - */ -uint8_t nand_lld_read_status(NANDDriver *nandp) { - - uint8_t status[1] = {0x01}; /* presume worse */ - - nand_lld_write_cmd(nandp, NAND_CMD_STATUS); - nand_lld_polled_read_data(nandp, status, 1); - - return status[0]; -} - -#endif /* HAL_USE_NAND */ - -/** @} */ - diff --git a/os/hal/ports/STM32/LLD/FSMCv1/nand_lld.h b/os/hal/ports/STM32/LLD/FSMCv1/nand_lld.h deleted file mode 100644 index c891fcc..0000000 --- a/os/hal/ports/STM32/LLD/FSMCv1/nand_lld.h +++ /dev/null @@ -1,324 +0,0 @@ -/* - ChibiOS/HAL - Copyright (C) 2014 Uladzimir Pylinsky aka barthess - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -/** - * @file nand_lld.h - * @brief NAND Driver subsystem low level driver header. - * - * @addtogroup NAND - * @{ - */ - -#ifndef _NAND_LLD_H_ -#define _NAND_LLD_H_ - -#include "fsmc.h" -#include "bitmap.h" - -#if (HAL_USE_NAND == TRUE) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver constants. */ -/*===========================================================================*/ -#define NAND_MIN_PAGE_SIZE 256 -#define NAND_MAX_PAGE_SIZE 8192 - -/*===========================================================================*/ -/* Driver pre-compile time settings. */ -/*===========================================================================*/ - -/** - * @name Configuration options - * @{ - */ -/** - * @brief FSMC1 interrupt priority level setting. - */ -#if !defined(STM32_EMC_FSMC1_IRQ_PRIORITY) || defined(__DOXYGEN__) -#define STM32_EMC_FSMC1_IRQ_PRIORITY 10 -#endif - -/** - * @brief NAND driver enable switch. - * @details If set to @p TRUE the support for NAND1 is included. - */ -#if !defined(STM32_NAND_USE_NAND1) || defined(__DOXYGEN__) -#define STM32_NAND_USE_NAND1 FALSE -#endif - -/** - * @brief NAND driver enable switch. - * @details If set to @p TRUE the support for NAND2 is included. - */ -#if !defined(STM32_NAND_USE_NAND2) || defined(__DOXYGEN__) -#define STM32_NAND_USE_NAND2 FALSE -#endif - -/** - * @brief NAND DMA error hook. - * @note The default action for DMA errors is a system halt because DMA - * error can only happen because programming errors. - */ -#if !defined(STM32_NAND_DMA_ERROR_HOOK) || defined(__DOXYGEN__) -#define STM32_NAND_DMA_ERROR_HOOK(nandp) osalSysHalt("DMA failure") -#endif - -/** - * @brief NAND interrupt enable switch. - * @details If set to @p TRUE the support for internal FSMC interrupt included. - */ -#if !defined(STM32_NAND_USE_INT) || defined(__DOXYGEN__) -#define STM32_NAND_USE_INT FALSE -#endif - -/** -* @brief NAND1 DMA priority (0..3|lowest..highest). -*/ -#if !defined(STM32_NAND_NAND1_DMA_PRIORITY) || defined(__DOXYGEN__) -#define STM32_NAND_NAND1_DMA_PRIORITY 0 -#endif - -/** -* @brief NAND2 DMA priority (0..3|lowest..highest). -*/ -#if !defined(STM32_NAND_NAND2_DMA_PRIORITY) || defined(__DOXYGEN__) -#define STM32_NAND_NAND2_DMA_PRIORITY 0 -#endif - -/** - * @brief DMA stream used for NAND operations. - * @note This option is only available on platforms with enhanced DMA. - */ -#if !defined(STM32_NAND_DMA_STREAM) || defined(__DOXYGEN__) -#define STM32_NAND_DMA_STREAM STM32_DMA_STREAM_ID(2, 6) -#endif - -/** @} */ - -/*===========================================================================*/ -/* Derived constants and error checks. */ -/*===========================================================================*/ - -#if !STM32_NAND_USE_FSMC_NAND1 && !STM32_NAND_USE_FSMC_NAND2 -#error "NAND driver activated but no NAND peripheral assigned" -#endif - -#if (STM32_NAND_USE_FSMC_NAND2 || STM32_NAND_USE_FSMC_NAND1) && !STM32_HAS_FSMC -#error "FSMC not present in the selected device" -#endif - -#if STM32_NAND_USE_EXT_INT && !HAL_USE_EXT -#error "External interrupt controller must be enabled to use this feature" -#endif - -#if !defined(STM32_DMA_REQUIRED) -#define STM32_DMA_REQUIRED -#endif - -/*===========================================================================*/ -/* Driver data structures and types. */ -/*===========================================================================*/ - -/** - * @brief NAND driver condition flags type. - */ -typedef uint32_t nandflags_t; - -/** - * @brief Type of a structure representing an NAND driver. - */ -typedef struct NANDDriver NANDDriver; - -/** - * @brief Type of interrupt handler function - */ -typedef void (*nandisrhandler_t)(NANDDriver *nandp); - -#if STM32_NAND_USE_EXT_INT -/** - * @brief Type of function switching external interrupts on and off. - */ -typedef void (*nandisrswitch_t)(void); -#endif /* STM32_NAND_USE_EXT_INT */ - -/** - * @brief Driver configuration structure. - * @note It could be empty on some architectures. - */ -typedef struct { - /** - * @brief Pointer to lower level driver. - */ - //const FSMCDriver *fsmcp; - /** - * @brief Number of erase blocks in NAND device. - */ - uint32_t blocks; - /** - * @brief Number of data bytes in page. - */ - uint32_t page_data_size; - /** - * @brief Number of spare bytes in page. - */ - uint32_t page_spare_size; - /** - * @brief Number of pages in block. - */ - uint32_t pages_per_block; - /** - * @brief Number of write cycles for row addressing. - */ - uint8_t rowcycles; - /** - * @brief Number of write cycles for column addressing. - */ - uint8_t colcycles; - - /* End of the mandatory fields.*/ - /** - * @brief Number of wait cycles. This value will be used both for - * PMEM and PATTR registers - * - * @note For proper calculation procedure please look at AN2784 document - * from STMicroelectronics. - */ - uint32_t pmem; -#if STM32_NAND_USE_EXT_INT - /** - * @brief Function enabling interrupts from EXTI - */ - nandisrswitch_t ext_nand_isr_enable; - /** - * @brief Function disabling interrupts from EXTI - */ - nandisrswitch_t ext_nand_isr_disable; -#endif /* STM32_NAND_USE_EXT_INT */ -} NANDConfig; - -/** - * @brief Structure representing an NAND driver. - */ -struct NANDDriver { - /** - * @brief Driver state. - */ - nandstate_t state; - /** - * @brief Current configuration data. - */ - const NANDConfig *config; - /** - * @brief Array to store bad block map. - */ -#if NAND_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__) -#if CH_CFG_USE_MUTEXES || defined(__DOXYGEN__) - /** - * @brief Mutex protecting the bus. - */ - mutex_t mutex; -#elif CH_CFG_USE_SEMAPHORES - semaphore_t semaphore; -#endif -#endif /* NAND_USE_MUTUAL_EXCLUSION */ - /* End of the mandatory fields.*/ - /** - * @brief Function enabling interrupts from FSMC - */ - nandisrhandler_t isr_handler; - /** - * @brief Pointer to current transaction buffer - */ - uint8_t *rxdata; - /** - * @brief Current transaction length - */ - size_t datalen; - /** - * @brief DMA mode bit mask. - */ - uint32_t dmamode; - /** - * @brief DMA channel. - */ - const stm32_dma_stream_t *dma; - /** - * @brief Thread waiting for I/O completion. - */ - thread_t *thread; - /** - * @brief Pointer to the FSMC NAND registers block. - */ - FSMC_NAND_TypeDef *nand; - /** - * @brief Memory mapping for data. - */ - uint8_t *map_data; - /** - * @brief Memory mapping for commands. - */ - uint8_t *map_cmd; - /** - * @brief Memory mapping for addresses. - */ - uint8_t *map_addr; - /** - * @brief Pointer to bad block map. - * @details One bit per block. All memory allocation is user's responsibility. - */ - bitmap_t *bb_map; -}; - -/*===========================================================================*/ -/* Driver macros. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -#if STM32_NAND_USE_FSMC_NAND1 && !defined(__DOXYGEN__) -extern NANDDriver NANDD1; -#endif - -#if STM32_NAND_USE_FSMC_NAND2 && !defined(__DOXYGEN__) -extern NANDDriver NANDD2; -#endif - -#ifdef __cplusplus -extern "C" { -#endif - void nand_lld_init(void); - void nand_lld_start(NANDDriver *nandp); - void nand_lld_stop(NANDDriver *nandp); - void nand_lld_read_data(NANDDriver *nandp, uint8_t *data, - size_t datalen, uint8_t *addr, size_t addrlen, uint32_t *ecc); - void nand_lld_polled_read_data(NANDDriver *nandp, uint8_t *data, size_t len); - void nand_lld_write_addr(NANDDriver *nandp, const uint8_t *addr, size_t len); - void nand_lld_write_cmd(NANDDriver *nandp, uint8_t cmd); - uint8_t nand_lld_erase(NANDDriver *nandp, uint8_t *addr, size_t addrlen); - uint8_t nand_lld_write_data(NANDDriver *nandp, const uint8_t *data, - size_t datalen, uint8_t *addr, size_t addrlen, uint32_t *ecc); - uint8_t nand_lld_read_status(NANDDriver *nandp); -#ifdef __cplusplus -} -#endif - -#endif /* HAL_USE_NAND */ - -#endif /* _NAND_LLD_H_ */ - -/** @} */ diff --git a/os/hal/ports/STM32/LLD/LTDCv1/hal_stm32_ltdc.c b/os/hal/ports/STM32/LLD/LTDCv1/hal_stm32_ltdc.c new file mode 100644 index 0000000..e5f9a09 --- /dev/null +++ b/os/hal/ports/STM32/LLD/LTDCv1/hal_stm32_ltdc.c @@ -0,0 +1,3792 @@ +/* + Copyright (C) 2013-2015 Andrea Zoppi + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file stm32_ltdc.c + * @brief LCD-TFT Controller Driver. + */ + +#include "ch.h" +#include "hal.h" + +#include "hal_stm32_ltdc.h" + +#if (TRUE == STM32_LTDC_USE_LTDC) || defined(__DOXYGEN__) + +/* TODO: Check preconditions (e.g., LTDC is ready).*/ + +/* Ignore annoying warning messages for actually safe code.*/ +#if defined(__GNUC__) && !defined(__DOXYGEN__) +#pragma GCC diagnostic ignored "-Wtype-limits" +#endif + +/** + * @addtogroup ltdc + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#if !defined(LTDC_LxBFCR_BF) && !defined(__DOXYGEN__) +#define LTDC_LxBFCR_BF (LTDC_LxBFCR_BF1 | LTDC_LxBFCR_BF2) +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief LTDC1 driver identifier. + */ +LTDCDriver LTDCD1; + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/** + * @brief Bits per pixel lookup table. + */ +static const uint8_t ltdc_bpp[LTDC_MAX_PIXFMT_ID + 1] = { + 32, /* LTDC_FMT_ARGB8888 */ + 24, /* LTDC_FMT_RGB888 */ + 16, /* LTDC_FMT_RGB565 */ + 16, /* LTDC_FMT_ARGB1555 */ + 16, /* LTDC_FMT_ARGB4444 */ + 8, /* LTDC_FMT_L8 */ + 8, /* LTDC_FMT_AL44 */ + 16 /* LTDC_FMT_AL88 */ +}; + +/** + * @brief Invalid frame. + */ +static const ltdc_frame_t ltdc_invalid_frame = { + NULL, + 1, + 1, + 1, + LTDC_FMT_L8 +}; + +/** + * @brief Invalid window. + * @details Pixel size, located at the origin of the screen. + */ +static const ltdc_window_t ltdc_invalid_window = { + 0, + 1, + 0, + 1 +}; + +/** + * @brief Default layer specifications. + */ +static const ltdc_laycfg_t ltdc_default_laycfg = { + <dc_invalid_frame, + <dc_invalid_window, + LTDC_COLOR_BLACK, + 0x00, + LTDC_COLOR_BLACK, + NULL, + 0, + LTDC_BLEND_FIX1_FIX2, + 0 +}; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Forces LTDC register reload. + * @details Blocking function. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @sclass + * @notapi + */ +static void ltdc_force_reload_s(LTDCDriver *ltdcp) { + + osalDbgCheckClassS(); + osalDbgCheck(ltdcp == <DCD1); + + LTDC->SRCR |= LTDC_SRCR_IMR; + while (LTDC->SRCR & (LTDC_SRCR_IMR | LTDC_SRCR_VBR)) + chSchDoYieldS(); +} + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @name LTDC interrupt handlers + * @{ + */ + +/** + * @brief LTDC event interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_LTDC_EV_HANDLER) { + + LTDCDriver *const ltdcp = <DCD1; + thread_t *tp = NULL; + + OSAL_IRQ_PROLOGUE(); + + /* Handle Line Interrupt ISR.*/ + if ((LTDC->ISR & LTDC_ISR_LIF) && (LTDC->IER & LTDC_IER_LIE)) { + osalDbgAssert(ltdcp->config->line_isr != NULL, "invalid state"); + ltdcp->config->line_isr(ltdcp); + LTDC->ICR |= LTDC_ICR_CLIF; + } + + /* Handle Register Reload ISR.*/ + if ((LTDC->ISR & LTDC_ISR_RRIF) && (LTDC->IER & LTDC_IER_RRIE)) { + if (ltdcp->config->rr_isr != NULL) + ltdcp->config->rr_isr(ltdcp); + + osalSysLockFromISR(); + osalDbgAssert(ltdcp->state == LTDC_ACTIVE, "invalid state"); +#if (TRUE == LTDC_USE_WAIT) + /* Wake the waiting thread up.*/ + if (ltdcp->thread != NULL) { + tp = ltdcp->thread; + ltdcp->thread = NULL; + tp->u.rdymsg = MSG_OK; + chSchReadyI(tp); + } +#endif /* LTDC_USE_WAIT */ + ltdcp->state = LTDC_READY; + osalSysUnlockFromISR(); + + LTDC->ICR |= LTDC_ICR_CRRIF; + } + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief LTDC error interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_LTDC_ER_HANDLER) { + + static LTDCDriver *const ltdcp = <DCD1; + + OSAL_IRQ_PROLOGUE(); + + /* Handle FIFO Underrun ISR.*/ + if ((LTDC->ISR & LTDC_ISR_FUIF) && (LTDC->IER & LTDC_IER_FUIE)) { + osalDbgAssert(ltdcp->config->fuerr_isr != NULL, "invalid state"); + ltdcp->config->fuerr_isr(ltdcp); + LTDC->ICR |= LTDC_ICR_CFUIF; + } + + /* Handle Transfer Error ISR.*/ + if ((LTDC->ISR & LTDC_ISR_TERRIF) && (LTDC->IER & LTDC_IER_TERRIE)) { + osalDbgAssert(ltdcp->config->terr_isr != NULL, "invalid state"); + ltdcp->config->terr_isr(ltdcp); + LTDC->ICR |= LTDC_ICR_CTERRIF; + } + + OSAL_IRQ_EPILOGUE(); +} + +/** @} */ + +/** + * @name LTDC driver-specific methods + * @{ + */ + +/** + * @brief LTDC Driver initialization. + * @details Initializes the LTDC subsystem and chosen drivers. Should be + * called at board initialization. + * + * @init + */ +void ltdcInit(void) { + + /* Reset the LTDC hardware module.*/ + rccResetLTDC(); + + /* Enable the LTDC clock.*/ + RCC->DCKCFGR = (RCC->DCKCFGR & ~RCC_DCKCFGR_PLLSAIDIVR) | (2 << 16); /* /8 */ + rccEnableLTDC(false); + + /* Driver struct initialization.*/ + ltdcObjectInit(<DCD1); + LTDCD1.state = LTDC_STOP; +} + +/** + * @brief Initializes the standard part of a @p LTDCDriver structure. + * + * @param[out] ltdcp pointer to the @p LTDCDriver object + * + * @init + */ +void ltdcObjectInit(LTDCDriver *ltdcp) { + + osalDbgCheck(ltdcp == <DCD1); + + ltdcp->state = LTDC_UNINIT; + ltdcp->config = NULL; + ltdcp->active_window = ltdc_invalid_window; +#if (TRUE == LTDC_USE_WAIT) + ltdcp->thread = NULL; +#endif /* LTDC_USE_WAIT */ +#if (TRUE == LTDC_USE_MUTUAL_EXCLUSION) +#if (TRUE == CH_CFG_USE_MUTEXES) + chMtxObjectInit(<dcp->lock); +#else + chSemObjectInit(<dcp->lock, 1); +#endif +#endif /* LTDC_USE_MUTUAL_EXCLUSION */ +} + +/** + * @brief Get the driver state. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @retun driver state + * + * @iclass + */ +ltdc_state_t ltdcGetStateI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + + return ltdcp->state; +} + +/** + * @brief Get the driver state. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @retun driver state + * + * @api + */ +ltdc_state_t ltdcGetState(LTDCDriver *ltdcp) { + + ltdc_state_t state; + osalSysLock(); + state = ltdcGetStateI(ltdcp); + osalSysUnlock(); + return state; +} + +/** + * @brief Configures and activates the LTDC peripheral. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] configp pointer to the @p LTDCConfig object + * + * @api + */ +void ltdcStart(LTDCDriver *ltdcp, const LTDCConfig *configp) { + + uint32_t hacc, vacc, flags; + + osalSysLock(); + + osalDbgCheck(ltdcp == <DCD1); + osalDbgCheck(configp != NULL); + osalDbgAssert(ltdcp->state == LTDC_STOP, "invalid state"); + + ltdcp->config = configp; + + /* Turn off the controller and its interrupts.*/ + LTDC->GCR = 0; + LTDC->IER = 0; + ltdc_force_reload_s(ltdcp); + + /* Set synchronization params.*/ + osalDbgAssert(configp->hsync_width >= LTDC_MIN_HSYNC_WIDTH, "bounds"); + osalDbgAssert(configp->hsync_width <= LTDC_MAX_HSYNC_WIDTH, "bounds"); + osalDbgAssert(configp->vsync_height >= LTDC_MIN_VSYNC_HEIGHT, "bounds"); + osalDbgAssert(configp->vsync_height <= LTDC_MAX_VSYNC_HEIGHT, "bounds"); + + hacc = configp->hsync_width - 1; + vacc = configp->vsync_height - 1; + + LTDC->SSCR = (((hacc << 16) & LTDC_SSCR_HSW) | + ((vacc << 0) & LTDC_SSCR_VSH)); + + /* Set accumulated back porch params.*/ + osalDbgAssert(configp->hbp_width >= LTDC_MIN_HBP_WIDTH, "bounds"); + osalDbgAssert(configp->hbp_width <= LTDC_MAX_HBP_WIDTH, "bounds"); + osalDbgAssert(configp->vbp_height >= LTDC_MIN_VBP_HEIGHT, "bounds"); + osalDbgAssert(configp->vbp_height <= LTDC_MAX_VBP_HEIGHT, "bounds"); + + hacc += configp->hbp_width; + vacc += configp->vbp_height; + + osalDbgAssert(hacc + 1 >= LTDC_MIN_ACC_HBP_WIDTH, "bounds"); + osalDbgAssert(hacc + 1 <= LTDC_MAX_ACC_HBP_WIDTH, "bounds"); + osalDbgAssert(vacc + 1 >= LTDC_MIN_ACC_VBP_HEIGHT, "bounds"); + osalDbgAssert(vacc + 1 <= LTDC_MAX_ACC_VBP_HEIGHT, "bounds"); + + LTDC->BPCR = (((hacc << 16) & LTDC_BPCR_AHBP) | + ((vacc << 0) & LTDC_BPCR_AVBP)); + + ltdcp->active_window.hstart = hacc + 1; + ltdcp->active_window.vstart = vacc + 1; + + /* Set accumulated active params.*/ + osalDbgAssert(configp->screen_width >= LTDC_MIN_SCREEN_WIDTH, "bounds"); + osalDbgAssert(configp->screen_width <= LTDC_MAX_SCREEN_WIDTH, "bounds"); + osalDbgAssert(configp->screen_height >= LTDC_MIN_SCREEN_HEIGHT, "bounds"); + osalDbgAssert(configp->screen_height <= LTDC_MAX_SCREEN_HEIGHT, "bounds"); + + hacc += configp->screen_width; + vacc += configp->screen_height; + + osalDbgAssert(hacc + 1 >= LTDC_MIN_ACC_ACTIVE_WIDTH, "bounds"); + osalDbgAssert(hacc + 1 <= LTDC_MAX_ACC_ACTIVE_WIDTH, "bounds"); + osalDbgAssert(vacc + 1 >= LTDC_MIN_ACC_ACTIVE_HEIGHT, "bounds"); + osalDbgAssert(vacc + 1 <= LTDC_MAX_ACC_ACTIVE_HEIGHT, "bounds"); + + LTDC->AWCR = (((hacc << 16) & LTDC_AWCR_AAW) | + ((vacc << 0) & LTDC_AWCR_AAH)); + + ltdcp->active_window.hstop = hacc; + ltdcp->active_window.vstop = vacc; + + /* Set accumulated total params.*/ + osalDbgAssert(configp->hfp_width >= LTDC_MIN_HFP_WIDTH, "bounds"); + osalDbgAssert(configp->hfp_width <= LTDC_MAX_HFP_WIDTH, "bounds"); + osalDbgAssert(configp->vfp_height >= LTDC_MIN_VFP_HEIGHT, "bounds"); + osalDbgAssert(configp->vfp_height <= LTDC_MAX_VFP_HEIGHT, "bounds"); + + hacc += configp->hfp_width; + vacc += configp->vfp_height; + + osalDbgAssert(hacc + 1 >= LTDC_MIN_ACC_TOTAL_WIDTH, "bounds"); + osalDbgAssert(hacc + 1 <= LTDC_MAX_ACC_TOTAL_WIDTH, "bounds"); + osalDbgAssert(vacc + 1 >= LTDC_MIN_ACC_TOTAL_HEIGHT, "bounds"); + osalDbgAssert(vacc + 1 <= LTDC_MAX_ACC_TOTAL_HEIGHT, "bounds"); + + LTDC->TWCR = (((hacc << 16) & LTDC_TWCR_TOTALW) | + ((vacc << 0) & LTDC_TWCR_TOTALH)); + + /* Set signal polarities and other flags.*/ + ltdcSetEnableFlagsI(ltdcp, configp->flags & ~LTDC_EF_ENABLE); + + /* Color settings.*/ + ltdcSetClearColorI(ltdcp, configp->clear_color); + + /* Load layer configurations.*/ + ltdcBgSetConfigI(ltdcp, configp->bg_laycfg); + ltdcFgSetConfigI(ltdcp, configp->fg_laycfg); + + /* Enable only the assigned interrupt service routines.*/ + nvicEnableVector(STM32_LTDC_EV_NUMBER, STM32_LTDC_EV_IRQ_PRIORITY); + nvicEnableVector(STM32_LTDC_ER_NUMBER, STM32_LTDC_ER_IRQ_PRIORITY); + + flags = LTDC_IER_RRIE; + if (configp->line_isr != NULL) + flags |= LTDC_IER_LIE; + if (configp->fuerr_isr != NULL) + flags |= LTDC_IER_FUIE; + if (configp->terr_isr != NULL) + flags |= LTDC_IER_TERRIE; + LTDC->IER = flags; + + /* Apply settings.*/ + ltdc_force_reload_s(ltdcp); + + /* Turn on the controller.*/ + LTDC->GCR |= LTDC_GCR_LTDCEN; + ltdc_force_reload_s(ltdcp); + + ltdcp->state = LTDC_READY; + osalSysUnlock(); +} + +/** + * @brief Deactivates the LTDC peripheral. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcStop(LTDCDriver *ltdcp) { + + osalDbgCheck(ltdcp == <DCD1); + + osalSysLock(); + osalDbgAssert(ltdcp->state == LTDC_READY, "invalid state"); + + /* Turn off the controller and its interrupts.*/ + LTDC->GCR &= ~LTDC_GCR_LTDCEN; + LTDC->IER = 0; +#if (TRUE == LTDC_USE_WAIT) + ltdcReloadS(ltdcp, true); +#else + ltdcStartReloadI(ltdcp, true); + while (ltdcIsReloadingI(ltdcp)) + chSchDoYieldS(); +#endif /* LTDC_USE_WAIT */ + + ltdcp->state = LTDC_STOP; + osalSysUnlock(); +} + +#if (TRUE == LTDC_USE_MUTUAL_EXCLUSION) + +/** + * @brief Gains exclusive access to the LTDC module. + * @details This function tries to gain ownership to the LTDC module, if the + * module is already being used then the invoking thread is queued. + * @pre In order to use this function the option + * @p LTDC_USE_MUTUAL_EXCLUSION must be enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @sclass + */ +void ltdcAcquireBusS(LTDCDriver *ltdcp) { + + osalDbgCheckClassS(); + osalDbgCheck(ltdcp == <DCD1); + +#if (TRUE == CH_CFG_USE_MUTEXES) + chMtxLockS(<dcp->lock); +#else + chSemWaitS(<dcp->lock); +#endif +} + +/** + * @brief Gains exclusive access to the LTDC module. + * @details This function tries to gain ownership to the LTDC module, if the + * module is already being used then the invoking thread is queued. + * @pre In order to use this function the option + * @p LTDC_USE_MUTUAL_EXCLUSION must be enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcAcquireBus(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcAcquireBusS(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Releases exclusive access to the LTDC module. + * @pre In order to use this function the option + * @p LTDC_USE_MUTUAL_EXCLUSION must be enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @sclass + */ +void ltdcReleaseBusS(LTDCDriver *ltdcp) { + + osalDbgCheckClassS(); + osalDbgCheck(ltdcp == <DCD1); + +#if (TRUE == CH_CFG_USE_MUTEXES) + chMtxUnlockS(<dcp->lock); +#else + chSemSignalI(<dcp->lock); +#endif +} + +/** + * @brief Releases exclusive access to the LTDC module. + * @pre In order to use this function the option + * @p LTDC_USE_MUTUAL_EXCLUSION must be enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcReleaseBus(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcReleaseBusS(ltdcp); + osalSysUnlock(); +} + +#endif /* LTDC_USE_MUTUAL_EXCLUSION */ + +/** @} */ + +/** + * @name LTDC global methods + * @{ + */ + +/** + * @brief Get enabled flags. + * @details Returns all the flags of the LTDC_EF_* group at once. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled flags + * + * @iclass + */ +ltdc_flags_t ltdcGetEnableFlagsI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return LTDC->GCR & LTDC_EF_MASK; +} + +/** + * @brief Get enabled flags. + * @details Returns all the flags of the LTDC_EF_* group at once. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled flags + * + * @api + */ +ltdc_flags_t ltdcGetEnableFlags(LTDCDriver *ltdcp) { + + ltdc_flags_t flags; + osalSysLock(); + flags = ltdcGetEnableFlagsI(ltdcp); + osalSysUnlock(); + return flags; +} + +/** + * @brief Set enabled flags. + * @details Sets all the flags of the LTDC_EF_* group at once. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] flags enabled flags + * + * @iclass + */ +void ltdcSetEnableFlagsI(LTDCDriver *ltdcp, ltdc_flags_t flags) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC->GCR = flags & LTDC_EF_MASK; +} + +/** + * @brief Set enabled flags. + * @details Sets all the flags of the LTDC_EF_* group at once. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] flags enabled flags + * + * @api + */ +void ltdcSetEnableFlags(LTDCDriver *ltdcp, ltdc_flags_t flags) { + + osalSysLock(); + ltdcSetEnableFlagsI(ltdcp, flags); + osalSysUnlock(); +} + +/** + * @brief Reloading shadow registers. + * @details Tells whether the LTDC is reloading shadow registers. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return reloading + * + * @iclass + */ +bool ltdcIsReloadingI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (LTDC->SRCR & (LTDC_SRCR_IMR | LTDC_SRCR_VBR)) != 0; +} + +/** + * @brief Reloading shadow registers. + * @details Tells whether the LTDC is reloading shadow registers. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return reloading + * + * @api + */ +bool ltdcIsReloading(LTDCDriver *ltdcp) { + + bool reloading; + osalSysLock(); + reloading = ltdcIsReloadingI(ltdcp); + osalSysUnlock(); + return reloading; +} + +/** + * @brief Reload shadow registers. + * @details Starts reloading LTDC shadow registers, upon vsync or immediately. + * @post At the end of the operation the configured callback is invoked. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] immediately reload immediately, not upon vsync + * + * @iclass + */ +void ltdcStartReloadI(LTDCDriver *ltdcp, bool immediately) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgAssert(ltdcp->state == LTDC_READY, "not ready"); + (void)ltdcp; + + ltdcp->state = LTDC_ACTIVE; + if (immediately) + LTDC->SRCR |= LTDC_SRCR_IMR; + else + LTDC->SRCR |= LTDC_SRCR_VBR; +} + +/** + * @brief Reload shadow registers. + * @details Starts reloading LTDC shadow registers, upon vsync or immediately. + * @post At the end of the operation the configured callback is invoked. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] immediately reload immediately, not upon vsync + * + * @api + */ +void ltdcStartReload(LTDCDriver *ltdcp, bool immediately) { + + osalSysLock(); + ltdcStartReloadI(ltdcp, immediately); + osalSysUnlock(); +} + +/** + * @brief Reload shadow registers. + * @details Reloads LTDC shadow registers, upon vsync or immediately. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] immediately reload immediately, not upon vsync + * + * @sclass + */ +void ltdcReloadS(LTDCDriver *ltdcp, bool immediately) { + + osalDbgCheckClassS(); + osalDbgCheck(ltdcp == <DCD1); + + ltdcStartReloadI(ltdcp, immediately); + +#if (TRUE == LTDC_USE_WAIT) + osalDbgAssert(ltdcp->thread == NULL, "already waiting"); + + if (immediately) { + while (LTDC->SRCR & LTDC_SRCR_IMR) + chSchDoYieldS(); + ltdcp->state = LTDC_READY; + } else { + ltdcp->thread = chThdGetSelfX(); + chSchGoSleepS(CH_STATE_SUSPENDED); + } +#else + while (LTDC->SRCR & LTDC_SRCR_IMR) + chSchDoYieldS(); + ltdcp->state = LTDC_READY; +#endif +} + +/** + * @brief Reload shadow registers. + * @details Reloads LTDC shadow registers, upon vsync or immediately. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] immediately reload immediately, not upon vsync + * + * @api + */ +void ltdcReload(LTDCDriver *ltdcp, bool immediately) { + + osalSysLock(); + ltdcReloadS(ltdcp, immediately); + osalSysUnlock(); +} + +/** + * @brief Dithering enabled. + * @details Tells whether the dithering is enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled + * + * @iclass + */ +bool ltdcIsDitheringEnabledI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (LTDC->GCR & LTDC_GCR_DTEN) != 0; +} + +/** + * @brief Dithering enabled. + * @details Tells whether the dithering is enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled + * + * @api + */ +bool ltdcIsDitheringEnabled(LTDCDriver *ltdcp) { + + bool enabled; + osalSysLock(); + enabled = ltdcIsDitheringEnabledI(ltdcp); + osalSysUnlock(); + return enabled; +} + +/** + * @brief Enable dithering. + * @details Enables dithering capabilities for pixel formats with less than + * 8 bits per channel. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcEnableDitheringI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC->GCR |= LTDC_GCR_DTEN; +} + +/** + * @brief Enable dithering. + * @details Enables dithering capabilities for pixel formats with less than + * 8 bits per channel. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcEnableDithering(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcEnableDitheringI(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Disable dithering. + * @details Disables dithering capabilities for pixel formats with less than + * 8 bits per channel. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcDisableDitheringI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC->GCR &= ~LTDC_GCR_DTEN; +} + +/** + * @brief Disable dithering. + * @details Disables dithering capabilities for pixel formats with less than + * 8 bits per channel. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcDisableDithering(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcDisableDitheringI(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Get clear screen color. + * @details Gets the clear screen (actual background) color. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return clear screen color, RGB-888 + * + * @iclass + */ +ltdc_color_t ltdcGetClearColorI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (ltdc_color_t)(LTDC->BCCR & 0x00FFFFFF); +} + +/** + * @brief Get clear screen color. + * @details Gets the clear screen (actual background) color. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return clear screen color, RGB-888 + * + * @api + */ +ltdc_color_t ltdcGetClearColor(LTDCDriver *ltdcp) { + + ltdc_color_t color; + osalSysLock(); + color = ltdcGetClearColorI(ltdcp); + osalSysUnlock(); + return color; +} + +/** + * @brief Set clear screen color. + * @details Sets the clear screen (actual background) color. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] c clear screen color, RGB-888 + * + * @iclass + */ +void ltdcSetClearColorI(LTDCDriver *ltdcp, ltdc_color_t c) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC->BCCR = (LTDC->BCCR & ~0x00FFFFFF) | (c & 0x00FFFFFF); +} + +/** + * @brief Set clear screen color. + * @details Sets the clear screen (actual background) color. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] c clear screen color, RGB-888 + * + * @api + */ +void ltdcSetClearColor(LTDCDriver *ltdcp, ltdc_color_t c) { + + osalSysLock(); + ltdcSetClearColorI(ltdcp, c); + osalSysUnlock(); +} + +/** + * @brief Get line interrupt position. + * @details Gets the line interrupt position. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return line interrupt position + * + * @iclass + */ +uint16_t ltdcGetLineInterruptPosI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (uint16_t)(LTDC->LIPCR & LTDC_LIPCR_LIPOS); +} + +/** + * @brief Get line interrupt position. + * @details Gets the line interrupt position. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return line interrupt position + * + * @api + */ +uint16_t ltdcGetLineInterruptPos(LTDCDriver *ltdcp) { + + uint16_t line; + osalSysLock(); + line = ltdcGetLineInterruptPosI(ltdcp); + osalSysUnlock(); + return line; +} + +/** + * @brief Set line interrupt position. + * @details Sets the line interrupt position. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcSetLineInterruptPosI(LTDCDriver *ltdcp, uint16_t line) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC->LIPCR = ((LTDC->LIPCR & ~LTDC_LIPCR_LIPOS) | + ((uint32_t)line & LTDC_LIPCR_LIPOS)); +} + +/** + * @brief Set line interrupt position. + * @details Sets the line interrupt position. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcSetLineInterruptPos(LTDCDriver *ltdcp, uint16_t line) { + + osalSysLock(); + ltdcSetLineInterruptPosI(ltdcp, line); + osalSysUnlock(); +} + +/** + * @brief Line interrupt enabled. + * @details Tells whether the line interrupt is enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled + * + * @iclass + */ +bool ltdcIsLineInterruptEnabledI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (LTDC->IER & LTDC_IER_LIE) != 0; +} + +/** + * @brief Line interrupt enabled. + * @details Tells whether the line interrupt is enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled + * + * @api + */ +bool ltdcIsLineInterruptEnabled(LTDCDriver *ltdcp) { + + bool enabled; + osalSysLock(); + enabled = ltdcIsLineInterruptEnabledI(ltdcp); + osalSysUnlock(); + return enabled; +} + +/** + * @brief Enable line interrupt. + * @details Enables line interrupt. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcEnableLineInterruptI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC->IER |= LTDC_IER_LIE; +} + +/** + * @brief Enable line interrupt. + * @details Enables line interrupt. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcEnableLineInterrupt(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcEnableLineInterruptI(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Disable line interrupt. + * @details Disables line interrupt. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcDisableLineInterruptI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC->IER &= ~LTDC_IER_LIE; +} + +/** + * @brief Disable line interrupt. + * @details Disables line interrupt. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcDisableLineInterrupt(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcDisableLineInterruptI(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Get current position. + * @details Gets the current position. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[out] xp pointer to the destination horizontal coordinate + * @param[out] yp pointer to the destination vertical coordinate + * + * @iclass + */ +void ltdcGetCurrentPosI(LTDCDriver *ltdcp, uint16_t *xp, uint16_t *yp) { + + const uint32_t r = LTDC->CPSR; + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + *xp = (uint16_t)((r & LTDC_CPSR_CXPOS) >> 16); + *yp = (uint16_t)((r & LTDC_CPSR_CYPOS) >> 0); +} + +/** + * @brief Get current position. + * @details Gets the current position. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[out] xp pointer to the destination horizontal coordinate + * @param[out] yp pointer to the destination vertical coordinate + * + * @api + */ +void ltdcGetCurrentPos(LTDCDriver *ltdcp, uint16_t *xp, uint16_t *yp) { + + osalSysLock(); + ltdcGetCurrentPosI(ltdcp, xp, yp); + osalSysUnlock(); +} + +/** @} */ + +/** + * @name LTDC background layer (layer 1) methods + * @{ + */ + +/** + * @brief Get background layer enabled flags. + * @details Returns all the flags of the LTDC_LEF_* group at once. + * Targeting the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled flags + * + * @iclass + */ +ltdc_flags_t ltdcBgGetEnableFlagsI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return LTDC_Layer1->CR & LTDC_LEF_MASK; +} + +/** + * @brief Get background layer enabled flags. + * @details Returns all the flags of the LTDC_LEF_* group at once. + * Targeting the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled flags + * + * @api + */ +ltdc_flags_t ltdcBgGetEnableFlags(LTDCDriver *ltdcp) { + + ltdc_flags_t flags; + osalSysLock(); + flags = ltdcBgGetEnableFlagsI(ltdcp); + osalSysUnlock(); + return flags; +} + +/** + * @brief Set background layer enabled flags. + * @details Sets all the flags of the LTDC_LEF_* group at once. + * Targeting the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] flags enabled flags + * + * @iclass + */ +void ltdcBgSetEnableFlagsI(LTDCDriver *ltdcp, ltdc_flags_t flags) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer1->CR = ((LTDC_Layer1->CR & ~LTDC_LEF_MASK) | + ((uint32_t)flags & LTDC_LEF_MASK)); +} + +/** + * @brief Set background layer enabled flags. + * @details Sets all the flags of the LTDC_LEF_* group at once. + * Targeting the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] flags enabled flags + * + * @api + */ +void ltdcBgSetEnableFlags(LTDCDriver *ltdcp, ltdc_flags_t flags) { + + osalSysLock(); + ltdcBgSetEnableFlagsI(ltdcp, flags); + osalSysUnlock(); +} + +/** + * @brief Background layer enabled. + * @details Tells whether the background layer (layer 1) is enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled + * + * @iclass + */ +bool ltdcBgIsEnabledI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (LTDC_Layer1->CR & ~LTDC_LxCR_LEN) != 0; +} + +/** + * @brief Background layer enabled. + * @details Tells whether the background layer (layer 1) is enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled + * + * @api + */ +bool ltdcBgIsEnabled(LTDCDriver *ltdcp) { + + bool enabled; + osalSysLock(); + enabled = ltdcBgIsEnabledI(ltdcp); + osalSysUnlock(); + return enabled; +} + +/** + * @brief Background layer enable. + * @details Enables the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcBgEnableI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer1->CR |= LTDC_LxCR_LEN; +} + +/** + * @brief Background layer enable. + * @details Enables the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcBgEnable(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcBgEnableI(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Background layer disable. + * @details Disables the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcBgDisableI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer1->CR &= ~LTDC_LxCR_LEN; +} + +/** + * @brief Background layer disable. + * @details Disables the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcBgDisable(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcBgDisableI(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Background layer palette enabled. + * @details Tells whether the background layer (layer 1) palette (color lookup + * table) is enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled + * + * @iclass + */ +bool ltdcBgIsPaletteEnabledI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (LTDC_Layer1->CR & ~LTDC_LxCR_CLUTEN) != 0; +} + +/** + * @brief Background layer palette enabled. + * @details Tells whether the background layer (layer 1) palette (color lookup + * table) is enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled + * + * @api + */ +bool ltdcBgIsPaletteEnabled(LTDCDriver *ltdcp) { + + bool enabled; + osalSysLock(); + enabled = ltdcBgIsPaletteEnabledI(ltdcp); + osalSysUnlock(); + return enabled; +} + +/** + * @brief Enable background layer palette. + * @details Enables the palette (color lookup table) of the background layer + * (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcBgEnablePaletteI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer1->CR |= LTDC_LxCR_CLUTEN; +} + +/** + * @brief Enable background layer palette. + * @details Enables the palette (color lookup table) of the background layer + * (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcBgEnablePalette(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcBgEnablePaletteI(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Disable background layer palette. + * @details Disables the palette (color lookup table) of the background layer + * (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcBgDisablePaletteI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer1->CR &= ~LTDC_LxCR_CLUTEN; +} + +/** + * @brief Disable background layer palette. + * @details Disables the palette (color lookup table) of the background layer + * (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcBgDisablePalette(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcBgDisablePaletteI(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Set background layer palette color. + * @details Sets the color of a palette (color lookup table) slot to the + * background layer (layer 1). + * @pre The layer must be disabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] slot palette slot + * @param[in] c color, RGB-888 + * + * @iclass + */ +void ltdcBgSetPaletteColorI(LTDCDriver *ltdcp, uint8_t slot, ltdc_color_t c) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgAssert(!ltdcBgIsEnabledI(ltdcp), "invalid state"); + (void)ltdcp; + + LTDC_Layer1->CLUTWR = (((uint32_t)slot << 24) | (c & 0x00FFFFFF)); +} + +/** + * @brief Set background layer palette color. + * @details Sets the color of a palette (color lookup table) slot to the + * background layer (layer 1). + * @pre The layer must be disabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] slot palette slot + * @param[in] c color, RGB-888 + * + * @api + */ +void ltdcBgSetPaletteColor(LTDCDriver *ltdcp, uint8_t slot, ltdc_color_t c) { + + osalSysLock(); + ltdcBgSetPaletteColorI(ltdcp, slot, c); + osalSysUnlock(); +} + +/** + * @brief Set background layer palette. + * @details Sets the entire palette color (color lookup table) slot. + * @pre The layer must be disabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] colors array of palette colors, RGB-888 + * @param[in] length number of palette colors + * + * @iclass + */ +void ltdcBgSetPaletteI(LTDCDriver *ltdcp, const ltdc_color_t colors[], + uint16_t length) { + + uint16_t i; + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgCheck((colors == NULL) == (length == 0)); + osalDbgAssert(length <= LTDC_MAX_PALETTE_LENGTH, "bounds"); + osalDbgAssert(!ltdcBgIsEnabledI(ltdcp), "invalid state"); + (void)ltdcp; + + for (i = 0; i < length; ++i) + LTDC_Layer1->CLUTWR = (((uint32_t)i << 24) | (colors[i] & 0x00FFFFFF)); +} + +/** + * @brief Set background layer palette. + * @details Sets the entire palette color (color lookup table) slot. + * @pre The layer must be disabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] colors array of palette colors, RGB-888 + * @param[in] length number of palette colors + * + * @api + */ +void ltdcBgSetPalette(LTDCDriver *ltdcp, const ltdc_color_t colors[], + uint16_t length) { + + osalSysLock(); + ltdcBgSetPaletteI(ltdcp, colors, length); + osalSysUnlock(); +} + +/** + * @brief Get background layer pixel format. + * @details Gets the pixel format of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return pixel format + * + * @iclass + */ +ltdc_pixfmt_t ltdcBgGetPixelFormatI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (ltdc_pixfmt_t)(LTDC_Layer1->PFCR & LTDC_LxPFCR_PF); +} + +/** + * @brief Get background layer pixel format. + * @details Gets the pixel format of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return pixel format + * + * @api + */ +ltdc_pixfmt_t ltdcBgGetPixelFormat(LTDCDriver *ltdcp) { + + ltdc_pixfmt_t fmt; + osalSysLock(); + fmt = ltdcBgGetPixelFormatI(ltdcp); + osalSysUnlock(); + return fmt; +} + +/** + * @brief Set background layer pixel format. + * @details Sets the pixel format of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] fmt pixel format + * + * @iclass + */ +void ltdcBgSetPixelFormatI(LTDCDriver *ltdcp, ltdc_pixfmt_t fmt) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgAssert(fmt >= LTDC_MIN_PIXFMT_ID, "bounds"); + osalDbgAssert(fmt <= LTDC_MAX_PIXFMT_ID, "bounds"); + (void)ltdcp; + + LTDC_Layer1->PFCR = ((LTDC_Layer1->PFCR & ~LTDC_LxPFCR_PF) | + ((uint32_t)fmt & LTDC_LxPFCR_PF)); +} + +/** + * @brief Set background layer pixel format. + * @details Sets the pixel format of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] fmt pixel format + * + * @api + */ +void ltdcBgSetPixelFormat(LTDCDriver *ltdcp, ltdc_pixfmt_t fmt) { + + osalSysLock(); + ltdcBgSetPixelFormatI(ltdcp, fmt); + osalSysUnlock(); +} + +/** + * @brief Background layer color keying enabled. + * @details Tells whether the background layer (layer 1) has color keying + * enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled + * + * @iclass + */ +bool ltdcBgIsKeyingEnabledI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (LTDC_Layer1->CR & ~LTDC_LxCR_COLKEN) != 0; +} + +/** + * @brief Background layer color keying enabled. + * @details Tells whether the background layer (layer 1) has color keying + * enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled + * + * @api + */ +bool ltdcBgIsKeyingEnabled(LTDCDriver *ltdcp) { + + bool enabled; + osalSysLock(); + enabled = ltdcBgIsKeyingEnabledI(ltdcp); + osalSysUnlock(); + return enabled; +} + +/** + * @brief Enable background layer color keying. + * @details Enables color keying capabilities of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcBgEnableKeyingI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer1->CR |= LTDC_LxCR_COLKEN; +} + +/** + * @brief Enable background layer color keying. + * @details Enables color keying capabilities of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcBgEnableKeying(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcBgEnableKeyingI(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Disable background layer color keying. + * @details Disables color keying capabilities of the background layer (layer + * 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcBgDisableKeyingI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer1->CR &= ~LTDC_LxCR_COLKEN; +} + +/** + * @brief Disable background layer color keying. + * @details Disables color keying capabilities of the background layer (layer + * 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcBgDisableKeying(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcBgDisableKeyingI(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Get background layer color key. + * @details Gets the color key of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return color key, RGB-888 + * + * @iclass + */ +ltdc_color_t ltdcBgGetKeyingColorI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (ltdc_color_t)(LTDC_Layer1->CKCR & 0x00FFFFFF); +} + +/** + * @brief Get background layer color key. + * @details Gets the color key of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return color key, RGB-888 + * + * @api + */ +ltdc_color_t ltdcBgGetKeyingColor(LTDCDriver *ltdcp) { + + ltdc_color_t color; + osalSysLock(); + color = ltdcBgGetKeyingColorI(ltdcp); + osalSysUnlock(); + return color; +} + +/** + * @brief Set background layer color key. + * @details Sets the color key of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] c color key, RGB-888 + * + * @iclass + */ +void ltdcBgSetKeyingColorI(LTDCDriver *ltdcp, ltdc_color_t c) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer1->CKCR = ((LTDC_Layer1->CKCR & ~0x00FFFFFF) | + ((uint32_t)c & 0x00FFFFFF)); +} + +/** + * @brief Set background layer color key. + * @details Sets the color key of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] c color key, RGB-888 + * + * @api + */ +void ltdcBgSetKeyingColor(LTDCDriver *ltdcp, ltdc_color_t c) { + + osalSysLock(); + ltdcBgSetKeyingColorI(ltdcp, c); + osalSysUnlock(); +} + +/** + * @brief Get background layer constant alpha. + * @details Gets the constant alpha component of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return constant alpha component, A-8 + * + * @iclass + */ +uint8_t ltdcBgGetConstantAlphaI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (uint8_t)(LTDC_Layer1->CACR & LTDC_LxCACR_CONSTA); +} + +/** + * @brief Get background layer constant alpha. + * @details Gets the constant alpha component of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return constant alpha component, A-8 + * + * @api + */ +uint8_t ltdcBgGetConstantAlpha(LTDCDriver *ltdcp) { + + uint8_t a; + osalSysLock(); + a = ltdcBgGetConstantAlphaI(ltdcp); + osalSysUnlock(); + return a; +} + +/** + * @brief Set background layer constant alpha. + * @details Sets the constant alpha component of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] a constant alpha component, A-8 + * + * @iclass + */ +void ltdcBgSetConstantAlphaI(LTDCDriver *ltdcp, uint8_t a) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer1->CACR = ((LTDC_Layer1->CACR & ~LTDC_LxCACR_CONSTA) | + ((uint32_t)a & LTDC_LxCACR_CONSTA)); +} + +/** + * @brief Set background layer constant alpha. + * @details Sets the constant alpha component of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] a constant alpha component, A-8 + * + * @api + */ +void ltdcBgSetConstantAlpha(LTDCDriver *ltdcp, uint8_t a) { + + osalSysLock(); + ltdcBgSetConstantAlphaI(ltdcp, a); + osalSysUnlock(); +} + +/** + * @brief Get background layer default color. + * @details Gets the default color of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return default color, RGB-888 + * + * @iclass + */ +ltdc_color_t ltdcBgGetDefaultColorI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (ltdc_color_t)LTDC_Layer1->DCCR; +} + +/** + * @brief Get background layer default color. + * @details Gets the default color of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return default color, RGB-888 + * + * @api + */ +ltdc_color_t ltdcBgGetDefaultColor(LTDCDriver *ltdcp) { + + ltdc_color_t color; + osalSysLock(); + color = ltdcBgGetDefaultColorI(ltdcp); + osalSysUnlock(); + return color; +} + +/** + * @brief Set background layer default color. + * @details Sets the default color of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] c default color, RGB-888 + * + * @iclass + */ +void ltdcBgSetDefaultColorI(LTDCDriver *ltdcp, ltdc_color_t c) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer1->DCCR = (uint32_t)c; +} + +/** + * @brief Set background layer default color. + * @details Sets the default color of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] c default color, RGB-888 + * + * @api + */ +void ltdcBgSetDefaultColor(LTDCDriver *ltdcp, ltdc_color_t c) { + + osalSysLock(); + ltdcBgSetDefaultColorI(ltdcp, c); + osalSysUnlock(); +} + +/** + * @brief Get background layer blending factors. + * @details Gets the blending factors of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return blending factors + * + * @iclass + */ +ltdc_blendf_t ltdcBgGetBlendingFactorsI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (ltdc_blendf_t)(LTDC_Layer1->BFCR & LTDC_LxBFCR_BF); +} + +/** + * @brief Get background layer blending factors. + * @details Gets the blending factors of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return blending factors + * + * @api + */ +ltdc_blendf_t ltdcBgGetBlendingFactors(LTDCDriver *ltdcp) { + + ltdc_blendf_t bf; + osalSysLock(); + bf = ltdcBgGetBlendingFactorsI(ltdcp); + osalSysUnlock(); + return bf; +} + +/** + * @brief Set background layer blending factors. + * @details Sets the blending factors of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] factors blending factors + * + * @iclass + */ +void ltdcBgSetBlendingFactorsI(LTDCDriver *ltdcp, ltdc_blendf_t bf) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer1->BFCR = ((LTDC_Layer1->BFCR & ~LTDC_LxBFCR_BF) | + ((uint32_t)bf & LTDC_LxBFCR_BF)); +} + +/** + * @brief Set background layer blending factors. + * @details Sets the blending factors of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] factors blending factors + * + * @api + */ +void ltdcBgSetBlendingFactors(LTDCDriver *ltdcp, ltdc_blendf_t bf) { + + osalSysLock(); + ltdcBgSetBlendingFactorsI(ltdcp, bf); + osalSysUnlock(); +} + +/** + * @brief Get background layer window specs. + * @details Gets the window specifications of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[out] windowp pointer to the window specifications + * + * @iclass + */ +void ltdcBgGetWindowI(LTDCDriver *ltdcp, ltdc_window_t *windowp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgCheck(windowp != NULL); + (void)ltdcp; + + windowp->hstart = + (uint16_t)((LTDC_Layer1->WHPCR & LTDC_LxWHPCR_WHSTPOS) >> 0); + windowp->hstop = + (uint16_t)((LTDC_Layer1->WHPCR & LTDC_LxWHPCR_WHSPPOS) >> 16); + windowp->vstart = + (uint16_t)((LTDC_Layer1->WVPCR & LTDC_LxWVPCR_WVSTPOS) >> 0); + windowp->vstop = + (uint16_t)((LTDC_Layer1->WVPCR & LTDC_LxWVPCR_WVSPPOS) >> 16); +} + +/** + * @brief Get background layer window specs. + * @details Gets the window specifications of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[out] windowp pointer to the window specifications + * + * @api + */ +void ltdcBgGetWindow(LTDCDriver *ltdcp, ltdc_window_t *windowp) { + + osalSysLock(); + ltdcBgGetWindowI(ltdcp, windowp); + osalSysUnlock(); +} + +/** + * @brief Set background layer window specs. + * @details Sets the window specifications of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] windowp pointer to the window specifications + * + * @iclass + */ +void ltdcBgSetWindowI(LTDCDriver *ltdcp, const ltdc_window_t *windowp) { + + uint32_t start, stop; + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgCheck(windowp != NULL); + (void)ltdcp; + + osalDbgAssert(windowp->hstop < ltdcp->config->screen_width, "bounds"); + osalDbgAssert(windowp->vstop < ltdcp->config->screen_height, "bounds"); + + /* Horizontal boundaries.*/ + start = (uint32_t)windowp->hstart + ltdcp->active_window.hstart; + stop = (uint32_t)windowp->hstop + ltdcp->active_window.hstart; + + osalDbgAssert(start >= ltdcp->active_window.hstart, "bounds"); + osalDbgAssert(stop <= ltdcp->active_window.hstop, "bounds"); + + LTDC_Layer1->WHPCR = (((start << 0) & LTDC_LxWHPCR_WHSTPOS) | + ((stop << 16) & LTDC_LxWHPCR_WHSPPOS)); + + /* Vertical boundaries.*/ + start = (uint32_t)windowp->vstart + ltdcp->active_window.vstart; + stop = (uint32_t)windowp->vstop + ltdcp->active_window.vstart; + + osalDbgAssert(start >= ltdcp->active_window.vstart, "bounds"); + osalDbgAssert(stop <= ltdcp->active_window.vstop, "bounds"); + + LTDC_Layer1->WVPCR = (((start << 0) & LTDC_LxWVPCR_WVSTPOS) | + ((stop << 16) & LTDC_LxWVPCR_WVSPPOS)); +} + +/** + * @brief Set background layer window specs. + * @details Sets the window specifications of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] windowp pointer to the window specifications + * + * @api + */ +void ltdcBgSetWindow(LTDCDriver *ltdcp, const ltdc_window_t *windowp) { + + osalSysLock(); + ltdcBgSetWindowI(ltdcp, windowp); + osalSysUnlock(); +} + +/** + * @brief Set background layer window as invalid. + * @details Sets the window specifications of the background layer (layer 1) + * so that the window is pixel sized at the screen origin. + * @note Useful before reconfiguring the frame specifications of the layer, + * to avoid errors. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcBgSetInvalidWindowI(LTDCDriver *ltdcp) { + + ltdcBgSetWindowI(ltdcp, <dc_invalid_window); +} + +/** + * @brief Set background layer window as invalid. + * @details Sets the window specifications of the background layer (layer 1) + * so that the window is pixel sized at the screen origin. + * @note Useful before reconfiguring the frame specifications of the layer, + * to avoid errors. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcBgSetInvalidWindow(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcBgSetWindowI(ltdcp, <dc_invalid_window); + osalSysUnlock(); +} + +/** + * @brief Get background layer frame buffer specs. + * @details Gets the frame buffer specifications of the background layer + * (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[out] framep pointer to the frame buffer specifications + * + * @iclass + */ +void ltdcBgGetFrameI(LTDCDriver *ltdcp, ltdc_frame_t *framep) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgCheck(framep != NULL); + + framep->bufferp = (void *)(LTDC_Layer1->CFBAR & LTDC_LxCFBAR_CFBADD); + framep->pitch = (size_t)((LTDC_Layer1->CFBLR & LTDC_LxCFBLR_CFBP) >> 16); + framep->width = (uint16_t)(((LTDC_Layer1->CFBLR & LTDC_LxCFBLR_CFBLL) - 3) / + ltdcBytesPerPixel(ltdcBgGetPixelFormatI(ltdcp))); + framep->height = (uint16_t)(LTDC_Layer1->CFBLNR & LTDC_LxCFBLNR_CFBLNBR); +} + +/** + * @brief Get background layer frame buffer specs. + * @details Gets the frame buffer specifications of the background layer + * (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[out] framep pointer to the frame buffer specifications + * + * @api + */ +void ltdcBgGetFrame(LTDCDriver *ltdcp, ltdc_frame_t *framep) { + + osalSysLock(); + ltdcBgGetFrameI(ltdcp, framep); + osalSysUnlock(); +} + +/** + * @brief Set background layer frame buffer specs. + * @details Sets the frame buffer specifications of the background layer + * (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] framep pointer to the frame buffer specifications + * + * @iclass + */ +void ltdcBgSetFrameI(LTDCDriver *ltdcp, const ltdc_frame_t *framep) { + + size_t linesize; + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgCheck(framep != NULL); + + ltdcBgSetPixelFormatI(ltdcp, framep->fmt); + + linesize = ltdcBytesPerPixel(framep->fmt) * framep->width; + + osalDbgAssert(framep->width <= ltdcp->config->screen_width, "bounds"); + osalDbgAssert(framep->height <= ltdcp->config->screen_height, "bounds"); + osalDbgAssert(linesize >= LTDC_MIN_FRAME_WIDTH_BYTES, "bounds"); + osalDbgAssert(linesize <= LTDC_MAX_FRAME_WIDTH_BYTES, "bounds"); + osalDbgAssert(framep->height >= LTDC_MIN_FRAME_HEIGHT_LINES, "bounds"); + osalDbgAssert(framep->height <= LTDC_MAX_FRAME_HEIGHT_LINES, "bounds"); + osalDbgAssert(framep->pitch >= linesize, "bounds"); + + LTDC_Layer1->CFBAR = (uint32_t)framep->bufferp & LTDC_LxCFBAR_CFBADD; + LTDC_Layer1->CFBLR = ((((uint32_t)framep->pitch << 16) & LTDC_LxCFBLR_CFBP) | + ((linesize + 3) & LTDC_LxCFBLR_CFBLL)); + LTDC_Layer1->CFBLNR = (uint32_t)framep->height & LTDC_LxCFBLNR_CFBLNBR; +} + +/** + * @brief Set background layer frame buffer specs. + * @details Sets the frame buffer specifications of the background layer + * (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] framep pointer to the frame buffer specifications + * + * @api + */ +void ltdcBgSetFrame(LTDCDriver *ltdcp, const ltdc_frame_t *framep) { + + osalSysLock(); + ltdcBgSetFrameI(ltdcp, framep); + osalSysUnlock(); +} + +/** + * @brief Get background layer frame buffer address. + * @details Gets the frame buffer address of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return frame buffer address + * + * @iclass + */ +void *ltdcBgGetFrameAddressI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (void *)LTDC_Layer1->CFBAR; +} + +/** + * @brief Get background layer frame buffer address. + * @details Gets the frame buffer address of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return frame buffer address + * + * @api + */ +void *ltdcBgGetFrameAddress(LTDCDriver *ltdcp) { + + void *bufferp; + osalSysLock(); + bufferp = ltdcBgGetFrameAddressI(ltdcp); + osalSysUnlock(); + return bufferp; +} + +/** + * @brief Set background layer frame buffer address. + * @details Sets the frame buffer address of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] bufferp frame buffer address + * + * @iclass + */ +void ltdcBgSetFrameAddressI(LTDCDriver *ltdcp, void *bufferp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer1->CFBAR = (uint32_t)bufferp; +} + +/** + * @brief Set background layer frame buffer address. + * @details Sets the frame buffer address of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] bufferp frame buffer address + * + * @api + */ +void ltdcBgSetFrameAddress(LTDCDriver *ltdcp, void *bufferp) { + + osalSysLock(); + ltdcBgSetFrameAddressI(ltdcp, bufferp); + osalSysUnlock(); +} + +/** + * @brief Get background layer specifications. + * @details Gets the background layer (layer 1) specifications at once. + * @note If palette specifications cannot be retrieved, they are set to + * @p NULL. This is not an error. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[out] cfgp pointer to the layer specifications + * + * @iclass + */ +void ltdcBgGetLayerI(LTDCDriver *ltdcp, ltdc_laycfg_t *cfgp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgCheck(cfgp != NULL); + + ltdcBgGetFrameI(ltdcp, (ltdc_frame_t *)cfgp->frame); + ltdcBgGetWindowI(ltdcp, (ltdc_window_t *)cfgp->window); + cfgp->def_color = ltdcBgGetDefaultColorI(ltdcp); + cfgp->key_color = ltdcBgGetKeyingColorI(ltdcp); + cfgp->const_alpha = ltdcBgGetConstantAlphaI(ltdcp); + cfgp->blending = ltdcBgGetBlendingFactorsI(ltdcp); + + cfgp->pal_colors = NULL; + cfgp->pal_length = 0; + + cfgp->flags = ltdcBgGetEnableFlagsI(ltdcp); +} + +/** + * @brief Get background layer specifications. + * @details Gets the background layer (layer 1) specifications at once. + * @note If palette specifications cannot be retrieved, they are set to + * @p NULL. This is not an error. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[out] cfgp pointer to the layer specifications + * + * @api + */ +void ltdcBgGetLayer(LTDCDriver *ltdcp, ltdc_laycfg_t *cfgp) { + + osalSysLock(); + ltdcBgGetLayerI(ltdcp, cfgp); + osalSysUnlock(); +} + +/** + * @brief Set background layer specifications. + * @details Sets the background layer (layer 1) specifications at once. + * @note If the palette is unspecified, the layer palette is unmodified. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] cfgp pointer to the layer specifications + * + * @iclass + */ +void ltdcBgSetConfigI(LTDCDriver *ltdcp, const ltdc_laycfg_t *cfgp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + + if (cfgp == NULL) + cfgp = <dc_default_laycfg; + + osalDbgCheck((cfgp->pal_colors == NULL) == (cfgp->pal_length == 0)); + + ltdcBgSetFrameI(ltdcp, cfgp->frame); + ltdcBgSetWindowI(ltdcp, cfgp->window); + ltdcBgSetDefaultColorI(ltdcp, cfgp->def_color); + ltdcBgSetKeyingColorI(ltdcp, cfgp->key_color); + ltdcBgSetConstantAlphaI(ltdcp, cfgp->const_alpha); + ltdcBgSetBlendingFactorsI(ltdcp, cfgp->blending); + + if (cfgp->pal_length > 0) + ltdcBgSetPaletteI(ltdcp, cfgp->pal_colors, cfgp->pal_length); + + ltdcBgSetEnableFlagsI(ltdcp, cfgp->flags); +} + +/** + * @brief Set background layer specifications. + * @details Sets the background layer (layer 1) specifications at once. + * @note If the palette is unspecified, the layer palette is unmodified. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] cfgp pointer to the layer specifications + * + * @api + */ +void ltdcBgSetConfig(LTDCDriver *ltdcp, const ltdc_laycfg_t *cfgp) { + + osalSysLock(); + ltdcBgSetConfigI(ltdcp, cfgp); + osalSysUnlock(); +} + +/** @} */ + +/** + * @name LTDC foreground layer (layer 2) methods + * @{ + */ + +/** + * @brief Get foreground layer enabled flags. + * @details Returns all the flags of the LTDC_LEF_* group at once. + * Targeting the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled flags + * + * @iclass + */ +ltdc_flags_t ltdcFgGetEnableFlagsI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return LTDC_Layer2->CR & LTDC_LEF_MASK; +} + +/** + * @brief Get foreground layer enabled flags. + * @details Returns all the flags of the LTDC_LEF_* group at once. + * Targeting the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled flags + * + * @api + */ +ltdc_flags_t ltdcFgGetEnableFlags(LTDCDriver *ltdcp) { + + ltdc_flags_t flags; + osalSysLock(); + flags = ltdcFgGetEnableFlagsI(ltdcp); + osalSysUnlock(); + return flags; +} + +/** + * @brief Set foreground layer enabled flags. + * @details Sets all the flags of the LTDC_LEF_* group at once. + * Targeting the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] flags enabled flags + * + * @iclass + */ +void ltdcFgSetEnableFlagsI(LTDCDriver *ltdcp, ltdc_flags_t flags) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer2->CR = ((LTDC_Layer2->CR & ~LTDC_LEF_MASK) | + ((uint32_t)flags & LTDC_LEF_MASK)); +} + +/** + * @brief Set foreground layer enabled flags. + * @details Sets all the flags of the LTDC_LEF_* group at once. + * Targeting the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] flags enabled flags + * + * @api + */ +void ltdcFgSetEnableFlags(LTDCDriver *ltdcp, ltdc_flags_t flags) { + + osalSysLock(); + ltdcFgSetEnableFlagsI(ltdcp, flags); + osalSysUnlock(); +} + +/** + * @brief Foreground layer enabled. + * @details Tells whether the foreground layer (layer 2) is enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled + * + * @iclass + */ +bool ltdcFgIsEnabledI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (LTDC_Layer2->CR & ~LTDC_LxCR_LEN) != 0; +} + +/** + * @brief Foreground layer enabled. + * @details Tells whether the foreground layer (layer 2) is enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled + * + * @api + */ +bool ltdcFgIsEnabled(LTDCDriver *ltdcp) { + + bool enabled; + osalSysLock(); + enabled = ltdcFgIsEnabledI(ltdcp); + osalSysUnlock(); + return enabled; +} + +/** + * @brief Foreground layer enable. + * @details Enables the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcFgEnableI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer2->CR |= LTDC_LxCR_LEN; +} + +/** + * @brief Foreground layer enable. + * @details Enables the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcFgEnable(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcFgEnableI(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Foreground layer disable. + * @details Disables the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcFgDisableI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer2->CR &= ~LTDC_LxCR_LEN; +} + +/** + * @brief Foreground layer disable. + * @details Disables the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcFgDisable(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcFgDisableI(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Foreground layer palette enabled. + * @details Tells whether the foreground layer (layer 2) palette (color lookup + * table) is enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled + * + * @iclass + */ +bool ltdcFgIsPaletteEnabledI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (LTDC_Layer2->CR & ~LTDC_LxCR_CLUTEN) != 0; +} + +/** + * @brief Foreground layer palette enabled. + * @details Tells whether the foreground layer (layer 2) palette (color lookup + * table) is enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled + * + * @api + */ +bool ltdcFgIsPaletteEnabled(LTDCDriver *ltdcp) { + + bool enabled; + osalSysLock(); + enabled = ltdcFgIsPaletteEnabledI(ltdcp); + osalSysUnlock(); + return enabled; +} + +/** + * @brief Enable foreground layer palette. + * @details Enables the palette (color lookup table) of the foreground layer + * (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcFgEnablePaletteI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer2->CR |= LTDC_LxCR_CLUTEN; +} + +/** + * @brief Enable foreground layer palette. + * @details Enables the palette (color lookup table) of the foreground layer + * (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcFgEnablePalette(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcFgEnablePaletteI(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Disable foreground layer palette. + * @details Disables the palette (color lookup table) of the foreground layer + * (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcFgDisablePaletteI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer2->CR &= ~LTDC_LxCR_CLUTEN; +} + +/** + * @brief Disable foreground layer palette. + * @details Disables the palette (color lookup table) of the foreground layer + * (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcFgDisablePalette(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcFgDisablePaletteI(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Set foreground layer palette color. + * @details Sets the color of a palette (color lookup table) slot to the + * foreground layer (layer 2). + * @pre The layer must be disabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] slot palette slot + * @param[in] c color, RGB-888 + * + * @iclass + */ +void ltdcFgSetPaletteColorI(LTDCDriver *ltdcp, uint8_t slot, ltdc_color_t c) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgAssert(!ltdcFgIsEnabledI(ltdcp), "invalid state"); + (void)ltdcp; + + LTDC_Layer2->CLUTWR = (((uint32_t)slot << 24) | (c & 0x00FFFFFF)); +} + +/** + * @brief Set foreground layer palette color. + * @details Sets the color of a palette (color lookup table) slot to the + * foreground layer (layer 2). + * @pre The layer must be disabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] slot palette slot + * @param[in] c color, RGB-888 + * + * @api + */ +void ltdcFgSetPaletteColor(LTDCDriver *ltdcp, uint8_t slot, ltdc_color_t c) { + + osalSysLock(); + ltdcFgSetPaletteColorI(ltdcp, slot, c); + osalSysUnlock(); +} + +/** + * @brief Set foreground layer palette. + * @details Sets the entire palette color (color lookup table) slot. + * @pre The layer must be disabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] colors array of palette colors, RGB-888 + * @param[in] length number of palette colors + * + * @iclass + */ +void ltdcFgSetPaletteI(LTDCDriver *ltdcp, const ltdc_color_t colors[], + uint16_t length) { + + uint16_t i; + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgCheck((colors == NULL) == (length == 0)); + osalDbgAssert(length <= LTDC_MAX_PALETTE_LENGTH, "bounds"); + osalDbgAssert(!ltdcFgIsEnabledI(ltdcp), "invalid state"); + (void)ltdcp; + + for (i = 0; i < length; ++i) + LTDC_Layer2->CLUTWR = (((uint32_t)i << 24) | (colors[i] & 0x00FFFFFF)); +} + +/** + * @brief Set foreground layer palette. + * @details Sets the entire palette color (color lookup table) slot. + * @pre The layer must be disabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] colors array of palette colors, RGB-888 + * @param[in] length number of palette colors + * + * @api + */ +void ltdcFgSetPalette(LTDCDriver *ltdcp, const ltdc_color_t colors[], + uint16_t length) { + + osalSysLock(); + ltdcFgSetPaletteI(ltdcp, colors, length); + osalSysUnlock(); +} + +/** + * @brief Get foreground layer pixel format. + * @details Gets the pixel format of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return pixel format + * + * @iclass + */ +ltdc_pixfmt_t ltdcFgGetPixelFormatI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (ltdc_pixfmt_t)(LTDC_Layer2->PFCR & LTDC_LxPFCR_PF); +} + +/** + * @brief Get foreground layer pixel format. + * @details Gets the pixel format of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return pixel format + * + * @api + */ +ltdc_pixfmt_t ltdcFgGetPixelFormat(LTDCDriver *ltdcp) { + + ltdc_pixfmt_t fmt; + osalSysLock(); + fmt = ltdcFgGetPixelFormatI(ltdcp); + osalSysUnlock(); + return fmt; +} + +/** + * @brief Set foreground layer pixel format. + * @details Sets the pixel format of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] fmt pixel format + * + * @iclass + */ +void ltdcFgSetPixelFormatI(LTDCDriver *ltdcp, ltdc_pixfmt_t fmt) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgAssert(fmt >= LTDC_MIN_PIXFMT_ID, "bounds"); + osalDbgAssert(fmt <= LTDC_MAX_PIXFMT_ID, "bounds"); + (void)ltdcp; + + LTDC_Layer2->PFCR = ((LTDC_Layer2->PFCR & ~LTDC_LxPFCR_PF) | + ((uint32_t)fmt & LTDC_LxPFCR_PF)); +} + +/** + * @brief Set foreground layer pixel format. + * @details Sets the pixel format of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] fmt pixel format + * + * @api + */ +void ltdcFgSetPixelFormat(LTDCDriver *ltdcp, ltdc_pixfmt_t fmt) { + + osalSysLock(); + ltdcFgSetPixelFormatI(ltdcp, fmt); + osalSysUnlock(); +} + +/** + * @brief Foreground layer color keying enabled. + * @details Tells whether the foreground layer (layer 2) has color keying + * enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled + * + * @iclass + */ +bool ltdcFgIsKeyingEnabledI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (LTDC_Layer2->CR & ~LTDC_LxCR_COLKEN) != 0; +} + +/** + * @brief Foreground layer color keying enabled. + * @details Tells whether the foreground layer (layer 2) has color keying + * enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled + * + * @api + */ +bool ltdcFgIsKeyingEnabled(LTDCDriver *ltdcp) { + + bool enabled; + osalSysLock(); + enabled = ltdcFgIsKeyingEnabledI(ltdcp); + osalSysUnlock(); + return enabled; +} + +/** + * @brief Enable foreground layer color keying. + * @details Enables color keying capabilities of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcFgEnableKeyingI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer2->CR |= LTDC_LxCR_COLKEN; +} + +/** + * @brief Enable foreground layer color keying. + * @details Enables color keying capabilities of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcFgEnableKeying(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcFgEnableKeyingI(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Disable foreground layer color keying. + * @details Disables color keying capabilities of the foreground layer (layer + * 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcFgDisableKeyingI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer2->CR &= ~LTDC_LxCR_COLKEN; +} + +/** + * @brief Disable foreground layer color keying. + * @details Disables color keying capabilities of the foreground layer (layer + * 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcFgDisableKeying(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcFgDisableKeyingI(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Get foreground layer color key. + * @details Gets the color key of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return color key, RGB-888 + * + * @iclass + */ +ltdc_color_t ltdcFgGetKeyingColorI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (ltdc_color_t)(LTDC_Layer2->CKCR & 0x00FFFFFF); +} + +/** + * @brief Get foreground layer color key. + * @details Gets the color key of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return color key, RGB-888 + * + * @api + */ +ltdc_color_t ltdcFgGetKeyingColor(LTDCDriver *ltdcp) { + + ltdc_color_t color; + osalSysLock(); + color = ltdcFgGetKeyingColorI(ltdcp); + osalSysUnlock(); + return color; +} + +/** + * @brief Set foreground layer color key. + * @details Sets the color key of the foreground layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] c color key, RGB-888 + * + * @iclass + */ +void ltdcFgSetKeyingColorI(LTDCDriver *ltdcp, ltdc_color_t c) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer2->CKCR = ((LTDC_Layer2->CKCR & ~0x00FFFFFF) | + ((uint32_t)c & 0x00FFFFFF)); +} + +/** + * @brief Set foreground layer color key. + * @details Sets the color key of the foreground layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] c color key, RGB-888 + * + * @api + */ +void ltdcFgSetKeyingColor(LTDCDriver *ltdcp, ltdc_color_t c) { + + osalSysLock(); + ltdcFgSetKeyingColorI(ltdcp, c); + osalSysUnlock(); +} + +/** + * @brief Get foreground layer constant alpha. + * @details Gets the constant alpha component of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return constant alpha component, A-8 + * + * @iclass + */ +uint8_t ltdcFgGetConstantAlphaI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (uint8_t)(LTDC_Layer2->CACR & LTDC_LxCACR_CONSTA); +} + +/** + * @brief Get foreground layer constant alpha. + * @details Gets the constant alpha component of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return constant alpha component, A-8 + * + * @api + */ +uint8_t ltdcFgGetConstantAlpha(LTDCDriver *ltdcp) { + + uint8_t a; + osalSysLock(); + a = ltdcFgGetConstantAlphaI(ltdcp); + osalSysUnlock(); + return a; +} + +/** + * @brief Set foreground layer constant alpha. + * @details Sets the constant alpha component of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] a constant alpha component, A-8 + * + * @iclass + */ +void ltdcFgSetConstantAlphaI(LTDCDriver *ltdcp, uint8_t a) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer2->CACR = ((LTDC_Layer2->CACR & ~LTDC_LxCACR_CONSTA) | + ((uint32_t)a & LTDC_LxCACR_CONSTA)); +} + +/** + * @brief Set foreground layer constant alpha. + * @details Sets the constant alpha component of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] a constant alpha component, A-8 + * + * @api + */ +void ltdcFgSetConstantAlpha(LTDCDriver *ltdcp, uint8_t a) { + + osalSysLock(); + ltdcFgSetConstantAlphaI(ltdcp, a); + osalSysUnlock(); +} + +/** + * @brief Get foreground layer default color. + * @details Gets the default color of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return default color, RGB-888 + * + * @iclass + */ +ltdc_color_t ltdcFgGetDefaultColorI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (ltdc_color_t)LTDC_Layer2->DCCR; +} + +/** + * @brief Get foreground layer default color. + * @details Gets the default color of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return default color, RGB-888 + * + * @api + */ +ltdc_color_t ltdcFgGetDefaultColor(LTDCDriver *ltdcp) { + + ltdc_color_t color; + osalSysLock(); + color = ltdcFgGetDefaultColorI(ltdcp); + osalSysUnlock(); + return color; +} + +/** + * @brief Set foreground layer default color. + * @details Sets the default color of the foreground layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] c default color, RGB-888 + * + * @iclass + */ +void ltdcFgSetDefaultColorI(LTDCDriver *ltdcp, ltdc_color_t c) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer2->DCCR = (uint32_t)c; +} + +/** + * @brief Set foreground layer default color. + * @details Sets the default color of the foreground layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] c default color, RGB-888 + * + * @api + */ +void ltdcFgSetDefaultColor(LTDCDriver *ltdcp, ltdc_color_t c) { + + osalSysLock(); + ltdcFgSetDefaultColorI(ltdcp, c); + osalSysUnlock(); +} + +/** + * @brief Get foreground layer blending factors. + * @details Gets the blending factors of the foreground layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return blending factors + * + * @iclass + */ +ltdc_blendf_t ltdcFgGetBlendingFactorsI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (ltdc_blendf_t)(LTDC_Layer2->BFCR & LTDC_LxBFCR_BF); +} + +/** + * @brief Get foreground layer blending factors. + * @details Gets the blending factors of the foreground layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return blending factors + * + * @api + */ +ltdc_blendf_t ltdcFgGetBlendingFactors(LTDCDriver *ltdcp) { + + ltdc_blendf_t bf; + osalSysLock(); + bf = ltdcFgGetBlendingFactorsI(ltdcp); + osalSysUnlock(); + return bf; +} + +/** + * @brief Set foreground layer blending factors. + * @details Sets the blending factors of the foreground layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] factors blending factors + * + * @iclass + */ +void ltdcFgSetBlendingFactorsI(LTDCDriver *ltdcp, ltdc_blendf_t bf) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer2->BFCR = ((LTDC_Layer2->BFCR & ~LTDC_LxBFCR_BF) | + ((uint32_t)bf & LTDC_LxBFCR_BF)); +} + +/** + * @brief Set foreground layer blending factors. + * @details Sets the blending factors of the foreground layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] factors blending factors + * + * @api + */ +void ltdcFgSetBlendingFactors(LTDCDriver *ltdcp, ltdc_blendf_t bf) { + + osalSysLock(); + ltdcFgSetBlendingFactorsI(ltdcp, bf); + osalSysUnlock(); +} + +/** + * @brief Get foreground layer window specs. + * @details Gets the window specifications of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[out] windowp pointer to the window specifications + * + * @iclass + */ +void ltdcFgGetWindowI(LTDCDriver *ltdcp, ltdc_window_t *windowp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgCheck(windowp != NULL); + (void)ltdcp; + + windowp->hstart = + (uint16_t)((LTDC_Layer2->WHPCR & LTDC_LxWHPCR_WHSTPOS) >> 0); + windowp->hstop = + (uint16_t)((LTDC_Layer2->WHPCR & LTDC_LxWHPCR_WHSPPOS) >> 16); + windowp->vstart = + (uint16_t)((LTDC_Layer2->WVPCR & LTDC_LxWVPCR_WVSTPOS) >> 0); + windowp->vstop = + (uint16_t)((LTDC_Layer2->WVPCR & LTDC_LxWVPCR_WVSPPOS) >> 16); +} + +/** + * @brief Get foreground layer window specs. + * @details Gets the window specifications of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[out] windowp pointer to the window specifications + * + * @api + */ +void ltdcFgGetWindow(LTDCDriver *ltdcp, ltdc_window_t *windowp) { + + osalSysLock(); + ltdcFgGetWindowI(ltdcp, windowp); + osalSysUnlock(); +} + +/** + * @brief Set foreground layer window specs. + * @details Sets the window specifications of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] windowp pointer to the window specifications + * + * @iclass + */ +void ltdcFgSetWindowI(LTDCDriver *ltdcp, const ltdc_window_t *windowp) { + + uint32_t start, stop; + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgCheck(windowp != NULL); + (void)ltdcp; + + osalDbgAssert(windowp->hstop < ltdcp->config->screen_width, "bounds"); + osalDbgAssert(windowp->vstop < ltdcp->config->screen_height, "bounds"); + + /* Horizontal boundaries.*/ + start = (uint32_t)windowp->hstart + ltdcp->active_window.hstart; + stop = (uint32_t)windowp->hstop + ltdcp->active_window.hstart; + + osalDbgAssert(start >= ltdcp->active_window.hstart, "bounds"); + osalDbgAssert(stop <= ltdcp->active_window.hstop, "bounds"); + + LTDC_Layer2->WHPCR = (((start << 0) & LTDC_LxWHPCR_WHSTPOS) | + ((stop << 16) & LTDC_LxWHPCR_WHSPPOS)); + + /* Vertical boundaries.*/ + start = (uint32_t)windowp->vstart + ltdcp->active_window.vstart; + stop = (uint32_t)windowp->vstop + ltdcp->active_window.vstart; + + osalDbgAssert(start >= ltdcp->active_window.vstart, "bounds"); + osalDbgAssert(stop <= ltdcp->active_window.vstop, "bounds"); + + LTDC_Layer2->WVPCR = (((start << 0) & LTDC_LxWVPCR_WVSTPOS) | + ((stop << 16) & LTDC_LxWVPCR_WVSPPOS)); +} + +/** + * @brief Set foreground layer window specs. + * @details Sets the window specifications of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] windowp pointer to the window specifications + * + * @api + */ +void ltdcFgSetWindow(LTDCDriver *ltdcp, const ltdc_window_t *windowp) { + + osalSysLock(); + ltdcFgSetWindowI(ltdcp, windowp); + osalSysUnlock(); +} + +/** + * @brief Set foreground layer window as invalid. + * @details Sets the window specifications of the foreground layer (layer 2) + * so that the window is pixel sized at the screen origin. + * @note Useful before reconfiguring the frame specifications of the layer, + * to avoid errors. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcFgSetInvalidWindowI(LTDCDriver *ltdcp) { + + ltdcFgSetWindowI(ltdcp, <dc_invalid_window); +} + +/** + * @brief Set foreground layer window as invalid. + * @details Sets the window specifications of the foreground layer (layer 2) + * so that the window is pixel sized at the screen origin. + * @note Useful before reconfiguring the frame specifications of the layer, + * to avoid errors. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcFgSetInvalidWindow(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcFgSetWindowI(ltdcp, <dc_invalid_window); + osalSysUnlock(); +} + +/** + * @brief Get foreground layer frame buffer specs. + * @details Gets the frame buffer specifications of the foreground layer + * (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[out] framep pointer to the frame buffer specifications + * + * @iclass + */ +void ltdcFgGetFrameI(LTDCDriver *ltdcp, ltdc_frame_t *framep) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgCheck(framep != NULL); + + framep->bufferp = (void *)(LTDC_Layer2->CFBAR & LTDC_LxCFBAR_CFBADD); + framep->pitch = (size_t)((LTDC_Layer2->CFBLR & LTDC_LxCFBLR_CFBP) >> 16); + framep->width = (uint16_t)(((LTDC_Layer2->CFBLR & LTDC_LxCFBLR_CFBLL) - 3) / + ltdcBytesPerPixel(ltdcFgGetPixelFormatI(ltdcp))); + framep->height = (uint16_t)(LTDC_Layer2->CFBLNR & LTDC_LxCFBLNR_CFBLNBR); +} + +/** + * @brief Get foreground layer frame buffer specs. + * @details Gets the frame buffer specifications of the foreground layer + * (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[out] framep pointer to the frame buffer specifications + * + * @api + */ +void ltdcFgGetFrame(LTDCDriver *ltdcp, ltdc_frame_t *framep) { + + osalSysLock(); + ltdcFgGetFrameI(ltdcp, framep); + osalSysUnlock(); +} + +/** + * @brief Set foreground layer frame buffer specs. + * @details Sets the frame buffer specifications of the foreground layer + * (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] framep pointer to the frame buffer specifications + * + * @iclass + */ +void ltdcFgSetFrameI(LTDCDriver *ltdcp, const ltdc_frame_t *framep) { + + size_t linesize; + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgCheck(framep != NULL); + + ltdcFgSetPixelFormatI(ltdcp, framep->fmt); + + linesize = ltdcBytesPerPixel(framep->fmt) * framep->width; + + osalDbgAssert(framep->width <= ltdcp->config->screen_width, "bounds"); + osalDbgAssert(framep->height <= ltdcp->config->screen_height, "bounds"); + osalDbgAssert(linesize >= LTDC_MIN_FRAME_WIDTH_BYTES, "bounds"); + osalDbgAssert(linesize <= LTDC_MAX_FRAME_WIDTH_BYTES, "bounds"); + osalDbgAssert(framep->height >= LTDC_MIN_FRAME_HEIGHT_LINES, "bounds"); + osalDbgAssert(framep->height <= LTDC_MAX_FRAME_HEIGHT_LINES, "bounds"); + osalDbgAssert(framep->pitch >= linesize, "bounds"); + + LTDC_Layer2->CFBAR = (uint32_t)framep->bufferp & LTDC_LxCFBAR_CFBADD; + LTDC_Layer2->CFBLR = ((((uint32_t)framep->pitch << 16) & LTDC_LxCFBLR_CFBP) | + ((linesize + 3) & LTDC_LxCFBLR_CFBLL)); + LTDC_Layer2->CFBLNR = (uint32_t)framep->height & LTDC_LxCFBLNR_CFBLNBR; +} + +/** + * @brief Set foreground layer frame buffer specs. + * @details Sets the frame buffer specifications of the foreground layer + * (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] framep pointer to the frame buffer specifications + * + * @api + */ +void ltdcFgSetFrame(LTDCDriver *ltdcp, const ltdc_frame_t *framep) { + + osalSysLock(); + ltdcFgSetFrameI(ltdcp, framep); + osalSysUnlock(); +} + +/** + * @brief Get foreground layer frame buffer address. + * @details Gets the frame buffer address of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return frame buffer address + * + * @iclass + */ +void *ltdcFgGetFrameAddressI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (void *)LTDC_Layer2->CFBAR; +} + +/** + * @brief Get foreground layer frame buffer address. + * @details Gets the frame buffer address of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return frame buffer address + * + * @api + */ +void *ltdcFgGetFrameAddress(LTDCDriver *ltdcp) { + + void *bufferp; + osalSysLock(); + bufferp = ltdcFgGetFrameAddressI(ltdcp); + osalSysUnlock(); + return bufferp; +} + +/** + * @brief Set foreground layer frame buffer address. + * @details Sets the frame buffer address of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] bufferp frame buffer address + * + * @iclass + */ +void ltdcFgSetFrameAddressI(LTDCDriver *ltdcp, void *bufferp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer2->CFBAR = (uint32_t)bufferp; +} + +/** + * @brief Set foreground layer frame buffer address. + * @details Sets the frame buffer address of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] bufferp frame buffer address + * + * @api + */ +void ltdcFgSetFrameAddress(LTDCDriver *ltdcp, void *bufferp) { + + osalSysLock(); + ltdcFgSetFrameAddressI(ltdcp, bufferp); + osalSysUnlock(); +} + +/** + * @brief Get foreground layer specifications. + * @details Gets the foreground layer (layer 2) specifications at once. + * @note If palette specifications cannot be retrieved, they are set to + * @p NULL. This is not an error. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[out] cfgp pointer to the layer specifications + * + * @iclass + */ +void ltdcFgGetLayerI(LTDCDriver *ltdcp, ltdc_laycfg_t *cfgp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgCheck(cfgp != NULL); + + ltdcFgGetFrameI(ltdcp, (ltdc_frame_t *)cfgp->frame); + ltdcFgGetWindowI(ltdcp, (ltdc_window_t *)cfgp->window); + cfgp->def_color = ltdcFgGetDefaultColorI(ltdcp); + cfgp->key_color = ltdcFgGetKeyingColorI(ltdcp); + cfgp->const_alpha = ltdcFgGetConstantAlphaI(ltdcp); + cfgp->blending = ltdcFgGetBlendingFactorsI(ltdcp); + + cfgp->pal_colors = NULL; + cfgp->pal_length = 0; + + cfgp->flags = ltdcFgGetEnableFlagsI(ltdcp); +} + +/** + * @brief Get foreground layer specifications. + * @details Gets the foreground layer (layer 2) specifications at once. + * @note If palette specifications cannot be retrieved, they are set to + * @p NULL. This is not an error. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[out] cfgp pointer to the layer specifications + * + * @api + */ +void ltdcFgGetLayer(LTDCDriver *ltdcp, ltdc_laycfg_t *cfgp) { + + osalSysLock(); + ltdcFgGetLayerI(ltdcp, cfgp); + osalSysUnlock(); +} + +/** + * @brief Set foreground layer specifications. + * @details Sets the foreground layer (layer 2) specifications at once. + * @note If the palette is unspecified, the layer palette is unmodified. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] cfgp pointer to the layer specifications + * + * @iclass + */ +void ltdcFgSetConfigI(LTDCDriver *ltdcp, const ltdc_laycfg_t *cfgp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + + if (cfgp == NULL) + cfgp = <dc_default_laycfg; + + osalDbgCheck((cfgp->pal_colors == NULL) == (cfgp->pal_length == 0)); + + ltdcFgSetFrameI(ltdcp, cfgp->frame); + ltdcFgSetWindowI(ltdcp, cfgp->window); + ltdcFgSetDefaultColorI(ltdcp, cfgp->def_color); + ltdcFgSetKeyingColorI(ltdcp, cfgp->key_color); + ltdcFgSetConstantAlphaI(ltdcp, cfgp->const_alpha); + ltdcFgSetBlendingFactorsI(ltdcp, cfgp->blending); + + if (cfgp->pal_length > 0) + ltdcFgSetPaletteI(ltdcp, cfgp->pal_colors, cfgp->pal_length); + + ltdcFgSetEnableFlagsI(ltdcp, cfgp->flags); +} + +/** + * @brief Set foreground layer specifications. + * @details Sets the foreground layer (layer 2) specifications at once. + * @note If the palette is unspecified, the layer palette is unmodified. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] cfgp pointer to the layer specifications + * + * @api + */ +void ltdcFgSetConfig(LTDCDriver *ltdcp, const ltdc_laycfg_t *cfgp) { + + osalSysLock(); + ltdcFgSetConfigI(ltdcp, cfgp); + osalSysUnlock(); +} + +/** @} */ + +/** + * @name LTDC helper functions + */ + +/** + * @brief Compute bits per pixel. + * @details Computes the bits per pixel for the specified pixel format. + * + * @param[in] fmt pixel format + * + * @retuen bits per pixel + * + * @api + */ +size_t ltdcBitsPerPixel(ltdc_pixfmt_t fmt) { + + osalDbgAssert(fmt < LTDC_MAX_PIXFMT_ID, "invalid format"); + + return (size_t)ltdc_bpp[(unsigned)fmt]; +} + +#if (TRUE == LTDC_USE_SOFTWARE_CONVERSIONS) || defined(__DOXYGEN__) + +/** + * @brief Convert from ARGB-8888. + * @details Converts an ARGB-8888 color to the specified pixel format. + * + * @param[in] c color, ARGB-8888 + * @param[in] fmt target pixel format + * + * @return raw color value for the target pixel format, left + * padded with zeros. + * + * @api + */ +ltdc_color_t ltdcFromARGB8888(ltdc_color_t c, ltdc_pixfmt_t fmt) { + + switch (fmt) { + case LTDC_FMT_ARGB8888: { + return c; + } + case LTDC_FMT_RGB888: { + return (c & 0x00FFFFFF); + } + case LTDC_FMT_RGB565: { + return (((c & 0x000000F8) >> ( 8 - 5)) | + ((c & 0x0000FC00) >> (16 - 11)) | + ((c & 0x00F80000) >> (24 - 16))); + } + case LTDC_FMT_ARGB1555: { + return (((c & 0x000000F8) >> ( 8 - 5)) | + ((c & 0x0000F800) >> (16 - 10)) | + ((c & 0x00F80000) >> (24 - 15)) | + ((c & 0x80000000) >> (32 - 16))); + } + case LTDC_FMT_ARGB4444: { + return (((c & 0x000000F0) >> ( 8 - 4)) | + ((c & 0x0000F000) >> (16 - 8)) | + ((c & 0x00F00000) >> (24 - 12)) | + ((c & 0xF0000000) >> (32 - 16))); + } + case LTDC_FMT_L8: { + return (c & 0x000000FF); + } + case LTDC_FMT_AL44: { + return (((c & 0x000000F0) >> ( 8 - 4)) | + ((c & 0xF0000000) >> (32 - 8))); + } + case LTDC_FMT_AL88: { + return (((c & 0x000000FF) >> ( 8 - 8)) | + ((c & 0xFF000000) >> (32 - 16))); + } + default: + osalDbgAssert(false, "invalid format"); + return 0; + } +} + +/** + * @brief Convert to ARGB-8888. + * @details Converts color of the specified pixel format to an ARGB-8888 color. + * + * @param[in] c color for the source pixel format, left padded with + * zeros. + * @param[in] fmt source pixel format + * + * @return color in ARGB-8888 format + * + * @api + */ +ltdc_color_t ltdcToARGB8888(ltdc_color_t c, ltdc_pixfmt_t fmt) { + + switch (fmt) { + case LTDC_FMT_ARGB8888: { + return c; + } + case LTDC_FMT_RGB888: { + return ((c & 0x00FFFFFF) | 0xFF000000); + } + case LTDC_FMT_RGB565: { + register ltdc_color_t output = 0xFF000000; + if (c & 0x001F) output |= (((c & 0x001F) << ( 8 - 5)) | 0x00000007); + if (c & 0x07E0) output |= (((c & 0x07E0) << (16 - 11)) | 0x00000300); + if (c & 0xF800) output |= (((c & 0xF800) << (24 - 16)) | 0x00070000); + return output; + } + case LTDC_FMT_ARGB1555: { + register ltdc_color_t output = 0x00000000; + if (c & 0x001F) output |= (((c & 0x001F) << ( 8 - 5)) | 0x00000007); + if (c & 0x03E0) output |= (((c & 0x03E0) << (16 - 10)) | 0x00000700); + if (c & 0x7C00) output |= (((c & 0x7C00) << (24 - 15)) | 0x00070000); + if (c & 0x8000) output |= 0xFF000000; + return output; + } + case LTDC_FMT_ARGB4444: { + register ltdc_color_t output = 0x00000000; + if (c & 0x000F) output |= (((c & 0x000F) << ( 8 - 4)) | 0x0000000F); + if (c & 0x00F0) output |= (((c & 0x00F0) << (16 - 8)) | 0x00000F00); + if (c & 0x0F00) output |= (((c & 0x0F00) << (24 - 12)) | 0x000F0000); + if (c & 0xF000) output |= (((c & 0xF000) << (32 - 16)) | 0x0F000000); + return output; + } + case LTDC_FMT_L8: { + return ((c & 0xFF) | 0xFF000000); + } + case LTDC_FMT_AL44: { + register ltdc_color_t output = 0x00000000; + if (c & 0x0F) output |= (((c & 0x0F) << ( 8 - 4)) | 0x0000000F); + if (c & 0xF0) output |= (((c & 0xF0) << (32 - 8)) | 0x0F000000); + return output; + } + case LTDC_FMT_AL88: { + return (((c & 0x00FF) << ( 8 - 8)) | + ((c & 0xFF00) << (32 - 16))); + } + default: + osalDbgAssert(false, "invalid format"); + return 0; + } +} + +#endif /* LTDC_USE_SOFTWARE_CONVERSIONS */ + +/** @} */ + +/** @} */ + +#endif /* STM32_LTDC_USE_LTDC */ diff --git a/os/hal/ports/STM32/LLD/LTDCv1/hal_stm32_ltdc.h b/os/hal/ports/STM32/LLD/LTDCv1/hal_stm32_ltdc.h new file mode 100644 index 0000000..16b38ca --- /dev/null +++ b/os/hal/ports/STM32/LLD/LTDCv1/hal_stm32_ltdc.h @@ -0,0 +1,736 @@ +/* + Copyright (C) 2013-2015 Andrea Zoppi + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file stm32_ltdc.h + * @brief LCD-TFT Controller Driver. + * + * @addtogroup ltdc + * @{ + */ + +#ifndef _STM32_LTDC_H_ +#define _STM32_LTDC_H_ + +/** + * @brief Using the LTDC driver. + */ +#if !defined(STM32_LTDC_USE_LTDC) || defined(__DOXYGEN__) +#define STM32_LTDC_USE_LTDC (FALSE) +#endif + +#if (TRUE == STM32_LTDC_USE_LTDC) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name LTDC enable flags + * @{ + */ +#define LTDC_EF_ENABLE (1 << 0) /**< LTDC enabled.*/ +#define LTDC_EF_DITHER (1 << 16) /**< Dithering enabled.*/ +#define LTDC_EF_PIXCLK_INVERT (1 << 28) /**< Inverted pixel clock.*/ +#define LTDC_EF_DATAEN_HIGH (1 << 29) /**< Active-high data enable.*/ +#define LTDC_EF_VSYNC_HIGH (1 << 30) /**< Active-high vsync.*/ +#define LTDC_EF_HSYNC_HIGH (1 << 31) /**< Active-high hsync.*/ + +#define LTDC_EF_MASK \ + (LTDC_EF_ENABLE | LTDC_EF_DITHER | LTDC_EF_PIXCLK_INVERT | \ + LTDC_EF_DATAEN_HIGH | LTDC_EF_VSYNC_HIGH | LTDC_EF_HSYNC_HIGH) +/** @} */ + +/** + * @name LTDC layer enable flags + * @{ + */ +#define LTDC_LEF_ENABLE (1 << 0) /**< Layer enabled*/ +#define LTDC_LEF_KEYING (1 << 1) /**< Color keying enabled.*/ +#define LTDC_LEF_PALETTE (1 << 4) /**< Palette enabled.*/ + +#define LTDC_LEF_MASK \ + (LTDC_LEF_ENABLE | LTDC_LEF_KEYING | LTDC_LEF_PALETTE) +/** @} */ + +/** + * @name LTDC pixel formats + * @{ + */ +#define LTDC_FMT_ARGB8888 (0) /**< ARGB-8888 format.*/ +#define LTDC_FMT_RGB888 (1) /**< RGB-888 format.*/ +#define LTDC_FMT_RGB565 (2) /**< RGB-565 format.*/ +#define LTDC_FMT_ARGB1555 (3) /**< ARGB-1555 format.*/ +#define LTDC_FMT_ARGB4444 (4) /**< ARGB-4444 format.*/ +#define LTDC_FMT_L8 (5) /**< L-8 format.*/ +#define LTDC_FMT_AL44 (6) /**< AL-44 format.*/ +#define LTDC_FMT_AL88 (7) /**< AL-88 format.*/ +/** @} */ + +/** + * @name LTDC pixel format aliased raw masks + * @{ + */ +#define LTDC_XMASK_ARGB8888 (0xFFFFFFFF) /**< ARGB-8888 aliased mask.*/ +#define LTDC_XMASK_RGB888 (0x00FFFFFF) /**< RGB-888 aliased mask.*/ +#define LTDC_XMASK_RGB565 (0x00F8FCF8) /**< RGB-565 aliased mask.*/ +#define LTDC_XMASK_ARGB1555 (0x80F8F8F8) /**< ARGB-1555 aliased mask.*/ +#define LTDC_XMASK_ARGB4444 (0xF0F0F0F0) /**< ARGB-4444 aliased mask.*/ +#define LTDC_XMASK_L8 (0x000000FF) /**< L-8 aliased mask.*/ +#define LTDC_XMASK_AL44 (0xF00000F0) /**< AL-44 aliased mask.*/ +#define LTDC_XMASK_AL88 (0xFF0000FF) /**< AL-88 aliased mask.*/ +/** @} */ + +/** + * @name LTDC blending factors + * @{ + */ +#define LTDC_BLEND_FIX1_FIX2 (0x0405) /**< cnst1; 1 - cnst2 */ +#define LTDC_BLEND_FIX1_MOD2 (0x0407) /**< cnst1; 1 - a2 * cnst2 */ +#define LTDC_BLEND_MOD1_FIX2 (0x0605) /**< a1 * cnst1; 1 - cnst2 */ +#define LTDC_BLEND_MOD1_MOD2 (0x0607) /**< a1 * cnst1; 1 - a2 * cnst2 */ +/** @} */ + +/** + * @name LTDC parameter bounds + * @{ + */ + +#define LTDC_MIN_SCREEN_WIDTH (1) +#define LTDC_MIN_SCREEN_HEIGHT (1) +#define LTDC_MAX_SCREEN_WIDTH (800) +#define LTDC_MAX_SCREEN_HEIGHT (600) + +#define LTDC_MIN_HSYNC_WIDTH (1) +#define LTDC_MIN_VSYNC_HEIGHT (1) +#define LTDC_MAX_HSYNC_WIDTH (1 << 12) +#define LTDC_MAX_VSYNC_HEIGHT (1 << 11) + +#define LTDC_MIN_HBP_WIDTH (0) +#define LTDC_MIN_VBP_HEIGHT (0) +#define LTDC_MAX_HBP_WIDTH (1 << 12) +#define LTDC_MAX_VBP_HEIGHT (1 << 11) + +#define LTDC_MIN_ACC_HBP_WIDTH (1) +#define LTDC_MIN_ACC_VBP_HEIGHT (1) +#define LTDC_MAX_ACC_HBP_WIDTH (1 << 12) +#define LTDC_MAX_ACC_VBP_HEIGHT (1 << 11) + +#define LTDC_MIN_HFP_WIDTH (0) +#define LTDC_MIN_VFP_HEIGHT (0) +#define LTDC_MAX_HFP_WIDTH (1 << 12) +#define LTDC_MAX_VFP_HEIGHT (1 << 11) + +#define LTDC_MIN_ACTIVE_WIDTH (0) +#define LTDC_MIN_ACTIVE_HEIGHT (0) +#define LTDC_MAX_ACTIVE_WIDTH (1 << 12) +#define LTDC_MAX_ACTIVE_HEIGHT (1 << 11) + +#define LTDC_MIN_ACC_ACTIVE_WIDTH (1) +#define LTDC_MIN_ACC_ACTIVE_HEIGHT (1) +#define LTDC_MAX_ACC_ACTIVE_WIDTH (1 << 12) +#define LTDC_MAX_ACC_ACTIVE_HEIGHT (1 << 11) + +#define LTDC_MIN_ACC_TOTAL_WIDTH (1) +#define LTDC_MIN_ACC_TOTAL_HEIGHT (1) +#define LTDC_MAX_ACC_TOTAL_WIDTH (1 << 12) +#define LTDC_MAX_ACC_TOTAL_HEIGHT (1 << 11) + +#define LTDC_MIN_LINE_INTERRUPT_POS (0) +#define LTDC_MAX_LINE_INTERRUPT_POS ((1 << 11) - 1) + +#define LTDC_MIN_WINDOW_HSTART (0) +#define LTDC_MIN_WINDOW_HSTART (0) +#define LTDC_MAX_WINDOW_HSTOP ((1 << 12) - 1) +#define LTDC_MAX_WINDOW_HSTOP ((1 << 12) - 1) + +#define LTDC_MIN_WINDOW_VSTART (0) +#define LTDC_MIN_WINDOW_VSTART (0) +#define LTDC_MAX_WINDOW_VSTOP ((1 << 11) - 1) +#define LTDC_MAX_WINDOW_VSTOP ((1 << 11) - 1) + +#define LTDC_MIN_FRAME_WIDTH_BYTES (0) +#define LTDC_MIN_FRAME_HEIGHT_LINES (0) +#define LTDC_MIN_FRAME_PITCH_BYTES (0) +#define LTDC_MAX_FRAME_WIDTH_BYTES ((1 << 13) - 1 - 3) +#define LTDC_MAX_FRAME_HEIGHT_LINES ((1 << 11) - 1) +#define LTDC_MAX_FRAME_PITCH_BYTES ((1 << 13) - 1) + +#define LTDC_MIN_PIXFMT_ID (0) +#define LTDC_MAX_PIXFMT_ID (7) + +#define LTDC_MAX_PALETTE_LENGTH (256) + +/** @} */ + +/** + * @name LTDC basic ARGB-8888 colors. + * @{ + */ +/* Microsoft Windows default 16-color palette.*/ +#define LTDC_COLOR_BLACK (0xFF000000) +#define LTDC_COLOR_MAROON (0xFF800000) +#define LTDC_COLOR_GREEN (0xFF008000) +#define LTDC_COLOR_OLIVE (0xFF808000) +#define LTDC_COLOR_NAVY (0xFF000080) +#define LTDC_COLOR_PURPLE (0xFF800080) +#define LTDC_COLOR_TEAL (0xFF008080) +#define LTDC_COLOR_SILVER (0xFFC0C0C0) +#define LTDC_COLOR_GRAY (0xFF808080) +#define LTDC_COLOR_RED (0xFFFF0000) +#define LTDC_COLOR_LIME (0xFF00FF00) +#define LTDC_COLOR_YELLOW (0xFFFFFF00) +#define LTDC_COLOR_BLUE (0xFF0000FF) +#define LTDC_COLOR_FUCHSIA (0xFFFF00FF) +#define LTDC_COLOR_AQUA (0xFF00FFFF) +#define LTDC_COLOR_WHITE (0xFFFFFFFF) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name LTDC configuration options + * @{ + */ + +/** + * @brief LTDC event interrupt priority level setting. + */ +#if !defined(STM32_LTDC_EV_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_LTDC_EV_IRQ_PRIORITY (11) +#endif + +/** + * @brief LTDC error interrupt priority level setting. + */ +#if !defined(STM32_LTDC_ER_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_LTDC_ER_IRQ_PRIORITY (11) +#endif + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(LTDC_USE_WAIT) || defined(__DOXYGEN__) +#define LTDC_USE_WAIT (TRUE) +#endif + +/** + * @brief Enables the @p ltdcAcquireBus() and @p ltdcReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(LTDC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define LTDC_USE_MUTUAL_EXCLUSION (TRUE) +#endif + +/** + * @brief Provides software color conversion functions. + * @note Disabling this option saves both code and data space. + */ +#if !defined(LTDC_USE_SOFTWARE_CONVERSIONS) || defined(__DOXYGEN__) +#define LTDC_USE_SOFTWARE_CONVERSIONS (TRUE) +#endif + +/** + * @brief Enables checks for LTDC functions. + * @note Disabling this option saves both code and data space. + * @note Disabling checks by ChibiOS will automatically disable LTDC checks. + */ +#if !defined(LTDC_USE_CHECKS) || defined(__DOXYGEN__) +#define LTDC_USE_CHECKS (TRUE) +#endif + +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if (TRUE != STM32_HAS_LTDC) +#error "LTDC must be present when using the LTDC subsystem" +#endif + +#if (TRUE == STM32_LTDC_USE_LTDC) && (TRUE != STM32_HAS_LTDC) +#error "LTDC not present in the selected device" +#endif + +#if (TRUE == LTDC_USE_MUTUAL_EXCLUSION) +#if (TRUE != CH_CFG_USE_MUTEXES) && (TRUE != CH_CFG_USE_SEMAPHORES) +#error "LTDC_USE_MUTUAL_EXCLUSION requires CH_CFG_USE_MUTEXES and/or CH_CFG_USE_SEMAPHORES" +#endif +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/* Complex types forwarding.*/ +typedef union ltdc_coloralias_t ltdc_coloralias_t; +typedef struct ltdc_window_t ltdc_window_t; +typedef struct ltdc_frame_t ltdc_frame_t; +typedef struct ltdc_laycfg_t ltdc_laycfg_t; +typedef struct LTDCConfig LTDCConfig; +typedef enum ltdc_state_t ltdc_state_t; +typedef struct LTDCDriver LTDCDriver; + +/** + * @name LTDC Data types + * @{ + */ + +/** + * @brief LTDC generic color. + */ +typedef uint32_t ltdc_color_t; + +/** + * @brief LTDC color aliases. + * @detail Mapped with ARGB-8888, except for luminance (L mapped onto B). + * Padding fields are prefixed with 'x', and should be clear + * (all 0) before compression and set (all 1) after expansion. + */ +typedef union ltdc_coloralias_t { + struct { + unsigned b : 8; + unsigned g : 8; + unsigned r : 8; + unsigned a : 8; + } argb8888; /**< Mapped ARGB-8888 bits.*/ + struct { + unsigned b : 8; + unsigned g : 8; + unsigned r : 8; + unsigned xa : 8; + } rgb888; /**< Mapped RGB-888 bits.*/ + struct { + unsigned xb : 3; + unsigned b : 5; + unsigned xg : 2; + unsigned g : 6; + unsigned xr : 3; + unsigned r : 5; + unsigned xa : 8; + } rgb565; /**< Mapped RGB-565 bits.*/ + struct { + unsigned xb : 3; + unsigned b : 5; + unsigned xg : 3; + unsigned g : 5; + unsigned xr : 3; + unsigned r : 5; + unsigned xa : 7; + unsigned a : 1; + } argb1555; /**< Mapped ARGB-1555 values.*/ + struct { + unsigned xb : 4; + unsigned b : 4; + unsigned xg : 4; + unsigned g : 4; + unsigned xr : 4; + unsigned r : 4; + unsigned xa : 4; + unsigned a : 4; + } argb4444; /**< Mapped ARGB-4444 values.*/ + struct { + unsigned l : 8; + unsigned x : 16; + unsigned xa : 8; + } l8; /**< Mapped L-8 bits.*/ + struct { + unsigned xl : 4; + unsigned l : 4; + unsigned x : 16; + unsigned xa : 4; + unsigned a : 4; + } al44; /**< Mapped AL-44 bits.*/ + struct { + unsigned l : 8; + unsigned x : 16; + unsigned a : 8; + } al88; /**< Mapped AL-88 bits.*/ + ltdc_color_t aliased; /**< Aliased raw bits.*/ +} ltdc_coloralias_t; + +/** + * @brief LTDC layer identifier. + */ +typedef uint32_t ltdc_layerid_t; + +/** + * @brief LTDC pixel format. + */ +typedef uint32_t ltdc_pixfmt_t; + +/** + * @brief LTDC blending factor. + */ +typedef uint32_t ltdc_blendf_t; + +/** + * @brief LTDC ISR callback. + */ +typedef void (*ltdc_isrcb_t)(LTDCDriver *ltdcp); + +/** + * @brief LTDC window specifications. + */ +typedef struct ltdc_window_t { + uint16_t hstart; /**< Horizontal start pixel (left).*/ + uint16_t hstop; /**< Horizontal stop pixel (right).*/ + uint16_t vstart; /**< Vertical start pixel (top).*/ + uint16_t vstop; /**< Vertical stop pixel (bottom).*/ +} ltdc_window_t; + +/** + * @brief LTDC frame specifications. + */ +typedef struct ltdc_frame_t { + void *bufferp; /**< Frame buffer address.*/ + uint16_t width; /**< Frame width, in pixels.*/ + uint16_t height; /**< Frame height, in pixels.*/ + size_t pitch; /**< Line pitch, in bytes.*/ + ltdc_pixfmt_t fmt; /**< Pixel format.*/ +} ltdc_frame_t; + +/** + * @brief LTDC configuration flags. + */ +typedef uint8_t ltdc_flags_t; + +/** + * @brief LTDC startup layer configuration. + */ +typedef struct ltdc_laycfg_t { + const ltdc_frame_t *frame; /**< Frame buffer specifications.*/ + const ltdc_window_t *window; /**< Window specifications.*/ + ltdc_color_t def_color; /**< Default color, ARGB-8888.*/ + uint8_t const_alpha; /**< Constant alpha factor.*/ + ltdc_color_t key_color; /**< Color key.*/ + const ltdc_color_t *pal_colors; /**< Palette colors, or @p NULL.*/ + uint16_t pal_length; /**< Palette length, or @p 0.*/ + ltdc_blendf_t blending; /**< Blending factors.*/ + ltdc_flags_t flags; /**< Layer configuration flags.*/ +} ltdc_laycfg_t; + +/** + * @brief LTDC driver configuration. + */ +typedef struct LTDCConfig { + /* Display specifications.*/ + uint16_t screen_width; /**< Screen pixel width.*/ + uint16_t screen_height; /**< Screen pixel height.*/ + uint16_t hsync_width; /**< Horizontal sync pixel width.*/ + uint16_t vsync_height; /**< Vertical sync pixel height.*/ + uint16_t hbp_width; /**< Horizontal back porch pixel width.*/ + uint16_t vbp_height; /**< Vertical back porch pixel height.*/ + uint16_t hfp_width; /**< Horizontal front porch pixel width.*/ + uint16_t vfp_height; /**< Vertical front porch pixel height.*/ + ltdc_flags_t flags; /**< Driver configuration flags.*/ + + /* ISR callbacks.*/ + ltdc_isrcb_t line_isr; /**< Line Interrupt ISR, or @p NULL.*/ + ltdc_isrcb_t rr_isr; /**< Register Reload ISR, or @p NULL.*/ + ltdc_isrcb_t fuerr_isr; /**< FIFO Underrun ISR, or @p NULL.*/ + ltdc_isrcb_t terr_isr; /**< Transfer Error ISR, or @p NULL.*/ + + /* Layer and color settings.*/ + ltdc_color_t clear_color; /**< Clear screen color, RGB-888.*/ + const ltdc_laycfg_t *bg_laycfg; /**< Background layer specs, or @p NULL.*/ + const ltdc_laycfg_t *fg_laycfg; /**< Foreground layer specs, or @p NULL.*/ +} LTDCConfig; + +/** + * @brief LTDC driver state. + */ +typedef enum ltdc_state_t { + LTDC_UNINIT = (0), /**< Not initialized.*/ + LTDC_STOP = (1), /**< Stopped.*/ + LTDC_READY = (2), /**< Ready.*/ + LTDC_ACTIVE = (3), /**< Executing commands.*/ +} ltdc_state_t; + +/** + * @brief LTDC driver. + */ +typedef struct LTDCDriver { + ltdc_state_t state; /**< Driver state.*/ + const LTDCConfig *config; /**< Driver configuration.*/ + + /* Handy computations.*/ + ltdc_window_t active_window; /**< Active window coordinates.*/ + + /* Multithreading stuff.*/ +#if (TRUE == LTDC_USE_WAIT) || defined(__DOXYGEN__) + thread_t *thread; /**< Waiting thread.*/ +#endif /* LTDC_USE_WAIT */ +#if (TRUE == LTDC_USE_MUTUAL_EXCLUSION) +#if (TRUE == CH_CFG_USE_MUTEXES) + mutex_t lock; /**< Multithreading lock.*/ +#elif (TRUE == CH_CFG_USE_SEMAPHORES) + semaphore_t lock; /**< Multithreading lock.*/ +#endif +#endif /* LTDC_USE_MUTUAL_EXCLUSION */ +} LTDCDriver; + +/** @} */ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Makes an ARGB-8888 value from byte components. + * + * @param[in] a alpha byte component + * @param[in] r red byte component + * @param[in] g green byte component + * @param[in] b blue byte component + * + * @return color in ARGB-8888 format + * + * @api + */ +#define ltdcMakeARGB8888(a, r, g, b) \ + ((((ltdc_color_t)(a) & 0xFF) << 24) | \ + (((ltdc_color_t)(r) & 0xFF) << 16) | \ + (((ltdc_color_t)(g) & 0xFF) << 8) | \ + (((ltdc_color_t)(b) & 0xFF) << 0)) + +/** + * @brief Compute bytes per pixel. + * @details Computes the bytes per pixel for the specified pixel format. + * Rounds to the ceiling. + * + * @param[in] fmt pixel format + * + * @return bytes per pixel + * + * @api + */ +#define ltdcBytesPerPixel(fmt) \ + ((ltdcBitsPerPixel(fmt) + 7) >> 3) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +extern LTDCDriver LTDCD1; + +#ifdef __cplusplus +extern "C" { +#endif + /* Driver methods.*/ + void ltdcInit(void); + void ltdcObjectInit(LTDCDriver *ltdcp); + ltdc_state_t ltdcGetStateI(LTDCDriver *ltdcp); + ltdc_state_t ltdcGetState(LTDCDriver *ltdcp); + void ltdcStart(LTDCDriver *ltdcp, const LTDCConfig *configp); + void ltdcStop(LTDCDriver *ltdcp); +#if (TRUE == LTDC_USE_MUTUAL_EXCLUSION) + void ltdcAcquireBusS(LTDCDriver *ltdcp); + void ltdcAcquireBus(LTDCDriver *ltdcp); + void ltdcReleaseBusS(LTDCDriver *ltdcp); + void ltdcReleaseBus(LTDCDriver *ltdcp); +#endif /* LTDC_USE_MUTUAL_EXCLUSION */ + + /* Global methods.*/ + ltdc_flags_t ltdcGetEnableFlagsI(LTDCDriver *ltdcp); + ltdc_flags_t ltdcGetEnableFlags(LTDCDriver *ltdcp); + void ltdcSetEnableFlagsI(LTDCDriver *ltdcp, ltdc_flags_t flags); + void ltdcSetEnableFlags(LTDCDriver *ltdcp, ltdc_flags_t flags); + bool ltdcIsReloadingI(LTDCDriver *ltdcp); + bool ltdcIsReloading(LTDCDriver *ltdcp); + void ltdcStartReloadI(LTDCDriver *ltdcp, bool immediately); + void ltdcStartReload(LTDCDriver *ltdcp, bool immediately); + void ltdcReloadS(LTDCDriver *ltdcp, bool immediately); + void ltdcReload(LTDCDriver *ltdcp, bool immediately); + bool ltdcIsDitheringEnabledI(LTDCDriver *ltdcp); + bool ltdcIsDitheringEnabled(LTDCDriver *ltdcp); + void ltdcEnableDitheringI(LTDCDriver *ltdcp); + void ltdcEnableDithering(LTDCDriver *ltdcp); + void ltdcDisableDitheringI(LTDCDriver *ltdcp); + void ltdcDisableDithering(LTDCDriver *ltdcp); + ltdc_color_t ltdcGetClearColorI(LTDCDriver *ltdcp); + ltdc_color_t ltdcGetClearColor(LTDCDriver *ltdcp); + void ltdcSetClearColorI(LTDCDriver *ltdcp, ltdc_color_t c); + void ltdcSetClearColor(LTDCDriver *ltdcp, ltdc_color_t c); + uint16_t ltdcGetLineInterruptPosI(LTDCDriver *ltdcp); + uint16_t ltdcGetLineInterruptPos(LTDCDriver *ltdcp); + void ltdcSetLineInterruptPosI(LTDCDriver *ltdcp, uint16_t line); + void ltdcSetLineInterruptPos(LTDCDriver *ltdcp, uint16_t line); + bool ltdcIsLineInterruptEnabledI(LTDCDriver *ltdcp); + bool ltdcIsLineInterruptEnabled(LTDCDriver *ltdcp); + void ltdcEnableLineInterruptI(LTDCDriver *ltdcp); + void ltdcEnableLineInterrupt(LTDCDriver *ltdcp); + void ltdcDisableLineInterruptI(LTDCDriver *ltdcp); + void ltdcDisableLineInterrupt(LTDCDriver *ltdcp); + void ltdcGetCurrentPosI(LTDCDriver *ltdcp, uint16_t *xp, uint16_t *yp); + void ltdcGetCurrentPos(LTDCDriver *ltdcp, uint16_t *xp, uint16_t *yp); + + /* Background layer methods.*/ + ltdc_flags_t ltdcBgGetEnableFlagsI(LTDCDriver *ltdcp); + ltdc_flags_t ltdcBgGetEnableFlags(LTDCDriver *ltdcp); + void ltdcBgSetEnableFlagsI(LTDCDriver *ltdcp, ltdc_flags_t flags); + void ltdcBgSetEnableFlags(LTDCDriver *ltdcp, ltdc_flags_t flags); + bool ltdcBgIsEnabledI(LTDCDriver *ltdcp); + bool ltdcBgIsEnabled(LTDCDriver *ltdcp); + void ltdcBgEnableI(LTDCDriver *ltdcp); + void ltdcBgEnable(LTDCDriver *ltdcp); + void ltdcBgDisableI(LTDCDriver *ltdcp); + void ltdcBgDisable(LTDCDriver *ltdcp); + bool ltdcBgIsPaletteEnabledI(LTDCDriver *ltdcp); + bool ltdcBgIsPaletteEnabled(LTDCDriver *ltdcp); + void ltdcBgEnablePaletteI(LTDCDriver *ltdcp); + void ltdcBgEnablePalette(LTDCDriver *ltdcp); + void ltdcBgDisablePaletteI(LTDCDriver *ltdcp); + void ltdcBgDisablePalette(LTDCDriver *ltdcp); + void ltdcBgSetPaletteColorI(LTDCDriver *ltdcp, uint8_t slot, ltdc_color_t c); + void ltdcBgSetPaletteColor(LTDCDriver *ltdcp, uint8_t slot, ltdc_color_t c); + void ltdcBgSetPaletteI(LTDCDriver *ltdcp, const ltdc_color_t colors[], + uint16_t length); + void ltdcBgSetPalette(LTDCDriver *ltdcp, const ltdc_color_t colors[], + uint16_t length); + ltdc_pixfmt_t ltdcBgGetPixelFormatI(LTDCDriver *ltdcp); + ltdc_pixfmt_t ltdcBgGetPixelFormat(LTDCDriver *ltdcp); + void ltdcBgSetPixelFormatI(LTDCDriver *ltdcp, ltdc_pixfmt_t fmt); + void ltdcBgSetPixelFormat(LTDCDriver *ltdcp, ltdc_pixfmt_t fmt); + bool ltdcBgIsKeyingEnabledI(LTDCDriver *ltdcp); + bool ltdcBgIsKeyingEnabled(LTDCDriver *ltdcp); + void ltdcBgEnableKeyingI(LTDCDriver *ltdcp); + void ltdcBgEnableKeying(LTDCDriver *ltdcp); + void ltdcBgDisableKeyingI(LTDCDriver *ltdcp); + void ltdcBgDisableKeying(LTDCDriver *ltdcp); + ltdc_color_t ltdcBgGetKeyingColorI(LTDCDriver *ltdcp); + ltdc_color_t ltdcBgGetKeyingColor(LTDCDriver *ltdcp); + void ltdcBgSetKeyingColorI(LTDCDriver *ltdcp, ltdc_color_t c); + void ltdcBgSetKeyingColor(LTDCDriver *ltdcp, ltdc_color_t c); + uint8_t ltdcBgGetConstantAlphaI(LTDCDriver *ltdcp); + uint8_t ltdcBgGetConstantAlpha(LTDCDriver *ltdcp); + void ltdcBgSetConstantAlphaI(LTDCDriver *ltdcp, uint8_t a); + void ltdcBgSetConstantAlpha(LTDCDriver *ltdcp, uint8_t a); + ltdc_color_t ltdcBgGetDefaultColorI(LTDCDriver *ltdcp); + ltdc_color_t ltdcBgGetDefaultColor(LTDCDriver *ltdcp); + void ltdcBgSetDefaultColorI(LTDCDriver *ltdcp, ltdc_color_t c); + void ltdcBgSetDefaultColor(LTDCDriver *ltdcp, ltdc_color_t c); + ltdc_blendf_t ltdcBgGetBlendingFactorsI(LTDCDriver *ltdcp); + ltdc_blendf_t ltdcBgGetBlendingFactors(LTDCDriver *ltdcp); + void ltdcBgSetBlendingFactorsI(LTDCDriver *ltdcp, ltdc_blendf_t bf); + void ltdcBgSetBlendingFactors(LTDCDriver *ltdcp, ltdc_blendf_t bf); + void ltdcBgGetWindowI(LTDCDriver *ltdcp, ltdc_window_t *windowp); + void ltdcBgGetWindow(LTDCDriver *ltdcp, ltdc_window_t *windowp); + void ltdcBgSetWindowI(LTDCDriver *ltdcp, const ltdc_window_t *windowp); + void ltdcBgSetWindow(LTDCDriver *ltdcp, const ltdc_window_t *windowp); + void ltdcBgSetInvalidWindowI(LTDCDriver *ltdcp); + void ltdcBgSetInvalidWindow(LTDCDriver *ltdcp); + void ltdcBgGetFrameI(LTDCDriver *ltdcp, ltdc_frame_t *framep); + void ltdcBgGetFrame(LTDCDriver *ltdcp, ltdc_frame_t *framep); + void ltdcBgSetFrameI(LTDCDriver *ltdcp, const ltdc_frame_t *framep); + void ltdcBgSetFrame(LTDCDriver *ltdcp, const ltdc_frame_t *framep); + void *ltdcBgGetFrameAddressI(LTDCDriver *ltdcp); + void *ltdcBgGetFrameAddress(LTDCDriver *ltdcp); + void ltdcBgSetFrameAddressI(LTDCDriver *ltdcp, void *bufferp); + void ltdcBgSetFrameAddress(LTDCDriver *ltdcp, void *bufferp); + void ltdcBgGetLayerI(LTDCDriver *ltdcp, ltdc_laycfg_t *cfgp); + void ltdcBgGetLayer(LTDCDriver *ltdcp, ltdc_laycfg_t *cfgp); + void ltdcBgSetConfigI(LTDCDriver *ltdcp, const ltdc_laycfg_t *cfgp); + void ltdcBgSetConfig(LTDCDriver *ltdcp, const ltdc_laycfg_t *cfgp); + + /* Foreground layer methods.*/ + ltdc_flags_t ltdcFgGetEnableFlagsI(LTDCDriver *ltdcp); + ltdc_flags_t ltdcFgGetEnableFlags(LTDCDriver *ltdcp); + void ltdcFgSetEnableFlagsI(LTDCDriver *ltdcp, ltdc_flags_t flags); + void ltdcFgSetEnableFlags(LTDCDriver *ltdcp, ltdc_flags_t flags); + bool ltdcFgIsEnabledI(LTDCDriver *ltdcp); + bool ltdcFgIsEnabled(LTDCDriver *ltdcp); + void ltdcFgEnableI(LTDCDriver *ltdcp); + void ltdcFgEnable(LTDCDriver *ltdcp); + void ltdcFgDisableI(LTDCDriver *ltdcp); + void ltdcFgDisable(LTDCDriver *ltdcp); + bool ltdcFgIsPaletteEnabledI(LTDCDriver *ltdcp); + bool ltdcFgIsPaletteEnabled(LTDCDriver *ltdcp); + void ltdcFgEnablePaletteI(LTDCDriver *ltdcp); + void ltdcFgEnablePalette(LTDCDriver *ltdcp); + void ltdcFgDisablePaletteI(LTDCDriver *ltdcp); + void ltdcFgDisablePalette(LTDCDriver *ltdcp); + void ltdcFgSetPaletteColorI(LTDCDriver *ltdcp, uint8_t slot, ltdc_color_t c); + void ltdcFgSetPaletteColor(LTDCDriver *ltdcp, uint8_t slot, ltdc_color_t c); + void ltdcFgSetPaletteI(LTDCDriver *ltdcp, const ltdc_color_t colors[], + uint16_t length); + void ltdcFgSetPalette(LTDCDriver *ltdcp, const ltdc_color_t colors[], + uint16_t length); + ltdc_pixfmt_t ltdcFgGetPixelFormatI(LTDCDriver *ltdcp); + ltdc_pixfmt_t ltdcFgGetPixelFormat(LTDCDriver *ltdcp); + void ltdcFgSetPixelFormatI(LTDCDriver *ltdcp, ltdc_pixfmt_t fmt); + void ltdcFgSetPixelFormat(LTDCDriver *ltdcp, ltdc_pixfmt_t fmt); + bool ltdcFgIsKeyingEnabledI(LTDCDriver *ltdcp); + bool ltdcFgIsKeyingEnabled(LTDCDriver *ltdcp); + void ltdcFgEnableKeyingI(LTDCDriver *ltdcp); + void ltdcFgEnableKeying(LTDCDriver *ltdcp); + void ltdcFgDisableKeyingI(LTDCDriver *ltdcp); + void ltdcFgDisableKeying(LTDCDriver *ltdcp); + ltdc_color_t ltdcFgGetKeyingColorI(LTDCDriver *ltdcp); + ltdc_color_t ltdcFgGetKeyingColor(LTDCDriver *ltdcp); + void ltdcFgSetKeyingColorI(LTDCDriver *ltdcp, ltdc_color_t c); + void ltdcFgSetKeyingColor(LTDCDriver *ltdcp, ltdc_color_t c); + uint8_t ltdcFgGetConstantAlphaI(LTDCDriver *ltdcp); + uint8_t ltdcFgGetConstantAlpha(LTDCDriver *ltdcp); + void ltdcFgSetConstantAlphaI(LTDCDriver *ltdcp, uint8_t a); + void ltdcFgSetConstantAlpha(LTDCDriver *ltdcp, uint8_t a); + ltdc_color_t ltdcFgGetDefaultColorI(LTDCDriver *ltdcp); + ltdc_color_t ltdcFgGetDefaultColor(LTDCDriver *ltdcp); + void ltdcFgSetDefaultColorI(LTDCDriver *ltdcp, ltdc_color_t c); + void ltdcFgSetDefaultColor(LTDCDriver *ltdcp, ltdc_color_t c); + ltdc_blendf_t ltdcFgGetBlendingFactorsI(LTDCDriver *ltdcp); + ltdc_blendf_t ltdcFgGetBlendingFactors(LTDCDriver *ltdcp); + void ltdcFgSetBlendingFactorsI(LTDCDriver *ltdcp, ltdc_blendf_t bf); + void ltdcFgSetBlendingFactors(LTDCDriver *ltdcp, ltdc_blendf_t bf); + void ltdcFgGetWindowI(LTDCDriver *ltdcp, ltdc_window_t *windowp); + void ltdcFgGetWindow(LTDCDriver *ltdcp, ltdc_window_t *windowp); + void ltdcFgSetWindowI(LTDCDriver *ltdcp, const ltdc_window_t *windowp); + void ltdcFgSetWindow(LTDCDriver *ltdcp, const ltdc_window_t *windowp); + void ltdcFgSetInvalidWindowI(LTDCDriver *ltdcp); + void ltdcFgSetInvalidWindow(LTDCDriver *ltdcp); + void ltdcFgGetFrameI(LTDCDriver *ltdcp, ltdc_frame_t *framep); + void ltdcFgGetFrame(LTDCDriver *ltdcp, ltdc_frame_t *framep); + void ltdcFgSetFrameI(LTDCDriver *ltdcp, const ltdc_frame_t *framep); + void ltdcFgSetFrame(LTDCDriver *ltdcp, const ltdc_frame_t *framep); + void *ltdcFgGetFrameAddressI(LTDCDriver *ltdcp); + void *ltdcFgGetFrameAddress(LTDCDriver *ltdcp); + void ltdcFgSetFrameAddressI(LTDCDriver *ltdcp, void *bufferp); + void ltdcFgSetFrameAddress(LTDCDriver *ltdcp, void *bufferp); + void ltdcFgGetLayerI(LTDCDriver *ltdcp, ltdc_laycfg_t *cfgp); + void ltdcFgGetLayer(LTDCDriver *ltdcp, ltdc_laycfg_t *cfgp); + void ltdcFgSetConfigI(LTDCDriver *ltdcp, const ltdc_laycfg_t *cfgp); + void ltdcFgSetConfig(LTDCDriver *ltdcp, const ltdc_laycfg_t *cfgp); + + /* Helper functions.*/ + size_t ltdcBitsPerPixel(ltdc_pixfmt_t fmt); +#if (TRUE == LTDC_USE_SOFTWARE_CONVERSIONS) || defined(__DOXYGEN__) + ltdc_color_t ltdcFromARGB8888(ltdc_color_t c, ltdc_pixfmt_t fmt); + ltdc_color_t ltdcToARGB8888(ltdc_color_t c, ltdc_pixfmt_t fmt); +#endif /* LTDC_USE_SOFTWARE_CONVERSIONS */ + +#ifdef __cplusplus +} +#endif + +#endif /* STM32_LTDC_USE_LTDC */ + +#endif /* _STM32_LTDC_H_ */ + +/** @} */ diff --git a/os/hal/ports/STM32/LLD/LTDCv1/stm32_ltdc.c b/os/hal/ports/STM32/LLD/LTDCv1/stm32_ltdc.c deleted file mode 100644 index 7037a7c..0000000 --- a/os/hal/ports/STM32/LLD/LTDCv1/stm32_ltdc.c +++ /dev/null @@ -1,3792 +0,0 @@ -/* - Copyright (C) 2013-2015 Andrea Zoppi - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -/** - * @file stm32_ltdc.c - * @brief LCD-TFT Controller Driver. - */ - -#include "ch.h" -#include "hal.h" - -#include "stm32_ltdc.h" - -#if (TRUE == STM32_LTDC_USE_LTDC) || defined(__DOXYGEN__) - -/* TODO: Check preconditions (e.g., LTDC is ready).*/ - -/* Ignore annoying warning messages for actually safe code.*/ -#if defined(__GNUC__) && !defined(__DOXYGEN__) -#pragma GCC diagnostic ignored "-Wtype-limits" -#endif - -/** - * @addtogroup ltdc - * @{ - */ - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -#if !defined(LTDC_LxBFCR_BF) && !defined(__DOXYGEN__) -#define LTDC_LxBFCR_BF (LTDC_LxBFCR_BF1 | LTDC_LxBFCR_BF2) -#endif - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/** - * @brief LTDC1 driver identifier. - */ -LTDCDriver LTDCD1; - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -/** - * @brief Bits per pixel lookup table. - */ -static const uint8_t ltdc_bpp[LTDC_MAX_PIXFMT_ID + 1] = { - 32, /* LTDC_FMT_ARGB8888 */ - 24, /* LTDC_FMT_RGB888 */ - 16, /* LTDC_FMT_RGB565 */ - 16, /* LTDC_FMT_ARGB1555 */ - 16, /* LTDC_FMT_ARGB4444 */ - 8, /* LTDC_FMT_L8 */ - 8, /* LTDC_FMT_AL44 */ - 16 /* LTDC_FMT_AL88 */ -}; - -/** - * @brief Invalid frame. - */ -static const ltdc_frame_t ltdc_invalid_frame = { - NULL, - 1, - 1, - 1, - LTDC_FMT_L8 -}; - -/** - * @brief Invalid window. - * @details Pixel size, located at the origin of the screen. - */ -static const ltdc_window_t ltdc_invalid_window = { - 0, - 1, - 0, - 1 -}; - -/** - * @brief Default layer specifications. - */ -static const ltdc_laycfg_t ltdc_default_laycfg = { - <dc_invalid_frame, - <dc_invalid_window, - LTDC_COLOR_BLACK, - 0x00, - LTDC_COLOR_BLACK, - NULL, - 0, - LTDC_BLEND_FIX1_FIX2, - 0 -}; - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -/** - * @brief Forces LTDC register reload. - * @details Blocking function. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @sclass - * @notapi - */ -static void ltdc_force_reload_s(LTDCDriver *ltdcp) { - - osalDbgCheckClassS(); - osalDbgCheck(ltdcp == <DCD1); - - LTDC->SRCR |= LTDC_SRCR_IMR; - while (LTDC->SRCR & (LTDC_SRCR_IMR | LTDC_SRCR_VBR)) - chSchDoYieldS(); -} - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @name LTDC interrupt handlers - * @{ - */ - -/** - * @brief LTDC event interrupt handler. - * - * @isr - */ -OSAL_IRQ_HANDLER(STM32_LTDC_EV_HANDLER) { - - LTDCDriver *const ltdcp = <DCD1; - thread_t *tp = NULL; - - OSAL_IRQ_PROLOGUE(); - - /* Handle Line Interrupt ISR.*/ - if ((LTDC->ISR & LTDC_ISR_LIF) && (LTDC->IER & LTDC_IER_LIE)) { - osalDbgAssert(ltdcp->config->line_isr != NULL, "invalid state"); - ltdcp->config->line_isr(ltdcp); - LTDC->ICR |= LTDC_ICR_CLIF; - } - - /* Handle Register Reload ISR.*/ - if ((LTDC->ISR & LTDC_ISR_RRIF) && (LTDC->IER & LTDC_IER_RRIE)) { - if (ltdcp->config->rr_isr != NULL) - ltdcp->config->rr_isr(ltdcp); - - osalSysLockFromISR(); - osalDbgAssert(ltdcp->state == LTDC_ACTIVE, "invalid state"); -#if (TRUE == LTDC_USE_WAIT) - /* Wake the waiting thread up.*/ - if (ltdcp->thread != NULL) { - tp = ltdcp->thread; - ltdcp->thread = NULL; - tp->u.rdymsg = MSG_OK; - chSchReadyI(tp); - } -#endif /* LTDC_USE_WAIT */ - ltdcp->state = LTDC_READY; - osalSysUnlockFromISR(); - - LTDC->ICR |= LTDC_ICR_CRRIF; - } - - OSAL_IRQ_EPILOGUE(); -} - -/** - * @brief LTDC error interrupt handler. - * - * @isr - */ -OSAL_IRQ_HANDLER(STM32_LTDC_ER_HANDLER) { - - static LTDCDriver *const ltdcp = <DCD1; - - OSAL_IRQ_PROLOGUE(); - - /* Handle FIFO Underrun ISR.*/ - if ((LTDC->ISR & LTDC_ISR_FUIF) && (LTDC->IER & LTDC_IER_FUIE)) { - osalDbgAssert(ltdcp->config->fuerr_isr != NULL, "invalid state"); - ltdcp->config->fuerr_isr(ltdcp); - LTDC->ICR |= LTDC_ICR_CFUIF; - } - - /* Handle Transfer Error ISR.*/ - if ((LTDC->ISR & LTDC_ISR_TERRIF) && (LTDC->IER & LTDC_IER_TERRIE)) { - osalDbgAssert(ltdcp->config->terr_isr != NULL, "invalid state"); - ltdcp->config->terr_isr(ltdcp); - LTDC->ICR |= LTDC_ICR_CTERRIF; - } - - OSAL_IRQ_EPILOGUE(); -} - -/** @} */ - -/** - * @name LTDC driver-specific methods - * @{ - */ - -/** - * @brief LTDC Driver initialization. - * @details Initializes the LTDC subsystem and chosen drivers. Should be - * called at board initialization. - * - * @init - */ -void ltdcInit(void) { - - /* Reset the LTDC hardware module.*/ - rccResetLTDC(); - - /* Enable the LTDC clock.*/ - RCC->DCKCFGR = (RCC->DCKCFGR & ~RCC_DCKCFGR_PLLSAIDIVR) | (2 << 16); /* /8 */ - rccEnableLTDC(false); - - /* Driver struct initialization.*/ - ltdcObjectInit(<DCD1); - LTDCD1.state = LTDC_STOP; -} - -/** - * @brief Initializes the standard part of a @p LTDCDriver structure. - * - * @param[out] ltdcp pointer to the @p LTDCDriver object - * - * @init - */ -void ltdcObjectInit(LTDCDriver *ltdcp) { - - osalDbgCheck(ltdcp == <DCD1); - - ltdcp->state = LTDC_UNINIT; - ltdcp->config = NULL; - ltdcp->active_window = ltdc_invalid_window; -#if (TRUE == LTDC_USE_WAIT) - ltdcp->thread = NULL; -#endif /* LTDC_USE_WAIT */ -#if (TRUE == LTDC_USE_MUTUAL_EXCLUSION) -#if (TRUE == CH_CFG_USE_MUTEXES) - chMtxObjectInit(<dcp->lock); -#else - chSemObjectInit(<dcp->lock, 1); -#endif -#endif /* LTDC_USE_MUTUAL_EXCLUSION */ -} - -/** - * @brief Get the driver state. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @retun driver state - * - * @iclass - */ -ltdc_state_t ltdcGetStateI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - - return ltdcp->state; -} - -/** - * @brief Get the driver state. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @retun driver state - * - * @api - */ -ltdc_state_t ltdcGetState(LTDCDriver *ltdcp) { - - ltdc_state_t state; - osalSysLock(); - state = ltdcGetStateI(ltdcp); - osalSysUnlock(); - return state; -} - -/** - * @brief Configures and activates the LTDC peripheral. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] configp pointer to the @p LTDCConfig object - * - * @api - */ -void ltdcStart(LTDCDriver *ltdcp, const LTDCConfig *configp) { - - uint32_t hacc, vacc, flags; - - osalSysLock(); - - osalDbgCheck(ltdcp == <DCD1); - osalDbgCheck(configp != NULL); - osalDbgAssert(ltdcp->state == LTDC_STOP, "invalid state"); - - ltdcp->config = configp; - - /* Turn off the controller and its interrupts.*/ - LTDC->GCR = 0; - LTDC->IER = 0; - ltdc_force_reload_s(ltdcp); - - /* Set synchronization params.*/ - osalDbgAssert(configp->hsync_width >= LTDC_MIN_HSYNC_WIDTH, "bounds"); - osalDbgAssert(configp->hsync_width <= LTDC_MAX_HSYNC_WIDTH, "bounds"); - osalDbgAssert(configp->vsync_height >= LTDC_MIN_VSYNC_HEIGHT, "bounds"); - osalDbgAssert(configp->vsync_height <= LTDC_MAX_VSYNC_HEIGHT, "bounds"); - - hacc = configp->hsync_width - 1; - vacc = configp->vsync_height - 1; - - LTDC->SSCR = (((hacc << 16) & LTDC_SSCR_HSW) | - ((vacc << 0) & LTDC_SSCR_VSH)); - - /* Set accumulated back porch params.*/ - osalDbgAssert(configp->hbp_width >= LTDC_MIN_HBP_WIDTH, "bounds"); - osalDbgAssert(configp->hbp_width <= LTDC_MAX_HBP_WIDTH, "bounds"); - osalDbgAssert(configp->vbp_height >= LTDC_MIN_VBP_HEIGHT, "bounds"); - osalDbgAssert(configp->vbp_height <= LTDC_MAX_VBP_HEIGHT, "bounds"); - - hacc += configp->hbp_width; - vacc += configp->vbp_height; - - osalDbgAssert(hacc + 1 >= LTDC_MIN_ACC_HBP_WIDTH, "bounds"); - osalDbgAssert(hacc + 1 <= LTDC_MAX_ACC_HBP_WIDTH, "bounds"); - osalDbgAssert(vacc + 1 >= LTDC_MIN_ACC_VBP_HEIGHT, "bounds"); - osalDbgAssert(vacc + 1 <= LTDC_MAX_ACC_VBP_HEIGHT, "bounds"); - - LTDC->BPCR = (((hacc << 16) & LTDC_BPCR_AHBP) | - ((vacc << 0) & LTDC_BPCR_AVBP)); - - ltdcp->active_window.hstart = hacc + 1; - ltdcp->active_window.vstart = vacc + 1; - - /* Set accumulated active params.*/ - osalDbgAssert(configp->screen_width >= LTDC_MIN_SCREEN_WIDTH, "bounds"); - osalDbgAssert(configp->screen_width <= LTDC_MAX_SCREEN_WIDTH, "bounds"); - osalDbgAssert(configp->screen_height >= LTDC_MIN_SCREEN_HEIGHT, "bounds"); - osalDbgAssert(configp->screen_height <= LTDC_MAX_SCREEN_HEIGHT, "bounds"); - - hacc += configp->screen_width; - vacc += configp->screen_height; - - osalDbgAssert(hacc + 1 >= LTDC_MIN_ACC_ACTIVE_WIDTH, "bounds"); - osalDbgAssert(hacc + 1 <= LTDC_MAX_ACC_ACTIVE_WIDTH, "bounds"); - osalDbgAssert(vacc + 1 >= LTDC_MIN_ACC_ACTIVE_HEIGHT, "bounds"); - osalDbgAssert(vacc + 1 <= LTDC_MAX_ACC_ACTIVE_HEIGHT, "bounds"); - - LTDC->AWCR = (((hacc << 16) & LTDC_AWCR_AAW) | - ((vacc << 0) & LTDC_AWCR_AAH)); - - ltdcp->active_window.hstop = hacc; - ltdcp->active_window.vstop = vacc; - - /* Set accumulated total params.*/ - osalDbgAssert(configp->hfp_width >= LTDC_MIN_HFP_WIDTH, "bounds"); - osalDbgAssert(configp->hfp_width <= LTDC_MAX_HFP_WIDTH, "bounds"); - osalDbgAssert(configp->vfp_height >= LTDC_MIN_VFP_HEIGHT, "bounds"); - osalDbgAssert(configp->vfp_height <= LTDC_MAX_VFP_HEIGHT, "bounds"); - - hacc += configp->hfp_width; - vacc += configp->vfp_height; - - osalDbgAssert(hacc + 1 >= LTDC_MIN_ACC_TOTAL_WIDTH, "bounds"); - osalDbgAssert(hacc + 1 <= LTDC_MAX_ACC_TOTAL_WIDTH, "bounds"); - osalDbgAssert(vacc + 1 >= LTDC_MIN_ACC_TOTAL_HEIGHT, "bounds"); - osalDbgAssert(vacc + 1 <= LTDC_MAX_ACC_TOTAL_HEIGHT, "bounds"); - - LTDC->TWCR = (((hacc << 16) & LTDC_TWCR_TOTALW) | - ((vacc << 0) & LTDC_TWCR_TOTALH)); - - /* Set signal polarities and other flags.*/ - ltdcSetEnableFlagsI(ltdcp, configp->flags & ~LTDC_EF_ENABLE); - - /* Color settings.*/ - ltdcSetClearColorI(ltdcp, configp->clear_color); - - /* Load layer configurations.*/ - ltdcBgSetConfigI(ltdcp, configp->bg_laycfg); - ltdcFgSetConfigI(ltdcp, configp->fg_laycfg); - - /* Enable only the assigned interrupt service routines.*/ - nvicEnableVector(STM32_LTDC_EV_NUMBER, STM32_LTDC_EV_IRQ_PRIORITY); - nvicEnableVector(STM32_LTDC_ER_NUMBER, STM32_LTDC_ER_IRQ_PRIORITY); - - flags = LTDC_IER_RRIE; - if (configp->line_isr != NULL) - flags |= LTDC_IER_LIE; - if (configp->fuerr_isr != NULL) - flags |= LTDC_IER_FUIE; - if (configp->terr_isr != NULL) - flags |= LTDC_IER_TERRIE; - LTDC->IER = flags; - - /* Apply settings.*/ - ltdc_force_reload_s(ltdcp); - - /* Turn on the controller.*/ - LTDC->GCR |= LTDC_GCR_LTDCEN; - ltdc_force_reload_s(ltdcp); - - ltdcp->state = LTDC_READY; - osalSysUnlock(); -} - -/** - * @brief Deactivates the LTDC peripheral. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @api - */ -void ltdcStop(LTDCDriver *ltdcp) { - - osalDbgCheck(ltdcp == <DCD1); - - osalSysLock(); - osalDbgAssert(ltdcp->state == LTDC_READY, "invalid state"); - - /* Turn off the controller and its interrupts.*/ - LTDC->GCR &= ~LTDC_GCR_LTDCEN; - LTDC->IER = 0; -#if (TRUE == LTDC_USE_WAIT) - ltdcReloadS(ltdcp, true); -#else - ltdcStartReloadI(ltdcp, true); - while (ltdcIsReloadingI(ltdcp)) - chSchDoYieldS(); -#endif /* LTDC_USE_WAIT */ - - ltdcp->state = LTDC_STOP; - osalSysUnlock(); -} - -#if (TRUE == LTDC_USE_MUTUAL_EXCLUSION) - -/** - * @brief Gains exclusive access to the LTDC module. - * @details This function tries to gain ownership to the LTDC module, if the - * module is already being used then the invoking thread is queued. - * @pre In order to use this function the option - * @p LTDC_USE_MUTUAL_EXCLUSION must be enabled. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @sclass - */ -void ltdcAcquireBusS(LTDCDriver *ltdcp) { - - osalDbgCheckClassS(); - osalDbgCheck(ltdcp == <DCD1); - -#if (TRUE == CH_CFG_USE_MUTEXES) - chMtxLockS(<dcp->lock); -#else - chSemWaitS(<dcp->lock); -#endif -} - -/** - * @brief Gains exclusive access to the LTDC module. - * @details This function tries to gain ownership to the LTDC module, if the - * module is already being used then the invoking thread is queued. - * @pre In order to use this function the option - * @p LTDC_USE_MUTUAL_EXCLUSION must be enabled. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @api - */ -void ltdcAcquireBus(LTDCDriver *ltdcp) { - - osalSysLock(); - ltdcAcquireBusS(ltdcp); - osalSysUnlock(); -} - -/** - * @brief Releases exclusive access to the LTDC module. - * @pre In order to use this function the option - * @p LTDC_USE_MUTUAL_EXCLUSION must be enabled. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @sclass - */ -void ltdcReleaseBusS(LTDCDriver *ltdcp) { - - osalDbgCheckClassS(); - osalDbgCheck(ltdcp == <DCD1); - -#if (TRUE == CH_CFG_USE_MUTEXES) - chMtxUnlockS(<dcp->lock); -#else - chSemSignalI(<dcp->lock); -#endif -} - -/** - * @brief Releases exclusive access to the LTDC module. - * @pre In order to use this function the option - * @p LTDC_USE_MUTUAL_EXCLUSION must be enabled. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @api - */ -void ltdcReleaseBus(LTDCDriver *ltdcp) { - - osalSysLock(); - ltdcReleaseBusS(ltdcp); - osalSysUnlock(); -} - -#endif /* LTDC_USE_MUTUAL_EXCLUSION */ - -/** @} */ - -/** - * @name LTDC global methods - * @{ - */ - -/** - * @brief Get enabled flags. - * @details Returns all the flags of the LTDC_EF_* group at once. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return enabled flags - * - * @iclass - */ -ltdc_flags_t ltdcGetEnableFlagsI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - return LTDC->GCR & LTDC_EF_MASK; -} - -/** - * @brief Get enabled flags. - * @details Returns all the flags of the LTDC_EF_* group at once. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return enabled flags - * - * @api - */ -ltdc_flags_t ltdcGetEnableFlags(LTDCDriver *ltdcp) { - - ltdc_flags_t flags; - osalSysLock(); - flags = ltdcGetEnableFlagsI(ltdcp); - osalSysUnlock(); - return flags; -} - -/** - * @brief Set enabled flags. - * @details Sets all the flags of the LTDC_EF_* group at once. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] flags enabled flags - * - * @iclass - */ -void ltdcSetEnableFlagsI(LTDCDriver *ltdcp, ltdc_flags_t flags) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - LTDC->GCR = flags & LTDC_EF_MASK; -} - -/** - * @brief Set enabled flags. - * @details Sets all the flags of the LTDC_EF_* group at once. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] flags enabled flags - * - * @api - */ -void ltdcSetEnableFlags(LTDCDriver *ltdcp, ltdc_flags_t flags) { - - osalSysLock(); - ltdcSetEnableFlagsI(ltdcp, flags); - osalSysUnlock(); -} - -/** - * @brief Reloading shadow registers. - * @details Tells whether the LTDC is reloading shadow registers. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return reloading - * - * @iclass - */ -bool ltdcIsReloadingI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - return (LTDC->SRCR & (LTDC_SRCR_IMR | LTDC_SRCR_VBR)) != 0; -} - -/** - * @brief Reloading shadow registers. - * @details Tells whether the LTDC is reloading shadow registers. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return reloading - * - * @api - */ -bool ltdcIsReloading(LTDCDriver *ltdcp) { - - bool reloading; - osalSysLock(); - reloading = ltdcIsReloadingI(ltdcp); - osalSysUnlock(); - return reloading; -} - -/** - * @brief Reload shadow registers. - * @details Starts reloading LTDC shadow registers, upon vsync or immediately. - * @post At the end of the operation the configured callback is invoked. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] immediately reload immediately, not upon vsync - * - * @iclass - */ -void ltdcStartReloadI(LTDCDriver *ltdcp, bool immediately) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - osalDbgAssert(ltdcp->state == LTDC_READY, "not ready"); - (void)ltdcp; - - ltdcp->state = LTDC_ACTIVE; - if (immediately) - LTDC->SRCR |= LTDC_SRCR_IMR; - else - LTDC->SRCR |= LTDC_SRCR_VBR; -} - -/** - * @brief Reload shadow registers. - * @details Starts reloading LTDC shadow registers, upon vsync or immediately. - * @post At the end of the operation the configured callback is invoked. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] immediately reload immediately, not upon vsync - * - * @api - */ -void ltdcStartReload(LTDCDriver *ltdcp, bool immediately) { - - osalSysLock(); - ltdcStartReloadI(ltdcp, immediately); - osalSysUnlock(); -} - -/** - * @brief Reload shadow registers. - * @details Reloads LTDC shadow registers, upon vsync or immediately. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] immediately reload immediately, not upon vsync - * - * @sclass - */ -void ltdcReloadS(LTDCDriver *ltdcp, bool immediately) { - - osalDbgCheckClassS(); - osalDbgCheck(ltdcp == <DCD1); - - ltdcStartReloadI(ltdcp, immediately); - -#if (TRUE == LTDC_USE_WAIT) - osalDbgAssert(ltdcp->thread == NULL, "already waiting"); - - if (immediately) { - while (LTDC->SRCR & LTDC_SRCR_IMR) - chSchDoYieldS(); - ltdcp->state = LTDC_READY; - } else { - ltdcp->thread = chThdGetSelfX(); - chSchGoSleepS(CH_STATE_SUSPENDED); - } -#else - while (LTDC->SRCR & LTDC_SRCR_IMR) - chSchDoYieldS(); - ltdcp->state = LTDC_READY; -#endif -} - -/** - * @brief Reload shadow registers. - * @details Reloads LTDC shadow registers, upon vsync or immediately. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] immediately reload immediately, not upon vsync - * - * @api - */ -void ltdcReload(LTDCDriver *ltdcp, bool immediately) { - - osalSysLock(); - ltdcReloadS(ltdcp, immediately); - osalSysUnlock(); -} - -/** - * @brief Dithering enabled. - * @details Tells whether the dithering is enabled. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return enabled - * - * @iclass - */ -bool ltdcIsDitheringEnabledI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - return (LTDC->GCR & LTDC_GCR_DTEN) != 0; -} - -/** - * @brief Dithering enabled. - * @details Tells whether the dithering is enabled. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return enabled - * - * @api - */ -bool ltdcIsDitheringEnabled(LTDCDriver *ltdcp) { - - bool enabled; - osalSysLock(); - enabled = ltdcIsDitheringEnabledI(ltdcp); - osalSysUnlock(); - return enabled; -} - -/** - * @brief Enable dithering. - * @details Enables dithering capabilities for pixel formats with less than - * 8 bits per channel. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @iclass - */ -void ltdcEnableDitheringI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - LTDC->GCR |= LTDC_GCR_DTEN; -} - -/** - * @brief Enable dithering. - * @details Enables dithering capabilities for pixel formats with less than - * 8 bits per channel. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @api - */ -void ltdcEnableDithering(LTDCDriver *ltdcp) { - - osalSysLock(); - ltdcEnableDitheringI(ltdcp); - osalSysUnlock(); -} - -/** - * @brief Disable dithering. - * @details Disables dithering capabilities for pixel formats with less than - * 8 bits per channel. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @iclass - */ -void ltdcDisableDitheringI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - LTDC->GCR &= ~LTDC_GCR_DTEN; -} - -/** - * @brief Disable dithering. - * @details Disables dithering capabilities for pixel formats with less than - * 8 bits per channel. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @api - */ -void ltdcDisableDithering(LTDCDriver *ltdcp) { - - osalSysLock(); - ltdcDisableDitheringI(ltdcp); - osalSysUnlock(); -} - -/** - * @brief Get clear screen color. - * @details Gets the clear screen (actual background) color. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return clear screen color, RGB-888 - * - * @iclass - */ -ltdc_color_t ltdcGetClearColorI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - return (ltdc_color_t)(LTDC->BCCR & 0x00FFFFFF); -} - -/** - * @brief Get clear screen color. - * @details Gets the clear screen (actual background) color. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return clear screen color, RGB-888 - * - * @api - */ -ltdc_color_t ltdcGetClearColor(LTDCDriver *ltdcp) { - - ltdc_color_t color; - osalSysLock(); - color = ltdcGetClearColorI(ltdcp); - osalSysUnlock(); - return color; -} - -/** - * @brief Set clear screen color. - * @details Sets the clear screen (actual background) color. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] c clear screen color, RGB-888 - * - * @iclass - */ -void ltdcSetClearColorI(LTDCDriver *ltdcp, ltdc_color_t c) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - LTDC->BCCR = (LTDC->BCCR & ~0x00FFFFFF) | (c & 0x00FFFFFF); -} - -/** - * @brief Set clear screen color. - * @details Sets the clear screen (actual background) color. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] c clear screen color, RGB-888 - * - * @api - */ -void ltdcSetClearColor(LTDCDriver *ltdcp, ltdc_color_t c) { - - osalSysLock(); - ltdcSetClearColorI(ltdcp, c); - osalSysUnlock(); -} - -/** - * @brief Get line interrupt position. - * @details Gets the line interrupt position. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return line interrupt position - * - * @iclass - */ -uint16_t ltdcGetLineInterruptPosI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - return (uint16_t)(LTDC->LIPCR & LTDC_LIPCR_LIPOS); -} - -/** - * @brief Get line interrupt position. - * @details Gets the line interrupt position. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return line interrupt position - * - * @api - */ -uint16_t ltdcGetLineInterruptPos(LTDCDriver *ltdcp) { - - uint16_t line; - osalSysLock(); - line = ltdcGetLineInterruptPosI(ltdcp); - osalSysUnlock(); - return line; -} - -/** - * @brief Set line interrupt position. - * @details Sets the line interrupt position. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @iclass - */ -void ltdcSetLineInterruptPosI(LTDCDriver *ltdcp, uint16_t line) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - LTDC->LIPCR = ((LTDC->LIPCR & ~LTDC_LIPCR_LIPOS) | - ((uint32_t)line & LTDC_LIPCR_LIPOS)); -} - -/** - * @brief Set line interrupt position. - * @details Sets the line interrupt position. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @api - */ -void ltdcSetLineInterruptPos(LTDCDriver *ltdcp, uint16_t line) { - - osalSysLock(); - ltdcSetLineInterruptPosI(ltdcp, line); - osalSysUnlock(); -} - -/** - * @brief Line interrupt enabled. - * @details Tells whether the line interrupt is enabled. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return enabled - * - * @iclass - */ -bool ltdcIsLineInterruptEnabledI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - return (LTDC->IER & LTDC_IER_LIE) != 0; -} - -/** - * @brief Line interrupt enabled. - * @details Tells whether the line interrupt is enabled. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return enabled - * - * @api - */ -bool ltdcIsLineInterruptEnabled(LTDCDriver *ltdcp) { - - bool enabled; - osalSysLock(); - enabled = ltdcIsLineInterruptEnabledI(ltdcp); - osalSysUnlock(); - return enabled; -} - -/** - * @brief Enable line interrupt. - * @details Enables line interrupt. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @iclass - */ -void ltdcEnableLineInterruptI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - LTDC->IER |= LTDC_IER_LIE; -} - -/** - * @brief Enable line interrupt. - * @details Enables line interrupt. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @api - */ -void ltdcEnableLineInterrupt(LTDCDriver *ltdcp) { - - osalSysLock(); - ltdcEnableLineInterruptI(ltdcp); - osalSysUnlock(); -} - -/** - * @brief Disable line interrupt. - * @details Disables line interrupt. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @iclass - */ -void ltdcDisableLineInterruptI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - LTDC->IER &= ~LTDC_IER_LIE; -} - -/** - * @brief Disable line interrupt. - * @details Disables line interrupt. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @api - */ -void ltdcDisableLineInterrupt(LTDCDriver *ltdcp) { - - osalSysLock(); - ltdcDisableLineInterruptI(ltdcp); - osalSysUnlock(); -} - -/** - * @brief Get current position. - * @details Gets the current position. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[out] xp pointer to the destination horizontal coordinate - * @param[out] yp pointer to the destination vertical coordinate - * - * @iclass - */ -void ltdcGetCurrentPosI(LTDCDriver *ltdcp, uint16_t *xp, uint16_t *yp) { - - const uint32_t r = LTDC->CPSR; - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - *xp = (uint16_t)((r & LTDC_CPSR_CXPOS) >> 16); - *yp = (uint16_t)((r & LTDC_CPSR_CYPOS) >> 0); -} - -/** - * @brief Get current position. - * @details Gets the current position. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[out] xp pointer to the destination horizontal coordinate - * @param[out] yp pointer to the destination vertical coordinate - * - * @api - */ -void ltdcGetCurrentPos(LTDCDriver *ltdcp, uint16_t *xp, uint16_t *yp) { - - osalSysLock(); - ltdcGetCurrentPosI(ltdcp, xp, yp); - osalSysUnlock(); -} - -/** @} */ - -/** - * @name LTDC background layer (layer 1) methods - * @{ - */ - -/** - * @brief Get background layer enabled flags. - * @details Returns all the flags of the LTDC_LEF_* group at once. - * Targeting the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return enabled flags - * - * @iclass - */ -ltdc_flags_t ltdcBgGetEnableFlagsI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - return LTDC_Layer1->CR & LTDC_LEF_MASK; -} - -/** - * @brief Get background layer enabled flags. - * @details Returns all the flags of the LTDC_LEF_* group at once. - * Targeting the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return enabled flags - * - * @api - */ -ltdc_flags_t ltdcBgGetEnableFlags(LTDCDriver *ltdcp) { - - ltdc_flags_t flags; - osalSysLock(); - flags = ltdcBgGetEnableFlagsI(ltdcp); - osalSysUnlock(); - return flags; -} - -/** - * @brief Set background layer enabled flags. - * @details Sets all the flags of the LTDC_LEF_* group at once. - * Targeting the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] flags enabled flags - * - * @iclass - */ -void ltdcBgSetEnableFlagsI(LTDCDriver *ltdcp, ltdc_flags_t flags) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - LTDC_Layer1->CR = ((LTDC_Layer1->CR & ~LTDC_LEF_MASK) | - ((uint32_t)flags & LTDC_LEF_MASK)); -} - -/** - * @brief Set background layer enabled flags. - * @details Sets all the flags of the LTDC_LEF_* group at once. - * Targeting the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] flags enabled flags - * - * @api - */ -void ltdcBgSetEnableFlags(LTDCDriver *ltdcp, ltdc_flags_t flags) { - - osalSysLock(); - ltdcBgSetEnableFlagsI(ltdcp, flags); - osalSysUnlock(); -} - -/** - * @brief Background layer enabled. - * @details Tells whether the background layer (layer 1) is enabled. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return enabled - * - * @iclass - */ -bool ltdcBgIsEnabledI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - return (LTDC_Layer1->CR & ~LTDC_LxCR_LEN) != 0; -} - -/** - * @brief Background layer enabled. - * @details Tells whether the background layer (layer 1) is enabled. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return enabled - * - * @api - */ -bool ltdcBgIsEnabled(LTDCDriver *ltdcp) { - - bool enabled; - osalSysLock(); - enabled = ltdcBgIsEnabledI(ltdcp); - osalSysUnlock(); - return enabled; -} - -/** - * @brief Background layer enable. - * @details Enables the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @iclass - */ -void ltdcBgEnableI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - LTDC_Layer1->CR |= LTDC_LxCR_LEN; -} - -/** - * @brief Background layer enable. - * @details Enables the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @api - */ -void ltdcBgEnable(LTDCDriver *ltdcp) { - - osalSysLock(); - ltdcBgEnableI(ltdcp); - osalSysUnlock(); -} - -/** - * @brief Background layer disable. - * @details Disables the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @iclass - */ -void ltdcBgDisableI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - LTDC_Layer1->CR &= ~LTDC_LxCR_LEN; -} - -/** - * @brief Background layer disable. - * @details Disables the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @api - */ -void ltdcBgDisable(LTDCDriver *ltdcp) { - - osalSysLock(); - ltdcBgDisableI(ltdcp); - osalSysUnlock(); -} - -/** - * @brief Background layer palette enabled. - * @details Tells whether the background layer (layer 1) palette (color lookup - * table) is enabled. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return enabled - * - * @iclass - */ -bool ltdcBgIsPaletteEnabledI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - return (LTDC_Layer1->CR & ~LTDC_LxCR_CLUTEN) != 0; -} - -/** - * @brief Background layer palette enabled. - * @details Tells whether the background layer (layer 1) palette (color lookup - * table) is enabled. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return enabled - * - * @api - */ -bool ltdcBgIsPaletteEnabled(LTDCDriver *ltdcp) { - - bool enabled; - osalSysLock(); - enabled = ltdcBgIsPaletteEnabledI(ltdcp); - osalSysUnlock(); - return enabled; -} - -/** - * @brief Enable background layer palette. - * @details Enables the palette (color lookup table) of the background layer - * (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @iclass - */ -void ltdcBgEnablePaletteI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - LTDC_Layer1->CR |= LTDC_LxCR_CLUTEN; -} - -/** - * @brief Enable background layer palette. - * @details Enables the palette (color lookup table) of the background layer - * (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @api - */ -void ltdcBgEnablePalette(LTDCDriver *ltdcp) { - - osalSysLock(); - ltdcBgEnablePaletteI(ltdcp); - osalSysUnlock(); -} - -/** - * @brief Disable background layer palette. - * @details Disables the palette (color lookup table) of the background layer - * (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @iclass - */ -void ltdcBgDisablePaletteI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - LTDC_Layer1->CR &= ~LTDC_LxCR_CLUTEN; -} - -/** - * @brief Disable background layer palette. - * @details Disables the palette (color lookup table) of the background layer - * (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @api - */ -void ltdcBgDisablePalette(LTDCDriver *ltdcp) { - - osalSysLock(); - ltdcBgDisablePaletteI(ltdcp); - osalSysUnlock(); -} - -/** - * @brief Set background layer palette color. - * @details Sets the color of a palette (color lookup table) slot to the - * background layer (layer 1). - * @pre The layer must be disabled. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] slot palette slot - * @param[in] c color, RGB-888 - * - * @iclass - */ -void ltdcBgSetPaletteColorI(LTDCDriver *ltdcp, uint8_t slot, ltdc_color_t c) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - osalDbgAssert(!ltdcBgIsEnabledI(ltdcp), "invalid state"); - (void)ltdcp; - - LTDC_Layer1->CLUTWR = (((uint32_t)slot << 24) | (c & 0x00FFFFFF)); -} - -/** - * @brief Set background layer palette color. - * @details Sets the color of a palette (color lookup table) slot to the - * background layer (layer 1). - * @pre The layer must be disabled. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] slot palette slot - * @param[in] c color, RGB-888 - * - * @api - */ -void ltdcBgSetPaletteColor(LTDCDriver *ltdcp, uint8_t slot, ltdc_color_t c) { - - osalSysLock(); - ltdcBgSetPaletteColorI(ltdcp, slot, c); - osalSysUnlock(); -} - -/** - * @brief Set background layer palette. - * @details Sets the entire palette color (color lookup table) slot. - * @pre The layer must be disabled. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] colors array of palette colors, RGB-888 - * @param[in] length number of palette colors - * - * @iclass - */ -void ltdcBgSetPaletteI(LTDCDriver *ltdcp, const ltdc_color_t colors[], - uint16_t length) { - - uint16_t i; - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - osalDbgCheck((colors == NULL) == (length == 0)); - osalDbgAssert(length <= LTDC_MAX_PALETTE_LENGTH, "bounds"); - osalDbgAssert(!ltdcBgIsEnabledI(ltdcp), "invalid state"); - (void)ltdcp; - - for (i = 0; i < length; ++i) - LTDC_Layer1->CLUTWR = (((uint32_t)i << 24) | (colors[i] & 0x00FFFFFF)); -} - -/** - * @brief Set background layer palette. - * @details Sets the entire palette color (color lookup table) slot. - * @pre The layer must be disabled. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] colors array of palette colors, RGB-888 - * @param[in] length number of palette colors - * - * @api - */ -void ltdcBgSetPalette(LTDCDriver *ltdcp, const ltdc_color_t colors[], - uint16_t length) { - - osalSysLock(); - ltdcBgSetPaletteI(ltdcp, colors, length); - osalSysUnlock(); -} - -/** - * @brief Get background layer pixel format. - * @details Gets the pixel format of the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return pixel format - * - * @iclass - */ -ltdc_pixfmt_t ltdcBgGetPixelFormatI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - return (ltdc_pixfmt_t)(LTDC_Layer1->PFCR & LTDC_LxPFCR_PF); -} - -/** - * @brief Get background layer pixel format. - * @details Gets the pixel format of the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return pixel format - * - * @api - */ -ltdc_pixfmt_t ltdcBgGetPixelFormat(LTDCDriver *ltdcp) { - - ltdc_pixfmt_t fmt; - osalSysLock(); - fmt = ltdcBgGetPixelFormatI(ltdcp); - osalSysUnlock(); - return fmt; -} - -/** - * @brief Set background layer pixel format. - * @details Sets the pixel format of the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] fmt pixel format - * - * @iclass - */ -void ltdcBgSetPixelFormatI(LTDCDriver *ltdcp, ltdc_pixfmt_t fmt) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - osalDbgAssert(fmt >= LTDC_MIN_PIXFMT_ID, "bounds"); - osalDbgAssert(fmt <= LTDC_MAX_PIXFMT_ID, "bounds"); - (void)ltdcp; - - LTDC_Layer1->PFCR = ((LTDC_Layer1->PFCR & ~LTDC_LxPFCR_PF) | - ((uint32_t)fmt & LTDC_LxPFCR_PF)); -} - -/** - * @brief Set background layer pixel format. - * @details Sets the pixel format of the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] fmt pixel format - * - * @api - */ -void ltdcBgSetPixelFormat(LTDCDriver *ltdcp, ltdc_pixfmt_t fmt) { - - osalSysLock(); - ltdcBgSetPixelFormatI(ltdcp, fmt); - osalSysUnlock(); -} - -/** - * @brief Background layer color keying enabled. - * @details Tells whether the background layer (layer 1) has color keying - * enabled. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return enabled - * - * @iclass - */ -bool ltdcBgIsKeyingEnabledI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - return (LTDC_Layer1->CR & ~LTDC_LxCR_COLKEN) != 0; -} - -/** - * @brief Background layer color keying enabled. - * @details Tells whether the background layer (layer 1) has color keying - * enabled. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return enabled - * - * @api - */ -bool ltdcBgIsKeyingEnabled(LTDCDriver *ltdcp) { - - bool enabled; - osalSysLock(); - enabled = ltdcBgIsKeyingEnabledI(ltdcp); - osalSysUnlock(); - return enabled; -} - -/** - * @brief Enable background layer color keying. - * @details Enables color keying capabilities of the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @iclass - */ -void ltdcBgEnableKeyingI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - LTDC_Layer1->CR |= LTDC_LxCR_COLKEN; -} - -/** - * @brief Enable background layer color keying. - * @details Enables color keying capabilities of the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @api - */ -void ltdcBgEnableKeying(LTDCDriver *ltdcp) { - - osalSysLock(); - ltdcBgEnableKeyingI(ltdcp); - osalSysUnlock(); -} - -/** - * @brief Disable background layer color keying. - * @details Disables color keying capabilities of the background layer (layer - * 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @iclass - */ -void ltdcBgDisableKeyingI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - LTDC_Layer1->CR &= ~LTDC_LxCR_COLKEN; -} - -/** - * @brief Disable background layer color keying. - * @details Disables color keying capabilities of the background layer (layer - * 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @api - */ -void ltdcBgDisableKeying(LTDCDriver *ltdcp) { - - osalSysLock(); - ltdcBgDisableKeyingI(ltdcp); - osalSysUnlock(); -} - -/** - * @brief Get background layer color key. - * @details Gets the color key of the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return color key, RGB-888 - * - * @iclass - */ -ltdc_color_t ltdcBgGetKeyingColorI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - return (ltdc_color_t)(LTDC_Layer1->CKCR & 0x00FFFFFF); -} - -/** - * @brief Get background layer color key. - * @details Gets the color key of the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return color key, RGB-888 - * - * @api - */ -ltdc_color_t ltdcBgGetKeyingColor(LTDCDriver *ltdcp) { - - ltdc_color_t color; - osalSysLock(); - color = ltdcBgGetKeyingColorI(ltdcp); - osalSysUnlock(); - return color; -} - -/** - * @brief Set background layer color key. - * @details Sets the color key of the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] c color key, RGB-888 - * - * @iclass - */ -void ltdcBgSetKeyingColorI(LTDCDriver *ltdcp, ltdc_color_t c) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - LTDC_Layer1->CKCR = ((LTDC_Layer1->CKCR & ~0x00FFFFFF) | - ((uint32_t)c & 0x00FFFFFF)); -} - -/** - * @brief Set background layer color key. - * @details Sets the color key of the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] c color key, RGB-888 - * - * @api - */ -void ltdcBgSetKeyingColor(LTDCDriver *ltdcp, ltdc_color_t c) { - - osalSysLock(); - ltdcBgSetKeyingColorI(ltdcp, c); - osalSysUnlock(); -} - -/** - * @brief Get background layer constant alpha. - * @details Gets the constant alpha component of the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return constant alpha component, A-8 - * - * @iclass - */ -uint8_t ltdcBgGetConstantAlphaI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - return (uint8_t)(LTDC_Layer1->CACR & LTDC_LxCACR_CONSTA); -} - -/** - * @brief Get background layer constant alpha. - * @details Gets the constant alpha component of the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return constant alpha component, A-8 - * - * @api - */ -uint8_t ltdcBgGetConstantAlpha(LTDCDriver *ltdcp) { - - uint8_t a; - osalSysLock(); - a = ltdcBgGetConstantAlphaI(ltdcp); - osalSysUnlock(); - return a; -} - -/** - * @brief Set background layer constant alpha. - * @details Sets the constant alpha component of the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] a constant alpha component, A-8 - * - * @iclass - */ -void ltdcBgSetConstantAlphaI(LTDCDriver *ltdcp, uint8_t a) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - LTDC_Layer1->CACR = ((LTDC_Layer1->CACR & ~LTDC_LxCACR_CONSTA) | - ((uint32_t)a & LTDC_LxCACR_CONSTA)); -} - -/** - * @brief Set background layer constant alpha. - * @details Sets the constant alpha component of the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] a constant alpha component, A-8 - * - * @api - */ -void ltdcBgSetConstantAlpha(LTDCDriver *ltdcp, uint8_t a) { - - osalSysLock(); - ltdcBgSetConstantAlphaI(ltdcp, a); - osalSysUnlock(); -} - -/** - * @brief Get background layer default color. - * @details Gets the default color of the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return default color, RGB-888 - * - * @iclass - */ -ltdc_color_t ltdcBgGetDefaultColorI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - return (ltdc_color_t)LTDC_Layer1->DCCR; -} - -/** - * @brief Get background layer default color. - * @details Gets the default color of the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return default color, RGB-888 - * - * @api - */ -ltdc_color_t ltdcBgGetDefaultColor(LTDCDriver *ltdcp) { - - ltdc_color_t color; - osalSysLock(); - color = ltdcBgGetDefaultColorI(ltdcp); - osalSysUnlock(); - return color; -} - -/** - * @brief Set background layer default color. - * @details Sets the default color of the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] c default color, RGB-888 - * - * @iclass - */ -void ltdcBgSetDefaultColorI(LTDCDriver *ltdcp, ltdc_color_t c) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - LTDC_Layer1->DCCR = (uint32_t)c; -} - -/** - * @brief Set background layer default color. - * @details Sets the default color of the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] c default color, RGB-888 - * - * @api - */ -void ltdcBgSetDefaultColor(LTDCDriver *ltdcp, ltdc_color_t c) { - - osalSysLock(); - ltdcBgSetDefaultColorI(ltdcp, c); - osalSysUnlock(); -} - -/** - * @brief Get background layer blending factors. - * @details Gets the blending factors of the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return blending factors - * - * @iclass - */ -ltdc_blendf_t ltdcBgGetBlendingFactorsI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - return (ltdc_blendf_t)(LTDC_Layer1->BFCR & LTDC_LxBFCR_BF); -} - -/** - * @brief Get background layer blending factors. - * @details Gets the blending factors of the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return blending factors - * - * @api - */ -ltdc_blendf_t ltdcBgGetBlendingFactors(LTDCDriver *ltdcp) { - - ltdc_blendf_t bf; - osalSysLock(); - bf = ltdcBgGetBlendingFactorsI(ltdcp); - osalSysUnlock(); - return bf; -} - -/** - * @brief Set background layer blending factors. - * @details Sets the blending factors of the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] factors blending factors - * - * @iclass - */ -void ltdcBgSetBlendingFactorsI(LTDCDriver *ltdcp, ltdc_blendf_t bf) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - LTDC_Layer1->BFCR = ((LTDC_Layer1->BFCR & ~LTDC_LxBFCR_BF) | - ((uint32_t)bf & LTDC_LxBFCR_BF)); -} - -/** - * @brief Set background layer blending factors. - * @details Sets the blending factors of the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] factors blending factors - * - * @api - */ -void ltdcBgSetBlendingFactors(LTDCDriver *ltdcp, ltdc_blendf_t bf) { - - osalSysLock(); - ltdcBgSetBlendingFactorsI(ltdcp, bf); - osalSysUnlock(); -} - -/** - * @brief Get background layer window specs. - * @details Gets the window specifications of the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[out] windowp pointer to the window specifications - * - * @iclass - */ -void ltdcBgGetWindowI(LTDCDriver *ltdcp, ltdc_window_t *windowp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - osalDbgCheck(windowp != NULL); - (void)ltdcp; - - windowp->hstart = - (uint16_t)((LTDC_Layer1->WHPCR & LTDC_LxWHPCR_WHSTPOS) >> 0); - windowp->hstop = - (uint16_t)((LTDC_Layer1->WHPCR & LTDC_LxWHPCR_WHSPPOS) >> 16); - windowp->vstart = - (uint16_t)((LTDC_Layer1->WVPCR & LTDC_LxWVPCR_WVSTPOS) >> 0); - windowp->vstop = - (uint16_t)((LTDC_Layer1->WVPCR & LTDC_LxWVPCR_WVSPPOS) >> 16); -} - -/** - * @brief Get background layer window specs. - * @details Gets the window specifications of the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[out] windowp pointer to the window specifications - * - * @api - */ -void ltdcBgGetWindow(LTDCDriver *ltdcp, ltdc_window_t *windowp) { - - osalSysLock(); - ltdcBgGetWindowI(ltdcp, windowp); - osalSysUnlock(); -} - -/** - * @brief Set background layer window specs. - * @details Sets the window specifications of the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] windowp pointer to the window specifications - * - * @iclass - */ -void ltdcBgSetWindowI(LTDCDriver *ltdcp, const ltdc_window_t *windowp) { - - uint32_t start, stop; - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - osalDbgCheck(windowp != NULL); - (void)ltdcp; - - osalDbgAssert(windowp->hstop < ltdcp->config->screen_width, "bounds"); - osalDbgAssert(windowp->vstop < ltdcp->config->screen_height, "bounds"); - - /* Horizontal boundaries.*/ - start = (uint32_t)windowp->hstart + ltdcp->active_window.hstart; - stop = (uint32_t)windowp->hstop + ltdcp->active_window.hstart; - - osalDbgAssert(start >= ltdcp->active_window.hstart, "bounds"); - osalDbgAssert(stop <= ltdcp->active_window.hstop, "bounds"); - - LTDC_Layer1->WHPCR = (((start << 0) & LTDC_LxWHPCR_WHSTPOS) | - ((stop << 16) & LTDC_LxWHPCR_WHSPPOS)); - - /* Vertical boundaries.*/ - start = (uint32_t)windowp->vstart + ltdcp->active_window.vstart; - stop = (uint32_t)windowp->vstop + ltdcp->active_window.vstart; - - osalDbgAssert(start >= ltdcp->active_window.vstart, "bounds"); - osalDbgAssert(stop <= ltdcp->active_window.vstop, "bounds"); - - LTDC_Layer1->WVPCR = (((start << 0) & LTDC_LxWVPCR_WVSTPOS) | - ((stop << 16) & LTDC_LxWVPCR_WVSPPOS)); -} - -/** - * @brief Set background layer window specs. - * @details Sets the window specifications of the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] windowp pointer to the window specifications - * - * @api - */ -void ltdcBgSetWindow(LTDCDriver *ltdcp, const ltdc_window_t *windowp) { - - osalSysLock(); - ltdcBgSetWindowI(ltdcp, windowp); - osalSysUnlock(); -} - -/** - * @brief Set background layer window as invalid. - * @details Sets the window specifications of the background layer (layer 1) - * so that the window is pixel sized at the screen origin. - * @note Useful before reconfiguring the frame specifications of the layer, - * to avoid errors. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @iclass - */ -void ltdcBgSetInvalidWindowI(LTDCDriver *ltdcp) { - - ltdcBgSetWindowI(ltdcp, <dc_invalid_window); -} - -/** - * @brief Set background layer window as invalid. - * @details Sets the window specifications of the background layer (layer 1) - * so that the window is pixel sized at the screen origin. - * @note Useful before reconfiguring the frame specifications of the layer, - * to avoid errors. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @api - */ -void ltdcBgSetInvalidWindow(LTDCDriver *ltdcp) { - - osalSysLock(); - ltdcBgSetWindowI(ltdcp, <dc_invalid_window); - osalSysUnlock(); -} - -/** - * @brief Get background layer frame buffer specs. - * @details Gets the frame buffer specifications of the background layer - * (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[out] framep pointer to the frame buffer specifications - * - * @iclass - */ -void ltdcBgGetFrameI(LTDCDriver *ltdcp, ltdc_frame_t *framep) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - osalDbgCheck(framep != NULL); - - framep->bufferp = (void *)(LTDC_Layer1->CFBAR & LTDC_LxCFBAR_CFBADD); - framep->pitch = (size_t)((LTDC_Layer1->CFBLR & LTDC_LxCFBLR_CFBP) >> 16); - framep->width = (uint16_t)(((LTDC_Layer1->CFBLR & LTDC_LxCFBLR_CFBLL) - 3) / - ltdcBytesPerPixel(ltdcBgGetPixelFormatI(ltdcp))); - framep->height = (uint16_t)(LTDC_Layer1->CFBLNR & LTDC_LxCFBLNR_CFBLNBR); -} - -/** - * @brief Get background layer frame buffer specs. - * @details Gets the frame buffer specifications of the background layer - * (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[out] framep pointer to the frame buffer specifications - * - * @api - */ -void ltdcBgGetFrame(LTDCDriver *ltdcp, ltdc_frame_t *framep) { - - osalSysLock(); - ltdcBgGetFrameI(ltdcp, framep); - osalSysUnlock(); -} - -/** - * @brief Set background layer frame buffer specs. - * @details Sets the frame buffer specifications of the background layer - * (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] framep pointer to the frame buffer specifications - * - * @iclass - */ -void ltdcBgSetFrameI(LTDCDriver *ltdcp, const ltdc_frame_t *framep) { - - size_t linesize; - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - osalDbgCheck(framep != NULL); - - ltdcBgSetPixelFormatI(ltdcp, framep->fmt); - - linesize = ltdcBytesPerPixel(framep->fmt) * framep->width; - - osalDbgAssert(framep->width <= ltdcp->config->screen_width, "bounds"); - osalDbgAssert(framep->height <= ltdcp->config->screen_height, "bounds"); - osalDbgAssert(linesize >= LTDC_MIN_FRAME_WIDTH_BYTES, "bounds"); - osalDbgAssert(linesize <= LTDC_MAX_FRAME_WIDTH_BYTES, "bounds"); - osalDbgAssert(framep->height >= LTDC_MIN_FRAME_HEIGHT_LINES, "bounds"); - osalDbgAssert(framep->height <= LTDC_MAX_FRAME_HEIGHT_LINES, "bounds"); - osalDbgAssert(framep->pitch >= linesize, "bounds"); - - LTDC_Layer1->CFBAR = (uint32_t)framep->bufferp & LTDC_LxCFBAR_CFBADD; - LTDC_Layer1->CFBLR = ((((uint32_t)framep->pitch << 16) & LTDC_LxCFBLR_CFBP) | - ((linesize + 3) & LTDC_LxCFBLR_CFBLL)); - LTDC_Layer1->CFBLNR = (uint32_t)framep->height & LTDC_LxCFBLNR_CFBLNBR; -} - -/** - * @brief Set background layer frame buffer specs. - * @details Sets the frame buffer specifications of the background layer - * (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] framep pointer to the frame buffer specifications - * - * @api - */ -void ltdcBgSetFrame(LTDCDriver *ltdcp, const ltdc_frame_t *framep) { - - osalSysLock(); - ltdcBgSetFrameI(ltdcp, framep); - osalSysUnlock(); -} - -/** - * @brief Get background layer frame buffer address. - * @details Gets the frame buffer address of the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return frame buffer address - * - * @iclass - */ -void *ltdcBgGetFrameAddressI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - return (void *)LTDC_Layer1->CFBAR; -} - -/** - * @brief Get background layer frame buffer address. - * @details Gets the frame buffer address of the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return frame buffer address - * - * @api - */ -void *ltdcBgGetFrameAddress(LTDCDriver *ltdcp) { - - void *bufferp; - osalSysLock(); - bufferp = ltdcBgGetFrameAddressI(ltdcp); - osalSysUnlock(); - return bufferp; -} - -/** - * @brief Set background layer frame buffer address. - * @details Sets the frame buffer address of the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] bufferp frame buffer address - * - * @iclass - */ -void ltdcBgSetFrameAddressI(LTDCDriver *ltdcp, void *bufferp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - LTDC_Layer1->CFBAR = (uint32_t)bufferp; -} - -/** - * @brief Set background layer frame buffer address. - * @details Sets the frame buffer address of the background layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] bufferp frame buffer address - * - * @api - */ -void ltdcBgSetFrameAddress(LTDCDriver *ltdcp, void *bufferp) { - - osalSysLock(); - ltdcBgSetFrameAddressI(ltdcp, bufferp); - osalSysUnlock(); -} - -/** - * @brief Get background layer specifications. - * @details Gets the background layer (layer 1) specifications at once. - * @note If palette specifications cannot be retrieved, they are set to - * @p NULL. This is not an error. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[out] cfgp pointer to the layer specifications - * - * @iclass - */ -void ltdcBgGetLayerI(LTDCDriver *ltdcp, ltdc_laycfg_t *cfgp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - osalDbgCheck(cfgp != NULL); - - ltdcBgGetFrameI(ltdcp, (ltdc_frame_t *)cfgp->frame); - ltdcBgGetWindowI(ltdcp, (ltdc_window_t *)cfgp->window); - cfgp->def_color = ltdcBgGetDefaultColorI(ltdcp); - cfgp->key_color = ltdcBgGetKeyingColorI(ltdcp); - cfgp->const_alpha = ltdcBgGetConstantAlphaI(ltdcp); - cfgp->blending = ltdcBgGetBlendingFactorsI(ltdcp); - - cfgp->pal_colors = NULL; - cfgp->pal_length = 0; - - cfgp->flags = ltdcBgGetEnableFlagsI(ltdcp); -} - -/** - * @brief Get background layer specifications. - * @details Gets the background layer (layer 1) specifications at once. - * @note If palette specifications cannot be retrieved, they are set to - * @p NULL. This is not an error. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[out] cfgp pointer to the layer specifications - * - * @api - */ -void ltdcBgGetLayer(LTDCDriver *ltdcp, ltdc_laycfg_t *cfgp) { - - osalSysLock(); - ltdcBgGetLayerI(ltdcp, cfgp); - osalSysUnlock(); -} - -/** - * @brief Set background layer specifications. - * @details Sets the background layer (layer 1) specifications at once. - * @note If the palette is unspecified, the layer palette is unmodified. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] cfgp pointer to the layer specifications - * - * @iclass - */ -void ltdcBgSetConfigI(LTDCDriver *ltdcp, const ltdc_laycfg_t *cfgp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - - if (cfgp == NULL) - cfgp = <dc_default_laycfg; - - osalDbgCheck((cfgp->pal_colors == NULL) == (cfgp->pal_length == 0)); - - ltdcBgSetFrameI(ltdcp, cfgp->frame); - ltdcBgSetWindowI(ltdcp, cfgp->window); - ltdcBgSetDefaultColorI(ltdcp, cfgp->def_color); - ltdcBgSetKeyingColorI(ltdcp, cfgp->key_color); - ltdcBgSetConstantAlphaI(ltdcp, cfgp->const_alpha); - ltdcBgSetBlendingFactorsI(ltdcp, cfgp->blending); - - if (cfgp->pal_length > 0) - ltdcBgSetPaletteI(ltdcp, cfgp->pal_colors, cfgp->pal_length); - - ltdcBgSetEnableFlagsI(ltdcp, cfgp->flags); -} - -/** - * @brief Set background layer specifications. - * @details Sets the background layer (layer 1) specifications at once. - * @note If the palette is unspecified, the layer palette is unmodified. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] cfgp pointer to the layer specifications - * - * @api - */ -void ltdcBgSetConfig(LTDCDriver *ltdcp, const ltdc_laycfg_t *cfgp) { - - osalSysLock(); - ltdcBgSetConfigI(ltdcp, cfgp); - osalSysUnlock(); -} - -/** @} */ - -/** - * @name LTDC foreground layer (layer 2) methods - * @{ - */ - -/** - * @brief Get foreground layer enabled flags. - * @details Returns all the flags of the LTDC_LEF_* group at once. - * Targeting the foreground layer (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return enabled flags - * - * @iclass - */ -ltdc_flags_t ltdcFgGetEnableFlagsI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - return LTDC_Layer2->CR & LTDC_LEF_MASK; -} - -/** - * @brief Get foreground layer enabled flags. - * @details Returns all the flags of the LTDC_LEF_* group at once. - * Targeting the foreground layer (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return enabled flags - * - * @api - */ -ltdc_flags_t ltdcFgGetEnableFlags(LTDCDriver *ltdcp) { - - ltdc_flags_t flags; - osalSysLock(); - flags = ltdcFgGetEnableFlagsI(ltdcp); - osalSysUnlock(); - return flags; -} - -/** - * @brief Set foreground layer enabled flags. - * @details Sets all the flags of the LTDC_LEF_* group at once. - * Targeting the foreground layer (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] flags enabled flags - * - * @iclass - */ -void ltdcFgSetEnableFlagsI(LTDCDriver *ltdcp, ltdc_flags_t flags) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - LTDC_Layer2->CR = ((LTDC_Layer2->CR & ~LTDC_LEF_MASK) | - ((uint32_t)flags & LTDC_LEF_MASK)); -} - -/** - * @brief Set foreground layer enabled flags. - * @details Sets all the flags of the LTDC_LEF_* group at once. - * Targeting the foreground layer (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] flags enabled flags - * - * @api - */ -void ltdcFgSetEnableFlags(LTDCDriver *ltdcp, ltdc_flags_t flags) { - - osalSysLock(); - ltdcFgSetEnableFlagsI(ltdcp, flags); - osalSysUnlock(); -} - -/** - * @brief Foreground layer enabled. - * @details Tells whether the foreground layer (layer 2) is enabled. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return enabled - * - * @iclass - */ -bool ltdcFgIsEnabledI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - return (LTDC_Layer2->CR & ~LTDC_LxCR_LEN) != 0; -} - -/** - * @brief Foreground layer enabled. - * @details Tells whether the foreground layer (layer 2) is enabled. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return enabled - * - * @api - */ -bool ltdcFgIsEnabled(LTDCDriver *ltdcp) { - - bool enabled; - osalSysLock(); - enabled = ltdcFgIsEnabledI(ltdcp); - osalSysUnlock(); - return enabled; -} - -/** - * @brief Foreground layer enable. - * @details Enables the foreground layer (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @iclass - */ -void ltdcFgEnableI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - LTDC_Layer2->CR |= LTDC_LxCR_LEN; -} - -/** - * @brief Foreground layer enable. - * @details Enables the foreground layer (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @api - */ -void ltdcFgEnable(LTDCDriver *ltdcp) { - - osalSysLock(); - ltdcFgEnableI(ltdcp); - osalSysUnlock(); -} - -/** - * @brief Foreground layer disable. - * @details Disables the foreground layer (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @iclass - */ -void ltdcFgDisableI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - LTDC_Layer2->CR &= ~LTDC_LxCR_LEN; -} - -/** - * @brief Foreground layer disable. - * @details Disables the foreground layer (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @api - */ -void ltdcFgDisable(LTDCDriver *ltdcp) { - - osalSysLock(); - ltdcFgDisableI(ltdcp); - osalSysUnlock(); -} - -/** - * @brief Foreground layer palette enabled. - * @details Tells whether the foreground layer (layer 2) palette (color lookup - * table) is enabled. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return enabled - * - * @iclass - */ -bool ltdcFgIsPaletteEnabledI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - return (LTDC_Layer2->CR & ~LTDC_LxCR_CLUTEN) != 0; -} - -/** - * @brief Foreground layer palette enabled. - * @details Tells whether the foreground layer (layer 2) palette (color lookup - * table) is enabled. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return enabled - * - * @api - */ -bool ltdcFgIsPaletteEnabled(LTDCDriver *ltdcp) { - - bool enabled; - osalSysLock(); - enabled = ltdcFgIsPaletteEnabledI(ltdcp); - osalSysUnlock(); - return enabled; -} - -/** - * @brief Enable foreground layer palette. - * @details Enables the palette (color lookup table) of the foreground layer - * (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @iclass - */ -void ltdcFgEnablePaletteI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - LTDC_Layer2->CR |= LTDC_LxCR_CLUTEN; -} - -/** - * @brief Enable foreground layer palette. - * @details Enables the palette (color lookup table) of the foreground layer - * (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @api - */ -void ltdcFgEnablePalette(LTDCDriver *ltdcp) { - - osalSysLock(); - ltdcFgEnablePaletteI(ltdcp); - osalSysUnlock(); -} - -/** - * @brief Disable foreground layer palette. - * @details Disables the palette (color lookup table) of the foreground layer - * (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @iclass - */ -void ltdcFgDisablePaletteI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - LTDC_Layer2->CR &= ~LTDC_LxCR_CLUTEN; -} - -/** - * @brief Disable foreground layer palette. - * @details Disables the palette (color lookup table) of the foreground layer - * (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @api - */ -void ltdcFgDisablePalette(LTDCDriver *ltdcp) { - - osalSysLock(); - ltdcFgDisablePaletteI(ltdcp); - osalSysUnlock(); -} - -/** - * @brief Set foreground layer palette color. - * @details Sets the color of a palette (color lookup table) slot to the - * foreground layer (layer 2). - * @pre The layer must be disabled. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] slot palette slot - * @param[in] c color, RGB-888 - * - * @iclass - */ -void ltdcFgSetPaletteColorI(LTDCDriver *ltdcp, uint8_t slot, ltdc_color_t c) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - osalDbgAssert(!ltdcFgIsEnabledI(ltdcp), "invalid state"); - (void)ltdcp; - - LTDC_Layer2->CLUTWR = (((uint32_t)slot << 24) | (c & 0x00FFFFFF)); -} - -/** - * @brief Set foreground layer palette color. - * @details Sets the color of a palette (color lookup table) slot to the - * foreground layer (layer 2). - * @pre The layer must be disabled. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] slot palette slot - * @param[in] c color, RGB-888 - * - * @api - */ -void ltdcFgSetPaletteColor(LTDCDriver *ltdcp, uint8_t slot, ltdc_color_t c) { - - osalSysLock(); - ltdcFgSetPaletteColorI(ltdcp, slot, c); - osalSysUnlock(); -} - -/** - * @brief Set foreground layer palette. - * @details Sets the entire palette color (color lookup table) slot. - * @pre The layer must be disabled. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] colors array of palette colors, RGB-888 - * @param[in] length number of palette colors - * - * @iclass - */ -void ltdcFgSetPaletteI(LTDCDriver *ltdcp, const ltdc_color_t colors[], - uint16_t length) { - - uint16_t i; - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - osalDbgCheck((colors == NULL) == (length == 0)); - osalDbgAssert(length <= LTDC_MAX_PALETTE_LENGTH, "bounds"); - osalDbgAssert(!ltdcFgIsEnabledI(ltdcp), "invalid state"); - (void)ltdcp; - - for (i = 0; i < length; ++i) - LTDC_Layer2->CLUTWR = (((uint32_t)i << 24) | (colors[i] & 0x00FFFFFF)); -} - -/** - * @brief Set foreground layer palette. - * @details Sets the entire palette color (color lookup table) slot. - * @pre The layer must be disabled. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] colors array of palette colors, RGB-888 - * @param[in] length number of palette colors - * - * @api - */ -void ltdcFgSetPalette(LTDCDriver *ltdcp, const ltdc_color_t colors[], - uint16_t length) { - - osalSysLock(); - ltdcFgSetPaletteI(ltdcp, colors, length); - osalSysUnlock(); -} - -/** - * @brief Get foreground layer pixel format. - * @details Gets the pixel format of the foreground layer (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return pixel format - * - * @iclass - */ -ltdc_pixfmt_t ltdcFgGetPixelFormatI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - return (ltdc_pixfmt_t)(LTDC_Layer2->PFCR & LTDC_LxPFCR_PF); -} - -/** - * @brief Get foreground layer pixel format. - * @details Gets the pixel format of the foreground layer (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return pixel format - * - * @api - */ -ltdc_pixfmt_t ltdcFgGetPixelFormat(LTDCDriver *ltdcp) { - - ltdc_pixfmt_t fmt; - osalSysLock(); - fmt = ltdcFgGetPixelFormatI(ltdcp); - osalSysUnlock(); - return fmt; -} - -/** - * @brief Set foreground layer pixel format. - * @details Sets the pixel format of the foreground layer (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] fmt pixel format - * - * @iclass - */ -void ltdcFgSetPixelFormatI(LTDCDriver *ltdcp, ltdc_pixfmt_t fmt) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - osalDbgAssert(fmt >= LTDC_MIN_PIXFMT_ID, "bounds"); - osalDbgAssert(fmt <= LTDC_MAX_PIXFMT_ID, "bounds"); - (void)ltdcp; - - LTDC_Layer2->PFCR = ((LTDC_Layer2->PFCR & ~LTDC_LxPFCR_PF) | - ((uint32_t)fmt & LTDC_LxPFCR_PF)); -} - -/** - * @brief Set foreground layer pixel format. - * @details Sets the pixel format of the foreground layer (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] fmt pixel format - * - * @api - */ -void ltdcFgSetPixelFormat(LTDCDriver *ltdcp, ltdc_pixfmt_t fmt) { - - osalSysLock(); - ltdcFgSetPixelFormatI(ltdcp, fmt); - osalSysUnlock(); -} - -/** - * @brief Foreground layer color keying enabled. - * @details Tells whether the foreground layer (layer 2) has color keying - * enabled. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return enabled - * - * @iclass - */ -bool ltdcFgIsKeyingEnabledI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - return (LTDC_Layer2->CR & ~LTDC_LxCR_COLKEN) != 0; -} - -/** - * @brief Foreground layer color keying enabled. - * @details Tells whether the foreground layer (layer 2) has color keying - * enabled. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return enabled - * - * @api - */ -bool ltdcFgIsKeyingEnabled(LTDCDriver *ltdcp) { - - bool enabled; - osalSysLock(); - enabled = ltdcFgIsKeyingEnabledI(ltdcp); - osalSysUnlock(); - return enabled; -} - -/** - * @brief Enable foreground layer color keying. - * @details Enables color keying capabilities of the foreground layer (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @iclass - */ -void ltdcFgEnableKeyingI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - LTDC_Layer2->CR |= LTDC_LxCR_COLKEN; -} - -/** - * @brief Enable foreground layer color keying. - * @details Enables color keying capabilities of the foreground layer (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @api - */ -void ltdcFgEnableKeying(LTDCDriver *ltdcp) { - - osalSysLock(); - ltdcFgEnableKeyingI(ltdcp); - osalSysUnlock(); -} - -/** - * @brief Disable foreground layer color keying. - * @details Disables color keying capabilities of the foreground layer (layer - * 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @iclass - */ -void ltdcFgDisableKeyingI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - LTDC_Layer2->CR &= ~LTDC_LxCR_COLKEN; -} - -/** - * @brief Disable foreground layer color keying. - * @details Disables color keying capabilities of the foreground layer (layer - * 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @api - */ -void ltdcFgDisableKeying(LTDCDriver *ltdcp) { - - osalSysLock(); - ltdcFgDisableKeyingI(ltdcp); - osalSysUnlock(); -} - -/** - * @brief Get foreground layer color key. - * @details Gets the color key of the foreground layer (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return color key, RGB-888 - * - * @iclass - */ -ltdc_color_t ltdcFgGetKeyingColorI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - return (ltdc_color_t)(LTDC_Layer2->CKCR & 0x00FFFFFF); -} - -/** - * @brief Get foreground layer color key. - * @details Gets the color key of the foreground layer (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return color key, RGB-888 - * - * @api - */ -ltdc_color_t ltdcFgGetKeyingColor(LTDCDriver *ltdcp) { - - ltdc_color_t color; - osalSysLock(); - color = ltdcFgGetKeyingColorI(ltdcp); - osalSysUnlock(); - return color; -} - -/** - * @brief Set foreground layer color key. - * @details Sets the color key of the foreground layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] c color key, RGB-888 - * - * @iclass - */ -void ltdcFgSetKeyingColorI(LTDCDriver *ltdcp, ltdc_color_t c) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - LTDC_Layer2->CKCR = ((LTDC_Layer2->CKCR & ~0x00FFFFFF) | - ((uint32_t)c & 0x00FFFFFF)); -} - -/** - * @brief Set foreground layer color key. - * @details Sets the color key of the foreground layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] c color key, RGB-888 - * - * @api - */ -void ltdcFgSetKeyingColor(LTDCDriver *ltdcp, ltdc_color_t c) { - - osalSysLock(); - ltdcFgSetKeyingColorI(ltdcp, c); - osalSysUnlock(); -} - -/** - * @brief Get foreground layer constant alpha. - * @details Gets the constant alpha component of the foreground layer (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return constant alpha component, A-8 - * - * @iclass - */ -uint8_t ltdcFgGetConstantAlphaI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - return (uint8_t)(LTDC_Layer2->CACR & LTDC_LxCACR_CONSTA); -} - -/** - * @brief Get foreground layer constant alpha. - * @details Gets the constant alpha component of the foreground layer (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return constant alpha component, A-8 - * - * @api - */ -uint8_t ltdcFgGetConstantAlpha(LTDCDriver *ltdcp) { - - uint8_t a; - osalSysLock(); - a = ltdcFgGetConstantAlphaI(ltdcp); - osalSysUnlock(); - return a; -} - -/** - * @brief Set foreground layer constant alpha. - * @details Sets the constant alpha component of the foreground layer (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] a constant alpha component, A-8 - * - * @iclass - */ -void ltdcFgSetConstantAlphaI(LTDCDriver *ltdcp, uint8_t a) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - LTDC_Layer2->CACR = ((LTDC_Layer2->CACR & ~LTDC_LxCACR_CONSTA) | - ((uint32_t)a & LTDC_LxCACR_CONSTA)); -} - -/** - * @brief Set foreground layer constant alpha. - * @details Sets the constant alpha component of the foreground layer (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] a constant alpha component, A-8 - * - * @api - */ -void ltdcFgSetConstantAlpha(LTDCDriver *ltdcp, uint8_t a) { - - osalSysLock(); - ltdcFgSetConstantAlphaI(ltdcp, a); - osalSysUnlock(); -} - -/** - * @brief Get foreground layer default color. - * @details Gets the default color of the foreground layer (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return default color, RGB-888 - * - * @iclass - */ -ltdc_color_t ltdcFgGetDefaultColorI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - return (ltdc_color_t)LTDC_Layer2->DCCR; -} - -/** - * @brief Get foreground layer default color. - * @details Gets the default color of the foreground layer (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return default color, RGB-888 - * - * @api - */ -ltdc_color_t ltdcFgGetDefaultColor(LTDCDriver *ltdcp) { - - ltdc_color_t color; - osalSysLock(); - color = ltdcFgGetDefaultColorI(ltdcp); - osalSysUnlock(); - return color; -} - -/** - * @brief Set foreground layer default color. - * @details Sets the default color of the foreground layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] c default color, RGB-888 - * - * @iclass - */ -void ltdcFgSetDefaultColorI(LTDCDriver *ltdcp, ltdc_color_t c) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - LTDC_Layer2->DCCR = (uint32_t)c; -} - -/** - * @brief Set foreground layer default color. - * @details Sets the default color of the foreground layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] c default color, RGB-888 - * - * @api - */ -void ltdcFgSetDefaultColor(LTDCDriver *ltdcp, ltdc_color_t c) { - - osalSysLock(); - ltdcFgSetDefaultColorI(ltdcp, c); - osalSysUnlock(); -} - -/** - * @brief Get foreground layer blending factors. - * @details Gets the blending factors of the foreground layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return blending factors - * - * @iclass - */ -ltdc_blendf_t ltdcFgGetBlendingFactorsI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - return (ltdc_blendf_t)(LTDC_Layer2->BFCR & LTDC_LxBFCR_BF); -} - -/** - * @brief Get foreground layer blending factors. - * @details Gets the blending factors of the foreground layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return blending factors - * - * @api - */ -ltdc_blendf_t ltdcFgGetBlendingFactors(LTDCDriver *ltdcp) { - - ltdc_blendf_t bf; - osalSysLock(); - bf = ltdcFgGetBlendingFactorsI(ltdcp); - osalSysUnlock(); - return bf; -} - -/** - * @brief Set foreground layer blending factors. - * @details Sets the blending factors of the foreground layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] factors blending factors - * - * @iclass - */ -void ltdcFgSetBlendingFactorsI(LTDCDriver *ltdcp, ltdc_blendf_t bf) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - LTDC_Layer2->BFCR = ((LTDC_Layer2->BFCR & ~LTDC_LxBFCR_BF) | - ((uint32_t)bf & LTDC_LxBFCR_BF)); -} - -/** - * @brief Set foreground layer blending factors. - * @details Sets the blending factors of the foreground layer (layer 1). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] factors blending factors - * - * @api - */ -void ltdcFgSetBlendingFactors(LTDCDriver *ltdcp, ltdc_blendf_t bf) { - - osalSysLock(); - ltdcFgSetBlendingFactorsI(ltdcp, bf); - osalSysUnlock(); -} - -/** - * @brief Get foreground layer window specs. - * @details Gets the window specifications of the foreground layer (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[out] windowp pointer to the window specifications - * - * @iclass - */ -void ltdcFgGetWindowI(LTDCDriver *ltdcp, ltdc_window_t *windowp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - osalDbgCheck(windowp != NULL); - (void)ltdcp; - - windowp->hstart = - (uint16_t)((LTDC_Layer2->WHPCR & LTDC_LxWHPCR_WHSTPOS) >> 0); - windowp->hstop = - (uint16_t)((LTDC_Layer2->WHPCR & LTDC_LxWHPCR_WHSPPOS) >> 16); - windowp->vstart = - (uint16_t)((LTDC_Layer2->WVPCR & LTDC_LxWVPCR_WVSTPOS) >> 0); - windowp->vstop = - (uint16_t)((LTDC_Layer2->WVPCR & LTDC_LxWVPCR_WVSPPOS) >> 16); -} - -/** - * @brief Get foreground layer window specs. - * @details Gets the window specifications of the foreground layer (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[out] windowp pointer to the window specifications - * - * @api - */ -void ltdcFgGetWindow(LTDCDriver *ltdcp, ltdc_window_t *windowp) { - - osalSysLock(); - ltdcFgGetWindowI(ltdcp, windowp); - osalSysUnlock(); -} - -/** - * @brief Set foreground layer window specs. - * @details Sets the window specifications of the foreground layer (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] windowp pointer to the window specifications - * - * @iclass - */ -void ltdcFgSetWindowI(LTDCDriver *ltdcp, const ltdc_window_t *windowp) { - - uint32_t start, stop; - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - osalDbgCheck(windowp != NULL); - (void)ltdcp; - - osalDbgAssert(windowp->hstop < ltdcp->config->screen_width, "bounds"); - osalDbgAssert(windowp->vstop < ltdcp->config->screen_height, "bounds"); - - /* Horizontal boundaries.*/ - start = (uint32_t)windowp->hstart + ltdcp->active_window.hstart; - stop = (uint32_t)windowp->hstop + ltdcp->active_window.hstart; - - osalDbgAssert(start >= ltdcp->active_window.hstart, "bounds"); - osalDbgAssert(stop <= ltdcp->active_window.hstop, "bounds"); - - LTDC_Layer2->WHPCR = (((start << 0) & LTDC_LxWHPCR_WHSTPOS) | - ((stop << 16) & LTDC_LxWHPCR_WHSPPOS)); - - /* Vertical boundaries.*/ - start = (uint32_t)windowp->vstart + ltdcp->active_window.vstart; - stop = (uint32_t)windowp->vstop + ltdcp->active_window.vstart; - - osalDbgAssert(start >= ltdcp->active_window.vstart, "bounds"); - osalDbgAssert(stop <= ltdcp->active_window.vstop, "bounds"); - - LTDC_Layer2->WVPCR = (((start << 0) & LTDC_LxWVPCR_WVSTPOS) | - ((stop << 16) & LTDC_LxWVPCR_WVSPPOS)); -} - -/** - * @brief Set foreground layer window specs. - * @details Sets the window specifications of the foreground layer (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] windowp pointer to the window specifications - * - * @api - */ -void ltdcFgSetWindow(LTDCDriver *ltdcp, const ltdc_window_t *windowp) { - - osalSysLock(); - ltdcFgSetWindowI(ltdcp, windowp); - osalSysUnlock(); -} - -/** - * @brief Set foreground layer window as invalid. - * @details Sets the window specifications of the foreground layer (layer 2) - * so that the window is pixel sized at the screen origin. - * @note Useful before reconfiguring the frame specifications of the layer, - * to avoid errors. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @iclass - */ -void ltdcFgSetInvalidWindowI(LTDCDriver *ltdcp) { - - ltdcFgSetWindowI(ltdcp, <dc_invalid_window); -} - -/** - * @brief Set foreground layer window as invalid. - * @details Sets the window specifications of the foreground layer (layer 2) - * so that the window is pixel sized at the screen origin. - * @note Useful before reconfiguring the frame specifications of the layer, - * to avoid errors. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @api - */ -void ltdcFgSetInvalidWindow(LTDCDriver *ltdcp) { - - osalSysLock(); - ltdcFgSetWindowI(ltdcp, <dc_invalid_window); - osalSysUnlock(); -} - -/** - * @brief Get foreground layer frame buffer specs. - * @details Gets the frame buffer specifications of the foreground layer - * (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[out] framep pointer to the frame buffer specifications - * - * @iclass - */ -void ltdcFgGetFrameI(LTDCDriver *ltdcp, ltdc_frame_t *framep) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - osalDbgCheck(framep != NULL); - - framep->bufferp = (void *)(LTDC_Layer2->CFBAR & LTDC_LxCFBAR_CFBADD); - framep->pitch = (size_t)((LTDC_Layer2->CFBLR & LTDC_LxCFBLR_CFBP) >> 16); - framep->width = (uint16_t)(((LTDC_Layer2->CFBLR & LTDC_LxCFBLR_CFBLL) - 3) / - ltdcBytesPerPixel(ltdcFgGetPixelFormatI(ltdcp))); - framep->height = (uint16_t)(LTDC_Layer2->CFBLNR & LTDC_LxCFBLNR_CFBLNBR); -} - -/** - * @brief Get foreground layer frame buffer specs. - * @details Gets the frame buffer specifications of the foreground layer - * (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[out] framep pointer to the frame buffer specifications - * - * @api - */ -void ltdcFgGetFrame(LTDCDriver *ltdcp, ltdc_frame_t *framep) { - - osalSysLock(); - ltdcFgGetFrameI(ltdcp, framep); - osalSysUnlock(); -} - -/** - * @brief Set foreground layer frame buffer specs. - * @details Sets the frame buffer specifications of the foreground layer - * (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] framep pointer to the frame buffer specifications - * - * @iclass - */ -void ltdcFgSetFrameI(LTDCDriver *ltdcp, const ltdc_frame_t *framep) { - - size_t linesize; - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - osalDbgCheck(framep != NULL); - - ltdcFgSetPixelFormatI(ltdcp, framep->fmt); - - linesize = ltdcBytesPerPixel(framep->fmt) * framep->width; - - osalDbgAssert(framep->width <= ltdcp->config->screen_width, "bounds"); - osalDbgAssert(framep->height <= ltdcp->config->screen_height, "bounds"); - osalDbgAssert(linesize >= LTDC_MIN_FRAME_WIDTH_BYTES, "bounds"); - osalDbgAssert(linesize <= LTDC_MAX_FRAME_WIDTH_BYTES, "bounds"); - osalDbgAssert(framep->height >= LTDC_MIN_FRAME_HEIGHT_LINES, "bounds"); - osalDbgAssert(framep->height <= LTDC_MAX_FRAME_HEIGHT_LINES, "bounds"); - osalDbgAssert(framep->pitch >= linesize, "bounds"); - - LTDC_Layer2->CFBAR = (uint32_t)framep->bufferp & LTDC_LxCFBAR_CFBADD; - LTDC_Layer2->CFBLR = ((((uint32_t)framep->pitch << 16) & LTDC_LxCFBLR_CFBP) | - ((linesize + 3) & LTDC_LxCFBLR_CFBLL)); - LTDC_Layer2->CFBLNR = (uint32_t)framep->height & LTDC_LxCFBLNR_CFBLNBR; -} - -/** - * @brief Set foreground layer frame buffer specs. - * @details Sets the frame buffer specifications of the foreground layer - * (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] framep pointer to the frame buffer specifications - * - * @api - */ -void ltdcFgSetFrame(LTDCDriver *ltdcp, const ltdc_frame_t *framep) { - - osalSysLock(); - ltdcFgSetFrameI(ltdcp, framep); - osalSysUnlock(); -} - -/** - * @brief Get foreground layer frame buffer address. - * @details Gets the frame buffer address of the foreground layer (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return frame buffer address - * - * @iclass - */ -void *ltdcFgGetFrameAddressI(LTDCDriver *ltdcp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - return (void *)LTDC_Layer2->CFBAR; -} - -/** - * @brief Get foreground layer frame buffer address. - * @details Gets the frame buffer address of the foreground layer (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * - * @return frame buffer address - * - * @api - */ -void *ltdcFgGetFrameAddress(LTDCDriver *ltdcp) { - - void *bufferp; - osalSysLock(); - bufferp = ltdcFgGetFrameAddressI(ltdcp); - osalSysUnlock(); - return bufferp; -} - -/** - * @brief Set foreground layer frame buffer address. - * @details Sets the frame buffer address of the foreground layer (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] bufferp frame buffer address - * - * @iclass - */ -void ltdcFgSetFrameAddressI(LTDCDriver *ltdcp, void *bufferp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - (void)ltdcp; - - LTDC_Layer2->CFBAR = (uint32_t)bufferp; -} - -/** - * @brief Set foreground layer frame buffer address. - * @details Sets the frame buffer address of the foreground layer (layer 2). - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] bufferp frame buffer address - * - * @api - */ -void ltdcFgSetFrameAddress(LTDCDriver *ltdcp, void *bufferp) { - - osalSysLock(); - ltdcFgSetFrameAddressI(ltdcp, bufferp); - osalSysUnlock(); -} - -/** - * @brief Get foreground layer specifications. - * @details Gets the foreground layer (layer 2) specifications at once. - * @note If palette specifications cannot be retrieved, they are set to - * @p NULL. This is not an error. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[out] cfgp pointer to the layer specifications - * - * @iclass - */ -void ltdcFgGetLayerI(LTDCDriver *ltdcp, ltdc_laycfg_t *cfgp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - osalDbgCheck(cfgp != NULL); - - ltdcFgGetFrameI(ltdcp, (ltdc_frame_t *)cfgp->frame); - ltdcFgGetWindowI(ltdcp, (ltdc_window_t *)cfgp->window); - cfgp->def_color = ltdcFgGetDefaultColorI(ltdcp); - cfgp->key_color = ltdcFgGetKeyingColorI(ltdcp); - cfgp->const_alpha = ltdcFgGetConstantAlphaI(ltdcp); - cfgp->blending = ltdcFgGetBlendingFactorsI(ltdcp); - - cfgp->pal_colors = NULL; - cfgp->pal_length = 0; - - cfgp->flags = ltdcFgGetEnableFlagsI(ltdcp); -} - -/** - * @brief Get foreground layer specifications. - * @details Gets the foreground layer (layer 2) specifications at once. - * @note If palette specifications cannot be retrieved, they are set to - * @p NULL. This is not an error. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[out] cfgp pointer to the layer specifications - * - * @api - */ -void ltdcFgGetLayer(LTDCDriver *ltdcp, ltdc_laycfg_t *cfgp) { - - osalSysLock(); - ltdcFgGetLayerI(ltdcp, cfgp); - osalSysUnlock(); -} - -/** - * @brief Set foreground layer specifications. - * @details Sets the foreground layer (layer 2) specifications at once. - * @note If the palette is unspecified, the layer palette is unmodified. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] cfgp pointer to the layer specifications - * - * @iclass - */ -void ltdcFgSetConfigI(LTDCDriver *ltdcp, const ltdc_laycfg_t *cfgp) { - - osalDbgCheckClassI(); - osalDbgCheck(ltdcp == <DCD1); - - if (cfgp == NULL) - cfgp = <dc_default_laycfg; - - osalDbgCheck((cfgp->pal_colors == NULL) == (cfgp->pal_length == 0)); - - ltdcFgSetFrameI(ltdcp, cfgp->frame); - ltdcFgSetWindowI(ltdcp, cfgp->window); - ltdcFgSetDefaultColorI(ltdcp, cfgp->def_color); - ltdcFgSetKeyingColorI(ltdcp, cfgp->key_color); - ltdcFgSetConstantAlphaI(ltdcp, cfgp->const_alpha); - ltdcFgSetBlendingFactorsI(ltdcp, cfgp->blending); - - if (cfgp->pal_length > 0) - ltdcFgSetPaletteI(ltdcp, cfgp->pal_colors, cfgp->pal_length); - - ltdcFgSetEnableFlagsI(ltdcp, cfgp->flags); -} - -/** - * @brief Set foreground layer specifications. - * @details Sets the foreground layer (layer 2) specifications at once. - * @note If the palette is unspecified, the layer palette is unmodified. - * - * @param[in] ltdcp pointer to the @p LTDCDriver object - * @param[in] cfgp pointer to the layer specifications - * - * @api - */ -void ltdcFgSetConfig(LTDCDriver *ltdcp, const ltdc_laycfg_t *cfgp) { - - osalSysLock(); - ltdcFgSetConfigI(ltdcp, cfgp); - osalSysUnlock(); -} - -/** @} */ - -/** - * @name LTDC helper functions - */ - -/** - * @brief Compute bits per pixel. - * @details Computes the bits per pixel for the specified pixel format. - * - * @param[in] fmt pixel format - * - * @retuen bits per pixel - * - * @api - */ -size_t ltdcBitsPerPixel(ltdc_pixfmt_t fmt) { - - osalDbgAssert(fmt < LTDC_MAX_PIXFMT_ID, "invalid format"); - - return (size_t)ltdc_bpp[(unsigned)fmt]; -} - -#if (TRUE == LTDC_USE_SOFTWARE_CONVERSIONS) || defined(__DOXYGEN__) - -/** - * @brief Convert from ARGB-8888. - * @details Converts an ARGB-8888 color to the specified pixel format. - * - * @param[in] c color, ARGB-8888 - * @param[in] fmt target pixel format - * - * @return raw color value for the target pixel format, left - * padded with zeros. - * - * @api - */ -ltdc_color_t ltdcFromARGB8888(ltdc_color_t c, ltdc_pixfmt_t fmt) { - - switch (fmt) { - case LTDC_FMT_ARGB8888: { - return c; - } - case LTDC_FMT_RGB888: { - return (c & 0x00FFFFFF); - } - case LTDC_FMT_RGB565: { - return (((c & 0x000000F8) >> ( 8 - 5)) | - ((c & 0x0000FC00) >> (16 - 11)) | - ((c & 0x00F80000) >> (24 - 16))); - } - case LTDC_FMT_ARGB1555: { - return (((c & 0x000000F8) >> ( 8 - 5)) | - ((c & 0x0000F800) >> (16 - 10)) | - ((c & 0x00F80000) >> (24 - 15)) | - ((c & 0x80000000) >> (32 - 16))); - } - case LTDC_FMT_ARGB4444: { - return (((c & 0x000000F0) >> ( 8 - 4)) | - ((c & 0x0000F000) >> (16 - 8)) | - ((c & 0x00F00000) >> (24 - 12)) | - ((c & 0xF0000000) >> (32 - 16))); - } - case LTDC_FMT_L8: { - return (c & 0x000000FF); - } - case LTDC_FMT_AL44: { - return (((c & 0x000000F0) >> ( 8 - 4)) | - ((c & 0xF0000000) >> (32 - 8))); - } - case LTDC_FMT_AL88: { - return (((c & 0x000000FF) >> ( 8 - 8)) | - ((c & 0xFF000000) >> (32 - 16))); - } - default: - osalDbgAssert(false, "invalid format"); - return 0; - } -} - -/** - * @brief Convert to ARGB-8888. - * @details Converts color of the specified pixel format to an ARGB-8888 color. - * - * @param[in] c color for the source pixel format, left padded with - * zeros. - * @param[in] fmt source pixel format - * - * @return color in ARGB-8888 format - * - * @api - */ -ltdc_color_t ltdcToARGB8888(ltdc_color_t c, ltdc_pixfmt_t fmt) { - - switch (fmt) { - case LTDC_FMT_ARGB8888: { - return c; - } - case LTDC_FMT_RGB888: { - return ((c & 0x00FFFFFF) | 0xFF000000); - } - case LTDC_FMT_RGB565: { - register ltdc_color_t output = 0xFF000000; - if (c & 0x001F) output |= (((c & 0x001F) << ( 8 - 5)) | 0x00000007); - if (c & 0x07E0) output |= (((c & 0x07E0) << (16 - 11)) | 0x00000300); - if (c & 0xF800) output |= (((c & 0xF800) << (24 - 16)) | 0x00070000); - return output; - } - case LTDC_FMT_ARGB1555: { - register ltdc_color_t output = 0x00000000; - if (c & 0x001F) output |= (((c & 0x001F) << ( 8 - 5)) | 0x00000007); - if (c & 0x03E0) output |= (((c & 0x03E0) << (16 - 10)) | 0x00000700); - if (c & 0x7C00) output |= (((c & 0x7C00) << (24 - 15)) | 0x00070000); - if (c & 0x8000) output |= 0xFF000000; - return output; - } - case LTDC_FMT_ARGB4444: { - register ltdc_color_t output = 0x00000000; - if (c & 0x000F) output |= (((c & 0x000F) << ( 8 - 4)) | 0x0000000F); - if (c & 0x00F0) output |= (((c & 0x00F0) << (16 - 8)) | 0x00000F00); - if (c & 0x0F00) output |= (((c & 0x0F00) << (24 - 12)) | 0x000F0000); - if (c & 0xF000) output |= (((c & 0xF000) << (32 - 16)) | 0x0F000000); - return output; - } - case LTDC_FMT_L8: { - return ((c & 0xFF) | 0xFF000000); - } - case LTDC_FMT_AL44: { - register ltdc_color_t output = 0x00000000; - if (c & 0x0F) output |= (((c & 0x0F) << ( 8 - 4)) | 0x0000000F); - if (c & 0xF0) output |= (((c & 0xF0) << (32 - 8)) | 0x0F000000); - return output; - } - case LTDC_FMT_AL88: { - return (((c & 0x00FF) << ( 8 - 8)) | - ((c & 0xFF00) << (32 - 16))); - } - default: - osalDbgAssert(false, "invalid format"); - return 0; - } -} - -#endif /* LTDC_USE_SOFTWARE_CONVERSIONS */ - -/** @} */ - -/** @} */ - -#endif /* STM32_LTDC_USE_LTDC */ diff --git a/os/hal/ports/STM32/LLD/LTDCv1/stm32_ltdc.h b/os/hal/ports/STM32/LLD/LTDCv1/stm32_ltdc.h deleted file mode 100644 index fdf1f5b..0000000 --- a/os/hal/ports/STM32/LLD/LTDCv1/stm32_ltdc.h +++ /dev/null @@ -1,736 +0,0 @@ -/* - Copyright (C) 2013-2015 Andrea Zoppi - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -/** - * @file stm32_ltdc.h - * @brief LCD-TFT Controller Driver. - * - * @addtogroup ltdc - * @{ - */ - -#ifndef _STM32_LTDC_H_ -#define _STM32_LTDC_H_ - -/** - * @brief Using the LTDC driver. - */ -#if !defined(STM32_LTDC_USE_LTDC) || defined(__DOXYGEN__) -#define STM32_LTDC_USE_LTDC (FALSE) -#endif - -#if (TRUE == STM32_LTDC_USE_LTDC) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver constants. */ -/*===========================================================================*/ - -/** - * @name LTDC enable flags - * @{ - */ -#define LTDC_EF_ENABLE (1 << 0) /**< LTDC enabled.*/ -#define LTDC_EF_DITHER (1 << 16) /**< Dithering enabled.*/ -#define LTDC_EF_PIXCLK_INVERT (1 << 28) /**< Inverted pixel clock.*/ -#define LTDC_EF_DATAEN_HIGH (1 << 29) /**< Active-high data enable.*/ -#define LTDC_EF_VSYNC_HIGH (1 << 30) /**< Active-high vsync.*/ -#define LTDC_EF_HSYNC_HIGH (1 << 31) /**< Active-high hsync.*/ - -#define LTDC_EF_MASK \ - (LTDC_EF_ENABLE | LTDC_EF_DITHER | LTDC_EF_PIXCLK_INVERT | \ - LTDC_EF_DATAEN_HIGH | LTDC_EF_VSYNC_HIGH | LTDC_EF_HSYNC_HIGH) -/** @} */ - -/** - * @name LTDC layer enable flags - * @{ - */ -#define LTDC_LEF_ENABLE (1 << 0) /**< Layer enabled*/ -#define LTDC_LEF_KEYING (1 << 1) /**< Color keying enabled.*/ -#define LTDC_LEF_PALETTE (1 << 4) /**< Palette enabled.*/ - -#define LTDC_LEF_MASK \ - (LTDC_LEF_ENABLE | LTDC_LEF_KEYING | LTDC_LEF_PALETTE) -/** @} */ - -/** - * @name LTDC pixel formats - * @{ - */ -#define LTDC_FMT_ARGB8888 (0) /**< ARGB-8888 format.*/ -#define LTDC_FMT_RGB888 (1) /**< RGB-888 format.*/ -#define LTDC_FMT_RGB565 (2) /**< RGB-565 format.*/ -#define LTDC_FMT_ARGB1555 (3) /**< ARGB-1555 format.*/ -#define LTDC_FMT_ARGB4444 (4) /**< ARGB-4444 format.*/ -#define LTDC_FMT_L8 (5) /**< L-8 format.*/ -#define LTDC_FMT_AL44 (6) /**< AL-44 format.*/ -#define LTDC_FMT_AL88 (7) /**< AL-88 format.*/ -/** @} */ - -/** - * @name LTDC pixel format aliased raw masks - * @{ - */ -#define LTDC_XMASK_ARGB8888 (0xFFFFFFFF) /**< ARGB-8888 aliased mask.*/ -#define LTDC_XMASK_RGB888 (0x00FFFFFF) /**< RGB-888 aliased mask.*/ -#define LTDC_XMASK_RGB565 (0x00F8FCF8) /**< RGB-565 aliased mask.*/ -#define LTDC_XMASK_ARGB1555 (0x80F8F8F8) /**< ARGB-1555 aliased mask.*/ -#define LTDC_XMASK_ARGB4444 (0xF0F0F0F0) /**< ARGB-4444 aliased mask.*/ -#define LTDC_XMASK_L8 (0x000000FF) /**< L-8 aliased mask.*/ -#define LTDC_XMASK_AL44 (0xF00000F0) /**< AL-44 aliased mask.*/ -#define LTDC_XMASK_AL88 (0xFF0000FF) /**< AL-88 aliased mask.*/ -/** @} */ - -/** - * @name LTDC blending factors - * @{ - */ -#define LTDC_BLEND_FIX1_FIX2 (0x0405) /**< cnst1; 1 - cnst2 */ -#define LTDC_BLEND_FIX1_MOD2 (0x0407) /**< cnst1; 1 - a2 * cnst2 */ -#define LTDC_BLEND_MOD1_FIX2 (0x0605) /**< a1 * cnst1; 1 - cnst2 */ -#define LTDC_BLEND_MOD1_MOD2 (0x0607) /**< a1 * cnst1; 1 - a2 * cnst2 */ -/** @} */ - -/** - * @name LTDC parameter bounds - * @{ - */ - -#define LTDC_MIN_SCREEN_WIDTH (1) -#define LTDC_MIN_SCREEN_HEIGHT (1) -#define LTDC_MAX_SCREEN_WIDTH (800) -#define LTDC_MAX_SCREEN_HEIGHT (600) - -#define LTDC_MIN_HSYNC_WIDTH (1) -#define LTDC_MIN_VSYNC_HEIGHT (1) -#define LTDC_MAX_HSYNC_WIDTH (1 << 12) -#define LTDC_MAX_VSYNC_HEIGHT (1 << 11) - -#define LTDC_MIN_HBP_WIDTH (0) -#define LTDC_MIN_VBP_HEIGHT (0) -#define LTDC_MAX_HBP_WIDTH (1 << 12) -#define LTDC_MAX_VBP_HEIGHT (1 << 11) - -#define LTDC_MIN_ACC_HBP_WIDTH (1) -#define LTDC_MIN_ACC_VBP_HEIGHT (1) -#define LTDC_MAX_ACC_HBP_WIDTH (1 << 12) -#define LTDC_MAX_ACC_VBP_HEIGHT (1 << 11) - -#define LTDC_MIN_HFP_WIDTH (0) -#define LTDC_MIN_VFP_HEIGHT (0) -#define LTDC_MAX_HFP_WIDTH (1 << 12) -#define LTDC_MAX_VFP_HEIGHT (1 << 11) - -#define LTDC_MIN_ACTIVE_WIDTH (0) -#define LTDC_MIN_ACTIVE_HEIGHT (0) -#define LTDC_MAX_ACTIVE_WIDTH (1 << 12) -#define LTDC_MAX_ACTIVE_HEIGHT (1 << 11) - -#define LTDC_MIN_ACC_ACTIVE_WIDTH (1) -#define LTDC_MIN_ACC_ACTIVE_HEIGHT (1) -#define LTDC_MAX_ACC_ACTIVE_WIDTH (1 << 12) -#define LTDC_MAX_ACC_ACTIVE_HEIGHT (1 << 11) - -#define LTDC_MIN_ACC_TOTAL_WIDTH (1) -#define LTDC_MIN_ACC_TOTAL_HEIGHT (1) -#define LTDC_MAX_ACC_TOTAL_WIDTH (1 << 12) -#define LTDC_MAX_ACC_TOTAL_HEIGHT (1 << 11) - -#define LTDC_MIN_LINE_INTERRUPT_POS (0) -#define LTDC_MAX_LINE_INTERRUPT_POS ((1 << 11) - 1) - -#define LTDC_MIN_WINDOW_HSTART (0) -#define LTDC_MIN_WINDOW_HSTART (0) -#define LTDC_MAX_WINDOW_HSTOP ((1 << 12) - 1) -#define LTDC_MAX_WINDOW_HSTOP ((1 << 12) - 1) - -#define LTDC_MIN_WINDOW_VSTART (0) -#define LTDC_MIN_WINDOW_VSTART (0) -#define LTDC_MAX_WINDOW_VSTOP ((1 << 11) - 1) -#define LTDC_MAX_WINDOW_VSTOP ((1 << 11) - 1) - -#define LTDC_MIN_FRAME_WIDTH_BYTES (0) -#define LTDC_MIN_FRAME_HEIGHT_LINES (0) -#define LTDC_MIN_FRAME_PITCH_BYTES (0) -#define LTDC_MAX_FRAME_WIDTH_BYTES ((1 << 13) - 1 - 3) -#define LTDC_MAX_FRAME_HEIGHT_LINES ((1 << 11) - 1) -#define LTDC_MAX_FRAME_PITCH_BYTES ((1 << 13) - 1) - -#define LTDC_MIN_PIXFMT_ID (0) -#define LTDC_MAX_PIXFMT_ID (7) - -#define LTDC_MAX_PALETTE_LENGTH (256) - -/** @} */ - -/** - * @name LTDC basic ARGB-8888 colors. - * @{ - */ -/* Microsoft Windows default 16-color palette.*/ -#define LTDC_COLOR_BLACK (0xFF000000) -#define LTDC_COLOR_MAROON (0xFF800000) -#define LTDC_COLOR_GREEN (0xFF008000) -#define LTDC_COLOR_OLIVE (0xFF808000) -#define LTDC_COLOR_NAVY (0xFF000080) -#define LTDC_COLOR_PURPLE (0xFF800080) -#define LTDC_COLOR_TEAL (0xFF008080) -#define LTDC_COLOR_SILVER (0xFFC0C0C0) -#define LTDC_COLOR_GRAY (0xFF808080) -#define LTDC_COLOR_RED (0xFFFF0000) -#define LTDC_COLOR_LIME (0xFF00FF00) -#define LTDC_COLOR_YELLOW (0xFFFFFF00) -#define LTDC_COLOR_BLUE (0xFF0000FF) -#define LTDC_COLOR_FUCHSIA (0xFFFF00FF) -#define LTDC_COLOR_AQUA (0xFF00FFFF) -#define LTDC_COLOR_WHITE (0xFFFFFFFF) -/** @} */ - -/*===========================================================================*/ -/* Driver pre-compile time settings. */ -/*===========================================================================*/ - -/** - * @name LTDC configuration options - * @{ - */ - -/** - * @brief LTDC event interrupt priority level setting. - */ -#if !defined(STM32_LTDC_EV_IRQ_PRIORITY) || defined(__DOXYGEN__) -#define STM32_LTDC_EV_IRQ_PRIORITY (11) -#endif - -/** - * @brief LTDC error interrupt priority level setting. - */ -#if !defined(STM32_LTDC_ER_IRQ_PRIORITY) || defined(__DOXYGEN__) -#define STM32_LTDC_ER_IRQ_PRIORITY (11) -#endif - -/** - * @brief Enables synchronous APIs. - * @note Disabling this option saves both code and data space. - */ -#if !defined(LTDC_USE_WAIT) || defined(__DOXYGEN__) -#define LTDC_USE_WAIT (TRUE) -#endif - -/** - * @brief Enables the @p ltdcAcquireBus() and @p ltdcReleaseBus() APIs. - * @note Disabling this option saves both code and data space. - */ -#if !defined(LTDC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) -#define LTDC_USE_MUTUAL_EXCLUSION (TRUE) -#endif - -/** - * @brief Provides software color conversion functions. - * @note Disabling this option saves both code and data space. - */ -#if !defined(LTDC_USE_SOFTWARE_CONVERSIONS) || defined(__DOXYGEN__) -#define LTDC_USE_SOFTWARE_CONVERSIONS (TRUE) -#endif - -/** - * @brief Enables checks for LTDC functions. - * @note Disabling this option saves both code and data space. - * @note Disabling checks by ChibiOS will automatically disable LTDC checks. - */ -#if !defined(LTDC_USE_CHECKS) || defined(__DOXYGEN__) -#define LTDC_USE_CHECKS (TRUE) -#endif - -/** @} */ - -/*===========================================================================*/ -/* Derived constants and error checks. */ -/*===========================================================================*/ - -#if (TRUE != STM32_HAS_LTDC) -#error "LTDC must be present when using the LTDC subsystem" -#endif - -#if (TRUE == STM32_LTDC_USE_LTDC) && (TRUE != STM32_HAS_LTDC) -#error "LTDC not present in the selected device" -#endif - -#if (TRUE == LTDC_USE_MUTUAL_EXCLUSION) -#if (TRUE != CH_CFG_USE_MUTEXES) && (TRUE != CH_CFG_USE_SEMAPHORES) -#error "LTDC_USE_MUTUAL_EXCLUSION requires CH_CFG_USE_MUTEXES and/or CH_CFG_USE_SEMAPHORES" -#endif -#endif - -/*===========================================================================*/ -/* Driver data structures and types. */ -/*===========================================================================*/ - -/* Complex types forwarding.*/ -typedef union ltdc_coloralias_t ltdc_coloralias_t; -typedef struct ltdc_window_t ltdc_window_t; -typedef struct ltdc_frame_t ltdc_frame_t; -typedef struct ltdc_laycfg_t ltdc_laycfg_t; -typedef struct LTDCConfig LTDCConfig; -typedef enum ltdc_state_t ltdc_state_t; -typedef struct LTDCDriver LTDCDriver; - -/** - * @name LTDC Data types - * @{ - */ - -/** - * @brief LTDC generic color. - */ -typedef uint32_t ltdc_color_t; - -/** - * @brief LTDC color aliases. - * @detail Mapped with ARGB-8888, except for luminance (L mapped onto B). - * Padding fields are prefixed with 'x', and should be clear - * (all 0) before compression and set (all 1) after expansion. - */ -typedef union ltdc_coloralias_t { - struct { - unsigned b : 8; - unsigned g : 8; - unsigned r : 8; - unsigned a : 8; - } argb8888; /**< Mapped ARGB-8888 bits.*/ - struct { - unsigned b : 8; - unsigned g : 8; - unsigned r : 8; - unsigned xa : 8; - } rgb888; /**< Mapped RGB-888 bits.*/ - struct { - unsigned xb : 3; - unsigned b : 5; - unsigned xg : 2; - unsigned g : 6; - unsigned xr : 3; - unsigned r : 5; - unsigned xa : 8; - } rgb565; /**< Mapped RGB-565 bits.*/ - struct { - unsigned xb : 3; - unsigned b : 5; - unsigned xg : 3; - unsigned g : 5; - unsigned xr : 3; - unsigned r : 5; - unsigned xa : 7; - unsigned a : 1; - } argb1555; /**< Mapped ARGB-1555 values.*/ - struct { - unsigned xb : 4; - unsigned b : 4; - unsigned xg : 4; - unsigned g : 4; - unsigned xr : 4; - unsigned r : 4; - unsigned xa : 4; - unsigned a : 4; - } argb4444; /**< Mapped ARGB-4444 values.*/ - struct { - unsigned l : 8; - unsigned x : 16; - unsigned xa : 8; - } l8; /**< Mapped L-8 bits.*/ - struct { - unsigned xl : 4; - unsigned l : 4; - unsigned x : 16; - unsigned xa : 4; - unsigned a : 4; - } al44; /**< Mapped AL-44 bits.*/ - struct { - unsigned l : 8; - unsigned x : 16; - unsigned a : 8; - } al88; /**< Mapped AL-88 bits.*/ - ltdc_color_t aliased; /**< Aliased raw bits.*/ -} ltdc_coloralias_t; - -/** - * @brief LTDC layer identifier. - */ -typedef uint32_t ltdc_layerid_t; - -/** - * @brief LTDC pixel format. - */ -typedef uint32_t ltdc_pixfmt_t; - -/** - * @brief LTDC blending factor. - */ -typedef uint32_t ltdc_blendf_t; - -/** - * @brief LTDC ISR callback. - */ -typedef void (*ltdc_isrcb_t)(LTDCDriver *ltdcp); - -/** - * @brief LTDC window specifications. - */ -typedef struct ltdc_window_t { - uint16_t hstart; /**< Horizontal start pixel (left).*/ - uint16_t hstop; /**< Horizontal stop pixel (right).*/ - uint16_t vstart; /**< Vertical start pixel (top).*/ - uint16_t vstop; /**< Vertical stop pixel (bottom).*/ -} ltdc_window_t; - -/** - * @brief LTDC frame specifications. - */ -typedef struct ltdc_frame_t { - void *bufferp; /**< Frame buffer address.*/ - uint16_t width; /**< Frame width, in pixels.*/ - uint16_t height; /**< Frame height, in pixels.*/ - size_t pitch; /**< Line pitch, in bytes.*/ - ltdc_pixfmt_t fmt; /**< Pixel format.*/ -} ltdc_frame_t; - -/** - * @brief LTDC configuration flags. - */ -typedef uint8_t ltdc_flags_t; - -/** - * @brief LTDC startup layer configuration. - */ -typedef struct ltdc_laycfg_t { - const ltdc_frame_t *frame; /**< Frame buffer specifications.*/ - const ltdc_window_t *window; /**< Window specifications.*/ - ltdc_color_t def_color; /**< Default color, ARGB-8888.*/ - uint8_t const_alpha; /**< Constant alpha factor.*/ - ltdc_color_t key_color; /**< Color key.*/ - const ltdc_color_t *pal_colors; /**< Palette colors, or @p NULL.*/ - uint16_t pal_length; /**< Palette length, or @p 0.*/ - ltdc_blendf_t blending; /**< Blending factors.*/ - ltdc_flags_t flags; /**< Layer configuration flags.*/ -} ltdc_laycfg_t; - -/** - * @brief LTDC driver configuration. - */ -typedef struct LTDCConfig { - /* Display specifications.*/ - uint16_t screen_width; /**< Screen pixel width.*/ - uint16_t screen_height; /**< Screen pixel height.*/ - uint16_t hsync_width; /**< Horizontal sync pixel width.*/ - uint16_t vsync_height; /**< Vertical sync pixel height.*/ - uint16_t hbp_width; /**< Horizontal back porch pixel width.*/ - uint16_t vbp_height; /**< Vertical back porch pixel height.*/ - uint16_t hfp_width; /**< Horizontal front porch pixel width.*/ - uint16_t vfp_height; /**< Vertical front porch pixel height.*/ - ltdc_flags_t flags; /**< Driver configuration flags.*/ - - /* ISR callbacks.*/ - ltdc_isrcb_t line_isr; /**< Line Interrupt ISR, or @p NULL.*/ - ltdc_isrcb_t rr_isr; /**< Register Reload ISR, or @p NULL.*/ - ltdc_isrcb_t fuerr_isr; /**< FIFO Underrun ISR, or @p NULL.*/ - ltdc_isrcb_t terr_isr; /**< Transfer Error ISR, or @p NULL.*/ - - /* Layer and color settings.*/ - ltdc_color_t clear_color; /**< Clear screen color, RGB-888.*/ - const ltdc_laycfg_t *bg_laycfg; /**< Background layer specs, or @p NULL.*/ - const ltdc_laycfg_t *fg_laycfg; /**< Foreground layer specs, or @p NULL.*/ -} LTDCConfig; - -/** - * @brief LTDC driver state. - */ -typedef enum ltdc_state_t { - LTDC_UNINIT = (0), /**< Not initialized.*/ - LTDC_STOP = (1), /**< Stopped.*/ - LTDC_READY = (2), /**< Ready.*/ - LTDC_ACTIVE = (3), /**< Executing commands.*/ -} ltdc_state_t; - -/** - * @brief LTDC driver. - */ -typedef struct LTDCDriver { - ltdc_state_t state; /**< Driver state.*/ - const LTDCConfig *config; /**< Driver configuration.*/ - - /* Handy computations.*/ - ltdc_window_t active_window; /**< Active window coordinates.*/ - - /* Multithreading stuff.*/ -#if (TRUE == LTDC_USE_WAIT) || defined(__DOXYGEN__) - thread_t *thread; /**< Waiting thread.*/ -#endif /* LTDC_USE_WAIT */ -#if (TRUE == LTDC_USE_MUTUAL_EXCLUSION) -#if (TRUE == CH_CFG_USE_MUTEXES) - mutex_t lock; /**< Multithreading lock.*/ -#elif (TRUE == CH_CFG_USE_SEMAPHORES) - semaphore_t lock; /**< Multithreading lock.*/ -#endif -#endif /* LTDC_USE_MUTUAL_EXCLUSION */ -} LTDCDriver; - -/** @} */ - -/*===========================================================================*/ -/* Driver macros. */ -/*===========================================================================*/ - -/** - * @brief Makes an ARGB-8888 value from byte components. - * - * @param[in] a alpha byte component - * @param[in] r red byte component - * @param[in] g green byte component - * @param[in] b blue byte component - * - * @return color in ARGB-8888 format - * - * @api - */ -#define ltdcMakeARGB8888(a, r, g, b) \ - ((((ltdc_color_t)(a) & 0xFF) << 24) | \ - (((ltdc_color_t)(r) & 0xFF) << 16) | \ - (((ltdc_color_t)(g) & 0xFF) << 8) | \ - (((ltdc_color_t)(b) & 0xFF) << 0)) - -/** - * @brief Compute bytes per pixel. - * @details Computes the bytes per pixel for the specified pixel format. - * Rounds to the ceiling. - * - * @param[in] fmt pixel format - * - * @return bytes per pixel - * - * @api - */ -#define ltdcBytesPerPixel(fmt) \ - ((ltdcBitsPerPixel(fmt) + 7) >> 3) - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -extern LTDCDriver LTDCD1; - -#ifdef __cplusplus -extern "C" { -#endif - /* Driver methods.*/ - void ltdcInit(void); - void ltdcObjectInit(LTDCDriver *ltdcp); - ltdc_state_t ltdcGetStateI(LTDCDriver *ltdcp); - ltdc_state_t ltdcGetState(LTDCDriver *ltdcp); - void ltdcStart(LTDCDriver *ltdcp, const LTDCConfig *configp); - void ltdcStop(LTDCDriver *ltdcp); -#if (TRUE == LTDC_USE_MUTUAL_EXCLUSION) - void ltdcAcquireBusS(LTDCDriver *ltdcp); - void ltdcAcquireBus(LTDCDriver *ltdcp); - void ltdcReleaseBusS(LTDCDriver *ltdcp); - void ltdcReleaseBus(LTDCDriver *ltdcp); -#endif /* LTDC_USE_MUTUAL_EXCLUSION */ - - /* Global methods.*/ - ltdc_flags_t ltdcGetEnableFlagsI(LTDCDriver *ltdcp); - ltdc_flags_t ltdcGetEnableFlags(LTDCDriver *ltdcp); - void ltdcSetEnableFlagsI(LTDCDriver *ltdcp, ltdc_flags_t flags); - void ltdcSetEnableFlags(LTDCDriver *ltdcp, ltdc_flags_t flags); - bool ltdcIsReloadingI(LTDCDriver *ltdcp); - bool ltdcIsReloading(LTDCDriver *ltdcp); - void ltdcStartReloadI(LTDCDriver *ltdcp, bool immediately); - void ltdcStartReload(LTDCDriver *ltdcp, bool immediately); - void ltdcReloadS(LTDCDriver *ltdcp, bool immediately); - void ltdcReload(LTDCDriver *ltdcp, bool immediately); - bool ltdcIsDitheringEnabledI(LTDCDriver *ltdcp); - bool ltdcIsDitheringEnabled(LTDCDriver *ltdcp); - void ltdcEnableDitheringI(LTDCDriver *ltdcp); - void ltdcEnableDithering(LTDCDriver *ltdcp); - void ltdcDisableDitheringI(LTDCDriver *ltdcp); - void ltdcDisableDithering(LTDCDriver *ltdcp); - ltdc_color_t ltdcGetClearColorI(LTDCDriver *ltdcp); - ltdc_color_t ltdcGetClearColor(LTDCDriver *ltdcp); - void ltdcSetClearColorI(LTDCDriver *ltdcp, ltdc_color_t c); - void ltdcSetClearColor(LTDCDriver *ltdcp, ltdc_color_t c); - uint16_t ltdcGetLineInterruptPosI(LTDCDriver *ltdcp); - uint16_t ltdcGetLineInterruptPos(LTDCDriver *ltdcp); - void ltdcSetLineInterruptPosI(LTDCDriver *ltdcp, uint16_t line); - void ltdcSetLineInterruptPos(LTDCDriver *ltdcp, uint16_t line); - bool ltdcIsLineInterruptEnabledI(LTDCDriver *ltdcp); - bool ltdcIsLineInterruptEnabled(LTDCDriver *ltdcp); - void ltdcEnableLineInterruptI(LTDCDriver *ltdcp); - void ltdcEnableLineInterrupt(LTDCDriver *ltdcp); - void ltdcDisableLineInterruptI(LTDCDriver *ltdcp); - void ltdcDisableLineInterrupt(LTDCDriver *ltdcp); - void ltdcGetCurrentPosI(LTDCDriver *ltdcp, uint16_t *xp, uint16_t *yp); - void ltdcGetCurrentPos(LTDCDriver *ltdcp, uint16_t *xp, uint16_t *yp); - - /* Background layer methods.*/ - ltdc_flags_t ltdcBgGetEnableFlagsI(LTDCDriver *ltdcp); - ltdc_flags_t ltdcBgGetEnableFlags(LTDCDriver *ltdcp); - void ltdcBgSetEnableFlagsI(LTDCDriver *ltdcp, ltdc_flags_t flags); - void ltdcBgSetEnableFlags(LTDCDriver *ltdcp, ltdc_flags_t flags); - bool ltdcBgIsEnabledI(LTDCDriver *ltdcp); - bool ltdcBgIsEnabled(LTDCDriver *ltdcp); - void ltdcBgEnableI(LTDCDriver *ltdcp); - void ltdcBgEnable(LTDCDriver *ltdcp); - void ltdcBgDisableI(LTDCDriver *ltdcp); - void ltdcBgDisable(LTDCDriver *ltdcp); - bool ltdcBgIsPaletteEnabledI(LTDCDriver *ltdcp); - bool ltdcBgIsPaletteEnabled(LTDCDriver *ltdcp); - void ltdcBgEnablePaletteI(LTDCDriver *ltdcp); - void ltdcBgEnablePalette(LTDCDriver *ltdcp); - void ltdcBgDisablePaletteI(LTDCDriver *ltdcp); - void ltdcBgDisablePalette(LTDCDriver *ltdcp); - void ltdcBgSetPaletteColorI(LTDCDriver *ltdcp, uint8_t slot, ltdc_color_t c); - void ltdcBgSetPaletteColor(LTDCDriver *ltdcp, uint8_t slot, ltdc_color_t c); - void ltdcBgSetPaletteI(LTDCDriver *ltdcp, const ltdc_color_t colors[], - uint16_t length); - void ltdcBgSetPalette(LTDCDriver *ltdcp, const ltdc_color_t colors[], - uint16_t length); - ltdc_pixfmt_t ltdcBgGetPixelFormatI(LTDCDriver *ltdcp); - ltdc_pixfmt_t ltdcBgGetPixelFormat(LTDCDriver *ltdcp); - void ltdcBgSetPixelFormatI(LTDCDriver *ltdcp, ltdc_pixfmt_t fmt); - void ltdcBgSetPixelFormat(LTDCDriver *ltdcp, ltdc_pixfmt_t fmt); - bool ltdcBgIsKeyingEnabledI(LTDCDriver *ltdcp); - bool ltdcBgIsKeyingEnabled(LTDCDriver *ltdcp); - void ltdcBgEnableKeyingI(LTDCDriver *ltdcp); - void ltdcBgEnableKeying(LTDCDriver *ltdcp); - void ltdcBgDisableKeyingI(LTDCDriver *ltdcp); - void ltdcBgDisableKeying(LTDCDriver *ltdcp); - ltdc_color_t ltdcBgGetKeyingColorI(LTDCDriver *ltdcp); - ltdc_color_t ltdcBgGetKeyingColor(LTDCDriver *ltdcp); - void ltdcBgSetKeyingColorI(LTDCDriver *ltdcp, ltdc_color_t c); - void ltdcBgSetKeyingColor(LTDCDriver *ltdcp, ltdc_color_t c); - uint8_t ltdcBgGetConstantAlphaI(LTDCDriver *ltdcp); - uint8_t ltdcBgGetConstantAlpha(LTDCDriver *ltdcp); - void ltdcBgSetConstantAlphaI(LTDCDriver *ltdcp, uint8_t a); - void ltdcBgSetConstantAlpha(LTDCDriver *ltdcp, uint8_t a); - ltdc_color_t ltdcBgGetDefaultColorI(LTDCDriver *ltdcp); - ltdc_color_t ltdcBgGetDefaultColor(LTDCDriver *ltdcp); - void ltdcBgSetDefaultColorI(LTDCDriver *ltdcp, ltdc_color_t c); - void ltdcBgSetDefaultColor(LTDCDriver *ltdcp, ltdc_color_t c); - ltdc_blendf_t ltdcBgGetBlendingFactorsI(LTDCDriver *ltdcp); - ltdc_blendf_t ltdcBgGetBlendingFactors(LTDCDriver *ltdcp); - void ltdcBgSetBlendingFactorsI(LTDCDriver *ltdcp, ltdc_blendf_t bf); - void ltdcBgSetBlendingFactors(LTDCDriver *ltdcp, ltdc_blendf_t bf); - void ltdcBgGetWindowI(LTDCDriver *ltdcp, ltdc_window_t *windowp); - void ltdcBgGetWindow(LTDCDriver *ltdcp, ltdc_window_t *windowp); - void ltdcBgSetWindowI(LTDCDriver *ltdcp, const ltdc_window_t *windowp); - void ltdcBgSetWindow(LTDCDriver *ltdcp, const ltdc_window_t *windowp); - void ltdcBgSetInvalidWindowI(LTDCDriver *ltdcp); - void ltdcBgSetInvalidWindow(LTDCDriver *ltdcp); - void ltdcBgGetFrameI(LTDCDriver *ltdcp, ltdc_frame_t *framep); - void ltdcBgGetFrame(LTDCDriver *ltdcp, ltdc_frame_t *framep); - void ltdcBgSetFrameI(LTDCDriver *ltdcp, const ltdc_frame_t *framep); - void ltdcBgSetFrame(LTDCDriver *ltdcp, const ltdc_frame_t *framep); - void *ltdcBgGetFrameAddressI(LTDCDriver *ltdcp); - void *ltdcBgGetFrameAddress(LTDCDriver *ltdcp); - void ltdcBgSetFrameAddressI(LTDCDriver *ltdcp, void *bufferp); - void ltdcBgSetFrameAddress(LTDCDriver *ltdcp, void *bufferp); - void ltdcBgGetLayerI(LTDCDriver *ltdcp, ltdc_laycfg_t *cfgp); - void ltdcBgGetLayer(LTDCDriver *ltdcp, ltdc_laycfg_t *cfgp); - void ltdcBgSetConfigI(LTDCDriver *ltdcp, const ltdc_laycfg_t *cfgp); - void ltdcBgSetConfig(LTDCDriver *ltdcp, const ltdc_laycfg_t *cfgp); - - /* Foreground layer methods.*/ - ltdc_flags_t ltdcFgGetEnableFlagsI(LTDCDriver *ltdcp); - ltdc_flags_t ltdcFgGetEnableFlags(LTDCDriver *ltdcp); - void ltdcFgSetEnableFlagsI(LTDCDriver *ltdcp, ltdc_flags_t flags); - void ltdcFgSetEnableFlags(LTDCDriver *ltdcp, ltdc_flags_t flags); - bool ltdcFgIsEnabledI(LTDCDriver *ltdcp); - bool ltdcFgIsEnabled(LTDCDriver *ltdcp); - void ltdcFgEnableI(LTDCDriver *ltdcp); - void ltdcFgEnable(LTDCDriver *ltdcp); - void ltdcFgDisableI(LTDCDriver *ltdcp); - void ltdcFgDisable(LTDCDriver *ltdcp); - bool ltdcFgIsPaletteEnabledI(LTDCDriver *ltdcp); - bool ltdcFgIsPaletteEnabled(LTDCDriver *ltdcp); - void ltdcFgEnablePaletteI(LTDCDriver *ltdcp); - void ltdcFgEnablePalette(LTDCDriver *ltdcp); - void ltdcFgDisablePaletteI(LTDCDriver *ltdcp); - void ltdcFgDisablePalette(LTDCDriver *ltdcp); - void ltdcFgSetPaletteColorI(LTDCDriver *ltdcp, uint8_t slot, ltdc_color_t c); - void ltdcFgSetPaletteColor(LTDCDriver *ltdcp, uint8_t slot, ltdc_color_t c); - void ltdcFgSetPaletteI(LTDCDriver *ltdcp, const ltdc_color_t colors[], - uint16_t length); - void ltdcFgSetPalette(LTDCDriver *ltdcp, const ltdc_color_t colors[], - uint16_t length); - ltdc_pixfmt_t ltdcFgGetPixelFormatI(LTDCDriver *ltdcp); - ltdc_pixfmt_t ltdcFgGetPixelFormat(LTDCDriver *ltdcp); - void ltdcFgSetPixelFormatI(LTDCDriver *ltdcp, ltdc_pixfmt_t fmt); - void ltdcFgSetPixelFormat(LTDCDriver *ltdcp, ltdc_pixfmt_t fmt); - bool ltdcFgIsKeyingEnabledI(LTDCDriver *ltdcp); - bool ltdcFgIsKeyingEnabled(LTDCDriver *ltdcp); - void ltdcFgEnableKeyingI(LTDCDriver *ltdcp); - void ltdcFgEnableKeying(LTDCDriver *ltdcp); - void ltdcFgDisableKeyingI(LTDCDriver *ltdcp); - void ltdcFgDisableKeying(LTDCDriver *ltdcp); - ltdc_color_t ltdcFgGetKeyingColorI(LTDCDriver *ltdcp); - ltdc_color_t ltdcFgGetKeyingColor(LTDCDriver *ltdcp); - void ltdcFgSetKeyingColorI(LTDCDriver *ltdcp, ltdc_color_t c); - void ltdcFgSetKeyingColor(LTDCDriver *ltdcp, ltdc_color_t c); - uint8_t ltdcFgGetConstantAlphaI(LTDCDriver *ltdcp); - uint8_t ltdcFgGetConstantAlpha(LTDCDriver *ltdcp); - void ltdcFgSetConstantAlphaI(LTDCDriver *ltdcp, uint8_t a); - void ltdcFgSetConstantAlpha(LTDCDriver *ltdcp, uint8_t a); - ltdc_color_t ltdcFgGetDefaultColorI(LTDCDriver *ltdcp); - ltdc_color_t ltdcFgGetDefaultColor(LTDCDriver *ltdcp); - void ltdcFgSetDefaultColorI(LTDCDriver *ltdcp, ltdc_color_t c); - void ltdcFgSetDefaultColor(LTDCDriver *ltdcp, ltdc_color_t c); - ltdc_blendf_t ltdcFgGetBlendingFactorsI(LTDCDriver *ltdcp); - ltdc_blendf_t ltdcFgGetBlendingFactors(LTDCDriver *ltdcp); - void ltdcFgSetBlendingFactorsI(LTDCDriver *ltdcp, ltdc_blendf_t bf); - void ltdcFgSetBlendingFactors(LTDCDriver *ltdcp, ltdc_blendf_t bf); - void ltdcFgGetWindowI(LTDCDriver *ltdcp, ltdc_window_t *windowp); - void ltdcFgGetWindow(LTDCDriver *ltdcp, ltdc_window_t *windowp); - void ltdcFgSetWindowI(LTDCDriver *ltdcp, const ltdc_window_t *windowp); - void ltdcFgSetWindow(LTDCDriver *ltdcp, const ltdc_window_t *windowp); - void ltdcFgSetInvalidWindowI(LTDCDriver *ltdcp); - void ltdcFgSetInvalidWindow(LTDCDriver *ltdcp); - void ltdcFgGetFrameI(LTDCDriver *ltdcp, ltdc_frame_t *framep); - void ltdcFgGetFrame(LTDCDriver *ltdcp, ltdc_frame_t *framep); - void ltdcFgSetFrameI(LTDCDriver *ltdcp, const ltdc_frame_t *framep); - void ltdcFgSetFrame(LTDCDriver *ltdcp, const ltdc_frame_t *framep); - void *ltdcFgGetFrameAddressI(LTDCDriver *ltdcp); - void *ltdcFgGetFrameAddress(LTDCDriver *ltdcp); - void ltdcFgSetFrameAddressI(LTDCDriver *ltdcp, void *bufferp); - void ltdcFgSetFrameAddress(LTDCDriver *ltdcp, void *bufferp); - void ltdcFgGetLayerI(LTDCDriver *ltdcp, ltdc_laycfg_t *cfgp); - void ltdcFgGetLayer(LTDCDriver *ltdcp, ltdc_laycfg_t *cfgp); - void ltdcFgSetConfigI(LTDCDriver *ltdcp, const ltdc_laycfg_t *cfgp); - void ltdcFgSetConfig(LTDCDriver *ltdcp, const ltdc_laycfg_t *cfgp); - - /* Helper functions.*/ - size_t ltdcBitsPerPixel(ltdc_pixfmt_t fmt); -#if (TRUE == LTDC_USE_SOFTWARE_CONVERSIONS) || defined(__DOXYGEN__) - ltdc_color_t ltdcFromARGB8888(ltdc_color_t c, ltdc_pixfmt_t fmt); - ltdc_color_t ltdcToARGB8888(ltdc_color_t c, ltdc_pixfmt_t fmt); -#endif /* LTDC_USE_SOFTWARE_CONVERSIONS */ - -#ifdef __cplusplus -} -#endif - -#endif /* STM32_LTDC_USE_LTDC */ - -#endif /* _STM32_LTDC_H_ */ - -/** @} */ diff --git a/os/hal/ports/STM32/LLD/TIMv1/eicu_lld.c b/os/hal/ports/STM32/LLD/TIMv1/eicu_lld.c deleted file mode 100644 index c04278e..0000000 --- a/os/hal/ports/STM32/LLD/TIMv1/eicu_lld.c +++ /dev/null @@ -1,1176 +0,0 @@ -/* - ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ -/* - Concepts and parts of this file have been contributed by Fabio Utzig and - Xo Wang. -*/ -/* - Rewritten by Emil Fresk (1/5 - 2014) for extended input capture - functionality. And fix for spurious callbacks in the interrupt handler. -*/ -/* - Improved by Uladzimir Pylinsky aka barthess (1/3 - 2015) for support of - 32-bit timers and timers with single capture/compare channels. -*/ - -/* - * Hardware Abstraction Layer for Extended Input Capture Unit - */ -#include "hal.h" - -#if (HAL_USE_EICU == TRUE) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ -/** - * @brief Inverts the polarity for the given channel. - * - * @param[in] eicup Pointer to the EICUDriver object. - * @param[in] channel The timer channel to invert. - * - * @notapi - */ -#define eicu_lld_invert_polarity(eicup, channel) \ - (eicup)->tim->CCER ^= ((uint16_t)(STM32_TIM_CCER_CC1P << ((channel) * 4))) - -/** - * @brief Returns the compare value of the latest cycle. - * - * @param[in] chp Pointer to channel structure that fired the interrupt. - * @return The number of ticks. - * - * @notapi - */ -#define eicu_lld_get_compare(chp) (*((chp)->ccrp) + 1) - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/** - * @brief EICUD1 driver identifier. - * @note The driver EICUD1 allocates the complex timer TIM1 when enabled. - */ -#if STM32_EICU_USE_TIM1 && !defined(__DOXYGEN__) -EICUDriver EICUD1; -#endif - -/** - * @brief EICUD2 driver identifier. - * @note The driver EICUD2 allocates the timer TIM2 when enabled. - */ -#if STM32_EICU_USE_TIM2 && !defined(__DOXYGEN__) -EICUDriver EICUD2; -#endif - -/** - * @brief EICUD3 driver identifier. - * @note The driver EICUD3 allocates the timer TIM3 when enabled. - */ -#if STM32_EICU_USE_TIM3 && !defined(__DOXYGEN__) -EICUDriver EICUD3; -#endif - -/** - * @brief EICUD4 driver identifier. - * @note The driver EICUD4 allocates the timer TIM4 when enabled. - */ -#if STM32_EICU_USE_TIM4 && !defined(__DOXYGEN__) -EICUDriver EICUD4; -#endif - -/** - * @brief EICUD5 driver identifier. - * @note The driver EICUD5 allocates the timer TIM5 when enabled. - */ -#if STM32_EICU_USE_TIM5 && !defined(__DOXYGEN__) -EICUDriver EICUD5; -#endif - -/** - * @brief EICUD8 driver identifier. - * @note The driver EICUD8 allocates the timer TIM8 when enabled. - */ -#if STM32_EICU_USE_TIM8 && !defined(__DOXYGEN__) -EICUDriver EICUD8; -#endif - -/** - * @brief EICUD9 driver identifier. - * @note The driver EICUD9 allocates the timer TIM9 when enabled. - */ -#if STM32_EICU_USE_TIM9 && !defined(__DOXYGEN__) -EICUDriver EICUD9; -#endif - -/** - * @brief EICUD12 driver identifier. - * @note The driver EICUD12 allocates the timer TIM12 when enabled. - */ -#if STM32_EICU_USE_TIM12 && !defined(__DOXYGEN__) -EICUDriver EICUD12; -#endif - -/** - * @brief EICUD10 driver identifier. - * @note The driver EICUD10 allocates the timer TIM10 when enabled. - */ -#if STM32_EICU_USE_TIM10 && !defined(__DOXYGEN__) -EICUDriver EICUD10; -#endif - -/** - * @brief EICUD11 driver identifier. - * @note The driver EICUD11 allocates the timer TIM11 when enabled. - */ -#if STM32_EICU_USE_TIM11 && !defined(__DOXYGEN__) -EICUDriver EICUD11; -#endif - -/** - * @brief EICUD13 driver identifier. - * @note The driver EICUD13 allocates the timer TIM13 when enabled. - */ -#if STM32_EICU_USE_TIM13 && !defined(__DOXYGEN__) -EICUDriver EICUD13; -#endif - -/** - * @brief EICUD14 driver identifier. - * @note The driver EICUD14 allocates the timer TIM14 when enabled. - */ -#if STM32_EICU_USE_TIM14 && !defined(__DOXYGEN__) -EICUDriver EICUD14; -#endif - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ -/** - * @brief Returns both pulse width and period. - * @details The time is defined as number of ticks. - * - * @param[in] eicup Pointer to the EICUDriver object. - * @param[in] channel The timer channel that fired the interrupt. - * @param[in] compare Content of the CCR register. - * @return The number of ticks. - * - * @notapi - */ -static eicuresult_t get_time_both(const EICUDriver *eicup, - eicuchannel_t channel, - eicucnt_t compare) { - - const EICUChannel *chp = &eicup->channel[channel]; - eicuresult_t ret; - - /* Note! there is no overflow check because it handles under the hood of - unsigned subtraction math.*/ - - /* 16-bit timer */ - if (EICU_WIDTH_16 == eicup->width) { - uint16_t cmp = compare; - uint16_t la = chp->last_active; - uint16_t li = chp->last_idle; - uint16_t w = li - la; - uint16_t p = cmp - la; - ret.width = w; - ret.period = p; - } - /* 32-bit timer */ - else if (EICU_WIDTH_32 == eicup->width) { - ret.width = chp->last_idle - chp->last_active; - ret.period = compare - chp->last_active; - } - /* error trap */ - else { - osalSysHalt("Unhandled width value"); - } - - return ret; -} - -/** - * @brief Returns pulse width. - * @details The time is defined as number of ticks. - * - * @param[in] eicup Pointer to the EICUDriver object. - * @param[in] channel The timer channel that fired the interrupt. - * @param[in] compare Content of the CCR register. - * @return The number of ticks. - * - * @notapi - */ -static eicucnt_t get_time_width(const EICUDriver *eicup, - eicuchannel_t channel, - eicucnt_t compare) { - - const EICUChannel *chp = &eicup->channel[channel]; - - /* Note! there is no overflow check because it handles under the hood of - unsigned subtraction math.*/ - - /* 16-bit timer */ - if (EICU_WIDTH_16 == eicup->width) { - uint16_t cmp = compare; - uint16_t la = chp->last_active; - uint16_t ret = cmp - la; - return ret; - } - /* 32-bit timer */ - else if (EICU_WIDTH_32 == eicup->width) { - return compare - chp->last_active; - } - /* error trap */ - else { - osalSysHalt("Unhandled width value"); - return 0; - } -} - -/** - * @brief Returns pulse period. - * @details The time is defined as number of ticks. - * - * @param[in] eicup Pointer to the EICUDriver object. - * @param[in] channel The timer channel that fired the interrupt. - * @param[in] compare Content of the CCR register. - * @return The number of ticks. - * - * @notapi - */ -static eicucnt_t get_time_period(const EICUDriver *eicup, - eicuchannel_t channel, - eicucnt_t compare) { - - const EICUChannel *chp = &eicup->channel[channel]; - - /* Note! there is no overflow check because it handles under the hood of - unsigned subtraction math.*/ - - /* 16-bit timer */ - if (EICU_WIDTH_16 == eicup->width) { - uint16_t cmp = compare; - uint16_t li = chp->last_idle; - uint16_t ret = cmp - li; - return ret; - } - /* 32-bit timer */ - else if (EICU_WIDTH_32 == eicup->width) { - return compare - chp->last_idle; - } - /* error trap */ - else { - osalSysHalt("Unhandled width value"); - return 0; - } -} - -/** - * @brief EICU width or (width + period) event. - * @note Needs special care since it needs to invert the - * correct polarity bit to detect pulses. - * @note Assumes that the polarity is not changed by some - * external user. It must only be changed using the HAL. - * - * @param[in] eicup Pointer to the @p EICUDriver object - * @param[in] channel The timer channel that fired the interrupt. - * - * @notapi - */ -static void isr_invoke_pulse_cb(EICUDriver *eicup, eicuchannel_t channel) { - EICUChannel *chp = &eicup->channel[channel]; - eicucnt_t compare = eicu_lld_get_compare(chp); - - if (EICU_CH_ACTIVE == chp->state) { - chp->state = EICU_CH_IDLE; - eicu_lld_invert_polarity(eicup, channel); - if (EICU_INPUT_PULSE == chp->config->mode) { - uint32_t width = get_time_width(eicup, channel, compare); - chp->config->capture_cb(eicup, channel, width, 0); - } - chp->last_idle = compare; - } - else { - chp->state = EICU_CH_ACTIVE; - eicu_lld_invert_polarity(eicup, channel); - if (EICU_INPUT_BOTH == chp->config->mode) { - eicuresult_t both = get_time_both(eicup, channel, compare); - chp->config->capture_cb(eicup, channel, both.width, both.period); - } - chp->last_active = compare; - } -} - -/** - * @brief EICU Edge detect event. - * - * @param[in] eicup Pointer to the @p EICUDriver object - * @param[in] channel The timer channel that fired the interrupt. - * - * @notapi - */ -static void isr_invoke_edge_cb(EICUDriver *eicup, eicuchannel_t channel) { - EICUChannel *chp = &eicup->channel[channel]; - eicucnt_t compare = eicu_lld_get_compare(chp); - uint32_t period = get_time_period(eicup, channel, compare); - - chp->config->capture_cb(eicup, channel, 0, period); - chp->last_idle = compare; -} - -/** - * @brief Common EICU detect call. - * - * @param[in] eicup Pointer to the @p EICUDriver object - * @param[in] channel The timer channel that fired the interrupt. - * - * @notapi - */ -static void eicu_isr_invoke_cb(EICUDriver *eicup, eicuchannel_t channel) { - - if (EICU_INPUT_EDGE == eicup->channel[channel].config->mode) - isr_invoke_edge_cb(eicup, channel); - else /* EICU_INPUT_PULSE || EICU_INPUT_BOTH */ - isr_invoke_pulse_cb(eicup, channel); -} - -/** - * @brief Shared IRQ handler. - * - * @param[in] eicup Pointer to the @p EICUDriver object - */ -static void eicu_lld_serve_interrupt(EICUDriver *eicup) { - uint16_t sr; - sr = eicup->tim->SR; - - /* Pick out the interrupts we are interested in by using - the interrupt enable bits as mask */ - sr &= (eicup->tim->DIER & STM32_TIM_DIER_IRQ_MASK); - - /* Clear interrupts */ - eicup->tim->SR = ~sr; - - if ((sr & STM32_TIM_SR_CC1IF) != 0) - eicu_isr_invoke_cb(eicup, EICU_CHANNEL_1); - if ((sr & STM32_TIM_SR_CC2IF) != 0) - eicu_isr_invoke_cb(eicup, EICU_CHANNEL_2); - if ((sr & STM32_TIM_SR_CC3IF) != 0) - eicu_isr_invoke_cb(eicup, EICU_CHANNEL_3); - if ((sr & STM32_TIM_SR_CC4IF) != 0) - eicu_isr_invoke_cb(eicup, EICU_CHANNEL_4); -} - -/** - * @brief Starts every channel. - * - * @param[in] eicup Pointer to the @p EICUDriver object - */ -static void start_channels(EICUDriver *eicup) { - - /* Set each input channel that is used as: a normal input capture channel, - link the corresponding CCR register and set polarity. */ - - /* Input capture channel 1 */ - if (eicup->config->iccfgp[0] != NULL) { - /* Normal capture input input */ - eicup->tim->CCMR1 |= STM32_TIM_CCMR1_CC1S(1); - - /* Link CCR register */ - eicup->channel[0].ccrp = &eicup->tim->CCR[0]; - - /* Set input polarity */ - if (eicup->config->iccfgp[0]->alvl == EICU_INPUT_ACTIVE_HIGH) - eicup->tim->CCER |= STM32_TIM_CCER_CC1E; - else - eicup->tim->CCER |= STM32_TIM_CCER_CC1E | STM32_TIM_CCER_CC1P; - } - - /* Input capture channel 2 */ - if (eicup->config->iccfgp[1] != NULL) { - /* Normal capture input input */ - eicup->tim->CCMR1 |= STM32_TIM_CCMR1_CC2S(1); - - /* Link CCR register */ - eicup->channel[1].ccrp = &eicup->tim->CCR[1]; - - /* Set input polarity */ - if (eicup->config->iccfgp[1]->alvl == EICU_INPUT_ACTIVE_HIGH) - eicup->tim->CCER |= STM32_TIM_CCER_CC2E; - else - eicup->tim->CCER |= STM32_TIM_CCER_CC2E | STM32_TIM_CCER_CC2P; - } - - /* Input capture channel 3 (not for TIM 9 and 12) */ - if (eicup->config->iccfgp[2] != NULL) { - /* Normal capture input input */ - eicup->tim->CCMR2 |= STM32_TIM_CCMR2_CC3S(1); - - /* Link CCR register */ - eicup->channel[2].ccrp = &eicup->tim->CCR[2]; - - /* Set input polarity */ - if (eicup->config->iccfgp[2]->alvl == EICU_INPUT_ACTIVE_HIGH) - eicup->tim->CCER |= STM32_TIM_CCER_CC3E; - else - eicup->tim->CCER |= STM32_TIM_CCER_CC3E | STM32_TIM_CCER_CC3P; - } - - /* Input capture channel 4 (not for TIM 9 and 12) */ - if (eicup->config->iccfgp[3] != NULL) { - /* Normal capture input input */ - eicup->tim->CCMR2 |= STM32_TIM_CCMR2_CC4S(1); - - /* Link CCR register */ - eicup->channel[3].ccrp = &eicup->tim->CCR[3]; - - /* Set input polarity */ - if (eicup->config->iccfgp[3]->alvl == EICU_INPUT_ACTIVE_HIGH) - eicup->tim->CCER |= STM32_TIM_CCER_CC4E; - else - eicup->tim->CCER |= STM32_TIM_CCER_CC4E | STM32_TIM_CCER_CC4P; - } -} - -/*===========================================================================*/ -/* Driver interrupt handlers. */ -/*===========================================================================*/ - -#if STM32_EICU_USE_TIM1 -#if !defined(STM32_TIM1_UP_HANDLER) -#error "STM32_TIM1_UP_HANDLER not defined" -#endif -/** - * @brief TIM1 compare interrupt handler. - * @note It is assumed that the various sources are only activated if the - * associated callback pointer is not equal to @p NULL in order to not - * perform an extra check in a potentially critical interrupt handler. - * - * @isr - */ -OSAL_IRQ_HANDLER(STM32_TIM1_UP_HANDLER) { - - OSAL_IRQ_PROLOGUE(); - - eicu_lld_serve_interrupt(&EICUD1); - - OSAL_IRQ_EPILOGUE(); -} - -#if !defined(STM32_TIM1_CC_HANDLER) -#error "STM32_TIM1_CC_HANDLER not defined" -#endif -/** - * @brief TIM1 compare interrupt handler. - * @note It is assumed that the various sources are only activated if the - * associated callback pointer is not equal to @p NULL in order to not - * perform an extra check in a potentially critical interrupt handler. - * - * @isr - */ -OSAL_IRQ_HANDLER(STM32_TIM1_CC_HANDLER) { - - OSAL_IRQ_PROLOGUE(); - - eicu_lld_serve_interrupt(&EICUD1); - - OSAL_IRQ_EPILOGUE(); -} -#endif /* STM32_EICU_USE_TIM1 */ - -#if STM32_EICU_USE_TIM2 - -#if !defined(STM32_TIM2_HANDLER) -#error "STM32_TIM2_HANDLER not defined" -#endif -/** - * @brief TIM2 interrupt handler. - * @note It is assumed that the various sources are only activated if the - * associated callback pointer is not equal to @p NULL in order to not - * perform an extra check in a potentially critical interrupt handler. - * - * @isr - */ -OSAL_IRQ_HANDLER(STM32_TIM2_HANDLER) { - - OSAL_IRQ_PROLOGUE(); - - eicu_lld_serve_interrupt(&EICUD2); - - OSAL_IRQ_EPILOGUE(); -} -#endif /* STM32_EICU_USE_TIM2 */ - -#if STM32_EICU_USE_TIM3 -#if !defined(STM32_TIM3_HANDLER) -#error "STM32_TIM3_HANDLER not defined" -#endif -/** - * @brief TIM3 interrupt handler. - * @note It is assumed that the various sources are only activated if the - * associated callback pointer is not equal to @p NULL in order to not - * perform an extra check in a potentially critical interrupt handler. - * - * @isr - */ -OSAL_IRQ_HANDLER(STM32_TIM3_HANDLER) { - - OSAL_IRQ_PROLOGUE(); - - eicu_lld_serve_interrupt(&EICUD3); - - OSAL_IRQ_EPILOGUE(); -} -#endif /* STM32_EICU_USE_TIM3 */ - -#if STM32_EICU_USE_TIM4 -#if !defined(STM32_TIM4_HANDLER) -#error "STM32_TIM4_HANDLER not defined" -#endif -/** - * @brief TIM4 interrupt handler. - * @note It is assumed that the various sources are only activated if the - * associated callback pointer is not equal to @p NULL in order to not - * perform an extra check in a potentially critical interrupt handler. - * - * @isr - */ -OSAL_IRQ_HANDLER(STM32_TIM4_HANDLER) { - - OSAL_IRQ_PROLOGUE(); - - eicu_lld_serve_interrupt(&EICUD4); - - OSAL_IRQ_EPILOGUE(); -} -#endif /* STM32_EICU_USE_TIM4 */ - -#if STM32_EICU_USE_TIM5 -#if !defined(STM32_TIM5_HANDLER) -#error "STM32_TIM5_HANDLER not defined" -#endif -/** - * @brief TIM5 interrupt handler. - * @note It is assumed that the various sources are only activated if the - * associated callback pointer is not equal to @p NULL in order to not - * perform an extra check in a potentially critical interrupt handler. - * - * @isr - */ -OSAL_IRQ_HANDLER(STM32_TIM5_HANDLER) { - - OSAL_IRQ_PROLOGUE(); - - eicu_lld_serve_interrupt(&EICUD5); - - OSAL_IRQ_EPILOGUE(); -} -#endif /* STM32_EICU_USE_TIM5 */ - -#if STM32_EICU_USE_TIM8 -#if !defined(STM32_TIM8_UP_HANDLER) -#error "STM32_TIM8_UP_HANDLER not defined" -#endif -/** - * @brief TIM8 compare interrupt handler. - * @note It is assumed that the various sources are only activated if the - * associated callback pointer is not equal to @p NULL in order to not - * perform an extra check in a potentially critical interrupt handler. - * - * @isr - */ -OSAL_IRQ_HANDLER(STM32_TIM8_UP_HANDLER) { - - OSAL_IRQ_PROLOGUE(); - - eicu_lld_serve_interrupt(&EICUD8); - - OSAL_IRQ_EPILOGUE(); -} - -#if !defined(STM32_TIM8_CC_HANDLER) -#error "STM32_TIM8_CC_HANDLER not defined" -#endif -/** - * @brief TIM8 compare interrupt handler. - * @note It is assumed that the various sources are only activated if the - * associated callback pointer is not equal to @p NULL in order to not - * perform an extra check in a potentially critical interrupt handler. - * - * @isr - */ -OSAL_IRQ_HANDLER(STM32_TIM8_CC_HANDLER) { - - OSAL_IRQ_PROLOGUE(); - - eicu_lld_serve_interrupt(&EICUD8); - - OSAL_IRQ_EPILOGUE(); -} -#endif /* STM32_EICU_USE_TIM8 */ - -#if STM32_EICU_USE_TIM9 -#if !defined(STM32_TIM9_HANDLER) -#error "STM32_TIM9_HANDLER not defined" -#endif -/** - * @brief TIM9 interrupt handler. - * @note It is assumed that the various sources are only activated if the - * associated callback pointer is not equal to @p NULL in order to not - * perform an extra check in a potentially critical interrupt handler. - * - * @isr - */ -OSAL_IRQ_HANDLER(STM32_TIM9_HANDLER) { - - OSAL_IRQ_PROLOGUE(); - - eicu_lld_serve_interrupt(&EICUD9); - - OSAL_IRQ_EPILOGUE(); -} -#endif /* STM32_EICU_USE_TIM9 */ - -#if STM32_EICU_USE_TIM12 -#if !defined(STM32_TIM12_HANDLER) -#error "STM32_TIM12_HANDLER not defined" -#endif -/** - * @brief TIM12 interrupt handler. - * @note It is assumed that the various sources are only activated if the - * associated callback pointer is not equal to @p NULL in order to not - * perform an extra check in a potentially critical interrupt handler. - * - * @isr - */ -OSAL_IRQ_HANDLER(STM32_TIM12_HANDLER) { - - OSAL_IRQ_PROLOGUE(); - - eicu_lld_serve_interrupt(&EICUD12); - - OSAL_IRQ_EPILOGUE(); -} -#endif /* STM32_EICU_USE_TIM12 */ - -#if STM32_EICU_USE_TIM10 -#if !defined(STM32_TIM10_HANDLER) -#error "STM32_TIM10_HANDLER not defined" -#endif -/** - * @brief TIM10 interrupt handler. - * @note It is assumed that the various sources are only activated if the - * associated callback pointer is not equal to @p NULL in order to not - * perform an extra check in a potentially critical interrupt handler. - * - * @isr - */ -OSAL_IRQ_HANDLER(STM32_TIM10_HANDLER) { - - OSAL_IRQ_PROLOGUE(); - - eicu_lld_serve_interrupt(&EICUD10); - - OSAL_IRQ_EPILOGUE(); -} -#endif /* STM32_EICU_USE_TIM10 */ - -#if STM32_EICU_USE_TIM11 -#if !defined(STM32_TIM11_HANDLER) -#error "STM32_TIM11_HANDLER not defined" -#endif -/** - * @brief TIM11 interrupt handler. - * @note It is assumed that the various sources are only activated if the - * associated callback pointer is not equal to @p NULL in order to not - * perform an extra check in a potentially critical interrupt handler. - * - * @isr - */ -OSAL_IRQ_HANDLER(STM32_TIM11_HANDLER) { - - OSAL_IRQ_PROLOGUE(); - - eicu_lld_serve_interrupt(&EICUD11); - - OSAL_IRQ_EPILOGUE(); -} -#endif /* STM32_EICU_USE_TIM11 */ - -#if STM32_EICU_USE_TIM13 -#if !defined(STM32_TIM13_HANDLER) -#error "STM32_TIM13_HANDLER not defined" -#endif -/** - * @brief TIM13 interrupt handler. - * @note It is assumed that the various sources are only activated if the - * associated callback pointer is not equal to @p NULL in order to not - * perform an extra check in a potentially critical interrupt handler. - * - * @isr - */ -OSAL_IRQ_HANDLER(STM32_TIM13_HANDLER) { - - OSAL_IRQ_PROLOGUE(); - - eicu_lld_serve_interrupt(&EICUD13); - - OSAL_IRQ_EPILOGUE(); -} -#endif /* STM32_EICU_USE_TIM13 */ - -#if STM32_EICU_USE_TIM14 -#if !defined(STM32_TIM14_HANDLER) -#error "STM32_TIM14_HANDLER not defined" -#endif -/** - * @brief TIM14 interrupt handler. - * @note It is assumed that the various sources are only activated if the - * associated callback pointer is not equal to @p NULL in order to not - * perform an extra check in a potentially critical interrupt handler. - * - * @isr - */ -OSAL_IRQ_HANDLER(STM32_TIM14_HANDLER) { - - OSAL_IRQ_PROLOGUE(); - - eicu_lld_serve_interrupt(&EICUD14); - - OSAL_IRQ_EPILOGUE(); -} -#endif /* STM32_EICU_USE_TIM14 */ - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief Low level EICU driver initialization. - * - * @notapi - */ -void eicu_lld_init(void) { -#if STM32_EICU_USE_TIM1 - /* Driver initialization.*/ - eicuObjectInit(&EICUD1); - EICUD1.tim = STM32_TIM1; -#endif - -#if STM32_EICU_USE_TIM2 - /* Driver initialization.*/ - eicuObjectInit(&EICUD2); - EICUD2.tim = STM32_TIM2; -#endif - -#if STM32_EICU_USE_TIM3 - /* Driver initialization.*/ - eicuObjectInit(&EICUD3); - EICUD3.tim = STM32_TIM3; -#endif - -#if STM32_EICU_USE_TIM4 - /* Driver initialization.*/ - eicuObjectInit(&EICUD4); - EICUD4.tim = STM32_TIM4; -#endif - -#if STM32_EICU_USE_TIM5 - /* Driver initialization.*/ - eicuObjectInit(&EICUD5); - EICUD5.tim = STM32_TIM5; -#endif - -#if STM32_EICU_USE_TIM8 - /* Driver initialization.*/ - eicuObjectInit(&EICUD8); - EICUD8.tim = STM32_TIM8; -#endif - -#if STM32_EICU_USE_TIM9 - /* Driver initialization.*/ - eicuObjectInit(&EICUD9); - EICUD9.tim = STM32_TIM9; -#endif - -#if STM32_EICU_USE_TIM12 - /* Driver initialization.*/ - eicuObjectInit(&EICUD12); - EICUD12.tim = STM32_TIM12; -#endif - -#if STM32_EICU_USE_TIM10 - /* Driver initialization.*/ - eicuObjectInit(&EICUD10); - EICUD10.tim = STM32_TIM10; -#endif - -#if STM32_EICU_USE_TIM11 - /* Driver initialization.*/ - eicuObjectInit(&EICUD11); - EICUD11.tim = STM32_TIM11; -#endif - -#if STM32_EICU_USE_TIM13 - /* Driver initialization.*/ - eicuObjectInit(&EICUD13); - EICUD13.tim = STM32_TIM13; -#endif - -#if STM32_EICU_USE_TIM14 - /* Driver initialization.*/ - eicuObjectInit(&EICUD14); - EICUD14.tim = STM32_TIM14; -#endif -} - -/** - * @brief Configures and activates the EICU peripheral. - * - * @param[in] eicup Pointer to the @p EICUDriver object - * - * @notapi - */ -void eicu_lld_start(EICUDriver *eicup) { - uint32_t psc; - size_t ch; - - osalDbgAssert((eicup->config->iccfgp[0] != NULL) || - (eicup->config->iccfgp[1] != NULL) || - (eicup->config->iccfgp[2] != NULL) || - (eicup->config->iccfgp[3] != NULL), - "invalid input configuration"); - - if (eicup->state == EICU_STOP) { - /* Clock activation and timer reset.*/ -#if STM32_EICU_USE_TIM1 - if (&EICUD1 == eicup) { - rccEnableTIM1(FALSE); - rccResetTIM1(); - nvicEnableVector(STM32_TIM1_UP_NUMBER, STM32_EICU_TIM1_IRQ_PRIORITY); - nvicEnableVector(STM32_TIM1_CC_NUMBER, STM32_EICU_TIM1_IRQ_PRIORITY); - eicup->channels = 4; -#if defined(STM32_TIM1CLK) - eicup->clock = STM32_TIM1CLK; -#else - eicup->clock = STM32_TIMCLK2; -#endif - } -#endif -#if STM32_EICU_USE_TIM2 - if (&EICUD2 == eicup) { - rccEnableTIM2(FALSE); - rccResetTIM2(); - nvicEnableVector(STM32_TIM2_NUMBER, STM32_EICU_TIM2_IRQ_PRIORITY); - eicup->channels = 4; - eicup->clock = STM32_TIMCLK1; - } -#endif -#if STM32_EICU_USE_TIM3 - if (&EICUD3 == eicup) { - rccEnableTIM3(FALSE); - rccResetTIM3(); - nvicEnableVector(STM32_TIM3_NUMBER, STM32_EICU_TIM3_IRQ_PRIORITY); - eicup->channels = 4; - eicup->clock = STM32_TIMCLK1; - } -#endif -#if STM32_EICU_USE_TIM4 - if (&EICUD4 == eicup) { - rccEnableTIM4(FALSE); - rccResetTIM4(); - nvicEnableVector(STM32_TIM4_NUMBER, STM32_EICU_TIM4_IRQ_PRIORITY); - eicup->channels = 4; - eicup->clock = STM32_TIMCLK1; - } -#endif -#if STM32_EICU_USE_TIM5 - if (&EICUD5 == eicup) { - rccEnableTIM5(FALSE); - rccResetTIM5(); - nvicEnableVector(STM32_TIM5_NUMBER, STM32_EICU_TIM5_IRQ_PRIORITY); - eicup->channels = 4; - eicup->clock = STM32_TIMCLK1; - } -#endif -#if STM32_EICU_USE_TIM8 - if (&EICUD8 == eicup) { - rccEnableTIM8(FALSE); - rccResetTIM8(); - nvicEnableVector(STM32_TIM8_UP_NUMBER, STM32_EICU_TIM8_IRQ_PRIORITY); - nvicEnableVector(STM32_TIM8_CC_NUMBER, STM32_EICU_TIM8_IRQ_PRIORITY); - eicup->channels = 4; -#if defined(STM32_TIM8CLK) - eicup->clock = STM32_TIM8CLK; -#else - eicup->clock = STM32_TIMCLK2; -#endif - } -#endif -#if STM32_EICU_USE_TIM9 - if (&EICUD9 == eicup) { - rccEnableTIM9(FALSE); - rccResetTIM9(); - nvicEnableVector(STM32_TIM9_NUMBER, STM32_EICU_TIM9_IRQ_PRIORITY); - eicup->channels = 2; - eicup->clock = STM32_TIMCLK2; - } -#endif -#if STM32_EICU_USE_TIM12 - if (&EICUD12 == eicup) { - rccEnableTIM12(FALSE); - rccResetTIM12(); - nvicEnableVector(STM32_TIM12_NUMBER, STM32_EICU_TIM12_IRQ_PRIORITY); - eicup->channels = 2; - eicup->clock = STM32_TIMCLK1; - } -#endif -#if STM32_EICU_USE_TIM10 - if (&EICUD10 == eicup) { - rccEnableTIM10(FALSE); - rccResetTIM10(); - nvicEnableVector(STM32_TIM10_NUMBER, STM32_EICU_TIM10_IRQ_PRIORITY); - eicup->channels = 1; - eicup->clock = STM32_TIMCLK2; - } -#endif -#if STM32_EICU_USE_TIM11 - if (&EICUD11 == eicup) { - rccEnableTIM11(FALSE); - rccResetTIM11(); - nvicEnableVector(STM32_TIM11_NUMBER, STM32_EICU_TIM11_IRQ_PRIORITY); - eicup->channels = 1; - eicup->clock = STM32_TIMCLK2; - } -#endif -#if STM32_EICU_USE_TIM13 - if (&EICUD13 == eicup) { - rccEnableTIM13(FALSE); - rccResetTIM13(); - nvicEnableVector(STM32_TIM13_NUMBER, STM32_EICU_TIM13_IRQ_PRIORITY); - eicup->channels = 1; - eicup->clock = STM32_TIMCLK1; - } -#endif -#if STM32_EICU_USE_TIM14 - if (&EICUD14 == eicup) { - rccEnableTIM14(FALSE); - rccResetTIM14(); - nvicEnableVector(STM32_TIM14_NUMBER, STM32_EICU_TIM14_IRQ_PRIORITY); - eicup->channels = 1; - eicup->clock = STM32_TIMCLK1; - } -#endif - } - else { - /* Driver re-configuration scenario, it must be stopped first.*/ - eicup->tim->CR1 = 0; /* Timer disabled. */ - eicup->tim->DIER = eicup->config->dier &/* DMA-related DIER settings. */ - ~STM32_TIM_DIER_IRQ_MASK; - eicup->tim->SR = 0; /* Clear eventual pending IRQs. */ - eicup->tim->CCR[0] = 0; /* Comparator 1 disabled. */ - eicup->tim->CCR[1] = 0; /* Comparator 2 disabled. */ - eicup->tim->CNT = 0; /* Counter reset to zero. */ - } - - /* Timer configuration.*/ - psc = (eicup->clock / eicup->config->frequency) - 1; - chDbgAssert((psc <= 0xFFFF) && - ((psc + 1) * eicup->config->frequency) == eicup->clock, - "invalid frequency"); - eicup->tim->PSC = (uint16_t)psc; - eicup->tim->ARR = (eicucnt_t)-1; - - /* Detect width.*/ - if (0xFFFFFFFF == eicup->tim->ARR) - eicup->width = EICU_WIDTH_32; - else if (0xFFFF == eicup->tim->ARR) - eicup->width = EICU_WIDTH_16; - else - osalSysHalt("Unsupported width"); - - /* Reset registers */ - eicup->tim->SMCR = 0; - eicup->tim->CCMR1 = 0; - if (eicup->channels > 2) - eicup->tim->CCMR2 = 0; - - /* clean channel structures and set pointers to channel configs */ - for (ch=0; chchannel[ch].last_active = 0; - eicup->channel[ch].last_idle = 0; - eicup->channel[ch].config = eicup->config->iccfgp[ch]; - eicup->channel[ch].state = EICU_CH_IDLE; - } - - /* TIM9 and TIM12 have only 2 channels.*/ - if (eicup->channels == 2) { - osalDbgCheck((eicup->config->iccfgp[2] == NULL) && - (eicup->config->iccfgp[3] == NULL)); - } - - /* TIM10, TIM11, TIM13 and TIM14 have only 1 channel.*/ - if (eicup->channels == 1) { - osalDbgCheck((eicup->config->iccfgp[1] == NULL) && - (eicup->config->iccfgp[2] == NULL) && - (eicup->config->iccfgp[3] == NULL)); - } - - start_channels(eicup); -} - -/** - * @brief Deactivates the EICU peripheral. - * - * @param[in] eicup Pointer to the @p EICUDriver object - * - * @notapi - */ -void eicu_lld_stop(EICUDriver *eicup) { - - if (eicup->state == EICU_READY) { - - /* Clock deactivation.*/ - eicup->tim->CR1 = 0; /* Timer disabled. */ - eicup->tim->DIER = 0; /* All IRQs disabled. */ - eicup->tim->SR = 0; /* Clear eventual pending IRQs. */ - -#if STM32_EICU_USE_TIM1 - if (&EICUD1 == eicup) { - nvicDisableVector(STM32_TIM1_UP_NUMBER); - nvicDisableVector(STM32_TIM1_CC_NUMBER); - rccDisableTIM1(FALSE); - } -#endif -#if STM32_EICU_USE_TIM2 - if (&EICUD2 == eicup) { - nvicDisableVector(STM32_TIM2_NUMBER); - rccDisableTIM2(FALSE); - } -#endif -#if STM32_EICU_USE_TIM3 - if (&EICUD3 == eicup) { - nvicDisableVector(STM32_TIM3_NUMBER); - rccDisableTIM3(FALSE); - } -#endif -#if STM32_EICU_USE_TIM4 - if (&EICUD4 == eicup) { - nvicDisableVector(STM32_TIM4_NUMBER); - rccDisableTIM4(FALSE); - } -#endif -#if STM32_EICU_USE_TIM5 - if (&EICUD5 == eicup) { - nvicDisableVector(STM32_TIM5_NUMBER); - rccDisableTIM5(FALSE); - } -#endif -#if STM32_EICU_USE_TIM8 - if (&EICUD8 == eicup) { - nvicDisableVector(STM32_TIM8_UP_NUMBER); - nvicDisableVector(STM32_TIM8_CC_NUMBER); - rccDisableTIM8(FALSE); - } -#endif -#if STM32_EICU_USE_TIM9 - if (&EICUD9 == eicup) { - nvicDisableVector(STM32_TIM9_NUMBER); - rccDisableTIM9(FALSE); - } -#endif -#if STM32_EICU_USE_TIM12 - if (&EICUD12 == eicup) { - nvicDisableVector(STM32_TIM12_NUMBER); - rccDisableTIM12(FALSE); - } -#endif - } -#if STM32_EICU_USE_TIM10 - if (&EICUD10 == eicup) { - nvicDisableVector(STM32_TIM10_NUMBER); - rccDisableTIM10(FALSE); - } -#endif -#if STM32_EICU_USE_TIM11 - if (&EICUD11 == eicup) { - nvicDisableVector(STM32_TIM11_NUMBER); - rccDisableTIM11(FALSE); - } -#endif -#if STM32_EICU_USE_TIM13 - if (&EICUD13 == eicup) { - nvicDisableVector(STM32_TIM13_NUMBER); - rccDisableTIM13(FALSE); - } -#endif -#if STM32_EICU_USE_TIM14 - if (&EICUD14 == eicup) { - nvicDisableVector(STM32_TIM14_NUMBER); - rccDisableTIM14(FALSE); - } -#endif -} - -/** - * @brief Enables the EICU. - * - * @param[in] eicup Pointer to the @p EICUDriver object - * - * @notapi - */ -void eicu_lld_enable(EICUDriver *eicup) { - - eicup->tim->EGR = STM32_TIM_EGR_UG; - eicup->tim->SR = 0; /* Clear pending IRQs (if any). */ - - if ((eicup->config->iccfgp[EICU_CHANNEL_1] != NULL) && - (eicup->config->iccfgp[EICU_CHANNEL_1]->capture_cb != NULL)) - eicup->tim->DIER |= STM32_TIM_DIER_CC1IE; - if ((eicup->config->iccfgp[EICU_CHANNEL_2] != NULL) && - (eicup->config->iccfgp[EICU_CHANNEL_2]->capture_cb != NULL)) - eicup->tim->DIER |= STM32_TIM_DIER_CC2IE; - if ((eicup->config->iccfgp[EICU_CHANNEL_3] != NULL) && - (eicup->config->iccfgp[EICU_CHANNEL_3]->capture_cb != NULL)) - eicup->tim->DIER |= STM32_TIM_DIER_CC3IE; - if ((eicup->config->iccfgp[EICU_CHANNEL_4] != NULL) && - (eicup->config->iccfgp[EICU_CHANNEL_4]->capture_cb != NULL)) - eicup->tim->DIER |= STM32_TIM_DIER_CC4IE; - - eicup->tim->CR1 = STM32_TIM_CR1_URS | STM32_TIM_CR1_CEN; -} - -/** - * @brief Disables the EICU. - * - * @param[in] eicup Pointer to the @p EICUDriver object - * - * @notapi - */ -void eicu_lld_disable(EICUDriver *eicup) { - eicup->tim->CR1 = 0; /* Initially stopped. */ - eicup->tim->SR = 0; /* Clear pending IRQs (if any). */ - - /* All interrupts disabled.*/ - eicup->tim->DIER &= ~STM32_TIM_DIER_IRQ_MASK; -} - -#endif /* HAL_USE_EICU */ diff --git a/os/hal/ports/STM32/LLD/TIMv1/eicu_lld.h b/os/hal/ports/STM32/LLD/TIMv1/eicu_lld.h deleted file mode 100644 index 927eb6f..0000000 --- a/os/hal/ports/STM32/LLD/TIMv1/eicu_lld.h +++ /dev/null @@ -1,554 +0,0 @@ -/* - ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ -/* - Rewritten by Emil Fresk (1/5 - 2014) for extended input capture - functionality. And fix for spurious callbacks in the interrupt handler. -*/ -/* - Improved by Uladzimir Pylinsky aka barthess (1/3 - 2015) for support of - 32-bit timers and timers with single capture/compare channels. -*/ - -#ifndef __EICU_LLD_H -#define __EICU_LLD_H - -#include "stm32_tim.h" - -#if (HAL_USE_EICU == TRUE) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver constants. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver pre-compile time settings. */ -/*===========================================================================*/ - -/** - * @name Configuration options - * @{ - */ -/** - * @brief EICUD1 driver enable switch. - * @details If set to @p TRUE the support for EICUD1 is included. - * @note The default is @p TRUE. - */ -#if !defined(STM32_EICU_USE_TIM1) || defined(__DOXYGEN__) -#define STM32_EICU_USE_TIM1 FALSE -#endif - -/** - * @brief EICUD2 driver enable switch. - * @details If set to @p TRUE the support for EICUD2 is included. - * @note The default is @p TRUE. - */ -#if !defined(STM32_EICU_USE_TIM2) || defined(__DOXYGEN__) -#define STM32_EICU_USE_TIM2 FALSE -#endif - -/** - * @brief EICUD3 driver enable switch. - * @details If set to @p TRUE the support for EICUD3 is included. - * @note The default is @p TRUE. - */ -#if !defined(STM32_EICU_USE_TIM3) || defined(__DOXYGEN__) -#define STM32_EICU_USE_TIM3 FALSE -#endif - -/** - * @brief EICUD4 driver enable switch. - * @details If set to @p TRUE the support for EICUD4 is included. - * @note The default is @p TRUE. - */ -#if !defined(STM32_EICU_USE_TIM4) || defined(__DOXYGEN__) -#define STM32_EICU_USE_TIM4 FALSE -#endif - -/** - * @brief EICUD5 driver enable switch. - * @details If set to @p TRUE the support for EICUD5 is included. - * @note The default is @p TRUE. - */ -#if !defined(STM32_EICU_USE_TIM5) || defined(__DOXYGEN__) -#define STM32_EICU_USE_TIM5 FALSE -#endif - -/** - * @brief EICUD8 driver enable switch. - * @details If set to @p TRUE the support for EICUD8 is included. - * @note The default is @p TRUE. - */ -#if !defined(STM32_EICU_USE_TIM8) || defined(__DOXYGEN__) -#define STM32_EICU_USE_TIM8 FALSE -#endif - -/** - * @brief EICUD9 driver enable switch. - * @details If set to @p TRUE the support for EICUD9 is included. - * @note The default is @p TRUE. - */ -#if !defined(STM32_EICU_USE_TIM9) || defined(__DOXYGEN__) -#define STM32_EICU_USE_TIM9 FALSE -#endif - -/** - * @brief EICUD12 driver enable switch. - * @details If set to @p TRUE the support for EICUD12 is included. - * @note The default is @p TRUE. - */ -#if !defined(STM32_EICU_USE_TIM12) || defined(__DOXYGEN__) -#define STM32_EICU_USE_TIM12 FALSE -#endif - -/** - * @brief EICUD1 interrupt priority level setting. - */ -#if !defined(STM32_EICU_TIM1_IRQ_PRIORITY) || defined(__DOXYGEN__) -#define STM32_EICU_TIM1_IRQ_PRIORITY 7 -#endif - -/** - * @brief EICUD2 interrupt priority level setting. - */ -#if !defined(STM32_EICU_TIM2_IRQ_PRIORITY) || defined(__DOXYGEN__) -#define STM32_EICU_TIM2_IRQ_PRIORITY 7 -#endif - -/** - * @brief EICUD3 interrupt priority level setting. - */ -#if !defined(STM32_EICU_TIM3_IRQ_PRIORITY) || defined(__DOXYGEN__) -#define STM32_EICU_TIM3_IRQ_PRIORITY 7 -#endif - -/** - * @brief EICUD4 interrupt priority level setting. - */ -#if !defined(STM32_EICU_TIM4_IRQ_PRIORITY) || defined(__DOXYGEN__) -#define STM32_EICU_TIM4_IRQ_PRIORITY 7 -#endif - -/** - * @brief EICUD5 interrupt priority level setting. - */ -#if !defined(STM32_EICU_TIM5_IRQ_PRIORITY) || defined(__DOXYGEN__) -#define STM32_EICU_TIM5_IRQ_PRIORITY 7 -#endif - -/** - * @brief EICUD8 interrupt priority level setting. - */ -#if !defined(STM32_EICU_TIM8_IRQ_PRIORITY) || defined(__DOXYGEN__) -#define STM32_EICU_TIM8_IRQ_PRIORITY 7 -#endif - -/** - * @brief EICUD9 interrupt priority level setting. - */ -#if !defined(STM32_EICU_TIM9_IRQ_PRIORITY) || defined(__DOXYGEN__) -#define STM32_EICU_TIM9_IRQ_PRIORITY 7 -#endif - -/** - * @brief EICUD12 interrupt priority level setting. - */ -#if !defined(STM32_EICU_TIM12_IRQ_PRIORITY) || defined(__DOXYGEN__) -#define STM32_EICU_TIM12_IRQ_PRIORITY 7 -#endif - -/** - * @brief EICUD10 interrupt priority level setting. - */ -#if !defined(STM32_EICU_TIM10_IRQ_PRIORITY) || defined(__DOXYGEN__) -#define STM32_EICU_TIM10_IRQ_PRIORITY 7 -#endif - -/** - * @brief EICUD11 interrupt priority level setting. - */ -#if !defined(STM32_EICU_TIM11_IRQ_PRIORITY) || defined(__DOXYGEN__) -#define STM32_EICU_TIM11_IRQ_PRIORITY 7 -#endif - -/** - * @brief EICUD13 interrupt priority level setting. - */ -#if !defined(STM32_EICU_TIM13_IRQ_PRIORITY) || defined(__DOXYGEN__) -#define STM32_EICU_TIM13_IRQ_PRIORITY 7 -#endif - -/** - * @brief EICUD14 interrupt priority level setting. - */ -#if !defined(STM32_EICU_TIM14_IRQ_PRIORITY) || defined(__DOXYGEN__) -#define STM32_EICU_TIM14_IRQ_PRIORITY 7 -#endif -/** @} */ - -/*===========================================================================*/ -/* Derived constants and error checks. */ -/*===========================================================================*/ - -#if STM32_EICU_USE_TIM1 && !STM32_HAS_TIM1 -#error "TIM1 not present in the selected device" -#endif - -#if STM32_EICU_USE_TIM2 && !STM32_HAS_TIM2 -#error "TIM2 not present in the selected device" -#endif - -#if STM32_EICU_USE_TIM3 && !STM32_HAS_TIM3 -#error "TIM3 not present in the selected device" -#endif - -#if STM32_EICU_USE_TIM4 && !STM32_HAS_TIM4 -#error "TIM4 not present in the selected device" -#endif - -#if STM32_EICU_USE_TIM5 && !STM32_HAS_TIM5 -#error "TIM5 not present in the selected device" -#endif - -#if STM32_EICU_USE_TIM8 && !STM32_HAS_TIM8 -#error "TIM8 not present in the selected device" -#endif - -#if STM32_EICU_USE_TIM9 && !STM32_HAS_TIM9 -#error "TIM9 not present in the selected device" -#endif - -#if STM32_EICU_USE_TIM12 && !STM32_HAS_TIM12 -#error "TIM12 not present in the selected device" -#endif - -#if STM32_EICU_USE_TIM10 && !STM32_HAS_TIM10 -#error "TIM10 not present in the selected device" -#endif - -#if STM32_EICU_USE_TIM11 && !STM32_HAS_TIM11 -#error "TIM11 not present in the selected device" -#endif - -#if STM32_EICU_USE_TIM13 && !STM32_HAS_TIM13 -#error "TIM13 not present in the selected device" -#endif - -#if STM32_EICU_USE_TIM14 && !STM32_HAS_TIM14 -#error "TIM14 not present in the selected device" -#endif - -#if !STM32_EICU_USE_TIM1 && !STM32_EICU_USE_TIM2 && \ - !STM32_EICU_USE_TIM3 && !STM32_EICU_USE_TIM4 && \ - !STM32_EICU_USE_TIM5 && !STM32_EICU_USE_TIM8 && \ - !STM32_EICU_USE_TIM9 && !STM32_EICU_USE_TIM12 && \ - !STM32_EICU_USE_TIM10 && !STM32_EICU_USE_TIM11 && \ - !STM32_EICU_USE_TIM13 && !STM32_EICU_USE_TIM14 -#error "EICU driver activated but no TIM peripheral assigned" -#endif - -#if STM32_EICU_USE_TIM1 && \ - !OSAL_IRQ_IS_VALID_PRIORITY(STM32_EICU_TIM1_IRQ_PRIORITY) -#error "Invalid IRQ priority assigned to TIM1" -#endif - -#if STM32_EICU_USE_TIM2 && \ - !OSAL_IRQ_IS_VALID_PRIORITY(STM32_EICU_TIM2_IRQ_PRIORITY) -#error "Invalid IRQ priority assigned to TIM2" -#endif - -#if STM32_EICU_USE_TIM3 && \ - !OSAL_IRQ_IS_VALID_PRIORITY(STM32_EICU_TIM3_IRQ_PRIORITY) -#error "Invalid IRQ priority assigned to TIM3" -#endif - -#if STM32_EICU_USE_TIM4 && \ - !OSAL_IRQ_IS_VALID_PRIORITY(STM32_EICU_TIM4_IRQ_PRIORITY) -#error "Invalid IRQ priority assigned to TIM4" -#endif - -#if STM32_EICU_USE_TIM5 && \ - !OSAL_IRQ_IS_VALID_PRIORITY(STM32_EICU_TIM5_IRQ_PRIORITY) -#error "Invalid IRQ priority assigned to TIM5" -#endif - -#if STM32_EICU_USE_TIM8 && \ - !OSAL_IRQ_IS_VALID_PRIORITY(STM32_EICU_TIM8_IRQ_PRIORITY) -#error "Invalid IRQ priority assigned to TIM8" -#endif - -#if STM32_EICU_USE_TIM9 && \ - !OSAL_IRQ_IS_VALID_PRIORITY(STM32_EICU_TIM9_IRQ_PRIORITY) -#error "Invalid IRQ priority assigned to TIM9" -#endif - -#if STM32_EICU_USE_TIM12 && \ - !OSAL_IRQ_IS_VALID_PRIORITY(STM32_EICU_TIM12_IRQ_PRIORITY) -#error "Invalid IRQ priority assigned to TIM12" -#endif - -#if STM32_EICU_USE_TIM10 && \ - !OSAL_IRQ_IS_VALID_PRIORITY(STM32_EICU_TIM10_IRQ_PRIORITY) -#error "Invalid IRQ priority assigned to TIM10" -#endif - -#if STM32_EICU_USE_TIM11 && \ - !OSAL_IRQ_IS_VALID_PRIORITY(STM32_EICU_TIM11_IRQ_PRIORITY) -#error "Invalid IRQ priority assigned to TIM11" -#endif - -#if STM32_EICU_USE_TIM13 && \ - !OSAL_IRQ_IS_VALID_PRIORITY(STM32_EICU_TIM13_IRQ_PRIORITY) -#error "Invalid IRQ priority assigned to TIM13" -#endif - -#if STM32_EICU_USE_TIM14 && \ - !OSAL_IRQ_IS_VALID_PRIORITY(STM32_EICU_TIM14_IRQ_PRIORITY) -#error "Invalid IRQ priority assigned to TIM14" -#endif - -/*===========================================================================*/ -/* Driver data structures and types. */ -/*===========================================================================*/ -/** - * @brief Active level selector. - */ -typedef enum { - EICU_INPUT_ACTIVE_HIGH, /**< Trigger on rising edge. */ - EICU_INPUT_ACTIVE_LOW, /**< Trigger on falling edge. */ -} eicuactivelevel_t; - -/** - * @brief Input type selector. - */ -typedef enum { - /** - * @brief Measures time between consequent edges. - * @details Callback fires on every _active_ edge. - */ - EICU_INPUT_EDGE, - /** - * @brief Measures pulse width. - * @details Callback fires on _idle_ edge of pulse. - */ - EICU_INPUT_PULSE, - /** - * @brief Measures both period and width.. - * @details Callback fires on _active_ edge of pulse. - */ - EICU_INPUT_BOTH -} eicucapturemode_t; - -/** - * @brief Timer registers width in bits. - */ -typedef enum { - EICU_WIDTH_16, - EICU_WIDTH_32 -} eicutimerwidth_t; - -/** - * @brief EICU frequency type. - */ -typedef uint32_t eicufreq_t; - -/** - * @brief EICU counter type. - */ -typedef uint32_t eicucnt_t; - -/** - * @brief EICU captured width and (or) period. - */ -typedef struct { - /** - * @brief Pulse width. - */ - eicucnt_t width; - /** - * @brief Pulse period. - */ - eicucnt_t period; -} eicuresult_t; - -/** - * @brief EICU Capture Channel Config structure definition. - */ -typedef struct { - /** - * @brief Specifies the active level of the input signal. - */ - eicuactivelevel_t alvl; - /** - * @brief Specifies the channel capture mode. - */ - eicucapturemode_t mode; - /** - * @brief Capture event callback. Used for PWM width, pulse width and - * pulse period capture event. - */ - eicucallback_t capture_cb; -} EICUChannelConfig; - -/** - * @brief EICU Capture Channel structure definition. - */ -typedef struct { - /** - * @brief Channel state for the internal state machine. - */ - eicuchannelstate_t state; - /** - * @brief Cached value for pulse width calculation. - */ - eicucnt_t last_active; - /** - * @brief Cached value for period calculation. - */ - eicucnt_t last_idle; - /** - * @brief Pointer to Input Capture channel configuration. - */ - const EICUChannelConfig *config; - /** - * @brief CCR register pointer for faster access. - */ - volatile uint32_t *ccrp; -} EICUChannel; - -/** - * @brief EICU Config structure definition. - */ -typedef struct { - /** - * @brief Specifies the Timer clock in Hz. - */ - eicufreq_t frequency; - /** - * @brief Pointer to each Input Capture channel configuration. - * @note A NULL parameter indicates the channel as unused. - * @note In PWM mode, only Channel 1 OR Channel 2 may be used. - */ - const EICUChannelConfig *iccfgp[EICU_CHANNEL_ENUM_END]; - /** - * @brief TIM DIER register initialization data. - */ - uint32_t dier; -} EICUConfig; - -/** - * @brief EICU Driver structure definition - */ -struct EICUDriver { - /** - * @brief STM32 timer peripheral for Input Capture. - */ - stm32_tim_t *tim; - /** - * @brief Driver state for the internal state machine. - */ - eicustate_t state; - /** - * @brief Channels' data structures. - */ - EICUChannel channel[EICU_CHANNEL_ENUM_END]; - /** - * @brief Timer base clock. - */ - uint32_t clock; - /** - * @brief Number of available capture compare channels in timer. - */ - size_t channels; - /** - * @brief Timer registers width in bits. - */ - eicutimerwidth_t width; - /** - * @brief Pointer to configuration for the driver. - */ - const EICUConfig *config; -}; - -/*===========================================================================*/ -/* Driver macros. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ -#if STM32_EICU_USE_TIM1 && !defined(__DOXYGEN__) -extern EICUDriver EICUD1; -#endif - -#if STM32_EICU_USE_TIM2 && !defined(__DOXYGEN__) -extern EICUDriver EICUD2; -#endif - -#if STM32_EICU_USE_TIM3 && !defined(__DOXYGEN__) -extern EICUDriver EICUD3; -#endif - -#if STM32_EICU_USE_TIM4 && !defined(__DOXYGEN__) -extern EICUDriver EICUD4; -#endif - -#if STM32_EICU_USE_TIM5 && !defined(__DOXYGEN__) -extern EICUDriver EICUD5; -#endif - -#if STM32_EICU_USE_TIM8 && !defined(__DOXYGEN__) -extern EICUDriver EICUD8; -#endif - -#if STM32_EICU_USE_TIM9 && !defined(__DOXYGEN__) -extern EICUDriver EICUD9; -#endif - -#if STM32_EICU_USE_TIM12 && !defined(__DOXYGEN__) -extern EICUDriver EICUD12; -#endif - -#if STM32_EICU_USE_TIM10 && !defined(__DOXYGEN__) -extern EICUDriver EICUD10; -#endif - -#if STM32_EICU_USE_TIM11 && !defined(__DOXYGEN__) -extern EICUDriver EICUD11; -#endif - -#if STM32_EICU_USE_TIM13 && !defined(__DOXYGEN__) -extern EICUDriver EICUD13; -#endif - -#if STM32_EICU_USE_TIM14 && !defined(__DOXYGEN__) -extern EICUDriver EICUD14; -#endif - -#ifdef __cplusplus -extern "C" { -#endif - void eicu_lld_init(void); - void eicu_lld_start(EICUDriver *eicup); - void eicu_lld_stop(EICUDriver *eicup); - void eicu_lld_enable(EICUDriver *eicup); - void eicu_lld_disable(EICUDriver *eicup); -#ifdef __cplusplus -} -#endif - -#endif /* HAL_USE_EICU */ - -#endif /* __EICU_LLD_H */ diff --git a/os/hal/ports/STM32/LLD/TIMv1/hal_eicu_lld.c b/os/hal/ports/STM32/LLD/TIMv1/hal_eicu_lld.c new file mode 100644 index 0000000..c04278e --- /dev/null +++ b/os/hal/ports/STM32/LLD/TIMv1/hal_eicu_lld.c @@ -0,0 +1,1176 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +/* + Concepts and parts of this file have been contributed by Fabio Utzig and + Xo Wang. +*/ +/* + Rewritten by Emil Fresk (1/5 - 2014) for extended input capture + functionality. And fix for spurious callbacks in the interrupt handler. +*/ +/* + Improved by Uladzimir Pylinsky aka barthess (1/3 - 2015) for support of + 32-bit timers and timers with single capture/compare channels. +*/ + +/* + * Hardware Abstraction Layer for Extended Input Capture Unit + */ +#include "hal.h" + +#if (HAL_USE_EICU == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ +/** + * @brief Inverts the polarity for the given channel. + * + * @param[in] eicup Pointer to the EICUDriver object. + * @param[in] channel The timer channel to invert. + * + * @notapi + */ +#define eicu_lld_invert_polarity(eicup, channel) \ + (eicup)->tim->CCER ^= ((uint16_t)(STM32_TIM_CCER_CC1P << ((channel) * 4))) + +/** + * @brief Returns the compare value of the latest cycle. + * + * @param[in] chp Pointer to channel structure that fired the interrupt. + * @return The number of ticks. + * + * @notapi + */ +#define eicu_lld_get_compare(chp) (*((chp)->ccrp) + 1) + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief EICUD1 driver identifier. + * @note The driver EICUD1 allocates the complex timer TIM1 when enabled. + */ +#if STM32_EICU_USE_TIM1 && !defined(__DOXYGEN__) +EICUDriver EICUD1; +#endif + +/** + * @brief EICUD2 driver identifier. + * @note The driver EICUD2 allocates the timer TIM2 when enabled. + */ +#if STM32_EICU_USE_TIM2 && !defined(__DOXYGEN__) +EICUDriver EICUD2; +#endif + +/** + * @brief EICUD3 driver identifier. + * @note The driver EICUD3 allocates the timer TIM3 when enabled. + */ +#if STM32_EICU_USE_TIM3 && !defined(__DOXYGEN__) +EICUDriver EICUD3; +#endif + +/** + * @brief EICUD4 driver identifier. + * @note The driver EICUD4 allocates the timer TIM4 when enabled. + */ +#if STM32_EICU_USE_TIM4 && !defined(__DOXYGEN__) +EICUDriver EICUD4; +#endif + +/** + * @brief EICUD5 driver identifier. + * @note The driver EICUD5 allocates the timer TIM5 when enabled. + */ +#if STM32_EICU_USE_TIM5 && !defined(__DOXYGEN__) +EICUDriver EICUD5; +#endif + +/** + * @brief EICUD8 driver identifier. + * @note The driver EICUD8 allocates the timer TIM8 when enabled. + */ +#if STM32_EICU_USE_TIM8 && !defined(__DOXYGEN__) +EICUDriver EICUD8; +#endif + +/** + * @brief EICUD9 driver identifier. + * @note The driver EICUD9 allocates the timer TIM9 when enabled. + */ +#if STM32_EICU_USE_TIM9 && !defined(__DOXYGEN__) +EICUDriver EICUD9; +#endif + +/** + * @brief EICUD12 driver identifier. + * @note The driver EICUD12 allocates the timer TIM12 when enabled. + */ +#if STM32_EICU_USE_TIM12 && !defined(__DOXYGEN__) +EICUDriver EICUD12; +#endif + +/** + * @brief EICUD10 driver identifier. + * @note The driver EICUD10 allocates the timer TIM10 when enabled. + */ +#if STM32_EICU_USE_TIM10 && !defined(__DOXYGEN__) +EICUDriver EICUD10; +#endif + +/** + * @brief EICUD11 driver identifier. + * @note The driver EICUD11 allocates the timer TIM11 when enabled. + */ +#if STM32_EICU_USE_TIM11 && !defined(__DOXYGEN__) +EICUDriver EICUD11; +#endif + +/** + * @brief EICUD13 driver identifier. + * @note The driver EICUD13 allocates the timer TIM13 when enabled. + */ +#if STM32_EICU_USE_TIM13 && !defined(__DOXYGEN__) +EICUDriver EICUD13; +#endif + +/** + * @brief EICUD14 driver identifier. + * @note The driver EICUD14 allocates the timer TIM14 when enabled. + */ +#if STM32_EICU_USE_TIM14 && !defined(__DOXYGEN__) +EICUDriver EICUD14; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ +/** + * @brief Returns both pulse width and period. + * @details The time is defined as number of ticks. + * + * @param[in] eicup Pointer to the EICUDriver object. + * @param[in] channel The timer channel that fired the interrupt. + * @param[in] compare Content of the CCR register. + * @return The number of ticks. + * + * @notapi + */ +static eicuresult_t get_time_both(const EICUDriver *eicup, + eicuchannel_t channel, + eicucnt_t compare) { + + const EICUChannel *chp = &eicup->channel[channel]; + eicuresult_t ret; + + /* Note! there is no overflow check because it handles under the hood of + unsigned subtraction math.*/ + + /* 16-bit timer */ + if (EICU_WIDTH_16 == eicup->width) { + uint16_t cmp = compare; + uint16_t la = chp->last_active; + uint16_t li = chp->last_idle; + uint16_t w = li - la; + uint16_t p = cmp - la; + ret.width = w; + ret.period = p; + } + /* 32-bit timer */ + else if (EICU_WIDTH_32 == eicup->width) { + ret.width = chp->last_idle - chp->last_active; + ret.period = compare - chp->last_active; + } + /* error trap */ + else { + osalSysHalt("Unhandled width value"); + } + + return ret; +} + +/** + * @brief Returns pulse width. + * @details The time is defined as number of ticks. + * + * @param[in] eicup Pointer to the EICUDriver object. + * @param[in] channel The timer channel that fired the interrupt. + * @param[in] compare Content of the CCR register. + * @return The number of ticks. + * + * @notapi + */ +static eicucnt_t get_time_width(const EICUDriver *eicup, + eicuchannel_t channel, + eicucnt_t compare) { + + const EICUChannel *chp = &eicup->channel[channel]; + + /* Note! there is no overflow check because it handles under the hood of + unsigned subtraction math.*/ + + /* 16-bit timer */ + if (EICU_WIDTH_16 == eicup->width) { + uint16_t cmp = compare; + uint16_t la = chp->last_active; + uint16_t ret = cmp - la; + return ret; + } + /* 32-bit timer */ + else if (EICU_WIDTH_32 == eicup->width) { + return compare - chp->last_active; + } + /* error trap */ + else { + osalSysHalt("Unhandled width value"); + return 0; + } +} + +/** + * @brief Returns pulse period. + * @details The time is defined as number of ticks. + * + * @param[in] eicup Pointer to the EICUDriver object. + * @param[in] channel The timer channel that fired the interrupt. + * @param[in] compare Content of the CCR register. + * @return The number of ticks. + * + * @notapi + */ +static eicucnt_t get_time_period(const EICUDriver *eicup, + eicuchannel_t channel, + eicucnt_t compare) { + + const EICUChannel *chp = &eicup->channel[channel]; + + /* Note! there is no overflow check because it handles under the hood of + unsigned subtraction math.*/ + + /* 16-bit timer */ + if (EICU_WIDTH_16 == eicup->width) { + uint16_t cmp = compare; + uint16_t li = chp->last_idle; + uint16_t ret = cmp - li; + return ret; + } + /* 32-bit timer */ + else if (EICU_WIDTH_32 == eicup->width) { + return compare - chp->last_idle; + } + /* error trap */ + else { + osalSysHalt("Unhandled width value"); + return 0; + } +} + +/** + * @brief EICU width or (width + period) event. + * @note Needs special care since it needs to invert the + * correct polarity bit to detect pulses. + * @note Assumes that the polarity is not changed by some + * external user. It must only be changed using the HAL. + * + * @param[in] eicup Pointer to the @p EICUDriver object + * @param[in] channel The timer channel that fired the interrupt. + * + * @notapi + */ +static void isr_invoke_pulse_cb(EICUDriver *eicup, eicuchannel_t channel) { + EICUChannel *chp = &eicup->channel[channel]; + eicucnt_t compare = eicu_lld_get_compare(chp); + + if (EICU_CH_ACTIVE == chp->state) { + chp->state = EICU_CH_IDLE; + eicu_lld_invert_polarity(eicup, channel); + if (EICU_INPUT_PULSE == chp->config->mode) { + uint32_t width = get_time_width(eicup, channel, compare); + chp->config->capture_cb(eicup, channel, width, 0); + } + chp->last_idle = compare; + } + else { + chp->state = EICU_CH_ACTIVE; + eicu_lld_invert_polarity(eicup, channel); + if (EICU_INPUT_BOTH == chp->config->mode) { + eicuresult_t both = get_time_both(eicup, channel, compare); + chp->config->capture_cb(eicup, channel, both.width, both.period); + } + chp->last_active = compare; + } +} + +/** + * @brief EICU Edge detect event. + * + * @param[in] eicup Pointer to the @p EICUDriver object + * @param[in] channel The timer channel that fired the interrupt. + * + * @notapi + */ +static void isr_invoke_edge_cb(EICUDriver *eicup, eicuchannel_t channel) { + EICUChannel *chp = &eicup->channel[channel]; + eicucnt_t compare = eicu_lld_get_compare(chp); + uint32_t period = get_time_period(eicup, channel, compare); + + chp->config->capture_cb(eicup, channel, 0, period); + chp->last_idle = compare; +} + +/** + * @brief Common EICU detect call. + * + * @param[in] eicup Pointer to the @p EICUDriver object + * @param[in] channel The timer channel that fired the interrupt. + * + * @notapi + */ +static void eicu_isr_invoke_cb(EICUDriver *eicup, eicuchannel_t channel) { + + if (EICU_INPUT_EDGE == eicup->channel[channel].config->mode) + isr_invoke_edge_cb(eicup, channel); + else /* EICU_INPUT_PULSE || EICU_INPUT_BOTH */ + isr_invoke_pulse_cb(eicup, channel); +} + +/** + * @brief Shared IRQ handler. + * + * @param[in] eicup Pointer to the @p EICUDriver object + */ +static void eicu_lld_serve_interrupt(EICUDriver *eicup) { + uint16_t sr; + sr = eicup->tim->SR; + + /* Pick out the interrupts we are interested in by using + the interrupt enable bits as mask */ + sr &= (eicup->tim->DIER & STM32_TIM_DIER_IRQ_MASK); + + /* Clear interrupts */ + eicup->tim->SR = ~sr; + + if ((sr & STM32_TIM_SR_CC1IF) != 0) + eicu_isr_invoke_cb(eicup, EICU_CHANNEL_1); + if ((sr & STM32_TIM_SR_CC2IF) != 0) + eicu_isr_invoke_cb(eicup, EICU_CHANNEL_2); + if ((sr & STM32_TIM_SR_CC3IF) != 0) + eicu_isr_invoke_cb(eicup, EICU_CHANNEL_3); + if ((sr & STM32_TIM_SR_CC4IF) != 0) + eicu_isr_invoke_cb(eicup, EICU_CHANNEL_4); +} + +/** + * @brief Starts every channel. + * + * @param[in] eicup Pointer to the @p EICUDriver object + */ +static void start_channels(EICUDriver *eicup) { + + /* Set each input channel that is used as: a normal input capture channel, + link the corresponding CCR register and set polarity. */ + + /* Input capture channel 1 */ + if (eicup->config->iccfgp[0] != NULL) { + /* Normal capture input input */ + eicup->tim->CCMR1 |= STM32_TIM_CCMR1_CC1S(1); + + /* Link CCR register */ + eicup->channel[0].ccrp = &eicup->tim->CCR[0]; + + /* Set input polarity */ + if (eicup->config->iccfgp[0]->alvl == EICU_INPUT_ACTIVE_HIGH) + eicup->tim->CCER |= STM32_TIM_CCER_CC1E; + else + eicup->tim->CCER |= STM32_TIM_CCER_CC1E | STM32_TIM_CCER_CC1P; + } + + /* Input capture channel 2 */ + if (eicup->config->iccfgp[1] != NULL) { + /* Normal capture input input */ + eicup->tim->CCMR1 |= STM32_TIM_CCMR1_CC2S(1); + + /* Link CCR register */ + eicup->channel[1].ccrp = &eicup->tim->CCR[1]; + + /* Set input polarity */ + if (eicup->config->iccfgp[1]->alvl == EICU_INPUT_ACTIVE_HIGH) + eicup->tim->CCER |= STM32_TIM_CCER_CC2E; + else + eicup->tim->CCER |= STM32_TIM_CCER_CC2E | STM32_TIM_CCER_CC2P; + } + + /* Input capture channel 3 (not for TIM 9 and 12) */ + if (eicup->config->iccfgp[2] != NULL) { + /* Normal capture input input */ + eicup->tim->CCMR2 |= STM32_TIM_CCMR2_CC3S(1); + + /* Link CCR register */ + eicup->channel[2].ccrp = &eicup->tim->CCR[2]; + + /* Set input polarity */ + if (eicup->config->iccfgp[2]->alvl == EICU_INPUT_ACTIVE_HIGH) + eicup->tim->CCER |= STM32_TIM_CCER_CC3E; + else + eicup->tim->CCER |= STM32_TIM_CCER_CC3E | STM32_TIM_CCER_CC3P; + } + + /* Input capture channel 4 (not for TIM 9 and 12) */ + if (eicup->config->iccfgp[3] != NULL) { + /* Normal capture input input */ + eicup->tim->CCMR2 |= STM32_TIM_CCMR2_CC4S(1); + + /* Link CCR register */ + eicup->channel[3].ccrp = &eicup->tim->CCR[3]; + + /* Set input polarity */ + if (eicup->config->iccfgp[3]->alvl == EICU_INPUT_ACTIVE_HIGH) + eicup->tim->CCER |= STM32_TIM_CCER_CC4E; + else + eicup->tim->CCER |= STM32_TIM_CCER_CC4E | STM32_TIM_CCER_CC4P; + } +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_EICU_USE_TIM1 +#if !defined(STM32_TIM1_UP_HANDLER) +#error "STM32_TIM1_UP_HANDLER not defined" +#endif +/** + * @brief TIM1 compare interrupt handler. + * @note It is assumed that the various sources are only activated if the + * associated callback pointer is not equal to @p NULL in order to not + * perform an extra check in a potentially critical interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM1_UP_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + eicu_lld_serve_interrupt(&EICUD1); + + OSAL_IRQ_EPILOGUE(); +} + +#if !defined(STM32_TIM1_CC_HANDLER) +#error "STM32_TIM1_CC_HANDLER not defined" +#endif +/** + * @brief TIM1 compare interrupt handler. + * @note It is assumed that the various sources are only activated if the + * associated callback pointer is not equal to @p NULL in order to not + * perform an extra check in a potentially critical interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM1_CC_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + eicu_lld_serve_interrupt(&EICUD1); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* STM32_EICU_USE_TIM1 */ + +#if STM32_EICU_USE_TIM2 + +#if !defined(STM32_TIM2_HANDLER) +#error "STM32_TIM2_HANDLER not defined" +#endif +/** + * @brief TIM2 interrupt handler. + * @note It is assumed that the various sources are only activated if the + * associated callback pointer is not equal to @p NULL in order to not + * perform an extra check in a potentially critical interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM2_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + eicu_lld_serve_interrupt(&EICUD2); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* STM32_EICU_USE_TIM2 */ + +#if STM32_EICU_USE_TIM3 +#if !defined(STM32_TIM3_HANDLER) +#error "STM32_TIM3_HANDLER not defined" +#endif +/** + * @brief TIM3 interrupt handler. + * @note It is assumed that the various sources are only activated if the + * associated callback pointer is not equal to @p NULL in order to not + * perform an extra check in a potentially critical interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM3_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + eicu_lld_serve_interrupt(&EICUD3); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* STM32_EICU_USE_TIM3 */ + +#if STM32_EICU_USE_TIM4 +#if !defined(STM32_TIM4_HANDLER) +#error "STM32_TIM4_HANDLER not defined" +#endif +/** + * @brief TIM4 interrupt handler. + * @note It is assumed that the various sources are only activated if the + * associated callback pointer is not equal to @p NULL in order to not + * perform an extra check in a potentially critical interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM4_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + eicu_lld_serve_interrupt(&EICUD4); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* STM32_EICU_USE_TIM4 */ + +#if STM32_EICU_USE_TIM5 +#if !defined(STM32_TIM5_HANDLER) +#error "STM32_TIM5_HANDLER not defined" +#endif +/** + * @brief TIM5 interrupt handler. + * @note It is assumed that the various sources are only activated if the + * associated callback pointer is not equal to @p NULL in order to not + * perform an extra check in a potentially critical interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM5_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + eicu_lld_serve_interrupt(&EICUD5); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* STM32_EICU_USE_TIM5 */ + +#if STM32_EICU_USE_TIM8 +#if !defined(STM32_TIM8_UP_HANDLER) +#error "STM32_TIM8_UP_HANDLER not defined" +#endif +/** + * @brief TIM8 compare interrupt handler. + * @note It is assumed that the various sources are only activated if the + * associated callback pointer is not equal to @p NULL in order to not + * perform an extra check in a potentially critical interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM8_UP_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + eicu_lld_serve_interrupt(&EICUD8); + + OSAL_IRQ_EPILOGUE(); +} + +#if !defined(STM32_TIM8_CC_HANDLER) +#error "STM32_TIM8_CC_HANDLER not defined" +#endif +/** + * @brief TIM8 compare interrupt handler. + * @note It is assumed that the various sources are only activated if the + * associated callback pointer is not equal to @p NULL in order to not + * perform an extra check in a potentially critical interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM8_CC_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + eicu_lld_serve_interrupt(&EICUD8); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* STM32_EICU_USE_TIM8 */ + +#if STM32_EICU_USE_TIM9 +#if !defined(STM32_TIM9_HANDLER) +#error "STM32_TIM9_HANDLER not defined" +#endif +/** + * @brief TIM9 interrupt handler. + * @note It is assumed that the various sources are only activated if the + * associated callback pointer is not equal to @p NULL in order to not + * perform an extra check in a potentially critical interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM9_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + eicu_lld_serve_interrupt(&EICUD9); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* STM32_EICU_USE_TIM9 */ + +#if STM32_EICU_USE_TIM12 +#if !defined(STM32_TIM12_HANDLER) +#error "STM32_TIM12_HANDLER not defined" +#endif +/** + * @brief TIM12 interrupt handler. + * @note It is assumed that the various sources are only activated if the + * associated callback pointer is not equal to @p NULL in order to not + * perform an extra check in a potentially critical interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM12_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + eicu_lld_serve_interrupt(&EICUD12); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* STM32_EICU_USE_TIM12 */ + +#if STM32_EICU_USE_TIM10 +#if !defined(STM32_TIM10_HANDLER) +#error "STM32_TIM10_HANDLER not defined" +#endif +/** + * @brief TIM10 interrupt handler. + * @note It is assumed that the various sources are only activated if the + * associated callback pointer is not equal to @p NULL in order to not + * perform an extra check in a potentially critical interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM10_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + eicu_lld_serve_interrupt(&EICUD10); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* STM32_EICU_USE_TIM10 */ + +#if STM32_EICU_USE_TIM11 +#if !defined(STM32_TIM11_HANDLER) +#error "STM32_TIM11_HANDLER not defined" +#endif +/** + * @brief TIM11 interrupt handler. + * @note It is assumed that the various sources are only activated if the + * associated callback pointer is not equal to @p NULL in order to not + * perform an extra check in a potentially critical interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM11_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + eicu_lld_serve_interrupt(&EICUD11); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* STM32_EICU_USE_TIM11 */ + +#if STM32_EICU_USE_TIM13 +#if !defined(STM32_TIM13_HANDLER) +#error "STM32_TIM13_HANDLER not defined" +#endif +/** + * @brief TIM13 interrupt handler. + * @note It is assumed that the various sources are only activated if the + * associated callback pointer is not equal to @p NULL in order to not + * perform an extra check in a potentially critical interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM13_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + eicu_lld_serve_interrupt(&EICUD13); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* STM32_EICU_USE_TIM13 */ + +#if STM32_EICU_USE_TIM14 +#if !defined(STM32_TIM14_HANDLER) +#error "STM32_TIM14_HANDLER not defined" +#endif +/** + * @brief TIM14 interrupt handler. + * @note It is assumed that the various sources are only activated if the + * associated callback pointer is not equal to @p NULL in order to not + * perform an extra check in a potentially critical interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM14_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + eicu_lld_serve_interrupt(&EICUD14); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* STM32_EICU_USE_TIM14 */ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level EICU driver initialization. + * + * @notapi + */ +void eicu_lld_init(void) { +#if STM32_EICU_USE_TIM1 + /* Driver initialization.*/ + eicuObjectInit(&EICUD1); + EICUD1.tim = STM32_TIM1; +#endif + +#if STM32_EICU_USE_TIM2 + /* Driver initialization.*/ + eicuObjectInit(&EICUD2); + EICUD2.tim = STM32_TIM2; +#endif + +#if STM32_EICU_USE_TIM3 + /* Driver initialization.*/ + eicuObjectInit(&EICUD3); + EICUD3.tim = STM32_TIM3; +#endif + +#if STM32_EICU_USE_TIM4 + /* Driver initialization.*/ + eicuObjectInit(&EICUD4); + EICUD4.tim = STM32_TIM4; +#endif + +#if STM32_EICU_USE_TIM5 + /* Driver initialization.*/ + eicuObjectInit(&EICUD5); + EICUD5.tim = STM32_TIM5; +#endif + +#if STM32_EICU_USE_TIM8 + /* Driver initialization.*/ + eicuObjectInit(&EICUD8); + EICUD8.tim = STM32_TIM8; +#endif + +#if STM32_EICU_USE_TIM9 + /* Driver initialization.*/ + eicuObjectInit(&EICUD9); + EICUD9.tim = STM32_TIM9; +#endif + +#if STM32_EICU_USE_TIM12 + /* Driver initialization.*/ + eicuObjectInit(&EICUD12); + EICUD12.tim = STM32_TIM12; +#endif + +#if STM32_EICU_USE_TIM10 + /* Driver initialization.*/ + eicuObjectInit(&EICUD10); + EICUD10.tim = STM32_TIM10; +#endif + +#if STM32_EICU_USE_TIM11 + /* Driver initialization.*/ + eicuObjectInit(&EICUD11); + EICUD11.tim = STM32_TIM11; +#endif + +#if STM32_EICU_USE_TIM13 + /* Driver initialization.*/ + eicuObjectInit(&EICUD13); + EICUD13.tim = STM32_TIM13; +#endif + +#if STM32_EICU_USE_TIM14 + /* Driver initialization.*/ + eicuObjectInit(&EICUD14); + EICUD14.tim = STM32_TIM14; +#endif +} + +/** + * @brief Configures and activates the EICU peripheral. + * + * @param[in] eicup Pointer to the @p EICUDriver object + * + * @notapi + */ +void eicu_lld_start(EICUDriver *eicup) { + uint32_t psc; + size_t ch; + + osalDbgAssert((eicup->config->iccfgp[0] != NULL) || + (eicup->config->iccfgp[1] != NULL) || + (eicup->config->iccfgp[2] != NULL) || + (eicup->config->iccfgp[3] != NULL), + "invalid input configuration"); + + if (eicup->state == EICU_STOP) { + /* Clock activation and timer reset.*/ +#if STM32_EICU_USE_TIM1 + if (&EICUD1 == eicup) { + rccEnableTIM1(FALSE); + rccResetTIM1(); + nvicEnableVector(STM32_TIM1_UP_NUMBER, STM32_EICU_TIM1_IRQ_PRIORITY); + nvicEnableVector(STM32_TIM1_CC_NUMBER, STM32_EICU_TIM1_IRQ_PRIORITY); + eicup->channels = 4; +#if defined(STM32_TIM1CLK) + eicup->clock = STM32_TIM1CLK; +#else + eicup->clock = STM32_TIMCLK2; +#endif + } +#endif +#if STM32_EICU_USE_TIM2 + if (&EICUD2 == eicup) { + rccEnableTIM2(FALSE); + rccResetTIM2(); + nvicEnableVector(STM32_TIM2_NUMBER, STM32_EICU_TIM2_IRQ_PRIORITY); + eicup->channels = 4; + eicup->clock = STM32_TIMCLK1; + } +#endif +#if STM32_EICU_USE_TIM3 + if (&EICUD3 == eicup) { + rccEnableTIM3(FALSE); + rccResetTIM3(); + nvicEnableVector(STM32_TIM3_NUMBER, STM32_EICU_TIM3_IRQ_PRIORITY); + eicup->channels = 4; + eicup->clock = STM32_TIMCLK1; + } +#endif +#if STM32_EICU_USE_TIM4 + if (&EICUD4 == eicup) { + rccEnableTIM4(FALSE); + rccResetTIM4(); + nvicEnableVector(STM32_TIM4_NUMBER, STM32_EICU_TIM4_IRQ_PRIORITY); + eicup->channels = 4; + eicup->clock = STM32_TIMCLK1; + } +#endif +#if STM32_EICU_USE_TIM5 + if (&EICUD5 == eicup) { + rccEnableTIM5(FALSE); + rccResetTIM5(); + nvicEnableVector(STM32_TIM5_NUMBER, STM32_EICU_TIM5_IRQ_PRIORITY); + eicup->channels = 4; + eicup->clock = STM32_TIMCLK1; + } +#endif +#if STM32_EICU_USE_TIM8 + if (&EICUD8 == eicup) { + rccEnableTIM8(FALSE); + rccResetTIM8(); + nvicEnableVector(STM32_TIM8_UP_NUMBER, STM32_EICU_TIM8_IRQ_PRIORITY); + nvicEnableVector(STM32_TIM8_CC_NUMBER, STM32_EICU_TIM8_IRQ_PRIORITY); + eicup->channels = 4; +#if defined(STM32_TIM8CLK) + eicup->clock = STM32_TIM8CLK; +#else + eicup->clock = STM32_TIMCLK2; +#endif + } +#endif +#if STM32_EICU_USE_TIM9 + if (&EICUD9 == eicup) { + rccEnableTIM9(FALSE); + rccResetTIM9(); + nvicEnableVector(STM32_TIM9_NUMBER, STM32_EICU_TIM9_IRQ_PRIORITY); + eicup->channels = 2; + eicup->clock = STM32_TIMCLK2; + } +#endif +#if STM32_EICU_USE_TIM12 + if (&EICUD12 == eicup) { + rccEnableTIM12(FALSE); + rccResetTIM12(); + nvicEnableVector(STM32_TIM12_NUMBER, STM32_EICU_TIM12_IRQ_PRIORITY); + eicup->channels = 2; + eicup->clock = STM32_TIMCLK1; + } +#endif +#if STM32_EICU_USE_TIM10 + if (&EICUD10 == eicup) { + rccEnableTIM10(FALSE); + rccResetTIM10(); + nvicEnableVector(STM32_TIM10_NUMBER, STM32_EICU_TIM10_IRQ_PRIORITY); + eicup->channels = 1; + eicup->clock = STM32_TIMCLK2; + } +#endif +#if STM32_EICU_USE_TIM11 + if (&EICUD11 == eicup) { + rccEnableTIM11(FALSE); + rccResetTIM11(); + nvicEnableVector(STM32_TIM11_NUMBER, STM32_EICU_TIM11_IRQ_PRIORITY); + eicup->channels = 1; + eicup->clock = STM32_TIMCLK2; + } +#endif +#if STM32_EICU_USE_TIM13 + if (&EICUD13 == eicup) { + rccEnableTIM13(FALSE); + rccResetTIM13(); + nvicEnableVector(STM32_TIM13_NUMBER, STM32_EICU_TIM13_IRQ_PRIORITY); + eicup->channels = 1; + eicup->clock = STM32_TIMCLK1; + } +#endif +#if STM32_EICU_USE_TIM14 + if (&EICUD14 == eicup) { + rccEnableTIM14(FALSE); + rccResetTIM14(); + nvicEnableVector(STM32_TIM14_NUMBER, STM32_EICU_TIM14_IRQ_PRIORITY); + eicup->channels = 1; + eicup->clock = STM32_TIMCLK1; + } +#endif + } + else { + /* Driver re-configuration scenario, it must be stopped first.*/ + eicup->tim->CR1 = 0; /* Timer disabled. */ + eicup->tim->DIER = eicup->config->dier &/* DMA-related DIER settings. */ + ~STM32_TIM_DIER_IRQ_MASK; + eicup->tim->SR = 0; /* Clear eventual pending IRQs. */ + eicup->tim->CCR[0] = 0; /* Comparator 1 disabled. */ + eicup->tim->CCR[1] = 0; /* Comparator 2 disabled. */ + eicup->tim->CNT = 0; /* Counter reset to zero. */ + } + + /* Timer configuration.*/ + psc = (eicup->clock / eicup->config->frequency) - 1; + chDbgAssert((psc <= 0xFFFF) && + ((psc + 1) * eicup->config->frequency) == eicup->clock, + "invalid frequency"); + eicup->tim->PSC = (uint16_t)psc; + eicup->tim->ARR = (eicucnt_t)-1; + + /* Detect width.*/ + if (0xFFFFFFFF == eicup->tim->ARR) + eicup->width = EICU_WIDTH_32; + else if (0xFFFF == eicup->tim->ARR) + eicup->width = EICU_WIDTH_16; + else + osalSysHalt("Unsupported width"); + + /* Reset registers */ + eicup->tim->SMCR = 0; + eicup->tim->CCMR1 = 0; + if (eicup->channels > 2) + eicup->tim->CCMR2 = 0; + + /* clean channel structures and set pointers to channel configs */ + for (ch=0; chchannel[ch].last_active = 0; + eicup->channel[ch].last_idle = 0; + eicup->channel[ch].config = eicup->config->iccfgp[ch]; + eicup->channel[ch].state = EICU_CH_IDLE; + } + + /* TIM9 and TIM12 have only 2 channels.*/ + if (eicup->channels == 2) { + osalDbgCheck((eicup->config->iccfgp[2] == NULL) && + (eicup->config->iccfgp[3] == NULL)); + } + + /* TIM10, TIM11, TIM13 and TIM14 have only 1 channel.*/ + if (eicup->channels == 1) { + osalDbgCheck((eicup->config->iccfgp[1] == NULL) && + (eicup->config->iccfgp[2] == NULL) && + (eicup->config->iccfgp[3] == NULL)); + } + + start_channels(eicup); +} + +/** + * @brief Deactivates the EICU peripheral. + * + * @param[in] eicup Pointer to the @p EICUDriver object + * + * @notapi + */ +void eicu_lld_stop(EICUDriver *eicup) { + + if (eicup->state == EICU_READY) { + + /* Clock deactivation.*/ + eicup->tim->CR1 = 0; /* Timer disabled. */ + eicup->tim->DIER = 0; /* All IRQs disabled. */ + eicup->tim->SR = 0; /* Clear eventual pending IRQs. */ + +#if STM32_EICU_USE_TIM1 + if (&EICUD1 == eicup) { + nvicDisableVector(STM32_TIM1_UP_NUMBER); + nvicDisableVector(STM32_TIM1_CC_NUMBER); + rccDisableTIM1(FALSE); + } +#endif +#if STM32_EICU_USE_TIM2 + if (&EICUD2 == eicup) { + nvicDisableVector(STM32_TIM2_NUMBER); + rccDisableTIM2(FALSE); + } +#endif +#if STM32_EICU_USE_TIM3 + if (&EICUD3 == eicup) { + nvicDisableVector(STM32_TIM3_NUMBER); + rccDisableTIM3(FALSE); + } +#endif +#if STM32_EICU_USE_TIM4 + if (&EICUD4 == eicup) { + nvicDisableVector(STM32_TIM4_NUMBER); + rccDisableTIM4(FALSE); + } +#endif +#if STM32_EICU_USE_TIM5 + if (&EICUD5 == eicup) { + nvicDisableVector(STM32_TIM5_NUMBER); + rccDisableTIM5(FALSE); + } +#endif +#if STM32_EICU_USE_TIM8 + if (&EICUD8 == eicup) { + nvicDisableVector(STM32_TIM8_UP_NUMBER); + nvicDisableVector(STM32_TIM8_CC_NUMBER); + rccDisableTIM8(FALSE); + } +#endif +#if STM32_EICU_USE_TIM9 + if (&EICUD9 == eicup) { + nvicDisableVector(STM32_TIM9_NUMBER); + rccDisableTIM9(FALSE); + } +#endif +#if STM32_EICU_USE_TIM12 + if (&EICUD12 == eicup) { + nvicDisableVector(STM32_TIM12_NUMBER); + rccDisableTIM12(FALSE); + } +#endif + } +#if STM32_EICU_USE_TIM10 + if (&EICUD10 == eicup) { + nvicDisableVector(STM32_TIM10_NUMBER); + rccDisableTIM10(FALSE); + } +#endif +#if STM32_EICU_USE_TIM11 + if (&EICUD11 == eicup) { + nvicDisableVector(STM32_TIM11_NUMBER); + rccDisableTIM11(FALSE); + } +#endif +#if STM32_EICU_USE_TIM13 + if (&EICUD13 == eicup) { + nvicDisableVector(STM32_TIM13_NUMBER); + rccDisableTIM13(FALSE); + } +#endif +#if STM32_EICU_USE_TIM14 + if (&EICUD14 == eicup) { + nvicDisableVector(STM32_TIM14_NUMBER); + rccDisableTIM14(FALSE); + } +#endif +} + +/** + * @brief Enables the EICU. + * + * @param[in] eicup Pointer to the @p EICUDriver object + * + * @notapi + */ +void eicu_lld_enable(EICUDriver *eicup) { + + eicup->tim->EGR = STM32_TIM_EGR_UG; + eicup->tim->SR = 0; /* Clear pending IRQs (if any). */ + + if ((eicup->config->iccfgp[EICU_CHANNEL_1] != NULL) && + (eicup->config->iccfgp[EICU_CHANNEL_1]->capture_cb != NULL)) + eicup->tim->DIER |= STM32_TIM_DIER_CC1IE; + if ((eicup->config->iccfgp[EICU_CHANNEL_2] != NULL) && + (eicup->config->iccfgp[EICU_CHANNEL_2]->capture_cb != NULL)) + eicup->tim->DIER |= STM32_TIM_DIER_CC2IE; + if ((eicup->config->iccfgp[EICU_CHANNEL_3] != NULL) && + (eicup->config->iccfgp[EICU_CHANNEL_3]->capture_cb != NULL)) + eicup->tim->DIER |= STM32_TIM_DIER_CC3IE; + if ((eicup->config->iccfgp[EICU_CHANNEL_4] != NULL) && + (eicup->config->iccfgp[EICU_CHANNEL_4]->capture_cb != NULL)) + eicup->tim->DIER |= STM32_TIM_DIER_CC4IE; + + eicup->tim->CR1 = STM32_TIM_CR1_URS | STM32_TIM_CR1_CEN; +} + +/** + * @brief Disables the EICU. + * + * @param[in] eicup Pointer to the @p EICUDriver object + * + * @notapi + */ +void eicu_lld_disable(EICUDriver *eicup) { + eicup->tim->CR1 = 0; /* Initially stopped. */ + eicup->tim->SR = 0; /* Clear pending IRQs (if any). */ + + /* All interrupts disabled.*/ + eicup->tim->DIER &= ~STM32_TIM_DIER_IRQ_MASK; +} + +#endif /* HAL_USE_EICU */ diff --git a/os/hal/ports/STM32/LLD/TIMv1/hal_eicu_lld.h b/os/hal/ports/STM32/LLD/TIMv1/hal_eicu_lld.h new file mode 100644 index 0000000..927eb6f --- /dev/null +++ b/os/hal/ports/STM32/LLD/TIMv1/hal_eicu_lld.h @@ -0,0 +1,554 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +/* + Rewritten by Emil Fresk (1/5 - 2014) for extended input capture + functionality. And fix for spurious callbacks in the interrupt handler. +*/ +/* + Improved by Uladzimir Pylinsky aka barthess (1/3 - 2015) for support of + 32-bit timers and timers with single capture/compare channels. +*/ + +#ifndef __EICU_LLD_H +#define __EICU_LLD_H + +#include "stm32_tim.h" + +#if (HAL_USE_EICU == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief EICUD1 driver enable switch. + * @details If set to @p TRUE the support for EICUD1 is included. + * @note The default is @p TRUE. + */ +#if !defined(STM32_EICU_USE_TIM1) || defined(__DOXYGEN__) +#define STM32_EICU_USE_TIM1 FALSE +#endif + +/** + * @brief EICUD2 driver enable switch. + * @details If set to @p TRUE the support for EICUD2 is included. + * @note The default is @p TRUE. + */ +#if !defined(STM32_EICU_USE_TIM2) || defined(__DOXYGEN__) +#define STM32_EICU_USE_TIM2 FALSE +#endif + +/** + * @brief EICUD3 driver enable switch. + * @details If set to @p TRUE the support for EICUD3 is included. + * @note The default is @p TRUE. + */ +#if !defined(STM32_EICU_USE_TIM3) || defined(__DOXYGEN__) +#define STM32_EICU_USE_TIM3 FALSE +#endif + +/** + * @brief EICUD4 driver enable switch. + * @details If set to @p TRUE the support for EICUD4 is included. + * @note The default is @p TRUE. + */ +#if !defined(STM32_EICU_USE_TIM4) || defined(__DOXYGEN__) +#define STM32_EICU_USE_TIM4 FALSE +#endif + +/** + * @brief EICUD5 driver enable switch. + * @details If set to @p TRUE the support for EICUD5 is included. + * @note The default is @p TRUE. + */ +#if !defined(STM32_EICU_USE_TIM5) || defined(__DOXYGEN__) +#define STM32_EICU_USE_TIM5 FALSE +#endif + +/** + * @brief EICUD8 driver enable switch. + * @details If set to @p TRUE the support for EICUD8 is included. + * @note The default is @p TRUE. + */ +#if !defined(STM32_EICU_USE_TIM8) || defined(__DOXYGEN__) +#define STM32_EICU_USE_TIM8 FALSE +#endif + +/** + * @brief EICUD9 driver enable switch. + * @details If set to @p TRUE the support for EICUD9 is included. + * @note The default is @p TRUE. + */ +#if !defined(STM32_EICU_USE_TIM9) || defined(__DOXYGEN__) +#define STM32_EICU_USE_TIM9 FALSE +#endif + +/** + * @brief EICUD12 driver enable switch. + * @details If set to @p TRUE the support for EICUD12 is included. + * @note The default is @p TRUE. + */ +#if !defined(STM32_EICU_USE_TIM12) || defined(__DOXYGEN__) +#define STM32_EICU_USE_TIM12 FALSE +#endif + +/** + * @brief EICUD1 interrupt priority level setting. + */ +#if !defined(STM32_EICU_TIM1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_EICU_TIM1_IRQ_PRIORITY 7 +#endif + +/** + * @brief EICUD2 interrupt priority level setting. + */ +#if !defined(STM32_EICU_TIM2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_EICU_TIM2_IRQ_PRIORITY 7 +#endif + +/** + * @brief EICUD3 interrupt priority level setting. + */ +#if !defined(STM32_EICU_TIM3_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_EICU_TIM3_IRQ_PRIORITY 7 +#endif + +/** + * @brief EICUD4 interrupt priority level setting. + */ +#if !defined(STM32_EICU_TIM4_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_EICU_TIM4_IRQ_PRIORITY 7 +#endif + +/** + * @brief EICUD5 interrupt priority level setting. + */ +#if !defined(STM32_EICU_TIM5_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_EICU_TIM5_IRQ_PRIORITY 7 +#endif + +/** + * @brief EICUD8 interrupt priority level setting. + */ +#if !defined(STM32_EICU_TIM8_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_EICU_TIM8_IRQ_PRIORITY 7 +#endif + +/** + * @brief EICUD9 interrupt priority level setting. + */ +#if !defined(STM32_EICU_TIM9_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_EICU_TIM9_IRQ_PRIORITY 7 +#endif + +/** + * @brief EICUD12 interrupt priority level setting. + */ +#if !defined(STM32_EICU_TIM12_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_EICU_TIM12_IRQ_PRIORITY 7 +#endif + +/** + * @brief EICUD10 interrupt priority level setting. + */ +#if !defined(STM32_EICU_TIM10_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_EICU_TIM10_IRQ_PRIORITY 7 +#endif + +/** + * @brief EICUD11 interrupt priority level setting. + */ +#if !defined(STM32_EICU_TIM11_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_EICU_TIM11_IRQ_PRIORITY 7 +#endif + +/** + * @brief EICUD13 interrupt priority level setting. + */ +#if !defined(STM32_EICU_TIM13_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_EICU_TIM13_IRQ_PRIORITY 7 +#endif + +/** + * @brief EICUD14 interrupt priority level setting. + */ +#if !defined(STM32_EICU_TIM14_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_EICU_TIM14_IRQ_PRIORITY 7 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if STM32_EICU_USE_TIM1 && !STM32_HAS_TIM1 +#error "TIM1 not present in the selected device" +#endif + +#if STM32_EICU_USE_TIM2 && !STM32_HAS_TIM2 +#error "TIM2 not present in the selected device" +#endif + +#if STM32_EICU_USE_TIM3 && !STM32_HAS_TIM3 +#error "TIM3 not present in the selected device" +#endif + +#if STM32_EICU_USE_TIM4 && !STM32_HAS_TIM4 +#error "TIM4 not present in the selected device" +#endif + +#if STM32_EICU_USE_TIM5 && !STM32_HAS_TIM5 +#error "TIM5 not present in the selected device" +#endif + +#if STM32_EICU_USE_TIM8 && !STM32_HAS_TIM8 +#error "TIM8 not present in the selected device" +#endif + +#if STM32_EICU_USE_TIM9 && !STM32_HAS_TIM9 +#error "TIM9 not present in the selected device" +#endif + +#if STM32_EICU_USE_TIM12 && !STM32_HAS_TIM12 +#error "TIM12 not present in the selected device" +#endif + +#if STM32_EICU_USE_TIM10 && !STM32_HAS_TIM10 +#error "TIM10 not present in the selected device" +#endif + +#if STM32_EICU_USE_TIM11 && !STM32_HAS_TIM11 +#error "TIM11 not present in the selected device" +#endif + +#if STM32_EICU_USE_TIM13 && !STM32_HAS_TIM13 +#error "TIM13 not present in the selected device" +#endif + +#if STM32_EICU_USE_TIM14 && !STM32_HAS_TIM14 +#error "TIM14 not present in the selected device" +#endif + +#if !STM32_EICU_USE_TIM1 && !STM32_EICU_USE_TIM2 && \ + !STM32_EICU_USE_TIM3 && !STM32_EICU_USE_TIM4 && \ + !STM32_EICU_USE_TIM5 && !STM32_EICU_USE_TIM8 && \ + !STM32_EICU_USE_TIM9 && !STM32_EICU_USE_TIM12 && \ + !STM32_EICU_USE_TIM10 && !STM32_EICU_USE_TIM11 && \ + !STM32_EICU_USE_TIM13 && !STM32_EICU_USE_TIM14 +#error "EICU driver activated but no TIM peripheral assigned" +#endif + +#if STM32_EICU_USE_TIM1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_EICU_TIM1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM1" +#endif + +#if STM32_EICU_USE_TIM2 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_EICU_TIM2_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM2" +#endif + +#if STM32_EICU_USE_TIM3 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_EICU_TIM3_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM3" +#endif + +#if STM32_EICU_USE_TIM4 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_EICU_TIM4_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM4" +#endif + +#if STM32_EICU_USE_TIM5 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_EICU_TIM5_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM5" +#endif + +#if STM32_EICU_USE_TIM8 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_EICU_TIM8_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM8" +#endif + +#if STM32_EICU_USE_TIM9 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_EICU_TIM9_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM9" +#endif + +#if STM32_EICU_USE_TIM12 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_EICU_TIM12_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM12" +#endif + +#if STM32_EICU_USE_TIM10 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_EICU_TIM10_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM10" +#endif + +#if STM32_EICU_USE_TIM11 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_EICU_TIM11_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM11" +#endif + +#if STM32_EICU_USE_TIM13 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_EICU_TIM13_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM13" +#endif + +#if STM32_EICU_USE_TIM14 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_EICU_TIM14_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM14" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ +/** + * @brief Active level selector. + */ +typedef enum { + EICU_INPUT_ACTIVE_HIGH, /**< Trigger on rising edge. */ + EICU_INPUT_ACTIVE_LOW, /**< Trigger on falling edge. */ +} eicuactivelevel_t; + +/** + * @brief Input type selector. + */ +typedef enum { + /** + * @brief Measures time between consequent edges. + * @details Callback fires on every _active_ edge. + */ + EICU_INPUT_EDGE, + /** + * @brief Measures pulse width. + * @details Callback fires on _idle_ edge of pulse. + */ + EICU_INPUT_PULSE, + /** + * @brief Measures both period and width.. + * @details Callback fires on _active_ edge of pulse. + */ + EICU_INPUT_BOTH +} eicucapturemode_t; + +/** + * @brief Timer registers width in bits. + */ +typedef enum { + EICU_WIDTH_16, + EICU_WIDTH_32 +} eicutimerwidth_t; + +/** + * @brief EICU frequency type. + */ +typedef uint32_t eicufreq_t; + +/** + * @brief EICU counter type. + */ +typedef uint32_t eicucnt_t; + +/** + * @brief EICU captured width and (or) period. + */ +typedef struct { + /** + * @brief Pulse width. + */ + eicucnt_t width; + /** + * @brief Pulse period. + */ + eicucnt_t period; +} eicuresult_t; + +/** + * @brief EICU Capture Channel Config structure definition. + */ +typedef struct { + /** + * @brief Specifies the active level of the input signal. + */ + eicuactivelevel_t alvl; + /** + * @brief Specifies the channel capture mode. + */ + eicucapturemode_t mode; + /** + * @brief Capture event callback. Used for PWM width, pulse width and + * pulse period capture event. + */ + eicucallback_t capture_cb; +} EICUChannelConfig; + +/** + * @brief EICU Capture Channel structure definition. + */ +typedef struct { + /** + * @brief Channel state for the internal state machine. + */ + eicuchannelstate_t state; + /** + * @brief Cached value for pulse width calculation. + */ + eicucnt_t last_active; + /** + * @brief Cached value for period calculation. + */ + eicucnt_t last_idle; + /** + * @brief Pointer to Input Capture channel configuration. + */ + const EICUChannelConfig *config; + /** + * @brief CCR register pointer for faster access. + */ + volatile uint32_t *ccrp; +} EICUChannel; + +/** + * @brief EICU Config structure definition. + */ +typedef struct { + /** + * @brief Specifies the Timer clock in Hz. + */ + eicufreq_t frequency; + /** + * @brief Pointer to each Input Capture channel configuration. + * @note A NULL parameter indicates the channel as unused. + * @note In PWM mode, only Channel 1 OR Channel 2 may be used. + */ + const EICUChannelConfig *iccfgp[EICU_CHANNEL_ENUM_END]; + /** + * @brief TIM DIER register initialization data. + */ + uint32_t dier; +} EICUConfig; + +/** + * @brief EICU Driver structure definition + */ +struct EICUDriver { + /** + * @brief STM32 timer peripheral for Input Capture. + */ + stm32_tim_t *tim; + /** + * @brief Driver state for the internal state machine. + */ + eicustate_t state; + /** + * @brief Channels' data structures. + */ + EICUChannel channel[EICU_CHANNEL_ENUM_END]; + /** + * @brief Timer base clock. + */ + uint32_t clock; + /** + * @brief Number of available capture compare channels in timer. + */ + size_t channels; + /** + * @brief Timer registers width in bits. + */ + eicutimerwidth_t width; + /** + * @brief Pointer to configuration for the driver. + */ + const EICUConfig *config; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ +#if STM32_EICU_USE_TIM1 && !defined(__DOXYGEN__) +extern EICUDriver EICUD1; +#endif + +#if STM32_EICU_USE_TIM2 && !defined(__DOXYGEN__) +extern EICUDriver EICUD2; +#endif + +#if STM32_EICU_USE_TIM3 && !defined(__DOXYGEN__) +extern EICUDriver EICUD3; +#endif + +#if STM32_EICU_USE_TIM4 && !defined(__DOXYGEN__) +extern EICUDriver EICUD4; +#endif + +#if STM32_EICU_USE_TIM5 && !defined(__DOXYGEN__) +extern EICUDriver EICUD5; +#endif + +#if STM32_EICU_USE_TIM8 && !defined(__DOXYGEN__) +extern EICUDriver EICUD8; +#endif + +#if STM32_EICU_USE_TIM9 && !defined(__DOXYGEN__) +extern EICUDriver EICUD9; +#endif + +#if STM32_EICU_USE_TIM12 && !defined(__DOXYGEN__) +extern EICUDriver EICUD12; +#endif + +#if STM32_EICU_USE_TIM10 && !defined(__DOXYGEN__) +extern EICUDriver EICUD10; +#endif + +#if STM32_EICU_USE_TIM11 && !defined(__DOXYGEN__) +extern EICUDriver EICUD11; +#endif + +#if STM32_EICU_USE_TIM13 && !defined(__DOXYGEN__) +extern EICUDriver EICUD13; +#endif + +#if STM32_EICU_USE_TIM14 && !defined(__DOXYGEN__) +extern EICUDriver EICUD14; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void eicu_lld_init(void); + void eicu_lld_start(EICUDriver *eicup); + void eicu_lld_stop(EICUDriver *eicup); + void eicu_lld_enable(EICUDriver *eicup); + void eicu_lld_disable(EICUDriver *eicup); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_EICU */ + +#endif /* __EICU_LLD_H */ diff --git a/os/hal/ports/STM32/LLD/TIMv1/hal_timcap_lld.c b/os/hal/ports/STM32/LLD/TIMv1/hal_timcap_lld.c new file mode 100644 index 0000000..8ab6176 --- /dev/null +++ b/os/hal/ports/STM32/LLD/TIMv1/hal_timcap_lld.c @@ -0,0 +1,818 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +/* + This file was derived from the ICU subsystem code, modified to achieve + timing measurements on 2 and/or 4 channel STM32 timers by Dave Camarillo. + */ +/* + Concepts and parts of this file have been contributed by Fabio Utzig and + Xo Wang. + */ + + +/** + * @file STM32/timcap_lld.c + * @brief STM32 TIMCAP subsystem low level driver header. + * + * @addtogroup TIMCAP + * @{ + */ + +#include "ch.h" +#include "hal.h" + +#if HAL_USE_TIMCAP || defined(__DOXYGEN__) + +#include "stm32_tim.h" +#include "hal_timcap.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief TIMCAPD1 driver identifier. + * @note The driver TIMCAPD1 allocates the complex timer TIM1 when enabled. + */ +#if STM32_TIMCAP_USE_TIM1 || defined(__DOXYGEN__) +TIMCAPDriver TIMCAPD1; +#endif + +/** + * @brief TIMCAPD2 driver identifier. + * @note The driver TIMCAPD1 allocates the timer TIM2 when enabled. + */ +#if STM32_TIMCAP_USE_TIM2 || defined(__DOXYGEN__) +TIMCAPDriver TIMCAPD2; +#endif + +/** + * @brief TIMCAPD3 driver identifier. + * @note The driver TIMCAPD1 allocates the timer TIM3 when enabled. + */ +#if STM32_TIMCAP_USE_TIM3 || defined(__DOXYGEN__) +TIMCAPDriver TIMCAPD3; +#endif + +/** + * @brief TIMCAPD4 driver identifier. + * @note The driver TIMCAPD4 allocates the timer TIM4 when enabled. + */ +#if STM32_TIMCAP_USE_TIM4 || defined(__DOXYGEN__) +TIMCAPDriver TIMCAPD4; +#endif + +/** + * @brief TIMCAPD5 driver identifier. + * @note The driver TIMCAPD5 allocates the timer TIM5 when enabled. + */ +#if STM32_TIMCAP_USE_TIM5 || defined(__DOXYGEN__) +TIMCAPDriver TIMCAPD5; +#endif + +/** + * @brief TIMCAPD8 driver identifier. + * @note The driver TIMCAPD8 allocates the timer TIM8 when enabled. + */ +#if STM32_TIMCAP_USE_TIM8 || defined(__DOXYGEN__) +TIMCAPDriver TIMCAPD8; +#endif + +/** + * @brief TIMCAPD9 driver identifier. + * @note The driver TIMCAPD9 allocates the timer TIM9 when enabled. + */ +#if STM32_TIMCAP_USE_TIM9 || defined(__DOXYGEN__) +TIMCAPDriver TIMCAPD9; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + + +/** + * @brief Returns the maximum channel number for the respective TIMCAP driver. + * Note: different timer perepherials on the STM32 have between 1 and 4 + * CCR registers. + * + * @param[in] timcapp pointer to the @p TIMCAPDriver object + */ +static timcapchannel_t timcap_get_max_timer_channel(const TIMCAPDriver *timcapp) { + //Choose a sane default value +#if STM32_TIMCAP_USE_TIM1 || defined(__DOXYGEN__) + if( timcapp == &TIMCAPD1 ) { + return(TIMCAP_CHANNEL_4); + } +#endif + +#if STM32_TIMCAP_USE_TIM2 || defined(__DOXYGEN__) + if( timcapp == &TIMCAPD2 ) { + return(TIMCAP_CHANNEL_4); + } +#endif + +#if STM32_TIMCAP_USE_TIM3 || defined(__DOXYGEN__) + if( timcapp == &TIMCAPD3 ) { + return(TIMCAP_CHANNEL_4); + } +#endif + +#if STM32_TIMCAP_USE_TIM4 || defined(__DOXYGEN__) + if( timcapp == &TIMCAPD4 ) { + return(TIMCAP_CHANNEL_4); + } +#endif + +#if STM32_TIMCAP_USE_TIM5 || defined(__DOXYGEN__) + if( timcapp == &TIMCAPD5 ) { + return(TIMCAP_CHANNEL_4); + } +#endif + +#if STM32_TIMCAP_USE_TIM8 || defined(__DOXYGEN__) + if( timcapp == &TIMCAPD8 ) { + return(TIMCAP_CHANNEL_4); + } +#endif + +#if STM32_TIMCAP_USE_TIM9 || defined(__DOXYGEN__) + if( timcapp == &TIMCAPD9 ) { + return(TIMCAP_CHANNEL_2); + } +#endif + + /*Return a conservative default value.*/ + return(TIMCAP_CHANNEL_1); +} + + +/** + * @brief Returns the maximum value for the ARR register of a given timer. + * + * @param[in] timcapp pointer to the @p TIMCAPDriver object + */ +static uint32_t timcap_get_max_arr(const TIMCAPDriver *timcapp) { + //Choose a sane default value +#if STM32_TIMCAP_USE_TIM1 || defined(__DOXYGEN__) + if( timcapp == &TIMCAPD1 ) { + return(UINT16_MAX); + } +#endif + +#if STM32_TIMCAP_USE_TIM2 || defined(__DOXYGEN__) + if( timcapp == &TIMCAPD2 ) { + return(UINT32_MAX); + } +#endif + +#if STM32_TIMCAP_USE_TIM3 || defined(__DOXYGEN__) + if( timcapp == &TIMCAPD3 ) { + return(UINT16_MAX); + } +#endif + +#if STM32_TIMCAP_USE_TIM4 || defined(__DOXYGEN__) + if( timcapp == &TIMCAPD4 ) { + return(UINT16_MAX); + } +#endif + +#if STM32_TIMCAP_USE_TIM5 || defined(__DOXYGEN__) + if( timcapp == &TIMCAPD5 ) { + return(UINT32_MAX); + } +#endif + +#if STM32_TIMCAP_USE_TIM8 || defined(__DOXYGEN__) + if( timcapp == &TIMCAPD8 ) { + return(UINT16_MAX); + } +#endif + +#if STM32_TIMCAP_USE_TIM9 || defined(__DOXYGEN__) + if( timcapp == &TIMCAPD9 ) { + return(UINT16_MAX); + } +#endif + + /*Return a conservative default value.*/ + return(UINT16_MAX); +} + +/** + * @brief Shared IRQ handler. + * + * @param[in] timcapp pointer to the @p TIMCAPDriver object + */ +static void timcap_lld_serve_interrupt(TIMCAPDriver *timcapp) { + uint16_t sr; + + sr = timcapp->tim->SR; + sr &= timcapp->tim->DIER & STM32_TIM_DIER_IRQ_MASK; + timcapp->tim->SR = ~sr; + + if ((sr & STM32_TIM_SR_CC1IF) != 0 && timcapp->config->capture_cb_array[TIMCAP_CHANNEL_1] != NULL ) + _timcap_isr_invoke_channel1_cb(timcapp); + + if ((sr & STM32_TIM_SR_CC2IF) != 0 && timcapp->config->capture_cb_array[TIMCAP_CHANNEL_2] != NULL ) + _timcap_isr_invoke_channel2_cb(timcapp); + + if ((sr & STM32_TIM_SR_CC3IF) != 0 && timcapp->config->capture_cb_array[TIMCAP_CHANNEL_3] != NULL ) + _timcap_isr_invoke_channel3_cb(timcapp); + + if ((sr & STM32_TIM_SR_CC4IF) != 0 && timcapp->config->capture_cb_array[TIMCAP_CHANNEL_4] != NULL ) + _timcap_isr_invoke_channel4_cb(timcapp); + + if ((sr & STM32_TIM_SR_UIF) != 0 && timcapp->config->overflow_cb != NULL) + _timcap_isr_invoke_overflow_cb(timcapp); +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_TIMCAP_USE_TIM1 +#if !defined(STM32_TIM1_UP_HANDLER) +#error "STM32_TIM1_UP_HANDLER not defined" +#endif +/** + * @brief TIM1 compare interrupt handler. + * @note It is assumed that the various sources are only activated if the + * associated callback pointer is not equal to @p NULL in order to not + * perform an extra check in a potentially critical interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(STM32_TIM1_UP_HANDLER) { + + CH_IRQ_PROLOGUE(); + + timcap_lld_serve_interrupt(&TIMCAPD1); + + CH_IRQ_EPILOGUE(); +} + +#if !defined(STM32_TIM1_CC_HANDLER) +#error "STM32_TIM1_CC_HANDLER not defined" +#endif +/** + * @brief TIM1 compare interrupt handler. + * @note It is assumed that the various sources are only activated if the + * associated callback pointer is not equal to @p NULL in order to not + * perform an extra check in a potentially critical interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(STM32_TIM1_CC_HANDLER) { + + CH_IRQ_PROLOGUE(); + + timcap_lld_serve_interrupt(&TIMCAPD1); + + CH_IRQ_EPILOGUE(); +} +#endif /* STM32_TIMCAP_USE_TIM1 */ + +#if STM32_TIMCAP_USE_TIM2 +#if !defined(STM32_TIM2_HANDLER) +#error "STM32_TIM2_HANDLER not defined" +#endif +/** + * @brief TIM2 interrupt handler. + * @note It is assumed that the various sources are only activated if the + * associated callback pointer is not equal to @p NULL in order to not + * perform an extra check in a potentially critical interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(STM32_TIM2_HANDLER) { + + CH_IRQ_PROLOGUE(); + + timcap_lld_serve_interrupt(&TIMCAPD2); + + CH_IRQ_EPILOGUE(); +} +#endif /* STM32_TIMCAP_USE_TIM2 */ + +#if STM32_TIMCAP_USE_TIM3 +#if !defined(STM32_TIM3_HANDLER) +#error "STM32_TIM3_HANDLER not defined" +#endif +/** + * @brief TIM3 interrupt handler. + * @note It is assumed that the various sources are only activated if the + * associated callback pointer is not equal to @p NULL in order to not + * perform an extra check in a potentially critical interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(STM32_TIM3_HANDLER) { + + CH_IRQ_PROLOGUE(); + + timcap_lld_serve_interrupt(&TIMCAPD3); + + CH_IRQ_EPILOGUE(); +} +#endif /* STM32_TIMCAP_USE_TIM3 */ + +#if STM32_TIMCAP_USE_TIM4 +#if !defined(STM32_TIM4_HANDLER) +#error "STM32_TIM4_HANDLER not defined" +#endif +/** + * @brief TIM4 interrupt handler. + * @note It is assumed that the various sources are only activated if the + * associated callback pointer is not equal to @p NULL in order to not + * perform an extra check in a potentially critical interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(STM32_TIM4_HANDLER) { + + CH_IRQ_PROLOGUE(); + + timcap_lld_serve_interrupt(&TIMCAPD4); + + CH_IRQ_EPILOGUE(); +} +#endif /* STM32_TIMCAP_USE_TIM4 */ + +#if STM32_TIMCAP_USE_TIM5 +#if !defined(STM32_TIM5_HANDLER) +#error "STM32_TIM5_HANDLER not defined" +#endif +/** + * @brief TIM5 interrupt handler. + * @note It is assumed that the various sources are only activated if the + * associated callback pointer is not equal to @p NULL in order to not + * perform an extra check in a potentially critical interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(STM32_TIM5_HANDLER) { + + CH_IRQ_PROLOGUE(); + + timcap_lld_serve_interrupt(&TIMCAPD5); + + CH_IRQ_EPILOGUE(); +} +#endif /* STM32_TIMCAP_USE_TIM5 */ + +#if STM32_TIMCAP_USE_TIM8 +#if !defined(STM32_TIM8_UP_HANDLER) +#error "STM32_TIM8_UP_HANDLER not defined" +#endif +/** + * @brief TIM8 compare interrupt handler. + * @note It is assumed that the various sources are only activated if the + * associated callback pointer is not equal to @p NULL in order to not + * perform an extra check in a potentially critical interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(STM32_TIM8_UP_HANDLER) { + + CH_IRQ_PROLOGUE(); + + timcap_lld_serve_interrupt(&TIMCAPD8); + + CH_IRQ_EPILOGUE(); +} + +#if !defined(STM32_TIM8_CC_HANDLER) +#error "STM32_TIM8_CC_HANDLER not defined" +#endif +/** + * @brief TIM8 compare interrupt handler. + * @note It is assumed that the various sources are only activated if the + * associated callback pointer is not equal to @p NULL in order to not + * perform an extra check in a potentially critical interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(STM32_TIM8_CC_HANDLER) { + + CH_IRQ_PROLOGUE(); + + timcap_lld_serve_interrupt(&TIMCAPD8); + + CH_IRQ_EPILOGUE(); +} +#endif /* STM32_TIMCAP_USE_TIM8 */ + +#if STM32_TIMCAP_USE_TIM9 +#if !defined(STM32_TIM9_HANDLER) +#error "STM32_TIM9_HANDLER not defined" +#endif +/** + * @brief TIM9 interrupt handler. + * @note It is assumed that the various sources are only activated if the + * associated callback pointer is not equal to @p NULL in order to not + * perform an extra check in a potentially critical interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(STM32_TIM9_HANDLER) { + + CH_IRQ_PROLOGUE(); + + timcap_lld_serve_interrupt(&TIMCAPD9); + + CH_IRQ_EPILOGUE(); +} +#endif /* STM32_TIMCAP_USE_TIM9 */ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level TIMCAP driver initialization. + * + * @notapi + */ +void timcap_lld_init(void) { + +#if STM32_TIMCAP_USE_TIM1 + /* Driver initialization.*/ + timcapObjectInit(&TIMCAPD1); + TIMCAPD1.tim = STM32_TIM1; +#endif + +#if STM32_TIMCAP_USE_TIM2 + /* Driver initialization.*/ + timcapObjectInit(&TIMCAPD2); + TIMCAPD2.tim = STM32_TIM2; +#endif + +#if STM32_TIMCAP_USE_TIM3 + /* Driver initialization.*/ + timcapObjectInit(&TIMCAPD3); + TIMCAPD3.tim = STM32_TIM3; +#endif + +#if STM32_TIMCAP_USE_TIM4 + /* Driver initialization.*/ + timcapObjectInit(&TIMCAPD4); + TIMCAPD4.tim = STM32_TIM4; +#endif + +#if STM32_TIMCAP_USE_TIM5 + /* Driver initialization.*/ + timcapObjectInit(&TIMCAPD5); + TIMCAPD5.tim = STM32_TIM5; +#endif + +#if STM32_TIMCAP_USE_TIM8 + /* Driver initialization.*/ + timcapObjectInit(&TIMCAPD8); + TIMCAPD8.tim = STM32_TIM8; +#endif + +#if STM32_TIMCAP_USE_TIM9 + /* Driver initialization.*/ + timcapObjectInit(&TIMCAPD9); + TIMCAPD9.tim = STM32_TIM9; +#endif +} + +/** + * @brief Configures and activates the TIMCAP peripheral. + * + * @param[in] timcapp pointer to the @p TIMCAPDriver object + * + * @notapi + */ +void timcap_lld_start(TIMCAPDriver *timcapp) { + uint32_t psc; + + const timcapchannel_t tim_max_channel = timcap_get_max_timer_channel(timcapp); + + if (timcapp->state == TIMCAP_STOP) { + /* Clock activation and timer reset.*/ +#if STM32_TIMCAP_USE_TIM1 + if (&TIMCAPD1 == timcapp) { + rccEnableTIM1(FALSE); + rccResetTIM1(); + nvicEnableVector(STM32_TIM1_UP_NUMBER, STM32_TIMCAP_TIM1_IRQ_PRIORITY); + nvicEnableVector(STM32_TIM1_CC_NUMBER, STM32_TIMCAP_TIM1_IRQ_PRIORITY); +#if defined(STM32_TIM1CLK) + timcapp->clock = STM32_TIM1CLK; +#else + timcapp->clock = STM32_TIMCLK2; +#endif + } +#endif +#if STM32_TIMCAP_USE_TIM2 + if (&TIMCAPD2 == timcapp) { + rccEnableTIM2(FALSE); + rccResetTIM2(); + nvicEnableVector(STM32_TIM2_NUMBER, STM32_TIMCAP_TIM2_IRQ_PRIORITY); + timcapp->clock = STM32_TIMCLK1; + } +#endif +#if STM32_TIMCAP_USE_TIM3 + if (&TIMCAPD3 == timcapp) { + rccEnableTIM3(FALSE); + rccResetTIM3(); + nvicEnableVector(STM32_TIM3_NUMBER, STM32_TIMCAP_TIM3_IRQ_PRIORITY); + timcapp->clock = STM32_TIMCLK1; + } +#endif +#if STM32_TIMCAP_USE_TIM4 + if (&TIMCAPD4 == timcapp) { + rccEnableTIM4(FALSE); + rccResetTIM4(); + nvicEnableVector(STM32_TIM4_NUMBER, STM32_TIMCAP_TIM4_IRQ_PRIORITY); + timcapp->clock = STM32_TIMCLK1; + } +#endif +#if STM32_TIMCAP_USE_TIM5 + if (&TIMCAPD5 == timcapp) { + rccEnableTIM5(FALSE); + rccResetTIM5(); + nvicEnableVector(STM32_TIM5_NUMBER, STM32_TIMCAP_TIM5_IRQ_PRIORITY); + timcapp->clock = STM32_TIMCLK1; + } +#endif +#if STM32_TIMCAP_USE_TIM8 + if (&TIMCAPD8 == timcapp) { + rccEnableTIM8(FALSE); + rccResetTIM8(); + nvicEnableVector(STM32_TIM8_UP_NUMBER, STM32_TIMCAP_TIM8_IRQ_PRIORITY); + nvicEnableVector(STM32_TIM8_CC_NUMBER, STM32_TIMCAP_TIM8_IRQ_PRIORITY); +#if defined(STM32_TIM8CLK) + timcapp->clock = STM32_TIM8CLK; +#else + timcapp->clock = STM32_TIMCLK2; +#endif + } +#endif +#if STM32_TIMCAP_USE_TIM9 + if (&TIMCAPD9 == timcapp) { + rccEnableTIM9(FALSE); + rccResetTIM9(); + nvicEnableVector(STM32_TIM9_NUMBER, STM32_TIMCAP_TIM9_IRQ_PRIORITY); + timcapp->clock = STM32_TIMCLK1; + } +#endif + } + else { + /* Driver re-configuration scenario, it must be stopped first.*/ + timcapp->tim->CR1 = 0; /* Timer disabled. */ + timcapp->tim->DIER = timcapp->config->dier &/* DMA-related DIER settings. */ + ~STM32_TIM_DIER_IRQ_MASK; + timcapp->tim->SR = 0; /* Clear eventual pending IRQs. */ + timcapp->tim->CCR[0] = 0; /* Comparator 1 disabled. */ + timcapp->tim->CCR[1] = 0; /* Comparator 2 disabled. */ + if( tim_max_channel >= TIMCAP_CHANNEL_3 ) + timcapp->tim->CCR[2] = 0; /* Comparator 3 disabled. */ + if( tim_max_channel >= TIMCAP_CHANNEL_4 ) + timcapp->tim->CCR[3] = 0; /* Comparator 4 disabled. */ + timcapp->tim->CNT = 0; /* Counter reset to zero. */ + } + + /* Timer configuration.*/ + psc = (timcapp->clock / timcapp->config->frequency) - 1; + osalDbgAssert((psc <= 0xFFFF) && + ((psc + 1) * timcapp->config->frequency) == timcapp->clock, + "invalid frequency"); + timcapp->tim->PSC = (uint16_t)psc; + timcapp->tim->ARR = timcap_get_max_arr(timcapp); + + timcapp->tim->CCMR1 = 0; + timcapp->tim->CCMR2 = 0; + timcapp->tim->CCER = 0; + + timcapchannel_t chan = TIMCAP_CHANNEL_1; + + /*go through each non-NULL callback channel and enable the capture register on rising/falling edge*/ + for( chan = TIMCAP_CHANNEL_1; chan <= tim_max_channel; chan++ ) { + if( timcapp->config->capture_cb_array[chan] == NULL ) { + continue; + } + + switch (chan) { + case TIMCAP_CHANNEL_1: + /*CCMR1_CC1S = 01 = CH1 Input on TI1.*/ + timcapp->tim->CCMR1 |= STM32_TIM_CCMR1_CC1S(1); + break; + case TIMCAP_CHANNEL_2: + /*CCMR1_CC2S = 10 = CH2 Input on TI1.*/ + timcapp->tim->CCMR1 |= STM32_TIM_CCMR1_CC2S(1); + break; + case TIMCAP_CHANNEL_3: + timcapp->tim->CCMR2 |= STM32_TIM_CCMR2_CC3S(1); + break; + case TIMCAP_CHANNEL_4: + timcapp->tim->CCMR2 |= STM32_TIM_CCMR2_CC4S(1); + break; + } + + /* The CCER settings depend on the selected trigger mode. + TIMCAP_INPUT_DISABLED: Input not used. + TIMCAP_INPUT_ACTIVE_HIGH: Active on rising edge, idle on falling edge. + TIMCAP_INPUT_ACTIVE_LOW: Active on falling edge, idle on rising edge.*/ + if (timcapp->config->modes[chan] == TIMCAP_INPUT_ACTIVE_HIGH) { + switch (chan) { + case TIMCAP_CHANNEL_1: + timcapp->tim->CCER |= STM32_TIM_CCER_CC1E; + break; + case TIMCAP_CHANNEL_2: + timcapp->tim->CCER |= STM32_TIM_CCER_CC2E; + break; + case TIMCAP_CHANNEL_3: + timcapp->tim->CCER |= STM32_TIM_CCER_CC3E; + break; + case TIMCAP_CHANNEL_4: + timcapp->tim->CCER |= STM32_TIM_CCER_CC4E; + break; + } + } + else if (timcapp->config->modes[chan] == TIMCAP_INPUT_ACTIVE_LOW) { + switch (chan) { + case TIMCAP_CHANNEL_1: + timcapp->tim->CCER |= STM32_TIM_CCER_CC1E | STM32_TIM_CCER_CC1P; + break; + case TIMCAP_CHANNEL_2: + timcapp->tim->CCER |= STM32_TIM_CCER_CC2E | STM32_TIM_CCER_CC2P; + break; + case TIMCAP_CHANNEL_3: + timcapp->tim->CCER |= STM32_TIM_CCER_CC3E | STM32_TIM_CCER_CC3P; + break; + case TIMCAP_CHANNEL_4: + timcapp->tim->CCER |= STM32_TIM_CCER_CC4E | STM32_TIM_CCER_CC4P; + break; + } + } + else { + switch (chan) { + case TIMCAP_CHANNEL_1: + timcapp->tim->CCER &= ~STM32_TIM_CCER_CC1E; + break; + case TIMCAP_CHANNEL_2: + timcapp->tim->CCER &= ~STM32_TIM_CCER_CC2E; + break; + case TIMCAP_CHANNEL_3: + timcapp->tim->CCER &= ~STM32_TIM_CCER_CC3E; + break; + case TIMCAP_CHANNEL_4: + timcapp->tim->CCER &= ~STM32_TIM_CCER_CC4E; + break; + } + } + /* Direct pointers to the capture registers in order to make reading + data faster from within callbacks.*/ + timcapp->ccr_p[chan] = &timcapp->tim->CCR[chan]; + } + + /* SMCR_TS = 101, input is TI1FP1.*/ + timcapp->tim->SMCR = STM32_TIM_SMCR_TS(5); +} + +/** + * @brief Deactivates the TIMCAP peripheral. + * + * @param[in] timcapp pointer to the @p TIMCAPDriver object + * + * @notapi + */ +void timcap_lld_stop(TIMCAPDriver *timcapp) { + + if (timcapp->state == TIMCAP_READY) { + /* Clock deactivation.*/ + timcapp->tim->CR1 = 0; /* Timer disabled. */ + timcapp->tim->DIER = 0; /* All IRQs disabled. */ + timcapp->tim->SR = 0; /* Clear eventual pending IRQs. */ + +#if STM32_TIMCAP_USE_TIM1 + if (&TIMCAPD1 == timcapp) { + nvicDisableVector(STM32_TIM1_UP_NUMBER); + nvicDisableVector(STM32_TIM1_CC_NUMBER); + rccDisableTIM1(FALSE); + } +#endif +#if STM32_TIMCAP_USE_TIM2 + if (&TIMCAPD2 == timcapp) { + nvicDisableVector(STM32_TIM2_NUMBER); + rccDisableTIM2(FALSE); + } +#endif +#if STM32_TIMCAP_USE_TIM3 + if (&TIMCAPD3 == timcapp) { + nvicDisableVector(STM32_TIM3_NUMBER); + rccDisableTIM3(FALSE); + } +#endif +#if STM32_TIMCAP_USE_TIM4 + if (&TIMCAPD4 == timcapp) { + nvicDisableVector(STM32_TIM4_NUMBER); + rccDisableTIM4(FALSE); + } +#endif +#if STM32_TIMCAP_USE_TIM5 + if (&TIMCAPD5 == timcapp) { + nvicDisableVector(STM32_TIM5_NUMBER); + rccDisableTIM5(FALSE); + } +#endif +#if STM32_TIMCAP_USE_TIM8 + if (&TIMCAPD8 == timcapp) { + nvicDisableVector(STM32_TIM8_UP_NUMBER); + nvicDisableVector(STM32_TIM8_CC_NUMBER); + rccDisableTIM8(FALSE); + } +#endif +#if STM32_TIMCAP_USE_TIM9 + if (&TIMCAPD9 == timcapp) { + nvicDisableVector(STM32_TIM9_NUMBER); + rccDisableTIM9(FALSE); + } +#endif + } +} + +/** + * @brief Enables the input capture. + * + * @param[in] timcapp pointer to the @p TIMCAPDriver object + * + * @notapi + */ +void timcap_lld_enable(TIMCAPDriver *timcapp) { + + timcapp->tim->EGR |= STM32_TIM_EGR_UG; + timcapp->tim->SR = 0; /* Clear pending IRQs (if any). */ + + timcapchannel_t chan = TIMCAP_CHANNEL_1; + const timcapchannel_t tim_max_channel = timcap_get_max_timer_channel(timcapp); + for( chan = TIMCAP_CHANNEL_1; chan <= tim_max_channel; chan++ ) { + if( timcapp->config->capture_cb_array[chan] != NULL + && timcapp->config->modes[chan] != TIMCAP_INPUT_DISABLED ) { + switch (chan) { + case TIMCAP_CHANNEL_1: + timcapp->tim->DIER |= STM32_TIM_DIER_CC1IE; + break; + case TIMCAP_CHANNEL_2: + timcapp->tim->DIER |= STM32_TIM_DIER_CC2IE; + break; + case TIMCAP_CHANNEL_3: + timcapp->tim->DIER |= STM32_TIM_DIER_CC3IE; + break; + case TIMCAP_CHANNEL_4: + timcapp->tim->DIER |= STM32_TIM_DIER_CC4IE; + break; + } + } + } + + if (timcapp->config->overflow_cb != NULL) + timcapp->tim->DIER |= STM32_TIM_DIER_UIE; + + timcapp->tim->CR1 = STM32_TIM_CR1_URS | STM32_TIM_CR1_CEN | timcapp->config->cr1; +} + +/** + * @brief Disables the input capture. + * + * @param[in] timcapp pointer to the @p TIMCAPDriver object + * + * @notapi + */ +void timcap_lld_disable(TIMCAPDriver *timcapp) { + + timcapp->tim->CR1 = 0; /* Initially stopped. */ + timcapp->tim->SR = 0; /* Clear pending IRQs (if any). */ + + /* All interrupts disabled.*/ + timcapp->tim->DIER &= ~STM32_TIM_DIER_IRQ_MASK; +} + +#endif /* HAL_USE_TIMCAP */ + +/** @} */ diff --git a/os/hal/ports/STM32/LLD/TIMv1/hal_timcap_lld.h b/os/hal/ports/STM32/LLD/TIMv1/hal_timcap_lld.h new file mode 100644 index 0000000..d39c438 --- /dev/null +++ b/os/hal/ports/STM32/LLD/TIMv1/hal_timcap_lld.h @@ -0,0 +1,390 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file STM32/timcap_lld.h + * @brief STM32 TIMCAP subsystem low level driver header. + * + * @addtogroup TIMCAP + * @{ + */ + +#ifndef _TIMCAP_LLD_H_ +#define _TIMCAP_LLD_H_ + +#include "ch.h" +#include "hal.h" +#include "stm32_tim.h" + + +#if HAL_USE_TIMCAP || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief TIMCAPD1 driver enable switch. + * @details If set to @p TRUE the support for TIMCAPD1 is included. + * @note The default is @p TRUE. + */ +#if !defined(STM32_TIMCAP_USE_TIM1) || defined(__DOXYGEN__) +#define STM32_TIMCAP_USE_TIM1 FALSE +#endif + +/** + * @brief TIMCAPD2 driver enable switch. + * @details If set to @p TRUE the support for TIMCAPD2 is included. + * @note The default is @p TRUE. + */ +#if !defined(STM32_TIMCAP_USE_TIM2) || defined(__DOXYGEN__) +#define STM32_TIMCAP_USE_TIM2 FALSE +#endif + +/** + * @brief TIMCAPD3 driver enable switch. + * @details If set to @p TRUE the support for TIMCAPD3 is included. + * @note The default is @p TRUE. + */ +#if !defined(STM32_TIMCAP_USE_TIM3) || defined(__DOXYGEN__) +#define STM32_TIMCAP_USE_TIM3 FALSE +#endif + +/** + * @brief TIMCAPD4 driver enable switch. + * @details If set to @p TRUE the support for TIMCAPD4 is included. + * @note The default is @p TRUE. + */ +#if !defined(STM32_TIMCAP_USE_TIM4) || defined(__DOXYGEN__) +#define STM32_TIMCAP_USE_TIM4 FALSE +#endif + +/** + * @brief TIMCAPD5 driver enable switch. + * @details If set to @p TRUE the support for TIMCAPD5 is included. + * @note The default is @p TRUE. + */ +#if !defined(STM32_TIMCAP_USE_TIM5) || defined(__DOXYGEN__) +#define STM32_TIMCAP_USE_TIM5 FALSE +#endif + +/** + * @brief TIMCAPD8 driver enable switch. + * @details If set to @p TRUE the support for TIMCAPD8 is included. + * @note The default is @p TRUE. + */ +#if !defined(STM32_TIMCAP_USE_TIM8) || defined(__DOXYGEN__) +#define STM32_TIMCAP_USE_TIM8 FALSE +#endif + +/** + * @brief TIMCAPD9 driver enable switch. + * @details If set to @p TRUE the support for TIMCAPD9 is included. + * @note The default is @p TRUE. + */ +#if !defined(STM32_TIMCAP_USE_TIM9) || defined(__DOXYGEN__) +#define STM32_TIMCAP_USE_TIM9 FALSE +#endif + +/** + * @brief TIMCAPD1 interrupt priority level setting. + */ +#if !defined(STM32_TIMCAP_TIM1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_TIMCAP_TIM1_IRQ_PRIORITY 7 +#endif + +/** + * @brief TIMCAPD2 interrupt priority level setting. + */ +#if !defined(STM32_TIMCAP_TIM2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_TIMCAP_TIM2_IRQ_PRIORITY 7 +#endif + +/** + * @brief TIMCAPD3 interrupt priority level setting. + */ +#if !defined(STM32_TIMCAP_TIM3_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_TIMCAP_TIM3_IRQ_PRIORITY 7 +#endif + +/** + * @brief TIMCAPD4 interrupt priority level setting. + */ +#if !defined(STM32_TIMCAP_TIM4_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_TIMCAP_TIM4_IRQ_PRIORITY 7 +#endif + +/** + * @brief TIMCAPD5 interrupt priority level setting. + */ +#if !defined(STM32_TIMCAP_TIM5_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_TIMCAP_TIM5_IRQ_PRIORITY 7 +#endif + +/** + * @brief TIMCAPD8 interrupt priority level setting. + */ +#if !defined(STM32_TIMCAP_TIM8_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_TIMCAP_TIM8_IRQ_PRIORITY 7 +#endif + +/** + * @brief TIMCAPD9 interrupt priority level setting. + */ +#if !defined(STM32_TIMCAP_TIM9_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_TIMCAP_TIM9_IRQ_PRIORITY 7 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if STM32_TIMCAP_USE_TIM1 && !STM32_HAS_TIM1 +#error "TIM1 not present in the selected device" +#endif + +#if STM32_TIMCAP_USE_TIM2 && !STM32_HAS_TIM2 +#error "TIM2 not present in the selected device" +#endif + +#if STM32_TIMCAP_USE_TIM3 && !STM32_HAS_TIM3 +#error "TIM3 not present in the selected device" +#endif + +#if STM32_TIMCAP_USE_TIM4 && !STM32_HAS_TIM4 +#error "TIM4 not present in the selected device" +#endif + +#if STM32_TIMCAP_USE_TIM5 && !STM32_HAS_TIM5 +#error "TIM5 not present in the selected device" +#endif + +#if STM32_TIMCAP_USE_TIM8 && !STM32_HAS_TIM8 +#error "TIM8 not present in the selected device" +#endif + +#if STM32_TIMCAP_USE_TIM9 && !STM32_HAS_TIM9 +#error "TIM9 not present in the selected device" +#endif + +#if !STM32_TIMCAP_USE_TIM1 && !STM32_TIMCAP_USE_TIM2 && \ + !STM32_TIMCAP_USE_TIM3 && !STM32_TIMCAP_USE_TIM4 && \ + !STM32_TIMCAP_USE_TIM5 && !STM32_TIMCAP_USE_TIM8 && \ + !STM32_TIMCAP_USE_TIM9 +#error "TIMCAP driver activated but no TIM peripheral assigned" +#endif + +#if STM32_TIMCAP_USE_TIM1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_TIMCAP_TIM1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM1" +#endif + +#if STM32_TIMCAP_USE_TIM2 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_TIMCAP_TIM2_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM2" +#endif + +#if STM32_TIMCAP_USE_TIM3 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_TIMCAP_TIM3_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM3" +#endif + +#if STM32_TIMCAP_USE_TIM4 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_TIMCAP_TIM4_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM4" +#endif + +#if STM32_TIMCAP_USE_TIM5 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_TIMCAP_TIM5_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM5" +#endif + +#if STM32_TIMCAP_USE_TIM8 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_TIMCAP_TIM8_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM8" +#endif + +#if STM32_TIMCAP_USE_TIM9 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_TIMCAP_TIM9_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIM9" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief TIMCAP driver mode. + */ +typedef enum { + TIMCAP_INPUT_DISABLED = 0, + TIMCAP_INPUT_ACTIVE_HIGH = 1, /**< Trigger on rising edge. */ + TIMCAP_INPUT_ACTIVE_LOW = 2, /**< Trigger on falling edge. */ +} timcapmode_t; + +/** + * @brief TIMCAP frequency type. + */ +typedef uint32_t timcapfreq_t; + +/** + * @brief TIMCAP channel type. + */ +typedef enum { + TIMCAP_CHANNEL_1 = 0, /**< Use TIMxCH1. */ + TIMCAP_CHANNEL_2 = 1, /**< Use TIMxCH2. */ + TIMCAP_CHANNEL_3 = 2, /**< Use TIMxCH3. */ + TIMCAP_CHANNEL_4 = 3, /**< Use TIMxCH4. */ +} timcapchannel_t; + + +/** + * @brief Driver configuration structure. + * @note It could be empty on some architectures. + */ +typedef struct { + /** + * @brief Driver mode. + */ + timcapmode_t modes[4]; + /** + * @brief Timer clock in Hz. + * @note The low level can use assertions in order to catch invalid + * frequency specifications. + */ + timcapfreq_t frequency; + + /** + * @brief Callback when a capture occurs + */ + timcapcallback_t capture_cb_array[4]; + + /** + * @brief Callback for timer overflow. + */ + timcapcallback_t overflow_cb; + + /* End of the mandatory fields.*/ + + /** + * @brief TIM DIER register initialization data. + * @note The value of this field should normally be equal to zero. + * @note Only the DMA-related bits can be specified in this field. + */ + uint32_t dier; + + /** + * @brief TIM CR1 register initialization data. + * @note The value of this field should normally be equal to zero. + */ + uint32_t cr1; +} TIMCAPConfig; + +/** + * @brief Structure representing an TIMCAP driver. + */ +struct TIMCAPDriver { + /** + * @brief Driver state. + */ + timcapstate_t state; + /** + * @brief Current configuration data. + */ + const TIMCAPConfig *config; +#if defined(TIMCAP_DRIVER_EXT_FIELDS) + TIMCAP_DRIVER_EXT_FIELDS +#endif + /* End of the mandatory fields.*/ + /** + * @brief Timer base clock. + */ + uint32_t clock; + /** + * @brief Pointer to the TIMx registers block. + */ + stm32_tim_t *tim; + /** + * @brief CCR register used for capture. + */ + volatile uint32_t *ccr_p[4]; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +//FIXME document this +#define timcap_lld_get_ccr(timcapp, channel) (*((timcapp)->ccr_p[channel]) + 1) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_TIMCAP_USE_TIM1 && !defined(__DOXYGEN__) +extern TIMCAPDriver TIMCAPD1; +#endif + +#if STM32_TIMCAP_USE_TIM2 && !defined(__DOXYGEN__) +extern TIMCAPDriver TIMCAPD2; +#endif + +#if STM32_TIMCAP_USE_TIM3 && !defined(__DOXYGEN__) +extern TIMCAPDriver TIMCAPD3; +#endif + +#if STM32_TIMCAP_USE_TIM4 && !defined(__DOXYGEN__) +extern TIMCAPDriver TIMCAPD4; +#endif + +#if STM32_TIMCAP_USE_TIM5 && !defined(__DOXYGEN__) +extern TIMCAPDriver TIMCAPD5; +#endif + +#if STM32_TIMCAP_USE_TIM8 && !defined(__DOXYGEN__) +extern TIMCAPDriver TIMCAPD8; +#endif + +#if STM32_TIMCAP_USE_TIM9 && !defined(__DOXYGEN__) +extern TIMCAPDriver TIMCAPD9; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void timcap_lld_init(void); + void timcap_lld_start(TIMCAPDriver *timcapp); + void timcap_lld_stop(TIMCAPDriver *timcapp); + void timcap_lld_enable(TIMCAPDriver *timcapp); + void timcap_lld_disable(TIMCAPDriver *timcapp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_TIMCAP */ + +#endif /* _TIMCAP_LLD_H_ */ + +/** @} */ diff --git a/os/hal/ports/STM32/LLD/TIMv1/timcap_lld.c b/os/hal/ports/STM32/LLD/TIMv1/timcap_lld.c deleted file mode 100644 index 635e9b2..0000000 --- a/os/hal/ports/STM32/LLD/TIMv1/timcap_lld.c +++ /dev/null @@ -1,818 +0,0 @@ -/* - ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ -/* - This file was derived from the ICU subsystem code, modified to achieve - timing measurements on 2 and/or 4 channel STM32 timers by Dave Camarillo. - */ -/* - Concepts and parts of this file have been contributed by Fabio Utzig and - Xo Wang. - */ - - -/** - * @file STM32/timcap_lld.c - * @brief STM32 TIMCAP subsystem low level driver header. - * - * @addtogroup TIMCAP - * @{ - */ - -#include "ch.h" -#include "hal.h" - -#if HAL_USE_TIMCAP || defined(__DOXYGEN__) - -#include "stm32_tim.h" -#include "timcap.h" - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/** - * @brief TIMCAPD1 driver identifier. - * @note The driver TIMCAPD1 allocates the complex timer TIM1 when enabled. - */ -#if STM32_TIMCAP_USE_TIM1 || defined(__DOXYGEN__) -TIMCAPDriver TIMCAPD1; -#endif - -/** - * @brief TIMCAPD2 driver identifier. - * @note The driver TIMCAPD1 allocates the timer TIM2 when enabled. - */ -#if STM32_TIMCAP_USE_TIM2 || defined(__DOXYGEN__) -TIMCAPDriver TIMCAPD2; -#endif - -/** - * @brief TIMCAPD3 driver identifier. - * @note The driver TIMCAPD1 allocates the timer TIM3 when enabled. - */ -#if STM32_TIMCAP_USE_TIM3 || defined(__DOXYGEN__) -TIMCAPDriver TIMCAPD3; -#endif - -/** - * @brief TIMCAPD4 driver identifier. - * @note The driver TIMCAPD4 allocates the timer TIM4 when enabled. - */ -#if STM32_TIMCAP_USE_TIM4 || defined(__DOXYGEN__) -TIMCAPDriver TIMCAPD4; -#endif - -/** - * @brief TIMCAPD5 driver identifier. - * @note The driver TIMCAPD5 allocates the timer TIM5 when enabled. - */ -#if STM32_TIMCAP_USE_TIM5 || defined(__DOXYGEN__) -TIMCAPDriver TIMCAPD5; -#endif - -/** - * @brief TIMCAPD8 driver identifier. - * @note The driver TIMCAPD8 allocates the timer TIM8 when enabled. - */ -#if STM32_TIMCAP_USE_TIM8 || defined(__DOXYGEN__) -TIMCAPDriver TIMCAPD8; -#endif - -/** - * @brief TIMCAPD9 driver identifier. - * @note The driver TIMCAPD9 allocates the timer TIM9 when enabled. - */ -#if STM32_TIMCAP_USE_TIM9 || defined(__DOXYGEN__) -TIMCAPDriver TIMCAPD9; -#endif - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - - -/** - * @brief Returns the maximum channel number for the respective TIMCAP driver. - * Note: different timer perepherials on the STM32 have between 1 and 4 - * CCR registers. - * - * @param[in] timcapp pointer to the @p TIMCAPDriver object - */ -static timcapchannel_t timcap_get_max_timer_channel(const TIMCAPDriver *timcapp) { - //Choose a sane default value -#if STM32_TIMCAP_USE_TIM1 || defined(__DOXYGEN__) - if( timcapp == &TIMCAPD1 ) { - return(TIMCAP_CHANNEL_4); - } -#endif - -#if STM32_TIMCAP_USE_TIM2 || defined(__DOXYGEN__) - if( timcapp == &TIMCAPD2 ) { - return(TIMCAP_CHANNEL_4); - } -#endif - -#if STM32_TIMCAP_USE_TIM3 || defined(__DOXYGEN__) - if( timcapp == &TIMCAPD3 ) { - return(TIMCAP_CHANNEL_4); - } -#endif - -#if STM32_TIMCAP_USE_TIM4 || defined(__DOXYGEN__) - if( timcapp == &TIMCAPD4 ) { - return(TIMCAP_CHANNEL_4); - } -#endif - -#if STM32_TIMCAP_USE_TIM5 || defined(__DOXYGEN__) - if( timcapp == &TIMCAPD5 ) { - return(TIMCAP_CHANNEL_4); - } -#endif - -#if STM32_TIMCAP_USE_TIM8 || defined(__DOXYGEN__) - if( timcapp == &TIMCAPD8 ) { - return(TIMCAP_CHANNEL_4); - } -#endif - -#if STM32_TIMCAP_USE_TIM9 || defined(__DOXYGEN__) - if( timcapp == &TIMCAPD9 ) { - return(TIMCAP_CHANNEL_2); - } -#endif - - /*Return a conservative default value.*/ - return(TIMCAP_CHANNEL_1); -} - - -/** - * @brief Returns the maximum value for the ARR register of a given timer. - * - * @param[in] timcapp pointer to the @p TIMCAPDriver object - */ -static uint32_t timcap_get_max_arr(const TIMCAPDriver *timcapp) { - //Choose a sane default value -#if STM32_TIMCAP_USE_TIM1 || defined(__DOXYGEN__) - if( timcapp == &TIMCAPD1 ) { - return(UINT16_MAX); - } -#endif - -#if STM32_TIMCAP_USE_TIM2 || defined(__DOXYGEN__) - if( timcapp == &TIMCAPD2 ) { - return(UINT32_MAX); - } -#endif - -#if STM32_TIMCAP_USE_TIM3 || defined(__DOXYGEN__) - if( timcapp == &TIMCAPD3 ) { - return(UINT16_MAX); - } -#endif - -#if STM32_TIMCAP_USE_TIM4 || defined(__DOXYGEN__) - if( timcapp == &TIMCAPD4 ) { - return(UINT16_MAX); - } -#endif - -#if STM32_TIMCAP_USE_TIM5 || defined(__DOXYGEN__) - if( timcapp == &TIMCAPD5 ) { - return(UINT32_MAX); - } -#endif - -#if STM32_TIMCAP_USE_TIM8 || defined(__DOXYGEN__) - if( timcapp == &TIMCAPD8 ) { - return(UINT16_MAX); - } -#endif - -#if STM32_TIMCAP_USE_TIM9 || defined(__DOXYGEN__) - if( timcapp == &TIMCAPD9 ) { - return(UINT16_MAX); - } -#endif - - /*Return a conservative default value.*/ - return(UINT16_MAX); -} - -/** - * @brief Shared IRQ handler. - * - * @param[in] timcapp pointer to the @p TIMCAPDriver object - */ -static void timcap_lld_serve_interrupt(TIMCAPDriver *timcapp) { - uint16_t sr; - - sr = timcapp->tim->SR; - sr &= timcapp->tim->DIER & STM32_TIM_DIER_IRQ_MASK; - timcapp->tim->SR = ~sr; - - if ((sr & STM32_TIM_SR_CC1IF) != 0 && timcapp->config->capture_cb_array[TIMCAP_CHANNEL_1] != NULL ) - _timcap_isr_invoke_channel1_cb(timcapp); - - if ((sr & STM32_TIM_SR_CC2IF) != 0 && timcapp->config->capture_cb_array[TIMCAP_CHANNEL_2] != NULL ) - _timcap_isr_invoke_channel2_cb(timcapp); - - if ((sr & STM32_TIM_SR_CC3IF) != 0 && timcapp->config->capture_cb_array[TIMCAP_CHANNEL_3] != NULL ) - _timcap_isr_invoke_channel3_cb(timcapp); - - if ((sr & STM32_TIM_SR_CC4IF) != 0 && timcapp->config->capture_cb_array[TIMCAP_CHANNEL_4] != NULL ) - _timcap_isr_invoke_channel4_cb(timcapp); - - if ((sr & STM32_TIM_SR_UIF) != 0 && timcapp->config->overflow_cb != NULL) - _timcap_isr_invoke_overflow_cb(timcapp); -} - -/*===========================================================================*/ -/* Driver interrupt handlers. */ -/*===========================================================================*/ - -#if STM32_TIMCAP_USE_TIM1 -#if !defined(STM32_TIM1_UP_HANDLER) -#error "STM32_TIM1_UP_HANDLER not defined" -#endif -/** - * @brief TIM1 compare interrupt handler. - * @note It is assumed that the various sources are only activated if the - * associated callback pointer is not equal to @p NULL in order to not - * perform an extra check in a potentially critical interrupt handler. - * - * @isr - */ -CH_IRQ_HANDLER(STM32_TIM1_UP_HANDLER) { - - CH_IRQ_PROLOGUE(); - - timcap_lld_serve_interrupt(&TIMCAPD1); - - CH_IRQ_EPILOGUE(); -} - -#if !defined(STM32_TIM1_CC_HANDLER) -#error "STM32_TIM1_CC_HANDLER not defined" -#endif -/** - * @brief TIM1 compare interrupt handler. - * @note It is assumed that the various sources are only activated if the - * associated callback pointer is not equal to @p NULL in order to not - * perform an extra check in a potentially critical interrupt handler. - * - * @isr - */ -CH_IRQ_HANDLER(STM32_TIM1_CC_HANDLER) { - - CH_IRQ_PROLOGUE(); - - timcap_lld_serve_interrupt(&TIMCAPD1); - - CH_IRQ_EPILOGUE(); -} -#endif /* STM32_TIMCAP_USE_TIM1 */ - -#if STM32_TIMCAP_USE_TIM2 -#if !defined(STM32_TIM2_HANDLER) -#error "STM32_TIM2_HANDLER not defined" -#endif -/** - * @brief TIM2 interrupt handler. - * @note It is assumed that the various sources are only activated if the - * associated callback pointer is not equal to @p NULL in order to not - * perform an extra check in a potentially critical interrupt handler. - * - * @isr - */ -CH_IRQ_HANDLER(STM32_TIM2_HANDLER) { - - CH_IRQ_PROLOGUE(); - - timcap_lld_serve_interrupt(&TIMCAPD2); - - CH_IRQ_EPILOGUE(); -} -#endif /* STM32_TIMCAP_USE_TIM2 */ - -#if STM32_TIMCAP_USE_TIM3 -#if !defined(STM32_TIM3_HANDLER) -#error "STM32_TIM3_HANDLER not defined" -#endif -/** - * @brief TIM3 interrupt handler. - * @note It is assumed that the various sources are only activated if the - * associated callback pointer is not equal to @p NULL in order to not - * perform an extra check in a potentially critical interrupt handler. - * - * @isr - */ -CH_IRQ_HANDLER(STM32_TIM3_HANDLER) { - - CH_IRQ_PROLOGUE(); - - timcap_lld_serve_interrupt(&TIMCAPD3); - - CH_IRQ_EPILOGUE(); -} -#endif /* STM32_TIMCAP_USE_TIM3 */ - -#if STM32_TIMCAP_USE_TIM4 -#if !defined(STM32_TIM4_HANDLER) -#error "STM32_TIM4_HANDLER not defined" -#endif -/** - * @brief TIM4 interrupt handler. - * @note It is assumed that the various sources are only activated if the - * associated callback pointer is not equal to @p NULL in order to not - * perform an extra check in a potentially critical interrupt handler. - * - * @isr - */ -CH_IRQ_HANDLER(STM32_TIM4_HANDLER) { - - CH_IRQ_PROLOGUE(); - - timcap_lld_serve_interrupt(&TIMCAPD4); - - CH_IRQ_EPILOGUE(); -} -#endif /* STM32_TIMCAP_USE_TIM4 */ - -#if STM32_TIMCAP_USE_TIM5 -#if !defined(STM32_TIM5_HANDLER) -#error "STM32_TIM5_HANDLER not defined" -#endif -/** - * @brief TIM5 interrupt handler. - * @note It is assumed that the various sources are only activated if the - * associated callback pointer is not equal to @p NULL in order to not - * perform an extra check in a potentially critical interrupt handler. - * - * @isr - */ -CH_IRQ_HANDLER(STM32_TIM5_HANDLER) { - - CH_IRQ_PROLOGUE(); - - timcap_lld_serve_interrupt(&TIMCAPD5); - - CH_IRQ_EPILOGUE(); -} -#endif /* STM32_TIMCAP_USE_TIM5 */ - -#if STM32_TIMCAP_USE_TIM8 -#if !defined(STM32_TIM8_UP_HANDLER) -#error "STM32_TIM8_UP_HANDLER not defined" -#endif -/** - * @brief TIM8 compare interrupt handler. - * @note It is assumed that the various sources are only activated if the - * associated callback pointer is not equal to @p NULL in order to not - * perform an extra check in a potentially critical interrupt handler. - * - * @isr - */ -CH_IRQ_HANDLER(STM32_TIM8_UP_HANDLER) { - - CH_IRQ_PROLOGUE(); - - timcap_lld_serve_interrupt(&TIMCAPD8); - - CH_IRQ_EPILOGUE(); -} - -#if !defined(STM32_TIM8_CC_HANDLER) -#error "STM32_TIM8_CC_HANDLER not defined" -#endif -/** - * @brief TIM8 compare interrupt handler. - * @note It is assumed that the various sources are only activated if the - * associated callback pointer is not equal to @p NULL in order to not - * perform an extra check in a potentially critical interrupt handler. - * - * @isr - */ -CH_IRQ_HANDLER(STM32_TIM8_CC_HANDLER) { - - CH_IRQ_PROLOGUE(); - - timcap_lld_serve_interrupt(&TIMCAPD8); - - CH_IRQ_EPILOGUE(); -} -#endif /* STM32_TIMCAP_USE_TIM8 */ - -#if STM32_TIMCAP_USE_TIM9 -#if !defined(STM32_TIM9_HANDLER) -#error "STM32_TIM9_HANDLER not defined" -#endif -/** - * @brief TIM9 interrupt handler. - * @note It is assumed that the various sources are only activated if the - * associated callback pointer is not equal to @p NULL in order to not - * perform an extra check in a potentially critical interrupt handler. - * - * @isr - */ -CH_IRQ_HANDLER(STM32_TIM9_HANDLER) { - - CH_IRQ_PROLOGUE(); - - timcap_lld_serve_interrupt(&TIMCAPD9); - - CH_IRQ_EPILOGUE(); -} -#endif /* STM32_TIMCAP_USE_TIM9 */ - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief Low level TIMCAP driver initialization. - * - * @notapi - */ -void timcap_lld_init(void) { - -#if STM32_TIMCAP_USE_TIM1 - /* Driver initialization.*/ - timcapObjectInit(&TIMCAPD1); - TIMCAPD1.tim = STM32_TIM1; -#endif - -#if STM32_TIMCAP_USE_TIM2 - /* Driver initialization.*/ - timcapObjectInit(&TIMCAPD2); - TIMCAPD2.tim = STM32_TIM2; -#endif - -#if STM32_TIMCAP_USE_TIM3 - /* Driver initialization.*/ - timcapObjectInit(&TIMCAPD3); - TIMCAPD3.tim = STM32_TIM3; -#endif - -#if STM32_TIMCAP_USE_TIM4 - /* Driver initialization.*/ - timcapObjectInit(&TIMCAPD4); - TIMCAPD4.tim = STM32_TIM4; -#endif - -#if STM32_TIMCAP_USE_TIM5 - /* Driver initialization.*/ - timcapObjectInit(&TIMCAPD5); - TIMCAPD5.tim = STM32_TIM5; -#endif - -#if STM32_TIMCAP_USE_TIM8 - /* Driver initialization.*/ - timcapObjectInit(&TIMCAPD8); - TIMCAPD8.tim = STM32_TIM8; -#endif - -#if STM32_TIMCAP_USE_TIM9 - /* Driver initialization.*/ - timcapObjectInit(&TIMCAPD9); - TIMCAPD9.tim = STM32_TIM9; -#endif -} - -/** - * @brief Configures and activates the TIMCAP peripheral. - * - * @param[in] timcapp pointer to the @p TIMCAPDriver object - * - * @notapi - */ -void timcap_lld_start(TIMCAPDriver *timcapp) { - uint32_t psc; - - const timcapchannel_t tim_max_channel = timcap_get_max_timer_channel(timcapp); - - if (timcapp->state == TIMCAP_STOP) { - /* Clock activation and timer reset.*/ -#if STM32_TIMCAP_USE_TIM1 - if (&TIMCAPD1 == timcapp) { - rccEnableTIM1(FALSE); - rccResetTIM1(); - nvicEnableVector(STM32_TIM1_UP_NUMBER, STM32_TIMCAP_TIM1_IRQ_PRIORITY); - nvicEnableVector(STM32_TIM1_CC_NUMBER, STM32_TIMCAP_TIM1_IRQ_PRIORITY); -#if defined(STM32_TIM1CLK) - timcapp->clock = STM32_TIM1CLK; -#else - timcapp->clock = STM32_TIMCLK2; -#endif - } -#endif -#if STM32_TIMCAP_USE_TIM2 - if (&TIMCAPD2 == timcapp) { - rccEnableTIM2(FALSE); - rccResetTIM2(); - nvicEnableVector(STM32_TIM2_NUMBER, STM32_TIMCAP_TIM2_IRQ_PRIORITY); - timcapp->clock = STM32_TIMCLK1; - } -#endif -#if STM32_TIMCAP_USE_TIM3 - if (&TIMCAPD3 == timcapp) { - rccEnableTIM3(FALSE); - rccResetTIM3(); - nvicEnableVector(STM32_TIM3_NUMBER, STM32_TIMCAP_TIM3_IRQ_PRIORITY); - timcapp->clock = STM32_TIMCLK1; - } -#endif -#if STM32_TIMCAP_USE_TIM4 - if (&TIMCAPD4 == timcapp) { - rccEnableTIM4(FALSE); - rccResetTIM4(); - nvicEnableVector(STM32_TIM4_NUMBER, STM32_TIMCAP_TIM4_IRQ_PRIORITY); - timcapp->clock = STM32_TIMCLK1; - } -#endif -#if STM32_TIMCAP_USE_TIM5 - if (&TIMCAPD5 == timcapp) { - rccEnableTIM5(FALSE); - rccResetTIM5(); - nvicEnableVector(STM32_TIM5_NUMBER, STM32_TIMCAP_TIM5_IRQ_PRIORITY); - timcapp->clock = STM32_TIMCLK1; - } -#endif -#if STM32_TIMCAP_USE_TIM8 - if (&TIMCAPD8 == timcapp) { - rccEnableTIM8(FALSE); - rccResetTIM8(); - nvicEnableVector(STM32_TIM8_UP_NUMBER, STM32_TIMCAP_TIM8_IRQ_PRIORITY); - nvicEnableVector(STM32_TIM8_CC_NUMBER, STM32_TIMCAP_TIM8_IRQ_PRIORITY); -#if defined(STM32_TIM8CLK) - timcapp->clock = STM32_TIM8CLK; -#else - timcapp->clock = STM32_TIMCLK2; -#endif - } -#endif -#if STM32_TIMCAP_USE_TIM9 - if (&TIMCAPD9 == timcapp) { - rccEnableTIM9(FALSE); - rccResetTIM9(); - nvicEnableVector(STM32_TIM9_NUMBER, STM32_TIMCAP_TIM9_IRQ_PRIORITY); - timcapp->clock = STM32_TIMCLK1; - } -#endif - } - else { - /* Driver re-configuration scenario, it must be stopped first.*/ - timcapp->tim->CR1 = 0; /* Timer disabled. */ - timcapp->tim->DIER = timcapp->config->dier &/* DMA-related DIER settings. */ - ~STM32_TIM_DIER_IRQ_MASK; - timcapp->tim->SR = 0; /* Clear eventual pending IRQs. */ - timcapp->tim->CCR[0] = 0; /* Comparator 1 disabled. */ - timcapp->tim->CCR[1] = 0; /* Comparator 2 disabled. */ - if( tim_max_channel >= TIMCAP_CHANNEL_3 ) - timcapp->tim->CCR[2] = 0; /* Comparator 3 disabled. */ - if( tim_max_channel >= TIMCAP_CHANNEL_4 ) - timcapp->tim->CCR[3] = 0; /* Comparator 4 disabled. */ - timcapp->tim->CNT = 0; /* Counter reset to zero. */ - } - - /* Timer configuration.*/ - psc = (timcapp->clock / timcapp->config->frequency) - 1; - osalDbgAssert((psc <= 0xFFFF) && - ((psc + 1) * timcapp->config->frequency) == timcapp->clock, - "invalid frequency"); - timcapp->tim->PSC = (uint16_t)psc; - timcapp->tim->ARR = timcap_get_max_arr(timcapp); - - timcapp->tim->CCMR1 = 0; - timcapp->tim->CCMR2 = 0; - timcapp->tim->CCER = 0; - - timcapchannel_t chan = TIMCAP_CHANNEL_1; - - /*go through each non-NULL callback channel and enable the capture register on rising/falling edge*/ - for( chan = TIMCAP_CHANNEL_1; chan <= tim_max_channel; chan++ ) { - if( timcapp->config->capture_cb_array[chan] == NULL ) { - continue; - } - - switch (chan) { - case TIMCAP_CHANNEL_1: - /*CCMR1_CC1S = 01 = CH1 Input on TI1.*/ - timcapp->tim->CCMR1 |= STM32_TIM_CCMR1_CC1S(1); - break; - case TIMCAP_CHANNEL_2: - /*CCMR1_CC2S = 10 = CH2 Input on TI1.*/ - timcapp->tim->CCMR1 |= STM32_TIM_CCMR1_CC2S(1); - break; - case TIMCAP_CHANNEL_3: - timcapp->tim->CCMR2 |= STM32_TIM_CCMR2_CC3S(1); - break; - case TIMCAP_CHANNEL_4: - timcapp->tim->CCMR2 |= STM32_TIM_CCMR2_CC4S(1); - break; - } - - /* The CCER settings depend on the selected trigger mode. - TIMCAP_INPUT_DISABLED: Input not used. - TIMCAP_INPUT_ACTIVE_HIGH: Active on rising edge, idle on falling edge. - TIMCAP_INPUT_ACTIVE_LOW: Active on falling edge, idle on rising edge.*/ - if (timcapp->config->modes[chan] == TIMCAP_INPUT_ACTIVE_HIGH) { - switch (chan) { - case TIMCAP_CHANNEL_1: - timcapp->tim->CCER |= STM32_TIM_CCER_CC1E; - break; - case TIMCAP_CHANNEL_2: - timcapp->tim->CCER |= STM32_TIM_CCER_CC2E; - break; - case TIMCAP_CHANNEL_3: - timcapp->tim->CCER |= STM32_TIM_CCER_CC3E; - break; - case TIMCAP_CHANNEL_4: - timcapp->tim->CCER |= STM32_TIM_CCER_CC4E; - break; - } - } - else if (timcapp->config->modes[chan] == TIMCAP_INPUT_ACTIVE_LOW) { - switch (chan) { - case TIMCAP_CHANNEL_1: - timcapp->tim->CCER |= STM32_TIM_CCER_CC1E | STM32_TIM_CCER_CC1P; - break; - case TIMCAP_CHANNEL_2: - timcapp->tim->CCER |= STM32_TIM_CCER_CC2E | STM32_TIM_CCER_CC2P; - break; - case TIMCAP_CHANNEL_3: - timcapp->tim->CCER |= STM32_TIM_CCER_CC3E | STM32_TIM_CCER_CC3P; - break; - case TIMCAP_CHANNEL_4: - timcapp->tim->CCER |= STM32_TIM_CCER_CC4E | STM32_TIM_CCER_CC4P; - break; - } - } - else { - switch (chan) { - case TIMCAP_CHANNEL_1: - timcapp->tim->CCER &= ~STM32_TIM_CCER_CC1E; - break; - case TIMCAP_CHANNEL_2: - timcapp->tim->CCER &= ~STM32_TIM_CCER_CC2E; - break; - case TIMCAP_CHANNEL_3: - timcapp->tim->CCER &= ~STM32_TIM_CCER_CC3E; - break; - case TIMCAP_CHANNEL_4: - timcapp->tim->CCER &= ~STM32_TIM_CCER_CC4E; - break; - } - } - /* Direct pointers to the capture registers in order to make reading - data faster from within callbacks.*/ - timcapp->ccr_p[chan] = &timcapp->tim->CCR[chan]; - } - - /* SMCR_TS = 101, input is TI1FP1.*/ - timcapp->tim->SMCR = STM32_TIM_SMCR_TS(5); -} - -/** - * @brief Deactivates the TIMCAP peripheral. - * - * @param[in] timcapp pointer to the @p TIMCAPDriver object - * - * @notapi - */ -void timcap_lld_stop(TIMCAPDriver *timcapp) { - - if (timcapp->state == TIMCAP_READY) { - /* Clock deactivation.*/ - timcapp->tim->CR1 = 0; /* Timer disabled. */ - timcapp->tim->DIER = 0; /* All IRQs disabled. */ - timcapp->tim->SR = 0; /* Clear eventual pending IRQs. */ - -#if STM32_TIMCAP_USE_TIM1 - if (&TIMCAPD1 == timcapp) { - nvicDisableVector(STM32_TIM1_UP_NUMBER); - nvicDisableVector(STM32_TIM1_CC_NUMBER); - rccDisableTIM1(FALSE); - } -#endif -#if STM32_TIMCAP_USE_TIM2 - if (&TIMCAPD2 == timcapp) { - nvicDisableVector(STM32_TIM2_NUMBER); - rccDisableTIM2(FALSE); - } -#endif -#if STM32_TIMCAP_USE_TIM3 - if (&TIMCAPD3 == timcapp) { - nvicDisableVector(STM32_TIM3_NUMBER); - rccDisableTIM3(FALSE); - } -#endif -#if STM32_TIMCAP_USE_TIM4 - if (&TIMCAPD4 == timcapp) { - nvicDisableVector(STM32_TIM4_NUMBER); - rccDisableTIM4(FALSE); - } -#endif -#if STM32_TIMCAP_USE_TIM5 - if (&TIMCAPD5 == timcapp) { - nvicDisableVector(STM32_TIM5_NUMBER); - rccDisableTIM5(FALSE); - } -#endif -#if STM32_TIMCAP_USE_TIM8 - if (&TIMCAPD8 == timcapp) { - nvicDisableVector(STM32_TIM8_UP_NUMBER); - nvicDisableVector(STM32_TIM8_CC_NUMBER); - rccDisableTIM8(FALSE); - } -#endif -#if STM32_TIMCAP_USE_TIM9 - if (&TIMCAPD9 == timcapp) { - nvicDisableVector(STM32_TIM9_NUMBER); - rccDisableTIM9(FALSE); - } -#endif - } -} - -/** - * @brief Enables the input capture. - * - * @param[in] timcapp pointer to the @p TIMCAPDriver object - * - * @notapi - */ -void timcap_lld_enable(TIMCAPDriver *timcapp) { - - timcapp->tim->EGR |= STM32_TIM_EGR_UG; - timcapp->tim->SR = 0; /* Clear pending IRQs (if any). */ - - timcapchannel_t chan = TIMCAP_CHANNEL_1; - const timcapchannel_t tim_max_channel = timcap_get_max_timer_channel(timcapp); - for( chan = TIMCAP_CHANNEL_1; chan <= tim_max_channel; chan++ ) { - if( timcapp->config->capture_cb_array[chan] != NULL - && timcapp->config->modes[chan] != TIMCAP_INPUT_DISABLED ) { - switch (chan) { - case TIMCAP_CHANNEL_1: - timcapp->tim->DIER |= STM32_TIM_DIER_CC1IE; - break; - case TIMCAP_CHANNEL_2: - timcapp->tim->DIER |= STM32_TIM_DIER_CC2IE; - break; - case TIMCAP_CHANNEL_3: - timcapp->tim->DIER |= STM32_TIM_DIER_CC3IE; - break; - case TIMCAP_CHANNEL_4: - timcapp->tim->DIER |= STM32_TIM_DIER_CC4IE; - break; - } - } - } - - if (timcapp->config->overflow_cb != NULL) - timcapp->tim->DIER |= STM32_TIM_DIER_UIE; - - timcapp->tim->CR1 = STM32_TIM_CR1_URS | STM32_TIM_CR1_CEN | timcapp->config->cr1; -} - -/** - * @brief Disables the input capture. - * - * @param[in] timcapp pointer to the @p TIMCAPDriver object - * - * @notapi - */ -void timcap_lld_disable(TIMCAPDriver *timcapp) { - - timcapp->tim->CR1 = 0; /* Initially stopped. */ - timcapp->tim->SR = 0; /* Clear pending IRQs (if any). */ - - /* All interrupts disabled.*/ - timcapp->tim->DIER &= ~STM32_TIM_DIER_IRQ_MASK; -} - -#endif /* HAL_USE_TIMCAP */ - -/** @} */ diff --git a/os/hal/ports/STM32/LLD/TIMv1/timcap_lld.h b/os/hal/ports/STM32/LLD/TIMv1/timcap_lld.h deleted file mode 100644 index d39c438..0000000 --- a/os/hal/ports/STM32/LLD/TIMv1/timcap_lld.h +++ /dev/null @@ -1,390 +0,0 @@ -/* - ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -/** - * @file STM32/timcap_lld.h - * @brief STM32 TIMCAP subsystem low level driver header. - * - * @addtogroup TIMCAP - * @{ - */ - -#ifndef _TIMCAP_LLD_H_ -#define _TIMCAP_LLD_H_ - -#include "ch.h" -#include "hal.h" -#include "stm32_tim.h" - - -#if HAL_USE_TIMCAP || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver constants. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver pre-compile time settings. */ -/*===========================================================================*/ - -/** - * @name Configuration options - * @{ - */ -/** - * @brief TIMCAPD1 driver enable switch. - * @details If set to @p TRUE the support for TIMCAPD1 is included. - * @note The default is @p TRUE. - */ -#if !defined(STM32_TIMCAP_USE_TIM1) || defined(__DOXYGEN__) -#define STM32_TIMCAP_USE_TIM1 FALSE -#endif - -/** - * @brief TIMCAPD2 driver enable switch. - * @details If set to @p TRUE the support for TIMCAPD2 is included. - * @note The default is @p TRUE. - */ -#if !defined(STM32_TIMCAP_USE_TIM2) || defined(__DOXYGEN__) -#define STM32_TIMCAP_USE_TIM2 FALSE -#endif - -/** - * @brief TIMCAPD3 driver enable switch. - * @details If set to @p TRUE the support for TIMCAPD3 is included. - * @note The default is @p TRUE. - */ -#if !defined(STM32_TIMCAP_USE_TIM3) || defined(__DOXYGEN__) -#define STM32_TIMCAP_USE_TIM3 FALSE -#endif - -/** - * @brief TIMCAPD4 driver enable switch. - * @details If set to @p TRUE the support for TIMCAPD4 is included. - * @note The default is @p TRUE. - */ -#if !defined(STM32_TIMCAP_USE_TIM4) || defined(__DOXYGEN__) -#define STM32_TIMCAP_USE_TIM4 FALSE -#endif - -/** - * @brief TIMCAPD5 driver enable switch. - * @details If set to @p TRUE the support for TIMCAPD5 is included. - * @note The default is @p TRUE. - */ -#if !defined(STM32_TIMCAP_USE_TIM5) || defined(__DOXYGEN__) -#define STM32_TIMCAP_USE_TIM5 FALSE -#endif - -/** - * @brief TIMCAPD8 driver enable switch. - * @details If set to @p TRUE the support for TIMCAPD8 is included. - * @note The default is @p TRUE. - */ -#if !defined(STM32_TIMCAP_USE_TIM8) || defined(__DOXYGEN__) -#define STM32_TIMCAP_USE_TIM8 FALSE -#endif - -/** - * @brief TIMCAPD9 driver enable switch. - * @details If set to @p TRUE the support for TIMCAPD9 is included. - * @note The default is @p TRUE. - */ -#if !defined(STM32_TIMCAP_USE_TIM9) || defined(__DOXYGEN__) -#define STM32_TIMCAP_USE_TIM9 FALSE -#endif - -/** - * @brief TIMCAPD1 interrupt priority level setting. - */ -#if !defined(STM32_TIMCAP_TIM1_IRQ_PRIORITY) || defined(__DOXYGEN__) -#define STM32_TIMCAP_TIM1_IRQ_PRIORITY 7 -#endif - -/** - * @brief TIMCAPD2 interrupt priority level setting. - */ -#if !defined(STM32_TIMCAP_TIM2_IRQ_PRIORITY) || defined(__DOXYGEN__) -#define STM32_TIMCAP_TIM2_IRQ_PRIORITY 7 -#endif - -/** - * @brief TIMCAPD3 interrupt priority level setting. - */ -#if !defined(STM32_TIMCAP_TIM3_IRQ_PRIORITY) || defined(__DOXYGEN__) -#define STM32_TIMCAP_TIM3_IRQ_PRIORITY 7 -#endif - -/** - * @brief TIMCAPD4 interrupt priority level setting. - */ -#if !defined(STM32_TIMCAP_TIM4_IRQ_PRIORITY) || defined(__DOXYGEN__) -#define STM32_TIMCAP_TIM4_IRQ_PRIORITY 7 -#endif - -/** - * @brief TIMCAPD5 interrupt priority level setting. - */ -#if !defined(STM32_TIMCAP_TIM5_IRQ_PRIORITY) || defined(__DOXYGEN__) -#define STM32_TIMCAP_TIM5_IRQ_PRIORITY 7 -#endif - -/** - * @brief TIMCAPD8 interrupt priority level setting. - */ -#if !defined(STM32_TIMCAP_TIM8_IRQ_PRIORITY) || defined(__DOXYGEN__) -#define STM32_TIMCAP_TIM8_IRQ_PRIORITY 7 -#endif - -/** - * @brief TIMCAPD9 interrupt priority level setting. - */ -#if !defined(STM32_TIMCAP_TIM9_IRQ_PRIORITY) || defined(__DOXYGEN__) -#define STM32_TIMCAP_TIM9_IRQ_PRIORITY 7 -#endif -/** @} */ - -/*===========================================================================*/ -/* Derived constants and error checks. */ -/*===========================================================================*/ - -#if STM32_TIMCAP_USE_TIM1 && !STM32_HAS_TIM1 -#error "TIM1 not present in the selected device" -#endif - -#if STM32_TIMCAP_USE_TIM2 && !STM32_HAS_TIM2 -#error "TIM2 not present in the selected device" -#endif - -#if STM32_TIMCAP_USE_TIM3 && !STM32_HAS_TIM3 -#error "TIM3 not present in the selected device" -#endif - -#if STM32_TIMCAP_USE_TIM4 && !STM32_HAS_TIM4 -#error "TIM4 not present in the selected device" -#endif - -#if STM32_TIMCAP_USE_TIM5 && !STM32_HAS_TIM5 -#error "TIM5 not present in the selected device" -#endif - -#if STM32_TIMCAP_USE_TIM8 && !STM32_HAS_TIM8 -#error "TIM8 not present in the selected device" -#endif - -#if STM32_TIMCAP_USE_TIM9 && !STM32_HAS_TIM9 -#error "TIM9 not present in the selected device" -#endif - -#if !STM32_TIMCAP_USE_TIM1 && !STM32_TIMCAP_USE_TIM2 && \ - !STM32_TIMCAP_USE_TIM3 && !STM32_TIMCAP_USE_TIM4 && \ - !STM32_TIMCAP_USE_TIM5 && !STM32_TIMCAP_USE_TIM8 && \ - !STM32_TIMCAP_USE_TIM9 -#error "TIMCAP driver activated but no TIM peripheral assigned" -#endif - -#if STM32_TIMCAP_USE_TIM1 && \ - !OSAL_IRQ_IS_VALID_PRIORITY(STM32_TIMCAP_TIM1_IRQ_PRIORITY) -#error "Invalid IRQ priority assigned to TIM1" -#endif - -#if STM32_TIMCAP_USE_TIM2 && \ - !OSAL_IRQ_IS_VALID_PRIORITY(STM32_TIMCAP_TIM2_IRQ_PRIORITY) -#error "Invalid IRQ priority assigned to TIM2" -#endif - -#if STM32_TIMCAP_USE_TIM3 && \ - !OSAL_IRQ_IS_VALID_PRIORITY(STM32_TIMCAP_TIM3_IRQ_PRIORITY) -#error "Invalid IRQ priority assigned to TIM3" -#endif - -#if STM32_TIMCAP_USE_TIM4 && \ - !OSAL_IRQ_IS_VALID_PRIORITY(STM32_TIMCAP_TIM4_IRQ_PRIORITY) -#error "Invalid IRQ priority assigned to TIM4" -#endif - -#if STM32_TIMCAP_USE_TIM5 && \ - !OSAL_IRQ_IS_VALID_PRIORITY(STM32_TIMCAP_TIM5_IRQ_PRIORITY) -#error "Invalid IRQ priority assigned to TIM5" -#endif - -#if STM32_TIMCAP_USE_TIM8 && \ - !OSAL_IRQ_IS_VALID_PRIORITY(STM32_TIMCAP_TIM8_IRQ_PRIORITY) -#error "Invalid IRQ priority assigned to TIM8" -#endif - -#if STM32_TIMCAP_USE_TIM9 && \ - !OSAL_IRQ_IS_VALID_PRIORITY(STM32_TIMCAP_TIM9_IRQ_PRIORITY) -#error "Invalid IRQ priority assigned to TIM9" -#endif - -/*===========================================================================*/ -/* Driver data structures and types. */ -/*===========================================================================*/ - -/** - * @brief TIMCAP driver mode. - */ -typedef enum { - TIMCAP_INPUT_DISABLED = 0, - TIMCAP_INPUT_ACTIVE_HIGH = 1, /**< Trigger on rising edge. */ - TIMCAP_INPUT_ACTIVE_LOW = 2, /**< Trigger on falling edge. */ -} timcapmode_t; - -/** - * @brief TIMCAP frequency type. - */ -typedef uint32_t timcapfreq_t; - -/** - * @brief TIMCAP channel type. - */ -typedef enum { - TIMCAP_CHANNEL_1 = 0, /**< Use TIMxCH1. */ - TIMCAP_CHANNEL_2 = 1, /**< Use TIMxCH2. */ - TIMCAP_CHANNEL_3 = 2, /**< Use TIMxCH3. */ - TIMCAP_CHANNEL_4 = 3, /**< Use TIMxCH4. */ -} timcapchannel_t; - - -/** - * @brief Driver configuration structure. - * @note It could be empty on some architectures. - */ -typedef struct { - /** - * @brief Driver mode. - */ - timcapmode_t modes[4]; - /** - * @brief Timer clock in Hz. - * @note The low level can use assertions in order to catch invalid - * frequency specifications. - */ - timcapfreq_t frequency; - - /** - * @brief Callback when a capture occurs - */ - timcapcallback_t capture_cb_array[4]; - - /** - * @brief Callback for timer overflow. - */ - timcapcallback_t overflow_cb; - - /* End of the mandatory fields.*/ - - /** - * @brief TIM DIER register initialization data. - * @note The value of this field should normally be equal to zero. - * @note Only the DMA-related bits can be specified in this field. - */ - uint32_t dier; - - /** - * @brief TIM CR1 register initialization data. - * @note The value of this field should normally be equal to zero. - */ - uint32_t cr1; -} TIMCAPConfig; - -/** - * @brief Structure representing an TIMCAP driver. - */ -struct TIMCAPDriver { - /** - * @brief Driver state. - */ - timcapstate_t state; - /** - * @brief Current configuration data. - */ - const TIMCAPConfig *config; -#if defined(TIMCAP_DRIVER_EXT_FIELDS) - TIMCAP_DRIVER_EXT_FIELDS -#endif - /* End of the mandatory fields.*/ - /** - * @brief Timer base clock. - */ - uint32_t clock; - /** - * @brief Pointer to the TIMx registers block. - */ - stm32_tim_t *tim; - /** - * @brief CCR register used for capture. - */ - volatile uint32_t *ccr_p[4]; -}; - -/*===========================================================================*/ -/* Driver macros. */ -/*===========================================================================*/ - -//FIXME document this -#define timcap_lld_get_ccr(timcapp, channel) (*((timcapp)->ccr_p[channel]) + 1) - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -#if STM32_TIMCAP_USE_TIM1 && !defined(__DOXYGEN__) -extern TIMCAPDriver TIMCAPD1; -#endif - -#if STM32_TIMCAP_USE_TIM2 && !defined(__DOXYGEN__) -extern TIMCAPDriver TIMCAPD2; -#endif - -#if STM32_TIMCAP_USE_TIM3 && !defined(__DOXYGEN__) -extern TIMCAPDriver TIMCAPD3; -#endif - -#if STM32_TIMCAP_USE_TIM4 && !defined(__DOXYGEN__) -extern TIMCAPDriver TIMCAPD4; -#endif - -#if STM32_TIMCAP_USE_TIM5 && !defined(__DOXYGEN__) -extern TIMCAPDriver TIMCAPD5; -#endif - -#if STM32_TIMCAP_USE_TIM8 && !defined(__DOXYGEN__) -extern TIMCAPDriver TIMCAPD8; -#endif - -#if STM32_TIMCAP_USE_TIM9 && !defined(__DOXYGEN__) -extern TIMCAPDriver TIMCAPD9; -#endif - -#ifdef __cplusplus -extern "C" { -#endif - void timcap_lld_init(void); - void timcap_lld_start(TIMCAPDriver *timcapp); - void timcap_lld_stop(TIMCAPDriver *timcapp); - void timcap_lld_enable(TIMCAPDriver *timcapp); - void timcap_lld_disable(TIMCAPDriver *timcapp); -#ifdef __cplusplus -} -#endif - -#endif /* HAL_USE_TIMCAP */ - -#endif /* _TIMCAP_LLD_H_ */ - -/** @} */ diff --git a/os/hal/ports/STM32/LLD/USBHv1/hal_stm32_otg.h b/os/hal/ports/STM32/LLD/USBHv1/hal_stm32_otg.h new file mode 100644 index 0000000..ca2dc49 --- /dev/null +++ b/os/hal/ports/STM32/LLD/USBHv1/hal_stm32_otg.h @@ -0,0 +1,929 @@ +/* + ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file stm32_otg.h + * @brief STM32 OTG registers layout header. + * + * @addtogroup USB + * @{ + */ + + +#ifndef _STM32_OTG_H_ +#define _STM32_OTG_H_ + +/** + * @brief Number of the implemented endpoints in OTG_FS. + * @details This value does not include the endpoint 0 that is always present. + */ +#define STM32_OTG1_ENDOPOINTS_NUMBER 3 + +/** + * @brief Number of the implemented endpoints in OTG_HS. + * @details This value does not include the endpoint 0 that is always present. + */ +#define STM32_OTG2_ENDOPOINTS_NUMBER 5 + +/** + * @brief OTG_FS FIFO memory size in words. + */ +#define STM32_OTG1_FIFO_MEM_SIZE 320 + +/** + * @brief OTG_HS FIFO memory size in words. + */ +#define STM32_OTG2_FIFO_MEM_SIZE 1024 + +/** + * @brief Host channel registers group. + */ +typedef struct { + volatile uint32_t HCCHAR; /**< @brief Host channel characteristics + register. */ + volatile uint32_t resvd8; + volatile uint32_t HCINT; /**< @brief Host channel interrupt register.*/ + volatile uint32_t HCINTMSK; /**< @brief Host channel interrupt mask + register. */ + volatile uint32_t HCTSIZ; /**< @brief Host channel transfer size + register. */ + volatile uint32_t resvd14; + volatile uint32_t resvd18; + volatile uint32_t resvd1c; +} stm32_otg_host_chn_t; + +/** + * @brief Device input endpoint registers group. + */ +typedef struct { + volatile uint32_t DIEPCTL; /**< @brief Device control IN endpoint + control register. */ + volatile uint32_t resvd4; + volatile uint32_t DIEPINT; /**< @brief Device IN endpoint interrupt + register. */ + volatile uint32_t resvdC; + volatile uint32_t DIEPTSIZ; /**< @brief Device IN endpoint transfer size + register. */ + volatile uint32_t resvd14; + volatile uint32_t DTXFSTS; /**< @brief Device IN endpoint transmit FIFO + status register. */ + volatile uint32_t resvd1C; +} stm32_otg_in_ep_t; + +/** + * @brief Device output endpoint registers group. + */ +typedef struct { + volatile uint32_t DOEPCTL; /**< @brief Device control OUT endpoint + control register. */ + volatile uint32_t resvd4; + volatile uint32_t DOEPINT; /**< @brief Device OUT endpoint interrupt + register. */ + volatile uint32_t resvdC; + volatile uint32_t DOEPTSIZ; /**< @brief Device OUT endpoint transfer + size register. */ + volatile uint32_t resvd14; + volatile uint32_t resvd18; + volatile uint32_t resvd1C; +} stm32_otg_out_ep_t; + +/** + * @brief USB registers memory map. + */ +typedef struct { + volatile uint32_t GOTGCTL; /**< @brief OTG control and status register.*/ + volatile uint32_t GOTGINT; /**< @brief OTG interrupt register. */ + volatile uint32_t GAHBCFG; /**< @brief AHB configuration register. */ + volatile uint32_t GUSBCFG; /**< @brief USB configuration register. */ + volatile uint32_t GRSTCTL; /**< @brief Reset register size. */ + volatile uint32_t GINTSTS; /**< @brief Interrupt register. */ + volatile uint32_t GINTMSK; /**< @brief Interrupt mask register. */ + volatile uint32_t GRXSTSR; /**< @brief Receive status debug read + register. */ + volatile uint32_t GRXSTSP; /**< @brief Receive status read/pop + register. */ + volatile uint32_t GRXFSIZ; /**< @brief Receive FIFO size register. */ + volatile uint32_t DIEPTXF0; /**< @brief Endpoint 0 transmit FIFO size + register. */ + volatile uint32_t HNPTXSTS; /**< @brief Non-periodic transmit FIFO/queue + status register. */ + volatile uint32_t resvd30; + volatile uint32_t resvd34; + volatile uint32_t GCCFG; /**< @brief General core configuration. */ + volatile uint32_t CID; /**< @brief Core ID register. */ + volatile uint32_t resvd58[48]; + volatile uint32_t HPTXFSIZ; /**< @brief Host periodic transmit FIFO size + register. */ + volatile uint32_t DIEPTXF[15];/**< @brief Device IN endpoint transmit FIFO + size registers. */ + volatile uint32_t resvd140[176]; + volatile uint32_t HCFG; /**< @brief Host configuration register. */ + volatile uint32_t HFIR; /**< @brief Host frame interval register. */ + volatile uint32_t HFNUM; /**< @brief Host frame number/frame time + Remaining register. */ + volatile uint32_t resvd40C; + volatile uint32_t HPTXSTS; /**< @brief Host periodic transmit FIFO/queue + status register. */ + volatile uint32_t HAINT; /**< @brief Host all channels interrupt + register. */ + volatile uint32_t HAINTMSK; /**< @brief Host all channels interrupt mask + register. */ + volatile uint32_t resvd41C[9]; + volatile uint32_t HPRT; /**< @brief Host port control and status + register. */ + volatile uint32_t resvd444[47]; + stm32_otg_host_chn_t hc[16]; /**< @brief Host channels array. */ + volatile uint32_t resvd700[64]; + volatile uint32_t DCFG; /**< @brief Device configuration register. */ + volatile uint32_t DCTL; /**< @brief Device control register. */ + volatile uint32_t DSTS; /**< @brief Device status register. */ + volatile uint32_t resvd80C; + volatile uint32_t DIEPMSK; /**< @brief Device IN endpoint common + interrupt mask register. */ + volatile uint32_t DOEPMSK; /**< @brief Device OUT endpoint common + interrupt mask register. */ + volatile uint32_t DAINT; /**< @brief Device all endpoints interrupt + register. */ + volatile uint32_t DAINTMSK; /**< @brief Device all endpoints interrupt + mask register. */ + volatile uint32_t resvd820; + volatile uint32_t resvd824; + volatile uint32_t DVBUSDIS; /**< @brief Device VBUS discharge time + register. */ + volatile uint32_t DVBUSPULSE; /**< @brief Device VBUS pulsing time + register. */ + volatile uint32_t resvd830; + volatile uint32_t DIEPEMPMSK; /**< @brief Device IN endpoint FIFO empty + interrupt mask register. */ + volatile uint32_t resvd838; + volatile uint32_t resvd83C; + volatile uint32_t resvd840[16]; + volatile uint32_t resvd880[16]; + volatile uint32_t resvd8C0[16]; + stm32_otg_in_ep_t ie[16]; /**< @brief Input endpoints. */ + stm32_otg_out_ep_t oe[16]; /**< @brief Output endpoints. */ + volatile uint32_t resvdD00[64]; + volatile uint32_t PCGCCTL; /**< @brief Power and clock gating control + register. */ + volatile uint32_t resvdE04[127]; + volatile uint32_t FIFO[16][1024]; +} stm32_otg_t; + +/** + * @name GOTGCTL register bit definitions + * @{ + */ +#define GOTGCTL_BSVLD (1U<<19) /**< B-Session Valid. */ +#define GOTGCTL_ASVLD (1U<<18) /**< A-Session Valid. */ +#define GOTGCTL_DBCT (1U<<17) /**< Long/Short debounce time. */ +#define GOTGCTL_CIDSTS (1U<<16) /**< Connector ID status. */ +#define GOTGCTL_EHEN (1U<<12) +#define GOTGCTL_DHNPEN (1U<<11) /**< Device HNP enabled. */ +#define GOTGCTL_HSHNPEN (1U<<10) /**< Host Set HNP enable. */ +#define GOTGCTL_HNPRQ (1U<<9) /**< HNP request. */ +#define GOTGCTL_HNGSCS (1U<<8) /**< Host negotiation success. */ +#define GOTGCTL_BVALOVAL (1U<<7) +#define GOTGCTL_BVALOEN (1U<<6) +#define GOTGCTL_AVALOVAL (1U<<5) +#define GOTGCTL_AVALOEN (1U<<4) +#define GOTGCTL_VBVALOVAL (1U<<3) +#define GOTGCTL_VBVALOEN (1U<<2) +#define GOTGCTL_SRQ (1U<<1) /**< Session request. */ +#define GOTGCTL_SRQSCS (1U<<0) /**< Session request success. */ +/** @} */ + +/** + * @name GOTGINT register bit definitions + * @{ + */ +#define GOTGINT_DBCDNE (1U<<19) /**< Debounce done. */ +#define GOTGINT_ADTOCHG (1U<<18) /**< A-Device timeout change. */ +#define GOTGINT_HNGDET (1U<<17) /**< Host negotiation detected. */ +#define GOTGINT_HNSSCHG (1U<<9) /**< Host negotiation success + status change. */ +#define GOTGINT_SRSSCHG (1U<<8) /**< Session request success + status change. */ +#define GOTGINT_SEDET (1U<<2) /**< Session end detected. */ +/** @} */ + +/** + * @name GAHBCFG register bit definitions + * @{ + */ +#define GAHBCFG_PTXFELVL (1U<<8) /**< Periodic TxFIFO empty + level. */ +#define GAHBCFG_TXFELVL (1U<<7) /**< Non-periodic TxFIFO empty + level. */ +#define GAHBCFG_DMAEN (1U<<5) /**< DMA enable (HS only). */ +#define GAHBCFG_HBSTLEN_MASK (15U<<1) /**< Burst length/type mask (HS + only). */ +#define GAHBCFG_HBSTLEN(n) ((n)<<1) /**< Burst length/type (HS + only). */ +#define GAHBCFG_GINTMSK (1U<<0) /**< Global interrupt mask. */ +/** @} */ + +/** + * @name GUSBCFG register bit definitions + * @{ + */ +#define GUSBCFG_CTXPKT (1U<<31) /**< Corrupt Tx packet. */ +#define GUSBCFG_FDMOD (1U<<30) /**< Force Device Mode. */ +#define GUSBCFG_FHMOD (1U<<29) /**< Force Host Mode. */ +#define GUSBCFG_TRDT_MASK (15U<<10) /**< USB Turnaround time field + mask. */ +#define GUSBCFG_TRDT(n) ((n)<<10) /**< USB Turnaround time field + value. */ +#define GUSBCFG_HNPCAP (1U<<9) /**< HNP-Capable. */ +#define GUSBCFG_SRPCAP (1U<<8) /**< SRP-Capable. */ +#define GUSBCFG_PHYSEL (1U<<6) /**< USB 2.0 High-Speed PHY or + USB 1.1 Full-Speed serial + transceiver Select. */ +#define GUSBCFG_TOCAL_MASK (7U<<0) /**< HS/FS timeout calibration + field mask. */ +#define GUSBCFG_TOCAL(n) ((n)<<0) /**< HS/FS timeout calibration + field value. */ +/** @} */ + +/** + * @name GRSTCTL register bit definitions + * @{ + */ +#define GRSTCTL_AHBIDL (1U<<31) /**< AHB Master Idle. */ +#define GRSTCTL_TXFNUM_MASK (31U<<6) /**< TxFIFO number field mask. */ +#define GRSTCTL_TXFNUM(n) ((n)<<6) /**< TxFIFO number field value. */ +#define GRSTCTL_TXFFLSH (1U<<5) /**< TxFIFO flush. */ +#define GRSTCTL_RXFFLSH (1U<<4) /**< RxFIFO flush. */ +#define GRSTCTL_FCRST (1U<<2) /**< Host frame counter reset. */ +#define GRSTCTL_HSRST (1U<<1) /**< HClk soft reset. */ +#define GRSTCTL_CSRST (1U<<0) /**< Core soft reset. */ +/** @} */ + +/** + * @name GINTSTS register bit definitions + * @{ + */ +#define GINTSTS_WKUPINT (1U<<31) /**< Resume/Remote wakeup + detected interrupt. */ +#define GINTSTS_SRQINT (1U<<30) /**< Session request/New session + detected interrupt. */ +#define GINTSTS_DISCINT (1U<<29) /**< Disconnect detected + interrupt. */ +#define GINTSTS_CIDSCHG (1U<<28) /**< Connector ID status change.*/ +#define GINTSTS_PTXFE (1U<<26) /**< Periodic TxFIFO empty. */ +#define GINTSTS_HCINT (1U<<25) /**< Host channels interrupt. */ +#define GINTSTS_HPRTINT (1U<<24) /**< Host port interrupt. */ +#define GINTSTS_IPXFR (1U<<21) /**< Incomplete periodic + transfer. */ +#define GINTSTS_IISOOXFR (1U<<21) /**< Incomplete isochronous OUT + transfer. */ +#define GINTSTS_IISOIXFR (1U<<20) /**< Incomplete isochronous IN + transfer. */ +#define GINTSTS_OEPINT (1U<<19) /**< OUT endpoints interrupt. */ +#define GINTSTS_IEPINT (1U<<18) /**< IN endpoints interrupt. */ +#define GINTSTS_EOPF (1U<<15) /**< End of periodic frame + interrupt. */ +#define GINTSTS_ISOODRP (1U<<14) /**< Isochronous OUT packet + dropped interrupt. */ +#define GINTSTS_ENUMDNE (1U<<13) /**< Enumeration done. */ +#define GINTSTS_USBRST (1U<<12) /**< USB reset. */ +#define GINTSTS_USBSUSP (1U<<11) /**< USB suspend. */ +#define GINTSTS_ESUSP (1U<<10) /**< Early suspend. */ +#define GINTSTS_GONAKEFF (1U<<7) /**< Global OUT NAK effective. */ +#define GINTSTS_GINAKEFF (1U<<6) /**< Global IN non-periodic NAK + effective. */ +#define GINTSTS_NPTXFE (1U<<5) /**< Non-periodic TxFIFO empty. */ +#define GINTSTS_RXFLVL (1U<<4) /**< RxFIFO non-empty. */ +#define GINTSTS_SOF (1U<<3) /**< Start of frame. */ +#define GINTSTS_OTGINT (1U<<2) /**< OTG interrupt. */ +#define GINTSTS_MMIS (1U<<1) /**< Mode Mismatch interrupt. */ +#define GINTSTS_CMOD (1U<<0) /**< Current mode of operation. */ +/** @} */ + +/** + * @name GINTMSK register bit definitions + * @{ + */ +#define GINTMSK_WKUM (1U<<31) /**< Resume/remote wakeup + detected interrupt mask. */ +#define GINTMSK_SRQM (1U<<30) /**< Session request/New session + detected interrupt mask. */ +#define GINTMSK_DISCM (1U<<29) /**< Disconnect detected + interrupt mask. */ +#define GINTMSK_CIDSCHGM (1U<<28) /**< Connector ID status change + mask. */ +#define GINTMSK_PTXFEM (1U<<26) /**< Periodic TxFIFO empty mask.*/ +#define GINTMSK_HCM (1U<<25) /**< Host channels interrupt + mask. */ +#define GINTMSK_HPRTM (1U<<24) /**< Host port interrupt mask. */ +#define GINTMSK_IPXFRM (1U<<21) /**< Incomplete periodic + transfer mask. */ +#define GINTMSK_IISOOXFRM (1U<<21) /**< Incomplete isochronous OUT + transfer mask. */ +#define GINTMSK_IISOIXFRM (1U<<20) /**< Incomplete isochronous IN + transfer mask. */ +#define GINTMSK_OEPM (1U<<19) /**< OUT endpoints interrupt + mask. */ +#define GINTMSK_IEPM (1U<<18) /**< IN endpoints interrupt + mask. */ +#define GINTMSK_EOPFM (1U<<15) /**< End of periodic frame + interrupt mask. */ +#define GINTMSK_ISOODRPM (1U<<14) /**< Isochronous OUT packet + dropped interrupt mask. */ +#define GINTMSK_ENUMDNEM (1U<<13) /**< Enumeration done mask. */ +#define GINTMSK_USBRSTM (1U<<12) /**< USB reset mask. */ +#define GINTMSK_USBSUSPM (1U<<11) /**< USB suspend mask. */ +#define GINTMSK_ESUSPM (1U<<10) /**< Early suspend mask. */ +#define GINTMSK_GONAKEFFM (1U<<7) /**< Global OUT NAK effective + mask. */ +#define GINTMSK_GINAKEFFM (1U<<6) /**< Global non-periodic IN NAK + effective mask. */ +#define GINTMSK_NPTXFEM (1U<<5) /**< Non-periodic TxFIFO empty + mask. */ +#define GINTMSK_RXFLVLM (1U<<4) /**< Receive FIFO non-empty + mask. */ +#define GINTMSK_SOFM (1U<<3) /**< Start of (micro)frame mask.*/ +#define GINTMSK_OTGM (1U<<2) /**< OTG interrupt mask. */ +#define GINTMSK_MMISM (1U<<1) /**< Mode Mismatch interrupt + mask. */ +/** @} */ + +/** + * @name GRXSTSR register bit definitions + * @{ + */ +#define GRXSTSR_PKTSTS_MASK (15U<<17) /**< Packet status mask. */ +#define GRXSTSR_PKTSTS(n) ((n)<<17) /**< Packet status value. */ +#define GRXSTSR_OUT_GLOBAL_NAK GRXSTSR_PKTSTS(1) +#define GRXSTSR_OUT_DATA GRXSTSR_PKTSTS(2) +#define GRXSTSR_OUT_COMP GRXSTSR_PKTSTS(3) +#define GRXSTSR_SETUP_COMP GRXSTSR_PKTSTS(4) +#define GRXSTSR_SETUP_DATA GRXSTSR_PKTSTS(6) +#define GRXSTSR_DPID_MASK (3U<<15) /**< Data PID mask. */ +#define GRXSTSR_DPID(n) ((n)<<15) /**< Data PID value. */ +#define GRXSTSR_BCNT_MASK (0x7FF<<4) /**< Byte count mask. */ +#define GRXSTSR_BCNT(n) ((n)<<4) /**< Byte count value. */ +#define GRXSTSR_CHNUM_MASK (15U<<0) /**< Channel number mask. */ +#define GRXSTSR_CHNUM(n) ((n)<<0) /**< Channel number value. */ +#define GRXSTSR_EPNUM_MASK (15U<<0) /**< Endpoint number mask. */ +#define GRXSTSR_EPNUM(n) ((n)<<0) /**< Endpoint number value. */ +/** @} */ + +/** + * @name GRXSTSP register bit definitions + * @{ + */ +#define GRXSTSP_PKTSTS_MASK (15<<17) /**< Packet status mask. */ +#define GRXSTSP_PKTSTS(n) ((n)<<17) /**< Packet status value. */ +#define GRXSTSP_OUT_GLOBAL_NAK GRXSTSP_PKTSTS(1) +#define GRXSTSP_OUT_DATA GRXSTSP_PKTSTS(2) +#define GRXSTSP_OUT_COMP GRXSTSP_PKTSTS(3) +#define GRXSTSP_SETUP_COMP GRXSTSP_PKTSTS(4) +#define GRXSTSP_SETUP_DATA GRXSTSP_PKTSTS(6) +#define GRXSTSP_DPID_MASK (3U<<15) /**< Data PID mask. */ +#define GRXSTSP_DPID(n) ((n)<<15) /**< Data PID value. */ +#define GRXSTSP_BCNT_MASK (0x7FF<<4) /**< Byte count mask. */ +#define GRXSTSP_BCNT_OFF 4 /**< Byte count offset. */ +#define GRXSTSP_BCNT(n) ((n)<<4) /**< Byte count value. */ +#define GRXSTSP_CHNUM_MASK (15U<<0) /**< Channel number mask. */ +#define GRXSTSP_CHNUM(n) ((n)<<0) /**< Channel number value. */ +#define GRXSTSP_EPNUM_MASK (15U<<0) /**< Endpoint number mask. */ +#define GRXSTSP_EPNUM_OFF 0 /**< Endpoint number offset. */ +#define GRXSTSP_EPNUM(n) ((n)<<0) /**< Endpoint number value. */ +/** @} */ + +/** + * @name GRXFSIZ register bit definitions + * @{ + */ +#define GRXFSIZ_RXFD_MASK (0xFFFF<<0) /**< RxFIFO depth mask. */ +#define GRXFSIZ_RXFD(n) ((n)<<0) /**< RxFIFO depth value. */ +/** @} */ + +/** + * @name DIEPTXFx register bit definitions + * @{ + */ +#define DIEPTXF_INEPTXFD_MASK (0xFFFFU<<16)/**< IN endpoint TxFIFO depth + mask. */ +#define DIEPTXF_INEPTXFD(n) ((n)<<16) /**< IN endpoint TxFIFO depth + value. */ +#define DIEPTXF_INEPTXSA_MASK (0xFFFF<<0) /**< IN endpoint FIFOx transmit + RAM start address mask. */ +#define DIEPTXF_INEPTXSA(n) ((n)<<0) /**< IN endpoint FIFOx transmit + RAM start address value. */ +/** @} */ + +/** + * @name GCCFG register bit definitions + * @{ + */ +#define GCCFG_NOVBUSSENS (1U<<21) /**< VBUS sensing disable. */ +#define GCCFG_SOFOUTEN (1U<<20) /**< SOF output enable. */ +#define GCCFG_VBUSBSEN (1U<<19) /**< Enable the VBUS sensing "B" + device. */ +#define GCCFG_VBUSASEN (1U<<18) /**< Enable the VBUS sensing "A" + device. */ +#define GCCFG_PWRDWN (1U<<16) /**< Power down. */ +/** @} */ + +/** + * @name HPTXFSIZ register bit definitions + * @{ + */ +#define HPTXFSIZ_PTXFD_MASK (0xFFFFU<<16)/**< Host periodic TxFIFO + depth mask. */ +#define HPTXFSIZ_PTXFD(n) ((n)<<16) /**< Host periodic TxFIFO + depth value. */ +#define HPTXFSIZ_PTXSA_MASK (0xFFFFU<<0)/**< Host periodic TxFIFO + Start address mask. */ +#define HPTXFSIZ_PTXSA(n) ((n)<<0) /**< Host periodic TxFIFO + start address value. */ +/** @} */ + +/** + * @name HCFG register bit definitions + * @{ + */ +#define HCFG_FSLSS (1U<<2) /**< FS- and LS-only support. */ +#define HCFG_FSLSPCS_MASK (3U<<0) /**< FS/LS PHY clock select + mask. */ +#define HCFG_FSLSPCS_48 (1U<<0) /**< PHY clock is running at + 48 MHz. */ +#define HCFG_FSLSPCS_6 (2U<<0) /**< PHY clock is running at + 6 MHz. */ +/** @} */ + +/** + * @name HFIR register bit definitions + * @{ + */ +#define HFIR_FRIVL_MASK (0xFFFFU<<0)/**< Frame interval mask. */ +#define HFIR_FRIVL(n) ((n)<<0) /**< Frame interval value. */ +/** @} */ + +/** + * @name HFNUM register bit definitions + * @{ + */ +#define HFNUM_FTREM_MASK (0xFFFFU<<16)/**< Frame time Remaining mask.*/ +#define HFNUM_FTREM(n) ((n)<<16) /**< Frame time Remaining value.*/ +#define HFNUM_FRNUM_MASK (0xFFFFU<<0)/**< Frame number mask. */ +#define HFNUM_FRNUM(n) ((n)<<0) /**< Frame number value. */ +/** @} */ + +/** + * @name HPTXSTS register bit definitions + * @{ + */ +#define HPTXSTS_PTXQTOP_MASK (0xFFU<<24) /**< Top of the periodic + transmit request queue + mask. */ +#define HPTXSTS_PTXQTOP(n) ((n)<<24) /**< Top of the periodic + transmit request queue + value. */ +#define HPTXSTS_PTXQSAV_MASK (0xFF<<16) /**< Periodic transmit request + queue Space Available + mask. */ +#define HPTXSTS_PTXQSAV(n) ((n)<<16) /**< Periodic transmit request + queue Space Available + value. */ +#define HPTXSTS_PTXFSAVL_MASK (0xFFFF<<0) /**< Periodic transmit Data + FIFO Space Available + mask. */ +#define HPTXSTS_PTXFSAVL(n) ((n)<<0) /**< Periodic transmit Data + FIFO Space Available + value. */ +/** @} */ + +/** + * @name HAINT register bit definitions + * @{ + */ +#define HAINT_HAINT_MASK (0xFFFFU<<0)/**< Channel interrupts mask. */ +#define HAINT_HAINT(n) ((n)<<0) /**< Channel interrupts value. */ +/** @} */ + +/** + * @name HAINTMSK register bit definitions + * @{ + */ +#define HAINTMSK_HAINTM_MASK (0xFFFFU<<0)/**< Channel interrupt mask + mask. */ +#define HAINTMSK_HAINTM(n) ((n)<<0) /**< Channel interrupt mask + value. */ +/** @} */ + +/** + * @name HPRT register bit definitions + * @{ + */ +#define HPRT_PSPD_MASK (3U<<17) /**< Port speed mask. */ +#define HPRT_PSPD_FS (1U<<17) /**< Full speed value. */ +#define HPRT_PSPD_LS (2U<<17) /**< Low speed value. */ +#define HPRT_PTCTL_MASK (15<<13) /**< Port Test control mask. */ +#define HPRT_PTCTL(n) ((n)<<13) /**< Port Test control value. */ +#define HPRT_PPWR (1U<<12) /**< Port power. */ +#define HPRT_PLSTS_MASK (3U<<11) /**< Port Line status mask. */ +#define HPRT_PLSTS_DM (1U<<11) /**< Logic level of D-. */ +#define HPRT_PLSTS_DP (1U<<10) /**< Logic level of D+. */ +#define HPRT_PRST (1U<<8) /**< Port reset. */ +#define HPRT_PSUSP (1U<<7) /**< Port suspend. */ +#define HPRT_PRES (1U<<6) /**< Port Resume. */ +#define HPRT_POCCHNG (1U<<5) /**< Port overcurrent change. */ +#define HPRT_POCA (1U<<4) /**< Port overcurrent active. */ +#define HPRT_PENCHNG (1U<<3) /**< Port enable/disable change.*/ +#define HPRT_PENA (1U<<2) /**< Port enable. */ +#define HPRT_PCDET (1U<<1) /**< Port Connect detected. */ +#define HPRT_PCSTS (1U<<0) /**< Port connect status. */ +/** @} */ + +/** + * @name HCCHAR register bit definitions + * @{ + */ +#define HCCHAR_CHENA (1U<<31) /**< Channel enable. */ +#define HCCHAR_CHDIS (1U<<30) /**< Channel Disable. */ +#define HCCHAR_ODDFRM (1U<<29) /**< Odd frame. */ +#define HCCHAR_DAD_MASK (0x7FU<<22) /**< Device Address mask. */ +#define HCCHAR_DAD(n) ((n)<<22) /**< Device Address value. */ +#define HCCHAR_MCNT_MASK (3U<<20) /**< Multicount mask. */ +#define HCCHAR_MCNT(n) ((n)<<20) /**< Multicount value. */ +#define HCCHAR_EPTYP_MASK (3U<<18) /**< Endpoint type mask. */ +#define HCCHAR_EPTYP(n) ((n)<<18) /**< Endpoint type value. */ +#define HCCHAR_EPTYP_CTL (0U<<18) /**< Control endpoint value. */ +#define HCCHAR_EPTYP_ISO (1U<<18) /**< Isochronous endpoint value.*/ +#define HCCHAR_EPTYP_BULK (2U<<18) /**< Bulk endpoint value. */ +#define HCCHAR_EPTYP_INTR (3U<<18) /**< Interrupt endpoint value. */ +#define HCCHAR_LSDEV (1U<<17) /**< Low-Speed device. */ +#define HCCHAR_EPDIR (1U<<15) /**< Endpoint direction. */ +#define HCCHAR_EPNUM_MASK (15U<<11) /**< Endpoint number mask. */ +#define HCCHAR_EPNUM(n) ((n)<<11) /**< Endpoint number value. */ +#define HCCHAR_MPS_MASK (0x7FFU<<0) /**< Maximum packet size mask. */ +#define HCCHAR_MPS(n) ((n)<<0) /**< Maximum packet size value. */ +/** @} */ + +/** + * @name HCINT register bit definitions + * @{ + */ +#define HCINT_DTERR (1U<<10) /**< Data toggle error. */ +#define HCINT_FRMOR (1U<<9) /**< Frame overrun. */ +#define HCINT_BBERR (1U<<8) /**< Babble error. */ +#define HCINT_TRERR (1U<<7) /**< Transaction Error. */ +#define HCINT_ACK (1U<<5) /**< ACK response + received/transmitted + interrupt. */ +#define HCINT_NAK (1U<<4) /**< NAK response received + interrupt. */ +#define HCINT_STALL (1U<<3) /**< STALL response received + interrupt. */ +#define HCINT_CHH (1U<<1) /**< Channel halted. */ +#define HCINT_XFRC (1U<<0) /**< Transfer completed. */ +/** @} */ + +/** + * @name HCINTMSK register bit definitions + * @{ + */ +#define HCINTMSK_DTERRM (1U<<10) /**< Data toggle error mask. */ +#define HCINTMSK_FRMORM (1U<<9) /**< Frame overrun mask. */ +#define HCINTMSK_BBERRM (1U<<8) /**< Babble error mask. */ +#define HCINTMSK_TRERRM (1U<<7) /**< Transaction error mask. */ +#define HCINTMSK_NYET (1U<<6) /**< NYET response received + interrupt mask. */ +#define HCINTMSK_ACKM (1U<<5) /**< ACK Response + received/transmitted + interrupt mask. */ +#define HCINTMSK_NAKM (1U<<4) /**< NAK response received + interrupt mask. */ +#define HCINTMSK_STALLM (1U<<3) /**< STALL response received + interrupt mask. */ +#define HCINTMSK_AHBERRM (1U<<2) +#define HCINTMSK_CHHM (1U<<1) /**< Channel halted mask. */ +#define HCINTMSK_XFRCM (1U<<0) /**< Transfer completed mask. */ +/** @} */ + +/** + * @name HCTSIZ register bit definitions + * @{ + */ +#define HCTSIZ_DPID_MASK (3U<<29) /**< PID mask. */ +#define HCTSIZ_DPID_DATA0 (0U<<29) /**< DATA0. */ +#define HCTSIZ_DPID_DATA2 (1U<<29) /**< DATA2. */ +#define HCTSIZ_DPID_DATA1 (2U<<29) /**< DATA1. */ +#define HCTSIZ_DPID_MDATA (3U<<29) /**< MDATA. */ +#define HCTSIZ_DPID_SETUP (3U<<29) /**< SETUP. */ +#define HCTSIZ_PKTCNT_MASK (0x3FFU<<19)/**< Packet count mask. */ +#define HCTSIZ_PKTCNT(n) ((n)<<19) /**< Packet count value. */ +#define HCTSIZ_XFRSIZ_MASK (0x7FFFF<<0)/**< Transfer size mask. */ +#define HCTSIZ_XFRSIZ(n) ((n)<<0) /**< Transfer size value. */ +/** @} */ + +/** + * @name DCFG register bit definitions + * @{ + */ +#define DCFG_PFIVL_MASK (3U<<11) /**< Periodic frame interval + mask. */ +#define DCFG_PFIVL(n) ((n)<<11) /**< Periodic frame interval + value. */ +#define DCFG_DAD_MASK (0x7FU<<4) /**< Device address mask. */ +#define DCFG_DAD(n) ((n)<<4) /**< Device address value. */ +#define DCFG_NZLSOHSK (1U<<2) /**< Non-Zero-Length status + OUT handshake. */ +#define DCFG_DSPD_MASK (3U<<0) /**< Device speed mask. */ +#define DCFG_DSPD_HS (0U<<0) /**< High speed (USB 2.0). */ +#define DCFG_DSPD_HS_FS (1U<<0) /**< High speed (USB 2.0) in FS + mode. */ +#define DCFG_DSPD_FS11 (3U<<0) /**< Full speed (USB 1.1 + transceiver clock is 48 + MHz). */ +/** @} */ + +/** + * @name DCTL register bit definitions + * @{ + */ +#define DCTL_POPRGDNE (1U<<11) /**< Power-on programming done. */ +#define DCTL_CGONAK (1U<<10) /**< Clear global OUT NAK. */ +#define DCTL_SGONAK (1U<<9) /**< Set global OUT NAK. */ +#define DCTL_CGINAK (1U<<8) /**< Clear global non-periodic + IN NAK. */ +#define DCTL_SGINAK (1U<<7) /**< Set global non-periodic + IN NAK. */ +#define DCTL_TCTL_MASK (7U<<4) /**< Test control mask. */ +#define DCTL_TCTL(n) ((n)<<4 /**< Test control value. */ +#define DCTL_GONSTS (1U<<3) /**< Global OUT NAK status. */ +#define DCTL_GINSTS (1U<<2) /**< Global non-periodic IN + NAK status. */ +#define DCTL_SDIS (1U<<1) /**< Soft disconnect. */ +#define DCTL_RWUSIG (1U<<0) /**< Remote wakeup signaling. */ +/** @} */ + +/** + * @name DSTS register bit definitions + * @{ + */ +#define DSTS_FNSOF_MASK (0x3FFU<<8) /**< Frame number of the received + SOF mask. */ +#define DSTS_FNSOF(n) ((n)<<8) /**< Frame number of the received + SOF value. */ +#define DSTS_FNSOF_ODD (1U<<8) /**< Frame parity of the received + SOF value. */ +#define DSTS_EERR (1U<<3) /**< Erratic error. */ +#define DSTS_ENUMSPD_MASK (3U<<1) /**< Enumerated speed mask. */ +#define DSTS_ENUMSPD_FS_48 (3U<<1) /**< Full speed (PHY clock is + running at 48 MHz). */ +#define DSTS_ENUMSPD_HS_480 (0U<<1) /**< High speed. */ +#define DSTS_SUSPSTS (1U<<0) /**< Suspend status. */ +/** @} */ + +/** + * @name DIEPMSK register bit definitions + * @{ + */ +#define DIEPMSK_TXFEM (1U<<6) /**< Transmit FIFO empty mask. */ +#define DIEPMSK_INEPNEM (1U<<6) /**< IN endpoint NAK effective + mask. */ +#define DIEPMSK_ITTXFEMSK (1U<<4) /**< IN token received when + TxFIFO empty mask. */ +#define DIEPMSK_TOCM (1U<<3) /**< Timeout condition mask. */ +#define DIEPMSK_EPDM (1U<<1) /**< Endpoint disabled + interrupt mask. */ +#define DIEPMSK_XFRCM (1U<<0) /**< Transfer completed + interrupt mask. */ +/** @} */ + +/** + * @name DOEPMSK register bit definitions + * @{ + */ +#define DOEPMSK_OTEPDM (1U<<4) /**< OUT token received when + endpoint disabled mask. */ +#define DOEPMSK_STUPM (1U<<3) /**< SETUP phase done mask. */ +#define DOEPMSK_EPDM (1U<<1) /**< Endpoint disabled + interrupt mask. */ +#define DOEPMSK_XFRCM (1U<<0) /**< Transfer completed + interrupt mask. */ +/** @} */ + +/** + * @name DAINT register bit definitions + * @{ + */ +#define DAINT_OEPINT_MASK (0xFFFFU<<16)/**< OUT endpoint interrupt + bits mask. */ +#define DAINT_OEPINT(n) ((n)<<16) /**< OUT endpoint interrupt + bits value. */ +#define DAINT_IEPINT_MASK (0xFFFFU<<0)/**< IN endpoint interrupt + bits mask. */ +#define DAINT_IEPINT(n) ((n)<<0) /**< IN endpoint interrupt + bits value. */ +/** @} */ + +/** + * @name DAINTMSK register bit definitions + * @{ + */ +#define DAINTMSK_OEPM_MASK (0xFFFFU<<16)/**< OUT EP interrupt mask + bits mask. */ +#define DAINTMSK_OEPM(n) (1U<<(16+(n)))/**< OUT EP interrupt mask + bits value. */ +#define DAINTMSK_IEPM_MASK (0xFFFFU<<0)/**< IN EP interrupt mask + bits mask. */ +#define DAINTMSK_IEPM(n) (1U<<(n)) /**< IN EP interrupt mask + bits value. */ +/** @} */ + +/** + * @name DVBUSDIS register bit definitions + * @{ + */ +#define DVBUSDIS_VBUSDT_MASK (0xFFFFU<<0)/**< Device VBUS discharge + time mask. */ +#define DVBUSDIS_VBUSDT(n) ((n)<<0) /**< Device VBUS discharge + time value. */ +/** @} */ + +/** + * @name DVBUSPULSE register bit definitions + * @{ + */ +#define DVBUSPULSE_DVBUSP_MASK (0xFFFU<<0) /**< Device VBUSpulsing time + mask. */ +#define DVBUSPULSE_DVBUSP(n) ((n)<<0) /**< Device VBUS pulsing time + value. */ +/** @} */ + +/** + * @name DIEPEMPMSK register bit definitions + * @{ + */ +#define DIEPEMPMSK_INEPTXFEM(n) (1U<<(n)) /**< IN EP Tx FIFO empty + interrupt mask bit. */ +/** @} */ + +/** + * @name DIEPCTL register bit definitions + * @{ + */ +#define DIEPCTL_EPENA (1U<<31) /**< Endpoint enable. */ +#define DIEPCTL_EPDIS (1U<<30) /**< Endpoint disable. */ +#define DIEPCTL_SD1PID (1U<<29) /**< Set DATA1 PID. */ +#define DIEPCTL_SODDFRM (1U<<29) /**< Set odd frame. */ +#define DIEPCTL_SD0PID (1U<<28) /**< Set DATA0 PID. */ +#define DIEPCTL_SEVNFRM (1U<<28) /**< Set even frame. */ +#define DIEPCTL_SNAK (1U<<27) /**< Set NAK. */ +#define DIEPCTL_CNAK (1U<<26) /**< Clear NAK. */ +#define DIEPCTL_TXFNUM_MASK (15U<<22) /**< TxFIFO number mask. */ +#define DIEPCTL_TXFNUM(n) ((n)<<22) /**< TxFIFO number value. */ +#define DIEPCTL_STALL (1U<<21) /**< STALL handshake. */ +#define DIEPCTL_SNPM (1U<<20) /**< Snoop mode. */ +#define DIEPCTL_EPTYP_MASK (3<<18) /**< Endpoint type mask. */ +#define DIEPCTL_EPTYP_CTRL (0U<<18) /**< Control. */ +#define DIEPCTL_EPTYP_ISO (1U<<18) /**< Isochronous. */ +#define DIEPCTL_EPTYP_BULK (2U<<18) /**< Bulk. */ +#define DIEPCTL_EPTYP_INTR (3U<<18) /**< Interrupt. */ +#define DIEPCTL_NAKSTS (1U<<17) /**< NAK status. */ +#define DIEPCTL_EONUM (1U<<16) /**< Even/odd frame. */ +#define DIEPCTL_DPID (1U<<16) /**< Endpoint data PID. */ +#define DIEPCTL_USBAEP (1U<<15) /**< USB active endpoint. */ +#define DIEPCTL_MPSIZ_MASK (0x3FFU<<0) /**< Maximum Packet size mask. */ +#define DIEPCTL_MPSIZ(n) ((n)<<0) /**< Maximum Packet size value. */ +/** @} */ + +/** + * @name DIEPINT register bit definitions + * @{ + */ +#define DIEPINT_TXFE (1U<<7) /**< Transmit FIFO empty. */ +#define DIEPINT_INEPNE (1U<<6) /**< IN endpoint NAK effective. */ +#define DIEPINT_ITTXFE (1U<<4) /**< IN Token received when + TxFIFO is empty. */ +#define DIEPINT_TOC (1U<<3) /**< Timeout condition. */ +#define DIEPINT_EPDISD (1U<<1) /**< Endpoint disabled + interrupt. */ +#define DIEPINT_XFRC (1U<<0) /**< Transfer completed. */ +/** @} */ + +/** + * @name DIEPTSIZ register bit definitions + * @{ + */ +#define DIEPTSIZ_MCNT_MASK (3U<<29) /**< Multi count mask. */ +#define DIEPTSIZ_MCNT(n) ((n)<<29) /**< Multi count value. */ +#define DIEPTSIZ_PKTCNT_MASK (0x3FF<<19) /**< Packet count mask. */ +#define DIEPTSIZ_PKTCNT(n) ((n)<<19) /**< Packet count value. */ +#define DIEPTSIZ_XFRSIZ_MASK (0x7FFFFU<<0)/**< Transfer size mask. */ +#define DIEPTSIZ_XFRSIZ(n) ((n)<<0) /**< Transfer size value. */ +/** @} */ + +/** + * @name DTXFSTS register bit definitions. + * @{ + */ +#define DTXFSTS_INEPTFSAV_MASK (0xFFFF<<0) /**< IN endpoint TxFIFO space + available. */ +/** @} */ + +/** + * @name DOEPCTL register bit definitions. + * @{ + */ +#define DOEPCTL_EPENA (1U<<31) /**< Endpoint enable. */ +#define DOEPCTL_EPDIS (1U<<30) /**< Endpoint disable. */ +#define DOEPCTL_SD1PID (1U<<29) /**< Set DATA1 PID. */ +#define DOEPCTL_SODDFRM (1U<<29) /**< Set odd frame. */ +#define DOEPCTL_SD0PID (1U<<28) /**< Set DATA0 PID. */ +#define DOEPCTL_SEVNFRM (1U<<28) /**< Set even frame. */ +#define DOEPCTL_SNAK (1U<<27) /**< Set NAK. */ +#define DOEPCTL_CNAK (1U<<26) /**< Clear NAK. */ +#define DOEPCTL_STALL (1U<<21) /**< STALL handshake. */ +#define DOEPCTL_SNPM (1U<<20) /**< Snoop mode. */ +#define DOEPCTL_EPTYP_MASK (3U<<18) /**< Endpoint type mask. */ +#define DOEPCTL_EPTYP_CTRL (0U<<18) /**< Control. */ +#define DOEPCTL_EPTYP_ISO (1U<<18) /**< Isochronous. */ +#define DOEPCTL_EPTYP_BULK (2U<<18) /**< Bulk. */ +#define DOEPCTL_EPTYP_INTR (3U<<18) /**< Interrupt. */ +#define DOEPCTL_NAKSTS (1U<<17) /**< NAK status. */ +#define DOEPCTL_EONUM (1U<<16) /**< Even/odd frame. */ +#define DOEPCTL_DPID (1U<<16) /**< Endpoint data PID. */ +#define DOEPCTL_USBAEP (1U<<15) /**< USB active endpoint. */ +#define DOEPCTL_MPSIZ_MASK (0x3FFU<<0) /**< Maximum Packet size mask. */ +#define DOEPCTL_MPSIZ(n) ((n)<<0) /**< Maximum Packet size value. */ +/** @} */ + +/** + * @name DOEPINT register bit definitions + * @{ + */ +#define DOEPINT_B2BSTUP (1U<<6) /**< Back-to-back SETUP packets + received. */ +#define DOEPINT_OTEPDIS (1U<<4) /**< OUT token received when + endpoint disabled. */ +#define DOEPINT_STUP (1U<<3) /**< SETUP phase done. */ +#define DOEPINT_EPDISD (1U<<1) /**< Endpoint disabled + interrupt. */ +#define DOEPINT_XFRC (1U<<0) /**< Transfer completed + interrupt. */ +/** @} */ + +/** + * @name DOEPTSIZ register bit definitions + * @{ + */ +#define DOEPTSIZ_RXDPID_MASK (3U<<29) /**< Received data PID mask. */ +#define DOEPTSIZ_RXDPID(n) ((n)<<29) /**< Received data PID value. */ +#define DOEPTSIZ_STUPCNT_MASK (3U<<29) /**< SETUP packet count mask. */ +#define DOEPTSIZ_STUPCNT(n) ((n)<<29) /**< SETUP packet count value. */ +#define DOEPTSIZ_PKTCNT_MASK (0x3FFU<<19)/**< Packet count mask. */ +#define DOEPTSIZ_PKTCNT(n) ((n)<<19) /**< Packet count value. */ +#define DOEPTSIZ_XFRSIZ_MASK (0x7FFFFU<<0)/**< Transfer size mask. */ +#define DOEPTSIZ_XFRSIZ(n) ((n)<<0) /**< Transfer size value. */ +/** @} */ + +/** + * @name PCGCCTL register bit definitions + * @{ + */ +#define PCGCCTL_PHYSUSP (1U<<4) /**< PHY Suspended. */ +#define PCGCCTL_GATEHCLK (1U<<1) /**< Gate HCLK. */ +#define PCGCCTL_STPPCLK (1U<<0) /**< Stop PCLK. */ +/** @} */ + +/** + * @brief OTG_FS registers block memory address. + */ +#define OTG_FS_ADDR 0x50000000 + +/** + * @brief OTG_HS registers block memory address. + */ +#define OTG_HS_ADDR 0x40040000 + +/** + * @brief Accesses to the OTG_FS registers block. + */ +#define OTG_FS ((stm32_otg_t *)OTG_FS_ADDR) + +/** + * @brief Accesses to the OTG_HS registers block. + */ +#define OTG_HS ((stm32_otg_t *)OTG_HS_ADDR) + +#endif /* _STM32_OTG_H_ */ + +/** @} */ diff --git a/os/hal/ports/STM32/LLD/USBHv1/hal_usbh_lld.c b/os/hal/ports/STM32/LLD/USBHv1/hal_usbh_lld.c new file mode 100644 index 0000000..3abab1c --- /dev/null +++ b/os/hal/ports/STM32/LLD/USBHv1/hal_usbh_lld.c @@ -0,0 +1,1604 @@ +/* + ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio + Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include "hal.h" + +#if HAL_USE_USBH +#include "usbh/internal.h" +#include + +#if USBH_LLD_DEBUG_ENABLE_TRACE +#define udbgf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) +#define udbg(f, ...) usbDbgPuts(f, ##__VA_ARGS__) +#else +#define udbgf(f, ...) do {} while(0) +#define udbg(f, ...) do {} while(0) +#endif + +#if USBH_LLD_DEBUG_ENABLE_INFO +#define uinfof(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) +#define uinfo(f, ...) usbDbgPuts(f, ##__VA_ARGS__) +#else +#define uinfof(f, ...) do {} while(0) +#define uinfo(f, ...) do {} while(0) +#endif + +#if USBH_LLD_DEBUG_ENABLE_WARNINGS +#define uwarnf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) +#define uwarn(f, ...) usbDbgPuts(f, ##__VA_ARGS__) +#else +#define uwarnf(f, ...) do {} while(0) +#define uwarn(f, ...) do {} while(0) +#endif + +#if USBH_LLD_DEBUG_ENABLE_ERRORS +#define uerrf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) +#define uerr(f, ...) usbDbgPuts(f, ##__VA_ARGS__) +#else +#define uerrf(f, ...) do {} while(0) +#define uerr(f, ...) do {} while(0) +#endif + +static void _transfer_completedI(usbh_ep_t *ep, usbh_urb_t *urb, usbh_urbstatus_t status); +static void _try_commit_np(USBHDriver *host); +static void otg_rxfifo_flush(USBHDriver *usbp); +static void otg_txfifo_flush(USBHDriver *usbp, uint32_t fifo); + +/*===========================================================================*/ +/* Little helper functions. */ +/*===========================================================================*/ +static inline void _move_to_pending_queue(usbh_ep_t *ep) { + list_move_tail(&ep->node, ep->pending_list); +} + +static inline usbh_urb_t *_active_urb(usbh_ep_t *ep) { + return list_first_entry(&ep->urb_list, usbh_urb_t, node); +} + +static inline void _save_dt_mask(usbh_ep_t *ep, uint32_t hctsiz) { + ep->dt_mask = hctsiz & HCTSIZ_DPID_MASK; +} + +#if 1 +#define _transfer_completed _transfer_completedI +#else +static inline void _transfer_completed(usbh_ep_t *ep, usbh_urb_t *urb, usbh_urbstatus_t status) { + osalSysLockFromISR(); + _transfer_completedI(ep, urb, status); + osalSysUnlockFromISR(); +} +#endif + +/*===========================================================================*/ +/* Functions called from many places. */ +/*===========================================================================*/ +static void _transfer_completedI(usbh_ep_t *ep, usbh_urb_t *urb, usbh_urbstatus_t status) { + osalDbgCheckClassI(); + + urb->queued = FALSE; + + /* remove URB from EP's queue */ + list_del_init(&urb->node); + + /* Call the callback function now, so that if it calls usbhURBSubmitI, + * the list_empty check below will be false. Also, note that the + * if (list_empty(&ep->node)) { + * ... + * } + * in usbh_lld_urb_submit will be false, since the endpoint is + * still in the active queue. + */ + _usbh_urb_completeI(urb, status); + + if (list_empty(&ep->urb_list)) { + /* no more URBs to process in this EP, remove EP from the host's queue */ + list_del_init(&ep->node); + } else { + /* more URBs to process */ + _move_to_pending_queue(ep); + } +} + +static void _halt_channel(USBHDriver *host, stm32_hc_management_t *hcm, usbh_lld_halt_reason_t reason) { + (void)host; + + if (hcm->halt_reason != USBH_LLD_HALTREASON_NONE) { + uwarnf("\t%s: Repeated halt (original=%d, new=%d)", hcm->ep->name, hcm->halt_reason, reason); + return; + } + +#if CH_DBG_ENABLE_CHECKS + if (usbhEPIsPeriodic(hcm->ep)) { + osalDbgCheck(host->otg->HPTXSTS & HPTXSTS_PTXQSAV_MASK); + } else { + osalDbgCheck(host->otg->HNPTXSTS & HPTXSTS_PTXQSAV_MASK); + } +#endif + + hcm->halt_reason = reason; + hcm->hc->HCCHAR |= HCCHAR_CHENA | HCCHAR_CHDIS; +} + +static void _release_channel(USBHDriver *host, stm32_hc_management_t *hcm) { +// static const char *reason[] = {"XFRC", "XFRC", "NAK", "STALL", "ERROR", "ABORT"}; +// udbgf("\t%s: release (%s)", hcm->ep->name, reason[hcm->halt_reason]); + hcm->hc->HCINTMSK = 0; + host->otg->HAINTMSK &= ~hcm->haintmsk; + hcm->halt_reason = USBH_LLD_HALTREASON_NONE; + if (usbhEPIsPeriodic(hcm->ep)) { + list_add(&hcm->node, &host->ch_free[0]); + } else { + list_add(&hcm->node, &host->ch_free[1]); + } + hcm->ep->xfer.hcm = 0; + hcm->ep = 0; +} + +static bool _activate_ep(USBHDriver *host, usbh_ep_t *ep) { + struct list_head *list; + uint16_t spc; + + osalDbgCheck(ep->xfer.hcm == NULL); + + if (usbhEPIsPeriodic(ep)) { + list = &host->ch_free[0]; + spc = (host->otg->HPTXSTS >> 16) & 0xff; + } else { + list = &host->ch_free[1]; + spc = (host->otg->HNPTXSTS >> 16) & 0xff; + } + + if (list_empty(list)) { + uwarnf("\t%s: No free %s channels", ep->name, usbhEPIsPeriodic(ep) ? "P" : "NP"); + return FALSE; + } + + if (spc <= STM32_USBH_MIN_QSPACE) { + uwarnf("\t%s: No space in %s Queue (spc=%d)", ep->name, usbhEPIsPeriodic(ep) ? "P" : "NP", spc); + return FALSE; + } + + /* get the first channel */ + stm32_hc_management_t *hcm = list_first_entry(list, stm32_hc_management_t, node); + osalDbgCheck((hcm->halt_reason == USBH_LLD_HALTREASON_NONE) && (hcm->ep == NULL)); + + usbh_urb_t *const urb = _active_urb(ep); + uint32_t hcintmsk = ep->hcintmsk; + uint32_t hcchar = ep->hcchar; + uint16_t mps = ep->wMaxPacketSize; + + uint32_t xfer_packets; + uint32_t xfer_len = 0; //Initialize just to shut up a compiler warning + + osalDbgCheck(urb->status == USBH_URBSTATUS_PENDING); + + /* check if the URB is a new one, or we must continue a previously started URB */ + if (urb->queued == FALSE) { + /* prepare EP for a new URB */ + if (ep->type == USBH_EPTYPE_CTRL) { + xfer_len = 8; + ep->xfer.buf = (uint8_t *)urb->setup_buff; + ep->dt_mask = HCTSIZ_DPID_SETUP; + ep->in = FALSE; + ep->xfer.u.ctrl_phase = USBH_LLD_CTRLPHASE_SETUP; + } else { + xfer_len = urb->requestedLength; + ep->xfer.buf = urb->buff; + } + ep->xfer.error_count = 0; + //urb->status = USBH_URBSTATUS_QUEUED; + } else { + osalDbgCheck(urb->requestedLength >= urb->actualLength); + + if (ep->type == USBH_EPTYPE_CTRL) { + switch (ep->xfer.u.ctrl_phase) { + case USBH_LLD_CTRLPHASE_SETUP: + xfer_len = 8; + ep->xfer.buf = (uint8_t *)urb->setup_buff; + ep->dt_mask = HCTSIZ_DPID_SETUP; + break; + case USBH_LLD_CTRLPHASE_DATA: + xfer_len = urb->requestedLength - urb->actualLength; + ep->xfer.buf = (uint8_t *) urb->buff + urb->actualLength; + break; + case USBH_LLD_CTRLPHASE_STATUS: + xfer_len = 0; + ep->dt_mask = HCTSIZ_DPID_DATA1; + ep->xfer.error_count = 0; + break; + default: + osalDbgCheck(0); + } + if (ep->in) { + hcintmsk |= HCINTMSK_DTERRM | HCINTMSK_BBERRM; + hcchar |= HCCHAR_EPDIR; + } + } else { + xfer_len = urb->requestedLength - urb->actualLength; + ep->xfer.buf = (uint8_t *) urb->buff + urb->actualLength; + } + + if (ep->xfer.error_count) + hcintmsk |= HCINTMSK_ACKM; + + } + ep->xfer.partial = 0; + + if (ep->type == USBH_EPTYPE_ISO) { + ep->dt_mask = HCTSIZ_DPID_DATA0; + + /* [USB 2.0 spec, 5.6.4]: A host must not issue more than 1 + * transaction in a (micro)frame for an isochronous endpoint + * unless the endpoint is high-speed, high-bandwidth. + */ + if (xfer_len > mps) + xfer_len = mps; + } else if (xfer_len > 0x7FFFF) { + xfer_len = 0x7FFFF - mps + 1; + } + + /* calculate required packets */ + if (xfer_len) { + xfer_packets = (xfer_len + mps - 1) / mps; + + if (xfer_packets > 0x3FF) { + xfer_packets = 0x3FF; + xfer_len = xfer_packets * mps; + } + } else { + xfer_packets = 1; /* Need 1 packet for transfer length of 0 */ + } + + if (ep->in) + xfer_len = xfer_packets * mps; + + /* Clear old interrupt conditions, + * configure transfer size, + * enable required interrupts */ + stm32_otg_host_chn_t *const hc = hcm->hc; + hc->HCINT = 0xffffffff; + hc->HCTSIZ = ep->dt_mask + | HCTSIZ_PKTCNT(xfer_packets) + | HCTSIZ_XFRSIZ(xfer_len); + hc->HCINTMSK = hcintmsk; + + /* Queue the transfer for the next frame (no effect for non-periodic transfers) */ + if (!(host->otg->HFNUM & 1)) + hcchar |= HCCHAR_ODDFRM; + + /* configure channel characteristics and queue a request */ + hc->HCCHAR = hcchar; + if (ep->in && (xfer_packets > 1)) { + /* For IN transfers, try to queue two back-to-back packets. + * This results in a 1% performance gain for Full Speed transfers + */ + if (--spc > STM32_USBH_MIN_QSPACE) { + hc->HCCHAR |= HCCHAR_CHENA; + } else { + uwarnf("\t%s: Could not queue back-to-back packets", ep->name); + } + } + + if (urb->queued == FALSE) { + urb->queued = TRUE; + udbgf("\t%s: Start (%dB)", ep->name, xfer_len); + } else { + udbgf("\t%s: Restart (%dB)", ep->name, xfer_len); + } + + ep->xfer.len = xfer_len; + ep->xfer.packets = (uint16_t)xfer_packets; + + /* remove the channel from the free list, link endpoint <-> channel and move to the active queue*/ + list_del(&hcm->node); + ep->xfer.hcm = hcm; + hcm->ep = ep; + list_move_tail(&ep->node, ep->active_list); + + + stm32_otg_t *const otg = host->otg; + + /* enable this channel's interrupt and global channel interrupt */ + otg->HAINTMSK |= hcm->haintmsk; + if (ep->in) { + otg->GINTMSK |= GINTMSK_HCM; + } else if (usbhEPIsPeriodic(ep)) { + otg->GINTMSK |= GINTMSK_HCM | GINTMSK_PTXFEM; + } else { + //TODO: write to the FIFO now + otg->GINTMSK |= GINTMSK_HCM | GINTMSK_NPTXFEM; + } + + return TRUE; +} + +static bool _update_urb(usbh_ep_t *ep, uint32_t hctsiz, usbh_urb_t *urb, bool completed) { + uint32_t len; + + if (!completed) { + len = ep->wMaxPacketSize * (ep->xfer.packets - ((hctsiz & HCTSIZ_PKTCNT_MASK) >> 19)); + } else { + if (ep->in) { + len = ep->xfer.len - ((hctsiz & HCTSIZ_XFRSIZ_MASK) >> 0); + } else { + len = ep->xfer.len; + } + osalDbgCheck(len == ep->xfer.partial); //TODO: if len == ep->xfer.partial, use this instead of the above code + } + +#if 1 + osalDbgAssert(urb->actualLength + len <= urb->requestedLength, "what happened?"); +#else + if (urb->actualLength + len > urb->requestedLength) { + uerrf("\t%s: Trimming actualLength %u -> %u", ep->name, urb->actualLength + len, urb->requestedLength); + urb->actualLength = urb->requestedLength; + return TRUE; + } +#endif + + urb->actualLength += len; + if ((urb->actualLength == urb->requestedLength) + || (ep->in && completed && (hctsiz & HCTSIZ_XFRSIZ_MASK))) + return TRUE; + + return FALSE; +} + +static void _try_commit_np(USBHDriver *host) { + usbh_ep_t *item, *tmp; + + list_for_each_entry_safe(item, usbh_ep_t, tmp, &host->ep_pending_lists[USBH_EPTYPE_CTRL], node) { + if (!_activate_ep(host, item)) + return; + } + + list_for_each_entry_safe(item, usbh_ep_t, tmp, &host->ep_pending_lists[USBH_EPTYPE_BULK], node) { + if (!_activate_ep(host, item)) + return; + } +} + +static void _try_commit_p(USBHDriver *host, bool sof) { + usbh_ep_t *item, *tmp; + + list_for_each_entry_safe(item, usbh_ep_t, tmp, &host->ep_pending_lists[USBH_EPTYPE_ISO], node) { + if (!_activate_ep(host, item)) + return; + } + + list_for_each_entry_safe(item, usbh_ep_t, tmp, &host->ep_pending_lists[USBH_EPTYPE_INT], node) { + osalDbgCheck(item); + /* TODO: improve this */ + if (sof && item->xfer.u.frame_counter) + --item->xfer.u.frame_counter; + + if (item->xfer.u.frame_counter == 0) { + if (!_activate_ep(host, item)) + return; + item->xfer.u.frame_counter = item->bInterval; + } + } + + if (list_empty(&host->ep_pending_lists[USBH_EPTYPE_ISO]) + && list_empty(&host->ep_pending_lists[USBH_EPTYPE_INT])) { + host->otg->GINTMSK &= ~GINTMSK_SOFM; + } else { + host->otg->GINTMSK |= GINTMSK_SOFM; + } +} + +static void _purge_queue(USBHDriver *host, struct list_head *list) { + usbh_ep_t *ep, *tmp; + list_for_each_entry_safe(ep, usbh_ep_t, tmp, list, node) { + usbh_urb_t *const urb = _active_urb(ep); + stm32_hc_management_t *const hcm = ep->xfer.hcm; + uwarnf("\t%s: Abort URB, USBH_URBSTATUS_DISCONNECTED", ep->name); + if (hcm) { + uwarnf("\t%s: URB had channel %d assigned, halt_reason = %d", ep->name, hcm - host->channels, hcm->halt_reason); + _release_channel(host, hcm); + _update_urb(ep, hcm->hc->HCTSIZ, urb, FALSE); + } + _transfer_completed(ep, urb, USBH_URBSTATUS_DISCONNECTED); + } +} + +static void _purge_active(USBHDriver *host) { + _purge_queue(host, &host->ep_active_lists[0]); + _purge_queue(host, &host->ep_active_lists[1]); + _purge_queue(host, &host->ep_active_lists[2]); + _purge_queue(host, &host->ep_active_lists[3]); +} + +static void _purge_pending(USBHDriver *host) { + _purge_queue(host, &host->ep_pending_lists[0]); + _purge_queue(host, &host->ep_pending_lists[1]); + _purge_queue(host, &host->ep_pending_lists[2]); + _purge_queue(host, &host->ep_pending_lists[3]); +} + +static uint32_t _write_packet(struct list_head *list, uint32_t space_available) { + usbh_ep_t *ep; + + uint32_t remaining = 0; + + list_for_each_entry(ep, usbh_ep_t, list, node) { + if (ep->in || (ep->xfer.hcm->halt_reason != USBH_LLD_HALTREASON_NONE)) + continue; + + int32_t rem = ep->xfer.len - ep->xfer.partial; + osalDbgCheck(rem >= 0); + if (rem <= 0) + continue; + + remaining += rem; + + if (!space_available) { + if (remaining) + break; + + continue; + } + + /* write one packet only */ + if (rem > ep->wMaxPacketSize) + rem = ep->wMaxPacketSize; + + /* round up to dwords */ + uint32_t words = (rem + 3) / 4; + + if (words > space_available) + words = space_available; + + space_available -= words; + + uint32_t written = words * 4; + if ((int32_t)written > rem) + written = rem; + + volatile uint32_t *dest = ep->xfer.hcm->fifo; + uint32_t *src = (uint32_t *)ep->xfer.buf; + udbgf("\t%s: write %d words (%dB), partial=%d", ep->name, words, written, ep->xfer.partial); + while (words--) { + *dest = *src++; + } + + ep->xfer.buf += written; + ep->xfer.partial += written; + + remaining -= written; + } + + return remaining; +} + + +/*===========================================================================*/ +/* API. */ +/*===========================================================================*/ + +void usbh_lld_ep_object_init(usbh_ep_t *ep) { +/* CTRL(IN) CTRL(OUT) INT(IN) INT(OUT) BULK(IN) BULK(OUT) ISO(IN) ISO(OUT) + * STALL si sólo DAT/STAT si si si si no no ep->type != ISO && (ep->type != CTRL || ctrlphase != SETUP) + * ACK si si si si si si no no ep->type != ISO + * NAK si si si si si si no no ep->type != ISO + * BBERR si no si no si no si no ep->in + * TRERR si si si si si si si no ep->type != ISO || ep->in + * DTERR si no si no si no no no ep->type != ISO && ep->in + * FRMOR no no si si no no si si ep->type = PERIODIC + */ + USBHDriver *host = ep->device->host; + uint32_t hcintmsk = HCINTMSK_CHHM | HCINTMSK_XFRCM | HCINTMSK_AHBERRM; + + switch (ep->type) { + case USBH_EPTYPE_ISO: + hcintmsk |= HCINTMSK_FRMORM; + if (ep->in) { + hcintmsk |= HCINTMSK_TRERRM | HCINTMSK_BBERRM; + } + break; + case USBH_EPTYPE_INT: + hcintmsk |= HCINTMSK_TRERRM | HCINTMSK_FRMORM | HCINTMSK_STALLM | HCINTMSK_NAKM; + if (ep->in) { + hcintmsk |= HCINTMSK_DTERRM | HCINTMSK_BBERRM; + } + ep->xfer.u.frame_counter = 1; + break; + case USBH_EPTYPE_CTRL: + hcintmsk |= HCINTMSK_TRERRM | HCINTMSK_STALLM | HCINTMSK_NAKM; + break; + case USBH_EPTYPE_BULK: + hcintmsk |= HCINTMSK_TRERRM | HCINTMSK_STALLM | HCINTMSK_NAKM; + if (ep->in) { + hcintmsk |= HCINTMSK_DTERRM | HCINTMSK_BBERRM; + } + break; + default: + chDbgCheck(0); + } + ep->active_list = &host->ep_active_lists[ep->type]; + ep->pending_list = &host->ep_pending_lists[ep->type]; + INIT_LIST_HEAD(&ep->urb_list); + INIT_LIST_HEAD(&ep->node); + + ep->hcintmsk = hcintmsk; + ep->hcchar = HCCHAR_CHENA + | HCCHAR_DAD(ep->device->address) + | HCCHAR_MCNT(1) + | HCCHAR_EPTYP(ep->type) + | ((ep->device->speed == USBH_DEVSPEED_LOW) ? HCCHAR_LSDEV : 0) + | (ep->in ? HCCHAR_EPDIR : 0) + | HCCHAR_EPNUM(ep->address) + | HCCHAR_MPS(ep->wMaxPacketSize); +} + +void usbh_lld_ep_open(usbh_ep_t *ep) { + uinfof("\t%s: Open EP", ep->name); + ep->status = USBH_EPSTATUS_OPEN; + osalOsRescheduleS(); +} + +void usbh_lld_ep_close(usbh_ep_t *ep) { + usbh_urb_t *urb, *tmp; + uinfof("\t%s: Closing EP...", ep->name); + list_for_each_entry_safe(urb, usbh_urb_t, tmp, &ep->urb_list, node) { + uinfof("\t%s: Abort URB, USBH_URBSTATUS_DISCONNECTED", ep->name); + _usbh_urb_abort_and_waitS(urb, USBH_URBSTATUS_DISCONNECTED); + } + uinfof("\t%s: Closed", ep->name); + ep->status = USBH_EPSTATUS_CLOSED; + osalOsRescheduleS(); +} + +void usbh_lld_urb_submit(usbh_urb_t *urb) { + usbh_ep_t *const ep = urb->ep; + + /* add the URB to the EP's queue */ + list_add_tail(&urb->node, &ep->urb_list); + + /* check if the EP wasn't in any queue (pending nor active) */ + if (list_empty(&ep->node)) { + + /* add the EP to the pending queue */ + _move_to_pending_queue(ep); + + if (usbhEPIsPeriodic(ep)) { + ep->device->host->otg->GINTMSK |= GINTMSK_SOFM; + } else { + /* try to queue non-periodic transfers */ + _try_commit_np(ep->device->host); + } + } +} + +bool usbh_lld_urb_abort(usbh_urb_t *urb, usbh_urbstatus_t status) { + osalDbgCheck(usbhURBIsBusy(urb)); + + usbh_ep_t *const ep = urb->ep; + osalDbgCheck(ep); + stm32_hc_management_t *const hcm = ep->xfer.hcm; + + if ((hcm != NULL) && (urb == _active_urb(ep))) { + /* This URB is active (channel assigned, top of the EP's URB list) */ + + if (hcm->halt_reason == USBH_LLD_HALTREASON_NONE) { + /* The channel is not being halted */ + urb->status = status; + _halt_channel(ep->device->host, hcm, USBH_LLD_HALTREASON_ABORT); + } else { + /* The channel is being halted, so we can't re-halt it. The CHH interrupt will + * be in charge of completing the transfer, but the URB will not have the specified status. + */ + } + return FALSE; + } + + /* This URB is active, we can cancel it now */ + _transfer_completedI(ep, urb, status); + + return TRUE; +} + + +/*===========================================================================*/ +/* Channel Interrupts. */ +/*===========================================================================*/ + +//CTRL(IN) CTRL(OUT) INT(IN) INT(OUT) BULK(IN) BULK(OUT) ISO(IN) ISO(OUT) +// si si si si si si no no ep->type != ISO && !ep->in +static inline void _ack_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) { + (void)host; + osalDbgAssert(hcm->ep->type != USBH_EPTYPE_ISO, "ACK should not happen in ISO endpoints"); + hcm->ep->xfer.error_count = 0; + hc->HCINTMSK &= ~HCINTMSK_ACKM; + udbgf("\t%s: ACK", hcm->ep->name); +} + +//CTRL(IN) CTRL(OUT) INT(IN) INT(OUT) BULK(IN) BULK(OUT) ISO(IN) ISO(OUT) +// si no si no si no no no ep->type != ISO && ep->in +static inline void _dterr_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) { + (void)host; + osalDbgAssert(hcm->ep->in && (hcm->ep->type != USBH_EPTYPE_ISO), "DTERR should not happen in OUT or ISO endpoints"); +#if 0 + hc->HCINTMSK &= ~(HCINTMSK_DTERRM | HCINTMSK_ACKM); + hcm->ep->xfer.error_count = 0; + _halt_channel(host, hcm, USBH_LLD_HALTREASON_ERROR); +#else + /* restart directly, no need to halt it in this case */ + hcm->ep->xfer.error_count = 0; + hc->HCINTMSK &= ~HCINTMSK_ACKM; + hc->HCCHAR |= HCCHAR_CHENA; +#endif + uerrf("\t%s: DTERR", hcm->ep->name); +} + +//CTRL(IN) CTRL(OUT) INT(IN) INT(OUT) BULK(IN) BULK(OUT) ISO(IN) ISO(OUT) +// si no si no si no si no ep->in +static inline void _bberr_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) { + osalDbgAssert(hcm->ep->in, "BBERR should not happen in OUT endpoints"); + hc->HCINTMSK &= ~HCINTMSK_BBERRM; + hcm->ep->xfer.error_count = 3; + _halt_channel(host, hcm, USBH_LLD_HALTREASON_ERROR); + uerrf("\t%s: BBERR", hcm->ep->name); +} + +///CTRL(IN) CTRL(OUT) INT(IN) INT(OUT) BULK(IN) BULK(OUT) ISO(IN) ISO(OUT) +// si si si si si si si no ep->type != ISO || ep->in +static inline void _trerr_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) { + osalDbgAssert(hcm->ep->in || (hcm->ep->type != USBH_EPTYPE_ISO), "TRERR should not happen in ISO OUT endpoints"); + hc->HCINTMSK &= ~HCINTMSK_TRERRM; + ++hcm->ep->xfer.error_count; + _halt_channel(host, hcm, USBH_LLD_HALTREASON_ERROR); + uerrf("\t%s: TRERR", hcm->ep->name); +} + +//CTRL(IN) CTRL(OUT) INT(IN) INT(OUT) BULK(IN) BULK(OUT) ISO(IN) ISO(OUT) +// no no si si no no si si ep->type = PERIODIC +static inline void _frmor_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) { + osalDbgAssert(usbhEPIsPeriodic(hcm->ep), "FRMOR should not happen in non-periodic endpoints"); + hc->HCINTMSK &= ~HCINTMSK_FRMORM; + hcm->ep->xfer.error_count = 3; + _halt_channel(host, hcm, USBH_LLD_HALTREASON_ERROR); + uerrf("\t%s: FRMOR", hcm->ep->name); +} + +//CTRL(IN) CTRL(OUT) INT(IN) INT(OUT) BULK(IN) BULK(OUT) ISO(IN) ISO(OUT) +// si si si si si si no no ep->type != ISO +static inline void _nak_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) { + osalDbgAssert(hcm->ep->type != USBH_EPTYPE_ISO, "NAK should not happen in ISO endpoints"); + if (!hcm->ep->in || (hcm->ep->type == USBH_EPTYPE_INT)) { + hc->HCINTMSK &= ~HCINTMSK_NAKM; + _halt_channel(host, hcm, USBH_LLD_HALTREASON_NAK); + } else { + /* restart directly, no need to halt it in this case */ + hcm->ep->xfer.error_count = 0; + hc->HCINTMSK &= ~HCINTMSK_ACKM; + hc->HCCHAR |= HCCHAR_CHENA; + } + udbgf("\t%s: NAK", hcm->ep->name); +} + +//CTRL(IN) CTRL(OUT) INT(IN) INT(OUT) BULK(IN) BULK(OUT) ISO(IN) ISO(OUT) +// si sólo DAT/STAT si si si si no no ep->type != ISO && (ep->type != CTRL || ctrlphase != SETUP) +static inline void _stall_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) { + osalDbgAssert(hcm->ep->type != USBH_EPTYPE_ISO, "STALL should not happen in ISO endpoints"); + hc->HCINTMSK &= ~HCINTMSK_STALLM; + _halt_channel(host, hcm, USBH_LLD_HALTREASON_STALL); + uwarnf("\t%s: STALL", hcm->ep->name); +} + +static void _complete_bulk_int(USBHDriver *host, stm32_hc_management_t *hcm, usbh_ep_t *ep, usbh_urb_t *urb, uint32_t hctsiz) { + _release_channel(host, hcm); + _save_dt_mask(ep, hctsiz); + if (_update_urb(ep, hctsiz, urb, TRUE)) { + udbgf("\t%s: done", ep->name); + _transfer_completed(ep, urb, USBH_URBSTATUS_OK); + } else { + osalDbgCheck(urb->requestedLength > 0x7FFFF); + uwarnf("\t%s: incomplete", ep->name); + _move_to_pending_queue(ep); + } + if (usbhEPIsPeriodic(ep)) { + _try_commit_p(host, FALSE); + } else { + _try_commit_np(host); + } +} + +static void _complete_control(USBHDriver *host, stm32_hc_management_t *hcm, usbh_ep_t *ep, usbh_urb_t *urb, uint32_t hctsiz) { + osalDbgCheck(ep->xfer.u.ctrl_phase != USBH_LLD_CTRLPHASE_SETUP); + + _release_channel(host, hcm); + if (ep->xfer.u.ctrl_phase == USBH_LLD_CTRLPHASE_DATA) { + if (_update_urb(ep, hctsiz, urb, TRUE)) { + udbgf("\t%s: DATA done", ep->name); + ep->xfer.u.ctrl_phase = USBH_LLD_CTRLPHASE_STATUS; + ep->in = !ep->in; + } else { + osalDbgCheck(urb->requestedLength > 0x7FFFF); + uwarnf("\t%s: DATA incomplete", ep->name); + _save_dt_mask(ep, hctsiz); + } + _move_to_pending_queue(ep); + } else { + osalDbgCheck(ep->xfer.u.ctrl_phase == USBH_LLD_CTRLPHASE_STATUS); + udbgf("\t%s: STATUS done", ep->name); + _transfer_completed(ep, urb, USBH_URBSTATUS_OK); + } + _try_commit_np(host); +} + +static void _complete_control_setup(USBHDriver *host, stm32_hc_management_t *hcm, usbh_ep_t *ep, usbh_urb_t *urb) { + _release_channel(host, hcm); + if (urb->requestedLength) { + udbgf("\t%s: SETUP done -> DATA", ep->name); + ep->xfer.u.ctrl_phase = USBH_LLD_CTRLPHASE_DATA; + ep->in = *((uint8_t *)urb->setup_buff) & 0x80 ? TRUE : FALSE; + ep->dt_mask = HCTSIZ_DPID_DATA1; + ep->xfer.error_count = 0; + } else { + udbgf("\t%s: SETUP done -> STATUS", ep->name); + ep->in = TRUE; + ep->xfer.u.ctrl_phase = USBH_LLD_CTRLPHASE_STATUS; + } + _move_to_pending_queue(ep); + _try_commit_np(host); +} + +static void _complete_iso(USBHDriver *host, stm32_hc_management_t *hcm, usbh_ep_t *ep, usbh_urb_t *urb, uint32_t hctsiz) { + udbgf("\t%s: done", hcm->ep->name); + _release_channel(host, hcm); + _update_urb(ep, hctsiz, urb, TRUE); + _transfer_completed(ep, urb, USBH_URBSTATUS_OK); + _try_commit_p(host, FALSE); +} + +static inline void _xfrc_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) { + usbh_ep_t *const ep = hcm->ep; + usbh_urb_t *const urb = _active_urb(ep); + osalDbgCheck(urb); + uint32_t hctsiz = hc->HCTSIZ; + + hc->HCINTMSK &= ~HCINTMSK_XFRCM; + + switch (ep->type) { + case USBH_EPTYPE_CTRL: + if (ep->xfer.u.ctrl_phase == USBH_LLD_CTRLPHASE_SETUP) { + _complete_control_setup(host, hcm, ep, urb); + } else if (ep->in) { + _halt_channel(host, hcm, USBH_LLD_HALTREASON_XFRC); + } else { + _complete_control(host, hcm, ep, urb, hctsiz); + } + break; + + case USBH_EPTYPE_BULK: + if (ep->in) { + _halt_channel(host, hcm, USBH_LLD_HALTREASON_XFRC); + } else { + _complete_bulk_int(host, hcm, ep, urb, hctsiz); + } + break; + + case USBH_EPTYPE_INT: + if (ep->in && (hctsiz & HCTSIZ_PKTCNT_MASK)) { + _halt_channel(host, hcm, USBH_LLD_HALTREASON_XFRC); + } else { + _complete_bulk_int(host, hcm, ep, urb, hctsiz); + } + break; + + case USBH_EPTYPE_ISO: + if (ep->in && (hctsiz & HCTSIZ_PKTCNT_MASK)) { + _halt_channel(host, hcm, USBH_LLD_HALTREASON_XFRC); + } else { + _complete_iso(host, hcm, ep, urb, hctsiz); + } + break; + } +} + +static inline void _chh_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) { + + usbh_ep_t *const ep = hcm->ep; + usbh_urb_t *const urb = _active_urb(ep); + osalDbgCheck(urb); + uint32_t hctsiz = hc->HCTSIZ; + usbh_lld_halt_reason_t reason = hcm->halt_reason; + + //osalDbgCheck(reason != USBH_LLD_HALTREASON_NONE); + if (reason == USBH_LLD_HALTREASON_NONE) { + uwarnf("\tCHH: ch=%d, USBH_LLD_HALTREASON_NONE", hcm - host->channels); + return; + } + + if (reason == USBH_LLD_HALTREASON_XFRC) { + osalDbgCheck(ep->in); + switch (ep->type) { + case USBH_EPTYPE_CTRL: + _complete_control(host, hcm, ep, urb, hctsiz); + break; + case USBH_EPTYPE_BULK: + case USBH_EPTYPE_INT: + _complete_bulk_int(host, hcm, ep, urb, hctsiz); + break; + case USBH_EPTYPE_ISO: + _complete_iso(host, hcm, ep, urb, hctsiz); + break; + } + } else { + _release_channel(host, hcm); + _save_dt_mask(ep, hctsiz); + bool done = _update_urb(ep, hctsiz, urb, FALSE); + + switch (reason) { + case USBH_LLD_HALTREASON_NAK: + if ((ep->type == USBH_EPTYPE_INT) && ep->in) { + _transfer_completed(ep, urb, USBH_URBSTATUS_TIMEOUT); + } else { + ep->xfer.error_count = 0; + _move_to_pending_queue(ep); + } + break; + + case USBH_LLD_HALTREASON_STALL: + if ((ep->type == USBH_EPTYPE_CTRL) && (ep->xfer.u.ctrl_phase == USBH_LLD_CTRLPHASE_SETUP)) { + uerrf("\t%s: Faulty device: STALLed SETUP phase", ep->name); + } + _transfer_completed(ep, urb, USBH_URBSTATUS_STALL); + break; + + case USBH_LLD_HALTREASON_ERROR: + if ((ep->type == USBH_EPTYPE_ISO) || done || (ep->xfer.error_count >= 3)) { + _transfer_completed(ep, urb, USBH_URBSTATUS_ERROR); + } else { + uerrf("\t%s: err=%d, done=%d, retry", ep->name, ep->xfer.error_count, done); + _move_to_pending_queue(ep); + } + break; + + case USBH_LLD_HALTREASON_ABORT: + uwarnf("\t%s: Abort", ep->name); + _transfer_completed(ep, urb, urb->status); + break; + + default: + osalDbgCheck(0); + break; + } + + if (usbhEPIsPeriodic(ep)) { + _try_commit_p(host, FALSE); + } else { + _try_commit_np(host); + } + } +} + +static void _hcint_n_int(USBHDriver *host, uint8_t chn) { + + stm32_hc_management_t *const hcm = &host->channels[chn]; + stm32_otg_host_chn_t *const hc = hcm->hc; + + uint32_t hcint = hc->HCINT; + hcint &= hc->HCINTMSK; + hc->HCINT = hcint; + + osalDbgCheck((hcint & HCINTMSK_AHBERRM) == 0); + osalDbgCheck(hcm->ep); + + if (hcint & HCINTMSK_STALLM) + _stall_int(host, hcm, hc); + if (hcint & HCINTMSK_NAKM) + _nak_int(host, hcm, hc); + if (hcint & HCINTMSK_ACKM) + _ack_int(host, hcm, hc); + if (hcint & HCINTMSK_TRERRM) + _trerr_int(host, hcm, hc); + if (hcint & HCINTMSK_BBERRM) + _bberr_int(host, hcm, hc); + if (hcint & HCINTMSK_FRMORM) + _frmor_int(host, hcm, hc); + if (hcint & HCINTMSK_DTERRM) + _dterr_int(host, hcm, hc); + if (hcint & HCINTMSK_XFRCM) + _xfrc_int(host, hcm, hc); + if (hcint & HCINTMSK_CHHM) + _chh_int(host, hcm, hc); +} + +static inline void _hcint_int(USBHDriver *host) { + uint32_t haint; + + haint = host->otg->HAINT; + haint &= host->otg->HAINTMSK; + + if (!haint) { + uerrf("HAINT=%08x, HAINTMSK=%08x", host->otg->HAINT, host->otg->HAINTMSK); + return; + } + +#if 1 //channel lookup loop + uint8_t i; + for (i = 0; haint && (i < host->channels_number); i++) { + if (haint & (1 << i)) { + _hcint_n_int(host, i); + haint &= ~(1 << i); + } + } +#else //faster calculation, with __CLZ (count leading zeroes) + while (haint) { + uint8_t chn = (uint8_t)(31 - __CLZ(haint)); + osalDbgAssert(chn < host->channels_number, "what?"); + haint &= ~host->channels[chn].haintmsk; + _hcint_n_int(host, chn); + } +#endif +} + + +/*===========================================================================*/ +/* Host interrupts. */ +/*===========================================================================*/ +static inline void _sof_int(USBHDriver *host) { + udbg("SOF"); + _try_commit_p(host, TRUE); +} + +static inline void _rxflvl_int(USBHDriver *host) { + + stm32_otg_t *const otg = host->otg; + + otg->GINTMSK &= ~GINTMSK_RXFLVLM; + while (otg->GINTSTS & GINTSTS_RXFLVL) { + uint32_t grxstsp = otg->GRXSTSP; + osalDbgCheck((grxstsp & GRXSTSP_CHNUM_MASK) < host->channels_number); + stm32_hc_management_t *const hcm = &host->channels[grxstsp & GRXSTSP_CHNUM_MASK]; + uint32_t hctsiz = hcm->hc->HCTSIZ; + + if ((grxstsp & GRXSTSP_PKTSTS_MASK) == GRXSTSP_PKTSTS(2)) { + /* 0010: IN data packet received */ + usbh_ep_t *const ep = hcm->ep; + osalDbgCheck(ep); + + /* restart the channel ASAP */ + if (hctsiz & HCTSIZ_PKTCNT_MASK) { +#if CH_DBG_ENABLE_CHECKS + if (usbhEPIsPeriodic(ep)) { + osalDbgCheck(host->otg->HPTXSTS & HPTXSTS_PTXQSAV_MASK); + } else { + osalDbgCheck(host->otg->HNPTXSTS & HPTXSTS_PTXQSAV_MASK); + } +#endif + hcm->hc->HCCHAR |= HCCHAR_CHENA; + } + + udbgf("\t%s: RXFLVL rx=%dB, rem=%dB (%dpkts)", + ep->name, + (grxstsp & GRXSTSP_BCNT_MASK) >> 4, + (hctsiz & HCTSIZ_XFRSIZ_MASK), + (hctsiz & HCTSIZ_PKTCNT_MASK) >> 19); + + /* Read */ + uint32_t *dest = (uint32_t *)ep->xfer.buf; + volatile uint32_t *const src = hcm->fifo; + + uint32_t bcnt = (grxstsp & GRXSTSP_BCNT_MASK) >> GRXSTSP_BCNT_OFF; + osalDbgCheck(bcnt + ep->xfer.partial <= ep->xfer.len); + + //TODO: optimize this + uint32_t words = bcnt / 4; + uint8_t bytes = bcnt & 3; + while (words--) { + *dest++ = *src; + } + if (bytes) { + uint32_t r = *src; + uint8_t *bsrc = (uint8_t *)&r; + uint8_t *bdest = (uint8_t *)dest; + do { + *bdest++ = *bsrc++; + } while (--bytes); + } + + ep->xfer.buf += bcnt; + ep->xfer.partial += bcnt; + +#if 0 //STM32_USBH_CHANNELS_NP > 1 + /* check bug */ + if (hctsiz & HCTSIZ_PKTCNT_MASK) { + uint32_t pkt = (hctsiz & HCTSIZ_PKTCNT_MASK) >> 19; + uint32_t siz = (hctsiz & HCTSIZ_XFRSIZ_MASK); + if (pkt * ep->wMaxPacketSize != siz) { + uerrf("\t%s: whatttt???", ep->name); + } + } +#endif + +#if USBH_DEBUG_ENABLE && USBH_LLD_DEBUG_ENABLE_ERRORS + } else { + /* 0011: IN transfer completed (triggers an interrupt) + * 0101: Data toggle error (triggers an interrupt) + * 0111: Channel halted (triggers an interrupt) + */ + switch (grxstsp & GRXSTSP_PKTSTS_MASK) { + case GRXSTSP_PKTSTS(3): + case GRXSTSP_PKTSTS(5): + case GRXSTSP_PKTSTS(7): + break; + default: + uerrf("\tRXFLVL: ch=%d, UNK=%d", grxstsp & GRXSTSP_CHNUM_MASK, (grxstsp & GRXSTSP_PKTSTS_MASK) >> 17); + break; + } +#endif + } + } + otg->GINTMSK |= GINTMSK_RXFLVLM; +} + +static inline void _nptxfe_int(USBHDriver *host) { + uint32_t rem; + stm32_otg_t *const otg = host->otg; + + rem = _write_packet(&host->ep_active_lists[USBH_EPTYPE_CTRL], + otg->HNPTXSTS & HPTXSTS_PTXFSAVL_MASK); + + rem += _write_packet(&host->ep_active_lists[USBH_EPTYPE_BULK], + otg->HNPTXSTS & HPTXSTS_PTXFSAVL_MASK); + +// if (rem) +// otg->GINTMSK |= GINTMSK_NPTXFEM; + + if (!rem) + otg->GINTMSK &= ~GINTMSK_NPTXFEM; + +} + +static inline void _ptxfe_int(USBHDriver *host) { + //TODO: implement + (void)host; + uinfo("PTXFE"); +} + +static inline void _discint_int(USBHDriver *host) { + uint32_t hprt = host->otg->HPRT; + + uwarn("\tDISCINT"); + + if (!(hprt & HPRT_PCSTS)) { + host->rootport.lld_status &= ~(USBH_PORTSTATUS_CONNECTION | USBH_PORTSTATUS_ENABLE); + host->rootport.lld_c_status |= USBH_PORTSTATUS_C_CONNECTION | USBH_PORTSTATUS_C_ENABLE; + } + _purge_active(host); + _purge_pending(host); +} + +static inline void _hprtint_int(USBHDriver *host) { + stm32_otg_t *const otg = host->otg; + uint32_t hprt = otg->HPRT; + + /* note: writing PENA = 1 actually disables the port */ + uint32_t hprt_clr = hprt & ~(HPRT_PENA | HPRT_PCDET | HPRT_PENCHNG | HPRT_POCCHNG); + + if (hprt & HPRT_PCDET) { + hprt_clr |= HPRT_PCDET; + if (hprt & HPRT_PCSTS) { + uinfo("\tHPRT: Port connection detected"); + host->rootport.lld_status |= USBH_PORTSTATUS_CONNECTION; + host->rootport.lld_c_status |= USBH_PORTSTATUS_C_CONNECTION; + } else { + uinfo("\tHPRT: Port disconnection detected"); + } + } + + if (hprt & HPRT_PENCHNG) { + hprt_clr |= HPRT_PENCHNG; + if (hprt & HPRT_PENA) { + uinfo("\tHPRT: Port enabled"); + host->rootport.lld_status |= USBH_PORTSTATUS_ENABLE; + host->rootport.lld_status &= ~(USBH_PORTSTATUS_HIGH_SPEED | USBH_PORTSTATUS_LOW_SPEED); + + /* Make sure the FIFOs are flushed. */ + otg_txfifo_flush(host, 0x10); + otg_rxfifo_flush(host); + + /* Clear all pending HC Interrupts */ + uint8_t i; + for (i = 0; i < host->channels_number; i++) { + otg->hc[i].HCINTMSK = 0; + otg->hc[i].HCINT = 0xFFFFFFFF; + } + + /* configure speed */ + if ((hprt & HPRT_PSPD_MASK) == HPRT_PSPD_LS) { + host->rootport.lld_status |= USBH_PORTSTATUS_LOW_SPEED; + otg->HFIR = 6000; + otg->HCFG = (otg->HCFG & ~HCFG_FSLSPCS_MASK) | HCFG_FSLSPCS_6; + } else { + otg->HFIR = 48000; + otg->HCFG = (otg->HCFG & ~HCFG_FSLSPCS_MASK) | HCFG_FSLSPCS_48; + } + } else { + if (hprt & HPRT_PCSTS) { + if (hprt & HPRT_POCA) { + uerr("\tHPRT: Port disabled due to overcurrent"); + } else { + uerr("\tHPRT: Port disabled due to port babble"); + } + } else { + uerr("\tHPRT: Port disabled due to disconnect"); + } + + _purge_active(host); + _purge_pending(host); + + host->rootport.lld_status &= ~USBH_PORTSTATUS_ENABLE; + } + host->rootport.lld_c_status |= USBH_PORTSTATUS_C_ENABLE; + } + + if (hprt & HPRT_POCCHNG) { + hprt_clr |= HPRT_POCCHNG; + if (hprt & HPRT_POCA) { + uerr("\tHPRT: Overcurrent"); + host->rootport.lld_status |= USBH_PORTSTATUS_OVERCURRENT; + } else { + udbg("\tHPRT: Clear overcurrent"); + host->rootport.lld_status &= ~USBH_PORTSTATUS_OVERCURRENT; + } + host->rootport.lld_c_status |= USBH_PORTSTATUS_C_OVERCURRENT; + } + + otg->HPRT = hprt_clr; +} + +static void usb_lld_serve_interrupt(USBHDriver *host) { + osalDbgCheck(host && (host->status != USBH_STATUS_STOPPED)); + + stm32_otg_t *const otg = host->otg; + uint32_t gintsts = otg->GINTSTS; + + /* check host mode */ + if (!(gintsts & GINTSTS_CMOD)) { + uerr("Device mode"); + otg->GINTSTS = gintsts; + return; + } + + /* check mismatch */ + if (gintsts & GINTSTS_MMIS) { + uerr("Mode Mismatch"); + otg->GINTSTS = gintsts; + return; + } + + gintsts &= otg->GINTMSK; + if (!gintsts) { + uwarnf("GINTSTS=%08x, GINTMSK=%08x", otg->GINTSTS, otg->GINTMSK); + return; + } +// otg->GINTMSK &= ~(GINTMSK_NPTXFEM | GINTMSK_PTXFEM); + otg->GINTSTS = gintsts; + + if (gintsts & GINTSTS_SOF) + _sof_int(host); + if (gintsts & GINTSTS_RXFLVL) + _rxflvl_int(host); + if (gintsts & GINTSTS_HPRTINT) + _hprtint_int(host); + if (gintsts & GINTSTS_DISCINT) + _discint_int(host); + if (gintsts & GINTSTS_HCINT) + _hcint_int(host); + if (gintsts & GINTSTS_NPTXFE) + _nptxfe_int(host); + if (gintsts & GINTSTS_PTXFE) + _ptxfe_int(host); + if (gintsts & GINTSTS_IPXFR) { + uerr("IPXFRM"); + } +} + + +/*===========================================================================*/ +/* Interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_USBH_USE_OTG1 +OSAL_IRQ_HANDLER(STM32_OTG1_HANDLER) { + OSAL_IRQ_PROLOGUE(); + osalSysLockFromISR(); + usb_lld_serve_interrupt(&USBHD1); + osalSysUnlockFromISR(); + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if STM32_USBH_USE_OTG2 +OSAL_IRQ_HANDLER(STM32_OTG2_HANDLER) { + OSAL_IRQ_PROLOGUE(); + osalSysLockFromISR(); + usb_lld_serve_interrupt(&USBHD2); + osalSysUnlockFromISR(); + OSAL_IRQ_EPILOGUE(); +} +#endif + + +/*===========================================================================*/ +/* Initialization functions. */ +/*===========================================================================*/ +static void otg_core_reset(USBHDriver *usbp) { + stm32_otg_t *const otgp = usbp->otg; + + /* Wait AHB idle condition.*/ + while ((otgp->GRSTCTL & GRSTCTL_AHBIDL) == 0) + ; + + osalSysPolledDelayX(64); + + /* Core reset and delay of at least 3 PHY cycles.*/ + otgp->GRSTCTL = GRSTCTL_CSRST; + while ((otgp->GRSTCTL & GRSTCTL_CSRST) != 0) + ; + + osalSysPolledDelayX(24); + + /* Wait AHB idle condition.*/ + while ((otgp->GRSTCTL & GRSTCTL_AHBIDL) == 0) + ; +} + +static void otg_rxfifo_flush(USBHDriver *usbp) { + stm32_otg_t *const otgp = usbp->otg; + + otgp->GRSTCTL = GRSTCTL_RXFFLSH; + while ((otgp->GRSTCTL & GRSTCTL_RXFFLSH) != 0) + ; + /* Wait for 3 PHY Clocks.*/ + osalSysPolledDelayX(24); +} + +static void otg_txfifo_flush(USBHDriver *usbp, uint32_t fifo) { + stm32_otg_t *const otgp = usbp->otg; + + otgp->GRSTCTL = GRSTCTL_TXFNUM(fifo) | GRSTCTL_TXFFLSH; + while ((otgp->GRSTCTL & GRSTCTL_TXFFLSH) != 0) + ; + /* Wait for 3 PHY Clocks.*/ + osalSysPolledDelayX(24); +} + +static void _init(USBHDriver *host) { + int i; + + usbhObjectInit(host); + +#if STM32_USBH_USE_OTG1 +#if STM32_USBH_USE_OTG2 + if (&USBHD1 == host) { +#endif + host->otg = OTG_FS; + host->channels_number = STM32_OTG1_CHANNELS_NUMBER; +#if STM32_USBH_USE_OTG2 + } +#endif +#endif + +#if STM32_USBH_USE_OTG2 +#if STM32_USBH_USE_OTG1 + if (&USBHD2 == host) { +#endif + host->otg = OTG_HS; + host->channels_number = STM32_OTG2_CHANNELS_NUMBER; +#if STM32_USBH_USE_OTG1 + } +#endif +#endif + INIT_LIST_HEAD(&host->ch_free[0]); + INIT_LIST_HEAD(&host->ch_free[1]); + for (i = 0; i < host->channels_number; i++) { + host->channels[i].haintmsk = 1 << i; + host->channels[i].hc = &host->otg->hc[i]; + host->channels[i].fifo = host->otg->FIFO[i]; + if (i < STM32_USBH_CHANNELS_NP) { + list_add_tail(&host->channels[i].node, &host->ch_free[1]); + } else { + list_add_tail(&host->channels[i].node, &host->ch_free[0]); + } + } + for (i = 0; i < 4; i++) { + INIT_LIST_HEAD(&host->ep_active_lists[i]); + INIT_LIST_HEAD(&host->ep_pending_lists[i]); + } +} + +void usbh_lld_init(void) { +#if STM32_USBH_USE_OTG1 + _init(&USBHD1); +#endif +#if STM32_USBH_USE_OTG2 + _init(&USBHD2); +#endif +} + +static void _usbh_start(USBHDriver *usbh) { + stm32_otg_t *const otgp = usbh->otg; + + /* Clock activation.*/ +#if STM32_USBH_USE_OTG1 +#if STM32_USBH_USE_OTG2 + if (&USBHD1 == usbh) { +#endif + /* OTG FS clock enable and reset.*/ + rccEnableOTG_FS(FALSE); + rccResetOTG_FS(); + + otgp->GINTMSK = 0; + + /* Enables IRQ vector.*/ + nvicEnableVector(STM32_OTG1_NUMBER, STM32_USB_OTG1_IRQ_PRIORITY); +#if STM32_USBH_USE_OTG2 + } +#endif +#endif + +#if STM32_USBH_USE_OTG2 +#if STM32_USBH_USE_OTG1 + if (&USBHD2 == usbh) { +#endif + /* OTG HS clock enable and reset.*/ + rccEnableOTG_HS(FALSE); + rccResetOTG_HS(); + + otgp->GINTMSK = 0; + + /* Enables IRQ vector.*/ + nvicEnableVector(STM32_OTG2_NUMBER, STM32_USB_OTG2_IRQ_PRIORITY); +#if STM32_USBH_USE_OTG1 + } +#endif +#endif + + otgp->GUSBCFG = GUSBCFG_PHYSEL | GUSBCFG_TRDT(5); + + otg_core_reset(usbh); + + otgp->GCCFG = GCCFG_PWRDWN; + + /* Forced host mode. */ + otgp->GUSBCFG = GUSBCFG_FHMOD | GUSBCFG_PHYSEL | GUSBCFG_TRDT(5); + + /* PHY enabled.*/ + otgp->PCGCCTL = 0; + + /* Internal FS PHY activation.*/ +#if defined(BOARD_OTG_NOVBUSSENS) + otgp->GCCFG = GCCFG_NOVBUSSENS | GCCFG_PWRDWN; +#else + otgp->GCCFG = GCCFG_PWRDWN; +#endif + + /* 48MHz 1.1 PHY.*/ + otgp->HCFG = HCFG_FSLSS | HCFG_FSLSPCS_48; + + /* Interrupts on FIFOs half empty.*/ + otgp->GAHBCFG = 0; + + otgp->GOTGINT = 0xFFFFFFFF; + + otgp->HPRT |= HPRT_PPWR; + + /* without this delay, the FIFO sizes are set INcorrectly */ + osalThreadSleepS(MS2ST(200)); + +#define HNPTXFSIZ DIEPTXF0 +#if STM32_USBH_USE_OTG1 +#if STM32_USBH_USE_OTG2 + if (&USBHD1 == usbh) { +#endif + otgp->GRXFSIZ = GRXFSIZ_RXFD(STM32_OTG1_RXFIFO_SIZE / 4); + otgp->HNPTXFSIZ = HPTXFSIZ_PTXSA((STM32_OTG1_RXFIFO_SIZE / 4)) | HPTXFSIZ_PTXFD(STM32_OTG1_NPTXFIFO_SIZE / 4); + otgp->HPTXFSIZ = HPTXFSIZ_PTXSA((STM32_OTG1_RXFIFO_SIZE / 4) + (STM32_OTG1_NPTXFIFO_SIZE / 4)) | HPTXFSIZ_PTXFD(STM32_OTG1_PTXFIFO_SIZE / 4); +#if STM32_USBH_USE_OTG2 + } +#endif +#endif +#if STM32_USBH_USE_OTG2 +#if STM32_USBH_USE_OTG1 + if (&USBHD2 == usbh) { +#endif + otgp->GRXFSIZ = GRXFSIZ_RXFD(STM32_OTG2_RXFIFO_SIZE / 4); + otgp->HNPTXFSIZ = HPTXFSIZ_PTXSA((STM32_OTG2_RXFIFO_SIZE / 4)) | HPTXFSIZ_PTXFD(STM32_OTG2_NPTXFIFO_SIZE / 4); + otgp->HPTXFSIZ = HPTXFSIZ_PTXSA((STM32_OTG2_RXFIFO_SIZE / 4) + (STM32_OTG2_NPTXFIFO_SIZE / 4)) | HPTXFSIZ_PTXFD(STM32_OTG2_PTXFIFO_SIZE / 4); +#if STM32_USBH_USE_OTG1 + } +#endif +#endif + + otg_txfifo_flush(usbh, 0x10); + otg_rxfifo_flush(usbh); + + otgp->GINTSTS = 0xffffffff; + otgp->GINTMSK = GINTMSK_DISCM /*| GINTMSK_PTXFEM*/ | GINTMSK_HCM | GINTMSK_HPRTM + /*| GINTMSK_IPXFRM | GINTMSK_NPTXFEM*/ | GINTMSK_RXFLVLM + /*| GINTMSK_SOFM */ | GINTMSK_MMISM; + + usbh->rootport.lld_status = USBH_PORTSTATUS_POWER; + usbh->rootport.lld_c_status = 0; + + /* Global interrupts enable.*/ + otgp->GAHBCFG |= GAHBCFG_GINTMSK; +} + +void usbh_lld_start(USBHDriver *usbh) { + if (usbh->status != USBH_STATUS_STOPPED) return; + _usbh_start(usbh); +} + +/*===========================================================================*/ +/* Root Hub request handler. */ +/*===========================================================================*/ +usbh_urbstatus_t usbh_lld_root_hub_request(USBHDriver *usbh, uint8_t bmRequestType, uint8_t bRequest, + uint16_t wvalue, uint16_t windex, uint16_t wlength, uint8_t *buf) { + + uint16_t typereq = (bmRequestType << 8) | bRequest; + + switch (typereq) { + case ClearHubFeature: + switch (wvalue) { + case USBH_HUB_FEAT_C_HUB_LOCAL_POWER: + case USBH_HUB_FEAT_C_HUB_OVER_CURRENT: + break; + default: + osalDbgAssert(0, "invalid wvalue"); + } + break; + + case ClearPortFeature: + chDbgAssert(windex == 1, "invalid windex"); + + osalSysLock(); + switch (wvalue) { + case USBH_PORT_FEAT_ENABLE: + case USBH_PORT_FEAT_SUSPEND: + case USBH_PORT_FEAT_POWER: + chDbgAssert(0, "unimplemented"); /* TODO */ + break; + + case USBH_PORT_FEAT_INDICATOR: + chDbgAssert(0, "unsupported"); + break; + + case USBH_PORT_FEAT_C_CONNECTION: + usbh->rootport.lld_c_status &= ~USBH_PORTSTATUS_C_CONNECTION; + break; + + case USBH_PORT_FEAT_C_RESET: + usbh->rootport.lld_c_status &= ~USBH_PORTSTATUS_C_RESET; + break; + + case USBH_PORT_FEAT_C_ENABLE: + usbh->rootport.lld_c_status &= ~USBH_PORTSTATUS_C_ENABLE; + break; + + case USBH_PORT_FEAT_C_SUSPEND: + usbh->rootport.lld_c_status &= ~USBH_PORTSTATUS_C_SUSPEND; + break; + + case USBH_PORT_FEAT_C_OVERCURRENT: + usbh->rootport.lld_c_status &= USBH_PORTSTATUS_C_OVERCURRENT; + break; + + default: + osalDbgAssert(0, "invalid wvalue"); + break; + } + osalOsRescheduleS(); + osalSysUnlock(); + break; + + case GetHubDescriptor: + /*dev_dbg(hsotg->dev, "GetHubDescriptor\n"); + hub_desc = (struct usb_hub_descriptor *)buf; + hub_desc->bDescLength = 9; + hub_desc->bDescriptorType = USB_DT_HUB; + hub_desc->bNbrPorts = 1; + hub_desc->wHubCharacteristics = + cpu_to_le16(HUB_CHAR_COMMON_LPSM | + HUB_CHAR_INDV_PORT_OCPM); + hub_desc->bPwrOn2PwrGood = 1; + hub_desc->bHubContrCurrent = 0; + hub_desc->u.hs.DeviceRemovable[0] = 0; + hub_desc->u.hs.DeviceRemovable[1] = 0xff;*/ + break; + + case GetHubStatus: + osalDbgCheck(wlength >= 4); + *(uint32_t *)buf = 0; + break; + + case GetPortStatus: + chDbgAssert(windex == 1, "invalid windex"); + osalDbgCheck(wlength >= 4); + osalSysLock(); + *(uint32_t *)buf = usbh->rootport.lld_status | (usbh->rootport.lld_c_status << 16); + osalOsRescheduleS(); + osalSysUnlock(); + break; + + case SetHubFeature: + chDbgAssert(0, "unsupported"); + break; + + case SetPortFeature: + chDbgAssert(windex == 1, "invalid windex"); + + switch (wvalue) { + case USBH_PORT_FEAT_TEST: + case USBH_PORT_FEAT_SUSPEND: + case USBH_PORT_FEAT_POWER: + chDbgAssert(0, "unimplemented"); /* TODO */ + break; + + case USBH_PORT_FEAT_RESET: { + osalSysLock(); + stm32_otg_t *const otg = usbh->otg; + uint32_t hprt; + otg->PCGCCTL = 0; + hprt = otg->HPRT; + /* note: writing PENA = 1 actually disables the port */ + hprt &= ~(HPRT_PSUSP | HPRT_PENA | HPRT_PCDET | HPRT_PENCHNG | HPRT_POCCHNG ); + otg->HPRT = hprt | HPRT_PRST; + osalThreadSleepS(MS2ST(60)); + otg->HPRT = hprt; + usbh->rootport.lld_c_status |= USBH_PORTSTATUS_C_RESET; + osalOsRescheduleS(); + osalSysUnlock(); + } break; + + case USBH_PORT_FEAT_INDICATOR: + chDbgAssert(0, "unsupported"); + break; + + default: + osalDbgAssert(0, "invalid wvalue"); + break; + } + break; + + default: + osalDbgAssert(0, "invalid typereq"); + break; + } + + return USBH_URBSTATUS_OK; +} + +uint8_t usbh_lld_roothub_get_statuschange_bitmap(USBHDriver *usbh) { + osalSysLock(); + if (usbh->rootport.lld_c_status) { + osalOsRescheduleS(); + osalSysUnlock(); + return 1 << 1; + } + osalOsRescheduleS(); + osalSysUnlock(); + return 0; +} + + +#endif diff --git a/os/hal/ports/STM32/LLD/USBHv1/hal_usbh_lld.h b/os/hal/ports/STM32/LLD/USBHv1/hal_usbh_lld.h new file mode 100644 index 0000000..e8df749 --- /dev/null +++ b/os/hal/ports/STM32/LLD/USBHv1/hal_usbh_lld.h @@ -0,0 +1,153 @@ +/* + ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio + Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#ifndef USBH_LLD_H_ +#define USBH_LLD_H_ + +#include "hal.h" + +#if HAL_USE_USBH + +#include "osal.h" +#include "stm32_otg.h" + +/* TODO: + * + * - Implement ISO/INT OUT and test + * - Consider DMA mode for OTG_HS, consider external PHY for HS. + * - Implement a data pump thread, so we don't have to copy data from the ISR + * This might be a bad idea for small endpoint packet sizes (the context switch + * could be longer than the copy) + */ + +typedef enum { + USBH_LLD_CTRLPHASE_SETUP, + USBH_LLD_CTRLPHASE_DATA, + USBH_LLD_CTRLPHASE_STATUS +} usbh_lld_ctrlphase_t; + +typedef enum { + USBH_LLD_HALTREASON_NONE, + USBH_LLD_HALTREASON_XFRC, + USBH_LLD_HALTREASON_NAK, + USBH_LLD_HALTREASON_STALL, + USBH_LLD_HALTREASON_ERROR, + USBH_LLD_HALTREASON_ABORT +} usbh_lld_halt_reason_t; + + +typedef struct stm32_hc_management { + struct list_head node; + + stm32_otg_host_chn_t *hc; + volatile uint32_t *fifo; + usbh_ep_t *ep; + uint16_t haintmsk; + usbh_lld_halt_reason_t halt_reason; +} stm32_hc_management_t; + + +#define _usbhdriver_ll_data \ + stm32_otg_t *otg; \ + /* channels */ \ + uint8_t channels_number; \ + stm32_hc_management_t channels[STM32_OTG2_CHANNELS_NUMBER]; \ + struct list_head ch_free[2]; \ + /* Enpoints being processed */ \ + struct list_head ep_active_lists[4]; \ + /* Pending endpoints */ \ + struct list_head ep_pending_lists[4]; + + +#define _usbh_ep_ll_data \ + struct list_head *active_list; /* shortcut to ep list */ \ + struct list_head *pending_list; /* shortcut to ep list */ \ + struct list_head urb_list; /* list of URBs queued in this EP */ \ + struct list_head node; /* this EP */ \ + uint32_t hcintmsk; \ + uint32_t hcchar; \ + uint32_t dt_mask; /* data-toggle mask */ \ + /* current transfer */ \ + struct { \ + stm32_hc_management_t *hcm; /* assigned channel */ \ + uint32_t len; /* this transfer's total length */ \ + uint8_t *buf; /* this transfer's buffer */ \ + uint32_t partial; /* this transfer's partial length */\ + uint16_t packets; /* packets allocated */ \ + union { \ + uint32_t frame_counter; /* frame counter (for INT) */ \ + usbh_lld_ctrlphase_t ctrl_phase; /* control phase (for CTRL) */ \ + } u; \ + uint8_t error_count; /* error count */ \ + } xfer; + + + + + +#define _usbh_port_ll_data \ + uint16_t lld_c_status; \ + uint16_t lld_status; + +#define _usbh_device_ll_data + +#define _usbh_hub_ll_data + +#define _usbh_urb_ll_data \ + struct list_head node; \ + bool queued; + + +#define usbh_lld_urb_object_init(urb) \ + do { \ + osalDbgAssert(((uint32_t)urb->buff & 3) == 0, \ + "use USBH_DEFINE_BUFFER() to declare the IO buffers"); \ + urb->queued = FALSE; \ + } while (0) + + +#define usbh_lld_urb_object_reset(urb) \ + do { \ + osalDbgAssert(urb->queued == FALSE, "wrong state"); \ + osalDbgAssert(((uint32_t)urb->buff & 3) == 0, \ + "use USBH_DEFINE_BUFFER() to declare the IO buffers"); \ + } while (0) + + + +void usbh_lld_init(void); +void usbh_lld_start(USBHDriver *usbh); +void usbh_lld_ep_object_init(usbh_ep_t *ep); +void usbh_lld_ep_open(usbh_ep_t *ep); +void usbh_lld_ep_close(usbh_ep_t *ep); +void usbh_lld_urb_submit(usbh_urb_t *urb); +bool usbh_lld_urb_abort(usbh_urb_t *urb, usbh_urbstatus_t status); +usbh_urbstatus_t usbh_lld_root_hub_request(USBHDriver *usbh, uint8_t bmRequestType, uint8_t bRequest, + uint16_t wvalue, uint16_t windex, uint16_t wlength, uint8_t *buf); +uint8_t usbh_lld_roothub_get_statuschange_bitmap(USBHDriver *usbh); + +#define usbh_lld_epreset(ep) do {(ep)->dt_mask = HCTSIZ_DPID_DATA0;} while (0); + +#ifdef __IAR_SYSTEMS_ICC__ +#define USBH_LLD_DEFINE_BUFFER(type, name) type name +#else +#define USBH_LLD_DEFINE_BUFFER(type, name) type name __attribute__((aligned(4))) +#endif + +#endif + +#endif /* USBH_LLD_H_ */ diff --git a/os/hal/ports/STM32/LLD/USBHv1/stm32_otg.h b/os/hal/ports/STM32/LLD/USBHv1/stm32_otg.h deleted file mode 100644 index 268c9bf..0000000 --- a/os/hal/ports/STM32/LLD/USBHv1/stm32_otg.h +++ /dev/null @@ -1,929 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -/** - * @file stm32_otg.h - * @brief STM32 OTG registers layout header. - * - * @addtogroup USB - * @{ - */ - - -#ifndef _STM32_OTG_H_ -#define _STM32_OTG_H_ - -/** - * @brief Number of the implemented endpoints in OTG_FS. - * @details This value does not include the endpoint 0 that is always present. - */ -#define STM32_OTG1_ENDOPOINTS_NUMBER 3 - -/** - * @brief Number of the implemented endpoints in OTG_HS. - * @details This value does not include the endpoint 0 that is always present. - */ -#define STM32_OTG2_ENDOPOINTS_NUMBER 5 - -/** - * @brief OTG_FS FIFO memory size in words. - */ -#define STM32_OTG1_FIFO_MEM_SIZE 320 - -/** - * @brief OTG_HS FIFO memory size in words. - */ -#define STM32_OTG2_FIFO_MEM_SIZE 1024 - -/** - * @brief Host channel registers group. - */ -typedef struct { - volatile uint32_t HCCHAR; /**< @brief Host channel characteristics - register. */ - volatile uint32_t resvd8; - volatile uint32_t HCINT; /**< @brief Host channel interrupt register.*/ - volatile uint32_t HCINTMSK; /**< @brief Host channel interrupt mask - register. */ - volatile uint32_t HCTSIZ; /**< @brief Host channel transfer size - register. */ - volatile uint32_t resvd14; - volatile uint32_t resvd18; - volatile uint32_t resvd1c; -} stm32_otg_host_chn_t; - -/** - * @brief Device input endpoint registers group. - */ -typedef struct { - volatile uint32_t DIEPCTL; /**< @brief Device control IN endpoint - control register. */ - volatile uint32_t resvd4; - volatile uint32_t DIEPINT; /**< @brief Device IN endpoint interrupt - register. */ - volatile uint32_t resvdC; - volatile uint32_t DIEPTSIZ; /**< @brief Device IN endpoint transfer size - register. */ - volatile uint32_t resvd14; - volatile uint32_t DTXFSTS; /**< @brief Device IN endpoint transmit FIFO - status register. */ - volatile uint32_t resvd1C; -} stm32_otg_in_ep_t; - -/** - * @brief Device output endpoint registers group. - */ -typedef struct { - volatile uint32_t DOEPCTL; /**< @brief Device control OUT endpoint - control register. */ - volatile uint32_t resvd4; - volatile uint32_t DOEPINT; /**< @brief Device OUT endpoint interrupt - register. */ - volatile uint32_t resvdC; - volatile uint32_t DOEPTSIZ; /**< @brief Device OUT endpoint transfer - size register. */ - volatile uint32_t resvd14; - volatile uint32_t resvd18; - volatile uint32_t resvd1C; -} stm32_otg_out_ep_t; - -/** - * @brief USB registers memory map. - */ -typedef struct { - volatile uint32_t GOTGCTL; /**< @brief OTG control and status register.*/ - volatile uint32_t GOTGINT; /**< @brief OTG interrupt register. */ - volatile uint32_t GAHBCFG; /**< @brief AHB configuration register. */ - volatile uint32_t GUSBCFG; /**< @brief USB configuration register. */ - volatile uint32_t GRSTCTL; /**< @brief Reset register size. */ - volatile uint32_t GINTSTS; /**< @brief Interrupt register. */ - volatile uint32_t GINTMSK; /**< @brief Interrupt mask register. */ - volatile uint32_t GRXSTSR; /**< @brief Receive status debug read - register. */ - volatile uint32_t GRXSTSP; /**< @brief Receive status read/pop - register. */ - volatile uint32_t GRXFSIZ; /**< @brief Receive FIFO size register. */ - volatile uint32_t DIEPTXF0; /**< @brief Endpoint 0 transmit FIFO size - register. */ - volatile uint32_t HNPTXSTS; /**< @brief Non-periodic transmit FIFO/queue - status register. */ - volatile uint32_t resvd30; - volatile uint32_t resvd34; - volatile uint32_t GCCFG; /**< @brief General core configuration. */ - volatile uint32_t CID; /**< @brief Core ID register. */ - volatile uint32_t resvd58[48]; - volatile uint32_t HPTXFSIZ; /**< @brief Host periodic transmit FIFO size - register. */ - volatile uint32_t DIEPTXF[15];/**< @brief Device IN endpoint transmit FIFO - size registers. */ - volatile uint32_t resvd140[176]; - volatile uint32_t HCFG; /**< @brief Host configuration register. */ - volatile uint32_t HFIR; /**< @brief Host frame interval register. */ - volatile uint32_t HFNUM; /**< @brief Host frame number/frame time - Remaining register. */ - volatile uint32_t resvd40C; - volatile uint32_t HPTXSTS; /**< @brief Host periodic transmit FIFO/queue - status register. */ - volatile uint32_t HAINT; /**< @brief Host all channels interrupt - register. */ - volatile uint32_t HAINTMSK; /**< @brief Host all channels interrupt mask - register. */ - volatile uint32_t resvd41C[9]; - volatile uint32_t HPRT; /**< @brief Host port control and status - register. */ - volatile uint32_t resvd444[47]; - stm32_otg_host_chn_t hc[16]; /**< @brief Host channels array. */ - volatile uint32_t resvd700[64]; - volatile uint32_t DCFG; /**< @brief Device configuration register. */ - volatile uint32_t DCTL; /**< @brief Device control register. */ - volatile uint32_t DSTS; /**< @brief Device status register. */ - volatile uint32_t resvd80C; - volatile uint32_t DIEPMSK; /**< @brief Device IN endpoint common - interrupt mask register. */ - volatile uint32_t DOEPMSK; /**< @brief Device OUT endpoint common - interrupt mask register. */ - volatile uint32_t DAINT; /**< @brief Device all endpoints interrupt - register. */ - volatile uint32_t DAINTMSK; /**< @brief Device all endpoints interrupt - mask register. */ - volatile uint32_t resvd820; - volatile uint32_t resvd824; - volatile uint32_t DVBUSDIS; /**< @brief Device VBUS discharge time - register. */ - volatile uint32_t DVBUSPULSE; /**< @brief Device VBUS pulsing time - register. */ - volatile uint32_t resvd830; - volatile uint32_t DIEPEMPMSK; /**< @brief Device IN endpoint FIFO empty - interrupt mask register. */ - volatile uint32_t resvd838; - volatile uint32_t resvd83C; - volatile uint32_t resvd840[16]; - volatile uint32_t resvd880[16]; - volatile uint32_t resvd8C0[16]; - stm32_otg_in_ep_t ie[16]; /**< @brief Input endpoints. */ - stm32_otg_out_ep_t oe[16]; /**< @brief Output endpoints. */ - volatile uint32_t resvdD00[64]; - volatile uint32_t PCGCCTL; /**< @brief Power and clock gating control - register. */ - volatile uint32_t resvdE04[127]; - volatile uint32_t FIFO[16][1024]; -} stm32_otg_t; - -/** - * @name GOTGCTL register bit definitions - * @{ - */ -#define GOTGCTL_BSVLD (1U<<19) /**< B-Session Valid. */ -#define GOTGCTL_ASVLD (1U<<18) /**< A-Session Valid. */ -#define GOTGCTL_DBCT (1U<<17) /**< Long/Short debounce time. */ -#define GOTGCTL_CIDSTS (1U<<16) /**< Connector ID status. */ -#define GOTGCTL_EHEN (1U<<12) -#define GOTGCTL_DHNPEN (1U<<11) /**< Device HNP enabled. */ -#define GOTGCTL_HSHNPEN (1U<<10) /**< Host Set HNP enable. */ -#define GOTGCTL_HNPRQ (1U<<9) /**< HNP request. */ -#define GOTGCTL_HNGSCS (1U<<8) /**< Host negotiation success. */ -#define GOTGCTL_BVALOVAL (1U<<7) -#define GOTGCTL_BVALOEN (1U<<6) -#define GOTGCTL_AVALOVAL (1U<<5) -#define GOTGCTL_AVALOEN (1U<<4) -#define GOTGCTL_VBVALOVAL (1U<<3) -#define GOTGCTL_VBVALOEN (1U<<2) -#define GOTGCTL_SRQ (1U<<1) /**< Session request. */ -#define GOTGCTL_SRQSCS (1U<<0) /**< Session request success. */ -/** @} */ - -/** - * @name GOTGINT register bit definitions - * @{ - */ -#define GOTGINT_DBCDNE (1U<<19) /**< Debounce done. */ -#define GOTGINT_ADTOCHG (1U<<18) /**< A-Device timeout change. */ -#define GOTGINT_HNGDET (1U<<17) /**< Host negotiation detected. */ -#define GOTGINT_HNSSCHG (1U<<9) /**< Host negotiation success - status change. */ -#define GOTGINT_SRSSCHG (1U<<8) /**< Session request success - status change. */ -#define GOTGINT_SEDET (1U<<2) /**< Session end detected. */ -/** @} */ - -/** - * @name GAHBCFG register bit definitions - * @{ - */ -#define GAHBCFG_PTXFELVL (1U<<8) /**< Periodic TxFIFO empty - level. */ -#define GAHBCFG_TXFELVL (1U<<7) /**< Non-periodic TxFIFO empty - level. */ -#define GAHBCFG_DMAEN (1U<<5) /**< DMA enable (HS only). */ -#define GAHBCFG_HBSTLEN_MASK (15U<<1) /**< Burst length/type mask (HS - only). */ -#define GAHBCFG_HBSTLEN(n) ((n)<<1) /**< Burst length/type (HS - only). */ -#define GAHBCFG_GINTMSK (1U<<0) /**< Global interrupt mask. */ -/** @} */ - -/** - * @name GUSBCFG register bit definitions - * @{ - */ -#define GUSBCFG_CTXPKT (1U<<31) /**< Corrupt Tx packet. */ -#define GUSBCFG_FDMOD (1U<<30) /**< Force Device Mode. */ -#define GUSBCFG_FHMOD (1U<<29) /**< Force Host Mode. */ -#define GUSBCFG_TRDT_MASK (15U<<10) /**< USB Turnaround time field - mask. */ -#define GUSBCFG_TRDT(n) ((n)<<10) /**< USB Turnaround time field - value. */ -#define GUSBCFG_HNPCAP (1U<<9) /**< HNP-Capable. */ -#define GUSBCFG_SRPCAP (1U<<8) /**< SRP-Capable. */ -#define GUSBCFG_PHYSEL (1U<<6) /**< USB 2.0 High-Speed PHY or - USB 1.1 Full-Speed serial - transceiver Select. */ -#define GUSBCFG_TOCAL_MASK (7U<<0) /**< HS/FS timeout calibration - field mask. */ -#define GUSBCFG_TOCAL(n) ((n)<<0) /**< HS/FS timeout calibration - field value. */ -/** @} */ - -/** - * @name GRSTCTL register bit definitions - * @{ - */ -#define GRSTCTL_AHBIDL (1U<<31) /**< AHB Master Idle. */ -#define GRSTCTL_TXFNUM_MASK (31U<<6) /**< TxFIFO number field mask. */ -#define GRSTCTL_TXFNUM(n) ((n)<<6) /**< TxFIFO number field value. */ -#define GRSTCTL_TXFFLSH (1U<<5) /**< TxFIFO flush. */ -#define GRSTCTL_RXFFLSH (1U<<4) /**< RxFIFO flush. */ -#define GRSTCTL_FCRST (1U<<2) /**< Host frame counter reset. */ -#define GRSTCTL_HSRST (1U<<1) /**< HClk soft reset. */ -#define GRSTCTL_CSRST (1U<<0) /**< Core soft reset. */ -/** @} */ - -/** - * @name GINTSTS register bit definitions - * @{ - */ -#define GINTSTS_WKUPINT (1U<<31) /**< Resume/Remote wakeup - detected interrupt. */ -#define GINTSTS_SRQINT (1U<<30) /**< Session request/New session - detected interrupt. */ -#define GINTSTS_DISCINT (1U<<29) /**< Disconnect detected - interrupt. */ -#define GINTSTS_CIDSCHG (1U<<28) /**< Connector ID status change.*/ -#define GINTSTS_PTXFE (1U<<26) /**< Periodic TxFIFO empty. */ -#define GINTSTS_HCINT (1U<<25) /**< Host channels interrupt. */ -#define GINTSTS_HPRTINT (1U<<24) /**< Host port interrupt. */ -#define GINTSTS_IPXFR (1U<<21) /**< Incomplete periodic - transfer. */ -#define GINTSTS_IISOOXFR (1U<<21) /**< Incomplete isochronous OUT - transfer. */ -#define GINTSTS_IISOIXFR (1U<<20) /**< Incomplete isochronous IN - transfer. */ -#define GINTSTS_OEPINT (1U<<19) /**< OUT endpoints interrupt. */ -#define GINTSTS_IEPINT (1U<<18) /**< IN endpoints interrupt. */ -#define GINTSTS_EOPF (1U<<15) /**< End of periodic frame - interrupt. */ -#define GINTSTS_ISOODRP (1U<<14) /**< Isochronous OUT packet - dropped interrupt. */ -#define GINTSTS_ENUMDNE (1U<<13) /**< Enumeration done. */ -#define GINTSTS_USBRST (1U<<12) /**< USB reset. */ -#define GINTSTS_USBSUSP (1U<<11) /**< USB suspend. */ -#define GINTSTS_ESUSP (1U<<10) /**< Early suspend. */ -#define GINTSTS_GONAKEFF (1U<<7) /**< Global OUT NAK effective. */ -#define GINTSTS_GINAKEFF (1U<<6) /**< Global IN non-periodic NAK - effective. */ -#define GINTSTS_NPTXFE (1U<<5) /**< Non-periodic TxFIFO empty. */ -#define GINTSTS_RXFLVL (1U<<4) /**< RxFIFO non-empty. */ -#define GINTSTS_SOF (1U<<3) /**< Start of frame. */ -#define GINTSTS_OTGINT (1U<<2) /**< OTG interrupt. */ -#define GINTSTS_MMIS (1U<<1) /**< Mode Mismatch interrupt. */ -#define GINTSTS_CMOD (1U<<0) /**< Current mode of operation. */ -/** @} */ - -/** - * @name GINTMSK register bit definitions - * @{ - */ -#define GINTMSK_WKUM (1U<<31) /**< Resume/remote wakeup - detected interrupt mask. */ -#define GINTMSK_SRQM (1U<<30) /**< Session request/New session - detected interrupt mask. */ -#define GINTMSK_DISCM (1U<<29) /**< Disconnect detected - interrupt mask. */ -#define GINTMSK_CIDSCHGM (1U<<28) /**< Connector ID status change - mask. */ -#define GINTMSK_PTXFEM (1U<<26) /**< Periodic TxFIFO empty mask.*/ -#define GINTMSK_HCM (1U<<25) /**< Host channels interrupt - mask. */ -#define GINTMSK_HPRTM (1U<<24) /**< Host port interrupt mask. */ -#define GINTMSK_IPXFRM (1U<<21) /**< Incomplete periodic - transfer mask. */ -#define GINTMSK_IISOOXFRM (1U<<21) /**< Incomplete isochronous OUT - transfer mask. */ -#define GINTMSK_IISOIXFRM (1U<<20) /**< Incomplete isochronous IN - transfer mask. */ -#define GINTMSK_OEPM (1U<<19) /**< OUT endpoints interrupt - mask. */ -#define GINTMSK_IEPM (1U<<18) /**< IN endpoints interrupt - mask. */ -#define GINTMSK_EOPFM (1U<<15) /**< End of periodic frame - interrupt mask. */ -#define GINTMSK_ISOODRPM (1U<<14) /**< Isochronous OUT packet - dropped interrupt mask. */ -#define GINTMSK_ENUMDNEM (1U<<13) /**< Enumeration done mask. */ -#define GINTMSK_USBRSTM (1U<<12) /**< USB reset mask. */ -#define GINTMSK_USBSUSPM (1U<<11) /**< USB suspend mask. */ -#define GINTMSK_ESUSPM (1U<<10) /**< Early suspend mask. */ -#define GINTMSK_GONAKEFFM (1U<<7) /**< Global OUT NAK effective - mask. */ -#define GINTMSK_GINAKEFFM (1U<<6) /**< Global non-periodic IN NAK - effective mask. */ -#define GINTMSK_NPTXFEM (1U<<5) /**< Non-periodic TxFIFO empty - mask. */ -#define GINTMSK_RXFLVLM (1U<<4) /**< Receive FIFO non-empty - mask. */ -#define GINTMSK_SOFM (1U<<3) /**< Start of (micro)frame mask.*/ -#define GINTMSK_OTGM (1U<<2) /**< OTG interrupt mask. */ -#define GINTMSK_MMISM (1U<<1) /**< Mode Mismatch interrupt - mask. */ -/** @} */ - -/** - * @name GRXSTSR register bit definitions - * @{ - */ -#define GRXSTSR_PKTSTS_MASK (15U<<17) /**< Packet status mask. */ -#define GRXSTSR_PKTSTS(n) ((n)<<17) /**< Packet status value. */ -#define GRXSTSR_OUT_GLOBAL_NAK GRXSTSR_PKTSTS(1) -#define GRXSTSR_OUT_DATA GRXSTSR_PKTSTS(2) -#define GRXSTSR_OUT_COMP GRXSTSR_PKTSTS(3) -#define GRXSTSR_SETUP_COMP GRXSTSR_PKTSTS(4) -#define GRXSTSR_SETUP_DATA GRXSTSR_PKTSTS(6) -#define GRXSTSR_DPID_MASK (3U<<15) /**< Data PID mask. */ -#define GRXSTSR_DPID(n) ((n)<<15) /**< Data PID value. */ -#define GRXSTSR_BCNT_MASK (0x7FF<<4) /**< Byte count mask. */ -#define GRXSTSR_BCNT(n) ((n)<<4) /**< Byte count value. */ -#define GRXSTSR_CHNUM_MASK (15U<<0) /**< Channel number mask. */ -#define GRXSTSR_CHNUM(n) ((n)<<0) /**< Channel number value. */ -#define GRXSTSR_EPNUM_MASK (15U<<0) /**< Endpoint number mask. */ -#define GRXSTSR_EPNUM(n) ((n)<<0) /**< Endpoint number value. */ -/** @} */ - -/** - * @name GRXSTSP register bit definitions - * @{ - */ -#define GRXSTSP_PKTSTS_MASK (15<<17) /**< Packet status mask. */ -#define GRXSTSP_PKTSTS(n) ((n)<<17) /**< Packet status value. */ -#define GRXSTSP_OUT_GLOBAL_NAK GRXSTSP_PKTSTS(1) -#define GRXSTSP_OUT_DATA GRXSTSP_PKTSTS(2) -#define GRXSTSP_OUT_COMP GRXSTSP_PKTSTS(3) -#define GRXSTSP_SETUP_COMP GRXSTSP_PKTSTS(4) -#define GRXSTSP_SETUP_DATA GRXSTSP_PKTSTS(6) -#define GRXSTSP_DPID_MASK (3U<<15) /**< Data PID mask. */ -#define GRXSTSP_DPID(n) ((n)<<15) /**< Data PID value. */ -#define GRXSTSP_BCNT_MASK (0x7FF<<4) /**< Byte count mask. */ -#define GRXSTSP_BCNT_OFF 4 /**< Byte count offset. */ -#define GRXSTSP_BCNT(n) ((n)<<4) /**< Byte count value. */ -#define GRXSTSP_CHNUM_MASK (15U<<0) /**< Channel number mask. */ -#define GRXSTSP_CHNUM(n) ((n)<<0) /**< Channel number value. */ -#define GRXSTSP_EPNUM_MASK (15U<<0) /**< Endpoint number mask. */ -#define GRXSTSP_EPNUM_OFF 0 /**< Endpoint number offset. */ -#define GRXSTSP_EPNUM(n) ((n)<<0) /**< Endpoint number value. */ -/** @} */ - -/** - * @name GRXFSIZ register bit definitions - * @{ - */ -#define GRXFSIZ_RXFD_MASK (0xFFFF<<0) /**< RxFIFO depth mask. */ -#define GRXFSIZ_RXFD(n) ((n)<<0) /**< RxFIFO depth value. */ -/** @} */ - -/** - * @name DIEPTXFx register bit definitions - * @{ - */ -#define DIEPTXF_INEPTXFD_MASK (0xFFFFU<<16)/**< IN endpoint TxFIFO depth - mask. */ -#define DIEPTXF_INEPTXFD(n) ((n)<<16) /**< IN endpoint TxFIFO depth - value. */ -#define DIEPTXF_INEPTXSA_MASK (0xFFFF<<0) /**< IN endpoint FIFOx transmit - RAM start address mask. */ -#define DIEPTXF_INEPTXSA(n) ((n)<<0) /**< IN endpoint FIFOx transmit - RAM start address value. */ -/** @} */ - -/** - * @name GCCFG register bit definitions - * @{ - */ -#define GCCFG_NOVBUSSENS (1U<<21) /**< VBUS sensing disable. */ -#define GCCFG_SOFOUTEN (1U<<20) /**< SOF output enable. */ -#define GCCFG_VBUSBSEN (1U<<19) /**< Enable the VBUS sensing "B" - device. */ -#define GCCFG_VBUSASEN (1U<<18) /**< Enable the VBUS sensing "A" - device. */ -#define GCCFG_PWRDWN (1U<<16) /**< Power down. */ -/** @} */ - -/** - * @name HPTXFSIZ register bit definitions - * @{ - */ -#define HPTXFSIZ_PTXFD_MASK (0xFFFFU<<16)/**< Host periodic TxFIFO - depth mask. */ -#define HPTXFSIZ_PTXFD(n) ((n)<<16) /**< Host periodic TxFIFO - depth value. */ -#define HPTXFSIZ_PTXSA_MASK (0xFFFFU<<0)/**< Host periodic TxFIFO - Start address mask. */ -#define HPTXFSIZ_PTXSA(n) ((n)<<0) /**< Host periodic TxFIFO - start address value. */ -/** @} */ - -/** - * @name HCFG register bit definitions - * @{ - */ -#define HCFG_FSLSS (1U<<2) /**< FS- and LS-only support. */ -#define HCFG_FSLSPCS_MASK (3U<<0) /**< FS/LS PHY clock select - mask. */ -#define HCFG_FSLSPCS_48 (1U<<0) /**< PHY clock is running at - 48 MHz. */ -#define HCFG_FSLSPCS_6 (2U<<0) /**< PHY clock is running at - 6 MHz. */ -/** @} */ - -/** - * @name HFIR register bit definitions - * @{ - */ -#define HFIR_FRIVL_MASK (0xFFFFU<<0)/**< Frame interval mask. */ -#define HFIR_FRIVL(n) ((n)<<0) /**< Frame interval value. */ -/** @} */ - -/** - * @name HFNUM register bit definitions - * @{ - */ -#define HFNUM_FTREM_MASK (0xFFFFU<<16)/**< Frame time Remaining mask.*/ -#define HFNUM_FTREM(n) ((n)<<16) /**< Frame time Remaining value.*/ -#define HFNUM_FRNUM_MASK (0xFFFFU<<0)/**< Frame number mask. */ -#define HFNUM_FRNUM(n) ((n)<<0) /**< Frame number value. */ -/** @} */ - -/** - * @name HPTXSTS register bit definitions - * @{ - */ -#define HPTXSTS_PTXQTOP_MASK (0xFFU<<24) /**< Top of the periodic - transmit request queue - mask. */ -#define HPTXSTS_PTXQTOP(n) ((n)<<24) /**< Top of the periodic - transmit request queue - value. */ -#define HPTXSTS_PTXQSAV_MASK (0xFF<<16) /**< Periodic transmit request - queue Space Available - mask. */ -#define HPTXSTS_PTXQSAV(n) ((n)<<16) /**< Periodic transmit request - queue Space Available - value. */ -#define HPTXSTS_PTXFSAVL_MASK (0xFFFF<<0) /**< Periodic transmit Data - FIFO Space Available - mask. */ -#define HPTXSTS_PTXFSAVL(n) ((n)<<0) /**< Periodic transmit Data - FIFO Space Available - value. */ -/** @} */ - -/** - * @name HAINT register bit definitions - * @{ - */ -#define HAINT_HAINT_MASK (0xFFFFU<<0)/**< Channel interrupts mask. */ -#define HAINT_HAINT(n) ((n)<<0) /**< Channel interrupts value. */ -/** @} */ - -/** - * @name HAINTMSK register bit definitions - * @{ - */ -#define HAINTMSK_HAINTM_MASK (0xFFFFU<<0)/**< Channel interrupt mask - mask. */ -#define HAINTMSK_HAINTM(n) ((n)<<0) /**< Channel interrupt mask - value. */ -/** @} */ - -/** - * @name HPRT register bit definitions - * @{ - */ -#define HPRT_PSPD_MASK (3U<<17) /**< Port speed mask. */ -#define HPRT_PSPD_FS (1U<<17) /**< Full speed value. */ -#define HPRT_PSPD_LS (2U<<17) /**< Low speed value. */ -#define HPRT_PTCTL_MASK (15<<13) /**< Port Test control mask. */ -#define HPRT_PTCTL(n) ((n)<<13) /**< Port Test control value. */ -#define HPRT_PPWR (1U<<12) /**< Port power. */ -#define HPRT_PLSTS_MASK (3U<<11) /**< Port Line status mask. */ -#define HPRT_PLSTS_DM (1U<<11) /**< Logic level of D-. */ -#define HPRT_PLSTS_DP (1U<<10) /**< Logic level of D+. */ -#define HPRT_PRST (1U<<8) /**< Port reset. */ -#define HPRT_PSUSP (1U<<7) /**< Port suspend. */ -#define HPRT_PRES (1U<<6) /**< Port Resume. */ -#define HPRT_POCCHNG (1U<<5) /**< Port overcurrent change. */ -#define HPRT_POCA (1U<<4) /**< Port overcurrent active. */ -#define HPRT_PENCHNG (1U<<3) /**< Port enable/disable change.*/ -#define HPRT_PENA (1U<<2) /**< Port enable. */ -#define HPRT_PCDET (1U<<1) /**< Port Connect detected. */ -#define HPRT_PCSTS (1U<<0) /**< Port connect status. */ -/** @} */ - -/** - * @name HCCHAR register bit definitions - * @{ - */ -#define HCCHAR_CHENA (1U<<31) /**< Channel enable. */ -#define HCCHAR_CHDIS (1U<<30) /**< Channel Disable. */ -#define HCCHAR_ODDFRM (1U<<29) /**< Odd frame. */ -#define HCCHAR_DAD_MASK (0x7FU<<22) /**< Device Address mask. */ -#define HCCHAR_DAD(n) ((n)<<22) /**< Device Address value. */ -#define HCCHAR_MCNT_MASK (3U<<20) /**< Multicount mask. */ -#define HCCHAR_MCNT(n) ((n)<<20) /**< Multicount value. */ -#define HCCHAR_EPTYP_MASK (3U<<18) /**< Endpoint type mask. */ -#define HCCHAR_EPTYP(n) ((n)<<18) /**< Endpoint type value. */ -#define HCCHAR_EPTYP_CTL (0U<<18) /**< Control endpoint value. */ -#define HCCHAR_EPTYP_ISO (1U<<18) /**< Isochronous endpoint value.*/ -#define HCCHAR_EPTYP_BULK (2U<<18) /**< Bulk endpoint value. */ -#define HCCHAR_EPTYP_INTR (3U<<18) /**< Interrupt endpoint value. */ -#define HCCHAR_LSDEV (1U<<17) /**< Low-Speed device. */ -#define HCCHAR_EPDIR (1U<<15) /**< Endpoint direction. */ -#define HCCHAR_EPNUM_MASK (15U<<11) /**< Endpoint number mask. */ -#define HCCHAR_EPNUM(n) ((n)<<11) /**< Endpoint number value. */ -#define HCCHAR_MPS_MASK (0x7FFU<<0) /**< Maximum packet size mask. */ -#define HCCHAR_MPS(n) ((n)<<0) /**< Maximum packet size value. */ -/** @} */ - -/** - * @name HCINT register bit definitions - * @{ - */ -#define HCINT_DTERR (1U<<10) /**< Data toggle error. */ -#define HCINT_FRMOR (1U<<9) /**< Frame overrun. */ -#define HCINT_BBERR (1U<<8) /**< Babble error. */ -#define HCINT_TRERR (1U<<7) /**< Transaction Error. */ -#define HCINT_ACK (1U<<5) /**< ACK response - received/transmitted - interrupt. */ -#define HCINT_NAK (1U<<4) /**< NAK response received - interrupt. */ -#define HCINT_STALL (1U<<3) /**< STALL response received - interrupt. */ -#define HCINT_CHH (1U<<1) /**< Channel halted. */ -#define HCINT_XFRC (1U<<0) /**< Transfer completed. */ -/** @} */ - -/** - * @name HCINTMSK register bit definitions - * @{ - */ -#define HCINTMSK_DTERRM (1U<<10) /**< Data toggle error mask. */ -#define HCINTMSK_FRMORM (1U<<9) /**< Frame overrun mask. */ -#define HCINTMSK_BBERRM (1U<<8) /**< Babble error mask. */ -#define HCINTMSK_TRERRM (1U<<7) /**< Transaction error mask. */ -#define HCINTMSK_NYET (1U<<6) /**< NYET response received - interrupt mask. */ -#define HCINTMSK_ACKM (1U<<5) /**< ACK Response - received/transmitted - interrupt mask. */ -#define HCINTMSK_NAKM (1U<<4) /**< NAK response received - interrupt mask. */ -#define HCINTMSK_STALLM (1U<<3) /**< STALL response received - interrupt mask. */ -#define HCINTMSK_AHBERRM (1U<<2) -#define HCINTMSK_CHHM (1U<<1) /**< Channel halted mask. */ -#define HCINTMSK_XFRCM (1U<<0) /**< Transfer completed mask. */ -/** @} */ - -/** - * @name HCTSIZ register bit definitions - * @{ - */ -#define HCTSIZ_DPID_MASK (3U<<29) /**< PID mask. */ -#define HCTSIZ_DPID_DATA0 (0U<<29) /**< DATA0. */ -#define HCTSIZ_DPID_DATA2 (1U<<29) /**< DATA2. */ -#define HCTSIZ_DPID_DATA1 (2U<<29) /**< DATA1. */ -#define HCTSIZ_DPID_MDATA (3U<<29) /**< MDATA. */ -#define HCTSIZ_DPID_SETUP (3U<<29) /**< SETUP. */ -#define HCTSIZ_PKTCNT_MASK (0x3FFU<<19)/**< Packet count mask. */ -#define HCTSIZ_PKTCNT(n) ((n)<<19) /**< Packet count value. */ -#define HCTSIZ_XFRSIZ_MASK (0x7FFFF<<0)/**< Transfer size mask. */ -#define HCTSIZ_XFRSIZ(n) ((n)<<0) /**< Transfer size value. */ -/** @} */ - -/** - * @name DCFG register bit definitions - * @{ - */ -#define DCFG_PFIVL_MASK (3U<<11) /**< Periodic frame interval - mask. */ -#define DCFG_PFIVL(n) ((n)<<11) /**< Periodic frame interval - value. */ -#define DCFG_DAD_MASK (0x7FU<<4) /**< Device address mask. */ -#define DCFG_DAD(n) ((n)<<4) /**< Device address value. */ -#define DCFG_NZLSOHSK (1U<<2) /**< Non-Zero-Length status - OUT handshake. */ -#define DCFG_DSPD_MASK (3U<<0) /**< Device speed mask. */ -#define DCFG_DSPD_HS (0U<<0) /**< High speed (USB 2.0). */ -#define DCFG_DSPD_HS_FS (1U<<0) /**< High speed (USB 2.0) in FS - mode. */ -#define DCFG_DSPD_FS11 (3U<<0) /**< Full speed (USB 1.1 - transceiver clock is 48 - MHz). */ -/** @} */ - -/** - * @name DCTL register bit definitions - * @{ - */ -#define DCTL_POPRGDNE (1U<<11) /**< Power-on programming done. */ -#define DCTL_CGONAK (1U<<10) /**< Clear global OUT NAK. */ -#define DCTL_SGONAK (1U<<9) /**< Set global OUT NAK. */ -#define DCTL_CGINAK (1U<<8) /**< Clear global non-periodic - IN NAK. */ -#define DCTL_SGINAK (1U<<7) /**< Set global non-periodic - IN NAK. */ -#define DCTL_TCTL_MASK (7U<<4) /**< Test control mask. */ -#define DCTL_TCTL(n) ((n)<<4 /**< Test control value. */ -#define DCTL_GONSTS (1U<<3) /**< Global OUT NAK status. */ -#define DCTL_GINSTS (1U<<2) /**< Global non-periodic IN - NAK status. */ -#define DCTL_SDIS (1U<<1) /**< Soft disconnect. */ -#define DCTL_RWUSIG (1U<<0) /**< Remote wakeup signaling. */ -/** @} */ - -/** - * @name DSTS register bit definitions - * @{ - */ -#define DSTS_FNSOF_MASK (0x3FFU<<8) /**< Frame number of the received - SOF mask. */ -#define DSTS_FNSOF(n) ((n)<<8) /**< Frame number of the received - SOF value. */ -#define DSTS_FNSOF_ODD (1U<<8) /**< Frame parity of the received - SOF value. */ -#define DSTS_EERR (1U<<3) /**< Erratic error. */ -#define DSTS_ENUMSPD_MASK (3U<<1) /**< Enumerated speed mask. */ -#define DSTS_ENUMSPD_FS_48 (3U<<1) /**< Full speed (PHY clock is - running at 48 MHz). */ -#define DSTS_ENUMSPD_HS_480 (0U<<1) /**< High speed. */ -#define DSTS_SUSPSTS (1U<<0) /**< Suspend status. */ -/** @} */ - -/** - * @name DIEPMSK register bit definitions - * @{ - */ -#define DIEPMSK_TXFEM (1U<<6) /**< Transmit FIFO empty mask. */ -#define DIEPMSK_INEPNEM (1U<<6) /**< IN endpoint NAK effective - mask. */ -#define DIEPMSK_ITTXFEMSK (1U<<4) /**< IN token received when - TxFIFO empty mask. */ -#define DIEPMSK_TOCM (1U<<3) /**< Timeout condition mask. */ -#define DIEPMSK_EPDM (1U<<1) /**< Endpoint disabled - interrupt mask. */ -#define DIEPMSK_XFRCM (1U<<0) /**< Transfer completed - interrupt mask. */ -/** @} */ - -/** - * @name DOEPMSK register bit definitions - * @{ - */ -#define DOEPMSK_OTEPDM (1U<<4) /**< OUT token received when - endpoint disabled mask. */ -#define DOEPMSK_STUPM (1U<<3) /**< SETUP phase done mask. */ -#define DOEPMSK_EPDM (1U<<1) /**< Endpoint disabled - interrupt mask. */ -#define DOEPMSK_XFRCM (1U<<0) /**< Transfer completed - interrupt mask. */ -/** @} */ - -/** - * @name DAINT register bit definitions - * @{ - */ -#define DAINT_OEPINT_MASK (0xFFFFU<<16)/**< OUT endpoint interrupt - bits mask. */ -#define DAINT_OEPINT(n) ((n)<<16) /**< OUT endpoint interrupt - bits value. */ -#define DAINT_IEPINT_MASK (0xFFFFU<<0)/**< IN endpoint interrupt - bits mask. */ -#define DAINT_IEPINT(n) ((n)<<0) /**< IN endpoint interrupt - bits value. */ -/** @} */ - -/** - * @name DAINTMSK register bit definitions - * @{ - */ -#define DAINTMSK_OEPM_MASK (0xFFFFU<<16)/**< OUT EP interrupt mask - bits mask. */ -#define DAINTMSK_OEPM(n) (1U<<(16+(n)))/**< OUT EP interrupt mask - bits value. */ -#define DAINTMSK_IEPM_MASK (0xFFFFU<<0)/**< IN EP interrupt mask - bits mask. */ -#define DAINTMSK_IEPM(n) (1U<<(n)) /**< IN EP interrupt mask - bits value. */ -/** @} */ - -/** - * @name DVBUSDIS register bit definitions - * @{ - */ -#define DVBUSDIS_VBUSDT_MASK (0xFFFFU<<0)/**< Device VBUS discharge - time mask. */ -#define DVBUSDIS_VBUSDT(n) ((n)<<0) /**< Device VBUS discharge - time value. */ -/** @} */ - -/** - * @name DVBUSPULSE register bit definitions - * @{ - */ -#define DVBUSPULSE_DVBUSP_MASK (0xFFFU<<0) /**< Device VBUSpulsing time - mask. */ -#define DVBUSPULSE_DVBUSP(n) ((n)<<0) /**< Device VBUS pulsing time - value. */ -/** @} */ - -/** - * @name DIEPEMPMSK register bit definitions - * @{ - */ -#define DIEPEMPMSK_INEPTXFEM(n) (1U<<(n)) /**< IN EP Tx FIFO empty - interrupt mask bit. */ -/** @} */ - -/** - * @name DIEPCTL register bit definitions - * @{ - */ -#define DIEPCTL_EPENA (1U<<31) /**< Endpoint enable. */ -#define DIEPCTL_EPDIS (1U<<30) /**< Endpoint disable. */ -#define DIEPCTL_SD1PID (1U<<29) /**< Set DATA1 PID. */ -#define DIEPCTL_SODDFRM (1U<<29) /**< Set odd frame. */ -#define DIEPCTL_SD0PID (1U<<28) /**< Set DATA0 PID. */ -#define DIEPCTL_SEVNFRM (1U<<28) /**< Set even frame. */ -#define DIEPCTL_SNAK (1U<<27) /**< Set NAK. */ -#define DIEPCTL_CNAK (1U<<26) /**< Clear NAK. */ -#define DIEPCTL_TXFNUM_MASK (15U<<22) /**< TxFIFO number mask. */ -#define DIEPCTL_TXFNUM(n) ((n)<<22) /**< TxFIFO number value. */ -#define DIEPCTL_STALL (1U<<21) /**< STALL handshake. */ -#define DIEPCTL_SNPM (1U<<20) /**< Snoop mode. */ -#define DIEPCTL_EPTYP_MASK (3<<18) /**< Endpoint type mask. */ -#define DIEPCTL_EPTYP_CTRL (0U<<18) /**< Control. */ -#define DIEPCTL_EPTYP_ISO (1U<<18) /**< Isochronous. */ -#define DIEPCTL_EPTYP_BULK (2U<<18) /**< Bulk. */ -#define DIEPCTL_EPTYP_INTR (3U<<18) /**< Interrupt. */ -#define DIEPCTL_NAKSTS (1U<<17) /**< NAK status. */ -#define DIEPCTL_EONUM (1U<<16) /**< Even/odd frame. */ -#define DIEPCTL_DPID (1U<<16) /**< Endpoint data PID. */ -#define DIEPCTL_USBAEP (1U<<15) /**< USB active endpoint. */ -#define DIEPCTL_MPSIZ_MASK (0x3FFU<<0) /**< Maximum Packet size mask. */ -#define DIEPCTL_MPSIZ(n) ((n)<<0) /**< Maximum Packet size value. */ -/** @} */ - -/** - * @name DIEPINT register bit definitions - * @{ - */ -#define DIEPINT_TXFE (1U<<7) /**< Transmit FIFO empty. */ -#define DIEPINT_INEPNE (1U<<6) /**< IN endpoint NAK effective. */ -#define DIEPINT_ITTXFE (1U<<4) /**< IN Token received when - TxFIFO is empty. */ -#define DIEPINT_TOC (1U<<3) /**< Timeout condition. */ -#define DIEPINT_EPDISD (1U<<1) /**< Endpoint disabled - interrupt. */ -#define DIEPINT_XFRC (1U<<0) /**< Transfer completed. */ -/** @} */ - -/** - * @name DIEPTSIZ register bit definitions - * @{ - */ -#define DIEPTSIZ_MCNT_MASK (3U<<29) /**< Multi count mask. */ -#define DIEPTSIZ_MCNT(n) ((n)<<29) /**< Multi count value. */ -#define DIEPTSIZ_PKTCNT_MASK (0x3FF<<19) /**< Packet count mask. */ -#define DIEPTSIZ_PKTCNT(n) ((n)<<19) /**< Packet count value. */ -#define DIEPTSIZ_XFRSIZ_MASK (0x7FFFFU<<0)/**< Transfer size mask. */ -#define DIEPTSIZ_XFRSIZ(n) ((n)<<0) /**< Transfer size value. */ -/** @} */ - -/** - * @name DTXFSTS register bit definitions. - * @{ - */ -#define DTXFSTS_INEPTFSAV_MASK (0xFFFF<<0) /**< IN endpoint TxFIFO space - available. */ -/** @} */ - -/** - * @name DOEPCTL register bit definitions. - * @{ - */ -#define DOEPCTL_EPENA (1U<<31) /**< Endpoint enable. */ -#define DOEPCTL_EPDIS (1U<<30) /**< Endpoint disable. */ -#define DOEPCTL_SD1PID (1U<<29) /**< Set DATA1 PID. */ -#define DOEPCTL_SODDFRM (1U<<29) /**< Set odd frame. */ -#define DOEPCTL_SD0PID (1U<<28) /**< Set DATA0 PID. */ -#define DOEPCTL_SEVNFRM (1U<<28) /**< Set even frame. */ -#define DOEPCTL_SNAK (1U<<27) /**< Set NAK. */ -#define DOEPCTL_CNAK (1U<<26) /**< Clear NAK. */ -#define DOEPCTL_STALL (1U<<21) /**< STALL handshake. */ -#define DOEPCTL_SNPM (1U<<20) /**< Snoop mode. */ -#define DOEPCTL_EPTYP_MASK (3U<<18) /**< Endpoint type mask. */ -#define DOEPCTL_EPTYP_CTRL (0U<<18) /**< Control. */ -#define DOEPCTL_EPTYP_ISO (1U<<18) /**< Isochronous. */ -#define DOEPCTL_EPTYP_BULK (2U<<18) /**< Bulk. */ -#define DOEPCTL_EPTYP_INTR (3U<<18) /**< Interrupt. */ -#define DOEPCTL_NAKSTS (1U<<17) /**< NAK status. */ -#define DOEPCTL_EONUM (1U<<16) /**< Even/odd frame. */ -#define DOEPCTL_DPID (1U<<16) /**< Endpoint data PID. */ -#define DOEPCTL_USBAEP (1U<<15) /**< USB active endpoint. */ -#define DOEPCTL_MPSIZ_MASK (0x3FFU<<0) /**< Maximum Packet size mask. */ -#define DOEPCTL_MPSIZ(n) ((n)<<0) /**< Maximum Packet size value. */ -/** @} */ - -/** - * @name DOEPINT register bit definitions - * @{ - */ -#define DOEPINT_B2BSTUP (1U<<6) /**< Back-to-back SETUP packets - received. */ -#define DOEPINT_OTEPDIS (1U<<4) /**< OUT token received when - endpoint disabled. */ -#define DOEPINT_STUP (1U<<3) /**< SETUP phase done. */ -#define DOEPINT_EPDISD (1U<<1) /**< Endpoint disabled - interrupt. */ -#define DOEPINT_XFRC (1U<<0) /**< Transfer completed - interrupt. */ -/** @} */ - -/** - * @name DOEPTSIZ register bit definitions - * @{ - */ -#define DOEPTSIZ_RXDPID_MASK (3U<<29) /**< Received data PID mask. */ -#define DOEPTSIZ_RXDPID(n) ((n)<<29) /**< Received data PID value. */ -#define DOEPTSIZ_STUPCNT_MASK (3U<<29) /**< SETUP packet count mask. */ -#define DOEPTSIZ_STUPCNT(n) ((n)<<29) /**< SETUP packet count value. */ -#define DOEPTSIZ_PKTCNT_MASK (0x3FFU<<19)/**< Packet count mask. */ -#define DOEPTSIZ_PKTCNT(n) ((n)<<19) /**< Packet count value. */ -#define DOEPTSIZ_XFRSIZ_MASK (0x7FFFFU<<0)/**< Transfer size mask. */ -#define DOEPTSIZ_XFRSIZ(n) ((n)<<0) /**< Transfer size value. */ -/** @} */ - -/** - * @name PCGCCTL register bit definitions - * @{ - */ -#define PCGCCTL_PHYSUSP (1U<<4) /**< PHY Suspended. */ -#define PCGCCTL_GATEHCLK (1U<<1) /**< Gate HCLK. */ -#define PCGCCTL_STPPCLK (1U<<0) /**< Stop PCLK. */ -/** @} */ - -/** - * @brief OTG_FS registers block memory address. - */ -#define OTG_FS_ADDR 0x50000000 - -/** - * @brief OTG_HS registers block memory address. - */ -#define OTG_HS_ADDR 0x40040000 - -/** - * @brief Accesses to the OTG_FS registers block. - */ -#define OTG_FS ((stm32_otg_t *)OTG_FS_ADDR) - -/** - * @brief Accesses to the OTG_HS registers block. - */ -#define OTG_HS ((stm32_otg_t *)OTG_HS_ADDR) - -#endif /* _STM32_OTG_H_ */ - -/** @} */ diff --git a/os/hal/ports/STM32/LLD/USBHv1/usbh_lld.c b/os/hal/ports/STM32/LLD/USBHv1/usbh_lld.c deleted file mode 100644 index 5455f52..0000000 --- a/os/hal/ports/STM32/LLD/USBHv1/usbh_lld.c +++ /dev/null @@ -1,1604 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio - Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail) - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -#include "hal.h" - -#if HAL_USE_USBH -#include "usbh/internal.h" -#include - -#if USBH_LLD_DEBUG_ENABLE_TRACE -#define udbgf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) -#define udbg(f, ...) usbDbgPuts(f, ##__VA_ARGS__) -#else -#define udbgf(f, ...) do {} while(0) -#define udbg(f, ...) do {} while(0) -#endif - -#if USBH_LLD_DEBUG_ENABLE_INFO -#define uinfof(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) -#define uinfo(f, ...) usbDbgPuts(f, ##__VA_ARGS__) -#else -#define uinfof(f, ...) do {} while(0) -#define uinfo(f, ...) do {} while(0) -#endif - -#if USBH_LLD_DEBUG_ENABLE_WARNINGS -#define uwarnf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) -#define uwarn(f, ...) usbDbgPuts(f, ##__VA_ARGS__) -#else -#define uwarnf(f, ...) do {} while(0) -#define uwarn(f, ...) do {} while(0) -#endif - -#if USBH_LLD_DEBUG_ENABLE_ERRORS -#define uerrf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) -#define uerr(f, ...) usbDbgPuts(f, ##__VA_ARGS__) -#else -#define uerrf(f, ...) do {} while(0) -#define uerr(f, ...) do {} while(0) -#endif - -static void _transfer_completedI(usbh_ep_t *ep, usbh_urb_t *urb, usbh_urbstatus_t status); -static void _try_commit_np(USBHDriver *host); -static void otg_rxfifo_flush(USBHDriver *usbp); -static void otg_txfifo_flush(USBHDriver *usbp, uint32_t fifo); - -/*===========================================================================*/ -/* Little helper functions. */ -/*===========================================================================*/ -static inline void _move_to_pending_queue(usbh_ep_t *ep) { - list_move_tail(&ep->node, ep->pending_list); -} - -static inline usbh_urb_t *_active_urb(usbh_ep_t *ep) { - return list_first_entry(&ep->urb_list, usbh_urb_t, node); -} - -static inline void _save_dt_mask(usbh_ep_t *ep, uint32_t hctsiz) { - ep->dt_mask = hctsiz & HCTSIZ_DPID_MASK; -} - -#if 1 -#define _transfer_completed _transfer_completedI -#else -static inline void _transfer_completed(usbh_ep_t *ep, usbh_urb_t *urb, usbh_urbstatus_t status) { - osalSysLockFromISR(); - _transfer_completedI(ep, urb, status); - osalSysUnlockFromISR(); -} -#endif - -/*===========================================================================*/ -/* Functions called from many places. */ -/*===========================================================================*/ -static void _transfer_completedI(usbh_ep_t *ep, usbh_urb_t *urb, usbh_urbstatus_t status) { - osalDbgCheckClassI(); - - urb->queued = FALSE; - - /* remove URB from EP's queue */ - list_del_init(&urb->node); - - /* Call the callback function now, so that if it calls usbhURBSubmitI, - * the list_empty check below will be false. Also, note that the - * if (list_empty(&ep->node)) { - * ... - * } - * in usbh_lld_urb_submit will be false, since the endpoint is - * still in the active queue. - */ - _usbh_urb_completeI(urb, status); - - if (list_empty(&ep->urb_list)) { - /* no more URBs to process in this EP, remove EP from the host's queue */ - list_del_init(&ep->node); - } else { - /* more URBs to process */ - _move_to_pending_queue(ep); - } -} - -static void _halt_channel(USBHDriver *host, stm32_hc_management_t *hcm, usbh_lld_halt_reason_t reason) { - (void)host; - - if (hcm->halt_reason != USBH_LLD_HALTREASON_NONE) { - uwarnf("\t%s: Repeated halt (original=%d, new=%d)", hcm->ep->name, hcm->halt_reason, reason); - return; - } - -#if CH_DBG_ENABLE_CHECKS - if (usbhEPIsPeriodic(hcm->ep)) { - osalDbgCheck(host->otg->HPTXSTS & HPTXSTS_PTXQSAV_MASK); - } else { - osalDbgCheck(host->otg->HNPTXSTS & HPTXSTS_PTXQSAV_MASK); - } -#endif - - hcm->halt_reason = reason; - hcm->hc->HCCHAR |= HCCHAR_CHENA | HCCHAR_CHDIS; -} - -static void _release_channel(USBHDriver *host, stm32_hc_management_t *hcm) { -// static const char *reason[] = {"XFRC", "XFRC", "NAK", "STALL", "ERROR", "ABORT"}; -// udbgf("\t%s: release (%s)", hcm->ep->name, reason[hcm->halt_reason]); - hcm->hc->HCINTMSK = 0; - host->otg->HAINTMSK &= ~hcm->haintmsk; - hcm->halt_reason = USBH_LLD_HALTREASON_NONE; - if (usbhEPIsPeriodic(hcm->ep)) { - list_add(&hcm->node, &host->ch_free[0]); - } else { - list_add(&hcm->node, &host->ch_free[1]); - } - hcm->ep->xfer.hcm = 0; - hcm->ep = 0; -} - -static bool _activate_ep(USBHDriver *host, usbh_ep_t *ep) { - struct list_head *list; - uint16_t spc; - - osalDbgCheck(ep->xfer.hcm == NULL); - - if (usbhEPIsPeriodic(ep)) { - list = &host->ch_free[0]; - spc = (host->otg->HPTXSTS >> 16) & 0xff; - } else { - list = &host->ch_free[1]; - spc = (host->otg->HNPTXSTS >> 16) & 0xff; - } - - if (list_empty(list)) { - uwarnf("\t%s: No free %s channels", ep->name, usbhEPIsPeriodic(ep) ? "P" : "NP"); - return FALSE; - } - - if (spc <= STM32_USBH_MIN_QSPACE) { - uwarnf("\t%s: No space in %s Queue (spc=%d)", ep->name, usbhEPIsPeriodic(ep) ? "P" : "NP", spc); - return FALSE; - } - - /* get the first channel */ - stm32_hc_management_t *hcm = list_first_entry(list, stm32_hc_management_t, node); - osalDbgCheck((hcm->halt_reason == USBH_LLD_HALTREASON_NONE) && (hcm->ep == NULL)); - - usbh_urb_t *const urb = _active_urb(ep); - uint32_t hcintmsk = ep->hcintmsk; - uint32_t hcchar = ep->hcchar; - uint16_t mps = ep->wMaxPacketSize; - - uint32_t xfer_packets; - uint32_t xfer_len = 0; //Initialize just to shut up a compiler warning - - osalDbgCheck(urb->status == USBH_URBSTATUS_PENDING); - - /* check if the URB is a new one, or we must continue a previously started URB */ - if (urb->queued == FALSE) { - /* prepare EP for a new URB */ - if (ep->type == USBH_EPTYPE_CTRL) { - xfer_len = 8; - ep->xfer.buf = (uint8_t *)urb->setup_buff; - ep->dt_mask = HCTSIZ_DPID_SETUP; - ep->in = FALSE; - ep->xfer.u.ctrl_phase = USBH_LLD_CTRLPHASE_SETUP; - } else { - xfer_len = urb->requestedLength; - ep->xfer.buf = urb->buff; - } - ep->xfer.error_count = 0; - //urb->status = USBH_URBSTATUS_QUEUED; - } else { - osalDbgCheck(urb->requestedLength >= urb->actualLength); - - if (ep->type == USBH_EPTYPE_CTRL) { - switch (ep->xfer.u.ctrl_phase) { - case USBH_LLD_CTRLPHASE_SETUP: - xfer_len = 8; - ep->xfer.buf = (uint8_t *)urb->setup_buff; - ep->dt_mask = HCTSIZ_DPID_SETUP; - break; - case USBH_LLD_CTRLPHASE_DATA: - xfer_len = urb->requestedLength - urb->actualLength; - ep->xfer.buf = (uint8_t *) urb->buff + urb->actualLength; - break; - case USBH_LLD_CTRLPHASE_STATUS: - xfer_len = 0; - ep->dt_mask = HCTSIZ_DPID_DATA1; - ep->xfer.error_count = 0; - break; - default: - osalDbgCheck(0); - } - if (ep->in) { - hcintmsk |= HCINTMSK_DTERRM | HCINTMSK_BBERRM; - hcchar |= HCCHAR_EPDIR; - } - } else { - xfer_len = urb->requestedLength - urb->actualLength; - ep->xfer.buf = (uint8_t *) urb->buff + urb->actualLength; - } - - if (ep->xfer.error_count) - hcintmsk |= HCINTMSK_ACKM; - - } - ep->xfer.partial = 0; - - if (ep->type == USBH_EPTYPE_ISO) { - ep->dt_mask = HCTSIZ_DPID_DATA0; - - /* [USB 2.0 spec, 5.6.4]: A host must not issue more than 1 - * transaction in a (micro)frame for an isochronous endpoint - * unless the endpoint is high-speed, high-bandwidth. - */ - if (xfer_len > mps) - xfer_len = mps; - } else if (xfer_len > 0x7FFFF) { - xfer_len = 0x7FFFF - mps + 1; - } - - /* calculate required packets */ - if (xfer_len) { - xfer_packets = (xfer_len + mps - 1) / mps; - - if (xfer_packets > 0x3FF) { - xfer_packets = 0x3FF; - xfer_len = xfer_packets * mps; - } - } else { - xfer_packets = 1; /* Need 1 packet for transfer length of 0 */ - } - - if (ep->in) - xfer_len = xfer_packets * mps; - - /* Clear old interrupt conditions, - * configure transfer size, - * enable required interrupts */ - stm32_otg_host_chn_t *const hc = hcm->hc; - hc->HCINT = 0xffffffff; - hc->HCTSIZ = ep->dt_mask - | HCTSIZ_PKTCNT(xfer_packets) - | HCTSIZ_XFRSIZ(xfer_len); - hc->HCINTMSK = hcintmsk; - - /* Queue the transfer for the next frame (no effect for non-periodic transfers) */ - if (!(host->otg->HFNUM & 1)) - hcchar |= HCCHAR_ODDFRM; - - /* configure channel characteristics and queue a request */ - hc->HCCHAR = hcchar; - if (ep->in && (xfer_packets > 1)) { - /* For IN transfers, try to queue two back-to-back packets. - * This results in a 1% performance gain for Full Speed transfers - */ - if (--spc > STM32_USBH_MIN_QSPACE) { - hc->HCCHAR |= HCCHAR_CHENA; - } else { - uwarnf("\t%s: Could not queue back-to-back packets", ep->name); - } - } - - if (urb->queued == FALSE) { - urb->queued = TRUE; - udbgf("\t%s: Start (%dB)", ep->name, xfer_len); - } else { - udbgf("\t%s: Restart (%dB)", ep->name, xfer_len); - } - - ep->xfer.len = xfer_len; - ep->xfer.packets = (uint16_t)xfer_packets; - - /* remove the channel from the free list, link endpoint <-> channel and move to the active queue*/ - list_del(&hcm->node); - ep->xfer.hcm = hcm; - hcm->ep = ep; - list_move_tail(&ep->node, ep->active_list); - - - stm32_otg_t *const otg = host->otg; - - /* enable this channel's interrupt and global channel interrupt */ - otg->HAINTMSK |= hcm->haintmsk; - if (ep->in) { - otg->GINTMSK |= GINTMSK_HCM; - } else if (usbhEPIsPeriodic(ep)) { - otg->GINTMSK |= GINTMSK_HCM | GINTMSK_PTXFEM; - } else { - //TODO: write to the FIFO now - otg->GINTMSK |= GINTMSK_HCM | GINTMSK_NPTXFEM; - } - - return TRUE; -} - -static bool _update_urb(usbh_ep_t *ep, uint32_t hctsiz, usbh_urb_t *urb, bool completed) { - uint32_t len; - - if (!completed) { - len = ep->wMaxPacketSize * (ep->xfer.packets - ((hctsiz & HCTSIZ_PKTCNT_MASK) >> 19)); - } else { - if (ep->in) { - len = ep->xfer.len - ((hctsiz & HCTSIZ_XFRSIZ_MASK) >> 0); - } else { - len = ep->xfer.len; - } - osalDbgCheck(len == ep->xfer.partial); //TODO: if len == ep->xfer.partial, use this instead of the above code - } - -#if 1 - osalDbgAssert(urb->actualLength + len <= urb->requestedLength, "what happened?"); -#else - if (urb->actualLength + len > urb->requestedLength) { - uerrf("\t%s: Trimming actualLength %u -> %u", ep->name, urb->actualLength + len, urb->requestedLength); - urb->actualLength = urb->requestedLength; - return TRUE; - } -#endif - - urb->actualLength += len; - if ((urb->actualLength == urb->requestedLength) - || (ep->in && completed && (hctsiz & HCTSIZ_XFRSIZ_MASK))) - return TRUE; - - return FALSE; -} - -static void _try_commit_np(USBHDriver *host) { - usbh_ep_t *item, *tmp; - - list_for_each_entry_safe(item, usbh_ep_t, tmp, &host->ep_pending_lists[USBH_EPTYPE_CTRL], node) { - if (!_activate_ep(host, item)) - return; - } - - list_for_each_entry_safe(item, usbh_ep_t, tmp, &host->ep_pending_lists[USBH_EPTYPE_BULK], node) { - if (!_activate_ep(host, item)) - return; - } -} - -static void _try_commit_p(USBHDriver *host, bool sof) { - usbh_ep_t *item, *tmp; - - list_for_each_entry_safe(item, usbh_ep_t, tmp, &host->ep_pending_lists[USBH_EPTYPE_ISO], node) { - if (!_activate_ep(host, item)) - return; - } - - list_for_each_entry_safe(item, usbh_ep_t, tmp, &host->ep_pending_lists[USBH_EPTYPE_INT], node) { - osalDbgCheck(item); - /* TODO: improve this */ - if (sof && item->xfer.u.frame_counter) - --item->xfer.u.frame_counter; - - if (item->xfer.u.frame_counter == 0) { - if (!_activate_ep(host, item)) - return; - item->xfer.u.frame_counter = item->bInterval; - } - } - - if (list_empty(&host->ep_pending_lists[USBH_EPTYPE_ISO]) - && list_empty(&host->ep_pending_lists[USBH_EPTYPE_INT])) { - host->otg->GINTMSK &= ~GINTMSK_SOFM; - } else { - host->otg->GINTMSK |= GINTMSK_SOFM; - } -} - -static void _purge_queue(USBHDriver *host, struct list_head *list) { - usbh_ep_t *ep, *tmp; - list_for_each_entry_safe(ep, usbh_ep_t, tmp, list, node) { - usbh_urb_t *const urb = _active_urb(ep); - stm32_hc_management_t *const hcm = ep->xfer.hcm; - uwarnf("\t%s: Abort URB, USBH_URBSTATUS_DISCONNECTED", ep->name); - if (hcm) { - uwarnf("\t%s: URB had channel %d assigned, halt_reason = %d", ep->name, hcm - host->channels, hcm->halt_reason); - _release_channel(host, hcm); - _update_urb(ep, hcm->hc->HCTSIZ, urb, FALSE); - } - _transfer_completed(ep, urb, USBH_URBSTATUS_DISCONNECTED); - } -} - -static void _purge_active(USBHDriver *host) { - _purge_queue(host, &host->ep_active_lists[0]); - _purge_queue(host, &host->ep_active_lists[1]); - _purge_queue(host, &host->ep_active_lists[2]); - _purge_queue(host, &host->ep_active_lists[3]); -} - -static void _purge_pending(USBHDriver *host) { - _purge_queue(host, &host->ep_pending_lists[0]); - _purge_queue(host, &host->ep_pending_lists[1]); - _purge_queue(host, &host->ep_pending_lists[2]); - _purge_queue(host, &host->ep_pending_lists[3]); -} - -static uint32_t _write_packet(struct list_head *list, uint32_t space_available) { - usbh_ep_t *ep; - - uint32_t remaining = 0; - - list_for_each_entry(ep, usbh_ep_t, list, node) { - if (ep->in || (ep->xfer.hcm->halt_reason != USBH_LLD_HALTREASON_NONE)) - continue; - - int32_t rem = ep->xfer.len - ep->xfer.partial; - osalDbgCheck(rem >= 0); - if (rem <= 0) - continue; - - remaining += rem; - - if (!space_available) { - if (remaining) - break; - - continue; - } - - /* write one packet only */ - if (rem > ep->wMaxPacketSize) - rem = ep->wMaxPacketSize; - - /* round up to dwords */ - uint32_t words = (rem + 3) / 4; - - if (words > space_available) - words = space_available; - - space_available -= words; - - uint32_t written = words * 4; - if ((int32_t)written > rem) - written = rem; - - volatile uint32_t *dest = ep->xfer.hcm->fifo; - uint32_t *src = (uint32_t *)ep->xfer.buf; - udbgf("\t%s: write %d words (%dB), partial=%d", ep->name, words, written, ep->xfer.partial); - while (words--) { - *dest = *src++; - } - - ep->xfer.buf += written; - ep->xfer.partial += written; - - remaining -= written; - } - - return remaining; -} - - -/*===========================================================================*/ -/* API. */ -/*===========================================================================*/ - -void usbh_lld_ep_object_init(usbh_ep_t *ep) { -/* CTRL(IN) CTRL(OUT) INT(IN) INT(OUT) BULK(IN) BULK(OUT) ISO(IN) ISO(OUT) - * STALL si sólo DAT/STAT si si si si no no ep->type != ISO && (ep->type != CTRL || ctrlphase != SETUP) - * ACK si si si si si si no no ep->type != ISO - * NAK si si si si si si no no ep->type != ISO - * BBERR si no si no si no si no ep->in - * TRERR si si si si si si si no ep->type != ISO || ep->in - * DTERR si no si no si no no no ep->type != ISO && ep->in - * FRMOR no no si si no no si si ep->type = PERIODIC - */ - USBHDriver *host = ep->device->host; - uint32_t hcintmsk = HCINTMSK_CHHM | HCINTMSK_XFRCM | HCINTMSK_AHBERRM; - - switch (ep->type) { - case USBH_EPTYPE_ISO: - hcintmsk |= HCINTMSK_FRMORM; - if (ep->in) { - hcintmsk |= HCINTMSK_TRERRM | HCINTMSK_BBERRM; - } - break; - case USBH_EPTYPE_INT: - hcintmsk |= HCINTMSK_TRERRM | HCINTMSK_FRMORM | HCINTMSK_STALLM | HCINTMSK_NAKM; - if (ep->in) { - hcintmsk |= HCINTMSK_DTERRM | HCINTMSK_BBERRM; - } - ep->xfer.u.frame_counter = 1; - break; - case USBH_EPTYPE_CTRL: - hcintmsk |= HCINTMSK_TRERRM | HCINTMSK_STALLM | HCINTMSK_NAKM; - break; - case USBH_EPTYPE_BULK: - hcintmsk |= HCINTMSK_TRERRM | HCINTMSK_STALLM | HCINTMSK_NAKM; - if (ep->in) { - hcintmsk |= HCINTMSK_DTERRM | HCINTMSK_BBERRM; - } - break; - default: - chDbgCheck(0); - } - ep->active_list = &host->ep_active_lists[ep->type]; - ep->pending_list = &host->ep_pending_lists[ep->type]; - INIT_LIST_HEAD(&ep->urb_list); - INIT_LIST_HEAD(&ep->node); - - ep->hcintmsk = hcintmsk; - ep->hcchar = HCCHAR_CHENA - | HCCHAR_DAD(ep->device->address) - | HCCHAR_MCNT(1) - | HCCHAR_EPTYP(ep->type) - | ((ep->device->speed == USBH_DEVSPEED_LOW) ? HCCHAR_LSDEV : 0) - | (ep->in ? HCCHAR_EPDIR : 0) - | HCCHAR_EPNUM(ep->address) - | HCCHAR_MPS(ep->wMaxPacketSize); -} - -void usbh_lld_ep_open(usbh_ep_t *ep) { - uinfof("\t%s: Open EP", ep->name); - ep->status = USBH_EPSTATUS_OPEN; - osalOsRescheduleS(); -} - -void usbh_lld_ep_close(usbh_ep_t *ep) { - usbh_urb_t *urb, *tmp; - uinfof("\t%s: Closing EP...", ep->name); - list_for_each_entry_safe(urb, usbh_urb_t, tmp, &ep->urb_list, node) { - uinfof("\t%s: Abort URB, USBH_URBSTATUS_DISCONNECTED", ep->name); - _usbh_urb_abort_and_waitS(urb, USBH_URBSTATUS_DISCONNECTED); - } - uinfof("\t%s: Closed", ep->name); - ep->status = USBH_EPSTATUS_CLOSED; - osalOsRescheduleS(); -} - -void usbh_lld_urb_submit(usbh_urb_t *urb) { - usbh_ep_t *const ep = urb->ep; - - /* add the URB to the EP's queue */ - list_add_tail(&urb->node, &ep->urb_list); - - /* check if the EP wasn't in any queue (pending nor active) */ - if (list_empty(&ep->node)) { - - /* add the EP to the pending queue */ - _move_to_pending_queue(ep); - - if (usbhEPIsPeriodic(ep)) { - ep->device->host->otg->GINTMSK |= GINTMSK_SOFM; - } else { - /* try to queue non-periodic transfers */ - _try_commit_np(ep->device->host); - } - } -} - -bool usbh_lld_urb_abort(usbh_urb_t *urb, usbh_urbstatus_t status) { - osalDbgCheck(usbhURBIsBusy(urb)); - - usbh_ep_t *const ep = urb->ep; - osalDbgCheck(ep); - stm32_hc_management_t *const hcm = ep->xfer.hcm; - - if ((hcm != NULL) && (urb == _active_urb(ep))) { - /* This URB is active (channel assigned, top of the EP's URB list) */ - - if (hcm->halt_reason == USBH_LLD_HALTREASON_NONE) { - /* The channel is not being halted */ - urb->status = status; - _halt_channel(ep->device->host, hcm, USBH_LLD_HALTREASON_ABORT); - } else { - /* The channel is being halted, so we can't re-halt it. The CHH interrupt will - * be in charge of completing the transfer, but the URB will not have the specified status. - */ - } - return FALSE; - } - - /* This URB is active, we can cancel it now */ - _transfer_completedI(ep, urb, status); - - return TRUE; -} - - -/*===========================================================================*/ -/* Channel Interrupts. */ -/*===========================================================================*/ - -//CTRL(IN) CTRL(OUT) INT(IN) INT(OUT) BULK(IN) BULK(OUT) ISO(IN) ISO(OUT) -// si si si si si si no no ep->type != ISO && !ep->in -static inline void _ack_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) { - (void)host; - osalDbgAssert(hcm->ep->type != USBH_EPTYPE_ISO, "ACK should not happen in ISO endpoints"); - hcm->ep->xfer.error_count = 0; - hc->HCINTMSK &= ~HCINTMSK_ACKM; - udbgf("\t%s: ACK", hcm->ep->name); -} - -//CTRL(IN) CTRL(OUT) INT(IN) INT(OUT) BULK(IN) BULK(OUT) ISO(IN) ISO(OUT) -// si no si no si no no no ep->type != ISO && ep->in -static inline void _dterr_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) { - (void)host; - osalDbgAssert(hcm->ep->in && (hcm->ep->type != USBH_EPTYPE_ISO), "DTERR should not happen in OUT or ISO endpoints"); -#if 0 - hc->HCINTMSK &= ~(HCINTMSK_DTERRM | HCINTMSK_ACKM); - hcm->ep->xfer.error_count = 0; - _halt_channel(host, hcm, USBH_LLD_HALTREASON_ERROR); -#else - /* restart directly, no need to halt it in this case */ - hcm->ep->xfer.error_count = 0; - hc->HCINTMSK &= ~HCINTMSK_ACKM; - hc->HCCHAR |= HCCHAR_CHENA; -#endif - uerrf("\t%s: DTERR", hcm->ep->name); -} - -//CTRL(IN) CTRL(OUT) INT(IN) INT(OUT) BULK(IN) BULK(OUT) ISO(IN) ISO(OUT) -// si no si no si no si no ep->in -static inline void _bberr_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) { - osalDbgAssert(hcm->ep->in, "BBERR should not happen in OUT endpoints"); - hc->HCINTMSK &= ~HCINTMSK_BBERRM; - hcm->ep->xfer.error_count = 3; - _halt_channel(host, hcm, USBH_LLD_HALTREASON_ERROR); - uerrf("\t%s: BBERR", hcm->ep->name); -} - -///CTRL(IN) CTRL(OUT) INT(IN) INT(OUT) BULK(IN) BULK(OUT) ISO(IN) ISO(OUT) -// si si si si si si si no ep->type != ISO || ep->in -static inline void _trerr_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) { - osalDbgAssert(hcm->ep->in || (hcm->ep->type != USBH_EPTYPE_ISO), "TRERR should not happen in ISO OUT endpoints"); - hc->HCINTMSK &= ~HCINTMSK_TRERRM; - ++hcm->ep->xfer.error_count; - _halt_channel(host, hcm, USBH_LLD_HALTREASON_ERROR); - uerrf("\t%s: TRERR", hcm->ep->name); -} - -//CTRL(IN) CTRL(OUT) INT(IN) INT(OUT) BULK(IN) BULK(OUT) ISO(IN) ISO(OUT) -// no no si si no no si si ep->type = PERIODIC -static inline void _frmor_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) { - osalDbgAssert(usbhEPIsPeriodic(hcm->ep), "FRMOR should not happen in non-periodic endpoints"); - hc->HCINTMSK &= ~HCINTMSK_FRMORM; - hcm->ep->xfer.error_count = 3; - _halt_channel(host, hcm, USBH_LLD_HALTREASON_ERROR); - uerrf("\t%s: FRMOR", hcm->ep->name); -} - -//CTRL(IN) CTRL(OUT) INT(IN) INT(OUT) BULK(IN) BULK(OUT) ISO(IN) ISO(OUT) -// si si si si si si no no ep->type != ISO -static inline void _nak_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) { - osalDbgAssert(hcm->ep->type != USBH_EPTYPE_ISO, "NAK should not happen in ISO endpoints"); - if (!hcm->ep->in || (hcm->ep->type == USBH_EPTYPE_INT)) { - hc->HCINTMSK &= ~HCINTMSK_NAKM; - _halt_channel(host, hcm, USBH_LLD_HALTREASON_NAK); - } else { - /* restart directly, no need to halt it in this case */ - hcm->ep->xfer.error_count = 0; - hc->HCINTMSK &= ~HCINTMSK_ACKM; - hc->HCCHAR |= HCCHAR_CHENA; - } - udbgf("\t%s: NAK", hcm->ep->name); -} - -//CTRL(IN) CTRL(OUT) INT(IN) INT(OUT) BULK(IN) BULK(OUT) ISO(IN) ISO(OUT) -// si sólo DAT/STAT si si si si no no ep->type != ISO && (ep->type != CTRL || ctrlphase != SETUP) -static inline void _stall_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) { - osalDbgAssert(hcm->ep->type != USBH_EPTYPE_ISO, "STALL should not happen in ISO endpoints"); - hc->HCINTMSK &= ~HCINTMSK_STALLM; - _halt_channel(host, hcm, USBH_LLD_HALTREASON_STALL); - uwarnf("\t%s: STALL", hcm->ep->name); -} - -static void _complete_bulk_int(USBHDriver *host, stm32_hc_management_t *hcm, usbh_ep_t *ep, usbh_urb_t *urb, uint32_t hctsiz) { - _release_channel(host, hcm); - _save_dt_mask(ep, hctsiz); - if (_update_urb(ep, hctsiz, urb, TRUE)) { - udbgf("\t%s: done", ep->name); - _transfer_completed(ep, urb, USBH_URBSTATUS_OK); - } else { - osalDbgCheck(urb->requestedLength > 0x7FFFF); - uwarnf("\t%s: incomplete", ep->name); - _move_to_pending_queue(ep); - } - if (usbhEPIsPeriodic(ep)) { - _try_commit_p(host, FALSE); - } else { - _try_commit_np(host); - } -} - -static void _complete_control(USBHDriver *host, stm32_hc_management_t *hcm, usbh_ep_t *ep, usbh_urb_t *urb, uint32_t hctsiz) { - osalDbgCheck(ep->xfer.u.ctrl_phase != USBH_LLD_CTRLPHASE_SETUP); - - _release_channel(host, hcm); - if (ep->xfer.u.ctrl_phase == USBH_LLD_CTRLPHASE_DATA) { - if (_update_urb(ep, hctsiz, urb, TRUE)) { - udbgf("\t%s: DATA done", ep->name); - ep->xfer.u.ctrl_phase = USBH_LLD_CTRLPHASE_STATUS; - ep->in = !ep->in; - } else { - osalDbgCheck(urb->requestedLength > 0x7FFFF); - uwarnf("\t%s: DATA incomplete", ep->name); - _save_dt_mask(ep, hctsiz); - } - _move_to_pending_queue(ep); - } else { - osalDbgCheck(ep->xfer.u.ctrl_phase == USBH_LLD_CTRLPHASE_STATUS); - udbgf("\t%s: STATUS done", ep->name); - _transfer_completed(ep, urb, USBH_URBSTATUS_OK); - } - _try_commit_np(host); -} - -static void _complete_control_setup(USBHDriver *host, stm32_hc_management_t *hcm, usbh_ep_t *ep, usbh_urb_t *urb) { - _release_channel(host, hcm); - if (urb->requestedLength) { - udbgf("\t%s: SETUP done -> DATA", ep->name); - ep->xfer.u.ctrl_phase = USBH_LLD_CTRLPHASE_DATA; - ep->in = *((uint8_t *)urb->setup_buff) & 0x80 ? TRUE : FALSE; - ep->dt_mask = HCTSIZ_DPID_DATA1; - ep->xfer.error_count = 0; - } else { - udbgf("\t%s: SETUP done -> STATUS", ep->name); - ep->in = TRUE; - ep->xfer.u.ctrl_phase = USBH_LLD_CTRLPHASE_STATUS; - } - _move_to_pending_queue(ep); - _try_commit_np(host); -} - -static void _complete_iso(USBHDriver *host, stm32_hc_management_t *hcm, usbh_ep_t *ep, usbh_urb_t *urb, uint32_t hctsiz) { - udbgf("\t%s: done", hcm->ep->name); - _release_channel(host, hcm); - _update_urb(ep, hctsiz, urb, TRUE); - _transfer_completed(ep, urb, USBH_URBSTATUS_OK); - _try_commit_p(host, FALSE); -} - -static inline void _xfrc_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) { - usbh_ep_t *const ep = hcm->ep; - usbh_urb_t *const urb = _active_urb(ep); - osalDbgCheck(urb); - uint32_t hctsiz = hc->HCTSIZ; - - hc->HCINTMSK &= ~HCINTMSK_XFRCM; - - switch (ep->type) { - case USBH_EPTYPE_CTRL: - if (ep->xfer.u.ctrl_phase == USBH_LLD_CTRLPHASE_SETUP) { - _complete_control_setup(host, hcm, ep, urb); - } else if (ep->in) { - _halt_channel(host, hcm, USBH_LLD_HALTREASON_XFRC); - } else { - _complete_control(host, hcm, ep, urb, hctsiz); - } - break; - - case USBH_EPTYPE_BULK: - if (ep->in) { - _halt_channel(host, hcm, USBH_LLD_HALTREASON_XFRC); - } else { - _complete_bulk_int(host, hcm, ep, urb, hctsiz); - } - break; - - case USBH_EPTYPE_INT: - if (ep->in && (hctsiz & HCTSIZ_PKTCNT_MASK)) { - _halt_channel(host, hcm, USBH_LLD_HALTREASON_XFRC); - } else { - _complete_bulk_int(host, hcm, ep, urb, hctsiz); - } - break; - - case USBH_EPTYPE_ISO: - if (ep->in && (hctsiz & HCTSIZ_PKTCNT_MASK)) { - _halt_channel(host, hcm, USBH_LLD_HALTREASON_XFRC); - } else { - _complete_iso(host, hcm, ep, urb, hctsiz); - } - break; - } -} - -static inline void _chh_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) { - - usbh_ep_t *const ep = hcm->ep; - usbh_urb_t *const urb = _active_urb(ep); - osalDbgCheck(urb); - uint32_t hctsiz = hc->HCTSIZ; - usbh_lld_halt_reason_t reason = hcm->halt_reason; - - //osalDbgCheck(reason != USBH_LLD_HALTREASON_NONE); - if (reason == USBH_LLD_HALTREASON_NONE) { - uwarnf("\tCHH: ch=%d, USBH_LLD_HALTREASON_NONE", hcm - host->channels); - return; - } - - if (reason == USBH_LLD_HALTREASON_XFRC) { - osalDbgCheck(ep->in); - switch (ep->type) { - case USBH_EPTYPE_CTRL: - _complete_control(host, hcm, ep, urb, hctsiz); - break; - case USBH_EPTYPE_BULK: - case USBH_EPTYPE_INT: - _complete_bulk_int(host, hcm, ep, urb, hctsiz); - break; - case USBH_EPTYPE_ISO: - _complete_iso(host, hcm, ep, urb, hctsiz); - break; - } - } else { - _release_channel(host, hcm); - _save_dt_mask(ep, hctsiz); - bool done = _update_urb(ep, hctsiz, urb, FALSE); - - switch (reason) { - case USBH_LLD_HALTREASON_NAK: - if ((ep->type == USBH_EPTYPE_INT) && ep->in) { - _transfer_completed(ep, urb, USBH_URBSTATUS_TIMEOUT); - } else { - ep->xfer.error_count = 0; - _move_to_pending_queue(ep); - } - break; - - case USBH_LLD_HALTREASON_STALL: - if ((ep->type == USBH_EPTYPE_CTRL) && (ep->xfer.u.ctrl_phase == USBH_LLD_CTRLPHASE_SETUP)) { - uerrf("\t%s: Faulty device: STALLed SETUP phase", ep->name); - } - _transfer_completed(ep, urb, USBH_URBSTATUS_STALL); - break; - - case USBH_LLD_HALTREASON_ERROR: - if ((ep->type == USBH_EPTYPE_ISO) || done || (ep->xfer.error_count >= 3)) { - _transfer_completed(ep, urb, USBH_URBSTATUS_ERROR); - } else { - uerrf("\t%s: err=%d, done=%d, retry", ep->name, ep->xfer.error_count, done); - _move_to_pending_queue(ep); - } - break; - - case USBH_LLD_HALTREASON_ABORT: - uwarnf("\t%s: Abort", ep->name); - _transfer_completed(ep, urb, urb->status); - break; - - default: - osalDbgCheck(0); - break; - } - - if (usbhEPIsPeriodic(ep)) { - _try_commit_p(host, FALSE); - } else { - _try_commit_np(host); - } - } -} - -static void _hcint_n_int(USBHDriver *host, uint8_t chn) { - - stm32_hc_management_t *const hcm = &host->channels[chn]; - stm32_otg_host_chn_t *const hc = hcm->hc; - - uint32_t hcint = hc->HCINT; - hcint &= hc->HCINTMSK; - hc->HCINT = hcint; - - osalDbgCheck((hcint & HCINTMSK_AHBERRM) == 0); - osalDbgCheck(hcm->ep); - - if (hcint & HCINTMSK_STALLM) - _stall_int(host, hcm, hc); - if (hcint & HCINTMSK_NAKM) - _nak_int(host, hcm, hc); - if (hcint & HCINTMSK_ACKM) - _ack_int(host, hcm, hc); - if (hcint & HCINTMSK_TRERRM) - _trerr_int(host, hcm, hc); - if (hcint & HCINTMSK_BBERRM) - _bberr_int(host, hcm, hc); - if (hcint & HCINTMSK_FRMORM) - _frmor_int(host, hcm, hc); - if (hcint & HCINTMSK_DTERRM) - _dterr_int(host, hcm, hc); - if (hcint & HCINTMSK_XFRCM) - _xfrc_int(host, hcm, hc); - if (hcint & HCINTMSK_CHHM) - _chh_int(host, hcm, hc); -} - -static inline void _hcint_int(USBHDriver *host) { - uint32_t haint; - - haint = host->otg->HAINT; - haint &= host->otg->HAINTMSK; - - if (!haint) { - uerrf("HAINT=%08x, HAINTMSK=%08x", host->otg->HAINT, host->otg->HAINTMSK); - return; - } - -#if 1 //channel lookup loop - uint8_t i; - for (i = 0; haint && (i < host->channels_number); i++) { - if (haint & (1 << i)) { - _hcint_n_int(host, i); - haint &= ~(1 << i); - } - } -#else //faster calculation, with __CLZ (count leading zeroes) - while (haint) { - uint8_t chn = (uint8_t)(31 - __CLZ(haint)); - osalDbgAssert(chn < host->channels_number, "what?"); - haint &= ~host->channels[chn].haintmsk; - _hcint_n_int(host, chn); - } -#endif -} - - -/*===========================================================================*/ -/* Host interrupts. */ -/*===========================================================================*/ -static inline void _sof_int(USBHDriver *host) { - udbg("SOF"); - _try_commit_p(host, TRUE); -} - -static inline void _rxflvl_int(USBHDriver *host) { - - stm32_otg_t *const otg = host->otg; - - otg->GINTMSK &= ~GINTMSK_RXFLVLM; - while (otg->GINTSTS & GINTSTS_RXFLVL) { - uint32_t grxstsp = otg->GRXSTSP; - osalDbgCheck((grxstsp & GRXSTSP_CHNUM_MASK) < host->channels_number); - stm32_hc_management_t *const hcm = &host->channels[grxstsp & GRXSTSP_CHNUM_MASK]; - uint32_t hctsiz = hcm->hc->HCTSIZ; - - if ((grxstsp & GRXSTSP_PKTSTS_MASK) == GRXSTSP_PKTSTS(2)) { - /* 0010: IN data packet received */ - usbh_ep_t *const ep = hcm->ep; - osalDbgCheck(ep); - - /* restart the channel ASAP */ - if (hctsiz & HCTSIZ_PKTCNT_MASK) { -#if CH_DBG_ENABLE_CHECKS - if (usbhEPIsPeriodic(ep)) { - osalDbgCheck(host->otg->HPTXSTS & HPTXSTS_PTXQSAV_MASK); - } else { - osalDbgCheck(host->otg->HNPTXSTS & HPTXSTS_PTXQSAV_MASK); - } -#endif - hcm->hc->HCCHAR |= HCCHAR_CHENA; - } - - udbgf("\t%s: RXFLVL rx=%dB, rem=%dB (%dpkts)", - ep->name, - (grxstsp & GRXSTSP_BCNT_MASK) >> 4, - (hctsiz & HCTSIZ_XFRSIZ_MASK), - (hctsiz & HCTSIZ_PKTCNT_MASK) >> 19); - - /* Read */ - uint32_t *dest = (uint32_t *)ep->xfer.buf; - volatile uint32_t *const src = hcm->fifo; - - uint32_t bcnt = (grxstsp & GRXSTSP_BCNT_MASK) >> GRXSTSP_BCNT_OFF; - osalDbgCheck(bcnt + ep->xfer.partial <= ep->xfer.len); - - //TODO: optimize this - uint32_t words = bcnt / 4; - uint8_t bytes = bcnt & 3; - while (words--) { - *dest++ = *src; - } - if (bytes) { - uint32_t r = *src; - uint8_t *bsrc = (uint8_t *)&r; - uint8_t *bdest = (uint8_t *)dest; - do { - *bdest++ = *bsrc++; - } while (--bytes); - } - - ep->xfer.buf += bcnt; - ep->xfer.partial += bcnt; - -#if 0 //STM32_USBH_CHANNELS_NP > 1 - /* check bug */ - if (hctsiz & HCTSIZ_PKTCNT_MASK) { - uint32_t pkt = (hctsiz & HCTSIZ_PKTCNT_MASK) >> 19; - uint32_t siz = (hctsiz & HCTSIZ_XFRSIZ_MASK); - if (pkt * ep->wMaxPacketSize != siz) { - uerrf("\t%s: whatttt???", ep->name); - } - } -#endif - -#if USBH_DEBUG_ENABLE && USBH_LLD_DEBUG_ENABLE_ERRORS - } else { - /* 0011: IN transfer completed (triggers an interrupt) - * 0101: Data toggle error (triggers an interrupt) - * 0111: Channel halted (triggers an interrupt) - */ - switch (grxstsp & GRXSTSP_PKTSTS_MASK) { - case GRXSTSP_PKTSTS(3): - case GRXSTSP_PKTSTS(5): - case GRXSTSP_PKTSTS(7): - break; - default: - uerrf("\tRXFLVL: ch=%d, UNK=%d", grxstsp & GRXSTSP_CHNUM_MASK, (grxstsp & GRXSTSP_PKTSTS_MASK) >> 17); - break; - } -#endif - } - } - otg->GINTMSK |= GINTMSK_RXFLVLM; -} - -static inline void _nptxfe_int(USBHDriver *host) { - uint32_t rem; - stm32_otg_t *const otg = host->otg; - - rem = _write_packet(&host->ep_active_lists[USBH_EPTYPE_CTRL], - otg->HNPTXSTS & HPTXSTS_PTXFSAVL_MASK); - - rem += _write_packet(&host->ep_active_lists[USBH_EPTYPE_BULK], - otg->HNPTXSTS & HPTXSTS_PTXFSAVL_MASK); - -// if (rem) -// otg->GINTMSK |= GINTMSK_NPTXFEM; - - if (!rem) - otg->GINTMSK &= ~GINTMSK_NPTXFEM; - -} - -static inline void _ptxfe_int(USBHDriver *host) { - //TODO: implement - (void)host; - uinfo("PTXFE"); -} - -static inline void _discint_int(USBHDriver *host) { - uint32_t hprt = host->otg->HPRT; - - uwarn("\tDISCINT"); - - if (!(hprt & HPRT_PCSTS)) { - host->rootport.lld_status &= ~(USBH_PORTSTATUS_CONNECTION | USBH_PORTSTATUS_ENABLE); - host->rootport.lld_c_status |= USBH_PORTSTATUS_C_CONNECTION | USBH_PORTSTATUS_C_ENABLE; - } - _purge_active(host); - _purge_pending(host); -} - -static inline void _hprtint_int(USBHDriver *host) { - stm32_otg_t *const otg = host->otg; - uint32_t hprt = otg->HPRT; - - /* note: writing PENA = 1 actually disables the port */ - uint32_t hprt_clr = hprt & ~(HPRT_PENA | HPRT_PCDET | HPRT_PENCHNG | HPRT_POCCHNG); - - if (hprt & HPRT_PCDET) { - hprt_clr |= HPRT_PCDET; - if (hprt & HPRT_PCSTS) { - uinfo("\tHPRT: Port connection detected"); - host->rootport.lld_status |= USBH_PORTSTATUS_CONNECTION; - host->rootport.lld_c_status |= USBH_PORTSTATUS_C_CONNECTION; - } else { - uinfo("\tHPRT: Port disconnection detected"); - } - } - - if (hprt & HPRT_PENCHNG) { - hprt_clr |= HPRT_PENCHNG; - if (hprt & HPRT_PENA) { - uinfo("\tHPRT: Port enabled"); - host->rootport.lld_status |= USBH_PORTSTATUS_ENABLE; - host->rootport.lld_status &= ~(USBH_PORTSTATUS_HIGH_SPEED | USBH_PORTSTATUS_LOW_SPEED); - - /* Make sure the FIFOs are flushed. */ - otg_txfifo_flush(host, 0x10); - otg_rxfifo_flush(host); - - /* Clear all pending HC Interrupts */ - uint8_t i; - for (i = 0; i < host->channels_number; i++) { - otg->hc[i].HCINTMSK = 0; - otg->hc[i].HCINT = 0xFFFFFFFF; - } - - /* configure speed */ - if ((hprt & HPRT_PSPD_MASK) == HPRT_PSPD_LS) { - host->rootport.lld_status |= USBH_PORTSTATUS_LOW_SPEED; - otg->HFIR = 6000; - otg->HCFG = (otg->HCFG & ~HCFG_FSLSPCS_MASK) | HCFG_FSLSPCS_6; - } else { - otg->HFIR = 48000; - otg->HCFG = (otg->HCFG & ~HCFG_FSLSPCS_MASK) | HCFG_FSLSPCS_48; - } - } else { - if (hprt & HPRT_PCSTS) { - if (hprt & HPRT_POCA) { - uerr("\tHPRT: Port disabled due to overcurrent"); - } else { - uerr("\tHPRT: Port disabled due to port babble"); - } - } else { - uerr("\tHPRT: Port disabled due to disconnect"); - } - - _purge_active(host); - _purge_pending(host); - - host->rootport.lld_status &= ~USBH_PORTSTATUS_ENABLE; - } - host->rootport.lld_c_status |= USBH_PORTSTATUS_C_ENABLE; - } - - if (hprt & HPRT_POCCHNG) { - hprt_clr |= HPRT_POCCHNG; - if (hprt & HPRT_POCA) { - uerr("\tHPRT: Overcurrent"); - host->rootport.lld_status |= USBH_PORTSTATUS_OVERCURRENT; - } else { - udbg("\tHPRT: Clear overcurrent"); - host->rootport.lld_status &= ~USBH_PORTSTATUS_OVERCURRENT; - } - host->rootport.lld_c_status |= USBH_PORTSTATUS_C_OVERCURRENT; - } - - otg->HPRT = hprt_clr; -} - -static void usb_lld_serve_interrupt(USBHDriver *host) { - osalDbgCheck(host && (host->status != USBH_STATUS_STOPPED)); - - stm32_otg_t *const otg = host->otg; - uint32_t gintsts = otg->GINTSTS; - - /* check host mode */ - if (!(gintsts & GINTSTS_CMOD)) { - uerr("Device mode"); - otg->GINTSTS = gintsts; - return; - } - - /* check mismatch */ - if (gintsts & GINTSTS_MMIS) { - uerr("Mode Mismatch"); - otg->GINTSTS = gintsts; - return; - } - - gintsts &= otg->GINTMSK; - if (!gintsts) { - uwarnf("GINTSTS=%08x, GINTMSK=%08x", otg->GINTSTS, otg->GINTMSK); - return; - } -// otg->GINTMSK &= ~(GINTMSK_NPTXFEM | GINTMSK_PTXFEM); - otg->GINTSTS = gintsts; - - if (gintsts & GINTSTS_SOF) - _sof_int(host); - if (gintsts & GINTSTS_RXFLVL) - _rxflvl_int(host); - if (gintsts & GINTSTS_HPRTINT) - _hprtint_int(host); - if (gintsts & GINTSTS_DISCINT) - _discint_int(host); - if (gintsts & GINTSTS_HCINT) - _hcint_int(host); - if (gintsts & GINTSTS_NPTXFE) - _nptxfe_int(host); - if (gintsts & GINTSTS_PTXFE) - _ptxfe_int(host); - if (gintsts & GINTSTS_IPXFR) { - uerr("IPXFRM"); - } -} - - -/*===========================================================================*/ -/* Interrupt handlers. */ -/*===========================================================================*/ - -#if STM32_USBH_USE_OTG1 -OSAL_IRQ_HANDLER(STM32_OTG1_HANDLER) { - OSAL_IRQ_PROLOGUE(); - osalSysLockFromISR(); - usb_lld_serve_interrupt(&USBHD1); - osalSysUnlockFromISR(); - OSAL_IRQ_EPILOGUE(); -} -#endif - -#if STM32_USBH_USE_OTG2 -OSAL_IRQ_HANDLER(STM32_OTG2_HANDLER) { - OSAL_IRQ_PROLOGUE(); - osalSysLockFromISR(); - usb_lld_serve_interrupt(&USBHD2); - osalSysUnlockFromISR(); - OSAL_IRQ_EPILOGUE(); -} -#endif - - -/*===========================================================================*/ -/* Initialization functions. */ -/*===========================================================================*/ -static void otg_core_reset(USBHDriver *usbp) { - stm32_otg_t *const otgp = usbp->otg; - - /* Wait AHB idle condition.*/ - while ((otgp->GRSTCTL & GRSTCTL_AHBIDL) == 0) - ; - - osalSysPolledDelayX(64); - - /* Core reset and delay of at least 3 PHY cycles.*/ - otgp->GRSTCTL = GRSTCTL_CSRST; - while ((otgp->GRSTCTL & GRSTCTL_CSRST) != 0) - ; - - osalSysPolledDelayX(24); - - /* Wait AHB idle condition.*/ - while ((otgp->GRSTCTL & GRSTCTL_AHBIDL) == 0) - ; -} - -static void otg_rxfifo_flush(USBHDriver *usbp) { - stm32_otg_t *const otgp = usbp->otg; - - otgp->GRSTCTL = GRSTCTL_RXFFLSH; - while ((otgp->GRSTCTL & GRSTCTL_RXFFLSH) != 0) - ; - /* Wait for 3 PHY Clocks.*/ - osalSysPolledDelayX(24); -} - -static void otg_txfifo_flush(USBHDriver *usbp, uint32_t fifo) { - stm32_otg_t *const otgp = usbp->otg; - - otgp->GRSTCTL = GRSTCTL_TXFNUM(fifo) | GRSTCTL_TXFFLSH; - while ((otgp->GRSTCTL & GRSTCTL_TXFFLSH) != 0) - ; - /* Wait for 3 PHY Clocks.*/ - osalSysPolledDelayX(24); -} - -static void _init(USBHDriver *host) { - int i; - - usbhObjectInit(host); - -#if STM32_USBH_USE_OTG1 -#if STM32_USBH_USE_OTG2 - if (&USBHD1 == host) { -#endif - host->otg = OTG_FS; - host->channels_number = STM32_OTG1_CHANNELS_NUMBER; -#if STM32_USBH_USE_OTG2 - } -#endif -#endif - -#if STM32_USBH_USE_OTG2 -#if STM32_USBH_USE_OTG1 - if (&USBHD2 == host) { -#endif - host->otg = OTG_HS; - host->channels_number = STM32_OTG2_CHANNELS_NUMBER; -#if STM32_USBH_USE_OTG1 - } -#endif -#endif - INIT_LIST_HEAD(&host->ch_free[0]); - INIT_LIST_HEAD(&host->ch_free[1]); - for (i = 0; i < host->channels_number; i++) { - host->channels[i].haintmsk = 1 << i; - host->channels[i].hc = &host->otg->hc[i]; - host->channels[i].fifo = host->otg->FIFO[i]; - if (i < STM32_USBH_CHANNELS_NP) { - list_add_tail(&host->channels[i].node, &host->ch_free[1]); - } else { - list_add_tail(&host->channels[i].node, &host->ch_free[0]); - } - } - for (i = 0; i < 4; i++) { - INIT_LIST_HEAD(&host->ep_active_lists[i]); - INIT_LIST_HEAD(&host->ep_pending_lists[i]); - } -} - -void usbh_lld_init(void) { -#if STM32_USBH_USE_OTG1 - _init(&USBHD1); -#endif -#if STM32_USBH_USE_OTG2 - _init(&USBHD2); -#endif -} - -static void _usbh_start(USBHDriver *usbh) { - stm32_otg_t *const otgp = usbh->otg; - - /* Clock activation.*/ -#if STM32_USBH_USE_OTG1 -#if STM32_USBH_USE_OTG2 - if (&USBHD1 == usbh) { -#endif - /* OTG FS clock enable and reset.*/ - rccEnableOTG_FS(FALSE); - rccResetOTG_FS(); - - otgp->GINTMSK = 0; - - /* Enables IRQ vector.*/ - nvicEnableVector(STM32_OTG1_NUMBER, STM32_USB_OTG1_IRQ_PRIORITY); -#if STM32_USBH_USE_OTG2 - } -#endif -#endif - -#if STM32_USBH_USE_OTG2 -#if STM32_USBH_USE_OTG1 - if (&USBHD2 == usbh) { -#endif - /* OTG HS clock enable and reset.*/ - rccEnableOTG_HS(FALSE); - rccResetOTG_HS(); - - otgp->GINTMSK = 0; - - /* Enables IRQ vector.*/ - nvicEnableVector(STM32_OTG2_NUMBER, STM32_USB_OTG2_IRQ_PRIORITY); -#if STM32_USBH_USE_OTG1 - } -#endif -#endif - - otgp->GUSBCFG = GUSBCFG_PHYSEL | GUSBCFG_TRDT(5); - - otg_core_reset(usbh); - - otgp->GCCFG = GCCFG_PWRDWN; - - /* Forced host mode. */ - otgp->GUSBCFG = GUSBCFG_FHMOD | GUSBCFG_PHYSEL | GUSBCFG_TRDT(5); - - /* PHY enabled.*/ - otgp->PCGCCTL = 0; - - /* Internal FS PHY activation.*/ -#if defined(BOARD_OTG_NOVBUSSENS) - otgp->GCCFG = GCCFG_NOVBUSSENS | GCCFG_PWRDWN; -#else - otgp->GCCFG = GCCFG_PWRDWN; -#endif - - /* 48MHz 1.1 PHY.*/ - otgp->HCFG = HCFG_FSLSS | HCFG_FSLSPCS_48; - - /* Interrupts on FIFOs half empty.*/ - otgp->GAHBCFG = 0; - - otgp->GOTGINT = 0xFFFFFFFF; - - otgp->HPRT |= HPRT_PPWR; - - /* without this delay, the FIFO sizes are set INcorrectly */ - osalThreadSleepS(MS2ST(200)); - -#define HNPTXFSIZ DIEPTXF0 -#if STM32_USBH_USE_OTG1 -#if STM32_USBH_USE_OTG2 - if (&USBHD1 == usbh) { -#endif - otgp->GRXFSIZ = GRXFSIZ_RXFD(STM32_OTG1_RXFIFO_SIZE / 4); - otgp->HNPTXFSIZ = HPTXFSIZ_PTXSA((STM32_OTG1_RXFIFO_SIZE / 4)) | HPTXFSIZ_PTXFD(STM32_OTG1_NPTXFIFO_SIZE / 4); - otgp->HPTXFSIZ = HPTXFSIZ_PTXSA((STM32_OTG1_RXFIFO_SIZE / 4) + (STM32_OTG1_NPTXFIFO_SIZE / 4)) | HPTXFSIZ_PTXFD(STM32_OTG1_PTXFIFO_SIZE / 4); -#if STM32_USBH_USE_OTG2 - } -#endif -#endif -#if STM32_USBH_USE_OTG2 -#if STM32_USBH_USE_OTG1 - if (&USBHD2 == usbh) { -#endif - otgp->GRXFSIZ = GRXFSIZ_RXFD(STM32_OTG2_RXFIFO_SIZE / 4); - otgp->HNPTXFSIZ = HPTXFSIZ_PTXSA((STM32_OTG2_RXFIFO_SIZE / 4)) | HPTXFSIZ_PTXFD(STM32_OTG2_NPTXFIFO_SIZE / 4); - otgp->HPTXFSIZ = HPTXFSIZ_PTXSA((STM32_OTG2_RXFIFO_SIZE / 4) + (STM32_OTG2_NPTXFIFO_SIZE / 4)) | HPTXFSIZ_PTXFD(STM32_OTG2_PTXFIFO_SIZE / 4); -#if STM32_USBH_USE_OTG1 - } -#endif -#endif - - otg_txfifo_flush(usbh, 0x10); - otg_rxfifo_flush(usbh); - - otgp->GINTSTS = 0xffffffff; - otgp->GINTMSK = GINTMSK_DISCM /*| GINTMSK_PTXFEM*/ | GINTMSK_HCM | GINTMSK_HPRTM - /*| GINTMSK_IPXFRM | GINTMSK_NPTXFEM*/ | GINTMSK_RXFLVLM - /*| GINTMSK_SOFM */ | GINTMSK_MMISM; - - usbh->rootport.lld_status = USBH_PORTSTATUS_POWER; - usbh->rootport.lld_c_status = 0; - - /* Global interrupts enable.*/ - otgp->GAHBCFG |= GAHBCFG_GINTMSK; -} - -void usbh_lld_start(USBHDriver *usbh) { - if (usbh->status != USBH_STATUS_STOPPED) return; - _usbh_start(usbh); -} - -/*===========================================================================*/ -/* Root Hub request handler. */ -/*===========================================================================*/ -usbh_urbstatus_t usbh_lld_root_hub_request(USBHDriver *usbh, uint8_t bmRequestType, uint8_t bRequest, - uint16_t wvalue, uint16_t windex, uint16_t wlength, uint8_t *buf) { - - uint16_t typereq = (bmRequestType << 8) | bRequest; - - switch (typereq) { - case ClearHubFeature: - switch (wvalue) { - case USBH_HUB_FEAT_C_HUB_LOCAL_POWER: - case USBH_HUB_FEAT_C_HUB_OVER_CURRENT: - break; - default: - osalDbgAssert(0, "invalid wvalue"); - } - break; - - case ClearPortFeature: - chDbgAssert(windex == 1, "invalid windex"); - - osalSysLock(); - switch (wvalue) { - case USBH_PORT_FEAT_ENABLE: - case USBH_PORT_FEAT_SUSPEND: - case USBH_PORT_FEAT_POWER: - chDbgAssert(0, "unimplemented"); /* TODO */ - break; - - case USBH_PORT_FEAT_INDICATOR: - chDbgAssert(0, "unsupported"); - break; - - case USBH_PORT_FEAT_C_CONNECTION: - usbh->rootport.lld_c_status &= ~USBH_PORTSTATUS_C_CONNECTION; - break; - - case USBH_PORT_FEAT_C_RESET: - usbh->rootport.lld_c_status &= ~USBH_PORTSTATUS_C_RESET; - break; - - case USBH_PORT_FEAT_C_ENABLE: - usbh->rootport.lld_c_status &= ~USBH_PORTSTATUS_C_ENABLE; - break; - - case USBH_PORT_FEAT_C_SUSPEND: - usbh->rootport.lld_c_status &= ~USBH_PORTSTATUS_C_SUSPEND; - break; - - case USBH_PORT_FEAT_C_OVERCURRENT: - usbh->rootport.lld_c_status &= USBH_PORTSTATUS_C_OVERCURRENT; - break; - - default: - osalDbgAssert(0, "invalid wvalue"); - break; - } - osalOsRescheduleS(); - osalSysUnlock(); - break; - - case GetHubDescriptor: - /*dev_dbg(hsotg->dev, "GetHubDescriptor\n"); - hub_desc = (struct usb_hub_descriptor *)buf; - hub_desc->bDescLength = 9; - hub_desc->bDescriptorType = USB_DT_HUB; - hub_desc->bNbrPorts = 1; - hub_desc->wHubCharacteristics = - cpu_to_le16(HUB_CHAR_COMMON_LPSM | - HUB_CHAR_INDV_PORT_OCPM); - hub_desc->bPwrOn2PwrGood = 1; - hub_desc->bHubContrCurrent = 0; - hub_desc->u.hs.DeviceRemovable[0] = 0; - hub_desc->u.hs.DeviceRemovable[1] = 0xff;*/ - break; - - case GetHubStatus: - osalDbgCheck(wlength >= 4); - *(uint32_t *)buf = 0; - break; - - case GetPortStatus: - chDbgAssert(windex == 1, "invalid windex"); - osalDbgCheck(wlength >= 4); - osalSysLock(); - *(uint32_t *)buf = usbh->rootport.lld_status | (usbh->rootport.lld_c_status << 16); - osalOsRescheduleS(); - osalSysUnlock(); - break; - - case SetHubFeature: - chDbgAssert(0, "unsupported"); - break; - - case SetPortFeature: - chDbgAssert(windex == 1, "invalid windex"); - - switch (wvalue) { - case USBH_PORT_FEAT_TEST: - case USBH_PORT_FEAT_SUSPEND: - case USBH_PORT_FEAT_POWER: - chDbgAssert(0, "unimplemented"); /* TODO */ - break; - - case USBH_PORT_FEAT_RESET: { - osalSysLock(); - stm32_otg_t *const otg = usbh->otg; - uint32_t hprt; - otg->PCGCCTL = 0; - hprt = otg->HPRT; - /* note: writing PENA = 1 actually disables the port */ - hprt &= ~(HPRT_PSUSP | HPRT_PENA | HPRT_PCDET | HPRT_PENCHNG | HPRT_POCCHNG ); - otg->HPRT = hprt | HPRT_PRST; - osalThreadSleepS(MS2ST(60)); - otg->HPRT = hprt; - usbh->rootport.lld_c_status |= USBH_PORTSTATUS_C_RESET; - osalOsRescheduleS(); - osalSysUnlock(); - } break; - - case USBH_PORT_FEAT_INDICATOR: - chDbgAssert(0, "unsupported"); - break; - - default: - osalDbgAssert(0, "invalid wvalue"); - break; - } - break; - - default: - osalDbgAssert(0, "invalid typereq"); - break; - } - - return USBH_URBSTATUS_OK; -} - -uint8_t usbh_lld_roothub_get_statuschange_bitmap(USBHDriver *usbh) { - osalSysLock(); - if (usbh->rootport.lld_c_status) { - osalOsRescheduleS(); - osalSysUnlock(); - return 1 << 1; - } - osalOsRescheduleS(); - osalSysUnlock(); - return 0; -} - - -#endif diff --git a/os/hal/ports/STM32/LLD/USBHv1/usbh_lld.h b/os/hal/ports/STM32/LLD/USBHv1/usbh_lld.h deleted file mode 100644 index e8da2ac..0000000 --- a/os/hal/ports/STM32/LLD/USBHv1/usbh_lld.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio - Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail) - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -#ifndef USBH_LLD_H_ -#define USBH_LLD_H_ - -#include "hal.h" - -#if HAL_USE_USBH - -#include "osal.h" -#include "stm32_otg.h" - -/* TODO: - * - * - Implement ISO/INT OUT and test - * - Consider DMA mode for OTG_HS, consider external PHY for HS. - * - Implement a data pump thread, so we don't have to copy data from the ISR - * This might be a bad idea for small endpoint packet sizes (the context switch - * could be longer than the copy) - */ - -typedef enum { - USBH_LLD_CTRLPHASE_SETUP, - USBH_LLD_CTRLPHASE_DATA, - USBH_LLD_CTRLPHASE_STATUS -} usbh_lld_ctrlphase_t; - -typedef enum { - USBH_LLD_HALTREASON_NONE, - USBH_LLD_HALTREASON_XFRC, - USBH_LLD_HALTREASON_NAK, - USBH_LLD_HALTREASON_STALL, - USBH_LLD_HALTREASON_ERROR, - USBH_LLD_HALTREASON_ABORT -} usbh_lld_halt_reason_t; - - -typedef struct stm32_hc_management { - struct list_head node; - - stm32_otg_host_chn_t *hc; - volatile uint32_t *fifo; - usbh_ep_t *ep; - uint16_t haintmsk; - usbh_lld_halt_reason_t halt_reason; -} stm32_hc_management_t; - - -#define _usbhdriver_ll_data \ - stm32_otg_t *otg; \ - /* channels */ \ - uint8_t channels_number; \ - stm32_hc_management_t channels[STM32_OTG2_CHANNELS_NUMBER]; \ - struct list_head ch_free[2]; \ - /* Enpoints being processed */ \ - struct list_head ep_active_lists[4]; \ - /* Pending endpoints */ \ - struct list_head ep_pending_lists[4]; - - -#define _usbh_ep_ll_data \ - struct list_head *active_list; /* shortcut to ep list */ \ - struct list_head *pending_list; /* shortcut to ep list */ \ - struct list_head urb_list; /* list of URBs queued in this EP */ \ - struct list_head node; /* this EP */ \ - uint32_t hcintmsk; \ - uint32_t hcchar; \ - uint32_t dt_mask; /* data-toggle mask */ \ - /* current transfer */ \ - struct { \ - stm32_hc_management_t *hcm; /* assigned channel */ \ - uint32_t len; /* this transfer's total length */ \ - uint8_t *buf; /* this transfer's buffer */ \ - uint32_t partial; /* this transfer's partial length */\ - uint16_t packets; /* packets allocated */ \ - union { \ - uint32_t frame_counter; /* frame counter (for INT) */ \ - usbh_lld_ctrlphase_t ctrl_phase; /* control phase (for CTRL) */ \ - } u; \ - uint8_t error_count; /* error count */ \ - } xfer; - - - - - -#define _usbh_port_ll_data \ - uint16_t lld_c_status; \ - uint16_t lld_status; - -#define _usbh_device_ll_data - -#define _usbh_hub_ll_data - -#define _usbh_urb_ll_data \ - struct list_head node; \ - bool queued; - - -#define usbh_lld_urb_object_init(urb) \ - do { \ - osalDbgAssert(((uint32_t)urb->buff & 3) == 0, \ - "use USBH_DEFINE_BUFFER() to declare the IO buffers"); \ - urb->queued = FALSE; \ - } while (0) - - -#define usbh_lld_urb_object_reset(urb) \ - do { \ - osalDbgAssert(urb->queued == FALSE, "wrong state"); \ - osalDbgAssert(((uint32_t)urb->buff & 3) == 0, \ - "use USBH_DEFINE_BUFFER() to declare the IO buffers"); \ - } while (0) - - - -void usbh_lld_init(void); -void usbh_lld_start(USBHDriver *usbh); -void usbh_lld_ep_object_init(usbh_ep_t *ep); -void usbh_lld_ep_open(usbh_ep_t *ep); -void usbh_lld_ep_close(usbh_ep_t *ep); -void usbh_lld_urb_submit(usbh_urb_t *urb); -bool usbh_lld_urb_abort(usbh_urb_t *urb, usbh_urbstatus_t status); -usbh_urbstatus_t usbh_lld_root_hub_request(USBHDriver *usbh, uint8_t bmRequestType, uint8_t bRequest, - uint16_t wvalue, uint16_t windex, uint16_t wlength, uint8_t *buf); -uint8_t usbh_lld_roothub_get_statuschange_bitmap(USBHDriver *usbh); - -#define usbh_lld_epreset(ep) do {(ep)->dt_mask = HCTSIZ_DPID_DATA0;} while (0); - -#ifdef __IAR_SYSTEMS_ICC__ -#define USBH_LLD_DEFINE_BUFFER(type, name) type name -#else -#define USBH_LLD_DEFINE_BUFFER(type, name) type name __attribute__((aligned(4))) -#endif - -#endif - -#endif /* USBH_LLD_H_ */ diff --git a/os/hal/ports/STM32/STM32F0xx/platform.mk b/os/hal/ports/STM32/STM32F0xx/platform.mk index 1dff83a..c796984 100644 --- a/os/hal/ports/STM32/STM32F0xx/platform.mk +++ b/os/hal/ports/STM32/STM32F0xx/platform.mk @@ -1,7 +1,7 @@ include ${CHIBIOS}/os/hal/ports/STM32/STM32F0xx/platform.mk -PLATFORMSRC += ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/CRCv1/crc_lld.c \ - ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/TIMv1/timcap_lld.c \ +PLATFORMSRC += ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/CRCv1/hal_crc_lld.c \ + ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/TIMv1/hal_timcap_lld.c \ PLATFORMINC += ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/CRCv1 \ ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/TIMv1 \ diff --git a/os/hal/ports/STM32/STM32F3xx/platform.mk b/os/hal/ports/STM32/STM32F3xx/platform.mk index e98de86..baa7578 100644 --- a/os/hal/ports/STM32/STM32F3xx/platform.mk +++ b/os/hal/ports/STM32/STM32F3xx/platform.mk @@ -1,8 +1,8 @@ include ${CHIBIOS}/os/hal/ports/STM32/STM32F3xx/platform.mk -PLATFORMSRC += ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/CRCv1/crc_lld.c \ - ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/TIMv1/eicu_lld.c \ - ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/TIMv1/timcap_lld.c +PLATFORMSRC += ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/CRCv1/hal_crc_lld.c \ + ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/TIMv1/hal_eicu_lld.c \ + ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/TIMv1/hal_timcap_lld.c PLATFORMINC += ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/CRCv1 \ ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/TIMv1 \ diff --git a/os/hal/ports/STM32/STM32F4xx/platform.mk b/os/hal/ports/STM32/STM32F4xx/platform.mk index 5ffc9dd..b78df83 100644 --- a/os/hal/ports/STM32/STM32F4xx/platform.mk +++ b/os/hal/ports/STM32/STM32F4xx/platform.mk @@ -1,15 +1,15 @@ include ${CHIBIOS}/os/hal/ports/STM32/STM32F4xx/platform.mk -PLATFORMSRC += ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/DMA2Dv1/stm32_dma2d.c \ - ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/FSMCv1/fsmc.c \ - ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/FSMCv1/nand_lld.c \ - ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/FSMCv1/fsmc_sram.c \ - ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/LTDCv1/stm32_ltdc.c \ - ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/TIMv1/eicu_lld.c \ - ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/TIMv1/timcap_lld.c \ - ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/USBHv1/usbh_lld.c \ - ${CHIBIOS_CONTRIB}/os/hal/src/fsmc_sdram.c \ - ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/CRCv1/crc_lld.c +PLATFORMSRC += ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/DMA2Dv1/hal_stm32_dma2d.c \ + ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc.c \ + ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/FSMCv1/hal_nand_lld.c \ + ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sram.c \ + ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/LTDCv1/hal_stm32_ltdc.c \ + ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/TIMv1/hal_eicu_lld.c \ + ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/TIMv1/hal_timcap_lld.c \ + ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/USBHv1/hal_usbh_lld.c \ + ${CHIBIOS_CONTRIB}/os/hal/src/hal_fsmc_sdram.c \ + ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/CRCv1/hal_crc_lld.c PLATFORMINC += ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/DMA2Dv1 \ ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/FSMCv1 \ -- cgit v1.2.3 From fd20f0fa17bfdf81dc28e7d30f13ca80264b7c78 Mon Sep 17 00:00:00 2001 From: Andrew Wygle Date: Fri, 8 Apr 2016 01:43:46 -0700 Subject: Initial MSP430X Port. This port includes hal, pal, serial, and st drivers. It supports both large and small model code and data for MSP430X-class CPUs. It has only been tested on the EXP430FR5969 LaunchPad board. --- os/hal/ports/MSP430X/hal_lld.c | 87 +++++ os/hal/ports/MSP430X/hal_lld.h | 245 +++++++++++++ os/hal/ports/MSP430X/hal_pal_lld.c | 215 +++++++++++ os/hal/ports/MSP430X/hal_pal_lld.h | 390 ++++++++++++++++++++ os/hal/ports/MSP430X/hal_serial_lld.c | 657 ++++++++++++++++++++++++++++++++++ os/hal/ports/MSP430X/hal_serial_lld.h | 320 +++++++++++++++++ os/hal/ports/MSP430X/hal_st_lld.c | 206 +++++++++++ os/hal/ports/MSP430X/hal_st_lld.h | 216 +++++++++++ os/hal/ports/MSP430X/platform.mk | 8 + 9 files changed, 2344 insertions(+) create mode 100644 os/hal/ports/MSP430X/hal_lld.c create mode 100644 os/hal/ports/MSP430X/hal_lld.h create mode 100644 os/hal/ports/MSP430X/hal_pal_lld.c create mode 100644 os/hal/ports/MSP430X/hal_pal_lld.h create mode 100644 os/hal/ports/MSP430X/hal_serial_lld.c create mode 100644 os/hal/ports/MSP430X/hal_serial_lld.h create mode 100644 os/hal/ports/MSP430X/hal_st_lld.c create mode 100644 os/hal/ports/MSP430X/hal_st_lld.h create mode 100644 os/hal/ports/MSP430X/platform.mk (limited to 'os/hal/ports') diff --git a/os/hal/ports/MSP430X/hal_lld.c b/os/hal/ports/MSP430X/hal_lld.c new file mode 100644 index 0000000..872fe97 --- /dev/null +++ b/os/hal/ports/MSP430X/hal_lld.c @@ -0,0 +1,87 @@ +/* + ChibiOS - Copyright (C) 2016 Andrew Wygle aka awygle + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file MSP430X/hal_lld.c + * @brief MSP430X HAL subsystem low level driver source. + * + * @addtogroup HAL + * @{ + */ + +#include "hal.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level HAL driver initialization. + * + * @notapi + */ +void hal_lld_init(void) { + /* Disable watchdog */ + /* TODO Real watchdog support */ + WDTCTL = WDTPW | WDTHOLD; + /* Init clock system */ + CSCTL0 = CSKEY; /* unlock clock system */ + CSCTL1 = MSP430X_DCOSEL; + CSCTL2 = (MSP430X_ACLK_SRC << 8) | (MSP430X_SMCLK_SRC << 4) | (MSP430X_MCLK_SRC); + CSCTL3 = (DIVIDER(MSP430X_ACLK_DIV) << 8) | (DIVIDER(MSP430X_SMCLK_DIV) << 4) | (DIVIDER(MSP430X_MCLK_DIV)); + CSCTL4 = (MSP430X_HFXTCLK_DRIVE << 14) | (MSP430X_HFXTCLK_BYPASS << 12) | (MSP430X_HFFREQ << 10) | HFXTOFF | \ + (MSP430X_LFXTCLK_DRIVE << 6) | (MSP430X_LFXTCLK_BYPASS << 4) | VLOOFF | LFXTOFF; + CSCTL6 = (MODCLKREQEN) | (SMCLKREQEN) | (MCLKREQEN) | (ACLKREQEN); + #if defined(MSP430X_USE_HFXT) && defined(MSP430X_USE_LFXT) + do { + CSCTL5 &= ~(HFXTOFFG | LFXTOFFG); + SFRIFG1 &= ~OFIFG; + } while (SFRIFG1 & OFIFG); + #elif defined(MSP430X_USE_HFXT) + do { + CSCTL5 &= ~(HFXTOFFG); + SFRIFG1 &= ~OFIFG; + } while (SFRIFG1 & OFIFG); + #elif defined(MSP430X_USE_LFXT) + do { + CSCTL5 &= ~(LFXTOFFG); + SFRIFG1 &= ~OFIFG; + } while (SFRIFG1 & OFIFG); + #endif + CSCTL0_H = 0xFF; /* Lock clock system */ +} + +/** @} */ diff --git a/os/hal/ports/MSP430X/hal_lld.h b/os/hal/ports/MSP430X/hal_lld.h new file mode 100644 index 0000000..9549453 --- /dev/null +++ b/os/hal/ports/MSP430X/hal_lld.h @@ -0,0 +1,245 @@ +/* + ChibiOS - Copyright (C) 2016 Andrew Wygle aka awygle + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file MSP430X/hal_lld.h + * @brief MSP430X HAL subsystem low level driver header. + * + * @addtogroup HAL + * @{ + */ + +#ifndef _HAL_LLD_H_ +#define _HAL_LLD_H_ + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @brief Defines the support for realtime counters in the HAL. + */ +/* someday*/ +#define HAL_IMPLEMENTS_COUNTERS FALSE + +/** + * @name Platform identification macros + * @{ + */ +#define PLATFORM_NAME "MSP430X" +/** @} */ + +#define MSP430X_LFXTCLK 0 +#define MSP430X_VLOCLK 1 +#define MSP430X_LFMODCLK 2 +#define MSP430X_DCOCLK 3 +#define MSP430X_MODCLK 4 +#define MSP430X_HFXTCLK 5 + +#if !defined(MSP430X_LFXTCLK_FREQ) + #define MSP430X_LFXTCLK_FREQ 32768 + #warning "LFXTCLK freqency not defined - assuming 32768 Hz" +#endif +#define MSP430X_VLOCLK_FREQ 10000 +#define MSP430X_MODCLK_FREQ 5000000 +#define MSP430X_LFMODCLK_FREQ (MSP430X_MODCLK_FREQ/128) +#if !defined(MSP430X_DCOCLK_FREQ) + #define MSP430X_DCOCLK_FREQ 8000000 + #warning "DCOCLK frequency not defined - assuming 8 MHz" +#endif +#if !defined(MSP430X_HFXTCLK_FREQ) + #define MSP430X_HFXTCLK_FREQ 0 + #warning "HFXTCLK frequency not defined - assuming disabled" +#endif + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name MSP430X configuration options + * @{ + */ + +/* Clock dividers */ +#if !defined(MSP430X_ACLK_DIV) + #define MSP430X_ACLK_DIV 1 +#endif +#if !defined(MSP430X_MCLK_DIV) + #define MSP430X_MCLK_DIV 8 +#endif +#if !defined(MSP430X_SMCLK_DIV) + #define MSP430X_SMCLK_DIV 8 +#endif + +/* Clock sources */ +#if !defined(MSP430X_ACLK_SRC) + #define MSP430X_ACLK_SRC MSP430X_LFXTCLK +#endif +#if !defined(MSP430X_MCLK_SRC) + #define MSP430X_MCLK_SRC MSP430X_DCOCLK +#endif +#if !defined(MSP430X_SMCLK_SRC) + #define MSP430X_SMCLK_SRC MSP430X_DCOCLK +#endif + +/* HFXT and LFXT settings */ +#if !defined(MSP430X_LFXTCLK_BYPASS) + #define MSP430X_LFXTCLK_BYPASS 0 +#endif +#if !defined(MSP430X_LFXTCLK_DRIVE) + #define MSP430X_LFXTCLK_DRIVE 3 +#endif +#if !defined(MSP430X_HFXTCLK_BYPASS) + #define MSP430X_HFXTCLK_BYPASS 0 +#endif +#if !defined(MSP430X_HFXTCLK_DRIVE) + #define MSP430X_HFXTCLK_DRIVE 3 +#endif + +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* + * Configuration-related checks. + */ +#if (MSP430X_ACLK_SRC == MSP430X_LFXTCLK) || (MSP430X_MCLK_SRC == MSP430X_LFXTCLK) || (MSP430X_SMCLK_SRC == MSP430X_LFXTCLK) + #define MSP430X_USE_LFXTCLK +#endif +#if (MSP430X_MCLK_SRC == MSP430X_HFXTCLK) || (MSP430X_SMCLK_SRC == MSP430X_HFXTCLK) + #define MSP430X_USE_HFXTCLK +#endif + +#if defined(MSP430X_USE_HFXTCLK) && MSP430X_HFXTCLK_FREQ == 0 + #error "HFXT requested as clock source but disabled" +#endif + +/* Clock speeds */ +#if (MSP430X_ACLK_SRC == MSP430X_LFXTCLK) + #define MSP430X_ACLK_FREQ (MSP430X_LFXTCLK_FREQ / MSP430X_ACLK_DIV) +#elif (MSP430X_ACLK_SRC == MSP430X_VLOCLK) + #define MSP430X_ACLK_FREQ (MSP430X_VLOCLK_FREQ / MSP430X_ACLK_DIV) +#elif (MSP430X_ACLK_SRC == MSP430X_LFMODCLK) + #define MSP430X_ACLK_FREQ (MSP430X_LFMODCLK_FREQ / MSP430X_ACLK_DIV) +#else + #error "ACLK source invalid!" +#endif +#if (MSP430X_MCLK_SRC == MSP430X_LFXTCLK) + #define MSP430X_MCLK_FREQ (MSP430X_LFXTCLK_FREQ / MSP430X_MCLK_DIV) +#elif (MSP430X_MCLK_SRC == MSP430X_VLOCLK) + #define MSP430X_MCLK_FREQ (MSP430X_VLOCLK_FREQ / MSP430X_MCLK_DIV) +#elif (MSP430X_MCLK_SRC == MSP430X_LFMODCLK) + #define MSP430X_MCLK_FREQ (MSP430X_LFMODCLK_FREQ / MSP430X_MCLK_DIV) +#elif (MSP430X_MCLK_SRC == MSP430X_DCOCLK) + #define MSP430X_MCLK_FREQ (MSP430X_DCOCLK_FREQ / MSP430X_MCLK_DIV) +#elif (MSP430X_MCLK_SRC == MSP430X_MODCLK) + #define MSP430X_MCLK_FREQ (MSP430X_MODCLK_FREQ / MSP430X_MCLK_DIV) +#elif (MSP430X_MCLK_SRC == MSP430X_HFXTCLK) + #define MSP430X_MCLK_FREQ (MSP430X_HFXTCLK_FREQ / MSP430X_MCLK_DIV) +#else + #error "MCLK source invalid!" +#endif +#if (MSP430X_SMCLK_SRC == MSP430X_LFXTCLK) + #define MSP430X_SMCLK_FREQ (MSP430X_LFXTCLK_FREQ / MSP430X_SMCLK_DIV) +#elif (MSP430X_SMCLK_SRC == MSP430X_VLOCLK) + #define MSP430X_SMCLK_FREQ (MSP430X_VLOCLK_FREQ / MSP430X_SMCLK_DIV) +#elif (MSP430X_SMCLK_SRC == MSP430X_LFMODCLK) + #define MSP430X_SMCLK_FREQ (MSP430X_LFMODCLK_FREQ / MSP430X_SMCLK_DIV) +#elif (MSP430X_SMCLK_SRC == MSP430X_DCOCLK) + #define MSP430X_SMCLK_FREQ (MSP430X_DCOCLK_FREQ / MSP430X_SMCLK_DIV) +#elif (MSP430X_SMCLK_SRC == MSP430X_MODCLK) + #define MSP430X_SMCLK_FREQ (MSP430X_MODCLK_FREQ / MSP430X_SMCLK_DIV) +#elif (MSP430X_SMCLK_SRC == MSP430X_HFXTCLK) + #define MSP430X_SMCLK_FREQ (MSP430X_HFXTCLK_FREQ / MSP430X_SMCLK_DIV) +#else + #error "SMCLK source invalid!" +#endif + +#if !defined(MSP430X_MCUCONF) +#error "Using an incorrect mcuconf.h file, MSP430X_MCUCONF not defined" +#endif + +/* HFXT-specific settings */ +#if MSP430X_HFXTCLK_FREQ <= 4000000 + #define MSP430X_HFFREQ HFFREQ_0 +#elif MSP430X_HFXTCLK_FREQ <= 8000000 + #define MSP430X_HFFREQ HFFREQ_1 +#elif MSP430X_HFXTCLK_FREQ <= 16000000 + #define MSP430X_HFFREQ HFFREQ_2 +#elif MSP430X_HFXTCLK_FREQ <= 24000000 + #define MSP430X_HFFREQ HFFREQ_3 +#else + #error "HFXT frequency too high - must be <= 24000000" +#endif + +/* DCO-specific settings */ +#if MSP430X_DCOCLK_FREQ == 1000000 + #define MSP430X_DCOSEL DCOFSEL_0 +#elif MSP430X_DCOCLK_FREQ == 2670000 + #define MSP430X_DCOSEL DCOFSEL_1 +#elif MSP430X_DCOCLK_FREQ == 3330000 + #define MSP430X_DCOSEL DCOFSEL_2 +#elif MSP430X_DCOCLK_FREQ == 4000000 + #define MSP430X_DCOSEL DCOFSEL_3 +#elif MSP430X_DCOCLK_FREQ == 5330000 + #define MSP430X_DCOSEL DCOFSEL_4 +#elif MSP430X_DCOCLK_FREQ == 6670000 + #define MSP430X_DCOSEL DCOFSEL_5 +#elif MSP430X_DCOCLK_FREQ == 8000000 + #define MSP430X_DCOSEL DCOFSEL_6 +#elif MSP430X_DCOCLK_FREQ == 16000000 + #define MSP430X_DCOSEL (DCORSEL | DCOFSEL_4) +#elif MSP430X_DCOCLK_FREQ == 21000000 + #define MSP430X_DCOSEL (DCORSEL | DCOFSEL_5) +#elif MSP430X_DCOCLK_FREQ == 24000000 + #define MSP430X_DCOSEL (DCORSEL | DCOFSEL_6) +#else + #error "DCO frequency invalid" +#endif + +#if MSP430X_LFXTCLK_FREQ > 50000 + #error "LFXT frequency too high - must be <= 5000" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +#define DIVIDER(x) DIV_HELPER(x) +#define DIV_HELPER(x) DIVM__ ## x + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void hal_lld_init(void); +#ifdef __cplusplus +} +#endif + +#endif /* _HAL_LLD_H_ */ + +/** @} */ diff --git a/os/hal/ports/MSP430X/hal_pal_lld.c b/os/hal/ports/MSP430X/hal_pal_lld.c new file mode 100644 index 0000000..4cfff3b --- /dev/null +++ b/os/hal/ports/MSP430X/hal_pal_lld.c @@ -0,0 +1,215 @@ +/* + ChibiOS - Copyright (C) 2016 Andrew Wygle aka awygle + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file MSP430X/hal_pal_lld.c + * @brief MSP430X PAL subsystem low level driver source. + * + * @addtogroup PAL + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_PAL == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief MSP430X I/O ports configuration. + * @details GPIO registers initialization + * + * @param[in] config the MSP430X ports configuration + * + * @notapi + */ +void _pal_lld_init(const PALConfig *config) { + +#if defined(PA_BASE) || defined(__DOXYGEN__) + PAOUT = config->porta.out; + PADIR = config->porta.dir; + PAREN = config->porta.ren; + PASEL0 = config->porta.sel0; + PASEL1 = config->porta.sel1; + PAIES = config->porta.ies; + PAIE = config->porta.ie; +#endif +#if defined(PB_BASE) || defined(__DOXYGEN__) + PBOUT = config->portb.out; + PBDIR = config->portb.dir; + PBREN = config->portb.ren; + PBSEL0 = config->portb.sel0; + PBSEL1 = config->portb.sel1; + PBIES = config->portb.ies; + PBIE = config->portb.ie; +#endif +#if defined(PC_BASE) || defined(__DOXYGEN__) + PCOUT = config->portc.out; + PCDIR = config->portc.dir; + PCREN = config->portc.ren; + PCSEL0 = config->portc.sel0; + PCSEL1 = config->portc.sel1; + PCIES = config->portc.ies; + PCIE = config->portc.ie; +#endif +#if defined(PD_BASE) || defined(__DOXYGEN__) + PDOUT = config->portd.out; + PDDIR = config->portd.dir; + PDREN = config->portd.ren; + PDSEL0 = config->portd.sel0; + PDSEL1 = config->portd.sel1; + PDIES = config->portd.ies; + PDIE = config->portd.ie; +#endif +#if defined(PE_BASE) || defined(__DOXYGEN__) + PEOUT = config->porte.out; + PEDIR = config->porte.dir; + PEREN = config->porte.ren; + PESEL0 = config->porte.sel0; + PESEL1 = config->porte.sel1; + PEIES = config->porte.ies; + PEIE = config->porte.ie; +#endif +#if defined(PF_BASE) || defined(__DOXYGEN__) + PFOUT = config->portf.out; + PFDIR = config->portf.dir; + PFREN = config->portf.ren; + PFSEL0 = config->portf.sel0; + PFSEL1 = config->portf.sel1; + PFIES = config->portf.ies; + PFIE = config->portf.ie; +#endif + PJOUT = config->portj.out; + PJDIR = config->portj.dir; + PJREN = config->portj.ren; + PJSEL0 = config->portj.sel0; + PJSEL1 = config->portj.sel1; + + PM5CTL0 &= ~LOCKLPM5; +} + +/** + * @brief Pads mode setup. + * @details This function programs a pads group belonging to the same port + * with the specified mode. + * @note @p PAL_MODE_UNCONNECTED is implemented as input with pullup. + * + * @param[in] port the port identifier + * @param[in] mask the group mask + * @param[in] mode the mode + * + * @notapi + */ +void _pal_lld_setgroupmode(ioportid_t port, + ioportmask_t mask, + iomode_t mode) { + + switch (mode) { + case PAL_MODE_RESET: + case PAL_MODE_INPUT: + port->dir &= ~mask; + port->ren &= ~mask; + if ((port->sel0 & mask) && (port->sel1 & mask)) + port->selc = mask; + else { + port->sel0 &= ~mask; + port->sel1 &= ~mask; + } + break; + case PAL_MODE_UNCONNECTED: + case PAL_MODE_INPUT_PULLUP: + port->dir &= ~mask; + port->ren |= mask; + port->out |= mask; + if ((port->sel0 & mask) && (port->sel1 & mask)) + port->selc = mask; + else { + port->sel0 &= ~mask; + port->sel1 &= ~mask; + } + break; + case PAL_MODE_INPUT_PULLDOWN: + port->dir &= ~mask; + port->ren |= mask; + port->out &= ~mask; + if ((port->sel0 & mask) && (port->sel1 & mask)) + port->selc = mask; + else { + port->sel0 &= ~mask; + port->sel1 &= ~mask; + } + break; + case PAL_MODE_OUTPUT_PUSHPULL: + port->dir |= mask; + if ((port->sel0 & mask) && (port->sel1 & mask)) + port->selc = mask; + else { + port->sel0 &= ~mask; + port->sel1 &= ~mask; + } + break; + case PAL_MSP430X_ALTERNATE_1: + if (!(port->sel0 & mask) && (port->sel1 & mask)) + port->selc = mask; + else { + port->sel0 |= mask; + port->sel1 &= ~mask; + } + break; + case PAL_MSP430X_ALTERNATE_2: + if ((port->sel0 & mask) && !(port->sel1 & mask)) + port->selc = mask; + else { + port->sel0 &= ~mask; + port->sel1 |= mask; + } + break; + case PAL_MSP430X_ALTERNATE_3: + if (!(port->sel0 & mask) && !(port->sel1 & mask)) + port->selc = mask; + else { + port->sel0 |= mask; + port->sel1 |= mask; + } + break; + } +} + +#endif /* HAL_USE_PAL == TRUE */ + +/** @} */ diff --git a/os/hal/ports/MSP430X/hal_pal_lld.h b/os/hal/ports/MSP430X/hal_pal_lld.h new file mode 100644 index 0000000..8789ed1 --- /dev/null +++ b/os/hal/ports/MSP430X/hal_pal_lld.h @@ -0,0 +1,390 @@ +/* + ChibiOS - Copyright (C) 2016 Andrew Wygle aka awygle + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file MSP430X/hal_pal_lld.h + * @brief MSP430X PAL subsystem low level driver header. + * + * @addtogroup PAL + * @{ + */ + +#ifndef HAL_PAL_LLD_H +#define HAL_PAL_LLD_H + +#if (HAL_USE_PAL == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Unsupported modes and specific modes */ +/*===========================================================================*/ + +#undef PAL_MODE_INPUT_ANALOG /* configure this through the ALTERNATE macros */ +#undef PAL_MODE_OUTPUT_OPENDRAIN + +/** + * @name MSP430X-specific I/O mode flags + * @{ + */ + +/** + * @brief Alternate mode 1 + */ +#define PAL_MSP430X_ALTERNATE_1 8 + +/** + * @brief Alternate mode 2 + */ +#define PAL_MSP430X_ALTERNATE_2 9 + +/** + * @brief Alternate mode 3 + */ +#define PAL_MSP430X_ALTERNATE_3 10 + +#define ALTERNATE_HELP(n) (PAL_MSP430X_ALTERNATE_ ## n) +/** + * @brief Alternate function. + * + * @param[in] n alternate function selector - 1 through 3 + */ +#define PAL_MODE_ALTERNATE(n) (ALTERNATE_HELP(n)) + +/** @} */ + +/*===========================================================================*/ +/* I/O Ports Types and constants. */ +/*===========================================================================*/ + +/** + * @name Port related definitions + * @{ + */ +/** + * @brief Width, in bits, of an I/O port. + */ +#define PAL_IOPORTS_WIDTH 16U + +/** + * @brief Whole port mask. + * @details This macro specifies all the valid bits into a port. + */ +#define PAL_WHOLE_PORT ((ioportmask_t)0xFFFFU) + +/** @} */ + + +/** + * @name Line handling macros + * @{ + */ +/** + * @brief Forms a line identifier. + * @details A port/pad pair are encoded into an @p ioline_t type. The encoding + * of this type is platform-dependent. + * @note In this driver the pad number is encoded in the upper 4 bits of + * the GPIO address which are guaranteed to be zero. + */ +#define PAL_LINE(port, pad) \ + ((ioline_t)((uint16_t)(port)) | (((uint16_t)(pad)) << 12)) + +/** + * @brief Decodes a port identifier from a line identifier. + */ +#define PAL_PORT(line) \ + ((msp430x_gpio_registers_t *)(((uint16_t)(line)) & 0x0FFFU)) + +/** + * @brief Decodes a pad identifier from a line identifier. + */ +#define PAL_PAD(line) \ + ((uint16_t)((uint16_t)(line) >> 12)) + +/** + * @brief Value identifying an invalid line. + */ +#define PAL_NOLINE 0U +/** @} */ + +/** + * @brief MSP430X register initialization + */ +typedef struct { + /** Initial value for OUT register.*/ + uint16_t out; + /** Initial value for DIR register.*/ + uint16_t dir; + /** Initial value for REN register.*/ + uint16_t ren; + /** Initial value for SEL0 register.*/ + uint16_t sel0; + /** Initial value for SEL1 register.*/ + uint16_t sel1; + /** Initial value for IES register.*/ + uint16_t ies; + /** Initial value for IE register.*/ + uint16_t ie; +} msp430x_gpio_setup_t; + +/** + * @brief MSP430X registers block + * @note Some ports do not support all of these fields. + */ +typedef struct { + volatile uint16_t in; + volatile uint16_t out; + volatile uint16_t dir; + volatile uint16_t _padding; + volatile uint16_t ren; + volatile uint16_t sel0; + volatile uint16_t sel1; + volatile uint16_t _padding1; + volatile uint16_t _padding2; + volatile uint16_t _padding3; + volatile uint16_t _padding4; + volatile uint16_t selc; + volatile uint16_t ies; + volatile uint16_t ie; + volatile uint16_t ifg; +} msp430x_gpio_registers_t; + +/** + * @brief MSP430X I/O ports static initializer. + * @details An instance of this structure must be passed to @p palInit() at + * system startup time in order to initialized the digital I/O + * subsystem. This represents only the initial setup, specific pads + * or whole ports can be reprogrammed at later time. + */ +typedef struct { +#if defined(PA_BASE) || defined(__DOXYGEN__) + msp430x_gpio_setup_t porta; +#endif +#if defined(PB_BASE) || defined(__DOXYGEN__) + msp430x_gpio_setup_t portb; +#endif +#if defined(PC_BASE) || defined(__DOXYGEN__) + msp430x_gpio_setup_t portc; +#endif +#if defined(PD_BASE) || defined(__DOXYGEN__) + msp430x_gpio_setup_t portd; +#endif +#if defined(PE_BASE) || defined(__DOXYGEN__) + msp430x_gpio_setup_t porte; +#endif +#if defined(PF_BASE) || defined(__DOXYGEN__) + msp430x_gpio_setup_t portf; +#endif + msp430x_gpio_setup_t portj; +} PALConfig; + +/** + * @brief Digital I/O port sized unsigned type. + */ +typedef uint16_t ioportmask_t; + +/** + * @brief Digital I/O modes. + */ +typedef uint16_t iomode_t; + +/** + * @brief Type of an I/O line. + */ +typedef uint16_t ioline_t; + +/** + * @brief Port Identifier. + * @details This type can be a scalar or some kind of pointer, do not make + * any assumption about it, use the provided macros when populating + * variables of this type. + */ +typedef msp430x_gpio_registers_t * ioportid_t; + +/*===========================================================================*/ +/* I/O Ports Identifiers. */ +/*===========================================================================*/ + +/** + * @brief GPIO port A identifier. + */ +#if defined(PA_BASE) || defined(__DOXYGEN__) +#define IOPORT1 ((volatile msp430x_gpio_registers_t *)PA_BASE) +#endif + +/** + * @brief GPIO port B identifier. + */ +#if defined(PB_BASE) || defined(__DOXYGEN__) +#define IOPORT2 ((volatile msp430x_gpio_registers_t *)PB_BASE) +#endif + +/** + * @brief GPIO port C identifier. + */ +#if defined(PC_BASE) || defined(__DOXYGEN__) +#define IOPORT3 ((volatile msp430x_gpio_registers_t *)PC_BASE) +#endif + +/** + * @brief GPIO port D identifier. + */ +#if defined(PD_BASE) || defined(__DOXYGEN__) +#define IOPORT4 ((volatile msp430x_gpio_registers_t *)PD_BASE) +#endif + +/** + * @brief GPIO port E identifier. + */ +#if defined(PE_BASE) || defined(__DOXYGEN__) +#define IOPORT5 ((volatile msp430x_gpio_registers_t *)PE_BASE) +#endif + +/** + * @brief GPIO port F identifier. + */ +#if defined(PF_BASE) || defined(__DOXYGEN__) +#define IOPORT6 ((volatile msp430x_gpio_registers_t *)PF_BASE +#endif + +/** + * @brief GPIO port J identifier. + */ +#define IOPORT0 ((volatile msp430x_gpio_registers_t *)PJ_BASE) + +/*===========================================================================*/ +/* Implementation, some of the following macros could be implemented as */ +/* functions, if so please put them in pal_lld.c. */ +/*===========================================================================*/ + +/** + * @brief Low level PAL subsystem initialization. + * + * @param[in] config architecture-dependent ports configuration + * + * @notapi + */ +#define pal_lld_init(config) _pal_lld_init(config) + +/** + * @brief Reads the physical I/O port states. + * + * @param[in] port port identifier + * @return The port bits. + * + * @notapi + */ +#define pal_lld_readport(port) ((port)->in) + +/** + * @brief Reads the output latch. + * @details The purpose of this function is to read back the latched output + * value. + * + * @param[in] port port identifier + * @return The latched logical states. + * + * @notapi + */ +#define pal_lld_readlatch(port) ((port)->out) + +/** + * @brief Writes a bits mask on a I/O port. + * + * @param[in] port port identifier + * @param[in] bits bits to be written on the specified port + * + * @notapi + */ +#define pal_lld_writeport(port, bits) ((port)->out = (bits)) + + +/** + * @brief Sets a bits mask on a I/O port. + * + * @param[in] port port identifier + * @param[in] bits bits to be ORed on the specified port + * + * @notapi + */ +#define pal_lld_setport(port, bits) ((port)->out |= (bits)) + +/** + * @brief Clears a bits mask on a I/O port. + * + * @param[in] port port identifier + * @param[in] bits bits to be cleared on the specified port + * + * @notapi + */ +#define pal_lld_clearport(port, bits) ((port)->out &= ~(bits)) + +/** + * @brief Toggles a bits mask on a I/O port. + * + * @param[in] port port identifier + * @param[in] bits bits to be XORed on the specified port + * + * @notapi + */ +#define pal_lld_toggleport(port, bits) ((port)->out ^= (bits)) + +/** + * @brief Pads group mode setup. + * @details This function programs a pads group belonging to the same port + * with the specified mode. + * @note Programming an unknown or unsupported mode is silently ignored. + * + * @param[in] port port identifier + * @param[in] mask group mask + * @param[in] offset group bit offset within the port + * @param[in] mode group mode + * + * @notapi + */ +#define pal_lld_setgroupmode(port, mask, offset, mode) \ + _pal_lld_setgroupmode(port, mask << offset, mode) + +/** + * @brief Clears a pad logical state to @p PAL_LOW. + * @details This function is implemented in a way which should + * produce a BIC instruction rather than an AND + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * + * @notapi + */ +#define pal_lld_clearpad(port, pad) ((port)->out &= ~(BIT ## pad)) + +#if !defined(__DOXYGEN__) +extern const PALConfig pal_default_config; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void _pal_lld_init(const PALConfig *config); + void _pal_lld_setgroupmode(ioportid_t port, + ioportmask_t mask, + iomode_t mode); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_PAL == TRUE */ + +#endif /* _PAL_LLD_H_ */ + +/** @} */ diff --git a/os/hal/ports/MSP430X/hal_serial_lld.c b/os/hal/ports/MSP430X/hal_serial_lld.c new file mode 100644 index 0000000..277f6d2 --- /dev/null +++ b/os/hal/ports/MSP430X/hal_serial_lld.c @@ -0,0 +1,657 @@ +/* + ChibiOS - Copyright (C) 2016 Andrew Wygle aka awygle + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file MSP430X/hal_serial_lld.c + * @brief MSP430X serial subsystem low level driver source. + * + * @addtogroup SERIAL + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_SERIAL == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief USART0 serial driver identifier.*/ +#if (MSP430X_SERIAL_USE_USART0 == TRUE) || defined(__DOXYGEN__) +#ifndef __MSP430_HAS_EUSCI_A0__ + #error "Cannot find USCI module to use for SD0" +#endif +SerialDriver SD0; +#endif + +/** @brief USART1 serial driver identifier.*/ +#if (MSP430X_SERIAL_USE_USART1 == TRUE) || defined(__DOXYGEN__) +#ifndef __MSP430_HAS_EUSCI_A1__ + #error "Cannot find USCI module to use for SD1" +#endif +SerialDriver SD1; +#endif + +/** @brief USART2 serial driver identifier.*/ +#if (MSP430X_SERIAL_USE_USART2 == TRUE) || defined(__DOXYGEN__) +#ifndef __MSP430_HAS_EUSCI_A2__ + #error "Cannot find USCI module to use for SD2" +#endif +SerialDriver SD2; +#endif + +/** @brief USART3 serial driver identifier.*/ +#if (MSP430X_SERIAL_USE_USART3 == TRUE) || defined(__DOXYGEN__) +#ifndef __MSP430_HAS_EUSCI_A3__ + #error "Cannot find USCI module to use for SD3" +#endif +SerialDriver SD3; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/** + * @brief Driver default configuration. + */ +static const SerialConfig default_config = { + SERIAL_DEFAULT_BITRATE +}; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief UCBRS calculation. + * @details This function calculates the UCBRS value for oversampled baud + * rates. + * + * @param[in] frac Fractional part of baud rate division, times 10000. + */ +static uint8_t UCBRS(uint16_t frac) { + /* TODO there must be a better way */ + if (frac < 529) + return 0x00; + else if (frac < 715) + return 0x01; + else if (frac < 835) + return 0x02; + else if (frac < 1001) + return 0x04; + else if (frac < 1252) + return 0x08; + else if (frac < 1430) + return 0x10; + else if (frac < 1670) + return 0x20; + else if (frac < 2147) + return 0x11; + else if (frac < 2224) + return 0x21; + else if (frac < 2503) + return 0x22; + else if (frac < 3000) + return 0x44; + else if (frac < 3335) + return 0x25; + else if (frac < 3575) + return 0x49; + else if (frac < 3753) + return 0x4A; + else if (frac < 4003) + return 0x52; + else if (frac < 4286) + return 0x92; + else if (frac < 4378) + return 0x53; + else if (frac < 5002) + return 0x55; + else if (frac < 5715) + return 0xAA; + else if (frac < 6003) + return 0x6B; + else if (frac < 6254) + return 0xAD; + else if (frac < 6432) + return 0xB5; + else if (frac < 6667) + return 0xB6; + else if (frac < 7001) + return 0xD6; + else if (frac < 7147) + return 0xB7; + else if (frac < 7503) + return 0xBB; + else if (frac < 7861) + return 0xDD; + else if (frac < 8004) + return 0xED; + else if (frac < 8333) + return 0xEE; + else if (frac < 8464) + return 0xBF; + else if (frac < 8572) + return 0xDF; + else if (frac < 8751) + return 0xEF; + else if (frac < 9004) + return 0xF7; + else if (frac < 9170) + return 0xFB; + else if (frac < 9288) + return 0xFD; + else + return 0xFE; +} + +/** + * @brief Modulation control word calculator. + * @details This function calculates the modulation control word from the + * input clock frequency and the requested baud rate. + * + * @param[in] baud Requested baud rate + * @param[in] freq Frequency of the clock driving the USCI module + */ +static uint16_t UCAxMCTLW(uint32_t baud, uint32_t freq) { + + uint16_t n = freq/baud; + /*uint16_t frac = (freq * 10000 / baud) - ((freq / baud) * 10000);*/ + uint16_t frac = (freq - (n * baud)) * 10000 / baud; + if (n > 16) { + while (n > 16) { + n -= 16; + } + return (UCBRS(frac) << 8) | (n << 4) | UCOS16; + } + return UCBRS(frac) << 8; +} + +/** + * @brief UCBRW calculation. + * @details This function calculates the UCBRW value for all baud + * rates. + * + * @param[in] baud Requested baud rate + * @param[in] freq Frequency of the clock driving the USCI module + */ +static uint16_t UCAxBRW(uint32_t baud, uint32_t freq) { + uint16_t n = freq/baud; + if (n > 16) { + return n >> 4; + } + return n; +} + +#if (MSP430X_SERIAL_USE_USART0 == TRUE) || defined(__DOXYGEN__) +static void usart0_init(const SerialConfig *config) { + UCA0BRW = UCAxBRW(config->sc_bitrate, MSP430X_USART0_CLK_FREQ); + UCA0MCTLW = UCAxMCTLW(config->sc_bitrate, MSP430X_USART0_CLK_FREQ); + UCA0STATW = 0; + UCA0ABCTL = 0; + UCA0IRCTL = 0; + UCA0CTLW0 = (MSP430X_USART0_PARITY << 14) | (MSP430X_USART0_ORDER << 13) | \ + (MSP430X_USART0_SIZE << 12) | (MSP430X_USART0_STOP << 11) | \ + (MSP430X_USART0_UCSSEL); + UCA0IE = UCRXIE; +} +#endif + +#if (MSP430X_SERIAL_USE_USART1 == TRUE) || defined(__DOXYGEN__) +static void usart1_init(const SerialConfig *config) { + UCA1BRW = UCAxBRW(config->sc_bitrate, MSP430X_USART1_CLK_FREQ); + UCA1MCTLW = UCAxMCTLW(config->sc_bitrate, MSP430X_USART1_CLK_FREQ); + UCA1STATW = 0; + UCA1ABCTL = 0; + UCA1IRCTL = 0; + UCA1IE = UCRXIE; + UCA1CTLW0 = (MSP430X_USART1_PARITY << 14) | (MSP430X_USART1_ORDER << 13) | \ + (MSP430X_USART1_SIZE << 12) | (MSP430X_USART1_STOP << 11) | \ + (MSP430X_USART1_UCSSEL); +} +#endif + +#if (MSP430X_SERIAL_USE_USART2 == TRUE) || defined(__DOXYGEN__) +static void usart2_init(const SerialConfig *config) { + UCA2BRW = UCAxBRW(config->sc_bitrate, MSP430X_USART2_CLK_FREQ); + UCA2MCTLW = UCAxMCTLW(config->sc_bitrate); + UCA2STATW = 0; + UCA2ABCTL = 0; + UCA2IRCTL = 0; + UCA2IE = UCRXIE; + UCA2CTLW0 = (MSP430X_USART2_PARITY << 14) | (MSP430X_USART2_ORDER << 13) | \ + (MSP430X_USART2_SIZE << 12) | (MSP430X_USART2_STOP << 11) | \ + (MSP430X_USART2_UCSSEL); +} +#endif + +#if (MSP430X_SERIAL_USE_USART3 == TRUE) || defined(__DOXYGEN__) +static void usart3_init(const SerialConfig *config) { + UCA3BRW = UCAxBRW(config->sc_bitrate, MSP430X_USART3_CLK_FREQ); + UCA3MCTLW = UCAxMCTLW(config->sc_bitrate, MSP430X_USART3_CLK_FREQ); + UCA3STATW = 0; + UCA3ABCTL = 0; + UCA3IRCTL = 0; + UCA3IE = UCRXIE; + UCA3CTLW0 = (MSP430X_USART3_PARITY << 14) | (MSP430X_USART3_ORDER << 13) | \ + (MSP430X_USART3_SIZE << 12) | (MSP430X_USART3_STOP << 11) | \ + (MSP430X_USART3_UCSSEL); +} +#endif + +#if (MSP430X_SERIAL_USE_USART0 == TRUE) || defined(__DOXYGEN__) +static void notify0(io_queue_t *qp) { + + (void)qp; + UCA0IE |= UCTXIE; +} +#endif + +#if (MSP430X_SERIAL_USE_USART1 == TRUE) || defined(__DOXYGEN__) +static void notify1(io_queue_t *qp) { + + (void)qp; + UCA1IE |= UCTXIE; +} +#endif + +#if (MSP430X_SERIAL_USE_USART2 == TRUE) || defined(__DOXYGEN__) +static void notify2(io_queue_t *qp) { + + (void)qp; + UCA2IE |= UCTXIE; +} +#endif + +#if (MSP430X_SERIAL_USE_USART3 == TRUE) || defined(__DOXYGEN__) +static void notify3(io_queue_t *qp) { + + (void)qp; + UCA3IE |= UCTXIE; +} +#endif + +/** + * @brief Error handling routine. + * + * @param[in] sra USCI status register containing errors + * @param[in] sdp pointer to a @p SerialDriver object + */ +static void set_error(uint16_t sra, SerialDriver *sdp) { + eventflags_t sts = 0; + + if (sra & UCOE) + sts |= SD_OVERRUN_ERROR; + if (sra & UCPE) + sts |= SD_PARITY_ERROR; + if (sra & UCFE) + sts |= SD_FRAMING_ERROR; + osalSysLockFromISR(); + chnAddFlagsI(sdp, sts); + osalSysUnlockFromISR(); +} + + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if MSP430X_SERIAL_USE_USART0 || defined(__DOXYGEN__) +/** + * @brief USART0 interrupt handler. + * + * @isr + */ +PORT_IRQ_HANDLER(USCI_A0_VECTOR) { + msg_t b; + + OSAL_IRQ_PROLOGUE(); + + switch (__even_in_range(UCA0IV,USCI_UART_UCTXCPTIFG)) { + case USCI_UART_UCRXIFG: /* RX interrupt */ + + /* Detect errors */ + if (UCA0STATW & UCRXERR) + set_error(UCA0STATW, &SD0); + + /* Data available */ + osalSysLockFromISR(); + sdIncomingDataI(&SD0, UCA0RXBUF); + osalSysUnlockFromISR(); + break; + + case USCI_UART_UCTXIFG: /* TX interrupt */ + + /* Transmission buffer empty */ + osalSysLockFromISR(); + b = sdRequestDataI(&SD0); + if (b < Q_OK) { + chnAddFlagsI(&SD0, CHN_OUTPUT_EMPTY); + UCA0IE = (UCA0IE & ~UCTXIE) | UCTXCPTIE; + UCA0IFG |= UCTXIFG; /* If we don't write to TXBUF, IFG won't get set */ + } + else + UCA0TXBUF = b; + osalSysUnlockFromISR(); + break; + + case USCI_UART_UCTXCPTIFG: /* TX complete interrupt */ + + /* Physical transmission end */ + osalSysLockFromISR(); + if (oqIsEmptyI(&SD0.oqueue)) + chnAddFlagsI(&SD0, CHN_TRANSMISSION_END); + UCA0IE &= ~UCTXCPTIE; + break; + + default: /* other interrupts */ + while (1); + break; + } + + OSAL_IRQ_EPILOGUE(); + +} +#endif + +#if MSP430X_SERIAL_USE_USART1 || defined(__DOXYGEN__) +/** + * @brief USART1 interrupt handler. + * + * @isr + */ +PORT_IRQ_HANDLER(USCI_A1_VECTOR) { + msg_t b; + + OSAL_IRQ_PROLOGUE(); + + switch (__even_in_range(UCA1IV,USCI_UART_UCTXCPTIFG)) { + case USCI_UART_UCRXIFG: /* RX interrupt */ + + /* Detect errors */ + if (UCA1STATW & UCRXERR) + set_error(UCA1STATW, &SD1); + + /* Data available */ + osalSysLockFromISR(); + sdIncomingDataI(&SD1, UCA1RXBUF); + osalSysUnlockFromISR(); + break; + + case USCI_UART_UCTXIFG: /* TX interrupt */ + + /* Transmission buffer empty */ + osalSysLockFromISR(); + b = sdRequestDataI(&SD1); + if (b < Q_OK) { + chnAddFlagsI(&SD1, CHN_OUTPUT_EMPTY); + UCA1IE = (UCA1IE & ~UCTXIE) | UCTXCPTIE; + UCA1IFG |= UCTXIFG; /* If we don't write to TXBUF, IFG won't get set */ + } + else + UCA1TXBUF = b; + osalSysUnlockFromISR(); + break; + + case USCI_UART_UCTXCPTIFG: /* TX complete interrupt */ + + /* Physical transmission end */ + osalSysLockFromISR(); + if (oqIsEmptyI(&SD1.oqueue)) + chnAddFlagsI(&SD1, CHN_TRANSMISSION_END); + UCA1IE &= ~UCTXCPTIE; + break; + + default: /* other interrupts */ + while (1); + break; + } + + OSAL_IRQ_EPILOGUE(); + +} +#endif + +#if MSP430X_SERIAL_USE_USART2 || defined(__DOXYGEN__) +/** + * @brief USART2 interrupt handler. + * + * @isr + */ +PORT_IRQ_HANDLER(USCI_A2_VECTOR) { + msg_t b; + + OSAL_IRQ_PROLOGUE(); + + switch (__even_in_range(UCA2IV,USCI_UART_UCTXCPTIFG)) { + case USCI_UART_UCRXIFG: /* RX interrupt */ + + /* Detect errors */ + if (UCA2STATW & UCRXERR) + set_error(UCA2STATW, &SD2); + + /* Data available */ + osalSysLockFromISR(); + sdIncomingDataI(&SD2, UCA2RXBUF); + osalSysUnlockFromISR(); + break; + + case USCI_UART_UCTXIFG: /* TX interrupt */ + + /* Transmission buffer empty */ + osalSysLockFromISR(); + b = sdRequestDataI(&SD2); + if (b < Q_OK) { + chnAddFlagsI(&SD2, CHN_OUTPUT_EMPTY); + UCA2IE = (UCA2IE & ~UCTXIE) | UCTXCPTIE; + UCA2IFG |= UCTXIFG; /* If we don't write to TXBUF, IFG won't get set */ + } + else + UCA2TXBUF = b; + osalSysUnlockFromISR(); + break; + + case USCI_UART_UCTXCPTIFG: /* TX complete interrupt */ + + /* Physical transmission end */ + osalSysLockFromISR(); + if (oqIsEmptyI(&SD2.oqueue)) + chnAddFlagsI(&SD2, CHN_TRANSMISSION_END); + UCA2IE &= ~UCTXCPTIE; + break; + + default: /* other interrupts */ + while (1); + break; + } + + OSAL_IRQ_EPILOGUE(); + +} +#endif + +#if MSP430X_SERIAL_USE_USART3 || defined(__DOXYGEN__) +/** + * @brief USART3 interrupt handler. + * + * @isr + */ +PORT_IRQ_HANDLER(USCI_A3_VECTOR) { + msg_t b; + + OSAL_IRQ_PROLOGUE(); + + switch (__even_in_range(UCA3IV,USCI_UART_UCTXCPTIFG)) { + case USCI_UART_UCRXIFG: /* RX interrupt */ + + /* Detect errors */ + if (UCA3STATW & UCRXERR) + set_error(UCA3STATW, &SD3); + + /* Data available */ + osalSysLockFromISR(); + sdIncomingDataI(&SD3, UCA3RXBUF); + osalSysUnlockFromISR(); + break; + + case USCI_UART_UCTXIFG: /* TX interrupt */ + + /* Transmission buffer empty */ + osalSysLockFromISR(); + b = sdRequestDataI(&SD3); + if (b < Q_OK) { + chnAddFlagsI(&SD3, CHN_OUTPUT_EMPTY); + UCA3IE = (UCA3IE & ~UCTXIE) | UCTXCPTIE; + UCA3IFG |= UCTXIFG; /* If we don't write to TXBUF, IFG won't get set */ + } + else + UCA3TXBUF = b; + osalSysUnlockFromISR(); + break; + + case USCI_UART_UCTXCPTIFG: /* TX complete interrupt */ + + /* Physical transmission end */ + osalSysLockFromISR(); + if (oqIsEmptyI(&SD3.oqueue)) + chnAddFlagsI(&SD3, CHN_TRANSMISSION_END); + UCA3IE &= ~UCTXCPTIE; + break; + + default: /* other interrupts */ + while (1); + break; + } + + OSAL_IRQ_EPILOGUE(); + +} +#endif + + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level serial driver initialization. + * + * @notapi + */ +void sd_lld_init(void) { + +#if MSP430X_SERIAL_USE_USART0 == TRUE + sdObjectInit(&SD0, NULL, notify0); +#endif + +#if MSP430X_SERIAL_USE_USART1 == TRUE + sdObjectInit(&SD1, NULL, notify1); +#endif + +#if MSP430X_SERIAL_USE_USART2 == TRUE + sdObjectInit(&SD2, NULL, notify2); +#endif + +#if MSP430X_SERIAL_USE_USART3 == TRUE + sdObjectInit(&SD3, NULL, notify3); +#endif +} + +/** + * @brief Low level serial driver configuration and (re)start. + * + * @param[in] sdp pointer to a @p SerialDriver object + * @param[in] config the architecture-dependent serial driver configuration. + * If this parameter is set to @p NULL then a default + * configuration is used. + * + * @notapi + */ +void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) { + + if (config == NULL) { + config = &default_config; + } + + + if (sdp->state == SD_STOP) { +#if MSP430X_SERIAL_USE_USART0 == TRUE + if (&SD0 == sdp) { + usart0_init(config); + } +#endif +#if MSP430X_SERIAL_USE_USART1 == TRUE + if (&SD1 == sdp) { + usart1_init(config); + } +#endif +#if MSP430X_SERIAL_USE_USART2 == TRUE + if (&SD2 == sdp) { + usart2_init(config); + } +#endif +#if MSP430X_SERIAL_USE_USART3 == TRUE + if (&SD3 == sdp) { + usart3_init(config); + } +#endif + } +} + +/** + * @brief Low level serial driver stop. + * @details De-initializes the USART, stops the associated clock, resets the + * interrupt vector. + * + * @param[in] sdp pointer to a @p SerialDriver object + * + * @notapi + */ +void sd_lld_stop(SerialDriver *sdp) { + + if (sdp->state == SD_READY) { +#if MSP430X_SERIAL_USE_USART0 == TRUE + if (&SD0 == sdp) { + UCA0CTLW0 = UCSWRST; + } +#endif +#if MSP430X_SERIAL_USE_USART1 == TRUE + if (&SD1 == sdp) { + UCA1CTLW0 = UCSWRST; + } +#endif +#if MSP430X_SERIAL_USE_USART2 == TRUE + if (&SD2 == sdp) { + UCA2CTLW0 = UCSWRST; + } +#endif +#if MSP430X_SERIAL_USE_USART3 == TRUE + if (&SD3 == sdp) { + UCA3CTLW0 = UCSWRST; + } +#endif + } +} + +#endif /* HAL_USE_SERIAL == TRUE */ + +/** @} */ diff --git a/os/hal/ports/MSP430X/hal_serial_lld.h b/os/hal/ports/MSP430X/hal_serial_lld.h new file mode 100644 index 0000000..389e5c8 --- /dev/null +++ b/os/hal/ports/MSP430X/hal_serial_lld.h @@ -0,0 +1,320 @@ +/* + ChibiOS - Copyright (C) 2016 Andrew Wygle aka awygle + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file MSP430X/hal_serial_lld.h + * @brief MSP430X serial subsystem low level driver header. + * + * @addtogroup SERIAL + * @{ + */ + +#ifndef _SERIAL_LLD_H_ +#define _SERIAL_LLD_H_ + +#if (HAL_USE_SERIAL == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +#define NONE 0 +#define ODD 2 +#define EVEN 3 + +#define MSB 1 +#define LSB 0 + +#define SEVEN 1 +#define EIGHT 0 + +#define ONE 0 +#define TWO 1 + +#define MSP430X_SERIAL_SMCLK UCSSEL__SMCLK +#define MSP430X_SERIAL_UCLK UCSSEL__UCLK +#define MSP430X_SERIAL_ACLK UCSSEL__ACLK + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name USART0 configuration options + * @{ + */ +/** + * @brief USART0 driver enable switch. + * @details If set to @p TRUE the support for USART1 is included. + * @note The default is @p FALSE. + */ +#if !defined(MSP430X_SERIAL_USE_USART0) || defined(__DOXYGEN__) +#define MSP430X_SERIAL_USE_USART0 FALSE +#endif +/** @} */ + +/** + * @name USART1 configuration options + * @{ + */ +/** + * @brief USART1 driver enable switch. + * @details If set to @p TRUE the support for USART1 is included. + * @note The default is @p FALSE. + */ +#if !defined(MSP430X_SERIAL_USE_USART1) || defined(__DOXYGEN__) +#define MSP430X_SERIAL_USE_USART1 FALSE +#endif +/** @} */ + +/** + * @name USART2 configuration options + * @{ + */ +/** + * @brief USART2 driver enable switch. + * @details If set to @p TRUE the support for USART1 is included. + * @note The default is @p FALSE. + */ +#if !defined(MSP430X_SERIAL_USE_USART2) || defined(__DOXYGEN__) +#define MSP430X_SERIAL_USE_USART2 FALSE +#endif +/** @} */ + +/** + * @name USART3 configuration options + * @{ + */ +/** + * @brief USART3 driver enable switch. + * @details If set to @p TRUE the support for USART1 is included. + * @note The default is @p FALSE. + */ +#if !defined(MSP430X_SERIAL_USE_USART3) || defined(__DOXYGEN__) +#define MSP430X_SERIAL_USE_USART3 FALSE +#endif + +#if MSP430X_SERIAL_USE_USART0 + #if !defined(MSP430X_USART0_PARITY) + #define MSP430X_USART0_PARITY NONE + #endif + #if !defined(MSP430X_USART0_ORDER) + #define MSP430X_USART0_ORDER LSB + #endif + #if !defined(MSP430X_USART0_SIZE) + #define MSP430X_USART0_SIZE EIGHT + #endif + #if !defined(MSP430X_USART0_STOP) + #define MSP430X_USART0_STOP ONE + #endif + #if !defined(MSP430X_USART0_CLK_SRC) + #define MSP430X_USART0_CLK_SRC MSP430X_UCLK_SRC + #ifndef MSP430X_USART0_CLK_FREQ + #error "Requested external UART0 clock but no frequency given" + #endif + #define MSP430X_USART0_UCSSEL UCSSEL__UCLK + #elif MSP430X_USART0_CLK_SRC == MSP430X_ACLK_SRC + #define MSP430X_USART0_CLK_SRC MSP430X_ACLK_SRC + #define MSP430X_USART0_CLK_FREQ MSP430X_ACLK_FREQ + #define MSP430X_USART0_UCSSEL UCSSEL__ACLK + #elif MSP430X_USART0_CLK_SRC == MSP430X_SMCLK_SRC + #define MSP430X_USART0_CLK_SRC MSP430X_SMCLK_SRC + #define MSP430X_USART0_CLK_FREQ MSP430X_SMCLK_FREQ + #define MSP430X_USART0_UCSSEL UCSSEL__SMCLK + #else + #error "MSP430X_USART0_CLK_SRC invalid" + #endif +#endif + +#if MSP430X_SERIAL_USE_USART1 + #if !defined(MSP430X_USART1_PARITY) + #define MSP430X_USART1_PARITY NONE + #endif + #if !defined(MSP430X_USART1_ORDER) + #define MSP430X_USART1_ORDER LSB + #endif + #if !defined(MSP430X_USART1_SIZE) + #define MSP430X_USART1_SIZE EIGHT + #endif + #if !defined(MSP430X_USART1_STOP) + #define MSP430X_USART1_STOP ONE + #endif + #if !defined(MSP430X_USART1_CLK_SRC) + #define MSP430X_USART1_CLK_SRC MSP430X_UCLK_SRC + #ifndef MSP430X_USART1_CLK_FREQ + #error "Requested external UART0 clock but no frequency given" + #endif + #define MSP430X_USART1_UCSSEL UCSSEL__UCLK + #elif MSP430X_USART1_CLK_SRC == MSP430X_ACLK_SRC + #define MSP430X_USART1_CLK_SRC MSP430X_ACLK_SRC + #define MSP430X_USART1_CLK_FREQ MSP430X_ACLK_FREQ + #define MSP430X_USART1_UCSSEL UCSSEL__ACLK + #elif MSP430X_USART1_CLK_SRC == MSP430X_SMCLK_SRC + #define MSP430X_USART1_CLK_SRC MSP430X_SMCLK_SRC + #define MSP430X_USART1_CLK_FREQ MSP430X_SMCLK_FREQ + #define MSP430X_USART1_UCSSEL UCSSEL__SMCLK + #else + #error "MSP430X_USART1_CLK_SRC invalid" + #endif +#endif + +#if MSP430X_SERIAL_USE_USART2 + #if !defined(MSP430X_USART2_PARITY) + #define MSP430X_USART2_PARITY NONE + #endif + #if !defined(MSP430X_USART2_ORDER) + #define MSP430X_USART2_ORDER LSB + #endif + #if !defined(MSP430X_USART2_SIZE) + #define MSP430X_USART2_SIZE EIGHT + #endif + #if !defined(MSP430X_USART2_STOP) + #define MSP430X_USART2_STOP ONE + #endif + #if !defined(MSP430X_USART2_CLK_SRC) + #define MSP430X_USART2_CLK_SRC MSP430X_UCLK_SRC + #ifndef MSP430X_USART2_CLK_FREQ + #error "Requested external UART0 clock but no frequency given" + #endif + #define MSP430X_USART2_UCSSEL UCSSEL__UCLK + #elif MSP430X_USART2_CLK_SRC == MSP430X_ACLK_SRC + #define MSP430X_USART2_CLK_SRC MSP430X_ACLK_SRC + #define MSP430X_USART2_CLK_FREQ MSP430X_ACLK_FREQ + #define MSP430X_USART2_UCSSEL UCSSEL__ACLK + #elif MSP430X_USART2_CLK_SRC == MSP430X_SMCLK_SRC + #define MSP430X_USART2_CLK_SRC MSP430X_SMCLK_SRC + #define MSP430X_USART2_CLK_FREQ MSP430X_SMCLK_FREQ + #define MSP430X_USART2_UCSSEL UCSSEL__SMCLK + #else + #error "MSP430X_USART2_CLK_SRC invalid" + #endif +#endif + +#if MSP430X_SERIAL_USE_USART3 + #if !defined(MSP430X_USART3_PARITY) + #define MSP430X_USART3_PARITY NONE + #endif + #if !defined(MSP430X_USART3_ORDER) + #define MSP430X_USART3_ORDER LSB + #endif + #if !defined(MSP430X_USART3_SIZE) + #define MSP430X_USART3_SIZE EIGHT + #endif + #if !defined(MSP430X_USART3_STOP) + #define MSP430X_USART3_STOP ONE + #endif + #if !defined(MSP430X_USART3_CLK_SRC) + #define MSP430X_USART3_CLK_SRC MSP430X_UCLK_SRC + #ifndef MSP430X_USART3_CLK_FREQ + #error "Requested external UART0 clock but no frequency given" + #endif + #define MSP430X_USART3_UCSSEL UCSSEL__UCLK + #elif MSP430X_USART3_CLK_SRC == MSP430X_ACLK_SRC + #define MSP430X_USART3_CLK_SRC MSP430X_ACLK_SRC + #define MSP430X_USART3_CLK_FREQ MSP430X_ACLK_FREQ + #define MSP430X_USART3_UCSSEL UCSSEL__ACLK + #elif MSP430X_USART3_CLK_SRC == MSP430X_SMCLK_SRC + #define MSP430X_USART3_CLK_SRC MSP430X_SMCLK_SRC + #define MSP430X_USART3_CLK_FREQ MSP430X_SMCLK_FREQ + #define MSP430X_USART3_UCSSEL UCSSEL__SMCLK + #else + #error "MSP430X_USART3_CLK_SRC invalid" + #endif +#endif + +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief MSP430X Serial Driver configuration structure. + * @details An insance of this structure must be passed to @p sdStart() + * in order to configure and start a serial driver operations. + * @note This structure content is architecture dependent, each driver + * implementation defines its own version and the custom static + * initializers. + */ +typedef struct { + /** + * @brief Bit rate. + */ + uint32_t sc_bitrate; + + /* End of the mandatory fields.*/ +} SerialConfig; + +/** + * @brief @p SerialDriver specific data. + */ +#define _serial_driver_data \ + _base_asynchronous_channel_data \ + /* Driver state.*/ \ + sdstate_t state; \ + /* Input queue.*/ \ + input_queue_t iqueue; \ + /* Output queue.*/ \ + output_queue_t oqueue; \ + /* Input circular buffer.*/ \ + uint8_t ib[SERIAL_BUFFERS_SIZE]; \ + /* Output circular buffer.*/ \ + uint8_t ob[SERIAL_BUFFERS_SIZE]; \ + /* End of the mandatory fields.*/ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if (MSP430X_SERIAL_USE_USART0 == TRUE) && !defined(__DOXYGEN__) +extern SerialDriver SD0; +#endif + +#if (MSP430X_SERIAL_USE_USART1 == TRUE) && !defined(__DOXYGEN__) +extern SerialDriver SD1; +#endif + +#if (MSP430X_SERIAL_USE_USART2 == TRUE) && !defined(__DOXYGEN__) +extern SerialDriver SD2; +#endif + +#if (MSP430X_SERIAL_USE_USART3 == TRUE) && !defined(__DOXYGEN__) +extern SerialDriver SD3; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void sd_lld_init(void); + void sd_lld_start(SerialDriver *sdp, const SerialConfig *config); + void sd_lld_stop(SerialDriver *sdp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_SERIAL == TRUE */ + +#endif /* _SERIAL_LLD_H_ */ + +/** @} */ diff --git a/os/hal/ports/MSP430X/hal_st_lld.c b/os/hal/ports/MSP430X/hal_st_lld.c new file mode 100644 index 0000000..8ea1b9d --- /dev/null +++ b/os/hal/ports/MSP430X/hal_st_lld.c @@ -0,0 +1,206 @@ +/* + ChibiOS - Copyright (C) 2016 Andrew Wygle aka awygle + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file MSP430X/hal_st_lld.c + * @brief MSP430X ST subsystem low level driver source. + * + * @addtogroup ST + * @{ + */ + +#include "hal.h" +#include + +#if (OSAL_ST_MODE != OSAL_ST_MODE_NONE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#if (OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING) || defined(__DOXYGEN__) + #define MSP430X_ST_DIV_CALC(x) ((MSP430X_ST_CLK_FREQ / OSAL_ST_FREQUENCY) == x) +#endif + + +#if (OSAL_ST_MODE == OSAL_ST_MODE_PERIODIC) || defined(__DOXYGEN__) + #if ((MSP430X_ST_CLK_FREQ / OSAL_ST_FREQUENCY / 64) > MSP_TIMER_COUNTER_MAX) + #error "Frequency too low for timer - please set OSAL_ST_FREQUENCY to a higher value" + #endif + + #define MSP430X_ST_DIV_CALC(x) ((MSP430X_ST_CLK_FREQ / OSAL_ST_FREQUENCY / x) <= MSP_TIMER_COUNTER_MAX) +#endif + +/* Find suitable prescaler setting */ +#if MSP430X_ST_DIV_CALC(1) + #define MSP430X_ST_DIV 1 + #define MSP430X_ST_DIV_BITS ID__1 + #define MSP430X_ST_DIV_EX_BITS TAIDEX_0 +#elif MSP430X_ST_DIV_CALC(2) + #define MSP430X_ST_DIV 2 + #define MSP430X_ST_DIV_BITS ID__1 + #define MSP430X_ST_DIV_EX_BITS TAIDEX_1 +#elif MSP430X_ST_DIV_CALC(3) + #define MSP430X_ST_DIV 3 + #define MSP430X_ST_DIV_BITS ID__1 + #define MSP430X_ST_DIV_EX_BITS TAIDEX_2 +#elif MSP430X_ST_DIV_CALC(4) + #define MSP430X_ST_DIV 4 + #define MSP430X_ST_DIV_BITS ID__1 + #define MSP430X_ST_DIV_EX_BITS TAIDEX_3 +#elif MSP430X_ST_DIV_CALC(5) + #define MSP430X_ST_DIV 5 + #define MSP430X_ST_DIV_BITS ID__1 + #define MSP430X_ST_DIV_EX_BITS TAIDEX_4 +#elif MSP430X_ST_DIV_CALC(6) + #define MSP430X_ST_DIV 6 + #define MSP430X_ST_DIV_BITS ID__1 + #define MSP430X_ST_DIV_EX_BITS TAIDEX_5 +#elif MSP430X_ST_DIV_CALC(7) + #define MSP430X_ST_DIV 7 + #define MSP430X_ST_DIV_BITS ID__1 + #define MSP430X_ST_DIV_EX_BITS TAIDEX_6 +#elif MSP430X_ST_DIV_CALC(8) + #define MSP430X_ST_DIV 8 + #define MSP430X_ST_DIV_BITS ID__1 + #define MSP430X_ST_DIV_EX_BITS TAIDEX_7 +#elif MSP430X_ST_DIV_CALC(10) + #define MSP430X_ST_DIV 10 + #define MSP430X_ST_DIV_BITS ID__2 + #define MSP430X_ST_DIV_EX_BITS TAIDEX_4 +#elif MSP430X_ST_DIV_CALC(12) + #define MSP430X_ST_DIV 12 + #define MSP430X_ST_DIV_BITS ID__2 + #define MSP430X_ST_DIV_EX_BITS TAIDEX_5 +#elif MSP430X_ST_DIV_CALC(14) + #define MSP430X_ST_DIV 14 + #define MSP430X_ST_DIV_BITS ID__2 + #define MSP430X_ST_DIV_EX_BITS TAIDEX_6 +#elif MSP430X_ST_DIV_CALC(16) + #define MSP430X_ST_DIV 16 + #define MSP430X_ST_DIV_BITS ID__2 + #define MSP430X_ST_DIV_EX_BITS TAIDEX_7 +#elif MSP430X_ST_DIV_CALC(20) + #define MSP430X_ST_DIV 20 + #define MSP430X_ST_DIV_BITS ID__4 + #define MSP430X_ST_DIV_EX_BITS TAIDEX_4 +#elif MSP430X_ST_DIV_CALC(24) + #define MSP430X_ST_DIV 24 + #define MSP430X_ST_DIV_BITS ID__4 + #define MSP430X_ST_DIV_EX_BITS TAIDEX_5 +#elif MSP430X_ST_DIV_CALC(28) + #define MSP430X_ST_DIV 28 + #define MSP430X_ST_DIV_BITS ID__4 + #define MSP430X_ST_DIV_EX_BITS TAIDEX_6 +#elif MSP430X_ST_DIV_CALC(32) + #define MSP430X_ST_DIV 32 + #define MSP430X_ST_DIV_BITS ID__4 + #define MSP430X_ST_DIV_EX_BITS TAIDEX_7 +#elif MSP430X_ST_DIV_CALC(40) + #define MSP430X_ST_DIV 40 + #define MSP430X_ST_DIV_BITS ID__8 + #define MSP430X_ST_DIV_EX_BITS TAIDEX_4 +#elif MSP430X_ST_DIV_CALC(48) + #define MSP430X_ST_DIV 48 + #define MSP430X_ST_DIV_BITS ID__8 + #define MSP430X_ST_DIV_EX_BITS TAIDEX_5 +#elif MSP430X_ST_DIV_CALC(56) + #define MSP430X_ST_DIV 56 + #define MSP430X_ST_DIV_BITS ID__8 + #define MSP430X_ST_DIV_EX_BITS TAIDEX_6 +#elif MSP430X_ST_DIV_CALC(64) + #define MSP430X_ST_DIV 64 + #define MSP430X_ST_DIV_BITS ID__8 + #define MSP430X_ST_DIV_EX_BITS TAIDEX_7 +#else + #error "Error in calculating dividers - check OSAL_ST_FREQUENCY and frequency of input clock" +#endif +/* ugh never again*/ + +#if (OSAL_ST_MODE == OSAL_ST_MODE_PERIODIC) || defined(__DOXYGEN__) + #define MSP_TIMER_COUNTER (MSP430X_ST_CLK_FREQ / OSAL_ST_FREQUENCY / MSP430X_ST_DIV) + #define MSP430X_ST_CLK_FREQ_ (MSP_TIMER_COUNTER * MSP430X_ST_DIV * OSAL_ST_FREQUENCY) + #if (MSP430X_ST_CLK_FREQ != MSP430X_ST_CLK_FREQ_) + #warning "OSAL_ST_FREQUENCY cannot be generated exactly using timer" + #endif + #undef MSP430X_ST_CLK_FREQ_ +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/** + * @brief Timer handler for both modes + */ + +PORT_IRQ_HANDLER( MSP430X_ST_ISR ) { + + OSAL_IRQ_PROLOGUE(); + + osalSysLockFromISR(); + osalOsTimerHandlerI(); + osalSysUnlockFromISR(); + + OSAL_IRQ_EPILOGUE(); +} + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level ST driver initialization. + * + * @notapi + */ +void st_lld_init(void) { + #if (OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING) || defined (__DOXYGEN__) + /* Start disabled */ + MSP430X_ST_CCR(MSP430X_ST_TIMER) = 0; + MSP430X_ST_CCTL(MSP430X_ST_TIMER) = 0; + MSP430X_ST_EX(MSP430X_ST_TIMER) = MSP430X_ST_DIV_EX_BITS; + MSP430X_ST_CTL(MSP430X_ST_TIMER) = (TACLR | MC_2 | MSP430X_ST_DIV_BITS | MSP430X_ST_TASSEL); + #endif /* OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING */ + + #if (OSAL_ST_MODE == OSAL_ST_MODE_PERIODIC) || defined (__DOXYGEN__) + /* Start enabled */ + MSP430X_ST_CCR(MSP430X_ST_TIMER) = MSP_TIMER_COUNTER - 1; + MSP430X_ST_CCTL(MSP430X_ST_TIMER) = CCIE; + MSP430X_ST_EX(MSP430X_ST_TIMER) = MSP430X_ST_DIV_EX_BITS; + MSP430X_ST_CTL(MSP430X_ST_TIMER) = (TACLR | MC_1 | MSP430X_ST_DIV_BITS | MSP430X_ST_TASSEL); + #endif /* OSAL_ST_MODE == OSAL_ST_MODE_PERIODIC */ +} + +#endif /* OSAL_ST_MODE != OSAL_ST_MODE_NONE */ + +/** @} */ diff --git a/os/hal/ports/MSP430X/hal_st_lld.h b/os/hal/ports/MSP430X/hal_st_lld.h new file mode 100644 index 0000000..32ad970 --- /dev/null +++ b/os/hal/ports/MSP430X/hal_st_lld.h @@ -0,0 +1,216 @@ +/* + ChibiOS - Copyright (C) 2016 Andrew Wygle aka awygle + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file MSP430X/hal_st_lld.h + * @brief MSP430X ST subsystem low level driver header. + * @details This header is designed to be include-able without having to + * include other files from the HAL. + * + * @addtogroup MSP430X + * @{ + */ + +#ifndef _ST_LLD_H_ +#define _ST_LLD_H_ + +#include + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @brief Timer maximum value + */ +#define MSP_TIMER_COUNTER_MAX 65535 + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief System timer clock source. + * + * @note Legal values are undefined, MSP430X_ACLK_SRC, and + * MSP430X_SMCLK_SRC. + * @note If undefined, must define MSP430X_ST_CLK_FREQ as frequency of + * external clock and configure PAL appropriately. + */ +#if !defined (MSP430X_ST_CLK_SRC) + #ifndef MSP430X_ST_CLK_FREQ + #warning "Requested external source for ST but no frequency given" + #warning "- assuming OSAL_ST_FREQUENCY" + #define MSP430X_ST_CLK_FREQ OSAL_ST_FREQUENCY + #endif + #define MSP430X_ST_TASSEL TASSEL__TACLK +#elif MSP430X_ST_CLK_SRC == MSP430X_ACLK_SRC + #define MSP430X_ST_CLK_FREQ MSP430X_ACLK_FREQ + #define MSP430X_ST_TASSEL TASSEL__ACLK +#elif MSP430X_ST_CLK_SRC == MSP430X_SMCLK_SRC + #define MSP430X_ST_CLK_FREQ MSP430X_SMCLK_FREQ + #define MSP430X_ST_TASSEL TASSEL__SMCLK +#endif + +/* Timers */ +/** + * @brief Timer type (by letter) to be used for ST. + * @note Legal values are A and B. D support not yet implemented. + * @note Defaults to A + */ +#if !defined(MSP430X_ST_TIMER_TYPE) + #define MSP430X_ST_TIMER_TYPE A +#endif +/** + * @brief Timer instance (by number) to be used for ST. + * @note Defaults to 0 + */ +#if !defined (MSP430X_ST_TIMER_INDEX) + #define MSP430X_ST_TIMER_INDEX 0 +#endif + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#define TIMER_HELPER2(x, y) x ## y +#define TIMER_HELPER(x, y) TIMER_HELPER2(x, y) +#define MSP430X_ST_TIMER TIMER_HELPER(MSP430X_ST_TIMER_TYPE, MSP430X_ST_TIMER_INDEX) +#define CCR_HELPER(x) T ## x ## CCR0 +#define MSP430X_ST_CCR(x) CCR_HELPER(x) +#define CCTL_HELPER(x) T ## x ## CCTL0 +#define MSP430X_ST_CCTL(x) CCTL_HELPER(x) +#define EX_HELPER(x) T ## x ## EX0 +#define MSP430X_ST_EX(x) EX_HELPER(x) +#define CTL_HELPER(x) T ## x ## CTL +#define MSP430X_ST_CTL(x) CTL_HELPER(x) +#define R_HELPER(x) T ## x ## R +#define MSP430X_ST_R(x) R_HELPER(x) +#define ISR_HELPER2(x, y) TIMER ## y ## _ ## x ## 0_VECTOR +#define ISR_HELPER(x, y) ISR_HELPER2(x, y) +#define MSP430X_ST_ISR ISR_HELPER(MSP430X_ST_TIMER_TYPE, MSP430X_ST_TIMER_INDEX) + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void st_lld_init(void); +#ifdef __cplusplus +} +#endif + +/*===========================================================================*/ +/* Driver inline functions. */ +/*===========================================================================*/ + +/** + * @brief Returns the time counter value. + * + * @return The counter value. + * + * @notapi + */ +static inline systime_t st_lld_get_counter(void) { + + return (systime_t)MSP430X_ST_R(MSP430X_ST_TIMER); +} + +/** + * @brief Starts the alarm. + * @note Makes sure that no spurious alarms are triggered after + * this call. + * + * @param[in] abstime the time to be set for the first alarm + * + * @notapi + */ +static inline void st_lld_start_alarm(systime_t abstime) { + + MSP430X_ST_CCR(MSP430X_ST_TIMER) = abstime; + + /* Reset pending interrupt */ + MSP430X_ST_CCTL(MSP430X_ST_TIMER) &= (~CCIFG); + + /* Enable interrupt */ + MSP430X_ST_CCTL(MSP430X_ST_TIMER) |= CCIE; +} + +/** + * @brief Stops the alarm interrupt. + * + * @notapi + */ +static inline void st_lld_stop_alarm(void) { + + MSP430X_ST_CCTL(MSP430X_ST_TIMER) &= (~CCIE); +} + +/** + * @brief Sets the alarm time. + * + * @param[in] abstime the time to be set for the next alarm + * + * @notapi + */ +static inline void st_lld_set_alarm(systime_t abstime) { + + MSP430X_ST_CCR(MSP430X_ST_TIMER) = abstime; +} + +/** + * @brief Returns the current alarm time. + * + * @return The currently set alarm time. + * + * @notapi + */ +static inline systime_t st_lld_get_alarm(void) { + + return MSP430X_ST_CCR(MSP430X_ST_TIMER); +} + +/** + * @brief Determines if the alarm is active. + * + * @return The alarm status. + * @retval false if the alarm is not active. + * @retval true is the alarm is active + * + * @notapi + */ +static inline bool st_lld_is_alarm_active(void) { + + return (bool)((MSP430X_ST_CCTL(MSP430X_ST_TIMER) & CCIE) != 0); +} + +#endif /* _ST_LLD_H_ */ + +/** @} */ diff --git a/os/hal/ports/MSP430X/platform.mk b/os/hal/ports/MSP430X/platform.mk new file mode 100644 index 0000000..b0f256e --- /dev/null +++ b/os/hal/ports/MSP430X/platform.mk @@ -0,0 +1,8 @@ +# List of all the MSP430X platform files. +PLATFORMSRC = ${CHIBIOS_CONTRIB}/os/hal/ports/MSP430X/hal_lld.c \ + ${CHIBIOS_CONTRIB}/os/hal/ports/MSP430X/hal_st_lld.c \ + ${CHIBIOS_CONTRIB}/os/hal/ports/MSP430X/hal_serial_lld.c \ + ${CHIBIOS_CONTRIB}/os/hal/ports/MSP430X/hal_pal_lld.c + +# Required include directories +PLATFORMINC = ${CHIBIOS_CONTRIB}/os/hal/ports/MSP430X -- cgit v1.2.3 From 62ffe525e0e399f6ca821be9272b4f57aca8009c Mon Sep 17 00:00:00 2001 From: Jonathan Struebel Date: Fri, 8 Apr 2016 19:15:52 -0700 Subject: [KINETIS] Fix I2C TX to not wait for RX if requested rxbytes is 0 --- os/hal/ports/KINETIS/LLD/hal_i2c_lld.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'os/hal/ports') diff --git a/os/hal/ports/KINETIS/LLD/hal_i2c_lld.c b/os/hal/ports/KINETIS/LLD/hal_i2c_lld.c index 3659a93..1095737 100644 --- a/os/hal/ports/KINETIS/LLD/hal_i2c_lld.c +++ b/os/hal/ports/KINETIS/LLD/hal_i2c_lld.c @@ -330,7 +330,7 @@ static inline msg_t _i2c_txrx_timeout(I2CDriver *i2cp, i2caddr_t addr, //if (i2cp->i2c->S & I2Cx_S_RXAK) // i2cp->errors |= I2C_ACK_FAILURE; - if (msg == MSG_OK && txbuf != NULL && rxbuf != NULL) { + if (msg == MSG_OK && txbuf != NULL && rxbuf != NULL && rxbytes > 0) { i2cp->i2c->C1 |= I2Cx_C1_RSTA; /* FIXME */ while (!(i2cp->i2c->S & I2Cx_S_BUSY)); -- cgit v1.2.3