Moin,
und zwar möchte ich mit dem STM32F767ZI Chip per QuadSPI einen ADC
ansprechen (AD4001). Wie im Protokoll definiert, habe ich dafür bereits
das Turbobit gesetzt, sowie den SPI-Takt auf mind. 70 MHz gesetzt. Der
Chip läuft mit 216MHz. Mein Problem besteht momentan noch darin, dass
der CS vom Controller zu lange auf High ist bevor das nächste Sample
ausgelesen wird (2µs von einer fallenden Flanke zur nächsten). Für die 2
MSPs Abtastrate müsste dieser Abstand aber bei 500ns liegen.
Initialisierung QSPI:
1 | static void MX_QUADSPI_Init(void)
|
2 | {
|
3 | /* QUADSPI parameter configuration*/
|
4 | hqspi.Instance = QUADSPI;
|
5 | hqspi.Init.ClockPrescaler = 2;
|
6 | hqspi.Init.FifoThreshold = 1;
|
7 | hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_NONE;
|
8 | hqspi.Init.FlashSize = 1;
|
9 | hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_2_CYCLE;
|
10 | hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;
|
11 | hqspi.Init.FlashID = QSPI_FLASH_ID_1;
|
12 | hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE;
|
13 | if (HAL_QSPI_Init(&hqspi) != HAL_OK)
|
14 | {
|
15 | Error_Handler();
|
16 | }
|
17 | }
|
Und hier die Konfiguration zum Auslesen der Daten im Indirect Read Mode.
1 | //Configure QSPI for receiving
|
2 |
|
3 | QSPI_CommandTypeDef qspicommand = {0};
|
4 | qspicommand.DdrMode = QSPI_DDR_MODE_DISABLE;
|
5 | qspicommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
|
6 | qspicommand.SIOOMode = QSPI_SIOO_INST_ONLY_FIRST_CMD;
|
7 | qspicommand.DataMode = QSPI_DATA_1_LINE;
|
8 | qspicommand.DummyCycles = 0;
|
9 | qspicommand.AlternateBytes = QSPI_ALTERNATE_BYTES_8_BITS;
|
10 | qspicommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
|
11 | qspicommand.AddressSize = QSPI_ADDRESS_8_BITS;
|
12 | qspicommand.AddressMode = QSPI_ADDRESS_NONE;
|
13 | qspicommand.InstructionMode = QSPI_INSTRUCTION_NONE;
|
14 | qspicommand.NbData = 2;
|
15 |
|
16 | HAL_QSPI_Command(&hqspi, &qspicommand, 0xFFFF);
|
Innerhalb meiner Main Methode erfolgt dann der Aufruf der Funktion zum
Auslesen der Daten:
1 | uint8_t tmp[2] = {0};
|
2 | while(1){
|
3 | HAL_QSPI_Receive(&hqspi, (uint8_t*)&tmp, 0x0000);
|
4 | }
|
Da die HAL-Funktion ziemlich aufgebläht mit Statusabfragen und ähnlichem
ist, habe ich die Methode etwas verkürzt:
1 | HAL_StatusTypeDef HAL_QSPI_Receive(QSPI_HandleTypeDef *hqspi, uint8_t *pData, uint32_t Timeout)
|
2 | {
|
3 | HAL_StatusTypeDef status = HAL_OK;
|
4 | uint32_t tickstart = HAL_GetTick();
|
5 | uint32_t addr_reg = READ_REG(hqspi->Instance->AR);
|
6 | __IO uint32_t *data_reg = &hqspi->Instance->DR;
|
7 |
|
8 | /* Configure counters and size of the handle */
|
9 | hqspi->RxXferCount = 2;
|
10 | hqspi->RxXferSize = 2;
|
11 | hqspi->pRxBuffPtr = pData;
|
12 |
|
13 | /* Configure QSPI: CCR register with functional as indirect read */
|
14 | MODIFY_REG(hqspi->Instance->CCR, QUADSPI_CCR_FMODE, QSPI_FUNCTIONAL_MODE_INDIRECT_READ);
|
15 |
|
16 | /* Start the transfer by re-writing the address in AR register */
|
17 | WRITE_REG(hqspi->Instance->AR, addr_reg);
|
18 |
|
19 | while(hqspi->RxXferCount > 0U)
|
20 | {
|
21 | /* Wait until FT or TC flag is set to read received data */
|
22 | status = QSPI_WaitFlagStateUntilTimeout(hqspi, (QSPI_FLAG_FT | QSPI_FLAG_TC), SET, tickstart, Timeout);
|
23 |
|
24 | *hqspi->pRxBuffPtr = *((__IO uint8_t *)data_reg);
|
25 | hqspi->pRxBuffPtr++;
|
26 | hqspi->RxXferCount--;
|
27 | }
|
28 |
|
29 |
|
30 | /* Wait until TC flag is set to go back in idle state */
|
31 |
|
32 | status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_TC, SET, tickstart, Timeout);
|
33 |
|
34 | /* Clear Transfer Complete bit */
|
35 | __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TC);
|
36 |
|
37 |
|
38 | return status;
|
39 | }
|
Damit habe ich die CS-Frequenz inzwischen auf 1 MHz erhöhen können,
höher ging es bisher nicht. Ich habe auch schon versucht, den CS Pin
ohne Alternate Function direkt anzusprechen und zu setzen, jedoch ohne
nennenswerte Zeitersparnis. Die Compilerflags sind auch auf O3 gesetzt.