Quadrokopter mit STM32F103CBT6

Programmieren mit CubeMX

Programmieren mit CubeMX

Hi

Ich möchte mal zeigen wie einfach man zur Initialisierung eines Peripheriebausteins mit CubeMX kommt.

Ziel: Pulse für WS2812 LEDs erzeugen lassen und dabei die MCU möglichst wenig belasten, also die DMA benutzen.

Erst mal sehen welche Pins für den Zweck noch frei sind und welche man vielleicht besser für Anderes aufhebt.

Zunächst wird in der Pinout Ansicht der Pin PB0 als TIM3_CH3 festgepinnt. Das Pinning kann später wieder gelöst werden.
Unter Peripherals wird TIM3 aufgeklappt und bei Channel3 "PWM Generation CH3" ausgewählt.

CubeMX-01.png

Dann zur Configuration Ansicht wechseln. Hier werden für alle Features Buttons gezeigt.
Wir klicken auf TIM3.

CubeMX-02.png

Im Tab "Parameter Settings" wird als einzige Änderung bei "Counter Period" 89 eingetragen.
Erklärung: Wir wollen 800 kHz Impulse, der Timer wird mit 72 MHz geclockt, das Auto Reload Register (ARR) aka "Counter Period"
wird mit Teiler - 1 geladen, kein Vorteiler wegen besserer Auflösung. Rechnung: 72 * 10^6 / 800 * 10^3 = 90 also 89 ins ARR

CubeMX-03.png

Im Tab "DMA Settings" wird ein DMA Kanal hinzugefügt und konfiguriert. Der Request soll jeweils vom abgelaufen Puls von TIM3_CH3 kommen.
Transportrichtung ist "Memory To Peripheral" und Priorität "high". Im Speicher sollen die Werte byteweise angeordnet sein, die Peripherie
hat Word lange Register. Im Speicher soll der Pointer inkrementiert werden in der Peripherie nicht. Die Werte aus dem Speicher sollen im Kreis herum
geladen werden.

CubeMX-04.png

Im Tab "GPIO Settings" wird der einzige für TIM3 zuständige Pin PB0 auf Speed "high" eingestellt und GPIO Mode auf "Alternate Function Opne Drain"
Erklärung: Die WS2812 LEDs werden mit 5V betrieben. Der STM32 kann von sich aus nur 3,3V an seinen Ausgängen liefern (Betriebsspannung).
Da die Pins aber 5V tolerant sind soll ein externer Pullup Widerstand verwendet werden.

CubeMX-05.png

Nachdem alles eingerichtet ist kann unter Project -> "Generate Code" neuer Code im vorhandenen Projekt erzeugt werden.

Ergebnis:
tim.c
Code:
#include "tim.h"

#include "dma.h"

/* USER CODE BEGIN 0 */                                                                                                                                            
                                                                                                                                                                   
/* USER CODE END 0 */                                                                                                                                              

TIM_HandleTypeDef htim2;
TIM_HandleTypeDef htim3;
DMA_HandleTypeDef hdma_tim3_ch3;

/* TIM2 init function */
void MX_TIM2_Init(void)
{
  TIM_MasterConfigTypeDef sMasterConfig;
  TIM_OC_InitTypeDef sConfigOC;

  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 17;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 19999;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }

  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 0;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }

  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
  {
    Error_Handler();
  }

  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
  {
    Error_Handler();
  }

  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
  {
    Error_Handler();
  }

  HAL_TIM_MspPostInit(&htim2);

}
/* TIM3 init function */
void MX_TIM3_Init(void)
{
  TIM_MasterConfigTypeDef sMasterConfig;
  TIM_OC_InitTypeDef sConfigOC;

  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 0;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 89;
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }

  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 0;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
  {
    Error_Handler();
  }

  HAL_TIM_MspPostInit(&htim3);

}

