Вот мой код:
auto port::transceiver(uint8_t* tdata, uint8_t* rdata, uint16_t len) -> error_t
{
// 0 - DMA должен быть выключен, это является признаком завершения предыдущей операции
if ((tdata == nullptr)||(rdata == nullptr)) return error_t::parameter;
if (len == 0) return error_t::parameter;
if (RDMA->CR & DMA_SxCR_EN) return error_t::busy;
if (TDMA->CR & DMA_SxCR_EN) return error_t::busy;
// 1 - Настраиваем CS
// Управление CS внешнее
// 1 - Настраиваем SPI
SPI->CR2 &= ~(SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN);
SPI->CR1 |= SPI_CR1_SPE;
// 2 - Настраиваем DMA-приёмник
mcu::dma::transaction(RDMA, mcu::dma::direction::PtoM, (uint32_t)&(SPI->DR), (uint32_t)rdata, len);
SPI->CR2 |= SPI_CR2_RXDMAEN;
// 3 - Настраиваем DMA-передатчик
mcu::dma::transaction(TDMA, mcu::dma::direction::MtoP, (uint32_t)tdata, (uint32_t)&(SPI->DR), len);
// 4 - Запуск передачи
SPI->CR2 |= SPI_CR2_TXDMAEN;
return error_t::ok;
}
void dma::transaction(DMA_Stream_TypeDef* DMA, direction dir, uint32_t src, uint32_t dest, uint16_t len)
{
// 0 - Проверка указателей и длины посылки
if ((src == 0)||(dest == 0)||(len == 0)) return;
// 1 - Задаём длину сообщения
// (Запись 0 в данный регистр ложит DMA!!!)
DMA->NDTR = len;
// 2 - Устанавливаем адреса
switch(dir)
{
case direction::PtoM:
case direction::MtoM:
DMA->PAR = src;
DMA->M0AR = dest;
break;
case direction::MtoP:
DMA->PAR = dest;
DMA->M0AR = src;
break;
}
// 3 - Запуск процесса передачи
DMA->CR |= DMA_SxCR_EN;
return;
}