Höhere macht beim Arduino Portenta h7 nicht gestattet

Hallo Doc_Arduino, Nyquist-Abtasttheorem fmax = Fs/2 usw, ja das ist mir alles bekannt.

Der clock Fluss bis zum DAC Timer, ist mir bekannt.
Fakt ist, ich habe einen Systemtakt von 480Mhz und eine APB1 Presacalr von 1
Das bedeute die APB1 clock läuft mit dem Systemtakt.

Das bedeutet im Umkehrschluss ich kann das DAc output Register 480 Millionen mal in der Sekunde beschreiben. Als im Grunde genommenem müsste ich eine Rechteck Impuls von 240 Mhz ausgeben können.

Das das nicht geht ist mir klar, weil der DAC irgendwo auch für eine Wandlung zeit benötigt.
Aber im Datenblatt steht, sofern man den Trigger auf None hat (also Automatisch), dann wird ins DAC Output Register geschrien nach einem Bus Takt sobald man ins DAC hold Register beschrieben hat.

Also quasi in Echtzeit zur loop. Der eine Takt ist zu vernachlässigen. Bei 480Mhz sind Das irgendwas mit 2,....ns.

Wenn ich jetzt folgende schleifen aufbau haben:

void loop() {
  uint16_t out = 0;
  uint16_t out_2 = 4090;
  unsigned long beginT = micros();
  for (uint16_t i = 0; i < 4090 * 2; i += 5) {
    if (out < 4095) {
      //HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1, DAC_ALIGN_12B_R, out);
      hdac1.Instance->DHR12R1 = out;
      out += 5;
    } else {
      //HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1, DAC_ALIGN_12B_R, out_2);
      hdac1.Instance->DHR12R1 = out_2;
      out_2 -= 5;
    }
  }
  unsigned long endT = micros() - beginT;
  //Serial.println(endT);
  //Serial.println(SystemCoreClock);
}

Dann erwarte ich ein "Ping-Pong" Output von weitaus mehr als 44kHz.

Die ganze schleife ist in gerade mal 22Mikrosekunden durchlaufen. Interessanter weiße ist 22Mikrosekunden ~45kHz.

Ich sehe mit meinem Redpitaya anscheint nur gewisse Punkte der DAC Ausgabe oder der STM32 überspringt Ausgabe werte. Wie Du es schon die ganze Zeit vermutest.

Gut okay, gehen wir die Sache etwas gemütlicher an und gehen mit der Samplerate auf 192kHz runter und geben ein 10kHz Sinus aus:

#include "stm32h7xx.h"
#include "nvic_addr.h"
#include "mbed_error.h"


#define FS 192000
#define FREQUENCY 10000

/******************************************************************************/
/*            PLL (clocked by HSE) used as System clock source                */
/******************************************************************************/
uint8_t SetSysClock_PLL_HSE() {
  RCC_ClkInitTypeDef RCC_ClkInitStruct = { 0 };
  RCC_OscInitTypeDef RCC_OscInitStruct = { 0 };
  RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = { 0 };

  // If we are reconfiguring the clock, select CSI as system clock source to allow modification of the PLL configuration
  if (__HAL_RCC_GET_PLL_OSCSOURCE() == RCC_PLLSOURCE_HSE) {
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_CSI;
    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK) {
      while (1)
        ;  //FAIL
    }
  }

  /* Enable oscillator pin */
  __HAL_RCC_GPIOH_CLK_ENABLE();
  GPIO_InitTypeDef gpio_osc_init_structure;
  gpio_osc_init_structure.Pin = GPIO_PIN_1;
  gpio_osc_init_structure.Mode = GPIO_MODE_OUTPUT_PP;
  gpio_osc_init_structure.Pull = GPIO_PULLUP;
  gpio_osc_init_structure.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOH, &gpio_osc_init_structure);
  HAL_Delay(10);
  HAL_GPIO_WritePin(GPIOH, GPIO_PIN_1, GPIO_PIN_SET);
  HAL_PWREx_ConfigSupply(PWR_SMPS_1V8_SUPPLIES_LDO);

  /* Configure the main internal regulator output voltage */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  while (!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}

  /* Enable HSE Oscillator and activate PLL with HSE as source */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_HSI48;
  RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS;
  RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 5;

  // 400 MHz (25 / 5 * 160 / 2 = 400)
  // 480 MHz (25 / 5 * 192 / 2 = 400)
  RCC_OscInitStruct.PLL.PLLN = 192;  //was 160;
  RCC_OscInitStruct.PLL.PLLFRACN = 0;
  RCC_OscInitStruct.PLL.PLLP = 2;
  RCC_OscInitStruct.PLL.PLLR = 2;
  RCC_OscInitStruct.PLL.PLLQ = 10;
  RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
  RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
    while (1)
      ;  // FAIL
  }

  /* Select PLL as system clock source and configure bus clocks dividers */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2 | RCC_CLOCKTYPE_D1PCLK1 | RCC_CLOCKTYPE_D3PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
  RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
  RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) {
    while (1)
      ;  //FAIL
  }


  __HAL_RCC_CSI_ENABLE();

  __HAL_RCC_SYSCFG_CLK_ENABLE();

  HAL_EnableCompensationCell();

  return 1;  // OK
}


