mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-04-24 03:29:57 -07:00
FuriHal: fix start duration furi_hal_subghz_async_tx (#3230)
* FuriHal: fix start duration furi_hal_subghz_async_tx * FuriHal: add check min duration arr for the first level * FuriHal: fix conflict dev * SubGhz: fix unit_test * FuriHal: subghz internal fix start/stop transmit duration * Drivers: subghz external fix start/stop transmit duration * FuriHal: subghz optimization * SubGhz: fix unit_test subghz * FuriHal: subghz fix end duration if size == size dma buf * FuriHal: revert enum values order, remove garbage * FuriHal: revert one more small bit in subghz * FuriHal: handle various corner cases in subghz transmission * FuriHal: cleanup subghz code * FuriHal: add parenthesis around value in subghz defines * FuriHal: add packer subghz_async_tx * FuriHal: more reliable subghz transmission end handling, fixes stuck transmission * FuriHal: add subghz crutch docs, and rename some defines to conform naming standards * FuriHal: subghz, the logic of timers has been changed. disabling the shadow register ARR * FuriHal: fix subghz off dma irq * SubGhzExt: fun rename * FuriHal,SubGhz: fix g0 state on reset, fix incorrect async_tx stop sequence, remove dead code. Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
@@ -18,14 +18,14 @@
|
||||
|
||||
#define TAG "SubGhzDeviceCc1101Ext"
|
||||
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_TX_GPIO &gpio_ext_pb2
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_TX_GPIO (&gpio_ext_pb2)
|
||||
|
||||
/* DMA Channels definition */
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_DMA DMA2
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_CHANNEL LL_DMA_CHANNEL_3
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_CHANNEL LL_DMA_CHANNEL_4
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_CHANNEL LL_DMA_CHANNEL_5
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_IRQ FuriHalInterruptIdDma2Ch3
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_DMA (DMA2)
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_CHANNEL (LL_DMA_CHANNEL_3)
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_CHANNEL (LL_DMA_CHANNEL_4)
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_CHANNEL (LL_DMA_CHANNEL_5)
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_IRQ (FuriHalInterruptIdDma2Ch3)
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF \
|
||||
SUBGHZ_DEVICE_CC1101_EXT_DMA, SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_CHANNEL
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF \
|
||||
@@ -34,10 +34,10 @@
|
||||
SUBGHZ_DEVICE_CC1101_EXT_DMA, SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_CHANNEL
|
||||
|
||||
/** Low level buffer dimensions and guard times */
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL (256)
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL (256u)
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_HALF \
|
||||
(SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL / 2)
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME 999 << 1
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME (999u >> 1)
|
||||
|
||||
/** SubGhz state */
|
||||
typedef enum {
|
||||
@@ -55,13 +55,25 @@ typedef enum {
|
||||
SubGhzDeviceCC1101ExtRegulationTxRx, /**TxRx*/
|
||||
} SubGhzDeviceCC1101ExtRegulation;
|
||||
|
||||
typedef enum {
|
||||
SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateIdle,
|
||||
SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateReset,
|
||||
SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateRun,
|
||||
} SubGhzDeviceCC1101ExtAsyncTxMiddlewareState;
|
||||
|
||||
typedef struct {
|
||||
SubGhzDeviceCC1101ExtAsyncTxMiddlewareState state;
|
||||
bool is_odd_level;
|
||||
uint32_t adder_duration;
|
||||
} SubGhzDeviceCC1101ExtAsyncTxMiddleware;
|
||||
|
||||
typedef struct {
|
||||
uint32_t* buffer;
|
||||
LevelDuration carry_ld;
|
||||
SubGhzDeviceCC1101ExtCallback callback;
|
||||
void* callback_context;
|
||||
uint32_t gpio_tx_buff[2];
|
||||
uint32_t debug_gpio_buff[2];
|
||||
SubGhzDeviceCC1101ExtAsyncTxMiddleware middleware;
|
||||
} SubGhzDeviceCC1101ExtAsyncTx;
|
||||
|
||||
typedef struct {
|
||||
@@ -259,8 +271,8 @@ void subghz_device_cc1101_ext_dump_state() {
|
||||
|
||||
void subghz_device_cc1101_ext_load_custom_preset(const uint8_t* preset_data) {
|
||||
//load config
|
||||
subghz_device_cc1101_ext_reset();
|
||||
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
cc1101_reset(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
uint32_t i = 0;
|
||||
uint8_t pa[8] = {0};
|
||||
while(preset_data[i]) {
|
||||
@@ -289,8 +301,8 @@ void subghz_device_cc1101_ext_load_custom_preset(const uint8_t* preset_data) {
|
||||
}
|
||||
|
||||
void subghz_device_cc1101_ext_load_registers(const uint8_t* data) {
|
||||
subghz_device_cc1101_ext_reset();
|
||||
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
cc1101_reset(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
uint32_t i = 0;
|
||||
while(data[i]) {
|
||||
cc1101_write_reg(subghz_device_cc1101_ext->spi_bus_handle, data[i], data[i + 1]);
|
||||
@@ -371,6 +383,7 @@ void subghz_device_cc1101_ext_reset() {
|
||||
furi_hal_gpio_init(subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
cc1101_switch_to_idle(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
cc1101_reset(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
// Warning: push pull cc1101 clock output on GD0
|
||||
cc1101_write_reg(
|
||||
subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHighImpedance);
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
@@ -563,50 +576,91 @@ void subghz_device_cc1101_ext_stop_async_rx() {
|
||||
furi_hal_gpio_init(subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
}
|
||||
|
||||
static void subghz_device_cc1101_ext_async_tx_refill(uint32_t* buffer, size_t samples) {
|
||||
furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx);
|
||||
while(samples > 0) {
|
||||
bool is_odd = samples % 2;
|
||||
LevelDuration ld;
|
||||
if(level_duration_is_reset(subghz_device_cc1101_ext->async_tx.carry_ld)) {
|
||||
ld = subghz_device_cc1101_ext->async_tx.callback(
|
||||
subghz_device_cc1101_ext->async_tx.callback_context);
|
||||
} else {
|
||||
ld = subghz_device_cc1101_ext->async_tx.carry_ld;
|
||||
subghz_device_cc1101_ext->async_tx.carry_ld = level_duration_reset();
|
||||
void subghz_device_cc1101_ext_async_tx_middleware_idle(
|
||||
SubGhzDeviceCC1101ExtAsyncTxMiddleware* middleware) {
|
||||
middleware->state = SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateIdle;
|
||||
middleware->is_odd_level = false;
|
||||
middleware->adder_duration = SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME;
|
||||
}
|
||||
|
||||
static inline uint32_t subghz_device_cc1101_ext_async_tx_middleware_get_duration(
|
||||
SubGhzDeviceCC1101ExtAsyncTxMiddleware* middleware,
|
||||
SubGhzDeviceCC1101ExtCallback callback) {
|
||||
uint32_t ret = 0;
|
||||
bool is_level = false;
|
||||
|
||||
if(middleware->state == SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateReset) return 0;
|
||||
|
||||
while(1) {
|
||||
LevelDuration ld = callback(subghz_device_cc1101_ext->async_tx.callback_context);
|
||||
if(level_duration_is_reset(ld)) {
|
||||
middleware->state = SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateReset;
|
||||
if(!middleware->is_odd_level) {
|
||||
return 0;
|
||||
} else {
|
||||
return middleware->adder_duration;
|
||||
}
|
||||
} else if(level_duration_is_wait(ld)) {
|
||||
middleware->is_odd_level = !middleware->is_odd_level;
|
||||
ret = middleware->adder_duration + SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME;
|
||||
middleware->adder_duration = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(level_duration_is_wait(ld)) {
|
||||
*buffer = SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME;
|
||||
buffer++;
|
||||
samples--;
|
||||
} else if(level_duration_is_reset(ld)) {
|
||||
is_level = level_duration_get_level(ld);
|
||||
|
||||
if(middleware->state == SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateIdle) {
|
||||
if(is_level != middleware->is_odd_level) {
|
||||
middleware->state = SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateRun;
|
||||
middleware->is_odd_level = is_level;
|
||||
middleware->adder_duration = level_duration_get_duration(ld);
|
||||
return SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if(middleware->state == SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateRun) {
|
||||
if(is_level == middleware->is_odd_level) {
|
||||
middleware->adder_duration += level_duration_get_duration(ld);
|
||||
continue;
|
||||
} else {
|
||||
middleware->is_odd_level = is_level;
|
||||
ret = middleware->adder_duration;
|
||||
middleware->adder_duration = level_duration_get_duration(ld);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void subghz_device_cc1101_ext_async_tx_refill(uint32_t* buffer, size_t samples) {
|
||||
furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx);
|
||||
|
||||
while(samples > 0) {
|
||||
volatile uint32_t duration = subghz_device_cc1101_ext_async_tx_middleware_get_duration(
|
||||
&subghz_device_cc1101_ext->async_tx.middleware,
|
||||
subghz_device_cc1101_ext->async_tx.callback);
|
||||
if(duration == 0) {
|
||||
*buffer = 0;
|
||||
buffer++;
|
||||
samples--;
|
||||
LL_DMA_DisableIT_HT(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF);
|
||||
LL_DMA_DisableIT_TC(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF);
|
||||
if(LL_DMA_IsActiveFlag_HT3(SUBGHZ_DEVICE_CC1101_EXT_DMA)) {
|
||||
LL_DMA_ClearFlag_HT3(SUBGHZ_DEVICE_CC1101_EXT_DMA);
|
||||
}
|
||||
if(LL_DMA_IsActiveFlag_TC3(SUBGHZ_DEVICE_CC1101_EXT_DMA)) {
|
||||
LL_DMA_ClearFlag_TC3(SUBGHZ_DEVICE_CC1101_EXT_DMA);
|
||||
}
|
||||
LL_TIM_EnableIT_UPDATE(TIM17);
|
||||
break;
|
||||
} else {
|
||||
bool level = level_duration_get_level(ld);
|
||||
|
||||
// Inject guard time if level is incorrect
|
||||
if(is_odd != level) {
|
||||
*buffer = SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME;
|
||||
buffer++;
|
||||
samples--;
|
||||
|
||||
// Special case: prevent buffer overflow if sample is last
|
||||
if(samples == 0) {
|
||||
subghz_device_cc1101_ext->async_tx.carry_ld = ld;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t duration = level_duration_get_duration(ld);
|
||||
furi_assert(duration > 0);
|
||||
*buffer = duration >> 1;
|
||||
// Lowest possible value is 4us
|
||||
if(duration < 4) duration = 4;
|
||||
// Divide by 2 since timer resolution is 2us
|
||||
// Subtract 1 since we counting from 0
|
||||
*buffer = (duration >> 1) - 1;
|
||||
buffer++;
|
||||
samples--;
|
||||
}
|
||||
@@ -638,12 +692,14 @@ static void subghz_device_cc1101_ext_async_tx_dma_isr() {
|
||||
static void subghz_device_cc1101_ext_async_tx_timer_isr() {
|
||||
if(LL_TIM_IsActiveFlag_UPDATE(TIM17)) {
|
||||
if(LL_TIM_GetAutoReload(TIM17) == 0) {
|
||||
LL_DMA_DisableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF);
|
||||
furi_hal_gpio_write(subghz_device_cc1101_ext->g0_pin, false);
|
||||
if(subghz_device_cc1101_ext->async_mirror_pin != NULL)
|
||||
furi_hal_gpio_write(subghz_device_cc1101_ext->async_mirror_pin, false);
|
||||
LL_TIM_DisableCounter(TIM17);
|
||||
subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateAsyncTxEnd;
|
||||
if(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx) {
|
||||
LL_DMA_DisableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF);
|
||||
subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateAsyncTxEnd;
|
||||
furi_hal_gpio_write(subghz_device_cc1101_ext->g0_pin, false);
|
||||
if(subghz_device_cc1101_ext->async_mirror_pin != NULL)
|
||||
furi_hal_gpio_write(subghz_device_cc1101_ext->async_mirror_pin, false);
|
||||
LL_TIM_DisableCounter(TIM17);
|
||||
}
|
||||
}
|
||||
LL_TIM_ClearFlag_UPDATE(TIM17);
|
||||
}
|
||||
@@ -693,16 +749,18 @@ bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callb
|
||||
|
||||
// Configure TIM
|
||||
// Set the timer resolution to 2 us
|
||||
LL_TIM_SetPrescaler(TIM17, (64 << 1) - 1);
|
||||
LL_TIM_SetCounterMode(TIM17, LL_TIM_COUNTERMODE_UP);
|
||||
LL_TIM_SetAutoReload(TIM17, 0xFFFF);
|
||||
LL_TIM_SetClockDivision(TIM17, LL_TIM_CLOCKDIVISION_DIV1);
|
||||
LL_TIM_SetAutoReload(TIM17, 500);
|
||||
LL_TIM_SetPrescaler(TIM17, (64 << 1) - 1);
|
||||
LL_TIM_SetClockSource(TIM17, LL_TIM_CLOCKSOURCE_INTERNAL);
|
||||
LL_TIM_DisableARRPreload(TIM17);
|
||||
|
||||
furi_hal_interrupt_set_isr(
|
||||
FuriHalInterruptIdTim1TrgComTim17, subghz_device_cc1101_ext_async_tx_timer_isr, NULL);
|
||||
|
||||
subghz_device_cc1101_ext_async_tx_middleware_idle(
|
||||
&subghz_device_cc1101_ext->async_tx.middleware);
|
||||
subghz_device_cc1101_ext_async_tx_refill(
|
||||
subghz_device_cc1101_ext->async_tx.buffer, SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL);
|
||||
|
||||
@@ -748,7 +806,6 @@ bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callb
|
||||
|
||||
// Start counter
|
||||
LL_TIM_EnableDMAReq_UPDATE(TIM17);
|
||||
LL_TIM_GenerateEvent_UPDATE(TIM17);
|
||||
|
||||
subghz_device_cc1101_ext_tx();
|
||||
|
||||
@@ -767,11 +824,15 @@ void subghz_device_cc1101_ext_stop_async_tx() {
|
||||
subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx ||
|
||||
subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTxEnd);
|
||||
|
||||
// Deinitialize GPIO
|
||||
furi_hal_gpio_write(subghz_device_cc1101_ext->g0_pin, false);
|
||||
furi_hal_gpio_init(
|
||||
subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullDown, GpioSpeedLow);
|
||||
|
||||
// Shutdown radio
|
||||
subghz_device_cc1101_ext_idle();
|
||||
|
||||
// Deinitialize Timer
|
||||
FURI_CRITICAL_ENTER();
|
||||
furi_hal_bus_disable(FuriHalBusTIM17);
|
||||
furi_hal_interrupt_set_isr(FuriHalInterruptIdTim1TrgComTim17, NULL, NULL);
|
||||
|
||||
@@ -780,17 +841,11 @@ void subghz_device_cc1101_ext_stop_async_tx() {
|
||||
LL_DMA_DisableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF);
|
||||
furi_hal_interrupt_set_isr(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_IRQ, NULL, NULL);
|
||||
|
||||
// Deinitialize GPIO
|
||||
furi_hal_gpio_write(subghz_device_cc1101_ext->g0_pin, false);
|
||||
furi_hal_gpio_init(subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
|
||||
// Stop debug
|
||||
if(subghz_device_cc1101_ext_stop_debug()) {
|
||||
LL_DMA_DisableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF);
|
||||
}
|
||||
|
||||
FURI_CRITICAL_EXIT();
|
||||
|
||||
free(subghz_device_cc1101_ext->async_tx.buffer);
|
||||
|
||||
subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateIdle;
|
||||
|
||||
Reference in New Issue
Block a user