2015-11-05 3 views
2

Depuis pas mal de temps, je me bats avec la communication DMA avec deux cartes STM32 sous une forme ou une autre. Mon numéro actuel est le suivant.STM32 DMA: octets restants dans le tampon, codés?

J'ai un hôte (un Raspberry Pi) exécutant le code suivant, en attendant que le conseil d'administration à la communication initialisez:

#include <fcntl.h> 
#include <stdio.h> 

int main(int argc, char *argv[]) { 
    unsigned int usbdev; 
    unsigned char c; 
    system("stty -F /dev/ttyUSB0 921600 icanon raw"); 
    usbdev = open("/dev/ttyUSB0", O_RDWR); 
    setbuf(stdout, NULL); 
    fprintf(stderr, "Waiting for signal..\n"); 
    while (!read(usbdev, &c, 1)); 
    unsigned char buf[] = "Defend at noon\r\n"; 
    write(usbdev, buf, 16); 
    fprintf(stderr, "Written 16 bytes\r\n"); 
    while (1) { 
     while (!read(usbdev, &c, 1)); 
     printf("%c", c); 
    } 
    return 0; 
} 

Fondamentalement, il attend un seul octet de données avant de les envoyer va « défendre à midi "au tableau, après quoi il imprime tout ce qui est renvoyé. Les cartes émettent d'abord un seul octet, puis attendent toutes les données entrantes, remplacent quelques octets et les renvoient. Voir le code à la fin de ce post. La carte peut être soit un STM32L100C soit un STM32F407 (en pratique, les cartes de découverte); Je ressens le même comportement avec les deux à ce stade.

La sortie que je vois (une bonne journée - un mauvais jour, il se bloque sur Written 16 bytes) est la suivante:

Waiting for signal.. 
Written 16 bytes 
^JDefend adawnon 

Comme vous pouvez le voir, les données sont envoyées et quatre octets sont remplacés comme prévu, mais il y a deux caractères supplémentaires devant (^J ou 0x5E et 0x4A). Ceci est une conséquence directe de la fonction signal_host. Lorsque je remplace le caractère par quelque chose d'arbitraire (par exemple, x), c'est ce qui sort de cette position. Il est intéressant de noter que \n est en fait converti à sa notation caret ^J quelque part le long de la route. Il semble que cela se produise dans la communication à la carte, parce que quand je code simplement une chaîne dans le tampon et utilise dma_transmit pour l'envoyer à un programme hôte non-interactif, il est très bien imprimé.

On dirait que j'ai mal configuré DMA dans le sens où il y a du tampon qui n'est pas effacé correctement. En outre, je ne fais pas vraiment confiance à la façon dont le programme côté hôte utilise stty .. Cependant, j'ai effectivement eu une communication de travail sans faille dans le passé, en utilisant ce code exact. Je l'ai comparé au code stocké dans mon histoire de git pendant plusieurs mois, et je ne peux pas trouver la différence/défaut.

Notez que le code ci-dessous utilise libopencm3 et est basé sur des exemples de libopencm3-examples.

Code STM32L1:

#include <libopencm3/stm32/rcc.h> 
#include <libopencm3/stm32/gpio.h> 
#include <libopencm3/stm32/usart.h> 
#include <libopencm3/cm3/nvic.h> 
#include <libopencm3/stm32/dma.h> 

void clock_setup(void) 
{ 
    rcc_clock_setup_pll(&clock_config[CLOCK_VRANGE1_HSI_PLL_32MHZ]); 
    rcc_periph_clock_enable(RCC_GPIOA); 
    rcc_periph_clock_enable(RCC_USART2); 
    rcc_periph_clock_enable(RCC_DMA1); 
} 

void gpio_setup(void) 
{ 
    gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO2 | GPIO3); 
    gpio_set_af(GPIOA, GPIO_AF7, GPIO2 | GPIO3); 
} 

void usart_setup(int baud) 
{ 
    usart_set_baudrate(USART2, baud); 
    usart_set_databits(USART2, 8); 
    usart_set_stopbits(USART2, USART_STOPBITS_1); 
    usart_set_mode(USART2, USART_MODE_TX_RX); 
    usart_set_parity(USART2, USART_PARITY_NONE); 
    usart_set_flow_control(USART2, USART_FLOWCONTROL_NONE); 

    usart_enable(USART2); 
} 