void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef* tim_pwmHandle)
{

  if(tim_pwmHandle->Instance==TIM2)
  {
  /* USER CODE BEGIN TIM2_MspInit 0 */

  /* USER CODE END TIM2_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_TIM2_CLK_ENABLE();

    /* Peripheral interrupt init */
    HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(TIM2_IRQn);
  /* USER CODE BEGIN TIM2_MspInit 1 */

  /* USER CODE END TIM2_MspInit 1 */
  }
  else if(tim_pwmHandle->Instance==TIM3)
  {
  /* USER CODE BEGIN TIM3_MspInit 0 */

  /* USER CODE END TIM3_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_TIM3_CLK_ENABLE();

    /* Peripheral DMA init*/
  
    hdma_tim3_ch3.Instance = DMA1_Channel2;
    hdma_tim3_ch3.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_tim3_ch3.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_tim3_ch3.Init.MemInc = DMA_MINC_ENABLE;
    hdma_tim3_ch3.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    hdma_tim3_ch3.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_tim3_ch3.Init.Mode = DMA_CIRCULAR;
    hdma_tim3_ch3.Init.Priority = DMA_PRIORITY_HIGH;
    if (HAL_DMA_Init(&hdma_tim3_ch3) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(tim_pwmHandle,hdma[TIM_DMA_ID_CC3],hdma_tim3_ch3);

  /* USER CODE BEGIN TIM3_MspInit 1 */

  /* USER CODE END TIM3_MspInit 1 */
  }
}
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct;
  if(timHandle->Instance==TIM2)
  {
  /* USER CODE BEGIN TIM2_MspPostInit 0 */

  /* USER CODE END TIM2_MspPostInit 0 */
    /**TIM2 GPIO Configuration    
    PA0-WKUP     ------> TIM2_CH1
    PA1     ------> TIM2_CH2
    PA2     ------> TIM2_CH3
    PA3     ------> TIM2_CH4 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* USER CODE BEGIN TIM2_MspPostInit 1 */

  /* USER CODE END TIM2_MspPostInit 1 */
  }
  else if(timHandle->Instance==TIM3)
  {
  /* USER CODE BEGIN TIM3_MspPostInit 0 */

  /* USER CODE END TIM3_MspPostInit 0 */
  
    /**TIM3 GPIO Configuration    
    PB0     ------> TIM3_CH3 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_0;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /* USER CODE BEGIN TIM3_MspPostInit 1 */

  /* USER CODE END TIM3_MspPostInit 1 */
  }

}

void HAL_TIM_PWM_MspDeInit(TIM_HandleTypeDef* tim_pwmHandle)
{

  if(tim_pwmHandle->Instance==TIM2)
  {
  /* USER CODE BEGIN TIM2_MspDeInit 0 */

  /* USER CODE END TIM2_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_TIM2_CLK_DISABLE();

    /* Peripheral interrupt Deinit*/
    HAL_NVIC_DisableIRQ(TIM2_IRQn);

  /* USER CODE BEGIN TIM2_MspDeInit 1 */

  /* USER CODE END TIM2_MspDeInit 1 */
  }
  else if(tim_pwmHandle->Instance==TIM3)
  {
  /* USER CODE BEGIN TIM3_MspDeInit 0 */

  /* USER CODE END TIM3_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_TIM3_CLK_DISABLE();

    /* Peripheral DMA DeInit*/
    HAL_DMA_DeInit(tim_pwmHandle->hdma[TIM_DMA_ID_CC3]);
  /* USER CODE BEGIN TIM3_MspDeInit 1 */

  /* USER CODE END TIM3_MspDeInit 1 */
  }
} 

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

/**
  * @}
  */

/**
  * @}
  */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

dma.c
Code:
#include "dma.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/*----------------------------------------------------------------------------*/
/* Configure DMA                                                              */
/*----------------------------------------------------------------------------*/

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

/** 
  * Enable DMA controller clock
  */
