Forum: Mikrocontroller und Digitale Elektronik STM32 QuadSPI CS-Frequenz erhöhen


von Kevin L. (kevka2908)


Lesenswert?

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.

von pegel (Gast)


Lesenswert?

Kevin L. schrieb:
> hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_2_CYCLE;

Geht das kleiner?

von pegel (Gast)


Lesenswert?

Und wie lang ist der "Cycle" überhaupt?

von Kevin L. (kevka2908)


Lesenswert?

pegel schrieb:
> Kevin L. schrieb:
>> hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_2_CYCLE;
>
> Geht das kleiner?

Geht noch auf einen Cycle runter ja, hat aber an der Frequenz nichts 
geändert.





pegel schrieb:
> Und wie lang ist der "Cycle" überhaupt?

Der Prescaler von QSPI beträgt drei, ergo ist ein Cycle 14 Nanosekunden 
lang, bzw. hat ne Frequenz von 72 MHz.

von pegel (Gast)


Lesenswert?

Habe es gerade mit CubeMX getestet, das stellt von sich aus auf ein 
Cycle.
Aber wenn das so wenig ausmacht ....

von A. B. (Gast)


Lesenswert?

Da ist vielleicht immer noch viel zu viel Drumherum ... Das Abfragen der 
Flags kann man sich auch schenken, am besten gleich die 2 Bytes mit 
einem Halfword-Zugriff aus dem FIFO lesen. Wenn noch keine Daten da 
sind, blockiert der Zugriff so lange ...

Das ist ja auch ziemlich am Sinn dieses QSPI-Interfaces vorbei: Da ist 
darauf optimiert, mit einer CS-Aktivierung gleich einen großen 
Datenblock zu lesen/zu schreiben, deshalb ja auch ein FIFO. Für immer 
nur zwei kümmerliche Bytes ist wie Fahren mit angezogener Handbremse.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.