diff --git a/targets/TARGET_STM/lp_ticker.c b/targets/TARGET_STM/lp_ticker.c index 689833ffcd6..dfe84aff752 100644 --- a/targets/TARGET_STM/lp_ticker.c +++ b/targets/TARGET_STM/lp_ticker.c @@ -1,6 +1,6 @@ /* mbed Microcontroller Library ******************************************************************************* - * Copyright (c) 2016, STMicroelectronics + * Copyright (c) 2017, STMicroelectronics * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,20 +31,11 @@ #if DEVICE_LOWPOWERTIMER -#include "ticker_api.h" -#include "lp_ticker_api.h" -#include "rtc_api.h" #include "rtc_api_hal.h" -static uint8_t lp_ticker_inited = 0; - void lp_ticker_init(void) { - if (lp_ticker_inited) return; - lp_ticker_inited = 1; - rtc_init(); - rtc_set_irq_handler((uint32_t) lp_ticker_irq_handler); } uint32_t lp_ticker_read(void) @@ -52,8 +43,6 @@ uint32_t lp_ticker_read(void) uint32_t usecs = 0; time_t time = 0; - lp_ticker_init(); - do { time = rtc_read(); usecs = rtc_read_subseconds(); @@ -82,7 +71,7 @@ void lp_ticker_disable_interrupt(void) void lp_ticker_clear_interrupt(void) { - + NVIC_ClearPendingIRQ(RTC_WKUP_IRQn); } -#endif +#endif /* DEVICE_LOWPOWERTIMER */ diff --git a/targets/TARGET_STM/rtc_api.c b/targets/TARGET_STM/rtc_api.c index 23f7625012b..2b9b31a769f 100644 --- a/targets/TARGET_STM/rtc_api.c +++ b/targets/TARGET_STM/rtc_api.c @@ -1,6 +1,6 @@ /* mbed Microcontroller Library ******************************************************************************* - * Copyright (c) 2016, STMicroelectronics + * Copyright (c) 2017, STMicroelectronics * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,29 +27,15 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************* */ + #if DEVICE_RTC -#include "rtc_api.h" #include "rtc_api_hal.h" #include "mbed_error.h" #include "mbed_mktime.h" static RTC_HandleTypeDef RtcHandle; -#if RTC_LSI -#define RTC_CLOCK LSI_VALUE -#else -#define RTC_CLOCK LSE_VALUE -#endif - -#if DEVICE_LOWPOWERTIMER -#define RTC_ASYNCH_PREDIV ((RTC_CLOCK - 1) / 0x8000) -#define RTC_SYNCH_PREDIV (RTC_CLOCK / (RTC_ASYNCH_PREDIV + 1) - 1) -#else -#define RTC_ASYNCH_PREDIV (0x007F) -#define RTC_SYNCH_PREDIV (RTC_CLOCK / (RTC_ASYNCH_PREDIV + 1) - 1) -#endif - #if DEVICE_LOWPOWERTIMER static void (*irq_handler)(void); static void RTC_IRQHandler(void); @@ -61,38 +47,38 @@ void rtc_init(void) RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; // Enable access to Backup domain + __HAL_RCC_PWR_CLK_ENABLE(); HAL_PWR_EnableBkUpAccess(); - RtcHandle.Instance = RTC; - RtcHandle.State = HAL_RTC_STATE_RESET; + if (rtc_isenabled()) { + return; + } -#if !RTC_LSI - RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE; +#if MBED_CONF_TARGET_LSE_AVAILABLE + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_LSE; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; // Mandatory, otherwise the PLL is reconfigured! RCC_OscInitStruct.LSEState = RCC_LSE_ON; RCC_OscInitStruct.LSIState = RCC_LSI_OFF; - if (HAL_RCC_OscConfig(&RCC_OscInitStruct) == HAL_OK) { - __HAL_RCC_RTC_CLKPRESCALER(RCC_RTCCLKSOURCE_LSE); - __HAL_RCC_RTC_CONFIG(RCC_RTCCLKSOURCE_LSE); - } else { + if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { error("Cannot initialize RTC with LSE\n"); } + __HAL_RCC_RTC_CLKPRESCALER(RCC_RTCCLKSOURCE_LSE); + __HAL_RCC_RTC_CONFIG(RCC_RTCCLKSOURCE_LSE); + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC; PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) { error("PeriphClkInitStruct RTC failed with LSE\n"); } -#else /* !RTC_LSI */ - __HAL_RCC_PWR_CLK_ENABLE(); - +#else /* MBED_CONF_TARGET_LSE_AVAILABLE */ // Reset Backup domain __HAL_RCC_BACKUPRESET_FORCE(); __HAL_RCC_BACKUPRESET_RELEASE(); // Enable LSI clock - RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI; + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_LSE; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; // Mandatory, otherwise the PLL is reconfigured! RCC_OscInitStruct.LSEState = RCC_LSE_OFF; RCC_OscInitStruct.LSIState = RCC_LSI_ON; @@ -108,46 +94,50 @@ void rtc_init(void) if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) { error("PeriphClkInitStruct RTC failed with LSI\n"); } -#endif /* !RTC_LSI */ +#endif /* MBED_CONF_TARGET_LSE_AVAILABLE */ // Enable RTC __HAL_RCC_RTC_ENABLE(); + RtcHandle.Instance = RTC; + RtcHandle.State = HAL_RTC_STATE_RESET; + #if TARGET_STM32F1 RtcHandle.Init.AsynchPrediv = RTC_AUTO_1_SECOND; #else /* TARGET_STM32F1 */ RtcHandle.Init.HourFormat = RTC_HOURFORMAT_24; - RtcHandle.Init.AsynchPrediv = RTC_ASYNCH_PREDIV; - RtcHandle.Init.SynchPrediv = RTC_SYNCH_PREDIV; + + /* PREDIV_A : 7-bit asynchronous prescaler */ +#if DEVICE_LOWPOWERTIMER + /* PREDIV_A is set to a small value to improve the SubSeconds resolution */ + /* with a 32768Hz clock, PREDIV_A=7 gives a precision of 244us */ + RtcHandle.Init.AsynchPrediv = 7; +#else + /* PREDIV_A is set to the maximum value to improve the consumption */ + RtcHandle.Init.AsynchPrediv = 0x007F; +#endif + /* PREDIV_S : 15-bit synchronous prescaler */ + /* PREDIV_S is set in order to get a 1 Hz clock */ + RtcHandle.Init.SynchPrediv = RTC_CLOCK / (RtcHandle.Init.AsynchPrediv + 1) - 1; RtcHandle.Init.OutPut = RTC_OUTPUT_DISABLE; RtcHandle.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH; RtcHandle.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN; #endif /* TARGET_STM32F1 */ if (HAL_RTC_Init(&RtcHandle) != HAL_OK) { - error("RTC error: RTC initialization failed."); + error("RTC initialization failed"); } -#if DEVICE_LOWPOWERTIMER + rtc_synchronize(); // Wait for RSF -#if !RTC_LSI - if (!rtc_isenabled()) -#endif /* !RTC_LSI */ - { + if (!rtc_isenabled()) { rtc_write(0); } - - NVIC_ClearPendingIRQ(RTC_WKUP_IRQn); - NVIC_DisableIRQ(RTC_WKUP_IRQn); - NVIC_SetVector(RTC_WKUP_IRQn, (uint32_t)RTC_IRQHandler); - NVIC_EnableIRQ(RTC_WKUP_IRQn); - -#endif /* DEVICE_LOWPOWERTIMER */ } void rtc_free(void) { -#if RTC_LSI +#if !MBED_CONF_TARGET_LSE_AVAILABLE // Enable Power clock __HAL_RCC_PWR_CLK_ENABLE(); @@ -279,8 +269,12 @@ void rtc_write(time_t t) #endif /* TARGET_STM32F1 */ // Change the RTC current date/time - HAL_RTC_SetDate(&RtcHandle, &dateStruct, RTC_FORMAT_BIN); - HAL_RTC_SetTime(&RtcHandle, &timeStruct, RTC_FORMAT_BIN); + if (HAL_RTC_SetDate(&RtcHandle, &dateStruct, RTC_FORMAT_BIN) != HAL_OK) { + error("HAL_RTC_SetDate error\n"); + } + if (HAL_RTC_SetTime(&RtcHandle, &timeStruct, RTC_FORMAT_BIN) != HAL_OK) { + error("HAL_RTC_SetTime error\n"); + } } int rtc_isenabled(void) @@ -292,6 +286,13 @@ int rtc_isenabled(void) #endif /* TARGET_STM32F1 */ } +void rtc_synchronize(void) +{ + if (HAL_RTC_WaitForSynchro(&RtcHandle) != HAL_OK) { + error("rtc_synchronize error\n"); + } +} + #if DEVICE_LOWPOWERTIMER static void RTC_IRQHandler(void) @@ -304,23 +305,42 @@ static void RTC_IRQHandler(void) } } -void rtc_set_irq_handler(uint32_t handler) -{ - irq_handler = (void (*)(void))handler; -} - uint32_t rtc_read_subseconds(void) { - return 1000000.f * ((double)(RTC_SYNCH_PREDIV - RTC->SSR) / (RTC_SYNCH_PREDIV + 1)); + return 1000000.f * ((double)((RTC->PRER & RTC_PRER_PREDIV_S) - RTC->SSR) / ((RTC->PRER & RTC_PRER_PREDIV_S) + 1)); } void rtc_set_wake_up_timer(uint32_t delta) { - uint32_t wake_up_counter = delta / (2000000 / RTC_CLOCK); + /* Ex for Wakeup period resolution with RTCCLK=32768 Hz : + * RTCCLK_DIV2: ~122us < wakeup period < ~4s + * RTCCLK_DIV4: ~244us < wakeup period < ~8s + * RTCCLK_DIV8: ~488us < wakeup period < ~16s + * RTCCLK_DIV16: ~976us < wakeup period < ~32s + * CK_SPRE_16BITS: 1s < wakeup period < (0xFFFF+ 1) x 1 s = 65536 s (18 hours) + * CK_SPRE_17BITS: 18h+1s < wakeup period < (0x1FFFF+ 1) x 1 s = 131072 s (36 hours) + */ + uint32_t WakeUpClock[6] = {RTC_WAKEUPCLOCK_RTCCLK_DIV2, RTC_WAKEUPCLOCK_RTCCLK_DIV4, RTC_WAKEUPCLOCK_RTCCLK_DIV8, RTC_WAKEUPCLOCK_RTCCLK_DIV16, RTC_WAKEUPCLOCK_CK_SPRE_16BITS, RTC_WAKEUPCLOCK_CK_SPRE_17BITS}; + uint8_t ClockDiv[4] = {2, 4, 8, 16}; + uint32_t WakeUpCounter; + uint8_t DivIndex = 0; + + do { + WakeUpCounter = delta / (ClockDiv[DivIndex] * 1000000 / RTC_CLOCK); + DivIndex++; + } while ( (WakeUpCounter > 0xFFFF) && (DivIndex < 4) ); + + if (WakeUpCounter > 0xFFFF) { + WakeUpCounter = delta / 1000000; + DivIndex++; + } - if (HAL_RTCEx_SetWakeUpTimer_IT(&RtcHandle, wake_up_counter, - RTC_WAKEUPCLOCK_RTCCLK_DIV2) != HAL_OK) { - error("Set wake up timer failed\n"); + irq_handler = (void (*)(void))lp_ticker_irq_handler; + NVIC_SetVector(RTC_WKUP_IRQn, (uint32_t)RTC_IRQHandler); + NVIC_EnableIRQ(RTC_WKUP_IRQn); + + if (HAL_RTCEx_SetWakeUpTimer_IT(&RtcHandle, 0xFFFF & WakeUpCounter, WakeUpClock[DivIndex-1]) != HAL_OK) { + error("rtc_set_wake_up_timer init error (%d)\n", DivIndex); } } @@ -329,10 +349,6 @@ void rtc_deactivate_wake_up_timer(void) HAL_RTCEx_DeactivateWakeUpTimer(&RtcHandle); } -void rtc_synchronize(void) -{ - HAL_RTC_WaitForSynchro(&RtcHandle); -} #endif /* DEVICE_LOWPOWERTIMER */ #endif /* DEVICE_RTC */ diff --git a/targets/TARGET_STM/rtc_api_hal.h b/targets/TARGET_STM/rtc_api_hal.h index 14a345438d3..ca948ca36b0 100644 --- a/targets/TARGET_STM/rtc_api_hal.h +++ b/targets/TARGET_STM/rtc_api_hal.h @@ -1,6 +1,6 @@ /* mbed Microcontroller Library ******************************************************************************* -* Copyright (c) 2016, STMicroelectronics +* Copyright (c) 2017, STMicroelectronics * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,19 +33,18 @@ #include #include "rtc_api.h" +#include "ticker_api.h" +#include "lp_ticker_api.h" #ifdef __cplusplus extern "C" { #endif -/* - * Extend rtc_api.h - */ -/** Set the given function as handler of wakeup timer event. - * - * @param handler The function to set as handler - */ -void rtc_set_irq_handler(uint32_t handler); +#if MBED_CONF_TARGET_LSE_AVAILABLE +#define RTC_CLOCK LSE_VALUE +#else +#define RTC_CLOCK LSI_VALUE +#endif /** Read the subsecond register. * diff --git a/targets/TARGET_STM/sleep.c b/targets/TARGET_STM/sleep.c index d41edfe5b74..fb232ec8b78 100644 --- a/targets/TARGET_STM/sleep.c +++ b/targets/TARGET_STM/sleep.c @@ -68,16 +68,16 @@ void hal_deepsleep(void) #if TARGET_STM32L4 int pwrClockEnabled = __HAL_RCC_PWR_IS_CLK_ENABLED(); int lowPowerModeEnabled = PWR->CR1 & PWR_CR1_LPR; - + if (!pwrClockEnabled) { __HAL_RCC_PWR_CLK_ENABLE(); } if (lowPowerModeEnabled) { HAL_PWREx_DisableLowPowerRunMode(); } - + HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI); - + if (lowPowerModeEnabled) { HAL_PWREx_EnableLowPowerRunMode(); } @@ -101,8 +101,15 @@ void hal_deepsleep(void) TimMasterHandle.Instance = TIM_MST; __HAL_TIM_SET_COUNTER(&TimMasterHandle, EnterTimeUS); -#if DEVICE_LOWPOWERTIMER - rtc_synchronize(); +#if DEVICE_RTC + /* Wait for RTC RSF bit synchro if RTC is configured */ +#if (TARGET_STM32F2) || (TARGET_STM32F4) || (TARGET_STM32F7) + if (READ_BIT(RCC->BDCR, RCC_BDCR_RTCSEL)) { +#else /* (TARGET_STM32F2) || (TARGET_STM32F4) || (TARGET_STM32F7) */ + if (__HAL_RCC_GET_RTC_SOURCE()) { +#endif /* (TARGET_STM32F2) || (TARGET_STM32F4) || (TARGET_STM32F7) */ + rtc_synchronize(); + } #endif } diff --git a/targets/targets.json b/targets/targets.json old mode 100755 new mode 100644 index f6d3f95f782..cbb87813b62 --- a/targets/targets.json +++ b/targets/targets.json @@ -706,6 +706,12 @@ "extra_labels": ["STM"], "supported_toolchains": ["ARM", "uARM", "IAR", "GCC_ARM"], "macros": ["TRANSACTION_QUEUE_SIZE_SPI=2"], + "config": { + "lse_available": { + "help": "Define if a Low Speed External xtal (LSE) is available on the board (0 = No, 1 = Yes). If Yes, the LSE will be used to clock the RTC, LPUART, ... otherwise the Low Speed Internal clock (LSI) will be used", + "value": "1" + } + }, "device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"] }, "LPC54114": { @@ -775,7 +781,8 @@ } }, "detect_code": ["0791"], - "macros_add": ["RTC_LSI=1", "CMSIS_VECTAB_VIRTUAL", "CMSIS_VECTAB_VIRTUAL_HEADER_FILE=\"cmsis_nvic.h\""], + "overrides": {"lse_available": 0}, + "macros_add": ["CMSIS_VECTAB_VIRTUAL", "CMSIS_VECTAB_VIRTUAL_HEADER_FILE=\"cmsis_nvic.h\""], "device_has_add": ["SERIAL_FC"], "default_lib": "small", "release_versions": ["2"], @@ -795,7 +802,8 @@ } }, "detect_code": ["0785"], - "macros_add": ["RTC_LSI=1", "CMSIS_VECTAB_VIRTUAL", "CMSIS_VECTAB_VIRTUAL_HEADER_FILE=\"cmsis_nvic.h\""], + "overrides": {"lse_available": 0}, + "macros_add": ["CMSIS_VECTAB_VIRTUAL", "CMSIS_VECTAB_VIRTUAL_HEADER_FILE=\"cmsis_nvic.h\""], "device_has_add": ["CAN", "SERIAL_FC"], "default_lib": "small", "release_versions": ["2"], @@ -924,7 +932,6 @@ "supported_form_factors": ["ARDUINO"], "core": "Cortex-M4F", "extra_labels_add": ["STM32F3", "STM32F303x8", "STM32F303K8"], - "macros_add": ["RTC_LSI=1"], "config": { "clock_source": { "help": "Mask value : USE_PLL_HSE_EXTC | USE_PLL_HSE_XTAL (need HW patch) | USE_PLL_HSI", @@ -932,6 +939,7 @@ "macro_name": "CLOCK_SOURCE" } }, + "overrides": {"lse_available": 0}, "detect_code": ["0775"], "default_lib": "small", "device_has_add": ["ANALOGOUT", "CAN", "LOWPOWERTIMER", "SERIAL_FC"], @@ -1004,7 +1012,7 @@ }, "detect_code": ["0720"], "macros_add": ["USB_STM_HAL", "USBHOST_OTHER"], - "device_has_add": ["SERIAL_ASYNCH", "SERIAL_FC", "FLASH"], + "device_has_add": ["SERIAL_ASYNCH", "SERIAL_FC", "FLASH", "LOWPOWERTIMER"], "release_versions": ["2", "5"], "device_name": "STM32F401RE" }, @@ -1479,7 +1487,7 @@ "inherits": ["FAMILY_STM32"], "core": "Cortex-M4F", "extra_labels_add": ["STM32F3", "STM32F303", "STM32F303xC", "STM32F303VC"], - "macros_add": ["RTC_LSI=1"], + "overrides": {"lse_available": 0}, "supported_toolchains": ["GCC_ARM"], "device_has_add": ["ANALOGOUT", "CAN", "LOWPOWERTIMER", "SERIAL_FC"], "device_name": "STM32F303VC" @@ -1488,7 +1496,6 @@ "inherits": ["FAMILY_STM32"], "core": "Cortex-M4F", "extra_labels_add": ["STM32F3", "STM32F334x8","STM32F334C8"], - "macros_add": ["RTC_LSI=1"], "config": { "clock_source": { "help": "Mask value : USE_PLL_HSE_EXTC | USE_PLL_HSE_XTAL (need HW patch) | USE_PLL_HSI", @@ -1496,6 +1503,7 @@ "macro_name": "CLOCK_SOURCE" } }, + "overrides": {"lse_available": 0}, "detect_code": ["0810"], "device_has_add": ["ANALOGOUT", "LOWPOWERTIMER", "SERIAL_ASYNCH", "SERIAL_FC"], "default_lib": "small", @@ -1507,7 +1515,8 @@ "core": "Cortex-M4F", "extra_labels_add": ["STM32F4", "STM32F407", "STM32F407xG", "STM32F407VG"], "supported_toolchains": ["ARM", "uARM", "GCC_ARM"], - "macros_add": ["RTC_LSI=1", "USB_STM_HAL"], + "macros_add": ["USB_STM_HAL"], + "overrides": {"lse_available": 0}, "device_has_add": ["ANALOGOUT"], "device_name": "STM32F407VG" }, @@ -1527,7 +1536,8 @@ "macro_name": "CLOCK_SOURCE_USB" } }, - "macros_add": ["RTC_LSI=1", "USB_STM_HAL", "USBHOST_OTHER"], + "overrides": {"lse_available": 0}, + "macros_add": ["USB_STM_HAL", "USBHOST_OTHER"], "device_has_add": ["ANALOGOUT", "CAN", "SERIAL_ASYNCH", "SERIAL_FC", "TRNG", "FLASH"], "release_versions": ["2", "5"], "device_name": "STM32F429ZI", @@ -1555,7 +1565,6 @@ "inherits": ["FAMILY_STM32"], "core": "Cortex-M0+", "extra_labels_add": ["STM32L0", "STM32L053x8", "STM32L053C8"], - "macros": ["RTC_LSI=1"], "config": { "clock_source": { "help": "Mask value : USE_PLL_HSE_EXTC | USE_PLL_HSE_XTAL (need HW patch) | USE_PLL_HSI", @@ -1563,6 +1572,7 @@ "macro_name": "CLOCK_SOURCE" } }, + "overrides": {"lse_available": 0}, "device_has_add": ["ANALOGOUT", "LOWPOWERTIMER", "SERIAL_FC", "FLASH"], "default_lib": "small", "release_versions": ["2"], @@ -1701,7 +1711,8 @@ "macro_name": "MODEM_ON_BOARD_UART" } }, - "macros_add": ["HSE_VALUE=26000000", "VECT_TAB_OFFSET=0x08010000", "RTC_LSI=1"], + "overrides": {"lse_available": 0}, + "macros_add": ["HSE_VALUE=26000000", "VECT_TAB_OFFSET=0x08010000"], "post_binary_hook": { "function": "MTSCode.combine_bins_mts_dragonfly", "toolchains": ["GCC_ARM", "ARM_STD", "ARM_MICRO", "IAR"] @@ -1737,7 +1748,7 @@ "core": "Cortex-M3", "default_toolchain": "uARM", "extra_labels_add": ["STM32L1", "STM32L152RC"], - "macros": ["RTC_LSI=1"], + "overrides": {"lse_available": 0}, "detect_code": ["4100"], "device_has_add": ["ANALOGOUT"], "default_lib": "small", @@ -1821,7 +1832,8 @@ "macro_name": "MODEM_ON_BOARD_UART" } }, - "macros_add": ["MBEDTLS_CONFIG_HW_SUPPORT", "RTC_LSI=1", "HSE_VALUE=12000000", "GNSSBAUD=9600"], + "macros_add": ["MBEDTLS_CONFIG_HW_SUPPORT", "HSE_VALUE=12000000", "GNSSBAUD=9600"], + "overrides": {"lse_available": 0}, "device_has_add": ["ANALOGOUT", "SERIAL_FC", "TRNG", "FLASH"], "features": ["LWIP"], "public": false, @@ -1842,7 +1854,7 @@ "default_toolchain": "uARM", "program_cycle_s": 1.5, "extra_labels_add": ["STM32L1", "STM32L151RC"], - "macros": ["RTC_LSI=1"], + "overrides": {"lse_available": 0}, "supported_toolchains": ["ARM", "uARM", "GCC_ARM"], "device_has_add": ["ANALOGOUT"], "default_lib": "small",