void MX_DMA_Init(void) 
{
  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();

  /* DMA interrupt init */
  /* DMA1_Channel2_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);

}

/* USER CODE BEGIN 2 */

/* USER CODE END 2 */

/**
  * @}
  */

/**
  * @}
  */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

tim.h und dma.h mit den Prototypen und Variablen für die handles werden natürlich auch erzeugt resp. modifiziert.
Wie man sieht, wurde der bereits vorhandenen Code für Timer2 sauber ergänzt und der Code für die erstmalig benutzte
DMA komplett neu erzeugt.

In main.c oder sonstwo brauch man dann nur noch sowas ähnliches:
Code:
#define NR_LEDS 12
enum { G, R, B };

void led_trans_vals(void);

uint8_t aCCValue_Buffer[392]; // max 16 LEDs (24 * 12 + 8)
uint8_t led_val[16][3];

led_val[0][G] = 0;
led_val[0][R] = 64;
led_val[0][B] = 0;
...
led_val[NR_LEDS - 1][G] = 0;
led_val[NR_LEDS - 1][R] = 64;
led_val[NR_LEDS - 1][B] = 0;

led_trans_vals();

HAL_TIM_PWM_Start_DMA(&htim3, TIM_CHANNEL_3, (uint32_t *) aCCValue_Buffer, NR_LEDS * 24 + 8);

void led_trans_vals(void)
{
    uint8_t i, j;
    uint16_t k;

    k = 0;
    for (i = 0; i < NR_LEDS; i++) // each LED
    {
        for (j = 0; j < 3; j++) // 3 colors
        {
            aCCValue_Buffer[k++] = led_val[i][j] & 1 << 7 ? 60 : 30; // each bit
            aCCValue_Buffer[k++] = led_val[i][j] & 1 << 6 ? 60 : 30;
            aCCValue_Buffer[k++] = led_val[i][j] & 1 << 5 ? 60 : 30;
            aCCValue_Buffer[k++] = led_val[i][j] & 1 << 4 ? 60 : 30;
            aCCValue_Buffer[k++] = led_val[i][j] & 1 << 3 ? 60 : 30;
            aCCValue_Buffer[k++] = led_val[i][j] & 1 << 2 ? 60 : 30;
            aCCValue_Buffer[k++] = led_val[i][j] & 1 << 1 ? 60 : 30;
            aCCValue_Buffer[k++] = led_val[i][j] & 1 ? 60 : 30;
        }
    }
    for (i = 0; i < 8; i++)
    {
        aCCValue_Buffer[k++] = 0; // pulse pause
    }
}

Nachdem HAL_TIM_PWM_Start_DMA einmal aufgerufen wurde braucht man nur noch die LED Farben nach belieben ändern und danach die Bits der RGB Werte mit led_trans_vals()
in Counter Werte für das Pulslängen Register (CCR) umzuwandeln. Die DMA liefert sie fortlaufend zum passenden Zeitpunkt an das Register. Die Werte für die 1 und 0 Pulse
ergeben sich wie folgt: 0 Puls 400 nS, 1 Puls 800 nS ==> 72 * 10^6 * 400 * 10^-9 = 30 ...

Natürlich ist das noch suboptimal und es gibt speichersparende Lösungen. Z.B. kann man nur 2 Werte in aCCValue_Buffer[] aufbewahren und den ersten
Wert interruptgesteuert in der Callback Function "XferHalfCpltCallback" ersetzen und den zweiten Wert in "XferCpltCallback".
Allerdings muss man dann für weniger Speicherverbrauch mit mehr verteilter Rechenzeit bezahlen. So hat man das Rechnen konzentriert an einer Stelle.

Gruß
Dieter
 

Ay3.14

User
Frame / Kit ?

Frame / Kit ?

Moin Dieter,

welchen Frame / Kit hast du für deinen Quadrokopter verwendet bzw. würdest du empfehlen?

Gruß
Albert
 
Moin

Ich habe für mein letztes Projekt ohne Display den Realac X210 Frame in 4mm genommen.
http://www.banggood.com/Realacc-X21...-FPV-Racing-Frame-w-5V-12V-PDB-p-1069204.html
Das ist der auf den zuletzt geposteten Fotos aber jetzt mit Fatshark Videoantenne und gesteuerter Beleuchtung. Die Motoren sind Tiger Motors MN 1806, Kv 2300. Regler sind die Kiss 18A und Propeller Dalprop 3 Blatt T5040
Der Akku ist ein TURNIGY NANO-TECH 1500MAH 3S 35~70C. Damit ist die Abflugmasse 367,8 g

Tatsächlich war heute der Erstflug, in einer Turnhalle. Die einzige Überraschung: über 11 Min. rumcruisen bis die Akkuspannung unter die eingestellte Schwelle von 10,5V ging.
Ich konnte schon das Potenzial für eine aus meiner Sicht brachiale Power spüren. So freue ich mich schon auf die ersten warmen Tage draußen.

Gruß
Dieter
 

Ay3.14

User
Danke!

Danke!

Hallo Dieter,

ich gratuliere zum Erstflug mit dem 210er Rahmen,
und vielen Dank für die Informationen und Tipps zu deiner aktuellen Kombination.

Der "Realacc X210 Frame" hat mir so gut gefallen das ich ihn sogleich bestellt habe, auch wegen dem aktuellen Neujahrs-Rabatt. :)

