Commit 3d30d605 authored by Damien George's avatar Damien George
Browse files

stmhal: Factor out DMA initialisation code from spi.c.

This is so that the DMA can be shared by multiple peripherals.
parent 7ed58cb6
...@@ -116,6 +116,7 @@ SRC_C = \ ...@@ -116,6 +116,7 @@ SRC_C = \
pin_defs_stmhal.c \ pin_defs_stmhal.c \
pin_named_pins.c \ pin_named_pins.c \
bufhelper.c \ bufhelper.c \
dma.c \
i2c.c \ i2c.c \
spi.c \ spi.c \
uart.c \ uart.c \
......
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2015 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stm32f4xx_hal.h>
#include "dma.h"
#define NSTREAM (16)
static const uint8_t dma_irqn[NSTREAM] = {
DMA1_Stream0_IRQn,
DMA1_Stream1_IRQn,
DMA1_Stream2_IRQn,
DMA1_Stream3_IRQn,
DMA1_Stream4_IRQn,
DMA1_Stream5_IRQn,
DMA1_Stream6_IRQn,
DMA1_Stream7_IRQn,
DMA2_Stream0_IRQn,
DMA2_Stream1_IRQn,
DMA2_Stream2_IRQn,
DMA2_Stream3_IRQn,
DMA2_Stream4_IRQn,
DMA2_Stream5_IRQn,
DMA2_Stream6_IRQn,
DMA2_Stream7_IRQn,
};
static DMA_HandleTypeDef *dma_handle[NSTREAM] = {NULL};
static uint32_t dma_last_channel[NSTREAM];
void DMA1_Stream0_IRQHandler(void) { if (dma_handle[0] != NULL) { HAL_DMA_IRQHandler(dma_handle[0]); } }
void DMA1_Stream1_IRQHandler(void) { if (dma_handle[1] != NULL) { HAL_DMA_IRQHandler(dma_handle[1]); } }
void DMA1_Stream2_IRQHandler(void) { if (dma_handle[2] != NULL) { HAL_DMA_IRQHandler(dma_handle[2]); } }
void DMA1_Stream3_IRQHandler(void) { if (dma_handle[3] != NULL) { HAL_DMA_IRQHandler(dma_handle[3]); } }
void DMA1_Stream4_IRQHandler(void) { if (dma_handle[4] != NULL) { HAL_DMA_IRQHandler(dma_handle[4]); } }
void DMA1_Stream5_IRQHandler(void) { if (dma_handle[5] != NULL) { HAL_DMA_IRQHandler(dma_handle[5]); } }
void DMA1_Stream6_IRQHandler(void) { if (dma_handle[6] != NULL) { HAL_DMA_IRQHandler(dma_handle[6]); } }
void DMA1_Stream7_IRQHandler(void) { if (dma_handle[7] != NULL) { HAL_DMA_IRQHandler(dma_handle[7]); } }
void DMA2_Stream0_IRQHandler(void) { if (dma_handle[8] != NULL) { HAL_DMA_IRQHandler(dma_handle[8]); } }
void DMA2_Stream1_IRQHandler(void) { if (dma_handle[9] != NULL) { HAL_DMA_IRQHandler(dma_handle[9]); } }
void DMA2_Stream2_IRQHandler(void) { if (dma_handle[10] != NULL) { HAL_DMA_IRQHandler(dma_handle[10]); } }
void DMA2_Stream3_IRQHandler(void) { if (dma_handle[11] != NULL) { HAL_DMA_IRQHandler(dma_handle[11]); } }
void DMA2_Stream4_IRQHandler(void) { if (dma_handle[12] != NULL) { HAL_DMA_IRQHandler(dma_handle[12]); } }
void DMA2_Stream5_IRQHandler(void) { if (dma_handle[13] != NULL) { HAL_DMA_IRQHandler(dma_handle[13]); } }
void DMA2_Stream6_IRQHandler(void) { if (dma_handle[14] != NULL) { HAL_DMA_IRQHandler(dma_handle[14]); } }
void DMA2_Stream7_IRQHandler(void) { if (dma_handle[15] != NULL) { HAL_DMA_IRQHandler(dma_handle[15]); } }
static int get_dma_id(DMA_Stream_TypeDef *dma_stream) {
if ((uint32_t)dma_stream < DMA2_BASE) {
return ((uint32_t)dma_stream - DMA1_Stream0_BASE) / 0x18;
} else {
return (NSTREAM / 2) + ((uint32_t)dma_stream - DMA2_Stream0_BASE) / 0x18;
}
}
void dma_init(DMA_HandleTypeDef *dma, DMA_Stream_TypeDef *dma_stream, uint32_t dma_channel, uint32_t direction, void *data) {
int dma_id = get_dma_id(dma_stream);
//printf("dma_init(%p, %p(%d), 0x%x, 0x%x, %p)\n", dma, dma_stream, dma_id, (uint)dma_channel, (uint)direction, data);
// TODO possibly don't need to clear the entire structure
memset(dma, 0, sizeof(*dma));
// set global pointer for IRQ handler
dma_handle[dma_id] = dma;
// initialise critical parameters
dma->Instance = dma_stream;
dma->Init.Direction = direction;
// half of __HAL_LINKDMA(data, xxx, *dma)
// caller must implement other half by doing: data->xxx = dma
dma->Parent = data;
// if this stream was previously configured for this channel then we
// can skip most of the initialisation
if (dma_last_channel[dma_id] == dma_channel) {
goto same_channel;
}
dma_last_channel[dma_id] = dma_channel;
// set DMA parameters (these are only used by HAL_DMA_Init)
dma->Init.Channel = dma_channel;
dma->Init.PeriphInc = DMA_PINC_DISABLE;
dma->Init.MemInc = DMA_MINC_ENABLE;
dma->Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
dma->Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
dma->Init.Mode = DMA_NORMAL;
dma->Init.Priority = DMA_PRIORITY_LOW;
dma->Init.FIFOMode = DMA_FIFOMODE_DISABLE;
dma->Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
dma->Init.MemBurst = DMA_MBURST_INC4;
dma->Init.PeriphBurst = DMA_PBURST_INC4;
// enable clock for needed DMA peripheral
if (dma_id <= 7) {
__DMA1_CLK_ENABLE();
} else {
__DMA2_CLK_ENABLE();
}
// reset and configure DMA peripheral
HAL_DMA_DeInit(dma);
HAL_DMA_Init(dma);
HAL_NVIC_SetPriority(dma_irqn[dma_id], 6, 0);
same_channel:
HAL_NVIC_EnableIRQ(dma_irqn[dma_id]);
}
void dma_deinit(DMA_HandleTypeDef *dma) {
int dma_id = get_dma_id(dma->Instance);
HAL_NVIC_DisableIRQ(dma_irqn[dma_id]);
dma_handle[dma_id] = NULL;
}
void dma_invalidate_channel(DMA_Stream_TypeDef *dma_stream, uint32_t dma_channel) {
int dma_id = get_dma_id(dma_stream);
if (dma_last_channel[dma_id] == dma_channel) {
dma_last_channel[dma_id] = 0xffffffff;
}
}
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2015 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
void dma_init(DMA_HandleTypeDef *dma, DMA_Stream_TypeDef *dma_stream, uint32_t dma_channel, uint32_t direction, void *data);
void dma_deinit(DMA_HandleTypeDef *dma);
void dma_invalidate_channel(DMA_Stream_TypeDef *dma_stream, uint32_t dma_channel);
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "pin.h" #include "pin.h"
#include "genhdr/pins.h" #include "genhdr/pins.h"
#include "bufhelper.h" #include "bufhelper.h"
#include "dma.h"
#include "spi.h" #include "spi.h"
#include MICROPY_HAL_H #include MICROPY_HAL_H
...@@ -60,6 +61,23 @@ ...@@ -60,6 +61,23 @@
/// spi.send_recv(b'1234', buf) # send 4 bytes and receive 4 into buf /// spi.send_recv(b'1234', buf) # send 4 bytes and receive 4 into buf
/// spi.send_recv(buf, buf) # send/recv 4 bytes from/to buf /// spi.send_recv(buf, buf) # send/recv 4 bytes from/to buf
// Possible DMA configurations for SPI busses:
// SPI1_TX: DMA2_Stream3.CHANNEL_3 or DMA2_Stream5.CHANNEL_3
// SPI1_RX: DMA2_Stream0.CHANNEL_3 or DMA2_Stream2.CHANNEL_3
// SPI2_TX: DMA1_Stream4.CHANNEL_0
// SPI2_RX: DMA1_Stream3.CHANNEL_0
// SPI3_TX: DMA1_Stream5.CHANNEL_0 or DMA1_Stream7.CHANNEL_0
// SPI3_RX: DMA1_Stream0.CHANNEL_0 or DMA1_Stream2.CHANNEL_0
typedef struct _pyb_spi_obj_t {
mp_obj_base_t base;
SPI_HandleTypeDef *spi;
DMA_Stream_TypeDef *tx_dma_stream;
uint32_t tx_dma_channel;
DMA_Stream_TypeDef *rx_dma_stream;
uint32_t rx_dma_channel;
} pyb_spi_obj_t;
#if MICROPY_HW_ENABLE_SPI1 #if MICROPY_HW_ENABLE_SPI1
SPI_HandleTypeDef SPIHandle1 = {.Instance = NULL}; SPI_HandleTypeDef SPIHandle1 = {.Instance = NULL};
#endif #endif
...@@ -70,61 +88,23 @@ SPI_HandleTypeDef SPIHandle2 = {.Instance = NULL}; ...@@ -70,61 +88,23 @@ SPI_HandleTypeDef SPIHandle2 = {.Instance = NULL};
SPI_HandleTypeDef SPIHandle3 = {.Instance = NULL}; SPI_HandleTypeDef SPIHandle3 = {.Instance = NULL};
#endif #endif
// Possible DMA configurations for SPI busses: STATIC const pyb_spi_obj_t pyb_spi_obj[] = {
// SPI1_RX: DMA2_Stream0.CHANNEL_3 or DMA2_Stream2.CHANNEL_3
// SPI1_TX: DMA2_Stream3.CHANNEL_3 or DMA2_Stream5.CHANNEL_3
// SPI2_RX: DMA1_Stream3.CHANNEL_0
// SPI2_TX: DMA1_Stream4.CHANNEL_0
// SPI3_RX: DMA1_Stream0.CHANNEL_0 or DMA1_Stream2.CHANNEL_0
// SPI3_TX: DMA1_Stream5.CHANNEL_0 or DMA1_Stream7.CHANNEL_0
#define SPI1_DMA_CLK_ENABLE __DMA2_CLK_ENABLE
#define SPI1_RX_DMA_STREAM (DMA2_Stream2)
#define SPI1_TX_DMA_STREAM (DMA2_Stream5)
#define SPI1_DMA_CHANNEL (DMA_CHANNEL_3)
#define SPI1_RX_DMA_IRQN (DMA2_Stream2_IRQn)
#define SPI1_TX_DMA_IRQN (DMA2_Stream5_IRQn)
#define SPI1_RX_DMA_IRQ_HANDLER DMA2_Stream2_IRQHandler
#define SPI1_TX_DMA_IRQ_HANDLER DMA2_Stream5_IRQHandler
#define SPI2_DMA_CLK_ENABLE __DMA1_CLK_ENABLE
#define SPI2_RX_DMA_STREAM (DMA1_Stream3)
#define SPI2_TX_DMA_STREAM (DMA1_Stream4)
#define SPI2_DMA_CHANNEL (DMA_CHANNEL_0)
#define SPI2_RX_DMA_IRQN (DMA1_Stream3_IRQn)
#define SPI2_TX_DMA_IRQN (DMA1_Stream4_IRQn)
#define SPI2_RX_DMA_IRQ_HANDLER DMA1_Stream3_IRQHandler
#define SPI2_TX_DMA_IRQ_HANDLER DMA1_Stream4_IRQHandler
#define SPI3_DMA_CLK_ENABLE __DMA1_CLK_ENABLE
#define SPI3_RX_DMA_STREAM (DMA1_Stream2)
#define SPI3_TX_DMA_STREAM (DMA1_Stream7)
#define SPI3_DMA_CHANNEL (DMA_CHANNEL_0)
#define SPI3_RX_DMA_IRQN (DMA1_Stream2_IRQn)
#define SPI3_TX_DMA_IRQN (DMA1_Stream7_IRQn)
#define SPI3_RX_DMA_IRQ_HANDLER DMA1_Stream2_IRQHandler
#define SPI3_TX_DMA_IRQ_HANDLER DMA1_Stream7_IRQHandler
#if MICROPY_HW_ENABLE_SPI1 #if MICROPY_HW_ENABLE_SPI1
STATIC DMA_HandleTypeDef spi1_rx_dma_handle; {{&pyb_spi_type}, &SPIHandle1, DMA2_Stream5, DMA_CHANNEL_3, DMA2_Stream2, DMA_CHANNEL_3},
STATIC DMA_HandleTypeDef spi1_tx_dma_handle; #else
void SPI1_RX_DMA_IRQ_HANDLER(void) { HAL_DMA_IRQHandler(&spi1_rx_dma_handle); } {{&pyb_spi_type}, NULL, NULL, 0, NULL, 0},
void SPI1_TX_DMA_IRQ_HANDLER(void) { HAL_DMA_IRQHandler(&spi1_tx_dma_handle); }
#endif #endif
#if MICROPY_HW_ENABLE_SPI2 #if MICROPY_HW_ENABLE_SPI2
STATIC DMA_HandleTypeDef spi2_rx_dma_handle; {{&pyb_spi_type}, &SPIHandle2, DMA1_Stream4, DMA_CHANNEL_0, DMA1_Stream3, DMA_CHANNEL_0},
STATIC DMA_HandleTypeDef spi2_tx_dma_handle; #else
void SPI2_RX_DMA_IRQ_HANDLER(void) { HAL_DMA_IRQHandler(&spi2_rx_dma_handle); } {{&pyb_spi_type}, NULL, NULL, 0, NULL, 0},
void SPI2_TX_DMA_IRQ_HANDLER(void) { HAL_DMA_IRQHandler(&spi2_tx_dma_handle); }
#endif #endif
#if MICROPY_HW_ENABLE_SPI3 #if MICROPY_HW_ENABLE_SPI3
STATIC DMA_HandleTypeDef spi3_rx_dma_handle; {{&pyb_spi_type}, &SPIHandle3, DMA1_Stream7, DMA_CHANNEL_0, DMA1_Stream2, DMA_CHANNEL_0},
STATIC DMA_HandleTypeDef spi3_tx_dma_handle; #else
void SPI3_RX_DMA_IRQ_HANDLER(void) { HAL_DMA_IRQHandler(&spi3_rx_dma_handle); } {{&pyb_spi_type}, NULL, NULL, 0, NULL, 0},
void SPI3_TX_DMA_IRQ_HANDLER(void) { HAL_DMA_IRQHandler(&spi3_tx_dma_handle); }
#endif #endif
};
void spi_init0(void) { void spi_init0(void) {
// reset the SPI handles // reset the SPI handles
...@@ -150,14 +130,14 @@ void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) { ...@@ -150,14 +130,14 @@ void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) {
GPIO_InitStructure.Speed = GPIO_SPEED_FAST; GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
GPIO_InitStructure.Pull = spi->Init.CLKPolarity == SPI_POLARITY_LOW ? GPIO_PULLDOWN : GPIO_PULLUP; GPIO_InitStructure.Pull = spi->Init.CLKPolarity == SPI_POLARITY_LOW ? GPIO_PULLDOWN : GPIO_PULLUP;
DMA_HandleTypeDef *rx_dma, *tx_dma; const pyb_spi_obj_t *self;
IRQn_Type rx_dma_irqn, tx_dma_irqn;
const pin_obj_t *pins[4]; const pin_obj_t *pins[4];
if (0) { if (0) {
#if MICROPY_HW_ENABLE_SPI1 #if MICROPY_HW_ENABLE_SPI1
} else if (spi->Instance == SPI1) { } else if (spi->Instance == SPI1) {
// X-skin: X5=PA4=SPI1_NSS, X6=PA5=SPI1_SCK, X7=PA6=SPI1_MISO, X8=PA7=SPI1_MOSI // X-skin: X5=PA4=SPI1_NSS, X6=PA5=SPI1_SCK, X7=PA6=SPI1_MISO, X8=PA7=SPI1_MOSI
self = &pyb_spi_obj[0];
pins[0] = &pin_A4; pins[0] = &pin_A4;
pins[1] = &pin_A5; pins[1] = &pin_A5;
pins[2] = &pin_A6; pins[2] = &pin_A6;
...@@ -165,19 +145,11 @@ void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) { ...@@ -165,19 +145,11 @@ void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) {
GPIO_InitStructure.Alternate = GPIO_AF5_SPI1; GPIO_InitStructure.Alternate = GPIO_AF5_SPI1;
// enable the SPI clock // enable the SPI clock
__SPI1_CLK_ENABLE(); __SPI1_CLK_ENABLE();
// configure DMA
SPI1_DMA_CLK_ENABLE();
spi1_rx_dma_handle.Instance = SPI1_RX_DMA_STREAM;
spi1_rx_dma_handle.Init.Channel = SPI1_DMA_CHANNEL;
spi1_tx_dma_handle.Instance = SPI1_TX_DMA_STREAM;
rx_dma = &spi1_rx_dma_handle;
tx_dma = &spi1_tx_dma_handle;
rx_dma_irqn = SPI1_RX_DMA_IRQN;
tx_dma_irqn = SPI1_TX_DMA_IRQN;
#endif #endif
#if MICROPY_HW_ENABLE_SPI2 #if MICROPY_HW_ENABLE_SPI2
} else if (spi->Instance == SPI2) { } else if (spi->Instance == SPI2) {
// Y-skin: Y5=PB12=SPI2_NSS, Y6=PB13=SPI2_SCK, Y7=PB14=SPI2_MISO, Y8=PB15=SPI2_MOSI // Y-skin: Y5=PB12=SPI2_NSS, Y6=PB13=SPI2_SCK, Y7=PB14=SPI2_MISO, Y8=PB15=SPI2_MOSI
self = &pyb_spi_obj[1];
pins[0] = &pin_B12; pins[0] = &pin_B12;
pins[1] = &pin_B13; pins[1] = &pin_B13;
pins[2] = &pin_B14; pins[2] = &pin_B14;
...@@ -185,18 +157,10 @@ void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) { ...@@ -185,18 +157,10 @@ void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) {
GPIO_InitStructure.Alternate = GPIO_AF5_SPI2; GPIO_InitStructure.Alternate = GPIO_AF5_SPI2;
// enable the SPI clock // enable the SPI clock
__SPI2_CLK_ENABLE(); __SPI2_CLK_ENABLE();
// configure DMA
SPI2_DMA_CLK_ENABLE();
spi2_rx_dma_handle.Instance = SPI2_RX_DMA_STREAM;
spi2_rx_dma_handle.Init.Channel = SPI2_DMA_CHANNEL;
spi2_tx_dma_handle.Instance = SPI2_TX_DMA_STREAM;
rx_dma = &spi2_rx_dma_handle;
tx_dma = &spi2_tx_dma_handle;
rx_dma_irqn = SPI2_RX_DMA_IRQN;
tx_dma_irqn = SPI2_TX_DMA_IRQN;
#endif #endif
#if MICROPY_HW_ENABLE_SPI3 #if MICROPY_HW_ENABLE_SPI3
} else if (spi->Instance == SPI3) { } else if (spi->Instance == SPI3) {
self = &pyb_spi_obj[2];
pins[0] = &pin_A4; pins[0] = &pin_A4;
pins[1] = &pin_B3; pins[1] = &pin_B3;
pins[2] = &pin_B4; pins[2] = &pin_B4;
...@@ -204,15 +168,6 @@ void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) { ...@@ -204,15 +168,6 @@ void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) {
GPIO_InitStructure.Alternate = GPIO_AF6_SPI3; GPIO_InitStructure.Alternate = GPIO_AF6_SPI3;
// enable the SPI clock // enable the SPI clock
__SPI3_CLK_ENABLE(); __SPI3_CLK_ENABLE();
// configure DMA
SPI3_DMA_CLK_ENABLE();
spi3_rx_dma_handle.Instance = SPI3_RX_DMA_STREAM;
spi3_rx_dma_handle.Init.Channel = SPI3_DMA_CHANNEL;
spi3_tx_dma_handle.Instance = SPI3_TX_DMA_STREAM;
rx_dma = &spi3_rx_dma_handle;
tx_dma = &spi3_tx_dma_handle;
rx_dma_irqn = SPI3_RX_DMA_IRQN;
tx_dma_irqn = SPI3_TX_DMA_IRQN;
#endif #endif
} else { } else {
// SPI does not exist for this board (shouldn't get here, should be checked by caller) // SPI does not exist for this board (shouldn't get here, should be checked by caller)
...@@ -233,36 +188,11 @@ void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) { ...@@ -233,36 +188,11 @@ void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) {
return; return;
} }
// configure DMA // After calling HAL_SPI_Init() it seems that the DMA gets disconnected if
// it was previously configured. So we invalidate the DMA channel to force
rx_dma->Init.Direction = DMA_PERIPH_TO_MEMORY; // an initialisation the next time we use it.
rx_dma->Init.PeriphInc = DMA_PINC_DISABLE; dma_invalidate_channel(self->tx_dma_stream, self->tx_dma_channel);
rx_dma->Init.MemInc = DMA_MINC_ENABLE; dma_invalidate_channel(self->rx_dma_stream, self->rx_dma_channel);
rx_dma->Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
rx_dma->Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
rx_dma->Init.Mode = DMA_NORMAL;
rx_dma->Init.Priority = DMA_PRIORITY_LOW;
rx_dma->Init.FIFOMode = DMA_FIFOMODE_DISABLE;
rx_dma->Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
rx_dma->Init.MemBurst = DMA_MBURST_INC4;
rx_dma->Init.PeriphBurst = DMA_PBURST_INC4;
tx_dma->Init = rx_dma->Init; // copy rx settings
tx_dma->Init.Direction = DMA_MEMORY_TO_PERIPH;
__HAL_LINKDMA(spi, hdmarx, *rx_dma);
HAL_DMA_DeInit(rx_dma);
HAL_DMA_Init(rx_dma);
__HAL_LINKDMA(spi, hdmatx, *tx_dma);
HAL_DMA_DeInit(tx_dma);
HAL_DMA_Init(tx_dma);
// Enable the relevant IRQs.
HAL_NVIC_SetPriority(rx_dma_irqn, 6, 0);
HAL_NVIC_EnableIRQ(rx_dma_irqn);
HAL_NVIC_SetPriority(tx_dma_irqn, 6, 0);
HAL_NVIC_EnableIRQ(tx_dma_irqn);
} }
void spi_deinit(SPI_HandleTypeDef *spi) { void spi_deinit(SPI_HandleTypeDef *spi) {
...@@ -305,29 +235,6 @@ STATIC HAL_StatusTypeDef spi_wait_dma_finished(SPI_HandleTypeDef *spi, uint32_t ...@@ -305,29 +235,6 @@ STATIC HAL_StatusTypeDef spi_wait_dma_finished(SPI_HandleTypeDef *spi, uint32_t
/******************************************************************************/ /******************************************************************************/
/* Micro Python bindings */ /* Micro Python bindings */
typedef struct _pyb_spi_obj_t {
mp_obj_base_t base;
SPI_HandleTypeDef *spi;
} pyb_spi_obj_t;
STATIC const pyb_spi_obj_t pyb_spi_obj[] = {
#if MICROPY_HW_ENABLE_SPI1
{{&pyb_spi_type}, &SPIHandle1},
#else
{{&pyb_spi_type}, NULL},
#endif
#if MICROPY_HW_ENABLE_SPI2
{{&pyb_spi_type}, &SPIHandle2},
#else
{{&pyb_spi_type}, NULL},
#endif
#if MICROPY_HW_ENABLE_SPI3
{{&pyb_spi_type}, &SPIHandle3},
#else
{{&pyb_spi_type}, NULL},
#endif
};
SPI_HandleTypeDef *spi_get_handle(mp_obj_t o) { SPI_HandleTypeDef *spi_get_handle(mp_obj_t o) {
if (!MP_OBJ_IS_TYPE(o, &pyb_spi_type)) { if (!MP_OBJ_IS_TYPE(o, &pyb_spi_type)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "expecting an SPI object")); nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "expecting an SPI object"));
...@@ -550,10 +457,15 @@ STATIC mp_obj_t pyb_spi_send(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_ ...@@ -550,10 +457,15 @@ STATIC mp_obj_t pyb_spi_send(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_
if (query_irq() == IRQ_STATE_DISABLED) { if (query_irq() == IRQ_STATE_DISABLED) {
status = HAL_SPI_Transmit(self->spi, bufinfo.buf, bufinfo.len, args[1].u_int); status = HAL_SPI_Transmit(self->spi, bufinfo.buf, bufinfo.len, args[1].u_int);
} else { } else {
DMA_HandleTypeDef tx_dma;
dma_init(&tx_dma, self->tx_dma_stream, self->tx_dma_channel, DMA_MEMORY_TO_PERIPH, self->spi);
self->spi->hdmatx = &tx_dma;
self->spi->hdmarx = NULL;
status = HAL_SPI_Transmit_DMA(self->spi, bufinfo.buf, bufinfo.len); status = HAL_SPI_Transmit_DMA(self->spi, bufinfo.buf, bufinfo.len);
if (status == HAL_OK) { if (status == HAL_OK) {
status = spi_wait_dma_finished(self->spi, args[1].u_int); status = spi_wait_dma_finished(self->spi, args[1].u_int);
} }
dma_deinit(&tx_dma);
} }
if (status != HAL_OK) { if (status != HAL_OK) {
...@@ -596,10 +508,23 @@ STATIC mp_obj_t pyb_spi_recv(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_ ...@@ -596,10 +508,23 @@ STATIC mp_obj_t pyb_spi_recv(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_
if (query_irq() == IRQ_STATE_DISABLED) { if (query_irq() == IRQ_STATE_DISABLED) {
status = HAL_SPI_Receive(self->spi, (uint8_t*)vstr.buf, vstr.len, args[1].u_int); status = HAL_SPI_Receive(self->spi, (uint8_t*)vstr.buf, vstr.len, args[1].u_int);
} else { } else {
DMA_HandleTypeDef tx_dma, rx_dma;
if (self->spi->Init.Mode == SPI_MODE_MASTER) {
// in master mode the HAL actually does a TransmitReceive call
dma_init(&tx_dma, self->tx_dma_stream, self->tx_dma_channel, DMA_MEMORY_TO_PERIPH, self->spi);
self->spi->hdmatx = &tx_dma;
} else {
self->spi->hdmatx = NULL;
}
dma_init(&rx_dma, self->rx_dma_stream, self->rx_dma_channel, DMA_PERIPH_TO_MEMORY, self->spi);
self->spi->hdmarx = &rx_dma;
status = HAL_SPI_Receive_DMA(self->spi, (uint8_t*)vstr.buf, vstr.len); status = HAL_SPI_Receive_DMA(self->spi, (uint8_t*)vstr.buf, vstr.len);
if (status == HAL_OK) { if (status == HAL_OK) {
status = spi_wait_dma_finished(self->spi, args[1].u_int); status = spi_wait_dma_finished(self->spi, args[1].u_int);
} }
dma_deinit(&tx_dma);
dma_deinit(&rx_dma);
} }
if (status != HAL_OK) { if (status != HAL_OK) {
...@@ -678,10 +603,17 @@ STATIC mp_obj_t pyb_spi_send_recv(mp_uint_t n_args, const mp_obj_t *pos_args, mp ...@@ -678,10 +603,17 @@ STATIC mp_obj_t pyb_spi_send_recv(mp_uint_t n_args, const mp_obj_t *pos_args, mp
if (query_irq() == IRQ_STATE_DISABLED) { if (query_irq() == IRQ_STATE_DISABLED) {
status = HAL_SPI_TransmitReceive(self->spi, bufinfo_send.buf, bufinfo_recv.buf, bufinfo_send.len, args[2].u_int); status = HAL_SPI_TransmitReceive(self->spi, bufinfo_send.buf, bufinfo_recv.buf, bufinfo_send.len, args[2].u_int);
} else { } else {
DMA_HandleTypeDef tx_dma, rx_dma;
dma_init(&tx_dma, self->tx_dma_stream, self->tx_dma_channel, DMA_MEMORY_TO_PERIPH, self->spi);
self->spi->hdmatx = &tx_dma;
dma_init(&rx_dma, self->rx_dma_stream, self->rx_dma_channel, DMA_PERIPH_TO_MEMORY, self->spi);
self->spi->hdmarx = &rx_dma;
status = HAL_SPI_TransmitReceive_DMA(self->spi, bufinfo_send.buf, bufinfo_recv.buf, bufinfo_send.len); status = HAL_SPI_TransmitReceive_DMA(self->spi, bufinfo_send.buf, bufinfo_recv.buf, bufinfo_send.len);
if (status == HAL_OK) { if (status == HAL_OK) {
status = spi_wait_dma_finished(self->spi, args[2].u_int); status = spi_wait_dma_finished(self->spi, args[2].u_int);
} }
dma_deinit(&tx_dma);
dma_deinit(&rx_dma);
} }
if (status != HAL_OK) { if (status != HAL_OK) {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment