2015年12月22日火曜日

STM32F1のSPIをDMAで転送

今回は送信だけ、と受信だけ、の処理です。全二重の送受信処理は以下の関数を変形するだけで作れます。

送信は一方的に送りつけるだけなので楽ですが、受信する場合はデータを送信する必要がなくても送信用のDMAを設定する必要があります。何もデータを送る必要が無いのに大容量のバッファを確保して初期化するのも馬鹿らしいので、1バイトの配列に初期値(0xFF)を設定し、MemoryIncをDisableにして送信してやります。

それから転送が終わったら責任をもってDMA関連をDisableにしてやりましょう。さもないと次にSPIで通信を行った時に謎の動作をします(謎というか、ハングアップするだけですが)。




void SPI_DMA_W(const uint8_t*buff, uint16_t len) {
    DMA_InitTypeDef DMA_InitStructure;

    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&SPI1->DR);
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)(buff);
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
    DMA_InitStructure.DMA_BufferSize = len;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

    DMA_DeInit(DMA1_Channel3);
    DMA_Init(DMA1_Channel3, &DMA_InitStructure);
    DMA_Cmd(DMA1_Channel3, ENABLE);

    SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);

    while (DMA_GetCurrDataCounter(DMA1_Channel3));
    while (!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE));
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY));

    DMA_Cmd(DMA1_Channel3, DISABLE);

    SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, DISABLE);
}

void SPI_DMA_R(uint8_t*buff, uint16_t len) {
    DMA_InitTypeDef DMA_InitStructure;
    uint8_t dummy[1] = { 0xFF };


    DMA_DeInit(DMA1_Channel2);
    DMA_DeInit(DMA1_Channel3);


    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&SPI1->DR);
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)(dummy);
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
    DMA_InitStructure.DMA_BufferSize = len;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

    DMA_Init(DMA1_Channel3, &DMA_InitStructure);


    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&SPI1->DR);
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)(buff);
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize = len;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

    DMA_Init(DMA1_Channel2, &DMA_InitStructure);


    DMA_Cmd(DMA1_Channel3, ENABLE);
    DMA_Cmd(DMA1_Channel2, ENABLE);

    SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx, ENABLE);
    SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);

    while (DMA_GetCurrDataCounter(DMA1_Channel2));
    while (!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE));
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY));

    DMA_Cmd(DMA1_Channel2, DISABLE);
    DMA_Cmd(DMA1_Channel3, DISABLE);

    SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx, DISABLE);
    SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, DISABLE);
}

0 件のコメント:

コメントを投稿