2017-10-06 13 views
2

J'ai un STM32F4, et je veux PWM un port GPIO qui a été avec un masque séparées par OR ..PWM DMA à l'ensemble GPIO

Alors, nous voulons peut-être PWM 0b00100010 pendant un certain temps à 200kHz , mais ensuite, 10khz plus tard, nous voulons maintenant PWM 0b00010001 ... puis, 10kHz plus tard, nous voulons PWM un autre masque sur le même GPIO.

Ma question est, comment faites-vous cela avec DMA? J'essaie de déclencher un transfert DMA qui va mettre tous les bits sur un front montant, puis un autre transfert DMA qui va effacer tous les bits sur un front descendant.

Je n'ai pas trouvé un bon moyen de le faire, (au moins avec CubeMX et mon expérience limitée avec C & STM32) car il semble que j'ai seulement une chance de faire quelque chose sur un front montant. L'une de mes principales préoccupations concerne le temps CPU, car bien que je mentionne des centaines de kilohertz dans l'exemple ci-dessus, je voudrais rendre ce cadre très robuste dans la mesure où il ne va pas gaspiller Ressources CPU ... C'est pourquoi j'aime l'idée de DMA, car c'est un matériel dédié qui fait l'objet d'un mot irrépressible, et le CPU peut faire d'autres choses comme des numéros crunch pour un PID ou autre chose.

Modifier Par souci de clarté: j'ai un ensemble de 6 valeurs que je pourrais écrire sur un GPIO. Ceux-ci sont stockés dans un tableau. Ce que j'essaie de faire est de configurer un temporisateur PWM pour définir le GPIO pendant la largeur positive du PWM, puis je veux que le GPIO soit réglé sur 0b00000000 pendant la période de faible largeur si le pwm. Donc, j'ai besoin de voir quand le front montant est, écrire rapidement sur le gpio, puis voir quand le front descendant est, et écrire 0 sur le gpio.

+0

qu'est-ce que 10kHz plus tard? Hz n'est pas l'unité de temps. DMA ne peut pas effectuer d'opérations logiques. Il ne fait que transférer les données de l'emplacement A vers l'adresse B. –

+0

Ok ... 100us plus tard, je veux appliquer le même pwm 200khz aux différentes broches du GPIO. Ainsi, nous transférons la variable contenant le masque vers le GPIOx-> BSRR ou avec DMA sur le front montant du PWM, puis sur le front descendant, nous remettons le GPIO à zéro ... 100us layer, un timer différent déborde ou compare ou quelque chose, et puis le seul changement qui conduit est que maintenant nous chargeons le DMA avec une valeur différente sur le front montant – testname123

+0

Je vous ai déjà donné la réponse. Mon exemple était pour 1 bit. ça peut être 16 aussi. Sinon, utilisez le minuteur généré PWM –

Répondre

1

solution limitée sans DMA

STM32F4 les contrôleurs ont 12 minuteurs avec jusqu'à 4 canaux PWM chacun, 32 au total. Certains d'entre eux peuvent être synchronisés pour commencer ensemble, par ex. vous pouvez avoir TIM1 en commençant TIM2, TIM3, TIM4 et TIM8 simultanément. C'est 20 sorties PWM synchronisées. Si ce n'est pas assez, vous pouvez former des chaînes où un timer esclave est un master pour un autre, mais il serait assez difficile de les garder parfaitement synchronisés. Pas si difficile, si un décalage de quelques cycles d'horloge est acceptable.

