diff --git a/targets/TARGET_STM/TARGET_STM32L5/PeripheralNames.h b/targets/TARGET_STM/TARGET_STM32L5/PeripheralNames.h new file mode 100644 index 0000000000..135f4817bf --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32L5/PeripheralNames.h @@ -0,0 +1,84 @@ +/* mbed Microcontroller Library + * SPDX-License-Identifier: BSD-3-Clause + ****************************************************************************** + * + * Copyright (c) 2017 STMicroelectronics. + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +#ifndef MBED_PERIPHERALNAMES_H +#define MBED_PERIPHERALNAMES_H + +#include "cmsis.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + ADC_1 = (int)ADC1_BASE, + ADC_2 = (int)ADC2_BASE +} ADCName; + +typedef enum { + DAC_1 = (int)DAC_BASE +} DACName; + +typedef enum { + UART_1 = (int)USART1_BASE, + UART_2 = (int)USART2_BASE, + UART_3 = (int)USART3_BASE, + UART_4 = (int)UART4_BASE, + UART_5 = (int)UART5_BASE, + LPUART_1 = (int)LPUART1_BASE +} UARTName; + +typedef enum { + SPI_1 = (int)SPI1_BASE, + SPI_2 = (int)SPI2_BASE, + SPI_3 = (int)SPI3_BASE +} SPIName; + +typedef enum { + I2C_1 = (int)I2C1_BASE, + I2C_2 = (int)I2C2_BASE, + I2C_3 = (int)I2C3_BASE, + I2C_4 = (int)I2C4_BASE +} I2CName; + +typedef enum { + PWM_1 = (int)TIM1_BASE, + PWM_2 = (int)TIM2_BASE, + PWM_3 = (int)TIM3_BASE, + PWM_4 = (int)TIM4_BASE, + PWM_5 = (int)TIM5_BASE, + PWM_8 = (int)TIM8_BASE, + PWM_15 = (int)TIM15_BASE, + PWM_16 = (int)TIM16_BASE, + PWM_17 = (int)TIM17_BASE +} PWMName; + +typedef enum { + CAN_1 = (int)FDCAN1_BASE +} CANName; + +typedef enum { + QSPI_1 = (int)OCTOSPI1_R_BASE +} QSPIName; + +typedef enum { + USB_FS = (int)USB_BASE, +} USBName; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/targets/TARGET_STM/TARGET_STM32L5/analogin_device.c b/targets/TARGET_STM/TARGET_STM32L5/analogin_device.c new file mode 100644 index 0000000000..5cda3b289a --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32L5/analogin_device.c @@ -0,0 +1,207 @@ +/* mbed Microcontroller Library + * SPDX-License-Identifier: BSD-3-Clause + ****************************************************************************** + * + * Copyright (c) 2015 STMicroelectronics. + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +#include "mbed_assert.h" +#include "analogin_api.h" + +#if DEVICE_ANALOGIN + +#include "mbed_wait_api.h" +#include "cmsis.h" +#include "pinmap.h" +#include "mbed_error.h" +#include "PeripheralPins.h" + +#if STATIC_PINMAP_READY +#define ANALOGIN_INIT_DIRECT analogin_init_direct +void analogin_init_direct(analogin_t *obj, const PinMap *pinmap) +#else +#define ANALOGIN_INIT_DIRECT _analogin_init_direct +static void _analogin_init_direct(analogin_t *obj, const PinMap *pinmap) +#endif +{ + uint32_t function = (uint32_t)pinmap->function; + + // Get the peripheral name from the pin and assign it to the object + obj->handle.Instance = (ADC_TypeDef *)pinmap->peripheral; + + // ADC Internal Channels "pins" (Temperature, Vref, Vbat, ...) + // are described in PinNames.h and PeripheralPins.c + // Pin value must be between 0xF0 and 0xFF + if ((pinmap->pin < 0xF0) || (pinmap->pin >= 0x100)) { + // Configure GPIO + pin_function(pinmap->pin, pinmap->function); + pin_mode(pinmap->pin, PullNone); + } else { + // Internal channels + // No GPIO configuration for internal channels + } + MBED_ASSERT(obj->handle.Instance != (ADC_TypeDef *)NC); + MBED_ASSERT(function != (uint32_t)NC); + + obj->channel = STM_PIN_CHANNEL(function); + + // Save pin number for the read function + obj->pin = pinmap->pin; + + // Configure ADC object structures + obj->handle.State = HAL_ADC_STATE_RESET; + obj->handle.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2; // Asynchronous clock mode, input ADC clock + obj->handle.Init.Resolution = ADC_RESOLUTION_12B; + obj->handle.Init.DataAlign = ADC_DATAALIGN_RIGHT; + obj->handle.Init.ScanConvMode = DISABLE; // Sequencer disabled (ADC conversion on only 1 channel: channel set on rank 1) + obj->handle.Init.EOCSelection = ADC_EOC_SINGLE_CONV; // On STM32L1xx ADC, overrun detection is enabled only if EOC selection is set to each conversion (or transfer by DMA enabled, this is not the case in this example). + obj->handle.Init.LowPowerAutoWait = DISABLE; + obj->handle.Init.ContinuousConvMode = DISABLE; // Continuous mode disabled to have only 1 conversion at each conversion trig + obj->handle.Init.NbrOfConversion = 1; // Parameter discarded because sequencer is disabled + obj->handle.Init.DiscontinuousConvMode = DISABLE; // Parameter discarded because sequencer is disabled + obj->handle.Init.NbrOfDiscConversion = 1; // Parameter discarded because sequencer is disabled + obj->handle.Init.ExternalTrigConv = ADC_SOFTWARE_START; // Software start to trig the 1st conversion manually, without external event + obj->handle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; + obj->handle.Init.DMAContinuousRequests = DISABLE; + obj->handle.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN; // DR register is overwritten with the last conversion result in case of overrun + obj->handle.Init.OversamplingMode = DISABLE; // No oversampling +#if defined(ADC_CFGR_DFSDMCFG) &&defined(DFSDM1_Channel0) + obj->handle.Init.DFSDMConfig = 0; +#endif + + // Enable ADC clock + __HAL_RCC_ADC_CLK_ENABLE(); + __HAL_RCC_ADC_CONFIG(RCC_ADCCLKSOURCE_SYSCLK); + + if (HAL_ADC_Init(&obj->handle) != HAL_OK) { + error("Cannot initialize ADC\n"); + } + + // ADC calibration is done only once + if (!HAL_ADCEx_Calibration_GetValue(&obj->handle, ADC_SINGLE_ENDED)) { + HAL_ADCEx_Calibration_Start(&obj->handle, ADC_SINGLE_ENDED); + } +} + +void analogin_init(analogin_t *obj, PinName pin) +{ + int peripheral; + int function; + + if ((pin < 0xF0) || (pin >= 0x100)) { + peripheral = (int)pinmap_peripheral(pin, PinMap_ADC); + function = (int)pinmap_find_function(pin, PinMap_ADC); + } else { + peripheral = (int)pinmap_peripheral(pin, PinMap_ADC_Internal); + function = (int)pinmap_find_function(pin, PinMap_ADC_Internal); + } + + const PinMap static_pinmap = {pin, peripheral, function}; + + ANALOGIN_INIT_DIRECT(obj, &static_pinmap); +} + + +uint16_t adc_read(analogin_t *obj) +{ + ADC_ChannelConfTypeDef sConfig = {0}; + + // Configure ADC channel + sConfig.Rank = ADC_REGULAR_RANK_1; + sConfig.SamplingTime = ADC_SAMPLETIME_47CYCLES_5; // default value (1.5 us for 80MHz clock) + sConfig.SingleDiff = ADC_SINGLE_ENDED; + sConfig.OffsetNumber = ADC_OFFSET_NONE; + sConfig.Offset = 0; + + switch (obj->channel) { + case 0: + sConfig.Channel = ADC_CHANNEL_VREFINT; + sConfig.SamplingTime = ADC_SAMPLETIME_247CYCLES_5; // Minimum ADC sampling time when reading the internal reference voltage is 4us + break; + case 1: + sConfig.Channel = ADC_CHANNEL_1; + break; + case 2: + sConfig.Channel = ADC_CHANNEL_2; + break; + case 3: + sConfig.Channel = ADC_CHANNEL_3; + break; + case 4: + sConfig.Channel = ADC_CHANNEL_4; + break; + case 5: + sConfig.Channel = ADC_CHANNEL_5; + break; + case 6: + sConfig.Channel = ADC_CHANNEL_6; + break; + case 7: + sConfig.Channel = ADC_CHANNEL_7; + break; + case 8: + sConfig.Channel = ADC_CHANNEL_8; + break; + case 9: + sConfig.Channel = ADC_CHANNEL_9; + break; + case 10: + sConfig.Channel = ADC_CHANNEL_10; + break; + case 11: + sConfig.Channel = ADC_CHANNEL_11; + break; + case 12: + sConfig.Channel = ADC_CHANNEL_12; + break; + case 13: + sConfig.Channel = ADC_CHANNEL_13; + break; + case 14: + sConfig.Channel = ADC_CHANNEL_14; + break; + case 15: + sConfig.Channel = ADC_CHANNEL_15; + break; + case 16: + sConfig.Channel = ADC_CHANNEL_16; + break; + case 17: + sConfig.Channel = ADC_CHANNEL_TEMPSENSOR; + sConfig.SamplingTime = ADC_SAMPLETIME_247CYCLES_5; // Minimum ADC sampling time when reading the temperature is 5us + break; + case 18: + sConfig.Channel = ADC_CHANNEL_VBAT; + sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5; // Minimum ADC sampling time when reading the VBAT is 12us + break; + default: + return 0; + } + + HAL_ADC_ConfigChannel(&obj->handle, &sConfig); + + HAL_ADC_Start(&obj->handle); // Start conversion + + // Wait end of conversion and get value + uint16_t adcValue = 0; + if (HAL_ADC_PollForConversion(&obj->handle, 10) == HAL_OK) { + adcValue = (uint16_t)HAL_ADC_GetValue(&obj->handle); + } + LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE((&obj->handle)->Instance), LL_ADC_PATH_INTERNAL_NONE); + return adcValue; +} + +const PinMap *analogin_pinmap() +{ + return PinMap_ADC; +} + +#endif diff --git a/targets/TARGET_STM/TARGET_STM32L5/analogout_device.c b/targets/TARGET_STM/TARGET_STM32L5/analogout_device.c new file mode 100644 index 0000000000..f085620fce --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32L5/analogout_device.c @@ -0,0 +1,136 @@ +/* mbed Microcontroller Library + * SPDX-License-Identifier: BSD-3-Clause + ****************************************************************************** + * + * Copyright (c) 2015 STMicroelectronics. + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +#include "mbed_assert.h" +#include "analogout_api.h" + +#if DEVICE_ANALOGOUT + +#include "cmsis.h" +#include "pinmap.h" +#include "mbed_error.h" +#include "PeripheralPins.h" + +// These variables are used for the "free" function +static int channel1_used = 0; +static int channel2_used = 0; + +#if STATIC_PINMAP_READY +#define ANALOGOUT_INIT_DIRECT analogout_init_direct +void analogout_init_direct(dac_t *obj, const PinMap *pinmap) +#else +#define ANALOGOUT_INIT_DIRECT _analogout_init_direct +static void _analogout_init_direct(dac_t *obj, const PinMap *pinmap) +#endif +{ + DAC_ChannelConfTypeDef sConfig = {0}; + + // Get the peripheral name from the pin and assign it to the object + obj->dac = (DACName)pinmap->peripheral; + MBED_ASSERT(obj->dac != (DACName)NC); + + // Get the pin function and assign the used channel to the object + uint32_t function = (uint32_t)pinmap->function; + MBED_ASSERT(function != (uint32_t)NC); + + switch (STM_PIN_CHANNEL(function)) { + case 1: + obj->channel = DAC_CHANNEL_1; + break; +#if defined(DAC_CHANNEL_2) + case 2: + obj->channel = DAC_CHANNEL_2; + break; +#endif + default: + error("Unknown DAC channel"); + break; + } + + // Configure GPIO + pin_function(pinmap->pin, pinmap->function); + pin_mode(pinmap->pin, PullNone); + + // Save the pin for future use + obj->pin = pinmap->pin; + + // Enable DAC clock + __HAL_RCC_DAC1_CLK_ENABLE(); + + // Configure DAC + obj->handle.Instance = DAC; + obj->handle.State = HAL_DAC_STATE_RESET; + + if (HAL_DAC_Init(&obj->handle) != HAL_OK) { + error("HAL_DAC_Init failed"); + } + + sConfig.DAC_SampleAndHold = DAC_SAMPLEANDHOLD_DISABLE; + sConfig.DAC_Trigger = DAC_TRIGGER_NONE; + sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; + sConfig.DAC_ConnectOnChipPeripheral = DAC_CHIPCONNECT_DISABLE; + sConfig.DAC_UserTrimming = DAC_TRIMMING_FACTORY; + + if (obj->channel == DAC_CHANNEL_1) { + channel1_used = 1; + } else { // channel 1 per default + channel2_used = 1; + } + + if (HAL_DAC_ConfigChannel(&obj->handle, &sConfig, obj->channel) != HAL_OK) { + error("Cannot configure DAC channel\n"); + } + + analogout_write_u16(obj, 0); +} + +void analogout_init(dac_t *obj, PinName pin) +{ + int peripheral = (int)pinmap_peripheral(pin, PinMap_DAC); + int function = (int)pinmap_find_function(pin, PinMap_DAC); + + const PinMap static_pinmap = {pin, peripheral, function}; + + ANALOGOUT_INIT_DIRECT(obj, &static_pinmap); +} + +void analogout_free(dac_t *obj) +{ + // Reset DAC and disable clock + if (obj->channel == DAC_CHANNEL_1) { + channel1_used = 0; + } +#if defined(DAC_CHANNEL_2) + if (obj->channel == DAC_CHANNEL_2) { + channel2_used = 0; + } +#endif + + if ((channel1_used == 0) && (channel2_used == 0)) { + __HAL_RCC_DAC1_FORCE_RESET(); + __HAL_RCC_DAC1_RELEASE_RESET(); + __HAL_RCC_DAC1_CLK_DISABLE(); + } + + // Configure GPIO + pin_function(obj->pin, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0)); +} + +const PinMap *analogout_pinmap() +{ + return PinMap_DAC; +} + +#endif // DEVICE_ANALOGOUT diff --git a/targets/TARGET_STM/TARGET_STM32L5/can_device.h b/targets/TARGET_STM/TARGET_STM32L5/can_device.h new file mode 100644 index 0000000000..357b6ec561 --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32L5/can_device.h @@ -0,0 +1,42 @@ +/* mbed Microcontroller Library + * SPDX-License-Identifier: BSD-3-Clause + ****************************************************************************** + * + * Copyright (c) 2017 STMicroelectronics. + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +#ifndef MBED_CAN_DEVICE_H +#define MBED_CAN_DEVICE_H + +#include "cmsis.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if DEVICE_CAN + +#define CAN_NUM 1 // Number of CAN peripherals present in the STM32 serie + +#define CAN1_IRQ_RX_IRQN CAN1_RX0_IRQn +#define CAN1_IRQ_RX_VECT CAN1_RX0_IRQHandler +#define CAN1_IRQ_TX_IRQN CAN1_TX_IRQn +#define CAN1_IRQ_TX_VECT CAN1_TX_IRQHandler +#define CAN1_IRQ_ERROR_IRQN CAN1_SCE_IRQn +#define CAN1_IRQ_ERROR_VECT CAN1_SCE_IRQHandler +#define CAN1_IRQ_PASSIVE_IRQN CAN1_SCE_IRQn +#define CAN1_IRQ_PASSIVE_VECT CAN1_SCE_IRQHandler +#define CAN1_IRQ_BUS_IRQN CAN1_SCE_IRQn +#define CAN1_IRQ_BUS_VECT CAN1_SCE_IRQHandler + +#endif // DEVICE_CAN + +#endif diff --git a/targets/TARGET_STM/TARGET_STM32L5/cmsis.h b/targets/TARGET_STM/TARGET_STM32L5/cmsis.h new file mode 100644 index 0000000000..eebdb7fb3d --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32L5/cmsis.h @@ -0,0 +1,22 @@ +/* mbed Microcontroller Library + * SPDX-License-Identifier: BSD-3-Clause + ****************************************************************************** + * + * Copyright (c) 2017 STMicroelectronics. + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +#ifndef MBED_CMSIS_H +#define MBED_CMSIS_H + +#include "stm32l5xx.h" +#include "cmsis_nvic.h" + +#endif diff --git a/targets/TARGET_STM/TARGET_STM32L5/flash_api.c b/targets/TARGET_STM/TARGET_STM32L5/flash_api.c new file mode 100644 index 0000000000..e8a9eba0d0 --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32L5/flash_api.c @@ -0,0 +1,299 @@ +/* mbed Microcontroller Library + * SPDX-License-Identifier: BSD-3-Clause + ****************************************************************************** + * + * Copyright (c) 2017 STMicroelectronics. + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +#include "flash_api.h" + +#if DEVICE_FLASH + + +/** + * @brief Gets the page of a given address + * @param Addr: Address of the FLASH Memory + * @retval The page of a given address + */ +static uint32_t GetPage(uint32_t Addr) +{ + uint32_t page = 0; + + if (READ_BIT(FLASH->OPTR, FLASH_OPTR_DBANK) != 0U) { + if (Addr < (FLASH_BASE + FLASH_BANK_SIZE)) { + /* Bank 1 */ + page = (Addr - FLASH_BASE) / FLASH_PAGE_SIZE; + } else { + /* Bank 2 */ + page = (Addr - (FLASH_BASE + FLASH_BANK_SIZE)) / FLASH_PAGE_SIZE; + } + } else { + page = (Addr - FLASH_BASE) / FLASH_PAGE_SIZE_128_BITS; + } + + return page; +} + +/** + * @brief Gets the bank of a given address + * @param Addr: Address of the FLASH Memory + * @retval The bank of a given address + */ +static uint32_t GetBank(uint32_t Addr) +{ + uint32_t bank = 0; + + if (READ_BIT(FLASH->OPTR, FLASH_OPTR_DBANK) != 0U) { + if (Addr < (FLASH_BASE + FLASH_BANK_SIZE)) { + bank = FLASH_BANK_1; + } else { + bank = FLASH_BANK_2; + } + } else { + bank = FLASH_BANK_1; + } + + return bank; +} + +/** Initialize the flash peripheral and the flash_t object + * + * @param obj The flash object + * @return 0 for success, -1 for error + */ +int32_t flash_init(flash_t *obj) +{ +#ifdef TARGET_TFM +/* TFM implementation needs dual bank configuration */ + if (READ_BIT(FLASH->OPTR, FLASH_OPTR_DBANK) != 0U) { + return 0; + } else { + return -1; + } +#else + return 0; +#endif +} + +/** Uninitialize the flash peripheral and the flash_t object + * + * @param obj The flash object + * @return 0 for success, -1 for error + */ +int32_t flash_free(flash_t *obj) +{ + return 0; +} + +static int32_t flash_unlock(void) +{ + /* Allow Access to Flash control registers and user Falsh */ + if (HAL_FLASH_Unlock()) { + return -1; + } else { + return 0; + } +} + +static int32_t flash_lock(void) +{ + /* Disable the Flash option control register access (recommended to protect + the option Bytes against possible unwanted operations) */ + if (HAL_FLASH_Lock()) { + return -1; + } else { + return 0; + } +} + +/** Erase one sector starting at defined address + * + * The address should be at sector boundary. This function does not do any check for address alignments + * @param obj The flash object + * @param address The sector starting address + * @return 0 for success, -1 for error + */ +int32_t flash_erase_sector(flash_t *obj, uint32_t address) +{ + uint32_t FirstPage = 0, BankNumber = 0; + uint32_t PAGEError = 0; + FLASH_EraseInitTypeDef EraseInitStruct; + + if ((address >= (flash_get_start_address(obj) + flash_get_size(obj))) || (address < flash_get_start_address(obj))) { + return -1; + } + + if (flash_unlock() != HAL_OK) { + return -1; + } + + /* Clear error programming flags */ + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS); + + /* Get the 1st page to erase */ + FirstPage = GetPage(address); + /* MBED HAL erases 1 page / sector at a time */ + /* Get the bank */ + BankNumber = GetBank(address); + + /* Fill EraseInit structure*/ + EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; + EraseInitStruct.Banks = BankNumber; + EraseInitStruct.Page = FirstPage; + EraseInitStruct.NbPages = 1; + + if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK) { + return -1; + } + + if (flash_lock() != HAL_OK) { + return -1; + } + + return 0; +} + +/** Program one page starting at defined address + * + * The page should be at page boundary, should not cross multiple sectors. + * This function does not do any check for address alignments or if size + * is aligned to a page size. + * @param obj The flash object + * @param address The sector starting address + * @param data The data buffer to be programmed + * @param size The number of bytes to program + * @return 0 for success, -1 for error + */ +int32_t flash_program_page(flash_t *obj, uint32_t address, + const uint8_t *data, uint32_t size) +{ + uint32_t StartAddress = 0; + int32_t status = 0; + if ((address >= (flash_get_start_address(obj) + flash_get_size(obj))) || (address < flash_get_start_address(obj))) { + return -1; + } + + if ((size % 8) != 0) { + /* L4 flash devices can only be programmed 64bits/8 bytes at a time */ + return -1; + } + + if (flash_unlock() != HAL_OK) { + return -1; + } + + /* Clear error programming flags */ + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS); + + /* Program the user Flash area word by word */ + StartAddress = address; + + /* HW needs an aligned address to program flash, which data + * parameters doesn't ensure */ + if ((uint32_t) data % 4 != 0) { + volatile uint64_t data64; + while ((address < (StartAddress + size)) && (status == 0)) { + for (uint8_t i = 0; i < 8; i++) { + *(((uint8_t *) &data64) + i) = *(data + i); + } + + if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, address, data64) + == HAL_OK) { + address = address + 8; + data = data + 8; + } else { + status = -1; + } + } + } else { /* case where data is aligned, so let's avoid any copy */ + while ((address < (StartAddress + size)) && (status == 0)) { + if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, address, + *((uint64_t *) data)) + == HAL_OK) { + address = address + 8; + data = data + 8; + } else { + status = -1; + } + } + } + + status = flash_unlock(); + + return status; +} + +/** Get sector size + * + * @param obj The flash object + * @param address The sector starting address + * @return The size of a sector + */ +uint32_t flash_get_sector_size(const flash_t *obj, uint32_t address) +{ + if ((address >= (flash_get_start_address(obj) + flash_get_size(obj))) || (address < flash_get_start_address(obj))) { + return MBED_FLASH_INVALID_SIZE; + } else { + if (READ_BIT(FLASH->OPTR, FLASH_OPTR_DBANK) != 0U) { + return FLASH_PAGE_SIZE; + } else { + return FLASH_PAGE_SIZE_128_BITS; + } + } +} + +/** Get page size + * + * @param obj The flash object + * @return The size of a page + */ +uint32_t flash_get_page_size(const flash_t *obj) +{ + /* Page size is the minimum programable size, which 8 bytes */ + return 8; +} + +/** Get start address for the flash region + * + * @param obj The flash object + * @return The start address for the flash region + */ +uint32_t flash_get_start_address(const flash_t *obj) +{ +#if (DOMAIN_NS == 1) + return NS_CODE_START; +#else + return FLASH_BASE; +#endif +} + +/** Get the flash region size + * + * @param obj The flash object + * @return The flash region size + */ +uint32_t flash_get_size(const flash_t *obj) +{ +#if (DOMAIN_NS == 1) + return NS_CODE_SIZE; +#else + return FLASH_SIZE; +#endif +} + +uint8_t flash_get_erase_value(const flash_t *obj) +{ + (void)obj; + + return 0xFF; +} + +#endif diff --git a/targets/TARGET_STM/TARGET_STM32L5/gpio_irq_device.c b/targets/TARGET_STM/TARGET_STM32L5/gpio_irq_device.c new file mode 100644 index 0000000000..ef6a579e62 --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32L5/gpio_irq_device.c @@ -0,0 +1,53 @@ +/* mbed Microcontroller Library + * SPDX-License-Identifier: BSD-3-Clause + ****************************************************************************** + * + * Copyright (c) 2017 STMicroelectronics. + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +#include "cmsis.h" +#include "gpio_irq_device.h" + +// Used to return the index for channels array. +const exti_lines_t pin_lines_desc[16] = { + // EXTI0 + {.gpio_idx = 0, .irq_index = 0, .irq_n = EXTI0_IRQn}, // pin 0 + // EXTI1 + {.gpio_idx = 0, .irq_index = 1, .irq_n = EXTI1_IRQn}, // pin 1 + // EXTI2 + {.gpio_idx = 0, .irq_index = 2, .irq_n = EXTI2_IRQn}, // pin 2 + // EXTI3 + {.gpio_idx = 0, .irq_index = 3, .irq_n = EXTI3_IRQn}, // pin 3 + // EXTI4 + {.gpio_idx = 0, .irq_index = 4, .irq_n = EXTI4_IRQn}, // pin 4 + // EXTI5 + {.gpio_idx = 0, .irq_index = 5, .irq_n = EXTI5_IRQn}, // pin 5 + // EXTI6 + {.gpio_idx = 0, .irq_index = 6, .irq_n = EXTI6_IRQn}, // pin 6 + // EXTI7 + {.gpio_idx = 0, .irq_index = 7, .irq_n = EXTI7_IRQn}, // pin 7 + // EXTI8 + {.gpio_idx = 0, .irq_index = 8, .irq_n = EXTI8_IRQn}, // pin 8 + // EXTI9 + {.gpio_idx = 0, .irq_index = 9, .irq_n = EXTI9_IRQn}, // pin 9 + // EXTI10 + {.gpio_idx = 0, .irq_index = 10, .irq_n = EXTI10_IRQn}, // pin 10 + // EXTI11 + {.gpio_idx = 0, .irq_index = 11, .irq_n = EXTI11_IRQn}, // pin 11 + // EXTI12 + {.gpio_idx = 0, .irq_index = 12, .irq_n = EXTI12_IRQn}, // pin 12 + // EXTI13 + {.gpio_idx = 0, .irq_index = 13, .irq_n = EXTI13_IRQn}, // pin 13 + // EXTI14 + {.gpio_idx = 0, .irq_index = 14, .irq_n = EXTI14_IRQn}, // pin 14 + // EXTI15 + {.gpio_idx = 0, .irq_index = 15, .irq_n = EXTI15_IRQn}, // pin 15 +}; diff --git a/targets/TARGET_STM/TARGET_STM32L5/gpio_irq_device.h b/targets/TARGET_STM/TARGET_STM32L5/gpio_irq_device.h new file mode 100644 index 0000000000..2db2143a76 --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32L5/gpio_irq_device.h @@ -0,0 +1,62 @@ +/* mbed Microcontroller Library + * SPDX-License-Identifier: BSD-3-Clause + ****************************************************************************** + * + * Copyright (c) 2017 STMicroelectronics. + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +#ifndef MBED_GPIO_IRQ_DEVICE_H +#define MBED_GPIO_IRQ_DEVICE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stm32l5xx_ll_exti.h" + +// Number of EXTI irq vectors (EXTI0 to EXTI15) +#define CHANNEL_NUM (16) + +#define EXTI_IRQ0_NUM_LINES 1 +#define EXTI_IRQ1_NUM_LINES 1 +#define EXTI_IRQ2_NUM_LINES 1 +#define EXTI_IRQ3_NUM_LINES 1 +#define EXTI_IRQ4_NUM_LINES 1 +#define EXTI_IRQ5_NUM_LINES 1 +#define EXTI_IRQ6_NUM_LINES 1 +#define EXTI_IRQ7_NUM_LINES 1 +#define EXTI_IRQ8_NUM_LINES 1 +#define EXTI_IRQ9_NUM_LINES 1 +#define EXTI_IRQ10_NUM_LINES 1 +#define EXTI_IRQ11_NUM_LINES 1 +#define EXTI_IRQ12_NUM_LINES 1 +#define EXTI_IRQ13_NUM_LINES 1 +#define EXTI_IRQ14_NUM_LINES 1 +#define EXTI_IRQ15_NUM_LINES 1 + +// Max pins for one line +#define MAX_PIN_LINE (1) + +/* Structure to describe how the HW EXTI lines are defined in this HW */ +typedef struct exti_lines { + uint32_t gpio_idx; // an index entry for each EXIT line + uint32_t irq_index; // the IRQ index + IRQn_Type irq_n; // the corresponding EXTI IRQn +} exti_lines_t; + +// Used to return the index for channels array. +extern const exti_lines_t pin_lines_desc[]; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/targets/TARGET_STM/TARGET_STM32L5/i2c_device.h b/targets/TARGET_STM/TARGET_STM32L5/i2c_device.h new file mode 100644 index 0000000000..90ee70c22f --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32L5/i2c_device.h @@ -0,0 +1,70 @@ +/* mbed Microcontroller Library + * SPDX-License-Identifier: BSD-3-Clause + ****************************************************************************** + * + * Copyright (c) 2015 STMicroelectronics. + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +#ifndef MBED_I2C_DEVICE_H +#define MBED_I2C_DEVICE_H + +#include "cmsis.h" +#include "mbed_error.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if DEVICE_I2C + +#define I2C_IP_VERSION_V2 + +#define I2C_IT_ALL (I2C_IT_ERRI|I2C_IT_TCI|I2C_IT_STOPI|I2C_IT_NACKI|I2C_IT_ADDRI|I2C_IT_RXI|I2C_IT_TXI) + +/* Family specifc settings for clock source */ +#define I2CAPI_I2C1_CLKSRC RCC_I2C1CLKSOURCE_SYSCLK +#define I2CAPI_I2C2_CLKSRC RCC_I2C2CLKSOURCE_SYSCLK +#define I2CAPI_I2C3_CLKSRC RCC_I2C3CLKSOURCE_SYSCLK +#define I2CAPI_I2C4_CLKSRC RCC_I2C4CLKSOURCE_SYSCLK + +/* Provide the suitable timing depending on requested frequencie */ +static inline uint32_t get_i2c_timing(int hz) +{ + uint32_t tim = 0; + if (SystemCoreClock == 110000000) { + // Common settings: I2C clock = 80 MHz, Analog filter = ON, Digital filter coefficient = 0 + switch (hz) { + case 100000: + tim = 0x40E15676; // Standard mode with Rise Time = 400ns and Fall Time = 100ns + break; + case 400000: + tim = 0x20C11434; // Fast mode with Rise Time = 250ns and Fall Time = 100ns + break; + case 1000000: + tim = 0x00C31536; // Fast mode Plus with Rise Time = 60ns and Fall Time = 100ns + break; + default: + break; + } + } + else { + error("Value not provided for SystemCoreClock %u\n", SystemCoreClock); + } + return tim; +} + +#ifdef __cplusplus +} +#endif + +#endif // DEVICE_I2C + +#endif diff --git a/targets/TARGET_STM/TARGET_STM32L5/objects.h b/targets/TARGET_STM/TARGET_STM32L5/objects.h new file mode 100644 index 0000000000..91d8a246f7 --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32L5/objects.h @@ -0,0 +1,162 @@ +/* mbed Microcontroller Library + * SPDX-License-Identifier: BSD-3-Clause + ****************************************************************************** + * + * Copyright (c) 2015 STMicroelectronics. + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +#ifndef MBED_OBJECTS_H +#define MBED_OBJECTS_H + +#include "cmsis.h" +#include "PortNames.h" +#include "PeripheralNames.h" +#include "PinNames.h" +#include "stm32l5xx_ll_usart.h" +#include "stm32l5xx_ll_lpuart.h" +#include "stm32l5xx_ll_tim.h" +#include "stm32l5xx_ll_rtc.h" +#include "stm32l5xx_ll_pwr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define RTC_WKUP_IRQn RTC_IRQn + +#define HAL_CRC_IS_SUPPORTED(polynomial, width) ((width) == 7 || (width) == 8 || (width) == 16 || (width) == 32) + +struct gpio_irq_s { + IRQn_Type irq_n; + uint32_t irq_index; + uint32_t event; + PinName pin; +}; + +struct port_s { + PortName port; + uint32_t mask; + PinDirection direction; + __IO uint32_t *reg_in; + __IO uint32_t *reg_out; +}; + +struct trng_s { + RNG_HandleTypeDef handle; +}; + +struct pwmout_s { + PWMName pwm; + PinName pin; + uint32_t prescaler; + uint32_t period; + uint32_t pulse; + uint8_t channel; + uint8_t inverted; +}; + +struct spi_s { + SPI_HandleTypeDef handle; + IRQn_Type spiIRQ; + SPIName spi; + PinName pin_miso; + PinName pin_mosi; + PinName pin_sclk; + PinName pin_ssel; +#if DEVICE_SPI_ASYNCH + uint32_t event; + uint8_t transfer_type; +#endif +}; + +struct serial_s { + UARTName uart; + int index; // Used by irq + uint32_t baudrate; + uint32_t databits; + uint32_t stopbits; + uint32_t parity; + PinName pin_tx; + PinName pin_rx; +#if DEVICE_SERIAL_ASYNCH + uint32_t events; +#endif +#if DEVICE_SERIAL_FC + uint32_t hw_flow_ctl; + PinName pin_rts; + PinName pin_cts; +#endif +}; + +struct i2c_s { + /* The 1st 2 members I2CName i2c + * and I2C_HandleTypeDef handle should + * be kept as the first members of this struct + * to ensure i2c_get_obj to work as expected + */ + I2CName i2c; + I2C_HandleTypeDef handle; + uint8_t index; + int hz; + PinName sda; + PinName scl; + IRQn_Type event_i2cIRQ; + IRQn_Type error_i2cIRQ; + uint32_t XferOperation; + volatile uint8_t event; + volatile int pending_start; +#if DEVICE_I2CSLAVE + uint8_t slave; + volatile uint8_t pending_slave_tx_master_rx; + volatile uint8_t pending_slave_rx_maxter_tx; +#endif +#if DEVICE_I2C_ASYNCH + uint32_t address; + uint8_t stop; + uint8_t available_events; +#endif +}; + +struct flash_s { + /* nothing to be stored for now */ + uint32_t dummy; +}; + +struct analogin_s { + ADC_HandleTypeDef handle; + PinName pin; + uint8_t channel; +}; + +#include "gpio_object.h" + +#if DEVICE_ANALOGOUT +struct dac_s { + DACName dac; + PinName pin; + uint32_t channel; + DAC_HandleTypeDef handle; +}; +#endif + +#if DEVICE_CAN +struct can_s { + CAN_HandleTypeDef CanHandle; + int index; + int hz; +}; +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/targets/TARGET_STM/TARGET_STM32L5/pin_device.h b/targets/TARGET_STM/TARGET_STM32L5/pin_device.h new file mode 100644 index 0000000000..9ea12edca7 --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32L5/pin_device.h @@ -0,0 +1,56 @@ +/* mbed Microcontroller Library + * SPDX-License-Identifier: BSD-3-Clause + ****************************************************************************** + * + * Copyright (c) 2015 STMicroelectronics. + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +#ifndef MBED_PIN_DEVICE_H +#define MBED_PIN_DEVICE_H + +#include "cmsis.h" +#include "stm32l5xx_ll_gpio.h" + +extern const uint32_t ll_pin_defines[16]; + +/* Family specific implementations */ +static inline void stm_pin_DisconnectDebug(PinName pin) +{ + /* empty for now */ +} + +static inline void stm_pin_PullConfig(GPIO_TypeDef *gpio, uint32_t ll_pin, uint32_t pull_config) +{ + switch (pull_config) { + case GPIO_PULLUP: + LL_GPIO_SetPinPull(gpio, ll_pin, LL_GPIO_PULL_UP); + break; + case GPIO_PULLDOWN: + LL_GPIO_SetPinPull(gpio, ll_pin, LL_GPIO_PULL_DOWN); + break; + default: + LL_GPIO_SetPinPull(gpio, ll_pin, LL_GPIO_PULL_NO); + break; + } +} + +static inline void stm_pin_SetAFPin(GPIO_TypeDef *gpio, PinName pin, uint32_t afnum) +{ + uint32_t ll_pin = ll_pin_defines[STM_PIN(pin)]; + + if (STM_PIN(pin) > 7) { + LL_GPIO_SetAFPin_8_15(gpio, ll_pin, afnum); + } else { + LL_GPIO_SetAFPin_0_7(gpio, ll_pin, afnum); + } +} + +#endif diff --git a/targets/TARGET_STM/TARGET_STM32L5/pwmout_device.c b/targets/TARGET_STM/TARGET_STM32L5/pwmout_device.c new file mode 100644 index 0000000000..ac07e38937 --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32L5/pwmout_device.c @@ -0,0 +1,53 @@ +/* mbed Microcontroller Library + * SPDX-License-Identifier: BSD-3-Clause + ****************************************************************************** + * + * Copyright (c) 2017 STMicroelectronics. + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +#include "cmsis.h" +#include "pwmout_api.h" +#include "pwmout_device.h" + +#if DEVICE_PWMOUT + +const pwm_apb_map_t pwm_apb_map_table[] = { +#if defined(TIM2_BASE) + {PWM_2, PWMOUT_ON_APB1}, +#endif +#if defined(TIM3_BASE) + {PWM_3, PWMOUT_ON_APB1}, +#endif +#if defined(TIM4_BASE) + {PWM_4, PWMOUT_ON_APB1}, +#endif +#if defined(TIM5_BASE) + {PWM_5, PWMOUT_ON_APB1}, +#endif +#if defined(TIM1_BASE) + {PWM_1, PWMOUT_ON_APB2}, +#endif +#if defined(TIM8_BASE) + {PWM_8, PWMOUT_ON_APB2}, +#endif +#if defined(TIM15_BASE) + {PWM_15, PWMOUT_ON_APB2}, +#endif +#if defined(TIM16_BASE) + {PWM_16, PWMOUT_ON_APB2}, +#endif +#if defined(TIM17_BASE) + {PWM_17, PWMOUT_ON_APB2}, +#endif + {(PWMName) 0, PWMOUT_UNKNOWN} +}; + +#endif // DEVICE_PWMOUT diff --git a/targets/TARGET_STM/TARGET_STM32L5/pwmout_device.h b/targets/TARGET_STM/TARGET_STM32L5/pwmout_device.h new file mode 100644 index 0000000000..40dee18624 --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32L5/pwmout_device.h @@ -0,0 +1,47 @@ +/* mbed Microcontroller Library + * SPDX-License-Identifier: BSD-3-Clause + ****************************************************************************** + * + * Copyright (c) 2017 STMicroelectronics. + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +#ifndef MBED_PWMOUT_DEVICE_H +#define MBED_PWMOUT_DEVICE_H + +#include "cmsis.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if DEVICE_PWMOUT + +typedef enum { + PWMOUT_ON_APB1 = 0, + PWMOUT_ON_APB2 = 1, + PWMOUT_UNKNOWN = 2 +} PwmoutApb; + +/* Structure to describe Timers to APB */ +typedef struct pwm_apb_map { + PWMName pwm; // an index entry for each EXIT line + PwmoutApb pwmoutApb; +} pwm_apb_map_t; + +extern const pwm_apb_map_t pwm_apb_map_table[]; + +#endif // DEVICE_PWMOUT + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/targets/TARGET_STM/TARGET_STM32L5/serial_device.c b/targets/TARGET_STM/TARGET_STM32L5/serial_device.c new file mode 100644 index 0000000000..3f8ed5413b --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32L5/serial_device.c @@ -0,0 +1,722 @@ +/* mbed Microcontroller Library + * SPDX-License-Identifier: BSD-3-Clause + ****************************************************************************** + * + * Copyright (c) 2017 STMicroelectronics. + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +#if DEVICE_SERIAL + +#include "serial_api_hal.h" + +#define UART_NUM (6) // USART1, USART2, USART3, UART4, UART5, LPUART1 + +uint32_t serial_irq_ids[UART_NUM] = {0}; +UART_HandleTypeDef uart_handlers[UART_NUM]; + +static uart_irq_handler irq_handler; + +// Defined in serial_api.c +extern int8_t get_uart_index(UARTName uart_name); + +/****************************************************************************** + * INTERRUPTS HANDLING + ******************************************************************************/ + +static void uart_irq(UARTName uart_name) +{ + int8_t id = get_uart_index(uart_name); + + if (id >= 0) { + UART_HandleTypeDef *huart = &uart_handlers[id]; + if (serial_irq_ids[id] != 0) { + if (__HAL_UART_GET_FLAG(huart, UART_FLAG_TXE) != RESET) { + if (__HAL_UART_GET_IT(huart, UART_IT_TXE) != RESET && __HAL_UART_GET_IT_SOURCE(huart, UART_IT_TXE)) { + irq_handler(serial_irq_ids[id], TxIrq); + } + } + if (__HAL_UART_GET_FLAG(huart, UART_FLAG_RXNE) != RESET) { + if (__HAL_UART_GET_IT(huart, UART_IT_RXNE) != RESET && __HAL_UART_GET_IT_SOURCE(huart, UART_IT_RXNE)) { + irq_handler(serial_irq_ids[id], RxIrq); + /* Flag has been cleared when reading the content */ + } + } + if (__HAL_UART_GET_FLAG(huart, UART_FLAG_ORE) != RESET) { + if (__HAL_UART_GET_IT(huart, UART_IT_ORE) != RESET) { + __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_OREF); + } + } + } + } +} + +#if defined(USART1_BASE) +static void uart1_irq(void) +{ + uart_irq(UART_1); +} +#endif + +#if defined(USART2_BASE) +static void uart2_irq(void) +{ + uart_irq(UART_2); +} +#endif + +#if defined(USART3_BASE) +static void uart3_irq(void) +{ + uart_irq(UART_3); +} +#endif + +#if defined(UART4_BASE) +static void uart4_irq(void) +{ + uart_irq(UART_4); +} +#endif + +#if defined(UART5_BASE) +static void uart5_irq(void) +{ + uart_irq(UART_5); +} +#endif + +#if defined(LPUART1_BASE) +static void lpuart1_irq(void) +{ + uart_irq(LPUART_1); +} +#endif + +void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id) +{ + struct serial_s *obj_s = SERIAL_S(obj); + + irq_handler = handler; + serial_irq_ids[obj_s->index] = id; +} + +void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) +{ + struct serial_s *obj_s = SERIAL_S(obj); + UART_HandleTypeDef *huart = &uart_handlers[obj_s->index]; + IRQn_Type irq_n = (IRQn_Type)0; + uint32_t vector = 0; + + switch (obj_s->uart) { +#if defined(USART1_BASE) + case UART_1: + irq_n = USART1_IRQn; + vector = (uint32_t)&uart1_irq; + break; +#endif +#if defined(USART2_BASE) + case UART_2: + irq_n = USART2_IRQn; + vector = (uint32_t)&uart2_irq; + break; +#endif +#if defined(USART3_BASE) + case UART_3: + irq_n = USART3_IRQn; + vector = (uint32_t)&uart3_irq; + break; +#endif +#if defined(UART4_BASE) + case UART_4: + irq_n = UART4_IRQn; + vector = (uint32_t)&uart4_irq; + break; +#endif +#if defined(UART5_BASE) + case UART_5: + irq_n = UART5_IRQn; + vector = (uint32_t)&uart5_irq; + break; +#endif +#if defined(LPUART1_BASE) + case LPUART_1: + irq_n = LPUART1_IRQn; + vector = (uint32_t)&lpuart1_irq; + break; +#endif + } + + if (enable) { + if (irq == RxIrq) { + __HAL_UART_ENABLE_IT(huart, UART_IT_RXNE); + } else { // TxIrq + __HAL_UART_ENABLE_IT(huart, UART_IT_TXE); + } + NVIC_SetVector(irq_n, vector); + NVIC_EnableIRQ(irq_n); + + } else { // disable + int all_disabled = 0; + if (irq == RxIrq) { + __HAL_UART_DISABLE_IT(huart, UART_IT_RXNE); + // Check if TxIrq is disabled too + if (LL_LPUART_IsEnabledIT_TXE(huart->Instance) == 0) { + all_disabled = 1; + } + } else { // TxIrq + __HAL_UART_DISABLE_IT(huart, UART_IT_TXE); + // Check if RxIrq is disabled too + if (LL_LPUART_IsEnabledIT_RXNE(huart->Instance) == 0) { + all_disabled = 1; + } + } + + if (all_disabled) { + NVIC_DisableIRQ(irq_n); + } + } +} + +/****************************************************************************** + * READ/WRITE + ******************************************************************************/ + +int serial_getc(serial_t *obj) +{ + struct serial_s *obj_s = SERIAL_S(obj); + UART_HandleTypeDef *huart = &uart_handlers[obj_s->index]; + + while (!serial_readable(obj)); + if (obj_s->databits == UART_WORDLENGTH_8B) { + return (int)(huart->Instance->RDR & (uint8_t)0xFF); + } else { + return (int)(huart->Instance->RDR & (uint16_t)0x1FF); + } +} + +void serial_putc(serial_t *obj, int c) +{ + struct serial_s *obj_s = SERIAL_S(obj); + UART_HandleTypeDef *huart = &uart_handlers[obj_s->index]; + + while (!serial_writable(obj)); + if (obj_s->databits == UART_WORDLENGTH_8B) { + huart->Instance->TDR = (uint8_t)(c & (uint8_t)0xFF); + } else { + huart->Instance->TDR = (uint16_t)(c & (uint16_t)0x1FF); + } +} + +void serial_clear(serial_t *obj) +{ + struct serial_s *obj_s = SERIAL_S(obj); + UART_HandleTypeDef *huart = &uart_handlers[obj_s->index]; + + /* Clear RXNE and error flags */ + volatile uint32_t tmpval __attribute__((unused)) = huart->Instance->RDR; + HAL_UART_ErrorCallback(huart); +} + +void serial_break_set(serial_t *obj) +{ + struct serial_s *obj_s = SERIAL_S(obj); + UART_HandleTypeDef *huart = &uart_handlers[obj_s->index]; + + HAL_LIN_SendBreak(huart); +} + +#if DEVICE_SERIAL_ASYNCH + +/****************************************************************************** + * LOCAL HELPER FUNCTIONS + ******************************************************************************/ + +/** + * Configure the TX buffer for an asynchronous write serial transaction + * + * @param obj The serial object. + * @param tx The buffer for sending. + * @param tx_length The number of words to transmit. + */ +static void serial_tx_buffer_set(serial_t *obj, void *tx, int tx_length, uint8_t width) +{ + (void)width; + + // Exit if a transmit is already on-going + if (serial_tx_active(obj)) { + return; + } + + obj->tx_buff.buffer = tx; + obj->tx_buff.length = tx_length; + obj->tx_buff.pos = 0; +} + +/** + * Configure the RX buffer for an asynchronous write serial transaction + * + * @param obj The serial object. + * @param tx The buffer for sending. + * @param tx_length The number of words to transmit. + */ +static void serial_rx_buffer_set(serial_t *obj, void *rx, int rx_length, uint8_t width) +{ + (void)width; + + // Exit if a reception is already on-going + if (serial_rx_active(obj)) { + return; + } + + obj->rx_buff.buffer = rx; + obj->rx_buff.length = rx_length; + obj->rx_buff.pos = 0; +} + +/** + * Configure events + * + * @param obj The serial object + * @param event The logical OR of the events to configure + * @param enable Set to non-zero to enable events, or zero to disable them + */ +static void serial_enable_event(serial_t *obj, int event, uint8_t enable) +{ + struct serial_s *obj_s = SERIAL_S(obj); + + // Shouldn't have to enable interrupt here, just need to keep track of the requested events. + if (enable) { + obj_s->events |= event; + } else { + obj_s->events &= ~event; + } +} + + +/** +* Get index of serial object TX IRQ, relating it to the physical peripheral. +* +* @param uart_name i.e. UART_1, UART_2, ... +* @return internal NVIC TX IRQ index of U(S)ART peripheral +*/ +static IRQn_Type serial_get_irq_n(UARTName uart_name) +{ + IRQn_Type irq_n; + + switch (uart_name) { +#if defined(USART1_BASE) + case UART_1: + irq_n = USART1_IRQn; + break; +#endif +#if defined(USART2_BASE) + case UART_2: + irq_n = USART2_IRQn; + break; +#endif +#if defined(USART3_BASE) + case UART_3: + irq_n = USART3_IRQn; + break; +#endif +#if defined(UART4_BASE) + case UART_4: + irq_n = UART4_IRQn; + break; +#endif +#if defined(UART5_BASE) + case UART_5: + irq_n = UART5_IRQn; + break; +#endif +#if defined(LPUART1_BASE) + case LPUART_1: + irq_n = LPUART1_IRQn; + break; +#endif + default: + irq_n = (IRQn_Type)0; + } + + return irq_n; +} + +/****************************************************************************** + * MBED API FUNCTIONS + ******************************************************************************/ + +/** + * Begin asynchronous TX transfer. The used buffer is specified in the serial + * object, tx_buff + * + * @param obj The serial object + * @param tx The buffer for sending + * @param tx_length The number of words to transmit + * @param tx_width The bit width of buffer word + * @param handler The serial handler + * @param event The logical OR of events to be registered + * @param hint A suggestion for how to use DMA with this transfer + * @return Returns number of data transfered, or 0 otherwise + */ +int serial_tx_asynch(serial_t *obj, const void *tx, size_t tx_length, uint8_t tx_width, uint32_t handler, uint32_t event, DMAUsage hint) +{ + // TODO: DMA usage is currently ignored + (void) hint; + + // Check buffer is ok + MBED_ASSERT(tx != (void *)0); + MBED_ASSERT(tx_width == 8); // support only 8b width + + struct serial_s *obj_s = SERIAL_S(obj); + UART_HandleTypeDef *huart = &uart_handlers[obj_s->index]; + + if (tx_length == 0) { + return 0; + } + + // Set up buffer + serial_tx_buffer_set(obj, (void *)tx, tx_length, tx_width); + + // Set up events + serial_enable_event(obj, SERIAL_EVENT_TX_ALL, 0); // Clear all events + serial_enable_event(obj, event, 1); // Set only the wanted events + + // Enable interrupt + IRQn_Type irq_n = serial_get_irq_n(obj_s->uart); + NVIC_ClearPendingIRQ(irq_n); + NVIC_DisableIRQ(irq_n); + NVIC_SetPriority(irq_n, 1); + NVIC_SetVector(irq_n, (uint32_t)handler); + NVIC_EnableIRQ(irq_n); + + // the following function will enable UART_IT_TXE and error interrupts + if (HAL_UART_Transmit_IT(huart, (uint8_t *)tx, tx_length) != HAL_OK) { + return 0; + } + + return tx_length; +} + +/** + * Begin asynchronous RX transfer (enable interrupt for data collecting) + * The used buffer is specified in the serial object, rx_buff + * + * @param obj The serial object + * @param rx The buffer for sending + * @param rx_length The number of words to transmit + * @param rx_width The bit width of buffer word + * @param handler The serial handler + * @param event The logical OR of events to be registered + * @param handler The serial handler + * @param char_match A character in range 0-254 to be matched + * @param hint A suggestion for how to use DMA with this transfer + */ +void serial_rx_asynch(serial_t *obj, void *rx, size_t rx_length, uint8_t rx_width, uint32_t handler, uint32_t event, uint8_t char_match, DMAUsage hint) +{ + // TODO: DMA usage is currently ignored + (void) hint; + + /* Sanity check arguments */ + MBED_ASSERT(obj); + MBED_ASSERT(rx != (void *)0); + MBED_ASSERT(rx_width == 8); // support only 8b width + + struct serial_s *obj_s = SERIAL_S(obj); + UART_HandleTypeDef *huart = &uart_handlers[obj_s->index]; + + serial_enable_event(obj, SERIAL_EVENT_RX_ALL, 0); + serial_enable_event(obj, event, 1); + + // set CharMatch + obj->char_match = char_match; + + serial_rx_buffer_set(obj, rx, rx_length, rx_width); + + IRQn_Type irq_n = serial_get_irq_n(obj_s->uart); + NVIC_ClearPendingIRQ(irq_n); + NVIC_DisableIRQ(irq_n); + NVIC_SetPriority(irq_n, 0); + NVIC_SetVector(irq_n, (uint32_t)handler); + NVIC_EnableIRQ(irq_n); + + // following HAL function will enable the RXNE interrupt + error interrupts + HAL_UART_Receive_IT(huart, (uint8_t *)rx, rx_length); +} + +/** + * Attempts to determine if the serial peripheral is already in use for TX + * + * @param obj The serial object + * @return Non-zero if the TX transaction is ongoing, 0 otherwise + */ +uint8_t serial_tx_active(serial_t *obj) +{ + MBED_ASSERT(obj); + + struct serial_s *obj_s = SERIAL_S(obj); + UART_HandleTypeDef *huart = &uart_handlers[obj_s->index]; + + return (((HAL_UART_GetState(huart) & HAL_UART_STATE_BUSY_TX) == HAL_UART_STATE_BUSY_TX) ? 1 : 0); +} + +/** + * Attempts to determine if the serial peripheral is already in use for RX + * + * @param obj The serial object + * @return Non-zero if the RX transaction is ongoing, 0 otherwise + */ +uint8_t serial_rx_active(serial_t *obj) +{ + MBED_ASSERT(obj); + + struct serial_s *obj_s = SERIAL_S(obj); + UART_HandleTypeDef *huart = &uart_handlers[obj_s->index]; + + return (((HAL_UART_GetState(huart) & HAL_UART_STATE_BUSY_RX) == HAL_UART_STATE_BUSY_RX) ? 1 : 0); +} + +void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) +{ + if (__HAL_UART_GET_FLAG(huart, UART_FLAG_PE) != RESET) { + volatile uint32_t tmpval __attribute__((unused)) = huart->Instance->RDR; // Clear PE flag + } else if (__HAL_UART_GET_FLAG(huart, UART_FLAG_FE) != RESET) { + volatile uint32_t tmpval __attribute__((unused)) = huart->Instance->RDR; // Clear FE flag + } else if (__HAL_UART_GET_FLAG(huart, UART_FLAG_NE) != RESET) { + volatile uint32_t tmpval __attribute__((unused)) = huart->Instance->RDR; // Clear NE flag + } else if (__HAL_UART_GET_FLAG(huart, UART_FLAG_ORE) != RESET) { + volatile uint32_t tmpval __attribute__((unused)) = huart->Instance->RDR; // Clear ORE flag + } +} + +/** + * The asynchronous TX and RX handler. + * + * @param obj The serial object + * @return Returns event flags if a TX/RX transfer termination condition was met or 0 otherwise + */ +int serial_irq_handler_asynch(serial_t *obj) +{ + struct serial_s *obj_s = SERIAL_S(obj); + UART_HandleTypeDef *huart = &uart_handlers[obj_s->index]; + + volatile int return_event = 0; + uint8_t *buf = (uint8_t *)(obj->rx_buff.buffer); + size_t i = 0; + + // TX PART: + if (__HAL_UART_GET_FLAG(huart, UART_FLAG_TC) != RESET) { + if (__HAL_UART_GET_IT_SOURCE(huart, UART_IT_TC) != RESET) { + // Return event SERIAL_EVENT_TX_COMPLETE if requested + if ((obj_s->events & SERIAL_EVENT_TX_COMPLETE) != 0) { + return_event |= (SERIAL_EVENT_TX_COMPLETE & obj_s->events); + } + } + } + + // Handle error events + if (__HAL_UART_GET_FLAG(huart, UART_FLAG_PE) != RESET) { + if (__HAL_UART_GET_IT(huart, UART_IT_PE) != RESET) { + return_event |= (SERIAL_EVENT_RX_PARITY_ERROR & obj_s->events); + } + } + + if (__HAL_UART_GET_FLAG(huart, UART_FLAG_FE) != RESET) { + if (__HAL_UART_GET_IT(huart, UART_IT_FE) != RESET) { + return_event |= (SERIAL_EVENT_RX_FRAMING_ERROR & obj_s->events); + } + } + + if (__HAL_UART_GET_FLAG(huart, UART_FLAG_ORE) != RESET) { + if (__HAL_UART_GET_IT(huart, UART_IT_ORE) != RESET) { + return_event |= (SERIAL_EVENT_RX_OVERRUN_ERROR & obj_s->events); + } + } + + HAL_UART_IRQHandler(huart); + + // Abort if an error occurs + if ((return_event & SERIAL_EVENT_RX_PARITY_ERROR) || + (return_event & SERIAL_EVENT_RX_FRAMING_ERROR) || + (return_event & SERIAL_EVENT_RX_OVERRUN_ERROR)) { + return return_event; + } + + //RX PART + if (huart->RxXferSize != 0) { + obj->rx_buff.pos = huart->RxXferSize - huart->RxXferCount; + } + if ((huart->RxXferCount == 0) && (obj->rx_buff.pos >= (obj->rx_buff.length - 1))) { + return_event |= (SERIAL_EVENT_RX_COMPLETE & obj_s->events); + } + + // Check if char_match is present + if (obj_s->events & SERIAL_EVENT_RX_CHARACTER_MATCH) { + if (buf != NULL) { + for (i = 0; i < obj->rx_buff.pos; i++) { + if (buf[i] == obj->char_match) { + obj->rx_buff.pos = i; + return_event |= (SERIAL_EVENT_RX_CHARACTER_MATCH & obj_s->events); + serial_rx_abort_asynch(obj); + break; + } + } + } + } + + return return_event; +} + +/** + * Abort the ongoing TX transaction. It disables the enabled interupt for TX and + * flush TX hardware buffer if TX FIFO is used + * + * @param obj The serial object + */ +void serial_tx_abort_asynch(serial_t *obj) +{ + struct serial_s *obj_s = SERIAL_S(obj); + UART_HandleTypeDef *huart = &uart_handlers[obj_s->index]; + + __HAL_UART_DISABLE_IT(huart, UART_IT_TC); + __HAL_UART_DISABLE_IT(huart, UART_IT_TXE); + + // reset states + huart->TxXferCount = 0; + // update handle state + if (huart->gState == HAL_UART_STATE_BUSY_TX_RX) { + huart->gState = HAL_UART_STATE_BUSY_RX; + } else { + huart->gState = HAL_UART_STATE_READY; + } +} + +/** + * Abort the ongoing RX transaction It disables the enabled interrupt for RX and + * flush RX hardware buffer if RX FIFO is used + * + * @param obj The serial object + */ +void serial_rx_abort_asynch(serial_t *obj) +{ + struct serial_s *obj_s = SERIAL_S(obj); + UART_HandleTypeDef *huart = &uart_handlers[obj_s->index]; + + // disable interrupts + __HAL_UART_DISABLE_IT(huart, UART_IT_RXNE); + __HAL_UART_DISABLE_IT(huart, UART_IT_PE); + __HAL_UART_DISABLE_IT(huart, UART_IT_ERR); + + // clear flags + __HAL_UART_CLEAR_FLAG(huart, UART_FLAG_RXNE); + volatile uint32_t tmpval __attribute__((unused)) = huart->Instance->RDR; // Clear errors flag + + // reset states + huart->RxXferCount = 0; + // update handle state + if (huart->RxState == HAL_UART_STATE_BUSY_TX_RX) { + huart->RxState = HAL_UART_STATE_BUSY_TX; + } else { + huart->RxState = HAL_UART_STATE_READY; + } +} + +#endif /* DEVICE_SERIAL_ASYNCH */ + +#if DEVICE_SERIAL_FC + +/** + * Set HW Control Flow + * @param obj The serial object + * @param type The Control Flow type (FlowControlNone, FlowControlRTS, FlowControlCTS, FlowControlRTSCTS) + * @param pinmap Pointer to structure which holds static pinmap + */ +#if STATIC_PINMAP_READY +#define SERIAL_SET_FC_DIRECT serial_set_flow_control_direct +void serial_set_flow_control_direct(serial_t *obj, FlowControl type, const serial_fc_pinmap_t *pinmap) +#else +#define SERIAL_SET_FC_DIRECT _serial_set_flow_control_direct +static void _serial_set_flow_control_direct(serial_t *obj, FlowControl type, const serial_fc_pinmap_t *pinmap) +#endif +{ + struct serial_s *obj_s = SERIAL_S(obj); + + if (type == FlowControlNone) { + // Disable hardware flow control + obj_s->hw_flow_ctl = UART_HWCONTROL_NONE; + } + if (type == FlowControlRTS) { + // Enable RTS + MBED_ASSERT(pinmap->rx_flow_pin != (UARTName)NC); + obj_s->hw_flow_ctl = UART_HWCONTROL_RTS; + obj_s->pin_rts = pinmap->rx_flow_pin; + // Enable the pin for RTS function + pin_function(pinmap->rx_flow_pin, pinmap->rx_flow_function); + pin_mode(pinmap->rx_flow_pin, PullNone); + } + if (type == FlowControlCTS) { + // Enable CTS + MBED_ASSERT(pinmap->tx_flow_pin != (UARTName)NC); + obj_s->hw_flow_ctl = UART_HWCONTROL_CTS; + obj_s->pin_cts = pinmap->tx_flow_pin; + // Enable the pin for CTS function + pin_function(pinmap->tx_flow_pin, pinmap->tx_flow_function); + pin_mode(pinmap->tx_flow_pin, PullNone); + } + if (type == FlowControlRTSCTS) { + // Enable CTS & RTS + MBED_ASSERT(pinmap->rx_flow_pin != (UARTName)NC); + MBED_ASSERT(pinmap->tx_flow_pin != (UARTName)NC); + obj_s->hw_flow_ctl = UART_HWCONTROL_RTS_CTS; + obj_s->pin_rts = pinmap->rx_flow_pin;; + obj_s->pin_cts = pinmap->tx_flow_pin;; + // Enable the pin for CTS function + pin_function(pinmap->tx_flow_pin, pinmap->tx_flow_function); + pin_mode(pinmap->tx_flow_pin, PullNone); + // Enable the pin for RTS function + pin_function(pinmap->rx_flow_pin, pinmap->rx_flow_function); + pin_mode(pinmap->rx_flow_pin, PullNone); + } + + init_uart(obj); +} + +/** + * Set HW Control Flow + * @param obj The serial object + * @param type The Control Flow type (FlowControlNone, FlowControlRTS, FlowControlCTS, FlowControlRTSCTS) + * @param rxflow Pin for the rxflow + * @param txflow Pin for the txflow + */ +void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, PinName txflow) +{ + struct serial_s *obj_s = SERIAL_S(obj); + + UARTName uart_rts = (UARTName)pinmap_peripheral(rxflow, PinMap_UART_RTS); + UARTName uart_cts = (UARTName)pinmap_peripheral(txflow, PinMap_UART_CTS); + + if (((UARTName)pinmap_merge(uart_rts, obj_s->uart) == (UARTName)NC) || ((UARTName)pinmap_merge(uart_cts, obj_s->uart) == (UARTName)NC)) { + MBED_ASSERT(0); + return; + } + + int peripheral = (int)pinmap_merge(uart_rts, uart_cts); + + int tx_flow_function = (int)pinmap_find_function(txflow, PinMap_UART_CTS); + int rx_flow_function = (int)pinmap_find_function(rxflow, PinMap_UART_RTS); + + const serial_fc_pinmap_t explicit_uart_fc_pinmap = {peripheral, txflow, tx_flow_function, rxflow, rx_flow_function}; + + SERIAL_SET_FC_DIRECT(obj, type, &explicit_uart_fc_pinmap); +} + +#endif /* DEVICE_SERIAL_FC */ + +#endif /* DEVICE_SERIAL */ diff --git a/targets/TARGET_STM/TARGET_STM32L5/spi_api.c b/targets/TARGET_STM/TARGET_STM32L5/spi_api.c new file mode 100644 index 0000000000..76280bb94a --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32L5/spi_api.c @@ -0,0 +1,61 @@ +/* mbed Microcontroller Library + * SPDX-License-Identifier: BSD-3-Clause + ****************************************************************************** + * + * Copyright (c) 2015 STMicroelectronics. + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +#include "mbed_assert.h" +#include "spi_api.h" + +#if DEVICE_SPI + +#include "cmsis.h" +#include "pinmap.h" +#include "mbed_error.h" +#include "PeripheralPins.h" + +#if DEVICE_SPI_ASYNCH +#define SPI_S(obj) (( struct spi_s *)(&(obj->spi))) +#else +#define SPI_S(obj) (( struct spi_s *)(obj)) +#endif + +/* + * Only the frequency is managed in the family specific part + * the rest of SPI management is common to all STM32 families + */ +int spi_get_clock_freq(spi_t *obj) +{ + struct spi_s *spiobj = SPI_S(obj); + int spi_hz = 0; + + /* Get source clock depending on SPI instance */ + switch ((int)spiobj->spi) { + case SPI_1: + /* SPI_1. Source CLK is PCKL2 */ + spi_hz = HAL_RCC_GetPCLK2Freq(); + break; +#if defined(SPI2_BASE) + case SPI_2: +#endif + case SPI_3: + /* SPI_2, SPI_3. Source CLK is PCKL1 */ + spi_hz = HAL_RCC_GetPCLK1Freq(); + break; + default: + error("CLK: SPI instance not set"); + break; + } + return spi_hz; +} + +#endif diff --git a/targets/TARGET_STM/TARGET_STM32L5/spi_device.h b/targets/TARGET_STM/TARGET_STM32L5/spi_device.h new file mode 100644 index 0000000000..a4f4a0b622 --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32L5/spi_device.h @@ -0,0 +1,21 @@ +/* mbed Microcontroller Library + * SPDX-License-Identifier: BSD-3-Clause + ****************************************************************************** + * + * Copyright (c) 2017 STMicroelectronics. + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +#ifndef MBED_SPI_DEVICE_H +#define MBED_SPI_DEVICE_H + +#include "stm32l5xx_ll_spi.h" + +#endif diff --git a/targets/TARGET_STM/TARGET_STM32L5/system_clock.c b/targets/TARGET_STM/TARGET_STM32L5/system_clock.c new file mode 100644 index 0000000000..94225c4c71 --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32L5/system_clock.c @@ -0,0 +1,198 @@ +/* mbed Microcontroller Library + * SPDX-License-Identifier: BSD-3-Clause + ****************************************************************************** + * + * Copyright (c) 2017 STMicroelectronics. + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/** + * This file configures the system clock as follows: + *----------------------------------------------------------------------------- + * System clock source | 1- USE_PLL_HSE_EXTC (external 8 MHz clock) + * | 2- USE_PLL_HSE_XTAL (external 8 MHz xtal) + * | 3- USE_PLL_HSI (internal 16 MHz) + * | 4- USE_PLL_MSI (internal 100kHz to 48 MHz) + *----------------------------------------------------------------------------- + * SYSCLK(MHz) | 110 + * AHBCLK (MHz) | 110 + * APB1CLK (MHz) | 110 + * APB2CLK (MHz) | 110 + * USB capable | NO // TODO + *----------------------------------------------------------------------------- +**/ + +#include "stm32l5xx.h" +#include "nvic_addr.h" +#include "mbed_error.h" +#include "mbed_toolchain.h" + + +// clock source is selected with CLOCK_SOURCE in json config +#define USE_PLL_HSE_EXTC 0x8 // Use external clock (ST Link MCO - not enabled by default) +#define USE_PLL_HSE_XTAL 0x4 // Use external xtal (X3 on board - not provided by default) +#define USE_PLL_HSI 0x2 // Use HSI internal clock +#define USE_PLL_MSI 0x1 // Use MSI internal clock + +#if ( ((CLOCK_SOURCE) & USE_PLL_HSE_XTAL) || ((CLOCK_SOURCE) & USE_PLL_HSE_EXTC) ) +uint8_t SetSysClock_PLL_HSE(uint8_t bypass); +#endif /* ((CLOCK_SOURCE) & USE_PLL_HSE_XTAL) || ((CLOCK_SOURCE) & USE_PLL_HSE_EXTC) */ + +#if ((CLOCK_SOURCE) & USE_PLL_HSI) +uint8_t SetSysClock_PLL_HSI(void); +#endif /* ((CLOCK_SOURCE) & USE_PLL_HSI) */ + +#if ((CLOCK_SOURCE) & USE_PLL_MSI) +uint8_t SetSysClock_PLL_MSI(void); +#endif /* ((CLOCK_SOURCE) & USE_PLL_MSI) */ + + + + + +/** + * @brief Configures the System clock source, PLL Multiplier and Divider factors, + * AHB/APBx prescalers and Flash settings + * @note This function should be called only once the RCC clock configuration + * is reset to the default reset state (done in SystemInit() function). + * @param None + * @retval None + */ + +MBED_WEAK void SetSysClock(void) +{ +#if ((CLOCK_SOURCE) & USE_PLL_HSE_EXTC) + /* 1- Try to start with HSE and external clock */ + if (SetSysClock_PLL_HSE(1) == 0) +#endif + { +#if ((CLOCK_SOURCE) & USE_PLL_HSE_XTAL) + /* 2- If fail try to start with HSE and external xtal */ + if (SetSysClock_PLL_HSE(0) == 0) +#endif + { +#if ((CLOCK_SOURCE) & USE_PLL_HSI) + /* 3- If fail start with HSI clock */ + if (SetSysClock_PLL_HSI() == 0) +#endif + { +#if ((CLOCK_SOURCE) & USE_PLL_MSI) + /* 4- If fail start with MSI clock */ + if (SetSysClock_PLL_MSI() == 0) +#endif + { + { + error("SetSysClock failed\n"); + } + } + } + } + } + +} + +#if ( ((CLOCK_SOURCE) & USE_PLL_HSE_XTAL) || ((CLOCK_SOURCE) & USE_PLL_HSE_EXTC) ) +/******************************************************************************/ +/* PLL (clocked by HSE) used as System clock source */ +/******************************************************************************/ +uint8_t SetSysClock_PLL_HSE(uint8_t bypass) +{ + return 0; // FAIL // TODO +} +#endif /* ((CLOCK_SOURCE) & USE_PLL_HSE_XTAL) || ((CLOCK_SOURCE) & USE_PLL_HSE_EXTC) */ + +#if ((CLOCK_SOURCE) & USE_PLL_HSI) +/******************************************************************************/ +/* PLL (clocked by HSI) used as System clock source */ +/******************************************************************************/ +uint8_t SetSysClock_PLL_HSI(void) +{ + return 0; // FAIL // TODO +} +#endif /* ((CLOCK_SOURCE) & USE_PLL_HSI) */ + +#if ((CLOCK_SOURCE) & USE_PLL_MSI) +/******************************************************************************/ +/* PLL (clocked by MSI) used as System clock source */ +/******************************************************************************/ +uint8_t SetSysClock_PLL_MSI(void) +{ + RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; + RCC_OscInitTypeDef RCC_OscInitStruct = {0}; + + /* Configure the main internal regulator output voltage */ + if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE0) != HAL_OK) { + return 0; // FAIL + } + + /* Configure LSE Drive Capability */ + __HAL_RCC_PWR_CLK_ENABLE(); + __HAL_RCC_SYSCFG_CLK_ENABLE(); + HAL_PWR_EnableBkUpAccess(); + __HAL_RCC_RTCAPB_CLK_ENABLE(); + +#if MBED_CONF_TARGET_LSE_AVAILABLE + __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW); + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; + RCC_OscInitStruct.LSEState = RCC_LSE_ON; // External 32.768 kHz clock on OSC_IN/OSC_OUT + if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { + return 0; // FAIL + } +#endif /* MBED_CONF_TARGET_LSE_AVAILABLE */ + + /* Enable MSI Oscillator and activate PLL with MSI as source */ + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI | RCC_OSCILLATORTYPE_HSI | RCC_OSCILLATORTYPE_HSI48 | RCC_OSCILLATORTYPE_HSE; + RCC_OscInitStruct.MSIState = RCC_MSI_ON; + RCC_OscInitStruct.HSEState = RCC_HSE_OFF; + RCC_OscInitStruct.HSIState = RCC_HSI_OFF; +#if DEVICE_TRNG + RCC_OscInitStruct.HSI48State = RCC_HSI48_ON; +#else + RCC_OscInitStruct.HSI48State = RCC_HSI48_OFF; +#endif + + RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT; + RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6; /* 4 MHz */ + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI; + RCC_OscInitStruct.PLL.PLLM = 1; /* 4 MHz */ + RCC_OscInitStruct.PLL.PLLN = 55; /* 220 MHz */ + RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7; + RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2; /* 110 MHz */ + RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2; /* 110 MHz */ + if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { + return 0; // FAIL + } + + // Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 clocks dividers + RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2); + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; /* 110 MHz */ + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; /* 110 MHz */ + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; /* 110 MHz */ + RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; /* 110 MHz */ + if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) { + return 0; // FAIL + } + + // Default STDIO is LPUART1 + RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; +#if DEVICE_TRNG + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LPUART1 | RCC_PERIPHCLK_RNG; + PeriphClkInitStruct.RngClockSelection = RCC_RNGCLKSOURCE_HSI48; +#else + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LPUART1; +#endif + PeriphClkInitStruct.Lpuart1ClockSelection = RCC_LPUART1CLKSOURCE_LSE; + HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct); + + return 1; // OK +} +#endif /* ((CLOCK_SOURCE) & USE_PLL_MSI) */ diff --git a/targets/TARGET_STM/TARGET_STM32L5/us_ticker_data.h b/targets/TARGET_STM/TARGET_STM32L5/us_ticker_data.h new file mode 100644 index 0000000000..91b44b812b --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32L5/us_ticker_data.h @@ -0,0 +1,41 @@ +/* mbed Microcontroller Library + * SPDX-License-Identifier: BSD-3-Clause + ****************************************************************************** + * + * Copyright (c) 2015 STMicroelectronics. + * All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +#ifndef __US_TICKER_DATA_H +#define __US_TICKER_DATA_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stm32l5xx.h" +#include "stm32l5xx_ll_tim.h" + +#define TIM_MST TIM5 +#define TIM_MST_IRQ TIM5_IRQn +#define TIM_MST_RCC __HAL_RCC_TIM5_CLK_ENABLE() + +#define TIM_MST_RESET_ON __HAL_RCC_TIM5_FORCE_RESET() +#define TIM_MST_RESET_OFF __HAL_RCC_TIM5_RELEASE_RESET() + +#define TIM_MST_BIT_WIDTH 32 // 16 or 32 + +#define TIM_MST_PCLK 1 // Select the peripheral clock number (1 or 2) + +#ifdef __cplusplus +} +#endif + +#endif // __US_TICKER_DATA_H