Estoy usando un STM32L052K6U6 para comunicarme con un esclavo SPI usando el modo síncrono UART1 (configurado con CubeMX, usando la biblioteca LL).
Código de configuración generado por CubeMX (Omití la configuración de pines Tx y Clk ya que esos pines hacen lo que deberían):
GPIO_InitStruct.Pin = USART1_RX_ECG_Pin;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_MEDIUM;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_4;
LL_GPIO_Init(USART1_RX_ECG_GPIO_Port, &GPIO_InitStruct);
USART_InitStruct.BaudRate = 2000000;
USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B;
USART_InitStruct.StopBits = LL_USART_STOPBITS_0_5;
USART_InitStruct.Parity = LL_USART_PARITY_NONE;
USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX;
USART_InitStruct.OverSampling = LL_USART_OVERSAMPLING_8;
LL_USART_Init(USART1, &USART_InitStruct);
USART_ClockInitStruct.ClockPolarity = LL_USART_POLARITY_LOW;
USART_ClockInitStruct.ClockPhase = LL_USART_PHASE_1EDGE;
USART_ClockInitStruct.LastBitClockPulse = LL_USART_LASTCLKPULSE_OUTPUT;
LL_USART_ClockInit(USART1, &USART_ClockInitStruct);
LL_USART_EnableDEMode(USART1);
LL_USART_DisableDEMode(USART1);
LL_USART_DisableDMADeactOnRxErr(USART1);
LL_USART_Enable(USART1);
LL_USART_ConfigSyncMode(USART1);
LL_USART_Enable(USART1);
Código de inicio escrito por mí, ejecutado después del código anterior (las llamadas EnableDirection no son realmente necesarias, Tx y RX ya están habilitados en el código anterior):
LL_USART_Disable(USART1);
LL_USART_SetTransferBitOrder(USART1, LL_USART_BITORDER_MSBFIRST);
LL_USART_EnableDirectionTx(USART1);
LL_USART_EnableDirectionRx(USART1);
LL_USART_Enable(USART1);
Esto es parte del código que recibe datos:
LL_USART_TransmitData8(USART1, 0);
while(!LL_USART_IsActiveFlag_BUSY(USART1));
while(LL_USART_IsActiveFlag_BUSY(USART1));
uint8_t data_1 = LL_USART_ReceiveData8(USART1);
Sondear el bus revela que la generación del reloj y el envío de datos funcionan bien y el esclavo responde con los datos esperados. El receptor está habilitado, pero el microcontrolador no recibe los datos. El registro de datos de recepción y la bandera RXNE permanecen en cero. Que podria causar esto?
Esperar TXE
antes de transmitir
Espere RXNE
en lugar de monitorear el BUSY
bit antes de leer la respuesta. Esperar de BUSY
esa manera puede fallar cuando llega una interrupción en el momento equivocado, y es posible que los datos aún no se transfieran al registro de datos cuando BUSY
vaya a 0
.
Marque CPOL
y CPHA
, podría estar muestreando la entrada en el momento equivocado
Encontré una solución, pero no sé por qué funciona.
Hay algunas escrituras para la inicialización (max30003_init se llama una vez) y luego secuencias de lectura repetidas (max30003_readReg se llama regularmente). La escritura siempre ha funcionado, pero la recepción de datos (y la configuración del indicador RXNE) solo funciona cuando se deshabilita y luego se vuelve a habilitar el USART después de que se escribe la inicialización. Sin él, el programa se atasca esperando que se configure RXNE. Con esto, el indicador RXNE se establece como se esperaba y los datos recibidos realmente llegan al registro de datos de recepción.
Código completo:
void max30003_init(void)
{
LL_GPIO_SetOutputPin(ECG_CS_GPIO_Port, ECG_CS_Pin);
LL_USART_Disable(USART1);
LL_USART_SetTransferBitOrder(USART1, LL_USART_BITORDER_MSBFIRST);
LL_USART_Enable(USART1);
LL_TIM_EnableCounter(TIM22);
LL_TIM_CC_EnableChannel(TIM22, LL_TIM_CHANNEL_CH1); //32.7...kHz FCLK
max30003_writeReg(REG_SW_RST,0x000000); //reset
delay_ms(10);
max30003_writeReg(REG_CNFG_GEN, 0x081007);
max30003_writeReg(REG_CNFG_CAL, 0x720000);
max30003_writeReg(REG_CNFG_EMUX,0x0B0000);
max30003_writeReg(REG_CNFG_ECG, 0x805000);
max30003_writeReg(REG_CNFG_RTOR1,0x3fc600);
max30003_writeReg(REG_SYNCH,0x000000);
//FIXME: receive doesn't work without this!?
LL_USART_Disable(USART1);
LL_USART_Enable(USART1);
delay_ms(10);
}
uint32_t max30003_readReg(uint8_t reg)
{
while(LL_USART_IsActiveFlag_BUSY(USART1));
while(!LL_USART_IsActiveFlag_TXE(USART1));
LL_USART_RequestRxDataFlush(USART1); //clear RXNE
LL_GPIO_ResetOutputPin(ECG_CS_GPIO_Port, ECG_CS_Pin);
LL_USART_TransmitData8(USART1, ((reg << 1) | READ));
while(!LL_USART_IsActiveFlag_RXNE(USART1));
LL_USART_RequestRxDataFlush(USART1); //clear RXNE
LL_USART_TransmitData8(USART1, 0);
while(!LL_USART_IsActiveFlag_RXNE(USART1));
uint8_t data_2 = LL_USART_ReceiveData8(USART1);
LL_USART_TransmitData8(USART1, 0);
while(!LL_USART_IsActiveFlag_RXNE(USART1));
uint8_t data_1 = LL_USART_ReceiveData8(USART1);
LL_USART_TransmitData8(USART1, 0);
while(!LL_USART_IsActiveFlag_RXNE(USART1));
uint8_t data_0 = LL_USART_ReceiveData8(USART1);
LL_GPIO_SetOutputPin(ECG_CS_GPIO_Port, ECG_CS_Pin);
return ((data_2 << 16) | (data_1 << 8) | data_0);
}
void max30003_writeReg(uint8_t reg, uint32_t data)
{
while(LL_USART_IsActiveFlag_BUSY(USART1));
while(!LL_USART_IsActiveFlag_TXE(USART1));
LL_GPIO_ResetOutputPin(ECG_CS_GPIO_Port, ECG_CS_Pin);
LL_USART_TransmitData8(USART1, ((reg << 1) | WRITE));
while(!LL_USART_IsActiveFlag_TXE(USART1));
LL_USART_TransmitData8(USART1, (uint8_t)(data >> 16));
while(!LL_USART_IsActiveFlag_TXE(USART1));
LL_USART_TransmitData8(USART1, (uint8_t)(data >> 8));
while(!LL_USART_IsActiveFlag_TXE(USART1));
LL_USART_TransmitData8(USART1, (uint8_t)data);
while(!LL_USART_IsActiveFlag_TC(USART1));
LL_GPIO_SetOutputPin(ECG_CS_GPIO_Port, ECG_CS_Pin);
}
No tengo idea de por qué se necesita el pulso de desactivación de USART. ¿Alguien tiene alguna idea?
EDITAR:
Esto es causado por el bit de error de desbordamiento, deshabilitar la detección de desbordamiento resuelve el problema. El manual de referencia lo explica en una nota: "Cuando se establece este bit, el contenido del registro RDR no se pierde, pero se sobrescribe el registro de desplazamiento". No hay nuevos datos RDR también significa que la bandera RXNE no se establece. Nuevo código de inicio:
void max30003_init(void)
{
LL_GPIO_SetOutputPin(ECG_CS_GPIO_Port, ECG_CS_Pin);
LL_USART_Disable(USART1);
LL_USART_SetTransferBitOrder(USART1, LL_USART_BITORDER_MSBFIRST);
LL_USART_DisableOverrunDetect(USART1);
LL_USART_Enable(USART1);
LL_TIM_EnableCounter(TIM22);
LL_TIM_CC_EnableChannel(TIM22, LL_TIM_CHANNEL_CH1); //32.7...kHz FCLK
max30003_writeReg(REG_SW_RST,0x000000); //reset
delay_ms(10);
max30003_writeReg(REG_CNFG_GEN, 0x081007);
max30003_writeReg(REG_CNFG_CAL, 0x720000);
max30003_writeReg(REG_CNFG_EMUX,0x0B0000);
max30003_writeReg(REG_CNFG_ECG, 0x805000);
max30003_writeReg(REG_CNFG_RTOR1,0x3fc600);
max30003_writeReg(REG_SYNCH,0x000000);
delay_ms(10);
}
¡Gracias por la ayuda a todos!
chris stratton
Fr4nky
chris stratton
Fr4nky
maximo pavlenko