3

私はしばらくの間、コンピューターからSTM32L100C-DISCOオーバー USART にデータのブロックを送信しようとしてきました。パフォーマンス上の理由から、これは DMA を使用して行われます。しかし、これまでのところ、私はそれを機能させることができませんでした。何が間違っているのかわからないので、ここで質問したいと思います。

私はlibopencm3を使用していますが、残念ながら、それ以外の優れた例のリポジトリにはSTM32L1xxx. ただし、一般的な DMA ヘッダー ファイルで使用可能な構成オプションに関しては、すべての基本をカバーしていることを確認しました。

当然のことながら、STM32L1xxx のリファレンス マニュアルを参照したところ、次の DMA1 の要求テーブルが記載されているため、使用する必要があるのはチャネル 6 であると確信しました。

DMA 要求テーブル

メモリと周辺機器 (つまり USART2) のサイズがよくわからなかったので、8 ビット、16 ビット、32 ビットのすべての組み合わせを変更しましたが、役に立ちませんでした。

難しい話は抜きにして; これは、私がやろうとしていることの最小限の動作 (まあ、動作していません..) の抜粋です。USART 自体は正常に動作するため、DMA 構成で何かを見落としているように感じます。

この時点で、何でも感謝されます。

このコードの背後にある考え方は、基本的に、バッファ内のデータが完全に置き換えられるまで永久にループし、置き換えられたら出力するというものです。ホストから、非常に認識しやすい 1 キロバイトのデータを送信していますが、返ってきたのは不正な形式のゴミだけです。それ何かを書いていますが、私が書こうとしているものではありません。

編集:これはメモリマップの写真です。USART2_BASEと評価される0x4000 4400ので、それも問題ないようです。

メモリマップ

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

const int buflength = 1024;

uint8_t buffer[1024];

static void clock_setup(void)
{
    rcc_clock_setup_pll(&clock_config[CLOCK_VRANGE1_HSI_PLL_32MHZ]);
    rcc_peripheral_enable_clock(&RCC_AHBENR, RCC_AHBENR_GPIOAEN);
    rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_USART2EN);
    rcc_periph_clock_enable(RCC_DMA1);

}

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

static void usart_setup(void)
{
    usart_set_baudrate(USART2, 115200);
    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);
}

static void dma_setup(void)
{
    dma_channel_reset(DMA1, DMA_CHANNEL6);
    dma_set_priority(DMA1, DMA_CHANNEL6, DMA_CCR_PL_VERY_HIGH);
    dma_set_memory_size(DMA1, DMA_CHANNEL6, DMA_CCR_MSIZE_8BIT);
    dma_set_peripheral_size(DMA1, DMA_CHANNEL6, DMA_CCR_PSIZE_8BIT);
    dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL6);
    dma_disable_peripheral_increment_mode(DMA1, DMA_CHANNEL6);
    dma_enable_circular_mode(DMA1, DMA_CHANNEL6);
    dma_set_read_from_peripheral(DMA1, DMA_CHANNEL6);

    dma_disable_transfer_error_interrupt(DMA1, DMA_CHANNEL6);
    dma_disable_half_transfer_interrupt(DMA1, DMA_CHANNEL6);
    dma_disable_transfer_complete_interrupt(DMA1, DMA_CHANNEL6);

    dma_set_peripheral_address(DMA1, DMA_CHANNEL6, (uint32_t) USART2_BASE);
    dma_set_memory_address(DMA1, DMA_CHANNEL6, (uint32_t) buffer);
    dma_set_number_of_data(DMA1, DMA_CHANNEL6, buflength);

    dma_enable_channel(DMA1, DMA_CHANNEL6);
}

int main(void)
{
    int i;
    for (i = 0; i < buflength; i++) {
        buffer[i] = 65;
    }
    clock_setup();
    gpio_setup();
    usart_setup();
    dma_setup();

    usart_enable_rx_dma(USART2);
    char flag = 1;
    while (flag) {
        flag = 0;
        for (i = 0; i < buflength; i++) {
            if (buffer[i] == 65) {
                flag = 1;
            }
        }
    }
    usart_disable_rx_dma(USART2);

    for (i = 0; i < buflength; i++) {
        usart_send_blocking(USART2, buffer[i]);
    }
    usart_send_blocking(USART2, '\n');

    return 0;
}
4

2 に答える 2

1

最後に、これは私がそれを機能させるために使用した構成です。

const int datasize = 32;

char buffer[32];

static void dma_setup(void)
{
    dma_channel_reset(DMA1, DMA_CHANNEL6);

    nvic_enable_irq(NVIC_DMA1_CHANNEL6_IRQ);

    // USART2_DR (not USART2_BASE) is where the data will be received
    dma_set_peripheral_address(DMA1, DMA_CHANNEL6, (uint32_t) &USART2_DR);
    dma_set_read_from_peripheral(DMA1, DMA_CHANNEL6);

    // should be 8 bit for USART2 as well as for the STM32L1
    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);

    // should be disabled for USART2, but varies for other peripherals
    dma_disable_peripheral_increment_mode(DMA1, DMA_CHANNEL6);
    // should be enabled, otherwise buffer[0] is overwritten
    dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL6);

    dma_set_memory_address(DMA1, DMA_CHANNEL6, (uint32_t) &buffer);
    dma_set_number_of_data(DMA1, DMA_CHANNEL6, datasize);

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

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

次に、転送が完了すると、dma1_channel6_isr関数のオーバーライドが呼び出され、すべてのデータがbuffer.

libopencm3-example リポジトリへのプル リクエストとして、完全に機能するコードを送信しました。ここで見つけることができます。コードがマージされたら、必ずリンクを更新します。

于 2015-07-08T07:45:08.220 に答える