SPI en STM32 no funcionará sin resistencias pullup e incluso entonces funciona mal

8

He estado tratando de hacer que el SPI1 en el STM32F103C8 ( tablero de píldora azul ) funcione correctamente desde hace algún tiempo. Cuando recién estoy comenzando a aprender ARM, simplemente estoy tratando de cambiar los datos a un registro de desplazamiento 74HC595 y bloquearlo para encender un byte de LED. No estoy leyendo ningún dato, así que solo tengo líneas MOSI, SCK y SS.

Al principio no estaba obteniendo nada, pero leyendo algunos ejemplos en línea podría solucionar estos primeros problemas para que la comunicación funcionara (necesitaba configurar correctamente los pines GPIOA y el software SS).

El principal problema en este momento es que si no incluyo resistencias pull-up en todas las líneas (MOSI, SCK y SS), el microcontrolador no genera nada en ninguna línea (verificado con un osciloscopio). Además de esto, después de agregar resistencias pull-up, el tiempo de aumento en los pulsos es muy lento, por lo que no puedo usar una frecuencia demasiado alta (con resistencias pull-up de 10 kΩ estoy limitado a aproximadamente 250 kHz SCK y conmutación a 330 Ω aproximadamente 4 MHz). Estoy trabajando en una placa de pruebas, pero incluso entonces con AVR y cableado más desordenado pude obtener un SPI de 4 MHz sin ningún problema sin resistencias adicionales y las formas de onda estaban más limpias.

Aquí hay dos imágenes (perdón por el estado abismal de mi pantalla de alcance) que transmiten el byte 0b01110010 a un reloj de 250 kHz. La traza superior es SCK y la inferior es MOSI. La primera imagen es con resistencias pull-up de 10 kΩ y la segunda con resistencias pull-up de 330 Ω que hacen que las formas de onda sean mucho más agradables (pero no deberían ser necesarias).

Agradecería un poco de ayuda para descubrir qué está pasando.

Resistencias pull-up de 10 kΩ y reloj de 250 kHz

Las resistencias pull-up de 330 Ω y 250 kHz hacen que la forma de onda sea mucho más agradable

Las partes relevantes de mi código son:

#define SS_LOW        GPIOA->BSRR |= 1 << 4 + 16;
#define SS_HIGH        GPIOA->BSRR |= 1 << 4;

// SPI GPIO configuration
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
GPIOA->CRL |= 0b0011 << 4 * 4;    // Set pin A4 as PP out 50mHz for SS
GPIOA->CRL |= 0b1011 << 5 * 4;    // Set pin A5 AltFunc PP out 50mHz for SCK
GPIOA->CRL |= 0b1011 << 7 * 4;    // Set pin A7 AltFunc PP out 50mHz for MOSI
SS_HIGH;

// SPI1 configuration
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;        // Enable SPI1 clock
SPI1->CR1 |= SPI_CR1_SSM;        // Software SS
SPI1->CR1 |= SPI_CR1_SSI;
SPI1->CR1 |= SPI_CR1_BR_0;        // Set prescaler
SPI1->CR1 |= SPI_CR1_BR_1;
SPI1->CR1 |= SPI_CR1_BR_2;
SPI1->CR1 |= SPI_CR1_MSTR;        // Master mode
SPI1->CR1 |= SPI_CR1_SPE;        // Enable SPI

// Transmit byte
SS_LOW;
SPI1->DR = 0b01110010;
while(!(SPI1->SR & SPI_SR_TXE));
while(SPI1->SR & SPI_SR_BSY);
SS_HIGH;
jjpprr
fuente
¿Cuál es tu configuración? ¿Cómo están conectados tus cables? ¿Estás usando una tabla personalizada o una placa de prueba?
Tarick Welling
Estoy usando una placa de pruebas. El 74hc595 se alimenta desde los 3.3V del tablero de pastillas azul (este para ser preciso: revspace.nl/File:Bluepill.jpg ). Los únicos cables que van desde y hacia el registro de desplazamiento son MOSI, SCK y SS. Estoy seguro de que el cableado es correcto, lo revisé varias veces (y una vez más antes de responderle).
jjpprr

Respuestas:

12

Debe restablecer el valor de los pines que está cambiando antes de configurar los bits.

El valor de reinicio de GPIOA_CRL es 0x4444 4444. Por lo tanto, cada pin se inicializa con 0b0100, si hace un | = 0b0011, termina con 0b0111, que es una salida de drenaje abierta. Lo mismo con 0b1011 se convierte en 0b1111 y esa es una función alternativa de drenaje abierto.

Entonces necesitas hacer algo como esto:

// Reset pin configuration
GPIOA->CRL &= ~(0b1111 << 4 * 4);  // Reset Pin A4
GPIOA->CRL &= ~(0b1111 << 5 * 4);  // Reset Pin A5
GPIOA->CRL &= ~(0b1111 << 7 * 4);  // Reset Pin A7
GPIOA->CRL |= 0b0011 << 4 * 4;  // Set pin A4 as PP out 50mHz for SS
GPIOA->CRL |= 0b1011 << 5 * 4;  // Set pin A5 AltFunc PP out 50mHz for SCK
GPIOA->CRL |= 0b1011 << 7 * 4;  // Set pin A7 AltFunc PP out 50mHz for MOSI
Arsenal
fuente
¡¡Esto fue!! Muchas gracias, sabía que iba a ser algo tan simple. Debería haber leído la primera línea en GPIOA_CRL de la hoja de datos, simplemente asumí que el valor de reinicio era todo ceros. Ahora funciona un encanto.
jjpprr
@jjpprr bueno, también me llevó un tiempo darme cuenta :-) Me alegro de poder ayudar. Si vas a usar I²C en el F103, prepárate para un viaje duro, recuerdo que fue horrible.
Arsenal
: O lo tendrá en cuenta, después de poner en marcha USART y ejecutarlo será el turno de I2C. Gracias por el aviso.
jjpprr
Lo que se destaca más profundamente en las interrupciones que estaba recibiendo sin ninguna fuente de interrupción que estropeó mi máquina de estados. Al final, opté por un enfoque que no utiliza interrupciones I²C (pero la interrupción DMA para el final de la transmisión) y solo sondea los bits I²C para el inicio y otras cosas, pero mi aplicación tuvo que esperar a que I²C terminara de todos modos , así que no estaba ganando tiempo con interrupciones de todos modos.
Arsenal
¿Fue esto solo con el F103 o también con otros chips stm32? Porque mi plan era usarlo solo para dominar los circuitos integrados stm32, pero luego pasar al F091 para proyectos pequeños y al F446 para cosas más exigentes.
jjpprr