mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-07-01 22:08:55 -07:00
add wplugins updates without conficting NFC and BT/BLE changes
Nice FloR-S emulation now working
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
#include "digital_signal.h"
|
||||
|
||||
#include <furi.h>
|
||||
#include <stm32wbxx_ll_dma.h>
|
||||
#include <stm32wbxx_ll_tim.h>
|
||||
#include <math.h>
|
||||
|
||||
#define F_TIM (64000000.0)
|
||||
#define T_TIM (1.0 / F_TIM)
|
||||
|
||||
#define MAX_ARR_BUFF_SIZE (10000)
|
||||
|
||||
// TODO rework with dynamic allocation
|
||||
static uint32_t digital_signal_arr_buff[MAX_ARR_BUFF_SIZE];
|
||||
|
||||
DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt) {
|
||||
DigitalSignal* signal = malloc(sizeof(DigitalSignal));
|
||||
signal->start_level = true;
|
||||
signal->edges_max_cnt = max_edges_cnt;
|
||||
signal->edge_timings = malloc(max_edges_cnt * sizeof(float));
|
||||
signal->edge_cnt = 0;
|
||||
|
||||
return signal;
|
||||
}
|
||||
|
||||
void digital_signal_free(DigitalSignal* signal) {
|
||||
furi_assert(signal);
|
||||
|
||||
free(signal->edge_timings);
|
||||
free(signal);
|
||||
}
|
||||
|
||||
bool digital_signal_append(DigitalSignal* signal_a, DigitalSignal* signal_b) {
|
||||
furi_assert(signal_a);
|
||||
furi_assert(signal_b);
|
||||
|
||||
if(signal_a->edges_max_cnt < signal_a->edge_cnt + signal_b->edge_cnt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool end_level = signal_a->start_level ^ !(signal_a->edge_cnt % 2);
|
||||
uint8_t start_copy = 0;
|
||||
if(end_level == signal_b->start_level) {
|
||||
if(signal_a->edge_cnt) {
|
||||
signal_a->edge_timings[signal_a->edge_cnt - 1] += signal_b->edge_timings[0];
|
||||
} else {
|
||||
signal_a->edge_timings[signal_a->edge_cnt] += signal_b->edge_timings[0];
|
||||
}
|
||||
start_copy += 1;
|
||||
}
|
||||
memcpy(
|
||||
&signal_a->edge_timings[signal_a->edge_cnt],
|
||||
&signal_b->edge_timings[start_copy],
|
||||
(signal_b->edge_cnt - start_copy) * sizeof(float));
|
||||
signal_a->edge_cnt += signal_b->edge_cnt - start_copy;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool digital_signal_get_start_level(DigitalSignal* signal) {
|
||||
furi_assert(signal);
|
||||
|
||||
return signal->start_level;
|
||||
}
|
||||
|
||||
uint32_t digital_signal_get_edges_cnt(DigitalSignal* signal) {
|
||||
furi_assert(signal);
|
||||
|
||||
return signal->edge_cnt;
|
||||
}
|
||||
|
||||
float digital_signal_get_edge(DigitalSignal* signal, uint32_t edge_num) {
|
||||
furi_assert(signal);
|
||||
furi_assert(edge_num < signal->edge_cnt);
|
||||
|
||||
return signal->edge_timings[edge_num];
|
||||
}
|
||||
|
||||
static void digital_signal_prepare_arr(DigitalSignal* signal, uint32_t* arr) {
|
||||
float t_signal = 0;
|
||||
float t_current = 0;
|
||||
float r = 0;
|
||||
float r_int = 0;
|
||||
float r_dec = 0;
|
||||
|
||||
for(size_t i = 0; i < signal->edge_cnt - 1; i++) {
|
||||
t_signal += signal->edge_timings[i];
|
||||
r = (t_signal - t_current) / T_TIM;
|
||||
r_dec = modff(r, &r_int);
|
||||
if(r_dec < 0.5f) {
|
||||
arr[i] = (uint32_t)r_int - 1;
|
||||
} else {
|
||||
arr[i] = (uint32_t)r_int;
|
||||
}
|
||||
t_current += (arr[i] + 1) * T_TIM;
|
||||
}
|
||||
}
|
||||
|
||||
bool digital_signal_send(DigitalSignal* signal, const GpioPin* gpio) {
|
||||
furi_assert(signal);
|
||||
furi_assert(gpio);
|
||||
|
||||
// Configure gpio as output
|
||||
furi_hal_gpio_init(gpio, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
|
||||
|
||||
// Init gpio buffer and DMA channel
|
||||
uint16_t gpio_reg = gpio->port->ODR;
|
||||
uint16_t gpio_buff[2];
|
||||
if(signal->start_level) {
|
||||
gpio_buff[0] = gpio_reg | gpio->pin;
|
||||
gpio_buff[1] = gpio_reg & ~(gpio->pin);
|
||||
} else {
|
||||
gpio_buff[0] = gpio_reg & ~(gpio->pin);
|
||||
gpio_buff[1] = gpio_reg | gpio->pin;
|
||||
}
|
||||
LL_DMA_InitTypeDef dma_config = {};
|
||||
dma_config.MemoryOrM2MDstAddress = (uint32_t)gpio_buff;
|
||||
dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (gpio->port->ODR);
|
||||
dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
|
||||
dma_config.Mode = LL_DMA_MODE_CIRCULAR;
|
||||
dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
|
||||
dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
|
||||
dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_HALFWORD;
|
||||
dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_HALFWORD;
|
||||
dma_config.NbData = 2;
|
||||
dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP;
|
||||
dma_config.Priority = LL_DMA_PRIORITY_VERYHIGH;
|
||||
LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &dma_config);
|
||||
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, 2);
|
||||
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);
|
||||
|
||||
// Init timer arr register buffer and DMA channel
|
||||
digital_signal_prepare_arr(signal, digital_signal_arr_buff);
|
||||
dma_config.MemoryOrM2MDstAddress = (uint32_t)digital_signal_arr_buff;
|
||||
dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR);
|
||||
dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
|
||||
dma_config.Mode = LL_DMA_MODE_NORMAL;
|
||||
dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
|
||||
dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
|
||||
dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD;
|
||||
dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
|
||||
dma_config.NbData = signal->edge_cnt - 2;
|
||||
dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP;
|
||||
dma_config.Priority = LL_DMA_PRIORITY_HIGH;
|
||||
LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &dma_config);
|
||||
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, signal->edge_cnt - 2);
|
||||
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2);
|
||||
|
||||
// Set up timer
|
||||
LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP);
|
||||
LL_TIM_SetClockDivision(TIM2, LL_TIM_CLOCKDIVISION_DIV1);
|
||||
LL_TIM_SetPrescaler(TIM2, 0);
|
||||
LL_TIM_SetAutoReload(TIM2, 10);
|
||||
LL_TIM_SetCounter(TIM2, 0);
|
||||
LL_TIM_EnableUpdateEvent(TIM2);
|
||||
LL_TIM_EnableDMAReq_UPDATE(TIM2);
|
||||
|
||||
// Start transactions
|
||||
LL_TIM_GenerateEvent_UPDATE(TIM2); // Do we really need it?
|
||||
LL_TIM_EnableCounter(TIM2);
|
||||
|
||||
while(!LL_DMA_IsActiveFlag_TC2(DMA1))
|
||||
;
|
||||
|
||||
LL_DMA_ClearFlag_TC1(DMA1);
|
||||
LL_DMA_ClearFlag_TC2(DMA1);
|
||||
LL_TIM_DisableCounter(TIM2);
|
||||
LL_TIM_SetCounter(TIM2, 0);
|
||||
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1);
|
||||
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <furi_hal_gpio.h>
|
||||
|
||||
typedef struct {
|
||||
bool start_level;
|
||||
uint32_t edge_cnt;
|
||||
uint32_t edges_max_cnt;
|
||||
float* edge_timings;
|
||||
} DigitalSignal;
|
||||
|
||||
DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt);
|
||||
|
||||
void digital_signal_free(DigitalSignal* signal);
|
||||
|
||||
bool digital_signal_append(DigitalSignal* signal_a, DigitalSignal* signal_b);
|
||||
|
||||
bool digital_signal_get_start_level(DigitalSignal* signal);
|
||||
|
||||
uint32_t digital_signal_get_edges_cnt(DigitalSignal* signal);
|
||||
|
||||
float digital_signal_get_edge(DigitalSignal* signal, uint32_t edge_num);
|
||||
|
||||
bool digital_signal_send(DigitalSignal* signal, const GpioPin* gpio);
|
||||
@@ -95,6 +95,11 @@ C_SOURCES += $(wildcard $(LIB_DIR)/toolbox/*/*.c)
|
||||
CPP_SOURCES += $(wildcard $(LIB_DIR)/toolbox/*.cpp)
|
||||
CPP_SOURCES += $(wildcard $(LIB_DIR)/toolbox/*/*.cpp)
|
||||
|
||||
# Digital signal
|
||||
CFLAGS += -I$(LIB_DIR)/digital_signal
|
||||
C_SOURCES += $(wildcard $(LIB_DIR)/digital_signal/*.c)
|
||||
|
||||
|
||||
# USB Stack
|
||||
CFLAGS += -I$(LIB_DIR)/libusb_stm32/inc
|
||||
C_SOURCES += $(LIB_DIR)/libusb_stm32/src/usbd_stm32wb55_devfs.c
|
||||
|
||||
Reference in New Issue
Block a user