[FL-873] Add F5 target, lp5562 driver and api-hal-light (#347)
* Add F5 target, lp5562 driver and api-hal-light. Update api-usage, switch to F5 by default. * API HAL: add i2c and hardware version api. Dolphin: show hardware version. * OTP version generator and flashing utility. * Assets script: fix code formatting * Backport F5 changes to F4 * F4: disable insomnia, prevent damage to BLE RX path * F5 HAL API Light: remove magic delay to fix magic BLE * Dolphin: HW target validation on start * invert RSSI indication in sub-1 * API HAL: rename board to body in version api * Gpio tester: detach and release viewport on exit Co-authored-by: aanper <mail@s3f.ru>
This commit is contained in:
		
							
								
								
									
										13
									
								
								firmware/targets/f5/api-hal/api-hal-boot.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								firmware/targets/f5/api-hal/api-hal-boot.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| #include <api-hal-boot.h> | ||||
| #include <stm32wbxx_ll_rtc.h> | ||||
|  | ||||
| #define BOOT_REQUEST_NONE 0x00000000 | ||||
| #define BOOT_REQUEST_DFU 0xDF00B000 | ||||
|  | ||||
| void api_hal_boot_set_mode(ApiHalBootMode mode) { | ||||
|     if (mode == ApiHalBootModeNormal) { | ||||
|         LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR0, BOOT_REQUEST_NONE); | ||||
|     } else if (mode == ApiHalBootModeDFU) { | ||||
|         LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR0, BOOT_REQUEST_DFU); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										78
									
								
								firmware/targets/f5/api-hal/api-hal-bt.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								firmware/targets/f5/api-hal/api-hal-bt.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,78 @@ | ||||
| #include <api-hal-bt.h> | ||||
| #include <app_entry.h> | ||||
| #include <ble.h> | ||||
| #include <stm32wbxx.h> | ||||
| #include <shci.h> | ||||
| #include <cmsis_os2.h> | ||||
|  | ||||
| void api_hal_bt_init() { | ||||
|     // Explicitly tell that we are in charge of CLK48 domain | ||||
|     HAL_HSEM_FastTake(CFG_HW_CLK48_CONFIG_SEMID); | ||||
|     // Start Core2, init HCI and start GAP/GATT | ||||
|     APPE_Init(); | ||||
| } | ||||
|  | ||||
| void api_hal_bt_dump_state(string_t buffer) { | ||||
|     BleGlueStatus status = APPE_Status(); | ||||
|     if (status == BleGlueStatusStarted) { | ||||
|         uint8_t HCI_Version; | ||||
|         uint16_t HCI_Revision; | ||||
|         uint8_t LMP_PAL_Version; | ||||
|         uint16_t Manufacturer_Name; | ||||
|         uint16_t LMP_PAL_Subversion; | ||||
|  | ||||
|         tBleStatus ret = hci_read_local_version_information( | ||||
|             &HCI_Version, &HCI_Revision, &LMP_PAL_Version, &Manufacturer_Name, &LMP_PAL_Subversion | ||||
|         ); | ||||
|  | ||||
|         string_cat_printf(buffer, | ||||
|             "Ret: %d, HCI_Version: %d, HCI_Revision: %d, LMP_PAL_Version: %d, Manufacturer_Name: %d, LMP_PAL_Subversion: %d", | ||||
|             ret, HCI_Version, HCI_Revision, LMP_PAL_Version, Manufacturer_Name, LMP_PAL_Subversion | ||||
|         ); | ||||
|     } else { | ||||
|         string_cat_printf(buffer, "BLE not ready"); | ||||
|     } | ||||
| } | ||||
|  | ||||
| bool api_hal_bt_is_alive() { | ||||
|     return APPE_Status() == BleGlueStatusStarted; | ||||
| } | ||||
|  | ||||
| bool api_hal_bt_wait_transition() { | ||||
|     uint8_t counter = 0; | ||||
|     while (APPE_Status() == BleGlueStatusStartup) { | ||||
|         osDelay(10); | ||||
|         counter++; | ||||
|         if (counter > 1000) { | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| bool api_hal_bt_lock_flash() { | ||||
|     if (!api_hal_bt_wait_transition()) { | ||||
|         return false; | ||||
|     } | ||||
|     if (APPE_Status() == BleGlueStatusUninitialized) { | ||||
|         HAL_FLASH_Unlock(); | ||||
|     } else { | ||||
|         while (HAL_HSEM_FastTake(CFG_HW_FLASH_SEMID) != HAL_OK) { | ||||
|             osDelay(1); | ||||
|         } | ||||
|         SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_ON); | ||||
|         HAL_FLASH_Unlock(); | ||||
|         while(LL_FLASH_IsOperationSuspended()) {}; | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| void api_hal_bt_unlock_flash() { | ||||
|     if (APPE_Status() == BleGlueStatusUninitialized) { | ||||
|         HAL_FLASH_Lock(); | ||||
|     } else { | ||||
|         SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_OFF); | ||||
|         HAL_FLASH_Lock(); | ||||
|         HAL_HSEM_Release(CFG_HW_FLASH_SEMID, HSEM_CPU1_COREID); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										27
									
								
								firmware/targets/f5/api-hal/api-hal-clock.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								firmware/targets/f5/api-hal/api-hal-clock.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| #include <api-hal-clock.h> | ||||
|  | ||||
| #include <stm32wbxx_ll_rcc.h> | ||||
|  | ||||
| void api_hal_clock_switch_to_hsi() { | ||||
|     LL_RCC_HSI_Enable( ); | ||||
|  | ||||
|     while(!LL_RCC_HSI_IsReady()); | ||||
|  | ||||
|     LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSI); | ||||
|     LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSI); | ||||
|  | ||||
|     while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSI); | ||||
| } | ||||
|  | ||||
| void api_hal_clock_switch_to_pll() { | ||||
|     LL_RCC_HSE_Enable(); | ||||
|     LL_RCC_PLL_Enable(); | ||||
|  | ||||
|     while(!LL_RCC_HSE_IsReady()); | ||||
|     while(!LL_RCC_PLL_IsReady()); | ||||
|  | ||||
|     LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL); | ||||
|     LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSE); | ||||
|  | ||||
|     while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL); | ||||
| } | ||||
							
								
								
									
										7
									
								
								firmware/targets/f5/api-hal/api-hal-clock.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								firmware/targets/f5/api-hal/api-hal-clock.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| #pragma once | ||||
|  | ||||
| /* Switch to HSI clock */ | ||||
| void api_hal_clock_switch_to_hsi(); | ||||
|  | ||||
| /* Switch to PLL clock */ | ||||
| void api_hal_clock_switch_to_pll(); | ||||
							
								
								
									
										27
									
								
								firmware/targets/f5/api-hal/api-hal-delay.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								firmware/targets/f5/api-hal/api-hal-delay.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| #include "api-hal-delay.h" | ||||
| #include "assert.h" | ||||
| #include "cmsis_os2.h" | ||||
|  | ||||
| static uint32_t clk_per_microsecond; | ||||
|  | ||||
| void delay_us_init_DWT(void) { | ||||
|     CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; | ||||
|     DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; | ||||
|     DWT->CYCCNT = 0U; | ||||
|     clk_per_microsecond = SystemCoreClock / 1000000.0f; | ||||
| } | ||||
|  | ||||
| void delay_us(float microseconds) { | ||||
|     uint32_t start = DWT->CYCCNT; | ||||
|     uint32_t time_ticks = microseconds * clk_per_microsecond; | ||||
|     while((DWT->CYCCNT - start) < time_ticks) { | ||||
|     }; | ||||
| } | ||||
|  | ||||
| // cannot be used in ISR | ||||
| // TODO add delay_ISR variant | ||||
| void delay(float milliseconds) { | ||||
|     uint32_t ticks = milliseconds / (1000.0f / osKernelGetTickFreq()); | ||||
|     osStatus_t result = osDelay(ticks); | ||||
|     assert(result == osOK); | ||||
| } | ||||
							
								
								
									
										35
									
								
								firmware/targets/f5/api-hal/api-hal-flash.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								firmware/targets/f5/api-hal/api-hal-flash.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| #include <api-hal-flash.h> | ||||
| #include <api-hal-bt.h> | ||||
| #include <stm32wbxx.h> | ||||
|  | ||||
| bool api_hal_flash_erase(uint8_t page, uint8_t count) { | ||||
|     if (!api_hal_bt_lock_flash()) { | ||||
|         return false; | ||||
|     } | ||||
|     FLASH_EraseInitTypeDef erase; | ||||
|     erase.TypeErase = FLASH_TYPEERASE_PAGES; | ||||
|     erase.Page = page; | ||||
|     erase.NbPages = count; | ||||
|     uint32_t error; | ||||
|     HAL_StatusTypeDef status = HAL_FLASHEx_Erase(&erase, &error); | ||||
|     api_hal_bt_unlock_flash(); | ||||
|     return status == HAL_OK; | ||||
| } | ||||
|  | ||||
| bool api_hal_flash_write_dword(size_t address, uint64_t data) { | ||||
|     if (!api_hal_bt_lock_flash()) { | ||||
|         return false; | ||||
|     } | ||||
|     HAL_StatusTypeDef status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, address, data); | ||||
|     api_hal_bt_unlock_flash(); | ||||
|     return status == HAL_OK; | ||||
| } | ||||
|  | ||||
| bool api_hal_flash_write_row(size_t address, size_t source_address) { | ||||
|     if (!api_hal_bt_lock_flash()) { | ||||
|         return false; | ||||
|     } | ||||
|     HAL_StatusTypeDef status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_FAST, address, source_address); | ||||
|     api_hal_bt_unlock_flash(); | ||||
|     return status == HAL_OK; | ||||
| } | ||||
							
								
								
									
										29
									
								
								firmware/targets/f5/api-hal/api-hal-flash.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								firmware/targets/f5/api-hal/api-hal-flash.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <stdbool.h> | ||||