DAC_HandleTypeDef hdac1;
HAL_DAC_StateTypeDef dacState;

const uint32_t numSamples = FS / FREQUENCY;
const double _T = 1.0f / FS * 1000 * 1000;
static uint16_t sineArray[FS] = { 0 };
uint32_t x = 0;

void initDAC1() {
  DAC_ChannelConfTypeDef sConfig = { 0 };
  // Enable clock for DAC
  __HAL_RCC_DAC12_CLK_ENABLE();
  // Initialize DAC
  hdac1.Instance = DAC1;
  hdac1.State = HAL_DAC_STATE_RESET;
  if (HAL_DAC_Init(&hdac1) != HAL_OK) {
    while (1)
      ;  //FAIL
  }

  sConfig.DAC_Trigger = DAC_TRIGGER_NONE;
  sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
  sConfig.DAC_SampleAndHold = DAC_SAMPLEANDHOLD_DISABLE;

  if (HAL_DAC_ConfigChannel(&hdac1, &sConfig, DAC_CHANNEL_1) != HAL_OK) {
    while (1)
      ;  //FAIL
  }
  HAL_DAC_Start(&hdac1, DAC_CHANNEL_1);
}

void delay_ns(uint32_t ns) {
  uint32_t tickstart = HAL_GetTick();
  uint32_t wait = ns * (SystemCoreClock / 1000000000UL);

  while ((HAL_GetTick() - tickstart) < wait) {};
}


void setup() {
  extern uint8_t SetSysClock_PLL_HSE();
  SetSysClock_PLL_HSE();
    Serial.begin(9600);
  unsigned long i = 0;
  for (; i < FS; i++) {
    int16_t val = 32767 * (sin(2 * PI * i * FREQUENCY / FS));
    sineArray[i] = (val + 32768) >> 4;
  }
  initDAC1();
}

void loop() {
  hdac1.Instance->DHR12R1 = sineArray[x];
  x = (x + 1) % FS;
  delayMicroseconds(_T);
  //Serial.println(SystemCoreClock);
}

Den Sampele intervall regelt delayMicroseconds(_T);. Ich erwarte einen 10Khz sinus am DAC ausgang.
Aber es kommen 100kHz heraus.

Also ist hier irgendwas nicht richtig an meiner Logic.

Hallo,

mach mal einen ganz einfachen Test.

loop
{
  DAC 0
  delay 1ms
  DAC 4095
  delay 1ms
}

Welchen Takt misst du? Dann reduzierst du das delay und misst erneut?
Stimmt die Erwartung überein oder nicht? Oder stimmt es irgendwann nicht mehr überein?
Meinetwegen noch die 4 relevanten Zeilen extra in eine while(1) einrahmen. Damit andere "Arduino-Hintergrundfunktionen" still bleiben.

