[FL-1196] Targets: add F6 (#427)
* Targets: add F6 * F6: Update linker script for use with internal storage * F6: synchronize with F5, add all changes arriving in V9 board, update cube project. Github workflow: add multi-target build, add F6 to build targets. * CI: fix full assembly * CI: better artifact naming scheme * CI: fix artifacts wildcard * F6: Swap C10 - A15, vibro and sdcard detect pins
This commit is contained in:
14
firmware/targets/f6/api-hal/api-hal-boot.c
Normal file
14
firmware/targets/f6/api-hal/api-hal-boot.c
Normal file
@@ -0,0 +1,14 @@
|
||||
#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);
|
||||
}
|
||||
}
|
||||
|
||||
109
firmware/targets/f6/api-hal/api-hal-bt.c
Normal file
109
firmware/targets/f6/api-hal/api-hal-bt.c
Normal file
@@ -0,0 +1,109 @@
|
||||
#include <api-hal-bt.h>
|
||||
#include <app_entry.h>
|
||||
#include <ble.h>
|
||||
#include <stm32wbxx.h>
|
||||
#include <shci.h>
|
||||
#include <cmsis_os2.h>
|
||||
#include <app_ble.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();
|
||||
}
|
||||
|
||||
bool api_hal_bt_start_app() {
|
||||
return APP_BLE_Start();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void api_hal_bt_start_tone_tx(uint8_t tx_channel, uint8_t power) {
|
||||
aci_hal_set_tx_power_level(0, power);
|
||||
aci_hal_tone_start(tx_channel, 0);
|
||||
}
|
||||
|
||||
void api_hal_bt_stop_tone_tx() {
|
||||
aci_hal_tone_stop();
|
||||
}
|
||||
|
||||
void api_hal_bt_start_packet_tx(uint8_t frequency, uint8_t datarate) {
|
||||
hci_le_enhanced_transmitter_test(frequency, 0x25, 2, datarate);
|
||||
}
|
||||
|
||||
void api_hal_bt_stop_packet_tx() {
|
||||
uint16_t num_of_packets;
|
||||
hci_le_test_end(&num_of_packets);
|
||||
}
|
||||
|
||||
void api_hal_bt_start_rx(uint8_t frequency) {
|
||||
aci_hal_rx_start(frequency);
|
||||
}
|
||||
|
||||
void api_hal_bt_stop_rx() {
|
||||
aci_hal_rx_stop();
|
||||
}
|
||||
27
firmware/targets/f6/api-hal/api-hal-clock.c
Normal file
27
firmware/targets/f6/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/f6/api-hal/api-hal-clock.h
Normal file
7
firmware/targets/f6/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();
|
||||
29
firmware/targets/f6/api-hal/api-hal-delay.c
Normal file
29
firmware/targets/f6/api-hal/api-hal-delay.c
Normal file
@@ -0,0 +1,29 @@
|
||||
#include "api-hal-delay.h"
|
||||
|
||||
#include <furi.h>
|
||||
#include <cmsis_os2.h>
|
||||
|
||||
static uint32_t clk_per_microsecond;
|
||||
|
||||
void api_hal_delay_init(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);
|
||||
(void)result;
|
||||
furi_assert(result == osOK);
|
||||
}
|
||||
88
firmware/targets/f6/api-hal/api-hal-flash.c
Normal file
88
firmware/targets/f6/api-hal/api-hal-flash.c
Normal file
@@ -0,0 +1,88 @@
|
||||
#include <api-hal-flash.h>
|
||||
#include <api-hal-bt.h>
|
||||
#include <stm32wbxx.h>
|
||||
#include <furi.h>
|
||||
|
||||
/* Free flash space borders, exported by linker */
|
||||
extern const void __free_flash_start__;
|
||||
extern const void __free_flash_end__;
|
||||
|
||||
#define API_HAL_FLASH_READ_BLOCK 8
|
||||
#define API_HAL_FLASH_WRITE_BLOCK 8
|
||||
#define API_HAL_FLASH_PAGE_SIZE 4096
|
||||
#define API_HAL_FLASH_CYCLES_COUNT 10000
|
||||
|
||||
size_t api_hal_flash_get_base() {
|
||||
return FLASH_BASE;
|
||||
}
|
||||
|
||||
size_t api_hal_flash_get_read_block_size() {
|
||||
return API_HAL_FLASH_READ_BLOCK;
|
||||
}
|
||||
|
||||
size_t api_hal_flash_get_write_block_size() {
|
||||
return API_HAL_FLASH_WRITE_BLOCK;
|
||||
}
|
||||
|
||||
size_t api_hal_flash_get_page_size() {
|
||||
return API_HAL_FLASH_PAGE_SIZE;
|
||||
}
|
||||
|
||||
size_t api_hal_flash_get_cycles_count() {
|
||||
return API_HAL_FLASH_CYCLES_COUNT;
|
||||
}
|
||||
|
||||
const void* api_hal_flash_get_free_start_address() {
|
||||
return &__free_flash_start__;
|
||||
}
|
||||
|
||||
const void* api_hal_flash_get_free_end_address() {
|
||||
return &__free_flash_end__;
|
||||
}
|
||||
|
||||
size_t api_hal_flash_get_free_page_start_address() {
|
||||
size_t start = (size_t)api_hal_flash_get_free_start_address();
|
||||
size_t page_start = start - start % API_HAL_FLASH_PAGE_SIZE;
|
||||
if (page_start != start) {
|
||||
page_start += API_HAL_FLASH_PAGE_SIZE;
|
||||
}
|
||||
return page_start;
|
||||
}
|
||||
|
||||
size_t api_hal_flash_get_free_page_count() {
|
||||
size_t end = (size_t)api_hal_flash_get_free_end_address();
|
||||
size_t page_start = (size_t)api_hal_flash_get_free_page_start_address();
|
||||
return (end-page_start) / API_HAL_FLASH_PAGE_SIZE;
|
||||
}
|
||||
|
||||
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_dword_from(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;
|
||||
}
|
||||
74
firmware/targets/f6/api-hal/api-hal-flash.h
Normal file
74
firmware/targets/f6/api-hal/api-hal-flash.h
Normal file
@@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/** Get flash base address
|
||||
* @return pointer to flash base
|
||||
*/
|
||||
size_t api_hal_flash_get_base();
|
||||
|
||||
/** Get flash read block size
|
||||
* @return size in bytes
|
||||
*/
|
||||
size_t api_hal_flash_get_read_block_size();
|
||||
|
||||
/** Get flash write block size
|
||||
* @return size in bytes
|
||||
*/
|
||||
size_t api_hal_flash_get_write_block_size();
|
||||
|
||||
/** Get flash page size
|
||||
* @return size in bytes
|
||||
*/
|
||||
size_t api_hal_flash_get_page_size();
|
||||
|
||||
/** Get expected flash cycles count
|
||||
* @return count of erase-write operations
|
||||
*/
|
||||
size_t api_hal_flash_get_cycles_count();
|
||||
|
||||
/** Get free flash start address
|
||||
* @return pointer to free region start
|
||||
*/
|
||||
const void* api_hal_flash_get_free_start_address();
|
||||
|
||||
/** Get free flash end address
|
||||
* @return pointer to free region end
|
||||
*/
|
||||
const void* api_hal_flash_get_free_end_address();
|
||||
|
||||
/** Get first free page start address
|
||||
* @return first free page memory address
|
||||
*/
|
||||
size_t api_hal_flash_get_free_page_start_address();
|
||||
|
||||
/** Get free page count
|
||||
* @return free page count
|
||||
*/
|
||||
size_t api_hal_flash_get_free_page_count();
|
||||
|
||||
/*
|
||||
* 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 double word (64 bits) from address
|
||||
* Locking operation, uses HSEM to manage shared access.
|
||||
* @param address - destination address, must be block aligned
|
||||
* @param source_address - source address
|
||||
*/
|
||||
bool api_hal_flash_write_dword_from(size_t address, size_t source_address);
|
||||
289
firmware/targets/f6/api-hal/api-hal-gpio.c
Normal file
289
firmware/targets/f6/api-hal/api-hal-gpio.c
Normal file
@@ -0,0 +1,289 @@
|
||||
#include <furi.h>
|
||||
#include <api-hal-gpio.h>
|
||||
#include <api-hal-version.h>
|
||||
|
||||
#define GET_SYSCFG_EXTI_PORT(gpio) \
|
||||
(((gpio) == (GPIOA)) ? LL_SYSCFG_EXTI_PORTA : \
|
||||
((gpio) == (GPIOB)) ? LL_SYSCFG_EXTI_PORTB : \
|
||||
((gpio) == (GPIOC)) ? LL_SYSCFG_EXTI_PORTC : \
|
||||
((gpio) == (GPIOD)) ? LL_SYSCFG_EXTI_PORTD : \
|
||||
((gpio) == (GPIOE)) ? LL_SYSCFG_EXTI_PORTE : \
|
||||
LL_SYSCFG_EXTI_PORTH)
|
||||
|
||||
#define GPIO_PIN_MAP(pin, prefix) \
|
||||
(((pin) == (LL_GPIO_PIN_0)) ? prefix##0 : \
|
||||
((pin) == (LL_GPIO_PIN_1)) ? prefix##1 : \
|
||||
((pin) == (LL_GPIO_PIN_2)) ? prefix##2 : \
|
||||
((pin) == (LL_GPIO_PIN_3)) ? prefix##3 : \
|
||||
((pin) == (LL_GPIO_PIN_4)) ? prefix##4 : \
|
||||
((pin) == (LL_GPIO_PIN_5)) ? prefix##5 : \
|
||||
((pin) == (LL_GPIO_PIN_6)) ? prefix##6 : \
|
||||
((pin) == (LL_GPIO_PIN_7)) ? prefix##7 : \
|
||||
((pin) == (LL_GPIO_PIN_8)) ? prefix##8 : \
|
||||
((pin) == (LL_GPIO_PIN_9)) ? prefix##9 : \
|
||||
((pin) == (LL_GPIO_PIN_10)) ? prefix##10 : \
|
||||
((pin) == (LL_GPIO_PIN_11)) ? prefix##11 : \
|
||||
((pin) == (LL_GPIO_PIN_12)) ? prefix##12 : \
|
||||
((pin) == (LL_GPIO_PIN_13)) ? prefix##13 : \
|
||||
((pin) == (LL_GPIO_PIN_14)) ? prefix##14 : \
|
||||
prefix##15)
|
||||
|
||||
#define GET_SYSCFG_EXTI_LINE(pin) GPIO_PIN_MAP(pin, LL_SYSCFG_EXTI_LINE)
|
||||
#define GET_EXTI_LINE(pin) GPIO_PIN_MAP(pin, LL_EXTI_LINE_)
|
||||
|
||||
static volatile GpioInterrupt gpio_interrupt[GPIO_NUMBER];
|
||||
|
||||
static uint8_t hal_gpio_get_pin_num(const GpioPin* gpio) {
|
||||
uint8_t pin_num = 0;
|
||||
for(pin_num = 0; pin_num < GPIO_NUMBER; pin_num++) {
|
||||
if(gpio->pin & (1 << pin_num)) break;
|
||||
}
|
||||
return pin_num;
|
||||
}
|
||||
|
||||
void hal_gpio_init(
|
||||
const GpioPin* gpio,
|
||||
const GpioMode mode,
|
||||
const GpioPull pull,
|
||||
const GpioSpeed speed) {
|
||||
uint32_t sys_exti_port = GET_SYSCFG_EXTI_PORT(gpio->port);
|
||||
uint32_t sys_exti_line = GET_SYSCFG_EXTI_LINE(gpio->pin);
|
||||
uint32_t exti_line = GET_EXTI_LINE(gpio->pin);
|
||||
|
||||
// Configure gpio with interrupts disabled
|
||||
__disable_irq();
|
||||
// Set gpio speed
|
||||
if(speed == GpioSpeedLow) {
|
||||
LL_GPIO_SetPinSpeed(gpio->port, gpio->pin, LL_GPIO_SPEED_FREQ_LOW);
|
||||
} else if(speed == GpioSpeedMedium) {
|
||||
LL_GPIO_SetPinSpeed(gpio->port, gpio->pin, LL_GPIO_SPEED_FREQ_MEDIUM);
|
||||
} else if(speed == GpioSpeedHigh) {
|
||||
LL_GPIO_SetPinSpeed(gpio->port, gpio->pin, LL_GPIO_SPEED_FREQ_HIGH);
|
||||
} else {
|
||||
LL_GPIO_SetPinSpeed(gpio->port, gpio->pin, LL_GPIO_SPEED_FREQ_VERY_HIGH);
|
||||
}
|
||||
// Set gpio pull mode
|
||||
if(pull == GpioPullNo) {
|
||||
LL_GPIO_SetPinPull(gpio->port, gpio->pin, LL_GPIO_PULL_NO);
|
||||
} else if(pull == GpioPullUp) {
|
||||
LL_GPIO_SetPinPull(gpio->port, gpio->pin, LL_GPIO_PULL_UP);
|
||||
} else {
|
||||
LL_GPIO_SetPinPull(gpio->port, gpio->pin, LL_GPIO_PULL_DOWN);
|
||||
}
|
||||
// Set gpio mode
|
||||
if(mode >= GpioModeInterruptRise) {
|
||||
// Set pin in interrupt mode
|
||||
LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_INPUT);
|
||||
LL_SYSCFG_SetEXTISource(sys_exti_port, sys_exti_line);
|
||||
if(mode == GpioModeInterruptRise || mode == GpioModeInterruptRiseFall) {
|
||||
LL_EXTI_EnableIT_0_31(exti_line);
|
||||
LL_EXTI_EnableRisingTrig_0_31(exti_line);
|
||||
}
|
||||
if(mode == GpioModeInterruptFall || mode == GpioModeInterruptRiseFall) {
|
||||
LL_EXTI_EnableIT_0_31(exti_line);
|
||||
LL_EXTI_EnableFallingTrig_0_31(exti_line);
|
||||
}
|
||||
if(mode == GpioModeEventRise || mode == GpioModeInterruptRiseFall) {
|
||||
LL_EXTI_EnableEvent_0_31(exti_line);
|
||||
LL_EXTI_EnableRisingTrig_0_31(exti_line);
|
||||
}
|
||||
if(mode == GpioModeEventFall || mode == GpioModeInterruptRiseFall) {
|
||||
LL_EXTI_EnableEvent_0_31(exti_line);
|
||||
LL_EXTI_EnableFallingTrig_0_31(exti_line);
|
||||
}
|
||||
} else {
|
||||
// Disable interrupt if it was set
|
||||
if(LL_SYSCFG_GetEXTISource(sys_exti_line) == sys_exti_port &&
|
||||
LL_EXTI_IsEnabledIT_0_31(exti_line)) {
|
||||
LL_EXTI_DisableIT_0_31(exti_line);
|
||||
LL_EXTI_DisableRisingTrig_0_31(exti_line);
|
||||
LL_EXTI_DisableFallingTrig_0_31(exti_line);
|
||||
}
|
||||
// Set not interrupt pin modes
|
||||
if(mode == GpioModeInput) {
|
||||
LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_INPUT);
|
||||
} else if(mode == GpioModeOutputPushPull || mode == GpioModeAltFunctionPushPull) {
|
||||
LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_OUTPUT);
|
||||
LL_GPIO_SetPinOutputType(gpio->port, gpio->pin, LL_GPIO_OUTPUT_PUSHPULL);
|
||||
} else if(mode == GpioModeOutputOpenDrain || mode == GpioModeAltFunctionOpenDrain) {
|
||||
LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_OUTPUT);
|
||||
LL_GPIO_SetPinOutputType(gpio->port, gpio->pin, LL_GPIO_OUTPUT_OPENDRAIN);
|
||||
} else if(mode == GpioModeAnalog) {
|
||||
LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_ANALOG);
|
||||
}
|
||||
}
|
||||
__enable_irq();
|
||||
}
|
||||
|
||||
void hal_gpio_init_alt(
|
||||
const GpioPin* gpio,
|
||||
const GpioMode mode,
|
||||
const GpioPull pull,
|
||||
const GpioSpeed speed,
|
||||
const GpioAltFn alt_fn) {
|
||||
hal_gpio_init(gpio, mode, pull, speed);
|
||||
|
||||
__disable_irq();
|
||||
// enable alternate mode
|
||||
LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_ALTERNATE);
|
||||
|
||||
// set alternate function
|
||||
if(hal_gpio_get_pin_num(gpio) < 8) {
|
||||
LL_GPIO_SetAFPin_0_7(gpio->port, gpio->pin, alt_fn);
|
||||
} else {
|
||||
LL_GPIO_SetAFPin_8_15(gpio->port, gpio->pin, alt_fn);
|
||||
}
|
||||
__enable_irq();
|
||||
}
|
||||
|
||||
void hal_gpio_add_int_callback(const GpioPin* gpio, GpioExtiCallback cb, void* ctx) {
|
||||
furi_assert(gpio);
|
||||
furi_assert(cb);
|
||||
|
||||
__disable_irq();
|
||||
uint8_t pin_num = hal_gpio_get_pin_num(gpio);
|
||||
gpio_interrupt[pin_num].callback = cb;
|
||||
gpio_interrupt[pin_num].context = ctx;
|
||||
gpio_interrupt[pin_num].ready = true;
|
||||
__enable_irq();
|
||||
}
|
||||
|
||||
void hal_gpio_enable_int_callback(const GpioPin* gpio) {
|
||||
furi_assert(gpio);
|
||||
|
||||
__disable_irq();
|
||||
uint8_t pin_num = hal_gpio_get_pin_num(gpio);
|
||||
if(gpio_interrupt[pin_num].callback) {
|
||||
gpio_interrupt[pin_num].ready = true;
|
||||
}
|
||||
__enable_irq();
|
||||
}
|
||||
|
||||
void hal_gpio_disable_int_callback(const GpioPin* gpio) {
|
||||
furi_assert(gpio);
|
||||
|
||||
__disable_irq();
|
||||
uint8_t pin_num = hal_gpio_get_pin_num(gpio);
|
||||
gpio_interrupt[pin_num].ready = false;
|
||||
__enable_irq();
|
||||
}
|
||||
|
||||
void hal_gpio_remove_int_callback(const GpioPin* gpio) {
|
||||
furi_assert(gpio);
|
||||
|
||||
__disable_irq();
|
||||
uint8_t pin_num = hal_gpio_get_pin_num(gpio);
|
||||
gpio_interrupt[pin_num].callback = NULL;
|
||||
gpio_interrupt[pin_num].context = NULL;
|
||||
gpio_interrupt[pin_num].ready = false;
|
||||
__enable_irq();
|
||||
}
|
||||
|
||||
static void hal_gpio_int_call(uint16_t pin_num) {
|
||||
if(gpio_interrupt[pin_num].callback && gpio_interrupt[pin_num].ready) {
|
||||
gpio_interrupt[pin_num].callback(gpio_interrupt[pin_num].context);
|
||||
}
|
||||
}
|
||||
|
||||
/* Interrupt handlers */
|
||||
void EXTI0_IRQHandler(void) {
|
||||
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_0)) {
|
||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_0);
|
||||
hal_gpio_int_call(0);
|
||||
}
|
||||
}
|
||||
|
||||
void EXTI1_IRQHandler(void) {
|
||||
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_1)) {
|
||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_1);
|
||||
hal_gpio_int_call(1);
|
||||
}
|
||||
}
|
||||
|
||||
void EXTI2_IRQHandler(void) {
|
||||
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_2)) {
|
||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_2);
|
||||
hal_gpio_int_call(2);
|
||||
}
|
||||
}
|
||||
|
||||
void EXTI3_IRQHandler(void) {
|
||||
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_3)) {
|
||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_3);
|
||||
hal_gpio_int_call(3);
|
||||
}
|
||||
}
|
||||
|
||||
void EXTI4_IRQHandler(void) {
|
||||
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_4)) {
|
||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_4);
|
||||
hal_gpio_int_call(4);
|
||||
}
|
||||
}
|
||||
|
||||
void EXTI9_5_IRQHandler(void) {
|
||||
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_5)) {
|
||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_5);
|
||||
hal_gpio_int_call(5);
|
||||
}
|
||||
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_6)) {
|
||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_6);
|
||||
hal_gpio_int_call(6);
|
||||
}
|
||||
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_7)) {
|
||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_7);
|
||||
hal_gpio_int_call(7);
|
||||
}
|
||||
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_8)) {
|
||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_8);
|
||||
hal_gpio_int_call(8);
|
||||
}
|
||||
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_9)) {
|
||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_9);
|
||||
hal_gpio_int_call(9);
|
||||
}
|
||||
}
|
||||
|
||||
void EXTI15_10_IRQHandler(void) {
|
||||
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_10)) {
|
||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_10);
|
||||
hal_gpio_int_call(10);
|
||||
}
|
||||
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_11)) {
|
||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_11);
|
||||
hal_gpio_int_call(11);
|
||||
}
|
||||
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_12)) {
|
||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_12);
|
||||
hal_gpio_int_call(12);
|
||||
}
|
||||
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_13)) {
|
||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_13);
|
||||
hal_gpio_int_call(13);
|
||||
}
|
||||
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_14)) {
|
||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_14);
|
||||
hal_gpio_int_call(14);
|
||||
}
|
||||
if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_15)) {
|
||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_15);
|
||||
hal_gpio_int_call(15);
|
||||
}
|
||||
}
|
||||
|
||||
extern COMP_HandleTypeDef hcomp1;
|
||||
|
||||
bool hal_gpio_get_rfid_in_level() {
|
||||
bool value = false;
|
||||
if(api_hal_version_get_hw_version() > 7) {
|
||||
value = (HAL_COMP_GetOutputLevel(&hcomp1) == COMP_OUTPUT_LEVEL_LOW);
|
||||
} else {
|
||||
value = (HAL_COMP_GetOutputLevel(&hcomp1) == COMP_OUTPUT_LEVEL_HIGH);
|
||||
}
|
||||
|
||||
#ifdef INVERT_RFID_IN
|
||||
return !value;
|
||||
#else
|
||||
return value;
|
||||
#endif
|
||||
}
|
||||
255
firmware/targets/f6/api-hal/api-hal-gpio.h
Normal file
255
firmware/targets/f6/api-hal/api-hal-gpio.h
Normal file
@@ -0,0 +1,255 @@
|
||||
#pragma once
|
||||
#include "main.h"
|
||||
#include "stdbool.h"
|
||||
#include <stm32wbxx_ll_gpio.h>
|
||||
#include <stm32wbxx_ll_system.h>
|
||||
#include <stm32wbxx_ll_exti.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Number of gpio on one port
|
||||
*/
|
||||
#define GPIO_NUMBER (16U)
|
||||
|
||||
/**
|
||||
* Interrupt callback prototype
|
||||
*/
|
||||
typedef void (*GpioExtiCallback)(void* ctx);
|
||||
|
||||
/**
|
||||
* Gpio interrupt type
|
||||
*/
|
||||
typedef struct {
|
||||
GpioExtiCallback callback;
|
||||
void* context;
|
||||
volatile bool ready;
|
||||
} GpioInterrupt;
|
||||
|
||||
/**
|
||||
* Gpio modes
|
||||
*/
|
||||
typedef enum {
|
||||
GpioModeInput,
|
||||
GpioModeOutputPushPull,
|
||||
GpioModeOutputOpenDrain,
|
||||
GpioModeAltFunctionPushPull,
|
||||
GpioModeAltFunctionOpenDrain,
|
||||
GpioModeAnalog,
|
||||
GpioModeInterruptRise,
|
||||
GpioModeInterruptFall,
|
||||
GpioModeInterruptRiseFall,
|
||||
GpioModeEventRise,
|
||||
GpioModeEventFall,
|
||||
GpioModeEventRiseFall,
|
||||
} GpioMode;
|
||||
|
||||
/**
|
||||
* Gpio pull modes
|
||||
*/
|
||||
typedef enum {
|
||||
GpioPullNo,
|
||||
GpioPullUp,
|
||||
GpioPullDown,
|
||||
} GpioPull;
|
||||
|
||||
/**
|
||||
* Gpio speed modes
|
||||
*/
|
||||
typedef enum {
|
||||
GpioSpeedLow,
|
||||
GpioSpeedMedium,
|
||||
GpioSpeedHigh,
|
||||
GpioSpeedVeryHigh,
|
||||
} GpioSpeed;
|
||||
|
||||
/**
|
||||
* Gpio alternate functions
|
||||
*/
|
||||
typedef enum {
|
||||
GpioAltFn0MCO = 0, /*!< MCO Alternate Function mapping */
|
||||
GpioAltFn0LSCO = 0, /*!< LSCO Alternate Function mapping */
|
||||
GpioAltFn0JTMS_SWDIO = 0, /*!< JTMS-SWDIO Alternate Function mapping */
|
||||
GpioAltFn0JTCK_SWCLK = 0, /*!< JTCK-SWCLK Alternate Function mapping */
|
||||
GpioAltFn0JTDI = 0, /*!< JTDI Alternate Function mapping */
|
||||
GpioAltFn0RTC_OUT = 0, /*!< RCT_OUT Alternate Function mapping */
|
||||
GpioAltFn0JTD_TRACE = 0, /*!< JTDO-TRACESWO Alternate Function mapping */
|
||||
GpioAltFn0NJTRST = 0, /*!< NJTRST Alternate Function mapping */
|
||||
GpioAltFn0RTC_REFIN = 0, /*!< RTC_REFIN Alternate Function mapping */
|
||||
GpioAltFn0TRACED0 = 0, /*!< TRACED0 Alternate Function mapping */
|
||||
GpioAltFn0TRACED1 = 0, /*!< TRACED1 Alternate Function mapping */
|
||||
GpioAltFn0TRACED2 = 0, /*!< TRACED2 Alternate Function mapping */
|
||||
GpioAltFn0TRACED3 = 0, /*!< TRACED3 Alternate Function mapping */
|
||||
GpioAltFn0TRIG_INOUT = 0, /*!< TRIG_INOUT Alternate Function mapping */
|
||||
GpioAltFn0TRACECK = 0, /*!< TRACECK Alternate Function mapping */
|
||||
GpioAltFn0SYS = 0, /*!< System Function mapping */
|
||||
|
||||
GpioAltFn1TIM1 = 1, /*!< TIM1 Alternate Function mapping */
|
||||
GpioAltFn1TIM2 = 1, /*!< TIM2 Alternate Function mapping */
|
||||
GpioAltFn1LPTIM1 = 1, /*!< LPTIM1 Alternate Function mapping */
|
||||
|
||||
GpioAltFn2TIM2 = 2, /*!< TIM2 Alternate Function mapping */
|
||||
GpioAltFn2TIM1 = 2, /*!< TIM1 Alternate Function mapping */
|
||||
|
||||
GpioAltFn3SAI1 = 3, /*!< SAI1_CK1 Alternate Function mapping */
|
||||
GpioAltFn3SPI2 = 3, /*!< SPI2 Alternate Function mapping */
|
||||
GpioAltFn3TIM1 = 3, /*!< TIM1 Alternate Function mapping */
|
||||
|
||||
GpioAltFn4I2C1 = 4, /*!< I2C1 Alternate Function mapping */
|
||||
GpioAltFn4I2C3 = 4, /*!< I2C3 Alternate Function mapping */
|
||||
|
||||
GpioAltFn5SPI1 = 5, /*!< SPI1 Alternate Function mapping */
|
||||
GpioAltFn5SPI2 = 5, /*!< SPI2 Alternate Function mapping */
|
||||
|
||||
GpioAltFn6MCO = 6, /*!< MCO Alternate Function mapping */
|
||||
GpioAltFn6LSCO = 6, /*!< LSCO Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB0 = 6, /*!< RF_DTB0 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB1 = 6, /*!< RF_DTB1 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB2 = 6, /*!< RF_DTB2 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB3 = 6, /*!< RF_DTB3 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB4 = 6, /*!< RF_DTB4 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB5 = 6, /*!< RF_DTB5 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB6 = 6, /*!< RF_DTB6 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB7 = 6, /*!< RF_DTB7 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB8 = 6, /*!< RF_DTB8 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB9 = 6, /*!< RF_DTB9 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB10 = 6, /*!< RF_DTB10 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB11 = 6, /*!< RF_DTB11 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB12 = 6, /*!< RF_DTB12 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB13 = 6, /*!< RF_DTB13 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB14 = 6, /*!< RF_DTB14 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB15 = 6, /*!< RF_DTB15 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB16 = 6, /*!< RF_DTB16 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB17 = 6, /*!< RF_DTB17 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB18 = 6, /*!< RF_DTB18 Alternate Function mapping */
|
||||
GpioAltFn6RF_MISO = 6, /*!< RF_MISO Alternate Function mapping */
|
||||
GpioAltFn6RF_MOSI = 6, /*!< RF_MOSI Alternate Function mapping */
|
||||
GpioAltFn6RF_SCK = 6, /*!< RF_SCK Alternate Function mapping */
|
||||
GpioAltFn6RF_NSS = 6, /*!< RF_NSS Alternate Function mapping */
|
||||
|
||||
GpioAltFn7USART1 = 7, /*!< USART1 Alternate Function mapping */
|
||||
|
||||
GpioAltFn8LPUART1 = 8, /*!< LPUART1 Alternate Function mapping */
|
||||
GpioAltFn8IR = 8, /*!< IR Alternate Function mapping */
|
||||
|
||||
GpioAltFn9TSC = 9, /*!< TSC Alternate Function mapping */
|
||||
|
||||
GpioAltFn10QUADSPI = 10, /*!< QUADSPI Alternate Function mapping */
|
||||
GpioAltFn10USB = 10, /*!< USB Alternate Function mapping */
|
||||
|
||||
GpioAltFn11LCD = 11, /*!< LCD Alternate Function mapping */
|
||||
|
||||
GpioAltFn12COMP1 = 12, /*!< COMP1 Alternate Function mapping */
|
||||
GpioAltFn12COMP2 = 12, /*!< COMP2 Alternate Function mapping */
|
||||
GpioAltFn12TIM1 = 12, /*!< TIM1 Alternate Function mapping */
|
||||
|
||||
GpioAltFn13SAI1 = 13, /*!< SAI1 Alternate Function mapping */
|
||||
|
||||
GpioAltFn14TIM2 = 14, /*!< TIM2 Alternate Function mapping */
|
||||
GpioAltFn14TIM16 = 14, /*!< TIM16 Alternate Function mapping */
|
||||
GpioAltFn14TIM17 = 14, /*!< TIM17 Alternate Function mapping */
|
||||
GpioAltFn14LPTIM2 = 14, /*!< LPTIM2 Alternate Function mapping */
|
||||
|
||||
GpioAltFn15EVENTOUT = 15, /*!< EVENTOUT Alternate Function mapping */
|
||||
} GpioAltFn;
|
||||
|
||||
/**
|
||||
* Gpio structure
|
||||
*/
|
||||
typedef struct {
|
||||
GPIO_TypeDef* port;
|
||||
uint16_t pin;
|
||||
} GpioPin;
|
||||
|
||||
/**
|
||||
* GPIO initialization function
|
||||
* @param gpio GpioPin
|
||||
* @param mode GpioMode
|
||||
* @param pull GpioPull
|
||||
* @param speed GpioSpeed
|
||||
*/
|
||||
void hal_gpio_init(
|
||||
const GpioPin* gpio,
|
||||
const GpioMode mode,
|
||||
const GpioPull pull,
|
||||
const GpioSpeed speed);
|
||||
|
||||
/**
|
||||
* GPIO initialization with alternative function
|
||||
* @param gpio GpioPin
|
||||
* @param mode GpioMode
|
||||
* @param pull GpioPull
|
||||
* @param speed GpioSpeed
|
||||
* @param alt_fn GpioAltFn
|
||||
*/
|
||||
void hal_gpio_init_alt(
|
||||
const GpioPin* gpio,
|
||||
const GpioMode mode,
|
||||
const GpioPull pull,
|
||||
const GpioSpeed speed,
|
||||
const GpioAltFn alt_fn);
|
||||
|
||||
/**
|
||||
* Add and enable interrupt
|
||||
* @param gpio GpioPin
|
||||
* @param cb GpioExtiCallback
|
||||
* @param ctx context for callback
|
||||
*/
|
||||
void hal_gpio_add_int_callback(const GpioPin* gpio, GpioExtiCallback cb, void* ctx);
|
||||
|
||||
/**
|
||||
* Enable interrupt
|
||||
* @param gpio GpioPin
|
||||
*/
|
||||
void hal_gpio_enable_int_callback(const GpioPin* gpio);
|
||||
|
||||
/**
|
||||
* Disable interrupt
|
||||
* @param gpio GpioPin
|
||||
*/
|
||||
void hal_gpio_disable_int_callback(const GpioPin* gpio);
|
||||
|
||||
/**
|
||||
* Remove interrupt
|
||||
* @param gpio GpioPin
|
||||
*/
|
||||
void hal_gpio_remove_int_callback(const GpioPin* gpio);
|
||||
|
||||
/**
|
||||
* GPIO write pin
|
||||
* @param gpio GpioPin
|
||||
* @param state true / false
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GPIO read pin
|
||||
* @param gpio GpioPin
|
||||
* @return true / false
|
||||
*/
|
||||
static inline bool hal_gpio_read(const GpioPin* gpio) {
|
||||
if((gpio->port->IDR & gpio->pin) != 0x00U) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get RFID IN level
|
||||
* @return false = LOW, true = HIGH
|
||||
*/
|
||||
bool hal_gpio_get_rfid_in_level();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
148
firmware/targets/f6/api-hal/api-hal-i2c.c
Normal file
148
firmware/targets/f6/api-hal/api-hal-i2c.c
Normal file
@@ -0,0 +1,148 @@
|
||||
#include <api-hal-i2c.h>
|
||||
#include <stm32wbxx_ll_i2c.h>
|
||||
#include <stm32wbxx_ll_gpio.h>
|
||||
#include <stm32wbxx_ll_cortex.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);
|
||||
|
||||
LL_I2C_InitTypeDef I2C_InitStruct = {0};
|
||||
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||
|
||||
LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1);
|
||||
|
||||
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
|
||||
GPIO_InitStruct.Pin = POWER_I2C_SCL_Pin | POWER_I2C_SDA_Pin;
|
||||
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
|
||||
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
|
||||
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
|
||||
GPIO_InitStruct.Alternate = LL_GPIO_AF_4;
|
||||
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
|
||||
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1);
|
||||
|
||||
I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;
|
||||
I2C_InitStruct.Timing = POWER_I2C_TIMINGS;
|
||||
I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE;
|
||||
I2C_InitStruct.DigitalFilter = 0;
|
||||
I2C_InitStruct.OwnAddress1 = 0;
|
||||
I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;
|
||||
I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
|
||||
LL_I2C_Init(I2C1, &I2C_InitStruct);
|
||||
LL_I2C_EnableAutoEndMode(I2C1);
|
||||
LL_I2C_SetOwnAddress2(I2C1, 0, LL_I2C_OWNADDRESS2_NOMASK);
|
||||
LL_I2C_DisableOwnAddress2(I2C1);
|
||||
LL_I2C_DisableGeneralCall(I2C1);
|
||||
LL_I2C_EnableClockStretching(I2C1);
|
||||
}
|
||||
|
||||
bool api_hal_i2c_tx(
|
||||
I2C_TypeDef* instance,
|
||||
uint8_t address,
|
||||
const uint8_t* data,
|
||||
uint8_t size,
|
||||
uint32_t timeout) {
|
||||
uint32_t time_left = timeout;
|
||||
bool ret = true;
|
||||
|
||||
while(LL_I2C_IsActiveFlag_BUSY(instance))
|
||||
;
|
||||
|
||||
LL_I2C_HandleTransfer(
|
||||
instance,
|
||||
address,
|
||||
LL_I2C_ADDRSLAVE_7BIT,
|
||||
size,
|
||||
LL_I2C_MODE_AUTOEND,
|
||||
LL_I2C_GENERATE_START_WRITE);
|
||||
|
||||
while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) {
|
||||
if(LL_I2C_IsActiveFlag_TXIS(instance)) {
|
||||
LL_I2C_TransmitData8(instance, (*data));
|
||||
data++;
|
||||
size--;
|
||||
time_left = timeout;
|
||||
}
|
||||
|
||||
if(LL_SYSTICK_IsActiveCounterFlag()) {
|
||||
if(--time_left == 0) {
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LL_I2C_ClearFlag_STOP(instance);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool api_hal_i2c_rx(
|
||||
I2C_TypeDef* instance,
|
||||
uint8_t address,
|
||||
uint8_t* data,
|
||||
uint8_t size,
|
||||
uint32_t timeout) {
|
||||
uint32_t time_left = timeout;
|
||||
bool ret = true;
|
||||
|
||||
while(LL_I2C_IsActiveFlag_BUSY(instance))
|
||||
;
|
||||
|
||||
LL_I2C_HandleTransfer(
|
||||
instance,
|
||||
address,
|
||||
LL_I2C_ADDRSLAVE_7BIT,
|
||||
size,
|
||||
LL_I2C_MODE_AUTOEND,
|
||||
LL_I2C_GENERATE_START_READ);
|
||||
|
||||
while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) {
|
||||
if(LL_I2C_IsActiveFlag_RXNE(instance)) {
|
||||
*data = LL_I2C_ReceiveData8(instance);
|
||||
data++;
|
||||
size--;
|
||||
time_left = timeout;
|
||||
}
|
||||
|
||||
if(LL_SYSTICK_IsActiveCounterFlag()) {
|
||||
if(--time_left == 0) {
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LL_I2C_ClearFlag_STOP(instance);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool api_hal_i2c_trx(
|
||||
I2C_TypeDef* instance,
|
||||
uint8_t address,
|
||||
const uint8_t* tx_data,
|
||||
uint8_t tx_size,
|
||||
uint8_t* rx_data,
|
||||
uint8_t rx_size,
|
||||
uint32_t timeout) {
|
||||
if(api_hal_i2c_tx(instance, address, tx_data, tx_size, timeout) &&
|
||||
api_hal_i2c_rx(instance, address, rx_data, rx_size, timeout)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
24
firmware/targets/f6/api-hal/api-hal-ibutton.c
Normal file
24
firmware/targets/f6/api-hal/api-hal-ibutton.c
Normal file
@@ -0,0 +1,24 @@
|
||||
#include <api-hal-ibutton.h>
|
||||
#include <api-hal-resources.h>
|
||||
|
||||
void api_hal_ibutton_start() {
|
||||
api_hal_ibutton_pin_high();
|
||||
hal_gpio_init(&ibutton_gpio, GpioModeOutputOpenDrain, GpioSpeedLow, GpioPullNo);
|
||||
}
|
||||
|
||||
void api_hal_ibutton_stop() {
|
||||
api_hal_ibutton_pin_high();
|
||||
hal_gpio_init(&ibutton_gpio, GpioModeAnalog, GpioSpeedLow, GpioPullNo);
|
||||
}
|
||||
|
||||
void api_hal_ibutton_pin_low() {
|
||||
hal_gpio_write(&ibutton_gpio, false);
|
||||
}
|
||||
|
||||
void api_hal_ibutton_pin_high() {
|
||||
hal_gpio_write(&ibutton_gpio, true);
|
||||
}
|
||||
|
||||
bool api_hal_ibutton_pin_get_level() {
|
||||
return hal_gpio_read(&ibutton_gpio);
|
||||
}
|
||||
43
firmware/targets/f6/api-hal/api-hal-light.c
Normal file
43
firmware/targets/f6/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;
|
||||
}
|
||||
}
|
||||
85
firmware/targets/f6/api-hal/api-hal-nfc.c
Normal file
85
firmware/targets/f6/api-hal/api-hal-nfc.c
Normal file
@@ -0,0 +1,85 @@
|
||||
#include "api-hal-nfc.h"
|
||||
#include <st25r3916.h>
|
||||
|
||||
static bool dev_is_found = false;
|
||||
|
||||
ReturnCode api_hal_nfc_init() {
|
||||
// Check if Nfc worker was started
|
||||
if(rfalNfcGetState() > RFAL_NFC_STATE_NOTINIT) {
|
||||
return ERR_NONE;
|
||||
}
|
||||
return rfalNfcInitialize();
|
||||
}
|
||||
|
||||
bool api_hal_nfc_is_busy() {
|
||||
return rfalNfcGetState() > RFAL_NFC_STATE_IDLE;
|
||||
}
|
||||
|
||||
void api_hal_nfc_field_on() {
|
||||
api_hal_nfc_exit_sleep();
|
||||
st25r3916TxRxOn();
|
||||
}
|
||||
|
||||
void api_hal_nfc_field_off() {
|
||||
st25r3916TxRxOff();
|
||||
api_hal_nfc_start_sleep();
|
||||
}
|
||||
|
||||
void api_hal_nfc_start_sleep() {
|
||||
rfalLowPowerModeStart();
|
||||
}
|
||||
|
||||
void api_hal_nfc_exit_sleep() {
|
||||
rfalLowPowerModeStop();
|
||||
}
|
||||
|
||||
static void api_hal_nfc_change_state_cb(rfalNfcState st) {
|
||||
FURI_LOG_D("HAL NFC", "NFC worker state: %d", st);
|
||||
if(st >= RFAL_NFC_STATE_POLL_SELECT) {
|
||||
dev_is_found = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool api_hal_nfc_detect(rfalNfcDevice **dev_list, uint8_t* dev_cnt, uint32_t cycles) {
|
||||
furi_assert(dev_list);
|
||||
furi_assert(dev_cnt);
|
||||
|
||||
rfalLowPowerModeStop();
|
||||
if(rfalNfcGetState() == RFAL_NFC_STATE_NOTINIT) {
|
||||
rfalNfcInitialize();
|
||||
}
|
||||
rfalNfcDiscoverParam params;
|
||||
params.compMode = RFAL_COMPLIANCE_MODE_EMV;
|
||||
params.techs2Find = RFAL_NFC_POLL_TECH_A | RFAL_NFC_POLL_TECH_B | RFAL_NFC_POLL_TECH_F |
|
||||
RFAL_NFC_POLL_TECH_V | RFAL_NFC_POLL_TECH_AP2P | RFAL_NFC_POLL_TECH_ST25TB;
|
||||
params.totalDuration = 1000;
|
||||
params.devLimit = 3;
|
||||
params.wakeupEnabled = false;
|
||||
params.wakeupConfigDefault = true;
|
||||
params.nfcfBR = RFAL_BR_212;
|
||||
params.ap2pBR = RFAL_BR_424;
|
||||
params.maxBR = RFAL_BR_KEEP;
|
||||
params.GBLen = RFAL_NFCDEP_GB_MAX_LEN;
|
||||
params.notifyCb = api_hal_nfc_change_state_cb;
|
||||
|
||||
dev_is_found = false;
|
||||
rfalNfcDiscover(¶ms);
|
||||
while(--cycles) {
|
||||
rfalNfcWorker();
|
||||
FURI_LOG_D("HAL NFC", "Current state %d", rfalNfcGetState());
|
||||
if(dev_is_found) {
|
||||
rfalNfcGetDevicesFound(dev_list, dev_cnt);
|
||||
FURI_LOG_D("HAL NFC", "Found %d devices", dev_cnt);
|
||||
break;
|
||||
}
|
||||
osDelay(5);
|
||||
}
|
||||
rfalNfcDeactivate(false);
|
||||
rfalLowPowerModeStart();
|
||||
if(!cycles) {
|
||||
FURI_LOG_D("HAL NFC", "Timeout");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
64
firmware/targets/f6/api-hal/api-hal-os-timer.h
Normal file
64
firmware/targets/f6/api-hal/api-hal-os-timer.h
Normal file
@@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
|
||||
#include <stm32wbxx_ll_lptim.h>
|
||||
#include <stm32wbxx_ll_bus.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// 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
|
||||
|
||||
static inline void api_hal_os_timer_init() {
|
||||
// Configure clock source
|
||||
LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM2_CLKSOURCE_LSE);
|
||||
LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPTIM2);
|
||||
// Set interrupt priority and enable them
|
||||
NVIC_SetPriority(API_HAL_OS_TIMER_IRQ, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 15, 0));
|
||||
NVIC_EnableIRQ(API_HAL_OS_TIMER_IRQ);
|
||||
}
|
||||
|
||||
static inline void api_hal_os_timer_continuous(uint32_t count) {
|
||||
// Enable timer
|
||||
LL_LPTIM_Enable(API_HAL_OS_TIMER);
|
||||
while(!LL_LPTIM_IsEnabled(API_HAL_OS_TIMER));
|
||||
|
||||
// Enable rutoreload match interrupt
|
||||
LL_LPTIM_EnableIT_ARRM(API_HAL_OS_TIMER);
|
||||
|
||||
// Set autoreload and start counter
|
||||
LL_LPTIM_SetAutoReload(API_HAL_OS_TIMER, count);
|
||||
LL_LPTIM_StartCounter(API_HAL_OS_TIMER, LL_LPTIM_OPERATING_MODE_CONTINUOUS);
|
||||
}
|
||||
|
||||
static inline void api_hal_os_timer_single(uint32_t count) {
|
||||
// Enable timer
|
||||
LL_LPTIM_Enable(API_HAL_OS_TIMER);
|
||||
while(!LL_LPTIM_IsEnabled(API_HAL_OS_TIMER));
|
||||
|
||||
// Enable compare match interrupt
|
||||
LL_LPTIM_EnableIT_CMPM(API_HAL_OS_TIMER);
|
||||
|
||||
// Set compare, autoreload and start counter
|
||||
// Include some marging to workaround ARRM behaviour
|
||||
LL_LPTIM_SetCompare(API_HAL_OS_TIMER, count-3);
|
||||
LL_LPTIM_SetAutoReload(API_HAL_OS_TIMER, count);
|
||||
LL_LPTIM_StartCounter(API_HAL_OS_TIMER, LL_LPTIM_OPERATING_MODE_ONESHOT);
|
||||
}
|
||||
|
||||
static inline void api_hal_os_timer_reset() {
|
||||
// Hard reset timer
|
||||
// THE ONLY RELIABLEWAY to stop it according to errata
|
||||
LL_LPTIM_DeInit(API_HAL_OS_TIMER);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
140
firmware/targets/f6/api-hal/api-hal-os.c
Normal file
140
firmware/targets/f6/api-hal/api-hal-os.c
Normal file
@@ -0,0 +1,140 @@
|
||||
#include <api-hal-os.h>
|
||||
#include <api-hal-os-timer.h>
|
||||
#include <api-hal-power.h>
|
||||
#include <stm32wbxx_ll_cortex.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_SLEEP_PORT GPIOA
|
||||
#define LED_SLEEP_PIN LL_GPIO_PIN_7
|
||||
#define LED_TICK_PORT GPIOA
|
||||
#define LED_TICK_PIN LL_GPIO_PIN_6
|
||||
#define LED_SECOND_PORT GPIOA
|
||||
#define LED_SECOND_PIN LL_GPIO_PIN_4
|
||||
|
||||
void api_hal_os_timer_callback() {
|
||||
LL_GPIO_TogglePin(LED_SECOND_PORT, LED_SECOND_PIN);
|
||||
}
|
||||
#endif
|
||||
|
||||
volatile uint32_t api_hal_os_skew = 0;
|
||||
|
||||
void api_hal_os_init() {
|
||||
LL_DBGMCU_APB1_GRP2_FreezePeriph(LL_DBGMCU_APB1_GRP2_LPTIM2_STOP);
|
||||
|
||||
api_hal_os_timer_init();
|
||||
api_hal_os_timer_continuous(API_HAL_OS_CLK_PER_TICK);
|
||||
|
||||
#ifdef API_HAL_OS_DEBUG
|
||||
LL_GPIO_SetPinMode(LED_SLEEP_PORT, LED_SLEEP_PIN, LL_GPIO_MODE_OUTPUT);
|
||||
LL_GPIO_SetPinMode(LED_TICK_PORT, LED_TICK_PIN, LL_GPIO_MODE_OUTPUT);
|
||||
LL_GPIO_SetPinMode(LED_SECOND_PORT, LED_SECOND_PIN, LL_GPIO_MODE_OUTPUT);
|
||||
osTimerId_t second_timer = osTimerNew(api_hal_os_timer_callback, osTimerPeriodic, NULL, NULL);
|
||||
osTimerStart(second_timer, 1024);
|
||||
#endif
|
||||
}
|
||||
|
||||
void LPTIM2_IRQHandler(void) {
|
||||
// Autoreload
|
||||
if(LL_LPTIM_IsActiveFlag_ARRM(API_HAL_OS_TIMER)) {
|
||||
LL_LPTIM_ClearFLAG_ARRM(API_HAL_OS_TIMER);
|
||||
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
|
||||
#ifdef API_HAL_OS_DEBUG
|
||||
LL_GPIO_TogglePin(LED_TICK_PORT, LED_TICK_PIN);
|
||||
#endif
|
||||
xPortSysTickHandler();
|
||||
}
|
||||
}
|
||||
if(LL_LPTIM_IsActiveFlag_CMPM(API_HAL_OS_TIMER)) {
|
||||
LL_LPTIM_ClearFLAG_CMPM(API_HAL_OS_TIMER);
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t api_hal_os_sleep(TickType_t expected_idle_ticks) {
|
||||
// Stop ticks
|
||||
api_hal_os_timer_reset();
|
||||
LL_SYSTICK_DisableIT();
|
||||
|
||||
// Start wakeup timer
|
||||
api_hal_os_timer_single(expected_idle_ticks * API_HAL_OS_CLK_PER_TICK);
|
||||
|
||||
#ifdef API_HAL_OS_DEBUG
|
||||
LL_GPIO_ResetOutputPin(LED_SLEEP_PORT, LED_SLEEP_PIN);
|
||||
#endif
|
||||
|
||||
// Go to sleep mode
|
||||
api_hal_power_sleep();
|
||||
|
||||
#ifdef API_HAL_OS_DEBUG
|
||||
LL_GPIO_SetOutputPin(LED_SLEEP_PORT, LED_SLEEP_PIN);
|
||||
#endif
|
||||
|
||||
// Calculate how much time we spent in the sleep
|
||||
uint32_t after_cnt = api_hal_os_timer_get_cnt() + api_hal_os_skew;
|
||||
uint32_t after_tick = after_cnt / API_HAL_OS_CLK_PER_TICK;
|
||||
api_hal_os_skew = after_cnt % API_HAL_OS_CLK_PER_TICK;
|
||||
|
||||
bool cmpm = LL_LPTIM_IsActiveFlag_CMPM(API_HAL_OS_TIMER);
|
||||
bool arrm = LL_LPTIM_IsActiveFlag_ARRM(API_HAL_OS_TIMER);
|
||||
if (cmpm && arrm) after_tick += expected_idle_ticks;
|
||||
|
||||
// Prepare tick timer for new round
|
||||
api_hal_os_timer_reset();
|
||||
|
||||
// Resume ticks
|
||||
LL_SYSTICK_EnableIT();
|
||||
api_hal_os_timer_continuous(API_HAL_OS_CLK_PER_TICK);
|
||||
|
||||
return after_tick;
|
||||
}
|
||||
|
||||
void vPortSuppressTicksAndSleep(TickType_t expected_idle_ticks) {
|
||||
if(!api_hal_power_sleep_available()) {
|
||||
__WFI();
|
||||
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
|
||||
if (eTaskConfirmSleepModeStatus() == eAbortSleep) {
|
||||
__enable_irq();
|
||||
return;
|
||||
}
|
||||
|
||||
// Sleep and track how much ticks we spent sleeping
|
||||
uint32_t completed_ticks = api_hal_os_sleep(expected_idle_ticks);
|
||||
|
||||
// Reenable IRQ
|
||||
__enable_irq();
|
||||
|
||||
// Notify system about time spent in sleep
|
||||
if (completed_ticks > 0) {
|
||||
if (completed_ticks > expected_idle_ticks) {
|
||||
vTaskStepTick(expected_idle_ticks);
|
||||
} else {
|
||||
vTaskStepTick(completed_ticks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vApplicationStackOverflowHook(TaskHandle_t xTask, signed char *pcTaskName) {
|
||||
asm("bkpt 1");
|
||||
while(1) {};
|
||||
}
|
||||
17
firmware/targets/f6/api-hal/api-hal-os.h
Normal file
17
firmware/targets/f6/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
|
||||
262
firmware/targets/f6/api-hal/api-hal-power.c
Normal file
262
firmware/targets/f6/api-hal/api-hal-power.c
Normal file
@@ -0,0 +1,262 @@
|
||||
#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 <stm32wbxx_ll_gpio.h>
|
||||
|
||||
#include <main.h>
|
||||
#include <hw_conf.h>
|
||||
#include <bq27220.h>
|
||||
#include <bq25896.h>
|
||||
|
||||
typedef struct {
|
||||
volatile uint32_t insomnia;
|
||||
volatile uint32_t deep_insomnia;
|
||||
} ApiHalPower;
|
||||
|
||||
static volatile ApiHalPower api_hal_power = {
|
||||
.insomnia = 0,
|
||||
.deep_insomnia = 1,
|
||||
};
|
||||
|
||||
const ParamCEDV cedv = {
|
||||
.full_charge_cap = 2100,
|
||||
.design_cap = 2100,
|
||||
.EMF = 3739,
|
||||
.C0 = 776,
|
||||
.C1 = 0,
|
||||
.R1 = 193,
|
||||
.R0 = 1,
|
||||
.T0 = 1,
|
||||
.TC = 11,
|
||||
.DOD0 = 4044,
|
||||
.DOD10 = 3899,
|
||||
.DOD20 = 3796,
|
||||
.DOD30 = 3704,
|
||||
.DOD40 = 3627,
|
||||
.DOD50 = 3573,
|
||||
.DOD60 = 3535,
|
||||
.DOD70 = 3501,
|
||||
.DOD80 = 3453,
|
||||
.DOD90 = 3366,
|
||||
.DOD100 = 2419,
|
||||
};
|
||||
|
||||
void HAL_RCC_CSSCallback(void) {
|
||||
// TODO: notify user about issue with HSE
|
||||
api_hal_power_reset();
|
||||
}
|
||||
|
||||
void api_hal_power_init() {
|
||||
LL_PWR_SMPS_SetMode(LL_PWR_SMPS_STEP_DOWN);
|
||||
bq27220_init(&cedv);
|
||||
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_sleep_available() {
|
||||
return api_hal_power.insomnia == 0;
|
||||
}
|
||||
|
||||
bool api_hal_power_deep_sleep_available() {
|
||||
return api_hal_bt_is_alive() && api_hal_power.deep_insomnia == 0;
|
||||
}
|
||||
|
||||
void api_hal_power_light_sleep() {
|
||||
__WFI();
|
||||
}
|
||||
|
||||
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_STOP1);
|
||||
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);
|
||||
}
|
||||
|
||||
void api_hal_power_sleep() {
|
||||
if(api_hal_power_deep_sleep_available()) {
|
||||
api_hal_power_deep_sleep();
|
||||
} else {
|
||||
api_hal_power_light_sleep();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t api_hal_power_get_pct() {
|
||||
return bq27220_get_state_of_charge();
|
||||
}
|
||||
|
||||
uint8_t api_hal_power_get_bat_health_pct() {
|
||||
return bq27220_get_state_of_health();
|
||||
}
|
||||
|
||||
bool api_hal_power_is_charging() {
|
||||
return bq25896_is_charging();
|
||||
}
|
||||
|
||||
void api_hal_power_off() {
|
||||
bq25896_poweroff();
|
||||
}
|
||||
|
||||
void api_hal_power_reset() {
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
float api_hal_power_get_usb_voltage(){
|
||||
return (float)bq25896_get_vbus_voltage() / 1000.0f;
|
||||
}
|
||||
|
||||
void api_hal_power_dump_state() {
|
||||
BatteryStatus battery_status;
|
||||
OperationStatus operation_status;
|
||||
if (bq27220_get_battery_status(&battery_status) == BQ27220_ERROR
|
||||
|| bq27220_get_operation_status(&operation_status) == BQ27220_ERROR) {
|
||||
printf("Failed to get bq27220 status. Communication error.\r\n");
|
||||
} else {
|
||||
printf(
|
||||
"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
|
||||
printf(
|
||||
"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
|
||||
printf(
|
||||
"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
|
||||
printf(
|
||||
"bq27220: Full capacity: %dmAh, Design capacity: %dmAh, Remaining capacity: %dmAh, State of Charge: %d%%, State of health: %d%%\r\n",
|
||||
bq27220_get_full_charge_capacity(), bq27220_get_design_capacity(), bq27220_get_remaining_capacity(),
|
||||
bq27220_get_state_of_charge(), bq27220_get_state_of_health()
|
||||
);
|
||||
printf(
|
||||
"bq27220: Voltage: %dmV, Current: %dmA, Temperature: %dC\r\n",
|
||||
bq27220_get_voltage(), bq27220_get_current(), (int)api_hal_power_get_battery_temperature(ApiHalPowerICFuelGauge)
|
||||
);
|
||||
}
|
||||
|
||||
printf(
|
||||
"bq25896: VBUS: %d, VSYS: %d, VBAT: %d, Current: %d, NTC: %ldm%%\r\n",
|
||||
bq25896_get_vbus_voltage(), bq25896_get_vsys_voltage(),
|
||||
bq25896_get_vbat_voltage(), bq25896_get_vbat_current(),
|
||||
bq25896_get_ntc_mpct()
|
||||
);
|
||||
}
|
||||
|
||||
void api_hal_power_enable_external_3_3v(){
|
||||
LL_GPIO_SetOutputPin(PERIPH_POWER_GPIO_Port, PERIPH_POWER_Pin);
|
||||
}
|
||||
|
||||
void api_hal_power_disable_external_3_3v(){
|
||||
LL_GPIO_ResetOutputPin(PERIPH_POWER_GPIO_Port, PERIPH_POWER_Pin);
|
||||
}
|
||||
57
firmware/targets/f6/api-hal/api-hal-pwm.c
Normal file
57
firmware/targets/f6/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) - 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_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);
|
||||
}
|
||||
19
firmware/targets/f6/api-hal/api-hal-pwm.h
Normal file
19
firmware/targets/f6/api-hal/api-hal-pwm.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include "main.h"
|
||||
#include "stdbool.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
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();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
50
firmware/targets/f6/api-hal/api-hal-resources.c
Normal file
50
firmware/targets/f6/api-hal/api-hal-resources.c
Normal file
@@ -0,0 +1,50 @@
|
||||
#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 vibro_gpio = {.port = VIBRO_GPIO_Port, .pin = VIBRO_Pin};
|
||||
const GpioPin ibutton_gpio = {.port = iBTN_GPIO_Port, .pin = iBTN_Pin};
|
||||
|
||||
const GpioPin gpio_cc1101_g0 = {.port = CC1101_G0_GPIO_Port, .pin = CC1101_G0_Pin};
|
||||
const GpioPin gpio_rf_sw_0 = {.port = RF_SW_0_GPIO_Port, .pin = RF_SW_0_Pin};
|
||||
|
||||
const GpioPin gpio_subghz_cs = {.port = CC1101_CS_GPIO_Port, .pin = CC1101_CS_Pin};
|
||||
const GpioPin gpio_display_cs = {.port = DISPLAY_CS_GPIO_Port, .pin = DISPLAY_CS_Pin};
|
||||
const GpioPin gpio_display_rst = {.port = DISPLAY_RST_GPIO_Port, .pin = DISPLAY_RST_Pin};
|
||||
const GpioPin gpio_display_di = {.port = DISPLAY_DI_GPIO_Port, .pin = DISPLAY_DI_Pin};
|
||||
const GpioPin gpio_sdcard_cs = {.port = SD_CS_GPIO_Port, .pin = SD_CS_Pin};
|
||||
const GpioPin gpio_nfc_cs = {.port = NFC_CS_GPIO_Port, .pin = NFC_CS_Pin};
|
||||
|
||||
const GpioPin gpio_spi_d_miso = {.port = SPI_D_MISO_GPIO_Port, .pin = SPI_D_MISO_Pin};
|
||||
const GpioPin gpio_spi_d_mosi = {.port = SPI_D_MOSI_GPIO_Port, .pin = SPI_D_MOSI_Pin};
|
||||
const GpioPin gpio_spi_d_sck = {.port = SPI_D_SCK_GPIO_Port, .pin = SPI_D_SCK_Pin};
|
||||
const GpioPin gpio_spi_r_miso = {.port = SPI_R_MISO_GPIO_Port, .pin = SPI_R_MISO_Pin};
|
||||
const GpioPin gpio_spi_r_mosi = {.port = SPI_R_MOSI_GPIO_Port, .pin = SPI_R_MOSI_Pin};
|
||||
const GpioPin gpio_spi_r_sck = {.port = SPI_R_SCK_GPIO_Port, .pin = SPI_R_SCK_Pin};
|
||||
|
||||
const GpioPin gpio_ext_pc0 = {.port = GPIOC, .pin = GPIO_PIN_0};
|
||||
const GpioPin gpio_ext_pc1 = {.port = GPIOC, .pin = GPIO_PIN_1};
|
||||
const GpioPin gpio_ext_pc3 = {.port = GPIOC, .pin = GPIO_PIN_3};
|
||||
const GpioPin gpio_ext_pb2 = {.port = GPIOB, .pin = GPIO_PIN_2};
|
||||
const GpioPin gpio_ext_pb3 = {.port = GPIOB, .pin = GPIO_PIN_3};
|
||||
const GpioPin gpio_ext_pa4 = {.port = GPIOA, .pin = GPIO_PIN_4};
|
||||
const GpioPin gpio_ext_pa6 = {.port = GPIOA, .pin = GPIO_PIN_6};
|
||||
const GpioPin gpio_ext_pa7 = {.port = GPIOA, .pin = GPIO_PIN_7};
|
||||
|
||||
const GpioPin gpio_rfid_pull = {.port = RFID_PULL_GPIO_Port, .pin = RFID_PULL_Pin};
|
||||
const GpioPin gpio_rfid_carrier_out = {.port = RFID_OUT_GPIO_Port, .pin = RFID_OUT_Pin};
|
||||
const GpioPin gpio_rfid_data_in = {.port = RFID_RF_IN_GPIO_Port, .pin = RFID_RF_IN_Pin};
|
||||
91
firmware/targets/f6/api-hal/api-hal-resources.h
Normal file
91
firmware/targets/f6/api-hal/api-hal-resources.h
Normal file
@@ -0,0 +1,91 @@
|
||||
#pragma once
|
||||
|
||||
#include "main.h"
|
||||
#include <furi.h>
|
||||
|
||||
#include <stm32wbxx.h>
|
||||
#include <stm32wbxx_ll_gpio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define POWER_I2C_SCL_Pin LL_GPIO_PIN_9
|
||||
#define POWER_I2C_SCL_GPIO_Port GPIOA
|
||||
#define POWER_I2C_SDA_Pin LL_GPIO_PIN_10
|
||||
#define POWER_I2C_SDA_GPIO_Port GPIOA
|
||||
|
||||
#define POWER_I2C I2C1
|
||||
/** Timing register value is computed with the STM32CubeMX Tool,
|
||||
* Fast Mode @100kHz with I2CCLK = 64 MHz,
|
||||
* rise time = 0ns, fall time = 0ns
|
||||
*/
|
||||
#define POWER_I2C_TIMINGS 0x10707DBC
|
||||
|
||||
/* 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 vibro_gpio;
|
||||
extern const GpioPin ibutton_gpio;
|
||||
|
||||
extern const GpioPin gpio_cc1101_g0;
|
||||
extern const GpioPin gpio_rf_sw_0;
|
||||
|
||||
extern const GpioPin gpio_subghz_cs;
|
||||
extern const GpioPin gpio_display_cs;
|
||||
extern const GpioPin gpio_display_rst;
|
||||
extern const GpioPin gpio_display_di;
|
||||
extern const GpioPin gpio_sdcard_cs;
|
||||
extern const GpioPin gpio_nfc_cs;
|
||||
|
||||
extern const GpioPin gpio_spi_d_miso;
|
||||
extern const GpioPin gpio_spi_d_mosi;
|
||||
extern const GpioPin gpio_spi_d_sck;
|
||||
extern const GpioPin gpio_spi_r_miso;
|
||||
extern const GpioPin gpio_spi_r_mosi;
|
||||
extern const GpioPin gpio_spi_r_sck;
|
||||
|
||||
extern const GpioPin gpio_ext_pc0;
|
||||
extern const GpioPin gpio_ext_pc1;
|
||||
extern const GpioPin gpio_ext_pc3;
|
||||
extern const GpioPin gpio_ext_pb2;
|
||||
extern const GpioPin gpio_ext_pb3;
|
||||
extern const GpioPin gpio_ext_pa4;
|
||||
extern const GpioPin gpio_ext_pa6;
|
||||
extern const GpioPin gpio_ext_pa7;
|
||||
|
||||
extern const GpioPin gpio_rfid_pull;
|
||||
extern const GpioPin gpio_rfid_carrier_out;
|
||||
extern const GpioPin gpio_rfid_data_in;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
202
firmware/targets/f6/api-hal/api-hal-rfid.c
Normal file
202
firmware/targets/f6/api-hal/api-hal-rfid.c
Normal file
@@ -0,0 +1,202 @@
|
||||
#include <api-hal-rfid.h>
|
||||
#include <api-hal-ibutton.h>
|
||||
#include <api-hal-resources.h>
|
||||
|
||||
void api_hal_rfid_pins_reset() {
|
||||
// ibutton bus disable
|
||||
api_hal_ibutton_stop();
|
||||
|
||||
// pulldown rfid antenna
|
||||
hal_gpio_init(&gpio_rfid_carrier_out, GpioModeOutputPushPull, GpioSpeedLow, GpioPullNo);
|
||||
hal_gpio_write(&gpio_rfid_carrier_out, true);
|
||||
|
||||
// from both sides
|
||||
hal_gpio_init(&gpio_rfid_pull, GpioModeOutputPushPull, GpioSpeedLow, GpioPullNo);
|
||||
hal_gpio_write(&gpio_rfid_pull, true);
|
||||
}
|
||||
|
||||
void api_hal_rfid_pins_emulate() {
|
||||
// ibutton low
|
||||
api_hal_ibutton_start();
|
||||
api_hal_ibutton_pin_low();
|
||||
|
||||
// pull pin to timer out
|
||||
hal_gpio_init_alt(
|
||||
&gpio_rfid_pull, GpioModeOutputPushPull, GpioSpeedLow, GpioPullNo, GpioAltFn1TIM1);
|
||||
|
||||
// pull rfid antenna from carrier side
|
||||
hal_gpio_init(&gpio_rfid_carrier_out, GpioModeOutputPushPull, GpioSpeedLow, GpioPullNo);
|
||||
hal_gpio_write(&gpio_rfid_carrier_out, true);
|
||||
}
|
||||
|
||||
void api_hal_rfid_pins_read() {
|
||||
// ibutton low
|
||||
api_hal_ibutton_start();
|
||||
api_hal_ibutton_pin_low();
|
||||
|
||||
// dont pull rfid antenna
|
||||
hal_gpio_init(&gpio_rfid_pull, GpioModeOutputPushPull, GpioSpeedLow, GpioPullNo);
|
||||
hal_gpio_write(&gpio_rfid_pull, false);
|
||||
|
||||
// carrier pin to timer out
|
||||
hal_gpio_init_alt(
|
||||
&gpio_rfid_carrier_out, GpioModeOutputPushPull, GpioSpeedLow, GpioPullNo, GpioAltFn1TIM1);
|
||||
|
||||
// comparator in
|
||||
hal_gpio_init(&gpio_rfid_data_in, GpioModeAnalog, GpioSpeedLow, GpioPullNo);
|
||||
}
|
||||
|
||||
void api_hal_rfid_tim_read(float freq, float duty_cycle) {
|
||||
// TODO LL init
|
||||
uint32_t period = (uint32_t)((SystemCoreClock) / freq) - 1;
|
||||
|
||||
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
|
||||
TIM_MasterConfigTypeDef sMasterConfig = {0};
|
||||
TIM_OC_InitTypeDef sConfigOC = {0};
|
||||
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
|
||||
|
||||
// basic PWM setup with needed freq and internal clock
|
||||
LFRFID_TIM.Instance = TIM1;
|
||||
LFRFID_TIM.Init.Prescaler = 0;
|
||||
LFRFID_TIM.Init.CounterMode = TIM_COUNTERMODE_UP;
|
||||
LFRFID_TIM.Init.Period = period;
|
||||
LFRFID_TIM.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
||||
LFRFID_TIM.Init.RepetitionCounter = 0;
|
||||
LFRFID_TIM.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
|
||||
if(HAL_TIM_Base_Init(&LFRFID_TIM) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
|
||||
if(HAL_TIM_ConfigClockSource(&LFRFID_TIM, &sClockSourceConfig) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
if(HAL_TIM_PWM_Init(&LFRFID_TIM) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
// no master-slave mode
|
||||
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
|
||||
sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
|
||||
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
|
||||
if(HAL_TIMEx_MasterConfigSynchronization(&LFRFID_TIM, &sMasterConfig) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
// pwm config
|
||||
sConfigOC.OCMode = TIM_OCMODE_PWM1;
|
||||
sConfigOC.Pulse = (uint32_t)(LFRFID_TIM.Init.Period * duty_cycle);
|
||||
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;
|
||||
if(HAL_TIM_OC_ConfigChannel(&LFRFID_TIM, &sConfigOC, LFRFID_CH) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
// no deadtime
|
||||
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
|
||||
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
|
||||
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
|
||||
sBreakDeadTimeConfig.DeadTime = 0;
|
||||
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
|
||||
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
|
||||
sBreakDeadTimeConfig.BreakFilter = 0;
|
||||
sBreakDeadTimeConfig.BreakAFMode = TIM_BREAK_AFMODE_INPUT;
|
||||
sBreakDeadTimeConfig.Break2State = TIM_BREAK2_DISABLE;
|
||||
sBreakDeadTimeConfig.Break2Polarity = TIM_BREAK2POLARITY_HIGH;
|
||||
sBreakDeadTimeConfig.Break2Filter = 0;
|
||||
sBreakDeadTimeConfig.Break2AFMode = TIM_BREAK_AFMODE_INPUT;
|
||||
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
|
||||
if(HAL_TIMEx_ConfigBreakDeadTime(&LFRFID_TIM, &sBreakDeadTimeConfig) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
}
|
||||
|
||||
void api_hal_rfid_tim_read_start() {
|
||||
HAL_TIMEx_PWMN_Start(&LFRFID_TIM, LFRFID_CH);
|
||||
}
|
||||
|
||||
void api_hal_rfid_tim_read_stop() {
|
||||
HAL_TIMEx_PWMN_Stop(&LFRFID_TIM, LFRFID_CH);
|
||||
}
|
||||
|
||||
void api_hal_rfid_tim_emulate(float freq) {
|
||||
// TODO LL init
|
||||
uint32_t prescaler = (uint32_t)((SystemCoreClock) / freq) - 1;
|
||||
|
||||
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
|
||||
TIM_MasterConfigTypeDef sMasterConfig = {0};
|
||||
TIM_OC_InitTypeDef sConfigOC = {0};
|
||||
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
|
||||
|
||||
// basic PWM setup with needed freq and internal clock
|
||||
LFRFID_TIM.Instance = TIM1;
|
||||
LFRFID_TIM.Init.Prescaler = prescaler;
|
||||
LFRFID_TIM.Init.CounterMode = TIM_COUNTERMODE_UP;
|
||||
LFRFID_TIM.Init.Period = 1;
|
||||
LFRFID_TIM.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
||||
LFRFID_TIM.Init.RepetitionCounter = 0;
|
||||
LFRFID_TIM.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
|
||||
if(HAL_TIM_Base_Init(&LFRFID_TIM) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
|
||||
if(HAL_TIM_ConfigClockSource(&LFRFID_TIM, &sClockSourceConfig) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
if(HAL_TIM_PWM_Init(&LFRFID_TIM) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
// no master-slave mode
|
||||
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
|
||||
sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
|
||||
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
|
||||
if(HAL_TIMEx_MasterConfigSynchronization(&LFRFID_TIM, &sMasterConfig) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
// pwm config
|
||||
sConfigOC.OCMode = TIM_OCMODE_PWM1;
|
||||
sConfigOC.Pulse = 1;
|
||||
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;
|
||||
if(HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, LFRFID_CH) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
// no deadtime
|
||||
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
|
||||
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
|
||||
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
|
||||
sBreakDeadTimeConfig.DeadTime = 0;
|
||||
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
|
||||
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
|
||||
sBreakDeadTimeConfig.BreakFilter = 0;
|
||||
sBreakDeadTimeConfig.BreakAFMode = TIM_BREAK_AFMODE_INPUT;
|
||||
sBreakDeadTimeConfig.Break2State = TIM_BREAK2_DISABLE;
|
||||
sBreakDeadTimeConfig.Break2Polarity = TIM_BREAK2POLARITY_HIGH;
|
||||
sBreakDeadTimeConfig.Break2Filter = 0;
|
||||
sBreakDeadTimeConfig.Break2AFMode = TIM_BREAK_AFMODE_INPUT;
|
||||
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
|
||||
if(HAL_TIMEx_ConfigBreakDeadTime(&LFRFID_TIM, &sBreakDeadTimeConfig) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
}
|
||||
|
||||
void api_hal_rfid_tim_emulate_start() {
|
||||
HAL_TIM_PWM_Start_IT(&LFRFID_TIM, LFRFID_CH);
|
||||
HAL_TIM_Base_Start_IT(&LFRFID_TIM);
|
||||
}
|
||||
|
||||
void api_hal_rfid_tim_emulate_stop() {
|
||||
HAL_TIM_Base_Stop(&LFRFID_TIM);
|
||||
HAL_TIM_PWM_Stop(&LFRFID_TIM, LFRFID_CH);
|
||||
}
|
||||
|
||||
void api_hal_rfid_tim_reset() {
|
||||
}
|
||||
22
firmware/targets/f6/api-hal/api-hal-sd.c
Normal file
22
firmware/targets/f6/api-hal/api-hal-sd.c
Normal file
@@ -0,0 +1,22 @@
|
||||
#include "api-hal-sd.h"
|
||||
#include <stm32wbxx_ll_gpio.h>
|
||||
#include <furi.h>
|
||||
|
||||
void hal_sd_detect_init(void) {
|
||||
// low speed input with pullup
|
||||
LL_GPIO_SetPinMode(SD_CD_GPIO_Port, SD_CD_Pin, LL_GPIO_MODE_INPUT);
|
||||
LL_GPIO_SetPinSpeed(SD_CD_GPIO_Port, SD_CD_Pin, LL_GPIO_SPEED_FREQ_LOW);
|
||||
LL_GPIO_SetPinPull(SD_CD_GPIO_Port, SD_CD_Pin, LL_GPIO_PULL_UP);
|
||||
}
|
||||
|
||||
void hal_sd_detect_set_low(void) {
|
||||
// low speed input with pullup
|
||||
LL_GPIO_SetPinMode(SD_CD_GPIO_Port, SD_CD_Pin, LL_GPIO_MODE_OUTPUT);
|
||||
LL_GPIO_SetPinOutputType(SD_CD_GPIO_Port, SD_CD_Pin, LL_GPIO_OUTPUT_OPENDRAIN);
|
||||
LL_GPIO_ResetOutputPin(SD_CD_GPIO_Port, SD_CD_Pin);
|
||||
}
|
||||
|
||||
bool hal_sd_detect(void) {
|
||||
bool result = !(LL_GPIO_IsInputPinSet(SD_CD_GPIO_Port, SD_CD_Pin));
|
||||
return result;
|
||||
}
|
||||
122
firmware/targets/f6/api-hal/api-hal-spi-config.c
Normal file
122
firmware/targets/f6/api-hal/api-hal-spi-config.c
Normal file
@@ -0,0 +1,122 @@
|
||||
#include <api-hal-spi-config.h>
|
||||
#include <api-hal-resources.h>
|
||||
|
||||
extern SPI_HandleTypeDef SPI_R;
|
||||
extern SPI_HandleTypeDef SPI_D;
|
||||
|
||||
const SPI_InitTypeDef api_hal_spi_config_nfc = {
|
||||
.Mode = SPI_MODE_MASTER,
|
||||
.Direction = SPI_DIRECTION_2LINES,
|
||||
.DataSize = SPI_DATASIZE_8BIT,
|
||||
.CLKPolarity = SPI_POLARITY_LOW,
|
||||
.CLKPhase = SPI_PHASE_2EDGE,
|
||||
.NSS = SPI_NSS_SOFT,
|
||||
.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8,
|
||||
.FirstBit = SPI_FIRSTBIT_MSB,
|
||||
.TIMode = SPI_TIMODE_DISABLE,
|
||||
.CRCCalculation = SPI_CRCCALCULATION_DISABLE,
|
||||
.CRCPolynomial = 7,
|
||||
.CRCLength = SPI_CRC_LENGTH_DATASIZE,
|
||||
.NSSPMode = SPI_NSS_PULSE_DISABLE,
|
||||
};
|
||||
|
||||
const SPI_InitTypeDef api_hal_spi_config_subghz = {
|
||||
.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_8,
|
||||
.FirstBit = SPI_FIRSTBIT_MSB,
|
||||
.TIMode = SPI_TIMODE_DISABLE,
|
||||
.CRCCalculation = SPI_CRCCALCULATION_DISABLE,
|
||||
.CRCPolynomial = 7,
|
||||
.CRCLength = SPI_CRC_LENGTH_DATASIZE,
|
||||
.NSSPMode = SPI_NSS_PULSE_DISABLE,
|
||||
};
|
||||
|
||||
const SPI_InitTypeDef api_hal_spi_config_display = {
|
||||
.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,
|
||||
};
|
||||
|
||||
osMutexId_t spi_mutex_d = NULL;
|
||||
osMutexId_t spi_mutex_r = NULL;
|
||||
|
||||
const ApiHalSpiBus spi_r = {
|
||||
.spi=&SPI_R,
|
||||
.mutex=&spi_mutex_r,
|
||||
.miso=&gpio_spi_r_miso,
|
||||
.mosi=&gpio_spi_r_mosi,
|
||||
.clk=&gpio_spi_r_sck,
|
||||
};
|
||||
|
||||
const ApiHalSpiBus spi_d = {
|
||||
.spi=&SPI_D,
|
||||
.mutex=&spi_mutex_d,
|
||||
.miso=&gpio_spi_d_miso,
|
||||
.mosi=&gpio_spi_d_mosi,
|
||||
.clk=&gpio_spi_d_sck,
|
||||
};
|
||||
|
||||
const ApiHalSpiDevice api_hal_spi_devices[ApiHalSpiDeviceIdMax] = {
|
||||
{ .bus=&spi_r, .config=&api_hal_spi_config_subghz, .chip_select=&gpio_subghz_cs, },
|
||||
{ .bus=&spi_d, .config=&api_hal_spi_config_display, .chip_select=&gpio_display_cs, },
|
||||
{ .bus=&spi_d, .config=NULL, .chip_select=&gpio_sdcard_cs, },
|
||||
{ .bus=&spi_r, .config=&api_hal_spi_config_nfc, .chip_select=&gpio_nfc_cs },
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* SD Card in fast mode (after init)
|
||||
*/
|
||||
const SPIDevice sd_fast_spi = {
|
||||
.bus= &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 = {
|
||||
.bus= &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,
|
||||
}};
|
||||
67
firmware/targets/f6/api-hal/api-hal-spi-config.h
Normal file
67
firmware/targets/f6/api-hal/api-hal-spi-config.h
Normal file
@@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
|
||||
#include <api-hal-gpio.h>
|
||||
#include <cmsis_os2.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern const SPI_InitTypeDef api_hal_spi_config_nfc;
|
||||
extern const SPI_InitTypeDef api_hal_spi_config_subghz;
|
||||
extern const SPI_InitTypeDef api_hal_spi_config_display;
|
||||
|
||||
/** API HAL SPI BUS handler
|
||||
* Structure content may change at some point
|
||||
*/
|
||||
typedef struct {
|
||||
const SPI_HandleTypeDef* spi;
|
||||
const osMutexId_t* mutex;
|
||||
const GpioPin* miso;
|
||||
const GpioPin* mosi;
|
||||
const GpioPin* clk;
|
||||
} ApiHalSpiBus;
|
||||
|
||||
/** API HAL SPI Device handler
|
||||
* Structure content may change at some point
|
||||
*/
|
||||
typedef struct {
|
||||
const ApiHalSpiBus* bus;
|
||||
const SPI_InitTypeDef* config;
|
||||
const GpioPin* chip_select;
|
||||
} ApiHalSpiDevice;
|
||||
|
||||
/** API HAL SPI Standard Device IDs */
|
||||
typedef enum {
|
||||
ApiHalSpiDeviceIdSubGhz, /** SubGhz: CC1101, non-standard SPI usage */
|
||||
ApiHalSpiDeviceIdDisplay, /** Display: ERC12864, only have MOSI */
|
||||
ApiHalSpiDeviceIdSdCard, /** SDCARD: no default bus config, bus must explicitly be configured */
|
||||
ApiHalSpiDeviceIdNfc, /** NFC: ST25R3916, pretty standard, but RFAL makes it complex */
|
||||
|
||||
ApiHalSpiDeviceIdMax, /** Service Value, do not use */
|
||||
} ApiHalSpiDeviceId;
|
||||
|
||||
/** Api Hal Spi Bus R
|
||||
* CC1101, Nfc
|
||||
*/
|
||||
extern const ApiHalSpiBus spi_r;
|
||||
|
||||
/** Api Hal Spi Bus D
|
||||
* Display, SdCard
|
||||
*/
|
||||
extern const ApiHalSpiBus spi_d;
|
||||
|
||||
/** Api Hal Spi devices */
|
||||
extern const ApiHalSpiDevice api_hal_spi_devices[ApiHalSpiDeviceIdMax];
|
||||
|
||||
typedef struct {
|
||||
const ApiHalSpiBus* bus;
|
||||
const SPI_InitTypeDef config;
|
||||
} SPIDevice;
|
||||
|
||||
extern const SPIDevice sd_fast_spi;
|
||||
extern const SPIDevice sd_slow_spi;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
180
firmware/targets/f6/api-hal/api-hal-spi.c
Normal file
180
firmware/targets/f6/api-hal/api-hal-spi.c
Normal file
@@ -0,0 +1,180 @@
|
||||
#include "api-hal-spi.h"
|
||||
#include <api-hal-resources.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <spi.h>
|
||||
#include <furi.h>
|
||||
|
||||
|
||||
extern void Enable_SPI(SPI_HandleTypeDef* spi);
|
||||
|
||||
void api_hal_spi_init() {
|
||||
// Spi structure is const, but mutex is not
|
||||
// Need some hell-ish casting to make it work
|
||||
*(osMutexId_t*)spi_r.mutex = osMutexNew(NULL);
|
||||
*(osMutexId_t*)spi_d.mutex = osMutexNew(NULL);
|
||||
//
|
||||
for (size_t i=0; i<ApiHalSpiDeviceIdMax; ++i) {
|
||||
hal_gpio_init(
|
||||
api_hal_spi_devices[i].chip_select,
|
||||
GpioModeOutputPushPull,
|
||||
GpioPullNo,
|
||||
GpioSpeedVeryHigh
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void api_hal_spi_bus_lock(const ApiHalSpiBus* bus) {
|
||||
furi_assert(bus);
|
||||
if (bus->mutex) {
|
||||
osMutexAcquire(*bus->mutex, osWaitForever);
|
||||
}
|
||||
}
|
||||
|
||||
void api_hal_spi_bus_unlock(const ApiHalSpiBus* bus) {
|
||||
furi_assert(bus);
|
||||
if (bus->mutex) {
|
||||
osMutexRelease(*bus->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
bool api_hal_spi_bus_rx(const ApiHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout) {
|
||||
furi_assert(bus);
|
||||
furi_assert(buffer);
|
||||
furi_assert(size > 0);
|
||||
|
||||
HAL_StatusTypeDef ret = HAL_SPI_Receive((SPI_HandleTypeDef *)bus->spi, buffer, size, HAL_MAX_DELAY);
|
||||
|
||||
return ret == HAL_OK;
|
||||
}
|
||||
|
||||
bool api_hal_spi_bus_tx(const ApiHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout) {
|
||||
furi_assert(bus);
|
||||
furi_assert(buffer);
|
||||
furi_assert(size > 0);
|
||||
|
||||
HAL_StatusTypeDef ret = HAL_SPI_Transmit((SPI_HandleTypeDef *)bus->spi, buffer, size, HAL_MAX_DELAY);
|
||||
|
||||
return ret == HAL_OK;
|
||||
}
|
||||
|
||||
bool api_hal_spi_bus_trx(const ApiHalSpiBus* bus, uint8_t* tx_buffer, uint8_t* rx_buffer, size_t size, uint32_t timeout) {
|
||||
furi_assert(bus);
|
||||
furi_assert(tx_buffer);
|
||||
furi_assert(rx_buffer);
|
||||
furi_assert(size > 0);
|
||||
|
||||
HAL_StatusTypeDef ret = HAL_SPI_TransmitReceive((SPI_HandleTypeDef *)bus->spi, tx_buffer, rx_buffer, size, HAL_MAX_DELAY);
|
||||
|
||||
return ret == HAL_OK;
|
||||
}
|
||||
|
||||
const ApiHalSpiDevice* api_hal_spi_device_get(ApiHalSpiDeviceId device_id) {
|
||||
furi_assert(device_id < ApiHalSpiDeviceIdMax);
|
||||
|
||||
const ApiHalSpiDevice* device = &api_hal_spi_devices[device_id];
|
||||
assert(device);
|
||||
api_hal_spi_bus_lock(device->bus);
|
||||
|
||||
if (device->config) {
|
||||
memcpy((SPI_InitTypeDef*)&device->bus->spi->Init, device->config, sizeof(SPI_InitTypeDef));
|
||||
if(HAL_SPI_Init((SPI_HandleTypeDef *)device->bus->spi) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
Enable_SPI((SPI_HandleTypeDef *)device->bus->spi);
|
||||
}
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
void api_hal_spi_device_return(const ApiHalSpiDevice* device) {
|
||||
api_hal_spi_bus_unlock(device->bus);
|
||||
}
|
||||
|
||||
bool api_hal_spi_device_rx(const ApiHalSpiDevice* device, uint8_t* buffer, size_t size, uint32_t timeout) {
|
||||
furi_assert(device);
|
||||
furi_assert(buffer);
|
||||
furi_assert(size > 0);
|
||||
|
||||
if (device->chip_select) {
|
||||
hal_gpio_write(device->chip_select, false);
|
||||
}
|
||||
|
||||
bool ret = api_hal_spi_bus_rx(device->bus, buffer, size, HAL_MAX_DELAY);
|
||||
|
||||
if (device->chip_select) {
|
||||
hal_gpio_write(device->chip_select, true);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool api_hal_spi_device_tx(const ApiHalSpiDevice* device, uint8_t* buffer, size_t size, uint32_t timeout) {
|
||||
furi_assert(device);
|
||||
furi_assert(buffer);
|
||||
furi_assert(size > 0);
|
||||
|
||||
if (device->chip_select) {
|
||||
hal_gpio_write(device->chip_select, false);
|
||||
}
|
||||
|
||||
bool ret = api_hal_spi_bus_tx(device->bus, buffer, size, HAL_MAX_DELAY);
|
||||
|
||||
if (device->chip_select) {
|
||||
hal_gpio_write(device->chip_select, true);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool api_hal_spi_device_trx(const ApiHalSpiDevice* device, uint8_t* tx_buffer, uint8_t* rx_buffer, size_t size, uint32_t timeout) {
|
||||
furi_assert(device);
|
||||
furi_assert(tx_buffer);
|
||||
furi_assert(rx_buffer);
|
||||
furi_assert(size > 0);
|
||||
|
||||
if (device->chip_select) {
|
||||
hal_gpio_write(device->chip_select, false);
|
||||
}
|
||||
|
||||
bool ret = api_hal_spi_bus_trx(device->bus, tx_buffer, rx_buffer, size, HAL_MAX_DELAY);
|
||||
|
||||
if (device->chip_select) {
|
||||
hal_gpio_write(device->chip_select, true);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void api_hal_spi_apply_config(const SPIDevice* device) {
|
||||
osKernelLock();
|
||||
|
||||
memcpy((SPI_InitTypeDef*)&device->bus->spi->Init, &device->config, sizeof(SPI_InitTypeDef));
|
||||
|
||||
if(HAL_SPI_Init((SPI_HandleTypeDef*)device->bus->spi) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
Enable_SPI((SPI_HandleTypeDef*)device->bus->spi);
|
||||
|
||||
osKernelUnlock();
|
||||
}
|
||||
|
||||
bool api_hal_spi_config_are_actual(const SPIDevice* device) {
|
||||
return (memcmp(&device->config, &device->bus->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_device(const SPIDevice* device) {
|
||||
api_hal_spi_bus_lock(device->bus);
|
||||
api_hal_spi_config_device(device);
|
||||
}
|
||||
|
||||
void api_hal_spi_unlock_device(const SPIDevice* device) {
|
||||
api_hal_spi_bus_unlock(device->bus);
|
||||
}
|
||||
106
firmware/targets/f6/api-hal/api-hal-spi.h
Normal file
106
firmware/targets/f6/api-hal/api-hal-spi.h
Normal file
@@ -0,0 +1,106 @@
|
||||
#pragma once
|
||||
#include "main.h"
|
||||
#include "api-hal-spi-config.h"
|
||||
#include <api-hal-gpio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Init SPI API
|
||||
*/
|
||||
void api_hal_spi_init();
|
||||
|
||||
/* Bus Level API */
|
||||
|
||||
/** Lock SPI bus
|
||||
* Takes bus mutex, if used
|
||||
*/
|
||||
void api_hal_spi_bus_lock(const ApiHalSpiBus* bus);
|
||||
|
||||
/** Unlock SPI bus
|
||||
* Releases BUS mutex, if used
|
||||
*/
|
||||
void api_hal_spi_bus_unlock(const ApiHalSpiBus* bus);
|
||||
|
||||
/** SPI Receive
|
||||
* @param bus - spi bus handler
|
||||
* @param buffer - receive buffer
|
||||
* @param size - transaction size
|
||||
* @param timeout - bus operation timeout in ms
|
||||
*/
|
||||
bool api_hal_spi_bus_rx(const ApiHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout);
|
||||
|
||||
/** SPI Transmit
|
||||
* @param bus - spi bus handler
|
||||
* @param buffer - transmit buffer
|
||||
* @param size - transaction size
|
||||
* @param timeout - bus operation timeout in ms
|
||||
*/
|
||||
bool api_hal_spi_bus_tx(const ApiHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout);
|
||||
|
||||
/** SPI Transmit and Receive
|
||||
* @param bus - spi bus handlere
|
||||
* @param tx_buffer - device handle
|
||||
* @param rx_buffer - device handle
|
||||
* @param size - transaction size
|
||||
* @param timeout - bus operation timeout in ms
|
||||
*/
|
||||
bool api_hal_spi_bus_trx(const ApiHalSpiBus* bus, uint8_t* tx_buffer, uint8_t* rx_buffer, size_t size, uint32_t timeout);
|
||||
|
||||
/* Device Level API */
|
||||
|
||||
/** Get Device handle
|
||||
* And lock access to the corresponding SPI BUS
|
||||
* @param device_id - device identifier
|
||||
* @return device handle
|
||||
*/
|
||||
const ApiHalSpiDevice* api_hal_spi_device_get(ApiHalSpiDeviceId device_id);
|
||||
|
||||
/** Return Device handle
|
||||
* And unlock access to the corresponding SPI BUS
|
||||
* @param device - device handle
|
||||
*/
|
||||
void api_hal_spi_device_return(const ApiHalSpiDevice* device);
|
||||
|
||||
/** SPI Recieve
|
||||
* @param device - device handle
|
||||
* @param buffer - receive buffer
|
||||
* @param size - transaction size
|
||||
* @param timeout - bus operation timeout in ms
|
||||
*/
|
||||
bool api_hal_spi_device_rx(const ApiHalSpiDevice* device, uint8_t* buffer, size_t size, uint32_t timeout);
|
||||
|
||||
/** SPI Transmit
|
||||
* @param device - device handle
|
||||
* @param buffer - transmit buffer
|
||||
* @param size - transaction size
|
||||
* @param timeout - bus operation timeout in ms
|
||||
*/
|
||||
bool api_hal_spi_device_tx(const ApiHalSpiDevice* device, uint8_t* buffer, size_t size, uint32_t timeout);
|
||||
|
||||
/** SPI Transmit and Receive
|
||||
* @param device - device handle
|
||||
* @param tx_buffer - device handle
|
||||
* @param rx_buffer - device handle
|
||||
* @param size - transaction size
|
||||
* @param timeout - bus operation timeout in ms
|
||||
*/
|
||||
bool api_hal_spi_device_trx(const ApiHalSpiDevice* device, uint8_t* tx_buffer, uint8_t* rx_buffer, size_t size, uint32_t timeout);
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
191
firmware/targets/f6/api-hal/api-hal-subghz.c
Normal file
191
firmware/targets/f6/api-hal/api-hal-subghz.c
Normal file
@@ -0,0 +1,191 @@
|
||||
#include "api-hal-subghz.h"
|
||||
|
||||
#include <api-hal-gpio.h>
|
||||
#include <api-hal-spi.h>
|
||||
#include <api-hal-resources.h>
|
||||
#include <furi.h>
|
||||
#include <cc1101.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static const uint8_t api_hal_subghz_preset_ook_async_regs[][2] = {
|
||||
/* Base setting */
|
||||
{ CC1101_IOCFG0, 0x0D }, // GD0 as async serial data output/input
|
||||
{ CC1101_FSCTRL1, 0x06 }, // Set IF 26m/2^10*2=2.2MHz
|
||||
{ CC1101_MCSM0, 0x18 }, // Autocalibrate on idle to TRX, ~150us OSC guard time
|
||||
/* Async OOK Specific things */
|
||||
{ CC1101_MDMCFG2, 0x30 }, // ASK/OOK, No preamble/sync
|
||||
{ CC1101_PKTCTRL0, 0x32 }, // Async, no CRC, Infinite
|
||||
{ CC1101_FREND0, 0x01 }, // OOK/ASK PATABLE
|
||||
/* End */
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
static const uint8_t api_hal_subghz_preset_ook_async_patable[8] = {
|
||||
0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
static const uint8_t api_hal_subghz_preset_2fsk_packet_regs[][2] = {
|
||||
/* Base setting */
|
||||
{ CC1101_IOCFG0, 0x06 }, // GD0 as async serial data output/input
|
||||
{ CC1101_FSCTRL1, 0x06 }, // Set IF 26m/2^10*2=2.2MHz
|
||||
{ CC1101_MCSM0, 0x18 }, // Autocalibrate on idle to TRX, ~150us OSC guard time
|
||||
/* End */
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
static const uint8_t api_hal_subghz_preset_2fsk_packet_patable[8] = {
|
||||
0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
void api_hal_subghz_init() {
|
||||
const ApiHalSpiDevice* device = api_hal_spi_device_get(ApiHalSpiDeviceIdSubGhz);
|
||||
// Reset and shutdown
|
||||
cc1101_reset(device);
|
||||
// Prepare GD0 for power on self test
|
||||
hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
|
||||
// GD0 low
|
||||
cc1101_write_reg(device, CC1101_IOCFG0, CC1101IocfgHW);
|
||||
while(hal_gpio_read(&gpio_cc1101_g0) != false);
|
||||
// GD0 high
|
||||
cc1101_write_reg(device, CC1101_IOCFG0, CC1101IocfgHW | CC1101_IOCFG_INV);
|
||||
while(hal_gpio_read(&gpio_cc1101_g0) != true);
|
||||
// Reset GD0 to floating state
|
||||
cc1101_write_reg(device, CC1101_IOCFG0, CC1101IocfgHighImpedance);
|
||||
hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
// RF switches
|
||||
hal_gpio_init(&gpio_rf_sw_0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
|
||||
cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW);
|
||||
// Turn off oscillator
|
||||
cc1101_shutdown(device);
|
||||
api_hal_spi_device_return(device);
|
||||
}
|
||||
|
||||
void api_hal_subghz_dump_state() {
|
||||
const ApiHalSpiDevice* device = api_hal_spi_device_get(ApiHalSpiDeviceIdSubGhz);
|
||||
printf(
|
||||
"[api_hal_subghz] cc1101 chip %d, version %d\r\n",
|
||||
cc1101_get_partnumber(device),
|
||||
cc1101_get_version(device)
|
||||
);
|
||||
api_hal_spi_device_return(device);
|
||||
}
|
||||
|
||||
void api_hal_subghz_load_preset(ApiHalSubGhzPreset preset) {
|
||||
if(preset == ApiHalSubGhzPresetOokAsync) {
|
||||
api_hal_subghz_load_registers(api_hal_subghz_preset_ook_async_regs);
|
||||
api_hal_subghz_load_patable(api_hal_subghz_preset_ook_async_patable);
|
||||
} else if(preset == ApiHalSubGhzPreset2FskPacket) {
|
||||
api_hal_subghz_load_registers(api_hal_subghz_preset_2fsk_packet_regs);
|
||||
api_hal_subghz_load_patable(api_hal_subghz_preset_2fsk_packet_patable);
|
||||
}
|
||||
}
|
||||
|
||||
void api_hal_subghz_load_registers(const uint8_t data[][2]) {
|
||||
const ApiHalSpiDevice* device = api_hal_spi_device_get(ApiHalSpiDeviceIdSubGhz);
|
||||
cc1101_reset(device);
|
||||
uint32_t i = 0;
|
||||
while (data[i][0]) {
|
||||
cc1101_write_reg(device, data[i][0], data[i][1]);
|
||||
i++;
|
||||
}
|
||||
api_hal_spi_device_return(device);
|
||||
}
|
||||
|
||||
void api_hal_subghz_load_patable(const uint8_t data[8]) {
|
||||
const ApiHalSpiDevice* device = api_hal_spi_device_get(ApiHalSpiDeviceIdSubGhz);
|
||||
cc1101_set_pa_table(device, data);
|
||||
api_hal_spi_device_return(device);
|
||||
}
|
||||
|
||||
void api_hal_subghz_write_packet(const uint8_t* data, uint8_t size) {
|
||||
const ApiHalSpiDevice* device = api_hal_spi_device_get(ApiHalSpiDeviceIdSubGhz);
|
||||
cc1101_flush_tx(device);
|
||||
cc1101_write_fifo(device, data, size);
|
||||
api_hal_spi_device_return(device);
|
||||
}
|
||||
|
||||
void api_hal_subghz_read_packet(uint8_t* data, uint8_t size) {
|
||||
|
||||
}
|
||||
|
||||
void api_hal_subghz_shutdown() {
|
||||
const ApiHalSpiDevice* device = api_hal_spi_device_get(ApiHalSpiDeviceIdSubGhz);
|
||||
// Reset and shutdown
|
||||
cc1101_shutdown(device);
|
||||
api_hal_spi_device_return(device);
|
||||
}
|
||||
|
||||
void api_hal_subghz_reset() {
|
||||
const ApiHalSpiDevice* device = api_hal_spi_device_get(ApiHalSpiDeviceIdSubGhz);
|
||||
cc1101_reset(device);
|
||||
api_hal_spi_device_return(device);
|
||||
}
|
||||
|
||||
void api_hal_subghz_idle() {
|
||||
const ApiHalSpiDevice* device = api_hal_spi_device_get(ApiHalSpiDeviceIdSubGhz);
|
||||
cc1101_switch_to_idle(device);
|
||||
api_hal_spi_device_return(device);
|
||||
}
|
||||
|
||||
void api_hal_subghz_rx() {
|
||||
const ApiHalSpiDevice* device = api_hal_spi_device_get(ApiHalSpiDeviceIdSubGhz);
|
||||
cc1101_switch_to_rx(device);
|
||||
api_hal_spi_device_return(device);
|
||||
}
|
||||
|
||||
void api_hal_subghz_tx() {
|
||||
const ApiHalSpiDevice* device = api_hal_spi_device_get(ApiHalSpiDeviceIdSubGhz);
|
||||
cc1101_switch_to_tx(device);
|
||||
api_hal_spi_device_return(device);
|
||||
}
|
||||
|
||||
float api_hal_subghz_get_rssi() {
|
||||
const ApiHalSpiDevice* device = api_hal_spi_device_get(ApiHalSpiDeviceIdSubGhz);
|
||||
int32_t rssi_dec = cc1101_get_rssi(device);
|
||||
api_hal_spi_device_return(device);
|
||||
|
||||
float rssi = rssi_dec;
|
||||
if(rssi_dec >= 128) {
|
||||
rssi = ((rssi - 256.0f) / 2.0f) - 74.0f;
|
||||
} else {
|
||||
rssi = (rssi / 2.0f) - 74.0f;
|
||||
}
|
||||
|
||||
return rssi;
|
||||
}
|
||||
|
||||
uint32_t api_hal_subghz_set_frequency(uint32_t value) {
|
||||
const ApiHalSpiDevice* device = api_hal_spi_device_get(ApiHalSpiDeviceIdSubGhz);
|
||||
|
||||
// Compensate rounding
|
||||
if (value % cc1101_get_frequency_step(device) > (cc1101_get_frequency_step(device) / 2)) {
|
||||
value += cc1101_get_frequency_step(device);
|
||||
}
|
||||
|
||||
uint32_t real_frequency = cc1101_set_frequency(device, value);
|
||||
cc1101_calibrate(device);
|
||||
|
||||
api_hal_spi_device_return(device);
|
||||
|
||||
return real_frequency;
|
||||
}
|
||||
|
||||
void api_hal_subghz_set_path(ApiHalSubGhzPath path) {
|
||||
const ApiHalSpiDevice* device = api_hal_spi_device_get(ApiHalSpiDeviceIdSubGhz);
|
||||
if (path == ApiHalSubGhzPath1) {
|
||||
hal_gpio_write(&gpio_rf_sw_0, 0);
|
||||
cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV);
|
||||
} else if (path == ApiHalSubGhzPath2) {
|
||||
hal_gpio_write(&gpio_rf_sw_0, 1);
|
||||
cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW);
|
||||
} else if (path == ApiHalSubGhzPath3) {
|
||||
hal_gpio_write(&gpio_rf_sw_0, 1);
|
||||
cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV);
|
||||
} else if (path == ApiHalSubGhzPathIsolate) {
|
||||
hal_gpio_write(&gpio_rf_sw_0, 0);
|
||||
cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW);
|
||||
} else {
|
||||
furi_check(0);
|
||||
}
|
||||
api_hal_spi_device_return(device);
|
||||
}
|
||||
54
firmware/targets/f6/api-hal/api-hal-task.c
Normal file
54
firmware/targets/f6/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/f6/api-hal/api-hal-task.h
Normal file
12
firmware/targets/f6/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/f6/api-hal/api-hal-tim.c
Normal file
47
firmware/targets/f6/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/f6/api-hal/api-hal-tim.h
Normal file
4
firmware/targets/f6/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/f6/api-hal/api-hal-uuid.c
Normal file
10
firmware/targets/f6/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;
|
||||
}
|
||||
101
firmware/targets/f6/api-hal/api-hal-vcp.c
Normal file
101
firmware/targets/f6/api-hal/api-hal-vcp.c
Normal file
@@ -0,0 +1,101 @@
|
||||
#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);
|
||||
}
|
||||
|
||||
size_t api_hal_vcp_rx_with_timeout(uint8_t* buffer, size_t size, uint32_t timeout) {
|
||||
furi_assert(api_hal_vcp);
|
||||
return xStreamBufferReceive(api_hal_vcp->rx_stream, buffer, size, timeout);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
55
firmware/targets/f6/api-hal/api-hal-version.c
Normal file
55
firmware/targets/f6/api-hal/api-hal-version.c
Normal file
@@ -0,0 +1,55 @@
|
||||
#include <api-hal-version.h>
|
||||
#include <stm32wbxx.h>
|
||||
#include <stm32wbxx_ll_rtc.h>
|
||||
|
||||
typedef struct {
|
||||
uint8_t version;
|
||||
uint8_t target;
|
||||
uint8_t body;
|
||||
uint8_t connect;
|
||||
uint32_t timestamp;
|
||||
char name[8];
|
||||
} 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;
|
||||
}
|
||||
|
||||
const char * api_hal_version_get_name_ptr() {
|
||||
char * name = ((ApiHalVersionOTP*)OTP_AREA_BASE)->name;
|
||||
return *name == 0xFFU ? NULL : name;
|
||||
}
|
||||
|
||||
const struct Version* api_hal_version_get_fw_version(void) {
|
||||
return version_get();
|
||||
}
|
||||
|
||||
const struct Version* api_hal_version_get_boot_version(void) {
|
||||
#ifdef NO_BOOTLOADER
|
||||
return 0;
|
||||
#else
|
||||
/* Backup register which points to structure in flash memory */
|
||||
return (const struct Version*) LL_RTC_BAK_GetRegister(RTC, LL_RTC_BKP_DR1);
|
||||
#endif
|
||||
}
|
||||
|
||||
11
firmware/targets/f6/api-hal/api-hal-vibro.c
Normal file
11
firmware/targets/f6/api-hal/api-hal-vibro.c
Normal file
@@ -0,0 +1,11 @@
|
||||
#include <api-hal-vibro.h>
|
||||
#include <api-hal-gpio.h>
|
||||
|
||||
void api_hal_vibro_init() {
|
||||
hal_gpio_init(&vibro_gpio, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
|
||||
hal_gpio_write(&vibro_gpio, false);
|
||||
}
|
||||
|
||||
void api_hal_vibro_on(bool value) {
|
||||
hal_gpio_write(&vibro_gpio, value);
|
||||
}
|
||||
22
firmware/targets/f6/api-hal/api-hal.c
Normal file
22
firmware/targets/f6/api-hal/api-hal.c
Normal file
@@ -0,0 +1,22 @@
|
||||
#include <api-hal.h>
|
||||
|
||||
void api_hal_init() {
|
||||
api_hal_delay_init();
|
||||
FURI_LOG_I("FURI_HAL", "DELAY OK");
|
||||
api_hal_os_init();
|
||||
FURI_LOG_I("FURI_HAL", "OS OK");
|
||||
api_hal_vcp_init();
|
||||
FURI_LOG_I("FURI_HAL", "VCP OK");
|
||||
api_hal_spi_init();
|
||||
FURI_LOG_I("FURI_HAL", "SPI OK");
|
||||
api_hal_i2c_init();
|
||||
FURI_LOG_I("FURI_HAL", "I2C OK");
|
||||
api_hal_power_init();
|
||||
FURI_LOG_I("FURI_HAL", "POWER OK");
|
||||
api_hal_light_init();
|
||||
FURI_LOG_I("FURI_HAL", "LIGHT OK");
|
||||
api_hal_vibro_init();
|
||||
FURI_LOG_I("FURI_HAL", "VIBRO OK");
|
||||
api_hal_subghz_init();
|
||||
FURI_LOG_I("FURI_HAL", "SUBGHZ OK");
|
||||
}
|
||||
26
firmware/targets/f6/api-hal/api-interrupts.c
Normal file
26
firmware/targets/f6/api-hal/api-interrupts.c
Normal file
@@ -0,0 +1,26 @@
|
||||
#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);
|
||||
}
|
||||
Reference in New Issue
Block a user