| #include <stdint.h> | ||||
| #include <stddef.h> | ||||
|  | ||||
| /* | ||||
|  * Erase Flash | ||||
|  * Locking operation, uses HSEM to manage shared access. | ||||
|  * @param page, page number | ||||
|  * @param count, page count to erase | ||||
|  */ | ||||
| bool api_hal_flash_erase(uint8_t page, uint8_t count); | ||||
|  | ||||
| /* | ||||
|  * Write double word (64 bits) | ||||
|  * Locking operation, uses HSEM to manage shared access. | ||||
|  * @param address - destination address, must be double word aligned. | ||||
|  * @param data - data to write | ||||
|  */ | ||||
| bool api_hal_flash_write_dword(size_t address, uint64_t data); | ||||
|  | ||||
| /* | ||||
|  * Write page (4096 bytes or 64 rows of double words). | ||||
|  * Locking operation, uses HSEM to manage shared access. | ||||
|  * @param address - destination address, must be page aligned | ||||
|  * @param source_address - source address | ||||
|  */ | ||||
| bool api_hal_flash_write_page(size_t address, size_t source_address); | ||||
							
								
								
									
										53
									
								
								firmware/targets/f5/api-hal/api-hal-gpio.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								firmware/targets/f5/api-hal/api-hal-gpio.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | ||||
