Ich verwende einen STM32L052K6U6, um mit einem SPI-Slave im UART1-Synchronmodus zu kommunizieren (konfiguriert mit CubeMX unter Verwendung der LL-Bibliothek).
Von CubeMX generierter Setup-Code (ich habe die Tx- und Clk-Pin-Konfiguration weggelassen, da diese Pins tun, was sie sollten):
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);
Von mir geschriebener Init-Code, der nach dem obigen Code ausgeführt wird (die EnableDirection-Aufrufe werden eigentlich nicht benötigt, Tx und RX sind im obigen Code bereits aktiviert):
LL_USART_Disable(USART1);
LL_USART_SetTransferBitOrder(USART1, LL_USART_BITORDER_MSBFIRST);
LL_USART_EnableDirectionTx(USART1);
LL_USART_EnableDirectionRx(USART1);
LL_USART_Enable(USART1);
Dies ist Teil des Codes, der Daten empfängt:
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);
Das Sondieren des Busses zeigt, dass die Takterzeugung und das Senden der Daten gut funktionieren und der Slave mit den erwarteten Daten antwortet. Der Empfänger ist aktiviert, aber die Daten werden nicht vom Mikrocontroller empfangen. Das Empfangsdatenregister und das RXNE-Flag bleiben Null. Was könnte das verursachen?
Warten Sie, TXE
bevor Sie senden
Warten Sie, RXNE
anstatt das BUSY
Bit zu überwachen, bevor Sie die Antwort lesen. Das Warten auf BUSY
diesen Weg könnte fehlschlagen, wenn ein Interrupt zur falschen Zeit kommt, und die Daten könnten noch nicht in das Datenregister übertragen werden, wenn BUSY
zu geht 0
.
Aktivieren Sie CPOL
und CPHA
, möglicherweise wird die Eingabe zur falschen Zeit abgetastet
Ich habe eine Lösung gefunden, aber ich weiß nicht, warum es funktioniert.
Es gibt einige Schreibvorgänge zur Initialisierung (max30003_init wird einmal aufgerufen) und dann wiederholte Lesesequenzen (max30003_readReg wird regelmäßig aufgerufen). Das Schreiben hat immer funktioniert, aber das Empfangen von Daten (und das Setzen des RXNE-Flags) funktioniert nur, wenn der USART nach den Initialisierungsschreibvorgängen deaktiviert und dann wieder aktiviert wird. Ohne sie bleibt das Programm hängen und wartet darauf, dass RXNE eingestellt wird. Damit wird das RXNE-Flag wie erwartet gesetzt und die empfangenen Daten gelangen tatsächlich in das Empfangsdatenregister.
Vollständiger Code:
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);
}
Ich habe keine Ahnung, warum der USART-Deaktivierungsimpuls benötigt wird. Hat jemand irgendwelche Ideen?
BEARBEITEN:
Dies wird durch das Overrun-Error-Bit verursacht, das Deaktivieren der Overrun-Erkennung löst das Problem. Das Referenzhandbuch erklärt es in einem Hinweis: "Wenn dieses Bit gesetzt ist, geht der Inhalt des RDR-Registers nicht verloren, sondern das Schieberegister wird überschrieben." Keine neuen RDR-Daten bedeuten auch, dass das RXNE-Flag nicht gesetzt wird. Neuer Init-Code:
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);
}
Danke für die Hilfe an alle!
Chris Stratton
Fr4nky
Chris Stratton
Fr4nky
Maxim Pawlenko