2023-08-02 05:05 AM
I am attempting to demodulate fm0 modulated signal which is received via gpio on stm32f401re.
What should be the approach to this demodulation? please enumerate the steps i can follow. (ps. ~ the symbol period of fm0 modulated data is 4us)
Some insights to this problem would be much appreciated...:smiling_face_with_smiling_eyes:
Solved! Go to Solution.
2023-08-02 09:58 PM - edited 2023-08-02 09:59 PM
/* USER CODE BEGIN 2 */
HAL_TIM_IC_Start_DMA(&htim1, TIM_CHANNEL_1, edge_buffer, EDGE_BUFFER_LENGTH);
/* USER CODE END 2 */
in main.c at global level add callbacks
/* USER CODE BEGIN 0 */
#define EDGE_BUFFER_LENGTH 256
uint16_t edge_buffer[EDGE_BUFFER_LENGTH];
void process(uint16_t edges[], size_t len)
{
// compute edge arrival time differences and decide which FM0 cases you have observed
}
void HAL_TIM_IC_CaptureHalfCpltCallback(TIM_HandleTypeDef *htim)
{
HAL_GPIO_WritePin(LD3_GPIO_Port, LD3_Pin, GPIO_PIN_SET);
process(&edge_buffer[0], EDGE_BUFFER_LENGTH/2);
}
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
HAL_GPIO_WritePin(LD3_GPIO_Port, LD3_Pin, GPIO_PIN_RESET);
process(&edge_buffer[EDGE_BUFFER_LENGTH/2], EDGE_BUFFER_LENGTH/2);
}
/* USER CODE END 0 */
Implement the missing parts. Use a debugger early and often, to better understand what the code does. Tune parameters to your needs (buffer size, prescaler,...).
hth
KnarfB
2023-08-02 06:34 AM - edited 2023-08-02 06:35 AM
It's not easy/straightforward, but it can be done. One way is to create a timer to re-create the clock and then use SPI to receive the data.
To create the clock, hook up the signal to the external reset, set duty cycle to 50%, set interval to be just over the width of the shortest period. Set channel 1 to provide the clock and have it go from low to high at the mid-point of the internal. Hook up that to SPI_SCK.
Hook up your signal to to SPI_MISO. Receive data in SPI mode, then do the conversion after it's received. 1010 -> 00, etc. A 4us period might be pushing things, but I imagine it's doable, barely.
2023-08-02 09:50 AM
Alternative ways:
hth
KnarfB
2023-08-02 06:42 PM
Thanks a lot. If it's not too much trouble, could you share some resources where I can learn how to implement this? I'm new to embedded systems, working as an intern in my third year of B-tech. Some help in this implementation will help me learn better.
2023-08-02 07:39 PM
I wouldn't use interrupts if it has a 4 us period. I have used the second method in the past. Works well.
2023-08-02 09:58 PM - edited 2023-08-02 09:59 PM
/* USER CODE BEGIN 2 */
HAL_TIM_IC_Start_DMA(&htim1, TIM_CHANNEL_1, edge_buffer, EDGE_BUFFER_LENGTH);
/* USER CODE END 2 */
in main.c at global level add callbacks
/* USER CODE BEGIN 0 */
#define EDGE_BUFFER_LENGTH 256
uint16_t edge_buffer[EDGE_BUFFER_LENGTH];
void process(uint16_t edges[], size_t len)
{
// compute edge arrival time differences and decide which FM0 cases you have observed
}
void HAL_TIM_IC_CaptureHalfCpltCallback(TIM_HandleTypeDef *htim)
{
HAL_GPIO_WritePin(LD3_GPIO_Port, LD3_Pin, GPIO_PIN_SET);
process(&edge_buffer[0], EDGE_BUFFER_LENGTH/2);
}
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
HAL_GPIO_WritePin(LD3_GPIO_Port, LD3_Pin, GPIO_PIN_RESET);
process(&edge_buffer[EDGE_BUFFER_LENGTH/2], EDGE_BUFFER_LENGTH/2);
}
/* USER CODE END 0 */
Implement the missing parts. Use a debugger early and often, to better understand what the code does. Tune parameters to your needs (buffer size, prescaler,...).
hth
KnarfB
2023-08-05 05:53 AM
Hello, I tried implementing your solution. I made a simple PWM signal and fed it to the gpio pin for dma.
/* USER CODE BEGIN 2 */
//for PWM
TIM1->CCR1 = 10;
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
uint16_t edgeTimestamps[100];
HAL_TIM_IC_Start_DMA(&htim4, TIM_CHANNEL_1, (uint8_t*)edgeTimestamps, 500);
char buffer[50];
for (uint8_t i = 0; i < 100; i++) {
snprintf(buffer, sizeof(buffer), "Time Difference %d: %lu\r\n", i, edgeTimestamps[i]);
HAL_UART_Transmit(&huart2, (uint8_t *)buffer, strlen(buffer), HAL_MAX_DELAY);
}
/* USER CODE END 2 */
I have set up the dma in cyclic mode, and am printing the captured values to serial terminal. Howerver, something seems to be wrong in my configuration of clocks. Both timer 3 and 4 are run of 40kHz clk.
TIM3 is generating a pwm signal of 8us with 50% duty cycle.
How do I set up the TIM 4 to properly monitor the signal? Like I need the time difference between every edge to be stored in a buffer array. Perhaps I have made a different error? What must the prescaler and counter period of the TIM 4 be to measure in microseconds properly? What exactly is this function [ HAL_TIM_IC_Start_DMA(&htim4, TIM_CHANNEL_1, (uint8_t*)edgeTimestamps, 500); ] doing when in cyclic mode? Is there a way to reset the counter register value of TIM 4 simultaneously after storing it in array so only the count of the edge difference is stored in array?
2023-08-05 09:29 AM
edgeTimestamps are absolute values in timer "ticks" (increment periods), you have to calculate the differences manually. The 500 parameter is wrong, it must be the length of the array passed, 100. Cyclic DMA may be overkill, depending on your overall protocol. Typically, there will be some preamble at the beginning of a transfer and you may have some ideas about the transfer length. Then you can start/stop a linear DMA.
There are more tutorials around for the opposite, generating an arbitrary waveform by a timer & DMA, but the principles are the same.