| #include <api-hal-gpio.h> | ||||
| #include <api-hal-spi.h> | ||||
| #include <api-hal-resources.h> | ||||
| #include <api-hal-delay.h> | ||||
|  | ||||
| // init GPIO | ||||
| void hal_gpio_init( | ||||
|     const GpioPin* gpio, | ||||
|     const GpioMode mode, | ||||
|     const GpioPull pull, | ||||
|     const GpioSpeed speed) { | ||||
|     // TODO: Alternate Functions | ||||
|     GPIO_InitTypeDef GPIO_InitStruct = {0}; | ||||
|  | ||||
|     GPIO_InitStruct.Pin = gpio->pin; | ||||
|     GPIO_InitStruct.Mode = mode; | ||||
|     GPIO_InitStruct.Pull = pull; | ||||
|     GPIO_InitStruct.Speed = speed; | ||||
|  | ||||
|     HAL_GPIO_Init(gpio->port, &GPIO_InitStruct); | ||||
| } | ||||
|  | ||||
| bool hal_gpio_read_sd_detect(void) { | ||||
|     bool result = false; | ||||
|  | ||||
|     // TODO open record | ||||
|     const GpioPin* sd_cs_record = &sd_cs_gpio; | ||||
|  | ||||
|     // TODO: SPI manager | ||||
|     api_hal_spi_lock(sd_fast_spi.spi); | ||||
|  | ||||
|     // configure pin as input | ||||
|     gpio_init_ex(sd_cs_record, GpioModeInput, GpioPullUp, GpioSpeedVeryHigh); | ||||
|     delay(1); | ||||
|  | ||||
|     // if gpio_read == 0 return true else return false | ||||
|     result = !gpio_read(sd_cs_record); | ||||
|  | ||||
|     // configure pin back | ||||
|     gpio_init_ex(sd_cs_record, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); | ||||
|     gpio_write(sd_cs_record, 1); | ||||
|     delay(1); | ||||
|  | ||||
|     // TODO: SPI manager | ||||
|     api_hal_spi_unlock(sd_fast_spi.spi); | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| void enable_cc1101_irq() { | ||||
|     HAL_NVIC_SetPriority(EXTI4_IRQn, 5, 0); | ||||
|     HAL_NVIC_EnableIRQ(EXTI4_IRQn); | ||||
| } | ||||
							
								
								
									
										77
									
								
								firmware/targets/f5/api-hal/api-hal-gpio.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								firmware/targets/f5/api-hal/api-hal-gpio.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,77 @@ | ||||
| #pragma once | ||||
| #include "main.h" | ||||
| #include "stdbool.h" | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| // this defined in xx_hal_gpio.c, so... | ||||
| #define GPIO_NUMBER (16U) | ||||
|  | ||||
| typedef enum { | ||||
|     GpioModeInput = GPIO_MODE_INPUT, | ||||
|     GpioModeOutputPushPull = GPIO_MODE_OUTPUT_PP, | ||||
|     GpioModeOutputOpenDrain = GPIO_MODE_OUTPUT_OD, | ||||
|     GpioModeAltFunctionPushPull = GPIO_MODE_AF_PP, | ||||
|     GpioModeAltFunctionOpenDrain = GPIO_MODE_AF_OD, | ||||
|     GpioModeAnalog = GPIO_MODE_ANALOG, | ||||
|     GpioModeInterruptRise = GPIO_MODE_IT_RISING, | ||||
|     GpioModeInterruptFall = GPIO_MODE_IT_FALLING, | ||||
|     GpioModeInterruptRiseFall = GPIO_MODE_IT_RISING_FALLING, | ||||
|     GpioModeEventRise = GPIO_MODE_EVT_RISING, | ||||
|     GpioModeEventFall = GPIO_MODE_EVT_FALLING, | ||||
|     GpioModeEventRiseFall = GPIO_MODE_EVT_RISING_FALLING, | ||||
| } GpioMode; | ||||
|  | ||||
| typedef enum { | ||||
|     GpioSpeedLow = GPIO_SPEED_FREQ_LOW, | ||||
|     GpioSpeedMedium = GPIO_SPEED_FREQ_MEDIUM, | ||||
|     GpioSpeedHigh = GPIO_SPEED_FREQ_HIGH, | ||||
|     GpioSpeedVeryHigh = GPIO_SPEED_FREQ_VERY_HIGH, | ||||
| } GpioSpeed; | ||||
|  | ||||
| typedef enum { | ||||
|     GpioPullNo = GPIO_NOPULL, | ||||
|     GpioPullUp = GPIO_PULLUP, | ||||
|     GpioPullDown = GPIO_PULLDOWN, | ||||
| } GpioPull; | ||||
|  | ||||
| typedef struct { | ||||
|     GPIO_TypeDef* port; | ||||
|     uint16_t pin; | ||||
| } GpioPin; | ||||
|  | ||||
| // init GPIO | ||||
| void hal_gpio_init( | ||||
|     const GpioPin* gpio, | ||||
|     const GpioMode mode, | ||||
|     const GpioPull pull, | ||||
|     const GpioSpeed speed); | ||||
|  | ||||
| // write value to GPIO, false = LOW, true = HIGH | ||||
| static inline void hal_gpio_write(const GpioPin* gpio, const bool state) { | ||||
|     // writing to BSSR is an atomic operation | ||||
|     if(state == true) { | ||||
|         gpio->port->BSRR = gpio->pin; | ||||
|     } else { | ||||
|         gpio->port->BSRR = (uint32_t)gpio->pin << GPIO_NUMBER; | ||||
|     } | ||||
| } | ||||
|  | ||||
| // read value from GPIO, false = LOW, true = HIGH | ||||
| static inline bool hal_gpio_read(const GpioPin* gpio) { | ||||
|     if((gpio->port->IDR & gpio->pin) != 0x00U) { | ||||
|         return true; | ||||
|     } else { | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
|  | ||||
| bool hal_gpio_read_sd_detect(void); | ||||
|  | ||||
| void enable_cc1101_irq(); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										17
									
								
								firmware/targets/f5/api-hal/api-hal-i2c.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								firmware/targets/f5/api-hal/api-hal-i2c.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| #include <api-hal-i2c.h> | ||||
| #include <furi.h> | ||||
|  | ||||
| osMutexId_t api_hal_i2c_mutex = NULL; | ||||
|  | ||||
| void api_hal_i2c_init() { | ||||
|     api_hal_i2c_mutex = osMutexNew(NULL); | ||||
|     furi_check(api_hal_i2c_mutex); | ||||
| } | ||||
|  | ||||
| void api_hal_i2c_lock() { | ||||
|     furi_check(osMutexAcquire(api_hal_i2c_mutex, osWaitForever) == osOK); | ||||
| } | ||||
|  | ||||
| void api_hal_i2c_unlock() { | ||||
|     furi_check(osMutexRelease(api_hal_i2c_mutex) == osOK); | ||||
| } | ||||
							
								
								
									
										43
									
								
								firmware/targets/f5/api-hal/api-hal-light.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								firmware/targets/f5/api-hal/api-hal-light.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| #include <api-hal-light.h> | ||||
| #include <lp5562.h> | ||||
|  | ||||
| #define LED_CURRENT_RED     50 | ||||
| #define LED_CURRENT_GREEN   50 | ||||
| #define LED_CURRENT_BLUE    50 | ||||
| #define LED_CURRENT_WHITE   150 | ||||
|  | ||||
| void api_hal_light_init() { | ||||
|     lp5562_reset(); | ||||
|  | ||||
|     lp5562_set_channel_current(LP5562ChannelRed, LED_CURRENT_RED); | ||||
|     lp5562_set_channel_current(LP5562ChannelGreen, LED_CURRENT_GREEN); | ||||
|     lp5562_set_channel_current(LP5562ChannelBlue, LED_CURRENT_BLUE); | ||||
|     lp5562_set_channel_current(LP5562ChannelWhite, LED_CURRENT_WHITE); | ||||
|  | ||||
|     lp5562_set_channel_value(LP5562ChannelRed, 0x00); | ||||
|     lp5562_set_channel_value(LP5562ChannelGreen, 0x00); | ||||
|     lp5562_set_channel_value(LP5562ChannelBlue, 0x00); | ||||
|     lp5562_set_channel_value(LP5562ChannelWhite, 0x00); | ||||
|  | ||||
|     lp5562_enable(); | ||||
|     lp5562_configure(); | ||||
| } | ||||
|  | ||||
| void api_hal_light_set(Light light, uint8_t value) { | ||||
|     switch(light) { | ||||
|         case LightRed: | ||||
|             lp5562_set_channel_value(LP5562ChannelRed, value); | ||||
|         break; | ||||
|         case LightGreen: | ||||
|             lp5562_set_channel_value(LP5562ChannelGreen, value); | ||||
|         break; | ||||
|         case LightBlue: | ||||
|             lp5562_set_channel_value(LP5562ChannelBlue, value); | ||||
|         break; | ||||
|         case LightBacklight: | ||||
|             lp5562_set_channel_value(LP5562ChannelWhite, value); | ||||
|         break; | ||||
|         default: | ||||
|         break; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										95
									
								
								firmware/targets/f5/api-hal/api-hal-os-timer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								firmware/targets/f5/api-hal/api-hal-os-timer.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,95 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <stm32wbxx_ll_lptim.h> | ||||
| #include <stdbool.h> | ||||
|  | ||||
| static inline void assert(bool value) { | ||||
|     if (!value) asm("bkpt 1"); | ||||
| } | ||||
|  | ||||
| // Timer used for system ticks | ||||
| #define API_HAL_OS_TIMER_MAX  0xFFFF | ||||
| #define API_HAL_OS_TIMER_REG_LOAD_DLY 0x1 | ||||
| #define API_HAL_OS_TIMER       LPTIM2 | ||||
| #define API_HAL_OS_TIMER_IRQ   LPTIM2_IRQn | ||||
| #define API_HAL_OS_TIMER_CLOCK_INIT() \ | ||||
| { \ | ||||
|     LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM2_CLKSOURCE_LSE); \ | ||||
|     LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPTIM2); \ | ||||
| } \ | ||||
|  | ||||
| static inline void api_hal_os_timer_init() { | ||||
|     API_HAL_OS_TIMER_CLOCK_INIT(); | ||||
|  | ||||
|     LL_LPTIM_Enable(API_HAL_OS_TIMER); | ||||
|     while(!LL_LPTIM_IsEnabled(API_HAL_OS_TIMER)) {} | ||||
|  | ||||
|     LL_LPTIM_SetClockSource(API_HAL_OS_TIMER, LL_LPTIM_CLK_SOURCE_INTERNAL); | ||||
|     LL_LPTIM_SetPrescaler(API_HAL_OS_TIMER, LL_LPTIM_PRESCALER_DIV1); | ||||
|     LL_LPTIM_SetPolarity(API_HAL_OS_TIMER, LL_LPTIM_OUTPUT_POLARITY_REGULAR); | ||||
|     LL_LPTIM_SetUpdateMode(API_HAL_OS_TIMER, LL_LPTIM_UPDATE_MODE_IMMEDIATE); | ||||
|     LL_LPTIM_SetCounterMode(API_HAL_OS_TIMER, LL_LPTIM_COUNTER_MODE_INTERNAL); | ||||
|     LL_LPTIM_TrigSw(API_HAL_OS_TIMER); | ||||
|     LL_LPTIM_SetInput1Src(API_HAL_OS_TIMER, LL_LPTIM_INPUT1_SRC_GPIO); | ||||
|     LL_LPTIM_SetInput2Src(API_HAL_OS_TIMER, LL_LPTIM_INPUT2_SRC_GPIO); | ||||
|  | ||||
|     NVIC_SetPriority(API_HAL_OS_TIMER_IRQ, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 15, 0)); | ||||
|     NVIC_EnableIRQ(API_HAL_OS_TIMER_IRQ); | ||||
| } | ||||
|  | ||||
| static inline uint32_t api_hal_os_timer_get_cnt() { | ||||
|     uint32_t counter = LL_LPTIM_GetCounter(API_HAL_OS_TIMER); | ||||
|     uint32_t counter_shadow = LL_LPTIM_GetCounter(API_HAL_OS_TIMER); | ||||
|     while(counter != counter_shadow) { | ||||
|         counter = counter_shadow; | ||||
|         counter_shadow = LL_LPTIM_GetCounter(API_HAL_OS_TIMER); | ||||
|     } | ||||
|     return counter; | ||||
| } | ||||
|  | ||||
| static inline bool api_hal_os_timer_arr_is_ok() { | ||||
|     return LL_LPTIM_IsActiveFlag_ARROK(API_HAL_OS_TIMER); | ||||
| } | ||||
|  | ||||
| static inline uint32_t api_hal_os_timer_get_arr() { | ||||
|     return LL_LPTIM_GetAutoReload(API_HAL_OS_TIMER);; | ||||
| } | ||||
|  | ||||
| static inline void api_hal_os_timer_set_arr(uint32_t value) { | ||||
|     value &= API_HAL_OS_TIMER_MAX; | ||||
|     if (value != api_hal_os_timer_get_arr()) { | ||||
|         assert(api_hal_os_timer_arr_is_ok()); | ||||
|         LL_LPTIM_ClearFlag_ARROK(API_HAL_OS_TIMER); | ||||
|         LL_LPTIM_SetAutoReload(API_HAL_OS_TIMER, value); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static inline bool api_hal_os_timer_cmp_is_ok() { | ||||
|     return LL_LPTIM_IsActiveFlag_CMPOK(API_HAL_OS_TIMER); | ||||
| } | ||||
|  | ||||
| static inline uint32_t api_hal_os_timer_get_cmp() { | ||||
|     return LL_LPTIM_GetCompare(API_HAL_OS_TIMER); | ||||
| } | ||||
|  | ||||
| static inline void api_hal_os_timer_set_cmp(uint32_t value) { | ||||
|     value &= API_HAL_OS_TIMER_MAX; | ||||
|     if (value != api_hal_os_timer_get_cmp()) { | ||||
|         assert(api_hal_os_timer_cmp_is_ok()); | ||||
|         LL_LPTIM_ClearFlag_CMPOK(API_HAL_OS_TIMER); | ||||
|         LL_LPTIM_SetCompare(API_HAL_OS_TIMER, value); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static inline bool api_hal_os_timer_is_safe() { | ||||
|     uint16_t cmp = api_hal_os_timer_get_cmp(); | ||||
|     uint16_t cnt = api_hal_os_timer_get_cnt(); | ||||
|     uint16_t margin = (cmp > cnt) ? cmp - cnt : cnt - cmp; | ||||
|     if (margin < 8) { | ||||
|         return false; | ||||
|     } | ||||
|     if (!api_hal_os_timer_cmp_is_ok()) { | ||||
|         return false; | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
							
								
								
									
										169
									
								
								firmware/targets/f5/api-hal/api-hal-os.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								firmware/targets/f5/api-hal/api-hal-os.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,169 @@ | ||||
| #include <api-hal-os.h> | ||||
| #include <api-hal-os-timer.h> | ||||
| #include <api-hal-power.h> | ||||
|  | ||||
| #include <FreeRTOS.h> | ||||
| #include <cmsis_os.h> | ||||
|  | ||||
| #define API_HAL_OS_CLK_FREQUENCY 32768 | ||||
| #define API_HAL_OS_TICK_PER_SECOND 1024 | ||||
| #define API_HAL_OS_CLK_PER_TICK (API_HAL_OS_CLK_FREQUENCY / API_HAL_OS_TICK_PER_SECOND) | ||||
| #define API_HAL_OS_TICK_PER_EPOCH (API_HAL_OS_TIMER_MAX / API_HAL_OS_CLK_PER_TICK) | ||||
| #define API_HAL_OS_MAX_SLEEP (API_HAL_OS_TICK_PER_EPOCH - 1) | ||||
|  | ||||
| #ifdef API_HAL_OS_DEBUG | ||||
| #include <stm32wbxx_ll_gpio.h> | ||||
| #define LED_GREEN_PORT GPIOA | ||||
| #define LED_GREEN_PIN LL_GPIO_PIN_7 | ||||
| #endif | ||||
|  | ||||
| typedef struct { | ||||
|     // Tick counters | ||||
|     volatile uint32_t in_sleep; | ||||
|     volatile uint32_t in_awake; | ||||
|     // Error counters | ||||
|     volatile uint32_t sleep_error; | ||||
|     volatile uint32_t awake_error; | ||||
| } ApiHalOs; | ||||
|  | ||||
| ApiHalOs api_hal_os = { | ||||
|     .in_sleep = 0, | ||||
|     .in_awake = 0, | ||||
|     .sleep_error = 0, | ||||
|     .awake_error = 0, | ||||
| }; | ||||
|  | ||||
| void api_hal_os_init() { | ||||
|     api_hal_os_timer_init(); | ||||
|     LL_DBGMCU_APB1_GRP2_FreezePeriph(LL_DBGMCU_APB1_GRP2_LPTIM2_STOP); | ||||
|  | ||||
|     LL_LPTIM_EnableIT_CMPM(API_HAL_OS_TIMER); | ||||
|     LL_LPTIM_EnableIT_ARRM(API_HAL_OS_TIMER); | ||||
|  | ||||
|     LL_LPTIM_SetAutoReload(API_HAL_OS_TIMER, API_HAL_OS_TIMER_MAX); | ||||
|     LL_LPTIM_SetCompare(API_HAL_OS_TIMER, API_HAL_OS_CLK_PER_TICK); | ||||
|  | ||||
|     LL_LPTIM_StartCounter(API_HAL_OS_TIMER, LL_LPTIM_OPERATING_MODE_CONTINUOUS); | ||||
| } | ||||
|  | ||||
| void LPTIM2_IRQHandler(void) { | ||||
|     // Autoreload | ||||
|     const bool arrm_flag = LL_LPTIM_IsActiveFlag_ARRM(API_HAL_OS_TIMER); | ||||
|     if(arrm_flag) { | ||||
|         LL_LPTIM_ClearFLAG_ARRM(API_HAL_OS_TIMER); | ||||
|     } | ||||
|     if(LL_LPTIM_IsActiveFlag_CMPM(API_HAL_OS_TIMER)) { | ||||
|         LL_LPTIM_ClearFLAG_CMPM(API_HAL_OS_TIMER); | ||||
|  | ||||
|         // Store important value | ||||
|         uint16_t cnt = api_hal_os_timer_get_cnt(); | ||||
|         uint16_t cmp = api_hal_os_timer_get_cmp(); | ||||
|         uint16_t current_tick = cnt / API_HAL_OS_CLK_PER_TICK; | ||||
|         uint16_t compare_tick = cmp / API_HAL_OS_CLK_PER_TICK; | ||||
|  | ||||
|         // Calculate error | ||||
|         // happens when HAL or other high priority IRQ takes our time | ||||
|         int32_t error = (int32_t)compare_tick - current_tick; | ||||
|         api_hal_os.awake_error += ((error>0) ? error : -error); | ||||
|  | ||||
|         // Calculate and set next tick  | ||||
|         uint16_t next_tick = current_tick + 1; | ||||
|         api_hal_os_timer_set_cmp(next_tick * API_HAL_OS_CLK_PER_TICK); | ||||
|  | ||||
|         // Notify OS | ||||
|         api_hal_os.in_awake ++; | ||||
|         if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { | ||||
|             xPortSysTickHandler(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| static inline uint32_t api_hal_os_sleep(TickType_t expected_idle_ticks) { | ||||
|     // Store important value before going to sleep | ||||
|     const uint16_t before_cnt = api_hal_os_timer_get_cnt(); | ||||
|     const uint16_t before_tick = before_cnt / API_HAL_OS_CLK_PER_TICK; | ||||
|  | ||||
|     // Calculate and set next wakeup compare value | ||||
|     const uint16_t expected_cnt = (before_tick + expected_idle_ticks - 2) * API_HAL_OS_CLK_PER_TICK; | ||||
|     api_hal_os_timer_set_cmp(expected_cnt); | ||||
|  | ||||
|     HAL_SuspendTick(); | ||||
|     // Go to stop2 mode | ||||
| #ifdef API_HAL_OS_DEBUG | ||||
|     LL_GPIO_SetOutputPin(LED_GREEN_PORT, LED_GREEN_PIN); | ||||
| #endif | ||||
|     api_hal_power_deep_sleep(); | ||||
| #ifdef API_HAL_OS_DEBUG | ||||
|     LL_GPIO_ResetOutputPin(LED_GREEN_PORT, LED_GREEN_PIN); | ||||
| #endif | ||||
|  | ||||
|     HAL_ResumeTick(); | ||||
|  | ||||
|     // Spin till we are in timer safe zone | ||||
|     while(!api_hal_os_timer_is_safe()) {} | ||||
|  | ||||
|     // Store current counter value, calculate current tick | ||||
|     const uint16_t after_cnt = api_hal_os_timer_get_cnt(); | ||||
|     const uint16_t after_tick = after_cnt / API_HAL_OS_CLK_PER_TICK; | ||||
|  | ||||
|     // Store and clear interrupt flags | ||||
|     // we don't want handler to be called after renabling IRQ | ||||
|     bool arrm_flag = LL_LPTIM_IsActiveFlag_ARRM(API_HAL_OS_TIMER); | ||||
|  | ||||
|     // Calculate and set next wakeup compare value | ||||
|     const uint16_t next_cmp = (after_tick + 1) * API_HAL_OS_CLK_PER_TICK; | ||||
|     api_hal_os_timer_set_cmp(next_cmp); | ||||
|  | ||||
|     // Calculate ticks count spent in sleep and perform sanity checks | ||||
|     int32_t completed_ticks = arrm_flag ? (int32_t)before_tick - after_tick : (int32_t)after_tick - before_tick; | ||||
|  | ||||
|     return completed_ticks; | ||||
| } | ||||
|  | ||||
| void vPortSuppressTicksAndSleep(TickType_t expected_idle_ticks) { | ||||
|     if (!api_hal_power_deep_available()) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     // Limit mount of ticks to maximum that timer can count | ||||
|     if (expected_idle_ticks > API_HAL_OS_MAX_SLEEP) { | ||||
|         expected_idle_ticks = API_HAL_OS_MAX_SLEEP; | ||||
|     } | ||||
|  | ||||
|     // Stop IRQ handling, no one should disturb us till we finish  | ||||
|     __disable_irq(); | ||||
|  | ||||
|     // Confirm OS that sleep is still possible | ||||
|     // And check if timer is in safe zone | ||||
|     // (8 clocks till any IRQ event or ongoing synchronization) | ||||
|     if (eTaskConfirmSleepModeStatus() == eAbortSleep | ||||
|         || !api_hal_os_timer_is_safe()) { | ||||
|         __enable_irq(); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     uint32_t completed_ticks = api_hal_os_sleep(expected_idle_ticks); | ||||
|     assert(completed_ticks >= 0); | ||||
|  | ||||
|     // Reenable IRQ | ||||
|     __enable_irq(); | ||||
|  | ||||
|     // Notify system about time spent in sleep | ||||
|     if (completed_ticks > 0) { | ||||
|         api_hal_os.in_sleep += completed_ticks; | ||||
|         if (completed_ticks > expected_idle_ticks) { | ||||
|             // We are late, count error | ||||
|             api_hal_os.sleep_error += (completed_ticks - expected_idle_ticks); | ||||
|             // Freertos is not happy when we overleep | ||||
|             // But we are not going to tell her | ||||
|             vTaskStepTick(expected_idle_ticks); | ||||
|         } else { | ||||
|             vTaskStepTick(completed_ticks); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| void vApplicationStackOverflowHook(TaskHandle_t xTask, signed char *pcTaskName) { | ||||
|     asm("bkpt 1"); | ||||
|     while(1) {}; | ||||
| } | ||||
							
								
								
									
										17
									
								
								firmware/targets/f5/api-hal/api-hal-os.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								firmware/targets/f5/api-hal/api-hal-os.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <stdint.h> | ||||
|  | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| /* Initialize OS helpers | ||||
|  * Configure and start tick timer | ||||
|  */ | ||||
| void api_hal_os_init(); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										194
									
								
								firmware/targets/f5/api-hal/api-hal-power.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										194
									
								
								firmware/targets/f5/api-hal/api-hal-power.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,194 @@ | ||||
| #include <api-hal-power.h> | ||||
| #include <api-hal-clock.h> | ||||
| #include <api-hal-bt.h> | ||||
|  | ||||
| #include <stm32wbxx_ll_rcc.h> | ||||
| #include <stm32wbxx_ll_pwr.h> | ||||
| #include <stm32wbxx_ll_hsem.h> | ||||
| #include <stm32wbxx_ll_cortex.h> | ||||
|  | ||||
| #include <main.h> | ||||
| #include <hw_conf.h> | ||||
| #include <bq27220.h> | ||||
| #include <bq25896.h> | ||||
|  | ||||
| volatile uint32_t api_hal_power_insomnia = 1; | ||||
|  | ||||
| void HAL_RCC_CSSCallback(void) { | ||||
|     LL_RCC_ForceBackupDomainReset(); | ||||
|     LL_RCC_ReleaseBackupDomainReset(); | ||||
|     NVIC_SystemReset(); | ||||
| } | ||||
|  | ||||
| void api_hal_power_init() { | ||||
|     LL_PWR_SMPS_SetMode(LL_PWR_SMPS_STEP_DOWN); | ||||
|     bq27220_init(); | ||||
|     bq25896_init(); | ||||
| } | ||||
|  | ||||
| uint16_t api_hal_power_insomnia_level() { | ||||
|     return api_hal_power_insomnia; | ||||
| } | ||||
|  | ||||
| void api_hal_power_insomnia_enter() { | ||||
|     api_hal_power_insomnia++; | ||||
| } | ||||
|  | ||||
| void api_hal_power_insomnia_exit() { | ||||
|     api_hal_power_insomnia--; | ||||
| } | ||||
|  | ||||
| bool api_hal_power_deep_available() { | ||||
|     return api_hal_bt_is_alive() && api_hal_power_insomnia == 0; | ||||
| } | ||||
|  | ||||
| void api_hal_power_deep_sleep() { | ||||
|   while( LL_HSEM_1StepLock(HSEM, CFG_HW_RCC_SEMID)); | ||||
|  | ||||
|   if (!LL_HSEM_1StepLock(HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID)) { | ||||
|         if(LL_PWR_IsActiveFlag_C2DS()) { | ||||
|             // Release ENTRY_STOP_MODE semaphore | ||||
|             LL_HSEM_ReleaseLock(HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID, 0); | ||||
|  | ||||
|             // The switch on HSI before entering Stop Mode is required  | ||||
|             api_hal_clock_switch_to_hsi(); | ||||
|         } | ||||
|     } else { | ||||
|         /** | ||||
|          * The switch on HSI before entering Stop Mode is required  | ||||
|          */ | ||||
|         api_hal_clock_switch_to_hsi(); | ||||
|     } | ||||
|  | ||||
|     /* Release RCC semaphore */ | ||||
|     LL_HSEM_ReleaseLock(HSEM, CFG_HW_RCC_SEMID, 0); | ||||
|  | ||||
|     // Prepare deep sleep | ||||
|     LL_PWR_SetPowerMode(LL_PWR_MODE_STOP2); | ||||
|     LL_LPM_EnableDeepSleep(); | ||||
|  | ||||
| #if defined ( __CC_ARM) | ||||
|     // Force store operations | ||||
|     __force_stores(); | ||||
| #endif | ||||
|  | ||||
|     __WFI(); | ||||
|  | ||||
|     /* Release ENTRY_STOP_MODE semaphore */ | ||||
|     LL_HSEM_ReleaseLock(HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID, 0); | ||||
|  | ||||
|     while(LL_HSEM_1StepLock(HSEM, CFG_HW_RCC_SEMID)); | ||||
|  | ||||
|     if(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) { | ||||
|         api_hal_clock_switch_to_pll(); | ||||
|     } | ||||
|  | ||||
|     LL_HSEM_ReleaseLock(HSEM, CFG_HW_RCC_SEMID, 0); | ||||
| } | ||||
|  | ||||
| uint8_t api_hal_power_get_pct() { | ||||
|     return bq27220_get_state_of_charge(); | ||||
| } | ||||
|  | ||||
| bool api_hal_power_is_charging() { | ||||
|     return bq25896_is_charging(); | ||||
| } | ||||
|  | ||||
| void api_hal_power_off() { | ||||
|     bq25896_poweroff(); | ||||
| } | ||||
|  | ||||
| void api_hal_power_enable_otg() { | ||||
|     bq25896_enable_otg(); | ||||
| } | ||||
|  | ||||
| void api_hal_power_disable_otg() { | ||||
|     bq25896_disable_otg(); | ||||
| } | ||||
|  | ||||
| uint32_t api_hal_power_get_battery_remaining_capacity() { | ||||
|     return bq27220_get_remaining_capacity(); | ||||
| } | ||||
|  | ||||
| uint32_t api_hal_power_get_battery_full_capacity() { | ||||
|     return bq27220_get_full_charge_capacity(); | ||||
| } | ||||
|  | ||||
| float api_hal_power_get_battery_voltage(ApiHalPowerIC ic) { | ||||
|     if (ic == ApiHalPowerICCharger) { | ||||
|         return (float)bq25896_get_vbat_voltage() / 1000.0f; | ||||
|     } else if (ic == ApiHalPowerICFuelGauge) { | ||||
|         return (float)bq27220_get_voltage() / 1000.0f; | ||||
|     } else { | ||||
|         return 0.0f; | ||||
|     } | ||||
| } | ||||
|  | ||||
| float api_hal_power_get_battery_current(ApiHalPowerIC ic) { | ||||
|     if (ic == ApiHalPowerICCharger) { | ||||
|         return (float)bq25896_get_vbat_current() / 1000.0f; | ||||
|     } else if (ic == ApiHalPowerICFuelGauge) { | ||||
|         return (float)bq27220_get_current() / 1000.0f; | ||||
|     } else { | ||||
|         return 0.0f; | ||||
|     } | ||||
| } | ||||
|  | ||||
| float api_hal_power_get_battery_temperature(ApiHalPowerIC ic) { | ||||
|     if (ic == ApiHalPowerICCharger) { | ||||
|         // Linear approximation, +/- 5 C | ||||
|         return (71.0f - (float)bq25896_get_ntc_mpct()/1000) / 0.6f; | ||||
|     } else if (ic == ApiHalPowerICFuelGauge) { | ||||
|         return ((float)bq27220_get_temperature() - 2731.0f) / 10.0f; | ||||
|     } else { | ||||
|         return 0.0f; | ||||
|     } | ||||
|      | ||||
| } | ||||
|  | ||||
| void api_hal_power_dump_state(string_t buffer) { | ||||
|     BatteryStatus battery_status; | ||||
|     OperationStatus operation_status; | ||||
|     if (bq27220_get_battery_status(&battery_status) == BQ27220_ERROR | ||||
|         || bq27220_get_operation_status(&operation_status) == BQ27220_ERROR) { | ||||
|         string_cat_printf(buffer, "Failed to get bq27220 status. Communication error.\r\n"); | ||||
|     } else { | ||||
|         string_cat_printf(buffer, | ||||
|            "bq27220: CALMD: %d, SEC0: %d, SEC1: %d, EDV2: %d, VDQ: %d, INITCOMP: %d, SMTH: %d, BTPINT: %d, CFGUPDATE: %d\r\n", | ||||
|             operation_status.CALMD, operation_status.SEC0, operation_status.SEC1, | ||||
|             operation_status.EDV2, operation_status.VDQ, operation_status.INITCOMP, | ||||
|             operation_status.SMTH, operation_status.BTPINT, operation_status.CFGUPDATE | ||||
|         ); | ||||
|         // Battery status register, part 1 | ||||
|         string_cat_printf(buffer, | ||||
|            "bq27220: CHGINH: %d, FC: %d, OTD: %d, OTC: %d, SLEEP: %d, OCVFAIL: %d, OCVCOMP: %d, FD: %d\r\n", | ||||
|             battery_status.CHGINH, battery_status.FC, battery_status.OTD, | ||||
|             battery_status.OTC, battery_status.SLEEP, battery_status.OCVFAIL, | ||||
|             battery_status.OCVCOMP, battery_status.FD | ||||
|         ); | ||||
|         // Battery status register, part 2 | ||||
|         string_cat_printf(buffer, | ||||
|            "bq27220: DSG: %d, SYSDWN: %d, TDA: %d, BATTPRES: %d, AUTH_GD: %d, OCVGD: %d, TCA: %d, RSVD: %d\r\n", | ||||
|             battery_status.DSG, battery_status.SYSDWN, battery_status.TDA, | ||||
|             battery_status.BATTPRES, battery_status.AUTH_GD, battery_status.OCVGD, | ||||
|             battery_status.TCA, battery_status.RSVD | ||||
|         ); | ||||
|         // Voltage and current info | ||||
|         string_cat_printf(buffer, | ||||
|             "bq27220: Full capacity: %dmAh, Remaining capacity: %dmAh, State of Charge: %d%%\r\n", | ||||
|             bq27220_get_full_charge_capacity(), bq27220_get_remaining_capacity(), | ||||
|             bq27220_get_state_of_charge() | ||||
|         ); | ||||
|         string_cat_printf(buffer, | ||||
|             "bq27220: Voltage: %dmV, Current: %dmA, Temperature: %dC\r\n", | ||||
|             bq27220_get_voltage(), bq27220_get_current(), (int)api_hal_power_get_battery_temperature(ApiHalPowerICFuelGauge) | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     string_cat_printf(buffer, | ||||
|         "bq25896: VBUS: %d, VSYS: %d, VBAT: %d, Current: %d, NTC: %dm%%\r\n", | ||||
|         bq25896_get_vbus_voltage(), bq25896_get_vsys_voltage(), | ||||
|         bq25896_get_vbat_voltage(), bq25896_get_vbat_current(), | ||||
|         bq25896_get_ntc_mpct() | ||||
|     ); | ||||
| } | ||||
							
								
								
									
										57
									
								
								firmware/targets/f5/api-hal/api-hal-pwm.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								firmware/targets/f5/api-hal/api-hal-pwm.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | ||||
| #include "api-hal-pwm.h" | ||||
|  | ||||
| void hal_pwm_set(float value, float freq, TIM_HandleTypeDef* tim, uint32_t channel) { | ||||
|     tim->Init.CounterMode = TIM_COUNTERMODE_UP; | ||||
|     tim->Init.Period = (uint32_t)((SystemCoreClock / (tim->Init.Prescaler + 1)) / freq); | ||||
|     tim->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; | ||||
|     tim->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; | ||||
|     HAL_TIM_PWM_Init(tim); | ||||
|  | ||||
|     TIM_OC_InitTypeDef sConfigOC; | ||||
|  | ||||
|     sConfigOC.OCMode = TIM_OCMODE_PWM1; | ||||
|     sConfigOC.Pulse = (uint16_t)(tim->Init.Period * value); | ||||
|     sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; | ||||
|     sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; | ||||
|     sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; | ||||
|     sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET; | ||||
|     sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET; | ||||
|     HAL_TIM_PWM_ConfigChannel(tim, &sConfigOC, channel); | ||||
|     HAL_TIM_PWM_Start(tim, channel); | ||||
| } | ||||
|  | ||||
| void hal_pwmn_set(float value, float freq, TIM_HandleTypeDef* tim, uint32_t channel) { | ||||
|     tim->Init.CounterMode = TIM_COUNTERMODE_UP; | ||||
|     tim->Init.Period = (uint32_t)((SystemCoreClock / (tim->Init.Prescaler + 1)) / freq - 1); | ||||
|     tim->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; | ||||
|     tim->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; | ||||
|     HAL_TIM_PWM_Init(tim); | ||||
|  | ||||
|     TIM_OC_InitTypeDef sConfigOC; | ||||
|  | ||||
|     sConfigOC.OCMode = TIM_OCMODE_PWM1; | ||||
|     sConfigOC.Pulse = (uint16_t)(tim->Init.Period * value); | ||||
|     sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; | ||||
|     sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; | ||||
|     sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; | ||||
|     sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET; | ||||
|     sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET; | ||||
|     HAL_TIM_PWM_ConfigChannel(tim, &sConfigOC, channel); | ||||
|     HAL_TIMEx_PWMN_Start(tim, channel); | ||||
| } | ||||
|  | ||||
| void hal_pwm_stop(TIM_HandleTypeDef* tim, uint32_t channel) { | ||||
|     HAL_TIM_PWM_Stop(tim, channel); | ||||
| } | ||||
|  | ||||
| void hal_pwmn_stop(TIM_HandleTypeDef* tim, uint32_t channel) { | ||||
|     HAL_TIMEx_PWMN_Stop(tim, channel); | ||||
| } | ||||
|  | ||||
| void irda_pwm_set(float value, float freq){ | ||||
|     hal_pwmn_set(value, freq, &IRDA_TX_TIM, IRDA_TX_CH); | ||||
| } | ||||
|  | ||||
| void irda_pwm_stop(){ | ||||
|     hal_pwmn_stop(&IRDA_TX_TIM, IRDA_TX_CH); | ||||
| } | ||||
							
								
								
									
										11
									
								
								firmware/targets/f5/api-hal/api-hal-pwm.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								firmware/targets/f5/api-hal/api-hal-pwm.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| #pragma once | ||||
| #include "main.h" | ||||
| #include "stdbool.h" | ||||
|  | ||||
| void hal_pwm_set(float value, float freq, TIM_HandleTypeDef* tim, uint32_t channel); | ||||
| void hal_pwmn_set(float value, float freq, TIM_HandleTypeDef* tim, uint32_t channel); | ||||
| void hal_pwm_stop(TIM_HandleTypeDef* tim, uint32_t channel); | ||||
| void hal_pwmn_stop(TIM_HandleTypeDef* tim, uint32_t channel); | ||||
|  | ||||
| void irda_pwm_set(float value, float freq); | ||||
| void irda_pwm_stop(); | ||||
							
								
								
									
										31
									
								
								firmware/targets/f5/api-hal/api-hal-resources.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								firmware/targets/f5/api-hal/api-hal-resources.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| #include <api-hal-resources.h> | ||||
| #include "main.h" | ||||
| #include <furi.h> | ||||
|  | ||||
| const InputPin input_pins[] = { | ||||
|     {.port = BUTTON_UP_GPIO_Port, .pin = BUTTON_UP_Pin, .key = InputKeyUp, .inverted = true}, | ||||
|     {.port = BUTTON_DOWN_GPIO_Port, | ||||
|      .pin = BUTTON_DOWN_Pin, | ||||
|      .key = InputKeyDown, | ||||
|      .inverted = true}, | ||||
|     {.port = BUTTON_RIGHT_GPIO_Port, | ||||
|      .pin = BUTTON_RIGHT_Pin, | ||||
|      .key = InputKeyRight, | ||||
|      .inverted = true}, | ||||
|     {.port = BUTTON_LEFT_GPIO_Port, | ||||
|      .pin = BUTTON_LEFT_Pin, | ||||
|      .key = InputKeyLeft, | ||||
|      .inverted = true}, | ||||
|     {.port = BUTTON_OK_GPIO_Port, .pin = BUTTON_OK_Pin, .key = InputKeyOk, .inverted = false}, | ||||
|     {.port = BUTTON_BACK_GPIO_Port, | ||||
|      .pin = BUTTON_BACK_Pin, | ||||
|      .key = InputKeyBack, | ||||
|      .inverted = true}, | ||||
| }; | ||||
|  | ||||
| const size_t input_pins_count = sizeof(input_pins) / sizeof(InputPin); | ||||
|  | ||||
| const GpioPin sd_cs_gpio = {SD_CS_GPIO_Port, SD_CS_Pin}; | ||||
| const GpioPin vibro_gpio = {VIBRO_GPIO_Port, VIBRO_Pin}; | ||||
| const GpioPin ibutton_gpio = {iBTN_GPIO_Port, iBTN_Pin}; | ||||
| const GpioPin cc1101_g0_gpio = {CC1101_G0_GPIO_Port, CC1101_G0_Pin}; | ||||
							
								
								
									
										48
									
								
								firmware/targets/f5/api-hal/api-hal-resources.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								firmware/targets/f5/api-hal/api-hal-resources.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "main.h" | ||||
| #include <furi.h> | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| /* Input Related Constants */ | ||||
| #define INPUT_DEBOUNCE_TICKS 20 | ||||
|  | ||||
| /* Input Keys */ | ||||
| typedef enum { | ||||
|     InputKeyUp, | ||||
|     InputKeyDown, | ||||
|     InputKeyRight, | ||||
|     InputKeyLeft, | ||||
|     InputKeyOk, | ||||
|     InputKeyBack, | ||||
| } InputKey; | ||||
|  | ||||
| /* Light */ | ||||
| typedef enum { | ||||
|     LightRed, | ||||
|     LightGreen, | ||||
|     LightBlue, | ||||
|     LightBacklight, | ||||
| } Light; | ||||
|  | ||||
| typedef struct { | ||||
|     const GPIO_TypeDef* port; | ||||
|     const uint16_t pin; | ||||
|     const InputKey key; | ||||
|     const bool inverted; | ||||
| } InputPin; | ||||
|  | ||||
| extern const InputPin input_pins[]; | ||||
| extern const size_t input_pins_count; | ||||
|  | ||||
| extern const GpioPin sd_cs_gpio; | ||||
| extern const GpioPin vibro_gpio; | ||||
| extern const GpioPin ibutton_gpio; | ||||
| extern const GpioPin cc1101_g0_gpio; | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										68
									
								
								firmware/targets/f5/api-hal/api-hal-spi-config.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								firmware/targets/f5/api-hal/api-hal-spi-config.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | ||||
| #include "main.h" | ||||
| #include "api-hal-spi-config.h" | ||||
|  | ||||
| extern SPI_HandleTypeDef SPI_R; | ||||
| extern SPI_HandleTypeDef SPI_D; | ||||
|  | ||||
| /** | ||||
|  * SD Card in fast mode (after init) | ||||
|  */ | ||||
| const SPIDevice sd_fast_spi = { | ||||
|     .spi = &SPI_D, | ||||
|     .config = { | ||||
|         .Mode = SPI_MODE_MASTER, | ||||
|         .Direction = SPI_DIRECTION_2LINES, | ||||
|         .DataSize = SPI_DATASIZE_8BIT, | ||||
|         .CLKPolarity = SPI_POLARITY_LOW, | ||||
|         .CLKPhase = SPI_PHASE_1EDGE, | ||||
|         .NSS = SPI_NSS_SOFT, | ||||
|         .BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2, | ||||
|         .FirstBit = SPI_FIRSTBIT_MSB, | ||||
|         .TIMode = SPI_TIMODE_DISABLE, | ||||
|         .CRCCalculation = SPI_CRCCALCULATION_DISABLE, | ||||
|         .CRCPolynomial = 7, | ||||
|         .CRCLength = SPI_CRC_LENGTH_DATASIZE, | ||||
|         .NSSPMode = SPI_NSS_PULSE_ENABLE, | ||||
|     }}; | ||||
|  | ||||
| /** | ||||
|  * SD Card in slow mode (before init) | ||||
|  */ | ||||
| const SPIDevice sd_slow_spi = { | ||||
|     .spi = &SPI_D, | ||||
|     .config = { | ||||
|         .Mode = SPI_MODE_MASTER, | ||||
|         .Direction = SPI_DIRECTION_2LINES, | ||||
|         .DataSize = SPI_DATASIZE_8BIT, | ||||
|         .CLKPolarity = SPI_POLARITY_LOW, | ||||
|         .CLKPhase = SPI_PHASE_1EDGE, | ||||
|         .NSS = SPI_NSS_SOFT, | ||||
|         .BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32, | ||||
|         .FirstBit = SPI_FIRSTBIT_MSB, | ||||
|         .TIMode = SPI_TIMODE_DISABLE, | ||||
|         .CRCCalculation = SPI_CRCCALCULATION_DISABLE, | ||||
|         .CRCPolynomial = 7, | ||||
|         .CRCLength = SPI_CRC_LENGTH_DATASIZE, | ||||
|         .NSSPMode = SPI_NSS_PULSE_ENABLE, | ||||
|     }}; | ||||
|  | ||||
| /** | ||||
|  * Display | ||||
|  */ | ||||
| const SPIDevice display_spi = { | ||||
|     .spi = &SPI_D, | ||||
|     .config = { | ||||
|         .Mode = SPI_MODE_MASTER, | ||||
|         .Direction = SPI_DIRECTION_2LINES, | ||||
|         .DataSize = SPI_DATASIZE_8BIT, | ||||
|         .CLKPolarity = SPI_POLARITY_LOW, | ||||
|         .CLKPhase = SPI_PHASE_1EDGE, | ||||
|         .NSS = SPI_NSS_SOFT, | ||||
|         .BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16, | ||||
|         .FirstBit = SPI_FIRSTBIT_MSB, | ||||
|         .TIMode = SPI_TIMODE_DISABLE, | ||||
|         .CRCCalculation = SPI_CRCCALCULATION_DISABLE, | ||||
|         .CRCPolynomial = 7, | ||||
|         .CRCLength = SPI_CRC_LENGTH_DATASIZE, | ||||
|         .NSSPMode = SPI_NSS_PULSE_ENABLE, | ||||
|     }}; | ||||
							
								
								
									
										18
									
								
								firmware/targets/f5/api-hal/api-hal-spi-config.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								firmware/targets/f5/api-hal/api-hal-spi-config.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| #pragma once | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| typedef struct { | ||||
|     SPI_HandleTypeDef* spi; | ||||
|     const SPI_InitTypeDef config; | ||||
| } SPIDevice; | ||||
|  | ||||
| extern const SPIDevice sd_fast_spi; | ||||
| extern const SPIDevice sd_slow_spi; | ||||
| extern const SPIDevice display_spi; | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										69
									
								
								firmware/targets/f5/api-hal/api-hal-spi.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								firmware/targets/f5/api-hal/api-hal-spi.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | ||||
| #include "api-hal-spi.h" | ||||
| #include <cmsis_os2.h> | ||||
| #include <stdbool.h> | ||||
| #include <string.h> | ||||
|  | ||||
| osMutexId_t spi_mutex_r; | ||||
| osMutexId_t spi_mutex_d; | ||||
|  | ||||
| extern SPI_HandleTypeDef SPI_R; | ||||
| extern SPI_HandleTypeDef SPI_D; | ||||
| extern void Enable_SPI(SPI_HandleTypeDef* spi); | ||||
|  | ||||
| void api_hal_spi_init() { | ||||
|     spi_mutex_r = osMutexNew(NULL); | ||||
|     spi_mutex_d = osMutexNew(NULL); | ||||
| } | ||||
|  | ||||
| void api_hal_spi_apply_config(const SPIDevice* device) { | ||||
|     osKernelLock(); | ||||
|  | ||||
|     memcpy(&device->spi->Init, &device->config, sizeof(SPI_InitTypeDef)); | ||||
|  | ||||
|     if(HAL_SPI_Init(device->spi) != HAL_OK) { | ||||
|         Error_Handler(); | ||||
|     } | ||||
|  | ||||
|     Enable_SPI(device->spi); | ||||
|  | ||||
|     osKernelUnlock(); | ||||
| } | ||||
|  | ||||
| bool api_hal_spi_config_are_actual(const SPIDevice* device) { | ||||
|     return (memcmp(&device->config, &device->spi->Init, sizeof(SPI_InitTypeDef)) == 0); | ||||
| } | ||||
|  | ||||
| void api_hal_spi_config_device(const SPIDevice* device) { | ||||
|     if(!api_hal_spi_config_are_actual(device)) { | ||||
|         api_hal_spi_apply_config(device); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void api_hal_spi_lock(SPI_HandleTypeDef* spi) { | ||||
|     if(spi == &SPI_D) { | ||||
|         osMutexAcquire(spi_mutex_d, osWaitForever); | ||||
|     } else if(spi == &SPI_R) { | ||||
|         osMutexAcquire(spi_mutex_r, osWaitForever); | ||||
|     } else { | ||||
|         Error_Handler(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void api_hal_spi_unlock(SPI_HandleTypeDef* spi) { | ||||
|     if(spi == &SPI_D) { | ||||
|         osMutexRelease(spi_mutex_d); | ||||
|     } else if(spi == &SPI_R) { | ||||
|         osMutexRelease(spi_mutex_r); | ||||
|     } else { | ||||
|         Error_Handler(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void api_hal_spi_lock_device(const SPIDevice* device) { | ||||
|     api_hal_spi_lock(device->spi); | ||||
|     api_hal_spi_config_device(device); | ||||
| } | ||||
|  | ||||
| void api_hal_spi_unlock_device(const SPIDevice* device) { | ||||
|     api_hal_spi_unlock(device->spi); | ||||
| } | ||||
							
								
								
									
										36
									
								
								firmware/targets/f5/api-hal/api-hal-spi.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								firmware/targets/f5/api-hal/api-hal-spi.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| #pragma once | ||||
| #include "main.h" | ||||
| #include "api-hal-spi-config.h" | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| /** | ||||
|  * Init SPI API | ||||
|  */ | ||||
| void api_hal_spi_init(); | ||||
|  | ||||
| /** | ||||
|  * Lock SPI bus | ||||
|  */ | ||||
| void api_hal_spi_lock(SPI_HandleTypeDef* spi); | ||||
|  | ||||
| /** | ||||
|  * Unlock SPI bus | ||||
|  */ | ||||
| void api_hal_spi_unlock(SPI_HandleTypeDef* spi); | ||||
|  | ||||
| /** | ||||
|  * Lock SPI device bus and apply config if needed | ||||
|  */ | ||||
| void api_hal_spi_lock_device(const SPIDevice* device); | ||||
|  | ||||
| /** | ||||
|  * Unlock SPI device bus | ||||
|  */ | ||||
| void api_hal_spi_unlock_device(const SPIDevice* device); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										54
									
								
								firmware/targets/f5/api-hal/api-hal-task.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								firmware/targets/f5/api-hal/api-hal-task.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | ||||
| #include "cmsis_os.h" | ||||
| #include "api-hal-task.h" | ||||
|  | ||||
| //-----------------------------cmsis_os2.c------------------------------- | ||||
| // helpers to get isr context | ||||
| // get arch | ||||
| #ifndef __ARM_ARCH_6M__ | ||||
| #define __ARM_ARCH_6M__ 0 | ||||
| #endif | ||||
| #ifndef __ARM_ARCH_7M__ | ||||
| #define __ARM_ARCH_7M__ 0 | ||||
| #endif | ||||
| #ifndef __ARM_ARCH_7EM__ | ||||
| #define __ARM_ARCH_7EM__ 0 | ||||
| #endif | ||||
| #ifndef __ARM_ARCH_8M_MAIN__ | ||||
| #define __ARM_ARCH_8M_MAIN__ 0 | ||||
| #endif | ||||
| #ifndef __ARM_ARCH_7A__ | ||||
| #define __ARM_ARCH_7A__ 0 | ||||
| #endif | ||||
|  | ||||
| // get masks | ||||
| #if((__ARM_ARCH_7M__ == 1U) || (__ARM_ARCH_7EM__ == 1U) || (__ARM_ARCH_8M_MAIN__ == 1U)) | ||||
| #define IS_IRQ_MASKED() ((__get_PRIMASK() != 0U) || (__get_BASEPRI() != 0U)) | ||||
| #elif(__ARM_ARCH_6M__ == 1U) | ||||
| #define IS_IRQ_MASKED() (__get_PRIMASK() != 0U) | ||||
| #elif(__ARM_ARCH_7A__ == 1U) | ||||
| /* CPSR mask bits */ | ||||
| #define CPSR_MASKBIT_I 0x80U | ||||
|  | ||||
| #define IS_IRQ_MASKED() ((__get_CPSR() & CPSR_MASKBIT_I) != 0U) | ||||
| #else | ||||
| #define IS_IRQ_MASKED() (__get_PRIMASK() != 0U) | ||||
| #endif | ||||
|  | ||||
| // get is irq mode | ||||
| #if(__ARM_ARCH_7A__ == 1U) | ||||
| /* CPSR mode bitmasks */ | ||||
| #define CPSR_MODE_USER 0x10U | ||||
| #define CPSR_MODE_SYSTEM 0x1FU | ||||
|  | ||||
| #define IS_IRQ_MODE() ((__get_mode() != CPSR_MODE_USER) && (__get_mode() != CPSR_MODE_SYSTEM)) | ||||
| #else | ||||
| #define IS_IRQ_MODE() (__get_IPSR() != 0U) | ||||
| #endif | ||||
|  | ||||
| // added osKernelGetState(), because KernelState is a static var | ||||
| #define IS_IRQ() (IS_IRQ_MODE() || (IS_IRQ_MASKED() && (osKernelGetState() == osKernelRunning))) | ||||
| //-------------------------end of cmsis_os2.c---------------------------- | ||||
|  | ||||
| bool task_is_isr_context(void) { | ||||
|     return IS_IRQ(); | ||||
| } | ||||
							
								
								
									
										12
									
								
								firmware/targets/f5/api-hal/api-hal-task.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								firmware/targets/f5/api-hal/api-hal-task.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| #pragma once | ||||
| #include "main.h" | ||||
| #include <cmsis_os2.h> | ||||
| #include <stdbool.h> | ||||
|  | ||||
| // Task stack size in bytes | ||||
| #define DEFAULT_STACK_SIZE 4096 | ||||
|  | ||||
| // Max system tasks count | ||||
| #define MAX_TASK_COUNT 14 | ||||
|  | ||||
| bool task_is_isr_context(void); | ||||
							
								
								
									
										47
									
								
								firmware/targets/f5/api-hal/api-hal-tim.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								firmware/targets/f5/api-hal/api-hal-tim.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| #include "cmsis_os.h" | ||||
| #include "api-hal-tim.h" | ||||
|  | ||||
| /* setup TIM2 CH1 and CH2 to capture rising and falling events */ | ||||
| void tim_irda_rx_init(void) { | ||||
|     TIM_ClockConfigTypeDef sClockSourceConfig = {0}; | ||||
|     TIM_MasterConfigTypeDef sMasterConfig = {0}; | ||||
|     TIM_IC_InitTypeDef sConfigIC = {0}; | ||||
|  | ||||
|     htim2.Instance = TIM2; | ||||
|     htim2.Init.Prescaler = 64 - 1; | ||||
|     htim2.Init.CounterMode = TIM_COUNTERMODE_UP; | ||||
|     htim2.Init.Period = 4294967295; | ||||
|     htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; | ||||
|     htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; | ||||
|     if(HAL_TIM_Base_Init(&htim2) != HAL_OK) { | ||||
|         Error_Handler(); | ||||
|     } | ||||
|     sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; | ||||
|     if(HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) { | ||||
|         Error_Handler(); | ||||
|     } | ||||
|     if(HAL_TIM_IC_Init(&htim2) != HAL_OK) { | ||||
|         Error_Handler(); | ||||
|     } | ||||
|     sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; | ||||
|     sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; | ||||
|     if(HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) { | ||||
|         Error_Handler(); | ||||
|     } | ||||
|     sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING; | ||||
|     sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI; | ||||
|     sConfigIC.ICPrescaler = TIM_ICPSC_DIV1; | ||||
|     sConfigIC.ICFilter = 0; | ||||
|     if(HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1) != HAL_OK) { | ||||
|         Error_Handler(); | ||||
|     } | ||||
|     sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING; | ||||
|     sConfigIC.ICSelection = TIM_ICSELECTION_INDIRECTTI; | ||||
|     if(HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_2) != HAL_OK) { | ||||
|         Error_Handler(); | ||||
|     } | ||||
|  | ||||
|     HAL_NVIC_SetPriority(TIM2_IRQn, 5, 0); | ||||
|     HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1); | ||||
|     HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2); | ||||
| } | ||||
							
								
								
									
										4
									
								
								firmware/targets/f5/api-hal/api-hal-tim.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								firmware/targets/f5/api-hal/api-hal-tim.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| #pragma once | ||||
| #include "main.h" | ||||
|  | ||||
| void tim_irda_rx_init(void); | ||||
							
								
								
									
										10
									
								
								firmware/targets/f5/api-hal/api-hal-uuid.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								firmware/targets/f5/api-hal/api-hal-uuid.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| #include <api-hal-uid.h> | ||||
| #include <stm32wbxx.h> | ||||
|  | ||||
| size_t api_hal_uid_size() { | ||||
|     return 64/8; | ||||
| } | ||||
|  | ||||
| const uint8_t* api_hal_uid() { | ||||
|     return (const uint8_t *)UID64_BASE; | ||||
| } | ||||
							
								
								
									
										96
									
								
								firmware/targets/f5/api-hal/api-hal-vcp.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								firmware/targets/f5/api-hal/api-hal-vcp.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,96 @@ | ||||
| #include <api-hal-vcp.h> | ||||
| #include <usbd_cdc_if.h> | ||||
| #include <furi.h> | ||||
| #include <stream_buffer.h> | ||||
|  | ||||
| #define API_HAL_VCP_RX_BUFFER_SIZE 600 | ||||
|  | ||||
| typedef struct { | ||||
|     StreamBufferHandle_t rx_stream; | ||||
|     osSemaphoreId_t tx_semaphore; | ||||
|     volatile bool alive; | ||||
|     volatile bool underrun; | ||||
| } ApiHalVcp; | ||||
|  | ||||
| static ApiHalVcp* api_hal_vcp = NULL; | ||||
|  | ||||
| static const uint8_t ascii_soh = 0x01; | ||||
| static const uint8_t ascii_eot = 0x04; | ||||
|  | ||||
| void _api_hal_vcp_init(); | ||||
| void _api_hal_vcp_deinit(); | ||||
| void _api_hal_vcp_control_line(uint8_t state); | ||||
| void _api_hal_vcp_rx_callback(const uint8_t* buffer, size_t size); | ||||
| void _api_hal_vcp_tx_complete(size_t size); | ||||
|  | ||||
| void api_hal_vcp_init() { | ||||
|     api_hal_vcp = furi_alloc(sizeof(ApiHalVcp)); | ||||
|     api_hal_vcp->rx_stream = xStreamBufferCreate(API_HAL_VCP_RX_BUFFER_SIZE, 1); | ||||
|     api_hal_vcp->tx_semaphore = osSemaphoreNew(1, 1, NULL); | ||||
|     api_hal_vcp->alive = false; | ||||
|     api_hal_vcp->underrun = false; | ||||
| } | ||||
|  | ||||
| void _api_hal_vcp_init() { | ||||
|     osSemaphoreRelease(api_hal_vcp->tx_semaphore); | ||||
| } | ||||
|  | ||||
| void _api_hal_vcp_deinit() { | ||||
|     api_hal_vcp->alive = false; | ||||
|     osSemaphoreRelease(api_hal_vcp->tx_semaphore); | ||||
| } | ||||
|  | ||||
| void _api_hal_vcp_control_line(uint8_t state) { | ||||
|     // bit 0: DTR state, bit 1: RTS state | ||||
|     // bool dtr = state & 0b01; | ||||
|     bool rts = state & 0b10; | ||||
|  | ||||
|     if (rts) { | ||||
|         api_hal_vcp->alive = true; | ||||
|         _api_hal_vcp_rx_callback(&ascii_soh, 1); // SOH | ||||
|     } else { | ||||
|         api_hal_vcp->alive = false; | ||||
|         _api_hal_vcp_rx_callback(&ascii_eot, 1); // EOT | ||||
|     } | ||||
|  | ||||
|     osSemaphoreRelease(api_hal_vcp->tx_semaphore); | ||||
| } | ||||
|  | ||||
| void _api_hal_vcp_rx_callback(const uint8_t* buffer, size_t size) { | ||||
|     BaseType_t xHigherPriorityTaskWoken = pdFALSE; | ||||
|     size_t ret = xStreamBufferSendFromISR(api_hal_vcp->rx_stream, buffer, size, &xHigherPriorityTaskWoken); | ||||
|     if (ret != size) { | ||||
|         api_hal_vcp->underrun = true; | ||||
|     } | ||||
|     portYIELD_FROM_ISR(xHigherPriorityTaskWoken); | ||||
| } | ||||
|  | ||||
| void _api_hal_vcp_tx_complete(size_t size) { | ||||
|     osSemaphoreRelease(api_hal_vcp->tx_semaphore); | ||||
| } | ||||
|  | ||||
| size_t api_hal_vcp_rx(uint8_t* buffer, size_t size) { | ||||
|     furi_assert(api_hal_vcp); | ||||
|     return xStreamBufferReceive(api_hal_vcp->rx_stream, buffer, size, portMAX_DELAY); | ||||
| } | ||||
|  | ||||
| void api_hal_vcp_tx(const uint8_t* buffer, size_t size) { | ||||
|     furi_assert(api_hal_vcp); | ||||
|  | ||||
|     while (size > 0 && api_hal_vcp->alive) { | ||||
|         furi_check(osSemaphoreAcquire(api_hal_vcp->tx_semaphore, osWaitForever) == osOK); | ||||
|  | ||||
|         size_t batch_size = size; | ||||
|         if (batch_size > APP_TX_DATA_SIZE) { | ||||
|             batch_size = APP_TX_DATA_SIZE; | ||||
|         } | ||||
|  | ||||
|         if (CDC_Transmit_FS((uint8_t*)buffer, batch_size) == USBD_OK) { | ||||
|             size -= batch_size; | ||||
|             buffer += batch_size; | ||||
|         } else { | ||||
|             // Shouldn't be there  | ||||
|             osDelay(100); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										34
									
								
								firmware/targets/f5/api-hal/api-hal-version.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								firmware/targets/f5/api-hal/api-hal-version.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| #include <api-hal-version.h> | ||||
| #include <stm32wbxx.h> | ||||
|  | ||||
| typedef struct { | ||||
|     uint8_t version; | ||||
|     uint8_t target; | ||||
|     uint8_t body; | ||||
|     uint8_t connect; | ||||
|     uint32_t timestamp; | ||||
| } ApiHalVersionOTP; | ||||
|  | ||||
| bool api_hal_version_do_i_belong_here() { | ||||
|     return api_hal_version_get_hw_target() == 5; | ||||
| } | ||||
|  | ||||
| const uint8_t api_hal_version_get_hw_version() { | ||||
|     return ((ApiHalVersionOTP*)OTP_AREA_BASE)->version; | ||||
| } | ||||
|  | ||||
| const uint8_t api_hal_version_get_hw_target() { | ||||
|     return ((ApiHalVersionOTP*)OTP_AREA_BASE)->target; | ||||
| } | ||||
|  | ||||
| const uint8_t api_hal_version_get_hw_body() { | ||||
|     return ((ApiHalVersionOTP*)OTP_AREA_BASE)->body; | ||||
| } | ||||
|  | ||||
| const uint8_t api_hal_version_get_hw_connect() { | ||||
|     return ((ApiHalVersionOTP*)OTP_AREA_BASE)->connect; | ||||
| } | ||||
|  | ||||
| const uint32_t api_hal_version_get_hw_timestamp() { | ||||
|     return ((ApiHalVersionOTP*)OTP_AREA_BASE)->timestamp; | ||||
| } | ||||
							
								
								
									
										9
									
								
								firmware/targets/f5/api-hal/api-hal.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								firmware/targets/f5/api-hal/api-hal.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| #include <api-hal.h> | ||||
|  | ||||
| void api_hal_init() { | ||||
|     api_hal_os_init(); | ||||
|     api_hal_vcp_init(); | ||||
|     api_hal_spi_init(); | ||||
|     api_hal_i2c_init(); | ||||
|     api_hal_light_init(); | ||||
| } | ||||
							
								
								
									
										36
									
								
								firmware/targets/f5/api-hal/api-interrupts.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								firmware/targets/f5/api-hal/api-interrupts.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| #include "api-hal/api-interrupt-mgr.h" | ||||
| #include <main.h> | ||||
|  | ||||
| extern void api_interrupt_call(InterruptType type, void* hw); | ||||
|  | ||||
| /* interrupts */ | ||||
|  | ||||
| /* Comparator trigger event */ | ||||
| void HAL_COMP_TriggerCallback(COMP_HandleTypeDef* hcomp) { | ||||
|     api_interrupt_call(InterruptTypeComparatorTrigger, hcomp); | ||||
| } | ||||
|  | ||||
| /* Timer input capture event */ | ||||
| void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef* htim) { | ||||
|     api_interrupt_call(InterruptTypeTimerCapture, htim); | ||||
| } | ||||
|  | ||||
| /* Output compare event */ | ||||
| void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef* htim) { | ||||
|     api_interrupt_call(InterruptTypeTimerOutputCompare, htim); | ||||
| } | ||||
|  | ||||
| /* Timer update event */ | ||||
| void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim) { | ||||
|     api_interrupt_call(InterruptTypeTimerUpdate, htim); | ||||
|  | ||||
|     // handle HAL ticks | ||||
|     if(htim->Instance == TIM17) { | ||||
|         HAL_IncTick(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* External interrupt event */ | ||||
| void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { | ||||
|     api_interrupt_call(InterruptTypeExternalInterrupt, (void*)(uint32_t)GPIO_Pin); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user