Actualización: vea mi respuesta para corregirla.
Estoy intentando leer 4 bytes de un esclavo compatible con SPI (MAX31855) en SPI semidúplex bidireccional de 1 cable.
Aquí está mi código [SW Controlado SS] [SO- > MOSI]
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/dma.h>
#include <libopencm3/stm32/spi.h>
#include <libopencm3/stm32/f0/nvic.h>
#include <libopencm3/stm32/gpio.h>
/* USE: read 4 byte from a spi compatible slave (MAX31855) in 1 wire bidirectonal spi half-duplex */
#define ARRAY_SIZE 50
uint8_t arr_tx[ARRAY_SIZE];
uint8_t arr_rx[ARRAY_SIZE];
/* temp fix for libopencm3 */
#define SPI2_I2S_BASE SPI2_BASE
void main(void)
{
rcc_periph_clock_enable(RCC_DMA);
rcc_periph_clock_enable(RCC_SPI2);
rcc_periph_clock_enable(RCC_GPIOB);
/* INIT SPI GPIO */
gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO13|GPIO14|GPIO15);
gpio_set_output_options(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_HIGH, GPIO13|GPIO14|GPIO15);
gpio_set_af(GPIOB, GPIO_AF0, GPIO13|GPIO14|GPIO15);
/* INIT SPI SS GPIO */
gpio_mode_setup(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO12);
gpio_set_output_options(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_HIGH, GPIO12);
gpio_set(GPIOB, GPIO12);
/* DMA NVIC */
nvic_set_priority(NVIC_DMA1_CHANNEL4_5_IRQ, 3);
nvic_enable_irq(NVIC_DMA1_CHANNEL4_5_IRQ);
/* SPI NVIC */
nvic_set_priority(NVIC_SPI2_IRQ, 3);
nvic_enable_irq(NVIC_SPI2_IRQ);
/* INIT DMA SPI RX (DMA CHAN4) */
DMA1_IFCR = DMA_IFCR_CGIF4;
DMA1_CCR4 = DMA_CCR_MINC | DMA_CCR_TEIE | DMA_CCR_TCIE;
DMA1_CNDTR4 = 4;
DMA1_CPAR4 = (uint32_t)&SPI2_DR;
DMA1_CMAR4 = (uint32_t)arr_rx;
/* INIT DMA SPI TX (DMA CHAN5) */
DMA1_IFCR = DMA_IFCR_CGIF5;
DMA1_CCR5 = DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TEIE | DMA_CCR_TCIE;
DMA1_CNDTR5 = 4;
DMA1_CPAR5 = (uint32_t)&SPI2_DR;
DMA1_CMAR5 = (uint32_t)arr_tx;
/* INIT SPI */
SPI2_I2SCFGR = 0;
SPI2_CR1 = SPI_CR1_BAUDRATE_FPCLK_DIV_256 | SPI_CR1_MSTR | SPI_CR1_BIDIMODE | SPI_CR1_SSM | SPI_CR1_SSI;
SPI2_CR2 = SPI_CR2_DS_8BIT | SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN | SPI_CR2_ERRIE | SPI_CR2_FRXTH;
gpio_clear(GPIOB, GPIO12);
DMA1_CCR4 |= DMA_CCR_EN; /* RX CHAN */
SPI2_CR1 |= SPI_CR1_SPE;
DMA1_CCR5 |= DMA_CCR_EN; /* TX CHAN */
/* LOOP */
for(;;) {
__asm__("wfi");
}
}
void spi2_isr(void)
{
__asm__("bkpt");
}
void dma1_channel4_5_isr(void)
{
/* error occured? */
if(DMA1_ISR & (DMA_ISR_TEIF4 | DMA_ISR_TEIF5)) {
/* clear the flags */
DMA1_IFCR = DMA_IFCR_CGIF4 | DMA_IFCR_CGIF5;
__asm__("bkpt");
}
/* execute next if transfer is complete */
if(DMA1_ISR & (DMA_ISR_TCIF4 | DMA_ISR_TCIF5)) {
/* Wait to receive last data */
while (SPI2_SR & SPI_SR_RXNE);
/* Wait to transmit last data */
while (!(SPI2_SR & SPI_SR_TXE));
/* Wait until not busy */
while (SPI2_SR & SPI_SR_BSY); // infinite loop here: SPI2_SR = 0x06c3
/* clear the flags */
DMA1_IFCR = DMA_IFCR_CGIF4 | DMA_IFCR_CGIF5;
gpio_set(GPIOB, GPIO12);
/* disable SPI */
SPI2_CR1 &= ~SPI_CR1_SPE;
/* disable DMA trigger */
SPI2_CR2 &= ~(SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN);
__asm__("bkpt");
} else {
__asm__("bkpt");
}
}
Código para SS controlados HW
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/dma.h>
#include <libopencm3/stm32/spi.h>
#include <libopencm3/stm32/f0/nvic.h>
#include <libopencm3/stm32/gpio.h>
/* USE: read 4 byte from a spi compatible slave (MAX31855) in 1 wire bidirectonal spi half-duplex */
#define ARRAY_SIZE 50
uint8_t arr_tx[ARRAY_SIZE];
uint8_t arr_rx[ARRAY_SIZE];
/* temp fix for libopencm3 */
#define SPI2_I2S_BASE SPI2_BASE
void main(void)
{
rcc_periph_clock_enable(RCC_DMA);
rcc_periph_clock_enable(RCC_SPI2);
rcc_periph_clock_enable(RCC_GPIOB);
/* INIT SPI GPIO */
gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO12|GPIO13|GPIO14|GPIO15);
gpio_set_output_options(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_HIGH, GPIO12|GPIO13|GPIO14|GPIO15);
gpio_set_af(GPIOB, GPIO_AF0, GPIO12|GPIO13|GPIO14|GPIO15);
/* DMA NVIC */
nvic_set_priority(NVIC_DMA1_CHANNEL4_5_IRQ, 3);
nvic_enable_irq(NVIC_DMA1_CHANNEL4_5_IRQ);
/* SPI NVIC */
nvic_set_priority(NVIC_SPI2_IRQ, 3);
nvic_enable_irq(NVIC_SPI2_IRQ);
/* INIT DMA SPI RX (DMA CHAN4) */
DMA1_IFCR = DMA_IFCR_CGIF4;
DMA1_CCR4 = DMA_CCR_MINC | DMA_CCR_TEIE | DMA_CCR_TCIE;
DMA1_CNDTR4 = 4;
DMA1_CPAR4 = (uint32_t)&SPI2_DR;
DMA1_CMAR4 = (uint32_t)arr_rx;
/* INIT DMA SPI TX (DMA CHAN5) */
DMA1_IFCR = DMA_IFCR_CGIF5;
DMA1_CCR5 = DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TEIE | DMA_CCR_TCIE;
DMA1_CNDTR5 = 4;
DMA1_CPAR5 = (uint32_t)&SPI2_DR;
DMA1_CMAR5 = (uint32_t)arr_tx;
/* INIT SPI */
SPI2_I2SCFGR = 0;
SPI2_CR1 = SPI_CR1_BAUDRATE_FPCLK_DIV_256 | SPI_CR1_MSTR | SPI_CR1_BIDIMODE;
SPI2_CR2 = SPI_CR2_DS_8BIT | SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN | SPI_CR2_ERRIE | SPI_CR2_FRXTH | SPI_CR2_SSOE;
DMA1_CCR4 |= DMA_CCR_EN; /* RX CHAN */
SPI2_CR1 |= SPI_CR1_SPE;
DMA1_CCR5 |= DMA_CCR_EN; /* TX CHAN */
/* LOOP */
for(;;) {
__asm__("wfi");
}
}
void spi2_isr(void)
{
__asm__("bkpt");
}
void dma1_channel4_5_isr(void)
{
/* error occured? */
if(DMA1_ISR & (DMA_ISR_TEIF4 | DMA_ISR_TEIF5)) {
/* clear the flags */
DMA1_IFCR = DMA_IFCR_CGIF4 | DMA_IFCR_CGIF5;
__asm__("bkpt");
}
/* execute next if transfer is complete */
if(DMA1_ISR & (DMA_ISR_TCIF4 | DMA_ISR_TCIF5)) {
/* Wait to receive last data */
while (SPI2_SR & SPI_SR_RXNE);
/* Wait to transmit last data */
while (!(SPI2_SR & SPI_SR_TXE));
/* Wait until not busy */
while (SPI2_SR & SPI_SR_BSY); // infinite loop here: SPI2_SR = 0x06c3
/* clear the flags */
DMA1_IFCR = DMA_IFCR_CGIF4 | DMA_IFCR_CGIF5;
/* disable SPI */
SPI2_CR1 &= ~SPI_CR1_SPE;
/* disable DMA trigger */
SPI2_CR2 &= ~(SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN);
__asm__("bkpt");
} else {
__asm__("bkpt");
}
}
Los mismos fragmentos de código se pueden utilizar para realizar la transferencia en Full Duplex eliminando el bit BIDIMODE y conectando SO- > MISO.
En el modo dúplex completo no se produce ningún error SR_OVR, pero en el modo semidúplex, el bit SR_OVR causa un bucle infinito.
Probado: STM32F072RBT6
Pregunta:
-
¿Por qué se establece el bit SR_OVR y causa un bucle infinito?
-
¿Qué está mal con mi código O con alguna solución para este problema?