Übrigens sowas hier ist gefährlich. Macht man nicht.

unsigned long i = 0;
for (; i < FS; i++) {
  int16_t val = 32767 * (sin(2 * PI * i * FREQUENCY / FS));
  sineArray[i] = (val + 32768) >> 4;
}

So ist sicher.

for (unsigned long i = 0; i < FS; i++) {
  int16_t val = 32767 * (sin(2 * PI * i * FREQUENCY / FS));
  sineArray[i] = (val + 32768) >> 4;
}

Edit:

noch besser wird sein um Fehlmessungen zu vermeiden

periode = 1ms

loop
{
  DAC 4095
  periode/2
  DAC 2048
  periode/2
  DAC 0
  periode*2      // zur Unterscheidung was zeitlicher loop Umlaufanteil ist

  Parser für Periodenwerte (optional)
}

Den Trigger am Oszi stellste auf 2,5V ... 3V ein.
Parser für Wertänderungen kannste dir schreiben um nicht laufend für Änderungen flashen zu müssen. Dann kann Meßreihen bequemer aufnehmen.

Hallo Doc_Arduino, danke für deine Bemühungen.
Habe das Problem gefunden. Durch das ändern der System PLL, habe ich wahrscheinlich die Delay Microseconds Funktion zersägt.

Zudem habe ich ein anderen Testkopf verwendet und at voila:



Tiefe Frequenzen haben noch eine recht gute Amplitude, alles über 500kHz da wird die Amplitude immer kleiner, bei 2,5Mhz kann ich die Schwingung kaum noch messen.

Problematisch für mein kommendes Projekt sind die nichtlineare Amplituden Verhältnisse.

Ich möchte gerne ein OFDM Signal erzeugen von 0 bis 1Mhz mit 20000 Trägern also 50Hz Abstand
Die träger sind alle einzeln Amplituden moduliert. ..Könnte spaßig werden xD
Solche Modulationen wurden schon auf dem Teensy 4.1 getestet und es funktioniert, nur hat man keinen DAC der das ausgeben kann
OFDM sample:

Aber die OFDM Geschichte ist erstmals zweitens.

Hier ist mein zu Letzt verwendeter Code:

#include "stm32h7xx.h"

#define FS ((2.5 * 1000000) * 2)// SamplingRate in MHz
#define FREQUENCY (2 * 1000000)//Mhz

/******************************************************************************/
/*            PLL (clocked by HSE) used as System clock source                */
/******************************************************************************/
uint8_t SetSysClock_PLL_HSE() {
  RCC_ClkInitTypeDef RCC_ClkInitStruct = { 0 };
  RCC_OscInitTypeDef RCC_OscInitStruct = { 0 };
  RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = { 0 };

  // If we are reconfiguring the clock, select CSI as system clock source to allow modification of the PLL configuration
  if (__HAL_RCC_GET_PLL_OSCSOURCE() == RCC_PLLSOURCE_HSE) {
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_CSI;
    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK) {
      while (1)
        ;  //FAIL
    }
  }

  /* Enable oscillator pin */
  __HAL_RCC_GPIOH_CLK_ENABLE();
  GPIO_InitTypeDef gpio_osc_init_structure;
  gpio_osc_init_structure.Pin = GPIO_PIN_1;
  gpio_osc_init_structure.Mode = GPIO_MODE_OUTPUT_PP;
  gpio_osc_init_structure.Pull = GPIO_PULLUP;
  gpio_osc_init_structure.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOH, &gpio_osc_init_structure);
  HAL_Delay(10);
  HAL_GPIO_WritePin(GPIOH, GPIO_PIN_1, GPIO_PIN_SET);
  HAL_PWREx_ConfigSupply(PWR_SMPS_1V8_SUPPLIES_LDO);

  /* Configure the main internal regulator output voltage */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  while (!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}

  /* Enable HSE Oscillator and activate PLL with HSE as source */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_HSI48;
  RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS;
  RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 5;

  // 400 MHz (25 / 5 * 160 / 2 = 400)
  // 480 MHz (25 / 5 * 192 / 2 = 400)
  RCC_OscInitStruct.PLL.PLLN = 192;  //was 160;
  RCC_OscInitStruct.PLL.PLLFRACN = 0;
  RCC_OscInitStruct.PLL.PLLP = 2;
  RCC_OscInitStruct.PLL.PLLR = 2;
  RCC_OscInitStruct.PLL.PLLQ = 10;
  RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
  RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
    while (1)
      ;  // FAIL
  }

  /* Select PLL as system clock source and configure bus clocks dividers */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2 | RCC_CLOCKTYPE_D1PCLK1 | RCC_CLOCKTYPE_D3PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
  RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
  RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) {
    while (1)
      ;  //FAIL
  }


  __HAL_RCC_CSI_ENABLE();

  __HAL_RCC_SYSCFG_CLK_ENABLE();

  HAL_EnableCompensationCell();

  return 1;  // OK
}


