[Cryptech-Commits] [sw/stm32] 05/06: Use DMA for UART RX instead of interrupts.

git at cryptech.is git at cryptech.is
Thu Jun 2 12:58:04 UTC 2016


This is an automated email from the git hooks/post-receive script.

fredrik at thulin.net pushed a commit to branch master
in repository sw/stm32.

commit ae1ecf87f6b8d7c34b32af0547f118ff7697c2ef
Author: Fredrik Thulin <fredrik at thulin.net>
AuthorDate: Thu Jun 2 14:56:56 2016 +0200

    Use DMA for UART RX instead of interrupts.
    
    DMA is more efficient and less prone to miss characters than interrupts.
    
    An open question is if circular mode is really the best. If someone
    copy-pastes more than the RX buffer size of configuration into the CLI,
    we risk the DMA controller catching up with the reader and overwriting
    data not yet read.
    
    Since we don't have flow control back to the users terminal, we will
    always fail if too much data is entered before we can process it. The
    question is if failing to stuff new data at the end of a buffer might be
    better than data being overwritten - thus messing up the commands in
    unpredictable ways.
---
 .../TARGET_CRYPTECH_ALPHA/stm32f4xx_hal_msp.c      | 59 +++++++++++++++++-
 .../TARGET_CRYPTECH_ALPHA/stm32f4xx_it.c           | 17 ++++++
 projects/cli-test/cli-test.c                       | 17 ------
 projects/cli-test/filetransfer                     |  6 +-
 projects/cli-test/mgmt-cli.c                       | 71 +++++++++++-----------
 projects/cli-test/mgmt-cli.h                       |  7 ++-
 projects/cli-test/mgmt-fpga.c                      | 64 ++++---------------
 projects/cli-test/mgmt-misc.c                      | 62 +++++++++++++++----
 projects/cli-test/mgmt-misc.h                      |  6 ++
 stm-init.c                                         | 29 +++++++++
 stm-uart.c                                         |  7 ++-
 stm-uart.h                                         |  3 +
 12 files changed, 223 insertions(+), 125 deletions(-)

diff --git a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_hal_msp.c b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_hal_msp.c
index 2a207b6..91a6f46 100644
--- a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_hal_msp.c
+++ b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_hal_msp.c
@@ -33,10 +33,8 @@
 */
 /* Includes ------------------------------------------------------------------*/
 #include "stm32f4xx_hal.h"
+#include "stm-uart.h"
 
-/* USER CODE BEGIN 0 */
-
-/* USER CODE END 0 */
 
 /**
  * Initializes the Global MSP.
@@ -121,6 +119,8 @@ void HAL_UART_MspInit(UART_HandleTypeDef* huart)
   GPIO_InitTypeDef GPIO_InitStruct;
 
   if (huart->Instance == USART1) {
+    /* This is huart_mgmt (USER_MGMT) */
+
     /* Peripheral clock enable */
     __USART1_CLK_ENABLE();
     __GPIOA_CLK_ENABLE();
@@ -138,7 +138,32 @@ void HAL_UART_MspInit(UART_HandleTypeDef* huart)
 
     HAL_NVIC_SetPriority(USART1_IRQn, 0, 1);
     HAL_NVIC_EnableIRQ(USART1_IRQn);