void dma_request_setup(void) 
{ 
    dma_channel_reset(DMA1, DMA_CHANNEL6); 

    nvic_enable_irq(NVIC_DMA1_CHANNEL6_IRQ); 

    dma_set_peripheral_address(DMA1, DMA_CHANNEL6, (uint32_t) &USART2_DR); 
    dma_set_read_from_peripheral(DMA1, DMA_CHANNEL6); 

    dma_set_peripheral_size(DMA1, DMA_CHANNEL6, DMA_CCR_PSIZE_8BIT); 
    dma_set_memory_size(DMA1, DMA_CHANNEL6, DMA_CCR_MSIZE_8BIT); 

    dma_set_priority(DMA1, DMA_CHANNEL6, DMA_CCR_PL_VERY_HIGH); 

    dma_disable_peripheral_increment_mode(DMA1, DMA_CHANNEL6); 
    dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL6); 

    dma_disable_transfer_error_interrupt(DMA1, DMA_CHANNEL6); 
    dma_disable_half_transfer_interrupt(DMA1, DMA_CHANNEL6); 
    dma_enable_transfer_complete_interrupt(DMA1, DMA_CHANNEL6); 
} 

void dma_transmit_setup(void) 
{ 
    dma_channel_reset(DMA1, DMA_CHANNEL7); 

    nvic_enable_irq(NVIC_DMA1_CHANNEL7_IRQ); 

    dma_set_peripheral_address(DMA1, DMA_CHANNEL7, (uint32_t) &USART2_DR); 
    dma_set_read_from_memory(DMA1, DMA_CHANNEL7); 

    dma_set_peripheral_size(DMA1, DMA_CHANNEL7, DMA_CCR_PSIZE_8BIT); 
    dma_set_memory_size(DMA1, DMA_CHANNEL7, DMA_CCR_MSIZE_8BIT); 

    dma_set_priority(DMA1, DMA_CHANNEL7, DMA_CCR_PL_VERY_HIGH); 

    dma_disable_peripheral_increment_mode(DMA1, DMA_CHANNEL7); 
    dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL7); 

    dma_disable_transfer_error_interrupt(DMA1, DMA_CHANNEL7); 
    dma_disable_half_transfer_interrupt(DMA1, DMA_CHANNEL7); 
    dma_enable_transfer_complete_interrupt(DMA1, DMA_CHANNEL7); 
} 

void dma_request(void* buffer, const int datasize) 
{ 
    dma_set_memory_address(DMA1, DMA_CHANNEL6, (uint32_t) buffer); 
    dma_set_number_of_data(DMA1, DMA_CHANNEL6, datasize); 

    dma_enable_channel(DMA1, DMA_CHANNEL6); 
    signal_host(); 
    usart_enable_rx_dma(USART2); 
} 

void dma_transmit(const void* buffer, const int datasize) 
{ 
    dma_set_memory_address(DMA1, DMA_CHANNEL7, (uint32_t) buffer); 
    dma_set_number_of_data(DMA1, DMA_CHANNEL7, datasize); 

    dma_enable_channel(DMA1, DMA_CHANNEL7); 
    usart_enable_tx_dma(USART2); 
} 

int dma_done(void) 
{ 
    return !((DMA1_CCR6 | DMA1_CCR7) & 1); 
} 

void dma1_channel6_isr(void) { 
    usart_disable_rx_dma(USART2); 
    dma_clear_interrupt_flags(DMA1, DMA_CHANNEL6, DMA_TCIF); 
    dma_disable_channel(DMA1, DMA_CHANNEL6); 
} 

void dma1_channel7_isr(void) { 
    usart_disable_tx_dma(USART2); 
    dma_clear_interrupt_flags(DMA1, DMA_CHANNEL7, DMA_TCIF); 
    dma_disable_channel(DMA1, DMA_CHANNEL7); 
} 

void signal_host(void) { 
    usart_send_blocking(USART2, '\n'); 
} 

