1
mirror of https://github.com/DarkFlippers/unleashed-firmware.git synced 2025-12-12 04:34:43 +04:00

SubGhz: add subghz tx_from_file CLI cmd, major TX flow refactoring, various improvements and bug fixes (#3302)

* SubGhz: add cmd CLI "subghz tx_from_file"
* SubGhz:  add sending raw.sub files
* SubGhz: add load custom preset
* SubGhz: remove unnecessary files
* SubGhz: change message
* SubGhz: fix printf formatting
* SubGhz: Cli refactoring code
* FuriHal: add furi_hal_subghz Tx Rx IDLE state switching test
* SubGhz: remove debug code, fix ext driver compilation
* SubGhz: cleanup code, move wait status routine to cc1101 driver
* SubGhz: proper pin mode transition in tx stop isr routine, proper DMA and ISR priorities, fix issue with async tx stuck
* SubGhz: simplify async tx stop flow, fix ISR ARR check condition race
* SubGhz: check ARR only when we transmitting
* SubGhz: check ARR only when we transmitting for ext cc1101
* SubGhz: lower ISR priorities to safe level
* SubGhz: proper gpio config, comments update

Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
Skorpionm
2024-01-15 09:38:43 +04:00
committed by GitHub
parent 3fd5f15e7f
commit d73d007797
8 changed files with 364 additions and 113 deletions

View File

@@ -36,7 +36,6 @@ typedef enum {
SubGhzStateAsyncRx, /**< Async RX started */
SubGhzStateAsyncTx, /**< Async TX started, DMA and timer is on */
SubGhzStateAsyncTxEnd, /**< Async TX complete, cleanup needed */
} SubGhzState;
@@ -277,12 +276,16 @@ void furi_hal_subghz_reset() {
void furi_hal_subghz_idle() {
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
cc1101_switch_to_idle(&furi_hal_spi_bus_handle_subghz);
//waiting for the chip to switch to IDLE mode
furi_check(cc1101_wait_status_state(&furi_hal_spi_bus_handle_subghz, CC1101StateIDLE, 10000));
furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
}
void furi_hal_subghz_rx() {
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
cc1101_switch_to_rx(&furi_hal_spi_bus_handle_subghz);
//waiting for the chip to switch to Rx mode
furi_check(cc1101_wait_status_state(&furi_hal_spi_bus_handle_subghz, CC1101StateRX, 10000));
furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
}
@@ -290,6 +293,8 @@ bool furi_hal_subghz_tx() {
if(furi_hal_subghz.regulation != SubGhzRegulationTxRx) return false;
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
cc1101_switch_to_tx(&furi_hal_spi_bus_handle_subghz);
//waiting for the chip to switch to Tx mode
furi_check(cc1101_wait_status_state(&furi_hal_spi_bus_handle_subghz, CC1101StateTX, 10000));
furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
return true;
}
@@ -352,10 +357,7 @@ uint32_t furi_hal_subghz_set_frequency(uint32_t value) {
uint32_t real_frequency = cc1101_set_frequency(&furi_hal_spi_bus_handle_subghz, value);
cc1101_calibrate(&furi_hal_spi_bus_handle_subghz);
while(true) {
CC1101Status status = cc1101_get_status(&furi_hal_spi_bus_handle_subghz);
if(status.STATE == CC1101StateIDLE) break;
}
furi_check(cc1101_wait_status_state(&furi_hal_spi_bus_handle_subghz, CC1101StateIDLE, 10000));
furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
return real_frequency;
@@ -624,7 +626,6 @@ static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) {
if(LL_DMA_IsActiveFlag_TC1(SUBGHZ_DMA)) {
LL_DMA_ClearFlag_TC1(SUBGHZ_DMA);
}
LL_TIM_EnableIT_UPDATE(TIM2);
break;
} else {
// Lowest possible value is 2us
@@ -666,21 +667,6 @@ static void furi_hal_subghz_async_tx_dma_isr() {
#endif
}
static void furi_hal_subghz_async_tx_timer_isr() {
if(LL_TIM_IsActiveFlag_UPDATE(TIM2)) {
LL_TIM_ClearFlag_UPDATE(TIM2);
if(LL_TIM_GetAutoReload(TIM2) == 0) {
if(furi_hal_subghz.state == SubGhzStateAsyncTx) {
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, GpioModeAnalog, GpioPullDown, GpioSpeedLow);
LL_TIM_DisableCounter(TIM2);
}
}
}
}
bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* context) {
furi_assert(furi_hal_subghz.state == SubGhzStateIdle);
furi_assert(callback);
@@ -701,7 +687,7 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
// Connect CC1101_GD0 to TIM2 as output
furi_hal_gpio_init_ex(
&gpio_cc1101_g0, GpioModeAltFunctionPushPull, GpioPullDown, GpioSpeedLow, GpioAltFn1TIM2);
&gpio_cc1101_g0, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn1TIM2);
// Configure DMA
LL_DMA_InitTypeDef dma_config = {0};
@@ -715,7 +701,8 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
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;
dma_config.Priority =
LL_DMA_PRIORITY_VERYHIGH; // Ensure that ARR is updated before anyone else try to check it
LL_DMA_Init(SUBGHZ_DMA_CH1_DEF, &dma_config);
furi_hal_interrupt_set_isr(SUBGHZ_DMA_CH1_IRQ, furi_hal_subghz_async_tx_dma_isr, NULL);
LL_DMA_EnableIT_TC(SUBGHZ_DMA_CH1_DEF);
@@ -743,8 +730,6 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
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, FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL);
@@ -752,15 +737,6 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
LL_TIM_EnableDMAReq_UPDATE(TIM2);
LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2);
// Start counter
#ifdef FURI_HAL_SUBGHZ_TX_GPIO
furi_hal_gpio_write(&FURI_HAL_SUBGHZ_TX_GPIO, true);
#endif
furi_hal_subghz_tx();
LL_TIM_SetCounter(TIM2, 0);
LL_TIM_EnableCounter(TIM2);
// Start debug
if(furi_hal_subghz_start_debug()) {
const GpioPin* gpio = furi_hal_subghz.async_mirror_pin;
@@ -777,30 +753,36 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
dma_config.NbData = 2;
dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP;
dma_config.Priority = LL_DMA_PRIORITY_VERYHIGH;
dma_config.Priority = LL_DMA_PRIORITY_HIGH; // Ensure that it's updated after ARR
LL_DMA_Init(SUBGHZ_DMA_CH2_DEF, &dma_config);
LL_DMA_SetDataLength(SUBGHZ_DMA_CH2_DEF, 2);
LL_DMA_EnableChannel(SUBGHZ_DMA_CH2_DEF);
}
// Start counter
#ifdef FURI_HAL_SUBGHZ_TX_GPIO
furi_hal_gpio_write(&FURI_HAL_SUBGHZ_TX_GPIO, true);
#endif
furi_hal_subghz_tx();
LL_TIM_SetCounter(TIM2, 0);
LL_TIM_EnableCounter(TIM2);
return true;
}
bool furi_hal_subghz_is_async_tx_complete() {
return furi_hal_subghz.state == SubGhzStateAsyncTxEnd;
return (furi_hal_subghz.state == SubGhzStateAsyncTx) && (LL_TIM_GetAutoReload(TIM2) == 0);
}
void furi_hal_subghz_stop_async_tx() {
furi_assert(
furi_hal_subghz.state == SubGhzStateAsyncTx ||
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);
furi_assert(furi_hal_subghz.state == SubGhzStateAsyncTx);
// Shutdown radio
furi_hal_subghz_idle();
// Deinitialize GPIO
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
#ifdef FURI_HAL_SUBGHZ_TX_GPIO
furi_hal_gpio_write(&FURI_HAL_SUBGHZ_TX_GPIO, false);
#endif