From 0ec7e72b01dca8070c1a8ae9a0b0347d2281eadb Mon Sep 17 00:00:00 2001 From: stevstrong Date: Fri, 21 Oct 2016 22:31:27 +0200 Subject: [PATCH 01/25] improved USB serial Rx and implemented buffered Tx --- .../maple/libmaple/usb/stm32f1/usb_cdcacm.c | 227 +++++++++++------- STM32F1/cores/maple/usb_serial.cpp | 45 +--- STM32F1/cores/maple/usb_serial.h | 2 +- .../system/libmaple/usb/stm32f1/usb_reg_map.h | 4 +- 4 files changed, 153 insertions(+), 125 deletions(-) diff --git a/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c b/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c index 448c05d..7a5a772 100644 --- a/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c +++ b/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c @@ -261,18 +261,28 @@ static ONE_DESCRIPTOR String_Descriptor[N_STRING_DESCRIPTORS] = { /* I/O state */ -#define CDC_SERIAL_BUFFER_SIZE 512 +#define CDC_SERIAL_RX_BUFFER_SIZE 256 // must be power of 2 +#define CDC_SERIAL_RX_BUFFER_SIZE_MASK (CDC_SERIAL_RX_BUFFER_SIZE-1) /* Received data */ -static volatile uint8 vcomBufferRx[CDC_SERIAL_BUFFER_SIZE]; -/* Read index into vcomBufferRx */ -static volatile uint32 rx_offset = 0; -/* Number of bytes left to transmit */ -static volatile uint32 n_unsent_bytes = 0; -/* Are we currently sending an IN packet? */ -static volatile uint8 transmitting = 0; -/* Number of unread bytes */ -static volatile uint32 n_unread_bytes = 0; +static volatile uint8 vcomBufferRx[CDC_SERIAL_RX_BUFFER_SIZE]; +/* Write index to vcomBufferRx */ +static volatile uint32 rx_head; +/* Read index from vcomBufferRx */ +static volatile uint32 rx_tail; + +#define CDC_SERIAL_TX_BUFFER_SIZE 256 // must be power of 2 +#define CDC_SERIAL_TX_BUFFER_SIZE_MASK (CDC_SERIAL_TX_BUFFER_SIZE-1) +// Tx data +static volatile uint8 vcomBufferTx[CDC_SERIAL_TX_BUFFER_SIZE]; +// Write index to vcomBufferTx +static volatile uint32 tx_head; +// Read index from vcomBufferTx +static volatile uint32 tx_tail; +// Are we currently sending an IN packet? +static volatile int8 transmitting; + + /* Other state (line coding, DTR/RTS) */ @@ -393,30 +403,34 @@ void usb_cdcacm_putc(char ch) { ; } -/* This function is blocking. +/* This function is non-blocking. * - * It copies data from a usercode buffer into the USB peripheral TX + * It copies data from a user buffer into the USB peripheral TX * buffer, and returns the number of bytes copied. */ -uint32 usb_cdcacm_tx(const uint8* buf, uint32 len) { - /* Last transmission hasn't finished, so abort. */ - while ( usb_cdcacm_is_transmitting()>0 ) ; // wait for end of transmission +uint32 usb_cdcacm_tx(const uint8* buf, uint32 len) +{ + if (len==0) return 0; // no data to send - /* We can only put USB_CDCACM_TX_EPSIZE bytes in the buffer. */ - if (len > USB_CDCACM_TX_EPSIZE) { - len = USB_CDCACM_TX_EPSIZE; - } + uint32 head = tx_head; // load volatile variable + uint32 tx_unsent = (head - tx_tail) & CDC_SERIAL_TX_BUFFER_SIZE_MASK; - /* Queue bytes for sending. */ - if (len) { - usb_copy_to_pma(buf, len, USB_CDCACM_TX_ADDR); + // We can only put bytes in the buffer if there is place + if (len > (CDC_SERIAL_TX_BUFFER_SIZE-tx_unsent-1) ) { + len = (CDC_SERIAL_TX_BUFFER_SIZE-tx_unsent-1); } - // We still need to wait for the interrupt, even if we're sending - // zero bytes. (Sending zero-size packets is useful for flushing - // host-side buffers.) - usb_set_ep_tx_count(USB_CDCACM_TX_ENDP, len); - n_unsent_bytes = len; - transmitting = 1; - usb_set_ep_tx_stat(USB_CDCACM_TX_ENDP, USB_EP_STAT_TX_VALID); + if (len==0) return 0; // buffer full + + uint16 i; + // copy data from user buffer to USB Tx buffer + for (i=0; i0 ? transmitting : 0); } uint16 usb_cdcacm_get_pending(void) { - return n_unsent_bytes; + return (tx_head - tx_tail) & CDC_SERIAL_TX_BUFFER_SIZE_MASK; } -/* Nonblocking byte receive. +/* Non-blocking byte receive. * * Copies up to len bytes from our private data buffer (*NOT* the PMA) * into buf and deq's the FIFO. */ -uint32 usb_cdcacm_rx(uint8* buf, uint32 len) { +uint32 usb_cdcacm_rx(uint8* buf, uint32 len) +{ /* Copy bytes to buffer. */ uint32 n_copied = usb_cdcacm_peek(buf, len); /* Mark bytes as read. */ - n_unread_bytes -= n_copied; - rx_offset = (rx_offset + n_copied) % CDC_SERIAL_BUFFER_SIZE; + uint16 tail = rx_tail; // load volatile variable + tail = (tail + n_copied) & CDC_SERIAL_RX_BUFFER_SIZE_MASK; + rx_tail = tail; // store volatile variable - /* If all bytes have been read, re-enable the RX endpoint, which - * was set to NAK when the current batch of bytes was received. */ - if (n_unread_bytes == 0) { - usb_set_ep_rx_count(USB_CDCACM_RX_ENDP, USB_CDCACM_RX_EPSIZE); + uint32 rx_unread = (rx_head - tail) & CDC_SERIAL_RX_BUFFER_SIZE_MASK; + // If buffer was emptied to a pre-set value, re-enable the RX endpoint + if ( rx_unread <= 64 ) { // experimental value, gives the best performance usb_set_ep_rx_stat(USB_CDCACM_RX_ENDP, USB_EP_STAT_RX_VALID); - } - + } return n_copied; } -/* Nonblocking byte lookahead. +/* Non-blocking byte lookahead. * * Looks at unread bytes without marking them as read. */ -uint32 usb_cdcacm_peek(uint8* buf, uint32 len) { +uint32 usb_cdcacm_peek(uint8* buf, uint32 len) +{ int i; - uint32 head = rx_offset; + uint32 tail = rx_tail; + uint32 rx_unread = (rx_head-tail) & CDC_SERIAL_RX_BUFFER_SIZE_MASK; - if (len > n_unread_bytes) { - len = n_unread_bytes; + if (len > rx_unread) { + len = rx_unread; } for (i = 0; i < len; i++) { - buf[i] = vcomBufferRx[head]; - head = (head + 1) % CDC_SERIAL_BUFFER_SIZE; + buf[i] = vcomBufferRx[tail]; + tail = (tail + 1) & CDC_SERIAL_RX_BUFFER_SIZE_MASK; } return len; } -uint32 usb_cdcacm_peek_ex(uint8* buf, uint32 offset, uint32 len) { +uint32 usb_cdcacm_peek_ex(uint8* buf, uint32 offset, uint32 len) +{ int i; - uint32 head = (rx_offset + offset) % CDC_SERIAL_BUFFER_SIZE; + uint32 tail = (rx_tail + offset) & CDC_SERIAL_RX_BUFFER_SIZE_MASK ; + uint32 rx_unread = (rx_head-tail) & CDC_SERIAL_RX_BUFFER_SIZE_MASK; - if (len + offset > n_unread_bytes) { - len = n_unread_bytes - offset; + if (len + offset > rx_unread) { + len = rx_unread - offset; } for (i = 0; i < len; i++) { - buf[i] = vcomBufferRx[head]; - head = (head + 1) % CDC_SERIAL_BUFFER_SIZE; + buf[i] = vcomBufferRx[tail]; + tail = (tail + 1) & CDC_SERIAL_RX_BUFFER_SIZE_MASK; } return len; @@ -495,12 +513,12 @@ uint32 usb_cdcacm_peek_ex(uint8* buf, uint32 offset, uint32 len) { /* Roger Clark. Added. for Arduino 1.0 API support of Serial.peek() */ int usb_cdcacm_peek_char() { - if (n_unread_bytes == 0) + if (usb_cdcacm_data_available() == 0) { return -1; } - return vcomBufferRx[rx_offset]; + return vcomBufferRx[rx_tail]; } uint8 usb_cdcacm_get_dtr() { @@ -534,41 +552,75 @@ int usb_cdcacm_get_n_data_bits(void) { return line_coding.bDataBits; } - /* * Callbacks */ - -static void vcomDataTxCb(void) { - n_unsent_bytes = 0; - transmitting = 0; +static void vcomDataTxCb(void) +{ + uint32 tail = tx_tail; // load volatile variable + uint32 tx_unsent = (tx_head - tail) & CDC_SERIAL_TX_BUFFER_SIZE_MASK; + if (tx_unsent==0) { + if ( (--transmitting)==0) goto flush; // no more data to send + return; // it was already flushed, keep Tx endpoint disabled + } + transmitting = 1; + // We can only send up to USB_CDCACM_TX_EPSIZE bytes in the endpoint. + if (tx_unsent > USB_CDCACM_TX_EPSIZE) { + tx_unsent = USB_CDCACM_TX_EPSIZE; + } + // copy the bytes from USB Tx buffer to PMA buffer + uint32 *dst = usb_pma_ptr(USB_CDCACM_TX_ADDR); + uint16 tmp = 0; + uint16 val; + int i; + for (i = 0; i < tx_unsent; i++) { + val = vcomBufferTx[tail]; + tail = (tail + 1) & CDC_SERIAL_TX_BUFFER_SIZE_MASK; + if (i&1) { + *dst++ = tmp | (val<<8); + } else { + tmp = val; + } + } + if ( tx_unsent&1 ) { + *dst = tmp; + } + tx_tail = tail; // store volatile variable +flush: + // enable Tx endpoint + usb_set_ep_tx_count(USB_CDCACM_TX_ENDP, tx_unsent); + usb_set_ep_tx_stat(USB_CDCACM_TX_ENDP, USB_EP_STAT_TX_VALID); } -static void vcomDataRxCb(void) { - uint32 ep_rx_size; - uint32 tail = (rx_offset + n_unread_bytes) % CDC_SERIAL_BUFFER_SIZE; - uint8 ep_rx_data[USB_CDCACM_RX_EPSIZE]; + +static void vcomDataRxCb(void) +{ + uint32 head = rx_head; // load volatile variable + + uint32 ep_rx_size = usb_get_ep_rx_count(USB_CDCACM_RX_ENDP); + // This copy won't overwrite unread bytes as long as there is + // enough room in the USB Rx buffer for next packet + uint32 *src = usb_pma_ptr(USB_CDCACM_RX_ADDR); + uint16 tmp = 0; + uint8 val; uint32 i; - - usb_set_ep_rx_stat(USB_CDCACM_RX_ENDP, USB_EP_STAT_RX_NAK); - ep_rx_size = usb_get_ep_rx_count(USB_CDCACM_RX_ENDP); - /* This copy won't overwrite unread bytes, since we've set the RX - * endpoint to NAK, and will only set it to VALID when all bytes - * have been read. */ - usb_copy_from_pma((uint8*)ep_rx_data, ep_rx_size, - USB_CDCACM_RX_ADDR); - for (i = 0; i < ep_rx_size; i++) { - vcomBufferRx[tail] = ep_rx_data[i]; - tail = (tail + 1) % CDC_SERIAL_BUFFER_SIZE; + if (i&1) { + val = tmp>>8; + } else { + tmp = *src++; + val = tmp&0xFF; + } + vcomBufferRx[head] = val; + head = (head + 1) & CDC_SERIAL_RX_BUFFER_SIZE_MASK; } + rx_head = head; // store volatile variable - n_unread_bytes += ep_rx_size; - - if ( n_unread_bytes == 0 ) { - usb_set_ep_rx_count(USB_CDCACM_RX_ENDP, USB_CDCACM_RX_EPSIZE); - usb_set_ep_rx_stat(USB_CDCACM_RX_ENDP, USB_EP_STAT_RX_VALID); - } + uint32 rx_unread = (head - rx_tail) & CDC_SERIAL_RX_BUFFER_SIZE_MASK; + // only enable further Rx if there is enough room to receive one more packet + if ( rx_unread < (CDC_SERIAL_RX_BUFFER_SIZE-USB_CDCACM_RX_EPSIZE) ) { + usb_set_ep_rx_stat(USB_CDCACM_RX_ENDP, USB_EP_STAT_RX_VALID); + } if (rx_hook) { rx_hook(USB_CDCACM_HOOK_RX, 0); @@ -646,10 +698,11 @@ static void usbReset(void) { SetDeviceAddress(0); /* Reset the RX/TX state */ - n_unread_bytes = 0; - n_unsent_bytes = 0; - rx_offset = 0; - transmitting = 0; + rx_head = 0; + rx_tail = 0; + tx_head = 0; + tx_tail = 0; + transmitting = -1; } static RESULT usbDataSetup(uint8 request) { diff --git a/STM32F1/cores/maple/usb_serial.cpp b/STM32F1/cores/maple/usb_serial.cpp index ab8816b..24b0014 100644 --- a/STM32F1/cores/maple/usb_serial.cpp +++ b/STM32F1/cores/maple/usb_serial.cpp @@ -100,44 +100,23 @@ size_t n = 0; size_t USBSerial::write(const char *str) { size_t n = 0; - this->write(str, strlen(str)); + this->write((const uint8*)str, strlen(str)); return n; } -size_t USBSerial::write(const void *buf, uint32 len) { +size_t USBSerial::write(const uint8 *buf, uint32 len) +{ size_t n = 0; if (!this->isConnected() || !buf) { return 0; } uint32 txed = 0; - uint32 old_txed = 0; - uint32 start = millis(); - - uint32 sent = 0; - - while (txed < len && (millis() - start < USB_TIMEOUT)) { - sent = usb_cdcacm_tx((const uint8*)buf + txed, len - txed); - txed += sent; - if (old_txed != txed) { - start = millis(); - } - old_txed = txed; + while (txed < len) { + txed += usb_cdcacm_tx((const uint8*)buf + txed, len - txed); } - -#if 0 -// this code leads to a serious performance drop and appears to be -// unnecessary - everything seems to work fine without, -jcw, 2015-11-05 -// see http://stm32duino.com/posting.php?mode=quote&f=3&p=7746 - if (sent == USB_CDCACM_TX_EPSIZE) { - while (usb_cdcacm_is_transmitting() != 0) { - } - /* flush out to avoid having the pc wait for more data */ - usb_cdcacm_tx(NULL, 0); - } -#endif - return n; + return n; } int USBSerial::available(void) { @@ -168,14 +147,10 @@ void USBSerial::flush(void) return; } -uint32 USBSerial::read(void *buf, uint32 len) { - if (!buf) { - return 0; - } - +uint32 USBSerial::read(uint8 * buf, uint32 len) { uint32 rxed = 0; while (rxed < len) { - rxed += usb_cdcacm_rx((uint8*)buf + rxed, len - rxed); + rxed += usb_cdcacm_rx(buf + rxed, len - rxed); } return rxed; @@ -183,13 +158,13 @@ uint32 USBSerial::read(void *buf, uint32 len) { /* Blocks forever until 1 byte is received */ int USBSerial::read(void) { - uint8 b; + int8 b; /* this->read(&b, 1); return b; */ - if (usb_cdcacm_rx(&b, 1)==0) + if (usb_cdcacm_rx((uint8*)&b, 1)==0) { return -1; } diff --git a/STM32F1/cores/maple/usb_serial.h b/STM32F1/cores/maple/usb_serial.h index 740ab0f..e50a16c 100644 --- a/STM32F1/cores/maple/usb_serial.h +++ b/STM32F1/cores/maple/usb_serial.h @@ -53,7 +53,7 @@ public: virtual int available(void);// Changed to virtual - uint32 read(void *buf, uint32 len); + uint32 read(uint8 * buf, uint32 len); // uint8 read(void); // Roger Clark. added functions to support Arduino 1.0 API diff --git a/STM32F1/system/libmaple/usb/stm32f1/usb_reg_map.h b/STM32F1/system/libmaple/usb/stm32f1/usb_reg_map.h index 6683264..9e9214c 100644 --- a/STM32F1/system/libmaple/usb/stm32f1/usb_reg_map.h +++ b/STM32F1/system/libmaple/usb/stm32f1/usb_reg_map.h @@ -349,8 +349,8 @@ static inline void usb_clear_status_out(uint8 ep) { void usb_copy_to_pma(const uint8 *buf, uint16 len, uint16 pma_offset); void usb_copy_from_pma(uint8 *buf, uint16 len, uint16 pma_offset); -static inline void* usb_pma_ptr(uint32 offset) { - return (void*)(USB_PMA_BASE + 2 * offset); +static inline uint32 * usb_pma_ptr(uint32 offset) { + return (uint32*)(USB_PMA_BASE + 2 * offset); } /* From 42cb8b5bc809df2aa4b9d82f535d7a71caae9282 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Fri, 21 Oct 2016 23:01:45 +0200 Subject: [PATCH 02/25] small change - revert local variable to uint8 in Serial.read --- STM32F1/cores/maple/usb_serial.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/STM32F1/cores/maple/usb_serial.cpp b/STM32F1/cores/maple/usb_serial.cpp index 24b0014..5eaf70e 100644 --- a/STM32F1/cores/maple/usb_serial.cpp +++ b/STM32F1/cores/maple/usb_serial.cpp @@ -158,13 +158,13 @@ uint32 USBSerial::read(uint8 * buf, uint32 len) { /* Blocks forever until 1 byte is received */ int USBSerial::read(void) { - int8 b; + uint8 b; /* this->read(&b, 1); return b; */ - if (usb_cdcacm_rx((uint8*)&b, 1)==0) + if (usb_cdcacm_rx(&b, 1)==0) { return -1; } From 4bc4b1d6bd42816c935053f043b8697f5e393434 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Mon, 31 Oct 2016 22:12:04 +0100 Subject: [PATCH 03/25] remove unused functions + adapt passed parameter - remove unused functions form usb_reg_map - change passed buffer type to uint8 * --- STM32F1/cores/maple/libmaple/usb/stm32f1/usb_reg_map.c | 8 ++++---- STM32F1/cores/maple/usb_serial.h | 2 +- STM32F1/system/libmaple/usb/stm32f1/usb_reg_map.h | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_reg_map.c b/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_reg_map.c index ea60cb3..3f5446a 100644 --- a/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_reg_map.c +++ b/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_reg_map.c @@ -29,7 +29,7 @@ /* TODO these could use some improvement; they're fairly * straightforward ports of the analogous ST code. The PMA blit * routines in particular are obvious targets for performance - * measurement and tuning. */ + * measurement and tuning. void usb_copy_to_pma(const uint8 *buf, uint16 len, uint16 pma_offset) { uint16 *dst = (uint16*)usb_pma_ptr(pma_offset); @@ -57,7 +57,7 @@ void usb_copy_from_pma(uint8 *buf, uint16 len, uint16 pma_offset) { *dst = *src & 0xFF; } } - + */ static void usb_set_ep_rx_count_common(uint32 *rxc, uint16 count) { uint16 nblocks; if (count > 62) { @@ -76,12 +76,12 @@ static void usb_set_ep_rx_count_common(uint32 *rxc, uint16 count) { *rxc = nblocks << 10; } } - +/* void usb_set_ep_rx_buf0_count(uint8 ep, uint16 count) { uint32 *rxc = usb_ep_rx_buf0_count_ptr(ep); usb_set_ep_rx_count_common(rxc, count); } - +*/ void usb_set_ep_rx_count(uint8 ep, uint16 count) { uint32 *rxc = usb_ep_rx_count_ptr(ep); usb_set_ep_rx_count_common(rxc, count); diff --git a/STM32F1/cores/maple/usb_serial.h b/STM32F1/cores/maple/usb_serial.h index e50a16c..96bbefc 100644 --- a/STM32F1/cores/maple/usb_serial.h +++ b/STM32F1/cores/maple/usb_serial.h @@ -65,7 +65,7 @@ public: size_t write(uint8); size_t write(const char *str); - size_t write(const void*, uint32); + size_t write(const uint8*, uint32); uint8 getRTS(); uint8 getDTR(); diff --git a/STM32F1/system/libmaple/usb/stm32f1/usb_reg_map.h b/STM32F1/system/libmaple/usb/stm32f1/usb_reg_map.h index 9e9214c..d0423fc 100644 --- a/STM32F1/system/libmaple/usb/stm32f1/usb_reg_map.h +++ b/STM32F1/system/libmaple/usb/stm32f1/usb_reg_map.h @@ -345,10 +345,10 @@ static inline void usb_clear_status_out(uint8 ep) { /* * PMA conveniences */ - +/* void usb_copy_to_pma(const uint8 *buf, uint16 len, uint16 pma_offset); void usb_copy_from_pma(uint8 *buf, uint16 len, uint16 pma_offset); - +*/ static inline uint32 * usb_pma_ptr(uint32 offset) { return (uint32*)(USB_PMA_BASE + 2 * offset); } @@ -567,7 +567,7 @@ static inline uint16 usb_get_ep_rx_buf0_count(uint8 ep) { return usb_get_ep_tx_count(ep); } -void usb_set_ep_rx_buf0_count(uint8 ep, uint16 count); +//void usb_set_ep_rx_buf0_count(uint8 ep, uint16 count); static inline uint32* usb_ep_rx_buf1_count_ptr(uint8 ep) { return usb_ep_rx_count_ptr(ep); From 5db25232840ec8f0922a79e3a1a19a86f5397207 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Mon, 31 Oct 2016 22:29:40 +0100 Subject: [PATCH 04/25] improve SPI low level functions - optimize code and run-time --- STM32F1/cores/maple/libmaple/spi.c | 6 +- STM32F1/libraries/SPI/src/SPI.cpp | 180 ++++++++++------------------- STM32F1/libraries/SPI/src/SPI.h | 25 ++-- 3 files changed, 75 insertions(+), 136 deletions(-) diff --git a/STM32F1/cores/maple/libmaple/spi.c b/STM32F1/cores/maple/libmaple/spi.c index 1020c5b..64f06d3 100644 --- a/STM32F1/cores/maple/libmaple/spi.c +++ b/STM32F1/cores/maple/libmaple/spi.c @@ -84,7 +84,7 @@ void spi_slave_enable(spi_dev *dev, spi_mode mode, uint32 flags) { } /** - * @brief Nonblocking SPI transmit. + * @brief Blocking SPI transmit. * @param dev SPI port to use for transmission * @param buf Buffer to transmit. The sizeof buf's elements are * inferred from dev's data frame format (i.e., are @@ -95,7 +95,8 @@ void spi_slave_enable(spi_dev *dev, spi_mode mode, uint32 flags) { uint32 spi_tx(spi_dev *dev, const void *buf, uint32 len) { uint32 txed = 0; uint8 byte_frame = spi_dff(dev) == SPI_DFF_8_BIT; - while (spi_is_tx_empty(dev) && (txed < len)) { + while ( txed < len ) { + while ( spi_is_tx_empty(dev)==0 ); // wait Tx to be empty if (byte_frame) { dev->regs->DR = ((const uint8*)buf)[txed++]; } else { @@ -162,5 +163,6 @@ static void spi_reconfigure(spi_dev *dev, uint32 cr1_config) { spi_irq_disable(dev, SPI_INTERRUPTS_ALL); if ( (dev->regs->CR1&MASK)!=(cr1_config&MASK) ) spi_peripheral_disable(dev); dev->regs->CR1 = cr1_config; + //spi_rx_dma_enable(dev); spi_peripheral_enable(dev); } diff --git a/STM32F1/libraries/SPI/src/SPI.cpp b/STM32F1/libraries/SPI/src/SPI.cpp index 4eeec38..0832791 100644 --- a/STM32F1/libraries/SPI/src/SPI.cpp +++ b/STM32F1/libraries/SPI/src/SPI.cpp @@ -41,6 +41,8 @@ #include "boards.h" //#include "HardwareSerial.h" +/** Time in ms for DMA receive timeout */ +#define DMA_TIMEOUT 100 #if CYCLES_PER_MICROSECOND != 72 /* TODO [0.2.0?] something smarter than this */ @@ -304,138 +306,110 @@ void SPIClass::endTransaction(void) * I/O */ -uint8 SPIClass::read(void) { - uint8 buf[1]; - this->read(buf, 1); - return buf[0]; +uint8 SPIClass::read(void) +{ + while ( spi_is_rx_nonempty(_currentSetting->spi_d)==0 ) ; + return (uint8)spi_rx_reg(_currentSetting->spi_d); } -void SPIClass::read(uint8 *buf, uint32 len) { +void SPIClass::read(uint8 *buf, uint32 len) +{ + spi_reg_map * regs = _currentSetting->spi_d->regs; + uint8 b = (regs->DR); // clear the RX buffer in case a byte is waiting on it. uint32 rxed = 0; - while (rxed < len) { - while (!spi_is_rx_nonempty(_currentSetting->spi_d)) - ; - buf[rxed++] = (uint8)spi_rx_reg(_currentSetting->spi_d); + // start sequence + while ( rxed < len) { + regs->DR = 0x00FF; // " write the data item to be transmitted into the SPI_DR register (this clears the TXE flag)." + while ( (regs->SR & SPI_SR_RXNE)==0 ) ; // wait till data is available in the Rx register + buf[rxed++] = (uint8)(regs->DR); // read and store the received byte } } -void SPIClass::write(uint16 data) { - // this->write(&data, 1); - +void SPIClass::write(uint16 data) +{ /* Added for 16bit data Victor Perez. Roger Clark - * Improved speed by just directly writing the single byte to the SPI data reg and wait for completion, * by taking the Tx code from transfer(byte) - * The original method, of calling write(*data, length) . + * Improved speed by just directly writing the single byte to the SPI data reg and wait for completion, + * by taking the Tx code from transfer(byte) * This almost doubles the speed of this function. */ - spi_tx_reg(_currentSetting->spi_d, data); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)." while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." } -//void SPIClass::write(uint8 byte) { - // this->write(&byte, 1); - - /* Roger Clark - * Improved speed by just directly writing the single byte to the SPI data reg and wait for completion, * by taking the Tx code from transfer(byte) - * The original method, of calling write(*data, length) . - * This almost doubles the speed of this function. - */ - -// spi_tx_reg(_currentSetting->spi_d, byte); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)." -// while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." -// while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." -//} - -void SPIClass::write(const uint8 *data, uint32 length) { - uint32 txed = 0; - while (txed < length) { - txed += spi_tx(_currentSetting->spi_d, data + txed, length - txed); - } - while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "4. After writing the last data item into the SPI_DR register, wait until TXE=1 ..." - while (spi_is_busy(_currentSetting->spi_d) != 0); // "... then wait until BSY=0, this indicates that the transmission of the last data is complete." +void SPIClass::write(const void *data, uint32 length) +{ + spi_tx(_currentSetting->spi_d, data, length); // data can be array of bytes or words + while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." + while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." // taken from SdSpiSTM32F1.cpp - Victor's lib, and adapted to support device selection - if (spi_is_rx_nonempty(_currentSetting->spi_d)) { - uint8_t b = spi_rx_reg(_currentSetting->spi_d); - } + uint16 b = spi_rx_reg(_currentSetting->spi_d); // dummy read, needed, don't remove! } uint16_t SPIClass::transfer16(uint16_t wr_data) const { spi_tx_reg(_currentSetting->spi_d, wr_data); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)." - while (spi_is_rx_nonempty(_currentSetting->spi_d) == 0); // "4. Wait until RXNE=1 ..." - uint16_t rd_data = spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data." -// while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." -// while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." - return rd_data; + while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." + while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." + return (uint16)spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data." } uint8 SPIClass::transfer(uint8 byte) const { spi_tx_reg(_currentSetting->spi_d, byte); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)." - while (spi_is_rx_nonempty(_currentSetting->spi_d) == 0); // "4. Wait until RXNE=1 ..." - uint8 b = spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data." - while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." - while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." - return b; + while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." + while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." + return (uint8)spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data." } + /* Roger Clark and Victor Perez, 2015 * Performs a DMA SPI transfer with at least a receive buffer. -* If a TX buffer is not provided, FF is sent over and over for the lenght of the transfer. -* On exit TX buffer is not modified, and RX buffer cotains the received data. +* If a TX buffer is not provided, FF is sent over and over for the length of the transfer. +* On exit TX buffer is not modified, and RX buffer contains the received data. * Still in progress. */ -uint8 SPIClass::dmaTransfer(uint8 *transmitBuf, uint8 *receiveBuf, uint16 length) { +uint8 SPIClass::dmaTransfer(void * transmitBuf, void * receiveBuf, uint16 length) +{ if (length == 0) return 0; uint8 b = 0; - if (spi_is_rx_nonempty(_currentSetting->spi_d) == 1) b = spi_rx_reg(_currentSetting->spi_d); //Clear the RX buffer in case a byte is waiting on it. + spi_rx_reg(_currentSetting->spi_d); //Clear the RX buffer in case a byte is waiting on it. // dma1_ch3_Active=true; dma_init(_currentSetting->spiDmaDev); // dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event); - + // RX spi_rx_dma_enable(_currentSetting->spi_d); - dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_8BITS, - receiveBuf, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_TRNS_CMPLT));// receive buffer DMA + dma_xfer_size dma_bit_size = (_currentSetting->dataSize==DATA_SIZE_8BIT) ? DMA_SIZE_8BITS : DMA_SIZE_16BITS; + dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size, + receiveBuf, dma_bit_size, (DMA_MINC_MODE | DMA_TRNS_CMPLT));// receive buffer DMA dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, length); - + // TX + uint32 flags = (DMA_MINC_MODE | DMA_FROM_MEM | DMA_TRNS_CMPLT); spi_tx_dma_enable(_currentSetting->spi_d); - if (!transmitBuf) { - static uint8_t ff = 0XFF; - transmitBuf = &ff; - dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_8BITS, - transmitBuf, DMA_SIZE_8BITS, (DMA_FROM_MEM | DMA_TRNS_CMPLT));// Transmit FF repeatedly - } - else { - dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_8BITS, - transmitBuf, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_FROM_MEM | DMA_TRNS_CMPLT));// Transmit buffer DMA + if ( transmitBuf==0 ) { + static uint8_t ff = 0XFF; + transmitBuf = &ff; + flags ^= DMA_MINC_MODE; // remove increment mode } + dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size, + transmitBuf, dma_bit_size, flags);// Transmit buffer DMA dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length); dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel);// enable receive dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit -// while (dma1_ch3_Active); -// if (receiveBuf) { uint32_t m = millis(); while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & 0x2)==0) {//Avoid interrupts and just loop waiting for the flag to be set. - if ((millis() - m) > 100) { -// dma1_ch3_Active = 0; - b = 2; - break; - } + if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; } } dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); -// } while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel); spi_rx_dma_disable(_currentSetting->spi_d); // And disable generation of DMA request from the SPI port so other peripherals can use the channels spi_tx_dma_disable(_currentSetting->spi_d); - if (spi_is_rx_nonempty(_currentSetting->spi_d) != 0){; // "4. Wait until RXNE=1 ..." - uint8 x = spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data." - } + uint16 x = spi_rx_reg(_currentSetting->spi_d); // dummy read, needed, don't remove! return b; } @@ -443,10 +417,12 @@ uint8 SPIClass::dmaTransfer(uint8 *transmitBuf, uint8 *receiveBuf, uint16 length * Performs a DMA SPI send using a TX buffer. * On exit TX buffer is not modified. * Still in progress. +* 2016 - stevstrong - reworked to automatically detect bit size from SPI setting */ -uint8 SPIClass::dmaSend(uint8 *transmitBuf, uint16 length, bool minc) { +uint8 SPIClass::dmaSend(void * transmitBuf, uint16 length) +{ if (length == 0) return 0; - uint32 flags = ((DMA_MINC_MODE * minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT); + uint32 flags = (DMA_MINC_MODE | DMA_FROM_MEM | DMA_TRNS_CMPLT); uint8 b = 0; // dma1_ch3_Active=true; dma_init(_currentSetting->spiDmaDev); @@ -454,55 +430,27 @@ uint8 SPIClass::dmaSend(uint8 *transmitBuf, uint16 length, bool minc) { // TX spi_tx_dma_enable(_currentSetting->spi_d); - dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_8BITS, - transmitBuf, DMA_SIZE_8BITS, flags);// Transmit buffer DMA + dma_xfer_size dma_bit_size = (_currentSetting->dataSize==DATA_SIZE_8BIT) ? DMA_SIZE_8BITS : DMA_SIZE_16BITS; + dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size, + transmitBuf, dma_bit_size, flags);// Transmit buffer DMA dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length); dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit - + // while (dma1_ch3_Active); - while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & 0x2)==0); //Avoid interrupts and just loop waiting for the flag to be set. + uint32_t m = millis(); + while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & 0x2)==0) {//Avoid interrupts and just loop waiting for the flag to be set. + if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; } + } dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); spi_tx_dma_disable(_currentSetting->spi_d); - if (spi_is_rx_nonempty(_currentSetting->spi_d) != 0){; // "4. Wait until RXNE=1 ..." - uint8 x = spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data." - } + uint16 x = spi_rx_reg(_currentSetting->spi_d); // dummy read, needed, don't remove! return b; } -uint8 SPIClass::dmaSend(uint16 *transmitBuf, uint16 length, bool minc) { - if (length == 0) return 0; - uint32 flags = ((DMA_MINC_MODE * minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT); - uint8 b; - dma1_ch3_Active=true; - dma_init(_currentSetting->spiDmaDev); -// dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event); - - // TX - spi_tx_dma_enable(_currentSetting->spi_d); - dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_16BITS, - transmitBuf, DMA_SIZE_16BITS, flags);// Transmit buffer DMA - dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length); - dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit - -// while (dma1_ch3_Active); - while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & 0x2)==0); //Avoid interrupts and just loop waiting for the flag to be set. - dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); - - while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." - while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." - dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); - spi_tx_dma_disable(_currentSetting->spi_d); - if (spi_is_rx_nonempty(_currentSetting->spi_d) != 0){; // "4. Wait until RXNE=1 ..." - b = spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data." - } - return b; -} - - void SPIClass::attachInterrupt(void) { // Should be enableInterrupt() } diff --git a/STM32F1/libraries/SPI/src/SPI.h b/STM32F1/libraries/SPI/src/SPI.h index e949051..0f8497a 100644 --- a/STM32F1/libraries/SPI/src/SPI.h +++ b/STM32F1/libraries/SPI/src/SPI.h @@ -249,7 +249,7 @@ public: * @param buffer Bytes to transmit. * @param length Number of bytes in buffer to transmit. */ - void write(const uint8 *buffer, uint32 length); + void write(const void * buffer, uint32 length); /** * @brief Transmit a byte, then return the next unread byte. @@ -264,6 +264,7 @@ public: /** * @brief Sets up a DMA Transfer for "length" bytes. + * The transfer mode (8 or 16 bit mode) is evaluated from the SPI peripheral setting. * * This function transmits and receives to buffers. * @@ -271,30 +272,18 @@ public: * @param receiveBuf buffer Bytes to save received data. * @param length Number of bytes in buffer to transmit. */ - uint8 dmaTransfer(uint8 *transmitBuf, uint8 *receiveBuf, uint16 length); + uint8 dmaTransfer(void * transmitBuf, void * receiveBuf, uint16 length); /** - * @brief Sets up a DMA Transmit for bytes. + * @brief Sets up a DMA Transmit for SPI 8 or 16 bit transfer mode. + * The transfer mode (8 or 16 bit mode) is evaluated from the SPI peripheral setting. * - * This function transmits and does not care about the RX fifo. - * - * @param transmitBuf buffer Bytes to transmit, - * @param length Number of bytes in buffer to transmit. - * @param minc Set to use Memory Increment mode, clear to use Circular mode. - */ - uint8 dmaSend(uint8 *transmitBuf, uint16 length, bool minc = 1); - - /** - * @brief Sets up a DMA Transmit for half words. - * SPI PERFIPHERAL MUST BE SET TO 16 BIT MODE BEFORE - * - * This function transmits and does not care about the RX fifo. + * This function only transmits and does not care about the RX fifo. * * @param data buffer half words to transmit, * @param length Number of bytes in buffer to transmit. - * @param minc Set to use Memory Increment mode (default if blank), clear to use Circular mode. */ - uint8 dmaSend(uint16 *transmitBuf, uint16 length, bool minc = 1); + uint8 dmaSend(void * transmitBuf, uint16 length); /* * Pin accessors From 3469ef291baad000b3c64564623d7a09e1312356 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Fri, 11 Nov 2016 22:04:16 +0100 Subject: [PATCH 05/25] Revert "improve SPI low level functions" This reverts commit 5db25232840ec8f0922a79e3a1a19a86f5397207. --- STM32F1/cores/maple/libmaple/spi.c | 6 +- STM32F1/libraries/SPI/src/SPI.cpp | 180 +++++++++++++++++++---------- STM32F1/libraries/SPI/src/SPI.h | 25 ++-- 3 files changed, 136 insertions(+), 75 deletions(-) diff --git a/STM32F1/cores/maple/libmaple/spi.c b/STM32F1/cores/maple/libmaple/spi.c index 64f06d3..1020c5b 100644 --- a/STM32F1/cores/maple/libmaple/spi.c +++ b/STM32F1/cores/maple/libmaple/spi.c @@ -84,7 +84,7 @@ void spi_slave_enable(spi_dev *dev, spi_mode mode, uint32 flags) { } /** - * @brief Blocking SPI transmit. + * @brief Nonblocking SPI transmit. * @param dev SPI port to use for transmission * @param buf Buffer to transmit. The sizeof buf's elements are * inferred from dev's data frame format (i.e., are @@ -95,8 +95,7 @@ void spi_slave_enable(spi_dev *dev, spi_mode mode, uint32 flags) { uint32 spi_tx(spi_dev *dev, const void *buf, uint32 len) { uint32 txed = 0; uint8 byte_frame = spi_dff(dev) == SPI_DFF_8_BIT; - while ( txed < len ) { - while ( spi_is_tx_empty(dev)==0 ); // wait Tx to be empty + while (spi_is_tx_empty(dev) && (txed < len)) { if (byte_frame) { dev->regs->DR = ((const uint8*)buf)[txed++]; } else { @@ -163,6 +162,5 @@ static void spi_reconfigure(spi_dev *dev, uint32 cr1_config) { spi_irq_disable(dev, SPI_INTERRUPTS_ALL); if ( (dev->regs->CR1&MASK)!=(cr1_config&MASK) ) spi_peripheral_disable(dev); dev->regs->CR1 = cr1_config; - //spi_rx_dma_enable(dev); spi_peripheral_enable(dev); } diff --git a/STM32F1/libraries/SPI/src/SPI.cpp b/STM32F1/libraries/SPI/src/SPI.cpp index 0832791..4eeec38 100644 --- a/STM32F1/libraries/SPI/src/SPI.cpp +++ b/STM32F1/libraries/SPI/src/SPI.cpp @@ -41,8 +41,6 @@ #include "boards.h" //#include "HardwareSerial.h" -/** Time in ms for DMA receive timeout */ -#define DMA_TIMEOUT 100 #if CYCLES_PER_MICROSECOND != 72 /* TODO [0.2.0?] something smarter than this */ @@ -306,110 +304,138 @@ void SPIClass::endTransaction(void) * I/O */ -uint8 SPIClass::read(void) -{ - while ( spi_is_rx_nonempty(_currentSetting->spi_d)==0 ) ; - return (uint8)spi_rx_reg(_currentSetting->spi_d); +uint8 SPIClass::read(void) { + uint8 buf[1]; + this->read(buf, 1); + return buf[0]; } -void SPIClass::read(uint8 *buf, uint32 len) -{ - spi_reg_map * regs = _currentSetting->spi_d->regs; - uint8 b = (regs->DR); // clear the RX buffer in case a byte is waiting on it. +void SPIClass::read(uint8 *buf, uint32 len) { uint32 rxed = 0; - // start sequence - while ( rxed < len) { - regs->DR = 0x00FF; // " write the data item to be transmitted into the SPI_DR register (this clears the TXE flag)." - while ( (regs->SR & SPI_SR_RXNE)==0 ) ; // wait till data is available in the Rx register - buf[rxed++] = (uint8)(regs->DR); // read and store the received byte + while (rxed < len) { + while (!spi_is_rx_nonempty(_currentSetting->spi_d)) + ; + buf[rxed++] = (uint8)spi_rx_reg(_currentSetting->spi_d); } } -void SPIClass::write(uint16 data) -{ +void SPIClass::write(uint16 data) { + // this->write(&data, 1); + /* Added for 16bit data Victor Perez. Roger Clark - * Improved speed by just directly writing the single byte to the SPI data reg and wait for completion, - * by taking the Tx code from transfer(byte) + * Improved speed by just directly writing the single byte to the SPI data reg and wait for completion, * by taking the Tx code from transfer(byte) + * The original method, of calling write(*data, length) . * This almost doubles the speed of this function. */ + spi_tx_reg(_currentSetting->spi_d, data); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)." while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." } -void SPIClass::write(const void *data, uint32 length) -{ - spi_tx(_currentSetting->spi_d, data, length); // data can be array of bytes or words - while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." - while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." +//void SPIClass::write(uint8 byte) { + // this->write(&byte, 1); + + /* Roger Clark + * Improved speed by just directly writing the single byte to the SPI data reg and wait for completion, * by taking the Tx code from transfer(byte) + * The original method, of calling write(*data, length) . + * This almost doubles the speed of this function. + */ + +// spi_tx_reg(_currentSetting->spi_d, byte); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)." +// while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." +// while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." +//} + +void SPIClass::write(const uint8 *data, uint32 length) { + uint32 txed = 0; + while (txed < length) { + txed += spi_tx(_currentSetting->spi_d, data + txed, length - txed); + } + while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "4. After writing the last data item into the SPI_DR register, wait until TXE=1 ..." + while (spi_is_busy(_currentSetting->spi_d) != 0); // "... then wait until BSY=0, this indicates that the transmission of the last data is complete." // taken from SdSpiSTM32F1.cpp - Victor's lib, and adapted to support device selection - uint16 b = spi_rx_reg(_currentSetting->spi_d); // dummy read, needed, don't remove! + if (spi_is_rx_nonempty(_currentSetting->spi_d)) { + uint8_t b = spi_rx_reg(_currentSetting->spi_d); + } } uint16_t SPIClass::transfer16(uint16_t wr_data) const { spi_tx_reg(_currentSetting->spi_d, wr_data); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)." - while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." - while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." - return (uint16)spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data." + while (spi_is_rx_nonempty(_currentSetting->spi_d) == 0); // "4. Wait until RXNE=1 ..." + uint16_t rd_data = spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data." +// while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." +// while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." + return rd_data; } uint8 SPIClass::transfer(uint8 byte) const { spi_tx_reg(_currentSetting->spi_d, byte); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)." - while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." - while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." - return (uint8)spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data." + while (spi_is_rx_nonempty(_currentSetting->spi_d) == 0); // "4. Wait until RXNE=1 ..." + uint8 b = spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data." + while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." + while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." + return b; } - /* Roger Clark and Victor Perez, 2015 * Performs a DMA SPI transfer with at least a receive buffer. -* If a TX buffer is not provided, FF is sent over and over for the length of the transfer. -* On exit TX buffer is not modified, and RX buffer contains the received data. +* If a TX buffer is not provided, FF is sent over and over for the lenght of the transfer. +* On exit TX buffer is not modified, and RX buffer cotains the received data. * Still in progress. */ -uint8 SPIClass::dmaTransfer(void * transmitBuf, void * receiveBuf, uint16 length) -{ +uint8 SPIClass::dmaTransfer(uint8 *transmitBuf, uint8 *receiveBuf, uint16 length) { if (length == 0) return 0; uint8 b = 0; - spi_rx_reg(_currentSetting->spi_d); //Clear the RX buffer in case a byte is waiting on it. + if (spi_is_rx_nonempty(_currentSetting->spi_d) == 1) b = spi_rx_reg(_currentSetting->spi_d); //Clear the RX buffer in case a byte is waiting on it. // dma1_ch3_Active=true; dma_init(_currentSetting->spiDmaDev); // dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event); - + // RX spi_rx_dma_enable(_currentSetting->spi_d); - dma_xfer_size dma_bit_size = (_currentSetting->dataSize==DATA_SIZE_8BIT) ? DMA_SIZE_8BITS : DMA_SIZE_16BITS; - dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size, - receiveBuf, dma_bit_size, (DMA_MINC_MODE | DMA_TRNS_CMPLT));// receive buffer DMA + dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_8BITS, + receiveBuf, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_TRNS_CMPLT));// receive buffer DMA dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, length); - + // TX - uint32 flags = (DMA_MINC_MODE | DMA_FROM_MEM | DMA_TRNS_CMPLT); spi_tx_dma_enable(_currentSetting->spi_d); - if ( transmitBuf==0 ) { - static uint8_t ff = 0XFF; - transmitBuf = &ff; - flags ^= DMA_MINC_MODE; // remove increment mode + if (!transmitBuf) { + static uint8_t ff = 0XFF; + transmitBuf = &ff; + dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_8BITS, + transmitBuf, DMA_SIZE_8BITS, (DMA_FROM_MEM | DMA_TRNS_CMPLT));// Transmit FF repeatedly + } + else { + dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_8BITS, + transmitBuf, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_FROM_MEM | DMA_TRNS_CMPLT));// Transmit buffer DMA } - dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size, - transmitBuf, dma_bit_size, flags);// Transmit buffer DMA dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length); dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel);// enable receive dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit +// while (dma1_ch3_Active); +// if (receiveBuf) { uint32_t m = millis(); while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & 0x2)==0) {//Avoid interrupts and just loop waiting for the flag to be set. - if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; } + if ((millis() - m) > 100) { +// dma1_ch3_Active = 0; + b = 2; + break; + } } dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); +// } while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel); spi_rx_dma_disable(_currentSetting->spi_d); // And disable generation of DMA request from the SPI port so other peripherals can use the channels spi_tx_dma_disable(_currentSetting->spi_d); - uint16 x = spi_rx_reg(_currentSetting->spi_d); // dummy read, needed, don't remove! + if (spi_is_rx_nonempty(_currentSetting->spi_d) != 0){; // "4. Wait until RXNE=1 ..." + uint8 x = spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data." + } return b; } @@ -417,12 +443,10 @@ uint8 SPIClass::dmaTransfer(void * transmitBuf, void * receiveBuf, uint16 length * Performs a DMA SPI send using a TX buffer. * On exit TX buffer is not modified. * Still in progress. -* 2016 - stevstrong - reworked to automatically detect bit size from SPI setting */ -uint8 SPIClass::dmaSend(void * transmitBuf, uint16 length) -{ +uint8 SPIClass::dmaSend(uint8 *transmitBuf, uint16 length, bool minc) { if (length == 0) return 0; - uint32 flags = (DMA_MINC_MODE | DMA_FROM_MEM | DMA_TRNS_CMPLT); + uint32 flags = ((DMA_MINC_MODE * minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT); uint8 b = 0; // dma1_ch3_Active=true; dma_init(_currentSetting->spiDmaDev); @@ -430,27 +454,55 @@ uint8 SPIClass::dmaSend(void * transmitBuf, uint16 length) // TX spi_tx_dma_enable(_currentSetting->spi_d); - dma_xfer_size dma_bit_size = (_currentSetting->dataSize==DATA_SIZE_8BIT) ? DMA_SIZE_8BITS : DMA_SIZE_16BITS; - dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size, - transmitBuf, dma_bit_size, flags);// Transmit buffer DMA + dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_8BITS, + transmitBuf, DMA_SIZE_8BITS, flags);// Transmit buffer DMA dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length); dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit - + // while (dma1_ch3_Active); - uint32_t m = millis(); - while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & 0x2)==0) {//Avoid interrupts and just loop waiting for the flag to be set. - if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; } - } + while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & 0x2)==0); //Avoid interrupts and just loop waiting for the flag to be set. dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); spi_tx_dma_disable(_currentSetting->spi_d); - uint16 x = spi_rx_reg(_currentSetting->spi_d); // dummy read, needed, don't remove! + if (spi_is_rx_nonempty(_currentSetting->spi_d) != 0){; // "4. Wait until RXNE=1 ..." + uint8 x = spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data." + } return b; } +uint8 SPIClass::dmaSend(uint16 *transmitBuf, uint16 length, bool minc) { + if (length == 0) return 0; + uint32 flags = ((DMA_MINC_MODE * minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT); + uint8 b; + dma1_ch3_Active=true; + dma_init(_currentSetting->spiDmaDev); +// dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event); + + // TX + spi_tx_dma_enable(_currentSetting->spi_d); + dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_16BITS, + transmitBuf, DMA_SIZE_16BITS, flags);// Transmit buffer DMA + dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length); + dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit + +// while (dma1_ch3_Active); + while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & 0x2)==0); //Avoid interrupts and just loop waiting for the flag to be set. + dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); + + while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." + while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." + dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); + spi_tx_dma_disable(_currentSetting->spi_d); + if (spi_is_rx_nonempty(_currentSetting->spi_d) != 0){; // "4. Wait until RXNE=1 ..." + b = spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data." + } + return b; +} + + void SPIClass::attachInterrupt(void) { // Should be enableInterrupt() } diff --git a/STM32F1/libraries/SPI/src/SPI.h b/STM32F1/libraries/SPI/src/SPI.h index 0f8497a..e949051 100644 --- a/STM32F1/libraries/SPI/src/SPI.h +++ b/STM32F1/libraries/SPI/src/SPI.h @@ -249,7 +249,7 @@ public: * @param buffer Bytes to transmit. * @param length Number of bytes in buffer to transmit. */ - void write(const void * buffer, uint32 length); + void write(const uint8 *buffer, uint32 length); /** * @brief Transmit a byte, then return the next unread byte. @@ -264,7 +264,6 @@ public: /** * @brief Sets up a DMA Transfer for "length" bytes. - * The transfer mode (8 or 16 bit mode) is evaluated from the SPI peripheral setting. * * This function transmits and receives to buffers. * @@ -272,18 +271,30 @@ public: * @param receiveBuf buffer Bytes to save received data. * @param length Number of bytes in buffer to transmit. */ - uint8 dmaTransfer(void * transmitBuf, void * receiveBuf, uint16 length); + uint8 dmaTransfer(uint8 *transmitBuf, uint8 *receiveBuf, uint16 length); /** - * @brief Sets up a DMA Transmit for SPI 8 or 16 bit transfer mode. - * The transfer mode (8 or 16 bit mode) is evaluated from the SPI peripheral setting. + * @brief Sets up a DMA Transmit for bytes. * - * This function only transmits and does not care about the RX fifo. + * This function transmits and does not care about the RX fifo. + * + * @param transmitBuf buffer Bytes to transmit, + * @param length Number of bytes in buffer to transmit. + * @param minc Set to use Memory Increment mode, clear to use Circular mode. + */ + uint8 dmaSend(uint8 *transmitBuf, uint16 length, bool minc = 1); + + /** + * @brief Sets up a DMA Transmit for half words. + * SPI PERFIPHERAL MUST BE SET TO 16 BIT MODE BEFORE + * + * This function transmits and does not care about the RX fifo. * * @param data buffer half words to transmit, * @param length Number of bytes in buffer to transmit. + * @param minc Set to use Memory Increment mode (default if blank), clear to use Circular mode. */ - uint8 dmaSend(void * transmitBuf, uint16 length); + uint8 dmaSend(uint16 *transmitBuf, uint16 length, bool minc = 1); /* * Pin accessors From b2e349ca36d245869111db0502123b08c318f5e7 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Fri, 11 Nov 2016 22:12:13 +0100 Subject: [PATCH 06/25] Revert "Revert "improve SPI low level functions"" This reverts commit 3469ef291baad000b3c64564623d7a09e1312356. --- STM32F1/cores/maple/libmaple/spi.c | 6 +- STM32F1/libraries/SPI/src/SPI.cpp | 180 ++++++++++------------------- STM32F1/libraries/SPI/src/SPI.h | 25 ++-- 3 files changed, 75 insertions(+), 136 deletions(-) diff --git a/STM32F1/cores/maple/libmaple/spi.c b/STM32F1/cores/maple/libmaple/spi.c index 1020c5b..64f06d3 100644 --- a/STM32F1/cores/maple/libmaple/spi.c +++ b/STM32F1/cores/maple/libmaple/spi.c @@ -84,7 +84,7 @@ void spi_slave_enable(spi_dev *dev, spi_mode mode, uint32 flags) { } /** - * @brief Nonblocking SPI transmit. + * @brief Blocking SPI transmit. * @param dev SPI port to use for transmission * @param buf Buffer to transmit. The sizeof buf's elements are * inferred from dev's data frame format (i.e., are @@ -95,7 +95,8 @@ void spi_slave_enable(spi_dev *dev, spi_mode mode, uint32 flags) { uint32 spi_tx(spi_dev *dev, const void *buf, uint32 len) { uint32 txed = 0; uint8 byte_frame = spi_dff(dev) == SPI_DFF_8_BIT; - while (spi_is_tx_empty(dev) && (txed < len)) { + while ( txed < len ) { + while ( spi_is_tx_empty(dev)==0 ); // wait Tx to be empty if (byte_frame) { dev->regs->DR = ((const uint8*)buf)[txed++]; } else { @@ -162,5 +163,6 @@ static void spi_reconfigure(spi_dev *dev, uint32 cr1_config) { spi_irq_disable(dev, SPI_INTERRUPTS_ALL); if ( (dev->regs->CR1&MASK)!=(cr1_config&MASK) ) spi_peripheral_disable(dev); dev->regs->CR1 = cr1_config; + //spi_rx_dma_enable(dev); spi_peripheral_enable(dev); } diff --git a/STM32F1/libraries/SPI/src/SPI.cpp b/STM32F1/libraries/SPI/src/SPI.cpp index 4eeec38..0832791 100644 --- a/STM32F1/libraries/SPI/src/SPI.cpp +++ b/STM32F1/libraries/SPI/src/SPI.cpp @@ -41,6 +41,8 @@ #include "boards.h" //#include "HardwareSerial.h" +/** Time in ms for DMA receive timeout */ +#define DMA_TIMEOUT 100 #if CYCLES_PER_MICROSECOND != 72 /* TODO [0.2.0?] something smarter than this */ @@ -304,138 +306,110 @@ void SPIClass::endTransaction(void) * I/O */ -uint8 SPIClass::read(void) { - uint8 buf[1]; - this->read(buf, 1); - return buf[0]; +uint8 SPIClass::read(void) +{ + while ( spi_is_rx_nonempty(_currentSetting->spi_d)==0 ) ; + return (uint8)spi_rx_reg(_currentSetting->spi_d); } -void SPIClass::read(uint8 *buf, uint32 len) { +void SPIClass::read(uint8 *buf, uint32 len) +{ + spi_reg_map * regs = _currentSetting->spi_d->regs; + uint8 b = (regs->DR); // clear the RX buffer in case a byte is waiting on it. uint32 rxed = 0; - while (rxed < len) { - while (!spi_is_rx_nonempty(_currentSetting->spi_d)) - ; - buf[rxed++] = (uint8)spi_rx_reg(_currentSetting->spi_d); + // start sequence + while ( rxed < len) { + regs->DR = 0x00FF; // " write the data item to be transmitted into the SPI_DR register (this clears the TXE flag)." + while ( (regs->SR & SPI_SR_RXNE)==0 ) ; // wait till data is available in the Rx register + buf[rxed++] = (uint8)(regs->DR); // read and store the received byte } } -void SPIClass::write(uint16 data) { - // this->write(&data, 1); - +void SPIClass::write(uint16 data) +{ /* Added for 16bit data Victor Perez. Roger Clark - * Improved speed by just directly writing the single byte to the SPI data reg and wait for completion, * by taking the Tx code from transfer(byte) - * The original method, of calling write(*data, length) . + * Improved speed by just directly writing the single byte to the SPI data reg and wait for completion, + * by taking the Tx code from transfer(byte) * This almost doubles the speed of this function. */ - spi_tx_reg(_currentSetting->spi_d, data); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)." while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." } -//void SPIClass::write(uint8 byte) { - // this->write(&byte, 1); - - /* Roger Clark - * Improved speed by just directly writing the single byte to the SPI data reg and wait for completion, * by taking the Tx code from transfer(byte) - * The original method, of calling write(*data, length) . - * This almost doubles the speed of this function. - */ - -// spi_tx_reg(_currentSetting->spi_d, byte); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)." -// while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." -// while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." -//} - -void SPIClass::write(const uint8 *data, uint32 length) { - uint32 txed = 0; - while (txed < length) { - txed += spi_tx(_currentSetting->spi_d, data + txed, length - txed); - } - while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "4. After writing the last data item into the SPI_DR register, wait until TXE=1 ..." - while (spi_is_busy(_currentSetting->spi_d) != 0); // "... then wait until BSY=0, this indicates that the transmission of the last data is complete." +void SPIClass::write(const void *data, uint32 length) +{ + spi_tx(_currentSetting->spi_d, data, length); // data can be array of bytes or words + while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." + while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." // taken from SdSpiSTM32F1.cpp - Victor's lib, and adapted to support device selection - if (spi_is_rx_nonempty(_currentSetting->spi_d)) { - uint8_t b = spi_rx_reg(_currentSetting->spi_d); - } + uint16 b = spi_rx_reg(_currentSetting->spi_d); // dummy read, needed, don't remove! } uint16_t SPIClass::transfer16(uint16_t wr_data) const { spi_tx_reg(_currentSetting->spi_d, wr_data); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)." - while (spi_is_rx_nonempty(_currentSetting->spi_d) == 0); // "4. Wait until RXNE=1 ..." - uint16_t rd_data = spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data." -// while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." -// while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." - return rd_data; + while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." + while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." + return (uint16)spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data." } uint8 SPIClass::transfer(uint8 byte) const { spi_tx_reg(_currentSetting->spi_d, byte); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)." - while (spi_is_rx_nonempty(_currentSetting->spi_d) == 0); // "4. Wait until RXNE=1 ..." - uint8 b = spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data." - while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." - while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." - return b; + while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." + while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." + return (uint8)spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data." } + /* Roger Clark and Victor Perez, 2015 * Performs a DMA SPI transfer with at least a receive buffer. -* If a TX buffer is not provided, FF is sent over and over for the lenght of the transfer. -* On exit TX buffer is not modified, and RX buffer cotains the received data. +* If a TX buffer is not provided, FF is sent over and over for the length of the transfer. +* On exit TX buffer is not modified, and RX buffer contains the received data. * Still in progress. */ -uint8 SPIClass::dmaTransfer(uint8 *transmitBuf, uint8 *receiveBuf, uint16 length) { +uint8 SPIClass::dmaTransfer(void * transmitBuf, void * receiveBuf, uint16 length) +{ if (length == 0) return 0; uint8 b = 0; - if (spi_is_rx_nonempty(_currentSetting->spi_d) == 1) b = spi_rx_reg(_currentSetting->spi_d); //Clear the RX buffer in case a byte is waiting on it. + spi_rx_reg(_currentSetting->spi_d); //Clear the RX buffer in case a byte is waiting on it. // dma1_ch3_Active=true; dma_init(_currentSetting->spiDmaDev); // dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event); - + // RX spi_rx_dma_enable(_currentSetting->spi_d); - dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_8BITS, - receiveBuf, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_TRNS_CMPLT));// receive buffer DMA + dma_xfer_size dma_bit_size = (_currentSetting->dataSize==DATA_SIZE_8BIT) ? DMA_SIZE_8BITS : DMA_SIZE_16BITS; + dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size, + receiveBuf, dma_bit_size, (DMA_MINC_MODE | DMA_TRNS_CMPLT));// receive buffer DMA dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, length); - + // TX + uint32 flags = (DMA_MINC_MODE | DMA_FROM_MEM | DMA_TRNS_CMPLT); spi_tx_dma_enable(_currentSetting->spi_d); - if (!transmitBuf) { - static uint8_t ff = 0XFF; - transmitBuf = &ff; - dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_8BITS, - transmitBuf, DMA_SIZE_8BITS, (DMA_FROM_MEM | DMA_TRNS_CMPLT));// Transmit FF repeatedly - } - else { - dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_8BITS, - transmitBuf, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_FROM_MEM | DMA_TRNS_CMPLT));// Transmit buffer DMA + if ( transmitBuf==0 ) { + static uint8_t ff = 0XFF; + transmitBuf = &ff; + flags ^= DMA_MINC_MODE; // remove increment mode } + dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size, + transmitBuf, dma_bit_size, flags);// Transmit buffer DMA dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length); dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel);// enable receive dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit -// while (dma1_ch3_Active); -// if (receiveBuf) { uint32_t m = millis(); while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & 0x2)==0) {//Avoid interrupts and just loop waiting for the flag to be set. - if ((millis() - m) > 100) { -// dma1_ch3_Active = 0; - b = 2; - break; - } + if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; } } dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); -// } while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel); spi_rx_dma_disable(_currentSetting->spi_d); // And disable generation of DMA request from the SPI port so other peripherals can use the channels spi_tx_dma_disable(_currentSetting->spi_d); - if (spi_is_rx_nonempty(_currentSetting->spi_d) != 0){; // "4. Wait until RXNE=1 ..." - uint8 x = spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data." - } + uint16 x = spi_rx_reg(_currentSetting->spi_d); // dummy read, needed, don't remove! return b; } @@ -443,10 +417,12 @@ uint8 SPIClass::dmaTransfer(uint8 *transmitBuf, uint8 *receiveBuf, uint16 length * Performs a DMA SPI send using a TX buffer. * On exit TX buffer is not modified. * Still in progress. +* 2016 - stevstrong - reworked to automatically detect bit size from SPI setting */ -uint8 SPIClass::dmaSend(uint8 *transmitBuf, uint16 length, bool minc) { +uint8 SPIClass::dmaSend(void * transmitBuf, uint16 length) +{ if (length == 0) return 0; - uint32 flags = ((DMA_MINC_MODE * minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT); + uint32 flags = (DMA_MINC_MODE | DMA_FROM_MEM | DMA_TRNS_CMPLT); uint8 b = 0; // dma1_ch3_Active=true; dma_init(_currentSetting->spiDmaDev); @@ -454,55 +430,27 @@ uint8 SPIClass::dmaSend(uint8 *transmitBuf, uint16 length, bool minc) { // TX spi_tx_dma_enable(_currentSetting->spi_d); - dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_8BITS, - transmitBuf, DMA_SIZE_8BITS, flags);// Transmit buffer DMA + dma_xfer_size dma_bit_size = (_currentSetting->dataSize==DATA_SIZE_8BIT) ? DMA_SIZE_8BITS : DMA_SIZE_16BITS; + dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size, + transmitBuf, dma_bit_size, flags);// Transmit buffer DMA dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length); dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit - + // while (dma1_ch3_Active); - while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & 0x2)==0); //Avoid interrupts and just loop waiting for the flag to be set. + uint32_t m = millis(); + while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & 0x2)==0) {//Avoid interrupts and just loop waiting for the flag to be set. + if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; } + } dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); spi_tx_dma_disable(_currentSetting->spi_d); - if (spi_is_rx_nonempty(_currentSetting->spi_d) != 0){; // "4. Wait until RXNE=1 ..." - uint8 x = spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data." - } + uint16 x = spi_rx_reg(_currentSetting->spi_d); // dummy read, needed, don't remove! return b; } -uint8 SPIClass::dmaSend(uint16 *transmitBuf, uint16 length, bool minc) { - if (length == 0) return 0; - uint32 flags = ((DMA_MINC_MODE * minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT); - uint8 b; - dma1_ch3_Active=true; - dma_init(_currentSetting->spiDmaDev); -// dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event); - - // TX - spi_tx_dma_enable(_currentSetting->spi_d); - dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_16BITS, - transmitBuf, DMA_SIZE_16BITS, flags);// Transmit buffer DMA - dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length); - dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit - -// while (dma1_ch3_Active); - while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & 0x2)==0); //Avoid interrupts and just loop waiting for the flag to be set. - dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); - - while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." - while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." - dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); - spi_tx_dma_disable(_currentSetting->spi_d); - if (spi_is_rx_nonempty(_currentSetting->spi_d) != 0){; // "4. Wait until RXNE=1 ..." - b = spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data." - } - return b; -} - - void SPIClass::attachInterrupt(void) { // Should be enableInterrupt() } diff --git a/STM32F1/libraries/SPI/src/SPI.h b/STM32F1/libraries/SPI/src/SPI.h index e949051..0f8497a 100644 --- a/STM32F1/libraries/SPI/src/SPI.h +++ b/STM32F1/libraries/SPI/src/SPI.h @@ -249,7 +249,7 @@ public: * @param buffer Bytes to transmit. * @param length Number of bytes in buffer to transmit. */ - void write(const uint8 *buffer, uint32 length); + void write(const void * buffer, uint32 length); /** * @brief Transmit a byte, then return the next unread byte. @@ -264,6 +264,7 @@ public: /** * @brief Sets up a DMA Transfer for "length" bytes. + * The transfer mode (8 or 16 bit mode) is evaluated from the SPI peripheral setting. * * This function transmits and receives to buffers. * @@ -271,30 +272,18 @@ public: * @param receiveBuf buffer Bytes to save received data. * @param length Number of bytes in buffer to transmit. */ - uint8 dmaTransfer(uint8 *transmitBuf, uint8 *receiveBuf, uint16 length); + uint8 dmaTransfer(void * transmitBuf, void * receiveBuf, uint16 length); /** - * @brief Sets up a DMA Transmit for bytes. + * @brief Sets up a DMA Transmit for SPI 8 or 16 bit transfer mode. + * The transfer mode (8 or 16 bit mode) is evaluated from the SPI peripheral setting. * - * This function transmits and does not care about the RX fifo. - * - * @param transmitBuf buffer Bytes to transmit, - * @param length Number of bytes in buffer to transmit. - * @param minc Set to use Memory Increment mode, clear to use Circular mode. - */ - uint8 dmaSend(uint8 *transmitBuf, uint16 length, bool minc = 1); - - /** - * @brief Sets up a DMA Transmit for half words. - * SPI PERFIPHERAL MUST BE SET TO 16 BIT MODE BEFORE - * - * This function transmits and does not care about the RX fifo. + * This function only transmits and does not care about the RX fifo. * * @param data buffer half words to transmit, * @param length Number of bytes in buffer to transmit. - * @param minc Set to use Memory Increment mode (default if blank), clear to use Circular mode. */ - uint8 dmaSend(uint16 *transmitBuf, uint16 length, bool minc = 1); + uint8 dmaSend(void * transmitBuf, uint16 length); /* * Pin accessors From e7456e191650dc54b0fa8e7b95670f5621356265 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Sat, 10 Dec 2016 22:36:21 +0100 Subject: [PATCH 07/25] further optimizations - extend read function to 16bit - add repeated write the same byte/word a specified number of time - revert increment option to dmaSend --- STM32F1/cores/maple/libmaple/spi.c | 26 ++++++++++-------- STM32F1/libraries/SPI/src/SPI.cpp | 42 ++++++++++++++++++------------ STM32F1/libraries/SPI/src/SPI.h | 37 +++++++++++++++----------- 3 files changed, 63 insertions(+), 42 deletions(-) diff --git a/STM32F1/cores/maple/libmaple/spi.c b/STM32F1/cores/maple/libmaple/spi.c index 64f06d3..e0ee90d 100644 --- a/STM32F1/cores/maple/libmaple/spi.c +++ b/STM32F1/cores/maple/libmaple/spi.c @@ -93,16 +93,21 @@ void spi_slave_enable(spi_dev *dev, spi_mode mode, uint32 flags) { * @return Number of elements transmitted. */ uint32 spi_tx(spi_dev *dev, const void *buf, uint32 len) { - uint32 txed = 0; - uint8 byte_frame = spi_dff(dev) == SPI_DFF_8_BIT; - while ( txed < len ) { - while ( spi_is_tx_empty(dev)==0 ); // wait Tx to be empty - if (byte_frame) { - dev->regs->DR = ((const uint8*)buf)[txed++]; - } else { - dev->regs->DR = ((const uint16*)buf)[txed++]; - } - } + uint32 txed = len; + spi_reg_map *regs = dev->regs; + if ( spi_dff(dev) == SPI_DFF_8_BIT ) { + const uint8 * dp8 = (const uint8*)buf; + while ( len-- ) { + while ( (regs->SR & SPI_SR_TXE)==0 ) ; //while ( spi_is_tx_empty(dev)==0 ); // wait Tx to be empty + regs->DR = *dp8++; + } + } else { + const uint16 * dp16 = (const uint16*)buf; + while ( len-- ) { + while ( (regs->SR & SPI_SR_TXE)==0 ) ; //while ( spi_is_tx_empty(dev)==0 ); // wait Tx to be empty + regs->DR = *dp16++; + } + } return txed; } @@ -163,6 +168,5 @@ static void spi_reconfigure(spi_dev *dev, uint32 cr1_config) { spi_irq_disable(dev, SPI_INTERRUPTS_ALL); if ( (dev->regs->CR1&MASK)!=(cr1_config&MASK) ) spi_peripheral_disable(dev); dev->regs->CR1 = cr1_config; - //spi_rx_dma_enable(dev); spi_peripheral_enable(dev); } diff --git a/STM32F1/libraries/SPI/src/SPI.cpp b/STM32F1/libraries/SPI/src/SPI.cpp index 0832791..9b6e28e 100644 --- a/STM32F1/libraries/SPI/src/SPI.cpp +++ b/STM32F1/libraries/SPI/src/SPI.cpp @@ -160,7 +160,7 @@ void SPIClass::begin(void) { void SPIClass::beginSlave(void) { spi_init(_currentSetting->spi_d); configure_gpios(_currentSetting->spi_d, 0); - uint32 flags = ((_currentSetting->bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | _currentSetting->dataSize | SPI_SW_SLAVE); + uint32 flags = ((_currentSetting->bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | _currentSetting->dataSize | SPI_RX_ONLY); #ifdef SPI_DEBUG Serial.print("spi_slave_enable("); Serial.print(_currentSetting->dataMode); Serial.print(","); Serial.print(flags); Serial.println(")"); #endif @@ -306,10 +306,10 @@ void SPIClass::endTransaction(void) * I/O */ -uint8 SPIClass::read(void) +uint16 SPIClass::read(void) { while ( spi_is_rx_nonempty(_currentSetting->spi_d)==0 ) ; - return (uint8)spi_rx_reg(_currentSetting->spi_d); + return (uint16)spi_rx_reg(_currentSetting->spi_d); } void SPIClass::read(uint8 *buf, uint32 len) @@ -321,7 +321,7 @@ void SPIClass::read(uint8 *buf, uint32 len) while ( rxed < len) { regs->DR = 0x00FF; // " write the data item to be transmitted into the SPI_DR register (this clears the TXE flag)." while ( (regs->SR & SPI_SR_RXNE)==0 ) ; // wait till data is available in the Rx register - buf[rxed++] = (uint8)(regs->DR); // read and store the received byte + *buf++ = (regs->DR); // read and store the received byte } } @@ -332,11 +332,21 @@ void SPIClass::write(uint16 data) * by taking the Tx code from transfer(byte) * This almost doubles the speed of this function. */ - spi_tx_reg(_currentSetting->spi_d, data); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)." - while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." + spi_tx_reg(_currentSetting->spi_d, data); // write the data to be transmitted into the SPI_DR register (this clears the TXE flag) while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." } +void SPIClass::write(uint16 data, uint32 n) +{ + // Added by stevstrong: Repeatedly send same data by the specified number of times + spi_reg_map * regs = _currentSetting->spi_d->regs; + while ( (n--)>0 ) { + regs->DR = data; // write the data to be transmitted into the SPI_DR register (this clears the TXE flag) + while ( (regs->SR & SPI_SR_TXE)==0 ) ; // wait till Tx empty + } + while ( (regs->SR & SPI_SR_BSY) != 0); // wait until BSY=0 before returning +} + void SPIClass::write(const void *data, uint32 length) { spi_tx(_currentSetting->spi_d, data, length); // data can be array of bytes or words @@ -346,13 +356,6 @@ void SPIClass::write(const void *data, uint32 length) uint16 b = spi_rx_reg(_currentSetting->spi_d); // dummy read, needed, don't remove! } -uint16_t SPIClass::transfer16(uint16_t wr_data) const { - spi_tx_reg(_currentSetting->spi_d, wr_data); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)." - while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." - while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." - return (uint16)spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data." -} - uint8 SPIClass::transfer(uint8 byte) const { spi_tx_reg(_currentSetting->spi_d, byte); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)." while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." @@ -360,6 +363,13 @@ uint8 SPIClass::transfer(uint8 byte) const { return (uint8)spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data." } +uint16_t SPIClass::transfer16(uint16_t wr_data) const { + spi_tx_reg(_currentSetting->spi_d, wr_data); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)." + while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." + while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." + return (uint16)spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data." +} + /* Roger Clark and Victor Perez, 2015 * Performs a DMA SPI transfer with at least a receive buffer. * If a TX buffer is not provided, FF is sent over and over for the length of the transfer. @@ -419,10 +429,10 @@ uint8 SPIClass::dmaTransfer(void * transmitBuf, void * receiveBuf, uint16 length * Still in progress. * 2016 - stevstrong - reworked to automatically detect bit size from SPI setting */ -uint8 SPIClass::dmaSend(void * transmitBuf, uint16 length) +uint8 SPIClass::dmaSend(void * transmitBuf, uint16 length, bool minc) { if (length == 0) return 0; - uint32 flags = (DMA_MINC_MODE | DMA_FROM_MEM | DMA_TRNS_CMPLT); + uint32 flags = ( (DMA_MINC_MODE*minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT); uint8 b = 0; // dma1_ch3_Active=true; dma_init(_currentSetting->spiDmaDev); @@ -438,7 +448,7 @@ uint8 SPIClass::dmaSend(void * transmitBuf, uint16 length) // while (dma1_ch3_Active); uint32_t m = millis(); - while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & 0x2)==0) {//Avoid interrupts and just loop waiting for the flag to be set. + while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & DMA_ISR_TCIF1)==0) {//Avoid interrupts and just loop waiting for the flag to be set. if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; } } dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); diff --git a/STM32F1/libraries/SPI/src/SPI.h b/STM32F1/libraries/SPI/src/SPI.h index 0f8497a..717a2e9 100644 --- a/STM32F1/libraries/SPI/src/SPI.h +++ b/STM32F1/libraries/SPI/src/SPI.h @@ -115,6 +115,13 @@ public: init_MightInline(clock, bitOrder, dataMode, dataSize); } } + SPISettings(uint32_t clock) { + if (__builtin_constant_p(clock)) { + init_AlwaysInline(clock, MSBFIRST, SPI_MODE0, DATA_SIZE_8BIT); + } else { + init_MightInline(clock, MSBFIRST, SPI_MODE0, DATA_SIZE_8BIT); + } + } SPISettings() { init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0, DATA_SIZE_8BIT); } private: void init_MightInline(uint32_t clock, BitOrder bitOrder, uint8_t dataMode, uint32_t dataSize) { @@ -216,38 +223,38 @@ public: */ /** - * @brief Return the next unread byte. + * @brief Return the next unread byte/word. * - * If there is no unread byte waiting, this function will block + * If there is no unread byte/word waiting, this function will block * until one is received. */ - uint8 read(void); + uint16 read(void); /** * @brief Read length bytes, storing them into buffer. * @param buffer Buffer to store received bytes into. - * @param length Number of bytes to store in buffer. This + * @param length Number of bytes to store in buffer. This * function will block until the desired number of * bytes have been read. */ void read(uint8 *buffer, uint32 length); /** - * @brief Transmit a byte. - * @param data Byte to transmit. - */ -// void write(uint8 data); - - /** - * @brief Transmit a half word. + * @brief Transmit one byte/word. * @param data to transmit. */ void write(uint16 data); /** - * @brief Transmit multiple bytes. - * @param buffer Bytes to transmit. - * @param length Number of bytes in buffer to transmit. + * @brief Transmit one byte/word a specified number of times. + * @param data to transmit. + */ + void write(uint16 data, uint32 n); + + /** + * @brief Transmit multiple bytes/words. + * @param buffer Bytes/words to transmit. + * @param length Number of bytes/words in buffer to transmit. */ void write(const void * buffer, uint32 length); @@ -283,7 +290,7 @@ public: * @param data buffer half words to transmit, * @param length Number of bytes in buffer to transmit. */ - uint8 dmaSend(void * transmitBuf, uint16 length); + uint8 dmaSend(void * transmitBuf, uint16 length, bool minc = 1); /* * Pin accessors From fb823b6929e4416b0921b4ff6c9ea4fa5a186262 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Mon, 26 Dec 2016 15:26:51 +0100 Subject: [PATCH 08/25] remove unused code & bugfixes - setDataSize shall first disable the SPI before writing new value - dmaTransfer adapted for TFT library usage --- .gitignore | 2 ++ STM32F1/libraries/SPI/src/SPI.cpp | 21 ++++++++++----------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index 05bb0a5..1fc5dc8 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ other/maple-bootloader/build other/maple-bootloader/*~ *.o tools/src/stm32flash_serial/src/parsers/parsers.a +*.bak +*.1 diff --git a/STM32F1/libraries/SPI/src/SPI.cpp b/STM32F1/libraries/SPI/src/SPI.cpp index 9b6e28e..45ee25a 100644 --- a/STM32F1/libraries/SPI/src/SPI.cpp +++ b/STM32F1/libraries/SPI/src/SPI.cpp @@ -214,8 +214,10 @@ void SPIClass::setBitOrder(BitOrder bitOrder) void SPIClass::setDataSize(uint32 datasize) { _currentSetting->dataSize = datasize; - uint32 cr1 = _currentSetting->spi_d->regs->CR1 & ~(SPI_CR1_DFF); - _currentSetting->spi_d->regs->CR1 = cr1 | (datasize & SPI_CR1_DFF); + uint32 cr1 = _currentSetting->spi_d->regs->CR1 & ~(SPI_CR1_DFF); + uint8 en = spi_is_enabled(_currentSetting->spi_d); + spi_peripheral_disable(_currentSetting->spi_d); + _currentSetting->spi_d->regs->CR1 = cr1 | (datasize & SPI_CR1_DFF) | en; } void SPIClass::setDataMode(uint8_t dataMode) @@ -316,12 +318,11 @@ void SPIClass::read(uint8 *buf, uint32 len) { spi_reg_map * regs = _currentSetting->spi_d->regs; uint8 b = (regs->DR); // clear the RX buffer in case a byte is waiting on it. - uint32 rxed = 0; // start sequence - while ( rxed < len) { + while ( (len--)>0) { regs->DR = 0x00FF; // " write the data item to be transmitted into the SPI_DR register (this clears the TXE flag)." while ( (regs->SR & SPI_SR_RXNE)==0 ) ; // wait till data is available in the Rx register - *buf++ = (regs->DR); // read and store the received byte + *buf++ = (uint8)(regs->DR); // read and store the received byte } } @@ -333,6 +334,7 @@ void SPIClass::write(uint16 data) * This almost doubles the speed of this function. */ spi_tx_reg(_currentSetting->spi_d, data); // write the data to be transmitted into the SPI_DR register (this clears the TXE flag) + while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." } @@ -387,7 +389,7 @@ uint8 SPIClass::dmaTransfer(void * transmitBuf, void * receiveBuf, uint16 length // RX spi_rx_dma_enable(_currentSetting->spi_d); - dma_xfer_size dma_bit_size = (_currentSetting->dataSize==DATA_SIZE_8BIT) ? DMA_SIZE_8BITS : DMA_SIZE_16BITS; + dma_xfer_size dma_bit_size = (_currentSetting->dataSize==DATA_SIZE_16BIT) ? DMA_SIZE_16BITS : DMA_SIZE_8BITS; dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size, receiveBuf, dma_bit_size, (DMA_MINC_MODE | DMA_TRNS_CMPLT));// receive buffer DMA dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, length); @@ -408,7 +410,7 @@ uint8 SPIClass::dmaTransfer(void * transmitBuf, void * receiveBuf, uint16 length dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit uint32_t m = millis(); - while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & 0x2)==0) {//Avoid interrupts and just loop waiting for the flag to be set. + while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & DMA_ISR_TCIF1)==0) {//Avoid interrupts and just loop waiting for the flag to be set. if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; } } dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); @@ -434,13 +436,10 @@ uint8 SPIClass::dmaSend(void * transmitBuf, uint16 length, bool minc) if (length == 0) return 0; uint32 flags = ( (DMA_MINC_MODE*minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT); uint8 b = 0; -// dma1_ch3_Active=true; dma_init(_currentSetting->spiDmaDev); -// dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event); - // TX spi_tx_dma_enable(_currentSetting->spi_d); - dma_xfer_size dma_bit_size = (_currentSetting->dataSize==DATA_SIZE_8BIT) ? DMA_SIZE_8BITS : DMA_SIZE_16BITS; + dma_xfer_size dma_bit_size = (_currentSetting->dataSize==DATA_SIZE_16BIT) ? DMA_SIZE_16BITS : DMA_SIZE_8BITS; dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size, transmitBuf, dma_bit_size, flags);// Transmit buffer DMA dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length); From 7c320774b1477acec19acd330264d6303de4d67a Mon Sep 17 00:00:00 2001 From: Josh Stewart Date: Wed, 8 Feb 2017 15:17:58 +1100 Subject: [PATCH 09/25] Add EEPROM.update() function --- STM32F1/libraries/EEPROM/EEPROM.cpp | 22 ++++++++++++++++++++++ STM32F1/libraries/EEPROM/EEPROM.h | 2 ++ 2 files changed, 24 insertions(+) diff --git a/STM32F1/libraries/EEPROM/EEPROM.cpp b/STM32F1/libraries/EEPROM/EEPROM.cpp index 2cfd648..289a93a 100644 --- a/STM32F1/libraries/EEPROM/EEPROM.cpp +++ b/STM32F1/libraries/EEPROM/EEPROM.cpp @@ -521,6 +521,28 @@ uint16 EEPROMClass::write(uint16 Address, uint16 Data) return status; } +/** + * @brief Writes/upadtes variable data in EEPROM. + The value is written only if differs from the one already saved at the same address. + * @param VirtAddress: Variable virtual address + * @param Data: 16 bit data to be written + * @retval Success or error status: + * - EEPROM_SAME_VALUE: If new Data matches existing EEPROM Data + * - FLASH_COMPLETE: on success + * - EEPROM_BAD_ADDRESS: if address = 0xFFFF + * - EEPROM_PAGE_FULL: if valid page is full + * - EEPROM_NO_VALID_PAGE: if no valid page was found + * - EEPROM_OUT_SIZE: if no empty EEPROM variables + * - Flash error code: on write Flash error + */ +uint16 EEPROMClass::update(uint16 Address, uint16 Data) +{ + if (read(Address) == Data) + return EEPROM_SAME_VALUE; + else + return write(Address, Data); +} + /** * @brief Return number of variable * @retval Number of variables diff --git a/STM32F1/libraries/EEPROM/EEPROM.h b/STM32F1/libraries/EEPROM/EEPROM.h index 8a8320b..2957476 100644 --- a/STM32F1/libraries/EEPROM/EEPROM.h +++ b/STM32F1/libraries/EEPROM/EEPROM.h @@ -47,6 +47,7 @@ enum : uint16 EEPROM_BAD_ADDRESS = ((uint16)0x0082), EEPROM_BAD_FLASH = ((uint16)0x0083), EEPROM_NOT_INIT = ((uint16)0x0084), + EEPROM_SAME_VALUE = ((uint16)0x0085), EEPROM_NO_VALID_PAGE = ((uint16)0x00AB) }; @@ -67,6 +68,7 @@ public: uint16 read (uint16 address); uint16 read (uint16 address, uint16 *data); uint16 write(uint16 address, uint16 data); + uint16 update(uint16 address, uint16 data); uint16 count(uint16 *); uint16 maxcount(void); From 83e5f4832206f1924168c217df0c7bff1b06dad7 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Thu, 13 Apr 2017 22:34:37 +0200 Subject: [PATCH 10/25] remove "deprecated" flag from dma_setup_transfer remove deprecated flag --- STM32F1/cores/maple/libmaple/dma_f1.c | 1 - STM32F1/system/libmaple/stm32f1/include/series/dma.h | 1 - 2 files changed, 2 deletions(-) diff --git a/STM32F1/cores/maple/libmaple/dma_f1.c b/STM32F1/cores/maple/libmaple/dma_f1.c index 6400d15..c7c3c00 100644 --- a/STM32F1/cores/maple/libmaple/dma_f1.c +++ b/STM32F1/cores/maple/libmaple/dma_f1.c @@ -341,7 +341,6 @@ void dma_set_per_addr(dma_dev *dev, dma_channel channel, __io void *addr) { * @see dma_attach_interrupt() * @see dma_enable() */ -__deprecated void dma_setup_transfer(dma_dev *dev, dma_channel channel, __io void *peripheral_address, diff --git a/STM32F1/system/libmaple/stm32f1/include/series/dma.h b/STM32F1/system/libmaple/stm32f1/include/series/dma.h index bedb602..ff61857 100644 --- a/STM32F1/system/libmaple/stm32f1/include/series/dma.h +++ b/STM32F1/system/libmaple/stm32f1/include/series/dma.h @@ -559,7 +559,6 @@ typedef enum dma_mode_flags { * * (It's not possible to fully configure a DMA stream on F2 with just * this information, so this interface is too tied to the F1.) */ -__deprecated void dma_setup_transfer(dma_dev *dev, dma_channel channel, __io void *peripheral_address, From 0590f27afaea2e007f7f5f672add36f462e509d1 Mon Sep 17 00:00:00 2001 From: Oleksandr Masliuchenko Date: Sat, 22 Apr 2017 16:27:30 +0300 Subject: [PATCH 11/25] Compiler warning fixed --- STM32F1/cores/maple/libmaple/gpio_f1.c | 1 - 1 file changed, 1 deletion(-) diff --git a/STM32F1/cores/maple/libmaple/gpio_f1.c b/STM32F1/cores/maple/libmaple/gpio_f1.c index ecd015d..6de16f5 100644 --- a/STM32F1/cores/maple/libmaple/gpio_f1.c +++ b/STM32F1/cores/maple/libmaple/gpio_f1.c @@ -142,7 +142,6 @@ gpio_pin_mode gpio_get_mode(gpio_dev *dev, uint8 pin) { gpio_reg_map *regs = dev->regs; __io uint32 *cr = ®s->CRL + (pin >> 3); uint32 shift = (pin & 0x7) * 4; - uint32 tmp = *cr; uint32 crMode = (*cr>>shift) & 0x0F; From 3d5c54e344ee8d8f769c318d034dd567da6ba25f Mon Sep 17 00:00:00 2001 From: edogaldo Date: Tue, 16 May 2017 00:00:59 +0200 Subject: [PATCH 12/25] Make HardwareSerial.flush() compatible with Arduino 1.0 api --- STM32F1/cores/maple/HardwareSerial.cpp | 5 +++-- STM32F1/system/libmaple/include/libmaple/ring_buffer.h | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/STM32F1/cores/maple/HardwareSerial.cpp b/STM32F1/cores/maple/HardwareSerial.cpp index c993bdf..024efbc 100644 --- a/STM32F1/cores/maple/HardwareSerial.cpp +++ b/STM32F1/cores/maple/HardwareSerial.cpp @@ -193,7 +193,8 @@ size_t HardwareSerial::write(unsigned char ch) { return 1; } +/* edogaldo: Waits for the transmission of outgoing serial data to complete (Arduino 1.0 api specs) */ void HardwareSerial::flush(void) { - usart_reset_rx(this->usart_device); - usart_reset_tx(this->usart_device); + while(!rb_is_empty(this->usart_device->wb)); // wait for TX buffer empty + while(!((this->usart_device->regs->SR) & (1< Date: Mon, 22 May 2017 21:09:12 +0200 Subject: [PATCH 13/25] SPI update - cleaned up commented out lines - run-time optimized write and transfer functions - run-time optimized non-DMA block read routine - function call order within DMA routines tied to F4 structure - in line with AN4031, chapter 4.3 - reworked send functions (currently not used, deprecated, but still) --- STM32F1/libraries/SPI/src/SPI.cpp | 118 +++++++++++++++--------------- STM32F1/libraries/SPI/src/SPI.h | 2 +- 2 files changed, 62 insertions(+), 58 deletions(-) diff --git a/STM32F1/libraries/SPI/src/SPI.cpp b/STM32F1/libraries/SPI/src/SPI.cpp index 45ee25a..1108014 100644 --- a/STM32F1/libraries/SPI/src/SPI.cpp +++ b/STM32F1/libraries/SPI/src/SPI.cpp @@ -135,9 +135,8 @@ SPIClass::SPIClass(uint32 spi_num) { _settings[2].spiDmaDev = DMA2; _settings[2].spiTxDmaChannel = DMA_CH2; _settings[2].spiRxDmaChannel = DMA_CH1; -#endif - - //pinMode(BOARD_SPI_DEFAULT_SS,OUTPUT); +#endif + } /* @@ -260,9 +259,6 @@ void SPIClass::beginTransaction(uint8_t pin, SPISettings settings) #ifdef SPI_DEBUG Serial.println("SPIClass::beginTransaction"); #endif - //_SSPin=pin; - //pinMode(_SSPin,OUTPUT); - //digitalWrite(_SSPin,LOW); setBitOrder(settings.bitOrder); setDataMode(settings.dataMode); setDataSize(settings.dataSize); @@ -316,14 +312,23 @@ uint16 SPIClass::read(void) void SPIClass::read(uint8 *buf, uint32 len) { + if ( len == 0 ) return; + spi_rx_reg(_currentSetting->spi_d); // clear the RX buffer in case a byte is waiting on it. spi_reg_map * regs = _currentSetting->spi_d->regs; - uint8 b = (regs->DR); // clear the RX buffer in case a byte is waiting on it. - // start sequence - while ( (len--)>0) { - regs->DR = 0x00FF; // " write the data item to be transmitted into the SPI_DR register (this clears the TXE flag)." - while ( (regs->SR & SPI_SR_RXNE)==0 ) ; // wait till data is available in the Rx register - *buf++ = (uint8)(regs->DR); // read and store the received byte - } + // start sequence: write byte 0 + regs->DR = 0x00FF; // write the first byte + // main loop + while ( (--len) ) { + while( !(regs->SR & SPI_SR_TXE) ); // wait for TXE flag + noInterrupts(); // go atomic level - avoid interrupts to surely get the previously received data + regs->DR = 0x00FF; // write the next data item to be transmitted into the SPI_DR register. This clears the TXE flag. + while ( !(regs->SR & SPI_SR_RXNE) ); // wait till data is available in the DR register + *buf++ = (uint8)(regs->DR); // read and store the received byte. This clears the RXNE flag. + interrupts(); // let systick do its job + } + // read remaining last byte + while ( !(regs->SR & SPI_SR_RXNE) ); // wait till data is available in the Rx register + *buf++ = (uint8)(regs->DR); // read and store the received byte } void SPIClass::write(uint16 data) @@ -344,32 +349,37 @@ void SPIClass::write(uint16 data, uint32 n) spi_reg_map * regs = _currentSetting->spi_d->regs; while ( (n--)>0 ) { regs->DR = data; // write the data to be transmitted into the SPI_DR register (this clears the TXE flag) - while ( (regs->SR & SPI_SR_TXE)==0 ) ; // wait till Tx empty + while ( (regs->SR & SPI_SR_TXE)==0 ) ; // wait till Tx empty } while ( (regs->SR & SPI_SR_BSY) != 0); // wait until BSY=0 before returning } -void SPIClass::write(const void *data, uint32 length) +void SPIClass::write(void *data, uint32 length) { - spi_tx(_currentSetting->spi_d, data, length); // data can be array of bytes or words - while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." - while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." - // taken from SdSpiSTM32F1.cpp - Victor's lib, and adapted to support device selection - uint16 b = spi_rx_reg(_currentSetting->spi_d); // dummy read, needed, don't remove! + spi_dev * spi_d = _currentSetting->spi_d; + spi_tx(spi_d, (void*)data, length); // data can be array of bytes or words + while (spi_is_tx_empty(spi_d) == 0); // "5. Wait until TXE=1 ..." + while (spi_is_busy(spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." } -uint8 SPIClass::transfer(uint8 byte) const { - spi_tx_reg(_currentSetting->spi_d, byte); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)." - while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." - while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." - return (uint8)spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data." +uint8 SPIClass::transfer(uint8 byte) const +{ + spi_dev * spi_d = _currentSetting->spi_d; + spi_rx_reg(spi_d); // read any previous data + spi_tx_reg(spi_d, byte); // Write the data item to be transmitted into the SPI_DR register + while (spi_is_tx_empty(spi_d) == 0); // "5. Wait until TXE=1 ..." + while (spi_is_busy(spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." + return (uint8)spi_rx_reg(spi_d); // "... and read the last received data." } -uint16_t SPIClass::transfer16(uint16_t wr_data) const { - spi_tx_reg(_currentSetting->spi_d, wr_data); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)." - while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." - while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." - return (uint16)spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data." +uint16_t SPIClass::transfer16(uint16_t wr_data) const +{ + spi_dev * spi_d = _currentSetting->spi_d; + spi_rx_reg(spi_d); // read any previous data + spi_tx_reg(spi_d, wr_data); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)." + while (spi_is_tx_empty(spi_d) == 0); // "5. Wait until TXE=1 ..." + while (spi_is_busy(spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." + return (uint16)spi_rx_reg(spi_d); // "... and read the last received data." } /* Roger Clark and Victor Perez, 2015 @@ -382,21 +392,19 @@ uint8 SPIClass::dmaTransfer(void * transmitBuf, void * receiveBuf, uint16 length { if (length == 0) return 0; uint8 b = 0; - spi_rx_reg(_currentSetting->spi_d); //Clear the RX buffer in case a byte is waiting on it. // dma1_ch3_Active=true; dma_init(_currentSetting->spiDmaDev); // dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event); // RX - spi_rx_dma_enable(_currentSetting->spi_d); dma_xfer_size dma_bit_size = (_currentSetting->dataSize==DATA_SIZE_16BIT) ? DMA_SIZE_16BITS : DMA_SIZE_8BITS; dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size, - receiveBuf, dma_bit_size, (DMA_MINC_MODE | DMA_TRNS_CMPLT));// receive buffer DMA + receiveBuf, dma_bit_size, (DMA_MINC_MODE));// receive buffer DMA dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, length); + dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel);// enable receive // TX - uint32 flags = (DMA_MINC_MODE | DMA_FROM_MEM | DMA_TRNS_CMPLT); - spi_tx_dma_enable(_currentSetting->spi_d); + uint32 flags = (DMA_MINC_MODE | DMA_FROM_MEM); if ( transmitBuf==0 ) { static uint8_t ff = 0XFF; transmitBuf = &ff; @@ -405,23 +413,25 @@ uint8 SPIClass::dmaTransfer(void * transmitBuf, void * receiveBuf, uint16 length dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size, transmitBuf, dma_bit_size, flags);// Transmit buffer DMA dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length); - - dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel);// enable receive + dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit + + spi_rx_reg(_currentSetting->spi_d); //Clear the RX buffer in case a byte is waiting on it. + spi_rx_dma_enable(_currentSetting->spi_d); + spi_tx_dma_enable(_currentSetting->spi_d); // must be the last enable to avoid DMA error flag uint32_t m = millis(); while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & DMA_ISR_TCIF1)==0) {//Avoid interrupts and just loop waiting for the flag to be set. + //delayMicroseconds(10); if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; } } - dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." - dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); - dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel); - spi_rx_dma_disable(_currentSetting->spi_d); // And disable generation of DMA request from the SPI port so other peripherals can use the channels spi_tx_dma_disable(_currentSetting->spi_d); - uint16 x = spi_rx_reg(_currentSetting->spi_d); // dummy read, needed, don't remove! + spi_rx_dma_disable(_currentSetting->spi_d); // And disable generation of DMA request from the SPI port so other peripherals can use the channels + dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); + dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel); return b; } @@ -438,26 +448,25 @@ uint8 SPIClass::dmaSend(void * transmitBuf, uint16 length, bool minc) uint8 b = 0; dma_init(_currentSetting->spiDmaDev); // TX - spi_tx_dma_enable(_currentSetting->spi_d); dma_xfer_size dma_bit_size = (_currentSetting->dataSize==DATA_SIZE_16BIT) ? DMA_SIZE_16BITS : DMA_SIZE_8BITS; dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size, transmitBuf, dma_bit_size, flags);// Transmit buffer DMA dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length); + dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit + spi_tx_dma_enable(_currentSetting->spi_d); -// while (dma1_ch3_Active); uint32_t m = millis(); while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & DMA_ISR_TCIF1)==0) {//Avoid interrupts and just loop waiting for the flag to be set. + //delayMicroseconds(10); if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; } } - dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." - dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); spi_tx_dma_disable(_currentSetting->spi_d); - uint16 x = spi_rx_reg(_currentSetting->spi_d); // dummy read, needed, don't remove! - return b; + dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); + return b; } void SPIClass::attachInterrupt(void) { @@ -493,18 +502,13 @@ uint8 SPIClass::nssPin(void) { */ uint8 SPIClass::send(uint8 data) { - uint8 buf[] = {data}; - return this->send(buf, 1); + this->write(data); + return 1; } uint8 SPIClass::send(uint8 *buf, uint32 len) { - uint32 txed = 0; - uint8 ret = 0; - while (txed < len) { - this->write(buf[txed++]); - ret = this->read(); - } - return ret; + this->write(buf, len); + return len; } uint8 SPIClass::recv(void) { diff --git a/STM32F1/libraries/SPI/src/SPI.h b/STM32F1/libraries/SPI/src/SPI.h index 717a2e9..b662384 100644 --- a/STM32F1/libraries/SPI/src/SPI.h +++ b/STM32F1/libraries/SPI/src/SPI.h @@ -256,7 +256,7 @@ public: * @param buffer Bytes/words to transmit. * @param length Number of bytes/words in buffer to transmit. */ - void write(const void * buffer, uint32 length); + void write(void * buffer, uint32 length); /** * @brief Transmit a byte, then return the next unread byte. From aa79ea1d6e5838bba1041f333c20f0758536452c Mon Sep 17 00:00:00 2001 From: stevstrong Date: Wed, 24 May 2017 18:40:41 +0200 Subject: [PATCH 14/25] Adafruit_ILI9341_STM - reworked for 16 bit SPI register accesses --- .../Adafruit_ILI9341_STM.cpp | 24 ++++--------------- .../Adafruit_ILI9341_STM.h | 8 +++++-- 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.cpp b/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.cpp index e21f33c..db57b3e 100644 --- a/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.cpp +++ b/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.cpp @@ -36,7 +36,7 @@ Adafruit_ILI9341_STM::Adafruit_ILI9341_STM(int8_t cs, int8_t dc, int8_t rst) : A } -void Adafruit_ILI9341_STM::spiwrite(uint8_t c) { +void Adafruit_ILI9341_STM::spiwrite(uint16_t c) { //Serial.print("0x"); Serial.print(c, HEX); Serial.print(", "); @@ -178,10 +178,7 @@ void Adafruit_ILI9341_STM::begin(void) { SPI.setBitOrder(MSBFIRST); SPI.setDataMode(SPI_MODE0); #elif defined (__STM32F1__) - SPI.begin(); - SPI.setClockDivider(SPI_CLOCK_DIV2); - SPI.setBitOrder(MSBFIRST); - SPI.setDataMode(SPI_MODE0); + SPI.beginTransaction(SPISettings(36000000)); #elif defined (__arm__) SPI.begin(); @@ -335,6 +332,7 @@ void Adafruit_ILI9341_STM::begin(void) { if (hwSPI) spi_begin(); writecommand(ILI9341_DISPON); //Display on if (hwSPI) spi_end(); + if (hwSPI) SPI.setDataSize(SPI_CR1_DFF); } @@ -345,18 +343,14 @@ void Adafruit_ILI9341_STM::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, writecommand(ILI9341_CASET); // Column addr set *dcport |= dcpinmask; *csport &= ~cspinmask; - SPI.setDataSize (SPI_CR1_DFF); SPI.write(x0); SPI.write(x1); -// SPI.setDataSize (0); writecommand(ILI9341_PASET); // Row addr set *dcport |= dcpinmask; *csport &= ~cspinmask; -// SPI.setDataSize (SPI_CR1_DFF); SPI.write(y0); SPI.write(y1); - SPI.setDataSize (0); writecommand(ILI9341_RAMWR); // write to RAM @@ -385,7 +379,6 @@ void Adafruit_ILI9341_STM::pushColor(uint16_t color) { //digitalWrite(_cs, LOW); *csport &= ~cspinmask; - spiwrite(color >> 8); spiwrite(color); *csport |= cspinmask; @@ -403,7 +396,6 @@ void Adafruit_ILI9341_STM::drawPixel(int16_t x, int16_t y, uint16_t color) { *dcport |= dcpinmask; *csport &= ~cspinmask; - spiwrite(color >> 8); spiwrite(color); *csport |= cspinmask; @@ -431,10 +423,8 @@ void Adafruit_ILI9341_STM::drawFastVLine(int16_t x, int16_t y, int16_t h, *csport &= ~cspinmask; #if defined (__STM32F1__) - SPI.setDataSize (SPI_CR1_DFF); // Set SPI 16bit mode lineBuffer[0] = color; SPI.dmaSend(lineBuffer, h, 0); - SPI.setDataSize (0); #else uint8_t hi = color >> 8, lo = color; while (h--) { @@ -464,10 +454,8 @@ void Adafruit_ILI9341_STM::drawFastHLine(int16_t x, int16_t y, int16_t w, *csport &= ~cspinmask; #if defined (__STM32F1__) - SPI.setDataSize (SPI_CR1_DFF); // Set spi 16bit mode lineBuffer[0] = color; SPI.dmaSend(lineBuffer, w, 0); - SPI.setDataSize (0); #else uint8_t hi = color >> 8, lo = color; while (w--) { @@ -485,11 +473,9 @@ void Adafruit_ILI9341_STM::fillScreen(uint16_t color) { setAddrWindow(0, 0, _width - 1, _height - 1); *dcport |= dcpinmask; *csport &= ~cspinmask; - SPI.setDataSize (SPI_CR1_DFF); // Set spi 16bit mode lineBuffer[0] = color; SPI.dmaSend(lineBuffer, (65535), 0); SPI.dmaSend(lineBuffer, ((_width * _height) - 65535), 0); - SPI.setDataSize (0); #else fillRect(0, 0, _width, _height, color); @@ -515,7 +501,6 @@ void Adafruit_ILI9341_STM::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, *dcport |= dcpinmask; *csport &= ~cspinmask; #if defined (__STM32F1__) - SPI.setDataSize (SPI_CR1_DFF); // Set spi 16bit mode lineBuffer[0] = color; if (w*h <= 65535) { SPI.dmaSend(lineBuffer, (w*h), 0); @@ -524,7 +509,6 @@ void Adafruit_ILI9341_STM::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, SPI.dmaSend(lineBuffer, (65535), 0); SPI.dmaSend(lineBuffer, ((w*h) - 65535), 0); } - SPI.setDataSize (0); #else uint8_t hi = color >> 8, lo = color; for(y=h; y>0; y--) @@ -672,6 +656,7 @@ uint16_t Adafruit_ILI9341_STM::color565(uint8_t r, uint8_t g, uint8_t b) { void Adafruit_ILI9341_STM::setRotation(uint8_t m) { if (hwSPI) spi_begin(); + if (hwSPI) SPI.setDataSize(0); writecommand(ILI9341_MADCTL); rotation = m % 4; // can't be higher than 3 switch (rotation) { @@ -696,6 +681,7 @@ void Adafruit_ILI9341_STM::setRotation(uint8_t m) { _height = ILI9341_TFTWIDTH; break; } + if (hwSPI) SPI.setDataSize(SPI_CR1_DFF); if (hwSPI) spi_end(); } diff --git a/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.h b/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.h index a716c27..6554bc0 100644 --- a/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.h +++ b/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.h @@ -8,9 +8,13 @@ This library has been modified for the Maple Mini #include "Arduino.h" #include "Print.h" -#include +#include #include +#ifndef swap + #define swap(a, b) { int16_t t = a; a = b; b = t; } +#endif + #define ILI9341_TFTWIDTH 240 #define ILI9341_TFTHEIGHT 320 @@ -125,7 +129,7 @@ class Adafruit_ILI9341_STM : public Adafruit_GFX { void dummyclock(void); */ - void spiwrite(uint8_t), + void spiwrite(uint16_t), writecommand(uint8_t c), writedata(uint8_t d), commandList(uint8_t *addr); From c6fe342d0f46256a5ccf581237f4b42c5c7b163c Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Thu, 25 May 2017 17:59:48 +1000 Subject: [PATCH 15/25] Add prototype for systick_attach_callback (thanks to @ag123) --- STM32F1/system/libmaple/include/libmaple/systick.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/STM32F1/system/libmaple/include/libmaple/systick.h b/STM32F1/system/libmaple/include/libmaple/systick.h index 551f800..51d0c56 100644 --- a/STM32F1/system/libmaple/include/libmaple/systick.h +++ b/STM32F1/system/libmaple/include/libmaple/systick.h @@ -108,6 +108,12 @@ static inline uint32 systick_check_underflow(void) { return SYSTICK_BASE->CSR & SYSTICK_CSR_COUNTFLAG; } +/** + * @brief prototype for systick_attach_callback + * + */ +extern void systick_attach_callback(void (*callback)(void)); + #ifdef __cplusplus } // extern "C" #endif From c3d9d1bc1e36b44a3d5f1c39bb145194df8d8b1f Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Thu, 25 May 2017 18:16:47 +1000 Subject: [PATCH 16/25] Added define for LED_BUILTIN to Maple mini and generic STM32F103C (on PC13 to suit the BluePill) --- STM32F1/variants/generic_stm32f103c/board/board.h | 2 ++ STM32F1/variants/maple_mini/board/board.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/STM32F1/variants/generic_stm32f103c/board/board.h b/STM32F1/variants/generic_stm32f103c/board/board.h index d2a4fd6..97231e0 100644 --- a/STM32F1/variants/generic_stm32f103c/board/board.h +++ b/STM32F1/variants/generic_stm32f103c/board/board.h @@ -73,6 +73,8 @@ #define BOARD_USB_DISC_DEV GPIOB #define BOARD_USB_DISC_BIT 10 +#define LED_BUILTIN PC13 + // Note this needs to match with the PIN_MAP array in board.cpp enum { PA0, PA1, PA2, PA3, PA4, PA5, PA6, PA7, PA8, PA9, PA10, PA11, PA12, PA13,PA14,PA15, diff --git a/STM32F1/variants/maple_mini/board/board.h b/STM32F1/variants/maple_mini/board/board.h index b7a54a8..10bcb5a 100644 --- a/STM32F1/variants/maple_mini/board/board.h +++ b/STM32F1/variants/maple_mini/board/board.h @@ -71,6 +71,8 @@ #define BOARD_USB_DISC_DEV GPIOB #define BOARD_USB_DISC_BIT 9 +#define LED_BUILTIN PB1 + enum { PB11, PB10, PB2, PB0, PA7, PA6, PA5, PA4, PA3, PA2, PA1, PA0, PC15, PC14, PC13, PB7, PB6, PB5, PB4, PB3, PA15, PA14, PA13, PA12, PA11, PA10, PA9, From 782b53119d7ee0c8dec605421c5bf5be60f622a4 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Thu, 25 May 2017 10:18:27 +0200 Subject: [PATCH 17/25] used GFX library changed back to GFX_AS --- STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.h b/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.h index 6554bc0..137b7a4 100644 --- a/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.h +++ b/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.h @@ -8,7 +8,7 @@ This library has been modified for the Maple Mini #include "Arduino.h" #include "Print.h" -#include +#include #include #ifndef swap From 437834a91fafc15bac2f24b9e889ddd259e86a72 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Thu, 25 May 2017 20:06:37 +1000 Subject: [PATCH 18/25] Added code by @danieleff to delay leaving the maple_upload script (in all platforms) until the Serial device has reconnected - this helps resolve the problem of needing to close the Arduino Serial Monitor prior to upload --- tools/linux/maple_upload | 9 +++++++++ tools/linux64/maple_upload | 9 +++++++++ tools/macosx/maple_upload | 9 +++++++++ tools/win/maple_upload.bat | 10 ++++++++++ 4 files changed, 37 insertions(+) diff --git a/tools/linux/maple_upload b/tools/linux/maple_upload index e799f3a..1953174 100755 --- a/tools/linux/maple_upload +++ b/tools/linux/maple_upload @@ -38,3 +38,12 @@ if [ ! -x "${DFU_UTIL}" ]; then fi "${DFU_UTIL}" -d ${usbID} -a ${altID} -D ${binfile} ${dfuse_addr} -R + +echo -n Waiting for ${dummy_port_fullpath} serial... + +COUNTER=0 +while [ ! -c ${dummy_port_fullpath} ] && ((COUNTER++ < 40)); do + sleep 0.1 +done + +echo Done diff --git a/tools/linux64/maple_upload b/tools/linux64/maple_upload index e799f3a..27e006c 100755 --- a/tools/linux64/maple_upload +++ b/tools/linux64/maple_upload @@ -38,3 +38,12 @@ if [ ! -x "${DFU_UTIL}" ]; then fi "${DFU_UTIL}" -d ${usbID} -a ${altID} -D ${binfile} ${dfuse_addr} -R + +echo -n Waiting for ${dummy_port_fullpath} serial... + +COUNTER=0 +while [ ! -c ${dummy_port_fullpath} ] && ((COUNTER++ < 40)); do + sleep 0.1 +done + +echo Done \ No newline at end of file diff --git a/tools/macosx/maple_upload b/tools/macosx/maple_upload index 8d15eff..3521aa1 100755 --- a/tools/macosx/maple_upload +++ b/tools/macosx/maple_upload @@ -51,3 +51,12 @@ if [ ! -x ${DFU_UTIL} ]; then fi ${DFU_UTIL} -d ${usbID} -a ${altID} -D ${binfile} -R ${dfuse_addr} -R + +echo -n Waiting for ${dummy_port_fullpath} serial... + +COUNTER=0 +while [ ! -c ${dummy_port_fullpath} ] && ((COUNTER++ < 40)); do + sleep 0.1 +done + +echo Done diff --git a/tools/win/maple_upload.bat b/tools/win/maple_upload.bat index 678969c..7d59bf5 100644 --- a/tools/win/maple_upload.bat +++ b/tools/win/maple_upload.bat @@ -6,3 +6,13 @@ set driverLetter=%driverLetter:~0,2% %driverLetter% cd %~dp0 java -jar maple_loader.jar %1 %2 %3 %4 %5 %6 %7 %8 %9 + +for /l %%x in (1, 1, 40) do ( + ping -w 50 -n 1 192.0.2.1 > nul + mode %1 > nul + if ERRORLEVEL 0 goto comPortFound +) + +echo timeout waiting for %1 serial + +:comPortFound From d3058d39f077daceea2573fd1fbe6255b5cc1497 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Thu, 25 May 2017 20:29:01 +1000 Subject: [PATCH 19/25] Fixed F4 ADC typo as noted by @stevstrong in reply to issue #265 --- STM32F4/cores/maple/libmaple/adc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/STM32F4/cores/maple/libmaple/adc.h b/STM32F4/cores/maple/libmaple/adc.h index 3a40d4c..bff18d9 100644 --- a/STM32F4/cores/maple/libmaple/adc.h +++ b/STM32F4/cores/maple/libmaple/adc.h @@ -166,7 +166,7 @@ extern const adc_dev *ADC3; #define ADC_CR2_ALIGN_BIT 11 #define ADC_CR2_JEXTTRIG_BIT 15 #define ADC_CR2_EXTTRIG_BIT 20 -#define ADC_CR2_TSEREFE_BIT 23 +#define ADC_CR2_TSVREFE_BIT 23 #ifdef STM32F2 #define ADC_CR2_JSWSTART_BIT 22 #define ADC_CR2_SWSTART_BIT 30 @@ -191,7 +191,7 @@ extern const adc_dev *ADC3; #define ADC_CR2_EXTTRIG BIT(ADC_CR2_EXTTRIG_BIT) #define ADC_CR2_JSWSTART BIT(ADC_CR2_JSWSTART_BIT) #define ADC_CR2_SWSTART BIT(ADC_CR2_SWSTART_BIT) -#define ADC_CR2_TSEREFE BIT(ADC_CR2_TSEREFE_BIT) +#define ADC_CR2_TSVREFE BIT(ADC_CR2_TSVREFE_BIT) /* Sample time register 1 */ From 66579ef8ef822fd188c11efd4e682d75b95126d8 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Fri, 26 May 2017 16:03:49 +1000 Subject: [PATCH 20/25] Added -std=gnu++11 and -std=gnu11 compile flags to F1 and F4 platform.txt compile recipes --- STM32F1/platform.txt | 4 ++-- STM32F4/platform.txt | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/STM32F1/platform.txt b/STM32F1/platform.txt index 3ffde2e..3da3070 100644 --- a/STM32F1/platform.txt +++ b/STM32F1/platform.txt @@ -16,13 +16,13 @@ compiler.warning_flags.all=-Wall -Wextra -DDEBUG_LEVEL=DEBUG_ALL # ---------------------- compiler.path={runtime.tools.arm-none-eabi-gcc.path}/bin/ compiler.c.cmd=arm-none-eabi-gcc -compiler.c.flags=-c -g -Os {compiler.warning_flags} -MMD -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 -DBOARD_{build.variant} -D{build.vect} -DERROR_LED_PORT={build.error_led_port} -DERROR_LED_PIN={build.error_led_pin} +compiler.c.flags=-c -g -Os {compiler.warning_flags} -std=gnu11 -MMD -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 -DBOARD_{build.variant} -D{build.vect} -DERROR_LED_PORT={build.error_led_port} -DERROR_LED_PIN={build.error_led_pin} compiler.c.elf.cmd=arm-none-eabi-g++ compiler.c.elf.flags=-Os -Wl,--gc-sections compiler.S.cmd=arm-none-eabi-gcc compiler.S.flags=-c -g -x assembler-with-cpp -MMD compiler.cpp.cmd=arm-none-eabi-g++ -compiler.cpp.flags=-c -g -Os {compiler.warning_flags} -MMD -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 -fno-rtti -fno-exceptions -DBOARD_{build.variant} -D{build.vect} -DERROR_LED_PORT={build.error_led_port} -DERROR_LED_PIN={build.error_led_pin} +compiler.cpp.flags=-c -g -Os {compiler.warning_flags} -std=gnu++11 -MMD -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 -fno-rtti -fno-exceptions -DBOARD_{build.variant} -D{build.vect} -DERROR_LED_PORT={build.error_led_port} -DERROR_LED_PIN={build.error_led_pin} compiler.ar.cmd=arm-none-eabi-ar compiler.ar.flags=rcs compiler.objcopy.cmd=arm-none-eabi-objcopy diff --git a/STM32F4/platform.txt b/STM32F4/platform.txt index 99ae555..c43a061 100755 --- a/STM32F4/platform.txt +++ b/STM32F4/platform.txt @@ -12,13 +12,13 @@ version=0.1.0 compiler.path={runtime.tools.arm-none-eabi-gcc.path}/bin/ compiler.c.cmd=arm-none-eabi-gcc -compiler.c.flags=-c -g -Os -w -MMD -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 -DBOARD_{build.variant} -D{build.vect} -DERROR_LED_PORT={build.error_led_port} -DERROR_LED_PIN={build.error_led_pin} +compiler.c.flags=-c -g -Os -w -MMD -std=gnu11 -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 -DBOARD_{build.variant} -D{build.vect} -DERROR_LED_PORT={build.error_led_port} -DERROR_LED_PIN={build.error_led_pin} compiler.c.elf.cmd=arm-none-eabi-g++ compiler.c.elf.flags=-Os -Wl,--gc-sections compiler.S.cmd=arm-none-eabi-gcc compiler.S.flags=-c -g -x assembler-with-cpp -MMD compiler.cpp.cmd=arm-none-eabi-g++ -compiler.cpp.flags=-c -g -Os -w -MMD -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 -fno-rtti -fno-exceptions -DBOARD_{build.variant} -D{build.vect} -DERROR_LED_PORT={build.error_led_port} -DERROR_LED_PIN={build.error_led_pin} +compiler.cpp.flags=-c -g -Os -w -MMD -std=gnu++11 -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 -fno-rtti -fno-exceptions -DBOARD_{build.variant} -D{build.vect} -DERROR_LED_PORT={build.error_led_port} -DERROR_LED_PIN={build.error_led_pin} compiler.ar.cmd=arm-none-eabi-ar compiler.ar.flags=rcs compiler.objcopy.cmd=arm-none-eabi-objcopy From f2c2323afde16917b5ba7059c677c54ef9ee0e8c Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Fri, 26 May 2017 16:22:16 +1000 Subject: [PATCH 21/25] Changed board variants to use calculate value from F_CPU for CYCLES_PER_MICROSECOND --- STM32F1/variants/STM32VLD/board/board.h | 3 ++- STM32F1/variants/generic_gd32f103c/board/board.h | 2 +- STM32F1/variants/generic_stm32f103c/board/board.h | 2 +- STM32F1/variants/generic_stm32f103r8/board/board.h | 2 +- STM32F1/variants/generic_stm32f103t/board/board.h | 2 +- STM32F1/variants/generic_stm32f103v/board/board.h | 2 +- STM32F1/variants/hytiny_stm32f103t/board/board.h | 2 +- STM32F1/variants/maple/board/board.h | 2 +- STM32F1/variants/maple_mini/board/board.h | 2 +- STM32F1/variants/microduino/board/board.h | 2 +- STM32F1/variants/nucleo_f103rb/board/board.h | 2 +- STM32F3/variants/discovery_f3/board/board.h | 4 ++-- 12 files changed, 14 insertions(+), 13 deletions(-) diff --git a/STM32F1/variants/STM32VLD/board/board.h b/STM32F1/variants/STM32VLD/board/board.h index ba8d556..be2f19e 100644 --- a/STM32F1/variants/STM32VLD/board/board.h +++ b/STM32F1/variants/STM32VLD/board/board.h @@ -38,7 +38,8 @@ -#define CYCLES_PER_MICROSECOND 24 +//#define CYCLES_PER_MICROSECOND 24 +#define CYCLES_PER_MICROSECOND (F_CPU / 1000000U) //#define SYSTICK_RELOAD_VAL (F_CPU/1000) - 1 /* takes a cycle to reload */ #define SYSTICK_RELOAD_VAL 23999 /* takes a cycle to reload */ diff --git a/STM32F1/variants/generic_gd32f103c/board/board.h b/STM32F1/variants/generic_gd32f103c/board/board.h index 209bc36..50dd989 100644 --- a/STM32F1/variants/generic_gd32f103c/board/board.h +++ b/STM32F1/variants/generic_gd32f103c/board/board.h @@ -36,7 +36,7 @@ #ifndef _BOARD_GENERIC_STM32F103C_H_ #define _BOARD_GENERIC_STM32F103C_H_ -#define CYCLES_PER_MICROSECOND 72 +#define CYCLES_PER_MICROSECOND (F_CPU / 1000000U) #define SYSTICK_RELOAD_VAL (F_CPU/1000) - 1 /* takes a cycle to reload */ #define BOARD_NR_USARTS 3 diff --git a/STM32F1/variants/generic_stm32f103c/board/board.h b/STM32F1/variants/generic_stm32f103c/board/board.h index 97231e0..09351a6 100644 --- a/STM32F1/variants/generic_stm32f103c/board/board.h +++ b/STM32F1/variants/generic_stm32f103c/board/board.h @@ -36,7 +36,7 @@ #ifndef _BOARD_GENERIC_STM32F103C_H_ #define _BOARD_GENERIC_STM32F103C_H_ -#define CYCLES_PER_MICROSECOND 72 +#define CYCLES_PER_MICROSECOND (F_CPU / 1000000U) #define SYSTICK_RELOAD_VAL (F_CPU/1000) - 1 /* takes a cycle to reload */ #define BOARD_NR_USARTS 3 diff --git a/STM32F1/variants/generic_stm32f103r8/board/board.h b/STM32F1/variants/generic_stm32f103r8/board/board.h index 5f6855d..c274d64 100644 --- a/STM32F1/variants/generic_stm32f103r8/board/board.h +++ b/STM32F1/variants/generic_stm32f103r8/board/board.h @@ -36,7 +36,7 @@ #ifndef _BOARD_GENERIC_STM32F103R8_H_ #define _BOARD_GENERIC_STM32F103R8_H_ -#define CYCLES_PER_MICROSECOND 72 +#define CYCLES_PER_MICROSECOND (F_CPU / 1000000U) #define SYSTICK_RELOAD_VAL (F_CPU/1000) - 1 /* takes a cycle to reload */ #define BOARD_NR_USARTS 3 diff --git a/STM32F1/variants/generic_stm32f103t/board/board.h b/STM32F1/variants/generic_stm32f103t/board/board.h index 5454958..9b261f6 100644 --- a/STM32F1/variants/generic_stm32f103t/board/board.h +++ b/STM32F1/variants/generic_stm32f103t/board/board.h @@ -36,7 +36,7 @@ #ifndef _BOARD_GENERIC_STM32F103T_H_ #define _BOARD_GENERIC_STM32F103T_H_ -#define CYCLES_PER_MICROSECOND 72 +#define CYCLES_PER_MICROSECOND (F_CPU / 1000000U) #define SYSTICK_RELOAD_VAL (F_CPU/1000) - 1 /* takes a cycle to reload */ #define BOARD_NR_USARTS 2 diff --git a/STM32F1/variants/generic_stm32f103v/board/board.h b/STM32F1/variants/generic_stm32f103v/board/board.h index 210dbf8..92f2bf8 100644 --- a/STM32F1/variants/generic_stm32f103v/board/board.h +++ b/STM32F1/variants/generic_stm32f103v/board/board.h @@ -38,7 +38,7 @@ /* A few of these values will seem strange given that it's a * high-density board. */ -#define CYCLES_PER_MICROSECOND 72 +#define CYCLES_PER_MICROSECOND (F_CPU / 1000000U) #define SYSTICK_RELOAD_VAL (F_CPU/1000) - 1 /* takes a cycle to reload */ #define BOARD_BUTTON_PIN PC0 diff --git a/STM32F1/variants/hytiny_stm32f103t/board/board.h b/STM32F1/variants/hytiny_stm32f103t/board/board.h index 194b2e5..179e5e5 100644 --- a/STM32F1/variants/hytiny_stm32f103t/board/board.h +++ b/STM32F1/variants/hytiny_stm32f103t/board/board.h @@ -36,7 +36,7 @@ #ifndef _BOARD_GENERIC_STM32F103C_H_ #define _BOARD_GENERIC_STM32F103C_H_ -#define CYCLES_PER_MICROSECOND 72 +#define CYCLES_PER_MICROSECOND (F_CPU / 1000000U) #define SYSTICK_RELOAD_VAL (F_CPU/1000) - 1 /* takes a cycle to reload */ #define BOARD_NR_USARTS 2 diff --git a/STM32F1/variants/maple/board/board.h b/STM32F1/variants/maple/board/board.h index caebcc7..5a09286 100644 --- a/STM32F1/variants/maple/board/board.h +++ b/STM32F1/variants/maple/board/board.h @@ -34,7 +34,7 @@ #define _BOARD_MAPLE_H_ /* 72 MHz -> 72 cycles per microsecond. */ -#define CYCLES_PER_MICROSECOND 72 +#define CYCLES_PER_MICROSECOND (F_CPU / 1000000U) /* Roger clark diff --git a/STM32F1/variants/maple_mini/board/board.h b/STM32F1/variants/maple_mini/board/board.h index 10bcb5a..9064807 100644 --- a/STM32F1/variants/maple_mini/board/board.h +++ b/STM32F1/variants/maple_mini/board/board.h @@ -36,7 +36,7 @@ #ifndef _BOARD_MAPLE_MINI_H_ #define _BOARD_MAPLE_MINI_H_ -#define CYCLES_PER_MICROSECOND 72 +#define CYCLES_PER_MICROSECOND (F_CPU / 1000000U) #define SYSTICK_RELOAD_VAL (F_CPU/1000) - 1 /* takes a cycle to reload */ #define BOARD_NR_USARTS 3 diff --git a/STM32F1/variants/microduino/board/board.h b/STM32F1/variants/microduino/board/board.h index 2a1295f..0c06363 100644 --- a/STM32F1/variants/microduino/board/board.h +++ b/STM32F1/variants/microduino/board/board.h @@ -37,7 +37,7 @@ #ifndef _BOARD_MICRODUINO_STM32_H_ #define _BOARD_MICRODUINO_STM32_H_ -#define CYCLES_PER_MICROSECOND 72 +#define CYCLES_PER_MICROSECOND (F_CPU / 1000000U) #define SYSTICK_RELOAD_VAL (F_CPU/1000) - 1 /* takes a cycle to reload */ /* Roger Clark. diff --git a/STM32F1/variants/nucleo_f103rb/board/board.h b/STM32F1/variants/nucleo_f103rb/board/board.h index 02f46d9..b27862d 100644 --- a/STM32F1/variants/nucleo_f103rb/board/board.h +++ b/STM32F1/variants/nucleo_f103rb/board/board.h @@ -33,7 +33,7 @@ #ifndef _BOARD_MAPLE_H_ #define _BOARD_MAPLE_H_ #define _BOARD_NUCLEOF103RB_ 1 // hack for HardwareSerial.cpp for a new order of serials -#define CYCLES_PER_MICROSECOND 72 +#define CYCLES_PER_MICROSECOND (F_CPU / 1000000U) #define SYSTICK_RELOAD_VAL (F_CPU/1000) - 1 /* takes a cycle to reload */ /* Roger clark. Removed defines for LED pin and Button pin as they are not Arduino API defines */ diff --git a/STM32F3/variants/discovery_f3/board/board.h b/STM32F3/variants/discovery_f3/board/board.h index 179dede..6b04a8b 100644 --- a/STM32F3/variants/discovery_f3/board/board.h +++ b/STM32F3/variants/discovery_f3/board/board.h @@ -38,8 +38,8 @@ #include -#define CYCLES_PER_MICROSECOND 72 -#define SYSTICK_RELOAD_VAL 71999 /* takes a cycle to reload */ +#define CYCLES_PER_MICROSECOND (F_CPU / 1000000U) +#define SYSTICK_RELOAD_VAL (F_CPU/1000) - 1 /* takes a cycle to reload */ enum { PC13, PC14, PC15, From b19fc38e5e8e57f5df399e972edbc5968b5b16b3 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Fri, 26 May 2017 17:00:47 +1000 Subject: [PATCH 22/25] Applied change to fix issue in itoa.c and itoa.h with newer versions of GCC (using the changes from STM's fix, in Arduino_Core_STM32) --- STM32F1/cores/maple/itoa.c | 6 +++++- STM32F1/cores/maple/itoa.h | 5 +++++ STM32F4/cores/maple/itoa.c | 6 +++++- STM32F4/cores/maple/itoa.h | 5 +++++ 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/STM32F1/cores/maple/itoa.c b/STM32F1/cores/maple/itoa.c index fc35766..ee74f82 100644 --- a/STM32F1/cores/maple/itoa.c +++ b/STM32F1/cores/maple/itoa.c @@ -120,8 +120,12 @@ extern char* ltoa( long value, char *string, int radix ) return string; } - +#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 9 || \ + (__GNUC_MINOR__ == 9 && __GNUC_PATCHLEVEL__ > 2))) +extern char* utoa( unsigned value, char *string, int radix ) +#else extern char* utoa( unsigned long value, char *string, int radix ) +#endif { return ultoa( value, string, radix ) ; } diff --git a/STM32F1/cores/maple/itoa.h b/STM32F1/cores/maple/itoa.h index 59af109..b88204c 100644 --- a/STM32F1/cores/maple/itoa.h +++ b/STM32F1/cores/maple/itoa.h @@ -31,7 +31,12 @@ extern void itoa( int n, char s[] ) ; extern char* itoa( int value, char *string, int radix ) ; extern char* ltoa( long value, char *string, int radix ) ; +#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 9 || \ + (__GNUC_MINOR__ == 9 && __GNUC_PATCHLEVEL__ > 2))) +extern char* utoa( unsigned value, char *string, int radix ) ; +#else extern char* utoa( unsigned long value, char *string, int radix ) ; +#endif extern char* ultoa( unsigned long value, char *string, int radix ) ; #endif /* 0 */ diff --git a/STM32F4/cores/maple/itoa.c b/STM32F4/cores/maple/itoa.c index fc35766..ee74f82 100644 --- a/STM32F4/cores/maple/itoa.c +++ b/STM32F4/cores/maple/itoa.c @@ -120,8 +120,12 @@ extern char* ltoa( long value, char *string, int radix ) return string; } - +#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 9 || \ + (__GNUC_MINOR__ == 9 && __GNUC_PATCHLEVEL__ > 2))) +extern char* utoa( unsigned value, char *string, int radix ) +#else extern char* utoa( unsigned long value, char *string, int radix ) +#endif { return ultoa( value, string, radix ) ; } diff --git a/STM32F4/cores/maple/itoa.h b/STM32F4/cores/maple/itoa.h index 59af109..b88204c 100644 --- a/STM32F4/cores/maple/itoa.h +++ b/STM32F4/cores/maple/itoa.h @@ -31,7 +31,12 @@ extern void itoa( int n, char s[] ) ; extern char* itoa( int value, char *string, int radix ) ; extern char* ltoa( long value, char *string, int radix ) ; +#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 9 || \ + (__GNUC_MINOR__ == 9 && __GNUC_PATCHLEVEL__ > 2))) +extern char* utoa( unsigned value, char *string, int radix ) ; +#else extern char* utoa( unsigned long value, char *string, int radix ) ; +#endif extern char* ultoa( unsigned long value, char *string, int radix ) ; #endif /* 0 */ From 9ae2f6fa78bc258d61a11fc3f0157fd3537780d0 Mon Sep 17 00:00:00 2001 From: Zou Hanya Date: Sat, 3 Jun 2017 08:27:33 +0900 Subject: [PATCH 23/25] Avoid initializing USB serial twice --- STM32F1/cores/maple/usb_serial.cpp | 5 +++++ STM32F1/cores/maple/usb_serial.h | 3 +++ 2 files changed, 8 insertions(+) diff --git a/STM32F1/cores/maple/usb_serial.cpp b/STM32F1/cores/maple/usb_serial.cpp index 5eaf70e..32fe471 100644 --- a/STM32F1/cores/maple/usb_serial.cpp +++ b/STM32F1/cores/maple/usb_serial.cpp @@ -55,6 +55,7 @@ static void ifaceSetupHook(unsigned, void*); #define USB_TIMEOUT 50 +bool USBSerial::_hasBegun = false; USBSerial::USBSerial(void) { #if !BOARD_HAVE_SERIALUSB ASSERT(0); @@ -62,6 +63,9 @@ USBSerial::USBSerial(void) { } void USBSerial::begin(void) { + if (_hasBegun) + return; + _hasBegun = true; #if BOARD_HAVE_SERIALUSB usb_cdcacm_enable(BOARD_USB_DISC_DEV, BOARD_USB_DISC_BIT); usb_cdcacm_set_hooks(USB_CDCACM_HOOK_RX, rxHook); @@ -90,6 +94,7 @@ void USBSerial::end(void) { usb_cdcacm_disable(BOARD_USB_DISC_DEV, BOARD_USB_DISC_BIT); usb_cdcacm_remove_hooks(USB_CDCACM_HOOK_RX | USB_CDCACM_HOOK_IFACE_SETUP); #endif + _hasBegun = false; } size_t USBSerial::write(uint8 ch) { diff --git a/STM32F1/cores/maple/usb_serial.h b/STM32F1/cores/maple/usb_serial.h index 96bbefc..3146a3c 100644 --- a/STM32F1/cores/maple/usb_serial.h +++ b/STM32F1/cores/maple/usb_serial.h @@ -71,6 +71,9 @@ public: uint8 getDTR(); uint8 isConnected(); uint8 pending(); + +protected: + static bool _hasBegun; }; #ifdef SERIAL_USB From df78777e98a411036036388cb0ab809f35c6741a Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Tue, 6 Jun 2017 20:45:50 +1000 Subject: [PATCH 24/25] Add yield() call in delay() to support the Arduino Scheduler library. Ref issue #299 --- STM32F1/cores/maple/wirish_time.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/STM32F1/cores/maple/wirish_time.cpp b/STM32F1/cores/maple/wirish_time.cpp index 08fd2d1..6404bec 100644 --- a/STM32F1/cores/maple/wirish_time.cpp +++ b/STM32F1/cores/maple/wirish_time.cpp @@ -32,11 +32,15 @@ #include #include +#include "Arduino.h" void delay(unsigned long ms) { uint32 start = millis(); - while (millis() - start < ms) - ; + do + { + yield(); + } + while (millis() - start < ms); } void delayMicroseconds(uint32 us) { From 3c4307ebac3102bf95bc6fd7b637449860bef053 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Wed, 7 Jun 2017 14:00:24 +1000 Subject: [PATCH 25/25] Fix issue where USB Serial begin(xx) begin(xx,yy) did nothing, when they should ahave called begin() --- STM32F1/cores/maple/usb_serial.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/STM32F1/cores/maple/usb_serial.cpp b/STM32F1/cores/maple/usb_serial.cpp index 32fe471..1fe2bf4 100644 --- a/STM32F1/cores/maple/usb_serial.cpp +++ b/STM32F1/cores/maple/usb_serial.cpp @@ -54,8 +54,10 @@ static void ifaceSetupHook(unsigned, void*); */ #define USB_TIMEOUT 50 - +#if BOARD_HAVE_SERIALUSB bool USBSerial::_hasBegun = false; +#endif + USBSerial::USBSerial(void) { #if !BOARD_HAVE_SERIALUSB ASSERT(0); @@ -63,10 +65,12 @@ USBSerial::USBSerial(void) { } void USBSerial::begin(void) { + +#if BOARD_HAVE_SERIALUSB if (_hasBegun) return; _hasBegun = true; -#if BOARD_HAVE_SERIALUSB + usb_cdcacm_enable(BOARD_USB_DISC_DEV, BOARD_USB_DISC_BIT); usb_cdcacm_set_hooks(USB_CDCACM_HOOK_RX, rxHook); usb_cdcacm_set_hooks(USB_CDCACM_HOOK_IFACE_SETUP, ifaceSetupHook); @@ -79,6 +83,7 @@ void USBSerial::begin(unsigned long ignoreBaud) volatile unsigned long removeCompilerWarningsIgnoreBaud=ignoreBaud; ignoreBaud=removeCompilerWarningsIgnoreBaud; + begin(); } void USBSerial::begin(unsigned long ignoreBaud, uint8_t ignore) { @@ -87,14 +92,16 @@ volatile uint8_t removeCompilerWarningsIgnore=ignore; ignoreBaud=removeCompilerWarningsIgnoreBaud; ignore=removeCompilerWarningsIgnore; + begin(); } void USBSerial::end(void) { #if BOARD_HAVE_SERIALUSB usb_cdcacm_disable(BOARD_USB_DISC_DEV, BOARD_USB_DISC_BIT); usb_cdcacm_remove_hooks(USB_CDCACM_HOOK_RX | USB_CDCACM_HOOK_IFACE_SETUP); + _hasBegun = false; #endif - _hasBegun = false; + } size_t USBSerial::write(uint8 ch) {