int main(void) 
{ 
    clock_setup(); 
    gpio_setup(); 
    usart_setup(921600); 
    dma_transmit_setup(); 
    dma_request_setup(); 

    unsigned char buf[16]; 

    dma_request(buf, 16); while (!dma_done()); 

    buf[10] = 'd'; 
    buf[11] = 'a'; 
    buf[12] = 'w'; 
    buf[13] = 'n'; 

    dma_transmit(buf, 16); while (!dma_done()); 

    while(1); 

    return 0; 
} 

STM32F4 Code:

#include <libopencm3/stm32/rcc.h> 
#include <libopencm3/stm32/gpio.h> 
#include <libopencm3/stm32/usart.h> 
#include <libopencm3/cm3/nvic.h> 
#include <libopencm3/stm32/dma.h> 

void clock_setup(void) 
{ 
    rcc_clock_setup_hse_3v3(&hse_8mhz_3v3[CLOCK_3V3_168MHZ]); 
    rcc_periph_clock_enable(RCC_GPIOA); 
    rcc_periph_clock_enable(RCC_USART2); 
    rcc_periph_clock_enable(RCC_DMA1); 
} 

void gpio_setup(void) 
{ 
    gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO2 | GPIO3); 
    gpio_set_af(GPIOA, GPIO_AF7, GPIO2 | GPIO3); 
} 

void usart_setup(int baud) 
{ 
    usart_set_baudrate(USART2, baud); 
    usart_set_databits(USART2, 8); 
    usart_set_stopbits(USART2, USART_STOPBITS_1); 
    usart_set_mode(USART2, USART_MODE_TX_RX); 
    usart_set_parity(USART2, USART_PARITY_NONE); 
    usart_set_flow_control(USART2, USART_FLOWCONTROL_NONE); 

    usart_enable(USART2); 
} 

void dma_request_setup(void) 
{ 
    dma_stream_reset(DMA1, DMA_STREAM5); 

    nvic_enable_irq(NVIC_DMA1_STREAM5_IRQ); 

    dma_set_peripheral_address(DMA1, DMA_STREAM5, (uint32_t) &USART2_DR); 
    dma_set_transfer_mode(DMA1, DMA_STREAM5, DMA_SxCR_DIR_PERIPHERAL_TO_MEM); 

    dma_set_peripheral_size(DMA1, DMA_STREAM5, DMA_SxCR_PSIZE_8BIT); 
    dma_set_memory_size(DMA1, DMA_STREAM5, DMA_SxCR_MSIZE_8BIT); 

    dma_set_priority(DMA1, DMA_STREAM5, DMA_SxCR_PL_VERY_HIGH); 

    dma_disable_peripheral_increment_mode(DMA1, DMA_SxCR_CHSEL_4); 
    dma_enable_memory_increment_mode(DMA1, DMA_STREAM5); 

    dma_disable_transfer_error_interrupt(DMA1, DMA_STREAM5); 
    dma_disable_half_transfer_interrupt(DMA1, DMA_STREAM5); 
    dma_disable_direct_mode_error_interrupt(DMA1, DMA_STREAM5); 
    dma_disable_fifo_error_interrupt(DMA1, DMA_STREAM5); 
    dma_enable_transfer_complete_interrupt(DMA1, DMA_STREAM5); 
} 

void dma_transmit_setup(void) 
{ 
    dma_stream_reset(DMA1, DMA_STREAM6); 

    nvic_enable_irq(NVIC_DMA1_STREAM6_IRQ); 

    dma_set_peripheral_address(DMA1, DMA_STREAM6, (uint32_t) &USART2_DR); 
    dma_set_transfer_mode(DMA1, DMA_STREAM6, DMA_SxCR_DIR_MEM_TO_PERIPHERAL); 

    dma_set_peripheral_size(DMA1, DMA_STREAM6, DMA_SxCR_PSIZE_8BIT); 
    dma_set_memory_size(DMA1, DMA_STREAM6, DMA_SxCR_MSIZE_8BIT); 

    dma_set_priority(DMA1, DMA_STREAM6, DMA_SxCR_PL_VERY_HIGH); 

    dma_disable_peripheral_increment_mode(DMA1, DMA_SxCR_CHSEL_4); 
    dma_enable_memory_increment_mode(DMA1, DMA_STREAM6); 

    dma_disable_transfer_error_interrupt(DMA1, DMA_STREAM6); 
    dma_disable_half_transfer_interrupt(DMA1, DMA_STREAM6); 
    dma_disable_direct_mode_error_interrupt(DMA1, DMA_STREAM6); 
    dma_disable_fifo_error_interrupt(DMA1, DMA_STREAM6); 
    dma_enable_transfer_complete_interrupt(DMA1, DMA_STREAM6); 
} 