+
+    /* Peripheral DMA init*/
+    hdma_usart_mgmt_rx.Instance = DMA2_Stream2;
+    hdma_usart_mgmt_rx.Init.Channel = DMA_CHANNEL_4;
+    hdma_usart_mgmt_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
+    hdma_usart_mgmt_rx.Init.PeriphInc = DMA_PINC_DISABLE;
+    hdma_usart_mgmt_rx.Init.MemInc = DMA_MINC_ENABLE;
+    hdma_usart_mgmt_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
+    hdma_usart_mgmt_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
+    hdma_usart_mgmt_rx.Init.Mode = DMA_CIRCULAR;
+    hdma_usart_mgmt_rx.Init.Priority = DMA_PRIORITY_LOW;
+    hdma_usart_mgmt_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
+    /*
+    hdma_usart_mgmt_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
+    hdma_usart_mgmt_rx.Init.MemBurst = DMA_MBURST_SINGLE;
+    hdma_usart_mgmt_rx.Init.PeriphBurst = DMA_PBURST_SINGLE;
+    */
+    if (HAL_DMA_Init(&hdma_usart_mgmt_rx) != HAL_OK) {
+	Error_Handler();
+    }
+
+    __HAL_LINKDMA(huart, hdmarx, hdma_usart_mgmt_rx);
+
   } else if (huart->Instance == USART2) {
+    /* This is huart_user (USER UART) */
+
     /* Peripheral clock enable */
     __USART2_CLK_ENABLE();
     __GPIOA_CLK_ENABLE();
@@ -156,6 +181,28 @@ void HAL_UART_MspInit(UART_HandleTypeDef* huart)
 
     HAL_NVIC_SetPriority(USART2_IRQn, 0, 1);
     HAL_NVIC_EnableIRQ(USART2_IRQn);
+
+    /* Peripheral DMA init*/
+    hdma_usart_user_rx.Instance = DMA1_Stream5;
+    hdma_usart_user_rx.Init.Channel = DMA_CHANNEL_4;
+    hdma_usart_user_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
+    hdma_usart_user_rx.Init.PeriphInc = DMA_PINC_DISABLE;
+    hdma_usart_user_rx.Init.MemInc = DMA_MINC_ENABLE;
+    hdma_usart_user_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
+    hdma_usart_user_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
+    hdma_usart_user_rx.Init.Mode = DMA_CIRCULAR;
+    hdma_usart_user_rx.Init.Priority = DMA_PRIORITY_LOW;
+    hdma_usart_user_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
+    /*
+    hdma_usart_user_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
+    hdma_usart_user_rx.Init.MemBurst = DMA_MBURST_SINGLE;
+    hdma_usart_user_rx.Init.PeriphBurst = DMA_PBURST_SINGLE;
+    */
+    if (HAL_DMA_Init(&hdma_usart_user_rx) != HAL_OK) {
+	Error_Handler();
+    }
+
+    __HAL_LINKDMA(huart, hdmarx, hdma_usart_user_rx);
   }
 }
 
@@ -172,6 +219,9 @@ void HAL_UART_MspDeInit(UART_HandleTypeDef* huart)
     HAL_GPIO_DeInit(GPIOA, GPIO_PIN_2 | GPIO_PIN_3);
 
     HAL_NVIC_DisableIRQ(USART1_IRQn);
+
+    /* Peripheral DMA DeInit*/
+    HAL_DMA_DeInit(huart->hdmarx);
   } else if (huart->Instance == USART2) {
     /* Peripheral clock disable */
     __USART2_CLK_DISABLE();
@@ -183,6 +233,9 @@ void HAL_UART_MspDeInit(UART_HandleTypeDef* huart)
     HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9 | GPIO_PIN_10);
 
     HAL_NVIC_DisableIRQ(USART2_IRQn);
+
+    /* Peripheral DMA DeInit*/
+    HAL_DMA_DeInit(huart->hdmarx);
   }
 }
 
diff --git a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_it.c b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_it.c
index a174d73..b3de408 100644
--- a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_it.c
+++ b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_it.c
@@ -166,4 +166,21 @@ void USART2_IRQHandler(void)
     HAL_UART_IRQHandler(&huart_user);
 }
 
+/**
+* @brief This function handles DMA1 stream5 global interrupt.
+*/
+void DMA1_Stream5_IRQHandler(void)
+{
+    HAL_DMA_IRQHandler(&hdma_usart_user_rx);
+}
+
+/**
+* @brief This function handles DMA2 stream2 global interrupt.
+*/
+void DMA2_Stream2_IRQHandler(void)
+{
+    HAL_DMA_IRQHandler(&hdma_usart_mgmt_rx);
+}
+
+
 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/projects/cli-test/cli-test.c b/projects/cli-test/cli-test.c
index b6178af..ed6aac3 100644
--- a/projects/cli-test/cli-test.c
+++ b/projects/cli-test/cli-test.c
@@ -71,23 +71,6 @@ void do_early_dfu_jump(void)
     while (1);
 }
 
