2022-07-12 12:32 PM
Hello all,
I have been working on an STM32F0, with an external ADC. I used PA5 as an SCK with SPI1_SCK, PA6 as an SDO with SPI1_MISO, and PA8 as a CNV with TIM1_CH1. With one external ADC, it all worked as intended. I used an oscilloscope to confirm that it is giving accurate waves. My next task is to implement a second external ADC. I am trying to implement it by itself before combining them, but I am running into issues. This time I plan to use PB13 as an SCK with SPI2_SCK, PB14 as an SDO with SPI2_MISO, and PB11 as a CNV with TIM2_CH4. With these, I cannot get any wave readings. I use the libopencm3 library.
This is my original working code:
#ifndef STM32F0
#define STM32F0
#endif
#include "spi_eadc.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
static void clock_setup(void)
{
/* Enable clock at 48mhz */
rcc_clock_setup_in_hsi_out_48mhz();
/* Enables clocks for all needed peripherals */
rcc_periph_clock_enable(RCC_GPIOA | RCC_GPIOB | RCC_GPIOC);
rcc_periph_clock_enable(RCC_SPI1);
rcc_periph_clock_enable(RCC_USART1);
rcc_periph_clock_enable(RCC_TIM1);
}
static void gpio_setup(void)
{
/** LED GPIO SETUP **/
gpio_mode_setup(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO8 | GPIO9);
/** SPI GPIO SETUP **/
/* Configure CNV GPIO as PA8 (TIM1_CH1) */
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO8);
gpio_set_af(GPIOA, GPIO_AF2, GPIO8);
gpio_set_output_options(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO8);
/* Configure SCK GPIO as PA5 */
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO5);
gpio_set_af(GPIOA, GPIO_AF0, GPIO5);
gpio_set_output_options(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_100MHZ, GPIO5);
/* Configure MISO GPIO as PA6 */
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO6);
gpio_set_af(GPIOA, GPIO_AF0, GPIO6);
gpio_set_output_options(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_100MHZ, GPIO6);
/* Setup GPIO pin GPIO_USART1_TX/GPIO9 on GPIO port A for transmit. */
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO9);
gpio_set_af(GPIOA, GPIO_AF1, GPIO9);
}
static void spi_setup(void)
{
spi_reset(SPI1);
spi_init_master(SPI1, SPI_CR1_BAUDRATE_FPCLK_DIV_4, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE,
SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_MSBFIRST);
spi_set_data_size(SPI1, 16);
spi_enable_software_slave_management(SPI1);
spi_set_nss_high(SPI1);
spi_enable(SPI1);
}
static void uart_setup(void)
{
nvic_enable_irq(NVIC_USART1_IRQ);
usart_set_baudrate(USART1, 115200);
usart_set_databits(USART1, 8);
usart_set_stopbits(USART1, 1);
usart_set_mode(USART1, USART_MODE_TX);
usart_set_parity(USART1, USART_PARITY_NONE);
usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE);
usart_set_mode(USART1, USART_MODE_TX_RX);
usart_enable(USART1);
}
static void timer_setup(void)
{
timer_set_oc_mode(TIM1, TIM_OC1, TIM_OCM_TOGGLE);
timer_enable_oc_output(TIM1, TIM_OC1);
timer_enable_break_main_output(TIM1);
timer_set_oc_value(TIM1, TIM_OC1, 24000);
timer_set_prescaler(TIM1, 480 - 1);
timer_set_period(TIM1, 48000 - 1);
timer_generate_event(TIM1, TIM_EGR_CC1G | TIM_EGR_TG);
nvic_enable_irq(NVIC_TIM1_CC_IRQ);
timer_enable_irq(TIM1, TIM_DIER_CC1IE);
TIM_CR1(TIM1) |= TIM_CR1_CEN;
}
void tim1_cc_isr(void)
{
gpio_toggle(GPIOC, GPIO9);
SPI1_DR = 0x1;
while (!(SPI1_SR & SPI_SR_RXNE))
; /* wait for SPI transfer complete */
// I do calculations here but remove them for simplicity
TIM1_CCMR1 = TIM_CCMR1_OC1M_FORCE_HIGH; // (assumes all other bits are zero)
TIM1_CCMR1 = TIM_CCMR1_OC1M_TOGGLE;
TIM1_SR = ~TIM_SR_CC1IF; // clear interrupt
}
int main(void)
{
clock_setup();
gpio_setup();
spi_setup();
uart_setup();
timer_setup();
while (1)
;
}
This is the code for the second ADC, that is not getting a response:
#ifndef STM32F0
#define STM32F0
#endif
#include "spi_eadc.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
static void clock_setup(void)
{
/* Enable clock at 48mhz */
rcc_clock_setup_in_hsi_out_48mhz();
/* Enables clocks for all needed peripherals */
rcc_periph_clock_enable(RCC_GPIOA | RCC_GPIOB | RCC_GPIOC);
rcc_periph_clock_enable(RCC_SPI2);
rcc_periph_clock_enable(RCC_USART1);
rcc_periph_clock_enable(RCC_TIM2);
}
static void gpio_setup(void)
{
/** LED GPIO SETUP **/
gpio_mode_setup(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO8 | GPIO9);
/** SPI GPIO SETUP **/
/* Configure CNV GPIO as PB11 (TIM2_CH4) */
gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO11);
gpio_set_af(GPIOB, GPIO_AF2, GPIO11);
gpio_set_output_options(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO11);
/* Configure SCK GPIO as PB13 */
gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO13);
gpio_set_af(GPIOB, GPIO_AF0, GPIO13);
gpio_set_output_options(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_100MHZ, GPIO13);
/* Configure MISO GPIO as PB14 */
gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO14);
gpio_set_af(GPIOB, GPIO_AF0, GPIO14);
gpio_set_output_options(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_100MHZ, GPIO14);
/* Setup GPIO pin GPIO_USART1_TX/GPIO9 on GPIO port A for transmit. */
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO9);
gpio_set_af(GPIOA, GPIO_AF1, GPIO9);
}
static void spi_setup(void)
{
spi_reset(SPI2);
spi_init_master(SPI2, SPI_CR1_BAUDRATE_FPCLK_DIV_4, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE,
SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_MSBFIRST);
spi_set_data_size(SPI2, 16);
spi_enable_software_slave_management(SPI2);
spi_set_nss_high(SPI2);
spi_enable(SPI2);
}
static void uart_setup(void)
{
nvic_enable_irq(NVIC_USART1_IRQ);
usart_set_baudrate(USART1, 115200);
usart_set_databits(USART1, 8);
usart_set_stopbits(USART1, 1);
usart_set_mode(USART1, USART_MODE_TX);
usart_set_parity(USART1, USART_PARITY_NONE);
usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE);
usart_set_mode(USART1, USART_MODE_TX_RX);
usart_enable(USART1);
}
static void timer_setup(void)
{
timer_set_oc_mode(TIM2, TIM_OC4, TIM_OCM_TOGGLE);
timer_enable_oc_output(TIM2, TIM_OC4);
timer_enable_break_main_output(TIM2);
timer_set_oc_value(TIM2, TIM_OC4, 24000);
timer_set_prescaler(TIM2, 480 - 1);
timer_set_period(TIM2, 48000 - 1);
timer_generate_event(TIM2, TIM_EGR_CC4G | TIM_EGR_TG);
nvic_enable_irq(NVIC_TIM2_IRQ);
timer_enable_irq(TIM2, TIM_DIER_CC4IE);
TIM_CR1(TIM2) |= TIM_CR1_CEN;
}
void tim2_isr(void)
{
gpio_toggle(GPIOC, GPIO9);
SPI2_DR = 0x1;
while (!(SPI2_SR & SPI_SR_RXNE))
; /* wait for SPI transfer complete */
// I do calculations here but remove them for simplicity
TIM2_CCMR2 = TIM_CCMR2_OC4M_FORCE_HIGH; // (assumes all other bits are zero)
TIM2_CCMR2 = TIM_CCMR2_OC4M_TOGGLE;
TIM2_SR = ~TIM_SR_CC4IF; // clear interrupt
}
int main(void)
{
clock_setup();
gpio_setup();
spi_setup();
uart_setup();
timer_setup();
while (1)
;
}
Any tips, insight, or solutions would be greatly appreciated. Thanks in advance!
2022-07-12 02:46 PM
That you use some unusual environment, does not help here, problem may be hidden in that environment too. Generally, read out and check/compare-to-working/post content of SPI, TIM and relevant GPIO registers.
> With these, I cannot get any wave readings
What is on the TIM and SPI pins?
Divide and conquer - get timer working separately, then get the interrupt working, then get polled SPI working, then put things together.
JW
2022-07-13 04:28 AM
Thank you for the response JW,
As for the environment, I forgot to mention that in my initial post I am using the libopencm3 library. I have worked to simplify the setup and focus on the CNV. I removed the external ADC entirely and have the scope tied directly to PB11. This narrows my focus in the code to timer_setup() and tim2_isr(). I am confident that I am reaching the interrupt function as I get the LED flash. That would lead me to believe that the problem lies in timer_setup(), yet everything that I try shows no life on the scope.
2022-07-13 06:30 AM
Thank you for the response JW,
As for the environment, I forgot to mention that in my initial post I am using the libopencm3 library. I have worked to simplify the setup and focus on the CNV. I removed the external ADC entirely and have the scope tied directly to PB11. This narrows my focus in the code to timer_setup() and tim2_isr(). I am confident that I am reaching the interrupt function as I get the LED flash. That would lead me to believe that the problem lies in timer_setup(), yet everything that I try shows no life on the scope.
2022-07-13 06:36 AM
Which F0, exactly?
Set PB11 as GPIO Output, toggle and observe (i.e. isn't there a bad solder joint or similar hw problem).
I don't quite understand, what do you do in the ISR with the TIMx_CCMR register, and why do you do it. Start without that, just output plain PWM.
Read out (in debugger; or in code, transmitting through suitable means e.g. UART) content of TIMx and relevant GPIO registers.
JW
2022-07-13 06:50 AM
STM32F051R8T6
This is the datasheet: https://www.st.com/resource/en/datasheet/stm32f051r8.pdf
I will attempt to read out the content of TIM
Thanks again :)