So langsam wächst meine Vier-Propeller-Fluglagesteuerung (dank deiner motivierenden Anregung) und wird demnächst auf eine Basisplatine verpflanzt werden.
2017-01-30 Vier-Propeller-Fluglagesteuerung.JPG

Many happy landings
Albert
 
Herztransplantation

Herztransplantation

Hi

Ich habe mal einen STM32L433CCT6 auf die Maple mini Clone Platine gelötet.

M4 core

64 KB of SRAM including 16 KB with
hardware parity check

256 KB single bank Flash

80 MHz

Pinkompatibel

Gruß
Dieter
 

Anhänge

  • P2032271-cropped-resized.JPG
    P2032271-cropped-resized.JPG
    1,2 MB · Aufrufe: 242
Hi,
ich lese so nebenbei mit...
Aber falls noch eine andere Basis in Frage kommt guckt euch das hier mal an.
https://www.pjrc.com/store/teensy36.html

Danke für den Hinweis.

Das wäre aber für diesen Zweck der totale Overkill. Kostet ja auch fast 10 mal soviel und die Platine ist außerdem größer.
Für die Flight Control, so wie sie jetzt ist, ist ja ein STM32F103 völlig ausreichend. Aber die Features aus dem M4 core
wie z.B floating point unit sind nett und man hat mehr Zeit für weitere Sachen. Mehr Ram ist auch toll, weil man Buffer einfach
mal größer machen kann, um z.B. das Display schneller zu machen, wenn man will. Der Umbau dieser Maple clone China Platinchen
hat für kleines Geld schon große Wirkung.

Teensy 3.2 ist aber schön klein. Womit entwickelt man für diese Platform?

Gruß
Dieter
 

adrock

User
HI,

nettes Projekt. Ich beschäftige mich seit 2 Jahren mit den STM32 MCUs, bis jetzt allerdings nur STM32F0 (hat bis jetzt gereicht...), fliegen tue ich eher Fläche und Heli, also kein Copter bis jetzt.

Wie auch immer, ein paar Anmerkungen:

- Um Schaltpläne zu zeichnen und einfache Boards zu layouten verwende ich DipTrace (ist mit Beschränkung kostenlos), KiCad oder Eagle waren mir von der Bedienung bisher her zu un-intuitiv, auch wenn sie von den Features her evtl. besser sind

- Als IDE verwende ich EmBitz, allerdings unter Windows, ist für Linux wohl nicht verfügbar

- CubeMX/HAL hatte ich mir angesehen und in manchen Projekten verwendet, in anderen auch direkt die Register beschrieben

Das Problem welches ich mit den HALs habe ist folgendes: Es ist weder Fisch noch Fleisch. Eine echte Abstraktion ist es nicht, ist auch eigentlich so garnicht mögich. Andererseits sind die Funktionen teilweise nicht wirklich toll dokumentiert (zumindest beim CMSIS bzw. den "alten" HAL libs war das so). Also muss man eigentllich doch jedes mal in den Sourcecode der HAL-Funktion schauen, um genau zu wissen wie sie funktioniert. Und das Refmanual zur entsprechenden STM32 Familie muss man auch lesen, da die Funktionen eben sehr hardwarenah sind. Also WAS genau bringen mir die Libs dann? Meines Erachtens hätten es bessere Includes (für viele Werte der HW-Register gibt es keine sprechenden Definitionen) mit ein paar Macros auch getan.