-/* Callback for HAL_UART_Receive_IT(). */
-void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
-{
-    if (huart->Instance == huart_mgmt.Instance) {
-	mgmt_cli_uart_isr((const uint8_t *) &uart_rx, 1);
-
-	/* Set things up to receive another byte. */
-	HAL_UART_Receive_IT(huart, (uint8_t *) &uart_rx, 1);
-    }
-}
-
-void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
-{
-    led_on(LED_RED);
-    led_on(LED_YELLOW);
-}
-
 int
 main()
 {
diff --git a/projects/cli-test/filetransfer b/projects/cli-test/filetransfer
index 025a6ac..f704e31 100755
--- a/projects/cli-test/filetransfer
+++ b/projects/cli-test/filetransfer
@@ -77,11 +77,9 @@ def parse_args():
 
 
 def _write(dst, data):
-    for i in range(len(data)):
-        dst.write(data[i])
-        time.sleep(0.1)
+    dst.write(data)
     if len(data) == 4:
-        print("Wrote 0x{:02x}{:02x}{:02x}{:02x}".format(ord(data[0]), ord(data[1]), ord(data[2]), ord(data[3])))
+        print("Wrote 0x{!s}".format(data.encode('hex')))
     else:
         print("Wrote {!r}".format(data))
 
diff --git a/projects/cli-test/mgmt-cli.c b/projects/cli-test/mgmt-cli.c
index abbd999..3b4ffe9 100644
--- a/projects/cli-test/mgmt-cli.c
+++ b/projects/cli-test/mgmt-cli.c
@@ -41,18 +41,17 @@
 extern uint8_t uart_rx;
 
 struct uart_ringbuf_t {
-    uint32_t enabled, ridx, widx, overflow;
+    uint32_t enabled, ridx;
+    enum mgmt_cli_dma_state rx_state;
     uint8_t buf[CLI_UART_RECVBUF_SIZE];
 };
 
-volatile struct uart_ringbuf_t uart_ringbuf = {1, 0, 0, 0, {0}};
+volatile struct uart_ringbuf_t uart_ringbuf = {1, 0, DMA_RX_STOP, {0}};
 
 #define RINGBUF_RIDX(rb)       (rb.ridx & CLI_UART_RECVBUF_MASK)
-#define RINGBUF_WIDX(rb)       (rb.widx & CLI_UART_RECVBUF_MASK)
-#define RINGBUF_COUNT(rb)      ((unsigned)(rb.widx - rb.ridx))
-#define RINGBUF_FULL(rb)       (RINGBUF_RIDX(rb) == ((rb.widx + 1) & CLI_UART_RECVBUF_MASK))
+#define RINGBUF_WIDX(rb)       (sizeof(rb.buf) - __HAL_DMA_GET_COUNTER(huart_mgmt.hdmarx))
+#define RINGBUF_COUNT(rb)      ((unsigned)(RINGBUF_WIDX(rb) - RINGBUF_RIDX(rb)))
 #define RINGBUF_READ(rb, dst)  {dst = rb.buf[RINGBUF_RIDX(rb)]; rb.buf[RINGBUF_RIDX(rb)] = '.'; rb.ridx++;}
-#define RINGBUF_WRITE(rb, src) {rb.buf[RINGBUF_WIDX(rb)] = src; rb.widx++;}
 
 void uart_cli_print(struct cli_def *cli __attribute__ ((unused)), const char *buf)
 {
@@ -64,23 +63,16 @@ void uart_cli_print(struct cli_def *cli __attribute__ ((unused)), const char *bu
 int uart_cli_read(struct cli_def *cli __attribute__ ((unused)), void *buf, size_t count)
 {
     uint32_t timeout = 0xffffff;
-
-    /* Always explicitly enable the RX interrupt when we get here.
-     * Prevents us getting stuck waiting for an interrupt that will never come.
-     */
-    __HAL_UART_FLUSH_DRREGISTER(&huart_mgmt);
-    HAL_UART_Receive_IT(&huart_mgmt, (uint8_t *) &uart_rx, 1);
-
-    while (count && timeout--) {
+    while (count && timeout) {
 	if (RINGBUF_COUNT(uart_ringbuf)) {
 	    RINGBUF_READ(uart_ringbuf, *(uint8_t *) buf);
 	    buf++;
 	    count--;
-	} else {
-	    led_toggle(LED_GREEN);
-	    HAL_Delay(10);
 	}
+	timeout--;
     }
+    if (! timeout) return 0;
+
     return 1;
 }
 
@@ -90,6 +82,26 @@ int uart_cli_write(struct cli_def *cli __attribute__ ((unused)), const void *buf
     return (int) count;
 }
 
+int control_mgmt_uart_dma_rx(enum mgmt_cli_dma_state state)
+{
+    if (state == DMA_RX_START) {
+	if (uart_ringbuf.rx_state != DMA_RX_START) {
+	    memset((void *) uart_ringbuf.buf, 0, sizeof(uart_ringbuf.buf));
+
+	    /* Start receiving data from the UART using DMA */
+	    HAL_UART_Receive_DMA(&huart_mgmt, (uint8_t *) uart_ringbuf.buf, sizeof(uart_ringbuf.buf));
+	    uart_ringbuf.ridx = 0;
+	    uart_ringbuf.rx_state = DMA_RX_START;
+	}
+	return 1;
+    } else if (state == DMA_RX_STOP) {
+	if (HAL_UART_DMAStop(&huart_mgmt) != HAL_OK) return 0;
+	uart_ringbuf.rx_state = DMA_RX_STOP;
+	return 1;
+    }
+    return 0;
+}
+
 int embedded_cli_loop(struct cli_def *cli)
 {
     unsigned char c;
@@ -110,15 +122,18 @@ int embedded_cli_loop(struct cli_def *cli)
     while (1) {
 	cli_loop_start_new_command(cli, &ctx);
 
+	control_mgmt_uart_dma_rx(DMA_RX_START);
+
 	while (1) {
 	    cli_loop_show_prompt(cli, &ctx);
 
 	    n = cli_loop_read_next_char(cli, &ctx, &c);
 
 	    /*
-	    cli_print(cli, "Next char: '%c'/%i, ringbuf ridx %i, widx %i (%i/%i) - count %i",
-		      c, (int) c, uart_ringbuf.ridx, uart_ringbuf.widx, RINGBUF_RIDX(uart_ringbuf),
-		      RINGBUF_WIDX(uart_ringbuf), RINGBUF_COUNT(uart_ringbuf));
+	    cli_print(cli, "Next char: '%c'/%i, ringbuf ridx %i, widx %i",
+		      c, (int) c,
+		      uart_ringbuf.ridx,
+		      RINGBUF_WIDX(uart_ringbuf)
 	    */
 	    if (n == CLI_LOOP_CTRL_BREAK)
 		break;
@@ -143,22 +158,6 @@ int embedded_cli_loop(struct cli_def *cli)
     return CLI_OK;
 }
 
-/* Interrupt service routine to be called when data has been received on the MGMT UART. */
-void mgmt_cli_uart_isr(const uint8_t *buf, size_t count)
-{
-    if (! uart_ringbuf.enabled) return;
-
-    while (count) {
-	if (RINGBUF_FULL(uart_ringbuf)) {
-	    uart_ringbuf.overflow++;
-	    return;
-	}
-	RINGBUF_WRITE(uart_ringbuf, *buf);
-	buf++;
-	count--;
-    }
-}
-
 void mgmt_cli_init(struct cli_def *cli)
 {
     cli_init(cli);
diff --git a/projects/cli-test/mgmt-cli.h b/projects/cli-test/mgmt-cli.h
index 3b7f503..16c9fbd 100644
--- a/projects/cli-test/mgmt-cli.h
+++ b/projects/cli-test/mgmt-cli.h
@@ -71,11 +71,16 @@
 #define CLI_UART_RECVBUF_SIZE  256  /* This must be a power of 2 */
 #define CLI_UART_RECVBUF_MASK  (CLI_UART_RECVBUF_SIZE - 1)
 
+enum mgmt_cli_dma_state {
+    DMA_RX_STOP,
+    DMA_RX_START,
+};
+
 extern void uart_cli_print(struct cli_def *cli __attribute__ ((unused)), const char *buf);
 extern int uart_cli_read(struct cli_def *cli __attribute__ ((unused)), void *buf, size_t count);
 extern int uart_cli_write(struct cli_def *cli __attribute__ ((unused)), const void *buf, size_t count);
 extern int embedded_cli_loop(struct cli_def *cli);
 extern void mgmt_cli_init(struct cli_def *cli);
-extern void mgmt_cli_uart_isr(const uint8_t *buf, size_t count);
+extern int control_mgmt_uart_dma_rx(enum mgmt_cli_dma_state state);
 
 #endif /* __STM32_MGMT_CLI_H */
diff --git a/projects/cli-test/mgmt-fpga.c b/projects/cli-test/mgmt-fpga.c
index c20b7b2..8c1b2a8 100644
--- a/projects/cli-test/mgmt-fpga.c
+++ b/projects/cli-test/mgmt-fpga.c
@@ -35,21 +35,29 @@
 #include "stm-init.h"
 #include "stm-uart.h"
 #include "stm-fpgacfg.h"
+
 #include "mgmt-cli.h"
 #include "mgmt-fpga.h"
+#include "mgmt-misc.h"
 
 #include <string.h>
 
 
-extern uint32_t update_crc(uint32_t crc, uint8_t *buf, int len);
+volatile uint32_t dfu_offset = 0;
+
 
+int _flash_write_callback(uint8_t *buf, size_t len) {
+    int res = fpgacfg_write_data(dfu_offset, buf, BITSTREAM_UPLOAD_CHUNK_SIZE) == 1;
+    dfu_offset += BITSTREAM_UPLOAD_CHUNK_SIZE;
+    return res;
+}
 
 int cmd_fpga_bitstream_upload(struct cli_def *cli, const char *command, char *argv[], int argc)
 {
-    uint32_t filesize = 0, crc = 0, my_crc = 0, counter = 0, i;
-    uint32_t offset = 0, n = BITSTREAM_UPLOAD_CHUNK_SIZE;
     uint8_t buf[BITSTREAM_UPLOAD_CHUNK_SIZE];
 
+    dfu_offset = 0;
+
     fpgacfg_access_control(ALLOW_ARM);
 
     cli_print(cli, "Checking if FPGA config memory is accessible");
@@ -58,57 +66,11 @@ int cmd_fpga_bitstream_upload(struct cli_def *cli, const char *command, char *ar
 	return CLI_ERROR;
     }
 
-    cli_print(cli, "OK, write FPGA bitstream file size (4 bytes), data in 4096 byte chunks, CRC-32 (4 bytes)");
-
-    /* Read file size (4 bytes) */
-    uart_receive_bytes(STM_UART_MGMT, (void *) &filesize, 4, 1000);
-    cli_print(cli, "File size %li", filesize);
-
-    while (filesize) {
-	/* By initializing buf to the same value that erased flash has (0xff), we don't
-	 * have to try and be smart when writing the last page of data to the memory.
-	 */
-	memset(buf, 0xff, sizeof(buf));
-
-	if (filesize < n) {
-	    n = filesize;
-	}
-
-	if (uart_receive_bytes(STM_UART_MGMT, (void *) &buf, n, 1000) != HAL_OK) {
-	    cli_print(cli, "Receive timed out");
-	    return CLI_ERROR;
-	}
-	filesize -= n;
-
-	/* After reception of 4 KB but before ACKing we have "all" the time in the world to
-	 * calculate CRC and write it to flash.
-	 */
-	my_crc = update_crc(my_crc, buf, n);
-
-	if ((i = fpgacfg_write_data(offset, buf, BITSTREAM_UPLOAD_CHUNK_SIZE)) != 1) {
-	    cli_print(cli, "Failed writing data at offset %li (counter = %li): %li", offset, counter, i);
-	    return CLI_ERROR;
-	}
-
-	offset += BITSTREAM_UPLOAD_CHUNK_SIZE;
-
-	/* ACK this chunk by sending the current chunk counter (4 bytes) */
-	counter++;
-	uart_send_bytes(STM_UART_MGMT, (void *) &counter, 4);
-    }
-
-    /* The sending side will now send it's calculated CRC-32 */
-    cli_print(cli, "Send CRC-32");
-    uart_receive_bytes(STM_UART_MGMT, (void *) &crc, 4, 1000);
-    cli_print(cli, "CRC-32 %li", crc);
-    if (crc == my_crc) {
-	cli_print(cli, "CRC checksum MATCHED");
-    } else {
-	cli_print(cli, "CRC checksum did NOT match");
-    }
+    cli_receive_data(cli, &buf[0], sizeof(buf), _flash_write_callback);
 
     fpgacfg_access_control(ALLOW_FPGA);
 
+    cli_print(cli, "DFU offset now: %li (%li chunks)", dfu_offset, dfu_offset / BITSTREAM_UPLOAD_CHUNK_SIZE);
     return CLI_OK;
 }
 
diff --git a/projects/cli-test/mgmt-misc.c b/projects/cli-test/mgmt-misc.c
index a98bf8d..aea790a 100644
--- a/projects/cli-test/mgmt-misc.c
+++ b/projects/cli-test/mgmt-misc.c
@@ -43,34 +43,64 @@
 
 extern uint32_t update_crc(uint32_t crc, uint8_t *buf, int len);
 
-int cmd_filetransfer(struct cli_def *cli, const char *command, char *argv[], int argc)
+
+volatile uint32_t demo_crc = 0;
+
+
+int _count_bytes_callback(uint8_t *buf, size_t len) {
+    demo_crc = update_crc(demo_crc, buf, len);
+    return 1;
+}
+
+int cli_receive_data(struct cli_def *cli, uint8_t *buf, size_t len, cli_data_callback data_callback)
 {
-    uint32_t filesize = 0, crc = 0, my_crc = 0, n = 256, counter = 0;
-    uint8_t buf[256];
+    uint32_t filesize = 0, crc = 0, my_crc = 0, counter = 0;
+    size_t n = len;
 
-    cli_print(cli, "OK, write file size (4 bytes), data in %li byte chunks, CRC-32 (4 bytes)", n);
+    if (! control_mgmt_uart_dma_rx(DMA_RX_STOP)) {
+	cli_print(cli, "Failed stopping DMA");
+	return CLI_OK;
+    }
+
+    cli_print(cli, "OK, write size (4 bytes), data in %li byte chunks, CRC-32 (4 bytes)", (uint32_t) n);
 
-    uart_receive_bytes(STM_UART_MGMT, (void *) &filesize, 4, 1000);
-    cli_print(cli, "File size %li", filesize);
+    if (uart_receive_bytes(STM_UART_MGMT, (void *) &filesize, 4, 1000) != HAL_OK) {
+	cli_print(cli, "Receive timed out");
+	return CLI_ERROR;
+    }
+
+    cli_print(cli, "Send %li bytes of data", filesize);
 
     while (filesize) {
-	if (filesize < n) {
-	    n = filesize;
-	}
+	/* By initializing buf to the same value that erased flash has (0xff), we don't
+	 * have to try and be smart when writing the last page of data to a flash memory.
+	 */
+	memset(buf, 0xff, len);
 
-	if (uart_receive_bytes(STM_UART_MGMT, (void *) &buf, n, 1000) != HAL_OK) {
+	if (filesize < n) n = filesize;
+
+	if (uart_receive_bytes(STM_UART_MGMT, (void *) buf, n, 1000) != HAL_OK) {
 	    cli_print(cli, "Receive timed out");
 	    return CLI_ERROR;
 	}
 	filesize -= n;
 	my_crc = update_crc(my_crc, buf, n);
+
+	/* After reception of a chunk but before ACKing we have "all" the time in the world to
+	 * calculate CRC and invoke the data_callback.
+	 */
+	if (data_callback != NULL && ! data_callback(buf, (size_t) n)) {
+	    cli_print(cli, "Data processing failed");
+	    return CLI_OK;
+	}
+
 	counter++;
 	uart_send_bytes(STM_UART_MGMT, (void *) &counter, 4);
     }
 
     cli_print(cli, "Send CRC-32");
     uart_receive_bytes(STM_UART_MGMT, (void *) &crc, 4, 1000);
-    cli_print(cli, "CRC-32 %li", crc);
+    cli_print(cli, "CRC-32 0x%x, calculated CRC 0x%x", (unsigned int) crc, (unsigned int) my_crc);
     if (crc == my_crc) {
 	cli_print(cli, "CRC checksum MATCHED");
     } else {
@@ -80,6 +110,16 @@ int cmd_filetransfer(struct cli_def *cli, const char *command, char *argv[], int
     return CLI_OK;
 }
 
+int cmd_filetransfer(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+    uint8_t buf[FILETRANSFER_UPLOAD_CHUNK_SIZE];
+
+    demo_crc = 0;
+    cli_receive_data(cli, &buf[0], sizeof(buf), _count_bytes_callback);
+    cli_print(cli, "Demo CRC is: %li/0x%x", demo_crc, (unsigned int) demo_crc);
+    return CLI_OK;
+}
+
 int cmd_reboot(struct cli_def *cli, const char *command, char *argv[], int argc)
 {
     cli_print(cli, "\n\n\nRebooting\n\n\n");
diff --git a/projects/cli-test/mgmt-misc.h b/projects/cli-test/mgmt-misc.h
index caf7024..b7eb4f4 100644
--- a/projects/cli-test/mgmt-misc.h
+++ b/projects/cli-test/mgmt-misc.h
@@ -38,6 +38,12 @@
 #include "stm-init.h"
 #include <libcli.h>
 
+
+#define FILETRANSFER_UPLOAD_CHUNK_SIZE 256
+
+typedef int (*cli_data_callback)(uint8_t *, size_t);
+
 extern void configure_cli_misc(struct cli_def *cli);
+extern int cli_receive_data(struct cli_def *cli, uint8_t *buf, size_t len, cli_data_callback data_callback);
 
 #endif /* __STM32_CLI_MGMT_MISC_H */
diff --git a/stm-init.c b/stm-init.c
index c8228d8..4fd9dd4 100644
--- a/stm-init.c
+++ b/stm-init.c
@@ -59,6 +59,9 @@ static void MX_GPIO_Init(void);
 static void MX_USART1_UART_Init(void);
 static void MX_USART2_UART_Init(void);
 #endif
+#ifdef HAL_DMA_MODULE_ENABLED
+static void MX_DMA_Init(void);
+#endif
 #ifdef HAL_I2C_MODULE_ENABLED
 static void MX_I2C2_Init(void);
 #endif
@@ -87,6 +90,9 @@ void stm_init(void)
   fpgacfg_access_control(ALLOW_FPGA);
   #endif
 #endif
+#ifdef HAL_DMA_MODULE_ENABLED
+  MX_DMA_Init();
+#endif
 #ifdef HAL_UART_MODULE_ENABLED
   MX_USART1_UART_Init();
   MX_USART2_UART_Init();
@@ -165,6 +171,29 @@ static void MX_GPIO_Init(void)
 #undef gpio_output
 #endif
 
+
+#ifdef HAL_DMA_MODULE_ENABLED
+/**
+ * Enable DMA controller clock
+ */
+static void MX_DMA_Init(void)
+{
+    /* DMA controller clock enable */
+    __HAL_RCC_DMA2_CLK_ENABLE();
+    __HAL_RCC_DMA1_CLK_ENABLE();
+
+    /* DMA interrupt init */
+
+    /* USER UART RX */
+    HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 0, 0);
+    HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);
+    /* MGMT UART RX */
+    HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 0, 0);
+    HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
+}
+#endif /* HAL_DMA_MODULE_ENABLED */
+
+
 #ifdef HAL_I2C_MODULE_ENABLED
 /* I2C2 init function (external RTC chip) */
 void MX_I2C2_Init(void)
diff --git a/stm-uart.c b/stm-uart.c
index 2f3aabe..59bbbe6 100644
--- a/stm-uart.c
+++ b/stm-uart.c
@@ -37,8 +37,11 @@
 
 #include <string.h>
 
-UART_HandleTypeDef huart_mgmt;
-UART_HandleTypeDef huart_user;
+UART_HandleTypeDef huart_mgmt;  /* USART1 */
+UART_HandleTypeDef huart_user;  /* USART2 */
+
+DMA_HandleTypeDef hdma_usart_mgmt_rx;
+DMA_HandleTypeDef hdma_usart_user_rx;
 
 #define DEFAULT_UART STM_UART_USER
 
diff --git a/stm-uart.h b/stm-uart.h
index e63aaa4..db3a045 100644
--- a/stm-uart.h
+++ b/stm-uart.h
@@ -48,6 +48,9 @@ enum stm_uart_port {
 extern UART_HandleTypeDef huart_mgmt;
 extern UART_HandleTypeDef huart_user;
 
+extern DMA_HandleTypeDef hdma_usart_mgmt_rx;
+extern DMA_HandleTypeDef hdma_usart_user_rx;
+
 extern HAL_StatusTypeDef uart_send_char(uint8_t ch);
 extern HAL_StatusTypeDef uart_recv_char(uint8_t *cp);
 



More information about the Commits mailing list