Il existe plusieurs exemples dans la section des exemples de projets de la bibliothèque STM32CubeF4, à partir desquels vous pouvez assembler votre configuration, voir Projects/*_EVAL/Examples/TIM/*Synchro*.

solution générale

Un but général ou une minuterie avancée (c'est tous sauf TIM6 et TIM7) peuvent déclencher un transfert DMA lorsque le compteur atteint la valeur de rechargement (événement de mise à jour) et lorsque le le compteur est égal à l'une des valeurs de comparaison (capture/compare event). L'idée est de laisser DMA écrire le modèle binaire souhaité sur la moitié basse (ensemble) de BSRR sur un événement de comparaison et les mêmes bits sur la moitié haute (réinitialisation) de BSRR sur un événement de mise à jour.

Il existe cependant un problème: DMA1 ne peut absolument pas accéder au bus AHB (voir Fig. 1 ou 2 du Manuel de référence) auquel les registres GPIO sont connectés. Par conséquent, nous devons utiliser DMA2, et cela nous laisse avec les minuteurs avancés TIM1 ou TIM8. Les choses sont encore plus compliquées parce que les requêtes DMA provoquées par la mise à jour et la comparaison des événements de ces temporisateurs aboutissent sur différents flux DMA (voir Tableau 43 dans la RM). Pour le rendre un peu plus simple, nous pouvons utiliser DMA 2, Stream 6 ou Stream 2, Channel 0, qui combinent les événements de 3 canaux de minuterie. Au lieu d'utiliser l'événement de mise à jour, nous pouvons définir le registre de comparaison sur un canal de minuterie à 0.

Mettre en place le flux DMA de la minuterie sélectionnée pour

  • canal 0
  • transfert unique (pas burst)
  • taille mémoire de données 16 bits
  • taille de données périphérique 16 bits
  • aucun incrément de mémoire
  • incrément adresse périphérique
  • en mode circulaire
  • mémoire périphérique
  • régulateur de débit périphérique: Je ne sais pas, expérience
  • nombre d'éléments de données 2
  • adresse périphérique GPIOx->BSRR
  • points d'adresse mémoire vers le modèle de bit de sortie
  • mode direct
  • enfin, activer le canal.

Maintenant, régler la minuterie

  • définir le prédiviseur et générer un événement de mise à jour si nécessaire
  • définir la valeur de recharge automatique pour atteindre la fréquence requise
  • ensemble la valeur de comparaison du canal 1 à 0
  • définir la valeur de comparaison du canal 2 au cycle de service requis
  • activer la demande DMA pour les deux canaux
  • permettent de comparer sur les deux canaux
  • activer le compteur

De cette façon, on peut contrôler 16 broches avec chaque minuterie, 32 si l'on utilise tous les deux en mode maître-esclave. Pour contrôler encore plus de broches (jusqu'à 64) à la fois, configurez les flux DMA supplémentaires pour les événements de comparaison et de mise à jour de canal 4, définissez le nombre d'éléments de données sur 1 et utilisez ((uint32_t)&GPIOx->BSRR)+2 comme adresse de périphérique pour la mise à jour courant.

Les canaux 2 et 4 peuvent être utilisés comme sorties PWM régulières, ce qui vous donne 4 broches supplémentaires. Peut-être que Channel 3 aussi.

Vous pouvez toujours utiliser TIM2, TIM3, TIM4 et TIM5 (chacun peut être asservi à TIM1 ou TIM8) pour 16 autres sorties PWM comme décrit dans la première partie de mon poste. Peut-être TIM9 et TIM12 aussi, pour 4 de plus, si vous pouvez trouver une configuration maître-esclave appropriée.

C'est 90 broches basculant à la fois. Attention aux limites de courant total.

+0

C'est tout! Je vous remercie! – testname123

0

que signifie PWM 0b00100010? PWM est une onde carrée avec un taux de service. Il sera très difficile d'archiver en utilisant DMA mais vous aurez besoin d'une table avec des valeurs déjà calculées. Par exemple, pour avoir un PWM de 2kHz avec un taux de 10%, vous devrez avoir 10 échantillons avec un bit défini, neuf avec un bit zéro. Vous configurez la minuterie à 20k/sec déclencher mem-to-mem (GPIO doit être fait de cette façon) Transmission DMA dans le mode circulaire. Sur la broche vous aurez 2kHz 10% d'onde. La résolution PWM sera de 10%. Si vous voulez faire 0,5%, vous aurez besoin de 200 échantillons de table et DMA déclenché 400k fois par seconde.

l'OMI, il est préférable d'utiliser pour charger de nouvelles valeurs timer et DMA à elle (lire le mode DMA rafale dans la documentation de la minuterie dans le Manuel de référence)

+0

Excusez-moi, mais j'ai l'air de déformer la question. Permettez-moi de clarifier: – testname123