Ansonsten ist das CubeMX natürlich nett mit der Pin-Zuweisung etc. Ich werde ihm auch nochmal eine Chance geben. Von der Performance her muss man sich glaube ich bei MCUs jenseits der 20 MHz wenig Sorgen machen das HAL viel ausbremst, wichtig ist eher das man die Hardware sinnvoll nutzt (DMA etc.), dann sind viele Klimmzüge in Software garnicht notwendig. Und notfalls kann man ja immer noch in zeitkritischen Sachen direkt die Register ansprechen.

Noch eine Frage:

Hast Du die EIn/Ausgänge für die Signale 5V tolerant gebaut oder funktioniert das auch mit 3.3V?

Viele Grüße
Markus
 
- Um Schaltpläne zu zeichnen und einfache Boards zu layouten verwende ich DipTrace (ist mit Beschränkung kostenlos), KiCad oder Eagle waren mir von der Bedienung bisher her zu un-intuitiv, auch wenn sie von den Features her evtl. besser sind

Hast Du die EIn/Ausgänge für die Signale 5V tolerant gebaut oder funktioniert das auch mit 3.3V?

Hi

Ich hatte mich mal in Target3001 eingearbeitet und damit einen Powerconverter ( 2,8 - 4,2 V In, 4,15V 4A Out, Masse 3g) realisiert. Das hat Wochen gedauert trotz weniger Bauteile. Damit fliege ich immer noch den Blade mCP-X Heli.
Target3001 ist auch mit Beschränkungen kostenlos. Inzwischen mag ich solche Beschränkungen gar nicht mehr. Schade um die Zeit der Einarbeitung. Alle Welt scheint heute KiCad zu benutzen. Es gibt auch nützliche tools im Umfeld z.B. http://kicad.rohrbacher.net/quicklib.php

Der einzige Ausgang den ich opendrain mit externem pullup Widerstand nach 5V betreibe ist für die Beleuchtung mit WS-2812 LEDs. Aus dem Jeti RSAT2 kommen wohl 5V auf den UART Pin.
Die Kiss Regler laufen ohne Störung mit 3,3V Steuersignal. In dem Schaltbild einer frühen NAZE32 Version finde ich auch die Ausgänge zu den Motorreglern direkt mit den MCU Pins verbunden.
Gibt es eigentlich ein öffentliches Schaltbild von neueren NAZE32?

Gruß
Dieter
 

Ay3.14

User
"Eingerahmt"

"Eingerahmt"

Hallo,

nachdem das Päckchen mit dem "Realacc X210 mm" Rahmen ankam wurde schon mal "eingerahmt".
2017-02-12 Eingerahmt mit Platine.JPG
Als nächstes wird nun die "erste" Lochrasterplatine mit der Fluglagesteuerung folgen. Nicht schön aber selten. Habe mich beim Abzählen der 2,54 mm Rasterung um +1 vertan und nun sind es 22 x 18 (statt 21 x 18).

Viele Grüße
Albert
 
Hallo Albert,

fliegt er schon?

Ich habe das Projekt auf den STM32L433CCT6 portiert.
https://github.com/nichtgedacht/L433CCTx-mini-sys
https://github.com/nichtgedacht/L433CCTx-bootloader

Änderungen sind vor Allem wegen dem Flash der sich nur 64 bit weise beschreiben lässt und 2k Seitengröße hat.
Die Pinbelegung hat sich etwas geändert um den weiteren seriellen Port USART2 mit DMA (Schreiben und Lesen) zur Verfügung zu haben.
Ebenso sind die Anschlüsse für die Beleuchtung und den Taster für Zwangs DFU Start gewandert.
In der nächsten Version werde ich diese Belegung auch für das ursprüngliche Projekt anwenden, das dann damit voll pinkompatibel sein wird.

Lange habe ich nach einem Fehler im SPI gesucht.

Wenn USB angeschlossen und in der Software initialisiert wurde gab es Bildfehler beim Darstellen eines BMP Files von SD-Karte.
Wenn das LCD-Display defined und in der Software initialisiert wurde, waren die Sensordaten nicht korrekt in den Variablen.
Ein Logik-Analyzer zeigte: alle Daten korrekt geschrieben und gelesen.

