[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