2017-01-13 6 views
0

J'ai un problème avec le STM32F0 DMA recevant des données de l'UART. J'utilise 2 canaux DMA (pour rx et tx) tous deux en mode non-circulaire, le canal rx a une priorité inférieure. Les données de l'UART traitent dans l'interruption de la ligne d'attente, où je lis le nombre d'octets reçus par DMA et les traite. Tout fonctionne correctement jusqu'à ce que le nombre d'octets dans le package soit inférieur ou égal à la taille du tampon DMA. Sinon, le DMA s'éteint étrangement et, à la suite des interruptions de ligne inactive, il me donne le nombre 1, 0, 0, ... de DMA reçus. Voici une partie du code, où je vérifie si les tampons DMA remplissages et essayer de réinitialiser le compteur DMA à la taille du tampon:STM32F0 "débordement d'entrée" DMA

#define S_M_INPUT_CMD_SIZE 20 
static char s_m_uart_dma_in_buff[S_M_INPUT_CMD_SIZE + 1]; 

void USART1_IRQHandler(void) 
{ 
    ITStatus reception_status = USART_GetITStatus(USART1, USART_IT_IDLE); 
    if(reception_status != RESET) 
    { 
     int32_t bytes_number = S_M_INPUT_CMD_SIZE - DMA_GetCurrDataCounter(DMA1_Channel3);    
     if (DMA_GetFlagStatus(DMA1_FLAG_TC3) != RESET) 
     { 
     USART_ITConfig(UART_, USART_IT_IDLE, DISABLE); 
     DMA_Cmd(DMA1_Channel3, DISABLE); 
     while (DMA1_Channel3->CCR & DMA_CCR_EN); 
     for (int i = 0; i < S_M_INPUT_CMD_SIZE; i++) 
      s_m_uart_dma_in_buff[i] = '\0'; 
     DMA_SetCurrDataCounter(DMA1_Channel3, S_M_INPUT_CMD_SIZE); 
     DMA_Cmd(DMA1_Channel3, ENABLE); 
     DMA_ClearFlag(DMA1_FLAG_GL3); 
     } 
     USART_ClearITPendingBit(UART_, USART_IT_IDLE); 
    } 
} 

Après le premier « débordement » et DMA permettant vient « taille de mémoire tampon + 1 » octet était dans le registre rx et plus tard le nombre d'octets reçus est stable à zéro. Qu'est-ce que je fais mal?

Répondre

1

Voici ce qui se passe si vous essayez de recevoir paquet avec une taille supérieure à S_M_INPUT_CMD_SIZE en utilisant votre code:

  1. DMA réception complète du bloc S_M_INPUT_CMD_SIZE et désactiver (mode non circulaire)
  2. USART1 reçoivent un octet
  3. USART1 recevoir un plus d'octets de paquet et déposez-les, parce que personne ne gère UART
  4. paquet terminé, vous obtenez d'interruption IDLE et reinit DMA
  5. rea DMA d précédemment octet reçu
  6. paquets Non plus - vous obtenez 0, 0, ... nombre de DMA reçu octets

Je dois dire, c'est vraiment étrange façon de gérer les transferts DMA. Les transferts DMA doivent généralement être gérés dans les gestionnaires d'interruption DMA, et non périphériques. Pour gérer les paquets longs, vous devez implémenter le gestionnaire d'interruption DMA. Donc, peut réinitialiser la réception DMA plus tôt que l'interruption IDLE. DMA sera donc prêt à recevoir plus de données de l'UART.

Encore une chose. Dans votre code il y a une course. entre vous lire bytes_number et désactiver DMA un ou plusieurs octets pourraient être transférés par DMA.

Mais une manière plus correcte de gérer UART est d'exécuter DMA en mode circulaire et ne pas le réinitialiser. Parce que chaque fois que vous désactivez DMA, vous pouvez manquer une entrée UART.

+0

Merci pour votre réponse @alexander. Peut-être que je ne vous comprends pas, mais a reçu le nombre octets "0, 0, ..." est la réaction sur les paquets suivants dans de nouvelles interruptions inactives, semble DMA juste fatigué de travailler. Le chemin est étrange Je suis d'accord, mais c'est la seule façon dont je suis venu pour recevoir un paquet de longueur variable avec un coût de cpu minimal. Et merci pour la course, je vais y remédier. – Yuriy

+0

@Yuriy, donc après un long paquet, vous envoyez un autre paquet? Et vous obtenez '0' aux paquets suivants? Comment vérifiez-vous bytes_number? J'espère que vous n'arrêtez pas le programme en utilisant JTAG dans ISR car JTAG peut corrompre une image réelle. Utilisez la variable globale pour enregistrer les événements. Il est également possible que UART et DMA se soient désynchronisés (vous devez donc réinitialiser UART ou DMA). En outre, il est possible que UART définisse un indicateur de dépassement de capacité et arrête la réception jusqu'à ce qu'il soit effacé. – alexander

+0

La vérification de zéro bytes_number ignore si (octets_numéro> 0). J'ai essayé de reconnecter USART et DMA, et j'ai essayé de désactiver/activer DMA RCC. Je vais essayer la réinitialisation complète, mais cela ne semble pas bon. – Yuriy