Ursache war, das die neue Peripherie einen FIFO für SPI hat und an zwei Stellen in den Low Level Funktionen vom LCD IO direkt
in die Datenregister geschrieben wird um die Sache schneller zu machen statt die regulären HAL Funktionen zu verwenden.
Beim bloßen Schreiben fallen auf dem RX seitigen FIFO aber Daten an, die nach der Aktion durch Zuweisung/Lesen ins Nirvana beförderd werden müssen.
Sonst hängen sie beim nächsten betätigen der HAL Funktion dazwischen.

Gruß
Dieter
 

Ay3.14

User
Hallo Klaus,

mein Quadrokopter fliegt noch nicht, ist aber schon mal für eine halbe Sekunde knapp über dem Boden "geschwebt". Ansonsten rutsche ich zum Testen noch über den Teppichboden oder halte den Quadrokopter in der Hand.

Ich bin momentan dabei die PID-Werte zu eruieren und habe dabei leider festgestellt das scheinbar meine Verbindung zum Graupner HoTT GR-12L Empfänger (via HoTT SUMD Data Protocol (alle 10 ms werden 29 Bytes (12 Kanäle) übertragen)) manchmal unterbrochen/gestört ist. Jetzt bin ich also auf der Suche nach der Fehlerquelle (vermutlich habe ich da irgendwo suboptimal programmiert).

Mein Quadrokopter wiegt flugbereit 473 g (wobei der LiPo (3s, 1500 mAh) 139 g wiegt).

2017-02-24 Mein Quadrokopter Flugbereit (1) reduziert.JPG

Welchen funktionalen Vorteil versprichst du dir vom STM32L433CCT6 zu diesen Zweck (also im Vergleich zur aktuellen Variante mit dem STM32F103)?

Holm- und Rippenbruch
Albert
 
...
Ich bin momentan dabei die PID-Werte zu eruieren und habe dabei leider festgestellt das scheinbar meine Verbindung zum Graupner HoTT GR-12L Empfänger (via HoTT SUMD Data Protocol (alle 10 ms werden 29 Bytes (12 Kanäle) übertragen)) manchmal unterbrochen/gestört ist. Jetzt bin ich also auf der Suche nach der Fehlerquelle (vermutlich habe ich da irgendwo suboptimal programmiert).
...
Welchen funktionalen Vorteil versprichst du dir vom STM32L433CCT6 zu diesen Zweck (also im Vergleich zur aktuellen Variante mit dem STM32F103)?

Hallo Albert,

HoTT SUMD ist doch das Gleiche wie SRXL resp. UDI mit 12 Kanälen, oder? Hast Du einen Logic Analyzer? So ein Ding für 8€ von eBay ist schon mehr wert als man dafür bezahlt.
Liest Du die Werte auch per Interrupt für jeweils einen Satz Kanaldaten ein?
Ich bin neugierig mal Deinen Code zu sehen.

PID Werte habe ich zunächst grob in der Hand eingestellt.

1. Nur P Anteil und soweit erhöhen bis er super lose gehalten das Schwingen anfängt.
2. P Anteil halbieren und I Anteil zugeben bis er super lose gehalten das Schwingen anfängt.
3. I Anteil halbieren und mit etwas zusätzlich D Anteil in der Hand testen.
4. Den D Anteil im Flug testen und soweit erhöhen bis ein Ruckartiges Anstoßen mit Roll- und Nick-Ausschlag kein Überschwingen mehr bewirkt.

Für das Quadcopterprojekt wie es jetzt ist gibt es wohl keine Vorteile durch einen schnelleren Kern. Man könnte durch die floatingpoint Unit vielleicht
die Genauigkeit der Regler verdoppeln und hätte vielleicht endlich die Zeit die Checksumme für SRXL zu verifizieren.
Oneshot 125 ist auch mit der F103 MCU schon möglich, wenn man komplett auf eine Aktualisierung des Displays im Flugmodus verzichtet.

Gruß
Dieter
 
Ansicht hell / dunkel umschalten
Oben Unten