void dma_request(void* buffer, const int datasize) 
{ 
    dma_set_memory_address(DMA1, DMA_STREAM5, (uint32_t) buffer); 
    dma_set_number_of_data(DMA1, DMA_STREAM5, datasize); 

    dma_channel_select(DMA1, DMA_STREAM5, DMA_SxCR_CHSEL_4); 
    dma_enable_stream(DMA1, DMA_STREAM5); 
    signal_host(); 
    usart_enable_rx_dma(USART2); 
} 

void dma_transmit(const void* buffer, const int datasize) 
{ 
    dma_set_memory_address(DMA1, DMA_STREAM6, (uint32_t) buffer); 
    dma_set_number_of_data(DMA1, DMA_STREAM6, datasize); 

    dma_channel_select(DMA1, DMA_STREAM6, DMA_SxCR_CHSEL_4); 
    dma_enable_stream(DMA1, DMA_STREAM6); 
    usart_enable_tx_dma(USART2); 
} 

int dma_done(void) 
{ 
    return !((DMA1_S5CR | DMA1_S6CR) & 1); 
} 

void dma1_stream5_isr(void) { 
    usart_disable_rx_dma(USART2); 
    dma_clear_interrupt_flags(DMA1, DMA_STREAM5, DMA_TCIF); 
    dma_disable_stream(DMA1, DMA_STREAM5); 
} 

void dma1_stream6_isr(void) { 
    usart_disable_tx_dma(USART2); 
    dma_clear_interrupt_flags(DMA1, DMA_STREAM6, DMA_TCIF); 
    dma_disable_stream(DMA1, DMA_STREAM6); 
} 

void signal_host(void) { 
    usart_send_blocking(USART2, '\n'); 
} 

int main(void) 
{ 
    clock_setup(); 
    gpio_setup(); 
    usart_setup(921600); 
    dma_transmit_setup(); 
    dma_request_setup(); 

    unsigned char buf[16]; 

    dma_request(buf, 16); while (!dma_done()); 

    buf[10] = 'd'; 
    buf[11] = 'a'; 
    buf[12] = 'w'; 
    buf[13] = 'n'; 

    dma_transmit(buf, 16); while (!dma_done()); 

    while(1); 

    return 0; 
} 
+0

TL; DR! Utilisez un débogueur! Ne ** pas ** utiliser le STLib merdique, mais allez matériel.C'est en fait plus facile et pas encore moins portable - quoi que prétende ST-Marketing. – Olaf

+0

Que voulez-vous dire par 'allez matériel'? Passer la couche d'abstraction libopencm3, ou même plus profond? – Joost

+0

Mise à jour: Ok, vous ne devez pas utiliser le STlib, mais un autre. Cela a l'air encore trop gonflé. Je suis à ma revendication: il suffit d'écrire directement dans les registres matériels et d'écrire des drivers/abstractions de plus haut niveau. Il n'y a aucun sens à l'abstraction à ce bas niveau. – Olaf

Répondre

1

Eh bien, je peux être bref sur celui-ci.

Je déconseille d'utiliser stty pour ce genre de chose. Je me rends compte que je n'ai probablement pas configuré stty correctement, et avec un peu de réglage de l'option, il est probablement possible de bien faire les choses, mais c'est complètement flou. J'ai fini par le jeter par la fenêtre et en utilisant pyserial à la place. J'aurais dû faire ça il y a des semaines. Le code STM32 ci-dessus fonctionne bien et le code Python requis est complètement trivial.

#!/usr/bin/env python3 
import serial 

dev = serial.Serial("/dev/ttyUSB0", 921600) 

dev.read(1) # wait for the signal 
dev.write("Defend at noon\r\n".encode('utf-8')) 

while True: 
    x = dev.read() 
    print(x.decode('utf-8'), end='', flush=True)