mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2024-11-22 17:33:13 +03: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:
parent
0b15fc3807
commit
34539cda17
@ -231,17 +231,17 @@ typedef struct {
|
||||
size_t pos;
|
||||
} SubGhzHalAsyncTxTest;
|
||||
|
||||
#define SUBGHZ_HAL_TEST_DURATION 1
|
||||
#define SUBGHZ_HAL_TEST_DURATION 3
|
||||
|
||||
static LevelDuration subghz_hal_async_tx_test_yield(void* context) {
|
||||
SubGhzHalAsyncTxTest* test = context;
|
||||
bool is_odd = test->pos % 2;
|
||||
|
||||
if(test->type == SubGhzHalAsyncTxTestTypeNormal) {
|
||||
if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
|
||||
if(test->pos < FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
|
||||
test->pos++;
|
||||
return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION);
|
||||
} else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
|
||||
} else if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
|
||||
test->pos++;
|
||||
return level_duration_reset();
|
||||
} else {
|
||||
@ -251,36 +251,36 @@ static LevelDuration subghz_hal_async_tx_test_yield(void* context) {
|
||||
if(test->pos == 0) {
|
||||
test->pos++;
|
||||
return level_duration_make(!is_odd, SUBGHZ_HAL_TEST_DURATION);
|
||||
} else if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
|
||||
} else if(test->pos < FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
|
||||
test->pos++;
|
||||
return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION);
|
||||
} else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
|
||||
} else if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
|
||||
test->pos++;
|
||||
return level_duration_reset();
|
||||
} else {
|
||||
furi_crash("Yield after reset");
|
||||
}
|
||||
} else if(test->type == SubGhzHalAsyncTxTestTypeInvalidMid) {
|
||||
if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF / 2) {
|
||||
if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF / 2) {
|
||||
test->pos++;
|
||||
return level_duration_make(!is_odd, SUBGHZ_HAL_TEST_DURATION);
|
||||
} else if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
|
||||
} else if(test->pos < FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
|
||||
test->pos++;
|
||||
return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION);
|
||||
} else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
|
||||
} else if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
|
||||
test->pos++;
|
||||
return level_duration_reset();
|
||||
} else {
|
||||
furi_crash("Yield after reset");
|
||||
}
|
||||
} else if(test->type == SubGhzHalAsyncTxTestTypeInvalidEnd) {
|
||||
if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL - 1) {
|
||||
if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL - 1) {
|
||||
test->pos++;
|
||||
return level_duration_make(!is_odd, SUBGHZ_HAL_TEST_DURATION);
|
||||
} else if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
|
||||
} else if(test->pos < FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
|
||||
test->pos++;
|
||||
return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION);
|
||||
} else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
|
||||
} else if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
|
||||
test->pos++;
|
||||
return level_duration_reset();
|
||||
} else {
|
||||
@ -294,20 +294,20 @@ static LevelDuration subghz_hal_async_tx_test_yield(void* context) {
|
||||
furi_crash("Yield after reset");
|
||||
}
|
||||
} else if(test->type == SubGhzHalAsyncTxTestTypeResetMid) {
|
||||
if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF / 2) {
|
||||
if(test->pos < FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF / 2) {
|
||||
test->pos++;
|
||||
return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION);
|
||||
} else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF / 2) {
|
||||
} else if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF / 2) {
|
||||
test->pos++;
|
||||
return level_duration_reset();
|
||||
} else {
|
||||
furi_crash("Yield after reset");
|
||||
}
|
||||
} else if(test->type == SubGhzHalAsyncTxTestTypeResetEnd) {
|
||||
if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL - 1) {
|
||||
if(test->pos < FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL) {
|
||||
test->pos++;
|
||||
return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION);
|
||||
} else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL - 1) {
|
||||
} else if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL) {
|
||||
test->pos++;
|
||||
return level_duration_reset();
|
||||
} else {
|
||||
@ -334,6 +334,8 @@ bool subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestType type) {
|
||||
|
||||
while(!furi_hal_subghz_is_async_tx_complete()) {
|
||||
if(furi_hal_cortex_timer_is_expired(timer)) {
|
||||
furi_hal_subghz_stop_async_tx();
|
||||
furi_hal_subghz_sleep();
|
||||
return false;
|
||||
}
|
||||
furi_delay_ms(10);
|
||||
|
@ -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;
|
||||
|
@ -18,7 +18,6 @@ struct SubGhzFileEncoderWorker {
|
||||
|
||||
volatile bool worker_running;
|
||||
volatile bool worker_stoping;
|
||||
bool level;
|
||||
bool is_storage_slow;
|
||||
FuriString* str_data;
|
||||
FuriString* file_path;
|
||||
@ -41,19 +40,8 @@ void subghz_file_encoder_worker_callback_end(
|
||||
void subghz_file_encoder_worker_add_level_duration(
|
||||
SubGhzFileEncoderWorker* instance,
|
||||
int32_t duration) {
|
||||
bool res = true;
|
||||
if(duration < 0 && !instance->level) {
|
||||
res = false;
|
||||
} else if(duration > 0 && instance->level) {
|
||||
res = false;
|
||||
}
|
||||
|
||||
if(res) {
|
||||
instance->level = !instance->level;
|
||||
furi_stream_buffer_send(instance->stream, &duration, sizeof(int32_t), 100);
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Invalid level in the stream");
|
||||
}
|
||||
size_t ret = furi_stream_buffer_send(instance->stream, &duration, sizeof(int32_t), 100);
|
||||
if(sizeof(int32_t) != ret) FURI_LOG_E(TAG, "Invalid add duration in the stream");
|
||||
}
|
||||
|
||||
bool subghz_file_encoder_worker_data_parse(SubGhzFileEncoderWorker* instance, const char* strStart) {
|
||||
@ -190,7 +178,6 @@ SubGhzFileEncoderWorker* subghz_file_encoder_worker_alloc() {
|
||||
|
||||
instance->str_data = furi_string_alloc();
|
||||
instance->file_path = furi_string_alloc();
|
||||
instance->level = false;
|
||||
instance->worker_stoping = true;
|
||||
|
||||
return instance;
|
||||
|
@ -17,13 +17,13 @@
|
||||
|
||||
#define TAG "FuriHalSubGhz"
|
||||
|
||||
static uint32_t furi_hal_subghz_debug_gpio_buff[2];
|
||||
static uint32_t furi_hal_subghz_debug_gpio_buff[2] = {0};
|
||||
|
||||
/* DMA Channels definition */
|
||||
#define SUBGHZ_DMA DMA2
|
||||
#define SUBGHZ_DMA_CH1_CHANNEL LL_DMA_CHANNEL_1
|
||||
#define SUBGHZ_DMA_CH2_CHANNEL LL_DMA_CHANNEL_2
|
||||
#define SUBGHZ_DMA_CH1_IRQ FuriHalInterruptIdDma2Ch1
|
||||
#define SUBGHZ_DMA (DMA2)
|
||||
#define SUBGHZ_DMA_CH1_CHANNEL (LL_DMA_CHANNEL_1)
|
||||
#define SUBGHZ_DMA_CH2_CHANNEL (LL_DMA_CHANNEL_2)
|
||||
#define SUBGHZ_DMA_CH1_IRQ (FuriHalInterruptIdDma2Ch1)
|
||||
#define SUBGHZ_DMA_CH1_DEF SUBGHZ_DMA, SUBGHZ_DMA_CH1_CHANNEL
|
||||
#define SUBGHZ_DMA_CH2_DEF SUBGHZ_DMA, SUBGHZ_DMA_CH2_CHANNEL
|
||||
|
||||
@ -36,7 +36,6 @@ typedef enum {
|
||||
SubGhzStateAsyncRx, /**< Async RX started */
|
||||
|
||||
SubGhzStateAsyncTx, /**< Async TX started, DMA and timer is on */
|
||||
SubGhzStateAsyncTxLast, /**< Async TX continue, DMA completed and timer got last value to go */
|
||||
SubGhzStateAsyncTxEnd, /**< Async TX complete, cleanup needed */
|
||||
|
||||
} SubGhzState;
|
||||
@ -79,6 +78,10 @@ void furi_hal_subghz_init() {
|
||||
&FURI_HAL_SUBGHZ_TX_GPIO, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
|
||||
#endif
|
||||
|
||||
#ifdef FURI_HAL_SUBGHZ_ASYNC_MIRROR_GPIO
|
||||
furi_hal_subghz_set_async_mirror_pin(&FURI_HAL_SUBGHZ_ASYNC_MIRROR_GPIO);
|
||||
#endif
|
||||
|
||||
// Reset
|
||||
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
cc1101_reset(&furi_hal_spi_bus_handle_subghz);
|
||||
@ -158,8 +161,8 @@ void furi_hal_subghz_dump_state() {
|
||||
|
||||
void furi_hal_subghz_load_custom_preset(const uint8_t* preset_data) {
|
||||
//load config
|
||||
furi_hal_subghz_reset();
|
||||
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
|
||||
cc1101_reset(&furi_hal_spi_bus_handle_subghz);
|
||||
uint32_t i = 0;
|
||||
uint8_t pa[8] = {0};
|
||||
while(preset_data[i]) {
|
||||
@ -187,8 +190,8 @@ void furi_hal_subghz_load_custom_preset(const uint8_t* preset_data) {
|
||||
}
|
||||
|
||||
void furi_hal_subghz_load_registers(const uint8_t* data) {
|
||||
furi_hal_subghz_reset();
|
||||
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
|
||||
cc1101_reset(&furi_hal_spi_bus_handle_subghz);
|
||||
uint32_t i = 0;
|
||||
while(data[i]) {
|
||||
cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, data[i], data[i + 1]);
|
||||
@ -266,6 +269,7 @@ void furi_hal_subghz_reset() {
|
||||
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
cc1101_switch_to_idle(&furi_hal_spi_bus_handle_subghz);
|
||||
cc1101_reset(&furi_hal_spi_bus_handle_subghz);
|
||||
// Warning: push pull cc1101 clock output on GD0
|
||||
cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHighImpedance);
|
||||
furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
|
||||
}
|
||||
@ -382,6 +386,7 @@ void furi_hal_subghz_set_path(FuriHalSubGhzPath path) {
|
||||
static bool furi_hal_subghz_start_debug() {
|
||||
bool ret = false;
|
||||
if(furi_hal_subghz.async_mirror_pin != NULL) {
|
||||
furi_hal_gpio_write(furi_hal_subghz.async_mirror_pin, false);
|
||||
furi_hal_gpio_init(
|
||||
furi_hal_subghz.async_mirror_pin,
|
||||
GpioModeOutputPushPull,
|
||||
@ -522,73 +527,121 @@ void furi_hal_subghz_stop_async_rx() {
|
||||
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
FuriHalSubGhzAsyncTxMiddlewareStateIdle,
|
||||
FuriHalSubGhzAsyncTxMiddlewareStateReset,
|
||||
FuriHalSubGhzAsyncTxMiddlewareStateRun,
|
||||
} FuriHalSubGhzAsyncTxMiddlewareState;
|
||||
|
||||
typedef struct {
|
||||
FuriHalSubGhzAsyncTxMiddlewareState state;
|
||||
bool is_odd_level;
|
||||
uint32_t adder_duration;
|
||||
} FuriHalSubGhzAsyncTxMiddleware;
|
||||
|
||||
typedef struct {
|
||||
uint32_t* buffer;
|
||||
LevelDuration carry_ld;
|
||||
FuriHalSubGhzAsyncTxCallback callback;
|
||||
void* callback_context;
|
||||
uint64_t duty_high;
|
||||
uint64_t duty_low;
|
||||
FuriHalSubGhzAsyncTxMiddleware middleware;
|
||||
} FuriHalSubGhzAsyncTx;
|
||||
|
||||
static FuriHalSubGhzAsyncTx furi_hal_subghz_async_tx = {0};
|
||||
|
||||
static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) {
|
||||
furi_assert(furi_hal_subghz.state == SubGhzStateAsyncTx);
|
||||
while(samples > 0) {
|
||||
bool is_odd = samples % 2;
|
||||
LevelDuration ld;
|
||||
if(level_duration_is_reset(furi_hal_subghz_async_tx.carry_ld)) {
|
||||
ld = furi_hal_subghz_async_tx.callback(furi_hal_subghz_async_tx.callback_context);
|
||||
} else {
|
||||
ld = furi_hal_subghz_async_tx.carry_ld;
|
||||
furi_hal_subghz_async_tx.carry_ld = level_duration_reset();
|
||||
void furi_hal_subghz_async_tx_middleware_idle(FuriHalSubGhzAsyncTxMiddleware* middleware) {
|
||||
middleware->state = FuriHalSubGhzAsyncTxMiddlewareStateIdle;
|
||||
middleware->is_odd_level = false;
|
||||
middleware->adder_duration = 0;
|
||||
}
|
||||
|
||||
static inline uint32_t furi_hal_subghz_async_tx_middleware_get_duration(
|
||||
FuriHalSubGhzAsyncTxMiddleware* middleware,
|
||||
FuriHalSubGhzAsyncTxCallback callback) {
|
||||
uint32_t ret = 0;
|
||||
bool is_level = false;
|
||||
|
||||
if(middleware->state == FuriHalSubGhzAsyncTxMiddlewareStateReset) return 0;
|
||||
|
||||
while(1) {
|
||||
LevelDuration ld = callback(furi_hal_subghz_async_tx.callback_context);
|
||||
if(level_duration_is_reset(ld)) {
|
||||
middleware->state = FuriHalSubGhzAsyncTxMiddlewareStateReset;
|
||||
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 + FURI_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME;
|
||||
middleware->adder_duration = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(level_duration_is_wait(ld)) {
|
||||
*buffer = API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME;
|
||||
buffer++;
|
||||
samples--;
|
||||
} else if(level_duration_is_reset(ld)) {
|
||||
is_level = level_duration_get_level(ld);
|
||||
|
||||
if(middleware->state == FuriHalSubGhzAsyncTxMiddlewareStateIdle) {
|
||||
if(is_level != middleware->is_odd_level) {
|
||||
middleware->state = FuriHalSubGhzAsyncTxMiddlewareStateRun;
|
||||
middleware->is_odd_level = is_level;
|
||||
middleware->adder_duration = 0;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if(middleware->state == FuriHalSubGhzAsyncTxMiddlewareStateRun) {
|
||||
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 furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) {
|
||||
furi_assert(furi_hal_subghz.state == SubGhzStateAsyncTx);
|
||||
|
||||
while(samples > 0) {
|
||||
volatile uint32_t duration = furi_hal_subghz_async_tx_middleware_get_duration(
|
||||
&furi_hal_subghz_async_tx.middleware, furi_hal_subghz_async_tx.callback);
|
||||
if(duration == 0) {
|
||||
*buffer = 0;
|
||||
buffer++;
|
||||
samples--;
|
||||
LL_DMA_DisableIT_HT(SUBGHZ_DMA_CH1_DEF);
|
||||
LL_DMA_DisableIT_TC(SUBGHZ_DMA_CH1_DEF);
|
||||
if(LL_DMA_IsActiveFlag_HT1(SUBGHZ_DMA)) {
|
||||
LL_DMA_ClearFlag_HT1(SUBGHZ_DMA);
|
||||
}
|
||||
if(LL_DMA_IsActiveFlag_TC1(SUBGHZ_DMA)) {
|
||||
LL_DMA_ClearFlag_TC1(SUBGHZ_DMA);
|
||||
}
|
||||
LL_TIM_EnableIT_UPDATE(TIM2);
|
||||
break;
|
||||
} else {
|
||||
bool level = level_duration_get_level(ld);
|
||||
|
||||
// Inject guard time if level is incorrect
|
||||
if(is_odd != level) {
|
||||
*buffer = API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME;
|
||||
buffer++;
|
||||
samples--;
|
||||
if(is_odd) {
|
||||
furi_hal_subghz_async_tx.duty_high += API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME;
|
||||
} else {
|
||||
furi_hal_subghz_async_tx.duty_low += API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME;
|
||||
}
|
||||
|
||||
// Special case: prevent buffer overflow if sample is last
|
||||
if(samples == 0) {
|
||||
furi_hal_subghz_async_tx.carry_ld = ld;
|
||||
break;
|
||||
}
|
||||
// Lowest possible value is 2us
|
||||
if(duration > 2) {
|
||||
// Subtract 1 since we counting from 0
|
||||
*buffer = duration - 1;
|
||||
} else {
|
||||
*buffer = 1;
|
||||
}
|
||||
|
||||
uint32_t duration = level_duration_get_duration(ld);
|
||||
furi_assert(duration > 0);
|
||||
*buffer = duration;
|
||||
buffer++;
|
||||
samples--;
|
||||
}
|
||||
|
||||
if(is_odd) {
|
||||
furi_hal_subghz_async_tx.duty_high += duration;
|
||||
} else {
|
||||
furi_hal_subghz_async_tx.duty_low += duration;
|
||||
}
|
||||
if(samples % 2) {
|
||||
furi_hal_subghz_async_tx.duty_high += duration;
|
||||
} else {
|
||||
furi_hal_subghz_async_tx.duty_low += duration;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -600,13 +653,13 @@ static void furi_hal_subghz_async_tx_dma_isr() {
|
||||
if(LL_DMA_IsActiveFlag_HT1(SUBGHZ_DMA)) {
|
||||
LL_DMA_ClearFlag_HT1(SUBGHZ_DMA);
|
||||
furi_hal_subghz_async_tx_refill(
|
||||
furi_hal_subghz_async_tx.buffer, API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF);
|
||||
furi_hal_subghz_async_tx.buffer, FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF);
|
||||
}
|
||||
if(LL_DMA_IsActiveFlag_TC1(SUBGHZ_DMA)) {
|
||||
LL_DMA_ClearFlag_TC1(SUBGHZ_DMA);
|
||||
furi_hal_subghz_async_tx_refill(
|
||||
furi_hal_subghz_async_tx.buffer + API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF,
|
||||
API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF);
|
||||
furi_hal_subghz_async_tx.buffer + FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF,
|
||||
FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF);
|
||||
}
|
||||
#else
|
||||
#error Update this code. Would you kindly?
|
||||
@ -618,15 +671,11 @@ static void furi_hal_subghz_async_tx_timer_isr() {
|
||||
LL_TIM_ClearFlag_UPDATE(TIM2);
|
||||
if(LL_TIM_GetAutoReload(TIM2) == 0) {
|
||||
if(furi_hal_subghz.state == SubGhzStateAsyncTx) {
|
||||
furi_hal_subghz.state = SubGhzStateAsyncTxLast;
|
||||
LL_DMA_DisableChannel(SUBGHZ_DMA_CH1_DEF);
|
||||
} else if(furi_hal_subghz.state == SubGhzStateAsyncTxLast) {
|
||||
furi_hal_subghz.state = SubGhzStateAsyncTxEnd;
|
||||
LL_DMA_DisableChannel(SUBGHZ_DMA_CH1_DEF);
|
||||
//forcibly pulls the pin to the ground so that there is no carrier
|
||||
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullDown, GpioSpeedLow);
|
||||
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullDown, GpioSpeedLow);
|
||||
LL_TIM_DisableCounter(TIM2);
|
||||
} else {
|
||||
furi_crash();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -648,7 +697,7 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
|
||||
furi_hal_subghz_async_tx.duty_high = 0;
|
||||
|
||||
furi_hal_subghz_async_tx.buffer =
|
||||
malloc(API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * sizeof(uint32_t));
|
||||
malloc(FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * sizeof(uint32_t));
|
||||
|
||||
// Connect CC1101_GD0 to TIM2 as output
|
||||
furi_hal_gpio_init_ex(
|
||||
@ -664,7 +713,7 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
|
||||
dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
|
||||
dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD;
|
||||
dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
|
||||
dma_config.NbData = API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL;
|
||||
dma_config.NbData = FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL;
|
||||
dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP;
|
||||
dma_config.Priority = LL_DMA_MODE_NORMAL;
|
||||
LL_DMA_Init(SUBGHZ_DMA_CH1_DEF, &dma_config);
|
||||
@ -676,14 +725,12 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
|
||||
furi_hal_bus_enable(FuriHalBusTIM2);
|
||||
|
||||
// Configure TIM2
|
||||
LL_TIM_InitTypeDef TIM_InitStruct = {0};
|
||||
TIM_InitStruct.Prescaler = 64 - 1;
|
||||
TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
|
||||
TIM_InitStruct.Autoreload = 1000;
|
||||
TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
|
||||
LL_TIM_Init(TIM2, &TIM_InitStruct);
|
||||
LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP);
|
||||
LL_TIM_SetClockDivision(TIM2, LL_TIM_CLOCKDIVISION_DIV1);
|
||||
LL_TIM_SetAutoReload(TIM2, 1000);
|
||||
LL_TIM_SetPrescaler(TIM2, 64 - 1);
|
||||
LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL);
|
||||
LL_TIM_EnableARRPreload(TIM2);
|
||||
LL_TIM_DisableARRPreload(TIM2);
|
||||
|
||||
// Configure TIM2 CH2
|
||||
LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0};
|
||||
@ -691,21 +738,21 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
|
||||
TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_DISABLE;
|
||||
TIM_OC_InitStruct.OCNState = LL_TIM_OCSTATE_DISABLE;
|
||||
TIM_OC_InitStruct.CompareValue = 0;
|
||||
TIM_OC_InitStruct.OCPolarity = LL_TIM_OCPOLARITY_LOW;
|
||||
TIM_OC_InitStruct.OCPolarity = LL_TIM_OCPOLARITY_HIGH;
|
||||
LL_TIM_OC_Init(TIM2, LL_TIM_CHANNEL_CH2, &TIM_OC_InitStruct);
|
||||
LL_TIM_OC_DisableFast(TIM2, LL_TIM_CHANNEL_CH2);
|
||||
LL_TIM_DisableMasterSlaveMode(TIM2);
|
||||
|
||||
furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, furi_hal_subghz_async_tx_timer_isr, NULL);
|
||||
|
||||
furi_hal_subghz_async_tx_middleware_idle(&furi_hal_subghz_async_tx.middleware);
|
||||
furi_hal_subghz_async_tx_refill(
|
||||
furi_hal_subghz_async_tx.buffer, API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL);
|
||||
furi_hal_subghz_async_tx.buffer, FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL);
|
||||
|
||||
LL_TIM_EnableDMAReq_UPDATE(TIM2);
|
||||
LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2);
|
||||
|
||||
// Start counter
|
||||
LL_TIM_GenerateEvent_UPDATE(TIM2);
|
||||
#ifdef FURI_HAL_SUBGHZ_TX_GPIO
|
||||
furi_hal_gpio_write(&FURI_HAL_SUBGHZ_TX_GPIO, true);
|
||||
#endif
|
||||
@ -717,8 +764,8 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
|
||||
// Start debug
|
||||
if(furi_hal_subghz_start_debug()) {
|
||||
const GpioPin* gpio = furi_hal_subghz.async_mirror_pin;
|
||||
furi_hal_subghz_debug_gpio_buff[0] = (uint32_t)gpio->pin << GPIO_NUMBER;
|
||||
furi_hal_subghz_debug_gpio_buff[1] = gpio->pin;
|
||||
furi_hal_subghz_debug_gpio_buff[0] = gpio->pin;
|
||||
furi_hal_subghz_debug_gpio_buff[1] = (uint32_t)gpio->pin << GPIO_NUMBER;
|
||||
|
||||
dma_config.MemoryOrM2MDstAddress = (uint32_t)furi_hal_subghz_debug_gpio_buff;
|
||||
dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (gpio->port->BSRR);
|
||||
@ -746,9 +793,12 @@ bool furi_hal_subghz_is_async_tx_complete() {
|
||||
void furi_hal_subghz_stop_async_tx() {
|
||||
furi_assert(
|
||||
furi_hal_subghz.state == SubGhzStateAsyncTx ||
|
||||
furi_hal_subghz.state == SubGhzStateAsyncTxLast ||
|
||||
furi_hal_subghz.state == SubGhzStateAsyncTxEnd);
|
||||
|
||||
// Deinitialize GPIO
|
||||
// Keep in mind that cc1101 will try to pull it up in idle.
|
||||
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullDown, GpioSpeedLow);
|
||||
|
||||
// Shutdown radio
|
||||
furi_hal_subghz_idle();
|
||||
#ifdef FURI_HAL_SUBGHZ_TX_GPIO
|
||||
@ -756,7 +806,6 @@ void furi_hal_subghz_stop_async_tx() {
|
||||
#endif
|
||||
|
||||
// Deinitialize Timer
|
||||
FURI_CRITICAL_ENTER();
|
||||
furi_hal_bus_disable(FuriHalBusTIM2);
|
||||
furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, NULL, NULL);
|
||||
|
||||
@ -765,16 +814,11 @@ void furi_hal_subghz_stop_async_tx() {
|
||||
|
||||
furi_hal_interrupt_set_isr(SUBGHZ_DMA_CH1_IRQ, NULL, NULL);
|
||||
|
||||
// Deinitialize GPIO
|
||||
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
|
||||
// Stop debug
|
||||
if(furi_hal_subghz_stop_debug()) {
|
||||
LL_DMA_DisableChannel(SUBGHZ_DMA_CH2_DEF);
|
||||
}
|
||||
|
||||
FURI_CRITICAL_EXIT();
|
||||
|
||||
free(furi_hal_subghz_async_tx.buffer);
|
||||
|
||||
float duty_cycle =
|
||||
|
@ -17,10 +17,10 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Low level buffer dimensions and guard times */
|
||||
#define API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL (256)
|
||||
#define API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF (API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL / 2)
|
||||
#define API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME 999
|
||||
/** Various subghz defines */
|
||||
#define FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL (256u)
|
||||
#define FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF (FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL / 2)
|
||||
#define FURI_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME (999u)
|
||||
|
||||
/** Switchable Radio Paths */
|
||||
typedef enum {
|
||||
|
Loading…
Reference in New Issue
Block a user