DAC_HandleTypeDef hdac1;
HAL_DAC_StateTypeDef dacState;

const uint32_t numSamples = FS / FREQUENCY;
const double _T = 1.0f / FS * 1000 * 1000 * 1000;
static uint16_t sineArray[numSamples] = { 0 };
uint32_t x = 0;

void initDAC1() {
  DAC_ChannelConfTypeDef sConfig = { 0 };
  // Enable clock for DAC
  __HAL_RCC_DAC12_CLK_ENABLE();
  // Initialize DAC
  hdac1.Instance = DAC1;
  hdac1.State = HAL_DAC_STATE_RESET;
  if (HAL_DAC_Init(&hdac1) != HAL_OK) {
    while (1)
      ;  //FAIL
  }

  sConfig.DAC_Trigger = DAC_TRIGGER_NONE;
  sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_DISABLE;
  sConfig.DAC_SampleAndHold = DAC_SAMPLEANDHOLD_DISABLE;

  if (HAL_DAC_ConfigChannel(&hdac1, &sConfig, DAC_CHANNEL_1) != HAL_OK) {
    while (1)
      ;  //FAIL
  }
  HAL_DAC_Start(&hdac1, DAC_CHANNEL_1);
}

// Wait for a number of nanoseconds.  During this time, interrupts remain
// active, but the rest of your program becomes effectively stalled.
static inline void delayNanoseconds(uint32_t nsec) {
  uint32_t begin = DWT->CYCCNT;
  uint32_t cycles = ((SystemCoreClock >> 16) * nsec) / (1000000000UL >> 16);
  while (DWT->CYCCNT - begin < cycles)
    ;  //wait
}


void setup() {
  extern uint8_t SetSysClock_PLL_HSE();
  SetSysClock_PLL_HSE();
  Serial.begin(9600);

  CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
  DWT->LAR = 0xC5ACCE55;
  DWT->CYCCNT = 0;
  DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;

  for (unsigned long i = 0; i < numSamples; i++) {
    int16_t val = 32767 * (sin(2 * PI * i * FREQUENCY / FS));
    sineArray[i] = (val + 32768) >> 4;
  }
  initDAC1();
}

void loop() {
  const int16_t *src, *end;
  src = (int16_t *)&sineArray[0];
  end = (int16_t *)&sineArray[numSamples];
  do {
    hdac1.Instance->DHR12R1 = *src++;
    delayNanoseconds(_T);
  } while (src < end);
  //Serial.println(SystemCoreClock);
}

Die SampleRate kann man bis auf 6Mhz hoch drehen, aber der DAC hört eben bei 2,5Mhz auf.

Die Sinuskurven berechnung ist auch nur quick and dirty. in der Regel berechent man eine LUT und gibt den Sinus uber ein Phasen Akkumulator aus.

Hallo,

schön das ein Problem weniger existiert. Jetzt ist alles im Nachgang wenigstens erklärbar.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.