From 0ec7e72b01dca8070c1a8ae9a0b0347d2281eadb Mon Sep 17 00:00:00 2001 From: stevstrong Date: Fri, 21 Oct 2016 22:31:27 +0200 Subject: [PATCH 001/351] 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 002/351] 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 003/351] 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 004/351] 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 005/351] 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 006/351] 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 007/351] 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 6030e1325878a264338c65905bbda47a8fa9d85a Mon Sep 17 00:00:00 2001 From: Testato Date: Sat, 17 Dec 2016 12:29:42 +0100 Subject: [PATCH 008/351] Update boards.txt PR for issue https://github.com/rogerclarkmelbourne/Arduino_STM32/issues/200 --- STM32F1/boards.txt | 82 ++++++++++++++++------------------------------ 1 file changed, 29 insertions(+), 53 deletions(-) diff --git a/STM32F1/boards.txt b/STM32F1/boards.txt index 95a5f86..030a961 100644 --- a/STM32F1/boards.txt +++ b/STM32F1/boards.txt @@ -25,17 +25,15 @@ mapleMini.upload.auto_reset=true mapleMini.menu.bootloader_version.original = Original (17k RAM,108k Flash) mapleMini.menu.bootloader_version.original.build.vect=VECT_TAB_ADDR=0x8005000 mapleMini.menu.bootloader_version.original.build.ldscript=ld/flash.ld -mapleMini.menu.bootloader_version.original.upload.ram.maximum_size=17408 -mapleMini.menu.bootloader_version.original.upload.flash.maximum_size=110592 mapleMini.menu.bootloader_version.original.upload.maximum_size=110592 +mapleMini.menu.bootloader_version.original.upload.maximum_data_size=17408 mapleMini.menu.bootloader_version.original.upload.altID=1 mapleMini.menu.bootloader_version.bootloader20 = Bootloader 2.0 (20k RAM,120k Flash) mapleMini.menu.bootloader_version.bootloader20.build.vect=VECT_TAB_ADDR=0x8002000 mapleMini.menu.bootloader_version.bootloader20.build.ldscript=ld/bootloader_20.ld -mapleMini.menu.bootloader_version.bootloader20.upload.ram.maximum_size=20480 -mapleMini.menu.bootloader_version.bootloader20.upload.flash.maximum_size=122880 mapleMini.menu.bootloader_version.bootloader20.upload.maximum_size=122880 +mapleMini.menu.bootloader_version.bootloader20.upload.maximum_data_size=20480 mapleMini.menu.bootloader_version.bootloader20.upload.altID=2 ############################################################## @@ -46,10 +44,9 @@ maple.pid.0=0x0004 maple.upload.tool=maple_upload maple.upload.protocol=maple_dfu maple.upload.maximum_size=108000 +maple.upload.maximum_data_size=17000 maple.upload.use_1200bps_touch=false maple.upload.file_type=bin -maple.upload.ram.maximum_size=17000 -maple.upload.flash.maximum_size=108000 maple.upload.usbID=1EAF:0003 maple.upload.altID=1 maple.upload.auto_reset=true @@ -77,10 +74,9 @@ mapleRET6.build.vect=VECT_TAB_ADDR=0x8005000 mapleRET6.upload.tool=maple_upload mapleRET6.upload.protocol=maple_dfu mapleRET6.upload.maximum_size=262144 +mapleRET6.upload.maximum_data_size=49152 mapleRET6.upload.use_1200bps_touch=false mapleRET6.upload.file_type=bin -mapleRET6.upload.ram.maximum_size=49152 -mapleRET6.upload.flash.maximum_size=262144 mapleRET6.upload.usbID=1EAF:0003 mapleRET6.upload.altID=1 mapleRET6.upload.auto_reset=true @@ -94,10 +90,9 @@ microduino32_flash.pid.0=0x0004 microduino32_flash.upload.tool=maple_upload microduino32_flash.upload.protocol=maple_dfu microduino32_flash.upload.maximum_size=108000 +microduino32_flash.upload.maximum_data_size=17000 microduino32_flash.upload.use_1200bps_touch=false microduino32_flash.upload.file_type=bin -microduino32_flash.upload.ram.maximum_size=17000 -microduino32_flash.upload.flash.maximum_size=108000 microduino32_flash.upload.usbID=1EAF:0003 microduino32_flash.upload.altID=1 microduino32_flash.upload.auto_reset=true @@ -123,10 +118,9 @@ nucleo_f103rb.name=STM Nucleo F103RB (STLink) nucleo_f103rb.upload.tool=stlink_upload nucleo_f103rb.upload.protocol=maple_dfu nucleo_f103rb.upload.maximum_size=108000 +nucleo_f103rb.upload.maximum_data_size=17000 nucleo_f103rb.upload.use_1200bps_touch=false nucleo_f103rb.upload.file_type=bin -nucleo_f103rb.upload.ram.maximum_size=17000 -nucleo_f103rb.upload.flash.maximum_size=108000 nucleo_f103rb.upload.params.quiet=no nucleo_f103rb.upload.usbID=1EAF:0003 @@ -174,16 +168,14 @@ genericSTM32F103C.menu.device_variant.STM32F103C8=STM32F103C8 (20k RAM. 64k Flas genericSTM32F103C.menu.device_variant.STM32F103C8.build.cpu_flags=-DMCU_STM32F103C8 genericSTM32F103C.menu.device_variant.STM32F103C8.build.ldscript=ld/jtag_c8.ld genericSTM32F103C.menu.device_variant.STM32F103C8.upload.maximum_size=65536 -genericSTM32F103C.menu.device_variant.STM32F103C8.upload.ram.maximum_size=20480 -genericSTM32F103C.menu.device_variant.STM32F103C8.upload.flash.maximum_size=65536 +genericSTM32F103C.menu.device_variant.STM32F103C8.upload.maximum_data_size=20480 ## STM32F103CB ------------------------- genericSTM32F103C.menu.device_variant.STM32F103CB=STM32F103CB (20k RAM. 128k Flash) genericSTM32F103C.menu.device_variant.STM32F103CB.build.cpu_flags=-DMCU_STM32F103CB genericSTM32F103C.menu.device_variant.STM32F103CB.build.ldscript=ld/jtag.ld genericSTM32F103C.menu.device_variant.STM32F103CB.upload.maximum_size=131072 -genericSTM32F103C.menu.device_variant.STM32F103CB.upload.ram.maximum_size=20480 -genericSTM32F103C.menu.device_variant.STM32F103CB.upload.flash.maximum_size=131072 +genericSTM32F103C.menu.device_variant.STM32F103C8.upload.maximum_data_size=20480 #---------------------------- UPLOAD METHODS --------------------------- @@ -211,7 +203,6 @@ genericSTM32F103C.menu.upload_method.BMPMethod.upload.protocol=gdb_bmp genericSTM32F103C.menu.upload_method.BMPMethod.upload.tool=bmp_upload genericSTM32F103C.menu.upload_method.BMPMethod.build.upload_flags=-DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG - genericSTM32F103C.menu.upload_method.jlinkMethod=JLink genericSTM32F103C.menu.upload_method.jlinkMethod.upload.protocol=jlink genericSTM32F103C.menu.upload_method.jlinkMethod.upload.tool=jlink_upload @@ -234,22 +225,21 @@ genericSTM32F103R.menu.device_variant.STM32F103R8=STM32F103R8 (20k RAM. 64k Flas genericSTM32F103R.menu.device_variant.STM32F103R8.build.variant=generic_stm32f103r8 genericSTM32F103R.menu.device_variant.STM32F103R8.build.cpu_flags=-DMCU_STM32F103R8 genericSTM32F103R.menu.device_variant.STM32F103R8.upload.maximum_size=65536 -genericSTM32F103R.menu.device_variant.STM32F103R8.upload.ram.maximum_size=20480 -genericSTM32F103R.menu.device_variant.STM32F103R8.upload.flash.maximum_size=65536 +genericSTM32F103R.menu.device_variant.STM32F103R8.upload.maximum_data_size=20480 genericSTM32F103R.menu.device_variant.STM32F103R8.build.ldscript=ld/stm32f103r8.ld genericSTM32F103R.menu.device_variant.STM32F103RB=STM32F103RB (20k RAM. 128k Flash) genericSTM32F103R.menu.device_variant.STM32F103RB.build.variant=generic_stm32f103r8 genericSTM32F103R.menu.device_variant.STM32F103RB.build.cpu_flags=-DMCU_STM32F103RB genericSTM32F103R.menu.device_variant.STM32F103RB.upload.maximum_size=131072 -genericSTM32F103R.menu.device_variant.STM32F103RB.upload.ram.maximum_size=20480 -genericSTM32F103R.menu.device_variant.STM32F103RB.upload.flash.maximum_size=131072 +genericSTM32F103R.menu.device_variant.STM32F103RB.upload.maximum_data_size=20480 genericSTM32F103R.menu.device_variant.STM32F103RB.build.ldscript=ld/stm32f103rb.ld genericSTM32F103R.menu.device_variant.STM32F103RC=STM32F103RC (48k RAM. 256k Flash) genericSTM32F103R.menu.device_variant.STM32F103RC.build.variant=generic_stm32f103r genericSTM32F103R.menu.device_variant.STM32F103RC.build.cpu_flags=-DMCU_STM32F103RC genericSTM32F103R.menu.device_variant.STM32F103RC.upload.maximum_size=262144 +genericSTM32F103R.menu.device_variant.STM32F103RC.upload.maximum_data_size=49152 genericSTM32F103R.menu.device_variant.STM32F103RC.upload.ram.maximum_size=49152 genericSTM32F103R.menu.device_variant.STM32F103RC.upload.flash.maximum_size=262144 genericSTM32F103R.menu.device_variant.STM32F103RC.build.ldscript=ld/stm32f103rc.ld @@ -258,8 +248,7 @@ genericSTM32F103R.menu.device_variant.STM32F103RE=STM32F103RE (64k RAM. 512k Fla genericSTM32F103R.menu.device_variant.STM32F103RE.build.variant=generic_stm32f103r genericSTM32F103R.menu.device_variant.STM32F103RE.build.cpu_flags=-DMCU_STM32F103RE genericSTM32F103R.menu.device_variant.STM32F103RE.upload.maximum_size=524288 -genericSTM32F103R.menu.device_variant.STM32F103RE.upload.ram.maximum_size=65536 -genericSTM32F103R.menu.device_variant.STM32F103RE.upload.flash.maximum_size=524288 +genericSTM32F103R.menu.device_variant.STM32F103RE.upload.maximum_data_size=65536 genericSTM32F103R.menu.device_variant.STM32F103RE.build.ldscript=ld/stm32f103re.ld #---------------------------- UPLOAD METHODS --------------------------- @@ -305,16 +294,14 @@ genericSTM32F103T.menu.device_variant.STM32F103T8=STM32F103T8 (20k RAM. 64k Flas genericSTM32F103T.menu.device_variant.STM32F103T8.build.cpu_flags=-DMCU_STM32F103T8 genericSTM32F103T.menu.device_variant.STM32F103T8.build.ldscript=ld/jtag_t8.ld genericSTM32F103T.menu.device_variant.STM32F103T8.upload.maximum_size=65536 -genericSTM32F103T.menu.device_variant.STM32F103T8.upload.ram.maximum_size=20480 -genericSTM32F103T.menu.device_variant.STM32F103T8.upload.flash.maximum_size=65536 +genericSTM32F103T.menu.device_variant.STM32F103T8.upload.maximum_data_size=20480 ## STM32F103TB ------------------------- genericSTM32F103T.menu.device_variant.STM32F103TB=STM32F103TB (20k RAM. 128k Flash) genericSTM32F103T.menu.device_variant.STM32F103TB.build.cpu_flags=-DMCU_STM32F103TB genericSTM32F103T.menu.device_variant.STM32F103TB.build.ldscript=ld/jtag.ld genericSTM32F103T.menu.device_variant.STM32F103TB.upload.maximum_size=131072 -genericSTM32F103T.menu.device_variant.STM32F103TB.upload.ram.maximum_size=20480 -genericSTM32F103T.menu.device_variant.STM32F103TB.upload.flash.maximum_size=131072 +genericSTM32F103T.menu.device_variant.STM32F103TB.upload.maximum_data_size=20480 #---------------------------- UPLOAD METHODS --------------------------- @@ -360,22 +347,19 @@ genericSTM32F103V.build.error_led_pin=6 genericSTM32F103V.menu.device_variant.STM32F103VC=STM32F103VC genericSTM32F103V.menu.device_variant.STM32F103VC.build.cpu_flags=-DMCU_STM32F103VC genericSTM32F103V.menu.device_variant.STM32F103VC.upload.maximum_size=262144 -genericSTM32F103V.menu.device_variant.STM32F103VC.upload.ram.maximum_size=49152 -genericSTM32F103V.menu.device_variant.STM32F103VC.upload.flash.maximum_size=262144 +genericSTM32F103V.menu.device_variant.STM32F103VC.upload.maximum_data_size=49152 genericSTM32F103V.menu.device_variant.STM32F103VC.build.ldscript=ld/stm32f103vc.ld genericSTM32F103V.menu.device_variant.STM32F103VD=STM32F103VD genericSTM32F103V.menu.device_variant.STM32F103VD.build.cpu_flags=-DMCU_STM32F103VD genericSTM32F103V.menu.device_variant.STM32F103VD.upload.maximum_size=393216 -genericSTM32F103V.menu.device_variant.STM32F103VD.upload.ram.maximum_size=65536 -genericSTM32F103V.menu.device_variant.STM32F103VD.upload.flash.maximum_size=393216 +genericSTM32F103V.menu.device_variant.STM32F103VD.upload.maximum_data_size=65536 genericSTM32F103V.menu.device_variant.STM32F103VD.build.ldscript=ld/stm32f103vd.ld genericSTM32F103V.menu.device_variant.STM32F103VE=STM32F103VE genericSTM32F103V.menu.device_variant.STM32F103VE.build.cpu_flags=-DMCU_STM32F103VE genericSTM32F103V.menu.device_variant.STM32F103VE.upload.maximum_size=524288 -genericSTM32F103V.menu.device_variant.STM32F103VE.upload.ram.maximum_size=65536 -genericSTM32F103V.menu.device_variant.STM32F103VE.upload.flash.maximum_size=524288 +genericSTM32F103V.menu.device_variant.STM32F103VE.upload.maximum_data_size=65536 genericSTM32F103V.menu.device_variant.STM32F103VE.build.ldscript=ld/stm32f103ve.ld #---------------------------- UPLOAD METHODS --------------------------- @@ -419,22 +403,19 @@ genericSTM32F103Z.upload.auto_reset=true genericSTM32F103Z.menu.device_variant.STM32F103ZC=STM32F103ZC genericSTM32F103Z.menu.device_variant.STM32F103ZC.build.cpu_flags=-DMCU_STM32F103ZC genericSTM32F103Z.menu.device_variant.STM32F103ZC.upload.maximum_size=262144 -genericSTM32F103Z.menu.device_variant.STM32F103ZC.upload.ram.maximum_size=49152 -genericSTM32F103Z.menu.device_variant.STM32F103ZC.upload.flash.maximum_size=262144 +genericSTM32F103Z.menu.device_variant.STM32F103ZC.upload.maximum_data_size=49152 genericSTM32F103Z.menu.device_variant.STM32F103ZC.build.ldscript=ld/stm32f103zc.ld genericSTM32F103Z.menu.device_variant.STM32F103ZD=STM32F103ZD genericSTM32F103Z.menu.device_variant.STM32F103ZD.build.cpu_flags=-DMCU_STM32F103ZD genericSTM32F103Z.menu.device_variant.STM32F103ZD.upload.maximum_size=393216 -genericSTM32F103Z.menu.device_variant.STM32F103ZD.upload.ram.maximum_size=65536 -genericSTM32F103Z.menu.device_variant.STM32F103ZD.upload.flash.maximum_size=393216 +genericSTM32F103Z.menu.device_variant.STM32F103ZD.upload.maximum_data_size=65536 genericSTM32F103Z.menu.device_variant.STM32F103ZD.build.ldscript=ld/stm32f103zd.ld genericSTM32F103Z.menu.device_variant.STM32F103ZE=STM32F103ZE genericSTM32F103Z.menu.device_variant.STM32F103ZE.build.cpu_flags=-DMCU_STM32F103ZE genericSTM32F103Z.menu.device_variant.STM32F103ZE.upload.maximum_size=524288 -genericSTM32F103Z.menu.device_variant.STM32F103ZE.upload.ram.maximum_size=65536 -genericSTM32F103Z.menu.device_variant.STM32F103ZE.upload.flash.maximum_size=524288 +genericSTM32F103Z.menu.device_variant.STM32F103ZE.upload.maximum_data_size=65536 genericSTM32F103Z.menu.device_variant.STM32F103ZE.build.ldscript=ld/stm32f103ze.ld #---------------------------- UPLOAD METHODS --------------------------- @@ -479,9 +460,7 @@ hytiny-stm32f103t.upload.auto_reset=true hytiny-stm32f103t.build.cpu_flags=-DMCU_STM32F103CB hytiny-stm32f103t.build.ldscript=ld/jtag.ld hytiny-stm32f103t.upload.maximum_size=131072 -hytiny-stm32f103t.upload.ram.maximum_size=20480 -hytiny-stm32f103t.upload.flash.maximum_size=131072 - +hytiny-stm32f103t.upload.maximum_data_size=20480 #---------------------------- UPLOAD METHODS --------------------------- @@ -529,20 +508,17 @@ genericGD32F103C.upload.auto_reset=true genericGD32F103C.build.cpu_flags=-DMCU_STM32F103CB genericGD32F103C.build.f_cpu=72000000L -## GD32F103CB ------------------------- -genericGD32F103C.menu.device_variant.GD32F103CB=GD32F103CB (20k RAM. 128k Flash) -genericGD32F103C.menu.device_variant.GD32F103CB.build.ldscript=ld/jtag.ld -genericGD32F103C.menu.device_variant.GD32F103CB.upload.maximum_size=131072 -genericGD32F103C.menu.device_variant.GD32F103CB.upload.ram.maximum_size=20480 -genericGD32F103C.menu.device_variant.GD32F103CB.upload.flash.maximum_size=131072 - - ## GD32F103C8 ------------------------- genericGD32F103C.menu.device_variant.GD32F103C8=GD32F103C8 (20k RAM. 64k Flash) genericGD32F103C.menu.device_variant.GD32F103C8.build.ldscript=ld/jtag_c8.ld genericGD32F103C.menu.device_variant.GD32F103C8.upload.maximum_size=65536 -genericGD32F103C.menu.device_variant.GD32F103C8.upload.ram.maximum_size=20480 -genericGD32F103C.menu.device_variant.GD32F103C8.upload.flash.maximum_size=65536 +genericGD32F103C.menu.device_variant.GD32F103C8.upload.maximum_data_size=20480 + +## GD32F103CB ------------------------- +genericGD32F103C.menu.device_variant.GD32F103CB=GD32F103CB (20k RAM. 128k Flash) +genericGD32F103C.menu.device_variant.GD32F103CB.build.ldscript=ld/jtag.ld +genericGD32F103C.menu.device_variant.GD32F103CB.upload.maximum_size=131072 +genericGD32F103C.menu.device_variant.GD32F103CB.upload.maximum_data_size=20480 #---------------------------- UPLOAD METHODS --------------------------- @@ -601,8 +577,8 @@ STM32VLD.upload.auto_reset=true STM32VLD.upload.params.quiet=no STM32VLD.build.cpu_flags=-DMCU_STM32F100RB -##---------------------------- UPLOAD METHODS --------------------------- +#---------------------------- UPLOAD METHODS --------------------------- STM32VLD.menu.upload_method.STLinkMethod=STLink STM32VLD.menu.upload_method.STLinkMethod.upload.protocol=STLink From 99ba590bd491df803d7fc6f4fb2ca1859c0f1a18 Mon Sep 17 00:00:00 2001 From: Testato Date: Sat, 17 Dec 2016 12:38:20 +0100 Subject: [PATCH 009/351] Update boards.txt PR for issue https://github.com/rogerclarkmelbourne/Arduino_STM32/issues/200 - replaced `upload.flash.maximum_size` and `upload.ram.maximum_size` by the new arduino standard `upload.maximum_size` and `upload.maximum_data_size` - corrected Flash and Ram value - Tested by builded --- STM32F3/boards.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/STM32F3/boards.txt b/STM32F3/boards.txt index 82b2bc5..6c011bc 100644 --- a/STM32F3/boards.txt +++ b/STM32F3/boards.txt @@ -8,9 +8,8 @@ discovery_f3.upload.protocol=stlink #discovery_f407.upload.use_1200bps_touch=false discovery_f3.upload.file_type=bin -discovery_f3.upload.ram.maximum_size=17000 -discovery_f3.upload.flash.maximum_size=108000 -discovery_f3.upload.maximum_size=108000 +discovery_f3.upload.maximum_size=262144 +discovery_f3.upload.maximum_data_size=49152 #discovery_f3.upload.usbID=1EAF:0003 #discovery_f3.upload.altID=1 From 54d67d77c4b01f22fa4910b841d13f61da8163af Mon Sep 17 00:00:00 2001 From: Testato Date: Sat, 17 Dec 2016 12:41:23 +0100 Subject: [PATCH 010/351] Update boards.txt PR for issue https://github.com/rogerclarkmelbourne/Arduino_STM32/issues/200 - replaced `upload.flash.maximum_size` and `upload.ram.maximum_size` by the new arduino standard `upload.maximum_size` and `upload.maximum_data_size` - corrected Flash and Ram value - Tested by builded every MCU on every Variant --- STM32F4/boards.txt | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/STM32F4/boards.txt b/STM32F4/boards.txt index 7577d19..daa1a04 100644 --- a/STM32F4/boards.txt +++ b/STM32F4/boards.txt @@ -8,9 +8,8 @@ discovery_f407.upload.protocol=stlink #discovery_f407.upload.use_1200bps_touch=false discovery_f407.upload.file_type=bin -discovery_f407.upload.ram.maximum_size=17000 -discovery_f407.upload.flash.maximum_size=1048576 discovery_f407.upload.maximum_size=1048576 +discovery_f407.upload.maximum_data_size=196608 #discovery_f407.upload.usbID=1EAF:0003 #discovery_f407.upload.altID=1 @@ -37,9 +36,8 @@ stm32f4stamp.upload.protocol=maple_dfu #stm32f4stamp.upload.use_1200bps_touch=false stm32f4stamp.upload.file_type=bin -stm32f4stamp.upload.ram.maximum_size=196608 -stm32f4stamp.upload.flash.maximum_size=1048576 stm32f4stamp.upload.maximum_size=1048576 +stm32f4stamp.upload.maximum_data_size=196608 stm32f4stamp.upload.usbID=0483:df11 stm32f4stamp.upload.altID=0 @@ -67,9 +65,8 @@ netduino2plus.upload.protocol=maple_dfu #netduino2plus.upload.use_1200bps_touch=false netduino2plus.upload.file_type=bin -netduino2plus.upload.ram.maximum_size=196608 -netduino2plus.upload.flash.maximum_size=1048576 netduino2plus.upload.maximum_size=1048576 +netduino2plus.upload.maximum_data_size=196608 netduino2plus.upload.usbID=0483:df11 netduino2plus.upload.altID=0 From fb823b6929e4416b0921b4ff6c9ea4fa5a186262 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Mon, 26 Dec 2016 15:26:51 +0100 Subject: [PATCH 011/351] 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 a8d1c1d1b614a5ed6924df3facc72a5f9980e34d Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Sun, 26 Feb 2017 13:26:24 +1100 Subject: [PATCH 012/351] Disabled SWD pins for all boards when using DFU (bootloader) upload method --- STM32F1/boards.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/STM32F1/boards.txt b/STM32F1/boards.txt index 24202fc..d5c4ec9 100644 --- a/STM32F1/boards.txt +++ b/STM32F1/boards.txt @@ -198,7 +198,7 @@ genericSTM32F103C.menu.device_variant.STM32F103CB.upload.flash.maximum_size=1310 genericSTM32F103C.menu.upload_method.DFUUploadMethod=STM32duino bootloader genericSTM32F103C.menu.upload_method.DFUUploadMethod.upload.protocol=maple_dfu genericSTM32F103C.menu.upload_method.DFUUploadMethod.upload.tool=maple_upload -genericSTM32F103C.menu.upload_method.DFUUploadMethod.build.upload_flags=-DSERIAL_USB -DGENERIC_BOOTLOADER -DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG=1 +genericSTM32F103C.menu.upload_method.DFUUploadMethod.build.upload_flags=-DSERIAL_USB -DGENERIC_BOOTLOADER genericSTM32F103C.menu.upload_method.DFUUploadMethod.build.vect=VECT_TAB_ADDR=0x8002000 genericSTM32F103C.menu.upload_method.DFUUploadMethod.build.ldscript=ld/bootloader_20.ld genericSTM32F103C.menu.upload_method.DFUUploadMethod.upload.usbID=1EAF:0003 @@ -282,7 +282,7 @@ genericSTM32F103R.menu.device_variant.STM32F103RE.build.ldscript=ld/stm32f103re. genericSTM32F103R.menu.upload_method.DFUUploadMethod=STM32duino bootloader genericSTM32F103R.menu.upload_method.DFUUploadMethod.upload.protocol=maple_dfu genericSTM32F103R.menu.upload_method.DFUUploadMethod.upload.tool=maple_upload -genericSTM32F103R.menu.upload_method.DFUUploadMethod.build.upload_flags=-DSERIAL_USB -DGENERIC_BOOTLOADER -DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG=1 +genericSTM32F103R.menu.upload_method.DFUUploadMethod.build.upload_flags=-DSERIAL_USB -DGENERIC_BOOTLOADER genericSTM32F103R.menu.upload_method.DFUUploadMethod.build.vect=VECT_TAB_ADDR=0x8002000 genericSTM32F103R.menu.upload_method.DFUUploadMethod.build.ldscript=ld/bootloader.ld genericSTM32F103R.menu.upload_method.DFUUploadMethod.upload.usbID=1EAF:0003 @@ -337,7 +337,7 @@ genericSTM32F103T.menu.device_variant.STM32F103TB.upload.flash.maximum_size=1310 genericSTM32F103T.menu.upload_method.DFUUploadMethod=STM32duino bootloader genericSTM32F103T.menu.upload_method.DFUUploadMethod.upload.protocol=maple_dfu genericSTM32F103T.menu.upload_method.DFUUploadMethod.upload.tool=maple_upload -genericSTM32F103T.menu.upload_method.DFUUploadMethod.build.upload_flags=-DSERIAL_USB -DGENERIC_BOOTLOADER -DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG=1 +genericSTM32F103T.menu.upload_method.DFUUploadMethod.build.upload_flags=-DSERIAL_USB -DGENERIC_BOOTLOADER genericSTM32F103T.menu.upload_method.DFUUploadMethod.build.vect=VECT_TAB_ADDR=0x8002000 genericSTM32F103T.menu.upload_method.DFUUploadMethod.build.ldscript=ld/bootloader_20.ld genericSTM32F103T.menu.upload_method.DFUUploadMethod.upload.usbID=1EAF:0003 @@ -400,7 +400,7 @@ genericSTM32F103V.menu.device_variant.STM32F103VE.build.ldscript=ld/stm32f103ve. genericSTM32F103V.menu.upload_method.DFUUploadMethod=STM32duino bootloader genericSTM32F103V.menu.upload_method.DFUUploadMethod.upload.protocol=maple_dfu genericSTM32F103V.menu.upload_method.DFUUploadMethod.upload.tool=maple_upload -genericSTM32F103V.menu.upload_method.DFUUploadMethod.build.upload_flags=-DSERIAL_USB -DGENERIC_BOOTLOADER -DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG=1 +genericSTM32F103V.menu.upload_method.DFUUploadMethod.build.upload_flags=-DSERIAL_USB -DGENERIC_BOOTLOADER genericSTM32F103V.menu.upload_method.DFUUploadMethod.build.vect=VECT_TAB_ADDR=0x8002000 genericSTM32F103V.menu.upload_method.DFUUploadMethod.build.ldscript=ld/stm32f103veDFU.ld genericSTM32F103V.menu.upload_method.DFUUploadMethod.upload.usbID=1EAF:0003 @@ -460,7 +460,7 @@ genericSTM32F103Z.menu.device_variant.STM32F103ZE.build.ldscript=ld/stm32f103ze. genericSTM32F103Z.menu.upload_method.DFUUploadMethod=STM32duino bootloader genericSTM32F103Z.menu.upload_method.DFUUploadMethod.upload.protocol=maple_dfu genericSTM32F103Z.menu.upload_method.DFUUploadMethod.upload.tool=maple_upload -genericSTM32F103Z.menu.upload_method.DFUUploadMethod.build.upload_flags=-DSERIAL_USB -DGENERIC_BOOTLOADER -DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG=1 +genericSTM32F103Z.menu.upload_method.DFUUploadMethod.build.upload_flags=-DSERIAL_USB -DGENERIC_BOOTLOADER genericSTM32F103Z.menu.upload_method.DFUUploadMethod.build.vect=VECT_TAB_ADDR=0x8002000 genericSTM32F103Z.menu.upload_method.DFUUploadMethod.build.ldscript=ld/stm32f103z_dfu.ld genericSTM32F103Z.menu.upload_method.DFUUploadMethod.upload.usbID=1EAF:0003 @@ -569,7 +569,7 @@ genericGD32F103C.menu.upload_method.DFUUploadMethod=GD32duino bootloader genericGD32F103C.menu.upload_method.DFUUploadMethod.upload.protocol=maple_dfu genericGD32F103C.menu.upload_method.DFUUploadMethod.upload.tool=maple_upload -genericGD32F103C.menu.upload_method.DFUUploadMethod.build.upload_flags=-DSERIAL_USB -DGENERIC_BOOTLOADER -DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG=1 +genericGD32F103C.menu.upload_method.DFUUploadMethod.build.upload_flags=-DSERIAL_USB -DGENERIC_BOOTLOADER genericGD32F103C.menu.upload_method.DFUUploadMethod.build.vect=VECT_TAB_ADDR=0x8002000 genericGD32F103C.menu.upload_method.DFUUploadMethod.build.ldscript=ld/bootloader_20.ld genericGD32F103C.menu.upload_method.DFUUploadMethod.upload.usbID=1EAF:0003 From 9b759c87f8635bf8f6551cafcadfcb5944396821 Mon Sep 17 00:00:00 2001 From: Floris Lambrechts Date: Wed, 22 Mar 2017 13:55:27 +0100 Subject: [PATCH 013/351] Fix F103T compilation error: remove const Method adc_default_config still had the adc_dev* 'const' for F103T, but this doesn't compile. For other boards, the 'const' was removed already. See for example commits 0b34af3b6a29c2ea40a0005fde57f67f75829378 and 2cdbbc83390b27570c9040fc92bda6e63947f160. Tested on Arduino IDE 1.6.13. Compilation error message was along these lines: STM32F1\variants\generic_stm32f103t\wirish\boards.cpp:183:34: error: invalid conversion from 'const adc_dev*' to 'adc_dev*' [-fpermissive] STM32F1\system/libmaple/include/libmaple/adc.h:306:13: error: initializing argument 1 of 'void adc_enable_single_swstart(adc_dev*)' [-fpermissive] STM32F1\variants\generic_stm32f103t\wirish\boards.cpp:184:53: error: invalid conversion from 'const adc_dev*' to 'adc_dev*' [-fpermissive] STM32F1\system/libmaple/include/libmaple/adc.h:268:6: error: initializing argument 1 of 'void adc_set_sample_rate(adc_dev*, adc_smp_rate)' [-fpermissive] STM32F1\variants\generic_stm32f103t\wirish\boards.cpp: In function 'void setup_adcs()': STM32F1\variants\generic_stm32f103t\wirish\boards.cpp:189:35: error: invalid conversion from 'void (*)(const adc_dev*)' to 'void (*)(adc_dev*)' [-fpermissive] STM32F1\system/libmaple/include/libmaple/adc.h:282:13: error: initializing argument 1 of 'void adc_foreach(void (*)(adc_dev*))' [-fpermissive] --- STM32F1/variants/generic_stm32f103t/wirish/boards.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/variants/generic_stm32f103t/wirish/boards.cpp b/STM32F1/variants/generic_stm32f103t/wirish/boards.cpp index 0c018e8..5274e7a 100644 --- a/STM32F1/variants/generic_stm32f103t/wirish/boards.cpp +++ b/STM32F1/variants/generic_stm32f103t/wirish/boards.cpp @@ -179,7 +179,7 @@ nvic_init((uint32)VECT_TAB_ADDR, 0); */ } -static void adc_default_config(const adc_dev *dev) { +static void adc_default_config(adc_dev *dev) { adc_enable_single_swstart(dev); adc_set_sample_rate(dev, wirish::priv::w_adc_smp); } From ea81f36fa526f17bf7069474720caa001382b898 Mon Sep 17 00:00:00 2001 From: victorpv Date: Sat, 25 Mar 2017 08:31:44 -0500 Subject: [PATCH 014/351] FreeRTOS900 --- .../FreeRTOS900/MapleFreeRTOS900.cpp | 44 + .../libraries/FreeRTOS900/MapleFreeRTOS900.h | 40 + .../examples/rtos_blink/rtos_blink.ino | 31 + .../rtos_display_blink/rtos_display_blink.ino | 212 + .../libraries/FreeRTOS900/utility/FreeRTOS.h | 1063 ++++ .../FreeRTOS900/utility/FreeRTOSConfig.h | 144 + .../FreeRTOS900/utility/MemMang/heap_1.c | 174 + .../FreeRTOS900/utility/MemMang/heap_2.c | 303 ++ .../FreeRTOS900/utility/MemMang/heap_3.c | 135 + .../FreeRTOS900/utility/MemMang/heap_4.c | 474 ++ .../FreeRTOS900/utility/MemMang/heap_5.c | 523 ++ .../FreeRTOS900/utility/StackMacros.h | 171 + .../libraries/FreeRTOS900/utility/croutine.c | 395 ++ .../libraries/FreeRTOS900/utility/croutine.h | 762 +++ .../utility/deprecated_definitions.h | 321 ++ .../FreeRTOS900/utility/event_groups.c | 752 +++ .../FreeRTOS900/utility/event_groups.h | 797 +++ .../libraries/FreeRTOS900/utility/heap_1.c | 174 + STM32F1/libraries/FreeRTOS900/utility/list.c | 240 + STM32F1/libraries/FreeRTOS900/utility/list.h | 453 ++ .../FreeRTOS900/utility/mpu_prototypes.h | 177 + .../FreeRTOS900/utility/mpu_wrappers.h | 201 + STM32F1/libraries/FreeRTOS900/utility/port.c | 717 +++ .../libraries/FreeRTOS900/utility/portable.h | 207 + .../libraries/FreeRTOS900/utility/portmacro.h | 284 + .../libraries/FreeRTOS900/utility/projdefs.h | 161 + STM32F1/libraries/FreeRTOS900/utility/queue.c | 2566 +++++++++ STM32F1/libraries/FreeRTOS900/utility/queue.h | 1798 ++++++ .../libraries/FreeRTOS900/utility/readme.txt | 17 + .../libraries/FreeRTOS900/utility/semphr.h | 1171 ++++ .../FreeRTOS900/utility/stdint.readme | 27 + STM32F1/libraries/FreeRTOS900/utility/task.h | 2267 ++++++++ STM32F1/libraries/FreeRTOS900/utility/tasks.c | 4807 +++++++++++++++++ .../libraries/FreeRTOS900/utility/timers.c | 1092 ++++ .../libraries/FreeRTOS900/utility/timers.h | 1314 +++++ 35 files changed, 24014 insertions(+) create mode 100644 STM32F1/libraries/FreeRTOS900/MapleFreeRTOS900.cpp create mode 100644 STM32F1/libraries/FreeRTOS900/MapleFreeRTOS900.h create mode 100644 STM32F1/libraries/FreeRTOS900/examples/rtos_blink/rtos_blink.ino create mode 100644 STM32F1/libraries/FreeRTOS900/examples/rtos_display_blink/rtos_display_blink.ino create mode 100644 STM32F1/libraries/FreeRTOS900/utility/FreeRTOS.h create mode 100644 STM32F1/libraries/FreeRTOS900/utility/FreeRTOSConfig.h create mode 100644 STM32F1/libraries/FreeRTOS900/utility/MemMang/heap_1.c create mode 100644 STM32F1/libraries/FreeRTOS900/utility/MemMang/heap_2.c create mode 100644 STM32F1/libraries/FreeRTOS900/utility/MemMang/heap_3.c create mode 100644 STM32F1/libraries/FreeRTOS900/utility/MemMang/heap_4.c create mode 100644 STM32F1/libraries/FreeRTOS900/utility/MemMang/heap_5.c create mode 100644 STM32F1/libraries/FreeRTOS900/utility/StackMacros.h create mode 100644 STM32F1/libraries/FreeRTOS900/utility/croutine.c create mode 100644 STM32F1/libraries/FreeRTOS900/utility/croutine.h create mode 100644 STM32F1/libraries/FreeRTOS900/utility/deprecated_definitions.h create mode 100644 STM32F1/libraries/FreeRTOS900/utility/event_groups.c create mode 100644 STM32F1/libraries/FreeRTOS900/utility/event_groups.h create mode 100644 STM32F1/libraries/FreeRTOS900/utility/heap_1.c create mode 100644 STM32F1/libraries/FreeRTOS900/utility/list.c create mode 100644 STM32F1/libraries/FreeRTOS900/utility/list.h create mode 100644 STM32F1/libraries/FreeRTOS900/utility/mpu_prototypes.h create mode 100644 STM32F1/libraries/FreeRTOS900/utility/mpu_wrappers.h create mode 100644 STM32F1/libraries/FreeRTOS900/utility/port.c create mode 100644 STM32F1/libraries/FreeRTOS900/utility/portable.h create mode 100644 STM32F1/libraries/FreeRTOS900/utility/portmacro.h create mode 100644 STM32F1/libraries/FreeRTOS900/utility/projdefs.h create mode 100644 STM32F1/libraries/FreeRTOS900/utility/queue.c create mode 100644 STM32F1/libraries/FreeRTOS900/utility/queue.h create mode 100644 STM32F1/libraries/FreeRTOS900/utility/readme.txt create mode 100644 STM32F1/libraries/FreeRTOS900/utility/semphr.h create mode 100644 STM32F1/libraries/FreeRTOS900/utility/stdint.readme create mode 100644 STM32F1/libraries/FreeRTOS900/utility/task.h create mode 100644 STM32F1/libraries/FreeRTOS900/utility/tasks.c create mode 100644 STM32F1/libraries/FreeRTOS900/utility/timers.c create mode 100644 STM32F1/libraries/FreeRTOS900/utility/timers.h diff --git a/STM32F1/libraries/FreeRTOS900/MapleFreeRTOS900.cpp b/STM32F1/libraries/FreeRTOS900/MapleFreeRTOS900.cpp new file mode 100644 index 0000000..43fc2f1 --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/MapleFreeRTOS900.cpp @@ -0,0 +1,44 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +#include "MapleFreeRTOS900.h" + +extern "C" { + +void vApplicationStackOverflowHook(xTaskHandle *pxTask, + signed char *pcTaskName) { + /* This function will get called if a task overflows its stack. + * If the parameters are corrupt then inspect pxCurrentTCB to find + * which was the offending task. */ + + (void) pxTask; + (void) pcTaskName; + + while (1) + ; +} + +} diff --git a/STM32F1/libraries/FreeRTOS900/MapleFreeRTOS900.h b/STM32F1/libraries/FreeRTOS900/MapleFreeRTOS900.h new file mode 100644 index 0000000..4cbbb96 --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/MapleFreeRTOS900.h @@ -0,0 +1,40 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +#ifndef __MAPLE_FREERTOS_H__ +#define __MAPLE_FREERTOS_H__ + +#include + +extern "C" { +#define GCC_ARMCM3 +#include "utility/FreeRTOS.h" +#include "utility/task.h" +#include "utility/queue.h" +#include "utility/semphr.h" +} + +#endif diff --git a/STM32F1/libraries/FreeRTOS900/examples/rtos_blink/rtos_blink.ino b/STM32F1/libraries/FreeRTOS900/examples/rtos_blink/rtos_blink.ino new file mode 100644 index 0000000..a972b6c --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/examples/rtos_blink/rtos_blink.ino @@ -0,0 +1,31 @@ +//#include +//#include "libraries/FreeRTOS/MapleFreeRTOS.h" +#include + +static void vLEDFlashTask(void *pvParameters) { + for (;;) { + vTaskDelay(1000); + digitalWrite(BOARD_LED_PIN, HIGH); + vTaskDelay(50); + digitalWrite(BOARD_LED_PIN, LOW); + } +} + +void setup() { + // initialize the digital pin as an output: + pinMode(BOARD_LED_PIN, OUTPUT); + + xTaskCreate(vLEDFlashTask, + "Task1", + configMINIMAL_STACK_SIZE, + NULL, + tskIDLE_PRIORITY + 2, + NULL); + vTaskStartScheduler(); +} + +void loop() { + // Insert background code here +} + + diff --git a/STM32F1/libraries/FreeRTOS900/examples/rtos_display_blink/rtos_display_blink.ino b/STM32F1/libraries/FreeRTOS900/examples/rtos_display_blink/rtos_display_blink.ino new file mode 100644 index 0000000..bd6c3e4 --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/examples/rtos_display_blink/rtos_display_blink.ino @@ -0,0 +1,212 @@ +#define USE_SEMAPHORE_DMA1 +#include +#include +#include +#include + +#define __CS 8 +#define __RST 9 +#define __DC 10 + +TFT_ILI9163C tft = TFT_ILI9163C(__CS, __DC, __RST); + +xSemaphoreHandle xDisplayFree; + + +const float sin_d[] = { + 0, 0.17, 0.34, 0.5, 0.64, 0.77, 0.87, 0.94, 0.98, 1, 0.98, 0.94, + 0.87, 0.77, 0.64, 0.5, 0.34, 0.17, 0, -0.17, -0.34, -0.5, -0.64, + -0.77, -0.87, -0.94, -0.98, -1, -0.98, -0.94, -0.87, -0.77, + -0.64, -0.5, -0.34, -0.17 +}; +const float cos_d[] = { + 1, 0.98, 0.94, 0.87, 0.77, 0.64, 0.5, 0.34, 0.17, 0, -0.17, -0.34, + -0.5, -0.64, -0.77, -0.87, -0.94, -0.98, -1, -0.98, -0.94, -0.87, + -0.77, -0.64, -0.5, -0.34, -0.17, 0, 0.17, 0.34, 0.5, 0.64, 0.77, + 0.87, 0.94, 0.98 +}; +const float d = 5; +float cube1_px[] = { + -d, d, d, -d, -d, d, d, -d +}; +float cube1_py[] = { + -d, -d, d, d, -d, -d, d, d +}; +float cube1_pz[] = { + -d, -d, -d, -d, d, d, d, d +}; + +float cube1_p2x[] = { + 0, 0, 0, 0, 0, 0, 0, 0 +}; +float cube1_p2y[] = { + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +int cube1_r[] = { + 0, 0, 0 +}; +const float d2 = 10; +float cube2_px[] = { + -d2, d2, d2, -d2, -d2, d2, d2, -d2 +}; +float cube2_py[] = { + -d2, -d2, d2, d2, -d2, -d2, d2, d2 +}; +float cube2_pz[] = { + -d2, -d2, -d2, -d2, d2, d2, d2, d2 +}; + +float cube2_p2x[] = { + 0, 0, 0, 0, 0, 0, 0, 0 +}; +float cube2_p2y[] = { + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +int cube2_r[] = { + 0, 0, 0 +}; + +uint16 cube1_x, cube1_y, cube2_x, cube2_y, cube1_color, cube2_color; + +static void vLEDFlashTask(void *pvParameters) { + for (;;) { + vTaskDelay(1000); + digitalWrite(BOARD_LED_PIN, HIGH); + vTaskDelay(50); + digitalWrite(BOARD_LED_PIN, LOW); + } +} + +static void vCube1LoopTask(void *pvParameters) { + while (1) { + if ( xSemaphoreTake( xDisplayFree, ( portTickType ) 10 ) == pdTRUE ) + { + cube(cube1_px, cube1_py, cube1_pz, cube1_p2x, cube1_p2y, cube1_r, &cube1_x, &cube1_y, &cube1_color); + xSemaphoreGive( xDisplayFree ); + vTaskDelay(15); + } + } +} + +static void vCube2LoopTask(void *pvParameters) { + while (1) { + if ( xSemaphoreTake( xDisplayFree, ( portTickType ) 10 ) == pdTRUE ) + { + cube(cube2_px, cube2_py, cube2_pz, cube2_p2x, cube2_p2y, cube2_r, &cube2_x, &cube2_y, &cube2_color); + xSemaphoreGive( xDisplayFree ); + vTaskDelay(40); + } + } +} + + +void cube(float *px, float *py, float *pz, float *p2x, float *p2y, int *r, uint16 *x, uint16 *y, uint16 *color) { + + for (int i = 0; i < 3; i++) { + tft.drawLine(p2x[i], p2y[i], p2x[i + 1], p2y[i + 1], WHITE); + tft.drawLine(p2x[i + 4], p2y[i + 4], p2x[i + 5], p2y[i + 5], WHITE); + tft.drawLine(p2x[i], p2y[i], p2x[i + 4], p2y[i + 4], WHITE); + } + tft.drawLine(p2x[3], p2y[3], p2x[0], p2y[0], WHITE); + tft.drawLine(p2x[7], p2y[7], p2x[4], p2y[4], WHITE); + tft.drawLine(p2x[3], p2y[3], p2x[7], p2y[7], WHITE); + + r[0] = r[0] + 1; + r[1] = r[1] + 1; + if (r[0] == 36) r[0] = 0; + if (r[1] == 36) r[1] = 0; + if (r[2] == 36) r[2] = 0; + for (int i = 0; i < 8; i++) + { + float px2 = px[i]; + float py2 = cos_d[r[0]] * py[i] - sin_d[r[0]] * pz[i]; + float pz2 = sin_d[r[0]] * py[i] + cos_d[r[0]] * pz[i]; + + float px3 = cos_d[r[1]] * px2 + sin_d[r[1]] * pz2; + float py3 = py2; + float pz3 = -sin_d[r[1]] * px2 + cos_d[r[1]] * pz2; + + float ax = cos_d[r[2]] * px3 - sin_d[r[2]] * py3; + float ay = sin_d[r[2]] * px3 + cos_d[r[2]] * py3; + float az = pz3 - 190; + + p2x[i] = *x + ax * 500 / az; + p2y[i] = *y + ay * 500 / az; + } + + for (int i = 0; i < 3; i++) { + tft.drawLine(p2x[i], p2y[i], p2x[i + 1], p2y[i + 1], *color); + tft.drawLine(p2x[i + 4], p2y[i + 4], p2x[i + 5], p2y[i + 5], *color); + tft.drawLine(p2x[i], p2y[i], p2x[i + 4], p2y[i + 4], *color); + } + tft.drawLine(p2x[3], p2y[3], p2x[0], p2y[0], *color); + tft.drawLine(p2x[7], p2y[7], p2x[4], p2y[4], *color); + tft.drawLine(p2x[3], p2y[3], p2x[7], p2y[7], *color); +} + +static void vSqrtTask(void *pvParameters) { + while (1){ + Serial.println ("Starting Sqrt calculations..."); + uint16 x = 0; + uint16 ixx[1001]; + // Library Sqrt + uint32_t t0 = millis(); + for (uint32_t n = 247583650 ; n > 247400000 ; n--) { + x = sqrt (n); + } + uint32_t t1 = millis() - t0; + Serial.print ("Sqrt calculations took (ms): "); + Serial.println (t1); + delay (5000); + } +} + +void setup() { + // initialize the digital pin as an output: + Serial.begin(9600); + delay (5000); + Serial.println ("Running..."); + pinMode(BOARD_LED_PIN, OUTPUT); + tft.begin(); + tft.fillScreen(WHITE); + cube1_x = ((tft.width()) / 4); + cube1_y = ((tft.height()) / 4); + cube2_x = ((tft.width()) / 2); + cube2_y = ((tft.height()) / 2); + cube1_color = BLACK; + cube2_color = RED; + vSemaphoreCreateBinary(xDisplayFree); + xTaskCreate(vLEDFlashTask, + "Task1", + configMINIMAL_STACK_SIZE, + NULL, + tskIDLE_PRIORITY + 2, + NULL); + xTaskCreate(vCube1LoopTask, + "Cube1", + configMINIMAL_STACK_SIZE, + NULL, + tskIDLE_PRIORITY + 2, + NULL); + xTaskCreate(vCube2LoopTask, + "Cube2", + configMINIMAL_STACK_SIZE, + NULL, + tskIDLE_PRIORITY+1, + NULL); + xTaskCreate(vSqrtTask, + "Sqrt", + configMINIMAL_STACK_SIZE, + NULL, + tskIDLE_PRIORITY, + NULL); + vTaskStartScheduler(); +} + +void loop() { + // Do not write any code here, it would not execute. +} + + diff --git a/STM32F1/libraries/FreeRTOS900/utility/FreeRTOS.h b/STM32F1/libraries/FreeRTOS900/utility/FreeRTOS.h new file mode 100644 index 0000000..f81172d --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/utility/FreeRTOS.h @@ -0,0 +1,1063 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef INC_FREERTOS_H +#define INC_FREERTOS_H + +/* + * Include the generic headers required for the FreeRTOS port being used. + */ +#include + +/* + * If stdint.h cannot be located then: + * + If using GCC ensure the -nostdint options is *not* being used. + * + Ensure the project's include path includes the directory in which your + * compiler stores stdint.h. + * + Set any compiler options necessary for it to support C99, as technically + * stdint.h is only mandatory with C99 (FreeRTOS does not require C99 in any + * other way). + * + The FreeRTOS download includes a simple stdint.h definition that can be + * used in cases where none is provided by the compiler. The files only + * contains the typedefs required to build FreeRTOS. Read the instructions + * in FreeRTOS/source/stdint.readme for more information. + */ +#include /* READ COMMENT ABOVE. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Application specific configuration options. */ +#include "FreeRTOSConfig.h" + +/* Basic FreeRTOS definitions. */ +#include "projdefs.h" + +/* Definitions specific to the port being used. */ +#include "portable.h" + +/* Must be defaulted before configUSE_NEWLIB_REENTRANT is used below. */ +#ifndef configUSE_NEWLIB_REENTRANT + #define configUSE_NEWLIB_REENTRANT 0 +#endif + +/* Required if struct _reent is used. */ +#if ( configUSE_NEWLIB_REENTRANT == 1 ) + #include +#endif +/* + * Check all the required application specific macros have been defined. + * These macros are application specific and (as downloaded) are defined + * within FreeRTOSConfig.h. + */ + +#ifndef configMINIMAL_STACK_SIZE + #error Missing definition: configMINIMAL_STACK_SIZE must be defined in FreeRTOSConfig.h. configMINIMAL_STACK_SIZE defines the size (in words) of the stack allocated to the idle task. Refer to the demo project provided for your port for a suitable value. +#endif + +#ifndef configMAX_PRIORITIES + #error Missing definition: configMAX_PRIORITIES must be defined in FreeRTOSConfig.h. See the Configuration section of the FreeRTOS API documentation for details. +#endif + +#ifndef configUSE_PREEMPTION + #error Missing definition: configUSE_PREEMPTION must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. +#endif + +#ifndef configUSE_IDLE_HOOK + #error Missing definition: configUSE_IDLE_HOOK must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. +#endif + +#ifndef configUSE_TICK_HOOK + #error Missing definition: configUSE_TICK_HOOK must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. +#endif + +#ifndef configUSE_16_BIT_TICKS + #error Missing definition: configUSE_16_BIT_TICKS must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. +#endif + +#ifndef configMAX_PRIORITIES + #error configMAX_PRIORITIES must be defined to be greater than or equal to 1. +#endif + +#ifndef configUSE_CO_ROUTINES + #define configUSE_CO_ROUTINES 0 +#endif + +#ifndef INCLUDE_vTaskPrioritySet + #define INCLUDE_vTaskPrioritySet 0 +#endif + +#ifndef INCLUDE_uxTaskPriorityGet + #define INCLUDE_uxTaskPriorityGet 0 +#endif + +#ifndef INCLUDE_vTaskDelete + #define INCLUDE_vTaskDelete 0 +#endif + +#ifndef INCLUDE_vTaskSuspend + #define INCLUDE_vTaskSuspend 0 +#endif + +#ifndef INCLUDE_vTaskDelayUntil + #define INCLUDE_vTaskDelayUntil 0 +#endif + +#ifndef INCLUDE_vTaskDelay + #define INCLUDE_vTaskDelay 0 +#endif + +#ifndef INCLUDE_xTaskGetIdleTaskHandle + #define INCLUDE_xTaskGetIdleTaskHandle 0 +#endif + +#ifndef INCLUDE_xTaskAbortDelay + #define INCLUDE_xTaskAbortDelay 0 +#endif + +#ifndef INCLUDE_xQueueGetMutexHolder + #define INCLUDE_xQueueGetMutexHolder 0 +#endif + +#ifndef INCLUDE_xSemaphoreGetMutexHolder + #define INCLUDE_xSemaphoreGetMutexHolder INCLUDE_xQueueGetMutexHolder +#endif + +#ifndef INCLUDE_xTaskGetHandle + #define INCLUDE_xTaskGetHandle 0 +#endif + +#ifndef INCLUDE_uxTaskGetStackHighWaterMark + #define INCLUDE_uxTaskGetStackHighWaterMark 0 +#endif + +#ifndef INCLUDE_eTaskGetState + #define INCLUDE_eTaskGetState 0 +#endif + +#ifndef INCLUDE_xTaskResumeFromISR + #define INCLUDE_xTaskResumeFromISR 1 +#endif + +#ifndef INCLUDE_xTimerPendFunctionCall + #define INCLUDE_xTimerPendFunctionCall 0 +#endif + +#ifndef INCLUDE_xTaskGetSchedulerState + #define INCLUDE_xTaskGetSchedulerState 0 +#endif + +#ifndef INCLUDE_xTaskGetCurrentTaskHandle + #define INCLUDE_xTaskGetCurrentTaskHandle 0 +#endif + +#if configUSE_CO_ROUTINES != 0 + #ifndef configMAX_CO_ROUTINE_PRIORITIES + #error configMAX_CO_ROUTINE_PRIORITIES must be greater than or equal to 1. + #endif +#endif + +#ifndef configUSE_DAEMON_TASK_STARTUP_HOOK + #define configUSE_DAEMON_TASK_STARTUP_HOOK 0 +#endif + +#ifndef configUSE_APPLICATION_TASK_TAG + #define configUSE_APPLICATION_TASK_TAG 0 +#endif + +#ifndef configNUM_THREAD_LOCAL_STORAGE_POINTERS + #define configNUM_THREAD_LOCAL_STORAGE_POINTERS 0 +#endif + +#ifndef configUSE_RECURSIVE_MUTEXES + #define configUSE_RECURSIVE_MUTEXES 0 +#endif + +#ifndef configUSE_MUTEXES + #define configUSE_MUTEXES 0 +#endif + +#ifndef configUSE_TIMERS + #define configUSE_TIMERS 0 +#endif + +#ifndef configUSE_COUNTING_SEMAPHORES + #define configUSE_COUNTING_SEMAPHORES 0 +#endif + +#ifndef configUSE_ALTERNATIVE_API + #define configUSE_ALTERNATIVE_API 0 +#endif + +#ifndef portCRITICAL_NESTING_IN_TCB + #define portCRITICAL_NESTING_IN_TCB 0 +#endif + +#ifndef configMAX_TASK_NAME_LEN + #define configMAX_TASK_NAME_LEN 16 +#endif + +#ifndef configIDLE_SHOULD_YIELD + #define configIDLE_SHOULD_YIELD 1 +#endif + +#if configMAX_TASK_NAME_LEN < 1 + #error configMAX_TASK_NAME_LEN must be set to a minimum of 1 in FreeRTOSConfig.h +#endif + +#ifndef configASSERT + #define configASSERT( x ) + #define configASSERT_DEFINED 0 +#else + #define configASSERT_DEFINED 1 +#endif + +/* The timers module relies on xTaskGetSchedulerState(). */ +#if configUSE_TIMERS == 1 + + #ifndef configTIMER_TASK_PRIORITY + #error If configUSE_TIMERS is set to 1 then configTIMER_TASK_PRIORITY must also be defined. + #endif /* configTIMER_TASK_PRIORITY */ + + #ifndef configTIMER_QUEUE_LENGTH + #error If configUSE_TIMERS is set to 1 then configTIMER_QUEUE_LENGTH must also be defined. + #endif /* configTIMER_QUEUE_LENGTH */ + + #ifndef configTIMER_TASK_STACK_DEPTH + #error If configUSE_TIMERS is set to 1 then configTIMER_TASK_STACK_DEPTH must also be defined. + #endif /* configTIMER_TASK_STACK_DEPTH */ + +#endif /* configUSE_TIMERS */ + +#ifndef portSET_INTERRUPT_MASK_FROM_ISR + #define portSET_INTERRUPT_MASK_FROM_ISR() 0 +#endif + +#ifndef portCLEAR_INTERRUPT_MASK_FROM_ISR + #define portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedStatusValue ) ( void ) uxSavedStatusValue +#endif + +#ifndef portCLEAN_UP_TCB + #define portCLEAN_UP_TCB( pxTCB ) ( void ) pxTCB +#endif + +#ifndef portPRE_TASK_DELETE_HOOK + #define portPRE_TASK_DELETE_HOOK( pvTaskToDelete, pxYieldPending ) +#endif + +#ifndef portSETUP_TCB + #define portSETUP_TCB( pxTCB ) ( void ) pxTCB +#endif + +#ifndef configQUEUE_REGISTRY_SIZE + #define configQUEUE_REGISTRY_SIZE 0U +#endif + +#if ( configQUEUE_REGISTRY_SIZE < 1 ) + #define vQueueAddToRegistry( xQueue, pcName ) + #define vQueueUnregisterQueue( xQueue ) + #define pcQueueGetName( xQueue ) +#endif + +#ifndef portPOINTER_SIZE_TYPE + #define portPOINTER_SIZE_TYPE uint32_t +#endif + +/* Remove any unused trace macros. */ +#ifndef traceSTART + /* Used to perform any necessary initialisation - for example, open a file + into which trace is to be written. */ + #define traceSTART() +#endif + +#ifndef traceEND + /* Use to close a trace, for example close a file into which trace has been + written. */ + #define traceEND() +#endif + +#ifndef traceTASK_SWITCHED_IN + /* Called after a task has been selected to run. pxCurrentTCB holds a pointer + to the task control block of the selected task. */ + #define traceTASK_SWITCHED_IN() +#endif + +#ifndef traceINCREASE_TICK_COUNT + /* Called before stepping the tick count after waking from tickless idle + sleep. */ + #define traceINCREASE_TICK_COUNT( x ) +#endif + +#ifndef traceLOW_POWER_IDLE_BEGIN + /* Called immediately before entering tickless idle. */ + #define traceLOW_POWER_IDLE_BEGIN() +#endif + +#ifndef traceLOW_POWER_IDLE_END + /* Called when returning to the Idle task after a tickless idle. */ + #define traceLOW_POWER_IDLE_END() +#endif + +#ifndef traceTASK_SWITCHED_OUT + /* Called before a task has been selected to run. pxCurrentTCB holds a pointer + to the task control block of the task being switched out. */ + #define traceTASK_SWITCHED_OUT() +#endif + +#ifndef traceTASK_PRIORITY_INHERIT + /* Called when a task attempts to take a mutex that is already held by a + lower priority task. pxTCBOfMutexHolder is a pointer to the TCB of the task + that holds the mutex. uxInheritedPriority is the priority the mutex holder + will inherit (the priority of the task that is attempting to obtain the + muted. */ + #define traceTASK_PRIORITY_INHERIT( pxTCBOfMutexHolder, uxInheritedPriority ) +#endif + +#ifndef traceTASK_PRIORITY_DISINHERIT + /* Called when a task releases a mutex, the holding of which had resulted in + the task inheriting the priority of a higher priority task. + pxTCBOfMutexHolder is a pointer to the TCB of the task that is releasing the + mutex. uxOriginalPriority is the task's configured (base) priority. */ + #define traceTASK_PRIORITY_DISINHERIT( pxTCBOfMutexHolder, uxOriginalPriority ) +#endif + +#ifndef traceBLOCKING_ON_QUEUE_RECEIVE + /* Task is about to block because it cannot read from a + queue/mutex/semaphore. pxQueue is a pointer to the queue/mutex/semaphore + upon which the read was attempted. pxCurrentTCB points to the TCB of the + task that attempted the read. */ + #define traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ) +#endif + +#ifndef traceBLOCKING_ON_QUEUE_SEND + /* Task is about to block because it cannot write to a + queue/mutex/semaphore. pxQueue is a pointer to the queue/mutex/semaphore + upon which the write was attempted. pxCurrentTCB points to the TCB of the + task that attempted the write. */ + #define traceBLOCKING_ON_QUEUE_SEND( pxQueue ) +#endif + +#ifndef configCHECK_FOR_STACK_OVERFLOW + #define configCHECK_FOR_STACK_OVERFLOW 0 +#endif + +/* The following event macros are embedded in the kernel API calls. */ + +#ifndef traceMOVED_TASK_TO_READY_STATE + #define traceMOVED_TASK_TO_READY_STATE( pxTCB ) +#endif + +#ifndef tracePOST_MOVED_TASK_TO_READY_STATE + #define tracePOST_MOVED_TASK_TO_READY_STATE( pxTCB ) +#endif + +#ifndef traceQUEUE_CREATE + #define traceQUEUE_CREATE( pxNewQueue ) +#endif + +#ifndef traceQUEUE_CREATE_FAILED + #define traceQUEUE_CREATE_FAILED( ucQueueType ) +#endif + +#ifndef traceCREATE_MUTEX + #define traceCREATE_MUTEX( pxNewQueue ) +#endif + +#ifndef traceCREATE_MUTEX_FAILED + #define traceCREATE_MUTEX_FAILED() +#endif + +#ifndef traceGIVE_MUTEX_RECURSIVE + #define traceGIVE_MUTEX_RECURSIVE( pxMutex ) +#endif + +#ifndef traceGIVE_MUTEX_RECURSIVE_FAILED + #define traceGIVE_MUTEX_RECURSIVE_FAILED( pxMutex ) +#endif + +#ifndef traceTAKE_MUTEX_RECURSIVE + #define traceTAKE_MUTEX_RECURSIVE( pxMutex ) +#endif + +#ifndef traceTAKE_MUTEX_RECURSIVE_FAILED + #define traceTAKE_MUTEX_RECURSIVE_FAILED( pxMutex ) +#endif + +#ifndef traceCREATE_COUNTING_SEMAPHORE + #define traceCREATE_COUNTING_SEMAPHORE() +#endif + +#ifndef traceCREATE_COUNTING_SEMAPHORE_FAILED + #define traceCREATE_COUNTING_SEMAPHORE_FAILED() +#endif + +#ifndef traceQUEUE_SEND + #define traceQUEUE_SEND( pxQueue ) +#endif + +#ifndef traceQUEUE_SEND_FAILED + #define traceQUEUE_SEND_FAILED( pxQueue ) +#endif + +#ifndef traceQUEUE_RECEIVE + #define traceQUEUE_RECEIVE( pxQueue ) +#endif + +#ifndef traceQUEUE_PEEK + #define traceQUEUE_PEEK( pxQueue ) +#endif + +#ifndef traceQUEUE_PEEK_FROM_ISR + #define traceQUEUE_PEEK_FROM_ISR( pxQueue ) +#endif + +#ifndef traceQUEUE_RECEIVE_FAILED + #define traceQUEUE_RECEIVE_FAILED( pxQueue ) +#endif + +#ifndef traceQUEUE_SEND_FROM_ISR + #define traceQUEUE_SEND_FROM_ISR( pxQueue ) +#endif + +#ifndef traceQUEUE_SEND_FROM_ISR_FAILED + #define traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue ) +#endif + +#ifndef traceQUEUE_RECEIVE_FROM_ISR + #define traceQUEUE_RECEIVE_FROM_ISR( pxQueue ) +#endif + +#ifndef traceQUEUE_RECEIVE_FROM_ISR_FAILED + #define traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue ) +#endif + +#ifndef traceQUEUE_PEEK_FROM_ISR_FAILED + #define traceQUEUE_PEEK_FROM_ISR_FAILED( pxQueue ) +#endif + +#ifndef traceQUEUE_DELETE + #define traceQUEUE_DELETE( pxQueue ) +#endif + +#ifndef traceTASK_CREATE + #define traceTASK_CREATE( pxNewTCB ) +#endif + +#ifndef traceTASK_CREATE_FAILED + #define traceTASK_CREATE_FAILED() +#endif + +#ifndef traceTASK_DELETE + #define traceTASK_DELETE( pxTaskToDelete ) +#endif + +#ifndef traceTASK_DELAY_UNTIL + #define traceTASK_DELAY_UNTIL( x ) +#endif + +#ifndef traceTASK_DELAY + #define traceTASK_DELAY() +#endif + +#ifndef traceTASK_PRIORITY_SET + #define traceTASK_PRIORITY_SET( pxTask, uxNewPriority ) +#endif + +#ifndef traceTASK_SUSPEND + #define traceTASK_SUSPEND( pxTaskToSuspend ) +#endif + +#ifndef traceTASK_RESUME + #define traceTASK_RESUME( pxTaskToResume ) +#endif + +#ifndef traceTASK_RESUME_FROM_ISR + #define traceTASK_RESUME_FROM_ISR( pxTaskToResume ) +#endif + +#ifndef traceTASK_INCREMENT_TICK + #define traceTASK_INCREMENT_TICK( xTickCount ) +#endif + +#ifndef traceTIMER_CREATE + #define traceTIMER_CREATE( pxNewTimer ) +#endif + +#ifndef traceTIMER_CREATE_FAILED + #define traceTIMER_CREATE_FAILED() +#endif + +#ifndef traceTIMER_COMMAND_SEND + #define traceTIMER_COMMAND_SEND( xTimer, xMessageID, xMessageValueValue, xReturn ) +#endif + +#ifndef traceTIMER_EXPIRED + #define traceTIMER_EXPIRED( pxTimer ) +#endif + +#ifndef traceTIMER_COMMAND_RECEIVED + #define traceTIMER_COMMAND_RECEIVED( pxTimer, xMessageID, xMessageValue ) +#endif + +#ifndef traceMALLOC + #define traceMALLOC( pvAddress, uiSize ) +#endif + +#ifndef traceFREE + #define traceFREE( pvAddress, uiSize ) +#endif + +#ifndef traceEVENT_GROUP_CREATE + #define traceEVENT_GROUP_CREATE( xEventGroup ) +#endif + +#ifndef traceEVENT_GROUP_CREATE_FAILED + #define traceEVENT_GROUP_CREATE_FAILED() +#endif + +#ifndef traceEVENT_GROUP_SYNC_BLOCK + #define traceEVENT_GROUP_SYNC_BLOCK( xEventGroup, uxBitsToSet, uxBitsToWaitFor ) +#endif + +#ifndef traceEVENT_GROUP_SYNC_END + #define traceEVENT_GROUP_SYNC_END( xEventGroup, uxBitsToSet, uxBitsToWaitFor, xTimeoutOccurred ) ( void ) xTimeoutOccurred +#endif + +#ifndef traceEVENT_GROUP_WAIT_BITS_BLOCK + #define traceEVENT_GROUP_WAIT_BITS_BLOCK( xEventGroup, uxBitsToWaitFor ) +#endif + +#ifndef traceEVENT_GROUP_WAIT_BITS_END + #define traceEVENT_GROUP_WAIT_BITS_END( xEventGroup, uxBitsToWaitFor, xTimeoutOccurred ) ( void ) xTimeoutOccurred +#endif + +#ifndef traceEVENT_GROUP_CLEAR_BITS + #define traceEVENT_GROUP_CLEAR_BITS( xEventGroup, uxBitsToClear ) +#endif + +#ifndef traceEVENT_GROUP_CLEAR_BITS_FROM_ISR + #define traceEVENT_GROUP_CLEAR_BITS_FROM_ISR( xEventGroup, uxBitsToClear ) +#endif + +#ifndef traceEVENT_GROUP_SET_BITS + #define traceEVENT_GROUP_SET_BITS( xEventGroup, uxBitsToSet ) +#endif + +#ifndef traceEVENT_GROUP_SET_BITS_FROM_ISR + #define traceEVENT_GROUP_SET_BITS_FROM_ISR( xEventGroup, uxBitsToSet ) +#endif + +#ifndef traceEVENT_GROUP_DELETE + #define traceEVENT_GROUP_DELETE( xEventGroup ) +#endif + +#ifndef tracePEND_FUNC_CALL + #define tracePEND_FUNC_CALL(xFunctionToPend, pvParameter1, ulParameter2, ret) +#endif + +#ifndef tracePEND_FUNC_CALL_FROM_ISR + #define tracePEND_FUNC_CALL_FROM_ISR(xFunctionToPend, pvParameter1, ulParameter2, ret) +#endif + +#ifndef traceQUEUE_REGISTRY_ADD + #define traceQUEUE_REGISTRY_ADD(xQueue, pcQueueName) +#endif + +#ifndef traceTASK_NOTIFY_TAKE_BLOCK + #define traceTASK_NOTIFY_TAKE_BLOCK() +#endif + +#ifndef traceTASK_NOTIFY_TAKE + #define traceTASK_NOTIFY_TAKE() +#endif + +#ifndef traceTASK_NOTIFY_WAIT_BLOCK + #define traceTASK_NOTIFY_WAIT_BLOCK() +#endif + +#ifndef traceTASK_NOTIFY_WAIT + #define traceTASK_NOTIFY_WAIT() +#endif + +#ifndef traceTASK_NOTIFY + #define traceTASK_NOTIFY() +#endif + +#ifndef traceTASK_NOTIFY_FROM_ISR + #define traceTASK_NOTIFY_FROM_ISR() +#endif + +#ifndef traceTASK_NOTIFY_GIVE_FROM_ISR + #define traceTASK_NOTIFY_GIVE_FROM_ISR() +#endif + +#ifndef configGENERATE_RUN_TIME_STATS + #define configGENERATE_RUN_TIME_STATS 0 +#endif + +#if ( configGENERATE_RUN_TIME_STATS == 1 ) + + #ifndef portCONFIGURE_TIMER_FOR_RUN_TIME_STATS + #error If configGENERATE_RUN_TIME_STATS is defined then portCONFIGURE_TIMER_FOR_RUN_TIME_STATS must also be defined. portCONFIGURE_TIMER_FOR_RUN_TIME_STATS should call a port layer function to setup a peripheral timer/counter that can then be used as the run time counter time base. + #endif /* portCONFIGURE_TIMER_FOR_RUN_TIME_STATS */ + + #ifndef portGET_RUN_TIME_COUNTER_VALUE + #ifndef portALT_GET_RUN_TIME_COUNTER_VALUE + #error If configGENERATE_RUN_TIME_STATS is defined then either portGET_RUN_TIME_COUNTER_VALUE or portALT_GET_RUN_TIME_COUNTER_VALUE must also be defined. See the examples provided and the FreeRTOS web site for more information. + #endif /* portALT_GET_RUN_TIME_COUNTER_VALUE */ + #endif /* portGET_RUN_TIME_COUNTER_VALUE */ + +#endif /* configGENERATE_RUN_TIME_STATS */ + +#ifndef portCONFIGURE_TIMER_FOR_RUN_TIME_STATS + #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() +#endif + +#ifndef configUSE_MALLOC_FAILED_HOOK + #define configUSE_MALLOC_FAILED_HOOK 0 +#endif + +#ifndef portPRIVILEGE_BIT + #define portPRIVILEGE_BIT ( ( UBaseType_t ) 0x00 ) +#endif + +#ifndef portYIELD_WITHIN_API + #define portYIELD_WITHIN_API portYIELD +#endif + +#ifndef portSUPPRESS_TICKS_AND_SLEEP + #define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) +#endif + +#ifndef configEXPECTED_IDLE_TIME_BEFORE_SLEEP + #define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 2 +#endif + +#if configEXPECTED_IDLE_TIME_BEFORE_SLEEP < 2 + #error configEXPECTED_IDLE_TIME_BEFORE_SLEEP must not be less than 2 +#endif + +#ifndef configUSE_TICKLESS_IDLE + #define configUSE_TICKLESS_IDLE 0 +#endif + +#ifndef configPRE_SLEEP_PROCESSING + #define configPRE_SLEEP_PROCESSING( x ) +#endif + +#ifndef configPOST_SLEEP_PROCESSING + #define configPOST_SLEEP_PROCESSING( x ) +#endif + +#ifndef configUSE_QUEUE_SETS + #define configUSE_QUEUE_SETS 0 +#endif + +#ifndef portTASK_USES_FLOATING_POINT + #define portTASK_USES_FLOATING_POINT() +#endif + +#ifndef configUSE_TIME_SLICING + #define configUSE_TIME_SLICING 1 +#endif + +#ifndef configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS + #define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 0 +#endif + +#ifndef configUSE_STATS_FORMATTING_FUNCTIONS + #define configUSE_STATS_FORMATTING_FUNCTIONS 0 +#endif + +#ifndef portASSERT_IF_INTERRUPT_PRIORITY_INVALID + #define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() +#endif + +#ifndef configUSE_TRACE_FACILITY + #define configUSE_TRACE_FACILITY 0 +#endif + +#ifndef mtCOVERAGE_TEST_MARKER + #define mtCOVERAGE_TEST_MARKER() +#endif + +#ifndef mtCOVERAGE_TEST_DELAY + #define mtCOVERAGE_TEST_DELAY() +#endif + +#ifndef portASSERT_IF_IN_ISR + #define portASSERT_IF_IN_ISR() +#endif + +#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION + #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#endif + +#ifndef configAPPLICATION_ALLOCATED_HEAP + #define configAPPLICATION_ALLOCATED_HEAP 0 +#endif + +#ifndef configUSE_TASK_NOTIFICATIONS + #define configUSE_TASK_NOTIFICATIONS 1 +#endif + +#ifndef portTICK_TYPE_IS_ATOMIC + #define portTICK_TYPE_IS_ATOMIC 0 +#endif + +#ifndef configSUPPORT_STATIC_ALLOCATION + /* Defaults to 0 for backward compatibility. */ + #define configSUPPORT_STATIC_ALLOCATION 0 +#endif + +#ifndef configSUPPORT_DYNAMIC_ALLOCATION + /* Defaults to 1 for backward compatibility. */ + #define configSUPPORT_DYNAMIC_ALLOCATION 1 +#endif + +/* Sanity check the configuration. */ +#if( configUSE_TICKLESS_IDLE != 0 ) + #if( INCLUDE_vTaskSuspend != 1 ) + #error INCLUDE_vTaskSuspend must be set to 1 if configUSE_TICKLESS_IDLE is not set to 0 + #endif /* INCLUDE_vTaskSuspend */ +#endif /* configUSE_TICKLESS_IDLE */ + +#if( ( configSUPPORT_STATIC_ALLOCATION == 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 0 ) ) + #error configSUPPORT_STATIC_ALLOCATION and configSUPPORT_DYNAMIC_ALLOCATION cannot both be 0, but can both be 1. +#endif + +#if( ( configUSE_RECURSIVE_MUTEXES == 1 ) && ( configUSE_MUTEXES != 1 ) ) + #error configUSE_MUTEXES must be set to 1 to use recursive mutexes +#endif + +#if( portTICK_TYPE_IS_ATOMIC == 0 ) + /* Either variables of tick type cannot be read atomically, or + portTICK_TYPE_IS_ATOMIC was not set - map the critical sections used when + the tick count is returned to the standard critical section macros. */ + #define portTICK_TYPE_ENTER_CRITICAL() portENTER_CRITICAL() + #define portTICK_TYPE_EXIT_CRITICAL() portEXIT_CRITICAL() + #define portTICK_TYPE_SET_INTERRUPT_MASK_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR() + #define portTICK_TYPE_CLEAR_INTERRUPT_MASK_FROM_ISR( x ) portCLEAR_INTERRUPT_MASK_FROM_ISR( ( x ) ) +#else + /* The tick type can be read atomically, so critical sections used when the + tick count is returned can be defined away. */ + #define portTICK_TYPE_ENTER_CRITICAL() + #define portTICK_TYPE_EXIT_CRITICAL() + #define portTICK_TYPE_SET_INTERRUPT_MASK_FROM_ISR() 0 + #define portTICK_TYPE_CLEAR_INTERRUPT_MASK_FROM_ISR( x ) ( void ) x +#endif + +/* Definitions to allow backward compatibility with FreeRTOS versions prior to +V8 if desired. */ +#ifndef configENABLE_BACKWARD_COMPATIBILITY + #define configENABLE_BACKWARD_COMPATIBILITY 1 +#endif + +#if configENABLE_BACKWARD_COMPATIBILITY == 1 + #define eTaskStateGet eTaskGetState + #define portTickType TickType_t + #define xTaskHandle TaskHandle_t + #define xQueueHandle QueueHandle_t + #define xSemaphoreHandle SemaphoreHandle_t + #define xQueueSetHandle QueueSetHandle_t + #define xQueueSetMemberHandle QueueSetMemberHandle_t + #define xTimeOutType TimeOut_t + #define xMemoryRegion MemoryRegion_t + #define xTaskParameters TaskParameters_t + #define xTaskStatusType TaskStatus_t + #define xTimerHandle TimerHandle_t + #define xCoRoutineHandle CoRoutineHandle_t + #define pdTASK_HOOK_CODE TaskHookFunction_t + #define portTICK_RATE_MS portTICK_PERIOD_MS + #define pcTaskGetTaskName pcTaskGetName + #define pcTimerGetTimerName pcTimerGetName + #define pcQueueGetQueueName pcQueueGetName + #define vTaskGetTaskInfo vTaskGetInfo + + /* Backward compatibility within the scheduler code only - these definitions + are not really required but are included for completeness. */ + #define tmrTIMER_CALLBACK TimerCallbackFunction_t + #define pdTASK_CODE TaskFunction_t + #define xListItem ListItem_t + #define xList List_t +#endif /* configENABLE_BACKWARD_COMPATIBILITY */ + +#if( configUSE_ALTERNATIVE_API != 0 ) + #error The alternative API was deprecated some time ago, and was removed in FreeRTOS V9.0 0 +#endif + +/* Set configUSE_TASK_FPU_SUPPORT to 0 to omit floating point support even +if floating point hardware is otherwise supported by the FreeRTOS port in use. +This constant is not supported by all FreeRTOS ports that include floating +point support. */ +#ifndef configUSE_TASK_FPU_SUPPORT + #define configUSE_TASK_FPU_SUPPORT 1 +#endif + +/* + * In line with software engineering best practice, FreeRTOS implements a strict + * data hiding policy, so the real structures used by FreeRTOS to maintain the + * state of tasks, queues, semaphores, etc. are not accessible to the application + * code. However, if the application writer wants to statically allocate such + * an object then the size of the object needs to be know. Dummy structures + * that are guaranteed to have the same size and alignment requirements of the + * real objects are used for this purpose. The dummy list and list item + * structures below are used for inclusion in such a dummy structure. + */ +struct xSTATIC_LIST_ITEM +{ + TickType_t xDummy1; + void *pvDummy2[ 4 ]; +}; +typedef struct xSTATIC_LIST_ITEM StaticListItem_t; + +/* See the comments above the struct xSTATIC_LIST_ITEM definition. */ +struct xSTATIC_MINI_LIST_ITEM +{ + TickType_t xDummy1; + void *pvDummy2[ 2 ]; +}; +typedef struct xSTATIC_MINI_LIST_ITEM StaticMiniListItem_t; + +/* See the comments above the struct xSTATIC_LIST_ITEM definition. */ +typedef struct xSTATIC_LIST +{ + UBaseType_t uxDummy1; + void *pvDummy2; + StaticMiniListItem_t xDummy3; +} StaticList_t; + +/* + * In line with software engineering best practice, especially when supplying a + * library that is likely to change in future versions, FreeRTOS implements a + * strict data hiding policy. This means the Task structure used internally by + * FreeRTOS is not accessible to application code. However, if the application + * writer wants to statically allocate the memory required to create a task then + * the size of the task object needs to be know. The StaticTask_t structure + * below is provided for this purpose. Its sizes and alignment requirements are + * guaranteed to match those of the genuine structure, no matter which + * architecture is being used, and no matter how the values in FreeRTOSConfig.h + * are set. Its contents are somewhat obfuscated in the hope users will + * recognise that it would be unwise to make direct use of the structure members. + */ +typedef struct xSTATIC_TCB +{ + void *pxDummy1; + #if ( portUSING_MPU_WRAPPERS == 1 ) + xMPU_SETTINGS xDummy2; + #endif + StaticListItem_t xDummy3[ 2 ]; + UBaseType_t uxDummy5; + void *pxDummy6; + uint8_t ucDummy7[ configMAX_TASK_NAME_LEN ]; + #if ( portSTACK_GROWTH > 0 ) + void *pxDummy8; + #endif + #if ( portCRITICAL_NESTING_IN_TCB == 1 ) + UBaseType_t uxDummy9; + #endif + #if ( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxDummy10[ 2 ]; + #endif + #if ( configUSE_MUTEXES == 1 ) + UBaseType_t uxDummy12[ 2 ]; + #endif + #if ( configUSE_APPLICATION_TASK_TAG == 1 ) + void *pxDummy14; + #endif + #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) + void *pvDummy15[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ]; + #endif + #if ( configGENERATE_RUN_TIME_STATS == 1 ) + uint32_t ulDummy16; + #endif + #if ( configUSE_NEWLIB_REENTRANT == 1 ) + struct _reent xDummy17; + #endif + #if ( configUSE_TASK_NOTIFICATIONS == 1 ) + uint32_t ulDummy18; + uint8_t ucDummy19; + #endif + #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + uint8_t uxDummy20; + #endif + +} StaticTask_t; + +/* + * In line with software engineering best practice, especially when supplying a + * library that is likely to change in future versions, FreeRTOS implements a + * strict data hiding policy. This means the Queue structure used internally by + * FreeRTOS is not accessible to application code. However, if the application + * writer wants to statically allocate the memory required to create a queue + * then the size of the queue object needs to be know. The StaticQueue_t + * structure below is provided for this purpose. Its sizes and alignment + * requirements are guaranteed to match those of the genuine structure, no + * matter which architecture is being used, and no matter how the values in + * FreeRTOSConfig.h are set. Its contents are somewhat obfuscated in the hope + * users will recognise that it would be unwise to make direct use of the + * structure members. + */ +typedef struct xSTATIC_QUEUE +{ + void *pvDummy1[ 3 ]; + + union + { + void *pvDummy2; + UBaseType_t uxDummy2; + } u; + + StaticList_t xDummy3[ 2 ]; + UBaseType_t uxDummy4[ 3 ]; + uint8_t ucDummy5[ 2 ]; + + #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + uint8_t ucDummy6; + #endif + + #if ( configUSE_QUEUE_SETS == 1 ) + void *pvDummy7; + #endif + + #if ( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxDummy8; + uint8_t ucDummy9; + #endif + +} StaticQueue_t; +typedef StaticQueue_t StaticSemaphore_t; + +/* + * In line with software engineering best practice, especially when supplying a + * library that is likely to change in future versions, FreeRTOS implements a + * strict data hiding policy. This means the event group structure used + * internally by FreeRTOS is not accessible to application code. However, if + * the application writer wants to statically allocate the memory required to + * create an event group then the size of the event group object needs to be + * know. The StaticEventGroup_t structure below is provided for this purpose. + * Its sizes and alignment requirements are guaranteed to match those of the + * genuine structure, no matter which architecture is being used, and no matter + * how the values in FreeRTOSConfig.h are set. Its contents are somewhat + * obfuscated in the hope users will recognise that it would be unwise to make + * direct use of the structure members. + */ +typedef struct xSTATIC_EVENT_GROUP +{ + TickType_t xDummy1; + StaticList_t xDummy2; + + #if( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxDummy3; + #endif + + #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + uint8_t ucDummy4; + #endif + +} StaticEventGroup_t; + +/* + * In line with software engineering best practice, especially when supplying a + * library that is likely to change in future versions, FreeRTOS implements a + * strict data hiding policy. This means the software timer structure used + * internally by FreeRTOS is not accessible to application code. However, if + * the application writer wants to statically allocate the memory required to + * create a software timer then the size of the queue object needs to be know. + * The StaticTimer_t structure below is provided for this purpose. Its sizes + * and alignment requirements are guaranteed to match those of the genuine + * structure, no matter which architecture is being used, and no matter how the + * values in FreeRTOSConfig.h are set. Its contents are somewhat obfuscated in + * the hope users will recognise that it would be unwise to make direct use of + * the structure members. + */ +typedef struct xSTATIC_TIMER +{ + void *pvDummy1; + StaticListItem_t xDummy2; + TickType_t xDummy3; + UBaseType_t uxDummy4; + void *pvDummy5[ 2 ]; + #if( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxDummy6; + #endif + + #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + uint8_t ucDummy7; + #endif + +} StaticTimer_t; + +#ifdef __cplusplus +} +#endif + +#endif /* INC_FREERTOS_H */ + diff --git a/STM32F1/libraries/FreeRTOS900/utility/FreeRTOSConfig.h b/STM32F1/libraries/FreeRTOS900/utility/FreeRTOSConfig.h new file mode 100644 index 0000000..87d6c5d --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/utility/FreeRTOSConfig.h @@ -0,0 +1,144 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * + * See http://www.freertos.org/a00110.html. + *----------------------------------------------------------*/ + +#define configUSE_PREEMPTION 1 +#define configUSE_IDLE_HOOK 0 +#define configUSE_TICK_HOOK 0 +#define configCPU_CLOCK_HZ ( ( unsigned long ) F_CPU ) +#define configTICK_RATE_HZ ( ( TickType_t ) 1000 ) +#define configMAX_PRIORITIES ( 5 ) +#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 120 ) +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 8 * 1024 ) ) +#define configMAX_TASK_NAME_LEN ( 16 ) +#define configUSE_TRACE_FACILITY 1 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) + +#define configUSE_MUTEXES 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_ALTERNATIVE_API 0 +#define configCHECK_FOR_STACK_OVERFLOW 2 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 0 +#define configGENERATE_RUN_TIME_STATS 0 + +/* Set the following definitions to 1 to include the API function, or zero +to exclude the API function. */ + +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 + +/* This is the raw value as per the Cortex-M3 NVIC. Values can be 255 +(lowest) to 0 (1?) (highest). */ +#define configKERNEL_INTERRUPT_PRIORITY 255 +/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!! +See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */ +#define configMAX_SYSCALL_INTERRUPT_PRIORITY 191 /* equivalent to 0xb0, or priority 11. */ + + +/* This is the value being used as per the ST library which permits 16 +priority values, 0 to 15. This must correspond to the +configKERNEL_INTERRUPT_PRIORITY setting. Here 15 corresponds to the lowest +NVIC value of 255. */ +#define configLIBRARY_KERNEL_INTERRUPT_PRIORITY 15 + +/*----------------------------------------------------------- + * UART configuration. + *-----------------------------------------------------------*/ +#define configCOM0_RX_BUFFER_LENGTH 128 +#define configCOM0_TX_BUFFER_LENGTH 128 +#define configCOM1_RX_BUFFER_LENGTH 128 +#define configCOM1_TX_BUFFER_LENGTH 128 + +#endif /* FREERTOS_CONFIG_H */ + diff --git a/STM32F1/libraries/FreeRTOS900/utility/MemMang/heap_1.c b/STM32F1/libraries/FreeRTOS900/utility/MemMang/heap_1.c new file mode 100644 index 0000000..178ff7c --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/utility/MemMang/heap_1.c @@ -0,0 +1,174 @@ +/* + FreeRTOS V8.2.1 - Copyright (C) 2015 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + + +/* + * The simplest possible implementation of pvPortMalloc(). Note that this + * implementation does NOT allow allocated memory to be freed again. + * + * See heap_2.c, heap_3.c and heap_4.c for alternative implementations, and the + * memory management pages of http://www.FreeRTOS.org for more information. + */ +#include + +/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining +all the API functions to use the MPU wrappers. That should only be done when +task.h is included from an application file. */ +#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +#include "FreeRTOS.h" +#include "task.h" + +#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +/* A few bytes might be lost to byte aligning the heap start address. */ +#define configADJUSTED_HEAP_SIZE ( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT ) + +/* Allocate the memory for the heap. */ +static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ]; +static size_t xNextFreeByte = ( size_t ) 0; + +/*-----------------------------------------------------------*/ + +void *pvPortMalloc( size_t xWantedSize ) +{ +void *pvReturn = NULL; +static uint8_t *pucAlignedHeap = NULL; + + /* Ensure that blocks are always aligned to the required number of bytes. */ + #if portBYTE_ALIGNMENT != 1 + if( xWantedSize & portBYTE_ALIGNMENT_MASK ) + { + /* Byte alignment required. */ + xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ); + } + #endif + + vTaskSuspendAll(); + { + if( pucAlignedHeap == NULL ) + { + /* Ensure the heap starts on a correctly aligned boundary. */ + pucAlignedHeap = ( uint8_t * ) ( ( ( portPOINTER_SIZE_TYPE ) &ucHeap[ portBYTE_ALIGNMENT ] ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) ); + } + + /* Check there is enough room left for the allocation. */ + if( ( ( xNextFreeByte + xWantedSize ) < configADJUSTED_HEAP_SIZE ) && + ( ( xNextFreeByte + xWantedSize ) > xNextFreeByte ) )/* Check for overflow. */ + { + /* Return the next free byte then increment the index past this + block. */ + pvReturn = pucAlignedHeap + xNextFreeByte; + xNextFreeByte += xWantedSize; + } + + traceMALLOC( pvReturn, xWantedSize ); + } + ( void ) xTaskResumeAll(); + + #if( configUSE_MALLOC_FAILED_HOOK == 1 ) + { + if( pvReturn == NULL ) + { + extern void vApplicationMallocFailedHook( void ); + vApplicationMallocFailedHook(); + } + } + #endif + + return pvReturn; +} +/*-----------------------------------------------------------*/ + +void vPortFree( void *pv ) +{ + /* Memory cannot be freed using this scheme. See heap_2.c, heap_3.c and + heap_4.c for alternative implementations, and the memory management pages of + http://www.FreeRTOS.org for more information. */ + ( void ) pv; + + /* Force an assert as it is invalid to call this function. */ + configASSERT( pv == NULL ); +} +/*-----------------------------------------------------------*/ + +void vPortInitialiseBlocks( void ) +{ + /* Only required when static memory is not cleared. */ + xNextFreeByte = ( size_t ) 0; +} +/*-----------------------------------------------------------*/ + +size_t xPortGetFreeHeapSize( void ) +{ + return ( configADJUSTED_HEAP_SIZE - xNextFreeByte ); +} + + + diff --git a/STM32F1/libraries/FreeRTOS900/utility/MemMang/heap_2.c b/STM32F1/libraries/FreeRTOS900/utility/MemMang/heap_2.c new file mode 100644 index 0000000..a1a7674 --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/utility/MemMang/heap_2.c @@ -0,0 +1,303 @@ +/* + FreeRTOS V8.2.1 - Copyright (C) 2015 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* + * A sample implementation of pvPortMalloc() and vPortFree() that permits + * allocated blocks to be freed, but does not combine adjacent free blocks + * into a single larger block (and so will fragment memory). See heap_4.c for + * an equivalent that does combine adjacent blocks into single larger blocks. + * + * See heap_1.c, heap_3.c and heap_4.c for alternative implementations, and the + * memory management pages of http://www.FreeRTOS.org for more information. + */ +#include + +/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining +all the API functions to use the MPU wrappers. That should only be done when +task.h is included from an application file. */ +#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +#include "FreeRTOS.h" +#include "task.h" + +#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +/* A few bytes might be lost to byte aligning the heap start address. */ +#define configADJUSTED_HEAP_SIZE ( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT ) + +/* + * Initialises the heap structures before their first use. + */ +static void prvHeapInit( void ); + +/* Allocate the memory for the heap. */ +static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ]; + +/* Define the linked list structure. This is used to link free blocks in order +of their size. */ +typedef struct A_BLOCK_LINK +{ + struct A_BLOCK_LINK *pxNextFreeBlock; /*<< The next free block in the list. */ + size_t xBlockSize; /*<< The size of the free block. */ +} BlockLink_t; + + +static const uint16_t heapSTRUCT_SIZE = ( ( sizeof ( BlockLink_t ) + ( portBYTE_ALIGNMENT - 1 ) ) & ~portBYTE_ALIGNMENT_MASK ); +#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( heapSTRUCT_SIZE * 2 ) ) + +/* Create a couple of list links to mark the start and end of the list. */ +static BlockLink_t xStart, xEnd; + +/* Keeps track of the number of free bytes remaining, but says nothing about +fragmentation. */ +static size_t xFreeBytesRemaining = configADJUSTED_HEAP_SIZE; + +/* STATIC FUNCTIONS ARE DEFINED AS MACROS TO MINIMIZE THE FUNCTION CALL DEPTH. */ + +/* + * Insert a block into the list of free blocks - which is ordered by size of + * the block. Small blocks at the start of the list and large blocks at the end + * of the list. + */ +#define prvInsertBlockIntoFreeList( pxBlockToInsert ) \ +{ \ +BlockLink_t *pxIterator; \ +size_t xBlockSize; \ + \ + xBlockSize = pxBlockToInsert->xBlockSize; \ + \ + /* Iterate through the list until a block is found that has a larger size */ \ + /* than the block we are inserting. */ \ + for( pxIterator = &xStart; pxIterator->pxNextFreeBlock->xBlockSize < xBlockSize; pxIterator = pxIterator->pxNextFreeBlock ) \ + { \ + /* There is nothing to do here - just iterate to the correct position. */ \ + } \ + \ + /* Update the list to include the block being inserted in the correct */ \ + /* position. */ \ + pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock; \ + pxIterator->pxNextFreeBlock = pxBlockToInsert; \ +} +/*-----------------------------------------------------------*/ + +void *pvPortMalloc( size_t xWantedSize ) +{ +BlockLink_t *pxBlock, *pxPreviousBlock, *pxNewBlockLink; +static BaseType_t xHeapHasBeenInitialised = pdFALSE; +void *pvReturn = NULL; + + vTaskSuspendAll(); + { + /* If this is the first call to malloc then the heap will require + initialisation to setup the list of free blocks. */ + if( xHeapHasBeenInitialised == pdFALSE ) + { + prvHeapInit(); + xHeapHasBeenInitialised = pdTRUE; + } + + /* The wanted size is increased so it can contain a BlockLink_t + structure in addition to the requested amount of bytes. */ + if( xWantedSize > 0 ) + { + xWantedSize += heapSTRUCT_SIZE; + + /* Ensure that blocks are always aligned to the required number of bytes. */ + if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0 ) + { + /* Byte alignment required. */ + xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ); + } + } + + if( ( xWantedSize > 0 ) && ( xWantedSize < configADJUSTED_HEAP_SIZE ) ) + { + /* Blocks are stored in byte order - traverse the list from the start + (smallest) block until one of adequate size is found. */ + pxPreviousBlock = &xStart; + pxBlock = xStart.pxNextFreeBlock; + while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) ) + { + pxPreviousBlock = pxBlock; + pxBlock = pxBlock->pxNextFreeBlock; + } + + /* If we found the end marker then a block of adequate size was not found. */ + if( pxBlock != &xEnd ) + { + /* Return the memory space - jumping over the BlockLink_t structure + at its start. */ + pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + heapSTRUCT_SIZE ); + + /* This block is being returned for use so must be taken out of the + list of free blocks. */ + pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock; + + /* If the block is larger than required it can be split into two. */ + if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE ) + { + /* This block is to be split into two. Create a new block + following the number of bytes requested. The void cast is + used to prevent byte alignment warnings from the compiler. */ + pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize ); + + /* Calculate the sizes of two blocks split from the single + block. */ + pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize; + pxBlock->xBlockSize = xWantedSize; + + /* Insert the new block into the list of free blocks. */ + prvInsertBlockIntoFreeList( ( pxNewBlockLink ) ); + } + + xFreeBytesRemaining -= pxBlock->xBlockSize; + } + } + + traceMALLOC( pvReturn, xWantedSize ); + } + ( void ) xTaskResumeAll(); + + #if( configUSE_MALLOC_FAILED_HOOK == 1 ) + { + if( pvReturn == NULL ) + { + extern void vApplicationMallocFailedHook( void ); + vApplicationMallocFailedHook(); + } + } + #endif + + return pvReturn; +} +/*-----------------------------------------------------------*/ + +void vPortFree( void *pv ) +{ +uint8_t *puc = ( uint8_t * ) pv; +BlockLink_t *pxLink; + + if( pv != NULL ) + { + /* The memory being freed will have an BlockLink_t structure immediately + before it. */ + puc -= heapSTRUCT_SIZE; + + /* This unexpected casting is to keep some compilers from issuing + byte alignment warnings. */ + pxLink = ( void * ) puc; + + vTaskSuspendAll(); + { + /* Add this block to the list of free blocks. */ + prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) ); + xFreeBytesRemaining += pxLink->xBlockSize; + traceFREE( pv, pxLink->xBlockSize ); + } + ( void ) xTaskResumeAll(); + } +} +/*-----------------------------------------------------------*/ + +size_t xPortGetFreeHeapSize( void ) +{ + return xFreeBytesRemaining; +} +/*-----------------------------------------------------------*/ + +void vPortInitialiseBlocks( void ) +{ + /* This just exists to keep the linker quiet. */ +} +/*-----------------------------------------------------------*/ + +static void prvHeapInit( void ) +{ +BlockLink_t *pxFirstFreeBlock; +uint8_t *pucAlignedHeap; + + /* Ensure the heap starts on a correctly aligned boundary. */ + pucAlignedHeap = ( uint8_t * ) ( ( ( portPOINTER_SIZE_TYPE ) &ucHeap[ portBYTE_ALIGNMENT ] ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) ); + + /* xStart is used to hold a pointer to the first item in the list of free + blocks. The void cast is used to prevent compiler warnings. */ + xStart.pxNextFreeBlock = ( void * ) pucAlignedHeap; + xStart.xBlockSize = ( size_t ) 0; + + /* xEnd is used to mark the end of the list of free blocks. */ + xEnd.xBlockSize = configADJUSTED_HEAP_SIZE; + xEnd.pxNextFreeBlock = NULL; + + /* To start with there is a single free block that is sized to take up the + entire heap space. */ + pxFirstFreeBlock = ( void * ) pucAlignedHeap; + pxFirstFreeBlock->xBlockSize = configADJUSTED_HEAP_SIZE; + pxFirstFreeBlock->pxNextFreeBlock = &xEnd; +} +/*-----------------------------------------------------------*/ diff --git a/STM32F1/libraries/FreeRTOS900/utility/MemMang/heap_3.c b/STM32F1/libraries/FreeRTOS900/utility/MemMang/heap_3.c new file mode 100644 index 0000000..f3c49c0 --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/utility/MemMang/heap_3.c @@ -0,0 +1,135 @@ +/* + FreeRTOS V8.2.1 - Copyright (C) 2015 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + + +/* + * Implementation of pvPortMalloc() and vPortFree() that relies on the + * compilers own malloc() and free() implementations. + * + * This file can only be used if the linker is configured to to generate + * a heap memory area. + * + * See heap_1.c, heap_2.c and heap_4.c for alternative implementations, and the + * memory management pages of http://www.FreeRTOS.org for more information. + */ + +#include + +/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining +all the API functions to use the MPU wrappers. That should only be done when +task.h is included from an application file. */ +#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +#include "FreeRTOS.h" +#include "task.h" + +#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +/*-----------------------------------------------------------*/ + +void *pvPortMalloc( size_t xWantedSize ) +{ +void *pvReturn; + + vTaskSuspendAll(); + { + pvReturn = malloc( xWantedSize ); + traceMALLOC( pvReturn, xWantedSize ); + } + ( void ) xTaskResumeAll(); + + #if( configUSE_MALLOC_FAILED_HOOK == 1 ) + { + if( pvReturn == NULL ) + { + extern void vApplicationMallocFailedHook( void ); + vApplicationMallocFailedHook(); + } + } + #endif + + return pvReturn; +} +/*-----------------------------------------------------------*/ + +void vPortFree( void *pv ) +{ + if( pv ) + { + vTaskSuspendAll(); + { + free( pv ); + traceFREE( pv, 0 ); + } + ( void ) xTaskResumeAll(); + } +} + + + diff --git a/STM32F1/libraries/FreeRTOS900/utility/MemMang/heap_4.c b/STM32F1/libraries/FreeRTOS900/utility/MemMang/heap_4.c new file mode 100644 index 0000000..8df0e9a --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/utility/MemMang/heap_4.c @@ -0,0 +1,474 @@ +/* + FreeRTOS V8.2.1 - Copyright (C) 2015 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* + * A sample implementation of pvPortMalloc() and vPortFree() that combines + * (coalescences) adjacent memory blocks as they are freed, and in so doing + * limits memory fragmentation. + * + * See heap_1.c, heap_2.c and heap_3.c for alternative implementations, and the + * memory management pages of http://www.FreeRTOS.org for more information. + */ +#include + +/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining +all the API functions to use the MPU wrappers. That should only be done when +task.h is included from an application file. */ +#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +#include "FreeRTOS.h" +#include "task.h" + +#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +/* Block sizes must not get too small. */ +#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( xHeapStructSize * 2 ) ) + +/* Assumes 8bit bytes! */ +#define heapBITS_PER_BYTE ( ( size_t ) 8 ) + +/* Allocate the memory for the heap. */ +#if( configAPPLICATION_ALLOCATED_HEAP == 1 ) + /* The application writer has already defined the array used for the RTOS + heap - probably so it can be placed in a special segment or address. */ + extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ]; +#else + static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ]; +#endif /* configAPPLICATION_ALLOCATED_HEAP */ + +/* Define the linked list structure. This is used to link free blocks in order +of their memory address. */ +typedef struct A_BLOCK_LINK +{ + struct A_BLOCK_LINK *pxNextFreeBlock; /*<< The next free block in the list. */ + size_t xBlockSize; /*<< The size of the free block. */ +} BlockLink_t; + +/*-----------------------------------------------------------*/ + +/* + * Inserts a block of memory that is being freed into the correct position in + * the list of free memory blocks. The block being freed will be merged with + * the block in front it and/or the block behind it if the memory blocks are + * adjacent to each other. + */ +static void prvInsertBlockIntoFreeList( BlockLink_t *pxBlockToInsert ); + +/* + * Called automatically to setup the required heap structures the first time + * pvPortMalloc() is called. + */ +static void prvHeapInit( void ); + +/*-----------------------------------------------------------*/ + +/* The size of the structure placed at the beginning of each allocated memory +block must by correctly byte aligned. */ +static const size_t xHeapStructSize = ( ( sizeof( BlockLink_t ) + ( ( ( size_t ) portBYTE_ALIGNMENT_MASK ) - ( size_t ) 1 ) ) & ~( ( size_t ) portBYTE_ALIGNMENT_MASK ) ); + +/* Create a couple of list links to mark the start and end of the list. */ +static BlockLink_t xStart, *pxEnd = NULL; + +/* Keeps track of the number of free bytes remaining, but says nothing about +fragmentation. */ +static size_t xFreeBytesRemaining = 0U; +static size_t xMinimumEverFreeBytesRemaining = 0U; + +/* Gets set to the top bit of an size_t type. When this bit in the xBlockSize +member of an BlockLink_t structure is set then the block belongs to the +application. When the bit is free the block is still part of the free heap +space. */ +static size_t xBlockAllocatedBit = 0; + +/*-----------------------------------------------------------*/ + +void *pvPortMalloc( size_t xWantedSize ) +{ +BlockLink_t *pxBlock, *pxPreviousBlock, *pxNewBlockLink; +void *pvReturn = NULL; + + vTaskSuspendAll(); + { + /* If this is the first call to malloc then the heap will require + initialisation to setup the list of free blocks. */ + if( pxEnd == NULL ) + { + prvHeapInit(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Check the requested block size is not so large that the top bit is + set. The top bit of the block size member of the BlockLink_t structure + is used to determine who owns the block - the application or the + kernel, so it must be free. */ + if( ( xWantedSize & xBlockAllocatedBit ) == 0 ) + { + /* The wanted size is increased so it can contain a BlockLink_t + structure in addition to the requested amount of bytes. */ + if( xWantedSize > 0 ) + { + xWantedSize += xHeapStructSize; + + /* Ensure that blocks are always aligned to the required number + of bytes. */ + if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 ) + { + /* Byte alignment required. */ + xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ); + configASSERT( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) == 0 ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) ) + { + /* Traverse the list from the start (lowest address) block until + one of adequate size is found. */ + pxPreviousBlock = &xStart; + pxBlock = xStart.pxNextFreeBlock; + while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) ) + { + pxPreviousBlock = pxBlock; + pxBlock = pxBlock->pxNextFreeBlock; + } + + /* If the end marker was reached then a block of adequate size + was not found. */ + if( pxBlock != pxEnd ) + { + /* Return the memory space pointed to - jumping over the + BlockLink_t structure at its start. */ + pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + xHeapStructSize ); + + /* This block is being returned for use so must be taken out + of the list of free blocks. */ + pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock; + + /* If the block is larger than required it can be split into + two. */ + if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE ) + { + /* This block is to be split into two. Create a new + block following the number of bytes requested. The void + cast is used to prevent byte alignment warnings from the + compiler. */ + pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize ); + configASSERT( ( ( ( uint32_t ) pxNewBlockLink ) & portBYTE_ALIGNMENT_MASK ) == 0 ); + + /* Calculate the sizes of two blocks split from the + single block. */ + pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize; + pxBlock->xBlockSize = xWantedSize; + + /* Insert the new block into the list of free blocks. */ + prvInsertBlockIntoFreeList( ( pxNewBlockLink ) ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + xFreeBytesRemaining -= pxBlock->xBlockSize; + + if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining ) + { + xMinimumEverFreeBytesRemaining = xFreeBytesRemaining; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* The block is being returned - it is allocated and owned + by the application and has no "next" block. */ + pxBlock->xBlockSize |= xBlockAllocatedBit; + pxBlock->pxNextFreeBlock = NULL; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + traceMALLOC( pvReturn, xWantedSize ); + } + ( void ) xTaskResumeAll(); + + #if( configUSE_MALLOC_FAILED_HOOK == 1 ) + { + if( pvReturn == NULL ) + { + extern void vApplicationMallocFailedHook( void ); + vApplicationMallocFailedHook(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif + + configASSERT( ( ( ( uint32_t ) pvReturn ) & portBYTE_ALIGNMENT_MASK ) == 0 ); + return pvReturn; +} +/*-----------------------------------------------------------*/ + +void vPortFree( void *pv ) +{ +uint8_t *puc = ( uint8_t * ) pv; +BlockLink_t *pxLink; + + if( pv != NULL ) + { + /* The memory being freed will have an BlockLink_t structure immediately + before it. */ + puc -= xHeapStructSize; + + /* This casting is to keep the compiler from issuing warnings. */ + pxLink = ( void * ) puc; + + /* Check the block is actually allocated. */ + configASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 ); + configASSERT( pxLink->pxNextFreeBlock == NULL ); + + if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 ) + { + if( pxLink->pxNextFreeBlock == NULL ) + { + /* The block is being returned to the heap - it is no longer + allocated. */ + pxLink->xBlockSize &= ~xBlockAllocatedBit; + + vTaskSuspendAll(); + { + /* Add this block to the list of free blocks. */ + xFreeBytesRemaining += pxLink->xBlockSize; + traceFREE( pv, pxLink->xBlockSize ); + prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) ); + } + ( void ) xTaskResumeAll(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } +} +/*-----------------------------------------------------------*/ + +size_t xPortGetFreeHeapSize( void ) +{ + return xFreeBytesRemaining; +} +/*-----------------------------------------------------------*/ + +size_t xPortGetMinimumEverFreeHeapSize( void ) +{ + return xMinimumEverFreeBytesRemaining; +} +/*-----------------------------------------------------------*/ + +void vPortInitialiseBlocks( void ) +{ + /* This just exists to keep the linker quiet. */ +} +/*-----------------------------------------------------------*/ + +static void prvHeapInit( void ) +{ +BlockLink_t *pxFirstFreeBlock; +uint8_t *pucAlignedHeap; +uint32_t ulAddress; +size_t xTotalHeapSize = configTOTAL_HEAP_SIZE; + + /* Ensure the heap starts on a correctly aligned boundary. */ + ulAddress = ( uint32_t ) ucHeap; + + if( ( ulAddress & portBYTE_ALIGNMENT_MASK ) != 0 ) + { + ulAddress += ( portBYTE_ALIGNMENT - 1 ); + ulAddress &= ~( ( uint32_t ) portBYTE_ALIGNMENT_MASK ); + xTotalHeapSize -= ulAddress - ( uint32_t ) ucHeap; + } + + pucAlignedHeap = ( uint8_t * ) ulAddress; + + /* xStart is used to hold a pointer to the first item in the list of free + blocks. The void cast is used to prevent compiler warnings. */ + xStart.pxNextFreeBlock = ( void * ) pucAlignedHeap; + xStart.xBlockSize = ( size_t ) 0; + + /* pxEnd is used to mark the end of the list of free blocks and is inserted + at the end of the heap space. */ + ulAddress = ( ( uint32_t ) pucAlignedHeap ) + xTotalHeapSize; + ulAddress -= xHeapStructSize; + ulAddress &= ~( ( uint32_t ) portBYTE_ALIGNMENT_MASK ); + pxEnd = ( void * ) ulAddress; + pxEnd->xBlockSize = 0; + pxEnd->pxNextFreeBlock = NULL; + + /* To start with there is a single free block that is sized to take up the + entire heap space, minus the space taken by pxEnd. */ + pxFirstFreeBlock = ( void * ) pucAlignedHeap; + pxFirstFreeBlock->xBlockSize = ulAddress - ( uint32_t ) pxFirstFreeBlock; + pxFirstFreeBlock->pxNextFreeBlock = pxEnd; + + /* Only one block exists - and it covers the entire usable heap space. */ + xMinimumEverFreeBytesRemaining = pxFirstFreeBlock->xBlockSize; + xFreeBytesRemaining = pxFirstFreeBlock->xBlockSize; + + /* Work out the position of the top bit in a size_t variable. */ + xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 ); +} +/*-----------------------------------------------------------*/ + +static void prvInsertBlockIntoFreeList( BlockLink_t *pxBlockToInsert ) +{ +BlockLink_t *pxIterator; +uint8_t *puc; + + /* Iterate through the list until a block is found that has a higher address + than the block being inserted. */ + for( pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock ) + { + /* Nothing to do here, just iterate to the right position. */ + } + + /* Do the block being inserted, and the block it is being inserted after + make a contiguous block of memory? */ + puc = ( uint8_t * ) pxIterator; + if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert ) + { + pxIterator->xBlockSize += pxBlockToInsert->xBlockSize; + pxBlockToInsert = pxIterator; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Do the block being inserted, and the block it is being inserted before + make a contiguous block of memory? */ + puc = ( uint8_t * ) pxBlockToInsert; + if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) pxIterator->pxNextFreeBlock ) + { + if( pxIterator->pxNextFreeBlock != pxEnd ) + { + /* Form one big block from the two blocks. */ + pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize; + pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock; + } + else + { + pxBlockToInsert->pxNextFreeBlock = pxEnd; + } + } + else + { + pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock; + } + + /* If the block being inserted plugged a gab, so was merged with the block + before and the block after, then it's pxNextFreeBlock pointer will have + already been set, and should not be set here as that would make it point + to itself. */ + if( pxIterator != pxBlockToInsert ) + { + pxIterator->pxNextFreeBlock = pxBlockToInsert; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } +} + diff --git a/STM32F1/libraries/FreeRTOS900/utility/MemMang/heap_5.c b/STM32F1/libraries/FreeRTOS900/utility/MemMang/heap_5.c new file mode 100644 index 0000000..b7bcaae --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/utility/MemMang/heap_5.c @@ -0,0 +1,523 @@ +/* + FreeRTOS V8.2.1 - Copyright (C) 2015 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* + * A sample implementation of pvPortMalloc() that allows the heap to be defined + * across multiple non-contigous blocks and combines (coalescences) adjacent + * memory blocks as they are freed. + * + * See heap_1.c, heap_2.c, heap_3.c and heap_4.c for alternative + * implementations, and the memory management pages of http://www.FreeRTOS.org + * for more information. + * + * Usage notes: + * + * vPortDefineHeapRegions() ***must*** be called before pvPortMalloc(). + * pvPortMalloc() will be called if any task objects (tasks, queues, event + * groups, etc.) are created, therefore vPortDefineHeapRegions() ***must*** be + * called before any other objects are defined. + * + * vPortDefineHeapRegions() takes a single parameter. The parameter is an array + * of HeapRegion_t structures. HeapRegion_t is defined in portable.h as + * + * typedef struct HeapRegion + * { + * uint8_t *pucStartAddress; << Start address of a block of memory that will be part of the heap. + * size_t xSizeInBytes; << Size of the block of memory. + * } HeapRegion_t; + * + * The array is terminated using a NULL zero sized region definition, and the + * memory regions defined in the array ***must*** appear in address order from + * low address to high address. So the following is a valid example of how + * to use the function. + * + * HeapRegion_t xHeapRegions[] = + * { + * { ( uint8_t * ) 0x80000000UL, 0x10000 }, << Defines a block of 0x10000 bytes starting at address 0x80000000 + * { ( uint8_t * ) 0x90000000UL, 0xa0000 }, << Defines a block of 0xa0000 bytes starting at address of 0x90000000 + * { NULL, 0 } << Terminates the array. + * }; + * + * vPortDefineHeapRegions( xHeapRegions ); << Pass the array into vPortDefineHeapRegions(). + * + * Note 0x80000000 is the lower address so appears in the array first. + * + */ +#include + +/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining +all the API functions to use the MPU wrappers. That should only be done when +task.h is included from an application file. */ +#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +#include "FreeRTOS.h" +#include "task.h" + +#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +/* Block sizes must not get too small. */ +#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( uxHeapStructSize << 1 ) ) + +/* Assumes 8bit bytes! */ +#define heapBITS_PER_BYTE ( ( size_t ) 8 ) + +/* Define the linked list structure. This is used to link free blocks in order +of their memory address. */ +typedef struct A_BLOCK_LINK +{ + struct A_BLOCK_LINK *pxNextFreeBlock; /*<< The next free block in the list. */ + size_t xBlockSize; /*<< The size of the free block. */ +} BlockLink_t; + +/*-----------------------------------------------------------*/ + +/* + * Inserts a block of memory that is being freed into the correct position in + * the list of free memory blocks. The block being freed will be merged with + * the block in front it and/or the block behind it if the memory blocks are + * adjacent to each other. + */ +static void prvInsertBlockIntoFreeList( BlockLink_t *pxBlockToInsert ); + +/*-----------------------------------------------------------*/ + +/* The size of the structure placed at the beginning of each allocated memory +block must by correctly byte aligned. */ +static const uint32_t uxHeapStructSize = ( ( sizeof ( BlockLink_t ) + ( portBYTE_ALIGNMENT - 1 ) ) & ~portBYTE_ALIGNMENT_MASK ); + +/* Create a couple of list links to mark the start and end of the list. */ +static BlockLink_t xStart, *pxEnd = NULL; + +/* Keeps track of the number of free bytes remaining, but says nothing about +fragmentation. */ +static size_t xFreeBytesRemaining = 0; +static size_t xMinimumEverFreeBytesRemaining = 0; + +/* Gets set to the top bit of an size_t type. When this bit in the xBlockSize +member of an BlockLink_t structure is set then the block belongs to the +application. When the bit is free the block is still part of the free heap +space. */ +static size_t xBlockAllocatedBit = 0; + +/*-----------------------------------------------------------*/ + +void *pvPortMalloc( size_t xWantedSize ) +{ +BlockLink_t *pxBlock, *pxPreviousBlock, *pxNewBlockLink; +void *pvReturn = NULL; + + /* The heap must be initialised before the first call to + prvPortMalloc(). */ + configASSERT( pxEnd ); + + vTaskSuspendAll(); + { + /* Check the requested block size is not so large that the top bit is + set. The top bit of the block size member of the BlockLink_t structure + is used to determine who owns the block - the application or the + kernel, so it must be free. */ + if( ( xWantedSize & xBlockAllocatedBit ) == 0 ) + { + /* The wanted size is increased so it can contain a BlockLink_t + structure in addition to the requested amount of bytes. */ + if( xWantedSize > 0 ) + { + xWantedSize += uxHeapStructSize; + + /* Ensure that blocks are always aligned to the required number + of bytes. */ + if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 ) + { + /* Byte alignment required. */ + xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) ) + { + /* Traverse the list from the start (lowest address) block until + one of adequate size is found. */ + pxPreviousBlock = &xStart; + pxBlock = xStart.pxNextFreeBlock; + while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) ) + { + pxPreviousBlock = pxBlock; + pxBlock = pxBlock->pxNextFreeBlock; + } + + /* If the end marker was reached then a block of adequate size + was not found. */ + if( pxBlock != pxEnd ) + { + /* Return the memory space pointed to - jumping over the + BlockLink_t structure at its start. */ + pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + uxHeapStructSize ); + + /* This block is being returned for use so must be taken out + of the list of free blocks. */ + pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock; + + /* If the block is larger than required it can be split into + two. */ + if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE ) + { + /* This block is to be split into two. Create a new + block following the number of bytes requested. The void + cast is used to prevent byte alignment warnings from the + compiler. */ + pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize ); + + /* Calculate the sizes of two blocks split from the + single block. */ + pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize; + pxBlock->xBlockSize = xWantedSize; + + /* Insert the new block into the list of free blocks. */ + prvInsertBlockIntoFreeList( ( pxNewBlockLink ) ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + xFreeBytesRemaining -= pxBlock->xBlockSize; + + if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining ) + { + xMinimumEverFreeBytesRemaining = xFreeBytesRemaining; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* The block is being returned - it is allocated and owned + by the application and has no "next" block. */ + pxBlock->xBlockSize |= xBlockAllocatedBit; + pxBlock->pxNextFreeBlock = NULL; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + traceMALLOC( pvReturn, xWantedSize ); + } + ( void ) xTaskResumeAll(); + + #if( configUSE_MALLOC_FAILED_HOOK == 1 ) + { + if( pvReturn == NULL ) + { + extern void vApplicationMallocFailedHook( void ); + vApplicationMallocFailedHook(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif + + return pvReturn; +} +/*-----------------------------------------------------------*/ + +void vPortFree( void *pv ) +{ +uint8_t *puc = ( uint8_t * ) pv; +BlockLink_t *pxLink; + + if( pv != NULL ) + { + /* The memory being freed will have an BlockLink_t structure immediately + before it. */ + puc -= uxHeapStructSize; + + /* This casting is to keep the compiler from issuing warnings. */ + pxLink = ( void * ) puc; + + /* Check the block is actually allocated. */ + configASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 ); + configASSERT( pxLink->pxNextFreeBlock == NULL ); + + if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 ) + { + if( pxLink->pxNextFreeBlock == NULL ) + { + /* The block is being returned to the heap - it is no longer + allocated. */ + pxLink->xBlockSize &= ~xBlockAllocatedBit; + + vTaskSuspendAll(); + { + /* Add this block to the list of free blocks. */ + xFreeBytesRemaining += pxLink->xBlockSize; + traceFREE( pv, pxLink->xBlockSize ); + prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) ); + } + ( void ) xTaskResumeAll(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } +} +/*-----------------------------------------------------------*/ + +size_t xPortGetFreeHeapSize( void ) +{ + return xFreeBytesRemaining; +} +/*-----------------------------------------------------------*/ + +size_t xPortGetMinimumEverFreeHeapSize( void ) +{ + return xMinimumEverFreeBytesRemaining; +} +/*-----------------------------------------------------------*/ + +static void prvInsertBlockIntoFreeList( BlockLink_t *pxBlockToInsert ) +{ +BlockLink_t *pxIterator; +uint8_t *puc; + + /* Iterate through the list until a block is found that has a higher address + than the block being inserted. */ + for( pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock ) + { + /* Nothing to do here, just iterate to the right position. */ + } + + /* Do the block being inserted, and the block it is being inserted after + make a contiguous block of memory? */ + puc = ( uint8_t * ) pxIterator; + if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert ) + { + pxIterator->xBlockSize += pxBlockToInsert->xBlockSize; + pxBlockToInsert = pxIterator; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Do the block being inserted, and the block it is being inserted before + make a contiguous block of memory? */ + puc = ( uint8_t * ) pxBlockToInsert; + if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) pxIterator->pxNextFreeBlock ) + { + if( pxIterator->pxNextFreeBlock != pxEnd ) + { + /* Form one big block from the two blocks. */ + pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize; + pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock; + } + else + { + pxBlockToInsert->pxNextFreeBlock = pxEnd; + } + } + else + { + pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock; + } + + /* If the block being inserted plugged a gab, so was merged with the block + before and the block after, then it's pxNextFreeBlock pointer will have + already been set, and should not be set here as that would make it point + to itself. */ + if( pxIterator != pxBlockToInsert ) + { + pxIterator->pxNextFreeBlock = pxBlockToInsert; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } +} +/*-----------------------------------------------------------*/ + +void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions ) +{ +BlockLink_t *pxFirstFreeBlockInRegion = NULL, *pxPreviousFreeBlock; +uint8_t *pucAlignedHeap; +size_t xTotalRegionSize, xTotalHeapSize = 0; +BaseType_t xDefinedRegions = 0; +uint32_t ulAddress; +const HeapRegion_t *pxHeapRegion; + + /* Can only call once! */ + configASSERT( pxEnd == NULL ); + + pxHeapRegion = &( pxHeapRegions[ xDefinedRegions ] ); + + while( pxHeapRegion->xSizeInBytes > 0 ) + { + xTotalRegionSize = pxHeapRegion->xSizeInBytes; + + /* Ensure the heap region starts on a correctly aligned boundary. */ + ulAddress = ( uint32_t ) pxHeapRegion->pucStartAddress; + if( ( ulAddress & portBYTE_ALIGNMENT_MASK ) != 0 ) + { + ulAddress += ( portBYTE_ALIGNMENT - 1 ); + ulAddress &= ~portBYTE_ALIGNMENT_MASK; + + /* Adjust the size for the bytes lost to alignment. */ + xTotalRegionSize -= ulAddress - ( uint32_t ) pxHeapRegion->pucStartAddress; + } + + pucAlignedHeap = ( uint8_t * ) ulAddress; + + /* Set xStart if it has not already been set. */ + if( xDefinedRegions == 0 ) + { + /* xStart is used to hold a pointer to the first item in the list of + free blocks. The void cast is used to prevent compiler warnings. */ + xStart.pxNextFreeBlock = ( BlockLink_t * ) pucAlignedHeap; + xStart.xBlockSize = ( size_t ) 0; + } + else + { + /* Should only get here if one region has already been added to the + heap. */ + configASSERT( pxEnd != NULL ); + + /* Check blocks are passed in with increasing start addresses. */ + configASSERT( ulAddress > ( uint32_t ) pxEnd ); + } + + /* Remember the location of the end marker in the previous region, if + any. */ + pxPreviousFreeBlock = pxEnd; + + /* pxEnd is used to mark the end of the list of free blocks and is + inserted at the end of the region space. */ + ulAddress = ( ( uint32_t ) pucAlignedHeap ) + xTotalRegionSize; + ulAddress -= uxHeapStructSize; + ulAddress &= ~portBYTE_ALIGNMENT_MASK; + pxEnd = ( BlockLink_t * ) ulAddress; + pxEnd->xBlockSize = 0; + pxEnd->pxNextFreeBlock = NULL; + + /* To start with there is a single free block in this region that is + sized to take up the entire heap region minus the space taken by the + free block structure. */ + pxFirstFreeBlockInRegion = ( BlockLink_t * ) pucAlignedHeap; + pxFirstFreeBlockInRegion->xBlockSize = ulAddress - ( uint32_t ) pxFirstFreeBlockInRegion; + pxFirstFreeBlockInRegion->pxNextFreeBlock = pxEnd; + + /* If this is not the first region that makes up the entire heap space + then link the previous region to this region. */ + if( pxPreviousFreeBlock != NULL ) + { + pxPreviousFreeBlock->pxNextFreeBlock = pxFirstFreeBlockInRegion; + } + + xTotalHeapSize += pxFirstFreeBlockInRegion->xBlockSize; + + /* Move onto the next HeapRegion_t structure. */ + xDefinedRegions++; + pxHeapRegion = &( pxHeapRegions[ xDefinedRegions ] ); + } + + xMinimumEverFreeBytesRemaining = xTotalHeapSize; + xFreeBytesRemaining = xTotalHeapSize; + + /* Check something was actually defined before it is accessed. */ + configASSERT( xTotalHeapSize ); + + /* Work out the position of the top bit in a size_t variable. */ + xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 ); +} + diff --git a/STM32F1/libraries/FreeRTOS900/utility/StackMacros.h b/STM32F1/libraries/FreeRTOS900/utility/StackMacros.h new file mode 100644 index 0000000..13c6b82 --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/utility/StackMacros.h @@ -0,0 +1,171 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef STACK_MACROS_H +#define STACK_MACROS_H + +/* + * Call the stack overflow hook function if the stack of the task being swapped + * out is currently overflowed, or looks like it might have overflowed in the + * past. + * + * Setting configCHECK_FOR_STACK_OVERFLOW to 1 will cause the macro to check + * the current stack state only - comparing the current top of stack value to + * the stack limit. Setting configCHECK_FOR_STACK_OVERFLOW to greater than 1 + * will also cause the last few stack bytes to be checked to ensure the value + * to which the bytes were set when the task was created have not been + * overwritten. Note this second test does not guarantee that an overflowed + * stack will always be recognised. + */ + +/*-----------------------------------------------------------*/ + +#if( ( configCHECK_FOR_STACK_OVERFLOW == 1 ) && ( portSTACK_GROWTH < 0 ) ) + + /* Only the current stack state is to be checked. */ + #define taskCHECK_FOR_STACK_OVERFLOW() \ + { \ + /* Is the currently saved stack pointer within the stack limit? */ \ + if( pxCurrentTCB->pxTopOfStack <= pxCurrentTCB->pxStack ) \ + { \ + vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ + } \ + } + +#endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */ +/*-----------------------------------------------------------*/ + +#if( ( configCHECK_FOR_STACK_OVERFLOW == 1 ) && ( portSTACK_GROWTH > 0 ) ) + + /* Only the current stack state is to be checked. */ + #define taskCHECK_FOR_STACK_OVERFLOW() \ + { \ + \ + /* Is the currently saved stack pointer within the stack limit? */ \ + if( pxCurrentTCB->pxTopOfStack >= pxCurrentTCB->pxEndOfStack ) \ + { \ + vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ + } \ + } + +#endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */ +/*-----------------------------------------------------------*/ + +#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH < 0 ) ) + + #define taskCHECK_FOR_STACK_OVERFLOW() \ + { \ + const uint32_t * const pulStack = ( uint32_t * ) pxCurrentTCB->pxStack; \ + const uint32_t ulCheckValue = ( uint32_t ) 0xa5a5a5a5; \ + \ + if( ( pulStack[ 0 ] != ulCheckValue ) || \ + ( pulStack[ 1 ] != ulCheckValue ) || \ + ( pulStack[ 2 ] != ulCheckValue ) || \ + ( pulStack[ 3 ] != ulCheckValue ) ) \ + { \ + vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ + } \ + } + +#endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */ +/*-----------------------------------------------------------*/ + +#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH > 0 ) ) + + #define taskCHECK_FOR_STACK_OVERFLOW() \ + { \ + int8_t *pcEndOfStack = ( int8_t * ) pxCurrentTCB->pxEndOfStack; \ + static const uint8_t ucExpectedStackBytes[] = { tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ + tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ + tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ + tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ + tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE }; \ + \ + \ + pcEndOfStack -= sizeof( ucExpectedStackBytes ); \ + \ + /* Has the extremity of the task stack ever been written over? */ \ + if( memcmp( ( void * ) pcEndOfStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) != 0 ) \ + { \ + vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ + } \ + } + +#endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */ +/*-----------------------------------------------------------*/ + +/* Remove stack overflow macro if not being used. */ +#ifndef taskCHECK_FOR_STACK_OVERFLOW + #define taskCHECK_FOR_STACK_OVERFLOW() +#endif + + + +#endif /* STACK_MACROS_H */ + diff --git a/STM32F1/libraries/FreeRTOS900/utility/croutine.c b/STM32F1/libraries/FreeRTOS900/utility/croutine.c new file mode 100644 index 0000000..993e09b --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/utility/croutine.c @@ -0,0 +1,395 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#include "FreeRTOS.h" +#include "task.h" +#include "croutine.h" + +/* Remove the whole file is co-routines are not being used. */ +#if( configUSE_CO_ROUTINES != 0 ) + +/* + * Some kernel aware debuggers require data to be viewed to be global, rather + * than file scope. + */ +#ifdef portREMOVE_STATIC_QUALIFIER + #define static +#endif + + +/* Lists for ready and blocked co-routines. --------------------*/ +static List_t pxReadyCoRoutineLists[ configMAX_CO_ROUTINE_PRIORITIES ]; /*< Prioritised ready co-routines. */ +static List_t xDelayedCoRoutineList1; /*< Delayed co-routines. */ +static List_t xDelayedCoRoutineList2; /*< Delayed co-routines (two lists are used - one for delays that have overflowed the current tick count. */ +static List_t * pxDelayedCoRoutineList; /*< Points to the delayed co-routine list currently being used. */ +static List_t * pxOverflowDelayedCoRoutineList; /*< Points to the delayed co-routine list currently being used to hold co-routines that have overflowed the current tick count. */ +static List_t xPendingReadyCoRoutineList; /*< Holds co-routines that have been readied by an external event. They cannot be added directly to the ready lists as the ready lists cannot be accessed by interrupts. */ + +/* Other file private variables. --------------------------------*/ +CRCB_t * pxCurrentCoRoutine = NULL; +static UBaseType_t uxTopCoRoutineReadyPriority = 0; +static TickType_t xCoRoutineTickCount = 0, xLastTickCount = 0, xPassedTicks = 0; + +/* The initial state of the co-routine when it is created. */ +#define corINITIAL_STATE ( 0 ) + +/* + * Place the co-routine represented by pxCRCB into the appropriate ready queue + * for the priority. It is inserted at the end of the list. + * + * This macro accesses the co-routine ready lists and therefore must not be + * used from within an ISR. + */ +#define prvAddCoRoutineToReadyQueue( pxCRCB ) \ +{ \ + if( pxCRCB->uxPriority > uxTopCoRoutineReadyPriority ) \ + { \ + uxTopCoRoutineReadyPriority = pxCRCB->uxPriority; \ + } \ + vListInsertEnd( ( List_t * ) &( pxReadyCoRoutineLists[ pxCRCB->uxPriority ] ), &( pxCRCB->xGenericListItem ) ); \ +} + +/* + * Utility to ready all the lists used by the scheduler. This is called + * automatically upon the creation of the first co-routine. + */ +static void prvInitialiseCoRoutineLists( void ); + +/* + * Co-routines that are readied by an interrupt cannot be placed directly into + * the ready lists (there is no mutual exclusion). Instead they are placed in + * in the pending ready list in order that they can later be moved to the ready + * list by the co-routine scheduler. + */ +static void prvCheckPendingReadyList( void ); + +/* + * Macro that looks at the list of co-routines that are currently delayed to + * see if any require waking. + * + * Co-routines are stored in the queue in the order of their wake time - + * meaning once one co-routine has been found whose timer has not expired + * we need not look any further down the list. + */ +static void prvCheckDelayedList( void ); + +/*-----------------------------------------------------------*/ + +BaseType_t xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, UBaseType_t uxPriority, UBaseType_t uxIndex ) +{ +BaseType_t xReturn; +CRCB_t *pxCoRoutine; + + /* Allocate the memory that will store the co-routine control block. */ + pxCoRoutine = ( CRCB_t * ) pvPortMalloc( sizeof( CRCB_t ) ); + if( pxCoRoutine ) + { + /* If pxCurrentCoRoutine is NULL then this is the first co-routine to + be created and the co-routine data structures need initialising. */ + if( pxCurrentCoRoutine == NULL ) + { + pxCurrentCoRoutine = pxCoRoutine; + prvInitialiseCoRoutineLists(); + } + + /* Check the priority is within limits. */ + if( uxPriority >= configMAX_CO_ROUTINE_PRIORITIES ) + { + uxPriority = configMAX_CO_ROUTINE_PRIORITIES - 1; + } + + /* Fill out the co-routine control block from the function parameters. */ + pxCoRoutine->uxState = corINITIAL_STATE; + pxCoRoutine->uxPriority = uxPriority; + pxCoRoutine->uxIndex = uxIndex; + pxCoRoutine->pxCoRoutineFunction = pxCoRoutineCode; + + /* Initialise all the other co-routine control block parameters. */ + vListInitialiseItem( &( pxCoRoutine->xGenericListItem ) ); + vListInitialiseItem( &( pxCoRoutine->xEventListItem ) ); + + /* Set the co-routine control block as a link back from the ListItem_t. + This is so we can get back to the containing CRCB from a generic item + in a list. */ + listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xGenericListItem ), pxCoRoutine ); + listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xEventListItem ), pxCoRoutine ); + + /* Event lists are always in priority order. */ + listSET_LIST_ITEM_VALUE( &( pxCoRoutine->xEventListItem ), ( ( TickType_t ) configMAX_CO_ROUTINE_PRIORITIES - ( TickType_t ) uxPriority ) ); + + /* Now the co-routine has been initialised it can be added to the ready + list at the correct priority. */ + prvAddCoRoutineToReadyQueue( pxCoRoutine ); + + xReturn = pdPASS; + } + else + { + xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +void vCoRoutineAddToDelayedList( TickType_t xTicksToDelay, List_t *pxEventList ) +{ +TickType_t xTimeToWake; + + /* Calculate the time to wake - this may overflow but this is + not a problem. */ + xTimeToWake = xCoRoutineTickCount + xTicksToDelay; + + /* We must remove ourselves from the ready list before adding + ourselves to the blocked list as the same list item is used for + both lists. */ + ( void ) uxListRemove( ( ListItem_t * ) &( pxCurrentCoRoutine->xGenericListItem ) ); + + /* The list item will be inserted in wake time order. */ + listSET_LIST_ITEM_VALUE( &( pxCurrentCoRoutine->xGenericListItem ), xTimeToWake ); + + if( xTimeToWake < xCoRoutineTickCount ) + { + /* Wake time has overflowed. Place this item in the + overflow list. */ + vListInsert( ( List_t * ) pxOverflowDelayedCoRoutineList, ( ListItem_t * ) &( pxCurrentCoRoutine->xGenericListItem ) ); + } + else + { + /* The wake time has not overflowed, so we can use the + current block list. */ + vListInsert( ( List_t * ) pxDelayedCoRoutineList, ( ListItem_t * ) &( pxCurrentCoRoutine->xGenericListItem ) ); + } + + if( pxEventList ) + { + /* Also add the co-routine to an event list. If this is done then the + function must be called with interrupts disabled. */ + vListInsert( pxEventList, &( pxCurrentCoRoutine->xEventListItem ) ); + } +} +/*-----------------------------------------------------------*/ + +static void prvCheckPendingReadyList( void ) +{ + /* Are there any co-routines waiting to get moved to the ready list? These + are co-routines that have been readied by an ISR. The ISR cannot access + the ready lists itself. */ + while( listLIST_IS_EMPTY( &xPendingReadyCoRoutineList ) == pdFALSE ) + { + CRCB_t *pxUnblockedCRCB; + + /* The pending ready list can be accessed by an ISR. */ + portDISABLE_INTERRUPTS(); + { + pxUnblockedCRCB = ( CRCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( (&xPendingReadyCoRoutineList) ); + ( void ) uxListRemove( &( pxUnblockedCRCB->xEventListItem ) ); + } + portENABLE_INTERRUPTS(); + + ( void ) uxListRemove( &( pxUnblockedCRCB->xGenericListItem ) ); + prvAddCoRoutineToReadyQueue( pxUnblockedCRCB ); + } +} +/*-----------------------------------------------------------*/ + +static void prvCheckDelayedList( void ) +{ +CRCB_t *pxCRCB; + + xPassedTicks = xTaskGetTickCount() - xLastTickCount; + while( xPassedTicks ) + { + xCoRoutineTickCount++; + xPassedTicks--; + + /* If the tick count has overflowed we need to swap the ready lists. */ + if( xCoRoutineTickCount == 0 ) + { + List_t * pxTemp; + + /* Tick count has overflowed so we need to swap the delay lists. If there are + any items in pxDelayedCoRoutineList here then there is an error! */ + pxTemp = pxDelayedCoRoutineList; + pxDelayedCoRoutineList = pxOverflowDelayedCoRoutineList; + pxOverflowDelayedCoRoutineList = pxTemp; + } + + /* See if this tick has made a timeout expire. */ + while( listLIST_IS_EMPTY( pxDelayedCoRoutineList ) == pdFALSE ) + { + pxCRCB = ( CRCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedCoRoutineList ); + + if( xCoRoutineTickCount < listGET_LIST_ITEM_VALUE( &( pxCRCB->xGenericListItem ) ) ) + { + /* Timeout not yet expired. */ + break; + } + + portDISABLE_INTERRUPTS(); + { + /* The event could have occurred just before this critical + section. If this is the case then the generic list item will + have been moved to the pending ready list and the following + line is still valid. Also the pvContainer parameter will have + been set to NULL so the following lines are also valid. */ + ( void ) uxListRemove( &( pxCRCB->xGenericListItem ) ); + + /* Is the co-routine waiting on an event also? */ + if( pxCRCB->xEventListItem.pvContainer ) + { + ( void ) uxListRemove( &( pxCRCB->xEventListItem ) ); + } + } + portENABLE_INTERRUPTS(); + + prvAddCoRoutineToReadyQueue( pxCRCB ); + } + } + + xLastTickCount = xCoRoutineTickCount; +} +/*-----------------------------------------------------------*/ + +void vCoRoutineSchedule( void ) +{ + /* See if any co-routines readied by events need moving to the ready lists. */ + prvCheckPendingReadyList(); + + /* See if any delayed co-routines have timed out. */ + prvCheckDelayedList(); + + /* Find the highest priority queue that contains ready co-routines. */ + while( listLIST_IS_EMPTY( &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) ) ) + { + if( uxTopCoRoutineReadyPriority == 0 ) + { + /* No more co-routines to check. */ + return; + } + --uxTopCoRoutineReadyPriority; + } + + /* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the co-routines + of the same priority get an equal share of the processor time. */ + listGET_OWNER_OF_NEXT_ENTRY( pxCurrentCoRoutine, &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) ); + + /* Call the co-routine. */ + ( pxCurrentCoRoutine->pxCoRoutineFunction )( pxCurrentCoRoutine, pxCurrentCoRoutine->uxIndex ); + + return; +} +/*-----------------------------------------------------------*/ + +static void prvInitialiseCoRoutineLists( void ) +{ +UBaseType_t uxPriority; + + for( uxPriority = 0; uxPriority < configMAX_CO_ROUTINE_PRIORITIES; uxPriority++ ) + { + vListInitialise( ( List_t * ) &( pxReadyCoRoutineLists[ uxPriority ] ) ); + } + + vListInitialise( ( List_t * ) &xDelayedCoRoutineList1 ); + vListInitialise( ( List_t * ) &xDelayedCoRoutineList2 ); + vListInitialise( ( List_t * ) &xPendingReadyCoRoutineList ); + + /* Start with pxDelayedCoRoutineList using list1 and the + pxOverflowDelayedCoRoutineList using list2. */ + pxDelayedCoRoutineList = &xDelayedCoRoutineList1; + pxOverflowDelayedCoRoutineList = &xDelayedCoRoutineList2; +} +/*-----------------------------------------------------------*/ + +BaseType_t xCoRoutineRemoveFromEventList( const List_t *pxEventList ) +{ +CRCB_t *pxUnblockedCRCB; +BaseType_t xReturn; + + /* This function is called from within an interrupt. It can only access + event lists and the pending ready list. This function assumes that a + check has already been made to ensure pxEventList is not empty. */ + pxUnblockedCRCB = ( CRCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList ); + ( void ) uxListRemove( &( pxUnblockedCRCB->xEventListItem ) ); + vListInsertEnd( ( List_t * ) &( xPendingReadyCoRoutineList ), &( pxUnblockedCRCB->xEventListItem ) ); + + if( pxUnblockedCRCB->uxPriority >= pxCurrentCoRoutine->uxPriority ) + { + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + + return xReturn; +} + +#endif /* configUSE_CO_ROUTINES == 0 */ + diff --git a/STM32F1/libraries/FreeRTOS900/utility/croutine.h b/STM32F1/libraries/FreeRTOS900/utility/croutine.h new file mode 100644 index 0000000..4f003a0 --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/utility/croutine.h @@ -0,0 +1,762 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef CO_ROUTINE_H +#define CO_ROUTINE_H + +#ifndef INC_FREERTOS_H + #error "include FreeRTOS.h must appear in source files before include croutine.h" +#endif + +#include "list.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Used to hide the implementation of the co-routine control block. The +control block structure however has to be included in the header due to +the macro implementation of the co-routine functionality. */ +typedef void * CoRoutineHandle_t; + +/* Defines the prototype to which co-routine functions must conform. */ +typedef void (*crCOROUTINE_CODE)( CoRoutineHandle_t, UBaseType_t ); + +typedef struct corCoRoutineControlBlock +{ + crCOROUTINE_CODE pxCoRoutineFunction; + ListItem_t xGenericListItem; /*< List item used to place the CRCB in ready and blocked queues. */ + ListItem_t xEventListItem; /*< List item used to place the CRCB in event lists. */ + UBaseType_t uxPriority; /*< The priority of the co-routine in relation to other co-routines. */ + UBaseType_t uxIndex; /*< Used to distinguish between co-routines when multiple co-routines use the same co-routine function. */ + uint16_t uxState; /*< Used internally by the co-routine implementation. */ +} CRCB_t; /* Co-routine control block. Note must be identical in size down to uxPriority with TCB_t. */ + +/** + * croutine. h + *
+ BaseType_t xCoRoutineCreate(
+                                 crCOROUTINE_CODE pxCoRoutineCode,
+                                 UBaseType_t uxPriority,
+                                 UBaseType_t uxIndex
+                               );
+ * + * Create a new co-routine and add it to the list of co-routines that are + * ready to run. + * + * @param pxCoRoutineCode Pointer to the co-routine function. Co-routine + * functions require special syntax - see the co-routine section of the WEB + * documentation for more information. + * + * @param uxPriority The priority with respect to other co-routines at which + * the co-routine will run. + * + * @param uxIndex Used to distinguish between different co-routines that + * execute the same function. See the example below and the co-routine section + * of the WEB documentation for further information. + * + * @return pdPASS if the co-routine was successfully created and added to a ready + * list, otherwise an error code defined with ProjDefs.h. + * + * Example usage: +
+ // Co-routine to be created.
+ void vFlashCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ // This may not be necessary for const variables.
+ static const char cLedToFlash[ 2 ] = { 5, 6 };
+ static const TickType_t uxFlashRates[ 2 ] = { 200, 400 };
+
+     // Must start every co-routine with a call to crSTART();
+     crSTART( xHandle );
+
+     for( ;; )
+     {
+         // This co-routine just delays for a fixed period, then toggles
+         // an LED.  Two co-routines are created using this function, so
+         // the uxIndex parameter is used to tell the co-routine which
+         // LED to flash and how int32_t to delay.  This assumes xQueue has
+         // already been created.
+         vParTestToggleLED( cLedToFlash[ uxIndex ] );
+         crDELAY( xHandle, uxFlashRates[ uxIndex ] );
+     }
+
+     // Must end every co-routine with a call to crEND();
+     crEND();
+ }
+
+ // Function that creates two co-routines.
+ void vOtherFunction( void )
+ {
+ uint8_t ucParameterToPass;
+ TaskHandle_t xHandle;
+
+     // Create two co-routines at priority 0.  The first is given index 0
+     // so (from the code above) toggles LED 5 every 200 ticks.  The second
+     // is given index 1 so toggles LED 6 every 400 ticks.
+     for( uxIndex = 0; uxIndex < 2; uxIndex++ )
+     {
+         xCoRoutineCreate( vFlashCoRoutine, 0, uxIndex );
+     }
+ }
+   
+ * \defgroup xCoRoutineCreate xCoRoutineCreate + * \ingroup Tasks + */ +BaseType_t xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, UBaseType_t uxPriority, UBaseType_t uxIndex ); + + +/** + * croutine. h + *
+ void vCoRoutineSchedule( void );
+ * + * Run a co-routine. + * + * vCoRoutineSchedule() executes the highest priority co-routine that is able + * to run. The co-routine will execute until it either blocks, yields or is + * preempted by a task. Co-routines execute cooperatively so one + * co-routine cannot be preempted by another, but can be preempted by a task. + * + * If an application comprises of both tasks and co-routines then + * vCoRoutineSchedule should be called from the idle task (in an idle task + * hook). + * + * Example usage: +
+ // This idle task hook will schedule a co-routine each time it is called.
+ // The rest of the idle task will execute between co-routine calls.
+ void vApplicationIdleHook( void )
+ {
+	vCoRoutineSchedule();
+ }
+
+ // Alternatively, if you do not require any other part of the idle task to
+ // execute, the idle task hook can call vCoRoutineScheduler() within an
+ // infinite loop.
+ void vApplicationIdleHook( void )
+ {
+    for( ;; )
+    {
+        vCoRoutineSchedule();
+    }
+ }
+ 
+ * \defgroup vCoRoutineSchedule vCoRoutineSchedule + * \ingroup Tasks + */ +void vCoRoutineSchedule( void ); + +/** + * croutine. h + *
+ crSTART( CoRoutineHandle_t xHandle );
+ * + * This macro MUST always be called at the start of a co-routine function. + * + * Example usage: +
+ // Co-routine to be created.
+ void vACoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ static int32_t ulAVariable;
+
+     // Must start every co-routine with a call to crSTART();
+     crSTART( xHandle );
+
+     for( ;; )
+     {
+          // Co-routine functionality goes here.
+     }
+
+     // Must end every co-routine with a call to crEND();
+     crEND();
+ }
+ * \defgroup crSTART crSTART + * \ingroup Tasks + */ +#define crSTART( pxCRCB ) switch( ( ( CRCB_t * )( pxCRCB ) )->uxState ) { case 0: + +/** + * croutine. h + *
+ crEND();
+ * + * This macro MUST always be called at the end of a co-routine function. + * + * Example usage: +
+ // Co-routine to be created.
+ void vACoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ static int32_t ulAVariable;
+
+     // Must start every co-routine with a call to crSTART();
+     crSTART( xHandle );
+
+     for( ;; )
+     {
+          // Co-routine functionality goes here.
+     }
+
+     // Must end every co-routine with a call to crEND();
+     crEND();
+ }
+ * \defgroup crSTART crSTART + * \ingroup Tasks + */ +#define crEND() } + +/* + * These macros are intended for internal use by the co-routine implementation + * only. The macros should not be used directly by application writers. + */ +#define crSET_STATE0( xHandle ) ( ( CRCB_t * )( xHandle ) )->uxState = (__LINE__ * 2); return; case (__LINE__ * 2): +#define crSET_STATE1( xHandle ) ( ( CRCB_t * )( xHandle ) )->uxState = ((__LINE__ * 2)+1); return; case ((__LINE__ * 2)+1): + +/** + * croutine. h + *
+ crDELAY( CoRoutineHandle_t xHandle, TickType_t xTicksToDelay );
+ * + * Delay a co-routine for a fixed period of time. + * + * crDELAY can only be called from the co-routine function itself - not + * from within a function called by the co-routine function. This is because + * co-routines do not maintain their own stack. + * + * @param xHandle The handle of the co-routine to delay. This is the xHandle + * parameter of the co-routine function. + * + * @param xTickToDelay The number of ticks that the co-routine should delay + * for. The actual amount of time this equates to is defined by + * configTICK_RATE_HZ (set in FreeRTOSConfig.h). The constant portTICK_PERIOD_MS + * can be used to convert ticks to milliseconds. + * + * Example usage: +
+ // Co-routine to be created.
+ void vACoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ // This may not be necessary for const variables.
+ // We are to delay for 200ms.
+ static const xTickType xDelayTime = 200 / portTICK_PERIOD_MS;
+
+     // Must start every co-routine with a call to crSTART();
+     crSTART( xHandle );
+
+     for( ;; )
+     {
+        // Delay for 200ms.
+        crDELAY( xHandle, xDelayTime );
+
+        // Do something here.
+     }
+
+     // Must end every co-routine with a call to crEND();
+     crEND();
+ }
+ * \defgroup crDELAY crDELAY + * \ingroup Tasks + */ +#define crDELAY( xHandle, xTicksToDelay ) \ + if( ( xTicksToDelay ) > 0 ) \ + { \ + vCoRoutineAddToDelayedList( ( xTicksToDelay ), NULL ); \ + } \ + crSET_STATE0( ( xHandle ) ); + +/** + *
+ crQUEUE_SEND(
+                  CoRoutineHandle_t xHandle,
+                  QueueHandle_t pxQueue,
+                  void *pvItemToQueue,
+                  TickType_t xTicksToWait,
+                  BaseType_t *pxResult
+             )
+ * + * The macro's crQUEUE_SEND() and crQUEUE_RECEIVE() are the co-routine + * equivalent to the xQueueSend() and xQueueReceive() functions used by tasks. + * + * crQUEUE_SEND and crQUEUE_RECEIVE can only be used from a co-routine whereas + * xQueueSend() and xQueueReceive() can only be used from tasks. + * + * crQUEUE_SEND can only be called from the co-routine function itself - not + * from within a function called by the co-routine function. This is because + * co-routines do not maintain their own stack. + * + * See the co-routine section of the WEB documentation for information on + * passing data between tasks and co-routines and between ISR's and + * co-routines. + * + * @param xHandle The handle of the calling co-routine. This is the xHandle + * parameter of the co-routine function. + * + * @param pxQueue The handle of the queue on which the data will be posted. + * The handle is obtained as the return value when the queue is created using + * the xQueueCreate() API function. + * + * @param pvItemToQueue A pointer to the data being posted onto the queue. + * The number of bytes of each queued item is specified when the queue is + * created. This number of bytes is copied from pvItemToQueue into the queue + * itself. + * + * @param xTickToDelay The number of ticks that the co-routine should block + * to wait for space to become available on the queue, should space not be + * available immediately. The actual amount of time this equates to is defined + * by configTICK_RATE_HZ (set in FreeRTOSConfig.h). The constant + * portTICK_PERIOD_MS can be used to convert ticks to milliseconds (see example + * below). + * + * @param pxResult The variable pointed to by pxResult will be set to pdPASS if + * data was successfully posted onto the queue, otherwise it will be set to an + * error defined within ProjDefs.h. + * + * Example usage: +
+ // Co-routine function that blocks for a fixed period then posts a number onto
+ // a queue.
+ static void prvCoRoutineFlashTask( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ static BaseType_t xNumberToPost = 0;
+ static BaseType_t xResult;
+
+    // Co-routines must begin with a call to crSTART().
+    crSTART( xHandle );
+
+    for( ;; )
+    {
+        // This assumes the queue has already been created.
+        crQUEUE_SEND( xHandle, xCoRoutineQueue, &xNumberToPost, NO_DELAY, &xResult );
+
+        if( xResult != pdPASS )
+        {
+            // The message was not posted!
+        }
+
+        // Increment the number to be posted onto the queue.
+        xNumberToPost++;
+
+        // Delay for 100 ticks.
+        crDELAY( xHandle, 100 );
+    }
+
+    // Co-routines must end with a call to crEND().
+    crEND();
+ }
+ * \defgroup crQUEUE_SEND crQUEUE_SEND + * \ingroup Tasks + */ +#define crQUEUE_SEND( xHandle, pxQueue, pvItemToQueue, xTicksToWait, pxResult ) \ +{ \ + *( pxResult ) = xQueueCRSend( ( pxQueue) , ( pvItemToQueue) , ( xTicksToWait ) ); \ + if( *( pxResult ) == errQUEUE_BLOCKED ) \ + { \ + crSET_STATE0( ( xHandle ) ); \ + *pxResult = xQueueCRSend( ( pxQueue ), ( pvItemToQueue ), 0 ); \ + } \ + if( *pxResult == errQUEUE_YIELD ) \ + { \ + crSET_STATE1( ( xHandle ) ); \ + *pxResult = pdPASS; \ + } \ +} + +/** + * croutine. h + *
+  crQUEUE_RECEIVE(
+                     CoRoutineHandle_t xHandle,
+                     QueueHandle_t pxQueue,
+                     void *pvBuffer,
+                     TickType_t xTicksToWait,
+                     BaseType_t *pxResult
+                 )
+ * + * The macro's crQUEUE_SEND() and crQUEUE_RECEIVE() are the co-routine + * equivalent to the xQueueSend() and xQueueReceive() functions used by tasks. + * + * crQUEUE_SEND and crQUEUE_RECEIVE can only be used from a co-routine whereas + * xQueueSend() and xQueueReceive() can only be used from tasks. + * + * crQUEUE_RECEIVE can only be called from the co-routine function itself - not + * from within a function called by the co-routine function. This is because + * co-routines do not maintain their own stack. + * + * See the co-routine section of the WEB documentation for information on + * passing data between tasks and co-routines and between ISR's and + * co-routines. + * + * @param xHandle The handle of the calling co-routine. This is the xHandle + * parameter of the co-routine function. + * + * @param pxQueue The handle of the queue from which the data will be received. + * The handle is obtained as the return value when the queue is created using + * the xQueueCreate() API function. + * + * @param pvBuffer The buffer into which the received item is to be copied. + * The number of bytes of each queued item is specified when the queue is + * created. This number of bytes is copied into pvBuffer. + * + * @param xTickToDelay The number of ticks that the co-routine should block + * to wait for data to become available from the queue, should data not be + * available immediately. The actual amount of time this equates to is defined + * by configTICK_RATE_HZ (set in FreeRTOSConfig.h). The constant + * portTICK_PERIOD_MS can be used to convert ticks to milliseconds (see the + * crQUEUE_SEND example). + * + * @param pxResult The variable pointed to by pxResult will be set to pdPASS if + * data was successfully retrieved from the queue, otherwise it will be set to + * an error code as defined within ProjDefs.h. + * + * Example usage: +
+ // A co-routine receives the number of an LED to flash from a queue.  It
+ // blocks on the queue until the number is received.
+ static void prvCoRoutineFlashWorkTask( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ static BaseType_t xResult;
+ static UBaseType_t uxLEDToFlash;
+
+    // All co-routines must start with a call to crSTART().
+    crSTART( xHandle );
+
+    for( ;; )
+    {
+        // Wait for data to become available on the queue.
+        crQUEUE_RECEIVE( xHandle, xCoRoutineQueue, &uxLEDToFlash, portMAX_DELAY, &xResult );
+
+        if( xResult == pdPASS )
+        {
+            // We received the LED to flash - flash it!
+            vParTestToggleLED( uxLEDToFlash );
+        }
+    }
+
+    crEND();
+ }
+ * \defgroup crQUEUE_RECEIVE crQUEUE_RECEIVE + * \ingroup Tasks + */ +#define crQUEUE_RECEIVE( xHandle, pxQueue, pvBuffer, xTicksToWait, pxResult ) \ +{ \ + *( pxResult ) = xQueueCRReceive( ( pxQueue) , ( pvBuffer ), ( xTicksToWait ) ); \ + if( *( pxResult ) == errQUEUE_BLOCKED ) \ + { \ + crSET_STATE0( ( xHandle ) ); \ + *( pxResult ) = xQueueCRReceive( ( pxQueue) , ( pvBuffer ), 0 ); \ + } \ + if( *( pxResult ) == errQUEUE_YIELD ) \ + { \ + crSET_STATE1( ( xHandle ) ); \ + *( pxResult ) = pdPASS; \ + } \ +} + +/** + * croutine. h + *
+  crQUEUE_SEND_FROM_ISR(
+                            QueueHandle_t pxQueue,
+                            void *pvItemToQueue,
+                            BaseType_t xCoRoutinePreviouslyWoken
+                       )
+ * + * The macro's crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() are the + * co-routine equivalent to the xQueueSendFromISR() and xQueueReceiveFromISR() + * functions used by tasks. + * + * crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() can only be used to + * pass data between a co-routine and and ISR, whereas xQueueSendFromISR() and + * xQueueReceiveFromISR() can only be used to pass data between a task and and + * ISR. + * + * crQUEUE_SEND_FROM_ISR can only be called from an ISR to send data to a queue + * that is being used from within a co-routine. + * + * See the co-routine section of the WEB documentation for information on + * passing data between tasks and co-routines and between ISR's and + * co-routines. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param xCoRoutinePreviouslyWoken This is included so an ISR can post onto + * the same queue multiple times from a single interrupt. The first call + * should always pass in pdFALSE. Subsequent calls should pass in + * the value returned from the previous call. + * + * @return pdTRUE if a co-routine was woken by posting onto the queue. This is + * used by the ISR to determine if a context switch may be required following + * the ISR. + * + * Example usage: +
+ // A co-routine that blocks on a queue waiting for characters to be received.
+ static void vReceivingCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
+ {
+ char cRxedChar;
+ BaseType_t xResult;
+
+     // All co-routines must start with a call to crSTART().
+     crSTART( xHandle );
+
+     for( ;; )
+     {
+         // Wait for data to become available on the queue.  This assumes the
+         // queue xCommsRxQueue has already been created!
+         crQUEUE_RECEIVE( xHandle, xCommsRxQueue, &uxLEDToFlash, portMAX_DELAY, &xResult );
+
+         // Was a character received?
+         if( xResult == pdPASS )
+         {
+             // Process the character here.
+         }
+     }
+
+     // All co-routines must end with a call to crEND().
+     crEND();
+ }
+
+ // An ISR that uses a queue to send characters received on a serial port to
+ // a co-routine.
+ void vUART_ISR( void )
+ {
+ char cRxedChar;
+ BaseType_t xCRWokenByPost = pdFALSE;
+
+     // We loop around reading characters until there are none left in the UART.
+     while( UART_RX_REG_NOT_EMPTY() )
+     {
+         // Obtain the character from the UART.
+         cRxedChar = UART_RX_REG;
+
+         // Post the character onto a queue.  xCRWokenByPost will be pdFALSE
+         // the first time around the loop.  If the post causes a co-routine
+         // to be woken (unblocked) then xCRWokenByPost will be set to pdTRUE.
+         // In this manner we can ensure that if more than one co-routine is
+         // blocked on the queue only one is woken by this ISR no matter how
+         // many characters are posted to the queue.
+         xCRWokenByPost = crQUEUE_SEND_FROM_ISR( xCommsRxQueue, &cRxedChar, xCRWokenByPost );
+     }
+ }
+ * \defgroup crQUEUE_SEND_FROM_ISR crQUEUE_SEND_FROM_ISR + * \ingroup Tasks + */ +#define crQUEUE_SEND_FROM_ISR( pxQueue, pvItemToQueue, xCoRoutinePreviouslyWoken ) xQueueCRSendFromISR( ( pxQueue ), ( pvItemToQueue ), ( xCoRoutinePreviouslyWoken ) ) + + +/** + * croutine. h + *
+  crQUEUE_SEND_FROM_ISR(
+                            QueueHandle_t pxQueue,
+                            void *pvBuffer,
+                            BaseType_t * pxCoRoutineWoken
+                       )
+ * + * The macro's crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() are the + * co-routine equivalent to the xQueueSendFromISR() and xQueueReceiveFromISR() + * functions used by tasks. + * + * crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() can only be used to + * pass data between a co-routine and and ISR, whereas xQueueSendFromISR() and + * xQueueReceiveFromISR() can only be used to pass data between a task and and + * ISR. + * + * crQUEUE_RECEIVE_FROM_ISR can only be called from an ISR to receive data + * from a queue that is being used from within a co-routine (a co-routine + * posted to the queue). + * + * See the co-routine section of the WEB documentation for information on + * passing data between tasks and co-routines and between ISR's and + * co-routines. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvBuffer A pointer to a buffer into which the received item will be + * placed. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from the queue into + * pvBuffer. + * + * @param pxCoRoutineWoken A co-routine may be blocked waiting for space to become + * available on the queue. If crQUEUE_RECEIVE_FROM_ISR causes such a + * co-routine to unblock *pxCoRoutineWoken will get set to pdTRUE, otherwise + * *pxCoRoutineWoken will remain unchanged. + * + * @return pdTRUE an item was successfully received from the queue, otherwise + * pdFALSE. + * + * Example usage: +
+ // A co-routine that posts a character to a queue then blocks for a fixed
+ // period.  The character is incremented each time.
+ static void vSendingCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
+ {
+ // cChar holds its value while this co-routine is blocked and must therefore
+ // be declared static.
+ static char cCharToTx = 'a';
+ BaseType_t xResult;
+
+     // All co-routines must start with a call to crSTART().
+     crSTART( xHandle );
+
+     for( ;; )
+     {
+         // Send the next character to the queue.
+         crQUEUE_SEND( xHandle, xCoRoutineQueue, &cCharToTx, NO_DELAY, &xResult );
+
+         if( xResult == pdPASS )
+         {
+             // The character was successfully posted to the queue.
+         }
+		 else
+		 {
+			// Could not post the character to the queue.
+		 }
+
+         // Enable the UART Tx interrupt to cause an interrupt in this
+		 // hypothetical UART.  The interrupt will obtain the character
+		 // from the queue and send it.
+		 ENABLE_RX_INTERRUPT();
+
+		 // Increment to the next character then block for a fixed period.
+		 // cCharToTx will maintain its value across the delay as it is
+		 // declared static.
+		 cCharToTx++;
+		 if( cCharToTx > 'x' )
+		 {
+			cCharToTx = 'a';
+		 }
+		 crDELAY( 100 );
+     }
+
+     // All co-routines must end with a call to crEND().
+     crEND();
+ }
+
+ // An ISR that uses a queue to receive characters to send on a UART.
+ void vUART_ISR( void )
+ {
+ char cCharToTx;
+ BaseType_t xCRWokenByPost = pdFALSE;
+
+     while( UART_TX_REG_EMPTY() )
+     {
+         // Are there any characters in the queue waiting to be sent?
+		 // xCRWokenByPost will automatically be set to pdTRUE if a co-routine
+		 // is woken by the post - ensuring that only a single co-routine is
+		 // woken no matter how many times we go around this loop.
+         if( crQUEUE_RECEIVE_FROM_ISR( pxQueue, &cCharToTx, &xCRWokenByPost ) )
+		 {
+			 SEND_CHARACTER( cCharToTx );
+		 }
+     }
+ }
+ * \defgroup crQUEUE_RECEIVE_FROM_ISR crQUEUE_RECEIVE_FROM_ISR + * \ingroup Tasks + */ +#define crQUEUE_RECEIVE_FROM_ISR( pxQueue, pvBuffer, pxCoRoutineWoken ) xQueueCRReceiveFromISR( ( pxQueue ), ( pvBuffer ), ( pxCoRoutineWoken ) ) + +/* + * This function is intended for internal use by the co-routine macros only. + * The macro nature of the co-routine implementation requires that the + * prototype appears here. The function should not be used by application + * writers. + * + * Removes the current co-routine from its ready list and places it in the + * appropriate delayed list. + */ +void vCoRoutineAddToDelayedList( TickType_t xTicksToDelay, List_t *pxEventList ); + +/* + * This function is intended for internal use by the queue implementation only. + * The function should not be used by application writers. + * + * Removes the highest priority co-routine from the event list and places it in + * the pending ready list. + */ +BaseType_t xCoRoutineRemoveFromEventList( const List_t *pxEventList ); + +#ifdef __cplusplus +} +#endif + +#endif /* CO_ROUTINE_H */ diff --git a/STM32F1/libraries/FreeRTOS900/utility/deprecated_definitions.h b/STM32F1/libraries/FreeRTOS900/utility/deprecated_definitions.h new file mode 100644 index 0000000..7c6721c --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/utility/deprecated_definitions.h @@ -0,0 +1,321 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef DEPRECATED_DEFINITIONS_H +#define DEPRECATED_DEFINITIONS_H + + +/* Each FreeRTOS port has a unique portmacro.h header file. Originally a +pre-processor definition was used to ensure the pre-processor found the correct +portmacro.h file for the port being used. That scheme was deprecated in favour +of setting the compiler's include path such that it found the correct +portmacro.h file - removing the need for the constant and allowing the +portmacro.h file to be located anywhere in relation to the port being used. The +definitions below remain in the code for backward compatibility only. New +projects should not use them. */ + +#ifdef OPEN_WATCOM_INDUSTRIAL_PC_PORT + #include "..\..\Source\portable\owatcom\16bitdos\pc\portmacro.h" + typedef void ( __interrupt __far *pxISR )(); +#endif + +#ifdef OPEN_WATCOM_FLASH_LITE_186_PORT + #include "..\..\Source\portable\owatcom\16bitdos\flsh186\portmacro.h" + typedef void ( __interrupt __far *pxISR )(); +#endif + +#ifdef GCC_MEGA_AVR + #include "../portable/GCC/ATMega323/portmacro.h" +#endif + +#ifdef IAR_MEGA_AVR + #include "../portable/IAR/ATMega323/portmacro.h" +#endif + +#ifdef MPLAB_PIC24_PORT + #include "../../Source/portable/MPLAB/PIC24_dsPIC/portmacro.h" +#endif + +#ifdef MPLAB_DSPIC_PORT + #include "../../Source/portable/MPLAB/PIC24_dsPIC/portmacro.h" +#endif + +#ifdef MPLAB_PIC18F_PORT + #include "../../Source/portable/MPLAB/PIC18F/portmacro.h" +#endif + +#ifdef MPLAB_PIC32MX_PORT + #include "../../Source/portable/MPLAB/PIC32MX/portmacro.h" +#endif + +#ifdef _FEDPICC + #include "libFreeRTOS/Include/portmacro.h" +#endif + +#ifdef SDCC_CYGNAL + #include "../../Source/portable/SDCC/Cygnal/portmacro.h" +#endif + +#ifdef GCC_ARM7 + #include "../../Source/portable/GCC/ARM7_LPC2000/portmacro.h" +#endif + +#ifdef GCC_ARM7_ECLIPSE + #include "portmacro.h" +#endif + +#ifdef ROWLEY_LPC23xx + #include "../../Source/portable/GCC/ARM7_LPC23xx/portmacro.h" +#endif + +#ifdef IAR_MSP430 + #include "..\..\Source\portable\IAR\MSP430\portmacro.h" +#endif + +#ifdef GCC_MSP430 + #include "../../Source/portable/GCC/MSP430F449/portmacro.h" +#endif + +#ifdef ROWLEY_MSP430 + #include "../../Source/portable/Rowley/MSP430F449/portmacro.h" +#endif + +#ifdef ARM7_LPC21xx_KEIL_RVDS + #include "..\..\Source\portable\RVDS\ARM7_LPC21xx\portmacro.h" +#endif + +#ifdef SAM7_GCC + #include "../../Source/portable/GCC/ARM7_AT91SAM7S/portmacro.h" +#endif + +#ifdef SAM7_IAR + #include "..\..\Source\portable\IAR\AtmelSAM7S64\portmacro.h" +#endif + +#ifdef SAM9XE_IAR + #include "..\..\Source\portable\IAR\AtmelSAM9XE\portmacro.h" +#endif + +#ifdef LPC2000_IAR + #include "..\..\Source\portable\IAR\LPC2000\portmacro.h" +#endif + +#ifdef STR71X_IAR + #include "..\..\Source\portable\IAR\STR71x\portmacro.h" +#endif + +#ifdef STR75X_IAR + #include "..\..\Source\portable\IAR\STR75x\portmacro.h" +#endif + +#ifdef STR75X_GCC + #include "..\..\Source\portable\GCC\STR75x\portmacro.h" +#endif + +#ifdef STR91X_IAR + #include "..\..\Source\portable\IAR\STR91x\portmacro.h" +#endif + +#ifdef GCC_H8S + #include "../../Source/portable/GCC/H8S2329/portmacro.h" +#endif + +#ifdef GCC_AT91FR40008 + #include "../../Source/portable/GCC/ARM7_AT91FR40008/portmacro.h" +#endif + +#ifdef RVDS_ARMCM3_LM3S102 + #include "../../Source/portable/RVDS/ARM_CM3/portmacro.h" +#endif + +#ifdef GCC_ARMCM3_LM3S102 + #include "../../Source/portable/GCC/ARM_CM3/portmacro.h" +#endif + +#ifdef GCC_ARMCM3 + #include "portmacro.h" +#endif + +#ifdef IAR_ARM_CM3 + #include "../../Source/portable/IAR/ARM_CM3/portmacro.h" +#endif + +#ifdef IAR_ARMCM3_LM + #include "../../Source/portable/IAR/ARM_CM3/portmacro.h" +#endif + +#ifdef HCS12_CODE_WARRIOR + #include "../../Source/portable/CodeWarrior/HCS12/portmacro.h" +#endif + +#ifdef MICROBLAZE_GCC + #include "../../Source/portable/GCC/MicroBlaze/portmacro.h" +#endif + +#ifdef TERN_EE + #include "..\..\Source\portable\Paradigm\Tern_EE\small\portmacro.h" +#endif + +#ifdef GCC_HCS12 + #include "../../Source/portable/GCC/HCS12/portmacro.h" +#endif + +#ifdef GCC_MCF5235 + #include "../../Source/portable/GCC/MCF5235/portmacro.h" +#endif + +#ifdef COLDFIRE_V2_GCC + #include "../../../Source/portable/GCC/ColdFire_V2/portmacro.h" +#endif + +#ifdef COLDFIRE_V2_CODEWARRIOR + #include "../../Source/portable/CodeWarrior/ColdFire_V2/portmacro.h" +#endif + +#ifdef GCC_PPC405 + #include "../../Source/portable/GCC/PPC405_Xilinx/portmacro.h" +#endif + +#ifdef GCC_PPC440 + #include "../../Source/portable/GCC/PPC440_Xilinx/portmacro.h" +#endif + +#ifdef _16FX_SOFTUNE + #include "..\..\Source\portable\Softune\MB96340\portmacro.h" +#endif + +#ifdef BCC_INDUSTRIAL_PC_PORT + /* A short file name has to be used in place of the normal + FreeRTOSConfig.h when using the Borland compiler. */ + #include "frconfig.h" + #include "..\portable\BCC\16BitDOS\PC\prtmacro.h" + typedef void ( __interrupt __far *pxISR )(); +#endif + +#ifdef BCC_FLASH_LITE_186_PORT + /* A short file name has to be used in place of the normal + FreeRTOSConfig.h when using the Borland compiler. */ + #include "frconfig.h" + #include "..\portable\BCC\16BitDOS\flsh186\prtmacro.h" + typedef void ( __interrupt __far *pxISR )(); +#endif + +#ifdef __GNUC__ + #ifdef __AVR32_AVR32A__ + #include "portmacro.h" + #endif +#endif + +#ifdef __ICCAVR32__ + #ifdef __CORE__ + #if __CORE__ == __AVR32A__ + #include "portmacro.h" + #endif + #endif +#endif + +#ifdef __91467D + #include "portmacro.h" +#endif + +#ifdef __96340 + #include "portmacro.h" +#endif + + +#ifdef __IAR_V850ES_Fx3__ + #include "../../Source/portable/IAR/V850ES/portmacro.h" +#endif + +#ifdef __IAR_V850ES_Jx3__ + #include "../../Source/portable/IAR/V850ES/portmacro.h" +#endif + +#ifdef __IAR_V850ES_Jx3_L__ + #include "../../Source/portable/IAR/V850ES/portmacro.h" +#endif + +#ifdef __IAR_V850ES_Jx2__ + #include "../../Source/portable/IAR/V850ES/portmacro.h" +#endif + +#ifdef __IAR_V850ES_Hx2__ + #include "../../Source/portable/IAR/V850ES/portmacro.h" +#endif + +#ifdef __IAR_78K0R_Kx3__ + #include "../../Source/portable/IAR/78K0R/portmacro.h" +#endif + +#ifdef __IAR_78K0R_Kx3L__ + #include "../../Source/portable/IAR/78K0R/portmacro.h" +#endif + +#endif /* DEPRECATED_DEFINITIONS_H */ + diff --git a/STM32F1/libraries/FreeRTOS900/utility/event_groups.c b/STM32F1/libraries/FreeRTOS900/utility/event_groups.c new file mode 100644 index 0000000..b8df5fd --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/utility/event_groups.c @@ -0,0 +1,752 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* Standard includes. */ +#include + +/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining +all the API functions to use the MPU wrappers. That should only be done when +task.h is included from an application file. */ +#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "timers.h" +#include "event_groups.h" + +/* Lint e961 and e750 are suppressed as a MISRA exception justified because the +MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the +header files above, but not in this file, in order to generate the correct +privileged Vs unprivileged linkage and placement. */ +#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */ + +/* The following bit fields convey control information in a task's event list +item value. It is important they don't clash with the +taskEVENT_LIST_ITEM_VALUE_IN_USE definition. */ +#if configUSE_16_BIT_TICKS == 1 + #define eventCLEAR_EVENTS_ON_EXIT_BIT 0x0100U + #define eventUNBLOCKED_DUE_TO_BIT_SET 0x0200U + #define eventWAIT_FOR_ALL_BITS 0x0400U + #define eventEVENT_BITS_CONTROL_BYTES 0xff00U +#else + #define eventCLEAR_EVENTS_ON_EXIT_BIT 0x01000000UL + #define eventUNBLOCKED_DUE_TO_BIT_SET 0x02000000UL + #define eventWAIT_FOR_ALL_BITS 0x04000000UL + #define eventEVENT_BITS_CONTROL_BYTES 0xff000000UL +#endif + +typedef struct xEventGroupDefinition +{ + EventBits_t uxEventBits; + List_t xTasksWaitingForBits; /*< List of tasks waiting for a bit to be set. */ + + #if( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxEventGroupNumber; + #endif + + #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the event group is statically allocated to ensure no attempt is made to free the memory. */ + #endif +} EventGroup_t; + +/*-----------------------------------------------------------*/ + +/* + * Test the bits set in uxCurrentEventBits to see if the wait condition is met. + * The wait condition is defined by xWaitForAllBits. If xWaitForAllBits is + * pdTRUE then the wait condition is met if all the bits set in uxBitsToWaitFor + * are also set in uxCurrentEventBits. If xWaitForAllBits is pdFALSE then the + * wait condition is met if any of the bits set in uxBitsToWait for are also set + * in uxCurrentEventBits. + */ +static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, const EventBits_t uxBitsToWaitFor, const BaseType_t xWaitForAllBits ) PRIVILEGED_FUNCTION; + +/*-----------------------------------------------------------*/ + +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + + EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer ) + { + EventGroup_t *pxEventBits; + + /* A StaticEventGroup_t object must be provided. */ + configASSERT( pxEventGroupBuffer ); + + /* The user has provided a statically allocated event group - use it. */ + pxEventBits = ( EventGroup_t * ) pxEventGroupBuffer; /*lint !e740 EventGroup_t and StaticEventGroup_t are guaranteed to have the same size and alignment requirement - checked by configASSERT(). */ + + if( pxEventBits != NULL ) + { + pxEventBits->uxEventBits = 0; + vListInitialise( &( pxEventBits->xTasksWaitingForBits ) ); + + #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + { + /* Both static and dynamic allocation can be used, so note that + this event group was created statically in case the event group + is later deleted. */ + pxEventBits->ucStaticallyAllocated = pdTRUE; + } + #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ + + traceEVENT_GROUP_CREATE( pxEventBits ); + } + else + { + traceEVENT_GROUP_CREATE_FAILED(); + } + + return ( EventGroupHandle_t ) pxEventBits; + } + +#endif /* configSUPPORT_STATIC_ALLOCATION */ +/*-----------------------------------------------------------*/ + +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + + EventGroupHandle_t xEventGroupCreate( void ) + { + EventGroup_t *pxEventBits; + + /* Allocate the event group. */ + pxEventBits = ( EventGroup_t * ) pvPortMalloc( sizeof( EventGroup_t ) ); + + if( pxEventBits != NULL ) + { + pxEventBits->uxEventBits = 0; + vListInitialise( &( pxEventBits->xTasksWaitingForBits ) ); + + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) + { + /* Both static and dynamic allocation can be used, so note this + event group was allocated statically in case the event group is + later deleted. */ + pxEventBits->ucStaticallyAllocated = pdFALSE; + } + #endif /* configSUPPORT_STATIC_ALLOCATION */ + + traceEVENT_GROUP_CREATE( pxEventBits ); + } + else + { + traceEVENT_GROUP_CREATE_FAILED(); + } + + return ( EventGroupHandle_t ) pxEventBits; + } + +#endif /* configSUPPORT_DYNAMIC_ALLOCATION */ +/*-----------------------------------------------------------*/ + +EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait ) +{ +EventBits_t uxOriginalBitValue, uxReturn; +EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup; +BaseType_t xAlreadyYielded; +BaseType_t xTimeoutOccurred = pdFALSE; + + configASSERT( ( uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES ) == 0 ); + configASSERT( uxBitsToWaitFor != 0 ); + #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) + { + configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) ); + } + #endif + + vTaskSuspendAll(); + { + uxOriginalBitValue = pxEventBits->uxEventBits; + + ( void ) xEventGroupSetBits( xEventGroup, uxBitsToSet ); + + if( ( ( uxOriginalBitValue | uxBitsToSet ) & uxBitsToWaitFor ) == uxBitsToWaitFor ) + { + /* All the rendezvous bits are now set - no need to block. */ + uxReturn = ( uxOriginalBitValue | uxBitsToSet ); + + /* Rendezvous always clear the bits. They will have been cleared + already unless this is the only task in the rendezvous. */ + pxEventBits->uxEventBits &= ~uxBitsToWaitFor; + + xTicksToWait = 0; + } + else + { + if( xTicksToWait != ( TickType_t ) 0 ) + { + traceEVENT_GROUP_SYNC_BLOCK( xEventGroup, uxBitsToSet, uxBitsToWaitFor ); + + /* Store the bits that the calling task is waiting for in the + task's event list item so the kernel knows when a match is + found. Then enter the blocked state. */ + vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | eventCLEAR_EVENTS_ON_EXIT_BIT | eventWAIT_FOR_ALL_BITS ), xTicksToWait ); + + /* This assignment is obsolete as uxReturn will get set after + the task unblocks, but some compilers mistakenly generate a + warning about uxReturn being returned without being set if the + assignment is omitted. */ + uxReturn = 0; + } + else + { + /* The rendezvous bits were not set, but no block time was + specified - just return the current event bit value. */ + uxReturn = pxEventBits->uxEventBits; + } + } + } + xAlreadyYielded = xTaskResumeAll(); + + if( xTicksToWait != ( TickType_t ) 0 ) + { + if( xAlreadyYielded == pdFALSE ) + { + portYIELD_WITHIN_API(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* The task blocked to wait for its required bits to be set - at this + point either the required bits were set or the block time expired. If + the required bits were set they will have been stored in the task's + event list item, and they should now be retrieved then cleared. */ + uxReturn = uxTaskResetEventItemValue(); + + if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 ) + { + /* The task timed out, just return the current event bit value. */ + taskENTER_CRITICAL(); + { + uxReturn = pxEventBits->uxEventBits; + + /* Although the task got here because it timed out before the + bits it was waiting for were set, it is possible that since it + unblocked another task has set the bits. If this is the case + then it needs to clear the bits before exiting. */ + if( ( uxReturn & uxBitsToWaitFor ) == uxBitsToWaitFor ) + { + pxEventBits->uxEventBits &= ~uxBitsToWaitFor; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); + + xTimeoutOccurred = pdTRUE; + } + else + { + /* The task unblocked because the bits were set. */ + } + + /* Control bits might be set as the task had blocked should not be + returned. */ + uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES; + } + + traceEVENT_GROUP_SYNC_END( xEventGroup, uxBitsToSet, uxBitsToWaitFor, xTimeoutOccurred ); + + return uxReturn; +} +/*-----------------------------------------------------------*/ + +EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait ) +{ +EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup; +EventBits_t uxReturn, uxControlBits = 0; +BaseType_t xWaitConditionMet, xAlreadyYielded; +BaseType_t xTimeoutOccurred = pdFALSE; + + /* Check the user is not attempting to wait on the bits used by the kernel + itself, and that at least one bit is being requested. */ + configASSERT( xEventGroup ); + configASSERT( ( uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES ) == 0 ); + configASSERT( uxBitsToWaitFor != 0 ); + #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) + { + configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) ); + } + #endif + + vTaskSuspendAll(); + { + const EventBits_t uxCurrentEventBits = pxEventBits->uxEventBits; + + /* Check to see if the wait condition is already met or not. */ + xWaitConditionMet = prvTestWaitCondition( uxCurrentEventBits, uxBitsToWaitFor, xWaitForAllBits ); + + if( xWaitConditionMet != pdFALSE ) + { + /* The wait condition has already been met so there is no need to + block. */ + uxReturn = uxCurrentEventBits; + xTicksToWait = ( TickType_t ) 0; + + /* Clear the wait bits if requested to do so. */ + if( xClearOnExit != pdFALSE ) + { + pxEventBits->uxEventBits &= ~uxBitsToWaitFor; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else if( xTicksToWait == ( TickType_t ) 0 ) + { + /* The wait condition has not been met, but no block time was + specified, so just return the current value. */ + uxReturn = uxCurrentEventBits; + } + else + { + /* The task is going to block to wait for its required bits to be + set. uxControlBits are used to remember the specified behaviour of + this call to xEventGroupWaitBits() - for use when the event bits + unblock the task. */ + if( xClearOnExit != pdFALSE ) + { + uxControlBits |= eventCLEAR_EVENTS_ON_EXIT_BIT; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + if( xWaitForAllBits != pdFALSE ) + { + uxControlBits |= eventWAIT_FOR_ALL_BITS; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Store the bits that the calling task is waiting for in the + task's event list item so the kernel knows when a match is + found. Then enter the blocked state. */ + vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | uxControlBits ), xTicksToWait ); + + /* This is obsolete as it will get set after the task unblocks, but + some compilers mistakenly generate a warning about the variable + being returned without being set if it is not done. */ + uxReturn = 0; + + traceEVENT_GROUP_WAIT_BITS_BLOCK( xEventGroup, uxBitsToWaitFor ); + } + } + xAlreadyYielded = xTaskResumeAll(); + + if( xTicksToWait != ( TickType_t ) 0 ) + { + if( xAlreadyYielded == pdFALSE ) + { + portYIELD_WITHIN_API(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* The task blocked to wait for its required bits to be set - at this + point either the required bits were set or the block time expired. If + the required bits were set they will have been stored in the task's + event list item, and they should now be retrieved then cleared. */ + uxReturn = uxTaskResetEventItemValue(); + + if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 ) + { + taskENTER_CRITICAL(); + { + /* The task timed out, just return the current event bit value. */ + uxReturn = pxEventBits->uxEventBits; + + /* It is possible that the event bits were updated between this + task leaving the Blocked state and running again. */ + if( prvTestWaitCondition( uxReturn, uxBitsToWaitFor, xWaitForAllBits ) != pdFALSE ) + { + if( xClearOnExit != pdFALSE ) + { + pxEventBits->uxEventBits &= ~uxBitsToWaitFor; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); + + /* Prevent compiler warnings when trace macros are not used. */ + xTimeoutOccurred = pdFALSE; + } + else + { + /* The task unblocked because the bits were set. */ + } + + /* The task blocked so control bits may have been set. */ + uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES; + } + traceEVENT_GROUP_WAIT_BITS_END( xEventGroup, uxBitsToWaitFor, xTimeoutOccurred ); + + return uxReturn; +} +/*-----------------------------------------------------------*/ + +EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ) +{ +EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup; +EventBits_t uxReturn; + + /* Check the user is not attempting to clear the bits used by the kernel + itself. */ + configASSERT( xEventGroup ); + configASSERT( ( uxBitsToClear & eventEVENT_BITS_CONTROL_BYTES ) == 0 ); + + taskENTER_CRITICAL(); + { + traceEVENT_GROUP_CLEAR_BITS( xEventGroup, uxBitsToClear ); + + /* The value returned is the event group value prior to the bits being + cleared. */ + uxReturn = pxEventBits->uxEventBits; + + /* Clear the bits. */ + pxEventBits->uxEventBits &= ~uxBitsToClear; + } + taskEXIT_CRITICAL(); + + return uxReturn; +} +/*-----------------------------------------------------------*/ + +#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) + + BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ) + { + BaseType_t xReturn; + + traceEVENT_GROUP_CLEAR_BITS_FROM_ISR( xEventGroup, uxBitsToClear ); + xReturn = xTimerPendFunctionCallFromISR( vEventGroupClearBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToClear, NULL ); + + return xReturn; + } + +#endif +/*-----------------------------------------------------------*/ + +EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup ) +{ +UBaseType_t uxSavedInterruptStatus; +EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup; +EventBits_t uxReturn; + + uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + { + uxReturn = pxEventBits->uxEventBits; + } + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + + return uxReturn; +} +/*-----------------------------------------------------------*/ + +EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet ) +{ +ListItem_t *pxListItem, *pxNext; +ListItem_t const *pxListEnd; +List_t *pxList; +EventBits_t uxBitsToClear = 0, uxBitsWaitedFor, uxControlBits; +EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup; +BaseType_t xMatchFound = pdFALSE; + + /* Check the user is not attempting to set the bits used by the kernel + itself. */ + configASSERT( xEventGroup ); + configASSERT( ( uxBitsToSet & eventEVENT_BITS_CONTROL_BYTES ) == 0 ); + + pxList = &( pxEventBits->xTasksWaitingForBits ); + pxListEnd = listGET_END_MARKER( pxList ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ + vTaskSuspendAll(); + { + traceEVENT_GROUP_SET_BITS( xEventGroup, uxBitsToSet ); + + pxListItem = listGET_HEAD_ENTRY( pxList ); + + /* Set the bits. */ + pxEventBits->uxEventBits |= uxBitsToSet; + + /* See if the new bit value should unblock any tasks. */ + while( pxListItem != pxListEnd ) + { + pxNext = listGET_NEXT( pxListItem ); + uxBitsWaitedFor = listGET_LIST_ITEM_VALUE( pxListItem ); + xMatchFound = pdFALSE; + + /* Split the bits waited for from the control bits. */ + uxControlBits = uxBitsWaitedFor & eventEVENT_BITS_CONTROL_BYTES; + uxBitsWaitedFor &= ~eventEVENT_BITS_CONTROL_BYTES; + + if( ( uxControlBits & eventWAIT_FOR_ALL_BITS ) == ( EventBits_t ) 0 ) + { + /* Just looking for single bit being set. */ + if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) != ( EventBits_t ) 0 ) + { + xMatchFound = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) == uxBitsWaitedFor ) + { + /* All bits are set. */ + xMatchFound = pdTRUE; + } + else + { + /* Need all bits to be set, but not all the bits were set. */ + } + + if( xMatchFound != pdFALSE ) + { + /* The bits match. Should the bits be cleared on exit? */ + if( ( uxControlBits & eventCLEAR_EVENTS_ON_EXIT_BIT ) != ( EventBits_t ) 0 ) + { + uxBitsToClear |= uxBitsWaitedFor; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Store the actual event flag value in the task's event list + item before removing the task from the event list. The + eventUNBLOCKED_DUE_TO_BIT_SET bit is set so the task knows + that is was unblocked due to its required bits matching, rather + than because it timed out. */ + ( void ) xTaskRemoveFromUnorderedEventList( pxListItem, pxEventBits->uxEventBits | eventUNBLOCKED_DUE_TO_BIT_SET ); + } + + /* Move onto the next list item. Note pxListItem->pxNext is not + used here as the list item may have been removed from the event list + and inserted into the ready/pending reading list. */ + pxListItem = pxNext; + } + + /* Clear any bits that matched when the eventCLEAR_EVENTS_ON_EXIT_BIT + bit was set in the control word. */ + pxEventBits->uxEventBits &= ~uxBitsToClear; + } + ( void ) xTaskResumeAll(); + + return pxEventBits->uxEventBits; +} +/*-----------------------------------------------------------*/ + +void vEventGroupDelete( EventGroupHandle_t xEventGroup ) +{ +EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup; +const List_t *pxTasksWaitingForBits = &( pxEventBits->xTasksWaitingForBits ); + + vTaskSuspendAll(); + { + traceEVENT_GROUP_DELETE( xEventGroup ); + + while( listCURRENT_LIST_LENGTH( pxTasksWaitingForBits ) > ( UBaseType_t ) 0 ) + { + /* Unblock the task, returning 0 as the event list is being deleted + and cannot therefore have any bits set. */ + configASSERT( pxTasksWaitingForBits->xListEnd.pxNext != ( ListItem_t * ) &( pxTasksWaitingForBits->xListEnd ) ); + ( void ) xTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET ); + } + + #if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) ) + { + /* The event group can only have been allocated dynamically - free + it again. */ + vPortFree( pxEventBits ); + } + #elif( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) + { + /* The event group could have been allocated statically or + dynamically, so check before attempting to free the memory. */ + if( pxEventBits->ucStaticallyAllocated == ( uint8_t ) pdFALSE ) + { + vPortFree( pxEventBits ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ + } + ( void ) xTaskResumeAll(); +} +/*-----------------------------------------------------------*/ + +/* For internal use only - execute a 'set bits' command that was pended from +an interrupt. */ +void vEventGroupSetBitsCallback( void *pvEventGroup, const uint32_t ulBitsToSet ) +{ + ( void ) xEventGroupSetBits( pvEventGroup, ( EventBits_t ) ulBitsToSet ); +} +/*-----------------------------------------------------------*/ + +/* For internal use only - execute a 'clear bits' command that was pended from +an interrupt. */ +void vEventGroupClearBitsCallback( void *pvEventGroup, const uint32_t ulBitsToClear ) +{ + ( void ) xEventGroupClearBits( pvEventGroup, ( EventBits_t ) ulBitsToClear ); +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, const EventBits_t uxBitsToWaitFor, const BaseType_t xWaitForAllBits ) +{ +BaseType_t xWaitConditionMet = pdFALSE; + + if( xWaitForAllBits == pdFALSE ) + { + /* Task only has to wait for one bit within uxBitsToWaitFor to be + set. Is one already set? */ + if( ( uxCurrentEventBits & uxBitsToWaitFor ) != ( EventBits_t ) 0 ) + { + xWaitConditionMet = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + /* Task has to wait for all the bits in uxBitsToWaitFor to be set. + Are they set already? */ + if( ( uxCurrentEventBits & uxBitsToWaitFor ) == uxBitsToWaitFor ) + { + xWaitConditionMet = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + + return xWaitConditionMet; +} +/*-----------------------------------------------------------*/ + +#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) + + BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken ) + { + BaseType_t xReturn; + + traceEVENT_GROUP_SET_BITS_FROM_ISR( xEventGroup, uxBitsToSet ); + xReturn = xTimerPendFunctionCallFromISR( vEventGroupSetBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToSet, pxHigherPriorityTaskWoken ); + + return xReturn; + } + +#endif +/*-----------------------------------------------------------*/ + +#if (configUSE_TRACE_FACILITY == 1) + + UBaseType_t uxEventGroupGetNumber( void* xEventGroup ) + { + UBaseType_t xReturn; + EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup; + + if( xEventGroup == NULL ) + { + xReturn = 0; + } + else + { + xReturn = pxEventBits->uxEventGroupNumber; + } + + return xReturn; + } + +#endif + diff --git a/STM32F1/libraries/FreeRTOS900/utility/event_groups.h b/STM32F1/libraries/FreeRTOS900/utility/event_groups.h new file mode 100644 index 0000000..7331c91 --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/utility/event_groups.h @@ -0,0 +1,797 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef EVENT_GROUPS_H +#define EVENT_GROUPS_H + +#ifndef INC_FREERTOS_H + #error "include FreeRTOS.h" must appear in source files before "include event_groups.h" +#endif + +/* FreeRTOS includes. */ +#include "timers.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * An event group is a collection of bits to which an application can assign a + * meaning. For example, an application may create an event group to convey + * the status of various CAN bus related events in which bit 0 might mean "A CAN + * message has been received and is ready for processing", bit 1 might mean "The + * application has queued a message that is ready for sending onto the CAN + * network", and bit 2 might mean "It is time to send a SYNC message onto the + * CAN network" etc. A task can then test the bit values to see which events + * are active, and optionally enter the Blocked state to wait for a specified + * bit or a group of specified bits to be active. To continue the CAN bus + * example, a CAN controlling task can enter the Blocked state (and therefore + * not consume any processing time) until either bit 0, bit 1 or bit 2 are + * active, at which time the bit that was actually active would inform the task + * which action it had to take (process a received message, send a message, or + * send a SYNC). + * + * The event groups implementation contains intelligence to avoid race + * conditions that would otherwise occur were an application to use a simple + * variable for the same purpose. This is particularly important with respect + * to when a bit within an event group is to be cleared, and when bits have to + * be set and then tested atomically - as is the case where event groups are + * used to create a synchronisation point between multiple tasks (a + * 'rendezvous'). + * + * \defgroup EventGroup + */ + + + +/** + * event_groups.h + * + * Type by which event groups are referenced. For example, a call to + * xEventGroupCreate() returns an EventGroupHandle_t variable that can then + * be used as a parameter to other event group functions. + * + * \defgroup EventGroupHandle_t EventGroupHandle_t + * \ingroup EventGroup + */ +typedef void * EventGroupHandle_t; + +/* + * The type that holds event bits always matches TickType_t - therefore the + * number of bits it holds is set by configUSE_16_BIT_TICKS (16 bits if set to 1, + * 32 bits if set to 0. + * + * \defgroup EventBits_t EventBits_t + * \ingroup EventGroup + */ +typedef TickType_t EventBits_t; + +/** + * event_groups.h + *
+ EventGroupHandle_t xEventGroupCreate( void );
+ 
+ * + * Create a new event group. + * + * Internally, within the FreeRTOS implementation, event groups use a [small] + * block of memory, in which the event group's structure is stored. If an event + * groups is created using xEventGropuCreate() then the required memory is + * automatically dynamically allocated inside the xEventGroupCreate() function. + * (see http://www.freertos.org/a00111.html). If an event group is created + * using xEventGropuCreateStatic() then the application writer must instead + * provide the memory that will get used by the event group. + * xEventGroupCreateStatic() therefore allows an event group to be created + * without using any dynamic memory allocation. + * + * Although event groups are not related to ticks, for internal implementation + * reasons the number of bits available for use in an event group is dependent + * on the configUSE_16_BIT_TICKS setting in FreeRTOSConfig.h. If + * configUSE_16_BIT_TICKS is 1 then each event group contains 8 usable bits (bit + * 0 to bit 7). If configUSE_16_BIT_TICKS is set to 0 then each event group has + * 24 usable bits (bit 0 to bit 23). The EventBits_t type is used to store + * event bits within an event group. + * + * @return If the event group was created then a handle to the event group is + * returned. If there was insufficient FreeRTOS heap available to create the + * event group then NULL is returned. See http://www.freertos.org/a00111.html + * + * Example usage: +
+	// Declare a variable to hold the created event group.
+	EventGroupHandle_t xCreatedEventGroup;
+
+	// Attempt to create the event group.
+	xCreatedEventGroup = xEventGroupCreate();
+
+	// Was the event group created successfully?
+	if( xCreatedEventGroup == NULL )
+	{
+		// The event group was not created because there was insufficient
+		// FreeRTOS heap available.
+	}
+	else
+	{
+		// The event group was created.
+	}
+   
+ * \defgroup xEventGroupCreate xEventGroupCreate + * \ingroup EventGroup + */ +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + EventGroupHandle_t xEventGroupCreate( void ) PRIVILEGED_FUNCTION; +#endif + +/** + * event_groups.h + *
+ EventGroupHandle_t xEventGroupCreateStatic( EventGroupHandle_t * pxEventGroupBuffer );
+ 
+ * + * Create a new event group. + * + * Internally, within the FreeRTOS implementation, event groups use a [small] + * block of memory, in which the event group's structure is stored. If an event + * groups is created using xEventGropuCreate() then the required memory is + * automatically dynamically allocated inside the xEventGroupCreate() function. + * (see http://www.freertos.org/a00111.html). If an event group is created + * using xEventGropuCreateStatic() then the application writer must instead + * provide the memory that will get used by the event group. + * xEventGroupCreateStatic() therefore allows an event group to be created + * without using any dynamic memory allocation. + * + * Although event groups are not related to ticks, for internal implementation + * reasons the number of bits available for use in an event group is dependent + * on the configUSE_16_BIT_TICKS setting in FreeRTOSConfig.h. If + * configUSE_16_BIT_TICKS is 1 then each event group contains 8 usable bits (bit + * 0 to bit 7). If configUSE_16_BIT_TICKS is set to 0 then each event group has + * 24 usable bits (bit 0 to bit 23). The EventBits_t type is used to store + * event bits within an event group. + * + * @param pxEventGroupBuffer pxEventGroupBuffer must point to a variable of type + * StaticEventGroup_t, which will be then be used to hold the event group's data + * structures, removing the need for the memory to be allocated dynamically. + * + * @return If the event group was created then a handle to the event group is + * returned. If pxEventGroupBuffer was NULL then NULL is returned. + * + * Example usage: +
+	// StaticEventGroup_t is a publicly accessible structure that has the same
+	// size and alignment requirements as the real event group structure.  It is
+	// provided as a mechanism for applications to know the size of the event
+	// group (which is dependent on the architecture and configuration file
+	// settings) without breaking the strict data hiding policy by exposing the
+	// real event group internals.  This StaticEventGroup_t variable is passed
+	// into the xSemaphoreCreateEventGroupStatic() function and is used to store
+	// the event group's data structures
+	StaticEventGroup_t xEventGroupBuffer;
+
+	// Create the event group without dynamically allocating any memory.
+	xEventGroup = xEventGroupCreateStatic( &xEventGroupBuffer );
+   
+ */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer ) PRIVILEGED_FUNCTION; +#endif + +/** + * event_groups.h + *
+	EventBits_t xEventGroupWaitBits( 	EventGroupHandle_t xEventGroup,
+										const EventBits_t uxBitsToWaitFor,
+										const BaseType_t xClearOnExit,
+										const BaseType_t xWaitForAllBits,
+										const TickType_t xTicksToWait );
+ 
+ * + * [Potentially] block to wait for one or more bits to be set within a + * previously created event group. + * + * This function cannot be called from an interrupt. + * + * @param xEventGroup The event group in which the bits are being tested. The + * event group must have previously been created using a call to + * xEventGroupCreate(). + * + * @param uxBitsToWaitFor A bitwise value that indicates the bit or bits to test + * inside the event group. For example, to wait for bit 0 and/or bit 2 set + * uxBitsToWaitFor to 0x05. To wait for bits 0 and/or bit 1 and/or bit 2 set + * uxBitsToWaitFor to 0x07. Etc. + * + * @param xClearOnExit If xClearOnExit is set to pdTRUE then any bits within + * uxBitsToWaitFor that are set within the event group will be cleared before + * xEventGroupWaitBits() returns if the wait condition was met (if the function + * returns for a reason other than a timeout). If xClearOnExit is set to + * pdFALSE then the bits set in the event group are not altered when the call to + * xEventGroupWaitBits() returns. + * + * @param xWaitForAllBits If xWaitForAllBits is set to pdTRUE then + * xEventGroupWaitBits() will return when either all the bits in uxBitsToWaitFor + * are set or the specified block time expires. If xWaitForAllBits is set to + * pdFALSE then xEventGroupWaitBits() will return when any one of the bits set + * in uxBitsToWaitFor is set or the specified block time expires. The block + * time is specified by the xTicksToWait parameter. + * + * @param xTicksToWait The maximum amount of time (specified in 'ticks') to wait + * for one/all (depending on the xWaitForAllBits value) of the bits specified by + * uxBitsToWaitFor to become set. + * + * @return The value of the event group at the time either the bits being waited + * for became set, or the block time expired. Test the return value to know + * which bits were set. If xEventGroupWaitBits() returned because its timeout + * expired then not all the bits being waited for will be set. If + * xEventGroupWaitBits() returned because the bits it was waiting for were set + * then the returned value is the event group value before any bits were + * automatically cleared in the case that xClearOnExit parameter was set to + * pdTRUE. + * + * Example usage: +
+   #define BIT_0	( 1 << 0 )
+   #define BIT_4	( 1 << 4 )
+
+   void aFunction( EventGroupHandle_t xEventGroup )
+   {
+   EventBits_t uxBits;
+   const TickType_t xTicksToWait = 100 / portTICK_PERIOD_MS;
+
+		// Wait a maximum of 100ms for either bit 0 or bit 4 to be set within
+		// the event group.  Clear the bits before exiting.
+		uxBits = xEventGroupWaitBits(
+					xEventGroup,	// The event group being tested.
+					BIT_0 | BIT_4,	// The bits within the event group to wait for.
+					pdTRUE,			// BIT_0 and BIT_4 should be cleared before returning.
+					pdFALSE,		// Don't wait for both bits, either bit will do.
+					xTicksToWait );	// Wait a maximum of 100ms for either bit to be set.
+
+		if( ( uxBits & ( BIT_0 | BIT_4 ) ) == ( BIT_0 | BIT_4 ) )
+		{
+			// xEventGroupWaitBits() returned because both bits were set.
+		}
+		else if( ( uxBits & BIT_0 ) != 0 )
+		{
+			// xEventGroupWaitBits() returned because just BIT_0 was set.
+		}
+		else if( ( uxBits & BIT_4 ) != 0 )
+		{
+			// xEventGroupWaitBits() returned because just BIT_4 was set.
+		}
+		else
+		{
+			// xEventGroupWaitBits() returned because xTicksToWait ticks passed
+			// without either BIT_0 or BIT_4 becoming set.
+		}
+   }
+   
+ * \defgroup xEventGroupWaitBits xEventGroupWaitBits + * \ingroup EventGroup + */ +EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; + +/** + * event_groups.h + *
+	EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear );
+ 
+ * + * Clear bits within an event group. This function cannot be called from an + * interrupt. + * + * @param xEventGroup The event group in which the bits are to be cleared. + * + * @param uxBitsToClear A bitwise value that indicates the bit or bits to clear + * in the event group. For example, to clear bit 3 only, set uxBitsToClear to + * 0x08. To clear bit 3 and bit 0 set uxBitsToClear to 0x09. + * + * @return The value of the event group before the specified bits were cleared. + * + * Example usage: +
+   #define BIT_0	( 1 << 0 )
+   #define BIT_4	( 1 << 4 )
+
+   void aFunction( EventGroupHandle_t xEventGroup )
+   {
+   EventBits_t uxBits;
+
+		// Clear bit 0 and bit 4 in xEventGroup.
+		uxBits = xEventGroupClearBits(
+								xEventGroup,	// The event group being updated.
+								BIT_0 | BIT_4 );// The bits being cleared.
+
+		if( ( uxBits & ( BIT_0 | BIT_4 ) ) == ( BIT_0 | BIT_4 ) )
+		{
+			// Both bit 0 and bit 4 were set before xEventGroupClearBits() was
+			// called.  Both will now be clear (not set).
+		}
+		else if( ( uxBits & BIT_0 ) != 0 )
+		{
+			// Bit 0 was set before xEventGroupClearBits() was called.  It will
+			// now be clear.
+		}
+		else if( ( uxBits & BIT_4 ) != 0 )
+		{
+			// Bit 4 was set before xEventGroupClearBits() was called.  It will
+			// now be clear.
+		}
+		else
+		{
+			// Neither bit 0 nor bit 4 were set in the first place.
+		}
+   }
+   
+ * \defgroup xEventGroupClearBits xEventGroupClearBits + * \ingroup EventGroup + */ +EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ) PRIVILEGED_FUNCTION; + +/** + * event_groups.h + *
+	BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet );
+ 
+ * + * A version of xEventGroupClearBits() that can be called from an interrupt. + * + * Setting bits in an event group is not a deterministic operation because there + * are an unknown number of tasks that may be waiting for the bit or bits being + * set. FreeRTOS does not allow nondeterministic operations to be performed + * while interrupts are disabled, so protects event groups that are accessed + * from tasks by suspending the scheduler rather than disabling interrupts. As + * a result event groups cannot be accessed directly from an interrupt service + * routine. Therefore xEventGroupClearBitsFromISR() sends a message to the + * timer task to have the clear operation performed in the context of the timer + * task. + * + * @param xEventGroup The event group in which the bits are to be cleared. + * + * @param uxBitsToClear A bitwise value that indicates the bit or bits to clear. + * For example, to clear bit 3 only, set uxBitsToClear to 0x08. To clear bit 3 + * and bit 0 set uxBitsToClear to 0x09. + * + * @return If the request to execute the function was posted successfully then + * pdPASS is returned, otherwise pdFALSE is returned. pdFALSE will be returned + * if the timer service queue was full. + * + * Example usage: +
+   #define BIT_0	( 1 << 0 )
+   #define BIT_4	( 1 << 4 )
+
+   // An event group which it is assumed has already been created by a call to
+   // xEventGroupCreate().
+   EventGroupHandle_t xEventGroup;
+
+   void anInterruptHandler( void )
+   {
+		// Clear bit 0 and bit 4 in xEventGroup.
+		xResult = xEventGroupClearBitsFromISR(
+							xEventGroup,	 // The event group being updated.
+							BIT_0 | BIT_4 ); // The bits being set.
+
+		if( xResult == pdPASS )
+		{
+			// The message was posted successfully.
+		}
+  }
+   
+ * \defgroup xEventGroupClearBitsFromISR xEventGroupClearBitsFromISR + * \ingroup EventGroup + */ +#if( configUSE_TRACE_FACILITY == 1 ) + BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet ) PRIVILEGED_FUNCTION; +#else + #define xEventGroupClearBitsFromISR( xEventGroup, uxBitsToClear ) xTimerPendFunctionCallFromISR( vEventGroupClearBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToClear, NULL ) +#endif + +/** + * event_groups.h + *
+	EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet );
+ 
+ * + * Set bits within an event group. + * This function cannot be called from an interrupt. xEventGroupSetBitsFromISR() + * is a version that can be called from an interrupt. + * + * Setting bits in an event group will automatically unblock tasks that are + * blocked waiting for the bits. + * + * @param xEventGroup The event group in which the bits are to be set. + * + * @param uxBitsToSet A bitwise value that indicates the bit or bits to set. + * For example, to set bit 3 only, set uxBitsToSet to 0x08. To set bit 3 + * and bit 0 set uxBitsToSet to 0x09. + * + * @return The value of the event group at the time the call to + * xEventGroupSetBits() returns. There are two reasons why the returned value + * might have the bits specified by the uxBitsToSet parameter cleared. First, + * if setting a bit results in a task that was waiting for the bit leaving the + * blocked state then it is possible the bit will be cleared automatically + * (see the xClearBitOnExit parameter of xEventGroupWaitBits()). Second, any + * unblocked (or otherwise Ready state) task that has a priority above that of + * the task that called xEventGroupSetBits() will execute and may change the + * event group value before the call to xEventGroupSetBits() returns. + * + * Example usage: +
+   #define BIT_0	( 1 << 0 )
+   #define BIT_4	( 1 << 4 )
+
+   void aFunction( EventGroupHandle_t xEventGroup )
+   {
+   EventBits_t uxBits;
+
+		// Set bit 0 and bit 4 in xEventGroup.
+		uxBits = xEventGroupSetBits(
+							xEventGroup,	// The event group being updated.
+							BIT_0 | BIT_4 );// The bits being set.
+
+		if( ( uxBits & ( BIT_0 | BIT_4 ) ) == ( BIT_0 | BIT_4 ) )
+		{
+			// Both bit 0 and bit 4 remained set when the function returned.
+		}
+		else if( ( uxBits & BIT_0 ) != 0 )
+		{
+			// Bit 0 remained set when the function returned, but bit 4 was
+			// cleared.  It might be that bit 4 was cleared automatically as a
+			// task that was waiting for bit 4 was removed from the Blocked
+			// state.
+		}
+		else if( ( uxBits & BIT_4 ) != 0 )
+		{
+			// Bit 4 remained set when the function returned, but bit 0 was
+			// cleared.  It might be that bit 0 was cleared automatically as a
+			// task that was waiting for bit 0 was removed from the Blocked
+			// state.
+		}
+		else
+		{
+			// Neither bit 0 nor bit 4 remained set.  It might be that a task
+			// was waiting for both of the bits to be set, and the bits were
+			// cleared as the task left the Blocked state.
+		}
+   }
+   
+ * \defgroup xEventGroupSetBits xEventGroupSetBits + * \ingroup EventGroup + */ +EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet ) PRIVILEGED_FUNCTION; + +/** + * event_groups.h + *
+	BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken );
+ 
+ * + * A version of xEventGroupSetBits() that can be called from an interrupt. + * + * Setting bits in an event group is not a deterministic operation because there + * are an unknown number of tasks that may be waiting for the bit or bits being + * set. FreeRTOS does not allow nondeterministic operations to be performed in + * interrupts or from critical sections. Therefore xEventGroupSetBitsFromISR() + * sends a message to the timer task to have the set operation performed in the + * context of the timer task - where a scheduler lock is used in place of a + * critical section. + * + * @param xEventGroup The event group in which the bits are to be set. + * + * @param uxBitsToSet A bitwise value that indicates the bit or bits to set. + * For example, to set bit 3 only, set uxBitsToSet to 0x08. To set bit 3 + * and bit 0 set uxBitsToSet to 0x09. + * + * @param pxHigherPriorityTaskWoken As mentioned above, calling this function + * will result in a message being sent to the timer daemon task. If the + * priority of the timer daemon task is higher than the priority of the + * currently running task (the task the interrupt interrupted) then + * *pxHigherPriorityTaskWoken will be set to pdTRUE by + * xEventGroupSetBitsFromISR(), indicating that a context switch should be + * requested before the interrupt exits. For that reason + * *pxHigherPriorityTaskWoken must be initialised to pdFALSE. See the + * example code below. + * + * @return If the request to execute the function was posted successfully then + * pdPASS is returned, otherwise pdFALSE is returned. pdFALSE will be returned + * if the timer service queue was full. + * + * Example usage: +
+   #define BIT_0	( 1 << 0 )
+   #define BIT_4	( 1 << 4 )
+
+   // An event group which it is assumed has already been created by a call to
+   // xEventGroupCreate().
+   EventGroupHandle_t xEventGroup;
+
+   void anInterruptHandler( void )
+   {
+   BaseType_t xHigherPriorityTaskWoken, xResult;
+
+		// xHigherPriorityTaskWoken must be initialised to pdFALSE.
+		xHigherPriorityTaskWoken = pdFALSE;
+
+		// Set bit 0 and bit 4 in xEventGroup.
+		xResult = xEventGroupSetBitsFromISR(
+							xEventGroup,	// The event group being updated.
+							BIT_0 | BIT_4   // The bits being set.
+							&xHigherPriorityTaskWoken );
+
+		// Was the message posted successfully?
+		if( xResult == pdPASS )
+		{
+			// If xHigherPriorityTaskWoken is now set to pdTRUE then a context
+			// switch should be requested.  The macro used is port specific and
+			// will be either portYIELD_FROM_ISR() or portEND_SWITCHING_ISR() -
+			// refer to the documentation page for the port being used.
+			portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
+		}
+  }
+   
+ * \defgroup xEventGroupSetBitsFromISR xEventGroupSetBitsFromISR + * \ingroup EventGroup + */ +#if( configUSE_TRACE_FACILITY == 1 ) + BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION; +#else + #define xEventGroupSetBitsFromISR( xEventGroup, uxBitsToSet, pxHigherPriorityTaskWoken ) xTimerPendFunctionCallFromISR( vEventGroupSetBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToSet, pxHigherPriorityTaskWoken ) +#endif + +/** + * event_groups.h + *
+	EventBits_t xEventGroupSync(	EventGroupHandle_t xEventGroup,
+									const EventBits_t uxBitsToSet,
+									const EventBits_t uxBitsToWaitFor,
+									TickType_t xTicksToWait );
+ 
+ * + * Atomically set bits within an event group, then wait for a combination of + * bits to be set within the same event group. This functionality is typically + * used to synchronise multiple tasks, where each task has to wait for the other + * tasks to reach a synchronisation point before proceeding. + * + * This function cannot be used from an interrupt. + * + * The function will return before its block time expires if the bits specified + * by the uxBitsToWait parameter are set, or become set within that time. In + * this case all the bits specified by uxBitsToWait will be automatically + * cleared before the function returns. + * + * @param xEventGroup The event group in which the bits are being tested. The + * event group must have previously been created using a call to + * xEventGroupCreate(). + * + * @param uxBitsToSet The bits to set in the event group before determining + * if, and possibly waiting for, all the bits specified by the uxBitsToWait + * parameter are set. + * + * @param uxBitsToWaitFor A bitwise value that indicates the bit or bits to test + * inside the event group. For example, to wait for bit 0 and bit 2 set + * uxBitsToWaitFor to 0x05. To wait for bits 0 and bit 1 and bit 2 set + * uxBitsToWaitFor to 0x07. Etc. + * + * @param xTicksToWait The maximum amount of time (specified in 'ticks') to wait + * for all of the bits specified by uxBitsToWaitFor to become set. + * + * @return The value of the event group at the time either the bits being waited + * for became set, or the block time expired. Test the return value to know + * which bits were set. If xEventGroupSync() returned because its timeout + * expired then not all the bits being waited for will be set. If + * xEventGroupSync() returned because all the bits it was waiting for were + * set then the returned value is the event group value before any bits were + * automatically cleared. + * + * Example usage: +
+ // Bits used by the three tasks.
+ #define TASK_0_BIT		( 1 << 0 )
+ #define TASK_1_BIT		( 1 << 1 )
+ #define TASK_2_BIT		( 1 << 2 )
+
+ #define ALL_SYNC_BITS ( TASK_0_BIT | TASK_1_BIT | TASK_2_BIT )
+
+ // Use an event group to synchronise three tasks.  It is assumed this event
+ // group has already been created elsewhere.
+ EventGroupHandle_t xEventBits;
+
+ void vTask0( void *pvParameters )
+ {
+ EventBits_t uxReturn;
+ TickType_t xTicksToWait = 100 / portTICK_PERIOD_MS;
+
+	 for( ;; )
+	 {
+		// Perform task functionality here.
+
+		// Set bit 0 in the event flag to note this task has reached the
+		// sync point.  The other two tasks will set the other two bits defined
+		// by ALL_SYNC_BITS.  All three tasks have reached the synchronisation
+		// point when all the ALL_SYNC_BITS are set.  Wait a maximum of 100ms
+		// for this to happen.
+		uxReturn = xEventGroupSync( xEventBits, TASK_0_BIT, ALL_SYNC_BITS, xTicksToWait );
+
+		if( ( uxReturn & ALL_SYNC_BITS ) == ALL_SYNC_BITS )
+		{
+			// All three tasks reached the synchronisation point before the call
+			// to xEventGroupSync() timed out.
+		}
+	}
+ }
+
+ void vTask1( void *pvParameters )
+ {
+	 for( ;; )
+	 {
+		// Perform task functionality here.
+
+		// Set bit 1 in the event flag to note this task has reached the
+		// synchronisation point.  The other two tasks will set the other two
+		// bits defined by ALL_SYNC_BITS.  All three tasks have reached the
+		// synchronisation point when all the ALL_SYNC_BITS are set.  Wait
+		// indefinitely for this to happen.
+		xEventGroupSync( xEventBits, TASK_1_BIT, ALL_SYNC_BITS, portMAX_DELAY );
+
+		// xEventGroupSync() was called with an indefinite block time, so
+		// this task will only reach here if the syncrhonisation was made by all
+		// three tasks, so there is no need to test the return value.
+	 }
+ }
+
+ void vTask2( void *pvParameters )
+ {
+	 for( ;; )
+	 {
+		// Perform task functionality here.
+
+		// Set bit 2 in the event flag to note this task has reached the
+		// synchronisation point.  The other two tasks will set the other two
+		// bits defined by ALL_SYNC_BITS.  All three tasks have reached the
+		// synchronisation point when all the ALL_SYNC_BITS are set.  Wait
+		// indefinitely for this to happen.
+		xEventGroupSync( xEventBits, TASK_2_BIT, ALL_SYNC_BITS, portMAX_DELAY );
+
+		// xEventGroupSync() was called with an indefinite block time, so
+		// this task will only reach here if the syncrhonisation was made by all
+		// three tasks, so there is no need to test the return value.
+	}
+ }
+
+ 
+ * \defgroup xEventGroupSync xEventGroupSync + * \ingroup EventGroup + */ +EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; + + +/** + * event_groups.h + *
+	EventBits_t xEventGroupGetBits( EventGroupHandle_t xEventGroup );
+ 
+ * + * Returns the current value of the bits in an event group. This function + * cannot be used from an interrupt. + * + * @param xEventGroup The event group being queried. + * + * @return The event group bits at the time xEventGroupGetBits() was called. + * + * \defgroup xEventGroupGetBits xEventGroupGetBits + * \ingroup EventGroup + */ +#define xEventGroupGetBits( xEventGroup ) xEventGroupClearBits( xEventGroup, 0 ) + +/** + * event_groups.h + *
+	EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup );
+ 
+ * + * A version of xEventGroupGetBits() that can be called from an ISR. + * + * @param xEventGroup The event group being queried. + * + * @return The event group bits at the time xEventGroupGetBitsFromISR() was called. + * + * \defgroup xEventGroupGetBitsFromISR xEventGroupGetBitsFromISR + * \ingroup EventGroup + */ +EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup ) PRIVILEGED_FUNCTION; + +/** + * event_groups.h + *
+	void xEventGroupDelete( EventGroupHandle_t xEventGroup );
+ 
+ * + * Delete an event group that was previously created by a call to + * xEventGroupCreate(). Tasks that are blocked on the event group will be + * unblocked and obtain 0 as the event group's value. + * + * @param xEventGroup The event group being deleted. + */ +void vEventGroupDelete( EventGroupHandle_t xEventGroup ) PRIVILEGED_FUNCTION; + +/* For internal use only. */ +void vEventGroupSetBitsCallback( void *pvEventGroup, const uint32_t ulBitsToSet ) PRIVILEGED_FUNCTION; +void vEventGroupClearBitsCallback( void *pvEventGroup, const uint32_t ulBitsToClear ) PRIVILEGED_FUNCTION; + + +#if (configUSE_TRACE_FACILITY == 1) + UBaseType_t uxEventGroupGetNumber( void* xEventGroup ) PRIVILEGED_FUNCTION; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT_GROUPS_H */ + + diff --git a/STM32F1/libraries/FreeRTOS900/utility/heap_1.c b/STM32F1/libraries/FreeRTOS900/utility/heap_1.c new file mode 100644 index 0000000..178ff7c --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/utility/heap_1.c @@ -0,0 +1,174 @@ +/* + FreeRTOS V8.2.1 - Copyright (C) 2015 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + + +/* + * The simplest possible implementation of pvPortMalloc(). Note that this + * implementation does NOT allow allocated memory to be freed again. + * + * See heap_2.c, heap_3.c and heap_4.c for alternative implementations, and the + * memory management pages of http://www.FreeRTOS.org for more information. + */ +#include + +/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining +all the API functions to use the MPU wrappers. That should only be done when +task.h is included from an application file. */ +#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +#include "FreeRTOS.h" +#include "task.h" + +#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +/* A few bytes might be lost to byte aligning the heap start address. */ +#define configADJUSTED_HEAP_SIZE ( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT ) + +/* Allocate the memory for the heap. */ +static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ]; +static size_t xNextFreeByte = ( size_t ) 0; + +/*-----------------------------------------------------------*/ + +void *pvPortMalloc( size_t xWantedSize ) +{ +void *pvReturn = NULL; +static uint8_t *pucAlignedHeap = NULL; + + /* Ensure that blocks are always aligned to the required number of bytes. */ + #if portBYTE_ALIGNMENT != 1 + if( xWantedSize & portBYTE_ALIGNMENT_MASK ) + { + /* Byte alignment required. */ + xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ); + } + #endif + + vTaskSuspendAll(); + { + if( pucAlignedHeap == NULL ) + { + /* Ensure the heap starts on a correctly aligned boundary. */ + pucAlignedHeap = ( uint8_t * ) ( ( ( portPOINTER_SIZE_TYPE ) &ucHeap[ portBYTE_ALIGNMENT ] ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) ); + } + + /* Check there is enough room left for the allocation. */ + if( ( ( xNextFreeByte + xWantedSize ) < configADJUSTED_HEAP_SIZE ) && + ( ( xNextFreeByte + xWantedSize ) > xNextFreeByte ) )/* Check for overflow. */ + { + /* Return the next free byte then increment the index past this + block. */ + pvReturn = pucAlignedHeap + xNextFreeByte; + xNextFreeByte += xWantedSize; + } + + traceMALLOC( pvReturn, xWantedSize ); + } + ( void ) xTaskResumeAll(); + + #if( configUSE_MALLOC_FAILED_HOOK == 1 ) + { + if( pvReturn == NULL ) + { + extern void vApplicationMallocFailedHook( void ); + vApplicationMallocFailedHook(); + } + } + #endif + + return pvReturn; +} +/*-----------------------------------------------------------*/ + +void vPortFree( void *pv ) +{ + /* Memory cannot be freed using this scheme. See heap_2.c, heap_3.c and + heap_4.c for alternative implementations, and the memory management pages of + http://www.FreeRTOS.org for more information. */ + ( void ) pv; + + /* Force an assert as it is invalid to call this function. */ + configASSERT( pv == NULL ); +} +/*-----------------------------------------------------------*/ + +void vPortInitialiseBlocks( void ) +{ + /* Only required when static memory is not cleared. */ + xNextFreeByte = ( size_t ) 0; +} +/*-----------------------------------------------------------*/ + +size_t xPortGetFreeHeapSize( void ) +{ + return ( configADJUSTED_HEAP_SIZE - xNextFreeByte ); +} + + + diff --git a/STM32F1/libraries/FreeRTOS900/utility/list.c b/STM32F1/libraries/FreeRTOS900/utility/list.c new file mode 100644 index 0000000..5e207c1 --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/utility/list.c @@ -0,0 +1,240 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + + +#include +#include "FreeRTOS.h" +#include "list.h" + +/*----------------------------------------------------------- + * PUBLIC LIST API documented in list.h + *----------------------------------------------------------*/ + +void vListInitialise( List_t * const pxList ) +{ + /* The list structure contains a list item which is used to mark the + end of the list. To initialise the list the list end is inserted + as the only list entry. */ + pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ + + /* The list end value is the highest possible value in the list to + ensure it remains at the end of the list. */ + pxList->xListEnd.xItemValue = portMAX_DELAY; + + /* The list end next and previous pointers point to itself so we know + when the list is empty. */ + pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ + pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );/*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ + + pxList->uxNumberOfItems = ( UBaseType_t ) 0U; + + /* Write known values into the list if + configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ + listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList ); + listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList ); +} +/*-----------------------------------------------------------*/ + +void vListInitialiseItem( ListItem_t * const pxItem ) +{ + /* Make sure the list item is not recorded as being on a list. */ + pxItem->pvContainer = NULL; + + /* Write known values into the list item if + configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ + listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ); + listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ); +} +/*-----------------------------------------------------------*/ + +void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem ) +{ +ListItem_t * const pxIndex = pxList->pxIndex; + + /* Only effective when configASSERT() is also defined, these tests may catch + the list data structures being overwritten in memory. They will not catch + data errors caused by incorrect configuration or use of FreeRTOS. */ + listTEST_LIST_INTEGRITY( pxList ); + listTEST_LIST_ITEM_INTEGRITY( pxNewListItem ); + + /* Insert a new list item into pxList, but rather than sort the list, + makes the new list item the last item to be removed by a call to + listGET_OWNER_OF_NEXT_ENTRY(). */ + pxNewListItem->pxNext = pxIndex; + pxNewListItem->pxPrevious = pxIndex->pxPrevious; + + /* Only used during decision coverage testing. */ + mtCOVERAGE_TEST_DELAY(); + + pxIndex->pxPrevious->pxNext = pxNewListItem; + pxIndex->pxPrevious = pxNewListItem; + + /* Remember which list the item is in. */ + pxNewListItem->pvContainer = ( void * ) pxList; + + ( pxList->uxNumberOfItems )++; +} +/*-----------------------------------------------------------*/ + +void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem ) +{ +ListItem_t *pxIterator; +const TickType_t xValueOfInsertion = pxNewListItem->xItemValue; + + /* Only effective when configASSERT() is also defined, these tests may catch + the list data structures being overwritten in memory. They will not catch + data errors caused by incorrect configuration or use of FreeRTOS. */ + listTEST_LIST_INTEGRITY( pxList ); + listTEST_LIST_ITEM_INTEGRITY( pxNewListItem ); + + /* Insert the new list item into the list, sorted in xItemValue order. + + If the list already contains a list item with the same item value then the + new list item should be placed after it. This ensures that TCB's which are + stored in ready lists (all of which have the same xItemValue value) get a + share of the CPU. However, if the xItemValue is the same as the back marker + the iteration loop below will not end. Therefore the value is checked + first, and the algorithm slightly modified if necessary. */ + if( xValueOfInsertion == portMAX_DELAY ) + { + pxIterator = pxList->xListEnd.pxPrevious; + } + else + { + /* *** NOTE *********************************************************** + If you find your application is crashing here then likely causes are + listed below. In addition see http://www.freertos.org/FAQHelp.html for + more tips, and ensure configASSERT() is defined! + http://www.freertos.org/a00110.html#configASSERT + + 1) Stack overflow - + see http://www.freertos.org/Stacks-and-stack-overflow-checking.html + 2) Incorrect interrupt priority assignment, especially on Cortex-M + parts where numerically high priority values denote low actual + interrupt priorities, which can seem counter intuitive. See + http://www.freertos.org/RTOS-Cortex-M3-M4.html and the definition + of configMAX_SYSCALL_INTERRUPT_PRIORITY on + http://www.freertos.org/a00110.html + 3) Calling an API function from within a critical section or when + the scheduler is suspended, or calling an API function that does + not end in "FromISR" from an interrupt. + 4) Using a queue or semaphore before it has been initialised or + before the scheduler has been started (are interrupts firing + before vTaskStartScheduler() has been called?). + **********************************************************************/ + + for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ + { + /* There is nothing to do here, just iterating to the wanted + insertion position. */ + } + } + + pxNewListItem->pxNext = pxIterator->pxNext; + pxNewListItem->pxNext->pxPrevious = pxNewListItem; + pxNewListItem->pxPrevious = pxIterator; + pxIterator->pxNext = pxNewListItem; + + /* Remember which list the item is in. This allows fast removal of the + item later. */ + pxNewListItem->pvContainer = ( void * ) pxList; + + ( pxList->uxNumberOfItems )++; +} +/*-----------------------------------------------------------*/ + +UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove ) +{ +/* The list item knows which list it is in. Obtain the list from the list +item. */ +List_t * const pxList = ( List_t * ) pxItemToRemove->pvContainer; + + pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious; + pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext; + + /* Only used during decision coverage testing. */ + mtCOVERAGE_TEST_DELAY(); + + /* Make sure the index is left pointing to a valid item. */ + if( pxList->pxIndex == pxItemToRemove ) + { + pxList->pxIndex = pxItemToRemove->pxPrevious; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + pxItemToRemove->pvContainer = NULL; + ( pxList->uxNumberOfItems )--; + + return pxList->uxNumberOfItems; +} +/*-----------------------------------------------------------*/ + diff --git a/STM32F1/libraries/FreeRTOS900/utility/list.h b/STM32F1/libraries/FreeRTOS900/utility/list.h new file mode 100644 index 0000000..a080d27 --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/utility/list.h @@ -0,0 +1,453 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* + * This is the list implementation used by the scheduler. While it is tailored + * heavily for the schedulers needs, it is also available for use by + * application code. + * + * list_ts can only store pointers to list_item_ts. Each ListItem_t contains a + * numeric value (xItemValue). Most of the time the lists are sorted in + * descending item value order. + * + * Lists are created already containing one list item. The value of this + * item is the maximum possible that can be stored, it is therefore always at + * the end of the list and acts as a marker. The list member pxHead always + * points to this marker - even though it is at the tail of the list. This + * is because the tail contains a wrap back pointer to the true head of + * the list. + * + * In addition to it's value, each list item contains a pointer to the next + * item in the list (pxNext), a pointer to the list it is in (pxContainer) + * and a pointer to back to the object that contains it. These later two + * pointers are included for efficiency of list manipulation. There is + * effectively a two way link between the object containing the list item and + * the list item itself. + * + * + * \page ListIntroduction List Implementation + * \ingroup FreeRTOSIntro + */ + +#ifndef INC_FREERTOS_H + #error FreeRTOS.h must be included before list.h +#endif + +#ifndef LIST_H +#define LIST_H + +/* + * The list structure members are modified from within interrupts, and therefore + * by rights should be declared volatile. However, they are only modified in a + * functionally atomic way (within critical sections of with the scheduler + * suspended) and are either passed by reference into a function or indexed via + * a volatile variable. Therefore, in all use cases tested so far, the volatile + * qualifier can be omitted in order to provide a moderate performance + * improvement without adversely affecting functional behaviour. The assembly + * instructions generated by the IAR, ARM and GCC compilers when the respective + * compiler's options were set for maximum optimisation has been inspected and + * deemed to be as intended. That said, as compiler technology advances, and + * especially if aggressive cross module optimisation is used (a use case that + * has not been exercised to any great extend) then it is feasible that the + * volatile qualifier will be needed for correct optimisation. It is expected + * that a compiler removing essential code because, without the volatile + * qualifier on the list structure members and with aggressive cross module + * optimisation, the compiler deemed the code unnecessary will result in + * complete and obvious failure of the scheduler. If this is ever experienced + * then the volatile qualifier can be inserted in the relevant places within the + * list structures by simply defining configLIST_VOLATILE to volatile in + * FreeRTOSConfig.h (as per the example at the bottom of this comment block). + * If configLIST_VOLATILE is not defined then the preprocessor directives below + * will simply #define configLIST_VOLATILE away completely. + * + * To use volatile list structure members then add the following line to + * FreeRTOSConfig.h (without the quotes): + * "#define configLIST_VOLATILE volatile" + */ +#ifndef configLIST_VOLATILE + #define configLIST_VOLATILE +#endif /* configSUPPORT_CROSS_MODULE_OPTIMISATION */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Macros that can be used to place known values within the list structures, +then check that the known values do not get corrupted during the execution of +the application. These may catch the list data structures being overwritten in +memory. They will not catch data errors caused by incorrect configuration or +use of FreeRTOS.*/ +#if( configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES == 0 ) + /* Define the macros to do nothing. */ + #define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE + #define listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE + #define listFIRST_LIST_INTEGRITY_CHECK_VALUE + #define listSECOND_LIST_INTEGRITY_CHECK_VALUE + #define listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ) + #define listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ) + #define listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList ) + #define listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList ) + #define listTEST_LIST_ITEM_INTEGRITY( pxItem ) + #define listTEST_LIST_INTEGRITY( pxList ) +#else + /* Define macros that add new members into the list structures. */ + #define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE TickType_t xListItemIntegrityValue1; + #define listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE TickType_t xListItemIntegrityValue2; + #define listFIRST_LIST_INTEGRITY_CHECK_VALUE TickType_t xListIntegrityValue1; + #define listSECOND_LIST_INTEGRITY_CHECK_VALUE TickType_t xListIntegrityValue2; + + /* Define macros that set the new structure members to known values. */ + #define listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ) ( pxItem )->xListItemIntegrityValue1 = pdINTEGRITY_CHECK_VALUE + #define listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ) ( pxItem )->xListItemIntegrityValue2 = pdINTEGRITY_CHECK_VALUE + #define listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList ) ( pxList )->xListIntegrityValue1 = pdINTEGRITY_CHECK_VALUE + #define listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList ) ( pxList )->xListIntegrityValue2 = pdINTEGRITY_CHECK_VALUE + + /* Define macros that will assert if one of the structure members does not + contain its expected value. */ + #define listTEST_LIST_ITEM_INTEGRITY( pxItem ) configASSERT( ( ( pxItem )->xListItemIntegrityValue1 == pdINTEGRITY_CHECK_VALUE ) && ( ( pxItem )->xListItemIntegrityValue2 == pdINTEGRITY_CHECK_VALUE ) ) + #define listTEST_LIST_INTEGRITY( pxList ) configASSERT( ( ( pxList )->xListIntegrityValue1 == pdINTEGRITY_CHECK_VALUE ) && ( ( pxList )->xListIntegrityValue2 == pdINTEGRITY_CHECK_VALUE ) ) +#endif /* configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES */ + + +/* + * Definition of the only type of object that a list can contain. + */ +struct xLIST_ITEM +{ + listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ + configLIST_VOLATILE TickType_t xItemValue; /*< The value being listed. In most cases this is used to sort the list in descending order. */ + struct xLIST_ITEM * configLIST_VOLATILE pxNext; /*< Pointer to the next ListItem_t in the list. */ + struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /*< Pointer to the previous ListItem_t in the list. */ + void * pvOwner; /*< Pointer to the object (normally a TCB) that contains the list item. There is therefore a two way link between the object containing the list item and the list item itself. */ + void * configLIST_VOLATILE pvContainer; /*< Pointer to the list in which this list item is placed (if any). */ + listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ +}; +typedef struct xLIST_ITEM ListItem_t; /* For some reason lint wants this as two separate definitions. */ + +struct xMINI_LIST_ITEM +{ + listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ + configLIST_VOLATILE TickType_t xItemValue; + struct xLIST_ITEM * configLIST_VOLATILE pxNext; + struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; +}; +typedef struct xMINI_LIST_ITEM MiniListItem_t; + +/* + * Definition of the type of queue used by the scheduler. + */ +typedef struct xLIST +{ + listFIRST_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ + configLIST_VOLATILE UBaseType_t uxNumberOfItems; + ListItem_t * configLIST_VOLATILE pxIndex; /*< Used to walk through the list. Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY (). */ + MiniListItem_t xListEnd; /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */ + listSECOND_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ +} List_t; + +/* + * Access macro to set the owner of a list item. The owner of a list item + * is the object (usually a TCB) that contains the list item. + * + * \page listSET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER + * \ingroup LinkedList + */ +#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner ) ( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) ) + +/* + * Access macro to get the owner of a list item. The owner of a list item + * is the object (usually a TCB) that contains the list item. + * + * \page listSET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER + * \ingroup LinkedList + */ +#define listGET_LIST_ITEM_OWNER( pxListItem ) ( ( pxListItem )->pvOwner ) + +/* + * Access macro to set the value of the list item. In most cases the value is + * used to sort the list in descending order. + * + * \page listSET_LIST_ITEM_VALUE listSET_LIST_ITEM_VALUE + * \ingroup LinkedList + */ +#define listSET_LIST_ITEM_VALUE( pxListItem, xValue ) ( ( pxListItem )->xItemValue = ( xValue ) ) + +/* + * Access macro to retrieve the value of the list item. The value can + * represent anything - for example the priority of a task, or the time at + * which a task should be unblocked. + * + * \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE + * \ingroup LinkedList + */ +#define listGET_LIST_ITEM_VALUE( pxListItem ) ( ( pxListItem )->xItemValue ) + +/* + * Access macro to retrieve the value of the list item at the head of a given + * list. + * + * \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE + * \ingroup LinkedList + */ +#define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext->xItemValue ) + +/* + * Return the list item at the head of the list. + * + * \page listGET_HEAD_ENTRY listGET_HEAD_ENTRY + * \ingroup LinkedList + */ +#define listGET_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext ) + +/* + * Return the list item at the head of the list. + * + * \page listGET_NEXT listGET_NEXT + * \ingroup LinkedList + */ +#define listGET_NEXT( pxListItem ) ( ( pxListItem )->pxNext ) + +/* + * Return the list item that marks the end of the list + * + * \page listGET_END_MARKER listGET_END_MARKER + * \ingroup LinkedList + */ +#define listGET_END_MARKER( pxList ) ( ( ListItem_t const * ) ( &( ( pxList )->xListEnd ) ) ) + +/* + * Access macro to determine if a list contains any items. The macro will + * only have the value true if the list is empty. + * + * \page listLIST_IS_EMPTY listLIST_IS_EMPTY + * \ingroup LinkedList + */ +#define listLIST_IS_EMPTY( pxList ) ( ( BaseType_t ) ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) ) + +/* + * Access macro to return the number of items in the list. + */ +#define listCURRENT_LIST_LENGTH( pxList ) ( ( pxList )->uxNumberOfItems ) + +/* + * Access function to obtain the owner of the next entry in a list. + * + * The list member pxIndex is used to walk through a list. Calling + * listGET_OWNER_OF_NEXT_ENTRY increments pxIndex to the next item in the list + * and returns that entry's pxOwner parameter. Using multiple calls to this + * function it is therefore possible to move through every item contained in + * a list. + * + * The pxOwner parameter of a list item is a pointer to the object that owns + * the list item. In the scheduler this is normally a task control block. + * The pxOwner parameter effectively creates a two way link between the list + * item and its owner. + * + * @param pxTCB pxTCB is set to the address of the owner of the next list item. + * @param pxList The list from which the next item owner is to be returned. + * + * \page listGET_OWNER_OF_NEXT_ENTRY listGET_OWNER_OF_NEXT_ENTRY + * \ingroup LinkedList + */ +#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList ) \ +{ \ +List_t * const pxConstList = ( pxList ); \ + /* Increment the index to the next item and return the item, ensuring */ \ + /* we don't return the marker used at the end of the list. */ \ + ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \ + if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) ) \ + { \ + ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \ + } \ + ( pxTCB ) = ( pxConstList )->pxIndex->pvOwner; \ +} + + +/* + * Access function to obtain the owner of the first entry in a list. Lists + * are normally sorted in ascending item value order. + * + * This function returns the pxOwner member of the first item in the list. + * The pxOwner parameter of a list item is a pointer to the object that owns + * the list item. In the scheduler this is normally a task control block. + * The pxOwner parameter effectively creates a two way link between the list + * item and its owner. + * + * @param pxList The list from which the owner of the head item is to be + * returned. + * + * \page listGET_OWNER_OF_HEAD_ENTRY listGET_OWNER_OF_HEAD_ENTRY + * \ingroup LinkedList + */ +#define listGET_OWNER_OF_HEAD_ENTRY( pxList ) ( (&( ( pxList )->xListEnd ))->pxNext->pvOwner ) + +/* + * Check to see if a list item is within a list. The list item maintains a + * "container" pointer that points to the list it is in. All this macro does + * is check to see if the container and the list match. + * + * @param pxList The list we want to know if the list item is within. + * @param pxListItem The list item we want to know if is in the list. + * @return pdTRUE if the list item is in the list, otherwise pdFALSE. + */ +#define listIS_CONTAINED_WITHIN( pxList, pxListItem ) ( ( BaseType_t ) ( ( pxListItem )->pvContainer == ( void * ) ( pxList ) ) ) + +/* + * Return the list a list item is contained within (referenced from). + * + * @param pxListItem The list item being queried. + * @return A pointer to the List_t object that references the pxListItem + */ +#define listLIST_ITEM_CONTAINER( pxListItem ) ( ( pxListItem )->pvContainer ) + +/* + * This provides a crude means of knowing if a list has been initialised, as + * pxList->xListEnd.xItemValue is set to portMAX_DELAY by the vListInitialise() + * function. + */ +#define listLIST_IS_INITIALISED( pxList ) ( ( pxList )->xListEnd.xItemValue == portMAX_DELAY ) + +/* + * Must be called before a list is used! This initialises all the members + * of the list structure and inserts the xListEnd item into the list as a + * marker to the back of the list. + * + * @param pxList Pointer to the list being initialised. + * + * \page vListInitialise vListInitialise + * \ingroup LinkedList + */ +void vListInitialise( List_t * const pxList ) PRIVILEGED_FUNCTION; + +/* + * Must be called before a list item is used. This sets the list container to + * null so the item does not think that it is already contained in a list. + * + * @param pxItem Pointer to the list item being initialised. + * + * \page vListInitialiseItem vListInitialiseItem + * \ingroup LinkedList + */ +void vListInitialiseItem( ListItem_t * const pxItem ) PRIVILEGED_FUNCTION; + +/* + * Insert a list item into a list. The item will be inserted into the list in + * a position determined by its item value (descending item value order). + * + * @param pxList The list into which the item is to be inserted. + * + * @param pxNewListItem The item that is to be placed in the list. + * + * \page vListInsert vListInsert + * \ingroup LinkedList + */ +void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem ) PRIVILEGED_FUNCTION; + +/* + * Insert a list item into a list. The item will be inserted in a position + * such that it will be the last item within the list returned by multiple + * calls to listGET_OWNER_OF_NEXT_ENTRY. + * + * The list member pxIndex is used to walk through a list. Calling + * listGET_OWNER_OF_NEXT_ENTRY increments pxIndex to the next item in the list. + * Placing an item in a list using vListInsertEnd effectively places the item + * in the list position pointed to by pxIndex. This means that every other + * item within the list will be returned by listGET_OWNER_OF_NEXT_ENTRY before + * the pxIndex parameter again points to the item being inserted. + * + * @param pxList The list into which the item is to be inserted. + * + * @param pxNewListItem The list item to be inserted into the list. + * + * \page vListInsertEnd vListInsertEnd + * \ingroup LinkedList + */ +void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem ) PRIVILEGED_FUNCTION; + +/* + * Remove an item from a list. The list item has a pointer to the list that + * it is in, so only the list item need be passed into the function. + * + * @param uxListRemove The item to be removed. The item will remove itself from + * the list pointed to by it's pxContainer parameter. + * + * @return The number of items that remain in the list after the list item has + * been removed. + * + * \page uxListRemove uxListRemove + * \ingroup LinkedList + */ +UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove ) PRIVILEGED_FUNCTION; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/STM32F1/libraries/FreeRTOS900/utility/mpu_prototypes.h b/STM32F1/libraries/FreeRTOS900/utility/mpu_prototypes.h new file mode 100644 index 0000000..8f7500b --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/utility/mpu_prototypes.h @@ -0,0 +1,177 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* + * When the MPU is used the standard (non MPU) API functions are mapped to + * equivalents that start "MPU_", the prototypes for which are defined in this + * header files. This will cause the application code to call the MPU_ version + * which wraps the non-MPU version with privilege promoting then demoting code, + * so the kernel code always runs will full privileges. + */ + + +#ifndef MPU_PROTOTYPES_H +#define MPU_PROTOTYPES_H + +/* MPU versions of tasks.h API function. */ +BaseType_t MPU_xTaskCreate( TaskFunction_t pxTaskCode, const char * const pcName, const uint16_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask ); +TaskHandle_t MPU_xTaskCreateStatic( TaskFunction_t pxTaskCode, const char * const pcName, const uint32_t ulStackDepth, void * const pvParameters, UBaseType_t uxPriority, StackType_t * const puxStackBuffer, StaticTask_t * const pxTaskBuffer ); +BaseType_t MPU_xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ); +void MPU_vTaskAllocateMPURegions( TaskHandle_t xTask, const MemoryRegion_t * const pxRegions ); +void MPU_vTaskDelete( TaskHandle_t xTaskToDelete ); +void MPU_vTaskDelay( const TickType_t xTicksToDelay ); +void MPU_vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement ); +BaseType_t MPU_xTaskAbortDelay( TaskHandle_t xTask ); +UBaseType_t MPU_uxTaskPriorityGet( TaskHandle_t xTask ); +eTaskState MPU_eTaskGetState( TaskHandle_t xTask ); +void MPU_vTaskGetInfo( TaskHandle_t xTask, TaskStatus_t *pxTaskStatus, BaseType_t xGetFreeStackSpace, eTaskState eState ); +void MPU_vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority ); +void MPU_vTaskSuspend( TaskHandle_t xTaskToSuspend ); +void MPU_vTaskResume( TaskHandle_t xTaskToResume ); +void MPU_vTaskStartScheduler( void ); +void MPU_vTaskSuspendAll( void ); +BaseType_t MPU_xTaskResumeAll( void ); +TickType_t MPU_xTaskGetTickCount( void ); +UBaseType_t MPU_uxTaskGetNumberOfTasks( void ); +char * MPU_pcTaskGetName( TaskHandle_t xTaskToQuery ); +TaskHandle_t MPU_xTaskGetHandle( const char *pcNameToQuery ); +UBaseType_t MPU_uxTaskGetStackHighWaterMark( TaskHandle_t xTask ); +void MPU_vTaskSetApplicationTaskTag( TaskHandle_t xTask, TaskHookFunction_t pxHookFunction ); +TaskHookFunction_t MPU_xTaskGetApplicationTaskTag( TaskHandle_t xTask ); +void MPU_vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet, BaseType_t xIndex, void *pvValue ); +void * MPU_pvTaskGetThreadLocalStoragePointer( TaskHandle_t xTaskToQuery, BaseType_t xIndex ); +BaseType_t MPU_xTaskCallApplicationTaskHook( TaskHandle_t xTask, void *pvParameter ); +TaskHandle_t MPU_xTaskGetIdleTaskHandle( void ); +UBaseType_t MPU_uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray, const UBaseType_t uxArraySize, uint32_t * const pulTotalRunTime ); +void MPU_vTaskList( char * pcWriteBuffer ); +void MPU_vTaskGetRunTimeStats( char *pcWriteBuffer ); +BaseType_t MPU_xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue ); +BaseType_t MPU_xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait ); +uint32_t MPU_ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait ); +BaseType_t MPU_xTaskNotifyStateClear( TaskHandle_t xTask ); +BaseType_t MPU_xTaskIncrementTick( void ); +TaskHandle_t MPU_xTaskGetCurrentTaskHandle( void ); +void MPU_vTaskSetTimeOutState( TimeOut_t * const pxTimeOut ); +BaseType_t MPU_xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut, TickType_t * const pxTicksToWait ); +void MPU_vTaskMissedYield( void ); +BaseType_t MPU_xTaskGetSchedulerState( void ); + +/* MPU versions of queue.h API function. */ +BaseType_t MPU_xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition ); +BaseType_t MPU_xQueueGenericReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait, const BaseType_t xJustPeek ); +UBaseType_t MPU_uxQueueMessagesWaiting( const QueueHandle_t xQueue ); +UBaseType_t MPU_uxQueueSpacesAvailable( const QueueHandle_t xQueue ); +void MPU_vQueueDelete( QueueHandle_t xQueue ); +QueueHandle_t MPU_xQueueCreateMutex( const uint8_t ucQueueType ); +QueueHandle_t MPU_xQueueCreateMutexStatic( const uint8_t ucQueueType, StaticQueue_t *pxStaticQueue ); +QueueHandle_t MPU_xQueueCreateCountingSemaphore( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount ); +QueueHandle_t MPU_xQueueCreateCountingSemaphoreStatic( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount, StaticQueue_t *pxStaticQueue ); +void* MPU_xQueueGetMutexHolder( QueueHandle_t xSemaphore ); +BaseType_t MPU_xQueueTakeMutexRecursive( QueueHandle_t xMutex, TickType_t xTicksToWait ); +BaseType_t MPU_xQueueGiveMutexRecursive( QueueHandle_t pxMutex ); +void MPU_vQueueAddToRegistry( QueueHandle_t xQueue, const char *pcName ); +void MPU_vQueueUnregisterQueue( QueueHandle_t xQueue ); +const char * MPU_pcQueueGetName( QueueHandle_t xQueue ); +QueueHandle_t MPU_xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType ); +QueueHandle_t MPU_xQueueGenericCreateStatic( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, StaticQueue_t *pxStaticQueue, const uint8_t ucQueueType ); +QueueSetHandle_t MPU_xQueueCreateSet( const UBaseType_t uxEventQueueLength ); +BaseType_t MPU_xQueueAddToSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet ); +BaseType_t MPU_xQueueRemoveFromSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet ); +QueueSetMemberHandle_t MPU_xQueueSelectFromSet( QueueSetHandle_t xQueueSet, const TickType_t xTicksToWait ); +BaseType_t MPU_xQueueGenericReset( QueueHandle_t xQueue, BaseType_t xNewQueue ); +void MPU_vQueueSetQueueNumber( QueueHandle_t xQueue, UBaseType_t uxQueueNumber ); +UBaseType_t MPU_uxQueueGetQueueNumber( QueueHandle_t xQueue ); +uint8_t MPU_ucQueueGetQueueType( QueueHandle_t xQueue ); + +/* MPU versions of timers.h API function. */ +TimerHandle_t MPU_xTimerCreate( const char * const pcTimerName, const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction ); +TimerHandle_t MPU_xTimerCreateStatic( const char * const pcTimerName, const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction, StaticTimer_t *pxTimerBuffer ); +void * MPU_pvTimerGetTimerID( const TimerHandle_t xTimer ); +void MPU_vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID ); +BaseType_t MPU_xTimerIsTimerActive( TimerHandle_t xTimer ); +TaskHandle_t MPU_xTimerGetTimerDaemonTaskHandle( void ); +BaseType_t MPU_xTimerPendFunctionCall( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, TickType_t xTicksToWait ); +const char * MPU_pcTimerGetName( TimerHandle_t xTimer ); +TickType_t MPU_xTimerGetPeriod( TimerHandle_t xTimer ); +TickType_t MPU_xTimerGetExpiryTime( TimerHandle_t xTimer ); +BaseType_t MPU_xTimerCreateTimerTask( void ); +BaseType_t MPU_xTimerGenericCommand( TimerHandle_t xTimer, const BaseType_t xCommandID, const TickType_t xOptionalValue, BaseType_t * const pxHigherPriorityTaskWoken, const TickType_t xTicksToWait ); + +/* MPU versions of event_group.h API function. */ +EventGroupHandle_t MPU_xEventGroupCreate( void ); +EventGroupHandle_t MPU_xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer ); +EventBits_t MPU_xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait ); +EventBits_t MPU_xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ); +EventBits_t MPU_xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet ); +EventBits_t MPU_xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait ); +void MPU_vEventGroupDelete( EventGroupHandle_t xEventGroup ); +UBaseType_t MPU_uxEventGroupGetNumber( void* xEventGroup ); + +#endif /* MPU_PROTOTYPES_H */ + diff --git a/STM32F1/libraries/FreeRTOS900/utility/mpu_wrappers.h b/STM32F1/libraries/FreeRTOS900/utility/mpu_wrappers.h new file mode 100644 index 0000000..78f5a9a --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/utility/mpu_wrappers.h @@ -0,0 +1,201 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef MPU_WRAPPERS_H +#define MPU_WRAPPERS_H + +/* This file redefines API functions to be called through a wrapper macro, but +only for ports that are using the MPU. */ +#ifdef portUSING_MPU_WRAPPERS + + /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE will be defined when this file is + included from queue.c or task.c to prevent it from having an effect within + those files. */ + #ifndef MPU_WRAPPERS_INCLUDED_FROM_API_FILE + + /* + * Map standard (non MPU) API functions to equivalents that start + * "MPU_". This will cause the application code to call the MPU_ + * version, which wraps the non-MPU version with privilege promoting + * then demoting code, so the kernel code always runs will full + * privileges. + */ + + /* Map standard tasks.h API functions to the MPU equivalents. */ + #define xTaskCreate MPU_xTaskCreate + #define xTaskCreateStatic MPU_xTaskCreateStatic + #define xTaskCreateRestricted MPU_xTaskCreateRestricted + #define vTaskAllocateMPURegions MPU_vTaskAllocateMPURegions + #define vTaskDelete MPU_vTaskDelete + #define vTaskDelay MPU_vTaskDelay + #define vTaskDelayUntil MPU_vTaskDelayUntil + #define xTaskAbortDelay MPU_xTaskAbortDelay + #define uxTaskPriorityGet MPU_uxTaskPriorityGet + #define eTaskGetState MPU_eTaskGetState + #define vTaskGetInfo MPU_vTaskGetInfo + #define vTaskPrioritySet MPU_vTaskPrioritySet + #define vTaskSuspend MPU_vTaskSuspend + #define vTaskResume MPU_vTaskResume + #define vTaskSuspendAll MPU_vTaskSuspendAll + #define xTaskResumeAll MPU_xTaskResumeAll + #define xTaskGetTickCount MPU_xTaskGetTickCount + #define uxTaskGetNumberOfTasks MPU_uxTaskGetNumberOfTasks + #define pcTaskGetName MPU_pcTaskGetName + #define xTaskGetHandle MPU_xTaskGetHandle + #define uxTaskGetStackHighWaterMark MPU_uxTaskGetStackHighWaterMark + #define vTaskSetApplicationTaskTag MPU_vTaskSetApplicationTaskTag + #define xTaskGetApplicationTaskTag MPU_xTaskGetApplicationTaskTag + #define vTaskSetThreadLocalStoragePointer MPU_vTaskSetThreadLocalStoragePointer + #define pvTaskGetThreadLocalStoragePointer MPU_pvTaskGetThreadLocalStoragePointer + #define xTaskCallApplicationTaskHook MPU_xTaskCallApplicationTaskHook + #define xTaskGetIdleTaskHandle MPU_xTaskGetIdleTaskHandle + #define uxTaskGetSystemState MPU_uxTaskGetSystemState + #define vTaskList MPU_vTaskList + #define vTaskGetRunTimeStats MPU_vTaskGetRunTimeStats + #define xTaskGenericNotify MPU_xTaskGenericNotify + #define xTaskNotifyWait MPU_xTaskNotifyWait + #define ulTaskNotifyTake MPU_ulTaskNotifyTake + #define xTaskNotifyStateClear MPU_xTaskNotifyStateClear + + #define xTaskGetCurrentTaskHandle MPU_xTaskGetCurrentTaskHandle + #define vTaskSetTimeOutState MPU_vTaskSetTimeOutState + #define xTaskCheckForTimeOut MPU_xTaskCheckForTimeOut + #define xTaskGetSchedulerState MPU_xTaskGetSchedulerState + + /* Map standard queue.h API functions to the MPU equivalents. */ + #define xQueueGenericSend MPU_xQueueGenericSend + #define xQueueGenericReceive MPU_xQueueGenericReceive + #define uxQueueMessagesWaiting MPU_uxQueueMessagesWaiting + #define uxQueueSpacesAvailable MPU_uxQueueSpacesAvailable + #define vQueueDelete MPU_vQueueDelete + #define xQueueCreateMutex MPU_xQueueCreateMutex + #define xQueueCreateMutexStatic MPU_xQueueCreateMutexStatic + #define xQueueCreateCountingSemaphore MPU_xQueueCreateCountingSemaphore + #define xQueueCreateCountingSemaphoreStatic MPU_xQueueCreateCountingSemaphoreStatic + #define xQueueGetMutexHolder MPU_xQueueGetMutexHolder + #define xQueueTakeMutexRecursive MPU_xQueueTakeMutexRecursive + #define xQueueGiveMutexRecursive MPU_xQueueGiveMutexRecursive + #define xQueueGenericCreate MPU_xQueueGenericCreate + #define xQueueGenericCreateStatic MPU_xQueueGenericCreateStatic + #define xQueueCreateSet MPU_xQueueCreateSet + #define xQueueAddToSet MPU_xQueueAddToSet + #define xQueueRemoveFromSet MPU_xQueueRemoveFromSet + #define xQueueSelectFromSet MPU_xQueueSelectFromSet + #define xQueueGenericReset MPU_xQueueGenericReset + + #if( configQUEUE_REGISTRY_SIZE > 0 ) + #define vQueueAddToRegistry MPU_vQueueAddToRegistry + #define vQueueUnregisterQueue MPU_vQueueUnregisterQueue + #define pcQueueGetName MPU_pcQueueGetName + #endif + + /* Map standard timer.h API functions to the MPU equivalents. */ + #define xTimerCreate MPU_xTimerCreate + #define xTimerCreateStatic MPU_xTimerCreateStatic + #define pvTimerGetTimerID MPU_pvTimerGetTimerID + #define vTimerSetTimerID MPU_vTimerSetTimerID + #define xTimerIsTimerActive MPU_xTimerIsTimerActive + #define xTimerGetTimerDaemonTaskHandle MPU_xTimerGetTimerDaemonTaskHandle + #define xTimerPendFunctionCall MPU_xTimerPendFunctionCall + #define pcTimerGetName MPU_pcTimerGetName + #define xTimerGetPeriod MPU_xTimerGetPeriod + #define xTimerGetExpiryTime MPU_xTimerGetExpiryTime + #define xTimerGenericCommand MPU_xTimerGenericCommand + + /* Map standard event_group.h API functions to the MPU equivalents. */ + #define xEventGroupCreate MPU_xEventGroupCreate + #define xEventGroupCreateStatic MPU_xEventGroupCreateStatic + #define xEventGroupWaitBits MPU_xEventGroupWaitBits + #define xEventGroupClearBits MPU_xEventGroupClearBits + #define xEventGroupSetBits MPU_xEventGroupSetBits + #define xEventGroupSync MPU_xEventGroupSync + #define vEventGroupDelete MPU_vEventGroupDelete + + /* Remove the privileged function macro. */ + #define PRIVILEGED_FUNCTION + + #else /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE */ + + /* Ensure API functions go in the privileged execution section. */ + #define PRIVILEGED_FUNCTION __attribute__((section("privileged_functions"))) + #define PRIVILEGED_DATA __attribute__((section("privileged_data"))) + + #endif /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE */ + +#else /* portUSING_MPU_WRAPPERS */ + + #define PRIVILEGED_FUNCTION + #define PRIVILEGED_DATA + #define portUSING_MPU_WRAPPERS 0 + +#endif /* portUSING_MPU_WRAPPERS */ + + +#endif /* MPU_WRAPPERS_H */ + diff --git a/STM32F1/libraries/FreeRTOS900/utility/port.c b/STM32F1/libraries/FreeRTOS900/utility/port.c new file mode 100644 index 0000000..6cfebe8 --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/utility/port.c @@ -0,0 +1,717 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/*----------------------------------------------------------- + * Implementation of functions defined in portable.h for the ARM CM3 port. + *----------------------------------------------------------*/ + +/* Scheduler includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* For backward compatibility, ensure configKERNEL_INTERRUPT_PRIORITY is +defined. The value should also ensure backward compatibility. +FreeRTOS.org versions prior to V4.4.0 did not include this definition. */ +#ifndef configKERNEL_INTERRUPT_PRIORITY + #define configKERNEL_INTERRUPT_PRIORITY 255 +#endif + +#ifndef configSYSTICK_CLOCK_HZ + #define configSYSTICK_CLOCK_HZ configCPU_CLOCK_HZ + /* Ensure the SysTick is clocked at the same frequency as the core. */ + #define portNVIC_SYSTICK_CLK_BIT ( 1UL << 2UL ) +#else + /* The way the SysTick is clocked is not modified in case it is not the same + as the core. */ + #define portNVIC_SYSTICK_CLK_BIT ( 0 ) +#endif + +/* Constants required to manipulate the core. Registers first... */ +#define portNVIC_SYSTICK_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000e010 ) ) +#define portNVIC_SYSTICK_LOAD_REG ( * ( ( volatile uint32_t * ) 0xe000e014 ) ) +#define portNVIC_SYSTICK_CURRENT_VALUE_REG ( * ( ( volatile uint32_t * ) 0xe000e018 ) ) +#define portNVIC_SYSPRI2_REG ( * ( ( volatile uint32_t * ) 0xe000ed20 ) ) +/* ...then bits in the registers. */ +#define portNVIC_SYSTICK_INT_BIT ( 1UL << 1UL ) +#define portNVIC_SYSTICK_ENABLE_BIT ( 1UL << 0UL ) +#define portNVIC_SYSTICK_COUNT_FLAG_BIT ( 1UL << 16UL ) +#define portNVIC_PENDSVCLEAR_BIT ( 1UL << 27UL ) +#define portNVIC_PEND_SYSTICK_CLEAR_BIT ( 1UL << 25UL ) + +#define portNVIC_PENDSV_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL ) +#define portNVIC_SYSTICK_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL ) + +/* Constants required to check the validity of an interrupt priority. */ +#define portFIRST_USER_INTERRUPT_NUMBER ( 16 ) +#define portNVIC_IP_REGISTERS_OFFSET_16 ( 0xE000E3F0 ) +#define portAIRCR_REG ( * ( ( volatile uint32_t * ) 0xE000ED0C ) ) +#define portMAX_8_BIT_VALUE ( ( uint8_t ) 0xff ) +#define portTOP_BIT_OF_BYTE ( ( uint8_t ) 0x80 ) +#define portMAX_PRIGROUP_BITS ( ( uint8_t ) 7 ) +#define portPRIORITY_GROUP_MASK ( 0x07UL << 8UL ) +#define portPRIGROUP_SHIFT ( 8UL ) + +/* Masks off all bits but the VECTACTIVE bits in the ICSR register. */ +#define portVECTACTIVE_MASK ( 0xFFUL ) + +/* Constants required to set up the initial stack. */ +#define portINITIAL_XPSR ( 0x01000000UL ) + +/* The systick is a 24-bit counter. */ +#define portMAX_24_BIT_NUMBER ( 0xffffffUL ) + +/* A fiddle factor to estimate the number of SysTick counts that would have +occurred while the SysTick counter is stopped during tickless idle +calculations. */ +#define portMISSED_COUNTS_FACTOR ( 45UL ) + +/* For strict compliance with the Cortex-M spec the task start address should +have bit-0 clear, as it is loaded into the PC on exit from an ISR. */ +#define portSTART_ADDRESS_MASK ( ( StackType_t ) 0xfffffffeUL ) + +/* Let the user override the pre-loading of the initial LR with the address of +prvTaskExitError() in case it messes up unwinding of the stack in the +debugger. */ +#ifdef configTASK_RETURN_ADDRESS + #define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS +#else + #define portTASK_RETURN_ADDRESS prvTaskExitError +#endif + +/* Each task maintains its own interrupt status in the critical nesting +variable. */ +static UBaseType_t uxCriticalNesting = 0xaaaaaaaa; + +/* + * Setup the timer to generate the tick interrupts. The implementation in this + * file is weak to allow application writers to change the timer used to + * generate the tick interrupt. + */ +void vPortSetupTimerInterrupt( void ); + +/* + * Exception handlers. + */ +void xPortPendSVHandler( void ) __attribute__ (( naked )); +void xPortSysTickHandler( void ); +void vPortSVCHandler( void ) __attribute__ (( naked )); + +/* + * Start first task is a separate function so it can be tested in isolation. + */ +static void prvPortStartFirstTask( void ) __attribute__ (( naked )); + +/* + * Used to catch tasks that attempt to return from their implementing function. + */ +static void prvTaskExitError( void ); + +/*-----------------------------------------------------------*/ + +/* + * The number of SysTick increments that make up one tick period. + */ +#if configUSE_TICKLESS_IDLE == 1 + static uint32_t ulTimerCountsForOneTick = 0; +#endif /* configUSE_TICKLESS_IDLE */ + +/* + * The maximum number of tick periods that can be suppressed is limited by the + * 24 bit resolution of the SysTick timer. + */ +#if configUSE_TICKLESS_IDLE == 1 + static uint32_t xMaximumPossibleSuppressedTicks = 0; +#endif /* configUSE_TICKLESS_IDLE */ + +/* + * Compensate for the CPU cycles that pass while the SysTick is stopped (low + * power functionality only. + */ +#if configUSE_TICKLESS_IDLE == 1 + static uint32_t ulStoppedTimerCompensation = 0; +#endif /* configUSE_TICKLESS_IDLE */ + +/* + * Used by the portASSERT_IF_INTERRUPT_PRIORITY_INVALID() macro to ensure + * FreeRTOS API functions are not called from interrupts that have been assigned + * a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY. + */ +#if ( configASSERT_DEFINED == 1 ) + static uint8_t ucMaxSysCallPriority = 0; + static uint32_t ulMaxPRIGROUPValue = 0; + static const volatile uint8_t * const pcInterruptPriorityRegisters = ( const volatile uint8_t * const ) portNVIC_IP_REGISTERS_OFFSET_16; +#endif /* configASSERT_DEFINED */ + +/*-----------------------------------------------------------*/ + +/* + * See header file for description. + */ +StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters ) +{ + /* Simulate the stack frame as it would be created by a context switch + interrupt. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR */ + pxTopOfStack--; + *pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK; /* PC */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR */ + pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */ + pxTopOfStack -= 8; /* R11, R10, R9, R8, R7, R6, R5 and R4. */ + + return pxTopOfStack; +} +/*-----------------------------------------------------------*/ + +static void prvTaskExitError( void ) +{ + /* A function that implements a task must not exit or attempt to return to + its caller as there is nothing to return to. If a task wants to exit it + should instead call vTaskDelete( NULL ). + + Artificially force an assert() to be triggered if configASSERT() is + defined, then stop here so application writers can catch the error. */ + configASSERT( uxCriticalNesting == ~0UL ); + portDISABLE_INTERRUPTS(); + for( ;; ); +} +/*-----------------------------------------------------------*/ + +// !!! Maple +//void vPortSVCHandler( void ) +void __exc_svc( void ) +// !!! Maple +{ + __asm volatile ( + " ldr r3, pxCurrentTCBConst2 \n" /* Restore the context. */ + " ldr r1, [r3] \n" /* Use pxCurrentTCBConst to get the pxCurrentTCB address. */ + " ldr r0, [r1] \n" /* The first item in pxCurrentTCB is the task top of stack. */ + " ldmia r0!, {r4-r11} \n" /* Pop the registers that are not automatically saved on exception entry and the critical nesting count. */ + " msr psp, r0 \n" /* Restore the task stack pointer. */ + " isb \n" + " mov r0, #0 \n" + " msr basepri, r0 \n" + " orr r14, #0xd \n" + " bx r14 \n" + " \n" + " .align 4 \n" + "pxCurrentTCBConst2: .word pxCurrentTCB \n" + ); +} +/*-----------------------------------------------------------*/ + +static void prvPortStartFirstTask( void ) +{ + __asm volatile( + " ldr r0, =0xE000ED08 \n" /* Use the NVIC offset register to locate the stack. */ + " ldr r0, [r0] \n" + " ldr r0, [r0] \n" + " msr msp, r0 \n" /* Set the msp back to the start of the stack. */ + " cpsie i \n" /* Globally enable interrupts. */ + " cpsie f \n" + " dsb \n" + " isb \n" + " svc 0 \n" /* System call to start first task. */ + " nop \n" + ); +} +/*-----------------------------------------------------------*/ + +/* + * See header file for description. + */ +BaseType_t xPortStartScheduler( void ) +{ + /* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. + See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */ + configASSERT( configMAX_SYSCALL_INTERRUPT_PRIORITY ); + + #if( configASSERT_DEFINED == 1 ) + { + volatile uint32_t ulOriginalPriority; + volatile uint8_t * const pucFirstUserPriorityRegister = ( volatile uint8_t * const ) ( portNVIC_IP_REGISTERS_OFFSET_16 + portFIRST_USER_INTERRUPT_NUMBER ); + volatile uint8_t ucMaxPriorityValue; + + /* Determine the maximum priority from which ISR safe FreeRTOS API + functions can be called. ISR safe functions are those that end in + "FromISR". FreeRTOS maintains separate thread and ISR API functions to + ensure interrupt entry is as fast and simple as possible. + + Save the interrupt priority value that is about to be clobbered. */ + ulOriginalPriority = *pucFirstUserPriorityRegister; + + /* Determine the number of priority bits available. First write to all + possible bits. */ + *pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE; + + /* Read the value back to see how many bits stuck. */ + ucMaxPriorityValue = *pucFirstUserPriorityRegister; + + /* Use the same mask on the maximum system call priority. */ + ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue; + + /* Calculate the maximum acceptable priority group value for the number + of bits read back. */ + ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS; + while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE ) + { + ulMaxPRIGROUPValue--; + ucMaxPriorityValue <<= ( uint8_t ) 0x01; + } + + /* Shift the priority group value back to its position within the AIRCR + register. */ + ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT; + ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK; + + /* Restore the clobbered interrupt priority register to its original + value. */ + *pucFirstUserPriorityRegister = ulOriginalPriority; + } + #endif /* conifgASSERT_DEFINED */ + + /* Make PendSV and SysTick the lowest priority interrupts. */ + portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI; + portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI; + + /* Start the timer that generates the tick ISR. Interrupts are disabled + here already. */ + //vPortSetupTimerInterrupt(); + systick_attach_callback(&xPortSysTickHandler); + // !!! Maple + + /* Initialise the critical nesting count ready for the first task. */ + uxCriticalNesting = 0; + + /* Start the first task. */ + prvPortStartFirstTask(); + + /* Should never get here as the tasks will now be executing! Call the task + exit error function to prevent compiler warnings about a static function + not being called in the case that the application writer overrides this + functionality by defining configTASK_RETURN_ADDRESS. */ + prvTaskExitError(); + + /* Should not get here! */ + return 0; +} +/*-----------------------------------------------------------*/ + +void vPortEndScheduler( void ) +{ + /* Not implemented in ports where there is nothing to return to. + Artificially force an assert. */ + configASSERT( uxCriticalNesting == 1000UL ); +} +/*-----------------------------------------------------------*/ + +void vPortEnterCritical( void ) +{ + portDISABLE_INTERRUPTS(); + uxCriticalNesting++; + + /* This is not the interrupt safe version of the enter critical function so + assert() if it is being called from an interrupt context. Only API + functions that end in "FromISR" can be used in an interrupt. Only assert if + the critical nesting count is 1 to protect against recursive calls if the + assert function also uses a critical section. */ + if( uxCriticalNesting == 1 ) + { + configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 ); + } +} +/*-----------------------------------------------------------*/ + +void vPortExitCritical( void ) +{ + configASSERT( uxCriticalNesting ); + uxCriticalNesting--; + if( uxCriticalNesting == 0 ) + { + portENABLE_INTERRUPTS(); + } +} +/*-----------------------------------------------------------*/ + + // !!! Maple + //void xPortPendSVHandler( void ) + void __exc_pendsv( void ) + { + /* This is a naked function. */ + + __asm volatile + ( + " mrs r0, psp \n" + " isb \n" + " \n" + " ldr r3, pxCurrentTCBConst \n" /* Get the location of the current TCB. */ + " ldr r2, [r3] \n" + " \n" + " stmdb r0!, {r4-r11} \n" /* Save the remaining registers. */ + " str r0, [r2] \n" /* Save the new top of stack into the first member of the TCB. */ + " \n" + " stmdb sp!, {r3, r14} \n" + " mov r0, %0 \n" + " msr basepri, r0 \n" + " bl vTaskSwitchContext \n" + " mov r0, #0 \n" + " msr basepri, r0 \n" + " ldmia sp!, {r3, r14} \n" + " \n" /* Restore the context, including the critical nesting count. */ + " ldr r1, [r3] \n" + " ldr r0, [r1] \n" /* The first item in pxCurrentTCB is the task top of stack. */ + " ldmia r0!, {r4-r11} \n" /* Pop the registers. */ + " msr psp, r0 \n" + " isb \n" + " bx r14 \n" + " \n" + " .align 4 \n" + "pxCurrentTCBConst: .word pxCurrentTCB \n" + ::"i"(configMAX_SYSCALL_INTERRUPT_PRIORITY) + ); +} +/*-----------------------------------------------------------*/ + +void xPortSysTickHandler( void ) +{ + /* The SysTick runs at the lowest interrupt priority, so when this interrupt + executes all interrupts must be unmasked. There is therefore no need to + save and then restore the interrupt mask value as its value is already + known. */ + portDISABLE_INTERRUPTS(); + { + /* Increment the RTOS tick. */ + if( xTaskIncrementTick() != pdFALSE ) + { + /* A context switch is required. Context switching is performed in + the PendSV interrupt. Pend the PendSV interrupt. */ + portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; + } + } + portENABLE_INTERRUPTS(); +} +/*-----------------------------------------------------------*/ + +#if configUSE_TICKLESS_IDLE == 1 + + __attribute__((weak)) void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ) + { + uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements, ulSysTickCTRL; + TickType_t xModifiableIdleTime; + + /* Make sure the SysTick reload value does not overflow the counter. */ + if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks ) + { + xExpectedIdleTime = xMaximumPossibleSuppressedTicks; + } + + /* Stop the SysTick momentarily. The time the SysTick is stopped for + is accounted for as best it can be, but using the tickless mode will + inevitably result in some tiny drift of the time maintained by the + kernel with respect to calendar time. */ + portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT; + + /* Calculate the reload value required to wait xExpectedIdleTime + tick periods. -1 is used because this code will execute part way + through one of the tick periods. */ + ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) ); + if( ulReloadValue > ulStoppedTimerCompensation ) + { + ulReloadValue -= ulStoppedTimerCompensation; + } + + /* Enter a critical section but don't use the taskENTER_CRITICAL() + method as that will mask interrupts that should exit sleep mode. */ + __asm volatile( "cpsid i" ); + __asm volatile( "dsb" ); + __asm volatile( "isb" ); + + /* If a context switch is pending or a task is waiting for the scheduler + to be unsuspended then abandon the low power entry. */ + if( eTaskConfirmSleepModeStatus() == eAbortSleep ) + { + /* Restart from whatever is left in the count register to complete + this tick period. */ + portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG; + + /* Restart SysTick. */ + portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT; + + /* Reset the reload register to the value required for normal tick + periods. */ + portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL; + + /* Re-enable interrupts - see comments above the cpsid instruction() + above. */ + __asm volatile( "cpsie i" ); + } + else + { + /* Set the new reload value. */ + portNVIC_SYSTICK_LOAD_REG = ulReloadValue; + + /* Clear the SysTick count flag and set the count value back to + zero. */ + portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; + + /* Restart SysTick. */ + portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT; + + /* Sleep until something happens. configPRE_SLEEP_PROCESSING() can + set its parameter to 0 to indicate that its implementation contains + its own wait for interrupt or wait for event instruction, and so wfi + should not be executed again. However, the original expected idle + time variable must remain unmodified, so a copy is taken. */ + xModifiableIdleTime = xExpectedIdleTime; + configPRE_SLEEP_PROCESSING( xModifiableIdleTime ); + if( xModifiableIdleTime > 0 ) + { + __asm volatile( "dsb" ); + __asm volatile( "wfi" ); + __asm volatile( "isb" ); + } + configPOST_SLEEP_PROCESSING( xExpectedIdleTime ); + + /* Stop SysTick. Again, the time the SysTick is stopped for is + accounted for as best it can be, but using the tickless mode will + inevitably result in some tiny drift of the time maintained by the + kernel with respect to calendar time. */ + ulSysTickCTRL = portNVIC_SYSTICK_CTRL_REG; + portNVIC_SYSTICK_CTRL_REG = ( ulSysTickCTRL & ~portNVIC_SYSTICK_ENABLE_BIT ); + + /* Re-enable interrupts - see comments above the cpsid instruction() + above. */ + __asm volatile( "cpsie i" ); + + if( ( ulSysTickCTRL & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 ) + { + uint32_t ulCalculatedLoadValue; + + /* The tick interrupt has already executed, and the SysTick + count reloaded with ulReloadValue. Reset the + portNVIC_SYSTICK_LOAD_REG with whatever remains of this tick + period. */ + ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG ); + + /* Don't allow a tiny value, or values that have somehow + underflowed because the post sleep hook did something + that took too long. */ + if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) ) + { + ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ); + } + + portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue; + + /* The tick interrupt handler will already have pended the tick + processing in the kernel. As the pending tick will be + processed as soon as this function exits, the tick value + maintained by the tick is stepped forward by one less than the + time spent waiting. */ + ulCompleteTickPeriods = xExpectedIdleTime - 1UL; + } + else + { + /* Something other than the tick interrupt ended the sleep. + Work out how long the sleep lasted rounded to complete tick + periods (not the ulReload value which accounted for part + ticks). */ + ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - portNVIC_SYSTICK_CURRENT_VALUE_REG; + + /* How many complete tick periods passed while the processor + was waiting? */ + ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick; + + /* The reload value is set to whatever fraction of a single tick + period remains. */ + portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1UL ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements; + } + + /* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG + again, then set portNVIC_SYSTICK_LOAD_REG back to its standard + value. The critical section is used to ensure the tick interrupt + can only execute once in the case that the reload register is near + zero. */ + portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; + portENTER_CRITICAL(); + { + portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT; + vTaskStepTick( ulCompleteTickPeriods ); + portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL; + } + portEXIT_CRITICAL(); + } + } + +#endif /* #if configUSE_TICKLESS_IDLE */ +/*-----------------------------------------------------------*/ + +/* + * Setup the systick timer to generate the tick interrupts at the required + * frequency. + */ +__attribute__(( weak )) void vPortSetupTimerInterrupt( void ) +{ + /* Calculate the constants required to configure the tick interrupt. */ + #if configUSE_TICKLESS_IDLE == 1 + { + ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ); + xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick; + ulStoppedTimerCompensation = portMISSED_COUNTS_FACTOR / ( configCPU_CLOCK_HZ / configSYSTICK_CLOCK_HZ ); + } + #endif /* configUSE_TICKLESS_IDLE */ + + /* Configure SysTick to interrupt at the requested rate. */ + portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; + portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT ); +} +/*-----------------------------------------------------------*/ + +#if( configASSERT_DEFINED == 1 ) + + void vPortValidateInterruptPriority( void ) + { + uint32_t ulCurrentInterrupt; + uint8_t ucCurrentPriority; + + /* Obtain the number of the currently executing interrupt. */ + __asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) ); + + /* Is the interrupt number a user defined interrupt? */ + if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER ) + { + /* Look up the interrupt's priority. */ + ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ]; + + /* The following assertion will fail if a service routine (ISR) for + an interrupt that has been assigned a priority above + configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API + function. ISR safe FreeRTOS API functions must *only* be called + from interrupts that have been assigned a priority at or below + configMAX_SYSCALL_INTERRUPT_PRIORITY. + + Numerically low interrupt priority numbers represent logically high + interrupt priorities, therefore the priority of the interrupt must + be set to a value equal to or numerically *higher* than + configMAX_SYSCALL_INTERRUPT_PRIORITY. + + Interrupts that use the FreeRTOS API must not be left at their + default priority of zero as that is the highest possible priority, + which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY, + and therefore also guaranteed to be invalid. + + FreeRTOS maintains separate thread and ISR API functions to ensure + interrupt entry is as fast and simple as possible. + + The following links provide detailed information: + http://www.freertos.org/RTOS-Cortex-M3-M4.html + http://www.freertos.org/FAQHelp.html */ + configASSERT( ucCurrentPriority >= ucMaxSysCallPriority ); + } + + /* Priority grouping: The interrupt controller (NVIC) allows the bits + that define each interrupt's priority to be split between bits that + define the interrupt's pre-emption priority bits and bits that define + the interrupt's sub-priority. For simplicity all bits must be defined + to be pre-emption priority bits. The following assertion will fail if + this is not the case (if some bits represent a sub-priority). + + If the application only uses CMSIS libraries for interrupt + configuration then the correct setting can be achieved on all Cortex-M + devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the + scheduler. Note however that some vendor specific peripheral libraries + assume a non-zero priority group setting, in which cases using a value + of zero will result in unpredicable behaviour. */ + configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue ); + } + +#endif /* configASSERT_DEFINED */ + + + + + + + + + + + + + + + + + + + + + diff --git a/STM32F1/libraries/FreeRTOS900/utility/portable.h b/STM32F1/libraries/FreeRTOS900/utility/portable.h new file mode 100644 index 0000000..b9f8be3 --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/utility/portable.h @@ -0,0 +1,207 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/*----------------------------------------------------------- + * Portable layer API. Each function must be defined for each port. + *----------------------------------------------------------*/ + +#ifndef PORTABLE_H +#define PORTABLE_H + +/* Each FreeRTOS port has a unique portmacro.h header file. Originally a +pre-processor definition was used to ensure the pre-processor found the correct +portmacro.h file for the port being used. That scheme was deprecated in favour +of setting the compiler's include path such that it found the correct +portmacro.h file - removing the need for the constant and allowing the +portmacro.h file to be located anywhere in relation to the port being used. +Purely for reasons of backward compatibility the old method is still valid, but +to make it clear that new projects should not use it, support for the port +specific constants has been moved into the deprecated_definitions.h header +file. */ +#include "deprecated_definitions.h" + +/* If portENTER_CRITICAL is not defined then including deprecated_definitions.h +did not result in a portmacro.h header file being included - and it should be +included here. In this case the path to the correct portmacro.h header file +must be set in the compiler's include path. */ +#ifndef portENTER_CRITICAL + #include "portmacro.h" +#endif + +#if portBYTE_ALIGNMENT == 32 + #define portBYTE_ALIGNMENT_MASK ( 0x001f ) +#endif + +#if portBYTE_ALIGNMENT == 16 + #define portBYTE_ALIGNMENT_MASK ( 0x000f ) +#endif + +#if portBYTE_ALIGNMENT == 8 + #define portBYTE_ALIGNMENT_MASK ( 0x0007 ) +#endif + +#if portBYTE_ALIGNMENT == 4 + #define portBYTE_ALIGNMENT_MASK ( 0x0003 ) +#endif + +#if portBYTE_ALIGNMENT == 2 + #define portBYTE_ALIGNMENT_MASK ( 0x0001 ) +#endif + +#if portBYTE_ALIGNMENT == 1 + #define portBYTE_ALIGNMENT_MASK ( 0x0000 ) +#endif + +#ifndef portBYTE_ALIGNMENT_MASK + #error "Invalid portBYTE_ALIGNMENT definition" +#endif + +#ifndef portNUM_CONFIGURABLE_REGIONS + #define portNUM_CONFIGURABLE_REGIONS 1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#include "mpu_wrappers.h" + +/* + * Setup the stack of a new task so it is ready to be placed under the + * scheduler control. The registers have to be placed on the stack in + * the order that the port expects to find them. + * + */ +#if( portUSING_MPU_WRAPPERS == 1 ) + StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters, BaseType_t xRunPrivileged ) PRIVILEGED_FUNCTION; +#else + StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters ) PRIVILEGED_FUNCTION; +#endif + +/* Used by heap_5.c. */ +typedef struct HeapRegion +{ + uint8_t *pucStartAddress; + size_t xSizeInBytes; +} HeapRegion_t; + +/* + * Used to define multiple heap regions for use by heap_5.c. This function + * must be called before any calls to pvPortMalloc() - not creating a task, + * queue, semaphore, mutex, software timer, event group, etc. will result in + * pvPortMalloc being called. + * + * pxHeapRegions passes in an array of HeapRegion_t structures - each of which + * defines a region of memory that can be used as the heap. The array is + * terminated by a HeapRegions_t structure that has a size of 0. The region + * with the lowest start address must appear first in the array. + */ +void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions ) PRIVILEGED_FUNCTION; + + +/* + * Map to the memory management routines required for the port. + */ +void *pvPortMalloc( size_t xSize ) PRIVILEGED_FUNCTION; +void vPortFree( void *pv ) PRIVILEGED_FUNCTION; +void vPortInitialiseBlocks( void ) PRIVILEGED_FUNCTION; +size_t xPortGetFreeHeapSize( void ) PRIVILEGED_FUNCTION; +size_t xPortGetMinimumEverFreeHeapSize( void ) PRIVILEGED_FUNCTION; + +/* + * Setup the hardware ready for the scheduler to take control. This generally + * sets up a tick interrupt and sets timers for the correct tick frequency. + */ +BaseType_t xPortStartScheduler( void ) PRIVILEGED_FUNCTION; + +/* + * Undo any hardware/ISR setup that was performed by xPortStartScheduler() so + * the hardware is left in its original condition after the scheduler stops + * executing. + */ +void vPortEndScheduler( void ) PRIVILEGED_FUNCTION; + +/* + * The structures and methods of manipulating the MPU are contained within the + * port layer. + * + * Fills the xMPUSettings structure with the memory region information + * contained in xRegions. + */ +#if( portUSING_MPU_WRAPPERS == 1 ) + struct xMEMORY_REGION; + void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMORY_REGION * const xRegions, StackType_t *pxBottomOfStack, uint32_t ulStackDepth ) PRIVILEGED_FUNCTION; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* PORTABLE_H */ + diff --git a/STM32F1/libraries/FreeRTOS900/utility/portmacro.h b/STM32F1/libraries/FreeRTOS900/utility/portmacro.h new file mode 100644 index 0000000..d44fc92 --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/utility/portmacro.h @@ -0,0 +1,284 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + + +#ifndef PORTMACRO_H +#define PORTMACRO_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*----------------------------------------------------------- + * Port specific definitions. + * + * The settings in this file configure FreeRTOS correctly for the + * given hardware and compiler. + * + * These settings should not be altered. + *----------------------------------------------------------- + */ + +/* Type definitions. */ +#define portCHAR char +#define portFLOAT float +#define portDOUBLE double +#define portLONG long +#define portSHORT short +#define portSTACK_TYPE uint32_t +#define portBASE_TYPE long + +typedef portSTACK_TYPE StackType_t; +typedef long BaseType_t; +typedef unsigned long UBaseType_t; + +#if( configUSE_16_BIT_TICKS == 1 ) + typedef uint16_t TickType_t; + #define portMAX_DELAY ( TickType_t ) 0xffff +#else + typedef uint32_t TickType_t; + #define portMAX_DELAY ( TickType_t ) 0xffffffffUL + + /* 32-bit tick type on a 32-bit architecture, so reads of the tick count do + not need to be guarded with a critical section. */ + #define portTICK_TYPE_IS_ATOMIC 1 +#endif +/*-----------------------------------------------------------*/ + +/* Architecture specifics. */ +#define portSTACK_GROWTH ( -1 ) +#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ ) +#define portBYTE_ALIGNMENT 8 +/*-----------------------------------------------------------*/ + +/* Scheduler utilities. */ +#define portYIELD() \ +{ \ + /* Set a PendSV to request a context switch. */ \ + portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \ + \ + /* Barriers are normally not required but do ensure the code is completely \ + within the specified behaviour for the architecture. */ \ + __asm volatile( "dsb" ); \ + __asm volatile( "isb" ); \ +} + +#define portNVIC_INT_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000ed04 ) ) +#define portNVIC_PENDSVSET_BIT ( 1UL << 28UL ) +#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) portYIELD() +#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x ) +/*-----------------------------------------------------------*/ + +/* Critical section management. */ +extern void vPortEnterCritical( void ); +extern void vPortExitCritical( void ); +#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortRaiseBASEPRI() +#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortSetBASEPRI(x) +#define portDISABLE_INTERRUPTS() vPortRaiseBASEPRI() +#define portENABLE_INTERRUPTS() vPortSetBASEPRI(0) +#define portENTER_CRITICAL() vPortEnterCritical() +#define portEXIT_CRITICAL() vPortExitCritical() + +/*-----------------------------------------------------------*/ + +/* Task function macros as described on the FreeRTOS.org WEB site. These are +not necessary for to use this port. They are defined so the common demo files +(which build with all the ports) will build. */ +#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters ) +#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters ) +/*-----------------------------------------------------------*/ + +/* Tickless idle/low power functionality. */ +#ifndef portSUPPRESS_TICKS_AND_SLEEP + extern void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ); + #define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime ) +#endif +/*-----------------------------------------------------------*/ + +/* Architecture specific optimisations. */ +#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION + #define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 +#endif + +#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 + + /* Generic helper function. */ + __attribute__( ( always_inline ) ) static inline uint8_t ucPortCountLeadingZeros( uint32_t ulBitmap ) + { + uint8_t ucReturn; + + __asm volatile ( "clz %0, %1" : "=r" ( ucReturn ) : "r" ( ulBitmap ) ); + return ucReturn; + } + + /* Check the configuration. */ + #if( configMAX_PRIORITIES > 32 ) + #error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice. + #endif + + /* Store/clear the ready priorities in a bit map. */ + #define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) ) + #define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) ) + + /*-----------------------------------------------------------*/ + + #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31UL - ( uint32_t ) ucPortCountLeadingZeros( ( uxReadyPriorities ) ) ) + +#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ + +/*-----------------------------------------------------------*/ + +#ifdef configASSERT + void vPortValidateInterruptPriority( void ); + #define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() vPortValidateInterruptPriority() +#endif + +/* portNOP() is not required by this port. */ +#define portNOP() + +#define portINLINE __inline + +#ifndef portFORCE_INLINE + #define portFORCE_INLINE inline __attribute__(( always_inline)) +#endif + +portFORCE_INLINE static BaseType_t xPortIsInsideInterrupt( void ) +{ +uint32_t ulCurrentInterrupt; +BaseType_t xReturn; + + /* Obtain the number of the currently executing interrupt. */ + __asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) ); + + if( ulCurrentInterrupt == 0 ) + { + xReturn = pdFALSE; + } + else + { + xReturn = pdTRUE; + } + + return xReturn; +} + +/*-----------------------------------------------------------*/ + +portFORCE_INLINE static void vPortRaiseBASEPRI( void ) +{ +uint32_t ulNewBASEPRI; + + __asm volatile + ( + " mov %0, %1 \n" \ + " msr basepri, %0 \n" \ + " isb \n" \ + " dsb \n" \ + :"=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) + ); +} + +/*-----------------------------------------------------------*/ + +portFORCE_INLINE static uint32_t ulPortRaiseBASEPRI( void ) +{ +uint32_t ulOriginalBASEPRI, ulNewBASEPRI; + + __asm volatile + ( + " mrs %0, basepri \n" \ + " mov %1, %2 \n" \ + " msr basepri, %1 \n" \ + " isb \n" \ + " dsb \n" \ + :"=r" (ulOriginalBASEPRI), "=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) + ); + + /* This return will not be reached but is necessary to prevent compiler + warnings. */ + return ulOriginalBASEPRI; +} +/*-----------------------------------------------------------*/ + +portFORCE_INLINE static void vPortSetBASEPRI( uint32_t ulNewMaskValue ) +{ + __asm volatile + ( + " msr basepri, %0 " :: "r" ( ulNewMaskValue ) + ); +} +/*-----------------------------------------------------------*/ + + +#ifdef __cplusplus +} +#endif + +#endif /* PORTMACRO_H */ + diff --git a/STM32F1/libraries/FreeRTOS900/utility/projdefs.h b/STM32F1/libraries/FreeRTOS900/utility/projdefs.h new file mode 100644 index 0000000..0b63fd8 --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/utility/projdefs.h @@ -0,0 +1,161 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef PROJDEFS_H +#define PROJDEFS_H + +/* + * Defines the prototype to which task functions must conform. Defined in this + * file to ensure the type is known before portable.h is included. + */ +typedef void (*TaskFunction_t)( void * ); + +/* Converts a time in milliseconds to a time in ticks. This macro can be +overridden by a macro of the same name defined in FreeRTOSConfig.h in case the +definition here is not suitable for your application. */ +#ifndef pdMS_TO_TICKS + #define pdMS_TO_TICKS( xTimeInMs ) ( ( TickType_t ) ( ( ( TickType_t ) ( xTimeInMs ) * ( TickType_t ) configTICK_RATE_HZ ) / ( TickType_t ) 1000 ) ) +#endif + +#define pdFALSE ( ( BaseType_t ) 0 ) +#define pdTRUE ( ( BaseType_t ) 1 ) + +#define pdPASS ( pdTRUE ) +#define pdFAIL ( pdFALSE ) +#define errQUEUE_EMPTY ( ( BaseType_t ) 0 ) +#define errQUEUE_FULL ( ( BaseType_t ) 0 ) + +/* FreeRTOS error definitions. */ +#define errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY ( -1 ) +#define errQUEUE_BLOCKED ( -4 ) +#define errQUEUE_YIELD ( -5 ) + +/* Macros used for basic data corruption checks. */ +#ifndef configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES + #define configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES 0 +#endif + +#if( configUSE_16_BIT_TICKS == 1 ) + #define pdINTEGRITY_CHECK_VALUE 0x5a5a +#else + #define pdINTEGRITY_CHECK_VALUE 0x5a5a5a5aUL +#endif + +/* The following errno values are used by FreeRTOS+ components, not FreeRTOS +itself. */ +#define pdFREERTOS_ERRNO_NONE 0 /* No errors */ +#define pdFREERTOS_ERRNO_ENOENT 2 /* No such file or directory */ +#define pdFREERTOS_ERRNO_EINTR 4 /* Interrupted system call */ +#define pdFREERTOS_ERRNO_EIO 5 /* I/O error */ +#define pdFREERTOS_ERRNO_ENXIO 6 /* No such device or address */ +#define pdFREERTOS_ERRNO_EBADF 9 /* Bad file number */ +#define pdFREERTOS_ERRNO_EAGAIN 11 /* No more processes */ +#define pdFREERTOS_ERRNO_EWOULDBLOCK 11 /* Operation would block */ +#define pdFREERTOS_ERRNO_ENOMEM 12 /* Not enough memory */ +#define pdFREERTOS_ERRNO_EACCES 13 /* Permission denied */ +#define pdFREERTOS_ERRNO_EFAULT 14 /* Bad address */ +#define pdFREERTOS_ERRNO_EBUSY 16 /* Mount device busy */ +#define pdFREERTOS_ERRNO_EEXIST 17 /* File exists */ +#define pdFREERTOS_ERRNO_EXDEV 18 /* Cross-device link */ +#define pdFREERTOS_ERRNO_ENODEV 19 /* No such device */ +#define pdFREERTOS_ERRNO_ENOTDIR 20 /* Not a directory */ +#define pdFREERTOS_ERRNO_EISDIR 21 /* Is a directory */ +#define pdFREERTOS_ERRNO_EINVAL 22 /* Invalid argument */ +#define pdFREERTOS_ERRNO_ENOSPC 28 /* No space left on device */ +#define pdFREERTOS_ERRNO_ESPIPE 29 /* Illegal seek */ +#define pdFREERTOS_ERRNO_EROFS 30 /* Read only file system */ +#define pdFREERTOS_ERRNO_EUNATCH 42 /* Protocol driver not attached */ +#define pdFREERTOS_ERRNO_EBADE 50 /* Invalid exchange */ +#define pdFREERTOS_ERRNO_EFTYPE 79 /* Inappropriate file type or format */ +#define pdFREERTOS_ERRNO_ENMFILE 89 /* No more files */ +#define pdFREERTOS_ERRNO_ENOTEMPTY 90 /* Directory not empty */ +#define pdFREERTOS_ERRNO_ENAMETOOLONG 91 /* File or path name too long */ +#define pdFREERTOS_ERRNO_EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ +#define pdFREERTOS_ERRNO_ENOBUFS 105 /* No buffer space available */ +#define pdFREERTOS_ERRNO_ENOPROTOOPT 109 /* Protocol not available */ +#define pdFREERTOS_ERRNO_EADDRINUSE 112 /* Address already in use */ +#define pdFREERTOS_ERRNO_ETIMEDOUT 116 /* Connection timed out */ +#define pdFREERTOS_ERRNO_EINPROGRESS 119 /* Connection already in progress */ +#define pdFREERTOS_ERRNO_EALREADY 120 /* Socket already connected */ +#define pdFREERTOS_ERRNO_EADDRNOTAVAIL 125 /* Address not available */ +#define pdFREERTOS_ERRNO_EISCONN 127 /* Socket is already connected */ +#define pdFREERTOS_ERRNO_ENOTCONN 128 /* Socket is not connected */ +#define pdFREERTOS_ERRNO_ENOMEDIUM 135 /* No medium inserted */ +#define pdFREERTOS_ERRNO_EILSEQ 138 /* An invalid UTF-16 sequence was encountered. */ +#define pdFREERTOS_ERRNO_ECANCELED 140 /* Operation canceled. */ + +/* The following endian values are used by FreeRTOS+ components, not FreeRTOS +itself. */ +#define pdFREERTOS_LITTLE_ENDIAN 0 +#define pdFREERTOS_BIG_ENDIAN 1 + +#endif /* PROJDEFS_H */ + + + diff --git a/STM32F1/libraries/FreeRTOS900/utility/queue.c b/STM32F1/libraries/FreeRTOS900/utility/queue.c new file mode 100644 index 0000000..ce623be --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/utility/queue.c @@ -0,0 +1,2566 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#include +#include + +/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining +all the API functions to use the MPU wrappers. That should only be done when +task.h is included from an application file. */ +#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" + +#if ( configUSE_CO_ROUTINES == 1 ) + #include "croutine.h" +#endif + +/* Lint e961 and e750 are suppressed as a MISRA exception justified because the +MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the +header files above, but not in this file, in order to generate the correct +privileged Vs unprivileged linkage and placement. */ +#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */ + + +/* Constants used with the cRxLock and cTxLock structure members. */ +#define queueUNLOCKED ( ( int8_t ) -1 ) +#define queueLOCKED_UNMODIFIED ( ( int8_t ) 0 ) + +/* When the Queue_t structure is used to represent a base queue its pcHead and +pcTail members are used as pointers into the queue storage area. When the +Queue_t structure is used to represent a mutex pcHead and pcTail pointers are +not necessary, and the pcHead pointer is set to NULL to indicate that the +pcTail pointer actually points to the mutex holder (if any). Map alternative +names to the pcHead and pcTail structure members to ensure the readability of +the code is maintained despite this dual use of two structure members. An +alternative implementation would be to use a union, but use of a union is +against the coding standard (although an exception to the standard has been +permitted where the dual use also significantly changes the type of the +structure member). */ +#define pxMutexHolder pcTail +#define uxQueueType pcHead +#define queueQUEUE_IS_MUTEX NULL + +/* Semaphores do not actually store or copy data, so have an item size of +zero. */ +#define queueSEMAPHORE_QUEUE_ITEM_LENGTH ( ( UBaseType_t ) 0 ) +#define queueMUTEX_GIVE_BLOCK_TIME ( ( TickType_t ) 0U ) + +#if( configUSE_PREEMPTION == 0 ) + /* If the cooperative scheduler is being used then a yield should not be + performed just because a higher priority task has been woken. */ + #define queueYIELD_IF_USING_PREEMPTION() +#else + #define queueYIELD_IF_USING_PREEMPTION() portYIELD_WITHIN_API() +#endif + +/* + * Definition of the queue used by the scheduler. + * Items are queued by copy, not reference. See the following link for the + * rationale: http://www.freertos.org/Embedded-RTOS-Queues.html + */ +typedef struct QueueDefinition +{ + int8_t *pcHead; /*< Points to the beginning of the queue storage area. */ + int8_t *pcTail; /*< Points to the byte at the end of the queue storage area. Once more byte is allocated than necessary to store the queue items, this is used as a marker. */ + int8_t *pcWriteTo; /*< Points to the free next place in the storage area. */ + + union /* Use of a union is an exception to the coding standard to ensure two mutually exclusive structure members don't appear simultaneously (wasting RAM). */ + { + int8_t *pcReadFrom; /*< Points to the last place that a queued item was read from when the structure is used as a queue. */ + UBaseType_t uxRecursiveCallCount;/*< Maintains a count of the number of times a recursive mutex has been recursively 'taken' when the structure is used as a mutex. */ + } u; + + List_t xTasksWaitingToSend; /*< List of tasks that are blocked waiting to post onto this queue. Stored in priority order. */ + List_t xTasksWaitingToReceive; /*< List of tasks that are blocked waiting to read from this queue. Stored in priority order. */ + + volatile UBaseType_t uxMessagesWaiting;/*< The number of items currently in the queue. */ + UBaseType_t uxLength; /*< The length of the queue defined as the number of items it will hold, not the number of bytes. */ + UBaseType_t uxItemSize; /*< The size of each items that the queue will hold. */ + + volatile int8_t cRxLock; /*< Stores the number of items received from the queue (removed from the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */ + volatile int8_t cTxLock; /*< Stores the number of items transmitted to the queue (added to the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */ + + #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the memory used by the queue was statically allocated to ensure no attempt is made to free the memory. */ + #endif + + #if ( configUSE_QUEUE_SETS == 1 ) + struct QueueDefinition *pxQueueSetContainer; + #endif + + #if ( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxQueueNumber; + uint8_t ucQueueType; + #endif + +} xQUEUE; + +/* The old xQUEUE name is maintained above then typedefed to the new Queue_t +name below to enable the use of older kernel aware debuggers. */ +typedef xQUEUE Queue_t; + +/*-----------------------------------------------------------*/ + +/* + * The queue registry is just a means for kernel aware debuggers to locate + * queue structures. It has no other purpose so is an optional component. + */ +#if ( configQUEUE_REGISTRY_SIZE > 0 ) + + /* The type stored within the queue registry array. This allows a name + to be assigned to each queue making kernel aware debugging a little + more user friendly. */ + typedef struct QUEUE_REGISTRY_ITEM + { + const char *pcQueueName; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + QueueHandle_t xHandle; + } xQueueRegistryItem; + + /* The old xQueueRegistryItem name is maintained above then typedefed to the + new xQueueRegistryItem name below to enable the use of older kernel aware + debuggers. */ + typedef xQueueRegistryItem QueueRegistryItem_t; + + /* The queue registry is simply an array of QueueRegistryItem_t structures. + The pcQueueName member of a structure being NULL is indicative of the + array position being vacant. */ + PRIVILEGED_DATA QueueRegistryItem_t xQueueRegistry[ configQUEUE_REGISTRY_SIZE ]; + +#endif /* configQUEUE_REGISTRY_SIZE */ + +/* + * Unlocks a queue locked by a call to prvLockQueue. Locking a queue does not + * prevent an ISR from adding or removing items to the queue, but does prevent + * an ISR from removing tasks from the queue event lists. If an ISR finds a + * queue is locked it will instead increment the appropriate queue lock count + * to indicate that a task may require unblocking. When the queue in unlocked + * these lock counts are inspected, and the appropriate action taken. + */ +static void prvUnlockQueue( Queue_t * const pxQueue ) PRIVILEGED_FUNCTION; + +/* + * Uses a critical section to determine if there is any data in a queue. + * + * @return pdTRUE if the queue contains no items, otherwise pdFALSE. + */ +static BaseType_t prvIsQueueEmpty( const Queue_t *pxQueue ) PRIVILEGED_FUNCTION; + +/* + * Uses a critical section to determine if there is any space in a queue. + * + * @return pdTRUE if there is no space, otherwise pdFALSE; + */ +static BaseType_t prvIsQueueFull( const Queue_t *pxQueue ) PRIVILEGED_FUNCTION; + +/* + * Copies an item into the queue, either at the front of the queue or the + * back of the queue. + */ +static BaseType_t prvCopyDataToQueue( Queue_t * const pxQueue, const void *pvItemToQueue, const BaseType_t xPosition ) PRIVILEGED_FUNCTION; + +/* + * Copies an item out of a queue. + */ +static void prvCopyDataFromQueue( Queue_t * const pxQueue, void * const pvBuffer ) PRIVILEGED_FUNCTION; + +#if ( configUSE_QUEUE_SETS == 1 ) + /* + * Checks to see if a queue is a member of a queue set, and if so, notifies + * the queue set that the queue contains data. + */ + static BaseType_t prvNotifyQueueSetContainer( const Queue_t * const pxQueue, const BaseType_t xCopyPosition ) PRIVILEGED_FUNCTION; +#endif + +/* + * Called after a Queue_t structure has been allocated either statically or + * dynamically to fill in the structure's members. + */ +static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, const uint8_t ucQueueType, Queue_t *pxNewQueue ) PRIVILEGED_FUNCTION; + +/* + * Mutexes are a special type of queue. When a mutex is created, first the + * queue is created, then prvInitialiseMutex() is called to configure the queue + * as a mutex. + */ +#if( configUSE_MUTEXES == 1 ) + static void prvInitialiseMutex( Queue_t *pxNewQueue ) PRIVILEGED_FUNCTION; +#endif + +/*-----------------------------------------------------------*/ + +/* + * Macro to mark a queue as locked. Locking a queue prevents an ISR from + * accessing the queue event lists. + */ +#define prvLockQueue( pxQueue ) \ + taskENTER_CRITICAL(); \ + { \ + if( ( pxQueue )->cRxLock == queueUNLOCKED ) \ + { \ + ( pxQueue )->cRxLock = queueLOCKED_UNMODIFIED; \ + } \ + if( ( pxQueue )->cTxLock == queueUNLOCKED ) \ + { \ + ( pxQueue )->cTxLock = queueLOCKED_UNMODIFIED; \ + } \ + } \ + taskEXIT_CRITICAL() +/*-----------------------------------------------------------*/ + +BaseType_t xQueueGenericReset( QueueHandle_t xQueue, BaseType_t xNewQueue ) +{ +Queue_t * const pxQueue = ( Queue_t * ) xQueue; + + configASSERT( pxQueue ); + + taskENTER_CRITICAL(); + { + pxQueue->pcTail = pxQueue->pcHead + ( pxQueue->uxLength * pxQueue->uxItemSize ); + pxQueue->uxMessagesWaiting = ( UBaseType_t ) 0U; + pxQueue->pcWriteTo = pxQueue->pcHead; + pxQueue->u.pcReadFrom = pxQueue->pcHead + ( ( pxQueue->uxLength - ( UBaseType_t ) 1U ) * pxQueue->uxItemSize ); + pxQueue->cRxLock = queueUNLOCKED; + pxQueue->cTxLock = queueUNLOCKED; + + if( xNewQueue == pdFALSE ) + { + /* If there are tasks blocked waiting to read from the queue, then + the tasks will remain blocked as after this function exits the queue + will still be empty. If there are tasks blocked waiting to write to + the queue, then one should be unblocked as after this function exits + it will be possible to write to it. */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) + { + queueYIELD_IF_USING_PREEMPTION(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + /* Ensure the event queues start in the correct state. */ + vListInitialise( &( pxQueue->xTasksWaitingToSend ) ); + vListInitialise( &( pxQueue->xTasksWaitingToReceive ) ); + } + } + taskEXIT_CRITICAL(); + + /* A value is returned for calling semantic consistency with previous + versions. */ + return pdPASS; +} +/*-----------------------------------------------------------*/ + +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + + QueueHandle_t xQueueGenericCreateStatic( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, StaticQueue_t *pxStaticQueue, const uint8_t ucQueueType ) + { + Queue_t *pxNewQueue; + + configASSERT( uxQueueLength > ( UBaseType_t ) 0 ); + + /* The StaticQueue_t structure and the queue storage area must be + supplied. */ + configASSERT( pxStaticQueue != NULL ); + + /* A queue storage area should be provided if the item size is not 0, and + should not be provided if the item size is 0. */ + configASSERT( !( ( pucQueueStorage != NULL ) && ( uxItemSize == 0 ) ) ); + configASSERT( !( ( pucQueueStorage == NULL ) && ( uxItemSize != 0 ) ) ); + + #if( configASSERT_DEFINED == 1 ) + { + /* Sanity check that the size of the structure used to declare a + variable of type StaticQueue_t or StaticSemaphore_t equals the size of + the real queue and semaphore structures. */ + volatile size_t xSize = sizeof( StaticQueue_t ); + configASSERT( xSize == sizeof( Queue_t ) ); + } + #endif /* configASSERT_DEFINED */ + + /* The address of a statically allocated queue was passed in, use it. + The address of a statically allocated storage area was also passed in + but is already set. */ + pxNewQueue = ( Queue_t * ) pxStaticQueue; /*lint !e740 Unusual cast is ok as the structures are designed to have the same alignment, and the size is checked by an assert. */ + + if( pxNewQueue != NULL ) + { + #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + { + /* Queues can be allocated wither statically or dynamically, so + note this queue was allocated statically in case the queue is + later deleted. */ + pxNewQueue->ucStaticallyAllocated = pdTRUE; + } + #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ + + prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue ); + } + + return pxNewQueue; + } + +#endif /* configSUPPORT_STATIC_ALLOCATION */ +/*-----------------------------------------------------------*/ + +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + + QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType ) + { + Queue_t *pxNewQueue; + size_t xQueueSizeInBytes; + uint8_t *pucQueueStorage; + + configASSERT( uxQueueLength > ( UBaseType_t ) 0 ); + + if( uxItemSize == ( UBaseType_t ) 0 ) + { + /* There is not going to be a queue storage area. */ + xQueueSizeInBytes = ( size_t ) 0; + } + else + { + /* Allocate enough space to hold the maximum number of items that + can be in the queue at any time. */ + xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + } + + pxNewQueue = ( Queue_t * ) pvPortMalloc( sizeof( Queue_t ) + xQueueSizeInBytes ); + + if( pxNewQueue != NULL ) + { + /* Jump past the queue structure to find the location of the queue + storage area. */ + pucQueueStorage = ( ( uint8_t * ) pxNewQueue ) + sizeof( Queue_t ); + + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) + { + /* Queues can be created either statically or dynamically, so + note this task was created dynamically in case it is later + deleted. */ + pxNewQueue->ucStaticallyAllocated = pdFALSE; + } + #endif /* configSUPPORT_STATIC_ALLOCATION */ + + prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue ); + } + + return pxNewQueue; + } + +#endif /* configSUPPORT_STATIC_ALLOCATION */ +/*-----------------------------------------------------------*/ + +static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, const uint8_t ucQueueType, Queue_t *pxNewQueue ) +{ + /* Remove compiler warnings about unused parameters should + configUSE_TRACE_FACILITY not be set to 1. */ + ( void ) ucQueueType; + + if( uxItemSize == ( UBaseType_t ) 0 ) + { + /* No RAM was allocated for the queue storage area, but PC head cannot + be set to NULL because NULL is used as a key to say the queue is used as + a mutex. Therefore just set pcHead to point to the queue as a benign + value that is known to be within the memory map. */ + pxNewQueue->pcHead = ( int8_t * ) pxNewQueue; + } + else + { + /* Set the head to the start of the queue storage area. */ + pxNewQueue->pcHead = ( int8_t * ) pucQueueStorage; + } + + /* Initialise the queue members as described where the queue type is + defined. */ + pxNewQueue->uxLength = uxQueueLength; + pxNewQueue->uxItemSize = uxItemSize; + ( void ) xQueueGenericReset( pxNewQueue, pdTRUE ); + + #if ( configUSE_TRACE_FACILITY == 1 ) + { + pxNewQueue->ucQueueType = ucQueueType; + } + #endif /* configUSE_TRACE_FACILITY */ + + #if( configUSE_QUEUE_SETS == 1 ) + { + pxNewQueue->pxQueueSetContainer = NULL; + } + #endif /* configUSE_QUEUE_SETS */ + + traceQUEUE_CREATE( pxNewQueue ); +} +/*-----------------------------------------------------------*/ + +#if( configUSE_MUTEXES == 1 ) + + static void prvInitialiseMutex( Queue_t *pxNewQueue ) + { + if( pxNewQueue != NULL ) + { + /* The queue create function will set all the queue structure members + correctly for a generic queue, but this function is creating a + mutex. Overwrite those members that need to be set differently - + in particular the information required for priority inheritance. */ + pxNewQueue->pxMutexHolder = NULL; + pxNewQueue->uxQueueType = queueQUEUE_IS_MUTEX; + + /* In case this is a recursive mutex. */ + pxNewQueue->u.uxRecursiveCallCount = 0; + + traceCREATE_MUTEX( pxNewQueue ); + + /* Start with the semaphore in the expected state. */ + ( void ) xQueueGenericSend( pxNewQueue, NULL, ( TickType_t ) 0U, queueSEND_TO_BACK ); + } + else + { + traceCREATE_MUTEX_FAILED(); + } + } + +#endif /* configUSE_MUTEXES */ +/*-----------------------------------------------------------*/ + +#if( ( configUSE_MUTEXES == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + + QueueHandle_t xQueueCreateMutex( const uint8_t ucQueueType ) + { + Queue_t *pxNewQueue; + const UBaseType_t uxMutexLength = ( UBaseType_t ) 1, uxMutexSize = ( UBaseType_t ) 0; + + pxNewQueue = ( Queue_t * ) xQueueGenericCreate( uxMutexLength, uxMutexSize, ucQueueType ); + prvInitialiseMutex( pxNewQueue ); + + return pxNewQueue; + } + +#endif /* configUSE_MUTEXES */ +/*-----------------------------------------------------------*/ + +#if( ( configUSE_MUTEXES == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) + + QueueHandle_t xQueueCreateMutexStatic( const uint8_t ucQueueType, StaticQueue_t *pxStaticQueue ) + { + Queue_t *pxNewQueue; + const UBaseType_t uxMutexLength = ( UBaseType_t ) 1, uxMutexSize = ( UBaseType_t ) 0; + + /* Prevent compiler warnings about unused parameters if + configUSE_TRACE_FACILITY does not equal 1. */ + ( void ) ucQueueType; + + pxNewQueue = ( Queue_t * ) xQueueGenericCreateStatic( uxMutexLength, uxMutexSize, NULL, pxStaticQueue, ucQueueType ); + prvInitialiseMutex( pxNewQueue ); + + return pxNewQueue; + } + +#endif /* configUSE_MUTEXES */ +/*-----------------------------------------------------------*/ + +#if ( ( configUSE_MUTEXES == 1 ) && ( INCLUDE_xSemaphoreGetMutexHolder == 1 ) ) + + void* xQueueGetMutexHolder( QueueHandle_t xSemaphore ) + { + void *pxReturn; + + /* This function is called by xSemaphoreGetMutexHolder(), and should not + be called directly. Note: This is a good way of determining if the + calling task is the mutex holder, but not a good way of determining the + identity of the mutex holder, as the holder may change between the + following critical section exiting and the function returning. */ + taskENTER_CRITICAL(); + { + if( ( ( Queue_t * ) xSemaphore )->uxQueueType == queueQUEUE_IS_MUTEX ) + { + pxReturn = ( void * ) ( ( Queue_t * ) xSemaphore )->pxMutexHolder; + } + else + { + pxReturn = NULL; + } + } + taskEXIT_CRITICAL(); + + return pxReturn; + } /*lint !e818 xSemaphore cannot be a pointer to const because it is a typedef. */ + +#endif +/*-----------------------------------------------------------*/ + +#if ( configUSE_RECURSIVE_MUTEXES == 1 ) + + BaseType_t xQueueGiveMutexRecursive( QueueHandle_t xMutex ) + { + BaseType_t xReturn; + Queue_t * const pxMutex = ( Queue_t * ) xMutex; + + configASSERT( pxMutex ); + + /* If this is the task that holds the mutex then pxMutexHolder will not + change outside of this task. If this task does not hold the mutex then + pxMutexHolder can never coincidentally equal the tasks handle, and as + this is the only condition we are interested in it does not matter if + pxMutexHolder is accessed simultaneously by another task. Therefore no + mutual exclusion is required to test the pxMutexHolder variable. */ + if( pxMutex->pxMutexHolder == ( void * ) xTaskGetCurrentTaskHandle() ) /*lint !e961 Not a redundant cast as TaskHandle_t is a typedef. */ + { + traceGIVE_MUTEX_RECURSIVE( pxMutex ); + + /* uxRecursiveCallCount cannot be zero if pxMutexHolder is equal to + the task handle, therefore no underflow check is required. Also, + uxRecursiveCallCount is only modified by the mutex holder, and as + there can only be one, no mutual exclusion is required to modify the + uxRecursiveCallCount member. */ + ( pxMutex->u.uxRecursiveCallCount )--; + + /* Has the recursive call count unwound to 0? */ + if( pxMutex->u.uxRecursiveCallCount == ( UBaseType_t ) 0 ) + { + /* Return the mutex. This will automatically unblock any other + task that might be waiting to access the mutex. */ + ( void ) xQueueGenericSend( pxMutex, NULL, queueMUTEX_GIVE_BLOCK_TIME, queueSEND_TO_BACK ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + xReturn = pdPASS; + } + else + { + /* The mutex cannot be given because the calling task is not the + holder. */ + xReturn = pdFAIL; + + traceGIVE_MUTEX_RECURSIVE_FAILED( pxMutex ); + } + + return xReturn; + } + +#endif /* configUSE_RECURSIVE_MUTEXES */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_RECURSIVE_MUTEXES == 1 ) + + BaseType_t xQueueTakeMutexRecursive( QueueHandle_t xMutex, TickType_t xTicksToWait ) + { + BaseType_t xReturn; + Queue_t * const pxMutex = ( Queue_t * ) xMutex; + + configASSERT( pxMutex ); + + /* Comments regarding mutual exclusion as per those within + xQueueGiveMutexRecursive(). */ + + traceTAKE_MUTEX_RECURSIVE( pxMutex ); + + if( pxMutex->pxMutexHolder == ( void * ) xTaskGetCurrentTaskHandle() ) /*lint !e961 Cast is not redundant as TaskHandle_t is a typedef. */ + { + ( pxMutex->u.uxRecursiveCallCount )++; + xReturn = pdPASS; + } + else + { + xReturn = xQueueGenericReceive( pxMutex, NULL, xTicksToWait, pdFALSE ); + + /* pdPASS will only be returned if the mutex was successfully + obtained. The calling task may have entered the Blocked state + before reaching here. */ + if( xReturn != pdFAIL ) + { + ( pxMutex->u.uxRecursiveCallCount )++; + } + else + { + traceTAKE_MUTEX_RECURSIVE_FAILED( pxMutex ); + } + } + + return xReturn; + } + +#endif /* configUSE_RECURSIVE_MUTEXES */ +/*-----------------------------------------------------------*/ + +#if( ( configUSE_COUNTING_SEMAPHORES == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) + + QueueHandle_t xQueueCreateCountingSemaphoreStatic( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount, StaticQueue_t *pxStaticQueue ) + { + QueueHandle_t xHandle; + + configASSERT( uxMaxCount != 0 ); + configASSERT( uxInitialCount <= uxMaxCount ); + + xHandle = xQueueGenericCreateStatic( uxMaxCount, queueSEMAPHORE_QUEUE_ITEM_LENGTH, NULL, pxStaticQueue, queueQUEUE_TYPE_COUNTING_SEMAPHORE ); + + if( xHandle != NULL ) + { + ( ( Queue_t * ) xHandle )->uxMessagesWaiting = uxInitialCount; + + traceCREATE_COUNTING_SEMAPHORE(); + } + else + { + traceCREATE_COUNTING_SEMAPHORE_FAILED(); + } + + return xHandle; + } + +#endif /* ( ( configUSE_COUNTING_SEMAPHORES == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) */ +/*-----------------------------------------------------------*/ + +#if( ( configUSE_COUNTING_SEMAPHORES == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + + QueueHandle_t xQueueCreateCountingSemaphore( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount ) + { + QueueHandle_t xHandle; + + configASSERT( uxMaxCount != 0 ); + configASSERT( uxInitialCount <= uxMaxCount ); + + xHandle = xQueueGenericCreate( uxMaxCount, queueSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_COUNTING_SEMAPHORE ); + + if( xHandle != NULL ) + { + ( ( Queue_t * ) xHandle )->uxMessagesWaiting = uxInitialCount; + + traceCREATE_COUNTING_SEMAPHORE(); + } + else + { + traceCREATE_COUNTING_SEMAPHORE_FAILED(); + } + + return xHandle; + } + +#endif /* ( ( configUSE_COUNTING_SEMAPHORES == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) */ +/*-----------------------------------------------------------*/ + +BaseType_t xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition ) +{ +BaseType_t xEntryTimeSet = pdFALSE, xYieldRequired; +TimeOut_t xTimeOut; +Queue_t * const pxQueue = ( Queue_t * ) xQueue; + + configASSERT( pxQueue ); + configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) ); + configASSERT( !( ( xCopyPosition == queueOVERWRITE ) && ( pxQueue->uxLength != 1 ) ) ); + #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) + { + configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) ); + } + #endif + + + /* This function relaxes the coding standard somewhat to allow return + statements within the function itself. This is done in the interest + of execution time efficiency. */ + for( ;; ) + { + taskENTER_CRITICAL(); + { + /* Is there room on the queue now? The running task must be the + highest priority task wanting to access the queue. If the head item + in the queue is to be overwritten then it does not matter if the + queue is full. */ + if( ( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) || ( xCopyPosition == queueOVERWRITE ) ) + { + traceQUEUE_SEND( pxQueue ); + xYieldRequired = prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition ); + + #if ( configUSE_QUEUE_SETS == 1 ) + { + if( pxQueue->pxQueueSetContainer != NULL ) + { + if( prvNotifyQueueSetContainer( pxQueue, xCopyPosition ) != pdFALSE ) + { + /* The queue is a member of a queue set, and posting + to the queue set caused a higher priority task to + unblock. A context switch is required. */ + queueYIELD_IF_USING_PREEMPTION(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + /* If there was a task waiting for data to arrive on the + queue then unblock it now. */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The unblocked task has a priority higher than + our own so yield immediately. Yes it is ok to + do this from within the critical section - the + kernel takes care of that. */ + queueYIELD_IF_USING_PREEMPTION(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else if( xYieldRequired != pdFALSE ) + { + /* This path is a special case that will only get + executed if the task was holding multiple mutexes + and the mutexes were given back in an order that is + different to that in which they were taken. */ + queueYIELD_IF_USING_PREEMPTION(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + } + #else /* configUSE_QUEUE_SETS */ + { + /* If there was a task waiting for data to arrive on the + queue then unblock it now. */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The unblocked task has a priority higher than + our own so yield immediately. Yes it is ok to do + this from within the critical section - the kernel + takes care of that. */ + queueYIELD_IF_USING_PREEMPTION(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else if( xYieldRequired != pdFALSE ) + { + /* This path is a special case that will only get + executed if the task was holding multiple mutexes and + the mutexes were given back in an order that is + different to that in which they were taken. */ + queueYIELD_IF_USING_PREEMPTION(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configUSE_QUEUE_SETS */ + + taskEXIT_CRITICAL(); + return pdPASS; + } + else + { + if( xTicksToWait == ( TickType_t ) 0 ) + { + /* The queue was full and no block time is specified (or + the block time has expired) so leave now. */ + taskEXIT_CRITICAL(); + + /* Return to the original privilege level before exiting + the function. */ + traceQUEUE_SEND_FAILED( pxQueue ); + return errQUEUE_FULL; + } + else if( xEntryTimeSet == pdFALSE ) + { + /* The queue was full and a block time was specified so + configure the timeout structure. */ + vTaskSetTimeOutState( &xTimeOut ); + xEntryTimeSet = pdTRUE; + } + else + { + /* Entry time was already set. */ + mtCOVERAGE_TEST_MARKER(); + } + } + } + taskEXIT_CRITICAL(); + + /* Interrupts and other tasks can send to and receive from the queue + now the critical section has been exited. */ + + vTaskSuspendAll(); + prvLockQueue( pxQueue ); + + /* Update the timeout state to see if it has expired yet. */ + if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) + { + if( prvIsQueueFull( pxQueue ) != pdFALSE ) + { + traceBLOCKING_ON_QUEUE_SEND( pxQueue ); + vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait ); + + /* Unlocking the queue means queue events can effect the + event list. It is possible that interrupts occurring now + remove this task from the event list again - but as the + scheduler is suspended the task will go onto the pending + ready last instead of the actual ready list. */ + prvUnlockQueue( pxQueue ); + + /* Resuming the scheduler will move tasks from the pending + ready list into the ready list - so it is feasible that this + task is already in a ready list before it yields - in which + case the yield will not cause a context switch unless there + is also a higher priority task in the pending ready list. */ + if( xTaskResumeAll() == pdFALSE ) + { + portYIELD_WITHIN_API(); + } + } + else + { + /* Try again. */ + prvUnlockQueue( pxQueue ); + ( void ) xTaskResumeAll(); + } + } + else + { + /* The timeout has expired. */ + prvUnlockQueue( pxQueue ); + ( void ) xTaskResumeAll(); + + traceQUEUE_SEND_FAILED( pxQueue ); + return errQUEUE_FULL; + } + } +} +/*-----------------------------------------------------------*/ + +BaseType_t xQueueGenericSendFromISR( QueueHandle_t xQueue, const void * const pvItemToQueue, BaseType_t * const pxHigherPriorityTaskWoken, const BaseType_t xCopyPosition ) +{ +BaseType_t xReturn; +UBaseType_t uxSavedInterruptStatus; +Queue_t * const pxQueue = ( Queue_t * ) xQueue; + + configASSERT( pxQueue ); + configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) ); + configASSERT( !( ( xCopyPosition == queueOVERWRITE ) && ( pxQueue->uxLength != 1 ) ) ); + + /* RTOS ports that support interrupt nesting have the concept of a maximum + system call (or maximum API call) interrupt priority. Interrupts that are + above the maximum system call priority are kept permanently enabled, even + when the RTOS kernel is in a critical section, but cannot make any calls to + FreeRTOS API functions. If configASSERT() is defined in FreeRTOSConfig.h + then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has been + assigned a priority above the configured maximum system call priority. + Only FreeRTOS functions that end in FromISR can be called from interrupts + that have been assigned a priority at or (logically) below the maximum + system call interrupt priority. FreeRTOS maintains a separate interrupt + safe API to ensure interrupt entry is as fast and as simple as possible. + More information (albeit Cortex-M specific) is provided on the following + link: http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + + /* Similar to xQueueGenericSend, except without blocking if there is no room + in the queue. Also don't directly wake a task that was blocked on a queue + read, instead return a flag to say whether a context switch is required or + not (i.e. has a task with a higher priority than us been woken by this + post). */ + uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + { + if( ( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) || ( xCopyPosition == queueOVERWRITE ) ) + { + const int8_t cTxLock = pxQueue->cTxLock; + + traceQUEUE_SEND_FROM_ISR( pxQueue ); + + /* Semaphores use xQueueGiveFromISR(), so pxQueue will not be a + semaphore or mutex. That means prvCopyDataToQueue() cannot result + in a task disinheriting a priority and prvCopyDataToQueue() can be + called here even though the disinherit function does not check if + the scheduler is suspended before accessing the ready lists. */ + ( void ) prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition ); + + /* The event list is not altered if the queue is locked. This will + be done when the queue is unlocked later. */ + if( cTxLock == queueUNLOCKED ) + { + #if ( configUSE_QUEUE_SETS == 1 ) + { + if( pxQueue->pxQueueSetContainer != NULL ) + { + if( prvNotifyQueueSetContainer( pxQueue, xCopyPosition ) != pdFALSE ) + { + /* The queue is a member of a queue set, and posting + to the queue set caused a higher priority task to + unblock. A context switch is required. */ + if( pxHigherPriorityTaskWoken != NULL ) + { + *pxHigherPriorityTaskWoken = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The task waiting has a higher priority so + record that a context switch is required. */ + if( pxHigherPriorityTaskWoken != NULL ) + { + *pxHigherPriorityTaskWoken = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + } + #else /* configUSE_QUEUE_SETS */ + { + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The task waiting has a higher priority so record that a + context switch is required. */ + if( pxHigherPriorityTaskWoken != NULL ) + { + *pxHigherPriorityTaskWoken = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configUSE_QUEUE_SETS */ + } + else + { + /* Increment the lock count so the task that unlocks the queue + knows that data was posted while it was locked. */ + pxQueue->cTxLock = ( int8_t ) ( cTxLock + 1 ); + } + + xReturn = pdPASS; + } + else + { + traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue ); + xReturn = errQUEUE_FULL; + } + } + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t xQueueGiveFromISR( QueueHandle_t xQueue, BaseType_t * const pxHigherPriorityTaskWoken ) +{ +BaseType_t xReturn; +UBaseType_t uxSavedInterruptStatus; +Queue_t * const pxQueue = ( Queue_t * ) xQueue; + + /* Similar to xQueueGenericSendFromISR() but used with semaphores where the + item size is 0. Don't directly wake a task that was blocked on a queue + read, instead return a flag to say whether a context switch is required or + not (i.e. has a task with a higher priority than us been woken by this + post). */ + + configASSERT( pxQueue ); + + /* xQueueGenericSendFromISR() should be used instead of xQueueGiveFromISR() + if the item size is not 0. */ + configASSERT( pxQueue->uxItemSize == 0 ); + + /* Normally a mutex would not be given from an interrupt, especially if + there is a mutex holder, as priority inheritance makes no sense for an + interrupts, only tasks. */ + configASSERT( !( ( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) && ( pxQueue->pxMutexHolder != NULL ) ) ); + + /* RTOS ports that support interrupt nesting have the concept of a maximum + system call (or maximum API call) interrupt priority. Interrupts that are + above the maximum system call priority are kept permanently enabled, even + when the RTOS kernel is in a critical section, but cannot make any calls to + FreeRTOS API functions. If configASSERT() is defined in FreeRTOSConfig.h + then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has been + assigned a priority above the configured maximum system call priority. + Only FreeRTOS functions that end in FromISR can be called from interrupts + that have been assigned a priority at or (logically) below the maximum + system call interrupt priority. FreeRTOS maintains a separate interrupt + safe API to ensure interrupt entry is as fast and as simple as possible. + More information (albeit Cortex-M specific) is provided on the following + link: http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + + uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + { + const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting; + + /* When the queue is used to implement a semaphore no data is ever + moved through the queue but it is still valid to see if the queue 'has + space'. */ + if( uxMessagesWaiting < pxQueue->uxLength ) + { + const int8_t cTxLock = pxQueue->cTxLock; + + traceQUEUE_SEND_FROM_ISR( pxQueue ); + + /* A task can only have an inherited priority if it is a mutex + holder - and if there is a mutex holder then the mutex cannot be + given from an ISR. As this is the ISR version of the function it + can be assumed there is no mutex holder and no need to determine if + priority disinheritance is needed. Simply increase the count of + messages (semaphores) available. */ + pxQueue->uxMessagesWaiting = uxMessagesWaiting + 1; + + /* The event list is not altered if the queue is locked. This will + be done when the queue is unlocked later. */ + if( cTxLock == queueUNLOCKED ) + { + #if ( configUSE_QUEUE_SETS == 1 ) + { + if( pxQueue->pxQueueSetContainer != NULL ) + { + if( prvNotifyQueueSetContainer( pxQueue, queueSEND_TO_BACK ) != pdFALSE ) + { + /* The semaphore is a member of a queue set, and + posting to the queue set caused a higher priority + task to unblock. A context switch is required. */ + if( pxHigherPriorityTaskWoken != NULL ) + { + *pxHigherPriorityTaskWoken = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The task waiting has a higher priority so + record that a context switch is required. */ + if( pxHigherPriorityTaskWoken != NULL ) + { + *pxHigherPriorityTaskWoken = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + } + #else /* configUSE_QUEUE_SETS */ + { + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The task waiting has a higher priority so record that a + context switch is required. */ + if( pxHigherPriorityTaskWoken != NULL ) + { + *pxHigherPriorityTaskWoken = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configUSE_QUEUE_SETS */ + } + else + { + /* Increment the lock count so the task that unlocks the queue + knows that data was posted while it was locked. */ + pxQueue->cTxLock = ( int8_t ) ( cTxLock + 1 ); + } + + xReturn = pdPASS; + } + else + { + traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue ); + xReturn = errQUEUE_FULL; + } + } + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t xQueueGenericReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait, const BaseType_t xJustPeeking ) +{ +BaseType_t xEntryTimeSet = pdFALSE; +TimeOut_t xTimeOut; +int8_t *pcOriginalReadPosition; +Queue_t * const pxQueue = ( Queue_t * ) xQueue; + + configASSERT( pxQueue ); + configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) ); + #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) + { + configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) ); + } + #endif + + /* This function relaxes the coding standard somewhat to allow return + statements within the function itself. This is done in the interest + of execution time efficiency. */ + + for( ;; ) + { + taskENTER_CRITICAL(); + { + const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting; + + /* Is there data in the queue now? To be running the calling task + must be the highest priority task wanting to access the queue. */ + if( uxMessagesWaiting > ( UBaseType_t ) 0 ) + { + /* Remember the read position in case the queue is only being + peeked. */ + pcOriginalReadPosition = pxQueue->u.pcReadFrom; + + prvCopyDataFromQueue( pxQueue, pvBuffer ); + + if( xJustPeeking == pdFALSE ) + { + traceQUEUE_RECEIVE( pxQueue ); + + /* Actually removing data, not just peeking. */ + pxQueue->uxMessagesWaiting = uxMessagesWaiting - 1; + + #if ( configUSE_MUTEXES == 1 ) + { + if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) + { + /* Record the information required to implement + priority inheritance should it become necessary. */ + pxQueue->pxMutexHolder = ( int8_t * ) pvTaskIncrementMutexHeldCount(); /*lint !e961 Cast is not redundant as TaskHandle_t is a typedef. */ + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configUSE_MUTEXES */ + + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) + { + queueYIELD_IF_USING_PREEMPTION(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + traceQUEUE_PEEK( pxQueue ); + + /* The data is not being removed, so reset the read + pointer. */ + pxQueue->u.pcReadFrom = pcOriginalReadPosition; + + /* The data is being left in the queue, so see if there are + any other tasks waiting for the data. */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The task waiting has a higher priority than this task. */ + queueYIELD_IF_USING_PREEMPTION(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + + taskEXIT_CRITICAL(); + return pdPASS; + } + else + { + if( xTicksToWait == ( TickType_t ) 0 ) + { + /* The queue was empty and no block time is specified (or + the block time has expired) so leave now. */ + taskEXIT_CRITICAL(); + traceQUEUE_RECEIVE_FAILED( pxQueue ); + return errQUEUE_EMPTY; + } + else if( xEntryTimeSet == pdFALSE ) + { + /* The queue was empty and a block time was specified so + configure the timeout structure. */ + vTaskSetTimeOutState( &xTimeOut ); + xEntryTimeSet = pdTRUE; + } + else + { + /* Entry time was already set. */ + mtCOVERAGE_TEST_MARKER(); + } + } + } + taskEXIT_CRITICAL(); + + /* Interrupts and other tasks can send to and receive from the queue + now the critical section has been exited. */ + + vTaskSuspendAll(); + prvLockQueue( pxQueue ); + + /* Update the timeout state to see if it has expired yet. */ + if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) + { + if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) + { + traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ); + + #if ( configUSE_MUTEXES == 1 ) + { + if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) + { + taskENTER_CRITICAL(); + { + vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder ); + } + taskEXIT_CRITICAL(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif + + vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); + prvUnlockQueue( pxQueue ); + if( xTaskResumeAll() == pdFALSE ) + { + portYIELD_WITHIN_API(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + /* Try again. */ + prvUnlockQueue( pxQueue ); + ( void ) xTaskResumeAll(); + } + } + else + { + prvUnlockQueue( pxQueue ); + ( void ) xTaskResumeAll(); + + if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) + { + traceQUEUE_RECEIVE_FAILED( pxQueue ); + return errQUEUE_EMPTY; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + } +} +/*-----------------------------------------------------------*/ + +BaseType_t xQueueReceiveFromISR( QueueHandle_t xQueue, void * const pvBuffer, BaseType_t * const pxHigherPriorityTaskWoken ) +{ +BaseType_t xReturn; +UBaseType_t uxSavedInterruptStatus; +Queue_t * const pxQueue = ( Queue_t * ) xQueue; + + configASSERT( pxQueue ); + configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) ); + + /* RTOS ports that support interrupt nesting have the concept of a maximum + system call (or maximum API call) interrupt priority. Interrupts that are + above the maximum system call priority are kept permanently enabled, even + when the RTOS kernel is in a critical section, but cannot make any calls to + FreeRTOS API functions. If configASSERT() is defined in FreeRTOSConfig.h + then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has been + assigned a priority above the configured maximum system call priority. + Only FreeRTOS functions that end in FromISR can be called from interrupts + that have been assigned a priority at or (logically) below the maximum + system call interrupt priority. FreeRTOS maintains a separate interrupt + safe API to ensure interrupt entry is as fast and as simple as possible. + More information (albeit Cortex-M specific) is provided on the following + link: http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + + uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + { + const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting; + + /* Cannot block in an ISR, so check there is data available. */ + if( uxMessagesWaiting > ( UBaseType_t ) 0 ) + { + const int8_t cRxLock = pxQueue->cRxLock; + + traceQUEUE_RECEIVE_FROM_ISR( pxQueue ); + + prvCopyDataFromQueue( pxQueue, pvBuffer ); + pxQueue->uxMessagesWaiting = uxMessagesWaiting - 1; + + /* If the queue is locked the event list will not be modified. + Instead update the lock count so the task that unlocks the queue + will know that an ISR has removed data while the queue was + locked. */ + if( cRxLock == queueUNLOCKED ) + { + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) + { + /* The task waiting has a higher priority than us so + force a context switch. */ + if( pxHigherPriorityTaskWoken != NULL ) + { + *pxHigherPriorityTaskWoken = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + /* Increment the lock count so the task that unlocks the queue + knows that data was removed while it was locked. */ + pxQueue->cRxLock = ( int8_t ) ( cRxLock + 1 ); + } + + xReturn = pdPASS; + } + else + { + xReturn = pdFAIL; + traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue ); + } + } + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t xQueuePeekFromISR( QueueHandle_t xQueue, void * const pvBuffer ) +{ +BaseType_t xReturn; +UBaseType_t uxSavedInterruptStatus; +int8_t *pcOriginalReadPosition; +Queue_t * const pxQueue = ( Queue_t * ) xQueue; + + configASSERT( pxQueue ); + configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) ); + configASSERT( pxQueue->uxItemSize != 0 ); /* Can't peek a semaphore. */ + + /* RTOS ports that support interrupt nesting have the concept of a maximum + system call (or maximum API call) interrupt priority. Interrupts that are + above the maximum system call priority are kept permanently enabled, even + when the RTOS kernel is in a critical section, but cannot make any calls to + FreeRTOS API functions. If configASSERT() is defined in FreeRTOSConfig.h + then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has been + assigned a priority above the configured maximum system call priority. + Only FreeRTOS functions that end in FromISR can be called from interrupts + that have been assigned a priority at or (logically) below the maximum + system call interrupt priority. FreeRTOS maintains a separate interrupt + safe API to ensure interrupt entry is as fast and as simple as possible. + More information (albeit Cortex-M specific) is provided on the following + link: http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + + uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + { + /* Cannot block in an ISR, so check there is data available. */ + if( pxQueue->uxMessagesWaiting > ( UBaseType_t ) 0 ) + { + traceQUEUE_PEEK_FROM_ISR( pxQueue ); + + /* Remember the read position so it can be reset as nothing is + actually being removed from the queue. */ + pcOriginalReadPosition = pxQueue->u.pcReadFrom; + prvCopyDataFromQueue( pxQueue, pvBuffer ); + pxQueue->u.pcReadFrom = pcOriginalReadPosition; + + xReturn = pdPASS; + } + else + { + xReturn = pdFAIL; + traceQUEUE_PEEK_FROM_ISR_FAILED( pxQueue ); + } + } + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +UBaseType_t uxQueueMessagesWaiting( const QueueHandle_t xQueue ) +{ +UBaseType_t uxReturn; + + configASSERT( xQueue ); + + taskENTER_CRITICAL(); + { + uxReturn = ( ( Queue_t * ) xQueue )->uxMessagesWaiting; + } + taskEXIT_CRITICAL(); + + return uxReturn; +} /*lint !e818 Pointer cannot be declared const as xQueue is a typedef not pointer. */ +/*-----------------------------------------------------------*/ + +UBaseType_t uxQueueSpacesAvailable( const QueueHandle_t xQueue ) +{ +UBaseType_t uxReturn; +Queue_t *pxQueue; + + pxQueue = ( Queue_t * ) xQueue; + configASSERT( pxQueue ); + + taskENTER_CRITICAL(); + { + uxReturn = pxQueue->uxLength - pxQueue->uxMessagesWaiting; + } + taskEXIT_CRITICAL(); + + return uxReturn; +} /*lint !e818 Pointer cannot be declared const as xQueue is a typedef not pointer. */ +/*-----------------------------------------------------------*/ + +UBaseType_t uxQueueMessagesWaitingFromISR( const QueueHandle_t xQueue ) +{ +UBaseType_t uxReturn; + + configASSERT( xQueue ); + + uxReturn = ( ( Queue_t * ) xQueue )->uxMessagesWaiting; + + return uxReturn; +} /*lint !e818 Pointer cannot be declared const as xQueue is a typedef not pointer. */ +/*-----------------------------------------------------------*/ + +void vQueueDelete( QueueHandle_t xQueue ) +{ +Queue_t * const pxQueue = ( Queue_t * ) xQueue; + + configASSERT( pxQueue ); + traceQUEUE_DELETE( pxQueue ); + + #if ( configQUEUE_REGISTRY_SIZE > 0 ) + { + vQueueUnregisterQueue( pxQueue ); + } + #endif + + #if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) ) + { + /* The queue can only have been allocated dynamically - free it + again. */ + vPortFree( pxQueue ); + } + #elif( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) + { + /* The queue could have been allocated statically or dynamically, so + check before attempting to free the memory. */ + if( pxQueue->ucStaticallyAllocated == ( uint8_t ) pdFALSE ) + { + vPortFree( pxQueue ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #else + { + /* The queue must have been statically allocated, so is not going to be + deleted. Avoid compiler warnings about the unused parameter. */ + ( void ) pxQueue; + } + #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ +} +/*-----------------------------------------------------------*/ + +#if ( configUSE_TRACE_FACILITY == 1 ) + + UBaseType_t uxQueueGetQueueNumber( QueueHandle_t xQueue ) + { + return ( ( Queue_t * ) xQueue )->uxQueueNumber; + } + +#endif /* configUSE_TRACE_FACILITY */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_TRACE_FACILITY == 1 ) + + void vQueueSetQueueNumber( QueueHandle_t xQueue, UBaseType_t uxQueueNumber ) + { + ( ( Queue_t * ) xQueue )->uxQueueNumber = uxQueueNumber; + } + +#endif /* configUSE_TRACE_FACILITY */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_TRACE_FACILITY == 1 ) + + uint8_t ucQueueGetQueueType( QueueHandle_t xQueue ) + { + return ( ( Queue_t * ) xQueue )->ucQueueType; + } + +#endif /* configUSE_TRACE_FACILITY */ +/*-----------------------------------------------------------*/ + +static BaseType_t prvCopyDataToQueue( Queue_t * const pxQueue, const void *pvItemToQueue, const BaseType_t xPosition ) +{ +BaseType_t xReturn = pdFALSE; +UBaseType_t uxMessagesWaiting; + + /* This function is called from a critical section. */ + + uxMessagesWaiting = pxQueue->uxMessagesWaiting; + + if( pxQueue->uxItemSize == ( UBaseType_t ) 0 ) + { + #if ( configUSE_MUTEXES == 1 ) + { + if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) + { + /* The mutex is no longer being held. */ + xReturn = xTaskPriorityDisinherit( ( void * ) pxQueue->pxMutexHolder ); + pxQueue->pxMutexHolder = NULL; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configUSE_MUTEXES */ + } + else if( xPosition == queueSEND_TO_BACK ) + { + ( void ) memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( size_t ) pxQueue->uxItemSize ); /*lint !e961 !e418 MISRA exception as the casts are only redundant for some ports, plus previous logic ensures a null pointer can only be passed to memcpy() if the copy size is 0. */ + pxQueue->pcWriteTo += pxQueue->uxItemSize; + if( pxQueue->pcWriteTo >= pxQueue->pcTail ) /*lint !e946 MISRA exception justified as comparison of pointers is the cleanest solution. */ + { + pxQueue->pcWriteTo = pxQueue->pcHead; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + ( void ) memcpy( ( void * ) pxQueue->u.pcReadFrom, pvItemToQueue, ( size_t ) pxQueue->uxItemSize ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + pxQueue->u.pcReadFrom -= pxQueue->uxItemSize; + if( pxQueue->u.pcReadFrom < pxQueue->pcHead ) /*lint !e946 MISRA exception justified as comparison of pointers is the cleanest solution. */ + { + pxQueue->u.pcReadFrom = ( pxQueue->pcTail - pxQueue->uxItemSize ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + if( xPosition == queueOVERWRITE ) + { + if( uxMessagesWaiting > ( UBaseType_t ) 0 ) + { + /* An item is not being added but overwritten, so subtract + one from the recorded number of items in the queue so when + one is added again below the number of recorded items remains + correct. */ + --uxMessagesWaiting; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + + pxQueue->uxMessagesWaiting = uxMessagesWaiting + 1; + + return xReturn; +} +/*-----------------------------------------------------------*/ + +static void prvCopyDataFromQueue( Queue_t * const pxQueue, void * const pvBuffer ) +{ + if( pxQueue->uxItemSize != ( UBaseType_t ) 0 ) + { + pxQueue->u.pcReadFrom += pxQueue->uxItemSize; + if( pxQueue->u.pcReadFrom >= pxQueue->pcTail ) /*lint !e946 MISRA exception justified as use of the relational operator is the cleanest solutions. */ + { + pxQueue->u.pcReadFrom = pxQueue->pcHead; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + ( void ) memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->u.pcReadFrom, ( size_t ) pxQueue->uxItemSize ); /*lint !e961 !e418 MISRA exception as the casts are only redundant for some ports. Also previous logic ensures a null pointer can only be passed to memcpy() when the count is 0. */ + } +} +/*-----------------------------------------------------------*/ + +static void prvUnlockQueue( Queue_t * const pxQueue ) +{ + /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. */ + + /* The lock counts contains the number of extra data items placed or + removed from the queue while the queue was locked. When a queue is + locked items can be added or removed, but the event lists cannot be + updated. */ + taskENTER_CRITICAL(); + { + int8_t cTxLock = pxQueue->cTxLock; + + /* See if data was added to the queue while it was locked. */ + while( cTxLock > queueLOCKED_UNMODIFIED ) + { + /* Data was posted while the queue was locked. Are any tasks + blocked waiting for data to become available? */ + #if ( configUSE_QUEUE_SETS == 1 ) + { + if( pxQueue->pxQueueSetContainer != NULL ) + { + if( prvNotifyQueueSetContainer( pxQueue, queueSEND_TO_BACK ) != pdFALSE ) + { + /* The queue is a member of a queue set, and posting to + the queue set caused a higher priority task to unblock. + A context switch is required. */ + vTaskMissedYield(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + /* Tasks that are removed from the event list will get + added to the pending ready list as the scheduler is still + suspended. */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The task waiting has a higher priority so record that a + context switch is required. */ + vTaskMissedYield(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + break; + } + } + } + #else /* configUSE_QUEUE_SETS */ + { + /* Tasks that are removed from the event list will get added to + the pending ready list as the scheduler is still suspended. */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The task waiting has a higher priority so record that + a context switch is required. */ + vTaskMissedYield(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + break; + } + } + #endif /* configUSE_QUEUE_SETS */ + + --cTxLock; + } + + pxQueue->cTxLock = queueUNLOCKED; + } + taskEXIT_CRITICAL(); + + /* Do the same for the Rx lock. */ + taskENTER_CRITICAL(); + { + int8_t cRxLock = pxQueue->cRxLock; + + while( cRxLock > queueLOCKED_UNMODIFIED ) + { + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) + { + vTaskMissedYield(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + --cRxLock; + } + else + { + break; + } + } + + pxQueue->cRxLock = queueUNLOCKED; + } + taskEXIT_CRITICAL(); +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvIsQueueEmpty( const Queue_t *pxQueue ) +{ +BaseType_t xReturn; + + taskENTER_CRITICAL(); + { + if( pxQueue->uxMessagesWaiting == ( UBaseType_t ) 0 ) + { + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + } + taskEXIT_CRITICAL(); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t xQueueIsQueueEmptyFromISR( const QueueHandle_t xQueue ) +{ +BaseType_t xReturn; + + configASSERT( xQueue ); + if( ( ( Queue_t * ) xQueue )->uxMessagesWaiting == ( UBaseType_t ) 0 ) + { + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + + return xReturn; +} /*lint !e818 xQueue could not be pointer to const because it is a typedef. */ +/*-----------------------------------------------------------*/ + +static BaseType_t prvIsQueueFull( const Queue_t *pxQueue ) +{ +BaseType_t xReturn; + + taskENTER_CRITICAL(); + { + if( pxQueue->uxMessagesWaiting == pxQueue->uxLength ) + { + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + } + taskEXIT_CRITICAL(); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue ) +{ +BaseType_t xReturn; + + configASSERT( xQueue ); + if( ( ( Queue_t * ) xQueue )->uxMessagesWaiting == ( ( Queue_t * ) xQueue )->uxLength ) + { + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + + return xReturn; +} /*lint !e818 xQueue could not be pointer to const because it is a typedef. */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_CO_ROUTINES == 1 ) + + BaseType_t xQueueCRSend( QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait ) + { + BaseType_t xReturn; + Queue_t * const pxQueue = ( Queue_t * ) xQueue; + + /* If the queue is already full we may have to block. A critical section + is required to prevent an interrupt removing something from the queue + between the check to see if the queue is full and blocking on the queue. */ + portDISABLE_INTERRUPTS(); + { + if( prvIsQueueFull( pxQueue ) != pdFALSE ) + { + /* The queue is full - do we want to block or just leave without + posting? */ + if( xTicksToWait > ( TickType_t ) 0 ) + { + /* As this is called from a coroutine we cannot block directly, but + return indicating that we need to block. */ + vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToSend ) ); + portENABLE_INTERRUPTS(); + return errQUEUE_BLOCKED; + } + else + { + portENABLE_INTERRUPTS(); + return errQUEUE_FULL; + } + } + } + portENABLE_INTERRUPTS(); + + portDISABLE_INTERRUPTS(); + { + if( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) + { + /* There is room in the queue, copy the data into the queue. */ + prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK ); + xReturn = pdPASS; + + /* Were any co-routines waiting for data to become available? */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + /* In this instance the co-routine could be placed directly + into the ready list as we are within a critical section. + Instead the same pending ready list mechanism is used as if + the event were caused from within an interrupt. */ + if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The co-routine waiting has a higher priority so record + that a yield might be appropriate. */ + xReturn = errQUEUE_YIELD; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + xReturn = errQUEUE_FULL; + } + } + portENABLE_INTERRUPTS(); + + return xReturn; + } + +#endif /* configUSE_CO_ROUTINES */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_CO_ROUTINES == 1 ) + + BaseType_t xQueueCRReceive( QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait ) + { + BaseType_t xReturn; + Queue_t * const pxQueue = ( Queue_t * ) xQueue; + + /* If the queue is already empty we may have to block. A critical section + is required to prevent an interrupt adding something to the queue + between the check to see if the queue is empty and blocking on the queue. */ + portDISABLE_INTERRUPTS(); + { + if( pxQueue->uxMessagesWaiting == ( UBaseType_t ) 0 ) + { + /* There are no messages in the queue, do we want to block or just + leave with nothing? */ + if( xTicksToWait > ( TickType_t ) 0 ) + { + /* As this is a co-routine we cannot block directly, but return + indicating that we need to block. */ + vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToReceive ) ); + portENABLE_INTERRUPTS(); + return errQUEUE_BLOCKED; + } + else + { + portENABLE_INTERRUPTS(); + return errQUEUE_FULL; + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + portENABLE_INTERRUPTS(); + + portDISABLE_INTERRUPTS(); + { + if( pxQueue->uxMessagesWaiting > ( UBaseType_t ) 0 ) + { + /* Data is available from the queue. */ + pxQueue->u.pcReadFrom += pxQueue->uxItemSize; + if( pxQueue->u.pcReadFrom >= pxQueue->pcTail ) + { + pxQueue->u.pcReadFrom = pxQueue->pcHead; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + --( pxQueue->uxMessagesWaiting ); + ( void ) memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->u.pcReadFrom, ( unsigned ) pxQueue->uxItemSize ); + + xReturn = pdPASS; + + /* Were any co-routines waiting for space to become available? */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) + { + /* In this instance the co-routine could be placed directly + into the ready list as we are within a critical section. + Instead the same pending ready list mechanism is used as if + the event were caused from within an interrupt. */ + if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) + { + xReturn = errQUEUE_YIELD; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + xReturn = pdFAIL; + } + } + portENABLE_INTERRUPTS(); + + return xReturn; + } + +#endif /* configUSE_CO_ROUTINES */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_CO_ROUTINES == 1 ) + + BaseType_t xQueueCRSendFromISR( QueueHandle_t xQueue, const void *pvItemToQueue, BaseType_t xCoRoutinePreviouslyWoken ) + { + Queue_t * const pxQueue = ( Queue_t * ) xQueue; + + /* Cannot block within an ISR so if there is no space on the queue then + exit without doing anything. */ + if( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) + { + prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK ); + + /* We only want to wake one co-routine per ISR, so check that a + co-routine has not already been woken. */ + if( xCoRoutinePreviouslyWoken == pdFALSE ) + { + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + return pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + return xCoRoutinePreviouslyWoken; + } + +#endif /* configUSE_CO_ROUTINES */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_CO_ROUTINES == 1 ) + + BaseType_t xQueueCRReceiveFromISR( QueueHandle_t xQueue, void *pvBuffer, BaseType_t *pxCoRoutineWoken ) + { + BaseType_t xReturn; + Queue_t * const pxQueue = ( Queue_t * ) xQueue; + + /* We cannot block from an ISR, so check there is data available. If + not then just leave without doing anything. */ + if( pxQueue->uxMessagesWaiting > ( UBaseType_t ) 0 ) + { + /* Copy the data from the queue. */ + pxQueue->u.pcReadFrom += pxQueue->uxItemSize; + if( pxQueue->u.pcReadFrom >= pxQueue->pcTail ) + { + pxQueue->u.pcReadFrom = pxQueue->pcHead; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + --( pxQueue->uxMessagesWaiting ); + ( void ) memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->u.pcReadFrom, ( unsigned ) pxQueue->uxItemSize ); + + if( ( *pxCoRoutineWoken ) == pdFALSE ) + { + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) + { + if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) + { + *pxCoRoutineWoken = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + xReturn = pdPASS; + } + else + { + xReturn = pdFAIL; + } + + return xReturn; + } + +#endif /* configUSE_CO_ROUTINES */ +/*-----------------------------------------------------------*/ + +#if ( configQUEUE_REGISTRY_SIZE > 0 ) + + void vQueueAddToRegistry( QueueHandle_t xQueue, const char *pcQueueName ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + { + UBaseType_t ux; + + /* See if there is an empty space in the registry. A NULL name denotes + a free slot. */ + for( ux = ( UBaseType_t ) 0U; ux < ( UBaseType_t ) configQUEUE_REGISTRY_SIZE; ux++ ) + { + if( xQueueRegistry[ ux ].pcQueueName == NULL ) + { + /* Store the information on this queue. */ + xQueueRegistry[ ux ].pcQueueName = pcQueueName; + xQueueRegistry[ ux ].xHandle = xQueue; + + traceQUEUE_REGISTRY_ADD( xQueue, pcQueueName ); + break; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + } + +#endif /* configQUEUE_REGISTRY_SIZE */ +/*-----------------------------------------------------------*/ + +#if ( configQUEUE_REGISTRY_SIZE > 0 ) + + const char *pcQueueGetName( QueueHandle_t xQueue ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + { + UBaseType_t ux; + const char *pcReturn = NULL; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + + /* Note there is nothing here to protect against another task adding or + removing entries from the registry while it is being searched. */ + for( ux = ( UBaseType_t ) 0U; ux < ( UBaseType_t ) configQUEUE_REGISTRY_SIZE; ux++ ) + { + if( xQueueRegistry[ ux ].xHandle == xQueue ) + { + pcReturn = xQueueRegistry[ ux ].pcQueueName; + break; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + + return pcReturn; + } + +#endif /* configQUEUE_REGISTRY_SIZE */ +/*-----------------------------------------------------------*/ + +#if ( configQUEUE_REGISTRY_SIZE > 0 ) + + void vQueueUnregisterQueue( QueueHandle_t xQueue ) + { + UBaseType_t ux; + + /* See if the handle of the queue being unregistered in actually in the + registry. */ + for( ux = ( UBaseType_t ) 0U; ux < ( UBaseType_t ) configQUEUE_REGISTRY_SIZE; ux++ ) + { + if( xQueueRegistry[ ux ].xHandle == xQueue ) + { + /* Set the name to NULL to show that this slot if free again. */ + xQueueRegistry[ ux ].pcQueueName = NULL; + + /* Set the handle to NULL to ensure the same queue handle cannot + appear in the registry twice if it is added, removed, then + added again. */ + xQueueRegistry[ ux ].xHandle = ( QueueHandle_t ) 0; + break; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + + } /*lint !e818 xQueue could not be pointer to const because it is a typedef. */ + +#endif /* configQUEUE_REGISTRY_SIZE */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_TIMERS == 1 ) + + void vQueueWaitForMessageRestricted( QueueHandle_t xQueue, TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely ) + { + Queue_t * const pxQueue = ( Queue_t * ) xQueue; + + /* This function should not be called by application code hence the + 'Restricted' in its name. It is not part of the public API. It is + designed for use by kernel code, and has special calling requirements. + It can result in vListInsert() being called on a list that can only + possibly ever have one item in it, so the list will be fast, but even + so it should be called with the scheduler locked and not from a critical + section. */ + + /* Only do anything if there are no messages in the queue. This function + will not actually cause the task to block, just place it on a blocked + list. It will not block until the scheduler is unlocked - at which + time a yield will be performed. If an item is added to the queue while + the queue is locked, and the calling task blocks on the queue, then the + calling task will be immediately unblocked when the queue is unlocked. */ + prvLockQueue( pxQueue ); + if( pxQueue->uxMessagesWaiting == ( UBaseType_t ) 0U ) + { + /* There is nothing in the queue, block for the specified period. */ + vTaskPlaceOnEventListRestricted( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait, xWaitIndefinitely ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + prvUnlockQueue( pxQueue ); + } + +#endif /* configUSE_TIMERS */ +/*-----------------------------------------------------------*/ + +#if( ( configUSE_QUEUE_SETS == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + + QueueSetHandle_t xQueueCreateSet( const UBaseType_t uxEventQueueLength ) + { + QueueSetHandle_t pxQueue; + + pxQueue = xQueueGenericCreate( uxEventQueueLength, sizeof( Queue_t * ), queueQUEUE_TYPE_SET ); + + return pxQueue; + } + +#endif /* configUSE_QUEUE_SETS */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_QUEUE_SETS == 1 ) + + BaseType_t xQueueAddToSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet ) + { + BaseType_t xReturn; + + taskENTER_CRITICAL(); + { + if( ( ( Queue_t * ) xQueueOrSemaphore )->pxQueueSetContainer != NULL ) + { + /* Cannot add a queue/semaphore to more than one queue set. */ + xReturn = pdFAIL; + } + else if( ( ( Queue_t * ) xQueueOrSemaphore )->uxMessagesWaiting != ( UBaseType_t ) 0 ) + { + /* Cannot add a queue/semaphore to a queue set if there are already + items in the queue/semaphore. */ + xReturn = pdFAIL; + } + else + { + ( ( Queue_t * ) xQueueOrSemaphore )->pxQueueSetContainer = xQueueSet; + xReturn = pdPASS; + } + } + taskEXIT_CRITICAL(); + + return xReturn; + } + +#endif /* configUSE_QUEUE_SETS */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_QUEUE_SETS == 1 ) + + BaseType_t xQueueRemoveFromSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet ) + { + BaseType_t xReturn; + Queue_t * const pxQueueOrSemaphore = ( Queue_t * ) xQueueOrSemaphore; + + if( pxQueueOrSemaphore->pxQueueSetContainer != xQueueSet ) + { + /* The queue was not a member of the set. */ + xReturn = pdFAIL; + } + else if( pxQueueOrSemaphore->uxMessagesWaiting != ( UBaseType_t ) 0 ) + { + /* It is dangerous to remove a queue from a set when the queue is + not empty because the queue set will still hold pending events for + the queue. */ + xReturn = pdFAIL; + } + else + { + taskENTER_CRITICAL(); + { + /* The queue is no longer contained in the set. */ + pxQueueOrSemaphore->pxQueueSetContainer = NULL; + } + taskEXIT_CRITICAL(); + xReturn = pdPASS; + } + + return xReturn; + } /*lint !e818 xQueueSet could not be declared as pointing to const as it is a typedef. */ + +#endif /* configUSE_QUEUE_SETS */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_QUEUE_SETS == 1 ) + + QueueSetMemberHandle_t xQueueSelectFromSet( QueueSetHandle_t xQueueSet, TickType_t const xTicksToWait ) + { + QueueSetMemberHandle_t xReturn = NULL; + + ( void ) xQueueGenericReceive( ( QueueHandle_t ) xQueueSet, &xReturn, xTicksToWait, pdFALSE ); /*lint !e961 Casting from one typedef to another is not redundant. */ + return xReturn; + } + +#endif /* configUSE_QUEUE_SETS */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_QUEUE_SETS == 1 ) + + QueueSetMemberHandle_t xQueueSelectFromSetFromISR( QueueSetHandle_t xQueueSet ) + { + QueueSetMemberHandle_t xReturn = NULL; + + ( void ) xQueueReceiveFromISR( ( QueueHandle_t ) xQueueSet, &xReturn, NULL ); /*lint !e961 Casting from one typedef to another is not redundant. */ + return xReturn; + } + +#endif /* configUSE_QUEUE_SETS */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_QUEUE_SETS == 1 ) + + static BaseType_t prvNotifyQueueSetContainer( const Queue_t * const pxQueue, const BaseType_t xCopyPosition ) + { + Queue_t *pxQueueSetContainer = pxQueue->pxQueueSetContainer; + BaseType_t xReturn = pdFALSE; + + /* This function must be called form a critical section. */ + + configASSERT( pxQueueSetContainer ); + configASSERT( pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength ); + + if( pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength ) + { + const int8_t cTxLock = pxQueueSetContainer->cTxLock; + + traceQUEUE_SEND( pxQueueSetContainer ); + + /* The data copied is the handle of the queue that contains data. */ + xReturn = prvCopyDataToQueue( pxQueueSetContainer, &pxQueue, xCopyPosition ); + + if( cTxLock == queueUNLOCKED ) + { + if( listLIST_IS_EMPTY( &( pxQueueSetContainer->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueueSetContainer->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The task waiting has a higher priority. */ + xReturn = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + pxQueueSetContainer->cTxLock = ( int8_t ) ( cTxLock + 1 ); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + return xReturn; + } + +#endif /* configUSE_QUEUE_SETS */ + + + + + + + + + + + + diff --git a/STM32F1/libraries/FreeRTOS900/utility/queue.h b/STM32F1/libraries/FreeRTOS900/utility/queue.h new file mode 100644 index 0000000..30be360 --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/utility/queue.h @@ -0,0 +1,1798 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + + +#ifndef QUEUE_H +#define QUEUE_H + +#ifndef INC_FREERTOS_H + #error "include FreeRTOS.h" must appear in source files before "include queue.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * Type by which queues are referenced. For example, a call to xQueueCreate() + * returns an QueueHandle_t variable that can then be used as a parameter to + * xQueueSend(), xQueueReceive(), etc. + */ +typedef void * QueueHandle_t; + +/** + * Type by which queue sets are referenced. For example, a call to + * xQueueCreateSet() returns an xQueueSet variable that can then be used as a + * parameter to xQueueSelectFromSet(), xQueueAddToSet(), etc. + */ +typedef void * QueueSetHandle_t; + +/** + * Queue sets can contain both queues and semaphores, so the + * QueueSetMemberHandle_t is defined as a type to be used where a parameter or + * return value can be either an QueueHandle_t or an SemaphoreHandle_t. + */ +typedef void * QueueSetMemberHandle_t; + +/* For internal use only. */ +#define queueSEND_TO_BACK ( ( BaseType_t ) 0 ) +#define queueSEND_TO_FRONT ( ( BaseType_t ) 1 ) +#define queueOVERWRITE ( ( BaseType_t ) 2 ) + +/* For internal use only. These definitions *must* match those in queue.c. */ +#define queueQUEUE_TYPE_BASE ( ( uint8_t ) 0U ) +#define queueQUEUE_TYPE_SET ( ( uint8_t ) 0U ) +#define queueQUEUE_TYPE_MUTEX ( ( uint8_t ) 1U ) +#define queueQUEUE_TYPE_COUNTING_SEMAPHORE ( ( uint8_t ) 2U ) +#define queueQUEUE_TYPE_BINARY_SEMAPHORE ( ( uint8_t ) 3U ) +#define queueQUEUE_TYPE_RECURSIVE_MUTEX ( ( uint8_t ) 4U ) + +/** + * queue. h + *
+ QueueHandle_t xQueueCreate(
+							  UBaseType_t uxQueueLength,
+							  UBaseType_t uxItemSize
+						  );
+ * 
+ * + * Creates a new queue instance, and returns a handle by which the new queue + * can be referenced. + * + * Internally, within the FreeRTOS implementation, queues use two blocks of + * memory. The first block is used to hold the queue's data structures. The + * second block is used to hold items placed into the queue. If a queue is + * created using xQueueCreate() then both blocks of memory are automatically + * dynamically allocated inside the xQueueCreate() function. (see + * http://www.freertos.org/a00111.html). If a queue is created using + * xQueueCreateStatic() then the application writer must provide the memory that + * will get used by the queue. xQueueCreateStatic() therefore allows a queue to + * be created without using any dynamic memory allocation. + * + * http://www.FreeRTOS.org/Embedded-RTOS-Queues.html + * + * @param uxQueueLength The maximum number of items that the queue can contain. + * + * @param uxItemSize The number of bytes each item in the queue will require. + * Items are queued by copy, not by reference, so this is the number of bytes + * that will be copied for each posted item. Each item on the queue must be + * the same size. + * + * @return If the queue is successfully create then a handle to the newly + * created queue is returned. If the queue cannot be created then 0 is + * returned. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ };
+
+ void vATask( void *pvParameters )
+ {
+ QueueHandle_t xQueue1, xQueue2;
+
+	// Create a queue capable of containing 10 uint32_t values.
+	xQueue1 = xQueueCreate( 10, sizeof( uint32_t ) );
+	if( xQueue1 == 0 )
+	{
+		// Queue was not created and must not be used.
+	}
+
+	// Create a queue capable of containing 10 pointers to AMessage structures.
+	// These should be passed by pointer as they contain a lot of data.
+	xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+	if( xQueue2 == 0 )
+	{
+		// Queue was not created and must not be used.
+	}
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueCreate xQueueCreate + * \ingroup QueueManagement + */ +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + #define xQueueCreate( uxQueueLength, uxItemSize ) xQueueGenericCreate( ( uxQueueLength ), ( uxItemSize ), ( queueQUEUE_TYPE_BASE ) ) +#endif + +/** + * queue. h + *
+ QueueHandle_t xQueueCreateStatic(
+							  UBaseType_t uxQueueLength,
+							  UBaseType_t uxItemSize,
+							  uint8_t *pucQueueStorageBuffer,
+							  StaticQueue_t *pxQueueBuffer
+						  );
+ * 
+ * + * Creates a new queue instance, and returns a handle by which the new queue + * can be referenced. + * + * Internally, within the FreeRTOS implementation, queues use two blocks of + * memory. The first block is used to hold the queue's data structures. The + * second block is used to hold items placed into the queue. If a queue is + * created using xQueueCreate() then both blocks of memory are automatically + * dynamically allocated inside the xQueueCreate() function. (see + * http://www.freertos.org/a00111.html). If a queue is created using + * xQueueCreateStatic() then the application writer must provide the memory that + * will get used by the queue. xQueueCreateStatic() therefore allows a queue to + * be created without using any dynamic memory allocation. + * + * http://www.FreeRTOS.org/Embedded-RTOS-Queues.html + * + * @param uxQueueLength The maximum number of items that the queue can contain. + * + * @param uxItemSize The number of bytes each item in the queue will require. + * Items are queued by copy, not by reference, so this is the number of bytes + * that will be copied for each posted item. Each item on the queue must be + * the same size. + * + * @param pucQueueStorageBuffer If uxItemSize is not zero then + * pucQueueStorageBuffer must point to a uint8_t array that is at least large + * enough to hold the maximum number of items that can be in the queue at any + * one time - which is ( uxQueueLength * uxItemsSize ) bytes. If uxItemSize is + * zero then pucQueueStorageBuffer can be NULL. + * + * @param pxQueueBuffer Must point to a variable of type StaticQueue_t, which + * will be used to hold the queue's data structure. + * + * @return If the queue is created then a handle to the created queue is + * returned. If pxQueueBuffer is NULL then NULL is returned. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ };
+
+ #define QUEUE_LENGTH 10
+ #define ITEM_SIZE sizeof( uint32_t )
+
+ // xQueueBuffer will hold the queue structure.
+ StaticQueue_t xQueueBuffer;
+
+ // ucQueueStorage will hold the items posted to the queue.  Must be at least
+ // [(queue length) * ( queue item size)] bytes long.
+ uint8_t ucQueueStorage[ QUEUE_LENGTH * ITEM_SIZE ];
+
+ void vATask( void *pvParameters )
+ {
+ QueueHandle_t xQueue1;
+
+	// Create a queue capable of containing 10 uint32_t values.
+	xQueue1 = xQueueCreate( QUEUE_LENGTH, // The number of items the queue can hold.
+							ITEM_SIZE	  // The size of each item in the queue
+							&( ucQueueStorage[ 0 ] ), // The buffer that will hold the items in the queue.
+							&xQueueBuffer ); // The buffer that will hold the queue structure.
+
+	// The queue is guaranteed to be created successfully as no dynamic memory
+	// allocation is used.  Therefore xQueue1 is now a handle to a valid queue.
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueCreateStatic xQueueCreateStatic + * \ingroup QueueManagement + */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + #define xQueueCreateStatic( uxQueueLength, uxItemSize, pucQueueStorage, pxQueueBuffer ) xQueueGenericCreateStatic( ( uxQueueLength ), ( uxItemSize ), ( pucQueueStorage ), ( pxQueueBuffer ), ( queueQUEUE_TYPE_BASE ) ) +#endif /* configSUPPORT_STATIC_ALLOCATION */ + +/** + * queue. h + *
+ BaseType_t xQueueSendToToFront(
+								   QueueHandle_t	xQueue,
+								   const void		*pvItemToQueue,
+								   TickType_t		xTicksToWait
+							   );
+ * 
+ * + * This is a macro that calls xQueueGenericSend(). + * + * Post an item to the front of a queue. The item is queued by copy, not by + * reference. This function must not be called from an interrupt service + * routine. See xQueueSendFromISR () for an alternative which may be used + * in an ISR. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param xTicksToWait The maximum amount of time the task should block + * waiting for space to become available on the queue, should it already + * be full. The call will return immediately if this is set to 0 and the + * queue is full. The time is defined in tick periods so the constant + * portTICK_PERIOD_MS should be used to convert to real time if this is required. + * + * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ } xMessage;
+
+ uint32_t ulVar = 10UL;
+
+ void vATask( void *pvParameters )
+ {
+ QueueHandle_t xQueue1, xQueue2;
+ struct AMessage *pxMessage;
+
+	// Create a queue capable of containing 10 uint32_t values.
+	xQueue1 = xQueueCreate( 10, sizeof( uint32_t ) );
+
+	// Create a queue capable of containing 10 pointers to AMessage structures.
+	// These should be passed by pointer as they contain a lot of data.
+	xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+
+	// ...
+
+	if( xQueue1 != 0 )
+	{
+		// Send an uint32_t.  Wait for 10 ticks for space to become
+		// available if necessary.
+		if( xQueueSendToFront( xQueue1, ( void * ) &ulVar, ( TickType_t ) 10 ) != pdPASS )
+		{
+			// Failed to post the message, even after 10 ticks.
+		}
+	}
+
+	if( xQueue2 != 0 )
+	{
+		// Send a pointer to a struct AMessage object.  Don't block if the
+		// queue is already full.
+		pxMessage = & xMessage;
+		xQueueSendToFront( xQueue2, ( void * ) &pxMessage, ( TickType_t ) 0 );
+	}
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueSend xQueueSend + * \ingroup QueueManagement + */ +#define xQueueSendToFront( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_FRONT ) + +/** + * queue. h + *
+ BaseType_t xQueueSendToBack(
+								   QueueHandle_t	xQueue,
+								   const void		*pvItemToQueue,
+								   TickType_t		xTicksToWait
+							   );
+ * 
+ * + * This is a macro that calls xQueueGenericSend(). + * + * Post an item to the back of a queue. The item is queued by copy, not by + * reference. This function must not be called from an interrupt service + * routine. See xQueueSendFromISR () for an alternative which may be used + * in an ISR. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param xTicksToWait The maximum amount of time the task should block + * waiting for space to become available on the queue, should it already + * be full. The call will return immediately if this is set to 0 and the queue + * is full. The time is defined in tick periods so the constant + * portTICK_PERIOD_MS should be used to convert to real time if this is required. + * + * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ } xMessage;
+
+ uint32_t ulVar = 10UL;
+
+ void vATask( void *pvParameters )
+ {
+ QueueHandle_t xQueue1, xQueue2;
+ struct AMessage *pxMessage;
+
+	// Create a queue capable of containing 10 uint32_t values.
+	xQueue1 = xQueueCreate( 10, sizeof( uint32_t ) );
+
+	// Create a queue capable of containing 10 pointers to AMessage structures.
+	// These should be passed by pointer as they contain a lot of data.
+	xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+
+	// ...
+
+	if( xQueue1 != 0 )
+	{
+		// Send an uint32_t.  Wait for 10 ticks for space to become
+		// available if necessary.
+		if( xQueueSendToBack( xQueue1, ( void * ) &ulVar, ( TickType_t ) 10 ) != pdPASS )
+		{
+			// Failed to post the message, even after 10 ticks.
+		}
+	}
+
+	if( xQueue2 != 0 )
+	{
+		// Send a pointer to a struct AMessage object.  Don't block if the
+		// queue is already full.
+		pxMessage = & xMessage;
+		xQueueSendToBack( xQueue2, ( void * ) &pxMessage, ( TickType_t ) 0 );
+	}
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueSend xQueueSend + * \ingroup QueueManagement + */ +#define xQueueSendToBack( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK ) + +/** + * queue. h + *
+ BaseType_t xQueueSend(
+							  QueueHandle_t xQueue,
+							  const void * pvItemToQueue,
+							  TickType_t xTicksToWait
+						 );
+ * 
+ * + * This is a macro that calls xQueueGenericSend(). It is included for + * backward compatibility with versions of FreeRTOS.org that did not + * include the xQueueSendToFront() and xQueueSendToBack() macros. It is + * equivalent to xQueueSendToBack(). + * + * Post an item on a queue. The item is queued by copy, not by reference. + * This function must not be called from an interrupt service routine. + * See xQueueSendFromISR () for an alternative which may be used in an ISR. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param xTicksToWait The maximum amount of time the task should block + * waiting for space to become available on the queue, should it already + * be full. The call will return immediately if this is set to 0 and the + * queue is full. The time is defined in tick periods so the constant + * portTICK_PERIOD_MS should be used to convert to real time if this is required. + * + * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ } xMessage;
+
+ uint32_t ulVar = 10UL;
+
+ void vATask( void *pvParameters )
+ {
+ QueueHandle_t xQueue1, xQueue2;
+ struct AMessage *pxMessage;
+
+	// Create a queue capable of containing 10 uint32_t values.
+	xQueue1 = xQueueCreate( 10, sizeof( uint32_t ) );
+
+	// Create a queue capable of containing 10 pointers to AMessage structures.
+	// These should be passed by pointer as they contain a lot of data.
+	xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+
+	// ...
+
+	if( xQueue1 != 0 )
+	{
+		// Send an uint32_t.  Wait for 10 ticks for space to become
+		// available if necessary.
+		if( xQueueSend( xQueue1, ( void * ) &ulVar, ( TickType_t ) 10 ) != pdPASS )
+		{
+			// Failed to post the message, even after 10 ticks.
+		}
+	}
+
+	if( xQueue2 != 0 )
+	{
+		// Send a pointer to a struct AMessage object.  Don't block if the
+		// queue is already full.
+		pxMessage = & xMessage;
+		xQueueSend( xQueue2, ( void * ) &pxMessage, ( TickType_t ) 0 );
+	}
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueSend xQueueSend + * \ingroup QueueManagement + */ +#define xQueueSend( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK ) + +/** + * queue. h + *
+ BaseType_t xQueueOverwrite(
+							  QueueHandle_t xQueue,
+							  const void * pvItemToQueue
+						 );
+ * 
+ * + * Only for use with queues that have a length of one - so the queue is either + * empty or full. + * + * Post an item on a queue. If the queue is already full then overwrite the + * value held in the queue. The item is queued by copy, not by reference. + * + * This function must not be called from an interrupt service routine. + * See xQueueOverwriteFromISR () for an alternative which may be used in an ISR. + * + * @param xQueue The handle of the queue to which the data is being sent. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @return xQueueOverwrite() is a macro that calls xQueueGenericSend(), and + * therefore has the same return values as xQueueSendToFront(). However, pdPASS + * is the only value that can be returned because xQueueOverwrite() will write + * to the queue even when the queue is already full. + * + * Example usage: +
+
+ void vFunction( void *pvParameters )
+ {
+ QueueHandle_t xQueue;
+ uint32_t ulVarToSend, ulValReceived;
+
+	// Create a queue to hold one uint32_t value.  It is strongly
+	// recommended *not* to use xQueueOverwrite() on queues that can
+	// contain more than one value, and doing so will trigger an assertion
+	// if configASSERT() is defined.
+	xQueue = xQueueCreate( 1, sizeof( uint32_t ) );
+
+	// Write the value 10 to the queue using xQueueOverwrite().
+	ulVarToSend = 10;
+	xQueueOverwrite( xQueue, &ulVarToSend );
+
+	// Peeking the queue should now return 10, but leave the value 10 in
+	// the queue.  A block time of zero is used as it is known that the
+	// queue holds a value.
+	ulValReceived = 0;
+	xQueuePeek( xQueue, &ulValReceived, 0 );
+
+	if( ulValReceived != 10 )
+	{
+		// Error unless the item was removed by a different task.
+	}
+
+	// The queue is still full.  Use xQueueOverwrite() to overwrite the
+	// value held in the queue with 100.
+	ulVarToSend = 100;
+	xQueueOverwrite( xQueue, &ulVarToSend );
+
+	// This time read from the queue, leaving the queue empty once more.
+	// A block time of 0 is used again.
+	xQueueReceive( xQueue, &ulValReceived, 0 );
+
+	// The value read should be the last value written, even though the
+	// queue was already full when the value was written.
+	if( ulValReceived != 100 )
+	{
+		// Error!
+	}
+
+	// ...
+}
+ 
+ * \defgroup xQueueOverwrite xQueueOverwrite + * \ingroup QueueManagement + */ +#define xQueueOverwrite( xQueue, pvItemToQueue ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), 0, queueOVERWRITE ) + + +/** + * queue. h + *
+ BaseType_t xQueueGenericSend(
+									QueueHandle_t xQueue,
+									const void * pvItemToQueue,
+									TickType_t xTicksToWait
+									BaseType_t xCopyPosition
+								);
+ * 
+ * + * It is preferred that the macros xQueueSend(), xQueueSendToFront() and + * xQueueSendToBack() are used in place of calling this function directly. + * + * Post an item on a queue. The item is queued by copy, not by reference. + * This function must not be called from an interrupt service routine. + * See xQueueSendFromISR () for an alternative which may be used in an ISR. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param xTicksToWait The maximum amount of time the task should block + * waiting for space to become available on the queue, should it already + * be full. The call will return immediately if this is set to 0 and the + * queue is full. The time is defined in tick periods so the constant + * portTICK_PERIOD_MS should be used to convert to real time if this is required. + * + * @param xCopyPosition Can take the value queueSEND_TO_BACK to place the + * item at the back of the queue, or queueSEND_TO_FRONT to place the item + * at the front of the queue (for high priority messages). + * + * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ } xMessage;
+
+ uint32_t ulVar = 10UL;
+
+ void vATask( void *pvParameters )
+ {
+ QueueHandle_t xQueue1, xQueue2;
+ struct AMessage *pxMessage;
+
+	// Create a queue capable of containing 10 uint32_t values.
+	xQueue1 = xQueueCreate( 10, sizeof( uint32_t ) );
+
+	// Create a queue capable of containing 10 pointers to AMessage structures.
+	// These should be passed by pointer as they contain a lot of data.
+	xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+
+	// ...
+
+	if( xQueue1 != 0 )
+	{
+		// Send an uint32_t.  Wait for 10 ticks for space to become
+		// available if necessary.
+		if( xQueueGenericSend( xQueue1, ( void * ) &ulVar, ( TickType_t ) 10, queueSEND_TO_BACK ) != pdPASS )
+		{
+			// Failed to post the message, even after 10 ticks.
+		}
+	}
+
+	if( xQueue2 != 0 )
+	{
+		// Send a pointer to a struct AMessage object.  Don't block if the
+		// queue is already full.
+		pxMessage = & xMessage;
+		xQueueGenericSend( xQueue2, ( void * ) &pxMessage, ( TickType_t ) 0, queueSEND_TO_BACK );
+	}
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueSend xQueueSend + * \ingroup QueueManagement + */ +BaseType_t xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition ) PRIVILEGED_FUNCTION; + +/** + * queue. h + *
+ BaseType_t xQueuePeek(
+							 QueueHandle_t xQueue,
+							 void *pvBuffer,
+							 TickType_t xTicksToWait
+						 );
+ * + * This is a macro that calls the xQueueGenericReceive() function. + * + * Receive an item from a queue without removing the item from the queue. + * The item is received by copy so a buffer of adequate size must be + * provided. The number of bytes copied into the buffer was defined when + * the queue was created. + * + * Successfully received items remain on the queue so will be returned again + * by the next call, or a call to xQueueReceive(). + * + * This macro must not be used in an interrupt service routine. See + * xQueuePeekFromISR() for an alternative that can be called from an interrupt + * service routine. + * + * @param xQueue The handle to the queue from which the item is to be + * received. + * + * @param pvBuffer Pointer to the buffer into which the received item will + * be copied. + * + * @param xTicksToWait The maximum amount of time the task should block + * waiting for an item to receive should the queue be empty at the time + * of the call. The time is defined in tick periods so the constant + * portTICK_PERIOD_MS should be used to convert to real time if this is required. + * xQueuePeek() will return immediately if xTicksToWait is 0 and the queue + * is empty. + * + * @return pdTRUE if an item was successfully received from the queue, + * otherwise pdFALSE. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ } xMessage;
+
+ QueueHandle_t xQueue;
+
+ // Task to create a queue and post a value.
+ void vATask( void *pvParameters )
+ {
+ struct AMessage *pxMessage;
+
+	// Create a queue capable of containing 10 pointers to AMessage structures.
+	// These should be passed by pointer as they contain a lot of data.
+	xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );
+	if( xQueue == 0 )
+	{
+		// Failed to create the queue.
+	}
+
+	// ...
+
+	// Send a pointer to a struct AMessage object.  Don't block if the
+	// queue is already full.
+	pxMessage = & xMessage;
+	xQueueSend( xQueue, ( void * ) &pxMessage, ( TickType_t ) 0 );
+
+	// ... Rest of task code.
+ }
+
+ // Task to peek the data from the queue.
+ void vADifferentTask( void *pvParameters )
+ {
+ struct AMessage *pxRxedMessage;
+
+	if( xQueue != 0 )
+	{
+		// Peek a message on the created queue.  Block for 10 ticks if a
+		// message is not immediately available.
+		if( xQueuePeek( xQueue, &( pxRxedMessage ), ( TickType_t ) 10 ) )
+		{
+			// pcRxedMessage now points to the struct AMessage variable posted
+			// by vATask, but the item still remains on the queue.
+		}
+	}
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueReceive xQueueReceive + * \ingroup QueueManagement + */ +#define xQueuePeek( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdTRUE ) + +/** + * queue. h + *
+ BaseType_t xQueuePeekFromISR(
+									QueueHandle_t xQueue,
+									void *pvBuffer,
+								);
+ * + * A version of xQueuePeek() that can be called from an interrupt service + * routine (ISR). + * + * Receive an item from a queue without removing the item from the queue. + * The item is received by copy so a buffer of adequate size must be + * provided. The number of bytes copied into the buffer was defined when + * the queue was created. + * + * Successfully received items remain on the queue so will be returned again + * by the next call, or a call to xQueueReceive(). + * + * @param xQueue The handle to the queue from which the item is to be + * received. + * + * @param pvBuffer Pointer to the buffer into which the received item will + * be copied. + * + * @return pdTRUE if an item was successfully received from the queue, + * otherwise pdFALSE. + * + * \defgroup xQueuePeekFromISR xQueuePeekFromISR + * \ingroup QueueManagement + */ +BaseType_t xQueuePeekFromISR( QueueHandle_t xQueue, void * const pvBuffer ) PRIVILEGED_FUNCTION; + +/** + * queue. h + *
+ BaseType_t xQueueReceive(
+								 QueueHandle_t xQueue,
+								 void *pvBuffer,
+								 TickType_t xTicksToWait
+							);
+ * + * This is a macro that calls the xQueueGenericReceive() function. + * + * Receive an item from a queue. The item is received by copy so a buffer of + * adequate size must be provided. The number of bytes copied into the buffer + * was defined when the queue was created. + * + * Successfully received items are removed from the queue. + * + * This function must not be used in an interrupt service routine. See + * xQueueReceiveFromISR for an alternative that can. + * + * @param xQueue The handle to the queue from which the item is to be + * received. + * + * @param pvBuffer Pointer to the buffer into which the received item will + * be copied. + * + * @param xTicksToWait The maximum amount of time the task should block + * waiting for an item to receive should the queue be empty at the time + * of the call. xQueueReceive() will return immediately if xTicksToWait + * is zero and the queue is empty. The time is defined in tick periods so the + * constant portTICK_PERIOD_MS should be used to convert to real time if this is + * required. + * + * @return pdTRUE if an item was successfully received from the queue, + * otherwise pdFALSE. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ } xMessage;
+
+ QueueHandle_t xQueue;
+
+ // Task to create a queue and post a value.
+ void vATask( void *pvParameters )
+ {
+ struct AMessage *pxMessage;
+
+	// Create a queue capable of containing 10 pointers to AMessage structures.
+	// These should be passed by pointer as they contain a lot of data.
+	xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );
+	if( xQueue == 0 )
+	{
+		// Failed to create the queue.
+	}
+
+	// ...
+
+	// Send a pointer to a struct AMessage object.  Don't block if the
+	// queue is already full.
+	pxMessage = & xMessage;
+	xQueueSend( xQueue, ( void * ) &pxMessage, ( TickType_t ) 0 );
+
+	// ... Rest of task code.
+ }
+
+ // Task to receive from the queue.
+ void vADifferentTask( void *pvParameters )
+ {
+ struct AMessage *pxRxedMessage;
+
+	if( xQueue != 0 )
+	{
+		// Receive a message on the created queue.  Block for 10 ticks if a
+		// message is not immediately available.
+		if( xQueueReceive( xQueue, &( pxRxedMessage ), ( TickType_t ) 10 ) )
+		{
+			// pcRxedMessage now points to the struct AMessage variable posted
+			// by vATask.
+		}
+	}
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueReceive xQueueReceive + * \ingroup QueueManagement + */ +#define xQueueReceive( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdFALSE ) + + +/** + * queue. h + *
+ BaseType_t xQueueGenericReceive(
+									   QueueHandle_t	xQueue,
+									   void	*pvBuffer,
+									   TickType_t	xTicksToWait
+									   BaseType_t	xJustPeek
+									);
+ * + * It is preferred that the macro xQueueReceive() be used rather than calling + * this function directly. + * + * Receive an item from a queue. The item is received by copy so a buffer of + * adequate size must be provided. The number of bytes copied into the buffer + * was defined when the queue was created. + * + * This function must not be used in an interrupt service routine. See + * xQueueReceiveFromISR for an alternative that can. + * + * @param xQueue The handle to the queue from which the item is to be + * received. + * + * @param pvBuffer Pointer to the buffer into which the received item will + * be copied. + * + * @param xTicksToWait The maximum amount of time the task should block + * waiting for an item to receive should the queue be empty at the time + * of the call. The time is defined in tick periods so the constant + * portTICK_PERIOD_MS should be used to convert to real time if this is required. + * xQueueGenericReceive() will return immediately if the queue is empty and + * xTicksToWait is 0. + * + * @param xJustPeek When set to true, the item received from the queue is not + * actually removed from the queue - meaning a subsequent call to + * xQueueReceive() will return the same item. When set to false, the item + * being received from the queue is also removed from the queue. + * + * @return pdTRUE if an item was successfully received from the queue, + * otherwise pdFALSE. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ } xMessage;
+
+ QueueHandle_t xQueue;
+
+ // Task to create a queue and post a value.
+ void vATask( void *pvParameters )
+ {
+ struct AMessage *pxMessage;
+
+	// Create a queue capable of containing 10 pointers to AMessage structures.
+	// These should be passed by pointer as they contain a lot of data.
+	xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );
+	if( xQueue == 0 )
+	{
+		// Failed to create the queue.
+	}
+
+	// ...
+
+	// Send a pointer to a struct AMessage object.  Don't block if the
+	// queue is already full.
+	pxMessage = & xMessage;
+	xQueueSend( xQueue, ( void * ) &pxMessage, ( TickType_t ) 0 );
+
+	// ... Rest of task code.
+ }
+
+ // Task to receive from the queue.
+ void vADifferentTask( void *pvParameters )
+ {
+ struct AMessage *pxRxedMessage;
+
+	if( xQueue != 0 )
+	{
+		// Receive a message on the created queue.  Block for 10 ticks if a
+		// message is not immediately available.
+		if( xQueueGenericReceive( xQueue, &( pxRxedMessage ), ( TickType_t ) 10 ) )
+		{
+			// pcRxedMessage now points to the struct AMessage variable posted
+			// by vATask.
+		}
+	}
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueReceive xQueueReceive + * \ingroup QueueManagement + */ +BaseType_t xQueueGenericReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait, const BaseType_t xJustPeek ) PRIVILEGED_FUNCTION; + +/** + * queue. h + *
UBaseType_t uxQueueMessagesWaiting( const QueueHandle_t xQueue );
+ * + * Return the number of messages stored in a queue. + * + * @param xQueue A handle to the queue being queried. + * + * @return The number of messages available in the queue. + * + * \defgroup uxQueueMessagesWaiting uxQueueMessagesWaiting + * \ingroup QueueManagement + */ +UBaseType_t uxQueueMessagesWaiting( const QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; + +/** + * queue. h + *
UBaseType_t uxQueueSpacesAvailable( const QueueHandle_t xQueue );
+ * + * Return the number of free spaces available in a queue. This is equal to the + * number of items that can be sent to the queue before the queue becomes full + * if no items are removed. + * + * @param xQueue A handle to the queue being queried. + * + * @return The number of spaces available in the queue. + * + * \defgroup uxQueueMessagesWaiting uxQueueMessagesWaiting + * \ingroup QueueManagement + */ +UBaseType_t uxQueueSpacesAvailable( const QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; + +/** + * queue. h + *
void vQueueDelete( QueueHandle_t xQueue );
+ * + * Delete a queue - freeing all the memory allocated for storing of items + * placed on the queue. + * + * @param xQueue A handle to the queue to be deleted. + * + * \defgroup vQueueDelete vQueueDelete + * \ingroup QueueManagement + */ +void vQueueDelete( QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; + +/** + * queue. h + *
+ BaseType_t xQueueSendToFrontFromISR(
+										 QueueHandle_t xQueue,
+										 const void *pvItemToQueue,
+										 BaseType_t *pxHigherPriorityTaskWoken
+									  );
+ 
+ * + * This is a macro that calls xQueueGenericSendFromISR(). + * + * Post an item to the front of a queue. It is safe to use this macro from + * within an interrupt service routine. + * + * Items are queued by copy not reference so it is preferable to only + * queue small items, especially when called from an ISR. In most cases + * it would be preferable to store a pointer to the item being queued. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param pxHigherPriorityTaskWoken xQueueSendToFrontFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task + * to unblock, and the unblocked task has a priority higher than the currently + * running task. If xQueueSendToFromFromISR() sets this value to pdTRUE then + * a context switch should be requested before the interrupt is exited. + * + * @return pdTRUE if the data was successfully sent to the queue, otherwise + * errQUEUE_FULL. + * + * Example usage for buffered IO (where the ISR can obtain more than one value + * per call): +
+ void vBufferISR( void )
+ {
+ char cIn;
+ BaseType_t xHigherPrioritTaskWoken;
+
+	// We have not woken a task at the start of the ISR.
+	xHigherPriorityTaskWoken = pdFALSE;
+
+	// Loop until the buffer is empty.
+	do
+	{
+		// Obtain a byte from the buffer.
+		cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
+
+		// Post the byte.
+		xQueueSendToFrontFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWoken );
+
+	} while( portINPUT_BYTE( BUFFER_COUNT ) );
+
+	// Now the buffer is empty we can switch context if necessary.
+	if( xHigherPriorityTaskWoken )
+	{
+		taskYIELD ();
+	}
+ }
+ 
+ * + * \defgroup xQueueSendFromISR xQueueSendFromISR + * \ingroup QueueManagement + */ +#define xQueueSendToFrontFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( xQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_FRONT ) + + +/** + * queue. h + *
+ BaseType_t xQueueSendToBackFromISR(
+										 QueueHandle_t xQueue,
+										 const void *pvItemToQueue,
+										 BaseType_t *pxHigherPriorityTaskWoken
+									  );
+ 
+ * + * This is a macro that calls xQueueGenericSendFromISR(). + * + * Post an item to the back of a queue. It is safe to use this macro from + * within an interrupt service routine. + * + * Items are queued by copy not reference so it is preferable to only + * queue small items, especially when called from an ISR. In most cases + * it would be preferable to store a pointer to the item being queued. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param pxHigherPriorityTaskWoken xQueueSendToBackFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task + * to unblock, and the unblocked task has a priority higher than the currently + * running task. If xQueueSendToBackFromISR() sets this value to pdTRUE then + * a context switch should be requested before the interrupt is exited. + * + * @return pdTRUE if the data was successfully sent to the queue, otherwise + * errQUEUE_FULL. + * + * Example usage for buffered IO (where the ISR can obtain more than one value + * per call): +
+ void vBufferISR( void )
+ {
+ char cIn;
+ BaseType_t xHigherPriorityTaskWoken;
+
+	// We have not woken a task at the start of the ISR.
+	xHigherPriorityTaskWoken = pdFALSE;
+
+	// Loop until the buffer is empty.
+	do
+	{
+		// Obtain a byte from the buffer.
+		cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
+
+		// Post the byte.
+		xQueueSendToBackFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWoken );
+
+	} while( portINPUT_BYTE( BUFFER_COUNT ) );
+
+	// Now the buffer is empty we can switch context if necessary.
+	if( xHigherPriorityTaskWoken )
+	{
+		taskYIELD ();
+	}
+ }
+ 
+ * + * \defgroup xQueueSendFromISR xQueueSendFromISR + * \ingroup QueueManagement + */ +#define xQueueSendToBackFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( xQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_BACK ) + +/** + * queue. h + *
+ BaseType_t xQueueOverwriteFromISR(
+							  QueueHandle_t xQueue,
+							  const void * pvItemToQueue,
+							  BaseType_t *pxHigherPriorityTaskWoken
+						 );
+ * 
+ * + * A version of xQueueOverwrite() that can be used in an interrupt service + * routine (ISR). + * + * Only for use with queues that can hold a single item - so the queue is either + * empty or full. + * + * Post an item on a queue. If the queue is already full then overwrite the + * value held in the queue. The item is queued by copy, not by reference. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param pxHigherPriorityTaskWoken xQueueOverwriteFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task + * to unblock, and the unblocked task has a priority higher than the currently + * running task. If xQueueOverwriteFromISR() sets this value to pdTRUE then + * a context switch should be requested before the interrupt is exited. + * + * @return xQueueOverwriteFromISR() is a macro that calls + * xQueueGenericSendFromISR(), and therefore has the same return values as + * xQueueSendToFrontFromISR(). However, pdPASS is the only value that can be + * returned because xQueueOverwriteFromISR() will write to the queue even when + * the queue is already full. + * + * Example usage: +
+
+ QueueHandle_t xQueue;
+
+ void vFunction( void *pvParameters )
+ {
+ 	// Create a queue to hold one uint32_t value.  It is strongly
+	// recommended *not* to use xQueueOverwriteFromISR() on queues that can
+	// contain more than one value, and doing so will trigger an assertion
+	// if configASSERT() is defined.
+	xQueue = xQueueCreate( 1, sizeof( uint32_t ) );
+}
+
+void vAnInterruptHandler( void )
+{
+// xHigherPriorityTaskWoken must be set to pdFALSE before it is used.
+BaseType_t xHigherPriorityTaskWoken = pdFALSE;
+uint32_t ulVarToSend, ulValReceived;
+
+	// Write the value 10 to the queue using xQueueOverwriteFromISR().
+	ulVarToSend = 10;
+	xQueueOverwriteFromISR( xQueue, &ulVarToSend, &xHigherPriorityTaskWoken );
+
+	// The queue is full, but calling xQueueOverwriteFromISR() again will still
+	// pass because the value held in the queue will be overwritten with the
+	// new value.
+	ulVarToSend = 100;
+	xQueueOverwriteFromISR( xQueue, &ulVarToSend, &xHigherPriorityTaskWoken );
+
+	// Reading from the queue will now return 100.
+
+	// ...
+
+	if( xHigherPrioritytaskWoken == pdTRUE )
+	{
+		// Writing to the queue caused a task to unblock and the unblocked task
+		// has a priority higher than or equal to the priority of the currently
+		// executing task (the task this interrupt interrupted).  Perform a context
+		// switch so this interrupt returns directly to the unblocked task.
+		portYIELD_FROM_ISR(); // or portEND_SWITCHING_ISR() depending on the port.
+	}
+}
+ 
+ * \defgroup xQueueOverwriteFromISR xQueueOverwriteFromISR + * \ingroup QueueManagement + */ +#define xQueueOverwriteFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( xQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueOVERWRITE ) + +/** + * queue. h + *
+ BaseType_t xQueueSendFromISR(
+									 QueueHandle_t xQueue,
+									 const void *pvItemToQueue,
+									 BaseType_t *pxHigherPriorityTaskWoken
+								);
+ 
+ * + * This is a macro that calls xQueueGenericSendFromISR(). It is included + * for backward compatibility with versions of FreeRTOS.org that did not + * include the xQueueSendToBackFromISR() and xQueueSendToFrontFromISR() + * macros. + * + * Post an item to the back of a queue. It is safe to use this function from + * within an interrupt service routine. + * + * Items are queued by copy not reference so it is preferable to only + * queue small items, especially when called from an ISR. In most cases + * it would be preferable to store a pointer to the item being queued. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param pxHigherPriorityTaskWoken xQueueSendFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task + * to unblock, and the unblocked task has a priority higher than the currently + * running task. If xQueueSendFromISR() sets this value to pdTRUE then + * a context switch should be requested before the interrupt is exited. + * + * @return pdTRUE if the data was successfully sent to the queue, otherwise + * errQUEUE_FULL. + * + * Example usage for buffered IO (where the ISR can obtain more than one value + * per call): +
+ void vBufferISR( void )
+ {
+ char cIn;
+ BaseType_t xHigherPriorityTaskWoken;
+
+	// We have not woken a task at the start of the ISR.
+	xHigherPriorityTaskWoken = pdFALSE;
+
+	// Loop until the buffer is empty.
+	do
+	{
+		// Obtain a byte from the buffer.
+		cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
+
+		// Post the byte.
+		xQueueSendFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWoken );
+
+	} while( portINPUT_BYTE( BUFFER_COUNT ) );
+
+	// Now the buffer is empty we can switch context if necessary.
+	if( xHigherPriorityTaskWoken )
+	{
+		// Actual macro used here is port specific.
+		portYIELD_FROM_ISR ();
+	}
+ }
+ 
+ * + * \defgroup xQueueSendFromISR xQueueSendFromISR + * \ingroup QueueManagement + */ +#define xQueueSendFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( xQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_BACK ) + +/** + * queue. h + *
+ BaseType_t xQueueGenericSendFromISR(
+										   QueueHandle_t		xQueue,
+										   const	void	*pvItemToQueue,
+										   BaseType_t	*pxHigherPriorityTaskWoken,
+										   BaseType_t	xCopyPosition
+									   );
+ 
+ * + * It is preferred that the macros xQueueSendFromISR(), + * xQueueSendToFrontFromISR() and xQueueSendToBackFromISR() be used in place + * of calling this function directly. xQueueGiveFromISR() is an + * equivalent for use by semaphores that don't actually copy any data. + * + * Post an item on a queue. It is safe to use this function from within an + * interrupt service routine. + * + * Items are queued by copy not reference so it is preferable to only + * queue small items, especially when called from an ISR. In most cases + * it would be preferable to store a pointer to the item being queued. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param pxHigherPriorityTaskWoken xQueueGenericSendFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task + * to unblock, and the unblocked task has a priority higher than the currently + * running task. If xQueueGenericSendFromISR() sets this value to pdTRUE then + * a context switch should be requested before the interrupt is exited. + * + * @param xCopyPosition Can take the value queueSEND_TO_BACK to place the + * item at the back of the queue, or queueSEND_TO_FRONT to place the item + * at the front of the queue (for high priority messages). + * + * @return pdTRUE if the data was successfully sent to the queue, otherwise + * errQUEUE_FULL. + * + * Example usage for buffered IO (where the ISR can obtain more than one value + * per call): +
+ void vBufferISR( void )
+ {
+ char cIn;
+ BaseType_t xHigherPriorityTaskWokenByPost;
+
+	// We have not woken a task at the start of the ISR.
+	xHigherPriorityTaskWokenByPost = pdFALSE;
+
+	// Loop until the buffer is empty.
+	do
+	{
+		// Obtain a byte from the buffer.
+		cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
+
+		// Post each byte.
+		xQueueGenericSendFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWokenByPost, queueSEND_TO_BACK );
+
+	} while( portINPUT_BYTE( BUFFER_COUNT ) );
+
+	// Now the buffer is empty we can switch context if necessary.  Note that the
+	// name of the yield function required is port specific.
+	if( xHigherPriorityTaskWokenByPost )
+	{
+		taskYIELD_YIELD_FROM_ISR();
+	}
+ }
+ 
+ * + * \defgroup xQueueSendFromISR xQueueSendFromISR + * \ingroup QueueManagement + */ +BaseType_t xQueueGenericSendFromISR( QueueHandle_t xQueue, const void * const pvItemToQueue, BaseType_t * const pxHigherPriorityTaskWoken, const BaseType_t xCopyPosition ) PRIVILEGED_FUNCTION; +BaseType_t xQueueGiveFromISR( QueueHandle_t xQueue, BaseType_t * const pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION; + +/** + * queue. h + *
+ BaseType_t xQueueReceiveFromISR(
+									   QueueHandle_t	xQueue,
+									   void	*pvBuffer,
+									   BaseType_t *pxTaskWoken
+								   );
+ * 
+ * + * Receive an item from a queue. It is safe to use this function from within an + * interrupt service routine. + * + * @param xQueue The handle to the queue from which the item is to be + * received. + * + * @param pvBuffer Pointer to the buffer into which the received item will + * be copied. + * + * @param pxTaskWoken A task may be blocked waiting for space to become + * available on the queue. If xQueueReceiveFromISR causes such a task to + * unblock *pxTaskWoken will get set to pdTRUE, otherwise *pxTaskWoken will + * remain unchanged. + * + * @return pdTRUE if an item was successfully received from the queue, + * otherwise pdFALSE. + * + * Example usage: +
+
+ QueueHandle_t xQueue;
+
+ // Function to create a queue and post some values.
+ void vAFunction( void *pvParameters )
+ {
+ char cValueToPost;
+ const TickType_t xTicksToWait = ( TickType_t )0xff;
+
+	// Create a queue capable of containing 10 characters.
+	xQueue = xQueueCreate( 10, sizeof( char ) );
+	if( xQueue == 0 )
+	{
+		// Failed to create the queue.
+	}
+
+	// ...
+
+	// Post some characters that will be used within an ISR.  If the queue
+	// is full then this task will block for xTicksToWait ticks.
+	cValueToPost = 'a';
+	xQueueSend( xQueue, ( void * ) &cValueToPost, xTicksToWait );
+	cValueToPost = 'b';
+	xQueueSend( xQueue, ( void * ) &cValueToPost, xTicksToWait );
+
+	// ... keep posting characters ... this task may block when the queue
+	// becomes full.
+
+	cValueToPost = 'c';
+	xQueueSend( xQueue, ( void * ) &cValueToPost, xTicksToWait );
+ }
+
+ // ISR that outputs all the characters received on the queue.
+ void vISR_Routine( void )
+ {
+ BaseType_t xTaskWokenByReceive = pdFALSE;
+ char cRxedChar;
+
+	while( xQueueReceiveFromISR( xQueue, ( void * ) &cRxedChar, &xTaskWokenByReceive) )
+	{
+		// A character was received.  Output the character now.
+		vOutputCharacter( cRxedChar );
+
+		// If removing the character from the queue woke the task that was
+		// posting onto the queue cTaskWokenByReceive will have been set to
+		// pdTRUE.  No matter how many times this loop iterates only one
+		// task will be woken.
+	}
+
+	if( cTaskWokenByPost != ( char ) pdFALSE;
+	{
+		taskYIELD ();
+	}
+ }
+ 
+ * \defgroup xQueueReceiveFromISR xQueueReceiveFromISR + * \ingroup QueueManagement + */ +BaseType_t xQueueReceiveFromISR( QueueHandle_t xQueue, void * const pvBuffer, BaseType_t * const pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION; + +/* + * Utilities to query queues that are safe to use from an ISR. These utilities + * should be used only from witin an ISR, or within a critical section. + */ +BaseType_t xQueueIsQueueEmptyFromISR( const QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; +BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; +UBaseType_t uxQueueMessagesWaitingFromISR( const QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; + +/* + * The functions defined above are for passing data to and from tasks. The + * functions below are the equivalents for passing data to and from + * co-routines. + * + * These functions are called from the co-routine macro implementation and + * should not be called directly from application code. Instead use the macro + * wrappers defined within croutine.h. + */ +BaseType_t xQueueCRSendFromISR( QueueHandle_t xQueue, const void *pvItemToQueue, BaseType_t xCoRoutinePreviouslyWoken ); +BaseType_t xQueueCRReceiveFromISR( QueueHandle_t xQueue, void *pvBuffer, BaseType_t *pxTaskWoken ); +BaseType_t xQueueCRSend( QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait ); +BaseType_t xQueueCRReceive( QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait ); + +/* + * For internal use only. Use xSemaphoreCreateMutex(), + * xSemaphoreCreateCounting() or xSemaphoreGetMutexHolder() instead of calling + * these functions directly. + */ +QueueHandle_t xQueueCreateMutex( const uint8_t ucQueueType ) PRIVILEGED_FUNCTION; +QueueHandle_t xQueueCreateMutexStatic( const uint8_t ucQueueType, StaticQueue_t *pxStaticQueue ) PRIVILEGED_FUNCTION; +QueueHandle_t xQueueCreateCountingSemaphore( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount ) PRIVILEGED_FUNCTION; +QueueHandle_t xQueueCreateCountingSemaphoreStatic( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount, StaticQueue_t *pxStaticQueue ) PRIVILEGED_FUNCTION; +void* xQueueGetMutexHolder( QueueHandle_t xSemaphore ) PRIVILEGED_FUNCTION; + +/* + * For internal use only. Use xSemaphoreTakeMutexRecursive() or + * xSemaphoreGiveMutexRecursive() instead of calling these functions directly. + */ +BaseType_t xQueueTakeMutexRecursive( QueueHandle_t xMutex, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; +BaseType_t xQueueGiveMutexRecursive( QueueHandle_t pxMutex ) PRIVILEGED_FUNCTION; + +/* + * Reset a queue back to its original empty state. The return value is now + * obsolete and is always set to pdPASS. + */ +#define xQueueReset( xQueue ) xQueueGenericReset( xQueue, pdFALSE ) + +/* + * The registry is provided as a means for kernel aware debuggers to + * locate queues, semaphores and mutexes. Call vQueueAddToRegistry() add + * a queue, semaphore or mutex handle to the registry if you want the handle + * to be available to a kernel aware debugger. If you are not using a kernel + * aware debugger then this function can be ignored. + * + * configQUEUE_REGISTRY_SIZE defines the maximum number of handles the + * registry can hold. configQUEUE_REGISTRY_SIZE must be greater than 0 + * within FreeRTOSConfig.h for the registry to be available. Its value + * does not effect the number of queues, semaphores and mutexes that can be + * created - just the number that the registry can hold. + * + * @param xQueue The handle of the queue being added to the registry. This + * is the handle returned by a call to xQueueCreate(). Semaphore and mutex + * handles can also be passed in here. + * + * @param pcName The name to be associated with the handle. This is the + * name that the kernel aware debugger will display. The queue registry only + * stores a pointer to the string - so the string must be persistent (global or + * preferably in ROM/Flash), not on the stack. + */ +#if( configQUEUE_REGISTRY_SIZE > 0 ) + void vQueueAddToRegistry( QueueHandle_t xQueue, const char *pcName ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +#endif + +/* + * The registry is provided as a means for kernel aware debuggers to + * locate queues, semaphores and mutexes. Call vQueueAddToRegistry() add + * a queue, semaphore or mutex handle to the registry if you want the handle + * to be available to a kernel aware debugger, and vQueueUnregisterQueue() to + * remove the queue, semaphore or mutex from the register. If you are not using + * a kernel aware debugger then this function can be ignored. + * + * @param xQueue The handle of the queue being removed from the registry. + */ +#if( configQUEUE_REGISTRY_SIZE > 0 ) + void vQueueUnregisterQueue( QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; +#endif + +/* + * The queue registry is provided as a means for kernel aware debuggers to + * locate queues, semaphores and mutexes. Call pcQueueGetName() to look + * up and return the name of a queue in the queue registry from the queue's + * handle. + * + * @param xQueue The handle of the queue the name of which will be returned. + * @return If the queue is in the registry then a pointer to the name of the + * queue is returned. If the queue is not in the registry then NULL is + * returned. + */ +#if( configQUEUE_REGISTRY_SIZE > 0 ) + const char *pcQueueGetName( QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +#endif + +/* + * Generic version of the function used to creaet a queue using dynamic memory + * allocation. This is called by other functions and macros that create other + * RTOS objects that use the queue structure as their base. + */ +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType ) PRIVILEGED_FUNCTION; +#endif + +/* + * Generic version of the function used to creaet a queue using dynamic memory + * allocation. This is called by other functions and macros that create other + * RTOS objects that use the queue structure as their base. + */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + QueueHandle_t xQueueGenericCreateStatic( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, StaticQueue_t *pxStaticQueue, const uint8_t ucQueueType ) PRIVILEGED_FUNCTION; +#endif + +/* + * Queue sets provide a mechanism to allow a task to block (pend) on a read + * operation from multiple queues or semaphores simultaneously. + * + * See FreeRTOS/Source/Demo/Common/Minimal/QueueSet.c for an example using this + * function. + * + * A queue set must be explicitly created using a call to xQueueCreateSet() + * before it can be used. Once created, standard FreeRTOS queues and semaphores + * can be added to the set using calls to xQueueAddToSet(). + * xQueueSelectFromSet() is then used to determine which, if any, of the queues + * or semaphores contained in the set is in a state where a queue read or + * semaphore take operation would be successful. + * + * Note 1: See the documentation on http://wwwFreeRTOS.org/RTOS-queue-sets.html + * for reasons why queue sets are very rarely needed in practice as there are + * simpler methods of blocking on multiple objects. + * + * Note 2: Blocking on a queue set that contains a mutex will not cause the + * mutex holder to inherit the priority of the blocked task. + * + * Note 3: An additional 4 bytes of RAM is required for each space in a every + * queue added to a queue set. Therefore counting semaphores that have a high + * maximum count value should not be added to a queue set. + * + * Note 4: A receive (in the case of a queue) or take (in the case of a + * semaphore) operation must not be performed on a member of a queue set unless + * a call to xQueueSelectFromSet() has first returned a handle to that set member. + * + * @param uxEventQueueLength Queue sets store events that occur on + * the queues and semaphores contained in the set. uxEventQueueLength specifies + * the maximum number of events that can be queued at once. To be absolutely + * certain that events are not lost uxEventQueueLength should be set to the + * total sum of the length of the queues added to the set, where binary + * semaphores and mutexes have a length of 1, and counting semaphores have a + * length set by their maximum count value. Examples: + * + If a queue set is to hold a queue of length 5, another queue of length 12, + * and a binary semaphore, then uxEventQueueLength should be set to + * (5 + 12 + 1), or 18. + * + If a queue set is to hold three binary semaphores then uxEventQueueLength + * should be set to (1 + 1 + 1 ), or 3. + * + If a queue set is to hold a counting semaphore that has a maximum count of + * 5, and a counting semaphore that has a maximum count of 3, then + * uxEventQueueLength should be set to (5 + 3), or 8. + * + * @return If the queue set is created successfully then a handle to the created + * queue set is returned. Otherwise NULL is returned. + */ +QueueSetHandle_t xQueueCreateSet( const UBaseType_t uxEventQueueLength ) PRIVILEGED_FUNCTION; + +/* + * Adds a queue or semaphore to a queue set that was previously created by a + * call to xQueueCreateSet(). + * + * See FreeRTOS/Source/Demo/Common/Minimal/QueueSet.c for an example using this + * function. + * + * Note 1: A receive (in the case of a queue) or take (in the case of a + * semaphore) operation must not be performed on a member of a queue set unless + * a call to xQueueSelectFromSet() has first returned a handle to that set member. + * + * @param xQueueOrSemaphore The handle of the queue or semaphore being added to + * the queue set (cast to an QueueSetMemberHandle_t type). + * + * @param xQueueSet The handle of the queue set to which the queue or semaphore + * is being added. + * + * @return If the queue or semaphore was successfully added to the queue set + * then pdPASS is returned. If the queue could not be successfully added to the + * queue set because it is already a member of a different queue set then pdFAIL + * is returned. + */ +BaseType_t xQueueAddToSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet ) PRIVILEGED_FUNCTION; + +/* + * Removes a queue or semaphore from a queue set. A queue or semaphore can only + * be removed from a set if the queue or semaphore is empty. + * + * See FreeRTOS/Source/Demo/Common/Minimal/QueueSet.c for an example using this + * function. + * + * @param xQueueOrSemaphore The handle of the queue or semaphore being removed + * from the queue set (cast to an QueueSetMemberHandle_t type). + * + * @param xQueueSet The handle of the queue set in which the queue or semaphore + * is included. + * + * @return If the queue or semaphore was successfully removed from the queue set + * then pdPASS is returned. If the queue was not in the queue set, or the + * queue (or semaphore) was not empty, then pdFAIL is returned. + */ +BaseType_t xQueueRemoveFromSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet ) PRIVILEGED_FUNCTION; + +/* + * xQueueSelectFromSet() selects from the members of a queue set a queue or + * semaphore that either contains data (in the case of a queue) or is available + * to take (in the case of a semaphore). xQueueSelectFromSet() effectively + * allows a task to block (pend) on a read operation on all the queues and + * semaphores in a queue set simultaneously. + * + * See FreeRTOS/Source/Demo/Common/Minimal/QueueSet.c for an example using this + * function. + * + * Note 1: See the documentation on http://wwwFreeRTOS.org/RTOS-queue-sets.html + * for reasons why queue sets are very rarely needed in practice as there are + * simpler methods of blocking on multiple objects. + * + * Note 2: Blocking on a queue set that contains a mutex will not cause the + * mutex holder to inherit the priority of the blocked task. + * + * Note 3: A receive (in the case of a queue) or take (in the case of a + * semaphore) operation must not be performed on a member of a queue set unless + * a call to xQueueSelectFromSet() has first returned a handle to that set member. + * + * @param xQueueSet The queue set on which the task will (potentially) block. + * + * @param xTicksToWait The maximum time, in ticks, that the calling task will + * remain in the Blocked state (with other tasks executing) to wait for a member + * of the queue set to be ready for a successful queue read or semaphore take + * operation. + * + * @return xQueueSelectFromSet() will return the handle of a queue (cast to + * a QueueSetMemberHandle_t type) contained in the queue set that contains data, + * or the handle of a semaphore (cast to a QueueSetMemberHandle_t type) contained + * in the queue set that is available, or NULL if no such queue or semaphore + * exists before before the specified block time expires. + */ +QueueSetMemberHandle_t xQueueSelectFromSet( QueueSetHandle_t xQueueSet, const TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; + +/* + * A version of xQueueSelectFromSet() that can be used from an ISR. + */ +QueueSetMemberHandle_t xQueueSelectFromSetFromISR( QueueSetHandle_t xQueueSet ) PRIVILEGED_FUNCTION; + +/* Not public API functions. */ +void vQueueWaitForMessageRestricted( QueueHandle_t xQueue, TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely ) PRIVILEGED_FUNCTION; +BaseType_t xQueueGenericReset( QueueHandle_t xQueue, BaseType_t xNewQueue ) PRIVILEGED_FUNCTION; +void vQueueSetQueueNumber( QueueHandle_t xQueue, UBaseType_t uxQueueNumber ) PRIVILEGED_FUNCTION; +UBaseType_t uxQueueGetQueueNumber( QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; +uint8_t ucQueueGetQueueType( QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; + + +#ifdef __cplusplus +} +#endif + +#endif /* QUEUE_H */ + diff --git a/STM32F1/libraries/FreeRTOS900/utility/readme.txt b/STM32F1/libraries/FreeRTOS900/utility/readme.txt new file mode 100644 index 0000000..58480c5 --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/utility/readme.txt @@ -0,0 +1,17 @@ +Each real time kernel port consists of three files that contain the core kernel +components and are common to every port, and one or more files that are +specific to a particular microcontroller and or compiler. + ++ The FreeRTOS/Source directory contains the three files that are common to +every port - list.c, queue.c and tasks.c. The kernel is contained within these +three files. croutine.c implements the optional co-routine functionality - which +is normally only used on very memory limited systems. + ++ The FreeRTOS/Source/Portable directory contains the files that are specific to +a particular microcontroller and or compiler. + ++ The FreeRTOS/Source/include directory contains the real time kernel header +files. + +See the readme file in the FreeRTOS/Source/Portable directory for more +information. \ No newline at end of file diff --git a/STM32F1/libraries/FreeRTOS900/utility/semphr.h b/STM32F1/libraries/FreeRTOS900/utility/semphr.h new file mode 100644 index 0000000..a674b02 --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/utility/semphr.h @@ -0,0 +1,1171 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef SEMAPHORE_H +#define SEMAPHORE_H + +#ifndef INC_FREERTOS_H + #error "include FreeRTOS.h" must appear in source files before "include semphr.h" +#endif + +#include "queue.h" + +typedef QueueHandle_t SemaphoreHandle_t; + +#define semBINARY_SEMAPHORE_QUEUE_LENGTH ( ( uint8_t ) 1U ) +#define semSEMAPHORE_QUEUE_ITEM_LENGTH ( ( uint8_t ) 0U ) +#define semGIVE_BLOCK_TIME ( ( TickType_t ) 0U ) + + +/** + * semphr. h + *
vSemaphoreCreateBinary( SemaphoreHandle_t xSemaphore )
+ * + * In many usage scenarios it is faster and more memory efficient to use a + * direct to task notification in place of a binary semaphore! + * http://www.freertos.org/RTOS-task-notifications.html + * + * This old vSemaphoreCreateBinary() macro is now deprecated in favour of the + * xSemaphoreCreateBinary() function. Note that binary semaphores created using + * the vSemaphoreCreateBinary() macro are created in a state such that the + * first call to 'take' the semaphore would pass, whereas binary semaphores + * created using xSemaphoreCreateBinary() are created in a state such that the + * the semaphore must first be 'given' before it can be 'taken'. + * + * Macro that implements a semaphore by using the existing queue mechanism. + * The queue length is 1 as this is a binary semaphore. The data size is 0 + * as we don't want to actually store any data - we just want to know if the + * queue is empty or full. + * + * This type of semaphore can be used for pure synchronisation between tasks or + * between an interrupt and a task. The semaphore need not be given back once + * obtained, so one task/interrupt can continuously 'give' the semaphore while + * another continuously 'takes' the semaphore. For this reason this type of + * semaphore does not use a priority inheritance mechanism. For an alternative + * that does use priority inheritance see xSemaphoreCreateMutex(). + * + * @param xSemaphore Handle to the created semaphore. Should be of type SemaphoreHandle_t. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore = NULL;
+
+ void vATask( void * pvParameters )
+ {
+    // Semaphore cannot be used before a call to vSemaphoreCreateBinary ().
+    // This is a macro so pass the variable in directly.
+    vSemaphoreCreateBinary( xSemaphore );
+
+    if( xSemaphore != NULL )
+    {
+        // The semaphore was created successfully.
+        // The semaphore can now be used.
+    }
+ }
+ 
+ * \defgroup vSemaphoreCreateBinary vSemaphoreCreateBinary + * \ingroup Semaphores + */ +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + #define vSemaphoreCreateBinary( xSemaphore ) \ + { \ + ( xSemaphore ) = xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE ); \ + if( ( xSemaphore ) != NULL ) \ + { \ + ( void ) xSemaphoreGive( ( xSemaphore ) ); \ + } \ + } +#endif + +/** + * semphr. h + *
SemaphoreHandle_t xSemaphoreCreateBinary( void )
+ * + * Creates a new binary semaphore instance, and returns a handle by which the + * new semaphore can be referenced. + * + * In many usage scenarios it is faster and more memory efficient to use a + * direct to task notification in place of a binary semaphore! + * http://www.freertos.org/RTOS-task-notifications.html + * + * Internally, within the FreeRTOS implementation, binary semaphores use a block + * of memory, in which the semaphore structure is stored. If a binary semaphore + * is created using xSemaphoreCreateBinary() then the required memory is + * automatically dynamically allocated inside the xSemaphoreCreateBinary() + * function. (see http://www.freertos.org/a00111.html). If a binary semaphore + * is created using xSemaphoreCreateBinaryStatic() then the application writer + * must provide the memory. xSemaphoreCreateBinaryStatic() therefore allows a + * binary semaphore to be created without using any dynamic memory allocation. + * + * The old vSemaphoreCreateBinary() macro is now deprecated in favour of this + * xSemaphoreCreateBinary() function. Note that binary semaphores created using + * the vSemaphoreCreateBinary() macro are created in a state such that the + * first call to 'take' the semaphore would pass, whereas binary semaphores + * created using xSemaphoreCreateBinary() are created in a state such that the + * the semaphore must first be 'given' before it can be 'taken'. + * + * This type of semaphore can be used for pure synchronisation between tasks or + * between an interrupt and a task. The semaphore need not be given back once + * obtained, so one task/interrupt can continuously 'give' the semaphore while + * another continuously 'takes' the semaphore. For this reason this type of + * semaphore does not use a priority inheritance mechanism. For an alternative + * that does use priority inheritance see xSemaphoreCreateMutex(). + * + * @return Handle to the created semaphore, or NULL if the memory required to + * hold the semaphore's data structures could not be allocated. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore = NULL;
+
+ void vATask( void * pvParameters )
+ {
+    // Semaphore cannot be used before a call to xSemaphoreCreateBinary().
+    // This is a macro so pass the variable in directly.
+    xSemaphore = xSemaphoreCreateBinary();
+
+    if( xSemaphore != NULL )
+    {
+        // The semaphore was created successfully.
+        // The semaphore can now be used.
+    }
+ }
+ 
+ * \defgroup xSemaphoreCreateBinary xSemaphoreCreateBinary + * \ingroup Semaphores + */ +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + #define xSemaphoreCreateBinary() xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE ) +#endif + +/** + * semphr. h + *
SemaphoreHandle_t xSemaphoreCreateBinaryStatic( StaticSemaphore_t *pxSemaphoreBuffer )
+ * + * Creates a new binary semaphore instance, and returns a handle by which the + * new semaphore can be referenced. + * + * NOTE: In many usage scenarios it is faster and more memory efficient to use a + * direct to task notification in place of a binary semaphore! + * http://www.freertos.org/RTOS-task-notifications.html + * + * Internally, within the FreeRTOS implementation, binary semaphores use a block + * of memory, in which the semaphore structure is stored. If a binary semaphore + * is created using xSemaphoreCreateBinary() then the required memory is + * automatically dynamically allocated inside the xSemaphoreCreateBinary() + * function. (see http://www.freertos.org/a00111.html). If a binary semaphore + * is created using xSemaphoreCreateBinaryStatic() then the application writer + * must provide the memory. xSemaphoreCreateBinaryStatic() therefore allows a + * binary semaphore to be created without using any dynamic memory allocation. + * + * This type of semaphore can be used for pure synchronisation between tasks or + * between an interrupt and a task. The semaphore need not be given back once + * obtained, so one task/interrupt can continuously 'give' the semaphore while + * another continuously 'takes' the semaphore. For this reason this type of + * semaphore does not use a priority inheritance mechanism. For an alternative + * that does use priority inheritance see xSemaphoreCreateMutex(). + * + * @param pxSemaphoreBuffer Must point to a variable of type StaticSemaphore_t, + * which will then be used to hold the semaphore's data structure, removing the + * need for the memory to be allocated dynamically. + * + * @return If the semaphore is created then a handle to the created semaphore is + * returned. If pxSemaphoreBuffer is NULL then NULL is returned. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore = NULL;
+ StaticSemaphore_t xSemaphoreBuffer;
+
+ void vATask( void * pvParameters )
+ {
+    // Semaphore cannot be used before a call to xSemaphoreCreateBinary().
+    // The semaphore's data structures will be placed in the xSemaphoreBuffer
+    // variable, the address of which is passed into the function.  The
+    // function's parameter is not NULL, so the function will not attempt any
+    // dynamic memory allocation, and therefore the function will not return
+    // return NULL.
+    xSemaphore = xSemaphoreCreateBinary( &xSemaphoreBuffer );
+
+    // Rest of task code goes here.
+ }
+ 
+ * \defgroup xSemaphoreCreateBinaryStatic xSemaphoreCreateBinaryStatic + * \ingroup Semaphores + */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + #define xSemaphoreCreateBinaryStatic( pxStaticSemaphore ) xQueueGenericCreateStatic( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, NULL, pxStaticSemaphore, queueQUEUE_TYPE_BINARY_SEMAPHORE ) +#endif /* configSUPPORT_STATIC_ALLOCATION */ + +/** + * semphr. h + *
xSemaphoreTake(
+ *                   SemaphoreHandle_t xSemaphore,
+ *                   TickType_t xBlockTime
+ *               )
+ * + * Macro to obtain a semaphore. The semaphore must have previously been + * created with a call to xSemaphoreCreateBinary(), xSemaphoreCreateMutex() or + * xSemaphoreCreateCounting(). + * + * @param xSemaphore A handle to the semaphore being taken - obtained when + * the semaphore was created. + * + * @param xBlockTime The time in ticks to wait for the semaphore to become + * available. The macro portTICK_PERIOD_MS can be used to convert this to a + * real time. A block time of zero can be used to poll the semaphore. A block + * time of portMAX_DELAY can be used to block indefinitely (provided + * INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h). + * + * @return pdTRUE if the semaphore was obtained. pdFALSE + * if xBlockTime expired without the semaphore becoming available. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore = NULL;
+
+ // A task that creates a semaphore.
+ void vATask( void * pvParameters )
+ {
+    // Create the semaphore to guard a shared resource.
+    xSemaphore = xSemaphoreCreateBinary();
+ }
+
+ // A task that uses the semaphore.
+ void vAnotherTask( void * pvParameters )
+ {
+    // ... Do other things.
+
+    if( xSemaphore != NULL )
+    {
+        // See if we can obtain the semaphore.  If the semaphore is not available
+        // wait 10 ticks to see if it becomes free.
+        if( xSemaphoreTake( xSemaphore, ( TickType_t ) 10 ) == pdTRUE )
+        {
+            // We were able to obtain the semaphore and can now access the
+            // shared resource.
+
+            // ...
+
+            // We have finished accessing the shared resource.  Release the
+            // semaphore.
+            xSemaphoreGive( xSemaphore );
+        }
+        else
+        {
+            // We could not obtain the semaphore and can therefore not access
+            // the shared resource safely.
+        }
+    }
+ }
+ 
+ * \defgroup xSemaphoreTake xSemaphoreTake + * \ingroup Semaphores + */ +#define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueGenericReceive( ( QueueHandle_t ) ( xSemaphore ), NULL, ( xBlockTime ), pdFALSE ) + +/** + * semphr. h + * xSemaphoreTakeRecursive( + * SemaphoreHandle_t xMutex, + * TickType_t xBlockTime + * ) + * + * Macro to recursively obtain, or 'take', a mutex type semaphore. + * The mutex must have previously been created using a call to + * xSemaphoreCreateRecursiveMutex(); + * + * configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h for this + * macro to be available. + * + * This macro must not be used on mutexes created using xSemaphoreCreateMutex(). + * + * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex + * doesn't become available again until the owner has called + * xSemaphoreGiveRecursive() for each successful 'take' request. For example, + * if a task successfully 'takes' the same mutex 5 times then the mutex will + * not be available to any other task until it has also 'given' the mutex back + * exactly five times. + * + * @param xMutex A handle to the mutex being obtained. This is the + * handle returned by xSemaphoreCreateRecursiveMutex(); + * + * @param xBlockTime The time in ticks to wait for the semaphore to become + * available. The macro portTICK_PERIOD_MS can be used to convert this to a + * real time. A block time of zero can be used to poll the semaphore. If + * the task already owns the semaphore then xSemaphoreTakeRecursive() will + * return immediately no matter what the value of xBlockTime. + * + * @return pdTRUE if the semaphore was obtained. pdFALSE if xBlockTime + * expired without the semaphore becoming available. + * + * Example usage: +
+ SemaphoreHandle_t xMutex = NULL;
+
+ // A task that creates a mutex.
+ void vATask( void * pvParameters )
+ {
+    // Create the mutex to guard a shared resource.
+    xMutex = xSemaphoreCreateRecursiveMutex();
+ }
+
+ // A task that uses the mutex.
+ void vAnotherTask( void * pvParameters )
+ {
+    // ... Do other things.
+
+    if( xMutex != NULL )
+    {
+        // See if we can obtain the mutex.  If the mutex is not available
+        // wait 10 ticks to see if it becomes free.
+        if( xSemaphoreTakeRecursive( xSemaphore, ( TickType_t ) 10 ) == pdTRUE )
+        {
+            // We were able to obtain the mutex and can now access the
+            // shared resource.
+
+            // ...
+            // For some reason due to the nature of the code further calls to
+			// xSemaphoreTakeRecursive() are made on the same mutex.  In real
+			// code these would not be just sequential calls as this would make
+			// no sense.  Instead the calls are likely to be buried inside
+			// a more complex call structure.
+            xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 );
+            xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 );
+
+            // The mutex has now been 'taken' three times, so will not be
+			// available to another task until it has also been given back
+			// three times.  Again it is unlikely that real code would have
+			// these calls sequentially, but instead buried in a more complex
+			// call structure.  This is just for illustrative purposes.
+            xSemaphoreGiveRecursive( xMutex );
+			xSemaphoreGiveRecursive( xMutex );
+			xSemaphoreGiveRecursive( xMutex );
+
+			// Now the mutex can be taken by other tasks.
+        }
+        else
+        {
+            // We could not obtain the mutex and can therefore not access
+            // the shared resource safely.
+        }
+    }
+ }
+ 
+ * \defgroup xSemaphoreTakeRecursive xSemaphoreTakeRecursive + * \ingroup Semaphores + */ +#if( configUSE_RECURSIVE_MUTEXES == 1 ) + #define xSemaphoreTakeRecursive( xMutex, xBlockTime ) xQueueTakeMutexRecursive( ( xMutex ), ( xBlockTime ) ) +#endif + +/** + * semphr. h + *
xSemaphoreGive( SemaphoreHandle_t xSemaphore )
+ * + * Macro to release a semaphore. The semaphore must have previously been + * created with a call to xSemaphoreCreateBinary(), xSemaphoreCreateMutex() or + * xSemaphoreCreateCounting(). and obtained using sSemaphoreTake(). + * + * This macro must not be used from an ISR. See xSemaphoreGiveFromISR () for + * an alternative which can be used from an ISR. + * + * This macro must also not be used on semaphores created using + * xSemaphoreCreateRecursiveMutex(). + * + * @param xSemaphore A handle to the semaphore being released. This is the + * handle returned when the semaphore was created. + * + * @return pdTRUE if the semaphore was released. pdFALSE if an error occurred. + * Semaphores are implemented using queues. An error can occur if there is + * no space on the queue to post a message - indicating that the + * semaphore was not first obtained correctly. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore = NULL;
+
+ void vATask( void * pvParameters )
+ {
+    // Create the semaphore to guard a shared resource.
+    xSemaphore = vSemaphoreCreateBinary();
+
+    if( xSemaphore != NULL )
+    {
+        if( xSemaphoreGive( xSemaphore ) != pdTRUE )
+        {
+            // We would expect this call to fail because we cannot give
+            // a semaphore without first "taking" it!
+        }
+
+        // Obtain the semaphore - don't block if the semaphore is not
+        // immediately available.
+        if( xSemaphoreTake( xSemaphore, ( TickType_t ) 0 ) )
+        {
+            // We now have the semaphore and can access the shared resource.
+
+            // ...
+
+            // We have finished accessing the shared resource so can free the
+            // semaphore.
+            if( xSemaphoreGive( xSemaphore ) != pdTRUE )
+            {
+                // We would not expect this call to fail because we must have
+                // obtained the semaphore to get here.
+            }
+        }
+    }
+ }
+ 
+ * \defgroup xSemaphoreGive xSemaphoreGive + * \ingroup Semaphores + */ +#define xSemaphoreGive( xSemaphore ) xQueueGenericSend( ( QueueHandle_t ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK ) + +/** + * semphr. h + *
xSemaphoreGiveRecursive( SemaphoreHandle_t xMutex )
+ * + * Macro to recursively release, or 'give', a mutex type semaphore. + * The mutex must have previously been created using a call to + * xSemaphoreCreateRecursiveMutex(); + * + * configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h for this + * macro to be available. + * + * This macro must not be used on mutexes created using xSemaphoreCreateMutex(). + * + * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex + * doesn't become available again until the owner has called + * xSemaphoreGiveRecursive() for each successful 'take' request. For example, + * if a task successfully 'takes' the same mutex 5 times then the mutex will + * not be available to any other task until it has also 'given' the mutex back + * exactly five times. + * + * @param xMutex A handle to the mutex being released, or 'given'. This is the + * handle returned by xSemaphoreCreateMutex(); + * + * @return pdTRUE if the semaphore was given. + * + * Example usage: +
+ SemaphoreHandle_t xMutex = NULL;
+
+ // A task that creates a mutex.
+ void vATask( void * pvParameters )
+ {
+    // Create the mutex to guard a shared resource.
+    xMutex = xSemaphoreCreateRecursiveMutex();
+ }
+
+ // A task that uses the mutex.
+ void vAnotherTask( void * pvParameters )
+ {
+    // ... Do other things.
+
+    if( xMutex != NULL )
+    {
+        // See if we can obtain the mutex.  If the mutex is not available
+        // wait 10 ticks to see if it becomes free.
+        if( xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 ) == pdTRUE )
+        {
+            // We were able to obtain the mutex and can now access the
+            // shared resource.
+
+            // ...
+            // For some reason due to the nature of the code further calls to
+			// xSemaphoreTakeRecursive() are made on the same mutex.  In real
+			// code these would not be just sequential calls as this would make
+			// no sense.  Instead the calls are likely to be buried inside
+			// a more complex call structure.
+            xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 );
+            xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 );
+
+            // The mutex has now been 'taken' three times, so will not be
+			// available to another task until it has also been given back
+			// three times.  Again it is unlikely that real code would have
+			// these calls sequentially, it would be more likely that the calls
+			// to xSemaphoreGiveRecursive() would be called as a call stack
+			// unwound.  This is just for demonstrative purposes.
+            xSemaphoreGiveRecursive( xMutex );
+			xSemaphoreGiveRecursive( xMutex );
+			xSemaphoreGiveRecursive( xMutex );
+
+			// Now the mutex can be taken by other tasks.
+        }
+        else
+        {
+            // We could not obtain the mutex and can therefore not access
+            // the shared resource safely.
+        }
+    }
+ }
+ 
+ * \defgroup xSemaphoreGiveRecursive xSemaphoreGiveRecursive + * \ingroup Semaphores + */ +#if( configUSE_RECURSIVE_MUTEXES == 1 ) + #define xSemaphoreGiveRecursive( xMutex ) xQueueGiveMutexRecursive( ( xMutex ) ) +#endif + +/** + * semphr. h + *
+ xSemaphoreGiveFromISR(
+                          SemaphoreHandle_t xSemaphore,
+                          BaseType_t *pxHigherPriorityTaskWoken
+                      )
+ * + * Macro to release a semaphore. The semaphore must have previously been + * created with a call to xSemaphoreCreateBinary() or xSemaphoreCreateCounting(). + * + * Mutex type semaphores (those created using a call to xSemaphoreCreateMutex()) + * must not be used with this macro. + * + * This macro can be used from an ISR. + * + * @param xSemaphore A handle to the semaphore being released. This is the + * handle returned when the semaphore was created. + * + * @param pxHigherPriorityTaskWoken xSemaphoreGiveFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if giving the semaphore caused a task + * to unblock, and the unblocked task has a priority higher than the currently + * running task. If xSemaphoreGiveFromISR() sets this value to pdTRUE then + * a context switch should be requested before the interrupt is exited. + * + * @return pdTRUE if the semaphore was successfully given, otherwise errQUEUE_FULL. + * + * Example usage: +
+ \#define LONG_TIME 0xffff
+ \#define TICKS_TO_WAIT	10
+ SemaphoreHandle_t xSemaphore = NULL;
+
+ // Repetitive task.
+ void vATask( void * pvParameters )
+ {
+    for( ;; )
+    {
+        // We want this task to run every 10 ticks of a timer.  The semaphore
+        // was created before this task was started.
+
+        // Block waiting for the semaphore to become available.
+        if( xSemaphoreTake( xSemaphore, LONG_TIME ) == pdTRUE )
+        {
+            // It is time to execute.
+
+            // ...
+
+            // We have finished our task.  Return to the top of the loop where
+            // we will block on the semaphore until it is time to execute
+            // again.  Note when using the semaphore for synchronisation with an
+			// ISR in this manner there is no need to 'give' the semaphore back.
+        }
+    }
+ }
+
+ // Timer ISR
+ void vTimerISR( void * pvParameters )
+ {
+ static uint8_t ucLocalTickCount = 0;
+ static BaseType_t xHigherPriorityTaskWoken;
+
+    // A timer tick has occurred.
+
+    // ... Do other time functions.
+
+    // Is it time for vATask () to run?
+	xHigherPriorityTaskWoken = pdFALSE;
+    ucLocalTickCount++;
+    if( ucLocalTickCount >= TICKS_TO_WAIT )
+    {
+        // Unblock the task by releasing the semaphore.
+        xSemaphoreGiveFromISR( xSemaphore, &xHigherPriorityTaskWoken );
+
+        // Reset the count so we release the semaphore again in 10 ticks time.
+        ucLocalTickCount = 0;
+    }
+
+    if( xHigherPriorityTaskWoken != pdFALSE )
+    {
+        // We can force a context switch here.  Context switching from an
+        // ISR uses port specific syntax.  Check the demo task for your port
+        // to find the syntax required.
+    }
+ }
+ 
+ * \defgroup xSemaphoreGiveFromISR xSemaphoreGiveFromISR + * \ingroup Semaphores + */ +#define xSemaphoreGiveFromISR( xSemaphore, pxHigherPriorityTaskWoken ) xQueueGiveFromISR( ( QueueHandle_t ) ( xSemaphore ), ( pxHigherPriorityTaskWoken ) ) + +/** + * semphr. h + *
+ xSemaphoreTakeFromISR(
+                          SemaphoreHandle_t xSemaphore,
+                          BaseType_t *pxHigherPriorityTaskWoken
+                      )
+ * + * Macro to take a semaphore from an ISR. The semaphore must have + * previously been created with a call to xSemaphoreCreateBinary() or + * xSemaphoreCreateCounting(). + * + * Mutex type semaphores (those created using a call to xSemaphoreCreateMutex()) + * must not be used with this macro. + * + * This macro can be used from an ISR, however taking a semaphore from an ISR + * is not a common operation. It is likely to only be useful when taking a + * counting semaphore when an interrupt is obtaining an object from a resource + * pool (when the semaphore count indicates the number of resources available). + * + * @param xSemaphore A handle to the semaphore being taken. This is the + * handle returned when the semaphore was created. + * + * @param pxHigherPriorityTaskWoken xSemaphoreTakeFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if taking the semaphore caused a task + * to unblock, and the unblocked task has a priority higher than the currently + * running task. If xSemaphoreTakeFromISR() sets this value to pdTRUE then + * a context switch should be requested before the interrupt is exited. + * + * @return pdTRUE if the semaphore was successfully taken, otherwise + * pdFALSE + */ +#define xSemaphoreTakeFromISR( xSemaphore, pxHigherPriorityTaskWoken ) xQueueReceiveFromISR( ( QueueHandle_t ) ( xSemaphore ), NULL, ( pxHigherPriorityTaskWoken ) ) + +/** + * semphr. h + *
SemaphoreHandle_t xSemaphoreCreateMutex( void )
+ * + * Creates a new mutex type semaphore instance, and returns a handle by which + * the new mutex can be referenced. + * + * Internally, within the FreeRTOS implementation, mutex semaphores use a block + * of memory, in which the mutex structure is stored. If a mutex is created + * using xSemaphoreCreateMutex() then the required memory is automatically + * dynamically allocated inside the xSemaphoreCreateMutex() function. (see + * http://www.freertos.org/a00111.html). If a mutex is created using + * xSemaphoreCreateMutexStatic() then the application writer must provided the + * memory. xSemaphoreCreateMutexStatic() therefore allows a mutex to be created + * without using any dynamic memory allocation. + * + * Mutexes created using this function can be accessed using the xSemaphoreTake() + * and xSemaphoreGive() macros. The xSemaphoreTakeRecursive() and + * xSemaphoreGiveRecursive() macros must not be used. + * + * This type of semaphore uses a priority inheritance mechanism so a task + * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the + * semaphore it is no longer required. + * + * Mutex type semaphores cannot be used from within interrupt service routines. + * + * See xSemaphoreCreateBinary() for an alternative implementation that can be + * used for pure synchronisation (where one task or interrupt always 'gives' the + * semaphore and another always 'takes' the semaphore) and from within interrupt + * service routines. + * + * @return If the mutex was successfully created then a handle to the created + * semaphore is returned. If there was not enough heap to allocate the mutex + * data structures then NULL is returned. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore;
+
+ void vATask( void * pvParameters )
+ {
+    // Semaphore cannot be used before a call to xSemaphoreCreateMutex().
+    // This is a macro so pass the variable in directly.
+    xSemaphore = xSemaphoreCreateMutex();
+
+    if( xSemaphore != NULL )
+    {
+        // The semaphore was created successfully.
+        // The semaphore can now be used.
+    }
+ }
+ 
+ * \defgroup xSemaphoreCreateMutex xSemaphoreCreateMutex + * \ingroup Semaphores + */ +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + #define xSemaphoreCreateMutex() xQueueCreateMutex( queueQUEUE_TYPE_MUTEX ) +#endif + +/** + * semphr. h + *
SemaphoreHandle_t xSemaphoreCreateMutexStatic( StaticSemaphore_t *pxMutexBuffer )
+ * + * Creates a new mutex type semaphore instance, and returns a handle by which + * the new mutex can be referenced. + * + * Internally, within the FreeRTOS implementation, mutex semaphores use a block + * of memory, in which the mutex structure is stored. If a mutex is created + * using xSemaphoreCreateMutex() then the required memory is automatically + * dynamically allocated inside the xSemaphoreCreateMutex() function. (see + * http://www.freertos.org/a00111.html). If a mutex is created using + * xSemaphoreCreateMutexStatic() then the application writer must provided the + * memory. xSemaphoreCreateMutexStatic() therefore allows a mutex to be created + * without using any dynamic memory allocation. + * + * Mutexes created using this function can be accessed using the xSemaphoreTake() + * and xSemaphoreGive() macros. The xSemaphoreTakeRecursive() and + * xSemaphoreGiveRecursive() macros must not be used. + * + * This type of semaphore uses a priority inheritance mechanism so a task + * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the + * semaphore it is no longer required. + * + * Mutex type semaphores cannot be used from within interrupt service routines. + * + * See xSemaphoreCreateBinary() for an alternative implementation that can be + * used for pure synchronisation (where one task or interrupt always 'gives' the + * semaphore and another always 'takes' the semaphore) and from within interrupt + * service routines. + * + * @param pxMutexBuffer Must point to a variable of type StaticSemaphore_t, + * which will be used to hold the mutex's data structure, removing the need for + * the memory to be allocated dynamically. + * + * @return If the mutex was successfully created then a handle to the created + * mutex is returned. If pxMutexBuffer was NULL then NULL is returned. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore;
+ StaticSemaphore_t xMutexBuffer;
+
+ void vATask( void * pvParameters )
+ {
+    // A mutex cannot be used before it has been created.  xMutexBuffer is
+    // into xSemaphoreCreateMutexStatic() so no dynamic memory allocation is
+    // attempted.
+    xSemaphore = xSemaphoreCreateMutexStatic( &xMutexBuffer );
+
+    // As no dynamic memory allocation was performed, xSemaphore cannot be NULL,
+    // so there is no need to check it.
+ }
+ 
+ * \defgroup xSemaphoreCreateMutexStatic xSemaphoreCreateMutexStatic + * \ingroup Semaphores + */ + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) + #define xSemaphoreCreateMutexStatic( pxMutexBuffer ) xQueueCreateMutexStatic( queueQUEUE_TYPE_MUTEX, ( pxMutexBuffer ) ) +#endif /* configSUPPORT_STATIC_ALLOCATION */ + + +/** + * semphr. h + *
SemaphoreHandle_t xSemaphoreCreateRecursiveMutex( void )
+ * + * Creates a new recursive mutex type semaphore instance, and returns a handle + * by which the new recursive mutex can be referenced. + * + * Internally, within the FreeRTOS implementation, recursive mutexs use a block + * of memory, in which the mutex structure is stored. If a recursive mutex is + * created using xSemaphoreCreateRecursiveMutex() then the required memory is + * automatically dynamically allocated inside the + * xSemaphoreCreateRecursiveMutex() function. (see + * http://www.freertos.org/a00111.html). If a recursive mutex is created using + * xSemaphoreCreateRecursiveMutexStatic() then the application writer must + * provide the memory that will get used by the mutex. + * xSemaphoreCreateRecursiveMutexStatic() therefore allows a recursive mutex to + * be created without using any dynamic memory allocation. + * + * Mutexes created using this macro can be accessed using the + * xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() macros. The + * xSemaphoreTake() and xSemaphoreGive() macros must not be used. + * + * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex + * doesn't become available again until the owner has called + * xSemaphoreGiveRecursive() for each successful 'take' request. For example, + * if a task successfully 'takes' the same mutex 5 times then the mutex will + * not be available to any other task until it has also 'given' the mutex back + * exactly five times. + * + * This type of semaphore uses a priority inheritance mechanism so a task + * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the + * semaphore it is no longer required. + * + * Mutex type semaphores cannot be used from within interrupt service routines. + * + * See xSemaphoreCreateBinary() for an alternative implementation that can be + * used for pure synchronisation (where one task or interrupt always 'gives' the + * semaphore and another always 'takes' the semaphore) and from within interrupt + * service routines. + * + * @return xSemaphore Handle to the created mutex semaphore. Should be of type + * SemaphoreHandle_t. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore;
+
+ void vATask( void * pvParameters )
+ {
+    // Semaphore cannot be used before a call to xSemaphoreCreateMutex().
+    // This is a macro so pass the variable in directly.
+    xSemaphore = xSemaphoreCreateRecursiveMutex();
+
+    if( xSemaphore != NULL )
+    {
+        // The semaphore was created successfully.
+        // The semaphore can now be used.
+    }
+ }
+ 
+ * \defgroup xSemaphoreCreateRecursiveMutex xSemaphoreCreateRecursiveMutex + * \ingroup Semaphores + */ +#if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configUSE_RECURSIVE_MUTEXES == 1 ) ) + #define xSemaphoreCreateRecursiveMutex() xQueueCreateMutex( queueQUEUE_TYPE_RECURSIVE_MUTEX ) +#endif + +/** + * semphr. h + *
SemaphoreHandle_t xSemaphoreCreateRecursiveMutexStatic( StaticSemaphore_t *pxMutexBuffer )
+ * + * Creates a new recursive mutex type semaphore instance, and returns a handle + * by which the new recursive mutex can be referenced. + * + * Internally, within the FreeRTOS implementation, recursive mutexs use a block + * of memory, in which the mutex structure is stored. If a recursive mutex is + * created using xSemaphoreCreateRecursiveMutex() then the required memory is + * automatically dynamically allocated inside the + * xSemaphoreCreateRecursiveMutex() function. (see + * http://www.freertos.org/a00111.html). If a recursive mutex is created using + * xSemaphoreCreateRecursiveMutexStatic() then the application writer must + * provide the memory that will get used by the mutex. + * xSemaphoreCreateRecursiveMutexStatic() therefore allows a recursive mutex to + * be created without using any dynamic memory allocation. + * + * Mutexes created using this macro can be accessed using the + * xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() macros. The + * xSemaphoreTake() and xSemaphoreGive() macros must not be used. + * + * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex + * doesn't become available again until the owner has called + * xSemaphoreGiveRecursive() for each successful 'take' request. For example, + * if a task successfully 'takes' the same mutex 5 times then the mutex will + * not be available to any other task until it has also 'given' the mutex back + * exactly five times. + * + * This type of semaphore uses a priority inheritance mechanism so a task + * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the + * semaphore it is no longer required. + * + * Mutex type semaphores cannot be used from within interrupt service routines. + * + * See xSemaphoreCreateBinary() for an alternative implementation that can be + * used for pure synchronisation (where one task or interrupt always 'gives' the + * semaphore and another always 'takes' the semaphore) and from within interrupt + * service routines. + * + * @param pxMutexBuffer Must point to a variable of type StaticSemaphore_t, + * which will then be used to hold the recursive mutex's data structure, + * removing the need for the memory to be allocated dynamically. + * + * @return If the recursive mutex was successfully created then a handle to the + * created recursive mutex is returned. If pxMutexBuffer was NULL then NULL is + * returned. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore;
+ StaticSemaphore_t xMutexBuffer;
+
+ void vATask( void * pvParameters )
+ {
+    // A recursive semaphore cannot be used before it is created.  Here a
+    // recursive mutex is created using xSemaphoreCreateRecursiveMutexStatic().
+    // The address of xMutexBuffer is passed into the function, and will hold
+    // the mutexes data structures - so no dynamic memory allocation will be
+    // attempted.
+    xSemaphore = xSemaphoreCreateRecursiveMutexStatic( &xMutexBuffer );
+
+    // As no dynamic memory allocation was performed, xSemaphore cannot be NULL,
+    // so there is no need to check it.
+ }
+ 
+ * \defgroup xSemaphoreCreateRecursiveMutexStatic xSemaphoreCreateRecursiveMutexStatic + * \ingroup Semaphores + */ +#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configUSE_RECURSIVE_MUTEXES == 1 ) ) + #define xSemaphoreCreateRecursiveMutexStatic( pxStaticSemaphore ) xQueueCreateMutexStatic( queueQUEUE_TYPE_RECURSIVE_MUTEX, pxStaticSemaphore ) +#endif /* configSUPPORT_STATIC_ALLOCATION */ + +/** + * semphr. h + *
SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount )
+ * + * Creates a new counting semaphore instance, and returns a handle by which the + * new counting semaphore can be referenced. + * + * In many usage scenarios it is faster and more memory efficient to use a + * direct to task notification in place of a counting semaphore! + * http://www.freertos.org/RTOS-task-notifications.html + * + * Internally, within the FreeRTOS implementation, counting semaphores use a + * block of memory, in which the counting semaphore structure is stored. If a + * counting semaphore is created using xSemaphoreCreateCounting() then the + * required memory is automatically dynamically allocated inside the + * xSemaphoreCreateCounting() function. (see + * http://www.freertos.org/a00111.html). If a counting semaphore is created + * using xSemaphoreCreateCountingStatic() then the application writer can + * instead optionally provide the memory that will get used by the counting + * semaphore. xSemaphoreCreateCountingStatic() therefore allows a counting + * semaphore to be created without using any dynamic memory allocation. + * + * Counting semaphores are typically used for two things: + * + * 1) Counting events. + * + * In this usage scenario an event handler will 'give' a semaphore each time + * an event occurs (incrementing the semaphore count value), and a handler + * task will 'take' a semaphore each time it processes an event + * (decrementing the semaphore count value). The count value is therefore + * the difference between the number of events that have occurred and the + * number that have been processed. In this case it is desirable for the + * initial count value to be zero. + * + * 2) Resource management. + * + * In this usage scenario the count value indicates the number of resources + * available. To obtain control of a resource a task must first obtain a + * semaphore - decrementing the semaphore count value. When the count value + * reaches zero there are no free resources. When a task finishes with the + * resource it 'gives' the semaphore back - incrementing the semaphore count + * value. In this case it is desirable for the initial count value to be + * equal to the maximum count value, indicating that all resources are free. + * + * @param uxMaxCount The maximum count value that can be reached. When the + * semaphore reaches this value it can no longer be 'given'. + * + * @param uxInitialCount The count value assigned to the semaphore when it is + * created. + * + * @return Handle to the created semaphore. Null if the semaphore could not be + * created. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore;
+
+ void vATask( void * pvParameters )
+ {
+ SemaphoreHandle_t xSemaphore = NULL;
+
+    // Semaphore cannot be used before a call to xSemaphoreCreateCounting().
+    // The max value to which the semaphore can count should be 10, and the
+    // initial value assigned to the count should be 0.
+    xSemaphore = xSemaphoreCreateCounting( 10, 0 );
+
+    if( xSemaphore != NULL )
+    {
+        // The semaphore was created successfully.
+        // The semaphore can now be used.
+    }
+ }
+ 
+ * \defgroup xSemaphoreCreateCounting xSemaphoreCreateCounting + * \ingroup Semaphores + */ +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + #define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) ) +#endif + +/** + * semphr. h + *
SemaphoreHandle_t xSemaphoreCreateCountingStatic( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount, StaticSemaphore_t *pxSemaphoreBuffer )
+ * + * Creates a new counting semaphore instance, and returns a handle by which the + * new counting semaphore can be referenced. + * + * In many usage scenarios it is faster and more memory efficient to use a + * direct to task notification in place of a counting semaphore! + * http://www.freertos.org/RTOS-task-notifications.html + * + * Internally, within the FreeRTOS implementation, counting semaphores use a + * block of memory, in which the counting semaphore structure is stored. If a + * counting semaphore is created using xSemaphoreCreateCounting() then the + * required memory is automatically dynamically allocated inside the + * xSemaphoreCreateCounting() function. (see + * http://www.freertos.org/a00111.html). If a counting semaphore is created + * using xSemaphoreCreateCountingStatic() then the application writer must + * provide the memory. xSemaphoreCreateCountingStatic() therefore allows a + * counting semaphore to be created without using any dynamic memory allocation. + * + * Counting semaphores are typically used for two things: + * + * 1) Counting events. + * + * In this usage scenario an event handler will 'give' a semaphore each time + * an event occurs (incrementing the semaphore count value), and a handler + * task will 'take' a semaphore each time it processes an event + * (decrementing the semaphore count value). The count value is therefore + * the difference between the number of events that have occurred and the + * number that have been processed. In this case it is desirable for the + * initial count value to be zero. + * + * 2) Resource management. + * + * In this usage scenario the count value indicates the number of resources + * available. To obtain control of a resource a task must first obtain a + * semaphore - decrementing the semaphore count value. When the count value + * reaches zero there are no free resources. When a task finishes with the + * resource it 'gives' the semaphore back - incrementing the semaphore count + * value. In this case it is desirable for the initial count value to be + * equal to the maximum count value, indicating that all resources are free. + * + * @param uxMaxCount The maximum count value that can be reached. When the + * semaphore reaches this value it can no longer be 'given'. + * + * @param uxInitialCount The count value assigned to the semaphore when it is + * created. + * + * @param pxSemaphoreBuffer Must point to a variable of type StaticSemaphore_t, + * which will then be used to hold the semaphore's data structure, removing the + * need for the memory to be allocated dynamically. + * + * @return If the counting semaphore was successfully created then a handle to + * the created counting semaphore is returned. If pxSemaphoreBuffer was NULL + * then NULL is returned. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore;
+ StaticSemaphore_t xSemaphoreBuffer;
+
+ void vATask( void * pvParameters )
+ {
+ SemaphoreHandle_t xSemaphore = NULL;
+
+    // Counting semaphore cannot be used before they have been created.  Create
+    // a counting semaphore using xSemaphoreCreateCountingStatic().  The max
+    // value to which the semaphore can count is 10, and the initial value
+    // assigned to the count will be 0.  The address of xSemaphoreBuffer is
+    // passed in and will be used to hold the semaphore structure, so no dynamic
+    // memory allocation will be used.
+    xSemaphore = xSemaphoreCreateCounting( 10, 0, &xSemaphoreBuffer );
+
+    // No memory allocation was attempted so xSemaphore cannot be NULL, so there
+    // is no need to check its value.
+ }
+ 
+ * \defgroup xSemaphoreCreateCountingStatic xSemaphoreCreateCountingStatic + * \ingroup Semaphores + */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + #define xSemaphoreCreateCountingStatic( uxMaxCount, uxInitialCount, pxSemaphoreBuffer ) xQueueCreateCountingSemaphoreStatic( ( uxMaxCount ), ( uxInitialCount ), ( pxSemaphoreBuffer ) ) +#endif /* configSUPPORT_STATIC_ALLOCATION */ + +/** + * semphr. h + *
void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );
+ * + * Delete a semaphore. This function must be used with care. For example, + * do not delete a mutex type semaphore if the mutex is held by a task. + * + * @param xSemaphore A handle to the semaphore to be deleted. + * + * \defgroup vSemaphoreDelete vSemaphoreDelete + * \ingroup Semaphores + */ +#define vSemaphoreDelete( xSemaphore ) vQueueDelete( ( QueueHandle_t ) ( xSemaphore ) ) + +/** + * semphr.h + *
TaskHandle_t xSemaphoreGetMutexHolder( SemaphoreHandle_t xMutex );
+ * + * If xMutex is indeed a mutex type semaphore, return the current mutex holder. + * If xMutex is not a mutex type semaphore, or the mutex is available (not held + * by a task), return NULL. + * + * Note: This is a good way of determining if the calling task is the mutex + * holder, but not a good way of determining the identity of the mutex holder as + * the holder may change between the function exiting and the returned value + * being tested. + */ +#define xSemaphoreGetMutexHolder( xSemaphore ) xQueueGetMutexHolder( ( xSemaphore ) ) + +/** + * semphr.h + *
UBaseType_t uxSemaphoreGetCount( SemaphoreHandle_t xSemaphore );
+ * + * If the semaphore is a counting semaphore then uxSemaphoreGetCount() returns + * its current count value. If the semaphore is a binary semaphore then + * uxSemaphoreGetCount() returns 1 if the semaphore is available, and 0 if the + * semaphore is not available. + * + */ +#define uxSemaphoreGetCount( xSemaphore ) uxQueueMessagesWaiting( ( QueueHandle_t ) ( xSemaphore ) ) + +#endif /* SEMAPHORE_H */ + + diff --git a/STM32F1/libraries/FreeRTOS900/utility/stdint.readme b/STM32F1/libraries/FreeRTOS900/utility/stdint.readme new file mode 100644 index 0000000..4414c29 --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/utility/stdint.readme @@ -0,0 +1,27 @@ + +#ifndef FREERTOS_STDINT +#define FREERTOS_STDINT + +/******************************************************************************* + * THIS IS NOT A FULL stdint.h IMPLEMENTATION - It only contains the definitions + * necessary to build the FreeRTOS code. It is provided to allow FreeRTOS to be + * built using compilers that do not provide their own stdint.h definition. + * + * To use this file: + * + * 1) Copy this file into the directory that contains your FreeRTOSConfig.h + * header file, as that directory will already be in the compilers include + * path. + * + * 2) Rename the copied file stdint.h. + * + */ + +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef long int32_t; +typedef unsigned long uint32_t; + +#endif /* FREERTOS_STDINT */ diff --git a/STM32F1/libraries/FreeRTOS900/utility/task.h b/STM32F1/libraries/FreeRTOS900/utility/task.h new file mode 100644 index 0000000..d0643c0 --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/utility/task.h @@ -0,0 +1,2267 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + + +#ifndef INC_TASK_H +#define INC_TASK_H + +#ifndef INC_FREERTOS_H + #error "include FreeRTOS.h must appear in source files before include task.h" +#endif + +#include "list.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*----------------------------------------------------------- + * MACROS AND DEFINITIONS + *----------------------------------------------------------*/ + +#define tskKERNEL_VERSION_NUMBER "V9.0.0" +#define tskKERNEL_VERSION_MAJOR 9 +#define tskKERNEL_VERSION_MINOR 0 +#define tskKERNEL_VERSION_BUILD 0 + +/** + * task. h + * + * Type by which tasks are referenced. For example, a call to xTaskCreate + * returns (via a pointer parameter) an TaskHandle_t variable that can then + * be used as a parameter to vTaskDelete to delete the task. + * + * \defgroup TaskHandle_t TaskHandle_t + * \ingroup Tasks + */ +typedef void * TaskHandle_t; + +/* + * Defines the prototype to which the application task hook function must + * conform. + */ +typedef BaseType_t (*TaskHookFunction_t)( void * ); + +/* Task states returned by eTaskGetState. */ +typedef enum +{ + eRunning = 0, /* A task is querying the state of itself, so must be running. */ + eReady, /* The task being queried is in a read or pending ready list. */ + eBlocked, /* The task being queried is in the Blocked state. */ + eSuspended, /* The task being queried is in the Suspended state, or is in the Blocked state with an infinite time out. */ + eDeleted, /* The task being queried has been deleted, but its TCB has not yet been freed. */ + eInvalid /* Used as an 'invalid state' value. */ +} eTaskState; + +/* Actions that can be performed when vTaskNotify() is called. */ +typedef enum +{ + eNoAction = 0, /* Notify the task without updating its notify value. */ + eSetBits, /* Set bits in the task's notification value. */ + eIncrement, /* Increment the task's notification value. */ + eSetValueWithOverwrite, /* Set the task's notification value to a specific value even if the previous value has not yet been read by the task. */ + eSetValueWithoutOverwrite /* Set the task's notification value if the previous value has been read by the task. */ +} eNotifyAction; + +/* + * Used internally only. + */ +typedef struct xTIME_OUT +{ + BaseType_t xOverflowCount; + TickType_t xTimeOnEntering; +} TimeOut_t; + +/* + * Defines the memory ranges allocated to the task when an MPU is used. + */ +typedef struct xMEMORY_REGION +{ + void *pvBaseAddress; + uint32_t ulLengthInBytes; + uint32_t ulParameters; +} MemoryRegion_t; + +/* + * Parameters required to create an MPU protected task. + */ +typedef struct xTASK_PARAMETERS +{ + TaskFunction_t pvTaskCode; + const char * const pcName; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + uint16_t usStackDepth; + void *pvParameters; + UBaseType_t uxPriority; + StackType_t *puxStackBuffer; + MemoryRegion_t xRegions[ portNUM_CONFIGURABLE_REGIONS ]; +} TaskParameters_t; + +/* Used with the uxTaskGetSystemState() function to return the state of each task +in the system. */ +typedef struct xTASK_STATUS +{ + TaskHandle_t xHandle; /* The handle of the task to which the rest of the information in the structure relates. */ + const char *pcTaskName; /* A pointer to the task's name. This value will be invalid if the task was deleted since the structure was populated! */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + UBaseType_t xTaskNumber; /* A number unique to the task. */ + eTaskState eCurrentState; /* The state in which the task existed when the structure was populated. */ + UBaseType_t uxCurrentPriority; /* The priority at which the task was running (may be inherited) when the structure was populated. */ + UBaseType_t uxBasePriority; /* The priority to which the task will return if the task's current priority has been inherited to avoid unbounded priority inversion when obtaining a mutex. Only valid if configUSE_MUTEXES is defined as 1 in FreeRTOSConfig.h. */ + uint32_t ulRunTimeCounter; /* The total run time allocated to the task so far, as defined by the run time stats clock. See http://www.freertos.org/rtos-run-time-stats.html. Only valid when configGENERATE_RUN_TIME_STATS is defined as 1 in FreeRTOSConfig.h. */ + StackType_t *pxStackBase; /* Points to the lowest address of the task's stack area. */ + uint16_t usStackHighWaterMark; /* The minimum amount of stack space that has remained for the task since the task was created. The closer this value is to zero the closer the task has come to overflowing its stack. */ +} TaskStatus_t; + +/* Possible return values for eTaskConfirmSleepModeStatus(). */ +typedef enum +{ + eAbortSleep = 0, /* A task has been made ready or a context switch pended since portSUPPORESS_TICKS_AND_SLEEP() was called - abort entering a sleep mode. */ + eStandardSleep, /* Enter a sleep mode that will not last any longer than the expected idle time. */ + eNoTasksWaitingTimeout /* No tasks are waiting for a timeout so it is safe to enter a sleep mode that can only be exited by an external interrupt. */ +} eSleepModeStatus; + +/** + * Defines the priority used by the idle task. This must not be modified. + * + * \ingroup TaskUtils + */ +#define tskIDLE_PRIORITY ( ( UBaseType_t ) 0U ) + +/** + * task. h + * + * Macro for forcing a context switch. + * + * \defgroup taskYIELD taskYIELD + * \ingroup SchedulerControl + */ +#define taskYIELD() portYIELD() + +/** + * task. h + * + * Macro to mark the start of a critical code region. Preemptive context + * switches cannot occur when in a critical region. + * + * NOTE: This may alter the stack (depending on the portable implementation) + * so must be used with care! + * + * \defgroup taskENTER_CRITICAL taskENTER_CRITICAL + * \ingroup SchedulerControl + */ +#define taskENTER_CRITICAL() portENTER_CRITICAL() +#define taskENTER_CRITICAL_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR() + +/** + * task. h + * + * Macro to mark the end of a critical code region. Preemptive context + * switches cannot occur when in a critical region. + * + * NOTE: This may alter the stack (depending on the portable implementation) + * so must be used with care! + * + * \defgroup taskEXIT_CRITICAL taskEXIT_CRITICAL + * \ingroup SchedulerControl + */ +#define taskEXIT_CRITICAL() portEXIT_CRITICAL() +#define taskEXIT_CRITICAL_FROM_ISR( x ) portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) +/** + * task. h + * + * Macro to disable all maskable interrupts. + * + * \defgroup taskDISABLE_INTERRUPTS taskDISABLE_INTERRUPTS + * \ingroup SchedulerControl + */ +#define taskDISABLE_INTERRUPTS() portDISABLE_INTERRUPTS() + +/** + * task. h + * + * Macro to enable microcontroller interrupts. + * + * \defgroup taskENABLE_INTERRUPTS taskENABLE_INTERRUPTS + * \ingroup SchedulerControl + */ +#define taskENABLE_INTERRUPTS() portENABLE_INTERRUPTS() + +/* Definitions returned by xTaskGetSchedulerState(). taskSCHEDULER_SUSPENDED is +0 to generate more optimal code when configASSERT() is defined as the constant +is used in assert() statements. */ +#define taskSCHEDULER_SUSPENDED ( ( BaseType_t ) 0 ) +#define taskSCHEDULER_NOT_STARTED ( ( BaseType_t ) 1 ) +#define taskSCHEDULER_RUNNING ( ( BaseType_t ) 2 ) + + +/*----------------------------------------------------------- + * TASK CREATION API + *----------------------------------------------------------*/ + +/** + * task. h + *
+ BaseType_t xTaskCreate(
+							  TaskFunction_t pvTaskCode,
+							  const char * const pcName,
+							  uint16_t usStackDepth,
+							  void *pvParameters,
+							  UBaseType_t uxPriority,
+							  TaskHandle_t *pvCreatedTask
+						  );
+ * + * Create a new task and add it to the list of tasks that are ready to run. + * + * Internally, within the FreeRTOS implementation, tasks use two blocks of + * memory. The first block is used to hold the task's data structures. The + * second block is used by the task as its stack. If a task is created using + * xTaskCreate() then both blocks of memory are automatically dynamically + * allocated inside the xTaskCreate() function. (see + * http://www.freertos.org/a00111.html). If a task is created using + * xTaskCreateStatic() then the application writer must provide the required + * memory. xTaskCreateStatic() therefore allows a task to be created without + * using any dynamic memory allocation. + * + * See xTaskCreateStatic() for a version that does not use any dynamic memory + * allocation. + * + * xTaskCreate() can only be used to create a task that has unrestricted + * access to the entire microcontroller memory map. Systems that include MPU + * support can alternatively create an MPU constrained task using + * xTaskCreateRestricted(). + * + * @param pvTaskCode Pointer to the task entry function. Tasks + * must be implemented to never return (i.e. continuous loop). + * + * @param pcName A descriptive name for the task. This is mainly used to + * facilitate debugging. Max length defined by configMAX_TASK_NAME_LEN - default + * is 16. + * + * @param usStackDepth The size of the task stack specified as the number of + * variables the stack can hold - not the number of bytes. For example, if + * the stack is 16 bits wide and usStackDepth is defined as 100, 200 bytes + * will be allocated for stack storage. + * + * @param pvParameters Pointer that will be used as the parameter for the task + * being created. + * + * @param uxPriority The priority at which the task should run. Systems that + * include MPU support can optionally create tasks in a privileged (system) + * mode by setting bit portPRIVILEGE_BIT of the priority parameter. For + * example, to create a privileged task at priority 2 the uxPriority parameter + * should be set to ( 2 | portPRIVILEGE_BIT ). + * + * @param pvCreatedTask Used to pass back a handle by which the created task + * can be referenced. + * + * @return pdPASS if the task was successfully created and added to a ready + * list, otherwise an error code defined in the file projdefs.h + * + * Example usage: +
+ // Task to be created.
+ void vTaskCode( void * pvParameters )
+ {
+	 for( ;; )
+	 {
+		 // Task code goes here.
+	 }
+ }
+
+ // Function that creates a task.
+ void vOtherFunction( void )
+ {
+ static uint8_t ucParameterToPass;
+ TaskHandle_t xHandle = NULL;
+
+	 // Create the task, storing the handle.  Note that the passed parameter ucParameterToPass
+	 // must exist for the lifetime of the task, so in this case is declared static.  If it was just an
+	 // an automatic stack variable it might no longer exist, or at least have been corrupted, by the time
+	 // the new task attempts to access it.
+	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, &ucParameterToPass, tskIDLE_PRIORITY, &xHandle );
+     configASSERT( xHandle );
+
+	 // Use the handle to delete the task.
+     if( xHandle != NULL )
+     {
+	     vTaskDelete( xHandle );
+     }
+ }
+   
+ * \defgroup xTaskCreate xTaskCreate + * \ingroup Tasks + */ +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, + const char * const pcName, + const uint16_t usStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t * const pxCreatedTask ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +#endif + +/** + * task. h + *
+ TaskHandle_t xTaskCreateStatic( TaskFunction_t pvTaskCode,
+								 const char * const pcName,
+								 uint32_t ulStackDepth,
+								 void *pvParameters,
+								 UBaseType_t uxPriority,
+								 StackType_t *pxStackBuffer,
+								 StaticTask_t *pxTaskBuffer );
+ * + * Create a new task and add it to the list of tasks that are ready to run. + * + * Internally, within the FreeRTOS implementation, tasks use two blocks of + * memory. The first block is used to hold the task's data structures. The + * second block is used by the task as its stack. If a task is created using + * xTaskCreate() then both blocks of memory are automatically dynamically + * allocated inside the xTaskCreate() function. (see + * http://www.freertos.org/a00111.html). If a task is created using + * xTaskCreateStatic() then the application writer must provide the required + * memory. xTaskCreateStatic() therefore allows a task to be created without + * using any dynamic memory allocation. + * + * @param pvTaskCode Pointer to the task entry function. Tasks + * must be implemented to never return (i.e. continuous loop). + * + * @param pcName A descriptive name for the task. This is mainly used to + * facilitate debugging. The maximum length of the string is defined by + * configMAX_TASK_NAME_LEN in FreeRTOSConfig.h. + * + * @param ulStackDepth The size of the task stack specified as the number of + * variables the stack can hold - not the number of bytes. For example, if + * the stack is 32-bits wide and ulStackDepth is defined as 100 then 400 bytes + * will be allocated for stack storage. + * + * @param pvParameters Pointer that will be used as the parameter for the task + * being created. + * + * @param uxPriority The priority at which the task will run. + * + * @param pxStackBuffer Must point to a StackType_t array that has at least + * ulStackDepth indexes - the array will then be used as the task's stack, + * removing the need for the stack to be allocated dynamically. + * + * @param pxTaskBuffer Must point to a variable of type StaticTask_t, which will + * then be used to hold the task's data structures, removing the need for the + * memory to be allocated dynamically. + * + * @return If neither pxStackBuffer or pxTaskBuffer are NULL, then the task will + * be created and pdPASS is returned. If either pxStackBuffer or pxTaskBuffer + * are NULL then the task will not be created and + * errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY is returned. + * + * Example usage: +
+
+    // Dimensions the buffer that the task being created will use as its stack.
+    // NOTE:  This is the number of words the stack will hold, not the number of
+    // bytes.  For example, if each stack item is 32-bits, and this is set to 100,
+    // then 400 bytes (100 * 32-bits) will be allocated.
+    #define STACK_SIZE 200
+
+    // Structure that will hold the TCB of the task being created.
+    StaticTask_t xTaskBuffer;
+
+    // Buffer that the task being created will use as its stack.  Note this is
+    // an array of StackType_t variables.  The size of StackType_t is dependent on
+    // the RTOS port.
+    StackType_t xStack[ STACK_SIZE ];
+
+    // Function that implements the task being created.
+    void vTaskCode( void * pvParameters )
+    {
+        // The parameter value is expected to be 1 as 1 is passed in the
+        // pvParameters value in the call to xTaskCreateStatic().
+        configASSERT( ( uint32_t ) pvParameters == 1UL );
+
+        for( ;; )
+        {
+            // Task code goes here.
+        }
+    }
+
+    // Function that creates a task.
+    void vOtherFunction( void )
+    {
+        TaskHandle_t xHandle = NULL;
+
+        // Create the task without using any dynamic memory allocation.
+        xHandle = xTaskCreateStatic(
+                      vTaskCode,       // Function that implements the task.
+                      "NAME",          // Text name for the task.
+                      STACK_SIZE,      // Stack size in words, not bytes.
+                      ( void * ) 1,    // Parameter passed into the task.
+                      tskIDLE_PRIORITY,// Priority at which the task is created.
+                      xStack,          // Array to use as the task's stack.
+                      &xTaskBuffer );  // Variable to hold the task's data structure.
+
+        // puxStackBuffer and pxTaskBuffer were not NULL, so the task will have
+        // been created, and xHandle will be the task's handle.  Use the handle
+        // to suspend the task.
+        vTaskSuspend( xHandle );
+    }
+   
+ * \defgroup xTaskCreateStatic xTaskCreateStatic + * \ingroup Tasks + */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode, + const char * const pcName, + const uint32_t ulStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + StackType_t * const puxStackBuffer, + StaticTask_t * const pxTaskBuffer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +#endif /* configSUPPORT_STATIC_ALLOCATION */ + +/** + * task. h + *
+ BaseType_t xTaskCreateRestricted( TaskParameters_t *pxTaskDefinition, TaskHandle_t *pxCreatedTask );
+ * + * xTaskCreateRestricted() should only be used in systems that include an MPU + * implementation. + * + * Create a new task and add it to the list of tasks that are ready to run. + * The function parameters define the memory regions and associated access + * permissions allocated to the task. + * + * @param pxTaskDefinition Pointer to a structure that contains a member + * for each of the normal xTaskCreate() parameters (see the xTaskCreate() API + * documentation) plus an optional stack buffer and the memory region + * definitions. + * + * @param pxCreatedTask Used to pass back a handle by which the created task + * can be referenced. + * + * @return pdPASS if the task was successfully created and added to a ready + * list, otherwise an error code defined in the file projdefs.h + * + * Example usage: +
+// Create an TaskParameters_t structure that defines the task to be created.
+static const TaskParameters_t xCheckTaskParameters =
+{
+	vATask,		// pvTaskCode - the function that implements the task.
+	"ATask",	// pcName - just a text name for the task to assist debugging.
+	100,		// usStackDepth	- the stack size DEFINED IN WORDS.
+	NULL,		// pvParameters - passed into the task function as the function parameters.
+	( 1UL | portPRIVILEGE_BIT ),// uxPriority - task priority, set the portPRIVILEGE_BIT if the task should run in a privileged state.
+	cStackBuffer,// puxStackBuffer - the buffer to be used as the task stack.
+
+	// xRegions - Allocate up to three separate memory regions for access by
+	// the task, with appropriate access permissions.  Different processors have
+	// different memory alignment requirements - refer to the FreeRTOS documentation
+	// for full information.
+	{
+		// Base address					Length	Parameters
+        { cReadWriteArray,				32,		portMPU_REGION_READ_WRITE },
+        { cReadOnlyArray,				32,		portMPU_REGION_READ_ONLY },
+        { cPrivilegedOnlyAccessArray,	128,	portMPU_REGION_PRIVILEGED_READ_WRITE }
+	}
+};
+
+int main( void )
+{
+TaskHandle_t xHandle;
+
+	// Create a task from the const structure defined above.  The task handle
+	// is requested (the second parameter is not NULL) but in this case just for
+	// demonstration purposes as its not actually used.
+	xTaskCreateRestricted( &xRegTest1Parameters, &xHandle );
+
+	// Start the scheduler.
+	vTaskStartScheduler();
+
+	// Will only get here if there was insufficient memory to create the idle
+	// and/or timer task.
+	for( ;; );
+}
+   
+ * \defgroup xTaskCreateRestricted xTaskCreateRestricted + * \ingroup Tasks + */ +#if( portUSING_MPU_WRAPPERS == 1 ) + BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ) PRIVILEGED_FUNCTION; +#endif + +/** + * task. h + *
+ void vTaskAllocateMPURegions( TaskHandle_t xTask, const MemoryRegion_t * const pxRegions );
+ * + * Memory regions are assigned to a restricted task when the task is created by + * a call to xTaskCreateRestricted(). These regions can be redefined using + * vTaskAllocateMPURegions(). + * + * @param xTask The handle of the task being updated. + * + * @param xRegions A pointer to an MemoryRegion_t structure that contains the + * new memory region definitions. + * + * Example usage: +
+// Define an array of MemoryRegion_t structures that configures an MPU region
+// allowing read/write access for 1024 bytes starting at the beginning of the
+// ucOneKByte array.  The other two of the maximum 3 definable regions are
+// unused so set to zero.
+static const MemoryRegion_t xAltRegions[ portNUM_CONFIGURABLE_REGIONS ] =
+{
+	// Base address		Length		Parameters
+	{ ucOneKByte,		1024,		portMPU_REGION_READ_WRITE },
+	{ 0,				0,			0 },
+	{ 0,				0,			0 }
+};
+
+void vATask( void *pvParameters )
+{
+	// This task was created such that it has access to certain regions of
+	// memory as defined by the MPU configuration.  At some point it is
+	// desired that these MPU regions are replaced with that defined in the
+	// xAltRegions const struct above.  Use a call to vTaskAllocateMPURegions()
+	// for this purpose.  NULL is used as the task handle to indicate that this
+	// function should modify the MPU regions of the calling task.
+	vTaskAllocateMPURegions( NULL, xAltRegions );
+
+	// Now the task can continue its function, but from this point on can only
+	// access its stack and the ucOneKByte array (unless any other statically
+	// defined or shared regions have been declared elsewhere).
+}
+   
+ * \defgroup xTaskCreateRestricted xTaskCreateRestricted + * \ingroup Tasks + */ +void vTaskAllocateMPURegions( TaskHandle_t xTask, const MemoryRegion_t * const pxRegions ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskDelete( TaskHandle_t xTask );
+ * + * INCLUDE_vTaskDelete must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * Remove a task from the RTOS real time kernel's management. The task being + * deleted will be removed from all ready, blocked, suspended and event lists. + * + * NOTE: The idle task is responsible for freeing the kernel allocated + * memory from tasks that have been deleted. It is therefore important that + * the idle task is not starved of microcontroller processing time if your + * application makes any calls to vTaskDelete (). Memory allocated by the + * task code is not automatically freed, and should be freed before the task + * is deleted. + * + * See the demo application file death.c for sample code that utilises + * vTaskDelete (). + * + * @param xTask The handle of the task to be deleted. Passing NULL will + * cause the calling task to be deleted. + * + * Example usage: +
+ void vOtherFunction( void )
+ {
+ TaskHandle_t xHandle;
+
+	 // Create the task, storing the handle.
+	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+	 // Use the handle to delete the task.
+	 vTaskDelete( xHandle );
+ }
+   
+ * \defgroup vTaskDelete vTaskDelete + * \ingroup Tasks + */ +void vTaskDelete( TaskHandle_t xTaskToDelete ) PRIVILEGED_FUNCTION; + +/*----------------------------------------------------------- + * TASK CONTROL API + *----------------------------------------------------------*/ + +/** + * task. h + *
void vTaskDelay( const TickType_t xTicksToDelay );
+ * + * Delay a task for a given number of ticks. The actual time that the + * task remains blocked depends on the tick rate. The constant + * portTICK_PERIOD_MS can be used to calculate real time from the tick + * rate - with the resolution of one tick period. + * + * INCLUDE_vTaskDelay must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * + * vTaskDelay() specifies a time at which the task wishes to unblock relative to + * the time at which vTaskDelay() is called. For example, specifying a block + * period of 100 ticks will cause the task to unblock 100 ticks after + * vTaskDelay() is called. vTaskDelay() does not therefore provide a good method + * of controlling the frequency of a periodic task as the path taken through the + * code, as well as other task and interrupt activity, will effect the frequency + * at which vTaskDelay() gets called and therefore the time at which the task + * next executes. See vTaskDelayUntil() for an alternative API function designed + * to facilitate fixed frequency execution. It does this by specifying an + * absolute time (rather than a relative time) at which the calling task should + * unblock. + * + * @param xTicksToDelay The amount of time, in tick periods, that + * the calling task should block. + * + * Example usage: + + void vTaskFunction( void * pvParameters ) + { + // Block for 500ms. + const TickType_t xDelay = 500 / portTICK_PERIOD_MS; + + for( ;; ) + { + // Simply toggle the LED every 500ms, blocking between each toggle. + vToggleLED(); + vTaskDelay( xDelay ); + } + } + + * \defgroup vTaskDelay vTaskDelay + * \ingroup TaskCtrl + */ +void vTaskDelay( const TickType_t xTicksToDelay ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskDelayUntil( TickType_t *pxPreviousWakeTime, const TickType_t xTimeIncrement );
+ * + * INCLUDE_vTaskDelayUntil must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * Delay a task until a specified time. This function can be used by periodic + * tasks to ensure a constant execution frequency. + * + * This function differs from vTaskDelay () in one important aspect: vTaskDelay () will + * cause a task to block for the specified number of ticks from the time vTaskDelay () is + * called. It is therefore difficult to use vTaskDelay () by itself to generate a fixed + * execution frequency as the time between a task starting to execute and that task + * calling vTaskDelay () may not be fixed [the task may take a different path though the + * code between calls, or may get interrupted or preempted a different number of times + * each time it executes]. + * + * Whereas vTaskDelay () specifies a wake time relative to the time at which the function + * is called, vTaskDelayUntil () specifies the absolute (exact) time at which it wishes to + * unblock. + * + * The constant portTICK_PERIOD_MS can be used to calculate real time from the tick + * rate - with the resolution of one tick period. + * + * @param pxPreviousWakeTime Pointer to a variable that holds the time at which the + * task was last unblocked. The variable must be initialised with the current time + * prior to its first use (see the example below). Following this the variable is + * automatically updated within vTaskDelayUntil (). + * + * @param xTimeIncrement The cycle time period. The task will be unblocked at + * time *pxPreviousWakeTime + xTimeIncrement. Calling vTaskDelayUntil with the + * same xTimeIncrement parameter value will cause the task to execute with + * a fixed interface period. + * + * Example usage: +
+ // Perform an action every 10 ticks.
+ void vTaskFunction( void * pvParameters )
+ {
+ TickType_t xLastWakeTime;
+ const TickType_t xFrequency = 10;
+
+	 // Initialise the xLastWakeTime variable with the current time.
+	 xLastWakeTime = xTaskGetTickCount ();
+	 for( ;; )
+	 {
+		 // Wait for the next cycle.
+		 vTaskDelayUntil( &xLastWakeTime, xFrequency );
+
+		 // Perform action here.
+	 }
+ }
+   
+ * \defgroup vTaskDelayUntil vTaskDelayUntil + * \ingroup TaskCtrl + */ +void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
BaseType_t xTaskAbortDelay( TaskHandle_t xTask );
+ * + * INCLUDE_xTaskAbortDelay must be defined as 1 in FreeRTOSConfig.h for this + * function to be available. + * + * A task will enter the Blocked state when it is waiting for an event. The + * event it is waiting for can be a temporal event (waiting for a time), such + * as when vTaskDelay() is called, or an event on an object, such as when + * xQueueReceive() or ulTaskNotifyTake() is called. If the handle of a task + * that is in the Blocked state is used in a call to xTaskAbortDelay() then the + * task will leave the Blocked state, and return from whichever function call + * placed the task into the Blocked state. + * + * @param xTask The handle of the task to remove from the Blocked state. + * + * @return If the task referenced by xTask was not in the Blocked state then + * pdFAIL is returned. Otherwise pdPASS is returned. + * + * \defgroup xTaskAbortDelay xTaskAbortDelay + * \ingroup TaskCtrl + */ +BaseType_t xTaskAbortDelay( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
UBaseType_t uxTaskPriorityGet( TaskHandle_t xTask );
+ * + * INCLUDE_uxTaskPriorityGet must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * Obtain the priority of any task. + * + * @param xTask Handle of the task to be queried. Passing a NULL + * handle results in the priority of the calling task being returned. + * + * @return The priority of xTask. + * + * Example usage: +
+ void vAFunction( void )
+ {
+ TaskHandle_t xHandle;
+
+	 // Create a task, storing the handle.
+	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+	 // ...
+
+	 // Use the handle to obtain the priority of the created task.
+	 // It was created with tskIDLE_PRIORITY, but may have changed
+	 // it itself.
+	 if( uxTaskPriorityGet( xHandle ) != tskIDLE_PRIORITY )
+	 {
+		 // The task has changed it's priority.
+	 }
+
+	 // ...
+
+	 // Is our priority higher than the created task?
+	 if( uxTaskPriorityGet( xHandle ) < uxTaskPriorityGet( NULL ) )
+	 {
+		 // Our priority (obtained using NULL handle) is higher.
+	 }
+ }
+   
+ * \defgroup uxTaskPriorityGet uxTaskPriorityGet + * \ingroup TaskCtrl + */ +UBaseType_t uxTaskPriorityGet( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
UBaseType_t uxTaskPriorityGetFromISR( TaskHandle_t xTask );
+ * + * A version of uxTaskPriorityGet() that can be used from an ISR. + */ +UBaseType_t uxTaskPriorityGetFromISR( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
eTaskState eTaskGetState( TaskHandle_t xTask );
+ * + * INCLUDE_eTaskGetState must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * Obtain the state of any task. States are encoded by the eTaskState + * enumerated type. + * + * @param xTask Handle of the task to be queried. + * + * @return The state of xTask at the time the function was called. Note the + * state of the task might change between the function being called, and the + * functions return value being tested by the calling task. + */ +eTaskState eTaskGetState( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskGetInfo( TaskHandle_t xTask, TaskStatus_t *pxTaskStatus, BaseType_t xGetFreeStackSpace, eTaskState eState );
+ * + * configUSE_TRACE_FACILITY must be defined as 1 for this function to be + * available. See the configuration section for more information. + * + * Populates a TaskStatus_t structure with information about a task. + * + * @param xTask Handle of the task being queried. If xTask is NULL then + * information will be returned about the calling task. + * + * @param pxTaskStatus A pointer to the TaskStatus_t structure that will be + * filled with information about the task referenced by the handle passed using + * the xTask parameter. + * + * @xGetFreeStackSpace The TaskStatus_t structure contains a member to report + * the stack high water mark of the task being queried. Calculating the stack + * high water mark takes a relatively long time, and can make the system + * temporarily unresponsive - so the xGetFreeStackSpace parameter is provided to + * allow the high water mark checking to be skipped. The high watermark value + * will only be written to the TaskStatus_t structure if xGetFreeStackSpace is + * not set to pdFALSE; + * + * @param eState The TaskStatus_t structure contains a member to report the + * state of the task being queried. Obtaining the task state is not as fast as + * a simple assignment - so the eState parameter is provided to allow the state + * information to be omitted from the TaskStatus_t structure. To obtain state + * information then set eState to eInvalid - otherwise the value passed in + * eState will be reported as the task state in the TaskStatus_t structure. + * + * Example usage: +
+ void vAFunction( void )
+ {
+ TaskHandle_t xHandle;
+ TaskStatus_t xTaskDetails;
+
+    // Obtain the handle of a task from its name.
+    xHandle = xTaskGetHandle( "Task_Name" );
+
+    // Check the handle is not NULL.
+    configASSERT( xHandle );
+
+    // Use the handle to obtain further information about the task.
+    vTaskGetInfo( xHandle,
+                  &xTaskDetails,
+                  pdTRUE, // Include the high water mark in xTaskDetails.
+                  eInvalid ); // Include the task state in xTaskDetails.
+ }
+   
+ * \defgroup vTaskGetInfo vTaskGetInfo + * \ingroup TaskCtrl + */ +void vTaskGetInfo( TaskHandle_t xTask, TaskStatus_t *pxTaskStatus, BaseType_t xGetFreeStackSpace, eTaskState eState ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority );
+ * + * INCLUDE_vTaskPrioritySet must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * Set the priority of any task. + * + * A context switch will occur before the function returns if the priority + * being set is higher than the currently executing task. + * + * @param xTask Handle to the task for which the priority is being set. + * Passing a NULL handle results in the priority of the calling task being set. + * + * @param uxNewPriority The priority to which the task will be set. + * + * Example usage: +
+ void vAFunction( void )
+ {
+ TaskHandle_t xHandle;
+
+	 // Create a task, storing the handle.
+	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+	 // ...
+
+	 // Use the handle to raise the priority of the created task.
+	 vTaskPrioritySet( xHandle, tskIDLE_PRIORITY + 1 );
+
+	 // ...
+
+	 // Use a NULL handle to raise our priority to the same value.
+	 vTaskPrioritySet( NULL, tskIDLE_PRIORITY + 1 );
+ }
+   
+ * \defgroup vTaskPrioritySet vTaskPrioritySet + * \ingroup TaskCtrl + */ +void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskSuspend( TaskHandle_t xTaskToSuspend );
+ * + * INCLUDE_vTaskSuspend must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * Suspend any task. When suspended a task will never get any microcontroller + * processing time, no matter what its priority. + * + * Calls to vTaskSuspend are not accumulative - + * i.e. calling vTaskSuspend () twice on the same task still only requires one + * call to vTaskResume () to ready the suspended task. + * + * @param xTaskToSuspend Handle to the task being suspended. Passing a NULL + * handle will cause the calling task to be suspended. + * + * Example usage: +
+ void vAFunction( void )
+ {
+ TaskHandle_t xHandle;
+
+	 // Create a task, storing the handle.
+	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+	 // ...
+
+	 // Use the handle to suspend the created task.
+	 vTaskSuspend( xHandle );
+
+	 // ...
+
+	 // The created task will not run during this period, unless
+	 // another task calls vTaskResume( xHandle ).
+
+	 //...
+
+
+	 // Suspend ourselves.
+	 vTaskSuspend( NULL );
+
+	 // We cannot get here unless another task calls vTaskResume
+	 // with our handle as the parameter.
+ }
+   
+ * \defgroup vTaskSuspend vTaskSuspend + * \ingroup TaskCtrl + */ +void vTaskSuspend( TaskHandle_t xTaskToSuspend ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskResume( TaskHandle_t xTaskToResume );
+ * + * INCLUDE_vTaskSuspend must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * Resumes a suspended task. + * + * A task that has been suspended by one or more calls to vTaskSuspend () + * will be made available for running again by a single call to + * vTaskResume (). + * + * @param xTaskToResume Handle to the task being readied. + * + * Example usage: +
+ void vAFunction( void )
+ {
+ TaskHandle_t xHandle;
+
+	 // Create a task, storing the handle.
+	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+	 // ...
+
+	 // Use the handle to suspend the created task.
+	 vTaskSuspend( xHandle );
+
+	 // ...
+
+	 // The created task will not run during this period, unless
+	 // another task calls vTaskResume( xHandle ).
+
+	 //...
+
+
+	 // Resume the suspended task ourselves.
+	 vTaskResume( xHandle );
+
+	 // The created task will once again get microcontroller processing
+	 // time in accordance with its priority within the system.
+ }
+   
+ * \defgroup vTaskResume vTaskResume + * \ingroup TaskCtrl + */ +void vTaskResume( TaskHandle_t xTaskToResume ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void xTaskResumeFromISR( TaskHandle_t xTaskToResume );
+ * + * INCLUDE_xTaskResumeFromISR must be defined as 1 for this function to be + * available. See the configuration section for more information. + * + * An implementation of vTaskResume() that can be called from within an ISR. + * + * A task that has been suspended by one or more calls to vTaskSuspend () + * will be made available for running again by a single call to + * xTaskResumeFromISR (). + * + * xTaskResumeFromISR() should not be used to synchronise a task with an + * interrupt if there is a chance that the interrupt could arrive prior to the + * task being suspended - as this can lead to interrupts being missed. Use of a + * semaphore as a synchronisation mechanism would avoid this eventuality. + * + * @param xTaskToResume Handle to the task being readied. + * + * @return pdTRUE if resuming the task should result in a context switch, + * otherwise pdFALSE. This is used by the ISR to determine if a context switch + * may be required following the ISR. + * + * \defgroup vTaskResumeFromISR vTaskResumeFromISR + * \ingroup TaskCtrl + */ +BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume ) PRIVILEGED_FUNCTION; + +/*----------------------------------------------------------- + * SCHEDULER CONTROL + *----------------------------------------------------------*/ + +/** + * task. h + *
void vTaskStartScheduler( void );
+ * + * Starts the real time kernel tick processing. After calling the kernel + * has control over which tasks are executed and when. + * + * See the demo application file main.c for an example of creating + * tasks and starting the kernel. + * + * Example usage: +
+ void vAFunction( void )
+ {
+	 // Create at least one task before starting the kernel.
+	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
+
+	 // Start the real time kernel with preemption.
+	 vTaskStartScheduler ();
+
+	 // Will not get here unless a task calls vTaskEndScheduler ()
+ }
+   
+ * + * \defgroup vTaskStartScheduler vTaskStartScheduler + * \ingroup SchedulerControl + */ +void vTaskStartScheduler( void ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskEndScheduler( void );
+ * + * NOTE: At the time of writing only the x86 real mode port, which runs on a PC + * in place of DOS, implements this function. + * + * Stops the real time kernel tick. All created tasks will be automatically + * deleted and multitasking (either preemptive or cooperative) will + * stop. Execution then resumes from the point where vTaskStartScheduler () + * was called, as if vTaskStartScheduler () had just returned. + * + * See the demo application file main. c in the demo/PC directory for an + * example that uses vTaskEndScheduler (). + * + * vTaskEndScheduler () requires an exit function to be defined within the + * portable layer (see vPortEndScheduler () in port. c for the PC port). This + * performs hardware specific operations such as stopping the kernel tick. + * + * vTaskEndScheduler () will cause all of the resources allocated by the + * kernel to be freed - but will not free resources allocated by application + * tasks. + * + * Example usage: +
+ void vTaskCode( void * pvParameters )
+ {
+	 for( ;; )
+	 {
+		 // Task code goes here.
+
+		 // At some point we want to end the real time kernel processing
+		 // so call ...
+		 vTaskEndScheduler ();
+	 }
+ }
+
+ void vAFunction( void )
+ {
+	 // Create at least one task before starting the kernel.
+	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
+
+	 // Start the real time kernel with preemption.
+	 vTaskStartScheduler ();
+
+	 // Will only get here when the vTaskCode () task has called
+	 // vTaskEndScheduler ().  When we get here we are back to single task
+	 // execution.
+ }
+   
+ * + * \defgroup vTaskEndScheduler vTaskEndScheduler + * \ingroup SchedulerControl + */ +void vTaskEndScheduler( void ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskSuspendAll( void );
+ * + * Suspends the scheduler without disabling interrupts. Context switches will + * not occur while the scheduler is suspended. + * + * After calling vTaskSuspendAll () the calling task will continue to execute + * without risk of being swapped out until a call to xTaskResumeAll () has been + * made. + * + * API functions that have the potential to cause a context switch (for example, + * vTaskDelayUntil(), xQueueSend(), etc.) must not be called while the scheduler + * is suspended. + * + * Example usage: +
+ void vTask1( void * pvParameters )
+ {
+	 for( ;; )
+	 {
+		 // Task code goes here.
+
+		 // ...
+
+		 // At some point the task wants to perform a long operation during
+		 // which it does not want to get swapped out.  It cannot use
+		 // taskENTER_CRITICAL ()/taskEXIT_CRITICAL () as the length of the
+		 // operation may cause interrupts to be missed - including the
+		 // ticks.
+
+		 // Prevent the real time kernel swapping out the task.
+		 vTaskSuspendAll ();
+
+		 // Perform the operation here.  There is no need to use critical
+		 // sections as we have all the microcontroller processing time.
+		 // During this time interrupts will still operate and the kernel
+		 // tick count will be maintained.
+
+		 // ...
+
+		 // The operation is complete.  Restart the kernel.
+		 xTaskResumeAll ();
+	 }
+ }
+   
+ * \defgroup vTaskSuspendAll vTaskSuspendAll + * \ingroup SchedulerControl + */ +void vTaskSuspendAll( void ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
BaseType_t xTaskResumeAll( void );
+ * + * Resumes scheduler activity after it was suspended by a call to + * vTaskSuspendAll(). + * + * xTaskResumeAll() only resumes the scheduler. It does not unsuspend tasks + * that were previously suspended by a call to vTaskSuspend(). + * + * @return If resuming the scheduler caused a context switch then pdTRUE is + * returned, otherwise pdFALSE is returned. + * + * Example usage: +
+ void vTask1( void * pvParameters )
+ {
+	 for( ;; )
+	 {
+		 // Task code goes here.
+
+		 // ...
+
+		 // At some point the task wants to perform a long operation during
+		 // which it does not want to get swapped out.  It cannot use
+		 // taskENTER_CRITICAL ()/taskEXIT_CRITICAL () as the length of the
+		 // operation may cause interrupts to be missed - including the
+		 // ticks.
+
+		 // Prevent the real time kernel swapping out the task.
+		 vTaskSuspendAll ();
+
+		 // Perform the operation here.  There is no need to use critical
+		 // sections as we have all the microcontroller processing time.
+		 // During this time interrupts will still operate and the real
+		 // time kernel tick count will be maintained.
+
+		 // ...
+
+		 // The operation is complete.  Restart the kernel.  We want to force
+		 // a context switch - but there is no point if resuming the scheduler
+		 // caused a context switch already.
+		 if( !xTaskResumeAll () )
+		 {
+			  taskYIELD ();
+		 }
+	 }
+ }
+   
+ * \defgroup xTaskResumeAll xTaskResumeAll + * \ingroup SchedulerControl + */ +BaseType_t xTaskResumeAll( void ) PRIVILEGED_FUNCTION; + +/*----------------------------------------------------------- + * TASK UTILITIES + *----------------------------------------------------------*/ + +/** + * task. h + *
TickType_t xTaskGetTickCount( void );
+ * + * @return The count of ticks since vTaskStartScheduler was called. + * + * \defgroup xTaskGetTickCount xTaskGetTickCount + * \ingroup TaskUtils + */ +TickType_t xTaskGetTickCount( void ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
TickType_t xTaskGetTickCountFromISR( void );
+ * + * @return The count of ticks since vTaskStartScheduler was called. + * + * This is a version of xTaskGetTickCount() that is safe to be called from an + * ISR - provided that TickType_t is the natural word size of the + * microcontroller being used or interrupt nesting is either not supported or + * not being used. + * + * \defgroup xTaskGetTickCountFromISR xTaskGetTickCountFromISR + * \ingroup TaskUtils + */ +TickType_t xTaskGetTickCountFromISR( void ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
uint16_t uxTaskGetNumberOfTasks( void );
+ * + * @return The number of tasks that the real time kernel is currently managing. + * This includes all ready, blocked and suspended tasks. A task that + * has been deleted but not yet freed by the idle task will also be + * included in the count. + * + * \defgroup uxTaskGetNumberOfTasks uxTaskGetNumberOfTasks + * \ingroup TaskUtils + */ +UBaseType_t uxTaskGetNumberOfTasks( void ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
char *pcTaskGetName( TaskHandle_t xTaskToQuery );
+ * + * @return The text (human readable) name of the task referenced by the handle + * xTaskToQuery. A task can query its own name by either passing in its own + * handle, or by setting xTaskToQuery to NULL. + * + * \defgroup pcTaskGetName pcTaskGetName + * \ingroup TaskUtils + */ +char *pcTaskGetName( TaskHandle_t xTaskToQuery ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + +/** + * task. h + *
TaskHandle_t xTaskGetHandle( const char *pcNameToQuery );
+ * + * NOTE: This function takes a relatively long time to complete and should be + * used sparingly. + * + * @return The handle of the task that has the human readable name pcNameToQuery. + * NULL is returned if no matching name is found. INCLUDE_xTaskGetHandle + * must be set to 1 in FreeRTOSConfig.h for pcTaskGetHandle() to be available. + * + * \defgroup pcTaskGetHandle pcTaskGetHandle + * \ingroup TaskUtils + */ +TaskHandle_t xTaskGetHandle( const char *pcNameToQuery ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + +/** + * task.h + *
UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask );
+ * + * INCLUDE_uxTaskGetStackHighWaterMark must be set to 1 in FreeRTOSConfig.h for + * this function to be available. + * + * Returns the high water mark of the stack associated with xTask. That is, + * the minimum free stack space there has been (in words, so on a 32 bit machine + * a value of 1 means 4 bytes) since the task started. The smaller the returned + * number the closer the task has come to overflowing its stack. + * + * @param xTask Handle of the task associated with the stack to be checked. + * Set xTask to NULL to check the stack of the calling task. + * + * @return The smallest amount of free stack space there has been (in words, so + * actual spaces on the stack rather than bytes) since the task referenced by + * xTask was created. + */ +UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; + +/* When using trace macros it is sometimes necessary to include task.h before +FreeRTOS.h. When this is done TaskHookFunction_t will not yet have been defined, +so the following two prototypes will cause a compilation error. This can be +fixed by simply guarding against the inclusion of these two prototypes unless +they are explicitly required by the configUSE_APPLICATION_TASK_TAG configuration +constant. */ +#ifdef configUSE_APPLICATION_TASK_TAG + #if configUSE_APPLICATION_TASK_TAG == 1 + /** + * task.h + *
void vTaskSetApplicationTaskTag( TaskHandle_t xTask, TaskHookFunction_t pxHookFunction );
+ * + * Sets pxHookFunction to be the task hook function used by the task xTask. + * Passing xTask as NULL has the effect of setting the calling tasks hook + * function. + */ + void vTaskSetApplicationTaskTag( TaskHandle_t xTask, TaskHookFunction_t pxHookFunction ) PRIVILEGED_FUNCTION; + + /** + * task.h + *
void xTaskGetApplicationTaskTag( TaskHandle_t xTask );
+ * + * Returns the pxHookFunction value assigned to the task xTask. + */ + TaskHookFunction_t xTaskGetApplicationTaskTag( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; + #endif /* configUSE_APPLICATION_TASK_TAG ==1 */ +#endif /* ifdef configUSE_APPLICATION_TASK_TAG */ + +#if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) + + /* Each task contains an array of pointers that is dimensioned by the + configNUM_THREAD_LOCAL_STORAGE_POINTERS setting in FreeRTOSConfig.h. The + kernel does not use the pointers itself, so the application writer can use + the pointers for any purpose they wish. The following two functions are + used to set and query a pointer respectively. */ + void vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet, BaseType_t xIndex, void *pvValue ) PRIVILEGED_FUNCTION; + void *pvTaskGetThreadLocalStoragePointer( TaskHandle_t xTaskToQuery, BaseType_t xIndex ) PRIVILEGED_FUNCTION; + +#endif + +/** + * task.h + *
BaseType_t xTaskCallApplicationTaskHook( TaskHandle_t xTask, void *pvParameter );
+ * + * Calls the hook function associated with xTask. Passing xTask as NULL has + * the effect of calling the Running tasks (the calling task) hook function. + * + * pvParameter is passed to the hook function for the task to interpret as it + * wants. The return value is the value returned by the task hook function + * registered by the user. + */ +BaseType_t xTaskCallApplicationTaskHook( TaskHandle_t xTask, void *pvParameter ) PRIVILEGED_FUNCTION; + +/** + * xTaskGetIdleTaskHandle() is only available if + * INCLUDE_xTaskGetIdleTaskHandle is set to 1 in FreeRTOSConfig.h. + * + * Simply returns the handle of the idle task. It is not valid to call + * xTaskGetIdleTaskHandle() before the scheduler has been started. + */ +TaskHandle_t xTaskGetIdleTaskHandle( void ) PRIVILEGED_FUNCTION; + +/** + * configUSE_TRACE_FACILITY must be defined as 1 in FreeRTOSConfig.h for + * uxTaskGetSystemState() to be available. + * + * uxTaskGetSystemState() populates an TaskStatus_t structure for each task in + * the system. TaskStatus_t structures contain, among other things, members + * for the task handle, task name, task priority, task state, and total amount + * of run time consumed by the task. See the TaskStatus_t structure + * definition in this file for the full member list. + * + * NOTE: This function is intended for debugging use only as its use results in + * the scheduler remaining suspended for an extended period. + * + * @param pxTaskStatusArray A pointer to an array of TaskStatus_t structures. + * The array must contain at least one TaskStatus_t structure for each task + * that is under the control of the RTOS. The number of tasks under the control + * of the RTOS can be determined using the uxTaskGetNumberOfTasks() API function. + * + * @param uxArraySize The size of the array pointed to by the pxTaskStatusArray + * parameter. The size is specified as the number of indexes in the array, or + * the number of TaskStatus_t structures contained in the array, not by the + * number of bytes in the array. + * + * @param pulTotalRunTime If configGENERATE_RUN_TIME_STATS is set to 1 in + * FreeRTOSConfig.h then *pulTotalRunTime is set by uxTaskGetSystemState() to the + * total run time (as defined by the run time stats clock, see + * http://www.freertos.org/rtos-run-time-stats.html) since the target booted. + * pulTotalRunTime can be set to NULL to omit the total run time information. + * + * @return The number of TaskStatus_t structures that were populated by + * uxTaskGetSystemState(). This should equal the number returned by the + * uxTaskGetNumberOfTasks() API function, but will be zero if the value passed + * in the uxArraySize parameter was too small. + * + * Example usage: +
+    // This example demonstrates how a human readable table of run time stats
+	// information is generated from raw data provided by uxTaskGetSystemState().
+	// The human readable table is written to pcWriteBuffer
+	void vTaskGetRunTimeStats( char *pcWriteBuffer )
+	{
+	TaskStatus_t *pxTaskStatusArray;
+	volatile UBaseType_t uxArraySize, x;
+	uint32_t ulTotalRunTime, ulStatsAsPercentage;
+
+		// Make sure the write buffer does not contain a string.
+		*pcWriteBuffer = 0x00;
+
+		// Take a snapshot of the number of tasks in case it changes while this
+		// function is executing.
+		uxArraySize = uxTaskGetNumberOfTasks();
+
+		// Allocate a TaskStatus_t structure for each task.  An array could be
+		// allocated statically at compile time.
+		pxTaskStatusArray = pvPortMalloc( uxArraySize * sizeof( TaskStatus_t ) );
+
+		if( pxTaskStatusArray != NULL )
+		{
+			// Generate raw status information about each task.
+			uxArraySize = uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, &ulTotalRunTime );
+
+			// For percentage calculations.
+			ulTotalRunTime /= 100UL;
+
+			// Avoid divide by zero errors.
+			if( ulTotalRunTime > 0 )
+			{
+				// For each populated position in the pxTaskStatusArray array,
+				// format the raw data as human readable ASCII data
+				for( x = 0; x < uxArraySize; x++ )
+				{
+					// What percentage of the total run time has the task used?
+					// This will always be rounded down to the nearest integer.
+					// ulTotalRunTimeDiv100 has already been divided by 100.
+					ulStatsAsPercentage = pxTaskStatusArray[ x ].ulRunTimeCounter / ulTotalRunTime;
+
+					if( ulStatsAsPercentage > 0UL )
+					{
+						sprintf( pcWriteBuffer, "%s\t\t%lu\t\t%lu%%\r\n", pxTaskStatusArray[ x ].pcTaskName, pxTaskStatusArray[ x ].ulRunTimeCounter, ulStatsAsPercentage );
+					}
+					else
+					{
+						// If the percentage is zero here then the task has
+						// consumed less than 1% of the total run time.
+						sprintf( pcWriteBuffer, "%s\t\t%lu\t\t<1%%\r\n", pxTaskStatusArray[ x ].pcTaskName, pxTaskStatusArray[ x ].ulRunTimeCounter );
+					}
+
+					pcWriteBuffer += strlen( ( char * ) pcWriteBuffer );
+				}
+			}
+
+			// The array is no longer needed, free the memory it consumes.
+			vPortFree( pxTaskStatusArray );
+		}
+	}
+	
+ */ +UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray, const UBaseType_t uxArraySize, uint32_t * const pulTotalRunTime ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskList( char *pcWriteBuffer );
+ * + * configUSE_TRACE_FACILITY and configUSE_STATS_FORMATTING_FUNCTIONS must + * both be defined as 1 for this function to be available. See the + * configuration section of the FreeRTOS.org website for more information. + * + * NOTE 1: This function will disable interrupts for its duration. It is + * not intended for normal application runtime use but as a debug aid. + * + * Lists all the current tasks, along with their current state and stack + * usage high water mark. + * + * Tasks are reported as blocked ('B'), ready ('R'), deleted ('D') or + * suspended ('S'). + * + * PLEASE NOTE: + * + * This function is provided for convenience only, and is used by many of the + * demo applications. Do not consider it to be part of the scheduler. + * + * vTaskList() calls uxTaskGetSystemState(), then formats part of the + * uxTaskGetSystemState() output into a human readable table that displays task + * names, states and stack usage. + * + * vTaskList() has a dependency on the sprintf() C library function that might + * bloat the code size, use a lot of stack, and provide different results on + * different platforms. An alternative, tiny, third party, and limited + * functionality implementation of sprintf() is provided in many of the + * FreeRTOS/Demo sub-directories in a file called printf-stdarg.c (note + * printf-stdarg.c does not provide a full snprintf() implementation!). + * + * It is recommended that production systems call uxTaskGetSystemState() + * directly to get access to raw stats data, rather than indirectly through a + * call to vTaskList(). + * + * @param pcWriteBuffer A buffer into which the above mentioned details + * will be written, in ASCII form. This buffer is assumed to be large + * enough to contain the generated report. Approximately 40 bytes per + * task should be sufficient. + * + * \defgroup vTaskList vTaskList + * \ingroup TaskUtils + */ +void vTaskList( char * pcWriteBuffer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + +/** + * task. h + *
void vTaskGetRunTimeStats( char *pcWriteBuffer );
+ * + * configGENERATE_RUN_TIME_STATS and configUSE_STATS_FORMATTING_FUNCTIONS + * must both be defined as 1 for this function to be available. The application + * must also then provide definitions for + * portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() and portGET_RUN_TIME_COUNTER_VALUE() + * to configure a peripheral timer/counter and return the timers current count + * value respectively. The counter should be at least 10 times the frequency of + * the tick count. + * + * NOTE 1: This function will disable interrupts for its duration. It is + * not intended for normal application runtime use but as a debug aid. + * + * Setting configGENERATE_RUN_TIME_STATS to 1 will result in a total + * accumulated execution time being stored for each task. The resolution + * of the accumulated time value depends on the frequency of the timer + * configured by the portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() macro. + * Calling vTaskGetRunTimeStats() writes the total execution time of each + * task into a buffer, both as an absolute count value and as a percentage + * of the total system execution time. + * + * NOTE 2: + * + * This function is provided for convenience only, and is used by many of the + * demo applications. Do not consider it to be part of the scheduler. + * + * vTaskGetRunTimeStats() calls uxTaskGetSystemState(), then formats part of the + * uxTaskGetSystemState() output into a human readable table that displays the + * amount of time each task has spent in the Running state in both absolute and + * percentage terms. + * + * vTaskGetRunTimeStats() has a dependency on the sprintf() C library function + * that might bloat the code size, use a lot of stack, and provide different + * results on different platforms. An alternative, tiny, third party, and + * limited functionality implementation of sprintf() is provided in many of the + * FreeRTOS/Demo sub-directories in a file called printf-stdarg.c (note + * printf-stdarg.c does not provide a full snprintf() implementation!). + * + * It is recommended that production systems call uxTaskGetSystemState() directly + * to get access to raw stats data, rather than indirectly through a call to + * vTaskGetRunTimeStats(). + * + * @param pcWriteBuffer A buffer into which the execution times will be + * written, in ASCII form. This buffer is assumed to be large enough to + * contain the generated report. Approximately 40 bytes per task should + * be sufficient. + * + * \defgroup vTaskGetRunTimeStats vTaskGetRunTimeStats + * \ingroup TaskUtils + */ +void vTaskGetRunTimeStats( char *pcWriteBuffer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + +/** + * task. h + *
BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction );
+ * + * configUSE_TASK_NOTIFICATIONS must be undefined or defined as 1 for this + * function to be available. + * + * When configUSE_TASK_NOTIFICATIONS is set to one each task has its own private + * "notification value", which is a 32-bit unsigned integer (uint32_t). + * + * Events can be sent to a task using an intermediary object. Examples of such + * objects are queues, semaphores, mutexes and event groups. Task notifications + * are a method of sending an event directly to a task without the need for such + * an intermediary object. + * + * A notification sent to a task can optionally perform an action, such as + * update, overwrite or increment the task's notification value. In that way + * task notifications can be used to send data to a task, or be used as light + * weight and fast binary or counting semaphores. + * + * A notification sent to a task will remain pending until it is cleared by the + * task calling xTaskNotifyWait() or ulTaskNotifyTake(). If the task was + * already in the Blocked state to wait for a notification when the notification + * arrives then the task will automatically be removed from the Blocked state + * (unblocked) and the notification cleared. + * + * A task can use xTaskNotifyWait() to [optionally] block to wait for a + * notification to be pending, or ulTaskNotifyTake() to [optionally] block + * to wait for its notification value to have a non-zero value. The task does + * not consume any CPU time while it is in the Blocked state. + * + * See http://www.FreeRTOS.org/RTOS-task-notifications.html for details. + * + * @param xTaskToNotify The handle of the task being notified. The handle to a + * task can be returned from the xTaskCreate() API function used to create the + * task, and the handle of the currently running task can be obtained by calling + * xTaskGetCurrentTaskHandle(). + * + * @param ulValue Data that can be sent with the notification. How the data is + * used depends on the value of the eAction parameter. + * + * @param eAction Specifies how the notification updates the task's notification + * value, if at all. Valid values for eAction are as follows: + * + * eSetBits - + * The task's notification value is bitwise ORed with ulValue. xTaskNofify() + * always returns pdPASS in this case. + * + * eIncrement - + * The task's notification value is incremented. ulValue is not used and + * xTaskNotify() always returns pdPASS in this case. + * + * eSetValueWithOverwrite - + * The task's notification value is set to the value of ulValue, even if the + * task being notified had not yet processed the previous notification (the + * task already had a notification pending). xTaskNotify() always returns + * pdPASS in this case. + * + * eSetValueWithoutOverwrite - + * If the task being notified did not already have a notification pending then + * the task's notification value is set to ulValue and xTaskNotify() will + * return pdPASS. If the task being notified already had a notification + * pending then no action is performed and pdFAIL is returned. + * + * eNoAction - + * The task receives a notification without its notification value being + * updated. ulValue is not used and xTaskNotify() always returns pdPASS in + * this case. + * + * pulPreviousNotificationValue - + * Can be used to pass out the subject task's notification value before any + * bits are modified by the notify function. + * + * @return Dependent on the value of eAction. See the description of the + * eAction parameter. + * + * \defgroup xTaskNotify xTaskNotify + * \ingroup TaskNotifications + */ +BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue ) PRIVILEGED_FUNCTION; +#define xTaskNotify( xTaskToNotify, ulValue, eAction ) xTaskGenericNotify( ( xTaskToNotify ), ( ulValue ), ( eAction ), NULL ) +#define xTaskNotifyAndQuery( xTaskToNotify, ulValue, eAction, pulPreviousNotifyValue ) xTaskGenericNotify( ( xTaskToNotify ), ( ulValue ), ( eAction ), ( pulPreviousNotifyValue ) ) + +/** + * task. h + *
BaseType_t xTaskNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, BaseType_t *pxHigherPriorityTaskWoken );
+ * + * configUSE_TASK_NOTIFICATIONS must be undefined or defined as 1 for this + * function to be available. + * + * When configUSE_TASK_NOTIFICATIONS is set to one each task has its own private + * "notification value", which is a 32-bit unsigned integer (uint32_t). + * + * A version of xTaskNotify() that can be used from an interrupt service routine + * (ISR). + * + * Events can be sent to a task using an intermediary object. Examples of such + * objects are queues, semaphores, mutexes and event groups. Task notifications + * are a method of sending an event directly to a task without the need for such + * an intermediary object. + * + * A notification sent to a task can optionally perform an action, such as + * update, overwrite or increment the task's notification value. In that way + * task notifications can be used to send data to a task, or be used as light + * weight and fast binary or counting semaphores. + * + * A notification sent to a task will remain pending until it is cleared by the + * task calling xTaskNotifyWait() or ulTaskNotifyTake(). If the task was + * already in the Blocked state to wait for a notification when the notification + * arrives then the task will automatically be removed from the Blocked state + * (unblocked) and the notification cleared. + * + * A task can use xTaskNotifyWait() to [optionally] block to wait for a + * notification to be pending, or ulTaskNotifyTake() to [optionally] block + * to wait for its notification value to have a non-zero value. The task does + * not consume any CPU time while it is in the Blocked state. + * + * See http://www.FreeRTOS.org/RTOS-task-notifications.html for details. + * + * @param xTaskToNotify The handle of the task being notified. The handle to a + * task can be returned from the xTaskCreate() API function used to create the + * task, and the handle of the currently running task can be obtained by calling + * xTaskGetCurrentTaskHandle(). + * + * @param ulValue Data that can be sent with the notification. How the data is + * used depends on the value of the eAction parameter. + * + * @param eAction Specifies how the notification updates the task's notification + * value, if at all. Valid values for eAction are as follows: + * + * eSetBits - + * The task's notification value is bitwise ORed with ulValue. xTaskNofify() + * always returns pdPASS in this case. + * + * eIncrement - + * The task's notification value is incremented. ulValue is not used and + * xTaskNotify() always returns pdPASS in this case. + * + * eSetValueWithOverwrite - + * The task's notification value is set to the value of ulValue, even if the + * task being notified had not yet processed the previous notification (the + * task already had a notification pending). xTaskNotify() always returns + * pdPASS in this case. + * + * eSetValueWithoutOverwrite - + * If the task being notified did not already have a notification pending then + * the task's notification value is set to ulValue and xTaskNotify() will + * return pdPASS. If the task being notified already had a notification + * pending then no action is performed and pdFAIL is returned. + * + * eNoAction - + * The task receives a notification without its notification value being + * updated. ulValue is not used and xTaskNotify() always returns pdPASS in + * this case. + * + * @param pxHigherPriorityTaskWoken xTaskNotifyFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if sending the notification caused the + * task to which the notification was sent to leave the Blocked state, and the + * unblocked task has a priority higher than the currently running task. If + * xTaskNotifyFromISR() sets this value to pdTRUE then a context switch should + * be requested before the interrupt is exited. How a context switch is + * requested from an ISR is dependent on the port - see the documentation page + * for the port in use. + * + * @return Dependent on the value of eAction. See the description of the + * eAction parameter. + * + * \defgroup xTaskNotify xTaskNotify + * \ingroup TaskNotifications + */ +BaseType_t xTaskGenericNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION; +#define xTaskNotifyFromISR( xTaskToNotify, ulValue, eAction, pxHigherPriorityTaskWoken ) xTaskGenericNotifyFromISR( ( xTaskToNotify ), ( ulValue ), ( eAction ), NULL, ( pxHigherPriorityTaskWoken ) ) +#define xTaskNotifyAndQueryFromISR( xTaskToNotify, ulValue, eAction, pulPreviousNotificationValue, pxHigherPriorityTaskWoken ) xTaskGenericNotifyFromISR( ( xTaskToNotify ), ( ulValue ), ( eAction ), ( pulPreviousNotificationValue ), ( pxHigherPriorityTaskWoken ) ) + +/** + * task. h + *
BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait );
+ * + * configUSE_TASK_NOTIFICATIONS must be undefined or defined as 1 for this + * function to be available. + * + * When configUSE_TASK_NOTIFICATIONS is set to one each task has its own private + * "notification value", which is a 32-bit unsigned integer (uint32_t). + * + * Events can be sent to a task using an intermediary object. Examples of such + * objects are queues, semaphores, mutexes and event groups. Task notifications + * are a method of sending an event directly to a task without the need for such + * an intermediary object. + * + * A notification sent to a task can optionally perform an action, such as + * update, overwrite or increment the task's notification value. In that way + * task notifications can be used to send data to a task, or be used as light + * weight and fast binary or counting semaphores. + * + * A notification sent to a task will remain pending until it is cleared by the + * task calling xTaskNotifyWait() or ulTaskNotifyTake(). If the task was + * already in the Blocked state to wait for a notification when the notification + * arrives then the task will automatically be removed from the Blocked state + * (unblocked) and the notification cleared. + * + * A task can use xTaskNotifyWait() to [optionally] block to wait for a + * notification to be pending, or ulTaskNotifyTake() to [optionally] block + * to wait for its notification value to have a non-zero value. The task does + * not consume any CPU time while it is in the Blocked state. + * + * See http://www.FreeRTOS.org/RTOS-task-notifications.html for details. + * + * @param ulBitsToClearOnEntry Bits that are set in ulBitsToClearOnEntry value + * will be cleared in the calling task's notification value before the task + * checks to see if any notifications are pending, and optionally blocks if no + * notifications are pending. Setting ulBitsToClearOnEntry to ULONG_MAX (if + * limits.h is included) or 0xffffffffUL (if limits.h is not included) will have + * the effect of resetting the task's notification value to 0. Setting + * ulBitsToClearOnEntry to 0 will leave the task's notification value unchanged. + * + * @param ulBitsToClearOnExit If a notification is pending or received before + * the calling task exits the xTaskNotifyWait() function then the task's + * notification value (see the xTaskNotify() API function) is passed out using + * the pulNotificationValue parameter. Then any bits that are set in + * ulBitsToClearOnExit will be cleared in the task's notification value (note + * *pulNotificationValue is set before any bits are cleared). Setting + * ulBitsToClearOnExit to ULONG_MAX (if limits.h is included) or 0xffffffffUL + * (if limits.h is not included) will have the effect of resetting the task's + * notification value to 0 before the function exits. Setting + * ulBitsToClearOnExit to 0 will leave the task's notification value unchanged + * when the function exits (in which case the value passed out in + * pulNotificationValue will match the task's notification value). + * + * @param pulNotificationValue Used to pass the task's notification value out + * of the function. Note the value passed out will not be effected by the + * clearing of any bits caused by ulBitsToClearOnExit being non-zero. + * + * @param xTicksToWait The maximum amount of time that the task should wait in + * the Blocked state for a notification to be received, should a notification + * not already be pending when xTaskNotifyWait() was called. The task + * will not consume any processing time while it is in the Blocked state. This + * is specified in kernel ticks, the macro pdMS_TO_TICSK( value_in_ms ) can be + * used to convert a time specified in milliseconds to a time specified in + * ticks. + * + * @return If a notification was received (including notifications that were + * already pending when xTaskNotifyWait was called) then pdPASS is + * returned. Otherwise pdFAIL is returned. + * + * \defgroup xTaskNotifyWait xTaskNotifyWait + * \ingroup TaskNotifications + */ +BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
BaseType_t xTaskNotifyGive( TaskHandle_t xTaskToNotify );
+ * + * configUSE_TASK_NOTIFICATIONS must be undefined or defined as 1 for this macro + * to be available. + * + * When configUSE_TASK_NOTIFICATIONS is set to one each task has its own private + * "notification value", which is a 32-bit unsigned integer (uint32_t). + * + * Events can be sent to a task using an intermediary object. Examples of such + * objects are queues, semaphores, mutexes and event groups. Task notifications + * are a method of sending an event directly to a task without the need for such + * an intermediary object. + * + * A notification sent to a task can optionally perform an action, such as + * update, overwrite or increment the task's notification value. In that way + * task notifications can be used to send data to a task, or be used as light + * weight and fast binary or counting semaphores. + * + * xTaskNotifyGive() is a helper macro intended for use when task notifications + * are used as light weight and faster binary or counting semaphore equivalents. + * Actual FreeRTOS semaphores are given using the xSemaphoreGive() API function, + * the equivalent action that instead uses a task notification is + * xTaskNotifyGive(). + * + * When task notifications are being used as a binary or counting semaphore + * equivalent then the task being notified should wait for the notification + * using the ulTaskNotificationTake() API function rather than the + * xTaskNotifyWait() API function. + * + * See http://www.FreeRTOS.org/RTOS-task-notifications.html for more details. + * + * @param xTaskToNotify The handle of the task being notified. The handle to a + * task can be returned from the xTaskCreate() API function used to create the + * task, and the handle of the currently running task can be obtained by calling + * xTaskGetCurrentTaskHandle(). + * + * @return xTaskNotifyGive() is a macro that calls xTaskNotify() with the + * eAction parameter set to eIncrement - so pdPASS is always returned. + * + * \defgroup xTaskNotifyGive xTaskNotifyGive + * \ingroup TaskNotifications + */ +#define xTaskNotifyGive( xTaskToNotify ) xTaskGenericNotify( ( xTaskToNotify ), ( 0 ), eIncrement, NULL ) + +/** + * task. h + *
void vTaskNotifyGiveFromISR( TaskHandle_t xTaskHandle, BaseType_t *pxHigherPriorityTaskWoken );
+ *
+ * configUSE_TASK_NOTIFICATIONS must be undefined or defined as 1 for this macro
+ * to be available.
+ *
+ * When configUSE_TASK_NOTIFICATIONS is set to one each task has its own private
+ * "notification value", which is a 32-bit unsigned integer (uint32_t).
+ *
+ * A version of xTaskNotifyGive() that can be called from an interrupt service
+ * routine (ISR).
+ *
+ * Events can be sent to a task using an intermediary object.  Examples of such
+ * objects are queues, semaphores, mutexes and event groups.  Task notifications
+ * are a method of sending an event directly to a task without the need for such
+ * an intermediary object.
+ *
+ * A notification sent to a task can optionally perform an action, such as
+ * update, overwrite or increment the task's notification value.  In that way
+ * task notifications can be used to send data to a task, or be used as light
+ * weight and fast binary or counting semaphores.
+ *
+ * vTaskNotifyGiveFromISR() is intended for use when task notifications are
+ * used as light weight and faster binary or counting semaphore equivalents.
+ * Actual FreeRTOS semaphores are given from an ISR using the
+ * xSemaphoreGiveFromISR() API function, the equivalent action that instead uses
+ * a task notification is vTaskNotifyGiveFromISR().
+ *
+ * When task notifications are being used as a binary or counting semaphore
+ * equivalent then the task being notified should wait for the notification
+ * using the ulTaskNotificationTake() API function rather than the
+ * xTaskNotifyWait() API function.
+ *
+ * See http://www.FreeRTOS.org/RTOS-task-notifications.html for more details.
+ *
+ * @param xTaskToNotify The handle of the task being notified.  The handle to a
+ * task can be returned from the xTaskCreate() API function used to create the
+ * task, and the handle of the currently running task can be obtained by calling
+ * xTaskGetCurrentTaskHandle().
+ *
+ * @param pxHigherPriorityTaskWoken  vTaskNotifyGiveFromISR() will set
+ * *pxHigherPriorityTaskWoken to pdTRUE if sending the notification caused the
+ * task to which the notification was sent to leave the Blocked state, and the
+ * unblocked task has a priority higher than the currently running task.  If
+ * vTaskNotifyGiveFromISR() sets this value to pdTRUE then a context switch
+ * should be requested before the interrupt is exited.  How a context switch is
+ * requested from an ISR is dependent on the port - see the documentation page
+ * for the port in use.
+ *
+ * \defgroup xTaskNotifyWait xTaskNotifyWait
+ * \ingroup TaskNotifications
+ */
+void vTaskNotifyGiveFromISR( TaskHandle_t xTaskToNotify, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * 
uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait );
+ * + * configUSE_TASK_NOTIFICATIONS must be undefined or defined as 1 for this + * function to be available. + * + * When configUSE_TASK_NOTIFICATIONS is set to one each task has its own private + * "notification value", which is a 32-bit unsigned integer (uint32_t). + * + * Events can be sent to a task using an intermediary object. Examples of such + * objects are queues, semaphores, mutexes and event groups. Task notifications + * are a method of sending an event directly to a task without the need for such + * an intermediary object. + * + * A notification sent to a task can optionally perform an action, such as + * update, overwrite or increment the task's notification value. In that way + * task notifications can be used to send data to a task, or be used as light + * weight and fast binary or counting semaphores. + * + * ulTaskNotifyTake() is intended for use when a task notification is used as a + * faster and lighter weight binary or counting semaphore alternative. Actual + * FreeRTOS semaphores are taken using the xSemaphoreTake() API function, the + * equivalent action that instead uses a task notification is + * ulTaskNotifyTake(). + * + * When a task is using its notification value as a binary or counting semaphore + * other tasks should send notifications to it using the xTaskNotifyGive() + * macro, or xTaskNotify() function with the eAction parameter set to + * eIncrement. + * + * ulTaskNotifyTake() can either clear the task's notification value to + * zero on exit, in which case the notification value acts like a binary + * semaphore, or decrement the task's notification value on exit, in which case + * the notification value acts like a counting semaphore. + * + * A task can use ulTaskNotifyTake() to [optionally] block to wait for a + * the task's notification value to be non-zero. The task does not consume any + * CPU time while it is in the Blocked state. + * + * Where as xTaskNotifyWait() will return when a notification is pending, + * ulTaskNotifyTake() will return when the task's notification value is + * not zero. + * + * See http://www.FreeRTOS.org/RTOS-task-notifications.html for details. + * + * @param xClearCountOnExit if xClearCountOnExit is pdFALSE then the task's + * notification value is decremented when the function exits. In this way the + * notification value acts like a counting semaphore. If xClearCountOnExit is + * not pdFALSE then the task's notification value is cleared to zero when the + * function exits. In this way the notification value acts like a binary + * semaphore. + * + * @param xTicksToWait The maximum amount of time that the task should wait in + * the Blocked state for the task's notification value to be greater than zero, + * should the count not already be greater than zero when + * ulTaskNotifyTake() was called. The task will not consume any processing + * time while it is in the Blocked state. This is specified in kernel ticks, + * the macro pdMS_TO_TICSK( value_in_ms ) can be used to convert a time + * specified in milliseconds to a time specified in ticks. + * + * @return The task's notification count before it is either cleared to zero or + * decremented (see the xClearCountOnExit parameter). + * + * \defgroup ulTaskNotifyTake ulTaskNotifyTake + * \ingroup TaskNotifications + */ +uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
BaseType_t xTaskNotifyStateClear( TaskHandle_t xTask );
+ * + * If the notification state of the task referenced by the handle xTask is + * eNotified, then set the task's notification state to eNotWaitingNotification. + * The task's notification value is not altered. Set xTask to NULL to clear the + * notification state of the calling task. + * + * @return pdTRUE if the task's notification state was set to + * eNotWaitingNotification, otherwise pdFALSE. + * \defgroup xTaskNotifyStateClear xTaskNotifyStateClear + * \ingroup TaskNotifications + */ +BaseType_t xTaskNotifyStateClear( TaskHandle_t xTask ); + +/*----------------------------------------------------------- + * SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES + *----------------------------------------------------------*/ + +/* + * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS ONLY + * INTENDED FOR USE WHEN IMPLEMENTING A PORT OF THE SCHEDULER AND IS + * AN INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER. + * + * Called from the real time kernel tick (either preemptive or cooperative), + * this increments the tick count and checks if any tasks that are blocked + * for a finite period required removing from a blocked list and placing on + * a ready list. If a non-zero value is returned then a context switch is + * required because either: + * + A task was removed from a blocked list because its timeout had expired, + * or + * + Time slicing is in use and there is a task of equal priority to the + * currently running task. + */ +BaseType_t xTaskIncrementTick( void ) PRIVILEGED_FUNCTION; + +/* + * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN + * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER. + * + * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED. + * + * Removes the calling task from the ready list and places it both + * on the list of tasks waiting for a particular event, and the + * list of delayed tasks. The task will be removed from both lists + * and replaced on the ready list should either the event occur (and + * there be no higher priority tasks waiting on the same event) or + * the delay period expires. + * + * The 'unordered' version replaces the event list item value with the + * xItemValue value, and inserts the list item at the end of the list. + * + * The 'ordered' version uses the existing event list item value (which is the + * owning tasks priority) to insert the list item into the event list is task + * priority order. + * + * @param pxEventList The list containing tasks that are blocked waiting + * for the event to occur. + * + * @param xItemValue The item value to use for the event list item when the + * event list is not ordered by task priority. + * + * @param xTicksToWait The maximum amount of time that the task should wait + * for the event to occur. This is specified in kernel ticks,the constant + * portTICK_PERIOD_MS can be used to convert kernel ticks into a real time + * period. + */ +void vTaskPlaceOnEventList( List_t * const pxEventList, const TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; +void vTaskPlaceOnUnorderedEventList( List_t * pxEventList, const TickType_t xItemValue, const TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; + +/* + * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN + * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER. + * + * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED. + * + * This function performs nearly the same function as vTaskPlaceOnEventList(). + * The difference being that this function does not permit tasks to block + * indefinitely, whereas vTaskPlaceOnEventList() does. + * + */ +void vTaskPlaceOnEventListRestricted( List_t * const pxEventList, TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely ) PRIVILEGED_FUNCTION; + +/* + * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN + * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER. + * + * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED. + * + * Removes a task from both the specified event list and the list of blocked + * tasks, and places it on a ready queue. + * + * xTaskRemoveFromEventList()/xTaskRemoveFromUnorderedEventList() will be called + * if either an event occurs to unblock a task, or the block timeout period + * expires. + * + * xTaskRemoveFromEventList() is used when the event list is in task priority + * order. It removes the list item from the head of the event list as that will + * have the highest priority owning task of all the tasks on the event list. + * xTaskRemoveFromUnorderedEventList() is used when the event list is not + * ordered and the event list items hold something other than the owning tasks + * priority. In this case the event list item value is updated to the value + * passed in the xItemValue parameter. + * + * @return pdTRUE if the task being removed has a higher priority than the task + * making the call, otherwise pdFALSE. + */ +BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList ) PRIVILEGED_FUNCTION; +BaseType_t xTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, const TickType_t xItemValue ) PRIVILEGED_FUNCTION; + +/* + * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS ONLY + * INTENDED FOR USE WHEN IMPLEMENTING A PORT OF THE SCHEDULER AND IS + * AN INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER. + * + * Sets the pointer to the current TCB to the TCB of the highest priority task + * that is ready to run. + */ +void vTaskSwitchContext( void ) PRIVILEGED_FUNCTION; + +/* + * THESE FUNCTIONS MUST NOT BE USED FROM APPLICATION CODE. THEY ARE USED BY + * THE EVENT BITS MODULE. + */ +TickType_t uxTaskResetEventItemValue( void ) PRIVILEGED_FUNCTION; + +/* + * Return the handle of the calling task. + */ +TaskHandle_t xTaskGetCurrentTaskHandle( void ) PRIVILEGED_FUNCTION; + +/* + * Capture the current time status for future reference. + */ +void vTaskSetTimeOutState( TimeOut_t * const pxTimeOut ) PRIVILEGED_FUNCTION; + +/* + * Compare the time status now with that previously captured to see if the + * timeout has expired. + */ +BaseType_t xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut, TickType_t * const pxTicksToWait ) PRIVILEGED_FUNCTION; + +/* + * Shortcut used by the queue implementation to prevent unnecessary call to + * taskYIELD(); + */ +void vTaskMissedYield( void ) PRIVILEGED_FUNCTION; + +/* + * Returns the scheduler state as taskSCHEDULER_RUNNING, + * taskSCHEDULER_NOT_STARTED or taskSCHEDULER_SUSPENDED. + */ +BaseType_t xTaskGetSchedulerState( void ) PRIVILEGED_FUNCTION; + +/* + * Raises the priority of the mutex holder to that of the calling task should + * the mutex holder have a priority less than the calling task. + */ +void vTaskPriorityInherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTION; + +/* + * Set the priority of a task back to its proper priority in the case that it + * inherited a higher priority while it was holding a semaphore. + */ +BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTION; + +/* + * Get the uxTCBNumber assigned to the task referenced by the xTask parameter. + */ +UBaseType_t uxTaskGetTaskNumber( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; + +/* + * Set the uxTaskNumber of the task referenced by the xTask parameter to + * uxHandle. + */ +void vTaskSetTaskNumber( TaskHandle_t xTask, const UBaseType_t uxHandle ) PRIVILEGED_FUNCTION; + +/* + * Only available when configUSE_TICKLESS_IDLE is set to 1. + * If tickless mode is being used, or a low power mode is implemented, then + * the tick interrupt will not execute during idle periods. When this is the + * case, the tick count value maintained by the scheduler needs to be kept up + * to date with the actual execution time by being skipped forward by a time + * equal to the idle period. + */ +void vTaskStepTick( const TickType_t xTicksToJump ) PRIVILEGED_FUNCTION; + +/* + * Only avilable when configUSE_TICKLESS_IDLE is set to 1. + * Provided for use within portSUPPRESS_TICKS_AND_SLEEP() to allow the port + * specific sleep function to determine if it is ok to proceed with the sleep, + * and if it is ok to proceed, if it is ok to sleep indefinitely. + * + * This function is necessary because portSUPPRESS_TICKS_AND_SLEEP() is only + * called with the scheduler suspended, not from within a critical section. It + * is therefore possible for an interrupt to request a context switch between + * portSUPPRESS_TICKS_AND_SLEEP() and the low power mode actually being + * entered. eTaskConfirmSleepModeStatus() should be called from a short + * critical section between the timer being stopped and the sleep mode being + * entered to ensure it is ok to proceed into the sleep mode. + */ +eSleepModeStatus eTaskConfirmSleepModeStatus( void ) PRIVILEGED_FUNCTION; + +/* + * For internal use only. Increment the mutex held count when a mutex is + * taken and return the handle of the task that has taken the mutex. + */ +void *pvTaskIncrementMutexHeldCount( void ) PRIVILEGED_FUNCTION; + +#ifdef __cplusplus +} +#endif +#endif /* INC_TASK_H */ + + + diff --git a/STM32F1/libraries/FreeRTOS900/utility/tasks.c b/STM32F1/libraries/FreeRTOS900/utility/tasks.c new file mode 100644 index 0000000..6c261a6 --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/utility/tasks.c @@ -0,0 +1,4807 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* Standard includes. */ +#include +#include + +/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining +all the API functions to use the MPU wrappers. That should only be done when +task.h is included from an application file. */ +#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "timers.h" +#include "StackMacros.h" + +/* Lint e961 and e750 are suppressed as a MISRA exception justified because the +MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the +header files above, but not in this file, in order to generate the correct +privileged Vs unprivileged linkage and placement. */ +#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */ + +/* Set configUSE_STATS_FORMATTING_FUNCTIONS to 2 to include the stats formatting +functions but without including stdio.h here. */ +#if ( configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) + /* At the bottom of this file are two optional functions that can be used + to generate human readable text from the raw data generated by the + uxTaskGetSystemState() function. Note the formatting functions are provided + for convenience only, and are NOT considered part of the kernel. */ + #include +#endif /* configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) */ + +#if( configUSE_PREEMPTION == 0 ) + /* If the cooperative scheduler is being used then a yield should not be + performed just because a higher priority task has been woken. */ + #define taskYIELD_IF_USING_PREEMPTION() +#else + #define taskYIELD_IF_USING_PREEMPTION() portYIELD_WITHIN_API() +#endif + +/* Values that can be assigned to the ucNotifyState member of the TCB. */ +#define taskNOT_WAITING_NOTIFICATION ( ( uint8_t ) 0 ) +#define taskWAITING_NOTIFICATION ( ( uint8_t ) 1 ) +#define taskNOTIFICATION_RECEIVED ( ( uint8_t ) 2 ) + +/* + * The value used to fill the stack of a task when the task is created. This + * is used purely for checking the high water mark for tasks. + */ +#define tskSTACK_FILL_BYTE ( 0xa5U ) + +/* Sometimes the FreeRTOSConfig.h settings only allow a task to be created using +dynamically allocated RAM, in which case when any task is deleted it is known +that both the task's stack and TCB need to be freed. Sometimes the +FreeRTOSConfig.h settings only allow a task to be created using statically +allocated RAM, in which case when any task is deleted it is known that neither +the task's stack or TCB should be freed. Sometimes the FreeRTOSConfig.h +settings allow a task to be created using either statically or dynamically +allocated RAM, in which case a member of the TCB is used to record whether the +stack and/or TCB were allocated statically or dynamically, so when a task is +deleted the RAM that was allocated dynamically is freed again and no attempt is +made to free the RAM that was allocated statically. +tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE is only true if it is possible for a +task to be created using either statically or dynamically allocated RAM. Note +that if portUSING_MPU_WRAPPERS is 1 then a protected task can be created with +a statically allocated stack and a dynamically allocated TCB. */ +#define tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE ( ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) || ( portUSING_MPU_WRAPPERS == 1 ) ) +#define tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB ( ( uint8_t ) 0 ) +#define tskSTATICALLY_ALLOCATED_STACK_ONLY ( ( uint8_t ) 1 ) +#define tskSTATICALLY_ALLOCATED_STACK_AND_TCB ( ( uint8_t ) 2 ) + +/* + * Macros used by vListTask to indicate which state a task is in. + */ +#define tskBLOCKED_CHAR ( 'B' ) +#define tskREADY_CHAR ( 'R' ) +#define tskDELETED_CHAR ( 'D' ) +#define tskSUSPENDED_CHAR ( 'S' ) + +/* + * Some kernel aware debuggers require the data the debugger needs access to be + * global, rather than file scope. + */ +#ifdef portREMOVE_STATIC_QUALIFIER + #define static +#endif + +#if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 ) + + /* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 0 then task selection is + performed in a generic way that is not optimised to any particular + microcontroller architecture. */ + + /* uxTopReadyPriority holds the priority of the highest priority ready + state task. */ + #define taskRECORD_READY_PRIORITY( uxPriority ) \ + { \ + if( ( uxPriority ) > uxTopReadyPriority ) \ + { \ + uxTopReadyPriority = ( uxPriority ); \ + } \ + } /* taskRECORD_READY_PRIORITY */ + + /*-----------------------------------------------------------*/ + + #define taskSELECT_HIGHEST_PRIORITY_TASK() \ + { \ + UBaseType_t uxTopPriority = uxTopReadyPriority; \ + \ + /* Find the highest priority queue that contains ready tasks. */ \ + while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopPriority ] ) ) ) \ + { \ + configASSERT( uxTopPriority ); \ + --uxTopPriority; \ + } \ + \ + /* listGET_OWNER_OF_NEXT_ENTRY indexes through the list, so the tasks of \ + the same priority get an equal share of the processor time. */ \ + listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \ + uxTopReadyPriority = uxTopPriority; \ + } /* taskSELECT_HIGHEST_PRIORITY_TASK */ + + /*-----------------------------------------------------------*/ + + /* Define away taskRESET_READY_PRIORITY() and portRESET_READY_PRIORITY() as + they are only required when a port optimised method of task selection is + being used. */ + #define taskRESET_READY_PRIORITY( uxPriority ) + #define portRESET_READY_PRIORITY( uxPriority, uxTopReadyPriority ) + +#else /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ + + /* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 1 then task selection is + performed in a way that is tailored to the particular microcontroller + architecture being used. */ + + /* A port optimised version is provided. Call the port defined macros. */ + #define taskRECORD_READY_PRIORITY( uxPriority ) portRECORD_READY_PRIORITY( uxPriority, uxTopReadyPriority ) + + /*-----------------------------------------------------------*/ + + #define taskSELECT_HIGHEST_PRIORITY_TASK() \ + { \ + UBaseType_t uxTopPriority; \ + \ + /* Find the highest priority list that contains ready tasks. */ \ + portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority ); \ + configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 ); \ + listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \ + } /* taskSELECT_HIGHEST_PRIORITY_TASK() */ + + /*-----------------------------------------------------------*/ + + /* A port optimised version is provided, call it only if the TCB being reset + is being referenced from a ready list. If it is referenced from a delayed + or suspended list then it won't be in a ready list. */ + #define taskRESET_READY_PRIORITY( uxPriority ) \ + { \ + if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ ( uxPriority ) ] ) ) == ( UBaseType_t ) 0 ) \ + { \ + portRESET_READY_PRIORITY( ( uxPriority ), ( uxTopReadyPriority ) ); \ + } \ + } + +#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ + +/*-----------------------------------------------------------*/ + +/* pxDelayedTaskList and pxOverflowDelayedTaskList are switched when the tick +count overflows. */ +#define taskSWITCH_DELAYED_LISTS() \ +{ \ + List_t *pxTemp; \ + \ + /* The delayed tasks list should be empty when the lists are switched. */ \ + configASSERT( ( listLIST_IS_EMPTY( pxDelayedTaskList ) ) ); \ + \ + pxTemp = pxDelayedTaskList; \ + pxDelayedTaskList = pxOverflowDelayedTaskList; \ + pxOverflowDelayedTaskList = pxTemp; \ + xNumOfOverflows++; \ + prvResetNextTaskUnblockTime(); \ +} + +/*-----------------------------------------------------------*/ + +/* + * Place the task represented by pxTCB into the appropriate ready list for + * the task. It is inserted at the end of the list. + */ +#define prvAddTaskToReadyList( pxTCB ) \ + traceMOVED_TASK_TO_READY_STATE( pxTCB ); \ + taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority ); \ + vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xStateListItem ) ); \ + tracePOST_MOVED_TASK_TO_READY_STATE( pxTCB ) +/*-----------------------------------------------------------*/ + +/* + * Several functions take an TaskHandle_t parameter that can optionally be NULL, + * where NULL is used to indicate that the handle of the currently executing + * task should be used in place of the parameter. This macro simply checks to + * see if the parameter is NULL and returns a pointer to the appropriate TCB. + */ +#define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? ( TCB_t * ) pxCurrentTCB : ( TCB_t * ) ( pxHandle ) ) + +/* The item value of the event list item is normally used to hold the priority +of the task to which it belongs (coded to allow it to be held in reverse +priority order). However, it is occasionally borrowed for other purposes. It +is important its value is not updated due to a task priority change while it is +being used for another purpose. The following bit definition is used to inform +the scheduler that the value should not be changed - in which case it is the +responsibility of whichever module is using the value to ensure it gets set back +to its original value when it is released. */ +#if( configUSE_16_BIT_TICKS == 1 ) + #define taskEVENT_LIST_ITEM_VALUE_IN_USE 0x8000U +#else + #define taskEVENT_LIST_ITEM_VALUE_IN_USE 0x80000000UL +#endif + +/* + * Task control block. A task control block (TCB) is allocated for each task, + * and stores task state information, including a pointer to the task's context + * (the task's run time environment, including register values) + */ +typedef struct tskTaskControlBlock +{ + volatile StackType_t *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */ + + #if ( portUSING_MPU_WRAPPERS == 1 ) + xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */ + #endif + + ListItem_t xStateListItem; /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */ + ListItem_t xEventListItem; /*< Used to reference a task from an event list. */ + UBaseType_t uxPriority; /*< The priority of the task. 0 is the lowest priority. */ + StackType_t *pxStack; /*< Points to the start of the stack. */ + char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + + #if ( portSTACK_GROWTH > 0 ) + StackType_t *pxEndOfStack; /*< Points to the end of the stack on architectures where the stack grows up from low memory. */ + #endif + + #if ( portCRITICAL_NESTING_IN_TCB == 1 ) + UBaseType_t uxCriticalNesting; /*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */ + #endif + + #if ( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxTCBNumber; /*< Stores a number that increments each time a TCB is created. It allows debuggers to determine when a task has been deleted and then recreated. */ + UBaseType_t uxTaskNumber; /*< Stores a number specifically for use by third party trace code. */ + #endif + + #if ( configUSE_MUTEXES == 1 ) + UBaseType_t uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */ + UBaseType_t uxMutexesHeld; + #endif + + #if ( configUSE_APPLICATION_TASK_TAG == 1 ) + TaskHookFunction_t pxTaskTag; + #endif + + #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) + void *pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ]; + #endif + + #if( configGENERATE_RUN_TIME_STATS == 1 ) + uint32_t ulRunTimeCounter; /*< Stores the amount of time the task has spent in the Running state. */ + #endif + + #if ( configUSE_NEWLIB_REENTRANT == 1 ) + /* Allocate a Newlib reent structure that is specific to this task. + Note Newlib support has been included by popular demand, but is not + used by the FreeRTOS maintainers themselves. FreeRTOS is not + responsible for resulting newlib operation. User must be familiar with + newlib and must provide system-wide implementations of the necessary + stubs. Be warned that (at the time of writing) the current newlib design + implements a system-wide malloc() that must be provided with locks. */ + struct _reent xNewLib_reent; + #endif + + #if( configUSE_TASK_NOTIFICATIONS == 1 ) + volatile uint32_t ulNotifiedValue; + volatile uint8_t ucNotifyState; + #endif + + /* See the comments above the definition of + tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */ + #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) + uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */ + #endif + + #if( INCLUDE_xTaskAbortDelay == 1 ) + uint8_t ucDelayAborted; + #endif + +} tskTCB; + +/* The old tskTCB name is maintained above then typedefed to the new TCB_t name +below to enable the use of older kernel aware debuggers. */ +typedef tskTCB TCB_t; + +/*lint -e956 A manual analysis and inspection has been used to determine which +static variables must be declared volatile. */ + +PRIVILEGED_DATA TCB_t * volatile pxCurrentTCB = NULL; + +/* Lists for ready and blocked tasks. --------------------*/ +PRIVILEGED_DATA static List_t pxReadyTasksLists[ configMAX_PRIORITIES ];/*< Prioritised ready tasks. */ +PRIVILEGED_DATA static List_t xDelayedTaskList1; /*< Delayed tasks. */ +PRIVILEGED_DATA static List_t xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */ +PRIVILEGED_DATA static List_t * volatile pxDelayedTaskList; /*< Points to the delayed task list currently being used. */ +PRIVILEGED_DATA static List_t * volatile pxOverflowDelayedTaskList; /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */ +PRIVILEGED_DATA static List_t xPendingReadyList; /*< Tasks that have been readied while the scheduler was suspended. They will be moved to the ready list when the scheduler is resumed. */ + +#if( INCLUDE_vTaskDelete == 1 ) + + PRIVILEGED_DATA static List_t xTasksWaitingTermination; /*< Tasks that have been deleted - but their memory not yet freed. */ + PRIVILEGED_DATA static volatile UBaseType_t uxDeletedTasksWaitingCleanUp = ( UBaseType_t ) 0U; + +#endif + +#if ( INCLUDE_vTaskSuspend == 1 ) + + PRIVILEGED_DATA static List_t xSuspendedTaskList; /*< Tasks that are currently suspended. */ + +#endif + +/* Other file private variables. --------------------------------*/ +PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks = ( UBaseType_t ) 0U; +PRIVILEGED_DATA static volatile TickType_t xTickCount = ( TickType_t ) 0U; +PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority = tskIDLE_PRIORITY; +PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning = pdFALSE; +PRIVILEGED_DATA static volatile UBaseType_t uxPendedTicks = ( UBaseType_t ) 0U; +PRIVILEGED_DATA static volatile BaseType_t xYieldPending = pdFALSE; +PRIVILEGED_DATA static volatile BaseType_t xNumOfOverflows = ( BaseType_t ) 0; +PRIVILEGED_DATA static UBaseType_t uxTaskNumber = ( UBaseType_t ) 0U; +PRIVILEGED_DATA static volatile TickType_t xNextTaskUnblockTime = ( TickType_t ) 0U; /* Initialised to portMAX_DELAY before the scheduler starts. */ +PRIVILEGED_DATA static TaskHandle_t xIdleTaskHandle = NULL; /*< Holds the handle of the idle task. The idle task is created automatically when the scheduler is started. */ + +/* Context switches are held pending while the scheduler is suspended. Also, +interrupts must not manipulate the xStateListItem of a TCB, or any of the +lists the xStateListItem can be referenced from, if the scheduler is suspended. +If an interrupt needs to unblock a task while the scheduler is suspended then it +moves the task's event list item into the xPendingReadyList, ready for the +kernel to move the task from the pending ready list into the real ready list +when the scheduler is unsuspended. The pending ready list itself can only be +accessed from a critical section. */ +PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t ) pdFALSE; + +#if ( configGENERATE_RUN_TIME_STATS == 1 ) + + PRIVILEGED_DATA static uint32_t ulTaskSwitchedInTime = 0UL; /*< Holds the value of a timer/counter the last time a task was switched in. */ + PRIVILEGED_DATA static uint32_t ulTotalRunTime = 0UL; /*< Holds the total amount of execution time as defined by the run time counter clock. */ + +#endif + +/*lint +e956 */ + +/*-----------------------------------------------------------*/ + +/* Callback function prototypes. --------------------------*/ +#if( configCHECK_FOR_STACK_OVERFLOW > 0 ) + extern void vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName ); +#endif + +#if( configUSE_TICK_HOOK > 0 ) + extern void vApplicationTickHook( void ); +#endif + +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + extern void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize ); +#endif + +/* File private functions. --------------------------------*/ + +/** + * Utility task that simply returns pdTRUE if the task referenced by xTask is + * currently in the Suspended state, or pdFALSE if the task referenced by xTask + * is in any other state. + */ +#if ( INCLUDE_vTaskSuspend == 1 ) + static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION; +#endif /* INCLUDE_vTaskSuspend */ + +/* + * Utility to ready all the lists used by the scheduler. This is called + * automatically upon the creation of the first task. + */ +static void prvInitialiseTaskLists( void ) PRIVILEGED_FUNCTION; + +/* + * The idle task, which as all tasks is implemented as a never ending loop. + * The idle task is automatically created and added to the ready lists upon + * creation of the first user task. + * + * The portTASK_FUNCTION_PROTO() macro is used to allow port/compiler specific + * language extensions. The equivalent prototype for this function is: + * + * void prvIdleTask( void *pvParameters ); + * + */ +static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters ); + +/* + * Utility to free all memory allocated by the scheduler to hold a TCB, + * including the stack pointed to by the TCB. + * + * This does not free memory allocated by the task itself (i.e. memory + * allocated by calls to pvPortMalloc from within the tasks application code). + */ +#if ( INCLUDE_vTaskDelete == 1 ) + + static void prvDeleteTCB( TCB_t *pxTCB ) PRIVILEGED_FUNCTION; + +#endif + +/* + * Used only by the idle task. This checks to see if anything has been placed + * in the list of tasks waiting to be deleted. If so the task is cleaned up + * and its TCB deleted. + */ +static void prvCheckTasksWaitingTermination( void ) PRIVILEGED_FUNCTION; + +/* + * The currently executing task is entering the Blocked state. Add the task to + * either the current or the overflow delayed task list. + */ +static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, const BaseType_t xCanBlockIndefinitely ) PRIVILEGED_FUNCTION; + +/* + * Fills an TaskStatus_t structure with information on each task that is + * referenced from the pxList list (which may be a ready list, a delayed list, + * a suspended list, etc.). + * + * THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY, AND SHOULD NOT BE CALLED FROM + * NORMAL APPLICATION CODE. + */ +#if ( configUSE_TRACE_FACILITY == 1 ) + + static UBaseType_t prvListTasksWithinSingleList( TaskStatus_t *pxTaskStatusArray, List_t *pxList, eTaskState eState ) PRIVILEGED_FUNCTION; + +#endif + +/* + * Searches pxList for a task with name pcNameToQuery - returning a handle to + * the task if it is found, or NULL if the task is not found. + */ +#if ( INCLUDE_xTaskGetHandle == 1 ) + + static TCB_t *prvSearchForNameWithinSingleList( List_t *pxList, const char pcNameToQuery[] ) PRIVILEGED_FUNCTION; + +#endif + +/* + * When a task is created, the stack of the task is filled with a known value. + * This function determines the 'high water mark' of the task stack by + * determining how much of the stack remains at the original preset value. + */ +#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) + + static uint16_t prvTaskCheckFreeStackSpace( const uint8_t * pucStackByte ) PRIVILEGED_FUNCTION; + +#endif + +/* + * Return the amount of time, in ticks, that will pass before the kernel will + * next move a task from the Blocked state to the Running state. + * + * This conditional compilation should use inequality to 0, not equality to 1. + * This is to ensure portSUPPRESS_TICKS_AND_SLEEP() can be called when user + * defined low power mode implementations require configUSE_TICKLESS_IDLE to be + * set to a value other than 1. + */ +#if ( configUSE_TICKLESS_IDLE != 0 ) + + static TickType_t prvGetExpectedIdleTime( void ) PRIVILEGED_FUNCTION; + +#endif + +/* + * Set xNextTaskUnblockTime to the time at which the next Blocked state task + * will exit the Blocked state. + */ +static void prvResetNextTaskUnblockTime( void ); + +#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) + + /* + * Helper function used to pad task names with spaces when printing out + * human readable tables of task information. + */ + static char *prvWriteNameToBuffer( char *pcBuffer, const char *pcTaskName ) PRIVILEGED_FUNCTION; + +#endif + +/* + * Called after a Task_t structure has been allocated either statically or + * dynamically to fill in the structure's members. + */ +static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, + const char * const pcName, + const uint32_t ulStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t * const pxCreatedTask, + TCB_t *pxNewTCB, + const MemoryRegion_t * const xRegions ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + +/* + * Called after a new task has been created and initialised to place the task + * under the control of the scheduler. + */ +static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION; + +/*-----------------------------------------------------------*/ + +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + + TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode, + const char * const pcName, + const uint32_t ulStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + StackType_t * const puxStackBuffer, + StaticTask_t * const pxTaskBuffer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + { + TCB_t *pxNewTCB; + TaskHandle_t xReturn; + + configASSERT( puxStackBuffer != NULL ); + configASSERT( pxTaskBuffer != NULL ); + + if( ( pxTaskBuffer != NULL ) && ( puxStackBuffer != NULL ) ) + { + /* The memory used for the task's TCB and stack are passed into this + function - use them. */ + pxNewTCB = ( TCB_t * ) pxTaskBuffer; /*lint !e740 Unusual cast is ok as the structures are designed to have the same alignment, and the size is checked by an assert. */ + pxNewTCB->pxStack = ( StackType_t * ) puxStackBuffer; + + #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) + { + /* Tasks can be created statically or dynamically, so note this + task was created statically in case the task is later deleted. */ + pxNewTCB->ucStaticallyAllocated = tskSTATICALLY_ALLOCATED_STACK_AND_TCB; + } + #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ + + prvInitialiseNewTask( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, &xReturn, pxNewTCB, NULL ); + prvAddNewTaskToReadyList( pxNewTCB ); + } + else + { + xReturn = NULL; + } + + return xReturn; + } + +#endif /* SUPPORT_STATIC_ALLOCATION */ +/*-----------------------------------------------------------*/ + +#if( portUSING_MPU_WRAPPERS == 1 ) + + BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ) + { + TCB_t *pxNewTCB; + BaseType_t xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; + + configASSERT( pxTaskDefinition->puxStackBuffer ); + + if( pxTaskDefinition->puxStackBuffer != NULL ) + { + /* Allocate space for the TCB. Where the memory comes from depends + on the implementation of the port malloc function and whether or + not static allocation is being used. */ + pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); + + if( pxNewTCB != NULL ) + { + /* Store the stack location in the TCB. */ + pxNewTCB->pxStack = pxTaskDefinition->puxStackBuffer; + + /* Tasks can be created statically or dynamically, so note + this task had a statically allocated stack in case it is + later deleted. The TCB was allocated dynamically. */ + pxNewTCB->ucStaticallyAllocated = tskSTATICALLY_ALLOCATED_STACK_ONLY; + + prvInitialiseNewTask( pxTaskDefinition->pvTaskCode, + pxTaskDefinition->pcName, + ( uint32_t ) pxTaskDefinition->usStackDepth, + pxTaskDefinition->pvParameters, + pxTaskDefinition->uxPriority, + pxCreatedTask, pxNewTCB, + pxTaskDefinition->xRegions ); + + prvAddNewTaskToReadyList( pxNewTCB ); + xReturn = pdPASS; + } + } + + return xReturn; + } + +#endif /* portUSING_MPU_WRAPPERS */ +/*-----------------------------------------------------------*/ + +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + + BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, + const char * const pcName, + const uint16_t usStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t * const pxCreatedTask ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + { + TCB_t *pxNewTCB; + BaseType_t xReturn; + + /* If the stack grows down then allocate the stack then the TCB so the stack + does not grow into the TCB. Likewise if the stack grows up then allocate + the TCB then the stack. */ + #if( portSTACK_GROWTH > 0 ) + { + /* Allocate space for the TCB. Where the memory comes from depends on + the implementation of the port malloc function and whether or not static + allocation is being used. */ + pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); + + if( pxNewTCB != NULL ) + { + /* Allocate space for the stack used by the task being created. + The base of the stack memory stored in the TCB so the task can + be deleted later if required. */ + pxNewTCB->pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + + if( pxNewTCB->pxStack == NULL ) + { + /* Could not allocate the stack. Delete the allocated TCB. */ + vPortFree( pxNewTCB ); + pxNewTCB = NULL; + } + } + } + #else /* portSTACK_GROWTH */ + { + StackType_t *pxStack; + + /* Allocate space for the stack used by the task being created. */ + pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + + if( pxStack != NULL ) + { + /* Allocate space for the TCB. */ + pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); /*lint !e961 MISRA exception as the casts are only redundant for some paths. */ + + if( pxNewTCB != NULL ) + { + /* Store the stack location in the TCB. */ + pxNewTCB->pxStack = pxStack; + } + else + { + /* The stack cannot be used as the TCB was not created. Free + it again. */ + vPortFree( pxStack ); + } + } + else + { + pxNewTCB = NULL; + } + } + #endif /* portSTACK_GROWTH */ + + if( pxNewTCB != NULL ) + { + #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) + { + /* Tasks can be created statically or dynamically, so note this + task was created dynamically in case it is later deleted. */ + pxNewTCB->ucStaticallyAllocated = tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB; + } + #endif /* configSUPPORT_STATIC_ALLOCATION */ + + prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL ); + prvAddNewTaskToReadyList( pxNewTCB ); + xReturn = pdPASS; + } + else + { + xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; + } + + return xReturn; + } + +#endif /* configSUPPORT_DYNAMIC_ALLOCATION */ +/*-----------------------------------------------------------*/ + +static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, + const char * const pcName, + const uint32_t ulStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t * const pxCreatedTask, + TCB_t *pxNewTCB, + const MemoryRegion_t * const xRegions ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +{ +StackType_t *pxTopOfStack; +UBaseType_t x; + + #if( portUSING_MPU_WRAPPERS == 1 ) + /* Should the task be created in privileged mode? */ + BaseType_t xRunPrivileged; + if( ( uxPriority & portPRIVILEGE_BIT ) != 0U ) + { + xRunPrivileged = pdTRUE; + } + else + { + xRunPrivileged = pdFALSE; + } + uxPriority &= ~portPRIVILEGE_BIT; + #endif /* portUSING_MPU_WRAPPERS == 1 */ + + /* Avoid dependency on memset() if it is not required. */ + #if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) + { + /* Fill the stack with a known value to assist debugging. */ + ( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) ulStackDepth * sizeof( StackType_t ) ); + } + #endif /* ( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) ) */ + + /* Calculate the top of stack address. This depends on whether the stack + grows from high memory to low (as per the 80x86) or vice versa. + portSTACK_GROWTH is used to make the result positive or negative as required + by the port. */ + #if( portSTACK_GROWTH < 0 ) + { + pxTopOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 ); + pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) ); /*lint !e923 MISRA exception. Avoiding casts between pointers and integers is not practical. Size differences accounted for using portPOINTER_SIZE_TYPE type. */ + + /* Check the alignment of the calculated top of stack is correct. */ + configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) ); + } + #else /* portSTACK_GROWTH */ + { + pxTopOfStack = pxNewTCB->pxStack; + + /* Check the alignment of the stack buffer is correct. */ + configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxNewTCB->pxStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) ); + + /* The other extreme of the stack space is required if stack checking is + performed. */ + pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 ); + } + #endif /* portSTACK_GROWTH */ + + /* Store the task name in the TCB. */ + for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ ) + { + pxNewTCB->pcTaskName[ x ] = pcName[ x ]; + + /* Don't copy all configMAX_TASK_NAME_LEN if the string is shorter than + configMAX_TASK_NAME_LEN characters just in case the memory after the + string is not accessible (extremely unlikely). */ + if( pcName[ x ] == 0x00 ) + { + break; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + + /* Ensure the name string is terminated in the case that the string length + was greater or equal to configMAX_TASK_NAME_LEN. */ + pxNewTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = '\0'; + + /* This is used as an array index so must ensure it's not too large. First + remove the privilege bit if one is present. */ + if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES ) + { + uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + pxNewTCB->uxPriority = uxPriority; + #if ( configUSE_MUTEXES == 1 ) + { + pxNewTCB->uxBasePriority = uxPriority; + pxNewTCB->uxMutexesHeld = 0; + } + #endif /* configUSE_MUTEXES */ + + vListInitialiseItem( &( pxNewTCB->xStateListItem ) ); + vListInitialiseItem( &( pxNewTCB->xEventListItem ) ); + + /* Set the pxNewTCB as a link back from the ListItem_t. This is so we can get + back to the containing TCB from a generic item in a list. */ + listSET_LIST_ITEM_OWNER( &( pxNewTCB->xStateListItem ), pxNewTCB ); + + /* Event lists are always in priority order. */ + listSET_LIST_ITEM_VALUE( &( pxNewTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + listSET_LIST_ITEM_OWNER( &( pxNewTCB->xEventListItem ), pxNewTCB ); + + #if ( portCRITICAL_NESTING_IN_TCB == 1 ) + { + pxNewTCB->uxCriticalNesting = ( UBaseType_t ) 0U; + } + #endif /* portCRITICAL_NESTING_IN_TCB */ + + #if ( configUSE_APPLICATION_TASK_TAG == 1 ) + { + pxNewTCB->pxTaskTag = NULL; + } + #endif /* configUSE_APPLICATION_TASK_TAG */ + + #if ( configGENERATE_RUN_TIME_STATS == 1 ) + { + pxNewTCB->ulRunTimeCounter = 0UL; + } + #endif /* configGENERATE_RUN_TIME_STATS */ + + #if ( portUSING_MPU_WRAPPERS == 1 ) + { + vPortStoreTaskMPUSettings( &( pxNewTCB->xMPUSettings ), xRegions, pxNewTCB->pxStack, ulStackDepth ); + } + #else + { + /* Avoid compiler warning about unreferenced parameter. */ + ( void ) xRegions; + } + #endif + + #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 ) + { + for( x = 0; x < ( UBaseType_t ) configNUM_THREAD_LOCAL_STORAGE_POINTERS; x++ ) + { + pxNewTCB->pvThreadLocalStoragePointers[ x ] = NULL; + } + } + #endif + + #if ( configUSE_TASK_NOTIFICATIONS == 1 ) + { + pxNewTCB->ulNotifiedValue = 0; + pxNewTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION; + } + #endif + + #if ( configUSE_NEWLIB_REENTRANT == 1 ) + { + /* Initialise this task's Newlib reent structure. */ + _REENT_INIT_PTR( ( &( pxNewTCB->xNewLib_reent ) ) ); + } + #endif + + #if( INCLUDE_xTaskAbortDelay == 1 ) + { + pxNewTCB->ucDelayAborted = pdFALSE; + } + #endif + + /* Initialize the TCB stack to look as if the task was already running, + but had been interrupted by the scheduler. The return address is set + to the start of the task function. Once the stack has been initialised + the top of stack variable is updated. */ + #if( portUSING_MPU_WRAPPERS == 1 ) + { + pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged ); + } + #else /* portUSING_MPU_WRAPPERS */ + { + pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters ); + } + #endif /* portUSING_MPU_WRAPPERS */ + + if( ( void * ) pxCreatedTask != NULL ) + { + /* Pass the handle out in an anonymous way. The handle can be used to + change the created task's priority, delete the created task, etc.*/ + *pxCreatedTask = ( TaskHandle_t ) pxNewTCB; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } +} +/*-----------------------------------------------------------*/ + +static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) +{ + /* Ensure interrupts don't access the task lists while the lists are being + updated. */ + taskENTER_CRITICAL(); + { + uxCurrentNumberOfTasks++; + if( pxCurrentTCB == NULL ) + { + /* There are no other tasks, or all the other tasks are in + the suspended state - make this the current task. */ + pxCurrentTCB = pxNewTCB; + + if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 ) + { + /* This is the first task to be created so do the preliminary + initialisation required. We will not recover if this call + fails, but we will report the failure. */ + prvInitialiseTaskLists(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + /* If the scheduler is not already running, make this task the + current task if it is the highest priority task to be created + so far. */ + if( xSchedulerRunning == pdFALSE ) + { + if( pxCurrentTCB->uxPriority <= pxNewTCB->uxPriority ) + { + pxCurrentTCB = pxNewTCB; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + + uxTaskNumber++; + + #if ( configUSE_TRACE_FACILITY == 1 ) + { + /* Add a counter into the TCB for tracing only. */ + pxNewTCB->uxTCBNumber = uxTaskNumber; + } + #endif /* configUSE_TRACE_FACILITY */ + traceTASK_CREATE( pxNewTCB ); + + prvAddTaskToReadyList( pxNewTCB ); + + portSETUP_TCB( pxNewTCB ); + } + taskEXIT_CRITICAL(); + + if( xSchedulerRunning != pdFALSE ) + { + /* If the created task is of a higher priority than the current task + then it should run now. */ + if( pxCurrentTCB->uxPriority < pxNewTCB->uxPriority ) + { + taskYIELD_IF_USING_PREEMPTION(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } +} +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_vTaskDelete == 1 ) + + void vTaskDelete( TaskHandle_t xTaskToDelete ) + { + TCB_t *pxTCB; + + taskENTER_CRITICAL(); + { + /* If null is passed in here then it is the calling task that is + being deleted. */ + pxTCB = prvGetTCBFromHandle( xTaskToDelete ); + + /* Remove task from the ready list. */ + if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) + { + taskRESET_READY_PRIORITY( pxTCB->uxPriority ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Is the task waiting on an event also? */ + if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) + { + ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Increment the uxTaskNumber also so kernel aware debuggers can + detect that the task lists need re-generating. This is done before + portPRE_TASK_DELETE_HOOK() as in the Windows port that macro will + not return. */ + uxTaskNumber++; + + if( pxTCB == pxCurrentTCB ) + { + /* A task is deleting itself. This cannot complete within the + task itself, as a context switch to another task is required. + Place the task in the termination list. The idle task will + check the termination list and free up any memory allocated by + the scheduler for the TCB and stack of the deleted task. */ + vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xStateListItem ) ); + + /* Increment the ucTasksDeleted variable so the idle task knows + there is a task that has been deleted and that it should therefore + check the xTasksWaitingTermination list. */ + ++uxDeletedTasksWaitingCleanUp; + + /* The pre-delete hook is primarily for the Windows simulator, + in which Windows specific clean up operations are performed, + after which it is not possible to yield away from this task - + hence xYieldPending is used to latch that a context switch is + required. */ + portPRE_TASK_DELETE_HOOK( pxTCB, &xYieldPending ); + } + else + { + --uxCurrentNumberOfTasks; + prvDeleteTCB( pxTCB ); + + /* Reset the next expected unblock time in case it referred to + the task that has just been deleted. */ + prvResetNextTaskUnblockTime(); + } + + traceTASK_DELETE( pxTCB ); + } + taskEXIT_CRITICAL(); + + /* Force a reschedule if it is the currently running task that has just + been deleted. */ + if( xSchedulerRunning != pdFALSE ) + { + if( pxTCB == pxCurrentTCB ) + { + configASSERT( uxSchedulerSuspended == 0 ); + portYIELD_WITHIN_API(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + } + +#endif /* INCLUDE_vTaskDelete */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_vTaskDelayUntil == 1 ) + + void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement ) + { + TickType_t xTimeToWake; + BaseType_t xAlreadyYielded, xShouldDelay = pdFALSE; + + configASSERT( pxPreviousWakeTime ); + configASSERT( ( xTimeIncrement > 0U ) ); + configASSERT( uxSchedulerSuspended == 0 ); + + vTaskSuspendAll(); + { + /* Minor optimisation. The tick count cannot change in this + block. */ + const TickType_t xConstTickCount = xTickCount; + + /* Generate the tick time at which the task wants to wake. */ + xTimeToWake = *pxPreviousWakeTime + xTimeIncrement; + + if( xConstTickCount < *pxPreviousWakeTime ) + { + /* The tick count has overflowed since this function was + lasted called. In this case the only time we should ever + actually delay is if the wake time has also overflowed, + and the wake time is greater than the tick time. When this + is the case it is as if neither time had overflowed. */ + if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xConstTickCount ) ) + { + xShouldDelay = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + /* The tick time has not overflowed. In this case we will + delay if either the wake time has overflowed, and/or the + tick time is less than the wake time. */ + if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xConstTickCount ) ) + { + xShouldDelay = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + + /* Update the wake time ready for the next call. */ + *pxPreviousWakeTime = xTimeToWake; + + if( xShouldDelay != pdFALSE ) + { + traceTASK_DELAY_UNTIL( xTimeToWake ); + + /* prvAddCurrentTaskToDelayedList() needs the block time, not + the time to wake, so subtract the current tick count. */ + prvAddCurrentTaskToDelayedList( xTimeToWake - xConstTickCount, pdFALSE ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + xAlreadyYielded = xTaskResumeAll(); + + /* Force a reschedule if xTaskResumeAll has not already done so, we may + have put ourselves to sleep. */ + if( xAlreadyYielded == pdFALSE ) + { + portYIELD_WITHIN_API(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + +#endif /* INCLUDE_vTaskDelayUntil */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_vTaskDelay == 1 ) + + void vTaskDelay( const TickType_t xTicksToDelay ) + { + BaseType_t xAlreadyYielded = pdFALSE; + + /* A delay time of zero just forces a reschedule. */ + if( xTicksToDelay > ( TickType_t ) 0U ) + { + configASSERT( uxSchedulerSuspended == 0 ); + vTaskSuspendAll(); + { + traceTASK_DELAY(); + + /* A task that is removed from the event list while the + scheduler is suspended will not get placed in the ready + list or removed from the blocked list until the scheduler + is resumed. + + This task cannot be in an event list as it is the currently + executing task. */ + prvAddCurrentTaskToDelayedList( xTicksToDelay, pdFALSE ); + } + xAlreadyYielded = xTaskResumeAll(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Force a reschedule if xTaskResumeAll has not already done so, we may + have put ourselves to sleep. */ + if( xAlreadyYielded == pdFALSE ) + { + portYIELD_WITHIN_API(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + +#endif /* INCLUDE_vTaskDelay */ +/*-----------------------------------------------------------*/ + +#if( ( INCLUDE_eTaskGetState == 1 ) || ( configUSE_TRACE_FACILITY == 1 ) ) + + eTaskState eTaskGetState( TaskHandle_t xTask ) + { + eTaskState eReturn; + List_t *pxStateList; + const TCB_t * const pxTCB = ( TCB_t * ) xTask; + + configASSERT( pxTCB ); + + if( pxTCB == pxCurrentTCB ) + { + /* The task calling this function is querying its own state. */ + eReturn = eRunning; + } + else + { + taskENTER_CRITICAL(); + { + pxStateList = ( List_t * ) listLIST_ITEM_CONTAINER( &( pxTCB->xStateListItem ) ); + } + taskEXIT_CRITICAL(); + + if( ( pxStateList == pxDelayedTaskList ) || ( pxStateList == pxOverflowDelayedTaskList ) ) + { + /* The task being queried is referenced from one of the Blocked + lists. */ + eReturn = eBlocked; + } + + #if ( INCLUDE_vTaskSuspend == 1 ) + else if( pxStateList == &xSuspendedTaskList ) + { + /* The task being queried is referenced from the suspended + list. Is it genuinely suspended or is it block + indefinitely? */ + if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL ) + { + eReturn = eSuspended; + } + else + { + eReturn = eBlocked; + } + } + #endif + + #if ( INCLUDE_vTaskDelete == 1 ) + else if( ( pxStateList == &xTasksWaitingTermination ) || ( pxStateList == NULL ) ) + { + /* The task being queried is referenced from the deleted + tasks list, or it is not referenced from any lists at + all. */ + eReturn = eDeleted; + } + #endif + + else /*lint !e525 Negative indentation is intended to make use of pre-processor clearer. */ + { + /* If the task is not in any other state, it must be in the + Ready (including pending ready) state. */ + eReturn = eReady; + } + } + + return eReturn; + } /*lint !e818 xTask cannot be a pointer to const because it is a typedef. */ + +#endif /* INCLUDE_eTaskGetState */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_uxTaskPriorityGet == 1 ) + + UBaseType_t uxTaskPriorityGet( TaskHandle_t xTask ) + { + TCB_t *pxTCB; + UBaseType_t uxReturn; + + taskENTER_CRITICAL(); + { + /* If null is passed in here then it is the priority of the that + called uxTaskPriorityGet() that is being queried. */ + pxTCB = prvGetTCBFromHandle( xTask ); + uxReturn = pxTCB->uxPriority; + } + taskEXIT_CRITICAL(); + + return uxReturn; + } + +#endif /* INCLUDE_uxTaskPriorityGet */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_uxTaskPriorityGet == 1 ) + + UBaseType_t uxTaskPriorityGetFromISR( TaskHandle_t xTask ) + { + TCB_t *pxTCB; + UBaseType_t uxReturn, uxSavedInterruptState; + + /* RTOS ports that support interrupt nesting have the concept of a + maximum system call (or maximum API call) interrupt priority. + Interrupts that are above the maximum system call priority are keep + permanently enabled, even when the RTOS kernel is in a critical section, + but cannot make any calls to FreeRTOS API functions. If configASSERT() + is defined in FreeRTOSConfig.h then + portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has + been assigned a priority above the configured maximum system call + priority. Only FreeRTOS functions that end in FromISR can be called + from interrupts that have been assigned a priority at or (logically) + below the maximum system call interrupt priority. FreeRTOS maintains a + separate interrupt safe API to ensure interrupt entry is as fast and as + simple as possible. More information (albeit Cortex-M specific) is + provided on the following link: + http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + + uxSavedInterruptState = portSET_INTERRUPT_MASK_FROM_ISR(); + { + /* If null is passed in here then it is the priority of the calling + task that is being queried. */ + pxTCB = prvGetTCBFromHandle( xTask ); + uxReturn = pxTCB->uxPriority; + } + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptState ); + + return uxReturn; + } + +#endif /* INCLUDE_uxTaskPriorityGet */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_vTaskPrioritySet == 1 ) + + void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority ) + { + TCB_t *pxTCB; + UBaseType_t uxCurrentBasePriority, uxPriorityUsedOnEntry; + BaseType_t xYieldRequired = pdFALSE; + + configASSERT( ( uxNewPriority < configMAX_PRIORITIES ) ); + + /* Ensure the new priority is valid. */ + if( uxNewPriority >= ( UBaseType_t ) configMAX_PRIORITIES ) + { + uxNewPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + taskENTER_CRITICAL(); + { + /* If null is passed in here then it is the priority of the calling + task that is being changed. */ + pxTCB = prvGetTCBFromHandle( xTask ); + + traceTASK_PRIORITY_SET( pxTCB, uxNewPriority ); + + #if ( configUSE_MUTEXES == 1 ) + { + uxCurrentBasePriority = pxTCB->uxBasePriority; + } + #else + { + uxCurrentBasePriority = pxTCB->uxPriority; + } + #endif + + if( uxCurrentBasePriority != uxNewPriority ) + { + /* The priority change may have readied a task of higher + priority than the calling task. */ + if( uxNewPriority > uxCurrentBasePriority ) + { + if( pxTCB != pxCurrentTCB ) + { + /* The priority of a task other than the currently + running task is being raised. Is the priority being + raised above that of the running task? */ + if( uxNewPriority >= pxCurrentTCB->uxPriority ) + { + xYieldRequired = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + /* The priority of the running task is being raised, + but the running task must already be the highest + priority task able to run so no yield is required. */ + } + } + else if( pxTCB == pxCurrentTCB ) + { + /* Setting the priority of the running task down means + there may now be another task of higher priority that + is ready to execute. */ + xYieldRequired = pdTRUE; + } + else + { + /* Setting the priority of any other task down does not + require a yield as the running task must be above the + new priority of the task being modified. */ + } + + /* Remember the ready list the task might be referenced from + before its uxPriority member is changed so the + taskRESET_READY_PRIORITY() macro can function correctly. */ + uxPriorityUsedOnEntry = pxTCB->uxPriority; + + #if ( configUSE_MUTEXES == 1 ) + { + /* Only change the priority being used if the task is not + currently using an inherited priority. */ + if( pxTCB->uxBasePriority == pxTCB->uxPriority ) + { + pxTCB->uxPriority = uxNewPriority; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* The base priority gets set whatever. */ + pxTCB->uxBasePriority = uxNewPriority; + } + #else + { + pxTCB->uxPriority = uxNewPriority; + } + #endif + + /* Only reset the event list item value if the value is not + being used for anything else. */ + if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL ) + { + listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxNewPriority ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* If the task is in the blocked or suspended list we need do + nothing more than change it's priority variable. However, if + the task is in a ready list it needs to be removed and placed + in the list appropriate to its new priority. */ + if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE ) + { + /* The task is currently in its ready list - remove before adding + it to it's new ready list. As we are in a critical section we + can do this even if the scheduler is suspended. */ + if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) + { + /* It is known that the task is in its ready list so + there is no need to check again and the port level + reset macro can be called directly. */ + portRESET_READY_PRIORITY( uxPriorityUsedOnEntry, uxTopReadyPriority ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + prvAddTaskToReadyList( pxTCB ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + if( xYieldRequired != pdFALSE ) + { + taskYIELD_IF_USING_PREEMPTION(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Remove compiler warning about unused variables when the port + optimised task selection is not being used. */ + ( void ) uxPriorityUsedOnEntry; + } + } + taskEXIT_CRITICAL(); + } + +#endif /* INCLUDE_vTaskPrioritySet */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_vTaskSuspend == 1 ) + + void vTaskSuspend( TaskHandle_t xTaskToSuspend ) + { + TCB_t *pxTCB; + + taskENTER_CRITICAL(); + { + /* If null is passed in here then it is the running task that is + being suspended. */ + pxTCB = prvGetTCBFromHandle( xTaskToSuspend ); + + traceTASK_SUSPEND( pxTCB ); + + /* Remove task from the ready/delayed list and place in the + suspended list. */ + if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) + { + taskRESET_READY_PRIORITY( pxTCB->uxPriority ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Is the task waiting on an event also? */ + if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) + { + ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) ); + } + taskEXIT_CRITICAL(); + + if( xSchedulerRunning != pdFALSE ) + { + /* Reset the next expected unblock time in case it referred to the + task that is now in the Suspended state. */ + taskENTER_CRITICAL(); + { + prvResetNextTaskUnblockTime(); + } + taskEXIT_CRITICAL(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + if( pxTCB == pxCurrentTCB ) + { + if( xSchedulerRunning != pdFALSE ) + { + /* The current task has just been suspended. */ + configASSERT( uxSchedulerSuspended == 0 ); + portYIELD_WITHIN_API(); + } + else + { + /* The scheduler is not running, but the task that was pointed + to by pxCurrentTCB has just been suspended and pxCurrentTCB + must be adjusted to point to a different task. */ + if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks ) + { + /* No other tasks are ready, so set pxCurrentTCB back to + NULL so when the next task is created pxCurrentTCB will + be set to point to it no matter what its relative priority + is. */ + pxCurrentTCB = NULL; + } + else + { + vTaskSwitchContext(); + } + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + +#endif /* INCLUDE_vTaskSuspend */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_vTaskSuspend == 1 ) + + static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask ) + { + BaseType_t xReturn = pdFALSE; + const TCB_t * const pxTCB = ( TCB_t * ) xTask; + + /* Accesses xPendingReadyList so must be called from a critical + section. */ + + /* It does not make sense to check if the calling task is suspended. */ + configASSERT( xTask ); + + /* Is the task being resumed actually in the suspended list? */ + if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xStateListItem ) ) != pdFALSE ) + { + /* Has the task already been resumed from within an ISR? */ + if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) == pdFALSE ) + { + /* Is it in the suspended list because it is in the Suspended + state, or because is is blocked with no timeout? */ + if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) != pdFALSE ) + { + xReturn = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + return xReturn; + } /*lint !e818 xTask cannot be a pointer to const because it is a typedef. */ + +#endif /* INCLUDE_vTaskSuspend */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_vTaskSuspend == 1 ) + + void vTaskResume( TaskHandle_t xTaskToResume ) + { + TCB_t * const pxTCB = ( TCB_t * ) xTaskToResume; + + /* It does not make sense to resume the calling task. */ + configASSERT( xTaskToResume ); + + /* The parameter cannot be NULL as it is impossible to resume the + currently executing task. */ + if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) ) + { + taskENTER_CRITICAL(); + { + if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE ) + { + traceTASK_RESUME( pxTCB ); + + /* As we are in a critical section we can access the ready + lists even if the scheduler is suspended. */ + ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); + prvAddTaskToReadyList( pxTCB ); + + /* We may have just resumed a higher priority task. */ + if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) + { + /* This yield may not cause the task just resumed to run, + but will leave the lists in the correct state for the + next yield. */ + taskYIELD_IF_USING_PREEMPTION(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + +#endif /* INCLUDE_vTaskSuspend */ + +/*-----------------------------------------------------------*/ + +#if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) ) + + BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume ) + { + BaseType_t xYieldRequired = pdFALSE; + TCB_t * const pxTCB = ( TCB_t * ) xTaskToResume; + UBaseType_t uxSavedInterruptStatus; + + configASSERT( xTaskToResume ); + + /* RTOS ports that support interrupt nesting have the concept of a + maximum system call (or maximum API call) interrupt priority. + Interrupts that are above the maximum system call priority are keep + permanently enabled, even when the RTOS kernel is in a critical section, + but cannot make any calls to FreeRTOS API functions. If configASSERT() + is defined in FreeRTOSConfig.h then + portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has + been assigned a priority above the configured maximum system call + priority. Only FreeRTOS functions that end in FromISR can be called + from interrupts that have been assigned a priority at or (logically) + below the maximum system call interrupt priority. FreeRTOS maintains a + separate interrupt safe API to ensure interrupt entry is as fast and as + simple as possible. More information (albeit Cortex-M specific) is + provided on the following link: + http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + + uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + { + if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE ) + { + traceTASK_RESUME_FROM_ISR( pxTCB ); + + /* Check the ready lists can be accessed. */ + if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) + { + /* Ready lists can be accessed so move the task from the + suspended list to the ready list directly. */ + if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) + { + xYieldRequired = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); + prvAddTaskToReadyList( pxTCB ); + } + else + { + /* The delayed or ready lists cannot be accessed so the task + is held in the pending ready list until the scheduler is + unsuspended. */ + vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) ); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + + return xYieldRequired; + } + +#endif /* ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) ) */ +/*-----------------------------------------------------------*/ + +void vTaskStartScheduler( void ) +{ +BaseType_t xReturn; + + /* Add the idle task at the lowest priority. */ + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) + { + StaticTask_t *pxIdleTaskTCBBuffer = NULL; + StackType_t *pxIdleTaskStackBuffer = NULL; + uint32_t ulIdleTaskStackSize; + + /* The Idle task is created using user provided RAM - obtain the + address of the RAM then create the idle task. */ + vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize ); + xIdleTaskHandle = xTaskCreateStatic( prvIdleTask, + "IDLE", + ulIdleTaskStackSize, + ( void * ) NULL, + ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), + pxIdleTaskStackBuffer, + pxIdleTaskTCBBuffer ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ + + if( xIdleTaskHandle != NULL ) + { + xReturn = pdPASS; + } + else + { + xReturn = pdFAIL; + } + } + #else + { + /* The Idle task is being created using dynamically allocated RAM. */ + xReturn = xTaskCreate( prvIdleTask, + "IDLE", configMINIMAL_STACK_SIZE, + ( void * ) NULL, + ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), + &xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ + } + #endif /* configSUPPORT_STATIC_ALLOCATION */ + + #if ( configUSE_TIMERS == 1 ) + { + if( xReturn == pdPASS ) + { + xReturn = xTimerCreateTimerTask(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configUSE_TIMERS */ + + if( xReturn == pdPASS ) + { + /* Interrupts are turned off here, to ensure a tick does not occur + before or during the call to xPortStartScheduler(). The stacks of + the created tasks contain a status word with interrupts switched on + so interrupts will automatically get re-enabled when the first task + starts to run. */ + portDISABLE_INTERRUPTS(); + + #if ( configUSE_NEWLIB_REENTRANT == 1 ) + { + /* Switch Newlib's _impure_ptr variable to point to the _reent + structure specific to the task that will run first. */ + _impure_ptr = &( pxCurrentTCB->xNewLib_reent ); + } + #endif /* configUSE_NEWLIB_REENTRANT */ + + xNextTaskUnblockTime = portMAX_DELAY; + xSchedulerRunning = pdTRUE; + xTickCount = ( TickType_t ) 0U; + + /* If configGENERATE_RUN_TIME_STATS is defined then the following + macro must be defined to configure the timer/counter used to generate + the run time counter time base. */ + portCONFIGURE_TIMER_FOR_RUN_TIME_STATS(); + + /* Setting up the timer tick is hardware specific and thus in the + portable interface. */ + if( xPortStartScheduler() != pdFALSE ) + { + /* Should not reach here as if the scheduler is running the + function will not return. */ + } + else + { + /* Should only reach here if a task calls xTaskEndScheduler(). */ + } + } + else + { + /* This line will only be reached if the kernel could not be started, + because there was not enough FreeRTOS heap to create the idle task + or the timer task. */ + configASSERT( xReturn != errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY ); + } + + /* Prevent compiler warnings if INCLUDE_xTaskGetIdleTaskHandle is set to 0, + meaning xIdleTaskHandle is not used anywhere else. */ + ( void ) xIdleTaskHandle; +} +/*-----------------------------------------------------------*/ + +void vTaskEndScheduler( void ) +{ + /* Stop the scheduler interrupts and call the portable scheduler end + routine so the original ISRs can be restored if necessary. The port + layer must ensure interrupts enable bit is left in the correct state. */ + portDISABLE_INTERRUPTS(); + xSchedulerRunning = pdFALSE; + vPortEndScheduler(); +} +/*----------------------------------------------------------*/ + +void vTaskSuspendAll( void ) +{ + /* A critical section is not required as the variable is of type + BaseType_t. Please read Richard Barry's reply in the following link to a + post in the FreeRTOS support forum before reporting this as a bug! - + http://goo.gl/wu4acr */ + ++uxSchedulerSuspended; +} +/*----------------------------------------------------------*/ + +#if ( configUSE_TICKLESS_IDLE != 0 ) + + static TickType_t prvGetExpectedIdleTime( void ) + { + TickType_t xReturn; + UBaseType_t uxHigherPriorityReadyTasks = pdFALSE; + + /* uxHigherPriorityReadyTasks takes care of the case where + configUSE_PREEMPTION is 0, so there may be tasks above the idle priority + task that are in the Ready state, even though the idle task is + running. */ + #if( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 ) + { + if( uxTopReadyPriority > tskIDLE_PRIORITY ) + { + uxHigherPriorityReadyTasks = pdTRUE; + } + } + #else + { + const UBaseType_t uxLeastSignificantBit = ( UBaseType_t ) 0x01; + + /* When port optimised task selection is used the uxTopReadyPriority + variable is used as a bit map. If bits other than the least + significant bit are set then there are tasks that have a priority + above the idle priority that are in the Ready state. This takes + care of the case where the co-operative scheduler is in use. */ + if( uxTopReadyPriority > uxLeastSignificantBit ) + { + uxHigherPriorityReadyTasks = pdTRUE; + } + } + #endif + + if( pxCurrentTCB->uxPriority > tskIDLE_PRIORITY ) + { + xReturn = 0; + } + else if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > 1 ) + { + /* There are other idle priority tasks in the ready state. If + time slicing is used then the very next tick interrupt must be + processed. */ + xReturn = 0; + } + else if( uxHigherPriorityReadyTasks != pdFALSE ) + { + /* There are tasks in the Ready state that have a priority above the + idle priority. This path can only be reached if + configUSE_PREEMPTION is 0. */ + xReturn = 0; + } + else + { + xReturn = xNextTaskUnblockTime - xTickCount; + } + + return xReturn; + } + +#endif /* configUSE_TICKLESS_IDLE */ +/*----------------------------------------------------------*/ + +BaseType_t xTaskResumeAll( void ) +{ +TCB_t *pxTCB = NULL; +BaseType_t xAlreadyYielded = pdFALSE; + + /* If uxSchedulerSuspended is zero then this function does not match a + previous call to vTaskSuspendAll(). */ + configASSERT( uxSchedulerSuspended ); + + /* It is possible that an ISR caused a task to be removed from an event + list while the scheduler was suspended. If this was the case then the + removed task will have been added to the xPendingReadyList. Once the + scheduler has been resumed it is safe to move all the pending ready + tasks from this list into their appropriate ready list. */ + taskENTER_CRITICAL(); + { + --uxSchedulerSuspended; + + if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) + { + if( uxCurrentNumberOfTasks > ( UBaseType_t ) 0U ) + { + /* Move any readied tasks from the pending list into the + appropriate ready list. */ + while( listLIST_IS_EMPTY( &xPendingReadyList ) == pdFALSE ) + { + pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyList ) ); + ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); + ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); + prvAddTaskToReadyList( pxTCB ); + + /* If the moved task has a priority higher than the current + task then a yield must be performed. */ + if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) + { + xYieldPending = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + + if( pxTCB != NULL ) + { + /* A task was unblocked while the scheduler was suspended, + which may have prevented the next unblock time from being + re-calculated, in which case re-calculate it now. Mainly + important for low power tickless implementations, where + this can prevent an unnecessary exit from low power + state. */ + prvResetNextTaskUnblockTime(); + } + + /* If any ticks occurred while the scheduler was suspended then + they should be processed now. This ensures the tick count does + not slip, and that any delayed tasks are resumed at the correct + time. */ + { + UBaseType_t uxPendedCounts = uxPendedTicks; /* Non-volatile copy. */ + + if( uxPendedCounts > ( UBaseType_t ) 0U ) + { + do + { + if( xTaskIncrementTick() != pdFALSE ) + { + xYieldPending = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + --uxPendedCounts; + } while( uxPendedCounts > ( UBaseType_t ) 0U ); + + uxPendedTicks = 0; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + + if( xYieldPending != pdFALSE ) + { + #if( configUSE_PREEMPTION != 0 ) + { + xAlreadyYielded = pdTRUE; + } + #endif + taskYIELD_IF_USING_PREEMPTION(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); + + return xAlreadyYielded; +} +/*-----------------------------------------------------------*/ + +TickType_t xTaskGetTickCount( void ) +{ +TickType_t xTicks; + + /* Critical section required if running on a 16 bit processor. */ + portTICK_TYPE_ENTER_CRITICAL(); + { + xTicks = xTickCount; + } + portTICK_TYPE_EXIT_CRITICAL(); + + return xTicks; +} +/*-----------------------------------------------------------*/ + +TickType_t xTaskGetTickCountFromISR( void ) +{ +TickType_t xReturn; +UBaseType_t uxSavedInterruptStatus; + + /* RTOS ports that support interrupt nesting have the concept of a maximum + system call (or maximum API call) interrupt priority. Interrupts that are + above the maximum system call priority are kept permanently enabled, even + when the RTOS kernel is in a critical section, but cannot make any calls to + FreeRTOS API functions. If configASSERT() is defined in FreeRTOSConfig.h + then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has been + assigned a priority above the configured maximum system call priority. + Only FreeRTOS functions that end in FromISR can be called from interrupts + that have been assigned a priority at or (logically) below the maximum + system call interrupt priority. FreeRTOS maintains a separate interrupt + safe API to ensure interrupt entry is as fast and as simple as possible. + More information (albeit Cortex-M specific) is provided on the following + link: http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + + uxSavedInterruptStatus = portTICK_TYPE_SET_INTERRUPT_MASK_FROM_ISR(); + { + xReturn = xTickCount; + } + portTICK_TYPE_CLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +UBaseType_t uxTaskGetNumberOfTasks( void ) +{ + /* A critical section is not required because the variables are of type + BaseType_t. */ + return uxCurrentNumberOfTasks; +} +/*-----------------------------------------------------------*/ + +char *pcTaskGetName( TaskHandle_t xTaskToQuery ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +{ +TCB_t *pxTCB; + + /* If null is passed in here then the name of the calling task is being + queried. */ + pxTCB = prvGetTCBFromHandle( xTaskToQuery ); + configASSERT( pxTCB ); + return &( pxTCB->pcTaskName[ 0 ] ); +} +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_xTaskGetHandle == 1 ) + + static TCB_t *prvSearchForNameWithinSingleList( List_t *pxList, const char pcNameToQuery[] ) + { + TCB_t *pxNextTCB, *pxFirstTCB, *pxReturn = NULL; + UBaseType_t x; + char cNextChar; + + /* This function is called with the scheduler suspended. */ + + if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 ) + { + listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList ); + + do + { + listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList ); + + /* Check each character in the name looking for a match or + mismatch. */ + for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ ) + { + cNextChar = pxNextTCB->pcTaskName[ x ]; + + if( cNextChar != pcNameToQuery[ x ] ) + { + /* Characters didn't match. */ + break; + } + else if( cNextChar == 0x00 ) + { + /* Both strings terminated, a match must have been + found. */ + pxReturn = pxNextTCB; + break; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + + if( pxReturn != NULL ) + { + /* The handle has been found. */ + break; + } + + } while( pxNextTCB != pxFirstTCB ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + return pxReturn; + } + +#endif /* INCLUDE_xTaskGetHandle */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_xTaskGetHandle == 1 ) + + TaskHandle_t xTaskGetHandle( const char *pcNameToQuery ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + { + UBaseType_t uxQueue = configMAX_PRIORITIES; + TCB_t* pxTCB; + + /* Task names will be truncated to configMAX_TASK_NAME_LEN - 1 bytes. */ + configASSERT( strlen( pcNameToQuery ) < configMAX_TASK_NAME_LEN ); + + vTaskSuspendAll(); + { + /* Search the ready lists. */ + do + { + uxQueue--; + pxTCB = prvSearchForNameWithinSingleList( ( List_t * ) &( pxReadyTasksLists[ uxQueue ] ), pcNameToQuery ); + + if( pxTCB != NULL ) + { + /* Found the handle. */ + break; + } + + } while( uxQueue > ( UBaseType_t ) tskIDLE_PRIORITY ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + + /* Search the delayed lists. */ + if( pxTCB == NULL ) + { + pxTCB = prvSearchForNameWithinSingleList( ( List_t * ) pxDelayedTaskList, pcNameToQuery ); + } + + if( pxTCB == NULL ) + { + pxTCB = prvSearchForNameWithinSingleList( ( List_t * ) pxOverflowDelayedTaskList, pcNameToQuery ); + } + + #if ( INCLUDE_vTaskSuspend == 1 ) + { + if( pxTCB == NULL ) + { + /* Search the suspended list. */ + pxTCB = prvSearchForNameWithinSingleList( &xSuspendedTaskList, pcNameToQuery ); + } + } + #endif + + #if( INCLUDE_vTaskDelete == 1 ) + { + if( pxTCB == NULL ) + { + /* Search the deleted list. */ + pxTCB = prvSearchForNameWithinSingleList( &xTasksWaitingTermination, pcNameToQuery ); + } + } + #endif + } + ( void ) xTaskResumeAll(); + + return ( TaskHandle_t ) pxTCB; + } + +#endif /* INCLUDE_xTaskGetHandle */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_TRACE_FACILITY == 1 ) + + UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray, const UBaseType_t uxArraySize, uint32_t * const pulTotalRunTime ) + { + UBaseType_t uxTask = 0, uxQueue = configMAX_PRIORITIES; + + vTaskSuspendAll(); + { + /* Is there a space in the array for each task in the system? */ + if( uxArraySize >= uxCurrentNumberOfTasks ) + { + /* Fill in an TaskStatus_t structure with information on each + task in the Ready state. */ + do + { + uxQueue--; + uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &( pxReadyTasksLists[ uxQueue ] ), eReady ); + + } while( uxQueue > ( UBaseType_t ) tskIDLE_PRIORITY ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + + /* Fill in an TaskStatus_t structure with information on each + task in the Blocked state. */ + uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxDelayedTaskList, eBlocked ); + uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxOverflowDelayedTaskList, eBlocked ); + + #if( INCLUDE_vTaskDelete == 1 ) + { + /* Fill in an TaskStatus_t structure with information on + each task that has been deleted but not yet cleaned up. */ + uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xTasksWaitingTermination, eDeleted ); + } + #endif + + #if ( INCLUDE_vTaskSuspend == 1 ) + { + /* Fill in an TaskStatus_t structure with information on + each task in the Suspended state. */ + uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xSuspendedTaskList, eSuspended ); + } + #endif + + #if ( configGENERATE_RUN_TIME_STATS == 1) + { + if( pulTotalRunTime != NULL ) + { + #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE + portALT_GET_RUN_TIME_COUNTER_VALUE( ( *pulTotalRunTime ) ); + #else + *pulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE(); + #endif + } + } + #else + { + if( pulTotalRunTime != NULL ) + { + *pulTotalRunTime = 0; + } + } + #endif + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + ( void ) xTaskResumeAll(); + + return uxTask; + } + +#endif /* configUSE_TRACE_FACILITY */ +/*----------------------------------------------------------*/ + +#if ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) + + TaskHandle_t xTaskGetIdleTaskHandle( void ) + { + /* If xTaskGetIdleTaskHandle() is called before the scheduler has been + started, then xIdleTaskHandle will be NULL. */ + configASSERT( ( xIdleTaskHandle != NULL ) ); + return xIdleTaskHandle; + } + +#endif /* INCLUDE_xTaskGetIdleTaskHandle */ +/*----------------------------------------------------------*/ + +/* This conditional compilation should use inequality to 0, not equality to 1. +This is to ensure vTaskStepTick() is available when user defined low power mode +implementations require configUSE_TICKLESS_IDLE to be set to a value other than +1. */ +#if ( configUSE_TICKLESS_IDLE != 0 ) + + void vTaskStepTick( const TickType_t xTicksToJump ) + { + /* Correct the tick count value after a period during which the tick + was suppressed. Note this does *not* call the tick hook function for + each stepped tick. */ + configASSERT( ( xTickCount + xTicksToJump ) <= xNextTaskUnblockTime ); + xTickCount += xTicksToJump; + traceINCREASE_TICK_COUNT( xTicksToJump ); + } + +#endif /* configUSE_TICKLESS_IDLE */ +/*----------------------------------------------------------*/ + +#if ( INCLUDE_xTaskAbortDelay == 1 ) + + BaseType_t xTaskAbortDelay( TaskHandle_t xTask ) + { + TCB_t *pxTCB = ( TCB_t * ) xTask; + BaseType_t xReturn = pdFALSE; + + configASSERT( pxTCB ); + + vTaskSuspendAll(); + { + /* A task can only be prematurely removed from the Blocked state if + it is actually in the Blocked state. */ + if( eTaskGetState( xTask ) == eBlocked ) + { + /* Remove the reference to the task from the blocked list. An + interrupt won't touch the xStateListItem because the + scheduler is suspended. */ + ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); + + /* Is the task waiting on an event also? If so remove it from + the event list too. Interrupts can touch the event list item, + even though the scheduler is suspended, so a critical section + is used. */ + taskENTER_CRITICAL(); + { + if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) + { + ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); + pxTCB->ucDelayAborted = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); + + /* Place the unblocked task into the appropriate ready list. */ + prvAddTaskToReadyList( pxTCB ); + + /* A task being unblocked cannot cause an immediate context + switch if preemption is turned off. */ + #if ( configUSE_PREEMPTION == 1 ) + { + /* Preemption is on, but a context switch should only be + performed if the unblocked task has a priority that is + equal to or higher than the currently executing task. */ + if( pxTCB->uxPriority > pxCurrentTCB->uxPriority ) + { + /* Pend the yield to be performed when the scheduler + is unsuspended. */ + xYieldPending = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configUSE_PREEMPTION */ + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + xTaskResumeAll(); + + return xReturn; + } + +#endif /* INCLUDE_xTaskAbortDelay */ +/*----------------------------------------------------------*/ + +BaseType_t xTaskIncrementTick( void ) +{ +TCB_t * pxTCB; +TickType_t xItemValue; +BaseType_t xSwitchRequired = pdFALSE; + + /* Called by the portable layer each time a tick interrupt occurs. + Increments the tick then checks to see if the new tick value will cause any + tasks to be unblocked. */ + traceTASK_INCREMENT_TICK( xTickCount ); + if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) + { + /* Minor optimisation. The tick count cannot change in this + block. */ + const TickType_t xConstTickCount = xTickCount + 1; + + /* Increment the RTOS tick, switching the delayed and overflowed + delayed lists if it wraps to 0. */ + xTickCount = xConstTickCount; + + if( xConstTickCount == ( TickType_t ) 0U ) + { + taskSWITCH_DELAYED_LISTS(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* See if this tick has made a timeout expire. Tasks are stored in + the queue in the order of their wake time - meaning once one task + has been found whose block time has not expired there is no need to + look any further down the list. */ + if( xConstTickCount >= xNextTaskUnblockTime ) + { + for( ;; ) + { + if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) + { + /* The delayed list is empty. Set xNextTaskUnblockTime + to the maximum possible value so it is extremely + unlikely that the + if( xTickCount >= xNextTaskUnblockTime ) test will pass + next time through. */ + xNextTaskUnblockTime = portMAX_DELAY; /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + break; + } + else + { + /* The delayed list is not empty, get the value of the + item at the head of the delayed list. This is the time + at which the task at the head of the delayed list must + be removed from the Blocked state. */ + pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); + xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xStateListItem ) ); + + if( xConstTickCount < xItemValue ) + { + /* It is not time to unblock this item yet, but the + item value is the time at which the task at the head + of the blocked list must be removed from the Blocked + state - so record the item value in + xNextTaskUnblockTime. */ + xNextTaskUnblockTime = xItemValue; + break; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* It is time to remove the item from the Blocked state. */ + ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); + + /* Is the task waiting on an event also? If so remove + it from the event list. */ + if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) + { + ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Place the unblocked task into the appropriate ready + list. */ + prvAddTaskToReadyList( pxTCB ); + + /* A task being unblocked cannot cause an immediate + context switch if preemption is turned off. */ + #if ( configUSE_PREEMPTION == 1 ) + { + /* Preemption is on, but a context switch should + only be performed if the unblocked task has a + priority that is equal to or higher than the + currently executing task. */ + if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) + { + xSwitchRequired = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configUSE_PREEMPTION */ + } + } + } + + /* Tasks of equal priority to the currently running task will share + processing time (time slice) if preemption is on, and the application + writer has not explicitly turned time slicing off. */ + #if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) + { + if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB->uxPriority ] ) ) > ( UBaseType_t ) 1 ) + { + xSwitchRequired = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */ + + #if ( configUSE_TICK_HOOK == 1 ) + { + /* Guard against the tick hook being called when the pended tick + count is being unwound (when the scheduler is being unlocked). */ + if( uxPendedTicks == ( UBaseType_t ) 0U ) + { + vApplicationTickHook(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configUSE_TICK_HOOK */ + } + else + { + ++uxPendedTicks; + + /* The tick hook gets called at regular intervals, even if the + scheduler is locked. */ + #if ( configUSE_TICK_HOOK == 1 ) + { + vApplicationTickHook(); + } + #endif + } + + #if ( configUSE_PREEMPTION == 1 ) + { + if( xYieldPending != pdFALSE ) + { + xSwitchRequired = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configUSE_PREEMPTION */ + + return xSwitchRequired; +} +/*-----------------------------------------------------------*/ + +#if ( configUSE_APPLICATION_TASK_TAG == 1 ) + + void vTaskSetApplicationTaskTag( TaskHandle_t xTask, TaskHookFunction_t pxHookFunction ) + { + TCB_t *xTCB; + + /* If xTask is NULL then it is the task hook of the calling task that is + getting set. */ + if( xTask == NULL ) + { + xTCB = ( TCB_t * ) pxCurrentTCB; + } + else + { + xTCB = ( TCB_t * ) xTask; + } + + /* Save the hook function in the TCB. A critical section is required as + the value can be accessed from an interrupt. */ + taskENTER_CRITICAL(); + xTCB->pxTaskTag = pxHookFunction; + taskEXIT_CRITICAL(); + } + +#endif /* configUSE_APPLICATION_TASK_TAG */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_APPLICATION_TASK_TAG == 1 ) + + TaskHookFunction_t xTaskGetApplicationTaskTag( TaskHandle_t xTask ) + { + TCB_t *xTCB; + TaskHookFunction_t xReturn; + + /* If xTask is NULL then we are setting our own task hook. */ + if( xTask == NULL ) + { + xTCB = ( TCB_t * ) pxCurrentTCB; + } + else + { + xTCB = ( TCB_t * ) xTask; + } + + /* Save the hook function in the TCB. A critical section is required as + the value can be accessed from an interrupt. */ + taskENTER_CRITICAL(); + { + xReturn = xTCB->pxTaskTag; + } + taskEXIT_CRITICAL(); + + return xReturn; + } + +#endif /* configUSE_APPLICATION_TASK_TAG */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_APPLICATION_TASK_TAG == 1 ) + + BaseType_t xTaskCallApplicationTaskHook( TaskHandle_t xTask, void *pvParameter ) + { + TCB_t *xTCB; + BaseType_t xReturn; + + /* If xTask is NULL then we are calling our own task hook. */ + if( xTask == NULL ) + { + xTCB = ( TCB_t * ) pxCurrentTCB; + } + else + { + xTCB = ( TCB_t * ) xTask; + } + + if( xTCB->pxTaskTag != NULL ) + { + xReturn = xTCB->pxTaskTag( pvParameter ); + } + else + { + xReturn = pdFAIL; + } + + return xReturn; + } + +#endif /* configUSE_APPLICATION_TASK_TAG */ +/*-----------------------------------------------------------*/ + +void vTaskSwitchContext( void ) +{ + if( uxSchedulerSuspended != ( UBaseType_t ) pdFALSE ) + { + /* The scheduler is currently suspended - do not allow a context + switch. */ + xYieldPending = pdTRUE; + } + else + { + xYieldPending = pdFALSE; + traceTASK_SWITCHED_OUT(); + + #if ( configGENERATE_RUN_TIME_STATS == 1 ) + { + #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE + portALT_GET_RUN_TIME_COUNTER_VALUE( ulTotalRunTime ); + #else + ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE(); + #endif + + /* Add the amount of time the task has been running to the + accumulated time so far. The time the task started running was + stored in ulTaskSwitchedInTime. Note that there is no overflow + protection here so count values are only valid until the timer + overflows. The guard against negative values is to protect + against suspect run time stat counter implementations - which + are provided by the application, not the kernel. */ + if( ulTotalRunTime > ulTaskSwitchedInTime ) + { + pxCurrentTCB->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + ulTaskSwitchedInTime = ulTotalRunTime; + } + #endif /* configGENERATE_RUN_TIME_STATS */ + + /* Check for stack overflow, if configured. */ + taskCHECK_FOR_STACK_OVERFLOW(); + + /* Select a new task to run using either the generic C or port + optimised asm code. */ + taskSELECT_HIGHEST_PRIORITY_TASK(); + traceTASK_SWITCHED_IN(); + + #if ( configUSE_NEWLIB_REENTRANT == 1 ) + { + /* Switch Newlib's _impure_ptr variable to point to the _reent + structure specific to this task. */ + _impure_ptr = &( pxCurrentTCB->xNewLib_reent ); + } + #endif /* configUSE_NEWLIB_REENTRANT */ + } +} +/*-----------------------------------------------------------*/ + +void vTaskPlaceOnEventList( List_t * const pxEventList, const TickType_t xTicksToWait ) +{ + configASSERT( pxEventList ); + + /* THIS FUNCTION MUST BE CALLED WITH EITHER INTERRUPTS DISABLED OR THE + SCHEDULER SUSPENDED AND THE QUEUE BEING ACCESSED LOCKED. */ + + /* Place the event list item of the TCB in the appropriate event list. + This is placed in the list in priority order so the highest priority task + is the first to be woken by the event. The queue that contains the event + list is locked, preventing simultaneous access from interrupts. */ + vListInsert( pxEventList, &( pxCurrentTCB->xEventListItem ) ); + + prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE ); +} +/*-----------------------------------------------------------*/ + +void vTaskPlaceOnUnorderedEventList( List_t * pxEventList, const TickType_t xItemValue, const TickType_t xTicksToWait ) +{ + configASSERT( pxEventList ); + + /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. It is used by + the event groups implementation. */ + configASSERT( uxSchedulerSuspended != 0 ); + + /* Store the item value in the event list item. It is safe to access the + event list item here as interrupts won't access the event list item of a + task that is not in the Blocked state. */ + listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ), xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE ); + + /* Place the event list item of the TCB at the end of the appropriate event + list. It is safe to access the event list here because it is part of an + event group implementation - and interrupts don't access event groups + directly (instead they access them indirectly by pending function calls to + the task level). */ + vListInsertEnd( pxEventList, &( pxCurrentTCB->xEventListItem ) ); + + prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE ); +} +/*-----------------------------------------------------------*/ + +#if( configUSE_TIMERS == 1 ) + + void vTaskPlaceOnEventListRestricted( List_t * const pxEventList, TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely ) + { + configASSERT( pxEventList ); + + /* This function should not be called by application code hence the + 'Restricted' in its name. It is not part of the public API. It is + designed for use by kernel code, and has special calling requirements - + it should be called with the scheduler suspended. */ + + + /* Place the event list item of the TCB in the appropriate event list. + In this case it is assume that this is the only task that is going to + be waiting on this event list, so the faster vListInsertEnd() function + can be used in place of vListInsert. */ + vListInsertEnd( pxEventList, &( pxCurrentTCB->xEventListItem ) ); + + /* If the task should block indefinitely then set the block time to a + value that will be recognised as an indefinite delay inside the + prvAddCurrentTaskToDelayedList() function. */ + if( xWaitIndefinitely != pdFALSE ) + { + xTicksToWait = portMAX_DELAY; + } + + traceTASK_DELAY_UNTIL( ( xTickCount + xTicksToWait ) ); + prvAddCurrentTaskToDelayedList( xTicksToWait, xWaitIndefinitely ); + } + +#endif /* configUSE_TIMERS */ +/*-----------------------------------------------------------*/ + +BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList ) +{ +TCB_t *pxUnblockedTCB; +BaseType_t xReturn; + + /* THIS FUNCTION MUST BE CALLED FROM A CRITICAL SECTION. It can also be + called from a critical section within an ISR. */ + + /* The event list is sorted in priority order, so the first in the list can + be removed as it is known to be the highest priority. Remove the TCB from + the delayed list, and add it to the ready list. + + If an event is for a queue that is locked then this function will never + get called - the lock count on the queue will get modified instead. This + means exclusive access to the event list is guaranteed here. + + This function assumes that a check has already been made to ensure that + pxEventList is not empty. */ + pxUnblockedTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList ); + configASSERT( pxUnblockedTCB ); + ( void ) uxListRemove( &( pxUnblockedTCB->xEventListItem ) ); + + if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) + { + ( void ) uxListRemove( &( pxUnblockedTCB->xStateListItem ) ); + prvAddTaskToReadyList( pxUnblockedTCB ); + } + else + { + /* The delayed and ready lists cannot be accessed, so hold this task + pending until the scheduler is resumed. */ + vListInsertEnd( &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) ); + } + + if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority ) + { + /* Return true if the task removed from the event list has a higher + priority than the calling task. This allows the calling task to know if + it should force a context switch now. */ + xReturn = pdTRUE; + + /* Mark that a yield is pending in case the user is not using the + "xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */ + xYieldPending = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + + #if( configUSE_TICKLESS_IDLE != 0 ) + { + /* If a task is blocked on a kernel object then xNextTaskUnblockTime + might be set to the blocked task's time out time. If the task is + unblocked for a reason other than a timeout xNextTaskUnblockTime is + normally left unchanged, because it is automatically reset to a new + value when the tick count equals xNextTaskUnblockTime. However if + tickless idling is used it might be more important to enter sleep mode + at the earliest possible time - so reset xNextTaskUnblockTime here to + ensure it is updated at the earliest possible time. */ + prvResetNextTaskUnblockTime(); + } + #endif + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t xTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, const TickType_t xItemValue ) +{ +TCB_t *pxUnblockedTCB; +BaseType_t xReturn; + + /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. It is used by + the event flags implementation. */ + configASSERT( uxSchedulerSuspended != pdFALSE ); + + /* Store the new item value in the event list. */ + listSET_LIST_ITEM_VALUE( pxEventListItem, xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE ); + + /* Remove the event list form the event flag. Interrupts do not access + event flags. */ + pxUnblockedTCB = ( TCB_t * ) listGET_LIST_ITEM_OWNER( pxEventListItem ); + configASSERT( pxUnblockedTCB ); + ( void ) uxListRemove( pxEventListItem ); + + /* Remove the task from the delayed list and add it to the ready list. The + scheduler is suspended so interrupts will not be accessing the ready + lists. */ + ( void ) uxListRemove( &( pxUnblockedTCB->xStateListItem ) ); + prvAddTaskToReadyList( pxUnblockedTCB ); + + if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority ) + { + /* Return true if the task removed from the event list has + a higher priority than the calling task. This allows + the calling task to know if it should force a context + switch now. */ + xReturn = pdTRUE; + + /* Mark that a yield is pending in case the user is not using the + "xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */ + xYieldPending = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +void vTaskSetTimeOutState( TimeOut_t * const pxTimeOut ) +{ + configASSERT( pxTimeOut ); + pxTimeOut->xOverflowCount = xNumOfOverflows; + pxTimeOut->xTimeOnEntering = xTickCount; +} +/*-----------------------------------------------------------*/ + +BaseType_t xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut, TickType_t * const pxTicksToWait ) +{ +BaseType_t xReturn; + + configASSERT( pxTimeOut ); + configASSERT( pxTicksToWait ); + + taskENTER_CRITICAL(); + { + /* Minor optimisation. The tick count cannot change in this block. */ + const TickType_t xConstTickCount = xTickCount; + + #if( INCLUDE_xTaskAbortDelay == 1 ) + if( pxCurrentTCB->ucDelayAborted != pdFALSE ) + { + /* The delay was aborted, which is not the same as a time out, + but has the same result. */ + pxCurrentTCB->ucDelayAborted = pdFALSE; + xReturn = pdTRUE; + } + else + #endif + + #if ( INCLUDE_vTaskSuspend == 1 ) + if( *pxTicksToWait == portMAX_DELAY ) + { + /* If INCLUDE_vTaskSuspend is set to 1 and the block time + specified is the maximum block time then the task should block + indefinitely, and therefore never time out. */ + xReturn = pdFALSE; + } + else + #endif + + if( ( xNumOfOverflows != pxTimeOut->xOverflowCount ) && ( xConstTickCount >= pxTimeOut->xTimeOnEntering ) ) /*lint !e525 Indentation preferred as is to make code within pre-processor directives clearer. */ + { + /* The tick count is greater than the time at which + vTaskSetTimeout() was called, but has also overflowed since + vTaskSetTimeOut() was called. It must have wrapped all the way + around and gone past again. This passed since vTaskSetTimeout() + was called. */ + xReturn = pdTRUE; + } + else if( ( ( TickType_t ) ( xConstTickCount - pxTimeOut->xTimeOnEntering ) ) < *pxTicksToWait ) /*lint !e961 Explicit casting is only redundant with some compilers, whereas others require it to prevent integer conversion errors. */ + { + /* Not a genuine timeout. Adjust parameters for time remaining. */ + *pxTicksToWait -= ( xConstTickCount - pxTimeOut->xTimeOnEntering ); + vTaskSetTimeOutState( pxTimeOut ); + xReturn = pdFALSE; + } + else + { + xReturn = pdTRUE; + } + } + taskEXIT_CRITICAL(); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +void vTaskMissedYield( void ) +{ + xYieldPending = pdTRUE; +} +/*-----------------------------------------------------------*/ + +#if ( configUSE_TRACE_FACILITY == 1 ) + + UBaseType_t uxTaskGetTaskNumber( TaskHandle_t xTask ) + { + UBaseType_t uxReturn; + TCB_t *pxTCB; + + if( xTask != NULL ) + { + pxTCB = ( TCB_t * ) xTask; + uxReturn = pxTCB->uxTaskNumber; + } + else + { + uxReturn = 0U; + } + + return uxReturn; + } + +#endif /* configUSE_TRACE_FACILITY */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_TRACE_FACILITY == 1 ) + + void vTaskSetTaskNumber( TaskHandle_t xTask, const UBaseType_t uxHandle ) + { + TCB_t *pxTCB; + + if( xTask != NULL ) + { + pxTCB = ( TCB_t * ) xTask; + pxTCB->uxTaskNumber = uxHandle; + } + } + +#endif /* configUSE_TRACE_FACILITY */ + +/* + * ----------------------------------------------------------- + * The Idle task. + * ---------------------------------------------------------- + * + * The portTASK_FUNCTION() macro is used to allow port/compiler specific + * language extensions. The equivalent prototype for this function is: + * + * void prvIdleTask( void *pvParameters ); + * + */ +static portTASK_FUNCTION( prvIdleTask, pvParameters ) +{ + /* Stop warnings. */ + ( void ) pvParameters; + + /** THIS IS THE RTOS IDLE TASK - WHICH IS CREATED AUTOMATICALLY WHEN THE + SCHEDULER IS STARTED. **/ + + for( ;; ) + { + /* See if any tasks have deleted themselves - if so then the idle task + is responsible for freeing the deleted task's TCB and stack. */ + prvCheckTasksWaitingTermination(); + + #if ( configUSE_PREEMPTION == 0 ) + { + /* If we are not using preemption we keep forcing a task switch to + see if any other task has become available. If we are using + preemption we don't need to do this as any task becoming available + will automatically get the processor anyway. */ + taskYIELD(); + } + #endif /* configUSE_PREEMPTION */ + + #if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) + { + /* When using preemption tasks of equal priority will be + timesliced. If a task that is sharing the idle priority is ready + to run then the idle task should yield before the end of the + timeslice. + + A critical region is not required here as we are just reading from + the list, and an occasional incorrect value will not matter. If + the ready list at the idle priority contains more than one task + then a task other than the idle task is ready to execute. */ + if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( UBaseType_t ) 1 ) + { + taskYIELD(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) */ + + #if ( configUSE_IDLE_HOOK == 1 ) + { + extern void vApplicationIdleHook( void ); + + /* Call the user defined function from within the idle task. This + allows the application designer to add background functionality + without the overhead of a separate task. + NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES, + CALL A FUNCTION THAT MIGHT BLOCK. */ + vApplicationIdleHook(); + } + #endif /* configUSE_IDLE_HOOK */ + + /* This conditional compilation should use inequality to 0, not equality + to 1. This is to ensure portSUPPRESS_TICKS_AND_SLEEP() is called when + user defined low power mode implementations require + configUSE_TICKLESS_IDLE to be set to a value other than 1. */ + #if ( configUSE_TICKLESS_IDLE != 0 ) + { + TickType_t xExpectedIdleTime; + + /* It is not desirable to suspend then resume the scheduler on + each iteration of the idle task. Therefore, a preliminary + test of the expected idle time is performed without the + scheduler suspended. The result here is not necessarily + valid. */ + xExpectedIdleTime = prvGetExpectedIdleTime(); + + if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP ) + { + vTaskSuspendAll(); + { + /* Now the scheduler is suspended, the expected idle + time can be sampled again, and this time its value can + be used. */ + configASSERT( xNextTaskUnblockTime >= xTickCount ); + xExpectedIdleTime = prvGetExpectedIdleTime(); + + if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP ) + { + traceLOW_POWER_IDLE_BEGIN(); + portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ); + traceLOW_POWER_IDLE_END(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + ( void ) xTaskResumeAll(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configUSE_TICKLESS_IDLE */ + } +} +/*-----------------------------------------------------------*/ + +#if( configUSE_TICKLESS_IDLE != 0 ) + + eSleepModeStatus eTaskConfirmSleepModeStatus( void ) + { + /* The idle task exists in addition to the application tasks. */ + const UBaseType_t uxNonApplicationTasks = 1; + eSleepModeStatus eReturn = eStandardSleep; + + if( listCURRENT_LIST_LENGTH( &xPendingReadyList ) != 0 ) + { + /* A task was made ready while the scheduler was suspended. */ + eReturn = eAbortSleep; + } + else if( xYieldPending != pdFALSE ) + { + /* A yield was pended while the scheduler was suspended. */ + eReturn = eAbortSleep; + } + else + { + /* If all the tasks are in the suspended list (which might mean they + have an infinite block time rather than actually being suspended) + then it is safe to turn all clocks off and just wait for external + interrupts. */ + if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == ( uxCurrentNumberOfTasks - uxNonApplicationTasks ) ) + { + eReturn = eNoTasksWaitingTimeout; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + + return eReturn; + } + +#endif /* configUSE_TICKLESS_IDLE */ +/*-----------------------------------------------------------*/ + +#if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 ) + + void vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet, BaseType_t xIndex, void *pvValue ) + { + TCB_t *pxTCB; + + if( xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS ) + { + pxTCB = prvGetTCBFromHandle( xTaskToSet ); + pxTCB->pvThreadLocalStoragePointers[ xIndex ] = pvValue; + } + } + +#endif /* configNUM_THREAD_LOCAL_STORAGE_POINTERS */ +/*-----------------------------------------------------------*/ + +#if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 ) + + void *pvTaskGetThreadLocalStoragePointer( TaskHandle_t xTaskToQuery, BaseType_t xIndex ) + { + void *pvReturn = NULL; + TCB_t *pxTCB; + + if( xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS ) + { + pxTCB = prvGetTCBFromHandle( xTaskToQuery ); + pvReturn = pxTCB->pvThreadLocalStoragePointers[ xIndex ]; + } + else + { + pvReturn = NULL; + } + + return pvReturn; + } + +#endif /* configNUM_THREAD_LOCAL_STORAGE_POINTERS */ +/*-----------------------------------------------------------*/ + +#if ( portUSING_MPU_WRAPPERS == 1 ) + + void vTaskAllocateMPURegions( TaskHandle_t xTaskToModify, const MemoryRegion_t * const xRegions ) + { + TCB_t *pxTCB; + + /* If null is passed in here then we are modifying the MPU settings of + the calling task. */ + pxTCB = prvGetTCBFromHandle( xTaskToModify ); + + vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, NULL, 0 ); + } + +#endif /* portUSING_MPU_WRAPPERS */ +/*-----------------------------------------------------------*/ + +static void prvInitialiseTaskLists( void ) +{ +UBaseType_t uxPriority; + + for( uxPriority = ( UBaseType_t ) 0U; uxPriority < ( UBaseType_t ) configMAX_PRIORITIES; uxPriority++ ) + { + vListInitialise( &( pxReadyTasksLists[ uxPriority ] ) ); + } + + vListInitialise( &xDelayedTaskList1 ); + vListInitialise( &xDelayedTaskList2 ); + vListInitialise( &xPendingReadyList ); + + #if ( INCLUDE_vTaskDelete == 1 ) + { + vListInitialise( &xTasksWaitingTermination ); + } + #endif /* INCLUDE_vTaskDelete */ + + #if ( INCLUDE_vTaskSuspend == 1 ) + { + vListInitialise( &xSuspendedTaskList ); + } + #endif /* INCLUDE_vTaskSuspend */ + + /* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList + using list2. */ + pxDelayedTaskList = &xDelayedTaskList1; + pxOverflowDelayedTaskList = &xDelayedTaskList2; +} +/*-----------------------------------------------------------*/ + +static void prvCheckTasksWaitingTermination( void ) +{ + + /** THIS FUNCTION IS CALLED FROM THE RTOS IDLE TASK **/ + + #if ( INCLUDE_vTaskDelete == 1 ) + { + BaseType_t xListIsEmpty; + + /* ucTasksDeleted is used to prevent vTaskSuspendAll() being called + too often in the idle task. */ + while( uxDeletedTasksWaitingCleanUp > ( UBaseType_t ) 0U ) + { + vTaskSuspendAll(); + { + xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination ); + } + ( void ) xTaskResumeAll(); + + if( xListIsEmpty == pdFALSE ) + { + TCB_t *pxTCB; + + taskENTER_CRITICAL(); + { + pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) ); + ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); + --uxCurrentNumberOfTasks; + --uxDeletedTasksWaitingCleanUp; + } + taskEXIT_CRITICAL(); + + prvDeleteTCB( pxTCB ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + } + #endif /* INCLUDE_vTaskDelete */ +} +/*-----------------------------------------------------------*/ + +#if( configUSE_TRACE_FACILITY == 1 ) + + void vTaskGetInfo( TaskHandle_t xTask, TaskStatus_t *pxTaskStatus, BaseType_t xGetFreeStackSpace, eTaskState eState ) + { + TCB_t *pxTCB; + + /* xTask is NULL then get the state of the calling task. */ + pxTCB = prvGetTCBFromHandle( xTask ); + + pxTaskStatus->xHandle = ( TaskHandle_t ) pxTCB; + pxTaskStatus->pcTaskName = ( const char * ) &( pxTCB->pcTaskName [ 0 ] ); + pxTaskStatus->uxCurrentPriority = pxTCB->uxPriority; + pxTaskStatus->pxStackBase = pxTCB->pxStack; + pxTaskStatus->xTaskNumber = pxTCB->uxTCBNumber; + + #if ( INCLUDE_vTaskSuspend == 1 ) + { + /* If the task is in the suspended list then there is a chance it is + actually just blocked indefinitely - so really it should be reported as + being in the Blocked state. */ + if( pxTaskStatus->eCurrentState == eSuspended ) + { + vTaskSuspendAll(); + { + if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) + { + pxTaskStatus->eCurrentState = eBlocked; + } + } + xTaskResumeAll(); + } + } + #endif /* INCLUDE_vTaskSuspend */ + + #if ( configUSE_MUTEXES == 1 ) + { + pxTaskStatus->uxBasePriority = pxTCB->uxBasePriority; + } + #else + { + pxTaskStatus->uxBasePriority = 0; + } + #endif + + #if ( configGENERATE_RUN_TIME_STATS == 1 ) + { + pxTaskStatus->ulRunTimeCounter = pxTCB->ulRunTimeCounter; + } + #else + { + pxTaskStatus->ulRunTimeCounter = 0; + } + #endif + + /* Obtaining the task state is a little fiddly, so is only done if the value + of eState passed into this function is eInvalid - otherwise the state is + just set to whatever is passed in. */ + if( eState != eInvalid ) + { + pxTaskStatus->eCurrentState = eState; + } + else + { + pxTaskStatus->eCurrentState = eTaskGetState( xTask ); + } + + /* Obtaining the stack space takes some time, so the xGetFreeStackSpace + parameter is provided to allow it to be skipped. */ + if( xGetFreeStackSpace != pdFALSE ) + { + #if ( portSTACK_GROWTH > 0 ) + { + pxTaskStatus->usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( uint8_t * ) pxTCB->pxEndOfStack ); + } + #else + { + pxTaskStatus->usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( uint8_t * ) pxTCB->pxStack ); + } + #endif + } + else + { + pxTaskStatus->usStackHighWaterMark = 0; + } + } + +#endif /* configUSE_TRACE_FACILITY */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_TRACE_FACILITY == 1 ) + + static UBaseType_t prvListTasksWithinSingleList( TaskStatus_t *pxTaskStatusArray, List_t *pxList, eTaskState eState ) + { + volatile TCB_t *pxNextTCB, *pxFirstTCB; + UBaseType_t uxTask = 0; + + if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 ) + { + listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList ); + + /* Populate an TaskStatus_t structure within the + pxTaskStatusArray array for each task that is referenced from + pxList. See the definition of TaskStatus_t in task.h for the + meaning of each TaskStatus_t structure member. */ + do + { + listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList ); + vTaskGetInfo( ( TaskHandle_t ) pxNextTCB, &( pxTaskStatusArray[ uxTask ] ), pdTRUE, eState ); + uxTask++; + } while( pxNextTCB != pxFirstTCB ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + return uxTask; + } + +#endif /* configUSE_TRACE_FACILITY */ +/*-----------------------------------------------------------*/ + +#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) + + static uint16_t prvTaskCheckFreeStackSpace( const uint8_t * pucStackByte ) + { + uint32_t ulCount = 0U; + + while( *pucStackByte == ( uint8_t ) tskSTACK_FILL_BYTE ) + { + pucStackByte -= portSTACK_GROWTH; + ulCount++; + } + + ulCount /= ( uint32_t ) sizeof( StackType_t ); /*lint !e961 Casting is not redundant on smaller architectures. */ + + return ( uint16_t ) ulCount; + } + +#endif /* ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) + + UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask ) + { + TCB_t *pxTCB; + uint8_t *pucEndOfStack; + UBaseType_t uxReturn; + + pxTCB = prvGetTCBFromHandle( xTask ); + + #if portSTACK_GROWTH < 0 + { + pucEndOfStack = ( uint8_t * ) pxTCB->pxStack; + } + #else + { + pucEndOfStack = ( uint8_t * ) pxTCB->pxEndOfStack; + } + #endif + + uxReturn = ( UBaseType_t ) prvTaskCheckFreeStackSpace( pucEndOfStack ); + + return uxReturn; + } + +#endif /* INCLUDE_uxTaskGetStackHighWaterMark */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_vTaskDelete == 1 ) + + static void prvDeleteTCB( TCB_t *pxTCB ) + { + /* This call is required specifically for the TriCore port. It must be + above the vPortFree() calls. The call is also used by ports/demos that + want to allocate and clean RAM statically. */ + portCLEAN_UP_TCB( pxTCB ); + + /* Free up the memory allocated by the scheduler for the task. It is up + to the task to free any memory allocated at the application level. */ + #if ( configUSE_NEWLIB_REENTRANT == 1 ) + { + _reclaim_reent( &( pxTCB->xNewLib_reent ) ); + } + #endif /* configUSE_NEWLIB_REENTRANT */ + + #if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) && ( portUSING_MPU_WRAPPERS == 0 ) ) + { + /* The task can only have been allocated dynamically - free both + the stack and TCB. */ + vPortFree( pxTCB->pxStack ); + vPortFree( pxTCB ); + } + #elif( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE == 1 ) + { + /* The task could have been allocated statically or dynamically, so + check what was statically allocated before trying to free the + memory. */ + if( pxTCB->ucStaticallyAllocated == tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB ) + { + /* Both the stack and TCB were allocated dynamically, so both + must be freed. */ + vPortFree( pxTCB->pxStack ); + vPortFree( pxTCB ); + } + else if( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_ONLY ) + { + /* Only the stack was statically allocated, so the TCB is the + only memory that must be freed. */ + vPortFree( pxTCB ); + } + else + { + /* Neither the stack nor the TCB were allocated dynamically, so + nothing needs to be freed. */ + configASSERT( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_AND_TCB ) + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ + } + +#endif /* INCLUDE_vTaskDelete */ +/*-----------------------------------------------------------*/ + +static void prvResetNextTaskUnblockTime( void ) +{ +TCB_t *pxTCB; + + if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) + { + /* The new current delayed list is empty. Set xNextTaskUnblockTime to + the maximum possible value so it is extremely unlikely that the + if( xTickCount >= xNextTaskUnblockTime ) test will pass until + there is an item in the delayed list. */ + xNextTaskUnblockTime = portMAX_DELAY; + } + else + { + /* The new current delayed list is not empty, get the value of + the item at the head of the delayed list. This is the time at + which the task at the head of the delayed list should be removed + from the Blocked state. */ + ( pxTCB ) = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); + xNextTaskUnblockTime = listGET_LIST_ITEM_VALUE( &( ( pxTCB )->xStateListItem ) ); + } +} +/*-----------------------------------------------------------*/ + +#if ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) + + TaskHandle_t xTaskGetCurrentTaskHandle( void ) + { + TaskHandle_t xReturn; + + /* A critical section is not required as this is not called from + an interrupt and the current TCB will always be the same for any + individual execution thread. */ + xReturn = pxCurrentTCB; + + return xReturn; + } + +#endif /* ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) */ +/*-----------------------------------------------------------*/ + +#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) + + BaseType_t xTaskGetSchedulerState( void ) + { + BaseType_t xReturn; + + if( xSchedulerRunning == pdFALSE ) + { + xReturn = taskSCHEDULER_NOT_STARTED; + } + else + { + if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) + { + xReturn = taskSCHEDULER_RUNNING; + } + else + { + xReturn = taskSCHEDULER_SUSPENDED; + } + } + + return xReturn; + } + +#endif /* ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_MUTEXES == 1 ) + + void vTaskPriorityInherit( TaskHandle_t const pxMutexHolder ) + { + TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder; + + /* If the mutex was given back by an interrupt while the queue was + locked then the mutex holder might now be NULL. */ + if( pxMutexHolder != NULL ) + { + /* If the holder of the mutex has a priority below the priority of + the task attempting to obtain the mutex then it will temporarily + inherit the priority of the task attempting to obtain the mutex. */ + if( pxTCB->uxPriority < pxCurrentTCB->uxPriority ) + { + /* Adjust the mutex holder state to account for its new + priority. Only reset the event list item value if the value is + not being used for anything else. */ + if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL ) + { + listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* If the task being modified is in the ready state it will need + to be moved into a new list. */ + if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xStateListItem ) ) != pdFALSE ) + { + if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) + { + taskRESET_READY_PRIORITY( pxTCB->uxPriority ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Inherit the priority before being moved into the new list. */ + pxTCB->uxPriority = pxCurrentTCB->uxPriority; + prvAddTaskToReadyList( pxTCB ); + } + else + { + /* Just inherit the priority. */ + pxTCB->uxPriority = pxCurrentTCB->uxPriority; + } + + traceTASK_PRIORITY_INHERIT( pxTCB, pxCurrentTCB->uxPriority ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + +#endif /* configUSE_MUTEXES */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_MUTEXES == 1 ) + + BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder ) + { + TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder; + BaseType_t xReturn = pdFALSE; + + if( pxMutexHolder != NULL ) + { + /* A task can only have an inherited priority if it holds the mutex. + If the mutex is held by a task then it cannot be given from an + interrupt, and if a mutex is given by the holding task then it must + be the running state task. */ + configASSERT( pxTCB == pxCurrentTCB ); + + configASSERT( pxTCB->uxMutexesHeld ); + ( pxTCB->uxMutexesHeld )--; + + /* Has the holder of the mutex inherited the priority of another + task? */ + if( pxTCB->uxPriority != pxTCB->uxBasePriority ) + { + /* Only disinherit if no other mutexes are held. */ + if( pxTCB->uxMutexesHeld == ( UBaseType_t ) 0 ) + { + /* A task can only have an inherited priority if it holds + the mutex. If the mutex is held by a task then it cannot be + given from an interrupt, and if a mutex is given by the + holding task then it must be the running state task. Remove + the holding task from the ready list. */ + if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) + { + taskRESET_READY_PRIORITY( pxTCB->uxPriority ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Disinherit the priority before adding the task into the + new ready list. */ + traceTASK_PRIORITY_DISINHERIT( pxTCB, pxTCB->uxBasePriority ); + pxTCB->uxPriority = pxTCB->uxBasePriority; + + /* Reset the event list item value. It cannot be in use for + any other purpose if this task is running, and it must be + running to give back the mutex. */ + listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + prvAddTaskToReadyList( pxTCB ); + + /* Return true to indicate that a context switch is required. + This is only actually required in the corner case whereby + multiple mutexes were held and the mutexes were given back + in an order different to that in which they were taken. + If a context switch did not occur when the first mutex was + returned, even if a task was waiting on it, then a context + switch should occur when the last mutex is returned whether + a task is waiting on it or not. */ + xReturn = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + return xReturn; + } + +#endif /* configUSE_MUTEXES */ +/*-----------------------------------------------------------*/ + +#if ( portCRITICAL_NESTING_IN_TCB == 1 ) + + void vTaskEnterCritical( void ) + { + portDISABLE_INTERRUPTS(); + + if( xSchedulerRunning != pdFALSE ) + { + ( pxCurrentTCB->uxCriticalNesting )++; + + /* This is not the interrupt safe version of the enter critical + function so assert() if it is being called from an interrupt + context. Only API functions that end in "FromISR" can be used in an + interrupt. Only assert if the critical nesting count is 1 to + protect against recursive calls if the assert function also uses a + critical section. */ + if( pxCurrentTCB->uxCriticalNesting == 1 ) + { + portASSERT_IF_IN_ISR(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + +#endif /* portCRITICAL_NESTING_IN_TCB */ +/*-----------------------------------------------------------*/ + +#if ( portCRITICAL_NESTING_IN_TCB == 1 ) + + void vTaskExitCritical( void ) + { + if( xSchedulerRunning != pdFALSE ) + { + if( pxCurrentTCB->uxCriticalNesting > 0U ) + { + ( pxCurrentTCB->uxCriticalNesting )--; + + if( pxCurrentTCB->uxCriticalNesting == 0U ) + { + portENABLE_INTERRUPTS(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + +#endif /* portCRITICAL_NESTING_IN_TCB */ +/*-----------------------------------------------------------*/ + +#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) + + static char *prvWriteNameToBuffer( char *pcBuffer, const char *pcTaskName ) + { + size_t x; + + /* Start by copying the entire string. */ + strcpy( pcBuffer, pcTaskName ); + + /* Pad the end of the string with spaces to ensure columns line up when + printed out. */ + for( x = strlen( pcBuffer ); x < ( size_t ) ( configMAX_TASK_NAME_LEN - 1 ); x++ ) + { + pcBuffer[ x ] = ' '; + } + + /* Terminate. */ + pcBuffer[ x ] = 0x00; + + /* Return the new end of string. */ + return &( pcBuffer[ x ] ); + } + +#endif /* ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) */ +/*-----------------------------------------------------------*/ + +#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) + + void vTaskList( char * pcWriteBuffer ) + { + TaskStatus_t *pxTaskStatusArray; + volatile UBaseType_t uxArraySize, x; + char cStatus; + + /* + * PLEASE NOTE: + * + * This function is provided for convenience only, and is used by many + * of the demo applications. Do not consider it to be part of the + * scheduler. + * + * vTaskList() calls uxTaskGetSystemState(), then formats part of the + * uxTaskGetSystemState() output into a human readable table that + * displays task names, states and stack usage. + * + * vTaskList() has a dependency on the sprintf() C library function that + * might bloat the code size, use a lot of stack, and provide different + * results on different platforms. An alternative, tiny, third party, + * and limited functionality implementation of sprintf() is provided in + * many of the FreeRTOS/Demo sub-directories in a file called + * printf-stdarg.c (note printf-stdarg.c does not provide a full + * snprintf() implementation!). + * + * It is recommended that production systems call uxTaskGetSystemState() + * directly to get access to raw stats data, rather than indirectly + * through a call to vTaskList(). + */ + + + /* Make sure the write buffer does not contain a string. */ + *pcWriteBuffer = 0x00; + + /* Take a snapshot of the number of tasks in case it changes while this + function is executing. */ + uxArraySize = uxCurrentNumberOfTasks; + + /* Allocate an array index for each task. NOTE! if + configSUPPORT_DYNAMIC_ALLOCATION is set to 0 then pvPortMalloc() will + equate to NULL. */ + pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( TaskStatus_t ) ); + + if( pxTaskStatusArray != NULL ) + { + /* Generate the (binary) data. */ + uxArraySize = uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, NULL ); + + /* Create a human readable table from the binary data. */ + for( x = 0; x < uxArraySize; x++ ) + { + switch( pxTaskStatusArray[ x ].eCurrentState ) + { + case eReady: cStatus = tskREADY_CHAR; + break; + + case eBlocked: cStatus = tskBLOCKED_CHAR; + break; + + case eSuspended: cStatus = tskSUSPENDED_CHAR; + break; + + case eDeleted: cStatus = tskDELETED_CHAR; + break; + + default: /* Should not get here, but it is included + to prevent static checking errors. */ + cStatus = 0x00; + break; + } + + /* Write the task name to the string, padding with spaces so it + can be printed in tabular form more easily. */ + pcWriteBuffer = prvWriteNameToBuffer( pcWriteBuffer, pxTaskStatusArray[ x ].pcTaskName ); + + /* Write the rest of the string. */ + sprintf( pcWriteBuffer, "\t%c\t%u\t%u\t%u\r\n", cStatus, ( unsigned int ) pxTaskStatusArray[ x ].uxCurrentPriority, ( unsigned int ) pxTaskStatusArray[ x ].usStackHighWaterMark, ( unsigned int ) pxTaskStatusArray[ x ].xTaskNumber ); + pcWriteBuffer += strlen( pcWriteBuffer ); + } + + /* Free the array again. NOTE! If configSUPPORT_DYNAMIC_ALLOCATION + is 0 then vPortFree() will be #defined to nothing. */ + vPortFree( pxTaskStatusArray ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + +#endif /* ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */ +/*----------------------------------------------------------*/ + +#if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) + + void vTaskGetRunTimeStats( char *pcWriteBuffer ) + { + TaskStatus_t *pxTaskStatusArray; + volatile UBaseType_t uxArraySize, x; + uint32_t ulTotalTime, ulStatsAsPercentage; + + #if( configUSE_TRACE_FACILITY != 1 ) + { + #error configUSE_TRACE_FACILITY must also be set to 1 in FreeRTOSConfig.h to use vTaskGetRunTimeStats(). + } + #endif + + /* + * PLEASE NOTE: + * + * This function is provided for convenience only, and is used by many + * of the demo applications. Do not consider it to be part of the + * scheduler. + * + * vTaskGetRunTimeStats() calls uxTaskGetSystemState(), then formats part + * of the uxTaskGetSystemState() output into a human readable table that + * displays the amount of time each task has spent in the Running state + * in both absolute and percentage terms. + * + * vTaskGetRunTimeStats() has a dependency on the sprintf() C library + * function that might bloat the code size, use a lot of stack, and + * provide different results on different platforms. An alternative, + * tiny, third party, and limited functionality implementation of + * sprintf() is provided in many of the FreeRTOS/Demo sub-directories in + * a file called printf-stdarg.c (note printf-stdarg.c does not provide + * a full snprintf() implementation!). + * + * It is recommended that production systems call uxTaskGetSystemState() + * directly to get access to raw stats data, rather than indirectly + * through a call to vTaskGetRunTimeStats(). + */ + + /* Make sure the write buffer does not contain a string. */ + *pcWriteBuffer = 0x00; + + /* Take a snapshot of the number of tasks in case it changes while this + function is executing. */ + uxArraySize = uxCurrentNumberOfTasks; + + /* Allocate an array index for each task. NOTE! If + configSUPPORT_DYNAMIC_ALLOCATION is set to 0 then pvPortMalloc() will + equate to NULL. */ + pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( TaskStatus_t ) ); + + if( pxTaskStatusArray != NULL ) + { + /* Generate the (binary) data. */ + uxArraySize = uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, &ulTotalTime ); + + /* For percentage calculations. */ + ulTotalTime /= 100UL; + + /* Avoid divide by zero errors. */ + if( ulTotalTime > 0 ) + { + /* Create a human readable table from the binary data. */ + for( x = 0; x < uxArraySize; x++ ) + { + /* What percentage of the total run time has the task used? + This will always be rounded down to the nearest integer. + ulTotalRunTimeDiv100 has already been divided by 100. */ + ulStatsAsPercentage = pxTaskStatusArray[ x ].ulRunTimeCounter / ulTotalTime; + + /* Write the task name to the string, padding with + spaces so it can be printed in tabular form more + easily. */ + pcWriteBuffer = prvWriteNameToBuffer( pcWriteBuffer, pxTaskStatusArray[ x ].pcTaskName ); + + if( ulStatsAsPercentage > 0UL ) + { + #ifdef portLU_PRINTF_SPECIFIER_REQUIRED + { + sprintf( pcWriteBuffer, "\t%lu\t\t%lu%%\r\n", pxTaskStatusArray[ x ].ulRunTimeCounter, ulStatsAsPercentage ); + } + #else + { + /* sizeof( int ) == sizeof( long ) so a smaller + printf() library can be used. */ + sprintf( pcWriteBuffer, "\t%u\t\t%u%%\r\n", ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter, ( unsigned int ) ulStatsAsPercentage ); + } + #endif + } + else + { + /* If the percentage is zero here then the task has + consumed less than 1% of the total run time. */ + #ifdef portLU_PRINTF_SPECIFIER_REQUIRED + { + sprintf( pcWriteBuffer, "\t%lu\t\t<1%%\r\n", pxTaskStatusArray[ x ].ulRunTimeCounter ); + } + #else + { + /* sizeof( int ) == sizeof( long ) so a smaller + printf() library can be used. */ + sprintf( pcWriteBuffer, "\t%u\t\t<1%%\r\n", ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter ); + } + #endif + } + + pcWriteBuffer += strlen( pcWriteBuffer ); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Free the array again. NOTE! If configSUPPORT_DYNAMIC_ALLOCATION + is 0 then vPortFree() will be #defined to nothing. */ + vPortFree( pxTaskStatusArray ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + +#endif /* ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */ +/*-----------------------------------------------------------*/ + +TickType_t uxTaskResetEventItemValue( void ) +{ +TickType_t uxReturn; + + uxReturn = listGET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ) ); + + /* Reset the event list item to its normal value - so it can be used with + queues and semaphores. */ + listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ), ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCB->uxPriority ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + + return uxReturn; +} +/*-----------------------------------------------------------*/ + +#if ( configUSE_MUTEXES == 1 ) + + void *pvTaskIncrementMutexHeldCount( void ) + { + /* If xSemaphoreCreateMutex() is called before any tasks have been created + then pxCurrentTCB will be NULL. */ + if( pxCurrentTCB != NULL ) + { + ( pxCurrentTCB->uxMutexesHeld )++; + } + + return pxCurrentTCB; + } + +#endif /* configUSE_MUTEXES */ +/*-----------------------------------------------------------*/ + +#if( configUSE_TASK_NOTIFICATIONS == 1 ) + + uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait ) + { + uint32_t ulReturn; + + taskENTER_CRITICAL(); + { + /* Only block if the notification count is not already non-zero. */ + if( pxCurrentTCB->ulNotifiedValue == 0UL ) + { + /* Mark this task as waiting for a notification. */ + pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION; + + if( xTicksToWait > ( TickType_t ) 0 ) + { + prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE ); + traceTASK_NOTIFY_TAKE_BLOCK(); + + /* All ports are written to allow a yield in a critical + section (some will yield immediately, others wait until the + critical section exits) - but it is not something that + application code should ever do. */ + portYIELD_WITHIN_API(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); + + taskENTER_CRITICAL(); + { + traceTASK_NOTIFY_TAKE(); + ulReturn = pxCurrentTCB->ulNotifiedValue; + + if( ulReturn != 0UL ) + { + if( xClearCountOnExit != pdFALSE ) + { + pxCurrentTCB->ulNotifiedValue = 0UL; + } + else + { + pxCurrentTCB->ulNotifiedValue = ulReturn - 1; + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION; + } + taskEXIT_CRITICAL(); + + return ulReturn; + } + +#endif /* configUSE_TASK_NOTIFICATIONS */ +/*-----------------------------------------------------------*/ + +#if( configUSE_TASK_NOTIFICATIONS == 1 ) + + BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait ) + { + BaseType_t xReturn; + + taskENTER_CRITICAL(); + { + /* Only block if a notification is not already pending. */ + if( pxCurrentTCB->ucNotifyState != taskNOTIFICATION_RECEIVED ) + { + /* Clear bits in the task's notification value as bits may get + set by the notifying task or interrupt. This can be used to + clear the value to zero. */ + pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnEntry; + + /* Mark this task as waiting for a notification. */ + pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION; + + if( xTicksToWait > ( TickType_t ) 0 ) + { + prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE ); + traceTASK_NOTIFY_WAIT_BLOCK(); + + /* All ports are written to allow a yield in a critical + section (some will yield immediately, others wait until the + critical section exits) - but it is not something that + application code should ever do. */ + portYIELD_WITHIN_API(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); + + taskENTER_CRITICAL(); + { + traceTASK_NOTIFY_WAIT(); + + if( pulNotificationValue != NULL ) + { + /* Output the current notification value, which may or may not + have changed. */ + *pulNotificationValue = pxCurrentTCB->ulNotifiedValue; + } + + /* If ucNotifyValue is set then either the task never entered the + blocked state (because a notification was already pending) or the + task unblocked because of a notification. Otherwise the task + unblocked because of a timeout. */ + if( pxCurrentTCB->ucNotifyState == taskWAITING_NOTIFICATION ) + { + /* A notification was not received. */ + xReturn = pdFALSE; + } + else + { + /* A notification was already pending or a notification was + received while the task was waiting. */ + pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnExit; + xReturn = pdTRUE; + } + + pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION; + } + taskEXIT_CRITICAL(); + + return xReturn; + } + +#endif /* configUSE_TASK_NOTIFICATIONS */ +/*-----------------------------------------------------------*/ + +#if( configUSE_TASK_NOTIFICATIONS == 1 ) + + BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue ) + { + TCB_t * pxTCB; + BaseType_t xReturn = pdPASS; + uint8_t ucOriginalNotifyState; + + configASSERT( xTaskToNotify ); + pxTCB = ( TCB_t * ) xTaskToNotify; + + taskENTER_CRITICAL(); + { + if( pulPreviousNotificationValue != NULL ) + { + *pulPreviousNotificationValue = pxTCB->ulNotifiedValue; + } + + ucOriginalNotifyState = pxTCB->ucNotifyState; + + pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED; + + switch( eAction ) + { + case eSetBits : + pxTCB->ulNotifiedValue |= ulValue; + break; + + case eIncrement : + ( pxTCB->ulNotifiedValue )++; + break; + + case eSetValueWithOverwrite : + pxTCB->ulNotifiedValue = ulValue; + break; + + case eSetValueWithoutOverwrite : + if( ucOriginalNotifyState != taskNOTIFICATION_RECEIVED ) + { + pxTCB->ulNotifiedValue = ulValue; + } + else + { + /* The value could not be written to the task. */ + xReturn = pdFAIL; + } + break; + + case eNoAction: + /* The task is being notified without its notify value being + updated. */ + break; + } + + traceTASK_NOTIFY(); + + /* If the task is in the blocked state specifically to wait for a + notification then unblock it now. */ + if( ucOriginalNotifyState == taskWAITING_NOTIFICATION ) + { + ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); + prvAddTaskToReadyList( pxTCB ); + + /* The task should not have been on an event list. */ + configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL ); + + #if( configUSE_TICKLESS_IDLE != 0 ) + { + /* If a task is blocked waiting for a notification then + xNextTaskUnblockTime might be set to the blocked task's time + out time. If the task is unblocked for a reason other than + a timeout xNextTaskUnblockTime is normally left unchanged, + because it will automatically get reset to a new value when + the tick count equals xNextTaskUnblockTime. However if + tickless idling is used it might be more important to enter + sleep mode at the earliest possible time - so reset + xNextTaskUnblockTime here to ensure it is updated at the + earliest possible time. */ + prvResetNextTaskUnblockTime(); + } + #endif + + if( pxTCB->uxPriority > pxCurrentTCB->uxPriority ) + { + /* The notified task has a priority above the currently + executing task so a yield is required. */ + taskYIELD_IF_USING_PREEMPTION(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); + + return xReturn; + } + +#endif /* configUSE_TASK_NOTIFICATIONS */ +/*-----------------------------------------------------------*/ + +#if( configUSE_TASK_NOTIFICATIONS == 1 ) + + BaseType_t xTaskGenericNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue, BaseType_t *pxHigherPriorityTaskWoken ) + { + TCB_t * pxTCB; + uint8_t ucOriginalNotifyState; + BaseType_t xReturn = pdPASS; + UBaseType_t uxSavedInterruptStatus; + + configASSERT( xTaskToNotify ); + + /* RTOS ports that support interrupt nesting have the concept of a + maximum system call (or maximum API call) interrupt priority. + Interrupts that are above the maximum system call priority are keep + permanently enabled, even when the RTOS kernel is in a critical section, + but cannot make any calls to FreeRTOS API functions. If configASSERT() + is defined in FreeRTOSConfig.h then + portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has + been assigned a priority above the configured maximum system call + priority. Only FreeRTOS functions that end in FromISR can be called + from interrupts that have been assigned a priority at or (logically) + below the maximum system call interrupt priority. FreeRTOS maintains a + separate interrupt safe API to ensure interrupt entry is as fast and as + simple as possible. More information (albeit Cortex-M specific) is + provided on the following link: + http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + + pxTCB = ( TCB_t * ) xTaskToNotify; + + uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + { + if( pulPreviousNotificationValue != NULL ) + { + *pulPreviousNotificationValue = pxTCB->ulNotifiedValue; + } + + ucOriginalNotifyState = pxTCB->ucNotifyState; + pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED; + + switch( eAction ) + { + case eSetBits : + pxTCB->ulNotifiedValue |= ulValue; + break; + + case eIncrement : + ( pxTCB->ulNotifiedValue )++; + break; + + case eSetValueWithOverwrite : + pxTCB->ulNotifiedValue = ulValue; + break; + + case eSetValueWithoutOverwrite : + if( ucOriginalNotifyState != taskNOTIFICATION_RECEIVED ) + { + pxTCB->ulNotifiedValue = ulValue; + } + else + { + /* The value could not be written to the task. */ + xReturn = pdFAIL; + } + break; + + case eNoAction : + /* The task is being notified without its notify value being + updated. */ + break; + } + + traceTASK_NOTIFY_FROM_ISR(); + + /* If the task is in the blocked state specifically to wait for a + notification then unblock it now. */ + if( ucOriginalNotifyState == taskWAITING_NOTIFICATION ) + { + /* The task should not have been on an event list. */ + configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL ); + + if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) + { + ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); + prvAddTaskToReadyList( pxTCB ); + } + else + { + /* The delayed and ready lists cannot be accessed, so hold + this task pending until the scheduler is resumed. */ + vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) ); + } + + if( pxTCB->uxPriority > pxCurrentTCB->uxPriority ) + { + /* The notified task has a priority above the currently + executing task so a yield is required. */ + if( pxHigherPriorityTaskWoken != NULL ) + { + *pxHigherPriorityTaskWoken = pdTRUE; + } + else + { + /* Mark that a yield is pending in case the user is not + using the "xHigherPriorityTaskWoken" parameter to an ISR + safe FreeRTOS function. */ + xYieldPending = pdTRUE; + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + } + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + + return xReturn; + } + +#endif /* configUSE_TASK_NOTIFICATIONS */ +/*-----------------------------------------------------------*/ + +#if( configUSE_TASK_NOTIFICATIONS == 1 ) + + void vTaskNotifyGiveFromISR( TaskHandle_t xTaskToNotify, BaseType_t *pxHigherPriorityTaskWoken ) + { + TCB_t * pxTCB; + uint8_t ucOriginalNotifyState; + UBaseType_t uxSavedInterruptStatus; + + configASSERT( xTaskToNotify ); + + /* RTOS ports that support interrupt nesting have the concept of a + maximum system call (or maximum API call) interrupt priority. + Interrupts that are above the maximum system call priority are keep + permanently enabled, even when the RTOS kernel is in a critical section, + but cannot make any calls to FreeRTOS API functions. If configASSERT() + is defined in FreeRTOSConfig.h then + portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has + been assigned a priority above the configured maximum system call + priority. Only FreeRTOS functions that end in FromISR can be called + from interrupts that have been assigned a priority at or (logically) + below the maximum system call interrupt priority. FreeRTOS maintains a + separate interrupt safe API to ensure interrupt entry is as fast and as + simple as possible. More information (albeit Cortex-M specific) is + provided on the following link: + http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + + pxTCB = ( TCB_t * ) xTaskToNotify; + + uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + { + ucOriginalNotifyState = pxTCB->ucNotifyState; + pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED; + + /* 'Giving' is equivalent to incrementing a count in a counting + semaphore. */ + ( pxTCB->ulNotifiedValue )++; + + traceTASK_NOTIFY_GIVE_FROM_ISR(); + + /* If the task is in the blocked state specifically to wait for a + notification then unblock it now. */ + if( ucOriginalNotifyState == taskWAITING_NOTIFICATION ) + { + /* The task should not have been on an event list. */ + configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL ); + + if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) + { + ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); + prvAddTaskToReadyList( pxTCB ); + } + else + { + /* The delayed and ready lists cannot be accessed, so hold + this task pending until the scheduler is resumed. */ + vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) ); + } + + if( pxTCB->uxPriority > pxCurrentTCB->uxPriority ) + { + /* The notified task has a priority above the currently + executing task so a yield is required. */ + if( pxHigherPriorityTaskWoken != NULL ) + { + *pxHigherPriorityTaskWoken = pdTRUE; + } + else + { + /* Mark that a yield is pending in case the user is not + using the "xHigherPriorityTaskWoken" parameter in an ISR + safe FreeRTOS function. */ + xYieldPending = pdTRUE; + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + } + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + } + +#endif /* configUSE_TASK_NOTIFICATIONS */ + +/*-----------------------------------------------------------*/ + +#if( configUSE_TASK_NOTIFICATIONS == 1 ) + + BaseType_t xTaskNotifyStateClear( TaskHandle_t xTask ) + { + TCB_t *pxTCB; + BaseType_t xReturn; + + /* If null is passed in here then it is the calling task that is having + its notification state cleared. */ + pxTCB = prvGetTCBFromHandle( xTask ); + + taskENTER_CRITICAL(); + { + if( pxTCB->ucNotifyState == taskNOTIFICATION_RECEIVED ) + { + pxTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION; + xReturn = pdPASS; + } + else + { + xReturn = pdFAIL; + } + } + taskEXIT_CRITICAL(); + + return xReturn; + } + +#endif /* configUSE_TASK_NOTIFICATIONS */ +/*-----------------------------------------------------------*/ + + +static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, const BaseType_t xCanBlockIndefinitely ) +{ +TickType_t xTimeToWake; +const TickType_t xConstTickCount = xTickCount; + + #if( INCLUDE_xTaskAbortDelay == 1 ) + { + /* About to enter a delayed list, so ensure the ucDelayAborted flag is + reset to pdFALSE so it can be detected as having been set to pdTRUE + when the task leaves the Blocked state. */ + pxCurrentTCB->ucDelayAborted = pdFALSE; + } + #endif + + /* Remove the task from the ready list before adding it to the blocked list + as the same list item is used for both lists. */ + if( uxListRemove( &( pxCurrentTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) + { + /* The current task must be in a ready list, so there is no need to + check, and the port reset macro can be called directly. */ + portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + #if ( INCLUDE_vTaskSuspend == 1 ) + { + if( ( xTicksToWait == portMAX_DELAY ) && ( xCanBlockIndefinitely != pdFALSE ) ) + { + /* Add the task to the suspended task list instead of a delayed task + list to ensure it is not woken by a timing event. It will block + indefinitely. */ + vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xStateListItem ) ); + } + else + { + /* Calculate the time at which the task should be woken if the event + does not occur. This may overflow but this doesn't matter, the + kernel will manage it correctly. */ + xTimeToWake = xConstTickCount + xTicksToWait; + + /* The list item will be inserted in wake time order. */ + listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake ); + + if( xTimeToWake < xConstTickCount ) + { + /* Wake time has overflowed. Place this item in the overflow + list. */ + vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) ); + } + else + { + /* The wake time has not overflowed, so the current block list + is used. */ + vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) ); + + /* If the task entering the blocked state was placed at the + head of the list of blocked tasks then xNextTaskUnblockTime + needs to be updated too. */ + if( xTimeToWake < xNextTaskUnblockTime ) + { + xNextTaskUnblockTime = xTimeToWake; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + } + } + #else /* INCLUDE_vTaskSuspend */ + { + /* Calculate the time at which the task should be woken if the event + does not occur. This may overflow but this doesn't matter, the kernel + will manage it correctly. */ + xTimeToWake = xConstTickCount + xTicksToWait; + + /* The list item will be inserted in wake time order. */ + listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake ); + + if( xTimeToWake < xConstTickCount ) + { + /* Wake time has overflowed. Place this item in the overflow list. */ + vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) ); + } + else + { + /* The wake time has not overflowed, so the current block list is used. */ + vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) ); + + /* If the task entering the blocked state was placed at the head of the + list of blocked tasks then xNextTaskUnblockTime needs to be updated + too. */ + if( xTimeToWake < xNextTaskUnblockTime ) + { + xNextTaskUnblockTime = xTimeToWake; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + + /* Avoid compiler warning when INCLUDE_vTaskSuspend is not 1. */ + ( void ) xCanBlockIndefinitely; + } + #endif /* INCLUDE_vTaskSuspend */ +} + + +#ifdef FREERTOS_MODULE_TEST + #include "tasks_test_access_functions.h" +#endif + diff --git a/STM32F1/libraries/FreeRTOS900/utility/timers.c b/STM32F1/libraries/FreeRTOS900/utility/timers.c new file mode 100644 index 0000000..d4a821a --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/utility/timers.c @@ -0,0 +1,1092 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* Standard includes. */ +#include + +/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining +all the API functions to use the MPU wrappers. That should only be done when +task.h is included from an application file. */ +#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "timers.h" + +#if ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 0 ) + #error configUSE_TIMERS must be set to 1 to make the xTimerPendFunctionCall() function available. +#endif + +/* Lint e961 and e750 are suppressed as a MISRA exception justified because the +MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the +header files above, but not in this file, in order to generate the correct +privileged Vs unprivileged linkage and placement. */ +#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */ + + +/* This entire source file will be skipped if the application is not configured +to include software timer functionality. This #if is closed at the very bottom +of this file. If you want to include software timer functionality then ensure +configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */ +#if ( configUSE_TIMERS == 1 ) + +/* Misc definitions. */ +#define tmrNO_DELAY ( TickType_t ) 0U + +/* The definition of the timers themselves. */ +typedef struct tmrTimerControl +{ + const char *pcTimerName; /*<< Text name. This is not used by the kernel, it is included simply to make debugging easier. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + ListItem_t xTimerListItem; /*<< Standard linked list item as used by all kernel features for event management. */ + TickType_t xTimerPeriodInTicks;/*<< How quickly and often the timer expires. */ + UBaseType_t uxAutoReload; /*<< Set to pdTRUE if the timer should be automatically restarted once expired. Set to pdFALSE if the timer is, in effect, a one-shot timer. */ + void *pvTimerID; /*<< An ID to identify the timer. This allows the timer to be identified when the same callback is used for multiple timers. */ + TimerCallbackFunction_t pxCallbackFunction; /*<< The function that will be called when the timer expires. */ + #if( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxTimerNumber; /*<< An ID assigned by trace tools such as FreeRTOS+Trace */ + #endif + + #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + uint8_t ucStaticallyAllocated; /*<< Set to pdTRUE if the timer was created statically so no attempt is made to free the memory again if the timer is later deleted. */ + #endif +} xTIMER; + +/* The old xTIMER name is maintained above then typedefed to the new Timer_t +name below to enable the use of older kernel aware debuggers. */ +typedef xTIMER Timer_t; + +/* The definition of messages that can be sent and received on the timer queue. +Two types of message can be queued - messages that manipulate a software timer, +and messages that request the execution of a non-timer related callback. The +two message types are defined in two separate structures, xTimerParametersType +and xCallbackParametersType respectively. */ +typedef struct tmrTimerParameters +{ + TickType_t xMessageValue; /*<< An optional value used by a subset of commands, for example, when changing the period of a timer. */ + Timer_t * pxTimer; /*<< The timer to which the command will be applied. */ +} TimerParameter_t; + + +typedef struct tmrCallbackParameters +{ + PendedFunction_t pxCallbackFunction; /* << The callback function to execute. */ + void *pvParameter1; /* << The value that will be used as the callback functions first parameter. */ + uint32_t ulParameter2; /* << The value that will be used as the callback functions second parameter. */ +} CallbackParameters_t; + +/* The structure that contains the two message types, along with an identifier +that is used to determine which message type is valid. */ +typedef struct tmrTimerQueueMessage +{ + BaseType_t xMessageID; /*<< The command being sent to the timer service task. */ + union + { + TimerParameter_t xTimerParameters; + + /* Don't include xCallbackParameters if it is not going to be used as + it makes the structure (and therefore the timer queue) larger. */ + #if ( INCLUDE_xTimerPendFunctionCall == 1 ) + CallbackParameters_t xCallbackParameters; + #endif /* INCLUDE_xTimerPendFunctionCall */ + } u; +} DaemonTaskMessage_t; + +/*lint -e956 A manual analysis and inspection has been used to determine which +static variables must be declared volatile. */ + +/* The list in which active timers are stored. Timers are referenced in expire +time order, with the nearest expiry time at the front of the list. Only the +timer service task is allowed to access these lists. */ +PRIVILEGED_DATA static List_t xActiveTimerList1; +PRIVILEGED_DATA static List_t xActiveTimerList2; +PRIVILEGED_DATA static List_t *pxCurrentTimerList; +PRIVILEGED_DATA static List_t *pxOverflowTimerList; + +/* A queue that is used to send commands to the timer service task. */ +PRIVILEGED_DATA static QueueHandle_t xTimerQueue = NULL; +PRIVILEGED_DATA static TaskHandle_t xTimerTaskHandle = NULL; + +/*lint +e956 */ + +/*-----------------------------------------------------------*/ + +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + + /* If static allocation is supported then the application must provide the + following callback function - which enables the application to optionally + provide the memory that will be used by the timer task as the task's stack + and TCB. */ + extern void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize ); + +#endif + +/* + * Initialise the infrastructure used by the timer service task if it has not + * been initialised already. + */ +static void prvCheckForValidListAndQueue( void ) PRIVILEGED_FUNCTION; + +/* + * The timer service task (daemon). Timer functionality is controlled by this + * task. Other tasks communicate with the timer service task using the + * xTimerQueue queue. + */ +static void prvTimerTask( void *pvParameters ) PRIVILEGED_FUNCTION; + +/* + * Called by the timer service task to interpret and process a command it + * received on the timer queue. + */ +static void prvProcessReceivedCommands( void ) PRIVILEGED_FUNCTION; + +/* + * Insert the timer into either xActiveTimerList1, or xActiveTimerList2, + * depending on if the expire time causes a timer counter overflow. + */ +static BaseType_t prvInsertTimerInActiveList( Timer_t * const pxTimer, const TickType_t xNextExpiryTime, const TickType_t xTimeNow, const TickType_t xCommandTime ) PRIVILEGED_FUNCTION; + +/* + * An active timer has reached its expire time. Reload the timer if it is an + * auto reload timer, then call its callback. + */ +static void prvProcessExpiredTimer( const TickType_t xNextExpireTime, const TickType_t xTimeNow ) PRIVILEGED_FUNCTION; + +/* + * The tick count has overflowed. Switch the timer lists after ensuring the + * current timer list does not still reference some timers. + */ +static void prvSwitchTimerLists( void ) PRIVILEGED_FUNCTION; + +/* + * Obtain the current tick count, setting *pxTimerListsWereSwitched to pdTRUE + * if a tick count overflow occurred since prvSampleTimeNow() was last called. + */ +static TickType_t prvSampleTimeNow( BaseType_t * const pxTimerListsWereSwitched ) PRIVILEGED_FUNCTION; + +/* + * If the timer list contains any active timers then return the expire time of + * the timer that will expire first and set *pxListWasEmpty to false. If the + * timer list does not contain any timers then return 0 and set *pxListWasEmpty + * to pdTRUE. + */ +static TickType_t prvGetNextExpireTime( BaseType_t * const pxListWasEmpty ) PRIVILEGED_FUNCTION; + +/* + * If a timer has expired, process it. Otherwise, block the timer service task + * until either a timer does expire or a command is received. + */ +static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime, BaseType_t xListWasEmpty ) PRIVILEGED_FUNCTION; + +/* + * Called after a Timer_t structure has been allocated either statically or + * dynamically to fill in the structure's members. + */ +static void prvInitialiseNewTimer( const char * const pcTimerName, + const TickType_t xTimerPeriodInTicks, + const UBaseType_t uxAutoReload, + void * const pvTimerID, + TimerCallbackFunction_t pxCallbackFunction, + Timer_t *pxNewTimer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +/*-----------------------------------------------------------*/ + +BaseType_t xTimerCreateTimerTask( void ) +{ +BaseType_t xReturn = pdFAIL; + + /* This function is called when the scheduler is started if + configUSE_TIMERS is set to 1. Check that the infrastructure used by the + timer service task has been created/initialised. If timers have already + been created then the initialisation will already have been performed. */ + prvCheckForValidListAndQueue(); + + if( xTimerQueue != NULL ) + { + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) + { + StaticTask_t *pxTimerTaskTCBBuffer = NULL; + StackType_t *pxTimerTaskStackBuffer = NULL; + uint32_t ulTimerTaskStackSize; + + vApplicationGetTimerTaskMemory( &pxTimerTaskTCBBuffer, &pxTimerTaskStackBuffer, &ulTimerTaskStackSize ); + xTimerTaskHandle = xTaskCreateStatic( prvTimerTask, + "Tmr Svc", + ulTimerTaskStackSize, + NULL, + ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, + pxTimerTaskStackBuffer, + pxTimerTaskTCBBuffer ); + + if( xTimerTaskHandle != NULL ) + { + xReturn = pdPASS; + } + } + #else + { + xReturn = xTaskCreate( prvTimerTask, + "Tmr Svc", + configTIMER_TASK_STACK_DEPTH, + NULL, + ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, + &xTimerTaskHandle ); + } + #endif /* configSUPPORT_STATIC_ALLOCATION */ + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + configASSERT( xReturn ); + return xReturn; +} +/*-----------------------------------------------------------*/ + +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + + TimerHandle_t xTimerCreate( const char * const pcTimerName, + const TickType_t xTimerPeriodInTicks, + const UBaseType_t uxAutoReload, + void * const pvTimerID, + TimerCallbackFunction_t pxCallbackFunction ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + { + Timer_t *pxNewTimer; + + pxNewTimer = ( Timer_t * ) pvPortMalloc( sizeof( Timer_t ) ); + + if( pxNewTimer != NULL ) + { + prvInitialiseNewTimer( pcTimerName, xTimerPeriodInTicks, uxAutoReload, pvTimerID, pxCallbackFunction, pxNewTimer ); + + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) + { + /* Timers can be created statically or dynamically, so note this + timer was created dynamically in case the timer is later + deleted. */ + pxNewTimer->ucStaticallyAllocated = pdFALSE; + } + #endif /* configSUPPORT_STATIC_ALLOCATION */ + } + + return pxNewTimer; + } + +#endif /* configSUPPORT_STATIC_ALLOCATION */ +/*-----------------------------------------------------------*/ + +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + + TimerHandle_t xTimerCreateStatic( const char * const pcTimerName, + const TickType_t xTimerPeriodInTicks, + const UBaseType_t uxAutoReload, + void * const pvTimerID, + TimerCallbackFunction_t pxCallbackFunction, + StaticTimer_t *pxTimerBuffer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + { + Timer_t *pxNewTimer; + + #if( configASSERT_DEFINED == 1 ) + { + /* Sanity check that the size of the structure used to declare a + variable of type StaticTimer_t equals the size of the real timer + structures. */ + volatile size_t xSize = sizeof( StaticTimer_t ); + configASSERT( xSize == sizeof( Timer_t ) ); + } + #endif /* configASSERT_DEFINED */ + + /* A pointer to a StaticTimer_t structure MUST be provided, use it. */ + configASSERT( pxTimerBuffer ); + pxNewTimer = ( Timer_t * ) pxTimerBuffer; /*lint !e740 Unusual cast is ok as the structures are designed to have the same alignment, and the size is checked by an assert. */ + + if( pxNewTimer != NULL ) + { + prvInitialiseNewTimer( pcTimerName, xTimerPeriodInTicks, uxAutoReload, pvTimerID, pxCallbackFunction, pxNewTimer ); + + #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + { + /* Timers can be created statically or dynamically so note this + timer was created statically in case it is later deleted. */ + pxNewTimer->ucStaticallyAllocated = pdTRUE; + } + #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ + } + + return pxNewTimer; + } + +#endif /* configSUPPORT_STATIC_ALLOCATION */ +/*-----------------------------------------------------------*/ + +static void prvInitialiseNewTimer( const char * const pcTimerName, + const TickType_t xTimerPeriodInTicks, + const UBaseType_t uxAutoReload, + void * const pvTimerID, + TimerCallbackFunction_t pxCallbackFunction, + Timer_t *pxNewTimer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +{ + /* 0 is not a valid value for xTimerPeriodInTicks. */ + configASSERT( ( xTimerPeriodInTicks > 0 ) ); + + if( pxNewTimer != NULL ) + { + /* Ensure the infrastructure used by the timer service task has been + created/initialised. */ + prvCheckForValidListAndQueue(); + + /* Initialise the timer structure members using the function + parameters. */ + pxNewTimer->pcTimerName = pcTimerName; + pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks; + pxNewTimer->uxAutoReload = uxAutoReload; + pxNewTimer->pvTimerID = pvTimerID; + pxNewTimer->pxCallbackFunction = pxCallbackFunction; + vListInitialiseItem( &( pxNewTimer->xTimerListItem ) ); + traceTIMER_CREATE( pxNewTimer ); + } +} +/*-----------------------------------------------------------*/ + +BaseType_t xTimerGenericCommand( TimerHandle_t xTimer, const BaseType_t xCommandID, const TickType_t xOptionalValue, BaseType_t * const pxHigherPriorityTaskWoken, const TickType_t xTicksToWait ) +{ +BaseType_t xReturn = pdFAIL; +DaemonTaskMessage_t xMessage; + + configASSERT( xTimer ); + + /* Send a message to the timer service task to perform a particular action + on a particular timer definition. */ + if( xTimerQueue != NULL ) + { + /* Send a command to the timer service task to start the xTimer timer. */ + xMessage.xMessageID = xCommandID; + xMessage.u.xTimerParameters.xMessageValue = xOptionalValue; + xMessage.u.xTimerParameters.pxTimer = ( Timer_t * ) xTimer; + + if( xCommandID < tmrFIRST_FROM_ISR_COMMAND ) + { + if( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING ) + { + xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xTicksToWait ); + } + else + { + xReturn = xQueueSendToBack( xTimerQueue, &xMessage, tmrNO_DELAY ); + } + } + else + { + xReturn = xQueueSendToBackFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken ); + } + + traceTIMER_COMMAND_SEND( xTimer, xCommandID, xOptionalValue, xReturn ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +TaskHandle_t xTimerGetTimerDaemonTaskHandle( void ) +{ + /* If xTimerGetTimerDaemonTaskHandle() is called before the scheduler has been + started, then xTimerTaskHandle will be NULL. */ + configASSERT( ( xTimerTaskHandle != NULL ) ); + return xTimerTaskHandle; +} +/*-----------------------------------------------------------*/ + +TickType_t xTimerGetPeriod( TimerHandle_t xTimer ) +{ +Timer_t *pxTimer = ( Timer_t * ) xTimer; + + configASSERT( xTimer ); + return pxTimer->xTimerPeriodInTicks; +} +/*-----------------------------------------------------------*/ + +TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ) +{ +Timer_t * pxTimer = ( Timer_t * ) xTimer; +TickType_t xReturn; + + configASSERT( xTimer ); + xReturn = listGET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ) ); + return xReturn; +} +/*-----------------------------------------------------------*/ + +const char * pcTimerGetName( TimerHandle_t xTimer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +{ +Timer_t *pxTimer = ( Timer_t * ) xTimer; + + configASSERT( xTimer ); + return pxTimer->pcTimerName; +} +/*-----------------------------------------------------------*/ + +static void prvProcessExpiredTimer( const TickType_t xNextExpireTime, const TickType_t xTimeNow ) +{ +BaseType_t xResult; +Timer_t * const pxTimer = ( Timer_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList ); + + /* Remove the timer from the list of active timers. A check has already + been performed to ensure the list is not empty. */ + ( void ) uxListRemove( &( pxTimer->xTimerListItem ) ); + traceTIMER_EXPIRED( pxTimer ); + + /* If the timer is an auto reload timer then calculate the next + expiry time and re-insert the timer in the list of active timers. */ + if( pxTimer->uxAutoReload == ( UBaseType_t ) pdTRUE ) + { + /* The timer is inserted into a list using a time relative to anything + other than the current time. It will therefore be inserted into the + correct list relative to the time this task thinks it is now. */ + if( prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xNextExpireTime ) != pdFALSE ) + { + /* The timer expired before it was added to the active timer + list. Reload it now. */ + xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xNextExpireTime, NULL, tmrNO_DELAY ); + configASSERT( xResult ); + ( void ) xResult; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Call the timer callback. */ + pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer ); +} +/*-----------------------------------------------------------*/ + +static void prvTimerTask( void *pvParameters ) +{ +TickType_t xNextExpireTime; +BaseType_t xListWasEmpty; + + /* Just to avoid compiler warnings. */ + ( void ) pvParameters; + + #if( configUSE_DAEMON_TASK_STARTUP_HOOK == 1 ) + { + extern void vApplicationDaemonTaskStartupHook( void ); + + /* Allow the application writer to execute some code in the context of + this task at the point the task starts executing. This is useful if the + application includes initialisation code that would benefit from + executing after the scheduler has been started. */ + vApplicationDaemonTaskStartupHook(); + } + #endif /* configUSE_DAEMON_TASK_STARTUP_HOOK */ + + for( ;; ) + { + /* Query the timers list to see if it contains any timers, and if so, + obtain the time at which the next timer will expire. */ + xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty ); + + /* If a timer has expired, process it. Otherwise, block this task + until either a timer does expire, or a command is received. */ + prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty ); + + /* Empty the command queue. */ + prvProcessReceivedCommands(); + } +} +/*-----------------------------------------------------------*/ + +static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime, BaseType_t xListWasEmpty ) +{ +TickType_t xTimeNow; +BaseType_t xTimerListsWereSwitched; + + vTaskSuspendAll(); + { + /* Obtain the time now to make an assessment as to whether the timer + has expired or not. If obtaining the time causes the lists to switch + then don't process this timer as any timers that remained in the list + when the lists were switched will have been processed within the + prvSampleTimeNow() function. */ + xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched ); + if( xTimerListsWereSwitched == pdFALSE ) + { + /* The tick count has not overflowed, has the timer expired? */ + if( ( xListWasEmpty == pdFALSE ) && ( xNextExpireTime <= xTimeNow ) ) + { + ( void ) xTaskResumeAll(); + prvProcessExpiredTimer( xNextExpireTime, xTimeNow ); + } + else + { + /* The tick count has not overflowed, and the next expire + time has not been reached yet. This task should therefore + block to wait for the next expire time or a command to be + received - whichever comes first. The following line cannot + be reached unless xNextExpireTime > xTimeNow, except in the + case when the current timer list is empty. */ + if( xListWasEmpty != pdFALSE ) + { + /* The current timer list is empty - is the overflow list + also empty? */ + xListWasEmpty = listLIST_IS_EMPTY( pxOverflowTimerList ); + } + + vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ), xListWasEmpty ); + + if( xTaskResumeAll() == pdFALSE ) + { + /* Yield to wait for either a command to arrive, or the + block time to expire. If a command arrived between the + critical section being exited and this yield then the yield + will not cause the task to block. */ + portYIELD_WITHIN_API(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + } + else + { + ( void ) xTaskResumeAll(); + } + } +} +/*-----------------------------------------------------------*/ + +static TickType_t prvGetNextExpireTime( BaseType_t * const pxListWasEmpty ) +{ +TickType_t xNextExpireTime; + + /* Timers are listed in expiry time order, with the head of the list + referencing the task that will expire first. Obtain the time at which + the timer with the nearest expiry time will expire. If there are no + active timers then just set the next expire time to 0. That will cause + this task to unblock when the tick count overflows, at which point the + timer lists will be switched and the next expiry time can be + re-assessed. */ + *pxListWasEmpty = listLIST_IS_EMPTY( pxCurrentTimerList ); + if( *pxListWasEmpty == pdFALSE ) + { + xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList ); + } + else + { + /* Ensure the task unblocks when the tick count rolls over. */ + xNextExpireTime = ( TickType_t ) 0U; + } + + return xNextExpireTime; +} +/*-----------------------------------------------------------*/ + +static TickType_t prvSampleTimeNow( BaseType_t * const pxTimerListsWereSwitched ) +{ +TickType_t xTimeNow; +PRIVILEGED_DATA static TickType_t xLastTime = ( TickType_t ) 0U; /*lint !e956 Variable is only accessible to one task. */ + + xTimeNow = xTaskGetTickCount(); + + if( xTimeNow < xLastTime ) + { + prvSwitchTimerLists(); + *pxTimerListsWereSwitched = pdTRUE; + } + else + { + *pxTimerListsWereSwitched = pdFALSE; + } + + xLastTime = xTimeNow; + + return xTimeNow; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvInsertTimerInActiveList( Timer_t * const pxTimer, const TickType_t xNextExpiryTime, const TickType_t xTimeNow, const TickType_t xCommandTime ) +{ +BaseType_t xProcessTimerNow = pdFALSE; + + listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xNextExpiryTime ); + listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer ); + + if( xNextExpiryTime <= xTimeNow ) + { + /* Has the expiry time elapsed between the command to start/reset a + timer was issued, and the time the command was processed? */ + if( ( ( TickType_t ) ( xTimeNow - xCommandTime ) ) >= pxTimer->xTimerPeriodInTicks ) /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + { + /* The time between a command being issued and the command being + processed actually exceeds the timers period. */ + xProcessTimerNow = pdTRUE; + } + else + { + vListInsert( pxOverflowTimerList, &( pxTimer->xTimerListItem ) ); + } + } + else + { + if( ( xTimeNow < xCommandTime ) && ( xNextExpiryTime >= xCommandTime ) ) + { + /* If, since the command was issued, the tick count has overflowed + but the expiry time has not, then the timer must have already passed + its expiry time and should be processed immediately. */ + xProcessTimerNow = pdTRUE; + } + else + { + vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) ); + } + } + + return xProcessTimerNow; +} +/*-----------------------------------------------------------*/ + +static void prvProcessReceivedCommands( void ) +{ +DaemonTaskMessage_t xMessage; +Timer_t *pxTimer; +BaseType_t xTimerListsWereSwitched, xResult; +TickType_t xTimeNow; + + while( xQueueReceive( xTimerQueue, &xMessage, tmrNO_DELAY ) != pdFAIL ) /*lint !e603 xMessage does not have to be initialised as it is passed out, not in, and it is not used unless xQueueReceive() returns pdTRUE. */ + { + #if ( INCLUDE_xTimerPendFunctionCall == 1 ) + { + /* Negative commands are pended function calls rather than timer + commands. */ + if( xMessage.xMessageID < ( BaseType_t ) 0 ) + { + const CallbackParameters_t * const pxCallback = &( xMessage.u.xCallbackParameters ); + + /* The timer uses the xCallbackParameters member to request a + callback be executed. Check the callback is not NULL. */ + configASSERT( pxCallback ); + + /* Call the function. */ + pxCallback->pxCallbackFunction( pxCallback->pvParameter1, pxCallback->ulParameter2 ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* INCLUDE_xTimerPendFunctionCall */ + + /* Commands that are positive are timer commands rather than pended + function calls. */ + if( xMessage.xMessageID >= ( BaseType_t ) 0 ) + { + /* The messages uses the xTimerParameters member to work on a + software timer. */ + pxTimer = xMessage.u.xTimerParameters.pxTimer; + + if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE ) + { + /* The timer is in a list, remove it. */ + ( void ) uxListRemove( &( pxTimer->xTimerListItem ) ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + traceTIMER_COMMAND_RECEIVED( pxTimer, xMessage.xMessageID, xMessage.u.xTimerParameters.xMessageValue ); + + /* In this case the xTimerListsWereSwitched parameter is not used, but + it must be present in the function call. prvSampleTimeNow() must be + called after the message is received from xTimerQueue so there is no + possibility of a higher priority task adding a message to the message + queue with a time that is ahead of the timer daemon task (because it + pre-empted the timer daemon task after the xTimeNow value was set). */ + xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched ); + + switch( xMessage.xMessageID ) + { + case tmrCOMMAND_START : + case tmrCOMMAND_START_FROM_ISR : + case tmrCOMMAND_RESET : + case tmrCOMMAND_RESET_FROM_ISR : + case tmrCOMMAND_START_DONT_TRACE : + /* Start or restart a timer. */ + if( prvInsertTimerInActiveList( pxTimer, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.u.xTimerParameters.xMessageValue ) != pdFALSE ) + { + /* The timer expired before it was added to the active + timer list. Process it now. */ + pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer ); + traceTIMER_EXPIRED( pxTimer ); + + if( pxTimer->uxAutoReload == ( UBaseType_t ) pdTRUE ) + { + xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, NULL, tmrNO_DELAY ); + configASSERT( xResult ); + ( void ) xResult; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + break; + + case tmrCOMMAND_STOP : + case tmrCOMMAND_STOP_FROM_ISR : + /* The timer has already been removed from the active list. + There is nothing to do here. */ + break; + + case tmrCOMMAND_CHANGE_PERIOD : + case tmrCOMMAND_CHANGE_PERIOD_FROM_ISR : + pxTimer->xTimerPeriodInTicks = xMessage.u.xTimerParameters.xMessageValue; + configASSERT( ( pxTimer->xTimerPeriodInTicks > 0 ) ); + + /* The new period does not really have a reference, and can + be longer or shorter than the old one. The command time is + therefore set to the current time, and as the period cannot + be zero the next expiry time can only be in the future, + meaning (unlike for the xTimerStart() case above) there is + no fail case that needs to be handled here. */ + ( void ) prvInsertTimerInActiveList( pxTimer, ( xTimeNow + pxTimer->xTimerPeriodInTicks ), xTimeNow, xTimeNow ); + break; + + case tmrCOMMAND_DELETE : + /* The timer has already been removed from the active list, + just free up the memory if the memory was dynamically + allocated. */ + #if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) ) + { + /* The timer can only have been allocated dynamically - + free it again. */ + vPortFree( pxTimer ); + } + #elif( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) + { + /* The timer could have been allocated statically or + dynamically, so check before attempting to free the + memory. */ + if( pxTimer->ucStaticallyAllocated == ( uint8_t ) pdFALSE ) + { + vPortFree( pxTimer ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ + break; + + default : + /* Don't expect to get here. */ + break; + } + } + } +} +/*-----------------------------------------------------------*/ + +static void prvSwitchTimerLists( void ) +{ +TickType_t xNextExpireTime, xReloadTime; +List_t *pxTemp; +Timer_t *pxTimer; +BaseType_t xResult; + + /* The tick count has overflowed. The timer lists must be switched. + If there are any timers still referenced from the current timer list + then they must have expired and should be processed before the lists + are switched. */ + while( listLIST_IS_EMPTY( pxCurrentTimerList ) == pdFALSE ) + { + xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList ); + + /* Remove the timer from the list. */ + pxTimer = ( Timer_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList ); + ( void ) uxListRemove( &( pxTimer->xTimerListItem ) ); + traceTIMER_EXPIRED( pxTimer ); + + /* Execute its callback, then send a command to restart the timer if + it is an auto-reload timer. It cannot be restarted here as the lists + have not yet been switched. */ + pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer ); + + if( pxTimer->uxAutoReload == ( UBaseType_t ) pdTRUE ) + { + /* Calculate the reload value, and if the reload value results in + the timer going into the same timer list then it has already expired + and the timer should be re-inserted into the current list so it is + processed again within this loop. Otherwise a command should be sent + to restart the timer to ensure it is only inserted into a list after + the lists have been swapped. */ + xReloadTime = ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ); + if( xReloadTime > xNextExpireTime ) + { + listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xReloadTime ); + listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer ); + vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) ); + } + else + { + xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xNextExpireTime, NULL, tmrNO_DELAY ); + configASSERT( xResult ); + ( void ) xResult; + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + + pxTemp = pxCurrentTimerList; + pxCurrentTimerList = pxOverflowTimerList; + pxOverflowTimerList = pxTemp; +} +/*-----------------------------------------------------------*/ + +static void prvCheckForValidListAndQueue( void ) +{ + /* Check that the list from which active timers are referenced, and the + queue used to communicate with the timer service, have been + initialised. */ + taskENTER_CRITICAL(); + { + if( xTimerQueue == NULL ) + { + vListInitialise( &xActiveTimerList1 ); + vListInitialise( &xActiveTimerList2 ); + pxCurrentTimerList = &xActiveTimerList1; + pxOverflowTimerList = &xActiveTimerList2; + + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) + { + /* The timer queue is allocated statically in case + configSUPPORT_DYNAMIC_ALLOCATION is 0. */ + static StaticQueue_t xStaticTimerQueue; + static uint8_t ucStaticTimerQueueStorage[ configTIMER_QUEUE_LENGTH * sizeof( DaemonTaskMessage_t ) ]; + + xTimerQueue = xQueueCreateStatic( ( UBaseType_t ) configTIMER_QUEUE_LENGTH, sizeof( DaemonTaskMessage_t ), &( ucStaticTimerQueueStorage[ 0 ] ), &xStaticTimerQueue ); + } + #else + { + xTimerQueue = xQueueCreate( ( UBaseType_t ) configTIMER_QUEUE_LENGTH, sizeof( DaemonTaskMessage_t ) ); + } + #endif + + #if ( configQUEUE_REGISTRY_SIZE > 0 ) + { + if( xTimerQueue != NULL ) + { + vQueueAddToRegistry( xTimerQueue, "TmrQ" ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configQUEUE_REGISTRY_SIZE */ + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); +} +/*-----------------------------------------------------------*/ + +BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer ) +{ +BaseType_t xTimerIsInActiveList; +Timer_t *pxTimer = ( Timer_t * ) xTimer; + + configASSERT( xTimer ); + + /* Is the timer in the list of active timers? */ + taskENTER_CRITICAL(); + { + /* Checking to see if it is in the NULL list in effect checks to see if + it is referenced from either the current or the overflow timer lists in + one go, but the logic has to be reversed, hence the '!'. */ + xTimerIsInActiveList = ( BaseType_t ) !( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) ); + } + taskEXIT_CRITICAL(); + + return xTimerIsInActiveList; +} /*lint !e818 Can't be pointer to const due to the typedef. */ +/*-----------------------------------------------------------*/ + +void *pvTimerGetTimerID( const TimerHandle_t xTimer ) +{ +Timer_t * const pxTimer = ( Timer_t * ) xTimer; +void *pvReturn; + + configASSERT( xTimer ); + + taskENTER_CRITICAL(); + { + pvReturn = pxTimer->pvTimerID; + } + taskEXIT_CRITICAL(); + + return pvReturn; +} +/*-----------------------------------------------------------*/ + +void vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID ) +{ +Timer_t * const pxTimer = ( Timer_t * ) xTimer; + + configASSERT( xTimer ); + + taskENTER_CRITICAL(); + { + pxTimer->pvTimerID = pvNewID; + } + taskEXIT_CRITICAL(); +} +/*-----------------------------------------------------------*/ + +#if( INCLUDE_xTimerPendFunctionCall == 1 ) + + BaseType_t xTimerPendFunctionCallFromISR( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, BaseType_t *pxHigherPriorityTaskWoken ) + { + DaemonTaskMessage_t xMessage; + BaseType_t xReturn; + + /* Complete the message with the function parameters and post it to the + daemon task. */ + xMessage.xMessageID = tmrCOMMAND_EXECUTE_CALLBACK_FROM_ISR; + xMessage.u.xCallbackParameters.pxCallbackFunction = xFunctionToPend; + xMessage.u.xCallbackParameters.pvParameter1 = pvParameter1; + xMessage.u.xCallbackParameters.ulParameter2 = ulParameter2; + + xReturn = xQueueSendFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken ); + + tracePEND_FUNC_CALL_FROM_ISR( xFunctionToPend, pvParameter1, ulParameter2, xReturn ); + + return xReturn; + } + +#endif /* INCLUDE_xTimerPendFunctionCall */ +/*-----------------------------------------------------------*/ + +#if( INCLUDE_xTimerPendFunctionCall == 1 ) + + BaseType_t xTimerPendFunctionCall( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, TickType_t xTicksToWait ) + { + DaemonTaskMessage_t xMessage; + BaseType_t xReturn; + + /* This function can only be called after a timer has been created or + after the scheduler has been started because, until then, the timer + queue does not exist. */ + configASSERT( xTimerQueue ); + + /* Complete the message with the function parameters and post it to the + daemon task. */ + xMessage.xMessageID = tmrCOMMAND_EXECUTE_CALLBACK; + xMessage.u.xCallbackParameters.pxCallbackFunction = xFunctionToPend; + xMessage.u.xCallbackParameters.pvParameter1 = pvParameter1; + xMessage.u.xCallbackParameters.ulParameter2 = ulParameter2; + + xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xTicksToWait ); + + tracePEND_FUNC_CALL( xFunctionToPend, pvParameter1, ulParameter2, xReturn ); + + return xReturn; + } + +#endif /* INCLUDE_xTimerPendFunctionCall */ +/*-----------------------------------------------------------*/ + +/* This entire source file will be skipped if the application is not configured +to include software timer functionality. If you want to include software timer +functionality then ensure configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */ +#endif /* configUSE_TIMERS == 1 */ + + + diff --git a/STM32F1/libraries/FreeRTOS900/utility/timers.h b/STM32F1/libraries/FreeRTOS900/utility/timers.h new file mode 100644 index 0000000..798c955 --- /dev/null +++ b/STM32F1/libraries/FreeRTOS900/utility/timers.h @@ -0,0 +1,1314 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + + +#ifndef TIMERS_H +#define TIMERS_H + +#ifndef INC_FREERTOS_H + #error "include FreeRTOS.h must appear in source files before include timers.h" +#endif + +/*lint -e537 This headers are only multiply included if the application code +happens to also be including task.h. */ +#include "task.h" +/*lint +e537 */ + +#ifdef __cplusplus +extern "C" { +#endif + +/*----------------------------------------------------------- + * MACROS AND DEFINITIONS + *----------------------------------------------------------*/ + +/* IDs for commands that can be sent/received on the timer queue. These are to +be used solely through the macros that make up the public software timer API, +as defined below. The commands that are sent from interrupts must use the +highest numbers as tmrFIRST_FROM_ISR_COMMAND is used to determine if the task +or interrupt version of the queue send function should be used. */ +#define tmrCOMMAND_EXECUTE_CALLBACK_FROM_ISR ( ( BaseType_t ) -2 ) +#define tmrCOMMAND_EXECUTE_CALLBACK ( ( BaseType_t ) -1 ) +#define tmrCOMMAND_START_DONT_TRACE ( ( BaseType_t ) 0 ) +#define tmrCOMMAND_START ( ( BaseType_t ) 1 ) +#define tmrCOMMAND_RESET ( ( BaseType_t ) 2 ) +#define tmrCOMMAND_STOP ( ( BaseType_t ) 3 ) +#define tmrCOMMAND_CHANGE_PERIOD ( ( BaseType_t ) 4 ) +#define tmrCOMMAND_DELETE ( ( BaseType_t ) 5 ) + +#define tmrFIRST_FROM_ISR_COMMAND ( ( BaseType_t ) 6 ) +#define tmrCOMMAND_START_FROM_ISR ( ( BaseType_t ) 6 ) +#define tmrCOMMAND_RESET_FROM_ISR ( ( BaseType_t ) 7 ) +#define tmrCOMMAND_STOP_FROM_ISR ( ( BaseType_t ) 8 ) +#define tmrCOMMAND_CHANGE_PERIOD_FROM_ISR ( ( BaseType_t ) 9 ) + + +/** + * Type by which software timers are referenced. For example, a call to + * xTimerCreate() returns an TimerHandle_t variable that can then be used to + * reference the subject timer in calls to other software timer API functions + * (for example, xTimerStart(), xTimerReset(), etc.). + */ +typedef void * TimerHandle_t; + +/* + * Defines the prototype to which timer callback functions must conform. + */ +typedef void (*TimerCallbackFunction_t)( TimerHandle_t xTimer ); + +/* + * Defines the prototype to which functions used with the + * xTimerPendFunctionCallFromISR() function must conform. + */ +typedef void (*PendedFunction_t)( void *, uint32_t ); + +/** + * TimerHandle_t xTimerCreate( const char * const pcTimerName, + * TickType_t xTimerPeriodInTicks, + * UBaseType_t uxAutoReload, + * void * pvTimerID, + * TimerCallbackFunction_t pxCallbackFunction ); + * + * Creates a new software timer instance, and returns a handle by which the + * created software timer can be referenced. + * + * Internally, within the FreeRTOS implementation, software timers use a block + * of memory, in which the timer data structure is stored. If a software timer + * is created using xTimerCreate() then the required memory is automatically + * dynamically allocated inside the xTimerCreate() function. (see + * http://www.freertos.org/a00111.html). If a software timer is created using + * xTimerCreateStatic() then the application writer must provide the memory that + * will get used by the software timer. xTimerCreateStatic() therefore allows a + * software timer to be created without using any dynamic memory allocation. + * + * Timers are created in the dormant state. The xTimerStart(), xTimerReset(), + * xTimerStartFromISR(), xTimerResetFromISR(), xTimerChangePeriod() and + * xTimerChangePeriodFromISR() API functions can all be used to transition a + * timer into the active state. + * + * @param pcTimerName A text name that is assigned to the timer. This is done + * purely to assist debugging. The kernel itself only ever references a timer + * by its handle, and never by its name. + * + * @param xTimerPeriodInTicks The timer period. The time is defined in tick + * periods so the constant portTICK_PERIOD_MS can be used to convert a time that + * has been specified in milliseconds. For example, if the timer must expire + * after 100 ticks, then xTimerPeriodInTicks should be set to 100. + * Alternatively, if the timer must expire after 500ms, then xPeriod can be set + * to ( 500 / portTICK_PERIOD_MS ) provided configTICK_RATE_HZ is less than or + * equal to 1000. + * + * @param uxAutoReload If uxAutoReload is set to pdTRUE then the timer will + * expire repeatedly with a frequency set by the xTimerPeriodInTicks parameter. + * If uxAutoReload is set to pdFALSE then the timer will be a one-shot timer and + * enter the dormant state after it expires. + * + * @param pvTimerID An identifier that is assigned to the timer being created. + * Typically this would be used in the timer callback function to identify which + * timer expired when the same callback function is assigned to more than one + * timer. + * + * @param pxCallbackFunction The function to call when the timer expires. + * Callback functions must have the prototype defined by TimerCallbackFunction_t, + * which is "void vCallbackFunction( TimerHandle_t xTimer );". + * + * @return If the timer is successfully created then a handle to the newly + * created timer is returned. If the timer cannot be created (because either + * there is insufficient FreeRTOS heap remaining to allocate the timer + * structures, or the timer period was set to 0) then NULL is returned. + * + * Example usage: + * @verbatim + * #define NUM_TIMERS 5 + * + * // An array to hold handles to the created timers. + * TimerHandle_t xTimers[ NUM_TIMERS ]; + * + * // An array to hold a count of the number of times each timer expires. + * int32_t lExpireCounters[ NUM_TIMERS ] = { 0 }; + * + * // Define a callback function that will be used by multiple timer instances. + * // The callback function does nothing but count the number of times the + * // associated timer expires, and stop the timer once the timer has expired + * // 10 times. + * void vTimerCallback( TimerHandle_t pxTimer ) + * { + * int32_t lArrayIndex; + * const int32_t xMaxExpiryCountBeforeStopping = 10; + * + * // Optionally do something if the pxTimer parameter is NULL. + * configASSERT( pxTimer ); + * + * // Which timer expired? + * lArrayIndex = ( int32_t ) pvTimerGetTimerID( pxTimer ); + * + * // Increment the number of times that pxTimer has expired. + * lExpireCounters[ lArrayIndex ] += 1; + * + * // If the timer has expired 10 times then stop it from running. + * if( lExpireCounters[ lArrayIndex ] == xMaxExpiryCountBeforeStopping ) + * { + * // Do not use a block time if calling a timer API function from a + * // timer callback function, as doing so could cause a deadlock! + * xTimerStop( pxTimer, 0 ); + * } + * } + * + * void main( void ) + * { + * int32_t x; + * + * // Create then start some timers. Starting the timers before the scheduler + * // has been started means the timers will start running immediately that + * // the scheduler starts. + * for( x = 0; x < NUM_TIMERS; x++ ) + * { + * xTimers[ x ] = xTimerCreate( "Timer", // Just a text name, not used by the kernel. + * ( 100 * x ), // The timer period in ticks. + * pdTRUE, // The timers will auto-reload themselves when they expire. + * ( void * ) x, // Assign each timer a unique id equal to its array index. + * vTimerCallback // Each timer calls the same callback when it expires. + * ); + * + * if( xTimers[ x ] == NULL ) + * { + * // The timer was not created. + * } + * else + * { + * // Start the timer. No block time is specified, and even if one was + * // it would be ignored because the scheduler has not yet been + * // started. + * if( xTimerStart( xTimers[ x ], 0 ) != pdPASS ) + * { + * // The timer could not be set into the Active state. + * } + * } + * } + * + * // ... + * // Create tasks here. + * // ... + * + * // Starting the scheduler will start the timers running as they have already + * // been set into the active state. + * vTaskStartScheduler(); + * + * // Should not reach here. + * for( ;; ); + * } + * @endverbatim + */ +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + TimerHandle_t xTimerCreate( const char * const pcTimerName, + const TickType_t xTimerPeriodInTicks, + const UBaseType_t uxAutoReload, + void * const pvTimerID, + TimerCallbackFunction_t pxCallbackFunction ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +#endif + +/** + * TimerHandle_t xTimerCreateStatic(const char * const pcTimerName, + * TickType_t xTimerPeriodInTicks, + * UBaseType_t uxAutoReload, + * void * pvTimerID, + * TimerCallbackFunction_t pxCallbackFunction, + * StaticTimer_t *pxTimerBuffer ); + * + * Creates a new software timer instance, and returns a handle by which the + * created software timer can be referenced. + * + * Internally, within the FreeRTOS implementation, software timers use a block + * of memory, in which the timer data structure is stored. If a software timer + * is created using xTimerCreate() then the required memory is automatically + * dynamically allocated inside the xTimerCreate() function. (see + * http://www.freertos.org/a00111.html). If a software timer is created using + * xTimerCreateStatic() then the application writer must provide the memory that + * will get used by the software timer. xTimerCreateStatic() therefore allows a + * software timer to be created without using any dynamic memory allocation. + * + * Timers are created in the dormant state. The xTimerStart(), xTimerReset(), + * xTimerStartFromISR(), xTimerResetFromISR(), xTimerChangePeriod() and + * xTimerChangePeriodFromISR() API functions can all be used to transition a + * timer into the active state. + * + * @param pcTimerName A text name that is assigned to the timer. This is done + * purely to assist debugging. The kernel itself only ever references a timer + * by its handle, and never by its name. + * + * @param xTimerPeriodInTicks The timer period. The time is defined in tick + * periods so the constant portTICK_PERIOD_MS can be used to convert a time that + * has been specified in milliseconds. For example, if the timer must expire + * after 100 ticks, then xTimerPeriodInTicks should be set to 100. + * Alternatively, if the timer must expire after 500ms, then xPeriod can be set + * to ( 500 / portTICK_PERIOD_MS ) provided configTICK_RATE_HZ is less than or + * equal to 1000. + * + * @param uxAutoReload If uxAutoReload is set to pdTRUE then the timer will + * expire repeatedly with a frequency set by the xTimerPeriodInTicks parameter. + * If uxAutoReload is set to pdFALSE then the timer will be a one-shot timer and + * enter the dormant state after it expires. + * + * @param pvTimerID An identifier that is assigned to the timer being created. + * Typically this would be used in the timer callback function to identify which + * timer expired when the same callback function is assigned to more than one + * timer. + * + * @param pxCallbackFunction The function to call when the timer expires. + * Callback functions must have the prototype defined by TimerCallbackFunction_t, + * which is "void vCallbackFunction( TimerHandle_t xTimer );". + * + * @param pxTimerBuffer Must point to a variable of type StaticTimer_t, which + * will be then be used to hold the software timer's data structures, removing + * the need for the memory to be allocated dynamically. + * + * @return If the timer is created then a handle to the created timer is + * returned. If pxTimerBuffer was NULL then NULL is returned. + * + * Example usage: + * @verbatim + * + * // The buffer used to hold the software timer's data structure. + * static StaticTimer_t xTimerBuffer; + * + * // A variable that will be incremented by the software timer's callback + * // function. + * UBaseType_t uxVariableToIncrement = 0; + * + * // A software timer callback function that increments a variable passed to + * // it when the software timer was created. After the 5th increment the + * // callback function stops the software timer. + * static void prvTimerCallback( TimerHandle_t xExpiredTimer ) + * { + * UBaseType_t *puxVariableToIncrement; + * BaseType_t xReturned; + * + * // Obtain the address of the variable to increment from the timer ID. + * puxVariableToIncrement = ( UBaseType_t * ) pvTimerGetTimerID( xExpiredTimer ); + * + * // Increment the variable to show the timer callback has executed. + * ( *puxVariableToIncrement )++; + * + * // If this callback has executed the required number of times, stop the + * // timer. + * if( *puxVariableToIncrement == 5 ) + * { + * // This is called from a timer callback so must not block. + * xTimerStop( xExpiredTimer, staticDONT_BLOCK ); + * } + * } + * + * + * void main( void ) + * { + * // Create the software time. xTimerCreateStatic() has an extra parameter + * // than the normal xTimerCreate() API function. The parameter is a pointer + * // to the StaticTimer_t structure that will hold the software timer + * // structure. If the parameter is passed as NULL then the structure will be + * // allocated dynamically, just as if xTimerCreate() had been called. + * xTimer = xTimerCreateStatic( "T1", // Text name for the task. Helps debugging only. Not used by FreeRTOS. + * xTimerPeriod, // The period of the timer in ticks. + * pdTRUE, // This is an auto-reload timer. + * ( void * ) &uxVariableToIncrement, // A variable incremented by the software timer's callback function + * prvTimerCallback, // The function to execute when the timer expires. + * &xTimerBuffer ); // The buffer that will hold the software timer structure. + * + * // The scheduler has not started yet so a block time is not used. + * xReturned = xTimerStart( xTimer, 0 ); + * + * // ... + * // Create tasks here. + * // ... + * + * // Starting the scheduler will start the timers running as they have already + * // been set into the active state. + * vTaskStartScheduler(); + * + * // Should not reach here. + * for( ;; ); + * } + * @endverbatim + */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + TimerHandle_t xTimerCreateStatic( const char * const pcTimerName, + const TickType_t xTimerPeriodInTicks, + const UBaseType_t uxAutoReload, + void * const pvTimerID, + TimerCallbackFunction_t pxCallbackFunction, + StaticTimer_t *pxTimerBuffer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +#endif /* configSUPPORT_STATIC_ALLOCATION */ + +/** + * void *pvTimerGetTimerID( TimerHandle_t xTimer ); + * + * Returns the ID assigned to the timer. + * + * IDs are assigned to timers using the pvTimerID parameter of the call to + * xTimerCreated() that was used to create the timer, and by calling the + * vTimerSetTimerID() API function. + * + * If the same callback function is assigned to multiple timers then the timer + * ID can be used as time specific (timer local) storage. + * + * @param xTimer The timer being queried. + * + * @return The ID assigned to the timer being queried. + * + * Example usage: + * + * See the xTimerCreate() API function example usage scenario. + */ +void *pvTimerGetTimerID( const TimerHandle_t xTimer ) PRIVILEGED_FUNCTION; + +/** + * void vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID ); + * + * Sets the ID assigned to the timer. + * + * IDs are assigned to timers using the pvTimerID parameter of the call to + * xTimerCreated() that was used to create the timer. + * + * If the same callback function is assigned to multiple timers then the timer + * ID can be used as time specific (timer local) storage. + * + * @param xTimer The timer being updated. + * + * @param pvNewID The ID to assign to the timer. + * + * Example usage: + * + * See the xTimerCreate() API function example usage scenario. + */ +void vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID ) PRIVILEGED_FUNCTION; + +/** + * BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer ); + * + * Queries a timer to see if it is active or dormant. + * + * A timer will be dormant if: + * 1) It has been created but not started, or + * 2) It is an expired one-shot timer that has not been restarted. + * + * Timers are created in the dormant state. The xTimerStart(), xTimerReset(), + * xTimerStartFromISR(), xTimerResetFromISR(), xTimerChangePeriod() and + * xTimerChangePeriodFromISR() API functions can all be used to transition a timer into the + * active state. + * + * @param xTimer The timer being queried. + * + * @return pdFALSE will be returned if the timer is dormant. A value other than + * pdFALSE will be returned if the timer is active. + * + * Example usage: + * @verbatim + * // This function assumes xTimer has already been created. + * void vAFunction( TimerHandle_t xTimer ) + * { + * if( xTimerIsTimerActive( xTimer ) != pdFALSE ) // or more simply and equivalently "if( xTimerIsTimerActive( xTimer ) )" + * { + * // xTimer is active, do something. + * } + * else + * { + * // xTimer is not active, do something else. + * } + * } + * @endverbatim + */ +BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION; + +/** + * TaskHandle_t xTimerGetTimerDaemonTaskHandle( void ); + * + * Simply returns the handle of the timer service/daemon task. It it not valid + * to call xTimerGetTimerDaemonTaskHandle() before the scheduler has been started. + */ +TaskHandle_t xTimerGetTimerDaemonTaskHandle( void ) PRIVILEGED_FUNCTION; + +/** + * BaseType_t xTimerStart( TimerHandle_t xTimer, TickType_t xTicksToWait ); + * + * Timer functionality is provided by a timer service/daemon task. Many of the + * public FreeRTOS timer API functions send commands to the timer service task + * through a queue called the timer command queue. The timer command queue is + * private to the kernel itself and is not directly accessible to application + * code. The length of the timer command queue is set by the + * configTIMER_QUEUE_LENGTH configuration constant. + * + * xTimerStart() starts a timer that was previously created using the + * xTimerCreate() API function. If the timer had already been started and was + * already in the active state, then xTimerStart() has equivalent functionality + * to the xTimerReset() API function. + * + * Starting a timer ensures the timer is in the active state. If the timer + * is not stopped, deleted, or reset in the mean time, the callback function + * associated with the timer will get called 'n' ticks after xTimerStart() was + * called, where 'n' is the timers defined period. + * + * It is valid to call xTimerStart() before the scheduler has been started, but + * when this is done the timer will not actually start until the scheduler is + * started, and the timers expiry time will be relative to when the scheduler is + * started, not relative to when xTimerStart() was called. + * + * The configUSE_TIMERS configuration constant must be set to 1 for xTimerStart() + * to be available. + * + * @param xTimer The handle of the timer being started/restarted. + * + * @param xTicksToWait Specifies the time, in ticks, that the calling task should + * be held in the Blocked state to wait for the start command to be successfully + * sent to the timer command queue, should the queue already be full when + * xTimerStart() was called. xTicksToWait is ignored if xTimerStart() is called + * before the scheduler is started. + * + * @return pdFAIL will be returned if the start command could not be sent to + * the timer command queue even after xTicksToWait ticks had passed. pdPASS will + * be returned if the command was successfully sent to the timer command queue. + * When the command is actually processed will depend on the priority of the + * timer service/daemon task relative to other tasks in the system, although the + * timers expiry time is relative to when xTimerStart() is actually called. The + * timer service/daemon task priority is set by the configTIMER_TASK_PRIORITY + * configuration constant. + * + * Example usage: + * + * See the xTimerCreate() API function example usage scenario. + * + */ +#define xTimerStart( xTimer, xTicksToWait ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCount() ), NULL, ( xTicksToWait ) ) + +/** + * BaseType_t xTimerStop( TimerHandle_t xTimer, TickType_t xTicksToWait ); + * + * Timer functionality is provided by a timer service/daemon task. Many of the + * public FreeRTOS timer API functions send commands to the timer service task + * through a queue called the timer command queue. The timer command queue is + * private to the kernel itself and is not directly accessible to application + * code. The length of the timer command queue is set by the + * configTIMER_QUEUE_LENGTH configuration constant. + * + * xTimerStop() stops a timer that was previously started using either of the + * The xTimerStart(), xTimerReset(), xTimerStartFromISR(), xTimerResetFromISR(), + * xTimerChangePeriod() or xTimerChangePeriodFromISR() API functions. + * + * Stopping a timer ensures the timer is not in the active state. + * + * The configUSE_TIMERS configuration constant must be set to 1 for xTimerStop() + * to be available. + * + * @param xTimer The handle of the timer being stopped. + * + * @param xTicksToWait Specifies the time, in ticks, that the calling task should + * be held in the Blocked state to wait for the stop command to be successfully + * sent to the timer command queue, should the queue already be full when + * xTimerStop() was called. xTicksToWait is ignored if xTimerStop() is called + * before the scheduler is started. + * + * @return pdFAIL will be returned if the stop command could not be sent to + * the timer command queue even after xTicksToWait ticks had passed. pdPASS will + * be returned if the command was successfully sent to the timer command queue. + * When the command is actually processed will depend on the priority of the + * timer service/daemon task relative to other tasks in the system. The timer + * service/daemon task priority is set by the configTIMER_TASK_PRIORITY + * configuration constant. + * + * Example usage: + * + * See the xTimerCreate() API function example usage scenario. + * + */ +#define xTimerStop( xTimer, xTicksToWait ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_STOP, 0U, NULL, ( xTicksToWait ) ) + +/** + * BaseType_t xTimerChangePeriod( TimerHandle_t xTimer, + * TickType_t xNewPeriod, + * TickType_t xTicksToWait ); + * + * Timer functionality is provided by a timer service/daemon task. Many of the + * public FreeRTOS timer API functions send commands to the timer service task + * through a queue called the timer command queue. The timer command queue is + * private to the kernel itself and is not directly accessible to application + * code. The length of the timer command queue is set by the + * configTIMER_QUEUE_LENGTH configuration constant. + * + * xTimerChangePeriod() changes the period of a timer that was previously + * created using the xTimerCreate() API function. + * + * xTimerChangePeriod() can be called to change the period of an active or + * dormant state timer. + * + * The configUSE_TIMERS configuration constant must be set to 1 for + * xTimerChangePeriod() to be available. + * + * @param xTimer The handle of the timer that is having its period changed. + * + * @param xNewPeriod The new period for xTimer. Timer periods are specified in + * tick periods, so the constant portTICK_PERIOD_MS can be used to convert a time + * that has been specified in milliseconds. For example, if the timer must + * expire after 100 ticks, then xNewPeriod should be set to 100. Alternatively, + * if the timer must expire after 500ms, then xNewPeriod can be set to + * ( 500 / portTICK_PERIOD_MS ) provided configTICK_RATE_HZ is less than + * or equal to 1000. + * + * @param xTicksToWait Specifies the time, in ticks, that the calling task should + * be held in the Blocked state to wait for the change period command to be + * successfully sent to the timer command queue, should the queue already be + * full when xTimerChangePeriod() was called. xTicksToWait is ignored if + * xTimerChangePeriod() is called before the scheduler is started. + * + * @return pdFAIL will be returned if the change period command could not be + * sent to the timer command queue even after xTicksToWait ticks had passed. + * pdPASS will be returned if the command was successfully sent to the timer + * command queue. When the command is actually processed will depend on the + * priority of the timer service/daemon task relative to other tasks in the + * system. The timer service/daemon task priority is set by the + * configTIMER_TASK_PRIORITY configuration constant. + * + * Example usage: + * @verbatim + * // This function assumes xTimer has already been created. If the timer + * // referenced by xTimer is already active when it is called, then the timer + * // is deleted. If the timer referenced by xTimer is not active when it is + * // called, then the period of the timer is set to 500ms and the timer is + * // started. + * void vAFunction( TimerHandle_t xTimer ) + * { + * if( xTimerIsTimerActive( xTimer ) != pdFALSE ) // or more simply and equivalently "if( xTimerIsTimerActive( xTimer ) )" + * { + * // xTimer is already active - delete it. + * xTimerDelete( xTimer ); + * } + * else + * { + * // xTimer is not active, change its period to 500ms. This will also + * // cause the timer to start. Block for a maximum of 100 ticks if the + * // change period command cannot immediately be sent to the timer + * // command queue. + * if( xTimerChangePeriod( xTimer, 500 / portTICK_PERIOD_MS, 100 ) == pdPASS ) + * { + * // The command was successfully sent. + * } + * else + * { + * // The command could not be sent, even after waiting for 100 ticks + * // to pass. Take appropriate action here. + * } + * } + * } + * @endverbatim + */ + #define xTimerChangePeriod( xTimer, xNewPeriod, xTicksToWait ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_CHANGE_PERIOD, ( xNewPeriod ), NULL, ( xTicksToWait ) ) + +/** + * BaseType_t xTimerDelete( TimerHandle_t xTimer, TickType_t xTicksToWait ); + * + * Timer functionality is provided by a timer service/daemon task. Many of the + * public FreeRTOS timer API functions send commands to the timer service task + * through a queue called the timer command queue. The timer command queue is + * private to the kernel itself and is not directly accessible to application + * code. The length of the timer command queue is set by the + * configTIMER_QUEUE_LENGTH configuration constant. + * + * xTimerDelete() deletes a timer that was previously created using the + * xTimerCreate() API function. + * + * The configUSE_TIMERS configuration constant must be set to 1 for + * xTimerDelete() to be available. + * + * @param xTimer The handle of the timer being deleted. + * + * @param xTicksToWait Specifies the time, in ticks, that the calling task should + * be held in the Blocked state to wait for the delete command to be + * successfully sent to the timer command queue, should the queue already be + * full when xTimerDelete() was called. xTicksToWait is ignored if xTimerDelete() + * is called before the scheduler is started. + * + * @return pdFAIL will be returned if the delete command could not be sent to + * the timer command queue even after xTicksToWait ticks had passed. pdPASS will + * be returned if the command was successfully sent to the timer command queue. + * When the command is actually processed will depend on the priority of the + * timer service/daemon task relative to other tasks in the system. The timer + * service/daemon task priority is set by the configTIMER_TASK_PRIORITY + * configuration constant. + * + * Example usage: + * + * See the xTimerChangePeriod() API function example usage scenario. + */ +#define xTimerDelete( xTimer, xTicksToWait ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_DELETE, 0U, NULL, ( xTicksToWait ) ) + +/** + * BaseType_t xTimerReset( TimerHandle_t xTimer, TickType_t xTicksToWait ); + * + * Timer functionality is provided by a timer service/daemon task. Many of the + * public FreeRTOS timer API functions send commands to the timer service task + * through a queue called the timer command queue. The timer command queue is + * private to the kernel itself and is not directly accessible to application + * code. The length of the timer command queue is set by the + * configTIMER_QUEUE_LENGTH configuration constant. + * + * xTimerReset() re-starts a timer that was previously created using the + * xTimerCreate() API function. If the timer had already been started and was + * already in the active state, then xTimerReset() will cause the timer to + * re-evaluate its expiry time so that it is relative to when xTimerReset() was + * called. If the timer was in the dormant state then xTimerReset() has + * equivalent functionality to the xTimerStart() API function. + * + * Resetting a timer ensures the timer is in the active state. If the timer + * is not stopped, deleted, or reset in the mean time, the callback function + * associated with the timer will get called 'n' ticks after xTimerReset() was + * called, where 'n' is the timers defined period. + * + * It is valid to call xTimerReset() before the scheduler has been started, but + * when this is done the timer will not actually start until the scheduler is + * started, and the timers expiry time will be relative to when the scheduler is + * started, not relative to when xTimerReset() was called. + * + * The configUSE_TIMERS configuration constant must be set to 1 for xTimerReset() + * to be available. + * + * @param xTimer The handle of the timer being reset/started/restarted. + * + * @param xTicksToWait Specifies the time, in ticks, that the calling task should + * be held in the Blocked state to wait for the reset command to be successfully + * sent to the timer command queue, should the queue already be full when + * xTimerReset() was called. xTicksToWait is ignored if xTimerReset() is called + * before the scheduler is started. + * + * @return pdFAIL will be returned if the reset command could not be sent to + * the timer command queue even after xTicksToWait ticks had passed. pdPASS will + * be returned if the command was successfully sent to the timer command queue. + * When the command is actually processed will depend on the priority of the + * timer service/daemon task relative to other tasks in the system, although the + * timers expiry time is relative to when xTimerStart() is actually called. The + * timer service/daemon task priority is set by the configTIMER_TASK_PRIORITY + * configuration constant. + * + * Example usage: + * @verbatim + * // When a key is pressed, an LCD back-light is switched on. If 5 seconds pass + * // without a key being pressed, then the LCD back-light is switched off. In + * // this case, the timer is a one-shot timer. + * + * TimerHandle_t xBacklightTimer = NULL; + * + * // The callback function assigned to the one-shot timer. In this case the + * // parameter is not used. + * void vBacklightTimerCallback( TimerHandle_t pxTimer ) + * { + * // The timer expired, therefore 5 seconds must have passed since a key + * // was pressed. Switch off the LCD back-light. + * vSetBacklightState( BACKLIGHT_OFF ); + * } + * + * // The key press event handler. + * void vKeyPressEventHandler( char cKey ) + * { + * // Ensure the LCD back-light is on, then reset the timer that is + * // responsible for turning the back-light off after 5 seconds of + * // key inactivity. Wait 10 ticks for the command to be successfully sent + * // if it cannot be sent immediately. + * vSetBacklightState( BACKLIGHT_ON ); + * if( xTimerReset( xBacklightTimer, 100 ) != pdPASS ) + * { + * // The reset command was not executed successfully. Take appropriate + * // action here. + * } + * + * // Perform the rest of the key processing here. + * } + * + * void main( void ) + * { + * int32_t x; + * + * // Create then start the one-shot timer that is responsible for turning + * // the back-light off if no keys are pressed within a 5 second period. + * xBacklightTimer = xTimerCreate( "BacklightTimer", // Just a text name, not used by the kernel. + * ( 5000 / portTICK_PERIOD_MS), // The timer period in ticks. + * pdFALSE, // The timer is a one-shot timer. + * 0, // The id is not used by the callback so can take any value. + * vBacklightTimerCallback // The callback function that switches the LCD back-light off. + * ); + * + * if( xBacklightTimer == NULL ) + * { + * // The timer was not created. + * } + * else + * { + * // Start the timer. No block time is specified, and even if one was + * // it would be ignored because the scheduler has not yet been + * // started. + * if( xTimerStart( xBacklightTimer, 0 ) != pdPASS ) + * { + * // The timer could not be set into the Active state. + * } + * } + * + * // ... + * // Create tasks here. + * // ... + * + * // Starting the scheduler will start the timer running as it has already + * // been set into the active state. + * vTaskStartScheduler(); + * + * // Should not reach here. + * for( ;; ); + * } + * @endverbatim + */ +#define xTimerReset( xTimer, xTicksToWait ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_RESET, ( xTaskGetTickCount() ), NULL, ( xTicksToWait ) ) + +/** + * BaseType_t xTimerStartFromISR( TimerHandle_t xTimer, + * BaseType_t *pxHigherPriorityTaskWoken ); + * + * A version of xTimerStart() that can be called from an interrupt service + * routine. + * + * @param xTimer The handle of the timer being started/restarted. + * + * @param pxHigherPriorityTaskWoken The timer service/daemon task spends most + * of its time in the Blocked state, waiting for messages to arrive on the timer + * command queue. Calling xTimerStartFromISR() writes a message to the timer + * command queue, so has the potential to transition the timer service/daemon + * task out of the Blocked state. If calling xTimerStartFromISR() causes the + * timer service/daemon task to leave the Blocked state, and the timer service/ + * daemon task has a priority equal to or greater than the currently executing + * task (the task that was interrupted), then *pxHigherPriorityTaskWoken will + * get set to pdTRUE internally within the xTimerStartFromISR() function. If + * xTimerStartFromISR() sets this value to pdTRUE then a context switch should + * be performed before the interrupt exits. + * + * @return pdFAIL will be returned if the start command could not be sent to + * the timer command queue. pdPASS will be returned if the command was + * successfully sent to the timer command queue. When the command is actually + * processed will depend on the priority of the timer service/daemon task + * relative to other tasks in the system, although the timers expiry time is + * relative to when xTimerStartFromISR() is actually called. The timer + * service/daemon task priority is set by the configTIMER_TASK_PRIORITY + * configuration constant. + * + * Example usage: + * @verbatim + * // This scenario assumes xBacklightTimer has already been created. When a + * // key is pressed, an LCD back-light is switched on. If 5 seconds pass + * // without a key being pressed, then the LCD back-light is switched off. In + * // this case, the timer is a one-shot timer, and unlike the example given for + * // the xTimerReset() function, the key press event handler is an interrupt + * // service routine. + * + * // The callback function assigned to the one-shot timer. In this case the + * // parameter is not used. + * void vBacklightTimerCallback( TimerHandle_t pxTimer ) + * { + * // The timer expired, therefore 5 seconds must have passed since a key + * // was pressed. Switch off the LCD back-light. + * vSetBacklightState( BACKLIGHT_OFF ); + * } + * + * // The key press interrupt service routine. + * void vKeyPressEventInterruptHandler( void ) + * { + * BaseType_t xHigherPriorityTaskWoken = pdFALSE; + * + * // Ensure the LCD back-light is on, then restart the timer that is + * // responsible for turning the back-light off after 5 seconds of + * // key inactivity. This is an interrupt service routine so can only + * // call FreeRTOS API functions that end in "FromISR". + * vSetBacklightState( BACKLIGHT_ON ); + * + * // xTimerStartFromISR() or xTimerResetFromISR() could be called here + * // as both cause the timer to re-calculate its expiry time. + * // xHigherPriorityTaskWoken was initialised to pdFALSE when it was + * // declared (in this function). + * if( xTimerStartFromISR( xBacklightTimer, &xHigherPriorityTaskWoken ) != pdPASS ) + * { + * // The start command was not executed successfully. Take appropriate + * // action here. + * } + * + * // Perform the rest of the key processing here. + * + * // If xHigherPriorityTaskWoken equals pdTRUE, then a context switch + * // should be performed. The syntax required to perform a context switch + * // from inside an ISR varies from port to port, and from compiler to + * // compiler. Inspect the demos for the port you are using to find the + * // actual syntax required. + * if( xHigherPriorityTaskWoken != pdFALSE ) + * { + * // Call the interrupt safe yield function here (actual function + * // depends on the FreeRTOS port being used). + * } + * } + * @endverbatim + */ +#define xTimerStartFromISR( xTimer, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START_FROM_ISR, ( xTaskGetTickCountFromISR() ), ( pxHigherPriorityTaskWoken ), 0U ) + +/** + * BaseType_t xTimerStopFromISR( TimerHandle_t xTimer, + * BaseType_t *pxHigherPriorityTaskWoken ); + * + * A version of xTimerStop() that can be called from an interrupt service + * routine. + * + * @param xTimer The handle of the timer being stopped. + * + * @param pxHigherPriorityTaskWoken The timer service/daemon task spends most + * of its time in the Blocked state, waiting for messages to arrive on the timer + * command queue. Calling xTimerStopFromISR() writes a message to the timer + * command queue, so has the potential to transition the timer service/daemon + * task out of the Blocked state. If calling xTimerStopFromISR() causes the + * timer service/daemon task to leave the Blocked state, and the timer service/ + * daemon task has a priority equal to or greater than the currently executing + * task (the task that was interrupted), then *pxHigherPriorityTaskWoken will + * get set to pdTRUE internally within the xTimerStopFromISR() function. If + * xTimerStopFromISR() sets this value to pdTRUE then a context switch should + * be performed before the interrupt exits. + * + * @return pdFAIL will be returned if the stop command could not be sent to + * the timer command queue. pdPASS will be returned if the command was + * successfully sent to the timer command queue. When the command is actually + * processed will depend on the priority of the timer service/daemon task + * relative to other tasks in the system. The timer service/daemon task + * priority is set by the configTIMER_TASK_PRIORITY configuration constant. + * + * Example usage: + * @verbatim + * // This scenario assumes xTimer has already been created and started. When + * // an interrupt occurs, the timer should be simply stopped. + * + * // The interrupt service routine that stops the timer. + * void vAnExampleInterruptServiceRoutine( void ) + * { + * BaseType_t xHigherPriorityTaskWoken = pdFALSE; + * + * // The interrupt has occurred - simply stop the timer. + * // xHigherPriorityTaskWoken was set to pdFALSE where it was defined + * // (within this function). As this is an interrupt service routine, only + * // FreeRTOS API functions that end in "FromISR" can be used. + * if( xTimerStopFromISR( xTimer, &xHigherPriorityTaskWoken ) != pdPASS ) + * { + * // The stop command was not executed successfully. Take appropriate + * // action here. + * } + * + * // If xHigherPriorityTaskWoken equals pdTRUE, then a context switch + * // should be performed. The syntax required to perform a context switch + * // from inside an ISR varies from port to port, and from compiler to + * // compiler. Inspect the demos for the port you are using to find the + * // actual syntax required. + * if( xHigherPriorityTaskWoken != pdFALSE ) + * { + * // Call the interrupt safe yield function here (actual function + * // depends on the FreeRTOS port being used). + * } + * } + * @endverbatim + */ +#define xTimerStopFromISR( xTimer, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_STOP_FROM_ISR, 0, ( pxHigherPriorityTaskWoken ), 0U ) + +/** + * BaseType_t xTimerChangePeriodFromISR( TimerHandle_t xTimer, + * TickType_t xNewPeriod, + * BaseType_t *pxHigherPriorityTaskWoken ); + * + * A version of xTimerChangePeriod() that can be called from an interrupt + * service routine. + * + * @param xTimer The handle of the timer that is having its period changed. + * + * @param xNewPeriod The new period for xTimer. Timer periods are specified in + * tick periods, so the constant portTICK_PERIOD_MS can be used to convert a time + * that has been specified in milliseconds. For example, if the timer must + * expire after 100 ticks, then xNewPeriod should be set to 100. Alternatively, + * if the timer must expire after 500ms, then xNewPeriod can be set to + * ( 500 / portTICK_PERIOD_MS ) provided configTICK_RATE_HZ is less than + * or equal to 1000. + * + * @param pxHigherPriorityTaskWoken The timer service/daemon task spends most + * of its time in the Blocked state, waiting for messages to arrive on the timer + * command queue. Calling xTimerChangePeriodFromISR() writes a message to the + * timer command queue, so has the potential to transition the timer service/ + * daemon task out of the Blocked state. If calling xTimerChangePeriodFromISR() + * causes the timer service/daemon task to leave the Blocked state, and the + * timer service/daemon task has a priority equal to or greater than the + * currently executing task (the task that was interrupted), then + * *pxHigherPriorityTaskWoken will get set to pdTRUE internally within the + * xTimerChangePeriodFromISR() function. If xTimerChangePeriodFromISR() sets + * this value to pdTRUE then a context switch should be performed before the + * interrupt exits. + * + * @return pdFAIL will be returned if the command to change the timers period + * could not be sent to the timer command queue. pdPASS will be returned if the + * command was successfully sent to the timer command queue. When the command + * is actually processed will depend on the priority of the timer service/daemon + * task relative to other tasks in the system. The timer service/daemon task + * priority is set by the configTIMER_TASK_PRIORITY configuration constant. + * + * Example usage: + * @verbatim + * // This scenario assumes xTimer has already been created and started. When + * // an interrupt occurs, the period of xTimer should be changed to 500ms. + * + * // The interrupt service routine that changes the period of xTimer. + * void vAnExampleInterruptServiceRoutine( void ) + * { + * BaseType_t xHigherPriorityTaskWoken = pdFALSE; + * + * // The interrupt has occurred - change the period of xTimer to 500ms. + * // xHigherPriorityTaskWoken was set to pdFALSE where it was defined + * // (within this function). As this is an interrupt service routine, only + * // FreeRTOS API functions that end in "FromISR" can be used. + * if( xTimerChangePeriodFromISR( xTimer, &xHigherPriorityTaskWoken ) != pdPASS ) + * { + * // The command to change the timers period was not executed + * // successfully. Take appropriate action here. + * } + * + * // If xHigherPriorityTaskWoken equals pdTRUE, then a context switch + * // should be performed. The syntax required to perform a context switch + * // from inside an ISR varies from port to port, and from compiler to + * // compiler. Inspect the demos for the port you are using to find the + * // actual syntax required. + * if( xHigherPriorityTaskWoken != pdFALSE ) + * { + * // Call the interrupt safe yield function here (actual function + * // depends on the FreeRTOS port being used). + * } + * } + * @endverbatim + */ +#define xTimerChangePeriodFromISR( xTimer, xNewPeriod, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_CHANGE_PERIOD_FROM_ISR, ( xNewPeriod ), ( pxHigherPriorityTaskWoken ), 0U ) + +/** + * BaseType_t xTimerResetFromISR( TimerHandle_t xTimer, + * BaseType_t *pxHigherPriorityTaskWoken ); + * + * A version of xTimerReset() that can be called from an interrupt service + * routine. + * + * @param xTimer The handle of the timer that is to be started, reset, or + * restarted. + * + * @param pxHigherPriorityTaskWoken The timer service/daemon task spends most + * of its time in the Blocked state, waiting for messages to arrive on the timer + * command queue. Calling xTimerResetFromISR() writes a message to the timer + * command queue, so has the potential to transition the timer service/daemon + * task out of the Blocked state. If calling xTimerResetFromISR() causes the + * timer service/daemon task to leave the Blocked state, and the timer service/ + * daemon task has a priority equal to or greater than the currently executing + * task (the task that was interrupted), then *pxHigherPriorityTaskWoken will + * get set to pdTRUE internally within the xTimerResetFromISR() function. If + * xTimerResetFromISR() sets this value to pdTRUE then a context switch should + * be performed before the interrupt exits. + * + * @return pdFAIL will be returned if the reset command could not be sent to + * the timer command queue. pdPASS will be returned if the command was + * successfully sent to the timer command queue. When the command is actually + * processed will depend on the priority of the timer service/daemon task + * relative to other tasks in the system, although the timers expiry time is + * relative to when xTimerResetFromISR() is actually called. The timer service/daemon + * task priority is set by the configTIMER_TASK_PRIORITY configuration constant. + * + * Example usage: + * @verbatim + * // This scenario assumes xBacklightTimer has already been created. When a + * // key is pressed, an LCD back-light is switched on. If 5 seconds pass + * // without a key being pressed, then the LCD back-light is switched off. In + * // this case, the timer is a one-shot timer, and unlike the example given for + * // the xTimerReset() function, the key press event handler is an interrupt + * // service routine. + * + * // The callback function assigned to the one-shot timer. In this case the + * // parameter is not used. + * void vBacklightTimerCallback( TimerHandle_t pxTimer ) + * { + * // The timer expired, therefore 5 seconds must have passed since a key + * // was pressed. Switch off the LCD back-light. + * vSetBacklightState( BACKLIGHT_OFF ); + * } + * + * // The key press interrupt service routine. + * void vKeyPressEventInterruptHandler( void ) + * { + * BaseType_t xHigherPriorityTaskWoken = pdFALSE; + * + * // Ensure the LCD back-light is on, then reset the timer that is + * // responsible for turning the back-light off after 5 seconds of + * // key inactivity. This is an interrupt service routine so can only + * // call FreeRTOS API functions that end in "FromISR". + * vSetBacklightState( BACKLIGHT_ON ); + * + * // xTimerStartFromISR() or xTimerResetFromISR() could be called here + * // as both cause the timer to re-calculate its expiry time. + * // xHigherPriorityTaskWoken was initialised to pdFALSE when it was + * // declared (in this function). + * if( xTimerResetFromISR( xBacklightTimer, &xHigherPriorityTaskWoken ) != pdPASS ) + * { + * // The reset command was not executed successfully. Take appropriate + * // action here. + * } + * + * // Perform the rest of the key processing here. + * + * // If xHigherPriorityTaskWoken equals pdTRUE, then a context switch + * // should be performed. The syntax required to perform a context switch + * // from inside an ISR varies from port to port, and from compiler to + * // compiler. Inspect the demos for the port you are using to find the + * // actual syntax required. + * if( xHigherPriorityTaskWoken != pdFALSE ) + * { + * // Call the interrupt safe yield function here (actual function + * // depends on the FreeRTOS port being used). + * } + * } + * @endverbatim + */ +#define xTimerResetFromISR( xTimer, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_RESET_FROM_ISR, ( xTaskGetTickCountFromISR() ), ( pxHigherPriorityTaskWoken ), 0U ) + + +/** + * BaseType_t xTimerPendFunctionCallFromISR( PendedFunction_t xFunctionToPend, + * void *pvParameter1, + * uint32_t ulParameter2, + * BaseType_t *pxHigherPriorityTaskWoken ); + * + * + * Used from application interrupt service routines to defer the execution of a + * function to the RTOS daemon task (the timer service task, hence this function + * is implemented in timers.c and is prefixed with 'Timer'). + * + * Ideally an interrupt service routine (ISR) is kept as short as possible, but + * sometimes an ISR either has a lot of processing to do, or needs to perform + * processing that is not deterministic. In these cases + * xTimerPendFunctionCallFromISR() can be used to defer processing of a function + * to the RTOS daemon task. + * + * A mechanism is provided that allows the interrupt to return directly to the + * task that will subsequently execute the pended callback function. This + * allows the callback function to execute contiguously in time with the + * interrupt - just as if the callback had executed in the interrupt itself. + * + * @param xFunctionToPend The function to execute from the timer service/ + * daemon task. The function must conform to the PendedFunction_t + * prototype. + * + * @param pvParameter1 The value of the callback function's first parameter. + * The parameter has a void * type to allow it to be used to pass any type. + * For example, unsigned longs can be cast to a void *, or the void * can be + * used to point to a structure. + * + * @param ulParameter2 The value of the callback function's second parameter. + * + * @param pxHigherPriorityTaskWoken As mentioned above, calling this function + * will result in a message being sent to the timer daemon task. If the + * priority of the timer daemon task (which is set using + * configTIMER_TASK_PRIORITY in FreeRTOSConfig.h) is higher than the priority of + * the currently running task (the task the interrupt interrupted) then + * *pxHigherPriorityTaskWoken will be set to pdTRUE within + * xTimerPendFunctionCallFromISR(), indicating that a context switch should be + * requested before the interrupt exits. For that reason + * *pxHigherPriorityTaskWoken must be initialised to pdFALSE. See the + * example code below. + * + * @return pdPASS is returned if the message was successfully sent to the + * timer daemon task, otherwise pdFALSE is returned. + * + * Example usage: + * @verbatim + * + * // The callback function that will execute in the context of the daemon task. + * // Note callback functions must all use this same prototype. + * void vProcessInterface( void *pvParameter1, uint32_t ulParameter2 ) + * { + * BaseType_t xInterfaceToService; + * + * // The interface that requires servicing is passed in the second + * // parameter. The first parameter is not used in this case. + * xInterfaceToService = ( BaseType_t ) ulParameter2; + * + * // ...Perform the processing here... + * } + * + * // An ISR that receives data packets from multiple interfaces + * void vAnISR( void ) + * { + * BaseType_t xInterfaceToService, xHigherPriorityTaskWoken; + * + * // Query the hardware to determine which interface needs processing. + * xInterfaceToService = prvCheckInterfaces(); + * + * // The actual processing is to be deferred to a task. Request the + * // vProcessInterface() callback function is executed, passing in the + * // number of the interface that needs processing. The interface to + * // service is passed in the second parameter. The first parameter is + * // not used in this case. + * xHigherPriorityTaskWoken = pdFALSE; + * xTimerPendFunctionCallFromISR( vProcessInterface, NULL, ( uint32_t ) xInterfaceToService, &xHigherPriorityTaskWoken ); + * + * // If xHigherPriorityTaskWoken is now set to pdTRUE then a context + * // switch should be requested. The macro used is port specific and will + * // be either portYIELD_FROM_ISR() or portEND_SWITCHING_ISR() - refer to + * // the documentation page for the port being used. + * portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); + * + * } + * @endverbatim + */ +BaseType_t xTimerPendFunctionCallFromISR( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION; + + /** + * BaseType_t xTimerPendFunctionCall( PendedFunction_t xFunctionToPend, + * void *pvParameter1, + * uint32_t ulParameter2, + * TickType_t xTicksToWait ); + * + * + * Used to defer the execution of a function to the RTOS daemon task (the timer + * service task, hence this function is implemented in timers.c and is prefixed + * with 'Timer'). + * + * @param xFunctionToPend The function to execute from the timer service/ + * daemon task. The function must conform to the PendedFunction_t + * prototype. + * + * @param pvParameter1 The value of the callback function's first parameter. + * The parameter has a void * type to allow it to be used to pass any type. + * For example, unsigned longs can be cast to a void *, or the void * can be + * used to point to a structure. + * + * @param ulParameter2 The value of the callback function's second parameter. + * + * @param xTicksToWait Calling this function will result in a message being + * sent to the timer daemon task on a queue. xTicksToWait is the amount of + * time the calling task should remain in the Blocked state (so not using any + * processing time) for space to become available on the timer queue if the + * queue is found to be full. + * + * @return pdPASS is returned if the message was successfully sent to the + * timer daemon task, otherwise pdFALSE is returned. + * + */ +BaseType_t xTimerPendFunctionCall( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; + +/** + * const char * const pcTimerGetName( TimerHandle_t xTimer ); + * + * Returns the name that was assigned to a timer when the timer was created. + * + * @param xTimer The handle of the timer being queried. + * + * @return The name assigned to the timer specified by the xTimer parameter. + */ +const char * pcTimerGetName( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + +/** + * TickType_t xTimerGetPeriod( TimerHandle_t xTimer ); + * + * Returns the period of a timer. + * + * @param xTimer The handle of the timer being queried. + * + * @return The period of the timer in ticks. + */ +TickType_t xTimerGetPeriod( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION; + +/** +* TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ); +* +* Returns the time in ticks at which the timer will expire. If this is less +* than the current tick count then the expiry time has overflowed from the +* current time. +* +* @param xTimer The handle of the timer being queried. +* +* @return If the timer is running then the time in ticks at which the timer +* will next expire is returned. If the timer is not running then the return +* value is undefined. +*/ +TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION; + +/* + * Functions beyond this part are not part of the public API and are intended + * for use by the kernel only. + */ +BaseType_t xTimerCreateTimerTask( void ) PRIVILEGED_FUNCTION; +BaseType_t xTimerGenericCommand( TimerHandle_t xTimer, const BaseType_t xCommandID, const TickType_t xOptionalValue, BaseType_t * const pxHigherPriorityTaskWoken, const TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; + +#ifdef __cplusplus +} +#endif +#endif /* TIMERS_H */ + + + From e7abad654e8ca03a86502c3b5a27f5411660060e Mon Sep 17 00:00:00 2001 From: victorpv Date: Sun, 26 Mar 2017 14:33:48 -0500 Subject: [PATCH 015/351] Timer DMA functions. Adding 2 functions to enable and disable Timer peripheral DMA requests on update event. --- STM32F1/system/libmaple/include/libmaple/timer.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/STM32F1/system/libmaple/include/libmaple/timer.h b/STM32F1/system/libmaple/include/libmaple/timer.h index 59b3403..28b6c95 100644 --- a/STM32F1/system/libmaple/include/libmaple/timer.h +++ b/STM32F1/system/libmaple/include/libmaple/timer.h @@ -785,6 +785,22 @@ static inline void timer_dma_disable_trg_req(timer_dev *dev) { *bb_perip(&(dev->regs).gen->DIER, TIMER_DIER_TDE_BIT) = 0; } +/** + * @brief Enable a timer's update DMA request + * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL + */ +static inline void timer_dma_enable_upd_req(timer_dev *dev) { + *bb_perip(&(dev->regs).gen->DIER, TIMER_DIER_UDE_BIT) = 1; +} + +/** + * @brief Disable a timer's update DMA request + * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL + */ +static inline void timer_dma_disable_upd_req(timer_dev *dev) { + *bb_perip(&(dev->regs).gen->DIER, TIMER_DIER_UDE_BIT) = 0; +} + /** * @brief Enable a timer channel's DMA request. * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL From 83e5f4832206f1924168c217df0c7bff1b06dad7 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Thu, 13 Apr 2017 22:34:37 +0200 Subject: [PATCH 016/351] 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 3d775ac3c5abe061945f0821489c20d7e4606f71 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Fri, 14 Apr 2017 00:04:32 +0200 Subject: [PATCH 017/351] added variant black_f4 + cleanup old F1 anf F2 definitions --- STM32F4/boards.txt | 28 +++++++++ STM32F4/cores/maple/boards.cpp | 12 ++-- STM32F4/cores/maple/boards.h | 2 + STM32F4/cores/maple/io.h | 9 ++- .../cores/maple/libmaple/HardwareSerial.cpp | 2 +- STM32F4/cores/maple/libmaple/adc.c | 12 ++-- STM32F4/cores/maple/libmaple/adc.h | 48 +++++--------- STM32F4/cores/maple/libmaple/dma.h | 7 +-- STM32F4/cores/maple/libmaple/exti.h | 4 -- STM32F4/cores/maple/libmaple/gpio.h | 7 +-- STM32F4/cores/maple/libmaple/libmaple.h | 11 +++- STM32F4/cores/maple/libmaple/libmaple_types.h | 12 ++-- STM32F4/cores/maple/libmaple/rcc.h | 7 +-- STM32F4/cores/maple/libmaple/rules.mk | 22 ------- STM32F4/cores/maple/libmaple/stm32.h | 63 +------------------ STM32F4/cores/maple/libmaple/timer.h | 19 ++---- STM32F4/cores/maple/libmaple/usart.h | 6 +- .../cores/maple/libmaple/usbF4/VCP/usb_conf.h | 4 ++ .../maple/libmaple/usbF4/VCP/usbd_cdc_vcp.c | 2 +- STM32F4/cores/maple/libmaple/usbF4/usb.c | 2 +- STM32F4/cores/maple/wirish.h | 1 - STM32F4/cores/maple/wirish_analog.cpp | 2 - STM32F4/cores/maple/wirish_digital.cpp | 14 ++--- STM32F4/cores/maple/wirish_types.h | 15 +++++ STM32F4/platform.txt | 8 +-- 25 files changed, 122 insertions(+), 197 deletions(-) diff --git a/STM32F4/boards.txt b/STM32F4/boards.txt index 7577d19..3ff182c 100644 --- a/STM32F4/boards.txt +++ b/STM32F4/boards.txt @@ -29,6 +29,34 @@ discovery_f407.build.error_led_port=GPIOD discovery_f407.build.error_led_pin=14 discovery_f407.build.board=STM32DiscoveryF407 +############################################################## +black_f407vet6.name=STM32 Black F407VET6 + +black_f407vet6.upload.tool=stlink_upload +black_f407vet6.upload.protocol=stlink + +black_f407vet6.upload.file_type=bin +black_f407vet6.upload.ram.maximum_size=65535 +black_f407vet6.upload.flash.maximum_size=514288 +black_f407vet6.upload.maximum_size=514288 + +#black_f407vet6.upload.usbID=0483:3748 +#black_f407vet6.upload.altID=1 +#black_f407vet6.upload.auto_reset=true + +black_f407vet6.build.mcu=cortex-m4 +black_f407vet6.build.f_cpu=168000000L +black_f407vet6.build.core=maple +black_f407vet6.build.extra_flags=-mthumb -DSTM32_HIGH_DENSITY -DSTM32F4 -DBOARD_black_f4 +black_f407vet6.build.ldscript=ld/jtag.ld +black_f407vet6.build.variant=black_f407vet6 +black_f407vet6.build.variant_system_lib=lib_f407.a +black_f407vet6.build.vect=VECT_TAB_BASE +black_f407vet6.build.density=STM32_HIGH_DENSITY +black_f407vet6.build.error_led_port=GPIOA +black_f407vet6.build.error_led_pin=7 +black_f407vet6.build.board=STM32BlackF407VET6 + ############################################################## stm32f4stamp.name=STM32F4Stamp F405 diff --git a/STM32F4/cores/maple/boards.cpp b/STM32F4/cores/maple/boards.cpp index a856571..f9bfd5a 100644 --- a/STM32F4/cores/maple/boards.cpp +++ b/STM32F4/cores/maple/boards.cpp @@ -41,9 +41,7 @@ #include "adc.h" #include "timer.h" #include "usb.h" -#ifdef STM32F2 -//#include "usbF4.h" -#endif + static void setupFlash(void); static void setupClocks(void); @@ -59,7 +57,7 @@ void init(void) { systick_init(SYSTICK_RELOAD_VAL); gpio_init_all(); -#ifdef STM32F2 +#ifdef STM32F4 rcc_clk_enable(RCC_SYSCFG); #else afio_init(); @@ -84,11 +82,13 @@ bool boardUsesPin(uint8 pin) { } static void setupFlash(void) { +/* #ifndef STM32F2 // for F2 and F4 CPUs this is done in SetupClock...(), e.g. in SetupClock168MHz() flash_enable_prefetch(); flash_set_latency(FLASH_WAIT_STATE_2); #endif +*/ } /* @@ -121,8 +121,8 @@ static void setupNVIC() { static void adcDefaultConfig(const adc_dev* dev); static void setupADC() { -#ifdef STM32F2 - setupADC_F2(); +#ifdef STM32F4 + setupADC_F4(); #else rcc_set_prescaler(RCC_PRESCALER_ADC, RCC_ADCPRE_PCLK_DIV_6); #endif diff --git a/STM32F4/cores/maple/boards.h b/STM32F4/cores/maple/boards.h index 00d07cd..5e0aae3 100644 --- a/STM32F4/cores/maple/boards.h +++ b/STM32F4/cores/maple/boards.h @@ -140,6 +140,8 @@ bool boardUsesPin(uint8 pin); #include "aeroquad32mini.h" #elif defined(BOARD_discovery_f4) #include "discovery_f4.h" +#elif defined(BOARD_black_f4) +#include "black_f4.h" #elif defined(BOARD_freeflight) #include "freeflight.h" #else diff --git a/STM32F4/cores/maple/io.h b/STM32F4/cores/maple/io.h index df1ab96..d4d1c25 100644 --- a/STM32F4/cores/maple/io.h +++ b/STM32F4/cores/maple/io.h @@ -33,6 +33,7 @@ #ifndef _IO_H_ #define _IO_H_ +#include #include "gpio.h" #include "adc.h" @@ -179,9 +180,11 @@ static inline void toggleLED() { * accomplished portably over all LeafLabs boards by calling * pinMode(BOARD_BUTTON_PIN, INPUT). * + * @param button - one of available on-board buttons (up to 3 for black F4) + * * @see pinMode() */ -uint8 isButtonPressed(); +uint8 isButtonPressed(uint8_t button); /** * Wait until the button is pressed and released, timing out if no @@ -195,12 +198,14 @@ uint8 isButtonPressed(); * button is pressed. If timeout_millis is left out (or 0), wait * forever. * + * @param button - one of available on-board buttons (up to 3 for black F4) + * * @return true, if the button was pressed; false, if the timeout was * reached. * * @see pinMode() */ -uint8 waitForButtonPress(uint32 timeout_millis=0); +uint8 waitForButtonPress(uint8_t button, uint32 timeout_millis=0); /** * Shift out a byte of data, one bit at a time. diff --git a/STM32F4/cores/maple/libmaple/HardwareSerial.cpp b/STM32F4/cores/maple/libmaple/HardwareSerial.cpp index 59ce71d..475116b 100644 --- a/STM32F4/cores/maple/libmaple/HardwareSerial.cpp +++ b/STM32F4/cores/maple/libmaple/HardwareSerial.cpp @@ -92,7 +92,7 @@ void HardwareSerial::begin(uint32 baud) { const stm32_pin_info *txi = &PIN_MAP[tx_pin]; const stm32_pin_info *rxi = &PIN_MAP[rx_pin]; -#ifdef STM32F2 +#ifdef STM32F4 // int af = 7<<8; if (usart_device == UART4 || usart_device == UART5) { gpio_set_af_mode(txi->gpio_device, txi->gpio_bit, 8); diff --git a/STM32F4/cores/maple/libmaple/adc.c b/STM32F4/cores/maple/libmaple/adc.c index aeeb43c..b803f29 100644 --- a/STM32F4/cores/maple/libmaple/adc.c +++ b/STM32F4/cores/maple/libmaple/adc.c @@ -74,7 +74,7 @@ const adc_dev *ADC3 = &adc3; */ void adc_init(const adc_dev *dev) { rcc_clk_enable(dev->clk_id); -#ifdef STM32F2 +#ifdef STM32F4 if(dev->clk_id == RCC_ADC1) { rcc_reset_dev(dev->clk_id); } @@ -136,7 +136,9 @@ void adc_set_sample_rate(const adc_dev *dev, adc_smp_rate smp_rate) { * @brief Calibrate an ADC peripheral * @param dev adc device */ -void adc_calibrate(const adc_dev *dev) { +void adc_calibrate(const adc_dev *dev) +{ +/* #ifndef STM32F2 __io uint32 *rstcal_bit = bb_perip(&(dev->regs->CR2), 3); __io uint32 *cal_bit = bb_perip(&(dev->regs->CR2), 2); @@ -149,6 +151,7 @@ void adc_calibrate(const adc_dev *dev) { while (*cal_bit) ; #endif +*/ } /** @@ -171,8 +174,8 @@ uint16 adc_read(const adc_dev *dev, uint8 channel) { return (uint16)(regs->DR & ADC_DR_DATA); } -void setupADC_F2() { -#ifdef STM32F2 +void setupADC_F4(void) +{ uint32 tmpreg1 = 0; tmpreg1 = ADC_COMMON->CCR; @@ -196,5 +199,4 @@ void setupADC_F2() { /* Write to ADC CCR */ ADC_COMMON->CCR = tmpreg1; -#endif } diff --git a/STM32F4/cores/maple/libmaple/adc.h b/STM32F4/cores/maple/libmaple/adc.h index 3a40d4c..7a39510 100644 --- a/STM32F4/cores/maple/libmaple/adc.h +++ b/STM32F4/cores/maple/libmaple/adc.h @@ -42,17 +42,15 @@ extern "C"{ #endif -#ifdef STM32F2 - typedef struct - { - __io uint32 CSR; /*!< ADC Common status register, Address offset: ADC1 base address + 0x300 */ - __io uint32 CCR; /*!< ADC common control register, Address offset: ADC1 base address + 0x304 */ - __io uint32 CDR; /*!< ADC common regular data register for dual - AND triple modes, Address offset: ADC1 base address + 0x308 */ - } ADC_Common_TypeDef; +typedef struct +{ + __io uint32 CSR; /*!< ADC Common status register, Address offset: ADC1 base address + 0x300 */ + __io uint32 CCR; /*!< ADC common control register, Address offset: ADC1 base address + 0x304 */ + __io uint32 CDR; /*!< ADC common regular data register for dual + AND triple modes, Address offset: ADC1 base address + 0x308 */ +} ADC_Common_TypeDef; #define ADC_COMMON ((ADC_Common_TypeDef *) 0x40012300) -#endif /** ADC register map type. */ typedef struct adc_reg_map { @@ -94,23 +92,12 @@ extern const adc_dev *ADC3; * Register map base pointers */ -#ifdef STM32F2 - /** ADC1 register map base pointer. */ - #define ADC1_BASE ((struct adc_reg_map*)0x40012000) - /** ADC2 register map base pointer. */ - #define ADC2_BASE ((struct adc_reg_map*)0x40012100) - /** ADC3 register map base pointer. */ - #define ADC3_BASE ((struct adc_reg_map*)0x40012200) -#else - /** ADC1 register map base pointer. */ - #define ADC1_BASE ((struct adc_reg_map*)0x40012400) - /** ADC2 register map base pointer. */ - #define ADC2_BASE ((struct adc_reg_map*)0x40012800) - #ifdef STM32_HIGH_DENSITY - /** ADC3 register map base pointer. */ - #define ADC3_BASE ((struct adc_reg_map*)0x40013C00) - #endif -#endif +/** ADC1 register map base pointer. */ +#define ADC1_BASE ((struct adc_reg_map*)0x40012000) +/** ADC2 register map base pointer. */ +#define ADC2_BASE ((struct adc_reg_map*)0x40012100) +/** ADC3 register map base pointer. */ +#define ADC3_BASE ((struct adc_reg_map*)0x40012200) /* * Register bit definitions @@ -167,17 +154,10 @@ extern const adc_dev *ADC3; #define ADC_CR2_JEXTTRIG_BIT 15 #define ADC_CR2_EXTTRIG_BIT 20 #define ADC_CR2_TSEREFE_BIT 23 -#ifdef STM32F2 #define ADC_CR2_JSWSTART_BIT 22 #define ADC_CR2_SWSTART_BIT 30 #define ADC_CR2_EXTSEL (0x0F000000) #define ADC_CR2_JEXTSEL (0x000F0000) -#else -#define ADC_CR2_JSWSTART_BIT 21 -#define ADC_CR2_SWSTART_BIT 22 -#define ADC_CR2_EXTSEL (0x000E0000) -#define ADC_CR2_JEXTSEL (0x00007000) -#endif @@ -388,7 +368,7 @@ static inline void adc_disable_all(void) { adc_foreach(adc_disable); } -void setupADC_F2(); +extern void setupADC_F4(void); #ifdef __cplusplus } // extern "C" diff --git a/STM32F4/cores/maple/libmaple/dma.h b/STM32F4/cores/maple/libmaple/dma.h index a965c03..420adf8 100644 --- a/STM32F4/cores/maple/libmaple/dma.h +++ b/STM32F4/cores/maple/libmaple/dma.h @@ -30,9 +30,4 @@ * @brief Direct Memory Access peripheral support */ -#ifdef STM32F2 -#include "dmaF2.h" -#include -#else -#include "dmaF1.h" -#endif +#include "dmaF4.h" diff --git a/STM32F4/cores/maple/libmaple/exti.h b/STM32F4/cores/maple/libmaple/exti.h index bac8adc..063f2d7 100644 --- a/STM32F4/cores/maple/libmaple/exti.h +++ b/STM32F4/cores/maple/libmaple/exti.h @@ -52,11 +52,7 @@ typedef struct exti_reg_map { } exti_reg_map; /** EXTI register map base pointer */ -#ifdef STM32F2 #define EXTI_BASE ((struct exti_reg_map*)0x40013C00) -#else -#define EXTI_BASE ((struct exti_reg_map*)0x40010400) -#endif /** External interrupt trigger mode */ typedef enum exti_trigger_mode { diff --git a/STM32F4/cores/maple/libmaple/gpio.h b/STM32F4/cores/maple/libmaple/gpio.h index 4d42386..f065c71 100644 --- a/STM32F4/cores/maple/libmaple/gpio.h +++ b/STM32F4/cores/maple/libmaple/gpio.h @@ -31,8 +31,5 @@ * (AFIO) prototypes, defines, and inlined access functions. */ -#ifdef STM32F2 -#include "gpioF2.h" -#else -#include "gpioF1.h" -#endif + +#include "gpioF4.h" diff --git a/STM32F4/cores/maple/libmaple/libmaple.h b/STM32F4/cores/maple/libmaple/libmaple.h index 10c6c0c..20a57bc 100644 --- a/STM32F4/cores/maple/libmaple/libmaple.h +++ b/STM32F4/cores/maple/libmaple/libmaple.h @@ -42,19 +42,24 @@ * * FIXME this has no business being here */ +/* #if defined(MCU_STM32F103VE) || defined(MCU_STM32F205VE) || defined(MCU_STM32F406VG) - /* e.g., Aeroquad32 */ - #define USER_ADDR_ROM 0x08010000 /* ala42 */ + // e.g., Aeroquad32 + #define USER_ADDR_ROM 0x08010000 // ala42 #define USER_ADDR_RAM 0x20000C00 #define STACK_TOP 0x20000800 #elif defined(BOARD_freeflight) +*/ #define USER_ADDR_ROM 0x08000000 -#define USER_ADDR_RAM 0x20000000 +#define USER_ADDR_RAM 0x20000C00 #define STACK_TOP 0x20000800 +/* #else #define USER_ADDR_ROM 0x08005000 #define USER_ADDR_RAM 0x20000C00 #define STACK_TOP 0x20000800 #endif +*/ + #endif diff --git a/STM32F4/cores/maple/libmaple/libmaple_types.h b/STM32F4/cores/maple/libmaple/libmaple_types.h index 332ded1..e20e327 100644 --- a/STM32F4/cores/maple/libmaple/libmaple_types.h +++ b/STM32F4/cores/maple/libmaple/libmaple_types.h @@ -46,12 +46,14 @@ typedef long long int64; typedef void (*voidFuncPtr)(void); #define __io volatile -#define __attr_flash __attribute__((section (".USER_FLASH"))) - -#define __always_inline inline __attribute__((always_inline)) - +#ifndef __attr_flash + #define __attr_flash __attribute__((section (".USER_FLASH"))) +#endif +#ifndef __always_inline + #define __always_inline inline __attribute__((always_inline)) +#endif #ifndef NULL -#define NULL 0 + #define NULL 0 #endif #endif diff --git a/STM32F4/cores/maple/libmaple/rcc.h b/STM32F4/cores/maple/libmaple/rcc.h index 6317cbd..75e2d3d 100644 --- a/STM32F4/cores/maple/libmaple/rcc.h +++ b/STM32F4/cores/maple/libmaple/rcc.h @@ -29,8 +29,5 @@ * @brief reset and clock control definitions and prototypes */ -#ifdef STM32F2 -#include "rccF2.h" -#else -#include "rccF1.h" -#endif + +#include "rccF4.h" diff --git a/STM32F4/cores/maple/libmaple/rules.mk b/STM32F4/cores/maple/libmaple/rules.mk index c4924dc..eb8d96d 100644 --- a/STM32F4/cores/maple/libmaple/rules.mk +++ b/STM32F4/cores/maple/libmaple/rules.mk @@ -3,17 +3,11 @@ sp := $(sp).x dirstack_$(sp) := $(d) d := $(dir) BUILDDIRS += $(BUILD_PATH)/$(d) -ifneq ($(MCU_FAMILY), STM32F2) -BUILDDIRS += $(BUILD_PATH)/$(d)/usb -BUILDDIRS += $(BUILD_PATH)/$(d)/usb/usb_lib -LIBMAPLE_INCLUDES := -I$(LIBMAPLE_PATH) -I$(LIBMAPLE_PATH)/usb -I$(LIBMAPLE_PATH)/usb/usb_lib -else BUILDDIRS += $(BUILD_PATH)/$(d)/usbF4/STM32_USB_Device_Library/Core/src BUILDDIRS += $(BUILD_PATH)/$(d)/usbF4/STM32_USB_Device_Library/Class/cdc/src BUILDDIRS += $(BUILD_PATH)/$(d)/usbF4/STM32_USB_OTG_Driver/src BUILDDIRS += $(BUILD_PATH)/$(d)/usbF4/VCP LIBMAPLE_INCLUDES := -I$(LIBMAPLE_PATH) -I$(LIBMAPLE_PATH)/usbF4 -endif # Local flags @@ -42,18 +36,6 @@ cSRCS_$(d) := adc.c \ usart.c \ util.c -ifneq ($(MCU_FAMILY), STM32F2) - cSRCS_$(d) += \ - usb/descriptors.c \ - usb/usb.c \ - usb/usb_callbacks.c \ - usb/usb_hardware.c \ - usb/usb_lib/usb_core.c \ - usb/usb_lib/usb_init.c \ - usb/usb_lib/usb_int.c \ - usb/usb_lib/usb_mem.c \ - usb/usb_lib/usb_regs.c -else V=1 cSRCS_$(d) += \ usbF4/STM32_USB_Device_Library/Core/src/usbd_core.c \ @@ -69,11 +51,7 @@ else usbF4/VCP/usbd_usr.c \ usbF4/usb.c \ usbF4/VCP/misc.c -endif -ifneq ($(MCU_FAMILY), STM32F2) - cSRCS_$(d) += bkp.c -endif sSRCS_$(d) := exc.S diff --git a/STM32F4/cores/maple/libmaple/stm32.h b/STM32F4/cores/maple/libmaple/stm32.h index 0d4deaa..3921788 100644 --- a/STM32F4/cores/maple/libmaple/stm32.h +++ b/STM32F4/cores/maple/libmaple/stm32.h @@ -138,69 +138,8 @@ #endif -#if defined(MCU_STM32F103RB) - /* e.g., LeafLabs Maple */ - #define STM32_NR_GPIO_PORTS 4 - #define STM32_DELAY_US_MULT 12 - #define STM32_SRAM_END ((void*)0x20005000) - - #define NR_GPIO_PORTS STM32_NR_GPIO_PORTS - #define DELAY_US_MULT STM32_DELAY_US_MULT - -#elif defined(MCU_STM32F103ZE) - /* e.g., LeafLabs Maple Native */ - - #define STM32_NR_GPIO_PORTS 7 - #define STM32_DELAY_US_MULT 12 - #define STM32_SRAM_END ((void*)0x20010000) - - #define NR_GPIO_PORTS STM32_NR_GPIO_PORTS - #define DELAY_US_MULT STM32_DELAY_US_MULT - -#elif defined(MCU_STM32F103CB) - /* e.g., LeafLabs Maple Mini */ - - /* This STM32_NR_GPIO_PORTS value is not, strictly speaking, true. - * But only pins 0 and 1 exist, and they're used for OSC on the - * Mini, so we'll live with this for now. */ - #define STM32_NR_GPIO_PORTS 3 - #define STM32_DELAY_US_MULT 12 - #define STM32_SRAM_END ((void*)0x20005000) - - #define NR_GPIO_PORTS STM32_NR_GPIO_PORTS - #define DELAY_US_MULT STM32_DELAY_US_MULT - -#elif defined(MCU_STM32F103RE) - /* e.g., LeafLabs Maple RET6 edition */ - - #define STM32_NR_GPIO_PORTS 4 - #define STM32_DELAY_US_MULT 12 - #define STM32_SRAM_END ((void*)0x20010000) - - #define NR_GPIO_PORTS STM32_NR_GPIO_PORTS - #define DELAY_US_MULT STM32_DELAY_US_MULT - -#elif defined(MCU_STM32F103VE) - /* e.g., LeafLabs Maple Native */ - - #define STM32_NR_GPIO_PORTS 5 - #define STM32_DELAY_US_MULT 12 - #define STM32_SRAM_END ((void*)0x20010000) - - #define NR_GPIO_PORTS STM32_NR_GPIO_PORTS - #define DELAY_US_MULT STM32_DELAY_US_MULT - -#elif defined(MCU_STM32F205VE) - #define STM32_TICKS_PER_US 120 - #define STM32_NR_GPIO_PORTS 5 - #define STM32_DELAY_US_MULT (STM32_TICKS_PER_US/3) - #define STM32_SRAM_END ((void*)0x20010000) - - #define NR_GPIO_PORTS STM32_NR_GPIO_PORTS - #define DELAY_US_MULT STM32_DELAY_US_MULT - -#elif defined(MCU_STM32F406VG) +#if defined( STM32F4 ) #define STM32_TICKS_PER_US 168 #define STM32_NR_GPIO_PORTS 5 #define STM32_DELAY_US_MULT (STM32_TICKS_PER_US/3) diff --git a/STM32F4/cores/maple/libmaple/timer.h b/STM32F4/cores/maple/libmaple/timer.h index fce6345..79b7d29 100644 --- a/STM32F4/cores/maple/libmaple/timer.h +++ b/STM32F4/cores/maple/libmaple/timer.h @@ -113,13 +113,8 @@ typedef struct timer_bas_reg_map { } timer_bas_reg_map; -#ifdef STM32F2 - /** Timer 1 register map base pointer */ - #define TIMER1_BASE ((struct timer_adv_reg_map*)0x40010000) -#else - /** Timer 1 register map base pointer */ - #define TIMER1_BASE ((struct timer_adv_reg_map*)0x40012C00) -#endif +/** Timer 1 register map base pointer */ +#define TIMER1_BASE ((struct timer_adv_reg_map*)0x40010000) /** Timer 2 register map base pointer */ #define TIMER2_BASE ((struct timer_gen_reg_map*)0x40000000) /** Timer 3 register map base pointer */ @@ -133,14 +128,8 @@ typedef struct timer_bas_reg_map { #define TIMER6_BASE ((struct timer_bas_reg_map*)0x40001000) /** Timer 7 register map base pointer */ #define TIMER7_BASE ((struct timer_bas_reg_map*)0x40001400) - -#ifdef STM32F2 - /** Timer 8 register map base pointer */ - #define TIMER8_BASE ((struct timer_adv_reg_map*)0x40010400) -#else - /** Timer 8 register map base pointer */ - #define TIMER8_BASE ((struct timer_adv_reg_map*)0x40013400) -#endif +/** Timer 8 register map base pointer */ +#define TIMER8_BASE ((struct timer_adv_reg_map*)0x40010400) #endif /* diff --git a/STM32F4/cores/maple/libmaple/usart.h b/STM32F4/cores/maple/libmaple/usart.h index 3f7c885..282293a 100644 --- a/STM32F4/cores/maple/libmaple/usart.h +++ b/STM32F4/cores/maple/libmaple/usart.h @@ -62,11 +62,7 @@ typedef struct usart_reg_map { } usart_reg_map; /** USART1 register map base pointer */ -#ifdef STM32F2 - #define USART1_BASE ((struct usart_reg_map*)0x40011000) -#else - #define USART1_BASE ((struct usart_reg_map*)0x40013800) -#endif +#define USART1_BASE ((struct usart_reg_map*)0x40011000) /** USART2 register map base pointer */ #define USART2_BASE ((struct usart_reg_map*)0x40004400) /** USART3 register map base pointer */ diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/usb_conf.h b/STM32F4/cores/maple/libmaple/usbF4/VCP/usb_conf.h index 61b0ac5..fd45f4d 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/usb_conf.h +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/usb_conf.h @@ -173,7 +173,9 @@ typedef unsigned char u8; #elif defined (__ICCARM__) /* IAR Compiler */ #define __packed __packed #elif defined ( __GNUC__ ) /* GNU Compiler */ + #ifndef __packed #define __packed __attribute__ ((__packed__)) + #endif #elif defined (__TASKING__) /* TASKING Compiler */ #define __packed __unaligned #endif /* __CC_ARM */ @@ -206,7 +208,9 @@ typedef unsigned char u8; #elif defined (__ICCARM__) /* IAR Compiler */ #define __packed __packed #elif defined ( __GNUC__ ) /* GNU Compiler */ + #ifndef __packed #define __packed __attribute__ ((__packed__)) + #endif #elif defined (__TASKING__) /* TASKING Compiler */ #define __packed __unaligned #endif /* __CC_ARM */ diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.c b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.c index b13260e..28a2d1f 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.c +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.c @@ -255,7 +255,7 @@ typedef struct { void systemHardReset(void) { SCB_TypeDef* rSCB = (SCB_TypeDef *) SCB_BASE; - typedef void (*funcPtr)(void); + //typedef void (*funcPtr)(void); // not used /* Reset */ rSCB->AIRCR = (u32)AIRCR_RESET_REQ; diff --git a/STM32F4/cores/maple/libmaple/usbF4/usb.c b/STM32F4/cores/maple/libmaple/usbF4/usb.c index 2c0672f..263e76f 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/usb.c +++ b/STM32F4/cores/maple/libmaple/usbF4/usb.c @@ -3,7 +3,7 @@ #include "usbd_desc.h" #include "usb.h" #include -#include +#include #include USB_OTG_CORE_HANDLE USB_OTG_dev; diff --git a/STM32F4/cores/maple/wirish.h b/STM32F4/cores/maple/wirish.h index 4aca74c..a9068e7 100644 --- a/STM32F4/cores/maple/wirish.h +++ b/STM32F4/cores/maple/wirish.h @@ -46,7 +46,6 @@ #include "wirish_math.h" #include "wirish_time.h" #include -#include "HardwareSPI.h" #include "HardwareSerial.h" #include "HardwareTimer.h" #include "usb_serial.h" diff --git a/STM32F4/cores/maple/wirish_analog.cpp b/STM32F4/cores/maple/wirish_analog.cpp index 63b5eb2..4e920e7 100644 --- a/STM32F4/cores/maple/wirish_analog.cpp +++ b/STM32F4/cores/maple/wirish_analog.cpp @@ -28,9 +28,7 @@ * @brief Arduino-compatible ADC implementation. */ -#include "libmaple.h" #include "wirish.h" -#include "io.h" /* Assumes that the ADC has been initialized and that the pin is set * to INPUT_ANALOG */ diff --git a/STM32F4/cores/maple/wirish_digital.cpp b/STM32F4/cores/maple/wirish_digital.cpp index a8b3ad8..da180dc 100644 --- a/STM32F4/cores/maple/wirish_digital.cpp +++ b/STM32F4/cores/maple/wirish_digital.cpp @@ -29,7 +29,7 @@ */ #include "wirish.h" -#include "io.h" + void pinMode(uint8 pin, WiringPinMode mode) { gpio_pin_mode outputMode; @@ -111,21 +111,21 @@ void togglePin(uint8 pin) { #define BUTTON_DEBOUNCE_DELAY 1 -uint8 isButtonPressed() { - if (digitalRead(BOARD_BUTTON_PIN)) { +uint8 isButtonPressed(uint8_t button) { + if (digitalRead(button)) { delay(BUTTON_DEBOUNCE_DELAY); - while (digitalRead(BOARD_BUTTON_PIN)) + while (digitalRead(button)) ; return true; } return false; } -uint8 waitForButtonPress(uint32 timeout) { +uint8 waitForButtonPress(uint8_t button, uint32 timeout) { uint32 start = millis(); uint32 time; if (timeout == 0) { - while (!isButtonPressed()) + while (!isButtonPressed(button)) ; return true; } @@ -136,6 +136,6 @@ uint8 waitForButtonPress(uint32 timeout) { time - start > timeout) { return false; } - } while (!isButtonPressed()); + } while (!isButtonPressed(button)); return true; } diff --git a/STM32F4/cores/maple/wirish_types.h b/STM32F4/cores/maple/wirish_types.h index a3c260a..2d6d6a9 100644 --- a/STM32F4/cores/maple/wirish_types.h +++ b/STM32F4/cores/maple/wirish_types.h @@ -48,6 +48,20 @@ * @brief Stores STM32-specific information related to a given Maple pin. * @see PIN_MAP */ +#ifdef BOARD_black_f4 +// restructure members to build consecutive pairs +typedef struct stm32_pin_info { + gpio_dev *gpio_device; /**< Maple pin's GPIO device */ + uint8 gpio_bit; /**< Pin's GPIO port bit. */ + timer_dev *timer_device; /**< Pin's timer device, if any. */ + uint8 timer_channel; /**< Timer channel, or 0 if none. */ + const adc_dev *adc_device; /**< ADC device, if any. */ + uint8 adc_channel; /**< Pin ADC channel, or ADCx if none. */ + uint8 filler; +} stm32_pin_info; + +#else + typedef struct stm32_pin_info { gpio_dev *gpio_device; /**< Maple pin's GPIO device */ timer_dev *timer_device; /**< Pin's timer device, if any. */ @@ -58,6 +72,7 @@ typedef struct stm32_pin_info { uint8 filler; } stm32_pin_info; +#endif /** * Variable attribute, instructs the linker to place the marked * variable in Flash instead of RAM. */ diff --git a/STM32F4/platform.txt b/STM32F4/platform.txt index 99ae555..b32f283 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 -Wall -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 -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 -Wall -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 @@ -44,12 +44,10 @@ compiler.ar.extra_flags= compiler.elf2hex.extra_flags= - ##compiler.libs.c.flags="-I{build.system.path}/libmaple" "-I{build.system.path}/libmaple/include" "-I{build.system.path}/libmaple/stm32f1/include" "-I{build.system.path}/libmaple/stm32f1/include/series" "-I{build.system.path}/libmaple/usb/stm32f1" "-I{build.system.path}/libmaple/usb/usb_lib" #compiler.libs.c.flags="-I{build.system.path}/libmaple" "-I{build.system.path}/libmaple/include" "-I{build.system.path}/libmaple/stm32f1/include" "-I{build.system.path}/libmaple/usb/stm32f1" "-I{build.system.path}/libmaple/usb/usb_lib" - -compiler.libs.c.flags="-I{build.core.path}/libmaple" -I{build.core.path}/libmaple/usbF4 -I{build.core.path}/libmaple/usbF4/STM32_USB_Device_Library/Core/inc -I{build.core.path}/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/inc -I{build.core.path}/libmaple/usbF4/STM32_USB_OTG_Driver/inc -I{build.core.path}/libmaple/usbF4/VCP +compiler.libs.c.flags=-I{build.core.path} -I{build.core.path}/libmaple -I{build.core.path}/libmaple/usbF4 -I{build.core.path}/libmaple/usbF4/STM32_USB_Device_Library/Core/inc -I{build.core.path}/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/inc -I{build.core.path}/libmaple/usbF4/STM32_USB_OTG_Driver/inc -I{build.core.path}/libmaple/usbF4/VCP From 065f58684dfb4ee6728b7a40c58f06b6380911a7 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Fri, 14 Apr 2017 19:26:18 +0200 Subject: [PATCH 018/351] added black F4 variant files + activated USB interface --- STM32F4/cores/maple/libmaple/dmaF4.c | 241 ++++++ STM32F4/cores/maple/libmaple/dmaF4.h | 270 +++++++ STM32F4/cores/maple/libmaple/gpioF4.c | 224 ++++++ STM32F4/cores/maple/libmaple/gpioF4.h | 550 ++++++++++++++ STM32F4/cores/maple/libmaple/rccF4.c | 707 ++++++++++++++++++ STM32F4/cores/maple/libmaple/rccF4.h | 642 ++++++++++++++++ STM32F4/variants/black_f407vet6/black_f4.cpp | 264 +++++++ STM32F4/variants/black_f407vet6/black_f4.h | 130 ++++ STM32F4/variants/black_f407vet6/ld/common.inc | 219 ++++++ .../variants/black_f407vet6/ld/extra_libs.inc | 7 + STM32F4/variants/black_f407vet6/ld/flash.ld | 20 + STM32F4/variants/black_f407vet6/ld/jtag.ld | 20 + STM32F4/variants/black_f407vet6/ld/names.inc | 78 ++ STM32F4/variants/black_f407vet6/ld/ram.ld | 19 + .../black_f407vet6/ld/vector_symbols.inc | 78 ++ .../variants/black_f407vet6/pins_arduino.h | 6 + STM32F4/variants/black_f407vet6/stm32_isrs.S | 323 ++++++++ .../black_f407vet6/stm32_vector_table.S | 113 +++ STM32F4/variants/black_f407vet6/variant.h | 21 + .../variants/black_f407vet6/wirish/start.S | 57 ++ .../variants/black_f407vet6/wirish/start_c.c | 95 +++ 21 files changed, 4084 insertions(+) create mode 100644 STM32F4/cores/maple/libmaple/dmaF4.c create mode 100644 STM32F4/cores/maple/libmaple/dmaF4.h create mode 100644 STM32F4/cores/maple/libmaple/gpioF4.c create mode 100644 STM32F4/cores/maple/libmaple/gpioF4.h create mode 100644 STM32F4/cores/maple/libmaple/rccF4.c create mode 100644 STM32F4/cores/maple/libmaple/rccF4.h create mode 100644 STM32F4/variants/black_f407vet6/black_f4.cpp create mode 100644 STM32F4/variants/black_f407vet6/black_f4.h create mode 100644 STM32F4/variants/black_f407vet6/ld/common.inc create mode 100644 STM32F4/variants/black_f407vet6/ld/extra_libs.inc create mode 100644 STM32F4/variants/black_f407vet6/ld/flash.ld create mode 100644 STM32F4/variants/black_f407vet6/ld/jtag.ld create mode 100644 STM32F4/variants/black_f407vet6/ld/names.inc create mode 100644 STM32F4/variants/black_f407vet6/ld/ram.ld create mode 100644 STM32F4/variants/black_f407vet6/ld/vector_symbols.inc create mode 100644 STM32F4/variants/black_f407vet6/pins_arduino.h create mode 100644 STM32F4/variants/black_f407vet6/stm32_isrs.S create mode 100644 STM32F4/variants/black_f407vet6/stm32_vector_table.S create mode 100644 STM32F4/variants/black_f407vet6/variant.h create mode 100644 STM32F4/variants/black_f407vet6/wirish/start.S create mode 100644 STM32F4/variants/black_f407vet6/wirish/start_c.c diff --git a/STM32F4/cores/maple/libmaple/dmaF4.c b/STM32F4/cores/maple/libmaple/dmaF4.c new file mode 100644 index 0000000..4b530af --- /dev/null +++ b/STM32F4/cores/maple/libmaple/dmaF4.c @@ -0,0 +1,241 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Michael Hope. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +#ifdef STM32F4 + +/** + * @file dmaF4.c + * @brief Direct Memory Access peripheral support + */ + +#include "dma.h" +#include "bitband.h" +#include "util.h" + +/* + * Devices + */ + +static dma_dev dma1 = { + .regs = DMA1_BASE, + .clk_id = RCC_DMA1, + .handlers = {{ .handler = NULL, .irq_line = 11 }, + { .handler = NULL, .irq_line = 12 }, + { .handler = NULL, .irq_line = 13 }, + { .handler = NULL, .irq_line = 14 }, + { .handler = NULL, .irq_line = 15 }, + { .handler = NULL, .irq_line = 16 }, + { .handler = NULL, .irq_line = 17 }, + { .handler = NULL, .irq_line = 47 }} +}; +/** DMA1 device */ +dma_dev *DMA1 = &dma1; + +static dma_dev dma2 = { + .regs = DMA2_BASE, + .clk_id = RCC_DMA2, + .handlers = {{ .handler = NULL, .irq_line = 56 }, + { .handler = NULL, .irq_line = 57 }, + { .handler = NULL, .irq_line = 58 }, + { .handler = NULL, .irq_line = 59 }, + { .handler = NULL, .irq_line = 60 }, + { .handler = NULL, .irq_line = 68 }, + { .handler = NULL, .irq_line = 69 }, + { .handler = NULL, .irq_line = 70 }} /* !@#$ */ +}; +/** DMA2 device */ +dma_dev *DMA2 = &dma2; + + +/* + * Convenience routines + */ + +/** + * @brief Initialize a DMA device. + * @param dev Device to initialize. + */ +void dma_init(dma_dev *dev) { + rcc_clk_enable(dev->clk_id); +} + +/** + * @brief Attach an interrupt to a DMA transfer. + * + * Interrupts are enabled using appropriate mode flags in + * dma_setup_transfer(). + * + * @param dev DMA device + * @param stream Stream to attach handler to + * @param handler Interrupt handler to call when channel interrupt fires. + * @see dma_setup_transfer() + * @see dma_detach_interrupt() + */ +void dma_attach_interrupt(dma_dev *dev, + dma_stream stream, + void (*handler)(void)) { + dev->handlers[stream].handler = handler; + nvic_irq_enable(dev->handlers[stream].irq_line); +} + +/** + * @brief Detach a DMA transfer interrupt handler. + * + * After calling this function, the given channel's interrupts will be + * disabled. + * + * @param dev DMA device + * @param stream Stream whose handler to detach + * @sideeffect Clears interrupt enable bits in the channel's CCR register. + * @see dma_attach_interrupt() + */ +void dma_detach_interrupt(dma_dev *dev, dma_stream stream) { + nvic_irq_disable(dev->handlers[stream].irq_line); + dev->handlers[stream].handler = NULL; +} + +void dma_clear_isr_bits(dma_dev *dev, dma_stream stream) { + switch (stream) { + case 0: + dev->regs->LIFCR|=0x0000003d; + break; + case 1: + dev->regs->LIFCR|=0x00000f40; + break; + case 2: + dev->regs->LIFCR|=0x003d0000; + break; + case 3: + dev->regs->LIFCR|=0x0f400000; + break; + case 4: + dev->regs->HIFCR|=0x0000003d; + break; + case 5: + dev->regs->HIFCR|=0x00000f40; + break; + case 6: + dev->regs->HIFCR|=0x003d0000; + break; + case 7: + dev->regs->HIFCR|=0x0f400000; + break; + } +} + +/* + * IRQ handlers + */ + +static inline void dispatch_handler(dma_dev *dev, dma_stream stream) { + void (*handler)(void) = dev->handlers[stream].handler; + if (handler) { + handler(); + dma_clear_isr_bits(dev, stream); /* in case handler doesn't */ + } +} + +//void __irq_dma1_stream0(void) { +void __irq_dma1_channel1(void) { + dispatch_handler(DMA1, DMA_STREAM0); +} + +//void __irq_dma1_stream1(void) { +void __irq_dma1_channel2(void) { + dispatch_handler(DMA1, DMA_STREAM1); +} + +//void __irq_dma1_stream2(void) { +void __irq_dma1_channel3(void) { + dispatch_handler(DMA1, DMA_STREAM2); +} + +//void __irq_dma1_stream3(void) { +void __irq_dma1_channel4(void) { + dispatch_handler(DMA1, DMA_STREAM3); +} + +//void __irq_dma1_stream4(void) { +void __irq_dma1_channel5(void) { + dispatch_handler(DMA1, DMA_STREAM4); +} + +//void __irq_dma1_stream5(void) { +void __irq_dma1_channel6(void) { + dispatch_handler(DMA1, DMA_STREAM5); +} + +//void __irq_dma1_stream6(void) { +void __irq_dma1_channel7(void) { + dispatch_handler(DMA1, DMA_STREAM6); +} + +//void __irq_dma1_stream7(void) { +void __irq_adc3(void) { + dispatch_handler(DMA1, DMA_STREAM7); +} + +//void __irq_dma2_stream0(void) { +void __irq_dma2_channel1(void) { + dispatch_handler(DMA2, DMA_STREAM0); +} + +//void __irq_dma2_stream1(void) { +void __irq_dma2_channel2(void) { + dispatch_handler(DMA2, DMA_STREAM1); +} + +//void __irq_dma2_stream2(void) { +void __irq_dma2_channel3(void) { + dispatch_handler(DMA2, DMA_STREAM2); +} + +//void __irq_dma2_stream3(void) { +void __irq_dma2_channel4_5(void) { + dispatch_handler(DMA2, DMA_STREAM3); +} + +//void __irq_dma2_stream4(void) { +void __irq_DMA2_Stream4_IRQHandler(void) { + dispatch_handler(DMA2, DMA_STREAM4); +} + +//void __irq_dma2_stream5(void) { +void __irq_DMA2_Stream5_IRQHandler(void) { + dispatch_handler(DMA2, DMA_STREAM5); +} + +//void __irq_dma2_stream6(void) { +void __irq_DMA2_Stream6_IRQHandler(void) { + dispatch_handler(DMA2, DMA_STREAM6); +} + +//void __irq_dma2_stream7(void) { +void __irq_DMA2_Stream7_IRQHandler(void) { + dispatch_handler(DMA2, DMA_STREAM7); +} + +#endif diff --git a/STM32F4/cores/maple/libmaple/dmaF4.h b/STM32F4/cores/maple/libmaple/dmaF4.h new file mode 100644 index 0000000..6f7086f --- /dev/null +++ b/STM32F4/cores/maple/libmaple/dmaF4.h @@ -0,0 +1,270 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Michael Hope. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file dma.h + * + * @author Marti Bolivar ; + * Original implementation by Michael Hope + * + * @brief Direct Memory Access peripheral support + */ + +/* + * See /notes/dma.txt for more information. + */ + +#ifndef _DMA_H_ +#define _DMA_H_ + +#include "libmaple_types.h" +#include "rcc.h" +#include "nvic.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +/* + * Register maps + */ + +/** + * @brief DMA stream type. + * + */ +typedef struct dma_stream_t { + __io uint32 CR; /**< Stream configuration register */ + __io uint32 NDTR; /**< Stream number of data register */ + __io uint32 PAR; /**< Stream peripheral address register */ + __io uint32 M0AR; /**< Stream memory address register 0 */ + __io uint32 M1AR; /**< Stream memory address register 1 */ + __io uint32 FCR; /**< Stream FIFO configuration register */ +} dma_stream_t; +/** + * @brief DMA register map type. + * + */ +typedef struct dma_reg_map { + __io uint32 LISR; /**< Low interrupt status register */ + __io uint32 HISR; /**< High interrupt status register */ + __io uint32 LIFCR; /**< Low interrupt flag clear register */ + __io uint32 HIFCR; /**< High interrupt flag clear register */ + dma_stream_t STREAM[8]; +} dma_reg_map; + +/** DMA controller register map base pointers */ +#define DMA1_BASE ((struct dma_reg_map*)0x40026000) +#define DMA2_BASE ((struct dma_reg_map*)0x40026400) + +/* + * Register bit definitions + */ + +/* Channel configuration register */ + +#define DMA_CR_CH0 (0x0 << 25) +#define DMA_CR_CH1 (0x1 << 25) +#define DMA_CR_CH2 (0x2 << 25) +#define DMA_CR_CH3 (0x3 << 25) +#define DMA_CR_CH4 (0x4 << 25) +#define DMA_CR_CH5 (0x5 << 25) +#define DMA_CR_CH6 (0x6 << 25) +#define DMA_CR_CH7 (0x7 << 25) +#define DMA_CR_MBURST0 (0x0 << 23) +#define DMA_CR_MBURST4 (0x1 << 23) +#define DMA_CR_MBURST8 (0x2 << 23) +#define DMA_CR_MBURST16 (0x3 << 23) +#define DMA_CR_PBURST0 (0x0 << 21) +#define DMA_CR_PBURST4 (0x1 << 21) +#define DMA_CR_PBURST8 (0x2 << 21) +#define DMA_CR_PBURST16 (0x3 << 21) +#define DMA_CR_CT0 (0x0 << 19) +#define DMA_CR_CT1 (0x1 << 19) +#define DMA_CR_DBM (0x1 << 18) + +#define DMA_CR_PL_LOW (0x0 << 16) +#define DMA_CR_PL_MEDIUM (0x1 << 16) +#define DMA_CR_PL_HIGH (0x2 << 16) +#define DMA_CR_PL_VERY_HIGH (0x3 << 16) +#define DMA_CR_PL_MASK (0x3 << 16) + +#define DMA_CR_PINCOS (0x1 << 15) + +#define DMA_CR_MSIZE_8BITS (0x0 << 13) +#define DMA_CR_MSIZE_16BITS (0x1 << 13) +#define DMA_CR_MSIZE_32BITS (0x2 << 13) + +#define DMA_CR_PSIZE_8BITS (0x0 << 11) +#define DMA_CR_PSIZE_16BITS (0x1 << 11) +#define DMA_CR_PSIZE_32BITS (0x2 << 11) + +#define DMA_CR_MINC (0x1 << 10) +#define DMA_CR_PINC (0x1 << 9) +#define DMA_CR_CIRC (0x1 << 8) +#define DMA_CR_DIR_P2M (0x0 << 6) +#define DMA_CR_DIR_M2P (0x1 << 6) +#define DMA_CR_DIR_M2M (0x2 << 6) + +#define DMA_CR_PFCTRL (0x1 << 5) +#define DMA_CR_TCIE (0x1 << 4) +#define DMA_CR_HTIE (0x1 << 3) +#define DMA_CR_TEIE (0x1 << 2) +#define DMA_CR_DMEIE (0x1 << 1) +#define DMA_CR_EN (0x1) + +/* + * Devices + */ + +/** Encapsulates state related to a DMA channel interrupt. */ +typedef struct dma_handler_config { + void (*handler)(void); /**< User-specified channel interrupt + handler */ + nvic_irq_num irq_line; /**< Channel's NVIC interrupt number */ +} dma_handler_config; + +/** DMA device type */ +typedef struct dma_dev { + dma_reg_map *regs; /**< Register map */ + rcc_clk_id clk_id; /**< Clock ID */ + dma_handler_config handlers[]; /**< + * @brief IRQ handlers and NVIC numbers. + * + * @see dma_attach_interrupt() + * @see dma_detach_interrupt() + */ +} dma_dev; + +extern dma_dev *DMA1; +extern dma_dev *DMA2; + +/* + * Convenience functions + */ + +void dma_init(dma_dev *dev); + +/** Flags for DMA transfer configuration. */ +typedef enum dma_mode_flags { + DMA_MEM_2_MEM = 1 << 14, /**< Memory to memory mode */ + DMA_MINC_MODE = 1 << 7, /**< Auto-increment memory address */ + DMA_PINC_MODE = 1 << 6, /**< Auto-increment peripheral address */ + DMA_CIRC_MODE = 1 << 5, /**< Circular mode */ + DMA_FROM_MEM = 1 << 4, /**< Read from memory to peripheral */ + DMA_TRNS_ERR = 1 << 3, /**< Interrupt on transfer error */ + DMA_HALF_TRNS = 1 << 2, /**< Interrupt on half-transfer */ + DMA_TRNS_CMPLT = 1 << 1 /**< Interrupt on transfer completion */ +} dma_mode_flags; + +/** Source and destination transfer sizes. */ +typedef enum dma_xfer_size { + DMA_SIZE_8BITS = 0, /**< 8-bit transfers */ + DMA_SIZE_16BITS = 1, /**< 16-bit transfers */ + DMA_SIZE_32BITS = 2 /**< 32-bit transfers */ +} dma_xfer_size; + +/** DMA channel */ +typedef enum dma_stream { + DMA_STREAM0 = 0, /**< Stream 0 */ + DMA_STREAM1 = 1, /**< Stream 1 */ + DMA_STREAM2 = 2, /**< Stream 2 */ + DMA_STREAM3 = 3, /**< Stream 3 */ + DMA_STREAM4 = 4, /**< Stream 4 */ + DMA_STREAM5 = 5, /**< Stream 5 */ + DMA_STREAM6 = 6, /**< Stream 6 */ + DMA_STREAM7 = 7, /**< Stream 7 */ +} dma_stream; + +static inline void dma_setup_transfer(dma_dev *dev, + dma_stream stream, + __io void *peripheral_address, + __io void *memory_address0, + __io void *memory_address1, + uint32 flags, + uint32 fifo_flags) { + dev->regs->STREAM[stream].CR &= ~DMA_CR_EN; // disable + dev->regs->STREAM[stream].PAR = (uint32)peripheral_address; + dev->regs->STREAM[stream].M0AR = (uint32)memory_address0; + dev->regs->STREAM[stream].M1AR = (uint32)memory_address1; + dev->regs->STREAM[stream].FCR = fifo_flags & 0x87; // mask out reserved bits + dev->regs->STREAM[stream].CR = flags & 0x0feffffe; // mask out reserved and enable +} + +static inline void dma_set_num_transfers(dma_dev *dev, + dma_stream stream, + uint16 num_transfers) { + dev->regs->STREAM[stream].NDTR = num_transfers; +} + +void dma_attach_interrupt(dma_dev *dev, + dma_stream stream, + void (*handler)(void)); + +void dma_detach_interrupt(dma_dev *dev, dma_stream stream); + +static inline void dma_enable(dma_dev *dev, dma_stream stream) { + dev->regs->STREAM[stream].CR |= DMA_CR_EN; +} + +static inline void dma_disable(dma_dev *dev, dma_stream stream) { + dev->regs->STREAM[stream].CR &= ~DMA_CR_EN; +} + +/** + * @brief Check if a DMA stream is enabled + * @param dev DMA device + * @param stream Stream whose enabled bit to check. + */ +static inline uint8 dma_is_stream_enabled(dma_dev *dev, dma_stream stream) { + return (uint8)(dev->regs->STREAM[stream].CR & DMA_CR_EN); +} + +/** + * @brief Get the ISR status bits for a DMA stream. + * + * The bits are returned right-aligned, in the following order: + * transfer error flag, half-transfer flag, transfer complete flag, + * global interrupt flag. + * + * @param dev DMA device + * @param stream Stream whose ISR bits to return. + */ +uint8 dma_get_isr_bits(dma_dev *dev, dma_stream stream); + +/** + * @brief Clear the ISR status bits for a given DMA stream. + * + * @param dev DMA device + * @param stream Stream whose ISR bits to clear. + */ +void dma_clear_isr_bits(dma_dev *dev, dma_stream stream); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/STM32F4/cores/maple/libmaple/gpioF4.c b/STM32F4/cores/maple/libmaple/gpioF4.c new file mode 100644 index 0000000..ba166f5 --- /dev/null +++ b/STM32F4/cores/maple/libmaple/gpioF4.c @@ -0,0 +1,224 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + + #ifdef STM32F4 + +/** + * @file gpio.c + * @brief GPIO initialization routine + */ + +#include "gpio.h" +#include "rcc.h" + +/* + * GPIO devices + */ + +gpio_dev gpioa = { + .regs = GPIOA_BASE, + .clk_id = RCC_GPIOA, + .exti_port = AFIO_EXTI_PA, +}; +/** GPIO port A device. */ +gpio_dev* const GPIOA = &gpioa; + +gpio_dev gpiob = { + .regs = GPIOB_BASE, + .clk_id = RCC_GPIOB, + .exti_port = AFIO_EXTI_PB, +}; +/** GPIO port B device. */ +gpio_dev* const GPIOB = &gpiob; + +gpio_dev gpioc = { + .regs = GPIOC_BASE, + .clk_id = RCC_GPIOC, + .exti_port = AFIO_EXTI_PC, +}; +/** GPIO port C device. */ +gpio_dev* const GPIOC = &gpioc; + +gpio_dev gpiod = { + .regs = GPIOD_BASE, + .clk_id = RCC_GPIOD, + .exti_port = AFIO_EXTI_PD, +}; +/** GPIO port D device. */ +gpio_dev* const GPIOD = &gpiod; + +#ifdef STM32_HIGH_DENSITY +gpio_dev gpioe = { + .regs = GPIOE_BASE, + .clk_id = RCC_GPIOE, + .exti_port = AFIO_EXTI_PE, +}; +/** GPIO port E device. */ +gpio_dev* const GPIOE = &gpioe; + +gpio_dev gpiof = { + .regs = GPIOF_BASE, + .clk_id = RCC_GPIOF, + .exti_port = AFIO_EXTI_PF, +}; +/** GPIO port F device. */ +gpio_dev* const GPIOF = &gpiof; + +gpio_dev gpiog = { + .regs = GPIOG_BASE, + .clk_id = RCC_GPIOG, + .exti_port = AFIO_EXTI_PG, +}; +/** GPIO port G device. */ +gpio_dev* const GPIOG = &gpiog; +#endif + +/* + * GPIO convenience routines + */ + +/** + * Initialize a GPIO device. + * + * Enables the clock for and resets the given device. + * + * @param dev GPIO device to initialize. + */ +void gpio_init(gpio_dev *dev) { + rcc_clk_enable(dev->clk_id); + rcc_reset_dev(dev->clk_id); +} + +/** + * Initialize and reset all available GPIO devices. + */ +void gpio_init_all(void) { + gpio_init(GPIOA); + gpio_init(GPIOB); + gpio_init(GPIOC); + gpio_init(GPIOD); + +#ifdef STM32_HIGH_DENSITY + gpio_init(GPIOE); + gpio_init(GPIOF); + gpio_init(GPIOG); +#endif + +#ifdef ARDUINO_STM32F4_NETDUINO2PLUS + // PA8 Output the Master Clock MCO1 + gpio_set_af_mode(GPIOA, 8, 0); + gpio_set_mode(GPIOA, 8, GPIO_MODE_AF | GPIO_OTYPE_PP | GPIO_OSPEED_100MHZ); + // PB4 as alternate MISO Input + gpio_set_af_mode(GPIOB, 4, 5); + // PA5 as alternate SCK Output + gpio_set_af_mode(GPIOA, 5, 5); + // PA7 as alternate MOSI Output + gpio_set_af_mode(GPIOA, 7, 5); +#endif +} + +/** + * Set the mode of a GPIO pin. + * + * @param dev GPIO device. + * @param pin Pin on the device whose mode to set, 0--15. + * @param mode General purpose or alternate function mode to set the pin to. + * @see gpio_pin_mode + */ +void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode) { + gpio_reg_map *regs = dev->regs; + + //regs->AFR[pin/8] = (regs->AFR[pin/8] & ~(15 << (4*(pin&7)))) | (((mode >> 8) & 15) << (4*(pin&7))); + //gpio_set_af_mode(dev, pin, mode>>8); + + regs->MODER = (regs->MODER & ~( 3 << (2*pin))) | (((mode >> 0) & 3) << (2*pin)); + regs->PUPDR = (regs->PUPDR & ~( 3 << (2*pin))) | (((mode >> 2) & 3) << (2*pin)); + regs->OSPEEDR = (regs->OSPEEDR & ~( 3 << (2*pin))) | (((mode >> 4) & 3) << (2*pin)); + regs->OTYPER = (regs->OTYPER & ~( 1 << (1*pin))) | (((mode >> 6) & 1) << (1*pin)); +} + +/** + * Set the alternate function mode of a GPIO pin. + * + * @param dev GPIO device. + * @param pin Pin on the device whose mode to set, 0--15. + * @param mode alternate function mode to set the pin to. + * @see gpio_pin_mode + */ +void gpio_set_af_mode(gpio_dev *dev, uint8 pin, int mode) { + gpio_reg_map *regs = dev->regs; + + regs->AFR[pin/8] = (regs->AFR[pin/8] & ~(15 << (4*(pin&7)))) | (((mode >> 0) & 15) << (4*(pin&7))); +} + +/* + * AFIO + */ + +/** + * @brief Initialize the AFIO clock, and reset the AFIO registers. + */ +void afio_init(void) { + //rcc_clk_enable(RCC_AFIO); + //rcc_reset_dev(RCC_AFIO); +} + +#define AFIO_EXTI_SEL_MASK 0xF + +/** + * @brief Select a source input for an external interrupt. + * + * @param exti External interrupt. + * @param gpio_port Port which contains pin to use as source input. + * @see afio_exti_num + * @see afio_exti_port + */ +void afio_exti_select(afio_exti_num exti, afio_exti_port gpio_port) { + __io uint32 *exti_cr = &SYSCFG_BASE->EXTICR1 + exti / 4; + uint32 shift = 4 * (exti % 4); + uint32 cr = *exti_cr; + + cr &= ~(AFIO_EXTI_SEL_MASK << shift); + cr |= gpio_port << shift; + *exti_cr = cr; +} + +/** + * @brief Perform an alternate function remap. + * @param remapping Remapping to perform. + */ +#if 0 +void afio_remap(afio_remap_peripheral remapping) { + if (remapping & AFIO_REMAP_USE_MAPR2) { + remapping &= ~AFIO_REMAP_USE_MAPR2; + AFIO_BASE->MAPR2 |= remapping; + } else { + AFIO_BASE->MAPR |= remapping; + } +} +#endif + +#endif diff --git a/STM32F4/cores/maple/libmaple/gpioF4.h b/STM32F4/cores/maple/libmaple/gpioF4.h new file mode 100644 index 0000000..91bd67b --- /dev/null +++ b/STM32F4/cores/maple/libmaple/gpioF4.h @@ -0,0 +1,550 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. +*****************************************************************************/ + +/** + * @file gpio.h + * + * @brief General purpose I/O (GPIO) and Alternate Function I/O + * (AFIO) prototypes, defines, and inlined access functions. + */ + +#ifndef _GPIO_H_ +#define _GPIO_H_ + +#include "libmaple.h" +#include "rcc.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +/* + * GPIO register maps and devices + */ + +/** GPIO register map type */ +typedef struct gpio_reg_map { + __io uint32 MODER; /*!< GPIO port mode register, Address offset: 0x00 */ + __io uint32 OTYPER; /*!< GPIO port output type register, Address offset: 0x04 */ + __io uint32 OSPEEDR; /*!< GPIO port output speed register, Address offset: 0x08 */ + __io uint32 PUPDR; /*!< GPIO port pull-up/pull-down register, Address offset: 0x0C */ + __io uint32 IDR; /*!< GPIO port input data register, Address offset: 0x10 */ + __io uint32 ODR; /*!< GPIO port output data register, Address offset: 0x14 */ + __io uint16 BSRRL; /*!< GPIO port bit set/reset low register, Address offset: 0x18 */ + __io uint16 BSRRH; /*!< GPIO port bit set/reset high register, Address offset: 0x1A */ + __io uint32 LCKR; /*!< GPIO port configuration lock register, Address offset: 0x1C */ + __io uint32 AFR[2]; /*!< GPIO alternate function registers, Address offset: 0x24-0x28 */ +} gpio_reg_map; + + + +/** + * @brief External interrupt line port selector. + * + * Used to determine which GPIO port to map an external interrupt line + * onto. */ +/* (See AFIO sections, below) */ +typedef enum afio_exti_port { + AFIO_EXTI_PA, /**< Use port A (PAx) pin. */ + AFIO_EXTI_PB, /**< Use port B (PBx) pin. */ + AFIO_EXTI_PC, /**< Use port C (PCx) pin. */ + AFIO_EXTI_PD, /**< Use port D (PDx) pin. */ +#ifdef STM32_HIGH_DENSITY + AFIO_EXTI_PE, /**< Use port E (PEx) pin. */ + AFIO_EXTI_PF, /**< Use port F (PFx) pin. */ + AFIO_EXTI_PG, /**< Use port G (PGx) pin. */ +#endif +} afio_exti_port; + +/** GPIO device type */ +typedef struct gpio_dev { + gpio_reg_map *regs; /**< Register map */ + rcc_clk_id clk_id; /**< RCC clock information */ + afio_exti_port exti_port; /**< AFIO external interrupt port value */ +} gpio_dev; + +extern gpio_dev gpioa; +extern gpio_dev* const GPIOA; +extern gpio_dev gpiob; +extern gpio_dev* const GPIOB; +extern gpio_dev gpioc; +extern gpio_dev* const GPIOC; +extern gpio_dev gpiod; +extern gpio_dev* const GPIOD; +#ifdef STM32_HIGH_DENSITY +extern gpio_dev gpioe; +extern gpio_dev* const GPIOE; +extern gpio_dev gpiof; +extern gpio_dev* const GPIOF; +extern gpio_dev gpiog; +extern gpio_dev* const GPIOG; +#endif + +/** GPIO port register map base pointer */ +#define GPIOA_BASE ((struct gpio_reg_map*)0x40020000) +#define GPIOB_BASE ((struct gpio_reg_map*)0x40020400) +#define GPIOC_BASE ((struct gpio_reg_map*)0x40020800) +#define GPIOD_BASE ((struct gpio_reg_map*)0x40020C00) +#ifdef STM32_HIGH_DENSITY +#define GPIOE_BASE ((struct gpio_reg_map*)0x40021000) +#define GPIOF_BASE ((struct gpio_reg_map*)0x40021400) +#define GPIOG_BASE ((struct gpio_reg_map*)0x40021800) +#endif + +/* + * GPIO register bit definitions + */ + +#define GPIO_MODE_INPUT 0 +#define GPIO_MODE_OUTPUT 1 +#define GPIO_MODE_AF 2 +#define GPIO_MODE_ANALOG 3 + +#define GPIO_PUPD_INPUT_FLOATING (0 << 2) +#define GPIO_PUPD_INPUT_PU (1 << 2) +#define GPIO_PUPD_INPUT_PD (2 << 2) + +#define GPIO_OSPEED_2MHZ (0 << 4) +#define GPIO_OSPEED_25MHZ (1 << 4) +#define GPIO_OSPEED_50MHZ (2 << 4) +#define GPIO_OSPEED_100MHZ (3 << 4) + +#define GPIO_OTYPE_PP (0 << 6) +#define GPIO_OTYPE_OD (1 << 6) + +/* +MODER +00: Input (reset state) +01: General purpose output mode +10: Alternate function mode +11: Analog mode + +OTYPER +0: Output push-pull (reset state) +1: Output open-drain + +OSPEEDR +00: 2 MHz Low speed +01: 25 MHz Medium speed +10: 50 MHz Fast speed +11: 100 MHz High speed on 30 pF (80 MHz Output max speed on 15 pF) + +PUPDR +00: No pull-up, pull-down +01: Pull-up +10: Pull-down + +AFRL 4 bit AF00-AF15 +AFRH 4 bit AF00-AF15 +*/ + +/** + * @brief GPIO Pin modes. + * + * These only allow for 50MHZ max output speeds; if you want slower, + * use direct register access. + */ +typedef enum gpio_pin_mode { + GPIO_OUTPUT_PP = (GPIO_MODE_OUTPUT | GPIO_OTYPE_PP | + GPIO_OSPEED_50MHZ), /**< Output push-pull. */ + GPIO_OUTPUT_OD = (GPIO_MODE_OUTPUT | GPIO_OTYPE_OD | + GPIO_OSPEED_50MHZ), /**< Output open-drain. */ + GPIO_AF_OUTPUT_PP = (GPIO_MODE_AF | GPIO_OTYPE_PP | + GPIO_OSPEED_50MHZ), /**< Alternate function + output push-pull. */ + GPIO_AF_OUTPUT_OD = (GPIO_MODE_AF | GPIO_OTYPE_OD | + GPIO_OSPEED_50MHZ), /**< Alternate function + output open drain. */ + GPIO_INPUT_ANALOG = (GPIO_MODE_ANALOG), /**< Analog input. */ + GPIO_INPUT_FLOATING = (GPIO_MODE_INPUT | + GPIO_PUPD_INPUT_FLOATING), /**< Input floating. */ + GPIO_INPUT_PD = (GPIO_MODE_INPUT | + GPIO_PUPD_INPUT_PD), /**< Input pull-down. */ + GPIO_INPUT_PU = (GPIO_MODE_INPUT | + GPIO_PUPD_INPUT_PU), /**< Input pull-up. */ + GPIO_AF_INPUT_PD = (GPIO_MODE_AF | + GPIO_PUPD_INPUT_PD), /**< Input pull-down. */ + GPIO_BIGNUMBER = 0xfff +} gpio_pin_mode; + +/* + * GPIO Convenience routines + */ + +void gpio_init(gpio_dev *dev); +void gpio_init_all(void); +void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode); +void gpio_set_af_mode(gpio_dev *dev, uint8 pin, int mode); + +/** + * @brief Get a GPIO port's corresponding afio_exti_port. + * @param dev GPIO device whose afio_exti_port to return. + */ +static inline afio_exti_port gpio_exti_port(gpio_dev *dev) { + return dev->exti_port; +} + +/** + * Set or reset a GPIO pin. + * + * Pin must have previously been configured to output mode. + * + * @param dev GPIO device whose pin to set. + * @param pin Pin on to set or reset + * @param val If true, set the pin. If false, reset the pin. + */ +static inline void gpio_write_bit(gpio_dev *dev, uint8 pin, uint8 val) { + if (val) { + dev->regs->BSRRL = BIT(pin); + } else { + dev->regs->BSRRH = BIT(pin); + } +} + +/** + * Determine whether or not a GPIO pin is set. + * + * Pin must have previously been configured to input mode. + * + * @param dev GPIO device whose pin to test. + * @param pin Pin on dev to test. + * @return True if the pin is set, false otherwise. + */ +static inline uint32 gpio_read_bit(gpio_dev *dev, uint8 pin) { + return dev->regs->IDR & BIT(pin); +} + +/** + * Toggle a pin configured as output push-pull. + * @param dev GPIO device. + * @param pin Pin on dev to toggle. + */ +static inline void gpio_toggle_bit(gpio_dev *dev, uint8 pin) { + dev->regs->ODR = dev->regs->ODR ^ BIT(pin); +} + +/* + * AFIO register map + */ + +/** AFIO register map */ +typedef struct syscfg_reg_map { + __io uint32 MEMRM; /**< memory remap register */ + __io uint32 PMC; /**< peripheral mode configuration register */ + __io uint32 EXTICR1; /**< External interrupt configuration register 1. */ + __io uint32 EXTICR2; /**< External interrupt configuration register 2. */ + __io uint32 EXTICR3; /**< External interrupt configuration register 3. */ + __io uint32 EXTICR4; /**< External interrupt configuration register 4. */ + __io uint32 CMPCR; /**< Compensation cell control register */ +} syscfg_reg_map; + +/** AFIO register map base pointer. */ +#define SYSCFG_BASE ((struct syscfg_reg_map *)0x40013800) + +/* + * AFIO register bit definitions + */ + +/* Event control register */ + +#define AFIO_EVCR_EVOE (0x1 << 7) +#define AFIO_EVCR_PORT_PA (0x0 << 4) +#define AFIO_EVCR_PORT_PB (0x1 << 4) +#define AFIO_EVCR_PORT_PC (0x2 << 4) +#define AFIO_EVCR_PORT_PD (0x3 << 4) +#define AFIO_EVCR_PORT_PE (0x4 << 4) +#define AFIO_EVCR_PIN_0 0x0 +#define AFIO_EVCR_PIN_1 0x1 +#define AFIO_EVCR_PIN_2 0x2 +#define AFIO_EVCR_PIN_3 0x3 +#define AFIO_EVCR_PIN_4 0x4 +#define AFIO_EVCR_PIN_5 0x5 +#define AFIO_EVCR_PIN_6 0x6 +#define AFIO_EVCR_PIN_7 0x7 +#define AFIO_EVCR_PIN_8 0x8 +#define AFIO_EVCR_PIN_9 0x9 +#define AFIO_EVCR_PIN_10 0xA +#define AFIO_EVCR_PIN_11 0xB +#define AFIO_EVCR_PIN_12 0xC +#define AFIO_EVCR_PIN_13 0xD +#define AFIO_EVCR_PIN_14 0xE +#define AFIO_EVCR_PIN_15 0xF + +/* AF remap and debug I/O configuration register */ + +#define AFIO_MAPR_SWJ_CFG (0x7 << 24) +#define AFIO_MAPR_SWJ_CFG_FULL_SWJ (0x0 << 24) +#define AFIO_MAPR_SWJ_CFG_FULL_SWJ_NO_NJRST (0x1 << 24) +#define AFIO_MAPR_SWJ_CFG_NO_JTAG_SW (0x2 << 24) +#define AFIO_MAPR_SWJ_CFG_NO_JTAG_NO_SW (0x4 << 24) +#define AFIO_MAPR_ADC2_ETRGREG_REMAP BIT(20) +#define AFIO_MAPR_ADC2_ETRGINJ_REMAP BIT(19) +#define AFIO_MAPR_ADC1_ETRGREG_REMAP BIT(18) +#define AFIO_MAPR_ADC1_ETRGINJ_REMAP BIT(17) +#define AFIO_MAPR_TIM5CH4_IREMAP BIT(16) +#define AFIO_MAPR_PD01_REMAP BIT(15) +#define AFIO_MAPR_CAN_REMAP (0x3 << 13) +#define AFIO_MAPR_CAN_REMAP_NONE (0x0 << 13) +#define AFIO_MAPR_CAN_REMAP_PB8_PB9 (0x2 << 13) +#define AFIO_MAPR_CAN_REMAP_PD0_PD1 (0x3 << 13) +#define AFIO_MAPR_TIM4_REMAP BIT(12) +#define AFIO_MAPR_TIM3_REMAP (0x3 << 10) +#define AFIO_MAPR_TIM3_REMAP_NONE (0x0 << 10) +#define AFIO_MAPR_TIM3_REMAP_PARTIAL (0x2 << 10) +#define AFIO_MAPR_TIM3_REMAP_FULL (0x3 << 10) +#define AFIO_MAPR_TIM2_REMAP (0x3 << 8) +#define AFIO_MAPR_TIM2_REMAP_NONE (0x0 << 8) +#define AFIO_MAPR_TIM2_REMAP_PA15_PB3_PA2_PA3 (0x1 << 8) +#define AFIO_MAPR_TIM2_REMAP_PA0_PA1_PB10_PB11 (0x2 << 8) +#define AFIO_MAPR_TIM2_REMAP_FULL (0x3 << 8) +#define AFIO_MAPR_TIM1_REMAP (0x3 << 6) +#define AFIO_MAPR_TIM1_REMAP_NONE (0x0 << 6) +#define AFIO_MAPR_TIM1_REMAP_PARTIAL (0x1 << 6) +#define AFIO_MAPR_TIM1_REMAP_FULL (0x3 << 6) +#define AFIO_MAPR_USART3_REMAP (0x3 << 4) +#define AFIO_MAPR_USART3_REMAP_NONE (0x0 << 4) +#define AFIO_MAPR_USART3_REMAP_PARTIAL (0x1 << 4) +#define AFIO_MAPR_USART3_REMAP_FULL (0x3 << 4) +#define AFIO_MAPR_USART2_REMAP BIT(3) +#define AFIO_MAPR_USART1_REMAP BIT(2) +#define AFIO_MAPR_I2C1_REMAP BIT(1) +#define AFIO_MAPR_SPI1_REMAP BIT(0) + +/* External interrupt configuration register 1 */ + +#define AFIO_EXTICR1_EXTI3 (0xF << 12) +#define AFIO_EXTICR1_EXTI3_PA (0x0 << 12) +#define AFIO_EXTICR1_EXTI3_PB (0x1 << 12) +#define AFIO_EXTICR1_EXTI3_PC (0x2 << 12) +#define AFIO_EXTICR1_EXTI3_PD (0x3 << 12) +#define AFIO_EXTICR1_EXTI3_PE (0x4 << 12) +#define AFIO_EXTICR1_EXTI3_PF (0x5 << 12) +#define AFIO_EXTICR1_EXTI3_PG (0x6 << 12) +#define AFIO_EXTICR1_EXTI2 (0xF << 8) +#define AFIO_EXTICR1_EXTI2_PA (0x0 << 8) +#define AFIO_EXTICR1_EXTI2_PB (0x1 << 8) +#define AFIO_EXTICR1_EXTI2_PC (0x2 << 8) +#define AFIO_EXTICR1_EXTI2_PD (0x3 << 8) +#define AFIO_EXTICR1_EXTI2_PE (0x4 << 8) +#define AFIO_EXTICR1_EXTI2_PF (0x5 << 8) +#define AFIO_EXTICR1_EXTI2_PG (0x6 << 8) +#define AFIO_EXTICR1_EXTI1 (0xF << 4) +#define AFIO_EXTICR1_EXTI1_PA (0x0 << 4) +#define AFIO_EXTICR1_EXTI1_PB (0x1 << 4) +#define AFIO_EXTICR1_EXTI1_PC (0x2 << 4) +#define AFIO_EXTICR1_EXTI1_PD (0x3 << 4) +#define AFIO_EXTICR1_EXTI1_PE (0x4 << 4) +#define AFIO_EXTICR1_EXTI1_PF (0x5 << 4) +#define AFIO_EXTICR1_EXTI1_PG (0x6 << 4) +#define AFIO_EXTICR1_EXTI0 0xF +#define AFIO_EXTICR1_EXTI0_PA 0x0 +#define AFIO_EXTICR1_EXTI0_PB 0x1 +#define AFIO_EXTICR1_EXTI0_PC 0x2 +#define AFIO_EXTICR1_EXTI0_PD 0x3 +#define AFIO_EXTICR1_EXTI0_PE 0x4 +#define AFIO_EXTICR1_EXTI0_PF 0x5 +#define AFIO_EXTICR1_EXTI0_PG 0x6 + +/* External interrupt configuration register 2 */ + +#define AFIO_EXTICR2_EXTI7 (0xF << 12) +#define AFIO_EXTICR2_EXTI7_PA (0x0 << 12) +#define AFIO_EXTICR2_EXTI7_PB (0x1 << 12) +#define AFIO_EXTICR2_EXTI7_PC (0x2 << 12) +#define AFIO_EXTICR2_EXTI7_PD (0x3 << 12) +#define AFIO_EXTICR2_EXTI7_PE (0x4 << 12) +#define AFIO_EXTICR2_EXTI7_PF (0x5 << 12) +#define AFIO_EXTICR2_EXTI7_PG (0x6 << 12) +#define AFIO_EXTICR2_EXTI6 (0xF << 8) +#define AFIO_EXTICR2_EXTI6_PA (0x0 << 8) +#define AFIO_EXTICR2_EXTI6_PB (0x1 << 8) +#define AFIO_EXTICR2_EXTI6_PC (0x2 << 8) +#define AFIO_EXTICR2_EXTI6_PD (0x3 << 8) +#define AFIO_EXTICR2_EXTI6_PE (0x4 << 8) +#define AFIO_EXTICR2_EXTI6_PF (0x5 << 8) +#define AFIO_EXTICR2_EXTI6_PG (0x6 << 8) +#define AFIO_EXTICR2_EXTI5 (0xF << 4) +#define AFIO_EXTICR2_EXTI5_PA (0x0 << 4) +#define AFIO_EXTICR2_EXTI5_PB (0x1 << 4) +#define AFIO_EXTICR2_EXTI5_PC (0x2 << 4) +#define AFIO_EXTICR2_EXTI5_PD (0x3 << 4) +#define AFIO_EXTICR2_EXTI5_PE (0x4 << 4) +#define AFIO_EXTICR2_EXTI5_PF (0x5 << 4) +#define AFIO_EXTICR2_EXTI5_PG (0x6 << 4) +#define AFIO_EXTICR2_EXTI4 0xF +#define AFIO_EXTICR2_EXTI4_PA 0x0 +#define AFIO_EXTICR2_EXTI4_PB 0x1 +#define AFIO_EXTICR2_EXTI4_PC 0x2 +#define AFIO_EXTICR2_EXTI4_PD 0x3 +#define AFIO_EXTICR2_EXTI4_PE 0x4 +#define AFIO_EXTICR2_EXTI4_PF 0x5 +#define AFIO_EXTICR2_EXTI4_PG 0x6 + +/* AF remap and debug I/O configuration register 2 */ + +#define AFIO_MAPR2_FSMC_NADV BIT(10) +#define AFIO_MAPR2_TIM14_REMAP BIT(9) +#define AFIO_MAPR2_TIM13_REMAP BIT(8) +#define AFIO_MAPR2_TIM11_REMAP BIT(7) +#define AFIO_MAPR2_TIM10_REMAP BIT(6) +#define AFIO_MAPR2_TIM9_REMAP BIT(5) + +/* + * AFIO convenience routines + */ + +void afio_init(void); + +/** + * External interrupt line numbers. + */ +typedef enum afio_exti_num { + AFIO_EXTI_0, /**< External interrupt line 0. */ + AFIO_EXTI_1, /**< External interrupt line 1. */ + AFIO_EXTI_2, /**< External interrupt line 2. */ + AFIO_EXTI_3, /**< External interrupt line 3. */ + AFIO_EXTI_4, /**< External interrupt line 4. */ + AFIO_EXTI_5, /**< External interrupt line 5. */ + AFIO_EXTI_6, /**< External interrupt line 6. */ + AFIO_EXTI_7, /**< External interrupt line 7. */ + AFIO_EXTI_8, /**< External interrupt line 8. */ + AFIO_EXTI_9, /**< External interrupt line 9. */ + AFIO_EXTI_10, /**< External interrupt line 10. */ + AFIO_EXTI_11, /**< External interrupt line 11. */ + AFIO_EXTI_12, /**< External interrupt line 12. */ + AFIO_EXTI_13, /**< External interrupt line 13. */ + AFIO_EXTI_14, /**< External interrupt line 14. */ + AFIO_EXTI_15, /**< External interrupt line 15. */ +} afio_exti_num; + +void afio_exti_select(afio_exti_num exti, afio_exti_port gpio_port); + +/* HACK: Use upper bit to denote MAPR2, Bit 31 is reserved and + * not used in either MAPR or MAPR2 */ +#define AFIO_REMAP_USE_MAPR2 (1 << 31) + +/** + * @brief Available peripheral remaps. + * @see afio_remap() + */ +typedef enum afio_remap_peripheral { + AFIO_REMAP_ADC2_ETRGREG = AFIO_MAPR_ADC2_ETRGREG_REMAP, /**< + ADC 2 external trigger regular conversion remapping */ + AFIO_REMAP_ADC2_ETRGINJ = AFIO_MAPR_ADC2_ETRGINJ_REMAP, /**< + ADC 2 external trigger injected conversion remapping */ + AFIO_REMAP_ADC1_ETRGREG = AFIO_MAPR_ADC1_ETRGREG_REMAP, /**< + ADC 1 external trigger regular conversion remapping */ + AFIO_REMAP_ADC1_ETRGINJ = AFIO_MAPR_ADC1_ETRGINJ_REMAP, /**< + ADC 1 external trigger injected conversion remapping */ + AFIO_REMAP_TIM5CH4_I = AFIO_MAPR_TIM5CH4_IREMAP, /**< + Timer 5 channel 4 internal remapping */ + AFIO_REMAP_PD01 = AFIO_MAPR_PD01_REMAP, /**< + Port D0/Port D1 mapping on OSC_IN/OSC_OUT */ + AFIO_REMAP_CAN_1 = AFIO_MAPR_CAN_REMAP_PB8_PB9, /**< + CAN alternate function remapping 1 (RX on PB8, TX on PB9) */ + AFIO_REMAP_CAN_2 = AFIO_MAPR_CAN_REMAP_PD0_PD1, /**< + CAN alternate function remapping 2 (RX on PD0, TX on PD1) */ + AFIO_REMAP_TIM4 = AFIO_MAPR_TIM4_REMAP, /**< + Timer 4 remapping */ + AFIO_REMAP_TIM3_PARTIAL = AFIO_MAPR_TIM3_REMAP_PARTIAL, /**< + Timer 3 partial remapping */ + AFIO_REMAP_TIM3_FULL = AFIO_MAPR_TIM3_REMAP_FULL, /**< + Timer 3 full remapping */ + AFIO_REMAP_TIM2_PARTIAL_1 = AFIO_MAPR_TIM2_REMAP_PA15_PB3_PA2_PA3, /**< + Timer 2 partial remapping 1 (CH1 and ETR on PA15, CH2 on PB3, CH3 + on PA2, CH4 on PA3) */ + AFIO_REMAP_TIM2_PARTIAL_2 = AFIO_MAPR_TIM2_REMAP_PA0_PA1_PB10_PB11, /**< + Timer 2 partial remapping 2 (CH1 and ETR on PA0, CH2 on PA1, CH3 + on PB10, CH4 on PB11) */ + AFIO_REMAP_TIM2_FULL = AFIO_MAPR_TIM2_REMAP_FULL, /**< + Timer 2 full remapping */ + AFIO_REMAP_USART2 = AFIO_MAPR_USART2_REMAP, /**< + USART 2 remapping */ + AFIO_REMAP_USART1 = AFIO_MAPR_USART1_REMAP, /**< + USART 1 remapping */ + AFIO_REMAP_I2C1 = AFIO_MAPR_I2C1_REMAP, /**< + I2C 1 remapping */ + AFIO_REMAP_SPI1 = AFIO_MAPR_SPI1_REMAP, /**< + SPI 1 remapping */ + AFIO_REMAP_FSMC_NADV = (AFIO_MAPR2_FSMC_NADV | + AFIO_REMAP_USE_MAPR2), /**< + NADV signal not connected */ + AFIO_REMAP_TIM14 = (AFIO_MAPR2_TIM14_REMAP | + AFIO_REMAP_USE_MAPR2), /**< + Timer 14 remapping */ + AFIO_REMAP_TIM13 = (AFIO_MAPR2_TIM13_REMAP | + AFIO_REMAP_USE_MAPR2), /**< + Timer 13 remapping */ + AFIO_REMAP_TIM11 = (AFIO_MAPR2_TIM11_REMAP | + AFIO_REMAP_USE_MAPR2), /**< + Timer 11 remapping */ + AFIO_REMAP_TIM10 = (AFIO_MAPR2_TIM10_REMAP | + AFIO_REMAP_USE_MAPR2), /**< + Timer 10 remapping */ + AFIO_REMAP_TIM9 = (AFIO_MAPR2_TIM9_REMAP | + AFIO_REMAP_USE_MAPR2) /**< + Timer 9 */ +} afio_remap_peripheral; + +void afio_remap(afio_remap_peripheral p); + +/** + * @brief Debug port configuration + * + * Used to configure the behavior of JTAG and Serial Wire (SW) debug + * ports and their associated GPIO pins. + * + * @see afio_cfg_debug_ports() + */ +typedef enum afio_debug_cfg { + AFIO_DEBUG_FULL_SWJ = AFIO_MAPR_SWJ_CFG_FULL_SWJ, /**< + Full Serial Wire and JTAG debug */ + AFIO_DEBUG_FULL_SWJ_NO_NJRST = AFIO_MAPR_SWJ_CFG_FULL_SWJ_NO_NJRST, /**< + Full Serial Wire and JTAG, but no NJTRST. */ + AFIO_DEBUG_SW_ONLY = AFIO_MAPR_SWJ_CFG_NO_JTAG_SW, /**< + Serial Wire debug only (JTAG-DP disabled, + SW-DP enabled) */ + AFIO_DEBUG_NONE = AFIO_MAPR_SWJ_CFG_NO_JTAG_NO_SW /**< + No debug; all JTAG and SW pins are free + for use as GPIOs. */ +} afio_debug_cfg; + +/** + * @brief Enable or disable the JTAG and SW debug ports. + * @param config Desired debug port configuration + * @see afio_debug_cfg + */ +static inline void afio_cfg_debug_ports(afio_debug_cfg config) { + //__io uint32 *mapr = &AFIO_BASE->MAPR; + //*mapr = (*mapr & ~AFIO_MAPR_SWJ_CFG) | config; +} + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/STM32F4/cores/maple/libmaple/rccF4.c b/STM32F4/cores/maple/libmaple/rccF4.c new file mode 100644 index 0000000..dd2ea26 --- /dev/null +++ b/STM32F4/cores/maple/libmaple/rccF4.c @@ -0,0 +1,707 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +#ifdef STM32F4 + +/** + * @file rcc.c + * @brief Implements pretty much only the basic clock setup on the + * stm32, clock enable/disable and peripheral reset commands. + */ + +#include "libmaple.h" +#include "flash.h" +#include "gpio.h" +#include "rcc.h" +#include "bitband.h" + +#define APB1 RCC_APB1 +#define APB2 RCC_APB2 +#define AHB1 RCC_AHB1 +#define AHB2 RCC_AHB2 +#define AHB3 RCC_AHB3 + +struct rcc_dev_info { + const rcc_clk_domain clk_domain; + const uint8 line_num; +}; + +static uint32 rcc_dev_clk_speed_table[AHB3]; + +/* Device descriptor table, maps rcc_clk_id onto bus and enable/reset + * register bit numbers. */ +static const struct rcc_dev_info rcc_dev_table[] = { + [RCC_GPIOA] = { .clk_domain = AHB1, .line_num = 0 }, //* + [RCC_GPIOB] = { .clk_domain = AHB1, .line_num = 1 }, //* + [RCC_GPIOC] = { .clk_domain = AHB1, .line_num = 2 }, //* + [RCC_GPIOD] = { .clk_domain = AHB1, .line_num = 3 }, //* + +// [RCC_AFIO] = { .clk_domain = APB2, .line_num = 0 }, + [RCC_ADC1] = { .clk_domain = APB2, .line_num = 8 }, //* + [RCC_ADC2] = { .clk_domain = APB2, .line_num = 9 }, //* + [RCC_ADC3] = { .clk_domain = APB2, .line_num = 10 }, //* + [RCC_USART1] = { .clk_domain = APB2, .line_num = 4 }, //* + [RCC_USART2] = { .clk_domain = APB1, .line_num = 17 }, //unchanged + [RCC_USART3] = { .clk_domain = APB1, .line_num = 18 }, //unchanged + [RCC_TIMER1] = { .clk_domain = APB2, .line_num = 0 }, //* + [RCC_TIMER2] = { .clk_domain = APB1, .line_num = 0 }, //unchanged + [RCC_TIMER3] = { .clk_domain = APB1, .line_num = 1 }, //unchanged + [RCC_TIMER4] = { .clk_domain = APB1, .line_num = 2 }, //unchanged + [RCC_SPI1] = { .clk_domain = APB2, .line_num = 12 }, //unchanged + [RCC_SPI2] = { .clk_domain = APB1, .line_num = 14 }, //unchanged + [RCC_DMA1] = { .clk_domain = AHB1, .line_num = 21 }, //* + [RCC_PWR] = { .clk_domain = APB1, .line_num = 28}, //unchanged + [RCC_BKP] = { .clk_domain = AHB1, .line_num = 18}, //* + [RCC_I2C1] = { .clk_domain = APB1, .line_num = 21 }, //unchanged + [RCC_I2C2] = { .clk_domain = APB1, .line_num = 22 }, //unchanged + [RCC_CRC] = { .clk_domain = AHB1, .line_num = 12}, //* +// [RCC_FLITF] = { .clk_domain = AHB, .line_num = 4}, +// [RCC_SRAM] = { .clk_domain = AHB, .line_num = 2}, + + [RCC_GPIOE] = { .clk_domain = AHB1, .line_num = 4 }, //* + [RCC_GPIOF] = { .clk_domain = AHB1, .line_num = 5 }, //* + [RCC_GPIOG] = { .clk_domain = AHB1, .line_num = 6 }, //* + [RCC_UART4] = { .clk_domain = APB1, .line_num = 19 }, //unchanged + [RCC_UART5] = { .clk_domain = APB1, .line_num = 20 }, //unchanged + [RCC_TIMER5] = { .clk_domain = APB1, .line_num = 3 }, //unchanged + [RCC_TIMER6] = { .clk_domain = APB1, .line_num = 4 }, //unchanged + [RCC_TIMER7] = { .clk_domain = APB1, .line_num = 5 }, //unchanged + [RCC_TIMER8] = { .clk_domain = APB2, .line_num = 1 }, //* + [RCC_FSMC] = { .clk_domain = AHB3, .line_num = 0 }, //* + [RCC_DAC] = { .clk_domain = APB1, .line_num = 29 }, //unchanged + [RCC_DMA2] = { .clk_domain = AHB1, .line_num = 22 }, //* + [RCC_SDIO] = { .clk_domain = APB2, .line_num = 11 }, //* + [RCC_SPI3] = { .clk_domain = APB1, .line_num = 15 }, //unchanged + [RCC_TIMER9] = { .clk_domain = APB2, .line_num = 16 }, //* + [RCC_TIMER10] = { .clk_domain = APB2, .line_num = 17 }, //* + [RCC_TIMER11] = { .clk_domain = APB2, .line_num = 18 }, //* + [RCC_TIMER12] = { .clk_domain = APB1, .line_num = 6 }, //unchanged + [RCC_TIMER13] = { .clk_domain = APB1, .line_num = 7 }, //unchanged + [RCC_TIMER14] = { .clk_domain = APB1, .line_num = 8 }, //unchanged + [RCC_USBFS] = { .clk_domain = AHB2, .line_num = 7 }, //* + [RCC_SYSCFG] = { .clk_domain = APB2, .line_num = 14 }, //* + [RCC_SPI4] = { .clk_domain = APB1, .line_num = 15 }, +}; + +/** + * @brief Initialize the clock control system. Initializes the system + * clock source to use the PLL driven by an external oscillator + * @param sysclk_src system clock source, must be PLL + * @param pll_src pll clock source, must be HSE + * @param pll_mul pll multiplier + */ + +#define HSE_STARTUP_TIMEOUT ((uint16)0x0500) /*!< Time out for HSE start up */ +#define RCC_CFGR_HPRE_DIV1 ((uint32)0x00000000) /*!< SYSCLK not divided */ +#define RCC_CFGR_PPRE1_DIV2 ((uint32)0x00001000) /*!< HCLK divided by 2 */ +#define RCC_CFGR_PPRE1_DIV4 ((uint32)0x00001400) /*!< HCLK divided by 4 */ +#define RCC_CFGR_PPRE2_DIV1 ((uint32)0x00000000) /*!< HCLK not divided */ +#define RCC_CFGR_PPRE2_DIV2 ((uint32)0x00008000) /*!< HCLK divided by 2 */ + +#define RCC_PLLCFGR_PLLSRC_HSE ((uint32)0x00400000) + +/******************* Bits definition for FLASH_ACR register *****************/ +//#define FLASH_ACR_LATENCY ((uint32_t)0x00000007) +#define FLASH_ACR_LATENCY_0WS ((uint32)0x00000000) +#define FLASH_ACR_LATENCY_1WS ((uint32)0x00000001) +#define FLASH_ACR_LATENCY_2WS ((uint32)0x00000002) +#define FLASH_ACR_LATENCY_3WS ((uint32)0x00000003) +#define FLASH_ACR_LATENCY_4WS ((uint32)0x00000004) +#define FLASH_ACR_LATENCY_5WS ((uint32)0x00000005) +#define FLASH_ACR_LATENCY_6WS ((uint32)0x00000006) +#define FLASH_ACR_LATENCY_7WS ((uint32)0x00000007) + +#define FLASH_ACR_PRFTEN ((uint32)0x00000100) +#define FLASH_ACR_ICEN ((uint32)0x00000200) +#define FLASH_ACR_DCEN ((uint32)0x00000400) +#define FLASH_ACR_ICRST ((uint32)0x00000800) +#define FLASH_ACR_DCRST ((uint32)0x00001000) +#define FLASH_ACR_BYTE0_ADDRESS ((uint32)0x40023C00) +#define FLASH_ACR_BYTE2_ADDRESS ((uint32)0x40023C03) + +typedef struct +{ + __io uint32 CR; /*!< PWR power control register, Address offset: 0x00 */ + __io uint32 CSR; /*!< PWR power control/status register, Address offset: 0x04 */ +} PWR_TypeDef; + +#define PWR_BASE (0x40007000) +#define PWR ((PWR_TypeDef *) PWR_BASE) +#define PWR_CR_VOS ((uint16)0x4000) /*!< Regulator voltage scaling output selection */ + +typedef struct +{ + __io uint32 ACR; /*!< FLASH access control register, Address offset: 0x00 */ + __io uint32 KEYR; /*!< FLASH key register, Address offset: 0x04 */ + __io uint32 OPTKEYR; /*!< FLASH option key register, Address offset: 0x08 */ + __io uint32 SR; /*!< FLASH status register, Address offset: 0x0C */ + __io uint32 CR; /*!< FLASH control register, Address offset: 0x10 */ + __io uint32 OPTCR; /*!< FLASH option control register, Address offset: 0x14 */ +} FLASH_TypeDef; + +#define FLASH_R_BASE (0x40023C00) +#define FLASH ((FLASH_TypeDef *) FLASH_R_BASE) +#define RESET 0 + +typedef uint32 uint32_t; + +void InitMCO1() +{ + rcc_reg_map *RCC = RCC_BASE; + // Turn MCO1 Master Clock Output mode + RCC->CFGR &= RCC_CFGR_MCO1_RESET_MASK; + RCC->CFGR |= RCC_CFGR_MCO1Source_HSE | RCC_CFGR_MCO1Div_1; + // PA8 Output the Master Clock MCO1 + gpio_set_af_mode(GPIOA, 8, 0); + gpio_set_mode(GPIOA, 8, GPIO_MODE_AF | GPIO_OTYPE_PP | GPIO_OSPEED_100MHZ); +} + + +void SetupClock72MHz() +{ + uint32_t SystemCoreClock = 72000000; + + /******************************************************************************/ + /* PLL (clocked by HSE) used as System clock source */ + /******************************************************************************/ + /************************* PLL Parameters *************************************/ + /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */ + int PLL_M = 4; + int PLL_N = 216; + + /* SYSCLK = PLL_VCO / PLL_P */ + int PLL_P = 6; + + /* USB OTG FS, SDIO and RNG Clock = PLL_VCO / PLLQ */ + int PLL_Q = 9; + + + uint32 StartUpCounter = 0, HSEStatus = 0; + rcc_reg_map *RCC = RCC_BASE; + + /* Enable HSE */ + RCC->CR |= ((uint32_t)RCC_CR_HSEON); + + /* Wait till HSE is ready and if Time out is reached exit */ + do + { + HSEStatus = RCC->CR & RCC_CR_HSERDY; + StartUpCounter++; + } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); + + if ((RCC->CR & RCC_CR_HSERDY) != RESET) + { + HSEStatus = (uint32_t)0x01; + } + else + { + HSEStatus = (uint32_t)0x00; + } + + if (HSEStatus == (uint32_t)0x01) + { + /* Select regulator voltage output Scale 2 mode, System frequency up to 144 MHz */ + RCC->APB1ENR |= RCC_APB1ENR_PWREN; + PWR->CR &= (uint32_t)~(PWR_CR_VOS); + + /* HCLK = SYSCLK / 1*/ + RCC->CFGR |= RCC_CFGR_HPRE_DIV1; + + /* PCLK2 = HCLK / 1*/ + RCC->CFGR |= RCC_CFGR_PPRE2_DIV1; + + /* PCLK1 = HCLK / 2*/ + RCC->CFGR |= RCC_CFGR_PPRE1_DIV2; + + // save bus clock values + rcc_dev_clk_speed_table[RCC_AHB1] = (SystemCoreClock/1); + rcc_dev_clk_speed_table[RCC_APB2] = (SystemCoreClock/1); + rcc_dev_clk_speed_table[RCC_APB1] = (SystemCoreClock/2); + + /* Configure the main PLL */ + RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) | + (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24); + + /* Enable the main PLL */ + RCC->CR |= RCC_CR_PLLON; + + /* Wait till the main PLL is ready */ + while((RCC->CR & RCC_CR_PLLRDY) == 0) + { + } + + /* Configure Flash prefetch, Instruction cache, Data cache and wait state */ + FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_2WS; + + /* Select the main PLL as system clock source */ + RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); + RCC->CFGR |= RCC_CFGR_SW_PLL; + + /* Wait till the main PLL is used as system clock source */ + while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL); + { + } + } + else + { /* If HSE fails to start-up, the application will have wrong clock + configuration. User can add here some code to deal with this error */ + } +} + + +void SetupClock120MHz() +{ + uint32_t SystemCoreClock = 120000000; + + /******************************************************************************/ + /* PLL (clocked by HSE) used as System clock source */ + /******************************************************************************/ + /************************* PLL Parameters *************************************/ + /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */ + int PLL_M = 8; + int PLL_N = 240; + + /* SYSCLK = PLL_VCO / PLL_P */ + int PLL_P = 2; + + /* USB OTG FS, SDIO and RNG Clock = PLL_VCO / PLLQ */ + int PLL_Q = 5; + + + uint32 StartUpCounter = 0, HSEStatus = 0; + rcc_reg_map *RCC = RCC_BASE; + + /* Enable HSE */ + RCC->CR |= ((uint32_t)RCC_CR_HSEON); + + /* Wait till HSE is ready and if Time out is reached exit */ + do + { + HSEStatus = RCC->CR & RCC_CR_HSERDY; + StartUpCounter++; + } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); + + if ((RCC->CR & RCC_CR_HSERDY) != RESET) + { + HSEStatus = (uint32_t)0x01; + } + else + { + HSEStatus = (uint32_t)0x00; + } + + if (HSEStatus == (uint32_t)0x01) + { + /* Select regulator voltage output Scale 2 mode, System frequency up to 144 MHz */ + RCC->APB1ENR |= RCC_APB1ENR_PWREN; + PWR->CR &= (uint32_t)~(PWR_CR_VOS); + + /* HCLK = SYSCLK / 1*/ + RCC->CFGR |= RCC_CFGR_HPRE_DIV1; + + /* PCLK2 = HCLK / 2*/ + RCC->CFGR |= RCC_CFGR_PPRE2_DIV2; + + /* PCLK1 = HCLK / 4*/ + RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; + + // save bus clock values + rcc_dev_clk_speed_table[RCC_AHB1] = (SystemCoreClock/1); + rcc_dev_clk_speed_table[RCC_APB2] = (SystemCoreClock/2); + rcc_dev_clk_speed_table[RCC_APB1] = (SystemCoreClock/4); + + /* Configure the main PLL */ + RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) | + (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24); + + /* Enable the main PLL */ + RCC->CR |= RCC_CR_PLLON; + + /* Wait till the main PLL is ready */ + while((RCC->CR & RCC_CR_PLLRDY) == 0) + { + } + + /* Configure Flash prefetch, Instruction cache, Data cache and wait state */ + FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_3WS; + + /* Select the main PLL as system clock source */ + RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); + RCC->CFGR |= RCC_CFGR_SW_PLL; + + /* Wait till the main PLL is used as system clock source */ + while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL); + { + } + } + else + { /* If HSE fails to start-up, the application will have wrong clock + configuration. User can add here some code to deal with this error */ + } +} + + +void SetupClock168MHz() +{ + uint32_t SystemCoreClock = 168000000; + + /******************************************************************************/ + /* PLL (clocked by HSE) used as System clock source */ + /******************************************************************************/ + /************************* PLL Parameters *************************************/ + /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */ +#ifdef ARDUINO_STM32F4_NETDUINO2PLUS + int PLL_M = 25; // The NETDUINO has a 25MHz external oscillator +#else + int PLL_M = 8; +#endif + int PLL_N = 336; + + /* SYSCLK = PLL_VCO / PLL_P */ + int PLL_P = 2; + + /* USB OTG FS, SDIO and RNG Clock = PLL_VCO / PLLQ */ + int PLL_Q = 7; + + + uint32 StartUpCounter = 0, HSEStatus = 0; + rcc_reg_map *RCC = RCC_BASE; + +#ifdef ARDUINO_STM32F4_NETDUINO2PLUS + InitMCO1(); +#endif + + /* Enable HSE */ + RCC->CR |= ((uint32_t)RCC_CR_HSEON); + + /* Wait till HSE is ready and if Time out is reached exit */ + do + { + HSEStatus = RCC->CR & RCC_CR_HSERDY; + StartUpCounter++; + } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); + + if ((RCC->CR & RCC_CR_HSERDY) != RESET) + { + HSEStatus = (uint32_t)0x01; + } + else + { + HSEStatus = (uint32_t)0x00; + } + + if (HSEStatus == (uint32_t)0x01) + { + /* Select regulator voltage output Scale 1 mode, System frequency up to 168 MHz */ + RCC->APB1ENR |= RCC_APB1ENR_PWREN; + PWR->CR |= PWR_CR_VOS; + + /* HCLK = SYSCLK / 1*/ + RCC->CFGR |= RCC_CFGR_HPRE_DIV1; + + /* PCLK2 = HCLK / 2*/ + RCC->CFGR |= RCC_CFGR_PPRE2_DIV2; + + /* PCLK1 = HCLK / 4*/ + RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; + + // save bus clock values + rcc_dev_clk_speed_table[RCC_AHB1] = (SystemCoreClock/1); + rcc_dev_clk_speed_table[RCC_APB2] = (SystemCoreClock/2); + rcc_dev_clk_speed_table[RCC_APB1] = (SystemCoreClock/4); + + /* Configure the main PLL */ + RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) | + (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24); + + /* Enable the main PLL */ + RCC->CR |= RCC_CR_PLLON; + + /* Wait till the main PLL is ready */ + while((RCC->CR & RCC_CR_PLLRDY) == 0) + { + } + + /* Configure Flash prefetch, Instruction cache, Data cache and wait state */ + FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS; + + /* Select the main PLL as system clock source */ + RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); + RCC->CFGR |= RCC_CFGR_SW_PLL; + + /* Wait till the main PLL is used as system clock source */ + while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL); + { + } + } + else + { /* If HSE fails to start-up, the application will have wrong clock + configuration. User can add here some code to deal with this error */ + } +} + + +void rcc_clk_init(rcc_sysclk_src sysclk_src, + rcc_pllsrc pll_src, + rcc_pll_multiplier pll_mul) { + + //SetupClock72MHz(); +#if STM32_TICKS_PER_US == 168 + SetupClock168MHz(); +#endif +#if STM32_TICKS_PER_US == 120 + SetupClock120MHz(); +#endif +#if STM32_TICKS_PER_US == 72 + SetupClock72MHz(); +#endif +} + + + + +#define PLL_M 8 +#define PLL_N 240 +/* SYSCLK = PLL_VCO / PLL_P */ +#define PLL_P 2 + +/* USB OTG FS, SDIO and RNG Clock = PLL_VCO / PLLQ */ +#define PLL_Q 5 + + +void rcc_clk_init2(rcc_sysclk_src sysclk_src, + rcc_pllsrc pll_src, + rcc_pll_multiplier pll_mul) { + +/******************************************************************************/ +/* PLL (clocked by HSE) used as System clock source */ +/******************************************************************************/ + uint32 StartUpCounter = 0, HSEStatus = 0; + rcc_reg_map *pRCC = RCC_BASE; + + /* Enable HSE */ + pRCC->CR |= RCC_CR_HSEON; + + /* Wait till HSE is ready and if Time out is reached exit */ + do + { + HSEStatus = pRCC->CR & RCC_CR_HSERDY; + StartUpCounter++; + } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); + + if ((pRCC->CR & RCC_CR_HSERDY) != 0) + { + HSEStatus = 0x01; + } + else + { + HSEStatus = 0x00; + } + + if (HSEStatus == 0x01) + { + /* HCLK = SYSCLK / 1*/ + pRCC->CFGR |= RCC_CFGR_HPRE_DIV1; + + /* PCLK2 = HCLK / 2*/ + pRCC->CFGR |= RCC_CFGR_PPRE2_DIV2; + + /* PCLK1 = HCLK / 4*/ + pRCC->CFGR |= RCC_CFGR_PPRE1_DIV4; + + /* Configure the main PLL */ + pRCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) | + (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24); + + /* Enable the main PLL */ + pRCC->CR |= RCC_CR_PLLON; + + /* Wait till the main PLL is ready */ + while((pRCC->CR & RCC_CR_PLLRDY) == 0) + { + } + + /* Configure Flash prefetch, Instruction cache, Data cache and wait state */ + ((FLASH_TypeDef*)FLASH)->ACR = FLASH_ACR_PRFTEN |FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_3WS; + + /* Select the main PLL as system clock source */ + pRCC->CFGR &= ~RCC_CFGR_SW; + pRCC->CFGR |= RCC_CFGR_SW_PLL; + + /* Wait till the main PLL is used as system clock source */ + while ((pRCC->CFGR & RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL); + { + } + } + else + { /* If HSE fails to start-up, the application will have wrong clock + configuration. User can add here some code to deal with this error */ + } + +#if 0 + uint32 cfgr = 0; + uint32 cr; + + /* Assume that we're going to clock the chip off the PLL, fed by + * the HSE */ + ASSERT(sysclk_src == RCC_CLKSRC_PLL && + pll_src == RCC_PLLSRC_HSE); + + RCC_BASE->CFGR = pll_src | pll_mul; + + /* Turn on the HSE */ + cr = RCC_BASE->CR; + cr |= RCC_CR_HSEON; + RCC_BASE->CR = cr; + while (!(RCC_BASE->CR & RCC_CR_HSERDY)) + ; + + /* Now the PLL */ + cr |= RCC_CR_PLLON; + RCC_BASE->CR = cr; + while (!(RCC_BASE->CR & RCC_CR_PLLRDY)) + ; + + /* Finally, let's switch over to the PLL */ + cfgr &= ~RCC_CFGR_SW; + cfgr |= RCC_CFGR_SW_PLL; + RCC_BASE->CFGR = cfgr; + while ((RCC_BASE->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) + ; +#endif +} + +/** + * @brief Turn on the clock line on a peripheral + * @param id Clock ID of the peripheral to turn on. + */ +void rcc_clk_enable(rcc_clk_id id) { + static const __io uint32* enable_regs[] = { + [APB1] = &RCC_BASE->APB1ENR, + [APB2] = &RCC_BASE->APB2ENR, + [AHB1] = &RCC_BASE->AHB1ENR, + [AHB2] = &RCC_BASE->AHB2ENR, + [AHB3] = &RCC_BASE->AHB3ENR, + }; + + rcc_clk_domain clk_domain = rcc_dev_clk(id); + __io uint32* enr = (__io uint32*)enable_regs[clk_domain]; + uint8 lnum = rcc_dev_table[id].line_num; + + bb_peri_set_bit(enr, lnum, 1); +} + +/** + * @brief Turn on the clock line on a peripheral + * @param id Clock ID of the peripheral to turn on. + */ +void rcc_clk_disable(rcc_clk_id id) { + static const __io uint32* enable_regs[] = { + [APB1] = &RCC_BASE->APB1ENR, + [APB2] = &RCC_BASE->APB2ENR, + [AHB1] = &RCC_BASE->AHB1ENR, + [AHB2] = &RCC_BASE->AHB2ENR, + [AHB3] = &RCC_BASE->AHB3ENR, + }; + + rcc_clk_domain clk_domain = rcc_dev_clk(id); + __io uint32* enr = (__io uint32*)enable_regs[clk_domain]; + uint8 lnum = rcc_dev_table[id].line_num; + + bb_peri_set_bit(enr, lnum, 0); +} + +/** + * @brief Reset a peripheral. + * @param id Clock ID of the peripheral to reset. + */ +void rcc_reset_dev(rcc_clk_id id) { + static const __io uint32* reset_regs[] = { + [APB1] = &RCC_BASE->APB1RSTR, + [APB2] = &RCC_BASE->APB2RSTR, + [AHB1] = &RCC_BASE->AHB1RSTR, + [AHB2] = &RCC_BASE->AHB2RSTR, + [AHB3] = &RCC_BASE->AHB3RSTR, + }; + + rcc_clk_domain clk_domain = rcc_dev_clk(id); + __io void* addr = (__io void*)reset_regs[clk_domain]; + uint8 lnum = rcc_dev_table[id].line_num; + + bb_peri_set_bit(addr, lnum, 1); + bb_peri_set_bit(addr, lnum, 0); +} + +/** + * @brief Get a peripheral's clock domain + * @param id Clock ID of the peripheral whose clock domain to return + * @return Clock source for the given clock ID + */ +rcc_clk_domain rcc_dev_clk(rcc_clk_id id) { + return rcc_dev_table[id].clk_domain; +} + +/** + * @brief Get a peripheral's clock domain speed + * @param id Clock ID of the peripheral whose clock domain speed to return + * @return Clock speed for the given clock ID + */ +uint32 rcc_dev_clk_speed(rcc_clk_id id) { + return rcc_dev_clk_speed_table[rcc_dev_clk(id)]; +} + +/** + * @brief Get a peripheral's timer clock domain speed + * @param id Clock ID of the peripheral whose clock domain speed to return + * @return Clock speed for the given clock ID + */ +uint32 rcc_dev_timer_clk_speed(rcc_clk_id id) { + return 2*rcc_dev_clk_speed(id); +} + +/** + * @brief Set the divider on a peripheral prescaler + * @param prescaler prescaler to set + * @param divider prescaler divider + */ +void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider) { +#if 0 + static const uint32 masks[] = { + [RCC_PRESCALER_AHB] = RCC_CFGR_HPRE, + [RCC_PRESCALER_APB1] = RCC_CFGR_PPRE1, + [RCC_PRESCALER_APB2] = RCC_CFGR_PPRE2, + [RCC_PRESCALER_USB] = RCC_CFGR_USBPRE, + [RCC_PRESCALER_ADC] = RCC_CFGR_ADCPRE, + }; + + uint32 cfgr = RCC_BASE->CFGR; + cfgr &= ~masks[prescaler]; + cfgr |= divider; + RCC_BASE->CFGR = cfgr; +#endif +} + +#endif diff --git a/STM32F4/cores/maple/libmaple/rccF4.h b/STM32F4/cores/maple/libmaple/rccF4.h new file mode 100644 index 0000000..99c5ff2 --- /dev/null +++ b/STM32F4/cores/maple/libmaple/rccF4.h @@ -0,0 +1,642 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file rcc.h + * @brief reset and clock control definitions and prototypes + */ + +#include "libmaple_types.h" +#include "bitband.h" + +#ifndef _RCC_H_ +#define _RCC_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +/** RCC register map type */ +typedef struct +{ + __io uint32 CR; /*!< RCC clock control register, Address offset: 0x00 */ + __io uint32 PLLCFGR; /*!< RCC PLL configuration register, Address offset: 0x04 */ + __io uint32 CFGR; /*!< RCC clock configuration register, Address offset: 0x08 */ + __io uint32 CIR; /*!< RCC clock interrupt register, Address offset: 0x0C */ + __io uint32 AHB1RSTR; /*!< RCC AHB1 peripheral reset register, Address offset: 0x10 */ + __io uint32 AHB2RSTR; /*!< RCC AHB2 peripheral reset register, Address offset: 0x14 */ + __io uint32 AHB3RSTR; /*!< RCC AHB3 peripheral reset register, Address offset: 0x18 */ + uint32 RESERVED0; /*!< Reserved, 0x1C */ + __io uint32 APB1RSTR; /*!< RCC APB1 peripheral reset register, Address offset: 0x20 */ + __io uint32 APB2RSTR; /*!< RCC APB2 peripheral reset register, Address offset: 0x24 */ + uint32 RESERVED1[2]; /*!< Reserved, 0x28-0x2C */ + __io uint32 AHB1ENR; /*!< RCC AHB1 peripheral clock register, Address offset: 0x30 */ + __io uint32 AHB2ENR; /*!< RCC AHB2 peripheral clock register, Address offset: 0x34 */ + __io uint32 AHB3ENR; /*!< RCC AHB3 peripheral clock register, Address offset: 0x38 */ + uint32 RESERVED2; /*!< Reserved, 0x3C */ + __io uint32 APB1ENR; /*!< RCC APB1 peripheral clock enable register, Address offset: 0x40 */ + __io uint32 APB2ENR; /*!< RCC APB2 peripheral clock enable register, Address offset: 0x44 */ + uint32 RESERVED3[2]; /*!< Reserved, 0x48-0x4C */ + __io uint32 AHB1LPENR; /*!< RCC AHB1 peripheral clock enable in low power mode register, Address offset: 0x50 */ + __io uint32 AHB2LPENR; /*!< RCC AHB2 peripheral clock enable in low power mode register, Address offset: 0x54 */ + __io uint32 AHB3LPENR; /*!< RCC AHB3 peripheral clock enable in low power mode register, Address offset: 0x58 */ + uint32 RESERVED4; /*!< Reserved, 0x5C */ + __io uint32 APB1LPENR; /*!< RCC APB1 peripheral clock enable in low power mode register, Address offset: 0x60 */ + __io uint32 APB2LPENR; /*!< RCC APB2 peripheral clock enable in low power mode register, Address offset: 0x64 */ + uint32 RESERVED5[2]; /*!< Reserved, 0x68-0x6C */ + __io uint32 BDCR; /*!< RCC Backup domain control register, Address offset: 0x70 */ + __io uint32 CSR; /*!< RCC clock control & status register, Address offset: 0x74 */ + uint32 RESERVED6[2]; /*!< Reserved, 0x78-0x7C */ + __io uint32 SSCGR; /*!< RCC spread spectrum clock generation register, Address offset: 0x80 */ + __io uint32 PLLI2SCFGR; /*!< RCC PLLI2S configuration register, Address offset: 0x84 */ +} rcc_reg_map; + +/** RCC register map base pointer */ +//#define RCC_BASE ((struct rcc_reg_map*)0x40021000) +#define RCC_BASE ((rcc_reg_map*)0x40023800) + +/* + * Register bit definitions + */ + +/* Clock control register */ + +#define RCC_CR_PLLRDY_BIT 25 +#define RCC_CR_PLLON_BIT 24 +#define RCC_CR_CSSON_BIT 19 +#define RCC_CR_HSEBYP_BIT 18 +#define RCC_CR_HSERDY_BIT 17 +#define RCC_CR_HSEON_BIT 16 +#define RCC_CR_HSIRDY_BIT 1 +#define RCC_CR_HSION_BIT 0 + +#define RCC_CR_PLLRDY BIT(RCC_CR_PLLRDY_BIT) +#define RCC_CR_PLLON BIT(RCC_CR_PLLON_BIT) +#define RCC_CR_CSSON BIT(RCC_CR_CSSON_BIT) +#define RCC_CR_HSEBYP BIT(RCC_CR_HSEBYP_BIT) +#define RCC_CR_HSERDY BIT(RCC_CR_HSERDY_BIT) +#define RCC_CR_HSEON BIT(RCC_CR_HSEON_BIT) +#define RCC_CR_HSICAL (0xFF << 8) +#define RCC_CR_HSITRIM (0x1F << 3) +#define RCC_CR_HSIRDY BIT(RCC_CR_HSIRDY_BIT) +#define RCC_CR_HSION BIT(RCC_CR_HSION_BIT) + +/* Clock configuration register */ + +#define RCC_CFGR_USBPRE_BIT 22 +#define RCC_CFGR_PLLXTPRE_BIT 17 +#define RCC_CFGR_PLLSRC_BIT 16 + +#define RCC_CFGR_MCO (0x3 << 24) +#define RCC_CFGR_USBPRE BIT(RCC_CFGR_USBPRE_BIT) +#define RCC_CFGR_PLLMUL (0xF << 18) +#define RCC_CFGR_PLLXTPRE BIT(RCC_CFGR_PLLXTPRE_BIT) +#define RCC_CFGR_PLLSRC BIT(RCC_CFGR_PLLSRC_BIT) +#define RCC_CFGR_ADCPRE (0x3 << 14) +#define RCC_CFGR_PPRE2 (0x7 << 11) +#define RCC_CFGR_PPRE1 (0x7 << 8) +#define RCC_CFGR_HPRE (0xF << 4) +#define RCC_CFGR_SWS (0x3 << 2) +#define RCC_CFGR_SWS_PLL (0x2 << 2) +#define RCC_CFGR_SWS_HSE (0x1 << 2) +#define RCC_CFGR_SW 0x3 +#define RCC_CFGR_SW_PLL 0x2 +#define RCC_CFGR_SW_HSE 0x1 + +#define RCC_CFGR_MCO1Source_HSI ((uint32_t)0x00000000) +#define RCC_CFGR_MCO1Source_LSE ((uint32_t)0x00200000) +#define RCC_CFGR_MCO1Source_HSE ((uint32_t)0x00400000) +#define RCC_CFGR_MCO1Source_PLLCLK ((uint32_t)0x00600000) +#define RCC_CFGR_MCO1Div_1 ((uint32_t)0x00000000) +#define RCC_CFGR_MCO1Div_2 ((uint32_t)0x04000000) +#define RCC_CFGR_MCO1Div_3 ((uint32_t)0x05000000) +#define RCC_CFGR_MCO1Div_4 ((uint32_t)0x06000000) +#define RCC_CFGR_MCO1Div_5 ((uint32_t)0x07000000) +#define RCC_CFGR_MCO1_RESET_MASK ((uint32_t)0xF89FFFFF) + +/* Clock interrupt register */ + +#define RCC_CIR_CSSC_BIT 23 +#define RCC_CIR_PLLRDYC_BIT 20 +#define RCC_CIR_HSERDYC_BIT 19 +#define RCC_CIR_HSIRDYC_BIT 18 +#define RCC_CIR_LSERDYC_BIT 17 +#define RCC_CIR_LSIRDYC_BIT 16 +#define RCC_CIR_PLLRDYIE_BIT 12 +#define RCC_CIR_HSERDYIE_BIT 11 +#define RCC_CIR_HSIRDYIE_BIT 10 +#define RCC_CIR_LSERDYIE_BIT 9 +#define RCC_CIR_LSIRDYIE_BIT 8 +#define RCC_CIR_CSSF_BIT 7 +#define RCC_CIR_PLLRDYF_BIT 4 +#define RCC_CIR_HSERDYF_BIT 3 +#define RCC_CIR_HSIRDYF_BIT 2 +#define RCC_CIR_LSERDYF_BIT 1 +#define RCC_CIR_LSIRDYF_BIT 0 + +#define RCC_CIR_CSSC BIT(RCC_CIR_CSSC_BIT) +#define RCC_CIR_PLLRDYC BIT(RCC_CIR_PLLRDYC_BIT) +#define RCC_CIR_HSERDYC BIT(RCC_CIR_HSERDYC_BIT) +#define RCC_CIR_HSIRDYC BIT(RCC_CIR_HSIRDYC_BIT) +#define RCC_CIR_LSERDYC BIT(RCC_CIR_LSERDYC_BIT) +#define RCC_CIR_LSIRDYC BIT(RCC_CIR_LSIRDYC_BIT) +#define RCC_CIR_PLLRDYIE BIT(RCC_CIR_PLLRDYIE_BIT) +#define RCC_CIR_HSERDYIE BIT(RCC_CIR_HSERDYIE_BIT) +#define RCC_CIR_HSIRDYIE BIT(RCC_CIR_HSIRDYIE_BIT) +#define RCC_CIR_LSERDYIE BIT(RCC_CIR_LSERDYIE_BIT) +#define RCC_CIR_LSIRDYIE BIT(RCC_CIR_LSIRDYIE_BIT) +#define RCC_CIR_CSSF BIT(RCC_CIR_CSSF_BIT) +#define RCC_CIR_PLLRDYF BIT(RCC_CIR_PLLRDYF_BIT) +#define RCC_CIR_HSERDYF BIT(RCC_CIR_HSERDYF_BIT) +#define RCC_CIR_HSIRDYF BIT(RCC_CIR_HSIRDYF_BIT) +#define RCC_CIR_LSERDYF BIT(RCC_CIR_LSERDYF_BIT) +#define RCC_CIR_LSIRDYF BIT(RCC_CIR_LSIRDYF_BIT) + +/* APB2 peripheral reset register */ + +#define RCC_APB2RSTR_TIM11RST_BIT 21 +#define RCC_APB2RSTR_TIM10RST_BIT 20 +#define RCC_APB2RSTR_TIM9RST_BIT 19 +#define RCC_APB2RSTR_ADC3RST_BIT 15 +#define RCC_APB2RSTR_USART1RST_BIT 14 +#define RCC_APB2RSTR_TIM8RST_BIT 13 +#define RCC_APB2RSTR_SPI1RST_BIT 12 +#define RCC_APB2RSTR_TIM1RST_BIT 11 +#define RCC_APB2RSTR_ADC2RST_BIT 10 +#define RCC_APB2RSTR_ADC1RST_BIT 9 +#define RCC_APB2RSTR_IOPGRST_BIT 8 +#define RCC_APB2RSTR_IOPFRST_BIT 7 +#define RCC_APB2RSTR_IOPERST_BIT 6 +#define RCC_APB2RSTR_IOPDRST_BIT 5 +#define RCC_APB2RSTR_IOPCRST_BIT 4 +#define RCC_APB2RSTR_IOPBRST_BIT 3 +#define RCC_APB2RSTR_IOPARST_BIT 2 +#define RCC_APB2RSTR_AFIORST_BIT 0 + +#define RCC_APB2RSTR_TIM11RST BIT(RCC_APB2RSTR_TIM11RST_BIT) +#define RCC_APB2RSTR_TIM10RST BIT(RCC_APB2RSTR_TIM10RST_BIT) +#define RCC_APB2RSTR_TIM9RST BIT(RCC_APB2RSTR_TIM9RST_BIT) +#define RCC_APB2RSTR_ADC3RST BIT(RCC_APB2RSTR_ADC3RST_BIT) +#define RCC_APB2RSTR_USART1RST BIT(RCC_APB2RSTR_USART1RST_BIT) +#define RCC_APB2RSTR_TIM8RST BIT(RCC_APB2RSTR_TIM8RST_BIT) +#define RCC_APB2RSTR_SPI1RST BIT(RCC_APB2RSTR_SPI1RST_BIT) +#define RCC_APB2RSTR_TIM1RST BIT(RCC_APB2RSTR_TIM1RST_BIT) +#define RCC_APB2RSTR_ADC2RST BIT(RCC_APB2RSTR_ADC2RST_BIT) +#define RCC_APB2RSTR_ADC1RST BIT(RCC_APB2RSTR_ADC1RST_BIT) +#define RCC_APB2RSTR_IOPGRST BIT(RCC_APB2RSTR_IOPGRST_BIT) +#define RCC_APB2RSTR_IOPFRST BIT(RCC_APB2RSTR_IOPFRST_BIT) +#define RCC_APB2RSTR_IOPERST BIT(RCC_APB2RSTR_IOPERST_BIT) +#define RCC_APB2RSTR_IOPDRST BIT(RCC_APB2RSTR_IOPDRST_BIT) +#define RCC_APB2RSTR_IOPCRST BIT(RCC_APB2RSTR_IOPCRST_BIT) +#define RCC_APB2RSTR_IOPBRST BIT(RCC_APB2RSTR_IOPBRST_BIT) +#define RCC_APB2RSTR_IOPARST BIT(RCC_APB2RSTR_IOPARST_BIT) +#define RCC_APB2RSTR_AFIORST BIT(RCC_APB2RSTR_AFIORST_BIT) + +/* APB1 peripheral reset register */ + +#define RCC_APB1RSTR_DACRST_BIT 29 +#define RCC_APB1RSTR_PWRRST_BIT 28 +#define RCC_APB1RSTR_BKPRST_BIT 27 +#define RCC_APB1RSTR_CANRST_BIT 25 +#define RCC_APB1RSTR_USBRST_BIT 23 +#define RCC_APB1RSTR_I2C2RST_BIT 22 +#define RCC_APB1RSTR_I2C1RST_BIT 21 +#define RCC_APB1RSTR_UART5RST_BIT 20 +#define RCC_APB1RSTR_UART4RST_BIT 19 +#define RCC_APB1RSTR_USART3RST_BIT 18 +#define RCC_APB1RSTR_USART2RST_BIT 17 +#define RCC_APB1RSTR_SPI3RST_BIT 15 +#define RCC_APB1RSTR_SPI2RST_BIT 14 +#define RCC_APB1RSTR_WWDRST_BIT 11 +#define RCC_APB1RSTR_TIM14RST_BIT 8 +#define RCC_APB1RSTR_TIM13RST_BIT 7 +#define RCC_APB1RSTR_TIM12RST_BIT 6 +#define RCC_APB1RSTR_TIM7RST_BIT 5 +#define RCC_APB1RSTR_TIM6RST_BIT 4 +#define RCC_APB1RSTR_TIM5RST_BIT 3 +#define RCC_APB1RSTR_TIM4RST_BIT 2 +#define RCC_APB1RSTR_TIM3RST_BIT 1 +#define RCC_APB1RSTR_TIM2RST_BIT 0 + +#define RCC_APB1RSTR_DACRST BIT(RCC_APB1RSTR_DACRST_BIT) +#define RCC_APB1RSTR_PWRRST BIT(RCC_APB1RSTR_PWRRST_BIT) +#define RCC_APB1RSTR_BKPRST BIT(RCC_APB1RSTR_BKPRST_BIT) +#define RCC_APB1RSTR_CANRST BIT(RCC_APB1RSTR_CANRST_BIT) +#define RCC_APB1RSTR_USBRST BIT(RCC_APB1RSTR_USBRST_BIT) +#define RCC_APB1RSTR_I2C2RST BIT(RCC_APB1RSTR_I2C2RST_BIT) +#define RCC_APB1RSTR_I2C1RST BIT(RCC_APB1RSTR_I2C1RST_BIT) +#define RCC_APB1RSTR_UART5RST BIT(RCC_APB1RSTR_UART5RST_BIT) +#define RCC_APB1RSTR_UART4RST BIT(RCC_APB1RSTR_UART4RST_BIT) +#define RCC_APB1RSTR_USART3RST BIT(RCC_APB1RSTR_USART3RST_BIT) +#define RCC_APB1RSTR_USART2RST BIT(RCC_APB1RSTR_USART2RST_BIT) +#define RCC_APB1RSTR_SPI3RST BIT(RCC_APB1RSTR_SPI3RST_BIT) +#define RCC_APB1RSTR_SPI2RST BIT(RCC_APB1RSTR_SPI2RST_BIT) +#define RCC_APB1RSTR_WWDRST BIT(RCC_APB1RSTR_WWDRST_BIT) +#define RCC_APB1RSTR_TIM14RST BIT(RCC_APB1RSTR_TIM14RST_BIT) +#define RCC_APB1RSTR_TIM13RST BIT(RCC_APB1RSTR_TIM13RST_BIT) +#define RCC_APB1RSTR_TIM12RST BIT(RCC_APB1RSTR_TIM12RST_BIT) +#define RCC_APB1RSTR_TIM7RST BIT(RCC_APB1RSTR_TIM7RST_BIT) +#define RCC_APB1RSTR_TIM6RST BIT(RCC_APB1RSTR_TIM6RST_BIT) +#define RCC_APB1RSTR_TIM5RST BIT(RCC_APB1RSTR_TIM5RST_BIT) +#define RCC_APB1RSTR_TIM4RST BIT(RCC_APB1RSTR_TIM4RST_BIT) +#define RCC_APB1RSTR_TIM3RST BIT(RCC_APB1RSTR_TIM3RST_BIT) +#define RCC_APB1RSTR_TIM2RST BIT(RCC_APB1RSTR_TIM2RST_BIT) + +/* AHB peripheral clock enable register */ + +#define RCC_AHBENR_SDIOEN_BIT 10 +#define RCC_AHBENR_FSMCEN_BIT 8 +#define RCC_AHBENR_CRCEN_BIT 7 +#define RCC_AHBENR_FLITFEN_BIT 4 +#define RCC_AHBENR_SRAMEN_BIT 2 +#define RCC_AHBENR_DMA2EN_BIT 1 +#define RCC_AHBENR_DMA1EN_BIT 0 + +#define RCC_AHBENR_SDIOEN BIT(RCC_AHBENR_SDIOEN_BIT) +#define RCC_AHBENR_FSMCEN BIT(RCC_AHBENR_FSMCEN_BIT) +#define RCC_AHBENR_CRCEN BIT(RCC_AHBENR_CRCEN_BIT) +#define RCC_AHBENR_FLITFEN BIT(RCC_AHBENR_FLITFEN_BIT) +#define RCC_AHBENR_SRAMEN BIT(RCC_AHBENR_SRAMEN_BIT) +#define RCC_AHBENR_DMA2EN BIT(RCC_AHBENR_DMA2EN_BIT) +#define RCC_AHBENR_DMA1EN BIT(RCC_AHBENR_DMA1EN_BIT) + +/* APB2 peripheral clock enable register */ + +#define RCC_APB2ENR_TIM11EN_BIT 21 +#define RCC_APB2ENR_TIM10EN_BIT 20 +#define RCC_APB2ENR_TIM9EN_BIT 19 +#define RCC_APB2ENR_ADC3EN_BIT 15 +#define RCC_APB2ENR_USART1EN_BIT 14 +#define RCC_APB2ENR_TIM8EN_BIT 13 +#define RCC_APB2ENR_SPI1EN_BIT 12 +#define RCC_APB2ENR_TIM1EN_BIT 11 +#define RCC_APB2ENR_ADC2EN_BIT 10 +#define RCC_APB2ENR_ADC1EN_BIT 9 +#define RCC_APB2ENR_IOPGEN_BIT 8 +#define RCC_APB2ENR_IOPFEN_BIT 7 +#define RCC_APB2ENR_IOPEEN_BIT 6 +#define RCC_APB2ENR_IOPDEN_BIT 5 +#define RCC_APB2ENR_IOPCEN_BIT 4 +#define RCC_APB2ENR_IOPBEN_BIT 3 +#define RCC_APB2ENR_IOPAEN_BIT 2 +#define RCC_APB2ENR_AFIOEN_BIT 0 + +#define RCC_APB2ENR_TIM11EN BIT(RCC_APB2ENR_TIM11EN_BIT) +#define RCC_APB2ENR_TIM10EN BIT(RCC_APB2ENR_TIM10EN_BIT) +#define RCC_APB2ENR_TIM9EN BIT(RCC_APB2ENR_TIM9EN_BIT) +#define RCC_APB2ENR_ADC3EN BIT(RCC_APB2ENR_ADC3EN_BIT) +#define RCC_APB2ENR_USART1EN BIT(RCC_APB2ENR_USART1EN_BIT) +#define RCC_APB2ENR_TIM8EN BIT(RCC_APB2ENR_TIM8EN_BIT) +#define RCC_APB2ENR_SPI1EN BIT(RCC_APB2ENR_SPI1EN_BIT) +#define RCC_APB2ENR_TIM1EN BIT(RCC_APB2ENR_TIM1EN_BIT) +#define RCC_APB2ENR_ADC2EN BIT(RCC_APB2ENR_ADC2EN_BIT) +#define RCC_APB2ENR_ADC1EN BIT(RCC_APB2ENR_ADC1EN_BIT) +#define RCC_APB2ENR_IOPGEN BIT(RCC_APB2ENR_IOPGEN_BIT) +#define RCC_APB2ENR_IOPFEN BIT(RCC_APB2ENR_IOPFEN_BIT) +#define RCC_APB2ENR_IOPEEN BIT(RCC_APB2ENR_IOPEEN_BIT) +#define RCC_APB2ENR_IOPDEN BIT(RCC_APB2ENR_IOPDEN_BIT) +#define RCC_APB2ENR_IOPCEN BIT(RCC_APB2ENR_IOPCEN_BIT) +#define RCC_APB2ENR_IOPBEN BIT(RCC_APB2ENR_IOPBEN_BIT) +#define RCC_APB2ENR_IOPAEN BIT(RCC_APB2ENR_IOPAEN_BIT) +#define RCC_APB2ENR_AFIOEN BIT(RCC_APB2ENR_AFIOEN_BIT) + +/* APB1 peripheral clock enable register */ + +#define RCC_APB1ENR_DACEN_BIT 29 +#define RCC_APB1ENR_PWREN_BIT 28 +#define RCC_APB1ENR_BKPEN_BIT 27 +#define RCC_APB1ENR_CANEN_BIT 25 +#define RCC_APB1ENR_USBEN_BIT 23 +#define RCC_APB1ENR_I2C2EN_BIT 22 +#define RCC_APB1ENR_I2C1EN_BIT 21 +#define RCC_APB1ENR_UART5EN_BIT 20 +#define RCC_APB1ENR_UART4EN_BIT 19 +#define RCC_APB1ENR_USART3EN_BIT 18 +#define RCC_APB1ENR_USART2EN_BIT 17 +#define RCC_APB1ENR_SPI3EN_BIT 15 +#define RCC_APB1ENR_SPI2EN_BIT 14 +#define RCC_APB1ENR_WWDEN_BIT 11 +#define RCC_APB1ENR_TIM14EN_BIT 8 +#define RCC_APB1ENR_TIM13EN_BIT 7 +#define RCC_APB1ENR_TIM12EN_BIT 6 +#define RCC_APB1ENR_TIM7EN_BIT 5 +#define RCC_APB1ENR_TIM6EN_BIT 4 +#define RCC_APB1ENR_TIM5EN_BIT 3 +#define RCC_APB1ENR_TIM4EN_BIT 2 +#define RCC_APB1ENR_TIM3EN_BIT 1 +#define RCC_APB1ENR_TIM2EN_BIT 0 + +#define RCC_APB1ENR_DACEN BIT(RCC_APB1ENR_DACEN_BIT) +#define RCC_APB1ENR_PWREN BIT(RCC_APB1ENR_PWREN_BIT) +#define RCC_APB1ENR_BKPEN BIT(RCC_APB1ENR_BKPEN_BIT) +#define RCC_APB1ENR_CANEN BIT(RCC_APB1ENR_CANEN_BIT) +#define RCC_APB1ENR_USBEN BIT(RCC_APB1ENR_USBEN_BIT) +#define RCC_APB1ENR_I2C2EN BIT(RCC_APB1ENR_I2C2EN_BIT) +#define RCC_APB1ENR_I2C1EN BIT(RCC_APB1ENR_I2C1EN_BIT) +#define RCC_APB1ENR_UART5EN BIT(RCC_APB1ENR_UART5EN_BIT) +#define RCC_APB1ENR_UART4EN BIT(RCC_APB1ENR_UART4EN_BIT) +#define RCC_APB1ENR_USART3EN BIT(RCC_APB1ENR_USART3EN_BIT) +#define RCC_APB1ENR_USART2EN BIT(RCC_APB1ENR_USART2EN_BIT) +#define RCC_APB1ENR_SPI3EN BIT(RCC_APB1ENR_SPI3EN_BIT) +#define RCC_APB1ENR_SPI2EN BIT(RCC_APB1ENR_SPI2EN_BIT) +#define RCC_APB1ENR_WWDEN BIT(RCC_APB1ENR_WWDEN_BIT) +#define RCC_APB1ENR_TIM14EN BIT(RCC_APB1ENR_TIM14EN_BIT) +#define RCC_APB1ENR_TIM13EN BIT(RCC_APB1ENR_TIM13EN_BIT) +#define RCC_APB1ENR_TIM12EN BIT(RCC_APB1ENR_TIM12EN_BIT) +#define RCC_APB1ENR_TIM7EN BIT(RCC_APB1ENR_TIM7EN_BIT) +#define RCC_APB1ENR_TIM6EN BIT(RCC_APB1ENR_TIM6EN_BIT) +#define RCC_APB1ENR_TIM5EN BIT(RCC_APB1ENR_TIM5EN_BIT) +#define RCC_APB1ENR_TIM4EN BIT(RCC_APB1ENR_TIM4EN_BIT) +#define RCC_APB1ENR_TIM3EN BIT(RCC_APB1ENR_TIM3EN_BIT) +#define RCC_APB1ENR_TIM2EN BIT(RCC_APB1ENR_TIM2EN_BIT) + +/* Backup domain control register */ + +#define RCC_BDCR_BDRST_BIT 16 +#define RCC_BDCR_RTCEN_BIT 15 +#define RCC_BDCR_LSEBYP_BIT 2 +#define RCC_BDCR_LSERDY_BIT 1 +#define RCC_BDCR_LSEON_BIT 0 + +#define RCC_BDCR_BDRST BIT(RCC_BDCR_BDRST_BIT) +#define RCC_BDCR_RTCEN BIT(RCC_BDCR_RTC_BIT) +#define RCC_BDCR_RTCSEL (0x3 << 8) +#define RCC_BDCR_RTCSEL_NONE (0x0 << 8) +#define RCC_BDCR_RTCSEL_LSE (0x1 << 8) +#define RCC_BDCR_RTCSEL_LSI (0x2 << 8) +#define RCC_BDCR_RTCSEL_HSE (0x3 << 8) +#define RCC_BDCR_LSEBYP BIT(RCC_BDCR_LSEBYP_BIT) +#define RCC_BDCR_LSERDY BIT(RCC_BDCR_LSERDY_BIT) +#define RCC_BDCR_LSEON BIT(RCC_BDCR_LSEON_BIT) + +/* Control/status register */ + +#define RCC_CSR_LPWRRSTF_BIT 31 +#define RCC_CSR_WWDGRSTF_BIT 30 +#define RCC_CSR_IWDGRSTF_BIT 29 +#define RCC_CSR_SFTRSTF_BIT 28 +#define RCC_CSR_PORRSTF_BIT 27 +#define RCC_CSR_PINRSTF_BIT 26 +#define RCC_CSR_RMVF_BIT 24 +#define RCC_CSR_LSIRDY_BIT 1 +#define RCC_CSR_LSION_BIT 0 + +#define RCC_CSR_LPWRRSTF BIT(RCC_CSR_LPWRRSTF_BIT) +#define RCC_CSR_WWDGRSTF BIT(RCC_CSR_WWDGRSTF_BIT) +#define RCC_CSR_IWDGRSTF BIT(RCC_CSR_IWDGRSTF_BIT) +#define RCC_CSR_SFTRSTF BIT(RCC_CSR_SFTRSTF_BIT) +#define RCC_CSR_PORRSTF BIT(RCC_CSR_PORRSTF_BIT) +#define RCC_CSR_PINRSTF BIT(RCC_CSR_PINRSTF_BIT) +#define RCC_CSR_RMVF BIT(RCC_CSR_RMVF_BIT) +#define RCC_CSR_LSIRDY BIT(RCC_CSR_LSIRDY_BIT) +#define RCC_CSR_LSION BIT(RCC_CSR_LSION_BIT) + +/* + * Convenience routines + */ + +/** + * SYSCLK sources + * @see rcc_clk_init() + */ +typedef enum rcc_sysclk_src { + RCC_CLKSRC_HSI = 0x0, + RCC_CLKSRC_HSE = 0x1, + RCC_CLKSRC_PLL = 0x2, +} rcc_sysclk_src; + +/** + * PLL entry clock source + * @see rcc_clk_init() + */ +typedef enum rcc_pllsrc { + RCC_PLLSRC_HSE = (0x1 << 16), + RCC_PLLSRC_HSI_DIV_2 = (0x0 << 16) +} rcc_pllsrc; + +/** + * PLL multipliers + * @see rcc_clk_init() + */ +typedef enum rcc_pll_multiplier { + RCC_PLLMUL_2 = (0x0 << 18), + RCC_PLLMUL_3 = (0x1 << 18), + RCC_PLLMUL_4 = (0x2 << 18), + RCC_PLLMUL_5 = (0x3 << 18), + RCC_PLLMUL_6 = (0x4 << 18), + RCC_PLLMUL_7 = (0x5 << 18), + RCC_PLLMUL_8 = (0x6 << 18), + RCC_PLLMUL_9 = (0x7 << 18), + RCC_PLLMUL_10 = (0x8 << 18), + RCC_PLLMUL_11 = (0x9 << 18), + RCC_PLLMUL_12 = (0xA << 18), + RCC_PLLMUL_13 = (0xB << 18), + RCC_PLLMUL_14 = (0xC << 18), + RCC_PLLMUL_15 = (0xD << 18), + RCC_PLLMUL_16 = (0xE << 18), +} rcc_pll_multiplier; + +/** + * @brief Identifies bus and clock line for a peripheral. + * + * Also generally useful as a unique identifier for that peripheral + * (or its corresponding device struct). + */ +typedef enum rcc_clk_id { + RCC_GPIOA, + RCC_GPIOB, + RCC_GPIOC, + RCC_GPIOD, +// RCC_AFIO, + RCC_ADC1, + RCC_ADC2, + RCC_ADC3, + RCC_USART1, + RCC_USART2, + RCC_USART3, + RCC_TIMER1, + RCC_TIMER2, + RCC_TIMER3, + RCC_TIMER4, + RCC_SPI1, + RCC_SPI2, + RCC_DMA1, + RCC_PWR, + RCC_BKP, + RCC_I2C1, + RCC_I2C2, + RCC_CRC, +// RCC_FLITF, +// RCC_SRAM, + RCC_GPIOE, + RCC_GPIOF, + RCC_GPIOG, + RCC_UART4, + RCC_UART5, + RCC_TIMER5, + RCC_TIMER6, + RCC_TIMER7, + RCC_TIMER8, + RCC_FSMC, + RCC_DAC, + RCC_DMA2, + RCC_SDIO, + RCC_SPI3, + RCC_TIMER9, + RCC_TIMER10, + RCC_TIMER11, + RCC_TIMER12, + RCC_TIMER13, + RCC_TIMER14, + RCC_USBFS, + RCC_SYSCFG, + RCC_SPI4 +} rcc_clk_id; + +void rcc_clk_init(rcc_sysclk_src sysclk_src, + rcc_pllsrc pll_src, + rcc_pll_multiplier pll_mul); +void rcc_clk_disable(rcc_clk_id device); +void rcc_clk_enable(rcc_clk_id device); +void rcc_reset_dev(rcc_clk_id device); + +void SetupClock72MHz(); +void SetupClock120MHz(); +void SetupClock168MHz(); + +typedef enum rcc_clk_domain { + RCC_APB1, + RCC_APB2, + RCC_AHB1, + RCC_AHB2, + RCC_AHB3 +} rcc_clk_domain; + +rcc_clk_domain rcc_dev_clk(rcc_clk_id device); + +uint32 rcc_dev_clk_speed(rcc_clk_id id); +uint32 rcc_dev_timer_clk_speed(rcc_clk_id id); + +/** + * Prescaler identifiers + * @see rcc_set_prescaler() + */ +typedef enum rcc_prescaler { + RCC_PRESCALER_AHB, + RCC_PRESCALER_APB1, + RCC_PRESCALER_APB2, + RCC_PRESCALER_USB, + RCC_PRESCALER_ADC +} rcc_prescaler; + +/** + * ADC prescaler dividers + * @see rcc_set_prescaler() + */ +typedef enum rcc_adc_divider { + RCC_ADCPRE_PCLK_DIV_2 = 0x0 << 14, + RCC_ADCPRE_PCLK_DIV_4 = 0x1 << 14, + RCC_ADCPRE_PCLK_DIV_6 = 0x2 << 14, + RCC_ADCPRE_PCLK_DIV_8 = 0x3 << 14, +} rcc_adc_divider; + +/** + * APB1 prescaler dividers + * @see rcc_set_prescaler() + */ +typedef enum rcc_apb1_divider { + RCC_APB1_HCLK_DIV_1 = 0x0 << 8, + RCC_APB1_HCLK_DIV_2 = 0x4 << 8, + RCC_APB1_HCLK_DIV_4 = 0x5 << 8, + RCC_APB1_HCLK_DIV_8 = 0x6 << 8, + RCC_APB1_HCLK_DIV_16 = 0x7 << 8, +} rcc_apb1_divider; + +/** + * APB2 prescaler dividers + * @see rcc_set_prescaler() + */ +typedef enum rcc_apb2_divider { + RCC_APB2_HCLK_DIV_1 = 0x0 << 11, + RCC_APB2_HCLK_DIV_2 = 0x4 << 11, + RCC_APB2_HCLK_DIV_4 = 0x5 << 11, + RCC_APB2_HCLK_DIV_8 = 0x6 << 11, + RCC_APB2_HCLK_DIV_16 = 0x7 << 11, +} rcc_apb2_divider; + +/** + * AHB prescaler dividers + * @see rcc_set_prescaler() + */ +typedef enum rcc_ahb_divider { + RCC_AHB_SYSCLK_DIV_1 = 0x0 << 4, + RCC_AHB_SYSCLK_DIV_2 = 0x8 << 4, + RCC_AHB_SYSCLK_DIV_4 = 0x9 << 4, + RCC_AHB_SYSCLK_DIV_8 = 0xA << 4, + RCC_AHB_SYSCLK_DIV_16 = 0xB << 4, + RCC_AHB_SYSCLK_DIV_32 = 0xC << 4, + RCC_AHB_SYSCLK_DIV_64 = 0xD << 4, + RCC_AHB_SYSCLK_DIV_128 = 0xD << 4, + RCC_AHB_SYSCLK_DIV_256 = 0xE << 4, + RCC_AHB_SYSCLK_DIV_512 = 0xF << 4, +} rcc_ahb_divider; + +void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider); + + +/** + * @brief Start the low speed internal oscillatior + */ +static inline void rcc_start_lsi(void) { + *bb_perip(&RCC_BASE->CSR, RCC_CSR_LSION_BIT) = 1; + while (*bb_perip(&RCC_BASE->CSR, RCC_CSR_LSIRDY_BIT) == 0); +} + +/* FIXME [0.0.13] Just have data point to an rcc_pll_multiplier! */ +/** + * @brief Start the low speed external oscillatior + */ +static inline void rcc_start_lse(void) { + bb_peri_set_bit(&RCC_BASE->BDCR, RCC_BDCR_LSEBYP_BIT, 0); + bb_peri_set_bit(&RCC_BASE->BDCR, RCC_BDCR_LSEON_BIT, 1); + while (bb_peri_get_bit(&RCC_BASE->BDCR, RCC_BDCR_LSERDY_BIT ) == 0); +} + +/* + * Deprecated bits. + */ +static inline void rcc_start_hse(void) { // Added to support RTClock +// *bb_perip(&RCC_BASE->CR, RCC_CR_HSEON_BIT) = 1; + while (bb_peri_get_bit(&RCC_BASE->CR, RCC_CR_HSERDY_BIT) == 0); +} + + + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/STM32F4/variants/black_f407vet6/black_f4.cpp b/STM32F4/variants/black_f407vet6/black_f4.cpp new file mode 100644 index 0000000..78d37aa --- /dev/null +++ b/STM32F4/variants/black_f407vet6/black_f4.cpp @@ -0,0 +1,264 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file black_f4.cpp + * @author ala42 + * @brief black_f4 board file. + */ + +#ifdef BOARD_black_f4 + +#include "black_f4.h" + +//#include "fsmc.h" +#include "gpio.h" +#include "rcc.h" +#include "timer.h" + +#include "wirish_types.h" + +// Pins reserved for the on-board hardware +#define USB_DM_PIN BOARD_USB_DM_PIN // PA11 +#define USB_DP_PIN BOARD_USB_DP_PIN // PA12 + +#define FLASH_CS_PIN PB0 +#define FLASH_CLK_PIN BOARD_SPI3_SCK_PIN // PB3 +#define FLASH_DO_PIN BOARD_SPI3_MISO_PIN // PB4 +#define FLASH_DI_PIN BOARD_SPI3_MOSI_PIN // PB5 + +#define NRF24_CLK_PIN BOARD_SPI3_SCK_PIN // PB3 +#define NRF24_DO_PIN BOARD_SPI3_MISO_PIN // PB4 +#define NRF24_DI_PIN BOARD_SPI3_MOSI_PIN // PB5 +#define NRF24_CE_PIN PB6 +#define NRF24_CS_PIN PB7 +#define NRF24_IRQ_PIN PB8 + +// SD card, SDIO mode +#define SD_DAT0 BOARD_SDIO_D0 // PC8 +#define SD_DAT1 BOARD_SDIO_D1 // PC9 +#define SD_DAT2 BOARD_SDIO_D2 // PC10 +#define SD_DAT3 BOARD_SDIO_D3 // PC11 +#define SD_CLK BOARD_SDIO_CK // PC12 +#define SD_CMD BOARD_SDIO_CMD // PD2 +// SD card, SPI mode, only usable with software SPI +#define SD_DI BOARD_SDIO_CMD // PD2 +#define SD_DO BOARD_SDIO_D0 // PC8 +#define SD_CS BOARD_SDIO_D3 // PC11 +#define SD_SCLK BOARD_SDIO_CK // PC12 + +//static void initSRAMChip(void); +/*****************************************************************************/ +// Alternate functions, see DocID022152 Rev 8, Table 9. +/*****************************************************************************/ +void boardInit(void) { +/* // remap TIMER8 to PC6-9 + gpio_set_af_mode(GPIOC, 6, 3); + gpio_set_af_mode(GPIOC, 7, 3); + gpio_set_af_mode(GPIOC, 8, 3); + gpio_set_af_mode(GPIOC, 9, 3); + + // remap TIMER1 to PE9,11,13,14 + gpio_set_af_mode(GPIOE, 9, 1); + gpio_set_af_mode(GPIOE, 11, 1); + gpio_set_af_mode(GPIOE, 13, 1); + gpio_set_af_mode(GPIOE, 14, 1); + + // remap TIMER3 to PB4,5,0,1 + gpio_set_af_mode(GPIOB, 4, 2); + gpio_set_af_mode(GPIOB, 5, 2); + gpio_set_af_mode(GPIOB, 0, 2); + gpio_set_af_mode(GPIOB, 1, 2); + + //gpio_set_af_mode(GPIOA, 2, 7); + //gpio_set_af_mode(GPIOA, 3, 7); +*/ + return; +} + +/* +typedef struct stm32_pin_info { + gpio_dev *gpio_device; // Maple pin's GPIO device + uint8 gpio_bit; // Pin's GPIO port bit. + timer_dev *timer_device; // Pin's timer device, if any. + uint8 timer_channel; // Timer channel, or 0 if none. + const adc_dev *adc_device; // ADC device, if any. + uint8 adc_channel; // Pin ADC channel, or ADCx if none. +} stm32_pin_info; +*/ + +extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { // LQFP100 package pin + {GPIOA, 0, TIMER5, 1, ADC1, 0}, // D00/PA0 | 23 | USART2_CTS | UART4_TX | ETH_MII_CRS | TIM2_CH1_ETR | TIM5_CH1 | TIM8_ETR | ADC123_IN0/WKUP + {GPIOA, 1, TIMER5, 2, ADC1, 1}, // D01/PA1 | 24 | USART2_RTS | UART4_RX | ETH_RMII_REF_CLK | ETH_MII_RX_CLK | TIM5_CH2 | TIM2_CH2 | ADC123_IN1 + {GPIOA, 2, TIMER5, 3, ADC1, 2}, // D02/PA2 | 25 | USART2_TX | TIM5_CH3 | TIM9_CH1 | TIM2_CH3 | ETH_MDIO | ADC123_IN2 + {GPIOA, 3, TIMER5, 4, ADC1, 3}, // D03/PA3 | 26 | USART2_RX | TIM5_CH4 | TIM9_CH2 | TIM2_CH4 | OTG_HS_ULPI_D0 | ETH_MII_COL | ADC123_IN3 + {GPIOA, 4, NULL, 0, ADC1, 4}, // D04/PA4 | 29 | SPI1_NSS | SPI3_NSS | USART2_CK | DCMI_HSYNC | OTG_HS_SOF | I2S3_WS | ADC12_IN4 / DAC_OUT1 + {GPIOA, 5, NULL, 0, ADC1, 5}, // D05/PA5 | 30 | SPI1_SCK | OTG_HS_ULPI_CK | TIM2_CH1_ETR | TIM8_CH1N | ADC12_IN5 / DAC_OUT2 + {GPIOA, 6, NULL, 1, ADC1, 6}, // D06/PA6 | 31 | SPI1_MISO | TIM8_BKIN | TIM13_CH1 | DCMI_PIXCLK | TIM3_CH1 | TIM1_BKIN | ADC12_IN6 + {GPIOA, 7, NULL, 0, ADC1, 7}, // D07/PA7 | 32 | SPI1_MOSI | TIM8_CH1N | TIM14_CH1 | TIM3_CH2 | ETH_MII_RX_DV | TIM1_CH1N / ETH_RMII_CRS_DV | ADC12_IN7 + {GPIOA, 8, NULL, 0, NULL, ADCx}, // D08/PA8 | 67 | MCO1 | USART1_CK | TIM1_CH1 | I2C3_SCL | OTG_FS_SOF + {GPIOA, 9, NULL, 0, NULL, ADCx}, // D09/PA9 | 68 | USART1_TX | TIM1_CH2 | I2C3_SMBA | DCMI_D0 + {GPIOA, 10, NULL, 0, NULL, ADCx}, // D10/PA10 | 69 | USART1_RX | TIM1_CH3 | OTG_FS_ID | DCMI_D1 + {GPIOA, 11, NULL, 0, NULL, ADCx}, // D11/PA11 | 70 | USART1_CTS | CAN1_RX | TIM1_CH4 | OTG_FS_DM + {GPIOA, 12, NULL, 0, NULL, ADCx}, // D12/PA12 | 71 | USART1_RTS | CAN1_TX | TIM1_ETR | OTG_FS_DP + {GPIOA, 13, NULL, 0, NULL, ADCx}, // D13/PA13 | 72 | JTMS-SWDIO + {GPIOA, 14, NULL, 0, NULL, ADCx}, // D14/PA14 | 76 | JTCK-SWCLK + {GPIOA, 15, TIMER2, 1, NULL, ADCx}, // D15/PA15 | 77 | JTDI | SPI3_NSS | I2S3_WS | TIM2_CH1_ETR | SPI1_NSS + + {GPIOB, 0, TIMER3, 3, ADC1, 8}, // D16/PB0 | 35 | TIM3_CH3 | TIM8_CH2N | OTG_HS_ULPI_D1 | ETH_MII_RXD2 | TIM1_CH2N | ADC12_IN8 + {GPIOB, 1, TIMER3, 4, ADC1, 9}, // D17/PB1 | 36 | TIM3_CH4 | TIM8_CH3N | OTG_HS_ULPI_D2 | ETH_MII_RXD3 | TIM1_CH3N | ADC12_IN9 + {GPIOB, 2, NULL, 0, NULL, ADCx}, // D18/PB2 | 37 | BOOT1 + {GPIOB, 3, TIMER2, 2, NULL, ADCx}, // D19/PB3 | 89 | JTDO | TRACESWO | SPI3_SCK | I2S3_CK | TIM2_CH2 | SPI1_SCK + {GPIOB, 4, TIMER3, 1, NULL, ADCx}, // D20/PB4 | 90 | NJTRST | SPI3_MISO | TIM3_CH1 | SPI1_MISO | I2S3ext_SD + {GPIOB, 5, TIMER3, 2, NULL, ADCx}, // D21/PB5 | 91 | I2C1_SMBA | CAN2_RX | OTG_HS_ULPI_D7 | ETH_PPS_OUT | TIM3_CH2 | SPI1_MOSI | SPI3_MOSI | DCMI_D10 | I2S3_SD + {GPIOB, 6, NULL, 0, NULL, ADCx}, // D22/PB6 | 92 | I2C1_SCL | TIM4_CH1 | CAN2_TX | DCMI_D5 | USART1_TX + {GPIOB, 7, NULL, 0, NULL, ADCx}, // D23/PB7 | 93 | I2C1_SDA | FSMC_NL | DCMI_VSYNC | USART1_RX | TIM4_CH2 + {GPIOB, 8, NULL, 0, NULL, ADCx}, // D24/PB8 | 95 | TIM4_CH3 | SDIO_D4 | TIM10_CH1 | DCMI_D6 | ETH_MII_TXD3 | I2C1_SCL | CAN1_RX + {GPIOB, 9, NULL, 0, NULL, ADCx}, // D25/PB9 | 96 | SPI2_NSS | I2S2_WS | TIM4_CH4 | TIM11_CH1 | SDIO_D5 | DCMI_D7 | I2C1_SDA | CAN1_TX + {GPIOB, 10, NULL, 0, NULL, ADCx}, // D26/PB10 | 47 | SPI2_SCK | I2S2_CK | I2C2_SCL | USART3_TX | OTG_HS_ULPI_D3 | ETH_MII_RX_ER | TIM2_CH3 + {GPIOB, 11, NULL, 0, NULL, ADCx}, // D27/PB11 | 48 | I2C2_SDA | USART3_RX | OTG_HS_ULPI_D4 | ETH_RMII_TX_EN | ETH_MII_TX_EN | TIM2_CH4 + {GPIOB, 12, NULL, 0, NULL, ADCx}, // D28/PB12 | 51 | SPI2_NSS | I2S2_WS | I2C2_SMBA | USART3_CK | TIM1_BKIN | CAN2_RX | OTG_HS_ULPI_D5 | ETH_RMII_TXD0 | ETH_MII_TXD0 | OTG_HS_ID + {GPIOB, 13, NULL, 0, NULL, ADCx}, // D29/PB13 | 52 | SPI2_SCK | I2S2_CK | USART3_CTS | TIM1_CH1N | CAN2_TX | OTG_HS_ULPI_D6 | ETH_RMII_TXD1 | ETH_MII_TXD1 + {GPIOB, 14, NULL, 0, NULL, ADCx}, // D30/PB14 | 53 | SPI2_MISO | TIM1_CH2N | TIM12_CH1 | OTG_HS_DM | USART3_RTS | TIM8_CH2N | I2S2ext_SD + {GPIOB, 15, NULL, 0, NULL, ADCx}, // D31/PB15 | 54 | SPI2_MOSI | I2S2_SD | TIM1_CH3N | TIM8_CH3N | TIM12_CH2 | OTG_HS_DP + + {GPIOC, 0, NULL, 0, ADC1, 10}, // D32/PC0 | 15 | OTG_HS_ULPI_STP | ADC123_IN10 + {GPIOC, 1, NULL, 0, ADC1, 11}, // D33/PC1 | 16 | ETH_MDC | ADC123_IN11 + {GPIOC, 2, NULL, 0, ADC1, 12}, // D34/PC2 | 17 | SPI2_MISO | OTG_HS_ULPI_DIR | ETH_MII_TXD2 | I2S2ext_SD | ADC123_IN12 + {GPIOC, 3, NULL, 0, ADC1, 13}, // D35/PC3 | 18 | SPI2_MOSI | I2S2_SD | OTG_HS_ULPI_NXT | ETH_MII_TX_CLK | ADC123_IN13 + {GPIOC, 4, NULL, 0, ADC1, 14}, // D36/PC4 | 33 | ETH_RMII_RX_D0 | ETH_MII_RX_D0 | ADC12_IN14 + {GPIOC, 5, NULL, 0, ADC1, 15}, // D37/PC5 | 34 | ETH_RMII_RX_D1 | ETH_MII_RX_D1 | ADC12_IN15 + {GPIOC, 6, TIMER8, 1, NULL, ADCx}, // D38/PC6 | 63 | I2S2_MCK | TIM8_CH1/SDIO_D6 | USART6_TX | DCMI_D0/TIM3_CH1 + {GPIOC, 7, TIMER8, 2, NULL, ADCx}, // D39/PC7 | 64 | I2S3_MCK | TIM8_CH2/SDIO_D7 | USART6_RX | DCMI_D1/TIM3_CH2 + {GPIOC, 8, TIMER8, 3, NULL, ADCx}, // D40/PC8 | 65 | TIM8_CH3 | SDIO_D0 | TIM3_CH3 | USART6_CK | DCMI_D2 + {GPIOC, 9, TIMER8, 4, NULL, ADCx}, // D41/PC9 | 66 | I2S_CKIN | MCO2 | TIM8_CH4 | SDIO_D1 | I2C3_SDA | DCMI_D3 | TIM3_CH4 + {GPIOC, 10, NULL, 0, NULL, ADCx}, // D42/PC10 | 78 | SPI3_SCK | I2S3_CK | UART4_TX | SDIO_D2 | DCMI_D8 | USART3_TX + {GPIOC, 11, NULL, 0, NULL, ADCx}, // D43/PC11 | 79 | UART4_RX | SPI3_MISO | SDIO_D3 | DCMI_D4 | USART3_RX | I2S3ext_SD + {GPIOC, 12, NULL, 0, NULL, ADCx}, // D44/PC12 | 80 | UART5_TX | SDIO_CK | DCMI_D9 | SPI3_MOSI | I2S3_SD | USART3_CK + {GPIOC, 13, NULL, 0, NULL, ADCx}, // D45/PC13 | 7 | RTC_OUT, RTC_TAMP1, RTC_TS + {GPIOC, 14, NULL, 0, NULL, ADCx}, // D46/PC14 | 8 | OSC32_IN + {GPIOC, 15, NULL, 0, NULL, ADCx}, // D47/PC15 | 9 | OSC32_OUT + + {GPIOD, 0, NULL, 0, NULL, ADCx}, // D48/PD0 | 81 | FSMC_D2 | CAN1_RX + {GPIOD, 1, NULL, 0, NULL, ADCx}, // D49/PD1 | 82 | FSMC_D3 | CAN1_TX + {GPIOD, 2, NULL, 0, NULL, ADCx}, // D50/PD2 | 83 | TIM3_ETR | UART5_RX | SDIO_CMD | DCMI_D11 + {GPIOD, 3, NULL, 0, NULL, ADCx}, // D51/PD3 | 84 | FSMC_CLK | USART2_CTS + {GPIOD, 4, NULL, 0, NULL, ADCx}, // D52/PD4 | 85 | FSMC_NOE | USART2_RTS + {GPIOD, 5, NULL, 0, NULL, ADCx}, // D53/PD5 | 86 | FSMC_NWE | USART2_TX + {GPIOD, 6, NULL, 0, NULL, ADCx}, // D54/PD6 | 87 | FSMC_NWAIT | USART2_RX + {GPIOD, 7, NULL, 0, NULL, ADCx}, // D55/PD7 | 88 | USART2_CK | FSMC_NE1 | FSMC_NCE2 + {GPIOD, 8, NULL, 0, NULL, ADCx}, // D56/PD8 | 55 | FSMC_D13 | USART3_TX + {GPIOD, 9, NULL, 0, NULL, ADCx}, // D57/PD9 | 56 | FSMC_D14 | USART3_RX + {GPIOD, 10, NULL, 0, NULL, ADCx}, // D58/PD10 | 57 | FSMC_D15 | USART3_CK + {GPIOD, 11, NULL, 0, NULL, ADCx}, // D59/PD11 | 58 | FSMC_CLE | FSMC_A16 | USART3_CTS + {GPIOD, 12, TIMER4, 1, NULL, ADCx}, // D60/PD12 | 59 | FSMC_ALE | FSMC_A17 | TIM4_CH1 | USART3_RTS // remap in + {GPIOD, 13, TIMER4, 2, NULL, ADCx}, // D61/PD13 | 60 | FSMC_A18 | TIM4_CH2 // remap in + {GPIOD, 14, TIMER4, 3, NULL, ADCx}, // D62/PD14 | 61 | FSMC_D0 | TIM4_CH3 // remap in + {GPIOD, 15, TIMER4, 4, NULL, ADCx}, // D63/PD15 | 62 | FSMC_D1 | TIM4_CH4 // remap in + + {GPIOE, 0, NULL, 0, NULL, ADCx}, // D64/PE0 | 97 | TIM4_ETR | FSMC_NBL0 | DCMI_D2 + {GPIOE, 1, NULL, 0, NULL, ADCx}, // D65/PE1 | 98 | FSMC_NBL1 | DCMI_D3 + {GPIOE, 2, NULL, 0, NULL, ADCx}, // D66/PE2 | 1 | TRACECLK | FSMC_A23 | ETH_MII_TXD3 + {GPIOE, 3, NULL, 0, NULL, ADCx}, // D67/PE3 | 2 | TRACED0 | FSMC_A19 + {GPIOE, 4, NULL, 0, NULL, ADCx}, // D68/PE4 | 3 | TRACED1 | FSMC_A20 | DCMI_D4 + {GPIOE, 5, NULL, 0, NULL, ADCx}, // D69/PE5 | 4 | TRACED2 | FSMC_A21 | TIM9_CH1 / DCMI_D6 + {GPIOE, 6, NULL, 0, NULL, ADCx}, // D70/PE6 | 5 | TRACED3 | FSMC_A22 | TIM9_CH2 / DCMI_D7 + {GPIOE, 7, NULL, 0, NULL, ADCx}, // D71/PE7 | 38 | FSMC_D4 | TIM1_ETR + {GPIOE, 8, NULL, 0, NULL, ADCx}, // D72/PE8 | 39 | FSMC_D5 | TIM1_CH1N + {GPIOE, 9, TIMER1, 1, NULL, ADCx}, // D73/PE9 | 40 | FSMC_D6 | TIM1_CH1 // remap in + {GPIOE, 10, NULL, 0, NULL, ADCx}, // D74/PE10 | 41 | FSMC_D7 | TIM1_CH2N + {GPIOE, 11, TIMER1, 2, NULL, ADCx}, // D75/PE11 | 42 | FSMC_D8 | TIM1_CH2 // remap in + {GPIOE, 12, NULL, 0, NULL, ADCx}, // D76/PE12 | 43 | FSMC_D9 | TIM1_CH3N + {GPIOE, 13, TIMER1, 3, NULL, ADCx}, // D77/PE13 | 44 | FSMC_D10 | TIM1_CH3 // remap in + {GPIOE, 14, TIMER1, 4, NULL, ADCx}, // D78/PE14 | 45 | FSMC_D11 | TIM1_CH4 // remap in + {GPIOE, 15, NULL, 0, NULL, ADCx}, // D79/PE15 | 46 | FSMC_D12 | TIM1_BKIN +#if 0 + {GPIOF, 0, NULL, 0, NULL, ADCx}, // D80/PF0 + {GPIOF, 1, NULL, 0, NULL, ADCx}, // D81/PF1 + {GPIOF, 2, NULL, 0, NULL, ADCx}, // D82/PF2 + {GPIOF, 3, NULL, 0, NULL, ADCx}, // D83/PF3 + {GPIOF, 4, NULL, 0, NULL, ADCx}, // D84/PF4 + {GPIOF, 5, NULL, 0, NULL, ADCx}, // D85/PF5 + {GPIOF, 6, NULL, 0, NULL, ADCx}, // D86/PF6 + {GPIOF, 7, NULL, 0, NULL, ADCx}, // D87/PF7 + {GPIOF, 8, NULL, 0, NULL, ADCx}, // D88/PF8 + {GPIOF, 9, NULL, 0, NULL, ADCx}, // D89/PF9 + {GPIOF, 10, NULL, 0, NULL, ADCx}, // D90/PF10 + {GPIOF, 11, NULL, 0, NULL, ADCx}, // D91/PF11 + {GPIOF, 12, NULL, 0, NULL, ADCx}, // D92/PF12 + {GPIOF, 13, NULL, 0, NULL, ADCx}, // D93/PF13 + {GPIOF, 14, NULL, 0, NULL, ADCx}, // D94/PF14 + {GPIOF, 15, NULL, 0, NULL, ADCx}, // D95/PF15 + + {GPIOG, 0, NULL, 0, NULL, ADCx}, // D96/PG0 + {GPIOG, 1, NULL, 0, NULL, ADCx}, // D97/PG1 + {GPIOG, 2, NULL, 0, NULL, ADCx}, // D98/PG2 + {GPIOG, 3, NULL, 0, NULL, ADCx}, // D99/PG3 + {GPIOG, 4, NULL, 0, NULL, ADCx}, // D100/PG4 + {GPIOG, 5, NULL, 0, NULL, ADCx}, // D101/PG5 + {GPIOG, 6, NULL, 0, NULL, ADCx}, // D102/PG6 + {GPIOG, 7, NULL, 0, NULL, ADCx}, // D103/PG7 + {GPIOG, 8, NULL, 0, NULL, ADCx}, // D104/PG8 + {GPIOG, 9, NULL, 0, NULL, ADCx}, // D105/PG9 + {GPIOG, 10, NULL, 0, NULL, ADCx}, // D106/PG10 + {GPIOG, 11, NULL, 0, NULL, ADCx}, // D107/PG11 + {GPIOG, 12, NULL, 0, NULL, ADCx}, // D108/PG12 + {GPIOG, 13, NULL, 0, NULL, ADCx}, // D109/PG13 + {GPIOG, 14, NULL, 0, NULL, ADCx}, // D110/PG14 + {GPIOG, 15, NULL, 0, NULL, ADCx} // D111/PG15 +#endif +}; +/* to be defined +extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { + 0, 1, 2, 3, 15, 16, 17, 19, 20, 21, 38, 39, 49, 41, 60, 61, 62, 63, 73, 75, 77, 78 +}; +*/ +extern const uint8 boardADCPins[BOARD_NR_ADC_PINS] __FLASH__ = { + PA0, PA1, PA2, PA3, PA4, PA5, PA6, PA7, PB0, PB1, PC0, PC1, PC2, PC3, PC4, PC5 +}; + +extern const uint8 boardUsedPins[BOARD_NR_USED_PINS] __FLASH__ = { + BOARD_LED_PIN, BOARD_LED2_PIN, BOARD_BUTTON1_PIN, BOARD_BUTTON2_PIN, BOARD_BUTTON2_PIN, + BOARD_JTMS_SWDIO_PIN, BOARD_JTCK_SWCLK_PIN, + FLASH_CS_PIN, FLASH_CLK_PIN, FLASH_DO_PIN, FLASH_DI_PIN, + NRF24_CE_PIN, NRF24_CS_PIN, NRF24_IRQ_PIN, + BOARD_SDIO_D0, BOARD_SDIO_D1, BOARD_SDIO_D2, BOARD_SDIO_D3, BOARD_SDIO_CK, BOARD_SDIO_CMD, + USB_DM_PIN, USB_DP_PIN +}; +/* +static void initSRAMChip(void) { + fsmc_nor_psram_reg_map *regs = FSMC_NOR_PSRAM1_BASE; + + fsmc_sram_init_gpios(); + rcc_clk_enable(RCC_FSMC); + + regs->BCR = (FSMC_BCR_WREN | FSMC_BCR_MWID_16BITS | FSMC_BCR_MTYP_SRAM | + FSMC_BCR_MBKEN); + fsmc_nor_psram_set_addset(regs, 0); + fsmc_nor_psram_set_datast(regs, 3); +} +*/ +#endif diff --git a/STM32F4/variants/black_f407vet6/black_f4.h b/STM32F4/variants/black_f407vet6/black_f4.h new file mode 100644 index 0000000..6f5d3da --- /dev/null +++ b/STM32F4/variants/black_f407vet6/black_f4.h @@ -0,0 +1,130 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file black_f4.h + * @author Marti Bolivar + * @brief Private include file for Maple Native in boards.h + * + * See maple.h for more information on these definitions. + */ + +#ifndef _BOARD_BLACK_F4_H_ +#define _BOARD_BLACK_F4_H_ + +#define Port2Pin(port, bit) ((port-'A')*16+bit) + +#define CYCLES_PER_MICROSECOND 168 + + +#undef STM32_PCLK1 +#undef STM32_PCLK2 +#define STM32_PCLK1 (CYCLES_PER_MICROSECOND*1000000/4) +#define STM32_PCLK2 (CYCLES_PER_MICROSECOND*1000000/2) + +#define SYSTICK_RELOAD_VAL (CYCLES_PER_MICROSECOND*1000-1) + +#define BOARD_USB_DM_PIN PA11 +#define BOARD_USB_DP_PIN PA12 + +#define BOARD_LED_PIN PA6 //Port2Pin('A', 6) +#define BOARD_LED2_PIN PA7 //Port2Pin('A', 7) +#define BOARD_BUTTON1_PIN PA0 //Port2Pin('A', 0) +#define BOARD_BUTTON2_PIN PE4 //Port2Pin('E', 4) +#define BOARD_BUTTON3_PIN PE3 //Port2Pin('E', 3) + +#define BOARD_NR_USARTS 5 +#define BOARD_USART1_TX_PIN PA9 //Port2Pin('A', 9) +#define BOARD_USART1_RX_PIN PA10 //Port2Pin('A',10) +#define BOARD_USART2_TX_PIN PA2 //Port2Pin('A', 2) +#define BOARD_USART2_RX_PIN PA3 //Port2Pin('A', 3) +#define BOARD_USART3_TX_PIN PB10 //Port2Pin('B',10) +#define BOARD_USART3_RX_PIN PB11 //Port2Pin('B',11) +#define BOARD_UART4_TX_PIN PA0 //Port2Pin('A', 0) +#define BOARD_UART4_RX_PIN PA1 //Port2Pin('A', 1) +#define BOARD_UART5_TX_PIN PC12 //Port2Pin('C',12) +#define BOARD_UART5_RX_PIN PD2 //Port2Pin('D', 2) + +#define BOARD_NR_SPI 3 +#define BOARD_SPI1_NSS_PIN PA4 //Port2Pin('A', 4) +#define BOARD_SPI1_SCK_PIN PA5 //Port2Pin('A', 5) +#define BOARD_SPI1_MISO_PIN PA6 //Port2Pin('A', 6) +#define BOARD_SPI1_MOSI_PIN PA7 //Port2Pin('A', 7) +#define BOARD_SPI1A_NSS_PIN PA15 //Port2Pin('A',15) +#define BOARD_SPI1A_SCK_PIN PB3 //Port2Pin('B', 3) +#define BOARD_SPI1A_MISO_PIN PB4 //Port2Pin('B', 4) +#define BOARD_SPI1A_MOSI_PIN PB5 //Port2Pin('B', 5) + +#define BOARD_SPI2_NSS_PIN PB12 //Port2Pin('B',12) +#define BOARD_SPI2_SCK_PIN PB13 //Port2Pin('B',13) +#define BOARD_SPI2_MISO_PIN PB14 //Port2Pin('B',14) +#define BOARD_SPI2_MOSI_PIN PB15 //Port2Pin('B',15) +#define BOARD_SPI2A_NSS_PIN PB9 //Port2Pin('B', 9) +#define BOARD_SPI2A_SCK_PIN PB10 //Port2Pin('B',10) +#define BOARD_SPI2A_MISO_PIN PC2 //Port2Pin('C', 2) +#define BOARD_SPI2A_MOSI_PIN pc3 //Port2Pin('C', 3) + +#define BOARD_SPI3_NSS_PIN PA15 //Port2Pin('A',15) +#define BOARD_SPI3_SCK_PIN PB3 //Port2Pin('B', 3) +#define BOARD_SPI3_MISO_PIN PB4 //Port2Pin('B', 4) +#define BOARD_SPI3_MOSI_PIN PB5 //Port2Pin('B', 5) +/* overlap with the SDIO interface for SD card +#define BOARD_SPI3A_NSS_PIN Port2Pin('A', 4) +#define BOARD_SPI3A_SCK_PIN Port2Pin('C',10) +#define BOARD_SPI3A_MISO_PIN Port2Pin('C',11) +#define BOARD_SPI3A_MOSI_PIN Port2Pin('C',12) +*/ +#define BOARD_SDIO_D0 PC8 //Port2Pin('C', 8) +#define BOARD_SDIO_D1 PC9 //Port2Pin('C', 9) +#define BOARD_SDIO_D2 PC10 //Port2Pin('C',10) +#define BOARD_SDIO_D3 PC11 //Port2Pin('C',11) +#define BOARD_SDIO_CK PC12 //Port2Pin('C',12) +#define BOARD_SDIO_CMD PD2 //Port2Pin('D', 2) + +#define BOARD_NR_GPIO_PINS 80 +#define BOARD_NR_PWM_PINS 22 +#define BOARD_NR_ADC_PINS 16 +#define BOARD_NR_USED_PINS 22 +#define BOARD_JTMS_SWDIO_PIN PA13 //Port2Pin('A',13) +#define BOARD_JTCK_SWCLK_PIN PA14 //Port2Pin('A',14) +#define BOARD_JTDI_PIN PA15 //Port2Pin('A',15) +#define BOARD_JTDO_PIN PB3 //Port2Pin('B', 3) +#define BOARD_NJTRST_PIN PB4 //Port2Pin('B', 4) + + +enum { +PA0,PA1,PA2,PA3,PA4,PA5,PA6,PA7,PA8,PA9,PA10,PA11,PA12,PA13,PA14,PA15, +PB0,PB1,PB2,PB3,PB4,PB5,PB6,PB7,PB8,PB9,PB10,PB11,PB12,PB13,PB14,PB15, +PC0,PC1,PC2,PC3,PC4,PC5,PC6,PC7,PC8,PC9,PC10,PC11,PC12,PC13,PC14,PC15, +PD0,PD1,PD2,PD3,PD4,PD5,PD6,PD7,PD8,PD9,PD10,PD11,PD12,PD13,PD14,PD15, +PE0,PE1,PE2,PE3,PE4,PE5,PE6,PE7,PE8,PE9,PE10,PE11,PE12,PE13,PE14,PE15, +#if 0 +PF0,PF1,PF2,PF3,PF4,PF5,PF6,PF7,PF8,PF9,PF10,PF11,PF12,PF13,PF14,PF15, +PG0,PG1,PG2,PG3,PG4,PG5,PG6,PG7,PG8,PG9,PG10,PG11,PG12,PG13,PG14,PG15 +#endif +}; + +#endif diff --git a/STM32F4/variants/black_f407vet6/ld/common.inc b/STM32F4/variants/black_f407vet6/ld/common.inc new file mode 100644 index 0000000..f5a0f5b --- /dev/null +++ b/STM32F4/variants/black_f407vet6/ld/common.inc @@ -0,0 +1,219 @@ +/* + * Linker script for libmaple. + * + * Original author "lanchon" from ST forums, with modifications by LeafLabs. + */ + +OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") + +/* + * Configure other libraries we want in the link. + * + * libgcc, libc, and libm are common across supported toolchains. + * However, some toolchains require additional archives which aren't + * present everywhere (e.g. ARM's gcc-arm-embedded releases). + * + * To hack around this, we let the build system specify additional + * archives by putting the right extra_libs.inc (in a directory under + * toolchains/) in our search path. + */ +GROUP(libgcc.a libc.a libm.a) +INCLUDE extra_libs.inc + +/* + * These force the linker to search for vector table symbols. + * + * These symbols vary by STM32 family (and also within families). + * It's up to the build system to configure the link's search path + * properly for the target MCU. + */ +INCLUDE vector_symbols.inc + +/* STM32 vector table. */ +EXTERN(__stm32_vector_table) + +/* C runtime initialization function. */ +EXTERN(start_c) + +/* main entry point */ +EXTERN(main) + +/* Initial stack pointer value. */ +EXTERN(__msp_init) +PROVIDE(__msp_init = ORIGIN(ram) + LENGTH(ram)); + +/* Reset vector and chip reset entry point */ +EXTERN(__start__) +ENTRY(__start__) +PROVIDE(__exc_reset = __start__); + +/* Heap boundaries, for libmaple */ +EXTERN(_lm_heap_start); +EXTERN(_lm_heap_end); + +SECTIONS +{ + .text : + { + __text_start__ = .; + /* + * STM32 vector table. Leave this here. Yes, really. + */ + *(.stm32.interrupt_vector) + + /* + * Program code and vague linking + */ + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + *(.gnu.warning) + *(.glue_7t) *(.glue_7) *(.vfp11_veneer) + + *(.ARM.extab* .gnu.linkonce.armextab.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + . = ALIGN(4); + KEEP(*(.init)) + + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + + . = ALIGN(0x4); + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + + . = ALIGN(4); + KEEP(*(.fini)) + + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + } > REGION_TEXT + + /* + * End of text + */ + .text.align : + { + . = ALIGN(8); + __text_end__ = .; + } > REGION_TEXT + + /* + * .ARM.exidx exception unwinding; mandated by ARM's C++ ABI + */ + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > REGION_RODATA + __exidx_end = .; + + /* + * .data + */ + .data : + { + . = ALIGN(8); + __data_start__ = .; + + *(.got.plt) *(.got) + *(.data .data.* .gnu.linkonce.d.*) + + . = ALIGN(8); + __data_end__ = .; + } > REGION_DATA AT> REGION_RODATA + + /* + * Read-only data + */ + .rodata : + { + *(.rodata .rodata.* .gnu.linkonce.r.*) + /* .USER_FLASH: We allow users to allocate into Flash here */ + *(.USER_FLASH) + /* ROM image configuration; for C startup */ + . = ALIGN(4); + _lm_rom_img_cfgp = .; + LONG(LOADADDR(.data)); + /* + * Heap: Linker scripts may choose a custom heap by overriding + * _lm_heap_start and _lm_heap_end. Otherwise, the heap is in + * internal SRAM, beginning after .bss, and growing towards + * the stack. + * + * I'm shoving these here naively; there's probably a cleaner way + * to go about this. [mbolivar] + */ + _lm_heap_start = DEFINED(_lm_heap_start) ? _lm_heap_start : _end; + _lm_heap_end = DEFINED(_lm_heap_end) ? _lm_heap_end : __msp_init; + } > REGION_RODATA + + /* + * .bss + */ + .bss : + { + . = ALIGN(8); + __bss_start__ = .; + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN (8); + __bss_end__ = .; + _end = __bss_end__; + } > REGION_BSS + + /* + * Debugging sections + */ + .stab 0 (NOLOAD) : { *(.stab) } + .stabstr 0 (NOLOAD) : { *(.stabstr) } + /* DWARF debug sections. + * Symbols in the DWARF debugging sections are relative to the beginning + * of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + + .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) } + .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) } + /DISCARD/ : { *(.note.GNU-stack) } +} diff --git a/STM32F4/variants/black_f407vet6/ld/extra_libs.inc b/STM32F4/variants/black_f407vet6/ld/extra_libs.inc new file mode 100644 index 0000000..dd2c84f --- /dev/null +++ b/STM32F4/variants/black_f407vet6/ld/extra_libs.inc @@ -0,0 +1,7 @@ +/* + * Extra archives needed by ARM's GCC ARM Embedded arm-none-eabi- + * releases (https://launchpad.net/gcc-arm-embedded/). + */ + +/* This is for the provided newlib. */ +GROUP(libnosys.a) diff --git a/STM32F4/variants/black_f407vet6/ld/flash.ld b/STM32F4/variants/black_f407vet6/ld/flash.ld new file mode 100644 index 0000000..c753a78 --- /dev/null +++ b/STM32F4/variants/black_f407vet6/ld/flash.ld @@ -0,0 +1,20 @@ +/* + * Discovery F4 (STM32F407VGT6, high density) linker script for + * Flash builds. + */ + +MEMORY +{ + ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 125K + rom (rx) : ORIGIN = 0x08010000, LENGTH = 960K /* ala42 */ +} + +/* GROUP(libcs4_stm32_high_density.a) */ + +REGION_ALIAS("REGION_TEXT", rom); +REGION_ALIAS("REGION_DATA", ram); +REGION_ALIAS("REGION_BSS", ram); +REGION_ALIAS("REGION_RODATA", rom); + +_FLASH_BUILD = 1; +INCLUDE common.inc diff --git a/STM32F4/variants/black_f407vet6/ld/jtag.ld b/STM32F4/variants/black_f407vet6/ld/jtag.ld new file mode 100644 index 0000000..fe70f68 --- /dev/null +++ b/STM32F4/variants/black_f407vet6/ld/jtag.ld @@ -0,0 +1,20 @@ +/* + * STM32F4xx high density linker script for + * JTAG (bare metal, no bootloader) builds. + */ + +MEMORY +{ + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 64K + rom (rx) : ORIGIN = 0x08000000, LENGTH = 512K +} + +/* GROUP(libcs3_stm32_high_density.a) */ + +REGION_ALIAS("REGION_TEXT", rom); +REGION_ALIAS("REGION_DATA", ram); +REGION_ALIAS("REGION_BSS", ram); +REGION_ALIAS("REGION_RODATA", rom); + +_FLASH_BUILD = 1; +INCLUDE common.inc diff --git a/STM32F4/variants/black_f407vet6/ld/names.inc b/STM32F4/variants/black_f407vet6/ld/names.inc new file mode 100644 index 0000000..6d7ff6e --- /dev/null +++ b/STM32F4/variants/black_f407vet6/ld/names.inc @@ -0,0 +1,78 @@ +EXTERN(__cs3_stack) +EXTERN(__cs3_reset) +EXTERN(__exc_nmi) +EXTERN(__exc_hardfault) +EXTERN(__exc_memmanage) +EXTERN(__exc_busfault) +EXTERN(__exc_usagefault) +EXTERN(__stm32reservedexception7) +EXTERN(__stm32reservedexception8) +EXTERN(__stm32reservedexception9) +EXTERN(__stm32reservedexception10) +EXTERN(__exc_svc) +EXTERN(__exc_debug_monitor) +EXTERN(__stm32reservedexception13) +EXTERN(__exc_pendsv) +EXTERN(__exc_systick) + +EXTERN(__irq_wwdg) +EXTERN(__irq_pvd) +EXTERN(__irq_tamper) +EXTERN(__irq_rtc) +EXTERN(__irq_flash) +EXTERN(__irq_rcc) +EXTERN(__irq_exti0) +EXTERN(__irq_exti1) +EXTERN(__irq_exti2) +EXTERN(__irq_exti3) +EXTERN(__irq_exti4) +EXTERN(__irq_dma1_channel1) +EXTERN(__irq_dma1_channel2) +EXTERN(__irq_dma1_channel3) +EXTERN(__irq_dma1_channel4) +EXTERN(__irq_dma1_channel5) +EXTERN(__irq_dma1_channel6) +EXTERN(__irq_dma1_channel7) +EXTERN(__irq_adc) +EXTERN(__irq_usb_hp_can_tx) +EXTERN(__irq_usb_lp_can_rx0) +EXTERN(__irq_can_rx1) +EXTERN(__irq_can_sce) +EXTERN(__irq_exti9_5) +EXTERN(__irq_tim1_brk) +EXTERN(__irq_tim1_up) +EXTERN(__irq_tim1_trg_com) +EXTERN(__irq_tim1_cc) +EXTERN(__irq_tim2) +EXTERN(__irq_tim3) +EXTERN(__irq_tim4) +EXTERN(__irq_i2c1_ev) +EXTERN(__irq_i2c1_er) +EXTERN(__irq_i2c2_ev) +EXTERN(__irq_i2c2_er) +EXTERN(__irq_spi1) +EXTERN(__irq_spi2) +EXTERN(__irq_usart1) +EXTERN(__irq_usart2) +EXTERN(__irq_usart3) +EXTERN(__irq_exti15_10) +EXTERN(__irq_rtcalarm) +EXTERN(__irq_usbwakeup) + +EXTERN(__irq_tim8_brk) +EXTERN(__irq_tim8_up) +EXTERN(__irq_tim8_trg_com) +EXTERN(__irq_tim8_cc) +EXTERN(__irq_adc3) +EXTERN(__irq_fsmc) +EXTERN(__irq_sdio) +EXTERN(__irq_tim5) +EXTERN(__irq_spi3) +EXTERN(__irq_uart4) +EXTERN(__irq_uart5) +EXTERN(__irq_tim6) +EXTERN(__irq_tim7) +EXTERN(__irq_dma2_channel1) +EXTERN(__irq_dma2_channel2) +EXTERN(__irq_dma2_channel3) +EXTERN(__irq_dma2_channel4_5) diff --git a/STM32F4/variants/black_f407vet6/ld/ram.ld b/STM32F4/variants/black_f407vet6/ld/ram.ld new file mode 100644 index 0000000..b57060c --- /dev/null +++ b/STM32F4/variants/black_f407vet6/ld/ram.ld @@ -0,0 +1,19 @@ +/* + * aeroquad32 (STM32F103VET6, high density) linker script for + * RAM builds. + */ + +MEMORY +{ + ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 61K + rom (rx) : ORIGIN = 0x08010000, LENGTH = 0K /* ala42 */ +} + +GROUP(libcs3_stm32_high_density.a) + +REGION_ALIAS("REGION_TEXT", ram); +REGION_ALIAS("REGION_DATA", ram); +REGION_ALIAS("REGION_BSS", ram); +REGION_ALIAS("REGION_RODATA", ram); + +INCLUDE common.inc diff --git a/STM32F4/variants/black_f407vet6/ld/vector_symbols.inc b/STM32F4/variants/black_f407vet6/ld/vector_symbols.inc new file mode 100644 index 0000000..f8519bb --- /dev/null +++ b/STM32F4/variants/black_f407vet6/ld/vector_symbols.inc @@ -0,0 +1,78 @@ +EXTERN(__msp_init) +EXTERN(__exc_reset) +EXTERN(__exc_nmi) +EXTERN(__exc_hardfault) +EXTERN(__exc_memmanage) +EXTERN(__exc_busfault) +EXTERN(__exc_usagefault) +EXTERN(__stm32reservedexception7) +EXTERN(__stm32reservedexception8) +EXTERN(__stm32reservedexception9) +EXTERN(__stm32reservedexception10) +EXTERN(__exc_svc) +EXTERN(__exc_debug_monitor) +EXTERN(__stm32reservedexception13) +EXTERN(__exc_pendsv) +EXTERN(__exc_systick) + +EXTERN(__irq_wwdg) +EXTERN(__irq_pvd) +EXTERN(__irq_tamper) +EXTERN(__irq_rtc) +EXTERN(__irq_flash) +EXTERN(__irq_rcc) +EXTERN(__irq_exti0) +EXTERN(__irq_exti1) +EXTERN(__irq_exti2) +EXTERN(__irq_exti3) +EXTERN(__irq_exti4) +EXTERN(__irq_dma1_channel1) +EXTERN(__irq_dma1_channel2) +EXTERN(__irq_dma1_channel3) +EXTERN(__irq_dma1_channel4) +EXTERN(__irq_dma1_channel5) +EXTERN(__irq_dma1_channel6) +EXTERN(__irq_dma1_channel7) +EXTERN(__irq_adc) +EXTERN(__irq_usb_hp_can_tx) +EXTERN(__irq_usb_lp_can_rx0) +EXTERN(__irq_can_rx1) +EXTERN(__irq_can_sce) +EXTERN(__irq_exti9_5) +EXTERN(__irq_tim1_brk) +EXTERN(__irq_tim1_up) +EXTERN(__irq_tim1_trg_com) +EXTERN(__irq_tim1_cc) +EXTERN(__irq_tim2) +EXTERN(__irq_tim3) +EXTERN(__irq_tim4) +EXTERN(__irq_i2c1_ev) +EXTERN(__irq_i2c1_er) +EXTERN(__irq_i2c2_ev) +EXTERN(__irq_i2c2_er) +EXTERN(__irq_spi1) +EXTERN(__irq_spi2) +EXTERN(__irq_usart1) +EXTERN(__irq_usart2) +EXTERN(__irq_usart3) +EXTERN(__irq_exti15_10) +EXTERN(__irq_rtcalarm) +EXTERN(__irq_usbwakeup) + +EXTERN(__irq_tim8_brk) +EXTERN(__irq_tim8_up) +EXTERN(__irq_tim8_trg_com) +EXTERN(__irq_tim8_cc) +EXTERN(__irq_adc3) +EXTERN(__irq_fsmc) +EXTERN(__irq_sdio) +EXTERN(__irq_tim5) +EXTERN(__irq_spi3) +EXTERN(__irq_uart4) +EXTERN(__irq_uart5) +EXTERN(__irq_tim6) +EXTERN(__irq_tim7) +EXTERN(__irq_dma2_channel1) +EXTERN(__irq_dma2_channel2) +EXTERN(__irq_dma2_channel3) +EXTERN(__irq_dma2_channel4_5) diff --git a/STM32F4/variants/black_f407vet6/pins_arduino.h b/STM32F4/variants/black_f407vet6/pins_arduino.h new file mode 100644 index 0000000..3052f2e --- /dev/null +++ b/STM32F4/variants/black_f407vet6/pins_arduino.h @@ -0,0 +1,6 @@ + + + + +// API compatibility +#include "variant.h" \ No newline at end of file diff --git a/STM32F4/variants/black_f407vet6/stm32_isrs.S b/STM32F4/variants/black_f407vet6/stm32_isrs.S new file mode 100644 index 0000000..34e515c --- /dev/null +++ b/STM32F4/variants/black_f407vet6/stm32_isrs.S @@ -0,0 +1,323 @@ +/* STM32 ISR weak declarations */ + + .thumb + +/* Default handler for all non-overridden interrupts and exceptions */ + .globl __default_handler + .type __default_handler, %function + +__default_handler: + b . + + .weak __exc_nmi + .globl __exc_nmi + .set __exc_nmi, __default_handler + .weak __exc_hardfault + .globl __exc_hardfault + .set __exc_hardfault, __default_handler + .weak __exc_memmanage + .globl __exc_memmanage + .set __exc_memmanage, __default_handler + .weak __exc_busfault + .globl __exc_busfault + .set __exc_busfault, __default_handler + .weak __exc_usagefault + .globl __exc_usagefault + .set __exc_usagefault, __default_handler + .weak __stm32reservedexception7 + .globl __stm32reservedexception7 + .set __stm32reservedexception7, __default_handler + .weak __stm32reservedexception8 + .globl __stm32reservedexception8 + .set __stm32reservedexception8, __default_handler + .weak __stm32reservedexception9 + .globl __stm32reservedexception9 + .set __stm32reservedexception9, __default_handler + .weak __stm32reservedexception10 + .globl __stm32reservedexception10 + .set __stm32reservedexception10, __default_handler + .weak __exc_svc + .globl __exc_svc + .set __exc_svc, __default_handler + .weak __exc_debug_monitor + .globl __exc_debug_monitor + .set __exc_debug_monitor, __default_handler + .weak __stm32reservedexception13 + .globl __stm32reservedexception13 + .set __stm32reservedexception13, __default_handler + .weak __exc_pendsv + .globl __exc_pendsv + .set __exc_pendsv, __default_handler + .weak __exc_systick + .globl __exc_systick + .set __exc_systick, __default_handler + .weak __irq_wwdg + .globl __irq_wwdg + .set __irq_wwdg, __default_handler + .weak __irq_pvd + .globl __irq_pvd + .set __irq_pvd, __default_handler + .weak __irq_tamper + .globl __irq_tamper + .set __irq_tamper, __default_handler + .weak __irq_rtc + .globl __irq_rtc + .set __irq_rtc, __default_handler + .weak __irq_flash + .globl __irq_flash + .set __irq_flash, __default_handler + .weak __irq_rcc + .globl __irq_rcc + .set __irq_rcc, __default_handler + .weak __irq_exti0 + .globl __irq_exti0 + .set __irq_exti0, __default_handler + .weak __irq_exti1 + .globl __irq_exti1 + .set __irq_exti1, __default_handler + .weak __irq_exti2 + .globl __irq_exti2 + .set __irq_exti2, __default_handler + .weak __irq_exti3 + .globl __irq_exti3 + .set __irq_exti3, __default_handler + .weak __irq_exti4 + .globl __irq_exti4 + .set __irq_exti4, __default_handler + .weak __irq_dma1_channel1 + .globl __irq_dma1_channel1 + .set __irq_dma1_channel1, __default_handler + .weak __irq_dma1_channel2 + .globl __irq_dma1_channel2 + .set __irq_dma1_channel2, __default_handler + .weak __irq_dma1_channel3 + .globl __irq_dma1_channel3 + .set __irq_dma1_channel3, __default_handler + .weak __irq_dma1_channel4 + .globl __irq_dma1_channel4 + .set __irq_dma1_channel4, __default_handler + .weak __irq_dma1_channel5 + .globl __irq_dma1_channel5 + .set __irq_dma1_channel5, __default_handler + .weak __irq_dma1_channel6 + .globl __irq_dma1_channel6 + .set __irq_dma1_channel6, __default_handler + .weak __irq_dma1_channel7 + .globl __irq_dma1_channel7 + .set __irq_dma1_channel7, __default_handler + .weak __irq_adc + .globl __irq_adc + .set __irq_adc, __default_handler + .weak __irq_usb_hp_can_tx + .globl __irq_usb_hp_can_tx + .set __irq_usb_hp_can_tx, __default_handler + .weak __irq_usb_lp_can_rx0 + .globl __irq_usb_lp_can_rx0 + .set __irq_usb_lp_can_rx0, __default_handler + .weak __irq_can_rx1 + .globl __irq_can_rx1 + .set __irq_can_rx1, __default_handler + .weak __irq_can_sce + .globl __irq_can_sce + .set __irq_can_sce, __default_handler + .weak __irq_exti9_5 + .globl __irq_exti9_5 + .set __irq_exti9_5, __default_handler + .weak __irq_tim1_brk + .globl __irq_tim1_brk + .set __irq_tim1_brk, __default_handler + .weak __irq_tim1_up + .globl __irq_tim1_up + .set __irq_tim1_up, __default_handler + .weak __irq_tim1_trg_com + .globl __irq_tim1_trg_com + .set __irq_tim1_trg_com, __default_handler + .weak __irq_tim1_cc + .globl __irq_tim1_cc + .set __irq_tim1_cc, __default_handler + .weak __irq_tim2 + .globl __irq_tim2 + .set __irq_tim2, __default_handler + .weak __irq_tim3 + .globl __irq_tim3 + .set __irq_tim3, __default_handler + .weak __irq_tim4 + .globl __irq_tim4 + .set __irq_tim4, __default_handler + .weak __irq_i2c1_ev + .globl __irq_i2c1_ev + .set __irq_i2c1_ev, __default_handler + .weak __irq_i2c1_er + .globl __irq_i2c1_er + .set __irq_i2c1_er, __default_handler + .weak __irq_i2c2_ev + .globl __irq_i2c2_ev + .set __irq_i2c2_ev, __default_handler + .weak __irq_i2c2_er + .globl __irq_i2c2_er + .set __irq_i2c2_er, __default_handler + .weak __irq_spi1 + .globl __irq_spi1 + .set __irq_spi1, __default_handler + .weak __irq_spi2 + .globl __irq_spi2 + .set __irq_spi2, __default_handler + .weak __irq_usart1 + .globl __irq_usart1 + .set __irq_usart1, __default_handler + .weak __irq_usart2 + .globl __irq_usart2 + .set __irq_usart2, __default_handler + .weak __irq_usart3 + .globl __irq_usart3 + .set __irq_usart3, __default_handler + .weak __irq_exti15_10 + .globl __irq_exti15_10 + .set __irq_exti15_10, __default_handler + .weak __irq_rtcalarm + .globl __irq_rtcalarm + .set __irq_rtcalarm, __default_handler + .weak __irq_usbwakeup + .globl __irq_usbwakeup + .set __irq_usbwakeup, __default_handler +#if defined (STM32_HIGH_DENSITY) + .weak __irq_tim8_brk + .globl __irq_tim8_brk + .set __irq_tim8_brk, __default_handler + .weak __irq_tim8_up + .globl __irq_tim8_up + .set __irq_tim8_up, __default_handler + .weak __irq_tim8_trg_com + .globl __irq_tim8_trg_com + .set __irq_tim8_trg_com, __default_handler + .weak __irq_tim8_cc + .globl __irq_tim8_cc + .set __irq_tim8_cc, __default_handler + .weak __irq_adc3 + .globl __irq_adc3 + .set __irq_adc3, __default_handler + .weak __irq_fsmc + .globl __irq_fsmc + .set __irq_fsmc, __default_handler + .weak __irq_sdio + .globl __irq_sdio + .set __irq_sdio, __default_handler + .weak __irq_tim5 + .globl __irq_tim5 + .set __irq_tim5, __default_handler + .weak __irq_spi3 + .globl __irq_spi3 + .set __irq_spi3, __default_handler + .weak __irq_uart4 + .globl __irq_uart4 + .set __irq_uart4, __default_handler + .weak __irq_uart5 + .globl __irq_uart5 + .set __irq_uart5, __default_handler + .weak __irq_tim6 + .globl __irq_tim6 + .set __irq_tim6, __default_handler + .weak __irq_tim7 + .globl __irq_tim7 + .set __irq_tim7, __default_handler + .weak __irq_dma2_channel1 + .globl __irq_dma2_channel1 + .set __irq_dma2_channel1, __default_handler + .weak __irq_dma2_channel2 + .globl __irq_dma2_channel2 + .set __irq_dma2_channel2, __default_handler + .weak __irq_dma2_channel3 + .globl __irq_dma2_channel3 + .set __irq_dma2_channel3, __default_handler + .weak __irq_dma2_channel4_5 + .globl __irq_dma2_channel4_5 + .set __irq_dma2_channel4_5, __default_handler +#endif /* STM32_HIGH_DENSITY */ + + .weak __irq_DMA2_Stream4_IRQHandler + .globl __irq_DMA2_Stream4_IRQHandler + .set __irq_DMA2_Stream4_IRQHandler, __default_handler + + .weak __irq_ETH_IRQHandler + .globl __irq_ETH_IRQHandler + .set __irq_ETH_IRQHandler, __default_handler + + .weak __irq_ETH_WKUP_IRQHandler + .globl __irq_ETH_WKUP_IRQHandler + .set __irq_ETH_WKUP_IRQHandler, __default_handler + + .weak __irq_CAN2_TX_IRQHandler + .globl __irq_CAN2_TX_IRQHandler + .set __irq_CAN2_TX_IRQHandler, __default_handler + + .weak __irq_CAN2_RX0_IRQHandler + .globl __irq_CAN2_RX0_IRQHandler + .set __irq_CAN2_RX0_IRQHandler, __default_handler + + .weak __irq_CAN2_RX1_IRQHandler + .globl __irq_CAN2_RX1_IRQHandler + .set __irq_CAN2_RX1_IRQHandler, __default_handler + + .weak __irq_CAN2_SCE_IRQHandler + .globl __irq_CAN2_SCE_IRQHandler + .set __irq_CAN2_SCE_IRQHandler, __default_handler + + .weak __irq_OTG_FS_IRQHandler + .globl __irq_OTG_FS_IRQHandler + .set __irq_OTG_FS_IRQHandler, __default_handler + + .weak __irq_DMA2_Stream5_IRQHandler + .globl __irq_DMA2_Stream5_IRQHandler + .set __irq_DMA2_Stream5_IRQHandler, __default_handler + + .weak __irq_DMA2_Stream6_IRQHandler + .globl __irq_DMA2_Stream6_IRQHandler + .set __irq_DMA2_Stream6_IRQHandler, __default_handler + + .weak __irq_DMA2_Stream7_IRQHandler + .globl __irq_DMA2_Stream7_IRQHandler + .set __irq_DMA2_Stream7_IRQHandler, __default_handler + + .weak __irq_USART6_IRQHandler + .globl __irq_USART6_IRQHandler + .set __irq_USART6_IRQHandler, __default_handler + + .weak __irq_I2C3_EV_IRQHandler + .globl __irq_I2C3_EV_IRQHandler + .set __irq_I2C3_EV_IRQHandler, __default_handler + + .weak __irq_I2C3_ER_IRQHandler + .globl __irq_I2C3_ER_IRQHandler + .set __irq_I2C3_ER_IRQHandler, __default_handler + + .weak __irq_OTG_HS_EP1_OUT_IRQHandler + .globl __irq_OTG_HS_EP1_OUT_IRQHandler + .set __irq_OTG_HS_EP1_OUT_IRQHandler, __default_handler + + .weak __irq_OTG_HS_EP1_IN_IRQHandler + .globl __irq_OTG_HS_EP1_IN_IRQHandler + .set __irq_OTG_HS_EP1_IN_IRQHandler, __default_handler + + .weak __irq_OTG_HS_WKUP_IRQHandler + .globl __irq_OTG_HS_WKUP_IRQHandler + .set __irq_OTG_HS_WKUP_IRQHandler, __default_handler + + .weak __irq_OTG_HS_IRQHandler + .globl __irq_OTG_HS_IRQHandler + .set __irq_OTG_HS_IRQHandler, __default_handler + + .weak __irq_DCMI_IRQHandler + .globl __irq_DCMI_IRQHandler + .set __irq_DCMI_IRQHandler, __default_handler + + .weak __irq_CRYP_IRQHandler + .globl __irq_CRYP_IRQHandler + .set __irq_CRYP_IRQHandler, __default_handler + + .weak __irq_HASH_RNG_IRQHandler + .globl __irq_HASH_RNG_IRQHandler + .set __irq_HASH_RNG_IRQHandler, __default_handler + + .weak __irq_FPU_IRQHandler + .globl __irq_FPU_IRQHandler + .set __irq_FPU_IRQHandler, __default_handler diff --git a/STM32F4/variants/black_f407vet6/stm32_vector_table.S b/STM32F4/variants/black_f407vet6/stm32_vector_table.S new file mode 100644 index 0000000..9f08d66 --- /dev/null +++ b/STM32F4/variants/black_f407vet6/stm32_vector_table.S @@ -0,0 +1,113 @@ +/* STM32 vector table */ + + .section ".stm32.interrupt_vector" + + .globl __stm32_vector_table + .type __stm32_vector_table, %object + +__stm32_vector_table: +/* CM3 core interrupts */ + .long __msp_init + .long __exc_reset + .long __exc_nmi + .long __exc_hardfault + .long __exc_memmanage + .long __exc_busfault + .long __exc_usagefault + .long __stm32reservedexception7 + .long __stm32reservedexception8 + .long __stm32reservedexception9 + .long __stm32reservedexception10 + .long __exc_svc + .long __exc_debug_monitor + .long __stm32reservedexception13 + .long __exc_pendsv + .long __exc_systick +/* Peripheral interrupts */ + .long __irq_wwdg + .long __irq_pvd + .long __irq_tamper + .long __irq_rtc + .long __irq_flash + .long __irq_rcc + .long __irq_exti0 + .long __irq_exti1 + .long __irq_exti2 + .long __irq_exti3 + .long __irq_exti4 + .long __irq_dma1_channel1 + .long __irq_dma1_channel2 + .long __irq_dma1_channel3 + .long __irq_dma1_channel4 + .long __irq_dma1_channel5 + .long __irq_dma1_channel6 + .long __irq_dma1_channel7 + .long __irq_adc + .long __irq_usb_hp_can_tx + .long __irq_usb_lp_can_rx0 + .long __irq_can_rx1 + .long __irq_can_sce + .long __irq_exti9_5 + .long __irq_tim1_brk + .long __irq_tim1_up + .long __irq_tim1_trg_com + .long __irq_tim1_cc + .long __irq_tim2 + .long __irq_tim3 + .long __irq_tim4 + .long __irq_i2c1_ev + .long __irq_i2c1_er + .long __irq_i2c2_ev + .long __irq_i2c2_er + .long __irq_spi1 + .long __irq_spi2 + .long __irq_usart1 + .long __irq_usart2 + .long __irq_usart3 + .long __irq_exti15_10 + .long __irq_rtcalarm + .long __irq_usbwakeup +#if defined (STM32_HIGH_DENSITY) + .long __irq_tim8_brk + .long __irq_tim8_up + .long __irq_tim8_trg_com + .long __irq_tim8_cc + .long __irq_adc3 + .long __irq_fsmc + .long __irq_sdio + .long __irq_tim5 + .long __irq_spi3 + .long __irq_uart4 + .long __irq_uart5 + .long __irq_tim6 + .long __irq_tim7 + .long __irq_dma2_channel1 + .long __irq_dma2_channel2 + .long __irq_dma2_channel3 + .long __irq_dma2_channel4_5 +#endif /* STM32_HIGH_DENSITY */ + + .long __irq_DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */ + .long __irq_ETH_IRQHandler /* Ethernet */ + .long __irq_ETH_WKUP_IRQHandler /* Ethernet Wakeup through EXTI line */ + .long __irq_CAN2_TX_IRQHandler /* CAN2 TX */ + .long __irq_CAN2_RX0_IRQHandler /* CAN2 RX0 */ + .long __irq_CAN2_RX1_IRQHandler /* CAN2 RX1 */ + .long __irq_CAN2_SCE_IRQHandler /* CAN2 SCE */ + .long __irq_OTG_FS_IRQHandler /* USB OTG FS */ + .long __irq_DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */ + .long __irq_DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */ + .long __irq_DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */ + .long __irq_USART6_IRQHandler /* USART6 */ + .long __irq_I2C3_EV_IRQHandler /* I2C3 event */ + .long __irq_I2C3_ER_IRQHandler /* I2C3 error */ + .long __irq_OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */ + .long __irq_OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */ + .long __irq_OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */ + .long __irq_OTG_HS_IRQHandler /* USB OTG HS */ + .long __irq_DCMI_IRQHandler /* DCMI */ + .long __irq_CRYP_IRQHandler /* CRYP crypto */ + .long __irq_HASH_RNG_IRQHandler /* Hash and Rng */ + .long __irq_FPU_IRQHandler /* FPU */ + + .size __stm32_vector_table, . - __stm32_vector_table diff --git a/STM32F4/variants/black_f407vet6/variant.h b/STM32F4/variants/black_f407vet6/variant.h new file mode 100644 index 0000000..cd0a96d --- /dev/null +++ b/STM32F4/variants/black_f407vet6/variant.h @@ -0,0 +1,21 @@ +#ifndef _VARIANT_ARDUINO_STM32_ +#define _VARIANT_ARDUINO_STM32_ + + +#define digitalPinToPort(P) ( PIN_MAP[P].gpio_device ) +#define digitalPinToBitMask(P) ( BIT(PIN_MAP[P].gpio_bit) ) +#define portOutputRegister(port) ( &(port->regs->ODR) ) +#define portInputRegister(port) ( &(port->regs->IDR) ) + +#define portSetRegister(pin) ( &(PIN_MAP[pin].gpio_device->regs->BSRR) ) +#define portClearRegister(pin) ( &(PIN_MAP[pin].gpio_device->regs->BRR) ) + +#define portConfigRegister(pin) ( &(PIN_MAP[pin].gpio_device->regs->CRL) ) + +static const uint8_t SS = BOARD_SPI1_NSS_PIN; +static const uint8_t SS1 = BOARD_SPI2_NSS_PIN; +static const uint8_t MOSI = BOARD_SPI1_MOSI_PIN; +static const uint8_t MISO = BOARD_SPI1_MISO_PIN; +static const uint8_t SCK = BOARD_SPI1_SCK_PIN; + +#endif /* _VARIANT_ARDUINO_STM32_ */ \ No newline at end of file diff --git a/STM32F4/variants/black_f407vet6/wirish/start.S b/STM32F4/variants/black_f407vet6/wirish/start.S new file mode 100644 index 0000000..8b181aa --- /dev/null +++ b/STM32F4/variants/black_f407vet6/wirish/start.S @@ -0,0 +1,57 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/* + * This file is a modified version of a file obtained from + * CodeSourcery Inc. (now part of Mentor Graphics Corp.), in which the + * following text appeared: + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + */ + + .text + .code 16 + .thumb_func + + .globl __start__ + .type __start__, %function +__start__: + .fnstart + ldr r1,=__msp_init + mov sp,r1 + ldr r1,=start_c + bx r1 + .pool + .cantunwind + .fnend diff --git a/STM32F4/variants/black_f407vet6/wirish/start_c.c b/STM32F4/variants/black_f407vet6/wirish/start_c.c new file mode 100644 index 0000000..655fefb --- /dev/null +++ b/STM32F4/variants/black_f407vet6/wirish/start_c.c @@ -0,0 +1,95 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/* + * This file is a modified version of a file obtained from + * CodeSourcery Inc. (now part of Mentor Graphics Corp.), in which the + * following text appeared: + * + * Copyright (c) 2006, 2007 CodeSourcery Inc + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + */ + +#include + +extern void __libc_init_array(void); + +extern int main(int, char**, char**); + +extern void exit(int) __attribute__((noreturn, weak)); + +/* The linker must ensure that these are at least 4-byte aligned. */ +extern char __data_start__, __data_end__; +extern char __bss_start__, __bss_end__; + +struct rom_img_cfg { + int *img_start; +}; + +extern char _lm_rom_img_cfgp; + +void __attribute__((noreturn)) start_c(void) { + struct rom_img_cfg *img_cfg = (struct rom_img_cfg*)&_lm_rom_img_cfgp; + int *src = img_cfg->img_start; + int *dst = (int*)&__data_start__; + int exit_code; + + /* Initialize .data, if necessary. */ + if (src != dst) { + int *end = (int*)&__data_end__; + while (dst < end) { + *dst++ = *src++; + } + } + + /* Zero .bss. */ + dst = (int*)&__bss_start__; + while (dst < (int*)&__bss_end__) { + *dst++ = 0; + } + + /* Run initializers. */ + __libc_init_array(); + + /* Jump to main. */ + exit_code = main(0, 0, 0); + if (exit) { + exit(exit_code); + } + + /* If exit is NULL, make sure we don't return. */ + for (;;) + continue; +} From 5c9dc5ebfcfbaed297c66fae38b3b41f6fe9fc9d Mon Sep 17 00:00:00 2001 From: stevstrong Date: Sat, 15 Apr 2017 12:35:06 +0200 Subject: [PATCH 019/351] renamed target from "black" to generic f407v + removed unused files --- STM32F4/boards.txt | 44 +- STM32F4/cores/maple/boards.cpp | 2 +- STM32F4/cores/maple/boards.h | 4 +- STM32F4/cores/maple/io.h | 4 +- STM32F4/cores/maple/libmaple/HardwareSPI.cpp | 424 ----------- STM32F4/cores/maple/libmaple/HardwareSPI.h | 279 ------- STM32F4/cores/maple/libmaple/dmaF1.c | 383 ---------- STM32F4/cores/maple/libmaple/dmaF1.h | 453 ----------- STM32F4/cores/maple/libmaple/dmaF2.c | 241 ------ STM32F4/cores/maple/libmaple/dmaF2.h | 270 ------- STM32F4/cores/maple/libmaple/gpio.c | 36 - STM32F4/cores/maple/libmaple/gpioF1.c | 200 ----- STM32F4/cores/maple/libmaple/gpioF1.h | 530 ------------- STM32F4/cores/maple/libmaple/gpioF2.c | 224 ------ STM32F4/cores/maple/libmaple/gpioF2.h | 550 -------------- STM32F4/cores/maple/libmaple/rcc.c | 37 - STM32F4/cores/maple/libmaple/rccF1.c | 233 ------ STM32F4/cores/maple/libmaple/rccF1.h | 572 -------------- STM32F4/cores/maple/libmaple/rccF2.c | 707 ------------------ STM32F4/cores/maple/libmaple/rccF2.h | 642 ---------------- STM32F4/cores/maple/libmaple/usbF4/usb.c | 4 +- STM32F4/cores/maple/wirish_types.h | 2 +- .../black_f4.h.old} | 2 +- .../generic_f407v.cpp} | 8 +- .../variants/generic_f407v/generic_f407v.h | 130 ++++ .../ld/common.inc | 0 .../ld/extra_libs.inc | 0 .../ld/flash.ld | 0 .../ld/jtag.ld | 0 .../ld/names.inc | 0 .../ld/ram.ld | 0 .../ld/vector_symbols.inc | 0 .../pins_arduino.h | 0 .../stm32_isrs.S | 0 .../stm32_vector_table.S | 0 .../variant.h | 0 .../wirish/start.S | 0 .../wirish/start_c.c | 0 38 files changed, 165 insertions(+), 5816 deletions(-) delete mode 100644 STM32F4/cores/maple/libmaple/HardwareSPI.cpp delete mode 100644 STM32F4/cores/maple/libmaple/HardwareSPI.h delete mode 100644 STM32F4/cores/maple/libmaple/dmaF1.c delete mode 100644 STM32F4/cores/maple/libmaple/dmaF1.h delete mode 100644 STM32F4/cores/maple/libmaple/dmaF2.c delete mode 100644 STM32F4/cores/maple/libmaple/dmaF2.h delete mode 100644 STM32F4/cores/maple/libmaple/gpio.c delete mode 100644 STM32F4/cores/maple/libmaple/gpioF1.c delete mode 100644 STM32F4/cores/maple/libmaple/gpioF1.h delete mode 100644 STM32F4/cores/maple/libmaple/gpioF2.c delete mode 100644 STM32F4/cores/maple/libmaple/gpioF2.h delete mode 100644 STM32F4/cores/maple/libmaple/rcc.c delete mode 100644 STM32F4/cores/maple/libmaple/rccF1.c delete mode 100644 STM32F4/cores/maple/libmaple/rccF1.h delete mode 100644 STM32F4/cores/maple/libmaple/rccF2.c delete mode 100644 STM32F4/cores/maple/libmaple/rccF2.h rename STM32F4/variants/{black_f407vet6/black_f4.h => generic_f407v/black_f4.h.old} (99%) rename STM32F4/variants/{black_f407vet6/black_f4.cpp => generic_f407v/generic_f407v.cpp} (99%) create mode 100644 STM32F4/variants/generic_f407v/generic_f407v.h rename STM32F4/variants/{black_f407vet6 => generic_f407v}/ld/common.inc (100%) rename STM32F4/variants/{black_f407vet6 => generic_f407v}/ld/extra_libs.inc (100%) rename STM32F4/variants/{black_f407vet6 => generic_f407v}/ld/flash.ld (100%) rename STM32F4/variants/{black_f407vet6 => generic_f407v}/ld/jtag.ld (100%) rename STM32F4/variants/{black_f407vet6 => generic_f407v}/ld/names.inc (100%) rename STM32F4/variants/{black_f407vet6 => generic_f407v}/ld/ram.ld (100%) rename STM32F4/variants/{black_f407vet6 => generic_f407v}/ld/vector_symbols.inc (100%) rename STM32F4/variants/{black_f407vet6 => generic_f407v}/pins_arduino.h (100%) rename STM32F4/variants/{black_f407vet6 => generic_f407v}/stm32_isrs.S (100%) rename STM32F4/variants/{black_f407vet6 => generic_f407v}/stm32_vector_table.S (100%) rename STM32F4/variants/{black_f407vet6 => generic_f407v}/variant.h (100%) rename STM32F4/variants/{black_f407vet6 => generic_f407v}/wirish/start.S (100%) rename STM32F4/variants/{black_f407vet6 => generic_f407v}/wirish/start_c.c (100%) diff --git a/STM32F4/boards.txt b/STM32F4/boards.txt index 3ff182c..df9f2b4 100644 --- a/STM32F4/boards.txt +++ b/STM32F4/boards.txt @@ -30,32 +30,32 @@ discovery_f407.build.error_led_pin=14 discovery_f407.build.board=STM32DiscoveryF407 ############################################################## -black_f407vet6.name=STM32 Black F407VET6 +generic_f407v.name=Generic STM32F407V series -black_f407vet6.upload.tool=stlink_upload -black_f407vet6.upload.protocol=stlink +generic_f407v.upload.tool=stlink_upload +generic_f407v.upload.protocol=stlink -black_f407vet6.upload.file_type=bin -black_f407vet6.upload.ram.maximum_size=65535 -black_f407vet6.upload.flash.maximum_size=514288 -black_f407vet6.upload.maximum_size=514288 +generic_f407v.upload.file_type=bin +generic_f407v.upload.ram.maximum_size=131072 +generic_f407v.upload.flash.maximum_size=514288 +generic_f407v.upload.maximum_size=514288 -#black_f407vet6.upload.usbID=0483:3748 -#black_f407vet6.upload.altID=1 -#black_f407vet6.upload.auto_reset=true +#generic_f407v.upload.usbID=0483:3748 +#generic_f407v.upload.altID=1 +#generic_f407v.upload.auto_reset=true -black_f407vet6.build.mcu=cortex-m4 -black_f407vet6.build.f_cpu=168000000L -black_f407vet6.build.core=maple -black_f407vet6.build.extra_flags=-mthumb -DSTM32_HIGH_DENSITY -DSTM32F4 -DBOARD_black_f4 -black_f407vet6.build.ldscript=ld/jtag.ld -black_f407vet6.build.variant=black_f407vet6 -black_f407vet6.build.variant_system_lib=lib_f407.a -black_f407vet6.build.vect=VECT_TAB_BASE -black_f407vet6.build.density=STM32_HIGH_DENSITY -black_f407vet6.build.error_led_port=GPIOA -black_f407vet6.build.error_led_pin=7 -black_f407vet6.build.board=STM32BlackF407VET6 +generic_f407v.build.mcu=cortex-m4 +generic_f407v.build.f_cpu=168000000L +generic_f407v.build.core=maple +generic_f407v.build.extra_flags=-mthumb -DSTM32_HIGH_DENSITY -DSTM32F4 -DBOARD_generic_f407v +generic_f407v.build.ldscript=ld/jtag.ld +generic_f407v.build.variant=generic_f407v +generic_f407v.build.variant_system_lib=lib_f407.a +generic_f407v.build.vect=VECT_TAB_BASE +generic_f407v.build.density=STM32_HIGH_DENSITY +generic_f407v.build.error_led_port=GPIOA +generic_f407v.build.error_led_pin=7 +generic_f407v.build.board=STM32GenericF407VET6 ############################################################## stm32f4stamp.name=STM32F4Stamp F405 diff --git a/STM32F4/cores/maple/boards.cpp b/STM32F4/cores/maple/boards.cpp index f9bfd5a..c8ba978 100644 --- a/STM32F4/cores/maple/boards.cpp +++ b/STM32F4/cores/maple/boards.cpp @@ -67,7 +67,7 @@ void init(void) { setupADC(); setupTimers(); - //setupUSB(); + setupUSB(); } /* You could farm this out to the files in boards/ if e.g. it takes diff --git a/STM32F4/cores/maple/boards.h b/STM32F4/cores/maple/boards.h index 5e0aae3..e123341 100644 --- a/STM32F4/cores/maple/boards.h +++ b/STM32F4/cores/maple/boards.h @@ -140,8 +140,8 @@ bool boardUsesPin(uint8 pin); #include "aeroquad32mini.h" #elif defined(BOARD_discovery_f4) #include "discovery_f4.h" -#elif defined(BOARD_black_f4) -#include "black_f4.h" +#elif defined(BOARD_generic_f407v) +#include "generic_f407v.h" #elif defined(BOARD_freeflight) #include "freeflight.h" #else diff --git a/STM32F4/cores/maple/io.h b/STM32F4/cores/maple/io.h index d4d1c25..1208be6 100644 --- a/STM32F4/cores/maple/io.h +++ b/STM32F4/cores/maple/io.h @@ -180,7 +180,7 @@ static inline void toggleLED() { * accomplished portably over all LeafLabs boards by calling * pinMode(BOARD_BUTTON_PIN, INPUT). * - * @param button - one of available on-board buttons (up to 3 for black F4) + * @param button - one of available on-board buttons (up to 3 for generic F4) * * @see pinMode() */ @@ -198,7 +198,7 @@ uint8 isButtonPressed(uint8_t button); * button is pressed. If timeout_millis is left out (or 0), wait * forever. * - * @param button - one of available on-board buttons (up to 3 for black F4) + * @param button - one of available on-board buttons (up to 3 for generic F4) * * @return true, if the button was pressed; false, if the timeout was * reached. diff --git a/STM32F4/cores/maple/libmaple/HardwareSPI.cpp b/STM32F4/cores/maple/libmaple/HardwareSPI.cpp deleted file mode 100644 index a5b4711..0000000 --- a/STM32F4/cores/maple/libmaple/HardwareSPI.cpp +++ /dev/null @@ -1,424 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @author Marti Bolivar - * @brief Wirish SPI implementation. - */ - -#include "HardwareSPI.h" - -#include "timer.h" -#include "util.h" -#include "rcc.h" - -#include "wirish.h" -#include "boards.h" - -struct spi_pins { - uint8 nss; - uint8 sck; - uint8 miso; - uint8 mosi; -}; - -static const spi_pins* dev_to_spi_pins(spi_dev *dev); - -static void enable_device(spi_dev *dev, - bool as_master, - SPIFrequency frequency, - spi_cfg_flag endianness, - spi_mode mode); - -static const spi_pins board_spi_pins[] __FLASH__ = { - {BOARD_SPI1_NSS_PIN, - BOARD_SPI1_SCK_PIN, - BOARD_SPI1_MISO_PIN, - BOARD_SPI1_MOSI_PIN}, -#ifdef BOARD_SPI2_NSS_PIN - {BOARD_SPI2_NSS_PIN, - BOARD_SPI2_SCK_PIN, - BOARD_SPI2_MISO_PIN, - BOARD_SPI2_MOSI_PIN}, -#endif -#ifdef STM32_HIGH_DENSITY - {BOARD_SPI3B_NSS_PIN, - BOARD_SPI3B_SCK_PIN, - BOARD_SPI3B_MISO_PIN, - BOARD_SPI3B_MOSI_PIN}, -#endif -#ifdef STM32F4 - {BOARD_SPI3B_NSS_PIN, - BOARD_SPI3B_SCK_PIN, - BOARD_SPI3B_MISO_PIN, - BOARD_SPI3B_MOSI_PIN}, -#endif -}; - - -/* - * Constructor - */ - -HardwareSPI::HardwareSPI(uint32 spi_num) { - switch (spi_num) { - case 1: - this->spi_d = SPI1; - break; - case 2: - this->spi_d = SPI2; - break; -#ifdef STM32_HIGH_DENSITY - case 3: - this->spi_d = SPI3; - break; -#endif -#ifdef STM32F4 -// case 4: -// this->spi_d = SPI4; -// break; -#endif - default: - ASSERT(0); - } -} - -/* - * Set up/tear down - */ - -void HardwareSPI::begin(SPIFrequency frequency, uint32 bitOrder, uint32 mode) { - if (mode >= 4) { - ASSERT(0); - return; - } - spi_cfg_flag end = bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB; - spi_mode m = (spi_mode)mode; - enable_device(this->spi_d, true, frequency, end, m); -} - -void HardwareSPI::begin(void) { - this->begin(SPI_1_125MHZ, MSBFIRST, 0); -} - -void HardwareSPI::beginSlave(uint32 bitOrder, uint32 mode) { - if (mode >= 4) { - ASSERT(0); - return; - } - spi_cfg_flag end = bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB; - spi_mode m = (spi_mode)mode; - enable_device(this->spi_d, false, (SPIFrequency)0, end, m); -} - -void HardwareSPI::beginSlave(void) { - this->beginSlave(MSBFIRST, 0); -} - - -/* -void HardwareSPI::beginTransaction(uint8_t pin, SPISettings settings) -{ -// this->begin(settings.clock, settings.bitOrder, settings.dataMode); - this->begin(SPI_1_125MHZ, settings.bitOrder, settings.dataMode); -} -*/ - -void HardwareSPI::end(void) { - if (!spi_is_enabled(this->spi_d)) { - return; - } - - // Follows RM0008's sequence for disabling a SPI in master/slave - // full duplex mode. - while (spi_is_rx_nonempty(this->spi_d)) { - // FIXME [0.1.0] remove this once you have an interrupt based driver - volatile uint16 rx __attribute__((unused)) = spi_rx_reg(this->spi_d); - } - while (!spi_is_tx_empty(this->spi_d)) - ; - while (spi_is_busy(this->spi_d)) - ; - spi_peripheral_disable(this->spi_d); -} - -/* - * I/O - */ - -uint8 HardwareSPI::read(void) { - uint8 buf[1]; - this->read(buf, 1); - return buf[0]; -} - -void HardwareSPI::read(uint8 *buf, uint32 len) { - uint32 rxed = 0; - while (rxed < len) { - while (!spi_is_rx_nonempty(this->spi_d)) - ; - buf[rxed++] = (uint8)spi_rx_reg(this->spi_d); - } -} - -#if 0 -void HardwareSPI::readMaster(uint8 *buf, uint32 len) { - uint32 rxed = 0; - while (rxed < len) { - spi_tx_reg(this->spi_d, 0xff); - while (!spi_is_rx_nonempty(this->spi_d)) - ; - buf[rxed++] = (uint8)spi_rx_reg(this->spi_d); - buf[rxed++] = this->spi_d->regs->DR; - } -} -#endif -void HardwareSPI::readMaster(uint8 *buf, uint32 len) { - spi_reg_map *r = this->spi_d->regs; - uint32 rxed = 0; - while (rxed < len) { - r->DR = 0xff; - while (!(r->SR & SPI_SR_RXNE)) - ; - buf[rxed++] = r->DR; - } -} - - -void HardwareSPI::waitReady() { - while (!spi_is_rx_nonempty(this->spi_d)) - ; -} - -void HardwareSPI::write(uint8 byte) { - this->write(&byte, 1); -} - -void HardwareSPI::write(const uint8 *data, uint32 length) { - uint32 txed = 0; - while (txed < length) { - txed += spi_tx(this->spi_d, data + txed, length - txed); - } -} - -uint8 HardwareSPI::transfer(uint8 byte) { - this->write(byte); - return this->read(); -} - -/* - * Pin accessors - */ - -uint8 HardwareSPI::misoPin(void) { - return dev_to_spi_pins(this->spi_d)->miso; -} - -uint8 HardwareSPI::mosiPin(void) { - return dev_to_spi_pins(this->spi_d)->mosi; -} - -uint8 HardwareSPI::sckPin(void) { - return dev_to_spi_pins(this->spi_d)->sck; -} - -uint8 HardwareSPI::nssPin(void) { - return dev_to_spi_pins(this->spi_d)->nss; -} - -/* - * Deprecated functions - */ - -uint8 HardwareSPI::send(uint8 data) { - uint8 buf[] = {data}; - return this->send(buf, 1); -} - -#if 1 -uint8 HardwareSPI::send(const uint8 *buf, uint32 len) { - uint32 txed = 0; - uint8 ret = 0; - while (txed < len) { - this->write(buf[txed++]); - ret = this->read(); - } - return ret; -} -#else -// this does not work for an unknown reason -uint8 HardwareSPI::send(const uint8 *buf, uint32 len) { - volatile uint32 *dr = &(this->spi_d->regs->DR); - volatile uint32 *sr = &(this->spi_d->regs->SR); - uint32 txed = 0; - uint32 rx=0; - while (txed < len) { - //while (!(*sr & SPI_SR_TXE)) - // ; - //*dr = buf[txed++]; - this->write(buf[txed++]); - - while (!(*sr & SPI_SR_RXNE)) - ; - rx = *dr; - //rx = this->read(); - } - - return rx; -} -#endif - -uint8 HardwareSPI::recv(void) { - return this->read(); -} - -/* - * Auxiliary functions - */ - -static void configure_gpios(spi_dev *dev, bool as_master); -static spi_baud_rate determine_baud_rate(spi_dev *dev, SPIFrequency freq); - -static const spi_pins* dev_to_spi_pins(spi_dev *dev) { - switch (dev->clk_id) { - case RCC_SPI1: return board_spi_pins; - case RCC_SPI2: return board_spi_pins + 1; -#ifdef STM32_HIGH_DENSITY - case RCC_SPI3: return board_spi_pins + 2; -#endif -#ifdef STM32F4 - case RCC_SPI4: return board_spi_pins + 3; -#endif - default: return NULL; - } -} - -/* Enables the device in master or slave full duplex mode. If you - * change this code, you must ensure that appropriate changes are made - * to HardwareSPI::end(). */ -static void enable_device(spi_dev *dev, - bool as_master, - SPIFrequency freq, - spi_cfg_flag endianness, - spi_mode mode) { - spi_baud_rate baud = determine_baud_rate(dev, freq); - uint32 cfg_flags = (endianness | SPI_DFF_8_BIT | SPI_SW_SLAVE | - (as_master ? SPI_SOFT_SS : 0)); - - spi_init(dev); - configure_gpios(dev, as_master); - if (as_master) { - spi_master_enable(dev, baud, mode, cfg_flags); - } else { - spi_slave_enable(dev, mode, cfg_flags); - } -} - -static void disable_pwm(const stm32_pin_info *i) { - if (i->timer_device) { - timer_set_mode(i->timer_device, i->timer_channel, TIMER_DISABLED); - } -} - -static void configure_gpios(spi_dev *dev, bool as_master) { - const spi_pins *pins = dev_to_spi_pins(dev); - - if (!pins) { - return; - } - - const stm32_pin_info *nssi = (pins->nss >= 0) ? &PIN_MAP[pins->nss] : NULL; - const stm32_pin_info *scki = &PIN_MAP[pins->sck]; - const stm32_pin_info *misoi = &PIN_MAP[pins->miso]; - const stm32_pin_info *mosii = &PIN_MAP[pins->mosi]; - - if(nssi) { - disable_pwm(nssi); - } - disable_pwm(scki); - disable_pwm(misoi); - disable_pwm(mosii); - -#ifdef STM32F4 - if(dev->clk_id <= RCC_SPI2) { - if(nssi) { - if(!as_master) { - gpio_set_af_mode(nssi->gpio_device, scki->gpio_bit, 5); - } - } - gpio_set_af_mode(scki->gpio_device, scki->gpio_bit, 5); - gpio_set_af_mode(misoi->gpio_device, misoi->gpio_bit, 5); - gpio_set_af_mode(mosii->gpio_device, mosii->gpio_bit, 5); - } else { - if(nssi) { - if(!as_master) { - gpio_set_af_mode(nssi->gpio_device, scki->gpio_bit, 6); - } - } - gpio_set_af_mode(scki->gpio_device, scki->gpio_bit, 6); - gpio_set_af_mode(misoi->gpio_device, misoi->gpio_bit, 6); - gpio_set_af_mode(mosii->gpio_device, mosii->gpio_bit, 6); - } -#endif - - if(nssi) { - spi_config_gpios(dev, as_master, nssi->gpio_device, nssi->gpio_bit, - scki->gpio_device, scki->gpio_bit, - misoi->gpio_device, misoi->gpio_bit, - mosii->gpio_device, mosii->gpio_bit); - } else { - spi_config_gpios(dev, as_master, NULL, -1, - scki->gpio_device, scki->gpio_bit, - misoi->gpio_device, misoi->gpio_bit, - mosii->gpio_device, mosii->gpio_bit); - } -} - -static const spi_baud_rate baud_rates[MAX_SPI_FREQS] __FLASH__ = { - SPI_BAUD_PCLK_DIV_2, - SPI_BAUD_PCLK_DIV_4, - SPI_BAUD_PCLK_DIV_8, - SPI_BAUD_PCLK_DIV_16, - SPI_BAUD_PCLK_DIV_32, - SPI_BAUD_PCLK_DIV_64, - SPI_BAUD_PCLK_DIV_128, - SPI_BAUD_PCLK_DIV_256, -}; - -/* - * Note: This assumes you're on a LeafLabs-style board - * (CYCLES_PER_MICROSECOND == 72, APB2 at 72MHz, APB1 at 36MHz). - */ -static spi_baud_rate determine_baud_rate(spi_dev *dev, SPIFrequency freq) { - if (rcc_dev_clk(dev->clk_id) == RCC_APB2 && freq == SPI_140_625KHZ) { - /* APB2 peripherals are too fast for 140.625 KHz */ - ASSERT(0); - return (spi_baud_rate)~0; - } - return (rcc_dev_clk(dev->clk_id) == RCC_APB2 ? - baud_rates[freq + 1] : - baud_rates[freq]); -} diff --git a/STM32F4/cores/maple/libmaple/HardwareSPI.h b/STM32F4/cores/maple/libmaple/HardwareSPI.h deleted file mode 100644 index 327f29d..0000000 --- a/STM32F4/cores/maple/libmaple/HardwareSPI.h +++ /dev/null @@ -1,279 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file HardwareSPI.h - * @brief High-level SPI interface - * - * This is a "bare essentials" polling driver for now. - */ - -/* TODO [0.1.0] Remove deprecated methods. */ - -#include "libmaple_types.h" -#include "spi.h" - -#include "boards.h" -#include "wirish.h" - -#ifndef _HARDWARESPI_H_ -#define _HARDWARESPI_H_ - -/** - * @brief Defines the possible SPI communication speeds. - */ -typedef enum SPIFrequency { - SPI_18MHZ = 0, /**< 18 MHz */ - SPI_9MHZ = 1, /**< 9 MHz */ - SPI_4_5MHZ = 2, /**< 4.5 MHz */ - SPI_2_25MHZ = 3, /**< 2.25 MHz */ - SPI_1_125MHZ = 4, /**< 1.125 MHz */ - SPI_562_500KHZ = 5, /**< 562.500 KHz */ - SPI_281_250KHZ = 6, /**< 281.250 KHz */ - SPI_140_625KHZ = 7, /**< 140.625 KHz */ -} SPIFrequency; - -#define MAX_SPI_FREQS 8 - -#if CYCLES_PER_MICROSECOND != 72 -/* TODO [0.2.0?] something smarter than this */ -//#warning "Unexpected clock speed; SPI frequency calculation will be incorrect" -#endif - - -//#define BOARD_SPI_DEFAULT_SS PC13 -#define BOARD_SPI_DEFAULT_SS PB0 -#define SPI_MODE0 SPI_MODE_0 -#define SPI_MODE1 SPI_MODE_1 -#define SPI_MODE2 SPI_MODE_2 -#define SPI_MODE3 SPI_MODE_3 - -/* -class SPISettings { -public: - SPISettings(uint32 clock, BitOrder bitOrder, uint8 dataMode) { - if (__builtin_constant_p(clock)) { - init_AlwaysInline(clock, bitOrder, dataMode); - } else { - init_MightInline(clock, bitOrder, dataMode); - } - } - SPISettings() { init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0); } -private: - void init_MightInline(uint32 clock, BitOrder bitOrder, uint8 dataMode) { - init_AlwaysInline(clock, bitOrder, dataMode); - } - void init_AlwaysInline(uint32 clock, BitOrder bitOrder, uint8 dataMode) __attribute__((__always_inline__)) { - this->clock = clock; - this->bitOrder = bitOrder; - this->dataMode = dataMode; - } - uint32 clock; - BitOrder bitOrder; - uint8 dataMode; - friend class HardwareSPI; -}; -*/ - - -/** - * @brief Wirish SPI interface. - * - * This implementation uses software slave management, so the caller - * is responsible for controlling the slave select line. - */ -class HardwareSPI { -public: - /** - * @param spiPortNumber Number of the SPI port to manage. - */ - HardwareSPI(uint32 spiPortNumber); - - /* - * Set up/tear down - */ - - /** - * @brief Turn on a SPI port and set its GPIO pin modes for use as master. - * - * SPI port is enabled in full duplex mode, with software slave management. - * - * @param frequency Communication frequency - * @param bitOrder Either LSBFIRST (little-endian) or MSBFIRST (big-endian) - * @param mode SPI mode to use, one of SPI_MODE_0, SPI_MODE_1, - * SPI_MODE_2, and SPI_MODE_3. - */ - void begin(SPIFrequency frequency, uint32 bitOrder, uint32 mode); - - /** - * @brief Equivalent to begin(SPI_1_125MHZ, MSBFIRST, 0). - */ - void begin(void); - - /** - * @brief Turn on a SPI port and set its GPIO pin modes for use as a slave. - * - * SPI port is enabled in full duplex mode, with software slave management. - * - * @param bitOrder Either LSBFIRST (little-endian) or MSBFIRST(big-endian) - * @param mode SPI mode to use - */ - void beginSlave(uint32 bitOrder, uint32 mode); - - /** - * @brief Equivalent to beginSlave(MSBFIRST, 0). - */ - void beginSlave(void); - - /** - * @brief Disables the SPI port, but leaves its GPIO pin modes unchanged. - */ - void end(void); - - /* - * I/O - */ - - /** - * @brief Return the next unread byte. - * - * If there is no unread byte waiting, this function will block - * until one is received. - */ - uint8 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 - * function will block until the desired number of - * bytes have been read. - */ - void read(uint8 *buffer, uint32 length); - - /** - * @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 - * function will block until the desired number of - * bytes have been read. - */ - void readMaster(uint8 *buffer, uint32 length); - - - void waitReady(); - /** - * @brief Transmit a byte. - * @param data Byte to transmit. - */ - void write(uint8 data); - - /** - * @brief Transmit multiple bytes. - * @param buffer Bytes to transmit. - * @param length Number of bytes in buffer to transmit. - */ - void write(const uint8 *buffer, uint32 length); - - /** - * @brief Transmit a byte, then return the next unread byte. - * - * This function transmits before receiving. - * - * @param data Byte to transmit. - * @return Next unread byte. - */ - uint8 transfer(uint8 data); - - /* - * Pin accessors - */ - - /** - * @brief Return the number of the MISO (master in, slave out) pin - */ - uint8 misoPin(void); - - /** - * @brief Return the number of the MOSI (master out, slave in) pin - */ - uint8 mosiPin(void); - - /** - * @brief Return the number of the SCK (serial clock) pin - */ - uint8 sckPin(void); - - /** - * @brief Return the number of the NSS (slave select) pin - */ - uint8 nssPin(void); - - /* -- The following methods are deprecated --------------------------- */ - - /** - * @brief Deprecated. - * - * Use HardwareSPI::transfer() instead. - * - * @see HardwareSPI::transfer() - */ - uint8 send(uint8 data); - - /** - * @brief Deprecated. - * - * Use HardwareSPI::write() in combination with - * HardwareSPI::read() (or HardwareSPI::transfer()) instead. - * - * @see HardwareSPI::write() - * @see HardwareSPI::read() - * @see HardwareSPI::transfer() - */ - uint8 send(const uint8 *data, uint32 length); - - /** - * @brief Deprecated. - * - * Use HardwareSPI::read() instead. - * - * @see HardwareSPI::read() - */ - uint8 recv(void); - -// void beginTransaction(SPISettings settings) { beginTransaction(BOARD_SPI_DEFAULT_SS, settings); } -// void beginTransaction(uint8 pin, SPISettings settings); - void endTransaction(void) { } - -private: - spi_dev *spi_d; -}; - - -extern HardwareSPI SPI; - -#endif - diff --git a/STM32F4/cores/maple/libmaple/dmaF1.c b/STM32F4/cores/maple/libmaple/dmaF1.c deleted file mode 100644 index f8ddb2d..0000000 --- a/STM32F4/cores/maple/libmaple/dmaF1.c +++ /dev/null @@ -1,383 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Michael Hope. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -#ifdef STM32F1 - -/** - * @file dma.c - * @author Marti Bolivar ; - * Original implementation by Michael Hope - * @brief Direct Memory Access peripheral support - */ - -#include "dma.h" -#include "bitband.h" -#include "util.h" - -/* - * Devices - */ - -static dma_dev dma1 = { - .regs = DMA1_BASE, - .clk_id = RCC_DMA1, - .handlers = {{ .handler = NULL, .irq_line = NVIC_DMA_CH1 }, - { .handler = NULL, .irq_line = NVIC_DMA_CH2 }, - { .handler = NULL, .irq_line = NVIC_DMA_CH3 }, - { .handler = NULL, .irq_line = NVIC_DMA_CH4 }, - { .handler = NULL, .irq_line = NVIC_DMA_CH5 }, - { .handler = NULL, .irq_line = NVIC_DMA_CH6 }, - { .handler = NULL, .irq_line = NVIC_DMA_CH7 }} -}; -/** DMA1 device */ -dma_dev *DMA1 = &dma1; - -#ifdef STM32_HIGH_DENSITY -static dma_dev dma2 = { - .regs = DMA2_BASE, - .clk_id = RCC_DMA2, - .handlers = {{ .handler = NULL, .irq_line = NVIC_DMA2_CH1 }, - { .handler = NULL, .irq_line = NVIC_DMA2_CH2 }, - { .handler = NULL, .irq_line = NVIC_DMA2_CH3 }, - { .handler = NULL, .irq_line = NVIC_DMA2_CH_4_5 }, - { .handler = NULL, .irq_line = NVIC_DMA2_CH_4_5 }} /* !@#$ */ -}; -/** DMA2 device */ -dma_dev *DMA2 = &dma2; -#endif - -/* - * Convenience routines - */ - -/** - * @brief Initialize a DMA device. - * @param dev Device to initialize. - */ -void dma_init(dma_dev *dev) { - rcc_clk_enable(dev->clk_id); -} - -/** - * @brief Set up a DMA transfer. - * - * The channel will be disabled before being reconfigured. The - * transfer will have low priority by default. You may choose another - * priority before the transfer begins using dma_set_priority(), as - * well as performing any other configuration you desire. When the - * channel is configured to your liking, enable it using dma_enable(). - * - * @param dev DMA device. - * @param channel DMA channel. - * @param peripheral_address Base address of peripheral data register - * involved in the transfer. - * @param peripheral_size Peripheral data transfer size. - * @param memory_address Base memory address involved in the transfer. - * @param memory_size Memory data transfer size. - * @param mode Logical OR of dma_mode_flags - * @sideeffect Disables the given DMA channel. - * @see dma_xfer_size - * @see dma_mode_flags - * @see dma_set_num_transfers() - * @see dma_set_priority() - * @see dma_attach_interrupt() - * @see dma_enable() - */ -void dma_setup_transfer(dma_dev *dev, - dma_channel channel, - __io void *peripheral_address, - dma_xfer_size peripheral_size, - __io void *memory_address, - dma_xfer_size memory_size, - uint32 mode) { - dma_channel_reg_map *channel_regs = dma_channel_regs(dev, channel); - - dma_disable(dev, channel); /* can't write to CMAR/CPAR otherwise */ - channel_regs->CCR = (memory_size << 10) | (peripheral_size << 8) | mode; - channel_regs->CMAR = (uint32)memory_address; - channel_regs->CPAR = (uint32)peripheral_address; -} - -/** - * @brief Set the number of data to be transferred on a DMA channel. - * - * You may not call this function while the channel is enabled. - * - * @param dev DMA device - * @param channel Channel through which the transfer occurs. - * @param num_transfers - */ -void dma_set_num_transfers(dma_dev *dev, - dma_channel channel, - uint16 num_transfers) { - dma_channel_reg_map *channel_regs; - - ASSERT_FAULT(!dma_is_channel_enabled(dev, channel)); - - channel_regs = dma_channel_regs(dev, channel); - channel_regs->CNDTR = num_transfers; -} - -/** - * @brief Set the priority of a DMA transfer. - * - * You may not call this function while the channel is enabled. - * - * @param dev DMA device - * @param channel DMA channel - * @param priority priority to set. - */ -void dma_set_priority(dma_dev *dev, - dma_channel channel, - dma_priority priority) { - dma_channel_reg_map *channel_regs; - uint32 ccr; - - ASSERT_FAULT(!dma_is_channel_enabled(dev, channel)); - - channel_regs = dma_channel_regs(dev, channel); - ccr = channel_regs->CCR; - ccr &= ~DMA_CCR_PL; - ccr |= priority; - channel_regs->CCR = ccr; -} - -/** - * @brief Attach an interrupt to a DMA transfer. - * - * Interrupts are enabled using appropriate mode flags in - * dma_setup_transfer(). - * - * @param dev DMA device - * @param channel Channel to attach handler to - * @param handler Interrupt handler to call when channel interrupt fires. - * @see dma_setup_transfer() - * @see dma_get_irq_cause() - * @see dma_detach_interrupt() - */ -void dma_attach_interrupt(dma_dev *dev, - dma_channel channel, - void (*handler)(void)) { - dev->handlers[channel - 1].handler = handler; - nvic_irq_enable(dev->handlers[channel - 1].irq_line); -} - -/** - * @brief Detach a DMA transfer interrupt handler. - * - * After calling this function, the given channel's interrupts will be - * disabled. - * - * @param dev DMA device - * @param channel Channel whose handler to detach - * @sideeffect Clears interrupt enable bits in the channel's CCR register. - * @see dma_attach_interrupt() - */ -void dma_detach_interrupt(dma_dev *dev, dma_channel channel) { - /* Don't use nvic_irq_disable()! Think about DMA2 channels 4 and 5. */ - dma_channel_regs(dev, channel)->CCR &= ~0xF; - dev->handlers[channel - 1].handler = NULL; -} - -/** - * @brief Discover the reason why a DMA interrupt was called. - * - * You may only call this function within an attached interrupt - * handler for the given channel. - * - * This function resets the internal DMA register state which encodes - * the cause of the interrupt; consequently, it can only be called - * once per interrupt handler invocation. - * - * @param dev DMA device - * @param channel Channel whose interrupt is being handled. - * @return Reason why the interrupt fired. - * @sideeffect Clears channel status flags in dev->regs->ISR. - * @see dma_attach_interrupt() - * @see dma_irq_cause - */ -dma_irq_cause dma_get_irq_cause(dma_dev *dev, dma_channel channel) { - uint8 status_bits = dma_get_isr_bits(dev, channel); - - /* If the channel global interrupt flag is cleared, then - * something's very wrong. */ - ASSERT(status_bits & BIT(0)); - - dma_clear_isr_bits(dev, channel); - - /* ISR flags get set even if the corresponding interrupt enable - * bits in the channel's configuration register are cleared, so we - * can't use a switch here. - * - * Don't change the order of these if statements. */ - if (status_bits & BIT(3)) { - return DMA_TRANSFER_ERROR; - } else if (status_bits & BIT(1)) { - return DMA_TRANSFER_COMPLETE; - } else if (status_bits & BIT(2)) { - return DMA_TRANSFER_HALF_COMPLETE; - } else if (status_bits & BIT(0)) { - /* Shouldn't happen (unless someone messed up an IFCR write). */ - throb(); - } -#if DEBUG_LEVEL < DEBUG_ALL - else { - /* We shouldn't have been called, but the debug level is too - * low for the above ASSERT() to have had any effect. In - * order to fail fast, mimic the DMA controller's behavior - * when an error occurs. */ - dma_disable(dev, channel); - } -#endif - return DMA_TRANSFER_ERROR; -} - -/** - * @brief Enable a DMA channel. - * @param dev DMA device - * @param channel Channel to enable - */ -void dma_enable(dma_dev *dev, dma_channel channel) { - dma_channel_reg_map *chan_regs = dma_channel_regs(dev, channel); - bb_peri_set_bit(&chan_regs->CCR, DMA_CCR_EN_BIT, 1); -} - -/** - * @brief Disable a DMA channel. - * @param dev DMA device - * @param channel Channel to disable - */ -void dma_disable(dma_dev *dev, dma_channel channel) { - dma_channel_reg_map *chan_regs = dma_channel_regs(dev, channel); - bb_peri_set_bit(&chan_regs->CCR, DMA_CCR_EN_BIT, 0); -} - -/** - * @brief Set the base memory address where data will be read from or - * written to. - * - * You must not call this function while the channel is enabled. - * - * If the DMA memory size is 16 bits, the address is automatically - * aligned to a half-word. If the DMA memory size is 32 bits, the - * address is aligned to a word. - * - * @param dev DMA Device - * @param channel Channel whose base memory address to set. - * @param addr Memory base address to use. - */ -void dma_set_mem_addr(dma_dev *dev, dma_channel channel, __io void *addr) { - dma_channel_reg_map *chan_regs; - - ASSERT_FAULT(!dma_is_channel_enabled(dev, channel)); - - chan_regs = dma_channel_regs(dev, channel); - chan_regs->CMAR = (uint32)addr; -} - -/** - * @brief Set the base peripheral address where data will be read from - * or written to. - * - * You must not call this function while the channel is enabled. - * - * If the DMA peripheral size is 16 bits, the address is automatically - * aligned to a half-word. If the DMA peripheral size is 32 bits, the - * address is aligned to a word. - * - * @param dev DMA Device - * @param channel Channel whose peripheral data register base address to set. - * @param addr Peripheral memory base address to use. - */ -void dma_set_per_addr(dma_dev *dev, dma_channel channel, __io void *addr) { - dma_channel_reg_map *chan_regs; - - ASSERT_FAULT(!dma_is_channel_enabled(dev, channel)); - - chan_regs = dma_channel_regs(dev, channel); - chan_regs->CPAR = (uint32)addr; -} - -/* - * IRQ handlers - */ - -static inline void dispatch_handler(dma_dev *dev, dma_channel channel) { - void (*handler)(void) = dev->handlers[channel - 1].handler; - if (handler) { - handler(); - dma_clear_isr_bits(dev, channel); /* in case handler doesn't */ - } -} - -void __irq_dma1_channel1(void) { - dispatch_handler(DMA1, DMA_CH1); -} - -void __irq_dma1_channel2(void) { - dispatch_handler(DMA1, DMA_CH2); -} - -void __irq_dma1_channel3(void) { - dispatch_handler(DMA1, DMA_CH3); -} - -void __irq_dma1_channel4(void) { - dispatch_handler(DMA1, DMA_CH4); -} - -void __irq_dma1_channel5(void) { - dispatch_handler(DMA1, DMA_CH5); -} - -void __irq_dma1_channel6(void) { - dispatch_handler(DMA1, DMA_CH6); -} - -void __irq_dma1_channel7(void) { - dispatch_handler(DMA1, DMA_CH7); -} - -#ifdef STM32_HIGH_DENSITY -void __irq_dma2_channel1(void) { - dispatch_handler(DMA2, DMA_CH1); -} - -void __irq_dma2_channel2(void) { - dispatch_handler(DMA2, DMA_CH2); -} - -void __irq_dma2_channel3(void) { - dispatch_handler(DMA2, DMA_CH3); -} - -void __irq_dma2_channel4_5(void) { - dispatch_handler(DMA2, DMA_CH4); - dispatch_handler(DMA2, DMA_CH5); -} -#endif - -#endif \ No newline at end of file diff --git a/STM32F4/cores/maple/libmaple/dmaF1.h b/STM32F4/cores/maple/libmaple/dmaF1.h deleted file mode 100644 index 6e8087f..0000000 --- a/STM32F4/cores/maple/libmaple/dmaF1.h +++ /dev/null @@ -1,453 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Michael Hope. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file dma.h - * - * @author Marti Bolivar ; - * Original implementation by Michael Hope - * - * @brief Direct Memory Access peripheral support - */ - -/* - * See /notes/dma.txt for more information. - */ - -#ifndef _DMA_H_ -#define _DMA_H_ - -#include "libmaple_types.h" -#include "rcc.h" -#include "nvic.h" - -#ifdef __cplusplus -extern "C"{ -#endif - -/* - * Register maps - */ - -/** - * @brief DMA register map type. - * - * Note that DMA controller 2 (register map base pointer DMA2_BASE) - * only supports channels 1--5. - */ -typedef struct dma_reg_map { - __io uint32 ISR; /**< Interrupt status register */ - __io uint32 IFCR; /**< Interrupt flag clear register */ - __io uint32 CCR1; /**< Channel 1 configuration register */ - __io uint32 CNDTR1; /**< Channel 1 number of data register */ - __io uint32 CPAR1; /**< Channel 1 peripheral address register */ - __io uint32 CMAR1; /**< Channel 1 memory address register */ - const uint32 RESERVED1; /**< Reserved. */ - __io uint32 CCR2; /**< Channel 2 configuration register */ - __io uint32 CNDTR2; /**< Channel 2 number of data register */ - __io uint32 CPAR2; /**< Channel 2 peripheral address register */ - __io uint32 CMAR2; /**< Channel 2 memory address register */ - const uint32 RESERVED2; /**< Reserved. */ - __io uint32 CCR3; /**< Channel 3 configuration register */ - __io uint32 CNDTR3; /**< Channel 3 number of data register */ - __io uint32 CPAR3; /**< Channel 3 peripheral address register */ - __io uint32 CMAR3; /**< Channel 3 memory address register */ - const uint32 RESERVED3; /**< Reserved. */ - __io uint32 CCR4; /**< Channel 4 configuration register */ - __io uint32 CNDTR4; /**< Channel 4 number of data register */ - __io uint32 CPAR4; /**< Channel 4 peripheral address register */ - __io uint32 CMAR4; /**< Channel 4 memory address register */ - const uint32 RESERVED4; /**< Reserved. */ - __io uint32 CCR5; /**< Channel 5 configuration register */ - __io uint32 CNDTR5; /**< Channel 5 number of data register */ - __io uint32 CPAR5; /**< Channel 5 peripheral address register */ - __io uint32 CMAR5; /**< Channel 5 memory address register */ - const uint32 RESERVED5; /**< Reserved. */ - __io uint32 CCR6; /**< Channel 6 configuration register */ - __io uint32 CNDTR6; /**< Channel 6 number of data register */ - __io uint32 CPAR6; /**< Channel 6 peripheral address register */ - __io uint32 CMAR6; /**< Channel 6 memory address register */ - const uint32 RESERVED6; /**< Reserved. */ - __io uint32 CCR7; /**< Channel 7 configuration register */ - __io uint32 CNDTR7; /**< Channel 7 number of data register */ - __io uint32 CPAR7; /**< Channel 7 peripheral address register */ - __io uint32 CMAR7; /**< Channel 7 memory address register */ - const uint32 RESERVED7; /**< Reserved. */ -} dma_reg_map; - -/** DMA controller 1 register map base pointer */ -#define DMA1_BASE ((struct dma_reg_map*)0x40020000) - -#ifdef STM32_HIGH_DENSITY -/** DMA controller 2 register map base pointer */ -#define DMA2_BASE ((struct dma_reg_map*)0x40020400) -#endif - -/* - * Register bit definitions - */ - -/* Interrupt status register */ - -#define DMA_ISR_TEIF7_BIT 27 -#define DMA_ISR_HTIF7_BIT 26 -#define DMA_ISR_TCIF7_BIT 25 -#define DMA_ISR_GIF7_BIT 24 -#define DMA_ISR_TEIF6_BIT 23 -#define DMA_ISR_HTIF6_BIT 22 -#define DMA_ISR_TCIF6_BIT 21 -#define DMA_ISR_GIF6_BIT 20 -#define DMA_ISR_TEIF5_BIT 19 -#define DMA_ISR_HTIF5_BIT 18 -#define DMA_ISR_TCIF5_BIT 17 -#define DMA_ISR_GIF5_BIT 16 -#define DMA_ISR_TEIF4_BIT 15 -#define DMA_ISR_HTIF4_BIT 14 -#define DMA_ISR_TCIF4_BIT 13 -#define DMA_ISR_GIF4_BIT 12 -#define DMA_ISR_TEIF3_BIT 11 -#define DMA_ISR_HTIF3_BIT 10 -#define DMA_ISR_TCIF3_BIT 9 -#define DMA_ISR_GIF3_BIT 8 -#define DMA_ISR_TEIF2_BIT 7 -#define DMA_ISR_HTIF2_BIT 6 -#define DMA_ISR_TCIF2_BIT 5 -#define DMA_ISR_GIF2_BIT 4 -#define DMA_ISR_TEIF1_BIT 3 -#define DMA_ISR_HTIF1_BIT 2 -#define DMA_ISR_TCIF1_BIT 1 -#define DMA_ISR_GIF1_BIT 0 - -#define DMA_ISR_TEIF7 BIT(DMA_ISR_TEIF7_BIT) -#define DMA_ISR_HTIF7 BIT(DMA_ISR_HTIF7_BIT) -#define DMA_ISR_TCIF7 BIT(DMA_ISR_TCIF7_BIT) -#define DMA_ISR_GIF7 BIT(DMA_ISR_GIF7_BIT) -#define DMA_ISR_TEIF6 BIT(DMA_ISR_TEIF6_BIT) -#define DMA_ISR_HTIF6 BIT(DMA_ISR_HTIF6_BIT) -#define DMA_ISR_TCIF6 BIT(DMA_ISR_TCIF6_BIT) -#define DMA_ISR_GIF6 BIT(DMA_ISR_GIF6_BIT) -#define DMA_ISR_TEIF5 BIT(DMA_ISR_TEIF5_BIT) -#define DMA_ISR_HTIF5 BIT(DMA_ISR_HTIF5_BIT) -#define DMA_ISR_TCIF5 BIT(DMA_ISR_TCIF5_BIT) -#define DMA_ISR_GIF5 BIT(DMA_ISR_GIF5_BIT) -#define DMA_ISR_TEIF4 BIT(DMA_ISR_TEIF4_BIT) -#define DMA_ISR_HTIF4 BIT(DMA_ISR_HTIF4_BIT) -#define DMA_ISR_TCIF4 BIT(DMA_ISR_TCIF4_BIT) -#define DMA_ISR_GIF4 BIT(DMA_ISR_GIF4_BIT) -#define DMA_ISR_TEIF3 BIT(DMA_ISR_TEIF3_BIT) -#define DMA_ISR_HTIF3 BIT(DMA_ISR_HTIF3_BIT) -#define DMA_ISR_TCIF3 BIT(DMA_ISR_TCIF3_BIT) -#define DMA_ISR_GIF3 BIT(DMA_ISR_GIF3_BIT) -#define DMA_ISR_TEIF2 BIT(DMA_ISR_TEIF2_BIT) -#define DMA_ISR_HTIF2 BIT(DMA_ISR_HTIF2_BIT) -#define DMA_ISR_TCIF2 BIT(DMA_ISR_TCIF2_BIT) -#define DMA_ISR_GIF2 BIT(DMA_ISR_GIF2_BIT) -#define DMA_ISR_TEIF1 BIT(DMA_ISR_TEIF1_BIT) -#define DMA_ISR_HTIF1 BIT(DMA_ISR_HTIF1_BIT) -#define DMA_ISR_TCIF1 BIT(DMA_ISR_TCIF1_BIT) -#define DMA_ISR_GIF1 BIT(DMA_ISR_GIF1_BIT) - -/* Interrupt flag clear register */ - -#define DMA_IFCR_CTEIF7_BIT 27 -#define DMA_IFCR_CHTIF7_BIT 26 -#define DMA_IFCR_CTCIF7_BIT 25 -#define DMA_IFCR_CGIF7_BIT 24 -#define DMA_IFCR_CTEIF6_BIT 23 -#define DMA_IFCR_CHTIF6_BIT 22 -#define DMA_IFCR_CTCIF6_BIT 21 -#define DMA_IFCR_CGIF6_BIT 20 -#define DMA_IFCR_CTEIF5_BIT 19 -#define DMA_IFCR_CHTIF5_BIT 18 -#define DMA_IFCR_CTCIF5_BIT 17 -#define DMA_IFCR_CGIF5_BIT 16 -#define DMA_IFCR_CTEIF4_BIT 15 -#define DMA_IFCR_CHTIF4_BIT 14 -#define DMA_IFCR_CTCIF4_BIT 13 -#define DMA_IFCR_CGIF4_BIT 12 -#define DMA_IFCR_CTEIF3_BIT 11 -#define DMA_IFCR_CHTIF3_BIT 10 -#define DMA_IFCR_CTCIF3_BIT 9 -#define DMA_IFCR_CGIF3_BIT 8 -#define DMA_IFCR_CTEIF2_BIT 7 -#define DMA_IFCR_CHTIF2_BIT 6 -#define DMA_IFCR_CTCIF2_BIT 5 -#define DMA_IFCR_CGIF2_BIT 4 -#define DMA_IFCR_CTEIF1_BIT 3 -#define DMA_IFCR_CHTIF1_BIT 2 -#define DMA_IFCR_CTCIF1_BIT 1 -#define DMA_IFCR_CGIF1_BIT 0 - -#define DMA_IFCR_CTEIF7 BIT(DMA_IFCR_CTEIF7_BIT) -#define DMA_IFCR_CHTIF7 BIT(DMA_IFCR_CHTIF7_BIT) -#define DMA_IFCR_CTCIF7 BIT(DMA_IFCR_CTCIF7_BIT) -#define DMA_IFCR_CGIF7 BIT(DMA_IFCR_CGIF7_BIT) -#define DMA_IFCR_CTEIF6 BIT(DMA_IFCR_CTEIF6_BIT) -#define DMA_IFCR_CHTIF6 BIT(DMA_IFCR_CHTIF6_BIT) -#define DMA_IFCR_CTCIF6 BIT(DMA_IFCR_CTCIF6_BIT) -#define DMA_IFCR_CGIF6 BIT(DMA_IFCR_CGIF6_BIT) -#define DMA_IFCR_CTEIF5 BIT(DMA_IFCR_CTEIF5_BIT) -#define DMA_IFCR_CHTIF5 BIT(DMA_IFCR_CHTIF5_BIT) -#define DMA_IFCR_CTCIF5 BIT(DMA_IFCR_CTCIF5_BIT) -#define DMA_IFCR_CGIF5 BIT(DMA_IFCR_CGIF5_BIT) -#define DMA_IFCR_CTEIF4 BIT(DMA_IFCR_CTEIF4_BIT) -#define DMA_IFCR_CHTIF4 BIT(DMA_IFCR_CHTIF4_BIT) -#define DMA_IFCR_CTCIF4 BIT(DMA_IFCR_CTCIF4_BIT) -#define DMA_IFCR_CGIF4 BIT(DMA_IFCR_CGIF4_BIT) -#define DMA_IFCR_CTEIF3 BIT(DMA_IFCR_CTEIF3_BIT) -#define DMA_IFCR_CHTIF3 BIT(DMA_IFCR_CHTIF3_BIT) -#define DMA_IFCR_CTCIF3 BIT(DMA_IFCR_CTCIF3_BIT) -#define DMA_IFCR_CGIF3 BIT(DMA_IFCR_CGIF3_BIT) -#define DMA_IFCR_CTEIF2 BIT(DMA_IFCR_CTEIF2_BIT) -#define DMA_IFCR_CHTIF2 BIT(DMA_IFCR_CHTIF2_BIT) -#define DMA_IFCR_CTCIF2 BIT(DMA_IFCR_CTCIF2_BIT) -#define DMA_IFCR_CGIF2 BIT(DMA_IFCR_CGIF2_BIT) -#define DMA_IFCR_CTEIF1 BIT(DMA_IFCR_CTEIF1_BIT) -#define DMA_IFCR_CHTIF1 BIT(DMA_IFCR_CHTIF1_BIT) -#define DMA_IFCR_CTCIF1 BIT(DMA_IFCR_CTCIF1_BIT) -#define DMA_IFCR_CGIF1 BIT(DMA_IFCR_CGIF1_BIT) - -/* Channel configuration register */ - -#define DMA_CCR_MEM2MEM_BIT 14 -#define DMA_CCR_MINC_BIT 7 -#define DMA_CCR_PINC_BIT 6 -#define DMA_CCR_CIRC_BIT 5 -#define DMA_CCR_DIR_BIT 4 -#define DMA_CCR_TEIE_BIT 3 -#define DMA_CCR_HTIE_BIT 2 -#define DMA_CCR_TCIE_BIT 1 -#define DMA_CCR_EN_BIT 0 - -#define DMA_CCR_MEM2MEM BIT(DMA_CCR_MEM2MEM_BIT) -#define DMA_CCR_PL (0x3 << 12) -#define DMA_CCR_PL_LOW (0x0 << 12) -#define DMA_CCR_PL_MEDIUM (0x1 << 12) -#define DMA_CCR_PL_HIGH (0x2 << 12) -#define DMA_CCR_PL_VERY_HIGH (0x3 << 12) -#define DMA_CCR_MSIZE (0x3 << 10) -#define DMA_CCR_MSIZE_8BITS (0x0 << 10) -#define DMA_CCR_MSIZE_16BITS (0x1 << 10) -#define DMA_CCR_MSIZE_32BITS (0x2 << 10) -#define DMA_CCR_PSIZE (0x3 << 8) -#define DMA_CCR_PSIZE_8BITS (0x0 << 8) -#define DMA_CCR_PSIZE_16BITS (0x1 << 8) -#define DMA_CCR_PSIZE_32BITS (0x2 << 8) -#define DMA_CCR_MINC BIT(DMA_CCR_MINC_BIT) -#define DMA_CCR_PINC BIT(DMA_CCR_PINC_BIT) -#define DMA_CCR_CIRC BIT(DMA_CCR_CIRC_BIT) -#define DMA_CCR_DIR BIT(DMA_CCR_DIR_BIT) -#define DMA_CCR_TEIE BIT(DMA_CCR_TEIE_BIT) -#define DMA_CCR_HTIE BIT(DMA_CCR_HTIE_BIT) -#define DMA_CCR_TCIE BIT(DMA_CCR_TCIE_BIT) -#define DMA_CCR_EN BIT(DMA_CCR_EN_BIT) - -/* - * Devices - */ - -/** Encapsulates state related to a DMA channel interrupt. */ -typedef struct dma_handler_config { - void (*handler)(void); /**< User-specified channel interrupt - handler */ - nvic_irq_num irq_line; /**< Channel's NVIC interrupt number */ -} dma_handler_config; - -/** DMA device type */ -typedef struct dma_dev { - dma_reg_map *regs; /**< Register map */ - rcc_clk_id clk_id; /**< Clock ID */ - dma_handler_config handlers[]; /**< - * @brief IRQ handlers and NVIC numbers. - * - * @see dma_attach_interrupt() - * @see dma_detach_interrupt() - */ -} dma_dev; - -extern dma_dev *DMA1; -#ifdef STM32_HIGH_DENSITY -extern dma_dev *DMA2; -#endif - -/* - * Convenience functions - */ - -void dma_init(dma_dev *dev); - -/** Flags for DMA transfer configuration. */ -typedef enum dma_mode_flags { - DMA_MEM_2_MEM = 1 << 14, /**< Memory to memory mode */ - DMA_MINC_MODE = 1 << 7, /**< Auto-increment memory address */ - DMA_PINC_MODE = 1 << 6, /**< Auto-increment peripheral address */ - DMA_CIRC_MODE = 1 << 5, /**< Circular mode */ - DMA_FROM_MEM = 1 << 4, /**< Read from memory to peripheral */ - DMA_TRNS_ERR = 1 << 3, /**< Interrupt on transfer error */ - DMA_HALF_TRNS = 1 << 2, /**< Interrupt on half-transfer */ - DMA_TRNS_CMPLT = 1 << 1 /**< Interrupt on transfer completion */ -} dma_mode_flags; - -/** Source and destination transfer sizes. */ -typedef enum dma_xfer_size { - DMA_SIZE_8BITS = 0, /**< 8-bit transfers */ - DMA_SIZE_16BITS = 1, /**< 16-bit transfers */ - DMA_SIZE_32BITS = 2 /**< 32-bit transfers */ -} dma_xfer_size; - -/** DMA channel */ -typedef enum dma_channel { - DMA_CH1 = 1, /**< Channel 1 */ - DMA_CH2 = 2, /**< Channel 2 */ - DMA_CH3 = 3, /**< Channel 3 */ - DMA_CH4 = 4, /**< Channel 4 */ - DMA_CH5 = 5, /**< Channel 5 */ - DMA_CH6 = 6, /**< Channel 6 */ - DMA_CH7 = 7, /**< Channel 7 */ -} dma_channel; - -void dma_setup_transfer(dma_dev *dev, - dma_channel channel, - __io void *peripheral_address, - dma_xfer_size peripheral_size, - __io void *memory_address, - dma_xfer_size memory_size, - uint32 mode); - -void dma_set_num_transfers(dma_dev *dev, - dma_channel channel, - uint16 num_transfers); - -/** DMA transfer priority. */ -typedef enum dma_priority { - DMA_PRIORITY_LOW = DMA_CCR_PL_LOW, /**< Low priority */ - DMA_PRIORITY_MEDIUM = DMA_CCR_PL_MEDIUM, /**< Medium priority */ - DMA_PRIORITY_HIGH = DMA_CCR_PL_HIGH, /**< High priority */ - DMA_PRIORITY_VERY_HIGH = DMA_CCR_PL_VERY_HIGH /**< Very high priority */ -} dma_priority; - -void dma_set_priority(dma_dev *dev, - dma_channel channel, - dma_priority priority); - -void dma_attach_interrupt(dma_dev *dev, - dma_channel channel, - void (*handler)(void)); -void dma_detach_interrupt(dma_dev *dev, dma_channel channel); - -/** - * Encodes the reason why a DMA interrupt was called. - * @see dma_get_irq_cause() - */ -typedef enum dma_irq_cause { - DMA_TRANSFER_COMPLETE, /**< Transfer is complete. */ - DMA_TRANSFER_HALF_COMPLETE, /**< Transfer is half complete. */ - DMA_TRANSFER_ERROR, /**< Error occurred during transfer. */ -} dma_irq_cause; - -dma_irq_cause dma_get_irq_cause(dma_dev *dev, dma_channel channel); - -void dma_enable(dma_dev *dev, dma_channel channel); -void dma_disable(dma_dev *dev, dma_channel channel); - -void dma_set_mem_addr(dma_dev *dev, dma_channel channel, __io void *address); -void dma_set_per_addr(dma_dev *dev, dma_channel channel, __io void *address); - -/** - * @brief DMA channel register map type. - * - * Provides access to an individual channel's registers. - */ -typedef struct dma_channel_reg_map { - __io uint32 CCR; /**< Channel configuration register */ - __io uint32 CNDTR; /**< Channel number of data register */ - __io uint32 CPAR; /**< Channel peripheral address register */ - __io uint32 CMAR; /**< Channel memory address register */ -} dma_channel_reg_map; - -#define DMA_CHANNEL_NREGS 5 - -/** - * @brief Obtain a pointer to an individual DMA channel's registers. - * - * For example, dma_channel_regs(DMA1, DMA_CH1)->CCR is DMA1_BASE->CCR1. - * - * @param dev DMA device - * @param channel DMA channel whose channel register map to obtain. - */ -static inline dma_channel_reg_map* dma_channel_regs(dma_dev *dev, - dma_channel channel) { - __io uint32 *ccr1 = &dev->regs->CCR1; - return (dma_channel_reg_map*)(ccr1 + DMA_CHANNEL_NREGS * (channel - 1)); -} - -/** - * @brief Check if a DMA channel is enabled - * @param dev DMA device - * @param channel Channel whose enabled bit to check. - */ -static inline uint8 dma_is_channel_enabled(dma_dev *dev, dma_channel channel) { - return (uint8)(dma_channel_regs(dev, channel)->CCR & DMA_CCR_EN); -} - -/** - * @brief Get the ISR status bits for a DMA channel. - * - * The bits are returned right-aligned, in the following order: - * transfer error flag, half-transfer flag, transfer complete flag, - * global interrupt flag. - * - * If you're attempting to figure out why a DMA interrupt fired; you - * may find dma_get_irq_cause() more convenient. - * - * @param dev DMA device - * @param channel Channel whose ISR bits to return. - * @see dma_get_irq_cause(). - */ -static inline uint8 dma_get_isr_bits(dma_dev *dev, dma_channel channel) { - uint8 shift = (channel - 1) * 4; - return (dev->regs->ISR >> shift) & 0xF; -} - -/** - * @brief Clear the ISR status bits for a given DMA channel. - * - * If you're attempting to clean up after yourself in a DMA interrupt, - * you may find dma_get_irq_cause() more convenient. - * - * @param dev DMA device - * @param channel Channel whose ISR bits to clear. - * @see dma_get_irq_cause() - */ -static inline void dma_clear_isr_bits(dma_dev *dev, dma_channel channel) { - dev->regs->IFCR = BIT(4 * (channel - 1)); -} - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif diff --git a/STM32F4/cores/maple/libmaple/dmaF2.c b/STM32F4/cores/maple/libmaple/dmaF2.c deleted file mode 100644 index 0911e58..0000000 --- a/STM32F4/cores/maple/libmaple/dmaF2.c +++ /dev/null @@ -1,241 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Michael Hope. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - - #ifdef STM32F2 - -/** - * @file dmaF2.c - * @brief Direct Memory Access peripheral support - */ - -#include "dma.h" -#include "bitband.h" -#include "util.h" - -/* - * Devices - */ - -static dma_dev dma1 = { - .regs = DMA1_BASE, - .clk_id = RCC_DMA1, - .handlers = {{ .handler = NULL, .irq_line = 11 }, - { .handler = NULL, .irq_line = 12 }, - { .handler = NULL, .irq_line = 13 }, - { .handler = NULL, .irq_line = 14 }, - { .handler = NULL, .irq_line = 15 }, - { .handler = NULL, .irq_line = 16 }, - { .handler = NULL, .irq_line = 17 }, - { .handler = NULL, .irq_line = 47 }} -}; -/** DMA1 device */ -dma_dev *DMA1 = &dma1; - -static dma_dev dma2 = { - .regs = DMA2_BASE, - .clk_id = RCC_DMA2, - .handlers = {{ .handler = NULL, .irq_line = 56 }, - { .handler = NULL, .irq_line = 57 }, - { .handler = NULL, .irq_line = 58 }, - { .handler = NULL, .irq_line = 59 }, - { .handler = NULL, .irq_line = 60 }, - { .handler = NULL, .irq_line = 68 }, - { .handler = NULL, .irq_line = 69 }, - { .handler = NULL, .irq_line = 70 }} /* !@#$ */ -}; -/** DMA2 device */ -dma_dev *DMA2 = &dma2; - - -/* - * Convenience routines - */ - -/** - * @brief Initialize a DMA device. - * @param dev Device to initialize. - */ -void dma_init(dma_dev *dev) { - rcc_clk_enable(dev->clk_id); -} - -/** - * @brief Attach an interrupt to a DMA transfer. - * - * Interrupts are enabled using appropriate mode flags in - * dma_setup_transfer(). - * - * @param dev DMA device - * @param stream Stream to attach handler to - * @param handler Interrupt handler to call when channel interrupt fires. - * @see dma_setup_transfer() - * @see dma_detach_interrupt() - */ -void dma_attach_interrupt(dma_dev *dev, - dma_stream stream, - void (*handler)(void)) { - dev->handlers[stream].handler = handler; - nvic_irq_enable(dev->handlers[stream].irq_line); -} - -/** - * @brief Detach a DMA transfer interrupt handler. - * - * After calling this function, the given channel's interrupts will be - * disabled. - * - * @param dev DMA device - * @param stream Stream whose handler to detach - * @sideeffect Clears interrupt enable bits in the channel's CCR register. - * @see dma_attach_interrupt() - */ -void dma_detach_interrupt(dma_dev *dev, dma_stream stream) { - nvic_irq_disable(dev->handlers[stream].irq_line); - dev->handlers[stream].handler = NULL; -} - -void dma_clear_isr_bits(dma_dev *dev, dma_stream stream) { - switch (stream) { - case 0: - dev->regs->LIFCR|=0x0000003d; - break; - case 1: - dev->regs->LIFCR|=0x00000f40; - break; - case 2: - dev->regs->LIFCR|=0x003d0000; - break; - case 3: - dev->regs->LIFCR|=0x0f400000; - break; - case 4: - dev->regs->HIFCR|=0x0000003d; - break; - case 5: - dev->regs->HIFCR|=0x00000f40; - break; - case 6: - dev->regs->HIFCR|=0x003d0000; - break; - case 7: - dev->regs->HIFCR|=0x0f400000; - break; - } -} - -/* - * IRQ handlers - */ - -static inline void dispatch_handler(dma_dev *dev, dma_stream stream) { - void (*handler)(void) = dev->handlers[stream].handler; - if (handler) { - handler(); - dma_clear_isr_bits(dev, stream); /* in case handler doesn't */ - } -} - -//void __irq_dma1_stream0(void) { -void __irq_dma1_channel1(void) { - dispatch_handler(DMA1, DMA_STREAM0); -} - -//void __irq_dma1_stream1(void) { -void __irq_dma1_channel2(void) { - dispatch_handler(DMA1, DMA_STREAM1); -} - -//void __irq_dma1_stream2(void) { -void __irq_dma1_channel3(void) { - dispatch_handler(DMA1, DMA_STREAM2); -} - -//void __irq_dma1_stream3(void) { -void __irq_dma1_channel4(void) { - dispatch_handler(DMA1, DMA_STREAM3); -} - -//void __irq_dma1_stream4(void) { -void __irq_dma1_channel5(void) { - dispatch_handler(DMA1, DMA_STREAM4); -} - -//void __irq_dma1_stream5(void) { -void __irq_dma1_channel6(void) { - dispatch_handler(DMA1, DMA_STREAM5); -} - -//void __irq_dma1_stream6(void) { -void __irq_dma1_channel7(void) { - dispatch_handler(DMA1, DMA_STREAM6); -} - -//void __irq_dma1_stream7(void) { -void __irq_adc3(void) { - dispatch_handler(DMA1, DMA_STREAM7); -} - -//void __irq_dma2_stream0(void) { -void __irq_dma2_channel1(void) { - dispatch_handler(DMA2, DMA_STREAM0); -} - -//void __irq_dma2_stream1(void) { -void __irq_dma2_channel2(void) { - dispatch_handler(DMA2, DMA_STREAM1); -} - -//void __irq_dma2_stream2(void) { -void __irq_dma2_channel3(void) { - dispatch_handler(DMA2, DMA_STREAM2); -} - -//void __irq_dma2_stream3(void) { -void __irq_dma2_channel4_5(void) { - dispatch_handler(DMA2, DMA_STREAM3); -} - -//void __irq_dma2_stream4(void) { -void __irq_DMA2_Stream4_IRQHandler(void) { - dispatch_handler(DMA2, DMA_STREAM4); -} - -//void __irq_dma2_stream5(void) { -void __irq_DMA2_Stream5_IRQHandler(void) { - dispatch_handler(DMA2, DMA_STREAM5); -} - -//void __irq_dma2_stream6(void) { -void __irq_DMA2_Stream6_IRQHandler(void) { - dispatch_handler(DMA2, DMA_STREAM6); -} - -//void __irq_dma2_stream7(void) { -void __irq_DMA2_Stream7_IRQHandler(void) { - dispatch_handler(DMA2, DMA_STREAM7); -} - -#endif diff --git a/STM32F4/cores/maple/libmaple/dmaF2.h b/STM32F4/cores/maple/libmaple/dmaF2.h deleted file mode 100644 index 6f7086f..0000000 --- a/STM32F4/cores/maple/libmaple/dmaF2.h +++ /dev/null @@ -1,270 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Michael Hope. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file dma.h - * - * @author Marti Bolivar ; - * Original implementation by Michael Hope - * - * @brief Direct Memory Access peripheral support - */ - -/* - * See /notes/dma.txt for more information. - */ - -#ifndef _DMA_H_ -#define _DMA_H_ - -#include "libmaple_types.h" -#include "rcc.h" -#include "nvic.h" - -#ifdef __cplusplus -extern "C"{ -#endif - -/* - * Register maps - */ - -/** - * @brief DMA stream type. - * - */ -typedef struct dma_stream_t { - __io uint32 CR; /**< Stream configuration register */ - __io uint32 NDTR; /**< Stream number of data register */ - __io uint32 PAR; /**< Stream peripheral address register */ - __io uint32 M0AR; /**< Stream memory address register 0 */ - __io uint32 M1AR; /**< Stream memory address register 1 */ - __io uint32 FCR; /**< Stream FIFO configuration register */ -} dma_stream_t; -/** - * @brief DMA register map type. - * - */ -typedef struct dma_reg_map { - __io uint32 LISR; /**< Low interrupt status register */ - __io uint32 HISR; /**< High interrupt status register */ - __io uint32 LIFCR; /**< Low interrupt flag clear register */ - __io uint32 HIFCR; /**< High interrupt flag clear register */ - dma_stream_t STREAM[8]; -} dma_reg_map; - -/** DMA controller register map base pointers */ -#define DMA1_BASE ((struct dma_reg_map*)0x40026000) -#define DMA2_BASE ((struct dma_reg_map*)0x40026400) - -/* - * Register bit definitions - */ - -/* Channel configuration register */ - -#define DMA_CR_CH0 (0x0 << 25) -#define DMA_CR_CH1 (0x1 << 25) -#define DMA_CR_CH2 (0x2 << 25) -#define DMA_CR_CH3 (0x3 << 25) -#define DMA_CR_CH4 (0x4 << 25) -#define DMA_CR_CH5 (0x5 << 25) -#define DMA_CR_CH6 (0x6 << 25) -#define DMA_CR_CH7 (0x7 << 25) -#define DMA_CR_MBURST0 (0x0 << 23) -#define DMA_CR_MBURST4 (0x1 << 23) -#define DMA_CR_MBURST8 (0x2 << 23) -#define DMA_CR_MBURST16 (0x3 << 23) -#define DMA_CR_PBURST0 (0x0 << 21) -#define DMA_CR_PBURST4 (0x1 << 21) -#define DMA_CR_PBURST8 (0x2 << 21) -#define DMA_CR_PBURST16 (0x3 << 21) -#define DMA_CR_CT0 (0x0 << 19) -#define DMA_CR_CT1 (0x1 << 19) -#define DMA_CR_DBM (0x1 << 18) - -#define DMA_CR_PL_LOW (0x0 << 16) -#define DMA_CR_PL_MEDIUM (0x1 << 16) -#define DMA_CR_PL_HIGH (0x2 << 16) -#define DMA_CR_PL_VERY_HIGH (0x3 << 16) -#define DMA_CR_PL_MASK (0x3 << 16) - -#define DMA_CR_PINCOS (0x1 << 15) - -#define DMA_CR_MSIZE_8BITS (0x0 << 13) -#define DMA_CR_MSIZE_16BITS (0x1 << 13) -#define DMA_CR_MSIZE_32BITS (0x2 << 13) - -#define DMA_CR_PSIZE_8BITS (0x0 << 11) -#define DMA_CR_PSIZE_16BITS (0x1 << 11) -#define DMA_CR_PSIZE_32BITS (0x2 << 11) - -#define DMA_CR_MINC (0x1 << 10) -#define DMA_CR_PINC (0x1 << 9) -#define DMA_CR_CIRC (0x1 << 8) -#define DMA_CR_DIR_P2M (0x0 << 6) -#define DMA_CR_DIR_M2P (0x1 << 6) -#define DMA_CR_DIR_M2M (0x2 << 6) - -#define DMA_CR_PFCTRL (0x1 << 5) -#define DMA_CR_TCIE (0x1 << 4) -#define DMA_CR_HTIE (0x1 << 3) -#define DMA_CR_TEIE (0x1 << 2) -#define DMA_CR_DMEIE (0x1 << 1) -#define DMA_CR_EN (0x1) - -/* - * Devices - */ - -/** Encapsulates state related to a DMA channel interrupt. */ -typedef struct dma_handler_config { - void (*handler)(void); /**< User-specified channel interrupt - handler */ - nvic_irq_num irq_line; /**< Channel's NVIC interrupt number */ -} dma_handler_config; - -/** DMA device type */ -typedef struct dma_dev { - dma_reg_map *regs; /**< Register map */ - rcc_clk_id clk_id; /**< Clock ID */ - dma_handler_config handlers[]; /**< - * @brief IRQ handlers and NVIC numbers. - * - * @see dma_attach_interrupt() - * @see dma_detach_interrupt() - */ -} dma_dev; - -extern dma_dev *DMA1; -extern dma_dev *DMA2; - -/* - * Convenience functions - */ - -void dma_init(dma_dev *dev); - -/** Flags for DMA transfer configuration. */ -typedef enum dma_mode_flags { - DMA_MEM_2_MEM = 1 << 14, /**< Memory to memory mode */ - DMA_MINC_MODE = 1 << 7, /**< Auto-increment memory address */ - DMA_PINC_MODE = 1 << 6, /**< Auto-increment peripheral address */ - DMA_CIRC_MODE = 1 << 5, /**< Circular mode */ - DMA_FROM_MEM = 1 << 4, /**< Read from memory to peripheral */ - DMA_TRNS_ERR = 1 << 3, /**< Interrupt on transfer error */ - DMA_HALF_TRNS = 1 << 2, /**< Interrupt on half-transfer */ - DMA_TRNS_CMPLT = 1 << 1 /**< Interrupt on transfer completion */ -} dma_mode_flags; - -/** Source and destination transfer sizes. */ -typedef enum dma_xfer_size { - DMA_SIZE_8BITS = 0, /**< 8-bit transfers */ - DMA_SIZE_16BITS = 1, /**< 16-bit transfers */ - DMA_SIZE_32BITS = 2 /**< 32-bit transfers */ -} dma_xfer_size; - -/** DMA channel */ -typedef enum dma_stream { - DMA_STREAM0 = 0, /**< Stream 0 */ - DMA_STREAM1 = 1, /**< Stream 1 */ - DMA_STREAM2 = 2, /**< Stream 2 */ - DMA_STREAM3 = 3, /**< Stream 3 */ - DMA_STREAM4 = 4, /**< Stream 4 */ - DMA_STREAM5 = 5, /**< Stream 5 */ - DMA_STREAM6 = 6, /**< Stream 6 */ - DMA_STREAM7 = 7, /**< Stream 7 */ -} dma_stream; - -static inline void dma_setup_transfer(dma_dev *dev, - dma_stream stream, - __io void *peripheral_address, - __io void *memory_address0, - __io void *memory_address1, - uint32 flags, - uint32 fifo_flags) { - dev->regs->STREAM[stream].CR &= ~DMA_CR_EN; // disable - dev->regs->STREAM[stream].PAR = (uint32)peripheral_address; - dev->regs->STREAM[stream].M0AR = (uint32)memory_address0; - dev->regs->STREAM[stream].M1AR = (uint32)memory_address1; - dev->regs->STREAM[stream].FCR = fifo_flags & 0x87; // mask out reserved bits - dev->regs->STREAM[stream].CR = flags & 0x0feffffe; // mask out reserved and enable -} - -static inline void dma_set_num_transfers(dma_dev *dev, - dma_stream stream, - uint16 num_transfers) { - dev->regs->STREAM[stream].NDTR = num_transfers; -} - -void dma_attach_interrupt(dma_dev *dev, - dma_stream stream, - void (*handler)(void)); - -void dma_detach_interrupt(dma_dev *dev, dma_stream stream); - -static inline void dma_enable(dma_dev *dev, dma_stream stream) { - dev->regs->STREAM[stream].CR |= DMA_CR_EN; -} - -static inline void dma_disable(dma_dev *dev, dma_stream stream) { - dev->regs->STREAM[stream].CR &= ~DMA_CR_EN; -} - -/** - * @brief Check if a DMA stream is enabled - * @param dev DMA device - * @param stream Stream whose enabled bit to check. - */ -static inline uint8 dma_is_stream_enabled(dma_dev *dev, dma_stream stream) { - return (uint8)(dev->regs->STREAM[stream].CR & DMA_CR_EN); -} - -/** - * @brief Get the ISR status bits for a DMA stream. - * - * The bits are returned right-aligned, in the following order: - * transfer error flag, half-transfer flag, transfer complete flag, - * global interrupt flag. - * - * @param dev DMA device - * @param stream Stream whose ISR bits to return. - */ -uint8 dma_get_isr_bits(dma_dev *dev, dma_stream stream); - -/** - * @brief Clear the ISR status bits for a given DMA stream. - * - * @param dev DMA device - * @param stream Stream whose ISR bits to clear. - */ -void dma_clear_isr_bits(dma_dev *dev, dma_stream stream); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif diff --git a/STM32F4/cores/maple/libmaple/gpio.c b/STM32F4/cores/maple/libmaple/gpio.c deleted file mode 100644 index 3792220..0000000 --- a/STM32F4/cores/maple/libmaple/gpio.c +++ /dev/null @@ -1,36 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file gpio.c - * @brief GPIO initialization routine - */ - -// #ifdef STM32F2 -// #include "gpioF2.c" -// #else -// #include "gpioF1.c" -// #endif diff --git a/STM32F4/cores/maple/libmaple/gpioF1.c b/STM32F4/cores/maple/libmaple/gpioF1.c deleted file mode 100644 index 846b754..0000000 --- a/STM32F4/cores/maple/libmaple/gpioF1.c +++ /dev/null @@ -1,200 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -#ifdef STM32F1 - -/** - * @file gpio.c - * @brief GPIO initialization routine - */ - -#include "gpio.h" -#include "rcc.h" - -/* - * GPIO devices - */ - -gpio_dev gpioa = { - .regs = GPIOA_BASE, - .clk_id = RCC_GPIOA, - .exti_port = AFIO_EXTI_PA, -}; -/** GPIO port A device. */ -gpio_dev* const GPIOA = &gpioa; - -gpio_dev gpiob = { - .regs = GPIOB_BASE, - .clk_id = RCC_GPIOB, - .exti_port = AFIO_EXTI_PB, -}; -/** GPIO port B device. */ -gpio_dev* const GPIOB = &gpiob; - -gpio_dev gpioc = { - .regs = GPIOC_BASE, - .clk_id = RCC_GPIOC, - .exti_port = AFIO_EXTI_PC, -}; -/** GPIO port C device. */ -gpio_dev* const GPIOC = &gpioc; - -gpio_dev gpiod = { - .regs = GPIOD_BASE, - .clk_id = RCC_GPIOD, - .exti_port = AFIO_EXTI_PD, -}; -/** GPIO port D device. */ -gpio_dev* const GPIOD = &gpiod; - -#ifdef STM32_HIGH_DENSITY -gpio_dev gpioe = { - .regs = GPIOE_BASE, - .clk_id = RCC_GPIOE, - .exti_port = AFIO_EXTI_PE, -}; -/** GPIO port E device. */ -gpio_dev* const GPIOE = &gpioe; - -gpio_dev gpiof = { - .regs = GPIOF_BASE, - .clk_id = RCC_GPIOF, - .exti_port = AFIO_EXTI_PF, -}; -/** GPIO port F device. */ -gpio_dev* const GPIOF = &gpiof; - -gpio_dev gpiog = { - .regs = GPIOG_BASE, - .clk_id = RCC_GPIOG, - .exti_port = AFIO_EXTI_PG, -}; -/** GPIO port G device. */ -gpio_dev* const GPIOG = &gpiog; -#endif - -/* - * GPIO convenience routines - */ - -/** - * Initialize a GPIO device. - * - * Enables the clock for and resets the given device. - * - * @param dev GPIO device to initialize. - */ -void gpio_init(gpio_dev *dev) { - rcc_clk_enable(dev->clk_id); - rcc_reset_dev(dev->clk_id); -} - -/** - * Initialize and reset all available GPIO devices. - */ -void gpio_init_all(void) { - gpio_init(GPIOA); - gpio_init(GPIOB); - gpio_init(GPIOC); - gpio_init(GPIOD); -#ifdef STM32_HIGH_DENSITY - gpio_init(GPIOE); - gpio_init(GPIOF); - gpio_init(GPIOG); -#endif -} - -/** - * Set the mode of a GPIO pin. - * - * @param dev GPIO device. - * @param pin Pin on the device whose mode to set, 0--15. - * @param mode General purpose or alternate function mode to set the pin to. - * @see gpio_pin_mode - */ -void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode) { - gpio_reg_map *regs = dev->regs; - __io uint32 *cr = ®s->CRL + (pin >> 3); - uint32 shift = (pin & 0x7) * 4; - uint32 tmp = *cr; - - tmp &= ~(0xF << shift); - tmp |= (mode == GPIO_INPUT_PU ? GPIO_INPUT_PD : mode) << shift; - *cr = tmp; - - if (mode == GPIO_INPUT_PD) { - regs->ODR &= ~BIT(pin); - } else if (mode == GPIO_INPUT_PU) { - regs->ODR |= BIT(pin); - } -} - -/* - * AFIO - */ - -/** - * @brief Initialize the AFIO clock, and reset the AFIO registers. - */ -void afio_init(void) { - rcc_clk_enable(RCC_AFIO); - rcc_reset_dev(RCC_AFIO); -} - -#define AFIO_EXTI_SEL_MASK 0xF - -/** - * @brief Select a source input for an external interrupt. - * - * @param exti External interrupt. - * @param gpio_port Port which contains pin to use as source input. - * @see afio_exti_num - * @see afio_exti_port - */ -void afio_exti_select(afio_exti_num exti, afio_exti_port gpio_port) { - __io uint32 *exti_cr = &AFIO_BASE->EXTICR1 + exti / 4; - uint32 shift = 4 * (exti % 4); - uint32 cr = *exti_cr; - - cr &= ~(AFIO_EXTI_SEL_MASK << shift); - cr |= gpio_port << shift; - *exti_cr = cr; -} - -/** - * @brief Perform an alternate function remap. - * @param remapping Remapping to perform. - */ -void afio_remap(afio_remap_peripheral remapping) { - if (remapping & AFIO_REMAP_USE_MAPR2) { - remapping &= ~AFIO_REMAP_USE_MAPR2; - AFIO_BASE->MAPR2 |= remapping; - } else { - AFIO_BASE->MAPR |= remapping; - } -} - -#endif diff --git a/STM32F4/cores/maple/libmaple/gpioF1.h b/STM32F4/cores/maple/libmaple/gpioF1.h deleted file mode 100644 index c69efb4..0000000 --- a/STM32F4/cores/maple/libmaple/gpioF1.h +++ /dev/null @@ -1,530 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -*****************************************************************************/ - -/** - * @file gpio.h - * - * @brief General purpose I/O (GPIO) and Alternate Function I/O - * (AFIO) prototypes, defines, and inlined access functions. - */ - -#ifndef _GPIO_H_ -#define _GPIO_H_ - -#include "libmaple.h" -#include "rcc.h" - -#ifdef __cplusplus -extern "C"{ -#endif - -/* - * GPIO register maps and devices - */ - -/** GPIO register map type */ -typedef struct gpio_reg_map { - __io uint32 CRL; /**< Port configuration register low */ - __io uint32 CRH; /**< Port configuration register high */ - __io uint32 IDR; /**< Port input data register */ - __io uint32 ODR; /**< Port output data register */ - __io uint32 BSRR; /**< Port bit set/reset register */ - __io uint32 BRR; /**< Port bit reset register */ - __io uint32 LCKR; /**< Port configuration lock register */ -} gpio_reg_map; - -/** - * @brief External interrupt line port selector. - * - * Used to determine which GPIO port to map an external interrupt line - * onto. */ -/* (See AFIO sections, below) */ -typedef enum afio_exti_port { - AFIO_EXTI_PA, /**< Use port A (PAx) pin. */ - AFIO_EXTI_PB, /**< Use port B (PBx) pin. */ - AFIO_EXTI_PC, /**< Use port C (PCx) pin. */ - AFIO_EXTI_PD, /**< Use port D (PDx) pin. */ -#ifdef STM32_HIGH_DENSITY - AFIO_EXTI_PE, /**< Use port E (PEx) pin. */ - AFIO_EXTI_PF, /**< Use port F (PFx) pin. */ - AFIO_EXTI_PG, /**< Use port G (PGx) pin. */ -#endif -} afio_exti_port; - -/** GPIO device type */ -typedef struct gpio_dev { - gpio_reg_map *regs; /**< Register map */ - rcc_clk_id clk_id; /**< RCC clock information */ - afio_exti_port exti_port; /**< AFIO external interrupt port value */ -} gpio_dev; - -extern gpio_dev gpioa; -extern gpio_dev* const GPIOA; -extern gpio_dev gpiob; -extern gpio_dev* const GPIOB; -extern gpio_dev gpioc; -extern gpio_dev* const GPIOC; -extern gpio_dev gpiod; -extern gpio_dev* const GPIOD; -#ifdef STM32_HIGH_DENSITY -extern gpio_dev gpioe; -extern gpio_dev* const GPIOE; -extern gpio_dev gpiof; -extern gpio_dev* const GPIOF; -extern gpio_dev gpiog; -extern gpio_dev* const GPIOG; -#endif - -/** GPIO port A register map base pointer */ -#define GPIOA_BASE ((struct gpio_reg_map*)0x40010800) -/** GPIO port B register map base pointer */ -#define GPIOB_BASE ((struct gpio_reg_map*)0x40010C00) -/** GPIO port C register map base pointer */ -#define GPIOC_BASE ((struct gpio_reg_map*)0x40011000) -/** GPIO port D register map base pointer */ -#define GPIOD_BASE ((struct gpio_reg_map*)0x40011400) -#ifdef STM32_HIGH_DENSITY -/** GPIO port E register map base pointer */ -#define GPIOE_BASE ((struct gpio_reg_map*)0x40011800) -/** GPIO port F register map base pointer */ -#define GPIOF_BASE ((struct gpio_reg_map*)0x40011C00) -/** GPIO port G register map base pointer */ -#define GPIOG_BASE ((struct gpio_reg_map*)0x40012000) -#endif - -/* - * GPIO register bit definitions - */ - -/* Control registers, low and high */ - -#define GPIO_CR_CNF (0x3 << 2) -#define GPIO_CR_CNF_INPUT_ANALOG (0x0 << 2) -#define GPIO_CR_CNF_INPUT_FLOATING (0x1 << 2) -#define GPIO_CR_CNF_INPUT_PU_PD (0x2 << 2) -#define GPIO_CR_CNF_OUTPUT_PP (0x0 << 2) -#define GPIO_CR_CNF_OUTPUT_OD (0x1 << 2) -#define GPIO_CR_CNF_AF_OUTPUT_PP (0x2 << 2) -#define GPIO_CR_CNF_AF_OUTPUT_OD (0x3 << 2) -#define GPIO_CR_MODE 0x3 -#define GPIO_CR_MODE_INPUT 0x0 -#define GPIO_CR_MODE_OUTPUT_10MHZ 0x1 -#define GPIO_CR_MODE_OUTPUT_2MHZ 0x2 -#define GPIO_CR_MODE_OUTPUT_50MHZ 0x3 - -/** - * @brief GPIO Pin modes. - * - * These only allow for 50MHZ max output speeds; if you want slower, - * use direct register access. - */ -typedef enum gpio_pin_mode { - GPIO_OUTPUT_PP = (GPIO_CR_CNF_OUTPUT_PP | - GPIO_CR_MODE_OUTPUT_50MHZ), /**< Output push-pull. */ - GPIO_OUTPUT_OD = (GPIO_CR_CNF_OUTPUT_OD | - GPIO_CR_MODE_OUTPUT_50MHZ), /**< Output open-drain. */ - GPIO_AF_OUTPUT_PP = (GPIO_CR_CNF_AF_OUTPUT_PP | - GPIO_CR_MODE_OUTPUT_50MHZ), /**< Alternate function - output push-pull. */ - GPIO_AF_OUTPUT_OD = (GPIO_CR_CNF_AF_OUTPUT_OD | - GPIO_CR_MODE_OUTPUT_50MHZ), /**< Alternate function - output open drain. */ - GPIO_INPUT_ANALOG = (GPIO_CR_CNF_INPUT_ANALOG | - GPIO_CR_MODE_INPUT), /**< Analog input. */ - GPIO_INPUT_FLOATING = (GPIO_CR_CNF_INPUT_FLOATING | - GPIO_CR_MODE_INPUT), /**< Input floating. */ - GPIO_INPUT_PD = (GPIO_CR_CNF_INPUT_PU_PD | - GPIO_CR_MODE_INPUT), /**< Input pull-down. */ - GPIO_AF_INPUT_PD = (GPIO_INPUT_PD), /**< Input pull-down. */ - GPIO_INPUT_PU /**< Input pull-up. */ - - - /* GPIO_INPUT_PU treated as a special case, for ODR twiddling */ -} gpio_pin_mode; - -/* - * GPIO Convenience routines - */ - -void gpio_init(gpio_dev *dev); -void gpio_init_all(void); -void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode); - -/** - * @brief Get a GPIO port's corresponding afio_exti_port. - * @param dev GPIO device whose afio_exti_port to return. - */ -static inline afio_exti_port gpio_exti_port(gpio_dev *dev) { - return dev->exti_port; -} - -/** - * Set or reset a GPIO pin. - * - * Pin must have previously been configured to output mode. - * - * @param dev GPIO device whose pin to set. - * @param pin Pin on to set or reset - * @param val If true, set the pin. If false, reset the pin. - */ -static inline void gpio_write_bit(gpio_dev *dev, uint8 pin, uint8 val) { - if (val) { - dev->regs->BSRR = BIT(pin); - } else { - dev->regs->BRR = BIT(pin); - } -} - -/** - * Determine whether or not a GPIO pin is set. - * - * Pin must have previously been configured to input mode. - * - * @param dev GPIO device whose pin to test. - * @param pin Pin on dev to test. - * @return True if the pin is set, false otherwise. - */ -static inline uint32 gpio_read_bit(gpio_dev *dev, uint8 pin) { - return dev->regs->IDR & BIT(pin); -} - -/** - * Toggle a pin configured as output push-pull. - * @param dev GPIO device. - * @param pin Pin on dev to toggle. - */ -static inline void gpio_toggle_bit(gpio_dev *dev, uint8 pin) { - dev->regs->ODR = dev->regs->ODR ^ BIT(pin); -} - -/* - * AFIO register map - */ - -/** AFIO register map */ -typedef struct afio_reg_map { - __io uint32 EVCR; /**< Event control register. */ - __io uint32 MAPR; /**< AF remap and debug I/O configuration - register. */ - __io uint32 EXTICR1; /**< External interrupt configuration - register 1. */ - __io uint32 EXTICR2; /**< External interrupt configuration - register 2. */ - __io uint32 EXTICR3; /**< External interrupt configuration - register 3. */ - __io uint32 EXTICR4; /**< External interrupt configuration - register 4. */ - __io uint32 MAPR2; /**< AF remap and debug I/O configuration - register 2. */ -} afio_reg_map; - -/** AFIO register map base pointer. */ -#define AFIO_BASE ((struct afio_reg_map *)0x40010000) - -/* - * AFIO register bit definitions - */ - -/* Event control register */ - -#define AFIO_EVCR_EVOE (0x1 << 7) -#define AFIO_EVCR_PORT_PA (0x0 << 4) -#define AFIO_EVCR_PORT_PB (0x1 << 4) -#define AFIO_EVCR_PORT_PC (0x2 << 4) -#define AFIO_EVCR_PORT_PD (0x3 << 4) -#define AFIO_EVCR_PORT_PE (0x4 << 4) -#define AFIO_EVCR_PIN_0 0x0 -#define AFIO_EVCR_PIN_1 0x1 -#define AFIO_EVCR_PIN_2 0x2 -#define AFIO_EVCR_PIN_3 0x3 -#define AFIO_EVCR_PIN_4 0x4 -#define AFIO_EVCR_PIN_5 0x5 -#define AFIO_EVCR_PIN_6 0x6 -#define AFIO_EVCR_PIN_7 0x7 -#define AFIO_EVCR_PIN_8 0x8 -#define AFIO_EVCR_PIN_9 0x9 -#define AFIO_EVCR_PIN_10 0xA -#define AFIO_EVCR_PIN_11 0xB -#define AFIO_EVCR_PIN_12 0xC -#define AFIO_EVCR_PIN_13 0xD -#define AFIO_EVCR_PIN_14 0xE -#define AFIO_EVCR_PIN_15 0xF - -/* AF remap and debug I/O configuration register */ - -#define AFIO_MAPR_SWJ_CFG (0x7 << 24) -#define AFIO_MAPR_SWJ_CFG_FULL_SWJ (0x0 << 24) -#define AFIO_MAPR_SWJ_CFG_FULL_SWJ_NO_NJRST (0x1 << 24) -#define AFIO_MAPR_SWJ_CFG_NO_JTAG_SW (0x2 << 24) -#define AFIO_MAPR_SWJ_CFG_NO_JTAG_NO_SW (0x4 << 24) -#define AFIO_MAPR_ADC2_ETRGREG_REMAP BIT(20) -#define AFIO_MAPR_ADC2_ETRGINJ_REMAP BIT(19) -#define AFIO_MAPR_ADC1_ETRGREG_REMAP BIT(18) -#define AFIO_MAPR_ADC1_ETRGINJ_REMAP BIT(17) -#define AFIO_MAPR_TIM5CH4_IREMAP BIT(16) -#define AFIO_MAPR_PD01_REMAP BIT(15) -#define AFIO_MAPR_CAN_REMAP (0x3 << 13) -#define AFIO_MAPR_CAN_REMAP_NONE (0x0 << 13) -#define AFIO_MAPR_CAN_REMAP_PB8_PB9 (0x2 << 13) -#define AFIO_MAPR_CAN_REMAP_PD0_PD1 (0x3 << 13) -#define AFIO_MAPR_TIM4_REMAP BIT(12) -#define AFIO_MAPR_TIM3_REMAP (0x3 << 10) -#define AFIO_MAPR_TIM3_REMAP_NONE (0x0 << 10) -#define AFIO_MAPR_TIM3_REMAP_PARTIAL (0x2 << 10) -#define AFIO_MAPR_TIM3_REMAP_FULL (0x3 << 10) -#define AFIO_MAPR_TIM2_REMAP (0x3 << 8) -#define AFIO_MAPR_TIM2_REMAP_NONE (0x0 << 8) -#define AFIO_MAPR_TIM2_REMAP_PA15_PB3_PA2_PA3 (0x1 << 8) -#define AFIO_MAPR_TIM2_REMAP_PA0_PA1_PB10_PB11 (0x2 << 8) -#define AFIO_MAPR_TIM2_REMAP_FULL (0x3 << 8) -#define AFIO_MAPR_TIM1_REMAP (0x3 << 6) -#define AFIO_MAPR_TIM1_REMAP_NONE (0x0 << 6) -#define AFIO_MAPR_TIM1_REMAP_PARTIAL (0x1 << 6) -#define AFIO_MAPR_TIM1_REMAP_FULL (0x3 << 6) -#define AFIO_MAPR_USART3_REMAP (0x3 << 4) -#define AFIO_MAPR_USART3_REMAP_NONE (0x0 << 4) -#define AFIO_MAPR_USART3_REMAP_PARTIAL (0x1 << 4) -#define AFIO_MAPR_USART3_REMAP_FULL (0x3 << 4) -#define AFIO_MAPR_USART2_REMAP BIT(3) -#define AFIO_MAPR_USART1_REMAP BIT(2) -#define AFIO_MAPR_I2C1_REMAP BIT(1) -#define AFIO_MAPR_SPI1_REMAP BIT(0) - -/* External interrupt configuration register 1 */ - -#define AFIO_EXTICR1_EXTI3 (0xF << 12) -#define AFIO_EXTICR1_EXTI3_PA (0x0 << 12) -#define AFIO_EXTICR1_EXTI3_PB (0x1 << 12) -#define AFIO_EXTICR1_EXTI3_PC (0x2 << 12) -#define AFIO_EXTICR1_EXTI3_PD (0x3 << 12) -#define AFIO_EXTICR1_EXTI3_PE (0x4 << 12) -#define AFIO_EXTICR1_EXTI3_PF (0x5 << 12) -#define AFIO_EXTICR1_EXTI3_PG (0x6 << 12) -#define AFIO_EXTICR1_EXTI2 (0xF << 8) -#define AFIO_EXTICR1_EXTI2_PA (0x0 << 8) -#define AFIO_EXTICR1_EXTI2_PB (0x1 << 8) -#define AFIO_EXTICR1_EXTI2_PC (0x2 << 8) -#define AFIO_EXTICR1_EXTI2_PD (0x3 << 8) -#define AFIO_EXTICR1_EXTI2_PE (0x4 << 8) -#define AFIO_EXTICR1_EXTI2_PF (0x5 << 8) -#define AFIO_EXTICR1_EXTI2_PG (0x6 << 8) -#define AFIO_EXTICR1_EXTI1 (0xF << 4) -#define AFIO_EXTICR1_EXTI1_PA (0x0 << 4) -#define AFIO_EXTICR1_EXTI1_PB (0x1 << 4) -#define AFIO_EXTICR1_EXTI1_PC (0x2 << 4) -#define AFIO_EXTICR1_EXTI1_PD (0x3 << 4) -#define AFIO_EXTICR1_EXTI1_PE (0x4 << 4) -#define AFIO_EXTICR1_EXTI1_PF (0x5 << 4) -#define AFIO_EXTICR1_EXTI1_PG (0x6 << 4) -#define AFIO_EXTICR1_EXTI0 0xF -#define AFIO_EXTICR1_EXTI0_PA 0x0 -#define AFIO_EXTICR1_EXTI0_PB 0x1 -#define AFIO_EXTICR1_EXTI0_PC 0x2 -#define AFIO_EXTICR1_EXTI0_PD 0x3 -#define AFIO_EXTICR1_EXTI0_PE 0x4 -#define AFIO_EXTICR1_EXTI0_PF 0x5 -#define AFIO_EXTICR1_EXTI0_PG 0x6 - -/* External interrupt configuration register 2 */ - -#define AFIO_EXTICR2_EXTI7 (0xF << 12) -#define AFIO_EXTICR2_EXTI7_PA (0x0 << 12) -#define AFIO_EXTICR2_EXTI7_PB (0x1 << 12) -#define AFIO_EXTICR2_EXTI7_PC (0x2 << 12) -#define AFIO_EXTICR2_EXTI7_PD (0x3 << 12) -#define AFIO_EXTICR2_EXTI7_PE (0x4 << 12) -#define AFIO_EXTICR2_EXTI7_PF (0x5 << 12) -#define AFIO_EXTICR2_EXTI7_PG (0x6 << 12) -#define AFIO_EXTICR2_EXTI6 (0xF << 8) -#define AFIO_EXTICR2_EXTI6_PA (0x0 << 8) -#define AFIO_EXTICR2_EXTI6_PB (0x1 << 8) -#define AFIO_EXTICR2_EXTI6_PC (0x2 << 8) -#define AFIO_EXTICR2_EXTI6_PD (0x3 << 8) -#define AFIO_EXTICR2_EXTI6_PE (0x4 << 8) -#define AFIO_EXTICR2_EXTI6_PF (0x5 << 8) -#define AFIO_EXTICR2_EXTI6_PG (0x6 << 8) -#define AFIO_EXTICR2_EXTI5 (0xF << 4) -#define AFIO_EXTICR2_EXTI5_PA (0x0 << 4) -#define AFIO_EXTICR2_EXTI5_PB (0x1 << 4) -#define AFIO_EXTICR2_EXTI5_PC (0x2 << 4) -#define AFIO_EXTICR2_EXTI5_PD (0x3 << 4) -#define AFIO_EXTICR2_EXTI5_PE (0x4 << 4) -#define AFIO_EXTICR2_EXTI5_PF (0x5 << 4) -#define AFIO_EXTICR2_EXTI5_PG (0x6 << 4) -#define AFIO_EXTICR2_EXTI4 0xF -#define AFIO_EXTICR2_EXTI4_PA 0x0 -#define AFIO_EXTICR2_EXTI4_PB 0x1 -#define AFIO_EXTICR2_EXTI4_PC 0x2 -#define AFIO_EXTICR2_EXTI4_PD 0x3 -#define AFIO_EXTICR2_EXTI4_PE 0x4 -#define AFIO_EXTICR2_EXTI4_PF 0x5 -#define AFIO_EXTICR2_EXTI4_PG 0x6 - -/* AF remap and debug I/O configuration register 2 */ - -#define AFIO_MAPR2_FSMC_NADV BIT(10) -#define AFIO_MAPR2_TIM14_REMAP BIT(9) -#define AFIO_MAPR2_TIM13_REMAP BIT(8) -#define AFIO_MAPR2_TIM11_REMAP BIT(7) -#define AFIO_MAPR2_TIM10_REMAP BIT(6) -#define AFIO_MAPR2_TIM9_REMAP BIT(5) - -/* - * AFIO convenience routines - */ - -void afio_init(void); - -/** - * External interrupt line numbers. - */ -typedef enum afio_exti_num { - AFIO_EXTI_0, /**< External interrupt line 0. */ - AFIO_EXTI_1, /**< External interrupt line 1. */ - AFIO_EXTI_2, /**< External interrupt line 2. */ - AFIO_EXTI_3, /**< External interrupt line 3. */ - AFIO_EXTI_4, /**< External interrupt line 4. */ - AFIO_EXTI_5, /**< External interrupt line 5. */ - AFIO_EXTI_6, /**< External interrupt line 6. */ - AFIO_EXTI_7, /**< External interrupt line 7. */ - AFIO_EXTI_8, /**< External interrupt line 8. */ - AFIO_EXTI_9, /**< External interrupt line 9. */ - AFIO_EXTI_10, /**< External interrupt line 10. */ - AFIO_EXTI_11, /**< External interrupt line 11. */ - AFIO_EXTI_12, /**< External interrupt line 12. */ - AFIO_EXTI_13, /**< External interrupt line 13. */ - AFIO_EXTI_14, /**< External interrupt line 14. */ - AFIO_EXTI_15, /**< External interrupt line 15. */ -} afio_exti_num; - -void afio_exti_select(afio_exti_num exti, afio_exti_port gpio_port); - -/* HACK: Use upper bit to denote MAPR2, Bit 31 is reserved and - * not used in either MAPR or MAPR2 */ -#define AFIO_REMAP_USE_MAPR2 (1 << 31) - -/** - * @brief Available peripheral remaps. - * @see afio_remap() - */ -typedef enum afio_remap_peripheral { - AFIO_REMAP_ADC2_ETRGREG = AFIO_MAPR_ADC2_ETRGREG_REMAP, /**< - ADC 2 external trigger regular conversion remapping */ - AFIO_REMAP_ADC2_ETRGINJ = AFIO_MAPR_ADC2_ETRGINJ_REMAP, /**< - ADC 2 external trigger injected conversion remapping */ - AFIO_REMAP_ADC1_ETRGREG = AFIO_MAPR_ADC1_ETRGREG_REMAP, /**< - ADC 1 external trigger regular conversion remapping */ - AFIO_REMAP_ADC1_ETRGINJ = AFIO_MAPR_ADC1_ETRGINJ_REMAP, /**< - ADC 1 external trigger injected conversion remapping */ - AFIO_REMAP_TIM5CH4_I = AFIO_MAPR_TIM5CH4_IREMAP, /**< - Timer 5 channel 4 internal remapping */ - AFIO_REMAP_PD01 = AFIO_MAPR_PD01_REMAP, /**< - Port D0/Port D1 mapping on OSC_IN/OSC_OUT */ - AFIO_REMAP_CAN_1 = AFIO_MAPR_CAN_REMAP_PB8_PB9, /**< - CAN alternate function remapping 1 (RX on PB8, TX on PB9) */ - AFIO_REMAP_CAN_2 = AFIO_MAPR_CAN_REMAP_PD0_PD1, /**< - CAN alternate function remapping 2 (RX on PD0, TX on PD1) */ - AFIO_REMAP_TIM4 = AFIO_MAPR_TIM4_REMAP, /**< - Timer 4 remapping */ - AFIO_REMAP_TIM3_PARTIAL = AFIO_MAPR_TIM3_REMAP_PARTIAL, /**< - Timer 3 partial remapping */ - AFIO_REMAP_TIM3_FULL = AFIO_MAPR_TIM3_REMAP_FULL, /**< - Timer 3 full remapping */ - AFIO_REMAP_TIM2_PARTIAL_1 = AFIO_MAPR_TIM2_REMAP_PA15_PB3_PA2_PA3, /**< - Timer 2 partial remapping 1 (CH1 and ETR on PA15, CH2 on PB3, CH3 - on PA2, CH4 on PA3) */ - AFIO_REMAP_TIM2_PARTIAL_2 = AFIO_MAPR_TIM2_REMAP_PA0_PA1_PB10_PB11, /**< - Timer 2 partial remapping 2 (CH1 and ETR on PA0, CH2 on PA1, CH3 - on PB10, CH4 on PB11) */ - AFIO_REMAP_TIM2_FULL = AFIO_MAPR_TIM2_REMAP_FULL, /**< - Timer 2 full remapping */ - AFIO_REMAP_USART2 = AFIO_MAPR_USART2_REMAP, /**< - USART 2 remapping */ - AFIO_REMAP_USART1 = AFIO_MAPR_USART1_REMAP, /**< - USART 1 remapping */ - AFIO_REMAP_I2C1 = AFIO_MAPR_I2C1_REMAP, /**< - I2C 1 remapping */ - AFIO_REMAP_SPI1 = AFIO_MAPR_SPI1_REMAP, /**< - SPI 1 remapping */ - AFIO_REMAP_FSMC_NADV = (AFIO_MAPR2_FSMC_NADV | - AFIO_REMAP_USE_MAPR2), /**< - NADV signal not connected */ - AFIO_REMAP_TIM14 = (AFIO_MAPR2_TIM14_REMAP | - AFIO_REMAP_USE_MAPR2), /**< - Timer 14 remapping */ - AFIO_REMAP_TIM13 = (AFIO_MAPR2_TIM13_REMAP | - AFIO_REMAP_USE_MAPR2), /**< - Timer 13 remapping */ - AFIO_REMAP_TIM11 = (AFIO_MAPR2_TIM11_REMAP | - AFIO_REMAP_USE_MAPR2), /**< - Timer 11 remapping */ - AFIO_REMAP_TIM10 = (AFIO_MAPR2_TIM10_REMAP | - AFIO_REMAP_USE_MAPR2), /**< - Timer 10 remapping */ - AFIO_REMAP_TIM9 = (AFIO_MAPR2_TIM9_REMAP | - AFIO_REMAP_USE_MAPR2) /**< - Timer 9 */ -} afio_remap_peripheral; - -void afio_remap(afio_remap_peripheral p); - -/** - * @brief Debug port configuration - * - * Used to configure the behavior of JTAG and Serial Wire (SW) debug - * ports and their associated GPIO pins. - * - * @see afio_cfg_debug_ports() - */ -typedef enum afio_debug_cfg { - AFIO_DEBUG_FULL_SWJ = AFIO_MAPR_SWJ_CFG_FULL_SWJ, /**< - Full Serial Wire and JTAG debug */ - AFIO_DEBUG_FULL_SWJ_NO_NJRST = AFIO_MAPR_SWJ_CFG_FULL_SWJ_NO_NJRST, /**< - Full Serial Wire and JTAG, but no NJTRST. */ - AFIO_DEBUG_SW_ONLY = AFIO_MAPR_SWJ_CFG_NO_JTAG_SW, /**< - Serial Wire debug only (JTAG-DP disabled, - SW-DP enabled) */ - AFIO_DEBUG_NONE = AFIO_MAPR_SWJ_CFG_NO_JTAG_NO_SW /**< - No debug; all JTAG and SW pins are free - for use as GPIOs. */ -} afio_debug_cfg; - -/** - * @brief Enable or disable the JTAG and SW debug ports. - * @param config Desired debug port configuration - * @see afio_debug_cfg - */ -static inline void afio_cfg_debug_ports(afio_debug_cfg config) { - __io uint32 *mapr = &AFIO_BASE->MAPR; - *mapr = (*mapr & ~AFIO_MAPR_SWJ_CFG) | config; -} - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/STM32F4/cores/maple/libmaple/gpioF2.c b/STM32F4/cores/maple/libmaple/gpioF2.c deleted file mode 100644 index b04c7e9..0000000 --- a/STM32F4/cores/maple/libmaple/gpioF2.c +++ /dev/null @@ -1,224 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - - #ifdef STM32F2 - -/** - * @file gpio.c - * @brief GPIO initialization routine - */ - -#include "gpio.h" -#include "rcc.h" - -/* - * GPIO devices - */ - -gpio_dev gpioa = { - .regs = GPIOA_BASE, - .clk_id = RCC_GPIOA, - .exti_port = AFIO_EXTI_PA, -}; -/** GPIO port A device. */ -gpio_dev* const GPIOA = &gpioa; - -gpio_dev gpiob = { - .regs = GPIOB_BASE, - .clk_id = RCC_GPIOB, - .exti_port = AFIO_EXTI_PB, -}; -/** GPIO port B device. */ -gpio_dev* const GPIOB = &gpiob; - -gpio_dev gpioc = { - .regs = GPIOC_BASE, - .clk_id = RCC_GPIOC, - .exti_port = AFIO_EXTI_PC, -}; -/** GPIO port C device. */ -gpio_dev* const GPIOC = &gpioc; - -gpio_dev gpiod = { - .regs = GPIOD_BASE, - .clk_id = RCC_GPIOD, - .exti_port = AFIO_EXTI_PD, -}; -/** GPIO port D device. */ -gpio_dev* const GPIOD = &gpiod; - -#ifdef STM32_HIGH_DENSITY -gpio_dev gpioe = { - .regs = GPIOE_BASE, - .clk_id = RCC_GPIOE, - .exti_port = AFIO_EXTI_PE, -}; -/** GPIO port E device. */ -gpio_dev* const GPIOE = &gpioe; - -gpio_dev gpiof = { - .regs = GPIOF_BASE, - .clk_id = RCC_GPIOF, - .exti_port = AFIO_EXTI_PF, -}; -/** GPIO port F device. */ -gpio_dev* const GPIOF = &gpiof; - -gpio_dev gpiog = { - .regs = GPIOG_BASE, - .clk_id = RCC_GPIOG, - .exti_port = AFIO_EXTI_PG, -}; -/** GPIO port G device. */ -gpio_dev* const GPIOG = &gpiog; -#endif - -/* - * GPIO convenience routines - */ - -/** - * Initialize a GPIO device. - * - * Enables the clock for and resets the given device. - * - * @param dev GPIO device to initialize. - */ -void gpio_init(gpio_dev *dev) { - rcc_clk_enable(dev->clk_id); - rcc_reset_dev(dev->clk_id); -} - -/** - * Initialize and reset all available GPIO devices. - */ -void gpio_init_all(void) { - gpio_init(GPIOA); - gpio_init(GPIOB); - gpio_init(GPIOC); - gpio_init(GPIOD); - -#ifdef STM32_HIGH_DENSITY - gpio_init(GPIOE); - gpio_init(GPIOF); - gpio_init(GPIOG); -#endif - -#ifdef ARDUINO_STM32F4_NETDUINO2PLUS - // PA8 Output the Master Clock MCO1 - gpio_set_af_mode(GPIOA, 8, 0); - gpio_set_mode(GPIOA, 8, GPIO_MODE_AF | GPIO_OTYPE_PP | GPIO_OSPEED_100MHZ); - // PB4 as alternate MISO Input - gpio_set_af_mode(GPIOB, 4, 5); - // PA5 as alternate SCK Output - gpio_set_af_mode(GPIOA, 5, 5); - // PA7 as alternate MOSI Output - gpio_set_af_mode(GPIOA, 7, 5); -#endif -} - -/** - * Set the mode of a GPIO pin. - * - * @param dev GPIO device. - * @param pin Pin on the device whose mode to set, 0--15. - * @param mode General purpose or alternate function mode to set the pin to. - * @see gpio_pin_mode - */ -void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode) { - gpio_reg_map *regs = dev->regs; - - //regs->AFR[pin/8] = (regs->AFR[pin/8] & ~(15 << (4*(pin&7)))) | (((mode >> 8) & 15) << (4*(pin&7))); - //gpio_set_af_mode(dev, pin, mode>>8); - - regs->MODER = (regs->MODER & ~( 3 << (2*pin))) | (((mode >> 0) & 3) << (2*pin)); - regs->PUPDR = (regs->PUPDR & ~( 3 << (2*pin))) | (((mode >> 2) & 3) << (2*pin)); - regs->OSPEEDR = (regs->OSPEEDR & ~( 3 << (2*pin))) | (((mode >> 4) & 3) << (2*pin)); - regs->OTYPER = (regs->OTYPER & ~( 1 << (1*pin))) | (((mode >> 6) & 1) << (1*pin)); -} - -/** - * Set the alternate function mode of a GPIO pin. - * - * @param dev GPIO device. - * @param pin Pin on the device whose mode to set, 0--15. - * @param mode alternate function mode to set the pin to. - * @see gpio_pin_mode - */ -void gpio_set_af_mode(gpio_dev *dev, uint8 pin, int mode) { - gpio_reg_map *regs = dev->regs; - - regs->AFR[pin/8] = (regs->AFR[pin/8] & ~(15 << (4*(pin&7)))) | (((mode >> 0) & 15) << (4*(pin&7))); -} - -/* - * AFIO - */ - -/** - * @brief Initialize the AFIO clock, and reset the AFIO registers. - */ -void afio_init(void) { - //rcc_clk_enable(RCC_AFIO); - //rcc_reset_dev(RCC_AFIO); -} - -#define AFIO_EXTI_SEL_MASK 0xF - -/** - * @brief Select a source input for an external interrupt. - * - * @param exti External interrupt. - * @param gpio_port Port which contains pin to use as source input. - * @see afio_exti_num - * @see afio_exti_port - */ -void afio_exti_select(afio_exti_num exti, afio_exti_port gpio_port) { - __io uint32 *exti_cr = &SYSCFG_BASE->EXTICR1 + exti / 4; - uint32 shift = 4 * (exti % 4); - uint32 cr = *exti_cr; - - cr &= ~(AFIO_EXTI_SEL_MASK << shift); - cr |= gpio_port << shift; - *exti_cr = cr; -} - -/** - * @brief Perform an alternate function remap. - * @param remapping Remapping to perform. - */ -#if 0 -void afio_remap(afio_remap_peripheral remapping) { - if (remapping & AFIO_REMAP_USE_MAPR2) { - remapping &= ~AFIO_REMAP_USE_MAPR2; - AFIO_BASE->MAPR2 |= remapping; - } else { - AFIO_BASE->MAPR |= remapping; - } -} -#endif - -#endif diff --git a/STM32F4/cores/maple/libmaple/gpioF2.h b/STM32F4/cores/maple/libmaple/gpioF2.h deleted file mode 100644 index 91bd67b..0000000 --- a/STM32F4/cores/maple/libmaple/gpioF2.h +++ /dev/null @@ -1,550 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -*****************************************************************************/ - -/** - * @file gpio.h - * - * @brief General purpose I/O (GPIO) and Alternate Function I/O - * (AFIO) prototypes, defines, and inlined access functions. - */ - -#ifndef _GPIO_H_ -#define _GPIO_H_ - -#include "libmaple.h" -#include "rcc.h" - -#ifdef __cplusplus -extern "C"{ -#endif - -/* - * GPIO register maps and devices - */ - -/** GPIO register map type */ -typedef struct gpio_reg_map { - __io uint32 MODER; /*!< GPIO port mode register, Address offset: 0x00 */ - __io uint32 OTYPER; /*!< GPIO port output type register, Address offset: 0x04 */ - __io uint32 OSPEEDR; /*!< GPIO port output speed register, Address offset: 0x08 */ - __io uint32 PUPDR; /*!< GPIO port pull-up/pull-down register, Address offset: 0x0C */ - __io uint32 IDR; /*!< GPIO port input data register, Address offset: 0x10 */ - __io uint32 ODR; /*!< GPIO port output data register, Address offset: 0x14 */ - __io uint16 BSRRL; /*!< GPIO port bit set/reset low register, Address offset: 0x18 */ - __io uint16 BSRRH; /*!< GPIO port bit set/reset high register, Address offset: 0x1A */ - __io uint32 LCKR; /*!< GPIO port configuration lock register, Address offset: 0x1C */ - __io uint32 AFR[2]; /*!< GPIO alternate function registers, Address offset: 0x24-0x28 */ -} gpio_reg_map; - - - -/** - * @brief External interrupt line port selector. - * - * Used to determine which GPIO port to map an external interrupt line - * onto. */ -/* (See AFIO sections, below) */ -typedef enum afio_exti_port { - AFIO_EXTI_PA, /**< Use port A (PAx) pin. */ - AFIO_EXTI_PB, /**< Use port B (PBx) pin. */ - AFIO_EXTI_PC, /**< Use port C (PCx) pin. */ - AFIO_EXTI_PD, /**< Use port D (PDx) pin. */ -#ifdef STM32_HIGH_DENSITY - AFIO_EXTI_PE, /**< Use port E (PEx) pin. */ - AFIO_EXTI_PF, /**< Use port F (PFx) pin. */ - AFIO_EXTI_PG, /**< Use port G (PGx) pin. */ -#endif -} afio_exti_port; - -/** GPIO device type */ -typedef struct gpio_dev { - gpio_reg_map *regs; /**< Register map */ - rcc_clk_id clk_id; /**< RCC clock information */ - afio_exti_port exti_port; /**< AFIO external interrupt port value */ -} gpio_dev; - -extern gpio_dev gpioa; -extern gpio_dev* const GPIOA; -extern gpio_dev gpiob; -extern gpio_dev* const GPIOB; -extern gpio_dev gpioc; -extern gpio_dev* const GPIOC; -extern gpio_dev gpiod; -extern gpio_dev* const GPIOD; -#ifdef STM32_HIGH_DENSITY -extern gpio_dev gpioe; -extern gpio_dev* const GPIOE; -extern gpio_dev gpiof; -extern gpio_dev* const GPIOF; -extern gpio_dev gpiog; -extern gpio_dev* const GPIOG; -#endif - -/** GPIO port register map base pointer */ -#define GPIOA_BASE ((struct gpio_reg_map*)0x40020000) -#define GPIOB_BASE ((struct gpio_reg_map*)0x40020400) -#define GPIOC_BASE ((struct gpio_reg_map*)0x40020800) -#define GPIOD_BASE ((struct gpio_reg_map*)0x40020C00) -#ifdef STM32_HIGH_DENSITY -#define GPIOE_BASE ((struct gpio_reg_map*)0x40021000) -#define GPIOF_BASE ((struct gpio_reg_map*)0x40021400) -#define GPIOG_BASE ((struct gpio_reg_map*)0x40021800) -#endif - -/* - * GPIO register bit definitions - */ - -#define GPIO_MODE_INPUT 0 -#define GPIO_MODE_OUTPUT 1 -#define GPIO_MODE_AF 2 -#define GPIO_MODE_ANALOG 3 - -#define GPIO_PUPD_INPUT_FLOATING (0 << 2) -#define GPIO_PUPD_INPUT_PU (1 << 2) -#define GPIO_PUPD_INPUT_PD (2 << 2) - -#define GPIO_OSPEED_2MHZ (0 << 4) -#define GPIO_OSPEED_25MHZ (1 << 4) -#define GPIO_OSPEED_50MHZ (2 << 4) -#define GPIO_OSPEED_100MHZ (3 << 4) - -#define GPIO_OTYPE_PP (0 << 6) -#define GPIO_OTYPE_OD (1 << 6) - -/* -MODER -00: Input (reset state) -01: General purpose output mode -10: Alternate function mode -11: Analog mode - -OTYPER -0: Output push-pull (reset state) -1: Output open-drain - -OSPEEDR -00: 2 MHz Low speed -01: 25 MHz Medium speed -10: 50 MHz Fast speed -11: 100 MHz High speed on 30 pF (80 MHz Output max speed on 15 pF) - -PUPDR -00: No pull-up, pull-down -01: Pull-up -10: Pull-down - -AFRL 4 bit AF00-AF15 -AFRH 4 bit AF00-AF15 -*/ - -/** - * @brief GPIO Pin modes. - * - * These only allow for 50MHZ max output speeds; if you want slower, - * use direct register access. - */ -typedef enum gpio_pin_mode { - GPIO_OUTPUT_PP = (GPIO_MODE_OUTPUT | GPIO_OTYPE_PP | - GPIO_OSPEED_50MHZ), /**< Output push-pull. */ - GPIO_OUTPUT_OD = (GPIO_MODE_OUTPUT | GPIO_OTYPE_OD | - GPIO_OSPEED_50MHZ), /**< Output open-drain. */ - GPIO_AF_OUTPUT_PP = (GPIO_MODE_AF | GPIO_OTYPE_PP | - GPIO_OSPEED_50MHZ), /**< Alternate function - output push-pull. */ - GPIO_AF_OUTPUT_OD = (GPIO_MODE_AF | GPIO_OTYPE_OD | - GPIO_OSPEED_50MHZ), /**< Alternate function - output open drain. */ - GPIO_INPUT_ANALOG = (GPIO_MODE_ANALOG), /**< Analog input. */ - GPIO_INPUT_FLOATING = (GPIO_MODE_INPUT | - GPIO_PUPD_INPUT_FLOATING), /**< Input floating. */ - GPIO_INPUT_PD = (GPIO_MODE_INPUT | - GPIO_PUPD_INPUT_PD), /**< Input pull-down. */ - GPIO_INPUT_PU = (GPIO_MODE_INPUT | - GPIO_PUPD_INPUT_PU), /**< Input pull-up. */ - GPIO_AF_INPUT_PD = (GPIO_MODE_AF | - GPIO_PUPD_INPUT_PD), /**< Input pull-down. */ - GPIO_BIGNUMBER = 0xfff -} gpio_pin_mode; - -/* - * GPIO Convenience routines - */ - -void gpio_init(gpio_dev *dev); -void gpio_init_all(void); -void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode); -void gpio_set_af_mode(gpio_dev *dev, uint8 pin, int mode); - -/** - * @brief Get a GPIO port's corresponding afio_exti_port. - * @param dev GPIO device whose afio_exti_port to return. - */ -static inline afio_exti_port gpio_exti_port(gpio_dev *dev) { - return dev->exti_port; -} - -/** - * Set or reset a GPIO pin. - * - * Pin must have previously been configured to output mode. - * - * @param dev GPIO device whose pin to set. - * @param pin Pin on to set or reset - * @param val If true, set the pin. If false, reset the pin. - */ -static inline void gpio_write_bit(gpio_dev *dev, uint8 pin, uint8 val) { - if (val) { - dev->regs->BSRRL = BIT(pin); - } else { - dev->regs->BSRRH = BIT(pin); - } -} - -/** - * Determine whether or not a GPIO pin is set. - * - * Pin must have previously been configured to input mode. - * - * @param dev GPIO device whose pin to test. - * @param pin Pin on dev to test. - * @return True if the pin is set, false otherwise. - */ -static inline uint32 gpio_read_bit(gpio_dev *dev, uint8 pin) { - return dev->regs->IDR & BIT(pin); -} - -/** - * Toggle a pin configured as output push-pull. - * @param dev GPIO device. - * @param pin Pin on dev to toggle. - */ -static inline void gpio_toggle_bit(gpio_dev *dev, uint8 pin) { - dev->regs->ODR = dev->regs->ODR ^ BIT(pin); -} - -/* - * AFIO register map - */ - -/** AFIO register map */ -typedef struct syscfg_reg_map { - __io uint32 MEMRM; /**< memory remap register */ - __io uint32 PMC; /**< peripheral mode configuration register */ - __io uint32 EXTICR1; /**< External interrupt configuration register 1. */ - __io uint32 EXTICR2; /**< External interrupt configuration register 2. */ - __io uint32 EXTICR3; /**< External interrupt configuration register 3. */ - __io uint32 EXTICR4; /**< External interrupt configuration register 4. */ - __io uint32 CMPCR; /**< Compensation cell control register */ -} syscfg_reg_map; - -/** AFIO register map base pointer. */ -#define SYSCFG_BASE ((struct syscfg_reg_map *)0x40013800) - -/* - * AFIO register bit definitions - */ - -/* Event control register */ - -#define AFIO_EVCR_EVOE (0x1 << 7) -#define AFIO_EVCR_PORT_PA (0x0 << 4) -#define AFIO_EVCR_PORT_PB (0x1 << 4) -#define AFIO_EVCR_PORT_PC (0x2 << 4) -#define AFIO_EVCR_PORT_PD (0x3 << 4) -#define AFIO_EVCR_PORT_PE (0x4 << 4) -#define AFIO_EVCR_PIN_0 0x0 -#define AFIO_EVCR_PIN_1 0x1 -#define AFIO_EVCR_PIN_2 0x2 -#define AFIO_EVCR_PIN_3 0x3 -#define AFIO_EVCR_PIN_4 0x4 -#define AFIO_EVCR_PIN_5 0x5 -#define AFIO_EVCR_PIN_6 0x6 -#define AFIO_EVCR_PIN_7 0x7 -#define AFIO_EVCR_PIN_8 0x8 -#define AFIO_EVCR_PIN_9 0x9 -#define AFIO_EVCR_PIN_10 0xA -#define AFIO_EVCR_PIN_11 0xB -#define AFIO_EVCR_PIN_12 0xC -#define AFIO_EVCR_PIN_13 0xD -#define AFIO_EVCR_PIN_14 0xE -#define AFIO_EVCR_PIN_15 0xF - -/* AF remap and debug I/O configuration register */ - -#define AFIO_MAPR_SWJ_CFG (0x7 << 24) -#define AFIO_MAPR_SWJ_CFG_FULL_SWJ (0x0 << 24) -#define AFIO_MAPR_SWJ_CFG_FULL_SWJ_NO_NJRST (0x1 << 24) -#define AFIO_MAPR_SWJ_CFG_NO_JTAG_SW (0x2 << 24) -#define AFIO_MAPR_SWJ_CFG_NO_JTAG_NO_SW (0x4 << 24) -#define AFIO_MAPR_ADC2_ETRGREG_REMAP BIT(20) -#define AFIO_MAPR_ADC2_ETRGINJ_REMAP BIT(19) -#define AFIO_MAPR_ADC1_ETRGREG_REMAP BIT(18) -#define AFIO_MAPR_ADC1_ETRGINJ_REMAP BIT(17) -#define AFIO_MAPR_TIM5CH4_IREMAP BIT(16) -#define AFIO_MAPR_PD01_REMAP BIT(15) -#define AFIO_MAPR_CAN_REMAP (0x3 << 13) -#define AFIO_MAPR_CAN_REMAP_NONE (0x0 << 13) -#define AFIO_MAPR_CAN_REMAP_PB8_PB9 (0x2 << 13) -#define AFIO_MAPR_CAN_REMAP_PD0_PD1 (0x3 << 13) -#define AFIO_MAPR_TIM4_REMAP BIT(12) -#define AFIO_MAPR_TIM3_REMAP (0x3 << 10) -#define AFIO_MAPR_TIM3_REMAP_NONE (0x0 << 10) -#define AFIO_MAPR_TIM3_REMAP_PARTIAL (0x2 << 10) -#define AFIO_MAPR_TIM3_REMAP_FULL (0x3 << 10) -#define AFIO_MAPR_TIM2_REMAP (0x3 << 8) -#define AFIO_MAPR_TIM2_REMAP_NONE (0x0 << 8) -#define AFIO_MAPR_TIM2_REMAP_PA15_PB3_PA2_PA3 (0x1 << 8) -#define AFIO_MAPR_TIM2_REMAP_PA0_PA1_PB10_PB11 (0x2 << 8) -#define AFIO_MAPR_TIM2_REMAP_FULL (0x3 << 8) -#define AFIO_MAPR_TIM1_REMAP (0x3 << 6) -#define AFIO_MAPR_TIM1_REMAP_NONE (0x0 << 6) -#define AFIO_MAPR_TIM1_REMAP_PARTIAL (0x1 << 6) -#define AFIO_MAPR_TIM1_REMAP_FULL (0x3 << 6) -#define AFIO_MAPR_USART3_REMAP (0x3 << 4) -#define AFIO_MAPR_USART3_REMAP_NONE (0x0 << 4) -#define AFIO_MAPR_USART3_REMAP_PARTIAL (0x1 << 4) -#define AFIO_MAPR_USART3_REMAP_FULL (0x3 << 4) -#define AFIO_MAPR_USART2_REMAP BIT(3) -#define AFIO_MAPR_USART1_REMAP BIT(2) -#define AFIO_MAPR_I2C1_REMAP BIT(1) -#define AFIO_MAPR_SPI1_REMAP BIT(0) - -/* External interrupt configuration register 1 */ - -#define AFIO_EXTICR1_EXTI3 (0xF << 12) -#define AFIO_EXTICR1_EXTI3_PA (0x0 << 12) -#define AFIO_EXTICR1_EXTI3_PB (0x1 << 12) -#define AFIO_EXTICR1_EXTI3_PC (0x2 << 12) -#define AFIO_EXTICR1_EXTI3_PD (0x3 << 12) -#define AFIO_EXTICR1_EXTI3_PE (0x4 << 12) -#define AFIO_EXTICR1_EXTI3_PF (0x5 << 12) -#define AFIO_EXTICR1_EXTI3_PG (0x6 << 12) -#define AFIO_EXTICR1_EXTI2 (0xF << 8) -#define AFIO_EXTICR1_EXTI2_PA (0x0 << 8) -#define AFIO_EXTICR1_EXTI2_PB (0x1 << 8) -#define AFIO_EXTICR1_EXTI2_PC (0x2 << 8) -#define AFIO_EXTICR1_EXTI2_PD (0x3 << 8) -#define AFIO_EXTICR1_EXTI2_PE (0x4 << 8) -#define AFIO_EXTICR1_EXTI2_PF (0x5 << 8) -#define AFIO_EXTICR1_EXTI2_PG (0x6 << 8) -#define AFIO_EXTICR1_EXTI1 (0xF << 4) -#define AFIO_EXTICR1_EXTI1_PA (0x0 << 4) -#define AFIO_EXTICR1_EXTI1_PB (0x1 << 4) -#define AFIO_EXTICR1_EXTI1_PC (0x2 << 4) -#define AFIO_EXTICR1_EXTI1_PD (0x3 << 4) -#define AFIO_EXTICR1_EXTI1_PE (0x4 << 4) -#define AFIO_EXTICR1_EXTI1_PF (0x5 << 4) -#define AFIO_EXTICR1_EXTI1_PG (0x6 << 4) -#define AFIO_EXTICR1_EXTI0 0xF -#define AFIO_EXTICR1_EXTI0_PA 0x0 -#define AFIO_EXTICR1_EXTI0_PB 0x1 -#define AFIO_EXTICR1_EXTI0_PC 0x2 -#define AFIO_EXTICR1_EXTI0_PD 0x3 -#define AFIO_EXTICR1_EXTI0_PE 0x4 -#define AFIO_EXTICR1_EXTI0_PF 0x5 -#define AFIO_EXTICR1_EXTI0_PG 0x6 - -/* External interrupt configuration register 2 */ - -#define AFIO_EXTICR2_EXTI7 (0xF << 12) -#define AFIO_EXTICR2_EXTI7_PA (0x0 << 12) -#define AFIO_EXTICR2_EXTI7_PB (0x1 << 12) -#define AFIO_EXTICR2_EXTI7_PC (0x2 << 12) -#define AFIO_EXTICR2_EXTI7_PD (0x3 << 12) -#define AFIO_EXTICR2_EXTI7_PE (0x4 << 12) -#define AFIO_EXTICR2_EXTI7_PF (0x5 << 12) -#define AFIO_EXTICR2_EXTI7_PG (0x6 << 12) -#define AFIO_EXTICR2_EXTI6 (0xF << 8) -#define AFIO_EXTICR2_EXTI6_PA (0x0 << 8) -#define AFIO_EXTICR2_EXTI6_PB (0x1 << 8) -#define AFIO_EXTICR2_EXTI6_PC (0x2 << 8) -#define AFIO_EXTICR2_EXTI6_PD (0x3 << 8) -#define AFIO_EXTICR2_EXTI6_PE (0x4 << 8) -#define AFIO_EXTICR2_EXTI6_PF (0x5 << 8) -#define AFIO_EXTICR2_EXTI6_PG (0x6 << 8) -#define AFIO_EXTICR2_EXTI5 (0xF << 4) -#define AFIO_EXTICR2_EXTI5_PA (0x0 << 4) -#define AFIO_EXTICR2_EXTI5_PB (0x1 << 4) -#define AFIO_EXTICR2_EXTI5_PC (0x2 << 4) -#define AFIO_EXTICR2_EXTI5_PD (0x3 << 4) -#define AFIO_EXTICR2_EXTI5_PE (0x4 << 4) -#define AFIO_EXTICR2_EXTI5_PF (0x5 << 4) -#define AFIO_EXTICR2_EXTI5_PG (0x6 << 4) -#define AFIO_EXTICR2_EXTI4 0xF -#define AFIO_EXTICR2_EXTI4_PA 0x0 -#define AFIO_EXTICR2_EXTI4_PB 0x1 -#define AFIO_EXTICR2_EXTI4_PC 0x2 -#define AFIO_EXTICR2_EXTI4_PD 0x3 -#define AFIO_EXTICR2_EXTI4_PE 0x4 -#define AFIO_EXTICR2_EXTI4_PF 0x5 -#define AFIO_EXTICR2_EXTI4_PG 0x6 - -/* AF remap and debug I/O configuration register 2 */ - -#define AFIO_MAPR2_FSMC_NADV BIT(10) -#define AFIO_MAPR2_TIM14_REMAP BIT(9) -#define AFIO_MAPR2_TIM13_REMAP BIT(8) -#define AFIO_MAPR2_TIM11_REMAP BIT(7) -#define AFIO_MAPR2_TIM10_REMAP BIT(6) -#define AFIO_MAPR2_TIM9_REMAP BIT(5) - -/* - * AFIO convenience routines - */ - -void afio_init(void); - -/** - * External interrupt line numbers. - */ -typedef enum afio_exti_num { - AFIO_EXTI_0, /**< External interrupt line 0. */ - AFIO_EXTI_1, /**< External interrupt line 1. */ - AFIO_EXTI_2, /**< External interrupt line 2. */ - AFIO_EXTI_3, /**< External interrupt line 3. */ - AFIO_EXTI_4, /**< External interrupt line 4. */ - AFIO_EXTI_5, /**< External interrupt line 5. */ - AFIO_EXTI_6, /**< External interrupt line 6. */ - AFIO_EXTI_7, /**< External interrupt line 7. */ - AFIO_EXTI_8, /**< External interrupt line 8. */ - AFIO_EXTI_9, /**< External interrupt line 9. */ - AFIO_EXTI_10, /**< External interrupt line 10. */ - AFIO_EXTI_11, /**< External interrupt line 11. */ - AFIO_EXTI_12, /**< External interrupt line 12. */ - AFIO_EXTI_13, /**< External interrupt line 13. */ - AFIO_EXTI_14, /**< External interrupt line 14. */ - AFIO_EXTI_15, /**< External interrupt line 15. */ -} afio_exti_num; - -void afio_exti_select(afio_exti_num exti, afio_exti_port gpio_port); - -/* HACK: Use upper bit to denote MAPR2, Bit 31 is reserved and - * not used in either MAPR or MAPR2 */ -#define AFIO_REMAP_USE_MAPR2 (1 << 31) - -/** - * @brief Available peripheral remaps. - * @see afio_remap() - */ -typedef enum afio_remap_peripheral { - AFIO_REMAP_ADC2_ETRGREG = AFIO_MAPR_ADC2_ETRGREG_REMAP, /**< - ADC 2 external trigger regular conversion remapping */ - AFIO_REMAP_ADC2_ETRGINJ = AFIO_MAPR_ADC2_ETRGINJ_REMAP, /**< - ADC 2 external trigger injected conversion remapping */ - AFIO_REMAP_ADC1_ETRGREG = AFIO_MAPR_ADC1_ETRGREG_REMAP, /**< - ADC 1 external trigger regular conversion remapping */ - AFIO_REMAP_ADC1_ETRGINJ = AFIO_MAPR_ADC1_ETRGINJ_REMAP, /**< - ADC 1 external trigger injected conversion remapping */ - AFIO_REMAP_TIM5CH4_I = AFIO_MAPR_TIM5CH4_IREMAP, /**< - Timer 5 channel 4 internal remapping */ - AFIO_REMAP_PD01 = AFIO_MAPR_PD01_REMAP, /**< - Port D0/Port D1 mapping on OSC_IN/OSC_OUT */ - AFIO_REMAP_CAN_1 = AFIO_MAPR_CAN_REMAP_PB8_PB9, /**< - CAN alternate function remapping 1 (RX on PB8, TX on PB9) */ - AFIO_REMAP_CAN_2 = AFIO_MAPR_CAN_REMAP_PD0_PD1, /**< - CAN alternate function remapping 2 (RX on PD0, TX on PD1) */ - AFIO_REMAP_TIM4 = AFIO_MAPR_TIM4_REMAP, /**< - Timer 4 remapping */ - AFIO_REMAP_TIM3_PARTIAL = AFIO_MAPR_TIM3_REMAP_PARTIAL, /**< - Timer 3 partial remapping */ - AFIO_REMAP_TIM3_FULL = AFIO_MAPR_TIM3_REMAP_FULL, /**< - Timer 3 full remapping */ - AFIO_REMAP_TIM2_PARTIAL_1 = AFIO_MAPR_TIM2_REMAP_PA15_PB3_PA2_PA3, /**< - Timer 2 partial remapping 1 (CH1 and ETR on PA15, CH2 on PB3, CH3 - on PA2, CH4 on PA3) */ - AFIO_REMAP_TIM2_PARTIAL_2 = AFIO_MAPR_TIM2_REMAP_PA0_PA1_PB10_PB11, /**< - Timer 2 partial remapping 2 (CH1 and ETR on PA0, CH2 on PA1, CH3 - on PB10, CH4 on PB11) */ - AFIO_REMAP_TIM2_FULL = AFIO_MAPR_TIM2_REMAP_FULL, /**< - Timer 2 full remapping */ - AFIO_REMAP_USART2 = AFIO_MAPR_USART2_REMAP, /**< - USART 2 remapping */ - AFIO_REMAP_USART1 = AFIO_MAPR_USART1_REMAP, /**< - USART 1 remapping */ - AFIO_REMAP_I2C1 = AFIO_MAPR_I2C1_REMAP, /**< - I2C 1 remapping */ - AFIO_REMAP_SPI1 = AFIO_MAPR_SPI1_REMAP, /**< - SPI 1 remapping */ - AFIO_REMAP_FSMC_NADV = (AFIO_MAPR2_FSMC_NADV | - AFIO_REMAP_USE_MAPR2), /**< - NADV signal not connected */ - AFIO_REMAP_TIM14 = (AFIO_MAPR2_TIM14_REMAP | - AFIO_REMAP_USE_MAPR2), /**< - Timer 14 remapping */ - AFIO_REMAP_TIM13 = (AFIO_MAPR2_TIM13_REMAP | - AFIO_REMAP_USE_MAPR2), /**< - Timer 13 remapping */ - AFIO_REMAP_TIM11 = (AFIO_MAPR2_TIM11_REMAP | - AFIO_REMAP_USE_MAPR2), /**< - Timer 11 remapping */ - AFIO_REMAP_TIM10 = (AFIO_MAPR2_TIM10_REMAP | - AFIO_REMAP_USE_MAPR2), /**< - Timer 10 remapping */ - AFIO_REMAP_TIM9 = (AFIO_MAPR2_TIM9_REMAP | - AFIO_REMAP_USE_MAPR2) /**< - Timer 9 */ -} afio_remap_peripheral; - -void afio_remap(afio_remap_peripheral p); - -/** - * @brief Debug port configuration - * - * Used to configure the behavior of JTAG and Serial Wire (SW) debug - * ports and their associated GPIO pins. - * - * @see afio_cfg_debug_ports() - */ -typedef enum afio_debug_cfg { - AFIO_DEBUG_FULL_SWJ = AFIO_MAPR_SWJ_CFG_FULL_SWJ, /**< - Full Serial Wire and JTAG debug */ - AFIO_DEBUG_FULL_SWJ_NO_NJRST = AFIO_MAPR_SWJ_CFG_FULL_SWJ_NO_NJRST, /**< - Full Serial Wire and JTAG, but no NJTRST. */ - AFIO_DEBUG_SW_ONLY = AFIO_MAPR_SWJ_CFG_NO_JTAG_SW, /**< - Serial Wire debug only (JTAG-DP disabled, - SW-DP enabled) */ - AFIO_DEBUG_NONE = AFIO_MAPR_SWJ_CFG_NO_JTAG_NO_SW /**< - No debug; all JTAG and SW pins are free - for use as GPIOs. */ -} afio_debug_cfg; - -/** - * @brief Enable or disable the JTAG and SW debug ports. - * @param config Desired debug port configuration - * @see afio_debug_cfg - */ -static inline void afio_cfg_debug_ports(afio_debug_cfg config) { - //__io uint32 *mapr = &AFIO_BASE->MAPR; - //*mapr = (*mapr & ~AFIO_MAPR_SWJ_CFG) | config; -} - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/STM32F4/cores/maple/libmaple/rcc.c b/STM32F4/cores/maple/libmaple/rcc.c deleted file mode 100644 index b3cb9c5..0000000 --- a/STM32F4/cores/maple/libmaple/rcc.c +++ /dev/null @@ -1,37 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file rcc.c - * @brief Implements pretty much only the basic clock setup on the - * stm32, clock enable/disable and peripheral reset commands. - */ - -// #ifdef STM32F2 -// #include "rccF2.c" -// #else -// #include "rccF1.c" -// #endif diff --git a/STM32F4/cores/maple/libmaple/rccF1.c b/STM32F4/cores/maple/libmaple/rccF1.c deleted file mode 100644 index 9eb56b8..0000000 --- a/STM32F4/cores/maple/libmaple/rccF1.c +++ /dev/null @@ -1,233 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - - #ifdef STM32F1 - -/** - * @file rcc.c - * @brief Implements pretty much only the basic clock setup on the - * stm32, clock enable/disable and peripheral reset commands. - */ - -#include "libmaple.h" -#include "flash.h" -#include "rcc.h" -#include "bitband.h" - -#define APB1 RCC_APB1 -#define APB2 RCC_APB2 -#define AHB RCC_AHB - -struct rcc_dev_info { - const rcc_clk_domain clk_domain; - const uint8 line_num; -}; - -/* Device descriptor table, maps rcc_clk_id onto bus and enable/reset - * register bit numbers. */ -static const struct rcc_dev_info rcc_dev_table[] = { - [RCC_GPIOA] = { .clk_domain = APB2, .line_num = 2 }, - [RCC_GPIOB] = { .clk_domain = APB2, .line_num = 3 }, - [RCC_GPIOC] = { .clk_domain = APB2, .line_num = 4 }, - [RCC_GPIOD] = { .clk_domain = APB2, .line_num = 5 }, - [RCC_AFIO] = { .clk_domain = APB2, .line_num = 0 }, - [RCC_ADC1] = { .clk_domain = APB2, .line_num = 9 }, - [RCC_ADC2] = { .clk_domain = APB2, .line_num = 10 }, - [RCC_ADC3] = { .clk_domain = APB2, .line_num = 15 }, - [RCC_USART1] = { .clk_domain = APB2, .line_num = 14 }, - [RCC_USART2] = { .clk_domain = APB1, .line_num = 17 }, - [RCC_USART3] = { .clk_domain = APB1, .line_num = 18 }, - [RCC_TIMER1] = { .clk_domain = APB2, .line_num = 11 }, - [RCC_TIMER2] = { .clk_domain = APB1, .line_num = 0 }, - [RCC_TIMER3] = { .clk_domain = APB1, .line_num = 1 }, - [RCC_TIMER4] = { .clk_domain = APB1, .line_num = 2 }, - [RCC_SPI1] = { .clk_domain = APB2, .line_num = 12 }, - [RCC_SPI2] = { .clk_domain = APB1, .line_num = 14 }, - [RCC_DMA1] = { .clk_domain = AHB, .line_num = 0 }, - [RCC_PWR] = { .clk_domain = APB1, .line_num = 28}, - [RCC_BKP] = { .clk_domain = APB1, .line_num = 27}, - [RCC_I2C1] = { .clk_domain = APB1, .line_num = 21 }, - [RCC_I2C2] = { .clk_domain = APB1, .line_num = 22 }, - [RCC_CRC] = { .clk_domain = AHB, .line_num = 6}, - [RCC_FLITF] = { .clk_domain = AHB, .line_num = 4}, - [RCC_SRAM] = { .clk_domain = AHB, .line_num = 2}, -#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) - [RCC_GPIOE] = { .clk_domain = APB2, .line_num = 6 }, - [RCC_GPIOF] = { .clk_domain = APB2, .line_num = 7 }, - [RCC_GPIOG] = { .clk_domain = APB2, .line_num = 8 }, - [RCC_UART4] = { .clk_domain = APB1, .line_num = 19 }, - [RCC_UART5] = { .clk_domain = APB1, .line_num = 20 }, - [RCC_TIMER5] = { .clk_domain = APB1, .line_num = 3 }, - [RCC_TIMER6] = { .clk_domain = APB1, .line_num = 4 }, - [RCC_TIMER7] = { .clk_domain = APB1, .line_num = 5 }, - [RCC_TIMER8] = { .clk_domain = APB2, .line_num = 13 }, - [RCC_FSMC] = { .clk_domain = AHB, .line_num = 8 }, - [RCC_DAC] = { .clk_domain = APB1, .line_num = 29 }, - [RCC_DMA2] = { .clk_domain = AHB, .line_num = 1 }, - [RCC_SDIO] = { .clk_domain = AHB, .line_num = 10 }, - [RCC_SPI3] = { .clk_domain = APB1, .line_num = 15 }, -#endif -#ifdef STM32_XL_DENSITY - [RCC_TIMER9] = { .clk_domain = APB2, .line_num = 19 }, - [RCC_TIMER10] = { .clk_domain = APB2, .line_num = 20 }, - [RCC_TIMER11] = { .clk_domain = APB2, .line_num = 21 }, - [RCC_TIMER12] = { .clk_domain = APB1, .line_num = 6 }, - [RCC_TIMER13] = { .clk_domain = APB1, .line_num = 7 }, - [RCC_TIMER14] = { .clk_domain = APB1, .line_num = 8 }, -#endif -}; - -/** - * @brief Initialize the clock control system. Initializes the system - * clock source to use the PLL driven by an external oscillator - * @param sysclk_src system clock source, must be PLL - * @param pll_src pll clock source, must be HSE - * @param pll_mul pll multiplier - */ -void rcc_clk_init(rcc_sysclk_src sysclk_src, - rcc_pllsrc pll_src, - rcc_pll_multiplier pll_mul) { - uint32 cfgr = 0; - uint32 cr; - - /* Assume that we're going to clock the chip off the PLL, fed by - * the HSE */ - ASSERT(sysclk_src == RCC_CLKSRC_PLL && - pll_src == RCC_PLLSRC_HSE); - - RCC_BASE->CFGR = pll_src | pll_mul; - - /* Turn on the HSE */ - cr = RCC_BASE->CR; - cr |= RCC_CR_HSEON; - RCC_BASE->CR = cr; - while (!(RCC_BASE->CR & RCC_CR_HSERDY)) - ; - - /* Now the PLL */ - cr |= RCC_CR_PLLON; - RCC_BASE->CR = cr; - while (!(RCC_BASE->CR & RCC_CR_PLLRDY)) - ; - - /* Finally, let's switch over to the PLL */ - cfgr &= ~RCC_CFGR_SW; - cfgr |= RCC_CFGR_SW_PLL; - RCC_BASE->CFGR = cfgr; - while ((RCC_BASE->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) - ; -} - -/** - * @brief Turn on the clock line on a peripheral - * @param id Clock ID of the peripheral to turn on. - */ -void rcc_clk_enable(rcc_clk_id id) { - static const __io uint32* enable_regs[] = { - [APB1] = &RCC_BASE->APB1ENR, - [APB2] = &RCC_BASE->APB2ENR, - [AHB] = &RCC_BASE->AHBENR, - }; - - rcc_clk_domain clk_domain = rcc_dev_clk(id); - __io uint32* enr = (__io uint32*)enable_regs[clk_domain]; - uint8 lnum = rcc_dev_table[id].line_num; - - bb_peri_set_bit(enr, lnum, 1); -} - -/** - * @brief Reset a peripheral. - * @param id Clock ID of the peripheral to reset. - */ -void rcc_reset_dev(rcc_clk_id id) { - static const __io uint32* reset_regs[] = { - [APB1] = &RCC_BASE->APB1RSTR, - [APB2] = &RCC_BASE->APB2RSTR, - }; - - rcc_clk_domain clk_domain = rcc_dev_clk(id); - __io void* addr = (__io void*)reset_regs[clk_domain]; - uint8 lnum = rcc_dev_table[id].line_num; - - bb_peri_set_bit(addr, lnum, 1); - bb_peri_set_bit(addr, lnum, 0); -} - -/** - * @brief Get a peripheral's clock domain - * @param id Clock ID of the peripheral whose clock domain to return - * @return Clock source for the given clock ID - */ -rcc_clk_domain rcc_dev_clk(rcc_clk_id id) { - return rcc_dev_table[id].clk_domain; -} - -/** - * @brief Get a peripheral's clock domain speed - * @param id Clock ID of the peripheral whose clock domain speed to return - * @return Clock speed for the given clock ID - */ -uint32 rcc_dev_clk_speed(rcc_clk_id id) { - static const uint32 rcc_dev_clk_speed_table[] = { - [RCC_AHB] = 72000000, - [RCC_APB1] = 36000000, - [RCC_APB2] = 72000000 - }; - return rcc_dev_clk_speed_table[rcc_dev_clk(id)]; -} - -/** - * @brief Get a peripheral's timer clock domain speed - * @param id Clock ID of the peripheral whose clock domain speed to return - * @return Clock speed for the given clock ID - */ -uint32 rcc_dev_timer_clk_speed(rcc_clk_id id) { - return rcc_dev_clk_speed(RCC_APB2); // 72 MHz for all counter -} - -/** - * @brief Set the divider on a peripheral prescaler - * @param prescaler prescaler to set - * @param divider prescaler divider - */ -void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider) { - static const uint32 masks[] = { - [RCC_PRESCALER_AHB] = RCC_CFGR_HPRE, - [RCC_PRESCALER_APB1] = RCC_CFGR_PPRE1, - [RCC_PRESCALER_APB2] = RCC_CFGR_PPRE2, - [RCC_PRESCALER_USB] = RCC_CFGR_USBPRE, - [RCC_PRESCALER_ADC] = RCC_CFGR_ADCPRE, - }; - - uint32 cfgr = RCC_BASE->CFGR; - cfgr &= ~masks[prescaler]; - cfgr |= divider; - RCC_BASE->CFGR = cfgr; -} - - -#endif diff --git a/STM32F4/cores/maple/libmaple/rccF1.h b/STM32F4/cores/maple/libmaple/rccF1.h deleted file mode 100644 index dd79704..0000000 --- a/STM32F4/cores/maple/libmaple/rccF1.h +++ /dev/null @@ -1,572 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file rcc.h - * @brief reset and clock control definitions and prototypes - */ - -#include "libmaple_types.h" - -#ifndef _RCC_H_ -#define _RCC_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -/** RCC register map type */ -typedef struct rcc_reg_map { - __io uint32 CR; /**< Clock control register */ - __io uint32 CFGR; /**< Clock configuration register */ - __io uint32 CIR; /**< Clock interrupt register */ - __io uint32 APB2RSTR; /**< APB2 peripheral reset register */ - __io uint32 APB1RSTR; /**< APB1 peripheral reset register */ - __io uint32 AHBENR; /**< AHB peripheral clock enable register */ - __io uint32 APB2ENR; /**< APB2 peripheral clock enable register */ - __io uint32 APB1ENR; /**< APB1 peripheral clock enable register */ - __io uint32 BDCR; /**< Backup domain control register */ - __io uint32 CSR; /**< Control/status register */ -} rcc_reg_map; - -/** RCC register map base pointer */ -#define RCC_BASE ((struct rcc_reg_map*)0x40021000) - -/* - * Register bit definitions - */ - -/* Clock control register */ - -#define RCC_CR_PLLRDY_BIT 25 -#define RCC_CR_PLLON_BIT 24 -#define RCC_CR_CSSON_BIT 19 -#define RCC_CR_HSEBYP_BIT 18 -#define RCC_CR_HSERDY_BIT 17 -#define RCC_CR_HSEON_BIT 16 -#define RCC_CR_HSIRDY_BIT 1 -#define RCC_CR_HSION_BIT 0 - -#define RCC_CR_PLLRDY BIT(RCC_CR_PLLRDY_BIT) -#define RCC_CR_PLLON BIT(RCC_CR_PLLON_BIT) -#define RCC_CR_CSSON BIT(RCC_CR_CSSON_BIT) -#define RCC_CR_HSEBYP BIT(RCC_CR_HSEBYP_BIT) -#define RCC_CR_HSERDY BIT(RCC_CR_HSERDY_BIT) -#define RCC_CR_HSEON BIT(RCC_CR_HSEON_BIT) -#define RCC_CR_HSICAL (0xFF << 8) -#define RCC_CR_HSITRIM (0x1F << 3) -#define RCC_CR_HSIRDY BIT(RCC_CR_HSIRDY_BIT) -#define RCC_CR_HSION BIT(RCC_CR_HSION_BIT) - -/* Clock configuration register */ - -#define RCC_CFGR_USBPRE_BIT 22 -#define RCC_CFGR_PLLXTPRE_BIT 17 -#define RCC_CFGR_PLLSRC_BIT 16 - -#define RCC_CFGR_MCO (0x3 << 24) -#define RCC_CFGR_USBPRE BIT(RCC_CFGR_USBPRE_BIT) -#define RCC_CFGR_PLLMUL (0xF << 18) -#define RCC_CFGR_PLLXTPRE BIT(RCC_CFGR_PLLXTPRE_BIT) -#define RCC_CFGR_PLLSRC BIT(RCC_CFGR_PLLSRC_BIT) -#define RCC_CFGR_ADCPRE (0x3 << 14) -#define RCC_CFGR_PPRE2 (0x7 << 11) -#define RCC_CFGR_PPRE1 (0x7 << 8) -#define RCC_CFGR_HPRE (0xF << 4) -#define RCC_CFGR_SWS (0x3 << 2) -#define RCC_CFGR_SWS_PLL (0x2 << 2) -#define RCC_CFGR_SWS_HSE (0x1 << 2) -#define RCC_CFGR_SW 0x3 -#define RCC_CFGR_SW_PLL 0x2 -#define RCC_CFGR_SW_HSE 0x1 - -/* Clock interrupt register */ - -#define RCC_CIR_CSSC_BIT 23 -#define RCC_CIR_PLLRDYC_BIT 20 -#define RCC_CIR_HSERDYC_BIT 19 -#define RCC_CIR_HSIRDYC_BIT 18 -#define RCC_CIR_LSERDYC_BIT 17 -#define RCC_CIR_LSIRDYC_BIT 16 -#define RCC_CIR_PLLRDYIE_BIT 12 -#define RCC_CIR_HSERDYIE_BIT 11 -#define RCC_CIR_HSIRDYIE_BIT 10 -#define RCC_CIR_LSERDYIE_BIT 9 -#define RCC_CIR_LSIRDYIE_BIT 8 -#define RCC_CIR_CSSF_BIT 7 -#define RCC_CIR_PLLRDYF_BIT 4 -#define RCC_CIR_HSERDYF_BIT 3 -#define RCC_CIR_HSIRDYF_BIT 2 -#define RCC_CIR_LSERDYF_BIT 1 -#define RCC_CIR_LSIRDYF_BIT 0 - -#define RCC_CIR_CSSC BIT(RCC_CIR_CSSC_BIT) -#define RCC_CIR_PLLRDYC BIT(RCC_CIR_PLLRDYC_BIT) -#define RCC_CIR_HSERDYC BIT(RCC_CIR_HSERDYC_BIT) -#define RCC_CIR_HSIRDYC BIT(RCC_CIR_HSIRDYC_BIT) -#define RCC_CIR_LSERDYC BIT(RCC_CIR_LSERDYC_BIT) -#define RCC_CIR_LSIRDYC BIT(RCC_CIR_LSIRDYC_BIT) -#define RCC_CIR_PLLRDYIE BIT(RCC_CIR_PLLRDYIE_BIT) -#define RCC_CIR_HSERDYIE BIT(RCC_CIR_HSERDYIE_BIT) -#define RCC_CIR_HSIRDYIE BIT(RCC_CIR_HSIRDYIE_BIT) -#define RCC_CIR_LSERDYIE BIT(RCC_CIR_LSERDYIE_BIT) -#define RCC_CIR_LSIRDYIE BIT(RCC_CIR_LSIRDYIE_BIT) -#define RCC_CIR_CSSF BIT(RCC_CIR_CSSF_BIT) -#define RCC_CIR_PLLRDYF BIT(RCC_CIR_PLLRDYF_BIT) -#define RCC_CIR_HSERDYF BIT(RCC_CIR_HSERDYF_BIT) -#define RCC_CIR_HSIRDYF BIT(RCC_CIR_HSIRDYF_BIT) -#define RCC_CIR_LSERDYF BIT(RCC_CIR_LSERDYF_BIT) -#define RCC_CIR_LSIRDYF BIT(RCC_CIR_LSIRDYF_BIT) - -/* APB2 peripheral reset register */ - -#define RCC_APB2RSTR_TIM11RST_BIT 21 -#define RCC_APB2RSTR_TIM10RST_BIT 20 -#define RCC_APB2RSTR_TIM9RST_BIT 19 -#define RCC_APB2RSTR_ADC3RST_BIT 15 -#define RCC_APB2RSTR_USART1RST_BIT 14 -#define RCC_APB2RSTR_TIM8RST_BIT 13 -#define RCC_APB2RSTR_SPI1RST_BIT 12 -#define RCC_APB2RSTR_TIM1RST_BIT 11 -#define RCC_APB2RSTR_ADC2RST_BIT 10 -#define RCC_APB2RSTR_ADC1RST_BIT 9 -#define RCC_APB2RSTR_IOPGRST_BIT 8 -#define RCC_APB2RSTR_IOPFRST_BIT 7 -#define RCC_APB2RSTR_IOPERST_BIT 6 -#define RCC_APB2RSTR_IOPDRST_BIT 5 -#define RCC_APB2RSTR_IOPCRST_BIT 4 -#define RCC_APB2RSTR_IOPBRST_BIT 3 -#define RCC_APB2RSTR_IOPARST_BIT 2 -#define RCC_APB2RSTR_AFIORST_BIT 0 - -#define RCC_APB2RSTR_TIM11RST BIT(RCC_APB2RSTR_TIM11RST_BIT) -#define RCC_APB2RSTR_TIM10RST BIT(RCC_APB2RSTR_TIM10RST_BIT) -#define RCC_APB2RSTR_TIM9RST BIT(RCC_APB2RSTR_TIM9RST_BIT) -#define RCC_APB2RSTR_ADC3RST BIT(RCC_APB2RSTR_ADC3RST_BIT) -#define RCC_APB2RSTR_USART1RST BIT(RCC_APB2RSTR_USART1RST_BIT) -#define RCC_APB2RSTR_TIM8RST BIT(RCC_APB2RSTR_TIM8RST_BIT) -#define RCC_APB2RSTR_SPI1RST BIT(RCC_APB2RSTR_SPI1RST_BIT) -#define RCC_APB2RSTR_TIM1RST BIT(RCC_APB2RSTR_TIM1RST_BIT) -#define RCC_APB2RSTR_ADC2RST BIT(RCC_APB2RSTR_ADC2RST_BIT) -#define RCC_APB2RSTR_ADC1RST BIT(RCC_APB2RSTR_ADC1RST_BIT) -#define RCC_APB2RSTR_IOPGRST BIT(RCC_APB2RSTR_IOPGRST_BIT) -#define RCC_APB2RSTR_IOPFRST BIT(RCC_APB2RSTR_IOPFRST_BIT) -#define RCC_APB2RSTR_IOPERST BIT(RCC_APB2RSTR_IOPERST_BIT) -#define RCC_APB2RSTR_IOPDRST BIT(RCC_APB2RSTR_IOPDRST_BIT) -#define RCC_APB2RSTR_IOPCRST BIT(RCC_APB2RSTR_IOPCRST_BIT) -#define RCC_APB2RSTR_IOPBRST BIT(RCC_APB2RSTR_IOPBRST_BIT) -#define RCC_APB2RSTR_IOPARST BIT(RCC_APB2RSTR_IOPARST_BIT) -#define RCC_APB2RSTR_AFIORST BIT(RCC_APB2RSTR_AFIORST_BIT) - -/* APB1 peripheral reset register */ - -#define RCC_APB1RSTR_DACRST_BIT 29 -#define RCC_APB1RSTR_PWRRST_BIT 28 -#define RCC_APB1RSTR_BKPRST_BIT 27 -#define RCC_APB1RSTR_CANRST_BIT 25 -#define RCC_APB1RSTR_USBRST_BIT 23 -#define RCC_APB1RSTR_I2C2RST_BIT 22 -#define RCC_APB1RSTR_I2C1RST_BIT 21 -#define RCC_APB1RSTR_UART5RST_BIT 20 -#define RCC_APB1RSTR_UART4RST_BIT 19 -#define RCC_APB1RSTR_USART3RST_BIT 18 -#define RCC_APB1RSTR_USART2RST_BIT 17 -#define RCC_APB1RSTR_SPI3RST_BIT 15 -#define RCC_APB1RSTR_SPI2RST_BIT 14 -#define RCC_APB1RSTR_WWDRST_BIT 11 -#define RCC_APB1RSTR_TIM14RST_BIT 8 -#define RCC_APB1RSTR_TIM13RST_BIT 7 -#define RCC_APB1RSTR_TIM12RST_BIT 6 -#define RCC_APB1RSTR_TIM7RST_BIT 5 -#define RCC_APB1RSTR_TIM6RST_BIT 4 -#define RCC_APB1RSTR_TIM5RST_BIT 3 -#define RCC_APB1RSTR_TIM4RST_BIT 2 -#define RCC_APB1RSTR_TIM3RST_BIT 1 -#define RCC_APB1RSTR_TIM2RST_BIT 0 - -#define RCC_APB1RSTR_DACRST BIT(RCC_APB1RSTR_DACRST_BIT) -#define RCC_APB1RSTR_PWRRST BIT(RCC_APB1RSTR_PWRRST_BIT) -#define RCC_APB1RSTR_BKPRST BIT(RCC_APB1RSTR_BKPRST_BIT) -#define RCC_APB1RSTR_CANRST BIT(RCC_APB1RSTR_CANRST_BIT) -#define RCC_APB1RSTR_USBRST BIT(RCC_APB1RSTR_USBRST_BIT) -#define RCC_APB1RSTR_I2C2RST BIT(RCC_APB1RSTR_I2C2RST_BIT) -#define RCC_APB1RSTR_I2C1RST BIT(RCC_APB1RSTR_I2C1RST_BIT) -#define RCC_APB1RSTR_UART5RST BIT(RCC_APB1RSTR_UART5RST_BIT) -#define RCC_APB1RSTR_UART4RST BIT(RCC_APB1RSTR_UART4RST_BIT) -#define RCC_APB1RSTR_USART3RST BIT(RCC_APB1RSTR_USART3RST_BIT) -#define RCC_APB1RSTR_USART2RST BIT(RCC_APB1RSTR_USART2RST_BIT) -#define RCC_APB1RSTR_SPI3RST BIT(RCC_APB1RSTR_SPI3RST_BIT) -#define RCC_APB1RSTR_SPI2RST BIT(RCC_APB1RSTR_SPI2RST_BIT) -#define RCC_APB1RSTR_WWDRST BIT(RCC_APB1RSTR_WWDRST_BIT) -#define RCC_APB1RSTR_TIM14RST BIT(RCC_APB1RSTR_TIM14RST_BIT) -#define RCC_APB1RSTR_TIM13RST BIT(RCC_APB1RSTR_TIM13RST_BIT) -#define RCC_APB1RSTR_TIM12RST BIT(RCC_APB1RSTR_TIM12RST_BIT) -#define RCC_APB1RSTR_TIM7RST BIT(RCC_APB1RSTR_TIM7RST_BIT) -#define RCC_APB1RSTR_TIM6RST BIT(RCC_APB1RSTR_TIM6RST_BIT) -#define RCC_APB1RSTR_TIM5RST BIT(RCC_APB1RSTR_TIM5RST_BIT) -#define RCC_APB1RSTR_TIM4RST BIT(RCC_APB1RSTR_TIM4RST_BIT) -#define RCC_APB1RSTR_TIM3RST BIT(RCC_APB1RSTR_TIM3RST_BIT) -#define RCC_APB1RSTR_TIM2RST BIT(RCC_APB1RSTR_TIM2RST_BIT) - -/* AHB peripheral clock enable register */ - -#define RCC_AHBENR_SDIOEN_BIT 10 -#define RCC_AHBENR_FSMCEN_BIT 8 -#define RCC_AHBENR_CRCEN_BIT 7 -#define RCC_AHBENR_FLITFEN_BIT 4 -#define RCC_AHBENR_SRAMEN_BIT 2 -#define RCC_AHBENR_DMA2EN_BIT 1 -#define RCC_AHBENR_DMA1EN_BIT 0 - -#define RCC_AHBENR_SDIOEN BIT(RCC_AHBENR_SDIOEN_BIT) -#define RCC_AHBENR_FSMCEN BIT(RCC_AHBENR_FSMCEN_BIT) -#define RCC_AHBENR_CRCEN BIT(RCC_AHBENR_CRCEN_BIT) -#define RCC_AHBENR_FLITFEN BIT(RCC_AHBENR_FLITFEN_BIT) -#define RCC_AHBENR_SRAMEN BIT(RCC_AHBENR_SRAMEN_BIT) -#define RCC_AHBENR_DMA2EN BIT(RCC_AHBENR_DMA2EN_BIT) -#define RCC_AHBENR_DMA1EN BIT(RCC_AHBENR_DMA1EN_BIT) - -/* APB2 peripheral clock enable register */ - -#define RCC_APB2ENR_TIM11EN_BIT 21 -#define RCC_APB2ENR_TIM10EN_BIT 20 -#define RCC_APB2ENR_TIM9EN_BIT 19 -#define RCC_APB2ENR_ADC3EN_BIT 15 -#define RCC_APB2ENR_USART1EN_BIT 14 -#define RCC_APB2ENR_TIM8EN_BIT 13 -#define RCC_APB2ENR_SPI1EN_BIT 12 -#define RCC_APB2ENR_TIM1EN_BIT 11 -#define RCC_APB2ENR_ADC2EN_BIT 10 -#define RCC_APB2ENR_ADC1EN_BIT 9 -#define RCC_APB2ENR_IOPGEN_BIT 8 -#define RCC_APB2ENR_IOPFEN_BIT 7 -#define RCC_APB2ENR_IOPEEN_BIT 6 -#define RCC_APB2ENR_IOPDEN_BIT 5 -#define RCC_APB2ENR_IOPCEN_BIT 4 -#define RCC_APB2ENR_IOPBEN_BIT 3 -#define RCC_APB2ENR_IOPAEN_BIT 2 -#define RCC_APB2ENR_AFIOEN_BIT 0 - -#define RCC_APB2ENR_TIM11EN BIT(RCC_APB2ENR_TIM11EN_BIT) -#define RCC_APB2ENR_TIM10EN BIT(RCC_APB2ENR_TIM10EN_BIT) -#define RCC_APB2ENR_TIM9EN BIT(RCC_APB2ENR_TIM9EN_BIT) -#define RCC_APB2ENR_ADC3EN BIT(RCC_APB2ENR_ADC3EN_BIT) -#define RCC_APB2ENR_USART1EN BIT(RCC_APB2ENR_USART1EN_BIT) -#define RCC_APB2ENR_TIM8EN BIT(RCC_APB2ENR_TIM8EN_BIT) -#define RCC_APB2ENR_SPI1EN BIT(RCC_APB2ENR_SPI1EN_BIT) -#define RCC_APB2ENR_TIM1EN BIT(RCC_APB2ENR_TIM1EN_BIT) -#define RCC_APB2ENR_ADC2EN BIT(RCC_APB2ENR_ADC2EN_BIT) -#define RCC_APB2ENR_ADC1EN BIT(RCC_APB2ENR_ADC1EN_BIT) -#define RCC_APB2ENR_IOPGEN BIT(RCC_APB2ENR_IOPGEN_BIT) -#define RCC_APB2ENR_IOPFEN BIT(RCC_APB2ENR_IOPFEN_BIT) -#define RCC_APB2ENR_IOPEEN BIT(RCC_APB2ENR_IOPEEN_BIT) -#define RCC_APB2ENR_IOPDEN BIT(RCC_APB2ENR_IOPDEN_BIT) -#define RCC_APB2ENR_IOPCEN BIT(RCC_APB2ENR_IOPCEN_BIT) -#define RCC_APB2ENR_IOPBEN BIT(RCC_APB2ENR_IOPBEN_BIT) -#define RCC_APB2ENR_IOPAEN BIT(RCC_APB2ENR_IOPAEN_BIT) -#define RCC_APB2ENR_AFIOEN BIT(RCC_APB2ENR_AFIOEN_BIT) - -/* APB1 peripheral clock enable register */ - -#define RCC_APB1ENR_DACEN_BIT 29 -#define RCC_APB1ENR_PWREN_BIT 28 -#define RCC_APB1ENR_BKPEN_BIT 27 -#define RCC_APB1ENR_CANEN_BIT 25 -#define RCC_APB1ENR_USBEN_BIT 23 -#define RCC_APB1ENR_I2C2EN_BIT 22 -#define RCC_APB1ENR_I2C1EN_BIT 21 -#define RCC_APB1ENR_UART5EN_BIT 20 -#define RCC_APB1ENR_UART4EN_BIT 19 -#define RCC_APB1ENR_USART3EN_BIT 18 -#define RCC_APB1ENR_USART2EN_BIT 17 -#define RCC_APB1ENR_SPI3EN_BIT 15 -#define RCC_APB1ENR_SPI2EN_BIT 14 -#define RCC_APB1ENR_WWDEN_BIT 11 -#define RCC_APB1ENR_TIM14EN_BIT 8 -#define RCC_APB1ENR_TIM13EN_BIT 7 -#define RCC_APB1ENR_TIM12EN_BIT 6 -#define RCC_APB1ENR_TIM7EN_BIT 5 -#define RCC_APB1ENR_TIM6EN_BIT 4 -#define RCC_APB1ENR_TIM5EN_BIT 3 -#define RCC_APB1ENR_TIM4EN_BIT 2 -#define RCC_APB1ENR_TIM3EN_BIT 1 -#define RCC_APB1ENR_TIM2EN_BIT 0 - -#define RCC_APB1ENR_DACEN BIT(RCC_APB1ENR_DACEN_BIT) -#define RCC_APB1ENR_PWREN BIT(RCC_APB1ENR_PWREN_BIT) -#define RCC_APB1ENR_BKPEN BIT(RCC_APB1ENR_BKPEN_BIT) -#define RCC_APB1ENR_CANEN BIT(RCC_APB1ENR_CANEN_BIT) -#define RCC_APB1ENR_USBEN BIT(RCC_APB1ENR_USBEN_BIT) -#define RCC_APB1ENR_I2C2EN BIT(RCC_APB1ENR_I2C2EN_BIT) -#define RCC_APB1ENR_I2C1EN BIT(RCC_APB1ENR_I2C1EN_BIT) -#define RCC_APB1ENR_UART5EN BIT(RCC_APB1ENR_UART5EN_BIT) -#define RCC_APB1ENR_UART4EN BIT(RCC_APB1ENR_UART4EN_BIT) -#define RCC_APB1ENR_USART3EN BIT(RCC_APB1ENR_USART3EN_BIT) -#define RCC_APB1ENR_USART2EN BIT(RCC_APB1ENR_USART2EN_BIT) -#define RCC_APB1ENR_SPI3EN BIT(RCC_APB1ENR_SPI3EN_BIT) -#define RCC_APB1ENR_SPI2EN BIT(RCC_APB1ENR_SPI2EN_BIT) -#define RCC_APB1ENR_WWDEN BIT(RCC_APB1ENR_WWDEN_BIT) -#define RCC_APB1ENR_TIM14EN BIT(RCC_APB1ENR_TIM14EN_BIT) -#define RCC_APB1ENR_TIM13EN BIT(RCC_APB1ENR_TIM13EN_BIT) -#define RCC_APB1ENR_TIM12EN BIT(RCC_APB1ENR_TIM12EN_BIT) -#define RCC_APB1ENR_TIM7EN BIT(RCC_APB1ENR_TIM7EN_BIT) -#define RCC_APB1ENR_TIM6EN BIT(RCC_APB1ENR_TIM6EN_BIT) -#define RCC_APB1ENR_TIM5EN BIT(RCC_APB1ENR_TIM5EN_BIT) -#define RCC_APB1ENR_TIM4EN BIT(RCC_APB1ENR_TIM4EN_BIT) -#define RCC_APB1ENR_TIM3EN BIT(RCC_APB1ENR_TIM3EN_BIT) -#define RCC_APB1ENR_TIM2EN BIT(RCC_APB1ENR_TIM2EN_BIT) - -/* Backup domain control register */ - -#define RCC_BDCR_BDRST_BIT 16 -#define RCC_BDCR_RTCEN_BIT 15 -#define RCC_BDCR_LSEBYP_BIT 2 -#define RCC_BDCR_LSERDY_BIT 1 -#define RCC_BDCR_LSEON_BIT 0 - -#define RCC_BDCR_BDRST BIT(RCC_BDCR_BDRST_BIT) -#define RCC_BDCR_RTCEN BIT(RCC_BDCR_RTC_BIT) -#define RCC_BDCR_RTCSEL (0x3 << 8) -#define RCC_BDCR_RTCSEL_NONE (0x0 << 8) -#define RCC_BDCR_RTCSEL_LSE (0x1 << 8) -#define RCC_BDCR_RTCSEL_HSE (0x3 << 8) -#define RCC_BDCR_LSEBYP BIT(RCC_BDCR_LSEBYP_BIT) -#define RCC_BDCR_LSERDY BIT(RCC_BDCR_LSERDY_BIT) -#define RCC_BDCR_LSEON BIT(RCC_BDCR_LSEON_BIT) - -/* Control/status register */ - -#define RCC_CSR_LPWRRSTF_BIT 31 -#define RCC_CSR_WWDGRSTF_BIT 30 -#define RCC_CSR_IWDGRSTF_BIT 29 -#define RCC_CSR_SFTRSTF_BIT 28 -#define RCC_CSR_PORRSTF_BIT 27 -#define RCC_CSR_PINRSTF_BIT 26 -#define RCC_CSR_RMVF_BIT 24 -#define RCC_CSR_LSIRDY_BIT 1 -#define RCC_CSR_LSION_BIT 0 - -#define RCC_CSR_LPWRRSTF BIT(RCC_CSR_LPWRRSTF_BIT) -#define RCC_CSR_WWDGRSTF BIT(RCC_CSR_WWDGRSTF_BIT) -#define RCC_CSR_IWDGRSTF BIT(RCC_CSR_IWDGRSTF_BIT) -#define RCC_CSR_SFTRSTF BIT(RCC_CSR_SFTRSTF_BIT) -#define RCC_CSR_PORRSTF BIT(RCC_CSR_PORRSTF_BIT) -#define RCC_CSR_PINRSTF BIT(RCC_CSR_PINRSTF_BIT) -#define RCC_CSR_RMVF BIT(RCC_CSR_RMVF_BIT) -#define RCC_CSR_LSIRDY BIT(RCC_CSR_LSIRDY_BIT) -#define RCC_CSR_LSION BIT(RCC_CSR_LSION_BIT) - -/* - * Convenience routines - */ - -/** - * SYSCLK sources - * @see rcc_clk_init() - */ -typedef enum rcc_sysclk_src { - RCC_CLKSRC_HSI = 0x0, - RCC_CLKSRC_HSE = 0x1, - RCC_CLKSRC_PLL = 0x2, -} rcc_sysclk_src; - -/** - * PLL entry clock source - * @see rcc_clk_init() - */ -typedef enum rcc_pllsrc { - RCC_PLLSRC_HSE = (0x1 << 16), - RCC_PLLSRC_HSI_DIV_2 = (0x0 << 16) -} rcc_pllsrc; - -/** - * PLL multipliers - * @see rcc_clk_init() - */ -typedef enum rcc_pll_multiplier { - RCC_PLLMUL_2 = (0x0 << 18), - RCC_PLLMUL_3 = (0x1 << 18), - RCC_PLLMUL_4 = (0x2 << 18), - RCC_PLLMUL_5 = (0x3 << 18), - RCC_PLLMUL_6 = (0x4 << 18), - RCC_PLLMUL_7 = (0x5 << 18), - RCC_PLLMUL_8 = (0x6 << 18), - RCC_PLLMUL_9 = (0x7 << 18), - RCC_PLLMUL_10 = (0x8 << 18), - RCC_PLLMUL_11 = (0x9 << 18), - RCC_PLLMUL_12 = (0xA << 18), - RCC_PLLMUL_13 = (0xB << 18), - RCC_PLLMUL_14 = (0xC << 18), - RCC_PLLMUL_15 = (0xD << 18), - RCC_PLLMUL_16 = (0xE << 18), -} rcc_pll_multiplier; - -/** - * @brief Identifies bus and clock line for a peripheral. - * - * Also generally useful as a unique identifier for that peripheral - * (or its corresponding device struct). - */ -typedef enum rcc_clk_id { - RCC_GPIOA, - RCC_GPIOB, - RCC_GPIOC, - RCC_GPIOD, - RCC_AFIO, - RCC_ADC1, - RCC_ADC2, - RCC_ADC3, - RCC_USART1, - RCC_USART2, - RCC_USART3, - RCC_TIMER1, - RCC_TIMER2, - RCC_TIMER3, - RCC_TIMER4, - RCC_SPI1, - RCC_SPI2, - RCC_DMA1, - RCC_PWR, - RCC_BKP, - RCC_I2C1, - RCC_I2C2, - RCC_CRC, - RCC_FLITF, - RCC_SRAM, -#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) - RCC_GPIOE, - RCC_GPIOF, - RCC_GPIOG, - RCC_UART4, - RCC_UART5, - RCC_TIMER5, - RCC_TIMER6, - RCC_TIMER7, - RCC_TIMER8, - RCC_FSMC, - RCC_DAC, - RCC_DMA2, - RCC_SDIO, - RCC_SPI3, -#endif -#ifdef STM32_XL_DENSITY - RCC_TIMER9, - RCC_TIMER10, - RCC_TIMER11, - RCC_TIMER12, - RCC_TIMER13, - RCC_TIMER14, -#endif -} rcc_clk_id; - -void rcc_clk_init(rcc_sysclk_src sysclk_src, - rcc_pllsrc pll_src, - rcc_pll_multiplier pll_mul); -void rcc_clk_enable(rcc_clk_id device); -void rcc_reset_dev(rcc_clk_id device); - -typedef enum rcc_clk_domain { - RCC_APB1, - RCC_APB2, - RCC_AHB -} rcc_clk_domain; - -rcc_clk_domain rcc_dev_clk(rcc_clk_id device); - -uint32 rcc_dev_clk_speed(rcc_clk_id id); -uint32 rcc_dev_timer_clk_speed(rcc_clk_id id); - -/** - * Prescaler identifiers - * @see rcc_set_prescaler() - */ -typedef enum rcc_prescaler { - RCC_PRESCALER_AHB, - RCC_PRESCALER_APB1, - RCC_PRESCALER_APB2, - RCC_PRESCALER_USB, - RCC_PRESCALER_ADC -} rcc_prescaler; - -/** - * ADC prescaler dividers - * @see rcc_set_prescaler() - */ -typedef enum rcc_adc_divider { - RCC_ADCPRE_PCLK_DIV_2 = 0x0 << 14, - RCC_ADCPRE_PCLK_DIV_4 = 0x1 << 14, - RCC_ADCPRE_PCLK_DIV_6 = 0x2 << 14, - RCC_ADCPRE_PCLK_DIV_8 = 0x3 << 14, -} rcc_adc_divider; - -/** - * APB1 prescaler dividers - * @see rcc_set_prescaler() - */ -typedef enum rcc_apb1_divider { - RCC_APB1_HCLK_DIV_1 = 0x0 << 8, - RCC_APB1_HCLK_DIV_2 = 0x4 << 8, - RCC_APB1_HCLK_DIV_4 = 0x5 << 8, - RCC_APB1_HCLK_DIV_8 = 0x6 << 8, - RCC_APB1_HCLK_DIV_16 = 0x7 << 8, -} rcc_apb1_divider; - -/** - * APB2 prescaler dividers - * @see rcc_set_prescaler() - */ -typedef enum rcc_apb2_divider { - RCC_APB2_HCLK_DIV_1 = 0x0 << 11, - RCC_APB2_HCLK_DIV_2 = 0x4 << 11, - RCC_APB2_HCLK_DIV_4 = 0x5 << 11, - RCC_APB2_HCLK_DIV_8 = 0x6 << 11, - RCC_APB2_HCLK_DIV_16 = 0x7 << 11, -} rcc_apb2_divider; - -/** - * AHB prescaler dividers - * @see rcc_set_prescaler() - */ -typedef enum rcc_ahb_divider { - RCC_AHB_SYSCLK_DIV_1 = 0x0 << 4, - RCC_AHB_SYSCLK_DIV_2 = 0x8 << 4, - RCC_AHB_SYSCLK_DIV_4 = 0x9 << 4, - RCC_AHB_SYSCLK_DIV_8 = 0xA << 4, - RCC_AHB_SYSCLK_DIV_16 = 0xB << 4, - RCC_AHB_SYSCLK_DIV_32 = 0xC << 4, - RCC_AHB_SYSCLK_DIV_64 = 0xD << 4, - RCC_AHB_SYSCLK_DIV_128 = 0xD << 4, - RCC_AHB_SYSCLK_DIV_256 = 0xE << 4, - RCC_AHB_SYSCLK_DIV_512 = 0xF << 4, -} rcc_ahb_divider; - -void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif diff --git a/STM32F4/cores/maple/libmaple/rccF2.c b/STM32F4/cores/maple/libmaple/rccF2.c deleted file mode 100644 index 691393a..0000000 --- a/STM32F4/cores/maple/libmaple/rccF2.c +++ /dev/null @@ -1,707 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - - #ifdef STM32F2 - -/** - * @file rcc.c - * @brief Implements pretty much only the basic clock setup on the - * stm32, clock enable/disable and peripheral reset commands. - */ - -#include "libmaple.h" -#include "flash.h" -#include "gpio.h" -#include "rcc.h" -#include "bitband.h" - -#define APB1 RCC_APB1 -#define APB2 RCC_APB2 -#define AHB1 RCC_AHB1 -#define AHB2 RCC_AHB2 -#define AHB3 RCC_AHB3 - -struct rcc_dev_info { - const rcc_clk_domain clk_domain; - const uint8 line_num; -}; - -static uint32 rcc_dev_clk_speed_table[AHB3]; - -/* Device descriptor table, maps rcc_clk_id onto bus and enable/reset - * register bit numbers. */ -static const struct rcc_dev_info rcc_dev_table[] = { - [RCC_GPIOA] = { .clk_domain = AHB1, .line_num = 0 }, //* - [RCC_GPIOB] = { .clk_domain = AHB1, .line_num = 1 }, //* - [RCC_GPIOC] = { .clk_domain = AHB1, .line_num = 2 }, //* - [RCC_GPIOD] = { .clk_domain = AHB1, .line_num = 3 }, //* - -// [RCC_AFIO] = { .clk_domain = APB2, .line_num = 0 }, - [RCC_ADC1] = { .clk_domain = APB2, .line_num = 8 }, //* - [RCC_ADC2] = { .clk_domain = APB2, .line_num = 9 }, //* - [RCC_ADC3] = { .clk_domain = APB2, .line_num = 10 }, //* - [RCC_USART1] = { .clk_domain = APB2, .line_num = 4 }, //* - [RCC_USART2] = { .clk_domain = APB1, .line_num = 17 }, //unchanged - [RCC_USART3] = { .clk_domain = APB1, .line_num = 18 }, //unchanged - [RCC_TIMER1] = { .clk_domain = APB2, .line_num = 0 }, //* - [RCC_TIMER2] = { .clk_domain = APB1, .line_num = 0 }, //unchanged - [RCC_TIMER3] = { .clk_domain = APB1, .line_num = 1 }, //unchanged - [RCC_TIMER4] = { .clk_domain = APB1, .line_num = 2 }, //unchanged - [RCC_SPI1] = { .clk_domain = APB2, .line_num = 12 }, //unchanged - [RCC_SPI2] = { .clk_domain = APB1, .line_num = 14 }, //unchanged - [RCC_DMA1] = { .clk_domain = AHB1, .line_num = 21 }, //* - [RCC_PWR] = { .clk_domain = APB1, .line_num = 28}, //unchanged - [RCC_BKP] = { .clk_domain = AHB1, .line_num = 18}, //* - [RCC_I2C1] = { .clk_domain = APB1, .line_num = 21 }, //unchanged - [RCC_I2C2] = { .clk_domain = APB1, .line_num = 22 }, //unchanged - [RCC_CRC] = { .clk_domain = AHB1, .line_num = 12}, //* -// [RCC_FLITF] = { .clk_domain = AHB, .line_num = 4}, -// [RCC_SRAM] = { .clk_domain = AHB, .line_num = 2}, - - [RCC_GPIOE] = { .clk_domain = AHB1, .line_num = 4 }, //* - [RCC_GPIOF] = { .clk_domain = AHB1, .line_num = 5 }, //* - [RCC_GPIOG] = { .clk_domain = AHB1, .line_num = 6 }, //* - [RCC_UART4] = { .clk_domain = APB1, .line_num = 19 }, //unchanged - [RCC_UART5] = { .clk_domain = APB1, .line_num = 20 }, //unchanged - [RCC_TIMER5] = { .clk_domain = APB1, .line_num = 3 }, //unchanged - [RCC_TIMER6] = { .clk_domain = APB1, .line_num = 4 }, //unchanged - [RCC_TIMER7] = { .clk_domain = APB1, .line_num = 5 }, //unchanged - [RCC_TIMER8] = { .clk_domain = APB2, .line_num = 1 }, //* - [RCC_FSMC] = { .clk_domain = AHB3, .line_num = 0 }, //* - [RCC_DAC] = { .clk_domain = APB1, .line_num = 29 }, //unchanged - [RCC_DMA2] = { .clk_domain = AHB1, .line_num = 22 }, //* - [RCC_SDIO] = { .clk_domain = APB2, .line_num = 11 }, //* - [RCC_SPI3] = { .clk_domain = APB1, .line_num = 15 }, //unchanged - [RCC_TIMER9] = { .clk_domain = APB2, .line_num = 16 }, //* - [RCC_TIMER10] = { .clk_domain = APB2, .line_num = 17 }, //* - [RCC_TIMER11] = { .clk_domain = APB2, .line_num = 18 }, //* - [RCC_TIMER12] = { .clk_domain = APB1, .line_num = 6 }, //unchanged - [RCC_TIMER13] = { .clk_domain = APB1, .line_num = 7 }, //unchanged - [RCC_TIMER14] = { .clk_domain = APB1, .line_num = 8 }, //unchanged - [RCC_USBFS] = { .clk_domain = AHB2, .line_num = 7 }, //* - [RCC_SYSCFG] = { .clk_domain = APB2, .line_num = 14 }, //* - [RCC_SPI4] = { .clk_domain = APB1, .line_num = 15 }, -}; - -/** - * @brief Initialize the clock control system. Initializes the system - * clock source to use the PLL driven by an external oscillator - * @param sysclk_src system clock source, must be PLL - * @param pll_src pll clock source, must be HSE - * @param pll_mul pll multiplier - */ - -#define HSE_STARTUP_TIMEOUT ((uint16)0x0500) /*!< Time out for HSE start up */ -#define RCC_CFGR_HPRE_DIV1 ((uint32)0x00000000) /*!< SYSCLK not divided */ -#define RCC_CFGR_PPRE1_DIV2 ((uint32)0x00001000) /*!< HCLK divided by 2 */ -#define RCC_CFGR_PPRE1_DIV4 ((uint32)0x00001400) /*!< HCLK divided by 4 */ -#define RCC_CFGR_PPRE2_DIV1 ((uint32)0x00000000) /*!< HCLK not divided */ -#define RCC_CFGR_PPRE2_DIV2 ((uint32)0x00008000) /*!< HCLK divided by 2 */ - -#define RCC_PLLCFGR_PLLSRC_HSE ((uint32)0x00400000) - -/******************* Bits definition for FLASH_ACR register *****************/ -//#define FLASH_ACR_LATENCY ((uint32_t)0x00000007) -#define FLASH_ACR_LATENCY_0WS ((uint32)0x00000000) -#define FLASH_ACR_LATENCY_1WS ((uint32)0x00000001) -#define FLASH_ACR_LATENCY_2WS ((uint32)0x00000002) -#define FLASH_ACR_LATENCY_3WS ((uint32)0x00000003) -#define FLASH_ACR_LATENCY_4WS ((uint32)0x00000004) -#define FLASH_ACR_LATENCY_5WS ((uint32)0x00000005) -#define FLASH_ACR_LATENCY_6WS ((uint32)0x00000006) -#define FLASH_ACR_LATENCY_7WS ((uint32)0x00000007) - -#define FLASH_ACR_PRFTEN ((uint32)0x00000100) -#define FLASH_ACR_ICEN ((uint32)0x00000200) -#define FLASH_ACR_DCEN ((uint32)0x00000400) -#define FLASH_ACR_ICRST ((uint32)0x00000800) -#define FLASH_ACR_DCRST ((uint32)0x00001000) -#define FLASH_ACR_BYTE0_ADDRESS ((uint32)0x40023C00) -#define FLASH_ACR_BYTE2_ADDRESS ((uint32)0x40023C03) - -typedef struct -{ - __io uint32 CR; /*!< PWR power control register, Address offset: 0x00 */ - __io uint32 CSR; /*!< PWR power control/status register, Address offset: 0x04 */ -} PWR_TypeDef; - -#define PWR_BASE (0x40007000) -#define PWR ((PWR_TypeDef *) PWR_BASE) -#define PWR_CR_VOS ((uint16)0x4000) /*!< Regulator voltage scaling output selection */ - -typedef struct -{ - __io uint32 ACR; /*!< FLASH access control register, Address offset: 0x00 */ - __io uint32 KEYR; /*!< FLASH key register, Address offset: 0x04 */ - __io uint32 OPTKEYR; /*!< FLASH option key register, Address offset: 0x08 */ - __io uint32 SR; /*!< FLASH status register, Address offset: 0x0C */ - __io uint32 CR; /*!< FLASH control register, Address offset: 0x10 */ - __io uint32 OPTCR; /*!< FLASH option control register, Address offset: 0x14 */ -} FLASH_TypeDef; - -#define FLASH_R_BASE (0x40023C00) -#define FLASH ((FLASH_TypeDef *) FLASH_R_BASE) -#define RESET 0 - -typedef uint32 uint32_t; - -void InitMCO1() -{ - rcc_reg_map *RCC = RCC_BASE; - // Turn MCO1 Master Clock Output mode - RCC->CFGR &= RCC_CFGR_MCO1_RESET_MASK; - RCC->CFGR |= RCC_CFGR_MCO1Source_HSE | RCC_CFGR_MCO1Div_1; - // PA8 Output the Master Clock MCO1 - gpio_set_af_mode(GPIOA, 8, 0); - gpio_set_mode(GPIOA, 8, GPIO_MODE_AF | GPIO_OTYPE_PP | GPIO_OSPEED_100MHZ); -} - - -void SetupClock72MHz() -{ - uint32_t SystemCoreClock = 72000000; - - /******************************************************************************/ - /* PLL (clocked by HSE) used as System clock source */ - /******************************************************************************/ - /************************* PLL Parameters *************************************/ - /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */ - int PLL_M = 4; - int PLL_N = 216; - - /* SYSCLK = PLL_VCO / PLL_P */ - int PLL_P = 6; - - /* USB OTG FS, SDIO and RNG Clock = PLL_VCO / PLLQ */ - int PLL_Q = 9; - - - uint32 StartUpCounter = 0, HSEStatus = 0; - rcc_reg_map *RCC = RCC_BASE; - - /* Enable HSE */ - RCC->CR |= ((uint32_t)RCC_CR_HSEON); - - /* Wait till HSE is ready and if Time out is reached exit */ - do - { - HSEStatus = RCC->CR & RCC_CR_HSERDY; - StartUpCounter++; - } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); - - if ((RCC->CR & RCC_CR_HSERDY) != RESET) - { - HSEStatus = (uint32_t)0x01; - } - else - { - HSEStatus = (uint32_t)0x00; - } - - if (HSEStatus == (uint32_t)0x01) - { - /* Select regulator voltage output Scale 2 mode, System frequency up to 144 MHz */ - RCC->APB1ENR |= RCC_APB1ENR_PWREN; - PWR->CR &= (uint32_t)~(PWR_CR_VOS); - - /* HCLK = SYSCLK / 1*/ - RCC->CFGR |= RCC_CFGR_HPRE_DIV1; - - /* PCLK2 = HCLK / 1*/ - RCC->CFGR |= RCC_CFGR_PPRE2_DIV1; - - /* PCLK1 = HCLK / 2*/ - RCC->CFGR |= RCC_CFGR_PPRE1_DIV2; - - // save bus clock values - rcc_dev_clk_speed_table[RCC_AHB1] = (SystemCoreClock/1); - rcc_dev_clk_speed_table[RCC_APB2] = (SystemCoreClock/1); - rcc_dev_clk_speed_table[RCC_APB1] = (SystemCoreClock/2); - - /* Configure the main PLL */ - RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) | - (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24); - - /* Enable the main PLL */ - RCC->CR |= RCC_CR_PLLON; - - /* Wait till the main PLL is ready */ - while((RCC->CR & RCC_CR_PLLRDY) == 0) - { - } - - /* Configure Flash prefetch, Instruction cache, Data cache and wait state */ - FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_2WS; - - /* Select the main PLL as system clock source */ - RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); - RCC->CFGR |= RCC_CFGR_SW_PLL; - - /* Wait till the main PLL is used as system clock source */ - while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL); - { - } - } - else - { /* If HSE fails to start-up, the application will have wrong clock - configuration. User can add here some code to deal with this error */ - } -} - - -void SetupClock120MHz() -{ - uint32_t SystemCoreClock = 120000000; - - /******************************************************************************/ - /* PLL (clocked by HSE) used as System clock source */ - /******************************************************************************/ - /************************* PLL Parameters *************************************/ - /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */ - int PLL_M = 8; - int PLL_N = 240; - - /* SYSCLK = PLL_VCO / PLL_P */ - int PLL_P = 2; - - /* USB OTG FS, SDIO and RNG Clock = PLL_VCO / PLLQ */ - int PLL_Q = 5; - - - uint32 StartUpCounter = 0, HSEStatus = 0; - rcc_reg_map *RCC = RCC_BASE; - - /* Enable HSE */ - RCC->CR |= ((uint32_t)RCC_CR_HSEON); - - /* Wait till HSE is ready and if Time out is reached exit */ - do - { - HSEStatus = RCC->CR & RCC_CR_HSERDY; - StartUpCounter++; - } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); - - if ((RCC->CR & RCC_CR_HSERDY) != RESET) - { - HSEStatus = (uint32_t)0x01; - } - else - { - HSEStatus = (uint32_t)0x00; - } - - if (HSEStatus == (uint32_t)0x01) - { - /* Select regulator voltage output Scale 2 mode, System frequency up to 144 MHz */ - RCC->APB1ENR |= RCC_APB1ENR_PWREN; - PWR->CR &= (uint32_t)~(PWR_CR_VOS); - - /* HCLK = SYSCLK / 1*/ - RCC->CFGR |= RCC_CFGR_HPRE_DIV1; - - /* PCLK2 = HCLK / 2*/ - RCC->CFGR |= RCC_CFGR_PPRE2_DIV2; - - /* PCLK1 = HCLK / 4*/ - RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; - - // save bus clock values - rcc_dev_clk_speed_table[RCC_AHB1] = (SystemCoreClock/1); - rcc_dev_clk_speed_table[RCC_APB2] = (SystemCoreClock/2); - rcc_dev_clk_speed_table[RCC_APB1] = (SystemCoreClock/4); - - /* Configure the main PLL */ - RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) | - (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24); - - /* Enable the main PLL */ - RCC->CR |= RCC_CR_PLLON; - - /* Wait till the main PLL is ready */ - while((RCC->CR & RCC_CR_PLLRDY) == 0) - { - } - - /* Configure Flash prefetch, Instruction cache, Data cache and wait state */ - FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_3WS; - - /* Select the main PLL as system clock source */ - RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); - RCC->CFGR |= RCC_CFGR_SW_PLL; - - /* Wait till the main PLL is used as system clock source */ - while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL); - { - } - } - else - { /* If HSE fails to start-up, the application will have wrong clock - configuration. User can add here some code to deal with this error */ - } -} - - -void SetupClock168MHz() -{ - uint32_t SystemCoreClock = 168000000; - - /******************************************************************************/ - /* PLL (clocked by HSE) used as System clock source */ - /******************************************************************************/ - /************************* PLL Parameters *************************************/ - /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */ -#ifdef ARDUINO_STM32F4_NETDUINO2PLUS - int PLL_M = 25; // The NETDUINO has a 25MHz external oscillator -#else - int PLL_M = 8; -#endif - int PLL_N = 336; - - /* SYSCLK = PLL_VCO / PLL_P */ - int PLL_P = 2; - - /* USB OTG FS, SDIO and RNG Clock = PLL_VCO / PLLQ */ - int PLL_Q = 7; - - - uint32 StartUpCounter = 0, HSEStatus = 0; - rcc_reg_map *RCC = RCC_BASE; - -#ifdef ARDUINO_STM32F4_NETDUINO2PLUS - InitMCO1(); -#endif - - /* Enable HSE */ - RCC->CR |= ((uint32_t)RCC_CR_HSEON); - - /* Wait till HSE is ready and if Time out is reached exit */ - do - { - HSEStatus = RCC->CR & RCC_CR_HSERDY; - StartUpCounter++; - } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); - - if ((RCC->CR & RCC_CR_HSERDY) != RESET) - { - HSEStatus = (uint32_t)0x01; - } - else - { - HSEStatus = (uint32_t)0x00; - } - - if (HSEStatus == (uint32_t)0x01) - { - /* Select regulator voltage output Scale 1 mode, System frequency up to 168 MHz */ - RCC->APB1ENR |= RCC_APB1ENR_PWREN; - PWR->CR |= PWR_CR_VOS; - - /* HCLK = SYSCLK / 1*/ - RCC->CFGR |= RCC_CFGR_HPRE_DIV1; - - /* PCLK2 = HCLK / 2*/ - RCC->CFGR |= RCC_CFGR_PPRE2_DIV2; - - /* PCLK1 = HCLK / 4*/ - RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; - - // save bus clock values - rcc_dev_clk_speed_table[RCC_AHB1] = (SystemCoreClock/1); - rcc_dev_clk_speed_table[RCC_APB2] = (SystemCoreClock/2); - rcc_dev_clk_speed_table[RCC_APB1] = (SystemCoreClock/4); - - /* Configure the main PLL */ - RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) | - (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24); - - /* Enable the main PLL */ - RCC->CR |= RCC_CR_PLLON; - - /* Wait till the main PLL is ready */ - while((RCC->CR & RCC_CR_PLLRDY) == 0) - { - } - - /* Configure Flash prefetch, Instruction cache, Data cache and wait state */ - FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS; - - /* Select the main PLL as system clock source */ - RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); - RCC->CFGR |= RCC_CFGR_SW_PLL; - - /* Wait till the main PLL is used as system clock source */ - while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL); - { - } - } - else - { /* If HSE fails to start-up, the application will have wrong clock - configuration. User can add here some code to deal with this error */ - } -} - - -void rcc_clk_init(rcc_sysclk_src sysclk_src, - rcc_pllsrc pll_src, - rcc_pll_multiplier pll_mul) { - - //SetupClock72MHz(); -#if STM32_TICKS_PER_US == 168 - SetupClock168MHz(); -#endif -#if STM32_TICKS_PER_US == 120 - SetupClock120MHz(); -#endif -#if STM32_TICKS_PER_US == 72 - SetupClock72MHz(); -#endif -} - - - - -#define PLL_M 8 -#define PLL_N 240 -/* SYSCLK = PLL_VCO / PLL_P */ -#define PLL_P 2 - -/* USB OTG FS, SDIO and RNG Clock = PLL_VCO / PLLQ */ -#define PLL_Q 5 - - -void rcc_clk_init2(rcc_sysclk_src sysclk_src, - rcc_pllsrc pll_src, - rcc_pll_multiplier pll_mul) { - -/******************************************************************************/ -/* PLL (clocked by HSE) used as System clock source */ -/******************************************************************************/ - uint32 StartUpCounter = 0, HSEStatus = 0; - rcc_reg_map *pRCC = RCC_BASE; - - /* Enable HSE */ - pRCC->CR |= RCC_CR_HSEON; - - /* Wait till HSE is ready and if Time out is reached exit */ - do - { - HSEStatus = pRCC->CR & RCC_CR_HSERDY; - StartUpCounter++; - } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); - - if ((pRCC->CR & RCC_CR_HSERDY) != 0) - { - HSEStatus = 0x01; - } - else - { - HSEStatus = 0x00; - } - - if (HSEStatus == 0x01) - { - /* HCLK = SYSCLK / 1*/ - pRCC->CFGR |= RCC_CFGR_HPRE_DIV1; - - /* PCLK2 = HCLK / 2*/ - pRCC->CFGR |= RCC_CFGR_PPRE2_DIV2; - - /* PCLK1 = HCLK / 4*/ - pRCC->CFGR |= RCC_CFGR_PPRE1_DIV4; - - /* Configure the main PLL */ - pRCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) | - (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24); - - /* Enable the main PLL */ - pRCC->CR |= RCC_CR_PLLON; - - /* Wait till the main PLL is ready */ - while((pRCC->CR & RCC_CR_PLLRDY) == 0) - { - } - - /* Configure Flash prefetch, Instruction cache, Data cache and wait state */ - ((FLASH_TypeDef*)FLASH)->ACR = FLASH_ACR_PRFTEN |FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_3WS; - - /* Select the main PLL as system clock source */ - pRCC->CFGR &= ~RCC_CFGR_SW; - pRCC->CFGR |= RCC_CFGR_SW_PLL; - - /* Wait till the main PLL is used as system clock source */ - while ((pRCC->CFGR & RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL); - { - } - } - else - { /* If HSE fails to start-up, the application will have wrong clock - configuration. User can add here some code to deal with this error */ - } - -#if 0 - uint32 cfgr = 0; - uint32 cr; - - /* Assume that we're going to clock the chip off the PLL, fed by - * the HSE */ - ASSERT(sysclk_src == RCC_CLKSRC_PLL && - pll_src == RCC_PLLSRC_HSE); - - RCC_BASE->CFGR = pll_src | pll_mul; - - /* Turn on the HSE */ - cr = RCC_BASE->CR; - cr |= RCC_CR_HSEON; - RCC_BASE->CR = cr; - while (!(RCC_BASE->CR & RCC_CR_HSERDY)) - ; - - /* Now the PLL */ - cr |= RCC_CR_PLLON; - RCC_BASE->CR = cr; - while (!(RCC_BASE->CR & RCC_CR_PLLRDY)) - ; - - /* Finally, let's switch over to the PLL */ - cfgr &= ~RCC_CFGR_SW; - cfgr |= RCC_CFGR_SW_PLL; - RCC_BASE->CFGR = cfgr; - while ((RCC_BASE->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) - ; -#endif -} - -/** - * @brief Turn on the clock line on a peripheral - * @param id Clock ID of the peripheral to turn on. - */ -void rcc_clk_enable(rcc_clk_id id) { - static const __io uint32* enable_regs[] = { - [APB1] = &RCC_BASE->APB1ENR, - [APB2] = &RCC_BASE->APB2ENR, - [AHB1] = &RCC_BASE->AHB1ENR, - [AHB2] = &RCC_BASE->AHB2ENR, - [AHB3] = &RCC_BASE->AHB3ENR, - }; - - rcc_clk_domain clk_domain = rcc_dev_clk(id); - __io uint32* enr = (__io uint32*)enable_regs[clk_domain]; - uint8 lnum = rcc_dev_table[id].line_num; - - bb_peri_set_bit(enr, lnum, 1); -} - -/** - * @brief Turn on the clock line on a peripheral - * @param id Clock ID of the peripheral to turn on. - */ -void rcc_clk_disable(rcc_clk_id id) { - static const __io uint32* enable_regs[] = { - [APB1] = &RCC_BASE->APB1ENR, - [APB2] = &RCC_BASE->APB2ENR, - [AHB1] = &RCC_BASE->AHB1ENR, - [AHB2] = &RCC_BASE->AHB2ENR, - [AHB3] = &RCC_BASE->AHB3ENR, - }; - - rcc_clk_domain clk_domain = rcc_dev_clk(id); - __io uint32* enr = (__io uint32*)enable_regs[clk_domain]; - uint8 lnum = rcc_dev_table[id].line_num; - - bb_peri_set_bit(enr, lnum, 0); -} - -/** - * @brief Reset a peripheral. - * @param id Clock ID of the peripheral to reset. - */ -void rcc_reset_dev(rcc_clk_id id) { - static const __io uint32* reset_regs[] = { - [APB1] = &RCC_BASE->APB1RSTR, - [APB2] = &RCC_BASE->APB2RSTR, - [AHB1] = &RCC_BASE->AHB1RSTR, - [AHB2] = &RCC_BASE->AHB2RSTR, - [AHB3] = &RCC_BASE->AHB3RSTR, - }; - - rcc_clk_domain clk_domain = rcc_dev_clk(id); - __io void* addr = (__io void*)reset_regs[clk_domain]; - uint8 lnum = rcc_dev_table[id].line_num; - - bb_peri_set_bit(addr, lnum, 1); - bb_peri_set_bit(addr, lnum, 0); -} - -/** - * @brief Get a peripheral's clock domain - * @param id Clock ID of the peripheral whose clock domain to return - * @return Clock source for the given clock ID - */ -rcc_clk_domain rcc_dev_clk(rcc_clk_id id) { - return rcc_dev_table[id].clk_domain; -} - -/** - * @brief Get a peripheral's clock domain speed - * @param id Clock ID of the peripheral whose clock domain speed to return - * @return Clock speed for the given clock ID - */ -uint32 rcc_dev_clk_speed(rcc_clk_id id) { - return rcc_dev_clk_speed_table[rcc_dev_clk(id)]; -} - -/** - * @brief Get a peripheral's timer clock domain speed - * @param id Clock ID of the peripheral whose clock domain speed to return - * @return Clock speed for the given clock ID - */ -uint32 rcc_dev_timer_clk_speed(rcc_clk_id id) { - return 2*rcc_dev_clk_speed(id); -} - -/** - * @brief Set the divider on a peripheral prescaler - * @param prescaler prescaler to set - * @param divider prescaler divider - */ -void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider) { -#if 0 - static const uint32 masks[] = { - [RCC_PRESCALER_AHB] = RCC_CFGR_HPRE, - [RCC_PRESCALER_APB1] = RCC_CFGR_PPRE1, - [RCC_PRESCALER_APB2] = RCC_CFGR_PPRE2, - [RCC_PRESCALER_USB] = RCC_CFGR_USBPRE, - [RCC_PRESCALER_ADC] = RCC_CFGR_ADCPRE, - }; - - uint32 cfgr = RCC_BASE->CFGR; - cfgr &= ~masks[prescaler]; - cfgr |= divider; - RCC_BASE->CFGR = cfgr; -#endif -} - -#endif diff --git a/STM32F4/cores/maple/libmaple/rccF2.h b/STM32F4/cores/maple/libmaple/rccF2.h deleted file mode 100644 index 99c5ff2..0000000 --- a/STM32F4/cores/maple/libmaple/rccF2.h +++ /dev/null @@ -1,642 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file rcc.h - * @brief reset and clock control definitions and prototypes - */ - -#include "libmaple_types.h" -#include "bitband.h" - -#ifndef _RCC_H_ -#define _RCC_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -/** RCC register map type */ -typedef struct -{ - __io uint32 CR; /*!< RCC clock control register, Address offset: 0x00 */ - __io uint32 PLLCFGR; /*!< RCC PLL configuration register, Address offset: 0x04 */ - __io uint32 CFGR; /*!< RCC clock configuration register, Address offset: 0x08 */ - __io uint32 CIR; /*!< RCC clock interrupt register, Address offset: 0x0C */ - __io uint32 AHB1RSTR; /*!< RCC AHB1 peripheral reset register, Address offset: 0x10 */ - __io uint32 AHB2RSTR; /*!< RCC AHB2 peripheral reset register, Address offset: 0x14 */ - __io uint32 AHB3RSTR; /*!< RCC AHB3 peripheral reset register, Address offset: 0x18 */ - uint32 RESERVED0; /*!< Reserved, 0x1C */ - __io uint32 APB1RSTR; /*!< RCC APB1 peripheral reset register, Address offset: 0x20 */ - __io uint32 APB2RSTR; /*!< RCC APB2 peripheral reset register, Address offset: 0x24 */ - uint32 RESERVED1[2]; /*!< Reserved, 0x28-0x2C */ - __io uint32 AHB1ENR; /*!< RCC AHB1 peripheral clock register, Address offset: 0x30 */ - __io uint32 AHB2ENR; /*!< RCC AHB2 peripheral clock register, Address offset: 0x34 */ - __io uint32 AHB3ENR; /*!< RCC AHB3 peripheral clock register, Address offset: 0x38 */ - uint32 RESERVED2; /*!< Reserved, 0x3C */ - __io uint32 APB1ENR; /*!< RCC APB1 peripheral clock enable register, Address offset: 0x40 */ - __io uint32 APB2ENR; /*!< RCC APB2 peripheral clock enable register, Address offset: 0x44 */ - uint32 RESERVED3[2]; /*!< Reserved, 0x48-0x4C */ - __io uint32 AHB1LPENR; /*!< RCC AHB1 peripheral clock enable in low power mode register, Address offset: 0x50 */ - __io uint32 AHB2LPENR; /*!< RCC AHB2 peripheral clock enable in low power mode register, Address offset: 0x54 */ - __io uint32 AHB3LPENR; /*!< RCC AHB3 peripheral clock enable in low power mode register, Address offset: 0x58 */ - uint32 RESERVED4; /*!< Reserved, 0x5C */ - __io uint32 APB1LPENR; /*!< RCC APB1 peripheral clock enable in low power mode register, Address offset: 0x60 */ - __io uint32 APB2LPENR; /*!< RCC APB2 peripheral clock enable in low power mode register, Address offset: 0x64 */ - uint32 RESERVED5[2]; /*!< Reserved, 0x68-0x6C */ - __io uint32 BDCR; /*!< RCC Backup domain control register, Address offset: 0x70 */ - __io uint32 CSR; /*!< RCC clock control & status register, Address offset: 0x74 */ - uint32 RESERVED6[2]; /*!< Reserved, 0x78-0x7C */ - __io uint32 SSCGR; /*!< RCC spread spectrum clock generation register, Address offset: 0x80 */ - __io uint32 PLLI2SCFGR; /*!< RCC PLLI2S configuration register, Address offset: 0x84 */ -} rcc_reg_map; - -/** RCC register map base pointer */ -//#define RCC_BASE ((struct rcc_reg_map*)0x40021000) -#define RCC_BASE ((rcc_reg_map*)0x40023800) - -/* - * Register bit definitions - */ - -/* Clock control register */ - -#define RCC_CR_PLLRDY_BIT 25 -#define RCC_CR_PLLON_BIT 24 -#define RCC_CR_CSSON_BIT 19 -#define RCC_CR_HSEBYP_BIT 18 -#define RCC_CR_HSERDY_BIT 17 -#define RCC_CR_HSEON_BIT 16 -#define RCC_CR_HSIRDY_BIT 1 -#define RCC_CR_HSION_BIT 0 - -#define RCC_CR_PLLRDY BIT(RCC_CR_PLLRDY_BIT) -#define RCC_CR_PLLON BIT(RCC_CR_PLLON_BIT) -#define RCC_CR_CSSON BIT(RCC_CR_CSSON_BIT) -#define RCC_CR_HSEBYP BIT(RCC_CR_HSEBYP_BIT) -#define RCC_CR_HSERDY BIT(RCC_CR_HSERDY_BIT) -#define RCC_CR_HSEON BIT(RCC_CR_HSEON_BIT) -#define RCC_CR_HSICAL (0xFF << 8) -#define RCC_CR_HSITRIM (0x1F << 3) -#define RCC_CR_HSIRDY BIT(RCC_CR_HSIRDY_BIT) -#define RCC_CR_HSION BIT(RCC_CR_HSION_BIT) - -/* Clock configuration register */ - -#define RCC_CFGR_USBPRE_BIT 22 -#define RCC_CFGR_PLLXTPRE_BIT 17 -#define RCC_CFGR_PLLSRC_BIT 16 - -#define RCC_CFGR_MCO (0x3 << 24) -#define RCC_CFGR_USBPRE BIT(RCC_CFGR_USBPRE_BIT) -#define RCC_CFGR_PLLMUL (0xF << 18) -#define RCC_CFGR_PLLXTPRE BIT(RCC_CFGR_PLLXTPRE_BIT) -#define RCC_CFGR_PLLSRC BIT(RCC_CFGR_PLLSRC_BIT) -#define RCC_CFGR_ADCPRE (0x3 << 14) -#define RCC_CFGR_PPRE2 (0x7 << 11) -#define RCC_CFGR_PPRE1 (0x7 << 8) -#define RCC_CFGR_HPRE (0xF << 4) -#define RCC_CFGR_SWS (0x3 << 2) -#define RCC_CFGR_SWS_PLL (0x2 << 2) -#define RCC_CFGR_SWS_HSE (0x1 << 2) -#define RCC_CFGR_SW 0x3 -#define RCC_CFGR_SW_PLL 0x2 -#define RCC_CFGR_SW_HSE 0x1 - -#define RCC_CFGR_MCO1Source_HSI ((uint32_t)0x00000000) -#define RCC_CFGR_MCO1Source_LSE ((uint32_t)0x00200000) -#define RCC_CFGR_MCO1Source_HSE ((uint32_t)0x00400000) -#define RCC_CFGR_MCO1Source_PLLCLK ((uint32_t)0x00600000) -#define RCC_CFGR_MCO1Div_1 ((uint32_t)0x00000000) -#define RCC_CFGR_MCO1Div_2 ((uint32_t)0x04000000) -#define RCC_CFGR_MCO1Div_3 ((uint32_t)0x05000000) -#define RCC_CFGR_MCO1Div_4 ((uint32_t)0x06000000) -#define RCC_CFGR_MCO1Div_5 ((uint32_t)0x07000000) -#define RCC_CFGR_MCO1_RESET_MASK ((uint32_t)0xF89FFFFF) - -/* Clock interrupt register */ - -#define RCC_CIR_CSSC_BIT 23 -#define RCC_CIR_PLLRDYC_BIT 20 -#define RCC_CIR_HSERDYC_BIT 19 -#define RCC_CIR_HSIRDYC_BIT 18 -#define RCC_CIR_LSERDYC_BIT 17 -#define RCC_CIR_LSIRDYC_BIT 16 -#define RCC_CIR_PLLRDYIE_BIT 12 -#define RCC_CIR_HSERDYIE_BIT 11 -#define RCC_CIR_HSIRDYIE_BIT 10 -#define RCC_CIR_LSERDYIE_BIT 9 -#define RCC_CIR_LSIRDYIE_BIT 8 -#define RCC_CIR_CSSF_BIT 7 -#define RCC_CIR_PLLRDYF_BIT 4 -#define RCC_CIR_HSERDYF_BIT 3 -#define RCC_CIR_HSIRDYF_BIT 2 -#define RCC_CIR_LSERDYF_BIT 1 -#define RCC_CIR_LSIRDYF_BIT 0 - -#define RCC_CIR_CSSC BIT(RCC_CIR_CSSC_BIT) -#define RCC_CIR_PLLRDYC BIT(RCC_CIR_PLLRDYC_BIT) -#define RCC_CIR_HSERDYC BIT(RCC_CIR_HSERDYC_BIT) -#define RCC_CIR_HSIRDYC BIT(RCC_CIR_HSIRDYC_BIT) -#define RCC_CIR_LSERDYC BIT(RCC_CIR_LSERDYC_BIT) -#define RCC_CIR_LSIRDYC BIT(RCC_CIR_LSIRDYC_BIT) -#define RCC_CIR_PLLRDYIE BIT(RCC_CIR_PLLRDYIE_BIT) -#define RCC_CIR_HSERDYIE BIT(RCC_CIR_HSERDYIE_BIT) -#define RCC_CIR_HSIRDYIE BIT(RCC_CIR_HSIRDYIE_BIT) -#define RCC_CIR_LSERDYIE BIT(RCC_CIR_LSERDYIE_BIT) -#define RCC_CIR_LSIRDYIE BIT(RCC_CIR_LSIRDYIE_BIT) -#define RCC_CIR_CSSF BIT(RCC_CIR_CSSF_BIT) -#define RCC_CIR_PLLRDYF BIT(RCC_CIR_PLLRDYF_BIT) -#define RCC_CIR_HSERDYF BIT(RCC_CIR_HSERDYF_BIT) -#define RCC_CIR_HSIRDYF BIT(RCC_CIR_HSIRDYF_BIT) -#define RCC_CIR_LSERDYF BIT(RCC_CIR_LSERDYF_BIT) -#define RCC_CIR_LSIRDYF BIT(RCC_CIR_LSIRDYF_BIT) - -/* APB2 peripheral reset register */ - -#define RCC_APB2RSTR_TIM11RST_BIT 21 -#define RCC_APB2RSTR_TIM10RST_BIT 20 -#define RCC_APB2RSTR_TIM9RST_BIT 19 -#define RCC_APB2RSTR_ADC3RST_BIT 15 -#define RCC_APB2RSTR_USART1RST_BIT 14 -#define RCC_APB2RSTR_TIM8RST_BIT 13 -#define RCC_APB2RSTR_SPI1RST_BIT 12 -#define RCC_APB2RSTR_TIM1RST_BIT 11 -#define RCC_APB2RSTR_ADC2RST_BIT 10 -#define RCC_APB2RSTR_ADC1RST_BIT 9 -#define RCC_APB2RSTR_IOPGRST_BIT 8 -#define RCC_APB2RSTR_IOPFRST_BIT 7 -#define RCC_APB2RSTR_IOPERST_BIT 6 -#define RCC_APB2RSTR_IOPDRST_BIT 5 -#define RCC_APB2RSTR_IOPCRST_BIT 4 -#define RCC_APB2RSTR_IOPBRST_BIT 3 -#define RCC_APB2RSTR_IOPARST_BIT 2 -#define RCC_APB2RSTR_AFIORST_BIT 0 - -#define RCC_APB2RSTR_TIM11RST BIT(RCC_APB2RSTR_TIM11RST_BIT) -#define RCC_APB2RSTR_TIM10RST BIT(RCC_APB2RSTR_TIM10RST_BIT) -#define RCC_APB2RSTR_TIM9RST BIT(RCC_APB2RSTR_TIM9RST_BIT) -#define RCC_APB2RSTR_ADC3RST BIT(RCC_APB2RSTR_ADC3RST_BIT) -#define RCC_APB2RSTR_USART1RST BIT(RCC_APB2RSTR_USART1RST_BIT) -#define RCC_APB2RSTR_TIM8RST BIT(RCC_APB2RSTR_TIM8RST_BIT) -#define RCC_APB2RSTR_SPI1RST BIT(RCC_APB2RSTR_SPI1RST_BIT) -#define RCC_APB2RSTR_TIM1RST BIT(RCC_APB2RSTR_TIM1RST_BIT) -#define RCC_APB2RSTR_ADC2RST BIT(RCC_APB2RSTR_ADC2RST_BIT) -#define RCC_APB2RSTR_ADC1RST BIT(RCC_APB2RSTR_ADC1RST_BIT) -#define RCC_APB2RSTR_IOPGRST BIT(RCC_APB2RSTR_IOPGRST_BIT) -#define RCC_APB2RSTR_IOPFRST BIT(RCC_APB2RSTR_IOPFRST_BIT) -#define RCC_APB2RSTR_IOPERST BIT(RCC_APB2RSTR_IOPERST_BIT) -#define RCC_APB2RSTR_IOPDRST BIT(RCC_APB2RSTR_IOPDRST_BIT) -#define RCC_APB2RSTR_IOPCRST BIT(RCC_APB2RSTR_IOPCRST_BIT) -#define RCC_APB2RSTR_IOPBRST BIT(RCC_APB2RSTR_IOPBRST_BIT) -#define RCC_APB2RSTR_IOPARST BIT(RCC_APB2RSTR_IOPARST_BIT) -#define RCC_APB2RSTR_AFIORST BIT(RCC_APB2RSTR_AFIORST_BIT) - -/* APB1 peripheral reset register */ - -#define RCC_APB1RSTR_DACRST_BIT 29 -#define RCC_APB1RSTR_PWRRST_BIT 28 -#define RCC_APB1RSTR_BKPRST_BIT 27 -#define RCC_APB1RSTR_CANRST_BIT 25 -#define RCC_APB1RSTR_USBRST_BIT 23 -#define RCC_APB1RSTR_I2C2RST_BIT 22 -#define RCC_APB1RSTR_I2C1RST_BIT 21 -#define RCC_APB1RSTR_UART5RST_BIT 20 -#define RCC_APB1RSTR_UART4RST_BIT 19 -#define RCC_APB1RSTR_USART3RST_BIT 18 -#define RCC_APB1RSTR_USART2RST_BIT 17 -#define RCC_APB1RSTR_SPI3RST_BIT 15 -#define RCC_APB1RSTR_SPI2RST_BIT 14 -#define RCC_APB1RSTR_WWDRST_BIT 11 -#define RCC_APB1RSTR_TIM14RST_BIT 8 -#define RCC_APB1RSTR_TIM13RST_BIT 7 -#define RCC_APB1RSTR_TIM12RST_BIT 6 -#define RCC_APB1RSTR_TIM7RST_BIT 5 -#define RCC_APB1RSTR_TIM6RST_BIT 4 -#define RCC_APB1RSTR_TIM5RST_BIT 3 -#define RCC_APB1RSTR_TIM4RST_BIT 2 -#define RCC_APB1RSTR_TIM3RST_BIT 1 -#define RCC_APB1RSTR_TIM2RST_BIT 0 - -#define RCC_APB1RSTR_DACRST BIT(RCC_APB1RSTR_DACRST_BIT) -#define RCC_APB1RSTR_PWRRST BIT(RCC_APB1RSTR_PWRRST_BIT) -#define RCC_APB1RSTR_BKPRST BIT(RCC_APB1RSTR_BKPRST_BIT) -#define RCC_APB1RSTR_CANRST BIT(RCC_APB1RSTR_CANRST_BIT) -#define RCC_APB1RSTR_USBRST BIT(RCC_APB1RSTR_USBRST_BIT) -#define RCC_APB1RSTR_I2C2RST BIT(RCC_APB1RSTR_I2C2RST_BIT) -#define RCC_APB1RSTR_I2C1RST BIT(RCC_APB1RSTR_I2C1RST_BIT) -#define RCC_APB1RSTR_UART5RST BIT(RCC_APB1RSTR_UART5RST_BIT) -#define RCC_APB1RSTR_UART4RST BIT(RCC_APB1RSTR_UART4RST_BIT) -#define RCC_APB1RSTR_USART3RST BIT(RCC_APB1RSTR_USART3RST_BIT) -#define RCC_APB1RSTR_USART2RST BIT(RCC_APB1RSTR_USART2RST_BIT) -#define RCC_APB1RSTR_SPI3RST BIT(RCC_APB1RSTR_SPI3RST_BIT) -#define RCC_APB1RSTR_SPI2RST BIT(RCC_APB1RSTR_SPI2RST_BIT) -#define RCC_APB1RSTR_WWDRST BIT(RCC_APB1RSTR_WWDRST_BIT) -#define RCC_APB1RSTR_TIM14RST BIT(RCC_APB1RSTR_TIM14RST_BIT) -#define RCC_APB1RSTR_TIM13RST BIT(RCC_APB1RSTR_TIM13RST_BIT) -#define RCC_APB1RSTR_TIM12RST BIT(RCC_APB1RSTR_TIM12RST_BIT) -#define RCC_APB1RSTR_TIM7RST BIT(RCC_APB1RSTR_TIM7RST_BIT) -#define RCC_APB1RSTR_TIM6RST BIT(RCC_APB1RSTR_TIM6RST_BIT) -#define RCC_APB1RSTR_TIM5RST BIT(RCC_APB1RSTR_TIM5RST_BIT) -#define RCC_APB1RSTR_TIM4RST BIT(RCC_APB1RSTR_TIM4RST_BIT) -#define RCC_APB1RSTR_TIM3RST BIT(RCC_APB1RSTR_TIM3RST_BIT) -#define RCC_APB1RSTR_TIM2RST BIT(RCC_APB1RSTR_TIM2RST_BIT) - -/* AHB peripheral clock enable register */ - -#define RCC_AHBENR_SDIOEN_BIT 10 -#define RCC_AHBENR_FSMCEN_BIT 8 -#define RCC_AHBENR_CRCEN_BIT 7 -#define RCC_AHBENR_FLITFEN_BIT 4 -#define RCC_AHBENR_SRAMEN_BIT 2 -#define RCC_AHBENR_DMA2EN_BIT 1 -#define RCC_AHBENR_DMA1EN_BIT 0 - -#define RCC_AHBENR_SDIOEN BIT(RCC_AHBENR_SDIOEN_BIT) -#define RCC_AHBENR_FSMCEN BIT(RCC_AHBENR_FSMCEN_BIT) -#define RCC_AHBENR_CRCEN BIT(RCC_AHBENR_CRCEN_BIT) -#define RCC_AHBENR_FLITFEN BIT(RCC_AHBENR_FLITFEN_BIT) -#define RCC_AHBENR_SRAMEN BIT(RCC_AHBENR_SRAMEN_BIT) -#define RCC_AHBENR_DMA2EN BIT(RCC_AHBENR_DMA2EN_BIT) -#define RCC_AHBENR_DMA1EN BIT(RCC_AHBENR_DMA1EN_BIT) - -/* APB2 peripheral clock enable register */ - -#define RCC_APB2ENR_TIM11EN_BIT 21 -#define RCC_APB2ENR_TIM10EN_BIT 20 -#define RCC_APB2ENR_TIM9EN_BIT 19 -#define RCC_APB2ENR_ADC3EN_BIT 15 -#define RCC_APB2ENR_USART1EN_BIT 14 -#define RCC_APB2ENR_TIM8EN_BIT 13 -#define RCC_APB2ENR_SPI1EN_BIT 12 -#define RCC_APB2ENR_TIM1EN_BIT 11 -#define RCC_APB2ENR_ADC2EN_BIT 10 -#define RCC_APB2ENR_ADC1EN_BIT 9 -#define RCC_APB2ENR_IOPGEN_BIT 8 -#define RCC_APB2ENR_IOPFEN_BIT 7 -#define RCC_APB2ENR_IOPEEN_BIT 6 -#define RCC_APB2ENR_IOPDEN_BIT 5 -#define RCC_APB2ENR_IOPCEN_BIT 4 -#define RCC_APB2ENR_IOPBEN_BIT 3 -#define RCC_APB2ENR_IOPAEN_BIT 2 -#define RCC_APB2ENR_AFIOEN_BIT 0 - -#define RCC_APB2ENR_TIM11EN BIT(RCC_APB2ENR_TIM11EN_BIT) -#define RCC_APB2ENR_TIM10EN BIT(RCC_APB2ENR_TIM10EN_BIT) -#define RCC_APB2ENR_TIM9EN BIT(RCC_APB2ENR_TIM9EN_BIT) -#define RCC_APB2ENR_ADC3EN BIT(RCC_APB2ENR_ADC3EN_BIT) -#define RCC_APB2ENR_USART1EN BIT(RCC_APB2ENR_USART1EN_BIT) -#define RCC_APB2ENR_TIM8EN BIT(RCC_APB2ENR_TIM8EN_BIT) -#define RCC_APB2ENR_SPI1EN BIT(RCC_APB2ENR_SPI1EN_BIT) -#define RCC_APB2ENR_TIM1EN BIT(RCC_APB2ENR_TIM1EN_BIT) -#define RCC_APB2ENR_ADC2EN BIT(RCC_APB2ENR_ADC2EN_BIT) -#define RCC_APB2ENR_ADC1EN BIT(RCC_APB2ENR_ADC1EN_BIT) -#define RCC_APB2ENR_IOPGEN BIT(RCC_APB2ENR_IOPGEN_BIT) -#define RCC_APB2ENR_IOPFEN BIT(RCC_APB2ENR_IOPFEN_BIT) -#define RCC_APB2ENR_IOPEEN BIT(RCC_APB2ENR_IOPEEN_BIT) -#define RCC_APB2ENR_IOPDEN BIT(RCC_APB2ENR_IOPDEN_BIT) -#define RCC_APB2ENR_IOPCEN BIT(RCC_APB2ENR_IOPCEN_BIT) -#define RCC_APB2ENR_IOPBEN BIT(RCC_APB2ENR_IOPBEN_BIT) -#define RCC_APB2ENR_IOPAEN BIT(RCC_APB2ENR_IOPAEN_BIT) -#define RCC_APB2ENR_AFIOEN BIT(RCC_APB2ENR_AFIOEN_BIT) - -/* APB1 peripheral clock enable register */ - -#define RCC_APB1ENR_DACEN_BIT 29 -#define RCC_APB1ENR_PWREN_BIT 28 -#define RCC_APB1ENR_BKPEN_BIT 27 -#define RCC_APB1ENR_CANEN_BIT 25 -#define RCC_APB1ENR_USBEN_BIT 23 -#define RCC_APB1ENR_I2C2EN_BIT 22 -#define RCC_APB1ENR_I2C1EN_BIT 21 -#define RCC_APB1ENR_UART5EN_BIT 20 -#define RCC_APB1ENR_UART4EN_BIT 19 -#define RCC_APB1ENR_USART3EN_BIT 18 -#define RCC_APB1ENR_USART2EN_BIT 17 -#define RCC_APB1ENR_SPI3EN_BIT 15 -#define RCC_APB1ENR_SPI2EN_BIT 14 -#define RCC_APB1ENR_WWDEN_BIT 11 -#define RCC_APB1ENR_TIM14EN_BIT 8 -#define RCC_APB1ENR_TIM13EN_BIT 7 -#define RCC_APB1ENR_TIM12EN_BIT 6 -#define RCC_APB1ENR_TIM7EN_BIT 5 -#define RCC_APB1ENR_TIM6EN_BIT 4 -#define RCC_APB1ENR_TIM5EN_BIT 3 -#define RCC_APB1ENR_TIM4EN_BIT 2 -#define RCC_APB1ENR_TIM3EN_BIT 1 -#define RCC_APB1ENR_TIM2EN_BIT 0 - -#define RCC_APB1ENR_DACEN BIT(RCC_APB1ENR_DACEN_BIT) -#define RCC_APB1ENR_PWREN BIT(RCC_APB1ENR_PWREN_BIT) -#define RCC_APB1ENR_BKPEN BIT(RCC_APB1ENR_BKPEN_BIT) -#define RCC_APB1ENR_CANEN BIT(RCC_APB1ENR_CANEN_BIT) -#define RCC_APB1ENR_USBEN BIT(RCC_APB1ENR_USBEN_BIT) -#define RCC_APB1ENR_I2C2EN BIT(RCC_APB1ENR_I2C2EN_BIT) -#define RCC_APB1ENR_I2C1EN BIT(RCC_APB1ENR_I2C1EN_BIT) -#define RCC_APB1ENR_UART5EN BIT(RCC_APB1ENR_UART5EN_BIT) -#define RCC_APB1ENR_UART4EN BIT(RCC_APB1ENR_UART4EN_BIT) -#define RCC_APB1ENR_USART3EN BIT(RCC_APB1ENR_USART3EN_BIT) -#define RCC_APB1ENR_USART2EN BIT(RCC_APB1ENR_USART2EN_BIT) -#define RCC_APB1ENR_SPI3EN BIT(RCC_APB1ENR_SPI3EN_BIT) -#define RCC_APB1ENR_SPI2EN BIT(RCC_APB1ENR_SPI2EN_BIT) -#define RCC_APB1ENR_WWDEN BIT(RCC_APB1ENR_WWDEN_BIT) -#define RCC_APB1ENR_TIM14EN BIT(RCC_APB1ENR_TIM14EN_BIT) -#define RCC_APB1ENR_TIM13EN BIT(RCC_APB1ENR_TIM13EN_BIT) -#define RCC_APB1ENR_TIM12EN BIT(RCC_APB1ENR_TIM12EN_BIT) -#define RCC_APB1ENR_TIM7EN BIT(RCC_APB1ENR_TIM7EN_BIT) -#define RCC_APB1ENR_TIM6EN BIT(RCC_APB1ENR_TIM6EN_BIT) -#define RCC_APB1ENR_TIM5EN BIT(RCC_APB1ENR_TIM5EN_BIT) -#define RCC_APB1ENR_TIM4EN BIT(RCC_APB1ENR_TIM4EN_BIT) -#define RCC_APB1ENR_TIM3EN BIT(RCC_APB1ENR_TIM3EN_BIT) -#define RCC_APB1ENR_TIM2EN BIT(RCC_APB1ENR_TIM2EN_BIT) - -/* Backup domain control register */ - -#define RCC_BDCR_BDRST_BIT 16 -#define RCC_BDCR_RTCEN_BIT 15 -#define RCC_BDCR_LSEBYP_BIT 2 -#define RCC_BDCR_LSERDY_BIT 1 -#define RCC_BDCR_LSEON_BIT 0 - -#define RCC_BDCR_BDRST BIT(RCC_BDCR_BDRST_BIT) -#define RCC_BDCR_RTCEN BIT(RCC_BDCR_RTC_BIT) -#define RCC_BDCR_RTCSEL (0x3 << 8) -#define RCC_BDCR_RTCSEL_NONE (0x0 << 8) -#define RCC_BDCR_RTCSEL_LSE (0x1 << 8) -#define RCC_BDCR_RTCSEL_LSI (0x2 << 8) -#define RCC_BDCR_RTCSEL_HSE (0x3 << 8) -#define RCC_BDCR_LSEBYP BIT(RCC_BDCR_LSEBYP_BIT) -#define RCC_BDCR_LSERDY BIT(RCC_BDCR_LSERDY_BIT) -#define RCC_BDCR_LSEON BIT(RCC_BDCR_LSEON_BIT) - -/* Control/status register */ - -#define RCC_CSR_LPWRRSTF_BIT 31 -#define RCC_CSR_WWDGRSTF_BIT 30 -#define RCC_CSR_IWDGRSTF_BIT 29 -#define RCC_CSR_SFTRSTF_BIT 28 -#define RCC_CSR_PORRSTF_BIT 27 -#define RCC_CSR_PINRSTF_BIT 26 -#define RCC_CSR_RMVF_BIT 24 -#define RCC_CSR_LSIRDY_BIT 1 -#define RCC_CSR_LSION_BIT 0 - -#define RCC_CSR_LPWRRSTF BIT(RCC_CSR_LPWRRSTF_BIT) -#define RCC_CSR_WWDGRSTF BIT(RCC_CSR_WWDGRSTF_BIT) -#define RCC_CSR_IWDGRSTF BIT(RCC_CSR_IWDGRSTF_BIT) -#define RCC_CSR_SFTRSTF BIT(RCC_CSR_SFTRSTF_BIT) -#define RCC_CSR_PORRSTF BIT(RCC_CSR_PORRSTF_BIT) -#define RCC_CSR_PINRSTF BIT(RCC_CSR_PINRSTF_BIT) -#define RCC_CSR_RMVF BIT(RCC_CSR_RMVF_BIT) -#define RCC_CSR_LSIRDY BIT(RCC_CSR_LSIRDY_BIT) -#define RCC_CSR_LSION BIT(RCC_CSR_LSION_BIT) - -/* - * Convenience routines - */ - -/** - * SYSCLK sources - * @see rcc_clk_init() - */ -typedef enum rcc_sysclk_src { - RCC_CLKSRC_HSI = 0x0, - RCC_CLKSRC_HSE = 0x1, - RCC_CLKSRC_PLL = 0x2, -} rcc_sysclk_src; - -/** - * PLL entry clock source - * @see rcc_clk_init() - */ -typedef enum rcc_pllsrc { - RCC_PLLSRC_HSE = (0x1 << 16), - RCC_PLLSRC_HSI_DIV_2 = (0x0 << 16) -} rcc_pllsrc; - -/** - * PLL multipliers - * @see rcc_clk_init() - */ -typedef enum rcc_pll_multiplier { - RCC_PLLMUL_2 = (0x0 << 18), - RCC_PLLMUL_3 = (0x1 << 18), - RCC_PLLMUL_4 = (0x2 << 18), - RCC_PLLMUL_5 = (0x3 << 18), - RCC_PLLMUL_6 = (0x4 << 18), - RCC_PLLMUL_7 = (0x5 << 18), - RCC_PLLMUL_8 = (0x6 << 18), - RCC_PLLMUL_9 = (0x7 << 18), - RCC_PLLMUL_10 = (0x8 << 18), - RCC_PLLMUL_11 = (0x9 << 18), - RCC_PLLMUL_12 = (0xA << 18), - RCC_PLLMUL_13 = (0xB << 18), - RCC_PLLMUL_14 = (0xC << 18), - RCC_PLLMUL_15 = (0xD << 18), - RCC_PLLMUL_16 = (0xE << 18), -} rcc_pll_multiplier; - -/** - * @brief Identifies bus and clock line for a peripheral. - * - * Also generally useful as a unique identifier for that peripheral - * (or its corresponding device struct). - */ -typedef enum rcc_clk_id { - RCC_GPIOA, - RCC_GPIOB, - RCC_GPIOC, - RCC_GPIOD, -// RCC_AFIO, - RCC_ADC1, - RCC_ADC2, - RCC_ADC3, - RCC_USART1, - RCC_USART2, - RCC_USART3, - RCC_TIMER1, - RCC_TIMER2, - RCC_TIMER3, - RCC_TIMER4, - RCC_SPI1, - RCC_SPI2, - RCC_DMA1, - RCC_PWR, - RCC_BKP, - RCC_I2C1, - RCC_I2C2, - RCC_CRC, -// RCC_FLITF, -// RCC_SRAM, - RCC_GPIOE, - RCC_GPIOF, - RCC_GPIOG, - RCC_UART4, - RCC_UART5, - RCC_TIMER5, - RCC_TIMER6, - RCC_TIMER7, - RCC_TIMER8, - RCC_FSMC, - RCC_DAC, - RCC_DMA2, - RCC_SDIO, - RCC_SPI3, - RCC_TIMER9, - RCC_TIMER10, - RCC_TIMER11, - RCC_TIMER12, - RCC_TIMER13, - RCC_TIMER14, - RCC_USBFS, - RCC_SYSCFG, - RCC_SPI4 -} rcc_clk_id; - -void rcc_clk_init(rcc_sysclk_src sysclk_src, - rcc_pllsrc pll_src, - rcc_pll_multiplier pll_mul); -void rcc_clk_disable(rcc_clk_id device); -void rcc_clk_enable(rcc_clk_id device); -void rcc_reset_dev(rcc_clk_id device); - -void SetupClock72MHz(); -void SetupClock120MHz(); -void SetupClock168MHz(); - -typedef enum rcc_clk_domain { - RCC_APB1, - RCC_APB2, - RCC_AHB1, - RCC_AHB2, - RCC_AHB3 -} rcc_clk_domain; - -rcc_clk_domain rcc_dev_clk(rcc_clk_id device); - -uint32 rcc_dev_clk_speed(rcc_clk_id id); -uint32 rcc_dev_timer_clk_speed(rcc_clk_id id); - -/** - * Prescaler identifiers - * @see rcc_set_prescaler() - */ -typedef enum rcc_prescaler { - RCC_PRESCALER_AHB, - RCC_PRESCALER_APB1, - RCC_PRESCALER_APB2, - RCC_PRESCALER_USB, - RCC_PRESCALER_ADC -} rcc_prescaler; - -/** - * ADC prescaler dividers - * @see rcc_set_prescaler() - */ -typedef enum rcc_adc_divider { - RCC_ADCPRE_PCLK_DIV_2 = 0x0 << 14, - RCC_ADCPRE_PCLK_DIV_4 = 0x1 << 14, - RCC_ADCPRE_PCLK_DIV_6 = 0x2 << 14, - RCC_ADCPRE_PCLK_DIV_8 = 0x3 << 14, -} rcc_adc_divider; - -/** - * APB1 prescaler dividers - * @see rcc_set_prescaler() - */ -typedef enum rcc_apb1_divider { - RCC_APB1_HCLK_DIV_1 = 0x0 << 8, - RCC_APB1_HCLK_DIV_2 = 0x4 << 8, - RCC_APB1_HCLK_DIV_4 = 0x5 << 8, - RCC_APB1_HCLK_DIV_8 = 0x6 << 8, - RCC_APB1_HCLK_DIV_16 = 0x7 << 8, -} rcc_apb1_divider; - -/** - * APB2 prescaler dividers - * @see rcc_set_prescaler() - */ -typedef enum rcc_apb2_divider { - RCC_APB2_HCLK_DIV_1 = 0x0 << 11, - RCC_APB2_HCLK_DIV_2 = 0x4 << 11, - RCC_APB2_HCLK_DIV_4 = 0x5 << 11, - RCC_APB2_HCLK_DIV_8 = 0x6 << 11, - RCC_APB2_HCLK_DIV_16 = 0x7 << 11, -} rcc_apb2_divider; - -/** - * AHB prescaler dividers - * @see rcc_set_prescaler() - */ -typedef enum rcc_ahb_divider { - RCC_AHB_SYSCLK_DIV_1 = 0x0 << 4, - RCC_AHB_SYSCLK_DIV_2 = 0x8 << 4, - RCC_AHB_SYSCLK_DIV_4 = 0x9 << 4, - RCC_AHB_SYSCLK_DIV_8 = 0xA << 4, - RCC_AHB_SYSCLK_DIV_16 = 0xB << 4, - RCC_AHB_SYSCLK_DIV_32 = 0xC << 4, - RCC_AHB_SYSCLK_DIV_64 = 0xD << 4, - RCC_AHB_SYSCLK_DIV_128 = 0xD << 4, - RCC_AHB_SYSCLK_DIV_256 = 0xE << 4, - RCC_AHB_SYSCLK_DIV_512 = 0xF << 4, -} rcc_ahb_divider; - -void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider); - - -/** - * @brief Start the low speed internal oscillatior - */ -static inline void rcc_start_lsi(void) { - *bb_perip(&RCC_BASE->CSR, RCC_CSR_LSION_BIT) = 1; - while (*bb_perip(&RCC_BASE->CSR, RCC_CSR_LSIRDY_BIT) == 0); -} - -/* FIXME [0.0.13] Just have data point to an rcc_pll_multiplier! */ -/** - * @brief Start the low speed external oscillatior - */ -static inline void rcc_start_lse(void) { - bb_peri_set_bit(&RCC_BASE->BDCR, RCC_BDCR_LSEBYP_BIT, 0); - bb_peri_set_bit(&RCC_BASE->BDCR, RCC_BDCR_LSEON_BIT, 1); - while (bb_peri_get_bit(&RCC_BASE->BDCR, RCC_BDCR_LSERDY_BIT ) == 0); -} - -/* - * Deprecated bits. - */ -static inline void rcc_start_hse(void) { // Added to support RTClock -// *bb_perip(&RCC_BASE->CR, RCC_CR_HSEON_BIT) = 1; - while (bb_peri_get_bit(&RCC_BASE->CR, RCC_CR_HSERDY_BIT) == 0); -} - - - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif diff --git a/STM32F4/cores/maple/libmaple/usbF4/usb.c b/STM32F4/cores/maple/libmaple/usbF4/usb.c index 263e76f..c013f04 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/usb.c +++ b/STM32F4/cores/maple/libmaple/usbF4/usb.c @@ -11,8 +11,8 @@ USB_OTG_CORE_HANDLE USB_OTG_dev; void setupUSB (void) { - #define USB_DISC_DEV GPIOD - #define USB_DISC_PIN 11 + #define USB_DISC_DEV GPIOA + #define USB_DISC_PIN 12 gpio_set_mode(USB_DISC_DEV, USB_DISC_PIN, GPIO_OUTPUT_OD); // ala42 #ifdef USB_DISC_OD diff --git a/STM32F4/cores/maple/wirish_types.h b/STM32F4/cores/maple/wirish_types.h index 2d6d6a9..55364ab 100644 --- a/STM32F4/cores/maple/wirish_types.h +++ b/STM32F4/cores/maple/wirish_types.h @@ -48,7 +48,7 @@ * @brief Stores STM32-specific information related to a given Maple pin. * @see PIN_MAP */ -#ifdef BOARD_black_f4 +#ifdef BOARD_generic_f407v // restructure members to build consecutive pairs typedef struct stm32_pin_info { gpio_dev *gpio_device; /**< Maple pin's GPIO device */ diff --git a/STM32F4/variants/black_f407vet6/black_f4.h b/STM32F4/variants/generic_f407v/black_f4.h.old similarity index 99% rename from STM32F4/variants/black_f407vet6/black_f4.h rename to STM32F4/variants/generic_f407v/black_f4.h.old index 6f5d3da..20bb174 100644 --- a/STM32F4/variants/black_f407vet6/black_f4.h +++ b/STM32F4/variants/generic_f407v/black_f4.h.old @@ -121,7 +121,7 @@ PB0,PB1,PB2,PB3,PB4,PB5,PB6,PB7,PB8,PB9,PB10,PB11,PB12,PB13,PB14,PB15, PC0,PC1,PC2,PC3,PC4,PC5,PC6,PC7,PC8,PC9,PC10,PC11,PC12,PC13,PC14,PC15, PD0,PD1,PD2,PD3,PD4,PD5,PD6,PD7,PD8,PD9,PD10,PD11,PD12,PD13,PD14,PD15, PE0,PE1,PE2,PE3,PE4,PE5,PE6,PE7,PE8,PE9,PE10,PE11,PE12,PE13,PE14,PE15, -#if 0 +#if 0 // not available on LQFP100 package PF0,PF1,PF2,PF3,PF4,PF5,PF6,PF7,PF8,PF9,PF10,PF11,PF12,PF13,PF14,PF15, PG0,PG1,PG2,PG3,PG4,PG5,PG6,PG7,PG8,PG9,PG10,PG11,PG12,PG13,PG14,PG15 #endif diff --git a/STM32F4/variants/black_f407vet6/black_f4.cpp b/STM32F4/variants/generic_f407v/generic_f407v.cpp similarity index 99% rename from STM32F4/variants/black_f407vet6/black_f4.cpp rename to STM32F4/variants/generic_f407v/generic_f407v.cpp index 78d37aa..1199064 100644 --- a/STM32F4/variants/black_f407vet6/black_f4.cpp +++ b/STM32F4/variants/generic_f407v/generic_f407v.cpp @@ -25,14 +25,14 @@ *****************************************************************************/ /** - * @file black_f4.cpp + * @file generic_f407v.cpp * @author ala42 - * @brief black_f4 board file. + * @brief generic_f407v board file. */ -#ifdef BOARD_black_f4 +#ifdef BOARD_generic_f407v -#include "black_f4.h" +#include "generic_f407v.h" //#include "fsmc.h" #include "gpio.h" diff --git a/STM32F4/variants/generic_f407v/generic_f407v.h b/STM32F4/variants/generic_f407v/generic_f407v.h new file mode 100644 index 0000000..15e93e4 --- /dev/null +++ b/STM32F4/variants/generic_f407v/generic_f407v.h @@ -0,0 +1,130 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file generic_f407v.h + * @author Marti Bolivar + * @brief Private include file for Maple Native in boards.h + * + * See maple.h for more information on these definitions. + */ + +#ifndef _BOARD_GENERIC_F407V_H_ +#define _BOARD_GENERIC_F407V_H_ + +#define Port2Pin(port, bit) ((port-'A')*16+bit) + +#define CYCLES_PER_MICROSECOND 168 + + +#undef STM32_PCLK1 +#undef STM32_PCLK2 +#define STM32_PCLK1 (CYCLES_PER_MICROSECOND*1000000/4) +#define STM32_PCLK2 (CYCLES_PER_MICROSECOND*1000000/2) + +#define SYSTICK_RELOAD_VAL (CYCLES_PER_MICROSECOND*1000-1) + +#define BOARD_USB_DM_PIN PA11 +#define BOARD_USB_DP_PIN PA12 + +#define BOARD_LED_PIN PA6 //Port2Pin('A', 6) +#define BOARD_LED2_PIN PA7 //Port2Pin('A', 7) +#define BOARD_BUTTON1_PIN PA0 //Port2Pin('A', 0) +#define BOARD_BUTTON2_PIN PE4 //Port2Pin('E', 4) +#define BOARD_BUTTON3_PIN PE3 //Port2Pin('E', 3) + +#define BOARD_NR_USARTS 5 +#define BOARD_USART1_TX_PIN PA9 //Port2Pin('A', 9) +#define BOARD_USART1_RX_PIN PA10 //Port2Pin('A',10) +#define BOARD_USART2_TX_PIN PA2 //Port2Pin('A', 2) +#define BOARD_USART2_RX_PIN PA3 //Port2Pin('A', 3) +#define BOARD_USART3_TX_PIN PB10 //Port2Pin('B',10) +#define BOARD_USART3_RX_PIN PB11 //Port2Pin('B',11) +#define BOARD_UART4_TX_PIN PA0 //Port2Pin('A', 0) +#define BOARD_UART4_RX_PIN PA1 //Port2Pin('A', 1) +#define BOARD_UART5_TX_PIN PC12 //Port2Pin('C',12) +#define BOARD_UART5_RX_PIN PD2 //Port2Pin('D', 2) + +#define BOARD_NR_SPI 3 +#define BOARD_SPI1_NSS_PIN PA4 //Port2Pin('A', 4) +#define BOARD_SPI1_SCK_PIN PA5 //Port2Pin('A', 5) +#define BOARD_SPI1_MISO_PIN PA6 //Port2Pin('A', 6) +#define BOARD_SPI1_MOSI_PIN PA7 //Port2Pin('A', 7) +#define BOARD_SPI1A_NSS_PIN PA15 //Port2Pin('A',15) +#define BOARD_SPI1A_SCK_PIN PB3 //Port2Pin('B', 3) +#define BOARD_SPI1A_MISO_PIN PB4 //Port2Pin('B', 4) +#define BOARD_SPI1A_MOSI_PIN PB5 //Port2Pin('B', 5) + +#define BOARD_SPI2_NSS_PIN PB12 //Port2Pin('B',12) +#define BOARD_SPI2_SCK_PIN PB13 //Port2Pin('B',13) +#define BOARD_SPI2_MISO_PIN PB14 //Port2Pin('B',14) +#define BOARD_SPI2_MOSI_PIN PB15 //Port2Pin('B',15) +#define BOARD_SPI2A_NSS_PIN PB9 //Port2Pin('B', 9) +#define BOARD_SPI2A_SCK_PIN PB10 //Port2Pin('B',10) +#define BOARD_SPI2A_MISO_PIN PC2 //Port2Pin('C', 2) +#define BOARD_SPI2A_MOSI_PIN pc3 //Port2Pin('C', 3) + +#define BOARD_SPI3_NSS_PIN PA15 //Port2Pin('A',15) +#define BOARD_SPI3_SCK_PIN PB3 //Port2Pin('B', 3) +#define BOARD_SPI3_MISO_PIN PB4 //Port2Pin('B', 4) +#define BOARD_SPI3_MOSI_PIN PB5 //Port2Pin('B', 5) +/* overlap with the SDIO interface for SD card +#define BOARD_SPI3A_NSS_PIN Port2Pin('A', 4) +#define BOARD_SPI3A_SCK_PIN Port2Pin('C',10) +#define BOARD_SPI3A_MISO_PIN Port2Pin('C',11) +#define BOARD_SPI3A_MOSI_PIN Port2Pin('C',12) +*/ +#define BOARD_SDIO_D0 PC8 //Port2Pin('C', 8) +#define BOARD_SDIO_D1 PC9 //Port2Pin('C', 9) +#define BOARD_SDIO_D2 PC10 //Port2Pin('C',10) +#define BOARD_SDIO_D3 PC11 //Port2Pin('C',11) +#define BOARD_SDIO_CK PC12 //Port2Pin('C',12) +#define BOARD_SDIO_CMD PD2 //Port2Pin('D', 2) + +#define BOARD_NR_GPIO_PINS 80 +#define BOARD_NR_PWM_PINS 22 +#define BOARD_NR_ADC_PINS 16 +#define BOARD_NR_USED_PINS 22 +#define BOARD_JTMS_SWDIO_PIN PA13 //Port2Pin('A',13) +#define BOARD_JTCK_SWCLK_PIN PA14 //Port2Pin('A',14) +#define BOARD_JTDI_PIN PA15 //Port2Pin('A',15) +#define BOARD_JTDO_PIN PB3 //Port2Pin('B', 3) +#define BOARD_NJTRST_PIN PB4 //Port2Pin('B', 4) + + +enum { +PA0,PA1,PA2,PA3,PA4,PA5,PA6,PA7,PA8,PA9,PA10,PA11,PA12,PA13,PA14,PA15, +PB0,PB1,PB2,PB3,PB4,PB5,PB6,PB7,PB8,PB9,PB10,PB11,PB12,PB13,PB14,PB15, +PC0,PC1,PC2,PC3,PC4,PC5,PC6,PC7,PC8,PC9,PC10,PC11,PC12,PC13,PC14,PC15, +PD0,PD1,PD2,PD3,PD4,PD5,PD6,PD7,PD8,PD9,PD10,PD11,PD12,PD13,PD14,PD15, +PE0,PE1,PE2,PE3,PE4,PE5,PE6,PE7,PE8,PE9,PE10,PE11,PE12,PE13,PE14,PE15, +#if 0 // not available on LQFP100 package +PF0,PF1,PF2,PF3,PF4,PF5,PF6,PF7,PF8,PF9,PF10,PF11,PF12,PF13,PF14,PF15, +PG0,PG1,PG2,PG3,PG4,PG5,PG6,PG7,PG8,PG9,PG10,PG11,PG12,PG13,PG14,PG15 +#endif +}; + +#endif diff --git a/STM32F4/variants/black_f407vet6/ld/common.inc b/STM32F4/variants/generic_f407v/ld/common.inc similarity index 100% rename from STM32F4/variants/black_f407vet6/ld/common.inc rename to STM32F4/variants/generic_f407v/ld/common.inc diff --git a/STM32F4/variants/black_f407vet6/ld/extra_libs.inc b/STM32F4/variants/generic_f407v/ld/extra_libs.inc similarity index 100% rename from STM32F4/variants/black_f407vet6/ld/extra_libs.inc rename to STM32F4/variants/generic_f407v/ld/extra_libs.inc diff --git a/STM32F4/variants/black_f407vet6/ld/flash.ld b/STM32F4/variants/generic_f407v/ld/flash.ld similarity index 100% rename from STM32F4/variants/black_f407vet6/ld/flash.ld rename to STM32F4/variants/generic_f407v/ld/flash.ld diff --git a/STM32F4/variants/black_f407vet6/ld/jtag.ld b/STM32F4/variants/generic_f407v/ld/jtag.ld similarity index 100% rename from STM32F4/variants/black_f407vet6/ld/jtag.ld rename to STM32F4/variants/generic_f407v/ld/jtag.ld diff --git a/STM32F4/variants/black_f407vet6/ld/names.inc b/STM32F4/variants/generic_f407v/ld/names.inc similarity index 100% rename from STM32F4/variants/black_f407vet6/ld/names.inc rename to STM32F4/variants/generic_f407v/ld/names.inc diff --git a/STM32F4/variants/black_f407vet6/ld/ram.ld b/STM32F4/variants/generic_f407v/ld/ram.ld similarity index 100% rename from STM32F4/variants/black_f407vet6/ld/ram.ld rename to STM32F4/variants/generic_f407v/ld/ram.ld diff --git a/STM32F4/variants/black_f407vet6/ld/vector_symbols.inc b/STM32F4/variants/generic_f407v/ld/vector_symbols.inc similarity index 100% rename from STM32F4/variants/black_f407vet6/ld/vector_symbols.inc rename to STM32F4/variants/generic_f407v/ld/vector_symbols.inc diff --git a/STM32F4/variants/black_f407vet6/pins_arduino.h b/STM32F4/variants/generic_f407v/pins_arduino.h similarity index 100% rename from STM32F4/variants/black_f407vet6/pins_arduino.h rename to STM32F4/variants/generic_f407v/pins_arduino.h diff --git a/STM32F4/variants/black_f407vet6/stm32_isrs.S b/STM32F4/variants/generic_f407v/stm32_isrs.S similarity index 100% rename from STM32F4/variants/black_f407vet6/stm32_isrs.S rename to STM32F4/variants/generic_f407v/stm32_isrs.S diff --git a/STM32F4/variants/black_f407vet6/stm32_vector_table.S b/STM32F4/variants/generic_f407v/stm32_vector_table.S similarity index 100% rename from STM32F4/variants/black_f407vet6/stm32_vector_table.S rename to STM32F4/variants/generic_f407v/stm32_vector_table.S diff --git a/STM32F4/variants/black_f407vet6/variant.h b/STM32F4/variants/generic_f407v/variant.h similarity index 100% rename from STM32F4/variants/black_f407vet6/variant.h rename to STM32F4/variants/generic_f407v/variant.h diff --git a/STM32F4/variants/black_f407vet6/wirish/start.S b/STM32F4/variants/generic_f407v/wirish/start.S similarity index 100% rename from STM32F4/variants/black_f407vet6/wirish/start.S rename to STM32F4/variants/generic_f407v/wirish/start.S diff --git a/STM32F4/variants/black_f407vet6/wirish/start_c.c b/STM32F4/variants/generic_f407v/wirish/start_c.c similarity index 100% rename from STM32F4/variants/black_f407vet6/wirish/start_c.c rename to STM32F4/variants/generic_f407v/wirish/start_c.c From cbfb87222fec84af899c11d2da8195fe92ad098f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Giorgiogg=C3=AC?= Date: Tue, 18 Apr 2017 12:24:06 +0200 Subject: [PATCH 020/351] Fix indentation --- STM32F1/cores/maple/usb_serial.h | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/STM32F1/cores/maple/usb_serial.h b/STM32F1/cores/maple/usb_serial.h index 96bbefc..c2de1c5 100644 --- a/STM32F1/cores/maple/usb_serial.h +++ b/STM32F1/cores/maple/usb_serial.h @@ -44,19 +44,19 @@ public: void begin(void); - // Roger Clark. Added dummy function so that existing Arduino sketches which specify baud rate will compile. - void begin(unsigned long); - void begin(unsigned long, uint8_t); + // Roger Clark. Added dummy function so that existing Arduino sketches which specify baud rate will compile. + void begin(unsigned long); + void begin(unsigned long, uint8_t); void end(void); - operator bool() { return true; } // Roger Clark. This is needed because in cardinfo.ino it does if (!Serial) . It seems to be a work around for the Leonardo that we needed to implement just to be compliant with the API + operator bool() { return true; } // Roger Clark. This is needed because in cardinfo.ino it does if (!Serial) . It seems to be a work around for the Leonardo that we needed to implement just to be compliant with the API virtual int available(void);// Changed to virtual uint32 read(uint8 * buf, uint32 len); - // uint8 read(void); + // uint8 read(void); - // Roger Clark. added functions to support Arduino 1.0 API + // Roger Clark. added functions to support Arduino 1.0 API virtual int peek(void); virtual int read(void); int availableForWrite(void); @@ -74,8 +74,7 @@ public: }; #ifdef SERIAL_USB - extern USBSerial Serial; + extern USBSerial Serial; #endif #endif - From 0be991b434abc14f7ec9c91252977b60350d263c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Giorgiogg=C3=AC?= Date: Tue, 18 Apr 2017 12:43:01 +0200 Subject: [PATCH 021/351] Update usb_serial.h --- STM32F1/cores/maple/usb_serial.h | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/STM32F1/cores/maple/usb_serial.h b/STM32F1/cores/maple/usb_serial.h index c2de1c5..ceb81e1 100644 --- a/STM32F1/cores/maple/usb_serial.h +++ b/STM32F1/cores/maple/usb_serial.h @@ -49,8 +49,6 @@ public: void begin(unsigned long, uint8_t); void end(void); - operator bool() { return true; } // Roger Clark. This is needed because in cardinfo.ino it does if (!Serial) . It seems to be a work around for the Leonardo that we needed to implement just to be compliant with the API - virtual int available(void);// Changed to virtual uint32 read(uint8 * buf, uint32 len); @@ -69,8 +67,20 @@ public: uint8 getRTS(); uint8 getDTR(); - uint8 isConnected(); uint8 pending(); + + /* SukkoPera: This is the Arduino way to check if an USB CDC serial + * connection is open. + + * Used for instance in cardinfo.ino. + */ + operator bool(); + + /* Old libmaple way to check for serial connection. + * + * Deprecated, use the above. + */ + uint8 isConnected() { return (bool) *this; } }; #ifdef SERIAL_USB From 38525521fd9ea4713970073326c21b8e9c54c09b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Giorgiogg=C3=AC?= Date: Tue, 18 Apr 2017 12:44:10 +0200 Subject: [PATCH 022/351] Update usb_serial.cpp --- STM32F1/cores/maple/usb_serial.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/STM32F1/cores/maple/usb_serial.cpp b/STM32F1/cores/maple/usb_serial.cpp index 5eaf70e..2f7dadd 100644 --- a/STM32F1/cores/maple/usb_serial.cpp +++ b/STM32F1/cores/maple/usb_serial.cpp @@ -178,10 +178,6 @@ uint8 USBSerial::pending(void) { return usb_cdcacm_get_pending(); } -uint8 USBSerial::isConnected(void) { - return usb_is_connected(USBLIB) && usb_is_configured(USBLIB) && usb_cdcacm_get_dtr(); -} - uint8 USBSerial::getDTR(void) { return usb_cdcacm_get_dtr(); } @@ -190,6 +186,10 @@ uint8 USBSerial::getRTS(void) { return usb_cdcacm_get_rts(); } +uint8 USBSerial::operator bool() { + return usb_is_connected(USBLIB) && usb_is_configured(USBLIB) && usb_cdcacm_get_dtr(); +} + #if BOARD_HAVE_SERIALUSB #ifdef SERIAL_USB USBSerial Serial; From 81b1b08b95695256f6253bd236c4ee4755eb0089 Mon Sep 17 00:00:00 2001 From: SukkoPera Date: Tue, 18 Apr 2017 23:25:36 +0200 Subject: [PATCH 023/351] Fix return type --- STM32F1/cores/maple/usb_serial.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/cores/maple/usb_serial.cpp b/STM32F1/cores/maple/usb_serial.cpp index 2f7dadd..85c7024 100644 --- a/STM32F1/cores/maple/usb_serial.cpp +++ b/STM32F1/cores/maple/usb_serial.cpp @@ -186,7 +186,7 @@ uint8 USBSerial::getRTS(void) { return usb_cdcacm_get_rts(); } -uint8 USBSerial::operator bool() { +USBSerial::operator bool() { return usb_is_connected(USBLIB) && usb_is_configured(USBLIB) && usb_cdcacm_get_dtr(); } From 0590f27afaea2e007f7f5f672add36f462e509d1 Mon Sep 17 00:00:00 2001 From: Oleksandr Masliuchenko Date: Sat, 22 Apr 2017 16:27:30 +0300 Subject: [PATCH 024/351] 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 83c834091c99589ae18cb374975fe20454687b81 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Wed, 26 Apr 2017 23:19:20 +0200 Subject: [PATCH 025/351] reworked gpio pin handling functions --- STM32F4/boards.txt | 11 +++ STM32F4/cores/maple/boards.cpp | 4 + STM32F4/cores/maple/boards.h | 23 ++--- .../cores/maple/libmaple/HardwareSerial.cpp | 28 +++--- STM32F4/cores/maple/libmaple/HardwareSerial.h | 2 +- STM32F4/cores/maple/libmaple/dac.c | 4 +- STM32F4/cores/maple/libmaple/fsmc.c | 53 +++++----- STM32F4/cores/maple/libmaple/gpio.h | 99 ++++++++++++++++++- STM32F4/cores/maple/libmaple/gpioF4.c | 24 +++-- .../maple/libmaple/{gpioF4.h => gpio_def.h} | 76 ++------------ STM32F4/cores/maple/libmaple/i2c.c | 40 ++++---- STM32F4/cores/maple/libmaple/i2c.h | 2 +- STM32F4/cores/maple/libmaple/libmaple_types.h | 3 + STM32F4/cores/maple/libmaple/rccF4.c | 5 +- STM32F4/cores/maple/libmaple/spi.h | 12 +-- STM32F4/cores/maple/libmaple/spiF4.h | 11 --- STM32F4/cores/maple/libmaple/spi_f4.c | 26 +++-- .../cores/maple/libmaple/usbF4/VCP/usb_bsp.c | 16 +-- STM32F4/cores/maple/libmaple/usbF4/usb.c | 13 ++- STM32F4/cores/maple/libmaple/util.c | 6 +- STM32F4/cores/maple/usb_serial.cpp | 4 + STM32F4/cores/maple/usb_serial.h | 5 + STM32F4/cores/maple/wirish.h | 4 +- STM32F4/cores/maple/wirish_digital.cpp | 17 ++-- STM32F4/cores/maple/wirish_types.h | 11 ++- STM32F4/platform.txt | 2 +- .../variants/generic_f407v/generic_f407v.h | 2 +- STM32F4/variants/generic_f407v/ld/jtag.ld | 2 +- 28 files changed, 276 insertions(+), 229 deletions(-) rename STM32F4/cores/maple/libmaple/{gpioF4.h => gpio_def.h} (91%) diff --git a/STM32F4/boards.txt b/STM32F4/boards.txt index df9f2b4..04bfd0f 100644 --- a/STM32F4/boards.txt +++ b/STM32F4/boards.txt @@ -1,5 +1,7 @@ # +menu.usb_cfg=USB configuration + ############################################################## discovery_f407.name=STM32 Discovery F407 @@ -57,6 +59,15 @@ generic_f407v.build.error_led_port=GPIOA generic_f407v.build.error_led_pin=7 generic_f407v.build.board=STM32GenericF407VET6 +generic_f407v.menu.usb_cfg.usb_nc=USB inactive +generic_f407v.menu.usb_cfg.usb_nc.build.cpu_flags=-DUSB_NC + +generic_f407v.menu.usb_cfg.usb_serial=USB serial (CDC) +generic_f407v.menu.usb_cfg.usb_serial.build.cpu_flags=-DSERIAL_USB + +generic_f407v.menu.usb_cfg.usb_msc=USB Mass Storage (MSC) +generic_f407v.menu.usb_cfg.usb_msc.build.cpu_flags=-DUSB_MSC + ############################################################## stm32f4stamp.name=STM32F4Stamp F405 diff --git a/STM32F4/cores/maple/boards.cpp b/STM32F4/cores/maple/boards.cpp index c8ba978..fc453fe 100644 --- a/STM32F4/cores/maple/boards.cpp +++ b/STM32F4/cores/maple/boards.cpp @@ -41,6 +41,7 @@ #include "adc.h" #include "timer.h" #include "usb.h" +#include "usb_serial.h" static void setupFlash(void); @@ -67,7 +68,10 @@ void init(void) { setupADC(); setupTimers(); +#ifdef SERIAL_USB setupUSB(); + SerialUSB.begin(); +#endif } /* You could farm this out to the files in boards/ if e.g. it takes diff --git a/STM32F4/cores/maple/boards.h b/STM32F4/cores/maple/boards.h index e123341..50fd89d 100644 --- a/STM32F4/cores/maple/boards.h +++ b/STM32F4/cores/maple/boards.h @@ -40,7 +40,6 @@ #define _BOARDS_H_ #include "libmaple.h" -#include "gpio.h" #include "timer.h" #include "wirish_types.h" @@ -55,9 +54,12 @@ enum { D32, D33, D34, D35, D36, D37, D38, D39, D40, D41, D42, D43, D44, D45, D46, D47, D48, D49, D50, D51, D52, D53, D54, D55, D56, D57, D58, D59, D60, D61, D62, D63, D64, D65, D66, D67, D68, D69, D70, D71, D72, D73, D74, D75, D76, +#if 0 // not available on LQFP100 package D77, D78, D79, D80, D81, D82, D83, D84, D85, D86, D87, D88, D89, D90, D91, D92, D93, D94, D95, D96, D97, D98, D99, D100, D101, D102, D103, D104, D105, - D106, D107, D108, D109, D110, D111, }; + D106, D107, D108, D109, D110, D111, +#endif // not available on LQFP100 package +}; /** * @brief Maps each Maple pin to a corresponding stm32_pin_info. @@ -115,26 +117,13 @@ extern void boardInit(void); * @return true if the given pin is in boardUsedPins, and false otherwise. * @see boardUsedPins */ -bool boardUsesPin(uint8 pin); +extern bool boardUsesPin(uint8 pin); /* Include the appropriate private header from boards/: */ /* FIXME HACK put boards/ before these paths once IDE uses make. */ -#ifdef BOARD_maple -#include "maple.h" -#elif defined(BOARD_maple_native) -#include "maple_native.h" -#elif defined(BOARD_maple_mini) -#include "maple_mini.h" -#elif defined(BOARD_maple_RET6) -/* - * **NOT** MAPLE REV6. This the **Maple RET6 EDITION**, which is a - * Maple with an STM32F103RET6 (...RET6) instead of an STM32F103RBT6 - * (...RBT6) on it. Maple Rev6 (as of March 2011) DOES NOT EXIST. - */ -#include "maple_RET6.h" -#elif defined(BOARD_aeroquad32) || defined(BOARD_aeroquad32f1) +#if defined(BOARD_aeroquad32) || defined(BOARD_aeroquad32f1) #include "aeroquad32.h" #elif defined(BOARD_aeroquad32mini) #include "aeroquad32mini.h" diff --git a/STM32F4/cores/maple/libmaple/HardwareSerial.cpp b/STM32F4/cores/maple/libmaple/HardwareSerial.cpp index 475116b..f9387d1 100644 --- a/STM32F4/cores/maple/libmaple/HardwareSerial.cpp +++ b/STM32F4/cores/maple/libmaple/HardwareSerial.cpp @@ -56,19 +56,19 @@ #define RX5 BOARD_UART5_RX_PIN #endif -HardwareSerial Serial(USART1, TX1, RX1); +HardwareSerial Serial1(USART1, TX1, RX1); #ifdef TX2 -HardwareSerial Serial1(USART2, TX2, RX2); +HardwareSerial Serial2(USART2, TX2, RX2); #endif #ifdef TX3 -HardwareSerial Serial2(USART3, TX3, RX3); +HardwareSerial Serial3(USART3, TX3, RX3); #endif #if defined(STM32_HIGH_DENSITY) && !defined(BOARD_maple_RET6) -HardwareSerial Serial3(UART4, TX4, RX4); -HardwareSerial Serial4(UART5, TX5, RX5); +HardwareSerial Serial4(UART4, TX4, RX4); +HardwareSerial Serial5(UART5, TX5, RX5); #endif HardwareSerial::HardwareSerial(usart_dev *usart_device, @@ -90,25 +90,23 @@ void HardwareSerial::begin(uint32 baud) { return; } - const stm32_pin_info *txi = &PIN_MAP[tx_pin]; - const stm32_pin_info *rxi = &PIN_MAP[rx_pin]; #ifdef STM32F4 // int af = 7<<8; if (usart_device == UART4 || usart_device == UART5) { - gpio_set_af_mode(txi->gpio_device, txi->gpio_bit, 8); - gpio_set_af_mode(rxi->gpio_device, rxi->gpio_bit, 8); + gpio_set_af_mode(tx_pin, 8); + gpio_set_af_mode(rx_pin, 8); } else { - gpio_set_af_mode(txi->gpio_device, txi->gpio_bit, 7); - gpio_set_af_mode(rxi->gpio_device, rxi->gpio_bit, 7); + gpio_set_af_mode(tx_pin, 7); + gpio_set_af_mode(rx_pin, 7); } - gpio_set_mode(txi->gpio_device, txi->gpio_bit, (gpio_pin_mode)(GPIO_AF_OUTPUT_PP | GPIO_PUPD_INPUT_PU | 0x700)); - gpio_set_mode(rxi->gpio_device, rxi->gpio_bit, (gpio_pin_mode)(GPIO_MODE_AF | GPIO_PUPD_INPUT_PU | 0x700)); + gpio_set_mode(tx_pin, (gpio_pin_mode)(GPIO_AF_OUTPUT_PP | GPIO_PUPD_INPUT_PU | 0x700)); + gpio_set_mode(rx_pin, (gpio_pin_mode)(GPIO_MODE_AF | GPIO_PUPD_INPUT_PU | 0x700)); //gpio_set_mode(txi->gpio_device, txi->gpio_bit, (gpio_pin_mode)(GPIO_PUPD_INPUT_PU)); //gpio_set_mode(rxi->gpio_device, rxi->gpio_bit, (gpio_pin_mode)(GPIO_PUPD_INPUT_PU)); #else - gpio_set_mode(txi->gpio_device, txi->gpio_bit, GPIO_AF_OUTPUT_PP); - gpio_set_mode(rxi->gpio_device, rxi->gpio_bit, GPIO_INPUT_FLOATING); + gpio_set_mode(tx_pin, GPIO_AF_OUTPUT_PP); + gpio_set_mode(rx_pin, GPIO_INPUT_FLOATING); #endif #if 0 if (txi->timer_device != NULL) { diff --git a/STM32F4/cores/maple/libmaple/HardwareSerial.h b/STM32F4/cores/maple/libmaple/HardwareSerial.h index c09fe54..d7e8a3d 100644 --- a/STM32F4/cores/maple/libmaple/HardwareSerial.h +++ b/STM32F4/cores/maple/libmaple/HardwareSerial.h @@ -75,12 +75,12 @@ private: uint8 rx_pin; }; -extern HardwareSerial Serial; extern HardwareSerial Serial1; extern HardwareSerial Serial2; #if defined(STM32_HIGH_DENSITY) && !defined(BOARD_maple_RET6) extern HardwareSerial Serial3; extern HardwareSerial Serial4; +extern HardwareSerial Serial5; #endif extern HardwareSerial &SerialDebug; #endif diff --git a/STM32F4/cores/maple/libmaple/dac.c b/STM32F4/cores/maple/libmaple/dac.c index 264e4e2..3853f90 100644 --- a/STM32F4/cores/maple/libmaple/dac.c +++ b/STM32F4/cores/maple/libmaple/dac.c @@ -126,11 +126,11 @@ void dac_enable_channel(const dac_dev *dev, uint8 channel) { */ switch (channel) { case 1: - gpio_set_mode(GPIOA, 4, GPIO_INPUT_ANALOG); + gpio_set_mode((uint8_t)PA4, GPIO_INPUT_ANALOG); dev->regs->CR |= DAC_CR_EN1; break; case 2: - gpio_set_mode(GPIOA, 5, GPIO_INPUT_ANALOG); + gpio_set_mode((uint8_t)PA5, GPIO_INPUT_ANALOG); dev->regs->CR |= DAC_CR_EN2; break; } diff --git a/STM32F4/cores/maple/libmaple/fsmc.c b/STM32F4/cores/maple/libmaple/fsmc.c index 06ca7df..42b0d77 100644 --- a/STM32F4/cores/maple/libmaple/fsmc.c +++ b/STM32F4/cores/maple/libmaple/fsmc.c @@ -39,27 +39,28 @@ */ void fsmc_sram_init_gpios(void) { /* Data lines... */ - gpio_set_mode(GPIOD, 0, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOD, 1, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOD, 8, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOD, 9, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOD, 10, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOD, 14, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOD, 15, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOE, 7, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOE, 8, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOE, 9, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOE, 10, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOE, 11, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOE, 12, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOE, 13, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOE, 14, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOE, 15, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PD0, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PD1, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PD8, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PD9, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PD10, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PD14, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PD15, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PE7, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PE8, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PE9, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PE10, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PE11, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PE12, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PE13, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PE14, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PE15, GPIO_AF_OUTPUT_PP); /* Address lines... */ - gpio_set_mode(GPIOD, 11, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOD, 12, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOD, 13, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PD11, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PD12, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PD13, GPIO_AF_OUTPUT_PP); +#if 0 // not available on LQFP package gpio_set_mode(GPIOF, 0, GPIO_AF_OUTPUT_PP); gpio_set_mode(GPIOF, 1, GPIO_AF_OUTPUT_PP); gpio_set_mode(GPIOF, 2, GPIO_AF_OUTPUT_PP); @@ -76,18 +77,20 @@ void fsmc_sram_init_gpios(void) { gpio_set_mode(GPIOG, 3, GPIO_AF_OUTPUT_PP); gpio_set_mode(GPIOG, 4, GPIO_AF_OUTPUT_PP); gpio_set_mode(GPIOG, 5, GPIO_AF_OUTPUT_PP); - +#endif // not available on LQFP package /* And control lines... */ - gpio_set_mode(GPIOD, 4, GPIO_AF_OUTPUT_PP); // NOE - gpio_set_mode(GPIOD, 5, GPIO_AF_OUTPUT_PP); // NWE + gpio_set_mode(PD4, GPIO_AF_OUTPUT_PP); // NOE + gpio_set_mode(PD5, GPIO_AF_OUTPUT_PP); // NWE - gpio_set_mode(GPIOD, 7, GPIO_AF_OUTPUT_PP); // NE1 + gpio_set_mode(PD7, GPIO_AF_OUTPUT_PP); // NE1 +#if 0 // not available on LQFP package gpio_set_mode(GPIOG, 9, GPIO_AF_OUTPUT_PP); // NE2 gpio_set_mode(GPIOG, 10, GPIO_AF_OUTPUT_PP); // NE3 gpio_set_mode(GPIOG, 12, GPIO_AF_OUTPUT_PP); // NE4 +#endif // not available on LQFP package - gpio_set_mode(GPIOE, 0, GPIO_AF_OUTPUT_PP); // NBL0 - gpio_set_mode(GPIOE, 1, GPIO_AF_OUTPUT_PP); // NBL1 + gpio_set_mode(PE0, GPIO_AF_OUTPUT_PP); // NBL0 + gpio_set_mode(PE1, GPIO_AF_OUTPUT_PP); // NBL1 } #endif /* STM32_HIGH_DENSITY */ diff --git a/STM32F4/cores/maple/libmaple/gpio.h b/STM32F4/cores/maple/libmaple/gpio.h index f065c71..4c0ba71 100644 --- a/STM32F4/cores/maple/libmaple/gpio.h +++ b/STM32F4/cores/maple/libmaple/gpio.h @@ -31,5 +31,102 @@ * (AFIO) prototypes, defines, and inlined access functions. */ +#ifndef _GPIO_H_ +#define _GPIO_H_ + +#include "libmaple.h" +#include "boards.h" + +#ifdef __cplusplus +extern "C"{ +#endif + + +/** + * @brief Get a GPIO port's corresponding afio_exti_port. + * @param dev GPIO device whose afio_exti_port to return. + */ +static inline afio_exti_port gpio_exti_port(gpio_dev *dev) { + return dev->exti_port; +} + +/** + * Set or reset a GPIO pin. + * + * Pin must have previously been configured to output mode. + * + * @param dev GPIO device whose pin to set. + * @param pin Pin on to set or reset + * @param val If true, set the pin. If false, reset the pin. + */ +static inline void gpio_write_pin(uint8_t pin, uint8 val) { + if (val) { + (PIN_MAP[pin].gpio_device)->regs->BSRRL = BIT(PIN_MAP[pin].gpio_bit); + } else { + (PIN_MAP[pin].gpio_device)->regs->BSRRH = BIT(PIN_MAP[pin].gpio_bit); + } +} + +static inline void gpio_set_pin(uint8_t pin) { + (PIN_MAP[pin].gpio_device)->regs->BSRRL = BIT(PIN_MAP[pin].gpio_bit); +} + +static inline void gpio_clear_pin(uint8_t pin) { + (PIN_MAP[pin].gpio_device)->regs->BSRRH = BIT(PIN_MAP[pin].gpio_bit); +} + +/** + * Determine whether or not a GPIO pin is set. + * + * Pin must have previously been configured to input mode. + * + * @param dev GPIO device whose pin to test. + * @param pin Pin on dev to test. + * @return True if the pin is set, false otherwise. + */ +static inline uint32 gpio_read_pin(uint8_t pin) { + return (PIN_MAP[pin].gpio_device)->regs->IDR & BIT(PIN_MAP[pin].gpio_bit); +} + +/** + * Toggle a pin configured as output push-pull. + * @param dev GPIO device. + * @param pin Pin on dev to toggle. + */ +static inline void gpio_toggle_pin(uint8_t pin) { + (PIN_MAP[pin].gpio_device)->regs->ODR = (PIN_MAP[pin].gpio_device)->regs->ODR ^ BIT(PIN_MAP[pin].gpio_bit); +} + +/* + * GPIO Convenience routines + */ + +extern void gpio_init(gpio_dev *dev); +extern void gpio_init_all(void); +extern void gpio_set_mode(uint8_t pin, gpio_pin_mode mode); +extern void gpio_set_af_mode(uint8_t pin, int mode); + +/* + * AFIO convenience routines + */ + +extern void afio_init(void); +extern void afio_exti_select(afio_exti_num exti, afio_exti_port gpio_port); +extern void afio_remap(afio_remap_peripheral p); + +/** + * @brief Enable or disable the JTAG and SW debug ports. + * @param config Desired debug port configuration + * @see afio_debug_cfg + */ +static inline void afio_cfg_debug_ports(afio_debug_cfg config) { + //__io uint32 *mapr = &AFIO_BASE->MAPR; + //*mapr = (*mapr & ~AFIO_MAPR_SWJ_CFG) | config; +} + +#ifdef __cplusplus +} +#endif + +#endif -#include "gpioF4.h" diff --git a/STM32F4/cores/maple/libmaple/gpioF4.c b/STM32F4/cores/maple/libmaple/gpioF4.c index ba166f5..0792e12 100644 --- a/STM32F4/cores/maple/libmaple/gpioF4.c +++ b/STM32F4/cores/maple/libmaple/gpioF4.c @@ -24,7 +24,7 @@ * SOFTWARE. *****************************************************************************/ - #ifdef STM32F4 +#ifdef STM32F4 /** * @file gpio.c @@ -79,6 +79,7 @@ gpio_dev gpioe = { /** GPIO port E device. */ gpio_dev* const GPIOE = &gpioe; + #if 0 // not available on LQFP 100 package gpio_dev gpiof = { .regs = GPIOF_BASE, .clk_id = RCC_GPIOF, @@ -94,6 +95,7 @@ gpio_dev gpiog = { }; /** GPIO port G device. */ gpio_dev* const GPIOG = &gpiog; + #endif // not available on LQFP 100 package #endif /* @@ -122,9 +124,11 @@ void gpio_init_all(void) { gpio_init(GPIOD); #ifdef STM32_HIGH_DENSITY - gpio_init(GPIOE); - gpio_init(GPIOF); - gpio_init(GPIOG); + gpio_init(GPIOE); + #if 0 // not available on LQFP 100 package + gpio_init(GPIOF); + gpio_init(GPIOG); + #endif // not available on LQFP 100 package #endif #ifdef ARDUINO_STM32F4_NETDUINO2PLUS @@ -148,8 +152,9 @@ void gpio_init_all(void) { * @param mode General purpose or alternate function mode to set the pin to. * @see gpio_pin_mode */ -void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode) { - gpio_reg_map *regs = dev->regs; +void gpio_set_mode(uint8_t io_pin, gpio_pin_mode mode) { + gpio_reg_map *regs = (PIN_MAP[io_pin].gpio_device)->regs; + uint8_t pin = PIN_MAP[io_pin].gpio_bit; //regs->AFR[pin/8] = (regs->AFR[pin/8] & ~(15 << (4*(pin&7)))) | (((mode >> 8) & 15) << (4*(pin&7))); //gpio_set_af_mode(dev, pin, mode>>8); @@ -168,10 +173,11 @@ void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode) { * @param mode alternate function mode to set the pin to. * @see gpio_pin_mode */ -void gpio_set_af_mode(gpio_dev *dev, uint8 pin, int mode) { - gpio_reg_map *regs = dev->regs; +void gpio_set_af_mode(uint8_t io_pin, int mode) { + gpio_reg_map *regs = (PIN_MAP[io_pin].gpio_device)->regs; + uint8_t pin = PIN_MAP[io_pin].gpio_bit; - regs->AFR[pin/8] = (regs->AFR[pin/8] & ~(15 << (4*(pin&7)))) | (((mode >> 0) & 15) << (4*(pin&7))); + regs->AFR[pin>>3] = (regs->AFR[pin>>3] & ~(15 << (4*(pin&7)))) | (((mode >> 0) & 15) << (4*(pin&7))); } /* diff --git a/STM32F4/cores/maple/libmaple/gpioF4.h b/STM32F4/cores/maple/libmaple/gpio_def.h similarity index 91% rename from STM32F4/cores/maple/libmaple/gpioF4.h rename to STM32F4/cores/maple/libmaple/gpio_def.h index 91bd67b..8b9e693 100644 --- a/STM32F4/cores/maple/libmaple/gpioF4.h +++ b/STM32F4/cores/maple/libmaple/gpio_def.h @@ -31,11 +31,12 @@ * (AFIO) prototypes, defines, and inlined access functions. */ -#ifndef _GPIO_H_ -#define _GPIO_H_ +#ifndef _GPIO_DEF_H_ +#define _GPIO_DEF_H_ #include "libmaple.h" #include "rcc.h" +#include "wirish_types.h" #ifdef __cplusplus extern "C"{ @@ -74,11 +75,14 @@ typedef enum afio_exti_port { AFIO_EXTI_PD, /**< Use port D (PDx) pin. */ #ifdef STM32_HIGH_DENSITY AFIO_EXTI_PE, /**< Use port E (PEx) pin. */ + #if 0 // not available on LQFP 100 package AFIO_EXTI_PF, /**< Use port F (PFx) pin. */ AFIO_EXTI_PG, /**< Use port G (PGx) pin. */ + #endif // not available on LQFP 100 package #endif } afio_exti_port; + /** GPIO device type */ typedef struct gpio_dev { gpio_reg_map *regs; /**< Register map */ @@ -97,10 +101,12 @@ extern gpio_dev* const GPIOD; #ifdef STM32_HIGH_DENSITY extern gpio_dev gpioe; extern gpio_dev* const GPIOE; + #if 0 // not available on LQFP 100 package extern gpio_dev gpiof; extern gpio_dev* const GPIOF; extern gpio_dev gpiog; extern gpio_dev* const GPIOG; + #endif // not available on LQFP 100 package #endif /** GPIO port register map base pointer */ @@ -110,8 +116,10 @@ extern gpio_dev* const GPIOG; #define GPIOD_BASE ((struct gpio_reg_map*)0x40020C00) #ifdef STM32_HIGH_DENSITY #define GPIOE_BASE ((struct gpio_reg_map*)0x40021000) + #if 0 // not available on LQFP 100 package #define GPIOF_BASE ((struct gpio_reg_map*)0x40021400) #define GPIOG_BASE ((struct gpio_reg_map*)0x40021800) + #endif // not available on LQFP 100 package #endif /* @@ -190,61 +198,6 @@ typedef enum gpio_pin_mode { GPIO_BIGNUMBER = 0xfff } gpio_pin_mode; -/* - * GPIO Convenience routines - */ - -void gpio_init(gpio_dev *dev); -void gpio_init_all(void); -void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode); -void gpio_set_af_mode(gpio_dev *dev, uint8 pin, int mode); - -/** - * @brief Get a GPIO port's corresponding afio_exti_port. - * @param dev GPIO device whose afio_exti_port to return. - */ -static inline afio_exti_port gpio_exti_port(gpio_dev *dev) { - return dev->exti_port; -} - -/** - * Set or reset a GPIO pin. - * - * Pin must have previously been configured to output mode. - * - * @param dev GPIO device whose pin to set. - * @param pin Pin on to set or reset - * @param val If true, set the pin. If false, reset the pin. - */ -static inline void gpio_write_bit(gpio_dev *dev, uint8 pin, uint8 val) { - if (val) { - dev->regs->BSRRL = BIT(pin); - } else { - dev->regs->BSRRH = BIT(pin); - } -} - -/** - * Determine whether or not a GPIO pin is set. - * - * Pin must have previously been configured to input mode. - * - * @param dev GPIO device whose pin to test. - * @param pin Pin on dev to test. - * @return True if the pin is set, false otherwise. - */ -static inline uint32 gpio_read_bit(gpio_dev *dev, uint8 pin) { - return dev->regs->IDR & BIT(pin); -} - -/** - * Toggle a pin configured as output push-pull. - * @param dev GPIO device. - * @param pin Pin on dev to toggle. - */ -static inline void gpio_toggle_bit(gpio_dev *dev, uint8 pin) { - dev->regs->ODR = dev->regs->ODR ^ BIT(pin); -} /* * AFIO register map @@ -532,15 +485,6 @@ typedef enum afio_debug_cfg { for use as GPIOs. */ } afio_debug_cfg; -/** - * @brief Enable or disable the JTAG and SW debug ports. - * @param config Desired debug port configuration - * @see afio_debug_cfg - */ -static inline void afio_cfg_debug_ports(afio_debug_cfg config) { - //__io uint32 *mapr = &AFIO_BASE->MAPR; - //*mapr = (*mapr & ~AFIO_MAPR_SWJ_CFG) | config; -} #ifdef __cplusplus } diff --git a/STM32F4/cores/maple/libmaple/i2c.c b/STM32F4/cores/maple/libmaple/i2c.c index e3f3199..a582ed0 100644 --- a/STM32F4/cores/maple/libmaple/i2c.c +++ b/STM32F4/cores/maple/libmaple/i2c.c @@ -41,9 +41,9 @@ static i2c_dev i2c_dev1 = { .regs = I2C1_BASE, - .gpio_port = &gpiob, - .sda_pin = 7, - .scl_pin = 6, + //.gpio_port = &gpiob, + .sda_pin = PB7, + .scl_pin = PB6, .clk_id = RCC_I2C1, .ev_nvic_line = NVIC_I2C1_EV, .er_nvic_line = NVIC_I2C1_ER, @@ -54,9 +54,9 @@ i2c_dev* const I2C1 = &i2c_dev1; static i2c_dev i2c_dev2 = { .regs = I2C2_BASE, - .gpio_port = &gpiob, - .sda_pin = 11, - .scl_pin = 10, + //.gpio_port = &gpiob, + .sda_pin = PB11, + .scl_pin = PB10, .clk_id = RCC_I2C2, .ev_nvic_line = NVIC_I2C2_EV, .er_nvic_line = NVIC_I2C2_ER, @@ -336,38 +336,38 @@ void __irq_i2c2_er(void) { */ void i2c_bus_reset(const i2c_dev *dev) { /* Release both lines */ - gpio_write_bit(dev->gpio_port, dev->scl_pin, 1); - gpio_write_bit(dev->gpio_port, dev->sda_pin, 1); - gpio_set_mode(dev->gpio_port, dev->scl_pin, GPIO_OUTPUT_OD); - gpio_set_mode(dev->gpio_port, dev->sda_pin, GPIO_OUTPUT_OD); + gpio_set_pin(dev->scl_pin); + gpio_set_pin(dev->sda_pin); + gpio_set_mode(dev->scl_pin, GPIO_OUTPUT_OD); + gpio_set_mode(dev->sda_pin, GPIO_OUTPUT_OD); /* * Make sure the bus is free by clocking it until any slaves release the * bus. */ - while (!gpio_read_bit(dev->gpio_port, dev->sda_pin)) { + while (!gpio_read_pin(dev->sda_pin)) { /* Wait for any clock stretching to finish */ - while (!gpio_read_bit(dev->gpio_port, dev->scl_pin)) + while (!gpio_read_pin(dev->scl_pin)) ; delay_us(10); /* Pull low */ - gpio_write_bit(dev->gpio_port, dev->scl_pin, 0); + gpio_clear_pin(dev->scl_pin); delay_us(10); /* Release high again */ - gpio_write_bit(dev->gpio_port, dev->scl_pin, 1); + gpio_set_pin(dev->scl_pin); delay_us(10); } /* Generate start then stop condition */ - gpio_write_bit(dev->gpio_port, dev->sda_pin, 0); + gpio_clear_pin(dev->sda_pin); delay_us(10); - gpio_write_bit(dev->gpio_port, dev->scl_pin, 0); + gpio_clear_pin(dev->scl_pin); delay_us(10); - gpio_write_bit(dev->gpio_port, dev->scl_pin, 1); + gpio_set_pin(dev->scl_pin); delay_us(10); - gpio_write_bit(dev->gpio_port, dev->sda_pin, 1); + gpio_set_pin(dev->sda_pin); } /** @@ -413,8 +413,8 @@ void i2c_master_enable(i2c_dev *dev, uint32 flags) { /* Turn on clock and set GPIO modes */ i2c_init(dev); - gpio_set_mode(dev->gpio_port, dev->sda_pin, GPIO_AF_OUTPUT_OD); - gpio_set_mode(dev->gpio_port, dev->scl_pin, GPIO_AF_OUTPUT_OD); + gpio_set_mode(dev->sda_pin, GPIO_AF_OUTPUT_OD); + gpio_set_mode(dev->scl_pin, GPIO_AF_OUTPUT_OD); /* I2C1 and I2C2 are fed from APB1, clocked at 36MHz */ i2c_set_input_clk(dev, I2C_CLK); diff --git a/STM32F4/cores/maple/libmaple/i2c.h b/STM32F4/cores/maple/libmaple/i2c.h index 4c60ad7..28819a3 100644 --- a/STM32F4/cores/maple/libmaple/i2c.h +++ b/STM32F4/cores/maple/libmaple/i2c.h @@ -78,7 +78,7 @@ typedef struct i2c_msg { */ typedef struct i2c_dev { i2c_reg_map *regs; /**< Register map */ - gpio_dev *gpio_port; /**< SDA, SCL pins' GPIO port */ + //gpio_dev *gpio_port; /**< SDA, SCL pins' GPIO port */ uint8 sda_pin; /**< SDA bit on gpio_port */ uint8 scl_pin; /**< SCL bit on gpio_port */ rcc_clk_id clk_id; /**< RCC clock information */ diff --git a/STM32F4/cores/maple/libmaple/libmaple_types.h b/STM32F4/cores/maple/libmaple/libmaple_types.h index e20e327..d2e8673 100644 --- a/STM32F4/cores/maple/libmaple/libmaple_types.h +++ b/STM32F4/cores/maple/libmaple/libmaple_types.h @@ -33,6 +33,9 @@ #ifndef _LIBMAPLE_TYPES_H_ #define _LIBMAPLE_TYPES_H_ +#include +#include + typedef unsigned char uint8; typedef unsigned short uint16; typedef unsigned int uint32; diff --git a/STM32F4/cores/maple/libmaple/rccF4.c b/STM32F4/cores/maple/libmaple/rccF4.c index dd2ea26..c4ff30d 100644 --- a/STM32F4/cores/maple/libmaple/rccF4.c +++ b/STM32F4/cores/maple/libmaple/rccF4.c @@ -166,7 +166,6 @@ typedef struct #define FLASH ((FLASH_TypeDef *) FLASH_R_BASE) #define RESET 0 -typedef uint32 uint32_t; void InitMCO1() { @@ -175,8 +174,8 @@ void InitMCO1() RCC->CFGR &= RCC_CFGR_MCO1_RESET_MASK; RCC->CFGR |= RCC_CFGR_MCO1Source_HSE | RCC_CFGR_MCO1Div_1; // PA8 Output the Master Clock MCO1 - gpio_set_af_mode(GPIOA, 8, 0); - gpio_set_mode(GPIOA, 8, GPIO_MODE_AF | GPIO_OTYPE_PP | GPIO_OSPEED_100MHZ); + gpio_set_af_mode(PA8, 0); + gpio_set_mode(PA8, GPIO_MODE_AF | GPIO_OTYPE_PP | GPIO_OSPEED_100MHZ); } diff --git a/STM32F4/cores/maple/libmaple/spi.h b/STM32F4/cores/maple/libmaple/spi.h index 88739c5..0436352 100644 --- a/STM32F4/cores/maple/libmaple/spi.h +++ b/STM32F4/cores/maple/libmaple/spi.h @@ -230,14 +230,10 @@ struct gpio_dev; */ extern void spi_config_gpios(spi_dev *dev, uint8 as_master, - struct gpio_dev *nss_dev, - uint8 nss_bit, - struct gpio_dev *sck_dev, - uint8 sck_bit, - struct gpio_dev *miso_dev, - uint8 miso_bit, - struct gpio_dev *mosi_dev, - uint8 mosi_bit); + uint8 nss_pin, + uint8 sck_pin, + uint8 miso_pin, + uint8 mosi_pin); /** * @brief SPI mode configuration. diff --git a/STM32F4/cores/maple/libmaple/spiF4.h b/STM32F4/cores/maple/libmaple/spiF4.h index 3f51164..d2ae557 100644 --- a/STM32F4/cores/maple/libmaple/spiF4.h +++ b/STM32F4/cores/maple/libmaple/spiF4.h @@ -62,17 +62,6 @@ extern struct spi_dev *SPI2; extern struct spi_dev *SPI3; #endif -/* - * Routines - */ - -/* spi_gpio_cfg(): Backwards compatibility shim to spi_config_gpios() */ -struct gpio_dev; -extern void spi_config_gpios(struct spi_dev*, uint8, - struct gpio_dev*, uint8, - struct gpio_dev*, uint8, - struct gpio_dev*, uint8, - struct gpio_dev*, uint8); #ifdef __cplusplus } diff --git a/STM32F4/cores/maple/libmaple/spi_f4.c b/STM32F4/cores/maple/libmaple/spi_f4.c index b9beb68..43f5092 100644 --- a/STM32F4/cores/maple/libmaple/spi_f4.c +++ b/STM32F4/cores/maple/libmaple/spi_f4.c @@ -56,25 +56,21 @@ spi_dev *SPI3 = &spi3; void spi_config_gpios(spi_dev *ignored, uint8 as_master, - gpio_dev *nss_dev, - uint8 nss_bit, - gpio_dev *sck_dev, - uint8 sck_bit, - gpio_dev *miso_dev, - uint8 miso_bit, - gpio_dev *mosi_dev, - uint8 mosi_bit) { + uint8 nss_pin, + uint8 sck_pin, + uint8 miso_pin, + uint8 mosi_pin) { if (as_master) { // gpio_set_mode(nss_dev, nss_bit, GPIO_AF_OUTPUT_PP); - gpio_set_mode(sck_dev, sck_bit, GPIO_AF_OUTPUT_PP); + gpio_set_mode(sck_pin, GPIO_AF_OUTPUT_PP); // gpio_set_mode(comm_dev, miso_bit, GPIO_INPUT_FLOATING); - gpio_set_mode(miso_dev, miso_bit, GPIO_AF_INPUT_PD); - gpio_set_mode(mosi_dev, mosi_bit, GPIO_AF_OUTPUT_PP); + gpio_set_mode(miso_pin, GPIO_AF_INPUT_PD); + gpio_set_mode(mosi_pin, GPIO_AF_OUTPUT_PP); } else { - gpio_set_mode(nss_dev, nss_bit, GPIO_INPUT_FLOATING); - gpio_set_mode(sck_dev, sck_bit, GPIO_INPUT_FLOATING); - gpio_set_mode(miso_dev, miso_bit, GPIO_AF_OUTPUT_PP); - gpio_set_mode(mosi_dev, mosi_bit, GPIO_INPUT_FLOATING); + gpio_set_mode(nss_pin, GPIO_INPUT_FLOATING); + gpio_set_mode(sck_pin, GPIO_INPUT_FLOATING); + gpio_set_mode(miso_pin, GPIO_AF_OUTPUT_PP); + gpio_set_mode(mosi_pin, GPIO_INPUT_FLOATING); } } diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/usb_bsp.c b/STM32F4/cores/maple/libmaple/usbF4/VCP/usb_bsp.c index df23ccb..c402bbd 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/usb_bsp.c +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/usb_bsp.c @@ -97,10 +97,10 @@ void USB_OTG_BSP_Init(USB_OTG_CORE_HANDLE *pdev) { // ala42 #define GPIO_AF_OTG1_FS ((uint8_t)0xA) /* OTG_FS Alternate Function mapping */ - gpio_set_mode(GPIOA,11,GPIO_MODE_AF | GPIO_OTYPE_PP | GPIO_OSPEED_100MHZ); - gpio_set_mode(GPIOA,12,GPIO_MODE_AF | GPIO_OTYPE_PP | GPIO_OSPEED_100MHZ); - gpio_set_af_mode(GPIOA,11,GPIO_AF_OTG1_FS) ; // OTG_FS_DM - gpio_set_af_mode(GPIOA,12,GPIO_AF_OTG1_FS) ; // OTG_FS_DP + gpio_set_mode(BOARD_USB_DM_PIN,GPIO_MODE_AF | GPIO_OTYPE_PP | GPIO_OSPEED_100MHZ); + gpio_set_mode(BOARD_USB_DP_PIN,GPIO_MODE_AF | GPIO_OTYPE_PP | GPIO_OSPEED_100MHZ); + gpio_set_af_mode(BOARD_USB_DM_PIN,GPIO_AF_OTG1_FS) ; // OTG_FS_DM + gpio_set_af_mode(BOARD_USB_DP_PIN,GPIO_AF_OTG1_FS) ; // OTG_FS_DP #ifdef USB_OTG_FS_SOF_OUTPUT_ENABLED gpio_set_mode(GPIOA, 8,GPIO_MODE_AF | GPIO_OTYPE_PP | GPIO_OSPEED_100MHZ); gpio_set_af_mode(GPIOA, 8,GPIO_AF_OTG1_FS) ; // OTG_FS_SOF @@ -122,10 +122,10 @@ void USB_OTG_BSP_DeInit(USB_OTG_CORE_HANDLE *pdev) { // ala42 #define GPIO_AF0 ((uint8_t)0) /* OTG_FS Alternate Function mapping */ - gpio_set_mode(GPIOA,11, GPIO_MODE_INPUT); - gpio_set_mode(GPIOA,12, GPIO_MODE_INPUT); - gpio_set_af_mode(GPIOA,11,GPIO_AF0) ; // OTG_FS_DM - gpio_set_af_mode(GPIOA,12,GPIO_AF0) ; // OTG_FS_DP + gpio_set_mode(BOARD_USB_DM_PIN, GPIO_MODE_INPUT); + gpio_set_mode(BOARD_USB_DP_PIN, GPIO_MODE_INPUT); + gpio_set_af_mode(BOARD_USB_DM_PIN,GPIO_AF0) ; // OTG_FS_DM + gpio_set_af_mode(BOARD_USB_DP_PIN,GPIO_AF0) ; // OTG_FS_DP #ifdef USB_OTG_FS_SOF_OUTPUT_ENABLED gpio_set_mode(GPIOA, 8,GPIO_MODE_INPUT); gpio_set_af_mode(GPIOA, 8,GPIO_AF0) ; // OTG_FS_SOF diff --git a/STM32F4/cores/maple/libmaple/usbF4/usb.c b/STM32F4/cores/maple/libmaple/usbF4/usb.c index c013f04..49ddc06 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/usb.c +++ b/STM32F4/cores/maple/libmaple/usbF4/usb.c @@ -5,23 +5,22 @@ #include #include #include +#include USB_OTG_CORE_HANDLE USB_OTG_dev; -void setupUSB (void) { - #define USB_DISC_DEV GPIOA - #define USB_DISC_PIN 12 - - gpio_set_mode(USB_DISC_DEV, USB_DISC_PIN, GPIO_OUTPUT_OD); // ala42 +void setupUSB (void) +{ + gpio_set_mode(BOARD_USB_DP_PIN, GPIO_OUTPUT_OD); // ala42 #ifdef USB_DISC_OD //gpio_set_mode(USB_DISC_DEV, USB_DISC_PIN, GPIO_OUTPUT_OD); // ala42 #else //gpio_set_mode(USB_DISC_DEV, USB_DISC_PIN, GPIO_OUTPUT_PP); // ala42 for active pull-up on disconnect pin #endif - gpio_write_bit(USB_DISC_DEV, USB_DISC_PIN,0); // ala42 + gpio_clear_pin(BOARD_USB_DP_PIN); // ala42 delay_us(200000); /* setup the apb1 clock for USB */ @@ -29,7 +28,7 @@ void setupUSB (void) { //pRCC->APB1ENR |= RCC_APB1ENR_USBEN; /* initialize the usb application */ - gpio_write_bit(USB_DISC_DEV, USB_DISC_PIN, 1); // ala42 // presents us to the host + gpio_set_pin(BOARD_USB_DP_PIN); // ala42 // presents us to the host USBD_Init(&USB_OTG_dev, USB_OTG_FS_CORE_ID, &USR_desc, diff --git a/STM32F4/cores/maple/libmaple/util.c b/STM32F4/cores/maple/libmaple/util.c index 8c03e18..8a745e8 100644 --- a/STM32F4/cores/maple/libmaple/util.c +++ b/STM32F4/cores/maple/libmaple/util.c @@ -128,7 +128,7 @@ void throb(void) { uint32 TOP_CNT = 0x0800; uint32 i = 0; - gpio_set_mode(ERROR_LED_PORT, ERROR_LED_PIN, GPIO_OUTPUT_PP); + gpio_set_mode(ERROR_LED_PIN, GPIO_OUTPUT_PP); /* Error fade. */ while (1) { if (CC == TOP_CNT) { @@ -143,9 +143,9 @@ void throb(void) { } if (i < CC) { - gpio_write_bit(ERROR_LED_PORT, ERROR_LED_PIN, 1); + gpio_set_pin(ERROR_LED_PIN); } else { - gpio_write_bit(ERROR_LED_PORT, ERROR_LED_PIN, 0); + gpio_clear_pin(ERROR_LED_PIN); } i++; } diff --git a/STM32F4/cores/maple/usb_serial.cpp b/STM32F4/cores/maple/usb_serial.cpp index cc726c2..cfeb382 100644 --- a/STM32F4/cores/maple/usb_serial.cpp +++ b/STM32F4/cores/maple/usb_serial.cpp @@ -33,6 +33,8 @@ #include "wirish.h" #include "usb.h" +#ifdef SERIAL_USB + #define USB_TIMEOUT 50 USBSerial::USBSerial(void) { @@ -153,3 +155,5 @@ void USBSerial::disableBlockingTx(void) { } USBSerial SerialUSB; + +#endif diff --git a/STM32F4/cores/maple/usb_serial.h b/STM32F4/cores/maple/usb_serial.h index a551e9d..301dc4b 100644 --- a/STM32F4/cores/maple/usb_serial.h +++ b/STM32F4/cores/maple/usb_serial.h @@ -33,6 +33,8 @@ #include "Stream.h" +#ifdef SERIAL_USB + /** * @brief Virtual serial terminal. */ @@ -68,3 +70,6 @@ extern USBSerial SerialUSB; #endif + +#endif + diff --git a/STM32F4/cores/maple/wirish.h b/STM32F4/cores/maple/wirish.h index a9068e7..7e94fb3 100644 --- a/STM32F4/cores/maple/wirish.h +++ b/STM32F4/cores/maple/wirish.h @@ -54,8 +54,8 @@ #define HIGH 0x1 #define LOW 0x0 -#define true 0x1 -#define false 0x0 +//#define true 0x1 +//#define false 0x0 #define lowByte(w) ((w) & 0xFF) diff --git a/STM32F4/cores/maple/wirish_digital.cpp b/STM32F4/cores/maple/wirish_digital.cpp index da180dc..4a65619 100644 --- a/STM32F4/cores/maple/wirish_digital.cpp +++ b/STM32F4/cores/maple/wirish_digital.cpp @@ -72,7 +72,7 @@ void pinMode(uint8 pin, WiringPinMode mode) { return; } - gpio_set_mode(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit, outputMode); + gpio_set_mode(pin, outputMode); if (PIN_MAP[pin].timer_device != NULL) { /* Enable/disable timer channels if we're switching into or @@ -84,29 +84,32 @@ void pinMode(uint8 pin, WiringPinMode mode) { } -uint32 digitalRead(uint8 pin) { +uint32 digitalRead(uint8 pin) +{ if (pin >= BOARD_NR_GPIO_PINS) { return 0; } - return gpio_read_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit) ? + return gpio_read_pin(pin) ? HIGH : LOW; } -void digitalWrite(uint8 pin, uint8 val) { +void digitalWrite(uint8 pin, uint8 val) +{ if (pin >= BOARD_NR_GPIO_PINS) { return; } - gpio_write_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit, val); + gpio_write_pin(pin, val); } -void togglePin(uint8 pin) { +void togglePin(uint8 pin) +{ if (pin >= BOARD_NR_GPIO_PINS) { return; } - gpio_toggle_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit); + gpio_toggle_pin(pin); } #define BUTTON_DEBOUNCE_DELAY 1 diff --git a/STM32F4/cores/maple/wirish_types.h b/STM32F4/cores/maple/wirish_types.h index 55364ab..95e524f 100644 --- a/STM32F4/cores/maple/wirish_types.h +++ b/STM32F4/cores/maple/wirish_types.h @@ -30,14 +30,14 @@ * @brief Wirish library type definitions. */ -#include "libmaple_types.h" -#include "gpio.h" -#include "timer.h" -#include "adc.h" - #ifndef _WIRISH_TYPES_H_ #define _WIRISH_TYPES_H_ +#include "libmaple_types.h" +#include "gpio_def.h" +#include "timer.h" +#include "adc.h" + /** * Invalid stm32_pin_info adc_channel value. * @see stm32_pin_info @@ -73,6 +73,7 @@ typedef struct stm32_pin_info { } stm32_pin_info; #endif + /** * Variable attribute, instructs the linker to place the marked * variable in Flash instead of RAM. */ diff --git a/STM32F4/platform.txt b/STM32F4/platform.txt index b32f283..5bfa22e 100755 --- a/STM32F4/platform.txt +++ b/STM32F4/platform.txt @@ -64,7 +64,7 @@ compiler.libs.c.flags=-I{build.core.path} -I{build.core.path}/libmaple -I{build. # --------------------- ## Compile c files -recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.flags} -mcpu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.c.extra_flags} {build.extra_flags} {compiler.libs.c.flags} {includes} "{source_file}" -o "{object_file}" +recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.flags} -mcpu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.c.extra_flags} {build.extra_flags} {build.cpu_flags} {compiler.libs.c.flags} {includes} "{source_file}" -o "{object_file}" ## Compile c++ files recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} -mcpu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {build.cpu_flags} {build.hs_flag} {build.common_flags} {compiler.libs.c.flags} {includes} "{source_file}" -o "{object_file}" diff --git a/STM32F4/variants/generic_f407v/generic_f407v.h b/STM32F4/variants/generic_f407v/generic_f407v.h index 15e93e4..b9f0348 100644 --- a/STM32F4/variants/generic_f407v/generic_f407v.h +++ b/STM32F4/variants/generic_f407v/generic_f407v.h @@ -124,7 +124,7 @@ PE0,PE1,PE2,PE3,PE4,PE5,PE6,PE7,PE8,PE9,PE10,PE11,PE12,PE13,PE14,PE15, #if 0 // not available on LQFP100 package PF0,PF1,PF2,PF3,PF4,PF5,PF6,PF7,PF8,PF9,PF10,PF11,PF12,PF13,PF14,PF15, PG0,PG1,PG2,PG3,PG4,PG5,PG6,PG7,PG8,PG9,PG10,PG11,PG12,PG13,PG14,PG15 -#endif +#endif // not available on LQFP100 package }; #endif diff --git a/STM32F4/variants/generic_f407v/ld/jtag.ld b/STM32F4/variants/generic_f407v/ld/jtag.ld index fe70f68..1001db5 100644 --- a/STM32F4/variants/generic_f407v/ld/jtag.ld +++ b/STM32F4/variants/generic_f407v/ld/jtag.ld @@ -5,7 +5,7 @@ MEMORY { - ram (rwx) : ORIGIN = 0x20000000, LENGTH = 64K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K rom (rx) : ORIGIN = 0x08000000, LENGTH = 512K } From 1d29d139677eb2b843deee4bea9183dad4c330b6 Mon Sep 17 00:00:00 2001 From: lacklustrlabs Date: Thu, 27 Apr 2017 18:22:18 +0200 Subject: [PATCH 026/351] The ssd1306_128x64_i2c_STM32 example would not build because of a missing swap() macro. --- STM32F1/libraries/Adafruit_SSD1306/Adafruit_SSD1306_STM32.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/STM32F1/libraries/Adafruit_SSD1306/Adafruit_SSD1306_STM32.cpp b/STM32F1/libraries/Adafruit_SSD1306/Adafruit_SSD1306_STM32.cpp index c0c24a0..3492039 100644 --- a/STM32F1/libraries/Adafruit_SSD1306/Adafruit_SSD1306_STM32.cpp +++ b/STM32F1/libraries/Adafruit_SSD1306/Adafruit_SSD1306_STM32.cpp @@ -29,6 +29,10 @@ HardWire HWIRE(2,I2C_FAST_MODE); // I2c2 #include "Adafruit_GFX.h" #include "Adafruit_SSD1306_STM32.h" +#ifndef swap +#define swap(a, b) { int16_t t = a; a = b; b = t; } +#endif + // the memory buffer for the LCD static uint8_t buffer[SSD1306_LCDHEIGHT * SSD1306_LCDWIDTH / 8] = { From 9dbcefdec34bb4e1038021dbc2a01ed20c23e509 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Wed, 3 May 2017 18:27:39 +0200 Subject: [PATCH 027/351] bugfix to include external libraries: reworked include paths + moved Arduino.h + updated SPI lib --- STM32F4/cores/maple/Arduino.h | 6 - STM32F4/cores/maple/Client.h | 5 +- STM32F4/cores/maple/HardwareTimer.h | 2 +- STM32F4/cores/maple/IPAddress.h | 4 +- STM32F4/cores/maple/Server.h | 4 +- STM32F4/cores/maple/Stream.h | 4 +- STM32F4/cores/maple/Udp.h | 4 +- STM32F4/cores/maple/WProgram.h | 7 +- STM32F4/cores/maple/WString.h | 7 +- STM32F4/cores/maple/bits.h | 5 + STM32F4/cores/maple/boards.cpp | 14 +- STM32F4/cores/maple/boards.h | 14 +- STM32F4/cores/maple/ext_interrupts.cpp | 4 +- STM32F4/cores/maple/ext_interrupts.h | 9 +- STM32F4/cores/maple/io.h | 4 +- STM32F4/cores/maple/itoa.h | 4 +- STM32F4/cores/maple/libmaple/gpioF4.c | 10 +- STM32F4/cores/maple/libmaple/gpio_def.h | 1 - STM32F4/cores/maple/libmaple/libmaple.h | 3 - STM32F4/cores/maple/libmaple/libmaple_types.h | 2 +- STM32F4/cores/maple/libmaple/spi.c | 39 +- STM32F4/cores/maple/libmaple/spi.h | 6 +- STM32F4/cores/maple/libmaple/spiF4.h | 4 +- .../Class/audio/inc/usbd_audio_core.h | 2 +- .../Class/cdc/inc/usbd_cdc_core.h | 3 +- .../Class/cdc/src/usbd_cdc_core.c | 7 +- .../Core/inc/usbd_core.h | 4 +- .../Core/inc/usbd_def.h | 2 +- .../Core/inc/usbd_req.h | 2 +- .../Core/src/usbd_core.c | 10 +- .../Core/src/usbd_ioreq.c | 2 +- .../Core/src/usbd_req.c | 6 +- .../usbF4/STM32_USB_OTG_Driver/inc/usb_core.h | 2 +- .../STM32_USB_OTG_Driver/inc/usb_defines.h | 2 +- .../usbF4/STM32_USB_OTG_Driver/inc/usb_otg.h | 1 + .../usbF4/STM32_USB_OTG_Driver/inc/usb_regs.h | 4 +- .../usbF4/STM32_USB_OTG_Driver/src/usb_core.c | 4 +- .../usbF4/STM32_USB_OTG_Driver/src/usb_dcd.c | 4 +- .../STM32_USB_OTG_Driver/src/usb_dcd_int.c | 4 +- .../cores/maple/libmaple/usbF4/VCP/core_cm4.h | 2 +- STM32F4/cores/maple/libmaple/usbF4/VCP/misc.c | 2 +- .../cores/maple/libmaple/usbF4/VCP/usb_bsp.c | 6 +- .../maple/libmaple/usbF4/VCP/usbd_cdc_vcp.h | 2 +- .../maple/libmaple/usbF4/VCP/usbd_conf.h | 1 + .../maple/libmaple/usbF4/VCP/usbd_desc.c | 6 +- .../maple/libmaple/usbF4/VCP/usbd_desc.h | 2 +- .../cores/maple/libmaple/usbF4/VCP/usbd_usr.c | 4 +- STM32F4/cores/maple/libmaple/usbF4/usb.c | 20 +- STM32F4/cores/maple/libmaple/usbF4/usb.h | 2 +- STM32F4/cores/maple/libmaple/util.h | 5 +- STM32F4/cores/maple/pwm.cpp | 4 +- STM32F4/cores/maple/wirish.h | 13 +- STM32F4/cores/maple/wirish_constants.h | 4 +- STM32F4/cores/maple/wirish_debug.h | 7 +- STM32F4/cores/maple/wirish_math.h | 4 +- STM32F4/cores/maple/wirish_time.cpp | 6 +- STM32F4/cores/maple/wirish_time.h | 5 +- STM32F4/cores/maple/wirish_types.h | 7 +- STM32F4/libraries/SPI/library.properties | 1 + STM32F4/libraries/SPI/src/SPI.cpp | 452 +++++++++--------- STM32F4/libraries/SPI/src/SPI.h | 142 ++++-- STM32F4/platform.txt | 12 +- STM32F4/system/libmaple/Arduino.h | 46 ++ .../variants/generic_f407v/generic_f407v.cpp | 37 +- .../variants/generic_f407v/generic_f407v.h | 41 +- 65 files changed, 580 insertions(+), 474 deletions(-) delete mode 100644 STM32F4/cores/maple/Arduino.h create mode 100644 STM32F4/system/libmaple/Arduino.h diff --git a/STM32F4/cores/maple/Arduino.h b/STM32F4/cores/maple/Arduino.h deleted file mode 100644 index d02a50c..0000000 --- a/STM32F4/cores/maple/Arduino.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef Arduino_h -#define Arduino_h -#include "WProgram.h" -#endif - -#include "variant.h" diff --git a/STM32F4/cores/maple/Client.h b/STM32F4/cores/maple/Client.h index b8e5d93..57bedb8 100644 --- a/STM32F4/cores/maple/Client.h +++ b/STM32F4/cores/maple/Client.h @@ -17,8 +17,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef client_h -#define client_h +#ifndef _CLIENT_H_ +#define _CLIENT_H_ + #include "Print.h" #include "Stream.h" #include "IPAddress.h" diff --git a/STM32F4/cores/maple/HardwareTimer.h b/STM32F4/cores/maple/HardwareTimer.h index 89e3564..c90356b 100644 --- a/STM32F4/cores/maple/HardwareTimer.h +++ b/STM32F4/cores/maple/HardwareTimer.h @@ -33,7 +33,7 @@ // TODO [0.1.0] Remove deprecated pieces, pick a better API -#include "timer.h" +#include /** Timer mode. */ typedef timer_mode TimerMode; diff --git a/STM32F4/cores/maple/IPAddress.h b/STM32F4/cores/maple/IPAddress.h index 271b240..c6e0697 100644 --- a/STM32F4/cores/maple/IPAddress.h +++ b/STM32F4/cores/maple/IPAddress.h @@ -17,8 +17,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef IPAddress_h -#define IPAddress_h +#ifndef _IPAddress_h_ +#define _IPAddress_h_ #include #include diff --git a/STM32F4/cores/maple/Server.h b/STM32F4/cores/maple/Server.h index 69e3e39..4a95c9f 100644 --- a/STM32F4/cores/maple/Server.h +++ b/STM32F4/cores/maple/Server.h @@ -17,8 +17,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef server_h -#define server_h +#ifndef _SERVER_H_ +#define _SERVER_H_ #include "Print.h" diff --git a/STM32F4/cores/maple/Stream.h b/STM32F4/cores/maple/Stream.h index abdcd17..870fbf0 100644 --- a/STM32F4/cores/maple/Stream.h +++ b/STM32F4/cores/maple/Stream.h @@ -19,8 +19,8 @@ parsing functions based on TextFinder library by Michael Margolis */ -#ifndef Stream_h -#define Stream_h +#ifndef _STREAM_H_ +#define _STREAM_H_ #include #include "Print.h" diff --git a/STM32F4/cores/maple/Udp.h b/STM32F4/cores/maple/Udp.h index dc5644b..1652caf 100644 --- a/STM32F4/cores/maple/Udp.h +++ b/STM32F4/cores/maple/Udp.h @@ -32,8 +32,8 @@ * bjoern@cs.stanford.edu 12/30/2008 */ -#ifndef udp_h -#define udp_h +#ifndef _UDP_H_ +#define _UDP_H_ #include #include diff --git a/STM32F4/cores/maple/WProgram.h b/STM32F4/cores/maple/WProgram.h index 2949a0a..82b759a 100644 --- a/STM32F4/cores/maple/WProgram.h +++ b/STM32F4/cores/maple/WProgram.h @@ -24,7 +24,12 @@ * SOFTWARE. *****************************************************************************/ -#include "wirish.h" +#ifndef _WPROGRAM_H_ +#define _WPROGRAM_H_ + +#include void setup(); void loop(); + +#endif \ No newline at end of file diff --git a/STM32F4/cores/maple/WString.h b/STM32F4/cores/maple/WString.h index 9038578..ec0eae7 100644 --- a/STM32F4/cores/maple/WString.h +++ b/STM32F4/cores/maple/WString.h @@ -19,8 +19,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef String_class_h -#define String_class_h +#ifndef _WSTRING_H_ +#define _WSTRING_H_ + #ifdef __cplusplus #include @@ -225,4 +226,4 @@ public: }; #endif // __cplusplus -#endif // String_class_h +#endif // _WSTRING_H_ diff --git a/STM32F4/cores/maple/bits.h b/STM32F4/cores/maple/bits.h index 3e755b7..3e3eff1 100644 --- a/STM32F4/cores/maple/bits.h +++ b/STM32F4/cores/maple/bits.h @@ -27,4 +27,9 @@ /* Note: Use of this header file is deprecated. Use bit_constants.h instead. */ +#ifndef _BITS_H_ +#define _BITS_H_ + #include "bit_constants.h" + +#endif diff --git a/STM32F4/cores/maple/boards.cpp b/STM32F4/cores/maple/boards.cpp index fc453fe..0d55e94 100644 --- a/STM32F4/cores/maple/boards.cpp +++ b/STM32F4/cores/maple/boards.cpp @@ -33,13 +33,13 @@ */ #include "boards.h" -#include "flash.h" -#include "rcc.h" -#include "nvic.h" -#include "systick.h" -#include "gpio.h" -#include "adc.h" -#include "timer.h" +#include +#include +#include +#include +#include +#include +#include #include "usb.h" #include "usb_serial.h" diff --git a/STM32F4/cores/maple/boards.h b/STM32F4/cores/maple/boards.h index 50fd89d..d37bff4 100644 --- a/STM32F4/cores/maple/boards.h +++ b/STM32F4/cores/maple/boards.h @@ -39,10 +39,8 @@ #ifndef _BOARDS_H_ #define _BOARDS_H_ -#include "libmaple.h" -#include "timer.h" - -#include "wirish_types.h" +#include +#include /* Set of all possible pin names; not all boards have all these (note * that we use the Dx convention since all of the Maple's pins are @@ -151,4 +149,12 @@ extern bool boardUsesPin(uint8 pin); #define CLOCK_SPEED_MHZ CYCLES_PER_MICROSECOND #define CLOCK_SPEED_HZ (CLOCK_SPEED_MHZ * 1000000UL) +#ifndef SYSTICK_RELOAD_VAL +#define SYSTICK_RELOAD_VAL (1000 * CYCLES_PER_MICROSECOND - 1) +#endif + +#ifndef BOARD_BUTTON_PRESSED_LEVEL +#define BOARD_BUTTON_PRESSED_LEVEL HIGH +#endif + #endif diff --git a/STM32F4/cores/maple/ext_interrupts.cpp b/STM32F4/cores/maple/ext_interrupts.cpp index f014f13..9e98548 100644 --- a/STM32F4/cores/maple/ext_interrupts.cpp +++ b/STM32F4/cores/maple/ext_interrupts.cpp @@ -31,8 +31,8 @@ */ #include "boards.h" -#include "gpio.h" -#include "exti.h" +#include +#include #include "ext_interrupts.h" static inline exti_trigger_mode exti_out_mode(ExtIntTriggerMode mode); diff --git a/STM32F4/cores/maple/ext_interrupts.h b/STM32F4/cores/maple/ext_interrupts.h index b5c6f98..fe215dc 100644 --- a/STM32F4/cores/maple/ext_interrupts.h +++ b/STM32F4/cores/maple/ext_interrupts.h @@ -24,8 +24,8 @@ * SOFTWARE. *****************************************************************************/ -#include "libmaple_types.h" -#include "nvic.h" +#ifndef _EXT_INTERRUPTS_H_ +#define _EXT_INTERRUPTS_H_ /** * @file ext_interrupts.h @@ -33,8 +33,9 @@ * @brief Wiring-like external interrupt prototypes and types. */ -#ifndef _EXT_INTERRUPTS_H_ -#define _EXT_INTERRUPTS_H_ +#include +#include + /** * The kind of transition on an external pin which should trigger an diff --git a/STM32F4/cores/maple/io.h b/STM32F4/cores/maple/io.h index 1208be6..aeaf0fd 100644 --- a/STM32F4/cores/maple/io.h +++ b/STM32F4/cores/maple/io.h @@ -34,8 +34,8 @@ #define _IO_H_ #include -#include "gpio.h" -#include "adc.h" +#include +#include #include "wirish_time.h" diff --git a/STM32F4/cores/maple/itoa.h b/STM32F4/cores/maple/itoa.h index 59af109..09e8b2f 100644 --- a/STM32F4/cores/maple/itoa.h +++ b/STM32F4/cores/maple/itoa.h @@ -16,8 +16,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef _ITOA_ -#define _ITOA_ +#ifndef _ITOA_H_ +#define _ITOA_H_ #ifdef __cplusplus extern "C"{ diff --git a/STM32F4/cores/maple/libmaple/gpioF4.c b/STM32F4/cores/maple/libmaple/gpioF4.c index 0792e12..6fec61c 100644 --- a/STM32F4/cores/maple/libmaple/gpioF4.c +++ b/STM32F4/cores/maple/libmaple/gpioF4.c @@ -159,10 +159,10 @@ void gpio_set_mode(uint8_t io_pin, gpio_pin_mode mode) { //regs->AFR[pin/8] = (regs->AFR[pin/8] & ~(15 << (4*(pin&7)))) | (((mode >> 8) & 15) << (4*(pin&7))); //gpio_set_af_mode(dev, pin, mode>>8); - regs->MODER = (regs->MODER & ~( 3 << (2*pin))) | (((mode >> 0) & 3) << (2*pin)); - regs->PUPDR = (regs->PUPDR & ~( 3 << (2*pin))) | (((mode >> 2) & 3) << (2*pin)); - regs->OSPEEDR = (regs->OSPEEDR & ~( 3 << (2*pin))) | (((mode >> 4) & 3) << (2*pin)); - regs->OTYPER = (regs->OTYPER & ~( 1 << (1*pin))) | (((mode >> 6) & 1) << (1*pin)); + regs->MODER = (regs->MODER & ~( 3 << (pin<<1))) | (((mode >> 0) & 3) << (pin<<1)); + regs->PUPDR = (regs->PUPDR & ~( 3 << (pin<<1))) | (((mode >> 2) & 3) << (pin<<1)); + regs->OSPEEDR = (regs->OSPEEDR & ~( 3 << (pin<<1))) | (((mode >> 4) & 3) << (pin<<1)); + regs->OTYPER = (regs->OTYPER & ~( 1 << (pin<<1))) | (((mode >> 6) & 1) << (pin<<1)); } /** @@ -177,7 +177,7 @@ void gpio_set_af_mode(uint8_t io_pin, int mode) { gpio_reg_map *regs = (PIN_MAP[io_pin].gpio_device)->regs; uint8_t pin = PIN_MAP[io_pin].gpio_bit; - regs->AFR[pin>>3] = (regs->AFR[pin>>3] & ~(15 << (4*(pin&7)))) | (((mode >> 0) & 15) << (4*(pin&7))); + regs->AFR[pin>>3] = (regs->AFR[pin>>3] & ~(15 << ((pin&7)<<2))) | (((mode >> 0) & 15) << ((pin&7)<<2)); } /* diff --git a/STM32F4/cores/maple/libmaple/gpio_def.h b/STM32F4/cores/maple/libmaple/gpio_def.h index 8b9e693..e2176ea 100644 --- a/STM32F4/cores/maple/libmaple/gpio_def.h +++ b/STM32F4/cores/maple/libmaple/gpio_def.h @@ -36,7 +36,6 @@ #include "libmaple.h" #include "rcc.h" -#include "wirish_types.h" #ifdef __cplusplus extern "C"{ diff --git a/STM32F4/cores/maple/libmaple/libmaple.h b/STM32F4/cores/maple/libmaple/libmaple.h index 20a57bc..8360ba3 100644 --- a/STM32F4/cores/maple/libmaple/libmaple.h +++ b/STM32F4/cores/maple/libmaple/libmaple.h @@ -32,10 +32,7 @@ #ifndef _LIBMAPLE_H_ #define _LIBMAPLE_H_ -#include "libmaple_types.h" -#include "stm32.h" #include "util.h" -#include "delay.h" /* * Where to put usercode, based on space reserved for bootloader. diff --git a/STM32F4/cores/maple/libmaple/libmaple_types.h b/STM32F4/cores/maple/libmaple/libmaple_types.h index d2e8673..8e765b4 100644 --- a/STM32F4/cores/maple/libmaple/libmaple_types.h +++ b/STM32F4/cores/maple/libmaple/libmaple_types.h @@ -34,7 +34,6 @@ #define _LIBMAPLE_TYPES_H_ #include -#include typedef unsigned char uint8; typedef unsigned short uint16; @@ -49,6 +48,7 @@ typedef long long int64; typedef void (*voidFuncPtr)(void); #define __io volatile +#define __IO volatile #ifndef __attr_flash #define __attr_flash __attribute__((section (".USER_FLASH"))) #endif diff --git a/STM32F4/cores/maple/libmaple/spi.c b/STM32F4/cores/maple/libmaple/spi.c index 194a82e..4b274cb 100644 --- a/STM32F4/cores/maple/libmaple/spi.c +++ b/STM32F4/cores/maple/libmaple/spi.c @@ -83,25 +83,29 @@ 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 * correctly treated as 8-bit or 16-bit quantities). * @param len Maximum number of elements to transmit. - * @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 (spi_is_tx_empty(dev) && (txed < len)) { - if (byte_frame) { - dev->regs->DR = ((const uint8*)buf)[txed++]; - } else { - dev->regs->DR = ((const uint16*)buf)[txed++]; - } - } - return txed; +void spi_tx(spi_dev *dev, void *buf, uint32 len) +{ + spi_reg_map *regs = dev->regs; + if ( spi_dff(dev) == SPI_DFF_8_BIT ) { + uint8 * dp8 = (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 { + uint16 * dp16 = (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++; + } + } } /** @@ -157,8 +161,9 @@ void spi_rx_dma_disable(spi_dev *dev) { */ static void spi_reconfigure(spi_dev *dev, uint32 cr1_config) { - spi_irq_disable(dev, SPI_INTERRUPTS_ALL); - spi_peripheral_disable(dev); - dev->regs->CR1 = cr1_config; - spi_peripheral_enable(dev); +#define MASK (SPI_CR1_CRCEN|SPI_CR1_DFF) + 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_peripheral_enable(dev); } diff --git a/STM32F4/cores/maple/libmaple/spi.h b/STM32F4/cores/maple/libmaple/spi.h index 0436352..f96b462 100644 --- a/STM32F4/cores/maple/libmaple/spi.h +++ b/STM32F4/cores/maple/libmaple/spi.h @@ -219,13 +219,9 @@ struct gpio_dev; * * @param dev SPI device * @param as_master If true, configure as bus master; otherwise, as slave. - * @param nss_dev NSS pin's GPIO device * @param nss_bit NSS pin's GPIO bit on nss_dev - * @param sck_dev SCK pin's GPIO device * @param sck_bit SCK pin's GPIO bit on comm_dev - * @param miso_dev MISO pin's GPIO device * @param miso_bit MISO pin's GPIO bit on comm_dev - * @param mosi_dev MOSI pin's GPIO device * @param mosi_bit MOSI pin's GPIO bit on comm_dev */ extern void spi_config_gpios(spi_dev *dev, @@ -308,7 +304,7 @@ void spi_slave_enable(spi_dev *dev, spi_mode mode, uint32 flags); -uint32 spi_tx(spi_dev *dev, const void *buf, uint32 len); +void spi_tx(spi_dev *dev, void *buf, uint32 len); /** * @brief Call a function on each SPI port diff --git a/STM32F4/cores/maple/libmaple/spiF4.h b/STM32F4/cores/maple/libmaple/spiF4.h index d2ae557..cbdc91a 100644 --- a/STM32F4/cores/maple/libmaple/spiF4.h +++ b/STM32F4/cores/maple/libmaple/spiF4.h @@ -31,8 +31,8 @@ * @brief STM32F1 SPI/I2S series header. */ -#ifndef _LIBMAPLE_STM32F1_SPI_H_ -#define _LIBMAPLE_STM32F1_SPI_H_ +#ifndef _LIBMAPLE_SPI_F4_H_ +#define _LIBMAPLE_SPI_F4_H_ #include diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/audio/inc/usbd_audio_core.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/audio/inc/usbd_audio_core.h index f58ff06..7ac987d 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/audio/inc/usbd_audio_core.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/audio/inc/usbd_audio_core.h @@ -26,7 +26,7 @@ #include "usbd_ioreq.h" #include "usbd_req.h" -#include "usbd_desc.h" +#include diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/inc/usbd_cdc_core.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/inc/usbd_cdc_core.h index 926f42e..b1c8cc1 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/inc/usbd_cdc_core.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/inc/usbd_cdc_core.h @@ -24,7 +24,8 @@ #ifndef __USB_CDC_CORE_H_ #define __USB_CDC_CORE_H_ -#include "usbd_ioreq.h" +#include +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/src/usbd_cdc_core.c b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/src/usbd_cdc_core.c index aac6776..8f97c51 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/src/usbd_cdc_core.c +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/src/usbd_cdc_core.c @@ -58,9 +58,10 @@ */ /* Includes ------------------------------------------------------------------*/ -#include "usbd_cdc_core.h" -#include "usbd_desc.h" -#include "usbd_req.h" +#include +#include +#include +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_core.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_core.h index b876856..063a30e 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_core.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_core.h @@ -24,9 +24,9 @@ #define __USBD_CORE_H /* Includes ------------------------------------------------------------------*/ -#include "usb_dcd.h" +#include #include "usbd_def.h" -#include "usbd_conf.h" +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_def.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_def.h index a8c8671..f2a3115 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_def.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_def.h @@ -24,7 +24,7 @@ #ifndef __USBD_DEF_H #define __USBD_DEF_H /* Includes ------------------------------------------------------------------*/ -#include "usbd_conf.h" +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_req.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_req.h index 9aa9e44..f9849c6 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_req.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_req.h @@ -27,7 +27,7 @@ /* Includes ------------------------------------------------------------------*/ #include "usbd_def.h" #include "usbd_core.h" -#include "usbd_conf.h" +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_core.c b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_core.c index af75842..00bb251 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_core.c +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_core.c @@ -20,11 +20,11 @@ */ /* Includes ------------------------------------------------------------------*/ -#include "usbd_core.h" -#include "usbd_req.h" -#include "usbd_ioreq.h" -#include "usb_dcd_int.h" -#include "usb_bsp.h" +#include +#include +#include +#include +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_ioreq.c b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_ioreq.c index 6964766..20ee5a0 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_ioreq.c +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_ioreq.c @@ -20,7 +20,7 @@ */ /* Includes ------------------------------------------------------------------*/ -#include "usbd_ioreq.h" +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @{ */ diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_req.c b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_req.c index f08d26c..5fc2e03 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_req.c +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_req.c @@ -20,9 +20,9 @@ */ /* Includes ------------------------------------------------------------------*/ -#include "usbd_req.h" -#include "usbd_ioreq.h" -#include "usbd_desc.h" +#include +#include +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_core.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_core.h index 82a09e1..43c4781 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_core.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_core.h @@ -24,7 +24,7 @@ #define __USB_CORE_H__ /* Includes ------------------------------------------------------------------*/ -#include "usb_conf.h" +#include #include "usb_regs.h" #include "usb_defines.h" diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_defines.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_defines.h index 8c23d72..ee2c1a0 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_defines.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_defines.h @@ -24,7 +24,7 @@ #define __USB_DEF_H__ /* Includes ------------------------------------------------------------------*/ -#include "usb_conf.h" +#include /** @addtogroup USB_OTG_DRIVER * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_otg.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_otg.h index 54d61b8..1347f31 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_otg.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_otg.h @@ -23,6 +23,7 @@ #ifndef __USB_OTG__ #define __USB_OTG__ +#include "usb_core.h" /** @addtogroup USB_OTG_DRIVER * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_regs.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_regs.h index cd71ddf..99f844e 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_regs.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_regs.h @@ -24,8 +24,8 @@ #define __USB_OTG_REGS_H__ /* Includes ------------------------------------------------------------------*/ -#include "usb_conf.h" - +#include +#include /** @addtogroup USB_OTG_DRIVER * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_core.c b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_core.c index cb9eabc..1687afa 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_core.c +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_core.c @@ -20,8 +20,8 @@ */ /* Includes ------------------------------------------------------------------*/ -#include "usb_bsp.h" -#include "usb_core.h" +#include +#include /** @addtogroup USB_OTG_DRIVER diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_dcd.c b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_dcd.c index c3336cb..dc9e538 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_dcd.c +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_dcd.c @@ -20,8 +20,8 @@ */ /* Includes ------------------------------------------------------------------*/ -#include "usb_dcd.h" -#include "usb_bsp.h" +#include +#include /** @addtogroup USB_OTG_DRIVER diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_dcd_int.c b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_dcd_int.c index 3a49ede..f9e561f 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_dcd_int.c +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_dcd_int.c @@ -20,12 +20,12 @@ */ /* Includes ------------------------------------------------------------------*/ -#include "usb_dcd_int.h" +#include typedef int IRQn_Type; #define __NVIC_PRIO_BITS 4 #define __Vendor_SysTickConfig 1 -#include +#include /** @addtogroup USB_OTG_DRIVER diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/core_cm4.h b/STM32F4/cores/maple/libmaple/usbF4/VCP/core_cm4.h index 443665c..ff5e9a6 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/core_cm4.h +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/core_cm4.h @@ -141,7 +141,7 @@ #endif #include /*!< standard types definitions */ -#include /*!< Core Instruction Access */ +#include "core_cmInstr.h" /*!< Core Instruction Access */ //#include /*!< Core Function Access */ //#include /*!< Compiler specific SIMD Intrinsics */ diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/misc.c b/STM32F4/cores/maple/libmaple/usbF4/VCP/misc.c index 9f33150..15a715e 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/misc.c +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/misc.c @@ -80,7 +80,7 @@ typedef unsigned char u8; typedef int IRQn_Type; #define __NVIC_PRIO_BITS 4 #define __Vendor_SysTickConfig 1 -#include +#include "core_cm4.h" /** @addtogroup STM32F4xx_StdPeriph_Driver * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/usb_bsp.c b/STM32F4/cores/maple/libmaple/usbF4/VCP/usb_bsp.c index c402bbd..e794cb1 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/usb_bsp.c +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/usb_bsp.c @@ -21,13 +21,13 @@ */ /* Includes ------------------------------------------------------------------*/ -#include "usb_bsp.h" +#include #include "usbd_conf.h" -#include +#include typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState; #define OTG_FS_IRQn 67 //typedef unsigned char uint8_t; -#include +#include "misc.h" //#include "stm32f4_discovery.h" diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.h b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.h index 67475e7..8398dbd 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.h +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.h @@ -26,7 +26,7 @@ /* Includes ------------------------------------------------------------------*/ //#include "stm32f4xx.h" -#include "usbd_cdc_core.h" +#include #include "usbd_conf.h" diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_conf.h b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_conf.h index 516a2fb..62a40c2 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_conf.h +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_conf.h @@ -25,6 +25,7 @@ /* Includes ------------------------------------------------------------------*/ //#include "stm32f4_discovery.h" +#include "usb_conf.h" /** @defgroup USB_CONF_Exported_Defines * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.c b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.c index 537f266..0153858 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.c +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.c @@ -20,11 +20,11 @@ */ /* Includes ------------------------------------------------------------------*/ -#include "usbd_core.h" +#include #include "usbd_desc.h" -#include "usbd_req.h" +#include #include "usbd_conf.h" -#include "usb_regs.h" +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.h b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.h index ed999dc..4ae998c 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.h +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.h @@ -25,7 +25,7 @@ #define __USB_DESC_H /* Includes ------------------------------------------------------------------*/ -#include "usbd_def.h" +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_usr.c b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_usr.c index 84e8d6a..a16ce40 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_usr.c +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_usr.c @@ -20,8 +20,8 @@ */ /* Includes ------------------------------------------------------------------*/ -#include "usbd_usr.h" -#include "usbd_ioreq.h" +#include +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY diff --git a/STM32F4/cores/maple/libmaple/usbF4/usb.c b/STM32F4/cores/maple/libmaple/usbF4/usb.c index 49ddc06..3850719 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/usb.c +++ b/STM32F4/cores/maple/libmaple/usbF4/usb.c @@ -1,10 +1,14 @@ -#include "usbd_cdc_core.h" -#include "usbd_usr.h" -#include "usbd_desc.h" +#ifndef _USBF4_USB_H_ +#define _USBF4_USB_H_ + + +#include +#include +#include #include "usb.h" -#include -#include -#include +#include +#include +#include #include USB_OTG_CORE_HANDLE USB_OTG_dev; @@ -92,7 +96,7 @@ RESULT usbPowerOff(void) { void usbDsbISR(void) {}; -#include "usb_dcd_int.h" +#include void __irq_OTG_FS_IRQHandler(void) { USBD_OTG_ISR_Handler (&USB_OTG_dev); @@ -101,3 +105,5 @@ void __irq_OTG_FS_IRQHandler(void) void x__irq_usbwakeup(void) { } + +#endif diff --git a/STM32F4/cores/maple/libmaple/usbF4/usb.h b/STM32F4/cores/maple/libmaple/usbF4/usb.h index f09f2bd..ce1a558 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/usb.h +++ b/STM32F4/cores/maple/libmaple/usbF4/usb.h @@ -5,7 +5,7 @@ extern "C" { #endif -#include "usb_conf.h" +#include typedef enum _RESULT { diff --git a/STM32F4/cores/maple/libmaple/util.h b/STM32F4/cores/maple/libmaple/util.h index 62ad8af..c5ed2de 100644 --- a/STM32F4/cores/maple/libmaple/util.h +++ b/STM32F4/cores/maple/libmaple/util.h @@ -29,11 +29,12 @@ * @brief Miscellaneous utility macros and procedures. */ -#include "libmaple_types.h" - #ifndef _UTIL_H_ #define _UTIL_H_ +#include "libmaple_types.h" +#include "delay.h" + #ifdef __cplusplus extern "C"{ #endif diff --git a/STM32F4/cores/maple/pwm.cpp b/STM32F4/cores/maple/pwm.cpp index 1806348..c5f2ccb 100644 --- a/STM32F4/cores/maple/pwm.cpp +++ b/STM32F4/cores/maple/pwm.cpp @@ -28,8 +28,8 @@ * @brief Arduino-style PWM implementation. */ -#include "libmaple_types.h" -#include "timer.h" +#include +#include #include "boards.h" #include "pwm.h" diff --git a/STM32F4/cores/maple/wirish.h b/STM32F4/cores/maple/wirish.h index 7e94fb3..d9a17bf 100644 --- a/STM32F4/cores/maple/wirish.h +++ b/STM32F4/cores/maple/wirish.h @@ -34,9 +34,9 @@ #define _WIRISH_H_ #include -#include "libmaple.h" +#include +#include -#include "wirish_types.h" #include "boards.h" #include "io.h" #include "bits.h" @@ -44,9 +44,8 @@ #include "ext_interrupts.h" #include "wirish_debug.h" #include "wirish_math.h" -#include "wirish_time.h" #include -#include "HardwareSerial.h" +#include #include "HardwareTimer.h" #include "usb_serial.h" @@ -54,8 +53,10 @@ #define HIGH 0x1 #define LOW 0x0 -//#define true 0x1 -//#define false 0x0 +#ifndef true + #define true 0x1 + #define false 0x0 +#endif #define lowByte(w) ((w) & 0xFF) diff --git a/STM32F4/cores/maple/wirish_constants.h b/STM32F4/cores/maple/wirish_constants.h index 06a85ae..f39c077 100644 --- a/STM32F4/cores/maple/wirish_constants.h +++ b/STM32F4/cores/maple/wirish_constants.h @@ -1,5 +1,5 @@ -#ifndef _WIRING_CONSTANTS_ -#define _WIRING_CONSTANTS_ +#ifndef _WIRISH_CONSTANTS_H_ +#define _WIRISH_CONSTANTS_H_ #ifdef __cplusplus extern "C"{ diff --git a/STM32F4/cores/maple/wirish_debug.h b/STM32F4/cores/maple/wirish_debug.h index d4c0bab..d7dea23 100644 --- a/STM32F4/cores/maple/wirish_debug.h +++ b/STM32F4/cores/maple/wirish_debug.h @@ -24,6 +24,9 @@ * SOFTWARE. *****************************************************************************/ +#ifndef _WIRISH_DEBUG_H_ +#define _WIRISH_DEBUG_H_ + /** * @file wirish_debug.h * @brief High level debug port configuration @@ -50,5 +53,7 @@ static inline void disableDebugPorts(void) { * @see disableDebugPorts() */ static inline void enableDebugPorts(void) { - afio_cfg_debug_ports(AFIO_DEBUG_FULL_SWJ); + afio_cfg_debug_ports(AFIO_DEBUG_SW_ONLY); //AFIO_DEBUG_FULL_SWJ); } + +#endif diff --git a/STM32F4/cores/maple/wirish_math.h b/STM32F4/cores/maple/wirish_math.h index a85b30a..0b8b222 100644 --- a/STM32F4/cores/maple/wirish_math.h +++ b/STM32F4/cores/maple/wirish_math.h @@ -29,8 +29,8 @@ * @brief Includes ; provides Arduino-compatible math routines. */ -#ifndef _WIRING_MATH_H_ -#define _WIRING_MATH_H_ +#ifndef _WIRISH_MATH_H_ +#define _WIRISH_MATH_H_ #include diff --git a/STM32F4/cores/maple/wirish_time.cpp b/STM32F4/cores/maple/wirish_time.cpp index 270da28..654c1a2 100644 --- a/STM32F4/cores/maple/wirish_time.cpp +++ b/STM32F4/cores/maple/wirish_time.cpp @@ -28,10 +28,10 @@ * @brief Delay implementation. */ -#include "libmaple.h" -#include "systick.h" +#include +#include #include "wirish_time.h" -#include "delay.h" +#include void delay(unsigned long ms) { uint32 i; diff --git a/STM32F4/cores/maple/wirish_time.h b/STM32F4/cores/maple/wirish_time.h index 20a2fbf..3a11786 100644 --- a/STM32F4/cores/maple/wirish_time.h +++ b/STM32F4/cores/maple/wirish_time.h @@ -32,10 +32,9 @@ #ifndef __WIRISH_TIME_H_ #define __WIRISH_TIME_H_ -#include "libmaple.h" -#include "nvic.h" -#include "systick.h" #include "boards.h" +#include +#include #define US_PER_MS 1000 diff --git a/STM32F4/cores/maple/wirish_types.h b/STM32F4/cores/maple/wirish_types.h index 95e524f..aea86fb 100644 --- a/STM32F4/cores/maple/wirish_types.h +++ b/STM32F4/cores/maple/wirish_types.h @@ -33,10 +33,9 @@ #ifndef _WIRISH_TYPES_H_ #define _WIRISH_TYPES_H_ -#include "libmaple_types.h" -#include "gpio_def.h" -#include "timer.h" -#include "adc.h" +#include +#include +#include /** * Invalid stm32_pin_info adc_channel value. diff --git a/STM32F4/libraries/SPI/library.properties b/STM32F4/libraries/SPI/library.properties index 6f20f01..ba3a577 100644 --- a/STM32F4/libraries/SPI/library.properties +++ b/STM32F4/libraries/SPI/library.properties @@ -7,3 +7,4 @@ paragraph=SPI for STM32F4 category=Communication url= architectures=STM32F4 +maintainer= \ No newline at end of file diff --git a/STM32F4/libraries/SPI/src/SPI.cpp b/STM32F4/libraries/SPI/src/SPI.cpp index 08fbbd5..baef0ab 100644 --- a/STM32F4/libraries/SPI/src/SPI.cpp +++ b/STM32F4/libraries/SPI/src/SPI.cpp @@ -40,9 +40,7 @@ #include "wirish.h" #include "boards.h" -//#include "HardwareSerial.h" - -#if CYCLES_PER_MICROSECOND != 72 +#if CYCLES_PER_MICROSECOND != 168 /* TODO [0.2.0?] something smarter than this */ #warning "Unexpected clock speed; SPI frequency calculation will be incorrect" #endif @@ -91,77 +89,105 @@ static const spi_pins board_spi_pins[] __FLASH__ = { */ SPIClass::SPIClass(uint32 spi_num) { + + _currentSetting=&_settings[spi_num-1];// SPI channels are called 1 2 and 3 but the array is zero indexed + + switch (spi_num) { #if BOARD_NR_SPI >= 1 case 1: - this->spi_d = SPI1; + _currentSetting->spi_d = SPI1; break; #endif #if BOARD_NR_SPI >= 2 case 2: - this->spi_d = SPI2; + _currentSetting->spi_d = SPI2; break; #endif #if BOARD_NR_SPI >= 3 case 3: - this->spi_d = SPI3; + _currentSetting->spi_d = SPI3; break; #endif default: ASSERT(0); } - //pinMode(BOARD_SPI_DEFAULT_SS,OUTPUT); - - clockDivider = SPI_BAUD_PCLK_DIV_16; - dataMode = SPI_MODE0; + // Init things specific to each SPI device + // clock divider setup is a bit of hack, and needs to be improved at a later date. + _settings[0].spi_d = SPI1; + _settings[0].clockDivider = determine_baud_rate(_settings[0].spi_d, _settings[0].clock); +#ifdef SPI_DMA + _settings[0].spiDmaDev = DMA1; + _settings[0].spiTxDmaChannel = DMA_CH3; + _settings[0].spiRxDmaChannel = DMA_CH2; +#endif + _settings[1].spi_d = SPI2; + _settings[1].clockDivider = determine_baud_rate(_settings[1].spi_d, _settings[1].clock); +#ifdef SPI_DMA + _settings[1].spiDmaDev = DMA1; + _settings[1].spiTxDmaChannel = DMA_CH5; + _settings[1].spiRxDmaChannel = DMA_CH4; +#endif +#if BOARD_NR_SPI >= 3 + _settings[2].spi_d = SPI3; + _settings[2].clockDivider = determine_baud_rate(_settings[2].spi_d, _settings[2].clock); +#ifdef SPI_DMA + _settings[2].spiDmaDev = DMA2; + _settings[2].spiTxDmaChannel = DMA_CH2; + _settings[2].spiRxDmaChannel = DMA_CH1; +#endif +#endif + } /* * Set up/tear down */ +void SPIClass::updateSettings(void) { + uint32 flags = ((_currentSetting->bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | _currentSetting->dataSize | SPI_SW_SLAVE | SPI_SOFT_SS); + #ifdef SPI_DEBUG + Serial.print("spi_master_enable("); Serial.print(_currentSetting->clockDivider); Serial.print(","); Serial.print(_currentSetting->dataMode); Serial.print(","); Serial.print(flags); Serial.println(")"); + #endif + spi_master_enable(_currentSetting->spi_d, (spi_baud_rate)_currentSetting->clockDivider, (spi_mode)_currentSetting->dataMode, flags); +} void SPIClass::begin(void) { - - uint32 flags = ((bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | SPI_DFF_8_BIT | SPI_SW_SLAVE | SPI_SOFT_SS); - spi_init(spi_d); - configure_gpios(spi_d, 1); - #ifdef SPI_DEBUG - Serial.print("spi_master_enable("); Serial.print(clockDivider); Serial.print(","); Serial.print(dataMode); Serial.print(","); Serial.print(flags); Serial.println(")"); - #endif - spi_master_enable(spi_d, (spi_baud_rate)clockDivider, (spi_mode)dataMode, flags); + spi_init(_currentSetting->spi_d); + configure_gpios(_currentSetting->spi_d, 1); + updateSettings(); +#ifdef SPI_USE_DMA_BUFFER + dmaSendBufferInit(); +#endif +//Serial.println("SPI class begin - end"); } void SPIClass::beginSlave(void) { - if (dataMode >= 4) { - ASSERT(0); - return; - } - uint32 flags = ((bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | SPI_DFF_8_BIT | SPI_SW_SLAVE); - spi_init(spi_d); - configure_gpios(spi_d, 0); + 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_RX_ONLY); #ifdef SPI_DEBUG - Serial.print("spi_slave_enable("); Serial.print(dataMode); Serial.print(","); Serial.print(flags); Serial.println(")"); + Serial.print("spi_slave_enable("); Serial.print(_currentSetting->dataMode); Serial.print(","); Serial.print(flags); Serial.println(")"); #endif - spi_slave_enable(spi_d, (spi_mode)dataMode, flags); + spi_slave_enable(_currentSetting->spi_d, (spi_mode)_currentSetting->dataMode, flags); } void SPIClass::end(void) { - if (!spi_is_enabled(this->spi_d)) { + if (!spi_is_enabled(_currentSetting->spi_d)) { return; } // Follows RM0008's sequence for disabling a SPI in master/slave // full duplex mode. - while (spi_is_rx_nonempty(this->spi_d)) { + while (spi_is_rx_nonempty(_currentSetting->spi_d)) { // FIXME [0.1.0] remove this once you have an interrupt based driver - volatile uint16 rx __attribute__((unused)) = spi_rx_reg(this->spi_d); + volatile uint16 rx __attribute__((unused)) = spi_rx_reg(_currentSetting->spi_d); } - while (!spi_is_tx_empty(this->spi_d)) + while (!spi_is_tx_empty(_currentSetting->spi_d)) ; - while (spi_is_busy(this->spi_d)) + while (spi_is_busy(_currentSetting->spi_d)) ; - spi_peripheral_disable(this->spi_d); + spi_peripheral_disable(_currentSetting->spi_d); } /* Roger Clark added 3 functions */ @@ -170,8 +196,9 @@ void SPIClass::setClockDivider(uint32_t clockDivider) #ifdef SPI_DEBUG Serial.print("Clock divider set to "); Serial.println(clockDivider); #endif - this->clockDivider = clockDivider; - this->begin(); + _currentSetting->clockDivider = clockDivider; + uint32 cr1 = _currentSetting->spi_d->regs->CR1 & ~(SPI_CR1_BR); + _currentSetting->spi_d->regs->CR1 = cr1 | (clockDivider & SPI_CR1_BR); } void SPIClass::setBitOrder(BitOrder bitOrder) @@ -179,8 +206,10 @@ void SPIClass::setBitOrder(BitOrder bitOrder) #ifdef SPI_DEBUG Serial.print("Bit order set to "); Serial.println(bitOrder); #endif - this->bitOrder = bitOrder; - this->begin(); + _currentSetting->bitOrder = bitOrder; + uint32 cr1 = _currentSetting->spi_d->regs->CR1 & ~(SPI_CR1_LSBFIRST); + if ( bitOrder==LSBFIRST ) cr1 |= SPI_CR1_LSBFIRST; + _currentSetting->spi_d->regs->CR1 = cr1; } /* Victor Perez. Added to test changing datasize from 8 to 16 bit modes on the fly. @@ -189,11 +218,11 @@ void SPIClass::setBitOrder(BitOrder bitOrder) */ void SPIClass::setDataSize(uint32 datasize) { - uint32 cr1 = this->spi_d->regs->CR1; - datasize &= SPI_CR1_DFF; - cr1 &= ~(SPI_CR1_DFF); - cr1 |= datasize; - this->spi_d->regs->CR1 = cr1; + _currentSetting->dataSize = datasize; + 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) @@ -212,13 +241,11 @@ SPI Mode CPOL CPHA Shift SCK-edge Capture SCK-edge On the STM32 it appears to be bit 1 - CPOL : Clock polarity - (This bit should not be changed when communication is ongoing) 0 : CLK to 0 when idle 1 : CLK to 1 when idle bit 0 - CPHA : Clock phase - (This bit should not be changed when communication is ongoing) 0 : The first clock transition is the first data capture edge 1 : The second clock transition is the first data capture edge @@ -228,10 +255,10 @@ If someone finds this is not the case or sees a logic error with this let me kno #ifdef SPI_DEBUG Serial.print("Data mode set to "); Serial.println(dataMode); #endif - this->dataMode = dataMode; - this->begin(); -} - + _currentSetting->dataMode = dataMode; + uint32 cr1 = _currentSetting->spi_d->regs->CR1 & ~(SPI_CR1_CPOL|SPI_CR1_CPHA); + _currentSetting->spi_d->regs->CR1 = cr1 | (dataMode & (SPI_CR1_CPOL|SPI_CR1_CPHA)); +} void SPIClass::beginTransaction(uint8_t pin, SPISettings settings) { @@ -243,29 +270,20 @@ void SPIClass::beginTransaction(uint8_t pin, SPISettings settings) //digitalWrite(_SSPin,LOW); setBitOrder(settings.bitOrder); setDataMode(settings.dataMode); - setClockDivider(determine_baud_rate(spi_d, settings.clock)); + setDataSize(settings.dataSize); + setClockDivider(determine_baud_rate(_currentSetting->spi_d, settings.clock)); begin(); -#if 0 -// code from SAM core - uint8_t mode = interruptMode; - if (mode > 0) { - if (mode < 16) { - if (mode & 1) PIOA->PIO_IDR = interruptMask[0]; - if (mode & 2) PIOB->PIO_IDR = interruptMask[1]; - if (mode & 4) PIOC->PIO_IDR = interruptMask[2]; - if (mode & 8) PIOD->PIO_IDR = interruptMask[3]; - } else { - interruptSave = interruptsStatus(); - noInterrupts(); - } - } - uint32_t ch = BOARD_PIN_TO_SPI_CHANNEL(pin); - bitOrder[ch] = settings.border; - SPI_ConfigureNPCS(spi, ch, settings.config); - //setBitOrder(pin, settings.border); - //setDataMode(pin, settings.datamode); - //setClockDivider(pin, settings.clockdiv); -#endif +} + +void SPIClass::beginTransactionSlave(SPISettings settings) +{ + #ifdef SPI_DEBUG + Serial.println(F("SPIClass::beginTransactionSlave")); + #endif + setBitOrder(settings.bitOrder); + setDataMode(settings.dataMode); + setDataSize(settings.dataSize); + beginSlave(); } void SPIClass::endTransaction(void) @@ -295,131 +313,127 @@ void SPIClass::endTransaction(void) * I/O */ -uint8 SPIClass::read(void) { - uint8 buf[1]; - this->read(buf, 1); - return buf[0]; +uint16 SPIClass::read(void) +{ + while ( spi_is_rx_nonempty(_currentSetting->spi_d)==0 ) ; + return (uint16)spi_rx_reg(_currentSetting->spi_d); } -void SPIClass::read(uint8 *buf, uint32 len) { - uint32 rxed = 0; - while (rxed < len) { - while (!spi_is_rx_nonempty(this->spi_d)) - ; - buf[rxed++] = (uint8)spi_rx_reg(this->spi_d); +void SPIClass::read(uint8 *buf, uint32 len) +{ + 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; + // 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 } } -void SPIClass::write(uint16 data) { - #ifdef SPI_DEBUG -// Serial.print("SPIClass::write("); Serial.print(data); Serial.println(")"); - #endif - // 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(this->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(this->spi_d) == 0); // "5. Wait until TXE=1 ..." - while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." + spi_tx_reg(_currentSetting->spi_d, data); // write the data to be transmitted into the SPI_DR register (this clears the TXE flag) +//return; + 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(this->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(this->spi_d) == 0); // "5. Wait until TXE=1 ..." -// while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." -//} - -void SPIClass::write(const uint8 *data, uint32 length) { - #ifdef SPI_DEBUG - Serial.print("SPIClass::write(data, "); Serial.print(length); Serial.println(")"); - #endif - uint32 txed = 0; - while (txed < length) { - txed += spi_tx(this->spi_d, data + txed, length - txed); - } - while (spi_is_tx_empty(this->spi_d) == 0); // "4. After writing the last data item into the SPI_DR register, wait until TXE=1 ..." - while (spi_is_busy(this->spi_d) != 0); // "... then wait until BSY=0, this indicates that the transmission of the last data is complete." +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 } -uint8 SPIClass::transfer(uint8 byte) const { - #ifdef SPI_DEBUG -// Serial.print("SPIClass::transfer("); Serial.print(byte); Serial.println(")"); - #endif - uint8 b; - spi_tx_reg(this->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(this->spi_d) == 0); // "4. Wait until RXNE=1 ..." - b = spi_rx_reg(this->spi_d); // "... and read the last received data." - while (spi_is_tx_empty(this->spi_d) == 0); // "5. Wait until TXE=1 ..." - while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." - return b; +void SPIClass::write(void *data, uint32 length) +{ + 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_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_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." +} + +#ifdef SPI_DMA /* 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; - if (spi_is_rx_nonempty(this->spi_d) == 1) b = spi_rx_reg(this->spi_d); //Clear the RX buffer in case a byte is waiting on it. - dma1_ch3_Active=true; - dma_init(DMA1); - dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event); - + 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(SPI1); - dma_setup_transfer(DMA1, DMA_CH2, &SPI1->regs->DR, DMA_SIZE_8BITS, - receiveBuf, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_TRNS_CMPLT));// receive buffer DMA - dma_set_num_transfers(DMA1, DMA_CH2, length); - + spi_rx_dma_enable(_currentSetting->spi_d); + dma_xfer_size dma_bit_size = (_currentSetting->dataSize==SPI_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); + // TX - spi_tx_dma_enable(SPI1); - if (!transmitBuf) { - static uint8_t ff = 0XFF; - transmitBuf = &ff; - dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_8BITS, - transmitBuf, DMA_SIZE_8BITS, (DMA_FROM_MEM | DMA_TRNS_CMPLT));// Transmit FF repeatedly + 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 } - else { - dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_8BITS, - transmitBuf, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_FROM_MEM | DMA_TRNS_CMPLT));// Transmit buffer DMA - } - dma_set_num_transfers(DMA1, DMA_CH3, 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(DMA1, DMA_CH2);// enable receive - dma_enable(DMA1, DMA_CH3);// enable transmit + 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 (dma1_ch3_Active) { - if ((millis() - m) > 100) { - dma1_ch3_Active = 0; - b = 2; - break; - } + 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); -// } - while (spi_is_tx_empty(this->spi_d) == 0); // "5. Wait until TXE=1 ..." - while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." - dma_disable(DMA1, DMA_CH3); - dma_disable(DMA1, DMA_CH2); - spi_rx_dma_disable(SPI1); - spi_tx_dma_disable(SPI1); + 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! return b; } @@ -427,56 +441,37 @@ 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, 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(DMA1); - dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event); - + uint32 flags = ( (DMA_MINC_MODE*minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT); + uint8 b = 0; + dma_init(_currentSetting->spiDmaDev); // TX - spi_tx_dma_enable(SPI1); - dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_8BITS, - transmitBuf, DMA_SIZE_8BITS, flags);// Transmit buffer DMA - dma_set_num_transfers(DMA1, DMA_CH3, length); - dma_enable(DMA1, DMA_CH3);// enable transmit - - while (dma1_ch3_Active); - while (spi_is_rx_nonempty(this->spi_d) == 0); // "4. Wait until RXNE=1 ..." - b = spi_rx_reg(this->spi_d); // "... and read the last received data." - while (spi_is_tx_empty(this->spi_d) == 0); // "5. Wait until TXE=1 ..." - while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." - dma_disable(DMA1, DMA_CH3); - spi_tx_dma_disable(SPI1); - return b; -} + spi_tx_dma_enable(_currentSetting->spi_d); + dma_xfer_size dma_bit_size = (_currentSetting->dataSize==SPI_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_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit -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(DMA1); - dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event); + 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. + if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; } + } + dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); - // TX - spi_tx_dma_enable(SPI1); - dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_16BITS, - transmitBuf, DMA_SIZE_16BITS, flags);// Transmit buffer DMA - dma_set_num_transfers(DMA1, DMA_CH3, length); - dma_enable(DMA1, DMA_CH3);// enable transmit - - while (dma1_ch3_Active); - while (spi_is_rx_nonempty(this->spi_d) == 0); // "4. Wait until RXNE=1 ..." - b = spi_rx_reg(this->spi_d); // "... and read the last received data." - while (spi_is_tx_empty(this->spi_d) == 0); // "5. Wait until TXE=1 ..." - while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." - dma_disable(DMA1, DMA_CH3); - spi_tx_dma_disable(SPI1); - 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." + 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; } +#endif + void SPIClass::attachInterrupt(void) { @@ -492,19 +487,19 @@ void SPIClass::detachInterrupt(void) { */ uint8 SPIClass::misoPin(void) { - return dev_to_spi_pins(this->spi_d)->miso; + return dev_to_spi_pins(_currentSetting->spi_d)->miso; } uint8 SPIClass::mosiPin(void) { - return dev_to_spi_pins(this->spi_d)->mosi; + return dev_to_spi_pins(_currentSetting->spi_d)->mosi; } uint8 SPIClass::sckPin(void) { - return dev_to_spi_pins(this->spi_d)->sck; + return dev_to_spi_pins(_currentSetting->spi_d)->sck; } uint8 SPIClass::nssPin(void) { - return dev_to_spi_pins(this->spi_d)->nss; + return dev_to_spi_pins(_currentSetting->spi_d)->nss; } /* @@ -585,29 +580,26 @@ static void configure_gpios(spi_dev *dev, bool as_master) { if(dev->clk_id <= RCC_SPI2) { if(nssi) { if(!as_master) { - gpio_set_af_mode(nssi->gpio_device, scki->gpio_bit, 5); + gpio_set_af_mode(pins->nss, 5); } } - gpio_set_af_mode(scki->gpio_device, scki->gpio_bit, 5); - gpio_set_af_mode(misoi->gpio_device, misoi->gpio_bit, 5); - gpio_set_af_mode(mosii->gpio_device, mosii->gpio_bit, 5); + gpio_set_af_mode(pins->sck, 5); + gpio_set_af_mode(pins->miso, 5); + gpio_set_af_mode(pins->mosi, 5); } else { if(nssi) { if(!as_master) { - gpio_set_af_mode(nssi->gpio_device, scki->gpio_bit, 6); + gpio_set_af_mode(pins->nss, 6); } } - gpio_set_af_mode(scki->gpio_device, scki->gpio_bit, 6); - gpio_set_af_mode(misoi->gpio_device, misoi->gpio_bit, 6); - gpio_set_af_mode(mosii->gpio_device, mosii->gpio_bit, 6); + gpio_set_af_mode(pins->sck, 6); + gpio_set_af_mode(pins->miso, 6); + gpio_set_af_mode(pins->mosi, 6); } #endif - spi_config_gpios(dev, as_master, nssi->gpio_device, nssi->gpio_bit, - scki->gpio_device, scki->gpio_bit, - misoi->gpio_device, misoi->gpio_bit, - mosii->gpio_device, mosii->gpio_bit); + spi_config_gpios(dev, as_master, pins->nss, pins->sck, pins->miso, pins->mosi); } static const spi_baud_rate baud_rates[8] __FLASH__ = { @@ -634,6 +626,8 @@ static spi_baud_rate determine_baud_rate(spi_dev *dev, uint32_t freq) { { case RCC_APB2: clock = STM32_PCLK2; break; // 72 Mhz case RCC_APB1: clock = STM32_PCLK1; break; // 36 Mhz + case RCC_AHB1: break; + default: break; } clock /= 2; i = 0; diff --git a/STM32F4/libraries/SPI/src/SPI.h b/STM32F4/libraries/SPI/src/SPI.h index 490d58b..1b01d9b 100644 --- a/STM32F4/libraries/SPI/src/SPI.h +++ b/STM32F4/libraries/SPI/src/SPI.h @@ -34,16 +34,12 @@ /* TODO [0.1.0] Remove deprecated methods. */ - -#ifndef _SPI_H_INCLUDED -#define _SPI_H_INCLUDED +#ifndef _LIB_SPI_H_ +#define _LIB_SPI_H_ #include #include #include - -#include -#include #include // SPI_HAS_TRANSACTION means SPI has @@ -96,33 +92,61 @@ #define SPI_MODE2 SPI_MODE_2 #define SPI_MODE3 SPI_MODE_3 +#define SPI_DATA_SIZE_8BIT SPI_CR1_DFF_8_BIT +#define SPI_DATA_SIZE_16BIT SPI_CR1_DFF_16_BIT + class SPISettings { public: SPISettings(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) { if (__builtin_constant_p(clock)) { - init_AlwaysInline(clock, bitOrder, dataMode); + init_AlwaysInline(clock, bitOrder, dataMode, SPI_DATA_SIZE_8BIT); } else { - init_MightInline(clock, bitOrder, dataMode); + init_MightInline(clock, bitOrder, dataMode, SPI_DATA_SIZE_8BIT); } } - SPISettings() { init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0); } -private: - void init_MightInline(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) { - init_AlwaysInline(clock, bitOrder, dataMode); + SPISettings(uint32_t clock, BitOrder bitOrder, uint8_t dataMode, uint32_t dataSize) { + if (__builtin_constant_p(clock)) { + init_AlwaysInline(clock, bitOrder, dataMode, dataSize); + } else { + init_MightInline(clock, bitOrder, dataMode, dataSize); + } } - void init_AlwaysInline(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) __attribute__((__always_inline__)) { + SPISettings(uint32_t clock) { + if (__builtin_constant_p(clock)) { + init_AlwaysInline(clock, MSBFIRST, SPI_MODE0, SPI_DATA_SIZE_8BIT); + } else { + init_MightInline(clock, MSBFIRST, SPI_MODE0, SPI_DATA_SIZE_8BIT); + } + } + SPISettings() { init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0, SPI_DATA_SIZE_8BIT); } +private: + void init_MightInline(uint32_t clock, BitOrder bitOrder, uint8_t dataMode, uint32_t dataSize) { + init_AlwaysInline(clock, bitOrder, dataMode, dataSize); + } + void init_AlwaysInline(uint32_t clock, BitOrder bitOrder, uint8_t dataMode, uint32_t dataSize) __attribute__((__always_inline__)) { this->clock = clock; this->bitOrder = bitOrder; this->dataMode = dataMode; + this->dataSize = dataSize; } uint32_t clock; BitOrder bitOrder; uint8_t dataMode; + uint32_t dataSize; + + spi_dev *spi_d; + //uint8_t _SSPin; + uint32_t clockDivider; +#ifdef SPI_DMA + dma_channel spiRxDmaChannel, spiTxDmaChannel; + dma_dev* spiDmaDev; +#endif + friend class SPIClass; }; -volatile static bool dma1_ch3_Active; + /** * @brief Wirish SPI interface. @@ -175,6 +199,8 @@ public: void beginTransaction(uint8_t pin, SPISettings settings); void endTransaction(void); + void beginTransactionSlave(SPISettings settings); + void setClockDivider(uint32_t clockDivider); void setBitOrder(BitOrder bitOrder); void setDataMode(uint8_t dataMode); @@ -195,40 +221,40 @@ 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(const uint8 *buffer, uint32 length); + 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(void * buffer, uint32 length); /** * @brief Transmit a byte, then return the next unread byte. @@ -239,9 +265,12 @@ public: * @return Next unread byte. */ uint8 transfer(uint8 data) const; + uint16_t transfer16(uint16_t data) const; +#ifdef SPI_DMA /** * @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. * @@ -249,30 +278,19 @@ 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, bool minc = 1); +#endif /* * Pin accessors @@ -304,7 +322,24 @@ public: * @brief Get a pointer to the underlying libmaple spi_dev for * this HardwareSPI instance. */ - spi_dev* c_dev(void) { return this->spi_d; } + spi_dev* c_dev(void) { return _currentSetting->spi_d; } + + + spi_dev *dev(){ return _currentSetting->spi_d;} + + /** + * @brief Sets the number of the SPI peripheral to be used by + * this HardwareSPI instance. + * + * @param spi_num Number of the SPI port. 1-2 in low density devices + * or 1-3 in high density devices. + */ + + void setModule(int spi_num) + { + _currentSetting=&_settings[spi_num-1];// SPI channels are called 1 2 and 3 but the array is zero indexed + } + /* -- The following methods are deprecated --------------------------- */ @@ -338,12 +373,8 @@ public: */ uint8 recv(void); - spi_dev *dev(){ return spi_d;} - - - private: - +/* static inline void DMA1_CH3_Event() { dma1_ch3_Active = 0; // dma_disable(DMA1, DMA_CH3); @@ -351,11 +382,18 @@ private: // To Do. Need to wait for } +*/ + SPISettings _settings[BOARD_NR_SPI]; + SPISettings *_currentSetting; + + void updateSettings(void); + /* spi_dev *spi_d; uint8_t _SSPin; uint32_t clockDivider; uint8_t dataMode; BitOrder bitOrder; + */ }; diff --git a/STM32F4/platform.txt b/STM32F4/platform.txt index 5bfa22e..2bb1946 100755 --- a/STM32F4/platform.txt +++ b/STM32F4/platform.txt @@ -8,8 +8,6 @@ version=0.1.0 # compiler variables # ---------------------- -#build.gcc_ver=gcc-arm-none-eabi-4.8.3-2014q1 - compiler.path={runtime.tools.arm-none-eabi-gcc.path}/bin/ compiler.c.cmd=arm-none-eabi-gcc compiler.c.flags=-c -g -Os -Wall -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} @@ -30,6 +28,8 @@ compiler.size.cmd=arm-none-eabi-size compiler.define=-DARDUINO= # this can be overriden in boards.txt +build.f_cpu=168000000L +build.mcu=cortex-m4 build.cpu_flags= build.hs_flag= build.common_flags=-mthumb -D__STM32F4__ @@ -44,10 +44,10 @@ compiler.ar.extra_flags= compiler.elf2hex.extra_flags= -##compiler.libs.c.flags="-I{build.system.path}/libmaple" "-I{build.system.path}/libmaple/include" "-I{build.system.path}/libmaple/stm32f1/include" "-I{build.system.path}/libmaple/stm32f1/include/series" "-I{build.system.path}/libmaple/usb/stm32f1" "-I{build.system.path}/libmaple/usb/usb_lib" -#compiler.libs.c.flags="-I{build.system.path}/libmaple" "-I{build.system.path}/libmaple/include" "-I{build.system.path}/libmaple/stm32f1/include" "-I{build.system.path}/libmaple/usb/stm32f1" "-I{build.system.path}/libmaple/usb/usb_lib" +##compiler.libs.c.flags="-I{build.system.path}/libmaple" "-I{build.system.path}/libmaple/include" "-I{build.system.path}/libmaple/stm32f1/include" "-I{build.system.path}/libmaple/usb/stm32f1" "-I{build.system.path}/libmaple/usb/usb_lib" +#compiler.libs.c.flags="-I{build.core.path}" "-I{build.core.path}/libmaple" "-I{build.core.path}/libmaple/usbF4" "-I{build.core.path}/libmaple/usbF4/STM32_USB_Device_Library/Core/inc" "-I{build.core.path}/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/inc" "-I{build.core.path}/libmaple/usbF4/STM32_USB_OTG_Driver/inc" "-I{build.core.path}/libmaple/usbF4/VCP" +compiler.libs.c.flags="-I{build.system.path}/libmaple" "-I{build.core.path}/libmaple/usbF4" -compiler.libs.c.flags=-I{build.core.path} -I{build.core.path}/libmaple -I{build.core.path}/libmaple/usbF4 -I{build.core.path}/libmaple/usbF4/STM32_USB_Device_Library/Core/inc -I{build.core.path}/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/inc -I{build.core.path}/libmaple/usbF4/STM32_USB_OTG_Driver/inc -I{build.core.path}/libmaple/usbF4/VCP @@ -71,7 +71,6 @@ recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} -m ## Compile S files recipe.S.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.S.flags} -mcpu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.S.extra_flags} {build.extra_flags} {build.cpu_flags} {build.hs_flag} {build.common_flags} {compiler.libs.c.flags} {includes} "{source_file}" -o "{object_file}" -#recipe.S.o.pattern="{compiler.path}{compiler.c.cmd}" "{source_file}" -o "{object_file}" ## Create archives recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{archive_file_path}" "{object_file}" @@ -90,7 +89,6 @@ recipe.objcopy.hex.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf ## Compute size recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.elf" -#recipe.size.regex=\.text\s+([0-9]+).* recipe.size.regex=^(?:\.text|\.rodata|\.ARM.exidx)\s+([0-9]+).* recipe.size.regex.data=^(?:\.data|\.bss|\.noinit)\s+([0-9]+).* diff --git a/STM32F4/system/libmaple/Arduino.h b/STM32F4/system/libmaple/Arduino.h new file mode 100644 index 0000000..cef8f08 --- /dev/null +++ b/STM32F4/system/libmaple/Arduino.h @@ -0,0 +1,46 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +#ifndef _WIRISH_ARDUINO_H_ +#define _WIRISH_ARDUINO_H_ + +//#warning Include Arduino.h from system\libmaple + +#include "wirish.h" + +void setup(); +void loop(); +#ifdef __cplusplus +extern "C"{ +#endif // __cplusplus +void yield(void); +#ifdef __cplusplus +} +#endif // __cplusplus + +#include "variant.h" + +#endif diff --git a/STM32F4/variants/generic_f407v/generic_f407v.cpp b/STM32F4/variants/generic_f407v/generic_f407v.cpp index 1199064..a4a5ecb 100644 --- a/STM32F4/variants/generic_f407v/generic_f407v.cpp +++ b/STM32F4/variants/generic_f407v/generic_f407v.cpp @@ -35,40 +35,11 @@ #include "generic_f407v.h" //#include "fsmc.h" -#include "gpio.h" -#include "rcc.h" -#include "timer.h" +#include +#include +#include -#include "wirish_types.h" - -// Pins reserved for the on-board hardware -#define USB_DM_PIN BOARD_USB_DM_PIN // PA11 -#define USB_DP_PIN BOARD_USB_DP_PIN // PA12 - -#define FLASH_CS_PIN PB0 -#define FLASH_CLK_PIN BOARD_SPI3_SCK_PIN // PB3 -#define FLASH_DO_PIN BOARD_SPI3_MISO_PIN // PB4 -#define FLASH_DI_PIN BOARD_SPI3_MOSI_PIN // PB5 - -#define NRF24_CLK_PIN BOARD_SPI3_SCK_PIN // PB3 -#define NRF24_DO_PIN BOARD_SPI3_MISO_PIN // PB4 -#define NRF24_DI_PIN BOARD_SPI3_MOSI_PIN // PB5 -#define NRF24_CE_PIN PB6 -#define NRF24_CS_PIN PB7 -#define NRF24_IRQ_PIN PB8 - -// SD card, SDIO mode -#define SD_DAT0 BOARD_SDIO_D0 // PC8 -#define SD_DAT1 BOARD_SDIO_D1 // PC9 -#define SD_DAT2 BOARD_SDIO_D2 // PC10 -#define SD_DAT3 BOARD_SDIO_D3 // PC11 -#define SD_CLK BOARD_SDIO_CK // PC12 -#define SD_CMD BOARD_SDIO_CMD // PD2 -// SD card, SPI mode, only usable with software SPI -#define SD_DI BOARD_SDIO_CMD // PD2 -#define SD_DO BOARD_SDIO_D0 // PC8 -#define SD_CS BOARD_SDIO_D3 // PC11 -#define SD_SCLK BOARD_SDIO_CK // PC12 +#include //static void initSRAMChip(void); /*****************************************************************************/ diff --git a/STM32F4/variants/generic_f407v/generic_f407v.h b/STM32F4/variants/generic_f407v/generic_f407v.h index b9f0348..927f9cd 100644 --- a/STM32F4/variants/generic_f407v/generic_f407v.h +++ b/STM32F4/variants/generic_f407v/generic_f407v.h @@ -47,6 +47,8 @@ #define SYSTICK_RELOAD_VAL (CYCLES_PER_MICROSECOND*1000-1) +/*****************************************************************************/ +// Board pin definitions #define BOARD_USB_DM_PIN PA11 #define BOARD_USB_DP_PIN PA12 @@ -92,10 +94,10 @@ #define BOARD_SPI3_MISO_PIN PB4 //Port2Pin('B', 4) #define BOARD_SPI3_MOSI_PIN PB5 //Port2Pin('B', 5) /* overlap with the SDIO interface for SD card -#define BOARD_SPI3A_NSS_PIN Port2Pin('A', 4) -#define BOARD_SPI3A_SCK_PIN Port2Pin('C',10) -#define BOARD_SPI3A_MISO_PIN Port2Pin('C',11) -#define BOARD_SPI3A_MOSI_PIN Port2Pin('C',12) +#define BOARD_SPI3A_NSS_PIN PA4 //Port2Pin('A', 4) +#define BOARD_SPI3A_SCK_PIN PC10 //Port2Pin('C',10) +#define BOARD_SPI3A_MISO_PIN PC11 //Port2Pin('C',11) +#define BOARD_SPI3A_MOSI_PIN PC12 //Port2Pin('C',12) */ #define BOARD_SDIO_D0 PC8 //Port2Pin('C', 8) #define BOARD_SDIO_D1 PC9 //Port2Pin('C', 9) @@ -114,6 +116,37 @@ #define BOARD_JTDO_PIN PB3 //Port2Pin('B', 3) #define BOARD_NJTRST_PIN PB4 //Port2Pin('B', 4) +/*****************************************************************************/ +// Pins reserved for the on-board hardware +#define USB_DM_PIN BOARD_USB_DM_PIN // PA11 +#define USB_DP_PIN BOARD_USB_DP_PIN // PA12 + +#define FLASH_CS_PIN PB0 +#define FLASH_CLK_PIN BOARD_SPI3_SCK_PIN // PB3 +#define FLASH_DO_PIN BOARD_SPI3_MISO_PIN // PB4 +#define FLASH_DI_PIN BOARD_SPI3_MOSI_PIN // PB5 + +#define NRF24_CLK_PIN BOARD_SPI3_SCK_PIN // PB3 +#define NRF24_DO_PIN BOARD_SPI3_MISO_PIN // PB4 +#define NRF24_DI_PIN BOARD_SPI3_MOSI_PIN // PB5 +#define NRF24_CE_PIN PB6 +#define NRF24_CS_PIN PB7 +#define NRF24_IRQ_PIN PB8 + +// SD card, SDIO mode +#define SD_DAT0 BOARD_SDIO_D0 // PC8 +#define SD_DAT1 BOARD_SDIO_D1 // PC9 +#define SD_DAT2 BOARD_SDIO_D2 // PC10 +#define SD_DAT3 BOARD_SDIO_D3 // PC11 +#define SD_CLK BOARD_SDIO_CK // PC12 +#define SD_CMD BOARD_SDIO_CMD // PD2 +// SD card, SPI mode, only usable with software SPI +#define SD_DI BOARD_SDIO_CMD // PD2 +#define SD_DO BOARD_SDIO_D0 // PC8 +#define SD_CS BOARD_SDIO_D3 // PC11 +#define SD_SCLK BOARD_SDIO_CK // PC12 + +/*****************************************************************************/ enum { PA0,PA1,PA2,PA3,PA4,PA5,PA6,PA7,PA8,PA9,PA10,PA11,PA12,PA13,PA14,PA15, From 483bbe17d3ddbe827a9c1ddd1197745f8b69a016 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Thu, 4 May 2017 17:18:11 +0200 Subject: [PATCH 028/351] corrected OTYPER register setting --- STM32F4/cores/maple/libmaple/gpioF4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F4/cores/maple/libmaple/gpioF4.c b/STM32F4/cores/maple/libmaple/gpioF4.c index 6fec61c..fe3cc87 100644 --- a/STM32F4/cores/maple/libmaple/gpioF4.c +++ b/STM32F4/cores/maple/libmaple/gpioF4.c @@ -162,7 +162,7 @@ void gpio_set_mode(uint8_t io_pin, gpio_pin_mode mode) { regs->MODER = (regs->MODER & ~( 3 << (pin<<1))) | (((mode >> 0) & 3) << (pin<<1)); regs->PUPDR = (regs->PUPDR & ~( 3 << (pin<<1))) | (((mode >> 2) & 3) << (pin<<1)); regs->OSPEEDR = (regs->OSPEEDR & ~( 3 << (pin<<1))) | (((mode >> 4) & 3) << (pin<<1)); - regs->OTYPER = (regs->OTYPER & ~( 1 << (pin<<1))) | (((mode >> 6) & 1) << (pin<<1)); + regs->OTYPER = (regs->OTYPER & ~( 1 << (pin<<0))) | (((mode >> 6) & 1) << (pin<<0)); } /** From 30d1bf490071c6beeeb3b6f1eb108f4450e0fdf6 Mon Sep 17 00:00:00 2001 From: syfre Date: Sat, 6 May 2017 23:02:54 +0200 Subject: [PATCH 029/351] Fix, add ADC_CR2_EXTTRIG to adc_set_extsel() to enable the external trigger mode --- STM32F1/cores/maple/libmaple/adc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/STM32F1/cores/maple/libmaple/adc.c b/STM32F1/cores/maple/libmaple/adc.c index 7c48ee4..416cfaa 100644 --- a/STM32F1/cores/maple/libmaple/adc.c +++ b/STM32F1/cores/maple/libmaple/adc.c @@ -59,6 +59,7 @@ void adc_set_extsel(adc_dev *dev, adc_extsel_event event) { uint32 cr2 = dev->regs->CR2; cr2 &= ~ADC_CR2_EXTSEL; cr2 |= event; + cr2 |= ADC_CR2_EXTTRIG; dev->regs->CR2 = cr2; } From 50e4d84db49dbe20d759f99614bb6d71ef8737e5 Mon Sep 17 00:00:00 2001 From: syfre Date: Sat, 6 May 2017 23:03:47 +0200 Subject: [PATCH 030/351] Add, setMasterModeTrGo to configure the TrGo mode Use to trigger the ADC on TIMx_TRGO --- STM32F1/cores/maple/HardwareTimer.cpp | 5 +++++ STM32F1/cores/maple/HardwareTimer.h | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/STM32F1/cores/maple/HardwareTimer.cpp b/STM32F1/cores/maple/HardwareTimer.cpp index 48d0400..ecd1b11 100644 --- a/STM32F1/cores/maple/HardwareTimer.cpp +++ b/STM32F1/cores/maple/HardwareTimer.cpp @@ -142,6 +142,11 @@ void HardwareTimer::refresh(void) { timer_generate_update(this->dev); } +void HardwareTimer::setMasterModeTrGo(uint32_t mode) { + this->dev->regs.bas->CR2 &= ~TIMER_CR2_MMS; + this->dev->regs.bas->CR2 |= mode; +} + /* CARLOS Changes to add encoder mode.*/ //direction of movement. (to be better described). diff --git a/STM32F1/cores/maple/HardwareTimer.h b/STM32F1/cores/maple/HardwareTimer.h index 45272ec..75601d0 100644 --- a/STM32F1/cores/maple/HardwareTimer.h +++ b/STM32F1/cores/maple/HardwareTimer.h @@ -209,6 +209,23 @@ public: */ void refresh(void); + // SYFRE + /** + * @brief Set the Master mode TRGO signal + * These bits allow to select the information to be sent in master mode to slave timers for + * synchronization (TRGO). + * mode: + * TIMER_CR2_MMS_RESET + * TIMER_CR2_MMS_ENABLE + * TIMER_CR2_MMS_UPDATE + * TIMER_CR2_MMS_COMPARE_PULSE + * TIMER_CR2_MMS_COMPARE_OC1REF + * TIMER_CR2_MMS_COMPARE_OC2REF + * TIMER_CR2_MMS_COMPARE_OC3REF + * TIMER_CR2_MMS_COMPARE_OC4REF + */ + void setMasterModeTrGo(uint32_t mode); + //CARLOS. /* added these functions to make sense for the encoder mode. From d240a7efa737a4f4a7a8f053c4a3d1eb4da68841 Mon Sep 17 00:00:00 2001 From: syfre Date: Sat, 6 May 2017 23:04:11 +0200 Subject: [PATCH 031/351] Fix, compile error in enable_internal_reading() --- STM32F1/libraries/STM32ADC/src/utility/util_adc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/libraries/STM32ADC/src/utility/util_adc.c b/STM32F1/libraries/STM32ADC/src/utility/util_adc.c index 5d44939..e64b58e 100644 --- a/STM32F1/libraries/STM32ADC/src/utility/util_adc.c +++ b/STM32F1/libraries/STM32ADC/src/utility/util_adc.c @@ -45,7 +45,7 @@ void enable_adc_irq(adc_dev* dev) {//ADC1 for now. Enable the reading of the internal variables (Temperature and Vref). */ void enable_internal_reading(adc_dev *dev) { - dev->regs->CR2 |= ADC_CR2_TSEREFE; + dev->regs->CR2 |= ADC_CR2_TSVREFE; } /* From c8df44228ced3ad7a08f0275ad7acc3458dede70 Mon Sep 17 00:00:00 2001 From: syfre Date: Sun, 7 May 2017 11:41:58 +0200 Subject: [PATCH 032/351] Add, SMT32ADC example, Single channel at fixed sample rate (timer) using circular buffer (DMA) --- ...ingleChannelAtSampleRateCircularBuffer.ino | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 STM32F1/libraries/STM32ADC/examples/SingleChannelAtSampleRateCircularBuffer/SingleChannelAtSampleRateCircularBuffer.ino diff --git a/STM32F1/libraries/STM32ADC/examples/SingleChannelAtSampleRateCircularBuffer/SingleChannelAtSampleRateCircularBuffer.ino b/STM32F1/libraries/STM32ADC/examples/SingleChannelAtSampleRateCircularBuffer/SingleChannelAtSampleRateCircularBuffer.ino new file mode 100644 index 0000000..e63fe32 --- /dev/null +++ b/STM32F1/libraries/STM32ADC/examples/SingleChannelAtSampleRateCircularBuffer/SingleChannelAtSampleRateCircularBuffer.ino @@ -0,0 +1,87 @@ +#include +#include + +#define pinLED PC13 +#define pinOUT PB0 + +#define _SEND_BY_USB +#ifdef SEND_BY_USB +USBSerial usb; +#endif + +// Channels to be acquired. +// A0 (adc1 channel 1) +uint8 pins = 0; + +#define maxSamples 2000 +uint16_t buffer[maxSamples]; +uint16_t *buffers[2]; +uint8_t bufr; +uint8_t bufw; + +#define sampleFreqKhz 200 +#define samplePeriodus 1000 / sampleFreqKhz +#define ticksPerSecond 2 * sampleFreqKhz * 1000 / maxSamples + + +STM32ADC myADC(ADC1); + + +long ticks; +void TimerIRQ(void) { + ticks++; +} +void DmaIRQ(void) { + digitalWrite(pinOUT, ! digitalRead(pinOUT)); + bufw = (bufw+1)%2; + ticks++; +} + +void setup() { + + pinMode(pinLED, OUTPUT); + pinMode(pinOUT, OUTPUT); + pinMode(pins, INPUT_ANALOG); + + Serial.begin(115200); + Serial.println("START"); + + #ifdef SEND_BY_USB + usb.begin(); + while (!usb.isConnected()) ; + #endif + + ticks = 0; + bufr = 0; + bufw = 0; + buffers[0] = &buffer[0]; + buffers[1] = &buffer[maxSamples/2]; + + Timer3.setPeriod(samplePeriodus); + Timer3.setMasterModeTrGo(TIMER_CR2_MMS_UPDATE); + + myADC.calibrate(); + myADC.setSampleRate(ADC_SMPR_1_5); // ? + myADC.setPins(&pins, 1); + myADC.setDMA(buffer, maxSamples, (DMA_MINC_MODE | DMA_CIRC_MODE | DMA_HALF_TRNS | DMA_TRNS_CMPLT), DmaIRQ); + myADC.setTrigger(ADC_EXT_EV_TIM3_TRGO); + myADC.startConversion(); +} + +void loop() { + + if (bufr!=bufw) { + // process data + + #ifdef SEND_BY_USB + if (usb.isConnected()) usb.write((uint8_t *)buffers[bufr],maxSamples); // send it : (maxSamples /2 )*2 (bytes) + #endif + + bufr = (bufr+1)%2; + } + + if (ticks==ticksPerSecond) { + digitalWrite(pinLED, ! digitalRead(pinLED)); + ticks = 0; + } +} From 28fa836f4f65e6a25c2f7e34765116f283c4f6c7 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Sun, 7 May 2017 15:09:15 +0200 Subject: [PATCH 033/351] PIN_MAP moved to flash --- STM32F4/cores/maple/ext_interrupts.cpp | 4 +- STM32F4/cores/maple/libmaple/adc.c | 21 +- STM32F4/cores/maple/libmaple/adc.h | 6 +- STM32F4/cores/maple/libmaple/gpio.h | 16 +- STM32F4/cores/maple/libmaple/gpioF4.c | 57 ++--- STM32F4/cores/maple/libmaple/gpio_def.h | 15 +- STM32F4/cores/maple/libmaple/spi.h | 1 - STM32F4/cores/maple/libmaple/timer.c | 16 +- STM32F4/cores/maple/usb_serial.cpp | 2 +- STM32F4/cores/maple/usb_serial.h | 12 +- STM32F4/cores/maple/wirish.h | 1 - STM32F4/cores/maple/wirish_types.h | 8 +- STM32F4/libraries/SPI/src/SPI.h | 1 - STM32F4/variants/generic_f407v/black_f4.h.old | 130 ----------- .../variants/generic_f407v/generic_f407v.cpp | 156 +------------ STM32F4/variants/generic_f407v/pin_map.c | 214 ++++++++++++++++++ 16 files changed, 286 insertions(+), 374 deletions(-) delete mode 100644 STM32F4/variants/generic_f407v/black_f4.h.old create mode 100644 STM32F4/variants/generic_f407v/pin_map.c diff --git a/STM32F4/cores/maple/ext_interrupts.cpp b/STM32F4/cores/maple/ext_interrupts.cpp index 9e98548..7111d0c 100644 --- a/STM32F4/cores/maple/ext_interrupts.cpp +++ b/STM32F4/cores/maple/ext_interrupts.cpp @@ -51,7 +51,7 @@ void attachInterrupt(uint8 pin, voidFuncPtr handler, ExtIntTriggerMode mode) { exti_trigger_mode outMode = exti_out_mode(mode); - exti_attach_interrupt((afio_exti_num)(PIN_MAP[pin].gpio_bit), + exti_attach_interrupt((afio_exti_num)(pin&0x0F), gpio_exti_port(PIN_MAP[pin].gpio_device), handler, outMode); @@ -66,7 +66,7 @@ void detachInterrupt(uint8 pin) { return; } - exti_detach_interrupt((afio_exti_num)(PIN_MAP[pin].gpio_bit)); + exti_detach_interrupt((afio_exti_num)(pin&0x0F)); } static inline exti_trigger_mode exti_out_mode(ExtIntTriggerMode mode) { diff --git a/STM32F4/cores/maple/libmaple/adc.c b/STM32F4/cores/maple/libmaple/adc.c index b803f29..0f4c02c 100644 --- a/STM32F4/cores/maple/libmaple/adc.c +++ b/STM32F4/cores/maple/libmaple/adc.c @@ -41,27 +41,24 @@ #include "rcc.h" #include "adc.h" -static adc_dev adc1 = { +/** ADC1 device. */ +const adc_dev ADC1 = { .regs = ADC1_BASE, .clk_id = RCC_ADC1 }; -/** ADC1 device. */ -const adc_dev *ADC1 = &adc1; -static adc_dev adc2 = { +/** ADC2 device. */ +const adc_dev ADC2 = { .regs = ADC2_BASE, .clk_id = RCC_ADC2 }; -/** ADC2 device. */ -const adc_dev *ADC2 = &adc2; #ifdef STM32_HIGH_DENSITY -adc_dev adc3 = { +/** ADC3 device. */ +const adc_dev ADC3 = { .regs = ADC3_BASE, .clk_id = RCC_ADC3 }; -/** ADC3 device. */ -const adc_dev *ADC3 = &adc3; #endif /** @@ -101,10 +98,10 @@ void adc_set_extsel(const adc_dev *dev, adc_extsel_event event) { * @param fn Function to call on each ADC device. */ void adc_foreach(void (*fn)(const adc_dev*)) { - fn(ADC1); - fn(ADC2); + fn(&ADC1); + fn(&ADC2); #ifdef STM32_HIGH_DENSITY - fn(ADC3); + fn(&ADC3); #endif } diff --git a/STM32F4/cores/maple/libmaple/adc.h b/STM32F4/cores/maple/libmaple/adc.h index 7a39510..6fa61f5 100644 --- a/STM32F4/cores/maple/libmaple/adc.h +++ b/STM32F4/cores/maple/libmaple/adc.h @@ -82,10 +82,10 @@ typedef struct adc_dev { rcc_clk_id clk_id; /**< RCC clock information */ } adc_dev; -extern const adc_dev *ADC1; -extern const adc_dev *ADC2; +extern const adc_dev ADC1; +extern const adc_dev ADC2; #ifdef STM32_HIGH_DENSITY -extern const adc_dev *ADC3; +extern const adc_dev ADC3; #endif /* diff --git a/STM32F4/cores/maple/libmaple/gpio.h b/STM32F4/cores/maple/libmaple/gpio.h index 4c0ba71..f1a141f 100644 --- a/STM32F4/cores/maple/libmaple/gpio.h +++ b/STM32F4/cores/maple/libmaple/gpio.h @@ -46,7 +46,7 @@ extern "C"{ * @brief Get a GPIO port's corresponding afio_exti_port. * @param dev GPIO device whose afio_exti_port to return. */ -static inline afio_exti_port gpio_exti_port(gpio_dev *dev) { +static inline afio_exti_port gpio_exti_port(const gpio_dev *dev) { return dev->exti_port; } @@ -61,18 +61,18 @@ static inline afio_exti_port gpio_exti_port(gpio_dev *dev) { */ static inline void gpio_write_pin(uint8_t pin, uint8 val) { if (val) { - (PIN_MAP[pin].gpio_device)->regs->BSRRL = BIT(PIN_MAP[pin].gpio_bit); + (PIN_MAP[pin].gpio_device)->regs->BSRRL = BIT(pin&0x0F); } else { - (PIN_MAP[pin].gpio_device)->regs->BSRRH = BIT(PIN_MAP[pin].gpio_bit); + (PIN_MAP[pin].gpio_device)->regs->BSRRH = BIT(pin&0x0F); } } static inline void gpio_set_pin(uint8_t pin) { - (PIN_MAP[pin].gpio_device)->regs->BSRRL = BIT(PIN_MAP[pin].gpio_bit); + (PIN_MAP[pin].gpio_device)->regs->BSRRL = BIT(pin&0x0F); } static inline void gpio_clear_pin(uint8_t pin) { - (PIN_MAP[pin].gpio_device)->regs->BSRRH = BIT(PIN_MAP[pin].gpio_bit); + (PIN_MAP[pin].gpio_device)->regs->BSRRH = BIT(pin&0x0F); } /** @@ -85,7 +85,7 @@ static inline void gpio_clear_pin(uint8_t pin) { * @return True if the pin is set, false otherwise. */ static inline uint32 gpio_read_pin(uint8_t pin) { - return (PIN_MAP[pin].gpio_device)->regs->IDR & BIT(PIN_MAP[pin].gpio_bit); + return (PIN_MAP[pin].gpio_device)->regs->IDR & BIT(pin&0x0F); } /** @@ -94,14 +94,14 @@ static inline uint32 gpio_read_pin(uint8_t pin) { * @param pin Pin on dev to toggle. */ static inline void gpio_toggle_pin(uint8_t pin) { - (PIN_MAP[pin].gpio_device)->regs->ODR = (PIN_MAP[pin].gpio_device)->regs->ODR ^ BIT(PIN_MAP[pin].gpio_bit); + (PIN_MAP[pin].gpio_device)->regs->ODR = (PIN_MAP[pin].gpio_device)->regs->ODR ^ BIT(pin&0x0F); } /* * GPIO Convenience routines */ -extern void gpio_init(gpio_dev *dev); +extern void gpio_init(const gpio_dev *dev); extern void gpio_init_all(void); extern void gpio_set_mode(uint8_t pin, gpio_pin_mode mode); extern void gpio_set_af_mode(uint8_t pin, int mode); diff --git a/STM32F4/cores/maple/libmaple/gpioF4.c b/STM32F4/cores/maple/libmaple/gpioF4.c index fe3cc87..67d3bea 100644 --- a/STM32F4/cores/maple/libmaple/gpioF4.c +++ b/STM32F4/cores/maple/libmaple/gpioF4.c @@ -24,8 +24,6 @@ * SOFTWARE. *****************************************************************************/ -#ifdef STM32F4 - /** * @file gpio.c * @brief GPIO initialization routine @@ -38,64 +36,57 @@ * GPIO devices */ -gpio_dev gpioa = { +/** GPIO port A device. */ +const gpio_dev GPIOA = { .regs = GPIOA_BASE, .clk_id = RCC_GPIOA, .exti_port = AFIO_EXTI_PA, }; -/** GPIO port A device. */ -gpio_dev* const GPIOA = &gpioa; -gpio_dev gpiob = { +/** GPIO port B device. */ +const gpio_dev GPIOB = { .regs = GPIOB_BASE, .clk_id = RCC_GPIOB, .exti_port = AFIO_EXTI_PB, }; -/** GPIO port B device. */ -gpio_dev* const GPIOB = &gpiob; -gpio_dev gpioc = { +/** GPIO port C device. */ +const gpio_dev GPIOC = { .regs = GPIOC_BASE, .clk_id = RCC_GPIOC, .exti_port = AFIO_EXTI_PC, }; -/** GPIO port C device. */ -gpio_dev* const GPIOC = &gpioc; -gpio_dev gpiod = { +/** GPIO port D device. */ +const gpio_dev GPIOD = { .regs = GPIOD_BASE, .clk_id = RCC_GPIOD, .exti_port = AFIO_EXTI_PD, }; -/** GPIO port D device. */ -gpio_dev* const GPIOD = &gpiod; #ifdef STM32_HIGH_DENSITY -gpio_dev gpioe = { +/** GPIO port E device. */ +const gpio_dev GPIOE = { .regs = GPIOE_BASE, .clk_id = RCC_GPIOE, .exti_port = AFIO_EXTI_PE, }; -/** GPIO port E device. */ -gpio_dev* const GPIOE = &gpioe; #if 0 // not available on LQFP 100 package -gpio_dev gpiof = { +/** GPIO port F device. */ +const gpio_dev GPIOF = { .regs = GPIOF_BASE, .clk_id = RCC_GPIOF, .exti_port = AFIO_EXTI_PF, }; -/** GPIO port F device. */ -gpio_dev* const GPIOF = &gpiof; -gpio_dev gpiog = { +/** GPIO port G device. */ +const gpio_dev GPIOG = { .regs = GPIOG_BASE, .clk_id = RCC_GPIOG, .exti_port = AFIO_EXTI_PG, }; -/** GPIO port G device. */ -gpio_dev* const GPIOG = &gpiog; - #endif // not available on LQFP 100 package +#endif #endif /* @@ -109,7 +100,7 @@ gpio_dev* const GPIOG = &gpiog; * * @param dev GPIO device to initialize. */ -void gpio_init(gpio_dev *dev) { +void gpio_init(const gpio_dev *dev) { rcc_clk_enable(dev->clk_id); rcc_reset_dev(dev->clk_id); } @@ -118,13 +109,13 @@ void gpio_init(gpio_dev *dev) { * Initialize and reset all available GPIO devices. */ void gpio_init_all(void) { - gpio_init(GPIOA); - gpio_init(GPIOB); - gpio_init(GPIOC); - gpio_init(GPIOD); + gpio_init(&GPIOA); + gpio_init(&GPIOB); + gpio_init(&GPIOC); + gpio_init(&GPIOD); #ifdef STM32_HIGH_DENSITY - gpio_init(GPIOE); + gpio_init(&GPIOE); #if 0 // not available on LQFP 100 package gpio_init(GPIOF); gpio_init(GPIOG); @@ -154,7 +145,7 @@ void gpio_init_all(void) { */ void gpio_set_mode(uint8_t io_pin, gpio_pin_mode mode) { gpio_reg_map *regs = (PIN_MAP[io_pin].gpio_device)->regs; - uint8_t pin = PIN_MAP[io_pin].gpio_bit; + uint8_t pin = io_pin&0x0f; //regs->AFR[pin/8] = (regs->AFR[pin/8] & ~(15 << (4*(pin&7)))) | (((mode >> 8) & 15) << (4*(pin&7))); //gpio_set_af_mode(dev, pin, mode>>8); @@ -175,7 +166,7 @@ void gpio_set_mode(uint8_t io_pin, gpio_pin_mode mode) { */ void gpio_set_af_mode(uint8_t io_pin, int mode) { gpio_reg_map *regs = (PIN_MAP[io_pin].gpio_device)->regs; - uint8_t pin = PIN_MAP[io_pin].gpio_bit; + uint8_t pin = io_pin&0x0F; regs->AFR[pin>>3] = (regs->AFR[pin>>3] & ~(15 << ((pin&7)<<2))) | (((mode >> 0) & 15) << ((pin&7)<<2)); } @@ -226,5 +217,3 @@ void afio_remap(afio_remap_peripheral remapping) { } } #endif - -#endif diff --git a/STM32F4/cores/maple/libmaple/gpio_def.h b/STM32F4/cores/maple/libmaple/gpio_def.h index e2176ea..cd1fb38 100644 --- a/STM32F4/cores/maple/libmaple/gpio_def.h +++ b/STM32F4/cores/maple/libmaple/gpio_def.h @@ -89,17 +89,12 @@ typedef struct gpio_dev { afio_exti_port exti_port; /**< AFIO external interrupt port value */ } gpio_dev; -extern gpio_dev gpioa; -extern gpio_dev* const GPIOA; -extern gpio_dev gpiob; -extern gpio_dev* const GPIOB; -extern gpio_dev gpioc; -extern gpio_dev* const GPIOC; -extern gpio_dev gpiod; -extern gpio_dev* const GPIOD; +extern const gpio_dev GPIOA; +extern const gpio_dev GPIOB; +extern const gpio_dev GPIOC; +extern const gpio_dev GPIOD; #ifdef STM32_HIGH_DENSITY -extern gpio_dev gpioe; -extern gpio_dev* const GPIOE; +extern const gpio_dev GPIOE; #if 0 // not available on LQFP 100 package extern gpio_dev gpiof; extern gpio_dev* const GPIOF; diff --git a/STM32F4/cores/maple/libmaple/spi.h b/STM32F4/cores/maple/libmaple/spi.h index f96b462..abed68c 100644 --- a/STM32F4/cores/maple/libmaple/spi.h +++ b/STM32F4/cores/maple/libmaple/spi.h @@ -213,7 +213,6 @@ typedef struct spi_dev { void spi_init(spi_dev *dev); -struct gpio_dev; /** * @brief Configure GPIO bit modes for use as a SPI port's pins. * diff --git a/STM32F4/cores/maple/libmaple/timer.c b/STM32F4/cores/maple/libmaple/timer.c index 83e9ace..f8e55a1 100644 --- a/STM32F4/cores/maple/libmaple/timer.c +++ b/STM32F4/cores/maple/libmaple/timer.c @@ -44,7 +44,7 @@ /* Update only. */ #define NR_BAS_HANDLERS 1 -static timer_dev timer1 = { +timer_dev timer1 = { .regs = { .adv = TIMER1_BASE }, .clk_id = RCC_TIMER1, .type = TIMER_ADVANCED, @@ -53,7 +53,7 @@ static timer_dev timer1 = { /** Timer 1 device (advanced) */ timer_dev *TIMER1 = &timer1; -static timer_dev timer2 = { +timer_dev timer2 = { .regs = { .gen = TIMER2_BASE }, .clk_id = RCC_TIMER2, .type = TIMER_GENERAL, @@ -62,7 +62,7 @@ static timer_dev timer2 = { /** Timer 2 device (general-purpose) */ timer_dev *TIMER2 = &timer2; -static timer_dev timer3 = { +timer_dev timer3 = { .regs = { .gen = TIMER3_BASE }, .clk_id = RCC_TIMER3, .type = TIMER_GENERAL, @@ -71,7 +71,7 @@ static timer_dev timer3 = { /** Timer 3 device (general-purpose) */ timer_dev *TIMER3 = &timer3; -static timer_dev timer4 = { +timer_dev timer4 = { .regs = { .gen = TIMER4_BASE }, .clk_id = RCC_TIMER4, .type = TIMER_GENERAL, @@ -81,7 +81,7 @@ static timer_dev timer4 = { timer_dev *TIMER4 = &timer4; #ifdef STM32_HIGH_DENSITY -static timer_dev timer5 = { +timer_dev timer5 = { .regs = { .gen = TIMER5_BASE }, .clk_id = RCC_TIMER5, .type = TIMER_GENERAL, @@ -90,7 +90,7 @@ static timer_dev timer5 = { /** Timer 5 device (general-purpose) */ timer_dev *TIMER5 = &timer5; -static timer_dev timer6 = { +timer_dev timer6 = { .regs = { .bas = TIMER6_BASE }, .clk_id = RCC_TIMER6, .type = TIMER_BASIC, @@ -99,7 +99,7 @@ static timer_dev timer6 = { /** Timer 6 device (basic) */ timer_dev *TIMER6 = &timer6; -static timer_dev timer7 = { +timer_dev timer7 = { .regs = { .bas = TIMER7_BASE }, .clk_id = RCC_TIMER7, .type = TIMER_BASIC, @@ -108,7 +108,7 @@ static timer_dev timer7 = { /** Timer 7 device (basic) */ timer_dev *TIMER7 = &timer7; -static timer_dev timer8 = { +timer_dev timer8 = { .regs = { .adv = TIMER8_BASE }, .clk_id = RCC_TIMER8, .type = TIMER_ADVANCED, diff --git a/STM32F4/cores/maple/usb_serial.cpp b/STM32F4/cores/maple/usb_serial.cpp index cfeb382..fadcb91 100644 --- a/STM32F4/cores/maple/usb_serial.cpp +++ b/STM32F4/cores/maple/usb_serial.cpp @@ -134,7 +134,7 @@ uint8 USBSerial::pending(void) { return usbGetPending(); } -uint8 USBSerial::isConnected(void) { +USBSerial::operator bool() { return usbIsConnected() && usbIsConfigured(); } diff --git a/STM32F4/cores/maple/usb_serial.h b/STM32F4/cores/maple/usb_serial.h index 301dc4b..8eeed96 100644 --- a/STM32F4/cores/maple/usb_serial.h +++ b/STM32F4/cores/maple/usb_serial.h @@ -59,7 +59,8 @@ public: uint8 getRTS(); uint8 getDTR(); - uint8 isConnected(); + operator bool(); + uint8 isConnected() { return (bool) *this; } uint8 pending(); void enableBlockingTx(void); @@ -67,9 +68,14 @@ public: }; extern USBSerial SerialUSB; +#define Serial SerialUSB -#endif +#else // _USB_SERIAL_H_ + +#define Serial Serial1 + +#endif // SERIAL_USB -#endif +#endif // _USB_SERIAL_H_ diff --git a/STM32F4/cores/maple/wirish.h b/STM32F4/cores/maple/wirish.h index d9a17bf..945e8fb 100644 --- a/STM32F4/cores/maple/wirish.h +++ b/STM32F4/cores/maple/wirish.h @@ -58,7 +58,6 @@ #define false 0x0 #endif - #define lowByte(w) ((w) & 0xFF) #define highByte(w) (((w) >> 8) & 0xFF) #define bitRead(value, bit) (((value) >> (bit)) & 0x01) diff --git a/STM32F4/cores/maple/wirish_types.h b/STM32F4/cores/maple/wirish_types.h index aea86fb..6a8c85c 100644 --- a/STM32F4/cores/maple/wirish_types.h +++ b/STM32F4/cores/maple/wirish_types.h @@ -50,13 +50,11 @@ #ifdef BOARD_generic_f407v // restructure members to build consecutive pairs typedef struct stm32_pin_info { - gpio_dev *gpio_device; /**< Maple pin's GPIO device */ - uint8 gpio_bit; /**< Pin's GPIO port bit. */ - timer_dev *timer_device; /**< Pin's timer device, if any. */ + const gpio_dev * gpio_device; /**< Maple pin's GPIO device */ + timer_dev * timer_device; /**< Pin's timer device, if any. */ uint8 timer_channel; /**< Timer channel, or 0 if none. */ - const adc_dev *adc_device; /**< ADC device, if any. */ uint8 adc_channel; /**< Pin ADC channel, or ADCx if none. */ - uint8 filler; + const adc_dev *adc_device; /**< ADC device, if any. */ } stm32_pin_info; #else diff --git a/STM32F4/libraries/SPI/src/SPI.h b/STM32F4/libraries/SPI/src/SPI.h index 1b01d9b..39a5a9e 100644 --- a/STM32F4/libraries/SPI/src/SPI.h +++ b/STM32F4/libraries/SPI/src/SPI.h @@ -397,5 +397,4 @@ private: }; -extern SPIClass SPI;//(1);// dummy params #endif diff --git a/STM32F4/variants/generic_f407v/black_f4.h.old b/STM32F4/variants/generic_f407v/black_f4.h.old deleted file mode 100644 index 20bb174..0000000 --- a/STM32F4/variants/generic_f407v/black_f4.h.old +++ /dev/null @@ -1,130 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2011 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file black_f4.h - * @author Marti Bolivar - * @brief Private include file for Maple Native in boards.h - * - * See maple.h for more information on these definitions. - */ - -#ifndef _BOARD_BLACK_F4_H_ -#define _BOARD_BLACK_F4_H_ - -#define Port2Pin(port, bit) ((port-'A')*16+bit) - -#define CYCLES_PER_MICROSECOND 168 - - -#undef STM32_PCLK1 -#undef STM32_PCLK2 -#define STM32_PCLK1 (CYCLES_PER_MICROSECOND*1000000/4) -#define STM32_PCLK2 (CYCLES_PER_MICROSECOND*1000000/2) - -#define SYSTICK_RELOAD_VAL (CYCLES_PER_MICROSECOND*1000-1) - -#define BOARD_USB_DM_PIN PA11 -#define BOARD_USB_DP_PIN PA12 - -#define BOARD_LED_PIN PA6 //Port2Pin('A', 6) -#define BOARD_LED2_PIN PA7 //Port2Pin('A', 7) -#define BOARD_BUTTON1_PIN PA0 //Port2Pin('A', 0) -#define BOARD_BUTTON2_PIN PE4 //Port2Pin('E', 4) -#define BOARD_BUTTON3_PIN PE3 //Port2Pin('E', 3) - -#define BOARD_NR_USARTS 5 -#define BOARD_USART1_TX_PIN PA9 //Port2Pin('A', 9) -#define BOARD_USART1_RX_PIN PA10 //Port2Pin('A',10) -#define BOARD_USART2_TX_PIN PA2 //Port2Pin('A', 2) -#define BOARD_USART2_RX_PIN PA3 //Port2Pin('A', 3) -#define BOARD_USART3_TX_PIN PB10 //Port2Pin('B',10) -#define BOARD_USART3_RX_PIN PB11 //Port2Pin('B',11) -#define BOARD_UART4_TX_PIN PA0 //Port2Pin('A', 0) -#define BOARD_UART4_RX_PIN PA1 //Port2Pin('A', 1) -#define BOARD_UART5_TX_PIN PC12 //Port2Pin('C',12) -#define BOARD_UART5_RX_PIN PD2 //Port2Pin('D', 2) - -#define BOARD_NR_SPI 3 -#define BOARD_SPI1_NSS_PIN PA4 //Port2Pin('A', 4) -#define BOARD_SPI1_SCK_PIN PA5 //Port2Pin('A', 5) -#define BOARD_SPI1_MISO_PIN PA6 //Port2Pin('A', 6) -#define BOARD_SPI1_MOSI_PIN PA7 //Port2Pin('A', 7) -#define BOARD_SPI1A_NSS_PIN PA15 //Port2Pin('A',15) -#define BOARD_SPI1A_SCK_PIN PB3 //Port2Pin('B', 3) -#define BOARD_SPI1A_MISO_PIN PB4 //Port2Pin('B', 4) -#define BOARD_SPI1A_MOSI_PIN PB5 //Port2Pin('B', 5) - -#define BOARD_SPI2_NSS_PIN PB12 //Port2Pin('B',12) -#define BOARD_SPI2_SCK_PIN PB13 //Port2Pin('B',13) -#define BOARD_SPI2_MISO_PIN PB14 //Port2Pin('B',14) -#define BOARD_SPI2_MOSI_PIN PB15 //Port2Pin('B',15) -#define BOARD_SPI2A_NSS_PIN PB9 //Port2Pin('B', 9) -#define BOARD_SPI2A_SCK_PIN PB10 //Port2Pin('B',10) -#define BOARD_SPI2A_MISO_PIN PC2 //Port2Pin('C', 2) -#define BOARD_SPI2A_MOSI_PIN pc3 //Port2Pin('C', 3) - -#define BOARD_SPI3_NSS_PIN PA15 //Port2Pin('A',15) -#define BOARD_SPI3_SCK_PIN PB3 //Port2Pin('B', 3) -#define BOARD_SPI3_MISO_PIN PB4 //Port2Pin('B', 4) -#define BOARD_SPI3_MOSI_PIN PB5 //Port2Pin('B', 5) -/* overlap with the SDIO interface for SD card -#define BOARD_SPI3A_NSS_PIN Port2Pin('A', 4) -#define BOARD_SPI3A_SCK_PIN Port2Pin('C',10) -#define BOARD_SPI3A_MISO_PIN Port2Pin('C',11) -#define BOARD_SPI3A_MOSI_PIN Port2Pin('C',12) -*/ -#define BOARD_SDIO_D0 PC8 //Port2Pin('C', 8) -#define BOARD_SDIO_D1 PC9 //Port2Pin('C', 9) -#define BOARD_SDIO_D2 PC10 //Port2Pin('C',10) -#define BOARD_SDIO_D3 PC11 //Port2Pin('C',11) -#define BOARD_SDIO_CK PC12 //Port2Pin('C',12) -#define BOARD_SDIO_CMD PD2 //Port2Pin('D', 2) - -#define BOARD_NR_GPIO_PINS 80 -#define BOARD_NR_PWM_PINS 22 -#define BOARD_NR_ADC_PINS 16 -#define BOARD_NR_USED_PINS 22 -#define BOARD_JTMS_SWDIO_PIN PA13 //Port2Pin('A',13) -#define BOARD_JTCK_SWCLK_PIN PA14 //Port2Pin('A',14) -#define BOARD_JTDI_PIN PA15 //Port2Pin('A',15) -#define BOARD_JTDO_PIN PB3 //Port2Pin('B', 3) -#define BOARD_NJTRST_PIN PB4 //Port2Pin('B', 4) - - -enum { -PA0,PA1,PA2,PA3,PA4,PA5,PA6,PA7,PA8,PA9,PA10,PA11,PA12,PA13,PA14,PA15, -PB0,PB1,PB2,PB3,PB4,PB5,PB6,PB7,PB8,PB9,PB10,PB11,PB12,PB13,PB14,PB15, -PC0,PC1,PC2,PC3,PC4,PC5,PC6,PC7,PC8,PC9,PC10,PC11,PC12,PC13,PC14,PC15, -PD0,PD1,PD2,PD3,PD4,PD5,PD6,PD7,PD8,PD9,PD10,PD11,PD12,PD13,PD14,PD15, -PE0,PE1,PE2,PE3,PE4,PE5,PE6,PE7,PE8,PE9,PE10,PE11,PE12,PE13,PE14,PE15, -#if 0 // not available on LQFP100 package -PF0,PF1,PF2,PF3,PF4,PF5,PF6,PF7,PF8,PF9,PF10,PF11,PF12,PF13,PF14,PF15, -PG0,PG1,PG2,PG3,PG4,PG5,PG6,PG7,PG8,PG9,PG10,PG11,PG12,PG13,PG14,PG15 -#endif -}; - -#endif diff --git a/STM32F4/variants/generic_f407v/generic_f407v.cpp b/STM32F4/variants/generic_f407v/generic_f407v.cpp index a4a5ecb..c51ff9b 100644 --- a/STM32F4/variants/generic_f407v/generic_f407v.cpp +++ b/STM32F4/variants/generic_f407v/generic_f407v.cpp @@ -34,12 +34,7 @@ #include "generic_f407v.h" -//#include "fsmc.h" -#include -#include -#include - -#include +#include "wirish_types.h" //static void initSRAMChip(void); /*****************************************************************************/ @@ -70,155 +65,6 @@ void boardInit(void) { return; } -/* -typedef struct stm32_pin_info { - gpio_dev *gpio_device; // Maple pin's GPIO device - uint8 gpio_bit; // Pin's GPIO port bit. - timer_dev *timer_device; // Pin's timer device, if any. - uint8 timer_channel; // Timer channel, or 0 if none. - const adc_dev *adc_device; // ADC device, if any. - uint8 adc_channel; // Pin ADC channel, or ADCx if none. -} stm32_pin_info; -*/ - -extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { // LQFP100 package pin - {GPIOA, 0, TIMER5, 1, ADC1, 0}, // D00/PA0 | 23 | USART2_CTS | UART4_TX | ETH_MII_CRS | TIM2_CH1_ETR | TIM5_CH1 | TIM8_ETR | ADC123_IN0/WKUP - {GPIOA, 1, TIMER5, 2, ADC1, 1}, // D01/PA1 | 24 | USART2_RTS | UART4_RX | ETH_RMII_REF_CLK | ETH_MII_RX_CLK | TIM5_CH2 | TIM2_CH2 | ADC123_IN1 - {GPIOA, 2, TIMER5, 3, ADC1, 2}, // D02/PA2 | 25 | USART2_TX | TIM5_CH3 | TIM9_CH1 | TIM2_CH3 | ETH_MDIO | ADC123_IN2 - {GPIOA, 3, TIMER5, 4, ADC1, 3}, // D03/PA3 | 26 | USART2_RX | TIM5_CH4 | TIM9_CH2 | TIM2_CH4 | OTG_HS_ULPI_D0 | ETH_MII_COL | ADC123_IN3 - {GPIOA, 4, NULL, 0, ADC1, 4}, // D04/PA4 | 29 | SPI1_NSS | SPI3_NSS | USART2_CK | DCMI_HSYNC | OTG_HS_SOF | I2S3_WS | ADC12_IN4 / DAC_OUT1 - {GPIOA, 5, NULL, 0, ADC1, 5}, // D05/PA5 | 30 | SPI1_SCK | OTG_HS_ULPI_CK | TIM2_CH1_ETR | TIM8_CH1N | ADC12_IN5 / DAC_OUT2 - {GPIOA, 6, NULL, 1, ADC1, 6}, // D06/PA6 | 31 | SPI1_MISO | TIM8_BKIN | TIM13_CH1 | DCMI_PIXCLK | TIM3_CH1 | TIM1_BKIN | ADC12_IN6 - {GPIOA, 7, NULL, 0, ADC1, 7}, // D07/PA7 | 32 | SPI1_MOSI | TIM8_CH1N | TIM14_CH1 | TIM3_CH2 | ETH_MII_RX_DV | TIM1_CH1N / ETH_RMII_CRS_DV | ADC12_IN7 - {GPIOA, 8, NULL, 0, NULL, ADCx}, // D08/PA8 | 67 | MCO1 | USART1_CK | TIM1_CH1 | I2C3_SCL | OTG_FS_SOF - {GPIOA, 9, NULL, 0, NULL, ADCx}, // D09/PA9 | 68 | USART1_TX | TIM1_CH2 | I2C3_SMBA | DCMI_D0 - {GPIOA, 10, NULL, 0, NULL, ADCx}, // D10/PA10 | 69 | USART1_RX | TIM1_CH3 | OTG_FS_ID | DCMI_D1 - {GPIOA, 11, NULL, 0, NULL, ADCx}, // D11/PA11 | 70 | USART1_CTS | CAN1_RX | TIM1_CH4 | OTG_FS_DM - {GPIOA, 12, NULL, 0, NULL, ADCx}, // D12/PA12 | 71 | USART1_RTS | CAN1_TX | TIM1_ETR | OTG_FS_DP - {GPIOA, 13, NULL, 0, NULL, ADCx}, // D13/PA13 | 72 | JTMS-SWDIO - {GPIOA, 14, NULL, 0, NULL, ADCx}, // D14/PA14 | 76 | JTCK-SWCLK - {GPIOA, 15, TIMER2, 1, NULL, ADCx}, // D15/PA15 | 77 | JTDI | SPI3_NSS | I2S3_WS | TIM2_CH1_ETR | SPI1_NSS - - {GPIOB, 0, TIMER3, 3, ADC1, 8}, // D16/PB0 | 35 | TIM3_CH3 | TIM8_CH2N | OTG_HS_ULPI_D1 | ETH_MII_RXD2 | TIM1_CH2N | ADC12_IN8 - {GPIOB, 1, TIMER3, 4, ADC1, 9}, // D17/PB1 | 36 | TIM3_CH4 | TIM8_CH3N | OTG_HS_ULPI_D2 | ETH_MII_RXD3 | TIM1_CH3N | ADC12_IN9 - {GPIOB, 2, NULL, 0, NULL, ADCx}, // D18/PB2 | 37 | BOOT1 - {GPIOB, 3, TIMER2, 2, NULL, ADCx}, // D19/PB3 | 89 | JTDO | TRACESWO | SPI3_SCK | I2S3_CK | TIM2_CH2 | SPI1_SCK - {GPIOB, 4, TIMER3, 1, NULL, ADCx}, // D20/PB4 | 90 | NJTRST | SPI3_MISO | TIM3_CH1 | SPI1_MISO | I2S3ext_SD - {GPIOB, 5, TIMER3, 2, NULL, ADCx}, // D21/PB5 | 91 | I2C1_SMBA | CAN2_RX | OTG_HS_ULPI_D7 | ETH_PPS_OUT | TIM3_CH2 | SPI1_MOSI | SPI3_MOSI | DCMI_D10 | I2S3_SD - {GPIOB, 6, NULL, 0, NULL, ADCx}, // D22/PB6 | 92 | I2C1_SCL | TIM4_CH1 | CAN2_TX | DCMI_D5 | USART1_TX - {GPIOB, 7, NULL, 0, NULL, ADCx}, // D23/PB7 | 93 | I2C1_SDA | FSMC_NL | DCMI_VSYNC | USART1_RX | TIM4_CH2 - {GPIOB, 8, NULL, 0, NULL, ADCx}, // D24/PB8 | 95 | TIM4_CH3 | SDIO_D4 | TIM10_CH1 | DCMI_D6 | ETH_MII_TXD3 | I2C1_SCL | CAN1_RX - {GPIOB, 9, NULL, 0, NULL, ADCx}, // D25/PB9 | 96 | SPI2_NSS | I2S2_WS | TIM4_CH4 | TIM11_CH1 | SDIO_D5 | DCMI_D7 | I2C1_SDA | CAN1_TX - {GPIOB, 10, NULL, 0, NULL, ADCx}, // D26/PB10 | 47 | SPI2_SCK | I2S2_CK | I2C2_SCL | USART3_TX | OTG_HS_ULPI_D3 | ETH_MII_RX_ER | TIM2_CH3 - {GPIOB, 11, NULL, 0, NULL, ADCx}, // D27/PB11 | 48 | I2C2_SDA | USART3_RX | OTG_HS_ULPI_D4 | ETH_RMII_TX_EN | ETH_MII_TX_EN | TIM2_CH4 - {GPIOB, 12, NULL, 0, NULL, ADCx}, // D28/PB12 | 51 | SPI2_NSS | I2S2_WS | I2C2_SMBA | USART3_CK | TIM1_BKIN | CAN2_RX | OTG_HS_ULPI_D5 | ETH_RMII_TXD0 | ETH_MII_TXD0 | OTG_HS_ID - {GPIOB, 13, NULL, 0, NULL, ADCx}, // D29/PB13 | 52 | SPI2_SCK | I2S2_CK | USART3_CTS | TIM1_CH1N | CAN2_TX | OTG_HS_ULPI_D6 | ETH_RMII_TXD1 | ETH_MII_TXD1 - {GPIOB, 14, NULL, 0, NULL, ADCx}, // D30/PB14 | 53 | SPI2_MISO | TIM1_CH2N | TIM12_CH1 | OTG_HS_DM | USART3_RTS | TIM8_CH2N | I2S2ext_SD - {GPIOB, 15, NULL, 0, NULL, ADCx}, // D31/PB15 | 54 | SPI2_MOSI | I2S2_SD | TIM1_CH3N | TIM8_CH3N | TIM12_CH2 | OTG_HS_DP - - {GPIOC, 0, NULL, 0, ADC1, 10}, // D32/PC0 | 15 | OTG_HS_ULPI_STP | ADC123_IN10 - {GPIOC, 1, NULL, 0, ADC1, 11}, // D33/PC1 | 16 | ETH_MDC | ADC123_IN11 - {GPIOC, 2, NULL, 0, ADC1, 12}, // D34/PC2 | 17 | SPI2_MISO | OTG_HS_ULPI_DIR | ETH_MII_TXD2 | I2S2ext_SD | ADC123_IN12 - {GPIOC, 3, NULL, 0, ADC1, 13}, // D35/PC3 | 18 | SPI2_MOSI | I2S2_SD | OTG_HS_ULPI_NXT | ETH_MII_TX_CLK | ADC123_IN13 - {GPIOC, 4, NULL, 0, ADC1, 14}, // D36/PC4 | 33 | ETH_RMII_RX_D0 | ETH_MII_RX_D0 | ADC12_IN14 - {GPIOC, 5, NULL, 0, ADC1, 15}, // D37/PC5 | 34 | ETH_RMII_RX_D1 | ETH_MII_RX_D1 | ADC12_IN15 - {GPIOC, 6, TIMER8, 1, NULL, ADCx}, // D38/PC6 | 63 | I2S2_MCK | TIM8_CH1/SDIO_D6 | USART6_TX | DCMI_D0/TIM3_CH1 - {GPIOC, 7, TIMER8, 2, NULL, ADCx}, // D39/PC7 | 64 | I2S3_MCK | TIM8_CH2/SDIO_D7 | USART6_RX | DCMI_D1/TIM3_CH2 - {GPIOC, 8, TIMER8, 3, NULL, ADCx}, // D40/PC8 | 65 | TIM8_CH3 | SDIO_D0 | TIM3_CH3 | USART6_CK | DCMI_D2 - {GPIOC, 9, TIMER8, 4, NULL, ADCx}, // D41/PC9 | 66 | I2S_CKIN | MCO2 | TIM8_CH4 | SDIO_D1 | I2C3_SDA | DCMI_D3 | TIM3_CH4 - {GPIOC, 10, NULL, 0, NULL, ADCx}, // D42/PC10 | 78 | SPI3_SCK | I2S3_CK | UART4_TX | SDIO_D2 | DCMI_D8 | USART3_TX - {GPIOC, 11, NULL, 0, NULL, ADCx}, // D43/PC11 | 79 | UART4_RX | SPI3_MISO | SDIO_D3 | DCMI_D4 | USART3_RX | I2S3ext_SD - {GPIOC, 12, NULL, 0, NULL, ADCx}, // D44/PC12 | 80 | UART5_TX | SDIO_CK | DCMI_D9 | SPI3_MOSI | I2S3_SD | USART3_CK - {GPIOC, 13, NULL, 0, NULL, ADCx}, // D45/PC13 | 7 | RTC_OUT, RTC_TAMP1, RTC_TS - {GPIOC, 14, NULL, 0, NULL, ADCx}, // D46/PC14 | 8 | OSC32_IN - {GPIOC, 15, NULL, 0, NULL, ADCx}, // D47/PC15 | 9 | OSC32_OUT - - {GPIOD, 0, NULL, 0, NULL, ADCx}, // D48/PD0 | 81 | FSMC_D2 | CAN1_RX - {GPIOD, 1, NULL, 0, NULL, ADCx}, // D49/PD1 | 82 | FSMC_D3 | CAN1_TX - {GPIOD, 2, NULL, 0, NULL, ADCx}, // D50/PD2 | 83 | TIM3_ETR | UART5_RX | SDIO_CMD | DCMI_D11 - {GPIOD, 3, NULL, 0, NULL, ADCx}, // D51/PD3 | 84 | FSMC_CLK | USART2_CTS - {GPIOD, 4, NULL, 0, NULL, ADCx}, // D52/PD4 | 85 | FSMC_NOE | USART2_RTS - {GPIOD, 5, NULL, 0, NULL, ADCx}, // D53/PD5 | 86 | FSMC_NWE | USART2_TX - {GPIOD, 6, NULL, 0, NULL, ADCx}, // D54/PD6 | 87 | FSMC_NWAIT | USART2_RX - {GPIOD, 7, NULL, 0, NULL, ADCx}, // D55/PD7 | 88 | USART2_CK | FSMC_NE1 | FSMC_NCE2 - {GPIOD, 8, NULL, 0, NULL, ADCx}, // D56/PD8 | 55 | FSMC_D13 | USART3_TX - {GPIOD, 9, NULL, 0, NULL, ADCx}, // D57/PD9 | 56 | FSMC_D14 | USART3_RX - {GPIOD, 10, NULL, 0, NULL, ADCx}, // D58/PD10 | 57 | FSMC_D15 | USART3_CK - {GPIOD, 11, NULL, 0, NULL, ADCx}, // D59/PD11 | 58 | FSMC_CLE | FSMC_A16 | USART3_CTS - {GPIOD, 12, TIMER4, 1, NULL, ADCx}, // D60/PD12 | 59 | FSMC_ALE | FSMC_A17 | TIM4_CH1 | USART3_RTS // remap in - {GPIOD, 13, TIMER4, 2, NULL, ADCx}, // D61/PD13 | 60 | FSMC_A18 | TIM4_CH2 // remap in - {GPIOD, 14, TIMER4, 3, NULL, ADCx}, // D62/PD14 | 61 | FSMC_D0 | TIM4_CH3 // remap in - {GPIOD, 15, TIMER4, 4, NULL, ADCx}, // D63/PD15 | 62 | FSMC_D1 | TIM4_CH4 // remap in - - {GPIOE, 0, NULL, 0, NULL, ADCx}, // D64/PE0 | 97 | TIM4_ETR | FSMC_NBL0 | DCMI_D2 - {GPIOE, 1, NULL, 0, NULL, ADCx}, // D65/PE1 | 98 | FSMC_NBL1 | DCMI_D3 - {GPIOE, 2, NULL, 0, NULL, ADCx}, // D66/PE2 | 1 | TRACECLK | FSMC_A23 | ETH_MII_TXD3 - {GPIOE, 3, NULL, 0, NULL, ADCx}, // D67/PE3 | 2 | TRACED0 | FSMC_A19 - {GPIOE, 4, NULL, 0, NULL, ADCx}, // D68/PE4 | 3 | TRACED1 | FSMC_A20 | DCMI_D4 - {GPIOE, 5, NULL, 0, NULL, ADCx}, // D69/PE5 | 4 | TRACED2 | FSMC_A21 | TIM9_CH1 / DCMI_D6 - {GPIOE, 6, NULL, 0, NULL, ADCx}, // D70/PE6 | 5 | TRACED3 | FSMC_A22 | TIM9_CH2 / DCMI_D7 - {GPIOE, 7, NULL, 0, NULL, ADCx}, // D71/PE7 | 38 | FSMC_D4 | TIM1_ETR - {GPIOE, 8, NULL, 0, NULL, ADCx}, // D72/PE8 | 39 | FSMC_D5 | TIM1_CH1N - {GPIOE, 9, TIMER1, 1, NULL, ADCx}, // D73/PE9 | 40 | FSMC_D6 | TIM1_CH1 // remap in - {GPIOE, 10, NULL, 0, NULL, ADCx}, // D74/PE10 | 41 | FSMC_D7 | TIM1_CH2N - {GPIOE, 11, TIMER1, 2, NULL, ADCx}, // D75/PE11 | 42 | FSMC_D8 | TIM1_CH2 // remap in - {GPIOE, 12, NULL, 0, NULL, ADCx}, // D76/PE12 | 43 | FSMC_D9 | TIM1_CH3N - {GPIOE, 13, TIMER1, 3, NULL, ADCx}, // D77/PE13 | 44 | FSMC_D10 | TIM1_CH3 // remap in - {GPIOE, 14, TIMER1, 4, NULL, ADCx}, // D78/PE14 | 45 | FSMC_D11 | TIM1_CH4 // remap in - {GPIOE, 15, NULL, 0, NULL, ADCx}, // D79/PE15 | 46 | FSMC_D12 | TIM1_BKIN -#if 0 - {GPIOF, 0, NULL, 0, NULL, ADCx}, // D80/PF0 - {GPIOF, 1, NULL, 0, NULL, ADCx}, // D81/PF1 - {GPIOF, 2, NULL, 0, NULL, ADCx}, // D82/PF2 - {GPIOF, 3, NULL, 0, NULL, ADCx}, // D83/PF3 - {GPIOF, 4, NULL, 0, NULL, ADCx}, // D84/PF4 - {GPIOF, 5, NULL, 0, NULL, ADCx}, // D85/PF5 - {GPIOF, 6, NULL, 0, NULL, ADCx}, // D86/PF6 - {GPIOF, 7, NULL, 0, NULL, ADCx}, // D87/PF7 - {GPIOF, 8, NULL, 0, NULL, ADCx}, // D88/PF8 - {GPIOF, 9, NULL, 0, NULL, ADCx}, // D89/PF9 - {GPIOF, 10, NULL, 0, NULL, ADCx}, // D90/PF10 - {GPIOF, 11, NULL, 0, NULL, ADCx}, // D91/PF11 - {GPIOF, 12, NULL, 0, NULL, ADCx}, // D92/PF12 - {GPIOF, 13, NULL, 0, NULL, ADCx}, // D93/PF13 - {GPIOF, 14, NULL, 0, NULL, ADCx}, // D94/PF14 - {GPIOF, 15, NULL, 0, NULL, ADCx}, // D95/PF15 - - {GPIOG, 0, NULL, 0, NULL, ADCx}, // D96/PG0 - {GPIOG, 1, NULL, 0, NULL, ADCx}, // D97/PG1 - {GPIOG, 2, NULL, 0, NULL, ADCx}, // D98/PG2 - {GPIOG, 3, NULL, 0, NULL, ADCx}, // D99/PG3 - {GPIOG, 4, NULL, 0, NULL, ADCx}, // D100/PG4 - {GPIOG, 5, NULL, 0, NULL, ADCx}, // D101/PG5 - {GPIOG, 6, NULL, 0, NULL, ADCx}, // D102/PG6 - {GPIOG, 7, NULL, 0, NULL, ADCx}, // D103/PG7 - {GPIOG, 8, NULL, 0, NULL, ADCx}, // D104/PG8 - {GPIOG, 9, NULL, 0, NULL, ADCx}, // D105/PG9 - {GPIOG, 10, NULL, 0, NULL, ADCx}, // D106/PG10 - {GPIOG, 11, NULL, 0, NULL, ADCx}, // D107/PG11 - {GPIOG, 12, NULL, 0, NULL, ADCx}, // D108/PG12 - {GPIOG, 13, NULL, 0, NULL, ADCx}, // D109/PG13 - {GPIOG, 14, NULL, 0, NULL, ADCx}, // D110/PG14 - {GPIOG, 15, NULL, 0, NULL, ADCx} // D111/PG15 -#endif -}; -/* to be defined -extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { - 0, 1, 2, 3, 15, 16, 17, 19, 20, 21, 38, 39, 49, 41, 60, 61, 62, 63, 73, 75, 77, 78 -}; -*/ -extern const uint8 boardADCPins[BOARD_NR_ADC_PINS] __FLASH__ = { - PA0, PA1, PA2, PA3, PA4, PA5, PA6, PA7, PB0, PB1, PC0, PC1, PC2, PC3, PC4, PC5 -}; - -extern const uint8 boardUsedPins[BOARD_NR_USED_PINS] __FLASH__ = { - BOARD_LED_PIN, BOARD_LED2_PIN, BOARD_BUTTON1_PIN, BOARD_BUTTON2_PIN, BOARD_BUTTON2_PIN, - BOARD_JTMS_SWDIO_PIN, BOARD_JTCK_SWCLK_PIN, - FLASH_CS_PIN, FLASH_CLK_PIN, FLASH_DO_PIN, FLASH_DI_PIN, - NRF24_CE_PIN, NRF24_CS_PIN, NRF24_IRQ_PIN, - BOARD_SDIO_D0, BOARD_SDIO_D1, BOARD_SDIO_D2, BOARD_SDIO_D3, BOARD_SDIO_CK, BOARD_SDIO_CMD, - USB_DM_PIN, USB_DP_PIN -}; /* static void initSRAMChip(void) { fsmc_nor_psram_reg_map *regs = FSMC_NOR_PSRAM1_BASE; diff --git a/STM32F4/variants/generic_f407v/pin_map.c b/STM32F4/variants/generic_f407v/pin_map.c new file mode 100644 index 0000000..58eeca4 --- /dev/null +++ b/STM32F4/variants/generic_f407v/pin_map.c @@ -0,0 +1,214 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file generic_f407v.cpp + * @author ala42 + * @brief generic_f407v board file. + */ + +#ifdef BOARD_generic_f407v + +#ifdef __cplusplus +extern "C"{ +#endif + +//#include "generic_f407v.h" + +//#include "fsmc.h" +#include +#include +#include + +#include + +extern timer_dev timer1; +extern timer_dev timer2; +extern timer_dev timer3; +extern timer_dev timer4; +extern timer_dev timer5; +extern timer_dev timer6; +extern timer_dev timer7; +extern timer_dev timer8; +/* +typedef struct stm32_pin_info { + gpio_dev *gpio_device; // Maple pin's GPIO device + uint8 gpio_bit; // Pin's GPIO port bit. + timer_dev *timer_device; // Pin's timer device, if any. + uint8 timer_channel; // Timer channel, or 0 if none. + const adc_dev *adc_device; // ADC device, if any. + uint8 adc_channel; // Pin ADC channel, or ADCx if none. +} stm32_pin_info; +*/ +const stm32_pin_info PIN_MAP1[] = { // LQFP100 package pin + {&GPIOA, &timer5, 1, 0, &ADC1}, // D00/PA0 | 23 | USART2_CTS | UART4_TX | ETH_MII_CRS | TIM2_CH1_ETR | TIM5_CH1 | TIM8_ETR | ADC123_IN0/WKUP +}; + +const stm32_pin_info PIN_MAP[] = { // LQFP100 package pin + {&GPIOA, &timer5, 1, 0, &ADC1}, // D00/PA0 | 23 | USART2_CTS | UART4_TX | ETH_MII_CRS | TIM2_CH1_ETR | TIM5_CH1 | TIM8_ETR | ADC123_IN0/WKUP + {&GPIOA, &timer5, 2, 1, &ADC1}, // D01/PA1 | 24 | USART2_RTS | UART4_RX | ETH_RMII_REF_CLK | ETH_MII_RX_CLK | TIM5_CH2 | TIM2_CH2 | ADC123_IN1 + {&GPIOA, &timer5, 3, 2, &ADC1}, // D02/PA2 | 25 | USART2_TX | TIM5_CH3 | TIM9_CH1 | TIM2_CH3 | ETH_MDIO | ADC123_IN2 + {&GPIOA, &timer5, 4, 3, &ADC1}, // D03/PA3 | 26 | USART2_RX | TIM5_CH4 | TIM9_CH2 | TIM2_CH4 | OTG_HS_ULPI_D0 | ETH_MII_COL | ADC123_IN3 + {&GPIOA, NULL, 0, 4, &ADC1}, // D04/PA4 | 29 | SPI1_NSS | SPI3_NSS | USART2_CK | DCMI_HSYNC | OTG_HS_SOF | I2S3_WS | ADC12_IN4 / DAC_OUT1 + {&GPIOA, NULL, 0, 5, &ADC1}, // D05/PA5 | 30 | SPI1_SCK | OTG_HS_ULPI_CK | TIM2_CH1_ETR | TIM8_CH1N | ADC12_IN5 / DAC_OUT2 + {&GPIOA, NULL, 1, 6, &ADC1}, // D06/PA6 | 31 | SPI1_MISO | TIM8_BKIN | TIM13_CH1 | DCMI_PIXCLK | TIM3_CH1 | TIM1_BKIN | ADC12_IN6 + {&GPIOA, NULL, 0, 7, &ADC1}, // D07/PA7 | 32 | SPI1_MOSI | TIM8_CH1N | TIM14_CH1 | TIM3_CH2 | ETH_MII_RX_DV | TIM1_CH1N / ETH_RMII_CRS_DV | ADC12_IN7 + {&GPIOA, NULL, 0, ADCx, NULL}, // D08/PA8 | 67 | MCO1 | USART1_CK | TIM1_CH1 | I2C3_SCL | OTG_FS_SOF + {&GPIOA, NULL, 0, ADCx, NULL}, // D09/PA9 | 68 | USART1_TX | TIM1_CH2 | I2C3_SMBA | DCMI_D0 + {&GPIOA, NULL, 0, ADCx, NULL}, // D10/PA10 | 69 | USART1_RX | TIM1_CH3 | OTG_FS_ID | DCMI_D1 + {&GPIOA, NULL, 0, ADCx, NULL}, // D11/PA11 | 70 | USART1_CTS | CAN1_RX | TIM1_CH4 | OTG_FS_DM + {&GPIOA, NULL, 0, ADCx, NULL}, // D12/PA12 | 71 | USART1_RTS | CAN1_TX | TIM1_ETR | OTG_FS_DP + {&GPIOA, NULL, 0, ADCx, NULL}, // D13/PA13 | 72 | JTMS-SWDIO + {&GPIOA, NULL, 0, ADCx, NULL}, // D14/PA14 | 76 | JTCK-SWCLK + {&GPIOA, &timer2, 1, ADCx, NULL}, // D15/PA15 | 77 | JTDI | SPI3_NSS | I2S3_WS | TIM2_CH1_ETR | SPI1_NSS + + {&GPIOB, &timer3, 3, 8, &ADC1}, // D16/PB0 | 35 | TIM3_CH3 | TIM8_CH2N | OTG_HS_ULPI_D1 | ETH_MII_RXD2 | TIM1_CH2N | ADC12_IN8 + {&GPIOB, &timer3, 4, 9, &ADC1}, // D17/PB1 | 36 | TIM3_CH4 | TIM8_CH3N | OTG_HS_ULPI_D2 | ETH_MII_RXD3 | TIM1_CH3N | ADC12_IN9 + {&GPIOB, NULL, 0, ADCx, NULL}, // D18/PB2 | 37 | BOOT1 + {&GPIOB, &timer2, 2, ADCx, NULL}, // D19/PB3 | 89 | JTDO | TRACESWO | SPI3_SCK | I2S3_CK | TIM2_CH2 | SPI1_SCK + {&GPIOB, &timer3, 1, ADCx, NULL}, // D20/PB4 | 90 | NJTRST | SPI3_MISO | TIM3_CH1 | SPI1_MISO | I2S3ext_SD + {&GPIOB, &timer3, 2, ADCx, NULL}, // D21/PB5 | 91 | I2C1_SMBA | CAN2_RX | OTG_HS_ULPI_D7 | ETH_PPS_OUT | TIM3_CH2 | SPI1_MOSI | SPI3_MOSI | DCMI_D10 | I2S3_SD + {&GPIOB, NULL, 0, ADCx, NULL}, // D22/PB6 | 92 | I2C1_SCL | TIM4_CH1 | CAN2_TX | DCMI_D5 | USART1_TX + {&GPIOB, NULL, 0, ADCx, NULL}, // D23/PB7 | 93 | I2C1_SDA | FSMC_NL | DCMI_VSYNC | USART1_RX | TIM4_CH2 + {&GPIOB, NULL, 0, ADCx, NULL}, // D24/PB8 | 95 | TIM4_CH3 | SDIO_D4 | TIM10_CH1 | DCMI_D6 | ETH_MII_TXD3 | I2C1_SCL | CAN1_RX + {&GPIOB, NULL, 0, ADCx, NULL}, // D25/PB9 | 96 | SPI2_NSS | I2S2_WS | TIM4_CH4 | TIM11_CH1 | SDIO_D5 | DCMI_D7 | I2C1_SDA | CAN1_TX + {&GPIOB, NULL, 0, ADCx, NULL}, // D26/PB10 | 47 | SPI2_SCK | I2S2_CK | I2C2_SCL | USART3_TX | OTG_HS_ULPI_D3 | ETH_MII_RX_ER | TIM2_CH3 + {&GPIOB, NULL, 0, ADCx, NULL}, // D27/PB11 | 48 | I2C2_SDA | USART3_RX | OTG_HS_ULPI_D4 | ETH_RMII_TX_EN | ETH_MII_TX_EN | TIM2_CH4 + {&GPIOB, NULL, 0, ADCx, NULL}, // D28/PB12 | 51 | SPI2_NSS | I2S2_WS | I2C2_SMBA | USART3_CK | TIM1_BKIN | CAN2_RX | OTG_HS_ULPI_D5 | ETH_RMII_TXD0 | ETH_MII_TXD0 | OTG_HS_ID + {&GPIOB, NULL, 0, ADCx, NULL}, // D29/PB13 | 52 | SPI2_SCK | I2S2_CK | USART3_CTS | TIM1_CH1N | CAN2_TX | OTG_HS_ULPI_D6 | ETH_RMII_TXD1 | ETH_MII_TXD1 + {&GPIOB, NULL, 0, ADCx, NULL}, // D30/PB14 | 53 | SPI2_MISO | TIM1_CH2N | TIM12_CH1 | OTG_HS_DM | USART3_RTS | TIM8_CH2N | I2S2ext_SD + {&GPIOB, NULL, 0, ADCx, NULL}, // D31/PB15 | 54 | SPI2_MOSI | I2S2_SD | TIM1_CH3N | TIM8_CH3N | TIM12_CH2 | OTG_HS_DP + + {&GPIOC, NULL, 0, 10, &ADC1}, // D32/PC0 | 15 | OTG_HS_ULPI_STP | ADC123_IN10 + {&GPIOC, NULL, 0, 11, &ADC1}, // D33/PC1 | 16 | ETH_MDC | ADC123_IN11 + {&GPIOC, NULL, 0, 12, &ADC1}, // D34/PC2 | 17 | SPI2_MISO | OTG_HS_ULPI_DIR | ETH_MII_TXD2 | I2S2ext_SD | ADC123_IN12 + {&GPIOC, NULL, 0, 13, &ADC1}, // D35/PC3 | 18 | SPI2_MOSI | I2S2_SD | OTG_HS_ULPI_NXT | ETH_MII_TX_CLK | ADC123_IN13 + {&GPIOC, NULL, 0, 14, &ADC1}, // D36/PC4 | 33 | ETH_RMII_RX_D0 | ETH_MII_RX_D0 | ADC12_IN14 + {&GPIOC, NULL, 0, 15, &ADC1}, // D37/PC5 | 34 | ETH_RMII_RX_D1 | ETH_MII_RX_D1 | ADC12_IN15 + {&GPIOC, &timer8, 1, ADCx, NULL}, // D38/PC6 | 63 | I2S2_MCK | TIM8_CH1/SDIO_D6 | USART6_TX | DCMI_D0/TIM3_CH1 + {&GPIOC, &timer8, 2, ADCx, NULL}, // D39/PC7 | 64 | I2S3_MCK | TIM8_CH2/SDIO_D7 | USART6_RX | DCMI_D1/TIM3_CH2 + {&GPIOC, &timer8, 3, ADCx, NULL}, // D40/PC8 | 65 | TIM8_CH3 | SDIO_D0 | TIM3_CH3 | USART6_CK | DCMI_D2 + {&GPIOC, &timer8, 4, ADCx, NULL}, // D41/PC9 | 66 | I2S_CKIN | MCO2 | TIM8_CH4 | SDIO_D1 | I2C3_SDA | DCMI_D3 | TIM3_CH4 + {&GPIOC, NULL, 0, ADCx, NULL}, // D42/PC10 | 78 | SPI3_SCK | I2S3_CK | UART4_TX | SDIO_D2 | DCMI_D8 | USART3_TX + {&GPIOC, NULL, 0, ADCx, NULL}, // D43/PC11 | 79 | UART4_RX | SPI3_MISO | SDIO_D3 | DCMI_D4 | USART3_RX | I2S3ext_SD + {&GPIOC, NULL, 0, ADCx, NULL}, // D44/PC12 | 80 | UART5_TX | SDIO_CK | DCMI_D9 | SPI3_MOSI | I2S3_SD | USART3_CK + {&GPIOC, NULL, 0, ADCx, NULL}, // D45/PC13 | 7 | RTC_OUT, RTC_TAMP1, RTC_TS + {&GPIOC, NULL, 0, ADCx, NULL}, // D46/PC14 | 8 | OSC32_IN + {&GPIOC, NULL, 0, ADCx, NULL}, // D47/PC15 | 9 | OSC32_OUT + + {&GPIOD, NULL, 0, ADCx, NULL}, // D48/PD0 | 81 | FSMC_D2 | CAN1_RX + {&GPIOD, NULL, 0, ADCx, NULL}, // D49/PD1 | 82 | FSMC_D3 | CAN1_TX + {&GPIOD, NULL, 0, ADCx, NULL}, // D50/PD2 | 83 | TIM3_ETR | UART5_RX | SDIO_CMD | DCMI_D11 + {&GPIOD, NULL, 0, ADCx, NULL}, // D51/PD3 | 84 | FSMC_CLK | USART2_CTS + {&GPIOD, NULL, 0, ADCx, NULL}, // D52/PD4 | 85 | FSMC_NOE | USART2_RTS + {&GPIOD, NULL, 0, ADCx, NULL}, // D53/PD5 | 86 | FSMC_NWE | USART2_TX + {&GPIOD, NULL, 0, ADCx, NULL}, // D54/PD6 | 87 | FSMC_NWAIT | USART2_RX + {&GPIOD, NULL, 0, ADCx, NULL}, // D55/PD7 | 88 | USART2_CK | FSMC_NE1 | FSMC_NCE2 + {&GPIOD, NULL, 0, ADCx, NULL}, // D56/PD8 | 55 | FSMC_D13 | USART3_TX + {&GPIOD, NULL, 0, ADCx, NULL}, // D57/PD9 | 56 | FSMC_D14 | USART3_RX + {&GPIOD, NULL, 0, ADCx, NULL}, // D58/PD10 | 57 | FSMC_D15 | USART3_CK + {&GPIOD, NULL, 0, ADCx, NULL}, // D59/PD11 | 58 | FSMC_CLE | FSMC_A16 | USART3_CTS + {&GPIOD, &timer4, 1, ADCx, NULL}, // D60/PD12 | 59 | FSMC_ALE | FSMC_A17 | TIM4_CH1 | USART3_RTS // remap in + {&GPIOD, &timer4, 2, ADCx, NULL}, // D61/PD13 | 60 | FSMC_A18 | TIM4_CH2 // remap in + {&GPIOD, &timer4, 3, ADCx, NULL}, // D62/PD14 | 61 | FSMC_D0 | TIM4_CH3 // remap in + {&GPIOD, &timer4, 4, ADCx, NULL}, // D63/PD15 | 62 | FSMC_D1 | TIM4_CH4 // remap in + + {&GPIOE, NULL, 0, ADCx, NULL}, // D64/PE0 | 97 | TIM4_ETR | FSMC_NBL0 | DCMI_D2 + {&GPIOE, NULL, 0, ADCx, NULL}, // D65/PE1 | 98 | FSMC_NBL1 | DCMI_D3 + {&GPIOE, NULL, 0, ADCx, NULL}, // D66/PE2 | 1 | TRACECLK | FSMC_A23 | ETH_MII_TXD3 + {&GPIOE, NULL, 0, ADCx, NULL}, // D67/PE3 | 2 | TRACED0 | FSMC_A19 + {&GPIOE, NULL, 0, ADCx, NULL}, // D68/PE4 | 3 | TRACED1 | FSMC_A20 | DCMI_D4 + {&GPIOE, NULL, 0, ADCx, NULL}, // D69/PE5 | 4 | TRACED2 | FSMC_A21 | TIM9_CH1 / DCMI_D6 + {&GPIOE, NULL, 0, ADCx, NULL}, // D70/PE6 | 5 | TRACED3 | FSMC_A22 | TIM9_CH2 / DCMI_D7 + {&GPIOE, NULL, 0, ADCx, NULL}, // D71/PE7 | 38 | FSMC_D4 | TIM1_ETR + {&GPIOE, NULL, 0, ADCx, NULL}, // D72/PE8 | 39 | FSMC_D5 | TIM1_CH1N + {&GPIOE, &timer1, 1, ADCx, NULL}, // D73/PE9 | 40 | FSMC_D6 | TIM1_CH1 // remap in + {&GPIOE, NULL, 0, ADCx, NULL}, // D74/PE10 | 41 | FSMC_D7 | TIM1_CH2N + {&GPIOE, &timer1, 2, ADCx, NULL}, // D75/PE11 | 42 | FSMC_D8 | TIM1_CH2 // remap in + {&GPIOE, NULL, 0, ADCx, NULL}, // D76/PE12 | 43 | FSMC_D9 | TIM1_CH3N + {&GPIOE, &timer1, 3, ADCx, NULL}, // D77/PE13 | 44 | FSMC_D10 | TIM1_CH3 // remap in + {&GPIOE, &timer1, 4, ADCx, NULL}, // D78/PE14 | 45 | FSMC_D11 | TIM1_CH4 // remap in + {&GPIOE, NULL, 0, ADCx, NULL}, // D79/PE15 | 46 | FSMC_D12 | TIM1_BKIN +#if 0 + {GPIOF, 0, NULL, 0, NULL, ADCx}, // D80/PF0 + {GPIOF, 1, NULL, 0, NULL, ADCx}, // D81/PF1 + {GPIOF, 2, NULL, 0, NULL, ADCx}, // D82/PF2 + {GPIOF, 3, NULL, 0, NULL, ADCx}, // D83/PF3 + {GPIOF, 4, NULL, 0, NULL, ADCx}, // D84/PF4 + {GPIOF, 5, NULL, 0, NULL, ADCx}, // D85/PF5 + {GPIOF, 6, NULL, 0, NULL, ADCx}, // D86/PF6 + {GPIOF, 7, NULL, 0, NULL, ADCx}, // D87/PF7 + {GPIOF, 8, NULL, 0, NULL, ADCx}, // D88/PF8 + {GPIOF, 9, NULL, 0, NULL, ADCx}, // D89/PF9 + {GPIOF, 10, NULL, 0, NULL, ADCx}, // D90/PF10 + {GPIOF, 11, NULL, 0, NULL, ADCx}, // D91/PF11 + {GPIOF, 12, NULL, 0, NULL, ADCx}, // D92/PF12 + {GPIOF, 13, NULL, 0, NULL, ADCx}, // D93/PF13 + {GPIOF, 14, NULL, 0, NULL, ADCx}, // D94/PF14 + {GPIOF, 15, NULL, 0, NULL, ADCx}, // D95/PF15 + + {GPIOG, 0, NULL, 0, NULL, ADCx}, // D96/PG0 + {GPIOG, 1, NULL, 0, NULL, ADCx}, // D97/PG1 + {GPIOG, 2, NULL, 0, NULL, ADCx}, // D98/PG2 + {GPIOG, 3, NULL, 0, NULL, ADCx}, // D99/PG3 + {GPIOG, 4, NULL, 0, NULL, ADCx}, // D100/PG4 + {GPIOG, 5, NULL, 0, NULL, ADCx}, // D101/PG5 + {GPIOG, 6, NULL, 0, NULL, ADCx}, // D102/PG6 + {GPIOG, 7, NULL, 0, NULL, ADCx}, // D103/PG7 + {GPIOG, 8, NULL, 0, NULL, ADCx}, // D104/PG8 + {GPIOG, 9, NULL, 0, NULL, ADCx}, // D105/PG9 + {GPIOG, 10, NULL, 0, NULL, ADCx}, // D106/PG10 + {GPIOG, 11, NULL, 0, NULL, ADCx}, // D107/PG11 + {GPIOG, 12, NULL, 0, NULL, ADCx}, // D108/PG12 + {GPIOG, 13, NULL, 0, NULL, ADCx}, // D109/PG13 + {GPIOG, 14, NULL, 0, NULL, ADCx}, // D110/PG14 + {GPIOG, 15, NULL, 0, NULL, ADCx} // D111/PG15 +#endif +}; +/* to be defined +extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { + 0, 1, 2, 3, 15, 16, 17, 19, 20, 21, 38, 39, 49, 41, 60, 61, 62, 63, 73, 75, 77, 78 +}; +*/ +const uint8 boardADCPins[BOARD_NR_ADC_PINS] = { + PA0, PA1, PA2, PA3, PA4, PA5, PA6, PA7, PB0, PB1, PC0, PC1, PC2, PC3, PC4, PC5 +}; + +const uint8 boardUsedPins[BOARD_NR_USED_PINS] = { + BOARD_LED_PIN, BOARD_LED2_PIN, BOARD_BUTTON1_PIN, BOARD_BUTTON2_PIN, BOARD_BUTTON2_PIN, + BOARD_JTMS_SWDIO_PIN, BOARD_JTCK_SWCLK_PIN, + FLASH_CS_PIN, FLASH_CLK_PIN, FLASH_DO_PIN, FLASH_DI_PIN, + NRF24_CE_PIN, NRF24_CS_PIN, NRF24_IRQ_PIN, + BOARD_SDIO_D0, BOARD_SDIO_D1, BOARD_SDIO_D2, BOARD_SDIO_D3, BOARD_SDIO_CK, BOARD_SDIO_CMD, + USB_DM_PIN, USB_DP_PIN +}; + +#ifdef __cplusplus +} +#endif + + +#endif // BOARD_generic_f407v From 467c450449ded9a8f92710be817418611a5bb571 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Tue, 9 May 2017 14:35:13 +0200 Subject: [PATCH 034/351] revert removing SPI declaration (needed by SdFat lib) + remove unused lines --- STM32F4/libraries/SPI/src/SPI.h | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/STM32F4/libraries/SPI/src/SPI.h b/STM32F4/libraries/SPI/src/SPI.h index 39a5a9e..78e7066 100644 --- a/STM32F4/libraries/SPI/src/SPI.h +++ b/STM32F4/libraries/SPI/src/SPI.h @@ -37,6 +37,8 @@ #ifndef _LIB_SPI_H_ #define _LIB_SPI_H_ +//#define SPI_DMA // enable this to use DMA for SPI transfers + #include #include #include @@ -374,27 +376,12 @@ public: uint8 recv(void); private: -/* - static inline void DMA1_CH3_Event() { - dma1_ch3_Active = 0; -// dma_disable(DMA1, DMA_CH3); -// dma_disable(DMA1, DMA_CH2); - - // To Do. Need to wait for - } -*/ SPISettings _settings[BOARD_NR_SPI]; SPISettings *_currentSetting; void updateSettings(void); - /* - spi_dev *spi_d; - uint8_t _SSPin; - uint32_t clockDivider; - uint8_t dataMode; - BitOrder bitOrder; - */ }; +extern SPIClass SPI; // needed bx SdFat(EX) lib #endif From e37d7eac483b5719f17264086c3c06ebea3f3ecf Mon Sep 17 00:00:00 2001 From: stevstrong Date: Tue, 9 May 2017 14:37:47 +0200 Subject: [PATCH 035/351] removed unused const array --- STM32F4/variants/generic_f407v/pin_map.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/STM32F4/variants/generic_f407v/pin_map.c b/STM32F4/variants/generic_f407v/pin_map.c index 58eeca4..2189902 100644 --- a/STM32F4/variants/generic_f407v/pin_map.c +++ b/STM32F4/variants/generic_f407v/pin_map.c @@ -53,20 +53,16 @@ extern timer_dev timer5; extern timer_dev timer6; extern timer_dev timer7; extern timer_dev timer8; + /* typedef struct stm32_pin_info { gpio_dev *gpio_device; // Maple pin's GPIO device - uint8 gpio_bit; // Pin's GPIO port bit. timer_dev *timer_device; // Pin's timer device, if any. uint8 timer_channel; // Timer channel, or 0 if none. - const adc_dev *adc_device; // ADC device, if any. uint8 adc_channel; // Pin ADC channel, or ADCx if none. + const adc_dev *adc_device; // ADC device, if any. } stm32_pin_info; */ -const stm32_pin_info PIN_MAP1[] = { // LQFP100 package pin - {&GPIOA, &timer5, 1, 0, &ADC1}, // D00/PA0 | 23 | USART2_CTS | UART4_TX | ETH_MII_CRS | TIM2_CH1_ETR | TIM5_CH1 | TIM8_ETR | ADC123_IN0/WKUP -}; - const stm32_pin_info PIN_MAP[] = { // LQFP100 package pin {&GPIOA, &timer5, 1, 0, &ADC1}, // D00/PA0 | 23 | USART2_CTS | UART4_TX | ETH_MII_CRS | TIM2_CH1_ETR | TIM5_CH1 | TIM8_ETR | ADC123_IN0/WKUP {&GPIOA, &timer5, 2, 1, &ADC1}, // D01/PA1 | 24 | USART2_RTS | UART4_RX | ETH_RMII_REF_CLK | ETH_MII_RX_CLK | TIM5_CH2 | TIM2_CH2 | ADC123_IN1 From 59b71f1370229a180484903e65dca0514d5475e8 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Tue, 9 May 2017 17:00:27 +0200 Subject: [PATCH 036/351] improved block read routine --- STM32F4/libraries/SPI/src/SPI.cpp | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/STM32F4/libraries/SPI/src/SPI.cpp b/STM32F4/libraries/SPI/src/SPI.cpp index baef0ab..2d2cc48 100644 --- a/STM32F4/libraries/SPI/src/SPI.cpp +++ b/STM32F4/libraries/SPI/src/SPI.cpp @@ -321,14 +321,32 @@ uint16 SPIClass::read(void) void SPIClass::read(uint8 *buf, uint32 len) { - spi_rx_reg(_currentSetting->spi_d); // clear the RX buffer in case a byte is waiting on it. + 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; +#if 1 + // 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 +#else // 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 - } + } +#endif } void SPIClass::write(uint16 data) @@ -339,7 +357,6 @@ 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) -//return; 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." } From 54cd854161ffe5d84cde14a3763b5abe68a30ae7 Mon Sep 17 00:00:00 2001 From: SukkoPera Date: Tue, 9 May 2017 23:16:10 +0200 Subject: [PATCH 037/351] Tag isConnected() with __attribute__(deprecated) --- STM32F1/cores/maple/usb_serial.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/cores/maple/usb_serial.h b/STM32F1/cores/maple/usb_serial.h index ceb81e1..40745c1 100644 --- a/STM32F1/cores/maple/usb_serial.h +++ b/STM32F1/cores/maple/usb_serial.h @@ -80,7 +80,7 @@ public: * * Deprecated, use the above. */ - uint8 isConnected() { return (bool) *this; } + uint8 isConnected() __attribute__((deprecated("Use !Serial instead"))) { return (bool) *this; } }; #ifdef SERIAL_USB From ad51f6f8f8888f528badcea133953f525fd1116b Mon Sep 17 00:00:00 2001 From: SukkoPera Date: Tue, 9 May 2017 23:16:47 +0200 Subject: [PATCH 038/351] Avoid usage of deprecated function --- STM32F1/cores/maple/usb_serial.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/cores/maple/usb_serial.cpp b/STM32F1/cores/maple/usb_serial.cpp index 85c7024..57b439f 100644 --- a/STM32F1/cores/maple/usb_serial.cpp +++ b/STM32F1/cores/maple/usb_serial.cpp @@ -107,7 +107,7 @@ size_t n = 0; size_t USBSerial::write(const uint8 *buf, uint32 len) { size_t n = 0; - if (!this->isConnected() || !buf) { + if (!(bool) *this || !buf) { return 0; } From 59ebf2a818b803094ee2319021630440e3bc0daf Mon Sep 17 00:00:00 2001 From: stevstrong Date: Wed, 10 May 2017 20:48:14 +0200 Subject: [PATCH 039/351] improved SPI no DMA block read + added SPI DMA --- STM32F4/cores/maple/libmaple/dmaF4.c | 35 +++-------- STM32F4/cores/maple/libmaple/dmaF4.h | 72 +++++++++++++++++------ STM32F4/cores/maple/libmaple/dma_common.h | 12 +--- STM32F4/cores/maple/libmaple/spi_f4.c | 2 +- STM32F4/libraries/SPI/src/SPI.h | 8 ++- 5 files changed, 71 insertions(+), 58 deletions(-) diff --git a/STM32F4/cores/maple/libmaple/dmaF4.c b/STM32F4/cores/maple/libmaple/dmaF4.c index 4b530af..add3d8e 100644 --- a/STM32F4/cores/maple/libmaple/dmaF4.c +++ b/STM32F4/cores/maple/libmaple/dmaF4.c @@ -117,33 +117,16 @@ void dma_detach_interrupt(dma_dev *dev, dma_stream stream) { dev->handlers[stream].handler = NULL; } +const uint8 dma_isr_bits_shift[] = { 0, 6, 16, 22}; + +uint8 dma_get_isr_bits(dma_dev *dev, dma_stream stream) { + if ( stream&0xFC ) return ((dev->regs->HISR)>>dma_isr_bits_shift[stream&0x03]) & 0x3d; + else return ((dev->regs->LISR)>>dma_isr_bits_shift[stream&0x03]) & 0x3d; +} + void dma_clear_isr_bits(dma_dev *dev, dma_stream stream) { - switch (stream) { - case 0: - dev->regs->LIFCR|=0x0000003d; - break; - case 1: - dev->regs->LIFCR|=0x00000f40; - break; - case 2: - dev->regs->LIFCR|=0x003d0000; - break; - case 3: - dev->regs->LIFCR|=0x0f400000; - break; - case 4: - dev->regs->HIFCR|=0x0000003d; - break; - case 5: - dev->regs->HIFCR|=0x00000f40; - break; - case 6: - dev->regs->HIFCR|=0x003d0000; - break; - case 7: - dev->regs->HIFCR|=0x0f400000; - break; - } + if ( stream&0xFC ) dev->regs->HIFCR = (uint32)0x0000003d << dma_isr_bits_shift[stream&0x03]; + else dev->regs->LIFCR = (uint32)0x0000003d << dma_isr_bits_shift[stream&0x03]; } /* diff --git a/STM32F4/cores/maple/libmaple/dmaF4.h b/STM32F4/cores/maple/libmaple/dmaF4.h index 6f7086f..757906c 100644 --- a/STM32F4/cores/maple/libmaple/dmaF4.h +++ b/STM32F4/cores/maple/libmaple/dmaF4.h @@ -25,7 +25,7 @@ *****************************************************************************/ /** - * @file dma.h + * @file dmaF4.h * * @author Marti Bolivar ; * Original implementation by Michael Hope @@ -84,7 +84,7 @@ typedef struct dma_reg_map { * Register bit definitions */ -/* Channel configuration register */ +/* Stream configuration register */ #define DMA_CR_CH0 (0x0 << 25) #define DMA_CR_CH1 (0x1 << 25) @@ -136,6 +136,25 @@ typedef struct dma_reg_map { #define DMA_CR_DMEIE (0x1 << 1) #define DMA_CR_EN (0x1) +typedef enum dma_channel { + DMA_CH0 = DMA_CR_CH0, /**< Channel 0 */ + DMA_CH1 = DMA_CR_CH1, /**< Channel 1 */ + DMA_CH2 = DMA_CR_CH2, /**< Channel 2 */ + DMA_CH3 = DMA_CR_CH3, /**< Channel 3 */ + DMA_CH4 = DMA_CR_CH4, /**< Channel 4 */ + DMA_CH5 = DMA_CR_CH5, /**< Channel 5 */ + DMA_CH6 = DMA_CR_CH6, /**< Channel 6 */ + DMA_CH7 = DMA_CR_CH7, /**< Channel 7 */ +} dma_channel; + +/* Device interrupt status register flags */ + +#define DMA_ISR_TCIF (1 << 5) +#define DMA_ISR_HTIF (1 << 4) +#define DMA_ISR_TEIF (1 << 3) +#define DMA_ISR_DMEIF (1 << 2) +#define DMA_ISR_FEIF (1 << 0) + /* * Devices */ @@ -166,25 +185,35 @@ extern dma_dev *DMA2; * Convenience functions */ -void dma_init(dma_dev *dev); +extern void dma_init(dma_dev *dev); /** Flags for DMA transfer configuration. */ typedef enum dma_mode_flags { - DMA_MEM_2_MEM = 1 << 14, /**< Memory to memory mode */ - DMA_MINC_MODE = 1 << 7, /**< Auto-increment memory address */ - DMA_PINC_MODE = 1 << 6, /**< Auto-increment peripheral address */ - DMA_CIRC_MODE = 1 << 5, /**< Circular mode */ - DMA_FROM_MEM = 1 << 4, /**< Read from memory to peripheral */ - DMA_TRNS_ERR = 1 << 3, /**< Interrupt on transfer error */ - DMA_HALF_TRNS = 1 << 2, /**< Interrupt on half-transfer */ - DMA_TRNS_CMPLT = 1 << 1 /**< Interrupt on transfer completion */ + DMA_MEM_BUF_0 = DMA_CR_CT0, /**< Current memory target buffer 0 */ + DMA_MEM_BUF_1 = DMA_CR_CT1, /**< Current memory target buffer 1 */ + DMA_DBL_BUF_MODE = DMA_CR_DBM, /**< Current memory double buffer mode */ + DMA_PINC_OFFSET = DMA_CR_PINCOS, /**< Peripheral increment offset size */ + DMA_MINC_MODE = DMA_CR_MINC, /**< Memory increment mode */ + DMA_PINC_MODE = DMA_CR_PINC, /**< Peripheral increment mode */ + DMA_CIRC_MODE = DMA_CR_CIRC, /**< Memory Circular mode */ + DMA_FROM_PER = DMA_CR_DIR_P2M, /**< Read from memory to peripheral */ + DMA_FROM_MEM = DMA_CR_DIR_M2P, /**< Read from memory to peripheral */ + DMA_MEM_TO_MEM = DMA_CR_DIR_M2M, /**< Read from memory to memory */ + DMA_PERIF_CTRL = DMA_CR_PFCTRL, /**< Peripheral flow controller */ + DMA_PRIO_MEDIUM = DMA_CR_PL_MEDIUM, /**< Medium priority */ + DMA_PRIO_HIGH = DMA_CR_PL_HIGH, /**< High priority */ + DMA_PRIO_VERY_HIGH = DMA_CR_PL_VERY_HIGH, /**< Very high priority */ + DMA_TRNS_CMPLT = DMA_CR_TCIE, /**< Interrupt on transfer completion */ + DMA_TRNS_HALF = DMA_CR_HTIE, /**< Interrupt on half-transfer */ + DMA_TRNS_ERR = DMA_CR_TEIE, /**< Interrupt on transfer error */ + DMA_DIR_MODE_ERR = DMA_CR_DMEIE /**< Interrupt on direct mode error */ } dma_mode_flags; /** Source and destination transfer sizes. */ typedef enum dma_xfer_size { - DMA_SIZE_8BITS = 0, /**< 8-bit transfers */ - DMA_SIZE_16BITS = 1, /**< 16-bit transfers */ - DMA_SIZE_32BITS = 2 /**< 32-bit transfers */ + DMA_SIZE_8BITS = ( DMA_CR_MSIZE_8BITS|DMA_CR_PSIZE_8BITS ), /**< 8-bit transfers */ + DMA_SIZE_16BITS = (DMA_CR_MSIZE_16BITS|DMA_CR_PSIZE_16BITS), /**< 16-bit transfers */ + DMA_SIZE_32BITS = (DMA_CR_MSIZE_32BITS|DMA_CR_PSIZE_32BITS) /**< 32-bit transfers */ } dma_xfer_size; /** DMA channel */ @@ -201,17 +230,17 @@ typedef enum dma_stream { static inline void dma_setup_transfer(dma_dev *dev, dma_stream stream, + dma_channel channel, + dma_xfer_size trx_size, __io void *peripheral_address, __io void *memory_address0, __io void *memory_address1, - uint32 flags, - uint32 fifo_flags) { + uint32 flags) { dev->regs->STREAM[stream].CR &= ~DMA_CR_EN; // disable dev->regs->STREAM[stream].PAR = (uint32)peripheral_address; dev->regs->STREAM[stream].M0AR = (uint32)memory_address0; dev->regs->STREAM[stream].M1AR = (uint32)memory_address1; - dev->regs->STREAM[stream].FCR = fifo_flags & 0x87; // mask out reserved bits - dev->regs->STREAM[stream].CR = flags & 0x0feffffe; // mask out reserved and enable + dev->regs->STREAM[stream].CR = ((flags|channel|trx_size) & 0x0feffffe); // mask out reserved and enable } static inline void dma_set_num_transfers(dma_dev *dev, @@ -220,6 +249,12 @@ static inline void dma_set_num_transfers(dma_dev *dev, dev->regs->STREAM[stream].NDTR = num_transfers; } +static inline void dma_set_fifo_flags(dma_dev *dev, + dma_stream stream, + uint8 fifo_flags) { + dev->regs->STREAM[stream].FCR = fifo_flags & 0x87; // mask out reserved bits +} + void dma_attach_interrupt(dma_dev *dev, dma_stream stream, void (*handler)(void)); @@ -232,6 +267,7 @@ static inline void dma_enable(dma_dev *dev, dma_stream stream) { static inline void dma_disable(dma_dev *dev, dma_stream stream) { dev->regs->STREAM[stream].CR &= ~DMA_CR_EN; + while (dev->regs->STREAM[stream].CR & DMA_CR_EN); // wait till EN bit is reset, see AN4031, chapter 4.1 } /** diff --git a/STM32F4/cores/maple/libmaple/dma_common.h b/STM32F4/cores/maple/libmaple/dma_common.h index 15dfab9..5f98921 100644 --- a/STM32F4/cores/maple/libmaple/dma_common.h +++ b/STM32F4/cores/maple/libmaple/dma_common.h @@ -56,7 +56,7 @@ extern "C"{ * Devices */ -struct dma_reg_map; +//struct dma_reg_map; /* Encapsulates state related to user interrupt handlers. You * shouldn't touch these directly; use dma_attach_interrupt() and @@ -82,16 +82,6 @@ struct dma_reg_map; * * @see dma_tube */ -typedef enum dma_channel { - DMA_CH0 = 0, /**< Channel 0 */ - DMA_CH1 = 1, /**< Channel 1 */ - DMA_CH2 = 2, /**< Channel 2 */ - DMA_CH3 = 3, /**< Channel 3 */ - DMA_CH4 = 4, /**< Channel 4 */ - DMA_CH5 = 5, /**< Channel 5 */ - DMA_CH6 = 6, /**< Channel 6 */ - DMA_CH7 = 7, /**< Channel 7 */ -} dma_channel; /** * @brief Source and destination transfer sizes. diff --git a/STM32F4/cores/maple/libmaple/spi_f4.c b/STM32F4/cores/maple/libmaple/spi_f4.c index 43f5092..8e1bc15 100644 --- a/STM32F4/cores/maple/libmaple/spi_f4.c +++ b/STM32F4/cores/maple/libmaple/spi_f4.c @@ -28,7 +28,7 @@ /** * @file libmaple/stm32f1/spi.c * @author Marti Bolivar - * @brief STM32F1 SPI/I2S. + * @brief STM32F4 SPI/I2S. */ #include diff --git a/STM32F4/libraries/SPI/src/SPI.h b/STM32F4/libraries/SPI/src/SPI.h index 39a5a9e..fe728b5 100644 --- a/STM32F4/libraries/SPI/src/SPI.h +++ b/STM32F4/libraries/SPI/src/SPI.h @@ -42,6 +42,8 @@ #include #include +#define SPI_DMA + // SPI_HAS_TRANSACTION means SPI has // - beginTransaction() // - endTransaction() @@ -135,11 +137,12 @@ private: uint32_t dataSize; spi_dev *spi_d; - //uint8_t _SSPin; uint32_t clockDivider; + #ifdef SPI_DMA - dma_channel spiRxDmaChannel, spiTxDmaChannel; dma_dev* spiDmaDev; + dma_channel spiDmaChannel; + dma_stream spiRxDmaStream, spiTxDmaStream; #endif friend class SPIClass; @@ -396,5 +399,6 @@ private: */ }; +extern SPIClass SPI; #endif From fc0ee241841d71a5e7e289f6d715c160581dfc38 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Thu, 11 May 2017 00:01:53 +0200 Subject: [PATCH 040/351] Revert "improved SPI no DMA block read + added SPI DMA" This reverts commit 59ebf2a818b803094ee2319021630440e3bc0daf. --- STM32F4/cores/maple/libmaple/dmaF4.c | 35 ++++++++--- STM32F4/cores/maple/libmaple/dmaF4.h | 72 ++++++----------------- STM32F4/cores/maple/libmaple/dma_common.h | 12 +++- STM32F4/cores/maple/libmaple/spi_f4.c | 2 +- STM32F4/libraries/SPI/src/SPI.h | 8 +-- 5 files changed, 58 insertions(+), 71 deletions(-) diff --git a/STM32F4/cores/maple/libmaple/dmaF4.c b/STM32F4/cores/maple/libmaple/dmaF4.c index add3d8e..4b530af 100644 --- a/STM32F4/cores/maple/libmaple/dmaF4.c +++ b/STM32F4/cores/maple/libmaple/dmaF4.c @@ -117,16 +117,33 @@ void dma_detach_interrupt(dma_dev *dev, dma_stream stream) { dev->handlers[stream].handler = NULL; } -const uint8 dma_isr_bits_shift[] = { 0, 6, 16, 22}; - -uint8 dma_get_isr_bits(dma_dev *dev, dma_stream stream) { - if ( stream&0xFC ) return ((dev->regs->HISR)>>dma_isr_bits_shift[stream&0x03]) & 0x3d; - else return ((dev->regs->LISR)>>dma_isr_bits_shift[stream&0x03]) & 0x3d; -} - void dma_clear_isr_bits(dma_dev *dev, dma_stream stream) { - if ( stream&0xFC ) dev->regs->HIFCR = (uint32)0x0000003d << dma_isr_bits_shift[stream&0x03]; - else dev->regs->LIFCR = (uint32)0x0000003d << dma_isr_bits_shift[stream&0x03]; + switch (stream) { + case 0: + dev->regs->LIFCR|=0x0000003d; + break; + case 1: + dev->regs->LIFCR|=0x00000f40; + break; + case 2: + dev->regs->LIFCR|=0x003d0000; + break; + case 3: + dev->regs->LIFCR|=0x0f400000; + break; + case 4: + dev->regs->HIFCR|=0x0000003d; + break; + case 5: + dev->regs->HIFCR|=0x00000f40; + break; + case 6: + dev->regs->HIFCR|=0x003d0000; + break; + case 7: + dev->regs->HIFCR|=0x0f400000; + break; + } } /* diff --git a/STM32F4/cores/maple/libmaple/dmaF4.h b/STM32F4/cores/maple/libmaple/dmaF4.h index 757906c..6f7086f 100644 --- a/STM32F4/cores/maple/libmaple/dmaF4.h +++ b/STM32F4/cores/maple/libmaple/dmaF4.h @@ -25,7 +25,7 @@ *****************************************************************************/ /** - * @file dmaF4.h + * @file dma.h * * @author Marti Bolivar ; * Original implementation by Michael Hope @@ -84,7 +84,7 @@ typedef struct dma_reg_map { * Register bit definitions */ -/* Stream configuration register */ +/* Channel configuration register */ #define DMA_CR_CH0 (0x0 << 25) #define DMA_CR_CH1 (0x1 << 25) @@ -136,25 +136,6 @@ typedef struct dma_reg_map { #define DMA_CR_DMEIE (0x1 << 1) #define DMA_CR_EN (0x1) -typedef enum dma_channel { - DMA_CH0 = DMA_CR_CH0, /**< Channel 0 */ - DMA_CH1 = DMA_CR_CH1, /**< Channel 1 */ - DMA_CH2 = DMA_CR_CH2, /**< Channel 2 */ - DMA_CH3 = DMA_CR_CH3, /**< Channel 3 */ - DMA_CH4 = DMA_CR_CH4, /**< Channel 4 */ - DMA_CH5 = DMA_CR_CH5, /**< Channel 5 */ - DMA_CH6 = DMA_CR_CH6, /**< Channel 6 */ - DMA_CH7 = DMA_CR_CH7, /**< Channel 7 */ -} dma_channel; - -/* Device interrupt status register flags */ - -#define DMA_ISR_TCIF (1 << 5) -#define DMA_ISR_HTIF (1 << 4) -#define DMA_ISR_TEIF (1 << 3) -#define DMA_ISR_DMEIF (1 << 2) -#define DMA_ISR_FEIF (1 << 0) - /* * Devices */ @@ -185,35 +166,25 @@ extern dma_dev *DMA2; * Convenience functions */ -extern void dma_init(dma_dev *dev); +void dma_init(dma_dev *dev); /** Flags for DMA transfer configuration. */ typedef enum dma_mode_flags { - DMA_MEM_BUF_0 = DMA_CR_CT0, /**< Current memory target buffer 0 */ - DMA_MEM_BUF_1 = DMA_CR_CT1, /**< Current memory target buffer 1 */ - DMA_DBL_BUF_MODE = DMA_CR_DBM, /**< Current memory double buffer mode */ - DMA_PINC_OFFSET = DMA_CR_PINCOS, /**< Peripheral increment offset size */ - DMA_MINC_MODE = DMA_CR_MINC, /**< Memory increment mode */ - DMA_PINC_MODE = DMA_CR_PINC, /**< Peripheral increment mode */ - DMA_CIRC_MODE = DMA_CR_CIRC, /**< Memory Circular mode */ - DMA_FROM_PER = DMA_CR_DIR_P2M, /**< Read from memory to peripheral */ - DMA_FROM_MEM = DMA_CR_DIR_M2P, /**< Read from memory to peripheral */ - DMA_MEM_TO_MEM = DMA_CR_DIR_M2M, /**< Read from memory to memory */ - DMA_PERIF_CTRL = DMA_CR_PFCTRL, /**< Peripheral flow controller */ - DMA_PRIO_MEDIUM = DMA_CR_PL_MEDIUM, /**< Medium priority */ - DMA_PRIO_HIGH = DMA_CR_PL_HIGH, /**< High priority */ - DMA_PRIO_VERY_HIGH = DMA_CR_PL_VERY_HIGH, /**< Very high priority */ - DMA_TRNS_CMPLT = DMA_CR_TCIE, /**< Interrupt on transfer completion */ - DMA_TRNS_HALF = DMA_CR_HTIE, /**< Interrupt on half-transfer */ - DMA_TRNS_ERR = DMA_CR_TEIE, /**< Interrupt on transfer error */ - DMA_DIR_MODE_ERR = DMA_CR_DMEIE /**< Interrupt on direct mode error */ + DMA_MEM_2_MEM = 1 << 14, /**< Memory to memory mode */ + DMA_MINC_MODE = 1 << 7, /**< Auto-increment memory address */ + DMA_PINC_MODE = 1 << 6, /**< Auto-increment peripheral address */ + DMA_CIRC_MODE = 1 << 5, /**< Circular mode */ + DMA_FROM_MEM = 1 << 4, /**< Read from memory to peripheral */ + DMA_TRNS_ERR = 1 << 3, /**< Interrupt on transfer error */ + DMA_HALF_TRNS = 1 << 2, /**< Interrupt on half-transfer */ + DMA_TRNS_CMPLT = 1 << 1 /**< Interrupt on transfer completion */ } dma_mode_flags; /** Source and destination transfer sizes. */ typedef enum dma_xfer_size { - DMA_SIZE_8BITS = ( DMA_CR_MSIZE_8BITS|DMA_CR_PSIZE_8BITS ), /**< 8-bit transfers */ - DMA_SIZE_16BITS = (DMA_CR_MSIZE_16BITS|DMA_CR_PSIZE_16BITS), /**< 16-bit transfers */ - DMA_SIZE_32BITS = (DMA_CR_MSIZE_32BITS|DMA_CR_PSIZE_32BITS) /**< 32-bit transfers */ + DMA_SIZE_8BITS = 0, /**< 8-bit transfers */ + DMA_SIZE_16BITS = 1, /**< 16-bit transfers */ + DMA_SIZE_32BITS = 2 /**< 32-bit transfers */ } dma_xfer_size; /** DMA channel */ @@ -230,17 +201,17 @@ typedef enum dma_stream { static inline void dma_setup_transfer(dma_dev *dev, dma_stream stream, - dma_channel channel, - dma_xfer_size trx_size, __io void *peripheral_address, __io void *memory_address0, __io void *memory_address1, - uint32 flags) { + uint32 flags, + uint32 fifo_flags) { dev->regs->STREAM[stream].CR &= ~DMA_CR_EN; // disable dev->regs->STREAM[stream].PAR = (uint32)peripheral_address; dev->regs->STREAM[stream].M0AR = (uint32)memory_address0; dev->regs->STREAM[stream].M1AR = (uint32)memory_address1; - dev->regs->STREAM[stream].CR = ((flags|channel|trx_size) & 0x0feffffe); // mask out reserved and enable + dev->regs->STREAM[stream].FCR = fifo_flags & 0x87; // mask out reserved bits + dev->regs->STREAM[stream].CR = flags & 0x0feffffe; // mask out reserved and enable } static inline void dma_set_num_transfers(dma_dev *dev, @@ -249,12 +220,6 @@ static inline void dma_set_num_transfers(dma_dev *dev, dev->regs->STREAM[stream].NDTR = num_transfers; } -static inline void dma_set_fifo_flags(dma_dev *dev, - dma_stream stream, - uint8 fifo_flags) { - dev->regs->STREAM[stream].FCR = fifo_flags & 0x87; // mask out reserved bits -} - void dma_attach_interrupt(dma_dev *dev, dma_stream stream, void (*handler)(void)); @@ -267,7 +232,6 @@ static inline void dma_enable(dma_dev *dev, dma_stream stream) { static inline void dma_disable(dma_dev *dev, dma_stream stream) { dev->regs->STREAM[stream].CR &= ~DMA_CR_EN; - while (dev->regs->STREAM[stream].CR & DMA_CR_EN); // wait till EN bit is reset, see AN4031, chapter 4.1 } /** diff --git a/STM32F4/cores/maple/libmaple/dma_common.h b/STM32F4/cores/maple/libmaple/dma_common.h index 5f98921..15dfab9 100644 --- a/STM32F4/cores/maple/libmaple/dma_common.h +++ b/STM32F4/cores/maple/libmaple/dma_common.h @@ -56,7 +56,7 @@ extern "C"{ * Devices */ -//struct dma_reg_map; +struct dma_reg_map; /* Encapsulates state related to user interrupt handlers. You * shouldn't touch these directly; use dma_attach_interrupt() and @@ -82,6 +82,16 @@ extern "C"{ * * @see dma_tube */ +typedef enum dma_channel { + DMA_CH0 = 0, /**< Channel 0 */ + DMA_CH1 = 1, /**< Channel 1 */ + DMA_CH2 = 2, /**< Channel 2 */ + DMA_CH3 = 3, /**< Channel 3 */ + DMA_CH4 = 4, /**< Channel 4 */ + DMA_CH5 = 5, /**< Channel 5 */ + DMA_CH6 = 6, /**< Channel 6 */ + DMA_CH7 = 7, /**< Channel 7 */ +} dma_channel; /** * @brief Source and destination transfer sizes. diff --git a/STM32F4/cores/maple/libmaple/spi_f4.c b/STM32F4/cores/maple/libmaple/spi_f4.c index 8e1bc15..43f5092 100644 --- a/STM32F4/cores/maple/libmaple/spi_f4.c +++ b/STM32F4/cores/maple/libmaple/spi_f4.c @@ -28,7 +28,7 @@ /** * @file libmaple/stm32f1/spi.c * @author Marti Bolivar - * @brief STM32F4 SPI/I2S. + * @brief STM32F1 SPI/I2S. */ #include diff --git a/STM32F4/libraries/SPI/src/SPI.h b/STM32F4/libraries/SPI/src/SPI.h index fe728b5..39a5a9e 100644 --- a/STM32F4/libraries/SPI/src/SPI.h +++ b/STM32F4/libraries/SPI/src/SPI.h @@ -42,8 +42,6 @@ #include #include -#define SPI_DMA - // SPI_HAS_TRANSACTION means SPI has // - beginTransaction() // - endTransaction() @@ -137,12 +135,11 @@ private: uint32_t dataSize; spi_dev *spi_d; + //uint8_t _SSPin; uint32_t clockDivider; - #ifdef SPI_DMA + dma_channel spiRxDmaChannel, spiTxDmaChannel; dma_dev* spiDmaDev; - dma_channel spiDmaChannel; - dma_stream spiRxDmaStream, spiTxDmaStream; #endif friend class SPIClass; @@ -399,6 +396,5 @@ private: */ }; -extern SPIClass SPI; #endif From bd3fb68a5ed4bd040809020955891492d909b5c7 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Thu, 11 May 2017 00:05:08 +0200 Subject: [PATCH 041/351] SPI improvements: non-DMA block read + added DMA transfer functions --- STM32F4/cores/maple/libmaple/dmaF4.c | 35 ++---- STM32F4/cores/maple/libmaple/dmaF4.h | 72 +++++++++--- STM32F4/libraries/SPI/src/SPI.cpp | 161 +++++++++++++++++---------- STM32F4/libraries/SPI/src/SPI.h | 17 +-- 4 files changed, 169 insertions(+), 116 deletions(-) diff --git a/STM32F4/cores/maple/libmaple/dmaF4.c b/STM32F4/cores/maple/libmaple/dmaF4.c index 4b530af..add3d8e 100644 --- a/STM32F4/cores/maple/libmaple/dmaF4.c +++ b/STM32F4/cores/maple/libmaple/dmaF4.c @@ -117,33 +117,16 @@ void dma_detach_interrupt(dma_dev *dev, dma_stream stream) { dev->handlers[stream].handler = NULL; } +const uint8 dma_isr_bits_shift[] = { 0, 6, 16, 22}; + +uint8 dma_get_isr_bits(dma_dev *dev, dma_stream stream) { + if ( stream&0xFC ) return ((dev->regs->HISR)>>dma_isr_bits_shift[stream&0x03]) & 0x3d; + else return ((dev->regs->LISR)>>dma_isr_bits_shift[stream&0x03]) & 0x3d; +} + void dma_clear_isr_bits(dma_dev *dev, dma_stream stream) { - switch (stream) { - case 0: - dev->regs->LIFCR|=0x0000003d; - break; - case 1: - dev->regs->LIFCR|=0x00000f40; - break; - case 2: - dev->regs->LIFCR|=0x003d0000; - break; - case 3: - dev->regs->LIFCR|=0x0f400000; - break; - case 4: - dev->regs->HIFCR|=0x0000003d; - break; - case 5: - dev->regs->HIFCR|=0x00000f40; - break; - case 6: - dev->regs->HIFCR|=0x003d0000; - break; - case 7: - dev->regs->HIFCR|=0x0f400000; - break; - } + if ( stream&0xFC ) dev->regs->HIFCR = (uint32)0x0000003d << dma_isr_bits_shift[stream&0x03]; + else dev->regs->LIFCR = (uint32)0x0000003d << dma_isr_bits_shift[stream&0x03]; } /* diff --git a/STM32F4/cores/maple/libmaple/dmaF4.h b/STM32F4/cores/maple/libmaple/dmaF4.h index 6f7086f..757906c 100644 --- a/STM32F4/cores/maple/libmaple/dmaF4.h +++ b/STM32F4/cores/maple/libmaple/dmaF4.h @@ -25,7 +25,7 @@ *****************************************************************************/ /** - * @file dma.h + * @file dmaF4.h * * @author Marti Bolivar ; * Original implementation by Michael Hope @@ -84,7 +84,7 @@ typedef struct dma_reg_map { * Register bit definitions */ -/* Channel configuration register */ +/* Stream configuration register */ #define DMA_CR_CH0 (0x0 << 25) #define DMA_CR_CH1 (0x1 << 25) @@ -136,6 +136,25 @@ typedef struct dma_reg_map { #define DMA_CR_DMEIE (0x1 << 1) #define DMA_CR_EN (0x1) +typedef enum dma_channel { + DMA_CH0 = DMA_CR_CH0, /**< Channel 0 */ + DMA_CH1 = DMA_CR_CH1, /**< Channel 1 */ + DMA_CH2 = DMA_CR_CH2, /**< Channel 2 */ + DMA_CH3 = DMA_CR_CH3, /**< Channel 3 */ + DMA_CH4 = DMA_CR_CH4, /**< Channel 4 */ + DMA_CH5 = DMA_CR_CH5, /**< Channel 5 */ + DMA_CH6 = DMA_CR_CH6, /**< Channel 6 */ + DMA_CH7 = DMA_CR_CH7, /**< Channel 7 */ +} dma_channel; + +/* Device interrupt status register flags */ + +#define DMA_ISR_TCIF (1 << 5) +#define DMA_ISR_HTIF (1 << 4) +#define DMA_ISR_TEIF (1 << 3) +#define DMA_ISR_DMEIF (1 << 2) +#define DMA_ISR_FEIF (1 << 0) + /* * Devices */ @@ -166,25 +185,35 @@ extern dma_dev *DMA2; * Convenience functions */ -void dma_init(dma_dev *dev); +extern void dma_init(dma_dev *dev); /** Flags for DMA transfer configuration. */ typedef enum dma_mode_flags { - DMA_MEM_2_MEM = 1 << 14, /**< Memory to memory mode */ - DMA_MINC_MODE = 1 << 7, /**< Auto-increment memory address */ - DMA_PINC_MODE = 1 << 6, /**< Auto-increment peripheral address */ - DMA_CIRC_MODE = 1 << 5, /**< Circular mode */ - DMA_FROM_MEM = 1 << 4, /**< Read from memory to peripheral */ - DMA_TRNS_ERR = 1 << 3, /**< Interrupt on transfer error */ - DMA_HALF_TRNS = 1 << 2, /**< Interrupt on half-transfer */ - DMA_TRNS_CMPLT = 1 << 1 /**< Interrupt on transfer completion */ + DMA_MEM_BUF_0 = DMA_CR_CT0, /**< Current memory target buffer 0 */ + DMA_MEM_BUF_1 = DMA_CR_CT1, /**< Current memory target buffer 1 */ + DMA_DBL_BUF_MODE = DMA_CR_DBM, /**< Current memory double buffer mode */ + DMA_PINC_OFFSET = DMA_CR_PINCOS, /**< Peripheral increment offset size */ + DMA_MINC_MODE = DMA_CR_MINC, /**< Memory increment mode */ + DMA_PINC_MODE = DMA_CR_PINC, /**< Peripheral increment mode */ + DMA_CIRC_MODE = DMA_CR_CIRC, /**< Memory Circular mode */ + DMA_FROM_PER = DMA_CR_DIR_P2M, /**< Read from memory to peripheral */ + DMA_FROM_MEM = DMA_CR_DIR_M2P, /**< Read from memory to peripheral */ + DMA_MEM_TO_MEM = DMA_CR_DIR_M2M, /**< Read from memory to memory */ + DMA_PERIF_CTRL = DMA_CR_PFCTRL, /**< Peripheral flow controller */ + DMA_PRIO_MEDIUM = DMA_CR_PL_MEDIUM, /**< Medium priority */ + DMA_PRIO_HIGH = DMA_CR_PL_HIGH, /**< High priority */ + DMA_PRIO_VERY_HIGH = DMA_CR_PL_VERY_HIGH, /**< Very high priority */ + DMA_TRNS_CMPLT = DMA_CR_TCIE, /**< Interrupt on transfer completion */ + DMA_TRNS_HALF = DMA_CR_HTIE, /**< Interrupt on half-transfer */ + DMA_TRNS_ERR = DMA_CR_TEIE, /**< Interrupt on transfer error */ + DMA_DIR_MODE_ERR = DMA_CR_DMEIE /**< Interrupt on direct mode error */ } dma_mode_flags; /** Source and destination transfer sizes. */ typedef enum dma_xfer_size { - DMA_SIZE_8BITS = 0, /**< 8-bit transfers */ - DMA_SIZE_16BITS = 1, /**< 16-bit transfers */ - DMA_SIZE_32BITS = 2 /**< 32-bit transfers */ + DMA_SIZE_8BITS = ( DMA_CR_MSIZE_8BITS|DMA_CR_PSIZE_8BITS ), /**< 8-bit transfers */ + DMA_SIZE_16BITS = (DMA_CR_MSIZE_16BITS|DMA_CR_PSIZE_16BITS), /**< 16-bit transfers */ + DMA_SIZE_32BITS = (DMA_CR_MSIZE_32BITS|DMA_CR_PSIZE_32BITS) /**< 32-bit transfers */ } dma_xfer_size; /** DMA channel */ @@ -201,17 +230,17 @@ typedef enum dma_stream { static inline void dma_setup_transfer(dma_dev *dev, dma_stream stream, + dma_channel channel, + dma_xfer_size trx_size, __io void *peripheral_address, __io void *memory_address0, __io void *memory_address1, - uint32 flags, - uint32 fifo_flags) { + uint32 flags) { dev->regs->STREAM[stream].CR &= ~DMA_CR_EN; // disable dev->regs->STREAM[stream].PAR = (uint32)peripheral_address; dev->regs->STREAM[stream].M0AR = (uint32)memory_address0; dev->regs->STREAM[stream].M1AR = (uint32)memory_address1; - dev->regs->STREAM[stream].FCR = fifo_flags & 0x87; // mask out reserved bits - dev->regs->STREAM[stream].CR = flags & 0x0feffffe; // mask out reserved and enable + dev->regs->STREAM[stream].CR = ((flags|channel|trx_size) & 0x0feffffe); // mask out reserved and enable } static inline void dma_set_num_transfers(dma_dev *dev, @@ -220,6 +249,12 @@ static inline void dma_set_num_transfers(dma_dev *dev, dev->regs->STREAM[stream].NDTR = num_transfers; } +static inline void dma_set_fifo_flags(dma_dev *dev, + dma_stream stream, + uint8 fifo_flags) { + dev->regs->STREAM[stream].FCR = fifo_flags & 0x87; // mask out reserved bits +} + void dma_attach_interrupt(dma_dev *dev, dma_stream stream, void (*handler)(void)); @@ -232,6 +267,7 @@ static inline void dma_enable(dma_dev *dev, dma_stream stream) { static inline void dma_disable(dma_dev *dev, dma_stream stream) { dev->regs->STREAM[stream].CR &= ~DMA_CR_EN; + while (dev->regs->STREAM[stream].CR & DMA_CR_EN); // wait till EN bit is reset, see AN4031, chapter 4.1 } /** diff --git a/STM32F4/libraries/SPI/src/SPI.cpp b/STM32F4/libraries/SPI/src/SPI.cpp index baef0ab..6edbceb 100644 --- a/STM32F4/libraries/SPI/src/SPI.cpp +++ b/STM32F4/libraries/SPI/src/SPI.cpp @@ -40,6 +40,8 @@ #include "wirish.h" #include "boards.h" +#define DMA_TIMEOUT 100 + #if CYCLES_PER_MICROSECOND != 168 /* TODO [0.2.0?] something smarter than this */ #warning "Unexpected clock speed; SPI frequency calculation will be incorrect" @@ -115,27 +117,37 @@ SPIClass::SPIClass(uint32 spi_num) { // Init things specific to each SPI device // clock divider setup is a bit of hack, and needs to be improved at a later date. +/*****************************************************************************/ +// DMA / Channel / Stream +// Rx Tx +// SPI1: 2 / 3 / 0 (2) - 2 / 3 / 3 (5) +// SPI2: 1 / 0 / 3 - 1 / 0 / 4 +// SPI3: 1 / 0 / 0 (2) - 1 / 0 / 5 (7) +/*****************************************************************************/ _settings[0].spi_d = SPI1; _settings[0].clockDivider = determine_baud_rate(_settings[0].spi_d, _settings[0].clock); #ifdef SPI_DMA - _settings[0].spiDmaDev = DMA1; - _settings[0].spiTxDmaChannel = DMA_CH3; - _settings[0].spiRxDmaChannel = DMA_CH2; + _settings[0].spiDmaDev = DMA2; + _settings[0].spiDmaChannel = DMA_CH3; + _settings[0].spiRxDmaStream = DMA_STREAM0; // alternative: DMA_STREAM2 + _settings[0].spiTxDmaStream = DMA_STREAM3; // alternative: DMA_STREAM5 #endif _settings[1].spi_d = SPI2; _settings[1].clockDivider = determine_baud_rate(_settings[1].spi_d, _settings[1].clock); #ifdef SPI_DMA _settings[1].spiDmaDev = DMA1; - _settings[1].spiTxDmaChannel = DMA_CH5; - _settings[1].spiRxDmaChannel = DMA_CH4; + _settings[1].spiDmaChannel = DMA_CH0; + _settings[1].spiRxDmaStream = DMA_STREAM3; // alternative: - + _settings[1].spiTxDmaStream = DMA_STREAM4; // alternative: - #endif #if BOARD_NR_SPI >= 3 _settings[2].spi_d = SPI3; _settings[2].clockDivider = determine_baud_rate(_settings[2].spi_d, _settings[2].clock); #ifdef SPI_DMA - _settings[2].spiDmaDev = DMA2; - _settings[2].spiTxDmaChannel = DMA_CH2; - _settings[2].spiRxDmaChannel = DMA_CH1; + _settings[2].spiDmaDev = DMA1; + _settings[2].spiDmaChannel = DMA_CH0; + _settings[2].spiRxDmaStream = DMA_STREAM0; // alternative: DMA_STREAM2 + _settings[2].spiTxDmaStream = DMA_STREAM5; // alternative: DMA_STREAM7 #endif #endif @@ -265,9 +277,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); @@ -321,14 +330,23 @@ uint16 SPIClass::read(void) void SPIClass::read(uint8 *buf, uint32 len) { - spi_rx_reg(_currentSetting->spi_d); // clear the RX buffer in case a byte is waiting on it. + 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; - // 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) @@ -393,47 +411,66 @@ uint16_t SPIClass::transfer16(uint16_t wr_data) const 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==SPI_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); + dma_setup_transfer( _currentSetting->spiDmaDev, + _currentSetting->spiRxDmaStream, + _currentSetting->spiDmaChannel, + dma_bit_size, + &_currentSetting->spi_d->regs->DR, // peripheral address + receiveBuf, // memory bank 0 address + NULL, // memory bank 1 address + (DMA_MINC_MODE | DMA_FROM_PER | DMA_PRIO_VERY_HIGH) // flags + ); + dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaStream, length); + dma_set_fifo_flags(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaStream, 0); + dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaStream); // 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); // | DMA_TRNS_CMPLT); if ( transmitBuf==0 ) { static uint8_t ff = 0XFF; transmitBuf = &ff; - flags ^= DMA_MINC_MODE; // remove increment mode + flags &= ~((uint32)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 + dma_setup_transfer( _currentSetting->spiDmaDev, + _currentSetting->spiTxDmaStream, + _currentSetting->spiDmaChannel, + dma_bit_size, + &_currentSetting->spi_d->regs->DR, // peripheral address + transmitBuf, // memory bank 0 address + NULL, // memory bank 1 address + flags + ); + dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream, length); + dma_set_fifo_flags(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream, 0); + dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream); + // software enable sequence, see AN4031, chapter 4.3 + dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaStream);// enable receive + dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream);// 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. + while ((b = dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream) & DMA_ISR_TCIF)==0 ) {// wait for completion flag to be set + if ( b&(DMA_ISR_TEIF|DMA_ISR_DMEIF|DMA_ISR_FEIF) ) { b = 1; break; } // break on any error flag if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; } } - dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); + if (b & DMA_ISR_TCIF) b = 0; 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 + // software disable sequence, see AN4031, chapter 4.1 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); + dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaStream); + dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream); return b; } @@ -446,28 +483,36 @@ uint8 SPIClass::dmaTransfer(void * transmitBuf, void * receiveBuf, uint16 length 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; dma_init(_currentSetting->spiDmaDev); // TX - spi_tx_dma_enable(_currentSetting->spi_d); dma_xfer_size dma_bit_size = (_currentSetting->dataSize==SPI_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_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit + dma_setup_transfer( _currentSetting->spiDmaDev, + _currentSetting->spiTxDmaStream, + _currentSetting->spiDmaChannel, + dma_bit_size, + &_currentSetting->spi_d->regs->DR, // peripheral address + transmitBuf, // memory bank 0 address + NULL, // memory bank 1 address + ( (DMA_MINC_MODE*minc) | DMA_FROM_MEM ) //| DMA_TRNS_CMPLT ) // flags + );// Transmit buffer DMA + dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream, length); + dma_set_fifo_flags(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream, 0); + dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream); + dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream);// enable transmit + spi_tx_dma_enable(_currentSetting->spi_d); 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. + while ((b = dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream) & DMA_ISR_TCIF)==0 ) {// wait for completion flag to be set + if ( b&(DMA_ISR_TEIF|DMA_ISR_DMEIF|DMA_ISR_FEIF) ) { b = 1; break; } // break on any error flag if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; } - } - dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); + } + if (b & DMA_ISR_TCIF) b = 0; 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! + dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream); return b; } #endif @@ -507,18 +552,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) { @@ -640,4 +680,3 @@ static spi_baud_rate determine_baud_rate(spi_dev *dev, uint32_t freq) { //SPIClass SPI(3); - diff --git a/STM32F4/libraries/SPI/src/SPI.h b/STM32F4/libraries/SPI/src/SPI.h index 39a5a9e..d9e1e7a 100644 --- a/STM32F4/libraries/SPI/src/SPI.h +++ b/STM32F4/libraries/SPI/src/SPI.h @@ -42,6 +42,8 @@ #include #include +#define SPI_DMA + // SPI_HAS_TRANSACTION means SPI has // - beginTransaction() // - endTransaction() @@ -135,19 +137,18 @@ private: uint32_t dataSize; spi_dev *spi_d; - //uint8_t _SSPin; uint32_t clockDivider; + #ifdef SPI_DMA - dma_channel spiRxDmaChannel, spiTxDmaChannel; dma_dev* spiDmaDev; + dma_channel spiDmaChannel; + dma_stream spiRxDmaStream, spiTxDmaStream; #endif friend class SPIClass; }; - - /** * @brief Wirish SPI interface. * @@ -157,18 +158,11 @@ private: class SPIClass { public: - - /** * @param spiPortNumber Number of the SPI port to manage. */ SPIClass(uint32 spiPortNumber); - /* - * Set up/tear down - */ - - /** * @brief Equivalent to begin(SPI_1_125MHZ, MSBFIRST, 0). @@ -396,5 +390,6 @@ private: */ }; +extern SPIClass SPI; #endif From 679217dfafc66b0f0a3c3741396328c8e70df5ad Mon Sep 17 00:00:00 2001 From: stevstrong Date: Thu, 11 May 2017 00:57:08 +0200 Subject: [PATCH 042/351] F4 development - added generic F4 variant - removed F1 and F2 files/defines - resolved include headers - now libraries are detected within sketches - reworked + added new GPIO access functions - moved and size-optimized PIN_MAP in flash - SPI improvements: optimized block read + added DMA --- STM32F4/boards.txt | 39 ++ STM32F4/cores/maple/Arduino.h | 6 - STM32F4/cores/maple/Client.h | 5 +- STM32F4/cores/maple/HardwareTimer.h | 2 +- STM32F4/cores/maple/IPAddress.h | 4 +- STM32F4/cores/maple/Server.h | 4 +- STM32F4/cores/maple/Stream.h | 4 +- STM32F4/cores/maple/Udp.h | 4 +- STM32F4/cores/maple/WProgram.h | 7 +- STM32F4/cores/maple/WString.h | 7 +- STM32F4/cores/maple/bits.h | 5 + STM32F4/cores/maple/boards.cpp | 32 +- STM32F4/cores/maple/boards.h | 39 +- STM32F4/cores/maple/ext_interrupts.cpp | 8 +- STM32F4/cores/maple/ext_interrupts.h | 9 +- STM32F4/cores/maple/io.h | 13 +- STM32F4/cores/maple/itoa.h | 4 +- STM32F4/cores/maple/libmaple/HardwareSPI.cpp | 424 ------------- STM32F4/cores/maple/libmaple/HardwareSPI.h | 279 --------- .../cores/maple/libmaple/HardwareSerial.cpp | 30 +- STM32F4/cores/maple/libmaple/HardwareSerial.h | 2 +- STM32F4/cores/maple/libmaple/adc.c | 33 +- STM32F4/cores/maple/libmaple/adc.h | 54 +- STM32F4/cores/maple/libmaple/dac.c | 4 +- STM32F4/cores/maple/libmaple/dma.h | 7 +- STM32F4/cores/maple/libmaple/dmaF1.c | 383 ------------ STM32F4/cores/maple/libmaple/dmaF1.h | 453 -------------- .../cores/maple/libmaple/{dmaF2.c => dmaF4.c} | 39 +- .../cores/maple/libmaple/{dmaF2.h => dmaF4.h} | 72 ++- STM32F4/cores/maple/libmaple/exti.h | 4 - STM32F4/cores/maple/libmaple/fsmc.c | 53 +- STM32F4/cores/maple/libmaple/gpio.h | 102 +++- STM32F4/cores/maple/libmaple/gpioF1.c | 200 ------ STM32F4/cores/maple/libmaple/gpioF1.h | 530 ---------------- .../maple/libmaple/{gpioF2.c => gpioF4.c} | 79 ++- .../maple/libmaple/{gpioF2.h => gpio_def.h} | 90 +-- STM32F4/cores/maple/libmaple/i2c.c | 40 +- STM32F4/cores/maple/libmaple/i2c.h | 2 +- STM32F4/cores/maple/libmaple/libmaple.h | 14 +- STM32F4/cores/maple/libmaple/libmaple_types.h | 15 +- STM32F4/cores/maple/libmaple/rcc.h | 7 +- STM32F4/cores/maple/libmaple/rccF1.c | 233 ------- STM32F4/cores/maple/libmaple/rccF1.h | 572 ------------------ .../cores/maple/libmaple/{rccF2.c => rccF4.c} | 7 +- .../cores/maple/libmaple/{rccF2.h => rccF4.h} | 0 STM32F4/cores/maple/libmaple/rules.mk | 22 - STM32F4/cores/maple/libmaple/spi.c | 39 +- STM32F4/cores/maple/libmaple/spi.h | 19 +- STM32F4/cores/maple/libmaple/spiF4.h | 15 +- STM32F4/cores/maple/libmaple/spi_f4.c | 26 +- STM32F4/cores/maple/libmaple/stm32.h | 63 +- STM32F4/cores/maple/libmaple/timer.c | 16 +- STM32F4/cores/maple/libmaple/timer.h | 19 +- STM32F4/cores/maple/libmaple/usart.h | 6 +- .../Class/audio/inc/usbd_audio_core.h | 2 +- .../Class/cdc/inc/usbd_cdc_core.h | 3 +- .../Class/cdc/src/usbd_cdc_core.c | 7 +- .../Core/inc/usbd_core.h | 4 +- .../Core/inc/usbd_def.h | 2 +- .../Core/inc/usbd_req.h | 2 +- .../Core/src/usbd_core.c | 10 +- .../Core/src/usbd_ioreq.c | 2 +- .../Core/src/usbd_req.c | 6 +- .../usbF4/STM32_USB_OTG_Driver/inc/usb_core.h | 2 +- .../STM32_USB_OTG_Driver/inc/usb_defines.h | 2 +- .../usbF4/STM32_USB_OTG_Driver/inc/usb_otg.h | 1 + .../usbF4/STM32_USB_OTG_Driver/inc/usb_regs.h | 4 +- .../usbF4/STM32_USB_OTG_Driver/src/usb_core.c | 4 +- .../usbF4/STM32_USB_OTG_Driver/src/usb_dcd.c | 4 +- .../STM32_USB_OTG_Driver/src/usb_dcd_int.c | 4 +- .../cores/maple/libmaple/usbF4/VCP/core_cm4.h | 2 +- STM32F4/cores/maple/libmaple/usbF4/VCP/misc.c | 2 +- .../cores/maple/libmaple/usbF4/VCP/usb_bsp.c | 22 +- .../cores/maple/libmaple/usbF4/VCP/usb_conf.h | 4 + .../maple/libmaple/usbF4/VCP/usbd_cdc_vcp.c | 2 +- .../maple/libmaple/usbF4/VCP/usbd_cdc_vcp.h | 2 +- .../maple/libmaple/usbF4/VCP/usbd_conf.h | 1 + .../maple/libmaple/usbF4/VCP/usbd_desc.c | 6 +- .../maple/libmaple/usbF4/VCP/usbd_desc.h | 2 +- .../cores/maple/libmaple/usbF4/VCP/usbd_usr.c | 4 +- STM32F4/cores/maple/libmaple/usbF4/usb.c | 33 +- STM32F4/cores/maple/libmaple/usbF4/usb.h | 2 +- STM32F4/cores/maple/libmaple/util.c | 6 +- STM32F4/cores/maple/libmaple/util.h | 5 +- STM32F4/cores/maple/pwm.cpp | 4 +- STM32F4/cores/maple/usb_serial.cpp | 6 +- STM32F4/cores/maple/usb_serial.h | 15 +- STM32F4/cores/maple/wirish.h | 15 +- STM32F4/cores/maple/wirish_analog.cpp | 2 - STM32F4/cores/maple/wirish_constants.h | 4 +- STM32F4/cores/maple/wirish_debug.h | 7 +- STM32F4/cores/maple/wirish_digital.cpp | 31 +- STM32F4/cores/maple/wirish_math.h | 4 +- STM32F4/cores/maple/wirish_time.cpp | 6 +- STM32F4/cores/maple/wirish_time.h | 5 +- STM32F4/cores/maple/wirish_types.h | 23 +- STM32F4/libraries/SPI/library.properties | 1 + STM32F4/libraries/SPI/src/SPI.cpp | 518 ++++++++-------- STM32F4/libraries/SPI/src/SPI.h | 161 ++--- STM32F4/platform.txt | 20 +- .../gpio.c => system/libmaple/Arduino.h} | 30 +- .../variants/generic_f407v/generic_f407v.cpp | 81 +++ .../variants/generic_f407v/generic_f407v.h | 163 +++++ STM32F4/variants/generic_f407v/ld/common.inc | 219 +++++++ .../variants/generic_f407v/ld/extra_libs.inc | 7 + STM32F4/variants/generic_f407v/ld/flash.ld | 20 + STM32F4/variants/generic_f407v/ld/jtag.ld | 20 + STM32F4/variants/generic_f407v/ld/names.inc | 78 +++ STM32F4/variants/generic_f407v/ld/ram.ld | 19 + .../generic_f407v/ld/vector_symbols.inc | 78 +++ STM32F4/variants/generic_f407v/pin_map.c | 210 +++++++ STM32F4/variants/generic_f407v/pins_arduino.h | 6 + STM32F4/variants/generic_f407v/stm32_isrs.S | 323 ++++++++++ .../generic_f407v/stm32_vector_table.S | 113 ++++ STM32F4/variants/generic_f407v/variant.h | 21 + .../generic_f407v/wirish/start.S} | 40 +- .../variants/generic_f407v/wirish/start_c.c | 95 +++ 117 files changed, 2548 insertions(+), 4094 deletions(-) delete mode 100644 STM32F4/cores/maple/Arduino.h delete mode 100644 STM32F4/cores/maple/libmaple/HardwareSPI.cpp delete mode 100644 STM32F4/cores/maple/libmaple/HardwareSPI.h delete mode 100644 STM32F4/cores/maple/libmaple/dmaF1.c delete mode 100644 STM32F4/cores/maple/libmaple/dmaF1.h rename STM32F4/cores/maple/libmaple/{dmaF2.c => dmaF4.c} (91%) rename STM32F4/cores/maple/libmaple/{dmaF2.h => dmaF4.h} (74%) delete mode 100644 STM32F4/cores/maple/libmaple/gpioF1.c delete mode 100644 STM32F4/cores/maple/libmaple/gpioF1.h rename STM32F4/cores/maple/libmaple/{gpioF2.c => gpioF4.c} (78%) rename STM32F4/cores/maple/libmaple/{gpioF2.h => gpio_def.h} (90%) delete mode 100644 STM32F4/cores/maple/libmaple/rccF1.c delete mode 100644 STM32F4/cores/maple/libmaple/rccF1.h rename STM32F4/cores/maple/libmaple/{rccF2.c => rccF4.c} (99%) rename STM32F4/cores/maple/libmaple/{rccF2.h => rccF4.h} (100%) rename STM32F4/{cores/maple/libmaple/gpio.c => system/libmaple/Arduino.h} (79%) create mode 100644 STM32F4/variants/generic_f407v/generic_f407v.cpp create mode 100644 STM32F4/variants/generic_f407v/generic_f407v.h create mode 100644 STM32F4/variants/generic_f407v/ld/common.inc create mode 100644 STM32F4/variants/generic_f407v/ld/extra_libs.inc create mode 100644 STM32F4/variants/generic_f407v/ld/flash.ld create mode 100644 STM32F4/variants/generic_f407v/ld/jtag.ld create mode 100644 STM32F4/variants/generic_f407v/ld/names.inc create mode 100644 STM32F4/variants/generic_f407v/ld/ram.ld create mode 100644 STM32F4/variants/generic_f407v/ld/vector_symbols.inc create mode 100644 STM32F4/variants/generic_f407v/pin_map.c create mode 100644 STM32F4/variants/generic_f407v/pins_arduino.h create mode 100644 STM32F4/variants/generic_f407v/stm32_isrs.S create mode 100644 STM32F4/variants/generic_f407v/stm32_vector_table.S create mode 100644 STM32F4/variants/generic_f407v/variant.h rename STM32F4/{cores/maple/libmaple/rcc.c => variants/generic_f407v/wirish/start.S} (54%) create mode 100644 STM32F4/variants/generic_f407v/wirish/start_c.c diff --git a/STM32F4/boards.txt b/STM32F4/boards.txt index 7577d19..04bfd0f 100644 --- a/STM32F4/boards.txt +++ b/STM32F4/boards.txt @@ -1,5 +1,7 @@ # +menu.usb_cfg=USB configuration + ############################################################## discovery_f407.name=STM32 Discovery F407 @@ -29,6 +31,43 @@ discovery_f407.build.error_led_port=GPIOD discovery_f407.build.error_led_pin=14 discovery_f407.build.board=STM32DiscoveryF407 +############################################################## +generic_f407v.name=Generic STM32F407V series + +generic_f407v.upload.tool=stlink_upload +generic_f407v.upload.protocol=stlink + +generic_f407v.upload.file_type=bin +generic_f407v.upload.ram.maximum_size=131072 +generic_f407v.upload.flash.maximum_size=514288 +generic_f407v.upload.maximum_size=514288 + +#generic_f407v.upload.usbID=0483:3748 +#generic_f407v.upload.altID=1 +#generic_f407v.upload.auto_reset=true + +generic_f407v.build.mcu=cortex-m4 +generic_f407v.build.f_cpu=168000000L +generic_f407v.build.core=maple +generic_f407v.build.extra_flags=-mthumb -DSTM32_HIGH_DENSITY -DSTM32F4 -DBOARD_generic_f407v +generic_f407v.build.ldscript=ld/jtag.ld +generic_f407v.build.variant=generic_f407v +generic_f407v.build.variant_system_lib=lib_f407.a +generic_f407v.build.vect=VECT_TAB_BASE +generic_f407v.build.density=STM32_HIGH_DENSITY +generic_f407v.build.error_led_port=GPIOA +generic_f407v.build.error_led_pin=7 +generic_f407v.build.board=STM32GenericF407VET6 + +generic_f407v.menu.usb_cfg.usb_nc=USB inactive +generic_f407v.menu.usb_cfg.usb_nc.build.cpu_flags=-DUSB_NC + +generic_f407v.menu.usb_cfg.usb_serial=USB serial (CDC) +generic_f407v.menu.usb_cfg.usb_serial.build.cpu_flags=-DSERIAL_USB + +generic_f407v.menu.usb_cfg.usb_msc=USB Mass Storage (MSC) +generic_f407v.menu.usb_cfg.usb_msc.build.cpu_flags=-DUSB_MSC + ############################################################## stm32f4stamp.name=STM32F4Stamp F405 diff --git a/STM32F4/cores/maple/Arduino.h b/STM32F4/cores/maple/Arduino.h deleted file mode 100644 index d02a50c..0000000 --- a/STM32F4/cores/maple/Arduino.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef Arduino_h -#define Arduino_h -#include "WProgram.h" -#endif - -#include "variant.h" diff --git a/STM32F4/cores/maple/Client.h b/STM32F4/cores/maple/Client.h index b8e5d93..57bedb8 100644 --- a/STM32F4/cores/maple/Client.h +++ b/STM32F4/cores/maple/Client.h @@ -17,8 +17,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef client_h -#define client_h +#ifndef _CLIENT_H_ +#define _CLIENT_H_ + #include "Print.h" #include "Stream.h" #include "IPAddress.h" diff --git a/STM32F4/cores/maple/HardwareTimer.h b/STM32F4/cores/maple/HardwareTimer.h index 89e3564..c90356b 100644 --- a/STM32F4/cores/maple/HardwareTimer.h +++ b/STM32F4/cores/maple/HardwareTimer.h @@ -33,7 +33,7 @@ // TODO [0.1.0] Remove deprecated pieces, pick a better API -#include "timer.h" +#include /** Timer mode. */ typedef timer_mode TimerMode; diff --git a/STM32F4/cores/maple/IPAddress.h b/STM32F4/cores/maple/IPAddress.h index 271b240..c6e0697 100644 --- a/STM32F4/cores/maple/IPAddress.h +++ b/STM32F4/cores/maple/IPAddress.h @@ -17,8 +17,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef IPAddress_h -#define IPAddress_h +#ifndef _IPAddress_h_ +#define _IPAddress_h_ #include #include diff --git a/STM32F4/cores/maple/Server.h b/STM32F4/cores/maple/Server.h index 69e3e39..4a95c9f 100644 --- a/STM32F4/cores/maple/Server.h +++ b/STM32F4/cores/maple/Server.h @@ -17,8 +17,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef server_h -#define server_h +#ifndef _SERVER_H_ +#define _SERVER_H_ #include "Print.h" diff --git a/STM32F4/cores/maple/Stream.h b/STM32F4/cores/maple/Stream.h index abdcd17..870fbf0 100644 --- a/STM32F4/cores/maple/Stream.h +++ b/STM32F4/cores/maple/Stream.h @@ -19,8 +19,8 @@ parsing functions based on TextFinder library by Michael Margolis */ -#ifndef Stream_h -#define Stream_h +#ifndef _STREAM_H_ +#define _STREAM_H_ #include #include "Print.h" diff --git a/STM32F4/cores/maple/Udp.h b/STM32F4/cores/maple/Udp.h index dc5644b..1652caf 100644 --- a/STM32F4/cores/maple/Udp.h +++ b/STM32F4/cores/maple/Udp.h @@ -32,8 +32,8 @@ * bjoern@cs.stanford.edu 12/30/2008 */ -#ifndef udp_h -#define udp_h +#ifndef _UDP_H_ +#define _UDP_H_ #include #include diff --git a/STM32F4/cores/maple/WProgram.h b/STM32F4/cores/maple/WProgram.h index 2949a0a..82b759a 100644 --- a/STM32F4/cores/maple/WProgram.h +++ b/STM32F4/cores/maple/WProgram.h @@ -24,7 +24,12 @@ * SOFTWARE. *****************************************************************************/ -#include "wirish.h" +#ifndef _WPROGRAM_H_ +#define _WPROGRAM_H_ + +#include void setup(); void loop(); + +#endif \ No newline at end of file diff --git a/STM32F4/cores/maple/WString.h b/STM32F4/cores/maple/WString.h index 9038578..ec0eae7 100644 --- a/STM32F4/cores/maple/WString.h +++ b/STM32F4/cores/maple/WString.h @@ -19,8 +19,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef String_class_h -#define String_class_h +#ifndef _WSTRING_H_ +#define _WSTRING_H_ + #ifdef __cplusplus #include @@ -225,4 +226,4 @@ public: }; #endif // __cplusplus -#endif // String_class_h +#endif // _WSTRING_H_ diff --git a/STM32F4/cores/maple/bits.h b/STM32F4/cores/maple/bits.h index 3e755b7..3e3eff1 100644 --- a/STM32F4/cores/maple/bits.h +++ b/STM32F4/cores/maple/bits.h @@ -27,4 +27,9 @@ /* Note: Use of this header file is deprecated. Use bit_constants.h instead. */ +#ifndef _BITS_H_ +#define _BITS_H_ + #include "bit_constants.h" + +#endif diff --git a/STM32F4/cores/maple/boards.cpp b/STM32F4/cores/maple/boards.cpp index a856571..0d55e94 100644 --- a/STM32F4/cores/maple/boards.cpp +++ b/STM32F4/cores/maple/boards.cpp @@ -33,17 +33,16 @@ */ #include "boards.h" -#include "flash.h" -#include "rcc.h" -#include "nvic.h" -#include "systick.h" -#include "gpio.h" -#include "adc.h" -#include "timer.h" +#include +#include +#include +#include +#include +#include +#include #include "usb.h" -#ifdef STM32F2 -//#include "usbF4.h" -#endif +#include "usb_serial.h" + static void setupFlash(void); static void setupClocks(void); @@ -59,7 +58,7 @@ void init(void) { systick_init(SYSTICK_RELOAD_VAL); gpio_init_all(); -#ifdef STM32F2 +#ifdef STM32F4 rcc_clk_enable(RCC_SYSCFG); #else afio_init(); @@ -69,7 +68,10 @@ void init(void) { setupADC(); setupTimers(); - //setupUSB(); +#ifdef SERIAL_USB + setupUSB(); + SerialUSB.begin(); +#endif } /* You could farm this out to the files in boards/ if e.g. it takes @@ -84,11 +86,13 @@ bool boardUsesPin(uint8 pin) { } static void setupFlash(void) { +/* #ifndef STM32F2 // for F2 and F4 CPUs this is done in SetupClock...(), e.g. in SetupClock168MHz() flash_enable_prefetch(); flash_set_latency(FLASH_WAIT_STATE_2); #endif +*/ } /* @@ -121,8 +125,8 @@ static void setupNVIC() { static void adcDefaultConfig(const adc_dev* dev); static void setupADC() { -#ifdef STM32F2 - setupADC_F2(); +#ifdef STM32F4 + setupADC_F4(); #else rcc_set_prescaler(RCC_PRESCALER_ADC, RCC_ADCPRE_PCLK_DIV_6); #endif diff --git a/STM32F4/cores/maple/boards.h b/STM32F4/cores/maple/boards.h index 00d07cd..d37bff4 100644 --- a/STM32F4/cores/maple/boards.h +++ b/STM32F4/cores/maple/boards.h @@ -39,11 +39,8 @@ #ifndef _BOARDS_H_ #define _BOARDS_H_ -#include "libmaple.h" -#include "gpio.h" -#include "timer.h" - -#include "wirish_types.h" +#include +#include /* Set of all possible pin names; not all boards have all these (note * that we use the Dx convention since all of the Maple's pins are @@ -55,9 +52,12 @@ enum { D32, D33, D34, D35, D36, D37, D38, D39, D40, D41, D42, D43, D44, D45, D46, D47, D48, D49, D50, D51, D52, D53, D54, D55, D56, D57, D58, D59, D60, D61, D62, D63, D64, D65, D66, D67, D68, D69, D70, D71, D72, D73, D74, D75, D76, +#if 0 // not available on LQFP100 package D77, D78, D79, D80, D81, D82, D83, D84, D85, D86, D87, D88, D89, D90, D91, D92, D93, D94, D95, D96, D97, D98, D99, D100, D101, D102, D103, D104, D105, - D106, D107, D108, D109, D110, D111, }; + D106, D107, D108, D109, D110, D111, +#endif // not available on LQFP100 package +}; /** * @brief Maps each Maple pin to a corresponding stm32_pin_info. @@ -115,31 +115,20 @@ extern void boardInit(void); * @return true if the given pin is in boardUsedPins, and false otherwise. * @see boardUsedPins */ -bool boardUsesPin(uint8 pin); +extern bool boardUsesPin(uint8 pin); /* Include the appropriate private header from boards/: */ /* FIXME HACK put boards/ before these paths once IDE uses make. */ -#ifdef BOARD_maple -#include "maple.h" -#elif defined(BOARD_maple_native) -#include "maple_native.h" -#elif defined(BOARD_maple_mini) -#include "maple_mini.h" -#elif defined(BOARD_maple_RET6) -/* - * **NOT** MAPLE REV6. This the **Maple RET6 EDITION**, which is a - * Maple with an STM32F103RET6 (...RET6) instead of an STM32F103RBT6 - * (...RBT6) on it. Maple Rev6 (as of March 2011) DOES NOT EXIST. - */ -#include "maple_RET6.h" -#elif defined(BOARD_aeroquad32) || defined(BOARD_aeroquad32f1) +#if defined(BOARD_aeroquad32) || defined(BOARD_aeroquad32f1) #include "aeroquad32.h" #elif defined(BOARD_aeroquad32mini) #include "aeroquad32mini.h" #elif defined(BOARD_discovery_f4) #include "discovery_f4.h" +#elif defined(BOARD_generic_f407v) +#include "generic_f407v.h" #elif defined(BOARD_freeflight) #include "freeflight.h" #else @@ -160,4 +149,12 @@ bool boardUsesPin(uint8 pin); #define CLOCK_SPEED_MHZ CYCLES_PER_MICROSECOND #define CLOCK_SPEED_HZ (CLOCK_SPEED_MHZ * 1000000UL) +#ifndef SYSTICK_RELOAD_VAL +#define SYSTICK_RELOAD_VAL (1000 * CYCLES_PER_MICROSECOND - 1) +#endif + +#ifndef BOARD_BUTTON_PRESSED_LEVEL +#define BOARD_BUTTON_PRESSED_LEVEL HIGH +#endif + #endif diff --git a/STM32F4/cores/maple/ext_interrupts.cpp b/STM32F4/cores/maple/ext_interrupts.cpp index f014f13..7111d0c 100644 --- a/STM32F4/cores/maple/ext_interrupts.cpp +++ b/STM32F4/cores/maple/ext_interrupts.cpp @@ -31,8 +31,8 @@ */ #include "boards.h" -#include "gpio.h" -#include "exti.h" +#include +#include #include "ext_interrupts.h" static inline exti_trigger_mode exti_out_mode(ExtIntTriggerMode mode); @@ -51,7 +51,7 @@ void attachInterrupt(uint8 pin, voidFuncPtr handler, ExtIntTriggerMode mode) { exti_trigger_mode outMode = exti_out_mode(mode); - exti_attach_interrupt((afio_exti_num)(PIN_MAP[pin].gpio_bit), + exti_attach_interrupt((afio_exti_num)(pin&0x0F), gpio_exti_port(PIN_MAP[pin].gpio_device), handler, outMode); @@ -66,7 +66,7 @@ void detachInterrupt(uint8 pin) { return; } - exti_detach_interrupt((afio_exti_num)(PIN_MAP[pin].gpio_bit)); + exti_detach_interrupt((afio_exti_num)(pin&0x0F)); } static inline exti_trigger_mode exti_out_mode(ExtIntTriggerMode mode) { diff --git a/STM32F4/cores/maple/ext_interrupts.h b/STM32F4/cores/maple/ext_interrupts.h index b5c6f98..fe215dc 100644 --- a/STM32F4/cores/maple/ext_interrupts.h +++ b/STM32F4/cores/maple/ext_interrupts.h @@ -24,8 +24,8 @@ * SOFTWARE. *****************************************************************************/ -#include "libmaple_types.h" -#include "nvic.h" +#ifndef _EXT_INTERRUPTS_H_ +#define _EXT_INTERRUPTS_H_ /** * @file ext_interrupts.h @@ -33,8 +33,9 @@ * @brief Wiring-like external interrupt prototypes and types. */ -#ifndef _EXT_INTERRUPTS_H_ -#define _EXT_INTERRUPTS_H_ +#include +#include + /** * The kind of transition on an external pin which should trigger an diff --git a/STM32F4/cores/maple/io.h b/STM32F4/cores/maple/io.h index df1ab96..aeaf0fd 100644 --- a/STM32F4/cores/maple/io.h +++ b/STM32F4/cores/maple/io.h @@ -33,8 +33,9 @@ #ifndef _IO_H_ #define _IO_H_ -#include "gpio.h" -#include "adc.h" +#include +#include +#include #include "wirish_time.h" @@ -179,9 +180,11 @@ static inline void toggleLED() { * accomplished portably over all LeafLabs boards by calling * pinMode(BOARD_BUTTON_PIN, INPUT). * + * @param button - one of available on-board buttons (up to 3 for generic F4) + * * @see pinMode() */ -uint8 isButtonPressed(); +uint8 isButtonPressed(uint8_t button); /** * Wait until the button is pressed and released, timing out if no @@ -195,12 +198,14 @@ uint8 isButtonPressed(); * button is pressed. If timeout_millis is left out (or 0), wait * forever. * + * @param button - one of available on-board buttons (up to 3 for generic F4) + * * @return true, if the button was pressed; false, if the timeout was * reached. * * @see pinMode() */ -uint8 waitForButtonPress(uint32 timeout_millis=0); +uint8 waitForButtonPress(uint8_t button, uint32 timeout_millis=0); /** * Shift out a byte of data, one bit at a time. diff --git a/STM32F4/cores/maple/itoa.h b/STM32F4/cores/maple/itoa.h index 59af109..09e8b2f 100644 --- a/STM32F4/cores/maple/itoa.h +++ b/STM32F4/cores/maple/itoa.h @@ -16,8 +16,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef _ITOA_ -#define _ITOA_ +#ifndef _ITOA_H_ +#define _ITOA_H_ #ifdef __cplusplus extern "C"{ diff --git a/STM32F4/cores/maple/libmaple/HardwareSPI.cpp b/STM32F4/cores/maple/libmaple/HardwareSPI.cpp deleted file mode 100644 index a5b4711..0000000 --- a/STM32F4/cores/maple/libmaple/HardwareSPI.cpp +++ /dev/null @@ -1,424 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @author Marti Bolivar - * @brief Wirish SPI implementation. - */ - -#include "HardwareSPI.h" - -#include "timer.h" -#include "util.h" -#include "rcc.h" - -#include "wirish.h" -#include "boards.h" - -struct spi_pins { - uint8 nss; - uint8 sck; - uint8 miso; - uint8 mosi; -}; - -static const spi_pins* dev_to_spi_pins(spi_dev *dev); - -static void enable_device(spi_dev *dev, - bool as_master, - SPIFrequency frequency, - spi_cfg_flag endianness, - spi_mode mode); - -static const spi_pins board_spi_pins[] __FLASH__ = { - {BOARD_SPI1_NSS_PIN, - BOARD_SPI1_SCK_PIN, - BOARD_SPI1_MISO_PIN, - BOARD_SPI1_MOSI_PIN}, -#ifdef BOARD_SPI2_NSS_PIN - {BOARD_SPI2_NSS_PIN, - BOARD_SPI2_SCK_PIN, - BOARD_SPI2_MISO_PIN, - BOARD_SPI2_MOSI_PIN}, -#endif -#ifdef STM32_HIGH_DENSITY - {BOARD_SPI3B_NSS_PIN, - BOARD_SPI3B_SCK_PIN, - BOARD_SPI3B_MISO_PIN, - BOARD_SPI3B_MOSI_PIN}, -#endif -#ifdef STM32F4 - {BOARD_SPI3B_NSS_PIN, - BOARD_SPI3B_SCK_PIN, - BOARD_SPI3B_MISO_PIN, - BOARD_SPI3B_MOSI_PIN}, -#endif -}; - - -/* - * Constructor - */ - -HardwareSPI::HardwareSPI(uint32 spi_num) { - switch (spi_num) { - case 1: - this->spi_d = SPI1; - break; - case 2: - this->spi_d = SPI2; - break; -#ifdef STM32_HIGH_DENSITY - case 3: - this->spi_d = SPI3; - break; -#endif -#ifdef STM32F4 -// case 4: -// this->spi_d = SPI4; -// break; -#endif - default: - ASSERT(0); - } -} - -/* - * Set up/tear down - */ - -void HardwareSPI::begin(SPIFrequency frequency, uint32 bitOrder, uint32 mode) { - if (mode >= 4) { - ASSERT(0); - return; - } - spi_cfg_flag end = bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB; - spi_mode m = (spi_mode)mode; - enable_device(this->spi_d, true, frequency, end, m); -} - -void HardwareSPI::begin(void) { - this->begin(SPI_1_125MHZ, MSBFIRST, 0); -} - -void HardwareSPI::beginSlave(uint32 bitOrder, uint32 mode) { - if (mode >= 4) { - ASSERT(0); - return; - } - spi_cfg_flag end = bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB; - spi_mode m = (spi_mode)mode; - enable_device(this->spi_d, false, (SPIFrequency)0, end, m); -} - -void HardwareSPI::beginSlave(void) { - this->beginSlave(MSBFIRST, 0); -} - - -/* -void HardwareSPI::beginTransaction(uint8_t pin, SPISettings settings) -{ -// this->begin(settings.clock, settings.bitOrder, settings.dataMode); - this->begin(SPI_1_125MHZ, settings.bitOrder, settings.dataMode); -} -*/ - -void HardwareSPI::end(void) { - if (!spi_is_enabled(this->spi_d)) { - return; - } - - // Follows RM0008's sequence for disabling a SPI in master/slave - // full duplex mode. - while (spi_is_rx_nonempty(this->spi_d)) { - // FIXME [0.1.0] remove this once you have an interrupt based driver - volatile uint16 rx __attribute__((unused)) = spi_rx_reg(this->spi_d); - } - while (!spi_is_tx_empty(this->spi_d)) - ; - while (spi_is_busy(this->spi_d)) - ; - spi_peripheral_disable(this->spi_d); -} - -/* - * I/O - */ - -uint8 HardwareSPI::read(void) { - uint8 buf[1]; - this->read(buf, 1); - return buf[0]; -} - -void HardwareSPI::read(uint8 *buf, uint32 len) { - uint32 rxed = 0; - while (rxed < len) { - while (!spi_is_rx_nonempty(this->spi_d)) - ; - buf[rxed++] = (uint8)spi_rx_reg(this->spi_d); - } -} - -#if 0 -void HardwareSPI::readMaster(uint8 *buf, uint32 len) { - uint32 rxed = 0; - while (rxed < len) { - spi_tx_reg(this->spi_d, 0xff); - while (!spi_is_rx_nonempty(this->spi_d)) - ; - buf[rxed++] = (uint8)spi_rx_reg(this->spi_d); - buf[rxed++] = this->spi_d->regs->DR; - } -} -#endif -void HardwareSPI::readMaster(uint8 *buf, uint32 len) { - spi_reg_map *r = this->spi_d->regs; - uint32 rxed = 0; - while (rxed < len) { - r->DR = 0xff; - while (!(r->SR & SPI_SR_RXNE)) - ; - buf[rxed++] = r->DR; - } -} - - -void HardwareSPI::waitReady() { - while (!spi_is_rx_nonempty(this->spi_d)) - ; -} - -void HardwareSPI::write(uint8 byte) { - this->write(&byte, 1); -} - -void HardwareSPI::write(const uint8 *data, uint32 length) { - uint32 txed = 0; - while (txed < length) { - txed += spi_tx(this->spi_d, data + txed, length - txed); - } -} - -uint8 HardwareSPI::transfer(uint8 byte) { - this->write(byte); - return this->read(); -} - -/* - * Pin accessors - */ - -uint8 HardwareSPI::misoPin(void) { - return dev_to_spi_pins(this->spi_d)->miso; -} - -uint8 HardwareSPI::mosiPin(void) { - return dev_to_spi_pins(this->spi_d)->mosi; -} - -uint8 HardwareSPI::sckPin(void) { - return dev_to_spi_pins(this->spi_d)->sck; -} - -uint8 HardwareSPI::nssPin(void) { - return dev_to_spi_pins(this->spi_d)->nss; -} - -/* - * Deprecated functions - */ - -uint8 HardwareSPI::send(uint8 data) { - uint8 buf[] = {data}; - return this->send(buf, 1); -} - -#if 1 -uint8 HardwareSPI::send(const uint8 *buf, uint32 len) { - uint32 txed = 0; - uint8 ret = 0; - while (txed < len) { - this->write(buf[txed++]); - ret = this->read(); - } - return ret; -} -#else -// this does not work for an unknown reason -uint8 HardwareSPI::send(const uint8 *buf, uint32 len) { - volatile uint32 *dr = &(this->spi_d->regs->DR); - volatile uint32 *sr = &(this->spi_d->regs->SR); - uint32 txed = 0; - uint32 rx=0; - while (txed < len) { - //while (!(*sr & SPI_SR_TXE)) - // ; - //*dr = buf[txed++]; - this->write(buf[txed++]); - - while (!(*sr & SPI_SR_RXNE)) - ; - rx = *dr; - //rx = this->read(); - } - - return rx; -} -#endif - -uint8 HardwareSPI::recv(void) { - return this->read(); -} - -/* - * Auxiliary functions - */ - -static void configure_gpios(spi_dev *dev, bool as_master); -static spi_baud_rate determine_baud_rate(spi_dev *dev, SPIFrequency freq); - -static const spi_pins* dev_to_spi_pins(spi_dev *dev) { - switch (dev->clk_id) { - case RCC_SPI1: return board_spi_pins; - case RCC_SPI2: return board_spi_pins + 1; -#ifdef STM32_HIGH_DENSITY - case RCC_SPI3: return board_spi_pins + 2; -#endif -#ifdef STM32F4 - case RCC_SPI4: return board_spi_pins + 3; -#endif - default: return NULL; - } -} - -/* Enables the device in master or slave full duplex mode. If you - * change this code, you must ensure that appropriate changes are made - * to HardwareSPI::end(). */ -static void enable_device(spi_dev *dev, - bool as_master, - SPIFrequency freq, - spi_cfg_flag endianness, - spi_mode mode) { - spi_baud_rate baud = determine_baud_rate(dev, freq); - uint32 cfg_flags = (endianness | SPI_DFF_8_BIT | SPI_SW_SLAVE | - (as_master ? SPI_SOFT_SS : 0)); - - spi_init(dev); - configure_gpios(dev, as_master); - if (as_master) { - spi_master_enable(dev, baud, mode, cfg_flags); - } else { - spi_slave_enable(dev, mode, cfg_flags); - } -} - -static void disable_pwm(const stm32_pin_info *i) { - if (i->timer_device) { - timer_set_mode(i->timer_device, i->timer_channel, TIMER_DISABLED); - } -} - -static void configure_gpios(spi_dev *dev, bool as_master) { - const spi_pins *pins = dev_to_spi_pins(dev); - - if (!pins) { - return; - } - - const stm32_pin_info *nssi = (pins->nss >= 0) ? &PIN_MAP[pins->nss] : NULL; - const stm32_pin_info *scki = &PIN_MAP[pins->sck]; - const stm32_pin_info *misoi = &PIN_MAP[pins->miso]; - const stm32_pin_info *mosii = &PIN_MAP[pins->mosi]; - - if(nssi) { - disable_pwm(nssi); - } - disable_pwm(scki); - disable_pwm(misoi); - disable_pwm(mosii); - -#ifdef STM32F4 - if(dev->clk_id <= RCC_SPI2) { - if(nssi) { - if(!as_master) { - gpio_set_af_mode(nssi->gpio_device, scki->gpio_bit, 5); - } - } - gpio_set_af_mode(scki->gpio_device, scki->gpio_bit, 5); - gpio_set_af_mode(misoi->gpio_device, misoi->gpio_bit, 5); - gpio_set_af_mode(mosii->gpio_device, mosii->gpio_bit, 5); - } else { - if(nssi) { - if(!as_master) { - gpio_set_af_mode(nssi->gpio_device, scki->gpio_bit, 6); - } - } - gpio_set_af_mode(scki->gpio_device, scki->gpio_bit, 6); - gpio_set_af_mode(misoi->gpio_device, misoi->gpio_bit, 6); - gpio_set_af_mode(mosii->gpio_device, mosii->gpio_bit, 6); - } -#endif - - if(nssi) { - spi_config_gpios(dev, as_master, nssi->gpio_device, nssi->gpio_bit, - scki->gpio_device, scki->gpio_bit, - misoi->gpio_device, misoi->gpio_bit, - mosii->gpio_device, mosii->gpio_bit); - } else { - spi_config_gpios(dev, as_master, NULL, -1, - scki->gpio_device, scki->gpio_bit, - misoi->gpio_device, misoi->gpio_bit, - mosii->gpio_device, mosii->gpio_bit); - } -} - -static const spi_baud_rate baud_rates[MAX_SPI_FREQS] __FLASH__ = { - SPI_BAUD_PCLK_DIV_2, - SPI_BAUD_PCLK_DIV_4, - SPI_BAUD_PCLK_DIV_8, - SPI_BAUD_PCLK_DIV_16, - SPI_BAUD_PCLK_DIV_32, - SPI_BAUD_PCLK_DIV_64, - SPI_BAUD_PCLK_DIV_128, - SPI_BAUD_PCLK_DIV_256, -}; - -/* - * Note: This assumes you're on a LeafLabs-style board - * (CYCLES_PER_MICROSECOND == 72, APB2 at 72MHz, APB1 at 36MHz). - */ -static spi_baud_rate determine_baud_rate(spi_dev *dev, SPIFrequency freq) { - if (rcc_dev_clk(dev->clk_id) == RCC_APB2 && freq == SPI_140_625KHZ) { - /* APB2 peripherals are too fast for 140.625 KHz */ - ASSERT(0); - return (spi_baud_rate)~0; - } - return (rcc_dev_clk(dev->clk_id) == RCC_APB2 ? - baud_rates[freq + 1] : - baud_rates[freq]); -} diff --git a/STM32F4/cores/maple/libmaple/HardwareSPI.h b/STM32F4/cores/maple/libmaple/HardwareSPI.h deleted file mode 100644 index 327f29d..0000000 --- a/STM32F4/cores/maple/libmaple/HardwareSPI.h +++ /dev/null @@ -1,279 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file HardwareSPI.h - * @brief High-level SPI interface - * - * This is a "bare essentials" polling driver for now. - */ - -/* TODO [0.1.0] Remove deprecated methods. */ - -#include "libmaple_types.h" -#include "spi.h" - -#include "boards.h" -#include "wirish.h" - -#ifndef _HARDWARESPI_H_ -#define _HARDWARESPI_H_ - -/** - * @brief Defines the possible SPI communication speeds. - */ -typedef enum SPIFrequency { - SPI_18MHZ = 0, /**< 18 MHz */ - SPI_9MHZ = 1, /**< 9 MHz */ - SPI_4_5MHZ = 2, /**< 4.5 MHz */ - SPI_2_25MHZ = 3, /**< 2.25 MHz */ - SPI_1_125MHZ = 4, /**< 1.125 MHz */ - SPI_562_500KHZ = 5, /**< 562.500 KHz */ - SPI_281_250KHZ = 6, /**< 281.250 KHz */ - SPI_140_625KHZ = 7, /**< 140.625 KHz */ -} SPIFrequency; - -#define MAX_SPI_FREQS 8 - -#if CYCLES_PER_MICROSECOND != 72 -/* TODO [0.2.0?] something smarter than this */ -//#warning "Unexpected clock speed; SPI frequency calculation will be incorrect" -#endif - - -//#define BOARD_SPI_DEFAULT_SS PC13 -#define BOARD_SPI_DEFAULT_SS PB0 -#define SPI_MODE0 SPI_MODE_0 -#define SPI_MODE1 SPI_MODE_1 -#define SPI_MODE2 SPI_MODE_2 -#define SPI_MODE3 SPI_MODE_3 - -/* -class SPISettings { -public: - SPISettings(uint32 clock, BitOrder bitOrder, uint8 dataMode) { - if (__builtin_constant_p(clock)) { - init_AlwaysInline(clock, bitOrder, dataMode); - } else { - init_MightInline(clock, bitOrder, dataMode); - } - } - SPISettings() { init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0); } -private: - void init_MightInline(uint32 clock, BitOrder bitOrder, uint8 dataMode) { - init_AlwaysInline(clock, bitOrder, dataMode); - } - void init_AlwaysInline(uint32 clock, BitOrder bitOrder, uint8 dataMode) __attribute__((__always_inline__)) { - this->clock = clock; - this->bitOrder = bitOrder; - this->dataMode = dataMode; - } - uint32 clock; - BitOrder bitOrder; - uint8 dataMode; - friend class HardwareSPI; -}; -*/ - - -/** - * @brief Wirish SPI interface. - * - * This implementation uses software slave management, so the caller - * is responsible for controlling the slave select line. - */ -class HardwareSPI { -public: - /** - * @param spiPortNumber Number of the SPI port to manage. - */ - HardwareSPI(uint32 spiPortNumber); - - /* - * Set up/tear down - */ - - /** - * @brief Turn on a SPI port and set its GPIO pin modes for use as master. - * - * SPI port is enabled in full duplex mode, with software slave management. - * - * @param frequency Communication frequency - * @param bitOrder Either LSBFIRST (little-endian) or MSBFIRST (big-endian) - * @param mode SPI mode to use, one of SPI_MODE_0, SPI_MODE_1, - * SPI_MODE_2, and SPI_MODE_3. - */ - void begin(SPIFrequency frequency, uint32 bitOrder, uint32 mode); - - /** - * @brief Equivalent to begin(SPI_1_125MHZ, MSBFIRST, 0). - */ - void begin(void); - - /** - * @brief Turn on a SPI port and set its GPIO pin modes for use as a slave. - * - * SPI port is enabled in full duplex mode, with software slave management. - * - * @param bitOrder Either LSBFIRST (little-endian) or MSBFIRST(big-endian) - * @param mode SPI mode to use - */ - void beginSlave(uint32 bitOrder, uint32 mode); - - /** - * @brief Equivalent to beginSlave(MSBFIRST, 0). - */ - void beginSlave(void); - - /** - * @brief Disables the SPI port, but leaves its GPIO pin modes unchanged. - */ - void end(void); - - /* - * I/O - */ - - /** - * @brief Return the next unread byte. - * - * If there is no unread byte waiting, this function will block - * until one is received. - */ - uint8 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 - * function will block until the desired number of - * bytes have been read. - */ - void read(uint8 *buffer, uint32 length); - - /** - * @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 - * function will block until the desired number of - * bytes have been read. - */ - void readMaster(uint8 *buffer, uint32 length); - - - void waitReady(); - /** - * @brief Transmit a byte. - * @param data Byte to transmit. - */ - void write(uint8 data); - - /** - * @brief Transmit multiple bytes. - * @param buffer Bytes to transmit. - * @param length Number of bytes in buffer to transmit. - */ - void write(const uint8 *buffer, uint32 length); - - /** - * @brief Transmit a byte, then return the next unread byte. - * - * This function transmits before receiving. - * - * @param data Byte to transmit. - * @return Next unread byte. - */ - uint8 transfer(uint8 data); - - /* - * Pin accessors - */ - - /** - * @brief Return the number of the MISO (master in, slave out) pin - */ - uint8 misoPin(void); - - /** - * @brief Return the number of the MOSI (master out, slave in) pin - */ - uint8 mosiPin(void); - - /** - * @brief Return the number of the SCK (serial clock) pin - */ - uint8 sckPin(void); - - /** - * @brief Return the number of the NSS (slave select) pin - */ - uint8 nssPin(void); - - /* -- The following methods are deprecated --------------------------- */ - - /** - * @brief Deprecated. - * - * Use HardwareSPI::transfer() instead. - * - * @see HardwareSPI::transfer() - */ - uint8 send(uint8 data); - - /** - * @brief Deprecated. - * - * Use HardwareSPI::write() in combination with - * HardwareSPI::read() (or HardwareSPI::transfer()) instead. - * - * @see HardwareSPI::write() - * @see HardwareSPI::read() - * @see HardwareSPI::transfer() - */ - uint8 send(const uint8 *data, uint32 length); - - /** - * @brief Deprecated. - * - * Use HardwareSPI::read() instead. - * - * @see HardwareSPI::read() - */ - uint8 recv(void); - -// void beginTransaction(SPISettings settings) { beginTransaction(BOARD_SPI_DEFAULT_SS, settings); } -// void beginTransaction(uint8 pin, SPISettings settings); - void endTransaction(void) { } - -private: - spi_dev *spi_d; -}; - - -extern HardwareSPI SPI; - -#endif - diff --git a/STM32F4/cores/maple/libmaple/HardwareSerial.cpp b/STM32F4/cores/maple/libmaple/HardwareSerial.cpp index 59ce71d..f9387d1 100644 --- a/STM32F4/cores/maple/libmaple/HardwareSerial.cpp +++ b/STM32F4/cores/maple/libmaple/HardwareSerial.cpp @@ -56,19 +56,19 @@ #define RX5 BOARD_UART5_RX_PIN #endif -HardwareSerial Serial(USART1, TX1, RX1); +HardwareSerial Serial1(USART1, TX1, RX1); #ifdef TX2 -HardwareSerial Serial1(USART2, TX2, RX2); +HardwareSerial Serial2(USART2, TX2, RX2); #endif #ifdef TX3 -HardwareSerial Serial2(USART3, TX3, RX3); +HardwareSerial Serial3(USART3, TX3, RX3); #endif #if defined(STM32_HIGH_DENSITY) && !defined(BOARD_maple_RET6) -HardwareSerial Serial3(UART4, TX4, RX4); -HardwareSerial Serial4(UART5, TX5, RX5); +HardwareSerial Serial4(UART4, TX4, RX4); +HardwareSerial Serial5(UART5, TX5, RX5); #endif HardwareSerial::HardwareSerial(usart_dev *usart_device, @@ -90,25 +90,23 @@ void HardwareSerial::begin(uint32 baud) { return; } - const stm32_pin_info *txi = &PIN_MAP[tx_pin]; - const stm32_pin_info *rxi = &PIN_MAP[rx_pin]; -#ifdef STM32F2 +#ifdef STM32F4 // int af = 7<<8; if (usart_device == UART4 || usart_device == UART5) { - gpio_set_af_mode(txi->gpio_device, txi->gpio_bit, 8); - gpio_set_af_mode(rxi->gpio_device, rxi->gpio_bit, 8); + gpio_set_af_mode(tx_pin, 8); + gpio_set_af_mode(rx_pin, 8); } else { - gpio_set_af_mode(txi->gpio_device, txi->gpio_bit, 7); - gpio_set_af_mode(rxi->gpio_device, rxi->gpio_bit, 7); + gpio_set_af_mode(tx_pin, 7); + gpio_set_af_mode(rx_pin, 7); } - gpio_set_mode(txi->gpio_device, txi->gpio_bit, (gpio_pin_mode)(GPIO_AF_OUTPUT_PP | GPIO_PUPD_INPUT_PU | 0x700)); - gpio_set_mode(rxi->gpio_device, rxi->gpio_bit, (gpio_pin_mode)(GPIO_MODE_AF | GPIO_PUPD_INPUT_PU | 0x700)); + gpio_set_mode(tx_pin, (gpio_pin_mode)(GPIO_AF_OUTPUT_PP | GPIO_PUPD_INPUT_PU | 0x700)); + gpio_set_mode(rx_pin, (gpio_pin_mode)(GPIO_MODE_AF | GPIO_PUPD_INPUT_PU | 0x700)); //gpio_set_mode(txi->gpio_device, txi->gpio_bit, (gpio_pin_mode)(GPIO_PUPD_INPUT_PU)); //gpio_set_mode(rxi->gpio_device, rxi->gpio_bit, (gpio_pin_mode)(GPIO_PUPD_INPUT_PU)); #else - gpio_set_mode(txi->gpio_device, txi->gpio_bit, GPIO_AF_OUTPUT_PP); - gpio_set_mode(rxi->gpio_device, rxi->gpio_bit, GPIO_INPUT_FLOATING); + gpio_set_mode(tx_pin, GPIO_AF_OUTPUT_PP); + gpio_set_mode(rx_pin, GPIO_INPUT_FLOATING); #endif #if 0 if (txi->timer_device != NULL) { diff --git a/STM32F4/cores/maple/libmaple/HardwareSerial.h b/STM32F4/cores/maple/libmaple/HardwareSerial.h index c09fe54..d7e8a3d 100644 --- a/STM32F4/cores/maple/libmaple/HardwareSerial.h +++ b/STM32F4/cores/maple/libmaple/HardwareSerial.h @@ -75,12 +75,12 @@ private: uint8 rx_pin; }; -extern HardwareSerial Serial; extern HardwareSerial Serial1; extern HardwareSerial Serial2; #if defined(STM32_HIGH_DENSITY) && !defined(BOARD_maple_RET6) extern HardwareSerial Serial3; extern HardwareSerial Serial4; +extern HardwareSerial Serial5; #endif extern HardwareSerial &SerialDebug; #endif diff --git a/STM32F4/cores/maple/libmaple/adc.c b/STM32F4/cores/maple/libmaple/adc.c index aeeb43c..0f4c02c 100644 --- a/STM32F4/cores/maple/libmaple/adc.c +++ b/STM32F4/cores/maple/libmaple/adc.c @@ -41,27 +41,24 @@ #include "rcc.h" #include "adc.h" -static adc_dev adc1 = { +/** ADC1 device. */ +const adc_dev ADC1 = { .regs = ADC1_BASE, .clk_id = RCC_ADC1 }; -/** ADC1 device. */ -const adc_dev *ADC1 = &adc1; -static adc_dev adc2 = { +/** ADC2 device. */ +const adc_dev ADC2 = { .regs = ADC2_BASE, .clk_id = RCC_ADC2 }; -/** ADC2 device. */ -const adc_dev *ADC2 = &adc2; #ifdef STM32_HIGH_DENSITY -adc_dev adc3 = { +/** ADC3 device. */ +const adc_dev ADC3 = { .regs = ADC3_BASE, .clk_id = RCC_ADC3 }; -/** ADC3 device. */ -const adc_dev *ADC3 = &adc3; #endif /** @@ -74,7 +71,7 @@ const adc_dev *ADC3 = &adc3; */ void adc_init(const adc_dev *dev) { rcc_clk_enable(dev->clk_id); -#ifdef STM32F2 +#ifdef STM32F4 if(dev->clk_id == RCC_ADC1) { rcc_reset_dev(dev->clk_id); } @@ -101,10 +98,10 @@ void adc_set_extsel(const adc_dev *dev, adc_extsel_event event) { * @param fn Function to call on each ADC device. */ void adc_foreach(void (*fn)(const adc_dev*)) { - fn(ADC1); - fn(ADC2); + fn(&ADC1); + fn(&ADC2); #ifdef STM32_HIGH_DENSITY - fn(ADC3); + fn(&ADC3); #endif } @@ -136,7 +133,9 @@ void adc_set_sample_rate(const adc_dev *dev, adc_smp_rate smp_rate) { * @brief Calibrate an ADC peripheral * @param dev adc device */ -void adc_calibrate(const adc_dev *dev) { +void adc_calibrate(const adc_dev *dev) +{ +/* #ifndef STM32F2 __io uint32 *rstcal_bit = bb_perip(&(dev->regs->CR2), 3); __io uint32 *cal_bit = bb_perip(&(dev->regs->CR2), 2); @@ -149,6 +148,7 @@ void adc_calibrate(const adc_dev *dev) { while (*cal_bit) ; #endif +*/ } /** @@ -171,8 +171,8 @@ uint16 adc_read(const adc_dev *dev, uint8 channel) { return (uint16)(regs->DR & ADC_DR_DATA); } -void setupADC_F2() { -#ifdef STM32F2 +void setupADC_F4(void) +{ uint32 tmpreg1 = 0; tmpreg1 = ADC_COMMON->CCR; @@ -196,5 +196,4 @@ void setupADC_F2() { /* Write to ADC CCR */ ADC_COMMON->CCR = tmpreg1; -#endif } diff --git a/STM32F4/cores/maple/libmaple/adc.h b/STM32F4/cores/maple/libmaple/adc.h index 3a40d4c..6fa61f5 100644 --- a/STM32F4/cores/maple/libmaple/adc.h +++ b/STM32F4/cores/maple/libmaple/adc.h @@ -42,17 +42,15 @@ extern "C"{ #endif -#ifdef STM32F2 - typedef struct - { - __io uint32 CSR; /*!< ADC Common status register, Address offset: ADC1 base address + 0x300 */ - __io uint32 CCR; /*!< ADC common control register, Address offset: ADC1 base address + 0x304 */ - __io uint32 CDR; /*!< ADC common regular data register for dual - AND triple modes, Address offset: ADC1 base address + 0x308 */ - } ADC_Common_TypeDef; +typedef struct +{ + __io uint32 CSR; /*!< ADC Common status register, Address offset: ADC1 base address + 0x300 */ + __io uint32 CCR; /*!< ADC common control register, Address offset: ADC1 base address + 0x304 */ + __io uint32 CDR; /*!< ADC common regular data register for dual + AND triple modes, Address offset: ADC1 base address + 0x308 */ +} ADC_Common_TypeDef; #define ADC_COMMON ((ADC_Common_TypeDef *) 0x40012300) -#endif /** ADC register map type. */ typedef struct adc_reg_map { @@ -84,33 +82,22 @@ typedef struct adc_dev { rcc_clk_id clk_id; /**< RCC clock information */ } adc_dev; -extern const adc_dev *ADC1; -extern const adc_dev *ADC2; +extern const adc_dev ADC1; +extern const adc_dev ADC2; #ifdef STM32_HIGH_DENSITY -extern const adc_dev *ADC3; +extern const adc_dev ADC3; #endif /* * Register map base pointers */ -#ifdef STM32F2 - /** ADC1 register map base pointer. */ - #define ADC1_BASE ((struct adc_reg_map*)0x40012000) - /** ADC2 register map base pointer. */ - #define ADC2_BASE ((struct adc_reg_map*)0x40012100) - /** ADC3 register map base pointer. */ - #define ADC3_BASE ((struct adc_reg_map*)0x40012200) -#else - /** ADC1 register map base pointer. */ - #define ADC1_BASE ((struct adc_reg_map*)0x40012400) - /** ADC2 register map base pointer. */ - #define ADC2_BASE ((struct adc_reg_map*)0x40012800) - #ifdef STM32_HIGH_DENSITY - /** ADC3 register map base pointer. */ - #define ADC3_BASE ((struct adc_reg_map*)0x40013C00) - #endif -#endif +/** ADC1 register map base pointer. */ +#define ADC1_BASE ((struct adc_reg_map*)0x40012000) +/** ADC2 register map base pointer. */ +#define ADC2_BASE ((struct adc_reg_map*)0x40012100) +/** ADC3 register map base pointer. */ +#define ADC3_BASE ((struct adc_reg_map*)0x40012200) /* * Register bit definitions @@ -167,17 +154,10 @@ extern const adc_dev *ADC3; #define ADC_CR2_JEXTTRIG_BIT 15 #define ADC_CR2_EXTTRIG_BIT 20 #define ADC_CR2_TSEREFE_BIT 23 -#ifdef STM32F2 #define ADC_CR2_JSWSTART_BIT 22 #define ADC_CR2_SWSTART_BIT 30 #define ADC_CR2_EXTSEL (0x0F000000) #define ADC_CR2_JEXTSEL (0x000F0000) -#else -#define ADC_CR2_JSWSTART_BIT 21 -#define ADC_CR2_SWSTART_BIT 22 -#define ADC_CR2_EXTSEL (0x000E0000) -#define ADC_CR2_JEXTSEL (0x00007000) -#endif @@ -388,7 +368,7 @@ static inline void adc_disable_all(void) { adc_foreach(adc_disable); } -void setupADC_F2(); +extern void setupADC_F4(void); #ifdef __cplusplus } // extern "C" diff --git a/STM32F4/cores/maple/libmaple/dac.c b/STM32F4/cores/maple/libmaple/dac.c index 264e4e2..3853f90 100644 --- a/STM32F4/cores/maple/libmaple/dac.c +++ b/STM32F4/cores/maple/libmaple/dac.c @@ -126,11 +126,11 @@ void dac_enable_channel(const dac_dev *dev, uint8 channel) { */ switch (channel) { case 1: - gpio_set_mode(GPIOA, 4, GPIO_INPUT_ANALOG); + gpio_set_mode((uint8_t)PA4, GPIO_INPUT_ANALOG); dev->regs->CR |= DAC_CR_EN1; break; case 2: - gpio_set_mode(GPIOA, 5, GPIO_INPUT_ANALOG); + gpio_set_mode((uint8_t)PA5, GPIO_INPUT_ANALOG); dev->regs->CR |= DAC_CR_EN2; break; } diff --git a/STM32F4/cores/maple/libmaple/dma.h b/STM32F4/cores/maple/libmaple/dma.h index a965c03..420adf8 100644 --- a/STM32F4/cores/maple/libmaple/dma.h +++ b/STM32F4/cores/maple/libmaple/dma.h @@ -30,9 +30,4 @@ * @brief Direct Memory Access peripheral support */ -#ifdef STM32F2 -#include "dmaF2.h" -#include -#else -#include "dmaF1.h" -#endif +#include "dmaF4.h" diff --git a/STM32F4/cores/maple/libmaple/dmaF1.c b/STM32F4/cores/maple/libmaple/dmaF1.c deleted file mode 100644 index f8ddb2d..0000000 --- a/STM32F4/cores/maple/libmaple/dmaF1.c +++ /dev/null @@ -1,383 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Michael Hope. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -#ifdef STM32F1 - -/** - * @file dma.c - * @author Marti Bolivar ; - * Original implementation by Michael Hope - * @brief Direct Memory Access peripheral support - */ - -#include "dma.h" -#include "bitband.h" -#include "util.h" - -/* - * Devices - */ - -static dma_dev dma1 = { - .regs = DMA1_BASE, - .clk_id = RCC_DMA1, - .handlers = {{ .handler = NULL, .irq_line = NVIC_DMA_CH1 }, - { .handler = NULL, .irq_line = NVIC_DMA_CH2 }, - { .handler = NULL, .irq_line = NVIC_DMA_CH3 }, - { .handler = NULL, .irq_line = NVIC_DMA_CH4 }, - { .handler = NULL, .irq_line = NVIC_DMA_CH5 }, - { .handler = NULL, .irq_line = NVIC_DMA_CH6 }, - { .handler = NULL, .irq_line = NVIC_DMA_CH7 }} -}; -/** DMA1 device */ -dma_dev *DMA1 = &dma1; - -#ifdef STM32_HIGH_DENSITY -static dma_dev dma2 = { - .regs = DMA2_BASE, - .clk_id = RCC_DMA2, - .handlers = {{ .handler = NULL, .irq_line = NVIC_DMA2_CH1 }, - { .handler = NULL, .irq_line = NVIC_DMA2_CH2 }, - { .handler = NULL, .irq_line = NVIC_DMA2_CH3 }, - { .handler = NULL, .irq_line = NVIC_DMA2_CH_4_5 }, - { .handler = NULL, .irq_line = NVIC_DMA2_CH_4_5 }} /* !@#$ */ -}; -/** DMA2 device */ -dma_dev *DMA2 = &dma2; -#endif - -/* - * Convenience routines - */ - -/** - * @brief Initialize a DMA device. - * @param dev Device to initialize. - */ -void dma_init(dma_dev *dev) { - rcc_clk_enable(dev->clk_id); -} - -/** - * @brief Set up a DMA transfer. - * - * The channel will be disabled before being reconfigured. The - * transfer will have low priority by default. You may choose another - * priority before the transfer begins using dma_set_priority(), as - * well as performing any other configuration you desire. When the - * channel is configured to your liking, enable it using dma_enable(). - * - * @param dev DMA device. - * @param channel DMA channel. - * @param peripheral_address Base address of peripheral data register - * involved in the transfer. - * @param peripheral_size Peripheral data transfer size. - * @param memory_address Base memory address involved in the transfer. - * @param memory_size Memory data transfer size. - * @param mode Logical OR of dma_mode_flags - * @sideeffect Disables the given DMA channel. - * @see dma_xfer_size - * @see dma_mode_flags - * @see dma_set_num_transfers() - * @see dma_set_priority() - * @see dma_attach_interrupt() - * @see dma_enable() - */ -void dma_setup_transfer(dma_dev *dev, - dma_channel channel, - __io void *peripheral_address, - dma_xfer_size peripheral_size, - __io void *memory_address, - dma_xfer_size memory_size, - uint32 mode) { - dma_channel_reg_map *channel_regs = dma_channel_regs(dev, channel); - - dma_disable(dev, channel); /* can't write to CMAR/CPAR otherwise */ - channel_regs->CCR = (memory_size << 10) | (peripheral_size << 8) | mode; - channel_regs->CMAR = (uint32)memory_address; - channel_regs->CPAR = (uint32)peripheral_address; -} - -/** - * @brief Set the number of data to be transferred on a DMA channel. - * - * You may not call this function while the channel is enabled. - * - * @param dev DMA device - * @param channel Channel through which the transfer occurs. - * @param num_transfers - */ -void dma_set_num_transfers(dma_dev *dev, - dma_channel channel, - uint16 num_transfers) { - dma_channel_reg_map *channel_regs; - - ASSERT_FAULT(!dma_is_channel_enabled(dev, channel)); - - channel_regs = dma_channel_regs(dev, channel); - channel_regs->CNDTR = num_transfers; -} - -/** - * @brief Set the priority of a DMA transfer. - * - * You may not call this function while the channel is enabled. - * - * @param dev DMA device - * @param channel DMA channel - * @param priority priority to set. - */ -void dma_set_priority(dma_dev *dev, - dma_channel channel, - dma_priority priority) { - dma_channel_reg_map *channel_regs; - uint32 ccr; - - ASSERT_FAULT(!dma_is_channel_enabled(dev, channel)); - - channel_regs = dma_channel_regs(dev, channel); - ccr = channel_regs->CCR; - ccr &= ~DMA_CCR_PL; - ccr |= priority; - channel_regs->CCR = ccr; -} - -/** - * @brief Attach an interrupt to a DMA transfer. - * - * Interrupts are enabled using appropriate mode flags in - * dma_setup_transfer(). - * - * @param dev DMA device - * @param channel Channel to attach handler to - * @param handler Interrupt handler to call when channel interrupt fires. - * @see dma_setup_transfer() - * @see dma_get_irq_cause() - * @see dma_detach_interrupt() - */ -void dma_attach_interrupt(dma_dev *dev, - dma_channel channel, - void (*handler)(void)) { - dev->handlers[channel - 1].handler = handler; - nvic_irq_enable(dev->handlers[channel - 1].irq_line); -} - -/** - * @brief Detach a DMA transfer interrupt handler. - * - * After calling this function, the given channel's interrupts will be - * disabled. - * - * @param dev DMA device - * @param channel Channel whose handler to detach - * @sideeffect Clears interrupt enable bits in the channel's CCR register. - * @see dma_attach_interrupt() - */ -void dma_detach_interrupt(dma_dev *dev, dma_channel channel) { - /* Don't use nvic_irq_disable()! Think about DMA2 channels 4 and 5. */ - dma_channel_regs(dev, channel)->CCR &= ~0xF; - dev->handlers[channel - 1].handler = NULL; -} - -/** - * @brief Discover the reason why a DMA interrupt was called. - * - * You may only call this function within an attached interrupt - * handler for the given channel. - * - * This function resets the internal DMA register state which encodes - * the cause of the interrupt; consequently, it can only be called - * once per interrupt handler invocation. - * - * @param dev DMA device - * @param channel Channel whose interrupt is being handled. - * @return Reason why the interrupt fired. - * @sideeffect Clears channel status flags in dev->regs->ISR. - * @see dma_attach_interrupt() - * @see dma_irq_cause - */ -dma_irq_cause dma_get_irq_cause(dma_dev *dev, dma_channel channel) { - uint8 status_bits = dma_get_isr_bits(dev, channel); - - /* If the channel global interrupt flag is cleared, then - * something's very wrong. */ - ASSERT(status_bits & BIT(0)); - - dma_clear_isr_bits(dev, channel); - - /* ISR flags get set even if the corresponding interrupt enable - * bits in the channel's configuration register are cleared, so we - * can't use a switch here. - * - * Don't change the order of these if statements. */ - if (status_bits & BIT(3)) { - return DMA_TRANSFER_ERROR; - } else if (status_bits & BIT(1)) { - return DMA_TRANSFER_COMPLETE; - } else if (status_bits & BIT(2)) { - return DMA_TRANSFER_HALF_COMPLETE; - } else if (status_bits & BIT(0)) { - /* Shouldn't happen (unless someone messed up an IFCR write). */ - throb(); - } -#if DEBUG_LEVEL < DEBUG_ALL - else { - /* We shouldn't have been called, but the debug level is too - * low for the above ASSERT() to have had any effect. In - * order to fail fast, mimic the DMA controller's behavior - * when an error occurs. */ - dma_disable(dev, channel); - } -#endif - return DMA_TRANSFER_ERROR; -} - -/** - * @brief Enable a DMA channel. - * @param dev DMA device - * @param channel Channel to enable - */ -void dma_enable(dma_dev *dev, dma_channel channel) { - dma_channel_reg_map *chan_regs = dma_channel_regs(dev, channel); - bb_peri_set_bit(&chan_regs->CCR, DMA_CCR_EN_BIT, 1); -} - -/** - * @brief Disable a DMA channel. - * @param dev DMA device - * @param channel Channel to disable - */ -void dma_disable(dma_dev *dev, dma_channel channel) { - dma_channel_reg_map *chan_regs = dma_channel_regs(dev, channel); - bb_peri_set_bit(&chan_regs->CCR, DMA_CCR_EN_BIT, 0); -} - -/** - * @brief Set the base memory address where data will be read from or - * written to. - * - * You must not call this function while the channel is enabled. - * - * If the DMA memory size is 16 bits, the address is automatically - * aligned to a half-word. If the DMA memory size is 32 bits, the - * address is aligned to a word. - * - * @param dev DMA Device - * @param channel Channel whose base memory address to set. - * @param addr Memory base address to use. - */ -void dma_set_mem_addr(dma_dev *dev, dma_channel channel, __io void *addr) { - dma_channel_reg_map *chan_regs; - - ASSERT_FAULT(!dma_is_channel_enabled(dev, channel)); - - chan_regs = dma_channel_regs(dev, channel); - chan_regs->CMAR = (uint32)addr; -} - -/** - * @brief Set the base peripheral address where data will be read from - * or written to. - * - * You must not call this function while the channel is enabled. - * - * If the DMA peripheral size is 16 bits, the address is automatically - * aligned to a half-word. If the DMA peripheral size is 32 bits, the - * address is aligned to a word. - * - * @param dev DMA Device - * @param channel Channel whose peripheral data register base address to set. - * @param addr Peripheral memory base address to use. - */ -void dma_set_per_addr(dma_dev *dev, dma_channel channel, __io void *addr) { - dma_channel_reg_map *chan_regs; - - ASSERT_FAULT(!dma_is_channel_enabled(dev, channel)); - - chan_regs = dma_channel_regs(dev, channel); - chan_regs->CPAR = (uint32)addr; -} - -/* - * IRQ handlers - */ - -static inline void dispatch_handler(dma_dev *dev, dma_channel channel) { - void (*handler)(void) = dev->handlers[channel - 1].handler; - if (handler) { - handler(); - dma_clear_isr_bits(dev, channel); /* in case handler doesn't */ - } -} - -void __irq_dma1_channel1(void) { - dispatch_handler(DMA1, DMA_CH1); -} - -void __irq_dma1_channel2(void) { - dispatch_handler(DMA1, DMA_CH2); -} - -void __irq_dma1_channel3(void) { - dispatch_handler(DMA1, DMA_CH3); -} - -void __irq_dma1_channel4(void) { - dispatch_handler(DMA1, DMA_CH4); -} - -void __irq_dma1_channel5(void) { - dispatch_handler(DMA1, DMA_CH5); -} - -void __irq_dma1_channel6(void) { - dispatch_handler(DMA1, DMA_CH6); -} - -void __irq_dma1_channel7(void) { - dispatch_handler(DMA1, DMA_CH7); -} - -#ifdef STM32_HIGH_DENSITY -void __irq_dma2_channel1(void) { - dispatch_handler(DMA2, DMA_CH1); -} - -void __irq_dma2_channel2(void) { - dispatch_handler(DMA2, DMA_CH2); -} - -void __irq_dma2_channel3(void) { - dispatch_handler(DMA2, DMA_CH3); -} - -void __irq_dma2_channel4_5(void) { - dispatch_handler(DMA2, DMA_CH4); - dispatch_handler(DMA2, DMA_CH5); -} -#endif - -#endif \ No newline at end of file diff --git a/STM32F4/cores/maple/libmaple/dmaF1.h b/STM32F4/cores/maple/libmaple/dmaF1.h deleted file mode 100644 index 6e8087f..0000000 --- a/STM32F4/cores/maple/libmaple/dmaF1.h +++ /dev/null @@ -1,453 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Michael Hope. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file dma.h - * - * @author Marti Bolivar ; - * Original implementation by Michael Hope - * - * @brief Direct Memory Access peripheral support - */ - -/* - * See /notes/dma.txt for more information. - */ - -#ifndef _DMA_H_ -#define _DMA_H_ - -#include "libmaple_types.h" -#include "rcc.h" -#include "nvic.h" - -#ifdef __cplusplus -extern "C"{ -#endif - -/* - * Register maps - */ - -/** - * @brief DMA register map type. - * - * Note that DMA controller 2 (register map base pointer DMA2_BASE) - * only supports channels 1--5. - */ -typedef struct dma_reg_map { - __io uint32 ISR; /**< Interrupt status register */ - __io uint32 IFCR; /**< Interrupt flag clear register */ - __io uint32 CCR1; /**< Channel 1 configuration register */ - __io uint32 CNDTR1; /**< Channel 1 number of data register */ - __io uint32 CPAR1; /**< Channel 1 peripheral address register */ - __io uint32 CMAR1; /**< Channel 1 memory address register */ - const uint32 RESERVED1; /**< Reserved. */ - __io uint32 CCR2; /**< Channel 2 configuration register */ - __io uint32 CNDTR2; /**< Channel 2 number of data register */ - __io uint32 CPAR2; /**< Channel 2 peripheral address register */ - __io uint32 CMAR2; /**< Channel 2 memory address register */ - const uint32 RESERVED2; /**< Reserved. */ - __io uint32 CCR3; /**< Channel 3 configuration register */ - __io uint32 CNDTR3; /**< Channel 3 number of data register */ - __io uint32 CPAR3; /**< Channel 3 peripheral address register */ - __io uint32 CMAR3; /**< Channel 3 memory address register */ - const uint32 RESERVED3; /**< Reserved. */ - __io uint32 CCR4; /**< Channel 4 configuration register */ - __io uint32 CNDTR4; /**< Channel 4 number of data register */ - __io uint32 CPAR4; /**< Channel 4 peripheral address register */ - __io uint32 CMAR4; /**< Channel 4 memory address register */ - const uint32 RESERVED4; /**< Reserved. */ - __io uint32 CCR5; /**< Channel 5 configuration register */ - __io uint32 CNDTR5; /**< Channel 5 number of data register */ - __io uint32 CPAR5; /**< Channel 5 peripheral address register */ - __io uint32 CMAR5; /**< Channel 5 memory address register */ - const uint32 RESERVED5; /**< Reserved. */ - __io uint32 CCR6; /**< Channel 6 configuration register */ - __io uint32 CNDTR6; /**< Channel 6 number of data register */ - __io uint32 CPAR6; /**< Channel 6 peripheral address register */ - __io uint32 CMAR6; /**< Channel 6 memory address register */ - const uint32 RESERVED6; /**< Reserved. */ - __io uint32 CCR7; /**< Channel 7 configuration register */ - __io uint32 CNDTR7; /**< Channel 7 number of data register */ - __io uint32 CPAR7; /**< Channel 7 peripheral address register */ - __io uint32 CMAR7; /**< Channel 7 memory address register */ - const uint32 RESERVED7; /**< Reserved. */ -} dma_reg_map; - -/** DMA controller 1 register map base pointer */ -#define DMA1_BASE ((struct dma_reg_map*)0x40020000) - -#ifdef STM32_HIGH_DENSITY -/** DMA controller 2 register map base pointer */ -#define DMA2_BASE ((struct dma_reg_map*)0x40020400) -#endif - -/* - * Register bit definitions - */ - -/* Interrupt status register */ - -#define DMA_ISR_TEIF7_BIT 27 -#define DMA_ISR_HTIF7_BIT 26 -#define DMA_ISR_TCIF7_BIT 25 -#define DMA_ISR_GIF7_BIT 24 -#define DMA_ISR_TEIF6_BIT 23 -#define DMA_ISR_HTIF6_BIT 22 -#define DMA_ISR_TCIF6_BIT 21 -#define DMA_ISR_GIF6_BIT 20 -#define DMA_ISR_TEIF5_BIT 19 -#define DMA_ISR_HTIF5_BIT 18 -#define DMA_ISR_TCIF5_BIT 17 -#define DMA_ISR_GIF5_BIT 16 -#define DMA_ISR_TEIF4_BIT 15 -#define DMA_ISR_HTIF4_BIT 14 -#define DMA_ISR_TCIF4_BIT 13 -#define DMA_ISR_GIF4_BIT 12 -#define DMA_ISR_TEIF3_BIT 11 -#define DMA_ISR_HTIF3_BIT 10 -#define DMA_ISR_TCIF3_BIT 9 -#define DMA_ISR_GIF3_BIT 8 -#define DMA_ISR_TEIF2_BIT 7 -#define DMA_ISR_HTIF2_BIT 6 -#define DMA_ISR_TCIF2_BIT 5 -#define DMA_ISR_GIF2_BIT 4 -#define DMA_ISR_TEIF1_BIT 3 -#define DMA_ISR_HTIF1_BIT 2 -#define DMA_ISR_TCIF1_BIT 1 -#define DMA_ISR_GIF1_BIT 0 - -#define DMA_ISR_TEIF7 BIT(DMA_ISR_TEIF7_BIT) -#define DMA_ISR_HTIF7 BIT(DMA_ISR_HTIF7_BIT) -#define DMA_ISR_TCIF7 BIT(DMA_ISR_TCIF7_BIT) -#define DMA_ISR_GIF7 BIT(DMA_ISR_GIF7_BIT) -#define DMA_ISR_TEIF6 BIT(DMA_ISR_TEIF6_BIT) -#define DMA_ISR_HTIF6 BIT(DMA_ISR_HTIF6_BIT) -#define DMA_ISR_TCIF6 BIT(DMA_ISR_TCIF6_BIT) -#define DMA_ISR_GIF6 BIT(DMA_ISR_GIF6_BIT) -#define DMA_ISR_TEIF5 BIT(DMA_ISR_TEIF5_BIT) -#define DMA_ISR_HTIF5 BIT(DMA_ISR_HTIF5_BIT) -#define DMA_ISR_TCIF5 BIT(DMA_ISR_TCIF5_BIT) -#define DMA_ISR_GIF5 BIT(DMA_ISR_GIF5_BIT) -#define DMA_ISR_TEIF4 BIT(DMA_ISR_TEIF4_BIT) -#define DMA_ISR_HTIF4 BIT(DMA_ISR_HTIF4_BIT) -#define DMA_ISR_TCIF4 BIT(DMA_ISR_TCIF4_BIT) -#define DMA_ISR_GIF4 BIT(DMA_ISR_GIF4_BIT) -#define DMA_ISR_TEIF3 BIT(DMA_ISR_TEIF3_BIT) -#define DMA_ISR_HTIF3 BIT(DMA_ISR_HTIF3_BIT) -#define DMA_ISR_TCIF3 BIT(DMA_ISR_TCIF3_BIT) -#define DMA_ISR_GIF3 BIT(DMA_ISR_GIF3_BIT) -#define DMA_ISR_TEIF2 BIT(DMA_ISR_TEIF2_BIT) -#define DMA_ISR_HTIF2 BIT(DMA_ISR_HTIF2_BIT) -#define DMA_ISR_TCIF2 BIT(DMA_ISR_TCIF2_BIT) -#define DMA_ISR_GIF2 BIT(DMA_ISR_GIF2_BIT) -#define DMA_ISR_TEIF1 BIT(DMA_ISR_TEIF1_BIT) -#define DMA_ISR_HTIF1 BIT(DMA_ISR_HTIF1_BIT) -#define DMA_ISR_TCIF1 BIT(DMA_ISR_TCIF1_BIT) -#define DMA_ISR_GIF1 BIT(DMA_ISR_GIF1_BIT) - -/* Interrupt flag clear register */ - -#define DMA_IFCR_CTEIF7_BIT 27 -#define DMA_IFCR_CHTIF7_BIT 26 -#define DMA_IFCR_CTCIF7_BIT 25 -#define DMA_IFCR_CGIF7_BIT 24 -#define DMA_IFCR_CTEIF6_BIT 23 -#define DMA_IFCR_CHTIF6_BIT 22 -#define DMA_IFCR_CTCIF6_BIT 21 -#define DMA_IFCR_CGIF6_BIT 20 -#define DMA_IFCR_CTEIF5_BIT 19 -#define DMA_IFCR_CHTIF5_BIT 18 -#define DMA_IFCR_CTCIF5_BIT 17 -#define DMA_IFCR_CGIF5_BIT 16 -#define DMA_IFCR_CTEIF4_BIT 15 -#define DMA_IFCR_CHTIF4_BIT 14 -#define DMA_IFCR_CTCIF4_BIT 13 -#define DMA_IFCR_CGIF4_BIT 12 -#define DMA_IFCR_CTEIF3_BIT 11 -#define DMA_IFCR_CHTIF3_BIT 10 -#define DMA_IFCR_CTCIF3_BIT 9 -#define DMA_IFCR_CGIF3_BIT 8 -#define DMA_IFCR_CTEIF2_BIT 7 -#define DMA_IFCR_CHTIF2_BIT 6 -#define DMA_IFCR_CTCIF2_BIT 5 -#define DMA_IFCR_CGIF2_BIT 4 -#define DMA_IFCR_CTEIF1_BIT 3 -#define DMA_IFCR_CHTIF1_BIT 2 -#define DMA_IFCR_CTCIF1_BIT 1 -#define DMA_IFCR_CGIF1_BIT 0 - -#define DMA_IFCR_CTEIF7 BIT(DMA_IFCR_CTEIF7_BIT) -#define DMA_IFCR_CHTIF7 BIT(DMA_IFCR_CHTIF7_BIT) -#define DMA_IFCR_CTCIF7 BIT(DMA_IFCR_CTCIF7_BIT) -#define DMA_IFCR_CGIF7 BIT(DMA_IFCR_CGIF7_BIT) -#define DMA_IFCR_CTEIF6 BIT(DMA_IFCR_CTEIF6_BIT) -#define DMA_IFCR_CHTIF6 BIT(DMA_IFCR_CHTIF6_BIT) -#define DMA_IFCR_CTCIF6 BIT(DMA_IFCR_CTCIF6_BIT) -#define DMA_IFCR_CGIF6 BIT(DMA_IFCR_CGIF6_BIT) -#define DMA_IFCR_CTEIF5 BIT(DMA_IFCR_CTEIF5_BIT) -#define DMA_IFCR_CHTIF5 BIT(DMA_IFCR_CHTIF5_BIT) -#define DMA_IFCR_CTCIF5 BIT(DMA_IFCR_CTCIF5_BIT) -#define DMA_IFCR_CGIF5 BIT(DMA_IFCR_CGIF5_BIT) -#define DMA_IFCR_CTEIF4 BIT(DMA_IFCR_CTEIF4_BIT) -#define DMA_IFCR_CHTIF4 BIT(DMA_IFCR_CHTIF4_BIT) -#define DMA_IFCR_CTCIF4 BIT(DMA_IFCR_CTCIF4_BIT) -#define DMA_IFCR_CGIF4 BIT(DMA_IFCR_CGIF4_BIT) -#define DMA_IFCR_CTEIF3 BIT(DMA_IFCR_CTEIF3_BIT) -#define DMA_IFCR_CHTIF3 BIT(DMA_IFCR_CHTIF3_BIT) -#define DMA_IFCR_CTCIF3 BIT(DMA_IFCR_CTCIF3_BIT) -#define DMA_IFCR_CGIF3 BIT(DMA_IFCR_CGIF3_BIT) -#define DMA_IFCR_CTEIF2 BIT(DMA_IFCR_CTEIF2_BIT) -#define DMA_IFCR_CHTIF2 BIT(DMA_IFCR_CHTIF2_BIT) -#define DMA_IFCR_CTCIF2 BIT(DMA_IFCR_CTCIF2_BIT) -#define DMA_IFCR_CGIF2 BIT(DMA_IFCR_CGIF2_BIT) -#define DMA_IFCR_CTEIF1 BIT(DMA_IFCR_CTEIF1_BIT) -#define DMA_IFCR_CHTIF1 BIT(DMA_IFCR_CHTIF1_BIT) -#define DMA_IFCR_CTCIF1 BIT(DMA_IFCR_CTCIF1_BIT) -#define DMA_IFCR_CGIF1 BIT(DMA_IFCR_CGIF1_BIT) - -/* Channel configuration register */ - -#define DMA_CCR_MEM2MEM_BIT 14 -#define DMA_CCR_MINC_BIT 7 -#define DMA_CCR_PINC_BIT 6 -#define DMA_CCR_CIRC_BIT 5 -#define DMA_CCR_DIR_BIT 4 -#define DMA_CCR_TEIE_BIT 3 -#define DMA_CCR_HTIE_BIT 2 -#define DMA_CCR_TCIE_BIT 1 -#define DMA_CCR_EN_BIT 0 - -#define DMA_CCR_MEM2MEM BIT(DMA_CCR_MEM2MEM_BIT) -#define DMA_CCR_PL (0x3 << 12) -#define DMA_CCR_PL_LOW (0x0 << 12) -#define DMA_CCR_PL_MEDIUM (0x1 << 12) -#define DMA_CCR_PL_HIGH (0x2 << 12) -#define DMA_CCR_PL_VERY_HIGH (0x3 << 12) -#define DMA_CCR_MSIZE (0x3 << 10) -#define DMA_CCR_MSIZE_8BITS (0x0 << 10) -#define DMA_CCR_MSIZE_16BITS (0x1 << 10) -#define DMA_CCR_MSIZE_32BITS (0x2 << 10) -#define DMA_CCR_PSIZE (0x3 << 8) -#define DMA_CCR_PSIZE_8BITS (0x0 << 8) -#define DMA_CCR_PSIZE_16BITS (0x1 << 8) -#define DMA_CCR_PSIZE_32BITS (0x2 << 8) -#define DMA_CCR_MINC BIT(DMA_CCR_MINC_BIT) -#define DMA_CCR_PINC BIT(DMA_CCR_PINC_BIT) -#define DMA_CCR_CIRC BIT(DMA_CCR_CIRC_BIT) -#define DMA_CCR_DIR BIT(DMA_CCR_DIR_BIT) -#define DMA_CCR_TEIE BIT(DMA_CCR_TEIE_BIT) -#define DMA_CCR_HTIE BIT(DMA_CCR_HTIE_BIT) -#define DMA_CCR_TCIE BIT(DMA_CCR_TCIE_BIT) -#define DMA_CCR_EN BIT(DMA_CCR_EN_BIT) - -/* - * Devices - */ - -/** Encapsulates state related to a DMA channel interrupt. */ -typedef struct dma_handler_config { - void (*handler)(void); /**< User-specified channel interrupt - handler */ - nvic_irq_num irq_line; /**< Channel's NVIC interrupt number */ -} dma_handler_config; - -/** DMA device type */ -typedef struct dma_dev { - dma_reg_map *regs; /**< Register map */ - rcc_clk_id clk_id; /**< Clock ID */ - dma_handler_config handlers[]; /**< - * @brief IRQ handlers and NVIC numbers. - * - * @see dma_attach_interrupt() - * @see dma_detach_interrupt() - */ -} dma_dev; - -extern dma_dev *DMA1; -#ifdef STM32_HIGH_DENSITY -extern dma_dev *DMA2; -#endif - -/* - * Convenience functions - */ - -void dma_init(dma_dev *dev); - -/** Flags for DMA transfer configuration. */ -typedef enum dma_mode_flags { - DMA_MEM_2_MEM = 1 << 14, /**< Memory to memory mode */ - DMA_MINC_MODE = 1 << 7, /**< Auto-increment memory address */ - DMA_PINC_MODE = 1 << 6, /**< Auto-increment peripheral address */ - DMA_CIRC_MODE = 1 << 5, /**< Circular mode */ - DMA_FROM_MEM = 1 << 4, /**< Read from memory to peripheral */ - DMA_TRNS_ERR = 1 << 3, /**< Interrupt on transfer error */ - DMA_HALF_TRNS = 1 << 2, /**< Interrupt on half-transfer */ - DMA_TRNS_CMPLT = 1 << 1 /**< Interrupt on transfer completion */ -} dma_mode_flags; - -/** Source and destination transfer sizes. */ -typedef enum dma_xfer_size { - DMA_SIZE_8BITS = 0, /**< 8-bit transfers */ - DMA_SIZE_16BITS = 1, /**< 16-bit transfers */ - DMA_SIZE_32BITS = 2 /**< 32-bit transfers */ -} dma_xfer_size; - -/** DMA channel */ -typedef enum dma_channel { - DMA_CH1 = 1, /**< Channel 1 */ - DMA_CH2 = 2, /**< Channel 2 */ - DMA_CH3 = 3, /**< Channel 3 */ - DMA_CH4 = 4, /**< Channel 4 */ - DMA_CH5 = 5, /**< Channel 5 */ - DMA_CH6 = 6, /**< Channel 6 */ - DMA_CH7 = 7, /**< Channel 7 */ -} dma_channel; - -void dma_setup_transfer(dma_dev *dev, - dma_channel channel, - __io void *peripheral_address, - dma_xfer_size peripheral_size, - __io void *memory_address, - dma_xfer_size memory_size, - uint32 mode); - -void dma_set_num_transfers(dma_dev *dev, - dma_channel channel, - uint16 num_transfers); - -/** DMA transfer priority. */ -typedef enum dma_priority { - DMA_PRIORITY_LOW = DMA_CCR_PL_LOW, /**< Low priority */ - DMA_PRIORITY_MEDIUM = DMA_CCR_PL_MEDIUM, /**< Medium priority */ - DMA_PRIORITY_HIGH = DMA_CCR_PL_HIGH, /**< High priority */ - DMA_PRIORITY_VERY_HIGH = DMA_CCR_PL_VERY_HIGH /**< Very high priority */ -} dma_priority; - -void dma_set_priority(dma_dev *dev, - dma_channel channel, - dma_priority priority); - -void dma_attach_interrupt(dma_dev *dev, - dma_channel channel, - void (*handler)(void)); -void dma_detach_interrupt(dma_dev *dev, dma_channel channel); - -/** - * Encodes the reason why a DMA interrupt was called. - * @see dma_get_irq_cause() - */ -typedef enum dma_irq_cause { - DMA_TRANSFER_COMPLETE, /**< Transfer is complete. */ - DMA_TRANSFER_HALF_COMPLETE, /**< Transfer is half complete. */ - DMA_TRANSFER_ERROR, /**< Error occurred during transfer. */ -} dma_irq_cause; - -dma_irq_cause dma_get_irq_cause(dma_dev *dev, dma_channel channel); - -void dma_enable(dma_dev *dev, dma_channel channel); -void dma_disable(dma_dev *dev, dma_channel channel); - -void dma_set_mem_addr(dma_dev *dev, dma_channel channel, __io void *address); -void dma_set_per_addr(dma_dev *dev, dma_channel channel, __io void *address); - -/** - * @brief DMA channel register map type. - * - * Provides access to an individual channel's registers. - */ -typedef struct dma_channel_reg_map { - __io uint32 CCR; /**< Channel configuration register */ - __io uint32 CNDTR; /**< Channel number of data register */ - __io uint32 CPAR; /**< Channel peripheral address register */ - __io uint32 CMAR; /**< Channel memory address register */ -} dma_channel_reg_map; - -#define DMA_CHANNEL_NREGS 5 - -/** - * @brief Obtain a pointer to an individual DMA channel's registers. - * - * For example, dma_channel_regs(DMA1, DMA_CH1)->CCR is DMA1_BASE->CCR1. - * - * @param dev DMA device - * @param channel DMA channel whose channel register map to obtain. - */ -static inline dma_channel_reg_map* dma_channel_regs(dma_dev *dev, - dma_channel channel) { - __io uint32 *ccr1 = &dev->regs->CCR1; - return (dma_channel_reg_map*)(ccr1 + DMA_CHANNEL_NREGS * (channel - 1)); -} - -/** - * @brief Check if a DMA channel is enabled - * @param dev DMA device - * @param channel Channel whose enabled bit to check. - */ -static inline uint8 dma_is_channel_enabled(dma_dev *dev, dma_channel channel) { - return (uint8)(dma_channel_regs(dev, channel)->CCR & DMA_CCR_EN); -} - -/** - * @brief Get the ISR status bits for a DMA channel. - * - * The bits are returned right-aligned, in the following order: - * transfer error flag, half-transfer flag, transfer complete flag, - * global interrupt flag. - * - * If you're attempting to figure out why a DMA interrupt fired; you - * may find dma_get_irq_cause() more convenient. - * - * @param dev DMA device - * @param channel Channel whose ISR bits to return. - * @see dma_get_irq_cause(). - */ -static inline uint8 dma_get_isr_bits(dma_dev *dev, dma_channel channel) { - uint8 shift = (channel - 1) * 4; - return (dev->regs->ISR >> shift) & 0xF; -} - -/** - * @brief Clear the ISR status bits for a given DMA channel. - * - * If you're attempting to clean up after yourself in a DMA interrupt, - * you may find dma_get_irq_cause() more convenient. - * - * @param dev DMA device - * @param channel Channel whose ISR bits to clear. - * @see dma_get_irq_cause() - */ -static inline void dma_clear_isr_bits(dma_dev *dev, dma_channel channel) { - dev->regs->IFCR = BIT(4 * (channel - 1)); -} - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif diff --git a/STM32F4/cores/maple/libmaple/dmaF2.c b/STM32F4/cores/maple/libmaple/dmaF4.c similarity index 91% rename from STM32F4/cores/maple/libmaple/dmaF2.c rename to STM32F4/cores/maple/libmaple/dmaF4.c index 0911e58..add3d8e 100644 --- a/STM32F4/cores/maple/libmaple/dmaF2.c +++ b/STM32F4/cores/maple/libmaple/dmaF4.c @@ -24,10 +24,10 @@ * SOFTWARE. *****************************************************************************/ - #ifdef STM32F2 +#ifdef STM32F4 /** - * @file dmaF2.c + * @file dmaF4.c * @brief Direct Memory Access peripheral support */ @@ -117,33 +117,16 @@ void dma_detach_interrupt(dma_dev *dev, dma_stream stream) { dev->handlers[stream].handler = NULL; } +const uint8 dma_isr_bits_shift[] = { 0, 6, 16, 22}; + +uint8 dma_get_isr_bits(dma_dev *dev, dma_stream stream) { + if ( stream&0xFC ) return ((dev->regs->HISR)>>dma_isr_bits_shift[stream&0x03]) & 0x3d; + else return ((dev->regs->LISR)>>dma_isr_bits_shift[stream&0x03]) & 0x3d; +} + void dma_clear_isr_bits(dma_dev *dev, dma_stream stream) { - switch (stream) { - case 0: - dev->regs->LIFCR|=0x0000003d; - break; - case 1: - dev->regs->LIFCR|=0x00000f40; - break; - case 2: - dev->regs->LIFCR|=0x003d0000; - break; - case 3: - dev->regs->LIFCR|=0x0f400000; - break; - case 4: - dev->regs->HIFCR|=0x0000003d; - break; - case 5: - dev->regs->HIFCR|=0x00000f40; - break; - case 6: - dev->regs->HIFCR|=0x003d0000; - break; - case 7: - dev->regs->HIFCR|=0x0f400000; - break; - } + if ( stream&0xFC ) dev->regs->HIFCR = (uint32)0x0000003d << dma_isr_bits_shift[stream&0x03]; + else dev->regs->LIFCR = (uint32)0x0000003d << dma_isr_bits_shift[stream&0x03]; } /* diff --git a/STM32F4/cores/maple/libmaple/dmaF2.h b/STM32F4/cores/maple/libmaple/dmaF4.h similarity index 74% rename from STM32F4/cores/maple/libmaple/dmaF2.h rename to STM32F4/cores/maple/libmaple/dmaF4.h index 6f7086f..757906c 100644 --- a/STM32F4/cores/maple/libmaple/dmaF2.h +++ b/STM32F4/cores/maple/libmaple/dmaF4.h @@ -25,7 +25,7 @@ *****************************************************************************/ /** - * @file dma.h + * @file dmaF4.h * * @author Marti Bolivar ; * Original implementation by Michael Hope @@ -84,7 +84,7 @@ typedef struct dma_reg_map { * Register bit definitions */ -/* Channel configuration register */ +/* Stream configuration register */ #define DMA_CR_CH0 (0x0 << 25) #define DMA_CR_CH1 (0x1 << 25) @@ -136,6 +136,25 @@ typedef struct dma_reg_map { #define DMA_CR_DMEIE (0x1 << 1) #define DMA_CR_EN (0x1) +typedef enum dma_channel { + DMA_CH0 = DMA_CR_CH0, /**< Channel 0 */ + DMA_CH1 = DMA_CR_CH1, /**< Channel 1 */ + DMA_CH2 = DMA_CR_CH2, /**< Channel 2 */ + DMA_CH3 = DMA_CR_CH3, /**< Channel 3 */ + DMA_CH4 = DMA_CR_CH4, /**< Channel 4 */ + DMA_CH5 = DMA_CR_CH5, /**< Channel 5 */ + DMA_CH6 = DMA_CR_CH6, /**< Channel 6 */ + DMA_CH7 = DMA_CR_CH7, /**< Channel 7 */ +} dma_channel; + +/* Device interrupt status register flags */ + +#define DMA_ISR_TCIF (1 << 5) +#define DMA_ISR_HTIF (1 << 4) +#define DMA_ISR_TEIF (1 << 3) +#define DMA_ISR_DMEIF (1 << 2) +#define DMA_ISR_FEIF (1 << 0) + /* * Devices */ @@ -166,25 +185,35 @@ extern dma_dev *DMA2; * Convenience functions */ -void dma_init(dma_dev *dev); +extern void dma_init(dma_dev *dev); /** Flags for DMA transfer configuration. */ typedef enum dma_mode_flags { - DMA_MEM_2_MEM = 1 << 14, /**< Memory to memory mode */ - DMA_MINC_MODE = 1 << 7, /**< Auto-increment memory address */ - DMA_PINC_MODE = 1 << 6, /**< Auto-increment peripheral address */ - DMA_CIRC_MODE = 1 << 5, /**< Circular mode */ - DMA_FROM_MEM = 1 << 4, /**< Read from memory to peripheral */ - DMA_TRNS_ERR = 1 << 3, /**< Interrupt on transfer error */ - DMA_HALF_TRNS = 1 << 2, /**< Interrupt on half-transfer */ - DMA_TRNS_CMPLT = 1 << 1 /**< Interrupt on transfer completion */ + DMA_MEM_BUF_0 = DMA_CR_CT0, /**< Current memory target buffer 0 */ + DMA_MEM_BUF_1 = DMA_CR_CT1, /**< Current memory target buffer 1 */ + DMA_DBL_BUF_MODE = DMA_CR_DBM, /**< Current memory double buffer mode */ + DMA_PINC_OFFSET = DMA_CR_PINCOS, /**< Peripheral increment offset size */ + DMA_MINC_MODE = DMA_CR_MINC, /**< Memory increment mode */ + DMA_PINC_MODE = DMA_CR_PINC, /**< Peripheral increment mode */ + DMA_CIRC_MODE = DMA_CR_CIRC, /**< Memory Circular mode */ + DMA_FROM_PER = DMA_CR_DIR_P2M, /**< Read from memory to peripheral */ + DMA_FROM_MEM = DMA_CR_DIR_M2P, /**< Read from memory to peripheral */ + DMA_MEM_TO_MEM = DMA_CR_DIR_M2M, /**< Read from memory to memory */ + DMA_PERIF_CTRL = DMA_CR_PFCTRL, /**< Peripheral flow controller */ + DMA_PRIO_MEDIUM = DMA_CR_PL_MEDIUM, /**< Medium priority */ + DMA_PRIO_HIGH = DMA_CR_PL_HIGH, /**< High priority */ + DMA_PRIO_VERY_HIGH = DMA_CR_PL_VERY_HIGH, /**< Very high priority */ + DMA_TRNS_CMPLT = DMA_CR_TCIE, /**< Interrupt on transfer completion */ + DMA_TRNS_HALF = DMA_CR_HTIE, /**< Interrupt on half-transfer */ + DMA_TRNS_ERR = DMA_CR_TEIE, /**< Interrupt on transfer error */ + DMA_DIR_MODE_ERR = DMA_CR_DMEIE /**< Interrupt on direct mode error */ } dma_mode_flags; /** Source and destination transfer sizes. */ typedef enum dma_xfer_size { - DMA_SIZE_8BITS = 0, /**< 8-bit transfers */ - DMA_SIZE_16BITS = 1, /**< 16-bit transfers */ - DMA_SIZE_32BITS = 2 /**< 32-bit transfers */ + DMA_SIZE_8BITS = ( DMA_CR_MSIZE_8BITS|DMA_CR_PSIZE_8BITS ), /**< 8-bit transfers */ + DMA_SIZE_16BITS = (DMA_CR_MSIZE_16BITS|DMA_CR_PSIZE_16BITS), /**< 16-bit transfers */ + DMA_SIZE_32BITS = (DMA_CR_MSIZE_32BITS|DMA_CR_PSIZE_32BITS) /**< 32-bit transfers */ } dma_xfer_size; /** DMA channel */ @@ -201,17 +230,17 @@ typedef enum dma_stream { static inline void dma_setup_transfer(dma_dev *dev, dma_stream stream, + dma_channel channel, + dma_xfer_size trx_size, __io void *peripheral_address, __io void *memory_address0, __io void *memory_address1, - uint32 flags, - uint32 fifo_flags) { + uint32 flags) { dev->regs->STREAM[stream].CR &= ~DMA_CR_EN; // disable dev->regs->STREAM[stream].PAR = (uint32)peripheral_address; dev->regs->STREAM[stream].M0AR = (uint32)memory_address0; dev->regs->STREAM[stream].M1AR = (uint32)memory_address1; - dev->regs->STREAM[stream].FCR = fifo_flags & 0x87; // mask out reserved bits - dev->regs->STREAM[stream].CR = flags & 0x0feffffe; // mask out reserved and enable + dev->regs->STREAM[stream].CR = ((flags|channel|trx_size) & 0x0feffffe); // mask out reserved and enable } static inline void dma_set_num_transfers(dma_dev *dev, @@ -220,6 +249,12 @@ static inline void dma_set_num_transfers(dma_dev *dev, dev->regs->STREAM[stream].NDTR = num_transfers; } +static inline void dma_set_fifo_flags(dma_dev *dev, + dma_stream stream, + uint8 fifo_flags) { + dev->regs->STREAM[stream].FCR = fifo_flags & 0x87; // mask out reserved bits +} + void dma_attach_interrupt(dma_dev *dev, dma_stream stream, void (*handler)(void)); @@ -232,6 +267,7 @@ static inline void dma_enable(dma_dev *dev, dma_stream stream) { static inline void dma_disable(dma_dev *dev, dma_stream stream) { dev->regs->STREAM[stream].CR &= ~DMA_CR_EN; + while (dev->regs->STREAM[stream].CR & DMA_CR_EN); // wait till EN bit is reset, see AN4031, chapter 4.1 } /** diff --git a/STM32F4/cores/maple/libmaple/exti.h b/STM32F4/cores/maple/libmaple/exti.h index bac8adc..063f2d7 100644 --- a/STM32F4/cores/maple/libmaple/exti.h +++ b/STM32F4/cores/maple/libmaple/exti.h @@ -52,11 +52,7 @@ typedef struct exti_reg_map { } exti_reg_map; /** EXTI register map base pointer */ -#ifdef STM32F2 #define EXTI_BASE ((struct exti_reg_map*)0x40013C00) -#else -#define EXTI_BASE ((struct exti_reg_map*)0x40010400) -#endif /** External interrupt trigger mode */ typedef enum exti_trigger_mode { diff --git a/STM32F4/cores/maple/libmaple/fsmc.c b/STM32F4/cores/maple/libmaple/fsmc.c index 06ca7df..42b0d77 100644 --- a/STM32F4/cores/maple/libmaple/fsmc.c +++ b/STM32F4/cores/maple/libmaple/fsmc.c @@ -39,27 +39,28 @@ */ void fsmc_sram_init_gpios(void) { /* Data lines... */ - gpio_set_mode(GPIOD, 0, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOD, 1, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOD, 8, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOD, 9, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOD, 10, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOD, 14, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOD, 15, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOE, 7, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOE, 8, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOE, 9, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOE, 10, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOE, 11, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOE, 12, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOE, 13, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOE, 14, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOE, 15, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PD0, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PD1, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PD8, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PD9, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PD10, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PD14, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PD15, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PE7, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PE8, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PE9, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PE10, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PE11, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PE12, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PE13, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PE14, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PE15, GPIO_AF_OUTPUT_PP); /* Address lines... */ - gpio_set_mode(GPIOD, 11, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOD, 12, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOD, 13, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PD11, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PD12, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PD13, GPIO_AF_OUTPUT_PP); +#if 0 // not available on LQFP package gpio_set_mode(GPIOF, 0, GPIO_AF_OUTPUT_PP); gpio_set_mode(GPIOF, 1, GPIO_AF_OUTPUT_PP); gpio_set_mode(GPIOF, 2, GPIO_AF_OUTPUT_PP); @@ -76,18 +77,20 @@ void fsmc_sram_init_gpios(void) { gpio_set_mode(GPIOG, 3, GPIO_AF_OUTPUT_PP); gpio_set_mode(GPIOG, 4, GPIO_AF_OUTPUT_PP); gpio_set_mode(GPIOG, 5, GPIO_AF_OUTPUT_PP); - +#endif // not available on LQFP package /* And control lines... */ - gpio_set_mode(GPIOD, 4, GPIO_AF_OUTPUT_PP); // NOE - gpio_set_mode(GPIOD, 5, GPIO_AF_OUTPUT_PP); // NWE + gpio_set_mode(PD4, GPIO_AF_OUTPUT_PP); // NOE + gpio_set_mode(PD5, GPIO_AF_OUTPUT_PP); // NWE - gpio_set_mode(GPIOD, 7, GPIO_AF_OUTPUT_PP); // NE1 + gpio_set_mode(PD7, GPIO_AF_OUTPUT_PP); // NE1 +#if 0 // not available on LQFP package gpio_set_mode(GPIOG, 9, GPIO_AF_OUTPUT_PP); // NE2 gpio_set_mode(GPIOG, 10, GPIO_AF_OUTPUT_PP); // NE3 gpio_set_mode(GPIOG, 12, GPIO_AF_OUTPUT_PP); // NE4 +#endif // not available on LQFP package - gpio_set_mode(GPIOE, 0, GPIO_AF_OUTPUT_PP); // NBL0 - gpio_set_mode(GPIOE, 1, GPIO_AF_OUTPUT_PP); // NBL1 + gpio_set_mode(PE0, GPIO_AF_OUTPUT_PP); // NBL0 + gpio_set_mode(PE1, GPIO_AF_OUTPUT_PP); // NBL1 } #endif /* STM32_HIGH_DENSITY */ diff --git a/STM32F4/cores/maple/libmaple/gpio.h b/STM32F4/cores/maple/libmaple/gpio.h index 4d42386..f1a141f 100644 --- a/STM32F4/cores/maple/libmaple/gpio.h +++ b/STM32F4/cores/maple/libmaple/gpio.h @@ -31,8 +31,102 @@ * (AFIO) prototypes, defines, and inlined access functions. */ -#ifdef STM32F2 -#include "gpioF2.h" -#else -#include "gpioF1.h" +#ifndef _GPIO_H_ +#define _GPIO_H_ + +#include "libmaple.h" +#include "boards.h" + +#ifdef __cplusplus +extern "C"{ #endif + + +/** + * @brief Get a GPIO port's corresponding afio_exti_port. + * @param dev GPIO device whose afio_exti_port to return. + */ +static inline afio_exti_port gpio_exti_port(const gpio_dev *dev) { + return dev->exti_port; +} + +/** + * Set or reset a GPIO pin. + * + * Pin must have previously been configured to output mode. + * + * @param dev GPIO device whose pin to set. + * @param pin Pin on to set or reset + * @param val If true, set the pin. If false, reset the pin. + */ +static inline void gpio_write_pin(uint8_t pin, uint8 val) { + if (val) { + (PIN_MAP[pin].gpio_device)->regs->BSRRL = BIT(pin&0x0F); + } else { + (PIN_MAP[pin].gpio_device)->regs->BSRRH = BIT(pin&0x0F); + } +} + +static inline void gpio_set_pin(uint8_t pin) { + (PIN_MAP[pin].gpio_device)->regs->BSRRL = BIT(pin&0x0F); +} + +static inline void gpio_clear_pin(uint8_t pin) { + (PIN_MAP[pin].gpio_device)->regs->BSRRH = BIT(pin&0x0F); +} + +/** + * Determine whether or not a GPIO pin is set. + * + * Pin must have previously been configured to input mode. + * + * @param dev GPIO device whose pin to test. + * @param pin Pin on dev to test. + * @return True if the pin is set, false otherwise. + */ +static inline uint32 gpio_read_pin(uint8_t pin) { + return (PIN_MAP[pin].gpio_device)->regs->IDR & BIT(pin&0x0F); +} + +/** + * Toggle a pin configured as output push-pull. + * @param dev GPIO device. + * @param pin Pin on dev to toggle. + */ +static inline void gpio_toggle_pin(uint8_t pin) { + (PIN_MAP[pin].gpio_device)->regs->ODR = (PIN_MAP[pin].gpio_device)->regs->ODR ^ BIT(pin&0x0F); +} + +/* + * GPIO Convenience routines + */ + +extern void gpio_init(const gpio_dev *dev); +extern void gpio_init_all(void); +extern void gpio_set_mode(uint8_t pin, gpio_pin_mode mode); +extern void gpio_set_af_mode(uint8_t pin, int mode); + +/* + * AFIO convenience routines + */ + +extern void afio_init(void); +extern void afio_exti_select(afio_exti_num exti, afio_exti_port gpio_port); +extern void afio_remap(afio_remap_peripheral p); + +/** + * @brief Enable or disable the JTAG and SW debug ports. + * @param config Desired debug port configuration + * @see afio_debug_cfg + */ +static inline void afio_cfg_debug_ports(afio_debug_cfg config) { + //__io uint32 *mapr = &AFIO_BASE->MAPR; + //*mapr = (*mapr & ~AFIO_MAPR_SWJ_CFG) | config; +} + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/STM32F4/cores/maple/libmaple/gpioF1.c b/STM32F4/cores/maple/libmaple/gpioF1.c deleted file mode 100644 index 846b754..0000000 --- a/STM32F4/cores/maple/libmaple/gpioF1.c +++ /dev/null @@ -1,200 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -#ifdef STM32F1 - -/** - * @file gpio.c - * @brief GPIO initialization routine - */ - -#include "gpio.h" -#include "rcc.h" - -/* - * GPIO devices - */ - -gpio_dev gpioa = { - .regs = GPIOA_BASE, - .clk_id = RCC_GPIOA, - .exti_port = AFIO_EXTI_PA, -}; -/** GPIO port A device. */ -gpio_dev* const GPIOA = &gpioa; - -gpio_dev gpiob = { - .regs = GPIOB_BASE, - .clk_id = RCC_GPIOB, - .exti_port = AFIO_EXTI_PB, -}; -/** GPIO port B device. */ -gpio_dev* const GPIOB = &gpiob; - -gpio_dev gpioc = { - .regs = GPIOC_BASE, - .clk_id = RCC_GPIOC, - .exti_port = AFIO_EXTI_PC, -}; -/** GPIO port C device. */ -gpio_dev* const GPIOC = &gpioc; - -gpio_dev gpiod = { - .regs = GPIOD_BASE, - .clk_id = RCC_GPIOD, - .exti_port = AFIO_EXTI_PD, -}; -/** GPIO port D device. */ -gpio_dev* const GPIOD = &gpiod; - -#ifdef STM32_HIGH_DENSITY -gpio_dev gpioe = { - .regs = GPIOE_BASE, - .clk_id = RCC_GPIOE, - .exti_port = AFIO_EXTI_PE, -}; -/** GPIO port E device. */ -gpio_dev* const GPIOE = &gpioe; - -gpio_dev gpiof = { - .regs = GPIOF_BASE, - .clk_id = RCC_GPIOF, - .exti_port = AFIO_EXTI_PF, -}; -/** GPIO port F device. */ -gpio_dev* const GPIOF = &gpiof; - -gpio_dev gpiog = { - .regs = GPIOG_BASE, - .clk_id = RCC_GPIOG, - .exti_port = AFIO_EXTI_PG, -}; -/** GPIO port G device. */ -gpio_dev* const GPIOG = &gpiog; -#endif - -/* - * GPIO convenience routines - */ - -/** - * Initialize a GPIO device. - * - * Enables the clock for and resets the given device. - * - * @param dev GPIO device to initialize. - */ -void gpio_init(gpio_dev *dev) { - rcc_clk_enable(dev->clk_id); - rcc_reset_dev(dev->clk_id); -} - -/** - * Initialize and reset all available GPIO devices. - */ -void gpio_init_all(void) { - gpio_init(GPIOA); - gpio_init(GPIOB); - gpio_init(GPIOC); - gpio_init(GPIOD); -#ifdef STM32_HIGH_DENSITY - gpio_init(GPIOE); - gpio_init(GPIOF); - gpio_init(GPIOG); -#endif -} - -/** - * Set the mode of a GPIO pin. - * - * @param dev GPIO device. - * @param pin Pin on the device whose mode to set, 0--15. - * @param mode General purpose or alternate function mode to set the pin to. - * @see gpio_pin_mode - */ -void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode) { - gpio_reg_map *regs = dev->regs; - __io uint32 *cr = ®s->CRL + (pin >> 3); - uint32 shift = (pin & 0x7) * 4; - uint32 tmp = *cr; - - tmp &= ~(0xF << shift); - tmp |= (mode == GPIO_INPUT_PU ? GPIO_INPUT_PD : mode) << shift; - *cr = tmp; - - if (mode == GPIO_INPUT_PD) { - regs->ODR &= ~BIT(pin); - } else if (mode == GPIO_INPUT_PU) { - regs->ODR |= BIT(pin); - } -} - -/* - * AFIO - */ - -/** - * @brief Initialize the AFIO clock, and reset the AFIO registers. - */ -void afio_init(void) { - rcc_clk_enable(RCC_AFIO); - rcc_reset_dev(RCC_AFIO); -} - -#define AFIO_EXTI_SEL_MASK 0xF - -/** - * @brief Select a source input for an external interrupt. - * - * @param exti External interrupt. - * @param gpio_port Port which contains pin to use as source input. - * @see afio_exti_num - * @see afio_exti_port - */ -void afio_exti_select(afio_exti_num exti, afio_exti_port gpio_port) { - __io uint32 *exti_cr = &AFIO_BASE->EXTICR1 + exti / 4; - uint32 shift = 4 * (exti % 4); - uint32 cr = *exti_cr; - - cr &= ~(AFIO_EXTI_SEL_MASK << shift); - cr |= gpio_port << shift; - *exti_cr = cr; -} - -/** - * @brief Perform an alternate function remap. - * @param remapping Remapping to perform. - */ -void afio_remap(afio_remap_peripheral remapping) { - if (remapping & AFIO_REMAP_USE_MAPR2) { - remapping &= ~AFIO_REMAP_USE_MAPR2; - AFIO_BASE->MAPR2 |= remapping; - } else { - AFIO_BASE->MAPR |= remapping; - } -} - -#endif diff --git a/STM32F4/cores/maple/libmaple/gpioF1.h b/STM32F4/cores/maple/libmaple/gpioF1.h deleted file mode 100644 index c69efb4..0000000 --- a/STM32F4/cores/maple/libmaple/gpioF1.h +++ /dev/null @@ -1,530 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -*****************************************************************************/ - -/** - * @file gpio.h - * - * @brief General purpose I/O (GPIO) and Alternate Function I/O - * (AFIO) prototypes, defines, and inlined access functions. - */ - -#ifndef _GPIO_H_ -#define _GPIO_H_ - -#include "libmaple.h" -#include "rcc.h" - -#ifdef __cplusplus -extern "C"{ -#endif - -/* - * GPIO register maps and devices - */ - -/** GPIO register map type */ -typedef struct gpio_reg_map { - __io uint32 CRL; /**< Port configuration register low */ - __io uint32 CRH; /**< Port configuration register high */ - __io uint32 IDR; /**< Port input data register */ - __io uint32 ODR; /**< Port output data register */ - __io uint32 BSRR; /**< Port bit set/reset register */ - __io uint32 BRR; /**< Port bit reset register */ - __io uint32 LCKR; /**< Port configuration lock register */ -} gpio_reg_map; - -/** - * @brief External interrupt line port selector. - * - * Used to determine which GPIO port to map an external interrupt line - * onto. */ -/* (See AFIO sections, below) */ -typedef enum afio_exti_port { - AFIO_EXTI_PA, /**< Use port A (PAx) pin. */ - AFIO_EXTI_PB, /**< Use port B (PBx) pin. */ - AFIO_EXTI_PC, /**< Use port C (PCx) pin. */ - AFIO_EXTI_PD, /**< Use port D (PDx) pin. */ -#ifdef STM32_HIGH_DENSITY - AFIO_EXTI_PE, /**< Use port E (PEx) pin. */ - AFIO_EXTI_PF, /**< Use port F (PFx) pin. */ - AFIO_EXTI_PG, /**< Use port G (PGx) pin. */ -#endif -} afio_exti_port; - -/** GPIO device type */ -typedef struct gpio_dev { - gpio_reg_map *regs; /**< Register map */ - rcc_clk_id clk_id; /**< RCC clock information */ - afio_exti_port exti_port; /**< AFIO external interrupt port value */ -} gpio_dev; - -extern gpio_dev gpioa; -extern gpio_dev* const GPIOA; -extern gpio_dev gpiob; -extern gpio_dev* const GPIOB; -extern gpio_dev gpioc; -extern gpio_dev* const GPIOC; -extern gpio_dev gpiod; -extern gpio_dev* const GPIOD; -#ifdef STM32_HIGH_DENSITY -extern gpio_dev gpioe; -extern gpio_dev* const GPIOE; -extern gpio_dev gpiof; -extern gpio_dev* const GPIOF; -extern gpio_dev gpiog; -extern gpio_dev* const GPIOG; -#endif - -/** GPIO port A register map base pointer */ -#define GPIOA_BASE ((struct gpio_reg_map*)0x40010800) -/** GPIO port B register map base pointer */ -#define GPIOB_BASE ((struct gpio_reg_map*)0x40010C00) -/** GPIO port C register map base pointer */ -#define GPIOC_BASE ((struct gpio_reg_map*)0x40011000) -/** GPIO port D register map base pointer */ -#define GPIOD_BASE ((struct gpio_reg_map*)0x40011400) -#ifdef STM32_HIGH_DENSITY -/** GPIO port E register map base pointer */ -#define GPIOE_BASE ((struct gpio_reg_map*)0x40011800) -/** GPIO port F register map base pointer */ -#define GPIOF_BASE ((struct gpio_reg_map*)0x40011C00) -/** GPIO port G register map base pointer */ -#define GPIOG_BASE ((struct gpio_reg_map*)0x40012000) -#endif - -/* - * GPIO register bit definitions - */ - -/* Control registers, low and high */ - -#define GPIO_CR_CNF (0x3 << 2) -#define GPIO_CR_CNF_INPUT_ANALOG (0x0 << 2) -#define GPIO_CR_CNF_INPUT_FLOATING (0x1 << 2) -#define GPIO_CR_CNF_INPUT_PU_PD (0x2 << 2) -#define GPIO_CR_CNF_OUTPUT_PP (0x0 << 2) -#define GPIO_CR_CNF_OUTPUT_OD (0x1 << 2) -#define GPIO_CR_CNF_AF_OUTPUT_PP (0x2 << 2) -#define GPIO_CR_CNF_AF_OUTPUT_OD (0x3 << 2) -#define GPIO_CR_MODE 0x3 -#define GPIO_CR_MODE_INPUT 0x0 -#define GPIO_CR_MODE_OUTPUT_10MHZ 0x1 -#define GPIO_CR_MODE_OUTPUT_2MHZ 0x2 -#define GPIO_CR_MODE_OUTPUT_50MHZ 0x3 - -/** - * @brief GPIO Pin modes. - * - * These only allow for 50MHZ max output speeds; if you want slower, - * use direct register access. - */ -typedef enum gpio_pin_mode { - GPIO_OUTPUT_PP = (GPIO_CR_CNF_OUTPUT_PP | - GPIO_CR_MODE_OUTPUT_50MHZ), /**< Output push-pull. */ - GPIO_OUTPUT_OD = (GPIO_CR_CNF_OUTPUT_OD | - GPIO_CR_MODE_OUTPUT_50MHZ), /**< Output open-drain. */ - GPIO_AF_OUTPUT_PP = (GPIO_CR_CNF_AF_OUTPUT_PP | - GPIO_CR_MODE_OUTPUT_50MHZ), /**< Alternate function - output push-pull. */ - GPIO_AF_OUTPUT_OD = (GPIO_CR_CNF_AF_OUTPUT_OD | - GPIO_CR_MODE_OUTPUT_50MHZ), /**< Alternate function - output open drain. */ - GPIO_INPUT_ANALOG = (GPIO_CR_CNF_INPUT_ANALOG | - GPIO_CR_MODE_INPUT), /**< Analog input. */ - GPIO_INPUT_FLOATING = (GPIO_CR_CNF_INPUT_FLOATING | - GPIO_CR_MODE_INPUT), /**< Input floating. */ - GPIO_INPUT_PD = (GPIO_CR_CNF_INPUT_PU_PD | - GPIO_CR_MODE_INPUT), /**< Input pull-down. */ - GPIO_AF_INPUT_PD = (GPIO_INPUT_PD), /**< Input pull-down. */ - GPIO_INPUT_PU /**< Input pull-up. */ - - - /* GPIO_INPUT_PU treated as a special case, for ODR twiddling */ -} gpio_pin_mode; - -/* - * GPIO Convenience routines - */ - -void gpio_init(gpio_dev *dev); -void gpio_init_all(void); -void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode); - -/** - * @brief Get a GPIO port's corresponding afio_exti_port. - * @param dev GPIO device whose afio_exti_port to return. - */ -static inline afio_exti_port gpio_exti_port(gpio_dev *dev) { - return dev->exti_port; -} - -/** - * Set or reset a GPIO pin. - * - * Pin must have previously been configured to output mode. - * - * @param dev GPIO device whose pin to set. - * @param pin Pin on to set or reset - * @param val If true, set the pin. If false, reset the pin. - */ -static inline void gpio_write_bit(gpio_dev *dev, uint8 pin, uint8 val) { - if (val) { - dev->regs->BSRR = BIT(pin); - } else { - dev->regs->BRR = BIT(pin); - } -} - -/** - * Determine whether or not a GPIO pin is set. - * - * Pin must have previously been configured to input mode. - * - * @param dev GPIO device whose pin to test. - * @param pin Pin on dev to test. - * @return True if the pin is set, false otherwise. - */ -static inline uint32 gpio_read_bit(gpio_dev *dev, uint8 pin) { - return dev->regs->IDR & BIT(pin); -} - -/** - * Toggle a pin configured as output push-pull. - * @param dev GPIO device. - * @param pin Pin on dev to toggle. - */ -static inline void gpio_toggle_bit(gpio_dev *dev, uint8 pin) { - dev->regs->ODR = dev->regs->ODR ^ BIT(pin); -} - -/* - * AFIO register map - */ - -/** AFIO register map */ -typedef struct afio_reg_map { - __io uint32 EVCR; /**< Event control register. */ - __io uint32 MAPR; /**< AF remap and debug I/O configuration - register. */ - __io uint32 EXTICR1; /**< External interrupt configuration - register 1. */ - __io uint32 EXTICR2; /**< External interrupt configuration - register 2. */ - __io uint32 EXTICR3; /**< External interrupt configuration - register 3. */ - __io uint32 EXTICR4; /**< External interrupt configuration - register 4. */ - __io uint32 MAPR2; /**< AF remap and debug I/O configuration - register 2. */ -} afio_reg_map; - -/** AFIO register map base pointer. */ -#define AFIO_BASE ((struct afio_reg_map *)0x40010000) - -/* - * AFIO register bit definitions - */ - -/* Event control register */ - -#define AFIO_EVCR_EVOE (0x1 << 7) -#define AFIO_EVCR_PORT_PA (0x0 << 4) -#define AFIO_EVCR_PORT_PB (0x1 << 4) -#define AFIO_EVCR_PORT_PC (0x2 << 4) -#define AFIO_EVCR_PORT_PD (0x3 << 4) -#define AFIO_EVCR_PORT_PE (0x4 << 4) -#define AFIO_EVCR_PIN_0 0x0 -#define AFIO_EVCR_PIN_1 0x1 -#define AFIO_EVCR_PIN_2 0x2 -#define AFIO_EVCR_PIN_3 0x3 -#define AFIO_EVCR_PIN_4 0x4 -#define AFIO_EVCR_PIN_5 0x5 -#define AFIO_EVCR_PIN_6 0x6 -#define AFIO_EVCR_PIN_7 0x7 -#define AFIO_EVCR_PIN_8 0x8 -#define AFIO_EVCR_PIN_9 0x9 -#define AFIO_EVCR_PIN_10 0xA -#define AFIO_EVCR_PIN_11 0xB -#define AFIO_EVCR_PIN_12 0xC -#define AFIO_EVCR_PIN_13 0xD -#define AFIO_EVCR_PIN_14 0xE -#define AFIO_EVCR_PIN_15 0xF - -/* AF remap and debug I/O configuration register */ - -#define AFIO_MAPR_SWJ_CFG (0x7 << 24) -#define AFIO_MAPR_SWJ_CFG_FULL_SWJ (0x0 << 24) -#define AFIO_MAPR_SWJ_CFG_FULL_SWJ_NO_NJRST (0x1 << 24) -#define AFIO_MAPR_SWJ_CFG_NO_JTAG_SW (0x2 << 24) -#define AFIO_MAPR_SWJ_CFG_NO_JTAG_NO_SW (0x4 << 24) -#define AFIO_MAPR_ADC2_ETRGREG_REMAP BIT(20) -#define AFIO_MAPR_ADC2_ETRGINJ_REMAP BIT(19) -#define AFIO_MAPR_ADC1_ETRGREG_REMAP BIT(18) -#define AFIO_MAPR_ADC1_ETRGINJ_REMAP BIT(17) -#define AFIO_MAPR_TIM5CH4_IREMAP BIT(16) -#define AFIO_MAPR_PD01_REMAP BIT(15) -#define AFIO_MAPR_CAN_REMAP (0x3 << 13) -#define AFIO_MAPR_CAN_REMAP_NONE (0x0 << 13) -#define AFIO_MAPR_CAN_REMAP_PB8_PB9 (0x2 << 13) -#define AFIO_MAPR_CAN_REMAP_PD0_PD1 (0x3 << 13) -#define AFIO_MAPR_TIM4_REMAP BIT(12) -#define AFIO_MAPR_TIM3_REMAP (0x3 << 10) -#define AFIO_MAPR_TIM3_REMAP_NONE (0x0 << 10) -#define AFIO_MAPR_TIM3_REMAP_PARTIAL (0x2 << 10) -#define AFIO_MAPR_TIM3_REMAP_FULL (0x3 << 10) -#define AFIO_MAPR_TIM2_REMAP (0x3 << 8) -#define AFIO_MAPR_TIM2_REMAP_NONE (0x0 << 8) -#define AFIO_MAPR_TIM2_REMAP_PA15_PB3_PA2_PA3 (0x1 << 8) -#define AFIO_MAPR_TIM2_REMAP_PA0_PA1_PB10_PB11 (0x2 << 8) -#define AFIO_MAPR_TIM2_REMAP_FULL (0x3 << 8) -#define AFIO_MAPR_TIM1_REMAP (0x3 << 6) -#define AFIO_MAPR_TIM1_REMAP_NONE (0x0 << 6) -#define AFIO_MAPR_TIM1_REMAP_PARTIAL (0x1 << 6) -#define AFIO_MAPR_TIM1_REMAP_FULL (0x3 << 6) -#define AFIO_MAPR_USART3_REMAP (0x3 << 4) -#define AFIO_MAPR_USART3_REMAP_NONE (0x0 << 4) -#define AFIO_MAPR_USART3_REMAP_PARTIAL (0x1 << 4) -#define AFIO_MAPR_USART3_REMAP_FULL (0x3 << 4) -#define AFIO_MAPR_USART2_REMAP BIT(3) -#define AFIO_MAPR_USART1_REMAP BIT(2) -#define AFIO_MAPR_I2C1_REMAP BIT(1) -#define AFIO_MAPR_SPI1_REMAP BIT(0) - -/* External interrupt configuration register 1 */ - -#define AFIO_EXTICR1_EXTI3 (0xF << 12) -#define AFIO_EXTICR1_EXTI3_PA (0x0 << 12) -#define AFIO_EXTICR1_EXTI3_PB (0x1 << 12) -#define AFIO_EXTICR1_EXTI3_PC (0x2 << 12) -#define AFIO_EXTICR1_EXTI3_PD (0x3 << 12) -#define AFIO_EXTICR1_EXTI3_PE (0x4 << 12) -#define AFIO_EXTICR1_EXTI3_PF (0x5 << 12) -#define AFIO_EXTICR1_EXTI3_PG (0x6 << 12) -#define AFIO_EXTICR1_EXTI2 (0xF << 8) -#define AFIO_EXTICR1_EXTI2_PA (0x0 << 8) -#define AFIO_EXTICR1_EXTI2_PB (0x1 << 8) -#define AFIO_EXTICR1_EXTI2_PC (0x2 << 8) -#define AFIO_EXTICR1_EXTI2_PD (0x3 << 8) -#define AFIO_EXTICR1_EXTI2_PE (0x4 << 8) -#define AFIO_EXTICR1_EXTI2_PF (0x5 << 8) -#define AFIO_EXTICR1_EXTI2_PG (0x6 << 8) -#define AFIO_EXTICR1_EXTI1 (0xF << 4) -#define AFIO_EXTICR1_EXTI1_PA (0x0 << 4) -#define AFIO_EXTICR1_EXTI1_PB (0x1 << 4) -#define AFIO_EXTICR1_EXTI1_PC (0x2 << 4) -#define AFIO_EXTICR1_EXTI1_PD (0x3 << 4) -#define AFIO_EXTICR1_EXTI1_PE (0x4 << 4) -#define AFIO_EXTICR1_EXTI1_PF (0x5 << 4) -#define AFIO_EXTICR1_EXTI1_PG (0x6 << 4) -#define AFIO_EXTICR1_EXTI0 0xF -#define AFIO_EXTICR1_EXTI0_PA 0x0 -#define AFIO_EXTICR1_EXTI0_PB 0x1 -#define AFIO_EXTICR1_EXTI0_PC 0x2 -#define AFIO_EXTICR1_EXTI0_PD 0x3 -#define AFIO_EXTICR1_EXTI0_PE 0x4 -#define AFIO_EXTICR1_EXTI0_PF 0x5 -#define AFIO_EXTICR1_EXTI0_PG 0x6 - -/* External interrupt configuration register 2 */ - -#define AFIO_EXTICR2_EXTI7 (0xF << 12) -#define AFIO_EXTICR2_EXTI7_PA (0x0 << 12) -#define AFIO_EXTICR2_EXTI7_PB (0x1 << 12) -#define AFIO_EXTICR2_EXTI7_PC (0x2 << 12) -#define AFIO_EXTICR2_EXTI7_PD (0x3 << 12) -#define AFIO_EXTICR2_EXTI7_PE (0x4 << 12) -#define AFIO_EXTICR2_EXTI7_PF (0x5 << 12) -#define AFIO_EXTICR2_EXTI7_PG (0x6 << 12) -#define AFIO_EXTICR2_EXTI6 (0xF << 8) -#define AFIO_EXTICR2_EXTI6_PA (0x0 << 8) -#define AFIO_EXTICR2_EXTI6_PB (0x1 << 8) -#define AFIO_EXTICR2_EXTI6_PC (0x2 << 8) -#define AFIO_EXTICR2_EXTI6_PD (0x3 << 8) -#define AFIO_EXTICR2_EXTI6_PE (0x4 << 8) -#define AFIO_EXTICR2_EXTI6_PF (0x5 << 8) -#define AFIO_EXTICR2_EXTI6_PG (0x6 << 8) -#define AFIO_EXTICR2_EXTI5 (0xF << 4) -#define AFIO_EXTICR2_EXTI5_PA (0x0 << 4) -#define AFIO_EXTICR2_EXTI5_PB (0x1 << 4) -#define AFIO_EXTICR2_EXTI5_PC (0x2 << 4) -#define AFIO_EXTICR2_EXTI5_PD (0x3 << 4) -#define AFIO_EXTICR2_EXTI5_PE (0x4 << 4) -#define AFIO_EXTICR2_EXTI5_PF (0x5 << 4) -#define AFIO_EXTICR2_EXTI5_PG (0x6 << 4) -#define AFIO_EXTICR2_EXTI4 0xF -#define AFIO_EXTICR2_EXTI4_PA 0x0 -#define AFIO_EXTICR2_EXTI4_PB 0x1 -#define AFIO_EXTICR2_EXTI4_PC 0x2 -#define AFIO_EXTICR2_EXTI4_PD 0x3 -#define AFIO_EXTICR2_EXTI4_PE 0x4 -#define AFIO_EXTICR2_EXTI4_PF 0x5 -#define AFIO_EXTICR2_EXTI4_PG 0x6 - -/* AF remap and debug I/O configuration register 2 */ - -#define AFIO_MAPR2_FSMC_NADV BIT(10) -#define AFIO_MAPR2_TIM14_REMAP BIT(9) -#define AFIO_MAPR2_TIM13_REMAP BIT(8) -#define AFIO_MAPR2_TIM11_REMAP BIT(7) -#define AFIO_MAPR2_TIM10_REMAP BIT(6) -#define AFIO_MAPR2_TIM9_REMAP BIT(5) - -/* - * AFIO convenience routines - */ - -void afio_init(void); - -/** - * External interrupt line numbers. - */ -typedef enum afio_exti_num { - AFIO_EXTI_0, /**< External interrupt line 0. */ - AFIO_EXTI_1, /**< External interrupt line 1. */ - AFIO_EXTI_2, /**< External interrupt line 2. */ - AFIO_EXTI_3, /**< External interrupt line 3. */ - AFIO_EXTI_4, /**< External interrupt line 4. */ - AFIO_EXTI_5, /**< External interrupt line 5. */ - AFIO_EXTI_6, /**< External interrupt line 6. */ - AFIO_EXTI_7, /**< External interrupt line 7. */ - AFIO_EXTI_8, /**< External interrupt line 8. */ - AFIO_EXTI_9, /**< External interrupt line 9. */ - AFIO_EXTI_10, /**< External interrupt line 10. */ - AFIO_EXTI_11, /**< External interrupt line 11. */ - AFIO_EXTI_12, /**< External interrupt line 12. */ - AFIO_EXTI_13, /**< External interrupt line 13. */ - AFIO_EXTI_14, /**< External interrupt line 14. */ - AFIO_EXTI_15, /**< External interrupt line 15. */ -} afio_exti_num; - -void afio_exti_select(afio_exti_num exti, afio_exti_port gpio_port); - -/* HACK: Use upper bit to denote MAPR2, Bit 31 is reserved and - * not used in either MAPR or MAPR2 */ -#define AFIO_REMAP_USE_MAPR2 (1 << 31) - -/** - * @brief Available peripheral remaps. - * @see afio_remap() - */ -typedef enum afio_remap_peripheral { - AFIO_REMAP_ADC2_ETRGREG = AFIO_MAPR_ADC2_ETRGREG_REMAP, /**< - ADC 2 external trigger regular conversion remapping */ - AFIO_REMAP_ADC2_ETRGINJ = AFIO_MAPR_ADC2_ETRGINJ_REMAP, /**< - ADC 2 external trigger injected conversion remapping */ - AFIO_REMAP_ADC1_ETRGREG = AFIO_MAPR_ADC1_ETRGREG_REMAP, /**< - ADC 1 external trigger regular conversion remapping */ - AFIO_REMAP_ADC1_ETRGINJ = AFIO_MAPR_ADC1_ETRGINJ_REMAP, /**< - ADC 1 external trigger injected conversion remapping */ - AFIO_REMAP_TIM5CH4_I = AFIO_MAPR_TIM5CH4_IREMAP, /**< - Timer 5 channel 4 internal remapping */ - AFIO_REMAP_PD01 = AFIO_MAPR_PD01_REMAP, /**< - Port D0/Port D1 mapping on OSC_IN/OSC_OUT */ - AFIO_REMAP_CAN_1 = AFIO_MAPR_CAN_REMAP_PB8_PB9, /**< - CAN alternate function remapping 1 (RX on PB8, TX on PB9) */ - AFIO_REMAP_CAN_2 = AFIO_MAPR_CAN_REMAP_PD0_PD1, /**< - CAN alternate function remapping 2 (RX on PD0, TX on PD1) */ - AFIO_REMAP_TIM4 = AFIO_MAPR_TIM4_REMAP, /**< - Timer 4 remapping */ - AFIO_REMAP_TIM3_PARTIAL = AFIO_MAPR_TIM3_REMAP_PARTIAL, /**< - Timer 3 partial remapping */ - AFIO_REMAP_TIM3_FULL = AFIO_MAPR_TIM3_REMAP_FULL, /**< - Timer 3 full remapping */ - AFIO_REMAP_TIM2_PARTIAL_1 = AFIO_MAPR_TIM2_REMAP_PA15_PB3_PA2_PA3, /**< - Timer 2 partial remapping 1 (CH1 and ETR on PA15, CH2 on PB3, CH3 - on PA2, CH4 on PA3) */ - AFIO_REMAP_TIM2_PARTIAL_2 = AFIO_MAPR_TIM2_REMAP_PA0_PA1_PB10_PB11, /**< - Timer 2 partial remapping 2 (CH1 and ETR on PA0, CH2 on PA1, CH3 - on PB10, CH4 on PB11) */ - AFIO_REMAP_TIM2_FULL = AFIO_MAPR_TIM2_REMAP_FULL, /**< - Timer 2 full remapping */ - AFIO_REMAP_USART2 = AFIO_MAPR_USART2_REMAP, /**< - USART 2 remapping */ - AFIO_REMAP_USART1 = AFIO_MAPR_USART1_REMAP, /**< - USART 1 remapping */ - AFIO_REMAP_I2C1 = AFIO_MAPR_I2C1_REMAP, /**< - I2C 1 remapping */ - AFIO_REMAP_SPI1 = AFIO_MAPR_SPI1_REMAP, /**< - SPI 1 remapping */ - AFIO_REMAP_FSMC_NADV = (AFIO_MAPR2_FSMC_NADV | - AFIO_REMAP_USE_MAPR2), /**< - NADV signal not connected */ - AFIO_REMAP_TIM14 = (AFIO_MAPR2_TIM14_REMAP | - AFIO_REMAP_USE_MAPR2), /**< - Timer 14 remapping */ - AFIO_REMAP_TIM13 = (AFIO_MAPR2_TIM13_REMAP | - AFIO_REMAP_USE_MAPR2), /**< - Timer 13 remapping */ - AFIO_REMAP_TIM11 = (AFIO_MAPR2_TIM11_REMAP | - AFIO_REMAP_USE_MAPR2), /**< - Timer 11 remapping */ - AFIO_REMAP_TIM10 = (AFIO_MAPR2_TIM10_REMAP | - AFIO_REMAP_USE_MAPR2), /**< - Timer 10 remapping */ - AFIO_REMAP_TIM9 = (AFIO_MAPR2_TIM9_REMAP | - AFIO_REMAP_USE_MAPR2) /**< - Timer 9 */ -} afio_remap_peripheral; - -void afio_remap(afio_remap_peripheral p); - -/** - * @brief Debug port configuration - * - * Used to configure the behavior of JTAG and Serial Wire (SW) debug - * ports and their associated GPIO pins. - * - * @see afio_cfg_debug_ports() - */ -typedef enum afio_debug_cfg { - AFIO_DEBUG_FULL_SWJ = AFIO_MAPR_SWJ_CFG_FULL_SWJ, /**< - Full Serial Wire and JTAG debug */ - AFIO_DEBUG_FULL_SWJ_NO_NJRST = AFIO_MAPR_SWJ_CFG_FULL_SWJ_NO_NJRST, /**< - Full Serial Wire and JTAG, but no NJTRST. */ - AFIO_DEBUG_SW_ONLY = AFIO_MAPR_SWJ_CFG_NO_JTAG_SW, /**< - Serial Wire debug only (JTAG-DP disabled, - SW-DP enabled) */ - AFIO_DEBUG_NONE = AFIO_MAPR_SWJ_CFG_NO_JTAG_NO_SW /**< - No debug; all JTAG and SW pins are free - for use as GPIOs. */ -} afio_debug_cfg; - -/** - * @brief Enable or disable the JTAG and SW debug ports. - * @param config Desired debug port configuration - * @see afio_debug_cfg - */ -static inline void afio_cfg_debug_ports(afio_debug_cfg config) { - __io uint32 *mapr = &AFIO_BASE->MAPR; - *mapr = (*mapr & ~AFIO_MAPR_SWJ_CFG) | config; -} - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/STM32F4/cores/maple/libmaple/gpioF2.c b/STM32F4/cores/maple/libmaple/gpioF4.c similarity index 78% rename from STM32F4/cores/maple/libmaple/gpioF2.c rename to STM32F4/cores/maple/libmaple/gpioF4.c index b04c7e9..67d3bea 100644 --- a/STM32F4/cores/maple/libmaple/gpioF2.c +++ b/STM32F4/cores/maple/libmaple/gpioF4.c @@ -24,8 +24,6 @@ * SOFTWARE. *****************************************************************************/ - #ifdef STM32F2 - /** * @file gpio.c * @brief GPIO initialization routine @@ -38,62 +36,57 @@ * GPIO devices */ -gpio_dev gpioa = { +/** GPIO port A device. */ +const gpio_dev GPIOA = { .regs = GPIOA_BASE, .clk_id = RCC_GPIOA, .exti_port = AFIO_EXTI_PA, }; -/** GPIO port A device. */ -gpio_dev* const GPIOA = &gpioa; -gpio_dev gpiob = { +/** GPIO port B device. */ +const gpio_dev GPIOB = { .regs = GPIOB_BASE, .clk_id = RCC_GPIOB, .exti_port = AFIO_EXTI_PB, }; -/** GPIO port B device. */ -gpio_dev* const GPIOB = &gpiob; -gpio_dev gpioc = { +/** GPIO port C device. */ +const gpio_dev GPIOC = { .regs = GPIOC_BASE, .clk_id = RCC_GPIOC, .exti_port = AFIO_EXTI_PC, }; -/** GPIO port C device. */ -gpio_dev* const GPIOC = &gpioc; -gpio_dev gpiod = { +/** GPIO port D device. */ +const gpio_dev GPIOD = { .regs = GPIOD_BASE, .clk_id = RCC_GPIOD, .exti_port = AFIO_EXTI_PD, }; -/** GPIO port D device. */ -gpio_dev* const GPIOD = &gpiod; #ifdef STM32_HIGH_DENSITY -gpio_dev gpioe = { +/** GPIO port E device. */ +const gpio_dev GPIOE = { .regs = GPIOE_BASE, .clk_id = RCC_GPIOE, .exti_port = AFIO_EXTI_PE, }; -/** GPIO port E device. */ -gpio_dev* const GPIOE = &gpioe; -gpio_dev gpiof = { + #if 0 // not available on LQFP 100 package +/** GPIO port F device. */ +const gpio_dev GPIOF = { .regs = GPIOF_BASE, .clk_id = RCC_GPIOF, .exti_port = AFIO_EXTI_PF, }; -/** GPIO port F device. */ -gpio_dev* const GPIOF = &gpiof; -gpio_dev gpiog = { +/** GPIO port G device. */ +const gpio_dev GPIOG = { .regs = GPIOG_BASE, .clk_id = RCC_GPIOG, .exti_port = AFIO_EXTI_PG, }; -/** GPIO port G device. */ -gpio_dev* const GPIOG = &gpiog; +#endif #endif /* @@ -107,7 +100,7 @@ gpio_dev* const GPIOG = &gpiog; * * @param dev GPIO device to initialize. */ -void gpio_init(gpio_dev *dev) { +void gpio_init(const gpio_dev *dev) { rcc_clk_enable(dev->clk_id); rcc_reset_dev(dev->clk_id); } @@ -116,15 +109,17 @@ void gpio_init(gpio_dev *dev) { * Initialize and reset all available GPIO devices. */ void gpio_init_all(void) { - gpio_init(GPIOA); - gpio_init(GPIOB); - gpio_init(GPIOC); - gpio_init(GPIOD); + gpio_init(&GPIOA); + gpio_init(&GPIOB); + gpio_init(&GPIOC); + gpio_init(&GPIOD); #ifdef STM32_HIGH_DENSITY - gpio_init(GPIOE); - gpio_init(GPIOF); - gpio_init(GPIOG); + gpio_init(&GPIOE); + #if 0 // not available on LQFP 100 package + gpio_init(GPIOF); + gpio_init(GPIOG); + #endif // not available on LQFP 100 package #endif #ifdef ARDUINO_STM32F4_NETDUINO2PLUS @@ -148,16 +143,17 @@ void gpio_init_all(void) { * @param mode General purpose or alternate function mode to set the pin to. * @see gpio_pin_mode */ -void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode) { - gpio_reg_map *regs = dev->regs; +void gpio_set_mode(uint8_t io_pin, gpio_pin_mode mode) { + gpio_reg_map *regs = (PIN_MAP[io_pin].gpio_device)->regs; + uint8_t pin = io_pin&0x0f; //regs->AFR[pin/8] = (regs->AFR[pin/8] & ~(15 << (4*(pin&7)))) | (((mode >> 8) & 15) << (4*(pin&7))); //gpio_set_af_mode(dev, pin, mode>>8); - regs->MODER = (regs->MODER & ~( 3 << (2*pin))) | (((mode >> 0) & 3) << (2*pin)); - regs->PUPDR = (regs->PUPDR & ~( 3 << (2*pin))) | (((mode >> 2) & 3) << (2*pin)); - regs->OSPEEDR = (regs->OSPEEDR & ~( 3 << (2*pin))) | (((mode >> 4) & 3) << (2*pin)); - regs->OTYPER = (regs->OTYPER & ~( 1 << (1*pin))) | (((mode >> 6) & 1) << (1*pin)); + regs->MODER = (regs->MODER & ~( 3 << (pin<<1))) | (((mode >> 0) & 3) << (pin<<1)); + regs->PUPDR = (regs->PUPDR & ~( 3 << (pin<<1))) | (((mode >> 2) & 3) << (pin<<1)); + regs->OSPEEDR = (regs->OSPEEDR & ~( 3 << (pin<<1))) | (((mode >> 4) & 3) << (pin<<1)); + regs->OTYPER = (regs->OTYPER & ~( 1 << (pin<<0))) | (((mode >> 6) & 1) << (pin<<0)); } /** @@ -168,10 +164,11 @@ void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode) { * @param mode alternate function mode to set the pin to. * @see gpio_pin_mode */ -void gpio_set_af_mode(gpio_dev *dev, uint8 pin, int mode) { - gpio_reg_map *regs = dev->regs; +void gpio_set_af_mode(uint8_t io_pin, int mode) { + gpio_reg_map *regs = (PIN_MAP[io_pin].gpio_device)->regs; + uint8_t pin = io_pin&0x0F; - regs->AFR[pin/8] = (regs->AFR[pin/8] & ~(15 << (4*(pin&7)))) | (((mode >> 0) & 15) << (4*(pin&7))); + regs->AFR[pin>>3] = (regs->AFR[pin>>3] & ~(15 << ((pin&7)<<2))) | (((mode >> 0) & 15) << ((pin&7)<<2)); } /* @@ -220,5 +217,3 @@ void afio_remap(afio_remap_peripheral remapping) { } } #endif - -#endif diff --git a/STM32F4/cores/maple/libmaple/gpioF2.h b/STM32F4/cores/maple/libmaple/gpio_def.h similarity index 90% rename from STM32F4/cores/maple/libmaple/gpioF2.h rename to STM32F4/cores/maple/libmaple/gpio_def.h index 91bd67b..cd1fb38 100644 --- a/STM32F4/cores/maple/libmaple/gpioF2.h +++ b/STM32F4/cores/maple/libmaple/gpio_def.h @@ -31,8 +31,8 @@ * (AFIO) prototypes, defines, and inlined access functions. */ -#ifndef _GPIO_H_ -#define _GPIO_H_ +#ifndef _GPIO_DEF_H_ +#define _GPIO_DEF_H_ #include "libmaple.h" #include "rcc.h" @@ -74,11 +74,14 @@ typedef enum afio_exti_port { AFIO_EXTI_PD, /**< Use port D (PDx) pin. */ #ifdef STM32_HIGH_DENSITY AFIO_EXTI_PE, /**< Use port E (PEx) pin. */ + #if 0 // not available on LQFP 100 package AFIO_EXTI_PF, /**< Use port F (PFx) pin. */ AFIO_EXTI_PG, /**< Use port G (PGx) pin. */ + #endif // not available on LQFP 100 package #endif } afio_exti_port; + /** GPIO device type */ typedef struct gpio_dev { gpio_reg_map *regs; /**< Register map */ @@ -86,21 +89,18 @@ typedef struct gpio_dev { afio_exti_port exti_port; /**< AFIO external interrupt port value */ } gpio_dev; -extern gpio_dev gpioa; -extern gpio_dev* const GPIOA; -extern gpio_dev gpiob; -extern gpio_dev* const GPIOB; -extern gpio_dev gpioc; -extern gpio_dev* const GPIOC; -extern gpio_dev gpiod; -extern gpio_dev* const GPIOD; +extern const gpio_dev GPIOA; +extern const gpio_dev GPIOB; +extern const gpio_dev GPIOC; +extern const gpio_dev GPIOD; #ifdef STM32_HIGH_DENSITY -extern gpio_dev gpioe; -extern gpio_dev* const GPIOE; +extern const gpio_dev GPIOE; + #if 0 // not available on LQFP 100 package extern gpio_dev gpiof; extern gpio_dev* const GPIOF; extern gpio_dev gpiog; extern gpio_dev* const GPIOG; + #endif // not available on LQFP 100 package #endif /** GPIO port register map base pointer */ @@ -110,8 +110,10 @@ extern gpio_dev* const GPIOG; #define GPIOD_BASE ((struct gpio_reg_map*)0x40020C00) #ifdef STM32_HIGH_DENSITY #define GPIOE_BASE ((struct gpio_reg_map*)0x40021000) + #if 0 // not available on LQFP 100 package #define GPIOF_BASE ((struct gpio_reg_map*)0x40021400) #define GPIOG_BASE ((struct gpio_reg_map*)0x40021800) + #endif // not available on LQFP 100 package #endif /* @@ -190,61 +192,6 @@ typedef enum gpio_pin_mode { GPIO_BIGNUMBER = 0xfff } gpio_pin_mode; -/* - * GPIO Convenience routines - */ - -void gpio_init(gpio_dev *dev); -void gpio_init_all(void); -void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode); -void gpio_set_af_mode(gpio_dev *dev, uint8 pin, int mode); - -/** - * @brief Get a GPIO port's corresponding afio_exti_port. - * @param dev GPIO device whose afio_exti_port to return. - */ -static inline afio_exti_port gpio_exti_port(gpio_dev *dev) { - return dev->exti_port; -} - -/** - * Set or reset a GPIO pin. - * - * Pin must have previously been configured to output mode. - * - * @param dev GPIO device whose pin to set. - * @param pin Pin on to set or reset - * @param val If true, set the pin. If false, reset the pin. - */ -static inline void gpio_write_bit(gpio_dev *dev, uint8 pin, uint8 val) { - if (val) { - dev->regs->BSRRL = BIT(pin); - } else { - dev->regs->BSRRH = BIT(pin); - } -} - -/** - * Determine whether or not a GPIO pin is set. - * - * Pin must have previously been configured to input mode. - * - * @param dev GPIO device whose pin to test. - * @param pin Pin on dev to test. - * @return True if the pin is set, false otherwise. - */ -static inline uint32 gpio_read_bit(gpio_dev *dev, uint8 pin) { - return dev->regs->IDR & BIT(pin); -} - -/** - * Toggle a pin configured as output push-pull. - * @param dev GPIO device. - * @param pin Pin on dev to toggle. - */ -static inline void gpio_toggle_bit(gpio_dev *dev, uint8 pin) { - dev->regs->ODR = dev->regs->ODR ^ BIT(pin); -} /* * AFIO register map @@ -532,15 +479,6 @@ typedef enum afio_debug_cfg { for use as GPIOs. */ } afio_debug_cfg; -/** - * @brief Enable or disable the JTAG and SW debug ports. - * @param config Desired debug port configuration - * @see afio_debug_cfg - */ -static inline void afio_cfg_debug_ports(afio_debug_cfg config) { - //__io uint32 *mapr = &AFIO_BASE->MAPR; - //*mapr = (*mapr & ~AFIO_MAPR_SWJ_CFG) | config; -} #ifdef __cplusplus } diff --git a/STM32F4/cores/maple/libmaple/i2c.c b/STM32F4/cores/maple/libmaple/i2c.c index e3f3199..a582ed0 100644 --- a/STM32F4/cores/maple/libmaple/i2c.c +++ b/STM32F4/cores/maple/libmaple/i2c.c @@ -41,9 +41,9 @@ static i2c_dev i2c_dev1 = { .regs = I2C1_BASE, - .gpio_port = &gpiob, - .sda_pin = 7, - .scl_pin = 6, + //.gpio_port = &gpiob, + .sda_pin = PB7, + .scl_pin = PB6, .clk_id = RCC_I2C1, .ev_nvic_line = NVIC_I2C1_EV, .er_nvic_line = NVIC_I2C1_ER, @@ -54,9 +54,9 @@ i2c_dev* const I2C1 = &i2c_dev1; static i2c_dev i2c_dev2 = { .regs = I2C2_BASE, - .gpio_port = &gpiob, - .sda_pin = 11, - .scl_pin = 10, + //.gpio_port = &gpiob, + .sda_pin = PB11, + .scl_pin = PB10, .clk_id = RCC_I2C2, .ev_nvic_line = NVIC_I2C2_EV, .er_nvic_line = NVIC_I2C2_ER, @@ -336,38 +336,38 @@ void __irq_i2c2_er(void) { */ void i2c_bus_reset(const i2c_dev *dev) { /* Release both lines */ - gpio_write_bit(dev->gpio_port, dev->scl_pin, 1); - gpio_write_bit(dev->gpio_port, dev->sda_pin, 1); - gpio_set_mode(dev->gpio_port, dev->scl_pin, GPIO_OUTPUT_OD); - gpio_set_mode(dev->gpio_port, dev->sda_pin, GPIO_OUTPUT_OD); + gpio_set_pin(dev->scl_pin); + gpio_set_pin(dev->sda_pin); + gpio_set_mode(dev->scl_pin, GPIO_OUTPUT_OD); + gpio_set_mode(dev->sda_pin, GPIO_OUTPUT_OD); /* * Make sure the bus is free by clocking it until any slaves release the * bus. */ - while (!gpio_read_bit(dev->gpio_port, dev->sda_pin)) { + while (!gpio_read_pin(dev->sda_pin)) { /* Wait for any clock stretching to finish */ - while (!gpio_read_bit(dev->gpio_port, dev->scl_pin)) + while (!gpio_read_pin(dev->scl_pin)) ; delay_us(10); /* Pull low */ - gpio_write_bit(dev->gpio_port, dev->scl_pin, 0); + gpio_clear_pin(dev->scl_pin); delay_us(10); /* Release high again */ - gpio_write_bit(dev->gpio_port, dev->scl_pin, 1); + gpio_set_pin(dev->scl_pin); delay_us(10); } /* Generate start then stop condition */ - gpio_write_bit(dev->gpio_port, dev->sda_pin, 0); + gpio_clear_pin(dev->sda_pin); delay_us(10); - gpio_write_bit(dev->gpio_port, dev->scl_pin, 0); + gpio_clear_pin(dev->scl_pin); delay_us(10); - gpio_write_bit(dev->gpio_port, dev->scl_pin, 1); + gpio_set_pin(dev->scl_pin); delay_us(10); - gpio_write_bit(dev->gpio_port, dev->sda_pin, 1); + gpio_set_pin(dev->sda_pin); } /** @@ -413,8 +413,8 @@ void i2c_master_enable(i2c_dev *dev, uint32 flags) { /* Turn on clock and set GPIO modes */ i2c_init(dev); - gpio_set_mode(dev->gpio_port, dev->sda_pin, GPIO_AF_OUTPUT_OD); - gpio_set_mode(dev->gpio_port, dev->scl_pin, GPIO_AF_OUTPUT_OD); + gpio_set_mode(dev->sda_pin, GPIO_AF_OUTPUT_OD); + gpio_set_mode(dev->scl_pin, GPIO_AF_OUTPUT_OD); /* I2C1 and I2C2 are fed from APB1, clocked at 36MHz */ i2c_set_input_clk(dev, I2C_CLK); diff --git a/STM32F4/cores/maple/libmaple/i2c.h b/STM32F4/cores/maple/libmaple/i2c.h index 4c60ad7..28819a3 100644 --- a/STM32F4/cores/maple/libmaple/i2c.h +++ b/STM32F4/cores/maple/libmaple/i2c.h @@ -78,7 +78,7 @@ typedef struct i2c_msg { */ typedef struct i2c_dev { i2c_reg_map *regs; /**< Register map */ - gpio_dev *gpio_port; /**< SDA, SCL pins' GPIO port */ + //gpio_dev *gpio_port; /**< SDA, SCL pins' GPIO port */ uint8 sda_pin; /**< SDA bit on gpio_port */ uint8 scl_pin; /**< SCL bit on gpio_port */ rcc_clk_id clk_id; /**< RCC clock information */ diff --git a/STM32F4/cores/maple/libmaple/libmaple.h b/STM32F4/cores/maple/libmaple/libmaple.h index 10c6c0c..8360ba3 100644 --- a/STM32F4/cores/maple/libmaple/libmaple.h +++ b/STM32F4/cores/maple/libmaple/libmaple.h @@ -32,29 +32,31 @@ #ifndef _LIBMAPLE_H_ #define _LIBMAPLE_H_ -#include "libmaple_types.h" -#include "stm32.h" #include "util.h" -#include "delay.h" /* * Where to put usercode, based on space reserved for bootloader. * * FIXME this has no business being here */ +/* #if defined(MCU_STM32F103VE) || defined(MCU_STM32F205VE) || defined(MCU_STM32F406VG) - /* e.g., Aeroquad32 */ - #define USER_ADDR_ROM 0x08010000 /* ala42 */ + // e.g., Aeroquad32 + #define USER_ADDR_ROM 0x08010000 // ala42 #define USER_ADDR_RAM 0x20000C00 #define STACK_TOP 0x20000800 #elif defined(BOARD_freeflight) +*/ #define USER_ADDR_ROM 0x08000000 -#define USER_ADDR_RAM 0x20000000 +#define USER_ADDR_RAM 0x20000C00 #define STACK_TOP 0x20000800 +/* #else #define USER_ADDR_ROM 0x08005000 #define USER_ADDR_RAM 0x20000C00 #define STACK_TOP 0x20000800 #endif +*/ + #endif diff --git a/STM32F4/cores/maple/libmaple/libmaple_types.h b/STM32F4/cores/maple/libmaple/libmaple_types.h index 332ded1..8e765b4 100644 --- a/STM32F4/cores/maple/libmaple/libmaple_types.h +++ b/STM32F4/cores/maple/libmaple/libmaple_types.h @@ -33,6 +33,8 @@ #ifndef _LIBMAPLE_TYPES_H_ #define _LIBMAPLE_TYPES_H_ +#include + typedef unsigned char uint8; typedef unsigned short uint16; typedef unsigned int uint32; @@ -46,12 +48,15 @@ typedef long long int64; typedef void (*voidFuncPtr)(void); #define __io volatile -#define __attr_flash __attribute__((section (".USER_FLASH"))) - -#define __always_inline inline __attribute__((always_inline)) - +#define __IO volatile +#ifndef __attr_flash + #define __attr_flash __attribute__((section (".USER_FLASH"))) +#endif +#ifndef __always_inline + #define __always_inline inline __attribute__((always_inline)) +#endif #ifndef NULL -#define NULL 0 + #define NULL 0 #endif #endif diff --git a/STM32F4/cores/maple/libmaple/rcc.h b/STM32F4/cores/maple/libmaple/rcc.h index 6317cbd..75e2d3d 100644 --- a/STM32F4/cores/maple/libmaple/rcc.h +++ b/STM32F4/cores/maple/libmaple/rcc.h @@ -29,8 +29,5 @@ * @brief reset and clock control definitions and prototypes */ -#ifdef STM32F2 -#include "rccF2.h" -#else -#include "rccF1.h" -#endif + +#include "rccF4.h" diff --git a/STM32F4/cores/maple/libmaple/rccF1.c b/STM32F4/cores/maple/libmaple/rccF1.c deleted file mode 100644 index 9eb56b8..0000000 --- a/STM32F4/cores/maple/libmaple/rccF1.c +++ /dev/null @@ -1,233 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - - #ifdef STM32F1 - -/** - * @file rcc.c - * @brief Implements pretty much only the basic clock setup on the - * stm32, clock enable/disable and peripheral reset commands. - */ - -#include "libmaple.h" -#include "flash.h" -#include "rcc.h" -#include "bitband.h" - -#define APB1 RCC_APB1 -#define APB2 RCC_APB2 -#define AHB RCC_AHB - -struct rcc_dev_info { - const rcc_clk_domain clk_domain; - const uint8 line_num; -}; - -/* Device descriptor table, maps rcc_clk_id onto bus and enable/reset - * register bit numbers. */ -static const struct rcc_dev_info rcc_dev_table[] = { - [RCC_GPIOA] = { .clk_domain = APB2, .line_num = 2 }, - [RCC_GPIOB] = { .clk_domain = APB2, .line_num = 3 }, - [RCC_GPIOC] = { .clk_domain = APB2, .line_num = 4 }, - [RCC_GPIOD] = { .clk_domain = APB2, .line_num = 5 }, - [RCC_AFIO] = { .clk_domain = APB2, .line_num = 0 }, - [RCC_ADC1] = { .clk_domain = APB2, .line_num = 9 }, - [RCC_ADC2] = { .clk_domain = APB2, .line_num = 10 }, - [RCC_ADC3] = { .clk_domain = APB2, .line_num = 15 }, - [RCC_USART1] = { .clk_domain = APB2, .line_num = 14 }, - [RCC_USART2] = { .clk_domain = APB1, .line_num = 17 }, - [RCC_USART3] = { .clk_domain = APB1, .line_num = 18 }, - [RCC_TIMER1] = { .clk_domain = APB2, .line_num = 11 }, - [RCC_TIMER2] = { .clk_domain = APB1, .line_num = 0 }, - [RCC_TIMER3] = { .clk_domain = APB1, .line_num = 1 }, - [RCC_TIMER4] = { .clk_domain = APB1, .line_num = 2 }, - [RCC_SPI1] = { .clk_domain = APB2, .line_num = 12 }, - [RCC_SPI2] = { .clk_domain = APB1, .line_num = 14 }, - [RCC_DMA1] = { .clk_domain = AHB, .line_num = 0 }, - [RCC_PWR] = { .clk_domain = APB1, .line_num = 28}, - [RCC_BKP] = { .clk_domain = APB1, .line_num = 27}, - [RCC_I2C1] = { .clk_domain = APB1, .line_num = 21 }, - [RCC_I2C2] = { .clk_domain = APB1, .line_num = 22 }, - [RCC_CRC] = { .clk_domain = AHB, .line_num = 6}, - [RCC_FLITF] = { .clk_domain = AHB, .line_num = 4}, - [RCC_SRAM] = { .clk_domain = AHB, .line_num = 2}, -#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) - [RCC_GPIOE] = { .clk_domain = APB2, .line_num = 6 }, - [RCC_GPIOF] = { .clk_domain = APB2, .line_num = 7 }, - [RCC_GPIOG] = { .clk_domain = APB2, .line_num = 8 }, - [RCC_UART4] = { .clk_domain = APB1, .line_num = 19 }, - [RCC_UART5] = { .clk_domain = APB1, .line_num = 20 }, - [RCC_TIMER5] = { .clk_domain = APB1, .line_num = 3 }, - [RCC_TIMER6] = { .clk_domain = APB1, .line_num = 4 }, - [RCC_TIMER7] = { .clk_domain = APB1, .line_num = 5 }, - [RCC_TIMER8] = { .clk_domain = APB2, .line_num = 13 }, - [RCC_FSMC] = { .clk_domain = AHB, .line_num = 8 }, - [RCC_DAC] = { .clk_domain = APB1, .line_num = 29 }, - [RCC_DMA2] = { .clk_domain = AHB, .line_num = 1 }, - [RCC_SDIO] = { .clk_domain = AHB, .line_num = 10 }, - [RCC_SPI3] = { .clk_domain = APB1, .line_num = 15 }, -#endif -#ifdef STM32_XL_DENSITY - [RCC_TIMER9] = { .clk_domain = APB2, .line_num = 19 }, - [RCC_TIMER10] = { .clk_domain = APB2, .line_num = 20 }, - [RCC_TIMER11] = { .clk_domain = APB2, .line_num = 21 }, - [RCC_TIMER12] = { .clk_domain = APB1, .line_num = 6 }, - [RCC_TIMER13] = { .clk_domain = APB1, .line_num = 7 }, - [RCC_TIMER14] = { .clk_domain = APB1, .line_num = 8 }, -#endif -}; - -/** - * @brief Initialize the clock control system. Initializes the system - * clock source to use the PLL driven by an external oscillator - * @param sysclk_src system clock source, must be PLL - * @param pll_src pll clock source, must be HSE - * @param pll_mul pll multiplier - */ -void rcc_clk_init(rcc_sysclk_src sysclk_src, - rcc_pllsrc pll_src, - rcc_pll_multiplier pll_mul) { - uint32 cfgr = 0; - uint32 cr; - - /* Assume that we're going to clock the chip off the PLL, fed by - * the HSE */ - ASSERT(sysclk_src == RCC_CLKSRC_PLL && - pll_src == RCC_PLLSRC_HSE); - - RCC_BASE->CFGR = pll_src | pll_mul; - - /* Turn on the HSE */ - cr = RCC_BASE->CR; - cr |= RCC_CR_HSEON; - RCC_BASE->CR = cr; - while (!(RCC_BASE->CR & RCC_CR_HSERDY)) - ; - - /* Now the PLL */ - cr |= RCC_CR_PLLON; - RCC_BASE->CR = cr; - while (!(RCC_BASE->CR & RCC_CR_PLLRDY)) - ; - - /* Finally, let's switch over to the PLL */ - cfgr &= ~RCC_CFGR_SW; - cfgr |= RCC_CFGR_SW_PLL; - RCC_BASE->CFGR = cfgr; - while ((RCC_BASE->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) - ; -} - -/** - * @brief Turn on the clock line on a peripheral - * @param id Clock ID of the peripheral to turn on. - */ -void rcc_clk_enable(rcc_clk_id id) { - static const __io uint32* enable_regs[] = { - [APB1] = &RCC_BASE->APB1ENR, - [APB2] = &RCC_BASE->APB2ENR, - [AHB] = &RCC_BASE->AHBENR, - }; - - rcc_clk_domain clk_domain = rcc_dev_clk(id); - __io uint32* enr = (__io uint32*)enable_regs[clk_domain]; - uint8 lnum = rcc_dev_table[id].line_num; - - bb_peri_set_bit(enr, lnum, 1); -} - -/** - * @brief Reset a peripheral. - * @param id Clock ID of the peripheral to reset. - */ -void rcc_reset_dev(rcc_clk_id id) { - static const __io uint32* reset_regs[] = { - [APB1] = &RCC_BASE->APB1RSTR, - [APB2] = &RCC_BASE->APB2RSTR, - }; - - rcc_clk_domain clk_domain = rcc_dev_clk(id); - __io void* addr = (__io void*)reset_regs[clk_domain]; - uint8 lnum = rcc_dev_table[id].line_num; - - bb_peri_set_bit(addr, lnum, 1); - bb_peri_set_bit(addr, lnum, 0); -} - -/** - * @brief Get a peripheral's clock domain - * @param id Clock ID of the peripheral whose clock domain to return - * @return Clock source for the given clock ID - */ -rcc_clk_domain rcc_dev_clk(rcc_clk_id id) { - return rcc_dev_table[id].clk_domain; -} - -/** - * @brief Get a peripheral's clock domain speed - * @param id Clock ID of the peripheral whose clock domain speed to return - * @return Clock speed for the given clock ID - */ -uint32 rcc_dev_clk_speed(rcc_clk_id id) { - static const uint32 rcc_dev_clk_speed_table[] = { - [RCC_AHB] = 72000000, - [RCC_APB1] = 36000000, - [RCC_APB2] = 72000000 - }; - return rcc_dev_clk_speed_table[rcc_dev_clk(id)]; -} - -/** - * @brief Get a peripheral's timer clock domain speed - * @param id Clock ID of the peripheral whose clock domain speed to return - * @return Clock speed for the given clock ID - */ -uint32 rcc_dev_timer_clk_speed(rcc_clk_id id) { - return rcc_dev_clk_speed(RCC_APB2); // 72 MHz for all counter -} - -/** - * @brief Set the divider on a peripheral prescaler - * @param prescaler prescaler to set - * @param divider prescaler divider - */ -void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider) { - static const uint32 masks[] = { - [RCC_PRESCALER_AHB] = RCC_CFGR_HPRE, - [RCC_PRESCALER_APB1] = RCC_CFGR_PPRE1, - [RCC_PRESCALER_APB2] = RCC_CFGR_PPRE2, - [RCC_PRESCALER_USB] = RCC_CFGR_USBPRE, - [RCC_PRESCALER_ADC] = RCC_CFGR_ADCPRE, - }; - - uint32 cfgr = RCC_BASE->CFGR; - cfgr &= ~masks[prescaler]; - cfgr |= divider; - RCC_BASE->CFGR = cfgr; -} - - -#endif diff --git a/STM32F4/cores/maple/libmaple/rccF1.h b/STM32F4/cores/maple/libmaple/rccF1.h deleted file mode 100644 index dd79704..0000000 --- a/STM32F4/cores/maple/libmaple/rccF1.h +++ /dev/null @@ -1,572 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file rcc.h - * @brief reset and clock control definitions and prototypes - */ - -#include "libmaple_types.h" - -#ifndef _RCC_H_ -#define _RCC_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -/** RCC register map type */ -typedef struct rcc_reg_map { - __io uint32 CR; /**< Clock control register */ - __io uint32 CFGR; /**< Clock configuration register */ - __io uint32 CIR; /**< Clock interrupt register */ - __io uint32 APB2RSTR; /**< APB2 peripheral reset register */ - __io uint32 APB1RSTR; /**< APB1 peripheral reset register */ - __io uint32 AHBENR; /**< AHB peripheral clock enable register */ - __io uint32 APB2ENR; /**< APB2 peripheral clock enable register */ - __io uint32 APB1ENR; /**< APB1 peripheral clock enable register */ - __io uint32 BDCR; /**< Backup domain control register */ - __io uint32 CSR; /**< Control/status register */ -} rcc_reg_map; - -/** RCC register map base pointer */ -#define RCC_BASE ((struct rcc_reg_map*)0x40021000) - -/* - * Register bit definitions - */ - -/* Clock control register */ - -#define RCC_CR_PLLRDY_BIT 25 -#define RCC_CR_PLLON_BIT 24 -#define RCC_CR_CSSON_BIT 19 -#define RCC_CR_HSEBYP_BIT 18 -#define RCC_CR_HSERDY_BIT 17 -#define RCC_CR_HSEON_BIT 16 -#define RCC_CR_HSIRDY_BIT 1 -#define RCC_CR_HSION_BIT 0 - -#define RCC_CR_PLLRDY BIT(RCC_CR_PLLRDY_BIT) -#define RCC_CR_PLLON BIT(RCC_CR_PLLON_BIT) -#define RCC_CR_CSSON BIT(RCC_CR_CSSON_BIT) -#define RCC_CR_HSEBYP BIT(RCC_CR_HSEBYP_BIT) -#define RCC_CR_HSERDY BIT(RCC_CR_HSERDY_BIT) -#define RCC_CR_HSEON BIT(RCC_CR_HSEON_BIT) -#define RCC_CR_HSICAL (0xFF << 8) -#define RCC_CR_HSITRIM (0x1F << 3) -#define RCC_CR_HSIRDY BIT(RCC_CR_HSIRDY_BIT) -#define RCC_CR_HSION BIT(RCC_CR_HSION_BIT) - -/* Clock configuration register */ - -#define RCC_CFGR_USBPRE_BIT 22 -#define RCC_CFGR_PLLXTPRE_BIT 17 -#define RCC_CFGR_PLLSRC_BIT 16 - -#define RCC_CFGR_MCO (0x3 << 24) -#define RCC_CFGR_USBPRE BIT(RCC_CFGR_USBPRE_BIT) -#define RCC_CFGR_PLLMUL (0xF << 18) -#define RCC_CFGR_PLLXTPRE BIT(RCC_CFGR_PLLXTPRE_BIT) -#define RCC_CFGR_PLLSRC BIT(RCC_CFGR_PLLSRC_BIT) -#define RCC_CFGR_ADCPRE (0x3 << 14) -#define RCC_CFGR_PPRE2 (0x7 << 11) -#define RCC_CFGR_PPRE1 (0x7 << 8) -#define RCC_CFGR_HPRE (0xF << 4) -#define RCC_CFGR_SWS (0x3 << 2) -#define RCC_CFGR_SWS_PLL (0x2 << 2) -#define RCC_CFGR_SWS_HSE (0x1 << 2) -#define RCC_CFGR_SW 0x3 -#define RCC_CFGR_SW_PLL 0x2 -#define RCC_CFGR_SW_HSE 0x1 - -/* Clock interrupt register */ - -#define RCC_CIR_CSSC_BIT 23 -#define RCC_CIR_PLLRDYC_BIT 20 -#define RCC_CIR_HSERDYC_BIT 19 -#define RCC_CIR_HSIRDYC_BIT 18 -#define RCC_CIR_LSERDYC_BIT 17 -#define RCC_CIR_LSIRDYC_BIT 16 -#define RCC_CIR_PLLRDYIE_BIT 12 -#define RCC_CIR_HSERDYIE_BIT 11 -#define RCC_CIR_HSIRDYIE_BIT 10 -#define RCC_CIR_LSERDYIE_BIT 9 -#define RCC_CIR_LSIRDYIE_BIT 8 -#define RCC_CIR_CSSF_BIT 7 -#define RCC_CIR_PLLRDYF_BIT 4 -#define RCC_CIR_HSERDYF_BIT 3 -#define RCC_CIR_HSIRDYF_BIT 2 -#define RCC_CIR_LSERDYF_BIT 1 -#define RCC_CIR_LSIRDYF_BIT 0 - -#define RCC_CIR_CSSC BIT(RCC_CIR_CSSC_BIT) -#define RCC_CIR_PLLRDYC BIT(RCC_CIR_PLLRDYC_BIT) -#define RCC_CIR_HSERDYC BIT(RCC_CIR_HSERDYC_BIT) -#define RCC_CIR_HSIRDYC BIT(RCC_CIR_HSIRDYC_BIT) -#define RCC_CIR_LSERDYC BIT(RCC_CIR_LSERDYC_BIT) -#define RCC_CIR_LSIRDYC BIT(RCC_CIR_LSIRDYC_BIT) -#define RCC_CIR_PLLRDYIE BIT(RCC_CIR_PLLRDYIE_BIT) -#define RCC_CIR_HSERDYIE BIT(RCC_CIR_HSERDYIE_BIT) -#define RCC_CIR_HSIRDYIE BIT(RCC_CIR_HSIRDYIE_BIT) -#define RCC_CIR_LSERDYIE BIT(RCC_CIR_LSERDYIE_BIT) -#define RCC_CIR_LSIRDYIE BIT(RCC_CIR_LSIRDYIE_BIT) -#define RCC_CIR_CSSF BIT(RCC_CIR_CSSF_BIT) -#define RCC_CIR_PLLRDYF BIT(RCC_CIR_PLLRDYF_BIT) -#define RCC_CIR_HSERDYF BIT(RCC_CIR_HSERDYF_BIT) -#define RCC_CIR_HSIRDYF BIT(RCC_CIR_HSIRDYF_BIT) -#define RCC_CIR_LSERDYF BIT(RCC_CIR_LSERDYF_BIT) -#define RCC_CIR_LSIRDYF BIT(RCC_CIR_LSIRDYF_BIT) - -/* APB2 peripheral reset register */ - -#define RCC_APB2RSTR_TIM11RST_BIT 21 -#define RCC_APB2RSTR_TIM10RST_BIT 20 -#define RCC_APB2RSTR_TIM9RST_BIT 19 -#define RCC_APB2RSTR_ADC3RST_BIT 15 -#define RCC_APB2RSTR_USART1RST_BIT 14 -#define RCC_APB2RSTR_TIM8RST_BIT 13 -#define RCC_APB2RSTR_SPI1RST_BIT 12 -#define RCC_APB2RSTR_TIM1RST_BIT 11 -#define RCC_APB2RSTR_ADC2RST_BIT 10 -#define RCC_APB2RSTR_ADC1RST_BIT 9 -#define RCC_APB2RSTR_IOPGRST_BIT 8 -#define RCC_APB2RSTR_IOPFRST_BIT 7 -#define RCC_APB2RSTR_IOPERST_BIT 6 -#define RCC_APB2RSTR_IOPDRST_BIT 5 -#define RCC_APB2RSTR_IOPCRST_BIT 4 -#define RCC_APB2RSTR_IOPBRST_BIT 3 -#define RCC_APB2RSTR_IOPARST_BIT 2 -#define RCC_APB2RSTR_AFIORST_BIT 0 - -#define RCC_APB2RSTR_TIM11RST BIT(RCC_APB2RSTR_TIM11RST_BIT) -#define RCC_APB2RSTR_TIM10RST BIT(RCC_APB2RSTR_TIM10RST_BIT) -#define RCC_APB2RSTR_TIM9RST BIT(RCC_APB2RSTR_TIM9RST_BIT) -#define RCC_APB2RSTR_ADC3RST BIT(RCC_APB2RSTR_ADC3RST_BIT) -#define RCC_APB2RSTR_USART1RST BIT(RCC_APB2RSTR_USART1RST_BIT) -#define RCC_APB2RSTR_TIM8RST BIT(RCC_APB2RSTR_TIM8RST_BIT) -#define RCC_APB2RSTR_SPI1RST BIT(RCC_APB2RSTR_SPI1RST_BIT) -#define RCC_APB2RSTR_TIM1RST BIT(RCC_APB2RSTR_TIM1RST_BIT) -#define RCC_APB2RSTR_ADC2RST BIT(RCC_APB2RSTR_ADC2RST_BIT) -#define RCC_APB2RSTR_ADC1RST BIT(RCC_APB2RSTR_ADC1RST_BIT) -#define RCC_APB2RSTR_IOPGRST BIT(RCC_APB2RSTR_IOPGRST_BIT) -#define RCC_APB2RSTR_IOPFRST BIT(RCC_APB2RSTR_IOPFRST_BIT) -#define RCC_APB2RSTR_IOPERST BIT(RCC_APB2RSTR_IOPERST_BIT) -#define RCC_APB2RSTR_IOPDRST BIT(RCC_APB2RSTR_IOPDRST_BIT) -#define RCC_APB2RSTR_IOPCRST BIT(RCC_APB2RSTR_IOPCRST_BIT) -#define RCC_APB2RSTR_IOPBRST BIT(RCC_APB2RSTR_IOPBRST_BIT) -#define RCC_APB2RSTR_IOPARST BIT(RCC_APB2RSTR_IOPARST_BIT) -#define RCC_APB2RSTR_AFIORST BIT(RCC_APB2RSTR_AFIORST_BIT) - -/* APB1 peripheral reset register */ - -#define RCC_APB1RSTR_DACRST_BIT 29 -#define RCC_APB1RSTR_PWRRST_BIT 28 -#define RCC_APB1RSTR_BKPRST_BIT 27 -#define RCC_APB1RSTR_CANRST_BIT 25 -#define RCC_APB1RSTR_USBRST_BIT 23 -#define RCC_APB1RSTR_I2C2RST_BIT 22 -#define RCC_APB1RSTR_I2C1RST_BIT 21 -#define RCC_APB1RSTR_UART5RST_BIT 20 -#define RCC_APB1RSTR_UART4RST_BIT 19 -#define RCC_APB1RSTR_USART3RST_BIT 18 -#define RCC_APB1RSTR_USART2RST_BIT 17 -#define RCC_APB1RSTR_SPI3RST_BIT 15 -#define RCC_APB1RSTR_SPI2RST_BIT 14 -#define RCC_APB1RSTR_WWDRST_BIT 11 -#define RCC_APB1RSTR_TIM14RST_BIT 8 -#define RCC_APB1RSTR_TIM13RST_BIT 7 -#define RCC_APB1RSTR_TIM12RST_BIT 6 -#define RCC_APB1RSTR_TIM7RST_BIT 5 -#define RCC_APB1RSTR_TIM6RST_BIT 4 -#define RCC_APB1RSTR_TIM5RST_BIT 3 -#define RCC_APB1RSTR_TIM4RST_BIT 2 -#define RCC_APB1RSTR_TIM3RST_BIT 1 -#define RCC_APB1RSTR_TIM2RST_BIT 0 - -#define RCC_APB1RSTR_DACRST BIT(RCC_APB1RSTR_DACRST_BIT) -#define RCC_APB1RSTR_PWRRST BIT(RCC_APB1RSTR_PWRRST_BIT) -#define RCC_APB1RSTR_BKPRST BIT(RCC_APB1RSTR_BKPRST_BIT) -#define RCC_APB1RSTR_CANRST BIT(RCC_APB1RSTR_CANRST_BIT) -#define RCC_APB1RSTR_USBRST BIT(RCC_APB1RSTR_USBRST_BIT) -#define RCC_APB1RSTR_I2C2RST BIT(RCC_APB1RSTR_I2C2RST_BIT) -#define RCC_APB1RSTR_I2C1RST BIT(RCC_APB1RSTR_I2C1RST_BIT) -#define RCC_APB1RSTR_UART5RST BIT(RCC_APB1RSTR_UART5RST_BIT) -#define RCC_APB1RSTR_UART4RST BIT(RCC_APB1RSTR_UART4RST_BIT) -#define RCC_APB1RSTR_USART3RST BIT(RCC_APB1RSTR_USART3RST_BIT) -#define RCC_APB1RSTR_USART2RST BIT(RCC_APB1RSTR_USART2RST_BIT) -#define RCC_APB1RSTR_SPI3RST BIT(RCC_APB1RSTR_SPI3RST_BIT) -#define RCC_APB1RSTR_SPI2RST BIT(RCC_APB1RSTR_SPI2RST_BIT) -#define RCC_APB1RSTR_WWDRST BIT(RCC_APB1RSTR_WWDRST_BIT) -#define RCC_APB1RSTR_TIM14RST BIT(RCC_APB1RSTR_TIM14RST_BIT) -#define RCC_APB1RSTR_TIM13RST BIT(RCC_APB1RSTR_TIM13RST_BIT) -#define RCC_APB1RSTR_TIM12RST BIT(RCC_APB1RSTR_TIM12RST_BIT) -#define RCC_APB1RSTR_TIM7RST BIT(RCC_APB1RSTR_TIM7RST_BIT) -#define RCC_APB1RSTR_TIM6RST BIT(RCC_APB1RSTR_TIM6RST_BIT) -#define RCC_APB1RSTR_TIM5RST BIT(RCC_APB1RSTR_TIM5RST_BIT) -#define RCC_APB1RSTR_TIM4RST BIT(RCC_APB1RSTR_TIM4RST_BIT) -#define RCC_APB1RSTR_TIM3RST BIT(RCC_APB1RSTR_TIM3RST_BIT) -#define RCC_APB1RSTR_TIM2RST BIT(RCC_APB1RSTR_TIM2RST_BIT) - -/* AHB peripheral clock enable register */ - -#define RCC_AHBENR_SDIOEN_BIT 10 -#define RCC_AHBENR_FSMCEN_BIT 8 -#define RCC_AHBENR_CRCEN_BIT 7 -#define RCC_AHBENR_FLITFEN_BIT 4 -#define RCC_AHBENR_SRAMEN_BIT 2 -#define RCC_AHBENR_DMA2EN_BIT 1 -#define RCC_AHBENR_DMA1EN_BIT 0 - -#define RCC_AHBENR_SDIOEN BIT(RCC_AHBENR_SDIOEN_BIT) -#define RCC_AHBENR_FSMCEN BIT(RCC_AHBENR_FSMCEN_BIT) -#define RCC_AHBENR_CRCEN BIT(RCC_AHBENR_CRCEN_BIT) -#define RCC_AHBENR_FLITFEN BIT(RCC_AHBENR_FLITFEN_BIT) -#define RCC_AHBENR_SRAMEN BIT(RCC_AHBENR_SRAMEN_BIT) -#define RCC_AHBENR_DMA2EN BIT(RCC_AHBENR_DMA2EN_BIT) -#define RCC_AHBENR_DMA1EN BIT(RCC_AHBENR_DMA1EN_BIT) - -/* APB2 peripheral clock enable register */ - -#define RCC_APB2ENR_TIM11EN_BIT 21 -#define RCC_APB2ENR_TIM10EN_BIT 20 -#define RCC_APB2ENR_TIM9EN_BIT 19 -#define RCC_APB2ENR_ADC3EN_BIT 15 -#define RCC_APB2ENR_USART1EN_BIT 14 -#define RCC_APB2ENR_TIM8EN_BIT 13 -#define RCC_APB2ENR_SPI1EN_BIT 12 -#define RCC_APB2ENR_TIM1EN_BIT 11 -#define RCC_APB2ENR_ADC2EN_BIT 10 -#define RCC_APB2ENR_ADC1EN_BIT 9 -#define RCC_APB2ENR_IOPGEN_BIT 8 -#define RCC_APB2ENR_IOPFEN_BIT 7 -#define RCC_APB2ENR_IOPEEN_BIT 6 -#define RCC_APB2ENR_IOPDEN_BIT 5 -#define RCC_APB2ENR_IOPCEN_BIT 4 -#define RCC_APB2ENR_IOPBEN_BIT 3 -#define RCC_APB2ENR_IOPAEN_BIT 2 -#define RCC_APB2ENR_AFIOEN_BIT 0 - -#define RCC_APB2ENR_TIM11EN BIT(RCC_APB2ENR_TIM11EN_BIT) -#define RCC_APB2ENR_TIM10EN BIT(RCC_APB2ENR_TIM10EN_BIT) -#define RCC_APB2ENR_TIM9EN BIT(RCC_APB2ENR_TIM9EN_BIT) -#define RCC_APB2ENR_ADC3EN BIT(RCC_APB2ENR_ADC3EN_BIT) -#define RCC_APB2ENR_USART1EN BIT(RCC_APB2ENR_USART1EN_BIT) -#define RCC_APB2ENR_TIM8EN BIT(RCC_APB2ENR_TIM8EN_BIT) -#define RCC_APB2ENR_SPI1EN BIT(RCC_APB2ENR_SPI1EN_BIT) -#define RCC_APB2ENR_TIM1EN BIT(RCC_APB2ENR_TIM1EN_BIT) -#define RCC_APB2ENR_ADC2EN BIT(RCC_APB2ENR_ADC2EN_BIT) -#define RCC_APB2ENR_ADC1EN BIT(RCC_APB2ENR_ADC1EN_BIT) -#define RCC_APB2ENR_IOPGEN BIT(RCC_APB2ENR_IOPGEN_BIT) -#define RCC_APB2ENR_IOPFEN BIT(RCC_APB2ENR_IOPFEN_BIT) -#define RCC_APB2ENR_IOPEEN BIT(RCC_APB2ENR_IOPEEN_BIT) -#define RCC_APB2ENR_IOPDEN BIT(RCC_APB2ENR_IOPDEN_BIT) -#define RCC_APB2ENR_IOPCEN BIT(RCC_APB2ENR_IOPCEN_BIT) -#define RCC_APB2ENR_IOPBEN BIT(RCC_APB2ENR_IOPBEN_BIT) -#define RCC_APB2ENR_IOPAEN BIT(RCC_APB2ENR_IOPAEN_BIT) -#define RCC_APB2ENR_AFIOEN BIT(RCC_APB2ENR_AFIOEN_BIT) - -/* APB1 peripheral clock enable register */ - -#define RCC_APB1ENR_DACEN_BIT 29 -#define RCC_APB1ENR_PWREN_BIT 28 -#define RCC_APB1ENR_BKPEN_BIT 27 -#define RCC_APB1ENR_CANEN_BIT 25 -#define RCC_APB1ENR_USBEN_BIT 23 -#define RCC_APB1ENR_I2C2EN_BIT 22 -#define RCC_APB1ENR_I2C1EN_BIT 21 -#define RCC_APB1ENR_UART5EN_BIT 20 -#define RCC_APB1ENR_UART4EN_BIT 19 -#define RCC_APB1ENR_USART3EN_BIT 18 -#define RCC_APB1ENR_USART2EN_BIT 17 -#define RCC_APB1ENR_SPI3EN_BIT 15 -#define RCC_APB1ENR_SPI2EN_BIT 14 -#define RCC_APB1ENR_WWDEN_BIT 11 -#define RCC_APB1ENR_TIM14EN_BIT 8 -#define RCC_APB1ENR_TIM13EN_BIT 7 -#define RCC_APB1ENR_TIM12EN_BIT 6 -#define RCC_APB1ENR_TIM7EN_BIT 5 -#define RCC_APB1ENR_TIM6EN_BIT 4 -#define RCC_APB1ENR_TIM5EN_BIT 3 -#define RCC_APB1ENR_TIM4EN_BIT 2 -#define RCC_APB1ENR_TIM3EN_BIT 1 -#define RCC_APB1ENR_TIM2EN_BIT 0 - -#define RCC_APB1ENR_DACEN BIT(RCC_APB1ENR_DACEN_BIT) -#define RCC_APB1ENR_PWREN BIT(RCC_APB1ENR_PWREN_BIT) -#define RCC_APB1ENR_BKPEN BIT(RCC_APB1ENR_BKPEN_BIT) -#define RCC_APB1ENR_CANEN BIT(RCC_APB1ENR_CANEN_BIT) -#define RCC_APB1ENR_USBEN BIT(RCC_APB1ENR_USBEN_BIT) -#define RCC_APB1ENR_I2C2EN BIT(RCC_APB1ENR_I2C2EN_BIT) -#define RCC_APB1ENR_I2C1EN BIT(RCC_APB1ENR_I2C1EN_BIT) -#define RCC_APB1ENR_UART5EN BIT(RCC_APB1ENR_UART5EN_BIT) -#define RCC_APB1ENR_UART4EN BIT(RCC_APB1ENR_UART4EN_BIT) -#define RCC_APB1ENR_USART3EN BIT(RCC_APB1ENR_USART3EN_BIT) -#define RCC_APB1ENR_USART2EN BIT(RCC_APB1ENR_USART2EN_BIT) -#define RCC_APB1ENR_SPI3EN BIT(RCC_APB1ENR_SPI3EN_BIT) -#define RCC_APB1ENR_SPI2EN BIT(RCC_APB1ENR_SPI2EN_BIT) -#define RCC_APB1ENR_WWDEN BIT(RCC_APB1ENR_WWDEN_BIT) -#define RCC_APB1ENR_TIM14EN BIT(RCC_APB1ENR_TIM14EN_BIT) -#define RCC_APB1ENR_TIM13EN BIT(RCC_APB1ENR_TIM13EN_BIT) -#define RCC_APB1ENR_TIM12EN BIT(RCC_APB1ENR_TIM12EN_BIT) -#define RCC_APB1ENR_TIM7EN BIT(RCC_APB1ENR_TIM7EN_BIT) -#define RCC_APB1ENR_TIM6EN BIT(RCC_APB1ENR_TIM6EN_BIT) -#define RCC_APB1ENR_TIM5EN BIT(RCC_APB1ENR_TIM5EN_BIT) -#define RCC_APB1ENR_TIM4EN BIT(RCC_APB1ENR_TIM4EN_BIT) -#define RCC_APB1ENR_TIM3EN BIT(RCC_APB1ENR_TIM3EN_BIT) -#define RCC_APB1ENR_TIM2EN BIT(RCC_APB1ENR_TIM2EN_BIT) - -/* Backup domain control register */ - -#define RCC_BDCR_BDRST_BIT 16 -#define RCC_BDCR_RTCEN_BIT 15 -#define RCC_BDCR_LSEBYP_BIT 2 -#define RCC_BDCR_LSERDY_BIT 1 -#define RCC_BDCR_LSEON_BIT 0 - -#define RCC_BDCR_BDRST BIT(RCC_BDCR_BDRST_BIT) -#define RCC_BDCR_RTCEN BIT(RCC_BDCR_RTC_BIT) -#define RCC_BDCR_RTCSEL (0x3 << 8) -#define RCC_BDCR_RTCSEL_NONE (0x0 << 8) -#define RCC_BDCR_RTCSEL_LSE (0x1 << 8) -#define RCC_BDCR_RTCSEL_HSE (0x3 << 8) -#define RCC_BDCR_LSEBYP BIT(RCC_BDCR_LSEBYP_BIT) -#define RCC_BDCR_LSERDY BIT(RCC_BDCR_LSERDY_BIT) -#define RCC_BDCR_LSEON BIT(RCC_BDCR_LSEON_BIT) - -/* Control/status register */ - -#define RCC_CSR_LPWRRSTF_BIT 31 -#define RCC_CSR_WWDGRSTF_BIT 30 -#define RCC_CSR_IWDGRSTF_BIT 29 -#define RCC_CSR_SFTRSTF_BIT 28 -#define RCC_CSR_PORRSTF_BIT 27 -#define RCC_CSR_PINRSTF_BIT 26 -#define RCC_CSR_RMVF_BIT 24 -#define RCC_CSR_LSIRDY_BIT 1 -#define RCC_CSR_LSION_BIT 0 - -#define RCC_CSR_LPWRRSTF BIT(RCC_CSR_LPWRRSTF_BIT) -#define RCC_CSR_WWDGRSTF BIT(RCC_CSR_WWDGRSTF_BIT) -#define RCC_CSR_IWDGRSTF BIT(RCC_CSR_IWDGRSTF_BIT) -#define RCC_CSR_SFTRSTF BIT(RCC_CSR_SFTRSTF_BIT) -#define RCC_CSR_PORRSTF BIT(RCC_CSR_PORRSTF_BIT) -#define RCC_CSR_PINRSTF BIT(RCC_CSR_PINRSTF_BIT) -#define RCC_CSR_RMVF BIT(RCC_CSR_RMVF_BIT) -#define RCC_CSR_LSIRDY BIT(RCC_CSR_LSIRDY_BIT) -#define RCC_CSR_LSION BIT(RCC_CSR_LSION_BIT) - -/* - * Convenience routines - */ - -/** - * SYSCLK sources - * @see rcc_clk_init() - */ -typedef enum rcc_sysclk_src { - RCC_CLKSRC_HSI = 0x0, - RCC_CLKSRC_HSE = 0x1, - RCC_CLKSRC_PLL = 0x2, -} rcc_sysclk_src; - -/** - * PLL entry clock source - * @see rcc_clk_init() - */ -typedef enum rcc_pllsrc { - RCC_PLLSRC_HSE = (0x1 << 16), - RCC_PLLSRC_HSI_DIV_2 = (0x0 << 16) -} rcc_pllsrc; - -/** - * PLL multipliers - * @see rcc_clk_init() - */ -typedef enum rcc_pll_multiplier { - RCC_PLLMUL_2 = (0x0 << 18), - RCC_PLLMUL_3 = (0x1 << 18), - RCC_PLLMUL_4 = (0x2 << 18), - RCC_PLLMUL_5 = (0x3 << 18), - RCC_PLLMUL_6 = (0x4 << 18), - RCC_PLLMUL_7 = (0x5 << 18), - RCC_PLLMUL_8 = (0x6 << 18), - RCC_PLLMUL_9 = (0x7 << 18), - RCC_PLLMUL_10 = (0x8 << 18), - RCC_PLLMUL_11 = (0x9 << 18), - RCC_PLLMUL_12 = (0xA << 18), - RCC_PLLMUL_13 = (0xB << 18), - RCC_PLLMUL_14 = (0xC << 18), - RCC_PLLMUL_15 = (0xD << 18), - RCC_PLLMUL_16 = (0xE << 18), -} rcc_pll_multiplier; - -/** - * @brief Identifies bus and clock line for a peripheral. - * - * Also generally useful as a unique identifier for that peripheral - * (or its corresponding device struct). - */ -typedef enum rcc_clk_id { - RCC_GPIOA, - RCC_GPIOB, - RCC_GPIOC, - RCC_GPIOD, - RCC_AFIO, - RCC_ADC1, - RCC_ADC2, - RCC_ADC3, - RCC_USART1, - RCC_USART2, - RCC_USART3, - RCC_TIMER1, - RCC_TIMER2, - RCC_TIMER3, - RCC_TIMER4, - RCC_SPI1, - RCC_SPI2, - RCC_DMA1, - RCC_PWR, - RCC_BKP, - RCC_I2C1, - RCC_I2C2, - RCC_CRC, - RCC_FLITF, - RCC_SRAM, -#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) - RCC_GPIOE, - RCC_GPIOF, - RCC_GPIOG, - RCC_UART4, - RCC_UART5, - RCC_TIMER5, - RCC_TIMER6, - RCC_TIMER7, - RCC_TIMER8, - RCC_FSMC, - RCC_DAC, - RCC_DMA2, - RCC_SDIO, - RCC_SPI3, -#endif -#ifdef STM32_XL_DENSITY - RCC_TIMER9, - RCC_TIMER10, - RCC_TIMER11, - RCC_TIMER12, - RCC_TIMER13, - RCC_TIMER14, -#endif -} rcc_clk_id; - -void rcc_clk_init(rcc_sysclk_src sysclk_src, - rcc_pllsrc pll_src, - rcc_pll_multiplier pll_mul); -void rcc_clk_enable(rcc_clk_id device); -void rcc_reset_dev(rcc_clk_id device); - -typedef enum rcc_clk_domain { - RCC_APB1, - RCC_APB2, - RCC_AHB -} rcc_clk_domain; - -rcc_clk_domain rcc_dev_clk(rcc_clk_id device); - -uint32 rcc_dev_clk_speed(rcc_clk_id id); -uint32 rcc_dev_timer_clk_speed(rcc_clk_id id); - -/** - * Prescaler identifiers - * @see rcc_set_prescaler() - */ -typedef enum rcc_prescaler { - RCC_PRESCALER_AHB, - RCC_PRESCALER_APB1, - RCC_PRESCALER_APB2, - RCC_PRESCALER_USB, - RCC_PRESCALER_ADC -} rcc_prescaler; - -/** - * ADC prescaler dividers - * @see rcc_set_prescaler() - */ -typedef enum rcc_adc_divider { - RCC_ADCPRE_PCLK_DIV_2 = 0x0 << 14, - RCC_ADCPRE_PCLK_DIV_4 = 0x1 << 14, - RCC_ADCPRE_PCLK_DIV_6 = 0x2 << 14, - RCC_ADCPRE_PCLK_DIV_8 = 0x3 << 14, -} rcc_adc_divider; - -/** - * APB1 prescaler dividers - * @see rcc_set_prescaler() - */ -typedef enum rcc_apb1_divider { - RCC_APB1_HCLK_DIV_1 = 0x0 << 8, - RCC_APB1_HCLK_DIV_2 = 0x4 << 8, - RCC_APB1_HCLK_DIV_4 = 0x5 << 8, - RCC_APB1_HCLK_DIV_8 = 0x6 << 8, - RCC_APB1_HCLK_DIV_16 = 0x7 << 8, -} rcc_apb1_divider; - -/** - * APB2 prescaler dividers - * @see rcc_set_prescaler() - */ -typedef enum rcc_apb2_divider { - RCC_APB2_HCLK_DIV_1 = 0x0 << 11, - RCC_APB2_HCLK_DIV_2 = 0x4 << 11, - RCC_APB2_HCLK_DIV_4 = 0x5 << 11, - RCC_APB2_HCLK_DIV_8 = 0x6 << 11, - RCC_APB2_HCLK_DIV_16 = 0x7 << 11, -} rcc_apb2_divider; - -/** - * AHB prescaler dividers - * @see rcc_set_prescaler() - */ -typedef enum rcc_ahb_divider { - RCC_AHB_SYSCLK_DIV_1 = 0x0 << 4, - RCC_AHB_SYSCLK_DIV_2 = 0x8 << 4, - RCC_AHB_SYSCLK_DIV_4 = 0x9 << 4, - RCC_AHB_SYSCLK_DIV_8 = 0xA << 4, - RCC_AHB_SYSCLK_DIV_16 = 0xB << 4, - RCC_AHB_SYSCLK_DIV_32 = 0xC << 4, - RCC_AHB_SYSCLK_DIV_64 = 0xD << 4, - RCC_AHB_SYSCLK_DIV_128 = 0xD << 4, - RCC_AHB_SYSCLK_DIV_256 = 0xE << 4, - RCC_AHB_SYSCLK_DIV_512 = 0xF << 4, -} rcc_ahb_divider; - -void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif diff --git a/STM32F4/cores/maple/libmaple/rccF2.c b/STM32F4/cores/maple/libmaple/rccF4.c similarity index 99% rename from STM32F4/cores/maple/libmaple/rccF2.c rename to STM32F4/cores/maple/libmaple/rccF4.c index 691393a..c4ff30d 100644 --- a/STM32F4/cores/maple/libmaple/rccF2.c +++ b/STM32F4/cores/maple/libmaple/rccF4.c @@ -24,7 +24,7 @@ * SOFTWARE. *****************************************************************************/ - #ifdef STM32F2 +#ifdef STM32F4 /** * @file rcc.c @@ -166,7 +166,6 @@ typedef struct #define FLASH ((FLASH_TypeDef *) FLASH_R_BASE) #define RESET 0 -typedef uint32 uint32_t; void InitMCO1() { @@ -175,8 +174,8 @@ void InitMCO1() RCC->CFGR &= RCC_CFGR_MCO1_RESET_MASK; RCC->CFGR |= RCC_CFGR_MCO1Source_HSE | RCC_CFGR_MCO1Div_1; // PA8 Output the Master Clock MCO1 - gpio_set_af_mode(GPIOA, 8, 0); - gpio_set_mode(GPIOA, 8, GPIO_MODE_AF | GPIO_OTYPE_PP | GPIO_OSPEED_100MHZ); + gpio_set_af_mode(PA8, 0); + gpio_set_mode(PA8, GPIO_MODE_AF | GPIO_OTYPE_PP | GPIO_OSPEED_100MHZ); } diff --git a/STM32F4/cores/maple/libmaple/rccF2.h b/STM32F4/cores/maple/libmaple/rccF4.h similarity index 100% rename from STM32F4/cores/maple/libmaple/rccF2.h rename to STM32F4/cores/maple/libmaple/rccF4.h diff --git a/STM32F4/cores/maple/libmaple/rules.mk b/STM32F4/cores/maple/libmaple/rules.mk index c4924dc..eb8d96d 100644 --- a/STM32F4/cores/maple/libmaple/rules.mk +++ b/STM32F4/cores/maple/libmaple/rules.mk @@ -3,17 +3,11 @@ sp := $(sp).x dirstack_$(sp) := $(d) d := $(dir) BUILDDIRS += $(BUILD_PATH)/$(d) -ifneq ($(MCU_FAMILY), STM32F2) -BUILDDIRS += $(BUILD_PATH)/$(d)/usb -BUILDDIRS += $(BUILD_PATH)/$(d)/usb/usb_lib -LIBMAPLE_INCLUDES := -I$(LIBMAPLE_PATH) -I$(LIBMAPLE_PATH)/usb -I$(LIBMAPLE_PATH)/usb/usb_lib -else BUILDDIRS += $(BUILD_PATH)/$(d)/usbF4/STM32_USB_Device_Library/Core/src BUILDDIRS += $(BUILD_PATH)/$(d)/usbF4/STM32_USB_Device_Library/Class/cdc/src BUILDDIRS += $(BUILD_PATH)/$(d)/usbF4/STM32_USB_OTG_Driver/src BUILDDIRS += $(BUILD_PATH)/$(d)/usbF4/VCP LIBMAPLE_INCLUDES := -I$(LIBMAPLE_PATH) -I$(LIBMAPLE_PATH)/usbF4 -endif # Local flags @@ -42,18 +36,6 @@ cSRCS_$(d) := adc.c \ usart.c \ util.c -ifneq ($(MCU_FAMILY), STM32F2) - cSRCS_$(d) += \ - usb/descriptors.c \ - usb/usb.c \ - usb/usb_callbacks.c \ - usb/usb_hardware.c \ - usb/usb_lib/usb_core.c \ - usb/usb_lib/usb_init.c \ - usb/usb_lib/usb_int.c \ - usb/usb_lib/usb_mem.c \ - usb/usb_lib/usb_regs.c -else V=1 cSRCS_$(d) += \ usbF4/STM32_USB_Device_Library/Core/src/usbd_core.c \ @@ -69,11 +51,7 @@ else usbF4/VCP/usbd_usr.c \ usbF4/usb.c \ usbF4/VCP/misc.c -endif -ifneq ($(MCU_FAMILY), STM32F2) - cSRCS_$(d) += bkp.c -endif sSRCS_$(d) := exc.S diff --git a/STM32F4/cores/maple/libmaple/spi.c b/STM32F4/cores/maple/libmaple/spi.c index 194a82e..4b274cb 100644 --- a/STM32F4/cores/maple/libmaple/spi.c +++ b/STM32F4/cores/maple/libmaple/spi.c @@ -83,25 +83,29 @@ 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 * correctly treated as 8-bit or 16-bit quantities). * @param len Maximum number of elements to transmit. - * @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 (spi_is_tx_empty(dev) && (txed < len)) { - if (byte_frame) { - dev->regs->DR = ((const uint8*)buf)[txed++]; - } else { - dev->regs->DR = ((const uint16*)buf)[txed++]; - } - } - return txed; +void spi_tx(spi_dev *dev, void *buf, uint32 len) +{ + spi_reg_map *regs = dev->regs; + if ( spi_dff(dev) == SPI_DFF_8_BIT ) { + uint8 * dp8 = (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 { + uint16 * dp16 = (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++; + } + } } /** @@ -157,8 +161,9 @@ void spi_rx_dma_disable(spi_dev *dev) { */ static void spi_reconfigure(spi_dev *dev, uint32 cr1_config) { - spi_irq_disable(dev, SPI_INTERRUPTS_ALL); - spi_peripheral_disable(dev); - dev->regs->CR1 = cr1_config; - spi_peripheral_enable(dev); +#define MASK (SPI_CR1_CRCEN|SPI_CR1_DFF) + 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_peripheral_enable(dev); } diff --git a/STM32F4/cores/maple/libmaple/spi.h b/STM32F4/cores/maple/libmaple/spi.h index 88739c5..abed68c 100644 --- a/STM32F4/cores/maple/libmaple/spi.h +++ b/STM32F4/cores/maple/libmaple/spi.h @@ -213,31 +213,22 @@ typedef struct spi_dev { void spi_init(spi_dev *dev); -struct gpio_dev; /** * @brief Configure GPIO bit modes for use as a SPI port's pins. * * @param dev SPI device * @param as_master If true, configure as bus master; otherwise, as slave. - * @param nss_dev NSS pin's GPIO device * @param nss_bit NSS pin's GPIO bit on nss_dev - * @param sck_dev SCK pin's GPIO device * @param sck_bit SCK pin's GPIO bit on comm_dev - * @param miso_dev MISO pin's GPIO device * @param miso_bit MISO pin's GPIO bit on comm_dev - * @param mosi_dev MOSI pin's GPIO device * @param mosi_bit MOSI pin's GPIO bit on comm_dev */ extern void spi_config_gpios(spi_dev *dev, uint8 as_master, - struct gpio_dev *nss_dev, - uint8 nss_bit, - struct gpio_dev *sck_dev, - uint8 sck_bit, - struct gpio_dev *miso_dev, - uint8 miso_bit, - struct gpio_dev *mosi_dev, - uint8 mosi_bit); + uint8 nss_pin, + uint8 sck_pin, + uint8 miso_pin, + uint8 mosi_pin); /** * @brief SPI mode configuration. @@ -312,7 +303,7 @@ void spi_slave_enable(spi_dev *dev, spi_mode mode, uint32 flags); -uint32 spi_tx(spi_dev *dev, const void *buf, uint32 len); +void spi_tx(spi_dev *dev, void *buf, uint32 len); /** * @brief Call a function on each SPI port diff --git a/STM32F4/cores/maple/libmaple/spiF4.h b/STM32F4/cores/maple/libmaple/spiF4.h index 3f51164..cbdc91a 100644 --- a/STM32F4/cores/maple/libmaple/spiF4.h +++ b/STM32F4/cores/maple/libmaple/spiF4.h @@ -31,8 +31,8 @@ * @brief STM32F1 SPI/I2S series header. */ -#ifndef _LIBMAPLE_STM32F1_SPI_H_ -#define _LIBMAPLE_STM32F1_SPI_H_ +#ifndef _LIBMAPLE_SPI_F4_H_ +#define _LIBMAPLE_SPI_F4_H_ #include @@ -62,17 +62,6 @@ extern struct spi_dev *SPI2; extern struct spi_dev *SPI3; #endif -/* - * Routines - */ - -/* spi_gpio_cfg(): Backwards compatibility shim to spi_config_gpios() */ -struct gpio_dev; -extern void spi_config_gpios(struct spi_dev*, uint8, - struct gpio_dev*, uint8, - struct gpio_dev*, uint8, - struct gpio_dev*, uint8, - struct gpio_dev*, uint8); #ifdef __cplusplus } diff --git a/STM32F4/cores/maple/libmaple/spi_f4.c b/STM32F4/cores/maple/libmaple/spi_f4.c index b9beb68..43f5092 100644 --- a/STM32F4/cores/maple/libmaple/spi_f4.c +++ b/STM32F4/cores/maple/libmaple/spi_f4.c @@ -56,25 +56,21 @@ spi_dev *SPI3 = &spi3; void spi_config_gpios(spi_dev *ignored, uint8 as_master, - gpio_dev *nss_dev, - uint8 nss_bit, - gpio_dev *sck_dev, - uint8 sck_bit, - gpio_dev *miso_dev, - uint8 miso_bit, - gpio_dev *mosi_dev, - uint8 mosi_bit) { + uint8 nss_pin, + uint8 sck_pin, + uint8 miso_pin, + uint8 mosi_pin) { if (as_master) { // gpio_set_mode(nss_dev, nss_bit, GPIO_AF_OUTPUT_PP); - gpio_set_mode(sck_dev, sck_bit, GPIO_AF_OUTPUT_PP); + gpio_set_mode(sck_pin, GPIO_AF_OUTPUT_PP); // gpio_set_mode(comm_dev, miso_bit, GPIO_INPUT_FLOATING); - gpio_set_mode(miso_dev, miso_bit, GPIO_AF_INPUT_PD); - gpio_set_mode(mosi_dev, mosi_bit, GPIO_AF_OUTPUT_PP); + gpio_set_mode(miso_pin, GPIO_AF_INPUT_PD); + gpio_set_mode(mosi_pin, GPIO_AF_OUTPUT_PP); } else { - gpio_set_mode(nss_dev, nss_bit, GPIO_INPUT_FLOATING); - gpio_set_mode(sck_dev, sck_bit, GPIO_INPUT_FLOATING); - gpio_set_mode(miso_dev, miso_bit, GPIO_AF_OUTPUT_PP); - gpio_set_mode(mosi_dev, mosi_bit, GPIO_INPUT_FLOATING); + gpio_set_mode(nss_pin, GPIO_INPUT_FLOATING); + gpio_set_mode(sck_pin, GPIO_INPUT_FLOATING); + gpio_set_mode(miso_pin, GPIO_AF_OUTPUT_PP); + gpio_set_mode(mosi_pin, GPIO_INPUT_FLOATING); } } diff --git a/STM32F4/cores/maple/libmaple/stm32.h b/STM32F4/cores/maple/libmaple/stm32.h index 0d4deaa..3921788 100644 --- a/STM32F4/cores/maple/libmaple/stm32.h +++ b/STM32F4/cores/maple/libmaple/stm32.h @@ -138,69 +138,8 @@ #endif -#if defined(MCU_STM32F103RB) - /* e.g., LeafLabs Maple */ - #define STM32_NR_GPIO_PORTS 4 - #define STM32_DELAY_US_MULT 12 - #define STM32_SRAM_END ((void*)0x20005000) - - #define NR_GPIO_PORTS STM32_NR_GPIO_PORTS - #define DELAY_US_MULT STM32_DELAY_US_MULT - -#elif defined(MCU_STM32F103ZE) - /* e.g., LeafLabs Maple Native */ - - #define STM32_NR_GPIO_PORTS 7 - #define STM32_DELAY_US_MULT 12 - #define STM32_SRAM_END ((void*)0x20010000) - - #define NR_GPIO_PORTS STM32_NR_GPIO_PORTS - #define DELAY_US_MULT STM32_DELAY_US_MULT - -#elif defined(MCU_STM32F103CB) - /* e.g., LeafLabs Maple Mini */ - - /* This STM32_NR_GPIO_PORTS value is not, strictly speaking, true. - * But only pins 0 and 1 exist, and they're used for OSC on the - * Mini, so we'll live with this for now. */ - #define STM32_NR_GPIO_PORTS 3 - #define STM32_DELAY_US_MULT 12 - #define STM32_SRAM_END ((void*)0x20005000) - - #define NR_GPIO_PORTS STM32_NR_GPIO_PORTS - #define DELAY_US_MULT STM32_DELAY_US_MULT - -#elif defined(MCU_STM32F103RE) - /* e.g., LeafLabs Maple RET6 edition */ - - #define STM32_NR_GPIO_PORTS 4 - #define STM32_DELAY_US_MULT 12 - #define STM32_SRAM_END ((void*)0x20010000) - - #define NR_GPIO_PORTS STM32_NR_GPIO_PORTS - #define DELAY_US_MULT STM32_DELAY_US_MULT - -#elif defined(MCU_STM32F103VE) - /* e.g., LeafLabs Maple Native */ - - #define STM32_NR_GPIO_PORTS 5 - #define STM32_DELAY_US_MULT 12 - #define STM32_SRAM_END ((void*)0x20010000) - - #define NR_GPIO_PORTS STM32_NR_GPIO_PORTS - #define DELAY_US_MULT STM32_DELAY_US_MULT - -#elif defined(MCU_STM32F205VE) - #define STM32_TICKS_PER_US 120 - #define STM32_NR_GPIO_PORTS 5 - #define STM32_DELAY_US_MULT (STM32_TICKS_PER_US/3) - #define STM32_SRAM_END ((void*)0x20010000) - - #define NR_GPIO_PORTS STM32_NR_GPIO_PORTS - #define DELAY_US_MULT STM32_DELAY_US_MULT - -#elif defined(MCU_STM32F406VG) +#if defined( STM32F4 ) #define STM32_TICKS_PER_US 168 #define STM32_NR_GPIO_PORTS 5 #define STM32_DELAY_US_MULT (STM32_TICKS_PER_US/3) diff --git a/STM32F4/cores/maple/libmaple/timer.c b/STM32F4/cores/maple/libmaple/timer.c index 83e9ace..f8e55a1 100644 --- a/STM32F4/cores/maple/libmaple/timer.c +++ b/STM32F4/cores/maple/libmaple/timer.c @@ -44,7 +44,7 @@ /* Update only. */ #define NR_BAS_HANDLERS 1 -static timer_dev timer1 = { +timer_dev timer1 = { .regs = { .adv = TIMER1_BASE }, .clk_id = RCC_TIMER1, .type = TIMER_ADVANCED, @@ -53,7 +53,7 @@ static timer_dev timer1 = { /** Timer 1 device (advanced) */ timer_dev *TIMER1 = &timer1; -static timer_dev timer2 = { +timer_dev timer2 = { .regs = { .gen = TIMER2_BASE }, .clk_id = RCC_TIMER2, .type = TIMER_GENERAL, @@ -62,7 +62,7 @@ static timer_dev timer2 = { /** Timer 2 device (general-purpose) */ timer_dev *TIMER2 = &timer2; -static timer_dev timer3 = { +timer_dev timer3 = { .regs = { .gen = TIMER3_BASE }, .clk_id = RCC_TIMER3, .type = TIMER_GENERAL, @@ -71,7 +71,7 @@ static timer_dev timer3 = { /** Timer 3 device (general-purpose) */ timer_dev *TIMER3 = &timer3; -static timer_dev timer4 = { +timer_dev timer4 = { .regs = { .gen = TIMER4_BASE }, .clk_id = RCC_TIMER4, .type = TIMER_GENERAL, @@ -81,7 +81,7 @@ static timer_dev timer4 = { timer_dev *TIMER4 = &timer4; #ifdef STM32_HIGH_DENSITY -static timer_dev timer5 = { +timer_dev timer5 = { .regs = { .gen = TIMER5_BASE }, .clk_id = RCC_TIMER5, .type = TIMER_GENERAL, @@ -90,7 +90,7 @@ static timer_dev timer5 = { /** Timer 5 device (general-purpose) */ timer_dev *TIMER5 = &timer5; -static timer_dev timer6 = { +timer_dev timer6 = { .regs = { .bas = TIMER6_BASE }, .clk_id = RCC_TIMER6, .type = TIMER_BASIC, @@ -99,7 +99,7 @@ static timer_dev timer6 = { /** Timer 6 device (basic) */ timer_dev *TIMER6 = &timer6; -static timer_dev timer7 = { +timer_dev timer7 = { .regs = { .bas = TIMER7_BASE }, .clk_id = RCC_TIMER7, .type = TIMER_BASIC, @@ -108,7 +108,7 @@ static timer_dev timer7 = { /** Timer 7 device (basic) */ timer_dev *TIMER7 = &timer7; -static timer_dev timer8 = { +timer_dev timer8 = { .regs = { .adv = TIMER8_BASE }, .clk_id = RCC_TIMER8, .type = TIMER_ADVANCED, diff --git a/STM32F4/cores/maple/libmaple/timer.h b/STM32F4/cores/maple/libmaple/timer.h index fce6345..79b7d29 100644 --- a/STM32F4/cores/maple/libmaple/timer.h +++ b/STM32F4/cores/maple/libmaple/timer.h @@ -113,13 +113,8 @@ typedef struct timer_bas_reg_map { } timer_bas_reg_map; -#ifdef STM32F2 - /** Timer 1 register map base pointer */ - #define TIMER1_BASE ((struct timer_adv_reg_map*)0x40010000) -#else - /** Timer 1 register map base pointer */ - #define TIMER1_BASE ((struct timer_adv_reg_map*)0x40012C00) -#endif +/** Timer 1 register map base pointer */ +#define TIMER1_BASE ((struct timer_adv_reg_map*)0x40010000) /** Timer 2 register map base pointer */ #define TIMER2_BASE ((struct timer_gen_reg_map*)0x40000000) /** Timer 3 register map base pointer */ @@ -133,14 +128,8 @@ typedef struct timer_bas_reg_map { #define TIMER6_BASE ((struct timer_bas_reg_map*)0x40001000) /** Timer 7 register map base pointer */ #define TIMER7_BASE ((struct timer_bas_reg_map*)0x40001400) - -#ifdef STM32F2 - /** Timer 8 register map base pointer */ - #define TIMER8_BASE ((struct timer_adv_reg_map*)0x40010400) -#else - /** Timer 8 register map base pointer */ - #define TIMER8_BASE ((struct timer_adv_reg_map*)0x40013400) -#endif +/** Timer 8 register map base pointer */ +#define TIMER8_BASE ((struct timer_adv_reg_map*)0x40010400) #endif /* diff --git a/STM32F4/cores/maple/libmaple/usart.h b/STM32F4/cores/maple/libmaple/usart.h index 3f7c885..282293a 100644 --- a/STM32F4/cores/maple/libmaple/usart.h +++ b/STM32F4/cores/maple/libmaple/usart.h @@ -62,11 +62,7 @@ typedef struct usart_reg_map { } usart_reg_map; /** USART1 register map base pointer */ -#ifdef STM32F2 - #define USART1_BASE ((struct usart_reg_map*)0x40011000) -#else - #define USART1_BASE ((struct usart_reg_map*)0x40013800) -#endif +#define USART1_BASE ((struct usart_reg_map*)0x40011000) /** USART2 register map base pointer */ #define USART2_BASE ((struct usart_reg_map*)0x40004400) /** USART3 register map base pointer */ diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/audio/inc/usbd_audio_core.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/audio/inc/usbd_audio_core.h index f58ff06..7ac987d 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/audio/inc/usbd_audio_core.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/audio/inc/usbd_audio_core.h @@ -26,7 +26,7 @@ #include "usbd_ioreq.h" #include "usbd_req.h" -#include "usbd_desc.h" +#include diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/inc/usbd_cdc_core.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/inc/usbd_cdc_core.h index 926f42e..b1c8cc1 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/inc/usbd_cdc_core.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/inc/usbd_cdc_core.h @@ -24,7 +24,8 @@ #ifndef __USB_CDC_CORE_H_ #define __USB_CDC_CORE_H_ -#include "usbd_ioreq.h" +#include +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/src/usbd_cdc_core.c b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/src/usbd_cdc_core.c index aac6776..8f97c51 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/src/usbd_cdc_core.c +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/src/usbd_cdc_core.c @@ -58,9 +58,10 @@ */ /* Includes ------------------------------------------------------------------*/ -#include "usbd_cdc_core.h" -#include "usbd_desc.h" -#include "usbd_req.h" +#include +#include +#include +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_core.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_core.h index b876856..063a30e 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_core.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_core.h @@ -24,9 +24,9 @@ #define __USBD_CORE_H /* Includes ------------------------------------------------------------------*/ -#include "usb_dcd.h" +#include #include "usbd_def.h" -#include "usbd_conf.h" +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_def.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_def.h index a8c8671..f2a3115 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_def.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_def.h @@ -24,7 +24,7 @@ #ifndef __USBD_DEF_H #define __USBD_DEF_H /* Includes ------------------------------------------------------------------*/ -#include "usbd_conf.h" +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_req.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_req.h index 9aa9e44..f9849c6 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_req.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_req.h @@ -27,7 +27,7 @@ /* Includes ------------------------------------------------------------------*/ #include "usbd_def.h" #include "usbd_core.h" -#include "usbd_conf.h" +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_core.c b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_core.c index af75842..00bb251 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_core.c +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_core.c @@ -20,11 +20,11 @@ */ /* Includes ------------------------------------------------------------------*/ -#include "usbd_core.h" -#include "usbd_req.h" -#include "usbd_ioreq.h" -#include "usb_dcd_int.h" -#include "usb_bsp.h" +#include +#include +#include +#include +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_ioreq.c b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_ioreq.c index 6964766..20ee5a0 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_ioreq.c +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_ioreq.c @@ -20,7 +20,7 @@ */ /* Includes ------------------------------------------------------------------*/ -#include "usbd_ioreq.h" +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @{ */ diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_req.c b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_req.c index f08d26c..5fc2e03 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_req.c +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_req.c @@ -20,9 +20,9 @@ */ /* Includes ------------------------------------------------------------------*/ -#include "usbd_req.h" -#include "usbd_ioreq.h" -#include "usbd_desc.h" +#include +#include +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_core.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_core.h index 82a09e1..43c4781 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_core.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_core.h @@ -24,7 +24,7 @@ #define __USB_CORE_H__ /* Includes ------------------------------------------------------------------*/ -#include "usb_conf.h" +#include #include "usb_regs.h" #include "usb_defines.h" diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_defines.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_defines.h index 8c23d72..ee2c1a0 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_defines.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_defines.h @@ -24,7 +24,7 @@ #define __USB_DEF_H__ /* Includes ------------------------------------------------------------------*/ -#include "usb_conf.h" +#include /** @addtogroup USB_OTG_DRIVER * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_otg.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_otg.h index 54d61b8..1347f31 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_otg.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_otg.h @@ -23,6 +23,7 @@ #ifndef __USB_OTG__ #define __USB_OTG__ +#include "usb_core.h" /** @addtogroup USB_OTG_DRIVER * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_regs.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_regs.h index cd71ddf..99f844e 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_regs.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_regs.h @@ -24,8 +24,8 @@ #define __USB_OTG_REGS_H__ /* Includes ------------------------------------------------------------------*/ -#include "usb_conf.h" - +#include +#include /** @addtogroup USB_OTG_DRIVER * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_core.c b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_core.c index cb9eabc..1687afa 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_core.c +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_core.c @@ -20,8 +20,8 @@ */ /* Includes ------------------------------------------------------------------*/ -#include "usb_bsp.h" -#include "usb_core.h" +#include +#include /** @addtogroup USB_OTG_DRIVER diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_dcd.c b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_dcd.c index c3336cb..dc9e538 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_dcd.c +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_dcd.c @@ -20,8 +20,8 @@ */ /* Includes ------------------------------------------------------------------*/ -#include "usb_dcd.h" -#include "usb_bsp.h" +#include +#include /** @addtogroup USB_OTG_DRIVER diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_dcd_int.c b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_dcd_int.c index 3a49ede..f9e561f 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_dcd_int.c +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_dcd_int.c @@ -20,12 +20,12 @@ */ /* Includes ------------------------------------------------------------------*/ -#include "usb_dcd_int.h" +#include typedef int IRQn_Type; #define __NVIC_PRIO_BITS 4 #define __Vendor_SysTickConfig 1 -#include +#include /** @addtogroup USB_OTG_DRIVER diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/core_cm4.h b/STM32F4/cores/maple/libmaple/usbF4/VCP/core_cm4.h index 443665c..ff5e9a6 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/core_cm4.h +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/core_cm4.h @@ -141,7 +141,7 @@ #endif #include /*!< standard types definitions */ -#include /*!< Core Instruction Access */ +#include "core_cmInstr.h" /*!< Core Instruction Access */ //#include /*!< Core Function Access */ //#include /*!< Compiler specific SIMD Intrinsics */ diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/misc.c b/STM32F4/cores/maple/libmaple/usbF4/VCP/misc.c index 9f33150..15a715e 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/misc.c +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/misc.c @@ -80,7 +80,7 @@ typedef unsigned char u8; typedef int IRQn_Type; #define __NVIC_PRIO_BITS 4 #define __Vendor_SysTickConfig 1 -#include +#include "core_cm4.h" /** @addtogroup STM32F4xx_StdPeriph_Driver * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/usb_bsp.c b/STM32F4/cores/maple/libmaple/usbF4/VCP/usb_bsp.c index df23ccb..e794cb1 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/usb_bsp.c +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/usb_bsp.c @@ -21,13 +21,13 @@ */ /* Includes ------------------------------------------------------------------*/ -#include "usb_bsp.h" +#include #include "usbd_conf.h" -#include +#include typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState; #define OTG_FS_IRQn 67 //typedef unsigned char uint8_t; -#include +#include "misc.h" //#include "stm32f4_discovery.h" @@ -97,10 +97,10 @@ void USB_OTG_BSP_Init(USB_OTG_CORE_HANDLE *pdev) { // ala42 #define GPIO_AF_OTG1_FS ((uint8_t)0xA) /* OTG_FS Alternate Function mapping */ - gpio_set_mode(GPIOA,11,GPIO_MODE_AF | GPIO_OTYPE_PP | GPIO_OSPEED_100MHZ); - gpio_set_mode(GPIOA,12,GPIO_MODE_AF | GPIO_OTYPE_PP | GPIO_OSPEED_100MHZ); - gpio_set_af_mode(GPIOA,11,GPIO_AF_OTG1_FS) ; // OTG_FS_DM - gpio_set_af_mode(GPIOA,12,GPIO_AF_OTG1_FS) ; // OTG_FS_DP + gpio_set_mode(BOARD_USB_DM_PIN,GPIO_MODE_AF | GPIO_OTYPE_PP | GPIO_OSPEED_100MHZ); + gpio_set_mode(BOARD_USB_DP_PIN,GPIO_MODE_AF | GPIO_OTYPE_PP | GPIO_OSPEED_100MHZ); + gpio_set_af_mode(BOARD_USB_DM_PIN,GPIO_AF_OTG1_FS) ; // OTG_FS_DM + gpio_set_af_mode(BOARD_USB_DP_PIN,GPIO_AF_OTG1_FS) ; // OTG_FS_DP #ifdef USB_OTG_FS_SOF_OUTPUT_ENABLED gpio_set_mode(GPIOA, 8,GPIO_MODE_AF | GPIO_OTYPE_PP | GPIO_OSPEED_100MHZ); gpio_set_af_mode(GPIOA, 8,GPIO_AF_OTG1_FS) ; // OTG_FS_SOF @@ -122,10 +122,10 @@ void USB_OTG_BSP_DeInit(USB_OTG_CORE_HANDLE *pdev) { // ala42 #define GPIO_AF0 ((uint8_t)0) /* OTG_FS Alternate Function mapping */ - gpio_set_mode(GPIOA,11, GPIO_MODE_INPUT); - gpio_set_mode(GPIOA,12, GPIO_MODE_INPUT); - gpio_set_af_mode(GPIOA,11,GPIO_AF0) ; // OTG_FS_DM - gpio_set_af_mode(GPIOA,12,GPIO_AF0) ; // OTG_FS_DP + gpio_set_mode(BOARD_USB_DM_PIN, GPIO_MODE_INPUT); + gpio_set_mode(BOARD_USB_DP_PIN, GPIO_MODE_INPUT); + gpio_set_af_mode(BOARD_USB_DM_PIN,GPIO_AF0) ; // OTG_FS_DM + gpio_set_af_mode(BOARD_USB_DP_PIN,GPIO_AF0) ; // OTG_FS_DP #ifdef USB_OTG_FS_SOF_OUTPUT_ENABLED gpio_set_mode(GPIOA, 8,GPIO_MODE_INPUT); gpio_set_af_mode(GPIOA, 8,GPIO_AF0) ; // OTG_FS_SOF diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/usb_conf.h b/STM32F4/cores/maple/libmaple/usbF4/VCP/usb_conf.h index 61b0ac5..fd45f4d 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/usb_conf.h +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/usb_conf.h @@ -173,7 +173,9 @@ typedef unsigned char u8; #elif defined (__ICCARM__) /* IAR Compiler */ #define __packed __packed #elif defined ( __GNUC__ ) /* GNU Compiler */ + #ifndef __packed #define __packed __attribute__ ((__packed__)) + #endif #elif defined (__TASKING__) /* TASKING Compiler */ #define __packed __unaligned #endif /* __CC_ARM */ @@ -206,7 +208,9 @@ typedef unsigned char u8; #elif defined (__ICCARM__) /* IAR Compiler */ #define __packed __packed #elif defined ( __GNUC__ ) /* GNU Compiler */ + #ifndef __packed #define __packed __attribute__ ((__packed__)) + #endif #elif defined (__TASKING__) /* TASKING Compiler */ #define __packed __unaligned #endif /* __CC_ARM */ diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.c b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.c index b13260e..28a2d1f 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.c +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.c @@ -255,7 +255,7 @@ typedef struct { void systemHardReset(void) { SCB_TypeDef* rSCB = (SCB_TypeDef *) SCB_BASE; - typedef void (*funcPtr)(void); + //typedef void (*funcPtr)(void); // not used /* Reset */ rSCB->AIRCR = (u32)AIRCR_RESET_REQ; diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.h b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.h index 67475e7..8398dbd 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.h +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.h @@ -26,7 +26,7 @@ /* Includes ------------------------------------------------------------------*/ //#include "stm32f4xx.h" -#include "usbd_cdc_core.h" +#include #include "usbd_conf.h" diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_conf.h b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_conf.h index 516a2fb..62a40c2 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_conf.h +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_conf.h @@ -25,6 +25,7 @@ /* Includes ------------------------------------------------------------------*/ //#include "stm32f4_discovery.h" +#include "usb_conf.h" /** @defgroup USB_CONF_Exported_Defines * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.c b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.c index 537f266..0153858 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.c +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.c @@ -20,11 +20,11 @@ */ /* Includes ------------------------------------------------------------------*/ -#include "usbd_core.h" +#include #include "usbd_desc.h" -#include "usbd_req.h" +#include #include "usbd_conf.h" -#include "usb_regs.h" +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.h b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.h index ed999dc..4ae998c 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.h +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.h @@ -25,7 +25,7 @@ #define __USB_DESC_H /* Includes ------------------------------------------------------------------*/ -#include "usbd_def.h" +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_usr.c b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_usr.c index 84e8d6a..a16ce40 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_usr.c +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_usr.c @@ -20,8 +20,8 @@ */ /* Includes ------------------------------------------------------------------*/ -#include "usbd_usr.h" -#include "usbd_ioreq.h" +#include +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY diff --git a/STM32F4/cores/maple/libmaple/usbF4/usb.c b/STM32F4/cores/maple/libmaple/usbF4/usb.c index 2c0672f..3850719 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/usb.c +++ b/STM32F4/cores/maple/libmaple/usbF4/usb.c @@ -1,27 +1,30 @@ -#include "usbd_cdc_core.h" -#include "usbd_usr.h" -#include "usbd_desc.h" +#ifndef _USBF4_USB_H_ +#define _USBF4_USB_H_ + + +#include +#include +#include #include "usb.h" -#include -#include -#include +#include +#include +#include +#include USB_OTG_CORE_HANDLE USB_OTG_dev; -void setupUSB (void) { - #define USB_DISC_DEV GPIOD - #define USB_DISC_PIN 11 - - gpio_set_mode(USB_DISC_DEV, USB_DISC_PIN, GPIO_OUTPUT_OD); // ala42 +void setupUSB (void) +{ + gpio_set_mode(BOARD_USB_DP_PIN, GPIO_OUTPUT_OD); // ala42 #ifdef USB_DISC_OD //gpio_set_mode(USB_DISC_DEV, USB_DISC_PIN, GPIO_OUTPUT_OD); // ala42 #else //gpio_set_mode(USB_DISC_DEV, USB_DISC_PIN, GPIO_OUTPUT_PP); // ala42 for active pull-up on disconnect pin #endif - gpio_write_bit(USB_DISC_DEV, USB_DISC_PIN,0); // ala42 + gpio_clear_pin(BOARD_USB_DP_PIN); // ala42 delay_us(200000); /* setup the apb1 clock for USB */ @@ -29,7 +32,7 @@ void setupUSB (void) { //pRCC->APB1ENR |= RCC_APB1ENR_USBEN; /* initialize the usb application */ - gpio_write_bit(USB_DISC_DEV, USB_DISC_PIN, 1); // ala42 // presents us to the host + gpio_set_pin(BOARD_USB_DP_PIN); // ala42 // presents us to the host USBD_Init(&USB_OTG_dev, USB_OTG_FS_CORE_ID, &USR_desc, @@ -93,7 +96,7 @@ RESULT usbPowerOff(void) { void usbDsbISR(void) {}; -#include "usb_dcd_int.h" +#include void __irq_OTG_FS_IRQHandler(void) { USBD_OTG_ISR_Handler (&USB_OTG_dev); @@ -102,3 +105,5 @@ void __irq_OTG_FS_IRQHandler(void) void x__irq_usbwakeup(void) { } + +#endif diff --git a/STM32F4/cores/maple/libmaple/usbF4/usb.h b/STM32F4/cores/maple/libmaple/usbF4/usb.h index f09f2bd..ce1a558 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/usb.h +++ b/STM32F4/cores/maple/libmaple/usbF4/usb.h @@ -5,7 +5,7 @@ extern "C" { #endif -#include "usb_conf.h" +#include typedef enum _RESULT { diff --git a/STM32F4/cores/maple/libmaple/util.c b/STM32F4/cores/maple/libmaple/util.c index 8c03e18..8a745e8 100644 --- a/STM32F4/cores/maple/libmaple/util.c +++ b/STM32F4/cores/maple/libmaple/util.c @@ -128,7 +128,7 @@ void throb(void) { uint32 TOP_CNT = 0x0800; uint32 i = 0; - gpio_set_mode(ERROR_LED_PORT, ERROR_LED_PIN, GPIO_OUTPUT_PP); + gpio_set_mode(ERROR_LED_PIN, GPIO_OUTPUT_PP); /* Error fade. */ while (1) { if (CC == TOP_CNT) { @@ -143,9 +143,9 @@ void throb(void) { } if (i < CC) { - gpio_write_bit(ERROR_LED_PORT, ERROR_LED_PIN, 1); + gpio_set_pin(ERROR_LED_PIN); } else { - gpio_write_bit(ERROR_LED_PORT, ERROR_LED_PIN, 0); + gpio_clear_pin(ERROR_LED_PIN); } i++; } diff --git a/STM32F4/cores/maple/libmaple/util.h b/STM32F4/cores/maple/libmaple/util.h index 62ad8af..c5ed2de 100644 --- a/STM32F4/cores/maple/libmaple/util.h +++ b/STM32F4/cores/maple/libmaple/util.h @@ -29,11 +29,12 @@ * @brief Miscellaneous utility macros and procedures. */ -#include "libmaple_types.h" - #ifndef _UTIL_H_ #define _UTIL_H_ +#include "libmaple_types.h" +#include "delay.h" + #ifdef __cplusplus extern "C"{ #endif diff --git a/STM32F4/cores/maple/pwm.cpp b/STM32F4/cores/maple/pwm.cpp index 1806348..c5f2ccb 100644 --- a/STM32F4/cores/maple/pwm.cpp +++ b/STM32F4/cores/maple/pwm.cpp @@ -28,8 +28,8 @@ * @brief Arduino-style PWM implementation. */ -#include "libmaple_types.h" -#include "timer.h" +#include +#include #include "boards.h" #include "pwm.h" diff --git a/STM32F4/cores/maple/usb_serial.cpp b/STM32F4/cores/maple/usb_serial.cpp index cc726c2..fadcb91 100644 --- a/STM32F4/cores/maple/usb_serial.cpp +++ b/STM32F4/cores/maple/usb_serial.cpp @@ -33,6 +33,8 @@ #include "wirish.h" #include "usb.h" +#ifdef SERIAL_USB + #define USB_TIMEOUT 50 USBSerial::USBSerial(void) { @@ -132,7 +134,7 @@ uint8 USBSerial::pending(void) { return usbGetPending(); } -uint8 USBSerial::isConnected(void) { +USBSerial::operator bool() { return usbIsConnected() && usbIsConfigured(); } @@ -153,3 +155,5 @@ void USBSerial::disableBlockingTx(void) { } USBSerial SerialUSB; + +#endif diff --git a/STM32F4/cores/maple/usb_serial.h b/STM32F4/cores/maple/usb_serial.h index a551e9d..8eeed96 100644 --- a/STM32F4/cores/maple/usb_serial.h +++ b/STM32F4/cores/maple/usb_serial.h @@ -33,6 +33,8 @@ #include "Stream.h" +#ifdef SERIAL_USB + /** * @brief Virtual serial terminal. */ @@ -57,7 +59,8 @@ public: uint8 getRTS(); uint8 getDTR(); - uint8 isConnected(); + operator bool(); + uint8 isConnected() { return (bool) *this; } uint8 pending(); void enableBlockingTx(void); @@ -65,6 +68,14 @@ public: }; extern USBSerial SerialUSB; +#define Serial SerialUSB -#endif +#else // _USB_SERIAL_H_ + +#define Serial Serial1 + +#endif // SERIAL_USB + + +#endif // _USB_SERIAL_H_ diff --git a/STM32F4/cores/maple/wirish.h b/STM32F4/cores/maple/wirish.h index 4aca74c..945e8fb 100644 --- a/STM32F4/cores/maple/wirish.h +++ b/STM32F4/cores/maple/wirish.h @@ -34,9 +34,9 @@ #define _WIRISH_H_ #include -#include "libmaple.h" +#include +#include -#include "wirish_types.h" #include "boards.h" #include "io.h" #include "bits.h" @@ -44,10 +44,8 @@ #include "ext_interrupts.h" #include "wirish_debug.h" #include "wirish_math.h" -#include "wirish_time.h" #include -#include "HardwareSPI.h" -#include "HardwareSerial.h" +#include #include "HardwareTimer.h" #include "usb_serial.h" @@ -55,9 +53,10 @@ #define HIGH 0x1 #define LOW 0x0 -#define true 0x1 -#define false 0x0 - +#ifndef true + #define true 0x1 + #define false 0x0 +#endif #define lowByte(w) ((w) & 0xFF) #define highByte(w) (((w) >> 8) & 0xFF) diff --git a/STM32F4/cores/maple/wirish_analog.cpp b/STM32F4/cores/maple/wirish_analog.cpp index 63b5eb2..4e920e7 100644 --- a/STM32F4/cores/maple/wirish_analog.cpp +++ b/STM32F4/cores/maple/wirish_analog.cpp @@ -28,9 +28,7 @@ * @brief Arduino-compatible ADC implementation. */ -#include "libmaple.h" #include "wirish.h" -#include "io.h" /* Assumes that the ADC has been initialized and that the pin is set * to INPUT_ANALOG */ diff --git a/STM32F4/cores/maple/wirish_constants.h b/STM32F4/cores/maple/wirish_constants.h index 06a85ae..f39c077 100644 --- a/STM32F4/cores/maple/wirish_constants.h +++ b/STM32F4/cores/maple/wirish_constants.h @@ -1,5 +1,5 @@ -#ifndef _WIRING_CONSTANTS_ -#define _WIRING_CONSTANTS_ +#ifndef _WIRISH_CONSTANTS_H_ +#define _WIRISH_CONSTANTS_H_ #ifdef __cplusplus extern "C"{ diff --git a/STM32F4/cores/maple/wirish_debug.h b/STM32F4/cores/maple/wirish_debug.h index d4c0bab..d7dea23 100644 --- a/STM32F4/cores/maple/wirish_debug.h +++ b/STM32F4/cores/maple/wirish_debug.h @@ -24,6 +24,9 @@ * SOFTWARE. *****************************************************************************/ +#ifndef _WIRISH_DEBUG_H_ +#define _WIRISH_DEBUG_H_ + /** * @file wirish_debug.h * @brief High level debug port configuration @@ -50,5 +53,7 @@ static inline void disableDebugPorts(void) { * @see disableDebugPorts() */ static inline void enableDebugPorts(void) { - afio_cfg_debug_ports(AFIO_DEBUG_FULL_SWJ); + afio_cfg_debug_ports(AFIO_DEBUG_SW_ONLY); //AFIO_DEBUG_FULL_SWJ); } + +#endif diff --git a/STM32F4/cores/maple/wirish_digital.cpp b/STM32F4/cores/maple/wirish_digital.cpp index a8b3ad8..4a65619 100644 --- a/STM32F4/cores/maple/wirish_digital.cpp +++ b/STM32F4/cores/maple/wirish_digital.cpp @@ -29,7 +29,7 @@ */ #include "wirish.h" -#include "io.h" + void pinMode(uint8 pin, WiringPinMode mode) { gpio_pin_mode outputMode; @@ -72,7 +72,7 @@ void pinMode(uint8 pin, WiringPinMode mode) { return; } - gpio_set_mode(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit, outputMode); + gpio_set_mode(pin, outputMode); if (PIN_MAP[pin].timer_device != NULL) { /* Enable/disable timer channels if we're switching into or @@ -84,48 +84,51 @@ void pinMode(uint8 pin, WiringPinMode mode) { } -uint32 digitalRead(uint8 pin) { +uint32 digitalRead(uint8 pin) +{ if (pin >= BOARD_NR_GPIO_PINS) { return 0; } - return gpio_read_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit) ? + return gpio_read_pin(pin) ? HIGH : LOW; } -void digitalWrite(uint8 pin, uint8 val) { +void digitalWrite(uint8 pin, uint8 val) +{ if (pin >= BOARD_NR_GPIO_PINS) { return; } - gpio_write_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit, val); + gpio_write_pin(pin, val); } -void togglePin(uint8 pin) { +void togglePin(uint8 pin) +{ if (pin >= BOARD_NR_GPIO_PINS) { return; } - gpio_toggle_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit); + gpio_toggle_pin(pin); } #define BUTTON_DEBOUNCE_DELAY 1 -uint8 isButtonPressed() { - if (digitalRead(BOARD_BUTTON_PIN)) { +uint8 isButtonPressed(uint8_t button) { + if (digitalRead(button)) { delay(BUTTON_DEBOUNCE_DELAY); - while (digitalRead(BOARD_BUTTON_PIN)) + while (digitalRead(button)) ; return true; } return false; } -uint8 waitForButtonPress(uint32 timeout) { +uint8 waitForButtonPress(uint8_t button, uint32 timeout) { uint32 start = millis(); uint32 time; if (timeout == 0) { - while (!isButtonPressed()) + while (!isButtonPressed(button)) ; return true; } @@ -136,6 +139,6 @@ uint8 waitForButtonPress(uint32 timeout) { time - start > timeout) { return false; } - } while (!isButtonPressed()); + } while (!isButtonPressed(button)); return true; } diff --git a/STM32F4/cores/maple/wirish_math.h b/STM32F4/cores/maple/wirish_math.h index a85b30a..0b8b222 100644 --- a/STM32F4/cores/maple/wirish_math.h +++ b/STM32F4/cores/maple/wirish_math.h @@ -29,8 +29,8 @@ * @brief Includes ; provides Arduino-compatible math routines. */ -#ifndef _WIRING_MATH_H_ -#define _WIRING_MATH_H_ +#ifndef _WIRISH_MATH_H_ +#define _WIRISH_MATH_H_ #include diff --git a/STM32F4/cores/maple/wirish_time.cpp b/STM32F4/cores/maple/wirish_time.cpp index 270da28..654c1a2 100644 --- a/STM32F4/cores/maple/wirish_time.cpp +++ b/STM32F4/cores/maple/wirish_time.cpp @@ -28,10 +28,10 @@ * @brief Delay implementation. */ -#include "libmaple.h" -#include "systick.h" +#include +#include #include "wirish_time.h" -#include "delay.h" +#include void delay(unsigned long ms) { uint32 i; diff --git a/STM32F4/cores/maple/wirish_time.h b/STM32F4/cores/maple/wirish_time.h index 20a2fbf..3a11786 100644 --- a/STM32F4/cores/maple/wirish_time.h +++ b/STM32F4/cores/maple/wirish_time.h @@ -32,10 +32,9 @@ #ifndef __WIRISH_TIME_H_ #define __WIRISH_TIME_H_ -#include "libmaple.h" -#include "nvic.h" -#include "systick.h" #include "boards.h" +#include +#include #define US_PER_MS 1000 diff --git a/STM32F4/cores/maple/wirish_types.h b/STM32F4/cores/maple/wirish_types.h index a3c260a..6a8c85c 100644 --- a/STM32F4/cores/maple/wirish_types.h +++ b/STM32F4/cores/maple/wirish_types.h @@ -30,14 +30,13 @@ * @brief Wirish library type definitions. */ -#include "libmaple_types.h" -#include "gpio.h" -#include "timer.h" -#include "adc.h" - #ifndef _WIRISH_TYPES_H_ #define _WIRISH_TYPES_H_ +#include +#include +#include + /** * Invalid stm32_pin_info adc_channel value. * @see stm32_pin_info @@ -48,6 +47,18 @@ * @brief Stores STM32-specific information related to a given Maple pin. * @see PIN_MAP */ +#ifdef BOARD_generic_f407v +// restructure members to build consecutive pairs +typedef struct stm32_pin_info { + const gpio_dev * gpio_device; /**< Maple pin's GPIO device */ + timer_dev * timer_device; /**< Pin's timer device, if any. */ + uint8 timer_channel; /**< Timer channel, or 0 if none. */ + uint8 adc_channel; /**< Pin ADC channel, or ADCx if none. */ + const adc_dev *adc_device; /**< ADC device, if any. */ +} stm32_pin_info; + +#else + typedef struct stm32_pin_info { gpio_dev *gpio_device; /**< Maple pin's GPIO device */ timer_dev *timer_device; /**< Pin's timer device, if any. */ @@ -58,6 +69,8 @@ typedef struct stm32_pin_info { uint8 filler; } stm32_pin_info; +#endif + /** * Variable attribute, instructs the linker to place the marked * variable in Flash instead of RAM. */ diff --git a/STM32F4/libraries/SPI/library.properties b/STM32F4/libraries/SPI/library.properties index 6f20f01..ba3a577 100644 --- a/STM32F4/libraries/SPI/library.properties +++ b/STM32F4/libraries/SPI/library.properties @@ -7,3 +7,4 @@ paragraph=SPI for STM32F4 category=Communication url= architectures=STM32F4 +maintainer= \ No newline at end of file diff --git a/STM32F4/libraries/SPI/src/SPI.cpp b/STM32F4/libraries/SPI/src/SPI.cpp index 08fbbd5..cb8f561 100644 --- a/STM32F4/libraries/SPI/src/SPI.cpp +++ b/STM32F4/libraries/SPI/src/SPI.cpp @@ -40,9 +40,9 @@ #include "wirish.h" #include "boards.h" -//#include "HardwareSerial.h" +#define DMA_TIMEOUT 100 -#if CYCLES_PER_MICROSECOND != 72 +#if CYCLES_PER_MICROSECOND != 168 /* TODO [0.2.0?] something smarter than this */ #warning "Unexpected clock speed; SPI frequency calculation will be incorrect" #endif @@ -91,77 +91,115 @@ static const spi_pins board_spi_pins[] __FLASH__ = { */ SPIClass::SPIClass(uint32 spi_num) { + + _currentSetting=&_settings[spi_num-1];// SPI channels are called 1 2 and 3 but the array is zero indexed + + switch (spi_num) { #if BOARD_NR_SPI >= 1 case 1: - this->spi_d = SPI1; + _currentSetting->spi_d = SPI1; break; #endif #if BOARD_NR_SPI >= 2 case 2: - this->spi_d = SPI2; + _currentSetting->spi_d = SPI2; break; #endif #if BOARD_NR_SPI >= 3 case 3: - this->spi_d = SPI3; + _currentSetting->spi_d = SPI3; break; #endif default: ASSERT(0); } - //pinMode(BOARD_SPI_DEFAULT_SS,OUTPUT); - - clockDivider = SPI_BAUD_PCLK_DIV_16; - dataMode = SPI_MODE0; + // Init things specific to each SPI device + // clock divider setup is a bit of hack, and needs to be improved at a later date. +/*****************************************************************************/ +// DMA / Channel / Stream +// Rx Tx +// SPI1: 2 / 3 / 0 (2) - 2 / 3 / 3 (5) +// SPI2: 1 / 0 / 3 - 1 / 0 / 4 +// SPI3: 1 / 0 / 0 (2) - 1 / 0 / 5 (7) +/*****************************************************************************/ + _settings[0].spi_d = SPI1; + _settings[0].clockDivider = determine_baud_rate(_settings[0].spi_d, _settings[0].clock); +#ifdef SPI_DMA + _settings[0].spiDmaDev = DMA2; + _settings[0].spiDmaChannel = DMA_CH3; + _settings[0].spiRxDmaStream = DMA_STREAM0; // alternative: DMA_STREAM2 + _settings[0].spiTxDmaStream = DMA_STREAM3; // alternative: DMA_STREAM5 +#endif + _settings[1].spi_d = SPI2; + _settings[1].clockDivider = determine_baud_rate(_settings[1].spi_d, _settings[1].clock); +#ifdef SPI_DMA + _settings[1].spiDmaDev = DMA1; + _settings[1].spiDmaChannel = DMA_CH0; + _settings[1].spiRxDmaStream = DMA_STREAM3; // alternative: - + _settings[1].spiTxDmaStream = DMA_STREAM4; // alternative: - +#endif +#if BOARD_NR_SPI >= 3 + _settings[2].spi_d = SPI3; + _settings[2].clockDivider = determine_baud_rate(_settings[2].spi_d, _settings[2].clock); +#ifdef SPI_DMA + _settings[2].spiDmaDev = DMA1; + _settings[2].spiDmaChannel = DMA_CH0; + _settings[2].spiRxDmaStream = DMA_STREAM0; // alternative: DMA_STREAM2 + _settings[2].spiTxDmaStream = DMA_STREAM5; // alternative: DMA_STREAM7 +#endif +#endif + } /* * Set up/tear down */ +void SPIClass::updateSettings(void) { + uint32 flags = ((_currentSetting->bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | _currentSetting->dataSize | SPI_SW_SLAVE | SPI_SOFT_SS); + #ifdef SPI_DEBUG + Serial.print("spi_master_enable("); Serial.print(_currentSetting->clockDivider); Serial.print(","); Serial.print(_currentSetting->dataMode); Serial.print(","); Serial.print(flags); Serial.println(")"); + #endif + spi_master_enable(_currentSetting->spi_d, (spi_baud_rate)_currentSetting->clockDivider, (spi_mode)_currentSetting->dataMode, flags); +} void SPIClass::begin(void) { - - uint32 flags = ((bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | SPI_DFF_8_BIT | SPI_SW_SLAVE | SPI_SOFT_SS); - spi_init(spi_d); - configure_gpios(spi_d, 1); - #ifdef SPI_DEBUG - Serial.print("spi_master_enable("); Serial.print(clockDivider); Serial.print(","); Serial.print(dataMode); Serial.print(","); Serial.print(flags); Serial.println(")"); - #endif - spi_master_enable(spi_d, (spi_baud_rate)clockDivider, (spi_mode)dataMode, flags); + spi_init(_currentSetting->spi_d); + configure_gpios(_currentSetting->spi_d, 1); + updateSettings(); +#ifdef SPI_USE_DMA_BUFFER + dmaSendBufferInit(); +#endif +//Serial.println("SPI class begin - end"); } void SPIClass::beginSlave(void) { - if (dataMode >= 4) { - ASSERT(0); - return; - } - uint32 flags = ((bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | SPI_DFF_8_BIT | SPI_SW_SLAVE); - spi_init(spi_d); - configure_gpios(spi_d, 0); + 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_RX_ONLY); #ifdef SPI_DEBUG - Serial.print("spi_slave_enable("); Serial.print(dataMode); Serial.print(","); Serial.print(flags); Serial.println(")"); + Serial.print("spi_slave_enable("); Serial.print(_currentSetting->dataMode); Serial.print(","); Serial.print(flags); Serial.println(")"); #endif - spi_slave_enable(spi_d, (spi_mode)dataMode, flags); + spi_slave_enable(_currentSetting->spi_d, (spi_mode)_currentSetting->dataMode, flags); } void SPIClass::end(void) { - if (!spi_is_enabled(this->spi_d)) { + if (!spi_is_enabled(_currentSetting->spi_d)) { return; } // Follows RM0008's sequence for disabling a SPI in master/slave // full duplex mode. - while (spi_is_rx_nonempty(this->spi_d)) { + while (spi_is_rx_nonempty(_currentSetting->spi_d)) { // FIXME [0.1.0] remove this once you have an interrupt based driver - volatile uint16 rx __attribute__((unused)) = spi_rx_reg(this->spi_d); + volatile uint16 rx __attribute__((unused)) = spi_rx_reg(_currentSetting->spi_d); } - while (!spi_is_tx_empty(this->spi_d)) + while (!spi_is_tx_empty(_currentSetting->spi_d)) ; - while (spi_is_busy(this->spi_d)) + while (spi_is_busy(_currentSetting->spi_d)) ; - spi_peripheral_disable(this->spi_d); + spi_peripheral_disable(_currentSetting->spi_d); } /* Roger Clark added 3 functions */ @@ -170,8 +208,9 @@ void SPIClass::setClockDivider(uint32_t clockDivider) #ifdef SPI_DEBUG Serial.print("Clock divider set to "); Serial.println(clockDivider); #endif - this->clockDivider = clockDivider; - this->begin(); + _currentSetting->clockDivider = clockDivider; + uint32 cr1 = _currentSetting->spi_d->regs->CR1 & ~(SPI_CR1_BR); + _currentSetting->spi_d->regs->CR1 = cr1 | (clockDivider & SPI_CR1_BR); } void SPIClass::setBitOrder(BitOrder bitOrder) @@ -179,8 +218,10 @@ void SPIClass::setBitOrder(BitOrder bitOrder) #ifdef SPI_DEBUG Serial.print("Bit order set to "); Serial.println(bitOrder); #endif - this->bitOrder = bitOrder; - this->begin(); + _currentSetting->bitOrder = bitOrder; + uint32 cr1 = _currentSetting->spi_d->regs->CR1 & ~(SPI_CR1_LSBFIRST); + if ( bitOrder==LSBFIRST ) cr1 |= SPI_CR1_LSBFIRST; + _currentSetting->spi_d->regs->CR1 = cr1; } /* Victor Perez. Added to test changing datasize from 8 to 16 bit modes on the fly. @@ -189,11 +230,11 @@ void SPIClass::setBitOrder(BitOrder bitOrder) */ void SPIClass::setDataSize(uint32 datasize) { - uint32 cr1 = this->spi_d->regs->CR1; - datasize &= SPI_CR1_DFF; - cr1 &= ~(SPI_CR1_DFF); - cr1 |= datasize; - this->spi_d->regs->CR1 = cr1; + _currentSetting->dataSize = datasize; + 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) @@ -212,13 +253,11 @@ SPI Mode CPOL CPHA Shift SCK-edge Capture SCK-edge On the STM32 it appears to be bit 1 - CPOL : Clock polarity - (This bit should not be changed when communication is ongoing) 0 : CLK to 0 when idle 1 : CLK to 1 when idle bit 0 - CPHA : Clock phase - (This bit should not be changed when communication is ongoing) 0 : The first clock transition is the first data capture edge 1 : The second clock transition is the first data capture edge @@ -228,44 +267,32 @@ If someone finds this is not the case or sees a logic error with this let me kno #ifdef SPI_DEBUG Serial.print("Data mode set to "); Serial.println(dataMode); #endif - this->dataMode = dataMode; - this->begin(); -} - + _currentSetting->dataMode = dataMode; + uint32 cr1 = _currentSetting->spi_d->regs->CR1 & ~(SPI_CR1_CPOL|SPI_CR1_CPHA); + _currentSetting->spi_d->regs->CR1 = cr1 | (dataMode & (SPI_CR1_CPOL|SPI_CR1_CPHA)); +} 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); - setClockDivider(determine_baud_rate(spi_d, settings.clock)); + setDataSize(settings.dataSize); + setClockDivider(determine_baud_rate(_currentSetting->spi_d, settings.clock)); begin(); -#if 0 -// code from SAM core - uint8_t mode = interruptMode; - if (mode > 0) { - if (mode < 16) { - if (mode & 1) PIOA->PIO_IDR = interruptMask[0]; - if (mode & 2) PIOB->PIO_IDR = interruptMask[1]; - if (mode & 4) PIOC->PIO_IDR = interruptMask[2]; - if (mode & 8) PIOD->PIO_IDR = interruptMask[3]; - } else { - interruptSave = interruptsStatus(); - noInterrupts(); - } - } - uint32_t ch = BOARD_PIN_TO_SPI_CHANNEL(pin); - bitOrder[ch] = settings.border; - SPI_ConfigureNPCS(spi, ch, settings.config); - //setBitOrder(pin, settings.border); - //setDataMode(pin, settings.datamode); - //setClockDivider(pin, settings.clockdiv); -#endif +} + +void SPIClass::beginTransactionSlave(SPISettings settings) +{ + #ifdef SPI_DEBUG + Serial.println(F("SPIClass::beginTransactionSlave")); + #endif + setBitOrder(settings.bitOrder); + setDataMode(settings.dataMode); + setDataSize(settings.dataSize); + beginSlave(); } void SPIClass::endTransaction(void) @@ -295,131 +322,154 @@ void SPIClass::endTransaction(void) * I/O */ -uint8 SPIClass::read(void) { - uint8 buf[1]; - this->read(buf, 1); - return buf[0]; +uint16 SPIClass::read(void) +{ + while ( spi_is_rx_nonempty(_currentSetting->spi_d)==0 ) ; + return (uint16)spi_rx_reg(_currentSetting->spi_d); } -void SPIClass::read(uint8 *buf, uint32 len) { - uint32 rxed = 0; - while (rxed < len) { - while (!spi_is_rx_nonempty(this->spi_d)) - ; - buf[rxed++] = (uint8)spi_rx_reg(this->spi_d); - } +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; + // 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) { - #ifdef SPI_DEBUG -// Serial.print("SPIClass::write("); Serial.print(data); Serial.println(")"); - #endif - // 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(this->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(this->spi_d) == 0); // "5. Wait until TXE=1 ..." - while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." + 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." } -//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(this->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(this->spi_d) == 0); // "5. Wait until TXE=1 ..." -// while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." -//} - -void SPIClass::write(const uint8 *data, uint32 length) { - #ifdef SPI_DEBUG - Serial.print("SPIClass::write(data, "); Serial.print(length); Serial.println(")"); - #endif - uint32 txed = 0; - while (txed < length) { - txed += spi_tx(this->spi_d, data + txed, length - txed); - } - while (spi_is_tx_empty(this->spi_d) == 0); // "4. After writing the last data item into the SPI_DR register, wait until TXE=1 ..." - while (spi_is_busy(this->spi_d) != 0); // "... then wait until BSY=0, this indicates that the transmission of the last data is complete." +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 } -uint8 SPIClass::transfer(uint8 byte) const { - #ifdef SPI_DEBUG -// Serial.print("SPIClass::transfer("); Serial.print(byte); Serial.println(")"); - #endif - uint8 b; - spi_tx_reg(this->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(this->spi_d) == 0); // "4. Wait until RXNE=1 ..." - b = spi_rx_reg(this->spi_d); // "... and read the last received data." - while (spi_is_tx_empty(this->spi_d) == 0); // "5. Wait until TXE=1 ..." - while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." - return b; +void SPIClass::write(void *data, uint32 length) +{ + 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_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_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." +} + +#ifdef SPI_DMA /* 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; - if (spi_is_rx_nonempty(this->spi_d) == 1) b = spi_rx_reg(this->spi_d); //Clear the RX buffer in case a byte is waiting on it. - dma1_ch3_Active=true; - dma_init(DMA1); - dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event); - + + uint8 b = 0; + + dma_init(_currentSetting->spiDmaDev); +// dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event); // RX - spi_rx_dma_enable(SPI1); - dma_setup_transfer(DMA1, DMA_CH2, &SPI1->regs->DR, DMA_SIZE_8BITS, - receiveBuf, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_TRNS_CMPLT));// receive buffer DMA - dma_set_num_transfers(DMA1, DMA_CH2, length); - + dma_xfer_size dma_bit_size = (_currentSetting->dataSize==SPI_DATA_SIZE_16BIT) ? DMA_SIZE_16BITS : DMA_SIZE_8BITS; + dma_setup_transfer( _currentSetting->spiDmaDev, + _currentSetting->spiRxDmaStream, + _currentSetting->spiDmaChannel, + dma_bit_size, + &_currentSetting->spi_d->regs->DR, // peripheral address + receiveBuf, // memory bank 0 address + NULL, // memory bank 1 address + (DMA_MINC_MODE | DMA_FROM_PER | DMA_PRIO_VERY_HIGH) // flags + ); + dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaStream, length); + dma_set_fifo_flags(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaStream, 0); + dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaStream); + // TX - spi_tx_dma_enable(SPI1); - if (!transmitBuf) { - static uint8_t ff = 0XFF; - transmitBuf = &ff; - dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_8BITS, - transmitBuf, DMA_SIZE_8BITS, (DMA_FROM_MEM | DMA_TRNS_CMPLT));// Transmit FF repeatedly + uint32 flags = (DMA_MINC_MODE | DMA_FROM_MEM); // | DMA_TRNS_CMPLT); + if ( transmitBuf==0 ) { + static uint8_t ff = 0XFF; + transmitBuf = &ff; + flags &= ~((uint32)DMA_MINC_MODE); // remove increment mode } - else { - dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_8BITS, - transmitBuf, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_FROM_MEM | DMA_TRNS_CMPLT));// Transmit buffer DMA - } - dma_set_num_transfers(DMA1, DMA_CH3, length); - - dma_enable(DMA1, DMA_CH2);// enable receive - dma_enable(DMA1, DMA_CH3);// enable transmit + dma_setup_transfer( _currentSetting->spiDmaDev, + _currentSetting->spiTxDmaStream, + _currentSetting->spiDmaChannel, + dma_bit_size, + &_currentSetting->spi_d->regs->DR, // peripheral address + transmitBuf, // memory bank 0 address + NULL, // memory bank 1 address + flags + ); + dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream, length); + dma_set_fifo_flags(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream, 0); + dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream); + // software enable sequence, see AN4031, chapter 4.3 + dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaStream);// enable receive + dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream);// 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 -// while (dma1_ch3_Active); -// if (receiveBuf) { uint32_t m = millis(); - while (dma1_ch3_Active) { - if ((millis() - m) > 100) { - dma1_ch3_Active = 0; - b = 2; - break; - } + while ((b = dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream) & DMA_ISR_TCIF)==0 ) {// wait for completion flag to be set + if ( b&(DMA_ISR_TEIF|DMA_ISR_DMEIF|DMA_ISR_FEIF) ) { b = 1; break; } // break on any error flag + if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; } } + if (b & DMA_ISR_TCIF) b = 0; -// } - while (spi_is_tx_empty(this->spi_d) == 0); // "5. Wait until TXE=1 ..." - while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." - dma_disable(DMA1, DMA_CH3); - dma_disable(DMA1, DMA_CH2); - spi_rx_dma_disable(SPI1); - spi_tx_dma_disable(SPI1); + 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." + // software disable sequence, see AN4031, chapter 4.1 + spi_tx_dma_disable(_currentSetting->spi_d); + spi_rx_dma_disable(_currentSetting->spi_d); + dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaStream); + dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream); return b; } @@ -427,56 +477,45 @@ 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, 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(DMA1); - dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event); - + uint8 b = 0; + dma_init(_currentSetting->spiDmaDev); // TX - spi_tx_dma_enable(SPI1); - dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_8BITS, - transmitBuf, DMA_SIZE_8BITS, flags);// Transmit buffer DMA - dma_set_num_transfers(DMA1, DMA_CH3, length); - dma_enable(DMA1, DMA_CH3);// enable transmit - - while (dma1_ch3_Active); - while (spi_is_rx_nonempty(this->spi_d) == 0); // "4. Wait until RXNE=1 ..." - b = spi_rx_reg(this->spi_d); // "... and read the last received data." - while (spi_is_tx_empty(this->spi_d) == 0); // "5. Wait until TXE=1 ..." - while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." - dma_disable(DMA1, DMA_CH3); - spi_tx_dma_disable(SPI1); - return b; -} + dma_xfer_size dma_bit_size = (_currentSetting->dataSize==SPI_DATA_SIZE_16BIT) ? DMA_SIZE_16BITS : DMA_SIZE_8BITS; + dma_setup_transfer( _currentSetting->spiDmaDev, + _currentSetting->spiTxDmaStream, + _currentSetting->spiDmaChannel, + dma_bit_size, + &_currentSetting->spi_d->regs->DR, // peripheral address + transmitBuf, // memory bank 0 address + NULL, // memory bank 1 address + ( (DMA_MINC_MODE*minc) | DMA_FROM_MEM ) //| DMA_TRNS_CMPLT ) // flags + );// Transmit buffer DMA + dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream, length); + dma_set_fifo_flags(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream, 0); + dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream); + dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream);// enable transmit + spi_tx_dma_enable(_currentSetting->spi_d); -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(DMA1); - dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event); + uint32_t m = millis(); + while ((b = dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream) & DMA_ISR_TCIF)==0 ) {// wait for completion flag to be set + if ( b&(DMA_ISR_TEIF|DMA_ISR_DMEIF|DMA_ISR_FEIF) ) { b = 1; break; } // break on any error flag + if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; } + } + if (b & DMA_ISR_TCIF) b = 0; - // TX - spi_tx_dma_enable(SPI1); - dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_16BITS, - transmitBuf, DMA_SIZE_16BITS, flags);// Transmit buffer DMA - dma_set_num_transfers(DMA1, DMA_CH3, length); - dma_enable(DMA1, DMA_CH3);// enable transmit - - while (dma1_ch3_Active); - while (spi_is_rx_nonempty(this->spi_d) == 0); // "4. Wait until RXNE=1 ..." - b = spi_rx_reg(this->spi_d); // "... and read the last received data." - while (spi_is_tx_empty(this->spi_d) == 0); // "5. Wait until TXE=1 ..." - while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." - dma_disable(DMA1, DMA_CH3); - spi_tx_dma_disable(SPI1); - 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." + spi_tx_dma_disable(_currentSetting->spi_d); + dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream); + return b; } +#endif + void SPIClass::attachInterrupt(void) { @@ -492,19 +531,19 @@ void SPIClass::detachInterrupt(void) { */ uint8 SPIClass::misoPin(void) { - return dev_to_spi_pins(this->spi_d)->miso; + return dev_to_spi_pins(_currentSetting->spi_d)->miso; } uint8 SPIClass::mosiPin(void) { - return dev_to_spi_pins(this->spi_d)->mosi; + return dev_to_spi_pins(_currentSetting->spi_d)->mosi; } uint8 SPIClass::sckPin(void) { - return dev_to_spi_pins(this->spi_d)->sck; + return dev_to_spi_pins(_currentSetting->spi_d)->sck; } uint8 SPIClass::nssPin(void) { - return dev_to_spi_pins(this->spi_d)->nss; + return dev_to_spi_pins(_currentSetting->spi_d)->nss; } /* @@ -512,18 +551,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) { @@ -585,29 +619,26 @@ static void configure_gpios(spi_dev *dev, bool as_master) { if(dev->clk_id <= RCC_SPI2) { if(nssi) { if(!as_master) { - gpio_set_af_mode(nssi->gpio_device, scki->gpio_bit, 5); + gpio_set_af_mode(pins->nss, 5); } } - gpio_set_af_mode(scki->gpio_device, scki->gpio_bit, 5); - gpio_set_af_mode(misoi->gpio_device, misoi->gpio_bit, 5); - gpio_set_af_mode(mosii->gpio_device, mosii->gpio_bit, 5); + gpio_set_af_mode(pins->sck, 5); + gpio_set_af_mode(pins->miso, 5); + gpio_set_af_mode(pins->mosi, 5); } else { if(nssi) { if(!as_master) { - gpio_set_af_mode(nssi->gpio_device, scki->gpio_bit, 6); + gpio_set_af_mode(pins->nss, 6); } } - gpio_set_af_mode(scki->gpio_device, scki->gpio_bit, 6); - gpio_set_af_mode(misoi->gpio_device, misoi->gpio_bit, 6); - gpio_set_af_mode(mosii->gpio_device, mosii->gpio_bit, 6); + gpio_set_af_mode(pins->sck, 6); + gpio_set_af_mode(pins->miso, 6); + gpio_set_af_mode(pins->mosi, 6); } #endif - spi_config_gpios(dev, as_master, nssi->gpio_device, nssi->gpio_bit, - scki->gpio_device, scki->gpio_bit, - misoi->gpio_device, misoi->gpio_bit, - mosii->gpio_device, mosii->gpio_bit); + spi_config_gpios(dev, as_master, pins->nss, pins->sck, pins->miso, pins->mosi); } static const spi_baud_rate baud_rates[8] __FLASH__ = { @@ -634,6 +665,8 @@ static spi_baud_rate determine_baud_rate(spi_dev *dev, uint32_t freq) { { case RCC_APB2: clock = STM32_PCLK2; break; // 72 Mhz case RCC_APB1: clock = STM32_PCLK1; break; // 36 Mhz + case RCC_AHB1: break; + default: break; } clock /= 2; i = 0; @@ -646,4 +679,3 @@ static spi_baud_rate determine_baud_rate(spi_dev *dev, uint32_t freq) { //SPIClass SPI(3); - diff --git a/STM32F4/libraries/SPI/src/SPI.h b/STM32F4/libraries/SPI/src/SPI.h index 490d58b..218449f 100644 --- a/STM32F4/libraries/SPI/src/SPI.h +++ b/STM32F4/libraries/SPI/src/SPI.h @@ -34,18 +34,15 @@ /* TODO [0.1.0] Remove deprecated methods. */ - -#ifndef _SPI_H_INCLUDED -#define _SPI_H_INCLUDED +#ifndef _LIB_SPI_H_ +#define _LIB_SPI_H_ #include #include #include - -#include -#include #include + // SPI_HAS_TRANSACTION means SPI has // - beginTransaction() // - endTransaction() @@ -96,34 +93,61 @@ #define SPI_MODE2 SPI_MODE_2 #define SPI_MODE3 SPI_MODE_3 +#define SPI_DATA_SIZE_8BIT SPI_CR1_DFF_8_BIT +#define SPI_DATA_SIZE_16BIT SPI_CR1_DFF_16_BIT + class SPISettings { public: SPISettings(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) { if (__builtin_constant_p(clock)) { - init_AlwaysInline(clock, bitOrder, dataMode); + init_AlwaysInline(clock, bitOrder, dataMode, SPI_DATA_SIZE_8BIT); } else { - init_MightInline(clock, bitOrder, dataMode); + init_MightInline(clock, bitOrder, dataMode, SPI_DATA_SIZE_8BIT); } } - SPISettings() { init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0); } -private: - void init_MightInline(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) { - init_AlwaysInline(clock, bitOrder, dataMode); + SPISettings(uint32_t clock, BitOrder bitOrder, uint8_t dataMode, uint32_t dataSize) { + if (__builtin_constant_p(clock)) { + init_AlwaysInline(clock, bitOrder, dataMode, dataSize); + } else { + init_MightInline(clock, bitOrder, dataMode, dataSize); + } } - void init_AlwaysInline(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) __attribute__((__always_inline__)) { + SPISettings(uint32_t clock) { + if (__builtin_constant_p(clock)) { + init_AlwaysInline(clock, MSBFIRST, SPI_MODE0, SPI_DATA_SIZE_8BIT); + } else { + init_MightInline(clock, MSBFIRST, SPI_MODE0, SPI_DATA_SIZE_8BIT); + } + } + SPISettings() { init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0, SPI_DATA_SIZE_8BIT); } +private: + void init_MightInline(uint32_t clock, BitOrder bitOrder, uint8_t dataMode, uint32_t dataSize) { + init_AlwaysInline(clock, bitOrder, dataMode, dataSize); + } + void init_AlwaysInline(uint32_t clock, BitOrder bitOrder, uint8_t dataMode, uint32_t dataSize) __attribute__((__always_inline__)) { this->clock = clock; this->bitOrder = bitOrder; this->dataMode = dataMode; + this->dataSize = dataSize; } uint32_t clock; BitOrder bitOrder; uint8_t dataMode; + uint32_t dataSize; + + spi_dev *spi_d; + uint32_t clockDivider; + +#ifdef SPI_DMA + dma_dev* spiDmaDev; + dma_channel spiDmaChannel; + dma_stream spiRxDmaStream, spiTxDmaStream; +#endif + friend class SPIClass; }; -volatile static bool dma1_ch3_Active; - /** * @brief Wirish SPI interface. * @@ -133,18 +157,11 @@ volatile static bool dma1_ch3_Active; class SPIClass { public: - - /** * @param spiPortNumber Number of the SPI port to manage. */ SPIClass(uint32 spiPortNumber); - /* - * Set up/tear down - */ - - /** * @brief Equivalent to begin(SPI_1_125MHZ, MSBFIRST, 0). @@ -175,6 +192,8 @@ public: void beginTransaction(uint8_t pin, SPISettings settings); void endTransaction(void); + void beginTransactionSlave(SPISettings settings); + void setClockDivider(uint32_t clockDivider); void setBitOrder(BitOrder bitOrder); void setDataMode(uint8_t dataMode); @@ -195,40 +214,40 @@ 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(const uint8 *buffer, uint32 length); + 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(void * buffer, uint32 length); /** * @brief Transmit a byte, then return the next unread byte. @@ -239,9 +258,12 @@ public: * @return Next unread byte. */ uint8 transfer(uint8 data) const; + uint16_t transfer16(uint16_t data) const; +#ifdef SPI_DMA /** * @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. * @@ -249,30 +271,19 @@ 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, bool minc = 1); +#endif /* * Pin accessors @@ -304,7 +315,24 @@ public: * @brief Get a pointer to the underlying libmaple spi_dev for * this HardwareSPI instance. */ - spi_dev* c_dev(void) { return this->spi_d; } + spi_dev* c_dev(void) { return _currentSetting->spi_d; } + + + spi_dev *dev(){ return _currentSetting->spi_d;} + + /** + * @brief Sets the number of the SPI peripheral to be used by + * this HardwareSPI instance. + * + * @param spi_num Number of the SPI port. 1-2 in low density devices + * or 1-3 in high density devices. + */ + + void setModule(int spi_num) + { + _currentSetting=&_settings[spi_num-1];// SPI channels are called 1 2 and 3 but the array is zero indexed + } + /* -- The following methods are deprecated --------------------------- */ @@ -338,26 +366,13 @@ public: */ uint8 recv(void); - spi_dev *dev(){ return spi_d;} - - - private: - - static inline void DMA1_CH3_Event() { - dma1_ch3_Active = 0; -// dma_disable(DMA1, DMA_CH3); -// dma_disable(DMA1, DMA_CH2); - - // To Do. Need to wait for - } - spi_dev *spi_d; - uint8_t _SSPin; - uint32_t clockDivider; - uint8_t dataMode; - BitOrder bitOrder; + SPISettings _settings[BOARD_NR_SPI]; + SPISettings *_currentSetting; + + void updateSettings(void); }; +extern SPIClass SPI; // needed bx SdFat(EX) lib -extern SPIClass SPI;//(1);// dummy params #endif diff --git a/STM32F4/platform.txt b/STM32F4/platform.txt index 99ae555..2bb1946 100755 --- a/STM32F4/platform.txt +++ b/STM32F4/platform.txt @@ -8,17 +8,15 @@ version=0.1.0 # compiler variables # ---------------------- -#build.gcc_ver=gcc-arm-none-eabi-4.8.3-2014q1 - 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 -Wall -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 -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 -Wall -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 @@ -30,6 +28,8 @@ compiler.size.cmd=arm-none-eabi-size compiler.define=-DARDUINO= # this can be overriden in boards.txt +build.f_cpu=168000000L +build.mcu=cortex-m4 build.cpu_flags= build.hs_flag= build.common_flags=-mthumb -D__STM32F4__ @@ -44,12 +44,10 @@ compiler.ar.extra_flags= compiler.elf2hex.extra_flags= +##compiler.libs.c.flags="-I{build.system.path}/libmaple" "-I{build.system.path}/libmaple/include" "-I{build.system.path}/libmaple/stm32f1/include" "-I{build.system.path}/libmaple/usb/stm32f1" "-I{build.system.path}/libmaple/usb/usb_lib" +#compiler.libs.c.flags="-I{build.core.path}" "-I{build.core.path}/libmaple" "-I{build.core.path}/libmaple/usbF4" "-I{build.core.path}/libmaple/usbF4/STM32_USB_Device_Library/Core/inc" "-I{build.core.path}/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/inc" "-I{build.core.path}/libmaple/usbF4/STM32_USB_OTG_Driver/inc" "-I{build.core.path}/libmaple/usbF4/VCP" +compiler.libs.c.flags="-I{build.system.path}/libmaple" "-I{build.core.path}/libmaple/usbF4" -##compiler.libs.c.flags="-I{build.system.path}/libmaple" "-I{build.system.path}/libmaple/include" "-I{build.system.path}/libmaple/stm32f1/include" "-I{build.system.path}/libmaple/stm32f1/include/series" "-I{build.system.path}/libmaple/usb/stm32f1" "-I{build.system.path}/libmaple/usb/usb_lib" -#compiler.libs.c.flags="-I{build.system.path}/libmaple" "-I{build.system.path}/libmaple/include" "-I{build.system.path}/libmaple/stm32f1/include" "-I{build.system.path}/libmaple/usb/stm32f1" "-I{build.system.path}/libmaple/usb/usb_lib" - - -compiler.libs.c.flags="-I{build.core.path}/libmaple" -I{build.core.path}/libmaple/usbF4 -I{build.core.path}/libmaple/usbF4/STM32_USB_Device_Library/Core/inc -I{build.core.path}/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/inc -I{build.core.path}/libmaple/usbF4/STM32_USB_OTG_Driver/inc -I{build.core.path}/libmaple/usbF4/VCP @@ -66,14 +64,13 @@ compiler.libs.c.flags="-I{build.core.path}/libmaple" -I{build.core.path}/libmapl # --------------------- ## Compile c files -recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.flags} -mcpu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.c.extra_flags} {build.extra_flags} {compiler.libs.c.flags} {includes} "{source_file}" -o "{object_file}" +recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.flags} -mcpu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.c.extra_flags} {build.extra_flags} {build.cpu_flags} {compiler.libs.c.flags} {includes} "{source_file}" -o "{object_file}" ## Compile c++ files recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} -mcpu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {build.cpu_flags} {build.hs_flag} {build.common_flags} {compiler.libs.c.flags} {includes} "{source_file}" -o "{object_file}" ## Compile S files recipe.S.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.S.flags} -mcpu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.S.extra_flags} {build.extra_flags} {build.cpu_flags} {build.hs_flag} {build.common_flags} {compiler.libs.c.flags} {includes} "{source_file}" -o "{object_file}" -#recipe.S.o.pattern="{compiler.path}{compiler.c.cmd}" "{source_file}" -o "{object_file}" ## Create archives recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{archive_file_path}" "{object_file}" @@ -92,7 +89,6 @@ recipe.objcopy.hex.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf ## Compute size recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.elf" -#recipe.size.regex=\.text\s+([0-9]+).* recipe.size.regex=^(?:\.text|\.rodata|\.ARM.exidx)\s+([0-9]+).* recipe.size.regex.data=^(?:\.data|\.bss|\.noinit)\s+([0-9]+).* diff --git a/STM32F4/cores/maple/libmaple/gpio.c b/STM32F4/system/libmaple/Arduino.h similarity index 79% rename from STM32F4/cores/maple/libmaple/gpio.c rename to STM32F4/system/libmaple/Arduino.h index 3792220..cef8f08 100644 --- a/STM32F4/cores/maple/libmaple/gpio.c +++ b/STM32F4/system/libmaple/Arduino.h @@ -1,7 +1,7 @@ /****************************************************************************** * The MIT License * - * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2010 LeafLabs LLC. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -24,13 +24,23 @@ * SOFTWARE. *****************************************************************************/ -/** - * @file gpio.c - * @brief GPIO initialization routine - */ +#ifndef _WIRISH_ARDUINO_H_ +#define _WIRISH_ARDUINO_H_ -// #ifdef STM32F2 -// #include "gpioF2.c" -// #else -// #include "gpioF1.c" -// #endif +//#warning Include Arduino.h from system\libmaple + +#include "wirish.h" + +void setup(); +void loop(); +#ifdef __cplusplus +extern "C"{ +#endif // __cplusplus +void yield(void); +#ifdef __cplusplus +} +#endif // __cplusplus + +#include "variant.h" + +#endif diff --git a/STM32F4/variants/generic_f407v/generic_f407v.cpp b/STM32F4/variants/generic_f407v/generic_f407v.cpp new file mode 100644 index 0000000..c51ff9b --- /dev/null +++ b/STM32F4/variants/generic_f407v/generic_f407v.cpp @@ -0,0 +1,81 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file generic_f407v.cpp + * @author ala42 + * @brief generic_f407v board file. + */ + +#ifdef BOARD_generic_f407v + +#include "generic_f407v.h" + +#include "wirish_types.h" + +//static void initSRAMChip(void); +/*****************************************************************************/ +// Alternate functions, see DocID022152 Rev 8, Table 9. +/*****************************************************************************/ +void boardInit(void) { +/* // remap TIMER8 to PC6-9 + gpio_set_af_mode(GPIOC, 6, 3); + gpio_set_af_mode(GPIOC, 7, 3); + gpio_set_af_mode(GPIOC, 8, 3); + gpio_set_af_mode(GPIOC, 9, 3); + + // remap TIMER1 to PE9,11,13,14 + gpio_set_af_mode(GPIOE, 9, 1); + gpio_set_af_mode(GPIOE, 11, 1); + gpio_set_af_mode(GPIOE, 13, 1); + gpio_set_af_mode(GPIOE, 14, 1); + + // remap TIMER3 to PB4,5,0,1 + gpio_set_af_mode(GPIOB, 4, 2); + gpio_set_af_mode(GPIOB, 5, 2); + gpio_set_af_mode(GPIOB, 0, 2); + gpio_set_af_mode(GPIOB, 1, 2); + + //gpio_set_af_mode(GPIOA, 2, 7); + //gpio_set_af_mode(GPIOA, 3, 7); +*/ + return; +} + +/* +static void initSRAMChip(void) { + fsmc_nor_psram_reg_map *regs = FSMC_NOR_PSRAM1_BASE; + + fsmc_sram_init_gpios(); + rcc_clk_enable(RCC_FSMC); + + regs->BCR = (FSMC_BCR_WREN | FSMC_BCR_MWID_16BITS | FSMC_BCR_MTYP_SRAM | + FSMC_BCR_MBKEN); + fsmc_nor_psram_set_addset(regs, 0); + fsmc_nor_psram_set_datast(regs, 3); +} +*/ +#endif diff --git a/STM32F4/variants/generic_f407v/generic_f407v.h b/STM32F4/variants/generic_f407v/generic_f407v.h new file mode 100644 index 0000000..927f9cd --- /dev/null +++ b/STM32F4/variants/generic_f407v/generic_f407v.h @@ -0,0 +1,163 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file generic_f407v.h + * @author Marti Bolivar + * @brief Private include file for Maple Native in boards.h + * + * See maple.h for more information on these definitions. + */ + +#ifndef _BOARD_GENERIC_F407V_H_ +#define _BOARD_GENERIC_F407V_H_ + +#define Port2Pin(port, bit) ((port-'A')*16+bit) + +#define CYCLES_PER_MICROSECOND 168 + + +#undef STM32_PCLK1 +#undef STM32_PCLK2 +#define STM32_PCLK1 (CYCLES_PER_MICROSECOND*1000000/4) +#define STM32_PCLK2 (CYCLES_PER_MICROSECOND*1000000/2) + +#define SYSTICK_RELOAD_VAL (CYCLES_PER_MICROSECOND*1000-1) + +/*****************************************************************************/ +// Board pin definitions +#define BOARD_USB_DM_PIN PA11 +#define BOARD_USB_DP_PIN PA12 + +#define BOARD_LED_PIN PA6 //Port2Pin('A', 6) +#define BOARD_LED2_PIN PA7 //Port2Pin('A', 7) +#define BOARD_BUTTON1_PIN PA0 //Port2Pin('A', 0) +#define BOARD_BUTTON2_PIN PE4 //Port2Pin('E', 4) +#define BOARD_BUTTON3_PIN PE3 //Port2Pin('E', 3) + +#define BOARD_NR_USARTS 5 +#define BOARD_USART1_TX_PIN PA9 //Port2Pin('A', 9) +#define BOARD_USART1_RX_PIN PA10 //Port2Pin('A',10) +#define BOARD_USART2_TX_PIN PA2 //Port2Pin('A', 2) +#define BOARD_USART2_RX_PIN PA3 //Port2Pin('A', 3) +#define BOARD_USART3_TX_PIN PB10 //Port2Pin('B',10) +#define BOARD_USART3_RX_PIN PB11 //Port2Pin('B',11) +#define BOARD_UART4_TX_PIN PA0 //Port2Pin('A', 0) +#define BOARD_UART4_RX_PIN PA1 //Port2Pin('A', 1) +#define BOARD_UART5_TX_PIN PC12 //Port2Pin('C',12) +#define BOARD_UART5_RX_PIN PD2 //Port2Pin('D', 2) + +#define BOARD_NR_SPI 3 +#define BOARD_SPI1_NSS_PIN PA4 //Port2Pin('A', 4) +#define BOARD_SPI1_SCK_PIN PA5 //Port2Pin('A', 5) +#define BOARD_SPI1_MISO_PIN PA6 //Port2Pin('A', 6) +#define BOARD_SPI1_MOSI_PIN PA7 //Port2Pin('A', 7) +#define BOARD_SPI1A_NSS_PIN PA15 //Port2Pin('A',15) +#define BOARD_SPI1A_SCK_PIN PB3 //Port2Pin('B', 3) +#define BOARD_SPI1A_MISO_PIN PB4 //Port2Pin('B', 4) +#define BOARD_SPI1A_MOSI_PIN PB5 //Port2Pin('B', 5) + +#define BOARD_SPI2_NSS_PIN PB12 //Port2Pin('B',12) +#define BOARD_SPI2_SCK_PIN PB13 //Port2Pin('B',13) +#define BOARD_SPI2_MISO_PIN PB14 //Port2Pin('B',14) +#define BOARD_SPI2_MOSI_PIN PB15 //Port2Pin('B',15) +#define BOARD_SPI2A_NSS_PIN PB9 //Port2Pin('B', 9) +#define BOARD_SPI2A_SCK_PIN PB10 //Port2Pin('B',10) +#define BOARD_SPI2A_MISO_PIN PC2 //Port2Pin('C', 2) +#define BOARD_SPI2A_MOSI_PIN pc3 //Port2Pin('C', 3) + +#define BOARD_SPI3_NSS_PIN PA15 //Port2Pin('A',15) +#define BOARD_SPI3_SCK_PIN PB3 //Port2Pin('B', 3) +#define BOARD_SPI3_MISO_PIN PB4 //Port2Pin('B', 4) +#define BOARD_SPI3_MOSI_PIN PB5 //Port2Pin('B', 5) +/* overlap with the SDIO interface for SD card +#define BOARD_SPI3A_NSS_PIN PA4 //Port2Pin('A', 4) +#define BOARD_SPI3A_SCK_PIN PC10 //Port2Pin('C',10) +#define BOARD_SPI3A_MISO_PIN PC11 //Port2Pin('C',11) +#define BOARD_SPI3A_MOSI_PIN PC12 //Port2Pin('C',12) +*/ +#define BOARD_SDIO_D0 PC8 //Port2Pin('C', 8) +#define BOARD_SDIO_D1 PC9 //Port2Pin('C', 9) +#define BOARD_SDIO_D2 PC10 //Port2Pin('C',10) +#define BOARD_SDIO_D3 PC11 //Port2Pin('C',11) +#define BOARD_SDIO_CK PC12 //Port2Pin('C',12) +#define BOARD_SDIO_CMD PD2 //Port2Pin('D', 2) + +#define BOARD_NR_GPIO_PINS 80 +#define BOARD_NR_PWM_PINS 22 +#define BOARD_NR_ADC_PINS 16 +#define BOARD_NR_USED_PINS 22 +#define BOARD_JTMS_SWDIO_PIN PA13 //Port2Pin('A',13) +#define BOARD_JTCK_SWCLK_PIN PA14 //Port2Pin('A',14) +#define BOARD_JTDI_PIN PA15 //Port2Pin('A',15) +#define BOARD_JTDO_PIN PB3 //Port2Pin('B', 3) +#define BOARD_NJTRST_PIN PB4 //Port2Pin('B', 4) + +/*****************************************************************************/ +// Pins reserved for the on-board hardware +#define USB_DM_PIN BOARD_USB_DM_PIN // PA11 +#define USB_DP_PIN BOARD_USB_DP_PIN // PA12 + +#define FLASH_CS_PIN PB0 +#define FLASH_CLK_PIN BOARD_SPI3_SCK_PIN // PB3 +#define FLASH_DO_PIN BOARD_SPI3_MISO_PIN // PB4 +#define FLASH_DI_PIN BOARD_SPI3_MOSI_PIN // PB5 + +#define NRF24_CLK_PIN BOARD_SPI3_SCK_PIN // PB3 +#define NRF24_DO_PIN BOARD_SPI3_MISO_PIN // PB4 +#define NRF24_DI_PIN BOARD_SPI3_MOSI_PIN // PB5 +#define NRF24_CE_PIN PB6 +#define NRF24_CS_PIN PB7 +#define NRF24_IRQ_PIN PB8 + +// SD card, SDIO mode +#define SD_DAT0 BOARD_SDIO_D0 // PC8 +#define SD_DAT1 BOARD_SDIO_D1 // PC9 +#define SD_DAT2 BOARD_SDIO_D2 // PC10 +#define SD_DAT3 BOARD_SDIO_D3 // PC11 +#define SD_CLK BOARD_SDIO_CK // PC12 +#define SD_CMD BOARD_SDIO_CMD // PD2 +// SD card, SPI mode, only usable with software SPI +#define SD_DI BOARD_SDIO_CMD // PD2 +#define SD_DO BOARD_SDIO_D0 // PC8 +#define SD_CS BOARD_SDIO_D3 // PC11 +#define SD_SCLK BOARD_SDIO_CK // PC12 + +/*****************************************************************************/ + +enum { +PA0,PA1,PA2,PA3,PA4,PA5,PA6,PA7,PA8,PA9,PA10,PA11,PA12,PA13,PA14,PA15, +PB0,PB1,PB2,PB3,PB4,PB5,PB6,PB7,PB8,PB9,PB10,PB11,PB12,PB13,PB14,PB15, +PC0,PC1,PC2,PC3,PC4,PC5,PC6,PC7,PC8,PC9,PC10,PC11,PC12,PC13,PC14,PC15, +PD0,PD1,PD2,PD3,PD4,PD5,PD6,PD7,PD8,PD9,PD10,PD11,PD12,PD13,PD14,PD15, +PE0,PE1,PE2,PE3,PE4,PE5,PE6,PE7,PE8,PE9,PE10,PE11,PE12,PE13,PE14,PE15, +#if 0 // not available on LQFP100 package +PF0,PF1,PF2,PF3,PF4,PF5,PF6,PF7,PF8,PF9,PF10,PF11,PF12,PF13,PF14,PF15, +PG0,PG1,PG2,PG3,PG4,PG5,PG6,PG7,PG8,PG9,PG10,PG11,PG12,PG13,PG14,PG15 +#endif // not available on LQFP100 package +}; + +#endif diff --git a/STM32F4/variants/generic_f407v/ld/common.inc b/STM32F4/variants/generic_f407v/ld/common.inc new file mode 100644 index 0000000..f5a0f5b --- /dev/null +++ b/STM32F4/variants/generic_f407v/ld/common.inc @@ -0,0 +1,219 @@ +/* + * Linker script for libmaple. + * + * Original author "lanchon" from ST forums, with modifications by LeafLabs. + */ + +OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") + +/* + * Configure other libraries we want in the link. + * + * libgcc, libc, and libm are common across supported toolchains. + * However, some toolchains require additional archives which aren't + * present everywhere (e.g. ARM's gcc-arm-embedded releases). + * + * To hack around this, we let the build system specify additional + * archives by putting the right extra_libs.inc (in a directory under + * toolchains/) in our search path. + */ +GROUP(libgcc.a libc.a libm.a) +INCLUDE extra_libs.inc + +/* + * These force the linker to search for vector table symbols. + * + * These symbols vary by STM32 family (and also within families). + * It's up to the build system to configure the link's search path + * properly for the target MCU. + */ +INCLUDE vector_symbols.inc + +/* STM32 vector table. */ +EXTERN(__stm32_vector_table) + +/* C runtime initialization function. */ +EXTERN(start_c) + +/* main entry point */ +EXTERN(main) + +/* Initial stack pointer value. */ +EXTERN(__msp_init) +PROVIDE(__msp_init = ORIGIN(ram) + LENGTH(ram)); + +/* Reset vector and chip reset entry point */ +EXTERN(__start__) +ENTRY(__start__) +PROVIDE(__exc_reset = __start__); + +/* Heap boundaries, for libmaple */ +EXTERN(_lm_heap_start); +EXTERN(_lm_heap_end); + +SECTIONS +{ + .text : + { + __text_start__ = .; + /* + * STM32 vector table. Leave this here. Yes, really. + */ + *(.stm32.interrupt_vector) + + /* + * Program code and vague linking + */ + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + *(.gnu.warning) + *(.glue_7t) *(.glue_7) *(.vfp11_veneer) + + *(.ARM.extab* .gnu.linkonce.armextab.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + . = ALIGN(4); + KEEP(*(.init)) + + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + + . = ALIGN(0x4); + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + + . = ALIGN(4); + KEEP(*(.fini)) + + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + } > REGION_TEXT + + /* + * End of text + */ + .text.align : + { + . = ALIGN(8); + __text_end__ = .; + } > REGION_TEXT + + /* + * .ARM.exidx exception unwinding; mandated by ARM's C++ ABI + */ + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > REGION_RODATA + __exidx_end = .; + + /* + * .data + */ + .data : + { + . = ALIGN(8); + __data_start__ = .; + + *(.got.plt) *(.got) + *(.data .data.* .gnu.linkonce.d.*) + + . = ALIGN(8); + __data_end__ = .; + } > REGION_DATA AT> REGION_RODATA + + /* + * Read-only data + */ + .rodata : + { + *(.rodata .rodata.* .gnu.linkonce.r.*) + /* .USER_FLASH: We allow users to allocate into Flash here */ + *(.USER_FLASH) + /* ROM image configuration; for C startup */ + . = ALIGN(4); + _lm_rom_img_cfgp = .; + LONG(LOADADDR(.data)); + /* + * Heap: Linker scripts may choose a custom heap by overriding + * _lm_heap_start and _lm_heap_end. Otherwise, the heap is in + * internal SRAM, beginning after .bss, and growing towards + * the stack. + * + * I'm shoving these here naively; there's probably a cleaner way + * to go about this. [mbolivar] + */ + _lm_heap_start = DEFINED(_lm_heap_start) ? _lm_heap_start : _end; + _lm_heap_end = DEFINED(_lm_heap_end) ? _lm_heap_end : __msp_init; + } > REGION_RODATA + + /* + * .bss + */ + .bss : + { + . = ALIGN(8); + __bss_start__ = .; + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN (8); + __bss_end__ = .; + _end = __bss_end__; + } > REGION_BSS + + /* + * Debugging sections + */ + .stab 0 (NOLOAD) : { *(.stab) } + .stabstr 0 (NOLOAD) : { *(.stabstr) } + /* DWARF debug sections. + * Symbols in the DWARF debugging sections are relative to the beginning + * of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + + .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) } + .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) } + /DISCARD/ : { *(.note.GNU-stack) } +} diff --git a/STM32F4/variants/generic_f407v/ld/extra_libs.inc b/STM32F4/variants/generic_f407v/ld/extra_libs.inc new file mode 100644 index 0000000..dd2c84f --- /dev/null +++ b/STM32F4/variants/generic_f407v/ld/extra_libs.inc @@ -0,0 +1,7 @@ +/* + * Extra archives needed by ARM's GCC ARM Embedded arm-none-eabi- + * releases (https://launchpad.net/gcc-arm-embedded/). + */ + +/* This is for the provided newlib. */ +GROUP(libnosys.a) diff --git a/STM32F4/variants/generic_f407v/ld/flash.ld b/STM32F4/variants/generic_f407v/ld/flash.ld new file mode 100644 index 0000000..c753a78 --- /dev/null +++ b/STM32F4/variants/generic_f407v/ld/flash.ld @@ -0,0 +1,20 @@ +/* + * Discovery F4 (STM32F407VGT6, high density) linker script for + * Flash builds. + */ + +MEMORY +{ + ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 125K + rom (rx) : ORIGIN = 0x08010000, LENGTH = 960K /* ala42 */ +} + +/* GROUP(libcs4_stm32_high_density.a) */ + +REGION_ALIAS("REGION_TEXT", rom); +REGION_ALIAS("REGION_DATA", ram); +REGION_ALIAS("REGION_BSS", ram); +REGION_ALIAS("REGION_RODATA", rom); + +_FLASH_BUILD = 1; +INCLUDE common.inc diff --git a/STM32F4/variants/generic_f407v/ld/jtag.ld b/STM32F4/variants/generic_f407v/ld/jtag.ld new file mode 100644 index 0000000..1001db5 --- /dev/null +++ b/STM32F4/variants/generic_f407v/ld/jtag.ld @@ -0,0 +1,20 @@ +/* + * STM32F4xx high density linker script for + * JTAG (bare metal, no bootloader) builds. + */ + +MEMORY +{ + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K + rom (rx) : ORIGIN = 0x08000000, LENGTH = 512K +} + +/* GROUP(libcs3_stm32_high_density.a) */ + +REGION_ALIAS("REGION_TEXT", rom); +REGION_ALIAS("REGION_DATA", ram); +REGION_ALIAS("REGION_BSS", ram); +REGION_ALIAS("REGION_RODATA", rom); + +_FLASH_BUILD = 1; +INCLUDE common.inc diff --git a/STM32F4/variants/generic_f407v/ld/names.inc b/STM32F4/variants/generic_f407v/ld/names.inc new file mode 100644 index 0000000..6d7ff6e --- /dev/null +++ b/STM32F4/variants/generic_f407v/ld/names.inc @@ -0,0 +1,78 @@ +EXTERN(__cs3_stack) +EXTERN(__cs3_reset) +EXTERN(__exc_nmi) +EXTERN(__exc_hardfault) +EXTERN(__exc_memmanage) +EXTERN(__exc_busfault) +EXTERN(__exc_usagefault) +EXTERN(__stm32reservedexception7) +EXTERN(__stm32reservedexception8) +EXTERN(__stm32reservedexception9) +EXTERN(__stm32reservedexception10) +EXTERN(__exc_svc) +EXTERN(__exc_debug_monitor) +EXTERN(__stm32reservedexception13) +EXTERN(__exc_pendsv) +EXTERN(__exc_systick) + +EXTERN(__irq_wwdg) +EXTERN(__irq_pvd) +EXTERN(__irq_tamper) +EXTERN(__irq_rtc) +EXTERN(__irq_flash) +EXTERN(__irq_rcc) +EXTERN(__irq_exti0) +EXTERN(__irq_exti1) +EXTERN(__irq_exti2) +EXTERN(__irq_exti3) +EXTERN(__irq_exti4) +EXTERN(__irq_dma1_channel1) +EXTERN(__irq_dma1_channel2) +EXTERN(__irq_dma1_channel3) +EXTERN(__irq_dma1_channel4) +EXTERN(__irq_dma1_channel5) +EXTERN(__irq_dma1_channel6) +EXTERN(__irq_dma1_channel7) +EXTERN(__irq_adc) +EXTERN(__irq_usb_hp_can_tx) +EXTERN(__irq_usb_lp_can_rx0) +EXTERN(__irq_can_rx1) +EXTERN(__irq_can_sce) +EXTERN(__irq_exti9_5) +EXTERN(__irq_tim1_brk) +EXTERN(__irq_tim1_up) +EXTERN(__irq_tim1_trg_com) +EXTERN(__irq_tim1_cc) +EXTERN(__irq_tim2) +EXTERN(__irq_tim3) +EXTERN(__irq_tim4) +EXTERN(__irq_i2c1_ev) +EXTERN(__irq_i2c1_er) +EXTERN(__irq_i2c2_ev) +EXTERN(__irq_i2c2_er) +EXTERN(__irq_spi1) +EXTERN(__irq_spi2) +EXTERN(__irq_usart1) +EXTERN(__irq_usart2) +EXTERN(__irq_usart3) +EXTERN(__irq_exti15_10) +EXTERN(__irq_rtcalarm) +EXTERN(__irq_usbwakeup) + +EXTERN(__irq_tim8_brk) +EXTERN(__irq_tim8_up) +EXTERN(__irq_tim8_trg_com) +EXTERN(__irq_tim8_cc) +EXTERN(__irq_adc3) +EXTERN(__irq_fsmc) +EXTERN(__irq_sdio) +EXTERN(__irq_tim5) +EXTERN(__irq_spi3) +EXTERN(__irq_uart4) +EXTERN(__irq_uart5) +EXTERN(__irq_tim6) +EXTERN(__irq_tim7) +EXTERN(__irq_dma2_channel1) +EXTERN(__irq_dma2_channel2) +EXTERN(__irq_dma2_channel3) +EXTERN(__irq_dma2_channel4_5) diff --git a/STM32F4/variants/generic_f407v/ld/ram.ld b/STM32F4/variants/generic_f407v/ld/ram.ld new file mode 100644 index 0000000..b57060c --- /dev/null +++ b/STM32F4/variants/generic_f407v/ld/ram.ld @@ -0,0 +1,19 @@ +/* + * aeroquad32 (STM32F103VET6, high density) linker script for + * RAM builds. + */ + +MEMORY +{ + ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 61K + rom (rx) : ORIGIN = 0x08010000, LENGTH = 0K /* ala42 */ +} + +GROUP(libcs3_stm32_high_density.a) + +REGION_ALIAS("REGION_TEXT", ram); +REGION_ALIAS("REGION_DATA", ram); +REGION_ALIAS("REGION_BSS", ram); +REGION_ALIAS("REGION_RODATA", ram); + +INCLUDE common.inc diff --git a/STM32F4/variants/generic_f407v/ld/vector_symbols.inc b/STM32F4/variants/generic_f407v/ld/vector_symbols.inc new file mode 100644 index 0000000..f8519bb --- /dev/null +++ b/STM32F4/variants/generic_f407v/ld/vector_symbols.inc @@ -0,0 +1,78 @@ +EXTERN(__msp_init) +EXTERN(__exc_reset) +EXTERN(__exc_nmi) +EXTERN(__exc_hardfault) +EXTERN(__exc_memmanage) +EXTERN(__exc_busfault) +EXTERN(__exc_usagefault) +EXTERN(__stm32reservedexception7) +EXTERN(__stm32reservedexception8) +EXTERN(__stm32reservedexception9) +EXTERN(__stm32reservedexception10) +EXTERN(__exc_svc) +EXTERN(__exc_debug_monitor) +EXTERN(__stm32reservedexception13) +EXTERN(__exc_pendsv) +EXTERN(__exc_systick) + +EXTERN(__irq_wwdg) +EXTERN(__irq_pvd) +EXTERN(__irq_tamper) +EXTERN(__irq_rtc) +EXTERN(__irq_flash) +EXTERN(__irq_rcc) +EXTERN(__irq_exti0) +EXTERN(__irq_exti1) +EXTERN(__irq_exti2) +EXTERN(__irq_exti3) +EXTERN(__irq_exti4) +EXTERN(__irq_dma1_channel1) +EXTERN(__irq_dma1_channel2) +EXTERN(__irq_dma1_channel3) +EXTERN(__irq_dma1_channel4) +EXTERN(__irq_dma1_channel5) +EXTERN(__irq_dma1_channel6) +EXTERN(__irq_dma1_channel7) +EXTERN(__irq_adc) +EXTERN(__irq_usb_hp_can_tx) +EXTERN(__irq_usb_lp_can_rx0) +EXTERN(__irq_can_rx1) +EXTERN(__irq_can_sce) +EXTERN(__irq_exti9_5) +EXTERN(__irq_tim1_brk) +EXTERN(__irq_tim1_up) +EXTERN(__irq_tim1_trg_com) +EXTERN(__irq_tim1_cc) +EXTERN(__irq_tim2) +EXTERN(__irq_tim3) +EXTERN(__irq_tim4) +EXTERN(__irq_i2c1_ev) +EXTERN(__irq_i2c1_er) +EXTERN(__irq_i2c2_ev) +EXTERN(__irq_i2c2_er) +EXTERN(__irq_spi1) +EXTERN(__irq_spi2) +EXTERN(__irq_usart1) +EXTERN(__irq_usart2) +EXTERN(__irq_usart3) +EXTERN(__irq_exti15_10) +EXTERN(__irq_rtcalarm) +EXTERN(__irq_usbwakeup) + +EXTERN(__irq_tim8_brk) +EXTERN(__irq_tim8_up) +EXTERN(__irq_tim8_trg_com) +EXTERN(__irq_tim8_cc) +EXTERN(__irq_adc3) +EXTERN(__irq_fsmc) +EXTERN(__irq_sdio) +EXTERN(__irq_tim5) +EXTERN(__irq_spi3) +EXTERN(__irq_uart4) +EXTERN(__irq_uart5) +EXTERN(__irq_tim6) +EXTERN(__irq_tim7) +EXTERN(__irq_dma2_channel1) +EXTERN(__irq_dma2_channel2) +EXTERN(__irq_dma2_channel3) +EXTERN(__irq_dma2_channel4_5) diff --git a/STM32F4/variants/generic_f407v/pin_map.c b/STM32F4/variants/generic_f407v/pin_map.c new file mode 100644 index 0000000..2189902 --- /dev/null +++ b/STM32F4/variants/generic_f407v/pin_map.c @@ -0,0 +1,210 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file generic_f407v.cpp + * @author ala42 + * @brief generic_f407v board file. + */ + +#ifdef BOARD_generic_f407v + +#ifdef __cplusplus +extern "C"{ +#endif + +//#include "generic_f407v.h" + +//#include "fsmc.h" +#include +#include +#include + +#include + +extern timer_dev timer1; +extern timer_dev timer2; +extern timer_dev timer3; +extern timer_dev timer4; +extern timer_dev timer5; +extern timer_dev timer6; +extern timer_dev timer7; +extern timer_dev timer8; + +/* +typedef struct stm32_pin_info { + gpio_dev *gpio_device; // Maple pin's GPIO device + timer_dev *timer_device; // Pin's timer device, if any. + uint8 timer_channel; // Timer channel, or 0 if none. + uint8 adc_channel; // Pin ADC channel, or ADCx if none. + const adc_dev *adc_device; // ADC device, if any. +} stm32_pin_info; +*/ +const stm32_pin_info PIN_MAP[] = { // LQFP100 package pin + {&GPIOA, &timer5, 1, 0, &ADC1}, // D00/PA0 | 23 | USART2_CTS | UART4_TX | ETH_MII_CRS | TIM2_CH1_ETR | TIM5_CH1 | TIM8_ETR | ADC123_IN0/WKUP + {&GPIOA, &timer5, 2, 1, &ADC1}, // D01/PA1 | 24 | USART2_RTS | UART4_RX | ETH_RMII_REF_CLK | ETH_MII_RX_CLK | TIM5_CH2 | TIM2_CH2 | ADC123_IN1 + {&GPIOA, &timer5, 3, 2, &ADC1}, // D02/PA2 | 25 | USART2_TX | TIM5_CH3 | TIM9_CH1 | TIM2_CH3 | ETH_MDIO | ADC123_IN2 + {&GPIOA, &timer5, 4, 3, &ADC1}, // D03/PA3 | 26 | USART2_RX | TIM5_CH4 | TIM9_CH2 | TIM2_CH4 | OTG_HS_ULPI_D0 | ETH_MII_COL | ADC123_IN3 + {&GPIOA, NULL, 0, 4, &ADC1}, // D04/PA4 | 29 | SPI1_NSS | SPI3_NSS | USART2_CK | DCMI_HSYNC | OTG_HS_SOF | I2S3_WS | ADC12_IN4 / DAC_OUT1 + {&GPIOA, NULL, 0, 5, &ADC1}, // D05/PA5 | 30 | SPI1_SCK | OTG_HS_ULPI_CK | TIM2_CH1_ETR | TIM8_CH1N | ADC12_IN5 / DAC_OUT2 + {&GPIOA, NULL, 1, 6, &ADC1}, // D06/PA6 | 31 | SPI1_MISO | TIM8_BKIN | TIM13_CH1 | DCMI_PIXCLK | TIM3_CH1 | TIM1_BKIN | ADC12_IN6 + {&GPIOA, NULL, 0, 7, &ADC1}, // D07/PA7 | 32 | SPI1_MOSI | TIM8_CH1N | TIM14_CH1 | TIM3_CH2 | ETH_MII_RX_DV | TIM1_CH1N / ETH_RMII_CRS_DV | ADC12_IN7 + {&GPIOA, NULL, 0, ADCx, NULL}, // D08/PA8 | 67 | MCO1 | USART1_CK | TIM1_CH1 | I2C3_SCL | OTG_FS_SOF + {&GPIOA, NULL, 0, ADCx, NULL}, // D09/PA9 | 68 | USART1_TX | TIM1_CH2 | I2C3_SMBA | DCMI_D0 + {&GPIOA, NULL, 0, ADCx, NULL}, // D10/PA10 | 69 | USART1_RX | TIM1_CH3 | OTG_FS_ID | DCMI_D1 + {&GPIOA, NULL, 0, ADCx, NULL}, // D11/PA11 | 70 | USART1_CTS | CAN1_RX | TIM1_CH4 | OTG_FS_DM + {&GPIOA, NULL, 0, ADCx, NULL}, // D12/PA12 | 71 | USART1_RTS | CAN1_TX | TIM1_ETR | OTG_FS_DP + {&GPIOA, NULL, 0, ADCx, NULL}, // D13/PA13 | 72 | JTMS-SWDIO + {&GPIOA, NULL, 0, ADCx, NULL}, // D14/PA14 | 76 | JTCK-SWCLK + {&GPIOA, &timer2, 1, ADCx, NULL}, // D15/PA15 | 77 | JTDI | SPI3_NSS | I2S3_WS | TIM2_CH1_ETR | SPI1_NSS + + {&GPIOB, &timer3, 3, 8, &ADC1}, // D16/PB0 | 35 | TIM3_CH3 | TIM8_CH2N | OTG_HS_ULPI_D1 | ETH_MII_RXD2 | TIM1_CH2N | ADC12_IN8 + {&GPIOB, &timer3, 4, 9, &ADC1}, // D17/PB1 | 36 | TIM3_CH4 | TIM8_CH3N | OTG_HS_ULPI_D2 | ETH_MII_RXD3 | TIM1_CH3N | ADC12_IN9 + {&GPIOB, NULL, 0, ADCx, NULL}, // D18/PB2 | 37 | BOOT1 + {&GPIOB, &timer2, 2, ADCx, NULL}, // D19/PB3 | 89 | JTDO | TRACESWO | SPI3_SCK | I2S3_CK | TIM2_CH2 | SPI1_SCK + {&GPIOB, &timer3, 1, ADCx, NULL}, // D20/PB4 | 90 | NJTRST | SPI3_MISO | TIM3_CH1 | SPI1_MISO | I2S3ext_SD + {&GPIOB, &timer3, 2, ADCx, NULL}, // D21/PB5 | 91 | I2C1_SMBA | CAN2_RX | OTG_HS_ULPI_D7 | ETH_PPS_OUT | TIM3_CH2 | SPI1_MOSI | SPI3_MOSI | DCMI_D10 | I2S3_SD + {&GPIOB, NULL, 0, ADCx, NULL}, // D22/PB6 | 92 | I2C1_SCL | TIM4_CH1 | CAN2_TX | DCMI_D5 | USART1_TX + {&GPIOB, NULL, 0, ADCx, NULL}, // D23/PB7 | 93 | I2C1_SDA | FSMC_NL | DCMI_VSYNC | USART1_RX | TIM4_CH2 + {&GPIOB, NULL, 0, ADCx, NULL}, // D24/PB8 | 95 | TIM4_CH3 | SDIO_D4 | TIM10_CH1 | DCMI_D6 | ETH_MII_TXD3 | I2C1_SCL | CAN1_RX + {&GPIOB, NULL, 0, ADCx, NULL}, // D25/PB9 | 96 | SPI2_NSS | I2S2_WS | TIM4_CH4 | TIM11_CH1 | SDIO_D5 | DCMI_D7 | I2C1_SDA | CAN1_TX + {&GPIOB, NULL, 0, ADCx, NULL}, // D26/PB10 | 47 | SPI2_SCK | I2S2_CK | I2C2_SCL | USART3_TX | OTG_HS_ULPI_D3 | ETH_MII_RX_ER | TIM2_CH3 + {&GPIOB, NULL, 0, ADCx, NULL}, // D27/PB11 | 48 | I2C2_SDA | USART3_RX | OTG_HS_ULPI_D4 | ETH_RMII_TX_EN | ETH_MII_TX_EN | TIM2_CH4 + {&GPIOB, NULL, 0, ADCx, NULL}, // D28/PB12 | 51 | SPI2_NSS | I2S2_WS | I2C2_SMBA | USART3_CK | TIM1_BKIN | CAN2_RX | OTG_HS_ULPI_D5 | ETH_RMII_TXD0 | ETH_MII_TXD0 | OTG_HS_ID + {&GPIOB, NULL, 0, ADCx, NULL}, // D29/PB13 | 52 | SPI2_SCK | I2S2_CK | USART3_CTS | TIM1_CH1N | CAN2_TX | OTG_HS_ULPI_D6 | ETH_RMII_TXD1 | ETH_MII_TXD1 + {&GPIOB, NULL, 0, ADCx, NULL}, // D30/PB14 | 53 | SPI2_MISO | TIM1_CH2N | TIM12_CH1 | OTG_HS_DM | USART3_RTS | TIM8_CH2N | I2S2ext_SD + {&GPIOB, NULL, 0, ADCx, NULL}, // D31/PB15 | 54 | SPI2_MOSI | I2S2_SD | TIM1_CH3N | TIM8_CH3N | TIM12_CH2 | OTG_HS_DP + + {&GPIOC, NULL, 0, 10, &ADC1}, // D32/PC0 | 15 | OTG_HS_ULPI_STP | ADC123_IN10 + {&GPIOC, NULL, 0, 11, &ADC1}, // D33/PC1 | 16 | ETH_MDC | ADC123_IN11 + {&GPIOC, NULL, 0, 12, &ADC1}, // D34/PC2 | 17 | SPI2_MISO | OTG_HS_ULPI_DIR | ETH_MII_TXD2 | I2S2ext_SD | ADC123_IN12 + {&GPIOC, NULL, 0, 13, &ADC1}, // D35/PC3 | 18 | SPI2_MOSI | I2S2_SD | OTG_HS_ULPI_NXT | ETH_MII_TX_CLK | ADC123_IN13 + {&GPIOC, NULL, 0, 14, &ADC1}, // D36/PC4 | 33 | ETH_RMII_RX_D0 | ETH_MII_RX_D0 | ADC12_IN14 + {&GPIOC, NULL, 0, 15, &ADC1}, // D37/PC5 | 34 | ETH_RMII_RX_D1 | ETH_MII_RX_D1 | ADC12_IN15 + {&GPIOC, &timer8, 1, ADCx, NULL}, // D38/PC6 | 63 | I2S2_MCK | TIM8_CH1/SDIO_D6 | USART6_TX | DCMI_D0/TIM3_CH1 + {&GPIOC, &timer8, 2, ADCx, NULL}, // D39/PC7 | 64 | I2S3_MCK | TIM8_CH2/SDIO_D7 | USART6_RX | DCMI_D1/TIM3_CH2 + {&GPIOC, &timer8, 3, ADCx, NULL}, // D40/PC8 | 65 | TIM8_CH3 | SDIO_D0 | TIM3_CH3 | USART6_CK | DCMI_D2 + {&GPIOC, &timer8, 4, ADCx, NULL}, // D41/PC9 | 66 | I2S_CKIN | MCO2 | TIM8_CH4 | SDIO_D1 | I2C3_SDA | DCMI_D3 | TIM3_CH4 + {&GPIOC, NULL, 0, ADCx, NULL}, // D42/PC10 | 78 | SPI3_SCK | I2S3_CK | UART4_TX | SDIO_D2 | DCMI_D8 | USART3_TX + {&GPIOC, NULL, 0, ADCx, NULL}, // D43/PC11 | 79 | UART4_RX | SPI3_MISO | SDIO_D3 | DCMI_D4 | USART3_RX | I2S3ext_SD + {&GPIOC, NULL, 0, ADCx, NULL}, // D44/PC12 | 80 | UART5_TX | SDIO_CK | DCMI_D9 | SPI3_MOSI | I2S3_SD | USART3_CK + {&GPIOC, NULL, 0, ADCx, NULL}, // D45/PC13 | 7 | RTC_OUT, RTC_TAMP1, RTC_TS + {&GPIOC, NULL, 0, ADCx, NULL}, // D46/PC14 | 8 | OSC32_IN + {&GPIOC, NULL, 0, ADCx, NULL}, // D47/PC15 | 9 | OSC32_OUT + + {&GPIOD, NULL, 0, ADCx, NULL}, // D48/PD0 | 81 | FSMC_D2 | CAN1_RX + {&GPIOD, NULL, 0, ADCx, NULL}, // D49/PD1 | 82 | FSMC_D3 | CAN1_TX + {&GPIOD, NULL, 0, ADCx, NULL}, // D50/PD2 | 83 | TIM3_ETR | UART5_RX | SDIO_CMD | DCMI_D11 + {&GPIOD, NULL, 0, ADCx, NULL}, // D51/PD3 | 84 | FSMC_CLK | USART2_CTS + {&GPIOD, NULL, 0, ADCx, NULL}, // D52/PD4 | 85 | FSMC_NOE | USART2_RTS + {&GPIOD, NULL, 0, ADCx, NULL}, // D53/PD5 | 86 | FSMC_NWE | USART2_TX + {&GPIOD, NULL, 0, ADCx, NULL}, // D54/PD6 | 87 | FSMC_NWAIT | USART2_RX + {&GPIOD, NULL, 0, ADCx, NULL}, // D55/PD7 | 88 | USART2_CK | FSMC_NE1 | FSMC_NCE2 + {&GPIOD, NULL, 0, ADCx, NULL}, // D56/PD8 | 55 | FSMC_D13 | USART3_TX + {&GPIOD, NULL, 0, ADCx, NULL}, // D57/PD9 | 56 | FSMC_D14 | USART3_RX + {&GPIOD, NULL, 0, ADCx, NULL}, // D58/PD10 | 57 | FSMC_D15 | USART3_CK + {&GPIOD, NULL, 0, ADCx, NULL}, // D59/PD11 | 58 | FSMC_CLE | FSMC_A16 | USART3_CTS + {&GPIOD, &timer4, 1, ADCx, NULL}, // D60/PD12 | 59 | FSMC_ALE | FSMC_A17 | TIM4_CH1 | USART3_RTS // remap in + {&GPIOD, &timer4, 2, ADCx, NULL}, // D61/PD13 | 60 | FSMC_A18 | TIM4_CH2 // remap in + {&GPIOD, &timer4, 3, ADCx, NULL}, // D62/PD14 | 61 | FSMC_D0 | TIM4_CH3 // remap in + {&GPIOD, &timer4, 4, ADCx, NULL}, // D63/PD15 | 62 | FSMC_D1 | TIM4_CH4 // remap in + + {&GPIOE, NULL, 0, ADCx, NULL}, // D64/PE0 | 97 | TIM4_ETR | FSMC_NBL0 | DCMI_D2 + {&GPIOE, NULL, 0, ADCx, NULL}, // D65/PE1 | 98 | FSMC_NBL1 | DCMI_D3 + {&GPIOE, NULL, 0, ADCx, NULL}, // D66/PE2 | 1 | TRACECLK | FSMC_A23 | ETH_MII_TXD3 + {&GPIOE, NULL, 0, ADCx, NULL}, // D67/PE3 | 2 | TRACED0 | FSMC_A19 + {&GPIOE, NULL, 0, ADCx, NULL}, // D68/PE4 | 3 | TRACED1 | FSMC_A20 | DCMI_D4 + {&GPIOE, NULL, 0, ADCx, NULL}, // D69/PE5 | 4 | TRACED2 | FSMC_A21 | TIM9_CH1 / DCMI_D6 + {&GPIOE, NULL, 0, ADCx, NULL}, // D70/PE6 | 5 | TRACED3 | FSMC_A22 | TIM9_CH2 / DCMI_D7 + {&GPIOE, NULL, 0, ADCx, NULL}, // D71/PE7 | 38 | FSMC_D4 | TIM1_ETR + {&GPIOE, NULL, 0, ADCx, NULL}, // D72/PE8 | 39 | FSMC_D5 | TIM1_CH1N + {&GPIOE, &timer1, 1, ADCx, NULL}, // D73/PE9 | 40 | FSMC_D6 | TIM1_CH1 // remap in + {&GPIOE, NULL, 0, ADCx, NULL}, // D74/PE10 | 41 | FSMC_D7 | TIM1_CH2N + {&GPIOE, &timer1, 2, ADCx, NULL}, // D75/PE11 | 42 | FSMC_D8 | TIM1_CH2 // remap in + {&GPIOE, NULL, 0, ADCx, NULL}, // D76/PE12 | 43 | FSMC_D9 | TIM1_CH3N + {&GPIOE, &timer1, 3, ADCx, NULL}, // D77/PE13 | 44 | FSMC_D10 | TIM1_CH3 // remap in + {&GPIOE, &timer1, 4, ADCx, NULL}, // D78/PE14 | 45 | FSMC_D11 | TIM1_CH4 // remap in + {&GPIOE, NULL, 0, ADCx, NULL}, // D79/PE15 | 46 | FSMC_D12 | TIM1_BKIN +#if 0 + {GPIOF, 0, NULL, 0, NULL, ADCx}, // D80/PF0 + {GPIOF, 1, NULL, 0, NULL, ADCx}, // D81/PF1 + {GPIOF, 2, NULL, 0, NULL, ADCx}, // D82/PF2 + {GPIOF, 3, NULL, 0, NULL, ADCx}, // D83/PF3 + {GPIOF, 4, NULL, 0, NULL, ADCx}, // D84/PF4 + {GPIOF, 5, NULL, 0, NULL, ADCx}, // D85/PF5 + {GPIOF, 6, NULL, 0, NULL, ADCx}, // D86/PF6 + {GPIOF, 7, NULL, 0, NULL, ADCx}, // D87/PF7 + {GPIOF, 8, NULL, 0, NULL, ADCx}, // D88/PF8 + {GPIOF, 9, NULL, 0, NULL, ADCx}, // D89/PF9 + {GPIOF, 10, NULL, 0, NULL, ADCx}, // D90/PF10 + {GPIOF, 11, NULL, 0, NULL, ADCx}, // D91/PF11 + {GPIOF, 12, NULL, 0, NULL, ADCx}, // D92/PF12 + {GPIOF, 13, NULL, 0, NULL, ADCx}, // D93/PF13 + {GPIOF, 14, NULL, 0, NULL, ADCx}, // D94/PF14 + {GPIOF, 15, NULL, 0, NULL, ADCx}, // D95/PF15 + + {GPIOG, 0, NULL, 0, NULL, ADCx}, // D96/PG0 + {GPIOG, 1, NULL, 0, NULL, ADCx}, // D97/PG1 + {GPIOG, 2, NULL, 0, NULL, ADCx}, // D98/PG2 + {GPIOG, 3, NULL, 0, NULL, ADCx}, // D99/PG3 + {GPIOG, 4, NULL, 0, NULL, ADCx}, // D100/PG4 + {GPIOG, 5, NULL, 0, NULL, ADCx}, // D101/PG5 + {GPIOG, 6, NULL, 0, NULL, ADCx}, // D102/PG6 + {GPIOG, 7, NULL, 0, NULL, ADCx}, // D103/PG7 + {GPIOG, 8, NULL, 0, NULL, ADCx}, // D104/PG8 + {GPIOG, 9, NULL, 0, NULL, ADCx}, // D105/PG9 + {GPIOG, 10, NULL, 0, NULL, ADCx}, // D106/PG10 + {GPIOG, 11, NULL, 0, NULL, ADCx}, // D107/PG11 + {GPIOG, 12, NULL, 0, NULL, ADCx}, // D108/PG12 + {GPIOG, 13, NULL, 0, NULL, ADCx}, // D109/PG13 + {GPIOG, 14, NULL, 0, NULL, ADCx}, // D110/PG14 + {GPIOG, 15, NULL, 0, NULL, ADCx} // D111/PG15 +#endif +}; +/* to be defined +extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { + 0, 1, 2, 3, 15, 16, 17, 19, 20, 21, 38, 39, 49, 41, 60, 61, 62, 63, 73, 75, 77, 78 +}; +*/ +const uint8 boardADCPins[BOARD_NR_ADC_PINS] = { + PA0, PA1, PA2, PA3, PA4, PA5, PA6, PA7, PB0, PB1, PC0, PC1, PC2, PC3, PC4, PC5 +}; + +const uint8 boardUsedPins[BOARD_NR_USED_PINS] = { + BOARD_LED_PIN, BOARD_LED2_PIN, BOARD_BUTTON1_PIN, BOARD_BUTTON2_PIN, BOARD_BUTTON2_PIN, + BOARD_JTMS_SWDIO_PIN, BOARD_JTCK_SWCLK_PIN, + FLASH_CS_PIN, FLASH_CLK_PIN, FLASH_DO_PIN, FLASH_DI_PIN, + NRF24_CE_PIN, NRF24_CS_PIN, NRF24_IRQ_PIN, + BOARD_SDIO_D0, BOARD_SDIO_D1, BOARD_SDIO_D2, BOARD_SDIO_D3, BOARD_SDIO_CK, BOARD_SDIO_CMD, + USB_DM_PIN, USB_DP_PIN +}; + +#ifdef __cplusplus +} +#endif + + +#endif // BOARD_generic_f407v diff --git a/STM32F4/variants/generic_f407v/pins_arduino.h b/STM32F4/variants/generic_f407v/pins_arduino.h new file mode 100644 index 0000000..3052f2e --- /dev/null +++ b/STM32F4/variants/generic_f407v/pins_arduino.h @@ -0,0 +1,6 @@ + + + + +// API compatibility +#include "variant.h" \ No newline at end of file diff --git a/STM32F4/variants/generic_f407v/stm32_isrs.S b/STM32F4/variants/generic_f407v/stm32_isrs.S new file mode 100644 index 0000000..34e515c --- /dev/null +++ b/STM32F4/variants/generic_f407v/stm32_isrs.S @@ -0,0 +1,323 @@ +/* STM32 ISR weak declarations */ + + .thumb + +/* Default handler for all non-overridden interrupts and exceptions */ + .globl __default_handler + .type __default_handler, %function + +__default_handler: + b . + + .weak __exc_nmi + .globl __exc_nmi + .set __exc_nmi, __default_handler + .weak __exc_hardfault + .globl __exc_hardfault + .set __exc_hardfault, __default_handler + .weak __exc_memmanage + .globl __exc_memmanage + .set __exc_memmanage, __default_handler + .weak __exc_busfault + .globl __exc_busfault + .set __exc_busfault, __default_handler + .weak __exc_usagefault + .globl __exc_usagefault + .set __exc_usagefault, __default_handler + .weak __stm32reservedexception7 + .globl __stm32reservedexception7 + .set __stm32reservedexception7, __default_handler + .weak __stm32reservedexception8 + .globl __stm32reservedexception8 + .set __stm32reservedexception8, __default_handler + .weak __stm32reservedexception9 + .globl __stm32reservedexception9 + .set __stm32reservedexception9, __default_handler + .weak __stm32reservedexception10 + .globl __stm32reservedexception10 + .set __stm32reservedexception10, __default_handler + .weak __exc_svc + .globl __exc_svc + .set __exc_svc, __default_handler + .weak __exc_debug_monitor + .globl __exc_debug_monitor + .set __exc_debug_monitor, __default_handler + .weak __stm32reservedexception13 + .globl __stm32reservedexception13 + .set __stm32reservedexception13, __default_handler + .weak __exc_pendsv + .globl __exc_pendsv + .set __exc_pendsv, __default_handler + .weak __exc_systick + .globl __exc_systick + .set __exc_systick, __default_handler + .weak __irq_wwdg + .globl __irq_wwdg + .set __irq_wwdg, __default_handler + .weak __irq_pvd + .globl __irq_pvd + .set __irq_pvd, __default_handler + .weak __irq_tamper + .globl __irq_tamper + .set __irq_tamper, __default_handler + .weak __irq_rtc + .globl __irq_rtc + .set __irq_rtc, __default_handler + .weak __irq_flash + .globl __irq_flash + .set __irq_flash, __default_handler + .weak __irq_rcc + .globl __irq_rcc + .set __irq_rcc, __default_handler + .weak __irq_exti0 + .globl __irq_exti0 + .set __irq_exti0, __default_handler + .weak __irq_exti1 + .globl __irq_exti1 + .set __irq_exti1, __default_handler + .weak __irq_exti2 + .globl __irq_exti2 + .set __irq_exti2, __default_handler + .weak __irq_exti3 + .globl __irq_exti3 + .set __irq_exti3, __default_handler + .weak __irq_exti4 + .globl __irq_exti4 + .set __irq_exti4, __default_handler + .weak __irq_dma1_channel1 + .globl __irq_dma1_channel1 + .set __irq_dma1_channel1, __default_handler + .weak __irq_dma1_channel2 + .globl __irq_dma1_channel2 + .set __irq_dma1_channel2, __default_handler + .weak __irq_dma1_channel3 + .globl __irq_dma1_channel3 + .set __irq_dma1_channel3, __default_handler + .weak __irq_dma1_channel4 + .globl __irq_dma1_channel4 + .set __irq_dma1_channel4, __default_handler + .weak __irq_dma1_channel5 + .globl __irq_dma1_channel5 + .set __irq_dma1_channel5, __default_handler + .weak __irq_dma1_channel6 + .globl __irq_dma1_channel6 + .set __irq_dma1_channel6, __default_handler + .weak __irq_dma1_channel7 + .globl __irq_dma1_channel7 + .set __irq_dma1_channel7, __default_handler + .weak __irq_adc + .globl __irq_adc + .set __irq_adc, __default_handler + .weak __irq_usb_hp_can_tx + .globl __irq_usb_hp_can_tx + .set __irq_usb_hp_can_tx, __default_handler + .weak __irq_usb_lp_can_rx0 + .globl __irq_usb_lp_can_rx0 + .set __irq_usb_lp_can_rx0, __default_handler + .weak __irq_can_rx1 + .globl __irq_can_rx1 + .set __irq_can_rx1, __default_handler + .weak __irq_can_sce + .globl __irq_can_sce + .set __irq_can_sce, __default_handler + .weak __irq_exti9_5 + .globl __irq_exti9_5 + .set __irq_exti9_5, __default_handler + .weak __irq_tim1_brk + .globl __irq_tim1_brk + .set __irq_tim1_brk, __default_handler + .weak __irq_tim1_up + .globl __irq_tim1_up + .set __irq_tim1_up, __default_handler + .weak __irq_tim1_trg_com + .globl __irq_tim1_trg_com + .set __irq_tim1_trg_com, __default_handler + .weak __irq_tim1_cc + .globl __irq_tim1_cc + .set __irq_tim1_cc, __default_handler + .weak __irq_tim2 + .globl __irq_tim2 + .set __irq_tim2, __default_handler + .weak __irq_tim3 + .globl __irq_tim3 + .set __irq_tim3, __default_handler + .weak __irq_tim4 + .globl __irq_tim4 + .set __irq_tim4, __default_handler + .weak __irq_i2c1_ev + .globl __irq_i2c1_ev + .set __irq_i2c1_ev, __default_handler + .weak __irq_i2c1_er + .globl __irq_i2c1_er + .set __irq_i2c1_er, __default_handler + .weak __irq_i2c2_ev + .globl __irq_i2c2_ev + .set __irq_i2c2_ev, __default_handler + .weak __irq_i2c2_er + .globl __irq_i2c2_er + .set __irq_i2c2_er, __default_handler + .weak __irq_spi1 + .globl __irq_spi1 + .set __irq_spi1, __default_handler + .weak __irq_spi2 + .globl __irq_spi2 + .set __irq_spi2, __default_handler + .weak __irq_usart1 + .globl __irq_usart1 + .set __irq_usart1, __default_handler + .weak __irq_usart2 + .globl __irq_usart2 + .set __irq_usart2, __default_handler + .weak __irq_usart3 + .globl __irq_usart3 + .set __irq_usart3, __default_handler + .weak __irq_exti15_10 + .globl __irq_exti15_10 + .set __irq_exti15_10, __default_handler + .weak __irq_rtcalarm + .globl __irq_rtcalarm + .set __irq_rtcalarm, __default_handler + .weak __irq_usbwakeup + .globl __irq_usbwakeup + .set __irq_usbwakeup, __default_handler +#if defined (STM32_HIGH_DENSITY) + .weak __irq_tim8_brk + .globl __irq_tim8_brk + .set __irq_tim8_brk, __default_handler + .weak __irq_tim8_up + .globl __irq_tim8_up + .set __irq_tim8_up, __default_handler + .weak __irq_tim8_trg_com + .globl __irq_tim8_trg_com + .set __irq_tim8_trg_com, __default_handler + .weak __irq_tim8_cc + .globl __irq_tim8_cc + .set __irq_tim8_cc, __default_handler + .weak __irq_adc3 + .globl __irq_adc3 + .set __irq_adc3, __default_handler + .weak __irq_fsmc + .globl __irq_fsmc + .set __irq_fsmc, __default_handler + .weak __irq_sdio + .globl __irq_sdio + .set __irq_sdio, __default_handler + .weak __irq_tim5 + .globl __irq_tim5 + .set __irq_tim5, __default_handler + .weak __irq_spi3 + .globl __irq_spi3 + .set __irq_spi3, __default_handler + .weak __irq_uart4 + .globl __irq_uart4 + .set __irq_uart4, __default_handler + .weak __irq_uart5 + .globl __irq_uart5 + .set __irq_uart5, __default_handler + .weak __irq_tim6 + .globl __irq_tim6 + .set __irq_tim6, __default_handler + .weak __irq_tim7 + .globl __irq_tim7 + .set __irq_tim7, __default_handler + .weak __irq_dma2_channel1 + .globl __irq_dma2_channel1 + .set __irq_dma2_channel1, __default_handler + .weak __irq_dma2_channel2 + .globl __irq_dma2_channel2 + .set __irq_dma2_channel2, __default_handler + .weak __irq_dma2_channel3 + .globl __irq_dma2_channel3 + .set __irq_dma2_channel3, __default_handler + .weak __irq_dma2_channel4_5 + .globl __irq_dma2_channel4_5 + .set __irq_dma2_channel4_5, __default_handler +#endif /* STM32_HIGH_DENSITY */ + + .weak __irq_DMA2_Stream4_IRQHandler + .globl __irq_DMA2_Stream4_IRQHandler + .set __irq_DMA2_Stream4_IRQHandler, __default_handler + + .weak __irq_ETH_IRQHandler + .globl __irq_ETH_IRQHandler + .set __irq_ETH_IRQHandler, __default_handler + + .weak __irq_ETH_WKUP_IRQHandler + .globl __irq_ETH_WKUP_IRQHandler + .set __irq_ETH_WKUP_IRQHandler, __default_handler + + .weak __irq_CAN2_TX_IRQHandler + .globl __irq_CAN2_TX_IRQHandler + .set __irq_CAN2_TX_IRQHandler, __default_handler + + .weak __irq_CAN2_RX0_IRQHandler + .globl __irq_CAN2_RX0_IRQHandler + .set __irq_CAN2_RX0_IRQHandler, __default_handler + + .weak __irq_CAN2_RX1_IRQHandler + .globl __irq_CAN2_RX1_IRQHandler + .set __irq_CAN2_RX1_IRQHandler, __default_handler + + .weak __irq_CAN2_SCE_IRQHandler + .globl __irq_CAN2_SCE_IRQHandler + .set __irq_CAN2_SCE_IRQHandler, __default_handler + + .weak __irq_OTG_FS_IRQHandler + .globl __irq_OTG_FS_IRQHandler + .set __irq_OTG_FS_IRQHandler, __default_handler + + .weak __irq_DMA2_Stream5_IRQHandler + .globl __irq_DMA2_Stream5_IRQHandler + .set __irq_DMA2_Stream5_IRQHandler, __default_handler + + .weak __irq_DMA2_Stream6_IRQHandler + .globl __irq_DMA2_Stream6_IRQHandler + .set __irq_DMA2_Stream6_IRQHandler, __default_handler + + .weak __irq_DMA2_Stream7_IRQHandler + .globl __irq_DMA2_Stream7_IRQHandler + .set __irq_DMA2_Stream7_IRQHandler, __default_handler + + .weak __irq_USART6_IRQHandler + .globl __irq_USART6_IRQHandler + .set __irq_USART6_IRQHandler, __default_handler + + .weak __irq_I2C3_EV_IRQHandler + .globl __irq_I2C3_EV_IRQHandler + .set __irq_I2C3_EV_IRQHandler, __default_handler + + .weak __irq_I2C3_ER_IRQHandler + .globl __irq_I2C3_ER_IRQHandler + .set __irq_I2C3_ER_IRQHandler, __default_handler + + .weak __irq_OTG_HS_EP1_OUT_IRQHandler + .globl __irq_OTG_HS_EP1_OUT_IRQHandler + .set __irq_OTG_HS_EP1_OUT_IRQHandler, __default_handler + + .weak __irq_OTG_HS_EP1_IN_IRQHandler + .globl __irq_OTG_HS_EP1_IN_IRQHandler + .set __irq_OTG_HS_EP1_IN_IRQHandler, __default_handler + + .weak __irq_OTG_HS_WKUP_IRQHandler + .globl __irq_OTG_HS_WKUP_IRQHandler + .set __irq_OTG_HS_WKUP_IRQHandler, __default_handler + + .weak __irq_OTG_HS_IRQHandler + .globl __irq_OTG_HS_IRQHandler + .set __irq_OTG_HS_IRQHandler, __default_handler + + .weak __irq_DCMI_IRQHandler + .globl __irq_DCMI_IRQHandler + .set __irq_DCMI_IRQHandler, __default_handler + + .weak __irq_CRYP_IRQHandler + .globl __irq_CRYP_IRQHandler + .set __irq_CRYP_IRQHandler, __default_handler + + .weak __irq_HASH_RNG_IRQHandler + .globl __irq_HASH_RNG_IRQHandler + .set __irq_HASH_RNG_IRQHandler, __default_handler + + .weak __irq_FPU_IRQHandler + .globl __irq_FPU_IRQHandler + .set __irq_FPU_IRQHandler, __default_handler diff --git a/STM32F4/variants/generic_f407v/stm32_vector_table.S b/STM32F4/variants/generic_f407v/stm32_vector_table.S new file mode 100644 index 0000000..9f08d66 --- /dev/null +++ b/STM32F4/variants/generic_f407v/stm32_vector_table.S @@ -0,0 +1,113 @@ +/* STM32 vector table */ + + .section ".stm32.interrupt_vector" + + .globl __stm32_vector_table + .type __stm32_vector_table, %object + +__stm32_vector_table: +/* CM3 core interrupts */ + .long __msp_init + .long __exc_reset + .long __exc_nmi + .long __exc_hardfault + .long __exc_memmanage + .long __exc_busfault + .long __exc_usagefault + .long __stm32reservedexception7 + .long __stm32reservedexception8 + .long __stm32reservedexception9 + .long __stm32reservedexception10 + .long __exc_svc + .long __exc_debug_monitor + .long __stm32reservedexception13 + .long __exc_pendsv + .long __exc_systick +/* Peripheral interrupts */ + .long __irq_wwdg + .long __irq_pvd + .long __irq_tamper + .long __irq_rtc + .long __irq_flash + .long __irq_rcc + .long __irq_exti0 + .long __irq_exti1 + .long __irq_exti2 + .long __irq_exti3 + .long __irq_exti4 + .long __irq_dma1_channel1 + .long __irq_dma1_channel2 + .long __irq_dma1_channel3 + .long __irq_dma1_channel4 + .long __irq_dma1_channel5 + .long __irq_dma1_channel6 + .long __irq_dma1_channel7 + .long __irq_adc + .long __irq_usb_hp_can_tx + .long __irq_usb_lp_can_rx0 + .long __irq_can_rx1 + .long __irq_can_sce + .long __irq_exti9_5 + .long __irq_tim1_brk + .long __irq_tim1_up + .long __irq_tim1_trg_com + .long __irq_tim1_cc + .long __irq_tim2 + .long __irq_tim3 + .long __irq_tim4 + .long __irq_i2c1_ev + .long __irq_i2c1_er + .long __irq_i2c2_ev + .long __irq_i2c2_er + .long __irq_spi1 + .long __irq_spi2 + .long __irq_usart1 + .long __irq_usart2 + .long __irq_usart3 + .long __irq_exti15_10 + .long __irq_rtcalarm + .long __irq_usbwakeup +#if defined (STM32_HIGH_DENSITY) + .long __irq_tim8_brk + .long __irq_tim8_up + .long __irq_tim8_trg_com + .long __irq_tim8_cc + .long __irq_adc3 + .long __irq_fsmc + .long __irq_sdio + .long __irq_tim5 + .long __irq_spi3 + .long __irq_uart4 + .long __irq_uart5 + .long __irq_tim6 + .long __irq_tim7 + .long __irq_dma2_channel1 + .long __irq_dma2_channel2 + .long __irq_dma2_channel3 + .long __irq_dma2_channel4_5 +#endif /* STM32_HIGH_DENSITY */ + + .long __irq_DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */ + .long __irq_ETH_IRQHandler /* Ethernet */ + .long __irq_ETH_WKUP_IRQHandler /* Ethernet Wakeup through EXTI line */ + .long __irq_CAN2_TX_IRQHandler /* CAN2 TX */ + .long __irq_CAN2_RX0_IRQHandler /* CAN2 RX0 */ + .long __irq_CAN2_RX1_IRQHandler /* CAN2 RX1 */ + .long __irq_CAN2_SCE_IRQHandler /* CAN2 SCE */ + .long __irq_OTG_FS_IRQHandler /* USB OTG FS */ + .long __irq_DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */ + .long __irq_DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */ + .long __irq_DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */ + .long __irq_USART6_IRQHandler /* USART6 */ + .long __irq_I2C3_EV_IRQHandler /* I2C3 event */ + .long __irq_I2C3_ER_IRQHandler /* I2C3 error */ + .long __irq_OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */ + .long __irq_OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */ + .long __irq_OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */ + .long __irq_OTG_HS_IRQHandler /* USB OTG HS */ + .long __irq_DCMI_IRQHandler /* DCMI */ + .long __irq_CRYP_IRQHandler /* CRYP crypto */ + .long __irq_HASH_RNG_IRQHandler /* Hash and Rng */ + .long __irq_FPU_IRQHandler /* FPU */ + + .size __stm32_vector_table, . - __stm32_vector_table diff --git a/STM32F4/variants/generic_f407v/variant.h b/STM32F4/variants/generic_f407v/variant.h new file mode 100644 index 0000000..cd0a96d --- /dev/null +++ b/STM32F4/variants/generic_f407v/variant.h @@ -0,0 +1,21 @@ +#ifndef _VARIANT_ARDUINO_STM32_ +#define _VARIANT_ARDUINO_STM32_ + + +#define digitalPinToPort(P) ( PIN_MAP[P].gpio_device ) +#define digitalPinToBitMask(P) ( BIT(PIN_MAP[P].gpio_bit) ) +#define portOutputRegister(port) ( &(port->regs->ODR) ) +#define portInputRegister(port) ( &(port->regs->IDR) ) + +#define portSetRegister(pin) ( &(PIN_MAP[pin].gpio_device->regs->BSRR) ) +#define portClearRegister(pin) ( &(PIN_MAP[pin].gpio_device->regs->BRR) ) + +#define portConfigRegister(pin) ( &(PIN_MAP[pin].gpio_device->regs->CRL) ) + +static const uint8_t SS = BOARD_SPI1_NSS_PIN; +static const uint8_t SS1 = BOARD_SPI2_NSS_PIN; +static const uint8_t MOSI = BOARD_SPI1_MOSI_PIN; +static const uint8_t MISO = BOARD_SPI1_MISO_PIN; +static const uint8_t SCK = BOARD_SPI1_SCK_PIN; + +#endif /* _VARIANT_ARDUINO_STM32_ */ \ No newline at end of file diff --git a/STM32F4/cores/maple/libmaple/rcc.c b/STM32F4/variants/generic_f407v/wirish/start.S similarity index 54% rename from STM32F4/cores/maple/libmaple/rcc.c rename to STM32F4/variants/generic_f407v/wirish/start.S index b3cb9c5..8b181aa 100644 --- a/STM32F4/cores/maple/libmaple/rcc.c +++ b/STM32F4/variants/generic_f407v/wirish/start.S @@ -1,7 +1,7 @@ /****************************************************************************** * The MIT License * - * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2011 LeafLabs, LLC. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -24,14 +24,34 @@ * SOFTWARE. *****************************************************************************/ -/** - * @file rcc.c - * @brief Implements pretty much only the basic clock setup on the - * stm32, clock enable/disable and peripheral reset commands. +/* + * This file is a modified version of a file obtained from + * CodeSourcery Inc. (now part of Mentor Graphics Corp.), in which the + * following text appeared: + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. */ -// #ifdef STM32F2 -// #include "rccF2.c" -// #else -// #include "rccF1.c" -// #endif + .text + .code 16 + .thumb_func + + .globl __start__ + .type __start__, %function +__start__: + .fnstart + ldr r1,=__msp_init + mov sp,r1 + ldr r1,=start_c + bx r1 + .pool + .cantunwind + .fnend diff --git a/STM32F4/variants/generic_f407v/wirish/start_c.c b/STM32F4/variants/generic_f407v/wirish/start_c.c new file mode 100644 index 0000000..655fefb --- /dev/null +++ b/STM32F4/variants/generic_f407v/wirish/start_c.c @@ -0,0 +1,95 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/* + * This file is a modified version of a file obtained from + * CodeSourcery Inc. (now part of Mentor Graphics Corp.), in which the + * following text appeared: + * + * Copyright (c) 2006, 2007 CodeSourcery Inc + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + */ + +#include + +extern void __libc_init_array(void); + +extern int main(int, char**, char**); + +extern void exit(int) __attribute__((noreturn, weak)); + +/* The linker must ensure that these are at least 4-byte aligned. */ +extern char __data_start__, __data_end__; +extern char __bss_start__, __bss_end__; + +struct rom_img_cfg { + int *img_start; +}; + +extern char _lm_rom_img_cfgp; + +void __attribute__((noreturn)) start_c(void) { + struct rom_img_cfg *img_cfg = (struct rom_img_cfg*)&_lm_rom_img_cfgp; + int *src = img_cfg->img_start; + int *dst = (int*)&__data_start__; + int exit_code; + + /* Initialize .data, if necessary. */ + if (src != dst) { + int *end = (int*)&__data_end__; + while (dst < end) { + *dst++ = *src++; + } + } + + /* Zero .bss. */ + dst = (int*)&__bss_start__; + while (dst < (int*)&__bss_end__) { + *dst++ = 0; + } + + /* Run initializers. */ + __libc_init_array(); + + /* Jump to main. */ + exit_code = main(0, 0, 0); + if (exit) { + exit(exit_code); + } + + /* If exit is NULL, make sure we don't return. */ + for (;;) + continue; +} From 220247c115287b4208407c34ee080d609e5bab0e Mon Sep 17 00:00:00 2001 From: stevstrong Date: Fri, 12 May 2017 20:51:12 +0200 Subject: [PATCH 043/351] bugfix: other variants than generic did not work --- STM32F4/boards.txt | 22 +- STM32F4/cores/maple/libmaple/gpioF4.c | 10 +- STM32F4/cores/maple/wirish_types.h | 4 +- STM32F4/libraries/SPI/src/SPI.h | 1 + .../variants/discovery_f407/discovery_f4.cpp | 277 +++++++++--------- .../variants/discovery_f407/discovery_f4.h | 3 + 6 files changed, 171 insertions(+), 146 deletions(-) diff --git a/STM32F4/boards.txt b/STM32F4/boards.txt index 04bfd0f..8fc1430 100644 --- a/STM32F4/boards.txt +++ b/STM32F4/boards.txt @@ -31,6 +31,12 @@ discovery_f407.build.error_led_port=GPIOD discovery_f407.build.error_led_pin=14 discovery_f407.build.board=STM32DiscoveryF407 +discovery_f407.menu.usb_cfg.usb_nc=USB inactive +discovery_f407.menu.usb_cfg.usb_nc.build.cpu_flags=-DUSB_NC +discovery_f407.menu.usb_cfg.usb_serial=USB serial (CDC) +discovery_f407.menu.usb_cfg.usb_serial.build.cpu_flags=-DSERIAL_USB +discovery_f407.menu.usb_cfg.usb_msc=USB Mass Storage (MSC) +discovery_f407.menu.usb_cfg.usb_msc.build.cpu_flags=-DUSB_MSC ############################################################## generic_f407v.name=Generic STM32F407V series @@ -88,7 +94,7 @@ stm32f4stamp.upload.dfuse_addr=0x8000000 stm32f4stamp.build.mcu=cortex-m4 stm32f4stamp.build.f_cpu=168000000L stm32f4stamp.build.core=maple -stm32f4stamp.build.extra_flags=-DMCU_STM32F406VG -mthumb -DSTM32_HIGH_DENSITY -DSTM32F2 -DSTM32F4 -DBOARD_discovery_f4 +stm32f4stamp.build.extra_flags=-DMCU_STM32F406VG -mthumb -DSTM32_HIGH_DENSITY -DSTM32F4 -DBOARD_discovery_f4 stm32f4stamp.build.ldscript=ld/jtag.ld stm32f4stamp.build.variant=discovery_f407 stm32f4stamp.build.variant_system_lib=lib_f407.a @@ -98,6 +104,12 @@ stm32f4stamp.build.error_led_port=GPIOD stm32f4stamp.build.error_led_pin=14 stm32f4stamp.build.board=STM32F4StampF405 +stm32f4stamp.menu.usb_cfg.usb_nc=USB inactive +stm32f4stamp.menu.usb_cfg.usb_nc.build.cpu_flags=-DUSB_NC +stm32f4stamp.menu.usb_cfg.usb_serial=USB serial (CDC) +stm32f4stamp.menu.usb_cfg.usb_serial.build.cpu_flags=-DSERIAL_USB +stm32f4stamp.menu.usb_cfg.usb_msc=USB Mass Storage (MSC) +stm32f4stamp.menu.usb_cfg.usb_msc.build.cpu_flags=-DUSB_MSC ############################################################## netduino2plus.name=Netduino2 F405 @@ -118,7 +130,7 @@ netduino2plus.upload.dfuse_addr=0x8000000 netduino2plus.build.mcu=cortex-m4 netduino2plus.build.f_cpu=168000000L netduino2plus.build.core=maple -netduino2plus.build.extra_flags=-DMCU_STM32F406VG -mthumb -DSTM32_HIGH_DENSITY -DSTM32F2 -DSTM32F4 -DBOARD_discovery_f4 -DARDUINO_STM32F4_NETDUINO2PLUS +netduino2plus.build.extra_flags=-DMCU_STM32F406VG -mthumb -DSTM32_HIGH_DENSITY -DSTM32F4 -DBOARD_discovery_f4 -DARDUINO_STM32F4_NETDUINO2PLUS netduino2plus.build.ldscript=ld/jtag.ld netduino2plus.build.variant=discovery_f407 netduino2plus.build.variant_system_lib=lib_f407.a @@ -128,5 +140,11 @@ netduino2plus.build.error_led_port=GPIOD netduino2plus.build.error_led_pin=14 netduino2plus.build.board=Netduino2F405 +netduino2plus.menu.usb_cfg.usb_nc=USB inactive +netduino2plus.menu.usb_cfg.usb_nc.build.cpu_flags=-DUSB_NC +netduino2plus.menu.usb_cfg.usb_serial=USB serial (CDC) +netduino2plus.menu.usb_cfg.usb_serial.build.cpu_flags=-DSERIAL_USB +netduino2plus.menu.usb_cfg.usb_msc=USB Mass Storage (MSC) +netduino2plus.menu.usb_cfg.usb_msc.build.cpu_flags=-DUSB_MSC ############################################################## diff --git a/STM32F4/cores/maple/libmaple/gpioF4.c b/STM32F4/cores/maple/libmaple/gpioF4.c index 67d3bea..af839eb 100644 --- a/STM32F4/cores/maple/libmaple/gpioF4.c +++ b/STM32F4/cores/maple/libmaple/gpioF4.c @@ -124,14 +124,14 @@ void gpio_init_all(void) { #ifdef ARDUINO_STM32F4_NETDUINO2PLUS // PA8 Output the Master Clock MCO1 - gpio_set_af_mode(GPIOA, 8, 0); - gpio_set_mode(GPIOA, 8, GPIO_MODE_AF | GPIO_OTYPE_PP | GPIO_OSPEED_100MHZ); + gpio_set_af_mode(PA8, 0); + gpio_set_mode(PA8, GPIO_MODE_AF | GPIO_OTYPE_PP | GPIO_OSPEED_100MHZ); // PB4 as alternate MISO Input - gpio_set_af_mode(GPIOB, 4, 5); + gpio_set_af_mode(PB4, 5); // PA5 as alternate SCK Output - gpio_set_af_mode(GPIOA, 5, 5); + gpio_set_af_mode(PA5, 5); // PA7 as alternate MOSI Output - gpio_set_af_mode(GPIOA, 7, 5); + gpio_set_af_mode(PA7, 5); #endif } diff --git a/STM32F4/cores/maple/wirish_types.h b/STM32F4/cores/maple/wirish_types.h index 6a8c85c..de685bf 100644 --- a/STM32F4/cores/maple/wirish_types.h +++ b/STM32F4/cores/maple/wirish_types.h @@ -60,13 +60,11 @@ typedef struct stm32_pin_info { #else typedef struct stm32_pin_info { - gpio_dev *gpio_device; /**< Maple pin's GPIO device */ + const gpio_dev *gpio_device; /**< Maple pin's GPIO device */ timer_dev *timer_device; /**< Pin's timer device, if any. */ const adc_dev *adc_device; /**< ADC device, if any. */ - uint8 gpio_bit; /**< Pin's GPIO port bit. */ uint8 timer_channel; /**< Timer channel, or 0 if none. */ uint8 adc_channel; /**< Pin ADC channel, or ADCx if none. */ - uint8 filler; } stm32_pin_info; #endif diff --git a/STM32F4/libraries/SPI/src/SPI.h b/STM32F4/libraries/SPI/src/SPI.h index 218449f..cabc0c2 100644 --- a/STM32F4/libraries/SPI/src/SPI.h +++ b/STM32F4/libraries/SPI/src/SPI.h @@ -42,6 +42,7 @@ #include #include +#define SPI_DMA // SPI_HAS_TRANSACTION means SPI has // - beginTransaction() diff --git a/STM32F4/variants/discovery_f407/discovery_f4.cpp b/STM32F4/variants/discovery_f407/discovery_f4.cpp index d97074e..74660f0 100644 --- a/STM32F4/variants/discovery_f407/discovery_f4.cpp +++ b/STM32F4/variants/discovery_f407/discovery_f4.cpp @@ -34,182 +34,187 @@ #include "discovery_f4.h" -//#include "fsmc.h" -#include "gpio.h" -#include "rcc.h" -#include "timer.h" +#include +#include #include "wirish_types.h" //static void initSRAMChip(void); void boardInit(void) { // remap TIMER8 to PC6-9 - gpio_set_af_mode(GPIOC, 6, 3); - gpio_set_af_mode(GPIOC, 7, 3); - gpio_set_af_mode(GPIOC, 8, 3); - gpio_set_af_mode(GPIOC, 9, 3); + gpio_set_af_mode(PC6, 3); + gpio_set_af_mode(PC7, 3); + gpio_set_af_mode(PC8, 3); + gpio_set_af_mode(PC9, 3); // remap TIMER1 to PE9,11,13,14 - gpio_set_af_mode(GPIOE, 9, 1); - gpio_set_af_mode(GPIOE, 11, 1); - gpio_set_af_mode(GPIOE, 13, 1); - gpio_set_af_mode(GPIOE, 14, 1); + gpio_set_af_mode(PE9, 1); + gpio_set_af_mode(PE11, 1); + gpio_set_af_mode(PE13, 1); + gpio_set_af_mode(PE14, 1); // remap TIMER3 to PB4,5,0,1 - gpio_set_af_mode(GPIOB, 4, 2); - gpio_set_af_mode(GPIOB, 5, 2); - gpio_set_af_mode(GPIOB, 0, 2); - gpio_set_af_mode(GPIOB, 1, 2); + gpio_set_af_mode(PB4, 2); + gpio_set_af_mode(PB5, 2); + gpio_set_af_mode(PB0, 2); + gpio_set_af_mode(PB1, 2); //gpio_set_af_mode(GPIOA, 2, 7); //gpio_set_af_mode(GPIOA, 3, 7); #ifdef ARDUINO_STM32F4_NETDUINO2PLUS // PA8 Output the Master Clock MCO1 - gpio_set_af_mode(GPIOA, 8, 0); + gpio_set_af_mode(PA8, 0); // PB4 as alternate MISO Input - gpio_set_af_mode(GPIOB, 4, 5); + gpio_set_af_mode(PB4, 5); // PA5 as alternate SCK Output - gpio_set_af_mode(GPIOA, 5, 5); + gpio_set_af_mode(PA5, 5); // PA7 as alternate MOSI Output - gpio_set_af_mode(GPIOA, 7, 5); + gpio_set_af_mode(PA7, 5); #endif return; } +extern timer_dev timer1; +extern timer_dev timer2; +extern timer_dev timer3; +extern timer_dev timer4; +extern timer_dev timer5; +extern timer_dev timer6; +extern timer_dev timer7; +extern timer_dev timer8; + #if 0 typedef struct stm32_pin_info { gpio_dev *gpio_device; /**< Maple pin's GPIO device */ timer_dev *timer_device; /**< Pin's timer device, if any. */ const adc_dev *adc_device; /**< ADC device, if any. */ - uint8 gpio_bit; /**< Pin's GPIO port bit. */ uint8 timer_channel; /**< Timer channel, or 0 if none. */ uint8 adc_channel; /**< Pin ADC channel, or ADCx if none. */ } stm32_pin_info; - #endif extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { - {GPIOA, TIMER5, ADC1, 0, 1, 0}, /* D00/PA0 */ - {GPIOA, TIMER5, ADC1, 1, 2, 1}, /* D01/PA1 */ - {GPIOA, TIMER5, ADC1, 2, 3, 2}, /* D02/PA2 */ - {GPIOA, TIMER5, ADC1, 3, 4, 3}, /* D03/PA3 */ - {GPIOA, NULL, ADC1, 4, 0, 4}, /* D04/PA4 */ - {GPIOA, NULL, ADC1, 5, 0, 5}, /* D05/PA5 */ - {GPIOA, NULL, ADC1, 6, 1, 6}, /* D06/PA6 */ // ala check TIMER3 - {GPIOA, NULL, ADC1, 7, 0, 7}, /* D07/PA7 */ - {GPIOA, NULL, NULL, 8, 0, ADCx}, /* D08/PA8 */ // remap out - {GPIOA, NULL, NULL, 9, 0, ADCx}, /* D09/PA9 */ // remap out - {GPIOA, NULL, NULL, 10, 0, ADCx}, /* D10/PA10 */ // remap out - {GPIOA, NULL, NULL, 11, 0, ADCx}, /* D11/PA11 */ // remap out - {GPIOA, NULL, NULL, 12, 0, ADCx}, /* D12/PA12 */ - {GPIOA, NULL, NULL, 13, 0, ADCx}, /* D13/PA13 */ - {GPIOA, NULL, NULL, 14, 0, ADCx}, /* D14/PA14 */ - {GPIOA, TIMER2, NULL, 15, 1, ADCx}, /* D15/PA15 */ // remap in + {&GPIOA, &timer5, &ADC1, 1, 0}, /* D00/PA0 */ + {&GPIOA, &timer5, &ADC1, 2, 1}, /* D01/PA1 */ + {&GPIOA, &timer5, &ADC1, 3, 2}, /* D02/PA2 */ + {&GPIOA, &timer5, &ADC1, 4, 3}, /* D03/PA3 */ + {&GPIOA, NULL, &ADC1, 0, 4}, /* D04/PA4 */ + {&GPIOA, NULL, &ADC1, 0, 5}, /* D05/PA5 */ + {&GPIOA, NULL, &ADC1, 1, 6}, /* D06/PA6 */ // ala check TIMER3 + {&GPIOA, NULL, &ADC1, 0, 7}, /* D07/PA7 */ + {&GPIOA, NULL, NULL, 0, ADCx}, /* D08/PA8 */ // remap out + {&GPIOA, NULL, NULL, 0, ADCx}, /* D09/PA9 */ // remap out + {&GPIOA, NULL, NULL, 0, ADCx}, /* D10/PA10 */ // remap out + {&GPIOA, NULL, NULL, 0, ADCx}, /* D11/PA11 */ // remap out + {&GPIOA, NULL, NULL, 0, ADCx}, /* D12/PA12 */ + {&GPIOA, NULL, NULL, 0, ADCx}, /* D13/PA13 */ + {&GPIOA, NULL, NULL, 0, ADCx}, /* D14/PA14 */ + {&GPIOA, &timer2, NULL, 1, ADCx}, /* D15/PA15 */ // remap in - {GPIOB, TIMER3, ADC1, 0, 3, 8}, /* D16/PB0 */ - {GPIOB, TIMER3, ADC1, 1, 4, 9}, /* D17/PB1 */ - {GPIOB, NULL, NULL, 2, 0, ADCx}, /* D18/PB2 */ - {GPIOB, TIMER2, NULL, 3, 2, ADCx}, /* D19/PB3 */ // remap in - {GPIOB, TIMER3, NULL, 4, 1, ADCx}, /* D20/PB4 */ // remap in - {GPIOB, TIMER3, NULL, 5, 2, ADCx}, /* D21/PB5 */ // remap in - {GPIOB, NULL, NULL, 6, 0, ADCx}, /* D22/PB6 */ // remap out - {GPIOB, NULL, NULL, 7, 0, ADCx}, /* D23/PB7 */ // remap out - {GPIOB, NULL, NULL, 8, 0, ADCx}, /* D24/PB8 */ // remap out - {GPIOB, NULL, NULL, 9, 0, ADCx}, /* D25/PB9 */ // remap out - {GPIOB, NULL, NULL, 10, 0, ADCx}, /* D26/PB10 */ - {GPIOB, NULL, NULL, 11, 0, ADCx}, /* D27/PB11 */ - {GPIOB, NULL, NULL, 12, 0, ADCx}, /* D28/PB12 */ - {GPIOB, NULL, NULL, 13, 0, ADCx}, /* D29/PB13 */ - {GPIOB, NULL, NULL, 14, 0, ADCx}, /* D30/PB14 */ - {GPIOB, NULL, NULL, 15, 0, ADCx}, /* D31/PB15 */ + {&GPIOB, &timer3, &ADC1, 3, 8}, /* D16/PB0 */ + {&GPIOB, &timer3, &ADC1, 4, 9}, /* D17/PB1 */ + {&GPIOB, NULL, NULL, 0, ADCx}, /* D18/PB2 */ + {&GPIOB, &timer2, NULL, 2, ADCx}, /* D19/PB3 */ // remap in + {&GPIOB, &timer3, NULL, 1, ADCx}, /* D20/PB4 */ // remap in + {&GPIOB, &timer3, NULL, 2, ADCx}, /* D21/PB5 */ // remap in + {&GPIOB, NULL, NULL, 0, ADCx}, /* D22/PB6 */ // remap out + {&GPIOB, NULL, NULL, 0, ADCx}, /* D23/PB7 */ // remap out + {&GPIOB, NULL, NULL, 0, ADCx}, /* D24/PB8 */ // remap out + {&GPIOB, NULL, NULL, 0, ADCx}, /* D25/PB9 */ // remap out + {&GPIOB, NULL, NULL, 0, ADCx}, /* D26/PB10 */ + {&GPIOB, NULL, NULL, 0, ADCx}, /* D27/PB11 */ + {&GPIOB, NULL, NULL, 0, ADCx}, /* D28/PB12 */ + {&GPIOB, NULL, NULL, 0, ADCx}, /* D29/PB13 */ + {&GPIOB, NULL, NULL, 0, ADCx}, /* D30/PB14 */ + {&GPIOB, NULL, NULL, 0, ADCx}, /* D31/PB15 */ - {GPIOC, NULL, ADC1, 0, 0, 10}, /* D32/PC0 */ - {GPIOC, NULL, ADC1, 1, 0, 11}, /* D33/PC1 */ - {GPIOC, NULL, ADC1, 2, 0, 12}, /* D34/PC2 */ - {GPIOC, NULL, ADC1, 3, 0, 13}, /* D35/PC3 */ - {GPIOC, NULL, ADC1, 4, 0, 14}, /* D36/PC4 */ - {GPIOC, NULL, ADC1, 5, 0, 15}, /* D37/PC5 */ - {GPIOC, TIMER8, NULL, 6, 1, ADCx}, /* D38/PC6 */ - {GPIOC, TIMER8, NULL, 7, 2, ADCx}, /* D39/PC7 */ - {GPIOC, TIMER8, NULL, 8, 3, ADCx}, /* D40/PC8 */ - {GPIOC, TIMER8, NULL, 9, 4, ADCx}, /* D41/PC9 */ - {GPIOC, NULL, NULL, 10, 0, ADCx}, /* D42/PC10 */ - {GPIOC, NULL, NULL, 11, 0, ADCx}, /* D43/PC11 */ - {GPIOC, NULL, NULL, 12, 0, ADCx}, /* D44/PC12 */ - {GPIOC, NULL, NULL, 13, 0, ADCx}, /* D45/PC13 */ - {GPIOC, NULL, NULL, 14, 0, ADCx}, /* D46/PC14 */ - {GPIOC, NULL, NULL, 15, 0, ADCx}, /* D47/PC15 */ + {&GPIOC, NULL, &ADC1, 0, 10}, /* D32/PC0 */ + {&GPIOC, NULL, &ADC1, 0, 11}, /* D33/PC1 */ + {&GPIOC, NULL, &ADC1, 0, 12}, /* D34/PC2 */ + {&GPIOC, NULL, &ADC1, 0, 13}, /* D35/PC3 */ + {&GPIOC, NULL, &ADC1, 0, 14}, /* D36/PC4 */ + {&GPIOC, NULL, &ADC1, 0, 15}, /* D37/PC5 */ + {&GPIOC, &timer8, NULL, 1, ADCx}, /* D38/PC6 */ + {&GPIOC, &timer8, NULL, 2, ADCx}, /* D39/PC7 */ + {&GPIOC, &timer8, NULL, 3, ADCx}, /* D40/PC8 */ + {&GPIOC, &timer8, NULL, 4, ADCx}, /* D41/PC9 */ + {&GPIOC, NULL, NULL, 0, ADCx}, /* D42/PC10 */ + {&GPIOC, NULL, NULL, 0, ADCx}, /* D43/PC11 */ + {&GPIOC, NULL, NULL, 0, ADCx}, /* D44/PC12 */ + {&GPIOC, NULL, NULL, 0, ADCx}, /* D45/PC13 */ + {&GPIOC, NULL, NULL, 0, ADCx}, /* D46/PC14 */ + {&GPIOC, NULL, NULL, 0, ADCx}, /* D47/PC15 */ - {GPIOD, NULL, NULL, 0, 0, ADCx}, /* D48/PD0 */ - {GPIOD, NULL, NULL, 1, 0, ADCx}, /* D49/PD1 */ - {GPIOD, NULL, NULL, 2, 0, ADCx}, /* D50/PD2 */ - {GPIOD, NULL, NULL, 3, 0, ADCx}, /* D51/PD3 */ - {GPIOD, NULL, NULL, 4, 0, ADCx}, /* D52/PD4 */ - {GPIOD, NULL, NULL, 5, 0, ADCx}, /* D53/PD5 */ - {GPIOD, NULL, NULL, 6, 0, ADCx}, /* D54/PD6 */ - {GPIOD, NULL, NULL, 7, 0, ADCx}, /* D55/PD7 */ - {GPIOD, NULL, NULL, 8, 0, ADCx}, /* D56/PD8 */ - {GPIOD, NULL, NULL, 9, 0, ADCx}, /* D57/PD9 */ - {GPIOD, NULL, NULL, 10, 0, ADCx}, /* D58/PD10 */ - {GPIOD, NULL, NULL, 11, 0, ADCx}, /* D59/PD11 */ - {GPIOD, TIMER4, NULL, 12, 1, ADCx}, /* D60/PD12 */ // remap in - {GPIOD, TIMER4, NULL, 13, 2, ADCx}, /* D61/PD13 */ // remap in - {GPIOD, TIMER4, NULL, 14, 3, ADCx}, /* D62/PD14 */ // remap in - {GPIOD, TIMER4, NULL, 15, 4, ADCx}, /* D63/PD15 */ // remap in + {&GPIOD, NULL, NULL, 0, ADCx}, /* D48/PD0 */ + {&GPIOD, NULL, NULL, 0, ADCx}, /* D49/PD1 */ + {&GPIOD, NULL, NULL, 0, ADCx}, /* D50/PD2 */ + {&GPIOD, NULL, NULL, 0, ADCx}, /* D51/PD3 */ + {&GPIOD, NULL, NULL, 0, ADCx}, /* D52/PD4 */ + {&GPIOD, NULL, NULL, 0, ADCx}, /* D53/PD5 */ + {&GPIOD, NULL, NULL, 0, ADCx}, /* D54/PD6 */ + {&GPIOD, NULL, NULL, 0, ADCx}, /* D55/PD7 */ + {&GPIOD, NULL, NULL, 0, ADCx}, /* D56/PD8 */ + {&GPIOD, NULL, NULL, 0, ADCx}, /* D57/PD9 */ + {&GPIOD, NULL, NULL, 0, ADCx}, /* D58/PD10 */ + {&GPIOD, NULL, NULL, 0, ADCx}, /* D59/PD11 */ + {&GPIOD, &timer4, NULL, 1, ADCx}, /* D60/PD12 */ // remap in + {&GPIOD, &timer4, NULL, 2, ADCx}, /* D61/PD13 */ // remap in + {&GPIOD, &timer4, NULL, 3, ADCx}, /* D62/PD14 */ // remap in + {&GPIOD, &timer4, NULL, 4, ADCx}, /* D63/PD15 */ // remap in - {GPIOE, NULL, NULL, 0, 0, ADCx}, /* D64/PE0 */ - {GPIOE, NULL, NULL, 1, 0, ADCx}, /* D65/PE1 */ - {GPIOE, NULL, NULL, 2, 0, ADCx}, /* D66/PE2 */ - {GPIOE, NULL, NULL, 3, 0, ADCx}, /* D67/PE3 */ - {GPIOE, NULL, NULL, 4, 0, ADCx}, /* D68/PE4 */ - {GPIOE, NULL, NULL, 5, 0, ADCx}, /* D69/PE5 */ - {GPIOE, NULL, NULL, 6, 0, ADCx}, /* D70/PE6 */ - {GPIOE, NULL, NULL, 7, 0, ADCx}, /* D71/PE7 */ - {GPIOE, NULL, NULL, 8, 0, ADCx}, /* D72/PE8 */ - {GPIOE, TIMER1, NULL, 9, 1, ADCx}, /* D73/PE9 */ // remap in - {GPIOE, NULL, NULL, 10, 0, ADCx}, /* D74/PE10 */ - {GPIOE, TIMER1, NULL, 11, 2, ADCx}, /* D75/PE11 */ // remap in - {GPIOE, NULL, NULL, 12, 0, ADCx}, /* D76/PE12 */ - {GPIOE, TIMER1, NULL, 13, 3, ADCx}, /* D77/PE13 */ // remap in - {GPIOE, TIMER1, NULL, 14, 4, ADCx}, /* D78/PE14 */ // remap in - {GPIOE, NULL, NULL, 15, 0, ADCx}, /* D79/PE15 */ - - {GPIOF, NULL, NULL, 0, 0, ADCx}, /* D80/PF0 */ - {GPIOF, NULL, NULL, 1, 0, ADCx}, /* D81/PF1 */ - {GPIOF, NULL, NULL, 2, 0, ADCx}, /* D82/PF2 */ - {GPIOF, NULL, NULL, 3, 0, ADCx}, /* D83/PF3 */ - {GPIOF, NULL, NULL, 4, 0, ADCx}, /* D84/PF4 */ - {GPIOF, NULL, NULL, 5, 0, ADCx}, /* D85/PF5 */ - {GPIOF, NULL, NULL, 6, 0, ADCx}, /* D86/PF6 */ - {GPIOF, NULL, NULL, 7, 0, ADCx}, /* D87/PF7 */ - {GPIOF, NULL, NULL, 8, 0, ADCx}, /* D88/PF8 */ - {GPIOF, NULL, NULL, 9, 0, ADCx}, /* D89/PF9 */ - {GPIOF, NULL, NULL, 10, 0, ADCx}, /* D90/PF10 */ - {GPIOF, NULL, NULL, 11, 0, ADCx}, /* D91/PF11 */ - {GPIOF, NULL, NULL, 12, 0, ADCx}, /* D92/PF12 */ - {GPIOF, NULL, NULL, 13, 0, ADCx}, /* D93/PF13 */ - {GPIOF, NULL, NULL, 14, 0, ADCx}, /* D94/PF14 */ - {GPIOF, NULL, NULL, 15, 0, ADCx}, /* D95/PF15 */ - - {GPIOG, NULL, NULL, 0, 0, ADCx}, /* D96/PG0 */ - {GPIOG, NULL, NULL, 1, 0, ADCx}, /* D97/PG1 */ - {GPIOG, NULL, NULL, 2, 0, ADCx}, /* D98/PG2 */ - {GPIOG, NULL, NULL, 3, 0, ADCx}, /* D99/PG3 */ - {GPIOG, NULL, NULL, 4, 0, ADCx}, /* D100/PG4 */ - {GPIOG, NULL, NULL, 5, 0, ADCx}, /* D101/PG5 */ - {GPIOG, NULL, NULL, 6, 0, ADCx}, /* D102/PG6 */ - {GPIOG, NULL, NULL, 7, 0, ADCx}, /* D103/PG7 */ - {GPIOG, NULL, NULL, 8, 0, ADCx}, /* D104/PG8 */ - {GPIOG, NULL, NULL, 9, 0, ADCx}, /* D105/PG9 */ - {GPIOG, NULL, NULL, 10, 0, ADCx}, /* D106/PG10 */ - {GPIOG, NULL, NULL, 11, 0, ADCx}, /* D107/PG11 */ - {GPIOG, NULL, NULL, 12, 0, ADCx}, /* D108/PG12 */ - {GPIOG, NULL, NULL, 13, 0, ADCx}, /* D109/PG13 */ - {GPIOG, NULL, NULL, 14, 0, ADCx}, /* D110/PG14 */ - {GPIOG, NULL, NULL, 15, 0, ADCx} /* D111/PG15 */ + {&GPIOE, NULL, NULL, 0, ADCx}, /* D64/PE0 */ + {&GPIOE, NULL, NULL, 0, ADCx}, /* D65/PE1 */ + {&GPIOE, NULL, NULL, 0, ADCx}, /* D66/PE2 */ + {&GPIOE, NULL, NULL, 0, ADCx}, /* D67/PE3 */ + {&GPIOE, NULL, NULL, 0, ADCx}, /* D68/PE4 */ + {&GPIOE, NULL, NULL, 0, ADCx}, /* D69/PE5 */ + {&GPIOE, NULL, NULL, 0, ADCx}, /* D70/PE6 */ + {&GPIOE, NULL, NULL, 0, ADCx}, /* D71/PE7 */ + {&GPIOE, NULL, NULL, 0, ADCx}, /* D72/PE8 */ + {&GPIOE, &timer1, NULL, 1, ADCx}, /* D73/PE9 */ // remap in + {&GPIOE, NULL, NULL, 0, ADCx}, /* D74/PE10 */ + {&GPIOE, &timer1, NULL, 2, ADCx}, /* D75/PE11 */ // remap in + {&GPIOE, NULL, NULL, 0, ADCx}, /* D76/PE12 */ + {&GPIOE, &timer1, NULL, 3, ADCx}, /* D77/PE13 */ // remap in + {&GPIOE, &timer1, NULL, 4, ADCx}, /* D78/PE14 */ // remap in + {&GPIOE, NULL, NULL, 0, ADCx}, /* D79/PE15 */ +#if 0 // not available on LQFP100 package + {&GPIOF, NULL, NULL, 0, ADCx}, /* D80/PF0 */ + {&GPIOF, NULL, NULL, 0, ADCx}, /* D81/PF1 */ + {&GPIOF, NULL, NULL, 0, ADCx}, /* D82/PF2 */ + {&GPIOF, NULL, NULL, 0, ADCx}, /* D83/PF3 */ + {&GPIOF, NULL, NULL, 0, ADCx}, /* D84/PF4 */ + {&GPIOF, NULL, NULL, 0, ADCx}, /* D85/PF5 */ + {&GPIOF, NULL, NULL, 0, ADCx}, /* D86/PF6 */ + {&GPIOF, NULL, NULL, 0, ADCx}, /* D87/PF7 */ + {&GPIOF, NULL, NULL, 0, ADCx}, /* D88/PF8 */ + {&GPIOF, NULL, NULL, 0, ADCx}, /* D89/PF9 */ + {&GPIOF, NULL, NULL, 0, ADCx}, /* D90/PF10 */ + {&GPIOF, NULL, NULL, 0, ADCx}, /* D91/PF11 */ + {&GPIOF, NULL, NULL, 0, ADCx}, /* D92/PF12 */ + {&GPIOF, NULL, NULL, 0, ADCx}, /* D93/PF13 */ + {&GPIOF, NULL, NULL, 0, ADCx}, /* D94/PF14 */ + {&GPIOF, NULL, NULL, 0, ADCx}, /* D95/PF15 */ + {&GPIOG, NULL, NULL, 0, ADCx}, /* D96/PG0 */ + {&GPIOG, NULL, NULL, 0, ADCx}, /* D97/PG1 */ + {&GPIOG, NULL, NULL, 0, ADCx}, /* D98/PG2 */ + {&GPIOG, NULL, NULL, 0, ADCx}, /* D99/PG3 */ + {&GPIOG, NULL, NULL, 0, ADCx}, /* D100/PG4 */ + {&GPIOG, NULL, NULL, 0, ADCx}, /* D101/PG5 */ + {&GPIOG, NULL, NULL, 0, ADCx}, /* D102/PG6 */ + {&GPIOG, NULL, NULL, 0, ADCx}, /* D103/PG7 */ + {&GPIOG, NULL, NULL, 0, ADCx}, /* D104/PG8 */ + {&GPIOG, NULL, NULL, 0, ADCx}, /* D105/PG9 */ + {&GPIOG, NULL, NULL, 0, ADCx}, /* D106/PG10 */ + {&GPIOG, NULL, NULL, 0, ADCx}, /* D107/PG11 */ + {&GPIOG, NULL, NULL, 0, ADCx}, /* D108/PG12 */ + {&GPIOG, NULL, NULL, 0, ADCx}, /* D109/PG13 */ + {&GPIOG, NULL, NULL, 0, ADCx}, /* D110/PG14 */ + {&GPIOG, NULL, NULL, 0, ADCx} /* D111/PG15 */ +#endif // not available on LQFP100 package }; extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { diff --git a/STM32F4/variants/discovery_f407/discovery_f4.h b/STM32F4/variants/discovery_f407/discovery_f4.h index 7501752..e3fa046 100644 --- a/STM32F4/variants/discovery_f407/discovery_f4.h +++ b/STM32F4/variants/discovery_f407/discovery_f4.h @@ -50,6 +50,9 @@ #define BOARD_LED_PIN Port2Pin('D', 12) #define BOARD_BUTTON_PIN Port2Pin('A', 0) +#define BOARD_USB_DM_PIN PA11 +#define BOARD_USB_DP_PIN PA12 + #define BOARD_NR_USARTS 5 #define BOARD_USART1_TX_PIN Port2Pin('A', 9) #define BOARD_USART1_RX_PIN Port2Pin('A',10) From 97329efca32eb20b01047c0afdfba6eea877b5da Mon Sep 17 00:00:00 2001 From: stevstrong Date: Sat, 13 May 2017 10:27:33 +0200 Subject: [PATCH 044/351] push the generic_f4 branch to master --- STM32F1/libraries/SPI/src/SPI.cpp | 9 +- STM32F4/boards.txt | 61 +- STM32F4/cores/maple/Arduino.h | 6 - STM32F4/cores/maple/Client.h | 5 +- STM32F4/cores/maple/HardwareTimer.h | 2 +- STM32F4/cores/maple/IPAddress.h | 4 +- STM32F4/cores/maple/Server.h | 4 +- STM32F4/cores/maple/Stream.h | 4 +- STM32F4/cores/maple/Udp.h | 4 +- STM32F4/cores/maple/WProgram.h | 7 +- STM32F4/cores/maple/WString.h | 7 +- STM32F4/cores/maple/bits.h | 5 + STM32F4/cores/maple/boards.cpp | 32 +- STM32F4/cores/maple/boards.h | 39 +- STM32F4/cores/maple/ext_interrupts.cpp | 8 +- STM32F4/cores/maple/ext_interrupts.h | 9 +- STM32F4/cores/maple/io.h | 13 +- STM32F4/cores/maple/itoa.h | 4 +- STM32F4/cores/maple/libmaple/HardwareSPI.cpp | 424 ------------- STM32F4/cores/maple/libmaple/HardwareSPI.h | 279 --------- .../cores/maple/libmaple/HardwareSerial.cpp | 30 +- STM32F4/cores/maple/libmaple/HardwareSerial.h | 2 +- STM32F4/cores/maple/libmaple/adc.c | 33 +- STM32F4/cores/maple/libmaple/adc.h | 54 +- STM32F4/cores/maple/libmaple/dac.c | 4 +- STM32F4/cores/maple/libmaple/dma.h | 7 +- STM32F4/cores/maple/libmaple/dmaF1.c | 383 ------------ STM32F4/cores/maple/libmaple/dmaF1.h | 453 -------------- .../cores/maple/libmaple/{dmaF2.c => dmaF4.c} | 39 +- .../cores/maple/libmaple/{dmaF2.h => dmaF4.h} | 72 ++- STM32F4/cores/maple/libmaple/exti.h | 4 - STM32F4/cores/maple/libmaple/fsmc.c | 53 +- STM32F4/cores/maple/libmaple/gpio.h | 102 +++- STM32F4/cores/maple/libmaple/gpioF1.c | 200 ------ STM32F4/cores/maple/libmaple/gpioF1.h | 530 ---------------- .../maple/libmaple/{gpioF2.c => gpioF4.c} | 89 ++- .../maple/libmaple/{gpioF2.h => gpio_def.h} | 90 +-- STM32F4/cores/maple/libmaple/i2c.c | 40 +- STM32F4/cores/maple/libmaple/i2c.h | 2 +- STM32F4/cores/maple/libmaple/libmaple.h | 14 +- STM32F4/cores/maple/libmaple/libmaple_types.h | 15 +- STM32F4/cores/maple/libmaple/rcc.h | 7 +- STM32F4/cores/maple/libmaple/rccF1.c | 233 ------- STM32F4/cores/maple/libmaple/rccF1.h | 572 ------------------ .../cores/maple/libmaple/{rccF2.c => rccF4.c} | 7 +- .../cores/maple/libmaple/{rccF2.h => rccF4.h} | 0 STM32F4/cores/maple/libmaple/rules.mk | 22 - STM32F4/cores/maple/libmaple/spi.c | 39 +- STM32F4/cores/maple/libmaple/spi.h | 19 +- STM32F4/cores/maple/libmaple/spiF4.h | 15 +- STM32F4/cores/maple/libmaple/spi_f4.c | 26 +- STM32F4/cores/maple/libmaple/stm32.h | 63 +- STM32F4/cores/maple/libmaple/timer.c | 16 +- STM32F4/cores/maple/libmaple/timer.h | 19 +- STM32F4/cores/maple/libmaple/usart.h | 6 +- .../Class/audio/inc/usbd_audio_core.h | 2 +- .../Class/cdc/inc/usbd_cdc_core.h | 3 +- .../Class/cdc/src/usbd_cdc_core.c | 7 +- .../Core/inc/usbd_core.h | 4 +- .../Core/inc/usbd_def.h | 2 +- .../Core/inc/usbd_req.h | 2 +- .../Core/src/usbd_core.c | 10 +- .../Core/src/usbd_ioreq.c | 2 +- .../Core/src/usbd_req.c | 6 +- .../usbF4/STM32_USB_OTG_Driver/inc/usb_core.h | 2 +- .../STM32_USB_OTG_Driver/inc/usb_defines.h | 2 +- .../usbF4/STM32_USB_OTG_Driver/inc/usb_otg.h | 1 + .../usbF4/STM32_USB_OTG_Driver/inc/usb_regs.h | 4 +- .../usbF4/STM32_USB_OTG_Driver/src/usb_core.c | 4 +- .../usbF4/STM32_USB_OTG_Driver/src/usb_dcd.c | 4 +- .../STM32_USB_OTG_Driver/src/usb_dcd_int.c | 4 +- .../cores/maple/libmaple/usbF4/VCP/core_cm4.h | 2 +- STM32F4/cores/maple/libmaple/usbF4/VCP/misc.c | 2 +- .../cores/maple/libmaple/usbF4/VCP/usb_bsp.c | 22 +- .../cores/maple/libmaple/usbF4/VCP/usb_conf.h | 4 + .../maple/libmaple/usbF4/VCP/usbd_cdc_vcp.c | 2 +- .../maple/libmaple/usbF4/VCP/usbd_cdc_vcp.h | 2 +- .../maple/libmaple/usbF4/VCP/usbd_conf.h | 1 + .../maple/libmaple/usbF4/VCP/usbd_desc.c | 6 +- .../maple/libmaple/usbF4/VCP/usbd_desc.h | 2 +- .../cores/maple/libmaple/usbF4/VCP/usbd_usr.c | 4 +- STM32F4/cores/maple/libmaple/usbF4/usb.c | 33 +- STM32F4/cores/maple/libmaple/usbF4/usb.h | 2 +- STM32F4/cores/maple/libmaple/util.c | 6 +- STM32F4/cores/maple/libmaple/util.h | 5 +- STM32F4/cores/maple/pwm.cpp | 4 +- STM32F4/cores/maple/usb_serial.cpp | 6 +- STM32F4/cores/maple/usb_serial.h | 15 +- STM32F4/cores/maple/wirish.h | 15 +- STM32F4/cores/maple/wirish_analog.cpp | 2 - STM32F4/cores/maple/wirish_constants.h | 4 +- STM32F4/cores/maple/wirish_debug.h | 7 +- STM32F4/cores/maple/wirish_digital.cpp | 31 +- STM32F4/cores/maple/wirish_math.h | 4 +- STM32F4/cores/maple/wirish_time.cpp | 6 +- STM32F4/cores/maple/wirish_time.h | 5 +- STM32F4/cores/maple/wirish_types.h | 31 +- STM32F4/libraries/SPI/library.properties | 1 + STM32F4/libraries/SPI/src/SPI.cpp | 518 ++++++++-------- STM32F4/libraries/SPI/src/SPI.h | 162 ++--- STM32F4/platform.txt | 20 +- .../gpio.c => system/libmaple/Arduino.h} | 30 +- .../variants/generic_f407v/generic_f407v.cpp | 81 +++ .../variants/generic_f407v/generic_f407v.h | 163 +++++ STM32F4/variants/generic_f407v/ld/common.inc | 219 +++++++ .../variants/generic_f407v/ld/extra_libs.inc | 7 + STM32F4/variants/generic_f407v/ld/flash.ld | 20 + STM32F4/variants/generic_f407v/ld/jtag.ld | 20 + STM32F4/variants/generic_f407v/ld/names.inc | 78 +++ STM32F4/variants/generic_f407v/ld/ram.ld | 19 + .../generic_f407v/ld/vector_symbols.inc | 78 +++ STM32F4/variants/generic_f407v/pin_map.c | 210 +++++++ STM32F4/variants/generic_f407v/pins_arduino.h | 6 + STM32F4/variants/generic_f407v/stm32_isrs.S | 323 ++++++++++ .../generic_f407v/stm32_vector_table.S | 113 ++++ STM32F4/variants/generic_f407v/variant.h | 21 + .../generic_f407v/wirish/start.S} | 40 +- .../variants/generic_f407v/wirish/start_c.c | 95 +++ 118 files changed, 2581 insertions(+), 4111 deletions(-) delete mode 100644 STM32F4/cores/maple/Arduino.h delete mode 100644 STM32F4/cores/maple/libmaple/HardwareSPI.cpp delete mode 100644 STM32F4/cores/maple/libmaple/HardwareSPI.h delete mode 100644 STM32F4/cores/maple/libmaple/dmaF1.c delete mode 100644 STM32F4/cores/maple/libmaple/dmaF1.h rename STM32F4/cores/maple/libmaple/{dmaF2.c => dmaF4.c} (91%) rename STM32F4/cores/maple/libmaple/{dmaF2.h => dmaF4.h} (74%) delete mode 100644 STM32F4/cores/maple/libmaple/gpioF1.c delete mode 100644 STM32F4/cores/maple/libmaple/gpioF1.h rename STM32F4/cores/maple/libmaple/{gpioF2.c => gpioF4.c} (75%) rename STM32F4/cores/maple/libmaple/{gpioF2.h => gpio_def.h} (90%) delete mode 100644 STM32F4/cores/maple/libmaple/rccF1.c delete mode 100644 STM32F4/cores/maple/libmaple/rccF1.h rename STM32F4/cores/maple/libmaple/{rccF2.c => rccF4.c} (99%) rename STM32F4/cores/maple/libmaple/{rccF2.h => rccF4.h} (100%) rename STM32F4/{cores/maple/libmaple/gpio.c => system/libmaple/Arduino.h} (79%) create mode 100644 STM32F4/variants/generic_f407v/generic_f407v.cpp create mode 100644 STM32F4/variants/generic_f407v/generic_f407v.h create mode 100644 STM32F4/variants/generic_f407v/ld/common.inc create mode 100644 STM32F4/variants/generic_f407v/ld/extra_libs.inc create mode 100644 STM32F4/variants/generic_f407v/ld/flash.ld create mode 100644 STM32F4/variants/generic_f407v/ld/jtag.ld create mode 100644 STM32F4/variants/generic_f407v/ld/names.inc create mode 100644 STM32F4/variants/generic_f407v/ld/ram.ld create mode 100644 STM32F4/variants/generic_f407v/ld/vector_symbols.inc create mode 100644 STM32F4/variants/generic_f407v/pin_map.c create mode 100644 STM32F4/variants/generic_f407v/pins_arduino.h create mode 100644 STM32F4/variants/generic_f407v/stm32_isrs.S create mode 100644 STM32F4/variants/generic_f407v/stm32_vector_table.S create mode 100644 STM32F4/variants/generic_f407v/variant.h rename STM32F4/{cores/maple/libmaple/rcc.c => variants/generic_f407v/wirish/start.S} (54%) create mode 100644 STM32F4/variants/generic_f407v/wirish/start_c.c diff --git a/STM32F1/libraries/SPI/src/SPI.cpp b/STM32F1/libraries/SPI/src/SPI.cpp index 45ee25a..34c8102 100644 --- a/STM32F1/libraries/SPI/src/SPI.cpp +++ b/STM32F1/libraries/SPI/src/SPI.cpp @@ -391,11 +391,11 @@ uint8 SPIClass::dmaTransfer(void * transmitBuf, void * receiveBuf, uint16 length 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); // TX - uint32 flags = (DMA_MINC_MODE | DMA_FROM_MEM | DMA_TRNS_CMPLT); + uint32 flags = (DMA_MINC_MODE | DMA_FROM_MEM); spi_tx_dma_enable(_currentSetting->spi_d); if ( transmitBuf==0 ) { static uint8_t ff = 0XFF; @@ -407,13 +407,13 @@ uint8 SPIClass::dmaTransfer(void * transmitBuf, void * receiveBuf, uint16 length 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 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. 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." @@ -443,14 +443,13 @@ uint8 SPIClass::dmaSend(void * transmitBuf, uint16 length, bool minc) 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 -// 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. 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." diff --git a/STM32F4/boards.txt b/STM32F4/boards.txt index 7577d19..8fc1430 100644 --- a/STM32F4/boards.txt +++ b/STM32F4/boards.txt @@ -1,5 +1,7 @@ # +menu.usb_cfg=USB configuration + ############################################################## discovery_f407.name=STM32 Discovery F407 @@ -29,6 +31,49 @@ discovery_f407.build.error_led_port=GPIOD discovery_f407.build.error_led_pin=14 discovery_f407.build.board=STM32DiscoveryF407 +discovery_f407.menu.usb_cfg.usb_nc=USB inactive +discovery_f407.menu.usb_cfg.usb_nc.build.cpu_flags=-DUSB_NC +discovery_f407.menu.usb_cfg.usb_serial=USB serial (CDC) +discovery_f407.menu.usb_cfg.usb_serial.build.cpu_flags=-DSERIAL_USB +discovery_f407.menu.usb_cfg.usb_msc=USB Mass Storage (MSC) +discovery_f407.menu.usb_cfg.usb_msc.build.cpu_flags=-DUSB_MSC +############################################################## +generic_f407v.name=Generic STM32F407V series + +generic_f407v.upload.tool=stlink_upload +generic_f407v.upload.protocol=stlink + +generic_f407v.upload.file_type=bin +generic_f407v.upload.ram.maximum_size=131072 +generic_f407v.upload.flash.maximum_size=514288 +generic_f407v.upload.maximum_size=514288 + +#generic_f407v.upload.usbID=0483:3748 +#generic_f407v.upload.altID=1 +#generic_f407v.upload.auto_reset=true + +generic_f407v.build.mcu=cortex-m4 +generic_f407v.build.f_cpu=168000000L +generic_f407v.build.core=maple +generic_f407v.build.extra_flags=-mthumb -DSTM32_HIGH_DENSITY -DSTM32F4 -DBOARD_generic_f407v +generic_f407v.build.ldscript=ld/jtag.ld +generic_f407v.build.variant=generic_f407v +generic_f407v.build.variant_system_lib=lib_f407.a +generic_f407v.build.vect=VECT_TAB_BASE +generic_f407v.build.density=STM32_HIGH_DENSITY +generic_f407v.build.error_led_port=GPIOA +generic_f407v.build.error_led_pin=7 +generic_f407v.build.board=STM32GenericF407VET6 + +generic_f407v.menu.usb_cfg.usb_nc=USB inactive +generic_f407v.menu.usb_cfg.usb_nc.build.cpu_flags=-DUSB_NC + +generic_f407v.menu.usb_cfg.usb_serial=USB serial (CDC) +generic_f407v.menu.usb_cfg.usb_serial.build.cpu_flags=-DSERIAL_USB + +generic_f407v.menu.usb_cfg.usb_msc=USB Mass Storage (MSC) +generic_f407v.menu.usb_cfg.usb_msc.build.cpu_flags=-DUSB_MSC + ############################################################## stm32f4stamp.name=STM32F4Stamp F405 @@ -49,7 +94,7 @@ stm32f4stamp.upload.dfuse_addr=0x8000000 stm32f4stamp.build.mcu=cortex-m4 stm32f4stamp.build.f_cpu=168000000L stm32f4stamp.build.core=maple -stm32f4stamp.build.extra_flags=-DMCU_STM32F406VG -mthumb -DSTM32_HIGH_DENSITY -DSTM32F2 -DSTM32F4 -DBOARD_discovery_f4 +stm32f4stamp.build.extra_flags=-DMCU_STM32F406VG -mthumb -DSTM32_HIGH_DENSITY -DSTM32F4 -DBOARD_discovery_f4 stm32f4stamp.build.ldscript=ld/jtag.ld stm32f4stamp.build.variant=discovery_f407 stm32f4stamp.build.variant_system_lib=lib_f407.a @@ -59,6 +104,12 @@ stm32f4stamp.build.error_led_port=GPIOD stm32f4stamp.build.error_led_pin=14 stm32f4stamp.build.board=STM32F4StampF405 +stm32f4stamp.menu.usb_cfg.usb_nc=USB inactive +stm32f4stamp.menu.usb_cfg.usb_nc.build.cpu_flags=-DUSB_NC +stm32f4stamp.menu.usb_cfg.usb_serial=USB serial (CDC) +stm32f4stamp.menu.usb_cfg.usb_serial.build.cpu_flags=-DSERIAL_USB +stm32f4stamp.menu.usb_cfg.usb_msc=USB Mass Storage (MSC) +stm32f4stamp.menu.usb_cfg.usb_msc.build.cpu_flags=-DUSB_MSC ############################################################## netduino2plus.name=Netduino2 F405 @@ -79,7 +130,7 @@ netduino2plus.upload.dfuse_addr=0x8000000 netduino2plus.build.mcu=cortex-m4 netduino2plus.build.f_cpu=168000000L netduino2plus.build.core=maple -netduino2plus.build.extra_flags=-DMCU_STM32F406VG -mthumb -DSTM32_HIGH_DENSITY -DSTM32F2 -DSTM32F4 -DBOARD_discovery_f4 -DARDUINO_STM32F4_NETDUINO2PLUS +netduino2plus.build.extra_flags=-DMCU_STM32F406VG -mthumb -DSTM32_HIGH_DENSITY -DSTM32F4 -DBOARD_discovery_f4 -DARDUINO_STM32F4_NETDUINO2PLUS netduino2plus.build.ldscript=ld/jtag.ld netduino2plus.build.variant=discovery_f407 netduino2plus.build.variant_system_lib=lib_f407.a @@ -89,5 +140,11 @@ netduino2plus.build.error_led_port=GPIOD netduino2plus.build.error_led_pin=14 netduino2plus.build.board=Netduino2F405 +netduino2plus.menu.usb_cfg.usb_nc=USB inactive +netduino2plus.menu.usb_cfg.usb_nc.build.cpu_flags=-DUSB_NC +netduino2plus.menu.usb_cfg.usb_serial=USB serial (CDC) +netduino2plus.menu.usb_cfg.usb_serial.build.cpu_flags=-DSERIAL_USB +netduino2plus.menu.usb_cfg.usb_msc=USB Mass Storage (MSC) +netduino2plus.menu.usb_cfg.usb_msc.build.cpu_flags=-DUSB_MSC ############################################################## diff --git a/STM32F4/cores/maple/Arduino.h b/STM32F4/cores/maple/Arduino.h deleted file mode 100644 index d02a50c..0000000 --- a/STM32F4/cores/maple/Arduino.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef Arduino_h -#define Arduino_h -#include "WProgram.h" -#endif - -#include "variant.h" diff --git a/STM32F4/cores/maple/Client.h b/STM32F4/cores/maple/Client.h index b8e5d93..57bedb8 100644 --- a/STM32F4/cores/maple/Client.h +++ b/STM32F4/cores/maple/Client.h @@ -17,8 +17,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef client_h -#define client_h +#ifndef _CLIENT_H_ +#define _CLIENT_H_ + #include "Print.h" #include "Stream.h" #include "IPAddress.h" diff --git a/STM32F4/cores/maple/HardwareTimer.h b/STM32F4/cores/maple/HardwareTimer.h index 89e3564..c90356b 100644 --- a/STM32F4/cores/maple/HardwareTimer.h +++ b/STM32F4/cores/maple/HardwareTimer.h @@ -33,7 +33,7 @@ // TODO [0.1.0] Remove deprecated pieces, pick a better API -#include "timer.h" +#include /** Timer mode. */ typedef timer_mode TimerMode; diff --git a/STM32F4/cores/maple/IPAddress.h b/STM32F4/cores/maple/IPAddress.h index 271b240..c6e0697 100644 --- a/STM32F4/cores/maple/IPAddress.h +++ b/STM32F4/cores/maple/IPAddress.h @@ -17,8 +17,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef IPAddress_h -#define IPAddress_h +#ifndef _IPAddress_h_ +#define _IPAddress_h_ #include #include diff --git a/STM32F4/cores/maple/Server.h b/STM32F4/cores/maple/Server.h index 69e3e39..4a95c9f 100644 --- a/STM32F4/cores/maple/Server.h +++ b/STM32F4/cores/maple/Server.h @@ -17,8 +17,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef server_h -#define server_h +#ifndef _SERVER_H_ +#define _SERVER_H_ #include "Print.h" diff --git a/STM32F4/cores/maple/Stream.h b/STM32F4/cores/maple/Stream.h index abdcd17..870fbf0 100644 --- a/STM32F4/cores/maple/Stream.h +++ b/STM32F4/cores/maple/Stream.h @@ -19,8 +19,8 @@ parsing functions based on TextFinder library by Michael Margolis */ -#ifndef Stream_h -#define Stream_h +#ifndef _STREAM_H_ +#define _STREAM_H_ #include #include "Print.h" diff --git a/STM32F4/cores/maple/Udp.h b/STM32F4/cores/maple/Udp.h index dc5644b..1652caf 100644 --- a/STM32F4/cores/maple/Udp.h +++ b/STM32F4/cores/maple/Udp.h @@ -32,8 +32,8 @@ * bjoern@cs.stanford.edu 12/30/2008 */ -#ifndef udp_h -#define udp_h +#ifndef _UDP_H_ +#define _UDP_H_ #include #include diff --git a/STM32F4/cores/maple/WProgram.h b/STM32F4/cores/maple/WProgram.h index 2949a0a..82b759a 100644 --- a/STM32F4/cores/maple/WProgram.h +++ b/STM32F4/cores/maple/WProgram.h @@ -24,7 +24,12 @@ * SOFTWARE. *****************************************************************************/ -#include "wirish.h" +#ifndef _WPROGRAM_H_ +#define _WPROGRAM_H_ + +#include void setup(); void loop(); + +#endif \ No newline at end of file diff --git a/STM32F4/cores/maple/WString.h b/STM32F4/cores/maple/WString.h index 9038578..ec0eae7 100644 --- a/STM32F4/cores/maple/WString.h +++ b/STM32F4/cores/maple/WString.h @@ -19,8 +19,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef String_class_h -#define String_class_h +#ifndef _WSTRING_H_ +#define _WSTRING_H_ + #ifdef __cplusplus #include @@ -225,4 +226,4 @@ public: }; #endif // __cplusplus -#endif // String_class_h +#endif // _WSTRING_H_ diff --git a/STM32F4/cores/maple/bits.h b/STM32F4/cores/maple/bits.h index 3e755b7..3e3eff1 100644 --- a/STM32F4/cores/maple/bits.h +++ b/STM32F4/cores/maple/bits.h @@ -27,4 +27,9 @@ /* Note: Use of this header file is deprecated. Use bit_constants.h instead. */ +#ifndef _BITS_H_ +#define _BITS_H_ + #include "bit_constants.h" + +#endif diff --git a/STM32F4/cores/maple/boards.cpp b/STM32F4/cores/maple/boards.cpp index a856571..0d55e94 100644 --- a/STM32F4/cores/maple/boards.cpp +++ b/STM32F4/cores/maple/boards.cpp @@ -33,17 +33,16 @@ */ #include "boards.h" -#include "flash.h" -#include "rcc.h" -#include "nvic.h" -#include "systick.h" -#include "gpio.h" -#include "adc.h" -#include "timer.h" +#include +#include +#include +#include +#include +#include +#include #include "usb.h" -#ifdef STM32F2 -//#include "usbF4.h" -#endif +#include "usb_serial.h" + static void setupFlash(void); static void setupClocks(void); @@ -59,7 +58,7 @@ void init(void) { systick_init(SYSTICK_RELOAD_VAL); gpio_init_all(); -#ifdef STM32F2 +#ifdef STM32F4 rcc_clk_enable(RCC_SYSCFG); #else afio_init(); @@ -69,7 +68,10 @@ void init(void) { setupADC(); setupTimers(); - //setupUSB(); +#ifdef SERIAL_USB + setupUSB(); + SerialUSB.begin(); +#endif } /* You could farm this out to the files in boards/ if e.g. it takes @@ -84,11 +86,13 @@ bool boardUsesPin(uint8 pin) { } static void setupFlash(void) { +/* #ifndef STM32F2 // for F2 and F4 CPUs this is done in SetupClock...(), e.g. in SetupClock168MHz() flash_enable_prefetch(); flash_set_latency(FLASH_WAIT_STATE_2); #endif +*/ } /* @@ -121,8 +125,8 @@ static void setupNVIC() { static void adcDefaultConfig(const adc_dev* dev); static void setupADC() { -#ifdef STM32F2 - setupADC_F2(); +#ifdef STM32F4 + setupADC_F4(); #else rcc_set_prescaler(RCC_PRESCALER_ADC, RCC_ADCPRE_PCLK_DIV_6); #endif diff --git a/STM32F4/cores/maple/boards.h b/STM32F4/cores/maple/boards.h index 00d07cd..d37bff4 100644 --- a/STM32F4/cores/maple/boards.h +++ b/STM32F4/cores/maple/boards.h @@ -39,11 +39,8 @@ #ifndef _BOARDS_H_ #define _BOARDS_H_ -#include "libmaple.h" -#include "gpio.h" -#include "timer.h" - -#include "wirish_types.h" +#include +#include /* Set of all possible pin names; not all boards have all these (note * that we use the Dx convention since all of the Maple's pins are @@ -55,9 +52,12 @@ enum { D32, D33, D34, D35, D36, D37, D38, D39, D40, D41, D42, D43, D44, D45, D46, D47, D48, D49, D50, D51, D52, D53, D54, D55, D56, D57, D58, D59, D60, D61, D62, D63, D64, D65, D66, D67, D68, D69, D70, D71, D72, D73, D74, D75, D76, +#if 0 // not available on LQFP100 package D77, D78, D79, D80, D81, D82, D83, D84, D85, D86, D87, D88, D89, D90, D91, D92, D93, D94, D95, D96, D97, D98, D99, D100, D101, D102, D103, D104, D105, - D106, D107, D108, D109, D110, D111, }; + D106, D107, D108, D109, D110, D111, +#endif // not available on LQFP100 package +}; /** * @brief Maps each Maple pin to a corresponding stm32_pin_info. @@ -115,31 +115,20 @@ extern void boardInit(void); * @return true if the given pin is in boardUsedPins, and false otherwise. * @see boardUsedPins */ -bool boardUsesPin(uint8 pin); +extern bool boardUsesPin(uint8 pin); /* Include the appropriate private header from boards/: */ /* FIXME HACK put boards/ before these paths once IDE uses make. */ -#ifdef BOARD_maple -#include "maple.h" -#elif defined(BOARD_maple_native) -#include "maple_native.h" -#elif defined(BOARD_maple_mini) -#include "maple_mini.h" -#elif defined(BOARD_maple_RET6) -/* - * **NOT** MAPLE REV6. This the **Maple RET6 EDITION**, which is a - * Maple with an STM32F103RET6 (...RET6) instead of an STM32F103RBT6 - * (...RBT6) on it. Maple Rev6 (as of March 2011) DOES NOT EXIST. - */ -#include "maple_RET6.h" -#elif defined(BOARD_aeroquad32) || defined(BOARD_aeroquad32f1) +#if defined(BOARD_aeroquad32) || defined(BOARD_aeroquad32f1) #include "aeroquad32.h" #elif defined(BOARD_aeroquad32mini) #include "aeroquad32mini.h" #elif defined(BOARD_discovery_f4) #include "discovery_f4.h" +#elif defined(BOARD_generic_f407v) +#include "generic_f407v.h" #elif defined(BOARD_freeflight) #include "freeflight.h" #else @@ -160,4 +149,12 @@ bool boardUsesPin(uint8 pin); #define CLOCK_SPEED_MHZ CYCLES_PER_MICROSECOND #define CLOCK_SPEED_HZ (CLOCK_SPEED_MHZ * 1000000UL) +#ifndef SYSTICK_RELOAD_VAL +#define SYSTICK_RELOAD_VAL (1000 * CYCLES_PER_MICROSECOND - 1) +#endif + +#ifndef BOARD_BUTTON_PRESSED_LEVEL +#define BOARD_BUTTON_PRESSED_LEVEL HIGH +#endif + #endif diff --git a/STM32F4/cores/maple/ext_interrupts.cpp b/STM32F4/cores/maple/ext_interrupts.cpp index f014f13..7111d0c 100644 --- a/STM32F4/cores/maple/ext_interrupts.cpp +++ b/STM32F4/cores/maple/ext_interrupts.cpp @@ -31,8 +31,8 @@ */ #include "boards.h" -#include "gpio.h" -#include "exti.h" +#include +#include #include "ext_interrupts.h" static inline exti_trigger_mode exti_out_mode(ExtIntTriggerMode mode); @@ -51,7 +51,7 @@ void attachInterrupt(uint8 pin, voidFuncPtr handler, ExtIntTriggerMode mode) { exti_trigger_mode outMode = exti_out_mode(mode); - exti_attach_interrupt((afio_exti_num)(PIN_MAP[pin].gpio_bit), + exti_attach_interrupt((afio_exti_num)(pin&0x0F), gpio_exti_port(PIN_MAP[pin].gpio_device), handler, outMode); @@ -66,7 +66,7 @@ void detachInterrupt(uint8 pin) { return; } - exti_detach_interrupt((afio_exti_num)(PIN_MAP[pin].gpio_bit)); + exti_detach_interrupt((afio_exti_num)(pin&0x0F)); } static inline exti_trigger_mode exti_out_mode(ExtIntTriggerMode mode) { diff --git a/STM32F4/cores/maple/ext_interrupts.h b/STM32F4/cores/maple/ext_interrupts.h index b5c6f98..fe215dc 100644 --- a/STM32F4/cores/maple/ext_interrupts.h +++ b/STM32F4/cores/maple/ext_interrupts.h @@ -24,8 +24,8 @@ * SOFTWARE. *****************************************************************************/ -#include "libmaple_types.h" -#include "nvic.h" +#ifndef _EXT_INTERRUPTS_H_ +#define _EXT_INTERRUPTS_H_ /** * @file ext_interrupts.h @@ -33,8 +33,9 @@ * @brief Wiring-like external interrupt prototypes and types. */ -#ifndef _EXT_INTERRUPTS_H_ -#define _EXT_INTERRUPTS_H_ +#include +#include + /** * The kind of transition on an external pin which should trigger an diff --git a/STM32F4/cores/maple/io.h b/STM32F4/cores/maple/io.h index df1ab96..aeaf0fd 100644 --- a/STM32F4/cores/maple/io.h +++ b/STM32F4/cores/maple/io.h @@ -33,8 +33,9 @@ #ifndef _IO_H_ #define _IO_H_ -#include "gpio.h" -#include "adc.h" +#include +#include +#include #include "wirish_time.h" @@ -179,9 +180,11 @@ static inline void toggleLED() { * accomplished portably over all LeafLabs boards by calling * pinMode(BOARD_BUTTON_PIN, INPUT). * + * @param button - one of available on-board buttons (up to 3 for generic F4) + * * @see pinMode() */ -uint8 isButtonPressed(); +uint8 isButtonPressed(uint8_t button); /** * Wait until the button is pressed and released, timing out if no @@ -195,12 +198,14 @@ uint8 isButtonPressed(); * button is pressed. If timeout_millis is left out (or 0), wait * forever. * + * @param button - one of available on-board buttons (up to 3 for generic F4) + * * @return true, if the button was pressed; false, if the timeout was * reached. * * @see pinMode() */ -uint8 waitForButtonPress(uint32 timeout_millis=0); +uint8 waitForButtonPress(uint8_t button, uint32 timeout_millis=0); /** * Shift out a byte of data, one bit at a time. diff --git a/STM32F4/cores/maple/itoa.h b/STM32F4/cores/maple/itoa.h index 59af109..09e8b2f 100644 --- a/STM32F4/cores/maple/itoa.h +++ b/STM32F4/cores/maple/itoa.h @@ -16,8 +16,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef _ITOA_ -#define _ITOA_ +#ifndef _ITOA_H_ +#define _ITOA_H_ #ifdef __cplusplus extern "C"{ diff --git a/STM32F4/cores/maple/libmaple/HardwareSPI.cpp b/STM32F4/cores/maple/libmaple/HardwareSPI.cpp deleted file mode 100644 index a5b4711..0000000 --- a/STM32F4/cores/maple/libmaple/HardwareSPI.cpp +++ /dev/null @@ -1,424 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @author Marti Bolivar - * @brief Wirish SPI implementation. - */ - -#include "HardwareSPI.h" - -#include "timer.h" -#include "util.h" -#include "rcc.h" - -#include "wirish.h" -#include "boards.h" - -struct spi_pins { - uint8 nss; - uint8 sck; - uint8 miso; - uint8 mosi; -}; - -static const spi_pins* dev_to_spi_pins(spi_dev *dev); - -static void enable_device(spi_dev *dev, - bool as_master, - SPIFrequency frequency, - spi_cfg_flag endianness, - spi_mode mode); - -static const spi_pins board_spi_pins[] __FLASH__ = { - {BOARD_SPI1_NSS_PIN, - BOARD_SPI1_SCK_PIN, - BOARD_SPI1_MISO_PIN, - BOARD_SPI1_MOSI_PIN}, -#ifdef BOARD_SPI2_NSS_PIN - {BOARD_SPI2_NSS_PIN, - BOARD_SPI2_SCK_PIN, - BOARD_SPI2_MISO_PIN, - BOARD_SPI2_MOSI_PIN}, -#endif -#ifdef STM32_HIGH_DENSITY - {BOARD_SPI3B_NSS_PIN, - BOARD_SPI3B_SCK_PIN, - BOARD_SPI3B_MISO_PIN, - BOARD_SPI3B_MOSI_PIN}, -#endif -#ifdef STM32F4 - {BOARD_SPI3B_NSS_PIN, - BOARD_SPI3B_SCK_PIN, - BOARD_SPI3B_MISO_PIN, - BOARD_SPI3B_MOSI_PIN}, -#endif -}; - - -/* - * Constructor - */ - -HardwareSPI::HardwareSPI(uint32 spi_num) { - switch (spi_num) { - case 1: - this->spi_d = SPI1; - break; - case 2: - this->spi_d = SPI2; - break; -#ifdef STM32_HIGH_DENSITY - case 3: - this->spi_d = SPI3; - break; -#endif -#ifdef STM32F4 -// case 4: -// this->spi_d = SPI4; -// break; -#endif - default: - ASSERT(0); - } -} - -/* - * Set up/tear down - */ - -void HardwareSPI::begin(SPIFrequency frequency, uint32 bitOrder, uint32 mode) { - if (mode >= 4) { - ASSERT(0); - return; - } - spi_cfg_flag end = bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB; - spi_mode m = (spi_mode)mode; - enable_device(this->spi_d, true, frequency, end, m); -} - -void HardwareSPI::begin(void) { - this->begin(SPI_1_125MHZ, MSBFIRST, 0); -} - -void HardwareSPI::beginSlave(uint32 bitOrder, uint32 mode) { - if (mode >= 4) { - ASSERT(0); - return; - } - spi_cfg_flag end = bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB; - spi_mode m = (spi_mode)mode; - enable_device(this->spi_d, false, (SPIFrequency)0, end, m); -} - -void HardwareSPI::beginSlave(void) { - this->beginSlave(MSBFIRST, 0); -} - - -/* -void HardwareSPI::beginTransaction(uint8_t pin, SPISettings settings) -{ -// this->begin(settings.clock, settings.bitOrder, settings.dataMode); - this->begin(SPI_1_125MHZ, settings.bitOrder, settings.dataMode); -} -*/ - -void HardwareSPI::end(void) { - if (!spi_is_enabled(this->spi_d)) { - return; - } - - // Follows RM0008's sequence for disabling a SPI in master/slave - // full duplex mode. - while (spi_is_rx_nonempty(this->spi_d)) { - // FIXME [0.1.0] remove this once you have an interrupt based driver - volatile uint16 rx __attribute__((unused)) = spi_rx_reg(this->spi_d); - } - while (!spi_is_tx_empty(this->spi_d)) - ; - while (spi_is_busy(this->spi_d)) - ; - spi_peripheral_disable(this->spi_d); -} - -/* - * I/O - */ - -uint8 HardwareSPI::read(void) { - uint8 buf[1]; - this->read(buf, 1); - return buf[0]; -} - -void HardwareSPI::read(uint8 *buf, uint32 len) { - uint32 rxed = 0; - while (rxed < len) { - while (!spi_is_rx_nonempty(this->spi_d)) - ; - buf[rxed++] = (uint8)spi_rx_reg(this->spi_d); - } -} - -#if 0 -void HardwareSPI::readMaster(uint8 *buf, uint32 len) { - uint32 rxed = 0; - while (rxed < len) { - spi_tx_reg(this->spi_d, 0xff); - while (!spi_is_rx_nonempty(this->spi_d)) - ; - buf[rxed++] = (uint8)spi_rx_reg(this->spi_d); - buf[rxed++] = this->spi_d->regs->DR; - } -} -#endif -void HardwareSPI::readMaster(uint8 *buf, uint32 len) { - spi_reg_map *r = this->spi_d->regs; - uint32 rxed = 0; - while (rxed < len) { - r->DR = 0xff; - while (!(r->SR & SPI_SR_RXNE)) - ; - buf[rxed++] = r->DR; - } -} - - -void HardwareSPI::waitReady() { - while (!spi_is_rx_nonempty(this->spi_d)) - ; -} - -void HardwareSPI::write(uint8 byte) { - this->write(&byte, 1); -} - -void HardwareSPI::write(const uint8 *data, uint32 length) { - uint32 txed = 0; - while (txed < length) { - txed += spi_tx(this->spi_d, data + txed, length - txed); - } -} - -uint8 HardwareSPI::transfer(uint8 byte) { - this->write(byte); - return this->read(); -} - -/* - * Pin accessors - */ - -uint8 HardwareSPI::misoPin(void) { - return dev_to_spi_pins(this->spi_d)->miso; -} - -uint8 HardwareSPI::mosiPin(void) { - return dev_to_spi_pins(this->spi_d)->mosi; -} - -uint8 HardwareSPI::sckPin(void) { - return dev_to_spi_pins(this->spi_d)->sck; -} - -uint8 HardwareSPI::nssPin(void) { - return dev_to_spi_pins(this->spi_d)->nss; -} - -/* - * Deprecated functions - */ - -uint8 HardwareSPI::send(uint8 data) { - uint8 buf[] = {data}; - return this->send(buf, 1); -} - -#if 1 -uint8 HardwareSPI::send(const uint8 *buf, uint32 len) { - uint32 txed = 0; - uint8 ret = 0; - while (txed < len) { - this->write(buf[txed++]); - ret = this->read(); - } - return ret; -} -#else -// this does not work for an unknown reason -uint8 HardwareSPI::send(const uint8 *buf, uint32 len) { - volatile uint32 *dr = &(this->spi_d->regs->DR); - volatile uint32 *sr = &(this->spi_d->regs->SR); - uint32 txed = 0; - uint32 rx=0; - while (txed < len) { - //while (!(*sr & SPI_SR_TXE)) - // ; - //*dr = buf[txed++]; - this->write(buf[txed++]); - - while (!(*sr & SPI_SR_RXNE)) - ; - rx = *dr; - //rx = this->read(); - } - - return rx; -} -#endif - -uint8 HardwareSPI::recv(void) { - return this->read(); -} - -/* - * Auxiliary functions - */ - -static void configure_gpios(spi_dev *dev, bool as_master); -static spi_baud_rate determine_baud_rate(spi_dev *dev, SPIFrequency freq); - -static const spi_pins* dev_to_spi_pins(spi_dev *dev) { - switch (dev->clk_id) { - case RCC_SPI1: return board_spi_pins; - case RCC_SPI2: return board_spi_pins + 1; -#ifdef STM32_HIGH_DENSITY - case RCC_SPI3: return board_spi_pins + 2; -#endif -#ifdef STM32F4 - case RCC_SPI4: return board_spi_pins + 3; -#endif - default: return NULL; - } -} - -/* Enables the device in master or slave full duplex mode. If you - * change this code, you must ensure that appropriate changes are made - * to HardwareSPI::end(). */ -static void enable_device(spi_dev *dev, - bool as_master, - SPIFrequency freq, - spi_cfg_flag endianness, - spi_mode mode) { - spi_baud_rate baud = determine_baud_rate(dev, freq); - uint32 cfg_flags = (endianness | SPI_DFF_8_BIT | SPI_SW_SLAVE | - (as_master ? SPI_SOFT_SS : 0)); - - spi_init(dev); - configure_gpios(dev, as_master); - if (as_master) { - spi_master_enable(dev, baud, mode, cfg_flags); - } else { - spi_slave_enable(dev, mode, cfg_flags); - } -} - -static void disable_pwm(const stm32_pin_info *i) { - if (i->timer_device) { - timer_set_mode(i->timer_device, i->timer_channel, TIMER_DISABLED); - } -} - -static void configure_gpios(spi_dev *dev, bool as_master) { - const spi_pins *pins = dev_to_spi_pins(dev); - - if (!pins) { - return; - } - - const stm32_pin_info *nssi = (pins->nss >= 0) ? &PIN_MAP[pins->nss] : NULL; - const stm32_pin_info *scki = &PIN_MAP[pins->sck]; - const stm32_pin_info *misoi = &PIN_MAP[pins->miso]; - const stm32_pin_info *mosii = &PIN_MAP[pins->mosi]; - - if(nssi) { - disable_pwm(nssi); - } - disable_pwm(scki); - disable_pwm(misoi); - disable_pwm(mosii); - -#ifdef STM32F4 - if(dev->clk_id <= RCC_SPI2) { - if(nssi) { - if(!as_master) { - gpio_set_af_mode(nssi->gpio_device, scki->gpio_bit, 5); - } - } - gpio_set_af_mode(scki->gpio_device, scki->gpio_bit, 5); - gpio_set_af_mode(misoi->gpio_device, misoi->gpio_bit, 5); - gpio_set_af_mode(mosii->gpio_device, mosii->gpio_bit, 5); - } else { - if(nssi) { - if(!as_master) { - gpio_set_af_mode(nssi->gpio_device, scki->gpio_bit, 6); - } - } - gpio_set_af_mode(scki->gpio_device, scki->gpio_bit, 6); - gpio_set_af_mode(misoi->gpio_device, misoi->gpio_bit, 6); - gpio_set_af_mode(mosii->gpio_device, mosii->gpio_bit, 6); - } -#endif - - if(nssi) { - spi_config_gpios(dev, as_master, nssi->gpio_device, nssi->gpio_bit, - scki->gpio_device, scki->gpio_bit, - misoi->gpio_device, misoi->gpio_bit, - mosii->gpio_device, mosii->gpio_bit); - } else { - spi_config_gpios(dev, as_master, NULL, -1, - scki->gpio_device, scki->gpio_bit, - misoi->gpio_device, misoi->gpio_bit, - mosii->gpio_device, mosii->gpio_bit); - } -} - -static const spi_baud_rate baud_rates[MAX_SPI_FREQS] __FLASH__ = { - SPI_BAUD_PCLK_DIV_2, - SPI_BAUD_PCLK_DIV_4, - SPI_BAUD_PCLK_DIV_8, - SPI_BAUD_PCLK_DIV_16, - SPI_BAUD_PCLK_DIV_32, - SPI_BAUD_PCLK_DIV_64, - SPI_BAUD_PCLK_DIV_128, - SPI_BAUD_PCLK_DIV_256, -}; - -/* - * Note: This assumes you're on a LeafLabs-style board - * (CYCLES_PER_MICROSECOND == 72, APB2 at 72MHz, APB1 at 36MHz). - */ -static spi_baud_rate determine_baud_rate(spi_dev *dev, SPIFrequency freq) { - if (rcc_dev_clk(dev->clk_id) == RCC_APB2 && freq == SPI_140_625KHZ) { - /* APB2 peripherals are too fast for 140.625 KHz */ - ASSERT(0); - return (spi_baud_rate)~0; - } - return (rcc_dev_clk(dev->clk_id) == RCC_APB2 ? - baud_rates[freq + 1] : - baud_rates[freq]); -} diff --git a/STM32F4/cores/maple/libmaple/HardwareSPI.h b/STM32F4/cores/maple/libmaple/HardwareSPI.h deleted file mode 100644 index 327f29d..0000000 --- a/STM32F4/cores/maple/libmaple/HardwareSPI.h +++ /dev/null @@ -1,279 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file HardwareSPI.h - * @brief High-level SPI interface - * - * This is a "bare essentials" polling driver for now. - */ - -/* TODO [0.1.0] Remove deprecated methods. */ - -#include "libmaple_types.h" -#include "spi.h" - -#include "boards.h" -#include "wirish.h" - -#ifndef _HARDWARESPI_H_ -#define _HARDWARESPI_H_ - -/** - * @brief Defines the possible SPI communication speeds. - */ -typedef enum SPIFrequency { - SPI_18MHZ = 0, /**< 18 MHz */ - SPI_9MHZ = 1, /**< 9 MHz */ - SPI_4_5MHZ = 2, /**< 4.5 MHz */ - SPI_2_25MHZ = 3, /**< 2.25 MHz */ - SPI_1_125MHZ = 4, /**< 1.125 MHz */ - SPI_562_500KHZ = 5, /**< 562.500 KHz */ - SPI_281_250KHZ = 6, /**< 281.250 KHz */ - SPI_140_625KHZ = 7, /**< 140.625 KHz */ -} SPIFrequency; - -#define MAX_SPI_FREQS 8 - -#if CYCLES_PER_MICROSECOND != 72 -/* TODO [0.2.0?] something smarter than this */ -//#warning "Unexpected clock speed; SPI frequency calculation will be incorrect" -#endif - - -//#define BOARD_SPI_DEFAULT_SS PC13 -#define BOARD_SPI_DEFAULT_SS PB0 -#define SPI_MODE0 SPI_MODE_0 -#define SPI_MODE1 SPI_MODE_1 -#define SPI_MODE2 SPI_MODE_2 -#define SPI_MODE3 SPI_MODE_3 - -/* -class SPISettings { -public: - SPISettings(uint32 clock, BitOrder bitOrder, uint8 dataMode) { - if (__builtin_constant_p(clock)) { - init_AlwaysInline(clock, bitOrder, dataMode); - } else { - init_MightInline(clock, bitOrder, dataMode); - } - } - SPISettings() { init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0); } -private: - void init_MightInline(uint32 clock, BitOrder bitOrder, uint8 dataMode) { - init_AlwaysInline(clock, bitOrder, dataMode); - } - void init_AlwaysInline(uint32 clock, BitOrder bitOrder, uint8 dataMode) __attribute__((__always_inline__)) { - this->clock = clock; - this->bitOrder = bitOrder; - this->dataMode = dataMode; - } - uint32 clock; - BitOrder bitOrder; - uint8 dataMode; - friend class HardwareSPI; -}; -*/ - - -/** - * @brief Wirish SPI interface. - * - * This implementation uses software slave management, so the caller - * is responsible for controlling the slave select line. - */ -class HardwareSPI { -public: - /** - * @param spiPortNumber Number of the SPI port to manage. - */ - HardwareSPI(uint32 spiPortNumber); - - /* - * Set up/tear down - */ - - /** - * @brief Turn on a SPI port and set its GPIO pin modes for use as master. - * - * SPI port is enabled in full duplex mode, with software slave management. - * - * @param frequency Communication frequency - * @param bitOrder Either LSBFIRST (little-endian) or MSBFIRST (big-endian) - * @param mode SPI mode to use, one of SPI_MODE_0, SPI_MODE_1, - * SPI_MODE_2, and SPI_MODE_3. - */ - void begin(SPIFrequency frequency, uint32 bitOrder, uint32 mode); - - /** - * @brief Equivalent to begin(SPI_1_125MHZ, MSBFIRST, 0). - */ - void begin(void); - - /** - * @brief Turn on a SPI port and set its GPIO pin modes for use as a slave. - * - * SPI port is enabled in full duplex mode, with software slave management. - * - * @param bitOrder Either LSBFIRST (little-endian) or MSBFIRST(big-endian) - * @param mode SPI mode to use - */ - void beginSlave(uint32 bitOrder, uint32 mode); - - /** - * @brief Equivalent to beginSlave(MSBFIRST, 0). - */ - void beginSlave(void); - - /** - * @brief Disables the SPI port, but leaves its GPIO pin modes unchanged. - */ - void end(void); - - /* - * I/O - */ - - /** - * @brief Return the next unread byte. - * - * If there is no unread byte waiting, this function will block - * until one is received. - */ - uint8 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 - * function will block until the desired number of - * bytes have been read. - */ - void read(uint8 *buffer, uint32 length); - - /** - * @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 - * function will block until the desired number of - * bytes have been read. - */ - void readMaster(uint8 *buffer, uint32 length); - - - void waitReady(); - /** - * @brief Transmit a byte. - * @param data Byte to transmit. - */ - void write(uint8 data); - - /** - * @brief Transmit multiple bytes. - * @param buffer Bytes to transmit. - * @param length Number of bytes in buffer to transmit. - */ - void write(const uint8 *buffer, uint32 length); - - /** - * @brief Transmit a byte, then return the next unread byte. - * - * This function transmits before receiving. - * - * @param data Byte to transmit. - * @return Next unread byte. - */ - uint8 transfer(uint8 data); - - /* - * Pin accessors - */ - - /** - * @brief Return the number of the MISO (master in, slave out) pin - */ - uint8 misoPin(void); - - /** - * @brief Return the number of the MOSI (master out, slave in) pin - */ - uint8 mosiPin(void); - - /** - * @brief Return the number of the SCK (serial clock) pin - */ - uint8 sckPin(void); - - /** - * @brief Return the number of the NSS (slave select) pin - */ - uint8 nssPin(void); - - /* -- The following methods are deprecated --------------------------- */ - - /** - * @brief Deprecated. - * - * Use HardwareSPI::transfer() instead. - * - * @see HardwareSPI::transfer() - */ - uint8 send(uint8 data); - - /** - * @brief Deprecated. - * - * Use HardwareSPI::write() in combination with - * HardwareSPI::read() (or HardwareSPI::transfer()) instead. - * - * @see HardwareSPI::write() - * @see HardwareSPI::read() - * @see HardwareSPI::transfer() - */ - uint8 send(const uint8 *data, uint32 length); - - /** - * @brief Deprecated. - * - * Use HardwareSPI::read() instead. - * - * @see HardwareSPI::read() - */ - uint8 recv(void); - -// void beginTransaction(SPISettings settings) { beginTransaction(BOARD_SPI_DEFAULT_SS, settings); } -// void beginTransaction(uint8 pin, SPISettings settings); - void endTransaction(void) { } - -private: - spi_dev *spi_d; -}; - - -extern HardwareSPI SPI; - -#endif - diff --git a/STM32F4/cores/maple/libmaple/HardwareSerial.cpp b/STM32F4/cores/maple/libmaple/HardwareSerial.cpp index 59ce71d..f9387d1 100644 --- a/STM32F4/cores/maple/libmaple/HardwareSerial.cpp +++ b/STM32F4/cores/maple/libmaple/HardwareSerial.cpp @@ -56,19 +56,19 @@ #define RX5 BOARD_UART5_RX_PIN #endif -HardwareSerial Serial(USART1, TX1, RX1); +HardwareSerial Serial1(USART1, TX1, RX1); #ifdef TX2 -HardwareSerial Serial1(USART2, TX2, RX2); +HardwareSerial Serial2(USART2, TX2, RX2); #endif #ifdef TX3 -HardwareSerial Serial2(USART3, TX3, RX3); +HardwareSerial Serial3(USART3, TX3, RX3); #endif #if defined(STM32_HIGH_DENSITY) && !defined(BOARD_maple_RET6) -HardwareSerial Serial3(UART4, TX4, RX4); -HardwareSerial Serial4(UART5, TX5, RX5); +HardwareSerial Serial4(UART4, TX4, RX4); +HardwareSerial Serial5(UART5, TX5, RX5); #endif HardwareSerial::HardwareSerial(usart_dev *usart_device, @@ -90,25 +90,23 @@ void HardwareSerial::begin(uint32 baud) { return; } - const stm32_pin_info *txi = &PIN_MAP[tx_pin]; - const stm32_pin_info *rxi = &PIN_MAP[rx_pin]; -#ifdef STM32F2 +#ifdef STM32F4 // int af = 7<<8; if (usart_device == UART4 || usart_device == UART5) { - gpio_set_af_mode(txi->gpio_device, txi->gpio_bit, 8); - gpio_set_af_mode(rxi->gpio_device, rxi->gpio_bit, 8); + gpio_set_af_mode(tx_pin, 8); + gpio_set_af_mode(rx_pin, 8); } else { - gpio_set_af_mode(txi->gpio_device, txi->gpio_bit, 7); - gpio_set_af_mode(rxi->gpio_device, rxi->gpio_bit, 7); + gpio_set_af_mode(tx_pin, 7); + gpio_set_af_mode(rx_pin, 7); } - gpio_set_mode(txi->gpio_device, txi->gpio_bit, (gpio_pin_mode)(GPIO_AF_OUTPUT_PP | GPIO_PUPD_INPUT_PU | 0x700)); - gpio_set_mode(rxi->gpio_device, rxi->gpio_bit, (gpio_pin_mode)(GPIO_MODE_AF | GPIO_PUPD_INPUT_PU | 0x700)); + gpio_set_mode(tx_pin, (gpio_pin_mode)(GPIO_AF_OUTPUT_PP | GPIO_PUPD_INPUT_PU | 0x700)); + gpio_set_mode(rx_pin, (gpio_pin_mode)(GPIO_MODE_AF | GPIO_PUPD_INPUT_PU | 0x700)); //gpio_set_mode(txi->gpio_device, txi->gpio_bit, (gpio_pin_mode)(GPIO_PUPD_INPUT_PU)); //gpio_set_mode(rxi->gpio_device, rxi->gpio_bit, (gpio_pin_mode)(GPIO_PUPD_INPUT_PU)); #else - gpio_set_mode(txi->gpio_device, txi->gpio_bit, GPIO_AF_OUTPUT_PP); - gpio_set_mode(rxi->gpio_device, rxi->gpio_bit, GPIO_INPUT_FLOATING); + gpio_set_mode(tx_pin, GPIO_AF_OUTPUT_PP); + gpio_set_mode(rx_pin, GPIO_INPUT_FLOATING); #endif #if 0 if (txi->timer_device != NULL) { diff --git a/STM32F4/cores/maple/libmaple/HardwareSerial.h b/STM32F4/cores/maple/libmaple/HardwareSerial.h index c09fe54..d7e8a3d 100644 --- a/STM32F4/cores/maple/libmaple/HardwareSerial.h +++ b/STM32F4/cores/maple/libmaple/HardwareSerial.h @@ -75,12 +75,12 @@ private: uint8 rx_pin; }; -extern HardwareSerial Serial; extern HardwareSerial Serial1; extern HardwareSerial Serial2; #if defined(STM32_HIGH_DENSITY) && !defined(BOARD_maple_RET6) extern HardwareSerial Serial3; extern HardwareSerial Serial4; +extern HardwareSerial Serial5; #endif extern HardwareSerial &SerialDebug; #endif diff --git a/STM32F4/cores/maple/libmaple/adc.c b/STM32F4/cores/maple/libmaple/adc.c index aeeb43c..0f4c02c 100644 --- a/STM32F4/cores/maple/libmaple/adc.c +++ b/STM32F4/cores/maple/libmaple/adc.c @@ -41,27 +41,24 @@ #include "rcc.h" #include "adc.h" -static adc_dev adc1 = { +/** ADC1 device. */ +const adc_dev ADC1 = { .regs = ADC1_BASE, .clk_id = RCC_ADC1 }; -/** ADC1 device. */ -const adc_dev *ADC1 = &adc1; -static adc_dev adc2 = { +/** ADC2 device. */ +const adc_dev ADC2 = { .regs = ADC2_BASE, .clk_id = RCC_ADC2 }; -/** ADC2 device. */ -const adc_dev *ADC2 = &adc2; #ifdef STM32_HIGH_DENSITY -adc_dev adc3 = { +/** ADC3 device. */ +const adc_dev ADC3 = { .regs = ADC3_BASE, .clk_id = RCC_ADC3 }; -/** ADC3 device. */ -const adc_dev *ADC3 = &adc3; #endif /** @@ -74,7 +71,7 @@ const adc_dev *ADC3 = &adc3; */ void adc_init(const adc_dev *dev) { rcc_clk_enable(dev->clk_id); -#ifdef STM32F2 +#ifdef STM32F4 if(dev->clk_id == RCC_ADC1) { rcc_reset_dev(dev->clk_id); } @@ -101,10 +98,10 @@ void adc_set_extsel(const adc_dev *dev, adc_extsel_event event) { * @param fn Function to call on each ADC device. */ void adc_foreach(void (*fn)(const adc_dev*)) { - fn(ADC1); - fn(ADC2); + fn(&ADC1); + fn(&ADC2); #ifdef STM32_HIGH_DENSITY - fn(ADC3); + fn(&ADC3); #endif } @@ -136,7 +133,9 @@ void adc_set_sample_rate(const adc_dev *dev, adc_smp_rate smp_rate) { * @brief Calibrate an ADC peripheral * @param dev adc device */ -void adc_calibrate(const adc_dev *dev) { +void adc_calibrate(const adc_dev *dev) +{ +/* #ifndef STM32F2 __io uint32 *rstcal_bit = bb_perip(&(dev->regs->CR2), 3); __io uint32 *cal_bit = bb_perip(&(dev->regs->CR2), 2); @@ -149,6 +148,7 @@ void adc_calibrate(const adc_dev *dev) { while (*cal_bit) ; #endif +*/ } /** @@ -171,8 +171,8 @@ uint16 adc_read(const adc_dev *dev, uint8 channel) { return (uint16)(regs->DR & ADC_DR_DATA); } -void setupADC_F2() { -#ifdef STM32F2 +void setupADC_F4(void) +{ uint32 tmpreg1 = 0; tmpreg1 = ADC_COMMON->CCR; @@ -196,5 +196,4 @@ void setupADC_F2() { /* Write to ADC CCR */ ADC_COMMON->CCR = tmpreg1; -#endif } diff --git a/STM32F4/cores/maple/libmaple/adc.h b/STM32F4/cores/maple/libmaple/adc.h index 3a40d4c..6fa61f5 100644 --- a/STM32F4/cores/maple/libmaple/adc.h +++ b/STM32F4/cores/maple/libmaple/adc.h @@ -42,17 +42,15 @@ extern "C"{ #endif -#ifdef STM32F2 - typedef struct - { - __io uint32 CSR; /*!< ADC Common status register, Address offset: ADC1 base address + 0x300 */ - __io uint32 CCR; /*!< ADC common control register, Address offset: ADC1 base address + 0x304 */ - __io uint32 CDR; /*!< ADC common regular data register for dual - AND triple modes, Address offset: ADC1 base address + 0x308 */ - } ADC_Common_TypeDef; +typedef struct +{ + __io uint32 CSR; /*!< ADC Common status register, Address offset: ADC1 base address + 0x300 */ + __io uint32 CCR; /*!< ADC common control register, Address offset: ADC1 base address + 0x304 */ + __io uint32 CDR; /*!< ADC common regular data register for dual + AND triple modes, Address offset: ADC1 base address + 0x308 */ +} ADC_Common_TypeDef; #define ADC_COMMON ((ADC_Common_TypeDef *) 0x40012300) -#endif /** ADC register map type. */ typedef struct adc_reg_map { @@ -84,33 +82,22 @@ typedef struct adc_dev { rcc_clk_id clk_id; /**< RCC clock information */ } adc_dev; -extern const adc_dev *ADC1; -extern const adc_dev *ADC2; +extern const adc_dev ADC1; +extern const adc_dev ADC2; #ifdef STM32_HIGH_DENSITY -extern const adc_dev *ADC3; +extern const adc_dev ADC3; #endif /* * Register map base pointers */ -#ifdef STM32F2 - /** ADC1 register map base pointer. */ - #define ADC1_BASE ((struct adc_reg_map*)0x40012000) - /** ADC2 register map base pointer. */ - #define ADC2_BASE ((struct adc_reg_map*)0x40012100) - /** ADC3 register map base pointer. */ - #define ADC3_BASE ((struct adc_reg_map*)0x40012200) -#else - /** ADC1 register map base pointer. */ - #define ADC1_BASE ((struct adc_reg_map*)0x40012400) - /** ADC2 register map base pointer. */ - #define ADC2_BASE ((struct adc_reg_map*)0x40012800) - #ifdef STM32_HIGH_DENSITY - /** ADC3 register map base pointer. */ - #define ADC3_BASE ((struct adc_reg_map*)0x40013C00) - #endif -#endif +/** ADC1 register map base pointer. */ +#define ADC1_BASE ((struct adc_reg_map*)0x40012000) +/** ADC2 register map base pointer. */ +#define ADC2_BASE ((struct adc_reg_map*)0x40012100) +/** ADC3 register map base pointer. */ +#define ADC3_BASE ((struct adc_reg_map*)0x40012200) /* * Register bit definitions @@ -167,17 +154,10 @@ extern const adc_dev *ADC3; #define ADC_CR2_JEXTTRIG_BIT 15 #define ADC_CR2_EXTTRIG_BIT 20 #define ADC_CR2_TSEREFE_BIT 23 -#ifdef STM32F2 #define ADC_CR2_JSWSTART_BIT 22 #define ADC_CR2_SWSTART_BIT 30 #define ADC_CR2_EXTSEL (0x0F000000) #define ADC_CR2_JEXTSEL (0x000F0000) -#else -#define ADC_CR2_JSWSTART_BIT 21 -#define ADC_CR2_SWSTART_BIT 22 -#define ADC_CR2_EXTSEL (0x000E0000) -#define ADC_CR2_JEXTSEL (0x00007000) -#endif @@ -388,7 +368,7 @@ static inline void adc_disable_all(void) { adc_foreach(adc_disable); } -void setupADC_F2(); +extern void setupADC_F4(void); #ifdef __cplusplus } // extern "C" diff --git a/STM32F4/cores/maple/libmaple/dac.c b/STM32F4/cores/maple/libmaple/dac.c index 264e4e2..3853f90 100644 --- a/STM32F4/cores/maple/libmaple/dac.c +++ b/STM32F4/cores/maple/libmaple/dac.c @@ -126,11 +126,11 @@ void dac_enable_channel(const dac_dev *dev, uint8 channel) { */ switch (channel) { case 1: - gpio_set_mode(GPIOA, 4, GPIO_INPUT_ANALOG); + gpio_set_mode((uint8_t)PA4, GPIO_INPUT_ANALOG); dev->regs->CR |= DAC_CR_EN1; break; case 2: - gpio_set_mode(GPIOA, 5, GPIO_INPUT_ANALOG); + gpio_set_mode((uint8_t)PA5, GPIO_INPUT_ANALOG); dev->regs->CR |= DAC_CR_EN2; break; } diff --git a/STM32F4/cores/maple/libmaple/dma.h b/STM32F4/cores/maple/libmaple/dma.h index a965c03..420adf8 100644 --- a/STM32F4/cores/maple/libmaple/dma.h +++ b/STM32F4/cores/maple/libmaple/dma.h @@ -30,9 +30,4 @@ * @brief Direct Memory Access peripheral support */ -#ifdef STM32F2 -#include "dmaF2.h" -#include -#else -#include "dmaF1.h" -#endif +#include "dmaF4.h" diff --git a/STM32F4/cores/maple/libmaple/dmaF1.c b/STM32F4/cores/maple/libmaple/dmaF1.c deleted file mode 100644 index f8ddb2d..0000000 --- a/STM32F4/cores/maple/libmaple/dmaF1.c +++ /dev/null @@ -1,383 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Michael Hope. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -#ifdef STM32F1 - -/** - * @file dma.c - * @author Marti Bolivar ; - * Original implementation by Michael Hope - * @brief Direct Memory Access peripheral support - */ - -#include "dma.h" -#include "bitband.h" -#include "util.h" - -/* - * Devices - */ - -static dma_dev dma1 = { - .regs = DMA1_BASE, - .clk_id = RCC_DMA1, - .handlers = {{ .handler = NULL, .irq_line = NVIC_DMA_CH1 }, - { .handler = NULL, .irq_line = NVIC_DMA_CH2 }, - { .handler = NULL, .irq_line = NVIC_DMA_CH3 }, - { .handler = NULL, .irq_line = NVIC_DMA_CH4 }, - { .handler = NULL, .irq_line = NVIC_DMA_CH5 }, - { .handler = NULL, .irq_line = NVIC_DMA_CH6 }, - { .handler = NULL, .irq_line = NVIC_DMA_CH7 }} -}; -/** DMA1 device */ -dma_dev *DMA1 = &dma1; - -#ifdef STM32_HIGH_DENSITY -static dma_dev dma2 = { - .regs = DMA2_BASE, - .clk_id = RCC_DMA2, - .handlers = {{ .handler = NULL, .irq_line = NVIC_DMA2_CH1 }, - { .handler = NULL, .irq_line = NVIC_DMA2_CH2 }, - { .handler = NULL, .irq_line = NVIC_DMA2_CH3 }, - { .handler = NULL, .irq_line = NVIC_DMA2_CH_4_5 }, - { .handler = NULL, .irq_line = NVIC_DMA2_CH_4_5 }} /* !@#$ */ -}; -/** DMA2 device */ -dma_dev *DMA2 = &dma2; -#endif - -/* - * Convenience routines - */ - -/** - * @brief Initialize a DMA device. - * @param dev Device to initialize. - */ -void dma_init(dma_dev *dev) { - rcc_clk_enable(dev->clk_id); -} - -/** - * @brief Set up a DMA transfer. - * - * The channel will be disabled before being reconfigured. The - * transfer will have low priority by default. You may choose another - * priority before the transfer begins using dma_set_priority(), as - * well as performing any other configuration you desire. When the - * channel is configured to your liking, enable it using dma_enable(). - * - * @param dev DMA device. - * @param channel DMA channel. - * @param peripheral_address Base address of peripheral data register - * involved in the transfer. - * @param peripheral_size Peripheral data transfer size. - * @param memory_address Base memory address involved in the transfer. - * @param memory_size Memory data transfer size. - * @param mode Logical OR of dma_mode_flags - * @sideeffect Disables the given DMA channel. - * @see dma_xfer_size - * @see dma_mode_flags - * @see dma_set_num_transfers() - * @see dma_set_priority() - * @see dma_attach_interrupt() - * @see dma_enable() - */ -void dma_setup_transfer(dma_dev *dev, - dma_channel channel, - __io void *peripheral_address, - dma_xfer_size peripheral_size, - __io void *memory_address, - dma_xfer_size memory_size, - uint32 mode) { - dma_channel_reg_map *channel_regs = dma_channel_regs(dev, channel); - - dma_disable(dev, channel); /* can't write to CMAR/CPAR otherwise */ - channel_regs->CCR = (memory_size << 10) | (peripheral_size << 8) | mode; - channel_regs->CMAR = (uint32)memory_address; - channel_regs->CPAR = (uint32)peripheral_address; -} - -/** - * @brief Set the number of data to be transferred on a DMA channel. - * - * You may not call this function while the channel is enabled. - * - * @param dev DMA device - * @param channel Channel through which the transfer occurs. - * @param num_transfers - */ -void dma_set_num_transfers(dma_dev *dev, - dma_channel channel, - uint16 num_transfers) { - dma_channel_reg_map *channel_regs; - - ASSERT_FAULT(!dma_is_channel_enabled(dev, channel)); - - channel_regs = dma_channel_regs(dev, channel); - channel_regs->CNDTR = num_transfers; -} - -/** - * @brief Set the priority of a DMA transfer. - * - * You may not call this function while the channel is enabled. - * - * @param dev DMA device - * @param channel DMA channel - * @param priority priority to set. - */ -void dma_set_priority(dma_dev *dev, - dma_channel channel, - dma_priority priority) { - dma_channel_reg_map *channel_regs; - uint32 ccr; - - ASSERT_FAULT(!dma_is_channel_enabled(dev, channel)); - - channel_regs = dma_channel_regs(dev, channel); - ccr = channel_regs->CCR; - ccr &= ~DMA_CCR_PL; - ccr |= priority; - channel_regs->CCR = ccr; -} - -/** - * @brief Attach an interrupt to a DMA transfer. - * - * Interrupts are enabled using appropriate mode flags in - * dma_setup_transfer(). - * - * @param dev DMA device - * @param channel Channel to attach handler to - * @param handler Interrupt handler to call when channel interrupt fires. - * @see dma_setup_transfer() - * @see dma_get_irq_cause() - * @see dma_detach_interrupt() - */ -void dma_attach_interrupt(dma_dev *dev, - dma_channel channel, - void (*handler)(void)) { - dev->handlers[channel - 1].handler = handler; - nvic_irq_enable(dev->handlers[channel - 1].irq_line); -} - -/** - * @brief Detach a DMA transfer interrupt handler. - * - * After calling this function, the given channel's interrupts will be - * disabled. - * - * @param dev DMA device - * @param channel Channel whose handler to detach - * @sideeffect Clears interrupt enable bits in the channel's CCR register. - * @see dma_attach_interrupt() - */ -void dma_detach_interrupt(dma_dev *dev, dma_channel channel) { - /* Don't use nvic_irq_disable()! Think about DMA2 channels 4 and 5. */ - dma_channel_regs(dev, channel)->CCR &= ~0xF; - dev->handlers[channel - 1].handler = NULL; -} - -/** - * @brief Discover the reason why a DMA interrupt was called. - * - * You may only call this function within an attached interrupt - * handler for the given channel. - * - * This function resets the internal DMA register state which encodes - * the cause of the interrupt; consequently, it can only be called - * once per interrupt handler invocation. - * - * @param dev DMA device - * @param channel Channel whose interrupt is being handled. - * @return Reason why the interrupt fired. - * @sideeffect Clears channel status flags in dev->regs->ISR. - * @see dma_attach_interrupt() - * @see dma_irq_cause - */ -dma_irq_cause dma_get_irq_cause(dma_dev *dev, dma_channel channel) { - uint8 status_bits = dma_get_isr_bits(dev, channel); - - /* If the channel global interrupt flag is cleared, then - * something's very wrong. */ - ASSERT(status_bits & BIT(0)); - - dma_clear_isr_bits(dev, channel); - - /* ISR flags get set even if the corresponding interrupt enable - * bits in the channel's configuration register are cleared, so we - * can't use a switch here. - * - * Don't change the order of these if statements. */ - if (status_bits & BIT(3)) { - return DMA_TRANSFER_ERROR; - } else if (status_bits & BIT(1)) { - return DMA_TRANSFER_COMPLETE; - } else if (status_bits & BIT(2)) { - return DMA_TRANSFER_HALF_COMPLETE; - } else if (status_bits & BIT(0)) { - /* Shouldn't happen (unless someone messed up an IFCR write). */ - throb(); - } -#if DEBUG_LEVEL < DEBUG_ALL - else { - /* We shouldn't have been called, but the debug level is too - * low for the above ASSERT() to have had any effect. In - * order to fail fast, mimic the DMA controller's behavior - * when an error occurs. */ - dma_disable(dev, channel); - } -#endif - return DMA_TRANSFER_ERROR; -} - -/** - * @brief Enable a DMA channel. - * @param dev DMA device - * @param channel Channel to enable - */ -void dma_enable(dma_dev *dev, dma_channel channel) { - dma_channel_reg_map *chan_regs = dma_channel_regs(dev, channel); - bb_peri_set_bit(&chan_regs->CCR, DMA_CCR_EN_BIT, 1); -} - -/** - * @brief Disable a DMA channel. - * @param dev DMA device - * @param channel Channel to disable - */ -void dma_disable(dma_dev *dev, dma_channel channel) { - dma_channel_reg_map *chan_regs = dma_channel_regs(dev, channel); - bb_peri_set_bit(&chan_regs->CCR, DMA_CCR_EN_BIT, 0); -} - -/** - * @brief Set the base memory address where data will be read from or - * written to. - * - * You must not call this function while the channel is enabled. - * - * If the DMA memory size is 16 bits, the address is automatically - * aligned to a half-word. If the DMA memory size is 32 bits, the - * address is aligned to a word. - * - * @param dev DMA Device - * @param channel Channel whose base memory address to set. - * @param addr Memory base address to use. - */ -void dma_set_mem_addr(dma_dev *dev, dma_channel channel, __io void *addr) { - dma_channel_reg_map *chan_regs; - - ASSERT_FAULT(!dma_is_channel_enabled(dev, channel)); - - chan_regs = dma_channel_regs(dev, channel); - chan_regs->CMAR = (uint32)addr; -} - -/** - * @brief Set the base peripheral address where data will be read from - * or written to. - * - * You must not call this function while the channel is enabled. - * - * If the DMA peripheral size is 16 bits, the address is automatically - * aligned to a half-word. If the DMA peripheral size is 32 bits, the - * address is aligned to a word. - * - * @param dev DMA Device - * @param channel Channel whose peripheral data register base address to set. - * @param addr Peripheral memory base address to use. - */ -void dma_set_per_addr(dma_dev *dev, dma_channel channel, __io void *addr) { - dma_channel_reg_map *chan_regs; - - ASSERT_FAULT(!dma_is_channel_enabled(dev, channel)); - - chan_regs = dma_channel_regs(dev, channel); - chan_regs->CPAR = (uint32)addr; -} - -/* - * IRQ handlers - */ - -static inline void dispatch_handler(dma_dev *dev, dma_channel channel) { - void (*handler)(void) = dev->handlers[channel - 1].handler; - if (handler) { - handler(); - dma_clear_isr_bits(dev, channel); /* in case handler doesn't */ - } -} - -void __irq_dma1_channel1(void) { - dispatch_handler(DMA1, DMA_CH1); -} - -void __irq_dma1_channel2(void) { - dispatch_handler(DMA1, DMA_CH2); -} - -void __irq_dma1_channel3(void) { - dispatch_handler(DMA1, DMA_CH3); -} - -void __irq_dma1_channel4(void) { - dispatch_handler(DMA1, DMA_CH4); -} - -void __irq_dma1_channel5(void) { - dispatch_handler(DMA1, DMA_CH5); -} - -void __irq_dma1_channel6(void) { - dispatch_handler(DMA1, DMA_CH6); -} - -void __irq_dma1_channel7(void) { - dispatch_handler(DMA1, DMA_CH7); -} - -#ifdef STM32_HIGH_DENSITY -void __irq_dma2_channel1(void) { - dispatch_handler(DMA2, DMA_CH1); -} - -void __irq_dma2_channel2(void) { - dispatch_handler(DMA2, DMA_CH2); -} - -void __irq_dma2_channel3(void) { - dispatch_handler(DMA2, DMA_CH3); -} - -void __irq_dma2_channel4_5(void) { - dispatch_handler(DMA2, DMA_CH4); - dispatch_handler(DMA2, DMA_CH5); -} -#endif - -#endif \ No newline at end of file diff --git a/STM32F4/cores/maple/libmaple/dmaF1.h b/STM32F4/cores/maple/libmaple/dmaF1.h deleted file mode 100644 index 6e8087f..0000000 --- a/STM32F4/cores/maple/libmaple/dmaF1.h +++ /dev/null @@ -1,453 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Michael Hope. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file dma.h - * - * @author Marti Bolivar ; - * Original implementation by Michael Hope - * - * @brief Direct Memory Access peripheral support - */ - -/* - * See /notes/dma.txt for more information. - */ - -#ifndef _DMA_H_ -#define _DMA_H_ - -#include "libmaple_types.h" -#include "rcc.h" -#include "nvic.h" - -#ifdef __cplusplus -extern "C"{ -#endif - -/* - * Register maps - */ - -/** - * @brief DMA register map type. - * - * Note that DMA controller 2 (register map base pointer DMA2_BASE) - * only supports channels 1--5. - */ -typedef struct dma_reg_map { - __io uint32 ISR; /**< Interrupt status register */ - __io uint32 IFCR; /**< Interrupt flag clear register */ - __io uint32 CCR1; /**< Channel 1 configuration register */ - __io uint32 CNDTR1; /**< Channel 1 number of data register */ - __io uint32 CPAR1; /**< Channel 1 peripheral address register */ - __io uint32 CMAR1; /**< Channel 1 memory address register */ - const uint32 RESERVED1; /**< Reserved. */ - __io uint32 CCR2; /**< Channel 2 configuration register */ - __io uint32 CNDTR2; /**< Channel 2 number of data register */ - __io uint32 CPAR2; /**< Channel 2 peripheral address register */ - __io uint32 CMAR2; /**< Channel 2 memory address register */ - const uint32 RESERVED2; /**< Reserved. */ - __io uint32 CCR3; /**< Channel 3 configuration register */ - __io uint32 CNDTR3; /**< Channel 3 number of data register */ - __io uint32 CPAR3; /**< Channel 3 peripheral address register */ - __io uint32 CMAR3; /**< Channel 3 memory address register */ - const uint32 RESERVED3; /**< Reserved. */ - __io uint32 CCR4; /**< Channel 4 configuration register */ - __io uint32 CNDTR4; /**< Channel 4 number of data register */ - __io uint32 CPAR4; /**< Channel 4 peripheral address register */ - __io uint32 CMAR4; /**< Channel 4 memory address register */ - const uint32 RESERVED4; /**< Reserved. */ - __io uint32 CCR5; /**< Channel 5 configuration register */ - __io uint32 CNDTR5; /**< Channel 5 number of data register */ - __io uint32 CPAR5; /**< Channel 5 peripheral address register */ - __io uint32 CMAR5; /**< Channel 5 memory address register */ - const uint32 RESERVED5; /**< Reserved. */ - __io uint32 CCR6; /**< Channel 6 configuration register */ - __io uint32 CNDTR6; /**< Channel 6 number of data register */ - __io uint32 CPAR6; /**< Channel 6 peripheral address register */ - __io uint32 CMAR6; /**< Channel 6 memory address register */ - const uint32 RESERVED6; /**< Reserved. */ - __io uint32 CCR7; /**< Channel 7 configuration register */ - __io uint32 CNDTR7; /**< Channel 7 number of data register */ - __io uint32 CPAR7; /**< Channel 7 peripheral address register */ - __io uint32 CMAR7; /**< Channel 7 memory address register */ - const uint32 RESERVED7; /**< Reserved. */ -} dma_reg_map; - -/** DMA controller 1 register map base pointer */ -#define DMA1_BASE ((struct dma_reg_map*)0x40020000) - -#ifdef STM32_HIGH_DENSITY -/** DMA controller 2 register map base pointer */ -#define DMA2_BASE ((struct dma_reg_map*)0x40020400) -#endif - -/* - * Register bit definitions - */ - -/* Interrupt status register */ - -#define DMA_ISR_TEIF7_BIT 27 -#define DMA_ISR_HTIF7_BIT 26 -#define DMA_ISR_TCIF7_BIT 25 -#define DMA_ISR_GIF7_BIT 24 -#define DMA_ISR_TEIF6_BIT 23 -#define DMA_ISR_HTIF6_BIT 22 -#define DMA_ISR_TCIF6_BIT 21 -#define DMA_ISR_GIF6_BIT 20 -#define DMA_ISR_TEIF5_BIT 19 -#define DMA_ISR_HTIF5_BIT 18 -#define DMA_ISR_TCIF5_BIT 17 -#define DMA_ISR_GIF5_BIT 16 -#define DMA_ISR_TEIF4_BIT 15 -#define DMA_ISR_HTIF4_BIT 14 -#define DMA_ISR_TCIF4_BIT 13 -#define DMA_ISR_GIF4_BIT 12 -#define DMA_ISR_TEIF3_BIT 11 -#define DMA_ISR_HTIF3_BIT 10 -#define DMA_ISR_TCIF3_BIT 9 -#define DMA_ISR_GIF3_BIT 8 -#define DMA_ISR_TEIF2_BIT 7 -#define DMA_ISR_HTIF2_BIT 6 -#define DMA_ISR_TCIF2_BIT 5 -#define DMA_ISR_GIF2_BIT 4 -#define DMA_ISR_TEIF1_BIT 3 -#define DMA_ISR_HTIF1_BIT 2 -#define DMA_ISR_TCIF1_BIT 1 -#define DMA_ISR_GIF1_BIT 0 - -#define DMA_ISR_TEIF7 BIT(DMA_ISR_TEIF7_BIT) -#define DMA_ISR_HTIF7 BIT(DMA_ISR_HTIF7_BIT) -#define DMA_ISR_TCIF7 BIT(DMA_ISR_TCIF7_BIT) -#define DMA_ISR_GIF7 BIT(DMA_ISR_GIF7_BIT) -#define DMA_ISR_TEIF6 BIT(DMA_ISR_TEIF6_BIT) -#define DMA_ISR_HTIF6 BIT(DMA_ISR_HTIF6_BIT) -#define DMA_ISR_TCIF6 BIT(DMA_ISR_TCIF6_BIT) -#define DMA_ISR_GIF6 BIT(DMA_ISR_GIF6_BIT) -#define DMA_ISR_TEIF5 BIT(DMA_ISR_TEIF5_BIT) -#define DMA_ISR_HTIF5 BIT(DMA_ISR_HTIF5_BIT) -#define DMA_ISR_TCIF5 BIT(DMA_ISR_TCIF5_BIT) -#define DMA_ISR_GIF5 BIT(DMA_ISR_GIF5_BIT) -#define DMA_ISR_TEIF4 BIT(DMA_ISR_TEIF4_BIT) -#define DMA_ISR_HTIF4 BIT(DMA_ISR_HTIF4_BIT) -#define DMA_ISR_TCIF4 BIT(DMA_ISR_TCIF4_BIT) -#define DMA_ISR_GIF4 BIT(DMA_ISR_GIF4_BIT) -#define DMA_ISR_TEIF3 BIT(DMA_ISR_TEIF3_BIT) -#define DMA_ISR_HTIF3 BIT(DMA_ISR_HTIF3_BIT) -#define DMA_ISR_TCIF3 BIT(DMA_ISR_TCIF3_BIT) -#define DMA_ISR_GIF3 BIT(DMA_ISR_GIF3_BIT) -#define DMA_ISR_TEIF2 BIT(DMA_ISR_TEIF2_BIT) -#define DMA_ISR_HTIF2 BIT(DMA_ISR_HTIF2_BIT) -#define DMA_ISR_TCIF2 BIT(DMA_ISR_TCIF2_BIT) -#define DMA_ISR_GIF2 BIT(DMA_ISR_GIF2_BIT) -#define DMA_ISR_TEIF1 BIT(DMA_ISR_TEIF1_BIT) -#define DMA_ISR_HTIF1 BIT(DMA_ISR_HTIF1_BIT) -#define DMA_ISR_TCIF1 BIT(DMA_ISR_TCIF1_BIT) -#define DMA_ISR_GIF1 BIT(DMA_ISR_GIF1_BIT) - -/* Interrupt flag clear register */ - -#define DMA_IFCR_CTEIF7_BIT 27 -#define DMA_IFCR_CHTIF7_BIT 26 -#define DMA_IFCR_CTCIF7_BIT 25 -#define DMA_IFCR_CGIF7_BIT 24 -#define DMA_IFCR_CTEIF6_BIT 23 -#define DMA_IFCR_CHTIF6_BIT 22 -#define DMA_IFCR_CTCIF6_BIT 21 -#define DMA_IFCR_CGIF6_BIT 20 -#define DMA_IFCR_CTEIF5_BIT 19 -#define DMA_IFCR_CHTIF5_BIT 18 -#define DMA_IFCR_CTCIF5_BIT 17 -#define DMA_IFCR_CGIF5_BIT 16 -#define DMA_IFCR_CTEIF4_BIT 15 -#define DMA_IFCR_CHTIF4_BIT 14 -#define DMA_IFCR_CTCIF4_BIT 13 -#define DMA_IFCR_CGIF4_BIT 12 -#define DMA_IFCR_CTEIF3_BIT 11 -#define DMA_IFCR_CHTIF3_BIT 10 -#define DMA_IFCR_CTCIF3_BIT 9 -#define DMA_IFCR_CGIF3_BIT 8 -#define DMA_IFCR_CTEIF2_BIT 7 -#define DMA_IFCR_CHTIF2_BIT 6 -#define DMA_IFCR_CTCIF2_BIT 5 -#define DMA_IFCR_CGIF2_BIT 4 -#define DMA_IFCR_CTEIF1_BIT 3 -#define DMA_IFCR_CHTIF1_BIT 2 -#define DMA_IFCR_CTCIF1_BIT 1 -#define DMA_IFCR_CGIF1_BIT 0 - -#define DMA_IFCR_CTEIF7 BIT(DMA_IFCR_CTEIF7_BIT) -#define DMA_IFCR_CHTIF7 BIT(DMA_IFCR_CHTIF7_BIT) -#define DMA_IFCR_CTCIF7 BIT(DMA_IFCR_CTCIF7_BIT) -#define DMA_IFCR_CGIF7 BIT(DMA_IFCR_CGIF7_BIT) -#define DMA_IFCR_CTEIF6 BIT(DMA_IFCR_CTEIF6_BIT) -#define DMA_IFCR_CHTIF6 BIT(DMA_IFCR_CHTIF6_BIT) -#define DMA_IFCR_CTCIF6 BIT(DMA_IFCR_CTCIF6_BIT) -#define DMA_IFCR_CGIF6 BIT(DMA_IFCR_CGIF6_BIT) -#define DMA_IFCR_CTEIF5 BIT(DMA_IFCR_CTEIF5_BIT) -#define DMA_IFCR_CHTIF5 BIT(DMA_IFCR_CHTIF5_BIT) -#define DMA_IFCR_CTCIF5 BIT(DMA_IFCR_CTCIF5_BIT) -#define DMA_IFCR_CGIF5 BIT(DMA_IFCR_CGIF5_BIT) -#define DMA_IFCR_CTEIF4 BIT(DMA_IFCR_CTEIF4_BIT) -#define DMA_IFCR_CHTIF4 BIT(DMA_IFCR_CHTIF4_BIT) -#define DMA_IFCR_CTCIF4 BIT(DMA_IFCR_CTCIF4_BIT) -#define DMA_IFCR_CGIF4 BIT(DMA_IFCR_CGIF4_BIT) -#define DMA_IFCR_CTEIF3 BIT(DMA_IFCR_CTEIF3_BIT) -#define DMA_IFCR_CHTIF3 BIT(DMA_IFCR_CHTIF3_BIT) -#define DMA_IFCR_CTCIF3 BIT(DMA_IFCR_CTCIF3_BIT) -#define DMA_IFCR_CGIF3 BIT(DMA_IFCR_CGIF3_BIT) -#define DMA_IFCR_CTEIF2 BIT(DMA_IFCR_CTEIF2_BIT) -#define DMA_IFCR_CHTIF2 BIT(DMA_IFCR_CHTIF2_BIT) -#define DMA_IFCR_CTCIF2 BIT(DMA_IFCR_CTCIF2_BIT) -#define DMA_IFCR_CGIF2 BIT(DMA_IFCR_CGIF2_BIT) -#define DMA_IFCR_CTEIF1 BIT(DMA_IFCR_CTEIF1_BIT) -#define DMA_IFCR_CHTIF1 BIT(DMA_IFCR_CHTIF1_BIT) -#define DMA_IFCR_CTCIF1 BIT(DMA_IFCR_CTCIF1_BIT) -#define DMA_IFCR_CGIF1 BIT(DMA_IFCR_CGIF1_BIT) - -/* Channel configuration register */ - -#define DMA_CCR_MEM2MEM_BIT 14 -#define DMA_CCR_MINC_BIT 7 -#define DMA_CCR_PINC_BIT 6 -#define DMA_CCR_CIRC_BIT 5 -#define DMA_CCR_DIR_BIT 4 -#define DMA_CCR_TEIE_BIT 3 -#define DMA_CCR_HTIE_BIT 2 -#define DMA_CCR_TCIE_BIT 1 -#define DMA_CCR_EN_BIT 0 - -#define DMA_CCR_MEM2MEM BIT(DMA_CCR_MEM2MEM_BIT) -#define DMA_CCR_PL (0x3 << 12) -#define DMA_CCR_PL_LOW (0x0 << 12) -#define DMA_CCR_PL_MEDIUM (0x1 << 12) -#define DMA_CCR_PL_HIGH (0x2 << 12) -#define DMA_CCR_PL_VERY_HIGH (0x3 << 12) -#define DMA_CCR_MSIZE (0x3 << 10) -#define DMA_CCR_MSIZE_8BITS (0x0 << 10) -#define DMA_CCR_MSIZE_16BITS (0x1 << 10) -#define DMA_CCR_MSIZE_32BITS (0x2 << 10) -#define DMA_CCR_PSIZE (0x3 << 8) -#define DMA_CCR_PSIZE_8BITS (0x0 << 8) -#define DMA_CCR_PSIZE_16BITS (0x1 << 8) -#define DMA_CCR_PSIZE_32BITS (0x2 << 8) -#define DMA_CCR_MINC BIT(DMA_CCR_MINC_BIT) -#define DMA_CCR_PINC BIT(DMA_CCR_PINC_BIT) -#define DMA_CCR_CIRC BIT(DMA_CCR_CIRC_BIT) -#define DMA_CCR_DIR BIT(DMA_CCR_DIR_BIT) -#define DMA_CCR_TEIE BIT(DMA_CCR_TEIE_BIT) -#define DMA_CCR_HTIE BIT(DMA_CCR_HTIE_BIT) -#define DMA_CCR_TCIE BIT(DMA_CCR_TCIE_BIT) -#define DMA_CCR_EN BIT(DMA_CCR_EN_BIT) - -/* - * Devices - */ - -/** Encapsulates state related to a DMA channel interrupt. */ -typedef struct dma_handler_config { - void (*handler)(void); /**< User-specified channel interrupt - handler */ - nvic_irq_num irq_line; /**< Channel's NVIC interrupt number */ -} dma_handler_config; - -/** DMA device type */ -typedef struct dma_dev { - dma_reg_map *regs; /**< Register map */ - rcc_clk_id clk_id; /**< Clock ID */ - dma_handler_config handlers[]; /**< - * @brief IRQ handlers and NVIC numbers. - * - * @see dma_attach_interrupt() - * @see dma_detach_interrupt() - */ -} dma_dev; - -extern dma_dev *DMA1; -#ifdef STM32_HIGH_DENSITY -extern dma_dev *DMA2; -#endif - -/* - * Convenience functions - */ - -void dma_init(dma_dev *dev); - -/** Flags for DMA transfer configuration. */ -typedef enum dma_mode_flags { - DMA_MEM_2_MEM = 1 << 14, /**< Memory to memory mode */ - DMA_MINC_MODE = 1 << 7, /**< Auto-increment memory address */ - DMA_PINC_MODE = 1 << 6, /**< Auto-increment peripheral address */ - DMA_CIRC_MODE = 1 << 5, /**< Circular mode */ - DMA_FROM_MEM = 1 << 4, /**< Read from memory to peripheral */ - DMA_TRNS_ERR = 1 << 3, /**< Interrupt on transfer error */ - DMA_HALF_TRNS = 1 << 2, /**< Interrupt on half-transfer */ - DMA_TRNS_CMPLT = 1 << 1 /**< Interrupt on transfer completion */ -} dma_mode_flags; - -/** Source and destination transfer sizes. */ -typedef enum dma_xfer_size { - DMA_SIZE_8BITS = 0, /**< 8-bit transfers */ - DMA_SIZE_16BITS = 1, /**< 16-bit transfers */ - DMA_SIZE_32BITS = 2 /**< 32-bit transfers */ -} dma_xfer_size; - -/** DMA channel */ -typedef enum dma_channel { - DMA_CH1 = 1, /**< Channel 1 */ - DMA_CH2 = 2, /**< Channel 2 */ - DMA_CH3 = 3, /**< Channel 3 */ - DMA_CH4 = 4, /**< Channel 4 */ - DMA_CH5 = 5, /**< Channel 5 */ - DMA_CH6 = 6, /**< Channel 6 */ - DMA_CH7 = 7, /**< Channel 7 */ -} dma_channel; - -void dma_setup_transfer(dma_dev *dev, - dma_channel channel, - __io void *peripheral_address, - dma_xfer_size peripheral_size, - __io void *memory_address, - dma_xfer_size memory_size, - uint32 mode); - -void dma_set_num_transfers(dma_dev *dev, - dma_channel channel, - uint16 num_transfers); - -/** DMA transfer priority. */ -typedef enum dma_priority { - DMA_PRIORITY_LOW = DMA_CCR_PL_LOW, /**< Low priority */ - DMA_PRIORITY_MEDIUM = DMA_CCR_PL_MEDIUM, /**< Medium priority */ - DMA_PRIORITY_HIGH = DMA_CCR_PL_HIGH, /**< High priority */ - DMA_PRIORITY_VERY_HIGH = DMA_CCR_PL_VERY_HIGH /**< Very high priority */ -} dma_priority; - -void dma_set_priority(dma_dev *dev, - dma_channel channel, - dma_priority priority); - -void dma_attach_interrupt(dma_dev *dev, - dma_channel channel, - void (*handler)(void)); -void dma_detach_interrupt(dma_dev *dev, dma_channel channel); - -/** - * Encodes the reason why a DMA interrupt was called. - * @see dma_get_irq_cause() - */ -typedef enum dma_irq_cause { - DMA_TRANSFER_COMPLETE, /**< Transfer is complete. */ - DMA_TRANSFER_HALF_COMPLETE, /**< Transfer is half complete. */ - DMA_TRANSFER_ERROR, /**< Error occurred during transfer. */ -} dma_irq_cause; - -dma_irq_cause dma_get_irq_cause(dma_dev *dev, dma_channel channel); - -void dma_enable(dma_dev *dev, dma_channel channel); -void dma_disable(dma_dev *dev, dma_channel channel); - -void dma_set_mem_addr(dma_dev *dev, dma_channel channel, __io void *address); -void dma_set_per_addr(dma_dev *dev, dma_channel channel, __io void *address); - -/** - * @brief DMA channel register map type. - * - * Provides access to an individual channel's registers. - */ -typedef struct dma_channel_reg_map { - __io uint32 CCR; /**< Channel configuration register */ - __io uint32 CNDTR; /**< Channel number of data register */ - __io uint32 CPAR; /**< Channel peripheral address register */ - __io uint32 CMAR; /**< Channel memory address register */ -} dma_channel_reg_map; - -#define DMA_CHANNEL_NREGS 5 - -/** - * @brief Obtain a pointer to an individual DMA channel's registers. - * - * For example, dma_channel_regs(DMA1, DMA_CH1)->CCR is DMA1_BASE->CCR1. - * - * @param dev DMA device - * @param channel DMA channel whose channel register map to obtain. - */ -static inline dma_channel_reg_map* dma_channel_regs(dma_dev *dev, - dma_channel channel) { - __io uint32 *ccr1 = &dev->regs->CCR1; - return (dma_channel_reg_map*)(ccr1 + DMA_CHANNEL_NREGS * (channel - 1)); -} - -/** - * @brief Check if a DMA channel is enabled - * @param dev DMA device - * @param channel Channel whose enabled bit to check. - */ -static inline uint8 dma_is_channel_enabled(dma_dev *dev, dma_channel channel) { - return (uint8)(dma_channel_regs(dev, channel)->CCR & DMA_CCR_EN); -} - -/** - * @brief Get the ISR status bits for a DMA channel. - * - * The bits are returned right-aligned, in the following order: - * transfer error flag, half-transfer flag, transfer complete flag, - * global interrupt flag. - * - * If you're attempting to figure out why a DMA interrupt fired; you - * may find dma_get_irq_cause() more convenient. - * - * @param dev DMA device - * @param channel Channel whose ISR bits to return. - * @see dma_get_irq_cause(). - */ -static inline uint8 dma_get_isr_bits(dma_dev *dev, dma_channel channel) { - uint8 shift = (channel - 1) * 4; - return (dev->regs->ISR >> shift) & 0xF; -} - -/** - * @brief Clear the ISR status bits for a given DMA channel. - * - * If you're attempting to clean up after yourself in a DMA interrupt, - * you may find dma_get_irq_cause() more convenient. - * - * @param dev DMA device - * @param channel Channel whose ISR bits to clear. - * @see dma_get_irq_cause() - */ -static inline void dma_clear_isr_bits(dma_dev *dev, dma_channel channel) { - dev->regs->IFCR = BIT(4 * (channel - 1)); -} - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif diff --git a/STM32F4/cores/maple/libmaple/dmaF2.c b/STM32F4/cores/maple/libmaple/dmaF4.c similarity index 91% rename from STM32F4/cores/maple/libmaple/dmaF2.c rename to STM32F4/cores/maple/libmaple/dmaF4.c index 0911e58..add3d8e 100644 --- a/STM32F4/cores/maple/libmaple/dmaF2.c +++ b/STM32F4/cores/maple/libmaple/dmaF4.c @@ -24,10 +24,10 @@ * SOFTWARE. *****************************************************************************/ - #ifdef STM32F2 +#ifdef STM32F4 /** - * @file dmaF2.c + * @file dmaF4.c * @brief Direct Memory Access peripheral support */ @@ -117,33 +117,16 @@ void dma_detach_interrupt(dma_dev *dev, dma_stream stream) { dev->handlers[stream].handler = NULL; } +const uint8 dma_isr_bits_shift[] = { 0, 6, 16, 22}; + +uint8 dma_get_isr_bits(dma_dev *dev, dma_stream stream) { + if ( stream&0xFC ) return ((dev->regs->HISR)>>dma_isr_bits_shift[stream&0x03]) & 0x3d; + else return ((dev->regs->LISR)>>dma_isr_bits_shift[stream&0x03]) & 0x3d; +} + void dma_clear_isr_bits(dma_dev *dev, dma_stream stream) { - switch (stream) { - case 0: - dev->regs->LIFCR|=0x0000003d; - break; - case 1: - dev->regs->LIFCR|=0x00000f40; - break; - case 2: - dev->regs->LIFCR|=0x003d0000; - break; - case 3: - dev->regs->LIFCR|=0x0f400000; - break; - case 4: - dev->regs->HIFCR|=0x0000003d; - break; - case 5: - dev->regs->HIFCR|=0x00000f40; - break; - case 6: - dev->regs->HIFCR|=0x003d0000; - break; - case 7: - dev->regs->HIFCR|=0x0f400000; - break; - } + if ( stream&0xFC ) dev->regs->HIFCR = (uint32)0x0000003d << dma_isr_bits_shift[stream&0x03]; + else dev->regs->LIFCR = (uint32)0x0000003d << dma_isr_bits_shift[stream&0x03]; } /* diff --git a/STM32F4/cores/maple/libmaple/dmaF2.h b/STM32F4/cores/maple/libmaple/dmaF4.h similarity index 74% rename from STM32F4/cores/maple/libmaple/dmaF2.h rename to STM32F4/cores/maple/libmaple/dmaF4.h index 6f7086f..757906c 100644 --- a/STM32F4/cores/maple/libmaple/dmaF2.h +++ b/STM32F4/cores/maple/libmaple/dmaF4.h @@ -25,7 +25,7 @@ *****************************************************************************/ /** - * @file dma.h + * @file dmaF4.h * * @author Marti Bolivar ; * Original implementation by Michael Hope @@ -84,7 +84,7 @@ typedef struct dma_reg_map { * Register bit definitions */ -/* Channel configuration register */ +/* Stream configuration register */ #define DMA_CR_CH0 (0x0 << 25) #define DMA_CR_CH1 (0x1 << 25) @@ -136,6 +136,25 @@ typedef struct dma_reg_map { #define DMA_CR_DMEIE (0x1 << 1) #define DMA_CR_EN (0x1) +typedef enum dma_channel { + DMA_CH0 = DMA_CR_CH0, /**< Channel 0 */ + DMA_CH1 = DMA_CR_CH1, /**< Channel 1 */ + DMA_CH2 = DMA_CR_CH2, /**< Channel 2 */ + DMA_CH3 = DMA_CR_CH3, /**< Channel 3 */ + DMA_CH4 = DMA_CR_CH4, /**< Channel 4 */ + DMA_CH5 = DMA_CR_CH5, /**< Channel 5 */ + DMA_CH6 = DMA_CR_CH6, /**< Channel 6 */ + DMA_CH7 = DMA_CR_CH7, /**< Channel 7 */ +} dma_channel; + +/* Device interrupt status register flags */ + +#define DMA_ISR_TCIF (1 << 5) +#define DMA_ISR_HTIF (1 << 4) +#define DMA_ISR_TEIF (1 << 3) +#define DMA_ISR_DMEIF (1 << 2) +#define DMA_ISR_FEIF (1 << 0) + /* * Devices */ @@ -166,25 +185,35 @@ extern dma_dev *DMA2; * Convenience functions */ -void dma_init(dma_dev *dev); +extern void dma_init(dma_dev *dev); /** Flags for DMA transfer configuration. */ typedef enum dma_mode_flags { - DMA_MEM_2_MEM = 1 << 14, /**< Memory to memory mode */ - DMA_MINC_MODE = 1 << 7, /**< Auto-increment memory address */ - DMA_PINC_MODE = 1 << 6, /**< Auto-increment peripheral address */ - DMA_CIRC_MODE = 1 << 5, /**< Circular mode */ - DMA_FROM_MEM = 1 << 4, /**< Read from memory to peripheral */ - DMA_TRNS_ERR = 1 << 3, /**< Interrupt on transfer error */ - DMA_HALF_TRNS = 1 << 2, /**< Interrupt on half-transfer */ - DMA_TRNS_CMPLT = 1 << 1 /**< Interrupt on transfer completion */ + DMA_MEM_BUF_0 = DMA_CR_CT0, /**< Current memory target buffer 0 */ + DMA_MEM_BUF_1 = DMA_CR_CT1, /**< Current memory target buffer 1 */ + DMA_DBL_BUF_MODE = DMA_CR_DBM, /**< Current memory double buffer mode */ + DMA_PINC_OFFSET = DMA_CR_PINCOS, /**< Peripheral increment offset size */ + DMA_MINC_MODE = DMA_CR_MINC, /**< Memory increment mode */ + DMA_PINC_MODE = DMA_CR_PINC, /**< Peripheral increment mode */ + DMA_CIRC_MODE = DMA_CR_CIRC, /**< Memory Circular mode */ + DMA_FROM_PER = DMA_CR_DIR_P2M, /**< Read from memory to peripheral */ + DMA_FROM_MEM = DMA_CR_DIR_M2P, /**< Read from memory to peripheral */ + DMA_MEM_TO_MEM = DMA_CR_DIR_M2M, /**< Read from memory to memory */ + DMA_PERIF_CTRL = DMA_CR_PFCTRL, /**< Peripheral flow controller */ + DMA_PRIO_MEDIUM = DMA_CR_PL_MEDIUM, /**< Medium priority */ + DMA_PRIO_HIGH = DMA_CR_PL_HIGH, /**< High priority */ + DMA_PRIO_VERY_HIGH = DMA_CR_PL_VERY_HIGH, /**< Very high priority */ + DMA_TRNS_CMPLT = DMA_CR_TCIE, /**< Interrupt on transfer completion */ + DMA_TRNS_HALF = DMA_CR_HTIE, /**< Interrupt on half-transfer */ + DMA_TRNS_ERR = DMA_CR_TEIE, /**< Interrupt on transfer error */ + DMA_DIR_MODE_ERR = DMA_CR_DMEIE /**< Interrupt on direct mode error */ } dma_mode_flags; /** Source and destination transfer sizes. */ typedef enum dma_xfer_size { - DMA_SIZE_8BITS = 0, /**< 8-bit transfers */ - DMA_SIZE_16BITS = 1, /**< 16-bit transfers */ - DMA_SIZE_32BITS = 2 /**< 32-bit transfers */ + DMA_SIZE_8BITS = ( DMA_CR_MSIZE_8BITS|DMA_CR_PSIZE_8BITS ), /**< 8-bit transfers */ + DMA_SIZE_16BITS = (DMA_CR_MSIZE_16BITS|DMA_CR_PSIZE_16BITS), /**< 16-bit transfers */ + DMA_SIZE_32BITS = (DMA_CR_MSIZE_32BITS|DMA_CR_PSIZE_32BITS) /**< 32-bit transfers */ } dma_xfer_size; /** DMA channel */ @@ -201,17 +230,17 @@ typedef enum dma_stream { static inline void dma_setup_transfer(dma_dev *dev, dma_stream stream, + dma_channel channel, + dma_xfer_size trx_size, __io void *peripheral_address, __io void *memory_address0, __io void *memory_address1, - uint32 flags, - uint32 fifo_flags) { + uint32 flags) { dev->regs->STREAM[stream].CR &= ~DMA_CR_EN; // disable dev->regs->STREAM[stream].PAR = (uint32)peripheral_address; dev->regs->STREAM[stream].M0AR = (uint32)memory_address0; dev->regs->STREAM[stream].M1AR = (uint32)memory_address1; - dev->regs->STREAM[stream].FCR = fifo_flags & 0x87; // mask out reserved bits - dev->regs->STREAM[stream].CR = flags & 0x0feffffe; // mask out reserved and enable + dev->regs->STREAM[stream].CR = ((flags|channel|trx_size) & 0x0feffffe); // mask out reserved and enable } static inline void dma_set_num_transfers(dma_dev *dev, @@ -220,6 +249,12 @@ static inline void dma_set_num_transfers(dma_dev *dev, dev->regs->STREAM[stream].NDTR = num_transfers; } +static inline void dma_set_fifo_flags(dma_dev *dev, + dma_stream stream, + uint8 fifo_flags) { + dev->regs->STREAM[stream].FCR = fifo_flags & 0x87; // mask out reserved bits +} + void dma_attach_interrupt(dma_dev *dev, dma_stream stream, void (*handler)(void)); @@ -232,6 +267,7 @@ static inline void dma_enable(dma_dev *dev, dma_stream stream) { static inline void dma_disable(dma_dev *dev, dma_stream stream) { dev->regs->STREAM[stream].CR &= ~DMA_CR_EN; + while (dev->regs->STREAM[stream].CR & DMA_CR_EN); // wait till EN bit is reset, see AN4031, chapter 4.1 } /** diff --git a/STM32F4/cores/maple/libmaple/exti.h b/STM32F4/cores/maple/libmaple/exti.h index bac8adc..063f2d7 100644 --- a/STM32F4/cores/maple/libmaple/exti.h +++ b/STM32F4/cores/maple/libmaple/exti.h @@ -52,11 +52,7 @@ typedef struct exti_reg_map { } exti_reg_map; /** EXTI register map base pointer */ -#ifdef STM32F2 #define EXTI_BASE ((struct exti_reg_map*)0x40013C00) -#else -#define EXTI_BASE ((struct exti_reg_map*)0x40010400) -#endif /** External interrupt trigger mode */ typedef enum exti_trigger_mode { diff --git a/STM32F4/cores/maple/libmaple/fsmc.c b/STM32F4/cores/maple/libmaple/fsmc.c index 06ca7df..42b0d77 100644 --- a/STM32F4/cores/maple/libmaple/fsmc.c +++ b/STM32F4/cores/maple/libmaple/fsmc.c @@ -39,27 +39,28 @@ */ void fsmc_sram_init_gpios(void) { /* Data lines... */ - gpio_set_mode(GPIOD, 0, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOD, 1, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOD, 8, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOD, 9, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOD, 10, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOD, 14, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOD, 15, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOE, 7, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOE, 8, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOE, 9, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOE, 10, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOE, 11, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOE, 12, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOE, 13, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOE, 14, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOE, 15, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PD0, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PD1, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PD8, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PD9, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PD10, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PD14, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PD15, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PE7, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PE8, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PE9, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PE10, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PE11, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PE12, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PE13, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PE14, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PE15, GPIO_AF_OUTPUT_PP); /* Address lines... */ - gpio_set_mode(GPIOD, 11, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOD, 12, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOD, 13, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PD11, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PD12, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PD13, GPIO_AF_OUTPUT_PP); +#if 0 // not available on LQFP package gpio_set_mode(GPIOF, 0, GPIO_AF_OUTPUT_PP); gpio_set_mode(GPIOF, 1, GPIO_AF_OUTPUT_PP); gpio_set_mode(GPIOF, 2, GPIO_AF_OUTPUT_PP); @@ -76,18 +77,20 @@ void fsmc_sram_init_gpios(void) { gpio_set_mode(GPIOG, 3, GPIO_AF_OUTPUT_PP); gpio_set_mode(GPIOG, 4, GPIO_AF_OUTPUT_PP); gpio_set_mode(GPIOG, 5, GPIO_AF_OUTPUT_PP); - +#endif // not available on LQFP package /* And control lines... */ - gpio_set_mode(GPIOD, 4, GPIO_AF_OUTPUT_PP); // NOE - gpio_set_mode(GPIOD, 5, GPIO_AF_OUTPUT_PP); // NWE + gpio_set_mode(PD4, GPIO_AF_OUTPUT_PP); // NOE + gpio_set_mode(PD5, GPIO_AF_OUTPUT_PP); // NWE - gpio_set_mode(GPIOD, 7, GPIO_AF_OUTPUT_PP); // NE1 + gpio_set_mode(PD7, GPIO_AF_OUTPUT_PP); // NE1 +#if 0 // not available on LQFP package gpio_set_mode(GPIOG, 9, GPIO_AF_OUTPUT_PP); // NE2 gpio_set_mode(GPIOG, 10, GPIO_AF_OUTPUT_PP); // NE3 gpio_set_mode(GPIOG, 12, GPIO_AF_OUTPUT_PP); // NE4 +#endif // not available on LQFP package - gpio_set_mode(GPIOE, 0, GPIO_AF_OUTPUT_PP); // NBL0 - gpio_set_mode(GPIOE, 1, GPIO_AF_OUTPUT_PP); // NBL1 + gpio_set_mode(PE0, GPIO_AF_OUTPUT_PP); // NBL0 + gpio_set_mode(PE1, GPIO_AF_OUTPUT_PP); // NBL1 } #endif /* STM32_HIGH_DENSITY */ diff --git a/STM32F4/cores/maple/libmaple/gpio.h b/STM32F4/cores/maple/libmaple/gpio.h index 4d42386..f1a141f 100644 --- a/STM32F4/cores/maple/libmaple/gpio.h +++ b/STM32F4/cores/maple/libmaple/gpio.h @@ -31,8 +31,102 @@ * (AFIO) prototypes, defines, and inlined access functions. */ -#ifdef STM32F2 -#include "gpioF2.h" -#else -#include "gpioF1.h" +#ifndef _GPIO_H_ +#define _GPIO_H_ + +#include "libmaple.h" +#include "boards.h" + +#ifdef __cplusplus +extern "C"{ #endif + + +/** + * @brief Get a GPIO port's corresponding afio_exti_port. + * @param dev GPIO device whose afio_exti_port to return. + */ +static inline afio_exti_port gpio_exti_port(const gpio_dev *dev) { + return dev->exti_port; +} + +/** + * Set or reset a GPIO pin. + * + * Pin must have previously been configured to output mode. + * + * @param dev GPIO device whose pin to set. + * @param pin Pin on to set or reset + * @param val If true, set the pin. If false, reset the pin. + */ +static inline void gpio_write_pin(uint8_t pin, uint8 val) { + if (val) { + (PIN_MAP[pin].gpio_device)->regs->BSRRL = BIT(pin&0x0F); + } else { + (PIN_MAP[pin].gpio_device)->regs->BSRRH = BIT(pin&0x0F); + } +} + +static inline void gpio_set_pin(uint8_t pin) { + (PIN_MAP[pin].gpio_device)->regs->BSRRL = BIT(pin&0x0F); +} + +static inline void gpio_clear_pin(uint8_t pin) { + (PIN_MAP[pin].gpio_device)->regs->BSRRH = BIT(pin&0x0F); +} + +/** + * Determine whether or not a GPIO pin is set. + * + * Pin must have previously been configured to input mode. + * + * @param dev GPIO device whose pin to test. + * @param pin Pin on dev to test. + * @return True if the pin is set, false otherwise. + */ +static inline uint32 gpio_read_pin(uint8_t pin) { + return (PIN_MAP[pin].gpio_device)->regs->IDR & BIT(pin&0x0F); +} + +/** + * Toggle a pin configured as output push-pull. + * @param dev GPIO device. + * @param pin Pin on dev to toggle. + */ +static inline void gpio_toggle_pin(uint8_t pin) { + (PIN_MAP[pin].gpio_device)->regs->ODR = (PIN_MAP[pin].gpio_device)->regs->ODR ^ BIT(pin&0x0F); +} + +/* + * GPIO Convenience routines + */ + +extern void gpio_init(const gpio_dev *dev); +extern void gpio_init_all(void); +extern void gpio_set_mode(uint8_t pin, gpio_pin_mode mode); +extern void gpio_set_af_mode(uint8_t pin, int mode); + +/* + * AFIO convenience routines + */ + +extern void afio_init(void); +extern void afio_exti_select(afio_exti_num exti, afio_exti_port gpio_port); +extern void afio_remap(afio_remap_peripheral p); + +/** + * @brief Enable or disable the JTAG and SW debug ports. + * @param config Desired debug port configuration + * @see afio_debug_cfg + */ +static inline void afio_cfg_debug_ports(afio_debug_cfg config) { + //__io uint32 *mapr = &AFIO_BASE->MAPR; + //*mapr = (*mapr & ~AFIO_MAPR_SWJ_CFG) | config; +} + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/STM32F4/cores/maple/libmaple/gpioF1.c b/STM32F4/cores/maple/libmaple/gpioF1.c deleted file mode 100644 index 846b754..0000000 --- a/STM32F4/cores/maple/libmaple/gpioF1.c +++ /dev/null @@ -1,200 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -#ifdef STM32F1 - -/** - * @file gpio.c - * @brief GPIO initialization routine - */ - -#include "gpio.h" -#include "rcc.h" - -/* - * GPIO devices - */ - -gpio_dev gpioa = { - .regs = GPIOA_BASE, - .clk_id = RCC_GPIOA, - .exti_port = AFIO_EXTI_PA, -}; -/** GPIO port A device. */ -gpio_dev* const GPIOA = &gpioa; - -gpio_dev gpiob = { - .regs = GPIOB_BASE, - .clk_id = RCC_GPIOB, - .exti_port = AFIO_EXTI_PB, -}; -/** GPIO port B device. */ -gpio_dev* const GPIOB = &gpiob; - -gpio_dev gpioc = { - .regs = GPIOC_BASE, - .clk_id = RCC_GPIOC, - .exti_port = AFIO_EXTI_PC, -}; -/** GPIO port C device. */ -gpio_dev* const GPIOC = &gpioc; - -gpio_dev gpiod = { - .regs = GPIOD_BASE, - .clk_id = RCC_GPIOD, - .exti_port = AFIO_EXTI_PD, -}; -/** GPIO port D device. */ -gpio_dev* const GPIOD = &gpiod; - -#ifdef STM32_HIGH_DENSITY -gpio_dev gpioe = { - .regs = GPIOE_BASE, - .clk_id = RCC_GPIOE, - .exti_port = AFIO_EXTI_PE, -}; -/** GPIO port E device. */ -gpio_dev* const GPIOE = &gpioe; - -gpio_dev gpiof = { - .regs = GPIOF_BASE, - .clk_id = RCC_GPIOF, - .exti_port = AFIO_EXTI_PF, -}; -/** GPIO port F device. */ -gpio_dev* const GPIOF = &gpiof; - -gpio_dev gpiog = { - .regs = GPIOG_BASE, - .clk_id = RCC_GPIOG, - .exti_port = AFIO_EXTI_PG, -}; -/** GPIO port G device. */ -gpio_dev* const GPIOG = &gpiog; -#endif - -/* - * GPIO convenience routines - */ - -/** - * Initialize a GPIO device. - * - * Enables the clock for and resets the given device. - * - * @param dev GPIO device to initialize. - */ -void gpio_init(gpio_dev *dev) { - rcc_clk_enable(dev->clk_id); - rcc_reset_dev(dev->clk_id); -} - -/** - * Initialize and reset all available GPIO devices. - */ -void gpio_init_all(void) { - gpio_init(GPIOA); - gpio_init(GPIOB); - gpio_init(GPIOC); - gpio_init(GPIOD); -#ifdef STM32_HIGH_DENSITY - gpio_init(GPIOE); - gpio_init(GPIOF); - gpio_init(GPIOG); -#endif -} - -/** - * Set the mode of a GPIO pin. - * - * @param dev GPIO device. - * @param pin Pin on the device whose mode to set, 0--15. - * @param mode General purpose or alternate function mode to set the pin to. - * @see gpio_pin_mode - */ -void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode) { - gpio_reg_map *regs = dev->regs; - __io uint32 *cr = ®s->CRL + (pin >> 3); - uint32 shift = (pin & 0x7) * 4; - uint32 tmp = *cr; - - tmp &= ~(0xF << shift); - tmp |= (mode == GPIO_INPUT_PU ? GPIO_INPUT_PD : mode) << shift; - *cr = tmp; - - if (mode == GPIO_INPUT_PD) { - regs->ODR &= ~BIT(pin); - } else if (mode == GPIO_INPUT_PU) { - regs->ODR |= BIT(pin); - } -} - -/* - * AFIO - */ - -/** - * @brief Initialize the AFIO clock, and reset the AFIO registers. - */ -void afio_init(void) { - rcc_clk_enable(RCC_AFIO); - rcc_reset_dev(RCC_AFIO); -} - -#define AFIO_EXTI_SEL_MASK 0xF - -/** - * @brief Select a source input for an external interrupt. - * - * @param exti External interrupt. - * @param gpio_port Port which contains pin to use as source input. - * @see afio_exti_num - * @see afio_exti_port - */ -void afio_exti_select(afio_exti_num exti, afio_exti_port gpio_port) { - __io uint32 *exti_cr = &AFIO_BASE->EXTICR1 + exti / 4; - uint32 shift = 4 * (exti % 4); - uint32 cr = *exti_cr; - - cr &= ~(AFIO_EXTI_SEL_MASK << shift); - cr |= gpio_port << shift; - *exti_cr = cr; -} - -/** - * @brief Perform an alternate function remap. - * @param remapping Remapping to perform. - */ -void afio_remap(afio_remap_peripheral remapping) { - if (remapping & AFIO_REMAP_USE_MAPR2) { - remapping &= ~AFIO_REMAP_USE_MAPR2; - AFIO_BASE->MAPR2 |= remapping; - } else { - AFIO_BASE->MAPR |= remapping; - } -} - -#endif diff --git a/STM32F4/cores/maple/libmaple/gpioF1.h b/STM32F4/cores/maple/libmaple/gpioF1.h deleted file mode 100644 index c69efb4..0000000 --- a/STM32F4/cores/maple/libmaple/gpioF1.h +++ /dev/null @@ -1,530 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -*****************************************************************************/ - -/** - * @file gpio.h - * - * @brief General purpose I/O (GPIO) and Alternate Function I/O - * (AFIO) prototypes, defines, and inlined access functions. - */ - -#ifndef _GPIO_H_ -#define _GPIO_H_ - -#include "libmaple.h" -#include "rcc.h" - -#ifdef __cplusplus -extern "C"{ -#endif - -/* - * GPIO register maps and devices - */ - -/** GPIO register map type */ -typedef struct gpio_reg_map { - __io uint32 CRL; /**< Port configuration register low */ - __io uint32 CRH; /**< Port configuration register high */ - __io uint32 IDR; /**< Port input data register */ - __io uint32 ODR; /**< Port output data register */ - __io uint32 BSRR; /**< Port bit set/reset register */ - __io uint32 BRR; /**< Port bit reset register */ - __io uint32 LCKR; /**< Port configuration lock register */ -} gpio_reg_map; - -/** - * @brief External interrupt line port selector. - * - * Used to determine which GPIO port to map an external interrupt line - * onto. */ -/* (See AFIO sections, below) */ -typedef enum afio_exti_port { - AFIO_EXTI_PA, /**< Use port A (PAx) pin. */ - AFIO_EXTI_PB, /**< Use port B (PBx) pin. */ - AFIO_EXTI_PC, /**< Use port C (PCx) pin. */ - AFIO_EXTI_PD, /**< Use port D (PDx) pin. */ -#ifdef STM32_HIGH_DENSITY - AFIO_EXTI_PE, /**< Use port E (PEx) pin. */ - AFIO_EXTI_PF, /**< Use port F (PFx) pin. */ - AFIO_EXTI_PG, /**< Use port G (PGx) pin. */ -#endif -} afio_exti_port; - -/** GPIO device type */ -typedef struct gpio_dev { - gpio_reg_map *regs; /**< Register map */ - rcc_clk_id clk_id; /**< RCC clock information */ - afio_exti_port exti_port; /**< AFIO external interrupt port value */ -} gpio_dev; - -extern gpio_dev gpioa; -extern gpio_dev* const GPIOA; -extern gpio_dev gpiob; -extern gpio_dev* const GPIOB; -extern gpio_dev gpioc; -extern gpio_dev* const GPIOC; -extern gpio_dev gpiod; -extern gpio_dev* const GPIOD; -#ifdef STM32_HIGH_DENSITY -extern gpio_dev gpioe; -extern gpio_dev* const GPIOE; -extern gpio_dev gpiof; -extern gpio_dev* const GPIOF; -extern gpio_dev gpiog; -extern gpio_dev* const GPIOG; -#endif - -/** GPIO port A register map base pointer */ -#define GPIOA_BASE ((struct gpio_reg_map*)0x40010800) -/** GPIO port B register map base pointer */ -#define GPIOB_BASE ((struct gpio_reg_map*)0x40010C00) -/** GPIO port C register map base pointer */ -#define GPIOC_BASE ((struct gpio_reg_map*)0x40011000) -/** GPIO port D register map base pointer */ -#define GPIOD_BASE ((struct gpio_reg_map*)0x40011400) -#ifdef STM32_HIGH_DENSITY -/** GPIO port E register map base pointer */ -#define GPIOE_BASE ((struct gpio_reg_map*)0x40011800) -/** GPIO port F register map base pointer */ -#define GPIOF_BASE ((struct gpio_reg_map*)0x40011C00) -/** GPIO port G register map base pointer */ -#define GPIOG_BASE ((struct gpio_reg_map*)0x40012000) -#endif - -/* - * GPIO register bit definitions - */ - -/* Control registers, low and high */ - -#define GPIO_CR_CNF (0x3 << 2) -#define GPIO_CR_CNF_INPUT_ANALOG (0x0 << 2) -#define GPIO_CR_CNF_INPUT_FLOATING (0x1 << 2) -#define GPIO_CR_CNF_INPUT_PU_PD (0x2 << 2) -#define GPIO_CR_CNF_OUTPUT_PP (0x0 << 2) -#define GPIO_CR_CNF_OUTPUT_OD (0x1 << 2) -#define GPIO_CR_CNF_AF_OUTPUT_PP (0x2 << 2) -#define GPIO_CR_CNF_AF_OUTPUT_OD (0x3 << 2) -#define GPIO_CR_MODE 0x3 -#define GPIO_CR_MODE_INPUT 0x0 -#define GPIO_CR_MODE_OUTPUT_10MHZ 0x1 -#define GPIO_CR_MODE_OUTPUT_2MHZ 0x2 -#define GPIO_CR_MODE_OUTPUT_50MHZ 0x3 - -/** - * @brief GPIO Pin modes. - * - * These only allow for 50MHZ max output speeds; if you want slower, - * use direct register access. - */ -typedef enum gpio_pin_mode { - GPIO_OUTPUT_PP = (GPIO_CR_CNF_OUTPUT_PP | - GPIO_CR_MODE_OUTPUT_50MHZ), /**< Output push-pull. */ - GPIO_OUTPUT_OD = (GPIO_CR_CNF_OUTPUT_OD | - GPIO_CR_MODE_OUTPUT_50MHZ), /**< Output open-drain. */ - GPIO_AF_OUTPUT_PP = (GPIO_CR_CNF_AF_OUTPUT_PP | - GPIO_CR_MODE_OUTPUT_50MHZ), /**< Alternate function - output push-pull. */ - GPIO_AF_OUTPUT_OD = (GPIO_CR_CNF_AF_OUTPUT_OD | - GPIO_CR_MODE_OUTPUT_50MHZ), /**< Alternate function - output open drain. */ - GPIO_INPUT_ANALOG = (GPIO_CR_CNF_INPUT_ANALOG | - GPIO_CR_MODE_INPUT), /**< Analog input. */ - GPIO_INPUT_FLOATING = (GPIO_CR_CNF_INPUT_FLOATING | - GPIO_CR_MODE_INPUT), /**< Input floating. */ - GPIO_INPUT_PD = (GPIO_CR_CNF_INPUT_PU_PD | - GPIO_CR_MODE_INPUT), /**< Input pull-down. */ - GPIO_AF_INPUT_PD = (GPIO_INPUT_PD), /**< Input pull-down. */ - GPIO_INPUT_PU /**< Input pull-up. */ - - - /* GPIO_INPUT_PU treated as a special case, for ODR twiddling */ -} gpio_pin_mode; - -/* - * GPIO Convenience routines - */ - -void gpio_init(gpio_dev *dev); -void gpio_init_all(void); -void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode); - -/** - * @brief Get a GPIO port's corresponding afio_exti_port. - * @param dev GPIO device whose afio_exti_port to return. - */ -static inline afio_exti_port gpio_exti_port(gpio_dev *dev) { - return dev->exti_port; -} - -/** - * Set or reset a GPIO pin. - * - * Pin must have previously been configured to output mode. - * - * @param dev GPIO device whose pin to set. - * @param pin Pin on to set or reset - * @param val If true, set the pin. If false, reset the pin. - */ -static inline void gpio_write_bit(gpio_dev *dev, uint8 pin, uint8 val) { - if (val) { - dev->regs->BSRR = BIT(pin); - } else { - dev->regs->BRR = BIT(pin); - } -} - -/** - * Determine whether or not a GPIO pin is set. - * - * Pin must have previously been configured to input mode. - * - * @param dev GPIO device whose pin to test. - * @param pin Pin on dev to test. - * @return True if the pin is set, false otherwise. - */ -static inline uint32 gpio_read_bit(gpio_dev *dev, uint8 pin) { - return dev->regs->IDR & BIT(pin); -} - -/** - * Toggle a pin configured as output push-pull. - * @param dev GPIO device. - * @param pin Pin on dev to toggle. - */ -static inline void gpio_toggle_bit(gpio_dev *dev, uint8 pin) { - dev->regs->ODR = dev->regs->ODR ^ BIT(pin); -} - -/* - * AFIO register map - */ - -/** AFIO register map */ -typedef struct afio_reg_map { - __io uint32 EVCR; /**< Event control register. */ - __io uint32 MAPR; /**< AF remap and debug I/O configuration - register. */ - __io uint32 EXTICR1; /**< External interrupt configuration - register 1. */ - __io uint32 EXTICR2; /**< External interrupt configuration - register 2. */ - __io uint32 EXTICR3; /**< External interrupt configuration - register 3. */ - __io uint32 EXTICR4; /**< External interrupt configuration - register 4. */ - __io uint32 MAPR2; /**< AF remap and debug I/O configuration - register 2. */ -} afio_reg_map; - -/** AFIO register map base pointer. */ -#define AFIO_BASE ((struct afio_reg_map *)0x40010000) - -/* - * AFIO register bit definitions - */ - -/* Event control register */ - -#define AFIO_EVCR_EVOE (0x1 << 7) -#define AFIO_EVCR_PORT_PA (0x0 << 4) -#define AFIO_EVCR_PORT_PB (0x1 << 4) -#define AFIO_EVCR_PORT_PC (0x2 << 4) -#define AFIO_EVCR_PORT_PD (0x3 << 4) -#define AFIO_EVCR_PORT_PE (0x4 << 4) -#define AFIO_EVCR_PIN_0 0x0 -#define AFIO_EVCR_PIN_1 0x1 -#define AFIO_EVCR_PIN_2 0x2 -#define AFIO_EVCR_PIN_3 0x3 -#define AFIO_EVCR_PIN_4 0x4 -#define AFIO_EVCR_PIN_5 0x5 -#define AFIO_EVCR_PIN_6 0x6 -#define AFIO_EVCR_PIN_7 0x7 -#define AFIO_EVCR_PIN_8 0x8 -#define AFIO_EVCR_PIN_9 0x9 -#define AFIO_EVCR_PIN_10 0xA -#define AFIO_EVCR_PIN_11 0xB -#define AFIO_EVCR_PIN_12 0xC -#define AFIO_EVCR_PIN_13 0xD -#define AFIO_EVCR_PIN_14 0xE -#define AFIO_EVCR_PIN_15 0xF - -/* AF remap and debug I/O configuration register */ - -#define AFIO_MAPR_SWJ_CFG (0x7 << 24) -#define AFIO_MAPR_SWJ_CFG_FULL_SWJ (0x0 << 24) -#define AFIO_MAPR_SWJ_CFG_FULL_SWJ_NO_NJRST (0x1 << 24) -#define AFIO_MAPR_SWJ_CFG_NO_JTAG_SW (0x2 << 24) -#define AFIO_MAPR_SWJ_CFG_NO_JTAG_NO_SW (0x4 << 24) -#define AFIO_MAPR_ADC2_ETRGREG_REMAP BIT(20) -#define AFIO_MAPR_ADC2_ETRGINJ_REMAP BIT(19) -#define AFIO_MAPR_ADC1_ETRGREG_REMAP BIT(18) -#define AFIO_MAPR_ADC1_ETRGINJ_REMAP BIT(17) -#define AFIO_MAPR_TIM5CH4_IREMAP BIT(16) -#define AFIO_MAPR_PD01_REMAP BIT(15) -#define AFIO_MAPR_CAN_REMAP (0x3 << 13) -#define AFIO_MAPR_CAN_REMAP_NONE (0x0 << 13) -#define AFIO_MAPR_CAN_REMAP_PB8_PB9 (0x2 << 13) -#define AFIO_MAPR_CAN_REMAP_PD0_PD1 (0x3 << 13) -#define AFIO_MAPR_TIM4_REMAP BIT(12) -#define AFIO_MAPR_TIM3_REMAP (0x3 << 10) -#define AFIO_MAPR_TIM3_REMAP_NONE (0x0 << 10) -#define AFIO_MAPR_TIM3_REMAP_PARTIAL (0x2 << 10) -#define AFIO_MAPR_TIM3_REMAP_FULL (0x3 << 10) -#define AFIO_MAPR_TIM2_REMAP (0x3 << 8) -#define AFIO_MAPR_TIM2_REMAP_NONE (0x0 << 8) -#define AFIO_MAPR_TIM2_REMAP_PA15_PB3_PA2_PA3 (0x1 << 8) -#define AFIO_MAPR_TIM2_REMAP_PA0_PA1_PB10_PB11 (0x2 << 8) -#define AFIO_MAPR_TIM2_REMAP_FULL (0x3 << 8) -#define AFIO_MAPR_TIM1_REMAP (0x3 << 6) -#define AFIO_MAPR_TIM1_REMAP_NONE (0x0 << 6) -#define AFIO_MAPR_TIM1_REMAP_PARTIAL (0x1 << 6) -#define AFIO_MAPR_TIM1_REMAP_FULL (0x3 << 6) -#define AFIO_MAPR_USART3_REMAP (0x3 << 4) -#define AFIO_MAPR_USART3_REMAP_NONE (0x0 << 4) -#define AFIO_MAPR_USART3_REMAP_PARTIAL (0x1 << 4) -#define AFIO_MAPR_USART3_REMAP_FULL (0x3 << 4) -#define AFIO_MAPR_USART2_REMAP BIT(3) -#define AFIO_MAPR_USART1_REMAP BIT(2) -#define AFIO_MAPR_I2C1_REMAP BIT(1) -#define AFIO_MAPR_SPI1_REMAP BIT(0) - -/* External interrupt configuration register 1 */ - -#define AFIO_EXTICR1_EXTI3 (0xF << 12) -#define AFIO_EXTICR1_EXTI3_PA (0x0 << 12) -#define AFIO_EXTICR1_EXTI3_PB (0x1 << 12) -#define AFIO_EXTICR1_EXTI3_PC (0x2 << 12) -#define AFIO_EXTICR1_EXTI3_PD (0x3 << 12) -#define AFIO_EXTICR1_EXTI3_PE (0x4 << 12) -#define AFIO_EXTICR1_EXTI3_PF (0x5 << 12) -#define AFIO_EXTICR1_EXTI3_PG (0x6 << 12) -#define AFIO_EXTICR1_EXTI2 (0xF << 8) -#define AFIO_EXTICR1_EXTI2_PA (0x0 << 8) -#define AFIO_EXTICR1_EXTI2_PB (0x1 << 8) -#define AFIO_EXTICR1_EXTI2_PC (0x2 << 8) -#define AFIO_EXTICR1_EXTI2_PD (0x3 << 8) -#define AFIO_EXTICR1_EXTI2_PE (0x4 << 8) -#define AFIO_EXTICR1_EXTI2_PF (0x5 << 8) -#define AFIO_EXTICR1_EXTI2_PG (0x6 << 8) -#define AFIO_EXTICR1_EXTI1 (0xF << 4) -#define AFIO_EXTICR1_EXTI1_PA (0x0 << 4) -#define AFIO_EXTICR1_EXTI1_PB (0x1 << 4) -#define AFIO_EXTICR1_EXTI1_PC (0x2 << 4) -#define AFIO_EXTICR1_EXTI1_PD (0x3 << 4) -#define AFIO_EXTICR1_EXTI1_PE (0x4 << 4) -#define AFIO_EXTICR1_EXTI1_PF (0x5 << 4) -#define AFIO_EXTICR1_EXTI1_PG (0x6 << 4) -#define AFIO_EXTICR1_EXTI0 0xF -#define AFIO_EXTICR1_EXTI0_PA 0x0 -#define AFIO_EXTICR1_EXTI0_PB 0x1 -#define AFIO_EXTICR1_EXTI0_PC 0x2 -#define AFIO_EXTICR1_EXTI0_PD 0x3 -#define AFIO_EXTICR1_EXTI0_PE 0x4 -#define AFIO_EXTICR1_EXTI0_PF 0x5 -#define AFIO_EXTICR1_EXTI0_PG 0x6 - -/* External interrupt configuration register 2 */ - -#define AFIO_EXTICR2_EXTI7 (0xF << 12) -#define AFIO_EXTICR2_EXTI7_PA (0x0 << 12) -#define AFIO_EXTICR2_EXTI7_PB (0x1 << 12) -#define AFIO_EXTICR2_EXTI7_PC (0x2 << 12) -#define AFIO_EXTICR2_EXTI7_PD (0x3 << 12) -#define AFIO_EXTICR2_EXTI7_PE (0x4 << 12) -#define AFIO_EXTICR2_EXTI7_PF (0x5 << 12) -#define AFIO_EXTICR2_EXTI7_PG (0x6 << 12) -#define AFIO_EXTICR2_EXTI6 (0xF << 8) -#define AFIO_EXTICR2_EXTI6_PA (0x0 << 8) -#define AFIO_EXTICR2_EXTI6_PB (0x1 << 8) -#define AFIO_EXTICR2_EXTI6_PC (0x2 << 8) -#define AFIO_EXTICR2_EXTI6_PD (0x3 << 8) -#define AFIO_EXTICR2_EXTI6_PE (0x4 << 8) -#define AFIO_EXTICR2_EXTI6_PF (0x5 << 8) -#define AFIO_EXTICR2_EXTI6_PG (0x6 << 8) -#define AFIO_EXTICR2_EXTI5 (0xF << 4) -#define AFIO_EXTICR2_EXTI5_PA (0x0 << 4) -#define AFIO_EXTICR2_EXTI5_PB (0x1 << 4) -#define AFIO_EXTICR2_EXTI5_PC (0x2 << 4) -#define AFIO_EXTICR2_EXTI5_PD (0x3 << 4) -#define AFIO_EXTICR2_EXTI5_PE (0x4 << 4) -#define AFIO_EXTICR2_EXTI5_PF (0x5 << 4) -#define AFIO_EXTICR2_EXTI5_PG (0x6 << 4) -#define AFIO_EXTICR2_EXTI4 0xF -#define AFIO_EXTICR2_EXTI4_PA 0x0 -#define AFIO_EXTICR2_EXTI4_PB 0x1 -#define AFIO_EXTICR2_EXTI4_PC 0x2 -#define AFIO_EXTICR2_EXTI4_PD 0x3 -#define AFIO_EXTICR2_EXTI4_PE 0x4 -#define AFIO_EXTICR2_EXTI4_PF 0x5 -#define AFIO_EXTICR2_EXTI4_PG 0x6 - -/* AF remap and debug I/O configuration register 2 */ - -#define AFIO_MAPR2_FSMC_NADV BIT(10) -#define AFIO_MAPR2_TIM14_REMAP BIT(9) -#define AFIO_MAPR2_TIM13_REMAP BIT(8) -#define AFIO_MAPR2_TIM11_REMAP BIT(7) -#define AFIO_MAPR2_TIM10_REMAP BIT(6) -#define AFIO_MAPR2_TIM9_REMAP BIT(5) - -/* - * AFIO convenience routines - */ - -void afio_init(void); - -/** - * External interrupt line numbers. - */ -typedef enum afio_exti_num { - AFIO_EXTI_0, /**< External interrupt line 0. */ - AFIO_EXTI_1, /**< External interrupt line 1. */ - AFIO_EXTI_2, /**< External interrupt line 2. */ - AFIO_EXTI_3, /**< External interrupt line 3. */ - AFIO_EXTI_4, /**< External interrupt line 4. */ - AFIO_EXTI_5, /**< External interrupt line 5. */ - AFIO_EXTI_6, /**< External interrupt line 6. */ - AFIO_EXTI_7, /**< External interrupt line 7. */ - AFIO_EXTI_8, /**< External interrupt line 8. */ - AFIO_EXTI_9, /**< External interrupt line 9. */ - AFIO_EXTI_10, /**< External interrupt line 10. */ - AFIO_EXTI_11, /**< External interrupt line 11. */ - AFIO_EXTI_12, /**< External interrupt line 12. */ - AFIO_EXTI_13, /**< External interrupt line 13. */ - AFIO_EXTI_14, /**< External interrupt line 14. */ - AFIO_EXTI_15, /**< External interrupt line 15. */ -} afio_exti_num; - -void afio_exti_select(afio_exti_num exti, afio_exti_port gpio_port); - -/* HACK: Use upper bit to denote MAPR2, Bit 31 is reserved and - * not used in either MAPR or MAPR2 */ -#define AFIO_REMAP_USE_MAPR2 (1 << 31) - -/** - * @brief Available peripheral remaps. - * @see afio_remap() - */ -typedef enum afio_remap_peripheral { - AFIO_REMAP_ADC2_ETRGREG = AFIO_MAPR_ADC2_ETRGREG_REMAP, /**< - ADC 2 external trigger regular conversion remapping */ - AFIO_REMAP_ADC2_ETRGINJ = AFIO_MAPR_ADC2_ETRGINJ_REMAP, /**< - ADC 2 external trigger injected conversion remapping */ - AFIO_REMAP_ADC1_ETRGREG = AFIO_MAPR_ADC1_ETRGREG_REMAP, /**< - ADC 1 external trigger regular conversion remapping */ - AFIO_REMAP_ADC1_ETRGINJ = AFIO_MAPR_ADC1_ETRGINJ_REMAP, /**< - ADC 1 external trigger injected conversion remapping */ - AFIO_REMAP_TIM5CH4_I = AFIO_MAPR_TIM5CH4_IREMAP, /**< - Timer 5 channel 4 internal remapping */ - AFIO_REMAP_PD01 = AFIO_MAPR_PD01_REMAP, /**< - Port D0/Port D1 mapping on OSC_IN/OSC_OUT */ - AFIO_REMAP_CAN_1 = AFIO_MAPR_CAN_REMAP_PB8_PB9, /**< - CAN alternate function remapping 1 (RX on PB8, TX on PB9) */ - AFIO_REMAP_CAN_2 = AFIO_MAPR_CAN_REMAP_PD0_PD1, /**< - CAN alternate function remapping 2 (RX on PD0, TX on PD1) */ - AFIO_REMAP_TIM4 = AFIO_MAPR_TIM4_REMAP, /**< - Timer 4 remapping */ - AFIO_REMAP_TIM3_PARTIAL = AFIO_MAPR_TIM3_REMAP_PARTIAL, /**< - Timer 3 partial remapping */ - AFIO_REMAP_TIM3_FULL = AFIO_MAPR_TIM3_REMAP_FULL, /**< - Timer 3 full remapping */ - AFIO_REMAP_TIM2_PARTIAL_1 = AFIO_MAPR_TIM2_REMAP_PA15_PB3_PA2_PA3, /**< - Timer 2 partial remapping 1 (CH1 and ETR on PA15, CH2 on PB3, CH3 - on PA2, CH4 on PA3) */ - AFIO_REMAP_TIM2_PARTIAL_2 = AFIO_MAPR_TIM2_REMAP_PA0_PA1_PB10_PB11, /**< - Timer 2 partial remapping 2 (CH1 and ETR on PA0, CH2 on PA1, CH3 - on PB10, CH4 on PB11) */ - AFIO_REMAP_TIM2_FULL = AFIO_MAPR_TIM2_REMAP_FULL, /**< - Timer 2 full remapping */ - AFIO_REMAP_USART2 = AFIO_MAPR_USART2_REMAP, /**< - USART 2 remapping */ - AFIO_REMAP_USART1 = AFIO_MAPR_USART1_REMAP, /**< - USART 1 remapping */ - AFIO_REMAP_I2C1 = AFIO_MAPR_I2C1_REMAP, /**< - I2C 1 remapping */ - AFIO_REMAP_SPI1 = AFIO_MAPR_SPI1_REMAP, /**< - SPI 1 remapping */ - AFIO_REMAP_FSMC_NADV = (AFIO_MAPR2_FSMC_NADV | - AFIO_REMAP_USE_MAPR2), /**< - NADV signal not connected */ - AFIO_REMAP_TIM14 = (AFIO_MAPR2_TIM14_REMAP | - AFIO_REMAP_USE_MAPR2), /**< - Timer 14 remapping */ - AFIO_REMAP_TIM13 = (AFIO_MAPR2_TIM13_REMAP | - AFIO_REMAP_USE_MAPR2), /**< - Timer 13 remapping */ - AFIO_REMAP_TIM11 = (AFIO_MAPR2_TIM11_REMAP | - AFIO_REMAP_USE_MAPR2), /**< - Timer 11 remapping */ - AFIO_REMAP_TIM10 = (AFIO_MAPR2_TIM10_REMAP | - AFIO_REMAP_USE_MAPR2), /**< - Timer 10 remapping */ - AFIO_REMAP_TIM9 = (AFIO_MAPR2_TIM9_REMAP | - AFIO_REMAP_USE_MAPR2) /**< - Timer 9 */ -} afio_remap_peripheral; - -void afio_remap(afio_remap_peripheral p); - -/** - * @brief Debug port configuration - * - * Used to configure the behavior of JTAG and Serial Wire (SW) debug - * ports and their associated GPIO pins. - * - * @see afio_cfg_debug_ports() - */ -typedef enum afio_debug_cfg { - AFIO_DEBUG_FULL_SWJ = AFIO_MAPR_SWJ_CFG_FULL_SWJ, /**< - Full Serial Wire and JTAG debug */ - AFIO_DEBUG_FULL_SWJ_NO_NJRST = AFIO_MAPR_SWJ_CFG_FULL_SWJ_NO_NJRST, /**< - Full Serial Wire and JTAG, but no NJTRST. */ - AFIO_DEBUG_SW_ONLY = AFIO_MAPR_SWJ_CFG_NO_JTAG_SW, /**< - Serial Wire debug only (JTAG-DP disabled, - SW-DP enabled) */ - AFIO_DEBUG_NONE = AFIO_MAPR_SWJ_CFG_NO_JTAG_NO_SW /**< - No debug; all JTAG and SW pins are free - for use as GPIOs. */ -} afio_debug_cfg; - -/** - * @brief Enable or disable the JTAG and SW debug ports. - * @param config Desired debug port configuration - * @see afio_debug_cfg - */ -static inline void afio_cfg_debug_ports(afio_debug_cfg config) { - __io uint32 *mapr = &AFIO_BASE->MAPR; - *mapr = (*mapr & ~AFIO_MAPR_SWJ_CFG) | config; -} - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/STM32F4/cores/maple/libmaple/gpioF2.c b/STM32F4/cores/maple/libmaple/gpioF4.c similarity index 75% rename from STM32F4/cores/maple/libmaple/gpioF2.c rename to STM32F4/cores/maple/libmaple/gpioF4.c index b04c7e9..af839eb 100644 --- a/STM32F4/cores/maple/libmaple/gpioF2.c +++ b/STM32F4/cores/maple/libmaple/gpioF4.c @@ -24,8 +24,6 @@ * SOFTWARE. *****************************************************************************/ - #ifdef STM32F2 - /** * @file gpio.c * @brief GPIO initialization routine @@ -38,62 +36,57 @@ * GPIO devices */ -gpio_dev gpioa = { +/** GPIO port A device. */ +const gpio_dev GPIOA = { .regs = GPIOA_BASE, .clk_id = RCC_GPIOA, .exti_port = AFIO_EXTI_PA, }; -/** GPIO port A device. */ -gpio_dev* const GPIOA = &gpioa; -gpio_dev gpiob = { +/** GPIO port B device. */ +const gpio_dev GPIOB = { .regs = GPIOB_BASE, .clk_id = RCC_GPIOB, .exti_port = AFIO_EXTI_PB, }; -/** GPIO port B device. */ -gpio_dev* const GPIOB = &gpiob; -gpio_dev gpioc = { +/** GPIO port C device. */ +const gpio_dev GPIOC = { .regs = GPIOC_BASE, .clk_id = RCC_GPIOC, .exti_port = AFIO_EXTI_PC, }; -/** GPIO port C device. */ -gpio_dev* const GPIOC = &gpioc; -gpio_dev gpiod = { +/** GPIO port D device. */ +const gpio_dev GPIOD = { .regs = GPIOD_BASE, .clk_id = RCC_GPIOD, .exti_port = AFIO_EXTI_PD, }; -/** GPIO port D device. */ -gpio_dev* const GPIOD = &gpiod; #ifdef STM32_HIGH_DENSITY -gpio_dev gpioe = { +/** GPIO port E device. */ +const gpio_dev GPIOE = { .regs = GPIOE_BASE, .clk_id = RCC_GPIOE, .exti_port = AFIO_EXTI_PE, }; -/** GPIO port E device. */ -gpio_dev* const GPIOE = &gpioe; -gpio_dev gpiof = { + #if 0 // not available on LQFP 100 package +/** GPIO port F device. */ +const gpio_dev GPIOF = { .regs = GPIOF_BASE, .clk_id = RCC_GPIOF, .exti_port = AFIO_EXTI_PF, }; -/** GPIO port F device. */ -gpio_dev* const GPIOF = &gpiof; -gpio_dev gpiog = { +/** GPIO port G device. */ +const gpio_dev GPIOG = { .regs = GPIOG_BASE, .clk_id = RCC_GPIOG, .exti_port = AFIO_EXTI_PG, }; -/** GPIO port G device. */ -gpio_dev* const GPIOG = &gpiog; +#endif #endif /* @@ -107,7 +100,7 @@ gpio_dev* const GPIOG = &gpiog; * * @param dev GPIO device to initialize. */ -void gpio_init(gpio_dev *dev) { +void gpio_init(const gpio_dev *dev) { rcc_clk_enable(dev->clk_id); rcc_reset_dev(dev->clk_id); } @@ -116,27 +109,29 @@ void gpio_init(gpio_dev *dev) { * Initialize and reset all available GPIO devices. */ void gpio_init_all(void) { - gpio_init(GPIOA); - gpio_init(GPIOB); - gpio_init(GPIOC); - gpio_init(GPIOD); + gpio_init(&GPIOA); + gpio_init(&GPIOB); + gpio_init(&GPIOC); + gpio_init(&GPIOD); #ifdef STM32_HIGH_DENSITY - gpio_init(GPIOE); - gpio_init(GPIOF); - gpio_init(GPIOG); + gpio_init(&GPIOE); + #if 0 // not available on LQFP 100 package + gpio_init(GPIOF); + gpio_init(GPIOG); + #endif // not available on LQFP 100 package #endif #ifdef ARDUINO_STM32F4_NETDUINO2PLUS // PA8 Output the Master Clock MCO1 - gpio_set_af_mode(GPIOA, 8, 0); - gpio_set_mode(GPIOA, 8, GPIO_MODE_AF | GPIO_OTYPE_PP | GPIO_OSPEED_100MHZ); + gpio_set_af_mode(PA8, 0); + gpio_set_mode(PA8, GPIO_MODE_AF | GPIO_OTYPE_PP | GPIO_OSPEED_100MHZ); // PB4 as alternate MISO Input - gpio_set_af_mode(GPIOB, 4, 5); + gpio_set_af_mode(PB4, 5); // PA5 as alternate SCK Output - gpio_set_af_mode(GPIOA, 5, 5); + gpio_set_af_mode(PA5, 5); // PA7 as alternate MOSI Output - gpio_set_af_mode(GPIOA, 7, 5); + gpio_set_af_mode(PA7, 5); #endif } @@ -148,16 +143,17 @@ void gpio_init_all(void) { * @param mode General purpose or alternate function mode to set the pin to. * @see gpio_pin_mode */ -void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode) { - gpio_reg_map *regs = dev->regs; +void gpio_set_mode(uint8_t io_pin, gpio_pin_mode mode) { + gpio_reg_map *regs = (PIN_MAP[io_pin].gpio_device)->regs; + uint8_t pin = io_pin&0x0f; //regs->AFR[pin/8] = (regs->AFR[pin/8] & ~(15 << (4*(pin&7)))) | (((mode >> 8) & 15) << (4*(pin&7))); //gpio_set_af_mode(dev, pin, mode>>8); - regs->MODER = (regs->MODER & ~( 3 << (2*pin))) | (((mode >> 0) & 3) << (2*pin)); - regs->PUPDR = (regs->PUPDR & ~( 3 << (2*pin))) | (((mode >> 2) & 3) << (2*pin)); - regs->OSPEEDR = (regs->OSPEEDR & ~( 3 << (2*pin))) | (((mode >> 4) & 3) << (2*pin)); - regs->OTYPER = (regs->OTYPER & ~( 1 << (1*pin))) | (((mode >> 6) & 1) << (1*pin)); + regs->MODER = (regs->MODER & ~( 3 << (pin<<1))) | (((mode >> 0) & 3) << (pin<<1)); + regs->PUPDR = (regs->PUPDR & ~( 3 << (pin<<1))) | (((mode >> 2) & 3) << (pin<<1)); + regs->OSPEEDR = (regs->OSPEEDR & ~( 3 << (pin<<1))) | (((mode >> 4) & 3) << (pin<<1)); + regs->OTYPER = (regs->OTYPER & ~( 1 << (pin<<0))) | (((mode >> 6) & 1) << (pin<<0)); } /** @@ -168,10 +164,11 @@ void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode) { * @param mode alternate function mode to set the pin to. * @see gpio_pin_mode */ -void gpio_set_af_mode(gpio_dev *dev, uint8 pin, int mode) { - gpio_reg_map *regs = dev->regs; +void gpio_set_af_mode(uint8_t io_pin, int mode) { + gpio_reg_map *regs = (PIN_MAP[io_pin].gpio_device)->regs; + uint8_t pin = io_pin&0x0F; - regs->AFR[pin/8] = (regs->AFR[pin/8] & ~(15 << (4*(pin&7)))) | (((mode >> 0) & 15) << (4*(pin&7))); + regs->AFR[pin>>3] = (regs->AFR[pin>>3] & ~(15 << ((pin&7)<<2))) | (((mode >> 0) & 15) << ((pin&7)<<2)); } /* @@ -220,5 +217,3 @@ void afio_remap(afio_remap_peripheral remapping) { } } #endif - -#endif diff --git a/STM32F4/cores/maple/libmaple/gpioF2.h b/STM32F4/cores/maple/libmaple/gpio_def.h similarity index 90% rename from STM32F4/cores/maple/libmaple/gpioF2.h rename to STM32F4/cores/maple/libmaple/gpio_def.h index 91bd67b..cd1fb38 100644 --- a/STM32F4/cores/maple/libmaple/gpioF2.h +++ b/STM32F4/cores/maple/libmaple/gpio_def.h @@ -31,8 +31,8 @@ * (AFIO) prototypes, defines, and inlined access functions. */ -#ifndef _GPIO_H_ -#define _GPIO_H_ +#ifndef _GPIO_DEF_H_ +#define _GPIO_DEF_H_ #include "libmaple.h" #include "rcc.h" @@ -74,11 +74,14 @@ typedef enum afio_exti_port { AFIO_EXTI_PD, /**< Use port D (PDx) pin. */ #ifdef STM32_HIGH_DENSITY AFIO_EXTI_PE, /**< Use port E (PEx) pin. */ + #if 0 // not available on LQFP 100 package AFIO_EXTI_PF, /**< Use port F (PFx) pin. */ AFIO_EXTI_PG, /**< Use port G (PGx) pin. */ + #endif // not available on LQFP 100 package #endif } afio_exti_port; + /** GPIO device type */ typedef struct gpio_dev { gpio_reg_map *regs; /**< Register map */ @@ -86,21 +89,18 @@ typedef struct gpio_dev { afio_exti_port exti_port; /**< AFIO external interrupt port value */ } gpio_dev; -extern gpio_dev gpioa; -extern gpio_dev* const GPIOA; -extern gpio_dev gpiob; -extern gpio_dev* const GPIOB; -extern gpio_dev gpioc; -extern gpio_dev* const GPIOC; -extern gpio_dev gpiod; -extern gpio_dev* const GPIOD; +extern const gpio_dev GPIOA; +extern const gpio_dev GPIOB; +extern const gpio_dev GPIOC; +extern const gpio_dev GPIOD; #ifdef STM32_HIGH_DENSITY -extern gpio_dev gpioe; -extern gpio_dev* const GPIOE; +extern const gpio_dev GPIOE; + #if 0 // not available on LQFP 100 package extern gpio_dev gpiof; extern gpio_dev* const GPIOF; extern gpio_dev gpiog; extern gpio_dev* const GPIOG; + #endif // not available on LQFP 100 package #endif /** GPIO port register map base pointer */ @@ -110,8 +110,10 @@ extern gpio_dev* const GPIOG; #define GPIOD_BASE ((struct gpio_reg_map*)0x40020C00) #ifdef STM32_HIGH_DENSITY #define GPIOE_BASE ((struct gpio_reg_map*)0x40021000) + #if 0 // not available on LQFP 100 package #define GPIOF_BASE ((struct gpio_reg_map*)0x40021400) #define GPIOG_BASE ((struct gpio_reg_map*)0x40021800) + #endif // not available on LQFP 100 package #endif /* @@ -190,61 +192,6 @@ typedef enum gpio_pin_mode { GPIO_BIGNUMBER = 0xfff } gpio_pin_mode; -/* - * GPIO Convenience routines - */ - -void gpio_init(gpio_dev *dev); -void gpio_init_all(void); -void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode); -void gpio_set_af_mode(gpio_dev *dev, uint8 pin, int mode); - -/** - * @brief Get a GPIO port's corresponding afio_exti_port. - * @param dev GPIO device whose afio_exti_port to return. - */ -static inline afio_exti_port gpio_exti_port(gpio_dev *dev) { - return dev->exti_port; -} - -/** - * Set or reset a GPIO pin. - * - * Pin must have previously been configured to output mode. - * - * @param dev GPIO device whose pin to set. - * @param pin Pin on to set or reset - * @param val If true, set the pin. If false, reset the pin. - */ -static inline void gpio_write_bit(gpio_dev *dev, uint8 pin, uint8 val) { - if (val) { - dev->regs->BSRRL = BIT(pin); - } else { - dev->regs->BSRRH = BIT(pin); - } -} - -/** - * Determine whether or not a GPIO pin is set. - * - * Pin must have previously been configured to input mode. - * - * @param dev GPIO device whose pin to test. - * @param pin Pin on dev to test. - * @return True if the pin is set, false otherwise. - */ -static inline uint32 gpio_read_bit(gpio_dev *dev, uint8 pin) { - return dev->regs->IDR & BIT(pin); -} - -/** - * Toggle a pin configured as output push-pull. - * @param dev GPIO device. - * @param pin Pin on dev to toggle. - */ -static inline void gpio_toggle_bit(gpio_dev *dev, uint8 pin) { - dev->regs->ODR = dev->regs->ODR ^ BIT(pin); -} /* * AFIO register map @@ -532,15 +479,6 @@ typedef enum afio_debug_cfg { for use as GPIOs. */ } afio_debug_cfg; -/** - * @brief Enable or disable the JTAG and SW debug ports. - * @param config Desired debug port configuration - * @see afio_debug_cfg - */ -static inline void afio_cfg_debug_ports(afio_debug_cfg config) { - //__io uint32 *mapr = &AFIO_BASE->MAPR; - //*mapr = (*mapr & ~AFIO_MAPR_SWJ_CFG) | config; -} #ifdef __cplusplus } diff --git a/STM32F4/cores/maple/libmaple/i2c.c b/STM32F4/cores/maple/libmaple/i2c.c index e3f3199..a582ed0 100644 --- a/STM32F4/cores/maple/libmaple/i2c.c +++ b/STM32F4/cores/maple/libmaple/i2c.c @@ -41,9 +41,9 @@ static i2c_dev i2c_dev1 = { .regs = I2C1_BASE, - .gpio_port = &gpiob, - .sda_pin = 7, - .scl_pin = 6, + //.gpio_port = &gpiob, + .sda_pin = PB7, + .scl_pin = PB6, .clk_id = RCC_I2C1, .ev_nvic_line = NVIC_I2C1_EV, .er_nvic_line = NVIC_I2C1_ER, @@ -54,9 +54,9 @@ i2c_dev* const I2C1 = &i2c_dev1; static i2c_dev i2c_dev2 = { .regs = I2C2_BASE, - .gpio_port = &gpiob, - .sda_pin = 11, - .scl_pin = 10, + //.gpio_port = &gpiob, + .sda_pin = PB11, + .scl_pin = PB10, .clk_id = RCC_I2C2, .ev_nvic_line = NVIC_I2C2_EV, .er_nvic_line = NVIC_I2C2_ER, @@ -336,38 +336,38 @@ void __irq_i2c2_er(void) { */ void i2c_bus_reset(const i2c_dev *dev) { /* Release both lines */ - gpio_write_bit(dev->gpio_port, dev->scl_pin, 1); - gpio_write_bit(dev->gpio_port, dev->sda_pin, 1); - gpio_set_mode(dev->gpio_port, dev->scl_pin, GPIO_OUTPUT_OD); - gpio_set_mode(dev->gpio_port, dev->sda_pin, GPIO_OUTPUT_OD); + gpio_set_pin(dev->scl_pin); + gpio_set_pin(dev->sda_pin); + gpio_set_mode(dev->scl_pin, GPIO_OUTPUT_OD); + gpio_set_mode(dev->sda_pin, GPIO_OUTPUT_OD); /* * Make sure the bus is free by clocking it until any slaves release the * bus. */ - while (!gpio_read_bit(dev->gpio_port, dev->sda_pin)) { + while (!gpio_read_pin(dev->sda_pin)) { /* Wait for any clock stretching to finish */ - while (!gpio_read_bit(dev->gpio_port, dev->scl_pin)) + while (!gpio_read_pin(dev->scl_pin)) ; delay_us(10); /* Pull low */ - gpio_write_bit(dev->gpio_port, dev->scl_pin, 0); + gpio_clear_pin(dev->scl_pin); delay_us(10); /* Release high again */ - gpio_write_bit(dev->gpio_port, dev->scl_pin, 1); + gpio_set_pin(dev->scl_pin); delay_us(10); } /* Generate start then stop condition */ - gpio_write_bit(dev->gpio_port, dev->sda_pin, 0); + gpio_clear_pin(dev->sda_pin); delay_us(10); - gpio_write_bit(dev->gpio_port, dev->scl_pin, 0); + gpio_clear_pin(dev->scl_pin); delay_us(10); - gpio_write_bit(dev->gpio_port, dev->scl_pin, 1); + gpio_set_pin(dev->scl_pin); delay_us(10); - gpio_write_bit(dev->gpio_port, dev->sda_pin, 1); + gpio_set_pin(dev->sda_pin); } /** @@ -413,8 +413,8 @@ void i2c_master_enable(i2c_dev *dev, uint32 flags) { /* Turn on clock and set GPIO modes */ i2c_init(dev); - gpio_set_mode(dev->gpio_port, dev->sda_pin, GPIO_AF_OUTPUT_OD); - gpio_set_mode(dev->gpio_port, dev->scl_pin, GPIO_AF_OUTPUT_OD); + gpio_set_mode(dev->sda_pin, GPIO_AF_OUTPUT_OD); + gpio_set_mode(dev->scl_pin, GPIO_AF_OUTPUT_OD); /* I2C1 and I2C2 are fed from APB1, clocked at 36MHz */ i2c_set_input_clk(dev, I2C_CLK); diff --git a/STM32F4/cores/maple/libmaple/i2c.h b/STM32F4/cores/maple/libmaple/i2c.h index 4c60ad7..28819a3 100644 --- a/STM32F4/cores/maple/libmaple/i2c.h +++ b/STM32F4/cores/maple/libmaple/i2c.h @@ -78,7 +78,7 @@ typedef struct i2c_msg { */ typedef struct i2c_dev { i2c_reg_map *regs; /**< Register map */ - gpio_dev *gpio_port; /**< SDA, SCL pins' GPIO port */ + //gpio_dev *gpio_port; /**< SDA, SCL pins' GPIO port */ uint8 sda_pin; /**< SDA bit on gpio_port */ uint8 scl_pin; /**< SCL bit on gpio_port */ rcc_clk_id clk_id; /**< RCC clock information */ diff --git a/STM32F4/cores/maple/libmaple/libmaple.h b/STM32F4/cores/maple/libmaple/libmaple.h index 10c6c0c..8360ba3 100644 --- a/STM32F4/cores/maple/libmaple/libmaple.h +++ b/STM32F4/cores/maple/libmaple/libmaple.h @@ -32,29 +32,31 @@ #ifndef _LIBMAPLE_H_ #define _LIBMAPLE_H_ -#include "libmaple_types.h" -#include "stm32.h" #include "util.h" -#include "delay.h" /* * Where to put usercode, based on space reserved for bootloader. * * FIXME this has no business being here */ +/* #if defined(MCU_STM32F103VE) || defined(MCU_STM32F205VE) || defined(MCU_STM32F406VG) - /* e.g., Aeroquad32 */ - #define USER_ADDR_ROM 0x08010000 /* ala42 */ + // e.g., Aeroquad32 + #define USER_ADDR_ROM 0x08010000 // ala42 #define USER_ADDR_RAM 0x20000C00 #define STACK_TOP 0x20000800 #elif defined(BOARD_freeflight) +*/ #define USER_ADDR_ROM 0x08000000 -#define USER_ADDR_RAM 0x20000000 +#define USER_ADDR_RAM 0x20000C00 #define STACK_TOP 0x20000800 +/* #else #define USER_ADDR_ROM 0x08005000 #define USER_ADDR_RAM 0x20000C00 #define STACK_TOP 0x20000800 #endif +*/ + #endif diff --git a/STM32F4/cores/maple/libmaple/libmaple_types.h b/STM32F4/cores/maple/libmaple/libmaple_types.h index 332ded1..8e765b4 100644 --- a/STM32F4/cores/maple/libmaple/libmaple_types.h +++ b/STM32F4/cores/maple/libmaple/libmaple_types.h @@ -33,6 +33,8 @@ #ifndef _LIBMAPLE_TYPES_H_ #define _LIBMAPLE_TYPES_H_ +#include + typedef unsigned char uint8; typedef unsigned short uint16; typedef unsigned int uint32; @@ -46,12 +48,15 @@ typedef long long int64; typedef void (*voidFuncPtr)(void); #define __io volatile -#define __attr_flash __attribute__((section (".USER_FLASH"))) - -#define __always_inline inline __attribute__((always_inline)) - +#define __IO volatile +#ifndef __attr_flash + #define __attr_flash __attribute__((section (".USER_FLASH"))) +#endif +#ifndef __always_inline + #define __always_inline inline __attribute__((always_inline)) +#endif #ifndef NULL -#define NULL 0 + #define NULL 0 #endif #endif diff --git a/STM32F4/cores/maple/libmaple/rcc.h b/STM32F4/cores/maple/libmaple/rcc.h index 6317cbd..75e2d3d 100644 --- a/STM32F4/cores/maple/libmaple/rcc.h +++ b/STM32F4/cores/maple/libmaple/rcc.h @@ -29,8 +29,5 @@ * @brief reset and clock control definitions and prototypes */ -#ifdef STM32F2 -#include "rccF2.h" -#else -#include "rccF1.h" -#endif + +#include "rccF4.h" diff --git a/STM32F4/cores/maple/libmaple/rccF1.c b/STM32F4/cores/maple/libmaple/rccF1.c deleted file mode 100644 index 9eb56b8..0000000 --- a/STM32F4/cores/maple/libmaple/rccF1.c +++ /dev/null @@ -1,233 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - - #ifdef STM32F1 - -/** - * @file rcc.c - * @brief Implements pretty much only the basic clock setup on the - * stm32, clock enable/disable and peripheral reset commands. - */ - -#include "libmaple.h" -#include "flash.h" -#include "rcc.h" -#include "bitband.h" - -#define APB1 RCC_APB1 -#define APB2 RCC_APB2 -#define AHB RCC_AHB - -struct rcc_dev_info { - const rcc_clk_domain clk_domain; - const uint8 line_num; -}; - -/* Device descriptor table, maps rcc_clk_id onto bus and enable/reset - * register bit numbers. */ -static const struct rcc_dev_info rcc_dev_table[] = { - [RCC_GPIOA] = { .clk_domain = APB2, .line_num = 2 }, - [RCC_GPIOB] = { .clk_domain = APB2, .line_num = 3 }, - [RCC_GPIOC] = { .clk_domain = APB2, .line_num = 4 }, - [RCC_GPIOD] = { .clk_domain = APB2, .line_num = 5 }, - [RCC_AFIO] = { .clk_domain = APB2, .line_num = 0 }, - [RCC_ADC1] = { .clk_domain = APB2, .line_num = 9 }, - [RCC_ADC2] = { .clk_domain = APB2, .line_num = 10 }, - [RCC_ADC3] = { .clk_domain = APB2, .line_num = 15 }, - [RCC_USART1] = { .clk_domain = APB2, .line_num = 14 }, - [RCC_USART2] = { .clk_domain = APB1, .line_num = 17 }, - [RCC_USART3] = { .clk_domain = APB1, .line_num = 18 }, - [RCC_TIMER1] = { .clk_domain = APB2, .line_num = 11 }, - [RCC_TIMER2] = { .clk_domain = APB1, .line_num = 0 }, - [RCC_TIMER3] = { .clk_domain = APB1, .line_num = 1 }, - [RCC_TIMER4] = { .clk_domain = APB1, .line_num = 2 }, - [RCC_SPI1] = { .clk_domain = APB2, .line_num = 12 }, - [RCC_SPI2] = { .clk_domain = APB1, .line_num = 14 }, - [RCC_DMA1] = { .clk_domain = AHB, .line_num = 0 }, - [RCC_PWR] = { .clk_domain = APB1, .line_num = 28}, - [RCC_BKP] = { .clk_domain = APB1, .line_num = 27}, - [RCC_I2C1] = { .clk_domain = APB1, .line_num = 21 }, - [RCC_I2C2] = { .clk_domain = APB1, .line_num = 22 }, - [RCC_CRC] = { .clk_domain = AHB, .line_num = 6}, - [RCC_FLITF] = { .clk_domain = AHB, .line_num = 4}, - [RCC_SRAM] = { .clk_domain = AHB, .line_num = 2}, -#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) - [RCC_GPIOE] = { .clk_domain = APB2, .line_num = 6 }, - [RCC_GPIOF] = { .clk_domain = APB2, .line_num = 7 }, - [RCC_GPIOG] = { .clk_domain = APB2, .line_num = 8 }, - [RCC_UART4] = { .clk_domain = APB1, .line_num = 19 }, - [RCC_UART5] = { .clk_domain = APB1, .line_num = 20 }, - [RCC_TIMER5] = { .clk_domain = APB1, .line_num = 3 }, - [RCC_TIMER6] = { .clk_domain = APB1, .line_num = 4 }, - [RCC_TIMER7] = { .clk_domain = APB1, .line_num = 5 }, - [RCC_TIMER8] = { .clk_domain = APB2, .line_num = 13 }, - [RCC_FSMC] = { .clk_domain = AHB, .line_num = 8 }, - [RCC_DAC] = { .clk_domain = APB1, .line_num = 29 }, - [RCC_DMA2] = { .clk_domain = AHB, .line_num = 1 }, - [RCC_SDIO] = { .clk_domain = AHB, .line_num = 10 }, - [RCC_SPI3] = { .clk_domain = APB1, .line_num = 15 }, -#endif -#ifdef STM32_XL_DENSITY - [RCC_TIMER9] = { .clk_domain = APB2, .line_num = 19 }, - [RCC_TIMER10] = { .clk_domain = APB2, .line_num = 20 }, - [RCC_TIMER11] = { .clk_domain = APB2, .line_num = 21 }, - [RCC_TIMER12] = { .clk_domain = APB1, .line_num = 6 }, - [RCC_TIMER13] = { .clk_domain = APB1, .line_num = 7 }, - [RCC_TIMER14] = { .clk_domain = APB1, .line_num = 8 }, -#endif -}; - -/** - * @brief Initialize the clock control system. Initializes the system - * clock source to use the PLL driven by an external oscillator - * @param sysclk_src system clock source, must be PLL - * @param pll_src pll clock source, must be HSE - * @param pll_mul pll multiplier - */ -void rcc_clk_init(rcc_sysclk_src sysclk_src, - rcc_pllsrc pll_src, - rcc_pll_multiplier pll_mul) { - uint32 cfgr = 0; - uint32 cr; - - /* Assume that we're going to clock the chip off the PLL, fed by - * the HSE */ - ASSERT(sysclk_src == RCC_CLKSRC_PLL && - pll_src == RCC_PLLSRC_HSE); - - RCC_BASE->CFGR = pll_src | pll_mul; - - /* Turn on the HSE */ - cr = RCC_BASE->CR; - cr |= RCC_CR_HSEON; - RCC_BASE->CR = cr; - while (!(RCC_BASE->CR & RCC_CR_HSERDY)) - ; - - /* Now the PLL */ - cr |= RCC_CR_PLLON; - RCC_BASE->CR = cr; - while (!(RCC_BASE->CR & RCC_CR_PLLRDY)) - ; - - /* Finally, let's switch over to the PLL */ - cfgr &= ~RCC_CFGR_SW; - cfgr |= RCC_CFGR_SW_PLL; - RCC_BASE->CFGR = cfgr; - while ((RCC_BASE->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) - ; -} - -/** - * @brief Turn on the clock line on a peripheral - * @param id Clock ID of the peripheral to turn on. - */ -void rcc_clk_enable(rcc_clk_id id) { - static const __io uint32* enable_regs[] = { - [APB1] = &RCC_BASE->APB1ENR, - [APB2] = &RCC_BASE->APB2ENR, - [AHB] = &RCC_BASE->AHBENR, - }; - - rcc_clk_domain clk_domain = rcc_dev_clk(id); - __io uint32* enr = (__io uint32*)enable_regs[clk_domain]; - uint8 lnum = rcc_dev_table[id].line_num; - - bb_peri_set_bit(enr, lnum, 1); -} - -/** - * @brief Reset a peripheral. - * @param id Clock ID of the peripheral to reset. - */ -void rcc_reset_dev(rcc_clk_id id) { - static const __io uint32* reset_regs[] = { - [APB1] = &RCC_BASE->APB1RSTR, - [APB2] = &RCC_BASE->APB2RSTR, - }; - - rcc_clk_domain clk_domain = rcc_dev_clk(id); - __io void* addr = (__io void*)reset_regs[clk_domain]; - uint8 lnum = rcc_dev_table[id].line_num; - - bb_peri_set_bit(addr, lnum, 1); - bb_peri_set_bit(addr, lnum, 0); -} - -/** - * @brief Get a peripheral's clock domain - * @param id Clock ID of the peripheral whose clock domain to return - * @return Clock source for the given clock ID - */ -rcc_clk_domain rcc_dev_clk(rcc_clk_id id) { - return rcc_dev_table[id].clk_domain; -} - -/** - * @brief Get a peripheral's clock domain speed - * @param id Clock ID of the peripheral whose clock domain speed to return - * @return Clock speed for the given clock ID - */ -uint32 rcc_dev_clk_speed(rcc_clk_id id) { - static const uint32 rcc_dev_clk_speed_table[] = { - [RCC_AHB] = 72000000, - [RCC_APB1] = 36000000, - [RCC_APB2] = 72000000 - }; - return rcc_dev_clk_speed_table[rcc_dev_clk(id)]; -} - -/** - * @brief Get a peripheral's timer clock domain speed - * @param id Clock ID of the peripheral whose clock domain speed to return - * @return Clock speed for the given clock ID - */ -uint32 rcc_dev_timer_clk_speed(rcc_clk_id id) { - return rcc_dev_clk_speed(RCC_APB2); // 72 MHz for all counter -} - -/** - * @brief Set the divider on a peripheral prescaler - * @param prescaler prescaler to set - * @param divider prescaler divider - */ -void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider) { - static const uint32 masks[] = { - [RCC_PRESCALER_AHB] = RCC_CFGR_HPRE, - [RCC_PRESCALER_APB1] = RCC_CFGR_PPRE1, - [RCC_PRESCALER_APB2] = RCC_CFGR_PPRE2, - [RCC_PRESCALER_USB] = RCC_CFGR_USBPRE, - [RCC_PRESCALER_ADC] = RCC_CFGR_ADCPRE, - }; - - uint32 cfgr = RCC_BASE->CFGR; - cfgr &= ~masks[prescaler]; - cfgr |= divider; - RCC_BASE->CFGR = cfgr; -} - - -#endif diff --git a/STM32F4/cores/maple/libmaple/rccF1.h b/STM32F4/cores/maple/libmaple/rccF1.h deleted file mode 100644 index dd79704..0000000 --- a/STM32F4/cores/maple/libmaple/rccF1.h +++ /dev/null @@ -1,572 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file rcc.h - * @brief reset and clock control definitions and prototypes - */ - -#include "libmaple_types.h" - -#ifndef _RCC_H_ -#define _RCC_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -/** RCC register map type */ -typedef struct rcc_reg_map { - __io uint32 CR; /**< Clock control register */ - __io uint32 CFGR; /**< Clock configuration register */ - __io uint32 CIR; /**< Clock interrupt register */ - __io uint32 APB2RSTR; /**< APB2 peripheral reset register */ - __io uint32 APB1RSTR; /**< APB1 peripheral reset register */ - __io uint32 AHBENR; /**< AHB peripheral clock enable register */ - __io uint32 APB2ENR; /**< APB2 peripheral clock enable register */ - __io uint32 APB1ENR; /**< APB1 peripheral clock enable register */ - __io uint32 BDCR; /**< Backup domain control register */ - __io uint32 CSR; /**< Control/status register */ -} rcc_reg_map; - -/** RCC register map base pointer */ -#define RCC_BASE ((struct rcc_reg_map*)0x40021000) - -/* - * Register bit definitions - */ - -/* Clock control register */ - -#define RCC_CR_PLLRDY_BIT 25 -#define RCC_CR_PLLON_BIT 24 -#define RCC_CR_CSSON_BIT 19 -#define RCC_CR_HSEBYP_BIT 18 -#define RCC_CR_HSERDY_BIT 17 -#define RCC_CR_HSEON_BIT 16 -#define RCC_CR_HSIRDY_BIT 1 -#define RCC_CR_HSION_BIT 0 - -#define RCC_CR_PLLRDY BIT(RCC_CR_PLLRDY_BIT) -#define RCC_CR_PLLON BIT(RCC_CR_PLLON_BIT) -#define RCC_CR_CSSON BIT(RCC_CR_CSSON_BIT) -#define RCC_CR_HSEBYP BIT(RCC_CR_HSEBYP_BIT) -#define RCC_CR_HSERDY BIT(RCC_CR_HSERDY_BIT) -#define RCC_CR_HSEON BIT(RCC_CR_HSEON_BIT) -#define RCC_CR_HSICAL (0xFF << 8) -#define RCC_CR_HSITRIM (0x1F << 3) -#define RCC_CR_HSIRDY BIT(RCC_CR_HSIRDY_BIT) -#define RCC_CR_HSION BIT(RCC_CR_HSION_BIT) - -/* Clock configuration register */ - -#define RCC_CFGR_USBPRE_BIT 22 -#define RCC_CFGR_PLLXTPRE_BIT 17 -#define RCC_CFGR_PLLSRC_BIT 16 - -#define RCC_CFGR_MCO (0x3 << 24) -#define RCC_CFGR_USBPRE BIT(RCC_CFGR_USBPRE_BIT) -#define RCC_CFGR_PLLMUL (0xF << 18) -#define RCC_CFGR_PLLXTPRE BIT(RCC_CFGR_PLLXTPRE_BIT) -#define RCC_CFGR_PLLSRC BIT(RCC_CFGR_PLLSRC_BIT) -#define RCC_CFGR_ADCPRE (0x3 << 14) -#define RCC_CFGR_PPRE2 (0x7 << 11) -#define RCC_CFGR_PPRE1 (0x7 << 8) -#define RCC_CFGR_HPRE (0xF << 4) -#define RCC_CFGR_SWS (0x3 << 2) -#define RCC_CFGR_SWS_PLL (0x2 << 2) -#define RCC_CFGR_SWS_HSE (0x1 << 2) -#define RCC_CFGR_SW 0x3 -#define RCC_CFGR_SW_PLL 0x2 -#define RCC_CFGR_SW_HSE 0x1 - -/* Clock interrupt register */ - -#define RCC_CIR_CSSC_BIT 23 -#define RCC_CIR_PLLRDYC_BIT 20 -#define RCC_CIR_HSERDYC_BIT 19 -#define RCC_CIR_HSIRDYC_BIT 18 -#define RCC_CIR_LSERDYC_BIT 17 -#define RCC_CIR_LSIRDYC_BIT 16 -#define RCC_CIR_PLLRDYIE_BIT 12 -#define RCC_CIR_HSERDYIE_BIT 11 -#define RCC_CIR_HSIRDYIE_BIT 10 -#define RCC_CIR_LSERDYIE_BIT 9 -#define RCC_CIR_LSIRDYIE_BIT 8 -#define RCC_CIR_CSSF_BIT 7 -#define RCC_CIR_PLLRDYF_BIT 4 -#define RCC_CIR_HSERDYF_BIT 3 -#define RCC_CIR_HSIRDYF_BIT 2 -#define RCC_CIR_LSERDYF_BIT 1 -#define RCC_CIR_LSIRDYF_BIT 0 - -#define RCC_CIR_CSSC BIT(RCC_CIR_CSSC_BIT) -#define RCC_CIR_PLLRDYC BIT(RCC_CIR_PLLRDYC_BIT) -#define RCC_CIR_HSERDYC BIT(RCC_CIR_HSERDYC_BIT) -#define RCC_CIR_HSIRDYC BIT(RCC_CIR_HSIRDYC_BIT) -#define RCC_CIR_LSERDYC BIT(RCC_CIR_LSERDYC_BIT) -#define RCC_CIR_LSIRDYC BIT(RCC_CIR_LSIRDYC_BIT) -#define RCC_CIR_PLLRDYIE BIT(RCC_CIR_PLLRDYIE_BIT) -#define RCC_CIR_HSERDYIE BIT(RCC_CIR_HSERDYIE_BIT) -#define RCC_CIR_HSIRDYIE BIT(RCC_CIR_HSIRDYIE_BIT) -#define RCC_CIR_LSERDYIE BIT(RCC_CIR_LSERDYIE_BIT) -#define RCC_CIR_LSIRDYIE BIT(RCC_CIR_LSIRDYIE_BIT) -#define RCC_CIR_CSSF BIT(RCC_CIR_CSSF_BIT) -#define RCC_CIR_PLLRDYF BIT(RCC_CIR_PLLRDYF_BIT) -#define RCC_CIR_HSERDYF BIT(RCC_CIR_HSERDYF_BIT) -#define RCC_CIR_HSIRDYF BIT(RCC_CIR_HSIRDYF_BIT) -#define RCC_CIR_LSERDYF BIT(RCC_CIR_LSERDYF_BIT) -#define RCC_CIR_LSIRDYF BIT(RCC_CIR_LSIRDYF_BIT) - -/* APB2 peripheral reset register */ - -#define RCC_APB2RSTR_TIM11RST_BIT 21 -#define RCC_APB2RSTR_TIM10RST_BIT 20 -#define RCC_APB2RSTR_TIM9RST_BIT 19 -#define RCC_APB2RSTR_ADC3RST_BIT 15 -#define RCC_APB2RSTR_USART1RST_BIT 14 -#define RCC_APB2RSTR_TIM8RST_BIT 13 -#define RCC_APB2RSTR_SPI1RST_BIT 12 -#define RCC_APB2RSTR_TIM1RST_BIT 11 -#define RCC_APB2RSTR_ADC2RST_BIT 10 -#define RCC_APB2RSTR_ADC1RST_BIT 9 -#define RCC_APB2RSTR_IOPGRST_BIT 8 -#define RCC_APB2RSTR_IOPFRST_BIT 7 -#define RCC_APB2RSTR_IOPERST_BIT 6 -#define RCC_APB2RSTR_IOPDRST_BIT 5 -#define RCC_APB2RSTR_IOPCRST_BIT 4 -#define RCC_APB2RSTR_IOPBRST_BIT 3 -#define RCC_APB2RSTR_IOPARST_BIT 2 -#define RCC_APB2RSTR_AFIORST_BIT 0 - -#define RCC_APB2RSTR_TIM11RST BIT(RCC_APB2RSTR_TIM11RST_BIT) -#define RCC_APB2RSTR_TIM10RST BIT(RCC_APB2RSTR_TIM10RST_BIT) -#define RCC_APB2RSTR_TIM9RST BIT(RCC_APB2RSTR_TIM9RST_BIT) -#define RCC_APB2RSTR_ADC3RST BIT(RCC_APB2RSTR_ADC3RST_BIT) -#define RCC_APB2RSTR_USART1RST BIT(RCC_APB2RSTR_USART1RST_BIT) -#define RCC_APB2RSTR_TIM8RST BIT(RCC_APB2RSTR_TIM8RST_BIT) -#define RCC_APB2RSTR_SPI1RST BIT(RCC_APB2RSTR_SPI1RST_BIT) -#define RCC_APB2RSTR_TIM1RST BIT(RCC_APB2RSTR_TIM1RST_BIT) -#define RCC_APB2RSTR_ADC2RST BIT(RCC_APB2RSTR_ADC2RST_BIT) -#define RCC_APB2RSTR_ADC1RST BIT(RCC_APB2RSTR_ADC1RST_BIT) -#define RCC_APB2RSTR_IOPGRST BIT(RCC_APB2RSTR_IOPGRST_BIT) -#define RCC_APB2RSTR_IOPFRST BIT(RCC_APB2RSTR_IOPFRST_BIT) -#define RCC_APB2RSTR_IOPERST BIT(RCC_APB2RSTR_IOPERST_BIT) -#define RCC_APB2RSTR_IOPDRST BIT(RCC_APB2RSTR_IOPDRST_BIT) -#define RCC_APB2RSTR_IOPCRST BIT(RCC_APB2RSTR_IOPCRST_BIT) -#define RCC_APB2RSTR_IOPBRST BIT(RCC_APB2RSTR_IOPBRST_BIT) -#define RCC_APB2RSTR_IOPARST BIT(RCC_APB2RSTR_IOPARST_BIT) -#define RCC_APB2RSTR_AFIORST BIT(RCC_APB2RSTR_AFIORST_BIT) - -/* APB1 peripheral reset register */ - -#define RCC_APB1RSTR_DACRST_BIT 29 -#define RCC_APB1RSTR_PWRRST_BIT 28 -#define RCC_APB1RSTR_BKPRST_BIT 27 -#define RCC_APB1RSTR_CANRST_BIT 25 -#define RCC_APB1RSTR_USBRST_BIT 23 -#define RCC_APB1RSTR_I2C2RST_BIT 22 -#define RCC_APB1RSTR_I2C1RST_BIT 21 -#define RCC_APB1RSTR_UART5RST_BIT 20 -#define RCC_APB1RSTR_UART4RST_BIT 19 -#define RCC_APB1RSTR_USART3RST_BIT 18 -#define RCC_APB1RSTR_USART2RST_BIT 17 -#define RCC_APB1RSTR_SPI3RST_BIT 15 -#define RCC_APB1RSTR_SPI2RST_BIT 14 -#define RCC_APB1RSTR_WWDRST_BIT 11 -#define RCC_APB1RSTR_TIM14RST_BIT 8 -#define RCC_APB1RSTR_TIM13RST_BIT 7 -#define RCC_APB1RSTR_TIM12RST_BIT 6 -#define RCC_APB1RSTR_TIM7RST_BIT 5 -#define RCC_APB1RSTR_TIM6RST_BIT 4 -#define RCC_APB1RSTR_TIM5RST_BIT 3 -#define RCC_APB1RSTR_TIM4RST_BIT 2 -#define RCC_APB1RSTR_TIM3RST_BIT 1 -#define RCC_APB1RSTR_TIM2RST_BIT 0 - -#define RCC_APB1RSTR_DACRST BIT(RCC_APB1RSTR_DACRST_BIT) -#define RCC_APB1RSTR_PWRRST BIT(RCC_APB1RSTR_PWRRST_BIT) -#define RCC_APB1RSTR_BKPRST BIT(RCC_APB1RSTR_BKPRST_BIT) -#define RCC_APB1RSTR_CANRST BIT(RCC_APB1RSTR_CANRST_BIT) -#define RCC_APB1RSTR_USBRST BIT(RCC_APB1RSTR_USBRST_BIT) -#define RCC_APB1RSTR_I2C2RST BIT(RCC_APB1RSTR_I2C2RST_BIT) -#define RCC_APB1RSTR_I2C1RST BIT(RCC_APB1RSTR_I2C1RST_BIT) -#define RCC_APB1RSTR_UART5RST BIT(RCC_APB1RSTR_UART5RST_BIT) -#define RCC_APB1RSTR_UART4RST BIT(RCC_APB1RSTR_UART4RST_BIT) -#define RCC_APB1RSTR_USART3RST BIT(RCC_APB1RSTR_USART3RST_BIT) -#define RCC_APB1RSTR_USART2RST BIT(RCC_APB1RSTR_USART2RST_BIT) -#define RCC_APB1RSTR_SPI3RST BIT(RCC_APB1RSTR_SPI3RST_BIT) -#define RCC_APB1RSTR_SPI2RST BIT(RCC_APB1RSTR_SPI2RST_BIT) -#define RCC_APB1RSTR_WWDRST BIT(RCC_APB1RSTR_WWDRST_BIT) -#define RCC_APB1RSTR_TIM14RST BIT(RCC_APB1RSTR_TIM14RST_BIT) -#define RCC_APB1RSTR_TIM13RST BIT(RCC_APB1RSTR_TIM13RST_BIT) -#define RCC_APB1RSTR_TIM12RST BIT(RCC_APB1RSTR_TIM12RST_BIT) -#define RCC_APB1RSTR_TIM7RST BIT(RCC_APB1RSTR_TIM7RST_BIT) -#define RCC_APB1RSTR_TIM6RST BIT(RCC_APB1RSTR_TIM6RST_BIT) -#define RCC_APB1RSTR_TIM5RST BIT(RCC_APB1RSTR_TIM5RST_BIT) -#define RCC_APB1RSTR_TIM4RST BIT(RCC_APB1RSTR_TIM4RST_BIT) -#define RCC_APB1RSTR_TIM3RST BIT(RCC_APB1RSTR_TIM3RST_BIT) -#define RCC_APB1RSTR_TIM2RST BIT(RCC_APB1RSTR_TIM2RST_BIT) - -/* AHB peripheral clock enable register */ - -#define RCC_AHBENR_SDIOEN_BIT 10 -#define RCC_AHBENR_FSMCEN_BIT 8 -#define RCC_AHBENR_CRCEN_BIT 7 -#define RCC_AHBENR_FLITFEN_BIT 4 -#define RCC_AHBENR_SRAMEN_BIT 2 -#define RCC_AHBENR_DMA2EN_BIT 1 -#define RCC_AHBENR_DMA1EN_BIT 0 - -#define RCC_AHBENR_SDIOEN BIT(RCC_AHBENR_SDIOEN_BIT) -#define RCC_AHBENR_FSMCEN BIT(RCC_AHBENR_FSMCEN_BIT) -#define RCC_AHBENR_CRCEN BIT(RCC_AHBENR_CRCEN_BIT) -#define RCC_AHBENR_FLITFEN BIT(RCC_AHBENR_FLITFEN_BIT) -#define RCC_AHBENR_SRAMEN BIT(RCC_AHBENR_SRAMEN_BIT) -#define RCC_AHBENR_DMA2EN BIT(RCC_AHBENR_DMA2EN_BIT) -#define RCC_AHBENR_DMA1EN BIT(RCC_AHBENR_DMA1EN_BIT) - -/* APB2 peripheral clock enable register */ - -#define RCC_APB2ENR_TIM11EN_BIT 21 -#define RCC_APB2ENR_TIM10EN_BIT 20 -#define RCC_APB2ENR_TIM9EN_BIT 19 -#define RCC_APB2ENR_ADC3EN_BIT 15 -#define RCC_APB2ENR_USART1EN_BIT 14 -#define RCC_APB2ENR_TIM8EN_BIT 13 -#define RCC_APB2ENR_SPI1EN_BIT 12 -#define RCC_APB2ENR_TIM1EN_BIT 11 -#define RCC_APB2ENR_ADC2EN_BIT 10 -#define RCC_APB2ENR_ADC1EN_BIT 9 -#define RCC_APB2ENR_IOPGEN_BIT 8 -#define RCC_APB2ENR_IOPFEN_BIT 7 -#define RCC_APB2ENR_IOPEEN_BIT 6 -#define RCC_APB2ENR_IOPDEN_BIT 5 -#define RCC_APB2ENR_IOPCEN_BIT 4 -#define RCC_APB2ENR_IOPBEN_BIT 3 -#define RCC_APB2ENR_IOPAEN_BIT 2 -#define RCC_APB2ENR_AFIOEN_BIT 0 - -#define RCC_APB2ENR_TIM11EN BIT(RCC_APB2ENR_TIM11EN_BIT) -#define RCC_APB2ENR_TIM10EN BIT(RCC_APB2ENR_TIM10EN_BIT) -#define RCC_APB2ENR_TIM9EN BIT(RCC_APB2ENR_TIM9EN_BIT) -#define RCC_APB2ENR_ADC3EN BIT(RCC_APB2ENR_ADC3EN_BIT) -#define RCC_APB2ENR_USART1EN BIT(RCC_APB2ENR_USART1EN_BIT) -#define RCC_APB2ENR_TIM8EN BIT(RCC_APB2ENR_TIM8EN_BIT) -#define RCC_APB2ENR_SPI1EN BIT(RCC_APB2ENR_SPI1EN_BIT) -#define RCC_APB2ENR_TIM1EN BIT(RCC_APB2ENR_TIM1EN_BIT) -#define RCC_APB2ENR_ADC2EN BIT(RCC_APB2ENR_ADC2EN_BIT) -#define RCC_APB2ENR_ADC1EN BIT(RCC_APB2ENR_ADC1EN_BIT) -#define RCC_APB2ENR_IOPGEN BIT(RCC_APB2ENR_IOPGEN_BIT) -#define RCC_APB2ENR_IOPFEN BIT(RCC_APB2ENR_IOPFEN_BIT) -#define RCC_APB2ENR_IOPEEN BIT(RCC_APB2ENR_IOPEEN_BIT) -#define RCC_APB2ENR_IOPDEN BIT(RCC_APB2ENR_IOPDEN_BIT) -#define RCC_APB2ENR_IOPCEN BIT(RCC_APB2ENR_IOPCEN_BIT) -#define RCC_APB2ENR_IOPBEN BIT(RCC_APB2ENR_IOPBEN_BIT) -#define RCC_APB2ENR_IOPAEN BIT(RCC_APB2ENR_IOPAEN_BIT) -#define RCC_APB2ENR_AFIOEN BIT(RCC_APB2ENR_AFIOEN_BIT) - -/* APB1 peripheral clock enable register */ - -#define RCC_APB1ENR_DACEN_BIT 29 -#define RCC_APB1ENR_PWREN_BIT 28 -#define RCC_APB1ENR_BKPEN_BIT 27 -#define RCC_APB1ENR_CANEN_BIT 25 -#define RCC_APB1ENR_USBEN_BIT 23 -#define RCC_APB1ENR_I2C2EN_BIT 22 -#define RCC_APB1ENR_I2C1EN_BIT 21 -#define RCC_APB1ENR_UART5EN_BIT 20 -#define RCC_APB1ENR_UART4EN_BIT 19 -#define RCC_APB1ENR_USART3EN_BIT 18 -#define RCC_APB1ENR_USART2EN_BIT 17 -#define RCC_APB1ENR_SPI3EN_BIT 15 -#define RCC_APB1ENR_SPI2EN_BIT 14 -#define RCC_APB1ENR_WWDEN_BIT 11 -#define RCC_APB1ENR_TIM14EN_BIT 8 -#define RCC_APB1ENR_TIM13EN_BIT 7 -#define RCC_APB1ENR_TIM12EN_BIT 6 -#define RCC_APB1ENR_TIM7EN_BIT 5 -#define RCC_APB1ENR_TIM6EN_BIT 4 -#define RCC_APB1ENR_TIM5EN_BIT 3 -#define RCC_APB1ENR_TIM4EN_BIT 2 -#define RCC_APB1ENR_TIM3EN_BIT 1 -#define RCC_APB1ENR_TIM2EN_BIT 0 - -#define RCC_APB1ENR_DACEN BIT(RCC_APB1ENR_DACEN_BIT) -#define RCC_APB1ENR_PWREN BIT(RCC_APB1ENR_PWREN_BIT) -#define RCC_APB1ENR_BKPEN BIT(RCC_APB1ENR_BKPEN_BIT) -#define RCC_APB1ENR_CANEN BIT(RCC_APB1ENR_CANEN_BIT) -#define RCC_APB1ENR_USBEN BIT(RCC_APB1ENR_USBEN_BIT) -#define RCC_APB1ENR_I2C2EN BIT(RCC_APB1ENR_I2C2EN_BIT) -#define RCC_APB1ENR_I2C1EN BIT(RCC_APB1ENR_I2C1EN_BIT) -#define RCC_APB1ENR_UART5EN BIT(RCC_APB1ENR_UART5EN_BIT) -#define RCC_APB1ENR_UART4EN BIT(RCC_APB1ENR_UART4EN_BIT) -#define RCC_APB1ENR_USART3EN BIT(RCC_APB1ENR_USART3EN_BIT) -#define RCC_APB1ENR_USART2EN BIT(RCC_APB1ENR_USART2EN_BIT) -#define RCC_APB1ENR_SPI3EN BIT(RCC_APB1ENR_SPI3EN_BIT) -#define RCC_APB1ENR_SPI2EN BIT(RCC_APB1ENR_SPI2EN_BIT) -#define RCC_APB1ENR_WWDEN BIT(RCC_APB1ENR_WWDEN_BIT) -#define RCC_APB1ENR_TIM14EN BIT(RCC_APB1ENR_TIM14EN_BIT) -#define RCC_APB1ENR_TIM13EN BIT(RCC_APB1ENR_TIM13EN_BIT) -#define RCC_APB1ENR_TIM12EN BIT(RCC_APB1ENR_TIM12EN_BIT) -#define RCC_APB1ENR_TIM7EN BIT(RCC_APB1ENR_TIM7EN_BIT) -#define RCC_APB1ENR_TIM6EN BIT(RCC_APB1ENR_TIM6EN_BIT) -#define RCC_APB1ENR_TIM5EN BIT(RCC_APB1ENR_TIM5EN_BIT) -#define RCC_APB1ENR_TIM4EN BIT(RCC_APB1ENR_TIM4EN_BIT) -#define RCC_APB1ENR_TIM3EN BIT(RCC_APB1ENR_TIM3EN_BIT) -#define RCC_APB1ENR_TIM2EN BIT(RCC_APB1ENR_TIM2EN_BIT) - -/* Backup domain control register */ - -#define RCC_BDCR_BDRST_BIT 16 -#define RCC_BDCR_RTCEN_BIT 15 -#define RCC_BDCR_LSEBYP_BIT 2 -#define RCC_BDCR_LSERDY_BIT 1 -#define RCC_BDCR_LSEON_BIT 0 - -#define RCC_BDCR_BDRST BIT(RCC_BDCR_BDRST_BIT) -#define RCC_BDCR_RTCEN BIT(RCC_BDCR_RTC_BIT) -#define RCC_BDCR_RTCSEL (0x3 << 8) -#define RCC_BDCR_RTCSEL_NONE (0x0 << 8) -#define RCC_BDCR_RTCSEL_LSE (0x1 << 8) -#define RCC_BDCR_RTCSEL_HSE (0x3 << 8) -#define RCC_BDCR_LSEBYP BIT(RCC_BDCR_LSEBYP_BIT) -#define RCC_BDCR_LSERDY BIT(RCC_BDCR_LSERDY_BIT) -#define RCC_BDCR_LSEON BIT(RCC_BDCR_LSEON_BIT) - -/* Control/status register */ - -#define RCC_CSR_LPWRRSTF_BIT 31 -#define RCC_CSR_WWDGRSTF_BIT 30 -#define RCC_CSR_IWDGRSTF_BIT 29 -#define RCC_CSR_SFTRSTF_BIT 28 -#define RCC_CSR_PORRSTF_BIT 27 -#define RCC_CSR_PINRSTF_BIT 26 -#define RCC_CSR_RMVF_BIT 24 -#define RCC_CSR_LSIRDY_BIT 1 -#define RCC_CSR_LSION_BIT 0 - -#define RCC_CSR_LPWRRSTF BIT(RCC_CSR_LPWRRSTF_BIT) -#define RCC_CSR_WWDGRSTF BIT(RCC_CSR_WWDGRSTF_BIT) -#define RCC_CSR_IWDGRSTF BIT(RCC_CSR_IWDGRSTF_BIT) -#define RCC_CSR_SFTRSTF BIT(RCC_CSR_SFTRSTF_BIT) -#define RCC_CSR_PORRSTF BIT(RCC_CSR_PORRSTF_BIT) -#define RCC_CSR_PINRSTF BIT(RCC_CSR_PINRSTF_BIT) -#define RCC_CSR_RMVF BIT(RCC_CSR_RMVF_BIT) -#define RCC_CSR_LSIRDY BIT(RCC_CSR_LSIRDY_BIT) -#define RCC_CSR_LSION BIT(RCC_CSR_LSION_BIT) - -/* - * Convenience routines - */ - -/** - * SYSCLK sources - * @see rcc_clk_init() - */ -typedef enum rcc_sysclk_src { - RCC_CLKSRC_HSI = 0x0, - RCC_CLKSRC_HSE = 0x1, - RCC_CLKSRC_PLL = 0x2, -} rcc_sysclk_src; - -/** - * PLL entry clock source - * @see rcc_clk_init() - */ -typedef enum rcc_pllsrc { - RCC_PLLSRC_HSE = (0x1 << 16), - RCC_PLLSRC_HSI_DIV_2 = (0x0 << 16) -} rcc_pllsrc; - -/** - * PLL multipliers - * @see rcc_clk_init() - */ -typedef enum rcc_pll_multiplier { - RCC_PLLMUL_2 = (0x0 << 18), - RCC_PLLMUL_3 = (0x1 << 18), - RCC_PLLMUL_4 = (0x2 << 18), - RCC_PLLMUL_5 = (0x3 << 18), - RCC_PLLMUL_6 = (0x4 << 18), - RCC_PLLMUL_7 = (0x5 << 18), - RCC_PLLMUL_8 = (0x6 << 18), - RCC_PLLMUL_9 = (0x7 << 18), - RCC_PLLMUL_10 = (0x8 << 18), - RCC_PLLMUL_11 = (0x9 << 18), - RCC_PLLMUL_12 = (0xA << 18), - RCC_PLLMUL_13 = (0xB << 18), - RCC_PLLMUL_14 = (0xC << 18), - RCC_PLLMUL_15 = (0xD << 18), - RCC_PLLMUL_16 = (0xE << 18), -} rcc_pll_multiplier; - -/** - * @brief Identifies bus and clock line for a peripheral. - * - * Also generally useful as a unique identifier for that peripheral - * (or its corresponding device struct). - */ -typedef enum rcc_clk_id { - RCC_GPIOA, - RCC_GPIOB, - RCC_GPIOC, - RCC_GPIOD, - RCC_AFIO, - RCC_ADC1, - RCC_ADC2, - RCC_ADC3, - RCC_USART1, - RCC_USART2, - RCC_USART3, - RCC_TIMER1, - RCC_TIMER2, - RCC_TIMER3, - RCC_TIMER4, - RCC_SPI1, - RCC_SPI2, - RCC_DMA1, - RCC_PWR, - RCC_BKP, - RCC_I2C1, - RCC_I2C2, - RCC_CRC, - RCC_FLITF, - RCC_SRAM, -#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) - RCC_GPIOE, - RCC_GPIOF, - RCC_GPIOG, - RCC_UART4, - RCC_UART5, - RCC_TIMER5, - RCC_TIMER6, - RCC_TIMER7, - RCC_TIMER8, - RCC_FSMC, - RCC_DAC, - RCC_DMA2, - RCC_SDIO, - RCC_SPI3, -#endif -#ifdef STM32_XL_DENSITY - RCC_TIMER9, - RCC_TIMER10, - RCC_TIMER11, - RCC_TIMER12, - RCC_TIMER13, - RCC_TIMER14, -#endif -} rcc_clk_id; - -void rcc_clk_init(rcc_sysclk_src sysclk_src, - rcc_pllsrc pll_src, - rcc_pll_multiplier pll_mul); -void rcc_clk_enable(rcc_clk_id device); -void rcc_reset_dev(rcc_clk_id device); - -typedef enum rcc_clk_domain { - RCC_APB1, - RCC_APB2, - RCC_AHB -} rcc_clk_domain; - -rcc_clk_domain rcc_dev_clk(rcc_clk_id device); - -uint32 rcc_dev_clk_speed(rcc_clk_id id); -uint32 rcc_dev_timer_clk_speed(rcc_clk_id id); - -/** - * Prescaler identifiers - * @see rcc_set_prescaler() - */ -typedef enum rcc_prescaler { - RCC_PRESCALER_AHB, - RCC_PRESCALER_APB1, - RCC_PRESCALER_APB2, - RCC_PRESCALER_USB, - RCC_PRESCALER_ADC -} rcc_prescaler; - -/** - * ADC prescaler dividers - * @see rcc_set_prescaler() - */ -typedef enum rcc_adc_divider { - RCC_ADCPRE_PCLK_DIV_2 = 0x0 << 14, - RCC_ADCPRE_PCLK_DIV_4 = 0x1 << 14, - RCC_ADCPRE_PCLK_DIV_6 = 0x2 << 14, - RCC_ADCPRE_PCLK_DIV_8 = 0x3 << 14, -} rcc_adc_divider; - -/** - * APB1 prescaler dividers - * @see rcc_set_prescaler() - */ -typedef enum rcc_apb1_divider { - RCC_APB1_HCLK_DIV_1 = 0x0 << 8, - RCC_APB1_HCLK_DIV_2 = 0x4 << 8, - RCC_APB1_HCLK_DIV_4 = 0x5 << 8, - RCC_APB1_HCLK_DIV_8 = 0x6 << 8, - RCC_APB1_HCLK_DIV_16 = 0x7 << 8, -} rcc_apb1_divider; - -/** - * APB2 prescaler dividers - * @see rcc_set_prescaler() - */ -typedef enum rcc_apb2_divider { - RCC_APB2_HCLK_DIV_1 = 0x0 << 11, - RCC_APB2_HCLK_DIV_2 = 0x4 << 11, - RCC_APB2_HCLK_DIV_4 = 0x5 << 11, - RCC_APB2_HCLK_DIV_8 = 0x6 << 11, - RCC_APB2_HCLK_DIV_16 = 0x7 << 11, -} rcc_apb2_divider; - -/** - * AHB prescaler dividers - * @see rcc_set_prescaler() - */ -typedef enum rcc_ahb_divider { - RCC_AHB_SYSCLK_DIV_1 = 0x0 << 4, - RCC_AHB_SYSCLK_DIV_2 = 0x8 << 4, - RCC_AHB_SYSCLK_DIV_4 = 0x9 << 4, - RCC_AHB_SYSCLK_DIV_8 = 0xA << 4, - RCC_AHB_SYSCLK_DIV_16 = 0xB << 4, - RCC_AHB_SYSCLK_DIV_32 = 0xC << 4, - RCC_AHB_SYSCLK_DIV_64 = 0xD << 4, - RCC_AHB_SYSCLK_DIV_128 = 0xD << 4, - RCC_AHB_SYSCLK_DIV_256 = 0xE << 4, - RCC_AHB_SYSCLK_DIV_512 = 0xF << 4, -} rcc_ahb_divider; - -void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif diff --git a/STM32F4/cores/maple/libmaple/rccF2.c b/STM32F4/cores/maple/libmaple/rccF4.c similarity index 99% rename from STM32F4/cores/maple/libmaple/rccF2.c rename to STM32F4/cores/maple/libmaple/rccF4.c index 691393a..c4ff30d 100644 --- a/STM32F4/cores/maple/libmaple/rccF2.c +++ b/STM32F4/cores/maple/libmaple/rccF4.c @@ -24,7 +24,7 @@ * SOFTWARE. *****************************************************************************/ - #ifdef STM32F2 +#ifdef STM32F4 /** * @file rcc.c @@ -166,7 +166,6 @@ typedef struct #define FLASH ((FLASH_TypeDef *) FLASH_R_BASE) #define RESET 0 -typedef uint32 uint32_t; void InitMCO1() { @@ -175,8 +174,8 @@ void InitMCO1() RCC->CFGR &= RCC_CFGR_MCO1_RESET_MASK; RCC->CFGR |= RCC_CFGR_MCO1Source_HSE | RCC_CFGR_MCO1Div_1; // PA8 Output the Master Clock MCO1 - gpio_set_af_mode(GPIOA, 8, 0); - gpio_set_mode(GPIOA, 8, GPIO_MODE_AF | GPIO_OTYPE_PP | GPIO_OSPEED_100MHZ); + gpio_set_af_mode(PA8, 0); + gpio_set_mode(PA8, GPIO_MODE_AF | GPIO_OTYPE_PP | GPIO_OSPEED_100MHZ); } diff --git a/STM32F4/cores/maple/libmaple/rccF2.h b/STM32F4/cores/maple/libmaple/rccF4.h similarity index 100% rename from STM32F4/cores/maple/libmaple/rccF2.h rename to STM32F4/cores/maple/libmaple/rccF4.h diff --git a/STM32F4/cores/maple/libmaple/rules.mk b/STM32F4/cores/maple/libmaple/rules.mk index c4924dc..eb8d96d 100644 --- a/STM32F4/cores/maple/libmaple/rules.mk +++ b/STM32F4/cores/maple/libmaple/rules.mk @@ -3,17 +3,11 @@ sp := $(sp).x dirstack_$(sp) := $(d) d := $(dir) BUILDDIRS += $(BUILD_PATH)/$(d) -ifneq ($(MCU_FAMILY), STM32F2) -BUILDDIRS += $(BUILD_PATH)/$(d)/usb -BUILDDIRS += $(BUILD_PATH)/$(d)/usb/usb_lib -LIBMAPLE_INCLUDES := -I$(LIBMAPLE_PATH) -I$(LIBMAPLE_PATH)/usb -I$(LIBMAPLE_PATH)/usb/usb_lib -else BUILDDIRS += $(BUILD_PATH)/$(d)/usbF4/STM32_USB_Device_Library/Core/src BUILDDIRS += $(BUILD_PATH)/$(d)/usbF4/STM32_USB_Device_Library/Class/cdc/src BUILDDIRS += $(BUILD_PATH)/$(d)/usbF4/STM32_USB_OTG_Driver/src BUILDDIRS += $(BUILD_PATH)/$(d)/usbF4/VCP LIBMAPLE_INCLUDES := -I$(LIBMAPLE_PATH) -I$(LIBMAPLE_PATH)/usbF4 -endif # Local flags @@ -42,18 +36,6 @@ cSRCS_$(d) := adc.c \ usart.c \ util.c -ifneq ($(MCU_FAMILY), STM32F2) - cSRCS_$(d) += \ - usb/descriptors.c \ - usb/usb.c \ - usb/usb_callbacks.c \ - usb/usb_hardware.c \ - usb/usb_lib/usb_core.c \ - usb/usb_lib/usb_init.c \ - usb/usb_lib/usb_int.c \ - usb/usb_lib/usb_mem.c \ - usb/usb_lib/usb_regs.c -else V=1 cSRCS_$(d) += \ usbF4/STM32_USB_Device_Library/Core/src/usbd_core.c \ @@ -69,11 +51,7 @@ else usbF4/VCP/usbd_usr.c \ usbF4/usb.c \ usbF4/VCP/misc.c -endif -ifneq ($(MCU_FAMILY), STM32F2) - cSRCS_$(d) += bkp.c -endif sSRCS_$(d) := exc.S diff --git a/STM32F4/cores/maple/libmaple/spi.c b/STM32F4/cores/maple/libmaple/spi.c index 194a82e..4b274cb 100644 --- a/STM32F4/cores/maple/libmaple/spi.c +++ b/STM32F4/cores/maple/libmaple/spi.c @@ -83,25 +83,29 @@ 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 * correctly treated as 8-bit or 16-bit quantities). * @param len Maximum number of elements to transmit. - * @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 (spi_is_tx_empty(dev) && (txed < len)) { - if (byte_frame) { - dev->regs->DR = ((const uint8*)buf)[txed++]; - } else { - dev->regs->DR = ((const uint16*)buf)[txed++]; - } - } - return txed; +void spi_tx(spi_dev *dev, void *buf, uint32 len) +{ + spi_reg_map *regs = dev->regs; + if ( spi_dff(dev) == SPI_DFF_8_BIT ) { + uint8 * dp8 = (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 { + uint16 * dp16 = (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++; + } + } } /** @@ -157,8 +161,9 @@ void spi_rx_dma_disable(spi_dev *dev) { */ static void spi_reconfigure(spi_dev *dev, uint32 cr1_config) { - spi_irq_disable(dev, SPI_INTERRUPTS_ALL); - spi_peripheral_disable(dev); - dev->regs->CR1 = cr1_config; - spi_peripheral_enable(dev); +#define MASK (SPI_CR1_CRCEN|SPI_CR1_DFF) + 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_peripheral_enable(dev); } diff --git a/STM32F4/cores/maple/libmaple/spi.h b/STM32F4/cores/maple/libmaple/spi.h index 88739c5..abed68c 100644 --- a/STM32F4/cores/maple/libmaple/spi.h +++ b/STM32F4/cores/maple/libmaple/spi.h @@ -213,31 +213,22 @@ typedef struct spi_dev { void spi_init(spi_dev *dev); -struct gpio_dev; /** * @brief Configure GPIO bit modes for use as a SPI port's pins. * * @param dev SPI device * @param as_master If true, configure as bus master; otherwise, as slave. - * @param nss_dev NSS pin's GPIO device * @param nss_bit NSS pin's GPIO bit on nss_dev - * @param sck_dev SCK pin's GPIO device * @param sck_bit SCK pin's GPIO bit on comm_dev - * @param miso_dev MISO pin's GPIO device * @param miso_bit MISO pin's GPIO bit on comm_dev - * @param mosi_dev MOSI pin's GPIO device * @param mosi_bit MOSI pin's GPIO bit on comm_dev */ extern void spi_config_gpios(spi_dev *dev, uint8 as_master, - struct gpio_dev *nss_dev, - uint8 nss_bit, - struct gpio_dev *sck_dev, - uint8 sck_bit, - struct gpio_dev *miso_dev, - uint8 miso_bit, - struct gpio_dev *mosi_dev, - uint8 mosi_bit); + uint8 nss_pin, + uint8 sck_pin, + uint8 miso_pin, + uint8 mosi_pin); /** * @brief SPI mode configuration. @@ -312,7 +303,7 @@ void spi_slave_enable(spi_dev *dev, spi_mode mode, uint32 flags); -uint32 spi_tx(spi_dev *dev, const void *buf, uint32 len); +void spi_tx(spi_dev *dev, void *buf, uint32 len); /** * @brief Call a function on each SPI port diff --git a/STM32F4/cores/maple/libmaple/spiF4.h b/STM32F4/cores/maple/libmaple/spiF4.h index 3f51164..cbdc91a 100644 --- a/STM32F4/cores/maple/libmaple/spiF4.h +++ b/STM32F4/cores/maple/libmaple/spiF4.h @@ -31,8 +31,8 @@ * @brief STM32F1 SPI/I2S series header. */ -#ifndef _LIBMAPLE_STM32F1_SPI_H_ -#define _LIBMAPLE_STM32F1_SPI_H_ +#ifndef _LIBMAPLE_SPI_F4_H_ +#define _LIBMAPLE_SPI_F4_H_ #include @@ -62,17 +62,6 @@ extern struct spi_dev *SPI2; extern struct spi_dev *SPI3; #endif -/* - * Routines - */ - -/* spi_gpio_cfg(): Backwards compatibility shim to spi_config_gpios() */ -struct gpio_dev; -extern void spi_config_gpios(struct spi_dev*, uint8, - struct gpio_dev*, uint8, - struct gpio_dev*, uint8, - struct gpio_dev*, uint8, - struct gpio_dev*, uint8); #ifdef __cplusplus } diff --git a/STM32F4/cores/maple/libmaple/spi_f4.c b/STM32F4/cores/maple/libmaple/spi_f4.c index b9beb68..43f5092 100644 --- a/STM32F4/cores/maple/libmaple/spi_f4.c +++ b/STM32F4/cores/maple/libmaple/spi_f4.c @@ -56,25 +56,21 @@ spi_dev *SPI3 = &spi3; void spi_config_gpios(spi_dev *ignored, uint8 as_master, - gpio_dev *nss_dev, - uint8 nss_bit, - gpio_dev *sck_dev, - uint8 sck_bit, - gpio_dev *miso_dev, - uint8 miso_bit, - gpio_dev *mosi_dev, - uint8 mosi_bit) { + uint8 nss_pin, + uint8 sck_pin, + uint8 miso_pin, + uint8 mosi_pin) { if (as_master) { // gpio_set_mode(nss_dev, nss_bit, GPIO_AF_OUTPUT_PP); - gpio_set_mode(sck_dev, sck_bit, GPIO_AF_OUTPUT_PP); + gpio_set_mode(sck_pin, GPIO_AF_OUTPUT_PP); // gpio_set_mode(comm_dev, miso_bit, GPIO_INPUT_FLOATING); - gpio_set_mode(miso_dev, miso_bit, GPIO_AF_INPUT_PD); - gpio_set_mode(mosi_dev, mosi_bit, GPIO_AF_OUTPUT_PP); + gpio_set_mode(miso_pin, GPIO_AF_INPUT_PD); + gpio_set_mode(mosi_pin, GPIO_AF_OUTPUT_PP); } else { - gpio_set_mode(nss_dev, nss_bit, GPIO_INPUT_FLOATING); - gpio_set_mode(sck_dev, sck_bit, GPIO_INPUT_FLOATING); - gpio_set_mode(miso_dev, miso_bit, GPIO_AF_OUTPUT_PP); - gpio_set_mode(mosi_dev, mosi_bit, GPIO_INPUT_FLOATING); + gpio_set_mode(nss_pin, GPIO_INPUT_FLOATING); + gpio_set_mode(sck_pin, GPIO_INPUT_FLOATING); + gpio_set_mode(miso_pin, GPIO_AF_OUTPUT_PP); + gpio_set_mode(mosi_pin, GPIO_INPUT_FLOATING); } } diff --git a/STM32F4/cores/maple/libmaple/stm32.h b/STM32F4/cores/maple/libmaple/stm32.h index 0d4deaa..3921788 100644 --- a/STM32F4/cores/maple/libmaple/stm32.h +++ b/STM32F4/cores/maple/libmaple/stm32.h @@ -138,69 +138,8 @@ #endif -#if defined(MCU_STM32F103RB) - /* e.g., LeafLabs Maple */ - #define STM32_NR_GPIO_PORTS 4 - #define STM32_DELAY_US_MULT 12 - #define STM32_SRAM_END ((void*)0x20005000) - - #define NR_GPIO_PORTS STM32_NR_GPIO_PORTS - #define DELAY_US_MULT STM32_DELAY_US_MULT - -#elif defined(MCU_STM32F103ZE) - /* e.g., LeafLabs Maple Native */ - - #define STM32_NR_GPIO_PORTS 7 - #define STM32_DELAY_US_MULT 12 - #define STM32_SRAM_END ((void*)0x20010000) - - #define NR_GPIO_PORTS STM32_NR_GPIO_PORTS - #define DELAY_US_MULT STM32_DELAY_US_MULT - -#elif defined(MCU_STM32F103CB) - /* e.g., LeafLabs Maple Mini */ - - /* This STM32_NR_GPIO_PORTS value is not, strictly speaking, true. - * But only pins 0 and 1 exist, and they're used for OSC on the - * Mini, so we'll live with this for now. */ - #define STM32_NR_GPIO_PORTS 3 - #define STM32_DELAY_US_MULT 12 - #define STM32_SRAM_END ((void*)0x20005000) - - #define NR_GPIO_PORTS STM32_NR_GPIO_PORTS - #define DELAY_US_MULT STM32_DELAY_US_MULT - -#elif defined(MCU_STM32F103RE) - /* e.g., LeafLabs Maple RET6 edition */ - - #define STM32_NR_GPIO_PORTS 4 - #define STM32_DELAY_US_MULT 12 - #define STM32_SRAM_END ((void*)0x20010000) - - #define NR_GPIO_PORTS STM32_NR_GPIO_PORTS - #define DELAY_US_MULT STM32_DELAY_US_MULT - -#elif defined(MCU_STM32F103VE) - /* e.g., LeafLabs Maple Native */ - - #define STM32_NR_GPIO_PORTS 5 - #define STM32_DELAY_US_MULT 12 - #define STM32_SRAM_END ((void*)0x20010000) - - #define NR_GPIO_PORTS STM32_NR_GPIO_PORTS - #define DELAY_US_MULT STM32_DELAY_US_MULT - -#elif defined(MCU_STM32F205VE) - #define STM32_TICKS_PER_US 120 - #define STM32_NR_GPIO_PORTS 5 - #define STM32_DELAY_US_MULT (STM32_TICKS_PER_US/3) - #define STM32_SRAM_END ((void*)0x20010000) - - #define NR_GPIO_PORTS STM32_NR_GPIO_PORTS - #define DELAY_US_MULT STM32_DELAY_US_MULT - -#elif defined(MCU_STM32F406VG) +#if defined( STM32F4 ) #define STM32_TICKS_PER_US 168 #define STM32_NR_GPIO_PORTS 5 #define STM32_DELAY_US_MULT (STM32_TICKS_PER_US/3) diff --git a/STM32F4/cores/maple/libmaple/timer.c b/STM32F4/cores/maple/libmaple/timer.c index 83e9ace..f8e55a1 100644 --- a/STM32F4/cores/maple/libmaple/timer.c +++ b/STM32F4/cores/maple/libmaple/timer.c @@ -44,7 +44,7 @@ /* Update only. */ #define NR_BAS_HANDLERS 1 -static timer_dev timer1 = { +timer_dev timer1 = { .regs = { .adv = TIMER1_BASE }, .clk_id = RCC_TIMER1, .type = TIMER_ADVANCED, @@ -53,7 +53,7 @@ static timer_dev timer1 = { /** Timer 1 device (advanced) */ timer_dev *TIMER1 = &timer1; -static timer_dev timer2 = { +timer_dev timer2 = { .regs = { .gen = TIMER2_BASE }, .clk_id = RCC_TIMER2, .type = TIMER_GENERAL, @@ -62,7 +62,7 @@ static timer_dev timer2 = { /** Timer 2 device (general-purpose) */ timer_dev *TIMER2 = &timer2; -static timer_dev timer3 = { +timer_dev timer3 = { .regs = { .gen = TIMER3_BASE }, .clk_id = RCC_TIMER3, .type = TIMER_GENERAL, @@ -71,7 +71,7 @@ static timer_dev timer3 = { /** Timer 3 device (general-purpose) */ timer_dev *TIMER3 = &timer3; -static timer_dev timer4 = { +timer_dev timer4 = { .regs = { .gen = TIMER4_BASE }, .clk_id = RCC_TIMER4, .type = TIMER_GENERAL, @@ -81,7 +81,7 @@ static timer_dev timer4 = { timer_dev *TIMER4 = &timer4; #ifdef STM32_HIGH_DENSITY -static timer_dev timer5 = { +timer_dev timer5 = { .regs = { .gen = TIMER5_BASE }, .clk_id = RCC_TIMER5, .type = TIMER_GENERAL, @@ -90,7 +90,7 @@ static timer_dev timer5 = { /** Timer 5 device (general-purpose) */ timer_dev *TIMER5 = &timer5; -static timer_dev timer6 = { +timer_dev timer6 = { .regs = { .bas = TIMER6_BASE }, .clk_id = RCC_TIMER6, .type = TIMER_BASIC, @@ -99,7 +99,7 @@ static timer_dev timer6 = { /** Timer 6 device (basic) */ timer_dev *TIMER6 = &timer6; -static timer_dev timer7 = { +timer_dev timer7 = { .regs = { .bas = TIMER7_BASE }, .clk_id = RCC_TIMER7, .type = TIMER_BASIC, @@ -108,7 +108,7 @@ static timer_dev timer7 = { /** Timer 7 device (basic) */ timer_dev *TIMER7 = &timer7; -static timer_dev timer8 = { +timer_dev timer8 = { .regs = { .adv = TIMER8_BASE }, .clk_id = RCC_TIMER8, .type = TIMER_ADVANCED, diff --git a/STM32F4/cores/maple/libmaple/timer.h b/STM32F4/cores/maple/libmaple/timer.h index fce6345..79b7d29 100644 --- a/STM32F4/cores/maple/libmaple/timer.h +++ b/STM32F4/cores/maple/libmaple/timer.h @@ -113,13 +113,8 @@ typedef struct timer_bas_reg_map { } timer_bas_reg_map; -#ifdef STM32F2 - /** Timer 1 register map base pointer */ - #define TIMER1_BASE ((struct timer_adv_reg_map*)0x40010000) -#else - /** Timer 1 register map base pointer */ - #define TIMER1_BASE ((struct timer_adv_reg_map*)0x40012C00) -#endif +/** Timer 1 register map base pointer */ +#define TIMER1_BASE ((struct timer_adv_reg_map*)0x40010000) /** Timer 2 register map base pointer */ #define TIMER2_BASE ((struct timer_gen_reg_map*)0x40000000) /** Timer 3 register map base pointer */ @@ -133,14 +128,8 @@ typedef struct timer_bas_reg_map { #define TIMER6_BASE ((struct timer_bas_reg_map*)0x40001000) /** Timer 7 register map base pointer */ #define TIMER7_BASE ((struct timer_bas_reg_map*)0x40001400) - -#ifdef STM32F2 - /** Timer 8 register map base pointer */ - #define TIMER8_BASE ((struct timer_adv_reg_map*)0x40010400) -#else - /** Timer 8 register map base pointer */ - #define TIMER8_BASE ((struct timer_adv_reg_map*)0x40013400) -#endif +/** Timer 8 register map base pointer */ +#define TIMER8_BASE ((struct timer_adv_reg_map*)0x40010400) #endif /* diff --git a/STM32F4/cores/maple/libmaple/usart.h b/STM32F4/cores/maple/libmaple/usart.h index 3f7c885..282293a 100644 --- a/STM32F4/cores/maple/libmaple/usart.h +++ b/STM32F4/cores/maple/libmaple/usart.h @@ -62,11 +62,7 @@ typedef struct usart_reg_map { } usart_reg_map; /** USART1 register map base pointer */ -#ifdef STM32F2 - #define USART1_BASE ((struct usart_reg_map*)0x40011000) -#else - #define USART1_BASE ((struct usart_reg_map*)0x40013800) -#endif +#define USART1_BASE ((struct usart_reg_map*)0x40011000) /** USART2 register map base pointer */ #define USART2_BASE ((struct usart_reg_map*)0x40004400) /** USART3 register map base pointer */ diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/audio/inc/usbd_audio_core.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/audio/inc/usbd_audio_core.h index f58ff06..7ac987d 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/audio/inc/usbd_audio_core.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/audio/inc/usbd_audio_core.h @@ -26,7 +26,7 @@ #include "usbd_ioreq.h" #include "usbd_req.h" -#include "usbd_desc.h" +#include diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/inc/usbd_cdc_core.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/inc/usbd_cdc_core.h index 926f42e..b1c8cc1 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/inc/usbd_cdc_core.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/inc/usbd_cdc_core.h @@ -24,7 +24,8 @@ #ifndef __USB_CDC_CORE_H_ #define __USB_CDC_CORE_H_ -#include "usbd_ioreq.h" +#include +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/src/usbd_cdc_core.c b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/src/usbd_cdc_core.c index aac6776..8f97c51 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/src/usbd_cdc_core.c +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/src/usbd_cdc_core.c @@ -58,9 +58,10 @@ */ /* Includes ------------------------------------------------------------------*/ -#include "usbd_cdc_core.h" -#include "usbd_desc.h" -#include "usbd_req.h" +#include +#include +#include +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_core.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_core.h index b876856..063a30e 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_core.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_core.h @@ -24,9 +24,9 @@ #define __USBD_CORE_H /* Includes ------------------------------------------------------------------*/ -#include "usb_dcd.h" +#include #include "usbd_def.h" -#include "usbd_conf.h" +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_def.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_def.h index a8c8671..f2a3115 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_def.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_def.h @@ -24,7 +24,7 @@ #ifndef __USBD_DEF_H #define __USBD_DEF_H /* Includes ------------------------------------------------------------------*/ -#include "usbd_conf.h" +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_req.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_req.h index 9aa9e44..f9849c6 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_req.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_req.h @@ -27,7 +27,7 @@ /* Includes ------------------------------------------------------------------*/ #include "usbd_def.h" #include "usbd_core.h" -#include "usbd_conf.h" +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_core.c b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_core.c index af75842..00bb251 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_core.c +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_core.c @@ -20,11 +20,11 @@ */ /* Includes ------------------------------------------------------------------*/ -#include "usbd_core.h" -#include "usbd_req.h" -#include "usbd_ioreq.h" -#include "usb_dcd_int.h" -#include "usb_bsp.h" +#include +#include +#include +#include +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_ioreq.c b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_ioreq.c index 6964766..20ee5a0 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_ioreq.c +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_ioreq.c @@ -20,7 +20,7 @@ */ /* Includes ------------------------------------------------------------------*/ -#include "usbd_ioreq.h" +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @{ */ diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_req.c b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_req.c index f08d26c..5fc2e03 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_req.c +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_req.c @@ -20,9 +20,9 @@ */ /* Includes ------------------------------------------------------------------*/ -#include "usbd_req.h" -#include "usbd_ioreq.h" -#include "usbd_desc.h" +#include +#include +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_core.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_core.h index 82a09e1..43c4781 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_core.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_core.h @@ -24,7 +24,7 @@ #define __USB_CORE_H__ /* Includes ------------------------------------------------------------------*/ -#include "usb_conf.h" +#include #include "usb_regs.h" #include "usb_defines.h" diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_defines.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_defines.h index 8c23d72..ee2c1a0 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_defines.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_defines.h @@ -24,7 +24,7 @@ #define __USB_DEF_H__ /* Includes ------------------------------------------------------------------*/ -#include "usb_conf.h" +#include /** @addtogroup USB_OTG_DRIVER * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_otg.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_otg.h index 54d61b8..1347f31 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_otg.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_otg.h @@ -23,6 +23,7 @@ #ifndef __USB_OTG__ #define __USB_OTG__ +#include "usb_core.h" /** @addtogroup USB_OTG_DRIVER * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_regs.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_regs.h index cd71ddf..99f844e 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_regs.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_regs.h @@ -24,8 +24,8 @@ #define __USB_OTG_REGS_H__ /* Includes ------------------------------------------------------------------*/ -#include "usb_conf.h" - +#include +#include /** @addtogroup USB_OTG_DRIVER * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_core.c b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_core.c index cb9eabc..1687afa 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_core.c +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_core.c @@ -20,8 +20,8 @@ */ /* Includes ------------------------------------------------------------------*/ -#include "usb_bsp.h" -#include "usb_core.h" +#include +#include /** @addtogroup USB_OTG_DRIVER diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_dcd.c b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_dcd.c index c3336cb..dc9e538 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_dcd.c +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_dcd.c @@ -20,8 +20,8 @@ */ /* Includes ------------------------------------------------------------------*/ -#include "usb_dcd.h" -#include "usb_bsp.h" +#include +#include /** @addtogroup USB_OTG_DRIVER diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_dcd_int.c b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_dcd_int.c index 3a49ede..f9e561f 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_dcd_int.c +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_dcd_int.c @@ -20,12 +20,12 @@ */ /* Includes ------------------------------------------------------------------*/ -#include "usb_dcd_int.h" +#include typedef int IRQn_Type; #define __NVIC_PRIO_BITS 4 #define __Vendor_SysTickConfig 1 -#include +#include /** @addtogroup USB_OTG_DRIVER diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/core_cm4.h b/STM32F4/cores/maple/libmaple/usbF4/VCP/core_cm4.h index 443665c..ff5e9a6 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/core_cm4.h +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/core_cm4.h @@ -141,7 +141,7 @@ #endif #include /*!< standard types definitions */ -#include /*!< Core Instruction Access */ +#include "core_cmInstr.h" /*!< Core Instruction Access */ //#include /*!< Core Function Access */ //#include /*!< Compiler specific SIMD Intrinsics */ diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/misc.c b/STM32F4/cores/maple/libmaple/usbF4/VCP/misc.c index 9f33150..15a715e 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/misc.c +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/misc.c @@ -80,7 +80,7 @@ typedef unsigned char u8; typedef int IRQn_Type; #define __NVIC_PRIO_BITS 4 #define __Vendor_SysTickConfig 1 -#include +#include "core_cm4.h" /** @addtogroup STM32F4xx_StdPeriph_Driver * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/usb_bsp.c b/STM32F4/cores/maple/libmaple/usbF4/VCP/usb_bsp.c index df23ccb..e794cb1 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/usb_bsp.c +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/usb_bsp.c @@ -21,13 +21,13 @@ */ /* Includes ------------------------------------------------------------------*/ -#include "usb_bsp.h" +#include #include "usbd_conf.h" -#include +#include typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState; #define OTG_FS_IRQn 67 //typedef unsigned char uint8_t; -#include +#include "misc.h" //#include "stm32f4_discovery.h" @@ -97,10 +97,10 @@ void USB_OTG_BSP_Init(USB_OTG_CORE_HANDLE *pdev) { // ala42 #define GPIO_AF_OTG1_FS ((uint8_t)0xA) /* OTG_FS Alternate Function mapping */ - gpio_set_mode(GPIOA,11,GPIO_MODE_AF | GPIO_OTYPE_PP | GPIO_OSPEED_100MHZ); - gpio_set_mode(GPIOA,12,GPIO_MODE_AF | GPIO_OTYPE_PP | GPIO_OSPEED_100MHZ); - gpio_set_af_mode(GPIOA,11,GPIO_AF_OTG1_FS) ; // OTG_FS_DM - gpio_set_af_mode(GPIOA,12,GPIO_AF_OTG1_FS) ; // OTG_FS_DP + gpio_set_mode(BOARD_USB_DM_PIN,GPIO_MODE_AF | GPIO_OTYPE_PP | GPIO_OSPEED_100MHZ); + gpio_set_mode(BOARD_USB_DP_PIN,GPIO_MODE_AF | GPIO_OTYPE_PP | GPIO_OSPEED_100MHZ); + gpio_set_af_mode(BOARD_USB_DM_PIN,GPIO_AF_OTG1_FS) ; // OTG_FS_DM + gpio_set_af_mode(BOARD_USB_DP_PIN,GPIO_AF_OTG1_FS) ; // OTG_FS_DP #ifdef USB_OTG_FS_SOF_OUTPUT_ENABLED gpio_set_mode(GPIOA, 8,GPIO_MODE_AF | GPIO_OTYPE_PP | GPIO_OSPEED_100MHZ); gpio_set_af_mode(GPIOA, 8,GPIO_AF_OTG1_FS) ; // OTG_FS_SOF @@ -122,10 +122,10 @@ void USB_OTG_BSP_DeInit(USB_OTG_CORE_HANDLE *pdev) { // ala42 #define GPIO_AF0 ((uint8_t)0) /* OTG_FS Alternate Function mapping */ - gpio_set_mode(GPIOA,11, GPIO_MODE_INPUT); - gpio_set_mode(GPIOA,12, GPIO_MODE_INPUT); - gpio_set_af_mode(GPIOA,11,GPIO_AF0) ; // OTG_FS_DM - gpio_set_af_mode(GPIOA,12,GPIO_AF0) ; // OTG_FS_DP + gpio_set_mode(BOARD_USB_DM_PIN, GPIO_MODE_INPUT); + gpio_set_mode(BOARD_USB_DP_PIN, GPIO_MODE_INPUT); + gpio_set_af_mode(BOARD_USB_DM_PIN,GPIO_AF0) ; // OTG_FS_DM + gpio_set_af_mode(BOARD_USB_DP_PIN,GPIO_AF0) ; // OTG_FS_DP #ifdef USB_OTG_FS_SOF_OUTPUT_ENABLED gpio_set_mode(GPIOA, 8,GPIO_MODE_INPUT); gpio_set_af_mode(GPIOA, 8,GPIO_AF0) ; // OTG_FS_SOF diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/usb_conf.h b/STM32F4/cores/maple/libmaple/usbF4/VCP/usb_conf.h index 61b0ac5..fd45f4d 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/usb_conf.h +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/usb_conf.h @@ -173,7 +173,9 @@ typedef unsigned char u8; #elif defined (__ICCARM__) /* IAR Compiler */ #define __packed __packed #elif defined ( __GNUC__ ) /* GNU Compiler */ + #ifndef __packed #define __packed __attribute__ ((__packed__)) + #endif #elif defined (__TASKING__) /* TASKING Compiler */ #define __packed __unaligned #endif /* __CC_ARM */ @@ -206,7 +208,9 @@ typedef unsigned char u8; #elif defined (__ICCARM__) /* IAR Compiler */ #define __packed __packed #elif defined ( __GNUC__ ) /* GNU Compiler */ + #ifndef __packed #define __packed __attribute__ ((__packed__)) + #endif #elif defined (__TASKING__) /* TASKING Compiler */ #define __packed __unaligned #endif /* __CC_ARM */ diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.c b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.c index b13260e..28a2d1f 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.c +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.c @@ -255,7 +255,7 @@ typedef struct { void systemHardReset(void) { SCB_TypeDef* rSCB = (SCB_TypeDef *) SCB_BASE; - typedef void (*funcPtr)(void); + //typedef void (*funcPtr)(void); // not used /* Reset */ rSCB->AIRCR = (u32)AIRCR_RESET_REQ; diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.h b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.h index 67475e7..8398dbd 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.h +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.h @@ -26,7 +26,7 @@ /* Includes ------------------------------------------------------------------*/ //#include "stm32f4xx.h" -#include "usbd_cdc_core.h" +#include #include "usbd_conf.h" diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_conf.h b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_conf.h index 516a2fb..62a40c2 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_conf.h +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_conf.h @@ -25,6 +25,7 @@ /* Includes ------------------------------------------------------------------*/ //#include "stm32f4_discovery.h" +#include "usb_conf.h" /** @defgroup USB_CONF_Exported_Defines * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.c b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.c index 537f266..0153858 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.c +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.c @@ -20,11 +20,11 @@ */ /* Includes ------------------------------------------------------------------*/ -#include "usbd_core.h" +#include #include "usbd_desc.h" -#include "usbd_req.h" +#include #include "usbd_conf.h" -#include "usb_regs.h" +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.h b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.h index ed999dc..4ae998c 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.h +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.h @@ -25,7 +25,7 @@ #define __USB_DESC_H /* Includes ------------------------------------------------------------------*/ -#include "usbd_def.h" +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_usr.c b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_usr.c index 84e8d6a..a16ce40 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_usr.c +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_usr.c @@ -20,8 +20,8 @@ */ /* Includes ------------------------------------------------------------------*/ -#include "usbd_usr.h" -#include "usbd_ioreq.h" +#include +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY diff --git a/STM32F4/cores/maple/libmaple/usbF4/usb.c b/STM32F4/cores/maple/libmaple/usbF4/usb.c index 2c0672f..3850719 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/usb.c +++ b/STM32F4/cores/maple/libmaple/usbF4/usb.c @@ -1,27 +1,30 @@ -#include "usbd_cdc_core.h" -#include "usbd_usr.h" -#include "usbd_desc.h" +#ifndef _USBF4_USB_H_ +#define _USBF4_USB_H_ + + +#include +#include +#include #include "usb.h" -#include -#include -#include +#include +#include +#include +#include USB_OTG_CORE_HANDLE USB_OTG_dev; -void setupUSB (void) { - #define USB_DISC_DEV GPIOD - #define USB_DISC_PIN 11 - - gpio_set_mode(USB_DISC_DEV, USB_DISC_PIN, GPIO_OUTPUT_OD); // ala42 +void setupUSB (void) +{ + gpio_set_mode(BOARD_USB_DP_PIN, GPIO_OUTPUT_OD); // ala42 #ifdef USB_DISC_OD //gpio_set_mode(USB_DISC_DEV, USB_DISC_PIN, GPIO_OUTPUT_OD); // ala42 #else //gpio_set_mode(USB_DISC_DEV, USB_DISC_PIN, GPIO_OUTPUT_PP); // ala42 for active pull-up on disconnect pin #endif - gpio_write_bit(USB_DISC_DEV, USB_DISC_PIN,0); // ala42 + gpio_clear_pin(BOARD_USB_DP_PIN); // ala42 delay_us(200000); /* setup the apb1 clock for USB */ @@ -29,7 +32,7 @@ void setupUSB (void) { //pRCC->APB1ENR |= RCC_APB1ENR_USBEN; /* initialize the usb application */ - gpio_write_bit(USB_DISC_DEV, USB_DISC_PIN, 1); // ala42 // presents us to the host + gpio_set_pin(BOARD_USB_DP_PIN); // ala42 // presents us to the host USBD_Init(&USB_OTG_dev, USB_OTG_FS_CORE_ID, &USR_desc, @@ -93,7 +96,7 @@ RESULT usbPowerOff(void) { void usbDsbISR(void) {}; -#include "usb_dcd_int.h" +#include void __irq_OTG_FS_IRQHandler(void) { USBD_OTG_ISR_Handler (&USB_OTG_dev); @@ -102,3 +105,5 @@ void __irq_OTG_FS_IRQHandler(void) void x__irq_usbwakeup(void) { } + +#endif diff --git a/STM32F4/cores/maple/libmaple/usbF4/usb.h b/STM32F4/cores/maple/libmaple/usbF4/usb.h index f09f2bd..ce1a558 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/usb.h +++ b/STM32F4/cores/maple/libmaple/usbF4/usb.h @@ -5,7 +5,7 @@ extern "C" { #endif -#include "usb_conf.h" +#include typedef enum _RESULT { diff --git a/STM32F4/cores/maple/libmaple/util.c b/STM32F4/cores/maple/libmaple/util.c index 8c03e18..8a745e8 100644 --- a/STM32F4/cores/maple/libmaple/util.c +++ b/STM32F4/cores/maple/libmaple/util.c @@ -128,7 +128,7 @@ void throb(void) { uint32 TOP_CNT = 0x0800; uint32 i = 0; - gpio_set_mode(ERROR_LED_PORT, ERROR_LED_PIN, GPIO_OUTPUT_PP); + gpio_set_mode(ERROR_LED_PIN, GPIO_OUTPUT_PP); /* Error fade. */ while (1) { if (CC == TOP_CNT) { @@ -143,9 +143,9 @@ void throb(void) { } if (i < CC) { - gpio_write_bit(ERROR_LED_PORT, ERROR_LED_PIN, 1); + gpio_set_pin(ERROR_LED_PIN); } else { - gpio_write_bit(ERROR_LED_PORT, ERROR_LED_PIN, 0); + gpio_clear_pin(ERROR_LED_PIN); } i++; } diff --git a/STM32F4/cores/maple/libmaple/util.h b/STM32F4/cores/maple/libmaple/util.h index 62ad8af..c5ed2de 100644 --- a/STM32F4/cores/maple/libmaple/util.h +++ b/STM32F4/cores/maple/libmaple/util.h @@ -29,11 +29,12 @@ * @brief Miscellaneous utility macros and procedures. */ -#include "libmaple_types.h" - #ifndef _UTIL_H_ #define _UTIL_H_ +#include "libmaple_types.h" +#include "delay.h" + #ifdef __cplusplus extern "C"{ #endif diff --git a/STM32F4/cores/maple/pwm.cpp b/STM32F4/cores/maple/pwm.cpp index 1806348..c5f2ccb 100644 --- a/STM32F4/cores/maple/pwm.cpp +++ b/STM32F4/cores/maple/pwm.cpp @@ -28,8 +28,8 @@ * @brief Arduino-style PWM implementation. */ -#include "libmaple_types.h" -#include "timer.h" +#include +#include #include "boards.h" #include "pwm.h" diff --git a/STM32F4/cores/maple/usb_serial.cpp b/STM32F4/cores/maple/usb_serial.cpp index cc726c2..fadcb91 100644 --- a/STM32F4/cores/maple/usb_serial.cpp +++ b/STM32F4/cores/maple/usb_serial.cpp @@ -33,6 +33,8 @@ #include "wirish.h" #include "usb.h" +#ifdef SERIAL_USB + #define USB_TIMEOUT 50 USBSerial::USBSerial(void) { @@ -132,7 +134,7 @@ uint8 USBSerial::pending(void) { return usbGetPending(); } -uint8 USBSerial::isConnected(void) { +USBSerial::operator bool() { return usbIsConnected() && usbIsConfigured(); } @@ -153,3 +155,5 @@ void USBSerial::disableBlockingTx(void) { } USBSerial SerialUSB; + +#endif diff --git a/STM32F4/cores/maple/usb_serial.h b/STM32F4/cores/maple/usb_serial.h index a551e9d..8eeed96 100644 --- a/STM32F4/cores/maple/usb_serial.h +++ b/STM32F4/cores/maple/usb_serial.h @@ -33,6 +33,8 @@ #include "Stream.h" +#ifdef SERIAL_USB + /** * @brief Virtual serial terminal. */ @@ -57,7 +59,8 @@ public: uint8 getRTS(); uint8 getDTR(); - uint8 isConnected(); + operator bool(); + uint8 isConnected() { return (bool) *this; } uint8 pending(); void enableBlockingTx(void); @@ -65,6 +68,14 @@ public: }; extern USBSerial SerialUSB; +#define Serial SerialUSB -#endif +#else // _USB_SERIAL_H_ + +#define Serial Serial1 + +#endif // SERIAL_USB + + +#endif // _USB_SERIAL_H_ diff --git a/STM32F4/cores/maple/wirish.h b/STM32F4/cores/maple/wirish.h index 4aca74c..945e8fb 100644 --- a/STM32F4/cores/maple/wirish.h +++ b/STM32F4/cores/maple/wirish.h @@ -34,9 +34,9 @@ #define _WIRISH_H_ #include -#include "libmaple.h" +#include +#include -#include "wirish_types.h" #include "boards.h" #include "io.h" #include "bits.h" @@ -44,10 +44,8 @@ #include "ext_interrupts.h" #include "wirish_debug.h" #include "wirish_math.h" -#include "wirish_time.h" #include -#include "HardwareSPI.h" -#include "HardwareSerial.h" +#include #include "HardwareTimer.h" #include "usb_serial.h" @@ -55,9 +53,10 @@ #define HIGH 0x1 #define LOW 0x0 -#define true 0x1 -#define false 0x0 - +#ifndef true + #define true 0x1 + #define false 0x0 +#endif #define lowByte(w) ((w) & 0xFF) #define highByte(w) (((w) >> 8) & 0xFF) diff --git a/STM32F4/cores/maple/wirish_analog.cpp b/STM32F4/cores/maple/wirish_analog.cpp index 63b5eb2..4e920e7 100644 --- a/STM32F4/cores/maple/wirish_analog.cpp +++ b/STM32F4/cores/maple/wirish_analog.cpp @@ -28,9 +28,7 @@ * @brief Arduino-compatible ADC implementation. */ -#include "libmaple.h" #include "wirish.h" -#include "io.h" /* Assumes that the ADC has been initialized and that the pin is set * to INPUT_ANALOG */ diff --git a/STM32F4/cores/maple/wirish_constants.h b/STM32F4/cores/maple/wirish_constants.h index 06a85ae..f39c077 100644 --- a/STM32F4/cores/maple/wirish_constants.h +++ b/STM32F4/cores/maple/wirish_constants.h @@ -1,5 +1,5 @@ -#ifndef _WIRING_CONSTANTS_ -#define _WIRING_CONSTANTS_ +#ifndef _WIRISH_CONSTANTS_H_ +#define _WIRISH_CONSTANTS_H_ #ifdef __cplusplus extern "C"{ diff --git a/STM32F4/cores/maple/wirish_debug.h b/STM32F4/cores/maple/wirish_debug.h index d4c0bab..d7dea23 100644 --- a/STM32F4/cores/maple/wirish_debug.h +++ b/STM32F4/cores/maple/wirish_debug.h @@ -24,6 +24,9 @@ * SOFTWARE. *****************************************************************************/ +#ifndef _WIRISH_DEBUG_H_ +#define _WIRISH_DEBUG_H_ + /** * @file wirish_debug.h * @brief High level debug port configuration @@ -50,5 +53,7 @@ static inline void disableDebugPorts(void) { * @see disableDebugPorts() */ static inline void enableDebugPorts(void) { - afio_cfg_debug_ports(AFIO_DEBUG_FULL_SWJ); + afio_cfg_debug_ports(AFIO_DEBUG_SW_ONLY); //AFIO_DEBUG_FULL_SWJ); } + +#endif diff --git a/STM32F4/cores/maple/wirish_digital.cpp b/STM32F4/cores/maple/wirish_digital.cpp index a8b3ad8..4a65619 100644 --- a/STM32F4/cores/maple/wirish_digital.cpp +++ b/STM32F4/cores/maple/wirish_digital.cpp @@ -29,7 +29,7 @@ */ #include "wirish.h" -#include "io.h" + void pinMode(uint8 pin, WiringPinMode mode) { gpio_pin_mode outputMode; @@ -72,7 +72,7 @@ void pinMode(uint8 pin, WiringPinMode mode) { return; } - gpio_set_mode(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit, outputMode); + gpio_set_mode(pin, outputMode); if (PIN_MAP[pin].timer_device != NULL) { /* Enable/disable timer channels if we're switching into or @@ -84,48 +84,51 @@ void pinMode(uint8 pin, WiringPinMode mode) { } -uint32 digitalRead(uint8 pin) { +uint32 digitalRead(uint8 pin) +{ if (pin >= BOARD_NR_GPIO_PINS) { return 0; } - return gpio_read_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit) ? + return gpio_read_pin(pin) ? HIGH : LOW; } -void digitalWrite(uint8 pin, uint8 val) { +void digitalWrite(uint8 pin, uint8 val) +{ if (pin >= BOARD_NR_GPIO_PINS) { return; } - gpio_write_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit, val); + gpio_write_pin(pin, val); } -void togglePin(uint8 pin) { +void togglePin(uint8 pin) +{ if (pin >= BOARD_NR_GPIO_PINS) { return; } - gpio_toggle_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit); + gpio_toggle_pin(pin); } #define BUTTON_DEBOUNCE_DELAY 1 -uint8 isButtonPressed() { - if (digitalRead(BOARD_BUTTON_PIN)) { +uint8 isButtonPressed(uint8_t button) { + if (digitalRead(button)) { delay(BUTTON_DEBOUNCE_DELAY); - while (digitalRead(BOARD_BUTTON_PIN)) + while (digitalRead(button)) ; return true; } return false; } -uint8 waitForButtonPress(uint32 timeout) { +uint8 waitForButtonPress(uint8_t button, uint32 timeout) { uint32 start = millis(); uint32 time; if (timeout == 0) { - while (!isButtonPressed()) + while (!isButtonPressed(button)) ; return true; } @@ -136,6 +139,6 @@ uint8 waitForButtonPress(uint32 timeout) { time - start > timeout) { return false; } - } while (!isButtonPressed()); + } while (!isButtonPressed(button)); return true; } diff --git a/STM32F4/cores/maple/wirish_math.h b/STM32F4/cores/maple/wirish_math.h index a85b30a..0b8b222 100644 --- a/STM32F4/cores/maple/wirish_math.h +++ b/STM32F4/cores/maple/wirish_math.h @@ -29,8 +29,8 @@ * @brief Includes ; provides Arduino-compatible math routines. */ -#ifndef _WIRING_MATH_H_ -#define _WIRING_MATH_H_ +#ifndef _WIRISH_MATH_H_ +#define _WIRISH_MATH_H_ #include diff --git a/STM32F4/cores/maple/wirish_time.cpp b/STM32F4/cores/maple/wirish_time.cpp index 270da28..654c1a2 100644 --- a/STM32F4/cores/maple/wirish_time.cpp +++ b/STM32F4/cores/maple/wirish_time.cpp @@ -28,10 +28,10 @@ * @brief Delay implementation. */ -#include "libmaple.h" -#include "systick.h" +#include +#include #include "wirish_time.h" -#include "delay.h" +#include void delay(unsigned long ms) { uint32 i; diff --git a/STM32F4/cores/maple/wirish_time.h b/STM32F4/cores/maple/wirish_time.h index 20a2fbf..3a11786 100644 --- a/STM32F4/cores/maple/wirish_time.h +++ b/STM32F4/cores/maple/wirish_time.h @@ -32,10 +32,9 @@ #ifndef __WIRISH_TIME_H_ #define __WIRISH_TIME_H_ -#include "libmaple.h" -#include "nvic.h" -#include "systick.h" #include "boards.h" +#include +#include #define US_PER_MS 1000 diff --git a/STM32F4/cores/maple/wirish_types.h b/STM32F4/cores/maple/wirish_types.h index a3c260a..de685bf 100644 --- a/STM32F4/cores/maple/wirish_types.h +++ b/STM32F4/cores/maple/wirish_types.h @@ -30,14 +30,13 @@ * @brief Wirish library type definitions. */ -#include "libmaple_types.h" -#include "gpio.h" -#include "timer.h" -#include "adc.h" - #ifndef _WIRISH_TYPES_H_ #define _WIRISH_TYPES_H_ +#include +#include +#include + /** * Invalid stm32_pin_info adc_channel value. * @see stm32_pin_info @@ -48,16 +47,28 @@ * @brief Stores STM32-specific information related to a given Maple pin. * @see PIN_MAP */ +#ifdef BOARD_generic_f407v +// restructure members to build consecutive pairs typedef struct stm32_pin_info { - gpio_dev *gpio_device; /**< Maple pin's GPIO device */ - timer_dev *timer_device; /**< Pin's timer device, if any. */ - const adc_dev *adc_device; /**< ADC device, if any. */ - uint8 gpio_bit; /**< Pin's GPIO port bit. */ + const gpio_dev * gpio_device; /**< Maple pin's GPIO device */ + timer_dev * timer_device; /**< Pin's timer device, if any. */ uint8 timer_channel; /**< Timer channel, or 0 if none. */ uint8 adc_channel; /**< Pin ADC channel, or ADCx if none. */ - uint8 filler; + const adc_dev *adc_device; /**< ADC device, if any. */ } stm32_pin_info; +#else + +typedef struct stm32_pin_info { + const gpio_dev *gpio_device; /**< Maple pin's GPIO device */ + timer_dev *timer_device; /**< Pin's timer device, if any. */ + const adc_dev *adc_device; /**< ADC device, if any. */ + uint8 timer_channel; /**< Timer channel, or 0 if none. */ + uint8 adc_channel; /**< Pin ADC channel, or ADCx if none. */ +} stm32_pin_info; + +#endif + /** * Variable attribute, instructs the linker to place the marked * variable in Flash instead of RAM. */ diff --git a/STM32F4/libraries/SPI/library.properties b/STM32F4/libraries/SPI/library.properties index 6f20f01..ba3a577 100644 --- a/STM32F4/libraries/SPI/library.properties +++ b/STM32F4/libraries/SPI/library.properties @@ -7,3 +7,4 @@ paragraph=SPI for STM32F4 category=Communication url= architectures=STM32F4 +maintainer= \ No newline at end of file diff --git a/STM32F4/libraries/SPI/src/SPI.cpp b/STM32F4/libraries/SPI/src/SPI.cpp index 08fbbd5..cb8f561 100644 --- a/STM32F4/libraries/SPI/src/SPI.cpp +++ b/STM32F4/libraries/SPI/src/SPI.cpp @@ -40,9 +40,9 @@ #include "wirish.h" #include "boards.h" -//#include "HardwareSerial.h" +#define DMA_TIMEOUT 100 -#if CYCLES_PER_MICROSECOND != 72 +#if CYCLES_PER_MICROSECOND != 168 /* TODO [0.2.0?] something smarter than this */ #warning "Unexpected clock speed; SPI frequency calculation will be incorrect" #endif @@ -91,77 +91,115 @@ static const spi_pins board_spi_pins[] __FLASH__ = { */ SPIClass::SPIClass(uint32 spi_num) { + + _currentSetting=&_settings[spi_num-1];// SPI channels are called 1 2 and 3 but the array is zero indexed + + switch (spi_num) { #if BOARD_NR_SPI >= 1 case 1: - this->spi_d = SPI1; + _currentSetting->spi_d = SPI1; break; #endif #if BOARD_NR_SPI >= 2 case 2: - this->spi_d = SPI2; + _currentSetting->spi_d = SPI2; break; #endif #if BOARD_NR_SPI >= 3 case 3: - this->spi_d = SPI3; + _currentSetting->spi_d = SPI3; break; #endif default: ASSERT(0); } - //pinMode(BOARD_SPI_DEFAULT_SS,OUTPUT); - - clockDivider = SPI_BAUD_PCLK_DIV_16; - dataMode = SPI_MODE0; + // Init things specific to each SPI device + // clock divider setup is a bit of hack, and needs to be improved at a later date. +/*****************************************************************************/ +// DMA / Channel / Stream +// Rx Tx +// SPI1: 2 / 3 / 0 (2) - 2 / 3 / 3 (5) +// SPI2: 1 / 0 / 3 - 1 / 0 / 4 +// SPI3: 1 / 0 / 0 (2) - 1 / 0 / 5 (7) +/*****************************************************************************/ + _settings[0].spi_d = SPI1; + _settings[0].clockDivider = determine_baud_rate(_settings[0].spi_d, _settings[0].clock); +#ifdef SPI_DMA + _settings[0].spiDmaDev = DMA2; + _settings[0].spiDmaChannel = DMA_CH3; + _settings[0].spiRxDmaStream = DMA_STREAM0; // alternative: DMA_STREAM2 + _settings[0].spiTxDmaStream = DMA_STREAM3; // alternative: DMA_STREAM5 +#endif + _settings[1].spi_d = SPI2; + _settings[1].clockDivider = determine_baud_rate(_settings[1].spi_d, _settings[1].clock); +#ifdef SPI_DMA + _settings[1].spiDmaDev = DMA1; + _settings[1].spiDmaChannel = DMA_CH0; + _settings[1].spiRxDmaStream = DMA_STREAM3; // alternative: - + _settings[1].spiTxDmaStream = DMA_STREAM4; // alternative: - +#endif +#if BOARD_NR_SPI >= 3 + _settings[2].spi_d = SPI3; + _settings[2].clockDivider = determine_baud_rate(_settings[2].spi_d, _settings[2].clock); +#ifdef SPI_DMA + _settings[2].spiDmaDev = DMA1; + _settings[2].spiDmaChannel = DMA_CH0; + _settings[2].spiRxDmaStream = DMA_STREAM0; // alternative: DMA_STREAM2 + _settings[2].spiTxDmaStream = DMA_STREAM5; // alternative: DMA_STREAM7 +#endif +#endif + } /* * Set up/tear down */ +void SPIClass::updateSettings(void) { + uint32 flags = ((_currentSetting->bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | _currentSetting->dataSize | SPI_SW_SLAVE | SPI_SOFT_SS); + #ifdef SPI_DEBUG + Serial.print("spi_master_enable("); Serial.print(_currentSetting->clockDivider); Serial.print(","); Serial.print(_currentSetting->dataMode); Serial.print(","); Serial.print(flags); Serial.println(")"); + #endif + spi_master_enable(_currentSetting->spi_d, (spi_baud_rate)_currentSetting->clockDivider, (spi_mode)_currentSetting->dataMode, flags); +} void SPIClass::begin(void) { - - uint32 flags = ((bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | SPI_DFF_8_BIT | SPI_SW_SLAVE | SPI_SOFT_SS); - spi_init(spi_d); - configure_gpios(spi_d, 1); - #ifdef SPI_DEBUG - Serial.print("spi_master_enable("); Serial.print(clockDivider); Serial.print(","); Serial.print(dataMode); Serial.print(","); Serial.print(flags); Serial.println(")"); - #endif - spi_master_enable(spi_d, (spi_baud_rate)clockDivider, (spi_mode)dataMode, flags); + spi_init(_currentSetting->spi_d); + configure_gpios(_currentSetting->spi_d, 1); + updateSettings(); +#ifdef SPI_USE_DMA_BUFFER + dmaSendBufferInit(); +#endif +//Serial.println("SPI class begin - end"); } void SPIClass::beginSlave(void) { - if (dataMode >= 4) { - ASSERT(0); - return; - } - uint32 flags = ((bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | SPI_DFF_8_BIT | SPI_SW_SLAVE); - spi_init(spi_d); - configure_gpios(spi_d, 0); + 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_RX_ONLY); #ifdef SPI_DEBUG - Serial.print("spi_slave_enable("); Serial.print(dataMode); Serial.print(","); Serial.print(flags); Serial.println(")"); + Serial.print("spi_slave_enable("); Serial.print(_currentSetting->dataMode); Serial.print(","); Serial.print(flags); Serial.println(")"); #endif - spi_slave_enable(spi_d, (spi_mode)dataMode, flags); + spi_slave_enable(_currentSetting->spi_d, (spi_mode)_currentSetting->dataMode, flags); } void SPIClass::end(void) { - if (!spi_is_enabled(this->spi_d)) { + if (!spi_is_enabled(_currentSetting->spi_d)) { return; } // Follows RM0008's sequence for disabling a SPI in master/slave // full duplex mode. - while (spi_is_rx_nonempty(this->spi_d)) { + while (spi_is_rx_nonempty(_currentSetting->spi_d)) { // FIXME [0.1.0] remove this once you have an interrupt based driver - volatile uint16 rx __attribute__((unused)) = spi_rx_reg(this->spi_d); + volatile uint16 rx __attribute__((unused)) = spi_rx_reg(_currentSetting->spi_d); } - while (!spi_is_tx_empty(this->spi_d)) + while (!spi_is_tx_empty(_currentSetting->spi_d)) ; - while (spi_is_busy(this->spi_d)) + while (spi_is_busy(_currentSetting->spi_d)) ; - spi_peripheral_disable(this->spi_d); + spi_peripheral_disable(_currentSetting->spi_d); } /* Roger Clark added 3 functions */ @@ -170,8 +208,9 @@ void SPIClass::setClockDivider(uint32_t clockDivider) #ifdef SPI_DEBUG Serial.print("Clock divider set to "); Serial.println(clockDivider); #endif - this->clockDivider = clockDivider; - this->begin(); + _currentSetting->clockDivider = clockDivider; + uint32 cr1 = _currentSetting->spi_d->regs->CR1 & ~(SPI_CR1_BR); + _currentSetting->spi_d->regs->CR1 = cr1 | (clockDivider & SPI_CR1_BR); } void SPIClass::setBitOrder(BitOrder bitOrder) @@ -179,8 +218,10 @@ void SPIClass::setBitOrder(BitOrder bitOrder) #ifdef SPI_DEBUG Serial.print("Bit order set to "); Serial.println(bitOrder); #endif - this->bitOrder = bitOrder; - this->begin(); + _currentSetting->bitOrder = bitOrder; + uint32 cr1 = _currentSetting->spi_d->regs->CR1 & ~(SPI_CR1_LSBFIRST); + if ( bitOrder==LSBFIRST ) cr1 |= SPI_CR1_LSBFIRST; + _currentSetting->spi_d->regs->CR1 = cr1; } /* Victor Perez. Added to test changing datasize from 8 to 16 bit modes on the fly. @@ -189,11 +230,11 @@ void SPIClass::setBitOrder(BitOrder bitOrder) */ void SPIClass::setDataSize(uint32 datasize) { - uint32 cr1 = this->spi_d->regs->CR1; - datasize &= SPI_CR1_DFF; - cr1 &= ~(SPI_CR1_DFF); - cr1 |= datasize; - this->spi_d->regs->CR1 = cr1; + _currentSetting->dataSize = datasize; + 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) @@ -212,13 +253,11 @@ SPI Mode CPOL CPHA Shift SCK-edge Capture SCK-edge On the STM32 it appears to be bit 1 - CPOL : Clock polarity - (This bit should not be changed when communication is ongoing) 0 : CLK to 0 when idle 1 : CLK to 1 when idle bit 0 - CPHA : Clock phase - (This bit should not be changed when communication is ongoing) 0 : The first clock transition is the first data capture edge 1 : The second clock transition is the first data capture edge @@ -228,44 +267,32 @@ If someone finds this is not the case or sees a logic error with this let me kno #ifdef SPI_DEBUG Serial.print("Data mode set to "); Serial.println(dataMode); #endif - this->dataMode = dataMode; - this->begin(); -} - + _currentSetting->dataMode = dataMode; + uint32 cr1 = _currentSetting->spi_d->regs->CR1 & ~(SPI_CR1_CPOL|SPI_CR1_CPHA); + _currentSetting->spi_d->regs->CR1 = cr1 | (dataMode & (SPI_CR1_CPOL|SPI_CR1_CPHA)); +} 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); - setClockDivider(determine_baud_rate(spi_d, settings.clock)); + setDataSize(settings.dataSize); + setClockDivider(determine_baud_rate(_currentSetting->spi_d, settings.clock)); begin(); -#if 0 -// code from SAM core - uint8_t mode = interruptMode; - if (mode > 0) { - if (mode < 16) { - if (mode & 1) PIOA->PIO_IDR = interruptMask[0]; - if (mode & 2) PIOB->PIO_IDR = interruptMask[1]; - if (mode & 4) PIOC->PIO_IDR = interruptMask[2]; - if (mode & 8) PIOD->PIO_IDR = interruptMask[3]; - } else { - interruptSave = interruptsStatus(); - noInterrupts(); - } - } - uint32_t ch = BOARD_PIN_TO_SPI_CHANNEL(pin); - bitOrder[ch] = settings.border; - SPI_ConfigureNPCS(spi, ch, settings.config); - //setBitOrder(pin, settings.border); - //setDataMode(pin, settings.datamode); - //setClockDivider(pin, settings.clockdiv); -#endif +} + +void SPIClass::beginTransactionSlave(SPISettings settings) +{ + #ifdef SPI_DEBUG + Serial.println(F("SPIClass::beginTransactionSlave")); + #endif + setBitOrder(settings.bitOrder); + setDataMode(settings.dataMode); + setDataSize(settings.dataSize); + beginSlave(); } void SPIClass::endTransaction(void) @@ -295,131 +322,154 @@ void SPIClass::endTransaction(void) * I/O */ -uint8 SPIClass::read(void) { - uint8 buf[1]; - this->read(buf, 1); - return buf[0]; +uint16 SPIClass::read(void) +{ + while ( spi_is_rx_nonempty(_currentSetting->spi_d)==0 ) ; + return (uint16)spi_rx_reg(_currentSetting->spi_d); } -void SPIClass::read(uint8 *buf, uint32 len) { - uint32 rxed = 0; - while (rxed < len) { - while (!spi_is_rx_nonempty(this->spi_d)) - ; - buf[rxed++] = (uint8)spi_rx_reg(this->spi_d); - } +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; + // 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) { - #ifdef SPI_DEBUG -// Serial.print("SPIClass::write("); Serial.print(data); Serial.println(")"); - #endif - // 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(this->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(this->spi_d) == 0); // "5. Wait until TXE=1 ..." - while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." + 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." } -//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(this->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(this->spi_d) == 0); // "5. Wait until TXE=1 ..." -// while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." -//} - -void SPIClass::write(const uint8 *data, uint32 length) { - #ifdef SPI_DEBUG - Serial.print("SPIClass::write(data, "); Serial.print(length); Serial.println(")"); - #endif - uint32 txed = 0; - while (txed < length) { - txed += spi_tx(this->spi_d, data + txed, length - txed); - } - while (spi_is_tx_empty(this->spi_d) == 0); // "4. After writing the last data item into the SPI_DR register, wait until TXE=1 ..." - while (spi_is_busy(this->spi_d) != 0); // "... then wait until BSY=0, this indicates that the transmission of the last data is complete." +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 } -uint8 SPIClass::transfer(uint8 byte) const { - #ifdef SPI_DEBUG -// Serial.print("SPIClass::transfer("); Serial.print(byte); Serial.println(")"); - #endif - uint8 b; - spi_tx_reg(this->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(this->spi_d) == 0); // "4. Wait until RXNE=1 ..." - b = spi_rx_reg(this->spi_d); // "... and read the last received data." - while (spi_is_tx_empty(this->spi_d) == 0); // "5. Wait until TXE=1 ..." - while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." - return b; +void SPIClass::write(void *data, uint32 length) +{ + 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_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_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." +} + +#ifdef SPI_DMA /* 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; - if (spi_is_rx_nonempty(this->spi_d) == 1) b = spi_rx_reg(this->spi_d); //Clear the RX buffer in case a byte is waiting on it. - dma1_ch3_Active=true; - dma_init(DMA1); - dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event); - + + uint8 b = 0; + + dma_init(_currentSetting->spiDmaDev); +// dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event); // RX - spi_rx_dma_enable(SPI1); - dma_setup_transfer(DMA1, DMA_CH2, &SPI1->regs->DR, DMA_SIZE_8BITS, - receiveBuf, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_TRNS_CMPLT));// receive buffer DMA - dma_set_num_transfers(DMA1, DMA_CH2, length); - + dma_xfer_size dma_bit_size = (_currentSetting->dataSize==SPI_DATA_SIZE_16BIT) ? DMA_SIZE_16BITS : DMA_SIZE_8BITS; + dma_setup_transfer( _currentSetting->spiDmaDev, + _currentSetting->spiRxDmaStream, + _currentSetting->spiDmaChannel, + dma_bit_size, + &_currentSetting->spi_d->regs->DR, // peripheral address + receiveBuf, // memory bank 0 address + NULL, // memory bank 1 address + (DMA_MINC_MODE | DMA_FROM_PER | DMA_PRIO_VERY_HIGH) // flags + ); + dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaStream, length); + dma_set_fifo_flags(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaStream, 0); + dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaStream); + // TX - spi_tx_dma_enable(SPI1); - if (!transmitBuf) { - static uint8_t ff = 0XFF; - transmitBuf = &ff; - dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_8BITS, - transmitBuf, DMA_SIZE_8BITS, (DMA_FROM_MEM | DMA_TRNS_CMPLT));// Transmit FF repeatedly + uint32 flags = (DMA_MINC_MODE | DMA_FROM_MEM); // | DMA_TRNS_CMPLT); + if ( transmitBuf==0 ) { + static uint8_t ff = 0XFF; + transmitBuf = &ff; + flags &= ~((uint32)DMA_MINC_MODE); // remove increment mode } - else { - dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_8BITS, - transmitBuf, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_FROM_MEM | DMA_TRNS_CMPLT));// Transmit buffer DMA - } - dma_set_num_transfers(DMA1, DMA_CH3, length); - - dma_enable(DMA1, DMA_CH2);// enable receive - dma_enable(DMA1, DMA_CH3);// enable transmit + dma_setup_transfer( _currentSetting->spiDmaDev, + _currentSetting->spiTxDmaStream, + _currentSetting->spiDmaChannel, + dma_bit_size, + &_currentSetting->spi_d->regs->DR, // peripheral address + transmitBuf, // memory bank 0 address + NULL, // memory bank 1 address + flags + ); + dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream, length); + dma_set_fifo_flags(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream, 0); + dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream); + // software enable sequence, see AN4031, chapter 4.3 + dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaStream);// enable receive + dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream);// 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 -// while (dma1_ch3_Active); -// if (receiveBuf) { uint32_t m = millis(); - while (dma1_ch3_Active) { - if ((millis() - m) > 100) { - dma1_ch3_Active = 0; - b = 2; - break; - } + while ((b = dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream) & DMA_ISR_TCIF)==0 ) {// wait for completion flag to be set + if ( b&(DMA_ISR_TEIF|DMA_ISR_DMEIF|DMA_ISR_FEIF) ) { b = 1; break; } // break on any error flag + if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; } } + if (b & DMA_ISR_TCIF) b = 0; -// } - while (spi_is_tx_empty(this->spi_d) == 0); // "5. Wait until TXE=1 ..." - while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." - dma_disable(DMA1, DMA_CH3); - dma_disable(DMA1, DMA_CH2); - spi_rx_dma_disable(SPI1); - spi_tx_dma_disable(SPI1); + 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." + // software disable sequence, see AN4031, chapter 4.1 + spi_tx_dma_disable(_currentSetting->spi_d); + spi_rx_dma_disable(_currentSetting->spi_d); + dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaStream); + dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream); return b; } @@ -427,56 +477,45 @@ 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, 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(DMA1); - dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event); - + uint8 b = 0; + dma_init(_currentSetting->spiDmaDev); // TX - spi_tx_dma_enable(SPI1); - dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_8BITS, - transmitBuf, DMA_SIZE_8BITS, flags);// Transmit buffer DMA - dma_set_num_transfers(DMA1, DMA_CH3, length); - dma_enable(DMA1, DMA_CH3);// enable transmit - - while (dma1_ch3_Active); - while (spi_is_rx_nonempty(this->spi_d) == 0); // "4. Wait until RXNE=1 ..." - b = spi_rx_reg(this->spi_d); // "... and read the last received data." - while (spi_is_tx_empty(this->spi_d) == 0); // "5. Wait until TXE=1 ..." - while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." - dma_disable(DMA1, DMA_CH3); - spi_tx_dma_disable(SPI1); - return b; -} + dma_xfer_size dma_bit_size = (_currentSetting->dataSize==SPI_DATA_SIZE_16BIT) ? DMA_SIZE_16BITS : DMA_SIZE_8BITS; + dma_setup_transfer( _currentSetting->spiDmaDev, + _currentSetting->spiTxDmaStream, + _currentSetting->spiDmaChannel, + dma_bit_size, + &_currentSetting->spi_d->regs->DR, // peripheral address + transmitBuf, // memory bank 0 address + NULL, // memory bank 1 address + ( (DMA_MINC_MODE*minc) | DMA_FROM_MEM ) //| DMA_TRNS_CMPLT ) // flags + );// Transmit buffer DMA + dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream, length); + dma_set_fifo_flags(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream, 0); + dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream); + dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream);// enable transmit + spi_tx_dma_enable(_currentSetting->spi_d); -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(DMA1); - dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event); + uint32_t m = millis(); + while ((b = dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream) & DMA_ISR_TCIF)==0 ) {// wait for completion flag to be set + if ( b&(DMA_ISR_TEIF|DMA_ISR_DMEIF|DMA_ISR_FEIF) ) { b = 1; break; } // break on any error flag + if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; } + } + if (b & DMA_ISR_TCIF) b = 0; - // TX - spi_tx_dma_enable(SPI1); - dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_16BITS, - transmitBuf, DMA_SIZE_16BITS, flags);// Transmit buffer DMA - dma_set_num_transfers(DMA1, DMA_CH3, length); - dma_enable(DMA1, DMA_CH3);// enable transmit - - while (dma1_ch3_Active); - while (spi_is_rx_nonempty(this->spi_d) == 0); // "4. Wait until RXNE=1 ..." - b = spi_rx_reg(this->spi_d); // "... and read the last received data." - while (spi_is_tx_empty(this->spi_d) == 0); // "5. Wait until TXE=1 ..." - while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." - dma_disable(DMA1, DMA_CH3); - spi_tx_dma_disable(SPI1); - 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." + spi_tx_dma_disable(_currentSetting->spi_d); + dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream); + return b; } +#endif + void SPIClass::attachInterrupt(void) { @@ -492,19 +531,19 @@ void SPIClass::detachInterrupt(void) { */ uint8 SPIClass::misoPin(void) { - return dev_to_spi_pins(this->spi_d)->miso; + return dev_to_spi_pins(_currentSetting->spi_d)->miso; } uint8 SPIClass::mosiPin(void) { - return dev_to_spi_pins(this->spi_d)->mosi; + return dev_to_spi_pins(_currentSetting->spi_d)->mosi; } uint8 SPIClass::sckPin(void) { - return dev_to_spi_pins(this->spi_d)->sck; + return dev_to_spi_pins(_currentSetting->spi_d)->sck; } uint8 SPIClass::nssPin(void) { - return dev_to_spi_pins(this->spi_d)->nss; + return dev_to_spi_pins(_currentSetting->spi_d)->nss; } /* @@ -512,18 +551,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) { @@ -585,29 +619,26 @@ static void configure_gpios(spi_dev *dev, bool as_master) { if(dev->clk_id <= RCC_SPI2) { if(nssi) { if(!as_master) { - gpio_set_af_mode(nssi->gpio_device, scki->gpio_bit, 5); + gpio_set_af_mode(pins->nss, 5); } } - gpio_set_af_mode(scki->gpio_device, scki->gpio_bit, 5); - gpio_set_af_mode(misoi->gpio_device, misoi->gpio_bit, 5); - gpio_set_af_mode(mosii->gpio_device, mosii->gpio_bit, 5); + gpio_set_af_mode(pins->sck, 5); + gpio_set_af_mode(pins->miso, 5); + gpio_set_af_mode(pins->mosi, 5); } else { if(nssi) { if(!as_master) { - gpio_set_af_mode(nssi->gpio_device, scki->gpio_bit, 6); + gpio_set_af_mode(pins->nss, 6); } } - gpio_set_af_mode(scki->gpio_device, scki->gpio_bit, 6); - gpio_set_af_mode(misoi->gpio_device, misoi->gpio_bit, 6); - gpio_set_af_mode(mosii->gpio_device, mosii->gpio_bit, 6); + gpio_set_af_mode(pins->sck, 6); + gpio_set_af_mode(pins->miso, 6); + gpio_set_af_mode(pins->mosi, 6); } #endif - spi_config_gpios(dev, as_master, nssi->gpio_device, nssi->gpio_bit, - scki->gpio_device, scki->gpio_bit, - misoi->gpio_device, misoi->gpio_bit, - mosii->gpio_device, mosii->gpio_bit); + spi_config_gpios(dev, as_master, pins->nss, pins->sck, pins->miso, pins->mosi); } static const spi_baud_rate baud_rates[8] __FLASH__ = { @@ -634,6 +665,8 @@ static spi_baud_rate determine_baud_rate(spi_dev *dev, uint32_t freq) { { case RCC_APB2: clock = STM32_PCLK2; break; // 72 Mhz case RCC_APB1: clock = STM32_PCLK1; break; // 36 Mhz + case RCC_AHB1: break; + default: break; } clock /= 2; i = 0; @@ -646,4 +679,3 @@ static spi_baud_rate determine_baud_rate(spi_dev *dev, uint32_t freq) { //SPIClass SPI(3); - diff --git a/STM32F4/libraries/SPI/src/SPI.h b/STM32F4/libraries/SPI/src/SPI.h index 490d58b..cabc0c2 100644 --- a/STM32F4/libraries/SPI/src/SPI.h +++ b/STM32F4/libraries/SPI/src/SPI.h @@ -34,18 +34,16 @@ /* TODO [0.1.0] Remove deprecated methods. */ - -#ifndef _SPI_H_INCLUDED -#define _SPI_H_INCLUDED +#ifndef _LIB_SPI_H_ +#define _LIB_SPI_H_ #include #include #include - -#include -#include #include +#define SPI_DMA + // SPI_HAS_TRANSACTION means SPI has // - beginTransaction() // - endTransaction() @@ -96,34 +94,61 @@ #define SPI_MODE2 SPI_MODE_2 #define SPI_MODE3 SPI_MODE_3 +#define SPI_DATA_SIZE_8BIT SPI_CR1_DFF_8_BIT +#define SPI_DATA_SIZE_16BIT SPI_CR1_DFF_16_BIT + class SPISettings { public: SPISettings(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) { if (__builtin_constant_p(clock)) { - init_AlwaysInline(clock, bitOrder, dataMode); + init_AlwaysInline(clock, bitOrder, dataMode, SPI_DATA_SIZE_8BIT); } else { - init_MightInline(clock, bitOrder, dataMode); + init_MightInline(clock, bitOrder, dataMode, SPI_DATA_SIZE_8BIT); } } - SPISettings() { init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0); } -private: - void init_MightInline(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) { - init_AlwaysInline(clock, bitOrder, dataMode); + SPISettings(uint32_t clock, BitOrder bitOrder, uint8_t dataMode, uint32_t dataSize) { + if (__builtin_constant_p(clock)) { + init_AlwaysInline(clock, bitOrder, dataMode, dataSize); + } else { + init_MightInline(clock, bitOrder, dataMode, dataSize); + } } - void init_AlwaysInline(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) __attribute__((__always_inline__)) { + SPISettings(uint32_t clock) { + if (__builtin_constant_p(clock)) { + init_AlwaysInline(clock, MSBFIRST, SPI_MODE0, SPI_DATA_SIZE_8BIT); + } else { + init_MightInline(clock, MSBFIRST, SPI_MODE0, SPI_DATA_SIZE_8BIT); + } + } + SPISettings() { init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0, SPI_DATA_SIZE_8BIT); } +private: + void init_MightInline(uint32_t clock, BitOrder bitOrder, uint8_t dataMode, uint32_t dataSize) { + init_AlwaysInline(clock, bitOrder, dataMode, dataSize); + } + void init_AlwaysInline(uint32_t clock, BitOrder bitOrder, uint8_t dataMode, uint32_t dataSize) __attribute__((__always_inline__)) { this->clock = clock; this->bitOrder = bitOrder; this->dataMode = dataMode; + this->dataSize = dataSize; } uint32_t clock; BitOrder bitOrder; uint8_t dataMode; + uint32_t dataSize; + + spi_dev *spi_d; + uint32_t clockDivider; + +#ifdef SPI_DMA + dma_dev* spiDmaDev; + dma_channel spiDmaChannel; + dma_stream spiRxDmaStream, spiTxDmaStream; +#endif + friend class SPIClass; }; -volatile static bool dma1_ch3_Active; - /** * @brief Wirish SPI interface. * @@ -133,18 +158,11 @@ volatile static bool dma1_ch3_Active; class SPIClass { public: - - /** * @param spiPortNumber Number of the SPI port to manage. */ SPIClass(uint32 spiPortNumber); - /* - * Set up/tear down - */ - - /** * @brief Equivalent to begin(SPI_1_125MHZ, MSBFIRST, 0). @@ -175,6 +193,8 @@ public: void beginTransaction(uint8_t pin, SPISettings settings); void endTransaction(void); + void beginTransactionSlave(SPISettings settings); + void setClockDivider(uint32_t clockDivider); void setBitOrder(BitOrder bitOrder); void setDataMode(uint8_t dataMode); @@ -195,40 +215,40 @@ 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(const uint8 *buffer, uint32 length); + 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(void * buffer, uint32 length); /** * @brief Transmit a byte, then return the next unread byte. @@ -239,9 +259,12 @@ public: * @return Next unread byte. */ uint8 transfer(uint8 data) const; + uint16_t transfer16(uint16_t data) const; +#ifdef SPI_DMA /** * @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. * @@ -249,30 +272,19 @@ 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, bool minc = 1); +#endif /* * Pin accessors @@ -304,7 +316,24 @@ public: * @brief Get a pointer to the underlying libmaple spi_dev for * this HardwareSPI instance. */ - spi_dev* c_dev(void) { return this->spi_d; } + spi_dev* c_dev(void) { return _currentSetting->spi_d; } + + + spi_dev *dev(){ return _currentSetting->spi_d;} + + /** + * @brief Sets the number of the SPI peripheral to be used by + * this HardwareSPI instance. + * + * @param spi_num Number of the SPI port. 1-2 in low density devices + * or 1-3 in high density devices. + */ + + void setModule(int spi_num) + { + _currentSetting=&_settings[spi_num-1];// SPI channels are called 1 2 and 3 but the array is zero indexed + } + /* -- The following methods are deprecated --------------------------- */ @@ -338,26 +367,13 @@ public: */ uint8 recv(void); - spi_dev *dev(){ return spi_d;} - - - private: - - static inline void DMA1_CH3_Event() { - dma1_ch3_Active = 0; -// dma_disable(DMA1, DMA_CH3); -// dma_disable(DMA1, DMA_CH2); - - // To Do. Need to wait for - } - spi_dev *spi_d; - uint8_t _SSPin; - uint32_t clockDivider; - uint8_t dataMode; - BitOrder bitOrder; + SPISettings _settings[BOARD_NR_SPI]; + SPISettings *_currentSetting; + + void updateSettings(void); }; +extern SPIClass SPI; // needed bx SdFat(EX) lib -extern SPIClass SPI;//(1);// dummy params #endif diff --git a/STM32F4/platform.txt b/STM32F4/platform.txt index 99ae555..2bb1946 100755 --- a/STM32F4/platform.txt +++ b/STM32F4/platform.txt @@ -8,17 +8,15 @@ version=0.1.0 # compiler variables # ---------------------- -#build.gcc_ver=gcc-arm-none-eabi-4.8.3-2014q1 - 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 -Wall -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 -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 -Wall -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 @@ -30,6 +28,8 @@ compiler.size.cmd=arm-none-eabi-size compiler.define=-DARDUINO= # this can be overriden in boards.txt +build.f_cpu=168000000L +build.mcu=cortex-m4 build.cpu_flags= build.hs_flag= build.common_flags=-mthumb -D__STM32F4__ @@ -44,12 +44,10 @@ compiler.ar.extra_flags= compiler.elf2hex.extra_flags= +##compiler.libs.c.flags="-I{build.system.path}/libmaple" "-I{build.system.path}/libmaple/include" "-I{build.system.path}/libmaple/stm32f1/include" "-I{build.system.path}/libmaple/usb/stm32f1" "-I{build.system.path}/libmaple/usb/usb_lib" +#compiler.libs.c.flags="-I{build.core.path}" "-I{build.core.path}/libmaple" "-I{build.core.path}/libmaple/usbF4" "-I{build.core.path}/libmaple/usbF4/STM32_USB_Device_Library/Core/inc" "-I{build.core.path}/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/inc" "-I{build.core.path}/libmaple/usbF4/STM32_USB_OTG_Driver/inc" "-I{build.core.path}/libmaple/usbF4/VCP" +compiler.libs.c.flags="-I{build.system.path}/libmaple" "-I{build.core.path}/libmaple/usbF4" -##compiler.libs.c.flags="-I{build.system.path}/libmaple" "-I{build.system.path}/libmaple/include" "-I{build.system.path}/libmaple/stm32f1/include" "-I{build.system.path}/libmaple/stm32f1/include/series" "-I{build.system.path}/libmaple/usb/stm32f1" "-I{build.system.path}/libmaple/usb/usb_lib" -#compiler.libs.c.flags="-I{build.system.path}/libmaple" "-I{build.system.path}/libmaple/include" "-I{build.system.path}/libmaple/stm32f1/include" "-I{build.system.path}/libmaple/usb/stm32f1" "-I{build.system.path}/libmaple/usb/usb_lib" - - -compiler.libs.c.flags="-I{build.core.path}/libmaple" -I{build.core.path}/libmaple/usbF4 -I{build.core.path}/libmaple/usbF4/STM32_USB_Device_Library/Core/inc -I{build.core.path}/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/inc -I{build.core.path}/libmaple/usbF4/STM32_USB_OTG_Driver/inc -I{build.core.path}/libmaple/usbF4/VCP @@ -66,14 +64,13 @@ compiler.libs.c.flags="-I{build.core.path}/libmaple" -I{build.core.path}/libmapl # --------------------- ## Compile c files -recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.flags} -mcpu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.c.extra_flags} {build.extra_flags} {compiler.libs.c.flags} {includes} "{source_file}" -o "{object_file}" +recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.flags} -mcpu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.c.extra_flags} {build.extra_flags} {build.cpu_flags} {compiler.libs.c.flags} {includes} "{source_file}" -o "{object_file}" ## Compile c++ files recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} -mcpu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {build.cpu_flags} {build.hs_flag} {build.common_flags} {compiler.libs.c.flags} {includes} "{source_file}" -o "{object_file}" ## Compile S files recipe.S.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.S.flags} -mcpu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.S.extra_flags} {build.extra_flags} {build.cpu_flags} {build.hs_flag} {build.common_flags} {compiler.libs.c.flags} {includes} "{source_file}" -o "{object_file}" -#recipe.S.o.pattern="{compiler.path}{compiler.c.cmd}" "{source_file}" -o "{object_file}" ## Create archives recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{archive_file_path}" "{object_file}" @@ -92,7 +89,6 @@ recipe.objcopy.hex.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf ## Compute size recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.elf" -#recipe.size.regex=\.text\s+([0-9]+).* recipe.size.regex=^(?:\.text|\.rodata|\.ARM.exidx)\s+([0-9]+).* recipe.size.regex.data=^(?:\.data|\.bss|\.noinit)\s+([0-9]+).* diff --git a/STM32F4/cores/maple/libmaple/gpio.c b/STM32F4/system/libmaple/Arduino.h similarity index 79% rename from STM32F4/cores/maple/libmaple/gpio.c rename to STM32F4/system/libmaple/Arduino.h index 3792220..cef8f08 100644 --- a/STM32F4/cores/maple/libmaple/gpio.c +++ b/STM32F4/system/libmaple/Arduino.h @@ -1,7 +1,7 @@ /****************************************************************************** * The MIT License * - * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2010 LeafLabs LLC. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -24,13 +24,23 @@ * SOFTWARE. *****************************************************************************/ -/** - * @file gpio.c - * @brief GPIO initialization routine - */ +#ifndef _WIRISH_ARDUINO_H_ +#define _WIRISH_ARDUINO_H_ -// #ifdef STM32F2 -// #include "gpioF2.c" -// #else -// #include "gpioF1.c" -// #endif +//#warning Include Arduino.h from system\libmaple + +#include "wirish.h" + +void setup(); +void loop(); +#ifdef __cplusplus +extern "C"{ +#endif // __cplusplus +void yield(void); +#ifdef __cplusplus +} +#endif // __cplusplus + +#include "variant.h" + +#endif diff --git a/STM32F4/variants/generic_f407v/generic_f407v.cpp b/STM32F4/variants/generic_f407v/generic_f407v.cpp new file mode 100644 index 0000000..c51ff9b --- /dev/null +++ b/STM32F4/variants/generic_f407v/generic_f407v.cpp @@ -0,0 +1,81 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file generic_f407v.cpp + * @author ala42 + * @brief generic_f407v board file. + */ + +#ifdef BOARD_generic_f407v + +#include "generic_f407v.h" + +#include "wirish_types.h" + +//static void initSRAMChip(void); +/*****************************************************************************/ +// Alternate functions, see DocID022152 Rev 8, Table 9. +/*****************************************************************************/ +void boardInit(void) { +/* // remap TIMER8 to PC6-9 + gpio_set_af_mode(GPIOC, 6, 3); + gpio_set_af_mode(GPIOC, 7, 3); + gpio_set_af_mode(GPIOC, 8, 3); + gpio_set_af_mode(GPIOC, 9, 3); + + // remap TIMER1 to PE9,11,13,14 + gpio_set_af_mode(GPIOE, 9, 1); + gpio_set_af_mode(GPIOE, 11, 1); + gpio_set_af_mode(GPIOE, 13, 1); + gpio_set_af_mode(GPIOE, 14, 1); + + // remap TIMER3 to PB4,5,0,1 + gpio_set_af_mode(GPIOB, 4, 2); + gpio_set_af_mode(GPIOB, 5, 2); + gpio_set_af_mode(GPIOB, 0, 2); + gpio_set_af_mode(GPIOB, 1, 2); + + //gpio_set_af_mode(GPIOA, 2, 7); + //gpio_set_af_mode(GPIOA, 3, 7); +*/ + return; +} + +/* +static void initSRAMChip(void) { + fsmc_nor_psram_reg_map *regs = FSMC_NOR_PSRAM1_BASE; + + fsmc_sram_init_gpios(); + rcc_clk_enable(RCC_FSMC); + + regs->BCR = (FSMC_BCR_WREN | FSMC_BCR_MWID_16BITS | FSMC_BCR_MTYP_SRAM | + FSMC_BCR_MBKEN); + fsmc_nor_psram_set_addset(regs, 0); + fsmc_nor_psram_set_datast(regs, 3); +} +*/ +#endif diff --git a/STM32F4/variants/generic_f407v/generic_f407v.h b/STM32F4/variants/generic_f407v/generic_f407v.h new file mode 100644 index 0000000..927f9cd --- /dev/null +++ b/STM32F4/variants/generic_f407v/generic_f407v.h @@ -0,0 +1,163 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file generic_f407v.h + * @author Marti Bolivar + * @brief Private include file for Maple Native in boards.h + * + * See maple.h for more information on these definitions. + */ + +#ifndef _BOARD_GENERIC_F407V_H_ +#define _BOARD_GENERIC_F407V_H_ + +#define Port2Pin(port, bit) ((port-'A')*16+bit) + +#define CYCLES_PER_MICROSECOND 168 + + +#undef STM32_PCLK1 +#undef STM32_PCLK2 +#define STM32_PCLK1 (CYCLES_PER_MICROSECOND*1000000/4) +#define STM32_PCLK2 (CYCLES_PER_MICROSECOND*1000000/2) + +#define SYSTICK_RELOAD_VAL (CYCLES_PER_MICROSECOND*1000-1) + +/*****************************************************************************/ +// Board pin definitions +#define BOARD_USB_DM_PIN PA11 +#define BOARD_USB_DP_PIN PA12 + +#define BOARD_LED_PIN PA6 //Port2Pin('A', 6) +#define BOARD_LED2_PIN PA7 //Port2Pin('A', 7) +#define BOARD_BUTTON1_PIN PA0 //Port2Pin('A', 0) +#define BOARD_BUTTON2_PIN PE4 //Port2Pin('E', 4) +#define BOARD_BUTTON3_PIN PE3 //Port2Pin('E', 3) + +#define BOARD_NR_USARTS 5 +#define BOARD_USART1_TX_PIN PA9 //Port2Pin('A', 9) +#define BOARD_USART1_RX_PIN PA10 //Port2Pin('A',10) +#define BOARD_USART2_TX_PIN PA2 //Port2Pin('A', 2) +#define BOARD_USART2_RX_PIN PA3 //Port2Pin('A', 3) +#define BOARD_USART3_TX_PIN PB10 //Port2Pin('B',10) +#define BOARD_USART3_RX_PIN PB11 //Port2Pin('B',11) +#define BOARD_UART4_TX_PIN PA0 //Port2Pin('A', 0) +#define BOARD_UART4_RX_PIN PA1 //Port2Pin('A', 1) +#define BOARD_UART5_TX_PIN PC12 //Port2Pin('C',12) +#define BOARD_UART5_RX_PIN PD2 //Port2Pin('D', 2) + +#define BOARD_NR_SPI 3 +#define BOARD_SPI1_NSS_PIN PA4 //Port2Pin('A', 4) +#define BOARD_SPI1_SCK_PIN PA5 //Port2Pin('A', 5) +#define BOARD_SPI1_MISO_PIN PA6 //Port2Pin('A', 6) +#define BOARD_SPI1_MOSI_PIN PA7 //Port2Pin('A', 7) +#define BOARD_SPI1A_NSS_PIN PA15 //Port2Pin('A',15) +#define BOARD_SPI1A_SCK_PIN PB3 //Port2Pin('B', 3) +#define BOARD_SPI1A_MISO_PIN PB4 //Port2Pin('B', 4) +#define BOARD_SPI1A_MOSI_PIN PB5 //Port2Pin('B', 5) + +#define BOARD_SPI2_NSS_PIN PB12 //Port2Pin('B',12) +#define BOARD_SPI2_SCK_PIN PB13 //Port2Pin('B',13) +#define BOARD_SPI2_MISO_PIN PB14 //Port2Pin('B',14) +#define BOARD_SPI2_MOSI_PIN PB15 //Port2Pin('B',15) +#define BOARD_SPI2A_NSS_PIN PB9 //Port2Pin('B', 9) +#define BOARD_SPI2A_SCK_PIN PB10 //Port2Pin('B',10) +#define BOARD_SPI2A_MISO_PIN PC2 //Port2Pin('C', 2) +#define BOARD_SPI2A_MOSI_PIN pc3 //Port2Pin('C', 3) + +#define BOARD_SPI3_NSS_PIN PA15 //Port2Pin('A',15) +#define BOARD_SPI3_SCK_PIN PB3 //Port2Pin('B', 3) +#define BOARD_SPI3_MISO_PIN PB4 //Port2Pin('B', 4) +#define BOARD_SPI3_MOSI_PIN PB5 //Port2Pin('B', 5) +/* overlap with the SDIO interface for SD card +#define BOARD_SPI3A_NSS_PIN PA4 //Port2Pin('A', 4) +#define BOARD_SPI3A_SCK_PIN PC10 //Port2Pin('C',10) +#define BOARD_SPI3A_MISO_PIN PC11 //Port2Pin('C',11) +#define BOARD_SPI3A_MOSI_PIN PC12 //Port2Pin('C',12) +*/ +#define BOARD_SDIO_D0 PC8 //Port2Pin('C', 8) +#define BOARD_SDIO_D1 PC9 //Port2Pin('C', 9) +#define BOARD_SDIO_D2 PC10 //Port2Pin('C',10) +#define BOARD_SDIO_D3 PC11 //Port2Pin('C',11) +#define BOARD_SDIO_CK PC12 //Port2Pin('C',12) +#define BOARD_SDIO_CMD PD2 //Port2Pin('D', 2) + +#define BOARD_NR_GPIO_PINS 80 +#define BOARD_NR_PWM_PINS 22 +#define BOARD_NR_ADC_PINS 16 +#define BOARD_NR_USED_PINS 22 +#define BOARD_JTMS_SWDIO_PIN PA13 //Port2Pin('A',13) +#define BOARD_JTCK_SWCLK_PIN PA14 //Port2Pin('A',14) +#define BOARD_JTDI_PIN PA15 //Port2Pin('A',15) +#define BOARD_JTDO_PIN PB3 //Port2Pin('B', 3) +#define BOARD_NJTRST_PIN PB4 //Port2Pin('B', 4) + +/*****************************************************************************/ +// Pins reserved for the on-board hardware +#define USB_DM_PIN BOARD_USB_DM_PIN // PA11 +#define USB_DP_PIN BOARD_USB_DP_PIN // PA12 + +#define FLASH_CS_PIN PB0 +#define FLASH_CLK_PIN BOARD_SPI3_SCK_PIN // PB3 +#define FLASH_DO_PIN BOARD_SPI3_MISO_PIN // PB4 +#define FLASH_DI_PIN BOARD_SPI3_MOSI_PIN // PB5 + +#define NRF24_CLK_PIN BOARD_SPI3_SCK_PIN // PB3 +#define NRF24_DO_PIN BOARD_SPI3_MISO_PIN // PB4 +#define NRF24_DI_PIN BOARD_SPI3_MOSI_PIN // PB5 +#define NRF24_CE_PIN PB6 +#define NRF24_CS_PIN PB7 +#define NRF24_IRQ_PIN PB8 + +// SD card, SDIO mode +#define SD_DAT0 BOARD_SDIO_D0 // PC8 +#define SD_DAT1 BOARD_SDIO_D1 // PC9 +#define SD_DAT2 BOARD_SDIO_D2 // PC10 +#define SD_DAT3 BOARD_SDIO_D3 // PC11 +#define SD_CLK BOARD_SDIO_CK // PC12 +#define SD_CMD BOARD_SDIO_CMD // PD2 +// SD card, SPI mode, only usable with software SPI +#define SD_DI BOARD_SDIO_CMD // PD2 +#define SD_DO BOARD_SDIO_D0 // PC8 +#define SD_CS BOARD_SDIO_D3 // PC11 +#define SD_SCLK BOARD_SDIO_CK // PC12 + +/*****************************************************************************/ + +enum { +PA0,PA1,PA2,PA3,PA4,PA5,PA6,PA7,PA8,PA9,PA10,PA11,PA12,PA13,PA14,PA15, +PB0,PB1,PB2,PB3,PB4,PB5,PB6,PB7,PB8,PB9,PB10,PB11,PB12,PB13,PB14,PB15, +PC0,PC1,PC2,PC3,PC4,PC5,PC6,PC7,PC8,PC9,PC10,PC11,PC12,PC13,PC14,PC15, +PD0,PD1,PD2,PD3,PD4,PD5,PD6,PD7,PD8,PD9,PD10,PD11,PD12,PD13,PD14,PD15, +PE0,PE1,PE2,PE3,PE4,PE5,PE6,PE7,PE8,PE9,PE10,PE11,PE12,PE13,PE14,PE15, +#if 0 // not available on LQFP100 package +PF0,PF1,PF2,PF3,PF4,PF5,PF6,PF7,PF8,PF9,PF10,PF11,PF12,PF13,PF14,PF15, +PG0,PG1,PG2,PG3,PG4,PG5,PG6,PG7,PG8,PG9,PG10,PG11,PG12,PG13,PG14,PG15 +#endif // not available on LQFP100 package +}; + +#endif diff --git a/STM32F4/variants/generic_f407v/ld/common.inc b/STM32F4/variants/generic_f407v/ld/common.inc new file mode 100644 index 0000000..f5a0f5b --- /dev/null +++ b/STM32F4/variants/generic_f407v/ld/common.inc @@ -0,0 +1,219 @@ +/* + * Linker script for libmaple. + * + * Original author "lanchon" from ST forums, with modifications by LeafLabs. + */ + +OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") + +/* + * Configure other libraries we want in the link. + * + * libgcc, libc, and libm are common across supported toolchains. + * However, some toolchains require additional archives which aren't + * present everywhere (e.g. ARM's gcc-arm-embedded releases). + * + * To hack around this, we let the build system specify additional + * archives by putting the right extra_libs.inc (in a directory under + * toolchains/) in our search path. + */ +GROUP(libgcc.a libc.a libm.a) +INCLUDE extra_libs.inc + +/* + * These force the linker to search for vector table symbols. + * + * These symbols vary by STM32 family (and also within families). + * It's up to the build system to configure the link's search path + * properly for the target MCU. + */ +INCLUDE vector_symbols.inc + +/* STM32 vector table. */ +EXTERN(__stm32_vector_table) + +/* C runtime initialization function. */ +EXTERN(start_c) + +/* main entry point */ +EXTERN(main) + +/* Initial stack pointer value. */ +EXTERN(__msp_init) +PROVIDE(__msp_init = ORIGIN(ram) + LENGTH(ram)); + +/* Reset vector and chip reset entry point */ +EXTERN(__start__) +ENTRY(__start__) +PROVIDE(__exc_reset = __start__); + +/* Heap boundaries, for libmaple */ +EXTERN(_lm_heap_start); +EXTERN(_lm_heap_end); + +SECTIONS +{ + .text : + { + __text_start__ = .; + /* + * STM32 vector table. Leave this here. Yes, really. + */ + *(.stm32.interrupt_vector) + + /* + * Program code and vague linking + */ + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + *(.gnu.warning) + *(.glue_7t) *(.glue_7) *(.vfp11_veneer) + + *(.ARM.extab* .gnu.linkonce.armextab.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + . = ALIGN(4); + KEEP(*(.init)) + + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + + . = ALIGN(0x4); + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + + . = ALIGN(4); + KEEP(*(.fini)) + + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + } > REGION_TEXT + + /* + * End of text + */ + .text.align : + { + . = ALIGN(8); + __text_end__ = .; + } > REGION_TEXT + + /* + * .ARM.exidx exception unwinding; mandated by ARM's C++ ABI + */ + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > REGION_RODATA + __exidx_end = .; + + /* + * .data + */ + .data : + { + . = ALIGN(8); + __data_start__ = .; + + *(.got.plt) *(.got) + *(.data .data.* .gnu.linkonce.d.*) + + . = ALIGN(8); + __data_end__ = .; + } > REGION_DATA AT> REGION_RODATA + + /* + * Read-only data + */ + .rodata : + { + *(.rodata .rodata.* .gnu.linkonce.r.*) + /* .USER_FLASH: We allow users to allocate into Flash here */ + *(.USER_FLASH) + /* ROM image configuration; for C startup */ + . = ALIGN(4); + _lm_rom_img_cfgp = .; + LONG(LOADADDR(.data)); + /* + * Heap: Linker scripts may choose a custom heap by overriding + * _lm_heap_start and _lm_heap_end. Otherwise, the heap is in + * internal SRAM, beginning after .bss, and growing towards + * the stack. + * + * I'm shoving these here naively; there's probably a cleaner way + * to go about this. [mbolivar] + */ + _lm_heap_start = DEFINED(_lm_heap_start) ? _lm_heap_start : _end; + _lm_heap_end = DEFINED(_lm_heap_end) ? _lm_heap_end : __msp_init; + } > REGION_RODATA + + /* + * .bss + */ + .bss : + { + . = ALIGN(8); + __bss_start__ = .; + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN (8); + __bss_end__ = .; + _end = __bss_end__; + } > REGION_BSS + + /* + * Debugging sections + */ + .stab 0 (NOLOAD) : { *(.stab) } + .stabstr 0 (NOLOAD) : { *(.stabstr) } + /* DWARF debug sections. + * Symbols in the DWARF debugging sections are relative to the beginning + * of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + + .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) } + .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) } + /DISCARD/ : { *(.note.GNU-stack) } +} diff --git a/STM32F4/variants/generic_f407v/ld/extra_libs.inc b/STM32F4/variants/generic_f407v/ld/extra_libs.inc new file mode 100644 index 0000000..dd2c84f --- /dev/null +++ b/STM32F4/variants/generic_f407v/ld/extra_libs.inc @@ -0,0 +1,7 @@ +/* + * Extra archives needed by ARM's GCC ARM Embedded arm-none-eabi- + * releases (https://launchpad.net/gcc-arm-embedded/). + */ + +/* This is for the provided newlib. */ +GROUP(libnosys.a) diff --git a/STM32F4/variants/generic_f407v/ld/flash.ld b/STM32F4/variants/generic_f407v/ld/flash.ld new file mode 100644 index 0000000..c753a78 --- /dev/null +++ b/STM32F4/variants/generic_f407v/ld/flash.ld @@ -0,0 +1,20 @@ +/* + * Discovery F4 (STM32F407VGT6, high density) linker script for + * Flash builds. + */ + +MEMORY +{ + ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 125K + rom (rx) : ORIGIN = 0x08010000, LENGTH = 960K /* ala42 */ +} + +/* GROUP(libcs4_stm32_high_density.a) */ + +REGION_ALIAS("REGION_TEXT", rom); +REGION_ALIAS("REGION_DATA", ram); +REGION_ALIAS("REGION_BSS", ram); +REGION_ALIAS("REGION_RODATA", rom); + +_FLASH_BUILD = 1; +INCLUDE common.inc diff --git a/STM32F4/variants/generic_f407v/ld/jtag.ld b/STM32F4/variants/generic_f407v/ld/jtag.ld new file mode 100644 index 0000000..1001db5 --- /dev/null +++ b/STM32F4/variants/generic_f407v/ld/jtag.ld @@ -0,0 +1,20 @@ +/* + * STM32F4xx high density linker script for + * JTAG (bare metal, no bootloader) builds. + */ + +MEMORY +{ + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K + rom (rx) : ORIGIN = 0x08000000, LENGTH = 512K +} + +/* GROUP(libcs3_stm32_high_density.a) */ + +REGION_ALIAS("REGION_TEXT", rom); +REGION_ALIAS("REGION_DATA", ram); +REGION_ALIAS("REGION_BSS", ram); +REGION_ALIAS("REGION_RODATA", rom); + +_FLASH_BUILD = 1; +INCLUDE common.inc diff --git a/STM32F4/variants/generic_f407v/ld/names.inc b/STM32F4/variants/generic_f407v/ld/names.inc new file mode 100644 index 0000000..6d7ff6e --- /dev/null +++ b/STM32F4/variants/generic_f407v/ld/names.inc @@ -0,0 +1,78 @@ +EXTERN(__cs3_stack) +EXTERN(__cs3_reset) +EXTERN(__exc_nmi) +EXTERN(__exc_hardfault) +EXTERN(__exc_memmanage) +EXTERN(__exc_busfault) +EXTERN(__exc_usagefault) +EXTERN(__stm32reservedexception7) +EXTERN(__stm32reservedexception8) +EXTERN(__stm32reservedexception9) +EXTERN(__stm32reservedexception10) +EXTERN(__exc_svc) +EXTERN(__exc_debug_monitor) +EXTERN(__stm32reservedexception13) +EXTERN(__exc_pendsv) +EXTERN(__exc_systick) + +EXTERN(__irq_wwdg) +EXTERN(__irq_pvd) +EXTERN(__irq_tamper) +EXTERN(__irq_rtc) +EXTERN(__irq_flash) +EXTERN(__irq_rcc) +EXTERN(__irq_exti0) +EXTERN(__irq_exti1) +EXTERN(__irq_exti2) +EXTERN(__irq_exti3) +EXTERN(__irq_exti4) +EXTERN(__irq_dma1_channel1) +EXTERN(__irq_dma1_channel2) +EXTERN(__irq_dma1_channel3) +EXTERN(__irq_dma1_channel4) +EXTERN(__irq_dma1_channel5) +EXTERN(__irq_dma1_channel6) +EXTERN(__irq_dma1_channel7) +EXTERN(__irq_adc) +EXTERN(__irq_usb_hp_can_tx) +EXTERN(__irq_usb_lp_can_rx0) +EXTERN(__irq_can_rx1) +EXTERN(__irq_can_sce) +EXTERN(__irq_exti9_5) +EXTERN(__irq_tim1_brk) +EXTERN(__irq_tim1_up) +EXTERN(__irq_tim1_trg_com) +EXTERN(__irq_tim1_cc) +EXTERN(__irq_tim2) +EXTERN(__irq_tim3) +EXTERN(__irq_tim4) +EXTERN(__irq_i2c1_ev) +EXTERN(__irq_i2c1_er) +EXTERN(__irq_i2c2_ev) +EXTERN(__irq_i2c2_er) +EXTERN(__irq_spi1) +EXTERN(__irq_spi2) +EXTERN(__irq_usart1) +EXTERN(__irq_usart2) +EXTERN(__irq_usart3) +EXTERN(__irq_exti15_10) +EXTERN(__irq_rtcalarm) +EXTERN(__irq_usbwakeup) + +EXTERN(__irq_tim8_brk) +EXTERN(__irq_tim8_up) +EXTERN(__irq_tim8_trg_com) +EXTERN(__irq_tim8_cc) +EXTERN(__irq_adc3) +EXTERN(__irq_fsmc) +EXTERN(__irq_sdio) +EXTERN(__irq_tim5) +EXTERN(__irq_spi3) +EXTERN(__irq_uart4) +EXTERN(__irq_uart5) +EXTERN(__irq_tim6) +EXTERN(__irq_tim7) +EXTERN(__irq_dma2_channel1) +EXTERN(__irq_dma2_channel2) +EXTERN(__irq_dma2_channel3) +EXTERN(__irq_dma2_channel4_5) diff --git a/STM32F4/variants/generic_f407v/ld/ram.ld b/STM32F4/variants/generic_f407v/ld/ram.ld new file mode 100644 index 0000000..b57060c --- /dev/null +++ b/STM32F4/variants/generic_f407v/ld/ram.ld @@ -0,0 +1,19 @@ +/* + * aeroquad32 (STM32F103VET6, high density) linker script for + * RAM builds. + */ + +MEMORY +{ + ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 61K + rom (rx) : ORIGIN = 0x08010000, LENGTH = 0K /* ala42 */ +} + +GROUP(libcs3_stm32_high_density.a) + +REGION_ALIAS("REGION_TEXT", ram); +REGION_ALIAS("REGION_DATA", ram); +REGION_ALIAS("REGION_BSS", ram); +REGION_ALIAS("REGION_RODATA", ram); + +INCLUDE common.inc diff --git a/STM32F4/variants/generic_f407v/ld/vector_symbols.inc b/STM32F4/variants/generic_f407v/ld/vector_symbols.inc new file mode 100644 index 0000000..f8519bb --- /dev/null +++ b/STM32F4/variants/generic_f407v/ld/vector_symbols.inc @@ -0,0 +1,78 @@ +EXTERN(__msp_init) +EXTERN(__exc_reset) +EXTERN(__exc_nmi) +EXTERN(__exc_hardfault) +EXTERN(__exc_memmanage) +EXTERN(__exc_busfault) +EXTERN(__exc_usagefault) +EXTERN(__stm32reservedexception7) +EXTERN(__stm32reservedexception8) +EXTERN(__stm32reservedexception9) +EXTERN(__stm32reservedexception10) +EXTERN(__exc_svc) +EXTERN(__exc_debug_monitor) +EXTERN(__stm32reservedexception13) +EXTERN(__exc_pendsv) +EXTERN(__exc_systick) + +EXTERN(__irq_wwdg) +EXTERN(__irq_pvd) +EXTERN(__irq_tamper) +EXTERN(__irq_rtc) +EXTERN(__irq_flash) +EXTERN(__irq_rcc) +EXTERN(__irq_exti0) +EXTERN(__irq_exti1) +EXTERN(__irq_exti2) +EXTERN(__irq_exti3) +EXTERN(__irq_exti4) +EXTERN(__irq_dma1_channel1) +EXTERN(__irq_dma1_channel2) +EXTERN(__irq_dma1_channel3) +EXTERN(__irq_dma1_channel4) +EXTERN(__irq_dma1_channel5) +EXTERN(__irq_dma1_channel6) +EXTERN(__irq_dma1_channel7) +EXTERN(__irq_adc) +EXTERN(__irq_usb_hp_can_tx) +EXTERN(__irq_usb_lp_can_rx0) +EXTERN(__irq_can_rx1) +EXTERN(__irq_can_sce) +EXTERN(__irq_exti9_5) +EXTERN(__irq_tim1_brk) +EXTERN(__irq_tim1_up) +EXTERN(__irq_tim1_trg_com) +EXTERN(__irq_tim1_cc) +EXTERN(__irq_tim2) +EXTERN(__irq_tim3) +EXTERN(__irq_tim4) +EXTERN(__irq_i2c1_ev) +EXTERN(__irq_i2c1_er) +EXTERN(__irq_i2c2_ev) +EXTERN(__irq_i2c2_er) +EXTERN(__irq_spi1) +EXTERN(__irq_spi2) +EXTERN(__irq_usart1) +EXTERN(__irq_usart2) +EXTERN(__irq_usart3) +EXTERN(__irq_exti15_10) +EXTERN(__irq_rtcalarm) +EXTERN(__irq_usbwakeup) + +EXTERN(__irq_tim8_brk) +EXTERN(__irq_tim8_up) +EXTERN(__irq_tim8_trg_com) +EXTERN(__irq_tim8_cc) +EXTERN(__irq_adc3) +EXTERN(__irq_fsmc) +EXTERN(__irq_sdio) +EXTERN(__irq_tim5) +EXTERN(__irq_spi3) +EXTERN(__irq_uart4) +EXTERN(__irq_uart5) +EXTERN(__irq_tim6) +EXTERN(__irq_tim7) +EXTERN(__irq_dma2_channel1) +EXTERN(__irq_dma2_channel2) +EXTERN(__irq_dma2_channel3) +EXTERN(__irq_dma2_channel4_5) diff --git a/STM32F4/variants/generic_f407v/pin_map.c b/STM32F4/variants/generic_f407v/pin_map.c new file mode 100644 index 0000000..2189902 --- /dev/null +++ b/STM32F4/variants/generic_f407v/pin_map.c @@ -0,0 +1,210 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file generic_f407v.cpp + * @author ala42 + * @brief generic_f407v board file. + */ + +#ifdef BOARD_generic_f407v + +#ifdef __cplusplus +extern "C"{ +#endif + +//#include "generic_f407v.h" + +//#include "fsmc.h" +#include +#include +#include + +#include + +extern timer_dev timer1; +extern timer_dev timer2; +extern timer_dev timer3; +extern timer_dev timer4; +extern timer_dev timer5; +extern timer_dev timer6; +extern timer_dev timer7; +extern timer_dev timer8; + +/* +typedef struct stm32_pin_info { + gpio_dev *gpio_device; // Maple pin's GPIO device + timer_dev *timer_device; // Pin's timer device, if any. + uint8 timer_channel; // Timer channel, or 0 if none. + uint8 adc_channel; // Pin ADC channel, or ADCx if none. + const adc_dev *adc_device; // ADC device, if any. +} stm32_pin_info; +*/ +const stm32_pin_info PIN_MAP[] = { // LQFP100 package pin + {&GPIOA, &timer5, 1, 0, &ADC1}, // D00/PA0 | 23 | USART2_CTS | UART4_TX | ETH_MII_CRS | TIM2_CH1_ETR | TIM5_CH1 | TIM8_ETR | ADC123_IN0/WKUP + {&GPIOA, &timer5, 2, 1, &ADC1}, // D01/PA1 | 24 | USART2_RTS | UART4_RX | ETH_RMII_REF_CLK | ETH_MII_RX_CLK | TIM5_CH2 | TIM2_CH2 | ADC123_IN1 + {&GPIOA, &timer5, 3, 2, &ADC1}, // D02/PA2 | 25 | USART2_TX | TIM5_CH3 | TIM9_CH1 | TIM2_CH3 | ETH_MDIO | ADC123_IN2 + {&GPIOA, &timer5, 4, 3, &ADC1}, // D03/PA3 | 26 | USART2_RX | TIM5_CH4 | TIM9_CH2 | TIM2_CH4 | OTG_HS_ULPI_D0 | ETH_MII_COL | ADC123_IN3 + {&GPIOA, NULL, 0, 4, &ADC1}, // D04/PA4 | 29 | SPI1_NSS | SPI3_NSS | USART2_CK | DCMI_HSYNC | OTG_HS_SOF | I2S3_WS | ADC12_IN4 / DAC_OUT1 + {&GPIOA, NULL, 0, 5, &ADC1}, // D05/PA5 | 30 | SPI1_SCK | OTG_HS_ULPI_CK | TIM2_CH1_ETR | TIM8_CH1N | ADC12_IN5 / DAC_OUT2 + {&GPIOA, NULL, 1, 6, &ADC1}, // D06/PA6 | 31 | SPI1_MISO | TIM8_BKIN | TIM13_CH1 | DCMI_PIXCLK | TIM3_CH1 | TIM1_BKIN | ADC12_IN6 + {&GPIOA, NULL, 0, 7, &ADC1}, // D07/PA7 | 32 | SPI1_MOSI | TIM8_CH1N | TIM14_CH1 | TIM3_CH2 | ETH_MII_RX_DV | TIM1_CH1N / ETH_RMII_CRS_DV | ADC12_IN7 + {&GPIOA, NULL, 0, ADCx, NULL}, // D08/PA8 | 67 | MCO1 | USART1_CK | TIM1_CH1 | I2C3_SCL | OTG_FS_SOF + {&GPIOA, NULL, 0, ADCx, NULL}, // D09/PA9 | 68 | USART1_TX | TIM1_CH2 | I2C3_SMBA | DCMI_D0 + {&GPIOA, NULL, 0, ADCx, NULL}, // D10/PA10 | 69 | USART1_RX | TIM1_CH3 | OTG_FS_ID | DCMI_D1 + {&GPIOA, NULL, 0, ADCx, NULL}, // D11/PA11 | 70 | USART1_CTS | CAN1_RX | TIM1_CH4 | OTG_FS_DM + {&GPIOA, NULL, 0, ADCx, NULL}, // D12/PA12 | 71 | USART1_RTS | CAN1_TX | TIM1_ETR | OTG_FS_DP + {&GPIOA, NULL, 0, ADCx, NULL}, // D13/PA13 | 72 | JTMS-SWDIO + {&GPIOA, NULL, 0, ADCx, NULL}, // D14/PA14 | 76 | JTCK-SWCLK + {&GPIOA, &timer2, 1, ADCx, NULL}, // D15/PA15 | 77 | JTDI | SPI3_NSS | I2S3_WS | TIM2_CH1_ETR | SPI1_NSS + + {&GPIOB, &timer3, 3, 8, &ADC1}, // D16/PB0 | 35 | TIM3_CH3 | TIM8_CH2N | OTG_HS_ULPI_D1 | ETH_MII_RXD2 | TIM1_CH2N | ADC12_IN8 + {&GPIOB, &timer3, 4, 9, &ADC1}, // D17/PB1 | 36 | TIM3_CH4 | TIM8_CH3N | OTG_HS_ULPI_D2 | ETH_MII_RXD3 | TIM1_CH3N | ADC12_IN9 + {&GPIOB, NULL, 0, ADCx, NULL}, // D18/PB2 | 37 | BOOT1 + {&GPIOB, &timer2, 2, ADCx, NULL}, // D19/PB3 | 89 | JTDO | TRACESWO | SPI3_SCK | I2S3_CK | TIM2_CH2 | SPI1_SCK + {&GPIOB, &timer3, 1, ADCx, NULL}, // D20/PB4 | 90 | NJTRST | SPI3_MISO | TIM3_CH1 | SPI1_MISO | I2S3ext_SD + {&GPIOB, &timer3, 2, ADCx, NULL}, // D21/PB5 | 91 | I2C1_SMBA | CAN2_RX | OTG_HS_ULPI_D7 | ETH_PPS_OUT | TIM3_CH2 | SPI1_MOSI | SPI3_MOSI | DCMI_D10 | I2S3_SD + {&GPIOB, NULL, 0, ADCx, NULL}, // D22/PB6 | 92 | I2C1_SCL | TIM4_CH1 | CAN2_TX | DCMI_D5 | USART1_TX + {&GPIOB, NULL, 0, ADCx, NULL}, // D23/PB7 | 93 | I2C1_SDA | FSMC_NL | DCMI_VSYNC | USART1_RX | TIM4_CH2 + {&GPIOB, NULL, 0, ADCx, NULL}, // D24/PB8 | 95 | TIM4_CH3 | SDIO_D4 | TIM10_CH1 | DCMI_D6 | ETH_MII_TXD3 | I2C1_SCL | CAN1_RX + {&GPIOB, NULL, 0, ADCx, NULL}, // D25/PB9 | 96 | SPI2_NSS | I2S2_WS | TIM4_CH4 | TIM11_CH1 | SDIO_D5 | DCMI_D7 | I2C1_SDA | CAN1_TX + {&GPIOB, NULL, 0, ADCx, NULL}, // D26/PB10 | 47 | SPI2_SCK | I2S2_CK | I2C2_SCL | USART3_TX | OTG_HS_ULPI_D3 | ETH_MII_RX_ER | TIM2_CH3 + {&GPIOB, NULL, 0, ADCx, NULL}, // D27/PB11 | 48 | I2C2_SDA | USART3_RX | OTG_HS_ULPI_D4 | ETH_RMII_TX_EN | ETH_MII_TX_EN | TIM2_CH4 + {&GPIOB, NULL, 0, ADCx, NULL}, // D28/PB12 | 51 | SPI2_NSS | I2S2_WS | I2C2_SMBA | USART3_CK | TIM1_BKIN | CAN2_RX | OTG_HS_ULPI_D5 | ETH_RMII_TXD0 | ETH_MII_TXD0 | OTG_HS_ID + {&GPIOB, NULL, 0, ADCx, NULL}, // D29/PB13 | 52 | SPI2_SCK | I2S2_CK | USART3_CTS | TIM1_CH1N | CAN2_TX | OTG_HS_ULPI_D6 | ETH_RMII_TXD1 | ETH_MII_TXD1 + {&GPIOB, NULL, 0, ADCx, NULL}, // D30/PB14 | 53 | SPI2_MISO | TIM1_CH2N | TIM12_CH1 | OTG_HS_DM | USART3_RTS | TIM8_CH2N | I2S2ext_SD + {&GPIOB, NULL, 0, ADCx, NULL}, // D31/PB15 | 54 | SPI2_MOSI | I2S2_SD | TIM1_CH3N | TIM8_CH3N | TIM12_CH2 | OTG_HS_DP + + {&GPIOC, NULL, 0, 10, &ADC1}, // D32/PC0 | 15 | OTG_HS_ULPI_STP | ADC123_IN10 + {&GPIOC, NULL, 0, 11, &ADC1}, // D33/PC1 | 16 | ETH_MDC | ADC123_IN11 + {&GPIOC, NULL, 0, 12, &ADC1}, // D34/PC2 | 17 | SPI2_MISO | OTG_HS_ULPI_DIR | ETH_MII_TXD2 | I2S2ext_SD | ADC123_IN12 + {&GPIOC, NULL, 0, 13, &ADC1}, // D35/PC3 | 18 | SPI2_MOSI | I2S2_SD | OTG_HS_ULPI_NXT | ETH_MII_TX_CLK | ADC123_IN13 + {&GPIOC, NULL, 0, 14, &ADC1}, // D36/PC4 | 33 | ETH_RMII_RX_D0 | ETH_MII_RX_D0 | ADC12_IN14 + {&GPIOC, NULL, 0, 15, &ADC1}, // D37/PC5 | 34 | ETH_RMII_RX_D1 | ETH_MII_RX_D1 | ADC12_IN15 + {&GPIOC, &timer8, 1, ADCx, NULL}, // D38/PC6 | 63 | I2S2_MCK | TIM8_CH1/SDIO_D6 | USART6_TX | DCMI_D0/TIM3_CH1 + {&GPIOC, &timer8, 2, ADCx, NULL}, // D39/PC7 | 64 | I2S3_MCK | TIM8_CH2/SDIO_D7 | USART6_RX | DCMI_D1/TIM3_CH2 + {&GPIOC, &timer8, 3, ADCx, NULL}, // D40/PC8 | 65 | TIM8_CH3 | SDIO_D0 | TIM3_CH3 | USART6_CK | DCMI_D2 + {&GPIOC, &timer8, 4, ADCx, NULL}, // D41/PC9 | 66 | I2S_CKIN | MCO2 | TIM8_CH4 | SDIO_D1 | I2C3_SDA | DCMI_D3 | TIM3_CH4 + {&GPIOC, NULL, 0, ADCx, NULL}, // D42/PC10 | 78 | SPI3_SCK | I2S3_CK | UART4_TX | SDIO_D2 | DCMI_D8 | USART3_TX + {&GPIOC, NULL, 0, ADCx, NULL}, // D43/PC11 | 79 | UART4_RX | SPI3_MISO | SDIO_D3 | DCMI_D4 | USART3_RX | I2S3ext_SD + {&GPIOC, NULL, 0, ADCx, NULL}, // D44/PC12 | 80 | UART5_TX | SDIO_CK | DCMI_D9 | SPI3_MOSI | I2S3_SD | USART3_CK + {&GPIOC, NULL, 0, ADCx, NULL}, // D45/PC13 | 7 | RTC_OUT, RTC_TAMP1, RTC_TS + {&GPIOC, NULL, 0, ADCx, NULL}, // D46/PC14 | 8 | OSC32_IN + {&GPIOC, NULL, 0, ADCx, NULL}, // D47/PC15 | 9 | OSC32_OUT + + {&GPIOD, NULL, 0, ADCx, NULL}, // D48/PD0 | 81 | FSMC_D2 | CAN1_RX + {&GPIOD, NULL, 0, ADCx, NULL}, // D49/PD1 | 82 | FSMC_D3 | CAN1_TX + {&GPIOD, NULL, 0, ADCx, NULL}, // D50/PD2 | 83 | TIM3_ETR | UART5_RX | SDIO_CMD | DCMI_D11 + {&GPIOD, NULL, 0, ADCx, NULL}, // D51/PD3 | 84 | FSMC_CLK | USART2_CTS + {&GPIOD, NULL, 0, ADCx, NULL}, // D52/PD4 | 85 | FSMC_NOE | USART2_RTS + {&GPIOD, NULL, 0, ADCx, NULL}, // D53/PD5 | 86 | FSMC_NWE | USART2_TX + {&GPIOD, NULL, 0, ADCx, NULL}, // D54/PD6 | 87 | FSMC_NWAIT | USART2_RX + {&GPIOD, NULL, 0, ADCx, NULL}, // D55/PD7 | 88 | USART2_CK | FSMC_NE1 | FSMC_NCE2 + {&GPIOD, NULL, 0, ADCx, NULL}, // D56/PD8 | 55 | FSMC_D13 | USART3_TX + {&GPIOD, NULL, 0, ADCx, NULL}, // D57/PD9 | 56 | FSMC_D14 | USART3_RX + {&GPIOD, NULL, 0, ADCx, NULL}, // D58/PD10 | 57 | FSMC_D15 | USART3_CK + {&GPIOD, NULL, 0, ADCx, NULL}, // D59/PD11 | 58 | FSMC_CLE | FSMC_A16 | USART3_CTS + {&GPIOD, &timer4, 1, ADCx, NULL}, // D60/PD12 | 59 | FSMC_ALE | FSMC_A17 | TIM4_CH1 | USART3_RTS // remap in + {&GPIOD, &timer4, 2, ADCx, NULL}, // D61/PD13 | 60 | FSMC_A18 | TIM4_CH2 // remap in + {&GPIOD, &timer4, 3, ADCx, NULL}, // D62/PD14 | 61 | FSMC_D0 | TIM4_CH3 // remap in + {&GPIOD, &timer4, 4, ADCx, NULL}, // D63/PD15 | 62 | FSMC_D1 | TIM4_CH4 // remap in + + {&GPIOE, NULL, 0, ADCx, NULL}, // D64/PE0 | 97 | TIM4_ETR | FSMC_NBL0 | DCMI_D2 + {&GPIOE, NULL, 0, ADCx, NULL}, // D65/PE1 | 98 | FSMC_NBL1 | DCMI_D3 + {&GPIOE, NULL, 0, ADCx, NULL}, // D66/PE2 | 1 | TRACECLK | FSMC_A23 | ETH_MII_TXD3 + {&GPIOE, NULL, 0, ADCx, NULL}, // D67/PE3 | 2 | TRACED0 | FSMC_A19 + {&GPIOE, NULL, 0, ADCx, NULL}, // D68/PE4 | 3 | TRACED1 | FSMC_A20 | DCMI_D4 + {&GPIOE, NULL, 0, ADCx, NULL}, // D69/PE5 | 4 | TRACED2 | FSMC_A21 | TIM9_CH1 / DCMI_D6 + {&GPIOE, NULL, 0, ADCx, NULL}, // D70/PE6 | 5 | TRACED3 | FSMC_A22 | TIM9_CH2 / DCMI_D7 + {&GPIOE, NULL, 0, ADCx, NULL}, // D71/PE7 | 38 | FSMC_D4 | TIM1_ETR + {&GPIOE, NULL, 0, ADCx, NULL}, // D72/PE8 | 39 | FSMC_D5 | TIM1_CH1N + {&GPIOE, &timer1, 1, ADCx, NULL}, // D73/PE9 | 40 | FSMC_D6 | TIM1_CH1 // remap in + {&GPIOE, NULL, 0, ADCx, NULL}, // D74/PE10 | 41 | FSMC_D7 | TIM1_CH2N + {&GPIOE, &timer1, 2, ADCx, NULL}, // D75/PE11 | 42 | FSMC_D8 | TIM1_CH2 // remap in + {&GPIOE, NULL, 0, ADCx, NULL}, // D76/PE12 | 43 | FSMC_D9 | TIM1_CH3N + {&GPIOE, &timer1, 3, ADCx, NULL}, // D77/PE13 | 44 | FSMC_D10 | TIM1_CH3 // remap in + {&GPIOE, &timer1, 4, ADCx, NULL}, // D78/PE14 | 45 | FSMC_D11 | TIM1_CH4 // remap in + {&GPIOE, NULL, 0, ADCx, NULL}, // D79/PE15 | 46 | FSMC_D12 | TIM1_BKIN +#if 0 + {GPIOF, 0, NULL, 0, NULL, ADCx}, // D80/PF0 + {GPIOF, 1, NULL, 0, NULL, ADCx}, // D81/PF1 + {GPIOF, 2, NULL, 0, NULL, ADCx}, // D82/PF2 + {GPIOF, 3, NULL, 0, NULL, ADCx}, // D83/PF3 + {GPIOF, 4, NULL, 0, NULL, ADCx}, // D84/PF4 + {GPIOF, 5, NULL, 0, NULL, ADCx}, // D85/PF5 + {GPIOF, 6, NULL, 0, NULL, ADCx}, // D86/PF6 + {GPIOF, 7, NULL, 0, NULL, ADCx}, // D87/PF7 + {GPIOF, 8, NULL, 0, NULL, ADCx}, // D88/PF8 + {GPIOF, 9, NULL, 0, NULL, ADCx}, // D89/PF9 + {GPIOF, 10, NULL, 0, NULL, ADCx}, // D90/PF10 + {GPIOF, 11, NULL, 0, NULL, ADCx}, // D91/PF11 + {GPIOF, 12, NULL, 0, NULL, ADCx}, // D92/PF12 + {GPIOF, 13, NULL, 0, NULL, ADCx}, // D93/PF13 + {GPIOF, 14, NULL, 0, NULL, ADCx}, // D94/PF14 + {GPIOF, 15, NULL, 0, NULL, ADCx}, // D95/PF15 + + {GPIOG, 0, NULL, 0, NULL, ADCx}, // D96/PG0 + {GPIOG, 1, NULL, 0, NULL, ADCx}, // D97/PG1 + {GPIOG, 2, NULL, 0, NULL, ADCx}, // D98/PG2 + {GPIOG, 3, NULL, 0, NULL, ADCx}, // D99/PG3 + {GPIOG, 4, NULL, 0, NULL, ADCx}, // D100/PG4 + {GPIOG, 5, NULL, 0, NULL, ADCx}, // D101/PG5 + {GPIOG, 6, NULL, 0, NULL, ADCx}, // D102/PG6 + {GPIOG, 7, NULL, 0, NULL, ADCx}, // D103/PG7 + {GPIOG, 8, NULL, 0, NULL, ADCx}, // D104/PG8 + {GPIOG, 9, NULL, 0, NULL, ADCx}, // D105/PG9 + {GPIOG, 10, NULL, 0, NULL, ADCx}, // D106/PG10 + {GPIOG, 11, NULL, 0, NULL, ADCx}, // D107/PG11 + {GPIOG, 12, NULL, 0, NULL, ADCx}, // D108/PG12 + {GPIOG, 13, NULL, 0, NULL, ADCx}, // D109/PG13 + {GPIOG, 14, NULL, 0, NULL, ADCx}, // D110/PG14 + {GPIOG, 15, NULL, 0, NULL, ADCx} // D111/PG15 +#endif +}; +/* to be defined +extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { + 0, 1, 2, 3, 15, 16, 17, 19, 20, 21, 38, 39, 49, 41, 60, 61, 62, 63, 73, 75, 77, 78 +}; +*/ +const uint8 boardADCPins[BOARD_NR_ADC_PINS] = { + PA0, PA1, PA2, PA3, PA4, PA5, PA6, PA7, PB0, PB1, PC0, PC1, PC2, PC3, PC4, PC5 +}; + +const uint8 boardUsedPins[BOARD_NR_USED_PINS] = { + BOARD_LED_PIN, BOARD_LED2_PIN, BOARD_BUTTON1_PIN, BOARD_BUTTON2_PIN, BOARD_BUTTON2_PIN, + BOARD_JTMS_SWDIO_PIN, BOARD_JTCK_SWCLK_PIN, + FLASH_CS_PIN, FLASH_CLK_PIN, FLASH_DO_PIN, FLASH_DI_PIN, + NRF24_CE_PIN, NRF24_CS_PIN, NRF24_IRQ_PIN, + BOARD_SDIO_D0, BOARD_SDIO_D1, BOARD_SDIO_D2, BOARD_SDIO_D3, BOARD_SDIO_CK, BOARD_SDIO_CMD, + USB_DM_PIN, USB_DP_PIN +}; + +#ifdef __cplusplus +} +#endif + + +#endif // BOARD_generic_f407v diff --git a/STM32F4/variants/generic_f407v/pins_arduino.h b/STM32F4/variants/generic_f407v/pins_arduino.h new file mode 100644 index 0000000..3052f2e --- /dev/null +++ b/STM32F4/variants/generic_f407v/pins_arduino.h @@ -0,0 +1,6 @@ + + + + +// API compatibility +#include "variant.h" \ No newline at end of file diff --git a/STM32F4/variants/generic_f407v/stm32_isrs.S b/STM32F4/variants/generic_f407v/stm32_isrs.S new file mode 100644 index 0000000..34e515c --- /dev/null +++ b/STM32F4/variants/generic_f407v/stm32_isrs.S @@ -0,0 +1,323 @@ +/* STM32 ISR weak declarations */ + + .thumb + +/* Default handler for all non-overridden interrupts and exceptions */ + .globl __default_handler + .type __default_handler, %function + +__default_handler: + b . + + .weak __exc_nmi + .globl __exc_nmi + .set __exc_nmi, __default_handler + .weak __exc_hardfault + .globl __exc_hardfault + .set __exc_hardfault, __default_handler + .weak __exc_memmanage + .globl __exc_memmanage + .set __exc_memmanage, __default_handler + .weak __exc_busfault + .globl __exc_busfault + .set __exc_busfault, __default_handler + .weak __exc_usagefault + .globl __exc_usagefault + .set __exc_usagefault, __default_handler + .weak __stm32reservedexception7 + .globl __stm32reservedexception7 + .set __stm32reservedexception7, __default_handler + .weak __stm32reservedexception8 + .globl __stm32reservedexception8 + .set __stm32reservedexception8, __default_handler + .weak __stm32reservedexception9 + .globl __stm32reservedexception9 + .set __stm32reservedexception9, __default_handler + .weak __stm32reservedexception10 + .globl __stm32reservedexception10 + .set __stm32reservedexception10, __default_handler + .weak __exc_svc + .globl __exc_svc + .set __exc_svc, __default_handler + .weak __exc_debug_monitor + .globl __exc_debug_monitor + .set __exc_debug_monitor, __default_handler + .weak __stm32reservedexception13 + .globl __stm32reservedexception13 + .set __stm32reservedexception13, __default_handler + .weak __exc_pendsv + .globl __exc_pendsv + .set __exc_pendsv, __default_handler + .weak __exc_systick + .globl __exc_systick + .set __exc_systick, __default_handler + .weak __irq_wwdg + .globl __irq_wwdg + .set __irq_wwdg, __default_handler + .weak __irq_pvd + .globl __irq_pvd + .set __irq_pvd, __default_handler + .weak __irq_tamper + .globl __irq_tamper + .set __irq_tamper, __default_handler + .weak __irq_rtc + .globl __irq_rtc + .set __irq_rtc, __default_handler + .weak __irq_flash + .globl __irq_flash + .set __irq_flash, __default_handler + .weak __irq_rcc + .globl __irq_rcc + .set __irq_rcc, __default_handler + .weak __irq_exti0 + .globl __irq_exti0 + .set __irq_exti0, __default_handler + .weak __irq_exti1 + .globl __irq_exti1 + .set __irq_exti1, __default_handler + .weak __irq_exti2 + .globl __irq_exti2 + .set __irq_exti2, __default_handler + .weak __irq_exti3 + .globl __irq_exti3 + .set __irq_exti3, __default_handler + .weak __irq_exti4 + .globl __irq_exti4 + .set __irq_exti4, __default_handler + .weak __irq_dma1_channel1 + .globl __irq_dma1_channel1 + .set __irq_dma1_channel1, __default_handler + .weak __irq_dma1_channel2 + .globl __irq_dma1_channel2 + .set __irq_dma1_channel2, __default_handler + .weak __irq_dma1_channel3 + .globl __irq_dma1_channel3 + .set __irq_dma1_channel3, __default_handler + .weak __irq_dma1_channel4 + .globl __irq_dma1_channel4 + .set __irq_dma1_channel4, __default_handler + .weak __irq_dma1_channel5 + .globl __irq_dma1_channel5 + .set __irq_dma1_channel5, __default_handler + .weak __irq_dma1_channel6 + .globl __irq_dma1_channel6 + .set __irq_dma1_channel6, __default_handler + .weak __irq_dma1_channel7 + .globl __irq_dma1_channel7 + .set __irq_dma1_channel7, __default_handler + .weak __irq_adc + .globl __irq_adc + .set __irq_adc, __default_handler + .weak __irq_usb_hp_can_tx + .globl __irq_usb_hp_can_tx + .set __irq_usb_hp_can_tx, __default_handler + .weak __irq_usb_lp_can_rx0 + .globl __irq_usb_lp_can_rx0 + .set __irq_usb_lp_can_rx0, __default_handler + .weak __irq_can_rx1 + .globl __irq_can_rx1 + .set __irq_can_rx1, __default_handler + .weak __irq_can_sce + .globl __irq_can_sce + .set __irq_can_sce, __default_handler + .weak __irq_exti9_5 + .globl __irq_exti9_5 + .set __irq_exti9_5, __default_handler + .weak __irq_tim1_brk + .globl __irq_tim1_brk + .set __irq_tim1_brk, __default_handler + .weak __irq_tim1_up + .globl __irq_tim1_up + .set __irq_tim1_up, __default_handler + .weak __irq_tim1_trg_com + .globl __irq_tim1_trg_com + .set __irq_tim1_trg_com, __default_handler + .weak __irq_tim1_cc + .globl __irq_tim1_cc + .set __irq_tim1_cc, __default_handler + .weak __irq_tim2 + .globl __irq_tim2 + .set __irq_tim2, __default_handler + .weak __irq_tim3 + .globl __irq_tim3 + .set __irq_tim3, __default_handler + .weak __irq_tim4 + .globl __irq_tim4 + .set __irq_tim4, __default_handler + .weak __irq_i2c1_ev + .globl __irq_i2c1_ev + .set __irq_i2c1_ev, __default_handler + .weak __irq_i2c1_er + .globl __irq_i2c1_er + .set __irq_i2c1_er, __default_handler + .weak __irq_i2c2_ev + .globl __irq_i2c2_ev + .set __irq_i2c2_ev, __default_handler + .weak __irq_i2c2_er + .globl __irq_i2c2_er + .set __irq_i2c2_er, __default_handler + .weak __irq_spi1 + .globl __irq_spi1 + .set __irq_spi1, __default_handler + .weak __irq_spi2 + .globl __irq_spi2 + .set __irq_spi2, __default_handler + .weak __irq_usart1 + .globl __irq_usart1 + .set __irq_usart1, __default_handler + .weak __irq_usart2 + .globl __irq_usart2 + .set __irq_usart2, __default_handler + .weak __irq_usart3 + .globl __irq_usart3 + .set __irq_usart3, __default_handler + .weak __irq_exti15_10 + .globl __irq_exti15_10 + .set __irq_exti15_10, __default_handler + .weak __irq_rtcalarm + .globl __irq_rtcalarm + .set __irq_rtcalarm, __default_handler + .weak __irq_usbwakeup + .globl __irq_usbwakeup + .set __irq_usbwakeup, __default_handler +#if defined (STM32_HIGH_DENSITY) + .weak __irq_tim8_brk + .globl __irq_tim8_brk + .set __irq_tim8_brk, __default_handler + .weak __irq_tim8_up + .globl __irq_tim8_up + .set __irq_tim8_up, __default_handler + .weak __irq_tim8_trg_com + .globl __irq_tim8_trg_com + .set __irq_tim8_trg_com, __default_handler + .weak __irq_tim8_cc + .globl __irq_tim8_cc + .set __irq_tim8_cc, __default_handler + .weak __irq_adc3 + .globl __irq_adc3 + .set __irq_adc3, __default_handler + .weak __irq_fsmc + .globl __irq_fsmc + .set __irq_fsmc, __default_handler + .weak __irq_sdio + .globl __irq_sdio + .set __irq_sdio, __default_handler + .weak __irq_tim5 + .globl __irq_tim5 + .set __irq_tim5, __default_handler + .weak __irq_spi3 + .globl __irq_spi3 + .set __irq_spi3, __default_handler + .weak __irq_uart4 + .globl __irq_uart4 + .set __irq_uart4, __default_handler + .weak __irq_uart5 + .globl __irq_uart5 + .set __irq_uart5, __default_handler + .weak __irq_tim6 + .globl __irq_tim6 + .set __irq_tim6, __default_handler + .weak __irq_tim7 + .globl __irq_tim7 + .set __irq_tim7, __default_handler + .weak __irq_dma2_channel1 + .globl __irq_dma2_channel1 + .set __irq_dma2_channel1, __default_handler + .weak __irq_dma2_channel2 + .globl __irq_dma2_channel2 + .set __irq_dma2_channel2, __default_handler + .weak __irq_dma2_channel3 + .globl __irq_dma2_channel3 + .set __irq_dma2_channel3, __default_handler + .weak __irq_dma2_channel4_5 + .globl __irq_dma2_channel4_5 + .set __irq_dma2_channel4_5, __default_handler +#endif /* STM32_HIGH_DENSITY */ + + .weak __irq_DMA2_Stream4_IRQHandler + .globl __irq_DMA2_Stream4_IRQHandler + .set __irq_DMA2_Stream4_IRQHandler, __default_handler + + .weak __irq_ETH_IRQHandler + .globl __irq_ETH_IRQHandler + .set __irq_ETH_IRQHandler, __default_handler + + .weak __irq_ETH_WKUP_IRQHandler + .globl __irq_ETH_WKUP_IRQHandler + .set __irq_ETH_WKUP_IRQHandler, __default_handler + + .weak __irq_CAN2_TX_IRQHandler + .globl __irq_CAN2_TX_IRQHandler + .set __irq_CAN2_TX_IRQHandler, __default_handler + + .weak __irq_CAN2_RX0_IRQHandler + .globl __irq_CAN2_RX0_IRQHandler + .set __irq_CAN2_RX0_IRQHandler, __default_handler + + .weak __irq_CAN2_RX1_IRQHandler + .globl __irq_CAN2_RX1_IRQHandler + .set __irq_CAN2_RX1_IRQHandler, __default_handler + + .weak __irq_CAN2_SCE_IRQHandler + .globl __irq_CAN2_SCE_IRQHandler + .set __irq_CAN2_SCE_IRQHandler, __default_handler + + .weak __irq_OTG_FS_IRQHandler + .globl __irq_OTG_FS_IRQHandler + .set __irq_OTG_FS_IRQHandler, __default_handler + + .weak __irq_DMA2_Stream5_IRQHandler + .globl __irq_DMA2_Stream5_IRQHandler + .set __irq_DMA2_Stream5_IRQHandler, __default_handler + + .weak __irq_DMA2_Stream6_IRQHandler + .globl __irq_DMA2_Stream6_IRQHandler + .set __irq_DMA2_Stream6_IRQHandler, __default_handler + + .weak __irq_DMA2_Stream7_IRQHandler + .globl __irq_DMA2_Stream7_IRQHandler + .set __irq_DMA2_Stream7_IRQHandler, __default_handler + + .weak __irq_USART6_IRQHandler + .globl __irq_USART6_IRQHandler + .set __irq_USART6_IRQHandler, __default_handler + + .weak __irq_I2C3_EV_IRQHandler + .globl __irq_I2C3_EV_IRQHandler + .set __irq_I2C3_EV_IRQHandler, __default_handler + + .weak __irq_I2C3_ER_IRQHandler + .globl __irq_I2C3_ER_IRQHandler + .set __irq_I2C3_ER_IRQHandler, __default_handler + + .weak __irq_OTG_HS_EP1_OUT_IRQHandler + .globl __irq_OTG_HS_EP1_OUT_IRQHandler + .set __irq_OTG_HS_EP1_OUT_IRQHandler, __default_handler + + .weak __irq_OTG_HS_EP1_IN_IRQHandler + .globl __irq_OTG_HS_EP1_IN_IRQHandler + .set __irq_OTG_HS_EP1_IN_IRQHandler, __default_handler + + .weak __irq_OTG_HS_WKUP_IRQHandler + .globl __irq_OTG_HS_WKUP_IRQHandler + .set __irq_OTG_HS_WKUP_IRQHandler, __default_handler + + .weak __irq_OTG_HS_IRQHandler + .globl __irq_OTG_HS_IRQHandler + .set __irq_OTG_HS_IRQHandler, __default_handler + + .weak __irq_DCMI_IRQHandler + .globl __irq_DCMI_IRQHandler + .set __irq_DCMI_IRQHandler, __default_handler + + .weak __irq_CRYP_IRQHandler + .globl __irq_CRYP_IRQHandler + .set __irq_CRYP_IRQHandler, __default_handler + + .weak __irq_HASH_RNG_IRQHandler + .globl __irq_HASH_RNG_IRQHandler + .set __irq_HASH_RNG_IRQHandler, __default_handler + + .weak __irq_FPU_IRQHandler + .globl __irq_FPU_IRQHandler + .set __irq_FPU_IRQHandler, __default_handler diff --git a/STM32F4/variants/generic_f407v/stm32_vector_table.S b/STM32F4/variants/generic_f407v/stm32_vector_table.S new file mode 100644 index 0000000..9f08d66 --- /dev/null +++ b/STM32F4/variants/generic_f407v/stm32_vector_table.S @@ -0,0 +1,113 @@ +/* STM32 vector table */ + + .section ".stm32.interrupt_vector" + + .globl __stm32_vector_table + .type __stm32_vector_table, %object + +__stm32_vector_table: +/* CM3 core interrupts */ + .long __msp_init + .long __exc_reset + .long __exc_nmi + .long __exc_hardfault + .long __exc_memmanage + .long __exc_busfault + .long __exc_usagefault + .long __stm32reservedexception7 + .long __stm32reservedexception8 + .long __stm32reservedexception9 + .long __stm32reservedexception10 + .long __exc_svc + .long __exc_debug_monitor + .long __stm32reservedexception13 + .long __exc_pendsv + .long __exc_systick +/* Peripheral interrupts */ + .long __irq_wwdg + .long __irq_pvd + .long __irq_tamper + .long __irq_rtc + .long __irq_flash + .long __irq_rcc + .long __irq_exti0 + .long __irq_exti1 + .long __irq_exti2 + .long __irq_exti3 + .long __irq_exti4 + .long __irq_dma1_channel1 + .long __irq_dma1_channel2 + .long __irq_dma1_channel3 + .long __irq_dma1_channel4 + .long __irq_dma1_channel5 + .long __irq_dma1_channel6 + .long __irq_dma1_channel7 + .long __irq_adc + .long __irq_usb_hp_can_tx + .long __irq_usb_lp_can_rx0 + .long __irq_can_rx1 + .long __irq_can_sce + .long __irq_exti9_5 + .long __irq_tim1_brk + .long __irq_tim1_up + .long __irq_tim1_trg_com + .long __irq_tim1_cc + .long __irq_tim2 + .long __irq_tim3 + .long __irq_tim4 + .long __irq_i2c1_ev + .long __irq_i2c1_er + .long __irq_i2c2_ev + .long __irq_i2c2_er + .long __irq_spi1 + .long __irq_spi2 + .long __irq_usart1 + .long __irq_usart2 + .long __irq_usart3 + .long __irq_exti15_10 + .long __irq_rtcalarm + .long __irq_usbwakeup +#if defined (STM32_HIGH_DENSITY) + .long __irq_tim8_brk + .long __irq_tim8_up + .long __irq_tim8_trg_com + .long __irq_tim8_cc + .long __irq_adc3 + .long __irq_fsmc + .long __irq_sdio + .long __irq_tim5 + .long __irq_spi3 + .long __irq_uart4 + .long __irq_uart5 + .long __irq_tim6 + .long __irq_tim7 + .long __irq_dma2_channel1 + .long __irq_dma2_channel2 + .long __irq_dma2_channel3 + .long __irq_dma2_channel4_5 +#endif /* STM32_HIGH_DENSITY */ + + .long __irq_DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */ + .long __irq_ETH_IRQHandler /* Ethernet */ + .long __irq_ETH_WKUP_IRQHandler /* Ethernet Wakeup through EXTI line */ + .long __irq_CAN2_TX_IRQHandler /* CAN2 TX */ + .long __irq_CAN2_RX0_IRQHandler /* CAN2 RX0 */ + .long __irq_CAN2_RX1_IRQHandler /* CAN2 RX1 */ + .long __irq_CAN2_SCE_IRQHandler /* CAN2 SCE */ + .long __irq_OTG_FS_IRQHandler /* USB OTG FS */ + .long __irq_DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */ + .long __irq_DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */ + .long __irq_DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */ + .long __irq_USART6_IRQHandler /* USART6 */ + .long __irq_I2C3_EV_IRQHandler /* I2C3 event */ + .long __irq_I2C3_ER_IRQHandler /* I2C3 error */ + .long __irq_OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */ + .long __irq_OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */ + .long __irq_OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */ + .long __irq_OTG_HS_IRQHandler /* USB OTG HS */ + .long __irq_DCMI_IRQHandler /* DCMI */ + .long __irq_CRYP_IRQHandler /* CRYP crypto */ + .long __irq_HASH_RNG_IRQHandler /* Hash and Rng */ + .long __irq_FPU_IRQHandler /* FPU */ + + .size __stm32_vector_table, . - __stm32_vector_table diff --git a/STM32F4/variants/generic_f407v/variant.h b/STM32F4/variants/generic_f407v/variant.h new file mode 100644 index 0000000..cd0a96d --- /dev/null +++ b/STM32F4/variants/generic_f407v/variant.h @@ -0,0 +1,21 @@ +#ifndef _VARIANT_ARDUINO_STM32_ +#define _VARIANT_ARDUINO_STM32_ + + +#define digitalPinToPort(P) ( PIN_MAP[P].gpio_device ) +#define digitalPinToBitMask(P) ( BIT(PIN_MAP[P].gpio_bit) ) +#define portOutputRegister(port) ( &(port->regs->ODR) ) +#define portInputRegister(port) ( &(port->regs->IDR) ) + +#define portSetRegister(pin) ( &(PIN_MAP[pin].gpio_device->regs->BSRR) ) +#define portClearRegister(pin) ( &(PIN_MAP[pin].gpio_device->regs->BRR) ) + +#define portConfigRegister(pin) ( &(PIN_MAP[pin].gpio_device->regs->CRL) ) + +static const uint8_t SS = BOARD_SPI1_NSS_PIN; +static const uint8_t SS1 = BOARD_SPI2_NSS_PIN; +static const uint8_t MOSI = BOARD_SPI1_MOSI_PIN; +static const uint8_t MISO = BOARD_SPI1_MISO_PIN; +static const uint8_t SCK = BOARD_SPI1_SCK_PIN; + +#endif /* _VARIANT_ARDUINO_STM32_ */ \ No newline at end of file diff --git a/STM32F4/cores/maple/libmaple/rcc.c b/STM32F4/variants/generic_f407v/wirish/start.S similarity index 54% rename from STM32F4/cores/maple/libmaple/rcc.c rename to STM32F4/variants/generic_f407v/wirish/start.S index b3cb9c5..8b181aa 100644 --- a/STM32F4/cores/maple/libmaple/rcc.c +++ b/STM32F4/variants/generic_f407v/wirish/start.S @@ -1,7 +1,7 @@ /****************************************************************************** * The MIT License * - * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2011 LeafLabs, LLC. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -24,14 +24,34 @@ * SOFTWARE. *****************************************************************************/ -/** - * @file rcc.c - * @brief Implements pretty much only the basic clock setup on the - * stm32, clock enable/disable and peripheral reset commands. +/* + * This file is a modified version of a file obtained from + * CodeSourcery Inc. (now part of Mentor Graphics Corp.), in which the + * following text appeared: + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. */ -// #ifdef STM32F2 -// #include "rccF2.c" -// #else -// #include "rccF1.c" -// #endif + .text + .code 16 + .thumb_func + + .globl __start__ + .type __start__, %function +__start__: + .fnstart + ldr r1,=__msp_init + mov sp,r1 + ldr r1,=start_c + bx r1 + .pool + .cantunwind + .fnend diff --git a/STM32F4/variants/generic_f407v/wirish/start_c.c b/STM32F4/variants/generic_f407v/wirish/start_c.c new file mode 100644 index 0000000..655fefb --- /dev/null +++ b/STM32F4/variants/generic_f407v/wirish/start_c.c @@ -0,0 +1,95 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/* + * This file is a modified version of a file obtained from + * CodeSourcery Inc. (now part of Mentor Graphics Corp.), in which the + * following text appeared: + * + * Copyright (c) 2006, 2007 CodeSourcery Inc + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + */ + +#include + +extern void __libc_init_array(void); + +extern int main(int, char**, char**); + +extern void exit(int) __attribute__((noreturn, weak)); + +/* The linker must ensure that these are at least 4-byte aligned. */ +extern char __data_start__, __data_end__; +extern char __bss_start__, __bss_end__; + +struct rom_img_cfg { + int *img_start; +}; + +extern char _lm_rom_img_cfgp; + +void __attribute__((noreturn)) start_c(void) { + struct rom_img_cfg *img_cfg = (struct rom_img_cfg*)&_lm_rom_img_cfgp; + int *src = img_cfg->img_start; + int *dst = (int*)&__data_start__; + int exit_code; + + /* Initialize .data, if necessary. */ + if (src != dst) { + int *end = (int*)&__data_end__; + while (dst < end) { + *dst++ = *src++; + } + } + + /* Zero .bss. */ + dst = (int*)&__bss_start__; + while (dst < (int*)&__bss_end__) { + *dst++ = 0; + } + + /* Run initializers. */ + __libc_init_array(); + + /* Jump to main. */ + exit_code = main(0, 0, 0); + if (exit) { + exit(exit_code); + } + + /* If exit is NULL, make sure we don't return. */ + for (;;) + continue; +} From 8ba463a68ceeafa08674a7643ff967172525bea3 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Sat, 13 May 2017 14:30:24 +0200 Subject: [PATCH 045/351] improved SPI non-DMA block read routine, taken over from F4 --- STM32F1/libraries/SPI/src/SPI.cpp | 109 ++++++++++++++++-------------- STM32F1/libraries/SPI/src/SPI.h | 2 +- 2 files changed, 58 insertions(+), 53 deletions(-) diff --git a/STM32F1/libraries/SPI/src/SPI.cpp b/STM32F1/libraries/SPI/src/SPI.cpp index 34c8102..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));// 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); - spi_tx_dma_enable(_currentSetting->spi_d); 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; } } 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,25 +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); 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; } } 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) { @@ -492,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 fbd6927d56f333510f045de10a4bd1ad4a983a43 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Sun, 14 May 2017 16:27:43 +0200 Subject: [PATCH 046/351] resolve Invalid library version number --- STM32F4/libraries/arduino_uip/library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F4/libraries/arduino_uip/library.properties b/STM32F4/libraries/arduino_uip/library.properties index d707a44..ce2c43b 100644 --- a/STM32F4/libraries/arduino_uip/library.properties +++ b/STM32F4/libraries/arduino_uip/library.properties @@ -6,6 +6,6 @@ paragraph=implements the same API as stock Ethernet-lib. Just replace the includ category=Communication url=https://github.com/ntruchsess/arduino_uip architectures=STM32F4 -version=1.04 +version=1.0.4 dependencies= core-dependencies=arduino (>=1.5.0) From b8afde026a89ad63fc7e3faf4910381c6169ba7a Mon Sep 17 00:00:00 2001 From: stevstrong Date: Sun, 14 May 2017 16:31:11 +0200 Subject: [PATCH 047/351] increase digitalWrite() value parameter width to 16 bit - this useful for the 16 bit parallel TFT lib --- STM32F4/cores/maple/libmaple/gpio.h | 2 +- STM32F4/cores/maple/wirish_digital.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/STM32F4/cores/maple/libmaple/gpio.h b/STM32F4/cores/maple/libmaple/gpio.h index f1a141f..dcf1151 100644 --- a/STM32F4/cores/maple/libmaple/gpio.h +++ b/STM32F4/cores/maple/libmaple/gpio.h @@ -59,7 +59,7 @@ static inline afio_exti_port gpio_exti_port(const gpio_dev *dev) { * @param pin Pin on to set or reset * @param val If true, set the pin. If false, reset the pin. */ -static inline void gpio_write_pin(uint8_t pin, uint8 val) { +static inline void gpio_write_pin(uint8_t pin, uint16 val) { if (val) { (PIN_MAP[pin].gpio_device)->regs->BSRRL = BIT(pin&0x0F); } else { diff --git a/STM32F4/cores/maple/wirish_digital.cpp b/STM32F4/cores/maple/wirish_digital.cpp index 4a65619..4769051 100644 --- a/STM32F4/cores/maple/wirish_digital.cpp +++ b/STM32F4/cores/maple/wirish_digital.cpp @@ -94,7 +94,7 @@ uint32 digitalRead(uint8 pin) HIGH : LOW; } -void digitalWrite(uint8 pin, uint8 val) +void digitalWrite(uint8 pin, uint16 val) { if (pin >= BOARD_NR_GPIO_PINS) { return; From 20fbc3613dc11b75c2763defcc3592855ea07ed1 Mon Sep 17 00:00:00 2001 From: MicroBahner Date: Sun, 14 May 2017 21:21:03 +0200 Subject: [PATCH 048/351] donot disable Timer in pinMode --- STM32F1/cores/maple/stm32f1/wirish_digital_f1.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/STM32F1/cores/maple/stm32f1/wirish_digital_f1.cpp b/STM32F1/cores/maple/stm32f1/wirish_digital_f1.cpp index f16181d..74c6dc3 100644 --- a/STM32F1/cores/maple/stm32f1/wirish_digital_f1.cpp +++ b/STM32F1/cores/maple/stm32f1/wirish_digital_f1.cpp @@ -79,11 +79,10 @@ void pinMode(uint8 pin, WiringPinMode mode) { gpio_set_mode(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit, outputMode); - if (PIN_MAP[pin].timer_device != NULL) { - /* Enable/disable timer channels if we're switching into or - * out of PWM. */ + if (pwm && PIN_MAP[pin].timer_device != NULL) { + /* Enable/disable timer channels if we're switching into PWM. */ timer_set_mode(PIN_MAP[pin].timer_device, PIN_MAP[pin].timer_channel, - pwm ? TIMER_PWM : TIMER_DISABLED); + TIMER_PWM ); } } From 3d5c54e344ee8d8f769c318d034dd567da6ba25f Mon Sep 17 00:00:00 2001 From: edogaldo Date: Tue, 16 May 2017 00:00:59 +0200 Subject: [PATCH 049/351] 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: Fri, 19 May 2017 17:24:26 +0200 Subject: [PATCH 050/351] digital IO write optimizations for 16bit parallel display types - digitalWrite value increased to 16 bit width - added IO device bit access functions - removed PWM enable/disable from pinMode() --- STM32F4/cores/maple/io.h | 2 +- STM32F4/cores/maple/libmaple/gpio.h | 14 ++++++++++++-- STM32F4/cores/maple/wirish_digital.cpp | 6 +++--- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/STM32F4/cores/maple/io.h b/STM32F4/cores/maple/io.h index aeaf0fd..14546b8 100644 --- a/STM32F4/cores/maple/io.h +++ b/STM32F4/cores/maple/io.h @@ -121,7 +121,7 @@ void pinMode(uint8 pin, WiringPinMode mode); * @param value Either LOW (write a 0) or HIGH (write a 1). * @see pinMode() */ -void digitalWrite(uint8 pin, uint8 value); +void digitalWrite(uint8 pin, uint16 value); /** * Read a digital value from a pin. The pin must have its mode set to diff --git a/STM32F4/cores/maple/libmaple/gpio.h b/STM32F4/cores/maple/libmaple/gpio.h index dcf1151..3083247 100644 --- a/STM32F4/cores/maple/libmaple/gpio.h +++ b/STM32F4/cores/maple/libmaple/gpio.h @@ -60,10 +60,12 @@ static inline afio_exti_port gpio_exti_port(const gpio_dev *dev) { * @param val If true, set the pin. If false, reset the pin. */ static inline void gpio_write_pin(uint8_t pin, uint16 val) { + uint16_t bit = BIT(pin&0x0F); + gpio_reg_map *regs = (PIN_MAP[pin].gpio_device)->regs; if (val) { - (PIN_MAP[pin].gpio_device)->regs->BSRRL = BIT(pin&0x0F); + regs->BSRRL = bit; } else { - (PIN_MAP[pin].gpio_device)->regs->BSRRH = BIT(pin&0x0F); + regs->BSRRH = bit; } } @@ -71,10 +73,18 @@ static inline void gpio_set_pin(uint8_t pin) { (PIN_MAP[pin].gpio_device)->regs->BSRRL = BIT(pin&0x0F); } +static inline void gpio_set_dev_bit(const gpio_dev * dev, uint8_t bit) { + dev->regs->BSRRL = BIT(bit); +} + static inline void gpio_clear_pin(uint8_t pin) { (PIN_MAP[pin].gpio_device)->regs->BSRRH = BIT(pin&0x0F); } +static inline void gpio_clear_dev_bit(const gpio_dev * dev, uint8_t bit) { + dev->regs->BSRRH = BIT(bit); +} + /** * Determine whether or not a GPIO pin is set. * diff --git a/STM32F4/cores/maple/wirish_digital.cpp b/STM32F4/cores/maple/wirish_digital.cpp index 4769051..4630da7 100644 --- a/STM32F4/cores/maple/wirish_digital.cpp +++ b/STM32F4/cores/maple/wirish_digital.cpp @@ -73,14 +73,14 @@ void pinMode(uint8 pin, WiringPinMode mode) { } gpio_set_mode(pin, outputMode); - +/* if (PIN_MAP[pin].timer_device != NULL) { - /* Enable/disable timer channels if we're switching into or - * out of PWM. */ + // Enable/disable timer channels if we're switching into or out of PWM. timer_set_mode(PIN_MAP[pin].timer_device, PIN_MAP[pin].timer_channel, pwm ? TIMER_PWM : TIMER_DISABLED); } +*/ } From c294b0d0dcad974e66b85295933a16807d3a0637 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Fri, 19 May 2017 17:25:51 +0200 Subject: [PATCH 051/351] SPI DMA cleanup --- STM32F4/libraries/SPI/src/SPI.cpp | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/STM32F4/libraries/SPI/src/SPI.cpp b/STM32F4/libraries/SPI/src/SPI.cpp index cb8f561..18c54cb 100644 --- a/STM32F4/libraries/SPI/src/SPI.cpp +++ b/STM32F4/libraries/SPI/src/SPI.cpp @@ -428,14 +428,13 @@ uint8 SPIClass::dmaTransfer(void * transmitBuf, void * receiveBuf, uint16 length ); dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaStream, length); dma_set_fifo_flags(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaStream, 0); - dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaStream); // TX - uint32 flags = (DMA_MINC_MODE | DMA_FROM_MEM); // | DMA_TRNS_CMPLT); + uint32 flags = (DMA_MINC_MODE | DMA_FROM_MEM); if ( transmitBuf==0 ) { - static uint8_t ff = 0XFF; + static uint16_t ff = 0XFFFF; transmitBuf = &ff; - flags &= ~((uint32)DMA_MINC_MODE); // remove increment mode + flags ^= DMA_MINC_MODE; // remove increment mode } dma_setup_transfer( _currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream, @@ -457,19 +456,18 @@ uint8 SPIClass::dmaTransfer(void * transmitBuf, void * receiveBuf, uint16 length spi_tx_dma_enable(_currentSetting->spi_d); // must be the last enable to avoid DMA error flag uint32_t m = millis(); - while ((b = dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream) & DMA_ISR_TCIF)==0 ) {// wait for completion flag to be set - if ( b&(DMA_ISR_TEIF|DMA_ISR_DMEIF|DMA_ISR_FEIF) ) { b = 1; break; } // break on any error flag + while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream) & DMA_ISR_TCIF)==0 ) {// wait for completion flag to be set if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; } } - if (b & DMA_ISR_TCIF) b = 0; 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." // software disable sequence, see AN4031, chapter 4.1 spi_tx_dma_disable(_currentSetting->spi_d); spi_rx_dma_disable(_currentSetting->spi_d); + dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream); dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaStream); - dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream); + return b; } @@ -502,11 +500,9 @@ uint8 SPIClass::dmaSend(void * transmitBuf, uint16 length, bool minc) spi_tx_dma_enable(_currentSetting->spi_d); uint32_t m = millis(); - while ((b = dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream) & DMA_ISR_TCIF)==0 ) {// wait for completion flag to be set - if ( b&(DMA_ISR_TEIF|DMA_ISR_DMEIF|DMA_ISR_FEIF) ) { b = 1; break; } // break on any error flag + while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream) & DMA_ISR_TCIF)==0 ) {// wait for completion flag to be set if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; } } - if (b & DMA_ISR_TCIF) b = 0; 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." From a84b8b209ab4a143816c5221f94240551e4221ff Mon Sep 17 00:00:00 2001 From: stevstrong Date: Fri, 19 May 2017 17:26:16 +0200 Subject: [PATCH 052/351] cosmetics --- STM32F4/variants/generic_f407v/generic_f407v.h | 2 +- STM32F4/variants/generic_f407v/pin_map.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/STM32F4/variants/generic_f407v/generic_f407v.h b/STM32F4/variants/generic_f407v/generic_f407v.h index 927f9cd..f8a747f 100644 --- a/STM32F4/variants/generic_f407v/generic_f407v.h +++ b/STM32F4/variants/generic_f407v/generic_f407v.h @@ -87,7 +87,7 @@ #define BOARD_SPI2A_NSS_PIN PB9 //Port2Pin('B', 9) #define BOARD_SPI2A_SCK_PIN PB10 //Port2Pin('B',10) #define BOARD_SPI2A_MISO_PIN PC2 //Port2Pin('C', 2) -#define BOARD_SPI2A_MOSI_PIN pc3 //Port2Pin('C', 3) +#define BOARD_SPI2A_MOSI_PIN PC3 //Port2Pin('C', 3) #define BOARD_SPI3_NSS_PIN PA15 //Port2Pin('A',15) #define BOARD_SPI3_SCK_PIN PB3 //Port2Pin('B', 3) diff --git a/STM32F4/variants/generic_f407v/pin_map.c b/STM32F4/variants/generic_f407v/pin_map.c index 2189902..b21fac8 100644 --- a/STM32F4/variants/generic_f407v/pin_map.c +++ b/STM32F4/variants/generic_f407v/pin_map.c @@ -56,7 +56,7 @@ extern timer_dev timer8; /* typedef struct stm32_pin_info { - gpio_dev *gpio_device; // Maple pin's GPIO device + const gpio_dev * gpio_device; // Maple pin's GPIO device timer_dev *timer_device; // Pin's timer device, if any. uint8 timer_channel; // Timer channel, or 0 if none. uint8 adc_channel; // Pin ADC channel, or ADCx if none. From ba4f3808c2799ecbc53c78cb1514b195188b70d4 Mon Sep 17 00:00:00 2001 From: MicroBahner Date: Sat, 20 May 2017 16:11:00 +0200 Subject: [PATCH 053/351] channel output disabled in non pwm-mode pwmMode disables the channel output in non pwm modes. Attached ISRs are left unchanged --- STM32F1/cores/maple/stm32f1/wirish_digital_f1.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/STM32F1/cores/maple/stm32f1/wirish_digital_f1.cpp b/STM32F1/cores/maple/stm32f1/wirish_digital_f1.cpp index 74c6dc3..3ea5ed0 100644 --- a/STM32F1/cores/maple/stm32f1/wirish_digital_f1.cpp +++ b/STM32F1/cores/maple/stm32f1/wirish_digital_f1.cpp @@ -79,10 +79,14 @@ void pinMode(uint8 pin, WiringPinMode mode) { gpio_set_mode(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit, outputMode); - if (pwm && PIN_MAP[pin].timer_device != NULL) { - /* Enable/disable timer channels if we're switching into PWM. */ + if (PIN_MAP[pin].timer_device != NULL) { + if ( pwm ) { // we're switching into PWM, enable timer channels timer_set_mode(PIN_MAP[pin].timer_device, PIN_MAP[pin].timer_channel, TIMER_PWM ); + } else { // disable channel output in non pwm-Mode + timer_cc_disable(PIN_MAP[pin].timer_device, + PIN_MAP[pin].timer_channel); + } } } From f7a444b9ef0a269febcf1ebab50177690fa18c45 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Sun, 21 May 2017 11:01:22 +0200 Subject: [PATCH 054/351] implemented FSMC for driving an LCD on 16 bit parallel data bus --- STM32F4/cores/maple/libmaple/fsmc.c | 101 ++++++++---------- STM32F4/cores/maple/libmaple/fsmc.h | 44 ++++++-- STM32F4/cores/maple/libmaple/gpio.h | 16 +-- STM32F4/cores/maple/wirish_digital.cpp | 6 +- .../variants/generic_f407v/generic_f407v.h | 29 +++++ 5 files changed, 121 insertions(+), 75 deletions(-) diff --git a/STM32F4/cores/maple/libmaple/fsmc.c b/STM32F4/cores/maple/libmaple/fsmc.c index 42b0d77..04c7555 100644 --- a/STM32F4/cores/maple/libmaple/fsmc.c +++ b/STM32F4/cores/maple/libmaple/fsmc.c @@ -35,62 +35,53 @@ #ifdef STM32_HIGH_DENSITY /** - * Configure FSMC GPIOs for use with SRAM. - */ -void fsmc_sram_init_gpios(void) { - /* Data lines... */ - gpio_set_mode(PD0, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PD1, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PD8, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PD9, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PD10, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PD14, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PD15, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PE7, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PE8, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PE9, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PE10, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PE11, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PE12, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PE13, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PE14, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PE15, GPIO_AF_OUTPUT_PP); + * Configure FSMC GPIOs for use with LCDs. + */ - /* Address lines... */ - gpio_set_mode(PD11, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PD12, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PD13, GPIO_AF_OUTPUT_PP); -#if 0 // not available on LQFP package - gpio_set_mode(GPIOF, 0, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOF, 1, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOF, 2, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOF, 3, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOF, 4, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOF, 5, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOF, 12, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOF, 13, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOF, 14, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOF, 15, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOG, 0, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOG, 1, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOG, 2, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOG, 3, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOG, 4, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOG, 5, GPIO_AF_OUTPUT_PP); -#endif // not available on LQFP package - /* And control lines... */ - gpio_set_mode(PD4, GPIO_AF_OUTPUT_PP); // NOE - gpio_set_mode(PD5, GPIO_AF_OUTPUT_PP); // NWE - - gpio_set_mode(PD7, GPIO_AF_OUTPUT_PP); // NE1 -#if 0 // not available on LQFP package - gpio_set_mode(GPIOG, 9, GPIO_AF_OUTPUT_PP); // NE2 - gpio_set_mode(GPIOG, 10, GPIO_AF_OUTPUT_PP); // NE3 - gpio_set_mode(GPIOG, 12, GPIO_AF_OUTPUT_PP); // NE4 -#endif // not available on LQFP package - - gpio_set_mode(PE0, GPIO_AF_OUTPUT_PP); // NBL0 - gpio_set_mode(PE1, GPIO_AF_OUTPUT_PP); // NBL1 +void fsmc_init(void) { + rcc_clk_enable(RCC_FSMC); + rcc_reset_dev(RCC_FSMC); } +// used control, address and data lines +// NOE -> RD, NWE -> WR, A18 -> RS, NE1 -> CS +const uint8_t fsmc_pins[]= {FSMC_NOE, FSMC_NWE, FSMC_NE1, FSMC_A18, + FSMC_D0, FSMC_D1, FSMC_D2, FSMC_D3, + FSMC_D4, FSMC_D5, FSMC_D6, FSMC_D7, + FSMC_D8, FSMC_D9, FSMC_D10, FSMC_D11, + FSMC_D12, FSMC_D13, FSMC_D14, FSMC_D15}; + +void fsmc_lcd_init_gpios(void) { + uint8_t i; + for (i=0; i +#include "libmaple_types.h" + #ifdef __cplusplus extern "C"{ #endif @@ -62,27 +63,27 @@ typedef struct fsmc_reg_map { __io uint32 BTR3; /**< SRAM/NOR-Flash chip-select timing register 3 */ __io uint32 BCR4; /**< SRAM/NOR-Flash chip-select control register 4 */ __io uint32 BTR4; /**< SRAM/NOR-Flash chip-select timing register 4 */ - const uint8 RESERVED1[64]; /**< Reserved */ + const uint32 RESERVED1[16]; /**< Reserved */ __io uint32 PCR2; /**< PC Card/NAND Flash control register 2 */ __io uint32 SR2; /**< FIFO status and interrupt register 2 */ __io uint32 PMEM2; /**< Common memory space timing register 2 */ __io uint32 PATT2; /**< Attribute memory space timing register 2 */ - const uint8 RESERVED2[4]; /**< Reserved */ + const uint32 RESERVED2; /**< Reserved */ __io uint32 ECCR2; /**< ECC result register 2 */ - const uint8 RESERVED3[2]; + const uint32 RESERVED3[2]; /**< Reserved */ __io uint32 PCR3; /**< PC Card/NAND Flash control register 3 */ __io uint32 SR3; /**< FIFO status and interrupt register 3 */ __io uint32 PMEM3; /**< Common memory space timing register 3 */ __io uint32 PATT3; /**< Attribute memory space timing register 3 */ const uint32 RESERVED4; /**< Reserved */ __io uint32 ECCR3; /**< ECC result register 3 */ - const uint8 RESERVED5[8]; /**< Reserved */ + const uint32 RESERVED5[2]; /**< Reserved */ __io uint32 PCR4; /**< PC Card/NAND Flash control register 4 */ __io uint32 SR4; /**< FIFO status and interrupt register 4 */ __io uint32 PMEM4; /**< Common memory space timing register 4 */ __io uint32 PATT4; /**< Attribute memory space timing register 4 */ __io uint32 PIO4; /**< I/O space timing register 4 */ - const uint8 RESERVED6[80]; /**< Reserved */ + const uint32 RESERVED6[20]; /**< Reserved */ __io uint32 BWTR1; /**< SRAM/NOR-Flash write timing register 1 */ const uint32 RESERVED7; /**< Reserved */ __io uint32 BWTR2; /**< SRAM/NOR-Flash write timing register 2 */ @@ -101,7 +102,7 @@ typedef struct fsmc_reg_map { typedef struct fsmc_nor_psram_reg_map { __io uint32 BCR; /**< Chip-select control register */ __io uint32 BTR; /**< Chip-select timing register */ - const uint8 RESERVED[252]; /**< Reserved */ + const uint32 RESERVED[64]; /**< Reserved */ __io uint32 BWTR; /**< Write timing register */ } fsmc_nor_psram_reg_map; @@ -170,6 +171,13 @@ typedef struct fsmc_nor_psram_reg_map { #define FSMC_BTR_ADDHLD (0xF << 4) #define FSMC_BTR_ADDSET 0xF +#define FSMC_BTR_DATLAT_(x) ((x<<24)&FSMC_BTR_DATLAT) +#define FSMC_BTR_CLKDIV_(x) ((x<<20)&FSMC_BTR_CLKDIV) +#define FSMC_BTR_BUSTURN_(x) ((x<<16)&FSMC_BTR_BUSTURN) +#define FSMC_BTR_DATAST_(x) ((x<<8)&FSMC_BTR_DATAST) +#define FSMC_BTR_ADDHLD_(x) ((x<<4)&FSMC_BTR_ADDHLD) +#define FSMC_BTR_ADDSET_(x) ((x<<0)&FSMC_BTR_ADDSET) + /* SRAM/NOR-Flash write timing registers */ #define FSMC_BWTR_ACCMOD (0x3 << 28) @@ -280,8 +288,26 @@ typedef struct fsmc_nor_psram_reg_map { /* * SRAM/NOR Flash routines */ +extern volatile uint16_t * fsmcData; +extern volatile uint16_t * fsmcCommand; -void fsmc_sram_init_gpios(void); +void fsmc_lcd_init(void); + +static inline void fsmc_nor_psram_set_BCR(fsmc_nor_psram_reg_map *regs, uint32_t bcr) { + regs->BCR = bcr; +} + +static inline void fsmc_nor_psram_set_BTR(fsmc_nor_psram_reg_map *regs, uint32_t btr) { + regs->BTR = btr; +} + +static inline void fsmc_nor_psram_bank_enable(fsmc_nor_psram_reg_map *regs) { + regs->BCR |= FSMC_BCR_MBKEN; +} + +static inline void fsmc_nor_psram_bank_disable(fsmc_nor_psram_reg_map *regs) { + regs->BCR ^= FSMC_BCR_MBKEN; +} /** * Set the DATAST bits in the given NOR/PSRAM register map's diff --git a/STM32F4/cores/maple/libmaple/gpio.h b/STM32F4/cores/maple/libmaple/gpio.h index 3083247..7f2e7f5 100644 --- a/STM32F4/cores/maple/libmaple/gpio.h +++ b/STM32F4/cores/maple/libmaple/gpio.h @@ -69,22 +69,22 @@ static inline void gpio_write_pin(uint8_t pin, uint16 val) { } } -static inline void gpio_set_pin(uint8_t pin) { - (PIN_MAP[pin].gpio_device)->regs->BSRRL = BIT(pin&0x0F); -} - static inline void gpio_set_dev_bit(const gpio_dev * dev, uint8_t bit) { dev->regs->BSRRL = BIT(bit); } -static inline void gpio_clear_pin(uint8_t pin) { - (PIN_MAP[pin].gpio_device)->regs->BSRRH = BIT(pin&0x0F); -} - static inline void gpio_clear_dev_bit(const gpio_dev * dev, uint8_t bit) { dev->regs->BSRRH = BIT(bit); } +static inline void gpio_set_pin(uint8_t pin) { + gpio_set_dev_bit(PIN_MAP[pin].gpio_device, (pin&0x0F)); +} + +static inline void gpio_clear_pin(uint8_t pin) { + gpio_clear_dev_bit(PIN_MAP[pin].gpio_device, (pin&0x0F)); +} + /** * Determine whether or not a GPIO pin is set. * diff --git a/STM32F4/cores/maple/wirish_digital.cpp b/STM32F4/cores/maple/wirish_digital.cpp index 4630da7..c976fbf 100644 --- a/STM32F4/cores/maple/wirish_digital.cpp +++ b/STM32F4/cores/maple/wirish_digital.cpp @@ -33,7 +33,7 @@ void pinMode(uint8 pin, WiringPinMode mode) { gpio_pin_mode outputMode; - boolean pwm = false; +// boolean pwm = false; if (pin >= BOARD_NR_GPIO_PINS) { return; @@ -61,11 +61,11 @@ void pinMode(uint8 pin, WiringPinMode mode) { break; case PWM: outputMode = GPIO_AF_OUTPUT_PP; - pwm = true; +// pwm = true; break; case PWM_OPEN_DRAIN: outputMode = GPIO_AF_OUTPUT_OD; - pwm = true; +// pwm = true; break; default: ASSERT(0); diff --git a/STM32F4/variants/generic_f407v/generic_f407v.h b/STM32F4/variants/generic_f407v/generic_f407v.h index f8a747f..24fae50 100644 --- a/STM32F4/variants/generic_f407v/generic_f407v.h +++ b/STM32F4/variants/generic_f407v/generic_f407v.h @@ -106,6 +106,35 @@ #define BOARD_SDIO_CK PC12 //Port2Pin('C',12) #define BOARD_SDIO_CMD PD2 //Port2Pin('D', 2) +#define FSMC_NOE PD4 +#define FSMC_NWE PD5 +#define FSMC_NE1 PD7 +#define FSMC_A18 PD13 +#define FSMC_A17 PD12 +#define FSMC_A16 PD11 +#define FSMC_D0 PD14 +#define FSMC_D1 PD15 +#define FSMC_D2 PD0 +#define FSMC_D3 PD1 +#define FSMC_D4 PE7 +#define FSMC_D5 PE8 +#define FSMC_D6 PE9 +#define FSMC_D7 PE10 +#define FSMC_D8 PE11 +#define FSMC_D9 PE12 +#define FSMC_D10 PE13 +#define FSMC_D11 PE14 +#define FSMC_D12 PE15 +#define FSMC_D13 PD8 +#define FSMC_D14 PD9 +#define FSMC_D15 PD10 + +#define BOARD_T_CS BOARD_SPI2_NSS_PIN +#define BOARD_T_SCK BOARD_SPI2_SCK_PIN +#define BOARD_T_MISO BOARD_SPI2_MISO_PIN +#define BOARD_T_MOSI BOARD_SPI2_MOSI_PIN +#define BOARD_T_PEN PC5 + #define BOARD_NR_GPIO_PINS 80 #define BOARD_NR_PWM_PINS 22 #define BOARD_NR_ADC_PINS 16 From 8574d238e8ebd1700c98bb099f6da847046269b2 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Mon, 22 May 2017 17:36:50 +0200 Subject: [PATCH 055/351] added FSMC + SPI brought in line with F1 --- STM32F4/cores/maple/libmaple/fsmc.c | 101 ++++++++---------- STM32F4/cores/maple/libmaple/fsmc.h | 44 ++++++-- STM32F4/libraries/SPI/src/SPI.cpp | 10 +- .../variants/generic_f407v/generic_f407v.h | 31 +++++- 4 files changed, 114 insertions(+), 72 deletions(-) diff --git a/STM32F4/cores/maple/libmaple/fsmc.c b/STM32F4/cores/maple/libmaple/fsmc.c index 42b0d77..04c7555 100644 --- a/STM32F4/cores/maple/libmaple/fsmc.c +++ b/STM32F4/cores/maple/libmaple/fsmc.c @@ -35,62 +35,53 @@ #ifdef STM32_HIGH_DENSITY /** - * Configure FSMC GPIOs for use with SRAM. - */ -void fsmc_sram_init_gpios(void) { - /* Data lines... */ - gpio_set_mode(PD0, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PD1, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PD8, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PD9, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PD10, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PD14, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PD15, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PE7, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PE8, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PE9, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PE10, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PE11, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PE12, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PE13, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PE14, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PE15, GPIO_AF_OUTPUT_PP); + * Configure FSMC GPIOs for use with LCDs. + */ - /* Address lines... */ - gpio_set_mode(PD11, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PD12, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PD13, GPIO_AF_OUTPUT_PP); -#if 0 // not available on LQFP package - gpio_set_mode(GPIOF, 0, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOF, 1, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOF, 2, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOF, 3, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOF, 4, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOF, 5, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOF, 12, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOF, 13, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOF, 14, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOF, 15, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOG, 0, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOG, 1, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOG, 2, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOG, 3, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOG, 4, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOG, 5, GPIO_AF_OUTPUT_PP); -#endif // not available on LQFP package - /* And control lines... */ - gpio_set_mode(PD4, GPIO_AF_OUTPUT_PP); // NOE - gpio_set_mode(PD5, GPIO_AF_OUTPUT_PP); // NWE - - gpio_set_mode(PD7, GPIO_AF_OUTPUT_PP); // NE1 -#if 0 // not available on LQFP package - gpio_set_mode(GPIOG, 9, GPIO_AF_OUTPUT_PP); // NE2 - gpio_set_mode(GPIOG, 10, GPIO_AF_OUTPUT_PP); // NE3 - gpio_set_mode(GPIOG, 12, GPIO_AF_OUTPUT_PP); // NE4 -#endif // not available on LQFP package - - gpio_set_mode(PE0, GPIO_AF_OUTPUT_PP); // NBL0 - gpio_set_mode(PE1, GPIO_AF_OUTPUT_PP); // NBL1 +void fsmc_init(void) { + rcc_clk_enable(RCC_FSMC); + rcc_reset_dev(RCC_FSMC); } +// used control, address and data lines +// NOE -> RD, NWE -> WR, A18 -> RS, NE1 -> CS +const uint8_t fsmc_pins[]= {FSMC_NOE, FSMC_NWE, FSMC_NE1, FSMC_A18, + FSMC_D0, FSMC_D1, FSMC_D2, FSMC_D3, + FSMC_D4, FSMC_D5, FSMC_D6, FSMC_D7, + FSMC_D8, FSMC_D9, FSMC_D10, FSMC_D11, + FSMC_D12, FSMC_D13, FSMC_D14, FSMC_D15}; + +void fsmc_lcd_init_gpios(void) { + uint8_t i; + for (i=0; i +#include "libmaple_types.h" + #ifdef __cplusplus extern "C"{ #endif @@ -62,27 +63,27 @@ typedef struct fsmc_reg_map { __io uint32 BTR3; /**< SRAM/NOR-Flash chip-select timing register 3 */ __io uint32 BCR4; /**< SRAM/NOR-Flash chip-select control register 4 */ __io uint32 BTR4; /**< SRAM/NOR-Flash chip-select timing register 4 */ - const uint8 RESERVED1[64]; /**< Reserved */ + const uint32 RESERVED1[16]; /**< Reserved */ __io uint32 PCR2; /**< PC Card/NAND Flash control register 2 */ __io uint32 SR2; /**< FIFO status and interrupt register 2 */ __io uint32 PMEM2; /**< Common memory space timing register 2 */ __io uint32 PATT2; /**< Attribute memory space timing register 2 */ - const uint8 RESERVED2[4]; /**< Reserved */ + const uint32 RESERVED2; /**< Reserved */ __io uint32 ECCR2; /**< ECC result register 2 */ - const uint8 RESERVED3[2]; + const uint32 RESERVED3[2]; /**< Reserved */ __io uint32 PCR3; /**< PC Card/NAND Flash control register 3 */ __io uint32 SR3; /**< FIFO status and interrupt register 3 */ __io uint32 PMEM3; /**< Common memory space timing register 3 */ __io uint32 PATT3; /**< Attribute memory space timing register 3 */ const uint32 RESERVED4; /**< Reserved */ __io uint32 ECCR3; /**< ECC result register 3 */ - const uint8 RESERVED5[8]; /**< Reserved */ + const uint32 RESERVED5[2]; /**< Reserved */ __io uint32 PCR4; /**< PC Card/NAND Flash control register 4 */ __io uint32 SR4; /**< FIFO status and interrupt register 4 */ __io uint32 PMEM4; /**< Common memory space timing register 4 */ __io uint32 PATT4; /**< Attribute memory space timing register 4 */ __io uint32 PIO4; /**< I/O space timing register 4 */ - const uint8 RESERVED6[80]; /**< Reserved */ + const uint32 RESERVED6[20]; /**< Reserved */ __io uint32 BWTR1; /**< SRAM/NOR-Flash write timing register 1 */ const uint32 RESERVED7; /**< Reserved */ __io uint32 BWTR2; /**< SRAM/NOR-Flash write timing register 2 */ @@ -101,7 +102,7 @@ typedef struct fsmc_reg_map { typedef struct fsmc_nor_psram_reg_map { __io uint32 BCR; /**< Chip-select control register */ __io uint32 BTR; /**< Chip-select timing register */ - const uint8 RESERVED[252]; /**< Reserved */ + const uint32 RESERVED[63]; /**< Reserved */ __io uint32 BWTR; /**< Write timing register */ } fsmc_nor_psram_reg_map; @@ -170,6 +171,13 @@ typedef struct fsmc_nor_psram_reg_map { #define FSMC_BTR_ADDHLD (0xF << 4) #define FSMC_BTR_ADDSET 0xF +#define FSMC_BTR_DATLAT_(x) ((x<<24)&FSMC_BTR_DATLAT) +#define FSMC_BTR_CLKDIV_(x) ((x<<20)&FSMC_BTR_CLKDIV) +#define FSMC_BTR_BUSTURN_(x) ((x<<16)&FSMC_BTR_BUSTURN) +#define FSMC_BTR_DATAST_(x) ((x<<8)&FSMC_BTR_DATAST) +#define FSMC_BTR_ADDHLD_(x) ((x<<4)&FSMC_BTR_ADDHLD) +#define FSMC_BTR_ADDSET_(x) ((x<<0)&FSMC_BTR_ADDSET) + /* SRAM/NOR-Flash write timing registers */ #define FSMC_BWTR_ACCMOD (0x3 << 28) @@ -280,8 +288,26 @@ typedef struct fsmc_nor_psram_reg_map { /* * SRAM/NOR Flash routines */ +extern volatile uint16_t * fsmcData; +extern volatile uint16_t * fsmcCommand; -void fsmc_sram_init_gpios(void); +void fsmc_lcd_init(void); + +static inline void fsmc_nor_psram_set_BCR(fsmc_nor_psram_reg_map *regs, uint32_t bcr) { + regs->BCR = bcr; +} + +static inline void fsmc_nor_psram_set_BTR(fsmc_nor_psram_reg_map *regs, uint32_t btr) { + regs->BTR = btr; +} + +static inline void fsmc_nor_psram_bank_enable(fsmc_nor_psram_reg_map *regs) { + regs->BCR |= FSMC_BCR_MBKEN; +} + +static inline void fsmc_nor_psram_bank_disable(fsmc_nor_psram_reg_map *regs) { + regs->BCR ^= FSMC_BCR_MBKEN; +} /** * Set the DATAST bits in the given NOR/PSRAM register map's diff --git a/STM32F4/libraries/SPI/src/SPI.cpp b/STM32F4/libraries/SPI/src/SPI.cpp index cb8f561..c4ad5f2 100644 --- a/STM32F4/libraries/SPI/src/SPI.cpp +++ b/STM32F4/libraries/SPI/src/SPI.cpp @@ -457,19 +457,17 @@ uint8 SPIClass::dmaTransfer(void * transmitBuf, void * receiveBuf, uint16 length spi_tx_dma_enable(_currentSetting->spi_d); // must be the last enable to avoid DMA error flag uint32_t m = millis(); - while ((b = dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream) & DMA_ISR_TCIF)==0 ) {// wait for completion flag to be set - if ( b&(DMA_ISR_TEIF|DMA_ISR_DMEIF|DMA_ISR_FEIF) ) { b = 1; break; } // break on any error flag + while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream) & DMA_ISR_TCIF)==0 ) {// wait for completion flag to be set if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; } } - if (b & DMA_ISR_TCIF) b = 0; 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." // software disable sequence, see AN4031, chapter 4.1 spi_tx_dma_disable(_currentSetting->spi_d); spi_rx_dma_disable(_currentSetting->spi_d); + dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream); dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaStream); - dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream); return b; } @@ -502,11 +500,9 @@ uint8 SPIClass::dmaSend(void * transmitBuf, uint16 length, bool minc) spi_tx_dma_enable(_currentSetting->spi_d); uint32_t m = millis(); - while ((b = dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream) & DMA_ISR_TCIF)==0 ) {// wait for completion flag to be set - if ( b&(DMA_ISR_TEIF|DMA_ISR_DMEIF|DMA_ISR_FEIF) ) { b = 1; break; } // break on any error flag + while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream) & DMA_ISR_TCIF)==0 ) {// wait for completion flag to be set if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; } } - if (b & DMA_ISR_TCIF) b = 0; 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." diff --git a/STM32F4/variants/generic_f407v/generic_f407v.h b/STM32F4/variants/generic_f407v/generic_f407v.h index 927f9cd..24fae50 100644 --- a/STM32F4/variants/generic_f407v/generic_f407v.h +++ b/STM32F4/variants/generic_f407v/generic_f407v.h @@ -87,7 +87,7 @@ #define BOARD_SPI2A_NSS_PIN PB9 //Port2Pin('B', 9) #define BOARD_SPI2A_SCK_PIN PB10 //Port2Pin('B',10) #define BOARD_SPI2A_MISO_PIN PC2 //Port2Pin('C', 2) -#define BOARD_SPI2A_MOSI_PIN pc3 //Port2Pin('C', 3) +#define BOARD_SPI2A_MOSI_PIN PC3 //Port2Pin('C', 3) #define BOARD_SPI3_NSS_PIN PA15 //Port2Pin('A',15) #define BOARD_SPI3_SCK_PIN PB3 //Port2Pin('B', 3) @@ -106,6 +106,35 @@ #define BOARD_SDIO_CK PC12 //Port2Pin('C',12) #define BOARD_SDIO_CMD PD2 //Port2Pin('D', 2) +#define FSMC_NOE PD4 +#define FSMC_NWE PD5 +#define FSMC_NE1 PD7 +#define FSMC_A18 PD13 +#define FSMC_A17 PD12 +#define FSMC_A16 PD11 +#define FSMC_D0 PD14 +#define FSMC_D1 PD15 +#define FSMC_D2 PD0 +#define FSMC_D3 PD1 +#define FSMC_D4 PE7 +#define FSMC_D5 PE8 +#define FSMC_D6 PE9 +#define FSMC_D7 PE10 +#define FSMC_D8 PE11 +#define FSMC_D9 PE12 +#define FSMC_D10 PE13 +#define FSMC_D11 PE14 +#define FSMC_D12 PE15 +#define FSMC_D13 PD8 +#define FSMC_D14 PD9 +#define FSMC_D15 PD10 + +#define BOARD_T_CS BOARD_SPI2_NSS_PIN +#define BOARD_T_SCK BOARD_SPI2_SCK_PIN +#define BOARD_T_MISO BOARD_SPI2_MISO_PIN +#define BOARD_T_MOSI BOARD_SPI2_MOSI_PIN +#define BOARD_T_PEN PC5 + #define BOARD_NR_GPIO_PINS 80 #define BOARD_NR_PWM_PINS 22 #define BOARD_NR_ADC_PINS 16 From 70aa720e34afcb7f3278a5c368b91ba26cfde2f4 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Mon, 22 May 2017 17:53:17 +0200 Subject: [PATCH 056/351] corrected RESERVED size in fsmc_nor_psram_reg_map --- STM32F4/cores/maple/libmaple/fsmc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F4/cores/maple/libmaple/fsmc.h b/STM32F4/cores/maple/libmaple/fsmc.h index e975492..3501583 100644 --- a/STM32F4/cores/maple/libmaple/fsmc.h +++ b/STM32F4/cores/maple/libmaple/fsmc.h @@ -102,7 +102,7 @@ typedef struct fsmc_reg_map { typedef struct fsmc_nor_psram_reg_map { __io uint32 BCR; /**< Chip-select control register */ __io uint32 BTR; /**< Chip-select timing register */ - const uint32 RESERVED[64]; /**< Reserved */ + const uint32 RESERVED[63]; /**< Reserved */ __io uint32 BWTR; /**< Write timing register */ } fsmc_nor_psram_reg_map; From f1608abe0b8e250d22999a804fc105f391974305 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Mon, 22 May 2017 21:09:12 +0200 Subject: [PATCH 057/351] 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 058/351] 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 059/351] 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 060/351] 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 061/351] 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 062/351] 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 063/351] 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 84dd9162304a21c3b0799cb113d87b014662706c Mon Sep 17 00:00:00 2001 From: Tom Vijlbrief Date: Thu, 25 May 2017 20:53:24 +0200 Subject: [PATCH 064/351] Fix documentation for usart_putc() --- STM32F1/system/libmaple/include/libmaple/usart.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/STM32F1/system/libmaple/include/libmaple/usart.h b/STM32F1/system/libmaple/include/libmaple/usart.h index fa7c7fb..245ddab 100644 --- a/STM32F1/system/libmaple/include/libmaple/usart.h +++ b/STM32F1/system/libmaple/include/libmaple/usart.h @@ -439,8 +439,8 @@ static inline void usart_disable_all(void) { /** * @brief Transmit one character on a serial port. * - * This function blocks until the character has been successfully - * transmitted. + * This function blocks until the character has been queued + * for transmission. * * @param dev Serial port to send on. * @param byte Byte to transmit. From 66579ef8ef822fd188c11efd4e682d75b95126d8 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Fri, 26 May 2017 16:03:49 +1000 Subject: [PATCH 065/351] 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 066/351] 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 067/351] 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 54a23097839088747206b363bf477bc53fdba01c Mon Sep 17 00:00:00 2001 From: stevstrong Date: Fri, 2 Jun 2017 17:25:32 +0200 Subject: [PATCH 068/351] corrected digitalPinToBitMask(P) --- STM32F4/variants/generic_f407v/variant.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F4/variants/generic_f407v/variant.h b/STM32F4/variants/generic_f407v/variant.h index cd0a96d..95a7f39 100644 --- a/STM32F4/variants/generic_f407v/variant.h +++ b/STM32F4/variants/generic_f407v/variant.h @@ -3,7 +3,7 @@ #define digitalPinToPort(P) ( PIN_MAP[P].gpio_device ) -#define digitalPinToBitMask(P) ( BIT(PIN_MAP[P].gpio_bit) ) +#define digitalPinToBitMask(P) ( BIT(P&0x0F) ) #define portOutputRegister(port) ( &(port->regs->ODR) ) #define portInputRegister(port) ( &(port->regs->IDR) ) From 9e4b05289cff9067289bb32873c02c108a21b63d Mon Sep 17 00:00:00 2001 From: stevstrong Date: Fri, 2 Jun 2017 19:28:50 +0200 Subject: [PATCH 069/351] corrected digitalPinToBitMask(P) --- STM32F4/variants/generic_f407v/variant.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F4/variants/generic_f407v/variant.h b/STM32F4/variants/generic_f407v/variant.h index cd0a96d..95a7f39 100644 --- a/STM32F4/variants/generic_f407v/variant.h +++ b/STM32F4/variants/generic_f407v/variant.h @@ -3,7 +3,7 @@ #define digitalPinToPort(P) ( PIN_MAP[P].gpio_device ) -#define digitalPinToBitMask(P) ( BIT(PIN_MAP[P].gpio_bit) ) +#define digitalPinToBitMask(P) ( BIT(P&0x0F) ) #define portOutputRegister(port) ( &(port->regs->ODR) ) #define portInputRegister(port) ( &(port->regs->IDR) ) From 1c097cc8c3bfa2eb15dd92794aa9cc3d828d18ce Mon Sep 17 00:00:00 2001 From: stevstrong Date: Fri, 2 Jun 2017 19:32:34 +0200 Subject: [PATCH 070/351] added pin modes: GPIO_AF_OUTPUT_PP_PU (for SDIO) and GPIO_AF_INPUT_PU/PD --- .../cores/maple/libmaple/HardwareSerial.cpp | 4 ++-- STM32F4/cores/maple/libmaple/gpio_def.h | 21 ++++++++++--------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/STM32F4/cores/maple/libmaple/HardwareSerial.cpp b/STM32F4/cores/maple/libmaple/HardwareSerial.cpp index f9387d1..7f3d281 100644 --- a/STM32F4/cores/maple/libmaple/HardwareSerial.cpp +++ b/STM32F4/cores/maple/libmaple/HardwareSerial.cpp @@ -100,8 +100,8 @@ void HardwareSerial::begin(uint32 baud) { gpio_set_af_mode(tx_pin, 7); gpio_set_af_mode(rx_pin, 7); } - gpio_set_mode(tx_pin, (gpio_pin_mode)(GPIO_AF_OUTPUT_PP | GPIO_PUPD_INPUT_PU | 0x700)); - gpio_set_mode(rx_pin, (gpio_pin_mode)(GPIO_MODE_AF | GPIO_PUPD_INPUT_PU | 0x700)); + gpio_set_mode(tx_pin, (gpio_pin_mode)(GPIO_AF_OUTPUT_PP_PU | 0x700)); + gpio_set_mode(rx_pin, (gpio_pin_mode)(GPIO_AF_INPUT_PU | 0x700)); //gpio_set_mode(txi->gpio_device, txi->gpio_bit, (gpio_pin_mode)(GPIO_PUPD_INPUT_PU)); //gpio_set_mode(rxi->gpio_device, rxi->gpio_bit, (gpio_pin_mode)(GPIO_PUPD_INPUT_PU)); #else diff --git a/STM32F4/cores/maple/libmaple/gpio_def.h b/STM32F4/cores/maple/libmaple/gpio_def.h index cd1fb38..4a8e61e 100644 --- a/STM32F4/cores/maple/libmaple/gpio_def.h +++ b/STM32F4/cores/maple/libmaple/gpio_def.h @@ -125,9 +125,9 @@ extern gpio_dev* const GPIOG; #define GPIO_MODE_AF 2 #define GPIO_MODE_ANALOG 3 -#define GPIO_PUPD_INPUT_FLOATING (0 << 2) -#define GPIO_PUPD_INPUT_PU (1 << 2) -#define GPIO_PUPD_INPUT_PD (2 << 2) +#define GPIO_PUPD_NONE (0 << 2) +#define GPIO_PUPD_PU (1 << 2) +#define GPIO_PUPD_PD (2 << 2) #define GPIO_OSPEED_2MHZ (0 << 4) #define GPIO_OSPEED_25MHZ (1 << 4) @@ -177,18 +177,19 @@ typedef enum gpio_pin_mode { GPIO_AF_OUTPUT_PP = (GPIO_MODE_AF | GPIO_OTYPE_PP | GPIO_OSPEED_50MHZ), /**< Alternate function output push-pull. */ + GPIO_AF_OUTPUT_PP_PU = (GPIO_MODE_AF | GPIO_OTYPE_PP | GPIO_PUPD_PU | + GPIO_OSPEED_50MHZ), /**< Alternate function + output push-pull. */ GPIO_AF_OUTPUT_OD = (GPIO_MODE_AF | GPIO_OTYPE_OD | GPIO_OSPEED_50MHZ), /**< Alternate function output open drain. */ GPIO_INPUT_ANALOG = (GPIO_MODE_ANALOG), /**< Analog input. */ GPIO_INPUT_FLOATING = (GPIO_MODE_INPUT | - GPIO_PUPD_INPUT_FLOATING), /**< Input floating. */ - GPIO_INPUT_PD = (GPIO_MODE_INPUT | - GPIO_PUPD_INPUT_PD), /**< Input pull-down. */ - GPIO_INPUT_PU = (GPIO_MODE_INPUT | - GPIO_PUPD_INPUT_PU), /**< Input pull-up. */ - GPIO_AF_INPUT_PD = (GPIO_MODE_AF | - GPIO_PUPD_INPUT_PD), /**< Input pull-down. */ + GPIO_PUPD_NONE), /**< Input floating. */ + GPIO_INPUT_PU = (GPIO_MODE_INPUT | GPIO_PUPD_PU), /**< Input pull-up. */ + GPIO_INPUT_PD = (GPIO_MODE_INPUT | GPIO_PUPD_PD), /**< Input pull-down. */ + GPIO_AF_INPUT_PU = (GPIO_MODE_AF | GPIO_PUPD_PU), /**< Alternate input pull-up. */ + GPIO_AF_INPUT_PD = (GPIO_MODE_AF | GPIO_PUPD_PD), /**< Alternate input pull-down. */ GPIO_BIGNUMBER = 0xfff } gpio_pin_mode; From cbd20e93844fac77258e635b9cf208ca1178b5b2 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Fri, 2 Jun 2017 19:35:32 +0200 Subject: [PATCH 071/351] corrected digitalPinToBitMask(P) for disco F4, too --- STM32F4/variants/discovery_f407/variant.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F4/variants/discovery_f407/variant.h b/STM32F4/variants/discovery_f407/variant.h index 8a88623..8782ccc 100644 --- a/STM32F4/variants/discovery_f407/variant.h +++ b/STM32F4/variants/discovery_f407/variant.h @@ -2,7 +2,7 @@ #define _VARIANT_ARDUINO_STM32_ #define digitalPinToPort(P) ( PIN_MAP[P].gpio_device ) -#define digitalPinToBitMask(P) ( BIT(PIN_MAP[P].gpio_bit) ) +#define digitalPinToBitMask(P) ( BIT(P&0x0F) ) #define portOutputRegister(port) ( &(port->regs->ODR) ) #define portInputRegister(port) ( &(port->regs->IDR) ) From 642495bec9cbb4b8176bfa4ff208b78c7f84c48c Mon Sep 17 00:00:00 2001 From: stevstrong Date: Fri, 2 Jun 2017 19:37:36 +0200 Subject: [PATCH 072/351] corrected typo for BOARD_SDIO_CLK (generic F4) --- STM32F4/variants/generic_f407v/generic_f407v.h | 2 +- STM32F4/variants/generic_f407v/pin_map.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/STM32F4/variants/generic_f407v/generic_f407v.h b/STM32F4/variants/generic_f407v/generic_f407v.h index 24fae50..bc3b77b 100644 --- a/STM32F4/variants/generic_f407v/generic_f407v.h +++ b/STM32F4/variants/generic_f407v/generic_f407v.h @@ -103,7 +103,7 @@ #define BOARD_SDIO_D1 PC9 //Port2Pin('C', 9) #define BOARD_SDIO_D2 PC10 //Port2Pin('C',10) #define BOARD_SDIO_D3 PC11 //Port2Pin('C',11) -#define BOARD_SDIO_CK PC12 //Port2Pin('C',12) +#define BOARD_SDIO_CLK PC12 //Port2Pin('C',12) #define BOARD_SDIO_CMD PD2 //Port2Pin('D', 2) #define FSMC_NOE PD4 diff --git a/STM32F4/variants/generic_f407v/pin_map.c b/STM32F4/variants/generic_f407v/pin_map.c index 2189902..5ecde53 100644 --- a/STM32F4/variants/generic_f407v/pin_map.c +++ b/STM32F4/variants/generic_f407v/pin_map.c @@ -198,7 +198,7 @@ const uint8 boardUsedPins[BOARD_NR_USED_PINS] = { BOARD_JTMS_SWDIO_PIN, BOARD_JTCK_SWCLK_PIN, FLASH_CS_PIN, FLASH_CLK_PIN, FLASH_DO_PIN, FLASH_DI_PIN, NRF24_CE_PIN, NRF24_CS_PIN, NRF24_IRQ_PIN, - BOARD_SDIO_D0, BOARD_SDIO_D1, BOARD_SDIO_D2, BOARD_SDIO_D3, BOARD_SDIO_CK, BOARD_SDIO_CMD, + BOARD_SDIO_D0, BOARD_SDIO_D1, BOARD_SDIO_D2, BOARD_SDIO_D3, BOARD_SDIO_CLK, BOARD_SDIO_CMD, USB_DM_PIN, USB_DP_PIN }; From 6dde3d39b401b01695c2844635331df1a1226b4e Mon Sep 17 00:00:00 2001 From: stevstrong Date: Fri, 2 Jun 2017 20:26:55 +0200 Subject: [PATCH 073/351] added serial bool operator for "if(!Serial)" --- STM32F4/cores/maple/libmaple/HardwareSerial.h | 1 + 1 file changed, 1 insertion(+) diff --git a/STM32F4/cores/maple/libmaple/HardwareSerial.h b/STM32F4/cores/maple/libmaple/HardwareSerial.h index d7e8a3d..b49c4cf 100644 --- a/STM32F4/cores/maple/libmaple/HardwareSerial.h +++ b/STM32F4/cores/maple/libmaple/HardwareSerial.h @@ -57,6 +57,7 @@ public: void begin(uint32 baud); void end(void); + operator bool() { return true; } // This is needed because of "if (!Serial)" /* I/O */ virtual int available(void); virtual int peek(void); From 9ae2f6fa78bc258d61a11fc3f0157fd3537780d0 Mon Sep 17 00:00:00 2001 From: Zou Hanya Date: Sat, 3 Jun 2017 08:27:33 +0900 Subject: [PATCH 074/351] 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 075/351] 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 076/351] 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) { From bf138eb389c50f68de28d708033442f8d4584c2b Mon Sep 17 00:00:00 2001 From: SukkoPera Date: Fri, 9 Jun 2017 22:07:05 +0200 Subject: [PATCH 077/351] Remove isConnected() usage from examples --- .../examples/General/BlinkNcount/BlinkNcount.ino | 2 +- .../examples/General/IntegerInput/IntegerInput.ino | 2 +- .../IntegerInput_FloatOutput/IntegerInput_FloatOutput.ino | 2 +- .../General/InternalTempSensor/InternalTempSensor.ino | 6 +++--- .../A_STM32_Examples/examples/General/PrimeNos/PrimeNos.ino | 2 +- .../examples/General/PrimeNos2/PrimeNos2.ino | 2 +- .../examples/General/PrimeNos3/PrimeNos3.ino | 2 +- .../examples/General/Print_Binary/Print_Binary.ino | 2 +- .../examples/General/Print_Float/Print_Float.ino | 2 +- .../examples/General/Print_HEX/Print_HEX.ino | 2 +- .../examples/General/SerialReadUntil/SerialReadUntil.ino | 2 +- .../examples/General/USB_ASCII/USB_ASCII.ino | 2 +- .../General/strtol_DecEquivalents/strtol_DecEquivalents.ino | 2 +- 13 files changed, 15 insertions(+), 15 deletions(-) diff --git a/STM32F1/libraries/A_STM32_Examples/examples/General/BlinkNcount/BlinkNcount.ino b/STM32F1/libraries/A_STM32_Examples/examples/General/BlinkNcount/BlinkNcount.ino index 7cabfde..1b1f58a 100644 --- a/STM32F1/libraries/A_STM32_Examples/examples/General/BlinkNcount/BlinkNcount.ino +++ b/STM32F1/libraries/A_STM32_Examples/examples/General/BlinkNcount/BlinkNcount.ino @@ -15,7 +15,7 @@ void setup() { // Initialize virtual COM over USB on Maple Mini Serial.begin(9600); // BAUD has no effect on USB serial: placeholder for physical UART // wait for serial monitor to be connected. - while (!(Serial.isConnected() && (Serial.getDTR() || Serial.getRTS()))) + while (!Serial) { digitalWrite(33,!digitalRead(33));// Turn the LED from off to on, or on to off delay(100); // fast blink diff --git a/STM32F1/libraries/A_STM32_Examples/examples/General/IntegerInput/IntegerInput.ino b/STM32F1/libraries/A_STM32_Examples/examples/General/IntegerInput/IntegerInput.ino index 55a68e8..4a1d16a 100644 --- a/STM32F1/libraries/A_STM32_Examples/examples/General/IntegerInput/IntegerInput.ino +++ b/STM32F1/libraries/A_STM32_Examples/examples/General/IntegerInput/IntegerInput.ino @@ -18,7 +18,7 @@ void setup() Serial.begin(BAUD); // BAUD has no effect on USB serial: placeholder for physical UART Serial.setTimeout(timeoutPeriod); // default is 1 second // wait for serial monitor to be connected. - while (!(Serial.isConnected() && (Serial.getDTR() || Serial.getRTS()))) + while (!Serial) { digitalWrite(33,!digitalRead(33));// Turn the LED from off to on, or on to off delay(100); // fast blink diff --git a/STM32F1/libraries/A_STM32_Examples/examples/General/IntegerInput_FloatOutput/IntegerInput_FloatOutput.ino b/STM32F1/libraries/A_STM32_Examples/examples/General/IntegerInput_FloatOutput/IntegerInput_FloatOutput.ino index 6f04840..b82394e 100644 --- a/STM32F1/libraries/A_STM32_Examples/examples/General/IntegerInput_FloatOutput/IntegerInput_FloatOutput.ino +++ b/STM32F1/libraries/A_STM32_Examples/examples/General/IntegerInput_FloatOutput/IntegerInput_FloatOutput.ino @@ -19,7 +19,7 @@ void setup() Serial.begin(BAUD); // BAUD has no effect on USB serial: placeholder for physical UART Serial.setTimeout(timeoutPeriod); // default is 1 second // wait for serial monitor to be connected. - while (!(Serial.isConnected() && (Serial.getDTR() || Serial.getRTS()))) + while (!Serial) { digitalWrite(33,!digitalRead(33));// Turn the LED from off to on, or on to off delay(100); // fast blink diff --git a/STM32F1/libraries/A_STM32_Examples/examples/General/InternalTempSensor/InternalTempSensor.ino b/STM32F1/libraries/A_STM32_Examples/examples/General/InternalTempSensor/InternalTempSensor.ino index d6000cd..871ae25 100644 --- a/STM32F1/libraries/A_STM32_Examples/examples/General/InternalTempSensor/InternalTempSensor.ino +++ b/STM32F1/libraries/A_STM32_Examples/examples/General/InternalTempSensor/InternalTempSensor.ino @@ -38,7 +38,7 @@ void setup(void) pinMode(A_RANDOM_ANALOG_PIN, INPUT_ANALOG); // wait for serial monitor to be connected. - while (!(Serial.isConnected() && (Serial.getDTR() || Serial.getRTS()))) + while (!Serial) { digitalWrite(33,!digitalRead(33));// Turn the LED from off to on, or on to off delay(100); // fast blink @@ -48,7 +48,7 @@ void setup(void) setup_temperature_sensor(); // announce start up - if(Serial.isConnected() && (Serial.getDTR() || Serial.getRTS())) + if(Serial) Serial.println("Temp mon startup"); } @@ -69,7 +69,7 @@ void loop(void) t2 = micros(); vsense = adc_read(ADC1, 16); t3 = micros(); - if(Serial.isConnected() && (Serial.getDTR() || Serial.getRTS())) { + if(Serial) { sprintf(buf,"%04x %08x %04x %08x" , vsense, t3-t2, alogpin, t2-t1); Serial.println(buf); } diff --git a/STM32F1/libraries/A_STM32_Examples/examples/General/PrimeNos/PrimeNos.ino b/STM32F1/libraries/A_STM32_Examples/examples/General/PrimeNos/PrimeNos.ino index 09a7a3f..c744219 100644 --- a/STM32F1/libraries/A_STM32_Examples/examples/General/PrimeNos/PrimeNos.ino +++ b/STM32F1/libraries/A_STM32_Examples/examples/General/PrimeNos/PrimeNos.ino @@ -29,7 +29,7 @@ void setup() pinMode(33, OUTPUT); Serial.begin(BAUD); // BAUD has no effect on USB serial: placeholder for physical UART // wait for serial monitor to be connected. - while (!(Serial.isConnected() && (Serial.getDTR() || Serial.getRTS()))) + while (!Serial) { digitalWrite(33,!digitalRead(33));// Turn the LED from off to on, or on to off delay(100); // fast blink diff --git a/STM32F1/libraries/A_STM32_Examples/examples/General/PrimeNos2/PrimeNos2.ino b/STM32F1/libraries/A_STM32_Examples/examples/General/PrimeNos2/PrimeNos2.ino index 51fe332..a2fd1c9 100644 --- a/STM32F1/libraries/A_STM32_Examples/examples/General/PrimeNos2/PrimeNos2.ino +++ b/STM32F1/libraries/A_STM32_Examples/examples/General/PrimeNos2/PrimeNos2.ino @@ -18,7 +18,7 @@ void setup() { pinMode(33, OUTPUT); Serial.begin(BAUD); // BAUD has no effect on USB serial: placeholder for physical UART // wait for serial monitor to be connected. - while (!(Serial.isConnected() && (Serial.getDTR() || Serial.getRTS()))) + while (!Serial) { digitalWrite(33,!digitalRead(33));// Turn the LED from off to on, or on to off delay(100); // fast blink diff --git a/STM32F1/libraries/A_STM32_Examples/examples/General/PrimeNos3/PrimeNos3.ino b/STM32F1/libraries/A_STM32_Examples/examples/General/PrimeNos3/PrimeNos3.ino index eec3dc0..8e8fe88 100644 --- a/STM32F1/libraries/A_STM32_Examples/examples/General/PrimeNos3/PrimeNos3.ino +++ b/STM32F1/libraries/A_STM32_Examples/examples/General/PrimeNos3/PrimeNos3.ino @@ -18,7 +18,7 @@ void setup() { pinMode(33, OUTPUT); Serial.begin(BAUD); // BAUD has no effect on USB serial: placeholder for physical UART // wait for serial monitor to be connected. - while (!(Serial.isConnected() && (Serial.getDTR() || Serial.getRTS()))) + while (!Serial) { digitalWrite(33,!digitalRead(33));// Turn the LED from off to on, or on to off delay(100); // fast blink diff --git a/STM32F1/libraries/A_STM32_Examples/examples/General/Print_Binary/Print_Binary.ino b/STM32F1/libraries/A_STM32_Examples/examples/General/Print_Binary/Print_Binary.ino index c9c4b88..7409ba5 100644 --- a/STM32F1/libraries/A_STM32_Examples/examples/General/Print_Binary/Print_Binary.ino +++ b/STM32F1/libraries/A_STM32_Examples/examples/General/Print_Binary/Print_Binary.ino @@ -15,7 +15,7 @@ void setup() pinMode(33, OUTPUT); Serial.begin(BAUD); // BAUD has no effect on USB serial: placeholder for physical UART // wait for serial monitor to be connected. - while (!(Serial.isConnected() && (Serial.getDTR() || Serial.getRTS()))) + while (!Serial) { digitalWrite(33,!digitalRead(33));// Turn the LED from off to on, or on to off delay(100); // fast blink diff --git a/STM32F1/libraries/A_STM32_Examples/examples/General/Print_Float/Print_Float.ino b/STM32F1/libraries/A_STM32_Examples/examples/General/Print_Float/Print_Float.ino index 289db9e..4351d31 100644 --- a/STM32F1/libraries/A_STM32_Examples/examples/General/Print_Float/Print_Float.ino +++ b/STM32F1/libraries/A_STM32_Examples/examples/General/Print_Float/Print_Float.ino @@ -17,7 +17,7 @@ void setup() // run once, when the sketch starts pinMode(33, OUTPUT); Serial.begin(BAUD); // BAUD has no effect on USB serial: placeholder for physical UART // wait for serial monitor to be connected. - while (!(Serial.isConnected() && (Serial.getDTR() || Serial.getRTS()))) + while (!Serial) { digitalWrite(33,!digitalRead(33));// Turn the LED from off to on, or on to off delay(100); // fast blink diff --git a/STM32F1/libraries/A_STM32_Examples/examples/General/Print_HEX/Print_HEX.ino b/STM32F1/libraries/A_STM32_Examples/examples/General/Print_HEX/Print_HEX.ino index cfdb977..2dc41fe 100644 --- a/STM32F1/libraries/A_STM32_Examples/examples/General/Print_HEX/Print_HEX.ino +++ b/STM32F1/libraries/A_STM32_Examples/examples/General/Print_HEX/Print_HEX.ino @@ -16,7 +16,7 @@ void setup() // run once, when the sketch starts pinMode(33, OUTPUT); Serial.begin(BAUD); // BAUD has no effect on USB serial: placeholder for physical UART // wait for serial monitor to be connected. - while (!(Serial.isConnected() && (Serial.getDTR() || Serial.getRTS()))) + while (!Serial) { digitalWrite(33,!digitalRead(33));// Turn the LED from off to on, or on to off delay(100); // fast blink diff --git a/STM32F1/libraries/A_STM32_Examples/examples/General/SerialReadUntil/SerialReadUntil.ino b/STM32F1/libraries/A_STM32_Examples/examples/General/SerialReadUntil/SerialReadUntil.ino index 1e7d400..80d3b3b 100644 --- a/STM32F1/libraries/A_STM32_Examples/examples/General/SerialReadUntil/SerialReadUntil.ino +++ b/STM32F1/libraries/A_STM32_Examples/examples/General/SerialReadUntil/SerialReadUntil.ino @@ -13,7 +13,7 @@ void setup() { pinMode(33, OUTPUT); Serial.begin(BAUD); // BAUD has no effect on USB serial: placeholder for physical UAR // wait for serial monitor to be connected. - while (!(Serial.isConnected() && (Serial.getDTR() || Serial.getRTS()))) + while (!Serial) { digitalWrite(33,!digitalRead(33));// Turn the LED from off to on, or on to off delay(100); // fast blink diff --git a/STM32F1/libraries/A_STM32_Examples/examples/General/USB_ASCII/USB_ASCII.ino b/STM32F1/libraries/A_STM32_Examples/examples/General/USB_ASCII/USB_ASCII.ino index e38b176..a884978 100644 --- a/STM32F1/libraries/A_STM32_Examples/examples/General/USB_ASCII/USB_ASCII.ino +++ b/STM32F1/libraries/A_STM32_Examples/examples/General/USB_ASCII/USB_ASCII.ino @@ -34,7 +34,7 @@ void setup() { pinMode(33, OUTPUT); Serial.begin(); // USB does not require BAUD // wait for serial monitor to be connected. - while (!(Serial.isConnected() && (Serial.getDTR() || Serial.getRTS()))) + while (!Serial) { digitalWrite(33,!digitalRead(33));// Turn the LED from off to on, or on to off delay(100); // fast blink diff --git a/STM32F1/libraries/A_STM32_Examples/examples/General/strtol_DecEquivalents/strtol_DecEquivalents.ino b/STM32F1/libraries/A_STM32_Examples/examples/General/strtol_DecEquivalents/strtol_DecEquivalents.ino index 7d799af..f759471 100644 --- a/STM32F1/libraries/A_STM32_Examples/examples/General/strtol_DecEquivalents/strtol_DecEquivalents.ino +++ b/STM32F1/libraries/A_STM32_Examples/examples/General/strtol_DecEquivalents/strtol_DecEquivalents.ino @@ -19,7 +19,7 @@ void setup() { pinMode(33, OUTPUT); Serial.begin(9600); // wait for serial monitor to be connected. - while (!(Serial.isConnected() && (Serial.getDTR() || Serial.getRTS()))) + while (!Serial) { digitalWrite(33,!digitalRead(33));// Turn the LED from off to on, or on to off delay(100); // fast blink From c4643b265ec344365d9d547ac4f8859d2e20083c Mon Sep 17 00:00:00 2001 From: SukkoPera Date: Fri, 9 Jun 2017 22:07:33 +0200 Subject: [PATCH 078/351] Remove isConnected() usage and binary zeros from StringEx_Parsinge xample --- .../StringEx_Parsing/StringEx_Parsing.ino | Bin 3285 -> 3217 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/STM32F1/libraries/A_STM32_Examples/examples/General/StringEx_Parsing/StringEx_Parsing.ino b/STM32F1/libraries/A_STM32_Examples/examples/General/StringEx_Parsing/StringEx_Parsing.ino index d98193c351739023a243a659979419438b658719..fd30b4ca30fcbbae814efffd42c6611eba5a2119 100644 GIT binary patch delta 69 zcmV-L0J{Ix8Ic*Vcmb1n0apWBL@blq0d$j30(G;+0yYB%Q)O~#VQjNG24V%1oeTX5 bTrfH?crs&LFq5GS7y$~CuL~6f3MwxOLQEB= delta 157 zcmbOzc~x>l1tX)v Date: Sun, 11 Jun 2017 15:35:14 +1000 Subject: [PATCH 079/351] Added an additional SPI API function dmaSendAsync which will start the a DMA send of a buffer and return immediately. The next time dmaSendAsync is called it waits if the previous transfer is not complete. Note the buffer is not copied, so ddouble buffering is needed to use this function --- STM32F1/libraries/SPI/src/SPI.cpp | 42 +++++++++++++++++++++++++++++++ STM32F1/libraries/SPI/src/SPI.h | 2 +- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/STM32F1/libraries/SPI/src/SPI.cpp b/STM32F1/libraries/SPI/src/SPI.cpp index 1108014..f0d9f7f 100644 --- a/STM32F1/libraries/SPI/src/SPI.cpp +++ b/STM32F1/libraries/SPI/src/SPI.cpp @@ -469,6 +469,48 @@ uint8 SPIClass::dmaSend(void * transmitBuf, uint16 length, bool minc) return b; } + +uint8 SPIClass::dmaSendAsync(void * transmitBuf, uint16 length, bool minc) +{ + static bool isRunning=false; + uint8 b = 0; + + if (isRunning) + { + + 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; } + } + + 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." + spi_tx_dma_disable(_currentSetting->spi_d); + dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); + isRunning=false; + } + + + if (length == 0) return 0; + uint32 flags = ( (DMA_MINC_MODE*minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT); + + dma_init(_currentSetting->spiDmaDev); + // TX + 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); + + isRunning=true; + + 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 b662384..4d9b563 100644 --- a/STM32F1/libraries/SPI/src/SPI.h +++ b/STM32F1/libraries/SPI/src/SPI.h @@ -291,7 +291,7 @@ public: * @param length Number of bytes in buffer to transmit. */ uint8 dmaSend(void * transmitBuf, uint16 length, bool minc = 1); - + uint8 dmaSendAsync(void * transmitBuf, uint16 length, bool minc = 1); /* * Pin accessors */ From f47846662db1c7aa61430ca5ffcde8ce9d6b9579 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Sun, 11 Jun 2017 15:42:05 +1000 Subject: [PATCH 080/351] Added Wire.end() for bit banged version (TwoWire.cpp) --- STM32F1/libraries/Wire/Wire.cpp | 12 ++++++++++++ STM32F1/libraries/Wire/Wire.h | 9 +++++++++ 2 files changed, 21 insertions(+) diff --git a/STM32F1/libraries/Wire/Wire.cpp b/STM32F1/libraries/Wire/Wire.cpp index abc57f8..01ee72f 100644 --- a/STM32F1/libraries/Wire/Wire.cpp +++ b/STM32F1/libraries/Wire/Wire.cpp @@ -184,6 +184,18 @@ void TwoWire::begin(uint8 self_addr) { set_sda(HIGH); } +void TwoWire::end() +{ + if (this->scl_pin) + { + pinMode(this->scl_pin, INPUT); + } + if (this->sda_pin) + { + pinMode(this->sda_pin, INPUT); + } +} + TwoWire::~TwoWire() { this->scl_pin=0; this->sda_pin=0; diff --git a/STM32F1/libraries/Wire/Wire.h b/STM32F1/libraries/Wire/Wire.h index add0ac9..c7edfef 100644 --- a/STM32F1/libraries/Wire/Wire.h +++ b/STM32F1/libraries/Wire/Wire.h @@ -111,6 +111,10 @@ class TwoWire : public WireBase { * Shifts out the data through SDA and clocks SCL for the slave device */ void i2c_shift_out(uint8); + + + + protected: /* * Processes the incoming I2C message defined by WireBase @@ -130,6 +134,11 @@ class TwoWire : public WireBase { */ void begin(uint8 = 0x00); + /* + * Sets pins SDA and SCL to INPUT + */ + void end(); + /* * If object is destroyed, set pin numbers to 0. */ From 953aa8b88e0c9479e591c693a03b6fa37a64a73a Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Sun, 11 Jun 2017 15:55:08 +1000 Subject: [PATCH 081/351] Added end() to HardWire (I2C) --- STM32F1/libraries/Wire/HardWire.cpp | 5 +++++ STM32F1/libraries/Wire/HardWire.h | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/STM32F1/libraries/Wire/HardWire.cpp b/STM32F1/libraries/Wire/HardWire.cpp index 8a63183..b3c1850 100644 --- a/STM32F1/libraries/Wire/HardWire.cpp +++ b/STM32F1/libraries/Wire/HardWire.cpp @@ -75,3 +75,8 @@ HardWire::~HardWire() { void HardWire::begin(uint8 self_addr) { i2c_master_enable(sel_hard, dev_flags); } + +void HardWire:end() { + i2c_disable(sel_hard); + sel_hard = 0; +} diff --git a/STM32F1/libraries/Wire/HardWire.h b/STM32F1/libraries/Wire/HardWire.h index 6f137b8..6f30cb3 100644 --- a/STM32F1/libraries/Wire/HardWire.h +++ b/STM32F1/libraries/Wire/HardWire.h @@ -59,6 +59,11 @@ public: * passed flags */ HardWire(uint8, uint8 = 0); + + /* + * Shuts down (disables) the hardware I2C + */ + void end(); /* * Disables the I2C device and remove the device address. From cc355255ac9b6358a4cd6e32b1d8216a49364764 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Mon, 12 Jun 2017 16:42:49 +1000 Subject: [PATCH 082/351] Added WS2812B (aka Neopixel) library using SPI DMA asynchronous transfers and double buffering --- STM32F1/libraries/WS2812B | 1 + 1 file changed, 1 insertion(+) create mode 160000 STM32F1/libraries/WS2812B diff --git a/STM32F1/libraries/WS2812B b/STM32F1/libraries/WS2812B new file mode 160000 index 0000000..b7f1e27 --- /dev/null +++ b/STM32F1/libraries/WS2812B @@ -0,0 +1 @@ +Subproject commit b7f1e2709e48f533e4d43aec3d36f8c48337bc31 From 7487d96f70ba3f78c00623556267cff6fb3a223c Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Tue, 13 Jun 2017 08:32:56 +1000 Subject: [PATCH 083/351] Fix typo in Hardware end() --- STM32F1/libraries/Wire/HardWire.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/libraries/Wire/HardWire.cpp b/STM32F1/libraries/Wire/HardWire.cpp index b3c1850..1f3ebf2 100644 --- a/STM32F1/libraries/Wire/HardWire.cpp +++ b/STM32F1/libraries/Wire/HardWire.cpp @@ -76,7 +76,7 @@ void HardWire::begin(uint8 self_addr) { i2c_master_enable(sel_hard, dev_flags); } -void HardWire:end() { +void HardWire::end() { i2c_disable(sel_hard); sel_hard = 0; } From 40dd7c6fe1a3f48a9657f54516737e80a78291a3 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Tue, 13 Jun 2017 10:37:16 +1000 Subject: [PATCH 084/351] Removed WS2812B lib as it had a .git folder in it which was causing problems --- STM32F1/libraries/WS2812B | 1 - 1 file changed, 1 deletion(-) delete mode 160000 STM32F1/libraries/WS2812B diff --git a/STM32F1/libraries/WS2812B b/STM32F1/libraries/WS2812B deleted file mode 160000 index b7f1e27..0000000 --- a/STM32F1/libraries/WS2812B +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b7f1e2709e48f533e4d43aec3d36f8c48337bc31 From ca484b4fdd2efcc1338381021ac267a211751639 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Tue, 13 Jun 2017 10:38:05 +1000 Subject: [PATCH 085/351] Add WS2812B library again, but this time without the .git folder in it --- STM32F1/libraries/WS2812B/README.md | 78 +++++ .../examples/WS2812B_test/WS2812B_test.ino | 303 ++++++++++++++++++ STM32F1/libraries/WS2812B/keywords.txt | 27 ++ STM32F1/libraries/WS2812B/library.properties | 10 + STM32F1/libraries/WS2812B/src/WS2812B.cpp | 238 ++++++++++++++ STM32F1/libraries/WS2812B/src/WS2812B.h | 81 +++++ 6 files changed, 737 insertions(+) create mode 100644 STM32F1/libraries/WS2812B/README.md create mode 100644 STM32F1/libraries/WS2812B/examples/WS2812B_test/WS2812B_test.ino create mode 100644 STM32F1/libraries/WS2812B/keywords.txt create mode 100644 STM32F1/libraries/WS2812B/library.properties create mode 100644 STM32F1/libraries/WS2812B/src/WS2812B.cpp create mode 100644 STM32F1/libraries/WS2812B/src/WS2812B.h diff --git a/STM32F1/libraries/WS2812B/README.md b/STM32F1/libraries/WS2812B/README.md new file mode 100644 index 0000000..3f10144 --- /dev/null +++ b/STM32F1/libraries/WS2812B/README.md @@ -0,0 +1,78 @@ +# WS2812B_STM32_Libmaple +WS2812B (Neopixel) library for Arduino STM32 (Libmaple core) + +Written by Roger Clark www.rogerclark.net, from first principals + +This library uses SPI DMA to control a strip of WS2812B (NeoPixel) LEDS + +It should be generally compatible with the Adafruit NeoPixel library, +except I have not had chance to implement one or two of the lesser used functions + +Connect Data In of the strip to SPI1 MOSI + +This library has only been tested on the WS2812B LED. It may not work with the older WS2812 or +other types of addressable RGB LED, becuase it relies on a division multiple of the 72Mhz clock +frequence on the STM32 SPI to generate the correct width T0H pulse, of 400ns +/- 150nS +SPI DIV32 gives a pulse width of 444nS which is well within spec for the WS2812B but +is probably too long for the WS2812 which needs a 350ns pulse for T0H + +##Technical details + +The library uses SPI to send the mark/space encoded data to the LED's + +Each mark/space squarewave is generated by 3 bits of data +A pixel 0 value is achieved by sending the bit pattern 100 +A pixel 1 value is achieved by sending the bit pattern 110 + +Where the duration of each bit is 444nS +Hence 100 generates a mark space value of 444/888nS +and 110 generates a mark space value of 888/444nS + +This method results in the smallest storage requirement and the fastest send times, +however because the 8 bit pixel channel data is encoded in 24 bits, (3 bytes) the values required in each of the 3 bytes to represent +a specific value is not easy to generate. + +The bit pattern in the 3 bytes is +88877766 65554443 33222111 + +For speed of operation the values reqired for each byte for each of the 256 possible values is held in 3 separate 256 byte LUTS +which were pre-computed by this function (which generates the full 24 bit pattern for a given input value (0-255) + +``` +uint32_t convert(uint8_t data) +{ + uint32_t out=0; + for(uint8_t mask = 0x80; mask; mask >>= 1) + { + out=out<<3; + if (data & mask) + { + out = out | 0B110;//Bit high + } + else + { + out = out | 0B100;// bit low + } + } + return out; +} +``` + +The STM32F103 has plenty of flash space (either 64 or 128k), so I used 256 byte LUTs even though the number of unique values in each LUT is +only 8,4 and 8 bytes respectively. +However to use small LUTS requires shifting and masking of the input data, and the code was written with a preference for speed over binary size + +The encoded pixel buffer is 2 bytes longer than the actual encoded data. +The first and last encoded bytes are all zeros. This is because the SPI hardware seems to preload MOSI with its output value before the start +of the DMA transfer, which causes the first encoded pulse to be around 50ns longer than the subsequent bits, (around 490 or 500ns) +This had the effect of causing the first LED to always think the MS bit of the green channel was set to High. + +So having the first encoded byte of zeros, is a work-around , as although the first encoded bit is still 490nS wide its a logic zero and is therefore +not visible, becuase the default state is of the SPI when not transmitting data is logic zero +The last byte was also set to all zeros, as occasionally MOSI seemed to be left set to logic high on completion of the SPI DMA send + +Adding these 2 bytes does slightly slow down the transfer, as it add 444ns * 8 = just over 3.5uS to both end. +But the WS2812B theoretically requires a reset time of more than 50uS between transmissions, so 3.5uS can be part of that time. +In reality the WS2812B seems to only need around 6uS of reset time, so for all practical purposes, there no delays are needed at all in the +library to enforce the reset time, as the overead of the function call and the SPI DMA setup plus the 3.5uS gives the enough reset time. + diff --git a/STM32F1/libraries/WS2812B/examples/WS2812B_test/WS2812B_test.ino b/STM32F1/libraries/WS2812B/examples/WS2812B_test/WS2812B_test.ino new file mode 100644 index 0000000..bf4934f --- /dev/null +++ b/STM32F1/libraries/WS2812B/examples/WS2812B_test/WS2812B_test.ino @@ -0,0 +1,303 @@ +#include + +#define NUM_LEDS 30 +/* + * Note. Library uses SPI1 + * Connect the WS2812B data input to MOSI on your board. + * + */ +WS2812B strip = WS2812B(NUM_LEDS); +// Note. Gamma is not really supported in the library, its only included as some functions used in this example require Gamma +uint8_t LEDGamma[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, + 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, + 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, + 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16, + 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25, + 25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36, + 37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50, + 51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68, + 69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89, + 90, 92, 93, 95, 96, 98, 99,101,102,104,105,107,109,110,112,114, + 115,117,119,120,122,124,126,127,129,131,133,135,137,138,140,142, + 144,146,148,150,152,154,156,158,160,162,164,167,169,171,173,175, + 177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213, +215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 }; + +void setup() +{ + strip.begin();// Sets up the SPI + strip.show();// Clears the strip, as by default the strip data is set to all LED's off. + // strip.setBrightness(8); +} + +void loop() +{ + colorWipe(strip.Color(0, 255, 0), 20); // Green + colorWipe(strip.Color(255, 0, 0), 20); // Red + colorWipe(strip.Color(0, 0, 255), 20); // Blue + rainbow(10); + rainbowCycle(10); + theaterChase(strip.Color(255, 0, 0), 20); // Red + theaterChase(strip.Color(0, 255, 0), 20); // Green + theaterChase(strip.Color(0, 0, 255), 20); // Blue + theaterChaseRainbow(10); + whiteOverRainbow(20,75,5); + pulseWhite(5); + delay(250); + fullWhite(); + delay(250); + rainbowFade2White(3,3,1); +} + +// Fill the dots one after the other with a color +void colorWipe(uint32_t c, uint8_t wait) +{ + for(uint16_t i=0; i= 0 ; j--){ + for(uint16_t i=0; i 255 - fadeMax ){ + fadeVal--; + } + + strip.show(); + delay(wait); + } + + } + + + + delay(500); + + + for(int k = 0 ; k < whiteLoops ; k ++){ + + for(int j = 0; j < 256 ; j++){ + + for(uint16_t i=0; i < strip.numPixels(); i++) { + strip.setPixelColor(i, strip.Color(0,0,0, LEDGamma[j] ) ); + } + strip.show(); + } + + delay(2000); + for(int j = 255; j >= 0 ; j--){ + + for(uint16_t i=0; i < strip.numPixels(); i++) { + strip.setPixelColor(i, strip.Color(0,0,0, LEDGamma[j] ) ); + } + strip.show(); + } + } + + delay(500); + + +} + +void whiteOverRainbow(uint8_t wait, uint8_t whiteSpeed, uint8_t whiteLength ) { + + if(whiteLength >= strip.numPixels()) whiteLength = strip.numPixels() - 1; + + int head = whiteLength - 1; + int tail = 0; + + int loops = 3; + int loopNum = 0; + + static unsigned long lastTime = 0; + + + while(true){ + for(int j=0; j<256; j++) { + for(uint16_t i=0; i= tail && i <= head) || (tail > head && i >= tail) || (tail > head && i <= head) ){ + strip.setPixelColor(i, strip.Color(0,0,0, 255 ) ); + } + else{ + strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255)); + } + + } + + if(millis() - lastTime > whiteSpeed) { + head++; + tail++; + if(head == strip.numPixels()){ + loopNum++; + } + lastTime = millis(); + } + + if(loopNum == loops) return; + + head%=strip.numPixels(); + tail%=strip.numPixels(); + strip.show(); + delay(wait); + } + } + +} +void fullWhite() { + + for(uint16_t i=0; i> 16); +} +uint8_t green(uint32_t c) { + return (c >> 8); +} +uint8_t blue(uint32_t c) { + return (c); +} diff --git a/STM32F1/libraries/WS2812B/keywords.txt b/STM32F1/libraries/WS2812B/keywords.txt new file mode 100644 index 0000000..2d8b83a --- /dev/null +++ b/STM32F1/libraries/WS2812B/keywords.txt @@ -0,0 +1,27 @@ +####################################### +# Syntax Coloring Map For WS2812B +# Class +####################################### + +WS2812B KEYWORD1 + +####################################### +# Methods and Functions +####################################### + +setPixelColor KEYWORD2 +numPixels KEYWORD2 +Color KEYWORD2 +show KEYWORD2 + +clear KEYWORD2 +updateLength KEYWORD2 + +canShow KEYWORD2 + + +####################################### +# Constants +####################################### + + diff --git a/STM32F1/libraries/WS2812B/library.properties b/STM32F1/libraries/WS2812B/library.properties new file mode 100644 index 0000000..936976d --- /dev/null +++ b/STM32F1/libraries/WS2812B/library.properties @@ -0,0 +1,10 @@ +name=WS2812B +version=1.0 +author=Roger Clark, based on the Adafruit Neopixel library API +email= +sentence=WS2812B (Neopixel) library +paragraph=WS2812B (Neopixel) library for STM32F1 LibMaple +url= +architectures=STM32F1 +maintainer=Roger Clark +category=Uncategorized \ No newline at end of file diff --git a/STM32F1/libraries/WS2812B/src/WS2812B.cpp b/STM32F1/libraries/WS2812B/src/WS2812B.cpp new file mode 100644 index 0000000..36483fc --- /dev/null +++ b/STM32F1/libraries/WS2812B/src/WS2812B.cpp @@ -0,0 +1,238 @@ +/*----------------------------------------------------------------------------------------------- + Arduino library to control WS2812B RGB Led strips using the Arduino STM32 LibMaple core + ----------------------------------------------------------------------------------------------- + + Note. + This library has only been tested on the WS2812B LED. It may not work with the older WS2812 or + other types of addressable RGB LED, becuase it relies on a division multiple of the 72Mhz clock + frequence on the STM32 SPI to generate the correct width T0H pulse, of 400ns +/- 150nS + SPI DIV32 gives a pulse width of 444nS which is well within spec for the WS2812B but + is probably too long for the WS2812 which needs a 350ns pulse for T0H + + This WS2811B library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + It is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + See . + -----------------------------------------------------------------------------------------------*/ + +#include "WS2812B.h" +#include "pins_arduino.h" +#include "wiring_private.h" +#include + + +// Constructor when n is the number of LEDs in the strip +WS2812B::WS2812B(uint16_t number_of_leds) : + brightness(0), pixels(NULL) +{ + updateLength(number_of_leds); +} + + +WS2812B::~WS2812B() +{ + if(pixels) + { + free(pixels); + } + SPI.end(); +} + +void WS2812B::begin(void) { + +if (!begun) +{ + SPI.setClockDivider(SPI_CLOCK_DIV32);// need bit rate of 400nS but closest we can do @ 72Mhz is 444ns (which is within spec) + SPI.begin(); + begun = true; +} +} + +void WS2812B::updateLength(uint16_t n) +{ + if(doubleBuffer) + { + free(doubleBuffer); + } + + numBytes = (n<<3) + n + 2; // 9 encoded bytes per pixel. 1 byte empty peamble to fix issue with SPI MOSI and on byte at the end to clear down MOSI + // Note. (n<<3) +n is a fast way of doing n*9 + if((doubleBuffer = (uint8_t *)malloc(numBytes*2))) + { + numLEDs = n; + pixels = doubleBuffer; + // Only need to init the part of the double buffer which will be interacted with by the API e.g. setPixelColor + *pixels=0;//clear the preamble byte + *(pixels+numBytes-1)=0;// clear the post send cleardown byte. + clear();// Set the encoded data to all encoded zeros + } + else + { + numLEDs = numBytes = 0; + } +} + +// Sends the current buffer to the leds +void WS2812B::show(void) +{ + SPI.dmaSendAsync(pixels,numBytes);// Start the DMA transfer of the current pixel buffer to the LEDs and return immediately. + + // Need to copy the last / current buffer to the other half of the double buffer as most API code does not rebuild the entire contents + // from scratch. Often just a few pixels are changed e.g in a chaser effect + + if (pixels==doubleBuffer) + { + // pixels was using the first buffer + pixels = doubleBuffer+numBytes; // set pixels to second buffer + memcpy(pixels,doubleBuffer,numBytes);// copy first buffer to second buffer + } + else + { + // pixels was using the second buffer + pixels = doubleBuffer; // set pixels to first buffer + memcpy(pixels,doubleBuffer+numBytes,numBytes); // copy second buffer to first buffer + } +} + +/*Sets a specific pixel to a specific r,g,b colour +* Because the pixels buffer contains the encoded bitstream, which is in triplets +* the lookup table need to be used to find the correct pattern for each byte in the 3 byte sequence. +*/ +void WS2812B::setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b) + { + uint8_t *bptr = pixels + (n<<3) + n +1; + uint8_t *tPtr = (uint8_t *)encoderLookup + g*2 + g;// need to index 3 x g into the lookup + + *bptr++ = *tPtr++; + *bptr++ = *tPtr++; + *bptr++ = *tPtr++; + + tPtr = (uint8_t *)encoderLookup + r*2 + r; + *bptr++ = *tPtr++; + *bptr++ = *tPtr++; + *bptr++ = *tPtr++; + + tPtr = (uint8_t *)encoderLookup + b*2 + b; + *bptr++ = *tPtr++; + *bptr++ = *tPtr++; + *bptr++ = *tPtr++; + } + +void WS2812B::setPixelColor(uint16_t n, uint32_t c) + { + uint8_t r,g,b; + + if(brightness) + { + r = ((int)((uint8_t)(c >> 16)) * (int)brightness) >> 8; + g = ((int)((uint8_t)(c >> 8)) * (int)brightness) >> 8; + b = ((int)((uint8_t)c) * (int)brightness) >> 8; + } + else + { + r = (uint8_t)(c >> 16), + g = (uint8_t)(c >> 8), + b = (uint8_t)c; + } + + uint8_t *bptr = pixels + (n<<3) + n +1; + uint8_t *tPtr = (uint8_t *)encoderLookup + g*2 + g;// need to index 3 x g into the lookup + + *bptr++ = *tPtr++; + *bptr++ = *tPtr++; + *bptr++ = *tPtr++; + + tPtr = (uint8_t *)encoderLookup + r*2 + r; + *bptr++ = *tPtr++; + *bptr++ = *tPtr++; + *bptr++ = *tPtr++; + + tPtr = (uint8_t *)encoderLookup + b*2 + b; + *bptr++ = *tPtr++; + *bptr++ = *tPtr++; + *bptr++ = *tPtr++; +} + +// Convert separate R,G,B into packed 32-bit RGB color. +// Packed format is always RGB, regardless of LED strand color order. +uint32_t WS2812B::Color(uint8_t r, uint8_t g, uint8_t b) { + return ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; +} + +// Convert separate R,G,B,W into packed 32-bit WRGB color. +// Packed format is always WRGB, regardless of LED strand color order. +uint32_t WS2812B::Color(uint8_t r, uint8_t g, uint8_t b, uint8_t w) { + return ((uint32_t)w << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; +} + + +uint16_t WS2812B::numPixels(void) const { + return numLEDs; +} + +// Adjust output brightness; 0=darkest (off), 255=brightest. This does +// NOT immediately affect what's currently displayed on the LEDs. The +// next call to show() will refresh the LEDs at this level. However, +// this process is potentially "lossy," especially when increasing +// brightness. The tight timing in the WS2811/WS2812 code means there +// aren't enough free cycles to perform this scaling on the fly as data +// is issued. So we make a pass through the existing color data in RAM +// and scale it (subsequent graphics commands also work at this +// brightness level). If there's a significant step up in brightness, +// the limited number of steps (quantization) in the old data will be +// quite visible in the re-scaled version. For a non-destructive +// change, you'll need to re-render the full strip data. C'est la vie. +void WS2812B::setBrightness(uint8_t b) { + // Stored brightness value is different than what's passed. + // This simplifies the actual scaling math later, allowing a fast + // 8x8-bit multiply and taking the MSB. 'brightness' is a uint8_t, + // adding 1 here may (intentionally) roll over...so 0 = max brightness + // (color values are interpreted literally; no scaling), 1 = min + // brightness (off), 255 = just below max brightness. + uint8_t newBrightness = b + 1; + if(newBrightness != brightness) { // Compare against prior value + // Brightness has changed -- re-scale existing data in RAM + uint8_t c, + *ptr = pixels, + oldBrightness = brightness - 1; // De-wrap old brightness value + uint16_t scale; + if(oldBrightness == 0) scale = 0; // Avoid /0 + else if(b == 255) scale = 65535 / oldBrightness; + else scale = (((uint16_t)newBrightness << 8) - 1) / oldBrightness; + for(uint16_t i=0; i> 8; + } + brightness = newBrightness; + } +} + +//Return the brightness value +uint8_t WS2812B::getBrightness(void) const { + return brightness - 1; +} + +/* +* Sets the encoded pixel data to turn all the LEDs off. +*/ +void WS2812B::clear() +{ + uint8_t * bptr= pixels+1;// Note first byte in the buffer is a preable and is always zero. hence the +1 + uint8_t *tPtr; + + for(int i=0;i< (numLEDs *3);i++) + { + tPtr = (uint8_t *)encoderLookup; + *bptr++ = *tPtr++; + *bptr++ = *tPtr++; + *bptr++ = *tPtr++; + } +} diff --git a/STM32F1/libraries/WS2812B/src/WS2812B.h b/STM32F1/libraries/WS2812B/src/WS2812B.h new file mode 100644 index 0000000..30bc875 --- /dev/null +++ b/STM32F1/libraries/WS2812B/src/WS2812B.h @@ -0,0 +1,81 @@ +/*-------------------------------------------------------------------- + The WS2812B library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + It is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + See . + --------------------------------------------------------------------*/ + +#ifndef WS2812B_H +#define WS2812B_H + +#include +/* + * old version used 3 separate tables, one per byte of the 24 bit encoded data + * +static const uint8_t byte0Lookup[256]={0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB}; +static const uint8_t byte1Lookup[256]={0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D}; +static const uint8_t byte2Lookup[256]={0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6}; +*/ + +// New version uses one large LUT as its faster index into sequential bytes for the GRB pattern +static const uint8_t encoderLookup[256*3]={ 0x92,0x49,0x24,0x92,0x49,0x26,0x92,0x49,0x34,0x92,0x49,0x36,0x92,0x49,0xA4,0x92,0x49,0xA6,0x92,0x49,0xB4,0x92,0x49,0xB6,0x92,0x4D,0x24,0x92,0x4D,0x26,0x92,0x4D,0x34,0x92,0x4D,0x36,0x92,0x4D,0xA4,0x92,0x4D,0xA6,0x92,0x4D,0xB4,0x92,0x4D,0xB6,0x92,0x69,0x24,0x92,0x69,0x26,0x92,0x69,0x34,0x92,0x69,0x36,0x92,0x69,0xA4,0x92,0x69,0xA6,0x92,0x69,0xB4,0x92,0x69,0xB6,0x92,0x6D,0x24,0x92,0x6D,0x26,0x92,0x6D,0x34,0x92,0x6D,0x36,0x92,0x6D,0xA4,0x92,0x6D,0xA6,0x92,0x6D,0xB4,0x92,0x6D,0xB6,0x93,0x49,0x24,0x93,0x49,0x26,0x93,0x49,0x34,0x93,0x49,0x36,0x93,0x49,0xA4,0x93,0x49,0xA6,0x93,0x49,0xB4,0x93,0x49,0xB6,0x93,0x4D,0x24,0x93,0x4D,0x26,0x93,0x4D,0x34,0x93,0x4D,0x36,0x93,0x4D,0xA4,0x93,0x4D,0xA6,0x93,0x4D,0xB4,0x93,0x4D,0xB6,0x93,0x69,0x24,0x93,0x69,0x26,0x93,0x69,0x34,0x93,0x69,0x36,0x93,0x69,0xA4,0x93,0x69,0xA6,0x93,0x69,0xB4,0x93,0x69,0xB6,0x93,0x6D,0x24,0x93,0x6D,0x26,0x93,0x6D,0x34,0x93,0x6D,0x36,0x93,0x6D,0xA4,0x93,0x6D,0xA6,0x93,0x6D,0xB4,0x93,0x6D,0xB6,0x9A,0x49,0x24,0x9A,0x49,0x26,0x9A,0x49,0x34,0x9A,0x49,0x36,0x9A,0x49,0xA4,0x9A,0x49,0xA6,0x9A,0x49,0xB4,0x9A,0x49,0xB6,0x9A,0x4D,0x24,0x9A,0x4D,0x26,0x9A,0x4D,0x34,0x9A,0x4D,0x36,0x9A,0x4D,0xA4,0x9A,0x4D,0xA6,0x9A,0x4D,0xB4,0x9A,0x4D,0xB6,0x9A,0x69,0x24,0x9A,0x69,0x26,0x9A,0x69,0x34,0x9A,0x69,0x36,0x9A,0x69,0xA4,0x9A,0x69,\ + 0xA6,0x9A,0x69,0xB4,0x9A,0x69,0xB6,0x9A,0x6D,0x24,0x9A,0x6D,0x26,0x9A,0x6D,0x34,0x9A,0x6D,0x36,0x9A,0x6D,0xA4,0x9A,0x6D,0xA6,0x9A,0x6D,0xB4,0x9A,0x6D,0xB6,0x9B,0x49,0x24,0x9B,0x49,0x26,0x9B,0x49,0x34,0x9B,0x49,0x36,0x9B,0x49,0xA4,0x9B,0x49,0xA6,0x9B,0x49,0xB4,0x9B,0x49,0xB6,0x9B,0x4D,0x24,0x9B,0x4D,0x26,0x9B,0x4D,0x34,0x9B,0x4D,0x36,0x9B,0x4D,0xA4,0x9B,0x4D,0xA6,0x9B,0x4D,0xB4,0x9B,0x4D,0xB6,0x9B,0x69,0x24,0x9B,0x69,0x26,0x9B,0x69,0x34,0x9B,0x69,0x36,0x9B,0x69,0xA4,0x9B,0x69,0xA6,0x9B,0x69,0xB4,0x9B,0x69,0xB6,0x9B,0x6D,0x24,0x9B,0x6D,0x26,0x9B,0x6D,0x34,0x9B,0x6D,0x36,0x9B,0x6D,0xA4,0x9B,0x6D,0xA6,0x9B,0x6D,0xB4,0x9B,0x6D,0xB6,0xD2,0x49,0x24,0xD2,0x49,0x26,0xD2,0x49,0x34,0xD2,0x49,0x36,0xD2,0x49,0xA4,0xD2,0x49,0xA6,0xD2,0x49,0xB4,0xD2,0x49,0xB6,0xD2,0x4D,0x24,0xD2,0x4D,0x26,0xD2,0x4D,0x34,0xD2,0x4D,0x36,0xD2,0x4D,0xA4,0xD2,0x4D,0xA6,0xD2,0x4D,0xB4,0xD2,0x4D,0xB6,0xD2,0x69,0x24,0xD2,0x69,0x26,0xD2,0x69,0x34,0xD2,0x69,0x36,0xD2,0x69,0xA4,0xD2,0x69,0xA6,0xD2,0x69,0xB4,0xD2,0x69,0xB6,0xD2,0x6D,0x24,0xD2,0x6D,0x26,0xD2,0x6D,0x34,0xD2,0x6D,0x36,0xD2,0x6D,0xA4,0xD2,0x6D,0xA6,0xD2,0x6D,0xB4,0xD2,0x6D,0xB6,0xD3,0x49,0x24,0xD3,0x49,0x26,0xD3,0x49,0x34,0xD3,0x49,0x36,0xD3,0x49,0xA4,0xD3,0x49,0xA6,0xD3,0x49,0xB4,0xD3,0x49,0xB6,0xD3,0x4D,0x24,0xD3,0x4D,0x26,0xD3,0x4D,0x34,0xD3,\ + 0x4D,0x36,0xD3,0x4D,0xA4,0xD3,0x4D,0xA6,0xD3,0x4D,0xB4,0xD3,0x4D,0xB6,0xD3,0x69,0x24,0xD3,0x69,0x26,0xD3,0x69,0x34,0xD3,0x69,0x36,0xD3,0x69,0xA4,0xD3,0x69,0xA6,0xD3,0x69,0xB4,0xD3,0x69,0xB6,0xD3,0x6D,0x24,0xD3,0x6D,0x26,0xD3,0x6D,0x34,0xD3,0x6D,0x36,0xD3,0x6D,0xA4,0xD3,0x6D,0xA6,0xD3,0x6D,0xB4,0xD3,0x6D,0xB6,0xDA,0x49,0x24,0xDA,0x49,0x26,0xDA,0x49,0x34,0xDA,0x49,0x36,0xDA,0x49,0xA4,0xDA,0x49,0xA6,0xDA,0x49,0xB4,0xDA,0x49,0xB6,0xDA,0x4D,0x24,0xDA,0x4D,0x26,0xDA,0x4D,0x34,0xDA,0x4D,0x36,0xDA,0x4D,0xA4,0xDA,0x4D,0xA6,0xDA,0x4D,0xB4,0xDA,0x4D,0xB6,0xDA,0x69,0x24,0xDA,0x69,0x26,0xDA,0x69,0x34,0xDA,0x69,0x36,0xDA,0x69,0xA4,0xDA,0x69,0xA6,0xDA,0x69,0xB4,0xDA,0x69,0xB6,0xDA,0x6D,0x24,0xDA,0x6D,0x26,0xDA,0x6D,0x34,0xDA,0x6D,0x36,0xDA,0x6D,0xA4,0xDA,0x6D,0xA6,0xDA,0x6D,0xB4,0xDA,0x6D,0xB6,0xDB,0x49,0x24,0xDB,0x49,0x26,0xDB,0x49,0x34,0xDB,0x49,0x36,0xDB,0x49,0xA4,0xDB,0x49,0xA6,0xDB,0x49,0xB4,0xDB,0x49,0xB6,0xDB,0x4D,0x24,0xDB,0x4D,0x26,0xDB,0x4D,0x34,0xDB,0x4D,0x36,0xDB,0x4D,0xA4,0xDB,0x4D,0xA6,0xDB,0x4D,0xB4,0xDB,0x4D,0xB6,0xDB,0x69,0x24,0xDB,0x69,0x26,0xDB,0x69,0x34,0xDB,0x69,0x36,0xDB,0x69,0xA4,0xDB,0x69,0xA6,0xDB,0x69,0xB4,0xDB,0x69,0xB6,0xDB,0x6D,0x24,0xDB,0x6D,0x26,0xDB,0x6D,0x34,0xDB,0x6D,0x36,0xDB,0x6D,0xA4,0xDB,0x6D,0xA6,0xDB,0x6D,0xB4,0xDB,0x6D,0xB6}; + +class WS2812B { + public: + + // Constructor: number of LEDs + WS2812B (uint16_t number_of_leds);// Constuctor + ~WS2812B(); + void + begin(void), + show(void), + setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b), + // setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w), + setPixelColor(uint16_t n, uint32_t c), + setBrightness(uint8_t), + clear(), + updateLength(uint16_t n); + uint8_t +// *getPixels(void) const, + getBrightness(void) const; + uint16_t + numPixels(void) const; + static uint32_t + Color(uint8_t r, uint8_t g, uint8_t b), + Color(uint8_t r, uint8_t g, uint8_t b, uint8_t w); + // uint32_t + // getPixelColor(uint16_t n) const; + inline bool + canShow(void) { return (micros() - endTime) >= 300L; } + + private: + + boolean + begun; // true if begin() previously called + uint16_t + numLEDs, // Number of RGB LEDs in strip + numBytes; // Size of 'pixels' buffer + + uint8_t + brightness, + *pixels, // Holds the current LED color values, which the external API calls interact with 9 bytes per pixel + start + end empty bytes + *doubleBuffer, // Holds the start of the double buffer (1 buffer for async DMA transfer and one for the API interaction. + rOffset, // Index of red byte within each 3- or 4-byte pixel + gOffset, // Index of green byte + bOffset, // Index of blue byte + wOffset; // Index of white byte (same as rOffset if no white) + uint32_t + endTime; // Latch timing reference +}; + + +#endif // WS2812B_H From aef93f74cde8f1127eb9b4c571d9f8fe910854b8 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Tue, 13 Jun 2017 10:39:42 +1000 Subject: [PATCH 086/351] Moved encoderLookup LUT from flash to RAM to give 30% speed increase of setPixelColor() - at the expense of 768 bytes of RAM --- STM32F1/libraries/WS2812B/src/WS2812B.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/libraries/WS2812B/src/WS2812B.h b/STM32F1/libraries/WS2812B/src/WS2812B.h index 30bc875..3a6bcb6 100644 --- a/STM32F1/libraries/WS2812B/src/WS2812B.h +++ b/STM32F1/libraries/WS2812B/src/WS2812B.h @@ -25,7 +25,7 @@ static const uint8_t byte2Lookup[256]={0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0 */ // New version uses one large LUT as its faster index into sequential bytes for the GRB pattern -static const uint8_t encoderLookup[256*3]={ 0x92,0x49,0x24,0x92,0x49,0x26,0x92,0x49,0x34,0x92,0x49,0x36,0x92,0x49,0xA4,0x92,0x49,0xA6,0x92,0x49,0xB4,0x92,0x49,0xB6,0x92,0x4D,0x24,0x92,0x4D,0x26,0x92,0x4D,0x34,0x92,0x4D,0x36,0x92,0x4D,0xA4,0x92,0x4D,0xA6,0x92,0x4D,0xB4,0x92,0x4D,0xB6,0x92,0x69,0x24,0x92,0x69,0x26,0x92,0x69,0x34,0x92,0x69,0x36,0x92,0x69,0xA4,0x92,0x69,0xA6,0x92,0x69,0xB4,0x92,0x69,0xB6,0x92,0x6D,0x24,0x92,0x6D,0x26,0x92,0x6D,0x34,0x92,0x6D,0x36,0x92,0x6D,0xA4,0x92,0x6D,0xA6,0x92,0x6D,0xB4,0x92,0x6D,0xB6,0x93,0x49,0x24,0x93,0x49,0x26,0x93,0x49,0x34,0x93,0x49,0x36,0x93,0x49,0xA4,0x93,0x49,0xA6,0x93,0x49,0xB4,0x93,0x49,0xB6,0x93,0x4D,0x24,0x93,0x4D,0x26,0x93,0x4D,0x34,0x93,0x4D,0x36,0x93,0x4D,0xA4,0x93,0x4D,0xA6,0x93,0x4D,0xB4,0x93,0x4D,0xB6,0x93,0x69,0x24,0x93,0x69,0x26,0x93,0x69,0x34,0x93,0x69,0x36,0x93,0x69,0xA4,0x93,0x69,0xA6,0x93,0x69,0xB4,0x93,0x69,0xB6,0x93,0x6D,0x24,0x93,0x6D,0x26,0x93,0x6D,0x34,0x93,0x6D,0x36,0x93,0x6D,0xA4,0x93,0x6D,0xA6,0x93,0x6D,0xB4,0x93,0x6D,0xB6,0x9A,0x49,0x24,0x9A,0x49,0x26,0x9A,0x49,0x34,0x9A,0x49,0x36,0x9A,0x49,0xA4,0x9A,0x49,0xA6,0x9A,0x49,0xB4,0x9A,0x49,0xB6,0x9A,0x4D,0x24,0x9A,0x4D,0x26,0x9A,0x4D,0x34,0x9A,0x4D,0x36,0x9A,0x4D,0xA4,0x9A,0x4D,0xA6,0x9A,0x4D,0xB4,0x9A,0x4D,0xB6,0x9A,0x69,0x24,0x9A,0x69,0x26,0x9A,0x69,0x34,0x9A,0x69,0x36,0x9A,0x69,0xA4,0x9A,0x69,\ +static uint8_t encoderLookup[256*3]={ 0x92,0x49,0x24,0x92,0x49,0x26,0x92,0x49,0x34,0x92,0x49,0x36,0x92,0x49,0xA4,0x92,0x49,0xA6,0x92,0x49,0xB4,0x92,0x49,0xB6,0x92,0x4D,0x24,0x92,0x4D,0x26,0x92,0x4D,0x34,0x92,0x4D,0x36,0x92,0x4D,0xA4,0x92,0x4D,0xA6,0x92,0x4D,0xB4,0x92,0x4D,0xB6,0x92,0x69,0x24,0x92,0x69,0x26,0x92,0x69,0x34,0x92,0x69,0x36,0x92,0x69,0xA4,0x92,0x69,0xA6,0x92,0x69,0xB4,0x92,0x69,0xB6,0x92,0x6D,0x24,0x92,0x6D,0x26,0x92,0x6D,0x34,0x92,0x6D,0x36,0x92,0x6D,0xA4,0x92,0x6D,0xA6,0x92,0x6D,0xB4,0x92,0x6D,0xB6,0x93,0x49,0x24,0x93,0x49,0x26,0x93,0x49,0x34,0x93,0x49,0x36,0x93,0x49,0xA4,0x93,0x49,0xA6,0x93,0x49,0xB4,0x93,0x49,0xB6,0x93,0x4D,0x24,0x93,0x4D,0x26,0x93,0x4D,0x34,0x93,0x4D,0x36,0x93,0x4D,0xA4,0x93,0x4D,0xA6,0x93,0x4D,0xB4,0x93,0x4D,0xB6,0x93,0x69,0x24,0x93,0x69,0x26,0x93,0x69,0x34,0x93,0x69,0x36,0x93,0x69,0xA4,0x93,0x69,0xA6,0x93,0x69,0xB4,0x93,0x69,0xB6,0x93,0x6D,0x24,0x93,0x6D,0x26,0x93,0x6D,0x34,0x93,0x6D,0x36,0x93,0x6D,0xA4,0x93,0x6D,0xA6,0x93,0x6D,0xB4,0x93,0x6D,0xB6,0x9A,0x49,0x24,0x9A,0x49,0x26,0x9A,0x49,0x34,0x9A,0x49,0x36,0x9A,0x49,0xA4,0x9A,0x49,0xA6,0x9A,0x49,0xB4,0x9A,0x49,0xB6,0x9A,0x4D,0x24,0x9A,0x4D,0x26,0x9A,0x4D,0x34,0x9A,0x4D,0x36,0x9A,0x4D,0xA4,0x9A,0x4D,0xA6,0x9A,0x4D,0xB4,0x9A,0x4D,0xB6,0x9A,0x69,0x24,0x9A,0x69,0x26,0x9A,0x69,0x34,0x9A,0x69,0x36,0x9A,0x69,0xA4,0x9A,0x69,\ 0xA6,0x9A,0x69,0xB4,0x9A,0x69,0xB6,0x9A,0x6D,0x24,0x9A,0x6D,0x26,0x9A,0x6D,0x34,0x9A,0x6D,0x36,0x9A,0x6D,0xA4,0x9A,0x6D,0xA6,0x9A,0x6D,0xB4,0x9A,0x6D,0xB6,0x9B,0x49,0x24,0x9B,0x49,0x26,0x9B,0x49,0x34,0x9B,0x49,0x36,0x9B,0x49,0xA4,0x9B,0x49,0xA6,0x9B,0x49,0xB4,0x9B,0x49,0xB6,0x9B,0x4D,0x24,0x9B,0x4D,0x26,0x9B,0x4D,0x34,0x9B,0x4D,0x36,0x9B,0x4D,0xA4,0x9B,0x4D,0xA6,0x9B,0x4D,0xB4,0x9B,0x4D,0xB6,0x9B,0x69,0x24,0x9B,0x69,0x26,0x9B,0x69,0x34,0x9B,0x69,0x36,0x9B,0x69,0xA4,0x9B,0x69,0xA6,0x9B,0x69,0xB4,0x9B,0x69,0xB6,0x9B,0x6D,0x24,0x9B,0x6D,0x26,0x9B,0x6D,0x34,0x9B,0x6D,0x36,0x9B,0x6D,0xA4,0x9B,0x6D,0xA6,0x9B,0x6D,0xB4,0x9B,0x6D,0xB6,0xD2,0x49,0x24,0xD2,0x49,0x26,0xD2,0x49,0x34,0xD2,0x49,0x36,0xD2,0x49,0xA4,0xD2,0x49,0xA6,0xD2,0x49,0xB4,0xD2,0x49,0xB6,0xD2,0x4D,0x24,0xD2,0x4D,0x26,0xD2,0x4D,0x34,0xD2,0x4D,0x36,0xD2,0x4D,0xA4,0xD2,0x4D,0xA6,0xD2,0x4D,0xB4,0xD2,0x4D,0xB6,0xD2,0x69,0x24,0xD2,0x69,0x26,0xD2,0x69,0x34,0xD2,0x69,0x36,0xD2,0x69,0xA4,0xD2,0x69,0xA6,0xD2,0x69,0xB4,0xD2,0x69,0xB6,0xD2,0x6D,0x24,0xD2,0x6D,0x26,0xD2,0x6D,0x34,0xD2,0x6D,0x36,0xD2,0x6D,0xA4,0xD2,0x6D,0xA6,0xD2,0x6D,0xB4,0xD2,0x6D,0xB6,0xD3,0x49,0x24,0xD3,0x49,0x26,0xD3,0x49,0x34,0xD3,0x49,0x36,0xD3,0x49,0xA4,0xD3,0x49,0xA6,0xD3,0x49,0xB4,0xD3,0x49,0xB6,0xD3,0x4D,0x24,0xD3,0x4D,0x26,0xD3,0x4D,0x34,0xD3,\ 0x4D,0x36,0xD3,0x4D,0xA4,0xD3,0x4D,0xA6,0xD3,0x4D,0xB4,0xD3,0x4D,0xB6,0xD3,0x69,0x24,0xD3,0x69,0x26,0xD3,0x69,0x34,0xD3,0x69,0x36,0xD3,0x69,0xA4,0xD3,0x69,0xA6,0xD3,0x69,0xB4,0xD3,0x69,0xB6,0xD3,0x6D,0x24,0xD3,0x6D,0x26,0xD3,0x6D,0x34,0xD3,0x6D,0x36,0xD3,0x6D,0xA4,0xD3,0x6D,0xA6,0xD3,0x6D,0xB4,0xD3,0x6D,0xB6,0xDA,0x49,0x24,0xDA,0x49,0x26,0xDA,0x49,0x34,0xDA,0x49,0x36,0xDA,0x49,0xA4,0xDA,0x49,0xA6,0xDA,0x49,0xB4,0xDA,0x49,0xB6,0xDA,0x4D,0x24,0xDA,0x4D,0x26,0xDA,0x4D,0x34,0xDA,0x4D,0x36,0xDA,0x4D,0xA4,0xDA,0x4D,0xA6,0xDA,0x4D,0xB4,0xDA,0x4D,0xB6,0xDA,0x69,0x24,0xDA,0x69,0x26,0xDA,0x69,0x34,0xDA,0x69,0x36,0xDA,0x69,0xA4,0xDA,0x69,0xA6,0xDA,0x69,0xB4,0xDA,0x69,0xB6,0xDA,0x6D,0x24,0xDA,0x6D,0x26,0xDA,0x6D,0x34,0xDA,0x6D,0x36,0xDA,0x6D,0xA4,0xDA,0x6D,0xA6,0xDA,0x6D,0xB4,0xDA,0x6D,0xB6,0xDB,0x49,0x24,0xDB,0x49,0x26,0xDB,0x49,0x34,0xDB,0x49,0x36,0xDB,0x49,0xA4,0xDB,0x49,0xA6,0xDB,0x49,0xB4,0xDB,0x49,0xB6,0xDB,0x4D,0x24,0xDB,0x4D,0x26,0xDB,0x4D,0x34,0xDB,0x4D,0x36,0xDB,0x4D,0xA4,0xDB,0x4D,0xA6,0xDB,0x4D,0xB4,0xDB,0x4D,0xB6,0xDB,0x69,0x24,0xDB,0x69,0x26,0xDB,0x69,0x34,0xDB,0x69,0x36,0xDB,0x69,0xA4,0xDB,0x69,0xA6,0xDB,0x69,0xB4,0xDB,0x69,0xB6,0xDB,0x6D,0x24,0xDB,0x6D,0x26,0xDB,0x6D,0x34,0xDB,0x6D,0x36,0xDB,0x6D,0xA4,0xDB,0x6D,0xA6,0xDB,0x6D,0xB4,0xDB,0x6D,0xB6}; From f58a96e0f62aaa1415a3816fa0fb2d2bc5742950 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Sun, 18 Jun 2017 17:27:02 +0200 Subject: [PATCH 087/351] implemented SDIO + small changes in DMA - reworked get and clear ISR bits + wirish_time compatible with "C" --- .gitignore | 1 + STM32F4/cores/maple/libmaple/dmaF4.c | 12 +- STM32F4/cores/maple/libmaple/dmaF4.h | 159 ++++++++++------- STM32F4/cores/maple/libmaple/sdio.c | 194 +++++++++++++++++++++ STM32F4/cores/maple/libmaple/sdio.h | 250 +++++++++++++++++++++++++++ STM32F4/cores/maple/wirish_time.h | 8 + 6 files changed, 555 insertions(+), 69 deletions(-) create mode 100644 STM32F4/cores/maple/libmaple/sdio.c create mode 100644 STM32F4/cores/maple/libmaple/sdio.h diff --git a/.gitignore b/.gitignore index 05bb0a5..b538f89 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ other/maple-bootloader/build other/maple-bootloader/*~ *.o tools/src/stm32flash_serial/src/parsers/parsers.a +*.bak diff --git a/STM32F4/cores/maple/libmaple/dmaF4.c b/STM32F4/cores/maple/libmaple/dmaF4.c index add3d8e..173f3a2 100644 --- a/STM32F4/cores/maple/libmaple/dmaF4.c +++ b/STM32F4/cores/maple/libmaple/dmaF4.c @@ -119,14 +119,14 @@ void dma_detach_interrupt(dma_dev *dev, dma_stream stream) { const uint8 dma_isr_bits_shift[] = { 0, 6, 16, 22}; -uint8 dma_get_isr_bits(dma_dev *dev, dma_stream stream) { - if ( stream&0xFC ) return ((dev->regs->HISR)>>dma_isr_bits_shift[stream&0x03]) & 0x3d; - else return ((dev->regs->LISR)>>dma_isr_bits_shift[stream&0x03]) & 0x3d; +uint8 dma_get_isr_bit(dma_dev *dev, dma_stream stream, uint8_t mask) { + if ( stream&0xFC ) return ((dev->regs->HISR)>>dma_isr_bits_shift[stream&0x03]) & mask; + else return ((dev->regs->LISR)>>dma_isr_bits_shift[stream&0x03]) & mask; } -void dma_clear_isr_bits(dma_dev *dev, dma_stream stream) { - if ( stream&0xFC ) dev->regs->HIFCR = (uint32)0x0000003d << dma_isr_bits_shift[stream&0x03]; - else dev->regs->LIFCR = (uint32)0x0000003d << dma_isr_bits_shift[stream&0x03]; +void dma_clear_isr_bit(dma_dev *dev, dma_stream stream, uint8_t mask) { + if ( stream&0xFC ) dev->regs->HIFCR = (uint32)mask << dma_isr_bits_shift[stream&0x03]; + else dev->regs->LIFCR = (uint32)mask << dma_isr_bits_shift[stream&0x03]; } /* diff --git a/STM32F4/cores/maple/libmaple/dmaF4.h b/STM32F4/cores/maple/libmaple/dmaF4.h index 757906c..cb23760 100644 --- a/STM32F4/cores/maple/libmaple/dmaF4.h +++ b/STM32F4/cores/maple/libmaple/dmaF4.h @@ -62,30 +62,30 @@ typedef struct dma_stream_t { __io uint32 PAR; /**< Stream peripheral address register */ __io uint32 M0AR; /**< Stream memory address register 0 */ __io uint32 M1AR; /**< Stream memory address register 1 */ - __io uint32 FCR; /**< Stream FIFO configuration register */ + __io uint32 FCR; /**< Stream FIFO configuration register */ } dma_stream_t; /** * @brief DMA register map type. * */ typedef struct dma_reg_map { - __io uint32 LISR; /**< Low interrupt status register */ - __io uint32 HISR; /**< High interrupt status register */ - __io uint32 LIFCR; /**< Low interrupt flag clear register */ - __io uint32 HIFCR; /**< High interrupt flag clear register */ - dma_stream_t STREAM[8]; + __io uint32 LISR; /**< Low interrupt status register */ + __io uint32 HISR; /**< High interrupt status register */ + __io uint32 LIFCR; /**< Low interrupt flag clear register */ + __io uint32 HIFCR; /**< High interrupt flag clear register */ + dma_stream_t STREAM[8]; } dma_reg_map; /** DMA controller register map base pointers */ #define DMA1_BASE ((struct dma_reg_map*)0x40026000) #define DMA2_BASE ((struct dma_reg_map*)0x40026400) + /* * Register bit definitions */ -/* Stream configuration register */ - +// Stream configuration register #define DMA_CR_CH0 (0x0 << 25) #define DMA_CR_CH1 (0x1 << 25) #define DMA_CR_CH2 (0x2 << 25) @@ -134,7 +134,34 @@ typedef struct dma_reg_map { #define DMA_CR_HTIE (0x1 << 3) #define DMA_CR_TEIE (0x1 << 2) #define DMA_CR_DMEIE (0x1 << 1) -#define DMA_CR_EN (0x1) +#define DMA_CR_EN (0x1 << 0) + +// Device interrupt status register flags +#define DMA_ISR_TCIF (1 << 5) +#define DMA_ISR_HTIF (1 << 4) +#define DMA_ISR_TEIF (1 << 3) +#define DMA_ISR_DMEIF (1 << 2) +#define DMA_ISR_FEIF (1 << 0) + +#define DMA_ISR_ERROR_BITS (DMA_ISR_TEIF | DMA_ISR_DMEIF | DMA_ISR_FEIF) +#define DMA_ISR_BIT_MASK 0x3D + +// FIFO control register flags +#define DMA_FCR_FEIE (0x1 << 7) // FIFO error interrupt enable +#define DMA_FCR_FS (0x7 << 3) // FIFO status (READ_ONLY): +#define DMA_FCR_FS_LEVEL_1 (0x0 << 3) // 000: 0 < fifo_level < 1/4 +#define DMA_FCR_FS_LEVEL_2 (0x1 << 3) // 001: 1/4 ≤ fifo_level < 1/2 +#define DMA_FCR_FS_LEVEL_3 (0x2 << 3) // 010: 1/2 ≤ fifo_level < 3/4 +#define DMA_FCR_FS_LEVEL_4 (0x3 << 3) // 011: 3/4 ≤ fifo_level < full +#define DMA_FCR_FS_EMPTY (0x4 << 3) // 100: FIFO is empty +#define DMA_FCR_FS_FULL (0x5 << 3) // 101: FIFO is full +#define DMA_FCR_DMDIS (0x1 << 2) // Direct mode disable +#define DMA_FCR_FTH (0x3 << 0) // FIFO threshold selection +#define DMA_FCR_FTH_1_4 (0x0 << 0) // 1/4 full FIFO +#define DMA_FCR_FTH_2_4 (0x1 << 0) // 2/4 full FIFO +#define DMA_FCR_FTH_3_4 (0x2 << 0) // 3/4 full FIFO +#define DMA_FCR_FTH_FULL (0x3 << 0) // full FIFO + typedef enum dma_channel { DMA_CH0 = DMA_CR_CH0, /**< Channel 0 */ @@ -147,18 +174,6 @@ typedef enum dma_channel { DMA_CH7 = DMA_CR_CH7, /**< Channel 7 */ } dma_channel; -/* Device interrupt status register flags */ - -#define DMA_ISR_TCIF (1 << 5) -#define DMA_ISR_HTIF (1 << 4) -#define DMA_ISR_TEIF (1 << 3) -#define DMA_ISR_DMEIF (1 << 2) -#define DMA_ISR_FEIF (1 << 0) - -/* - * Devices - */ - /** Encapsulates state related to a DMA channel interrupt. */ typedef struct dma_handler_config { void (*handler)(void); /**< User-specified channel interrupt @@ -172,50 +187,53 @@ typedef struct dma_dev { rcc_clk_id clk_id; /**< Clock ID */ dma_handler_config handlers[]; /**< * @brief IRQ handlers and NVIC numbers. - * - * @see dma_attach_interrupt() * @see dma_detach_interrupt() */ } dma_dev; +/* + * Devices + */ extern dma_dev *DMA1; extern dma_dev *DMA2; -/* - * Convenience functions - */ - -extern void dma_init(dma_dev *dev); - /** Flags for DMA transfer configuration. */ typedef enum dma_mode_flags { - DMA_MEM_BUF_0 = DMA_CR_CT0, /**< Current memory target buffer 0 */ - DMA_MEM_BUF_1 = DMA_CR_CT1, /**< Current memory target buffer 1 */ - DMA_DBL_BUF_MODE = DMA_CR_DBM, /**< Current memory double buffer mode */ - DMA_PINC_OFFSET = DMA_CR_PINCOS, /**< Peripheral increment offset size */ - DMA_MINC_MODE = DMA_CR_MINC, /**< Memory increment mode */ - DMA_PINC_MODE = DMA_CR_PINC, /**< Peripheral increment mode */ - DMA_CIRC_MODE = DMA_CR_CIRC, /**< Memory Circular mode */ - DMA_FROM_PER = DMA_CR_DIR_P2M, /**< Read from memory to peripheral */ - DMA_FROM_MEM = DMA_CR_DIR_M2P, /**< Read from memory to peripheral */ - DMA_MEM_TO_MEM = DMA_CR_DIR_M2M, /**< Read from memory to memory */ - DMA_PERIF_CTRL = DMA_CR_PFCTRL, /**< Peripheral flow controller */ + DMA_MEM_BUF_0 = DMA_CR_CT0, /**< Current memory target buffer 0 */ + DMA_MEM_BUF_1 = DMA_CR_CT1, /**< Current memory target buffer 1 */ + DMA_DBL_BUF_MODE = DMA_CR_DBM, /**< Current memory double buffer mode */ + DMA_PINC_OFFSET = DMA_CR_PINCOS, /**< Peripheral increment offset size */ + DMA_MINC_MODE = DMA_CR_MINC, /**< Memory increment mode */ + DMA_PINC_MODE = DMA_CR_PINC, /**< Peripheral increment mode */ + DMA_CIRC_MODE = DMA_CR_CIRC, /**< Memory Circular mode */ + DMA_FROM_PER = DMA_CR_DIR_P2M, /**< Read from memory to peripheral */ + DMA_FROM_MEM = DMA_CR_DIR_M2P, /**< Read from memory to peripheral */ + DMA_MEM_TO_MEM = DMA_CR_DIR_M2M, /**< Read from memory to memory */ + DMA_PERIF_CTRL = DMA_CR_PFCTRL, /**< Peripheral flow controller */ DMA_PRIO_MEDIUM = DMA_CR_PL_MEDIUM, /**< Medium priority */ DMA_PRIO_HIGH = DMA_CR_PL_HIGH, /**< High priority */ DMA_PRIO_VERY_HIGH = DMA_CR_PL_VERY_HIGH, /**< Very high priority */ - DMA_TRNS_CMPLT = DMA_CR_TCIE, /**< Interrupt on transfer completion */ - DMA_TRNS_HALF = DMA_CR_HTIE, /**< Interrupt on half-transfer */ + DMA_TRNS_CMPLT = DMA_CR_TCIE, /**< Interrupt on transfer completion */ + DMA_TRNS_HALF = DMA_CR_HTIE, /**< Interrupt on half-transfer */ DMA_TRNS_ERR = DMA_CR_TEIE, /**< Interrupt on transfer error */ DMA_DIR_MODE_ERR = DMA_CR_DMEIE /**< Interrupt on direct mode error */ } dma_mode_flags; -/** Source and destination transfer sizes. */ +// Source and destination transfer sizes. typedef enum dma_xfer_size { - DMA_SIZE_8BITS = ( DMA_CR_MSIZE_8BITS|DMA_CR_PSIZE_8BITS ), /**< 8-bit transfers */ - DMA_SIZE_16BITS = (DMA_CR_MSIZE_16BITS|DMA_CR_PSIZE_16BITS), /**< 16-bit transfers */ - DMA_SIZE_32BITS = (DMA_CR_MSIZE_32BITS|DMA_CR_PSIZE_32BITS) /**< 32-bit transfers */ + DMA_SIZE_8BITS = ( DMA_CR_MSIZE_8BITS|DMA_CR_PSIZE_8BITS ), // 8-bit transfers + DMA_SIZE_16BITS = (DMA_CR_MSIZE_16BITS|DMA_CR_PSIZE_16BITS), // 16-bit transfers + DMA_SIZE_32BITS = (DMA_CR_MSIZE_32BITS|DMA_CR_PSIZE_32BITS) // 32-bit transfers } dma_xfer_size; +// Source and destination burst sizes. +typedef enum dma_burst_size { + DMA_BURST_INCR0 = ( DMA_CR_MBURST0|DMA_CR_PBURST0 ), // single transfer + DMA_BURST_INCR4 = ( DMA_CR_MBURST4|DMA_CR_PBURST4 ), // incremental burst of 4 beats + DMA_BURST_INCR8 = ( DMA_CR_MBURST8|DMA_CR_PBURST8 ), // incremental burst of 8 beats + DMA_BURST_INCR16 = (DMA_CR_MBURST16|DMA_CR_PBURST16) // incremental burst of 16 beats +} dma_burst_size; + /** DMA channel */ typedef enum dma_stream { DMA_STREAM0 = 0, /**< Stream 0 */ @@ -227,7 +245,12 @@ typedef enum dma_stream { DMA_STREAM6 = 6, /**< Stream 6 */ DMA_STREAM7 = 7, /**< Stream 7 */ } dma_stream; - + +/* + * Convenience functions + */ +extern void dma_init(dma_dev *dev); + static inline void dma_setup_transfer(dma_dev *dev, dma_stream stream, dma_channel channel, @@ -235,24 +258,24 @@ static inline void dma_setup_transfer(dma_dev *dev, __io void *peripheral_address, __io void *memory_address0, __io void *memory_address1, - uint32 flags) { + uint32 flags) +{ dev->regs->STREAM[stream].CR &= ~DMA_CR_EN; // disable + while( (dev->regs->STREAM[stream].CR)&DMA_CR_EN ); // wait till enable bit is cleared dev->regs->STREAM[stream].PAR = (uint32)peripheral_address; dev->regs->STREAM[stream].M0AR = (uint32)memory_address0; dev->regs->STREAM[stream].M1AR = (uint32)memory_address1; - dev->regs->STREAM[stream].CR = ((flags|channel|trx_size) & 0x0feffffe); // mask out reserved and enable + dev->regs->STREAM[stream].CR = (uint32)((flags|channel|trx_size) & 0x0feffffe); // mask out reserved and enable } -static inline void dma_set_num_transfers(dma_dev *dev, - dma_stream stream, - uint16 num_transfers) { - dev->regs->STREAM[stream].NDTR = num_transfers; +static inline void dma_set_num_transfers(dma_dev *dev, dma_stream stream, uint16 num_transfers) +{ + dev->regs->STREAM[stream].NDTR = (uint32)num_transfers; } -static inline void dma_set_fifo_flags(dma_dev *dev, - dma_stream stream, - uint8 fifo_flags) { - dev->regs->STREAM[stream].FCR = fifo_flags & 0x87; // mask out reserved bits +static inline void dma_set_fifo_flags(dma_dev *dev, dma_stream stream, uint8 fifo_flags) +{ + dev->regs->STREAM[stream].FCR = (uint32)(fifo_flags & 0x87); // mask out reserved bits } void dma_attach_interrupt(dma_dev *dev, @@ -261,12 +284,14 @@ void dma_attach_interrupt(dma_dev *dev, void dma_detach_interrupt(dma_dev *dev, dma_stream stream); -static inline void dma_enable(dma_dev *dev, dma_stream stream) { - dev->regs->STREAM[stream].CR |= DMA_CR_EN; +static inline void dma_enable(dma_dev *dev, dma_stream stream) +{ + dev->regs->STREAM[stream].CR |= (uint32)DMA_CR_EN; } -static inline void dma_disable(dma_dev *dev, dma_stream stream) { - dev->regs->STREAM[stream].CR &= ~DMA_CR_EN; +static inline void dma_disable(dma_dev *dev, dma_stream stream) +{ + dev->regs->STREAM[stream].CR &= (uint32)(~DMA_CR_EN); while (dev->regs->STREAM[stream].CR & DMA_CR_EN); // wait till EN bit is reset, see AN4031, chapter 4.1 } @@ -289,7 +314,11 @@ static inline uint8 dma_is_stream_enabled(dma_dev *dev, dma_stream stream) { * @param dev DMA device * @param stream Stream whose ISR bits to return. */ -uint8 dma_get_isr_bits(dma_dev *dev, dma_stream stream); +uint8 dma_get_isr_bit(dma_dev *dev, dma_stream stream, uint8_t mask); + +static inline uint8 dma_get_isr_bits(dma_dev *dev, dma_stream stream) { + return dma_get_isr_bit(dev, stream, DMA_ISR_BIT_MASK); +} /** * @brief Clear the ISR status bits for a given DMA stream. @@ -297,7 +326,11 @@ uint8 dma_get_isr_bits(dma_dev *dev, dma_stream stream); * @param dev DMA device * @param stream Stream whose ISR bits to clear. */ -void dma_clear_isr_bits(dma_dev *dev, dma_stream stream); +void dma_clear_isr_bit(dma_dev *dev, dma_stream stream, uint8_t mask); + +static inline void dma_clear_isr_bits(dma_dev *dev, dma_stream stream) { + dma_clear_isr_bit(dev, stream, DMA_ISR_BIT_MASK); +} #ifdef __cplusplus } // extern "C" diff --git a/STM32F4/cores/maple/libmaple/sdio.c b/STM32F4/cores/maple/libmaple/sdio.c new file mode 100644 index 0000000..1a9113a --- /dev/null +++ b/STM32F4/cores/maple/libmaple/sdio.c @@ -0,0 +1,194 @@ +/****************************************************************************** + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/sdio.c + * @author stevstrong + * @brief Secure digital input/output interface. + */ + +#include "sdio.h" +#include "gpio.h" +#include "wirish_time.h" + +#if defined(BOARD_generic_f407v) + +sdio_dev * SDIO = SDIO_BASE; + +#define DELAY_LONG 10 +#define DELAY_SHORT 1 + +uint8_t dly = DELAY_LONG; // microseconds delay after accessing registers + +/* + * SDIO convenience routines + */ +static void sdio_gpios_init(void) +{ + gpio_set_mode(BOARD_SDIO_D0, GPIO_AF_OUTPUT_PP_PU); + gpio_set_mode(BOARD_SDIO_D1, GPIO_AF_OUTPUT_PP_PU); + gpio_set_mode(BOARD_SDIO_D2, GPIO_AF_OUTPUT_PP_PU); + gpio_set_mode(BOARD_SDIO_D3, GPIO_AF_OUTPUT_PP_PU); + gpio_set_mode(BOARD_SDIO_CLK, GPIO_AF_OUTPUT_PP); + gpio_set_mode(BOARD_SDIO_CMD, GPIO_AF_OUTPUT_PP_PU); + // + gpio_set_af_mode(BOARD_SDIO_D0, 12); + gpio_set_af_mode(BOARD_SDIO_D1, 12); + gpio_set_af_mode(BOARD_SDIO_D2, 12); + gpio_set_af_mode(BOARD_SDIO_D3, 12); + gpio_set_af_mode(BOARD_SDIO_CLK, 12); + gpio_set_af_mode(BOARD_SDIO_CMD, 12); +} + +static void sdio_gpios_deinit(void) +{ + gpio_set_mode(BOARD_SDIO_D0, GPIO_INPUT_FLOATING); + gpio_set_mode(BOARD_SDIO_D1, GPIO_INPUT_FLOATING); + gpio_set_mode(BOARD_SDIO_D2, GPIO_INPUT_FLOATING); + gpio_set_mode(BOARD_SDIO_D3, GPIO_INPUT_FLOATING); + gpio_set_mode(BOARD_SDIO_CLK, GPIO_INPUT_FLOATING); + gpio_set_mode(BOARD_SDIO_CMD, GPIO_INPUT_FLOATING); + // + gpio_set_af_mode(BOARD_SDIO_D0, 0); + gpio_set_af_mode(BOARD_SDIO_D1, 0); + gpio_set_af_mode(BOARD_SDIO_D2, 0); + gpio_set_af_mode(BOARD_SDIO_D3, 0); + gpio_set_af_mode(BOARD_SDIO_CLK, 0); + gpio_set_af_mode(BOARD_SDIO_CMD, 0); +} + +/** + * @brief Initialize and reset the SDIO device. + */ +void sdio_init(void) +{ + rcc_clk_enable(RCC_SDIO); + rcc_reset_dev(RCC_SDIO); +} + +void sdio_power_on(void) +{ + SDIO->POWER = SDIO_POWER_PWRCTRL_ON; +// After a data write, data cannot be written to this register for three SDIOCLK clock periods +// plus two PCLK2 clock periods. + delayMicroseconds(DELAY_LONG); +} + +void sdio_power_off(void) +{ + SDIO->POWER = SDIO_POWER_PWRCTRL_OFF; +// After a data write, data cannot be written to this register for three SDIOCLK clock periods +// plus two PCLK2 clock periods. + delayMicroseconds(DELAY_LONG); +} + +/** + * @brief Enable the SDIO peripheral + +void sdio_peripheral_enable(void) { + bb_peri_set_bit(SDIO->CR1, SPI_CR1_SPE_BIT, 1); +} + */ +/** + * @brief Disable a SPI peripheral + +void sdio_peripheral_disable(spi_dev *dev) { + bb_peri_set_bit(&dev->regs->CR1, SPI_CR1_SPE_BIT, 0); +} + */ +void sdio_set_clock(uint32_t clk) +{ + if (clk>24000000UL) clk = 24000000UL; // limit the SDIO master clock to 24MHz + + if (clk<1000000) dly = DELAY_LONG; + else dly = DELAY_SHORT; + + sdio_disable(); + SDIO->CLKCR = (SDIO->CLKCR & (~(SDIO_CLKCR_CLKDIV|SDIO_CLKCR_BYPASS))) | SDIO_CLKCR_CLKEN | (((SDIOCLK/clk)-2)&SDIO_CLKCR_CLKDIV); + delayMicroseconds(dly); +} + +void sdio_set_dbus_width(uint16_t bus_w) +{ + SDIO->CLKCR = (SDIO->CLKCR & (~SDIO_CLKCR_WIDBUS)) | bus_w; + delayMicroseconds(dly); +} + +void sdio_set_dblock_size(uint8_t dbsize) +{ + SDIO->DCTRL = (SDIO->DCTRL&(~SDIO_DCTRL_DBLOCKSIZE)) | ((dbsize&0xF)<<4); + delayMicroseconds(dly); +} + +void sdio_enable(void) +{ + SDIO->CLKCR |= SDIO_CLKCR_CLKEN; + delayMicroseconds(dly); +} + +void sdio_disable(void) +{ + SDIO->CLKCR ^= SDIO_CLKCR_CLKEN; + delayMicroseconds(dly); +} + +/** + * @brief Configure and enable the SDIO device. + */ +void sdio_begin(void) +{ + sdio_gpios_init(); + sdio_init(); + sdio_power_on(); + // Set initial SCK rate. + sdio_set_clock(400000); + delayMicroseconds(200); // generate 80 pulses at 400kHz +} + +/** + * @brief Disables the SDIO device. + */ +void sdio_end(void) +{ + sdio_disable(); + while ( sdio_cmd_xfer_ongoing() ); + sdio_power_off(); + rcc_clk_disable(RCC_SDIO); + sdio_gpios_deinit(); +} + +/** + * @brief Send command by the SDIO device. + */ +uint8_t sdio_cmd_send(uint16_t cmd_index_resp_type, uint32_t arg) +{ + uint8_t retries = 10; // in case of errors + do { // retry command if errors detected + // clear interrupt flags - IMPORTANT!!! + SDIO->ICR = SDIO_ICR_CMD_FLAGS; + // write command + SDIO->ARG = arg; + SDIO->CMD = (uint32_t)(SDIO_CMD_CPSMEN | cmd_index_resp_type ); + while ( (SDIO->STA&SDIO_STA_CMDACT) ) ; // wait for actual command transfer to finish + // wait for response, if the case + if ( cmd_index_resp_type&(SDIO_CMD_WAIT_SHORT_RESP|SDIO_CMD_WAIT_LONG_RESP) ) { + while ( !(SDIO->STA&(SDIO_STA_CMDREND|SDIO_STA_CMD_ERROR_FLAGS)) ) ; + } else break; // no response required + if ( SDIO->STA&(SDIO_STA_CMDREND|SDIO_STA_CTIMEOUT) ) + break; // response received or timeout + // ignore CRC error for CMD5 and ACMD41 + if ( ((cmd_index_resp_type&SDIO_CMD_CMDINDEX)==5) || ((cmd_index_resp_type&SDIO_CMD_CMDINDEX)==41) ) + break; + } while ( (--retries) ); + return (uint8_t)retries; +} + +#endif // BOARD_generic_f407v diff --git a/STM32F4/cores/maple/libmaple/sdio.h b/STM32F4/cores/maple/libmaple/sdio.h new file mode 100644 index 0000000..f0afaa16 --- /dev/null +++ b/STM32F4/cores/maple/libmaple/sdio.h @@ -0,0 +1,250 @@ +/****************************************************************************** + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file sdio.h + * @brief Secure digital input/output interface. + */ + +#ifndef _SDIO_H_ +#define _SDIO_H_ + + +#include "libmaple_types.h" + + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifdef STM32_HIGH_DENSITY + +/* + * Register maps and devices + */ + +// SDIO register map type +typedef struct sdio_reg_map { + __io uint32 POWER; // 0x00 + __io uint32 CLKCR; // 0x04 + __io uint32 ARG; // 0x08 + __io uint32 CMD; // 0x0C + __io uint32 RESPCMD; // 0x10 (0x3F) + const uint32 RESP[4]; // 0x14 - contain the card status, which is part of the received response. + __io uint32 DTIMER; // 0x24 - contains the data timeout period, in card bus clock periods. + __io uint32 DLEN; // 0x28 (0x01FF FFFF) - contains the number of data bytes to be transferred + __io uint32 DCTRL; // 0x2C + __io uint32 DCOUNT; // 0x30 (0x01FF FFFF) + __io uint32 STA; // 0x34 + __io uint32 ICR; // 0x38 + __io uint32 MASK; // 0x3C + const uint32 RESERVED1[2]; + __io uint32 FIFOCNT; // 0x48 (0x01FF FFFF) + const uint32 RESERVED2[13]; + __io uint32 FIFO; // 0x80 +} sdio_reg_map; +#define sdio_dev sdio_reg_map + +/** SDIO register map base pointer */ +#define SDIO_BASE ((struct sdio_reg_map*)0x40012C00) + +extern sdio_dev * SDIO; + +/* + * Register bit definitions + */ + +/* NOR/PSRAM chip-select control registers */ + +// SDIO_POWER register bits +// At least seven HCLK clock periods are needed between two write accesses to this register. +// After a data write, data cannot be written to this register for three SDIOCLK clock periods +// plus two PCLK2 clock periods. +#define SDIO_POWER_PWRCTRL_OFF 0x00 +#define SDIO_POWER_PWRCTRL_ON 0x03 + +// SDIO_CLKCR register bits +// Controls the SDIO_CK output clock. +// After a data write, data cannot be written to this register for three SDIOCLK clock periods +// plus two PCLK2 clock periods. SDIO_CK can also be stopped during the read wait interval +// for SD I/O cards: in this case the SDIO_CLKCR register does not control SDIO_CK. +#define SDIO_CLKCR_HWFC_EN (1<<14) // HW Flow Control enable - DON'T USE!!! (see errata sheet 2.12.1) + // Overrun errors (Rx mode) and FIFO underrun (Tx mode) + // should be managed by the application software. +#define SDIO_CLKCR_NEGEDGE (1<<13) // SDIO_CK de-phasing selection bit - DON'T USE!!! (see errata sheet 2.12.4) +#define SDIO_CLKCR_WIDBUS (3<<11) // Data bus width +#define SDIO_CLKCR_WIDBUS_1BIT (0<<11) // 1 bit (SDIO_D0 used) +#define SDIO_CLKCR_WIDBUS_4BIT (1<<11) // 4-bit (SDIO_D[3:0] used) +#define SDIO_CLKCR_BYPASS (1<<10) // Clock divider bypass enable bit - SDIO_CK = SDIOCLK, CLKDIV not relevant. +#define SDIO_CLKCR_PWRSAV (1<<9) // 0: SDIO_CK clock is always enabled, 1: SDIO_CK is only enabled when the bus is active +#define SDIO_CLKCR_CLKEN (1<<8) // Clock enable +#define SDIO_CLKCR_CLKDIV (0xFF) // SDIO_CK = SDIOCLK / [CLKDIV + 2] +#define SDIOCLK 48000000UL // SDIO master clock frequency + +// SDIO_CMD register bits +// After a data write, data cannot be written to this register for three SDIOCLK clock periods +// plus two PCLK2 clock periods. +// MultiMediaCards can send two kinds of response: short responses, 48 bits long, or long +// responses,136 bits long. SD card and SD I/O card can send only short responses, the +// argument can vary according to the type of response: the software will distinguish the type +// of response according to the sent command. CE-ATA devices send only short responses. +#define SDIO_CMD_ATACMD (1<<14) +#define SDIO_CMD_NIEN (1<<13) +#define SDIO_CMD_ENCMDCOMPL (1<<12) +#define SDIO_CMD_SDIOSUSPEND (1<<11) +#define SDIO_CMD_CPSMEN (1<<10) +#define SDIO_CMD_WAITPEND (1<<9) +#define SDIO_CMD_WAITINT (1<<8) +#define SDIO_CMD_WAITRESP (3<<6) +#define SDIO_CMD_WAIT_NO_RESP (0<<6) +#define SDIO_CMD_WAIT_SHORT_RESP (1<<6) +#define SDIO_CMD_WAIT_LONG_RESP (3<<6) +#define SDIO_CMD_CMDINDEX (0x3F) + +// SDIO_DLEN register bits +// For a block data transfer, the value in the data length register must be a multiple of the block +// size (see SDIO_DCTRL). A data transfer must be written to the data timer register and the +// data length register before being written to the data control register. +// For an SDIO multibyte transfer the value in the data length register must be between 1 and 512. +#define SDIO_DLEN_DATALENGTH (0x01FFFFFF) + +// SDIO_DCTRL register bits +// Controls the data path state machine (DPSM). +// After a data write, data cannot be written to this register for three SDIOCLK clock periods +// plus two PCLK2 clock periods. +#define SDIO_DCTRL_SDIOEN (1<<11) // the DPSM performs an SD I/O-card-specific operation. +#define SDIO_DCTRL_RWMODE (1<<10) // 0: Read Wait control stopping SDIO_D2, 1:Read Wait control using SDIO_CK +#define SDIO_DCTRL_RWSTOP (1<<9) // 0: Read wait in progress if RWSTART bit is set, 1: Enable for read wait stop if RWSTART bit is set +#define SDIO_DCTRL_RWSTART (1<<8) // read wait operation starts +#define SDIO_DCTRL_DBLOCKSIZE (0xF<<4) // Define the data block length when the block data transfer mode is selected: 2^N bytes +#define SDIO_BLOCKSIZE_64 (6<<4) +#define SDIO_BLOCKSIZE_512 (9<<4) +#define SDIO_DCTRL_DMAEN (1<<3) // DMA enable +#define SDIO_DCTRL_DTMODE (1<<2) // Data transfer mode selection: 0: Block data transfer, 1: Stream or SDIO multi-byte data transfer +#define SDIO_DCTRL_DTDIR (1<<1) // Data transfer direction selection: 0: From controller to card, 1: From card to controller. +#define SDIO_DIR_TX (0<<1) +#define SDIO_DIR_RX (1<<1) +#define SDIO_DCTRL_DTEN (1<<0) // Start data transfer. Depending on the direction bit, DTDIR, + // the DPSM moves to the Wait_S, Wait_R state or Readwait if RW Start is set immediately at + // the beginning of the transfer. It is not necessary to clear the enable bit after the end of a data + // transfer but the SDIO_DCTRL must be updated to enable a new data transfer +// The meaning of the DTMODE bit changes according to the value of the SDIOEN bit: +// When DTEN=0 and DTMODE=1, the MultiMediaCard stream mode is enabled. +// When DTEN=1 and DTMODE=1, the peripheral enables an SDIO multi-byte transfer. + +// SDIO_STA register bits +#define SDIO_STA_CEATAEND (1<<23) // CE-ATA command completion signal received for CMD61 +#define SDIO_STA_SDIOIT (1<<22) // SDIO interrupt received +#define SDIO_STA_RXDAVL (1<<21) // Data available in receive FIFO +#define SDIO_STA_TXDAVL (1<<20) // Data available in transmit FIFO +#define SDIO_STA_RXFIFOE (1<<19) // Receive FIFO empty +#define SDIO_STA_TXFIFOE (1<<18) // Transmit FIFO empty (2 words) +#define SDIO_STA_RXFIFOF (1<<17) // Receive FIFO full (2 words before the FIFO is full.) +#define SDIO_STA_TXFIFOF (1<<16) // Transmit FIFO full +#define SDIO_STA_RXFIFOHF (1<<15) // Receive FIFO half full: there are at least 8 words in the FIFO +#define SDIO_STA_TXFIFOHE (1<<14) // Transmit FIFO half empty: at least 8 words can be written into the FIFO +#define SDIO_STA_RXACT (1<<13) // Data receive in progress +#define SDIO_STA_TXACT (1<<12) // Data transmit in progress +#define SDIO_STA_CMDACT (1<<11) // Command transfer in progress +#define SDIO_STA_DBCKEND (1<<10) // Data block sent/received (CRC check passed) +#define SDIO_STA_STBITERR (1<<9) // Start bit not detected on all data signals in wide bus mode +#define SDIO_STA_DATAEND (1<<8) // Data end (data counter SDIOCOUNT is zero) +#define SDIO_STA_CMDSENT (1<<7) // Command sent (no response required) +#define SDIO_STA_CMDREND (1<<6) // Command response received (CRC check passed) +#define SDIO_STA_RXOVERR (1<<5) // Received FIFO overrun error +#define SDIO_STA_TXUNDERR (1<<4) // Transmit FIFO underrun error +#define SDIO_STA_DTIMEOUT (1<<3) // Data timeout +#define SDIO_STA_CTIMEOUT (1<<2) // Command response timeout. The Command TimeOut period has a fixed value of 64 SDIO_CK clock periods. +#define SDIO_STA_DCRCFAIL (1<<1) // Data block sent/received (CRC check failed) +#define SDIO_STA_CCRCFAIL (1<<0) // Command response received (CRC check failed) + +#define SDIO_STA_CMD_ERROR_FLAGS (SDIO_STA_CTIMEOUT | SDIO_STA_CCRCFAIL) +#define SDIO_STA_TRX_ERROR_FLAGS (SDIO_STA_STBITERR | SDIO_STA_RXOVERR | SDIO_STA_TXUNDERR | SDIO_STA_DTIMEOUT | SDIO_STA_DCRCFAIL) +#define SDIO_STA_TRX_ACT_FLAGS (SDIO_STA_RXACT|SDIO_STA_TXACT) + +// SDIO_ICR register bits (WO - write only) +#define SDIO_ICR_CEATAENDC (1<<23) // clear CEATAEND flag +#define SDIO_ICR_SDIOITC (1<<22) // clear SDIOIT flag +#define SDIO_ICR_DBCKENDC (1<<10) // clear DBCKENDC flag +#define SDIO_ICR_STBITERRC (1<<9) // clear STBITERRC flag +#define SDIO_ICR_DATAENDC (1<<8) // clear DATAENDC flag +#define SDIO_ICR_CMDSENTC (1<<7) // clear CMDSENTC flag +#define SDIO_ICR_CMDRENDC (1<<6) // clear CMDREND flag +#define SDIO_ICR_RXOVERRC (1<<5) // clear RXOVERR flag +#define SDIO_ICR_TXUNDERRC (1<<4) // clear TXUNDERR flag +#define SDIO_ICR_DTIMEOUTC (1<<3) // clear DTIMEOUT flag +#define SDIO_ICR_CTIMEOUTC (1<<2) // clear CTIMEOUT flag +#define SDIO_ICR_DCRCFAILC (1<<1) // clear DCRCFAIL flag +#define SDIO_ICR_CCRCFAILC (1<<0) // clear CCRCFAIL flag + +#define SDIO_ICR_CMD_FLAGS (SDIO_ICR_CEATAENDC | SDIO_ICR_SDIOITC | SDIO_ICR_CMDSENTC | SDIO_ICR_CMDRENDC | SDIO_ICR_CTIMEOUTC | SDIO_ICR_CCRCFAILC) +#define SDIO_ICR_DATA_FLAGS (SDIO_ICR_DBCKENDC | SDIO_ICR_STBITERRC | SDIO_ICR_DATAENDC | SDIO_ICR_RXOVERRC | SDIO_ICR_TXUNDERRC | SDIO_ICR_DTIMEOUTC | SDIO_ICR_DCRCFAILC) + +// SDIO_MASK register bits +// Determines which status flags generate an interrupt request by setting the corresponding bit to 1b. +#define SDIO_MASK_CEATAENDIE (1<<23) // enable CEATAEND interrupt +#define SDIO_MASK_SDIOITIE (1<<22) // enable SDIOIT interrupt +#define SDIO_MASK_RXDAVLIE (1<<21) // enable RXDAVL interrupt +#define SDIO_MASK_TXDAVLIE (1<<20) // enable TXDAVL interrupt +#define SDIO_MASK_RXFIFOEIE (1<<19) // enable RXFIFOE interrupt +#define SDIO_MASK_TXFIFOEIE (1<<18) // enable TXFIFOE interrupt +#define SDIO_MASK_RXFIFOFIE (1<<17) // enable RXFIFOF interrupt +#define SDIO_MASK_TXFIFOFIE (1<<16) // enable TXFIFOF interrupt +#define SDIO_MASK_RXFIFOHFIE (1<<15) // enable RXFIFOHF interrupt +#define SDIO_MASK_TXFIFOHEIE (1<<14) // enable TXFIFOHE interrupt +#define SDIO_MASK_RXACTIE (1<<13) // enable RXACT interrupt +#define SDIO_MASK_TXACTIE (1<<12) // enable TXACT interrupt +#define SDIO_MASK_CMDACTIE (1<<11) // enable CMDACT interrupt +#define SDIO_MASK_DBCKENDIE (1<<10) // enable DBCKENDC interrupt +#define SDIO_MASK_STBITERRIE (1<<9) // enable STBITERR interrupt +#define SDIO_MASK_DATAENDIE (1<<8) // enable DATAENDC interrupt +#define SDIO_MASK_CMDSENTIE (1<<7) // enable CMDSENTC interrupt +#define SDIO_MASK_CMDRENDIE (1<<6) // enable CMDREND interrupt +#define SDIO_MASK_RXOVERRIE (1<<5) // enable RXOVERR interrupt +#define SDIO_MASK_TXUNDERRIE (1<<4) // enable TXUNDERR interrupt +#define SDIO_MASK_DTIMEOUTIE (1<<3) // enable DTIMEOUT interrupt +#define SDIO_MASK_CTIMEOUTIE (1<<2) // enable CTIMEOUT interrupt +#define SDIO_MASK_DCRCFAILIE (1<<1) // enable DCRCFAIL interrupt +#define SDIO_MASK_CCRCFAILIE (1<<0) // enable CCRCFAIL interrupt + + +void sdio_enable(void); +void sdio_disable(void); +void sdio_begin(void); +uint8_t sdio_cmd_send(uint16_t cmd_index_resp_type, uint32_t arg); +void sdio_set_clock(uint32_t clk); +void sdio_set_dbus_width(uint16_t bus_w); +void sdio_set_dblock_size(uint8_t dbsize); +//void sdio_trx_enable(uint8_t dir); +inline void sdio_trx_enable(void) +{ + SDIO->DCTRL |= SDIO_DCTRL_DTEN; // enable data transfer +} + +inline uint32_t sdio_cmd_xfer_ongoing(void) { return (SDIO->STA&SDIO_STA_CMDACT); } +inline uint32_t sdio_cmd_complete(void) { return (SDIO->STA&SDIO_STA_CMDSENT); } + +inline void sdio_setup_transfer(uint32_t dtimer, uint32_t dlen, uint16_t flags) +{ + SDIO->ICR = SDIO_ICR_DATA_FLAGS; // clear data access relevant flags + SDIO->DTIMER = dtimer; + SDIO->DLEN = dlen; + SDIO->DCTRL = flags;// | SDIO_DCTRL_DTEN; // enable data transfer +} + +#endif /* STM32_HIGH_DENSITY */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/STM32F4/cores/maple/wirish_time.h b/STM32F4/cores/maple/wirish_time.h index 3a11786..87091a3 100644 --- a/STM32F4/cores/maple/wirish_time.h +++ b/STM32F4/cores/maple/wirish_time.h @@ -36,6 +36,10 @@ #include #include +#ifdef __cplusplus +extern "C"{ +#endif + #define US_PER_MS 1000 /** @@ -101,4 +105,8 @@ void delay(unsigned long ms); */ void delayMicroseconds(uint32 us); +#ifdef __cplusplus +} /* extern "C" */ +#endif + #endif From 4aa44ee0e0eb99707a0aa8d407444eb8c539a694 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Sun, 18 Jun 2017 18:40:40 +0200 Subject: [PATCH 088/351] added SDIO lib files --- STM32F4/libraries/SDIO/SdioF4.cpp | 801 ++++++++++++++++++++++++++++++ STM32F4/libraries/SDIO/SdioF4.h | 7 + 2 files changed, 808 insertions(+) create mode 100644 STM32F4/libraries/SDIO/SdioF4.cpp create mode 100644 STM32F4/libraries/SDIO/SdioF4.h diff --git a/STM32F4/libraries/SDIO/SdioF4.cpp b/STM32F4/libraries/SDIO/SdioF4.cpp new file mode 100644 index 0000000..1d533a0 --- /dev/null +++ b/STM32F4/libraries/SDIO/SdioF4.cpp @@ -0,0 +1,801 @@ +/* Arduino SdCard Library + * Copyright (C) 2016 by William Greiman + * + * This file is part of the Arduino SdSpiCard Library + * + * This Library is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This Library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Arduino SdSpiCard Library. If not, see + * . + */ + +#include "SdioF4.h" +#include +#include +#include + +#define USE_DEBUG_MODE 0 + +//============================================================================== +//#define SDHC_PROCTL_DTW_4BIT 0x01 +#define CMD8_RETRIES 10 +#define BUSY_TIMEOUT_MILLIS 500 +//============================================================================== +#define CMD_RESP_NONE SDIO_CMD_WAIT_NO_RESP +#define CMD_RESP_R1 SDIO_CMD_WAIT_SHORT_RESP // normal response +#define CMD_RESP_R1b SDIO_CMD_WAIT_SHORT_RESP // normal response + busy data line (optional) +#define CMD_RESP_R2 SDIO_CMD_WAIT_LONG_RESP // CID, CSD +#define CMD_RESP_R3 SDIO_CMD_WAIT_SHORT_RESP // OCR register, response to ACMD41 +#define CMD_RESP_R6 SDIO_CMD_WAIT_SHORT_RESP // published RCA response, response to CMD3 +#define CMD_RESP_R7 SDIO_CMD_WAIT_SHORT_RESP // response to CMD8 + +#define CMD0_XFERTYP (uint16_t)( CMD0 | CMD_RESP_NONE ) +#define CMD2_XFERTYP (uint16_t)( CMD2 | CMD_RESP_R2 ) +#define CMD3_XFERTYP (uint16_t)( CMD3 | CMD_RESP_R6 ) +#define CMD6_XFERTYP (uint16_t)( CMD6 | CMD_RESP_R1 ) +#define ACMD6_XFERTYP (uint16_t)( ACMD6 | CMD_RESP_R1 ) +#define CMD7_XFERTYP (uint16_t)( CMD7 | CMD_RESP_R1b ) +#define CMD8_XFERTYP (uint16_t)( CMD8 | CMD_RESP_R7 ) +#define CMD9_XFERTYP (uint16_t)( CMD9 | CMD_RESP_R2 ) +#define CMD10_XFERTYP (uint16_t)( CMD10 | CMD_RESP_R2 ) +#define CMD12_XFERTYP (uint16_t)( CMD12 | CMD_RESP_R1b ) +#define CMD13_XFERTYP (uint16_t)( CMD13 | CMD_RESP_R1 ) +#define CMD17_XFERTYP (uint16_t)( CMD17 | CMD_RESP_R1 ) +#define CMD18_XFERTYP (uint16_t)( CMD18 | CMD_RESP_R1 ) +#define ACMD23_XFERTYP (uint16_t)( ACMD23 | CMD_RESP_R1 ) +#define CMD24_XFERTYP (uint16_t)( CMD24 | CMD_RESP_R1 ) +#define CMD25_XFERTYP (uint16_t)( CMD25 | CMD_RESP_R1 ) +#define CMD32_XFERTYP (uint16_t)( CMD32 | CMD_RESP_R1 ) +#define CMD33_XFERTYP (uint16_t)( CMD32 | CMD_RESP_R1 ) +#define CMD38_XFERTYP (uint16_t)( CMD38 | CMD_RESP_R1b ) +#define ACMD41_XFERTYP (uint16_t)( ACMD41 | CMD_RESP_R3 ) + +#define CMD55_XFERTYP (uint16_t)( CMD55 | CMD_RESP_R1 ) + +//============================================================================= +//static void enableGPIO(bool enable); +//static void enableDmaIrs(); +static void initSDHC(void); +static bool isBusyCMD13(void); +static bool isBusyTransferComplete(void); +//static bool isBusyCommandComplete(); +//static bool isBusyCommandInhibit(); +static bool readReg16(uint32_t xfertyp, void* data); +//static void setSdclk(uint32_t kHzMax); +static bool yieldTimeout(bool (*fcn)(void)); +static bool waitDmaStatus(void); +static bool waitTimeout(bool (*fcn)(void)); +//----------------------------------------------------------------------------- +#define TRX_RD 0 +#define TRX_WR 1 +static uint8_t m_dir = TRX_RD; +static bool (*m_busyFcn)() = 0; +static bool m_initDone = false; +static uint32_t m_lba; // for raw non-DMA read(write)Start, read(write)Data, read(write)Stop +static uint32_t m_cnt; // for raw non-DMA read(write)Start, read(write)Data, read(write)Stop +static bool m_version2; +static bool m_highCapacity; +static uint8_t m_errorCode = SD_CARD_ERROR_INIT_NOT_CALLED; +static uint32_t m_errorLine = 0; +static uint32_t m_rca; +//static volatile bool m_dmaBusy = false; +static volatile uint32_t m_irqstat; +static uint32_t m_sdClkKhz = 0; +static uint32_t m_ocr; +static cid_t m_cid; +static csd_t m_csd; +static uint32_t t = 0; +//============================================================================= +#if USE_DEBUG_MODE +#define DBG_PRINT() { \ + Serial.write('_'); Serial.print(__FUNCTION__); Serial.write('_'); Serial.print(__LINE__); Serial.print(": "); \ + Serial.print("DMA->LISR: "); Serial.print(DMA2->regs->LISR, HEX); \ + /*Serial.print("DMA->HISR: "); Serial.println(DMA2->regs->HISR, HEX);*/ \ + Serial.print(", DMA->CR: "); Serial.print(DMA2->regs->STREAM[DMA_STREAM3].CR, HEX); \ + Serial.print(", DMA->NDTR: "); Serial.print(DMA2->regs->STREAM[DMA_STREAM3].NDTR, HEX); \ + /**/Serial.print(", DMA->PAR: "); Serial.print(DMA2->regs->STREAM[DMA_STREAM3].PAR, HEX); \ + /**/Serial.print(", DMA->M0AR: "); Serial.print(DMA2->regs->STREAM[DMA_STREAM3].M0AR, HEX); \ + Serial.print(", DMA->FCR: "); Serial.print(DMA2->regs->STREAM[DMA_STREAM3].FCR, HEX); \ + \ + /*Serial.print(" SDIO->POWER: "); Serial.println(SDIO->POWER, HEX);*/ \ + Serial.print(", SDIO->CLKCR: "); Serial.print(SDIO->CLKCR, HEX); \ + Serial.print(", SDIO->DTIMER: "); Serial.print(SDIO->DTIMER, HEX); \ + Serial.print(", SDIO->DCTRL: "); Serial.print(SDIO->DCTRL, HEX); \ + /**/Serial.print(", SDIO->DLEN: "); Serial.print(SDIO->DLEN); \ + Serial.print(", SDIO->DCOUNT: "); Serial.print(SDIO->DCOUNT); \ + Serial.print(", SDIO->STA: "); Serial.println(SDIO->STA, HEX); \ + /*delay(1);*/ \ +} +#define DBG_PIN PD0 + +#else // USE_DEBUG_MODE +#define DBG_PRINT() +#endif // USE_DEBUG_MODE + +/*****************************************************************************/ +static void _panic(const char *message, uint32_t code) +{ + Serial.print(message); Serial.println(code, HEX); + //Block the execution with blinky leds + pinMode(BOARD_LED_PIN, OUTPUT); + pinMode(BOARD_LED2_PIN, OUTPUT); + while (1) { + digitalWrite(BOARD_LED_PIN, HIGH); + digitalWrite(BOARD_LED2_PIN, LOW); + delay(250); + digitalWrite(BOARD_LED_PIN, LOW); + digitalWrite(BOARD_LED2_PIN, HIGH); + delay(250); + } +} +/*=========================================================================== +void yield(void) +{ + uint32_t val = SDIO->STA; + if ( val & SDIO_STA_TRX_ERROR_FLAGS ) { + Serial.print("SDIO ERROR:: SDIO->CLKCR: "); Serial.print(SDIO->CLKCR, HEX); \ + Serial.print(", SDIO->DTIMER: "); Serial.print(SDIO->DTIMER, HEX); \ + Serial.print(", SDIO->DCTRL: "); Serial.print(SDIO->DCTRL, HEX); \ + Serial.print(", SDIO->DLEN: "); Serial.print(SDIO->DLEN); \ + Serial.print(", SDIO->DCOUNT: "); Serial.print(SDIO->DCOUNT); \ + Serial.print(", SDIO->STA: "); Serial.print(SDIO->STA, HEX); \ + Serial.print(", SDIO->RESP0: "); Serial.println(SDIO->RESP[0], HEX); \ + if (val & SDIO_STA_STBITERR) Serial.print(" STBITERR"); + if (val & SDIO_STA_RXOVERR) Serial.print(" RXOVERR"); + if (val & SDIO_STA_TXUNDERR) Serial.print(" TXUNDERR"); + if (val & SDIO_STA_DTIMEOUT) Serial.print(" DTIMEOUT"); + if (val & SDIO_STA_DCRCFAIL) Serial.print(" DCRCFAIL"); + _panic(" - SDIO: Data Transmission Error ", val); + } + + val = dma_get_isr_bit(DMA2, DMA_STREAM3, DMA_ISR_ERROR_BITS); + if ( val & DMA_ISR_FEIF ) { + val ^= DMA_ISR_FEIF; + dma_clear_isr_bit(DMA2, DMA_STREAM3, DMA_ISR_FEIF); + } + if ( val ) { + if (val & DMA_ISR_TEIF) Serial.print(" TEIF"); + if (val & DMA_ISR_DMEIF) Serial.print(" DMEIF"); + //if (val & DMA_ISR_FEIF) Serial.print(" FEIF"); + _panic(" - DMA: Data Transmission Error ", val); + } + //Serial.write('.'); +}*/ +//============================================================================= +// Error function and macro. +inline bool setSdErrorCode(uint8_t code, uint32_t line) { + m_errorCode = code; + m_errorLine = line; + return false; // setSdErrorCode +} +#define sdError(code) setSdErrorCode(code, __LINE__) +//============================================================================= +/* ISR +void sdhc_isr() { + SDHC_IRQSIGEN = 0; + m_irqstat = SDHC_IRQSTAT; + SDHC_IRQSTAT = m_irqstat; + m_dmaBusy = false; +}*/ +//============================================================================= +// Static functions. +//----------------------------------------------------------------------------- +static bool cardCommand(uint16_t xfertyp, uint32_t arg) +{ +#if USE_DEBUG_MODE + Serial.print("cardCommand: "); Serial.print(xfertyp&SDIO_CMD_CMDINDEX); Serial.print(", arg: "); Serial.print(arg, HEX); +#endif + uint8_t resp = sdio_cmd_send(xfertyp, arg); // returns non-zero if fails, zero if OK +#if USE_DEBUG_MODE + Serial.print(", resp: "); Serial.print(resp, HEX); + Serial.print(", SDIO->STA: "); Serial.print(SDIO->STA, HEX); Serial.print(", cmd_resp: "); Serial.print(SDIO->RESP[0], HEX); + if ( (xfertyp&SDIO_CMD_WAIT_LONG_RESP)==SDIO_CMD_WAIT_LONG_RESP ) { + Serial.print(", "); Serial.print(SDIO->RESP[1], HEX); Serial.print(", "); Serial.print(SDIO->RESP[2], HEX); Serial.print(", "); Serial.println(SDIO->RESP[3], HEX); + } else Serial.println(); +#endif + return resp; // return non-zero when OK +} +//----------------------------------------------------------------------------- +static bool cardAcmd(uint32_t rca, uint32_t xfertyp, uint32_t arg) { + return cardCommand(CMD55_XFERTYP, rca) && cardCommand((uint16_t)xfertyp, arg); +} +/*---------------------------------------------------------------------------*/ +static bool cardCMD6(uint32_t arg, uint8_t* status) { + // CMD6 returns 64 bytes. + // use polling only for the moment + if (waitTimeout(isBusyCMD13)) { + return sdError(SD_CARD_ERROR_CMD13); + } + // get the 64 bytes over data lines + sdio_setup_transfer(80000, 64, (SDIO_BLOCKSIZE_64 | SDIO_DIR_RX | SDIO_DCTRL_DTEN)); + + cardCommand(CMD6_XFERTYP, arg); + + // wait data Rx response + if (waitTimeout(isBusyTransferComplete)) { + return sdError(SD_CARD_ERROR_CMD6); + } +DBG_PRINT(); + // copy 64 bytes as 16 words from FIFO to buffer + for (uint8_t i=0; i<16; i++) { + *(uint32_t*)(&status[i<<2]) = SDIO->FIFO; + } + //SDIO->DCTRL = 0; // disable data controller + +#if USE_DEBUG_MODE + Serial.print("read data: "); for (uint8_t i=0; i<17; i++) { Serial.print(status[i], HEX); Serial.print(", "); } Serial.println(); +#endif +return true; +} +//----------------------------------------------------------------------------- +static void initSDHC(void) +{ + sdio_begin(); + DBG_PRINT(); +} +/*---------------------------------------------------------------------------*/ +static bool isBusyCMD13(void) { + if (!cardCommand(CMD13_XFERTYP, m_rca)) { // SEND_STATUS + // Caller will timeout. + return true; + } + return !(SDIO->RESP[0] & CARD_STATUS_READY_FOR_DATA); +} +/*---------------------------------------------------------------------------*/ +static bool isBusyDMA(void) +{ + uint8_t isr = dma_get_isr_bit(DMA2, DMA_STREAM3, (DMA_ISR_TCIF | DMA_ISR_ERROR_BITS)); + //if (isr&DMA_ISR_TCIF) dma_disable(DMA2, DMA_STREAM3); + return !(isr^DMA_ISR_FEIF); // ignore transfer error flag +} +/*---------------------------------------------------------------------------*/ +static bool isBusyTransferComplete(void) +{ + uint32_t mask = SDIO->STA &(SDIO_STA_DATAEND | SDIO_STA_TRX_ERROR_FLAGS); +#if USE_DEBUG_MODE + if ( mask & SDIO_STA_TRX_ERROR_FLAGS ) { + Serial.print("XFER ERROR: SDIO->STA: "); Serial.print(SDIO->STA, HEX); + if (mask & SDIO_STA_STBITERR) Serial.print(" STBITERR"); + if (mask & SDIO_STA_RXOVERR) Serial.print(" RXOVERR"); + if (mask & SDIO_STA_TXUNDERR) Serial.print(" TXUNDERR"); + if (mask & SDIO_STA_DTIMEOUT) Serial.print(" DTIMEOUT"); + if (mask & SDIO_STA_DCRCFAIL) Serial.print(" DCRCFAIL"); + Serial.println(); + } +#endif + if (mask) { + dma_disable(DMA2, DMA_STREAM3); + return false; + } + return true; +} +/*---------------------------------------------------------------------------*/ +static void trxStart(uint8_t* buf, uint32_t n, uint8_t dir) +{ + m_dir = dir; + uint32_t flags = (SDIO_BLOCKSIZE_512 | SDIO_DCTRL_DTEN); + if (dir==TRX_RD) flags |= SDIO_DIR_RX; + // setup SDIO to transfer n blocks of 512 bytes + sdio_setup_transfer(0x00FFFFFF, n, flags); +} +/*---------------------------------------------------------------------------*/ +static bool trxStop() +{ + if (!cardCommand(CMD12_XFERTYP, 0)) { + return sdError(SD_CARD_ERROR_CMD12); + } + if ( t ) { + Serial.print(", in "); Serial.println(millis()-t); + t = 0; + } + return true; +} +/*---------------------------------------------------------------------------*/ +static bool dmaTrxStart(uint8_t* buf, uint32_t n, uint8_t dir) +{ + m_dir = dir; + if ((3 & (uint32_t)buf) || n == 0) { // check alignment + _panic("- transferStart: unaligned buffer address ", (uint32_t)buf); + return sdError(SD_CARD_ERROR_DMA); + } + if (dir==TRX_RD && yieldTimeout(isBusyCMD13)) { + return sdError(SD_CARD_ERROR_CMD13); + } + uint32_t flags = (SDIO_BLOCKSIZE_512 | SDIO_DCTRL_DMAEN | SDIO_DCTRL_DTEN); + if (dir==TRX_RD) flags |= SDIO_DIR_RX; + // setup SDIO to transfer n blocks of 512 bytes + sdio_setup_transfer(0x00FFFFFF, n, flags); + // setup DMA2 stream 3 channel 4 + dma_init(DMA2); + flags = (DMA_PERIF_CTRL | DMA_BURST_INCR4 | DMA_MINC_MODE | DMA_PRIO_VERY_HIGH); + if (dir==TRX_RD) flags |= DMA_FROM_PER; // read + else flags |= DMA_FROM_MEM; // write + dma_setup_transfer(DMA2, DMA_STREAM3, DMA_CH4, DMA_SIZE_32BITS, &SDIO->FIFO, buf, NULL, flags); + dma_set_num_transfers(DMA2, DMA_STREAM3, n); + dma_set_fifo_flags(DMA2, DMA_STREAM3, (DMA_FCR_DMDIS | DMA_FCR_FTH_FULL)); // disable direct mode | threshold FULL + dma_clear_isr_bits(DMA2, DMA_STREAM3); + dma_enable(DMA2, DMA_STREAM3); + return true; +} +/*---------------------------------------------------------------------------*/ +static bool dmaTrxEnd(bool multi_block) +{ + if ( !waitDmaStatus() ) { + return sdError(SD_CARD_ERROR_DMA); + } + if ( waitTimeout(isBusyTransferComplete) ) { + if (m_dir==TRX_RD) + return sdError(SD_CARD_ERROR_READ_TIMEOUT); + else + return sdError(SD_CARD_ERROR_WRITE_TIMEOUT); + } + if (multi_block) { + return trxStop(); + } else { + if ( t ) { + Serial.print(", in "); Serial.println(millis()-t); + t = 0; + } + return true; + } +} +//----------------------------------------------------------------------------- +// Read 16 byte CID or CSD register. +static bool readReg16(uint32_t xfertyp, void* data) +{ + uint8_t* d = reinterpret_cast(data); + if (!cardCommand(xfertyp, m_rca)) { + return false; // Caller will set errorCode. + } + *(uint32_t*)(&d[0]) = __builtin_bswap32(SDIO->RESP[0]); + *(uint32_t*)(&d[4]) = __builtin_bswap32(SDIO->RESP[1]); + *(uint32_t*)(&d[8]) = __builtin_bswap32(SDIO->RESP[2]); + *(uint32_t*)(&d[12]) = __builtin_bswap32(SDIO->RESP[3]); + d[15] = 0; + return true; +} +/*---------------------------------------------------------------------------*/ +// Return true if timeout occurs. +static bool yieldTimeout(bool (*fcn)()) { + uint32_t m = millis(); + while (fcn()) { + if ((millis() - m) > BUSY_TIMEOUT_MILLIS) { + return true; + } + yield(); + } + return false; // Caller will set errorCode. +} +/*---------------------------------------------------------------------------*/ +static bool waitDmaStatus(void) +{ + if (yieldTimeout(isBusyDMA)) { + return false; // Caller will set errorCode. + } + return true; +} +/*---------------------------------------------------------------------------*/ +// Return true if timeout occurs. +static bool waitTimeout(bool (*fcn)(void)) { + uint32_t m = millis(); + while (fcn()) { + if ((millis() - m) > BUSY_TIMEOUT_MILLIS) { + return true; + } + delayMicroseconds(1); + } + return false; // Caller will set errorCode. +} + +uint32_t aligned[128]; // temporary buffer for misaligned buffers +//============================================================================= +bool SdioCard::begin(void) +{ + m_initDone = false; + m_errorCode = SD_CARD_ERROR_NONE; + m_highCapacity = false; + m_version2 = false; + +#if USE_DEBUG_MODE +pinMode(DBG_PIN, OUTPUT); +digitalWrite(DBG_PIN, HIGH); +delay(100); +#endif + // initialize controller. + initSDHC(); + + if (!cardCommand(CMD0_XFERTYP, 0)) { + return sdError(SD_CARD_ERROR_CMD0); + } + // Try several times for case of reset delay. + for (uint32_t i = 0; i < CMD8_RETRIES; i++) { + if (cardCommand(CMD8_XFERTYP, 0X1AA)) { + if (SDIO->RESP[0] != 0X1AA) { + return sdError(SD_CARD_ERROR_CMD8); + } + m_version2 = true; + break; + } + } + uint32_t arg = m_version2 ? 0X40300000 : 0x00300000; + uint32_t m = millis(); + do { + if (!cardAcmd(0, ACMD41_XFERTYP, arg) || + ((millis() - m) > BUSY_TIMEOUT_MILLIS)) { + return sdError(SD_CARD_ERROR_ACMD41); + } + } while ((SDIO->RESP[0] & 0x80000000) == 0); + + m_ocr = SDIO->RESP[0]; + if (m_ocr & 0x40000000) { + // Is high capacity. + m_highCapacity = true; + } + if (!cardCommand(CMD2_XFERTYP, 0)) { + return sdError(SD_CARD_ERROR_CMD2); + } + if (!cardCommand(CMD3_XFERTYP, 0)) { + return sdError(SD_CARD_ERROR_CMD3); + } + m_rca = SDIO->RESP[0] & 0xFFFF0000; + if (!readReg16(CMD9_XFERTYP, &m_csd)) { + return sdError(SD_CARD_ERROR_CMD9); + } + if (!readReg16(CMD10_XFERTYP, &m_cid)) { + return sdError(SD_CARD_ERROR_CMD10); + } + if (!cardCommand(CMD7_XFERTYP, m_rca)) { + return sdError(SD_CARD_ERROR_CMD7); + } + // Set card to bus width four. + if (!cardAcmd(m_rca, ACMD6_XFERTYP, 2)) { + return sdError(SD_CARD_ERROR_ACMD6); + } + sdio_set_dbus_width(SDIO_CLKCR_WIDBUS_4BIT); + + // Determine if High Speed mode is supported and set frequency. + uint8_t status[64]; + // see "Physical Layer Simplified Specification Version 6.00", chapter 4.3.10, Table 4-13. + // Support Bits of Functions in Function Group 1: bits 415:400, which are bytes [12][13] + // Function Selection of Function Group 1: bits 379:376, which is low nibble of byte [16] + if (cardCMD6(0X00FFFFFF, status) && (2 & status[13]) && + cardCMD6(0X80FFFFF1, status) && (status[16] & 0XF) == 1) { + //Serial.println("\n*** 50MHz clock supported ***"); + } else { + _panic("*** Only 25MHz clock supported! ***", 0); + } + + m_sdClkKhz = 24000; + sdio_set_clock(m_sdClkKhz*1000); // set clock to 24MHz + + m_initDone = true; + return true; +} +//----------------------------------------------------------------------------- +uint32_t SdioCard::cardSize(void) { + return sdCardCapacity(&m_csd); +} +/*---------------------------------------------------------------------------*/ +bool SdioCard::erase(uint32_t firstBlock, uint32_t lastBlock) { + // check for single block erase + if (!m_csd.v1.erase_blk_en) { + // erase size mask + uint8_t m = (m_csd.v1.sector_size_high << 1) | m_csd.v1.sector_size_low; + if ((firstBlock & m) != 0 || ((lastBlock + 1) & m) != 0) { + // error card can't erase specified area + return sdError(SD_CARD_ERROR_ERASE_SINGLE_BLOCK); + } + } + if (!m_highCapacity) { + firstBlock <<= 9; + lastBlock <<= 9; + } + if (!cardCommand(CMD32_XFERTYP, firstBlock)) { + return sdError(SD_CARD_ERROR_CMD32); + } + if (!cardCommand(CMD33_XFERTYP, lastBlock)) { + return sdError(SD_CARD_ERROR_CMD33); + } + if (!cardCommand(CMD38_XFERTYP, 0)) { + return sdError(SD_CARD_ERROR_CMD38); + } + if (waitTimeout(isBusyCMD13)) { + return sdError(SD_CARD_ERROR_ERASE_TIMEOUT); + } + return true; +} +//----------------------------------------------------------------------------- +uint8_t SdioCard::errorCode() { + return m_errorCode; +} +//----------------------------------------------------------------------------- +uint32_t SdioCard::errorData() { + return m_irqstat; +} +//----------------------------------------------------------------------------- +uint32_t SdioCard::errorLine() { + return m_errorLine; +} +//----------------------------------------------------------------------------- +bool SdioCard::isBusy() { + return m_busyFcn ? m_busyFcn() : m_initDone && isBusyCMD13(); +} +//----------------------------------------------------------------------------- +uint32_t SdioCard::kHzSdClk() { + return m_sdClkKhz; +} +/*---------------------------------------------------------------------------*/ +bool SdioCard::readBlock(uint32_t lba, uint8_t* buf) +{ + // prepare SDIO and DMA for data read transfer + dmaTrxStart((uint32_t)buf & 3 ? (uint8_t*)aligned : buf, 512, TRX_RD); + // send command to start data transfer + if ( !cardCommand(CMD17_XFERTYP, (m_highCapacity ? lba : 512*lba)) ) { + return sdError(SD_CARD_ERROR_CMD17); + } + if ( dmaTrxEnd(0)) { + if ( (uint32_t)buf & 3 ) { + //memcpy(buf, aligned, 512); + register uint8_t * dst = buf; + register uint8_t * src = (uint8_t *)aligned; + register uint16_t i = 64; + while ( i-- ) { // do 8 byte copies, is much faster than single byte copy + *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; + *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; + } + } + return true; + } + return false; +} +/*---------------------------------------------------------------------------*/ +bool SdioCard::readBlocks(uint32_t lba, uint8_t* buf, size_t n) +{ + if ((uint32_t)buf & 3) { + for (size_t i = 0; i < n; i++, lba++, buf += 512) { + if (!readBlock(lba, buf)) { + return false; // readBlock will set errorCode. + } + } + return true; + } + // prepare SDIO and DMA for data read transfer + dmaTrxStart(buf, 512*n, TRX_RD); + // send command to start data transfer + if ( !cardCommand(CMD18_XFERTYP, (m_highCapacity ? lba : 512*lba)) ) { + return sdError(SD_CARD_ERROR_CMD18); + } + return dmaTrxEnd(1); +} +//----------------------------------------------------------------------------- +bool SdioCard::readCID(void* cid) { + memcpy(cid, &m_cid, 16); + return true; +} +//----------------------------------------------------------------------------- +bool SdioCard::readCSD(void* csd) { + memcpy(csd, &m_csd, 16); + return true; +} +/*---------------------------------------------------------------------------*/ +bool SdioCard::readData(uint8_t *dst) +{ + //Serial.print("readData: "); Serial.print(m_lba); Serial.print(", m_cnt: "); Serial.println(m_cnt); + if ( m_cnt==0 ) return false; + if (yieldTimeout(isBusyCMD13)) { // wait for previous transmission end + return sdError(SD_CARD_ERROR_CMD13); + } + // non-DMA block read + trxStart(dst, 512, TRX_RD); + // send command to start data transfer + if ( !cardCommand(CMD17_XFERTYP, (m_highCapacity ? m_lba : 512*m_lba)) ) { + return sdError(SD_CARD_ERROR_CMD17); + } + // Receive a data block from the SDIO + register uint32_t STA; // to speed up SDIO flags checking + register uint16_t cnt = 512; + register uint32_t * ptr = (uint32_t *)dst; + // ----> TIME CRITICAL SECTION BEGIN <---- + do { + STA = SDIO->STA; + if (STA & SDIO_STA_RXFIFOHF) { + // Receive FIFO half full, there are at least 8 words in it + noInterrupts(); + *ptr++ = SDIO->FIFO; *ptr++ = SDIO->FIFO; *ptr++ = SDIO->FIFO; *ptr++ = SDIO->FIFO; + *ptr++ = SDIO->FIFO; *ptr++ = SDIO->FIFO; *ptr++ = SDIO->FIFO; *ptr++ = SDIO->FIFO; + interrupts(); + cnt -= 8; + } + } while ( !(STA & (SDIO_STA_DATAEND | SDIO_STA_TRX_ERROR_FLAGS)) ); + // <---- TIME CRITICAL SECTION END ----> + + // read data still available in FIFO + while ( (SDIO->STA & SDIO_STA_RXDAVL) && (cnt--) ) { + *ptr++ = SDIO->FIFO; + } + // check error, temporary stuff, remove for final version + if ( SDIO->STA & SDIO_STA_TRX_ERROR_FLAGS ) { + _panic("ERROR: non-DMA read error ", SDIO->STA); + return false; + } + m_lba++; + m_cnt--; + return !(SDIO->STA&SDIO_STA_TRX_ERROR_FLAGS); +} +//----------------------------------------------------------------------------- +bool SdioCard::readOCR(uint32_t* ocr) { + *ocr = m_ocr; + return true; +} +//----------------------------------------------------------------------------- +bool SdioCard::readStart(uint32_t lba) +{ + m_lba = lba; + m_cnt = 1024; + return true; +} +/*---------------------------------------------------------------------------*/ +// SDHC will do Auto CMD12 after count blocks. +bool SdioCard::readStart(uint32_t lba, uint32_t count) +{ + //Serial.print("readStart: "); Serial.print(lba); Serial.print(", cnt: "); Serial.println(count); + m_lba = lba; + m_cnt = count; + return true; +} +/*---------------------------------------------------------------------------*/ +bool SdioCard::readStop() +{ + //Serial.println("readStop."); + m_lba = 0; + m_cnt = 0; + return true; +} +//----------------------------------------------------------------------------- +bool SdioCard::syncBlocks() { + return true; +} +//----------------------------------------------------------------------------- +uint8_t SdioCard::type() { + return m_version2 ? m_highCapacity ? + SD_CARD_TYPE_SDHC : SD_CARD_TYPE_SD2 : SD_CARD_TYPE_SD1; +} +/*---------------------------------------------------------------------------*/ +bool SdioCard::writeBlock(uint32_t lba, const uint8_t* buf) +{ + uint8_t * ptr = (uint8_t *)buf; + if (3 & (uint32_t)ptr) { + //Serial.print("writeBlock: "); Serial.print(lba); + Serial.print(", buf: "); Serial.print((uint32_t)ptr, HEX); + //memcpy(aligned, buf, 512); + register uint8_t * src = (uint8_t *)ptr; + ptr = (uint8_t *)aligned; + register uint8_t * dst = ptr; + register uint16_t i = 64; + while ( i-- ) { // do 8 byte copies, is much faster than single byte copy + *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; + *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; + } + } + if (yieldTimeout(isBusyCMD13)) { // wait for previous transmission end + return sdError(SD_CARD_ERROR_CMD13); + } + // send command to start data transfer + if ( !cardCommand(CMD24_XFERTYP, (m_highCapacity ? lba : 512*lba)) ) { + return sdError(SD_CARD_ERROR_CMD24); + } + // prepare SDIO and DMA for data transfer + dmaTrxStart(ptr, 512, TRX_WR); // 1 block, write transfer + + return dmaTrxEnd(0); +} +/*---------------------------------------------------------------------------*/ +bool SdioCard::writeBlocks(uint32_t lba, const uint8_t* buf, size_t n) +{ + if (3 & (uint32_t)buf) { // misaligned buffer address, write single blocks + for (size_t i = 0; i < n; i++, lba++, buf += 512) { + if (!writeBlock(lba, buf)) { + return false; // writeBlock will set errorCode. + } + } + return true; + } + //Serial.print("writeBlocks: "); Serial.print(lba); Serial.print(", "); Serial.print(n); + if (yieldTimeout(isBusyCMD13)) { + return sdError(SD_CARD_ERROR_CMD13); + } +#if 0 + // set number of blocks to write - this can speed up block write + if ( !cardAcmd(m_rca, ACMD23_XFERTYP, n) ) { + return sdError(SD_CARD_ERROR_ACMD23); + } +#endif + // send command to start data transfer + if ( !cardCommand(CMD25_XFERTYP, (m_highCapacity ? lba : 512*lba)) ) { + return sdError(SD_CARD_ERROR_CMD25); + } + // prepare SDIO and DMA for data transfer + dmaTrxStart((uint8_t *)buf, 512*n, TRX_WR); // n blocks, write transfer + + return dmaTrxEnd(1); +} +/*---------------------------------------------------------------------------*/ +bool SdioCard::writeData(const uint8_t* src) +{ + //Serial.print("writeData: "); Serial.print(m_lba); Serial.print(", cnt: "); Serial.println(m_cnt); + if ( !m_cnt ) return false; + if (yieldTimeout(isBusyCMD13)) { // wait for previous transmission end + return sdError(SD_CARD_ERROR_CMD13); + } + // send command to start block data transfer + if ( !cardCommand(CMD24_XFERTYP, (m_highCapacity ? m_lba : 512*m_lba)) ) { + return sdError(SD_CARD_ERROR_CMD24); + } + // non-DMA block write + trxStart((uint8_t*)src, 512, TRX_WR); + // Receive a data block from the SDIO + register uint32_t STA; // to speed up SDIO flags checking + register uint16_t cnt = 512; + register uint32_t * ptr = (uint32_t*)src; + // pre-fill up the FIFO with 32 words + noInterrupts(); + while ( (cnt--)>(512-32) ) SDIO->FIFO = *ptr++; + interrupts(); + // ----> TIME CRITICAL SECTION BEGIN <---- + do { + STA = SDIO->STA; + if (STA & SDIO_STA_TXFIFOHE) { + // Transmit FIFO half empty, fill up the remaining 16 words + noInterrupts(); + SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++; + SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++; + SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++; + SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++; + interrupts(); + cnt -= 16; + } + } while ( !(STA & (SDIO_STA_DATAEND | SDIO_STA_TRX_ERROR_FLAGS)) && cnt); + // <---- TIME CRITICAL SECTION END ----> + if ( waitTimeout(isBusyTransferComplete) ) { + return sdError(SD_CARD_ERROR_WRITE_TIMEOUT); + } + m_lba++; + m_cnt--; + if (SDIO->STA&SDIO_STA_TRX_ERROR_FLAGS) { + _panic("writeData error: ", SDIO->STA); + } + return !(SDIO->STA&SDIO_STA_TRX_ERROR_FLAGS); +} +//----------------------------------------------------------------------------- +bool SdioCard::writeStart(uint32_t lba) +{ + m_lba = lba; + m_cnt = 1024; + return true; +} +/*---------------------------------------------------------------------------*/ +// SDHC will do Auto CMD12 after count blocks. +bool SdioCard::writeStart(uint32_t lba, uint32_t count) +{ + //Serial.print("writeStart: "); Serial.print(lba); Serial.print(", cnt: "); Serial.println(count); + m_lba = lba; + m_cnt = count; + return true; +} +/*---------------------------------------------------------------------------*/ +bool SdioCard::writeStop() +{ + //Serial.println("writeStop."); + m_lba = 0; + m_cnt = 0; + return true; +} diff --git a/STM32F4/libraries/SDIO/SdioF4.h b/STM32F4/libraries/SDIO/SdioF4.h new file mode 100644 index 0000000..c995b1c --- /dev/null +++ b/STM32F4/libraries/SDIO/SdioF4.h @@ -0,0 +1,7 @@ + +#ifndef _SDIOF4_H_ +#define _SDIOF4_H_ + +#include + +#endif From 8af6002812e15379ac75e1494558a894ed24970b Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Mon, 19 Jun 2017 17:11:04 +1000 Subject: [PATCH 089/351] Added link to gitter chat room in the readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 019cb2b..b6c60f6 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,8 @@ This repo contains, the "Hardware" files to support STM32 based boards on Arduin ***PRIMARY SUPPORT FORUM: http://www.stm32duino.com/*** +*** We are also on Gitter https://gitter.im/stm32duino/Lobby *** + ##Background & Support: * Based on https://github.com/bobc/maple-asp, which is in turn based on LibMaple by Leaflabs * **Please read the wiki (https://github.com/rogerclarkmelbourne/Arduino_STM32/wiki) for full details** From 6fa060c05a702f5d68c4c63752cdb2911b0764b1 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Mon, 19 Jun 2017 17:11:31 +1000 Subject: [PATCH 090/351] Updated readme for gitter (again) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b6c60f6..b77db01 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ This repo contains, the "Hardware" files to support STM32 based boards on Arduin ***PRIMARY SUPPORT FORUM: http://www.stm32duino.com/*** -*** We are also on Gitter https://gitter.im/stm32duino/Lobby *** +***We are also on Gitter https://gitter.im/stm32duino/Lobby/*** ##Background & Support: * Based on https://github.com/bobc/maple-asp, which is in turn based on LibMaple by Leaflabs From b7fb21aa0ca9a3a679233ee403d4ae2e88ccc300 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Tue, 20 Jun 2017 18:33:00 +0200 Subject: [PATCH 091/351] make USB serial Tx blocking (bugfix for lost TX characters) --- STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.c b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.c index 28a2d1f..bc43747 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.c +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.c @@ -25,7 +25,6 @@ /* Includes ------------------------------------------------------------------*/ #include "usbd_cdc_vcp.h" -//#include "stm32f4_discovery.h" /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ @@ -57,7 +56,7 @@ uint8_t UsbRecBuffer[UsbRecBufferSize]; volatile int UsbRecRead = 0; volatile int UsbRecWrite = 0; volatile int VCP_DTRHIGH = 0; -uint8_t UsbTXBlock = 0; +uint8_t UsbTXBlock = 1; uint32_t VCPBytesAvailable(void) { return (UsbRecWrite - UsbRecRead + UsbRecBufferSize) % UsbRecBufferSize; From d872cb1963b39384c7344a1229179f59a09a2c17 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Tue, 20 Jun 2017 18:50:23 +0200 Subject: [PATCH 092/351] avoid multiple USB serial begin (taken from F1) --- STM32F4/cores/maple/usb_serial.cpp | 7 ++++++- STM32F4/cores/maple/usb_serial.h | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/STM32F4/cores/maple/usb_serial.cpp b/STM32F4/cores/maple/usb_serial.cpp index fadcb91..1764e86 100644 --- a/STM32F4/cores/maple/usb_serial.cpp +++ b/STM32F4/cores/maple/usb_serial.cpp @@ -36,20 +36,25 @@ #ifdef SERIAL_USB #define USB_TIMEOUT 50 +bool USBSerial::_hasBegun = false; USBSerial::USBSerial(void) { } void USBSerial::begin(void) { + if (_hasBegun) + return; + _hasBegun = true; setupUSB(); } void USBSerial::begin(int) { - setupUSB(); + this->begin(); } void USBSerial::end(void) { disableUSB(); + _hasBegun = false; } size_t USBSerial::write(uint8 ch) { diff --git a/STM32F4/cores/maple/usb_serial.h b/STM32F4/cores/maple/usb_serial.h index 8eeed96..2288025 100644 --- a/STM32F4/cores/maple/usb_serial.h +++ b/STM32F4/cores/maple/usb_serial.h @@ -65,6 +65,9 @@ public: void enableBlockingTx(void); void disableBlockingTx(void); + +protected: + static bool _hasBegun; }; extern USBSerial SerialUSB; From f6dea1e50efa6694b9ccc577fb6b4103a7fa9272 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Tue, 20 Jun 2017 21:03:18 +0200 Subject: [PATCH 093/351] added CCMRAM definitions --- STM32F4/variants/generic_f407v/ld/common.inc | 9 +++++++++ STM32F4/variants/generic_f407v/ld/jtag.ld | 5 +++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/STM32F4/variants/generic_f407v/ld/common.inc b/STM32F4/variants/generic_f407v/ld/common.inc index f5a0f5b..30c49c2 100644 --- a/STM32F4/variants/generic_f407v/ld/common.inc +++ b/STM32F4/variants/generic_f407v/ld/common.inc @@ -183,6 +183,15 @@ SECTIONS } > REGION_BSS /* + * .ccmram + */ + .ccmram (NOLOAD): + { + . = ALIGN(8); + *(.ccmram .ccmram.*) + } > ccmram + + /* * Debugging sections */ .stab 0 (NOLOAD) : { *(.stab) } diff --git a/STM32F4/variants/generic_f407v/ld/jtag.ld b/STM32F4/variants/generic_f407v/ld/jtag.ld index 1001db5..2156f15 100644 --- a/STM32F4/variants/generic_f407v/ld/jtag.ld +++ b/STM32F4/variants/generic_f407v/ld/jtag.ld @@ -5,8 +5,9 @@ MEMORY { - ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K - rom (rx) : ORIGIN = 0x08000000, LENGTH = 512K + ccmram (rw): ORIGIN = 0x10000000, LENGTH = 64K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K + rom (rx) : ORIGIN = 0x08000000, LENGTH = 512K } /* GROUP(libcs3_stm32_high_density.a) */ From 747634a31acd6b1aca33a8fdd9160e5a557dd6c6 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Sat, 24 Jun 2017 17:23:54 +1000 Subject: [PATCH 094/351] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b77db01..7e13786 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ This repo contains, the "Hardware" files to support STM32 based boards on Arduin ***PRIMARY SUPPORT FORUM: http://www.stm32duino.com/*** ***We are also on Gitter https://gitter.im/stm32duino/Lobby/*** +[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/stm32duino/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) ##Background & Support: * Based on https://github.com/bobc/maple-asp, which is in turn based on LibMaple by Leaflabs From f7a576f2e0efcee958bdfd737d9af7a2f6c76051 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Sun, 25 Jun 2017 13:08:30 +1000 Subject: [PATCH 095/351] Fixed issue with PB10 being set to OUTPUT for use as a USB Disconnect control on boards which do not have the additional USB disconnect hardware e.g. the Blue Pill. Note. Some variants seem to have the disconnect control on another pin, so I did not change those in case they were actually used --- .../cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c | 15 +++++++++++---- STM32F1/variants/generic_gd32f103c/board/board.h | 4 ++-- STM32F1/variants/generic_stm32f103c/board/board.h | 4 ++-- .../variants/generic_stm32f103r8/board/board.h | 4 ++-- STM32F1/variants/nucleo_f103rb/board/board.h | 7 ++----- 5 files changed, 19 insertions(+), 15 deletions(-) diff --git a/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c b/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c index 7a5a772..774be42 100644 --- a/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c +++ b/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c @@ -384,9 +384,13 @@ void usb_cdcacm_enable(gpio_dev *disc_dev, uint8 disc_bit) { /* Present ourselves to the host. Writing 0 to "disc" pin must * pull USB_DP pin up while leaving USB_DM pulled down by the * transceiver. See USB 2.0 spec, section 7.1.7.3. */ - gpio_set_mode(disc_dev, disc_bit, GPIO_OUTPUT_PP); - gpio_write_bit(disc_dev, disc_bit, 0); - + + if (disc_dev!=NULL) + { + gpio_set_mode(disc_dev, disc_bit, GPIO_OUTPUT_PP); + gpio_write_bit(disc_dev, disc_bit, 0); + } + /* Initialize the USB peripheral. */ usb_init_usblib(USBLIB, ep_int_in, ep_int_out); } @@ -395,7 +399,10 @@ void usb_cdcacm_disable(gpio_dev *disc_dev, uint8 disc_bit) { /* Turn off the interrupt and signal disconnect (see e.g. USB 2.0 * spec, section 7.1.7.3). */ nvic_irq_disable(NVIC_USB_LP_CAN_RX0); - gpio_write_bit(disc_dev, disc_bit, 1); + if (disc_dev!=NULL) + { + gpio_write_bit(disc_dev, disc_bit, 1); + } } void usb_cdcacm_putc(char ch) { diff --git a/STM32F1/variants/generic_gd32f103c/board/board.h b/STM32F1/variants/generic_gd32f103c/board/board.h index 50dd989..16295a1 100644 --- a/STM32F1/variants/generic_gd32f103c/board/board.h +++ b/STM32F1/variants/generic_gd32f103c/board/board.h @@ -70,8 +70,8 @@ #define BOARD_JTDO_PIN 19 #define BOARD_NJTRST_PIN 18 -#define BOARD_USB_DISC_DEV GPIOB -#define BOARD_USB_DISC_BIT 10 +#define BOARD_USB_DISC_DEV NULL +#define BOARD_USB_DISC_BIT NULL // Note this needs to match with the PIN_MAP array in board.cpp enum { diff --git a/STM32F1/variants/generic_stm32f103c/board/board.h b/STM32F1/variants/generic_stm32f103c/board/board.h index 09351a6..4736dc9 100644 --- a/STM32F1/variants/generic_stm32f103c/board/board.h +++ b/STM32F1/variants/generic_stm32f103c/board/board.h @@ -70,8 +70,8 @@ #define BOARD_JTDO_PIN 19 #define BOARD_NJTRST_PIN 18 -#define BOARD_USB_DISC_DEV GPIOB -#define BOARD_USB_DISC_BIT 10 +#define BOARD_USB_DISC_DEV NULL +#define BOARD_USB_DISC_BIT NULL #define LED_BUILTIN PC13 diff --git a/STM32F1/variants/generic_stm32f103r8/board/board.h b/STM32F1/variants/generic_stm32f103r8/board/board.h index c274d64..36c2241 100644 --- a/STM32F1/variants/generic_stm32f103r8/board/board.h +++ b/STM32F1/variants/generic_stm32f103r8/board/board.h @@ -70,8 +70,8 @@ #define BOARD_JTDO_PIN 19 #define BOARD_NJTRST_PIN 18 -#define BOARD_USB_DISC_DEV GPIOB -#define BOARD_USB_DISC_BIT 10 +#define BOARD_USB_DISC_DEV NULL +#define BOARD_USB_DISC_BIT NULL // Note this needs to match with the PIN_MAP array in board.cpp enum { diff --git a/STM32F1/variants/nucleo_f103rb/board/board.h b/STM32F1/variants/nucleo_f103rb/board/board.h index b27862d..5c7ece7 100644 --- a/STM32F1/variants/nucleo_f103rb/board/board.h +++ b/STM32F1/variants/nucleo_f103rb/board/board.h @@ -102,11 +102,8 @@ /** * Note: there is no USB in this board. */ - // Roger Clark. These USB disconnect pin definitions have been added as a temporary fix in order that the this board compiles - // following changes to add usb serial to other boards - // I will remove them when the code in the core usb_serial.cpp has been tidied up so that they are no longer needed. -#define BOARD_USB_DISC_DEV GPIOB -#define BOARD_USB_DISC_BIT 10 +#define BOARD_USB_DISC_DEV NULL +#define BOARD_USB_DISC_BIT NULL /* Pin aliases: these give the GPIO port/bit for each pin as an * enum. These are optional, but recommended. They make it easier to From 80339e6073d25b58ce0c8dbc0d7c5bbabb8a441f Mon Sep 17 00:00:00 2001 From: "U-MarquisSeven\\Brandon" Date: Mon, 26 Jun 2017 18:57:49 -0500 Subject: [PATCH 096/351] checking out work from master --- STM32F1/libraries/Wire/HardWire.cpp | 6 +++++- STM32F1/libraries/Wire/HardWire.h | 1 + STM32F1/libraries/Wire/Wire.cpp | 22 ++++++++++++++++++++-- STM32F1/libraries/Wire/Wire.h | 8 +++++++- STM32F1/libraries/Wire/WireBase.cpp | 8 ++++++-- STM32F1/libraries/Wire/WireBase.h | 2 ++ 6 files changed, 41 insertions(+), 6 deletions(-) diff --git a/STM32F1/libraries/Wire/HardWire.cpp b/STM32F1/libraries/Wire/HardWire.cpp index 1f3ebf2..d81f584 100644 --- a/STM32F1/libraries/Wire/HardWire.cpp +++ b/STM32F1/libraries/Wire/HardWire.cpp @@ -38,7 +38,7 @@ #include "HardWire.h" -uint8 HardWire::process() { +uint8 HardWire::process(uint8 stop) { int8 res = i2c_master_xfer(sel_hard, &itc_msg, 1, 0); if (res == I2C_ERROR_PROTOCOL) { if (sel_hard->error_flags & I2C_SR1_AF) { /* NACK */ @@ -55,6 +55,10 @@ uint8 HardWire::process() { return res; } +uint8 HardWire::process(){ + return process(true); +} + // TODO: Add in Error Handling if devsel is out of range for other Maples HardWire::HardWire(uint8 dev_sel, uint8 flags) { if (dev_sel == 1) { diff --git a/STM32F1/libraries/Wire/HardWire.h b/STM32F1/libraries/Wire/HardWire.h index 6f30cb3..bf59a2f 100644 --- a/STM32F1/libraries/Wire/HardWire.h +++ b/STM32F1/libraries/Wire/HardWire.h @@ -52,6 +52,7 @@ protected: * Processes the incoming I2C message defined by WireBase to the * hardware. If an error occured, restart the I2C device. */ + uint8 process(uint8); uint8 process(); public: /* diff --git a/STM32F1/libraries/Wire/Wire.cpp b/STM32F1/libraries/Wire/Wire.cpp index 01ee72f..8e8d3e5 100644 --- a/STM32F1/libraries/Wire/Wire.cpp +++ b/STM32F1/libraries/Wire/Wire.cpp @@ -40,6 +40,9 @@ * Updated by Roger Clark. 20141111. Fixed issue when process() returned because of missing ACK (often caused by invalid device address being used), caused SCL to be left * LOW so that in the next call to process() , the first clock pulse was not sent, because SCL was LOW when it should have been high. */ + /* + * Updated by Brandon Green. 20172306. Implementing the repeated stop functionality. + */ #include "Wire.h" @@ -76,6 +79,12 @@ void TwoWire::i2c_stop() { set_sda(HIGH); } +void TwoWire::i2c_repeated_start() { + set_sda(HIGH); + set_scl(HIGH); + set_sda(LOW); +} + bool TwoWire::i2c_get_ack() { set_scl(LOW); set_sda(HIGH); @@ -121,7 +130,8 @@ void TwoWire::i2c_shift_out(uint8 val) { } } -uint8 TwoWire::process() { +//process needs to be updated for repeated start. +uint8 TwoWire::process(uint8 stop) { itc_msg.xferred = 0; uint8 sla_addr = (itc_msg.addr << 1); @@ -162,10 +172,18 @@ uint8 TwoWire::process() { itc_msg.xferred++; } } - i2c_stop(); + if(stop == true) + i2c_stop(); + else i2c_repeated_start(); + return SUCCESS; } +// For compatibility with legacy code +uint8 TwoWire::process(){ + return process(true); +} + // TODO: Add in Error Handling if pins is out of range for other Maples // TODO: Make delays more capable TwoWire::TwoWire(uint8 scl, uint8 sda, uint8 delay) : i2c_delay(delay) { diff --git a/STM32F1/libraries/Wire/Wire.h b/STM32F1/libraries/Wire/Wire.h index c7edfef..df474da 100644 --- a/STM32F1/libraries/Wire/Wire.h +++ b/STM32F1/libraries/Wire/Wire.h @@ -86,7 +86,12 @@ class TwoWire : public WireBase { * Creates a Stop condition on the bus */ void i2c_stop(); - + + /* + * Created a Repeated Start condition on the bus + */ + void i2c_repeated_start(); + /* * Gets an ACK condition from a slave device on the bus */ @@ -119,6 +124,7 @@ class TwoWire : public WireBase { /* * Processes the incoming I2C message defined by WireBase */ + uint8 process(uint8); uint8 process(); public: /* diff --git a/STM32F1/libraries/Wire/WireBase.cpp b/STM32F1/libraries/Wire/WireBase.cpp index ff0dae3..73d0398 100644 --- a/STM32F1/libraries/Wire/WireBase.cpp +++ b/STM32F1/libraries/Wire/WireBase.cpp @@ -59,17 +59,21 @@ void WireBase::beginTransmission(int slave_address) { beginTransmission((uint8)slave_address); } -uint8 WireBase::endTransmission(void) { +uint8 WireBase::endTransmission(uint8 stop) { uint8 retVal; if (tx_buf_overflow) { return EDATA; } - retVal = process();// Changed so that the return value from process is returned by this function see also the return line below + retVal = process(stop);// Changed so that the return value from process is returned by this function see also the return line below tx_buf_idx = 0; tx_buf_overflow = false; return retVal;//SUCCESS; } +uint8 WireBase::endTransmission(){ + endTransmission(true); +} + //TODO: Add the ability to queue messages (adding a boolean to end of function // call, allows for the Arduino style to stay while also giving the flexibility // to bulk send diff --git a/STM32F1/libraries/Wire/WireBase.h b/STM32F1/libraries/Wire/WireBase.h index 4e51c0d..4038428 100644 --- a/STM32F1/libraries/Wire/WireBase.h +++ b/STM32F1/libraries/Wire/WireBase.h @@ -65,6 +65,7 @@ protected: boolean tx_buf_overflow; // Force derived classes to define process function + virtual uint8 process(uint8) = 0; virtual uint8 process() = 0; public: WireBase() {} @@ -90,6 +91,7 @@ public: * Call the process function to process the message if the TX * buffer has not overflowed. */ + uint8 endTransmission(uint8); uint8 endTransmission(void); /* From 54044592fb4a05149c6694d429a26b4d3a014626 Mon Sep 17 00:00:00 2001 From: "U-MarquisSeven\\Brandon" Date: Mon, 26 Jun 2017 18:59:33 -0500 Subject: [PATCH 097/351] changing comment --- STM32F1/libraries/Wire/Wire.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/libraries/Wire/Wire.cpp b/STM32F1/libraries/Wire/Wire.cpp index 8e8d3e5..fff850b 100644 --- a/STM32F1/libraries/Wire/Wire.cpp +++ b/STM32F1/libraries/Wire/Wire.cpp @@ -41,7 +41,7 @@ * LOW so that in the next call to process() , the first clock pulse was not sent, because SCL was LOW when it should have been high. */ /* - * Updated by Brandon Green. 20172306. Implementing the repeated stop functionality. + * Updated by Brandon Green. 20172306. Implementing the repeated start functionality. */ #include "Wire.h" From f7440485833c83405dd9396f034f21a53d9ba5a7 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Sun, 2 Jul 2017 15:02:55 +0200 Subject: [PATCH 098/351] include backslashes replaced by slashes --- STM32F4/libraries/SDIO/SdioF4.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/STM32F4/libraries/SDIO/SdioF4.cpp b/STM32F4/libraries/SDIO/SdioF4.cpp index 1d533a0..e32e9f2 100644 --- a/STM32F4/libraries/SDIO/SdioF4.cpp +++ b/STM32F4/libraries/SDIO/SdioF4.cpp @@ -19,8 +19,8 @@ */ #include "SdioF4.h" -#include -#include +#include +#include #include #define USE_DEBUG_MODE 0 From 753d92977ddfec1dba4344ff750c87b207f43210 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Mon, 3 Jul 2017 20:47:25 +0200 Subject: [PATCH 099/351] remove duplicated generic variant --- STM32F4/boards.txt | 37 ------------------------------------- 1 file changed, 37 deletions(-) diff --git a/STM32F4/boards.txt b/STM32F4/boards.txt index 035acc9..8fc1430 100644 --- a/STM32F4/boards.txt +++ b/STM32F4/boards.txt @@ -74,43 +74,6 @@ generic_f407v.menu.usb_cfg.usb_serial.build.cpu_flags=-DSERIAL_USB generic_f407v.menu.usb_cfg.usb_msc=USB Mass Storage (MSC) generic_f407v.menu.usb_cfg.usb_msc.build.cpu_flags=-DUSB_MSC -############################################################## -generic_f407v.name=Generic STM32F407V series - -generic_f407v.upload.tool=stlink_upload -generic_f407v.upload.protocol=stlink - -generic_f407v.upload.file_type=bin -generic_f407v.upload.ram.maximum_size=131072 -generic_f407v.upload.flash.maximum_size=514288 -generic_f407v.upload.maximum_size=514288 - -#generic_f407v.upload.usbID=0483:3748 -#generic_f407v.upload.altID=1 -#generic_f407v.upload.auto_reset=true - -generic_f407v.build.mcu=cortex-m4 -generic_f407v.build.f_cpu=168000000L -generic_f407v.build.core=maple -generic_f407v.build.extra_flags=-mthumb -DSTM32_HIGH_DENSITY -DSTM32F4 -DBOARD_generic_f407v -generic_f407v.build.ldscript=ld/jtag.ld -generic_f407v.build.variant=generic_f407v -generic_f407v.build.variant_system_lib=lib_f407.a -generic_f407v.build.vect=VECT_TAB_BASE -generic_f407v.build.density=STM32_HIGH_DENSITY -generic_f407v.build.error_led_port=GPIOA -generic_f407v.build.error_led_pin=7 -generic_f407v.build.board=STM32GenericF407VET6 - -generic_f407v.menu.usb_cfg.usb_nc=USB inactive -generic_f407v.menu.usb_cfg.usb_nc.build.cpu_flags=-DUSB_NC - -generic_f407v.menu.usb_cfg.usb_serial=USB serial (CDC) -generic_f407v.menu.usb_cfg.usb_serial.build.cpu_flags=-DSERIAL_USB - -generic_f407v.menu.usb_cfg.usb_msc=USB Mass Storage (MSC) -generic_f407v.menu.usb_cfg.usb_msc.build.cpu_flags=-DUSB_MSC - ############################################################## stm32f4stamp.name=STM32F4Stamp F405 From 832f10209075e4ff4f283281a636cd2a263f3f31 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Mon, 3 Jul 2017 20:50:53 +0200 Subject: [PATCH 100/351] bring up in sync with master --- STM32F4/cores/maple/libmaple/dmaF4.h | 73 ------------------- STM32F4/cores/maple/libmaple/fsmc.c | 57 --------------- STM32F4/libraries/SPI/src/SPI.cpp | 1 + STM32F4/system/libmaple/Arduino.h~HEAD | 46 ------------ .../Arduino.h~refs_remotes_origin_master | 46 ------------ 5 files changed, 1 insertion(+), 222 deletions(-) delete mode 100644 STM32F4/system/libmaple/Arduino.h~HEAD delete mode 100644 STM32F4/system/libmaple/Arduino.h~refs_remotes_origin_master diff --git a/STM32F4/cores/maple/libmaple/dmaF4.h b/STM32F4/cores/maple/libmaple/dmaF4.h index 5815f1c..cb23760 100644 --- a/STM32F4/cores/maple/libmaple/dmaF4.h +++ b/STM32F4/cores/maple/libmaple/dmaF4.h @@ -85,12 +85,7 @@ typedef struct dma_reg_map { * Register bit definitions */ -<<<<<<< HEAD:STM32F4/cores/maple/libmaple/dmaF4.h -/* Stream configuration register */ - -======= // Stream configuration register ->>>>>>> refs/remotes/origin/master:STM32F4/cores/maple/libmaple/dmaF4.h #define DMA_CR_CH0 (0x0 << 25) #define DMA_CR_CH1 (0x1 << 25) #define DMA_CR_CH2 (0x2 << 25) @@ -139,9 +134,6 @@ typedef struct dma_reg_map { #define DMA_CR_HTIE (0x1 << 3) #define DMA_CR_TEIE (0x1 << 2) #define DMA_CR_DMEIE (0x1 << 1) -<<<<<<< HEAD:STM32F4/cores/maple/libmaple/dmaF4.h -#define DMA_CR_EN (0x1) -======= #define DMA_CR_EN (0x1 << 0) // Device interrupt status register flags @@ -170,7 +162,6 @@ typedef struct dma_reg_map { #define DMA_FCR_FTH_3_4 (0x2 << 0) // 3/4 full FIFO #define DMA_FCR_FTH_FULL (0x3 << 0) // full FIFO ->>>>>>> refs/remotes/origin/master:STM32F4/cores/maple/libmaple/dmaF4.h typedef enum dma_channel { DMA_CH0 = DMA_CR_CH0, /**< Channel 0 */ @@ -182,21 +173,6 @@ typedef enum dma_channel { DMA_CH6 = DMA_CR_CH6, /**< Channel 6 */ DMA_CH7 = DMA_CR_CH7, /**< Channel 7 */ } dma_channel; -<<<<<<< HEAD:STM32F4/cores/maple/libmaple/dmaF4.h - -/* Device interrupt status register flags */ - -#define DMA_ISR_TCIF (1 << 5) -#define DMA_ISR_HTIF (1 << 4) -#define DMA_ISR_TEIF (1 << 3) -#define DMA_ISR_DMEIF (1 << 2) -#define DMA_ISR_FEIF (1 << 0) - -/* - * Devices - */ -======= ->>>>>>> refs/remotes/origin/master:STM32F4/cores/maple/libmaple/dmaF4.h /** Encapsulates state related to a DMA channel interrupt. */ typedef struct dma_handler_config { @@ -218,29 +194,6 @@ typedef struct dma_dev { /* * Devices */ -<<<<<<< HEAD:STM32F4/cores/maple/libmaple/dmaF4.h - -extern void dma_init(dma_dev *dev); - -/** Flags for DMA transfer configuration. */ -typedef enum dma_mode_flags { - DMA_MEM_BUF_0 = DMA_CR_CT0, /**< Current memory target buffer 0 */ - DMA_MEM_BUF_1 = DMA_CR_CT1, /**< Current memory target buffer 1 */ - DMA_DBL_BUF_MODE = DMA_CR_DBM, /**< Current memory double buffer mode */ - DMA_PINC_OFFSET = DMA_CR_PINCOS, /**< Peripheral increment offset size */ - DMA_MINC_MODE = DMA_CR_MINC, /**< Memory increment mode */ - DMA_PINC_MODE = DMA_CR_PINC, /**< Peripheral increment mode */ - DMA_CIRC_MODE = DMA_CR_CIRC, /**< Memory Circular mode */ - DMA_FROM_PER = DMA_CR_DIR_P2M, /**< Read from memory to peripheral */ - DMA_FROM_MEM = DMA_CR_DIR_M2P, /**< Read from memory to peripheral */ - DMA_MEM_TO_MEM = DMA_CR_DIR_M2M, /**< Read from memory to memory */ - DMA_PERIF_CTRL = DMA_CR_PFCTRL, /**< Peripheral flow controller */ - DMA_PRIO_MEDIUM = DMA_CR_PL_MEDIUM, /**< Medium priority */ - DMA_PRIO_HIGH = DMA_CR_PL_HIGH, /**< High priority */ - DMA_PRIO_VERY_HIGH = DMA_CR_PL_VERY_HIGH, /**< Very high priority */ - DMA_TRNS_CMPLT = DMA_CR_TCIE, /**< Interrupt on transfer completion */ - DMA_TRNS_HALF = DMA_CR_HTIE, /**< Interrupt on half-transfer */ -======= extern dma_dev *DMA1; extern dma_dev *DMA2; @@ -262,22 +215,15 @@ typedef enum dma_mode_flags { DMA_PRIO_VERY_HIGH = DMA_CR_PL_VERY_HIGH, /**< Very high priority */ DMA_TRNS_CMPLT = DMA_CR_TCIE, /**< Interrupt on transfer completion */ DMA_TRNS_HALF = DMA_CR_HTIE, /**< Interrupt on half-transfer */ ->>>>>>> refs/remotes/origin/master:STM32F4/cores/maple/libmaple/dmaF4.h DMA_TRNS_ERR = DMA_CR_TEIE, /**< Interrupt on transfer error */ DMA_DIR_MODE_ERR = DMA_CR_DMEIE /**< Interrupt on direct mode error */ } dma_mode_flags; // Source and destination transfer sizes. typedef enum dma_xfer_size { -<<<<<<< HEAD:STM32F4/cores/maple/libmaple/dmaF4.h - DMA_SIZE_8BITS = ( DMA_CR_MSIZE_8BITS|DMA_CR_PSIZE_8BITS ), /**< 8-bit transfers */ - DMA_SIZE_16BITS = (DMA_CR_MSIZE_16BITS|DMA_CR_PSIZE_16BITS), /**< 16-bit transfers */ - DMA_SIZE_32BITS = (DMA_CR_MSIZE_32BITS|DMA_CR_PSIZE_32BITS) /**< 32-bit transfers */ -======= DMA_SIZE_8BITS = ( DMA_CR_MSIZE_8BITS|DMA_CR_PSIZE_8BITS ), // 8-bit transfers DMA_SIZE_16BITS = (DMA_CR_MSIZE_16BITS|DMA_CR_PSIZE_16BITS), // 16-bit transfers DMA_SIZE_32BITS = (DMA_CR_MSIZE_32BITS|DMA_CR_PSIZE_32BITS) // 32-bit transfers ->>>>>>> refs/remotes/origin/master:STM32F4/cores/maple/libmaple/dmaF4.h } dma_xfer_size; // Source and destination burst sizes. @@ -312,22 +258,14 @@ static inline void dma_setup_transfer(dma_dev *dev, __io void *peripheral_address, __io void *memory_address0, __io void *memory_address1, -<<<<<<< HEAD:STM32F4/cores/maple/libmaple/dmaF4.h - uint32 flags) { -======= uint32 flags) { ->>>>>>> refs/remotes/origin/master:STM32F4/cores/maple/libmaple/dmaF4.h dev->regs->STREAM[stream].CR &= ~DMA_CR_EN; // disable while( (dev->regs->STREAM[stream].CR)&DMA_CR_EN ); // wait till enable bit is cleared dev->regs->STREAM[stream].PAR = (uint32)peripheral_address; dev->regs->STREAM[stream].M0AR = (uint32)memory_address0; dev->regs->STREAM[stream].M1AR = (uint32)memory_address1; -<<<<<<< HEAD:STM32F4/cores/maple/libmaple/dmaF4.h - dev->regs->STREAM[stream].CR = ((flags|channel|trx_size) & 0x0feffffe); // mask out reserved and enable -======= dev->regs->STREAM[stream].CR = (uint32)((flags|channel|trx_size) & 0x0feffffe); // mask out reserved and enable ->>>>>>> refs/remotes/origin/master:STM32F4/cores/maple/libmaple/dmaF4.h } static inline void dma_set_num_transfers(dma_dev *dev, dma_stream stream, uint16 num_transfers) @@ -340,12 +278,6 @@ static inline void dma_set_fifo_flags(dma_dev *dev, dma_stream stream, uint8 fif dev->regs->STREAM[stream].FCR = (uint32)(fifo_flags & 0x87); // mask out reserved bits } -static inline void dma_set_fifo_flags(dma_dev *dev, - dma_stream stream, - uint8 fifo_flags) { - dev->regs->STREAM[stream].FCR = fifo_flags & 0x87; // mask out reserved bits -} - void dma_attach_interrupt(dma_dev *dev, dma_stream stream, void (*handler)(void)); @@ -357,14 +289,9 @@ static inline void dma_enable(dma_dev *dev, dma_stream stream) dev->regs->STREAM[stream].CR |= (uint32)DMA_CR_EN; } -<<<<<<< HEAD:STM32F4/cores/maple/libmaple/dmaF4.h -static inline void dma_disable(dma_dev *dev, dma_stream stream) { - dev->regs->STREAM[stream].CR &= ~DMA_CR_EN; -======= static inline void dma_disable(dma_dev *dev, dma_stream stream) { dev->regs->STREAM[stream].CR &= (uint32)(~DMA_CR_EN); ->>>>>>> refs/remotes/origin/master:STM32F4/cores/maple/libmaple/dmaF4.h while (dev->regs->STREAM[stream].CR & DMA_CR_EN); // wait till EN bit is reset, see AN4031, chapter 4.1 } diff --git a/STM32F4/cores/maple/libmaple/fsmc.c b/STM32F4/cores/maple/libmaple/fsmc.c index 301a855..1e3691a 100644 --- a/STM32F4/cores/maple/libmaple/fsmc.c +++ b/STM32F4/cores/maple/libmaple/fsmc.c @@ -37,62 +37,6 @@ /** * Configure FSMC GPIOs for use with LCDs. */ -<<<<<<< HEAD -void fsmc_sram_init_gpios(void) { - /* Data lines... */ - gpio_set_mode(PD0, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PD1, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PD8, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PD9, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PD10, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PD14, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PD15, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PE7, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PE8, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PE9, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PE10, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PE11, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PE12, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PE13, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PE14, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PE15, GPIO_AF_OUTPUT_PP); - - /* Address lines... */ - gpio_set_mode(PD11, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PD12, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PD13, GPIO_AF_OUTPUT_PP); -#if 0 // not available on LQFP package - gpio_set_mode(GPIOF, 0, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOF, 1, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOF, 2, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOF, 3, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOF, 4, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOF, 5, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOF, 12, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOF, 13, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOF, 14, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOF, 15, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOG, 0, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOG, 1, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOG, 2, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOG, 3, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOG, 4, GPIO_AF_OUTPUT_PP); - gpio_set_mode(GPIOG, 5, GPIO_AF_OUTPUT_PP); -#endif // not available on LQFP package - /* And control lines... */ - gpio_set_mode(PD4, GPIO_AF_OUTPUT_PP); // NOE - gpio_set_mode(PD5, GPIO_AF_OUTPUT_PP); // NWE - - gpio_set_mode(PD7, GPIO_AF_OUTPUT_PP); // NE1 -#if 0 // not available on LQFP package - gpio_set_mode(GPIOG, 9, GPIO_AF_OUTPUT_PP); // NE2 - gpio_set_mode(GPIOG, 10, GPIO_AF_OUTPUT_PP); // NE3 - gpio_set_mode(GPIOG, 12, GPIO_AF_OUTPUT_PP); // NE4 -#endif // not available on LQFP package - - gpio_set_mode(PE0, GPIO_AF_OUTPUT_PP); // NBL0 - gpio_set_mode(PE1, GPIO_AF_OUTPUT_PP); // NBL1 -======= void fsmc_init(void) { rcc_clk_enable(RCC_FSMC); @@ -137,7 +81,6 @@ void fsmc_lcd_init(void) fsmc_nor_psram_set_BTR(FSMC_NOR_PSRAM1_BASE, val); // enable FSCM fsmc_nor_psram_bank_enable(FSMC_NOR_PSRAM1_BASE); ->>>>>>> refs/remotes/origin/master } diff --git a/STM32F4/libraries/SPI/src/SPI.cpp b/STM32F4/libraries/SPI/src/SPI.cpp index eb07c8f..63ed4db 100644 --- a/STM32F4/libraries/SPI/src/SPI.cpp +++ b/STM32F4/libraries/SPI/src/SPI.cpp @@ -460,6 +460,7 @@ uint8 SPIClass::dmaTransfer(void * transmitBuf, void * receiveBuf, uint16 length while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaStream) & DMA_ISR_TCIF)==0 ) {// wait for completion flag to be set if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; } } + 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." // software disable sequence, see AN4031, chapter 4.1 diff --git a/STM32F4/system/libmaple/Arduino.h~HEAD b/STM32F4/system/libmaple/Arduino.h~HEAD deleted file mode 100644 index cef8f08..0000000 --- a/STM32F4/system/libmaple/Arduino.h~HEAD +++ /dev/null @@ -1,46 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 LeafLabs LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -#ifndef _WIRISH_ARDUINO_H_ -#define _WIRISH_ARDUINO_H_ - -//#warning Include Arduino.h from system\libmaple - -#include "wirish.h" - -void setup(); -void loop(); -#ifdef __cplusplus -extern "C"{ -#endif // __cplusplus -void yield(void); -#ifdef __cplusplus -} -#endif // __cplusplus - -#include "variant.h" - -#endif diff --git a/STM32F4/system/libmaple/Arduino.h~refs_remotes_origin_master b/STM32F4/system/libmaple/Arduino.h~refs_remotes_origin_master deleted file mode 100644 index cef8f08..0000000 --- a/STM32F4/system/libmaple/Arduino.h~refs_remotes_origin_master +++ /dev/null @@ -1,46 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 LeafLabs LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -#ifndef _WIRISH_ARDUINO_H_ -#define _WIRISH_ARDUINO_H_ - -//#warning Include Arduino.h from system\libmaple - -#include "wirish.h" - -void setup(); -void loop(); -#ifdef __cplusplus -extern "C"{ -#endif // __cplusplus -void yield(void); -#ifdef __cplusplus -} -#endif // __cplusplus - -#include "variant.h" - -#endif From 66df08b6bb1c6c5559531b5af4994a1b567faf00 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Mon, 3 Jul 2017 20:59:56 +0200 Subject: [PATCH 101/351] update .gitignore --- .gitignore | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitignore b/.gitignore index 6ef9800..078faf6 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,5 @@ other/maple-bootloader/cscope.out other/maple-bootloader/build other/maple-bootloader/*~ *.o -tools/src/stm32flash_serial/src/parsers/parsers.a *.bak *.1 -STM32F4/cores/maple/libmaple/adc.h From 85f8b8237af7f580fbcd823e42d4ba4e9c530b58 Mon Sep 17 00:00:00 2001 From: Testato Date: Tue, 4 Jul 2017 10:05:01 +0200 Subject: [PATCH 102/351] Update boards.txt - Exluded CCM Ram --- STM32F4/boards.txt | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/STM32F4/boards.txt b/STM32F4/boards.txt index 0df9990..60d4fc4 100644 --- a/STM32F4/boards.txt +++ b/STM32F4/boards.txt @@ -11,7 +11,7 @@ discovery_f407.upload.protocol=stlink #discovery_f407.upload.use_1200bps_touch=false discovery_f407.upload.file_type=bin discovery_f407.upload.maximum_size=1048576 -discovery_f407.upload.maximum_data_size=196608 +discovery_f407.upload.maximum_data_size=131072 #discovery_f407.upload.usbID=1EAF:0003 #discovery_f407.upload.altID=1 @@ -43,9 +43,8 @@ generic_f407v.upload.tool=stlink_upload generic_f407v.upload.protocol=stlink generic_f407v.upload.file_type=bin -generic_f407v.upload.ram.maximum_size=131072 -generic_f407v.upload.flash.maximum_size=514288 generic_f407v.upload.maximum_size=514288 +generic_f407v.upload.ram.maximum_size=131072 #generic_f407v.upload.usbID=0483:3748 #generic_f407v.upload.altID=1 @@ -82,7 +81,7 @@ stm32f4stamp.upload.protocol=maple_dfu #stm32f4stamp.upload.use_1200bps_touch=false stm32f4stamp.upload.file_type=bin stm32f4stamp.upload.maximum_size=1048576 -stm32f4stamp.upload.maximum_data_size=196608 +stm32f4stamp.upload.maximum_data_size=131072 stm32f4stamp.upload.usbID=0483:df11 stm32f4stamp.upload.altID=0 @@ -117,7 +116,7 @@ netduino2plus.upload.protocol=maple_dfu #netduino2plus.upload.use_1200bps_touch=false netduino2plus.upload.file_type=bin netduino2plus.upload.maximum_size=1048576 -netduino2plus.upload.maximum_data_size=196608 +netduino2plus.upload.maximum_data_size=131072 netduino2plus.upload.usbID=0483:df11 netduino2plus.upload.altID=0 From 4467592149551b87e2c31f82658feb6f20c108e8 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Tue, 4 Jul 2017 19:11:48 +0200 Subject: [PATCH 103/351] adapt flash and RAM maximum sizes for Arduino --- STM32F4/boards.txt | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/STM32F4/boards.txt b/STM32F4/boards.txt index 8fc1430..514c8a5 100644 --- a/STM32F4/boards.txt +++ b/STM32F4/boards.txt @@ -10,9 +10,8 @@ discovery_f407.upload.protocol=stlink #discovery_f407.upload.use_1200bps_touch=false discovery_f407.upload.file_type=bin -discovery_f407.upload.ram.maximum_size=17000 -discovery_f407.upload.flash.maximum_size=1048576 discovery_f407.upload.maximum_size=1048576 +discovery_f407.upload.maximum_data_size=131072 #discovery_f407.upload.usbID=1EAF:0003 #discovery_f407.upload.altID=1 @@ -44,9 +43,8 @@ generic_f407v.upload.tool=stlink_upload generic_f407v.upload.protocol=stlink generic_f407v.upload.file_type=bin -generic_f407v.upload.ram.maximum_size=131072 -generic_f407v.upload.flash.maximum_size=514288 generic_f407v.upload.maximum_size=514288 +generic_f407v.upload.maximum_data_size=131072 #generic_f407v.upload.usbID=0483:3748 #generic_f407v.upload.altID=1 @@ -82,9 +80,8 @@ stm32f4stamp.upload.protocol=maple_dfu #stm32f4stamp.upload.use_1200bps_touch=false stm32f4stamp.upload.file_type=bin -stm32f4stamp.upload.ram.maximum_size=196608 -stm32f4stamp.upload.flash.maximum_size=1048576 stm32f4stamp.upload.maximum_size=1048576 +stm32f4stamp.upload.maximum_data_size=131072 stm32f4stamp.upload.usbID=0483:df11 stm32f4stamp.upload.altID=0 From 9b30346bfa379df4fd41c4985650a14c674a9c76 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Tue, 4 Jul 2017 19:13:20 +0200 Subject: [PATCH 104/351] default activated SPI class - needed by external libs --- STM32F4/libraries/SPI/src/SPI.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F4/libraries/SPI/src/SPI.cpp b/STM32F4/libraries/SPI/src/SPI.cpp index 63ed4db..45aa366 100644 --- a/STM32F4/libraries/SPI/src/SPI.cpp +++ b/STM32F4/libraries/SPI/src/SPI.cpp @@ -651,4 +651,4 @@ static spi_baud_rate determine_baud_rate(spi_dev *dev, uint32_t freq) { } -//SPIClass SPI(3); +SPIClass SPI(3); // needed for external libs From 597f77ac1d2824ebe369fc33b500cd9358d5d6db Mon Sep 17 00:00:00 2001 From: stevstrong Date: Tue, 4 Jul 2017 19:28:50 +0200 Subject: [PATCH 105/351] replace all backslaches by slashes in include paths --- STM32F4/cores/maple/libmaple/fsmc.h | 2 +- .../Class/audio/inc/usbd_audio_core.h | 2 +- .../Class/cdc/inc/usbd_cdc_core.h | 4 ++-- .../Class/cdc/src/usbd_cdc_core.c | 8 ++++---- .../STM32_USB_Device_Library/Core/inc/usbd_core.h | 2 +- .../usbF4/STM32_USB_Device_Library/Core/inc/usbd_def.h | 2 +- .../usbF4/STM32_USB_Device_Library/Core/inc/usbd_req.h | 2 +- .../STM32_USB_Device_Library/Core/src/usbd_core.c | 10 +++++----- .../STM32_USB_Device_Library/Core/src/usbd_ioreq.c | 2 +- .../usbF4/STM32_USB_Device_Library/Core/src/usbd_req.c | 6 +++--- .../libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_core.h | 2 +- .../usbF4/STM32_USB_OTG_Driver/inc/usb_defines.h | 2 +- .../libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_regs.h | 4 ++-- .../libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_core.c | 4 ++-- .../libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_dcd.c | 4 ++-- .../usbF4/STM32_USB_OTG_Driver/src/usb_dcd_int.c | 4 ++-- STM32F4/cores/maple/libmaple/usbF4/VCP/usb_bsp.c | 2 +- STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.h | 2 +- STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.c | 6 +++--- STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.h | 2 +- STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_usr.c | 4 ++-- STM32F4/cores/maple/libmaple/usbF4/usb.c | 6 +++--- STM32F4/cores/maple/libmaple/usbF4/usb.h | 2 +- STM32F4/system/libmaple/Arduino.h | 1 - STM32F4/variants/discovery_f407/discovery_f4.cpp | 4 ++-- STM32F4/variants/generic_f407v/pin_map.c | 6 +++--- 26 files changed, 47 insertions(+), 48 deletions(-) diff --git a/STM32F4/cores/maple/libmaple/fsmc.h b/STM32F4/cores/maple/libmaple/fsmc.h index 3501583..03a6acf 100644 --- a/STM32F4/cores/maple/libmaple/fsmc.h +++ b/STM32F4/cores/maple/libmaple/fsmc.h @@ -40,7 +40,7 @@ #ifndef _FSMC_H_ #define _FSMC_H_ -#include +#include #include "libmaple_types.h" #ifdef __cplusplus diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/audio/inc/usbd_audio_core.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/audio/inc/usbd_audio_core.h index 7ac987d..69f7ffa 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/audio/inc/usbd_audio_core.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/audio/inc/usbd_audio_core.h @@ -26,7 +26,7 @@ #include "usbd_ioreq.h" #include "usbd_req.h" -#include +#include diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/inc/usbd_cdc_core.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/inc/usbd_cdc_core.h index b1c8cc1..29a38e9 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/inc/usbd_cdc_core.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/inc/usbd_cdc_core.h @@ -24,8 +24,8 @@ #ifndef __USB_CDC_CORE_H_ #define __USB_CDC_CORE_H_ -#include -#include +#include +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/src/usbd_cdc_core.c b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/src/usbd_cdc_core.c index 8f97c51..8963a8a 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/src/usbd_cdc_core.c +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/src/usbd_cdc_core.c @@ -58,10 +58,10 @@ */ /* Includes ------------------------------------------------------------------*/ -#include -#include -#include -#include +#include +#include +#include +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_core.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_core.h index 063a30e..3e4db9b 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_core.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_core.h @@ -26,7 +26,7 @@ /* Includes ------------------------------------------------------------------*/ #include #include "usbd_def.h" -#include +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_def.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_def.h index f2a3115..03a8afc 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_def.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_def.h @@ -24,7 +24,7 @@ #ifndef __USBD_DEF_H #define __USBD_DEF_H /* Includes ------------------------------------------------------------------*/ -#include +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_req.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_req.h index f9849c6..fd3c055 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_req.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/inc/usbd_req.h @@ -27,7 +27,7 @@ /* Includes ------------------------------------------------------------------*/ #include "usbd_def.h" #include "usbd_core.h" -#include +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_core.c b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_core.c index 00bb251..2c5e822 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_core.c +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_core.c @@ -20,11 +20,11 @@ */ /* Includes ------------------------------------------------------------------*/ -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_ioreq.c b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_ioreq.c index 20ee5a0..620b9e5 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_ioreq.c +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_ioreq.c @@ -20,7 +20,7 @@ */ /* Includes ------------------------------------------------------------------*/ -#include +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @{ */ diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_req.c b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_req.c index 5fc2e03..2233d15 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_req.c +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_Device_Library/Core/src/usbd_req.c @@ -20,9 +20,9 @@ */ /* Includes ------------------------------------------------------------------*/ -#include -#include -#include +#include +#include +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_core.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_core.h index 43c4781..dd6a86a 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_core.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_core.h @@ -24,7 +24,7 @@ #define __USB_CORE_H__ /* Includes ------------------------------------------------------------------*/ -#include +#include #include "usb_regs.h" #include "usb_defines.h" diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_defines.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_defines.h index ee2c1a0..546f5ab 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_defines.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_defines.h @@ -24,7 +24,7 @@ #define __USB_DEF_H__ /* Includes ------------------------------------------------------------------*/ -#include +#include /** @addtogroup USB_OTG_DRIVER * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_regs.h b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_regs.h index 99f844e..3038f0d 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_regs.h +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/inc/usb_regs.h @@ -24,8 +24,8 @@ #define __USB_OTG_REGS_H__ /* Includes ------------------------------------------------------------------*/ -#include -#include +#include +#include /** @addtogroup USB_OTG_DRIVER * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_core.c b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_core.c index 1687afa..dd3856f 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_core.c +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_core.c @@ -20,8 +20,8 @@ */ /* Includes ------------------------------------------------------------------*/ -#include -#include +#include +#include /** @addtogroup USB_OTG_DRIVER diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_dcd.c b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_dcd.c index dc9e538..0d23a97 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_dcd.c +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_dcd.c @@ -20,8 +20,8 @@ */ /* Includes ------------------------------------------------------------------*/ -#include -#include +#include +#include /** @addtogroup USB_OTG_DRIVER diff --git a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_dcd_int.c b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_dcd_int.c index f9e561f..fb3bb9d 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_dcd_int.c +++ b/STM32F4/cores/maple/libmaple/usbF4/STM32_USB_OTG_Driver/src/usb_dcd_int.c @@ -20,12 +20,12 @@ */ /* Includes ------------------------------------------------------------------*/ -#include +#include typedef int IRQn_Type; #define __NVIC_PRIO_BITS 4 #define __Vendor_SysTickConfig 1 -#include +#include /** @addtogroup USB_OTG_DRIVER diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/usb_bsp.c b/STM32F4/cores/maple/libmaple/usbF4/VCP/usb_bsp.c index e794cb1..c365038 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/usb_bsp.c +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/usb_bsp.c @@ -21,7 +21,7 @@ */ /* Includes ------------------------------------------------------------------*/ -#include +#include #include "usbd_conf.h" #include typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState; diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.h b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.h index 8398dbd..1ac6c2f 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.h +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_cdc_vcp.h @@ -26,7 +26,7 @@ /* Includes ------------------------------------------------------------------*/ //#include "stm32f4xx.h" -#include +#include #include "usbd_conf.h" diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.c b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.c index 0153858..e37e28c 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.c +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.c @@ -20,11 +20,11 @@ */ /* Includes ------------------------------------------------------------------*/ -#include +#include #include "usbd_desc.h" -#include +#include #include "usbd_conf.h" -#include +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.h b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.h index 4ae998c..987767f 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.h +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_desc.h @@ -25,7 +25,7 @@ #define __USB_DESC_H /* Includes ------------------------------------------------------------------*/ -#include +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @{ diff --git a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_usr.c b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_usr.c index a16ce40..44eef15 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_usr.c +++ b/STM32F4/cores/maple/libmaple/usbF4/VCP/usbd_usr.c @@ -20,8 +20,8 @@ */ /* Includes ------------------------------------------------------------------*/ -#include -#include +#include +#include /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY diff --git a/STM32F4/cores/maple/libmaple/usbF4/usb.c b/STM32F4/cores/maple/libmaple/usbF4/usb.c index 3850719..3e92186 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/usb.c +++ b/STM32F4/cores/maple/libmaple/usbF4/usb.c @@ -4,11 +4,11 @@ #include #include -#include +#include #include "usb.h" #include #include -#include +#include #include USB_OTG_CORE_HANDLE USB_OTG_dev; @@ -96,7 +96,7 @@ RESULT usbPowerOff(void) { void usbDsbISR(void) {}; -#include +#include void __irq_OTG_FS_IRQHandler(void) { USBD_OTG_ISR_Handler (&USB_OTG_dev); diff --git a/STM32F4/cores/maple/libmaple/usbF4/usb.h b/STM32F4/cores/maple/libmaple/usbF4/usb.h index ce1a558..7f0b2aa 100644 --- a/STM32F4/cores/maple/libmaple/usbF4/usb.h +++ b/STM32F4/cores/maple/libmaple/usbF4/usb.h @@ -5,7 +5,7 @@ extern "C" { #endif -#include +#include typedef enum _RESULT { diff --git a/STM32F4/system/libmaple/Arduino.h b/STM32F4/system/libmaple/Arduino.h index cef8f08..d445126 100644 --- a/STM32F4/system/libmaple/Arduino.h +++ b/STM32F4/system/libmaple/Arduino.h @@ -27,7 +27,6 @@ #ifndef _WIRISH_ARDUINO_H_ #define _WIRISH_ARDUINO_H_ -//#warning Include Arduino.h from system\libmaple #include "wirish.h" diff --git a/STM32F4/variants/discovery_f407/discovery_f4.cpp b/STM32F4/variants/discovery_f407/discovery_f4.cpp index 74660f0..7d288d5 100644 --- a/STM32F4/variants/discovery_f407/discovery_f4.cpp +++ b/STM32F4/variants/discovery_f407/discovery_f4.cpp @@ -34,8 +34,8 @@ #include "discovery_f4.h" -#include -#include +#include +#include #include "wirish_types.h" diff --git a/STM32F4/variants/generic_f407v/pin_map.c b/STM32F4/variants/generic_f407v/pin_map.c index 5ecde53..db5247b 100644 --- a/STM32F4/variants/generic_f407v/pin_map.c +++ b/STM32F4/variants/generic_f407v/pin_map.c @@ -39,9 +39,9 @@ extern "C"{ //#include "generic_f407v.h" //#include "fsmc.h" -#include -#include -#include +#include +#include +#include #include From 8f46bf3c9e3a5c575eb9850ad0285d4189514664 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Tue, 4 Jul 2017 20:09:11 +0200 Subject: [PATCH 106/351] remove leaflasb USB CDC ACM warning --- STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c b/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c index 774be42..cba050f 100644 --- a/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c +++ b/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c @@ -62,8 +62,8 @@ #if !(defined(BOARD_maple) || defined(BOARD_maple_RET6) || \ defined(BOARD_maple_mini) || defined(BOARD_maple_native)) -#warning USB CDC ACM relies on LeafLabs board-specific configuration.\ - You may have problems on non-LeafLabs boards. +//#warning USB CDC ACM relies on LeafLabs board-specific configuration.\ +// You may have problems on non-LeafLabs boards. #endif static void vcomDataTxCb(void); From 6fcecec2b02f96791041257850a18fa20d1400c8 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Tue, 4 Jul 2017 20:20:14 +0200 Subject: [PATCH 107/351] remove compiler warning about passing NULL to non-pointer argument --- 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 1fe2bf4..6cffbf5 100644 --- a/STM32F1/cores/maple/usb_serial.cpp +++ b/STM32F1/cores/maple/usb_serial.cpp @@ -71,7 +71,7 @@ void USBSerial::begin(void) { return; _hasBegun = true; - usb_cdcacm_enable(BOARD_USB_DISC_DEV, BOARD_USB_DISC_BIT); + usb_cdcacm_enable(BOARD_USB_DISC_DEV, (uint8_t)BOARD_USB_DISC_BIT); usb_cdcacm_set_hooks(USB_CDCACM_HOOK_RX, rxHook); usb_cdcacm_set_hooks(USB_CDCACM_HOOK_IFACE_SETUP, ifaceSetupHook); #endif @@ -97,7 +97,7 @@ volatile uint8_t removeCompilerWarningsIgnore=ignore; void USBSerial::end(void) { #if BOARD_HAVE_SERIALUSB - usb_cdcacm_disable(BOARD_USB_DISC_DEV, BOARD_USB_DISC_BIT); + usb_cdcacm_disable(BOARD_USB_DISC_DEV, (uint8_t)BOARD_USB_DISC_BIT); usb_cdcacm_remove_hooks(USB_CDCACM_HOOK_RX | USB_CDCACM_HOOK_IFACE_SETUP); _hasBegun = false; #endif From 6f2effadac3d703b45fe4c4cbacba79df544ebfb Mon Sep 17 00:00:00 2001 From: stevstrong Date: Thu, 6 Jul 2017 00:29:45 +0200 Subject: [PATCH 108/351] update SdioF4.cpp - fix for CL4 cards --- STM32F4/libraries/SDIO/SdioF4.cpp | 33 ++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/STM32F4/libraries/SDIO/SdioF4.cpp b/STM32F4/libraries/SDIO/SdioF4.cpp index e32e9f2..63c928a 100644 --- a/STM32F4/libraries/SDIO/SdioF4.cpp +++ b/STM32F4/libraries/SDIO/SdioF4.cpp @@ -24,11 +24,12 @@ #include #define USE_DEBUG_MODE 0 +#define USE_YIELD 0 //============================================================================== //#define SDHC_PROCTL_DTW_4BIT 0x01 #define CMD8_RETRIES 10 -#define BUSY_TIMEOUT_MILLIS 500 +#define BUSY_TIMEOUT_MILLIS 750 //============================================================================== #define CMD_RESP_NONE SDIO_CMD_WAIT_NO_RESP #define CMD_RESP_R1 SDIO_CMD_WAIT_SHORT_RESP // normal response @@ -137,7 +138,8 @@ static void _panic(const char *message, uint32_t code) delay(250); } } -/*=========================================================================== +/*===========================================================================*/ +#if USE_YIELD void yield(void) { uint32_t val = SDIO->STA; @@ -169,7 +171,8 @@ void yield(void) _panic(" - DMA: Data Transmission Error ", val); } //Serial.write('.'); -}*/ +} +#endif //============================================================================= // Error function and macro. inline bool setSdErrorCode(uint8_t code, uint32_t line) { @@ -191,11 +194,11 @@ void sdhc_isr() { //----------------------------------------------------------------------------- static bool cardCommand(uint16_t xfertyp, uint32_t arg) { -#if USE_DEBUG_MODE +#if USE_DEBUG_MODE==2 Serial.print("cardCommand: "); Serial.print(xfertyp&SDIO_CMD_CMDINDEX); Serial.print(", arg: "); Serial.print(arg, HEX); #endif uint8_t resp = sdio_cmd_send(xfertyp, arg); // returns non-zero if fails, zero if OK -#if USE_DEBUG_MODE +#if USE_DEBUG_MODE==2 Serial.print(", resp: "); Serial.print(resp, HEX); Serial.print(", SDIO->STA: "); Serial.print(SDIO->STA, HEX); Serial.print(", cmd_resp: "); Serial.print(SDIO->RESP[0], HEX); if ( (xfertyp&SDIO_CMD_WAIT_LONG_RESP)==SDIO_CMD_WAIT_LONG_RESP ) { @@ -330,6 +333,7 @@ static bool dmaTrxStart(uint8_t* buf, uint32_t n, uint8_t dir) static bool dmaTrxEnd(bool multi_block) { if ( !waitDmaStatus() ) { + DBG_PRINT(); return sdError(SD_CARD_ERROR_DMA); } if ( waitTimeout(isBusyTransferComplete) ) { @@ -536,6 +540,9 @@ uint32_t SdioCard::kHzSdClk() { /*---------------------------------------------------------------------------*/ bool SdioCard::readBlock(uint32_t lba, uint8_t* buf) { +#if USE_DEBUG_MODE + Serial.print("readBlock: "); Serial.println(lba); //Serial.print(", buf: "); Serial.println((uint32_t)buf, HEX); +#endif // prepare SDIO and DMA for data read transfer dmaTrxStart((uint32_t)buf & 3 ? (uint8_t*)aligned : buf, 512, TRX_RD); // send command to start data transfer @@ -560,6 +567,11 @@ bool SdioCard::readBlock(uint32_t lba, uint8_t* buf) /*---------------------------------------------------------------------------*/ bool SdioCard::readBlocks(uint32_t lba, uint8_t* buf, size_t n) { +#if USE_DEBUG_MODE + Serial.print("readBlocks: "); Serial.print(lba); + //Serial.print(", buf: "); Serial.print((uint32_t)buf, HEX); + Serial.print(", "); Serial.println(n); +#endif if ((uint32_t)buf & 3) { for (size_t i = 0; i < n; i++, lba++, buf += 512) { if (!readBlock(lba, buf)) { @@ -672,9 +684,12 @@ uint8_t SdioCard::type() { /*---------------------------------------------------------------------------*/ bool SdioCard::writeBlock(uint32_t lba, const uint8_t* buf) { +#if USE_DEBUG_MODE + Serial.print("writeBlock: "); Serial.println(lba); //Serial.print(", buf: "); Serial.println((uint32_t)buf, HEX); +#endif uint8_t * ptr = (uint8_t *)buf; if (3 & (uint32_t)ptr) { - //Serial.print("writeBlock: "); Serial.print(lba); + Serial.print("writeBlock: "); Serial.print(lba); Serial.print(", buf: "); Serial.print((uint32_t)ptr, HEX); //memcpy(aligned, buf, 512); register uint8_t * src = (uint8_t *)ptr; @@ -701,6 +716,11 @@ bool SdioCard::writeBlock(uint32_t lba, const uint8_t* buf) /*---------------------------------------------------------------------------*/ bool SdioCard::writeBlocks(uint32_t lba, const uint8_t* buf, size_t n) { +#if USE_DEBUG_MODE + Serial.print("writeBlocks: "); Serial.print(lba); + //Serial.print(", buf: "); Serial.print((uint32_t)buf, HEX); + Serial.print(", "); Serial.println(n); +#endif if (3 & (uint32_t)buf) { // misaligned buffer address, write single blocks for (size_t i = 0; i < n; i++, lba++, buf += 512) { if (!writeBlock(lba, buf)) { @@ -709,7 +729,6 @@ bool SdioCard::writeBlocks(uint32_t lba, const uint8_t* buf, size_t n) } return true; } - //Serial.print("writeBlocks: "); Serial.print(lba); Serial.print(", "); Serial.print(n); if (yieldTimeout(isBusyCMD13)) { return sdError(SD_CARD_ERROR_CMD13); } From 54dd788f2b223869854532d2df64ee9ab9e6d507 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Thu, 6 Jul 2017 10:57:20 +1000 Subject: [PATCH 109/351] Fix warning caused by commit #f7a576f2e0efcee958bdfd737d9af7a2f6c76051 --- STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c | 4 ++-- STM32F1/cores/maple/usb_serial.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c b/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c index 774be42..cba050f 100644 --- a/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c +++ b/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c @@ -62,8 +62,8 @@ #if !(defined(BOARD_maple) || defined(BOARD_maple_RET6) || \ defined(BOARD_maple_mini) || defined(BOARD_maple_native)) -#warning USB CDC ACM relies on LeafLabs board-specific configuration.\ - You may have problems on non-LeafLabs boards. +//#warning USB CDC ACM relies on LeafLabs board-specific configuration.\ +// You may have problems on non-LeafLabs boards. #endif static void vcomDataTxCb(void); diff --git a/STM32F1/cores/maple/usb_serial.cpp b/STM32F1/cores/maple/usb_serial.cpp index 1fe2bf4..6cffbf5 100644 --- a/STM32F1/cores/maple/usb_serial.cpp +++ b/STM32F1/cores/maple/usb_serial.cpp @@ -71,7 +71,7 @@ void USBSerial::begin(void) { return; _hasBegun = true; - usb_cdcacm_enable(BOARD_USB_DISC_DEV, BOARD_USB_DISC_BIT); + usb_cdcacm_enable(BOARD_USB_DISC_DEV, (uint8_t)BOARD_USB_DISC_BIT); usb_cdcacm_set_hooks(USB_CDCACM_HOOK_RX, rxHook); usb_cdcacm_set_hooks(USB_CDCACM_HOOK_IFACE_SETUP, ifaceSetupHook); #endif @@ -97,7 +97,7 @@ volatile uint8_t removeCompilerWarningsIgnore=ignore; void USBSerial::end(void) { #if BOARD_HAVE_SERIALUSB - usb_cdcacm_disable(BOARD_USB_DISC_DEV, BOARD_USB_DISC_BIT); + usb_cdcacm_disable(BOARD_USB_DISC_DEV, (uint8_t)BOARD_USB_DISC_BIT); usb_cdcacm_remove_hooks(USB_CDCACM_HOOK_RX | USB_CDCACM_HOOK_IFACE_SETUP); _hasBegun = false; #endif From 8683035cb7f95127b18b386be24b0fac537bb1f8 Mon Sep 17 00:00:00 2001 From: victorpv Date: Sat, 8 Jul 2017 10:46:49 -0500 Subject: [PATCH 110/351] Update usb_serial.h --- STM32F1/cores/maple/usb_serial.h | 1 + 1 file changed, 1 insertion(+) diff --git a/STM32F1/cores/maple/usb_serial.h b/STM32F1/cores/maple/usb_serial.h index d6c3e02..153eb8e 100644 --- a/STM32F1/cores/maple/usb_serial.h +++ b/STM32F1/cores/maple/usb_serial.h @@ -51,6 +51,7 @@ public: virtual int available(void);// Changed to virtual + size_t usb_serial_class::readBytes(char *buf, const size_t& len); uint32 read(uint8 * buf, uint32 len); // uint8 read(void); From 1c07e25bd71f4e823aa9d61e2194731a9d9aee8a Mon Sep 17 00:00:00 2001 From: victorpv Date: Sat, 8 Jul 2017 10:49:14 -0500 Subject: [PATCH 111/351] Update usb_serial.h --- STM32F1/cores/maple/usb_serial.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/cores/maple/usb_serial.h b/STM32F1/cores/maple/usb_serial.h index 153eb8e..8351593 100644 --- a/STM32F1/cores/maple/usb_serial.h +++ b/STM32F1/cores/maple/usb_serial.h @@ -51,7 +51,7 @@ public: virtual int available(void);// Changed to virtual - size_t usb_serial_class::readBytes(char *buf, const size_t& len); + size_t readBytes(char *buf, const size_t& len); uint32 read(uint8 * buf, uint32 len); // uint8 read(void); From fd95b999146be0ffbb607551370bf4cd0d7bfaff Mon Sep 17 00:00:00 2001 From: victorpv Date: Sat, 8 Jul 2017 10:52:50 -0500 Subject: [PATCH 112/351] Added readBytes function to usbSerial Add Arduino USB implementation of Arduino Stream class readBytes, which reads bytes in blocks with a timeout. Increases the speed from 300KB/s to 500KB/s over the Stream class readBytes function. --- STM32F1/cores/maple/usb_serial.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/STM32F1/cores/maple/usb_serial.cpp b/STM32F1/cores/maple/usb_serial.cpp index 994cd7a..0902c50 100644 --- a/STM32F1/cores/maple/usb_serial.cpp +++ b/STM32F1/cores/maple/usb_serial.cpp @@ -168,6 +168,19 @@ uint32 USBSerial::read(uint8 * buf, uint32 len) { return rxed; } +size_t USBSerial::readBytes(char *buf, const size_t& len) +{ + size_t rxed=0; + unsigned long startMillis; + startMillis = millis(); + if (len <= 0) return 0; + do { + rxed += usb_cdcacm_rx((uint8 *)buf + rxed, len - rxed); + if (rxed == len) return rxed; + } while(millis() - startMillis < _timeout); + return rxed; +} + /* Blocks forever until 1 byte is received */ int USBSerial::read(void) { uint8 b; From b892004cc236553618c29c7afb43663f00af9016 Mon Sep 17 00:00:00 2001 From: victorpv Date: Mon, 10 Jul 2017 12:00:29 -0500 Subject: [PATCH 113/351] Add files via upload --- STM32F1/libraries/SPI/src/SPI.cpp | 362 +++++++++++++++++++++--------- STM32F1/libraries/SPI/src/SPI.h | 81 +++++-- 2 files changed, 313 insertions(+), 130 deletions(-) diff --git a/STM32F1/libraries/SPI/src/SPI.cpp b/STM32F1/libraries/SPI/src/SPI.cpp index f0d9f7f..998f9b0 100644 --- a/STM32F1/libraries/SPI/src/SPI.cpp +++ b/STM32F1/libraries/SPI/src/SPI.cpp @@ -101,16 +101,19 @@ SPIClass::SPIClass(uint32 spi_num) { #if BOARD_NR_SPI >= 1 case 1: _currentSetting->spi_d = SPI1; + _spi1_this = (void*) this; break; #endif #if BOARD_NR_SPI >= 2 case 2: _currentSetting->spi_d = SPI2; + _spi2_this = (void*) this; break; #endif #if BOARD_NR_SPI >= 3 case 3: _currentSetting->spi_d = SPI3; + _spi3_this = (void*) this; break; #endif default: @@ -137,6 +140,8 @@ SPIClass::SPIClass(uint32 spi_num) { _settings[2].spiRxDmaChannel = DMA_CH1; #endif + // added for DMA callbacks. + _currentSetting->state = SPI_STATE_IDLE; } /* @@ -154,6 +159,8 @@ void SPIClass::begin(void) { spi_init(_currentSetting->spi_d); configure_gpios(_currentSetting->spi_d, 1); updateSettings(); + // added for DMA callbacks. + _currentSetting->state = SPI_STATE_READY; } void SPIClass::beginSlave(void) { @@ -164,6 +171,8 @@ void SPIClass::beginSlave(void) { Serial.print("spi_slave_enable("); Serial.print(_currentSetting->dataMode); Serial.print(","); Serial.print(flags); Serial.println(")"); #endif spi_slave_enable(_currentSetting->spi_d, (spi_mode)_currentSetting->dataMode, flags); + // added for DMA callbacks. + _currentSetting->state = SPI_STATE_READY; } void SPIClass::end(void) { @@ -182,6 +191,9 @@ void SPIClass::end(void) { while (spi_is_busy(_currentSetting->spi_d)) ; spi_peripheral_disable(_currentSetting->spi_d); + // added for DMA callbacks. + // Need to add unsetting the callbacks for the DMA channels. + _currentSetting->state = SPI_STATE_IDLE; } /* Roger Clark added 3 functions */ @@ -384,98 +396,126 @@ uint16_t SPIClass::transfer16(uint16_t wr_data) const /* 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) -{ - if (length == 0) return 0; - uint8 b = 0; -// dma1_ch3_Active=true; +void SPIClass::dmaTransferSet(void *transmitBuf, void *receiveBuf) { dma_init(_currentSetting->spiDmaDev); -// dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event); - - // RX + //spi_rx_dma_enable(_currentSetting->spi_d); + //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->spiRxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size, - 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); - if ( transmitBuf==0 ) { - static uint8_t ff = 0XFF; - transmitBuf = &ff; - flags ^= DMA_MINC_MODE; // remove increment mode + receiveBuf, dma_bit_size, (DMA_MINC_MODE | DMA_TRNS_CMPLT ));// receive buffer DMA + if (!transmitBuf) { + transmitBuf = &ff; + dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size, + transmitBuf, dma_bit_size, (DMA_FROM_MEM));// Transmit FF repeatedly } + else { 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 + transmitBuf, dma_bit_size, (DMA_MINC_MODE | DMA_FROM_MEM ));// Transmit buffer DMA + } + dma_set_priority(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, DMA_PRIORITY_LOW); + dma_set_priority(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, DMA_PRIORITY_VERY_HIGH); +} - spi_rx_reg(_currentSetting->spi_d); //Clear the RX buffer in case a byte is waiting on it. +uint8 SPIClass::dmaTransferRepeat(uint16 length) { + if (length == 0) return 0; + if (spi_is_rx_nonempty(_currentSetting->spi_d) == 1) spi_rx_reg(_currentSetting->spi_d); + _currentSetting->state = SPI_STATE_TRANSFER; + dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, length); + 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 spi_rx_dma_enable(_currentSetting->spi_d); - spi_tx_dma_enable(_currentSetting->spi_d); // must be the last enable to avoid DMA error flag - + spi_tx_dma_enable(_currentSetting->spi_d); + if (_currentSetting->receiveCallback){ + return 0; + } + //uint32_t m = millis(); + uint8 b = 0; 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); + 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; } } 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." + while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." spi_tx_dma_disable(_currentSetting->spi_d); - 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); + spi_rx_dma_disable(_currentSetting->spi_d); + dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel); + dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel); + dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); + _currentSetting->state = SPI_STATE_READY; 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. +* Still in progress. +*/ + +uint8 SPIClass::dmaTransfer(void *transmitBuf, void *receiveBuf, uint16 length) { + dmaTransferSet(transmitBuf, receiveBuf); + return dmaTransferRepeat(length); +} + /* Roger Clark and Victor Perez, 2015 * 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, bool minc) -{ + +void SPIClass::dmaSendSet(void * transmitBuf, bool minc) { + uint32 flags = ( (DMA_MINC_MODE*minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT); + dma_init(_currentSetting->spiDmaDev); + 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_priority(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, DMA_PRIORITY_LOW); +} + +uint8 SPIClass::dmaSendRepeat(uint16 length) { if (length == 0) return 0; - uint32 flags = ( (DMA_MINC_MODE*minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT); - uint8 b = 0; - dma_init(_currentSetting->spiDmaDev); - // TX - 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_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length); + _currentSetting->state = SPI_STATE_TRANSMIT; dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit - spi_tx_dma_enable(_currentSetting->spi_d); - - 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); + spi_tx_dma_enable(_currentSetting->spi_d); + if (_currentSetting->transmitCallback) + { + return 0; + } + uint32_t m = millis(); + uint8 b = 0; + 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; } - } - + } 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." spi_tx_dma_disable(_currentSetting->spi_d); dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); + dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); + _currentSetting->state = SPI_STATE_READY; return b; } +uint8 SPIClass::dmaSend(void * transmitBuf, uint16 length, bool minc) { + dmaSendSet(transmitBuf, minc); + return dmaSendRepeat(length); +} -uint8 SPIClass::dmaSendAsync(void * transmitBuf, uint16 length, bool minc) -{ - static bool isRunning=false; +uint8 SPIClass::dmaSendAsync(void * transmitBuf, uint16 length, bool minc) { uint8 b = 0; - if (isRunning) + if (_currentSetting->state != SPI_STATE_READY) { uint32_t m = millis(); @@ -488,29 +528,121 @@ uint8 SPIClass::dmaSendAsync(void * transmitBuf, uint16 length, bool minc) while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." spi_tx_dma_disable(_currentSetting->spi_d); dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); - isRunning=false; + _currentSetting->state = SPI_STATE_READY; } if (length == 0) return 0; uint32 flags = ( (DMA_MINC_MODE*minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT); - dma_init(_currentSetting->spiDmaDev); + + dma_init(_currentSetting->spiDmaDev); // TX 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_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); - isRunning=true; + _currentSetting->state = SPI_STATE_TRANSMIT; return b; } +/* + New functions added to manage callbacks. + Victor Perez 2017 +*/ + +void SPIClass::onReceive(void(*callback)(void)) { + _currentSetting->receiveCallback = callback; + if (callback){ + switch (_currentSetting->spi_d->clk_id) { + case RCC_SPI1: + dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &SPIClass::_spi1EventCallback); + break; + case RCC_SPI2: + dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &SPIClass::_spi2EventCallback); + break; + #if BOARD_NR_SPI >= 3 + case RCC_SPI3: + dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &SPIClass::_spi3EventCallback); + break; + #endif + default: + ASSERT(0); + } + } + else { + dma_detach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel); + } +} + +void SPIClass::onTransmit(void(*callback)(void)) { + _currentSetting->transmitCallback = callback; + if (callback){ + switch (_currentSetting->spi_d->clk_id) { + case RCC_SPI1: + dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &SPIClass::_spi1EventCallback); + break; + case RCC_SPI2: + dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &SPIClass::_spi2EventCallback); + break; + #if BOARD_NR_SPI >= 3 + case RCC_SPI3: + dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &SPIClass::_spi3EventCallback); + break; + #endif + default: + ASSERT(0); + } + } + else { + dma_detach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); + } +} + +/* + TODO: check if better to first call the customer code, next disable the DMA requests. + Also see if we need to check whether callbacks are set or not, may be better to be checked during the initial setup and only set the callback to EventCallback if they are set. +*/ + +void SPIClass::EventCallback() { + 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" + switch (_currentSetting->state) { + case SPI_STATE_TRANSFER: + while (spi_is_rx_nonempty(_currentSetting->spi_d)); + _currentSetting->state = SPI_STATE_READY; + spi_tx_dma_disable(_currentSetting->spi_d); + spi_rx_dma_disable(_currentSetting->spi_d); + //dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); + //dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel); + + if (_currentSetting->receiveCallback) + { + _currentSetting->receiveCallback(); + } + break; + case SPI_STATE_TRANSMIT: + _currentSetting->state = SPI_STATE_READY; + spi_tx_dma_disable(_currentSetting->spi_d); + //dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); + if (_currentSetting->transmitCallback) + { + _currentSetting->transmitCallback(); + } + + break; + default: + // we shouldn't get here, so better to add an assert and fail. + return; + } +} + void SPIClass::attachInterrupt(void) { // Should be enableInterrupt() } @@ -557,85 +689,101 @@ uint8 SPIClass::recv(void) { return this->read(); } - /* - * Auxiliary functions - */ + DMA call back functions, one per port. +*/ + +void SPIClass::_spi1EventCallback() +{ + reinterpret_cast(_spi1_this)->EventCallback(); +} + +void SPIClass::_spi2EventCallback() { + reinterpret_cast(_spi2_this)->EventCallback(); +} +#if BOARD_NR_SPI >= 3 +void SPIClass::_spi3EventCallback() { + reinterpret_cast(_spi3_this)->EventCallback(); +} +#endif +/* +* Auxiliary functions +*/ static const spi_pins* dev_to_spi_pins(spi_dev *dev) { - switch (dev->clk_id) { + switch (dev->clk_id) { #if BOARD_NR_SPI >= 1 - case RCC_SPI1: return board_spi_pins; + case RCC_SPI1: return board_spi_pins; #endif #if BOARD_NR_SPI >= 2 - case RCC_SPI2: return board_spi_pins + 1; + case RCC_SPI2: return board_spi_pins + 1; #endif #if BOARD_NR_SPI >= 3 - case RCC_SPI3: return board_spi_pins + 2; + case RCC_SPI3: return board_spi_pins + 2; #endif - default: return NULL; - } + default: return NULL; + } } static void disable_pwm(const stm32_pin_info *i) { - if (i->timer_device) { - timer_set_mode(i->timer_device, i->timer_channel, TIMER_DISABLED); - } + if (i->timer_device) { + timer_set_mode(i->timer_device, i->timer_channel, TIMER_DISABLED); + } } static void configure_gpios(spi_dev *dev, bool as_master) { - const spi_pins *pins = dev_to_spi_pins(dev); + const spi_pins *pins = dev_to_spi_pins(dev); - if (!pins) { - return; - } + if (!pins) { + return; + } - const stm32_pin_info *nssi = &PIN_MAP[pins->nss]; - const stm32_pin_info *scki = &PIN_MAP[pins->sck]; - const stm32_pin_info *misoi = &PIN_MAP[pins->miso]; - const stm32_pin_info *mosii = &PIN_MAP[pins->mosi]; + const stm32_pin_info *nssi = &PIN_MAP[pins->nss]; + const stm32_pin_info *scki = &PIN_MAP[pins->sck]; + const stm32_pin_info *misoi = &PIN_MAP[pins->miso]; + const stm32_pin_info *mosii = &PIN_MAP[pins->mosi]; - disable_pwm(nssi); - disable_pwm(scki); - disable_pwm(misoi); - disable_pwm(mosii); + disable_pwm(nssi); + disable_pwm(scki); + disable_pwm(misoi); + disable_pwm(mosii); - spi_config_gpios(dev, as_master, nssi->gpio_device, nssi->gpio_bit, - scki->gpio_device, scki->gpio_bit, misoi->gpio_bit, - mosii->gpio_bit); + spi_config_gpios(dev, as_master, nssi->gpio_device, nssi->gpio_bit, + scki->gpio_device, scki->gpio_bit, misoi->gpio_bit, + mosii->gpio_bit); } static const spi_baud_rate baud_rates[8] __FLASH__ = { - SPI_BAUD_PCLK_DIV_2, - SPI_BAUD_PCLK_DIV_4, - SPI_BAUD_PCLK_DIV_8, - SPI_BAUD_PCLK_DIV_16, - SPI_BAUD_PCLK_DIV_32, - SPI_BAUD_PCLK_DIV_64, - SPI_BAUD_PCLK_DIV_128, - SPI_BAUD_PCLK_DIV_256, + SPI_BAUD_PCLK_DIV_2, + SPI_BAUD_PCLK_DIV_4, + SPI_BAUD_PCLK_DIV_8, + SPI_BAUD_PCLK_DIV_16, + SPI_BAUD_PCLK_DIV_32, + SPI_BAUD_PCLK_DIV_64, + SPI_BAUD_PCLK_DIV_128, + SPI_BAUD_PCLK_DIV_256, }; /* - * Note: This assumes you're on a LeafLabs-style board - * (CYCLES_PER_MICROSECOND == 72, APB2 at 72MHz, APB1 at 36MHz). - */ +* Note: This assumes you're on a LeafLabs-style board +* (CYCLES_PER_MICROSECOND == 72, APB2 at 72MHz, APB1 at 36MHz). +*/ static spi_baud_rate determine_baud_rate(spi_dev *dev, uint32_t freq) { uint32_t clock = 0, i; #ifdef SPI_DEBUG Serial.print("determine_baud_rate("); Serial.print(freq); Serial.println(")"); #endif - switch (rcc_dev_clk(dev->clk_id)) - { - case RCC_APB2: clock = STM32_PCLK2; break; // 72 Mhz - case RCC_APB1: clock = STM32_PCLK1; break; // 36 Mhz - } - clock /= 2; - i = 0; - while (i < 7 && freq < clock) { - clock /= 2; - i++; - } + switch (rcc_dev_clk(dev->clk_id)) + { + case RCC_APB2: clock = STM32_PCLK2; break; // 72 Mhz + case RCC_APB1: clock = STM32_PCLK1; break; // 36 Mhz + } + clock /= 2; + i = 0; + while (i < 7 && freq < clock) { + clock /= 2; + i++; + } return baud_rates[i]; } diff --git a/STM32F1/libraries/SPI/src/SPI.h b/STM32F1/libraries/SPI/src/SPI.h index 4d9b563..2160d26 100644 --- a/STM32F1/libraries/SPI/src/SPI.h +++ b/STM32F1/libraries/SPI/src/SPI.h @@ -99,6 +99,13 @@ #define DATA_SIZE_8BIT SPI_CR1_DFF_8_BIT #define DATA_SIZE_16BIT SPI_CR1_DFF_16_BIT +typedef enum { + SPI_STATE_IDLE, + SPI_STATE_READY, + SPI_STATE_RECEIVE, + SPI_STATE_TRANSMIT, + SPI_STATE_TRANSFER + } spi_mode_t; class SPISettings { public: SPISettings(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) { @@ -134,21 +141,31 @@ private: this->dataSize = dataSize; } uint32_t clock; + uint32_t dataSize; + uint32_t clockDivider; BitOrder bitOrder; uint8_t dataMode; - uint32_t dataSize; - + uint8_t _SSPin; + volatile spi_mode_t state; spi_dev *spi_d; - uint8_t _SSPin; - uint32_t clockDivider; dma_channel spiRxDmaChannel, spiTxDmaChannel; dma_dev* spiDmaDev; + void (*receiveCallback)(void) = NULL; + void (*transmitCallback)(void) = NULL; friend class SPIClass; }; -volatile static bool dma1_ch3_Active; +/* + Should move this to within the class once tested out, just for tidyness +*/ +static uint8_t ff = 0XFF; +static void (*_spi1_this); +static void (*_spi2_this); +#if BOARD_NR_SPI >= 3 +static void (*_spi3_this); +#endif /** * @brief Wirish SPI interface. @@ -217,7 +234,15 @@ public: */ void setDataSize(uint32 ds); - + /* Victor Perez 2017. Added to set and clear callback functions for callback + * on DMA transfer completion. + * onReceive used to set the callback in case of dmaTransfer (tx/rx), once rx is completed + * onTransmit used to set the callback in case of dmaSend (tx only). That function + * will NOT be called in case of TX/RX + */ + void onReceive(void(*)(void)); + void onTransmit(void(*)(void)); + /* * I/O */ @@ -279,7 +304,9 @@ 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(void * transmitBuf, void * receiveBuf, uint16 length); + void dmaTransferSet(void *transmitBuf, void *receiveBuf); + uint8 dmaTransferRepeat(uint16 length); /** * @brief Sets up a DMA Transmit for SPI 8 or 16 bit transfer mode. @@ -289,9 +316,13 @@ public: * * @param data buffer half words 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(void * transmitBuf, uint16 length, bool minc = 1); - uint8 dmaSendAsync(void * transmitBuf, uint16 length, bool minc = 1); + uint8 dmaSend(void * transmitBuf, uint16 length, bool minc = 1); + void dmaSendSet(void * transmitBuf, bool minc); + uint8 dmaSendRepeat(uint16 length); + + uint8 dmaSendAsync(void * transmitBuf, uint16 length, bool minc = 1); /* * Pin accessors */ @@ -325,7 +356,7 @@ public: spi_dev* c_dev(void) { return _currentSetting->spi_d; } - spi_dev *dev(){ return _currentSetting->spi_d;} + spi_dev *dev(){ return _currentSetting->spi_d;} /** * @brief Sets the number of the SPI peripheral to be used by @@ -335,10 +366,10 @@ public: * or 1-3 in high density devices. */ - void setModule(int spi_num) - { - _currentSetting=&_settings[spi_num-1];// SPI channels are called 1 2 and 3 but the array is zero indexed - } + void setModule(int spi_num) + { + _currentSetting=&_settings[spi_num-1];// SPI channels are called 1 2 and 3 but the array is zero indexed + } /* -- The following methods are deprecated --------------------------- */ @@ -374,19 +405,23 @@ public: uint8 recv(void); private: -/* - static inline void DMA1_CH3_Event() { - dma1_ch3_Active = 0; -// dma_disable(DMA1, DMA_CH3); -// dma_disable(DMA1, DMA_CH2); - - // To Do. Need to wait for - } -*/ + SPISettings _settings[BOARD_NR_SPI]; SPISettings *_currentSetting; void updateSettings(void); + /* + * Functions added for DMA transfers with Callback. + * Experimental. + */ + + void EventCallback(void); + + static void _spi1EventCallback(void); + static void _spi2EventCallback(void); + #if BOARD_NR_SPI >= 3 + static void _spi3EventCallback(void); + #endif /* spi_dev *spi_d; uint8_t _SSPin; From 910072c7db2c0f81452589cc8fdf965457824aa1 Mon Sep 17 00:00:00 2001 From: victorpv Date: Mon, 10 Jul 2017 12:08:59 -0500 Subject: [PATCH 114/351] Changes tabs for spaces. --- STM32F1/libraries/SPI/src/SPI.cpp | 684 +++++++++++++++--------------- 1 file changed, 342 insertions(+), 342 deletions(-) diff --git a/STM32F1/libraries/SPI/src/SPI.cpp b/STM32F1/libraries/SPI/src/SPI.cpp index 998f9b0..94e5031 100644 --- a/STM32F1/libraries/SPI/src/SPI.cpp +++ b/STM32F1/libraries/SPI/src/SPI.cpp @@ -94,14 +94,14 @@ static const spi_pins board_spi_pins[] __FLASH__ = { SPIClass::SPIClass(uint32 spi_num) { - _currentSetting=&_settings[spi_num-1];// SPI channels are called 1 2 and 3 but the array is zero indexed + _currentSetting=&_settings[spi_num-1];// SPI channels are called 1 2 and 3 but the array is zero indexed - + switch (spi_num) { #if BOARD_NR_SPI >= 1 case 1: _currentSetting->spi_d = SPI1; - _spi1_this = (void*) this; + _spi1_this = (void*) this; break; #endif #if BOARD_NR_SPI >= 2 @@ -119,25 +119,25 @@ SPIClass::SPIClass(uint32 spi_num) { default: ASSERT(0); } - - // Init things specific to each SPI device - // clock divider setup is a bit of hack, and needs to be improved at a later date. - _settings[0].spi_d = SPI1; - _settings[0].clockDivider = determine_baud_rate(_settings[0].spi_d, _settings[0].clock); - _settings[0].spiDmaDev = DMA1; - _settings[0].spiTxDmaChannel = DMA_CH3; - _settings[0].spiRxDmaChannel = DMA_CH2; - _settings[1].spi_d = SPI2; - _settings[1].clockDivider = determine_baud_rate(_settings[1].spi_d, _settings[1].clock); - _settings[1].spiDmaDev = DMA1; - _settings[1].spiTxDmaChannel = DMA_CH5; - _settings[1].spiRxDmaChannel = DMA_CH4; + + // Init things specific to each SPI device + // clock divider setup is a bit of hack, and needs to be improved at a later date. + _settings[0].spi_d = SPI1; + _settings[0].clockDivider = determine_baud_rate(_settings[0].spi_d, _settings[0].clock); + _settings[0].spiDmaDev = DMA1; + _settings[0].spiTxDmaChannel = DMA_CH3; + _settings[0].spiRxDmaChannel = DMA_CH2; + _settings[1].spi_d = SPI2; + _settings[1].clockDivider = determine_baud_rate(_settings[1].spi_d, _settings[1].clock); + _settings[1].spiDmaDev = DMA1; + _settings[1].spiTxDmaChannel = DMA_CH5; + _settings[1].spiRxDmaChannel = DMA_CH4; #if BOARD_NR_SPI >= 3 - _settings[2].spi_d = SPI3; - _settings[2].clockDivider = determine_baud_rate(_settings[2].spi_d, _settings[2].clock); - _settings[2].spiDmaDev = DMA2; - _settings[2].spiTxDmaChannel = DMA_CH2; - _settings[2].spiRxDmaChannel = DMA_CH1; + _settings[2].spi_d = SPI3; + _settings[2].clockDivider = determine_baud_rate(_settings[2].spi_d, _settings[2].clock); + _settings[2].spiDmaDev = DMA2; + _settings[2].spiTxDmaChannel = DMA_CH2; + _settings[2].spiRxDmaChannel = DMA_CH1; #endif // added for DMA callbacks. @@ -148,11 +148,11 @@ SPIClass::SPIClass(uint32 spi_num) { * Set up/tear down */ void SPIClass::updateSettings(void) { - uint32 flags = ((_currentSetting->bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | _currentSetting->dataSize | SPI_SW_SLAVE | SPI_SOFT_SS); - #ifdef SPI_DEBUG - Serial.print("spi_master_enable("); Serial.print(_currentSetting->clockDivider); Serial.print(","); Serial.print(_currentSetting->dataMode); Serial.print(","); Serial.print(flags); Serial.println(")"); - #endif - spi_master_enable(_currentSetting->spi_d, (spi_baud_rate)_currentSetting->clockDivider, (spi_mode)_currentSetting->dataMode, flags); + uint32 flags = ((_currentSetting->bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | _currentSetting->dataSize | SPI_SW_SLAVE | SPI_SOFT_SS); + #ifdef SPI_DEBUG + Serial.print("spi_master_enable("); Serial.print(_currentSetting->clockDivider); Serial.print(","); Serial.print(_currentSetting->dataMode); Serial.print(","); Serial.print(flags); Serial.println(")"); + #endif + spi_master_enable(_currentSetting->spi_d, (spi_baud_rate)_currentSetting->clockDivider, (spi_mode)_currentSetting->dataMode, flags); } void SPIClass::begin(void) { @@ -167,9 +167,9 @@ 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_RX_ONLY); - #ifdef SPI_DEBUG - Serial.print("spi_slave_enable("); Serial.print(_currentSetting->dataMode); Serial.print(","); Serial.print(flags); Serial.println(")"); - #endif + #ifdef SPI_DEBUG + Serial.print("spi_slave_enable("); Serial.print(_currentSetting->dataMode); Serial.print(","); Serial.print(flags); Serial.println(")"); + #endif spi_slave_enable(_currentSetting->spi_d, (spi_mode)_currentSetting->dataMode, flags); // added for DMA callbacks. _currentSetting->state = SPI_STATE_READY; @@ -199,23 +199,23 @@ void SPIClass::end(void) { /* Roger Clark added 3 functions */ void SPIClass::setClockDivider(uint32_t clockDivider) { - #ifdef SPI_DEBUG - Serial.print("Clock divider set to "); Serial.println(clockDivider); - #endif - _currentSetting->clockDivider = clockDivider; - uint32 cr1 = _currentSetting->spi_d->regs->CR1 & ~(SPI_CR1_BR); - _currentSetting->spi_d->regs->CR1 = cr1 | (clockDivider & SPI_CR1_BR); + #ifdef SPI_DEBUG + Serial.print("Clock divider set to "); Serial.println(clockDivider); + #endif + _currentSetting->clockDivider = clockDivider; + uint32 cr1 = _currentSetting->spi_d->regs->CR1 & ~(SPI_CR1_BR); + _currentSetting->spi_d->regs->CR1 = cr1 | (clockDivider & SPI_CR1_BR); } void SPIClass::setBitOrder(BitOrder bitOrder) { - #ifdef SPI_DEBUG - Serial.print("Bit order set to "); Serial.println(bitOrder); - #endif - _currentSetting->bitOrder = bitOrder; - uint32 cr1 = _currentSetting->spi_d->regs->CR1 & ~(SPI_CR1_LSBFIRST); - if ( bitOrder==LSBFIRST ) cr1 |= SPI_CR1_LSBFIRST; - _currentSetting->spi_d->regs->CR1 = cr1; + #ifdef SPI_DEBUG + Serial.print("Bit order set to "); Serial.println(bitOrder); + #endif + _currentSetting->bitOrder = bitOrder; + uint32 cr1 = _currentSetting->spi_d->regs->CR1 & ~(SPI_CR1_LSBFIRST); + if ( bitOrder==LSBFIRST ) cr1 |= SPI_CR1_LSBFIRST; + _currentSetting->spi_d->regs->CR1 = cr1; } /* Victor Perez. Added to test changing datasize from 8 to 16 bit modes on the fly. @@ -224,11 +224,11 @@ void SPIClass::setBitOrder(BitOrder bitOrder) */ void SPIClass::setDataSize(uint32 datasize) { - _currentSetting->dataSize = datasize; - 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; + _currentSetting->dataSize = datasize; + 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) @@ -258,56 +258,56 @@ bit 0 - CPHA : Clock phase If someone finds this is not the case or sees a logic error with this let me know ;-) */ - #ifdef SPI_DEBUG - Serial.print("Data mode set to "); Serial.println(dataMode); - #endif - _currentSetting->dataMode = dataMode; - uint32 cr1 = _currentSetting->spi_d->regs->CR1 & ~(SPI_CR1_CPOL|SPI_CR1_CPHA); - _currentSetting->spi_d->regs->CR1 = cr1 | (dataMode & (SPI_CR1_CPOL|SPI_CR1_CPHA)); + #ifdef SPI_DEBUG + Serial.print("Data mode set to "); Serial.println(dataMode); + #endif + _currentSetting->dataMode = dataMode; + uint32 cr1 = _currentSetting->spi_d->regs->CR1 & ~(SPI_CR1_CPOL|SPI_CR1_CPHA); + _currentSetting->spi_d->regs->CR1 = cr1 | (dataMode & (SPI_CR1_CPOL|SPI_CR1_CPHA)); } void SPIClass::beginTransaction(uint8_t pin, SPISettings settings) { - #ifdef SPI_DEBUG - Serial.println("SPIClass::beginTransaction"); - #endif - setBitOrder(settings.bitOrder); - setDataMode(settings.dataMode); - setDataSize(settings.dataSize); - setClockDivider(determine_baud_rate(_currentSetting->spi_d, settings.clock)); - begin(); + #ifdef SPI_DEBUG + Serial.println("SPIClass::beginTransaction"); + #endif + setBitOrder(settings.bitOrder); + setDataMode(settings.dataMode); + setDataSize(settings.dataSize); + setClockDivider(determine_baud_rate(_currentSetting->spi_d, settings.clock)); + begin(); } void SPIClass::beginTransactionSlave(SPISettings settings) { - #ifdef SPI_DEBUG - Serial.println(F("SPIClass::beginTransactionSlave")); - #endif - setBitOrder(settings.bitOrder); - setDataMode(settings.dataMode); - setDataSize(settings.dataSize); - beginSlave(); + #ifdef SPI_DEBUG + Serial.println(F("SPIClass::beginTransactionSlave")); + #endif + setBitOrder(settings.bitOrder); + setDataMode(settings.dataMode); + setDataSize(settings.dataSize); + beginSlave(); } void SPIClass::endTransaction(void) { - #ifdef SPI_DEBUG - Serial.println("SPIClass::endTransaction"); - #endif - //digitalWrite(_SSPin,HIGH); + #ifdef SPI_DEBUG + Serial.println("SPIClass::endTransaction"); + #endif + //digitalWrite(_SSPin,HIGH); #if false // code from SAM core - uint8_t mode = interruptMode; - if (mode > 0) { - if (mode < 16) { - if (mode & 1) PIOA->PIO_IER = interruptMask[0]; - if (mode & 2) PIOB->PIO_IER = interruptMask[1]; - if (mode & 4) PIOC->PIO_IER = interruptMask[2]; - if (mode & 8) PIOD->PIO_IER = interruptMask[3]; - } else { - if (interruptSave) interrupts(); - } - } + uint8_t mode = interruptMode; + if (mode > 0) { + if (mode < 16) { + if (mode & 1) PIOA->PIO_IER = interruptMask[0]; + if (mode & 2) PIOB->PIO_IER = interruptMask[1]; + if (mode & 4) PIOC->PIO_IER = interruptMask[2]; + if (mode & 8) PIOD->PIO_IER = interruptMask[3]; + } else { + if (interruptSave) interrupts(); + } + } #endif } @@ -318,80 +318,80 @@ void SPIClass::endTransaction(void) uint16 SPIClass::read(void) { - while ( spi_is_rx_nonempty(_currentSetting->spi_d)==0 ) ; - return (uint16)spi_rx_reg(_currentSetting->spi_d); + while ( spi_is_rx_nonempty(_currentSetting->spi_d)==0 ) ; + return (uint16)spi_rx_reg(_currentSetting->spi_d); } 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; - // 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 + 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; + // 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) { - /* 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) - * 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." + /* 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) + * 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." } 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 + // 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(void *data, uint32 length) { - 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." + 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_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." + 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_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." + 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 @@ -402,54 +402,54 @@ uint16_t SPIClass::transfer16(uint16_t wr_data) const */ void SPIClass::dmaTransferSet(void *transmitBuf, void *receiveBuf) { dma_init(_currentSetting->spiDmaDev); - //spi_rx_dma_enable(_currentSetting->spi_d); - //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->spiRxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size, + //spi_rx_dma_enable(_currentSetting->spi_d); + //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->spiRxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size, receiveBuf, dma_bit_size, (DMA_MINC_MODE | DMA_TRNS_CMPLT ));// receive buffer DMA - if (!transmitBuf) { - transmitBuf = &ff; - dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size, + if (!transmitBuf) { + transmitBuf = &ff; + dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size, transmitBuf, dma_bit_size, (DMA_FROM_MEM));// Transmit FF repeatedly - } - else { + } + else { dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size, transmitBuf, dma_bit_size, (DMA_MINC_MODE | DMA_FROM_MEM ));// Transmit buffer DMA - } - dma_set_priority(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, DMA_PRIORITY_LOW); - dma_set_priority(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, DMA_PRIORITY_VERY_HIGH); + } + dma_set_priority(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, DMA_PRIORITY_LOW); + dma_set_priority(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, DMA_PRIORITY_VERY_HIGH); } uint8 SPIClass::dmaTransferRepeat(uint16 length) { - if (length == 0) return 0; - if (spi_is_rx_nonempty(_currentSetting->spi_d) == 1) spi_rx_reg(_currentSetting->spi_d); - _currentSetting->state = SPI_STATE_TRANSFER; - dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, length); - 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 - spi_rx_dma_enable(_currentSetting->spi_d); - spi_tx_dma_enable(_currentSetting->spi_d); + if (length == 0) return 0; + if (spi_is_rx_nonempty(_currentSetting->spi_d) == 1) spi_rx_reg(_currentSetting->spi_d); + _currentSetting->state = SPI_STATE_TRANSFER; + dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, length); + 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 + spi_rx_dma_enable(_currentSetting->spi_d); + spi_tx_dma_enable(_currentSetting->spi_d); if (_currentSetting->receiveCallback){ return 0; } //uint32_t m = millis(); uint8 b = 0; 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. - if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; } + 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; } } - 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." - spi_tx_dma_disable(_currentSetting->spi_d); - spi_rx_dma_disable(_currentSetting->spi_d); + 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." + spi_tx_dma_disable(_currentSetting->spi_d); + spi_rx_dma_disable(_currentSetting->spi_d); dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); - dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel); - dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel); - dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); - _currentSetting->state = SPI_STATE_READY; + dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel); + dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel); + dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); + _currentSetting->state = SPI_STATE_READY; return b; } @@ -461,8 +461,8 @@ uint8 SPIClass::dmaTransferRepeat(uint16 length) { */ uint8 SPIClass::dmaTransfer(void *transmitBuf, void *receiveBuf, uint16 length) { - dmaTransferSet(transmitBuf, receiveBuf); - return dmaTransferRepeat(length); + dmaTransferSet(transmitBuf, receiveBuf); + return dmaTransferRepeat(length); } /* Roger Clark and Victor Perez, 2015 @@ -482,29 +482,29 @@ void SPIClass::dmaSendSet(void * transmitBuf, bool minc) { } uint8 SPIClass::dmaSendRepeat(uint16 length) { - if (length == 0) return 0; - dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); - dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length); - _currentSetting->state = SPI_STATE_TRANSMIT; - dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit - spi_tx_dma_enable(_currentSetting->spi_d); - if (_currentSetting->transmitCallback) - { - return 0; - } - uint32_t m = millis(); - uint8 b = 0; - 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; } - } - 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." - spi_tx_dma_disable(_currentSetting->spi_d); - dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); - dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); - _currentSetting->state = SPI_STATE_READY; - return b; + if (length == 0) return 0; + dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); + dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length); + _currentSetting->state = SPI_STATE_TRANSMIT; + dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit + spi_tx_dma_enable(_currentSetting->spi_d); + if (_currentSetting->transmitCallback) + { + return 0; + } + uint32_t m = millis(); + uint8 b = 0; + 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; } + } + 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." + spi_tx_dma_disable(_currentSetting->spi_d); + dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); + dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); + _currentSetting->state = SPI_STATE_READY; + return b; } uint8 SPIClass::dmaSend(void * transmitBuf, uint16 length, bool minc) { @@ -513,42 +513,42 @@ uint8 SPIClass::dmaSend(void * transmitBuf, uint16 length, bool minc) { } uint8 SPIClass::dmaSendAsync(void * transmitBuf, uint16 length, bool minc) { - uint8 b = 0; + uint8 b = 0; - if (_currentSetting->state != SPI_STATE_READY) - { + if (_currentSetting->state != SPI_STATE_READY) + { - 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; } - } - - 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." - spi_tx_dma_disable(_currentSetting->spi_d); - dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); - _currentSetting->state = SPI_STATE_READY; - } + 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; } + } + + 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." + spi_tx_dma_disable(_currentSetting->spi_d); + dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); + _currentSetting->state = SPI_STATE_READY; + } - - if (length == 0) return 0; - uint32 flags = ( (DMA_MINC_MODE*minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT); + + if (length == 0) return 0; + uint32 flags = ( (DMA_MINC_MODE*minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT); - - dma_init(_currentSetting->spiDmaDev); - // TX - 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); + + dma_init(_currentSetting->spiDmaDev); + // TX + 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); - _currentSetting->state = SPI_STATE_TRANSMIT; + _currentSetting->state = SPI_STATE_TRANSMIT; - return b; + return b; } @@ -558,51 +558,51 @@ uint8 SPIClass::dmaSendAsync(void * transmitBuf, uint16 length, bool minc) { */ void SPIClass::onReceive(void(*callback)(void)) { - _currentSetting->receiveCallback = callback; - if (callback){ - switch (_currentSetting->spi_d->clk_id) { - case RCC_SPI1: - dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &SPIClass::_spi1EventCallback); - break; - case RCC_SPI2: - dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &SPIClass::_spi2EventCallback); - break; - #if BOARD_NR_SPI >= 3 - case RCC_SPI3: - dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &SPIClass::_spi3EventCallback); - break; - #endif - default: - ASSERT(0); - } - } - else { - dma_detach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel); - } + _currentSetting->receiveCallback = callback; + if (callback){ + switch (_currentSetting->spi_d->clk_id) { + case RCC_SPI1: + dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &SPIClass::_spi1EventCallback); + break; + case RCC_SPI2: + dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &SPIClass::_spi2EventCallback); + break; + #if BOARD_NR_SPI >= 3 + case RCC_SPI3: + dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &SPIClass::_spi3EventCallback); + break; + #endif + default: + ASSERT(0); + } + } + else { + dma_detach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel); + } } void SPIClass::onTransmit(void(*callback)(void)) { - _currentSetting->transmitCallback = callback; - if (callback){ - switch (_currentSetting->spi_d->clk_id) { - case RCC_SPI1: - dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &SPIClass::_spi1EventCallback); - break; - case RCC_SPI2: - dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &SPIClass::_spi2EventCallback); - break; - #if BOARD_NR_SPI >= 3 - case RCC_SPI3: - dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &SPIClass::_spi3EventCallback); - break; - #endif - default: - ASSERT(0); - } - } - else { - dma_detach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); - } + _currentSetting->transmitCallback = callback; + if (callback){ + switch (_currentSetting->spi_d->clk_id) { + case RCC_SPI1: + dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &SPIClass::_spi1EventCallback); + break; + case RCC_SPI2: + dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &SPIClass::_spi2EventCallback); + break; + #if BOARD_NR_SPI >= 3 + case RCC_SPI3: + dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &SPIClass::_spi3EventCallback); + break; + #endif + default: + ASSERT(0); + } + } + else { + dma_detach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); + } } /* @@ -611,44 +611,44 @@ void SPIClass::onTransmit(void(*callback)(void)) { */ void SPIClass::EventCallback() { - 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" - switch (_currentSetting->state) { - case SPI_STATE_TRANSFER: - while (spi_is_rx_nonempty(_currentSetting->spi_d)); - _currentSetting->state = SPI_STATE_READY; - spi_tx_dma_disable(_currentSetting->spi_d); - spi_rx_dma_disable(_currentSetting->spi_d); - //dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); - //dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel); + 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" + switch (_currentSetting->state) { + case SPI_STATE_TRANSFER: + while (spi_is_rx_nonempty(_currentSetting->spi_d)); + _currentSetting->state = SPI_STATE_READY; + spi_tx_dma_disable(_currentSetting->spi_d); + spi_rx_dma_disable(_currentSetting->spi_d); + //dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); + //dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel); - if (_currentSetting->receiveCallback) - { - _currentSetting->receiveCallback(); - } - break; - case SPI_STATE_TRANSMIT: - _currentSetting->state = SPI_STATE_READY; - spi_tx_dma_disable(_currentSetting->spi_d); - //dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); - if (_currentSetting->transmitCallback) - { - _currentSetting->transmitCallback(); - } + if (_currentSetting->receiveCallback) + { + _currentSetting->receiveCallback(); + } + break; + case SPI_STATE_TRANSMIT: + _currentSetting->state = SPI_STATE_READY; + spi_tx_dma_disable(_currentSetting->spi_d); + //dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); + if (_currentSetting->transmitCallback) + { + _currentSetting->transmitCallback(); + } - break; - default: - // we shouldn't get here, so better to add an assert and fail. - return; - } + break; + default: + // we shouldn't get here, so better to add an assert and fail. + return; + } } void SPIClass::attachInterrupt(void) { - // Should be enableInterrupt() + // Should be enableInterrupt() } void SPIClass::detachInterrupt(void) { - // Should be disableInterrupt() + // Should be disableInterrupt() } /* @@ -699,11 +699,11 @@ void SPIClass::_spi1EventCallback() } void SPIClass::_spi2EventCallback() { - reinterpret_cast(_spi2_this)->EventCallback(); + reinterpret_cast(_spi2_this)->EventCallback(); } #if BOARD_NR_SPI >= 3 void SPIClass::_spi3EventCallback() { - reinterpret_cast(_spi3_this)->EventCallback(); + reinterpret_cast(_spi3_this)->EventCallback(); } #endif /* @@ -711,57 +711,57 @@ void SPIClass::_spi3EventCallback() { */ static const spi_pins* dev_to_spi_pins(spi_dev *dev) { - switch (dev->clk_id) { + switch (dev->clk_id) { #if BOARD_NR_SPI >= 1 - case RCC_SPI1: return board_spi_pins; + case RCC_SPI1: return board_spi_pins; #endif #if BOARD_NR_SPI >= 2 - case RCC_SPI2: return board_spi_pins + 1; + case RCC_SPI2: return board_spi_pins + 1; #endif #if BOARD_NR_SPI >= 3 - case RCC_SPI3: return board_spi_pins + 2; + case RCC_SPI3: return board_spi_pins + 2; #endif - default: return NULL; - } + default: return NULL; + } } static void disable_pwm(const stm32_pin_info *i) { - if (i->timer_device) { - timer_set_mode(i->timer_device, i->timer_channel, TIMER_DISABLED); - } + if (i->timer_device) { + timer_set_mode(i->timer_device, i->timer_channel, TIMER_DISABLED); + } } static void configure_gpios(spi_dev *dev, bool as_master) { - const spi_pins *pins = dev_to_spi_pins(dev); + const spi_pins *pins = dev_to_spi_pins(dev); - if (!pins) { - return; - } + if (!pins) { + return; + } - const stm32_pin_info *nssi = &PIN_MAP[pins->nss]; - const stm32_pin_info *scki = &PIN_MAP[pins->sck]; - const stm32_pin_info *misoi = &PIN_MAP[pins->miso]; - const stm32_pin_info *mosii = &PIN_MAP[pins->mosi]; + const stm32_pin_info *nssi = &PIN_MAP[pins->nss]; + const stm32_pin_info *scki = &PIN_MAP[pins->sck]; + const stm32_pin_info *misoi = &PIN_MAP[pins->miso]; + const stm32_pin_info *mosii = &PIN_MAP[pins->mosi]; - disable_pwm(nssi); - disable_pwm(scki); - disable_pwm(misoi); - disable_pwm(mosii); + disable_pwm(nssi); + disable_pwm(scki); + disable_pwm(misoi); + disable_pwm(mosii); - spi_config_gpios(dev, as_master, nssi->gpio_device, nssi->gpio_bit, - scki->gpio_device, scki->gpio_bit, misoi->gpio_bit, - mosii->gpio_bit); + spi_config_gpios(dev, as_master, nssi->gpio_device, nssi->gpio_bit, + scki->gpio_device, scki->gpio_bit, misoi->gpio_bit, + mosii->gpio_bit); } static const spi_baud_rate baud_rates[8] __FLASH__ = { - SPI_BAUD_PCLK_DIV_2, - SPI_BAUD_PCLK_DIV_4, - SPI_BAUD_PCLK_DIV_8, - SPI_BAUD_PCLK_DIV_16, - SPI_BAUD_PCLK_DIV_32, - SPI_BAUD_PCLK_DIV_64, - SPI_BAUD_PCLK_DIV_128, - SPI_BAUD_PCLK_DIV_256, + SPI_BAUD_PCLK_DIV_2, + SPI_BAUD_PCLK_DIV_4, + SPI_BAUD_PCLK_DIV_8, + SPI_BAUD_PCLK_DIV_16, + SPI_BAUD_PCLK_DIV_32, + SPI_BAUD_PCLK_DIV_64, + SPI_BAUD_PCLK_DIV_128, + SPI_BAUD_PCLK_DIV_256, }; /* @@ -769,22 +769,22 @@ static const spi_baud_rate baud_rates[8] __FLASH__ = { * (CYCLES_PER_MICROSECOND == 72, APB2 at 72MHz, APB1 at 36MHz). */ static spi_baud_rate determine_baud_rate(spi_dev *dev, uint32_t freq) { - uint32_t clock = 0, i; - #ifdef SPI_DEBUG - Serial.print("determine_baud_rate("); Serial.print(freq); Serial.println(")"); - #endif - switch (rcc_dev_clk(dev->clk_id)) - { - case RCC_APB2: clock = STM32_PCLK2; break; // 72 Mhz - case RCC_APB1: clock = STM32_PCLK1; break; // 36 Mhz - } - clock /= 2; - i = 0; - while (i < 7 && freq < clock) { - clock /= 2; - i++; - } - return baud_rates[i]; + uint32_t clock = 0, i; + #ifdef SPI_DEBUG + Serial.print("determine_baud_rate("); Serial.print(freq); Serial.println(")"); + #endif + switch (rcc_dev_clk(dev->clk_id)) + { + case RCC_APB2: clock = STM32_PCLK2; break; // 72 Mhz + case RCC_APB1: clock = STM32_PCLK1; break; // 36 Mhz + } + clock /= 2; + i = 0; + while (i < 7 && freq < clock) { + clock /= 2; + i++; + } + return baud_rates[i]; } SPIClass SPI(1); From 0393be34008f663b99141d46a9919b901e522dac Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Sat, 15 Jul 2017 18:31:02 +1000 Subject: [PATCH 115/351] Added setClock() to Wire and Hardware - only 100000Hz and 400000Hz are supported --- STM32F1/libraries/Wire/HardWire.cpp | 15 +++++++++++++++ STM32F1/libraries/Wire/HardWire.h | 1 + STM32F1/libraries/Wire/Wire.cpp | 26 ++++++++++++++++++++++++-- STM32F1/libraries/Wire/Wire.h | 9 ++++++++- 4 files changed, 48 insertions(+), 3 deletions(-) diff --git a/STM32F1/libraries/Wire/HardWire.cpp b/STM32F1/libraries/Wire/HardWire.cpp index d81f584..51af7ad 100644 --- a/STM32F1/libraries/Wire/HardWire.cpp +++ b/STM32F1/libraries/Wire/HardWire.cpp @@ -84,3 +84,18 @@ void HardWire::end() { i2c_disable(sel_hard); sel_hard = 0; } + +void HardWire::setClock(uint32_t frequencyHz) +{ + switch(frequencyHz) + { + case 400000: + dev_flags |= I2C_FAST_MODE;// set FAST_MODE bit + break; + case 100000: + default: + dev_flags &= ~I2C_FAST_MODE;// clear FAST_MODE bit + break; + } + +} diff --git a/STM32F1/libraries/Wire/HardWire.h b/STM32F1/libraries/Wire/HardWire.h index bf59a2f..4d49e1a 100644 --- a/STM32F1/libraries/Wire/HardWire.h +++ b/STM32F1/libraries/Wire/HardWire.h @@ -66,6 +66,7 @@ public: */ void end(); + void setClock(uint32_t frequencyHz); /* * Disables the I2C device and remove the device address. */ diff --git a/STM32F1/libraries/Wire/Wire.cpp b/STM32F1/libraries/Wire/Wire.cpp index fff850b..712adf4 100644 --- a/STM32F1/libraries/Wire/Wire.cpp +++ b/STM32F1/libraries/Wire/Wire.cpp @@ -56,7 +56,9 @@ void TwoWire::set_scl(bool state) { I2C_DELAY(this->i2c_delay); - digitalWrite(this->scl_pin,state); + + gpio_write_bit(sclDevice,sclBit, state); +// digitalWrite(this->scl_pin,state); //Allow for clock stretching - dangerous currently if (state == HIGH) { while(digitalRead(this->scl_pin) == 0); @@ -65,7 +67,8 @@ void TwoWire::set_scl(bool state) { void TwoWire::set_sda(bool state) { I2C_DELAY(this->i2c_delay); - digitalWrite(this->sda_pin, state); + gpio_write_bit(sdaDevice,sdaBit, state); + //digitalWrite(this->sda_pin, state); } void TwoWire::i2c_start() { @@ -198,6 +201,11 @@ void TwoWire::begin(uint8 self_addr) { rx_buf_len = 0; pinMode(this->scl_pin, OUTPUT_OPEN_DRAIN); pinMode(this->sda_pin, OUTPUT_OPEN_DRAIN); + + sclDevice = PIN_MAP[this->scl_pin].gpio_device; + sclBit = PIN_MAP[this->scl_pin].gpio_bit; + sdaDevice = PIN_MAP[this->sda_pin].gpio_device; + sdaBit = PIN_MAP[this->sda_pin].gpio_bit; set_scl(HIGH); set_sda(HIGH); } @@ -214,6 +222,20 @@ void TwoWire::end() } } +void TwoWire::setClock(uint32_t frequencyHz) +{ + switch(frequencyHz) + { + case 400000: + i2c_delay = SOFT_FAST; + break; + case 100000: + default: + i2c_delay = SOFT_STANDARD; + break; + } +} + TwoWire::~TwoWire() { this->scl_pin=0; this->sda_pin=0; diff --git a/STM32F1/libraries/Wire/Wire.h b/STM32F1/libraries/Wire/Wire.h index df474da..8fbddaa 100644 --- a/STM32F1/libraries/Wire/Wire.h +++ b/STM32F1/libraries/Wire/Wire.h @@ -50,7 +50,7 @@ #define SDA PB7 #define SCL PB6 -#define SOFT_STANDARD 27 +#define SOFT_STANDARD 19 #define SOFT_FAST 0 @@ -126,6 +126,11 @@ class TwoWire : public WireBase { */ uint8 process(uint8); uint8 process(); + private: + gpio_dev *sdaDevice; + uint8 sdaBit; + gpio_dev *sclDevice; + uint8 sclBit; public: /* * Accept pin numbers for SCL and SDA lines. Set the delay needed @@ -139,6 +144,8 @@ class TwoWire : public WireBase { * .begin(uint8) in WireBase */ void begin(uint8 = 0x00); + + void setClock(uint32_t frequencyHz); /* * Sets pins SDA and SCL to INPUT From 4bfb444447905cd04c833d6538b6a0cee27f0d6a Mon Sep 17 00:00:00 2001 From: Cristi Marius Tiutiu Date: Mon, 17 Jul 2017 10:35:23 +0300 Subject: [PATCH 116/351] added teensy like ide compiler opts menus --- STM32F1/boards.txt | 417 ++++++++++++++++++++++++++++++++++++++++++- STM32F1/platform.txt | 10 +- STM32F3/boards.txt | 32 ++++ STM32F3/platform.txt | 8 +- STM32F4/boards.txt | 132 +++++++++++++- STM32F4/platform.txt | 8 +- 6 files changed, 592 insertions(+), 15 deletions(-) diff --git a/STM32F1/boards.txt b/STM32F1/boards.txt index 10a6591..b526236 100644 --- a/STM32F1/boards.txt +++ b/STM32F1/boards.txt @@ -4,6 +4,7 @@ menu.device_variant=Variant menu.bootloader_version=Bootloader version menu.upload_method=Upload method menu.cpu_speed=CPU Speed(MHz) +menu.opt=Optimize ############################################################## mapleMini.name=Maple Mini @@ -43,6 +44,38 @@ mapleMini.menu.cpu_speed.speed_72mhz.build.f_cpu=72000000L mapleMini.menu.cpu_speed.speed_48mhz=48Mhz (Slow - with USB) mapleMini.menu.cpu_speed.speed_48mhz.build.f_cpu=48000000L +#-- Optimizations +mapleMini.menu.opt.o2std=Faster +mapleMini.menu.opt.o2std.build.flags.optimize=-O2 +mapleMini.menu.opt.o2std.build.flags.ldspecs= +mapleMini.menu.opt.o2lto=Faster with LTO +mapleMini.menu.opt.o2lto.build.flags.optimize=-O2 -flto +mapleMini.menu.opt.o2lto.build.flags.ldspecs=-flto +mapleMini.menu.opt.o1std=Fast +mapleMini.menu.opt.o1std.build.flags.optimize=-O1 +mapleMini.menu.opt.o1std.build.flags.ldspecs= +mapleMini.menu.opt.o1lto=Fast with LTO +mapleMini.menu.opt.o1lto.build.flags.optimize=-O1 -flto +mapleMini.menu.opt.o1lto.build.flags.ldspecs=-flto +mapleMini.menu.opt.o3std=Fastest +mapleMini.menu.opt.o3std.build.flags.optimize=-O3 +mapleMini.menu.opt.o3std.build.flags.ldspecs= +mapleMini.menu.opt.o3lto=Fastest with LTO +mapleMini.menu.opt.o3lto.build.flags.optimize=-O3 -flto +mapleMini.menu.opt.o3lto.build.flags.ldspecs=-flto +mapleMini.menu.opt.ogstd=Debug +mapleMini.menu.opt.ogstd.build.flags.optimize=-Og +mapleMini.menu.opt.ogstd.build.flags.ldspecs= +mapleMini.menu.opt.oglto=Debug with LTO +mapleMini.menu.opt.oglto.build.flags.optimize=-Og -flto +mapleMini.menu.opt.oglto.build.flags.ldspecs=-flto +mapleMini.menu.opt.osstd=Smallest Code +mapleMini.menu.opt.osstd.build.flags.optimize=-Os +mapleMini.menu.opt.osstd.build.flags.ldspecs= +mapleMini.menu.opt.oslto=Smallest Code with LTO +mapleMini.menu.opt.oslto.build.flags.optimize=-Os -flto +mapleMini.menu.opt.oslto.build.flags.ldspecs=-flto + ############################################################## maple.name=Maple (Rev 3) @@ -66,6 +99,38 @@ maple.build.ldscript=ld/flash.ld maple.build.variant=maple maple.build.vect=VECT_TAB_ADDR=0x8005000 +#-- Optimizations +maple.menu.opt.o2std=Faster +maple.menu.opt.o2std.build.flags.optimize=-O2 +maple.menu.opt.o2std.build.flags.ldspecs= +maple.menu.opt.o2lto=Faster with LTO +maple.menu.opt.o2lto.build.flags.optimize=-O2 -flto +maple.menu.opt.o2lto.build.flags.ldspecs=-flto +maple.menu.opt.o1std=Fast +maple.menu.opt.o1std.build.flags.optimize=-O1 +maple.menu.opt.o1std.build.flags.ldspecs= +maple.menu.opt.o1lto=Fast with LTO +maple.menu.opt.o1lto.build.flags.optimize=-O1 -flto +maple.menu.opt.o1lto.build.flags.ldspecs=-flto +maple.menu.opt.o3std=Fastest +maple.menu.opt.o3std.build.flags.optimize=-O3 +maple.menu.opt.o3std.build.flags.ldspecs= +maple.menu.opt.o3lto=Fastest with LTO +maple.menu.opt.o3lto.build.flags.optimize=-O3 -flto +maple.menu.opt.o3lto.build.flags.ldspecs=-flto +maple.menu.opt.ogstd=Debug +maple.menu.opt.ogstd.build.flags.optimize=-Og +maple.menu.opt.ogstd.build.flags.ldspecs= +maple.menu.opt.oglto=Debug with LTO +maple.menu.opt.oglto.build.flags.optimize=-Og -flto +maple.menu.opt.oglto.build.flags.ldspecs=-flto +maple.menu.opt.osstd=Smallest Code +maple.menu.opt.osstd.build.flags.optimize=-Os +maple.menu.opt.osstd.build.flags.ldspecs= +maple.menu.opt.oslto=Smallest Code with LTO +maple.menu.opt.oslto.build.flags.optimize=-Os -flto +maple.menu.opt.oslto.build.flags.ldspecs=-flto + ############################################################## mapleRET6.name=Maple (RET6) @@ -89,6 +154,38 @@ mapleRET6.upload.usbID=1EAF:0003 mapleRET6.upload.altID=1 mapleRET6.upload.auto_reset=true +#-- Optimizations +mapleRET6.menu.opt.o2std=Faster +mapleRET6.menu.opt.o2std.build.flags.optimize=-O2 +mapleRET6.menu.opt.o2std.build.flags.ldspecs= +mapleRET6.menu.opt.o2lto=Faster with LTO +mapleRET6.menu.opt.o2lto.build.flags.optimize=-O2 -flto +mapleRET6.menu.opt.o2lto.build.flags.ldspecs=-flto +mapleRET6.menu.opt.o1std=Fast +mapleRET6.menu.opt.o1std.build.flags.optimize=-O1 +mapleRET6.menu.opt.o1std.build.flags.ldspecs= +mapleRET6.menu.opt.o1lto=Fast with LTO +mapleRET6.menu.opt.o1lto.build.flags.optimize=-O1 -flto +mapleRET6.menu.opt.o1lto.build.flags.ldspecs=-flto +mapleRET6.menu.opt.o3std=Fastest +mapleRET6.menu.opt.o3std.build.flags.optimize=-O3 +mapleRET6.menu.opt.o3std.build.flags.ldspecs= +mapleRET6.menu.opt.o3lto=Fastest with LTO +mapleRET6.menu.opt.o3lto.build.flags.optimize=-O3 -flto +mapleRET6.menu.opt.o3lto.build.flags.ldspecs=-flto +mapleRET6.menu.opt.ogstd=Debug +mapleRET6.menu.opt.ogstd.build.flags.optimize=-Og +mapleRET6.menu.opt.ogstd.build.flags.ldspecs= +mapleRET6.menu.opt.oglto=Debug with LTO +mapleRET6.menu.opt.oglto.build.flags.optimize=-Og -flto +mapleRET6.menu.opt.oglto.build.flags.ldspecs=-flto +mapleRET6.menu.opt.osstd=Smallest Code +mapleRET6.menu.opt.osstd.build.flags.optimize=-Os +mapleRET6.menu.opt.osstd.build.flags.ldspecs= +mapleRET6.menu.opt.oslto=Smallest Code with LTO +mapleRET6.menu.opt.oslto.build.flags.optimize=-Os -flto +mapleRET6.menu.opt.oslto.build.flags.ldspecs=-flto + ############################################################## microduino32_flash.name=Microduino Core STM32 to Flash @@ -120,6 +217,38 @@ microduino32_flash.build.error_led_port=GPIOB microduino32_flash.build.error_led_pin=1 microduino32_flash.build.gcc_ver=gcc-arm-none-eabi-4.8.3-2014q1 +#-- Optimizations +microduino32_flash.menu.opt.o2std=Faster +microduino32_flash.menu.opt.o2std.build.flags.optimize=-O2 +microduino32_flash.menu.opt.o2std.build.flags.ldspecs= +microduino32_flash.menu.opt.o2lto=Faster with LTO +microduino32_flash.menu.opt.o2lto.build.flags.optimize=-O2 -flto +microduino32_flash.menu.opt.o2lto.build.flags.ldspecs=-flto +microduino32_flash.menu.opt.o1std=Fast +microduino32_flash.menu.opt.o1std.build.flags.optimize=-O1 +microduino32_flash.menu.opt.o1std.build.flags.ldspecs= +microduino32_flash.menu.opt.o1lto=Fast with LTO +microduino32_flash.menu.opt.o1lto.build.flags.optimize=-O1 -flto +microduino32_flash.menu.opt.o1lto.build.flags.ldspecs=-flto +microduino32_flash.menu.opt.o3std=Fastest +microduino32_flash.menu.opt.o3std.build.flags.optimize=-O3 +microduino32_flash.menu.opt.o3std.build.flags.ldspecs= +microduino32_flash.menu.opt.o3lto=Fastest with LTO +microduino32_flash.menu.opt.o3lto.build.flags.optimize=-O3 -flto +microduino32_flash.menu.opt.o3lto.build.flags.ldspecs=-flto +microduino32_flash.menu.opt.ogstd=Debug +microduino32_flash.menu.opt.ogstd.build.flags.optimize=-Og +microduino32_flash.menu.opt.ogstd.build.flags.ldspecs= +microduino32_flash.menu.opt.oglto=Debug with LTO +microduino32_flash.menu.opt.oglto.build.flags.optimize=-Og -flto +microduino32_flash.menu.opt.oglto.build.flags.ldspecs=-flto +microduino32_flash.menu.opt.osstd=Smallest Code +microduino32_flash.menu.opt.osstd.build.flags.optimize=-Os +microduino32_flash.menu.opt.osstd.build.flags.ldspecs= +microduino32_flash.menu.opt.oslto=Smallest Code with LTO +microduino32_flash.menu.opt.oslto.build.flags.optimize=-Os -flto +microduino32_flash.menu.opt.oslto.build.flags.ldspecs=-flto + ############################################################## nucleo_f103rb.name=STM Nucleo F103RB (STLink) @@ -158,6 +287,38 @@ nucleo_f103rb.menu.device_variant.NucleoF103_HSE=Nucleo F103 @ 72 MHz w/ crystal nucleo_f103rb.menu.device_variant.NucleoF103_HSE.build.f_cpu=72000000L nucleo_f103rb.menu.device_variant.NucleoF103_HSE.build.extra_flags=-DNUCLEO_HSE_CRYSTAL -DMCU_STM32F103RB -mthumb -march=armv7-m -D__STM32F1__ +#-- Optimizations +nucleo_f103rb.menu.opt.o2std=Faster +nucleo_f103rb.menu.opt.o2std.build.flags.optimize=-O2 +nucleo_f103rb.menu.opt.o2std.build.flags.ldspecs= +nucleo_f103rb.menu.opt.o2lto=Faster with LTO +nucleo_f103rb.menu.opt.o2lto.build.flags.optimize=-O2 -flto +nucleo_f103rb.menu.opt.o2lto.build.flags.ldspecs=-flto +nucleo_f103rb.menu.opt.o1std=Fast +nucleo_f103rb.menu.opt.o1std.build.flags.optimize=-O1 +nucleo_f103rb.menu.opt.o1std.build.flags.ldspecs= +nucleo_f103rb.menu.opt.o1lto=Fast with LTO +nucleo_f103rb.menu.opt.o1lto.build.flags.optimize=-O1 -flto +nucleo_f103rb.menu.opt.o1lto.build.flags.ldspecs=-flto +nucleo_f103rb.menu.opt.o3std=Fastest +nucleo_f103rb.menu.opt.o3std.build.flags.optimize=-O3 +nucleo_f103rb.menu.opt.o3std.build.flags.ldspecs= +nucleo_f103rb.menu.opt.o3lto=Fastest with LTO +nucleo_f103rb.menu.opt.o3lto.build.flags.optimize=-O3 -flto +nucleo_f103rb.menu.opt.o3lto.build.flags.ldspecs=-flto +nucleo_f103rb.menu.opt.ogstd=Debug +nucleo_f103rb.menu.opt.ogstd.build.flags.optimize=-Og +nucleo_f103rb.menu.opt.ogstd.build.flags.ldspecs= +nucleo_f103rb.menu.opt.oglto=Debug with LTO +nucleo_f103rb.menu.opt.oglto.build.flags.optimize=-Og -flto +nucleo_f103rb.menu.opt.oglto.build.flags.ldspecs=-flto +nucleo_f103rb.menu.opt.osstd=Smallest Code +nucleo_f103rb.menu.opt.osstd.build.flags.optimize=-Os +nucleo_f103rb.menu.opt.osstd.build.flags.ldspecs= +nucleo_f103rb.menu.opt.oslto=Smallest Code with LTO +nucleo_f103rb.menu.opt.oslto.build.flags.optimize=-Os -flto +nucleo_f103rb.menu.opt.oslto.build.flags.ldspecs=-flto + ###################### Generic STM32F103C ######################################## genericSTM32F103C.name=Generic STM32F103C series @@ -223,6 +384,38 @@ genericSTM32F103C.menu.cpu_speed.speed_72mhz.build.f_cpu=72000000L genericSTM32F103C.menu.cpu_speed.speed_48mhz=48Mhz (Slow - with USB) genericSTM32F103C.menu.cpu_speed.speed_48mhz.build.f_cpu=48000000L +#-- Optimizations +genericSTM32F103C.menu.opt.o2std=Faster +genericSTM32F103C.menu.opt.o2std.build.flags.optimize=-O2 +genericSTM32F103C.menu.opt.o2std.build.flags.ldspecs= +genericSTM32F103C.menu.opt.o2lto=Faster with LTO +genericSTM32F103C.menu.opt.o2lto.build.flags.optimize=-O2 -flto +genericSTM32F103C.menu.opt.o2lto.build.flags.ldspecs=-flto +genericSTM32F103C.menu.opt.o1std=Fast +genericSTM32F103C.menu.opt.o1std.build.flags.optimize=-O1 +genericSTM32F103C.menu.opt.o1std.build.flags.ldspecs= +genericSTM32F103C.menu.opt.o1lto=Fast with LTO +genericSTM32F103C.menu.opt.o1lto.build.flags.optimize=-O1 -flto +genericSTM32F103C.menu.opt.o1lto.build.flags.ldspecs=-flto +genericSTM32F103C.menu.opt.o3std=Fastest +genericSTM32F103C.menu.opt.o3std.build.flags.optimize=-O3 +genericSTM32F103C.menu.opt.o3std.build.flags.ldspecs= +genericSTM32F103C.menu.opt.o3lto=Fastest with LTO +genericSTM32F103C.menu.opt.o3lto.build.flags.optimize=-O3 -flto +genericSTM32F103C.menu.opt.o3lto.build.flags.ldspecs=-flto +genericSTM32F103C.menu.opt.ogstd=Debug +genericSTM32F103C.menu.opt.ogstd.build.flags.optimize=-Og +genericSTM32F103C.menu.opt.ogstd.build.flags.ldspecs= +genericSTM32F103C.menu.opt.oglto=Debug with LTO +genericSTM32F103C.menu.opt.oglto.build.flags.optimize=-Og -flto +genericSTM32F103C.menu.opt.oglto.build.flags.ldspecs=-flto +genericSTM32F103C.menu.opt.osstd=Smallest Code +genericSTM32F103C.menu.opt.osstd.build.flags.optimize=-Os +genericSTM32F103C.menu.opt.osstd.build.flags.ldspecs= +genericSTM32F103C.menu.opt.oslto=Smallest Code with LTO +genericSTM32F103C.menu.opt.oslto.build.flags.optimize=-Os -flto +genericSTM32F103C.menu.opt.oslto.build.flags.ldspecs=-flto + ########################### Generic STM32F103R ########################### genericSTM32F103R.name=Generic STM32F103R series @@ -292,6 +485,38 @@ genericSTM32F103R.menu.upload_method.BMPMethod.upload.protocol=gdb_bmp genericSTM32F103R.menu.upload_method.BMPMethod.upload.tool=bmp_upload genericSTM32F103R.menu.upload_method.BMPMethod.build.upload_flags=-DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG +#-- Optimizations +genericSTM32F103R.menu.opt.o2std=Faster +genericSTM32F103R.menu.opt.o2std.build.flags.optimize=-O2 +genericSTM32F103R.menu.opt.o2std.build.flags.ldspecs= +genericSTM32F103R.menu.opt.o2lto=Faster with LTO +genericSTM32F103R.menu.opt.o2lto.build.flags.optimize=-O2 -flto +genericSTM32F103R.menu.opt.o2lto.build.flags.ldspecs=-flto +genericSTM32F103R.menu.opt.o1std=Fast +genericSTM32F103R.menu.opt.o1std.build.flags.optimize=-O1 +genericSTM32F103R.menu.opt.o1std.build.flags.ldspecs= +genericSTM32F103R.menu.opt.o1lto=Fast with LTO +genericSTM32F103R.menu.opt.o1lto.build.flags.optimize=-O1 -flto +genericSTM32F103R.menu.opt.o1lto.build.flags.ldspecs=-flto +genericSTM32F103R.menu.opt.o3std=Fastest +genericSTM32F103R.menu.opt.o3std.build.flags.optimize=-O3 +genericSTM32F103R.menu.opt.o3std.build.flags.ldspecs= +genericSTM32F103R.menu.opt.o3lto=Fastest with LTO +genericSTM32F103R.menu.opt.o3lto.build.flags.optimize=-O3 -flto +genericSTM32F103R.menu.opt.o3lto.build.flags.ldspecs=-flto +genericSTM32F103R.menu.opt.ogstd=Debug +genericSTM32F103R.menu.opt.ogstd.build.flags.optimize=-Og +genericSTM32F103R.menu.opt.ogstd.build.flags.ldspecs= +genericSTM32F103R.menu.opt.oglto=Debug with LTO +genericSTM32F103R.menu.opt.oglto.build.flags.optimize=-Og -flto +genericSTM32F103R.menu.opt.oglto.build.flags.ldspecs=-flto +genericSTM32F103R.menu.opt.osstd=Smallest Code +genericSTM32F103R.menu.opt.osstd.build.flags.optimize=-Os +genericSTM32F103R.menu.opt.osstd.build.flags.ldspecs= +genericSTM32F103R.menu.opt.oslto=Smallest Code with LTO +genericSTM32F103R.menu.opt.oslto.build.flags.optimize=-Os -flto +genericSTM32F103R.menu.opt.oslto.build.flags.ldspecs=-flto + ###################### Generic STM32F103T ######################################## genericSTM32F103T.name=Generic STM32F103T series @@ -345,6 +570,38 @@ genericSTM32F103T.menu.upload_method.BMPMethod.upload.protocol=gdb_bmp genericSTM32F103T.menu.upload_method.BMPMethod.upload.tool=bmp_upload genericSTM32F103T.menu.upload_method.BMPMethod.build.upload_flags=-DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG +#-- Optimizations +genericSTM32F103T.menu.opt.o2std=Faster +genericSTM32F103T.menu.opt.o2std.build.flags.optimize=-O2 +genericSTM32F103T.menu.opt.o2std.build.flags.ldspecs= +genericSTM32F103T.menu.opt.o2lto=Faster with LTO +genericSTM32F103T.menu.opt.o2lto.build.flags.optimize=-O2 -flto +genericSTM32F103T.menu.opt.o2lto.build.flags.ldspecs=-flto +genericSTM32F103T.menu.opt.o1std=Fast +genericSTM32F103T.menu.opt.o1std.build.flags.optimize=-O1 +genericSTM32F103T.menu.opt.o1std.build.flags.ldspecs= +genericSTM32F103T.menu.opt.o1lto=Fast with LTO +genericSTM32F103T.menu.opt.o1lto.build.flags.optimize=-O1 -flto +genericSTM32F103T.menu.opt.o1lto.build.flags.ldspecs=-flto +genericSTM32F103T.menu.opt.o3std=Fastest +genericSTM32F103T.menu.opt.o3std.build.flags.optimize=-O3 +genericSTM32F103T.menu.opt.o3std.build.flags.ldspecs= +genericSTM32F103T.menu.opt.o3lto=Fastest with LTO +genericSTM32F103T.menu.opt.o3lto.build.flags.optimize=-O3 -flto +genericSTM32F103T.menu.opt.o3lto.build.flags.ldspecs=-flto +genericSTM32F103T.menu.opt.ogstd=Debug +genericSTM32F103T.menu.opt.ogstd.build.flags.optimize=-Og +genericSTM32F103T.menu.opt.ogstd.build.flags.ldspecs= +genericSTM32F103T.menu.opt.oglto=Debug with LTO +genericSTM32F103T.menu.opt.oglto.build.flags.optimize=-Og -flto +genericSTM32F103T.menu.opt.oglto.build.flags.ldspecs=-flto +genericSTM32F103T.menu.opt.osstd=Smallest Code +genericSTM32F103T.menu.opt.osstd.build.flags.optimize=-Os +genericSTM32F103T.menu.opt.osstd.build.flags.ldspecs= +genericSTM32F103T.menu.opt.oslto=Smallest Code with LTO +genericSTM32F103T.menu.opt.oslto.build.flags.optimize=-Os -flto +genericSTM32F103T.menu.opt.oslto.build.flags.ldspecs=-flto + ########################### Generic STM32F103V ########################### genericSTM32F103V.name=Generic STM32F103V series @@ -405,6 +662,38 @@ genericSTM32F103V.menu.upload_method.BMPMethod.upload.protocol=gdb_bmp genericSTM32F103V.menu.upload_method.BMPMethod.upload.tool=bmp_upload genericSTM32F103V.menu.upload_method.BMPMethod.build.upload_flags=-DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG +#-- Optimizations +genericSTM32F103V.menu.opt.o2std=Faster +genericSTM32F103V.menu.opt.o2std.build.flags.optimize=-O2 +genericSTM32F103V.menu.opt.o2std.build.flags.ldspecs= +genericSTM32F103V.menu.opt.o2lto=Faster with LTO +genericSTM32F103V.menu.opt.o2lto.build.flags.optimize=-O2 -flto +genericSTM32F103V.menu.opt.o2lto.build.flags.ldspecs=-flto +genericSTM32F103V.menu.opt.o1std=Fast +genericSTM32F103V.menu.opt.o1std.build.flags.optimize=-O1 +genericSTM32F103V.menu.opt.o1std.build.flags.ldspecs= +genericSTM32F103V.menu.opt.o1lto=Fast with LTO +genericSTM32F103V.menu.opt.o1lto.build.flags.optimize=-O1 -flto +genericSTM32F103V.menu.opt.o1lto.build.flags.ldspecs=-flto +genericSTM32F103V.menu.opt.o3std=Fastest +genericSTM32F103V.menu.opt.o3std.build.flags.optimize=-O3 +genericSTM32F103V.menu.opt.o3std.build.flags.ldspecs= +genericSTM32F103V.menu.opt.o3lto=Fastest with LTO +genericSTM32F103V.menu.opt.o3lto.build.flags.optimize=-O3 -flto +genericSTM32F103V.menu.opt.o3lto.build.flags.ldspecs=-flto +genericSTM32F103V.menu.opt.ogstd=Debug +genericSTM32F103V.menu.opt.ogstd.build.flags.optimize=-Og +genericSTM32F103V.menu.opt.ogstd.build.flags.ldspecs= +genericSTM32F103V.menu.opt.oglto=Debug with LTO +genericSTM32F103V.menu.opt.oglto.build.flags.optimize=-Og -flto +genericSTM32F103V.menu.opt.oglto.build.flags.ldspecs=-flto +genericSTM32F103V.menu.opt.osstd=Smallest Code +genericSTM32F103V.menu.opt.osstd.build.flags.optimize=-Os +genericSTM32F103V.menu.opt.osstd.build.flags.ldspecs= +genericSTM32F103V.menu.opt.oslto=Smallest Code with LTO +genericSTM32F103V.menu.opt.oslto.build.flags.optimize=-Os -flto +genericSTM32F103V.menu.opt.oslto.build.flags.ldspecs=-flto + ########################### Generic STM32F103Z ########################### genericSTM32F103Z.name=Generic STM32F103Z series @@ -462,6 +751,38 @@ genericSTM32F103Z.menu.upload_method.BMPMethod.upload.protocol=gdb_bmp genericSTM32F103Z.menu.upload_method.BMPMethod.upload.tool=bmp_upload genericSTM32F103Z.menu.upload_method.BMPMethod.build.upload_flags=-DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG +#-- Optimizations +genericSTM32F103Z.menu.opt.o2std=Faster +genericSTM32F103Z.menu.opt.o2std.build.flags.optimize=-O2 +genericSTM32F103Z.menu.opt.o2std.build.flags.ldspecs= +genericSTM32F103Z.menu.opt.o2lto=Faster with LTO +genericSTM32F103Z.menu.opt.o2lto.build.flags.optimize=-O2 -flto +genericSTM32F103Z.menu.opt.o2lto.build.flags.ldspecs=-flto +genericSTM32F103Z.menu.opt.o1std=Fast +genericSTM32F103Z.menu.opt.o1std.build.flags.optimize=-O1 +genericSTM32F103Z.menu.opt.o1std.build.flags.ldspecs= +genericSTM32F103Z.menu.opt.o1lto=Fast with LTO +genericSTM32F103Z.menu.opt.o1lto.build.flags.optimize=-O1 -flto +genericSTM32F103Z.menu.opt.o1lto.build.flags.ldspecs=-flto +genericSTM32F103Z.menu.opt.o3std=Fastest +genericSTM32F103Z.menu.opt.o3std.build.flags.optimize=-O3 +genericSTM32F103Z.menu.opt.o3std.build.flags.ldspecs= +genericSTM32F103Z.menu.opt.o3lto=Fastest with LTO +genericSTM32F103Z.menu.opt.o3lto.build.flags.optimize=-O3 -flto +genericSTM32F103Z.menu.opt.o3lto.build.flags.ldspecs=-flto +genericSTM32F103Z.menu.opt.ogstd=Debug +genericSTM32F103Z.menu.opt.ogstd.build.flags.optimize=-Og +genericSTM32F103Z.menu.opt.ogstd.build.flags.ldspecs= +genericSTM32F103Z.menu.opt.oglto=Debug with LTO +genericSTM32F103Z.menu.opt.oglto.build.flags.optimize=-Og -flto +genericSTM32F103Z.menu.opt.oglto.build.flags.ldspecs=-flto +genericSTM32F103Z.menu.opt.osstd=Smallest Code +genericSTM32F103Z.menu.opt.osstd.build.flags.optimize=-Os +genericSTM32F103Z.menu.opt.osstd.build.flags.ldspecs= +genericSTM32F103Z.menu.opt.oslto=Smallest Code with LTO +genericSTM32F103Z.menu.opt.oslto.build.flags.optimize=-Os -flto +genericSTM32F103Z.menu.opt.oslto.build.flags.ldspecs=-flto + ###################### HYTiny STM32F103T ######################################## hytiny-stm32f103t.name=HYTiny STM32F103TB @@ -513,6 +834,37 @@ hytiny-stm32f103t.menu.upload_method.jlinkMethod.upload.protocol=jlink hytiny-stm32f103t.menu.upload_method.jlinkMethod.upload.tool=jlink_upload hytiny-stm32f103t.menu.upload_method.jlinkMethod.build.upload_flags=-DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG=1 -DSERIAL_USB -DGENERIC_BOOTLOADER +#-- Optimizations +hytiny-stm32f103t.menu.opt.o2std=Faster +hytiny-stm32f103t.menu.opt.o2std.build.flags.optimize=-O2 +hytiny-stm32f103t.menu.opt.o2std.build.flags.ldspecs= +hytiny-stm32f103t.menu.opt.o2lto=Faster with LTO +hytiny-stm32f103t.menu.opt.o2lto.build.flags.optimize=-O2 -flto +hytiny-stm32f103t.menu.opt.o2lto.build.flags.ldspecs=-flto +hytiny-stm32f103t.menu.opt.o1std=Fast +hytiny-stm32f103t.menu.opt.o1std.build.flags.optimize=-O1 +hytiny-stm32f103t.menu.opt.o1std.build.flags.ldspecs= +hytiny-stm32f103t.menu.opt.o1lto=Fast with LTO +hytiny-stm32f103t.menu.opt.o1lto.build.flags.optimize=-O1 -flto +hytiny-stm32f103t.menu.opt.o1lto.build.flags.ldspecs=-flto +hytiny-stm32f103t.menu.opt.o3std=Fastest +hytiny-stm32f103t.menu.opt.o3std.build.flags.optimize=-O3 +hytiny-stm32f103t.menu.opt.o3std.build.flags.ldspecs= +hytiny-stm32f103t.menu.opt.o3lto=Fastest with LTO +hytiny-stm32f103t.menu.opt.o3lto.build.flags.optimize=-O3 -flto +hytiny-stm32f103t.menu.opt.o3lto.build.flags.ldspecs=-flto +hytiny-stm32f103t.menu.opt.ogstd=Debug +hytiny-stm32f103t.menu.opt.ogstd.build.flags.optimize=-Og +hytiny-stm32f103t.menu.opt.ogstd.build.flags.ldspecs= +hytiny-stm32f103t.menu.opt.oglto=Debug with LTO +hytiny-stm32f103t.menu.opt.oglto.build.flags.optimize=-Og -flto +hytiny-stm32f103t.menu.opt.oglto.build.flags.ldspecs=-flto +hytiny-stm32f103t.menu.opt.osstd=Smallest Code +hytiny-stm32f103t.menu.opt.osstd.build.flags.optimize=-Os +hytiny-stm32f103t.menu.opt.osstd.build.flags.ldspecs= +hytiny-stm32f103t.menu.opt.oslto=Smallest Code with LTO +hytiny-stm32f103t.menu.opt.oslto.build.flags.optimize=-Os -flto +hytiny-stm32f103t.menu.opt.oslto.build.flags.ldspecs=-flto ###################### Generic GD32F103C ######################################## @@ -576,6 +928,38 @@ genericGD32F103C.menu.cpu_speed.speed_96mhz.build.f_cpu=96000000L genericGD32F103C.menu.cpu_speed.speed_72mhz=72Mhz (compatibility) genericGD32F103C.menu.cpu_speed.speed_72mhz.build.f_cpu=72000000L +#-- Optimizations +genericGD32F103C.menu.opt.o2std=Faster +genericGD32F103C.menu.opt.o2std.build.flags.optimize=-O2 +genericGD32F103C.menu.opt.o2std.build.flags.ldspecs= +genericGD32F103C.menu.opt.o2lto=Faster with LTO +genericGD32F103C.menu.opt.o2lto.build.flags.optimize=-O2 -flto +genericGD32F103C.menu.opt.o2lto.build.flags.ldspecs=-flto +genericGD32F103C.menu.opt.o1std=Fast +genericGD32F103C.menu.opt.o1std.build.flags.optimize=-O1 +genericGD32F103C.menu.opt.o1std.build.flags.ldspecs= +genericGD32F103C.menu.opt.o1lto=Fast with LTO +genericGD32F103C.menu.opt.o1lto.build.flags.optimize=-O1 -flto +genericGD32F103C.menu.opt.o1lto.build.flags.ldspecs=-flto +genericGD32F103C.menu.opt.o3std=Fastest +genericGD32F103C.menu.opt.o3std.build.flags.optimize=-O3 +genericGD32F103C.menu.opt.o3std.build.flags.ldspecs= +genericGD32F103C.menu.opt.o3lto=Fastest with LTO +genericGD32F103C.menu.opt.o3lto.build.flags.optimize=-O3 -flto +genericGD32F103C.menu.opt.o3lto.build.flags.ldspecs=-flto +genericGD32F103C.menu.opt.ogstd=Debug +genericGD32F103C.menu.opt.ogstd.build.flags.optimize=-Og +genericGD32F103C.menu.opt.ogstd.build.flags.ldspecs= +genericGD32F103C.menu.opt.oglto=Debug with LTO +genericGD32F103C.menu.opt.oglto.build.flags.optimize=-Og -flto +genericGD32F103C.menu.opt.oglto.build.flags.ldspecs=-flto +genericGD32F103C.menu.opt.osstd=Smallest Code +genericGD32F103C.menu.opt.osstd.build.flags.optimize=-Os +genericGD32F103C.menu.opt.osstd.build.flags.ldspecs= +genericGD32F103C.menu.opt.oslto=Smallest Code with LTO +genericGD32F103C.menu.opt.oslto.build.flags.optimize=-Os -flto +genericGD32F103C.menu.opt.oslto.build.flags.ldspecs=-flto + ########################### STM32VLD to FLASH ########################### STM32VLD.name=STM32VLD to FLASH @@ -604,5 +988,36 @@ STM32VLD.menu.upload_method.STLinkMethod.upload.protocol=STLink STM32VLD.menu.upload_method.STLinkMethod.upload.tool=stlink_upload STM32VLD.menu.upload_method.STLinkMethod.build.upload_flags=-DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG +#-- Optimizations +STM32VLD.menu.opt.o2std=Faster +STM32VLD.menu.opt.o2std.build.flags.optimize=-O2 +STM32VLD.menu.opt.o2std.build.flags.ldspecs= +STM32VLD.menu.opt.o2lto=Faster with LTO +STM32VLD.menu.opt.o2lto.build.flags.optimize=-O2 -flto +STM32VLD.menu.opt.o2lto.build.flags.ldspecs=-flto +STM32VLD.menu.opt.o1std=Fast +STM32VLD.menu.opt.o1std.build.flags.optimize=-O1 +STM32VLD.menu.opt.o1std.build.flags.ldspecs= +STM32VLD.menu.opt.o1lto=Fast with LTO +STM32VLD.menu.opt.o1lto.build.flags.optimize=-O1 -flto +STM32VLD.menu.opt.o1lto.build.flags.ldspecs=-flto +STM32VLD.menu.opt.o3std=Fastest +STM32VLD.menu.opt.o3std.build.flags.optimize=-O3 +STM32VLD.menu.opt.o3std.build.flags.ldspecs= +STM32VLD.menu.opt.o3lto=Fastest with LTO +STM32VLD.menu.opt.o3lto.build.flags.optimize=-O3 -flto +STM32VLD.menu.opt.o3lto.build.flags.ldspecs=-flto +STM32VLD.menu.opt.ogstd=Debug +STM32VLD.menu.opt.ogstd.build.flags.optimize=-Og +STM32VLD.menu.opt.ogstd.build.flags.ldspecs= +STM32VLD.menu.opt.oglto=Debug with LTO +STM32VLD.menu.opt.oglto.build.flags.optimize=-Og -flto +STM32VLD.menu.opt.oglto.build.flags.ldspecs=-flto +STM32VLD.menu.opt.osstd=Smallest Code +STM32VLD.menu.opt.osstd.build.flags.optimize=-Os +STM32VLD.menu.opt.osstd.build.flags.ldspecs= +STM32VLD.menu.opt.oslto=Smallest Code with LTO +STM32VLD.menu.opt.oslto.build.flags.optimize=-Os -flto +STM32VLD.menu.opt.oslto.build.flags.ldspecs=-flto -################################################################################ +################################################################################ \ No newline at end of file diff --git a/STM32F1/platform.txt b/STM32F1/platform.txt index 3da3070..de1f206 100644 --- a/STM32F1/platform.txt +++ b/STM32F1/platform.txt @@ -16,20 +16,20 @@ 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} -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.flags=-c -g {build.flags.optimize} {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.c.elf.flags={build.flags.optimize} -Wl,--gc-sections {build.flags.ldspecs} 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} -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.cpp.flags=-c -g {build.flags.optimize} {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 compiler.objcopy.eep.flags=-O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 compiler.elf2hex.flags=-O binary compiler.elf2hex.cmd=arm-none-eabi-objcopy -compiler.ldflags= +compiler.ldflags={build.flags.ldspecs} compiler.size.cmd=arm-none-eabi-size compiler.define=-DARDUINO= @@ -160,4 +160,4 @@ tools.jlink_upload.path.linux={runtime.hardware.path}/tools/linux tools.jlink_upload.path.linux64={runtime.hardware.path}/tools/linux64 tools.jlink_upload.upload.params.verbose=-d tools.jlink_upload.upload.params.quiet=n -tools.jlink_upload.upload.pattern="{path}/{cmd}" "{build.path}/{build.project_name}.bin" +tools.jlink_upload.upload.pattern="{path}/{cmd}" "{build.path}/{build.project_name}.bin" \ No newline at end of file diff --git a/STM32F3/boards.txt b/STM32F3/boards.txt index 6c011bc..bfe24bb 100644 --- a/STM32F3/boards.txt +++ b/STM32F3/boards.txt @@ -28,5 +28,37 @@ discovery_f3.build.error_led_port=GPIOE discovery_f3.build.error_led_pin=8 discovery_f3.build.board=STM32F3Discovery +#-- Optimizations +discovery_f3.menu.opt.o2std=Faster +discovery_f3.menu.opt.o2std.build.flags.optimize=-O2 +discovery_f3.menu.opt.o2std.build.flags.ldspecs= +discovery_f3.menu.opt.o2lto=Faster with LTO +discovery_f3.menu.opt.o2lto.build.flags.optimize=-O2 -flto +discovery_f3.menu.opt.o2lto.build.flags.ldspecs=-flto +discovery_f3.menu.opt.o1std=Fast +discovery_f3.menu.opt.o1std.build.flags.optimize=-O1 +discovery_f3.menu.opt.o1std.build.flags.ldspecs= +discovery_f3.menu.opt.o1lto=Fast with LTO +discovery_f3.menu.opt.o1lto.build.flags.optimize=-O1 -flto +discovery_f3.menu.opt.o1lto.build.flags.ldspecs=-flto +discovery_f3.menu.opt.o3std=Fastest +discovery_f3.menu.opt.o3std.build.flags.optimize=-O3 +discovery_f3.menu.opt.o3std.build.flags.ldspecs= +discovery_f3.menu.opt.o3lto=Fastest with LTO +discovery_f3.menu.opt.o3lto.build.flags.optimize=-O3 -flto +discovery_f3.menu.opt.o3lto.build.flags.ldspecs=-flto +discovery_f3.menu.opt.ogstd=Debug +discovery_f3.menu.opt.ogstd.build.flags.optimize=-Og +discovery_f3.menu.opt.ogstd.build.flags.ldspecs= +discovery_f3.menu.opt.oglto=Debug with LTO +discovery_f3.menu.opt.oglto.build.flags.optimize=-Og -flto +discovery_f3.menu.opt.oglto.build.flags.ldspecs=-flto +discovery_f3.menu.opt.osstd=Smallest Code +discovery_f3.menu.opt.osstd.build.flags.optimize=-Os +discovery_f3.menu.opt.osstd.build.flags.ldspecs= +discovery_f3.menu.opt.oslto=Smallest Code with LTO +discovery_f3.menu.opt.oslto.build.flags.optimize=-Os -flto +discovery_f3.menu.opt.oslto.build.flags.ldspecs=-flto + ############################################################## diff --git a/STM32F3/platform.txt b/STM32F3/platform.txt index 3218f85..94f787c 100644 --- a/STM32F3/platform.txt +++ b/STM32F3/platform.txt @@ -12,20 +12,20 @@ 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 {build.flags.optimize} -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.elf.cmd=arm-none-eabi-g++ -compiler.c.elf.flags=-Os -Wl,--gc-sections +compiler.c.elf.flags={build.flags.optimize} -Wl,--gc-sections {build.flags.ldspecs} 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 {build.flags.optimize} -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.ar.cmd=arm-none-eabi-ar compiler.ar.flags=rcs compiler.objcopy.cmd=arm-none-eabi-objcopy compiler.objcopy.eep.flags=-O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 compiler.elf2hex.flags=-O binary compiler.elf2hex.cmd=arm-none-eabi-objcopy -compiler.ldflags= +compiler.ldflags={build.flags.ldspecs} compiler.size.cmd=arm-none-eabi-size compiler.define=-DARDUINO= diff --git a/STM32F4/boards.txt b/STM32F4/boards.txt index baf6f6e..25a9c31 100644 --- a/STM32F4/boards.txt +++ b/STM32F4/boards.txt @@ -36,6 +36,39 @@ discovery_f407.menu.usb_cfg.usb_serial=USB serial (CDC) discovery_f407.menu.usb_cfg.usb_serial.build.cpu_flags=-DSERIAL_USB discovery_f407.menu.usb_cfg.usb_msc=USB Mass Storage (MSC) discovery_f407.menu.usb_cfg.usb_msc.build.cpu_flags=-DUSB_MSC + +#-- Optimizations +discovery_f407.menu.opt.o2std=Faster +discovery_f407.menu.opt.o2std.build.flags.optimize=-O2 +discovery_f407.menu.opt.o2std.build.flags.ldspecs= +discovery_f407.menu.opt.o2lto=Faster with LTO +discovery_f407.menu.opt.o2lto.build.flags.optimize=-O2 -flto +discovery_f407.menu.opt.o2lto.build.flags.ldspecs=-flto +discovery_f407.menu.opt.o1std=Fast +discovery_f407.menu.opt.o1std.build.flags.optimize=-O1 +discovery_f407.menu.opt.o1std.build.flags.ldspecs= +discovery_f407.menu.opt.o1lto=Fast with LTO +discovery_f407.menu.opt.o1lto.build.flags.optimize=-O1 -flto +discovery_f407.menu.opt.o1lto.build.flags.ldspecs=-flto +discovery_f407.menu.opt.o3std=Fastest +discovery_f407.menu.opt.o3std.build.flags.optimize=-O3 +discovery_f407.menu.opt.o3std.build.flags.ldspecs= +discovery_f407.menu.opt.o3lto=Fastest with LTO +discovery_f407.menu.opt.o3lto.build.flags.optimize=-O3 -flto +discovery_f407.menu.opt.o3lto.build.flags.ldspecs=-flto +discovery_f407.menu.opt.ogstd=Debug +discovery_f407.menu.opt.ogstd.build.flags.optimize=-Og +discovery_f407.menu.opt.ogstd.build.flags.ldspecs= +discovery_f407.menu.opt.oglto=Debug with LTO +discovery_f407.menu.opt.oglto.build.flags.optimize=-Og -flto +discovery_f407.menu.opt.oglto.build.flags.ldspecs=-flto +discovery_f407.menu.opt.osstd=Smallest Code +discovery_f407.menu.opt.osstd.build.flags.optimize=-Os +discovery_f407.menu.opt.osstd.build.flags.ldspecs= +discovery_f407.menu.opt.oslto=Smallest Code with LTO +discovery_f407.menu.opt.oslto.build.flags.optimize=-Os -flto +discovery_f407.menu.opt.oslto.build.flags.ldspecs=-flto + ############################################################## generic_f407v.name=Generic STM32F407V series @@ -72,6 +105,38 @@ generic_f407v.menu.usb_cfg.usb_serial.build.cpu_flags=-DSERIAL_USB generic_f407v.menu.usb_cfg.usb_msc=USB Mass Storage (MSC) generic_f407v.menu.usb_cfg.usb_msc.build.cpu_flags=-DUSB_MSC +#-- Optimizations +generic_f407v.menu.opt.o2std=Faster +generic_f407v.menu.opt.o2std.build.flags.optimize=-O2 +generic_f407v.menu.opt.o2std.build.flags.ldspecs= +generic_f407v.menu.opt.o2lto=Faster with LTO +generic_f407v.menu.opt.o2lto.build.flags.optimize=-O2 -flto +generic_f407v.menu.opt.o2lto.build.flags.ldspecs=-flto +generic_f407v.menu.opt.o1std=Fast +generic_f407v.menu.opt.o1std.build.flags.optimize=-O1 +generic_f407v.menu.opt.o1std.build.flags.ldspecs= +generic_f407v.menu.opt.o1lto=Fast with LTO +generic_f407v.menu.opt.o1lto.build.flags.optimize=-O1 -flto +generic_f407v.menu.opt.o1lto.build.flags.ldspecs=-flto +generic_f407v.menu.opt.o3std=Fastest +generic_f407v.menu.opt.o3std.build.flags.optimize=-O3 +generic_f407v.menu.opt.o3std.build.flags.ldspecs= +generic_f407v.menu.opt.o3lto=Fastest with LTO +generic_f407v.menu.opt.o3lto.build.flags.optimize=-O3 -flto +generic_f407v.menu.opt.o3lto.build.flags.ldspecs=-flto +generic_f407v.menu.opt.ogstd=Debug +generic_f407v.menu.opt.ogstd.build.flags.optimize=-Og +generic_f407v.menu.opt.ogstd.build.flags.ldspecs= +generic_f407v.menu.opt.oglto=Debug with LTO +generic_f407v.menu.opt.oglto.build.flags.optimize=-Og -flto +generic_f407v.menu.opt.oglto.build.flags.ldspecs=-flto +generic_f407v.menu.opt.osstd=Smallest Code +generic_f407v.menu.opt.osstd.build.flags.optimize=-Os +generic_f407v.menu.opt.osstd.build.flags.ldspecs= +generic_f407v.menu.opt.oslto=Smallest Code with LTO +generic_f407v.menu.opt.oslto.build.flags.optimize=-Os -flto +generic_f407v.menu.opt.oslto.build.flags.ldspecs=-flto + ############################################################## stm32f4stamp.name=STM32F4Stamp F405 @@ -107,6 +172,39 @@ stm32f4stamp.menu.usb_cfg.usb_serial=USB serial (CDC) stm32f4stamp.menu.usb_cfg.usb_serial.build.cpu_flags=-DSERIAL_USB stm32f4stamp.menu.usb_cfg.usb_msc=USB Mass Storage (MSC) stm32f4stamp.menu.usb_cfg.usb_msc.build.cpu_flags=-DUSB_MSC + +#-- Optimizations +stm32f4stamp.menu.opt.o2std=Faster +stm32f4stamp.menu.opt.o2std.build.flags.optimize=-O2 +stm32f4stamp.menu.opt.o2std.build.flags.ldspecs= +stm32f4stamp.menu.opt.o2lto=Faster with LTO +stm32f4stamp.menu.opt.o2lto.build.flags.optimize=-O2 -flto +stm32f4stamp.menu.opt.o2lto.build.flags.ldspecs=-flto +stm32f4stamp.menu.opt.o1std=Fast +stm32f4stamp.menu.opt.o1std.build.flags.optimize=-O1 +stm32f4stamp.menu.opt.o1std.build.flags.ldspecs= +stm32f4stamp.menu.opt.o1lto=Fast with LTO +stm32f4stamp.menu.opt.o1lto.build.flags.optimize=-O1 -flto +stm32f4stamp.menu.opt.o1lto.build.flags.ldspecs=-flto +stm32f4stamp.menu.opt.o3std=Fastest +stm32f4stamp.menu.opt.o3std.build.flags.optimize=-O3 +stm32f4stamp.menu.opt.o3std.build.flags.ldspecs= +stm32f4stamp.menu.opt.o3lto=Fastest with LTO +stm32f4stamp.menu.opt.o3lto.build.flags.optimize=-O3 -flto +stm32f4stamp.menu.opt.o3lto.build.flags.ldspecs=-flto +stm32f4stamp.menu.opt.ogstd=Debug +stm32f4stamp.menu.opt.ogstd.build.flags.optimize=-Og +stm32f4stamp.menu.opt.ogstd.build.flags.ldspecs= +stm32f4stamp.menu.opt.oglto=Debug with LTO +stm32f4stamp.menu.opt.oglto.build.flags.optimize=-Og -flto +stm32f4stamp.menu.opt.oglto.build.flags.ldspecs=-flto +stm32f4stamp.menu.opt.osstd=Smallest Code +stm32f4stamp.menu.opt.osstd.build.flags.optimize=-Os +stm32f4stamp.menu.opt.osstd.build.flags.ldspecs= +stm32f4stamp.menu.opt.oslto=Smallest Code with LTO +stm32f4stamp.menu.opt.oslto.build.flags.optimize=-Os -flto +stm32f4stamp.menu.opt.oslto.build.flags.ldspecs=-flto + ############################################################## netduino2plus.name=Netduino2 F405 @@ -142,5 +240,37 @@ netduino2plus.menu.usb_cfg.usb_serial=USB serial (CDC) netduino2plus.menu.usb_cfg.usb_serial.build.cpu_flags=-DSERIAL_USB netduino2plus.menu.usb_cfg.usb_msc=USB Mass Storage (MSC) netduino2plus.menu.usb_cfg.usb_msc.build.cpu_flags=-DUSB_MSC -############################################################## +#-- Optimizations +netduino2plus.menu.opt.o2std=Faster +netduino2plus.menu.opt.o2std.build.flags.optimize=-O2 +netduino2plus.menu.opt.o2std.build.flags.ldspecs= +netduino2plus.menu.opt.o2lto=Faster with LTO +netduino2plus.menu.opt.o2lto.build.flags.optimize=-O2 -flto +netduino2plus.menu.opt.o2lto.build.flags.ldspecs=-flto +netduino2plus.menu.opt.o1std=Fast +netduino2plus.menu.opt.o1std.build.flags.optimize=-O1 +netduino2plus.menu.opt.o1std.build.flags.ldspecs= +netduino2plus.menu.opt.o1lto=Fast with LTO +netduino2plus.menu.opt.o1lto.build.flags.optimize=-O1 -flto +netduino2plus.menu.opt.o1lto.build.flags.ldspecs=-flto +netduino2plus.menu.opt.o3std=Fastest +netduino2plus.menu.opt.o3std.build.flags.optimize=-O3 +netduino2plus.menu.opt.o3std.build.flags.ldspecs= +netduino2plus.menu.opt.o3lto=Fastest with LTO +netduino2plus.menu.opt.o3lto.build.flags.optimize=-O3 -flto +netduino2plus.menu.opt.o3lto.build.flags.ldspecs=-flto +netduino2plus.menu.opt.ogstd=Debug +netduino2plus.menu.opt.ogstd.build.flags.optimize=-Og +netduino2plus.menu.opt.ogstd.build.flags.ldspecs= +netduino2plus.menu.opt.oglto=Debug with LTO +netduino2plus.menu.opt.oglto.build.flags.optimize=-Og -flto +netduino2plus.menu.opt.oglto.build.flags.ldspecs=-flto +netduino2plus.menu.opt.osstd=Smallest Code +netduino2plus.menu.opt.osstd.build.flags.optimize=-Os +netduino2plus.menu.opt.osstd.build.flags.ldspecs= +netduino2plus.menu.opt.oslto=Smallest Code with LTO +netduino2plus.menu.opt.oslto.build.flags.optimize=-Os -flto +netduino2plus.menu.opt.oslto.build.flags.ldspecs=-flto + +############################################################## diff --git a/STM32F4/platform.txt b/STM32F4/platform.txt index b64fe3e..92dc1ea 100755 --- a/STM32F4/platform.txt +++ b/STM32F4/platform.txt @@ -10,20 +10,20 @@ 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 -Wall -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.flags=-c -g {build.flags.optimize} -Wall -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.c.elf.flags={build.flags.optimize} -Wl,--gc-sections {build.flags.ldspecs} 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 -Wall -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.cpp.flags=-c -g {build.flags.optimize} -Wall -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 compiler.objcopy.eep.flags=-O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 compiler.elf2hex.flags=-O binary compiler.elf2hex.cmd=arm-none-eabi-objcopy -compiler.ldflags= +compiler.ldflags={build.flags.ldspecs} compiler.size.cmd=arm-none-eabi-size compiler.define=-DARDUINO= From 4f3c4da648a72633a17d0ed3c105a02df277489f Mon Sep 17 00:00:00 2001 From: Cristi Marius Tiutiu Date: Mon, 17 Jul 2017 10:45:37 +0300 Subject: [PATCH 117/351] added missing menu opts for F3/F4 boards --- STM32F3/boards.txt | 2 ++ STM32F4/boards.txt | 1 + 2 files changed, 3 insertions(+) diff --git a/STM32F3/boards.txt b/STM32F3/boards.txt index bfe24bb..d3a3735 100644 --- a/STM32F3/boards.txt +++ b/STM32F3/boards.txt @@ -1,5 +1,7 @@ # +menu.opt=Optimize + ############################################################## discovery_f3.name=STM32F3Discovery diff --git a/STM32F4/boards.txt b/STM32F4/boards.txt index 25a9c31..429ba4b 100644 --- a/STM32F4/boards.txt +++ b/STM32F4/boards.txt @@ -1,6 +1,7 @@ # menu.usb_cfg=USB configuration +menu.opt=Optimize ############################################################## discovery_f407.name=STM32 Discovery F407 From 01de9ee977a9335aed2b8dd07ff332c52a8f7386 Mon Sep 17 00:00:00 2001 From: Hemal Chevli Date: Wed, 19 Jul 2017 10:46:25 +0530 Subject: [PATCH 118/351] Fixed headings --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 7e13786..4ffc9ed 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,14 @@ Arduino STM32 ============= -##Notice +## Notice This software is experimental and a work in progress. Under no circumstances should these files be used in relation to any critical system(s). Use of these files is at your own risk. -##Summary: +## Summary: This repo contains, the "Hardware" files to support STM32 based boards on Arduino version 1.6.13 or 1.6.12 (some older versions may also work) including [LeafLabs Maple, and Maple mini](http://www.leaflabs.com/about-maple/), and other generic STM32F103 boards ***PRIMARY SUPPORT FORUM: http://www.stm32duino.com/*** @@ -16,7 +16,7 @@ This repo contains, the "Hardware" files to support STM32 based boards on Arduin ***We are also on Gitter https://gitter.im/stm32duino/Lobby/*** [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/stm32duino/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -##Background & Support: +## Background & Support: * Based on https://github.com/bobc/maple-asp, which is in turn based on LibMaple by Leaflabs * **Please read the wiki (https://github.com/rogerclarkmelbourne/Arduino_STM32/wiki) for full details** * See also my blog: http://www.rogerclark.net/stm32f103-and-maple-maple-mini-with-arduino-1-5-x-ide/ @@ -29,11 +29,11 @@ This repo contains, the "Hardware" files to support STM32 based boards on Arduin * 20150413: [STM32 for Arduino 1.6.2 or newer (update)](https://www.youtube.com/watch?v=TePglhSkghg) * 20150419: [Uploading via USB to Serial to STM32F103 boards](https://www.youtube.com/watch?v=G_RF0a0hrak) -##Additional Links & Info: +## Additional Links & Info: * https://www.hackster.io/rayburne/4-dollar-90-mips-32-bit-72-mhz-arm-arduino -##Purchase info: -###Entry level boards +## Purchase info: +### Entry level boards * [Ebay search for "arduino maple"](http://www.ebay.com/sch/i.html?_from=R40&_sacat=0&LH_BIN=1&_nkw=arduino+maple&_sop=15) (currently costs <$5 with shipping) * [AliExpress search for "leaflabs maple"] (http://www.aliexpress.com/wholesale?catId=0&initiative_id=SB_20150607085526&SearchText=leaflabs+maple) From b29fed855b440f3d55c627b9d4478940b7fff29d Mon Sep 17 00:00:00 2001 From: stevstrong Date: Wed, 19 Jul 2017 19:11:44 +0200 Subject: [PATCH 119/351] reworked RTC - no need for extra time library http://www.stm32duino.com/viewtopic.php?f=39&t=775&p=31218#p31218 --- .../examples/Test_RTClock/Test_RTClock.ino | 209 +++++++++++++ STM32F4/libraries/RTClock/library.properties | 1 + STM32F4/libraries/RTClock/src/RTClock.cpp | 293 ++++++++++-------- STM32F4/libraries/RTClock/src/RTClock.h | 136 ++++++-- 4 files changed, 485 insertions(+), 154 deletions(-) create mode 100644 STM32F4/libraries/RTClock/examples/Test_RTClock/Test_RTClock.ino diff --git a/STM32F4/libraries/RTClock/examples/Test_RTClock/Test_RTClock.ino b/STM32F4/libraries/RTClock/examples/Test_RTClock/Test_RTClock.ino new file mode 100644 index 0000000..ec6afa4 --- /dev/null +++ b/STM32F4/libraries/RTClock/examples/Test_RTClock/Test_RTClock.ino @@ -0,0 +1,209 @@ +/* + This is an example of how to use the RTclock of STM32F4 device + + This example can also be used to set the RTC to the current epoch time: + - goto: http://www.unixtimestamp.com/ + - enter the current date and time to the right field "Timestamp converter" + - press the "Convert" button + - +*/ + +#include + +#include + + +//RTClock rt(RTCSEL_LSE); // initialise +RTClock rtc; + +time_t tt; +tm_t tm; + +const uint32_t DEFAULT_TIME = 1498944019; // 2017.07.01, 21:20:19 used as reference epoch time + +#define TIME_HEADER 'T' // Header tag for serial time sync message +#define TIME_REQUEST 7 // ASCII bell character requests a time sync message + +#define LED_PIN BOARD_LED_PIN + +//----------------------------------------------------------------------------- +void blink () +{ + digitalWrite(LED_PIN, digitalRead(LED_PIN)?LOW:HIGH); +} + +uint8_t s[20]; // for serial parsing + +//----------------------------------------------------------------------------- +char * read_line() +{ + while ( Serial.available() ) Serial.read(); // empty Rx buffer + while ( Serial.available()<=0 ) ; // wait for new characters + uint8_t c, i = 0; + s[0] = 0; + while ( Serial.available() && (i<20) ) { + c = Serial.read(); + if ( c=='\n' || c== '\r') { + s[i] = 0; + break; + } + s[i++] = c; + } + while ( Serial.available() ) Serial.read(); // flush Rx + return (char*)&s[0]; +} + +//----------------------------------------------------------------------------- +void processSyncMessage(void) +{ + if ( Serial.available() ) { + if( *read_line()==(TIME_HEADER) ) { + uint32_t pctime = atoi((const char*)&s[1]); + Serial << ("Epoch time received: ") << pctime << endl; + if ( pctime >= DEFAULT_TIME) { // check the integer is a valid epoch time + rtc.setTime(pctime); // Set RTC to the time received via the serial port + } + } + Serial << endl; + } +} + +//----------------------------------------------------------------------------- +void Change_DateTime(void) +{ + // check and correct the weekday if necessary + rtc.getTime(tm); + Serial << "Current weekday is " << (tm.weekday); + // get time elements + tt = rtc.makeTime(tm); + uint16_t tmp = rtc.weekday(tt); + if ( tmp!=tm.weekday ) {// correct weekday + rtc.setTime(tt); + Serial << " instead of " << tmp << ". Now is corrected.\n"; + } else { + Serial << " - seems to be fine, no need to change it.\n"; + } + + uint8_t chg = 0; + // get time elements + rtc.getTime(tm); + Serial << "\nCurrent RTC date: " << (1970+tm.year) << "." << (tm.month) << (".") << (tm.day) << (", weekday: ") << (tm.weekday) << endl; + Serial << "Do you want to change it? (y/n)\n"; + if ( *read_line()=='y' ) { + // change here the date +change_year: + Serial << "Current year: " << (1970+tm.year) << ". Enter new year in \"YYYY\" format (numbers only) or press enter to skip.\n"; + if (*read_line()==0) goto change_month; + tmp = atoi((const char*)s); + if ( tmp<1970 ) { Serial << "Please enter a valid number greater than 1970\n"; goto change_year; } + Serial << "You entered: " << tmp << ". Accept value? (y/n)\n"; + if ( *read_line()=='n' ) goto change_year; + tm.year = tmp-1970; + chg = 1; +change_month: + Serial << "Current month: " << tm.month << ". Enter new month in \"MM\" format [1..12] or press enter to skip.\n"; + if (*read_line()==0) goto change_day; + tmp = atoi((const char*)s); + if ( tmp<1 || tmp>12 ) { Serial << "Please enter a valid number [1..12]\n"; goto change_month; } + Serial << "You entered: " << tmp << ". Accept value? (y/n)\n"; + if ( *read_line()=='n' ) goto change_month; + tm.month = tmp; + chg = 1; +change_day: + Serial << "Current day: " << tm.day << ". Enter new day in \"DD\" format [1..31] or press enter to skip.\n"; + if (*read_line()==0) goto change_weekday; + tmp = atoi((const char*)s); + if ( tmp<1 || tmp>31 ) { Serial << "Please enter a valid number [1..31]\n"; goto change_day; } + Serial << "You entered: " << tmp << ". Accept value? (y/n)\n"; + if ( *read_line()=='n' ) goto change_day; + tm.day = tmp; + chg = 1; +change_weekday: + Serial << "Current weekday: " << tm.weekday << ". Enter new weekday [1(=Monday)..7(=Sunday)] or press enter to skip.\n"; + if (*read_line()==0) goto change_time; + tmp = atoi((const char*)s); + if ( tmp<1 || tmp>7 ) { Serial << "Please enter a valid number [1..7]\n"; goto change_weekday; } + Serial << "You entered: " << tmp << ". Accept value? (y/n)\n"; + if ( *read_line()=='n' ) goto change_weekday; + tm.weekday = tmp; + chg = 1; +change_time: + Serial << "Current RTC time: " << _TIME(tm.hour, tm.minute, tm.second) << endl; + Serial << "Do you want to change it? (y/n)\n"; + if ( *read_line()=='n' ) goto change_end; +change_hour: + Serial << "Current hour: " << tm.hour << ". Enter new hour [0..23] or press enter to skip.\n"; + if (*read_line()==0) goto change_minute; + tmp = atoi((const char*)s); + if ( tmp>23 ) { Serial << "Please enter a valid number [0..23]\n"; goto change_hour; } + Serial << "You entered: " << tmp << ". Accept value? (y/n)\n"; + if ( *read_line()=='n' ) goto change_hour; + tm.hour = tmp; + chg = 1; +change_minute: + Serial << "Current minute: " << tm.minute << ". Enter new minute [0..59] or press enter to skip.\n"; + if (*read_line()==0) goto change_second; + tmp = atoi((const char*)s); + if ( tmp>59 ) { Serial << "Please enter a valid number [0..59]\n"; goto change_minute; } + Serial << "You entered: " << tmp << ". Accept value? (y/n)\n"; + if ( *read_line()=='n' ) goto change_minute; + tm.minute = tmp; + chg = 1; +change_second: + Serial << "Current second: " << tm.second << ". Enter new second [0..59] or press enter to skip.\n"; + if (*read_line()==0) goto change_end; + tmp = atoi((const char*)s); + if ( tmp>59 ) { Serial << "Please enter a valid number [0..59]\n"; goto change_second; } + Serial << "You entered: " << tmp << ". Accept value? (y/n)\n"; + if ( *read_line()=='n' ) goto change_second; + tm.second = tmp; + chg = 1; + } else { + goto change_time; + } + +change_end: + if ( chg ) { + // set here the RTC time. + Serial << "Changed date & time: " << (1970+tm.year) << "." << (tm.month) << (".") << (tm.day) << (", weekday: ") << (tm.weekday) << ", " << _TIME(tm.hour, tm.minute, tm.second) << endl; + Serial << "Write now to RTC? (y/n)\n"; + read_line(); + if ( s[0]=='y' ) { + rtc.setTime(tm); + Serial << "Data written to RTC.\n\n"; + } + } else + Serial << "RTC was not changed.\n\n"; +} +//----------------------------------------------------------------------------- +void setup() +{ + Serial.begin(); + delay(3000); + + pinMode(LED_PIN, OUTPUT); + + Serial << "This is an example of how to use the STM32F4 RTC library.\n\n"; + + Change_DateTime(); +} + +//----------------------------------------------------------------------------- +void loop() +{ + if ( Serial.available() ) { + // adjust time according to received epoch time from PC + processSyncMessage(); + } + + if (tt!=rtc.now()) { + // get epoch time + tt = rtc.now(); + Serial << ("- RTC epoch timestamp = ") << (tt); + // get time elements + rtc.getTime(tm); + //rtc.breakTime(tt, tm); + Serial << (" == ") << (1970+tm.year) << "." << (tm.month) << (".") << (tm.day) << (", weekday ") << (tm.weekday) << (", "); + Serial << _TIME(tm.hour, tm.minute, tm.second) << endl; + } +} \ No newline at end of file diff --git a/STM32F4/libraries/RTClock/library.properties b/STM32F4/libraries/RTClock/library.properties index 5a5e4b7..a8878f6 100644 --- a/STM32F4/libraries/RTClock/library.properties +++ b/STM32F4/libraries/RTClock/library.properties @@ -7,3 +7,4 @@ paragraph=Real Time Clock for STM32F4 category=Other url= architectures=STM32F4 +maintainer=www.stm32duino.com diff --git a/STM32F4/libraries/RTClock/src/RTClock.cpp b/STM32F4/libraries/RTClock/src/RTClock.cpp index ee82c95..e7c2ca8 100644 --- a/STM32F4/libraries/RTClock/src/RTClock.cpp +++ b/STM32F4/libraries/RTClock/src/RTClock.cpp @@ -42,15 +42,7 @@ voidFuncPtr handlerAlarmA = NULL; voidFuncPtr handlerAlarmB = NULL; voidFuncPtr handlerPeriodicWakeup = NULL; - -RTClock::RTClock() { - RTClock(RTCSEL_HSE, 7999, 124); -} - -RTClock::RTClock(rtc_clk_src src) { - RTClock(src, 0, 0); -} - +//----------------------------------------------------------------------------- RTClock::RTClock(rtc_clk_src src, uint16 sync_prescaler, uint16 async_prescaler) { uint32 t = 0; RCC_BASE->APB1ENR |= RCC_APB1RSTR_PWRRST; @@ -144,117 +136,155 @@ RTClock::~RTClock() { } */ -void RTClock::setTime (time_t time_stamp) { - unsigned char years = 0; - unsigned char months = 0; - unsigned char monthLength = 0; - unsigned char wdays = 0; - unsigned char hours = 0; - unsigned char mins = 0; - unsigned char secs = 0; - unsigned long days; +//----------------------------------------------------------------------------- +void RTClock::setTime (time_t time_stamp) +{ + breakTime(time_stamp, tm); // time will be broken to tm + setTime(tm); +} - secs = time_stamp % 60; - time_stamp /= 60; // now it is minutes - mins = time_stamp % 60; - time_stamp /= 60; // now it is hours - hours = time_stamp % 24; - time_stamp /= 24; // now it is days - wdays = ((time_stamp + 4) % 7) + 1; // Sunday is day 1 - - while((unsigned)(days += (LEAP_YEAR(years) ? 366 : 365)) <= time_stamp) { - years++; - } - - days -= LEAP_YEAR(years) ? 366 : 365; - time_stamp -= days; // now it is days in this year, starting at 0 - - for (months = 0; months < 12; months++) { - if (months == 1) { // february - if (LEAP_YEAR(years)) { - monthLength = 29; - } else { - monthLength = 28; - } - } else { - monthLength = monthDays[months]; - } - - if (time_stamp >= monthLength) { - time_stamp -= monthLength; - } else { - break; - } - } - months++; // jan is month 1 - days = time_stamp + 1; // day of month +//----------------------------------------------------------------------------- +void RTClock::setTime (tm_t & tm) +{ + if (tm.year > 99) + tm.year = tm.year % 100; rtc_enter_config_mode(); - RTC_BASE->TR = ((hours / 10) << 20) | ((hours % 10) << 16) | ((mins / 10) << 12) | ((mins % 10) << 8) | ((secs / 10) << 4) | (secs % 10); - RTC_BASE->DR = ((years / 10) << 20) | ((years % 10) << 16) | (wdays << 13) | ((months / 10) << 12) | ((months % 10) << 8) | ((days / 10) << 4) | (days % 10); + RTC_BASE->TR = BUILD_TIME_REGISTER(tm.hour, tm.minute, tm.second); + RTC_BASE->DR = BUILD_DATE_REGISTER(tm.year, tm.month, tm.day, tm.weekday); rtc_exit_config_mode(); } - -void RTClock::setTime (struct tm* tm_ptr) { - rtc_enter_config_mode(); - if (tm_ptr->tm_year > 99) - tm_ptr->tm_year = tm_ptr->tm_year % 100; - tm_ptr->tm_wday = tm_ptr->tm_wday & 0x7; - RTC_BASE->TR = ((tm_ptr->tm_hour / 10) << 20) | ((tm_ptr->tm_hour % 10) << 16) | - ((tm_ptr->tm_min / 10) << 12) | ((tm_ptr->tm_min % 10) << 8) | - ((tm_ptr->tm_sec / 10) << 4) | (tm_ptr->tm_sec % 10); - RTC_BASE->DR = ((tm_ptr->tm_year / 10) << 20) | ((tm_ptr->tm_year % 10) << 16) | (tm_ptr->tm_wday << 13) | - ((tm_ptr->tm_mon / 10) << 12) | ((tm_ptr->tm_mon % 10) << 8) | - ((tm_ptr->tm_mday / 10) << 4) | (tm_ptr->tm_mday % 10); - rtc_exit_config_mode(); -} - -time_t RTClock::getTime() { - uint32 dr_reg = RTC_BASE->DR; - uint32 tr_reg = RTC_BASE->TR; - int years = 10 * ((dr_reg & 0x00F00000) >> 20) + ((dr_reg & 0x000F0000) >> 16); - int months = 10 * ((dr_reg & 0x00001000) >> 12) + ((dr_reg & 0x00000F00) >> 8); - int days = 10 * ((dr_reg & 0x00000030) >> 4) + (dr_reg & 0x000000F); - int hours = 10 * ((tr_reg & 0x00300000) >> 20) + ((tr_reg & 0x000F0000) >> 16); - int mins = 10 * ((tr_reg & 0x00007000) >> 12) + ((tr_reg & 0x0000F00) >> 8); - int secs = 10 * ((tr_reg & 0x00000070) >> 4) + (tr_reg & 0x0000000F); - // seconds from 1970 till 1 jan 00:00:00 of the given year - time_t t = (years + 30) * SECS_PER_DAY * 365; - for (int i = 0; i < (years + 30); i++) { - if (LEAP_YEAR(i)) { - t += SECS_PER_DAY; // add extra days for leap years + +/*============================================================================*/ +/* functions to convert to and from system time */ +/* These are for interfacing with time serivces and are not normally needed in a sketch */ + +// leap year calulator expects year argument as years offset from 1970 +#define LEAP_YEAR(Y) ( ((1970+Y)>0) && !((1970+Y)%4) && ( ((1970+Y)%100) || !((1970+Y)%400) ) ) + +//static const uint8_t monthDays[]={31,28,31,30,31,30,31,31,30,31,30,31}; // API starts months from 1, this array starts from 0 + +//----------------------------------------------------------------------------- +void RTClock::breakTime(time_t timeInput, tm_t & tm) +{ +// break the given time_t into time components +// this is a more compact version of the C library localtime function +// note that year is offset from 1970 !!! + + uint8_t year; + uint8_t month, monthLength; + uint32_t time; + uint32_t days; + + time = (uint32_t)timeInput; + tm.second = time % 60; + time /= 60; // now it is minutes + tm.minute = time % 60; + time /= 60; // now it is hours + tm.hour = time % 24; + time /= 24; // now it is days + tm.weekday = ((time + 4) % 7); // Monday is day 1 // + 1; // Sunday is day 1 + + year = 0; + days = 0; + while((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= time) { + year++; } - } - // add days for this year, months start from 1 - for (int i = 1; i < months; i++) { - if ( (i == 2) && LEAP_YEAR(years)) { - t += SECS_PER_DAY * 29; - } else { - t += SECS_PER_DAY * monthDays[i - 1]; //monthDays array starts from 0 + tm.year = year; // year is offset from 1970 + + days -= LEAP_YEAR(year) ? 366 : 365; + time -= days; // now it is days in this year, starting at 0 + + days = 0; + month = 0; + monthLength = 0; + for (month=0; month<12; month++) { + if (month==1) { // february + if (LEAP_YEAR(year)) { + monthLength=29; + } else { + monthLength=28; + } + } else { + monthLength = monthDays[month]; + } + + if (time >= monthLength) { + time -= monthLength; + } else { + break; + } } - } - t += (days - 1) * SECS_PER_DAY + hours * SECS_PER_HOUR + mins * SECS_PER_MIN + secs; - return t; + tm.month = month + 1; // jan is month 1 + tm.day = time + 1; // day of month } - -struct tm* RTClock::getTime(struct tm* tm_ptr) { - uint32 dr_reg = RTC_BASE->DR; - uint32 tr_reg = RTC_BASE->TR; - tm_ptr->tm_year = 10 * ((dr_reg & 0x00F00000) >> 20) + ((dr_reg & 0x000F0000) >> 16); - tm_ptr->tm_mon = 10 * ((dr_reg & 0x00001000) >> 12) + ((dr_reg & 0x00000F00) >> 8); - tm_ptr->tm_mday = 10 * ((dr_reg & 0x00000030) >> 4) + (dr_reg & 0x000000F); - tm_ptr->tm_hour = 10 * ((tr_reg & 0x00300000) >> 20) + ((tr_reg & 0x000F0000) >> 16); - tm_ptr->tm_min = 10 * ((tr_reg & 0x00007000) >> 12) + ((tr_reg & 0x0000F00) >> 8); - tm_ptr->tm_sec = 10 * ((tr_reg & 0x00000070) >> 4) + (tr_reg & 0x0000000F); - return tm_ptr; + +//----------------------------------------------------------------------------- +time_t RTClock::makeTime(tm_t & tm) +{ +// assemble time elements into time_t +// note year argument is offset from 1970 (see macros in time.h to convert to other formats) +// previous version used full four digit year (or digits since 2000),i.e. 2009 was 2009 or 9 + + int i; + uint32_t seconds; + + // seconds from 1970 till 1 jan 00:00:00 of the given year + seconds = tm.year*(SECS_PER_DAY * 365); + for (i = 0; i < tm.year; i++) { + if (LEAP_YEAR(i)) { + seconds += SECS_PER_DAY; // add extra days for leap years + } + } + + // add days for this year, months start from 1 + for (i = 1; i < tm.month; i++) { + if ( (i == 2) && LEAP_YEAR(tm.year)) { + seconds += SECS_PER_DAY * 29; + } else { + seconds += SECS_PER_DAY * monthDays[i-1]; //monthDay array starts from 0 + } + } + seconds+= (tm.day-1) * SECS_PER_DAY; + seconds+= tm.hour * SECS_PER_HOUR; + seconds+= tm.minute * SECS_PER_MIN; + seconds+= tm.second; + return (time_t)seconds; } - -void RTClock::setAlarmATime (tm * tm_ptr, bool hours_match, bool mins_match, bool secs_match, bool date_match) { + +//----------------------------------------------------------------------------- +void RTClock::getTime(tm_t & tm) +{ + uint32_t dr_reg, tr_reg; + do { // read multiple time till both readings are equal + dr_reg = getDReg(); + tr_reg = getTReg(); + } while ( (dr_reg!=getDReg()) || (tr_reg!=getTReg()) ); + tm.year = _year(dr_reg); + tm.month = _month(dr_reg); + tm.day = _day(dr_reg); + tm.weekday = _weekday(dr_reg); + tm.pm = _pm(tr_reg); + tm.hour = _hour(tr_reg); + tm.minute = _minute(tr_reg); + tm.second = _second(tr_reg); +} + +//----------------------------------------------------------------------------- +time_t RTClock::getTime() +{ + getTime(tm); + return makeTime(tm); +} + +//----------------------------------------------------------------------------- +void RTClock::setAlarmATime (tm_t * tm_ptr, bool hours_match, bool mins_match, bool secs_match, bool date_match) +{ uint32 t = 0; rtc_enter_config_mode(); - unsigned int bits = ((tm_ptr->tm_mday / 10) << 28) | ((tm_ptr->tm_mday % 10) << 24) | - ((tm_ptr->tm_hour / 10) << 20) | ((tm_ptr->tm_hour % 10) << 16) | - ((tm_ptr->tm_min / 10) << 12) | ((tm_ptr->tm_min % 10) << 8) | - ((tm_ptr->tm_sec / 10) << 4) | (tm_ptr->tm_sec % 10); + unsigned int bits = ((tm_ptr->day / 10) << 28) | ((tm.day % 10) << 24) | + ((tm_ptr->hour / 10) << 20) | ((tm_ptr->hour % 10) << 16) | + ((tm_ptr->minute / 10) << 12) | ((tm_ptr->minute % 10) << 8) | + ((tm_ptr->second / 10) << 4) | (tm_ptr->second % 10); if (!date_match) bits |= (1 << 31); if (!hours_match) bits |= (1 << 23); if (!mins_match) bits |= (1 << 15); @@ -276,27 +306,30 @@ void RTClock::setAlarmATime (tm * tm_ptr, bool hours_match, bool mins_match, boo rtc_enable_alarm_event(); } - -void RTClock::setAlarmATime (time_t alarm_time, bool hours_match, bool mins_match, bool secs_match, bool date_match) { - struct tm* tm_ptr = gmtime(&alarm_time); - setAlarmATime(tm_ptr, hours_match, mins_match, secs_match, date_match); +//----------------------------------------------------------------------------- +void RTClock::setAlarmATime (time_t alarm_time, bool hours_match, bool mins_match, bool secs_match, bool date_match) +{ + breakTime(alarm_time, tm); + setAlarmATime(&tm, hours_match, mins_match, secs_match, date_match); } - -void RTClock::turnOffAlarmA() { +//----------------------------------------------------------------------------- +void RTClock::turnOffAlarmA(void) +{ rtc_enter_config_mode(); RTC_BASE->CR &= ~(1 << RTC_CR_ALRAIE_BIT); // turn off ALRAIE rtc_exit_config_mode(); } - -void RTClock::setAlarmBTime (tm * tm_ptr, bool hours_match, bool mins_match, bool secs_match, bool date_match) { +//----------------------------------------------------------------------------- +void RTClock::setAlarmBTime (tm_t * tm_ptr, bool hours_match, bool mins_match, bool secs_match, bool date_match) +{ uint32 t = 0; rtc_enter_config_mode(); - unsigned int bits = ((tm_ptr->tm_mday / 10) << 28) | ((tm_ptr->tm_mday % 10) << 24) | - ((tm_ptr->tm_hour / 10) << 20) | ((tm_ptr->tm_hour % 10) << 16) | - ((tm_ptr->tm_min / 10) << 12) | ((tm_ptr->tm_min % 10) << 8) | - ((tm_ptr->tm_sec / 10) << 4) | (tm_ptr->tm_sec % 10); + unsigned int bits = ((tm_ptr->day / 10) << 28) | ((tm_ptr->day % 10) << 24) | + ((tm_ptr->hour / 10) << 20) | ((tm_ptr->hour % 10) << 16) | + ((tm_ptr->minute / 10) << 12) | ((tm_ptr->minute % 10) << 8) | + ((tm_ptr->second / 10) << 4) | (tm_ptr->second % 10); if (!date_match) bits |= (1 << 31); if (!hours_match) bits |= (1 << 23); if (!mins_match) bits |= (1 << 15); @@ -318,21 +351,23 @@ void RTClock::setAlarmBTime (tm * tm_ptr, bool hours_match, bool mins_match, boo rtc_enable_alarm_event(); } - -void RTClock::setAlarmBTime (time_t alarm_time, bool hours_match, bool mins_match, bool secs_match, bool date_match) { - struct tm* tm_ptr = gmtime(&alarm_time); - setAlarmBTime(tm_ptr, hours_match, mins_match, secs_match, date_match); +//----------------------------------------------------------------------------- +void RTClock::setAlarmBTime (time_t alarm_time, bool hours_match, bool mins_match, bool secs_match, bool date_match) +{ + breakTime(alarm_time, tm); + setAlarmBTime(&tm, hours_match, mins_match, secs_match, date_match); } - +//----------------------------------------------------------------------------- void RTClock::turnOffAlarmB() { rtc_enter_config_mode(); RTC_BASE->CR &= ~(1 << RTC_CR_ALRBIE_BIT); // turn off ALRBIE rtc_exit_config_mode(); } - -void RTClock::setPeriodicWakeup(uint16 period) { +//----------------------------------------------------------------------------- +void RTClock::setPeriodicWakeup(uint16 period) +{ uint32 t = 0; rtc_enter_config_mode(); RTC_BASE->CR &= ~(1 << RTC_CR_WUTE_BIT); diff --git a/STM32F4/libraries/RTClock/src/RTClock.h b/STM32F4/libraries/RTClock/src/RTClock.h index facaa00..c13bf5f 100644 --- a/STM32F4/libraries/RTClock/src/RTClock.h +++ b/STM32F4/libraries/RTClock/src/RTClock.h @@ -1,29 +1,35 @@ -#include -#include -#include -#include -#include -#include -#include - #ifndef _RTCLOCK_H_ #define _RTCLOCK_H_ -//#define RTC_DEBUG #ifdef __cplusplus extern "C" { #endif + + +#include // for __time_t_defined +#include +#include +#include +#include +#include +#include + +//#define RTC_DEBUG + + +#if !defined(__time_t_defined) // avoid conflict with newlib or other posix libc + #warning "Using private time_t definintion" + typedef uint32_t time_t; +#endif + #ifdef RTC_DEBUG extern void dbg_printf(const char *fmt, ... ); #define rtc_debug_printf(fmt, ...) dbg_printf(fmt, ##__VA_ARGS__); #else #define rtc_debug_printf(...) #endif -#ifdef __cplusplus -} -#endif #define SECS_PER_MIN (60UL) @@ -33,7 +39,7 @@ extern "C" { #define SECS_PER_WEEK (SECS_PER_DAY * DAYS_PER_WEEK) #define SECS_PER_YEAR (SECS_PER_WEEK * 52UL) #define SECS_YR_2000 (946684800UL) // the time at the start of y2k -#define LEAP_YEAR(Y) ( ((1970+Y)>0) && !((1970+Y)%4) && ( ((1970+Y)%100) || !((1970+Y)%400) ) ) +#define LEAP_YEAR(Y) ( ((1970+Y)>0) && !((1970+Y)%4) && ( ((1970+Y)%100) || !((1970+Y)%400) ) ) static const unsigned char monthDays[]={31,28,31,30,31,30,31,31,30,31,30,31}; // API starts months from 1, this array starts from 0 @@ -91,6 +97,28 @@ typedef enum rtc_clk_src { RTCSEL_HSE = 0x13, } rtc_clk_src; +// Time register +#define RTC_TR_PM_BIT 22 +#define RTC_TR_HOUR_BIT 16 +#define RTC_TR_MINUTE_BIT 8 +#define RTC_TR_SECOND_BIT 0 + +#define RTC_TR_PM_MASK (0x01)//<>4)) + (b&0x0F) ); } +static inline uint8_t bin2bcd(uint8_t b) { return ( ((b/10)<<4) + (b%10) ); } class RTClock { - public: - RTClock(); - RTClock(rtc_clk_src src ); + public: + RTClock() { RTClock(RTCSEL_LSE, 0, 0); } + RTClock(rtc_clk_src src ) { RTClock(src, 0, 0); } RTClock(rtc_clk_src src, uint16 sync_prescaler, uint16 async_prescaler); //~RTClock(); //to implement + + void breakTime(time_t epoch_time, tm_t & tm); + time_t makeTime(tm_t & tm); void setTime (time_t time_stamp); - void setTime (struct tm * tm_ptr); + void setTime (tm_t & tm); - struct tm* getTime(struct tm* tm_ptr); time_t getTime(); + void getTime(tm_t & tm); + #define now getTime + + uint8_t year(void) { getTime(tm); return tm.year; } + uint8_t month(void) { getTime(tm); return tm.month; } + uint8_t day(void) { getTime(tm); return tm.day; } + uint8_t weekday(void) { getTime(tm); return tm.weekday; } + uint8_t hour(void) { getTime(tm); return tm.hour; } + uint8_t minute(void) { getTime(tm); return tm.minute; } + uint8_t second(void) { getTime(tm); return tm.second; } + //uint8_t pm(void) { return _pm(RTC_BASE->TR); } + uint8_t isPM(void) { return ( hour()>=12 ); } - void setAlarmATime (tm * tm_ptr, bool hours_match = true, bool mins_match = true, bool secs_match = true, bool date_match = false); + uint8_t year(time_t t) { breakTime(t, tm); return tm.year; } + uint8_t month(time_t t) { breakTime(t, tm); return tm.month; } + uint8_t day(time_t t) { breakTime(t, tm); return tm.day; } + uint8_t weekday(time_t t) { breakTime(t, tm); return tm.weekday; } + uint8_t hour(time_t t) { breakTime(t, tm); return tm.hour; } + uint8_t minute(time_t t) { breakTime(t, tm); return tm.minute; } + uint8_t second(time_t t) { breakTime(t, tm); return tm.second; } + uint8_t isPM(time_t t) { return (hour(t)>=12); } + + void setAlarmATime (tm_t * tm_ptr, bool hours_match = true, bool mins_match = true, bool secs_match = true, bool date_match = false); void setAlarmATime (time_t alarm_time, bool hours_match = true, bool mins_match = true, bool secs_match = true, bool date_match = false); void turnOffAlarmA(); - void setAlarmBTime (tm * tm_ptr, bool hours_match = true, bool mins_match = true, bool secs_match = true, bool date_match = false); + void setAlarmBTime (tm_t * tm_ptr, bool hours_match = true, bool mins_match = true, bool secs_match = true, bool date_match = false); void setAlarmBTime (time_t alarm_time, bool hours_match = true, bool mins_match = true, bool secs_match = true, bool date_match = false); void turnOffAlarmB(); @@ -143,17 +216,29 @@ class RTClock { void attachPeriodicWakeupInterrupt(voidFuncPtr function); void detachPeriodicWakeupInterrupt(); + inline void attachSecondsInterrupt(voidFuncPtr function) { attachPeriodicWakeupInterrupt(function); } + inline void detachSecondsInterrupt() { detachPeriodicWakeupInterrupt(); } void attachAlarmAInterrupt(voidFuncPtr function); void detachAlarmAInterrupt(); void attachAlarmBInterrupt(voidFuncPtr function); void detachAlarmBInterrupt(); - //private: - -} ; + private: + inline uint8_t _year(uint32_t dr) { return bcd2bin( (dr>>RTC_DR_YEAR_BIT) & RTC_DR_YEAR_MASK ); } + inline uint8_t _month(uint32_t dr) { return bcd2bin( (dr>>RTC_DR_MONTH_BIT) & RTC_DR_MONTH_MASK ); } + inline uint8_t _day(uint32_t dr) { return bcd2bin( (dr>>RTC_DR_DAY_BIT) & RTC_DR_DAY_MASK ); } + inline uint8_t _weekday(uint32_t dr) { return bcd2bin( (dr>>RTC_DR_WEEKDAY_BIT) & RTC_DR_WEEKDAY_MASK ); } + inline uint8_t _pm(uint32_t tr) { return ( (tr>>RTC_TR_PM_BIT) & RTC_TR_PM_MASK ); } + inline uint8_t _hour(uint32_t tr) { return bcd2bin( (tr>>RTC_TR_HOUR_BIT) & RTC_TR_HOUR_MASK ); } + inline uint8_t _minute(uint32_t tr) { return bcd2bin( (tr>>RTC_TR_MINUTE_BIT) & RTC_TR_MINUTE_MASK ); } + inline uint8_t _second(uint32_t tr) { return bcd2bin( (tr>>RTC_TR_SECOND_BIT) & RTC_TR_SECOND_MASK ); } + tm_t tm; +}; +inline uint32_t getTReg(void) { return (uint32_t)(RTC_BASE->TR); } +inline uint32_t getDReg(void) { return (uint32_t)(RTC_BASE->DR); } /** * @brief Clear the register synchronized flag. The flag is then set by hardware after a write to PRL/DIV or CNT. @@ -246,7 +331,8 @@ static inline void rtc_disable_wakeup_event() { *bb_perip(&EXTI_BASE->RTSR, EXTI_RTC_WAKEUP_BIT) = 0; } - +#ifdef __cplusplus +} +#endif #endif // _RTCLOCK_H_ - \ No newline at end of file From 6b856152216df10212454461043930fd8e0f3bc8 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Thu, 20 Jul 2017 17:43:13 +1000 Subject: [PATCH 120/351] Change Wire endTransmission to have bool instead of unit8 argument - to match with the Arduino API --- STM32F1/libraries/Wire/WireBase.cpp | 2 +- STM32F1/libraries/Wire/WireBase.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/STM32F1/libraries/Wire/WireBase.cpp b/STM32F1/libraries/Wire/WireBase.cpp index 73d0398..90ec370 100644 --- a/STM32F1/libraries/Wire/WireBase.cpp +++ b/STM32F1/libraries/Wire/WireBase.cpp @@ -59,7 +59,7 @@ void WireBase::beginTransmission(int slave_address) { beginTransmission((uint8)slave_address); } -uint8 WireBase::endTransmission(uint8 stop) { +uint8 WireBase::endTransmission(bool stop) { uint8 retVal; if (tx_buf_overflow) { return EDATA; diff --git a/STM32F1/libraries/Wire/WireBase.h b/STM32F1/libraries/Wire/WireBase.h index 4038428..5e51ab7 100644 --- a/STM32F1/libraries/Wire/WireBase.h +++ b/STM32F1/libraries/Wire/WireBase.h @@ -91,7 +91,7 @@ public: * Call the process function to process the message if the TX * buffer has not overflowed. */ - uint8 endTransmission(uint8); + uint8 endTransmission(bool); uint8 endTransmission(void); /* From 0db43ae36f8e2f378fbd3d7fd4b834febd20dc0c Mon Sep 17 00:00:00 2001 From: stevstrong Date: Fri, 28 Jul 2017 17:51:54 +0200 Subject: [PATCH 121/351] SPI clean up + add 16 bit access functions in 8 bit mode --- STM32F1/libraries/SPI/src/SPI.cpp | 68 ++++++++++++------------------- STM32F1/libraries/SPI/src/SPI.h | 44 +++++++++----------- 2 files changed, 46 insertions(+), 66 deletions(-) diff --git a/STM32F1/libraries/SPI/src/SPI.cpp b/STM32F1/libraries/SPI/src/SPI.cpp index 94e5031..34df62e 100644 --- a/STM32F1/libraries/SPI/src/SPI.cpp +++ b/STM32F1/libraries/SPI/src/SPI.cpp @@ -31,7 +31,6 @@ #include "SPI.h" -//#define SPI_DEBUG #include #include @@ -92,11 +91,10 @@ static const spi_pins board_spi_pins[] __FLASH__ = { * Constructor */ -SPIClass::SPIClass(uint32 spi_num) { - +SPIClass::SPIClass(uint32 spi_num) +{ _currentSetting=&_settings[spi_num-1];// SPI channels are called 1 2 and 3 but the array is zero indexed - switch (spi_num) { #if BOARD_NR_SPI >= 1 case 1: @@ -119,7 +117,7 @@ SPIClass::SPIClass(uint32 spi_num) { default: ASSERT(0); } - + // Init things specific to each SPI device // clock divider setup is a bit of hack, and needs to be improved at a later date. _settings[0].spi_d = SPI1; @@ -149,9 +147,6 @@ SPIClass::SPIClass(uint32 spi_num) { */ void SPIClass::updateSettings(void) { uint32 flags = ((_currentSetting->bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | _currentSetting->dataSize | SPI_SW_SLAVE | SPI_SOFT_SS); - #ifdef SPI_DEBUG - Serial.print("spi_master_enable("); Serial.print(_currentSetting->clockDivider); Serial.print(","); Serial.print(_currentSetting->dataMode); Serial.print(","); Serial.print(flags); Serial.println(")"); - #endif spi_master_enable(_currentSetting->spi_d, (spi_baud_rate)_currentSetting->clockDivider, (spi_mode)_currentSetting->dataMode, flags); } @@ -167,9 +162,6 @@ 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_RX_ONLY); - #ifdef SPI_DEBUG - Serial.print("spi_slave_enable("); Serial.print(_currentSetting->dataMode); Serial.print(","); Serial.print(flags); Serial.println(")"); - #endif spi_slave_enable(_currentSetting->spi_d, (spi_mode)_currentSetting->dataMode, flags); // added for DMA callbacks. _currentSetting->state = SPI_STATE_READY; @@ -199,9 +191,6 @@ void SPIClass::end(void) { /* Roger Clark added 3 functions */ void SPIClass::setClockDivider(uint32_t clockDivider) { - #ifdef SPI_DEBUG - Serial.print("Clock divider set to "); Serial.println(clockDivider); - #endif _currentSetting->clockDivider = clockDivider; uint32 cr1 = _currentSetting->spi_d->regs->CR1 & ~(SPI_CR1_BR); _currentSetting->spi_d->regs->CR1 = cr1 | (clockDivider & SPI_CR1_BR); @@ -209,9 +198,6 @@ void SPIClass::setClockDivider(uint32_t clockDivider) void SPIClass::setBitOrder(BitOrder bitOrder) { - #ifdef SPI_DEBUG - Serial.print("Bit order set to "); Serial.println(bitOrder); - #endif _currentSetting->bitOrder = bitOrder; uint32 cr1 = _currentSetting->spi_d->regs->CR1 & ~(SPI_CR1_LSBFIRST); if ( bitOrder==LSBFIRST ) cr1 |= SPI_CR1_LSBFIRST; @@ -258,9 +244,6 @@ bit 0 - CPHA : Clock phase If someone finds this is not the case or sees a logic error with this let me know ;-) */ - #ifdef SPI_DEBUG - Serial.print("Data mode set to "); Serial.println(dataMode); - #endif _currentSetting->dataMode = dataMode; uint32 cr1 = _currentSetting->spi_d->regs->CR1 & ~(SPI_CR1_CPOL|SPI_CR1_CPHA); _currentSetting->spi_d->regs->CR1 = cr1 | (dataMode & (SPI_CR1_CPOL|SPI_CR1_CPHA)); @@ -268,9 +251,6 @@ If someone finds this is not the case or sees a logic error with this let me kno void SPIClass::beginTransaction(uint8_t pin, SPISettings settings) { - #ifdef SPI_DEBUG - Serial.println("SPIClass::beginTransaction"); - #endif setBitOrder(settings.bitOrder); setDataMode(settings.dataMode); setDataSize(settings.dataSize); @@ -280,9 +260,6 @@ void SPIClass::beginTransaction(uint8_t pin, SPISettings settings) void SPIClass::beginTransactionSlave(SPISettings settings) { - #ifdef SPI_DEBUG - Serial.println(F("SPIClass::beginTransactionSlave")); - #endif setBitOrder(settings.bitOrder); setDataMode(settings.dataMode); setDataSize(settings.dataSize); @@ -291,9 +268,6 @@ void SPIClass::beginTransactionSlave(SPISettings settings) void SPIClass::endTransaction(void) { - #ifdef SPI_DEBUG - Serial.println("SPIClass::endTransaction"); - #endif //digitalWrite(_SSPin,HIGH); #if false // code from SAM core @@ -355,6 +329,16 @@ void SPIClass::write(uint16 data) while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." } +void SPIClass::write16(uint16 data) +{ + // Added by stevestrong: write two consecutive bytes in 8 bit mode (DFF=0) + spi_tx_reg(_currentSetting->spi_d, data>>8); // write high byte + while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // Wait until TXE=1 + spi_tx_reg(_currentSetting->spi_d, data); // write low byte + while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // Wait until TXE=1 + while (spi_is_busy(_currentSetting->spi_d) != 0); // wait until BSY=0 +} + void SPIClass::write(uint16 data, uint32 n) { // Added by stevstrong: Repeatedly send same data by the specified number of times @@ -384,14 +368,21 @@ uint8 SPIClass::transfer(uint8 byte) const return (uint8)spi_rx_reg(spi_d); // "... and read the last received data." } -uint16_t SPIClass::transfer16(uint16_t wr_data) const +uint16_t SPIClass::transfer16(uint16_t data) const { + // Modified by stevestrong: write & read two consecutive bytes in 8 bit mode (DFF=0) + // This is more effective than two distinct byte transfers 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." + spi_rx_reg(spi_d); // read any previous data + spi_tx_reg(spi_d, data>>8); // write high byte + while (spi_is_tx_empty(spi_d) == 0); // wait until TXE=1 + while (spi_is_busy(spi_d) != 0); // wait until BSY=0 + uint16_t ret = spi_rx_reg(spi_d)<<8; // read and shift high byte + spi_tx_reg(spi_d, data); // write low byte + while (spi_is_tx_empty(spi_d) == 0); // wait until TXE=1 + while (spi_is_busy(spi_d) != 0); // wait until BSY=0 + ret += spi_rx_reg(spi_d); // read low byte + return ret; } /* Roger Clark and Victor Perez, 2015 @@ -523,7 +514,7 @@ uint8 SPIClass::dmaSendAsync(void * transmitBuf, uint16 length, bool minc) { //delayMicroseconds(10); if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; } } - + 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." spi_tx_dma_disable(_currentSetting->spi_d); @@ -531,11 +522,9 @@ uint8 SPIClass::dmaSendAsync(void * transmitBuf, uint16 length, bool minc) { _currentSetting->state = SPI_STATE_READY; } - if (length == 0) return 0; uint32 flags = ( (DMA_MINC_MODE*minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT); - dma_init(_currentSetting->spiDmaDev); // TX dma_xfer_size dma_bit_size = (_currentSetting->dataSize==DATA_SIZE_16BIT) ? DMA_SIZE_16BITS : DMA_SIZE_8BITS; @@ -770,9 +759,6 @@ static const spi_baud_rate baud_rates[8] __FLASH__ = { */ static spi_baud_rate determine_baud_rate(spi_dev *dev, uint32_t freq) { uint32_t clock = 0, i; - #ifdef SPI_DEBUG - Serial.print("determine_baud_rate("); Serial.print(freq); Serial.println(")"); - #endif switch (rcc_dev_clk(dev->clk_id)) { case RCC_APB2: clock = STM32_PCLK2; break; // 72 Mhz diff --git a/STM32F1/libraries/SPI/src/SPI.h b/STM32F1/libraries/SPI/src/SPI.h index 2160d26..25eea86 100644 --- a/STM32F1/libraries/SPI/src/SPI.h +++ b/STM32F1/libraries/SPI/src/SPI.h @@ -176,8 +176,6 @@ static void (*_spi3_this); class SPIClass { public: - - /** * @param spiPortNumber Number of the SPI port to manage. */ @@ -187,8 +185,6 @@ public: * Set up/tear down */ - - /** * @brief Equivalent to begin(SPI_1_125MHZ, MSBFIRST, 0). */ @@ -268,14 +264,15 @@ public: * @brief Transmit one byte/word. * @param data to transmit. */ - void write(uint16 data); - + void write(uint16 data); + void write16(uint16 data); // write 2 bytes in 8 bit mode (DFF=0) + /** * @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. @@ -293,7 +290,7 @@ public: */ uint8 transfer(uint8 data) const; uint16_t transfer16(uint16_t data) const; - + /** * @brief Sets up a DMA Transfer for "length" bytes. * The transfer mode (8 or 16 bit mode) is evaluated from the SPI peripheral setting. @@ -321,7 +318,7 @@ public: uint8 dmaSend(void * transmitBuf, uint16 length, bool minc = 1); void dmaSendSet(void * transmitBuf, bool minc); uint8 dmaSendRepeat(uint16 length); - + uint8 dmaSendAsync(void * transmitBuf, uint16 length, bool minc = 1); /* * Pin accessors @@ -354,24 +351,21 @@ public: * this HardwareSPI instance. */ spi_dev* c_dev(void) { return _currentSetting->spi_d; } - - + spi_dev *dev(){ return _currentSetting->spi_d;} - - /** - * @brief Sets the number of the SPI peripheral to be used by - * this HardwareSPI instance. - * - * @param spi_num Number of the SPI port. 1-2 in low density devices - * or 1-3 in high density devices. - */ - + + /** + * @brief Sets the number of the SPI peripheral to be used by + * this HardwareSPI instance. + * + * @param spi_num Number of the SPI port. 1-2 in low density devices + * or 1-3 in high density devices. + */ void setModule(int spi_num) { _currentSetting=&_settings[spi_num-1];// SPI channels are called 1 2 and 3 but the array is zero indexed } - /* -- The following methods are deprecated --------------------------- */ /** @@ -403,20 +397,20 @@ public: * @see HardwareSPI::read() */ uint8 recv(void); - + private: SPISettings _settings[BOARD_NR_SPI]; SPISettings *_currentSetting; - + void updateSettings(void); /* * Functions added for DMA transfers with Callback. * Experimental. */ - + void EventCallback(void); - + static void _spi1EventCallback(void); static void _spi2EventCallback(void); #if BOARD_NR_SPI >= 3 From 0aae3d31f1ca1a43b1afc3619acf215406837e39 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Sun, 30 Jul 2017 16:07:30 +1000 Subject: [PATCH 122/351] Changed order of optimisation options, so that current settings (-Os) are the default, and reverted F4 and F3 boards.txt to current master to remove these changes from those boards, as they will need to be updated in the same way I did for the F1, and I don't have time to do it now --- STM32F1/boards.txt | 650 ++++++++++++++++++++++----------------------- STM32F3/boards.txt | 34 --- STM32F4/boards.txt | 133 +--------- 3 files changed, 326 insertions(+), 491 deletions(-) diff --git a/STM32F1/boards.txt b/STM32F1/boards.txt index b526236..fe18609 100644 --- a/STM32F1/boards.txt +++ b/STM32F1/boards.txt @@ -45,36 +45,36 @@ mapleMini.menu.cpu_speed.speed_48mhz=48Mhz (Slow - with USB) mapleMini.menu.cpu_speed.speed_48mhz.build.f_cpu=48000000L #-- Optimizations -mapleMini.menu.opt.o2std=Faster -mapleMini.menu.opt.o2std.build.flags.optimize=-O2 -mapleMini.menu.opt.o2std.build.flags.ldspecs= -mapleMini.menu.opt.o2lto=Faster with LTO -mapleMini.menu.opt.o2lto.build.flags.optimize=-O2 -flto -mapleMini.menu.opt.o2lto.build.flags.ldspecs=-flto -mapleMini.menu.opt.o1std=Fast -mapleMini.menu.opt.o1std.build.flags.optimize=-O1 -mapleMini.menu.opt.o1std.build.flags.ldspecs= -mapleMini.menu.opt.o1lto=Fast with LTO -mapleMini.menu.opt.o1lto.build.flags.optimize=-O1 -flto -mapleMini.menu.opt.o1lto.build.flags.ldspecs=-flto -mapleMini.menu.opt.o3std=Fastest -mapleMini.menu.opt.o3std.build.flags.optimize=-O3 -mapleMini.menu.opt.o3std.build.flags.ldspecs= -mapleMini.menu.opt.o3lto=Fastest with LTO -mapleMini.menu.opt.o3lto.build.flags.optimize=-O3 -flto -mapleMini.menu.opt.o3lto.build.flags.ldspecs=-flto -mapleMini.menu.opt.ogstd=Debug -mapleMini.menu.opt.ogstd.build.flags.optimize=-Og -mapleMini.menu.opt.ogstd.build.flags.ldspecs= -mapleMini.menu.opt.oglto=Debug with LTO -mapleMini.menu.opt.oglto.build.flags.optimize=-Og -flto -mapleMini.menu.opt.oglto.build.flags.ldspecs=-flto -mapleMini.menu.opt.osstd=Smallest Code +mapleMini.menu.opt.osstd=Smallest (default) mapleMini.menu.opt.osstd.build.flags.optimize=-Os mapleMini.menu.opt.osstd.build.flags.ldspecs= mapleMini.menu.opt.oslto=Smallest Code with LTO mapleMini.menu.opt.oslto.build.flags.optimize=-Os -flto mapleMini.menu.opt.oslto.build.flags.ldspecs=-flto +mapleMini.menu.opt.o1std=Fast (-O1) +mapleMini.menu.opt.o1std.build.flags.optimize=-O1 +mapleMini.menu.opt.o1std.build.flags.ldspecs= +mapleMini.menu.opt.o1lto=Fast (-O1) with LTO +mapleMini.menu.opt.o1lto.build.flags.optimize=-O1 -flto +mapleMini.menu.opt.o1lto.build.flags.ldspecs=-flto +mapleMini.menu.opt.o2std=Faster (-O2) +mapleMini.menu.opt.o2std.build.flags.optimize=-O2 +mapleMini.menu.opt.o2std.build.flags.ldspecs= +mapleMini.menu.opt.o2lto=Faster (-O2) with LTO +mapleMini.menu.opt.o2lto.build.flags.optimize=-O2 -flto +mapleMini.menu.opt.o2lto.build.flags.ldspecs=-flto +mapleMini.menu.opt.o3std=Fastest (-03) +mapleMini.menu.opt.o3std.build.flags.optimize=-O3 +mapleMini.menu.opt.o3std.build.flags.ldspecs= +mapleMini.menu.opt.o3lto=Fastest (-0) with LTO +mapleMini.menu.opt.o3lto.build.flags.optimize=-O3 -flto +mapleMini.menu.opt.o3lto.build.flags.ldspecs=-flto +mapleMini.menu.opt.ogstd=Debug (-g) +mapleMini.menu.opt.ogstd.build.flags.optimize=-Og +mapleMini.menu.opt.ogstd.build.flags.ldspecs= +mapleMini.menu.opt.oglto=Debug with LTO +mapleMini.menu.opt.oglto.build.flags.optimize=-Og -flto +mapleMini.menu.opt.oglto.build.flags.ldspecs=-flto ############################################################## @@ -100,36 +100,36 @@ maple.build.variant=maple maple.build.vect=VECT_TAB_ADDR=0x8005000 #-- Optimizations -maple.menu.opt.o2std=Faster -maple.menu.opt.o2std.build.flags.optimize=-O2 -maple.menu.opt.o2std.build.flags.ldspecs= -maple.menu.opt.o2lto=Faster with LTO -maple.menu.opt.o2lto.build.flags.optimize=-O2 -flto -maple.menu.opt.o2lto.build.flags.ldspecs=-flto -maple.menu.opt.o1std=Fast -maple.menu.opt.o1std.build.flags.optimize=-O1 -maple.menu.opt.o1std.build.flags.ldspecs= -maple.menu.opt.o1lto=Fast with LTO -maple.menu.opt.o1lto.build.flags.optimize=-O1 -flto -maple.menu.opt.o1lto.build.flags.ldspecs=-flto -maple.menu.opt.o3std=Fastest -maple.menu.opt.o3std.build.flags.optimize=-O3 -maple.menu.opt.o3std.build.flags.ldspecs= -maple.menu.opt.o3lto=Fastest with LTO -maple.menu.opt.o3lto.build.flags.optimize=-O3 -flto -maple.menu.opt.o3lto.build.flags.ldspecs=-flto -maple.menu.opt.ogstd=Debug -maple.menu.opt.ogstd.build.flags.optimize=-Og -maple.menu.opt.ogstd.build.flags.ldspecs= -maple.menu.opt.oglto=Debug with LTO -maple.menu.opt.oglto.build.flags.optimize=-Og -flto -maple.menu.opt.oglto.build.flags.ldspecs=-flto -maple.menu.opt.osstd=Smallest Code +maple.menu.opt.osstd=Smallest (default) maple.menu.opt.osstd.build.flags.optimize=-Os maple.menu.opt.osstd.build.flags.ldspecs= maple.menu.opt.oslto=Smallest Code with LTO maple.menu.opt.oslto.build.flags.optimize=-Os -flto maple.menu.opt.oslto.build.flags.ldspecs=-flto +maple.menu.opt.o1std=Fast (-O1) +maple.menu.opt.o1std.build.flags.optimize=-O1 +maple.menu.opt.o1std.build.flags.ldspecs= +maple.menu.opt.o1lto=Fast (-O1) with LTO +maple.menu.opt.o1lto.build.flags.optimize=-O1 -flto +maple.menu.opt.o1lto.build.flags.ldspecs=-flto +maple.menu.opt.o2std=Faster (-O2) +maple.menu.opt.o2std.build.flags.optimize=-O2 +maple.menu.opt.o2std.build.flags.ldspecs= +maple.menu.opt.o2lto=Faster (-O2) with LTO +maple.menu.opt.o2lto.build.flags.optimize=-O2 -flto +maple.menu.opt.o2lto.build.flags.ldspecs=-flto +maple.menu.opt.o3std=Fastest (-03) +maple.menu.opt.o3std.build.flags.optimize=-O3 +maple.menu.opt.o3std.build.flags.ldspecs= +maple.menu.opt.o3lto=Fastest (-0) with LTO +maple.menu.opt.o3lto.build.flags.optimize=-O3 -flto +maple.menu.opt.o3lto.build.flags.ldspecs=-flto +maple.menu.opt.ogstd=Debug (-g) +maple.menu.opt.ogstd.build.flags.optimize=-Og +maple.menu.opt.ogstd.build.flags.ldspecs= +maple.menu.opt.oglto=Debug with LTO +maple.menu.opt.oglto.build.flags.optimize=-Og -flto +maple.menu.opt.oglto.build.flags.ldspecs=-flto ############################################################## mapleRET6.name=Maple (RET6) @@ -155,36 +155,36 @@ mapleRET6.upload.altID=1 mapleRET6.upload.auto_reset=true #-- Optimizations -mapleRET6.menu.opt.o2std=Faster -mapleRET6.menu.opt.o2std.build.flags.optimize=-O2 -mapleRET6.menu.opt.o2std.build.flags.ldspecs= -mapleRET6.menu.opt.o2lto=Faster with LTO -mapleRET6.menu.opt.o2lto.build.flags.optimize=-O2 -flto -mapleRET6.menu.opt.o2lto.build.flags.ldspecs=-flto -mapleRET6.menu.opt.o1std=Fast -mapleRET6.menu.opt.o1std.build.flags.optimize=-O1 -mapleRET6.menu.opt.o1std.build.flags.ldspecs= -mapleRET6.menu.opt.o1lto=Fast with LTO -mapleRET6.menu.opt.o1lto.build.flags.optimize=-O1 -flto -mapleRET6.menu.opt.o1lto.build.flags.ldspecs=-flto -mapleRET6.menu.opt.o3std=Fastest -mapleRET6.menu.opt.o3std.build.flags.optimize=-O3 -mapleRET6.menu.opt.o3std.build.flags.ldspecs= -mapleRET6.menu.opt.o3lto=Fastest with LTO -mapleRET6.menu.opt.o3lto.build.flags.optimize=-O3 -flto -mapleRET6.menu.opt.o3lto.build.flags.ldspecs=-flto -mapleRET6.menu.opt.ogstd=Debug -mapleRET6.menu.opt.ogstd.build.flags.optimize=-Og -mapleRET6.menu.opt.ogstd.build.flags.ldspecs= -mapleRET6.menu.opt.oglto=Debug with LTO -mapleRET6.menu.opt.oglto.build.flags.optimize=-Og -flto -mapleRET6.menu.opt.oglto.build.flags.ldspecs=-flto -mapleRET6.menu.opt.osstd=Smallest Code +mapleRET6.menu.opt.osstd=Smallest (default) mapleRET6.menu.opt.osstd.build.flags.optimize=-Os mapleRET6.menu.opt.osstd.build.flags.ldspecs= mapleRET6.menu.opt.oslto=Smallest Code with LTO mapleRET6.menu.opt.oslto.build.flags.optimize=-Os -flto mapleRET6.menu.opt.oslto.build.flags.ldspecs=-flto +mapleRET6.menu.opt.o1std=Fast (-O1) +mapleRET6.menu.opt.o1std.build.flags.optimize=-O1 +mapleRET6.menu.opt.o1std.build.flags.ldspecs= +mapleRET6.menu.opt.o1lto=Fast (-O1) with LTO +mapleRET6.menu.opt.o1lto.build.flags.optimize=-O1 -flto +mapleRET6.menu.opt.o1lto.build.flags.ldspecs=-flto +mapleRET6.menu.opt.o2std=Faster (-O2) +mapleRET6.menu.opt.o2std.build.flags.optimize=-O2 +mapleRET6.menu.opt.o2std.build.flags.ldspecs= +mapleRET6.menu.opt.o2lto=Faster (-O2) with LTO +mapleRET6.menu.opt.o2lto.build.flags.optimize=-O2 -flto +mapleRET6.menu.opt.o2lto.build.flags.ldspecs=-flto +mapleRET6.menu.opt.o3std=Fastest (-03) +mapleRET6.menu.opt.o3std.build.flags.optimize=-O3 +mapleRET6.menu.opt.o3std.build.flags.ldspecs= +mapleRET6.menu.opt.o3lto=Fastest (-0) with LTO +mapleRET6.menu.opt.o3lto.build.flags.optimize=-O3 -flto +mapleRET6.menu.opt.ogstd=Debug (-g) +mapleRET6.menu.opt.o3lto.build.flags.ldspecs=-flto +mapleRET6.menu.opt.ogstd.build.flags.optimize=-Og +mapleRET6.menu.opt.ogstd.build.flags.ldspecs= +mapleRET6.menu.opt.oglto=Debug with LTO +mapleRET6.menu.opt.oglto.build.flags.optimize=-Og -flto +mapleRET6.menu.opt.oglto.build.flags.ldspecs=-flto ############################################################## @@ -218,36 +218,36 @@ microduino32_flash.build.error_led_pin=1 microduino32_flash.build.gcc_ver=gcc-arm-none-eabi-4.8.3-2014q1 #-- Optimizations -microduino32_flash.menu.opt.o2std=Faster -microduino32_flash.menu.opt.o2std.build.flags.optimize=-O2 -microduino32_flash.menu.opt.o2std.build.flags.ldspecs= -microduino32_flash.menu.opt.o2lto=Faster with LTO -microduino32_flash.menu.opt.o2lto.build.flags.optimize=-O2 -flto -microduino32_flash.menu.opt.o2lto.build.flags.ldspecs=-flto -microduino32_flash.menu.opt.o1std=Fast -microduino32_flash.menu.opt.o1std.build.flags.optimize=-O1 -microduino32_flash.menu.opt.o1std.build.flags.ldspecs= -microduino32_flash.menu.opt.o1lto=Fast with LTO -microduino32_flash.menu.opt.o1lto.build.flags.optimize=-O1 -flto -microduino32_flash.menu.opt.o1lto.build.flags.ldspecs=-flto -microduino32_flash.menu.opt.o3std=Fastest -microduino32_flash.menu.opt.o3std.build.flags.optimize=-O3 -microduino32_flash.menu.opt.o3std.build.flags.ldspecs= -microduino32_flash.menu.opt.o3lto=Fastest with LTO -microduino32_flash.menu.opt.o3lto.build.flags.optimize=-O3 -flto -microduino32_flash.menu.opt.o3lto.build.flags.ldspecs=-flto -microduino32_flash.menu.opt.ogstd=Debug -microduino32_flash.menu.opt.ogstd.build.flags.optimize=-Og -microduino32_flash.menu.opt.ogstd.build.flags.ldspecs= -microduino32_flash.menu.opt.oglto=Debug with LTO -microduino32_flash.menu.opt.oglto.build.flags.optimize=-Og -flto -microduino32_flash.menu.opt.oglto.build.flags.ldspecs=-flto -microduino32_flash.menu.opt.osstd=Smallest Code +microduino32_flash.menu.opt.osstd=Smallest (default) microduino32_flash.menu.opt.osstd.build.flags.optimize=-Os microduino32_flash.menu.opt.osstd.build.flags.ldspecs= microduino32_flash.menu.opt.oslto=Smallest Code with LTO microduino32_flash.menu.opt.oslto.build.flags.optimize=-Os -flto microduino32_flash.menu.opt.oslto.build.flags.ldspecs=-flto +microduino32_flash.menu.opt.o1std=Fast (-O1) +microduino32_flash.menu.opt.o1std.build.flags.optimize=-O1 +microduino32_flash.menu.opt.o1std.build.flags.ldspecs= +microduino32_flash.menu.opt.o1lto=Fast (-O1) with LTO +microduino32_flash.menu.opt.o1lto.build.flags.optimize=-O1 -flto +microduino32_flash.menu.opt.o1lto.build.flags.ldspecs=-flto +microduino32_flash.menu.opt.o2std=Faster (-O2) +microduino32_flash.menu.opt.o2std.build.flags.optimize=-O2 +microduino32_flash.menu.opt.o2std.build.flags.ldspecs= +microduino32_flash.menu.opt.o2lto=Faster (-O2) with LTO +microduino32_flash.menu.opt.o2lto.build.flags.optimize=-O2 -flto +microduino32_flash.menu.opt.o2lto.build.flags.ldspecs=-flto +microduino32_flash.menu.opt.o3std=Fastest (-03) +microduino32_flash.menu.opt.o3std.build.flags.optimize=-O3 +microduino32_flash.menu.opt.o3std.build.flags.ldspecs= +microduino32_flash.menu.opt.o3lto=Fastest (-0) with LTO +microduino32_flash.menu.opt.o3lto.build.flags.optimize=-O3 -flto +microduino32_flash.menu.opt.ogstd=Debug (-g) +microduino32_flash.menu.opt.o3lto.build.flags.ldspecs=-flto +microduino32_flash.menu.opt.ogstd.build.flags.optimize=-Og +microduino32_flash.menu.opt.ogstd.build.flags.ldspecs= +microduino32_flash.menu.opt.oglto=Debug with LTO +microduino32_flash.menu.opt.oglto.build.flags.optimize=-Og -flto +microduino32_flash.menu.opt.oglto.build.flags.ldspecs=-flto ############################################################## nucleo_f103rb.name=STM Nucleo F103RB (STLink) @@ -288,36 +288,36 @@ nucleo_f103rb.menu.device_variant.NucleoF103_HSE.build.f_cpu=72000000L nucleo_f103rb.menu.device_variant.NucleoF103_HSE.build.extra_flags=-DNUCLEO_HSE_CRYSTAL -DMCU_STM32F103RB -mthumb -march=armv7-m -D__STM32F1__ #-- Optimizations -nucleo_f103rb.menu.opt.o2std=Faster -nucleo_f103rb.menu.opt.o2std.build.flags.optimize=-O2 -nucleo_f103rb.menu.opt.o2std.build.flags.ldspecs= -nucleo_f103rb.menu.opt.o2lto=Faster with LTO -nucleo_f103rb.menu.opt.o2lto.build.flags.optimize=-O2 -flto -nucleo_f103rb.menu.opt.o2lto.build.flags.ldspecs=-flto -nucleo_f103rb.menu.opt.o1std=Fast -nucleo_f103rb.menu.opt.o1std.build.flags.optimize=-O1 -nucleo_f103rb.menu.opt.o1std.build.flags.ldspecs= -nucleo_f103rb.menu.opt.o1lto=Fast with LTO -nucleo_f103rb.menu.opt.o1lto.build.flags.optimize=-O1 -flto -nucleo_f103rb.menu.opt.o1lto.build.flags.ldspecs=-flto -nucleo_f103rb.menu.opt.o3std=Fastest -nucleo_f103rb.menu.opt.o3std.build.flags.optimize=-O3 -nucleo_f103rb.menu.opt.o3std.build.flags.ldspecs= -nucleo_f103rb.menu.opt.o3lto=Fastest with LTO -nucleo_f103rb.menu.opt.o3lto.build.flags.optimize=-O3 -flto -nucleo_f103rb.menu.opt.o3lto.build.flags.ldspecs=-flto -nucleo_f103rb.menu.opt.ogstd=Debug -nucleo_f103rb.menu.opt.ogstd.build.flags.optimize=-Og -nucleo_f103rb.menu.opt.ogstd.build.flags.ldspecs= -nucleo_f103rb.menu.opt.oglto=Debug with LTO -nucleo_f103rb.menu.opt.oglto.build.flags.optimize=-Og -flto -nucleo_f103rb.menu.opt.oglto.build.flags.ldspecs=-flto -nucleo_f103rb.menu.opt.osstd=Smallest Code +nucleo_f103rb.menu.opt.osstd=Smallest (default) nucleo_f103rb.menu.opt.osstd.build.flags.optimize=-Os nucleo_f103rb.menu.opt.osstd.build.flags.ldspecs= nucleo_f103rb.menu.opt.oslto=Smallest Code with LTO nucleo_f103rb.menu.opt.oslto.build.flags.optimize=-Os -flto nucleo_f103rb.menu.opt.oslto.build.flags.ldspecs=-flto +nucleo_f103rb.menu.opt.o1std=Fast (-O1) +nucleo_f103rb.menu.opt.o1std.build.flags.optimize=-O1 +nucleo_f103rb.menu.opt.o1std.build.flags.ldspecs= +nucleo_f103rb.menu.opt.o1lto=Fast (-O1) with LTO +nucleo_f103rb.menu.opt.o1lto.build.flags.optimize=-O1 -flto +nucleo_f103rb.menu.opt.o1lto.build.flags.ldspecs=-flto +nucleo_f103rb.menu.opt.o2std=Faster (-O2) +nucleo_f103rb.menu.opt.o2std.build.flags.optimize=-O2 +nucleo_f103rb.menu.opt.o2std.build.flags.ldspecs= +nucleo_f103rb.menu.opt.o2lto=Faster (-O2) with LTO +nucleo_f103rb.menu.opt.o2lto.build.flags.optimize=-O2 -flto +nucleo_f103rb.menu.opt.o2lto.build.flags.ldspecs=-flto +nucleo_f103rb.menu.opt.o3std=Fastest (-03) +nucleo_f103rb.menu.opt.o3std.build.flags.optimize=-O3 +nucleo_f103rb.menu.opt.o3std.build.flags.ldspecs= +nucleo_f103rb.menu.opt.o3lto=Fastest (-0) with LTO +nucleo_f103rb.menu.opt.o3lto.build.flags.optimize=-O3 -flto +nucleo_f103rb.menu.opt.ogstd=Debug (-g) +nucleo_f103rb.menu.opt.o3lto.build.flags.ldspecs=-flto +nucleo_f103rb.menu.opt.ogstd.build.flags.optimize=-Og +nucleo_f103rb.menu.opt.ogstd.build.flags.ldspecs= +nucleo_f103rb.menu.opt.oglto=Debug with LTO +nucleo_f103rb.menu.opt.oglto.build.flags.optimize=-Og -flto +nucleo_f103rb.menu.opt.oglto.build.flags.ldspecs=-flto ###################### Generic STM32F103C ######################################## @@ -385,36 +385,36 @@ genericSTM32F103C.menu.cpu_speed.speed_48mhz=48Mhz (Slow - with USB) genericSTM32F103C.menu.cpu_speed.speed_48mhz.build.f_cpu=48000000L #-- Optimizations -genericSTM32F103C.menu.opt.o2std=Faster -genericSTM32F103C.menu.opt.o2std.build.flags.optimize=-O2 -genericSTM32F103C.menu.opt.o2std.build.flags.ldspecs= -genericSTM32F103C.menu.opt.o2lto=Faster with LTO -genericSTM32F103C.menu.opt.o2lto.build.flags.optimize=-O2 -flto -genericSTM32F103C.menu.opt.o2lto.build.flags.ldspecs=-flto -genericSTM32F103C.menu.opt.o1std=Fast -genericSTM32F103C.menu.opt.o1std.build.flags.optimize=-O1 -genericSTM32F103C.menu.opt.o1std.build.flags.ldspecs= -genericSTM32F103C.menu.opt.o1lto=Fast with LTO -genericSTM32F103C.menu.opt.o1lto.build.flags.optimize=-O1 -flto -genericSTM32F103C.menu.opt.o1lto.build.flags.ldspecs=-flto -genericSTM32F103C.menu.opt.o3std=Fastest -genericSTM32F103C.menu.opt.o3std.build.flags.optimize=-O3 -genericSTM32F103C.menu.opt.o3std.build.flags.ldspecs= -genericSTM32F103C.menu.opt.o3lto=Fastest with LTO -genericSTM32F103C.menu.opt.o3lto.build.flags.optimize=-O3 -flto -genericSTM32F103C.menu.opt.o3lto.build.flags.ldspecs=-flto -genericSTM32F103C.menu.opt.ogstd=Debug -genericSTM32F103C.menu.opt.ogstd.build.flags.optimize=-Og -genericSTM32F103C.menu.opt.ogstd.build.flags.ldspecs= -genericSTM32F103C.menu.opt.oglto=Debug with LTO -genericSTM32F103C.menu.opt.oglto.build.flags.optimize=-Og -flto -genericSTM32F103C.menu.opt.oglto.build.flags.ldspecs=-flto -genericSTM32F103C.menu.opt.osstd=Smallest Code +genericSTM32F103C.menu.opt.osstd=Smallest (default) genericSTM32F103C.menu.opt.osstd.build.flags.optimize=-Os genericSTM32F103C.menu.opt.osstd.build.flags.ldspecs= genericSTM32F103C.menu.opt.oslto=Smallest Code with LTO genericSTM32F103C.menu.opt.oslto.build.flags.optimize=-Os -flto genericSTM32F103C.menu.opt.oslto.build.flags.ldspecs=-flto +genericSTM32F103C.menu.opt.o1std=Fast (-O1) +genericSTM32F103C.menu.opt.o1std.build.flags.optimize=-O1 +genericSTM32F103C.menu.opt.o1std.build.flags.ldspecs= +genericSTM32F103C.menu.opt.o1lto=Fast (-O1) with LTO +genericSTM32F103C.menu.opt.o1lto.build.flags.optimize=-O1 -flto +genericSTM32F103C.menu.opt.o1lto.build.flags.ldspecs=-flto +genericSTM32F103C.menu.opt.o2std=Faster (-O2) +genericSTM32F103C.menu.opt.o2std.build.flags.optimize=-O2 +genericSTM32F103C.menu.opt.o2std.build.flags.ldspecs= +genericSTM32F103C.menu.opt.o2lto=Faster (-O2) with LTO +genericSTM32F103C.menu.opt.o2lto.build.flags.optimize=-O2 -flto +genericSTM32F103C.menu.opt.o2lto.build.flags.ldspecs=-flto +genericSTM32F103C.menu.opt.o3std=Fastest (-03) +genericSTM32F103C.menu.opt.o3std.build.flags.optimize=-O3 +genericSTM32F103C.menu.opt.o3std.build.flags.ldspecs= +genericSTM32F103C.menu.opt.o3lto=Fastest (-0) with LTO +genericSTM32F103C.menu.opt.o3lto.build.flags.optimize=-O3 -flto +genericSTM32F103C.menu.opt.ogstd=Debug (-g) +genericSTM32F103C.menu.opt.o3lto.build.flags.ldspecs=-flto +genericSTM32F103C.menu.opt.ogstd.build.flags.optimize=-Og +genericSTM32F103C.menu.opt.ogstd.build.flags.ldspecs= +genericSTM32F103C.menu.opt.oglto=Debug with LTO +genericSTM32F103C.menu.opt.oglto.build.flags.optimize=-Og -flto +genericSTM32F103C.menu.opt.oglto.build.flags.ldspecs=-flto ########################### Generic STM32F103R ########################### @@ -486,36 +486,36 @@ genericSTM32F103R.menu.upload_method.BMPMethod.upload.tool=bmp_upload genericSTM32F103R.menu.upload_method.BMPMethod.build.upload_flags=-DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG #-- Optimizations -genericSTM32F103R.menu.opt.o2std=Faster -genericSTM32F103R.menu.opt.o2std.build.flags.optimize=-O2 -genericSTM32F103R.menu.opt.o2std.build.flags.ldspecs= -genericSTM32F103R.menu.opt.o2lto=Faster with LTO -genericSTM32F103R.menu.opt.o2lto.build.flags.optimize=-O2 -flto -genericSTM32F103R.menu.opt.o2lto.build.flags.ldspecs=-flto -genericSTM32F103R.menu.opt.o1std=Fast -genericSTM32F103R.menu.opt.o1std.build.flags.optimize=-O1 -genericSTM32F103R.menu.opt.o1std.build.flags.ldspecs= -genericSTM32F103R.menu.opt.o1lto=Fast with LTO -genericSTM32F103R.menu.opt.o1lto.build.flags.optimize=-O1 -flto -genericSTM32F103R.menu.opt.o1lto.build.flags.ldspecs=-flto -genericSTM32F103R.menu.opt.o3std=Fastest -genericSTM32F103R.menu.opt.o3std.build.flags.optimize=-O3 -genericSTM32F103R.menu.opt.o3std.build.flags.ldspecs= -genericSTM32F103R.menu.opt.o3lto=Fastest with LTO -genericSTM32F103R.menu.opt.o3lto.build.flags.optimize=-O3 -flto -genericSTM32F103R.menu.opt.o3lto.build.flags.ldspecs=-flto -genericSTM32F103R.menu.opt.ogstd=Debug -genericSTM32F103R.menu.opt.ogstd.build.flags.optimize=-Og -genericSTM32F103R.menu.opt.ogstd.build.flags.ldspecs= -genericSTM32F103R.menu.opt.oglto=Debug with LTO -genericSTM32F103R.menu.opt.oglto.build.flags.optimize=-Og -flto -genericSTM32F103R.menu.opt.oglto.build.flags.ldspecs=-flto -genericSTM32F103R.menu.opt.osstd=Smallest Code +genericSTM32F103R.menu.opt.osstd=Smallest (default) genericSTM32F103R.menu.opt.osstd.build.flags.optimize=-Os genericSTM32F103R.menu.opt.osstd.build.flags.ldspecs= genericSTM32F103R.menu.opt.oslto=Smallest Code with LTO genericSTM32F103R.menu.opt.oslto.build.flags.optimize=-Os -flto genericSTM32F103R.menu.opt.oslto.build.flags.ldspecs=-flto +genericSTM32F103R.menu.opt.o1std=Fast (-O1) +genericSTM32F103R.menu.opt.o1std.build.flags.optimize=-O1 +genericSTM32F103R.menu.opt.o1std.build.flags.ldspecs= +genericSTM32F103R.menu.opt.o1lto=Fast (-O1) with LTO +genericSTM32F103R.menu.opt.o1lto.build.flags.optimize=-O1 -flto +genericSTM32F103R.menu.opt.o1lto.build.flags.ldspecs=-flto +genericSTM32F103R.menu.opt.o2std=Faster (-O2) +genericSTM32F103R.menu.opt.o2std.build.flags.optimize=-O2 +genericSTM32F103R.menu.opt.o2std.build.flags.ldspecs= +genericSTM32F103R.menu.opt.o2lto=Faster (-O2) with LTO +genericSTM32F103R.menu.opt.o2lto.build.flags.optimize=-O2 -flto +genericSTM32F103R.menu.opt.o2lto.build.flags.ldspecs=-flto +genericSTM32F103R.menu.opt.o3std=Fastest (-03) +genericSTM32F103R.menu.opt.o3std.build.flags.optimize=-O3 +genericSTM32F103R.menu.opt.o3std.build.flags.ldspecs= +genericSTM32F103R.menu.opt.o3lto=Fastest (-0) with LTO +genericSTM32F103R.menu.opt.o3lto.build.flags.optimize=-O3 -flto +genericSTM32F103R.menu.opt.ogstd=Debug (-g) +genericSTM32F103R.menu.opt.o3lto.build.flags.ldspecs=-flto +genericSTM32F103R.menu.opt.ogstd.build.flags.optimize=-Og +genericSTM32F103R.menu.opt.ogstd.build.flags.ldspecs= +genericSTM32F103R.menu.opt.oglto=Debug with LTO +genericSTM32F103R.menu.opt.oglto.build.flags.optimize=-Og -flto +genericSTM32F103R.menu.opt.oglto.build.flags.ldspecs=-flto ###################### Generic STM32F103T ######################################## @@ -571,36 +571,36 @@ genericSTM32F103T.menu.upload_method.BMPMethod.upload.tool=bmp_upload genericSTM32F103T.menu.upload_method.BMPMethod.build.upload_flags=-DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG #-- Optimizations -genericSTM32F103T.menu.opt.o2std=Faster -genericSTM32F103T.menu.opt.o2std.build.flags.optimize=-O2 -genericSTM32F103T.menu.opt.o2std.build.flags.ldspecs= -genericSTM32F103T.menu.opt.o2lto=Faster with LTO -genericSTM32F103T.menu.opt.o2lto.build.flags.optimize=-O2 -flto -genericSTM32F103T.menu.opt.o2lto.build.flags.ldspecs=-flto -genericSTM32F103T.menu.opt.o1std=Fast -genericSTM32F103T.menu.opt.o1std.build.flags.optimize=-O1 -genericSTM32F103T.menu.opt.o1std.build.flags.ldspecs= -genericSTM32F103T.menu.opt.o1lto=Fast with LTO -genericSTM32F103T.menu.opt.o1lto.build.flags.optimize=-O1 -flto -genericSTM32F103T.menu.opt.o1lto.build.flags.ldspecs=-flto -genericSTM32F103T.menu.opt.o3std=Fastest -genericSTM32F103T.menu.opt.o3std.build.flags.optimize=-O3 -genericSTM32F103T.menu.opt.o3std.build.flags.ldspecs= -genericSTM32F103T.menu.opt.o3lto=Fastest with LTO -genericSTM32F103T.menu.opt.o3lto.build.flags.optimize=-O3 -flto -genericSTM32F103T.menu.opt.o3lto.build.flags.ldspecs=-flto -genericSTM32F103T.menu.opt.ogstd=Debug -genericSTM32F103T.menu.opt.ogstd.build.flags.optimize=-Og -genericSTM32F103T.menu.opt.ogstd.build.flags.ldspecs= -genericSTM32F103T.menu.opt.oglto=Debug with LTO -genericSTM32F103T.menu.opt.oglto.build.flags.optimize=-Og -flto -genericSTM32F103T.menu.opt.oglto.build.flags.ldspecs=-flto -genericSTM32F103T.menu.opt.osstd=Smallest Code +genericSTM32F103T.menu.opt.osstd=Smallest (default) genericSTM32F103T.menu.opt.osstd.build.flags.optimize=-Os genericSTM32F103T.menu.opt.osstd.build.flags.ldspecs= genericSTM32F103T.menu.opt.oslto=Smallest Code with LTO genericSTM32F103T.menu.opt.oslto.build.flags.optimize=-Os -flto genericSTM32F103T.menu.opt.oslto.build.flags.ldspecs=-flto +genericSTM32F103T.menu.opt.o1std=Fast (-O1) +genericSTM32F103T.menu.opt.o1std.build.flags.optimize=-O1 +genericSTM32F103T.menu.opt.o1std.build.flags.ldspecs= +genericSTM32F103T.menu.opt.o1lto=Fast (-O1) with LTO +genericSTM32F103T.menu.opt.o1lto.build.flags.optimize=-O1 -flto +genericSTM32F103T.menu.opt.o1lto.build.flags.ldspecs=-flto +genericSTM32F103T.menu.opt.o2std=Faster (-O2) +genericSTM32F103T.menu.opt.o2std.build.flags.optimize=-O2 +genericSTM32F103T.menu.opt.o2std.build.flags.ldspecs= +genericSTM32F103T.menu.opt.o2lto=Faster (-O2) with LTO +genericSTM32F103T.menu.opt.o2lto.build.flags.optimize=-O2 -flto +genericSTM32F103T.menu.opt.o2lto.build.flags.ldspecs=-flto +genericSTM32F103T.menu.opt.o3std=Fastest (-03) +genericSTM32F103T.menu.opt.o3std.build.flags.optimize=-O3 +genericSTM32F103T.menu.opt.o3std.build.flags.ldspecs= +genericSTM32F103T.menu.opt.o3lto=Fastest (-0) with LTO +genericSTM32F103T.menu.opt.o3lto.build.flags.optimize=-O3 -flto +genericSTM32F103T.menu.opt.ogstd=Debug (-g) +genericSTM32F103T.menu.opt.o3lto.build.flags.ldspecs=-flto +genericSTM32F103T.menu.opt.ogstd.build.flags.optimize=-Og +genericSTM32F103T.menu.opt.ogstd.build.flags.ldspecs= +genericSTM32F103T.menu.opt.oglto=Debug with LTO +genericSTM32F103T.menu.opt.oglto.build.flags.optimize=-Og -flto +genericSTM32F103T.menu.opt.oglto.build.flags.ldspecs=-flto ########################### Generic STM32F103V ########################### @@ -663,36 +663,36 @@ genericSTM32F103V.menu.upload_method.BMPMethod.upload.tool=bmp_upload genericSTM32F103V.menu.upload_method.BMPMethod.build.upload_flags=-DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG #-- Optimizations -genericSTM32F103V.menu.opt.o2std=Faster -genericSTM32F103V.menu.opt.o2std.build.flags.optimize=-O2 -genericSTM32F103V.menu.opt.o2std.build.flags.ldspecs= -genericSTM32F103V.menu.opt.o2lto=Faster with LTO -genericSTM32F103V.menu.opt.o2lto.build.flags.optimize=-O2 -flto -genericSTM32F103V.menu.opt.o2lto.build.flags.ldspecs=-flto -genericSTM32F103V.menu.opt.o1std=Fast -genericSTM32F103V.menu.opt.o1std.build.flags.optimize=-O1 -genericSTM32F103V.menu.opt.o1std.build.flags.ldspecs= -genericSTM32F103V.menu.opt.o1lto=Fast with LTO -genericSTM32F103V.menu.opt.o1lto.build.flags.optimize=-O1 -flto -genericSTM32F103V.menu.opt.o1lto.build.flags.ldspecs=-flto -genericSTM32F103V.menu.opt.o3std=Fastest -genericSTM32F103V.menu.opt.o3std.build.flags.optimize=-O3 -genericSTM32F103V.menu.opt.o3std.build.flags.ldspecs= -genericSTM32F103V.menu.opt.o3lto=Fastest with LTO -genericSTM32F103V.menu.opt.o3lto.build.flags.optimize=-O3 -flto -genericSTM32F103V.menu.opt.o3lto.build.flags.ldspecs=-flto -genericSTM32F103V.menu.opt.ogstd=Debug -genericSTM32F103V.menu.opt.ogstd.build.flags.optimize=-Og -genericSTM32F103V.menu.opt.ogstd.build.flags.ldspecs= -genericSTM32F103V.menu.opt.oglto=Debug with LTO -genericSTM32F103V.menu.opt.oglto.build.flags.optimize=-Og -flto -genericSTM32F103V.menu.opt.oglto.build.flags.ldspecs=-flto -genericSTM32F103V.menu.opt.osstd=Smallest Code +genericSTM32F103V.menu.opt.osstd=Smallest (default) genericSTM32F103V.menu.opt.osstd.build.flags.optimize=-Os genericSTM32F103V.menu.opt.osstd.build.flags.ldspecs= genericSTM32F103V.menu.opt.oslto=Smallest Code with LTO genericSTM32F103V.menu.opt.oslto.build.flags.optimize=-Os -flto genericSTM32F103V.menu.opt.oslto.build.flags.ldspecs=-flto +genericSTM32F103V.menu.opt.o1std=Fast (-O1) +genericSTM32F103V.menu.opt.o1std.build.flags.optimize=-O1 +genericSTM32F103V.menu.opt.o1std.build.flags.ldspecs= +genericSTM32F103V.menu.opt.o1lto=Fast (-O1) with LTO +genericSTM32F103V.menu.opt.o1lto.build.flags.optimize=-O1 -flto +genericSTM32F103V.menu.opt.o1lto.build.flags.ldspecs=-flto +genericSTM32F103V.menu.opt.o2std=Faster (-O2) +genericSTM32F103V.menu.opt.o2std.build.flags.optimize=-O2 +genericSTM32F103V.menu.opt.o2std.build.flags.ldspecs= +genericSTM32F103V.menu.opt.o2lto=Faster (-O2) with LTO +genericSTM32F103V.menu.opt.o2lto.build.flags.optimize=-O2 -flto +genericSTM32F103V.menu.opt.o2lto.build.flags.ldspecs=-flto +genericSTM32F103V.menu.opt.o3std=Fastest (-03) +genericSTM32F103V.menu.opt.o3std.build.flags.optimize=-O3 +genericSTM32F103V.menu.opt.o3std.build.flags.ldspecs= +genericSTM32F103V.menu.opt.o3lto=Fastest (-0) with LTO +genericSTM32F103V.menu.opt.o3lto.build.flags.optimize=-O3 -flto +genericSTM32F103V.menu.opt.ogstd=Debug (-g) +genericSTM32F103V.menu.opt.o3lto.build.flags.ldspecs=-flto +genericSTM32F103V.menu.opt.ogstd.build.flags.optimize=-Og +genericSTM32F103V.menu.opt.ogstd.build.flags.ldspecs= +genericSTM32F103V.menu.opt.oglto=Debug with LTO +genericSTM32F103V.menu.opt.oglto.build.flags.optimize=-Og -flto +genericSTM32F103V.menu.opt.oglto.build.flags.ldspecs=-flto ########################### Generic STM32F103Z ########################### @@ -752,36 +752,36 @@ genericSTM32F103Z.menu.upload_method.BMPMethod.upload.tool=bmp_upload genericSTM32F103Z.menu.upload_method.BMPMethod.build.upload_flags=-DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG #-- Optimizations -genericSTM32F103Z.menu.opt.o2std=Faster -genericSTM32F103Z.menu.opt.o2std.build.flags.optimize=-O2 -genericSTM32F103Z.menu.opt.o2std.build.flags.ldspecs= -genericSTM32F103Z.menu.opt.o2lto=Faster with LTO -genericSTM32F103Z.menu.opt.o2lto.build.flags.optimize=-O2 -flto -genericSTM32F103Z.menu.opt.o2lto.build.flags.ldspecs=-flto -genericSTM32F103Z.menu.opt.o1std=Fast -genericSTM32F103Z.menu.opt.o1std.build.flags.optimize=-O1 -genericSTM32F103Z.menu.opt.o1std.build.flags.ldspecs= -genericSTM32F103Z.menu.opt.o1lto=Fast with LTO -genericSTM32F103Z.menu.opt.o1lto.build.flags.optimize=-O1 -flto -genericSTM32F103Z.menu.opt.o1lto.build.flags.ldspecs=-flto -genericSTM32F103Z.menu.opt.o3std=Fastest -genericSTM32F103Z.menu.opt.o3std.build.flags.optimize=-O3 -genericSTM32F103Z.menu.opt.o3std.build.flags.ldspecs= -genericSTM32F103Z.menu.opt.o3lto=Fastest with LTO -genericSTM32F103Z.menu.opt.o3lto.build.flags.optimize=-O3 -flto -genericSTM32F103Z.menu.opt.o3lto.build.flags.ldspecs=-flto -genericSTM32F103Z.menu.opt.ogstd=Debug -genericSTM32F103Z.menu.opt.ogstd.build.flags.optimize=-Og -genericSTM32F103Z.menu.opt.ogstd.build.flags.ldspecs= -genericSTM32F103Z.menu.opt.oglto=Debug with LTO -genericSTM32F103Z.menu.opt.oglto.build.flags.optimize=-Og -flto -genericSTM32F103Z.menu.opt.oglto.build.flags.ldspecs=-flto -genericSTM32F103Z.menu.opt.osstd=Smallest Code +genericSTM32F103Z.menu.opt.osstd=Smallest (default) genericSTM32F103Z.menu.opt.osstd.build.flags.optimize=-Os genericSTM32F103Z.menu.opt.osstd.build.flags.ldspecs= genericSTM32F103Z.menu.opt.oslto=Smallest Code with LTO genericSTM32F103Z.menu.opt.oslto.build.flags.optimize=-Os -flto genericSTM32F103Z.menu.opt.oslto.build.flags.ldspecs=-flto +genericSTM32F103Z.menu.opt.o1std=Fast (-O1) +genericSTM32F103Z.menu.opt.o1std.build.flags.optimize=-O1 +genericSTM32F103Z.menu.opt.o1std.build.flags.ldspecs= +genericSTM32F103Z.menu.opt.o1lto=Fast (-O1) with LTO +genericSTM32F103Z.menu.opt.o1lto.build.flags.optimize=-O1 -flto +genericSTM32F103Z.menu.opt.o1lto.build.flags.ldspecs=-flto +genericSTM32F103Z.menu.opt.o2std=Faster (-O2) +genericSTM32F103Z.menu.opt.o2std.build.flags.optimize=-O2 +genericSTM32F103Z.menu.opt.o2std.build.flags.ldspecs= +genericSTM32F103Z.menu.opt.o2lto=Faster (-O2) with LTO +genericSTM32F103Z.menu.opt.o2lto.build.flags.optimize=-O2 -flto +genericSTM32F103Z.menu.opt.o2lto.build.flags.ldspecs=-flto +genericSTM32F103Z.menu.opt.o3std=Fastest (-03) +genericSTM32F103Z.menu.opt.o3std.build.flags.optimize=-O3 +genericSTM32F103Z.menu.opt.o3std.build.flags.ldspecs= +genericSTM32F103Z.menu.opt.o3lto=Fastest (-0) with LTO +genericSTM32F103Z.menu.opt.o3lto.build.flags.optimize=-O3 -flto +genericSTM32F103Z.menu.opt.ogstd=Debug (-g) +genericSTM32F103Z.menu.opt.o3lto.build.flags.ldspecs=-flto +genericSTM32F103Z.menu.opt.ogstd.build.flags.optimize=-Og +genericSTM32F103Z.menu.opt.ogstd.build.flags.ldspecs= +genericSTM32F103Z.menu.opt.oglto=Debug with LTO +genericSTM32F103Z.menu.opt.oglto.build.flags.optimize=-Og -flto +genericSTM32F103Z.menu.opt.oglto.build.flags.ldspecs=-flto ###################### HYTiny STM32F103T ######################################## @@ -835,36 +835,36 @@ hytiny-stm32f103t.menu.upload_method.jlinkMethod.upload.tool=jlink_upload hytiny-stm32f103t.menu.upload_method.jlinkMethod.build.upload_flags=-DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG=1 -DSERIAL_USB -DGENERIC_BOOTLOADER #-- Optimizations -hytiny-stm32f103t.menu.opt.o2std=Faster -hytiny-stm32f103t.menu.opt.o2std.build.flags.optimize=-O2 -hytiny-stm32f103t.menu.opt.o2std.build.flags.ldspecs= -hytiny-stm32f103t.menu.opt.o2lto=Faster with LTO -hytiny-stm32f103t.menu.opt.o2lto.build.flags.optimize=-O2 -flto -hytiny-stm32f103t.menu.opt.o2lto.build.flags.ldspecs=-flto -hytiny-stm32f103t.menu.opt.o1std=Fast -hytiny-stm32f103t.menu.opt.o1std.build.flags.optimize=-O1 -hytiny-stm32f103t.menu.opt.o1std.build.flags.ldspecs= -hytiny-stm32f103t.menu.opt.o1lto=Fast with LTO -hytiny-stm32f103t.menu.opt.o1lto.build.flags.optimize=-O1 -flto -hytiny-stm32f103t.menu.opt.o1lto.build.flags.ldspecs=-flto -hytiny-stm32f103t.menu.opt.o3std=Fastest -hytiny-stm32f103t.menu.opt.o3std.build.flags.optimize=-O3 -hytiny-stm32f103t.menu.opt.o3std.build.flags.ldspecs= -hytiny-stm32f103t.menu.opt.o3lto=Fastest with LTO -hytiny-stm32f103t.menu.opt.o3lto.build.flags.optimize=-O3 -flto -hytiny-stm32f103t.menu.opt.o3lto.build.flags.ldspecs=-flto -hytiny-stm32f103t.menu.opt.ogstd=Debug -hytiny-stm32f103t.menu.opt.ogstd.build.flags.optimize=-Og -hytiny-stm32f103t.menu.opt.ogstd.build.flags.ldspecs= -hytiny-stm32f103t.menu.opt.oglto=Debug with LTO -hytiny-stm32f103t.menu.opt.oglto.build.flags.optimize=-Og -flto -hytiny-stm32f103t.menu.opt.oglto.build.flags.ldspecs=-flto -hytiny-stm32f103t.menu.opt.osstd=Smallest Code +hytiny-stm32f103t.menu.opt.osstd=Smallest (default) hytiny-stm32f103t.menu.opt.osstd.build.flags.optimize=-Os hytiny-stm32f103t.menu.opt.osstd.build.flags.ldspecs= hytiny-stm32f103t.menu.opt.oslto=Smallest Code with LTO hytiny-stm32f103t.menu.opt.oslto.build.flags.optimize=-Os -flto hytiny-stm32f103t.menu.opt.oslto.build.flags.ldspecs=-flto +hytiny-stm32f103t.menu.opt.o1std=Fast (-O1) +hytiny-stm32f103t.menu.opt.o1std.build.flags.optimize=-O1 +hytiny-stm32f103t.menu.opt.o1std.build.flags.ldspecs= +hytiny-stm32f103t.menu.opt.o1lto=Fast (-O1) with LTO +hytiny-stm32f103t.menu.opt.o1lto.build.flags.optimize=-O1 -flto +hytiny-stm32f103t.menu.opt.o1lto.build.flags.ldspecs=-flto +hytiny-stm32f103t.menu.opt.o2std=Faster (-O2) +hytiny-stm32f103t.menu.opt.o2std.build.flags.optimize=-O2 +hytiny-stm32f103t.menu.opt.o2std.build.flags.ldspecs= +hytiny-stm32f103t.menu.opt.o2lto=Faster (-O2) with LTO +hytiny-stm32f103t.menu.opt.o2lto.build.flags.optimize=-O2 -flto +hytiny-stm32f103t.menu.opt.o2lto.build.flags.ldspecs=-flto +hytiny-stm32f103t.menu.opt.o3std=Fastest (-03) +hytiny-stm32f103t.menu.opt.o3std.build.flags.optimize=-O3 +hytiny-stm32f103t.menu.opt.o3std.build.flags.ldspecs= +hytiny-stm32f103t.menu.opt.o3lto=Fastest (-0) with LTO +hytiny-stm32f103t.menu.opt.o3lto.build.flags.optimize=-O3 -flto +hytiny-stm32f103t.menu.opt.ogstd=Debug (-g) +hytiny-stm32f103t.menu.opt.o3lto.build.flags.ldspecs=-flto +hytiny-stm32f103t.menu.opt.ogstd.build.flags.optimize=-Og +hytiny-stm32f103t.menu.opt.ogstd.build.flags.ldspecs= +hytiny-stm32f103t.menu.opt.oglto=Debug with LTO +hytiny-stm32f103t.menu.opt.oglto.build.flags.optimize=-Og -flto +hytiny-stm32f103t.menu.opt.oglto.build.flags.ldspecs=-flto ###################### Generic GD32F103C ######################################## @@ -929,36 +929,36 @@ genericGD32F103C.menu.cpu_speed.speed_72mhz=72Mhz (compatibility) genericGD32F103C.menu.cpu_speed.speed_72mhz.build.f_cpu=72000000L #-- Optimizations -genericGD32F103C.menu.opt.o2std=Faster -genericGD32F103C.menu.opt.o2std.build.flags.optimize=-O2 -genericGD32F103C.menu.opt.o2std.build.flags.ldspecs= -genericGD32F103C.menu.opt.o2lto=Faster with LTO -genericGD32F103C.menu.opt.o2lto.build.flags.optimize=-O2 -flto -genericGD32F103C.menu.opt.o2lto.build.flags.ldspecs=-flto -genericGD32F103C.menu.opt.o1std=Fast -genericGD32F103C.menu.opt.o1std.build.flags.optimize=-O1 -genericGD32F103C.menu.opt.o1std.build.flags.ldspecs= -genericGD32F103C.menu.opt.o1lto=Fast with LTO -genericGD32F103C.menu.opt.o1lto.build.flags.optimize=-O1 -flto -genericGD32F103C.menu.opt.o1lto.build.flags.ldspecs=-flto -genericGD32F103C.menu.opt.o3std=Fastest -genericGD32F103C.menu.opt.o3std.build.flags.optimize=-O3 -genericGD32F103C.menu.opt.o3std.build.flags.ldspecs= -genericGD32F103C.menu.opt.o3lto=Fastest with LTO -genericGD32F103C.menu.opt.o3lto.build.flags.optimize=-O3 -flto -genericGD32F103C.menu.opt.o3lto.build.flags.ldspecs=-flto -genericGD32F103C.menu.opt.ogstd=Debug -genericGD32F103C.menu.opt.ogstd.build.flags.optimize=-Og -genericGD32F103C.menu.opt.ogstd.build.flags.ldspecs= -genericGD32F103C.menu.opt.oglto=Debug with LTO -genericGD32F103C.menu.opt.oglto.build.flags.optimize=-Og -flto -genericGD32F103C.menu.opt.oglto.build.flags.ldspecs=-flto -genericGD32F103C.menu.opt.osstd=Smallest Code +genericGD32F103C.menu.opt.osstd=Smallest (default) genericGD32F103C.menu.opt.osstd.build.flags.optimize=-Os genericGD32F103C.menu.opt.osstd.build.flags.ldspecs= genericGD32F103C.menu.opt.oslto=Smallest Code with LTO genericGD32F103C.menu.opt.oslto.build.flags.optimize=-Os -flto genericGD32F103C.menu.opt.oslto.build.flags.ldspecs=-flto +genericGD32F103C.menu.opt.o1std=Fast (-O1) +genericGD32F103C.menu.opt.o1std.build.flags.optimize=-O1 +genericGD32F103C.menu.opt.o1std.build.flags.ldspecs= +genericGD32F103C.menu.opt.o1lto=Fast (-O1) with LTO +genericGD32F103C.menu.opt.o1lto.build.flags.optimize=-O1 -flto +genericGD32F103C.menu.opt.o1lto.build.flags.ldspecs=-flto +genericGD32F103C.menu.opt.o2std=Faster (-O2) +genericGD32F103C.menu.opt.o2std.build.flags.optimize=-O2 +genericGD32F103C.menu.opt.o2std.build.flags.ldspecs= +genericGD32F103C.menu.opt.o2lto=Faster (-O2) with LTO +genericGD32F103C.menu.opt.o2lto.build.flags.optimize=-O2 -flto +genericGD32F103C.menu.opt.o2lto.build.flags.ldspecs=-flto +genericGD32F103C.menu.opt.o3std=Fastest (-03) +genericGD32F103C.menu.opt.o3std.build.flags.optimize=-O3 +genericGD32F103C.menu.opt.o3std.build.flags.ldspecs= +genericGD32F103C.menu.opt.o3lto=Fastest (-0) with LTO +genericGD32F103C.menu.opt.o3lto.build.flags.optimize=-O3 -flto +genericGD32F103C.menu.opt.ogstd=Debug (-g) +genericGD32F103C.menu.opt.o3lto.build.flags.ldspecs=-flto +genericGD32F103C.menu.opt.ogstd.build.flags.optimize=-Og +genericGD32F103C.menu.opt.ogstd.build.flags.ldspecs= +genericGD32F103C.menu.opt.oglto=Debug with LTO +genericGD32F103C.menu.opt.oglto.build.flags.optimize=-Og -flto +genericGD32F103C.menu.opt.oglto.build.flags.ldspecs=-flto ########################### STM32VLD to FLASH ########################### @@ -989,35 +989,35 @@ STM32VLD.menu.upload_method.STLinkMethod.upload.tool=stlink_upload STM32VLD.menu.upload_method.STLinkMethod.build.upload_flags=-DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG #-- Optimizations -STM32VLD.menu.opt.o2std=Faster -STM32VLD.menu.opt.o2std.build.flags.optimize=-O2 -STM32VLD.menu.opt.o2std.build.flags.ldspecs= -STM32VLD.menu.opt.o2lto=Faster with LTO -STM32VLD.menu.opt.o2lto.build.flags.optimize=-O2 -flto -STM32VLD.menu.opt.o2lto.build.flags.ldspecs=-flto -STM32VLD.menu.opt.o1std=Fast -STM32VLD.menu.opt.o1std.build.flags.optimize=-O1 -STM32VLD.menu.opt.o1std.build.flags.ldspecs= -STM32VLD.menu.opt.o1lto=Fast with LTO -STM32VLD.menu.opt.o1lto.build.flags.optimize=-O1 -flto -STM32VLD.menu.opt.o1lto.build.flags.ldspecs=-flto -STM32VLD.menu.opt.o3std=Fastest -STM32VLD.menu.opt.o3std.build.flags.optimize=-O3 -STM32VLD.menu.opt.o3std.build.flags.ldspecs= -STM32VLD.menu.opt.o3lto=Fastest with LTO -STM32VLD.menu.opt.o3lto.build.flags.optimize=-O3 -flto -STM32VLD.menu.opt.o3lto.build.flags.ldspecs=-flto -STM32VLD.menu.opt.ogstd=Debug -STM32VLD.menu.opt.ogstd.build.flags.optimize=-Og -STM32VLD.menu.opt.ogstd.build.flags.ldspecs= -STM32VLD.menu.opt.oglto=Debug with LTO -STM32VLD.menu.opt.oglto.build.flags.optimize=-Og -flto -STM32VLD.menu.opt.oglto.build.flags.ldspecs=-flto -STM32VLD.menu.opt.osstd=Smallest Code +STM32VLD.menu.opt.osstd=Smallest (default) STM32VLD.menu.opt.osstd.build.flags.optimize=-Os STM32VLD.menu.opt.osstd.build.flags.ldspecs= STM32VLD.menu.opt.oslto=Smallest Code with LTO STM32VLD.menu.opt.oslto.build.flags.optimize=-Os -flto STM32VLD.menu.opt.oslto.build.flags.ldspecs=-flto +STM32VLD.menu.opt.o1std=Fast (-O1) +STM32VLD.menu.opt.o1std.build.flags.optimize=-O1 +STM32VLD.menu.opt.o1std.build.flags.ldspecs= +STM32VLD.menu.opt.o1lto=Fast (-O1) with LTO +STM32VLD.menu.opt.o1lto.build.flags.optimize=-O1 -flto +STM32VLD.menu.opt.o1lto.build.flags.ldspecs=-flto +STM32VLD.menu.opt.o2std=Faster (-O2) +STM32VLD.menu.opt.o2std.build.flags.optimize=-O2 +STM32VLD.menu.opt.o2std.build.flags.ldspecs= +STM32VLD.menu.opt.o2lto=Faster (-O2) with LTO +STM32VLD.menu.opt.o2lto.build.flags.optimize=-O2 -flto +STM32VLD.menu.opt.o2lto.build.flags.ldspecs=-flto +STM32VLD.menu.opt.o3std=Fastest (-03) +STM32VLD.menu.opt.o3std.build.flags.optimize=-O3 +STM32VLD.menu.opt.o3std.build.flags.ldspecs= +STM32VLD.menu.opt.o3lto=Fastest (-0) with LTO +STM32VLD.menu.opt.o3lto.build.flags.optimize=-O3 -flto +STM32VLD.menu.opt.ogstd=Debug (-g) +STM32VLD.menu.opt.o3lto.build.flags.ldspecs=-flto +STM32VLD.menu.opt.ogstd.build.flags.optimize=-Og +STM32VLD.menu.opt.ogstd.build.flags.ldspecs= +STM32VLD.menu.opt.oglto=Debug with LTO +STM32VLD.menu.opt.oglto.build.flags.optimize=-Og -flto +STM32VLD.menu.opt.oglto.build.flags.ldspecs=-flto ################################################################################ \ No newline at end of file diff --git a/STM32F3/boards.txt b/STM32F3/boards.txt index d3a3735..6c011bc 100644 --- a/STM32F3/boards.txt +++ b/STM32F3/boards.txt @@ -1,7 +1,5 @@ # -menu.opt=Optimize - ############################################################## discovery_f3.name=STM32F3Discovery @@ -30,37 +28,5 @@ discovery_f3.build.error_led_port=GPIOE discovery_f3.build.error_led_pin=8 discovery_f3.build.board=STM32F3Discovery -#-- Optimizations -discovery_f3.menu.opt.o2std=Faster -discovery_f3.menu.opt.o2std.build.flags.optimize=-O2 -discovery_f3.menu.opt.o2std.build.flags.ldspecs= -discovery_f3.menu.opt.o2lto=Faster with LTO -discovery_f3.menu.opt.o2lto.build.flags.optimize=-O2 -flto -discovery_f3.menu.opt.o2lto.build.flags.ldspecs=-flto -discovery_f3.menu.opt.o1std=Fast -discovery_f3.menu.opt.o1std.build.flags.optimize=-O1 -discovery_f3.menu.opt.o1std.build.flags.ldspecs= -discovery_f3.menu.opt.o1lto=Fast with LTO -discovery_f3.menu.opt.o1lto.build.flags.optimize=-O1 -flto -discovery_f3.menu.opt.o1lto.build.flags.ldspecs=-flto -discovery_f3.menu.opt.o3std=Fastest -discovery_f3.menu.opt.o3std.build.flags.optimize=-O3 -discovery_f3.menu.opt.o3std.build.flags.ldspecs= -discovery_f3.menu.opt.o3lto=Fastest with LTO -discovery_f3.menu.opt.o3lto.build.flags.optimize=-O3 -flto -discovery_f3.menu.opt.o3lto.build.flags.ldspecs=-flto -discovery_f3.menu.opt.ogstd=Debug -discovery_f3.menu.opt.ogstd.build.flags.optimize=-Og -discovery_f3.menu.opt.ogstd.build.flags.ldspecs= -discovery_f3.menu.opt.oglto=Debug with LTO -discovery_f3.menu.opt.oglto.build.flags.optimize=-Og -flto -discovery_f3.menu.opt.oglto.build.flags.ldspecs=-flto -discovery_f3.menu.opt.osstd=Smallest Code -discovery_f3.menu.opt.osstd.build.flags.optimize=-Os -discovery_f3.menu.opt.osstd.build.flags.ldspecs= -discovery_f3.menu.opt.oslto=Smallest Code with LTO -discovery_f3.menu.opt.oslto.build.flags.optimize=-Os -flto -discovery_f3.menu.opt.oslto.build.flags.ldspecs=-flto - ############################################################## diff --git a/STM32F4/boards.txt b/STM32F4/boards.txt index 429ba4b..baf6f6e 100644 --- a/STM32F4/boards.txt +++ b/STM32F4/boards.txt @@ -1,7 +1,6 @@ # menu.usb_cfg=USB configuration -menu.opt=Optimize ############################################################## discovery_f407.name=STM32 Discovery F407 @@ -37,39 +36,6 @@ discovery_f407.menu.usb_cfg.usb_serial=USB serial (CDC) discovery_f407.menu.usb_cfg.usb_serial.build.cpu_flags=-DSERIAL_USB discovery_f407.menu.usb_cfg.usb_msc=USB Mass Storage (MSC) discovery_f407.menu.usb_cfg.usb_msc.build.cpu_flags=-DUSB_MSC - -#-- Optimizations -discovery_f407.menu.opt.o2std=Faster -discovery_f407.menu.opt.o2std.build.flags.optimize=-O2 -discovery_f407.menu.opt.o2std.build.flags.ldspecs= -discovery_f407.menu.opt.o2lto=Faster with LTO -discovery_f407.menu.opt.o2lto.build.flags.optimize=-O2 -flto -discovery_f407.menu.opt.o2lto.build.flags.ldspecs=-flto -discovery_f407.menu.opt.o1std=Fast -discovery_f407.menu.opt.o1std.build.flags.optimize=-O1 -discovery_f407.menu.opt.o1std.build.flags.ldspecs= -discovery_f407.menu.opt.o1lto=Fast with LTO -discovery_f407.menu.opt.o1lto.build.flags.optimize=-O1 -flto -discovery_f407.menu.opt.o1lto.build.flags.ldspecs=-flto -discovery_f407.menu.opt.o3std=Fastest -discovery_f407.menu.opt.o3std.build.flags.optimize=-O3 -discovery_f407.menu.opt.o3std.build.flags.ldspecs= -discovery_f407.menu.opt.o3lto=Fastest with LTO -discovery_f407.menu.opt.o3lto.build.flags.optimize=-O3 -flto -discovery_f407.menu.opt.o3lto.build.flags.ldspecs=-flto -discovery_f407.menu.opt.ogstd=Debug -discovery_f407.menu.opt.ogstd.build.flags.optimize=-Og -discovery_f407.menu.opt.ogstd.build.flags.ldspecs= -discovery_f407.menu.opt.oglto=Debug with LTO -discovery_f407.menu.opt.oglto.build.flags.optimize=-Og -flto -discovery_f407.menu.opt.oglto.build.flags.ldspecs=-flto -discovery_f407.menu.opt.osstd=Smallest Code -discovery_f407.menu.opt.osstd.build.flags.optimize=-Os -discovery_f407.menu.opt.osstd.build.flags.ldspecs= -discovery_f407.menu.opt.oslto=Smallest Code with LTO -discovery_f407.menu.opt.oslto.build.flags.optimize=-Os -flto -discovery_f407.menu.opt.oslto.build.flags.ldspecs=-flto - ############################################################## generic_f407v.name=Generic STM32F407V series @@ -106,38 +72,6 @@ generic_f407v.menu.usb_cfg.usb_serial.build.cpu_flags=-DSERIAL_USB generic_f407v.menu.usb_cfg.usb_msc=USB Mass Storage (MSC) generic_f407v.menu.usb_cfg.usb_msc.build.cpu_flags=-DUSB_MSC -#-- Optimizations -generic_f407v.menu.opt.o2std=Faster -generic_f407v.menu.opt.o2std.build.flags.optimize=-O2 -generic_f407v.menu.opt.o2std.build.flags.ldspecs= -generic_f407v.menu.opt.o2lto=Faster with LTO -generic_f407v.menu.opt.o2lto.build.flags.optimize=-O2 -flto -generic_f407v.menu.opt.o2lto.build.flags.ldspecs=-flto -generic_f407v.menu.opt.o1std=Fast -generic_f407v.menu.opt.o1std.build.flags.optimize=-O1 -generic_f407v.menu.opt.o1std.build.flags.ldspecs= -generic_f407v.menu.opt.o1lto=Fast with LTO -generic_f407v.menu.opt.o1lto.build.flags.optimize=-O1 -flto -generic_f407v.menu.opt.o1lto.build.flags.ldspecs=-flto -generic_f407v.menu.opt.o3std=Fastest -generic_f407v.menu.opt.o3std.build.flags.optimize=-O3 -generic_f407v.menu.opt.o3std.build.flags.ldspecs= -generic_f407v.menu.opt.o3lto=Fastest with LTO -generic_f407v.menu.opt.o3lto.build.flags.optimize=-O3 -flto -generic_f407v.menu.opt.o3lto.build.flags.ldspecs=-flto -generic_f407v.menu.opt.ogstd=Debug -generic_f407v.menu.opt.ogstd.build.flags.optimize=-Og -generic_f407v.menu.opt.ogstd.build.flags.ldspecs= -generic_f407v.menu.opt.oglto=Debug with LTO -generic_f407v.menu.opt.oglto.build.flags.optimize=-Og -flto -generic_f407v.menu.opt.oglto.build.flags.ldspecs=-flto -generic_f407v.menu.opt.osstd=Smallest Code -generic_f407v.menu.opt.osstd.build.flags.optimize=-Os -generic_f407v.menu.opt.osstd.build.flags.ldspecs= -generic_f407v.menu.opt.oslto=Smallest Code with LTO -generic_f407v.menu.opt.oslto.build.flags.optimize=-Os -flto -generic_f407v.menu.opt.oslto.build.flags.ldspecs=-flto - ############################################################## stm32f4stamp.name=STM32F4Stamp F405 @@ -173,39 +107,6 @@ stm32f4stamp.menu.usb_cfg.usb_serial=USB serial (CDC) stm32f4stamp.menu.usb_cfg.usb_serial.build.cpu_flags=-DSERIAL_USB stm32f4stamp.menu.usb_cfg.usb_msc=USB Mass Storage (MSC) stm32f4stamp.menu.usb_cfg.usb_msc.build.cpu_flags=-DUSB_MSC - -#-- Optimizations -stm32f4stamp.menu.opt.o2std=Faster -stm32f4stamp.menu.opt.o2std.build.flags.optimize=-O2 -stm32f4stamp.menu.opt.o2std.build.flags.ldspecs= -stm32f4stamp.menu.opt.o2lto=Faster with LTO -stm32f4stamp.menu.opt.o2lto.build.flags.optimize=-O2 -flto -stm32f4stamp.menu.opt.o2lto.build.flags.ldspecs=-flto -stm32f4stamp.menu.opt.o1std=Fast -stm32f4stamp.menu.opt.o1std.build.flags.optimize=-O1 -stm32f4stamp.menu.opt.o1std.build.flags.ldspecs= -stm32f4stamp.menu.opt.o1lto=Fast with LTO -stm32f4stamp.menu.opt.o1lto.build.flags.optimize=-O1 -flto -stm32f4stamp.menu.opt.o1lto.build.flags.ldspecs=-flto -stm32f4stamp.menu.opt.o3std=Fastest -stm32f4stamp.menu.opt.o3std.build.flags.optimize=-O3 -stm32f4stamp.menu.opt.o3std.build.flags.ldspecs= -stm32f4stamp.menu.opt.o3lto=Fastest with LTO -stm32f4stamp.menu.opt.o3lto.build.flags.optimize=-O3 -flto -stm32f4stamp.menu.opt.o3lto.build.flags.ldspecs=-flto -stm32f4stamp.menu.opt.ogstd=Debug -stm32f4stamp.menu.opt.ogstd.build.flags.optimize=-Og -stm32f4stamp.menu.opt.ogstd.build.flags.ldspecs= -stm32f4stamp.menu.opt.oglto=Debug with LTO -stm32f4stamp.menu.opt.oglto.build.flags.optimize=-Og -flto -stm32f4stamp.menu.opt.oglto.build.flags.ldspecs=-flto -stm32f4stamp.menu.opt.osstd=Smallest Code -stm32f4stamp.menu.opt.osstd.build.flags.optimize=-Os -stm32f4stamp.menu.opt.osstd.build.flags.ldspecs= -stm32f4stamp.menu.opt.oslto=Smallest Code with LTO -stm32f4stamp.menu.opt.oslto.build.flags.optimize=-Os -flto -stm32f4stamp.menu.opt.oslto.build.flags.ldspecs=-flto - ############################################################## netduino2plus.name=Netduino2 F405 @@ -241,37 +142,5 @@ netduino2plus.menu.usb_cfg.usb_serial=USB serial (CDC) netduino2plus.menu.usb_cfg.usb_serial.build.cpu_flags=-DSERIAL_USB netduino2plus.menu.usb_cfg.usb_msc=USB Mass Storage (MSC) netduino2plus.menu.usb_cfg.usb_msc.build.cpu_flags=-DUSB_MSC - -#-- Optimizations -netduino2plus.menu.opt.o2std=Faster -netduino2plus.menu.opt.o2std.build.flags.optimize=-O2 -netduino2plus.menu.opt.o2std.build.flags.ldspecs= -netduino2plus.menu.opt.o2lto=Faster with LTO -netduino2plus.menu.opt.o2lto.build.flags.optimize=-O2 -flto -netduino2plus.menu.opt.o2lto.build.flags.ldspecs=-flto -netduino2plus.menu.opt.o1std=Fast -netduino2plus.menu.opt.o1std.build.flags.optimize=-O1 -netduino2plus.menu.opt.o1std.build.flags.ldspecs= -netduino2plus.menu.opt.o1lto=Fast with LTO -netduino2plus.menu.opt.o1lto.build.flags.optimize=-O1 -flto -netduino2plus.menu.opt.o1lto.build.flags.ldspecs=-flto -netduino2plus.menu.opt.o3std=Fastest -netduino2plus.menu.opt.o3std.build.flags.optimize=-O3 -netduino2plus.menu.opt.o3std.build.flags.ldspecs= -netduino2plus.menu.opt.o3lto=Fastest with LTO -netduino2plus.menu.opt.o3lto.build.flags.optimize=-O3 -flto -netduino2plus.menu.opt.o3lto.build.flags.ldspecs=-flto -netduino2plus.menu.opt.ogstd=Debug -netduino2plus.menu.opt.ogstd.build.flags.optimize=-Og -netduino2plus.menu.opt.ogstd.build.flags.ldspecs= -netduino2plus.menu.opt.oglto=Debug with LTO -netduino2plus.menu.opt.oglto.build.flags.optimize=-Og -flto -netduino2plus.menu.opt.oglto.build.flags.ldspecs=-flto -netduino2plus.menu.opt.osstd=Smallest Code -netduino2plus.menu.opt.osstd.build.flags.optimize=-Os -netduino2plus.menu.opt.osstd.build.flags.ldspecs= -netduino2plus.menu.opt.oslto=Smallest Code with LTO -netduino2plus.menu.opt.oslto.build.flags.optimize=-Os -flto -netduino2plus.menu.opt.oslto.build.flags.ldspecs=-flto - ############################################################## + From a683dfccca19bbe84322c7b56152961e0f59cb0c Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Sun, 30 Jul 2017 16:16:24 +1000 Subject: [PATCH 123/351] revert changes to STM32F3/platform.txt and STM32F4/platform.txt as they should not have been changed in the previous commit --- STM32F3/platform.txt | 8 ++++---- STM32F4/platform.txt | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/STM32F3/platform.txt b/STM32F3/platform.txt index 94f787c..3218f85 100644 --- a/STM32F3/platform.txt +++ b/STM32F3/platform.txt @@ -12,20 +12,20 @@ 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 {build.flags.optimize} -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 -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={build.flags.optimize} -Wl,--gc-sections {build.flags.ldspecs} +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 {build.flags.optimize} -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 -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 compiler.objcopy.eep.flags=-O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 compiler.elf2hex.flags=-O binary compiler.elf2hex.cmd=arm-none-eabi-objcopy -compiler.ldflags={build.flags.ldspecs} +compiler.ldflags= compiler.size.cmd=arm-none-eabi-size compiler.define=-DARDUINO= diff --git a/STM32F4/platform.txt b/STM32F4/platform.txt index 92dc1ea..b64fe3e 100755 --- a/STM32F4/platform.txt +++ b/STM32F4/platform.txt @@ -10,20 +10,20 @@ 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 {build.flags.optimize} -Wall -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.flags=-c -g -Os -Wall -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={build.flags.optimize} -Wl,--gc-sections {build.flags.ldspecs} +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 {build.flags.optimize} -Wall -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.cpp.flags=-c -g -Os -Wall -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 compiler.objcopy.eep.flags=-O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 compiler.elf2hex.flags=-O binary compiler.elf2hex.cmd=arm-none-eabi-objcopy -compiler.ldflags={build.flags.ldspecs} +compiler.ldflags= compiler.size.cmd=arm-none-eabi-size compiler.define=-DARDUINO= From 86d823a3b5f80121e3f5b51f653b7bf83de2a668 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Sun, 30 Jul 2017 16:21:26 +1000 Subject: [PATCH 124/351] Fixed typo in optimisation menu --- STM32F1/boards.txt | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/STM32F1/boards.txt b/STM32F1/boards.txt index fe18609..3ed5158 100644 --- a/STM32F1/boards.txt +++ b/STM32F1/boards.txt @@ -66,7 +66,7 @@ mapleMini.menu.opt.o2lto.build.flags.ldspecs=-flto mapleMini.menu.opt.o3std=Fastest (-03) mapleMini.menu.opt.o3std.build.flags.optimize=-O3 mapleMini.menu.opt.o3std.build.flags.ldspecs= -mapleMini.menu.opt.o3lto=Fastest (-0) with LTO +mapleMini.menu.opt.o3lto=Fastest (-O3) with LTO mapleMini.menu.opt.o3lto.build.flags.optimize=-O3 -flto mapleMini.menu.opt.o3lto.build.flags.ldspecs=-flto mapleMini.menu.opt.ogstd=Debug (-g) @@ -121,7 +121,7 @@ maple.menu.opt.o2lto.build.flags.ldspecs=-flto maple.menu.opt.o3std=Fastest (-03) maple.menu.opt.o3std.build.flags.optimize=-O3 maple.menu.opt.o3std.build.flags.ldspecs= -maple.menu.opt.o3lto=Fastest (-0) with LTO +maple.menu.opt.o3lto=Fastest (-O3) with LTO maple.menu.opt.o3lto.build.flags.optimize=-O3 -flto maple.menu.opt.o3lto.build.flags.ldspecs=-flto maple.menu.opt.ogstd=Debug (-g) @@ -176,7 +176,7 @@ mapleRET6.menu.opt.o2lto.build.flags.ldspecs=-flto mapleRET6.menu.opt.o3std=Fastest (-03) mapleRET6.menu.opt.o3std.build.flags.optimize=-O3 mapleRET6.menu.opt.o3std.build.flags.ldspecs= -mapleRET6.menu.opt.o3lto=Fastest (-0) with LTO +mapleRET6.menu.opt.o3lto=Fastest (-O3) with LTO mapleRET6.menu.opt.o3lto.build.flags.optimize=-O3 -flto mapleRET6.menu.opt.ogstd=Debug (-g) mapleRET6.menu.opt.o3lto.build.flags.ldspecs=-flto @@ -239,7 +239,7 @@ microduino32_flash.menu.opt.o2lto.build.flags.ldspecs=-flto microduino32_flash.menu.opt.o3std=Fastest (-03) microduino32_flash.menu.opt.o3std.build.flags.optimize=-O3 microduino32_flash.menu.opt.o3std.build.flags.ldspecs= -microduino32_flash.menu.opt.o3lto=Fastest (-0) with LTO +microduino32_flash.menu.opt.o3lto=Fastest (-O3) with LTO microduino32_flash.menu.opt.o3lto.build.flags.optimize=-O3 -flto microduino32_flash.menu.opt.ogstd=Debug (-g) microduino32_flash.menu.opt.o3lto.build.flags.ldspecs=-flto @@ -309,7 +309,7 @@ nucleo_f103rb.menu.opt.o2lto.build.flags.ldspecs=-flto nucleo_f103rb.menu.opt.o3std=Fastest (-03) nucleo_f103rb.menu.opt.o3std.build.flags.optimize=-O3 nucleo_f103rb.menu.opt.o3std.build.flags.ldspecs= -nucleo_f103rb.menu.opt.o3lto=Fastest (-0) with LTO +nucleo_f103rb.menu.opt.o3lto=Fastest (-O3) with LTO nucleo_f103rb.menu.opt.o3lto.build.flags.optimize=-O3 -flto nucleo_f103rb.menu.opt.ogstd=Debug (-g) nucleo_f103rb.menu.opt.o3lto.build.flags.ldspecs=-flto @@ -406,7 +406,7 @@ genericSTM32F103C.menu.opt.o2lto.build.flags.ldspecs=-flto genericSTM32F103C.menu.opt.o3std=Fastest (-03) genericSTM32F103C.menu.opt.o3std.build.flags.optimize=-O3 genericSTM32F103C.menu.opt.o3std.build.flags.ldspecs= -genericSTM32F103C.menu.opt.o3lto=Fastest (-0) with LTO +genericSTM32F103C.menu.opt.o3lto=Fastest (-O3) with LTO genericSTM32F103C.menu.opt.o3lto.build.flags.optimize=-O3 -flto genericSTM32F103C.menu.opt.ogstd=Debug (-g) genericSTM32F103C.menu.opt.o3lto.build.flags.ldspecs=-flto @@ -507,7 +507,7 @@ genericSTM32F103R.menu.opt.o2lto.build.flags.ldspecs=-flto genericSTM32F103R.menu.opt.o3std=Fastest (-03) genericSTM32F103R.menu.opt.o3std.build.flags.optimize=-O3 genericSTM32F103R.menu.opt.o3std.build.flags.ldspecs= -genericSTM32F103R.menu.opt.o3lto=Fastest (-0) with LTO +genericSTM32F103R.menu.opt.o3lto=Fastest (-O3) with LTO genericSTM32F103R.menu.opt.o3lto.build.flags.optimize=-O3 -flto genericSTM32F103R.menu.opt.ogstd=Debug (-g) genericSTM32F103R.menu.opt.o3lto.build.flags.ldspecs=-flto @@ -592,7 +592,7 @@ genericSTM32F103T.menu.opt.o2lto.build.flags.ldspecs=-flto genericSTM32F103T.menu.opt.o3std=Fastest (-03) genericSTM32F103T.menu.opt.o3std.build.flags.optimize=-O3 genericSTM32F103T.menu.opt.o3std.build.flags.ldspecs= -genericSTM32F103T.menu.opt.o3lto=Fastest (-0) with LTO +genericSTM32F103T.menu.opt.o3lto=Fastest (-O3) with LTO genericSTM32F103T.menu.opt.o3lto.build.flags.optimize=-O3 -flto genericSTM32F103T.menu.opt.ogstd=Debug (-g) genericSTM32F103T.menu.opt.o3lto.build.flags.ldspecs=-flto @@ -684,7 +684,7 @@ genericSTM32F103V.menu.opt.o2lto.build.flags.ldspecs=-flto genericSTM32F103V.menu.opt.o3std=Fastest (-03) genericSTM32F103V.menu.opt.o3std.build.flags.optimize=-O3 genericSTM32F103V.menu.opt.o3std.build.flags.ldspecs= -genericSTM32F103V.menu.opt.o3lto=Fastest (-0) with LTO +genericSTM32F103V.menu.opt.o3lto=Fastest (-O3) with LTO genericSTM32F103V.menu.opt.o3lto.build.flags.optimize=-O3 -flto genericSTM32F103V.menu.opt.ogstd=Debug (-g) genericSTM32F103V.menu.opt.o3lto.build.flags.ldspecs=-flto @@ -773,7 +773,7 @@ genericSTM32F103Z.menu.opt.o2lto.build.flags.ldspecs=-flto genericSTM32F103Z.menu.opt.o3std=Fastest (-03) genericSTM32F103Z.menu.opt.o3std.build.flags.optimize=-O3 genericSTM32F103Z.menu.opt.o3std.build.flags.ldspecs= -genericSTM32F103Z.menu.opt.o3lto=Fastest (-0) with LTO +genericSTM32F103Z.menu.opt.o3lto=Fastest (-O3) with LTO genericSTM32F103Z.menu.opt.o3lto.build.flags.optimize=-O3 -flto genericSTM32F103Z.menu.opt.ogstd=Debug (-g) genericSTM32F103Z.menu.opt.o3lto.build.flags.ldspecs=-flto @@ -856,7 +856,7 @@ hytiny-stm32f103t.menu.opt.o2lto.build.flags.ldspecs=-flto hytiny-stm32f103t.menu.opt.o3std=Fastest (-03) hytiny-stm32f103t.menu.opt.o3std.build.flags.optimize=-O3 hytiny-stm32f103t.menu.opt.o3std.build.flags.ldspecs= -hytiny-stm32f103t.menu.opt.o3lto=Fastest (-0) with LTO +hytiny-stm32f103t.menu.opt.o3lto=Fastest (-O3) with LTO hytiny-stm32f103t.menu.opt.o3lto.build.flags.optimize=-O3 -flto hytiny-stm32f103t.menu.opt.ogstd=Debug (-g) hytiny-stm32f103t.menu.opt.o3lto.build.flags.ldspecs=-flto @@ -950,7 +950,7 @@ genericGD32F103C.menu.opt.o2lto.build.flags.ldspecs=-flto genericGD32F103C.menu.opt.o3std=Fastest (-03) genericGD32F103C.menu.opt.o3std.build.flags.optimize=-O3 genericGD32F103C.menu.opt.o3std.build.flags.ldspecs= -genericGD32F103C.menu.opt.o3lto=Fastest (-0) with LTO +genericGD32F103C.menu.opt.o3lto=Fastest (-O3) with LTO genericGD32F103C.menu.opt.o3lto.build.flags.optimize=-O3 -flto genericGD32F103C.menu.opt.ogstd=Debug (-g) genericGD32F103C.menu.opt.o3lto.build.flags.ldspecs=-flto @@ -1010,7 +1010,7 @@ STM32VLD.menu.opt.o2lto.build.flags.ldspecs=-flto STM32VLD.menu.opt.o3std=Fastest (-03) STM32VLD.menu.opt.o3std.build.flags.optimize=-O3 STM32VLD.menu.opt.o3std.build.flags.ldspecs= -STM32VLD.menu.opt.o3lto=Fastest (-0) with LTO +STM32VLD.menu.opt.o3lto=Fastest (-O3) with LTO STM32VLD.menu.opt.o3lto.build.flags.optimize=-O3 -flto STM32VLD.menu.opt.ogstd=Debug (-g) STM32VLD.menu.opt.o3lto.build.flags.ldspecs=-flto From 7aae010eae645972e8bab22ff2a5c69a4a205407 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Sun, 30 Jul 2017 17:05:57 +1000 Subject: [PATCH 125/351] Fixed yet another of my typos in the optimisation menu --- STM32F1/boards.txt | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/STM32F1/boards.txt b/STM32F1/boards.txt index 3ed5158..c80bda9 100644 --- a/STM32F1/boards.txt +++ b/STM32F1/boards.txt @@ -63,7 +63,7 @@ mapleMini.menu.opt.o2std.build.flags.ldspecs= mapleMini.menu.opt.o2lto=Faster (-O2) with LTO mapleMini.menu.opt.o2lto.build.flags.optimize=-O2 -flto mapleMini.menu.opt.o2lto.build.flags.ldspecs=-flto -mapleMini.menu.opt.o3std=Fastest (-03) +mapleMini.menu.opt.o3std=Fastest (-O3) mapleMini.menu.opt.o3std.build.flags.optimize=-O3 mapleMini.menu.opt.o3std.build.flags.ldspecs= mapleMini.menu.opt.o3lto=Fastest (-O3) with LTO @@ -118,7 +118,7 @@ maple.menu.opt.o2std.build.flags.ldspecs= maple.menu.opt.o2lto=Faster (-O2) with LTO maple.menu.opt.o2lto.build.flags.optimize=-O2 -flto maple.menu.opt.o2lto.build.flags.ldspecs=-flto -maple.menu.opt.o3std=Fastest (-03) +maple.menu.opt.o3std=Fastest (-O3) maple.menu.opt.o3std.build.flags.optimize=-O3 maple.menu.opt.o3std.build.flags.ldspecs= maple.menu.opt.o3lto=Fastest (-O3) with LTO @@ -173,7 +173,7 @@ mapleRET6.menu.opt.o2std.build.flags.ldspecs= mapleRET6.menu.opt.o2lto=Faster (-O2) with LTO mapleRET6.menu.opt.o2lto.build.flags.optimize=-O2 -flto mapleRET6.menu.opt.o2lto.build.flags.ldspecs=-flto -mapleRET6.menu.opt.o3std=Fastest (-03) +mapleRET6.menu.opt.o3std=Fastest (-O3) mapleRET6.menu.opt.o3std.build.flags.optimize=-O3 mapleRET6.menu.opt.o3std.build.flags.ldspecs= mapleRET6.menu.opt.o3lto=Fastest (-O3) with LTO @@ -236,7 +236,7 @@ microduino32_flash.menu.opt.o2std.build.flags.ldspecs= microduino32_flash.menu.opt.o2lto=Faster (-O2) with LTO microduino32_flash.menu.opt.o2lto.build.flags.optimize=-O2 -flto microduino32_flash.menu.opt.o2lto.build.flags.ldspecs=-flto -microduino32_flash.menu.opt.o3std=Fastest (-03) +microduino32_flash.menu.opt.o3std=Fastest (-O3) microduino32_flash.menu.opt.o3std.build.flags.optimize=-O3 microduino32_flash.menu.opt.o3std.build.flags.ldspecs= microduino32_flash.menu.opt.o3lto=Fastest (-O3) with LTO @@ -306,7 +306,7 @@ nucleo_f103rb.menu.opt.o2std.build.flags.ldspecs= nucleo_f103rb.menu.opt.o2lto=Faster (-O2) with LTO nucleo_f103rb.menu.opt.o2lto.build.flags.optimize=-O2 -flto nucleo_f103rb.menu.opt.o2lto.build.flags.ldspecs=-flto -nucleo_f103rb.menu.opt.o3std=Fastest (-03) +nucleo_f103rb.menu.opt.o3std=Fastest (-O3) nucleo_f103rb.menu.opt.o3std.build.flags.optimize=-O3 nucleo_f103rb.menu.opt.o3std.build.flags.ldspecs= nucleo_f103rb.menu.opt.o3lto=Fastest (-O3) with LTO @@ -403,7 +403,7 @@ genericSTM32F103C.menu.opt.o2std.build.flags.ldspecs= genericSTM32F103C.menu.opt.o2lto=Faster (-O2) with LTO genericSTM32F103C.menu.opt.o2lto.build.flags.optimize=-O2 -flto genericSTM32F103C.menu.opt.o2lto.build.flags.ldspecs=-flto -genericSTM32F103C.menu.opt.o3std=Fastest (-03) +genericSTM32F103C.menu.opt.o3std=Fastest (-O3) genericSTM32F103C.menu.opt.o3std.build.flags.optimize=-O3 genericSTM32F103C.menu.opt.o3std.build.flags.ldspecs= genericSTM32F103C.menu.opt.o3lto=Fastest (-O3) with LTO @@ -504,7 +504,7 @@ genericSTM32F103R.menu.opt.o2std.build.flags.ldspecs= genericSTM32F103R.menu.opt.o2lto=Faster (-O2) with LTO genericSTM32F103R.menu.opt.o2lto.build.flags.optimize=-O2 -flto genericSTM32F103R.menu.opt.o2lto.build.flags.ldspecs=-flto -genericSTM32F103R.menu.opt.o3std=Fastest (-03) +genericSTM32F103R.menu.opt.o3std=Fastest (-O3) genericSTM32F103R.menu.opt.o3std.build.flags.optimize=-O3 genericSTM32F103R.menu.opt.o3std.build.flags.ldspecs= genericSTM32F103R.menu.opt.o3lto=Fastest (-O3) with LTO @@ -589,7 +589,7 @@ genericSTM32F103T.menu.opt.o2std.build.flags.ldspecs= genericSTM32F103T.menu.opt.o2lto=Faster (-O2) with LTO genericSTM32F103T.menu.opt.o2lto.build.flags.optimize=-O2 -flto genericSTM32F103T.menu.opt.o2lto.build.flags.ldspecs=-flto -genericSTM32F103T.menu.opt.o3std=Fastest (-03) +genericSTM32F103T.menu.opt.o3std=Fastest (-O3) genericSTM32F103T.menu.opt.o3std.build.flags.optimize=-O3 genericSTM32F103T.menu.opt.o3std.build.flags.ldspecs= genericSTM32F103T.menu.opt.o3lto=Fastest (-O3) with LTO @@ -681,7 +681,7 @@ genericSTM32F103V.menu.opt.o2std.build.flags.ldspecs= genericSTM32F103V.menu.opt.o2lto=Faster (-O2) with LTO genericSTM32F103V.menu.opt.o2lto.build.flags.optimize=-O2 -flto genericSTM32F103V.menu.opt.o2lto.build.flags.ldspecs=-flto -genericSTM32F103V.menu.opt.o3std=Fastest (-03) +genericSTM32F103V.menu.opt.o3std=Fastest (-O3) genericSTM32F103V.menu.opt.o3std.build.flags.optimize=-O3 genericSTM32F103V.menu.opt.o3std.build.flags.ldspecs= genericSTM32F103V.menu.opt.o3lto=Fastest (-O3) with LTO @@ -770,7 +770,7 @@ genericSTM32F103Z.menu.opt.o2std.build.flags.ldspecs= genericSTM32F103Z.menu.opt.o2lto=Faster (-O2) with LTO genericSTM32F103Z.menu.opt.o2lto.build.flags.optimize=-O2 -flto genericSTM32F103Z.menu.opt.o2lto.build.flags.ldspecs=-flto -genericSTM32F103Z.menu.opt.o3std=Fastest (-03) +genericSTM32F103Z.menu.opt.o3std=Fastest (-O3) genericSTM32F103Z.menu.opt.o3std.build.flags.optimize=-O3 genericSTM32F103Z.menu.opt.o3std.build.flags.ldspecs= genericSTM32F103Z.menu.opt.o3lto=Fastest (-O3) with LTO @@ -853,7 +853,7 @@ hytiny-stm32f103t.menu.opt.o2std.build.flags.ldspecs= hytiny-stm32f103t.menu.opt.o2lto=Faster (-O2) with LTO hytiny-stm32f103t.menu.opt.o2lto.build.flags.optimize=-O2 -flto hytiny-stm32f103t.menu.opt.o2lto.build.flags.ldspecs=-flto -hytiny-stm32f103t.menu.opt.o3std=Fastest (-03) +hytiny-stm32f103t.menu.opt.o3std=Fastest (-O3) hytiny-stm32f103t.menu.opt.o3std.build.flags.optimize=-O3 hytiny-stm32f103t.menu.opt.o3std.build.flags.ldspecs= hytiny-stm32f103t.menu.opt.o3lto=Fastest (-O3) with LTO @@ -947,7 +947,7 @@ genericGD32F103C.menu.opt.o2std.build.flags.ldspecs= genericGD32F103C.menu.opt.o2lto=Faster (-O2) with LTO genericGD32F103C.menu.opt.o2lto.build.flags.optimize=-O2 -flto genericGD32F103C.menu.opt.o2lto.build.flags.ldspecs=-flto -genericGD32F103C.menu.opt.o3std=Fastest (-03) +genericGD32F103C.menu.opt.o3std=Fastest (-O3) genericGD32F103C.menu.opt.o3std.build.flags.optimize=-O3 genericGD32F103C.menu.opt.o3std.build.flags.ldspecs= genericGD32F103C.menu.opt.o3lto=Fastest (-O3) with LTO @@ -1007,7 +1007,7 @@ STM32VLD.menu.opt.o2std.build.flags.ldspecs= STM32VLD.menu.opt.o2lto=Faster (-O2) with LTO STM32VLD.menu.opt.o2lto.build.flags.optimize=-O2 -flto STM32VLD.menu.opt.o2lto.build.flags.ldspecs=-flto -STM32VLD.menu.opt.o3std=Fastest (-03) +STM32VLD.menu.opt.o3std=Fastest (-O3) STM32VLD.menu.opt.o3std.build.flags.optimize=-O3 STM32VLD.menu.opt.o3std.build.flags.ldspecs= STM32VLD.menu.opt.o3lto=Fastest (-O3) with LTO From cb901b4e4f8c8630bf570ffbf30a4ca46cbcb840 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Sun, 30 Jul 2017 17:43:40 +1000 Subject: [PATCH 126/351] Added CPU Speed menu to all boards except Nucleo RB, with additional entry for 128Mhz Turbo - NO USB. Note only tested on the Blue Pill --- STM32F1/boards.txt | 105 ++++++++++++++++++ .../wirish/boards_setup.cpp | 12 +- .../wirish/boards_setup.cpp | 12 +- .../wirish/boards_setup.cpp | 12 +- .../wirish/boards_setup.cpp | 12 +- .../wirish/boards_setup.cpp | 12 +- .../wirish/boards_setup.cpp | 12 +- .../hytiny_stm32f103t/wirish/boards_setup.cpp | 12 +- .../variants/maple/wirish/boards_setup.cpp | 12 +- .../maple_mini/wirish/boards_setup.cpp | 12 +- .../maple_ret6/wirish/boards_setup.cpp | 12 +- .../microduino/wirish/boards_setup.cpp | 12 +- 12 files changed, 182 insertions(+), 55 deletions(-) diff --git a/STM32F1/boards.txt b/STM32F1/boards.txt index c80bda9..adb2006 100644 --- a/STM32F1/boards.txt +++ b/STM32F1/boards.txt @@ -44,6 +44,16 @@ mapleMini.menu.cpu_speed.speed_72mhz.build.f_cpu=72000000L mapleMini.menu.cpu_speed.speed_48mhz=48Mhz (Slow - with USB) mapleMini.menu.cpu_speed.speed_48mhz.build.f_cpu=48000000L +#-- CPU Clock frequency +mapleMini.menu.cpu_speed.speed_72mhz=72Mhz (Normal) +mapleMini.menu.cpu_speed.speed_72mhz.build.f_cpu=72000000L + +mapleMini.menu.cpu_speed.speed_48mhz=48Mhz (Slow - with USB) +mapleMini.menu.cpu_speed.speed_48mhz.build.f_cpu=48000000L + +mapleMini.menu.cpu_speed.speed_128mhz=128Mhz (Turbo NO USB!) +mapleMini.menu.cpu_speed.speed_128mhz.build.f_cpu=128000000L + #-- Optimizations mapleMini.menu.opt.osstd=Smallest (default) mapleMini.menu.opt.osstd.build.flags.optimize=-Os @@ -99,6 +109,16 @@ maple.build.ldscript=ld/flash.ld maple.build.variant=maple maple.build.vect=VECT_TAB_ADDR=0x8005000 +#-- CPU Clock frequency +maple.menu.cpu_speed.speed_72mhz=72Mhz (Normal) +maple.menu.cpu_speed.speed_72mhz.build.f_cpu=72000000L + +maple.menu.cpu_speed.speed_48mhz=48Mhz (Slow - with USB) +maple.menu.cpu_speed.speed_48mhz.build.f_cpu=48000000L + +maple.menu.cpu_speed.speed_128mhz=128Mhz (Turbo NO USB!) +maple.menu.cpu_speed.speed_128mhz.build.f_cpu=128000000L + #-- Optimizations maple.menu.opt.osstd=Smallest (default) maple.menu.opt.osstd.build.flags.optimize=-Os @@ -154,6 +174,17 @@ mapleRET6.upload.usbID=1EAF:0003 mapleRET6.upload.altID=1 mapleRET6.upload.auto_reset=true +#-- CPU Clock frequency +mapleRET6.menu.cpu_speed.speed_72mhz=72Mhz (Normal) +mapleRET6.menu.cpu_speed.speed_72mhz.build.f_cpu=72000000L + +mapleRET6.menu.cpu_speed.speed_48mhz=48Mhz (Slow - with USB) +mapleRET6.menu.cpu_speed.speed_48mhz.build.f_cpu=48000000L + +mapleRET6.menu.cpu_speed.speed_128mhz=128Mhz (Turbo NO USB!) +mapleRET6.menu.cpu_speed.speed_128mhz.build.f_cpu=128000000L + + #-- Optimizations mapleRET6.menu.opt.osstd=Smallest (default) mapleRET6.menu.opt.osstd.build.flags.optimize=-Os @@ -217,6 +248,16 @@ microduino32_flash.build.error_led_port=GPIOB microduino32_flash.build.error_led_pin=1 microduino32_flash.build.gcc_ver=gcc-arm-none-eabi-4.8.3-2014q1 +#-- CPU Clock frequency +microduino32_flash.menu.cpu_speed.speed_72mhz=72Mhz (Normal) +microduino32_flash.menu.cpu_speed.speed_72mhz.build.f_cpu=72000000L + +microduino32_flash.menu.cpu_speed.speed_48mhz=48Mhz (Slow - with USB) +microduino32_flash.menu.cpu_speed.speed_48mhz.build.f_cpu=48000000L + +microduino32_flash.menu.cpu_speed.speed_128mhz=128Mhz (Turbo NO USB!) +microduino32_flash.menu.cpu_speed.speed_128mhz.build.f_cpu=128000000L + #-- Optimizations microduino32_flash.menu.opt.osstd=Smallest (default) microduino32_flash.menu.opt.osstd.build.flags.optimize=-Os @@ -384,6 +425,9 @@ genericSTM32F103C.menu.cpu_speed.speed_72mhz.build.f_cpu=72000000L genericSTM32F103C.menu.cpu_speed.speed_48mhz=48Mhz (Slow - with USB) genericSTM32F103C.menu.cpu_speed.speed_48mhz.build.f_cpu=48000000L +genericSTM32F103C.menu.cpu_speed.speed_128mhz=128Mhz (Turbo NO USB!) +genericSTM32F103C.menu.cpu_speed.speed_128mhz.build.f_cpu=128000000L + #-- Optimizations genericSTM32F103C.menu.opt.osstd=Smallest (default) genericSTM32F103C.menu.opt.osstd.build.flags.optimize=-Os @@ -485,6 +529,17 @@ genericSTM32F103R.menu.upload_method.BMPMethod.upload.protocol=gdb_bmp genericSTM32F103R.menu.upload_method.BMPMethod.upload.tool=bmp_upload genericSTM32F103R.menu.upload_method.BMPMethod.build.upload_flags=-DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG +#-- CPU Clock frequency +genericSTM32F103R.menu.cpu_speed.speed_72mhz=72Mhz (Normal) +genericSTM32F103R.menu.cpu_speed.speed_72mhz.build.f_cpu=72000000L + +genericSTM32F103R.menu.cpu_speed.speed_48mhz=48Mhz (Slow - with USB) +genericSTM32F103R.menu.cpu_speed.speed_48mhz.build.f_cpu=48000000L + +genericSTM32F103R.menu.cpu_speed.speed_128mhz=128Mhz (Turbo NO USB!) +genericSTM32F103R.menu.cpu_speed.speed_128mhz.build.f_cpu=128000000L + + #-- Optimizations genericSTM32F103R.menu.opt.osstd=Smallest (default) genericSTM32F103R.menu.opt.osstd.build.flags.optimize=-Os @@ -570,6 +625,16 @@ genericSTM32F103T.menu.upload_method.BMPMethod.upload.protocol=gdb_bmp genericSTM32F103T.menu.upload_method.BMPMethod.upload.tool=bmp_upload genericSTM32F103T.menu.upload_method.BMPMethod.build.upload_flags=-DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG +#-- CPU Clock frequency +genericSTM32F103T.menu.cpu_speed.speed_72mhz=72Mhz (Normal) +genericSTM32F103T.menu.cpu_speed.speed_72mhz.build.f_cpu=72000000L + +genericSTM32F103T.menu.cpu_speed.speed_48mhz=48Mhz (Slow - with USB) +genericSTM32F103T.menu.cpu_speed.speed_48mhz.build.f_cpu=48000000L + +genericSTM32F103T.menu.cpu_speed.speed_128mhz=128Mhz (Turbo NO USB!) +genericSTM32F103T.menu.cpu_speed.speed_128mhz.build.f_cpu=128000000L + #-- Optimizations genericSTM32F103T.menu.opt.osstd=Smallest (default) genericSTM32F103T.menu.opt.osstd.build.flags.optimize=-Os @@ -662,6 +727,16 @@ genericSTM32F103V.menu.upload_method.BMPMethod.upload.protocol=gdb_bmp genericSTM32F103V.menu.upload_method.BMPMethod.upload.tool=bmp_upload genericSTM32F103V.menu.upload_method.BMPMethod.build.upload_flags=-DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG +#-- CPU Clock frequency +genericSTM32F103V.menu.cpu_speed.speed_72mhz=72Mhz (Normal) +genericSTM32F103V.menu.cpu_speed.speed_72mhz.build.f_cpu=72000000L + +genericSTM32F103V.menu.cpu_speed.speed_48mhz=48Mhz (Slow - with USB) +genericSTM32F103V.menu.cpu_speed.speed_48mhz.build.f_cpu=48000000L + +genericSTM32F103V.menu.cpu_speed.speed_128mhz=128Mhz (Turbo NO USB!) +genericSTM32F103V.menu.cpu_speed.speed_128mhz.build.f_cpu=128000000L + #-- Optimizations genericSTM32F103V.menu.opt.osstd=Smallest (default) genericSTM32F103V.menu.opt.osstd.build.flags.optimize=-Os @@ -751,6 +826,16 @@ genericSTM32F103Z.menu.upload_method.BMPMethod.upload.protocol=gdb_bmp genericSTM32F103Z.menu.upload_method.BMPMethod.upload.tool=bmp_upload genericSTM32F103Z.menu.upload_method.BMPMethod.build.upload_flags=-DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG +#-- CPU Clock frequency +genericSTM32F103Z.menu.cpu_speed.speed_72mhz=72Mhz (Normal) +genericSTM32F103Z.menu.cpu_speed.speed_72mhz.build.f_cpu=72000000L + +genericSTM32F103Z.menu.cpu_speed.speed_48mhz=48Mhz (Slow - with USB) +genericSTM32F103Z.menu.cpu_speed.speed_48mhz.build.f_cpu=48000000L + +genericSTM32F103Z.menu.cpu_speed.speed_128mhz=128Mhz (Turbo NO USB!) +genericSTM32F103Z.menu.cpu_speed.speed_128mhz.build.f_cpu=128000000L + #-- Optimizations genericSTM32F103Z.menu.opt.osstd=Smallest (default) genericSTM32F103Z.menu.opt.osstd.build.flags.optimize=-Os @@ -834,6 +919,16 @@ hytiny-stm32f103t.menu.upload_method.jlinkMethod.upload.protocol=jlink hytiny-stm32f103t.menu.upload_method.jlinkMethod.upload.tool=jlink_upload hytiny-stm32f103t.menu.upload_method.jlinkMethod.build.upload_flags=-DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG=1 -DSERIAL_USB -DGENERIC_BOOTLOADER +#-- CPU Clock frequency +hytiny-stm32f103t.menu.cpu_speed.speed_72mhz=72Mhz (Normal) +hytiny-stm32f103t.menu.cpu_speed.speed_72mhz.build.f_cpu=72000000L + +hytiny-stm32f103t.menu.cpu_speed.speed_48mhz=48Mhz (Slow - with USB) +hytiny-stm32f103t.menu.cpu_speed.speed_48mhz.build.f_cpu=48000000L + +hytiny-stm32f103t.menu.cpu_speed.speed_128mhz=128Mhz (Turbo NO USB!) +hytiny-stm32f103t.menu.cpu_speed.speed_128mhz.build.f_cpu=128000000L + #-- Optimizations hytiny-stm32f103t.menu.opt.osstd=Smallest (default) hytiny-stm32f103t.menu.opt.osstd.build.flags.optimize=-Os @@ -988,6 +1083,16 @@ STM32VLD.menu.upload_method.STLinkMethod.upload.protocol=STLink STM32VLD.menu.upload_method.STLinkMethod.upload.tool=stlink_upload STM32VLD.menu.upload_method.STLinkMethod.build.upload_flags=-DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG +#-- CPU Clock frequency +STM32VLD.menu.cpu_speed.speed_72mhz=72Mhz (Normal) +STM32VLD.menu.cpu_speed.speed_72mhz.build.f_cpu=72000000L + +STM32VLD.menu.cpu_speed.speed_48mhz=48Mhz (Slow - with USB) +STM32VLD.menu.cpu_speed.speed_48mhz.build.f_cpu=48000000L + +STM32VLD.menu.cpu_speed.speed_128mhz=128Mhz (Turbo NO USB!) +STM32VLD.menu.cpu_speed.speed_128mhz.build.f_cpu=128000000L + #-- Optimizations STM32VLD.menu.opt.osstd=Smallest (default) STM32VLD.menu.opt.osstd.build.flags.optimize=-Os diff --git a/STM32F1/variants/generic_stm32f103c/wirish/boards_setup.cpp b/STM32F1/variants/generic_stm32f103c/wirish/boards_setup.cpp index 5516282..9e8332e 100644 --- a/STM32F1/variants/generic_stm32f103c/wirish/boards_setup.cpp +++ b/STM32F1/variants/generic_stm32f103c/wirish/boards_setup.cpp @@ -48,11 +48,13 @@ // works for F103 performance line MCUs, which is all that LeafLabs // currently officially supports). #ifndef BOARD_RCC_PLLMUL - #if F_CPU==72000000 - #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 - #elif F_CPU==48000000 - #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 - #endif + #if F_CPU==128000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_16 + #elif F_CPU==72000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 + #elif F_CPU==48000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 + #endif #endif namespace wirish { diff --git a/STM32F1/variants/generic_stm32f103r/wirish/boards_setup.cpp b/STM32F1/variants/generic_stm32f103r/wirish/boards_setup.cpp index d7774f7..0413015 100644 --- a/STM32F1/variants/generic_stm32f103r/wirish/boards_setup.cpp +++ b/STM32F1/variants/generic_stm32f103r/wirish/boards_setup.cpp @@ -48,11 +48,13 @@ // works for F103 performance line MCUs, which is all that LeafLabs // currently officially supports). #ifndef BOARD_RCC_PLLMUL - #if F_CPU==72000000 - #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 - #elif F_CPU==48000000 - #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 - #endif + #if F_CPU==128000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_16 + #elif F_CPU==72000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 + #elif F_CPU==48000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 + #endif #endif namespace wirish { diff --git a/STM32F1/variants/generic_stm32f103r8/wirish/boards_setup.cpp b/STM32F1/variants/generic_stm32f103r8/wirish/boards_setup.cpp index 7c93977..8da724d 100644 --- a/STM32F1/variants/generic_stm32f103r8/wirish/boards_setup.cpp +++ b/STM32F1/variants/generic_stm32f103r8/wirish/boards_setup.cpp @@ -48,11 +48,13 @@ // works for F103 performance line MCUs, which is all that LeafLabs // currently officially supports). #ifndef BOARD_RCC_PLLMUL - #if F_CPU==72000000 - #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 - #elif F_CPU==48000000 - #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 - #endif + #if F_CPU==128000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_16 + #elif F_CPU==72000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 + #elif F_CPU==48000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 + #endif #endif namespace wirish { diff --git a/STM32F1/variants/generic_stm32f103t/wirish/boards_setup.cpp b/STM32F1/variants/generic_stm32f103t/wirish/boards_setup.cpp index 5516282..9e8332e 100644 --- a/STM32F1/variants/generic_stm32f103t/wirish/boards_setup.cpp +++ b/STM32F1/variants/generic_stm32f103t/wirish/boards_setup.cpp @@ -48,11 +48,13 @@ // works for F103 performance line MCUs, which is all that LeafLabs // currently officially supports). #ifndef BOARD_RCC_PLLMUL - #if F_CPU==72000000 - #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 - #elif F_CPU==48000000 - #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 - #endif + #if F_CPU==128000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_16 + #elif F_CPU==72000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 + #elif F_CPU==48000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 + #endif #endif namespace wirish { diff --git a/STM32F1/variants/generic_stm32f103v/wirish/boards_setup.cpp b/STM32F1/variants/generic_stm32f103v/wirish/boards_setup.cpp index 1f23679..dba014b 100644 --- a/STM32F1/variants/generic_stm32f103v/wirish/boards_setup.cpp +++ b/STM32F1/variants/generic_stm32f103v/wirish/boards_setup.cpp @@ -48,11 +48,13 @@ // works for F103 performance line MCUs, which is all that LeafLabs // currently officially supports). #ifndef BOARD_RCC_PLLMUL - #if F_CPU==72000000 - #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 - #elif F_CPU==48000000 - #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 - #endif + #if F_CPU==128000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_16 + #elif F_CPU==72000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 + #elif F_CPU==48000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 + #endif #endif namespace wirish { diff --git a/STM32F1/variants/generic_stm32f103z/wirish/boards_setup.cpp b/STM32F1/variants/generic_stm32f103z/wirish/boards_setup.cpp index e2cfe4a..3d4e4e8 100644 --- a/STM32F1/variants/generic_stm32f103z/wirish/boards_setup.cpp +++ b/STM32F1/variants/generic_stm32f103z/wirish/boards_setup.cpp @@ -48,11 +48,13 @@ // works for F103 performance line MCUs, which is all that LeafLabs // currently officially supports). #ifndef BOARD_RCC_PLLMUL - #if F_CPU==72000000 - #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 - #elif F_CPU==48000000 - #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 - #endif + #if F_CPU==128000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_16 + #elif F_CPU==72000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 + #elif F_CPU==48000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 + #endif #endif namespace wirish { diff --git a/STM32F1/variants/hytiny_stm32f103t/wirish/boards_setup.cpp b/STM32F1/variants/hytiny_stm32f103t/wirish/boards_setup.cpp index df39347..f10fcf8 100644 --- a/STM32F1/variants/hytiny_stm32f103t/wirish/boards_setup.cpp +++ b/STM32F1/variants/hytiny_stm32f103t/wirish/boards_setup.cpp @@ -48,11 +48,13 @@ // works for F103 performance line MCUs, which is all that LeafLabs // currently officially supports). #ifndef BOARD_RCC_PLLMUL - #if F_CPU==72000000 - #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 - #elif F_CPU==48000000 - #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 - #endif + #if F_CPU==128000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_16 + #elif F_CPU==72000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 + #elif F_CPU==48000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 + #endif #endif namespace wirish { diff --git a/STM32F1/variants/maple/wirish/boards_setup.cpp b/STM32F1/variants/maple/wirish/boards_setup.cpp index 1071d6d..c4b55c0 100644 --- a/STM32F1/variants/maple/wirish/boards_setup.cpp +++ b/STM32F1/variants/maple/wirish/boards_setup.cpp @@ -48,11 +48,13 @@ // works for F103 performance line MCUs, which is all that LeafLabs // currently officially supports). #ifndef BOARD_RCC_PLLMUL - #if F_CPU==72000000 - #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 - #elif F_CPU==48000000 - #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 - #endif + #if F_CPU==128000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_16 + #elif F_CPU==72000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 + #elif F_CPU==48000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 + #endif #endif namespace wirish { diff --git a/STM32F1/variants/maple_mini/wirish/boards_setup.cpp b/STM32F1/variants/maple_mini/wirish/boards_setup.cpp index df39347..f10fcf8 100644 --- a/STM32F1/variants/maple_mini/wirish/boards_setup.cpp +++ b/STM32F1/variants/maple_mini/wirish/boards_setup.cpp @@ -48,11 +48,13 @@ // works for F103 performance line MCUs, which is all that LeafLabs // currently officially supports). #ifndef BOARD_RCC_PLLMUL - #if F_CPU==72000000 - #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 - #elif F_CPU==48000000 - #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 - #endif + #if F_CPU==128000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_16 + #elif F_CPU==72000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 + #elif F_CPU==48000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 + #endif #endif namespace wirish { diff --git a/STM32F1/variants/maple_ret6/wirish/boards_setup.cpp b/STM32F1/variants/maple_ret6/wirish/boards_setup.cpp index 1071d6d..c4b55c0 100644 --- a/STM32F1/variants/maple_ret6/wirish/boards_setup.cpp +++ b/STM32F1/variants/maple_ret6/wirish/boards_setup.cpp @@ -48,11 +48,13 @@ // works for F103 performance line MCUs, which is all that LeafLabs // currently officially supports). #ifndef BOARD_RCC_PLLMUL - #if F_CPU==72000000 - #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 - #elif F_CPU==48000000 - #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 - #endif + #if F_CPU==128000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_16 + #elif F_CPU==72000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 + #elif F_CPU==48000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 + #endif #endif namespace wirish { diff --git a/STM32F1/variants/microduino/wirish/boards_setup.cpp b/STM32F1/variants/microduino/wirish/boards_setup.cpp index e899843..785753a 100644 --- a/STM32F1/variants/microduino/wirish/boards_setup.cpp +++ b/STM32F1/variants/microduino/wirish/boards_setup.cpp @@ -48,11 +48,13 @@ // works for F103 performance line MCUs, which is all that LeafLabs // currently officially supports). #ifndef BOARD_RCC_PLLMUL - #if F_CPU==72000000 - #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 - #elif F_CPU==48000000 - #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 - #endif + #if F_CPU==128000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_16 + #elif F_CPU==72000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 + #elif F_CPU==48000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 + #endif #endif namespace wirish { From 375a8f84b570077d6260babe6c040aef14f6235e Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Sun, 30 Jul 2017 20:08:20 +1000 Subject: [PATCH 127/351] Fixed typo in F1 boards.txt for STM32F103CB RAM size --- STM32F1/boards.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/boards.txt b/STM32F1/boards.txt index adb2006..9c2def4 100644 --- a/STM32F1/boards.txt +++ b/STM32F1/boards.txt @@ -385,7 +385,7 @@ genericSTM32F103C.menu.device_variant.STM32F103CB=STM32F103CB (20k RAM. 128k Fla genericSTM32F103C.menu.device_variant.STM32F103CB.build.cpu_flags=-DMCU_STM32F103CB genericSTM32F103C.menu.device_variant.STM32F103CB.build.ldscript=ld/jtag.ld genericSTM32F103C.menu.device_variant.STM32F103CB.upload.maximum_size=131072 -genericSTM32F103C.menu.device_variant.STM32F103C8.upload.maximum_data_size=20480 +genericSTM32F103C.menu.device_variant.STM32F103CB.upload.maximum_data_size=20480 #---------------------------- UPLOAD METHODS --------------------------- From 14ddcfd97dd82d0e1f91b9fb90307bcf7d597fc9 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Mon, 31 Jul 2017 10:51:52 +1000 Subject: [PATCH 128/351] Changed text on 128Mhz CPU speed option - to add warning that there is No USB and also Manual reset needed to upload --- STM32F1/boards.txt | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/STM32F1/boards.txt b/STM32F1/boards.txt index 9c2def4..ef6fc8e 100644 --- a/STM32F1/boards.txt +++ b/STM32F1/boards.txt @@ -51,7 +51,7 @@ mapleMini.menu.cpu_speed.speed_72mhz.build.f_cpu=72000000L mapleMini.menu.cpu_speed.speed_48mhz=48Mhz (Slow - with USB) mapleMini.menu.cpu_speed.speed_48mhz.build.f_cpu=48000000L -mapleMini.menu.cpu_speed.speed_128mhz=128Mhz (Turbo NO USB!) +mapleMini.menu.cpu_speed.speed_128mhz=Overclocked 128Mhz NO USB SERIAL. MANUAL RESET NEEDED TO UPLOAD mapleMini.menu.cpu_speed.speed_128mhz.build.f_cpu=128000000L #-- Optimizations @@ -116,7 +116,7 @@ maple.menu.cpu_speed.speed_72mhz.build.f_cpu=72000000L maple.menu.cpu_speed.speed_48mhz=48Mhz (Slow - with USB) maple.menu.cpu_speed.speed_48mhz.build.f_cpu=48000000L -maple.menu.cpu_speed.speed_128mhz=128Mhz (Turbo NO USB!) +maple.menu.cpu_speed.speed_128mhz=Overclocked 128Mhz NO USB SERIAL. MANUAL RESET NEEDED TO UPLOAD maple.menu.cpu_speed.speed_128mhz.build.f_cpu=128000000L #-- Optimizations @@ -181,7 +181,7 @@ mapleRET6.menu.cpu_speed.speed_72mhz.build.f_cpu=72000000L mapleRET6.menu.cpu_speed.speed_48mhz=48Mhz (Slow - with USB) mapleRET6.menu.cpu_speed.speed_48mhz.build.f_cpu=48000000L -mapleRET6.menu.cpu_speed.speed_128mhz=128Mhz (Turbo NO USB!) +mapleRET6.menu.cpu_speed.speed_128mhz=Overclocked 128Mhz NO USB SERIAL. MANUAL RESET NEEDED TO UPLOAD mapleRET6.menu.cpu_speed.speed_128mhz.build.f_cpu=128000000L @@ -255,7 +255,7 @@ microduino32_flash.menu.cpu_speed.speed_72mhz.build.f_cpu=72000000L microduino32_flash.menu.cpu_speed.speed_48mhz=48Mhz (Slow - with USB) microduino32_flash.menu.cpu_speed.speed_48mhz.build.f_cpu=48000000L -microduino32_flash.menu.cpu_speed.speed_128mhz=128Mhz (Turbo NO USB!) +microduino32_flash.menu.cpu_speed.speed_128mhz=Overclocked 128Mhz NO USB SERIAL. MANUAL RESET NEEDED TO UPLOAD microduino32_flash.menu.cpu_speed.speed_128mhz.build.f_cpu=128000000L #-- Optimizations @@ -425,7 +425,7 @@ genericSTM32F103C.menu.cpu_speed.speed_72mhz.build.f_cpu=72000000L genericSTM32F103C.menu.cpu_speed.speed_48mhz=48Mhz (Slow - with USB) genericSTM32F103C.menu.cpu_speed.speed_48mhz.build.f_cpu=48000000L -genericSTM32F103C.menu.cpu_speed.speed_128mhz=128Mhz (Turbo NO USB!) +genericSTM32F103C.menu.cpu_speed.speed_128mhz=Overclocked 128Mhz NO USB SERIAL. MANUAL RESET NEEDED TO UPLOAD genericSTM32F103C.menu.cpu_speed.speed_128mhz.build.f_cpu=128000000L #-- Optimizations @@ -536,7 +536,7 @@ genericSTM32F103R.menu.cpu_speed.speed_72mhz.build.f_cpu=72000000L genericSTM32F103R.menu.cpu_speed.speed_48mhz=48Mhz (Slow - with USB) genericSTM32F103R.menu.cpu_speed.speed_48mhz.build.f_cpu=48000000L -genericSTM32F103R.menu.cpu_speed.speed_128mhz=128Mhz (Turbo NO USB!) +genericSTM32F103R.menu.cpu_speed.speed_128mhz=Overclocked 128Mhz NO USB SERIAL. MANUAL RESET NEEDED TO UPLOAD genericSTM32F103R.menu.cpu_speed.speed_128mhz.build.f_cpu=128000000L @@ -632,7 +632,7 @@ genericSTM32F103T.menu.cpu_speed.speed_72mhz.build.f_cpu=72000000L genericSTM32F103T.menu.cpu_speed.speed_48mhz=48Mhz (Slow - with USB) genericSTM32F103T.menu.cpu_speed.speed_48mhz.build.f_cpu=48000000L -genericSTM32F103T.menu.cpu_speed.speed_128mhz=128Mhz (Turbo NO USB!) +genericSTM32F103T.menu.cpu_speed.speed_128mhz=Overclocked 128Mhz NO USB SERIAL. MANUAL RESET NEEDED TO UPLOAD genericSTM32F103T.menu.cpu_speed.speed_128mhz.build.f_cpu=128000000L #-- Optimizations @@ -734,7 +734,7 @@ genericSTM32F103V.menu.cpu_speed.speed_72mhz.build.f_cpu=72000000L genericSTM32F103V.menu.cpu_speed.speed_48mhz=48Mhz (Slow - with USB) genericSTM32F103V.menu.cpu_speed.speed_48mhz.build.f_cpu=48000000L -genericSTM32F103V.menu.cpu_speed.speed_128mhz=128Mhz (Turbo NO USB!) +genericSTM32F103V.menu.cpu_speed.speed_128mhz=Overclocked 128Mhz NO USB SERIAL. MANUAL RESET NEEDED TO UPLOAD genericSTM32F103V.menu.cpu_speed.speed_128mhz.build.f_cpu=128000000L #-- Optimizations @@ -833,7 +833,7 @@ genericSTM32F103Z.menu.cpu_speed.speed_72mhz.build.f_cpu=72000000L genericSTM32F103Z.menu.cpu_speed.speed_48mhz=48Mhz (Slow - with USB) genericSTM32F103Z.menu.cpu_speed.speed_48mhz.build.f_cpu=48000000L -genericSTM32F103Z.menu.cpu_speed.speed_128mhz=128Mhz (Turbo NO USB!) +genericSTM32F103Z.menu.cpu_speed.speed_128mhz=Overclocked 128Mhz NO USB SERIAL. MANUAL RESET NEEDED TO UPLOAD genericSTM32F103Z.menu.cpu_speed.speed_128mhz.build.f_cpu=128000000L #-- Optimizations @@ -926,7 +926,7 @@ hytiny-stm32f103t.menu.cpu_speed.speed_72mhz.build.f_cpu=72000000L hytiny-stm32f103t.menu.cpu_speed.speed_48mhz=48Mhz (Slow - with USB) hytiny-stm32f103t.menu.cpu_speed.speed_48mhz.build.f_cpu=48000000L -hytiny-stm32f103t.menu.cpu_speed.speed_128mhz=128Mhz (Turbo NO USB!) +hytiny-stm32f103t.menu.cpu_speed.speed_128mhz=Overclocked 128Mhz NO USB SERIAL. MANUAL RESET NEEDED TO UPLOAD hytiny-stm32f103t.menu.cpu_speed.speed_128mhz.build.f_cpu=128000000L #-- Optimizations @@ -1090,7 +1090,7 @@ STM32VLD.menu.cpu_speed.speed_72mhz.build.f_cpu=72000000L STM32VLD.menu.cpu_speed.speed_48mhz=48Mhz (Slow - with USB) STM32VLD.menu.cpu_speed.speed_48mhz.build.f_cpu=48000000L -STM32VLD.menu.cpu_speed.speed_128mhz=128Mhz (Turbo NO USB!) +STM32VLD.menu.cpu_speed.speed_128mhz=Overclocked 128Mhz NO USB SERIAL. MANUAL RESET NEEDED TO UPLOAD STM32VLD.menu.cpu_speed.speed_128mhz.build.f_cpu=128000000L #-- Optimizations From 7d1119ee3456e6db4e44dc8a621671d83af76f88 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Mon, 31 Jul 2017 10:56:31 +1000 Subject: [PATCH 129/351] Removed Debug with LTO optimisation option, to fix issue #320 --- STM32F1/boards.txt | 39 --------------------------------------- 1 file changed, 39 deletions(-) diff --git a/STM32F1/boards.txt b/STM32F1/boards.txt index ef6fc8e..9cef207 100644 --- a/STM32F1/boards.txt +++ b/STM32F1/boards.txt @@ -82,9 +82,6 @@ mapleMini.menu.opt.o3lto.build.flags.ldspecs=-flto mapleMini.menu.opt.ogstd=Debug (-g) mapleMini.menu.opt.ogstd.build.flags.optimize=-Og mapleMini.menu.opt.ogstd.build.flags.ldspecs= -mapleMini.menu.opt.oglto=Debug with LTO -mapleMini.menu.opt.oglto.build.flags.optimize=-Og -flto -mapleMini.menu.opt.oglto.build.flags.ldspecs=-flto ############################################################## @@ -147,9 +144,6 @@ maple.menu.opt.o3lto.build.flags.ldspecs=-flto maple.menu.opt.ogstd=Debug (-g) maple.menu.opt.ogstd.build.flags.optimize=-Og maple.menu.opt.ogstd.build.flags.ldspecs= -maple.menu.opt.oglto=Debug with LTO -maple.menu.opt.oglto.build.flags.optimize=-Og -flto -maple.menu.opt.oglto.build.flags.ldspecs=-flto ############################################################## mapleRET6.name=Maple (RET6) @@ -213,9 +207,6 @@ mapleRET6.menu.opt.ogstd=Debug (-g) mapleRET6.menu.opt.o3lto.build.flags.ldspecs=-flto mapleRET6.menu.opt.ogstd.build.flags.optimize=-Og mapleRET6.menu.opt.ogstd.build.flags.ldspecs= -mapleRET6.menu.opt.oglto=Debug with LTO -mapleRET6.menu.opt.oglto.build.flags.optimize=-Og -flto -mapleRET6.menu.opt.oglto.build.flags.ldspecs=-flto ############################################################## @@ -286,9 +277,6 @@ microduino32_flash.menu.opt.ogstd=Debug (-g) microduino32_flash.menu.opt.o3lto.build.flags.ldspecs=-flto microduino32_flash.menu.opt.ogstd.build.flags.optimize=-Og microduino32_flash.menu.opt.ogstd.build.flags.ldspecs= -microduino32_flash.menu.opt.oglto=Debug with LTO -microduino32_flash.menu.opt.oglto.build.flags.optimize=-Og -flto -microduino32_flash.menu.opt.oglto.build.flags.ldspecs=-flto ############################################################## nucleo_f103rb.name=STM Nucleo F103RB (STLink) @@ -356,9 +344,6 @@ nucleo_f103rb.menu.opt.ogstd=Debug (-g) nucleo_f103rb.menu.opt.o3lto.build.flags.ldspecs=-flto nucleo_f103rb.menu.opt.ogstd.build.flags.optimize=-Og nucleo_f103rb.menu.opt.ogstd.build.flags.ldspecs= -nucleo_f103rb.menu.opt.oglto=Debug with LTO -nucleo_f103rb.menu.opt.oglto.build.flags.optimize=-Og -flto -nucleo_f103rb.menu.opt.oglto.build.flags.ldspecs=-flto ###################### Generic STM32F103C ######################################## @@ -456,9 +441,6 @@ genericSTM32F103C.menu.opt.ogstd=Debug (-g) genericSTM32F103C.menu.opt.o3lto.build.flags.ldspecs=-flto genericSTM32F103C.menu.opt.ogstd.build.flags.optimize=-Og genericSTM32F103C.menu.opt.ogstd.build.flags.ldspecs= -genericSTM32F103C.menu.opt.oglto=Debug with LTO -genericSTM32F103C.menu.opt.oglto.build.flags.optimize=-Og -flto -genericSTM32F103C.menu.opt.oglto.build.flags.ldspecs=-flto ########################### Generic STM32F103R ########################### @@ -568,9 +550,6 @@ genericSTM32F103R.menu.opt.ogstd=Debug (-g) genericSTM32F103R.menu.opt.o3lto.build.flags.ldspecs=-flto genericSTM32F103R.menu.opt.ogstd.build.flags.optimize=-Og genericSTM32F103R.menu.opt.ogstd.build.flags.ldspecs= -genericSTM32F103R.menu.opt.oglto=Debug with LTO -genericSTM32F103R.menu.opt.oglto.build.flags.optimize=-Og -flto -genericSTM32F103R.menu.opt.oglto.build.flags.ldspecs=-flto ###################### Generic STM32F103T ######################################## @@ -663,9 +642,6 @@ genericSTM32F103T.menu.opt.ogstd=Debug (-g) genericSTM32F103T.menu.opt.o3lto.build.flags.ldspecs=-flto genericSTM32F103T.menu.opt.ogstd.build.flags.optimize=-Og genericSTM32F103T.menu.opt.ogstd.build.flags.ldspecs= -genericSTM32F103T.menu.opt.oglto=Debug with LTO -genericSTM32F103T.menu.opt.oglto.build.flags.optimize=-Og -flto -genericSTM32F103T.menu.opt.oglto.build.flags.ldspecs=-flto ########################### Generic STM32F103V ########################### @@ -765,9 +741,6 @@ genericSTM32F103V.menu.opt.ogstd=Debug (-g) genericSTM32F103V.menu.opt.o3lto.build.flags.ldspecs=-flto genericSTM32F103V.menu.opt.ogstd.build.flags.optimize=-Og genericSTM32F103V.menu.opt.ogstd.build.flags.ldspecs= -genericSTM32F103V.menu.opt.oglto=Debug with LTO -genericSTM32F103V.menu.opt.oglto.build.flags.optimize=-Og -flto -genericSTM32F103V.menu.opt.oglto.build.flags.ldspecs=-flto ########################### Generic STM32F103Z ########################### @@ -864,9 +837,6 @@ genericSTM32F103Z.menu.opt.ogstd=Debug (-g) genericSTM32F103Z.menu.opt.o3lto.build.flags.ldspecs=-flto genericSTM32F103Z.menu.opt.ogstd.build.flags.optimize=-Og genericSTM32F103Z.menu.opt.ogstd.build.flags.ldspecs= -genericSTM32F103Z.menu.opt.oglto=Debug with LTO -genericSTM32F103Z.menu.opt.oglto.build.flags.optimize=-Og -flto -genericSTM32F103Z.menu.opt.oglto.build.flags.ldspecs=-flto ###################### HYTiny STM32F103T ######################################## @@ -957,9 +927,6 @@ hytiny-stm32f103t.menu.opt.ogstd=Debug (-g) hytiny-stm32f103t.menu.opt.o3lto.build.flags.ldspecs=-flto hytiny-stm32f103t.menu.opt.ogstd.build.flags.optimize=-Og hytiny-stm32f103t.menu.opt.ogstd.build.flags.ldspecs= -hytiny-stm32f103t.menu.opt.oglto=Debug with LTO -hytiny-stm32f103t.menu.opt.oglto.build.flags.optimize=-Og -flto -hytiny-stm32f103t.menu.opt.oglto.build.flags.ldspecs=-flto ###################### Generic GD32F103C ######################################## @@ -1051,9 +1018,6 @@ genericGD32F103C.menu.opt.ogstd=Debug (-g) genericGD32F103C.menu.opt.o3lto.build.flags.ldspecs=-flto genericGD32F103C.menu.opt.ogstd.build.flags.optimize=-Og genericGD32F103C.menu.opt.ogstd.build.flags.ldspecs= -genericGD32F103C.menu.opt.oglto=Debug with LTO -genericGD32F103C.menu.opt.oglto.build.flags.optimize=-Og -flto -genericGD32F103C.menu.opt.oglto.build.flags.ldspecs=-flto ########################### STM32VLD to FLASH ########################### @@ -1121,8 +1085,5 @@ STM32VLD.menu.opt.ogstd=Debug (-g) STM32VLD.menu.opt.o3lto.build.flags.ldspecs=-flto STM32VLD.menu.opt.ogstd.build.flags.optimize=-Og STM32VLD.menu.opt.ogstd.build.flags.ldspecs= -STM32VLD.menu.opt.oglto=Debug with LTO -STM32VLD.menu.opt.oglto.build.flags.optimize=-Og -flto -STM32VLD.menu.opt.oglto.build.flags.ldspecs=-flto ################################################################################ \ No newline at end of file From ac27993d10a9d910890b6c655a4435fcd1f10ab6 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Mon, 31 Jul 2017 13:33:00 +1000 Subject: [PATCH 130/351] Added makeWord macro and functions to fix #316 --- STM32F1/cores/maple/wirish_math.cpp | 9 +++++++++ STM32F1/cores/maple/wirish_math.h | 6 ++++++ 2 files changed, 15 insertions(+) diff --git a/STM32F1/cores/maple/wirish_math.cpp b/STM32F1/cores/maple/wirish_math.cpp index 3b682d3..f8ada9f 100644 --- a/STM32F1/cores/maple/wirish_math.cpp +++ b/STM32F1/cores/maple/wirish_math.cpp @@ -47,3 +47,12 @@ long random(long howsmall, long howbig) { return random(diff) + howsmall; } +extern uint16_t makeWord( uint16_t w ) +{ + return w ; +} + +extern uint16_t makeWord( uint8_t h, uint8_t l ) +{ + return (h << 8) | l ; +} diff --git a/STM32F1/cores/maple/wirish_math.h b/STM32F1/cores/maple/wirish_math.h index d103d86..9140d06 100644 --- a/STM32F1/cores/maple/wirish_math.h +++ b/STM32F1/cores/maple/wirish_math.h @@ -33,6 +33,7 @@ #define _WIRISH_WIRISH_MATH_H_ #include +#include /** * @brief Initialize the pseudo-random number generator. @@ -161,4 +162,9 @@ double sqrt(double x); */ double pow(double x, double y); +extern uint16_t makeWord( uint16_t w ) ; +extern uint16_t makeWord( uint8_t h, uint8_t l ) ; + +#define word(...) makeWord(__VA_ARGS__) + #endif From c0f655f90ff0a89e7c88b05e94c2826bace60510 Mon Sep 17 00:00:00 2001 From: Cristi Marius Tiutiu Date: Mon, 31 Jul 2017 11:42:28 +0300 Subject: [PATCH 131/351] added menu optimizations support for F3/F4 boards --- STM32F3/boards.txt | 30 +++++++++++ STM32F3/platform.txt | 8 +-- STM32F4/boards.txt | 116 +++++++++++++++++++++++++++++++++++++++++++ STM32F4/platform.txt | 8 +-- 4 files changed, 154 insertions(+), 8 deletions(-) diff --git a/STM32F3/boards.txt b/STM32F3/boards.txt index 6c011bc..98a184d 100644 --- a/STM32F3/boards.txt +++ b/STM32F3/boards.txt @@ -1,5 +1,7 @@ # +menu.opt=Optimize + ############################################################## discovery_f3.name=STM32F3Discovery @@ -28,5 +30,33 @@ discovery_f3.build.error_led_port=GPIOE discovery_f3.build.error_led_pin=8 discovery_f3.build.board=STM32F3Discovery +#-- Optimizations +discovery_f3.menu.opt.osstd=Smallest (default) +discovery_f3.menu.opt.osstd.build.flags.optimize=-Os +discovery_f3.menu.opt.osstd.build.flags.ldspecs= +discovery_f3.menu.opt.oslto=Smallest Code with LTO +discovery_f3.menu.opt.oslto.build.flags.optimize=-Os -flto +discovery_f3.menu.opt.oslto.build.flags.ldspecs=-flto +discovery_f3.menu.opt.o1std=Fast (-O1) +discovery_f3.menu.opt.o1std.build.flags.optimize=-O1 +discovery_f3.menu.opt.o1std.build.flags.ldspecs= +discovery_f3.menu.opt.o1lto=Fast (-O1) with LTO +discovery_f3.menu.opt.o1lto.build.flags.optimize=-O1 -flto +discovery_f3.menu.opt.o1lto.build.flags.ldspecs=-flto +discovery_f3.menu.opt.o2std=Faster (-O2) +discovery_f3.menu.opt.o2std.build.flags.optimize=-O2 +discovery_f3.menu.opt.o2std.build.flags.ldspecs= +discovery_f3.menu.opt.o2lto=Faster (-O2) with LTO +discovery_f3.menu.opt.o2lto.build.flags.optimize=-O2 -flto +discovery_f3.menu.opt.o2lto.build.flags.ldspecs=-flto +discovery_f3.menu.opt.o3std=Fastest (-O3) +discovery_f3.menu.opt.o3std.build.flags.optimize=-O3 +discovery_f3.menu.opt.o3std.build.flags.ldspecs= +discovery_f3.menu.opt.o3lto=Fastest (-O3) with LTO +discovery_f3.menu.opt.o3lto.build.flags.optimize=-O3 -flto +discovery_f3.menu.opt.o3lto.build.flags.ldspecs=-flto +discovery_f3.menu.opt.ogstd=Debug (-g) +discovery_f3.menu.opt.ogstd.build.flags.optimize=-Og +discovery_f3.menu.opt.ogstd.build.flags.ldspecs= ############################################################## diff --git a/STM32F3/platform.txt b/STM32F3/platform.txt index 3218f85..94f787c 100644 --- a/STM32F3/platform.txt +++ b/STM32F3/platform.txt @@ -12,20 +12,20 @@ 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 {build.flags.optimize} -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.elf.cmd=arm-none-eabi-g++ -compiler.c.elf.flags=-Os -Wl,--gc-sections +compiler.c.elf.flags={build.flags.optimize} -Wl,--gc-sections {build.flags.ldspecs} 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 {build.flags.optimize} -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.ar.cmd=arm-none-eabi-ar compiler.ar.flags=rcs compiler.objcopy.cmd=arm-none-eabi-objcopy compiler.objcopy.eep.flags=-O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 compiler.elf2hex.flags=-O binary compiler.elf2hex.cmd=arm-none-eabi-objcopy -compiler.ldflags= +compiler.ldflags={build.flags.ldspecs} compiler.size.cmd=arm-none-eabi-size compiler.define=-DARDUINO= diff --git a/STM32F4/boards.txt b/STM32F4/boards.txt index baf6f6e..abc40f0 100644 --- a/STM32F4/boards.txt +++ b/STM32F4/boards.txt @@ -1,6 +1,7 @@ # menu.usb_cfg=USB configuration +menu.opt=Optimize ############################################################## discovery_f407.name=STM32 Discovery F407 @@ -36,6 +37,35 @@ discovery_f407.menu.usb_cfg.usb_serial=USB serial (CDC) discovery_f407.menu.usb_cfg.usb_serial.build.cpu_flags=-DSERIAL_USB discovery_f407.menu.usb_cfg.usb_msc=USB Mass Storage (MSC) discovery_f407.menu.usb_cfg.usb_msc.build.cpu_flags=-DUSB_MSC + +#-- Optimizations +discovery_f407.menu.opt.osstd=Smallest (default) +discovery_f407.menu.opt.osstd.build.flags.optimize=-Os +discovery_f407.menu.opt.osstd.build.flags.ldspecs= +discovery_f407.menu.opt.oslto=Smallest Code with LTO +discovery_f407.menu.opt.oslto.build.flags.optimize=-Os -flto +discovery_f407.menu.opt.oslto.build.flags.ldspecs=-flto +discovery_f407.menu.opt.o1std=Fast (-O1) +discovery_f407.menu.opt.o1std.build.flags.optimize=-O1 +discovery_f407.menu.opt.o1std.build.flags.ldspecs= +discovery_f407.menu.opt.o1lto=Fast (-O1) with LTO +discovery_f407.menu.opt.o1lto.build.flags.optimize=-O1 -flto +discovery_f407.menu.opt.o1lto.build.flags.ldspecs=-flto +discovery_f407.menu.opt.o2std=Faster (-O2) +discovery_f407.menu.opt.o2std.build.flags.optimize=-O2 +discovery_f407.menu.opt.o2std.build.flags.ldspecs= +discovery_f407.menu.opt.o2lto=Faster (-O2) with LTO +discovery_f407.menu.opt.o2lto.build.flags.optimize=-O2 -flto +discovery_f407.menu.opt.o2lto.build.flags.ldspecs=-flto +discovery_f407.menu.opt.o3std=Fastest (-O3) +discovery_f407.menu.opt.o3std.build.flags.optimize=-O3 +discovery_f407.menu.opt.o3std.build.flags.ldspecs= +discovery_f407.menu.opt.o3lto=Fastest (-O3) with LTO +discovery_f407.menu.opt.o3lto.build.flags.optimize=-O3 -flto +discovery_f407.menu.opt.o3lto.build.flags.ldspecs=-flto +discovery_f407.menu.opt.ogstd=Debug (-g) +discovery_f407.menu.opt.ogstd.build.flags.optimize=-Og +discovery_f407.menu.opt.ogstd.build.flags.ldspecs= ############################################################## generic_f407v.name=Generic STM32F407V series @@ -72,6 +102,34 @@ generic_f407v.menu.usb_cfg.usb_serial.build.cpu_flags=-DSERIAL_USB generic_f407v.menu.usb_cfg.usb_msc=USB Mass Storage (MSC) generic_f407v.menu.usb_cfg.usb_msc.build.cpu_flags=-DUSB_MSC +#-- Optimizations +generic_f407v.menu.opt.osstd=Smallest (default) +generic_f407v.menu.opt.osstd.build.flags.optimize=-Os +generic_f407v.menu.opt.osstd.build.flags.ldspecs= +generic_f407v.menu.opt.oslto=Smallest Code with LTO +generic_f407v.menu.opt.oslto.build.flags.optimize=-Os -flto +generic_f407v.menu.opt.oslto.build.flags.ldspecs=-flto +generic_f407v.menu.opt.o1std=Fast (-O1) +generic_f407v.menu.opt.o1std.build.flags.optimize=-O1 +generic_f407v.menu.opt.o1std.build.flags.ldspecs= +generic_f407v.menu.opt.o1lto=Fast (-O1) with LTO +generic_f407v.menu.opt.o1lto.build.flags.optimize=-O1 -flto +generic_f407v.menu.opt.o1lto.build.flags.ldspecs=-flto +generic_f407v.menu.opt.o2std=Faster (-O2) +generic_f407v.menu.opt.o2std.build.flags.optimize=-O2 +generic_f407v.menu.opt.o2std.build.flags.ldspecs= +generic_f407v.menu.opt.o2lto=Faster (-O2) with LTO +generic_f407v.menu.opt.o2lto.build.flags.optimize=-O2 -flto +generic_f407v.menu.opt.o2lto.build.flags.ldspecs=-flto +generic_f407v.menu.opt.o3std=Fastest (-O3) +generic_f407v.menu.opt.o3std.build.flags.optimize=-O3 +generic_f407v.menu.opt.o3std.build.flags.ldspecs= +generic_f407v.menu.opt.o3lto=Fastest (-O3) with LTO +generic_f407v.menu.opt.o3lto.build.flags.optimize=-O3 -flto +generic_f407v.menu.opt.o3lto.build.flags.ldspecs=-flto +generic_f407v.menu.opt.ogstd=Debug (-g) +generic_f407v.menu.opt.ogstd.build.flags.optimize=-Og +generic_f407v.menu.opt.ogstd.build.flags.ldspecs= ############################################################## stm32f4stamp.name=STM32F4Stamp F405 @@ -107,6 +165,35 @@ stm32f4stamp.menu.usb_cfg.usb_serial=USB serial (CDC) stm32f4stamp.menu.usb_cfg.usb_serial.build.cpu_flags=-DSERIAL_USB stm32f4stamp.menu.usb_cfg.usb_msc=USB Mass Storage (MSC) stm32f4stamp.menu.usb_cfg.usb_msc.build.cpu_flags=-DUSB_MSC + +#-- Optimizations +stm32f4stamp.menu.opt.osstd=Smallest (default) +stm32f4stamp.menu.opt.osstd.build.flags.optimize=-Os +stm32f4stamp.menu.opt.osstd.build.flags.ldspecs= +stm32f4stamp.menu.opt.oslto=Smallest Code with LTO +stm32f4stamp.menu.opt.oslto.build.flags.optimize=-Os -flto +stm32f4stamp.menu.opt.oslto.build.flags.ldspecs=-flto +stm32f4stamp.menu.opt.o1std=Fast (-O1) +stm32f4stamp.menu.opt.o1std.build.flags.optimize=-O1 +stm32f4stamp.menu.opt.o1std.build.flags.ldspecs= +stm32f4stamp.menu.opt.o1lto=Fast (-O1) with LTO +stm32f4stamp.menu.opt.o1lto.build.flags.optimize=-O1 -flto +stm32f4stamp.menu.opt.o1lto.build.flags.ldspecs=-flto +stm32f4stamp.menu.opt.o2std=Faster (-O2) +stm32f4stamp.menu.opt.o2std.build.flags.optimize=-O2 +stm32f4stamp.menu.opt.o2std.build.flags.ldspecs= +stm32f4stamp.menu.opt.o2lto=Faster (-O2) with LTO +stm32f4stamp.menu.opt.o2lto.build.flags.optimize=-O2 -flto +stm32f4stamp.menu.opt.o2lto.build.flags.ldspecs=-flto +stm32f4stamp.menu.opt.o3std=Fastest (-O3) +stm32f4stamp.menu.opt.o3std.build.flags.optimize=-O3 +stm32f4stamp.menu.opt.o3std.build.flags.ldspecs= +stm32f4stamp.menu.opt.o3lto=Fastest (-O3) with LTO +stm32f4stamp.menu.opt.o3lto.build.flags.optimize=-O3 -flto +stm32f4stamp.menu.opt.o3lto.build.flags.ldspecs=-flto +stm32f4stamp.menu.opt.ogstd=Debug (-g) +stm32f4stamp.menu.opt.ogstd.build.flags.optimize=-Og +stm32f4stamp.menu.opt.ogstd.build.flags.ldspecs= ############################################################## netduino2plus.name=Netduino2 F405 @@ -142,5 +229,34 @@ netduino2plus.menu.usb_cfg.usb_serial=USB serial (CDC) netduino2plus.menu.usb_cfg.usb_serial.build.cpu_flags=-DSERIAL_USB netduino2plus.menu.usb_cfg.usb_msc=USB Mass Storage (MSC) netduino2plus.menu.usb_cfg.usb_msc.build.cpu_flags=-DUSB_MSC + +#-- Optimizations +netduino2plus.menu.opt.osstd=Smallest (default) +netduino2plus.menu.opt.osstd.build.flags.optimize=-Os +netduino2plus.menu.opt.osstd.build.flags.ldspecs= +netduino2plus.menu.opt.oslto=Smallest Code with LTO +netduino2plus.menu.opt.oslto.build.flags.optimize=-Os -flto +netduino2plus.menu.opt.oslto.build.flags.ldspecs=-flto +netduino2plus.menu.opt.o1std=Fast (-O1) +netduino2plus.menu.opt.o1std.build.flags.optimize=-O1 +netduino2plus.menu.opt.o1std.build.flags.ldspecs= +netduino2plus.menu.opt.o1lto=Fast (-O1) with LTO +netduino2plus.menu.opt.o1lto.build.flags.optimize=-O1 -flto +netduino2plus.menu.opt.o1lto.build.flags.ldspecs=-flto +netduino2plus.menu.opt.o2std=Faster (-O2) +netduino2plus.menu.opt.o2std.build.flags.optimize=-O2 +netduino2plus.menu.opt.o2std.build.flags.ldspecs= +netduino2plus.menu.opt.o2lto=Faster (-O2) with LTO +netduino2plus.menu.opt.o2lto.build.flags.optimize=-O2 -flto +netduino2plus.menu.opt.o2lto.build.flags.ldspecs=-flto +netduino2plus.menu.opt.o3std=Fastest (-O3) +netduino2plus.menu.opt.o3std.build.flags.optimize=-O3 +netduino2plus.menu.opt.o3std.build.flags.ldspecs= +netduino2plus.menu.opt.o3lto=Fastest (-O3) with LTO +netduino2plus.menu.opt.o3lto.build.flags.optimize=-O3 -flto +netduino2plus.menu.opt.o3lto.build.flags.ldspecs=-flto +netduino2plus.menu.opt.ogstd=Debug (-g) +netduino2plus.menu.opt.ogstd.build.flags.optimize=-Og +netduino2plus.menu.opt.ogstd.build.flags.ldspecs= ############################################################## diff --git a/STM32F4/platform.txt b/STM32F4/platform.txt index b64fe3e..92dc1ea 100755 --- a/STM32F4/platform.txt +++ b/STM32F4/platform.txt @@ -10,20 +10,20 @@ 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 -Wall -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.flags=-c -g {build.flags.optimize} -Wall -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.c.elf.flags={build.flags.optimize} -Wl,--gc-sections {build.flags.ldspecs} 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 -Wall -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.cpp.flags=-c -g {build.flags.optimize} -Wall -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 compiler.objcopy.eep.flags=-O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 compiler.elf2hex.flags=-O binary compiler.elf2hex.cmd=arm-none-eabi-objcopy -compiler.ldflags= +compiler.ldflags={build.flags.ldspecs} compiler.size.cmd=arm-none-eabi-size compiler.define=-DARDUINO= From bc41851ce49b2ab669c1ad649387fc8eda8254e6 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Tue, 1 Aug 2017 16:47:39 +1000 Subject: [PATCH 132/351] Changed default Wire (I2C) to use hardware I2C rather than bit banged software. The existing software Wire implementation has been retained as SoftWare. Examples have also been updated to include Wire, HardWire and Softwire. --- STM32F1/libraries/Wire/HardWire.cpp | 101 ------- STM32F1/libraries/Wire/HardWire.h | 78 ------ STM32F1/libraries/Wire/SoftWire.cpp | 246 ++++++++++++++++++ STM32F1/libraries/Wire/SoftWire.h | 163 ++++++++++++ STM32F1/libraries/Wire/Wire.cpp | 231 ++++------------ STM32F1/libraries/Wire/Wire.h | 147 +++-------- .../i2c_scanner_hardwire.ino} | 2 +- .../i2c_scanner_softwire.ino | 54 ++++ 8 files changed, 539 insertions(+), 483 deletions(-) delete mode 100644 STM32F1/libraries/Wire/HardWire.cpp delete mode 100644 STM32F1/libraries/Wire/HardWire.h create mode 100644 STM32F1/libraries/Wire/SoftWire.cpp create mode 100644 STM32F1/libraries/Wire/SoftWire.h rename STM32F1/libraries/Wire/examples/{i2c_scanner_hwire/i2c_scanner_hwire.ino => i2c_scanner_hardwire/i2c_scanner_hardwire.ino} (98%) create mode 100644 STM32F1/libraries/Wire/examples/i2c_scanner_softwire/i2c_scanner_softwire.ino diff --git a/STM32F1/libraries/Wire/HardWire.cpp b/STM32F1/libraries/Wire/HardWire.cpp deleted file mode 100644 index 51af7ad..0000000 --- a/STM32F1/libraries/Wire/HardWire.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 LeafLabs LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file HardWire.cpp - * @author Trystan Jones - * @brief Wire library, uses the hardware I2C available in the Maple to - * interact with I2C slave devices. - */ - -/* - * Library created by crenn to use the new WireBase system and allow Arduino - * users easy interaction with the I2C Hardware in a familiar method. - */ - -#include "HardWire.h" - -uint8 HardWire::process(uint8 stop) { - int8 res = i2c_master_xfer(sel_hard, &itc_msg, 1, 0); - if (res == I2C_ERROR_PROTOCOL) { - if (sel_hard->error_flags & I2C_SR1_AF) { /* NACK */ - res = (sel_hard->error_flags & I2C_SR1_ADDR ? ENACKADDR : - ENACKTRNS); - } else if (sel_hard->error_flags & I2C_SR1_OVR) { /* Over/Underrun */ - res = EDATA; - } else { /* Bus or Arbitration error */ - res = EOTHER; - } - i2c_disable(sel_hard); - i2c_master_enable(sel_hard, (I2C_BUS_RESET | dev_flags)); - } - return res; -} - -uint8 HardWire::process(){ - return process(true); -} - -// TODO: Add in Error Handling if devsel is out of range for other Maples -HardWire::HardWire(uint8 dev_sel, uint8 flags) { - if (dev_sel == 1) { - sel_hard = I2C1; - } else if (dev_sel == 2) { - sel_hard = I2C2; - } else { - ASSERT(1); - } - dev_flags = flags; -} - -HardWire::~HardWire() { - i2c_disable(sel_hard); - sel_hard = 0; -} - -void HardWire::begin(uint8 self_addr) { - i2c_master_enable(sel_hard, dev_flags); -} - -void HardWire::end() { - i2c_disable(sel_hard); - sel_hard = 0; -} - -void HardWire::setClock(uint32_t frequencyHz) -{ - switch(frequencyHz) - { - case 400000: - dev_flags |= I2C_FAST_MODE;// set FAST_MODE bit - break; - case 100000: - default: - dev_flags &= ~I2C_FAST_MODE;// clear FAST_MODE bit - break; - } - -} diff --git a/STM32F1/libraries/Wire/HardWire.h b/STM32F1/libraries/Wire/HardWire.h deleted file mode 100644 index 4d49e1a..0000000 --- a/STM32F1/libraries/Wire/HardWire.h +++ /dev/null @@ -1,78 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 LeafLabs LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file HardWire.h - * @author Trystan Jones - * @brief Wire library, uses the hardware I2C available in the Maple to - * interact with I2C slave devices. - */ - -/* - * Library created by crenn to use the new WireBase system and allow Arduino - * users easy interaction with the I2C Hardware in a familiar method. - */ - -#ifndef _HARDWIRE_H_ -#define _HARDWIRE_H_ - -#include "WireBase.h" -#include "wirish.h" -#include - -class HardWire : public WireBase { -private: - i2c_dev* sel_hard; - uint8 dev_flags; -protected: - /* - * Processes the incoming I2C message defined by WireBase to the - * hardware. If an error occured, restart the I2C device. - */ - uint8 process(uint8); - uint8 process(); -public: - /* - * Check if devsel is within range and enable selected I2C interface with - * passed flags - */ - HardWire(uint8, uint8 = 0); - - /* - * Shuts down (disables) the hardware I2C - */ - void end(); - - void setClock(uint32_t frequencyHz); - /* - * Disables the I2C device and remove the device address. - */ - ~HardWire(); - - void begin(uint8 = 0x00); -}; -extern HardWire HWire; -#endif // _HARDWIRE_H_ diff --git a/STM32F1/libraries/Wire/SoftWire.cpp b/STM32F1/libraries/Wire/SoftWire.cpp new file mode 100644 index 0000000..781bb97 --- /dev/null +++ b/STM32F1/libraries/Wire/SoftWire.cpp @@ -0,0 +1,246 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file Wire.cpp + * @author Trystan Jones + * @brief Wire library, uses the WireBase to create the primary interface + * while keeping low level interactions invisible to the user. + */ + +/* + * Library updated by crenn to follow new Wire system. + * Code was derived from the original Wire for maple code by leaflabs and the + * modifications by gke and ala42. + */ + /* + * Updated by Roger Clark. 20141111. Fixed issue when process() returned because of missing ACK (often caused by invalid device address being used), caused SCL to be left + * LOW so that in the next call to process() , the first clock pulse was not sent, because SCL was LOW when it should have been high. + */ + /* + * Updated by Brandon Green. 20172306. Implementing the repeated start functionality. + */ + +#include "SoftWire.h" + +#define I2C_WRITE 0 +#define I2C_READ 1 + +/* low level conventions: + * - SDA/SCL idle high (expected high) + * - always start with i2c_delay rather than end + */ + +void TwoWire::set_scl(bool state) { + I2C_DELAY(this->i2c_delay); + + gpio_write_bit(sclDevice,sclBit, state); +// digitalWrite(this->scl_pin,state); + //Allow for clock stretching - dangerous currently + if (state == HIGH) { + while(digitalRead(this->scl_pin) == 0); + } +} + +void TwoWire::set_sda(bool state) { + I2C_DELAY(this->i2c_delay); + gpio_write_bit(sdaDevice,sdaBit, state); + //digitalWrite(this->sda_pin, state); +} + +void TwoWire::i2c_start() { + set_sda(LOW); + set_scl(LOW); +} + +void TwoWire::i2c_stop() { + set_sda(LOW); + set_scl(HIGH); + set_sda(HIGH); +} + +void TwoWire::i2c_repeated_start() { + set_sda(HIGH); + set_scl(HIGH); + set_sda(LOW); +} + +bool TwoWire::i2c_get_ack() { + set_scl(LOW); + set_sda(HIGH); + set_scl(HIGH); + + bool ret = !digitalRead(this->sda_pin); + set_scl(LOW); + return ret; +} + +void TwoWire::i2c_send_ack() { + set_sda(LOW); + set_scl(HIGH); + set_scl(LOW); +} + +void TwoWire::i2c_send_nack() { + set_sda(HIGH); + set_scl(HIGH); + set_scl(LOW); +} + +uint8 TwoWire::i2c_shift_in() { + uint8 data = 0; + set_sda(HIGH); + + int i; + for (i = 0; i < 8; i++) { + set_scl(HIGH); + data |= digitalRead(this->sda_pin) << (7-i); + set_scl(LOW); + } + + return data; +} + +void TwoWire::i2c_shift_out(uint8 val) { + int i; + for (i = 0; i < 8; i++) { + set_sda(!!(val & (1 << (7 - i)) ) ); + set_scl(HIGH); + set_scl(LOW); + } +} + +//process needs to be updated for repeated start. +uint8 TwoWire::process(uint8 stop) { + itc_msg.xferred = 0; + + uint8 sla_addr = (itc_msg.addr << 1); + if (itc_msg.flags == I2C_MSG_READ) { + sla_addr |= I2C_READ; + } + i2c_start(); + // shift out the address we're transmitting to + i2c_shift_out(sla_addr); + if (!i2c_get_ack()) + { + i2c_stop();// Roger Clark. 20141110 added to set clock high again, as it will be left in a low state otherwise + return ENACKADDR; + } + // Recieving + if (itc_msg.flags == I2C_MSG_READ) { + while (itc_msg.xferred < itc_msg.length) { + itc_msg.data[itc_msg.xferred++] = i2c_shift_in(); + if (itc_msg.xferred < itc_msg.length) + { + i2c_send_ack(); + } + else + { + i2c_send_nack(); + } + } + } + // Sending + else { + for (uint8 i = 0; i < itc_msg.length; i++) { + i2c_shift_out(itc_msg.data[i]); + if (!i2c_get_ack()) + { + i2c_stop();// Roger Clark. 20141110 added to set clock high again, as it will be left in a low state otherwise + return ENACKTRNS; + } + itc_msg.xferred++; + } + } + if(stop == true) + i2c_stop(); + else i2c_repeated_start(); + + return SUCCESS; +} + +// For compatibility with legacy code +uint8 TwoWire::process(){ + return process(true); +} + +// TODO: Add in Error Handling if pins is out of range for other Maples +// TODO: Make delays more capable +TwoWire::TwoWire(uint8 scl, uint8 sda, uint8 delay) : i2c_delay(delay) { + this->scl_pin=scl; + this->sda_pin=sda; +} + +void TwoWire::begin(uint8 self_addr) { + tx_buf_idx = 0; + tx_buf_overflow = false; + rx_buf_idx = 0; + rx_buf_len = 0; + pinMode(this->scl_pin, OUTPUT_OPEN_DRAIN); + pinMode(this->sda_pin, OUTPUT_OPEN_DRAIN); + + sclDevice = PIN_MAP[this->scl_pin].gpio_device; + sclBit = PIN_MAP[this->scl_pin].gpio_bit; + sdaDevice = PIN_MAP[this->sda_pin].gpio_device; + sdaBit = PIN_MAP[this->sda_pin].gpio_bit; + set_scl(HIGH); + set_sda(HIGH); +} + +void TwoWire::end() +{ + if (this->scl_pin) + { + pinMode(this->scl_pin, INPUT); + } + if (this->sda_pin) + { + pinMode(this->sda_pin, INPUT); + } +} + +void TwoWire::setClock(uint32_t frequencyHz) +{ + switch(frequencyHz) + { + case 400000: + i2c_delay = SOFT_FAST; + break; + case 100000: + default: + i2c_delay = SOFT_STANDARD; + break; + } +} + +TwoWire::~TwoWire() { + this->scl_pin=0; + this->sda_pin=0; +} + +// Declare the instance that the users of the library can use +//TwoWire Wire(SCL, SDA, SOFT_STANDARD); +//TwoWire Wire(PB6, PB7, SOFT_FAST); diff --git a/STM32F1/libraries/Wire/SoftWire.h b/STM32F1/libraries/Wire/SoftWire.h new file mode 100644 index 0000000..0804c0f --- /dev/null +++ b/STM32F1/libraries/Wire/SoftWire.h @@ -0,0 +1,163 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file Wire.h + * @author Trystan Jones + * @brief Wire library, uses the WireBase to create the primary interface + * while keeping low level interactions invisible to the user. + */ + +/* + * Library updated by crenn to follow new Wire system. + * Code was derived from the original Wire for maple code by leaflabs and the + * modifications by gke and ala42. + */ + +#ifndef _SOFTWIRE_H_ +#define _SOFTWIRE_H_ + +#include "WireBase.h" +#include "wirish.h" + +/* + * On the Maple, let the default pins be in the same location as the Arduino + * pins + */ +#define SDA PB7 +#define SCL PB6 + +#define SOFT_STANDARD 19 +#define SOFT_FAST 0 + + +//#define I2C_DELAY(x) {uint32 time=micros(); while(time>(micros()+x));} +#define I2C_DELAY(x) do{for(int i=0;i - * @brief Wire library, uses the WireBase to create the primary interface - * while keeping low level interactions invisible to the user. + * @brief Wire library, uses the hardware I2C available in the Maple to + * interact with I2C slave devices. */ /* - * Library updated by crenn to follow new Wire system. - * Code was derived from the original Wire for maple code by leaflabs and the - * modifications by gke and ala42. + * Library created by crenn to use the new WireBase system and allow Arduino + * users easy interaction with the I2C Hardware in a familiar method. */ - /* - * Updated by Roger Clark. 20141111. Fixed issue when process() returned because of missing ACK (often caused by invalid device address being used), caused SCL to be left - * LOW so that in the next call to process() , the first clock pulse was not sent, because SCL was LOW when it should have been high. - */ - /* - * Updated by Brandon Green. 20172306. Implementing the repeated start functionality. - */ #include "Wire.h" -#define I2C_WRITE 0 -#define I2C_READ 1 - -/* low level conventions: - * - SDA/SCL idle high (expected high) - * - always start with i2c_delay rather than end - */ - -void TwoWire::set_scl(bool state) { - I2C_DELAY(this->i2c_delay); - - gpio_write_bit(sclDevice,sclBit, state); -// digitalWrite(this->scl_pin,state); - //Allow for clock stretching - dangerous currently - if (state == HIGH) { - while(digitalRead(this->scl_pin) == 0); - } -} - -void TwoWire::set_sda(bool state) { - I2C_DELAY(this->i2c_delay); - gpio_write_bit(sdaDevice,sdaBit, state); - //digitalWrite(this->sda_pin, state); -} - -void TwoWire::i2c_start() { - set_sda(LOW); - set_scl(LOW); -} - -void TwoWire::i2c_stop() { - set_sda(LOW); - set_scl(HIGH); - set_sda(HIGH); -} - -void TwoWire::i2c_repeated_start() { - set_sda(HIGH); - set_scl(HIGH); - set_sda(LOW); -} - -bool TwoWire::i2c_get_ack() { - set_scl(LOW); - set_sda(HIGH); - set_scl(HIGH); - - bool ret = !digitalRead(this->sda_pin); - set_scl(LOW); - return ret; -} - -void TwoWire::i2c_send_ack() { - set_sda(LOW); - set_scl(HIGH); - set_scl(LOW); -} - -void TwoWire::i2c_send_nack() { - set_sda(HIGH); - set_scl(HIGH); - set_scl(LOW); -} - -uint8 TwoWire::i2c_shift_in() { - uint8 data = 0; - set_sda(HIGH); - - int i; - for (i = 0; i < 8; i++) { - set_scl(HIGH); - data |= digitalRead(this->sda_pin) << (7-i); - set_scl(LOW); - } - - return data; -} - -void TwoWire::i2c_shift_out(uint8 val) { - int i; - for (i = 0; i < 8; i++) { - set_sda(!!(val & (1 << (7 - i)) ) ); - set_scl(HIGH); - set_scl(LOW); - } -} - -//process needs to be updated for repeated start. -uint8 TwoWire::process(uint8 stop) { - itc_msg.xferred = 0; - - uint8 sla_addr = (itc_msg.addr << 1); - if (itc_msg.flags == I2C_MSG_READ) { - sla_addr |= I2C_READ; - } - i2c_start(); - // shift out the address we're transmitting to - i2c_shift_out(sla_addr); - if (!i2c_get_ack()) - { - i2c_stop();// Roger Clark. 20141110 added to set clock high again, as it will be left in a low state otherwise - return ENACKADDR; - } - // Recieving - if (itc_msg.flags == I2C_MSG_READ) { - while (itc_msg.xferred < itc_msg.length) { - itc_msg.data[itc_msg.xferred++] = i2c_shift_in(); - if (itc_msg.xferred < itc_msg.length) - { - i2c_send_ack(); - } - else - { - i2c_send_nack(); - } +uint8 HardWire::process(uint8 stop) { + int8 res = i2c_master_xfer(sel_hard, &itc_msg, 1, 0); + if (res == I2C_ERROR_PROTOCOL) { + if (sel_hard->error_flags & I2C_SR1_AF) { /* NACK */ + res = (sel_hard->error_flags & I2C_SR1_ADDR ? ENACKADDR : + ENACKTRNS); + } else if (sel_hard->error_flags & I2C_SR1_OVR) { /* Over/Underrun */ + res = EDATA; + } else { /* Bus or Arbitration error */ + res = EOTHER; } + i2c_disable(sel_hard); + i2c_master_enable(sel_hard, (I2C_BUS_RESET | dev_flags)); } - // Sending - else { - for (uint8 i = 0; i < itc_msg.length; i++) { - i2c_shift_out(itc_msg.data[i]); - if (!i2c_get_ack()) - { - i2c_stop();// Roger Clark. 20141110 added to set clock high again, as it will be left in a low state otherwise - return ENACKTRNS; - } - itc_msg.xferred++; - } - } - if(stop == true) - i2c_stop(); - else i2c_repeated_start(); - - return SUCCESS; + return res; } -// For compatibility with legacy code -uint8 TwoWire::process(){ +uint8 HardWire::process(){ return process(true); } -// TODO: Add in Error Handling if pins is out of range for other Maples -// TODO: Make delays more capable -TwoWire::TwoWire(uint8 scl, uint8 sda, uint8 delay) : i2c_delay(delay) { - this->scl_pin=scl; - this->sda_pin=sda; +// TODO: Add in Error Handling if devsel is out of range for other Maples +HardWire::HardWire(uint8 dev_sel, uint8 flags) { + if (dev_sel == 1) { + sel_hard = I2C1; + } else if (dev_sel == 2) { + sel_hard = I2C2; + } else { + ASSERT(1); + } + dev_flags = flags; } -void TwoWire::begin(uint8 self_addr) { - tx_buf_idx = 0; - tx_buf_overflow = false; - rx_buf_idx = 0; - rx_buf_len = 0; - pinMode(this->scl_pin, OUTPUT_OPEN_DRAIN); - pinMode(this->sda_pin, OUTPUT_OPEN_DRAIN); - - sclDevice = PIN_MAP[this->scl_pin].gpio_device; - sclBit = PIN_MAP[this->scl_pin].gpio_bit; - sdaDevice = PIN_MAP[this->sda_pin].gpio_device; - sdaBit = PIN_MAP[this->sda_pin].gpio_bit; - set_scl(HIGH); - set_sda(HIGH); +HardWire::~HardWire() { + i2c_disable(sel_hard); + sel_hard = 0; } -void TwoWire::end() -{ - if (this->scl_pin) - { - pinMode(this->scl_pin, INPUT); - } - if (this->sda_pin) - { - pinMode(this->sda_pin, INPUT); - } +void HardWire::begin(uint8 self_addr) { + i2c_master_enable(sel_hard, dev_flags); } -void TwoWire::setClock(uint32_t frequencyHz) +void HardWire::end() { + i2c_disable(sel_hard); + sel_hard = 0; +} + +void HardWire::setClock(uint32_t frequencyHz) { switch(frequencyHz) { case 400000: - i2c_delay = SOFT_FAST; + dev_flags |= I2C_FAST_MODE;// set FAST_MODE bit break; case 100000: default: - i2c_delay = SOFT_STANDARD; + dev_flags &= ~I2C_FAST_MODE;// clear FAST_MODE bit break; } + } -TwoWire::~TwoWire() { - this->scl_pin=0; - this->sda_pin=0; -} - -// Declare the instance that the users of the library can use -TwoWire Wire(SCL, SDA, SOFT_STANDARD); -//TwoWire Wire(PB6, PB7, SOFT_STANDARD); +HardWire Wire(1, I2C_FAST_MODE);; diff --git a/STM32F1/libraries/Wire/Wire.h b/STM32F1/libraries/Wire/Wire.h index 8fbddaa..88d4a1b 100644 --- a/STM32F1/libraries/Wire/Wire.h +++ b/STM32F1/libraries/Wire/Wire.h @@ -25,139 +25,54 @@ *****************************************************************************/ /** - * @file Wire.h + * @file HardWire.h * @author Trystan Jones - * @brief Wire library, uses the WireBase to create the primary interface - * while keeping low level interactions invisible to the user. + * @brief Wire library, uses the hardware I2C available in the Maple to + * interact with I2C slave devices. */ /* - * Library updated by crenn to follow new Wire system. - * Code was derived from the original Wire for maple code by leaflabs and the - * modifications by gke and ala42. + * Library created by crenn to use the new WireBase system and allow Arduino + * users easy interaction with the I2C Hardware in a familiar method. */ -#ifndef _WIRE_H_ -#define _WIRE_H_ +#ifndef _HARDWIRE_H_ +#define _HARDWIRE_H_ #include "WireBase.h" #include "wirish.h" +#include -/* - * On the Maple, let the default pins be in the same location as the Arduino - * pins - */ -#define SDA PB7 -#define SCL PB6 - -#define SOFT_STANDARD 19 -#define SOFT_FAST 0 - - -//#define I2C_DELAY(x) {uint32 time=micros(); while(time>(micros()+x));} -#define I2C_DELAY(x) do{for(int i=0;i +#include HardWire HWire(1, I2C_FAST_MODE); // I2c1 diff --git a/STM32F1/libraries/Wire/examples/i2c_scanner_softwire/i2c_scanner_softwire.ino b/STM32F1/libraries/Wire/examples/i2c_scanner_softwire/i2c_scanner_softwire.ino new file mode 100644 index 0000000..0b4580a --- /dev/null +++ b/STM32F1/libraries/Wire/examples/i2c_scanner_softwire/i2c_scanner_softwire.ino @@ -0,0 +1,54 @@ +// -------------------------------------- +// i2c_scanner +// +// + +#include + +TwoWire SWire(PB6, PB7, SOFT_FAST); + + +void setup() { + Serial.begin(115200); + SWire.begin(); + Serial.println("\nSoftware I2C.. Scanner"); +} + + +void loop() { + byte error, address; + int nDevices; + + Serial.println("Scanning..."); + + nDevices = 0; + for(address = 1; address < 127; address++) { + // The i2c_scanner uses the return value of + // the Write.endTransmisstion to see if + // a device did acknowledge to the address. + + SWire.beginTransmission(address); + error = SWire.endTransmission(); + + if (error == 0) { + Serial.print("I2C device found at address 0x"); + if (address < 16) + Serial.print("0"); + Serial.println(address, HEX); + + nDevices++; + } + else if (error == 4) { + Serial.print("Unknown error at address 0x"); + if (address < 16) + Serial.print("0"); + Serial.println(address, HEX); + } + } + if (nDevices == 0) + Serial.println("No I2C devices found"); + else + Serial.println("done"); + + delay(5000); // wait 5 seconds for next scan +} \ No newline at end of file From 859a447ecfb74a4a2b173d05e8e956e23a8aa05a Mon Sep 17 00:00:00 2001 From: Cristi Marius Tiutiu Date: Tue, 1 Aug 2017 10:35:47 +0300 Subject: [PATCH 133/351] linux fix for gd32 variant in boards.txt --- STM32F1/boards.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/STM32F1/boards.txt b/STM32F1/boards.txt index 9cef207..b3eac90 100644 --- a/STM32F1/boards.txt +++ b/STM32F1/boards.txt @@ -931,7 +931,7 @@ hytiny-stm32f103t.menu.opt.ogstd.build.flags.ldspecs= ###################### Generic GD32F103C ######################################## genericGD32F103C.name=Generic GD32F103C series -genericGD32F103C.build.variant=generic_GD32f103c +genericGD32F103C.build.variant=generic_gd32f103c genericGD32F103C.build.vect=VECT_TAB_ADDR=0x8000000 genericGD32F103C.build.core=maple genericGD32F103C.build.board=GENERIC_GD32F103C @@ -1086,4 +1086,4 @@ STM32VLD.menu.opt.o3lto.build.flags.ldspecs=-flto STM32VLD.menu.opt.ogstd.build.flags.optimize=-Og STM32VLD.menu.opt.ogstd.build.flags.ldspecs= -################################################################################ \ No newline at end of file +################################################################################ From 0a9d06b5e5398588df747dcc8c5a5399cf0b157b Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Thu, 3 Aug 2017 09:28:14 +1000 Subject: [PATCH 134/351] Fix typo in dma.h (thanks to @stevestrong) --- STM32F1/system/libmaple/stm32f1/include/series/dma.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/system/libmaple/stm32f1/include/series/dma.h b/STM32F1/system/libmaple/stm32f1/include/series/dma.h index ff61857..56e559b 100644 --- a/STM32F1/system/libmaple/stm32f1/include/series/dma.h +++ b/STM32F1/system/libmaple/stm32f1/include/series/dma.h @@ -152,7 +152,7 @@ typedef struct dma_tube_reg_map { #define DMA_ISR_TEIF (1 << DMA_ISR_TEIF_BIT) #define DMA_ISR_HTIF (1 << DMA_ISR_HTIF_BIT) -#define DMA_ISR_TCID (1 << DMA_ISR_TCIF_BIT) +#define DMA_ISR_TCIF (1 << DMA_ISR_TCIF_BIT) #define DMA_ISR_GIF (1 << DMA_ISR_GIF_BIT) #define DMA_ISR_TEIF7_BIT 27 From 1ea988a57d0d5923967722e4cee092db496892c0 Mon Sep 17 00:00:00 2001 From: victorpv Date: Thu, 3 Aug 2017 11:47:15 -0500 Subject: [PATCH 135/351] Correcting FreeRTOS900 examples The examples were still including the 821 version of FreeRTOS, so changing them to include the right one. --- .../libraries/FreeRTOS900/examples/rtos_blink/rtos_blink.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/libraries/FreeRTOS900/examples/rtos_blink/rtos_blink.ino b/STM32F1/libraries/FreeRTOS900/examples/rtos_blink/rtos_blink.ino index a972b6c..935c629 100644 --- a/STM32F1/libraries/FreeRTOS900/examples/rtos_blink/rtos_blink.ino +++ b/STM32F1/libraries/FreeRTOS900/examples/rtos_blink/rtos_blink.ino @@ -1,6 +1,6 @@ //#include //#include "libraries/FreeRTOS/MapleFreeRTOS.h" -#include +#include static void vLEDFlashTask(void *pvParameters) { for (;;) { From db9a70c74f76195f2a365482475e373a78f25f56 Mon Sep 17 00:00:00 2001 From: victorpv Date: Thu, 3 Aug 2017 11:48:26 -0500 Subject: [PATCH 136/351] Correcting FreeRTOS900 example. --- .../examples/rtos_display_blink/rtos_display_blink.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/libraries/FreeRTOS900/examples/rtos_display_blink/rtos_display_blink.ino b/STM32F1/libraries/FreeRTOS900/examples/rtos_display_blink/rtos_display_blink.ino index bd6c3e4..7d92100 100644 --- a/STM32F1/libraries/FreeRTOS900/examples/rtos_display_blink/rtos_display_blink.ino +++ b/STM32F1/libraries/FreeRTOS900/examples/rtos_display_blink/rtos_display_blink.ino @@ -1,5 +1,5 @@ #define USE_SEMAPHORE_DMA1 -#include +#include #include #include #include From 8f7a0b6d5a47b70093a6f355f6ecf24e3e189f74 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Fri, 4 Aug 2017 20:34:48 +1000 Subject: [PATCH 137/351] Added pushColors() to ILI9341 library to better support the OV7670 camera --- .../Adafruit_ILI9341_STM.cpp | 17 +++++++++++++++++ .../Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.h | 1 + 2 files changed, 18 insertions(+) diff --git a/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.cpp b/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.cpp index db57b3e..766b910 100644 --- a/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.cpp +++ b/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.cpp @@ -386,6 +386,23 @@ void Adafruit_ILI9341_STM::pushColor(uint16_t color) { if (hwSPI) spi_end(); } +void Adafruit_ILI9341_STM::pushColors(void * colorBuffer, uint16_t nr_pixels, uint8_t async) +{ + *dcport |= dcpinmask; + *csport &= ~cspinmask; + + if (async==0) + { + SPI.dmaSend(colorBuffer, nr_pixels, 1); + *csport |= cspinmask; + } + else + { + SPI.dmaSendAsync(colorBuffer, nr_pixels, 1); + } + +} + void Adafruit_ILI9341_STM::drawPixel(int16_t x, int16_t y, uint16_t color) { if ((x < 0) || (x >= _width) || (y < 0) || (y >= _height)) return; diff --git a/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.h b/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.h index 137b7a4..7ee395c 100644 --- a/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.h +++ b/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.h @@ -107,6 +107,7 @@ class Adafruit_ILI9341_STM : public Adafruit_GFX { void begin(void), setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1), pushColor(uint16_t color), + pushColors(void * colorBuffer, uint16_t nr_pixels, uint8_t async), fillScreen(uint16_t color), #if defined (__STM32F1__) drawLine(int16_t x0, int16_t y0,int16_t x1, int16_t y1, uint16_t color), From 33411b6e946dc0fc71420420f847c6bac6ce2aad Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Sun, 6 Aug 2017 21:04:02 +1000 Subject: [PATCH 138/351] Default Wire to 100khz --- STM32F1/libraries/Wire/Wire.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/libraries/Wire/Wire.cpp b/STM32F1/libraries/Wire/Wire.cpp index d8252c1..c4e9bef 100644 --- a/STM32F1/libraries/Wire/Wire.cpp +++ b/STM32F1/libraries/Wire/Wire.cpp @@ -100,4 +100,4 @@ void HardWire::setClock(uint32_t frequencyHz) } -HardWire Wire(1, I2C_FAST_MODE);; +HardWire Wire(1); From a9767e4c535e28ecf781f98fc8fbc85e134b406c Mon Sep 17 00:00:00 2001 From: victorpv Date: Fri, 18 Aug 2017 17:33:00 -0500 Subject: [PATCH 139/351] Adding new.cpp as in F1 core. This is to avoid libstdc++ being pulled in when new() is used. Already included in the F1 in 2016. Discussed on this thread: http://www.stm32duino.com/viewtopic.php?f=39&t=2460&p=33163 --- STM32F4/cores/maple/new.cpp | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 STM32F4/cores/maple/new.cpp diff --git a/STM32F4/cores/maple/new.cpp b/STM32F4/cores/maple/new.cpp new file mode 100644 index 0000000..7553ddf --- /dev/null +++ b/STM32F4/cores/maple/new.cpp @@ -0,0 +1,35 @@ +/* + Copyright (c) 2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +void *operator new(size_t size) { + return malloc(size); +} + +void *operator new[](size_t size) { + return malloc(size); +} + +void operator delete(void * ptr) { + free(ptr); +} + +void operator delete[](void * ptr) { + free(ptr); +} From 71d5ab9112ab0c28e2c216a31b3a3ff05d0b1d37 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Fri, 25 Aug 2017 18:33:04 +1000 Subject: [PATCH 140/351] Wire lib change buffer size definition to BUFFER_LENGTH for better AVR compatibility --- STM32F1/libraries/Wire/SoftWire.h | 2 +- STM32F1/libraries/Wire/WireBase.cpp | 6 +++--- STM32F1/libraries/Wire/WireBase.h | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/STM32F1/libraries/Wire/SoftWire.h b/STM32F1/libraries/Wire/SoftWire.h index 0804c0f..136dc3d 100644 --- a/STM32F1/libraries/Wire/SoftWire.h +++ b/STM32F1/libraries/Wire/SoftWire.h @@ -57,7 +57,7 @@ //#define I2C_DELAY(x) {uint32 time=micros(); while(time>(micros()+x));} #define I2C_DELAY(x) do{for(int i=0;i WIRE_BUFSIZ) { - num_bytes = WIRE_BUFSIZ; + if (num_bytes > BUFFER_LENGTH) { + num_bytes = BUFFER_LENGTH; } itc_msg.addr = address; itc_msg.flags = I2C_MSG_READ; @@ -96,7 +96,7 @@ uint8 WireBase::requestFrom(int address, int numBytes) { } void WireBase::write(uint8 value) { - if (tx_buf_idx == WIRE_BUFSIZ) { + if (tx_buf_idx == BUFFER_LENGTH) { tx_buf_overflow = true; return; } diff --git a/STM32F1/libraries/Wire/WireBase.h b/STM32F1/libraries/Wire/WireBase.h index 5e51ab7..72facde 100644 --- a/STM32F1/libraries/Wire/WireBase.h +++ b/STM32F1/libraries/Wire/WireBase.h @@ -44,7 +44,7 @@ #include "wirish.h" #include -#define WIRE_BUFSIZ 32 +#define BUFFER_LENGTH 32 /* return codes from endTransmission() */ #define SUCCESS 0 /* transmission was successful */ @@ -56,11 +56,11 @@ class WireBase { // Abstraction is awesome! protected: i2c_msg itc_msg; - uint8 rx_buf[WIRE_BUFSIZ]; /* receive buffer */ + uint8 rx_buf[BUFFER_LENGTH]; /* receive buffer */ uint8 rx_buf_idx; /* first unread idx in rx_buf */ uint8 rx_buf_len; /* number of bytes read */ - uint8 tx_buf[WIRE_BUFSIZ]; /* transmit buffer */ + uint8 tx_buf[BUFFER_LENGTH]; /* transmit buffer */ uint8 tx_buf_idx; // next idx available in tx_buf, -1 overflow boolean tx_buf_overflow; From 5058d8f5838b8b5b63ba21f0ea950585d849a4d3 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Sat, 26 Aug 2017 14:37:40 +1000 Subject: [PATCH 141/351] Removed support for GD32 - by removing entry from boards.txt --- STM32F1/boards.txt | 91 ---------------------------------------------- 1 file changed, 91 deletions(-) diff --git a/STM32F1/boards.txt b/STM32F1/boards.txt index b3eac90..6d110d0 100644 --- a/STM32F1/boards.txt +++ b/STM32F1/boards.txt @@ -928,97 +928,6 @@ hytiny-stm32f103t.menu.opt.o3lto.build.flags.ldspecs=-flto hytiny-stm32f103t.menu.opt.ogstd.build.flags.optimize=-Og hytiny-stm32f103t.menu.opt.ogstd.build.flags.ldspecs= -###################### Generic GD32F103C ######################################## - -genericGD32F103C.name=Generic GD32F103C series -genericGD32F103C.build.variant=generic_gd32f103c -genericGD32F103C.build.vect=VECT_TAB_ADDR=0x8000000 -genericGD32F103C.build.core=maple -genericGD32F103C.build.board=GENERIC_GD32F103C -genericGD32F103C.upload.use_1200bps_touch=false -genericGD32F103C.upload.file_type=bin -genericGD32F103C.upload.auto_reset=true -genericGD32F103C.build.cpu_flags=-DMCU_STM32F103CB -genericGD32F103C.build.f_cpu=72000000L - -## GD32F103C8 ------------------------- -genericGD32F103C.menu.device_variant.GD32F103C8=GD32F103C8 (20k RAM. 64k Flash) -genericGD32F103C.menu.device_variant.GD32F103C8.build.ldscript=ld/jtag_c8.ld -genericGD32F103C.menu.device_variant.GD32F103C8.upload.maximum_size=65536 -genericGD32F103C.menu.device_variant.GD32F103C8.upload.maximum_data_size=20480 - -## GD32F103CB ------------------------- -genericGD32F103C.menu.device_variant.GD32F103CB=GD32F103CB (20k RAM. 128k Flash) -genericGD32F103C.menu.device_variant.GD32F103CB.build.ldscript=ld/jtag.ld -genericGD32F103C.menu.device_variant.GD32F103CB.upload.maximum_size=131072 -genericGD32F103C.menu.device_variant.GD32F103CB.upload.maximum_data_size=20480 - -#---------------------------- UPLOAD METHODS --------------------------- - -genericGD32F103C.menu.upload_method.DFUUploadMethod=GD32duino bootloader - -genericGD32F103C.menu.upload_method.DFUUploadMethod.upload.protocol=maple_dfu -genericGD32F103C.menu.upload_method.DFUUploadMethod.upload.tool=maple_upload -genericGD32F103C.menu.upload_method.DFUUploadMethod.build.upload_flags=-DSERIAL_USB -DGENERIC_BOOTLOADER -genericGD32F103C.menu.upload_method.DFUUploadMethod.build.vect=VECT_TAB_ADDR=0x8002000 -genericGD32F103C.menu.upload_method.DFUUploadMethod.build.ldscript=ld/bootloader_20.ld -genericGD32F103C.menu.upload_method.DFUUploadMethod.upload.usbID=1EAF:0003 -genericGD32F103C.menu.upload_method.DFUUploadMethod.upload.altID=2 - -genericGD32F103C.menu.upload_method.serialMethod=Serial -genericGD32F103C.menu.upload_method.serialMethod.upload.protocol=maple_serial -genericGD32F103C.menu.upload_method.serialMethod.upload.tool=serial_upload -genericGD32F103C.menu.upload_method.serialMethod.build.upload_flags=-DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG=1 - -genericGD32F103C.menu.upload_method.STLinkMethod=STLink -genericGD32F103C.menu.upload_method.STLinkMethod.upload.protocol=STLink -genericGD32F103C.menu.upload_method.STLinkMethod.upload.tool=stlink_upload -genericGD32F103C.menu.upload_method.STLinkMethod.build.upload_flags=-DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG=1 -DSERIAL_USB -DGENERIC_BOOTLOADER - - -genericGD32F103C.menu.upload_method.BMPMethod=BMP (Black Magic Probe) -genericGD32F103C.menu.upload_method.BMPMethod.upload.protocol=gdb_bmp -genericGD32F103C.menu.upload_method.BMPMethod.upload.tool=bmp_upload -genericGD32F103C.menu.upload_method.BMPMethod.build.upload_flags=-DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG - -genericGD32F103C.menu.cpu_speed.speed_120mhz=120Mhz (overdrive) -genericGD32F103C.menu.cpu_speed.speed_120mhz.build.f_cpu=120000000L - -genericGD32F103C.menu.cpu_speed.speed_96mhz=96Mhz (Stable) -genericGD32F103C.menu.cpu_speed.speed_96mhz.build.f_cpu=96000000L - -genericGD32F103C.menu.cpu_speed.speed_72mhz=72Mhz (compatibility) -genericGD32F103C.menu.cpu_speed.speed_72mhz.build.f_cpu=72000000L - -#-- Optimizations -genericGD32F103C.menu.opt.osstd=Smallest (default) -genericGD32F103C.menu.opt.osstd.build.flags.optimize=-Os -genericGD32F103C.menu.opt.osstd.build.flags.ldspecs= -genericGD32F103C.menu.opt.oslto=Smallest Code with LTO -genericGD32F103C.menu.opt.oslto.build.flags.optimize=-Os -flto -genericGD32F103C.menu.opt.oslto.build.flags.ldspecs=-flto -genericGD32F103C.menu.opt.o1std=Fast (-O1) -genericGD32F103C.menu.opt.o1std.build.flags.optimize=-O1 -genericGD32F103C.menu.opt.o1std.build.flags.ldspecs= -genericGD32F103C.menu.opt.o1lto=Fast (-O1) with LTO -genericGD32F103C.menu.opt.o1lto.build.flags.optimize=-O1 -flto -genericGD32F103C.menu.opt.o1lto.build.flags.ldspecs=-flto -genericGD32F103C.menu.opt.o2std=Faster (-O2) -genericGD32F103C.menu.opt.o2std.build.flags.optimize=-O2 -genericGD32F103C.menu.opt.o2std.build.flags.ldspecs= -genericGD32F103C.menu.opt.o2lto=Faster (-O2) with LTO -genericGD32F103C.menu.opt.o2lto.build.flags.optimize=-O2 -flto -genericGD32F103C.menu.opt.o2lto.build.flags.ldspecs=-flto -genericGD32F103C.menu.opt.o3std=Fastest (-O3) -genericGD32F103C.menu.opt.o3std.build.flags.optimize=-O3 -genericGD32F103C.menu.opt.o3std.build.flags.ldspecs= -genericGD32F103C.menu.opt.o3lto=Fastest (-O3) with LTO -genericGD32F103C.menu.opt.o3lto.build.flags.optimize=-O3 -flto -genericGD32F103C.menu.opt.ogstd=Debug (-g) -genericGD32F103C.menu.opt.o3lto.build.flags.ldspecs=-flto -genericGD32F103C.menu.opt.ogstd.build.flags.optimize=-Og -genericGD32F103C.menu.opt.ogstd.build.flags.ldspecs= - ########################### STM32VLD to FLASH ########################### STM32VLD.name=STM32VLD to FLASH From 47c94bc10ca54c8394f0ff800d6a88a4f90ace22 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Sat, 26 Aug 2017 20:34:43 +1000 Subject: [PATCH 142/351] Update Arduino IDE version in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4ffc9ed..9d167cf 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Use of these files is at your own risk. ## Summary: -This repo contains, the "Hardware" files to support STM32 based boards on Arduino version 1.6.13 or 1.6.12 (some older versions may also work) including [LeafLabs Maple, and Maple mini](http://www.leaflabs.com/about-maple/), and other generic STM32F103 boards +This repo contains, the "Hardware" files to support STM32 based boards on Arduino version 1.8.x (some older versions may also work) including [LeafLabs Maple, and Maple mini](http://www.leaflabs.com/about-maple/), and other generic STM32F103 boards ***PRIMARY SUPPORT FORUM: http://www.stm32duino.com/*** From e6ed2d5cccff1cf6ca4bd98ec42b4d02377587f3 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Tue, 29 Aug 2017 11:16:43 +0200 Subject: [PATCH 143/351] Update RTClock.cpp bugfix setAlarmATime - corrected day variable --- STM32F4/libraries/RTClock/src/RTClock.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F4/libraries/RTClock/src/RTClock.cpp b/STM32F4/libraries/RTClock/src/RTClock.cpp index e7c2ca8..a6ef9f1 100644 --- a/STM32F4/libraries/RTClock/src/RTClock.cpp +++ b/STM32F4/libraries/RTClock/src/RTClock.cpp @@ -281,7 +281,7 @@ void RTClock::setAlarmATime (tm_t * tm_ptr, bool hours_match, bool mins_match, b { uint32 t = 0; rtc_enter_config_mode(); - unsigned int bits = ((tm_ptr->day / 10) << 28) | ((tm.day % 10) << 24) | + unsigned int bits = ((tm_ptr->day / 10) << 28) | ((tm_ptr->day % 10) << 24) | ((tm_ptr->hour / 10) << 20) | ((tm_ptr->hour % 10) << 16) | ((tm_ptr->minute / 10) << 12) | ((tm_ptr->minute % 10) << 8) | ((tm_ptr->second / 10) << 4) | (tm_ptr->second % 10); From fbe6264003935b48cf12ff1790d0c11f3342edd6 Mon Sep 17 00:00:00 2001 From: csnol Date: Tue, 29 Aug 2017 10:07:42 -0500 Subject: [PATCH 144/351] Rewrite the RTClock library. --- STM32F1/libraries/RTClock/src/RTClock.cpp | 114 +++++++++++++++++++--- STM32F1/libraries/RTClock/src/RTClock.h | 65 ++++++++++-- 2 files changed, 158 insertions(+), 21 deletions(-) diff --git a/STM32F1/libraries/RTClock/src/RTClock.cpp b/STM32F1/libraries/RTClock/src/RTClock.cpp index 869e152..f2f8501 100644 --- a/STM32F1/libraries/RTClock/src/RTClock.cpp +++ b/STM32F1/libraries/RTClock/src/RTClock.cpp @@ -81,21 +81,108 @@ */ void RTClock::setTime (time_t time_stamp) { - rtc_set_count(time_stamp); + breakTime(time_stamp, tmm); // time will be broken to tm + setTime(tmm); + //rtc_set_count(time_stamp); } - void RTClock::setTime (struct tm* tm_ptr) { - rtc_set_count(mktime (tm_ptr)); - } + #define LEAP_YEAR(Y) ( ((1970+Y)>0) && !((1970+Y)%4) && ( ((1970+Y)%100) || !((1970+Y)%400) ) ) + //----------------------------------------------------------------------------- +void RTClock::breakTime(time_t timeInput, tm_t & tmm) +{ +// break the given time_t into time components +// this is a more compact version of the C library localtime function +// note that year is offset from 1970 !!! + + uint8_t year; + uint8_t month, monthLength; + uint32_t time; + uint32_t days; + + time = (uint32_t)timeInput; + tmm.second = time % 60; + time /= 60; // now it is minutes + tmm.minute = time % 60; + time /= 60; // now it is hours + tmm.hour = time % 24; + time /= 24; // now it is days + tmm.weekday = ((time + 4) % 7); // Monday is day 1 // + 1; // Sunday is day 1 + + year = 0; + days = 0; + while((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= time) { + year++; + } + tmm.year = year; // year is offset from 1970 + + days -= LEAP_YEAR(year) ? 366 : 365; + time -= days; // now it is days in this year, starting at 0 + + days = 0; + month = 0; + monthLength = 0; + for (month=0; month<12; month++) { + if (month==1) { // february + if (LEAP_YEAR(year)) { + monthLength=29; + } else { + monthLength=28; + } + } else { + monthLength = monthDays[month]; + } + + if (time >= monthLength) { + time -= monthLength; + } else { + break; + } + } + tmm.month = month + 1; // jan is month 1 + tmm.day = time + 1; // day of month +} + +//----------------------------------------------------------------------------- +time_t RTClock::makeTime(tm_t & tmm) +{ +// assemble time elements into time_t +// note year argument is offset from 1970 (see macros in time.h to convert to other formats) +// previous version used full four digit year (or digits since 2000),i.e. 2009 was 2009 or 9 + + int i; + uint32_t seconds; + + // seconds from 1970 till 1 jan 00:00:00 of the given year + seconds = tmm.year*(SECS_PER_DAY * 365); + for (i = 0; i < tmm.year; i++) { + if (LEAP_YEAR(i)) { + seconds += SECS_PER_DAY; // add extra days for leap years + } + } + + // add days for this year, months start from 1 + for (i = 1; i < tmm.month; i++) { + if ( (i == 2) && LEAP_YEAR(tmm.year)) { + seconds += SECS_PER_DAY * 29; + } else { + seconds += SECS_PER_DAY * monthDays[i-1]; //monthDay array starts from 0 + } + } + seconds+= (tmm.day-1) * SECS_PER_DAY; + seconds+= tmm.hour * SECS_PER_HOUR; + seconds+= tmm.minute * SECS_PER_MIN; + seconds+= tmm.second; + return (time_t)seconds; +} + time_t RTClock::getTime() { return rtc_get_count(); } - - struct tm* RTClock::getTime(struct tm* tm_ptr) { + + void RTClock::getTime(tm_t & tm_ptr) { time_t res = rtc_get_count(); - tm_ptr = gmtime(&res); //why not gmtime? - return tm_ptr; + breakTime(res, tm_ptr); } void RTClock::createAlarm(voidFuncPtr function, time_t alarm_time_t) { @@ -110,15 +197,16 @@ rtc_detach_interrupt(RTC_SECONDS_INTERRUPT); } - - void RTClock::createAlarm(voidFuncPtr function, tm* alarm_tm) { - time_t alarm = mktime(alarm_tm);//convert to time_t + + void RTClock::createAlarm(voidFuncPtr function, tm_t & alarm_tm) { + time_t alarm = makeTime(alarm_tm);//convert to time_t createAlarm(function, alarm); } //change alarm time - void RTClock::setAlarmTime (tm * tm_ptr) { - time_t time = mktime(tm_ptr);//convert to time_t + + void RTClock::setAlarmTime (tm_t & tm_ptr) { + time_t time = makeTime(tm_ptr);//convert to time_t rtc_set_alarm(time); //must be int... for standardization sake. } diff --git a/STM32F1/libraries/RTClock/src/RTClock.h b/STM32F1/libraries/RTClock/src/RTClock.h index 443a30b..711992e 100644 --- a/STM32F1/libraries/RTClock/src/RTClock.h +++ b/STM32F1/libraries/RTClock/src/RTClock.h @@ -7,9 +7,35 @@ #ifndef _RTCLOCK_H_ #define _RTCLOCK_H_ +#define SECS_PER_MIN (60UL) +#define SECS_PER_HOUR (3600UL) +#define SECS_PER_DAY (SECS_PER_HOUR * 24UL) +#define DAYS_PER_WEEK (7UL) +#define SECS_PER_WEEK (SECS_PER_DAY * DAYS_PER_WEEK) +#define SECS_PER_YEAR (SECS_PER_WEEK * 52UL) +#define SECS_YR_2000 (946684800UL) // the time at the start of y2k +#define LEAP_YEAR(Y) ( ((1970+Y)>0) && !((1970+Y)%4) && ( ((1970+Y)%100) || !((1970+Y)%400) ) ) +#if !defined(__time_t_defined) // avoid conflict with newlib or other posix libc + #warning "Using private time_t definintion" + typedef uint32_t time_t; +#endif +static const unsigned char monthDays[]={31,28,31,30,31,30,31,31,30,31,30,31}; // API starts months from 1, this array starts from 0 +typedef struct tm_t { + uint8_t year; // years since 1970 + uint8_t month; // month of a year - [ 1 to 12 ] + uint8_t day; // day of a month - [ 1 to 31 ] + uint8_t weekday; // day of a week (first day is Sunday) - [ 0 to 6 ] + uint8_t pm; // AM: 0, PM: 1 + uint8_t hour; // hour of a day - [ 0 to 23 ] + uint8_t minute; // minute of an hour - [ 0 to 59 ] + uint8_t second; // second of a minute - [ 0 to 59 ] +} tm_t; + +static inline uint8_t bcd2bin(uint8_t b) { return ( (10*(b>>4)) + (b&0x0F) ); } +static inline uint8_t bin2bcd(uint8_t b) { return ( ((b/10)<<4) + (b%10) ); } class RTClock { public: @@ -18,24 +44,47 @@ class RTClock { RTClock(rtc_clk_src src, uint16 prescaler ); //~RTClock(); //to implement - - void setTime (time_t time_stamp); - void setTime (struct tm * tm_ptr); + void breakTime(time_t epoch_time, tm_t & tmm); + time_t makeTime(tm_t & tmm); + + void setTime (time_t time_stamp); + void setTime (tm_t & tmm); - struct tm* getTime(struct tm* tm_ptr); time_t getTime(); + void getTime(tm_t & tmm ); + #define now getTime + + uint8_t year(void) { getTime(tmm); return tmm.year; } + uint8_t month(void) { getTime(tmm); return tmm.month; } + uint8_t day(void) { getTime(tmm); return tmm.day; } + uint8_t weekday(void) { getTime(tmm); return tmm.weekday; } + uint8_t hour(void) { getTime(tmm); return tmm.hour; } + uint8_t minute(void) { getTime(tmm); return tmm.minute; } + uint8_t second(void) { getTime(tmm); return tmm.second; } + uint8_t isPM(void) { return ( hour()>=12 ); } + + uint8_t year(time_t t) { breakTime(t, tmm); return tmm.year; } + uint8_t month(time_t t) { breakTime(t, tmm); return tmm.month; } + uint8_t day(time_t t) { breakTime(t, tmm); return tmm.day; } + uint8_t weekday(time_t t) { breakTime(t, tmm); return tmm.weekday; } + uint8_t hour(time_t t) { breakTime(t, tmm); return tmm.hour; } + uint8_t minute(time_t t) { breakTime(t, tmm); return tmm.minute; } + uint8_t second(time_t t) { breakTime(t, tmm); return tmm.second; } + uint8_t isPM(time_t t) { return (hour(t)>=12); } void createAlarm(voidFuncPtr function, time_t alarm_time_t); - void createAlarm(voidFuncPtr function, struct tm* alarm_tm); + void createAlarm(voidFuncPtr function, struct tm_t & alarm_tm); void attachSecondsInterrupt(voidFuncPtr function); void detachSecondsInterrupt(); - void setAlarmTime (tm * tm_ptr); + void setAlarmTime (tm_t & tm_ptr); void setAlarmTime (time_t alarm_time); - //private: + + + tm_t tmm; +}; -} ; From 27f8e127a4d9bdd5c77c026088a3655b9e57f95a Mon Sep 17 00:00:00 2001 From: csnol Date: Tue, 29 Aug 2017 23:13:02 +0800 Subject: [PATCH 145/351] Create a RTC example for new library. --- .../examples/RTC-Serial-Set-Newlibrary.ino | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 STM32F1/libraries/RTClock/examples/RTC-Serial-Set-Newlibrary.ino diff --git a/STM32F1/libraries/RTClock/examples/RTC-Serial-Set-Newlibrary.ino b/STM32F1/libraries/RTClock/examples/RTC-Serial-Set-Newlibrary.ino new file mode 100644 index 0000000..ba89a4e --- /dev/null +++ b/STM32F1/libraries/RTClock/examples/RTC-Serial-Set-Newlibrary.ino @@ -0,0 +1,80 @@ +/* STM32F103C8 Black Pill ( PB12) + + Serialport set and display RTC clock , Write by CSNOL https://github.com/csnol/STM32-Examples + based on https://github.com/rogerclarkmelbourne/Arduino_STM32 + + 1. Blink on PB12 per 1s. + 2. change to your timezone in the sketch; . + 3. get Unix epoch time from https://www.epochconverter.com/ ; + 4. last step input the 10 bits number( example: 1503945555) to Serialport ; + 5. the clock will be reset to you wanted. + + ## Why the 10 bits Unix epoch time be used? +****Because I wanna connect to NTP server by ESP-8266. +****in the library. getNtpTime() will return this 10 bits Unix epoch time. +*/ + + +#include + +RTClock rtclock (RTCSEL_LSE); // initialise +time_t tt; +tm_t mtt = { 47, 8, 27, 0, 1, 20, 30, 30 }; +char weekday1[][7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; // 0,1,2,3,4,5,6 +uint8_t timeread[11]; +int timezone = 8 * 3600; // timezone -8 + DST +1 = -7 CA USA +time_t tt1; + +#define LED_PIN PB12 + +// This function is called in the attachSecondsInterrpt +void blink () +{ + digitalWrite(LED_PIN, !digitalRead(LED_PIN)); + tt++; +} + +void setup() +{ + Serial.begin(115200); + pinMode(LED_PIN, OUTPUT); + tt = rtclock.makeTime(mtt); + tt1 = tt; + rtclock.attachSecondsInterrupt(blink);// Call blink +} + + +int i = 0; +void loop() +{ + while (Serial.available()) + { timeread[i] = Serial.read(); + if (i < 11) { + i++; + } + else { + i = 0; + tt = (timeread[0] - '0') * 1000000000 + (timeread[1] - '0') * 100000000 + (timeread[2] - '0') * 10000000 + (timeread[3] - '0') * 1000000 + (timeread[4] - '0') * 100000; + tt += (timeread[5] - '0') * 10000 + (timeread[6] - '0') * 1000 + (timeread[7] - '0') * 100 + (timeread[8] - '0') * 10 + (timeread[9] - '0') + timezone; + } + } + if (tt1 != tt) + { + tt1 = tt; + rtclock.breakTime(tt, mtt); + Serial.print("Date: "); + Serial.print(mtt.day); + Serial.print("- "); + Serial.print(mtt.month); + Serial.print(" "); + Serial.print(mtt.year + 1970); + Serial.print(" "); + Serial.print(weekday1[mtt.weekday]); + Serial.print(" Time: "); + Serial.print(mtt.hour); + Serial.print(" : "); + Serial.print(mtt.minute); + Serial.print(" : "); + Serial.println(mtt.second); + } +} From 6e92ddd8bc0a723359a52d86a3cd004be178385d Mon Sep 17 00:00:00 2001 From: csnol Date: Tue, 29 Aug 2017 10:30:27 -0500 Subject: [PATCH 146/351] Add STM32F103-RTC-Serial-Set.jpg --- .../examples/STM32F103-RTC-Serial-Set.jpg | Bin 0 -> 131470 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 STM32F1/libraries/RTClock/examples/STM32F103-RTC-Serial-Set.jpg diff --git a/STM32F1/libraries/RTClock/examples/STM32F103-RTC-Serial-Set.jpg b/STM32F1/libraries/RTClock/examples/STM32F103-RTC-Serial-Set.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b2e701ea9e4789dd48ad0bbfe2c93534d7c61c19 GIT binary patch literal 131470 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 AO$pHf*yADG%HUemy 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%0ACJfMVz1%{y?hP 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 literal 0 HcmV?d00001 From 6c0be70f2efa2706e8ad0eb617dcb9226c0d335e Mon Sep 17 00:00:00 2001 From: csnol Date: Wed, 30 Aug 2017 23:28:01 +0800 Subject: [PATCH 147/351] Update RTClock.cpp --- STM32F1/libraries/RTClock/src/RTClock.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/STM32F1/libraries/RTClock/src/RTClock.cpp b/STM32F1/libraries/RTClock/src/RTClock.cpp index f2f8501..5baaa40 100644 --- a/STM32F1/libraries/RTClock/src/RTClock.cpp +++ b/STM32F1/libraries/RTClock/src/RTClock.cpp @@ -81,12 +81,16 @@ */ void RTClock::setTime (time_t time_stamp) { - breakTime(time_stamp, tmm); // time will be broken to tm - setTime(tmm); + breakTime(time_stamp, tmm); // time will be broken to tmm + setTime(tmm); //rtc_set_count(time_stamp); } - #define LEAP_YEAR(Y) ( ((1970+Y)>0) && !((1970+Y)%4) && ( ((1970+Y)%100) || !((1970+Y)%400) ) ) + void RTClock::setTime (time_t time_stamp) { + rtc_set_count(time_stamp); + } + +#define LEAP_YEAR(Y) ( ((1970+Y)>0) && !((1970+Y)%4) && ( ((1970+Y)%100) || !((1970+Y)%400) ) ) //----------------------------------------------------------------------------- void RTClock::breakTime(time_t timeInput, tm_t & tmm) From d53cacdb1ec2298382fec602164562690e815eec Mon Sep 17 00:00:00 2001 From: csnol Date: Wed, 30 Aug 2017 23:37:41 +0800 Subject: [PATCH 148/351] Update RTClock.cpp --- STM32F1/libraries/RTClock/src/RTClock.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/STM32F1/libraries/RTClock/src/RTClock.cpp b/STM32F1/libraries/RTClock/src/RTClock.cpp index 5baaa40..cc7b63e 100644 --- a/STM32F1/libraries/RTClock/src/RTClock.cpp +++ b/STM32F1/libraries/RTClock/src/RTClock.cpp @@ -80,9 +80,9 @@ } */ - void RTClock::setTime (time_t time_stamp) { - breakTime(time_stamp, tmm); // time will be broken to tmm - setTime(tmm); + void RTClock::setTime (tm_t & tmm) { + time_t mktm = makeTime(tmm); // time will be make to mktm + setTime(mktm); //rtc_set_count(time_stamp); } From f12bad6790eff27e7f107ca689298473153fdf49 Mon Sep 17 00:00:00 2001 From: Jan Chrillesen Date: Thu, 31 Aug 2017 20:54:29 +0200 Subject: [PATCH 149/351] add JLink upload support for OSX --- tools/macosx/jlink_upload | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100755 tools/macosx/jlink_upload diff --git a/tools/macosx/jlink_upload b/tools/macosx/jlink_upload new file mode 100755 index 0000000..a9e9810 --- /dev/null +++ b/tools/macosx/jlink_upload @@ -0,0 +1,9 @@ +#!/bin/bash + +echo erase > "$1".jlink +echo loadbin "$1" , 0x8000000 >> "$1".jlink +echo r >> "$1".jlink +echo q >> "$1".jlink + +/Applications/SEGGER/JLink/JLinkExe -device STM32F103C8 -if SWD -speed auto -CommanderScript "$1".jlink + From 58e50e7fd9062e45ec23d575a16cd411522c37cb Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Sun, 3 Sep 2017 10:51:08 +1000 Subject: [PATCH 150/351] Add partial support for a DFU bootloader for the F4 --- STM32F4/boards.txt | 26 ++++++++++++++++++- STM32F4/cores/maple/libmaple/libmaple.h | 2 ++ STM32F4/platform.txt | 10 +++---- .../generic_f407v/ld/bootloader_8004000.ld | 21 +++++++++++++++ 4 files changed, 53 insertions(+), 6 deletions(-) create mode 100644 STM32F4/variants/generic_f407v/ld/bootloader_8004000.ld diff --git a/STM32F4/boards.txt b/STM32F4/boards.txt index abc40f0..907e6f7 100644 --- a/STM32F4/boards.txt +++ b/STM32F4/boards.txt @@ -2,6 +2,7 @@ menu.usb_cfg=USB configuration menu.opt=Optimize +menu.upload_method=Upload method ############################################################## discovery_f407.name=STM32 Discovery F407 @@ -30,6 +31,7 @@ discovery_f407.build.density=STM32_HIGH_DENSITY discovery_f407.build.error_led_port=GPIOD discovery_f407.build.error_led_pin=14 discovery_f407.build.board=STM32DiscoveryF407 +discovery_f407.build.vect_flags=-DVECT_TAB_FLASH -DUSER_ADDR_ROM=(uint32)0x08000000 discovery_f407.menu.usb_cfg.usb_nc=USB inactive discovery_f407.menu.usb_cfg.usb_nc.build.cpu_flags=-DUSB_NC @@ -92,16 +94,37 @@ generic_f407v.build.density=STM32_HIGH_DENSITY generic_f407v.build.error_led_port=GPIOA generic_f407v.build.error_led_pin=7 generic_f407v.build.board=STM32GenericF407VET6 +generic_f407v.build.vect_flags=-DVECT_TAB_FLASH -DUSER_ADDR_ROM=(uint32)0x08000000 generic_f407v.menu.usb_cfg.usb_nc=USB inactive generic_f407v.menu.usb_cfg.usb_nc.build.cpu_flags=-DUSB_NC generic_f407v.menu.usb_cfg.usb_serial=USB serial (CDC) generic_f407v.menu.usb_cfg.usb_serial.build.cpu_flags=-DSERIAL_USB - generic_f407v.menu.usb_cfg.usb_msc=USB Mass Storage (MSC) generic_f407v.menu.usb_cfg.usb_msc.build.cpu_flags=-DUSB_MSC +#note STLink is the default from the main block of config above, so does not need settings for everything +generic_f407v.menu.upload_method.STLinkMethod=STLink +generic_f407v.menu.upload_method.STLinkMethod.upload.protocol=STLink +generic_f407v.menu.upload_method.STLinkMethod.upload.tool=stlink_upload +generic_f407v.menu.upload_method.STLinkMethod.upload.dfuse_addr=0x08004000 +generic_f407v.menu.upload_method.STLinkMethod.build.vect_flags=-DVECT_TAB_FLASH -DUSER_ADDR_ROM=(uint32)0x08000000 + + +generic_f407v.menu.upload_method.DFUUploadMethod=STM32duino bootloader +generic_f407v.menu.upload_method.DFUUploadMethod.upload.protocol=maple_dfu +generic_f407v.menu.upload_method.DFUUploadMethod.upload.tool=maple_upload +generic_f407v.menu.upload_method.DFUUploadMethod.build.vect_flags=-DVECT_TAB_FLASH -DUSER_ADDR_ROM=(uint32)0x08004000 +generic_f407v.menu.upload_method.DFUUploadMethod.build.ldscript=ld/bootloader_8004000.ld +generic_f407v.menu.upload_method.DFUUploadMethod.upload.usbID=1EAF:0003 +generic_f407v.menu.upload_method.DFUUploadMethod.upload.altID=2 + + + + + + #-- Optimizations generic_f407v.menu.opt.osstd=Smallest (default) generic_f407v.menu.opt.osstd.build.flags.optimize=-Os @@ -158,6 +181,7 @@ stm32f4stamp.build.density=STM32_HIGH_DENSITY stm32f4stamp.build.error_led_port=GPIOD stm32f4stamp.build.error_led_pin=14 stm32f4stamp.build.board=STM32F4StampF405 +stm32f4stamp.build.vect_flags=-DVECT_TAB_FLASH -DUSER_ADDR_ROM=(uint32)0x08000000 stm32f4stamp.menu.usb_cfg.usb_nc=USB inactive stm32f4stamp.menu.usb_cfg.usb_nc.build.cpu_flags=-DUSB_NC diff --git a/STM32F4/cores/maple/libmaple/libmaple.h b/STM32F4/cores/maple/libmaple/libmaple.h index 8360ba3..2ec0b28 100644 --- a/STM32F4/cores/maple/libmaple/libmaple.h +++ b/STM32F4/cores/maple/libmaple/libmaple.h @@ -47,7 +47,9 @@ #define STACK_TOP 0x20000800 #elif defined(BOARD_freeflight) */ +#ifndef USER_ADDR_ROM #define USER_ADDR_ROM 0x08000000 +#endif #define USER_ADDR_RAM 0x20000C00 #define STACK_TOP 0x20000800 /* diff --git a/STM32F4/platform.txt b/STM32F4/platform.txt index 92dc1ea..d115210 100755 --- a/STM32F4/platform.txt +++ b/STM32F4/platform.txt @@ -10,13 +10,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 {build.flags.optimize} -Wall -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.flags=-c -g {build.flags.optimize} -Wall -MMD -std=gnu11 -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 -DBOARD_{build.variant} {build.vect_flags} -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={build.flags.optimize} -Wl,--gc-sections {build.flags.ldspecs} 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 {build.flags.optimize} -Wall -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.cpp.flags=-c -g {build.flags.optimize} -Wall -MMD -std=gnu++11 -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 -fno-rtti -fno-exceptions -DBOARD_{build.variant} {build.vect_flags} -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 @@ -64,13 +64,13 @@ compiler.libs.c.flags="-I{build.system.path}/libmaple" "-I{build.core.path}/libm # --------------------- ## Compile c files -recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.flags} -mcpu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.c.extra_flags} {build.extra_flags} {build.cpu_flags} {compiler.libs.c.flags} {includes} "{source_file}" -o "{object_file}" +recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.flags} -mcpu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.c.extra_flags} {build.extra_flags} {build.cpu_flags} {build.vect_flags} {compiler.libs.c.flags} {includes} "{source_file}" -o "{object_file}" ## Compile c++ files -recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} -mcpu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {build.cpu_flags} {build.hs_flag} {build.common_flags} {compiler.libs.c.flags} {includes} "{source_file}" -o "{object_file}" +recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} -mcpu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {build.cpu_flags} {build.vect_flags} {build.hs_flag} {build.common_flags} {compiler.libs.c.flags} {includes} "{source_file}" -o "{object_file}" ## Compile S files -recipe.S.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.S.flags} -mcpu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.S.extra_flags} {build.extra_flags} {build.cpu_flags} {build.hs_flag} {build.common_flags} {compiler.libs.c.flags} {includes} "{source_file}" -o "{object_file}" +recipe.S.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.S.flags} -mcpu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.S.extra_flags} {build.extra_flags} {build.cpu_flags} {build.vect_flags} {build.hs_flag} {build.common_flags} {compiler.libs.c.flags} {includes} "{source_file}" -o "{object_file}" ## Create archives recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{archive_file_path}" "{object_file}" diff --git a/STM32F4/variants/generic_f407v/ld/bootloader_8004000.ld b/STM32F4/variants/generic_f407v/ld/bootloader_8004000.ld new file mode 100644 index 0000000..677683e --- /dev/null +++ b/STM32F4/variants/generic_f407v/ld/bootloader_8004000.ld @@ -0,0 +1,21 @@ +/* + * STM32F4xx high density linker script for + * JTAG (bare metal, no bootloader) builds. + */ + +MEMORY +{ + ccmram (rw): ORIGIN = 0x10000000, LENGTH = 64K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K + rom (rx) : ORIGIN = 0x08004000, LENGTH = 496K +} + +/* GROUP(libcs3_stm32_high_density.a) */ + +REGION_ALIAS("REGION_TEXT", rom); +REGION_ALIAS("REGION_DATA", ram); +REGION_ALIAS("REGION_BSS", ram); +REGION_ALIAS("REGION_RODATA", rom); + +_FLASH_BUILD = 1; +INCLUDE common.inc From b1e1782019265992abf115a513be6facec68d259 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Sun, 3 Sep 2017 11:00:16 +1000 Subject: [PATCH 151/351] Fix for map() function - supplied by @Pito --- STM32F1/cores/maple/wirish_math.h | 11 ++++++----- STM32F4/cores/maple/wirish_math.h | 11 ++++++----- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/STM32F1/cores/maple/wirish_math.h b/STM32F1/cores/maple/wirish_math.h index 9140d06..b85253f 100644 --- a/STM32F1/cores/maple/wirish_math.h +++ b/STM32F1/cores/maple/wirish_math.h @@ -79,11 +79,12 @@ long random(long min, long max); * @param toEnd the end of the value's mapped range. * @return the mapped value. */ -static inline long map(long value, long fromStart, long fromEnd, - long toStart, long toEnd) { - return (value - fromStart) * (toEnd - toStart) / (fromEnd - fromStart) + - toStart; -} + // Fix by Pito 9/2017 + static inline int32_t map(int32_t value, int32_t fromStart, int32_t fromEnd, + int32_t toStart, int32_t toEnd) { + return ((int64_t)(value - fromStart) * (toEnd - toStart)) / (fromEnd - fromStart) + + toStart; + } #define PI 3.1415926535897932384626433832795 #define HALF_PI 1.5707963267948966192313216916398 diff --git a/STM32F4/cores/maple/wirish_math.h b/STM32F4/cores/maple/wirish_math.h index 0b8b222..e037372 100644 --- a/STM32F4/cores/maple/wirish_math.h +++ b/STM32F4/cores/maple/wirish_math.h @@ -78,11 +78,12 @@ long random(long min, long max); * @param toEnd the end of the value's mapped range. * @return the mapped value. */ -static inline long map(long value, long fromStart, long fromEnd, - long toStart, long toEnd) { - return (value - fromStart) * (toEnd - toStart) / (fromEnd - fromStart) + - toStart; -} + // Fix by Pito 9/2017 + static inline int32_t map(int32_t value, int32_t fromStart, int32_t fromEnd, + int32_t toStart, int32_t toEnd) { + return ((int64_t)(value - fromStart) * (toEnd - toStart)) / (fromEnd - fromStart) + + toStart; + } #define PI 3.1415926535897932384626433832795 #define HALF_PI 1.5707963267948966192313216916398 From 56abaa31735b0c7137cedef5484178cd0855866e Mon Sep 17 00:00:00 2001 From: victorpv Date: Mon, 4 Sep 2017 10:41:58 -0500 Subject: [PATCH 152/351] Correction to upload issue in Sloeber As discussed in http://stm32duino.com/viewtopic.php?f=41&t=2535 Changes to the Generic Boards options so the maple dfu option is the default one and Sloeber uploads correctly. --- STM32F1/boards.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/STM32F1/boards.txt b/STM32F1/boards.txt index 6d110d0..10379ec 100644 --- a/STM32F1/boards.txt +++ b/STM32F1/boards.txt @@ -357,6 +357,8 @@ genericSTM32F103C.build.board=GENERIC_STM32F103C genericSTM32F103C.upload.use_1200bps_touch=false genericSTM32F103C.upload.file_type=bin genericSTM32F103C.upload.auto_reset=true +genericSTM32F103C.upload.tool=maple_upload +genericSTM32F103C.upload.protocol=maple_dfu ## STM32F103C8 ------------------------- genericSTM32F103C.menu.device_variant.STM32F103C8=STM32F103C8 (20k RAM. 64k Flash) @@ -454,6 +456,8 @@ genericSTM32F103R.build.board=GENERIC_STM32F103R genericSTM32F103R.upload.use_1200bps_touch=false genericSTM32F103R.upload.file_type=bin genericSTM32F103R.upload.auto_reset=true +genericSTM32F103R.upload.tool=maple_upload +genericSTM32F103R.upload.protocol=maple_dfu genericSTM32F103R.menu.device_variant.STM32F103R8=STM32F103R8 (20k RAM. 64k Flash) genericSTM32F103R.menu.device_variant.STM32F103R8.build.variant=generic_stm32f103r8 @@ -563,6 +567,8 @@ genericSTM32F103T.build.board=GENERIC_STM32F103T genericSTM32F103T.upload.use_1200bps_touch=false genericSTM32F103T.upload.file_type=bin genericSTM32F103T.upload.auto_reset=true +genericSTM32F103T.upload.tool=maple_upload +genericSTM32F103T.upload.protocol=maple_dfu ## STM32F103T8 ------------------------- genericSTM32F103T.menu.device_variant.STM32F103T8=STM32F103T8 (20k RAM. 64k Flash) @@ -655,6 +661,8 @@ genericSTM32F103V.build.board=GENERIC_STM32F103V genericSTM32F103V.upload.use_1200bps_touch=false genericSTM32F103V.upload.file_type=bin genericSTM32F103V.upload.auto_reset=true +genericSTM32F103V.upload.tool=maple_upload +genericSTM32F103V.upload.protocol=maple_dfu genericSTM32F103V.build.error_led_port=GPIOE genericSTM32F103V.build.error_led_pin=6 @@ -754,6 +762,8 @@ genericSTM32F103Z.build.board=GENERIC_STM32F103Z genericSTM32F103Z.upload.use_1200bps_touch=false genericSTM32F103Z.upload.file_type=bin genericSTM32F103Z.upload.auto_reset=true +genericSTM32F103Z.upload.tool=maple_upload +genericSTM32F103Z.upload.protocol=maple_dfu genericSTM32F103Z.menu.device_variant.STM32F103ZC=STM32F103ZC genericSTM32F103Z.menu.device_variant.STM32F103ZC.build.cpu_flags=-DMCU_STM32F103ZC From 81100beeea63040ff429ac87420f1162bcaf909c Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Tue, 5 Sep 2017 17:03:16 +1000 Subject: [PATCH 153/351] Updated readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9d167cf..9493be9 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ This software is experimental and a work in progress. Under no circumstances should these files be used in relation to any critical system(s). Use of these files is at your own risk. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ## Summary: This repo contains, the "Hardware" files to support STM32 based boards on Arduino version 1.8.x (some older versions may also work) including [LeafLabs Maple, and Maple mini](http://www.leaflabs.com/about-maple/), and other generic STM32F103 boards From f769556e9a5d74161bba2daff09ea8d25ab216cc Mon Sep 17 00:00:00 2001 From: victorpv Date: Mon, 11 Sep 2017 21:25:09 -0500 Subject: [PATCH 154/351] F1 SDIO initial version --- STM32F1/libraries/SDIO/SdioF1.cpp | 852 ++++++++++++++++++++++++++++++ 1 file changed, 852 insertions(+) create mode 100644 STM32F1/libraries/SDIO/SdioF1.cpp diff --git a/STM32F1/libraries/SDIO/SdioF1.cpp b/STM32F1/libraries/SDIO/SdioF1.cpp new file mode 100644 index 0000000..8957b37 --- /dev/null +++ b/STM32F1/libraries/SDIO/SdioF1.cpp @@ -0,0 +1,852 @@ +/* Arduino SdCard Library + * Copyright (C) 2016 by William Greiman + * + * This file is part of the Arduino SdSpiCard Library + * + * This Library is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This Library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Arduino SdSpiCard Library. If not, see + * . + */ + +#include "SdioF1.h" +#include +#include +#include + + +#define USE_DEBUG_MODE 0 +#define USE_YIELD 0 + +//============================================================================== +//#define SDHC_PROCTL_DTW_4BIT 0x01 +#define CMD8_RETRIES 10 +#define BUSY_TIMEOUT_MILLIS 1500 +//============================================================================== +#define CMD_RESP_NONE SDIO_CMD_WAIT_NO_RESP +#define CMD_RESP_R1 SDIO_CMD_WAIT_SHORT_RESP // normal response +#define CMD_RESP_R1b SDIO_CMD_WAIT_SHORT_RESP // normal response + busy data line (optional) +#define CMD_RESP_R2 SDIO_CMD_WAIT_LONG_RESP // CID, CSD +#define CMD_RESP_R3 SDIO_CMD_WAIT_SHORT_RESP // OCR register, response to ACMD41 +#define CMD_RESP_R6 SDIO_CMD_WAIT_SHORT_RESP // published RCA response, response to CMD3 +#define CMD_RESP_R7 SDIO_CMD_WAIT_SHORT_RESP // response to CMD8 + +#define CMD0_XFERTYP (uint16_t)( CMD0 | CMD_RESP_NONE ) +#define CMD2_XFERTYP (uint16_t)( CMD2 | CMD_RESP_R2 ) +#define CMD3_XFERTYP (uint16_t)( CMD3 | CMD_RESP_R6 ) +#define CMD6_XFERTYP (uint16_t)( CMD6 | CMD_RESP_R1 ) +#define ACMD6_XFERTYP (uint16_t)( ACMD6 | CMD_RESP_R1 ) +#define CMD7_XFERTYP (uint16_t)( CMD7 | CMD_RESP_R1b ) +#define CMD8_XFERTYP (uint16_t)( CMD8 | CMD_RESP_R7 ) +#define CMD9_XFERTYP (uint16_t)( CMD9 | CMD_RESP_R2 ) +#define CMD10_XFERTYP (uint16_t)( CMD10 | CMD_RESP_R2 ) +#define CMD12_XFERTYP (uint16_t)( CMD12 | CMD_RESP_R1b ) +#define CMD13_XFERTYP (uint16_t)( CMD13 | CMD_RESP_R1 ) +#define CMD17_XFERTYP (uint16_t)( CMD17 | CMD_RESP_R1 ) +#define CMD18_XFERTYP (uint16_t)( CMD18 | CMD_RESP_R1 ) +#define ACMD23_XFERTYP (uint16_t)( ACMD23 | CMD_RESP_R1 ) +#define CMD24_XFERTYP (uint16_t)( CMD24 | CMD_RESP_R1 ) +#define CMD25_XFERTYP (uint16_t)( CMD25 | CMD_RESP_R1 ) +#define CMD32_XFERTYP (uint16_t)( CMD32 | CMD_RESP_R1 ) +#define CMD33_XFERTYP (uint16_t)( CMD32 | CMD_RESP_R1 ) +#define CMD38_XFERTYP (uint16_t)( CMD38 | CMD_RESP_R1b ) +#define ACMD41_XFERTYP (uint16_t)( ACMD41 | CMD_RESP_R3 ) + +#define CMD55_XFERTYP (uint16_t)( CMD55 | CMD_RESP_R1 ) + +//============================================================================= +//static void enableGPIO(bool enable); +//static void enableDmaIrs(); +static void initSDHC(void); +static bool isBusyCMD13(void); +static bool isBusyTransferComplete(void); +//static bool isBusyCommandComplete(); +//static bool isBusyCommandInhibit(); +static bool readReg16(uint32_t xfertyp, void* data); +//static void setSdclk(uint32_t kHzMax); +static bool yieldTimeout(bool (*fcn)(void)); +static bool waitDmaStatus(void); +static bool waitTimeout(bool (*fcn)(void)); +//----------------------------------------------------------------------------- +#define TRX_RD 0 +#define TRX_WR 1 +static uint8_t m_dir = TRX_RD; +static bool (*m_busyFcn)() = 0; +static bool m_initDone = false; +static uint32_t m_lba; // for raw non-DMA read(write)Start, read(write)Data, read(write)Stop +static uint32_t m_cnt; // for raw non-DMA read(write)Start, read(write)Data, read(write)Stop +static bool m_version2; +static bool m_highCapacity; +static uint8_t m_errorCode = SD_CARD_ERROR_INIT_NOT_CALLED; +static uint32_t m_errorLine = 0; +static uint32_t m_rca; +//static volatile bool m_dmaBusy = false; +static volatile uint32_t m_irqstat; +static uint32_t m_sdClkKhz = 0; +static uint32_t m_ocr; +static cid_t m_cid; +static csd_t m_csd; +static uint32_t t = 0; +//============================================================================= +/* + * Todo Remove this or change it, but rather remove since this can be checked with debugger. + */ +#if USE_DEBUG_MODE +#define DBG_PRINT() { \ + Serial.write('_'); Serial.print(__FUNCTION__); Serial.write('_'); Serial.print(__LINE__); Serial.print(": "); \ + Serial.print("DMA->LISR: "); Serial.print(SDIO_DMA_DEV->regs->LISR, HEX); \ + /*Serial.print("DMA->HISR: "); Serial.println(SDIO_DMA_DEV->regs->HISR, HEX);*/ \ + Serial.print(", DMA->CR: "); Serial.print(SDIO_DMA_DEV->regs->STREAM[SDIO_DMA_CHANNEL].CR, HEX); \ + Serial.print(", DMA->NDTR: "); Serial.print(SDIO_DMA_DEV->regs->STREAM[SDIO_DMA_CHANNEL].NDTR, HEX); \ + /**/Serial.print(", DMA->PAR: "); Serial.print(SDIO_DMA_DEV->regs->STREAM[SDIO_DMA_CHANNEL].PAR, HEX); \ + /**/Serial.print(", DMA->M0AR: "); Serial.print(SDIO_DMA_DEV->regs->STREAM[SDIO_DMA_CHANNEL].M0AR, HEX); \ + Serial.print(", DMA->FCR: "); Serial.print(SDIO_DMA_DEV->regs->STREAM[SDIO_DMA_CHANNEL].FCR, HEX); \ + \ + /*Serial.print(" SDIO->POWER: "); Serial.println(SDIO->POWER, HEX);*/ \ + Serial.print(", SDIO->CLKCR: "); Serial.print(SDIO->CLKCR, HEX); \ + Serial.print(", SDIO->DTIMER: "); Serial.print(SDIO->DTIMER, HEX); \ + Serial.print(", SDIO->DCTRL: "); Serial.print(SDIO->DCTRL, HEX); \ + /**/Serial.print(", SDIO->DLEN: "); Serial.print(SDIO->DLEN); \ + Serial.print(", SDIO->DCOUNT: "); Serial.print(SDIO->DCOUNT); \ + Serial.print(", SDIO->STA: "); Serial.println(SDIO->STA, HEX); \ + /*delay(1);*/ \ +} +#define DBG_PIN PD0 + +#else // USE_DEBUG_MODE +#define DBG_PRINT() +#endif // USE_DEBUG_MODE + +/*****************************************************************************/ +static void _panic(const char *message, uint32_t code) +{ + Serial.print(message); Serial.println(code, HEX); + //Block the execution with blinky leds + while (1); +/* + pinMode(BOARD_LED_PIN, OUTPUT); + //pinMode(BOARD_LED2_PIN, OUTPUT); + while (1) { + digitalWrite(BOARD_LED_PIN, HIGH); + //digitalWrite(BOARD_LED2_PIN, LOW); + delay(250); + digitalWrite(BOARD_LED_PIN, LOW); + //digitalWrite(BOARD_LED2_PIN, HIGH); + delay(250); + } + */ +} +/*===========================================================================*/ +/* + * Todo: Change the DMA parts so it works with F1 DMA, but since yield is disabled, we can ignore it for now. +*/ + +#if USE_YIELD +void yield(void) +{ + uint32_t val = SDIO->STA; + if ( val & SDIO_STA_TRX_ERROR_FLAGS ) { + Serial.print("SDIO ERROR:: SDIO->CLKCR: "); Serial.print(SDIO->CLKCR, HEX); \ + Serial.print(", SDIO->DTIMER: "); Serial.print(SDIO->DTIMER, HEX); \ + Serial.print(", SDIO->DCTRL: "); Serial.print(SDIO->DCTRL, HEX); \ + Serial.print(", SDIO->DLEN: "); Serial.print(SDIO->DLEN); \ + Serial.print(", SDIO->DCOUNT: "); Serial.print(SDIO->DCOUNT); \ + Serial.print(", SDIO->STA: "); Serial.print(SDIO->STA, HEX); \ + Serial.print(", SDIO->RESP0: "); Serial.println(SDIO->RESP[0], HEX); \ + if (val & SDIO_STA_STBITERR) Serial.print(" STBITERR"); + if (val & SDIO_STA_RXOVERR) Serial.print(" RXOVERR"); + if (val & SDIO_STA_TXUNDERR) Serial.print(" TXUNDERR"); + if (val & SDIO_STA_DTIMEOUT) Serial.print(" DTIMEOUT"); + if (val & SDIO_STA_DCRCFAIL) Serial.print(" DCRCFAIL"); + _panic(" - SDIO: Data Transmission Error ", val); + } + + val = dma_get_isr_bits(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); + if ( val & DMA_ISR_FEIF ) { + val ^= DMA_ISR_FEIF; + dma_clear_isr_bits(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); + } + if ( val ) { + if (val & DMA_ISR_TEIF) Serial.print(" TEIF"); + if (val & DMA_ISR_DMEIF) Serial.print(" DMEIF"); + //if (val & DMA_ISR_FEIF) Serial.print(" FEIF"); + _panic(" - DMA: Data Transmission Error ", val); + } + //Serial.write('.'); +} +#endif +//============================================================================= +// Error function and macro. +inline bool setSdErrorCode(uint8_t code, uint32_t line) { + m_errorCode = code; + m_errorLine = line; + return false; // setSdErrorCode +} +#define sdError(code) setSdErrorCode(code, __LINE__) +//============================================================================= +/* ISR +void sdhc_isr() { + SDHC_IRQSIGEN = 0; + m_irqstat = SDHC_IRQSTAT; + SDHC_IRQSTAT = m_irqstat; + m_dmaBusy = false; +}*/ +//============================================================================= +// Static functions. +//----------------------------------------------------------------------------- +static bool cardCommand(uint16_t xfertyp, uint32_t arg) +{ +#if USE_DEBUG_MODE==2 + Serial.print("cardCommand: "); Serial.print(xfertyp&SDIO_CMD_CMDINDEX); Serial.print(", arg: "); Serial.print(arg, HEX); +#endif + uint8_t resp = sdio_cmd_send(xfertyp, arg); // returns non-zero if fails, zero if OK +#if USE_DEBUG_MODE==2 + Serial.print(", resp: "); Serial.print(resp, HEX); + Serial.print(", SDIO->STA: "); Serial.print(SDIO->STA, HEX); Serial.print(", cmd_resp: "); Serial.print(SDIO->RESP[0], HEX); + if ( (xfertyp&SDIO_CMD_WAIT_LONG_RESP)==SDIO_CMD_WAIT_LONG_RESP ) { + Serial.print(", "); Serial.print(SDIO->RESP[1], HEX); Serial.print(", "); Serial.print(SDIO->RESP[2], HEX); Serial.print(", "); Serial.println(SDIO->RESP[3], HEX); + } else Serial.println(); +#endif + return resp; // return non-zero when OK +} +//----------------------------------------------------------------------------- +static bool cardAcmd(uint32_t rca, uint32_t xfertyp, uint32_t arg) { + return cardCommand(CMD55_XFERTYP, rca) && cardCommand((uint16_t)xfertyp, arg); +} +/*---------------------------------------------------------------------------*/ +static bool cardCMD6(uint32_t arg, uint8_t* status) { + // CMD6 returns 64 bytes. + // use polling only for the moment + if (waitTimeout(isBusyCMD13)) { + return sdError(SD_CARD_ERROR_CMD13); + } + // get the 64 bytes over data lines + sdio_setup_transfer(80000, 64, (SDIO_BLOCKSIZE_64 | SDIO_DIR_RX | SDIO_DCTRL_DTEN)); + + cardCommand(CMD6_XFERTYP, arg); + + // wait data Rx response + if (waitTimeout(isBusyTransferComplete)) { + return sdError(SD_CARD_ERROR_CMD6); + } +DBG_PRINT(); + // copy 64 bytes as 16 words from FIFO to buffer + for (uint8_t i=0; i<16; i++) { + *(uint32_t*)(&status[i<<2]) = SDIO->FIFO; + } + //SDIO->DCTRL = 0; // disable data controller + +#if USE_DEBUG_MODE + Serial.print("read data: "); for (uint8_t i=0; i<17; i++) { Serial.print(status[i], HEX); Serial.print(", "); } Serial.println(); +#endif +return true; +} +//----------------------------------------------------------------------------- +static void initSDHC(void) +{ + sdio_begin(); + DBG_PRINT(); +} +/*---------------------------------------------------------------------------*/ +static bool isBusyCMD13(void) { + if (!cardCommand(CMD13_XFERTYP, m_rca)) { // SEND_STATUS + // Caller will timeout. + return true; + } + return !(SDIO->RESP[0] & CARD_STATUS_READY_FOR_DATA); +} +/*---------------------------------------------------------------------------*/ +static bool isBusyDMA(void) +{ + uint8_t isr = dma_get_isr_bits(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); + isr &= DMA_ISR_TCIF | DMA_ISR_TEIF; + //if (isr&DMA_ISR_TCIF) dma_disable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); + return !(isr); // ignore transfer error flag +} +/*---------------------------------------------------------------------------*/ +static bool isBusyTransferComplete(void) +{ + uint32_t mask = SDIO->STA &(SDIO_STA_DATAEND | SDIO_STA_TRX_ERROR_FLAGS); +#if USE_DEBUG_MODE + if ( mask & SDIO_STA_TRX_ERROR_FLAGS ) { + Serial.print("XFER ERROR: SDIO->STA: "); Serial.print(SDIO->STA, HEX); + if (mask & SDIO_STA_STBITERR) Serial.print(" STBITERR"); + if (mask & SDIO_STA_RXOVERR) Serial.print(" RXOVERR"); + if (mask & SDIO_STA_TXUNDERR) Serial.print(" TXUNDERR"); + if (mask & SDIO_STA_DTIMEOUT) Serial.print(" DTIMEOUT"); + if (mask & SDIO_STA_DCRCFAIL) Serial.print(" DCRCFAIL"); + Serial.println(); + } +#endif + if (mask) { + dma_disable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); + return false; + } + return true; +} +/*---------------------------------------------------------------------------*/ +static void trxStart(uint8_t* buf, uint32_t n, uint8_t dir) +{ + m_dir = dir; + uint32_t flags = (SDIO_BLOCKSIZE_512 | SDIO_DCTRL_DTEN); + if (dir==TRX_RD) flags |= SDIO_DIR_RX; + // setup SDIO to transfer n blocks of 512 bytes + sdio_setup_transfer(0x00FFFFFF, n, flags); +} +/*---------------------------------------------------------------------------*/ +static bool trxStop() +{ + if (!cardCommand(CMD12_XFERTYP, 0)) { + return sdError(SD_CARD_ERROR_CMD12); + } + if ( t ) { + Serial.print(", in "); Serial.println(millis()-t); + t = 0; + } + return true; +} +/*---------------------------------------------------------------------------*/ +static bool dmaTrxStart(uint8_t* buf, uint32_t n, uint8_t dir) +{ + m_dir = dir; + if ((3 & (uint32_t)buf) || n == 0) { // check alignment + _panic("- transferStart: unaligned buffer address ", (uint32_t)buf); + return sdError(SD_CARD_ERROR_DMA); + } + if (dir==TRX_RD && yieldTimeout(isBusyCMD13)) { + return sdError(SD_CARD_ERROR_CMD13); + } + uint32_t flags = (SDIO_BLOCKSIZE_512 | SDIO_DCTRL_DMAEN | SDIO_DCTRL_DTEN); + if (dir==TRX_RD) flags |= SDIO_DIR_RX; + // setup SDIO to transfer n blocks of 512 bytes + sdio_setup_transfer(0x00FFFFFF, n, flags); + // setup SDIO_DMA_DEV stream 3 channel 4 + /* + * Moved to begin. + */ + //dma_init(SDIO_DMA_DEV); + /* + * Todo. Check this, channel must be disabled to change DMA priority, and seems like channel is not completing transfers + */ + //dma_set_priority(SDIO_DMA_DEV, SDIO_DMA_CHANNEL, DMA_PRIORITY_VERY_HIGH); + flags = (DMA_MINC_MODE); + // not extra flag if read + if (dir!=TRX_RD) flags |= DMA_FROM_MEM;// write + dma_setup_transfer(SDIO_DMA_DEV, SDIO_DMA_CHANNEL, &SDIO->FIFO, DMA_SIZE_32BITS, buf, DMA_SIZE_32BITS, flags); + dma_set_num_transfers(SDIO_DMA_DEV, SDIO_DMA_CHANNEL, n>>2); // F1 DMA controller counts each word as 1 data item. + //dma_set_fifo_flags(SDIO_DMA_DEV, SDIO_DMA_CHANNEL, (DMA_FCR_DMDIS | DMA_FCR_FTH_FULL)); // disable direct mode | threshold FULL + dma_clear_isr_bits(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); + dma_enable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); + return true; +} +/*---------------------------------------------------------------------------*/ +static bool dmaTrxEnd(bool multi_block) +{ + if ( !waitDmaStatus() ) { + DBG_PRINT(); + return sdError(SD_CARD_ERROR_DMA); + } + if ( waitTimeout(isBusyTransferComplete) ) { + if (m_dir==TRX_RD) + return sdError(SD_CARD_ERROR_READ_TIMEOUT); + else + return sdError(SD_CARD_ERROR_WRITE_TIMEOUT); + } + if (multi_block) { + return trxStop(); + } else { + if ( t ) { + Serial.print(", in "); Serial.println(millis()-t); + t = 0; + } + return true; + } +} +//----------------------------------------------------------------------------- +// Read 16 byte CID or CSD register. +static bool readReg16(uint32_t xfertyp, void* data) +{ + uint8_t* d = reinterpret_cast(data); + if (!cardCommand(xfertyp, m_rca)) { + return false; // Caller will set errorCode. + } + *(uint32_t*)(&d[0]) = __builtin_bswap32(SDIO->RESP[0]); + *(uint32_t*)(&d[4]) = __builtin_bswap32(SDIO->RESP[1]); + *(uint32_t*)(&d[8]) = __builtin_bswap32(SDIO->RESP[2]); + *(uint32_t*)(&d[12]) = __builtin_bswap32(SDIO->RESP[3]); + d[15] = 0; + return true; +} +/*---------------------------------------------------------------------------*/ +// Return true if timeout occurs. +static bool yieldTimeout(bool (*fcn)()) { + uint32_t m = millis(); + while (fcn()) { + if ((millis() - m) > BUSY_TIMEOUT_MILLIS) { + return true; + } + yield(); + } + return false; // Caller will set errorCode. +} +/*---------------------------------------------------------------------------*/ +static bool waitDmaStatus(void) +{ + if (yieldTimeout(isBusyDMA)) { + return false; // Caller will set errorCode. + } + return true; +} +/*---------------------------------------------------------------------------*/ +// Return true if timeout occurs. +static bool waitTimeout(bool (*fcn)(void)) { + uint32_t m = millis(); + while (fcn()) { + if ((millis() - m) > BUSY_TIMEOUT_MILLIS) { + return true; + } + delayMicroseconds(1); + } + return false; // Caller will set errorCode. +} + +uint32_t aligned[128]; // temporary buffer for misaligned buffers +//============================================================================= +bool SdioCard::begin(void) +{ + m_initDone = false; + m_errorCode = SD_CARD_ERROR_NONE; + m_highCapacity = false; + m_version2 = false; + +#if USE_DEBUG_MODE +pinMode(DBG_PIN, OUTPUT); +digitalWrite(DBG_PIN, HIGH); +delay(100); +#endif + // initialize controller. + initSDHC(); + + // initialize DMA device + dma_init(SDIO_DMA_DEV); + dma_disable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); // Disable DMA in case it was left enabled from a previous use. + /* + * Todo. Check this, channel must be disabled to change DMA priority, and seems like channel is not completing transfers + */ + dma_set_priority(SDIO_DMA_DEV, SDIO_DMA_CHANNEL, DMA_PRIORITY_VERY_HIGH); + + if (!cardCommand(CMD0_XFERTYP, 0)) { + return sdError(SD_CARD_ERROR_CMD0); + } + // Try several times for case of reset delay. + for (uint32_t i = 0; i < CMD8_RETRIES; i++) { + if (cardCommand(CMD8_XFERTYP, 0X1AA)) { + if (SDIO->RESP[0] != 0X1AA) { + return sdError(SD_CARD_ERROR_CMD8); + } + m_version2 = true; + break; + } + } + uint32_t arg = m_version2 ? 0X40300000 : 0x00300000; + uint32_t m = millis(); + do { + if (!cardAcmd(0, ACMD41_XFERTYP, arg) || + ((millis() - m) > BUSY_TIMEOUT_MILLIS)) { + return sdError(SD_CARD_ERROR_ACMD41); + } + } while ((SDIO->RESP[0] & 0x80000000) == 0); + + m_ocr = SDIO->RESP[0]; + if (m_ocr & 0x40000000) { + // Is high capacity. + m_highCapacity = true; + } + if (!cardCommand(CMD2_XFERTYP, 0)) { + return sdError(SD_CARD_ERROR_CMD2); + } + if (!cardCommand(CMD3_XFERTYP, 0)) { + return sdError(SD_CARD_ERROR_CMD3); + } + m_rca = SDIO->RESP[0] & 0xFFFF0000; + if (!readReg16(CMD9_XFERTYP, &m_csd)) { + return sdError(SD_CARD_ERROR_CMD9); + } + if (!readReg16(CMD10_XFERTYP, &m_cid)) { + return sdError(SD_CARD_ERROR_CMD10); + } + if (!cardCommand(CMD7_XFERTYP, m_rca)) { + return sdError(SD_CARD_ERROR_CMD7); + } + // Set card to bus width four. + /* + if (!cardAcmd(m_rca, ACMD6_XFERTYP, 2)) { + return sdError(SD_CARD_ERROR_ACMD6); + } + sdio_set_dbus_width(SDIO_CLKCR_WIDBUS_4BIT); + */ + + // Determine if High Speed mode is supported and set frequency. + uint8_t status[64]; + // see "Physical Layer Simplified Specification Version 6.00", chapter 4.3.10, Table 4-13. + // Support Bits of Functions in Function Group 1: bits 415:400, which are bytes [12][13] + // Function Selection of Function Group 1: bits 379:376, which is low nibble of byte [16] + if (cardCMD6(0X00FFFFFF, status) && (2 & status[13]) && + cardCMD6(0X80FFFFF1, status) && (status[16] & 0XF) == 1) { + //Serial.println("\n*** 50MHz clock supported ***"); + } else { + //_panic("*** Only 25MHz clock supported! ***", 0); + } + + /* + * Todo Raise clock to 24Mhz once transfers work + */ + m_sdClkKhz = 24000; // set clock to 24MHz + sdio_set_clock(m_sdClkKhz*1000); + + m_initDone = true; + return true; +} +//----------------------------------------------------------------------------- +uint32_t SdioCard::cardSize(void) { + return sdCardCapacity(&m_csd); +} +/*---------------------------------------------------------------------------*/ +bool SdioCard::erase(uint32_t firstBlock, uint32_t lastBlock) { + // check for single block erase + if (!m_csd.v1.erase_blk_en) { + // erase size mask + uint8_t m = (m_csd.v1.sector_size_high << 1) | m_csd.v1.sector_size_low; + if ((firstBlock & m) != 0 || ((lastBlock + 1) & m) != 0) { + // error card can't erase specified area + return sdError(SD_CARD_ERROR_ERASE_SINGLE_BLOCK); + } + } + if (!m_highCapacity) { + firstBlock <<= 9; + lastBlock <<= 9; + } + if (!cardCommand(CMD32_XFERTYP, firstBlock)) { + return sdError(SD_CARD_ERROR_CMD32); + } + if (!cardCommand(CMD33_XFERTYP, lastBlock)) { + return sdError(SD_CARD_ERROR_CMD33); + } + if (!cardCommand(CMD38_XFERTYP, 0)) { + return sdError(SD_CARD_ERROR_CMD38); + } + if (waitTimeout(isBusyCMD13)) { + return sdError(SD_CARD_ERROR_ERASE_TIMEOUT); + } + return true; +} +//----------------------------------------------------------------------------- +uint8_t SdioCard::errorCode() { + return m_errorCode; +} +//----------------------------------------------------------------------------- +uint32_t SdioCard::errorData() { + return m_irqstat; +} +//----------------------------------------------------------------------------- +uint32_t SdioCard::errorLine() { + return m_errorLine; +} +//----------------------------------------------------------------------------- +bool SdioCard::isBusy() { + return m_busyFcn ? m_busyFcn() : m_initDone && isBusyCMD13(); +} +//----------------------------------------------------------------------------- +uint32_t SdioCard::kHzSdClk() { + return m_sdClkKhz; +} +/*---------------------------------------------------------------------------*/ +bool SdioCard::readBlock(uint32_t lba, uint8_t* buf) +{ +#if USE_DEBUG_MODE + Serial.print("readBlock: "); Serial.println(lba); //Serial.print(", buf: "); Serial.println((uint32_t)buf, HEX); +#endif + // prepare SDIO and DMA for data read transfer + dmaTrxStart((uint32_t)buf & 3 ? (uint8_t*)aligned : buf, 512, TRX_RD); + // send command to start data transfer + if ( !cardCommand(CMD17_XFERTYP, (m_highCapacity ? lba : 512*lba)) ) { + return sdError(SD_CARD_ERROR_CMD17); + } + if ( dmaTrxEnd(0)) { + if ( (uint32_t)buf & 3 ) { + //memcpy(buf, aligned, 512); + register uint8_t * dst = buf; + register uint8_t * src = (uint8_t *)aligned; + register uint16_t i = 64; + while ( i-- ) { // do 8 byte copies, is much faster than single byte copy + *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; + *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; + } + } + return true; + } + return false; +} +/*---------------------------------------------------------------------------*/ +bool SdioCard::readBlocks(uint32_t lba, uint8_t* buf, size_t n) +{ +#if USE_DEBUG_MODE + Serial.print("readBlocks: "); Serial.print(lba); + //Serial.print(", buf: "); Serial.print((uint32_t)buf, HEX); + Serial.print(", "); Serial.println(n); +#endif + if ((uint32_t)buf & 3) { + for (size_t i = 0; i < n; i++, lba++, buf += 512) { + if (!readBlock(lba, buf)) { + return false; // readBlock will set errorCode. + } + } + return true; + } + // prepare SDIO and DMA for data read transfer + dmaTrxStart(buf, 512*n, TRX_RD); + // send command to start data transfer + if ( !cardCommand(CMD18_XFERTYP, (m_highCapacity ? lba : 512*lba)) ) { + return sdError(SD_CARD_ERROR_CMD18); + } + return dmaTrxEnd(1); +} +//----------------------------------------------------------------------------- +bool SdioCard::readCID(void* cid) { + memcpy(cid, &m_cid, 16); + return true; +} +//----------------------------------------------------------------------------- +bool SdioCard::readCSD(void* csd) { + memcpy(csd, &m_csd, 16); + return true; +} +/*---------------------------------------------------------------------------*/ +bool SdioCard::readData(uint8_t *dst) +{ + //Serial.print("readData: "); Serial.print(m_lba); Serial.print(", m_cnt: "); Serial.println(m_cnt); + if ( m_cnt==0 ) return false; + if (yieldTimeout(isBusyCMD13)) { // wait for previous transmission end + return sdError(SD_CARD_ERROR_CMD13); + } + // non-DMA block read + trxStart(dst, 512, TRX_RD); + // send command to start data transfer + if ( !cardCommand(CMD17_XFERTYP, (m_highCapacity ? m_lba : 512*m_lba)) ) { + return sdError(SD_CARD_ERROR_CMD17); + } + // Receive a data block from the SDIO + register uint32_t STA; // to speed up SDIO flags checking + register uint16_t cnt = 512; + register uint32_t * ptr = (uint32_t *)dst; + // ----> TIME CRITICAL SECTION BEGIN <---- + do { + STA = SDIO->STA; + if (STA & SDIO_STA_RXFIFOHF) { + // Receive FIFO half full, there are at least 8 words in it + noInterrupts(); + *ptr++ = SDIO->FIFO; *ptr++ = SDIO->FIFO; *ptr++ = SDIO->FIFO; *ptr++ = SDIO->FIFO; + *ptr++ = SDIO->FIFO; *ptr++ = SDIO->FIFO; *ptr++ = SDIO->FIFO; *ptr++ = SDIO->FIFO; + interrupts(); + cnt -= 8; + } + } while ( !(STA & (SDIO_STA_DATAEND | SDIO_STA_TRX_ERROR_FLAGS)) ); + // <---- TIME CRITICAL SECTION END ----> + + // read data still available in FIFO + while ( (SDIO->STA & SDIO_STA_RXDAVL) && (cnt--) ) { + *ptr++ = SDIO->FIFO; + } + // check error, temporary stuff, remove for final version + if ( SDIO->STA & SDIO_STA_TRX_ERROR_FLAGS ) { + _panic("ERROR: non-DMA read error ", SDIO->STA); + return false; + } + m_lba++; + m_cnt--; + return !(SDIO->STA&SDIO_STA_TRX_ERROR_FLAGS); +} +//----------------------------------------------------------------------------- +bool SdioCard::readOCR(uint32_t* ocr) { + *ocr = m_ocr; + return true; +} +//----------------------------------------------------------------------------- +bool SdioCard::readStart(uint32_t lba) +{ + m_lba = lba; + m_cnt = 1024; + return true; +} +/*---------------------------------------------------------------------------*/ +// SDHC will do Auto CMD12 after count blocks. +bool SdioCard::readStart(uint32_t lba, uint32_t count) +{ + //Serial.print("readStart: "); Serial.print(lba); Serial.print(", cnt: "); Serial.println(count); + m_lba = lba; + m_cnt = count; + return true; +} +/*---------------------------------------------------------------------------*/ +bool SdioCard::readStop() +{ + //Serial.println("readStop."); + m_lba = 0; + m_cnt = 0; + return true; +} +//----------------------------------------------------------------------------- +bool SdioCard::syncBlocks() { + return true; +} +//----------------------------------------------------------------------------- +uint8_t SdioCard::type() { + return m_version2 ? m_highCapacity ? + SD_CARD_TYPE_SDHC : SD_CARD_TYPE_SD2 : SD_CARD_TYPE_SD1; +} +/*---------------------------------------------------------------------------*/ +bool SdioCard::writeBlock(uint32_t lba, const uint8_t* buf) +{ +#if USE_DEBUG_MODE + Serial.print("writeBlock: "); Serial.println(lba); //Serial.print(", buf: "); Serial.println((uint32_t)buf, HEX); +#endif + uint8_t * ptr = (uint8_t *)buf; + if (3 & (uint32_t)ptr) { + Serial.print("writeBlock: "); Serial.print(lba); + Serial.print(", buf: "); Serial.print((uint32_t)ptr, HEX); + //memcpy(aligned, buf, 512); + register uint8_t * src = (uint8_t *)ptr; + ptr = (uint8_t *)aligned; + register uint8_t * dst = ptr; + register uint16_t i = 64; + while ( i-- ) { // do 8 byte copies, is much faster than single byte copy + *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; + *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; + } + } + if (yieldTimeout(isBusyCMD13)) { // wait for previous transmission end + return sdError(SD_CARD_ERROR_CMD13); + } + // send command to start data transfer + if ( !cardCommand(CMD24_XFERTYP, (m_highCapacity ? lba : 512*lba)) ) { + return sdError(SD_CARD_ERROR_CMD24); + } + // prepare SDIO and DMA for data transfer + dmaTrxStart(ptr, 512, TRX_WR); // 1 block, write transfer + + return dmaTrxEnd(0); +} +/*---------------------------------------------------------------------------*/ +bool SdioCard::writeBlocks(uint32_t lba, const uint8_t* buf, size_t n) +{ +#if USE_DEBUG_MODE + Serial.print("writeBlocks: "); Serial.print(lba); + //Serial.print(", buf: "); Serial.print((uint32_t)buf, HEX); + Serial.print(", "); Serial.println(n); +#endif + if (3 & (uint32_t)buf) { // misaligned buffer address, write single blocks + for (size_t i = 0; i < n; i++, lba++, buf += 512) { + if (!writeBlock(lba, buf)) { + return false; // writeBlock will set errorCode. + } + } + return true; + } + if (yieldTimeout(isBusyCMD13)) { + return sdError(SD_CARD_ERROR_CMD13); + } +#if 0 + // set number of blocks to write - this can speed up block write + if ( !cardAcmd(m_rca, ACMD23_XFERTYP, n) ) { + return sdError(SD_CARD_ERROR_ACMD23); + } +#endif + // send command to start data transfer + if ( !cardCommand(CMD25_XFERTYP, (m_highCapacity ? lba : 512*lba)) ) { + return sdError(SD_CARD_ERROR_CMD25); + } + // prepare SDIO and DMA for data transfer + dmaTrxStart((uint8_t *)buf, 512*n, TRX_WR); // n blocks, write transfer + + return dmaTrxEnd(1); +} +/*---------------------------------------------------------------------------*/ +bool SdioCard::writeData(const uint8_t* src) +{ + //Serial.print("writeData: "); Serial.print(m_lba); Serial.print(", cnt: "); Serial.println(m_cnt); + if ( !m_cnt ) return false; + if (yieldTimeout(isBusyCMD13)) { // wait for previous transmission end + return sdError(SD_CARD_ERROR_CMD13); + } + // send command to start block data transfer + if ( !cardCommand(CMD24_XFERTYP, (m_highCapacity ? m_lba : 512*m_lba)) ) { + return sdError(SD_CARD_ERROR_CMD24); + } + // non-DMA block write + trxStart((uint8_t*)src, 512, TRX_WR); + // Receive a data block from the SDIO + register uint32_t STA; // to speed up SDIO flags checking + register uint16_t cnt = 512; + register uint32_t * ptr = (uint32_t*)src; + // pre-fill up the FIFO with 32 words + noInterrupts(); + while ( (cnt--)>(512-32) ) SDIO->FIFO = *ptr++; + interrupts(); + // ----> TIME CRITICAL SECTION BEGIN <---- + do { + STA = SDIO->STA; + if (STA & SDIO_STA_TXFIFOHE) { + // Transmit FIFO half empty, fill up the remaining 16 words + noInterrupts(); + SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++; + SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++; + SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++; + SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++; SDIO->FIFO = *ptr++; + interrupts(); + cnt -= 16; + } + } while ( !(STA & (SDIO_STA_DATAEND | SDIO_STA_TRX_ERROR_FLAGS)) && cnt); + // <---- TIME CRITICAL SECTION END ----> + if ( waitTimeout(isBusyTransferComplete) ) { + return sdError(SD_CARD_ERROR_WRITE_TIMEOUT); + } + m_lba++; + m_cnt--; + if (SDIO->STA&SDIO_STA_TRX_ERROR_FLAGS) { + _panic("writeData error: ", SDIO->STA); + } + return !(SDIO->STA&SDIO_STA_TRX_ERROR_FLAGS); +} +//----------------------------------------------------------------------------- +bool SdioCard::writeStart(uint32_t lba) +{ + m_lba = lba; + m_cnt = 1024; + return true; +} +/*---------------------------------------------------------------------------*/ +// SDHC will do Auto CMD12 after count blocks. +bool SdioCard::writeStart(uint32_t lba, uint32_t count) +{ + //Serial.print("writeStart: "); Serial.print(lba); Serial.print(", cnt: "); Serial.println(count); + m_lba = lba; + m_cnt = count; + return true; +} +/*---------------------------------------------------------------------------*/ +bool SdioCard::writeStop() +{ + //Serial.println("writeStop."); + m_lba = 0; + m_cnt = 0; + return true; +} From 434cb255a56197ab2e686ba04c2ea281ce46ab4f Mon Sep 17 00:00:00 2001 From: victorpv Date: Mon, 11 Sep 2017 21:26:50 -0500 Subject: [PATCH 155/351] F1 SDIO --- STM32F1/libraries/SDIO/SdioF1.h | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 STM32F1/libraries/SDIO/SdioF1.h diff --git a/STM32F1/libraries/SDIO/SdioF1.h b/STM32F1/libraries/SDIO/SdioF1.h new file mode 100644 index 0000000..c995b1c --- /dev/null +++ b/STM32F1/libraries/SDIO/SdioF1.h @@ -0,0 +1,7 @@ + +#ifndef _SDIOF4_H_ +#define _SDIOF4_H_ + +#include + +#endif From 7e1cc92d237ea809b715325cab2aae8366af7b3e Mon Sep 17 00:00:00 2001 From: victorpv Date: Mon, 11 Sep 2017 21:28:07 -0500 Subject: [PATCH 156/351] SDIO --- .../system/libmaple/include/libmaple/sdio.h | 270 ++++++++++++++++++ 1 file changed, 270 insertions(+) create mode 100644 STM32F1/system/libmaple/include/libmaple/sdio.h diff --git a/STM32F1/system/libmaple/include/libmaple/sdio.h b/STM32F1/system/libmaple/include/libmaple/sdio.h new file mode 100644 index 0000000..dec31c8 --- /dev/null +++ b/STM32F1/system/libmaple/include/libmaple/sdio.h @@ -0,0 +1,270 @@ +/****************************************************************************** + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file sdio.h + * @brief Secure digital input/output interface. + */ + +#ifndef _SDIO_H_ +#define _SDIO_H_ + +#include +#include +#include + + +/* +#include +#include + +//#include +#include +//#include + */ + +#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) + +/* + * DMA controller and channel used in STM32F103 + */ + +#define SDIO_DMA_DEV DMA2 +#define SDIO_DMA_CHANNEL DMA_CH4 +/* +#ifdef __cplusplus +extern "C" { +#endif +*/ + +/* + * Register maps and devices + */ + +// SDIO register map type +typedef struct sdio_reg_map { + __io uint32 POWER; // 0x00 + __io uint32 CLKCR; // 0x04 + __io uint32 ARG; // 0x08 + __io uint32 CMD; // 0x0C + __io uint32 RESPCMD; // 0x10 (0x3F) + const uint32 RESP[4]; // 0x14 - contain the card status, which is part of the received response. + __io uint32 DTIMER; // 0x24 - contains the data timeout period, in card bus clock periods. + __io uint32 DLEN; // 0x28 (0x01FF FFFF) - contains the number of data bytes to be transferred + __io uint32 DCTRL; // 0x2C + __io uint32 DCOUNT; // 0x30 (0x01FF FFFF) + __io uint32 STA; // 0x34 + __io uint32 ICR; // 0x38 + __io uint32 MASK; // 0x3C + const uint32 RESERVED1[2]; + __io uint32 FIFOCNT; // 0x48 (0x01FF FFFF) + const uint32 RESERVED2[13]; + __io uint32 FIFO; // 0x80 +} sdio_reg_map; +#define sdio_dev sdio_reg_map + +/** SDIO register map base pointer */ +#define SDIO_BASE ((struct sdio_reg_map*)0x40018000) + +extern sdio_dev * SDIO; + +/* + * Register bit definitions + */ + +/* NOR/PSRAM chip-select control registers */ + +// SDIO_POWER register bits +// At least seven HCLK clock periods are needed between two write accesses to this register. +// After a data write, data cannot be written to this register for three SDIOCLK clock periods +// plus two PCLK2 clock periods. +#define SDIO_POWER_PWRCTRL_OFF 0x00 +#define SDIO_POWER_PWRCTRL_ON 0x03 + +// SDIO_CLKCR register bits +// Controls the SDIO_CK output clock. +// After a data write, data cannot be written to this register for three SDIOCLK clock periods +// plus two PCLK2 clock periods. SDIO_CK can also be stopped during the read wait interval +// for SD I/O cards: in this case the SDIO_CLKCR register does not control SDIO_CK. +#define SDIO_CLKCR_HWFC_EN (1<<14) // HW Flow Control enable - DON'T USE!!! (see errata sheet 2.12.1) + // Overrun errors (Rx mode) and FIFO underrun (Tx mode) + // should be managed by the application software. +#define SDIO_CLKCR_NEGEDGE (1<<13) // SDIO_CK de-phasing selection bit - DON'T USE!!! (see errata sheet 2.12.4) +#define SDIO_CLKCR_WIDBUS (3<<11) // Data bus width +#define SDIO_CLKCR_WIDBUS_1BIT (0<<11) // 1 bit (SDIO_D0 used) +#define SDIO_CLKCR_WIDBUS_4BIT (1<<11) // 4-bit (SDIO_D[3:0] used) +#define SDIO_CLKCR_BYPASS (1<<10) // Clock divider bypass enable bit - SDIO_CK = SDIOCLK, CLKDIV not relevant. +#define SDIO_CLKCR_PWRSAV (1<<9) // 0: SDIO_CK clock is always enabled, 1: SDIO_CK is only enabled when the bus is active +#define SDIO_CLKCR_CLKEN (1<<8) // Clock enable +#define SDIO_CLKCR_CLKDIV (0xFF) // SDIO_CK = SDIOCLK / [CLKDIV + 2] +#define SDIOCLK 72000000UL // SDIO master clock frequency + +// SDIO_CMD register bits +// After a data write, data cannot be written to this register for three SDIOCLK clock periods +// plus two PCLK2 clock periods. +// MultiMediaCards can send two kinds of response: short responses, 48 bits long, or long +// responses,136 bits long. SD card and SD I/O card can send only short responses, the +// argument can vary according to the type of response: the software will distinguish the type +// of response according to the sent command. CE-ATA devices send only short responses. +#define SDIO_CMD_ATACMD (1<<14) +#define SDIO_CMD_NIEN (1<<13) +#define SDIO_CMD_ENCMDCOMPL (1<<12) +#define SDIO_CMD_SDIOSUSPEND (1<<11) +#define SDIO_CMD_CPSMEN (1<<10) +#define SDIO_CMD_WAITPEND (1<<9) +#define SDIO_CMD_WAITINT (1<<8) +#define SDIO_CMD_WAITRESP (3<<6) +#define SDIO_CMD_WAIT_NO_RESP (0<<6) +#define SDIO_CMD_WAIT_SHORT_RESP (1<<6) +#define SDIO_CMD_WAIT_LONG_RESP (3<<6) +#define SDIO_CMD_CMDINDEX (0x3F) + +// SDIO_DLEN register bits +// For a block data transfer, the value in the data length register must be a multiple of the block +// size (see SDIO_DCTRL). A data transfer must be written to the data timer register and the +// data length register before being written to the data control register. +// For an SDIO multibyte transfer the value in the data length register must be between 1 and 512. +#define SDIO_DLEN_DATALENGTH (0x01FFFFFF) + +// SDIO_DCTRL register bits +// Controls the data path state machine (DPSM). +// After a data write, data cannot be written to this register for three SDIOCLK clock periods +// plus two PCLK2 clock periods. +#define SDIO_DCTRL_SDIOEN (1<<11) // the DPSM performs an SD I/O-card-specific operation. +#define SDIO_DCTRL_RWMODE (1<<10) // 0: Read Wait control stopping SDIO_D2, 1:Read Wait control using SDIO_CK +#define SDIO_DCTRL_RWSTOP (1<<9) // 0: Read wait in progress if RWSTART bit is set, 1: Enable for read wait stop if RWSTART bit is set +#define SDIO_DCTRL_RWSTART (1<<8) // read wait operation starts +#define SDIO_DCTRL_DBLOCKSIZE (0xF<<4) // Define the data block length when the block data transfer mode is selected: 2^N bytes +#define SDIO_BLOCKSIZE_64 (6<<4) +#define SDIO_BLOCKSIZE_512 (9<<4) +#define SDIO_DCTRL_DMAEN (1<<3) // DMA enable +#define SDIO_DCTRL_DTMODE (1<<2) // Data transfer mode selection: 0: Block data transfer, 1: Stream or SDIO multi-byte data transfer +#define SDIO_DCTRL_DTDIR (1<<1) // Data transfer direction selection: 0: From controller to card, 1: From card to controller. +#define SDIO_DIR_TX (0<<1) +#define SDIO_DIR_RX (1<<1) +#define SDIO_DCTRL_DTEN (1<<0) // Start data transfer. Depending on the direction bit, DTDIR, + // the DPSM moves to the Wait_S, Wait_R state or Readwait if RW Start is set immediately at + // the beginning of the transfer. It is not necessary to clear the enable bit after the end of a data + // transfer but the SDIO_DCTRL must be updated to enable a new data transfer +// The meaning of the DTMODE bit changes according to the value of the SDIOEN bit: +// When DTEN=0 and DTMODE=1, the MultiMediaCard stream mode is enabled. +// When DTEN=1 and DTMODE=1, the peripheral enables an SDIO multi-byte transfer. + +// SDIO_STA register bits +#define SDIO_STA_CEATAEND (1<<23) // CE-ATA command completion signal received for CMD61 +#define SDIO_STA_SDIOIT (1<<22) // SDIO interrupt received +#define SDIO_STA_RXDAVL (1<<21) // Data available in receive FIFO +#define SDIO_STA_TXDAVL (1<<20) // Data available in transmit FIFO +#define SDIO_STA_RXFIFOE (1<<19) // Receive FIFO empty +#define SDIO_STA_TXFIFOE (1<<18) // Transmit FIFO empty (2 words) +#define SDIO_STA_RXFIFOF (1<<17) // Receive FIFO full (2 words before the FIFO is full.) +#define SDIO_STA_TXFIFOF (1<<16) // Transmit FIFO full +#define SDIO_STA_RXFIFOHF (1<<15) // Receive FIFO half full: there are at least 8 words in the FIFO +#define SDIO_STA_TXFIFOHE (1<<14) // Transmit FIFO half empty: at least 8 words can be written into the FIFO +#define SDIO_STA_RXACT (1<<13) // Data receive in progress +#define SDIO_STA_TXACT (1<<12) // Data transmit in progress +#define SDIO_STA_CMDACT (1<<11) // Command transfer in progress +#define SDIO_STA_DBCKEND (1<<10) // Data block sent/received (CRC check passed) +#define SDIO_STA_STBITERR (1<<9) // Start bit not detected on all data signals in wide bus mode +#define SDIO_STA_DATAEND (1<<8) // Data end (data counter SDIOCOUNT is zero) +#define SDIO_STA_CMDSENT (1<<7) // Command sent (no response required) +#define SDIO_STA_CMDREND (1<<6) // Command response received (CRC check passed) +#define SDIO_STA_RXOVERR (1<<5) // Received FIFO overrun error +#define SDIO_STA_TXUNDERR (1<<4) // Transmit FIFO underrun error +#define SDIO_STA_DTIMEOUT (1<<3) // Data timeout +#define SDIO_STA_CTIMEOUT (1<<2) // Command response timeout. The Command TimeOut period has a fixed value of 64 SDIO_CK clock periods. +#define SDIO_STA_DCRCFAIL (1<<1) // Data block sent/received (CRC check failed) +#define SDIO_STA_CCRCFAIL (1<<0) // Command response received (CRC check failed) + +#define SDIO_STA_CMD_ERROR_FLAGS (SDIO_STA_CTIMEOUT | SDIO_STA_CCRCFAIL) +#define SDIO_STA_TRX_ERROR_FLAGS (SDIO_STA_STBITERR | SDIO_STA_RXOVERR | SDIO_STA_TXUNDERR | SDIO_STA_DTIMEOUT | SDIO_STA_DCRCFAIL) +#define SDIO_STA_TRX_ACT_FLAGS (SDIO_STA_RXACT|SDIO_STA_TXACT) + +// SDIO_ICR register bits (WO - write only) +#define SDIO_ICR_CEATAENDC (1<<23) // clear CEATAEND flag +#define SDIO_ICR_SDIOITC (1<<22) // clear SDIOIT flag +#define SDIO_ICR_DBCKENDC (1<<10) // clear DBCKENDC flag +#define SDIO_ICR_STBITERRC (1<<9) // clear STBITERRC flag +#define SDIO_ICR_DATAENDC (1<<8) // clear DATAENDC flag +#define SDIO_ICR_CMDSENTC (1<<7) // clear CMDSENTC flag +#define SDIO_ICR_CMDRENDC (1<<6) // clear CMDREND flag +#define SDIO_ICR_RXOVERRC (1<<5) // clear RXOVERR flag +#define SDIO_ICR_TXUNDERRC (1<<4) // clear TXUNDERR flag +#define SDIO_ICR_DTIMEOUTC (1<<3) // clear DTIMEOUT flag +#define SDIO_ICR_CTIMEOUTC (1<<2) // clear CTIMEOUT flag +#define SDIO_ICR_DCRCFAILC (1<<1) // clear DCRCFAIL flag +#define SDIO_ICR_CCRCFAILC (1<<0) // clear CCRCFAIL flag + +#define SDIO_ICR_CMD_FLAGS (SDIO_ICR_CEATAENDC | SDIO_ICR_SDIOITC | SDIO_ICR_CMDSENTC | SDIO_ICR_CMDRENDC | SDIO_ICR_CTIMEOUTC | SDIO_ICR_CCRCFAILC) +#define SDIO_ICR_DATA_FLAGS (SDIO_ICR_DBCKENDC | SDIO_ICR_STBITERRC | SDIO_ICR_DATAENDC | SDIO_ICR_RXOVERRC | SDIO_ICR_TXUNDERRC | SDIO_ICR_DTIMEOUTC | SDIO_ICR_DCRCFAILC) + +// SDIO_MASK register bits +// Determines which status flags generate an interrupt request by setting the corresponding bit to 1b. +#define SDIO_MASK_CEATAENDIE (1<<23) // enable CEATAEND interrupt +#define SDIO_MASK_SDIOITIE (1<<22) // enable SDIOIT interrupt +#define SDIO_MASK_RXDAVLIE (1<<21) // enable RXDAVL interrupt +#define SDIO_MASK_TXDAVLIE (1<<20) // enable TXDAVL interrupt +#define SDIO_MASK_RXFIFOEIE (1<<19) // enable RXFIFOE interrupt +#define SDIO_MASK_TXFIFOEIE (1<<18) // enable TXFIFOE interrupt +#define SDIO_MASK_RXFIFOFIE (1<<17) // enable RXFIFOF interrupt +#define SDIO_MASK_TXFIFOFIE (1<<16) // enable TXFIFOF interrupt +#define SDIO_MASK_RXFIFOHFIE (1<<15) // enable RXFIFOHF interrupt +#define SDIO_MASK_TXFIFOHEIE (1<<14) // enable TXFIFOHE interrupt +#define SDIO_MASK_RXACTIE (1<<13) // enable RXACT interrupt +#define SDIO_MASK_TXACTIE (1<<12) // enable TXACT interrupt +#define SDIO_MASK_CMDACTIE (1<<11) // enable CMDACT interrupt +#define SDIO_MASK_DBCKENDIE (1<<10) // enable DBCKENDC interrupt +#define SDIO_MASK_STBITERRIE (1<<9) // enable STBITERR interrupt +#define SDIO_MASK_DATAENDIE (1<<8) // enable DATAENDC interrupt +#define SDIO_MASK_CMDSENTIE (1<<7) // enable CMDSENTC interrupt +#define SDIO_MASK_CMDRENDIE (1<<6) // enable CMDREND interrupt +#define SDIO_MASK_RXOVERRIE (1<<5) // enable RXOVERR interrupt +#define SDIO_MASK_TXUNDERRIE (1<<4) // enable TXUNDERR interrupt +#define SDIO_MASK_DTIMEOUTIE (1<<3) // enable DTIMEOUT interrupt +#define SDIO_MASK_CTIMEOUTIE (1<<2) // enable CTIMEOUT interrupt +#define SDIO_MASK_DCRCFAILIE (1<<1) // enable DCRCFAIL interrupt +#define SDIO_MASK_CCRCFAILIE (1<<0) // enable CCRCFAIL interrupt + + +void sdio_enable(void); +void sdio_disable(void); +void sdio_begin(void); +uint8_t sdio_cmd_send(uint16_t cmd_index_resp_type, uint32_t arg); +void sdio_set_clock(uint32_t clk); +void sdio_set_dbus_width(uint16_t bus_w); +void sdio_set_dblock_size(uint8_t dbsize); +//void sdio_trx_enable(uint8_t dir); +inline void sdio_trx_enable(void) +{ + SDIO->DCTRL |= SDIO_DCTRL_DTEN; // enable data transfer +} + +inline uint32_t sdio_cmd_xfer_ongoing(void) { return (SDIO->STA&SDIO_STA_CMDACT); } +inline uint32_t sdio_cmd_complete(void) { return (SDIO->STA&SDIO_STA_CMDSENT); } + +inline void sdio_setup_transfer(uint32_t dtimer, uint32_t dlen, uint16_t flags) +{ + SDIO->ICR = SDIO_ICR_DATA_FLAGS; // clear data access relevant flags + SDIO->DTIMER = dtimer; + SDIO->DLEN = dlen; + SDIO->DCTRL = flags;// | SDIO_DCTRL_DTEN; // enable data transfer +} + +/* +#ifdef __cplusplus +} // extern "C" +#endif +*/ + +#endif /* (STM32_HIGH_DENSITY) || (STM32_XL_DENSITY) */ + +#endif From 8929bbbde08b1896626c9c2b50e1c865804e918d Mon Sep 17 00:00:00 2001 From: victorpv Date: Mon, 11 Sep 2017 21:29:33 -0500 Subject: [PATCH 157/351] F1 SDIO --- STM32F1/cores/maple/sdio.cpp | 198 +++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 STM32F1/cores/maple/sdio.cpp diff --git a/STM32F1/cores/maple/sdio.cpp b/STM32F1/cores/maple/sdio.cpp new file mode 100644 index 0000000..8bd9491 --- /dev/null +++ b/STM32F1/cores/maple/sdio.cpp @@ -0,0 +1,198 @@ +/****************************************************************************** + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/sdio.c + * @author stevstrong + * @brief Secure digital input/output interface. + */ + +#include +#include +#include +#include "wirish.h" + + +//#include +//#include +//#include +//#include "wirish.h" +//#include "boards.h" +// + +#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) + +sdio_dev * SDIO = SDIO_BASE; + +#define DELAY_LONG 10 +#define DELAY_SHORT 1 + +uint8_t dly = DELAY_LONG; // microseconds delay after accessing registers + +/* + * SDIO convenience routines + */ +void sdio_gpios_init(void) +{ + gpio_set_mode(PIN_MAP[BOARD_SDIO_D0].gpio_device, PIN_MAP[BOARD_SDIO_D0].gpio_bit, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PIN_MAP[BOARD_SDIO_D1].gpio_device, PIN_MAP[BOARD_SDIO_D1].gpio_bit, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PIN_MAP[BOARD_SDIO_D2].gpio_device, PIN_MAP[BOARD_SDIO_D2].gpio_bit, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PIN_MAP[BOARD_SDIO_D3].gpio_device, PIN_MAP[BOARD_SDIO_D3].gpio_bit, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PIN_MAP[BOARD_SDIO_CLK].gpio_device, PIN_MAP[BOARD_SDIO_CLK].gpio_bit, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PIN_MAP[BOARD_SDIO_CMD].gpio_device, PIN_MAP[BOARD_SDIO_CMD].gpio_bit, GPIO_AF_OUTPUT_PP); + /* + * Todo just remove it, not needed for F1. + */ + /* + gpio_set_af_mode(BOARD_SDIO_D0, 12); + gpio_set_af_mode(BOARD_SDIO_D1, 12); + gpio_set_af_mode(BOARD_SDIO_D2, 12); + gpio_set_af_mode(BOARD_SDIO_D3, 12); + gpio_set_af_mode(BOARD_SDIO_CLK, 12); + gpio_set_af_mode(BOARD_SDIO_CMD, 12); + */ +} + +void sdio_gpios_deinit(void) +{ + gpio_set_mode(PIN_MAP[BOARD_SDIO_D0].gpio_device, PIN_MAP[BOARD_SDIO_D0].gpio_bit, GPIO_INPUT_FLOATING); + gpio_set_mode(PIN_MAP[BOARD_SDIO_D1].gpio_device, PIN_MAP[BOARD_SDIO_D1].gpio_bit, GPIO_INPUT_FLOATING); + gpio_set_mode(PIN_MAP[BOARD_SDIO_D2].gpio_device, PIN_MAP[BOARD_SDIO_D2].gpio_bit, GPIO_INPUT_FLOATING); + gpio_set_mode(PIN_MAP[BOARD_SDIO_D3].gpio_device, PIN_MAP[BOARD_SDIO_D3].gpio_bit, GPIO_INPUT_FLOATING); + gpio_set_mode(PIN_MAP[BOARD_SDIO_CLK].gpio_device, PIN_MAP[BOARD_SDIO_CLK].gpio_bit, GPIO_INPUT_FLOATING); + gpio_set_mode(PIN_MAP[BOARD_SDIO_CMD].gpio_device, PIN_MAP[BOARD_SDIO_CMD].gpio_bit, GPIO_INPUT_FLOATING); + + /* + * Todo just remove it, not needed for F1. + */ + /* + gpio_set_af_mode(BOARD_SDIO_D0, 0); + gpio_set_af_mode(BOARD_SDIO_D1, 0); + gpio_set_af_mode(BOARD_SDIO_D2, 0); + gpio_set_af_mode(BOARD_SDIO_D3, 0); + gpio_set_af_mode(BOARD_SDIO_CLK, 0); + gpio_set_af_mode(BOARD_SDIO_CMD, 0); + */ +} + +/** + * @brief Initialize and reset the SDIO device. + */ +void sdio_init(void) +{ + rcc_clk_enable(RCC_SDIO); + rcc_reset_dev(RCC_SDIO); +} + +void sdio_power_on(void) +{ + SDIO->POWER = SDIO_POWER_PWRCTRL_ON; +// After a data write, data cannot be written to this register for three SDIOCLK clock periods +// plus two PCLK2 clock periods. + delay_us(DELAY_LONG); +} + +void sdio_power_off(void) +{ + SDIO->POWER = SDIO_POWER_PWRCTRL_OFF; +// After a data write, data cannot be written to this register for three SDIOCLK clock periods +// plus two PCLK2 clock periods. + delay_us(DELAY_LONG); +} + +void sdio_set_clock(uint32_t clk) +{ + if (clk>24000000UL) clk = 24000000UL; // limit the SDIO master clock to 24MHz + + if (clk<1000000) dly = DELAY_LONG; + else dly = DELAY_SHORT; + + sdio_disable(); + SDIO->CLKCR = (SDIO->CLKCR & (~(SDIO_CLKCR_CLKDIV|SDIO_CLKCR_BYPASS))) | SDIO_CLKCR_CLKEN | (((SDIOCLK/clk)-2)&SDIO_CLKCR_CLKDIV); + delay_us(dly); +} + +void sdio_set_dbus_width(uint16_t bus_w) +{ + SDIO->CLKCR = (SDIO->CLKCR & (~SDIO_CLKCR_WIDBUS)) | bus_w; + delay_us(dly); +} + +void sdio_set_dblock_size(uint8_t dbsize) +{ + SDIO->DCTRL = (SDIO->DCTRL&(~SDIO_DCTRL_DBLOCKSIZE)) | ((dbsize&0xF)<<4); + delay_us(dly); +} + +void sdio_enable(void) +{ + SDIO->CLKCR |= SDIO_CLKCR_CLKEN; + delay_us(dly); +} + +void sdio_disable(void) +{ + SDIO->CLKCR ^= SDIO_CLKCR_CLKEN; + delay_us(dly); +} + +/** + * @brief Configure and enable the SDIO device. + */ +void sdio_begin(void) +{ + sdio_gpios_init(); + sdio_init(); + sdio_power_on(); + // Set initial SCK rate. + sdio_set_clock(400000); + delay_us(200); // generate 80 pulses at 400kHz +} + +/** + * @brief Disables the SDIO device. + */ +void sdio_end(void) +{ + sdio_disable(); + while ( sdio_cmd_xfer_ongoing() ); + sdio_power_off(); + rcc_clk_disable(RCC_SDIO); + sdio_gpios_deinit(); +} + +/** + * @brief Send command by the SDIO device. + */ +uint8_t sdio_cmd_send(uint16_t cmd_index_resp_type, uint32_t arg) +{ + uint8_t retries = 10; // in case of errors + do { // retry command if errors detected + // clear interrupt flags - IMPORTANT!!! + SDIO->ICR = SDIO_ICR_CMD_FLAGS; + // write command + SDIO->ARG = arg; + SDIO->CMD = (uint32_t)(SDIO_CMD_CPSMEN | cmd_index_resp_type ); + while ( (SDIO->STA&SDIO_STA_CMDACT) ) ; // wait for actual command transfer to finish + // wait for response, if the case + if ( cmd_index_resp_type&(SDIO_CMD_WAIT_SHORT_RESP|SDIO_CMD_WAIT_LONG_RESP) ) { + while ( !(SDIO->STA&(SDIO_STA_CMDREND|SDIO_STA_CMD_ERROR_FLAGS)) ) ; + } else break; // no response required + if ( SDIO->STA&(SDIO_STA_CMDREND|SDIO_STA_CTIMEOUT) ) + break; // response received or timeout + // ignore CRC error for CMD5 and ACMD41 + if ( ((cmd_index_resp_type&SDIO_CMD_CMDINDEX)==5) || ((cmd_index_resp_type&SDIO_CMD_CMDINDEX)==41) ) + break; + } while ( (--retries) ); + return (uint8_t)retries; +} + +#endif // defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) From 1db95cf251f8100610fd716fbe7a5f970b931207 Mon Sep 17 00:00:00 2001 From: victorpv Date: Mon, 11 Sep 2017 21:40:25 -0500 Subject: [PATCH 158/351] F1 SDIO --- STM32F1/variants/generic_stm32f103r/board/board.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/STM32F1/variants/generic_stm32f103r/board/board.h b/STM32F1/variants/generic_stm32f103r/board/board.h index 0719afa..925c882 100644 --- a/STM32F1/variants/generic_stm32f103r/board/board.h +++ b/STM32F1/variants/generic_stm32f103r/board/board.h @@ -102,6 +102,16 @@ #define BOARD_USB_DISC_DEV GPIOC #define BOARD_USB_DISC_BIT 12 +/* + * SDIO Pins + */ +#define BOARD_SDIO_D0 PC8 +#define BOARD_SDIO_D1 PC9 +#define BOARD_SDIO_D2 PC10 +#define BOARD_SDIO_D3 PC11 +#define BOARD_SDIO_CLK PC12 +#define BOARD_SDIO_CMD PD2 + /* Pin aliases: these give the GPIO port/bit for each pin as an * enum. These are optional, but recommended. They make it easier to * write code using low-level GPIO functionality. */ From 799f2b3b8a42a180879260dff910d682e3a2d104 Mon Sep 17 00:00:00 2001 From: victorpv Date: Mon, 11 Sep 2017 22:01:55 -0500 Subject: [PATCH 159/351] Correct issue with port speed not changing. The current implementation will not change speed if Wire.setClock is called after begin() since the flags are only applied when the port is enabled from being disabled. Corrected that by adding 2 lines to disable the port, and then enable it again with the new settings. Tested and confirmed the new speed is applied. --- STM32F1/libraries/Wire/Wire.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/STM32F1/libraries/Wire/Wire.cpp b/STM32F1/libraries/Wire/Wire.cpp index c4e9bef..3f5f161 100644 --- a/STM32F1/libraries/Wire/Wire.cpp +++ b/STM32F1/libraries/Wire/Wire.cpp @@ -97,7 +97,8 @@ void HardWire::setClock(uint32_t frequencyHz) dev_flags &= ~I2C_FAST_MODE;// clear FAST_MODE bit break; } - + i2c_disable(sel_hard); + i2c_master_enable(sel_hard, dev_flags); } HardWire Wire(1); From a530b6a3d46385586e6ece1202ee505c09157150 Mon Sep 17 00:00:00 2001 From: victorpv Date: Mon, 11 Sep 2017 22:49:03 -0500 Subject: [PATCH 160/351] Update Wire.cpp Adds a check to verify if the port had been already enabled, and only in that case disables/re-enables the port. This also solves the issue of setClock being called after begin(), but doesn't not enable the port if begin() had not been called yet. --- STM32F1/libraries/Wire/Wire.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/STM32F1/libraries/Wire/Wire.cpp b/STM32F1/libraries/Wire/Wire.cpp index 3f5f161..a026e2e 100644 --- a/STM32F1/libraries/Wire/Wire.cpp +++ b/STM32F1/libraries/Wire/Wire.cpp @@ -97,8 +97,10 @@ void HardWire::setClock(uint32_t frequencyHz) dev_flags &= ~I2C_FAST_MODE;// clear FAST_MODE bit break; } - i2c_disable(sel_hard); - i2c_master_enable(sel_hard, dev_flags); + if (sel_hard->regs->CR1 & I2C_CR1_PE){ + i2c_disable(sel_hard); + i2c_master_enable(sel_hard, dev_flags); + } } HardWire Wire(1); From 7752fc68f2860afc096c707529d740f3766268f2 Mon Sep 17 00:00:00 2001 From: csnol Date: Wed, 13 Sep 2017 04:08:04 +0800 Subject: [PATCH 161/351] add attachAlarmInterrupt() detachAlarmInterrupt() --- STM32F1/libraries/RTClock/src/RTClock.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/STM32F1/libraries/RTClock/src/RTClock.cpp b/STM32F1/libraries/RTClock/src/RTClock.cpp index cc7b63e..deefcf0 100644 --- a/STM32F1/libraries/RTClock/src/RTClock.cpp +++ b/STM32F1/libraries/RTClock/src/RTClock.cpp @@ -201,6 +201,18 @@ time_t RTClock::makeTime(tm_t & tmm) rtc_detach_interrupt(RTC_SECONDS_INTERRUPT); } + void RTClock::attachAlarmInterrupt(voidFuncPtr function, time_t alarm_time) { // Don't need run RTClock::setAlarmTime(time_t alarm_time) + rtc_set_alarm(alarm_time); + rtc_attach_interrupt(RTC_ALARM_GLOBAL_INTERRUPT, function); + } + + void RTClock::attachAlarmInterrupt(voidFuncPtr function) { // Must run RTClock::setAlarmTime (time_t alarm_time or tm_t & alarm_tm) first + rtc_attach_interrupt(RTC_ALARM_GLOBAL_INTERRUPT, function); + } + + void RTClock::detachAlarmInterrupt() { + rtc_detach_interrupt(RTC_ALARM_GLOBAL_INTERRUPT); + } void RTClock::createAlarm(voidFuncPtr function, tm_t & alarm_tm) { time_t alarm = makeTime(alarm_tm);//convert to time_t From a87ad87fa71bb7190b2e6bdc94d097752c4cd359 Mon Sep 17 00:00:00 2001 From: csnol Date: Wed, 13 Sep 2017 04:10:25 +0800 Subject: [PATCH 162/351] add attachAlarmInterrupt and detachAlarmInterrupt --- STM32F1/libraries/RTClock/src/RTClock.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/STM32F1/libraries/RTClock/src/RTClock.h b/STM32F1/libraries/RTClock/src/RTClock.h index 711992e..aa97ac9 100644 --- a/STM32F1/libraries/RTClock/src/RTClock.h +++ b/STM32F1/libraries/RTClock/src/RTClock.h @@ -78,6 +78,10 @@ class RTClock { void attachSecondsInterrupt(voidFuncPtr function); void detachSecondsInterrupt(); + void attachAlarmInterrupt(voidFuncPtr function); + void attachAlarmInterrupt(voidFuncPtr function, time_t alarm_time); + void detachAlarmInterrupt(); + void setAlarmTime (tm_t & tm_ptr); void setAlarmTime (time_t alarm_time); @@ -89,4 +93,4 @@ class RTClock { #endif // _RTCLOCK_H_ - \ No newline at end of file + From 30f8527eaa67d78fdffdc475a5620bda36bac87e Mon Sep 17 00:00:00 2001 From: csnol Date: Wed, 13 Sep 2017 10:53:08 +0800 Subject: [PATCH 163/351] added TimeZone(time_t xxx, timezone); Usage: time_t localtime; localtime = TimeZone(UnixTime, 8); // Beijing timezone = 8 --- STM32F1/libraries/RTClock/src/RTClock.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/STM32F1/libraries/RTClock/src/RTClock.h b/STM32F1/libraries/RTClock/src/RTClock.h index aa97ac9..74f7397 100644 --- a/STM32F1/libraries/RTClock/src/RTClock.h +++ b/STM32F1/libraries/RTClock/src/RTClock.h @@ -72,6 +72,8 @@ class RTClock { uint8_t second(time_t t) { breakTime(t, tmm); return tmm.second; } uint8_t isPM(time_t t) { return (hour(t)>=12); } + time_t TimeZone(time_t t, uint8_t TZ) { return ( t - (TZ * SECS_PER_HOUR)); } // usage: localtime = TimeZone(UnixTime, 8); // Beijing timezone = 8 + void createAlarm(voidFuncPtr function, time_t alarm_time_t); void createAlarm(voidFuncPtr function, struct tm_t & alarm_tm); From 6be069cdb6094bd3957f65184625f4e20287e3d0 Mon Sep 17 00:00:00 2001 From: csnol Date: Wed, 13 Sep 2017 11:02:24 +0800 Subject: [PATCH 164/351] change TZ from unit_8 to int, negatives timezone usage: localtime = TimeZone(UnixTime, -7); // CA USA = -7 --- STM32F1/libraries/RTClock/src/RTClock.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/libraries/RTClock/src/RTClock.h b/STM32F1/libraries/RTClock/src/RTClock.h index 74f7397..e67fcb3 100644 --- a/STM32F1/libraries/RTClock/src/RTClock.h +++ b/STM32F1/libraries/RTClock/src/RTClock.h @@ -72,7 +72,7 @@ class RTClock { uint8_t second(time_t t) { breakTime(t, tmm); return tmm.second; } uint8_t isPM(time_t t) { return (hour(t)>=12); } - time_t TimeZone(time_t t, uint8_t TZ) { return ( t - (TZ * SECS_PER_HOUR)); } // usage: localtime = TimeZone(UnixTime, 8); // Beijing timezone = 8 + time_t TimeZone(time_t t, int TZ) { return ( t - (TZ * SECS_PER_HOUR)); } // usage: localtime = TimeZone(UnixTime, 8); // Beijing timezone = 8 void createAlarm(voidFuncPtr function, time_t alarm_time_t); void createAlarm(voidFuncPtr function, struct tm_t & alarm_tm); From ed797d43e530087dd8d9deaf3a5684df49c3e1bd Mon Sep 17 00:00:00 2001 From: csnol Date: Thu, 14 Sep 2017 00:03:55 +0800 Subject: [PATCH 165/351] Tested on BluePill for new function of RTC --- .../BlutPill-RTClock-test.ino | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 STM32F1/libraries/RTClock/examples/BlutPill-RTClock-test/BlutPill-RTClock-test.ino diff --git a/STM32F1/libraries/RTClock/examples/BlutPill-RTClock-test/BlutPill-RTClock-test.ino b/STM32F1/libraries/RTClock/examples/BlutPill-RTClock-test/BlutPill-RTClock-test.ino new file mode 100644 index 0000000..b6e6610 --- /dev/null +++ b/STM32F1/libraries/RTClock/examples/BlutPill-RTClock-test/BlutPill-RTClock-test.ino @@ -0,0 +1,130 @@ +/* STM32F103C8 Blue Pill ( PC13) + + Serialport set and display RTC clock , Write by CSNOL https://github.com/csnol/STM32-Examples + based on https://github.com/rogerclarkmelbourne/Arduino_STM32 + + 1. Blink on PC13 per 4s or 7s by attachAlarmInterrupt for 10 times + 2. Second counter by attachSecondsInterrpt + 3. Serial output on(41s) or off(21s) by creatAlarm + 4. change to your timezone in the sketch; . + 3. get Unix epoch time from https://www.epochconverter.com/ ; + 4. last step input the 10 bits number( example: 1503945555) to Serialport ; + 5. the clock will be reset to you wanted. + + ## Why the 10 bits Unix epoch time be used? +****Because I wanna connect to NTP server by ESP-8266. +****in the library. getNtpTime() will return this 10 bits Unix epoch time. +*/ + + +#include + +RTClock rtclock (RTCSEL_LSE); // initialise +int timezone = 8; // change to your timezone +time_t tt; +time_t tt1; +tm_t mtt = { 47, 9, 13, 3, 1, 22, 30, 30 }; // init time 47+1970 = 2017 Unix epoch Time counted from 00:00:00 1 Jan 1970 +char weekday1[][7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; // 0,1,2,3,4,5,6 +uint8_t dateread[11]; +int globAlmCount = 0; +int lastGlobAlmCount; +int SPECAlmCount = 0; +int lastSPECAlmCount; +int i = 0; +int alarmcount = 3; +uint8_t AlarmExchange = 0; +bool dispflag = true; + +#define LED_PIN PC13 + +// This function is called in the attachSecondsInterrpt +void SecondCount () +{ + tt++; +} +// This function is called in the attachAlarmInterrpt +void blink () +{ + digitalWrite(LED_PIN, !digitalRead(LED_PIN)); + globAlmCount++; + //tt++; +} + +void OnOffSerial () +{ + dispflag = !dispflag; + SPECAlmCount++; +} + +void setup() +{ + lastGlobAlmCount = ~globAlmCount; + lastSPECAlmCount = ~SPECAlmCount; + Serial.begin(115200); + pinMode(LED_PIN, OUTPUT); + tt = rtclock.makeTime(mtt); + tt1 = tt; + rtclock.attachAlarmInterrupt(blink);// Call blink + rtclock.attachSecondsInterrupt(SecondCount);// Call SecondCount +} + +void loop() +{ + while (Serial.available()) + { dateread[i] = Serial.read(); + if (i < 11) { + i++; + } + else { + i = 0; + tt = (dateread[0] - '0') * 1000000000 + (dateread[1] - '0') * 100000000 + (dateread[2] - '0') * 10000000 + (dateread[3] - '0') * 1000000 + (dateread[4] - '0') * 100000; + tt += (dateread[5] - '0') * 10000 + (dateread[6] - '0') * 1000 + (dateread[7] - '0') * 100 + (dateread[8] - '0') * 10 + (dateread[9] - '0'); + tt = rtclock.TimeZone(tt, timezone); //adjust to your local date + } + } + if (lastGlobAlmCount != globAlmCount | lastSPECAlmCount != SPECAlmCount ) { + if (globAlmCount == 10) { // to detachAlarmInterrupt and start creatAlarm after 10 times about 110s + rtclock.detachAlarmInterrupt(); + globAlmCount = 0; + rtclock.createAlarm(OnOffSerial, (rtclock.getTime() + 20)); // call OnOffSerial stop output date from Serial after 2 mins + alarmcount = 20; //change to creatAlarm 21S close Serial output and 41s open Serial output. + } + else { + lastGlobAlmCount = globAlmCount; + lastSPECAlmCount = SPECAlmCount; + Serial.println(" Say hello to every guys "); + if(dispflag == false) + Serial.println(" SPECAlarm turn Display Off "); + switch (AlarmExchange) { + case 0: + rtclock.setAlarmTime(rtclock.getTime() + alarmcount); // reset alarm = current time + 4s for attachAlarmInterrupt, 21s for creatAlarm + AlarmExchange = 1; + break; + case 1: + rtclock.breakTime(rtclock.getTime() + alarmcount * 2, mtt); //// reset alarm = current time + 7s for attachAlarmInterrupt, 41s for creatAlarm + rtclock.setAlarmTime(mtt); + AlarmExchange = 0; + break; + } + } + } + if (tt1 != tt & dispflag == true ) + { + tt1 = tt; + rtclock.breakTime(tt, mtt); + Serial.print("Date: "); + Serial.print(mtt.day); + Serial.print("- "); + Serial.print(mtt.month); + Serial.print(" "); + Serial.print(mtt.year + 1970); + Serial.print(" "); + Serial.print(weekday1[mtt.weekday]); + Serial.print(" Time: "); + Serial.print(mtt.hour); + Serial.print(" : "); + Serial.print(mtt.minute); + Serial.print(" : "); + Serial.println(mtt.second); + } +} From 2d6abe679aeaa4d12e19d6a3e3f234b418b956c9 Mon Sep 17 00:00:00 2001 From: csnol Date: Thu, 14 Sep 2017 15:05:42 +0800 Subject: [PATCH 166/351] Add keywords for new functions --- STM32F1/libraries/RTClock/keywords.txt | 29 +++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/STM32F1/libraries/RTClock/keywords.txt b/STM32F1/libraries/RTClock/keywords.txt index ddd0680..31bf13e 100644 --- a/STM32F1/libraries/RTClock/keywords.txt +++ b/STM32F1/libraries/RTClock/keywords.txt @@ -5,16 +5,35 @@ ####################################### # Datatypes (KEYWORD1) ####################################### -RTClock KEYWORD1 + +RTClock KEYWORD1 -setTime KEYWORD2 -getTime KEYWORD2 +setTime KEYWORD2 +getTime KEYWORD2 + +createAlarm KEYWORD2 +setAlarmTime KEYWORD2 -createAlarm KEYWORD2 attachSecondsInterrupt KEYWORD2 detachSecondsInterrupt KEYWORD2 -setAlarmTime KEYWORD2 + +attachAlarmInterrupt KEYWORD2 +detachAlarmInterrupt KEYWORD2 + +breakTime KEYWORD2 +makeTime KEYWORD2 + +TimeZone KEYWORD2 +now KEYWORD2 +year KEYWORD2 +month KEYWORD2 +day KEYWORD2 +weekday KEYWORD2 +hour KEYWORD2 +minute KEYWORD2 +second KEYWORD2 +isPM KEYWORD2 ####################################### From fa7bcde3cd21b50fd23b5ef3e10cf0445aed75ea Mon Sep 17 00:00:00 2001 From: csnol Date: Thu, 14 Sep 2017 16:05:28 +0800 Subject: [PATCH 167/351] Update example for Chinese friends. timezone and filename error --- .../BluePill-RTClock-test.ino} | 31 ++++++++++++------- STM32F1/libraries/RTClock/src/RTClock.h | 4 +-- 2 files changed, 22 insertions(+), 13 deletions(-) rename STM32F1/libraries/RTClock/examples/{BlutPill-RTClock-test/BlutPill-RTClock-test.ino => BluePill-RTClock-test/BluePill-RTClock-test.ino} (74%) diff --git a/STM32F1/libraries/RTClock/examples/BlutPill-RTClock-test/BlutPill-RTClock-test.ino b/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino similarity index 74% rename from STM32F1/libraries/RTClock/examples/BlutPill-RTClock-test/BlutPill-RTClock-test.ino rename to STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino index b6e6610..d49025a 100644 --- a/STM32F1/libraries/RTClock/examples/BlutPill-RTClock-test/BlutPill-RTClock-test.ino +++ b/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino @@ -14,6 +14,13 @@ ## Why the 10 bits Unix epoch time be used? ****Because I wanna connect to NTP server by ESP-8266. ****in the library. getNtpTime() will return this 10 bits Unix epoch time. +* +* å—¨ï¼æœ‹å‹ä»¬ï¼Œ 这是一个STM32F10x系列的RTC应用的例å­ï¼Œå¸Œæœ›å¯¹ä½ çš„ç¼–ç æœ‰æ‰€å¸®åŠ© +* 这个程åºåŸºäºŽhttps://github.com/rogerclarkmelbourne/Arduino_STM32 , 感谢所有贡献者的付出。 +* 程åºæµ‹è¯•äº† F10x系列RTC çš„ 几ç§ä¸­æ–­ï¼Œ 并通过LED和串å£è¿›è¡Œè¡¨è¾¾ã€‚ +* RTClock 使用 UTC 作为时间标准, ä½ å¯ä»¥ä»Žhttps://www.epochconverter.com/ 获得 Unix epoch time数值 +* 并通过串å£è¿›è¡Œè®¾ç½®ï¼Œ 当然你也å¯ä»¥ç•¥å¾®ä¿®æ”¹ä¸€ä¸‹ä¸²å£æŽ¥æ”¶å¤„ç†æ–¹æ³•ï¼Œç›´æŽ¥ä»Žä¸²å£æŽ¥æ”¶æ—¥æœŸå½¢å¼ã€‚如 2017-9-13-10:30:00, +* å¦å¤–一个方法是通过ESP8266获å–NTP网络时间,并定期å‘é€ç»™F10x进行更新。 */ @@ -23,7 +30,7 @@ RTClock rtclock (RTCSEL_LSE); // initialise int timezone = 8; // change to your timezone time_t tt; time_t tt1; -tm_t mtt = { 47, 9, 13, 3, 1, 22, 30, 30 }; // init time 47+1970 = 2017 Unix epoch Time counted from 00:00:00 1 Jan 1970 +tm_t mtt = { 47, 9, 13, 3, 11, 22, 30, 30 }; // init time 47+1970 = 2017 Unix epoch Time counted from 00:00:00 1 Jan 1970 char weekday1[][7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; // 0,1,2,3,4,5,6 uint8_t dateread[11]; int globAlmCount = 0; @@ -62,7 +69,8 @@ void setup() lastSPECAlmCount = ~SPECAlmCount; Serial.begin(115200); pinMode(LED_PIN, OUTPUT); - tt = rtclock.makeTime(mtt); + tt = rtclock.makeTime(mtt); + rtclock.setTime(tt); tt1 = tt; rtclock.attachAlarmInterrupt(blink);// Call blink rtclock.attachSecondsInterrupt(SecondCount);// Call SecondCount @@ -79,7 +87,8 @@ void loop() i = 0; tt = (dateread[0] - '0') * 1000000000 + (dateread[1] - '0') * 100000000 + (dateread[2] - '0') * 10000000 + (dateread[3] - '0') * 1000000 + (dateread[4] - '0') * 100000; tt += (dateread[5] - '0') * 10000 + (dateread[6] - '0') * 1000 + (dateread[7] - '0') * 100 + (dateread[8] - '0') * 10 + (dateread[9] - '0'); - tt = rtclock.TimeZone(tt, timezone); //adjust to your local date + rtclock.TimeZone(tt, timezone); //adjust to your local date + rtclock.setTime(rtclock.TimeZone(tt, timezone)); } } if (lastGlobAlmCount != globAlmCount | lastSPECAlmCount != SPECAlmCount ) { @@ -111,20 +120,20 @@ void loop() if (tt1 != tt & dispflag == true ) { tt1 = tt; - rtclock.breakTime(tt, mtt); + //rtclock.breakTime(tt, mtt); Serial.print("Date: "); - Serial.print(mtt.day); + Serial.print(rtclock.day()); Serial.print("- "); - Serial.print(mtt.month); + Serial.print(rtclock.month()); Serial.print(" "); - Serial.print(mtt.year + 1970); + Serial.print(rtclock.year() + 1970); Serial.print(" "); - Serial.print(weekday1[mtt.weekday]); + Serial.print(weekday1[rtclock.weekday()]); Serial.print(" Time: "); - Serial.print(mtt.hour); + Serial.print(rtclock.hour()); Serial.print(" : "); - Serial.print(mtt.minute); + Serial.print(rtclock.minute()); Serial.print(" : "); - Serial.println(mtt.second); + Serial.println(rtclock.second()); } } diff --git a/STM32F1/libraries/RTClock/src/RTClock.h b/STM32F1/libraries/RTClock/src/RTClock.h index e67fcb3..6f1cba0 100644 --- a/STM32F1/libraries/RTClock/src/RTClock.h +++ b/STM32F1/libraries/RTClock/src/RTClock.h @@ -72,7 +72,7 @@ class RTClock { uint8_t second(time_t t) { breakTime(t, tmm); return tmm.second; } uint8_t isPM(time_t t) { return (hour(t)>=12); } - time_t TimeZone(time_t t, int TZ) { return ( t - (TZ * SECS_PER_HOUR)); } // usage: localtime = TimeZone(UnixTime, 8); // Beijing timezone = 8 + time_t TimeZone(time_t t, int TZ) { return ( t + (TZ * SECS_PER_HOUR)); } // usage: localtime = TimeZone(UnixTime, 8); // Beijing timezone = 8 void createAlarm(voidFuncPtr function, time_t alarm_time_t); void createAlarm(voidFuncPtr function, struct tm_t & alarm_tm); @@ -95,4 +95,4 @@ class RTClock { #endif // _RTCLOCK_H_ - + \ No newline at end of file From c25957ee21b93686f650d3157714551a6dbbc10f Mon Sep 17 00:00:00 2001 From: csnol Date: Thu, 14 Sep 2017 20:47:12 +0800 Subject: [PATCH 168/351] Add removeAlarm function --- .../examples/RTC-Serial-Set-Newlibrary.ino | 80 ------------------ .../examples/STM32F103-RTC-Serial-Set.jpg | Bin 131470 -> 0 bytes STM32F1/libraries/RTClock/keywords.txt | 1 + STM32F1/libraries/RTClock/src/RTClock.cpp | 4 + STM32F1/libraries/RTClock/src/RTClock.h | 3 +- 5 files changed, 7 insertions(+), 81 deletions(-) delete mode 100644 STM32F1/libraries/RTClock/examples/RTC-Serial-Set-Newlibrary.ino delete mode 100644 STM32F1/libraries/RTClock/examples/STM32F103-RTC-Serial-Set.jpg diff --git a/STM32F1/libraries/RTClock/examples/RTC-Serial-Set-Newlibrary.ino b/STM32F1/libraries/RTClock/examples/RTC-Serial-Set-Newlibrary.ino deleted file mode 100644 index ba89a4e..0000000 --- a/STM32F1/libraries/RTClock/examples/RTC-Serial-Set-Newlibrary.ino +++ /dev/null @@ -1,80 +0,0 @@ -/* STM32F103C8 Black Pill ( PB12) - - Serialport set and display RTC clock , Write by CSNOL https://github.com/csnol/STM32-Examples - based on https://github.com/rogerclarkmelbourne/Arduino_STM32 - - 1. Blink on PB12 per 1s. - 2. change to your timezone in the sketch; . - 3. get Unix epoch time from https://www.epochconverter.com/ ; - 4. last step input the 10 bits number( example: 1503945555) to Serialport ; - 5. the clock will be reset to you wanted. - - ## Why the 10 bits Unix epoch time be used? -****Because I wanna connect to NTP server by ESP-8266. -****in the library. getNtpTime() will return this 10 bits Unix epoch time. -*/ - - -#include - -RTClock rtclock (RTCSEL_LSE); // initialise -time_t tt; -tm_t mtt = { 47, 8, 27, 0, 1, 20, 30, 30 }; -char weekday1[][7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; // 0,1,2,3,4,5,6 -uint8_t timeread[11]; -int timezone = 8 * 3600; // timezone -8 + DST +1 = -7 CA USA -time_t tt1; - -#define LED_PIN PB12 - -// This function is called in the attachSecondsInterrpt -void blink () -{ - digitalWrite(LED_PIN, !digitalRead(LED_PIN)); - tt++; -} - -void setup() -{ - Serial.begin(115200); - pinMode(LED_PIN, OUTPUT); - tt = rtclock.makeTime(mtt); - tt1 = tt; - rtclock.attachSecondsInterrupt(blink);// Call blink -} - - -int i = 0; -void loop() -{ - while (Serial.available()) - { timeread[i] = Serial.read(); - if (i < 11) { - i++; - } - else { - i = 0; - tt = (timeread[0] - '0') * 1000000000 + (timeread[1] - '0') * 100000000 + (timeread[2] - '0') * 10000000 + (timeread[3] - '0') * 1000000 + (timeread[4] - '0') * 100000; - tt += (timeread[5] - '0') * 10000 + (timeread[6] - '0') * 1000 + (timeread[7] - '0') * 100 + (timeread[8] - '0') * 10 + (timeread[9] - '0') + timezone; - } - } - if (tt1 != tt) - { - tt1 = tt; - rtclock.breakTime(tt, mtt); - Serial.print("Date: "); - Serial.print(mtt.day); - Serial.print("- "); - Serial.print(mtt.month); - Serial.print(" "); - Serial.print(mtt.year + 1970); - Serial.print(" "); - Serial.print(weekday1[mtt.weekday]); - Serial.print(" Time: "); - Serial.print(mtt.hour); - Serial.print(" : "); - Serial.print(mtt.minute); - Serial.print(" : "); - Serial.println(mtt.second); - } -} diff --git a/STM32F1/libraries/RTClock/examples/STM32F103-RTC-Serial-Set.jpg b/STM32F1/libraries/RTClock/examples/STM32F103-RTC-Serial-Set.jpg deleted file mode 100644 index b2e701ea9e4789dd48ad0bbfe2c93534d7c61c19..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 131470 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 AO$pHf*yADG%HUemy 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%0ACJfMVz1%{y?hP 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 diff --git a/STM32F1/libraries/RTClock/keywords.txt b/STM32F1/libraries/RTClock/keywords.txt index 31bf13e..7e9a60d 100644 --- a/STM32F1/libraries/RTClock/keywords.txt +++ b/STM32F1/libraries/RTClock/keywords.txt @@ -13,6 +13,7 @@ setTime KEYWORD2 getTime KEYWORD2 createAlarm KEYWORD2 +removeAlarm KEYWORD2 setAlarmTime KEYWORD2 attachSecondsInterrupt KEYWORD2 diff --git a/STM32F1/libraries/RTClock/src/RTClock.cpp b/STM32F1/libraries/RTClock/src/RTClock.cpp index deefcf0..e95bead 100644 --- a/STM32F1/libraries/RTClock/src/RTClock.cpp +++ b/STM32F1/libraries/RTClock/src/RTClock.cpp @@ -194,6 +194,10 @@ time_t RTClock::makeTime(tm_t & tmm) rtc_attach_interrupt(RTC_ALARM_SPECIFIC_INTERRUPT, function); } + void RTClock::removeAlarm() { + rtc_detach_interrupt(RTC_ALARM_SPECIFIC_INTERRUPT); + } + void RTClock::attachSecondsInterrupt(voidFuncPtr function) { rtc_attach_interrupt(RTC_SECONDS_INTERRUPT, function); } diff --git a/STM32F1/libraries/RTClock/src/RTClock.h b/STM32F1/libraries/RTClock/src/RTClock.h index 6f1cba0..4d8399e 100644 --- a/STM32F1/libraries/RTClock/src/RTClock.h +++ b/STM32F1/libraries/RTClock/src/RTClock.h @@ -76,11 +76,12 @@ class RTClock { void createAlarm(voidFuncPtr function, time_t alarm_time_t); void createAlarm(voidFuncPtr function, struct tm_t & alarm_tm); + void removeAlarm(); void attachSecondsInterrupt(voidFuncPtr function); void detachSecondsInterrupt(); - void attachAlarmInterrupt(voidFuncPtr function); + void attachAlarmInterrupt(voidFuncPtr function); void attachAlarmInterrupt(voidFuncPtr function, time_t alarm_time); void detachAlarmInterrupt(); From f84f73c4a1a350e8eda607a5e6b54f2b39a8c608 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Tue, 19 Sep 2017 20:42:16 +0200 Subject: [PATCH 169/351] Create hooks.c similar to F1 - it was missing --- STM32F4/cores/maple/hooks.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 STM32F4/cores/maple/hooks.c diff --git a/STM32F4/cores/maple/hooks.c b/STM32F4/cores/maple/hooks.c new file mode 100644 index 0000000..641eabc --- /dev/null +++ b/STM32F4/cores/maple/hooks.c @@ -0,0 +1,31 @@ +/* + Copyright (c) 2012 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * Empty yield() hook. + * + * This function is intended to be used by library writers to build + * libraries or sketches that supports cooperative threads. + * + * Its defined as a weak symbol and it can be redefined to implement a + * real cooperative scheduler. + */ +static void __empty() { + // Empty +} +void yield(void) __attribute__ ((weak, alias("__empty"))); From f8d28b8663a53fa37f75c2f20ed0aebc81c83fba Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Thu, 21 Sep 2017 17:35:20 +1000 Subject: [PATCH 170/351] Removed unused cygwin dll's from tools/win --- tools/win/cygiconv-2.dll | Bin 969728 -> 0 bytes tools/win/cygwin1.dll | Bin 1872821 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tools/win/cygiconv-2.dll delete mode 100644 tools/win/cygwin1.dll diff --git a/tools/win/cygiconv-2.dll b/tools/win/cygiconv-2.dll deleted file mode 100644 index 64fd39e3e9e2f266dfbb45bb8e6a6c5799cb14e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 969728 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

P=blKI{EPjXcY+wxIf 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�< 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

R*}9q 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

-2n0uMu-Spw~5ejq3GGaEJ{3GWN+B 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

Cf@j2zgz;rktt5(;7xmXRz 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

$j)Rv{&QKUzs-Lt>-D$$g|dFXGN=tg3Vl$i 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

rmIfI-<&LQWK3&=&}5^@>2f?P$eA=i-` z$W7!H5`qMfAkxoQz7IeJqJmJts1Q^rDhw5lia^7nO&~M-`w7QAMa?R0*mSRfZ}@RiG+SRj6uI4XPGZhpI<4 zpc+w4sAg0Psuk6SYDfLtuI@$kq54q+s6o^aYS>q?9z~6z#!(ZfNt7=_j+#NuqUKQZ zs0Gv_Y6-QBT0yO%)==xH4b&!T3k5*|C=lg$=6@D&7I+qP7JL?R7J3$T7Je3S7U{FT zqt9Y|<)@#zPf5N8RLWWES=w2;Ppr;7%R0+G%kjz8d1v`&1wO^P=&bmxa6;#=FG>~oz`oi(4eoVA{{owc8JoOPacopqn}_-Z9d)$*|WK``Ll(y#j~Ze<+Ha^%G%lb*~Z!C+14543^)VN z{LudB0Cb?QV;hVP@wFzy(BbF^bR;?o9gU7b$D-rV@#q9}B0343j7~wPqSMgn=nS+k zkdMwr=b&@ZdFXs}0lE-fgf2#xpi9wZ=yG%gx)NQ5u143OYteP+dUON25#5AtMz^3_ z(QW8>xedvDl0D2HTgdRqZphwYT=yCJ}dJ;Y5tJ=+=XVG)$dGrE$ z5xs<7Mz5e((QD{+^agqpy@iH+s|WdE{4oKTKui!O7!!gC#e`wPF%g(ZOcW*>6N8Dx z#9`tw3E%p>$(R&ODkcq+j>*7eVzMyVm>f(lCJ&R3DZmtBiZI2P5=<$k3{#G&z*J(Y zFx8kEOf9AkQ;%uDG-8@C&6pNUE2a(8j_JU3V!ANhm>x_orVrDP8Ndu;hA_jJ5zHuN z3^R_Iz)WJMFw>YB%q(UOGmlxoEMk^0%a|3+DrOC{j@iI$Vzw|441fVKe&_z@0q23| zLFd8eA?KmzVdvrJ5$BQTQRmU;G3T-8ap&>p3FnFDNj|;qZ`yTP=h^2u=eg&3=lSOa z=Y{7*=f&qG=cPX7uKc{>yz;#2y!yQ6y!O2Ay#Bo5yz#v0y!pK4y!E{8y#2i6yz{*4 zy!*W8y!X8Cy#IXQeDHkeeE59ieDr+meEfXkeDZwieENLmeD-|qeExjleDQqgeEEFk zeD!?oeEodmuWc^y-0#BwBH$wMBIqLcBIF|UBJ3jkBH|+QBI+XgBIY9YBJLvoBH<$O zBIzReBIP3WBJCpmBI6?SBI_diBIhFaBJU#qqTr(NqUfUdqU56VqU@slqT-_RqUxgh zqUNIZqVA&pqT!3{%Yw_o%c9HT%aY5|%d*Sz%Zkg&%c{%j%bLsD%eu?@%ZAIw z%cjfb%a+U5%eKq*%Z|&=%dX4r%bv^L%f8G0%Yng$^8+UvUO`s;@4 z#_Oi*=IfU0*6X(G_Un%8&g<{>z25(#y!TUg@2$Bvb3J=KcRhc-aJ_iFbiI7Na=m)J zcD?Sa^KD*lT|<1`KJeP_#{VYZCh#WcCio`gCiEukCj2JiCh{igCi*7kCiW)oCjKVj zCh;ceCiy1iCiN!m=B-lon~kdfw?b9jP5n*7P2)||P4i95P3ukDP5Vv9P3KM5P4`XD zP47+LP5;fn&EU<@&G600&FIb8&G^m4&E(D0&GgO8&FszG&HT;6&En0{&GOC4&FanC z&HBy8&F0P44de#60dM@U{@4I)AT|gaj19qtV#BcE*a&PSHVPY!jlsrZzjt2}u}Rou zYzj6Nn}$utW?(b1S=elB4mKB?ht0A3J~@#13JHu_M?~>=9`DBCN2w?jmyF1;_`6$xB^@ut_WA` zv%gAlWw>%&1+EfTg{#KZ;A(MoxO!Xzt`XOSYsR(UT5)Z-c3cOp^Veor@2|D6LEI2- z7&n3&#f{;{aTB;n+!SsaH-nqS&Ee*83%Etx5^fo{f?LI{;nr~*xJ}#^4uS)4AkGi( zj}O2H;)C$P_z-+3J`5j@kHAObqwvxA7?e=9}*REeJX>pt`%ehI&fU%{{9*YNB3 z4g4m43lH&i=|Q|7!JiO72qXj%f(apnP(m0XoDe~XBt#LS2{D9NLL4EUkU&TzBoUGc zDTGu)8X=vKLC7Rz5wZz6gj_-%A)in{C?pgSiU}ozQbHM_oKQiiBvcWq2{nXTLLH%= z&_HM;G!dE!EreD=o3H!#z53VfYyR~T`Uw4m0bc=dh%ihTA&e5n2;+na!X#meFin^t z%o64Z^MnP$B4LTJOjseT64nUogbl(bVT%AE00fZWM|`U?1rmdZ!Nd?^C^3u}PK+Q% z5~GOG#28{MF^(8dOduu_lZeU0@Aac}Vg@mjm_^Jc<`8pwlL5J!n)#Bt&TagsPioF>i?XNhyfdEx?bk+?)$Caw@yiEG4l;s$Y(xJ85z0U}8B zBl(j8NP(mvQZOlm6iNysg_9ykk)$Y6G%1D@ONt}KlM+aYq$E-@DTS0uN+YHFOuI}{ z7Ac#QL&_!Pk@86eq(V{=shCtkDkYVX%1ITZN>UZ6np8uoCDoDYeF|P9sfpA~Y9Y0f z+DPrB4pJwni_}f(A@!2_Nd2S%(jaMwG)x*HjgrPl!c0RCTWWVApsr$IgOl7&LC%!v&h-x9C9u>kDN~~AQzI0$i?Imaw)ltTu!baSCXs9 z)#Ms-ExC?dPi`PLlAFlQ9ks)M&43hmQ{*(a9o5T=I z3892i!YJXC2udU+iV{tUp~O<+DDjj8N+KnRl1xdVq*Br->68pgCMAoKP069;Qt~MI zlmbd2rHE2YDWQ~7$|&WO3Q8rVic(Ffq1009DBp|AO_XLz3#FCPMro&XP&z4Hlx|87 z<*oYKPZ^*LQidqQlo87J^5q0&k}^e^rp!=gDRY#0$^vDPvP4;?tWe$xZ0nQ_$|hxt z0-*pDkm5)6rv^|1sX^3WY6vxy8b%GLMo=TEQPgN^3^kS-M~$Z@P!p+1)MRQ3HIjNZfXy;m)b||rw&jDsYBFZ>In7CRs2a+^a1YFS?U~hp1MF? zq%KjHsVme~>Kb*OxL$|}X zBe#Ed7klA$@pkEU`F7=Y^>*!c{dVJa^LFbNatqvow|+E#S^zDO7DNlCh0sE2VYF~s z1TB&lMT@4z&|+zEw0K$qEs>T)OQxmJQfX2la@uxrsdFbX?e7KS^=$)RzxeN zmC#CQWwdfy1+9`+MXRRO&}wPlOLL91CR#JCh1N=IqqWmIXq~h!S~snS)=PUUxed?; zX+yMO+6ZlwHbxt#z4gGHodLTWB9!w9Rhtk97;q(Z4Bt42AO^>0+(&Omy^aOe$J&B%7PobyM)9C5+407Bo`XGIXK1?5>kJ88Ja!bdc`%P3sK23%U!w3%Luu3%d)yi@1xti@J-xi@A%v zi@S@zOSntCOS((`8{S>!UDjRpUCv$ZUEW>(UBO-9UC~|fUCCYPUD;jvUBzAHUDaLn zUCmwXUEN*%UBg}D-EXQ@op)V#-9ACD_pa}*|8C%J@NVdC_-^EG^lt2K{BGiI@^0#G z`fldeddtGy;@#5SvQKeYy<59mzuUOmyxY2i+yQssogc%W5x@v!1TlgcA&gK)7$ck! z!H8r;F`^kUj95k-Bc74KNMs~2k{KzCR7M&josq%FWMnb2899txMjj)dQNSo<6fue! zC5%!=8Kaz0!Kh?ZF{&9gj9Nw=qn^>gXk;`oni(yORz@46ozcPQWOOmQ89j_%MjxY} zF~AsP3^9foBaBhT7~>~3eVQ@Dm}Sf{<{1l&MaB|inens5yvf*NKo|f6Wcc0t-v`_W z-Ur-bdX>-^bj?-pAd?-zVHB-Y4BB->3L$@;_Isv+r~6bMN!+ z^Y07p3-62Wi|%kL}hEAOlBtM6;>Ywzps>+c)x8}FO$o9|ohTkqTM+wVK> zJMX*hyYGAMd++=1`|rPZU5D>S?nm#(?#J&Z?kDf3?x*i(?q~1k?&t3p?icTu?!UK0 z*Y4NvH|{s@x9%bLz&&{H$Mk0gFaw!E%wT2+Gn5&|3};3#BbiamXl4vEmKn#4XC^Qc znMurKW(qTvnZ`_KzR5dT%xq>3Gnbji%x4xb3zG259P%uZ$(vzyt&>}B>b`OZD~J`$3Sot^!dT&~ z2v#I3iWSX@Va2lISn;d`Rw65jmCQ8uP^CM%1T&B|frvhrB@tO8actB6(1 zDq)qf%2?&B3RWenidD_3Vb!wgSoN$1RwJv4)y!&PwX)h+?W_(~C##Fq&FW$Gviey4 ztO3>_Ylt<>8exsH##rO53DzWQiZ#ueVa>AUSo5p}*5Y3mT-R9ZtPR#CYl{V80W6T^ z$M$Cjumjma>|k~XJCq&94rfQOBiT{xX!dvAD4w0bPGl#sli4ZkRCXFWot?qXWM{Fn z**WZ7b{;#QUBE767qN@kCG1jm8M~Za!LDRiv8&lN>{@mmyPo}4N^fE}vs>7$>^62g zyMz7KjqYamuzT5k?0)uJ5qO9_%pPHnvd7rt>_zqxdzrn$ z_R%%$b@m2(lfA`;umLv6_T%_-0yu%3AWkqRgcHgMmd27HAa)vm=oDt3_XN)t>ncz%v zra03a9|_C(UdLYKEOC}OE1Xr%8fTre!P(?&aUdLk19JSh{@eg=AUB8`%njj&a>Kac z+z4(YH;Nn0jp4>}3-A-9NI z%q`)Ta?7~o+zM_bw~AZMt>M;k>$vsY25uv_iQCL=;kI(yxb55yZYQ^k+s*Ca_Hz5U z{oDcWAa{s6%pKv5a>uyi+zIX^cZxgBo#D=M=eYCS1@0nuiMz~Q;jVJmxa-^v?k0DO z3*iD>kn8vGciVtb577@X53vt%5AhEP4~Y*+56KTH52+7n59tpX519{H57`en54jI{ z5BU!T4}}j!55*5952X)f59JRP50wv957iHEhSqNiTCERl5A6>f51kKP58V$v54{h4 z5B(1V4}%Xw55o^552Fub591FL50ej557Q4b53>(*5AzQT4?o*FYY*!W8xNZgTMv*2 z-~oK_KE zE%BClE4)?S8gHGq!Q13*@gO{a2lD**{`>%bAU}v7%n#v*^27My{0M#|KZ+mCkKxDi z-hEj27V*IiQmj`;kWYJ`0e}-ekZ?+-_7sg_wxJr{rmy`Ab*HI%pc*8 z^2hk&{0aUfe~LfNpW)B)=lJvd1^yy`iNDNW;ji-7`0M-){w9Bm?;|MqAm2~m@6*r% z1wn#fL5Lt!5GDv0L6f;Z1$MX)MZ z6RZn11e<~_0Ym@@K!M+*|6{;o;A7BZ@MFkh=wsMp_+!Ll|@+x{A0r7 zPbP2bW7=c-W5#3VW7cE#W6oplW8P!_W5HwLW6@*rW65LbW7%W*W5r|TW7T8zW6k4t zPqX2%@v-T#`LX4(^|9@-{juY*^Rer(`?2S-_p$G>|8d}P@NwvI_;KWM^l|KQ{Bh#f zvfRw$>^D{JO_W=DTz*`6Tzy=7Tz}kn+1nYr1-3gw5Rl^jK8H-6g<5-6~#{_Po+;~PvuV)PnAzqPt{K~ zPqj~VPxVg?PmNDaPt8v)PpwaFPwh_~Pn|yDqWh`msn@4r^!t2_!Kb08;ir+O(WkMe z@u!KW$)~BO>8F{e*{8Xu`KN`a#iymG<)@XW)u*+m^{0)e&8Mv=$deC$ee!$ue-3yK zd=7dJehzsKeGc>W$RnO3pQE0meHHRpUvoVEIpI0+Iq5n1IpsO^Iqf<9IpaC=IqNz5 zIp;a|Iqy0Dx!}3*x#+q0x#Vw@v#Wlio&9q;yY0FCx#PL>x$C+6x#zj}x$n9EdEj~Q zdFXlgdE|NYdF*-odE$BUdFpxESKOX`o_n5uUU*)7UV2`BUU^=9UVC1D-gw@8-uiW^ z+E3^&3=jqigM`7t5Mih=Oc*YV5Jn24gwetnVXQDt7%xl^CJK{;$-)$2sxVEMF3b>S z3bTaS!W?0)Fi)5-ED#n7i-g6(5@D&ZOjs_g5LODSgw?_tVXd%ESTAf4HVT`B&B7L8 ztFTSjF67oo#rYK94Ey@w)itSDiM{6%0%U&3Q?t~ zN>nYX5!H(7MD?NuQKP6y)GTTdwTjwA?V=7*r>INRE$R{Viuy$Tq5;vMXh<|H8WD|( z#zfq$#UliJQeO;#P5+xLw>K?i6>4 zyTv_XA1fyA7Y~RB#Y5s@@rZa-JSH9&PlzYQQ{rjyjCfW&C!QBCh!@36;$`uQcvZY6 zUKekOH^p0Gh!_xqV!s#vmw=bRm!OyLN=(>G_)Ek~q)&^9eu;UBeTjRCfBDJPNO?(p zNqb3u$#}_p$$H6t$$80r$$QCvc`NW2y%fKcyp+C_y_COHyi~sUxR#fim)e)Qm-?56 zm&TW-m*$t2m)4iImv)~i*ZI=*(*4r&()-f)(*H8>GWas|GW;^~GWs(1GX660GWjy~ zGW|01GW#<3GXJvhviP#}vi!30vih?2vi`F1viY+00(k*mz!yJ>za&5sC<&4TOF|@} zk}yfQBtjA?iIPN1VkEJWI7z%DL6Rs*k|aw~B&m`#NxCFMk}1iOWJ_`+xsp6dzNA1> zC@GQ@OG+fAk}^rTq(V|DsghJnY9zIiI!V2xLDDE`k~B+NB(0J*NxP&&(kbbZbW3_9 zy^=mjzhpo%C>fFrOGYH4k}=7+WI{42nUYLPW+bzcImx_aL9!@Wk}OMBB&(7&$#=bY zO9GJq5>VnN^_K=n1EoRIU}=anR2n7?mqthh8YhjHCP)*dNz!C#iZoT4 zCQX-SNHe8b(rjstG*_A@&6gHP3#CQUVrhxAR9Yr2msUtCrB%{uX^pg2S|_cSHb@(# zP10s*i?mhRCT*8?NIRun(r#&wv{%|E?UxQn2c<*OVd;o;R5~Udmrh70rBl*r>5Oz% zIwzf%E=U)pOVVZOigZ=FCS8|qNH?WhQiv3gf>J-3zbrr&C<~GW%R*$KvM^b=EJ7A3 zi;_jlVq~$hI9a?bL6#^>k|oPhWT~<=S-LDkmMP1UWy^A8xw1T2zN|o2C@Yc`%SvRW zvNBn@tU^{PtCCgAYGk#tI$6D}LDnd1k~Pa(WUaC`S-Y%5)+y_fb<28Wy|O-8zidD@ zC>xRu%SL3QvN74XY(h3Eo03h-W@NLnIoZ5yLAEGck}bZe-@-$@ z@^E_<&bh%Iieg@jw#2L6Us^DlyX`*qnuUFDd&|7%0=apa#^{e zTve_q*OeQ}P34vnq6Czn&%5wf1*ig5L8@R?h$>VSrV3X@s3KKSs%TY=DpnPzidQA5 z5>-j6WL1hPRh6bnS7oR&RavTRRgNlGm8Z&A6{reTMXF*|iKt%-Rn?|yS9Pd5Rb8rXRgbDy)u-xL4X6fHL#kobh-y?drW#jG zs3uiYs%h1XYF0I;npZ8T7FA2CWz~vmRkfyCS8b>^Ra+{E3Q&P6KefL)Kpm(KQoq?> zq3SSoxH>`|sg6=dt7Fu$>Ns`0IzgSNPEseUQ`D*IGKb*ex=#IOFEy&0)XnM^b*s8f-LCFXcdEP8-Rd57 zuewj&uO3hjs)y9W>Jjy*dQ3g8o={J!r_|Hx8TG7sPCc()P%o;N)Ndxws(MYmuHH~@ zs<+e-HJ}F7ej0yGfF@8AqzTr9XhJn%ns7~oCQ=iniPpquVl{D^cuj&PQIn)e)}&}s zHEEi3O@<~@lcmYlMXq$$>vXi7C@nsQBrrczU-sn*nJYBhD5dQF3- zQPZSp*0g9^HEo)9O^2pa)1~Rw^k{lDKgr2Mnqkd|W>hn#8P`l`CN)!kJ^25UpKq1rHQxHdu?sg2S` zYh$#r+Bj{zHbI-HP0}W7Q?#ktG;O-}O}5F>W@~e_x!OE!zP3PHs4dbKYfH4H+A?jq zwnAH}tbw5{4UZM(KZ+o|o+c58dIz1lu)zji=7s2$P{ zYe(K-b?vxzLOZFQ(oSn_7Irfb)A z=sI;>x^7*Mu2(>qF26aQaVcm#sR5zv@*G=dqbyK=&-HdKlH>aD|E$9|?OS)y< zif&c6rd!u-=r(m*I*1O?fx0(MGC&`w57GzgL-e8gFnzc_LLaG*(nsrK^s)LleY`$F zpQumLCx6rM()8*241K0POP{UJ(dX*(^!fS%eWAWcU#u_Dm+H&(<@ySJrM^mE?eoQI z^>zAseS^MH-=uHWx9D5-Z9aFbL*J?I(s%27^u78%eZPJ{Kd2wl59>$tqxv!Zxc*I> zn$l0}XY{lBIsLqTLBFV9(l6^*^sD+c{kncbzp3BSL-c?i)cYCy4FQHgLy#fZ5Ml^5 zgc-sO5r#-Zlp)#>V~91x8R88IhD1Y>A=!{(NHwGx(hV7gOhc9-+mK_(HRKuc4F!fm zLy@7_P+}-Glo`qm6^2Sfm7&^DW2iOM8R`uUhDJk^q1n)4Xf?DM+6^6sPD7WW+t6d^ zHS`(!4FiTj!;oRvFk%=rj2Xra6NX8{lwsO1W0*C}8RiWOhDF1YVcD=^ST(E})(snm zO~aM}VgL-F!O!S#3@`>7gN(t(5M!t@%ouKrFh&}qjM2szW2`aG7;j84CK{8B$;K38 zs_{)F&oE{hvy9os9AmCA&zNs4Fcun%jK#(hW2v#sSZ=H^RvN2})y5iQt+CEnZ)`9& z`Xu6JV~erX*k)`ub{IR2UB+%>kFnR-XY4l)7zd3*#$n@#anv|w95+rFCyi6aY2%D> z);Rag7=05)myIjNRpXj*-MC@gG;SFoM!*Of{a*cF16~7PgI%i;a z>(J})>&WZq>)7k~>%{Bi>(uM?>)$q)R$f-b@6mLo}C7O~<$)*%jswvHsZptuanzBsUrW{kQDbJK| zDliqAicG~m8>iG%W-2#Tm?}+GrfQ#nQ){X-)teejjix43v#G_@YHBmJn>tLLrY=*r zsmIi7>NEA5226vdA=9vF#58IeGmV=jOp~T5)3j;EG;5kO&6^fXi>4*hvT4P%YFaa` zn>I|FrY#f11eidRpV{9WU=B0~nS;$C=1_B(Ioup!jxWDT~4SVOI0)^KZtHPRYojkd;EW36%4cx!?+(VApUwx(E9t!dVDYlbz` znq|$l=2&yBdDeVufwj&p$S%!&AS?ip2-nw92 zv@Thftt-}5>zZ}lx?$b4ZdoB#zzSOZZ2q+Ujiewgy|Ht;yDGYq7Q3+HCE%4qK+N12z_85DtJ=~7wn7nCHt~{ z#lC7^v#;AX?3?y2JH!syLA#&B-x1&lbObqq9U+cTN0=kr5#fk*L^+}zF^*VAoFm?m z;7D{NIg%YIj#NjQBi)hV$aG{mvK={&Tt}WG-%;QwbQC#?9VL!ZN13DCQQ@d`R5_|0 zHI7 zG2xhWOgW|CXQDI7ne0q)raIG{>COyirZdZ#?aXoJI`f?Q z&H`tlv&dQOEOC}P%bexT3TLIW%31BKan?HPob}EIXQQ*p+3aj_wmRFK?amHor?bo1 z?d);(I{Tdc&H?A3bI3XD9C401$DHHN3FoA9$~o&^}5rqf3_I{_!?^mF;U0$hQvAXl&}#1-labA`JiT#>FQSF|g}73+#~#k&$*iLNA9 zvMa@v>PmB^yE0svt}Iu!E60`V%5&wr3S5P*B3H4i#8v7lbCtU)T$QdWSGB9gRqLvA z)w>#8jjkqFv#Z6`>S}YfyET~tG23&)#A=j{L#5L*~bB((uT$8RT z*R*TKHS3yl&AS#{i>@WtvTMb)>RNNHyEa^#t}PeD1-L+$pWELZ;0|;Lxr5yy?ofA_ zJKP=Nj&w)4qunv?Sa+N|-kso1bSJr!-6`%=cbYrho#D=OXSuW8IqqC{o;%-N;4X9* zxr^N;?oxM|yWCyju5?$qtKBv3T6dkh-reACbT_%1-7W4`cbmK2-Qn)^Y4F|d9(S+1 z&)x4Ha1XkN+{5k>_o#c!J?@@xPr9ev)9xAftb5Kq?_O{(x|iI`?iKf{d(FM>-f(Za zx7-jn;0E1(9)C}OC(sk*3HF3|LOo%ga8HCM(i7#0_QZH%J#n6RPl6}WljKSEq~hHczQj3o_^1OXV5d`8TO2LMm=MmanFQj(lh0m_RM%@ zJ#(IU&w^*sv*cO!taw&EYo2w_hG)~W<$-tr59smp`g;Ssf!-i*us6gT>J9UTdn3G& z-Y9RhH^v+5jq}F)@VrECk~i6#;!X9YdDFca-b`1l+n4q)9bY=Xbbaam((|SFOW&9NF9Tl&zYKjD{xb4q z^h?T@)Gxnj{o#Lj_wMI=|Bmp(yRWn#>|Y;$_|-pB_&)pp@BW)_Kjg^w9lyTcIrcsO zTlWF#dk^}<@4q|oJ^tqPzJvYn;T`;kcSh6?|6Sk34;vqU^Phcx)$*>XxAWa#Z_m5P z>!Ekszccma~ec$!>Q{Kb=dG>oNs_gxbvCZ!_Wj*h=Mu*=2xHJF0_1|s2 z7izw|7a9=nfBD1p`{!rc`yYRNexIsUzIU6g?|=N&rw(v1(lL->;q|E~DU z2QL@?L7RH{Vc8G&;g8lSAO7Rr{RjP`;KP526MryL)E{;aEFZGlzkYD%{`N=b*MI)e z_Rs#ukH*VC{P_CI|LtR|^_L$}JrN%bKc;{D`X7rvLUL+8{wrSV$CI&#=rjb2Y&zl zlPu+rKmFl9_)nkw{@yP?{oZQmCv#-{r~kV<>yy@A_Nn0C)P8FE_idm4!rA``VwnE) zUrj81`n|t|e9Ei)vroFH-A}*z@$6Ib(#_gigSe1VVs70_nXMTb6A}mMqD#C0WH1={+I6_ul&6P@J zkWPSrKHc)&`__8*-uM1Rd;OTvo;{<5ST@EU6s~sJm4UTC934};^wrGTO38}aH>!WH z{k8e7+RCqEwUx3fwI3=ERqtw-Z78q3uiC>)Bm=!>@eyA7ka#cYb$u_sNv2moWxm%v zrIXi&2Rg6BduFfPV$$nuHtSWjx1U$Z*FrDbg$Z7_KhE(|2Cnp~_5L@n@A3|>Th&Lr zHkO_BI$CkvtF-Eg*YK*3UO~fudMS#xch%Q$Z>1{P`})x=?}`sCy*GdC;=SiP;9aed z-b%IX-BualttivIMP-S1jqV;>JGn+qUqj9@@pH;^)%&UCIp`k<%4~ysweoUpSt_hlrQ(mE!p6+egAHstQEyRWvedu6h6D)dMf=W?UB1(g_4RGLYNYST zGn0HTmd*3MvVWCtg|gLmU5DMinf;IWdZr!ojW50E8*$`@uTt^UcW3zrU!}6jH>+hW zzsLRj{mg^H{o*Zge${W%{A!eDesvzT^V@j7o8N#J2ET5PAwTpz=~ul}@FTAb@|)Cq zlwY$46a8HCX8Jv>yU1^J%yPeJr`P+%_SxiD>fGn|`Sx+Ydv`DTIoe(I+t==v->XYc z{5Bik`t9rT#qZ6_Uw*5;diy`@5#ry*Gs3^9BGLayY?^=R@I3$2@^=18q26EFg!w-# z<@|@&4D=_IvHr^b+5TmvEBy=KZ}KlJIpAOQ<&^&$<(hwq^4Pz$@S}f;`w#!fe!u+B zZ>|;KtQQn8V0?JMlOOd0^4(Gb_BF~3_*l^*Af#WrfO9Xq1w8C*2=JQ>1!!$(K&U?% zkP^fO3_a2(pg44Bz_EUX0abUW1Yx-(!{g98DFYEA`!lg|gR zo2~_HkGmgmsN_|^x4WMMHWO6=cbuMqFE<1R9=RA9ScWAB22?f*e0Q{YVBy0qfyz%~ zU{8e%TvE&jmdzLtNW2{tcyHB|z+p${2X0o@1S-nTz?$lkz^a-{fu;F(17|gP5?Jbb zAGl({_rTq+G(m#mA5{1%Drf+c7}VRG7F2VoY0!lFt%6!A-Gie2bwRDFEJ3>(QbA{N zF^C`r2F=)B81&saHOOQ5+@P&(mIq}XE(#LMb_KOAJsMPa^kPt1@tq(=c^#yj{uWeH z?H+7zlND01lKRb9=Mt<;~taiZ<{igy(D<_?wH|DUX8} z6ut`{tW*TIBs@ZHDZwF?H)BHXSJn^tQPL#j!J9TA4;OV0sVsy-K9)K{KH_pnl`=A< zVAh2A$d#8nLke#dhe+k;L#j954EZ?tNk~m;Sx6Q6D@3XCt5Y~C zvQG7|6%ib$X~rRc@&AqFrd>wJxE%zZycTtH{usP*P*rM zd0-xGGqd^qe~ z<=L=TtFDJ_81yhq+5av~X=z zU3f*w&+uPuJ?kn;m@2t$_1DIA%awL@ORIHtl>%#Br9`Z&bRArGW#;I*j}A_&JMGf^ zx{BATx&u#bsQamMXI*7Laowy=r|K3yyjEAKD6PBj=j*y9g+J;ZQ9L3_HwQ&1+v6g# zjy8z+dM`JkYK-K3SO=Ijp#Oou zPUNrR=aIz2vdAi>CUVhG@2Hxu;Ze&r#YasnYYAZ0qoS0m8BvO|BC2Zprl_@TcSmIvmPD12e?)!fZbp@MdK3lhdLH#C^+QzIlb=zm zs%k~Q8xb76e{gJcnk6avRQ>emW7D&uJKo8Qp0=-Tbkdiu(eEWg^o@5|G%R=}g&K99XSsw}p?xjeS!mPg#KMgDOGha=;D zD5-ISJ7>j}C~e|KD!t+q#Tu76gpOPPNQ#Tn4TxKLc~o3^;q*AAd|6yc>kV-W$(?bE zr8sUwzcX={_Fj#fx%PJ4_f1dYNakJK?|*)Yt1MCCEPK7#o#`Z+mNQoJ&1LHw`MwegCwOLZdt)!9q&O7(+y zOW?Eki-$kPf1Xhuk6+N#t0(!^s~HthPx+BjPpN8BPfJ=UDwSV?qQs~gs#>agCMe}-!bpWv`$JTdRf`j2Omk$xECjAJdY;0wL7Nfk0p$*JezP)xslLo*n@r-dvqf7UP{L6^12N_KHh;{FaB63>NfN#y-@C$64#D6#FB6N$asolRVQ;Zow^ zs9TAv4?Rp&3f?6iJo+QCFPX;pFiq_0IilWIOeNeSoBB&+C1+OCt59#jlT`uSjN(r;co%9Z=o&4c$Nb(*sCV635YI03MZn9F= zA$j2N-pSRk(B#5nj^y&61<57FBa+K%rY67JIX_unxH?&RwJo`<#lhrJ)n}5cM_y09 zRaTl@R{bGa8C;cIs`#c9E0HOM)u}1U$0jLCz4j^Z5BEx`+JK}~yV+8Hp5#+*Um2L< z&RUd5#@Dj$$qp^Qzf z`Yz6C{>W@-htNEWQ?*>XqL<6NJwSl7Ksk$^!s?80Q3P*!-rJs5}Ry9|( zR<%oYLiJ~ZLgk6ter`~rXwnoVSe2m4PAe&EqqaH~p_0=y!3AmV-hISMQIgZ*QJ&J+@5y-&7riinse$JcT}%cKULo8 ziV~@6plX(`)a#t?rs>bc=uL1_vvAJMfKbClHT9bHx(%9c%fgzkJ}>} zD$eAFRaH3+m6G-i6~&;URDD%rRC82oR6AA2Ro5D}^}N$iqq)=2E%;tT&x8jJ%fG#D zcx1(whTV@=H9Y01G@LfOR>q(QK^dbBp&1QABQp-vOUzhR)G&i5n`ZR+(I(^i%5E7~ zNK?j_A7qC4CYQ0ZVV{igI|gR-ZaFGrz}ZO|&7oNtWh<9uyi+!2D8>6Tz80R!sILAq zW53(ojA6^3WgJg?li?lvA%i?!p7Hamd!w&0{*A6wMKvn)(Kf0s%WkA7?Norurs|^_ zt(vV`t=geF)~HOm(nu+Jr1n3mZME74WGXeWnTnF3YNhI>vZ`FF5t&NKG__r(+MKCW z9a7s1nM&bZwSA+iQ2AsjRgqaGO8qQF$yaq%!78U}aF$XsQEeBhin5gQy=r?ptDfdU zRtL9BSsKmXj2?X@E7J4Ntah5~SsL#fYF-t5Gi!|Ic9wU--7IgP2U!W8kFwm_JG^$Z2y3g?EA{4?3y8Wvh$0dWoN{`$=<*Hd$w}lqjBYt zz{ZLa-+1@l2957j=QiF@*0yo!?Ou)F)F6$2z>dc6l)mct7}cD{ZI3T)yhz!g_V=sK zs&1=ZsmfJeIf@dIQ%@6{qv;l(lkA?Df>Eb459y18Xklc=x=X;}71+(foRpQ(E(09s8y7&sCIIRfejSs+Y>Da;ZkB zrmL3cDnY;JdTKW2dfT_=X1njmZC7(3x7FL@xp!V&%>6#0rRKrwLRZCTyREJa-RQFVGRh25=rs~f~m9A=` z>d{mwK$=D^B%7W~Vw!5^b4@iT#HL;zeVW$xAJDW)8K>6FQ>|0&R-IH`S3OgGRe9to zN~kJHm8zK~=zMf&QoizAR=%>RRsNvrZuyl3ru@PMWPX_<=l@bh z&*DR@7TC=QXdCiKNl{No&<^SF;{10RQz50L7%&VDSv!G^C&D{Uxx)c7Fb^r5~ z|5L@pzg}h1Kdv>oW{TRMS~Kk*ng2BVFJm+QUOD}LJ>xI4X4TC6xAkNH?Z{td{^c0= zA1X%wm$5PbrT@2?fB8D{UuOR~{?Fcse_1)?AKAhG=>2of{~x_!|BH3)HOzmka{R|p z>%SSr{!RYBe^=1|y7Irz{ZAS5zg>6g#%UX;Z=A7l=EhkYXK$Rdaqh->8|QCau<@U( z0e_uq`uhs-Ut6RG|CcKg|1$f}wZy-U%YU!x`;Y4Wf9(yZ8Tj|i(0`2lbM8NTRFm8E%c-GTpM= zvfUcH<+$a#HF0a_*27Kb2D%yDOm1d3$PISG+^lZ6o88Uf=5*uScsIdKbd%iry7hM( z;5N{0klSFlA#P*cHo5(9i*`?Q&v4Il&vwsoZ{pt6J>R{hdu#VL?rq)Mxwm)k;NH=_ zvwIi!uI}C3ySw*r@8#axUFVLv6YhQ8`@4^DAL)M8{f2wGMtPc^F4sMcuQ+}-N9g}Ft$#s2mFcXaFQ*43@MTQBvl3vMpAOKw-xxTeN+ zHEybLTaCMF+*jkF+fTPjH^3cqx4GNh&$ypc;}7>c?)Thhd#qJslgAE^6KY)W(0ICg z26+N%fSy4KAqjO7BGiaZh)IY~NKUAqkd@F_jV5a3CA3Irm9RNsYl3^Cry8{ry%T*C z!xJMC6B4zFWTGpvAaPjYti<_=3lf(mdTD*Mf!bg->S)8Xb+u927;UUJQLEJ^tC6Zk zhPIJ5OPi~0rfsEdqwT8guI;Jqtu<(kT2gD*I<%Zt()Q8L*Dlm9)-Khq*A{7yYL96{ zl0uWnWFfhK^73RQxmSulWkAa4l-VhBQx>MIN?Dt-Gi6W8;gq8(r&G?QTuAvNQoU1sQ`@GtSEFO<=*+R1<1!~?PRg8;IW==e=EBUynMIkuXKu{goVhh~ zd*-gpJ(+tm4`d$7Jd$}n^I~RM)~_rj%QM?EJ2E>qyIyuec6xT}?6%qMvgcUQT*Wc1}*t+MM+{GjeC=F3Vk&yE=Dm?#bNKxtDUU>X7H7{s>x%su`kD5Pj-mk@g7QI{QTS~18 zT9vkX(#qTpZb!7Ywa@F=tmEd6TRZOPxU1uXj*rxT=fB;lXP4exY+dYKv|W?CHt3q( zb$Hj2U8i@Q*|kgeZrz7=AKraL_fg%)bRVzAr0z?*FYmsx`|9p{yC3L2sMnBQD|@Z) zRi}4!@2$PJ_f~ortx|3?uNzi0Qg<&6Q}-e*taw@Ry5dvCmkPhiU^VKf5ndTl8C4ly zsZ}GTGPN?jGOH#>jn3+h45J!|8csD_H5!FfN|l$2`hJ1>`Ftn0Zf?~I^vWrR+jTp1J9T?>`*izt2XqH@M|8!yqq=jtKXg}g zS9O2t?&L$m)Hl}W>YM8G_09Dy^=-*~a=?Cfu>xbxv>WAq^ z>PPFx=*Q|O=qKtY>8I+a>u2g`>*wm{=@;l1>KE&m=$Go3>sRVm>DTDj>euTx>$mE6 z=y&RO>38e*==bUO>ksG;>JRA;>yPM*^+)x`^vCrl^k?*E_2=~G^%wPj=r8I2)L+-% z(BIVG(%;qJ*FV-j)j!w2(7)2Z)4$h$(tpu^(|_0h(3k5g^i}#_`f9zR*8u7h8sMQm zRn-D&173hP-~;#qen21)41@roKsZnrhyY@MI3ONK0JK07kPOrZ8Uk5BHqaQz0dj#R zKvN(O$OoDM&4HFcYoIOA4rmW_06GDkfi6IIpa;+s=nVjX0RRCbU;-cj1`xmkU;qvf z014Ot3a|qXfCgB=32*=p2!IGkfD9A>eSp3|KcGJ_02l}i0fqv@fDyn*U<@!87zd08 zCIXXyDZo@<8ZaH03Csd!19O16z&v0+umD&HECLn-OMs=oGGIBd0$2&G0#*ZSfVIGS zpa|FmYzDRh+koxB4qzv+8`uNv1@-~^fdjxn;0RC*90f{%W599X1aJ~K1)K)X0B3=7 zz4fPBO2CX54t`e z3_~MBrXkCaZD?%BG2|MW7@8XL4Ecs;hUSJAhL(m_hSr8Qh7N|Vh8~7q2Ax4~01TkP zXn+lf!D7G+xPdT`2AhF0I1IFbH8>5tK`;~;`Wc29Mi~kX;|${s6AhCLQw`G$GYzv0 zvkh|$^9=J1iw#Q+D-0_Qs|;%l>kLJP4Tj$h8x5NbTMgR`dkhB*2Mvb|M-3&0KS zw}$tIkA}~NFNSZ1azl;56RZXLfPSDq7z74`pOl}Rf@Tl~5zqpnAO_+f3EDtA=m2Su z1vyXzU7!TYU>~qA*dH7K4g?2*gTW!-P;eMH92^0T0!M@6!13S&a3VMfoB~b-r-9SK z8Q@HC7B~l-3(f}@fD6Gz;9_tIxD;Ftt_Obui@*)wHgG$*1Kb1d1^0pb!2{qy@DO+y zJOUPj$H3#@3Gftn8axA@122GofS16_;1%#1cpba}-UM%hcfot$eeePJ5PSqa2A_aW z!DrwL@Fn;Pd=0(<--7SJ_uvQcBUlE02ETw`!EfMq@CR59{sgPQUtqQR64Tx2Ve~Y5 z8GVetMn9v!G0+%dtYZu{h8ZJ`F~(S9ys@59YfLt#80#Aw7}JamjTy#9#w=sDv9U47 zm}_ieY--Fi<{O(CTNzs$+Zj6;I~ltedm4Kgdm90x$%q&&M$CvC86#&Dj4q>O>}MQg z9BLeH9AO-39AzAB9Ag}3oMfDAoNAnDoMoJCoMW78oM)VGTxeWmTw+{iTy9)xTy0!q zTyNZ9++^Hr++y5n+-}@q+-clp+-=-r+-ux#JYYO%JY+m#EH)lB9y6Xao-&>`o-v*^ zUN&AaUN!z{yl%W{yk~r1d}w@Rd}4fRd}aJ*tWQ!&9uX`%e2?D&$Qok&~(Uj#B|hj(sbH%!F17d%XG(d-}Kn@ z#Prnk%=Fy!&h*|?X8L6MZ2D&UZu(&=H~lnKn5s-QCXLzM>|ypa*D`yXea(Jme{+C2 z&|JqHY7RHoHAk2u%~9rPbF4Ye9B-~?PBf>OQ_T&`Y37FJM&=xI6LV8@p1GO1xw(b8 zrMb1aow288hQ%!c3ZNX1m#8=FGfV zG#8lrnERUhnfsdun1`B&nMaxn%@fQM&C|^@%rnii&2!E3%nQs5&5O)S&CARy&8y98 z%xlf-%U&_nKzran75j@nYWvFn0J}?nD?0vm=Bqcm`lvZ%*V|q%qPuf z%xBH#%oofT&6mwr%va4f&9}{W%y-TA%=gWY%#Y1a&9BUF%pc4j&7aJl&EL#F%s3e|r9tUXLnsrk)B9_j#fggQZ;p)OEYs2kKB>H+nH z^bi0UAP_P_W(a~%2!n8lfJn#&QIG>-AQo~$5+p+fP#>rt)E^oE4TJ_mL!hD1FlZz+ z3Mzy~Lt~(^&^Ty3GzppvO@XFD)1c|l3}`kq2bv4bhZaB!p+(SQXbH3wS_UnLRzNGE zRnTf^4YU?o5B&xeK^vgop^eZcXfw10+6rxhc0fC!UC?f5540EB2OWS8LWiKkP%(5A zDuIqc$DtF@N$3=G8ae}=h0a0ep^MNT&?V?HbOpK!U4#CFu0uDWThJZoF7yC;2EBk@ zLa(6L&>QG2^d9;Ml|f&iuh0*u9Qp}WLBAjk>;}8TwO}vU5B7%x;6OMC4u(VEI&df) z28Y9S;RrYqj)J4%7&s1&hZEpLSPLh^DR3%WA8rUYhI8O1a8o!B&WD@9t>D&hTev;k z5$*(chP%Ms;O=lw7=(?m2{ywJjKCJy4m)55cET=LhWo&M;ePM{cpy9k9tsbGN5Z4v zLU=Sh2A%{@hNr+&;TiBucosYxo&(Q^7r+bQMet&H3A_|u4zGY$!mHrl;NRg*@D_MG zyaV0|?}qon`{4cXLHH1S7(N0Q!$;u~_!xW~J_VnK&%kHlbMSfi0{jPj3BC$ngRjH4 z;M?$h_yPO~egZ#*pTRHSm+&k2HT(vC3%`Tk!yn;K@Mri7{1yHV|A5QkD)<*%11qo_ z;(>S~wGeN_2k}Mxkw7E}2}bH5p-31~7l}Y3k!U0aiACa&dWaTDLQ;@aq(0IBNkbYU z8Au}}6UjmvBRNPe(gevv@{wjpbEE~*5^06BM%o~4k#5Ozix+2|>?nn=$ zC!$022!Mcy5iuhW0wWd#MKHvQ;0TG>5DKv)4unQn#EEbSj|hl_$VdUw2kDFSL;52F zkb%e`WH2%W8Hx-;h9e`8kw_sj78#FBL?$7Vk*UZuWI8efnTgCoW+QWu`N#rfA+iWr zj4VTzBP)>A$QooVvJP2~{Du@E8<0)NW@HPp71@StM|L1PkzL4cWDl|z*@x^$4j>1S zL&#yI7&(fRAjgms$VucBat1kzoI}nd7m$m{AIK%-GI9mEiu{ROM{XduklV-|+kyprTDm^X=`a`>1gR}>0;?&>1F9{0W6@!Xt7u@i`9Z#2n%VUEDj58 zVJ%JzXW=b^MYOmql0~)@So&D{TKZWAS_WH&S%zCiSVmb2Eu$?HEK@AgEYmGBEwe1M zEpsgMEekA*ElVxSEXyq`EUPT5Eo&@mEk%|MmMxa8mK~Ozmfe;;mc5pJmi?9kmP3{! zmSRhZ<(TET<%H#=<&@>L<*enL<-Fw&%O%TY%N5H_%Pq@Y%YDluOR43t<%#8~<+oQf~QaskHpER9k8+8q^*2Mg7nKG!P9! zgV8!@7#fb&MI+ECG#ZUT|Bq1=bR4g|)`oU~RGXSO=^l)(Pv3b-}t~-LURh53DEF3+s*PFg*rh z5Jq4&jKZ84hl!Yk$yfo_4;z3D!UkhQu%Xy+Yy>t6E5ycP6S1k-3~VMg8=Hg8#pYuR zu~pax?00MJF#8Ze(Vr-7(0R;!;WJov2)mY>;iTXyM$fFu3*=&8`w?k z7IquEgWbjMVfV2I*kkM|_6&Q8y~5sLZ?SjSd+Y;NhJD7qU|+Fs*mvv)R*qF;HJHZg zZuPL%vU*v)t$tR2Yk)P-8f>j&4YfvCqpUI3cxydtf;G{aWKFd;u%=nltqrY>teMs< zYqmAVnrm%p&9mlPJ6bzgyI8wgds%y1L95YfvO-qaida!AX0=*zD`~Y`X{*!9S$V5q z6|F9-WbI?^XYFqtU>#^3WF2fBVjXTBVI655WgTrDXB}^yV4Y~4WSwH2YMo}CX`N-A zYn^9ZU|nHdX-MY!T&AQ#X!@A45$GXpY(0a&v*m}fz)OyT% z!g|tr+Iq%%)_Tr*-g?3MhxL;6vh|Afs`Z-ny7h+jruCNfw)Kwnp7p-*3v7OjK>?C#(dx%5CVd4l;Oq3AEh~vZw;v{j3I8B@(&JyQ{i^Lzq zCE_x1g}6%GAZ`-3i95ty;vVsUct|`VN{PqB6XGfHjCfAGAYKx$h&RML;yv+!_(+ry zpNP-I7vd}No%l&q5LLu4qME2h)+W73A5#5S1u~EfChL%4WL+|fj3#5rI5M70B(-D` znM^hy8$eZLn@;>>1d_Td*y}7HW&IMcSfm@wR$4tu4ux zY|F4UvSr$`ZH;X?wp?2iTb?c7*38!2*231>*2dP(*2&h{*2UJ<*3H)4*2C7zrnBj7 z2Ak1lvOzZ3hS)Hh)kfGzo6Sbq7#nMoZGCP1Yy)fqZG&y2Y@=;sY-4Q`Y!hvhY?EzM zZPRQsZL@5%ZF6k%Yzu6QY>RD6Y|CvcZEI|6ZR>5n**4fV+BVs?*>>1=+xFV_+4kEG z+78)@ZAWb-wqv&AwiC9Kwo|sVwsW@gwm)o_Y?p0UY*%f6+OFGf*lyWw+wR)#+aB4T z*q+*+*`C{8*xuSc+rHSo+sbV}ZB@2kwrX3AO|iLC9+W3li}Ip;DL=}e3Z_D+I#ehX zM%ASvs7NY`ilJhuI4Yh>q_k8D)qqN)(y0up5tT`0QQ1^uDu>FYnov!tJSv}RMm48e zP%WueRBNgY)sAXUb)Y&@ov6-K7pg1Oo$5*Trt}m*fs~OlQ4j@F2xXyA3ZtwPL6MY= zq9_MNQw+sYJS9*f<)S1?rV6OOR6nXeHGmpK4WWio!>HlZ2x=rXiYlZ=Q)8&H)HrH9 zHG!H)O`;}KQ>dxbbZQ1Qi<(W%q2^Nas0GwQY7w=VT0$+QmQl;8mDDO~HMNFXORb~U zQ@>F~)Fx^(wUydNZKrlnJE>jNZfXy;m)b`ipbk=psKe9|s+cOFj#0;{lhi5dGN<6kx<%cl?ofBBd(?gE0ril2M3qvHsVCG^>KXN%dO^LSUQ=(V zx70i8J@tY5NR?5asL#|F>MQk)`azXbKdB0;lB%M9QPorprLnu&-R&NBPkSx9m)*x6 zY7etV*<Hb9)PWOM5GO2YV-b zXL}cW54+wD*v)px4%;nu)NZxocEV2DZFb6Tx6^jU&e{9g``HKB2igbQhuDYNhucTm z$Joc($Jr;?C)y|3C)=mlr`u=PXWD1kXWQr7m)MuvSJ+qD*V&8g8|)kHo9tWd+w9xz zJM6pcyX|}I`|SJe2keLJNA1V#$L%NW7wuQ<*X%d#5ABcakL^$F&+TvR@9dxKU+mxQ zKkXIvN_&-EZtEXb7VLg zIWisDj>e8$M-xX=N1h|!(ah1((aO=r(bmz<(caO?(bdt-(ZgYIfDWU>?m;@a~yY^aGZ3UcARybb6jv-bo}AC=D6;-;kfCz?YQH(>$vB*?|9&N=qPnObv$>x zaJ+Q9a=doDbG&zabd)(hIX*kSI=(x~9TkpBN0sB3qelH8+>@?Nd(qys5A90_(1COa zU55^*>(UW)BppRZ({Xe?T1zL<$#e=`pKd^>(GBTLI*ZPx8`C*-F5Q&Qqx0!zbaT2T z-HL8Qx1&4I9qI0LPr4V~o7T~K8lVldkv7v14bv7Hr7_w{<1|UzXo|Me4w|MJnx#2f zphen6%X9(Vhwe-Fqx;hX=z;VgdN4hl9zl1p(IdImj{ zo<+~5=h5@&Mf75NDZPwdPOqR>(W~h-^jdly{Tp3GZ=iptH_@Bv?etE17rmR_L+_&x z(ue6{`Y2sOAE!^!r|2{ES^6A(p1wd|r2n9=(AVhe^bPtZeT%+J-=pu-59o(T5f1p3oW%MWdGyR4BN`Irj(?95P`X^mMSJGAVFS?qpp%vPV zac4XjPo@@AoAF}28DGYa@n-^M{{b6cf$FFtJP=6VKFR5|~6r z%Oo+$Oe#~KX~3j0=}ZRGh{0n?Z1&kSS+F+-T4%rIs+GlCh( zjA9DaT?=EFvCKGTJTrlr$V_IYsJj?usQVaZF>{&u%mQX1vzS@RtYB8E`x@3V>zE?u zcV-i_h1tgJWOgyTnLW&2W*@VkIlvrZ4l_rY66P3lf;r2aW6m=dm`lu6<{ERIxxw6I z?l5;!fqJDHurPGzUDGuWBzEOs_Kmz~GX zXBV)G*(K~!b{V^zUCFLuSF>x_wd^`}J^LG5#BO9av76Z~>{fO=yMx`y?qYYdd)a;L ze)a%+h&{|6VT;)k_85DdJ;9!2PqC-jGwfOR9DAOZ-_8R*qd!4<( z-ehmFx7j=FJ@ye>%06bFuus`%>~r=7`-*+dzGdIB@7WLRN4AXp%zkHous_*Kwu-H0 z-JI@D52vTImb13g%jxe7bOt#?oOPU`&brP>XOuJA8S9L9CO8wFT4$0o*_q<3?@V)M zIowJ;C zoO7M?ob#OvolBg{oU5Fxook%yokh-#&MnSu&YjL(&OOe9&O^?_&LhrZ=TT>g^O*C5 z^R)Af^Q`ln^Stwd^P=+)=OyQ5=S}A==WXYGXQ}gv^O^Ix^QH5Z^R@G>^PTg9^P}^N z^Skqhv)uX9S>dd7RylvETNT_mcg}xpHzFa@9KR1vY!VTqyal^S0+(>Q|SICX##&YAiN!(;^3OALT z#!csDa5K5t+#GH$H=kR;E#ww+OSq-nGHyAyf?LV0;#PBOxOLom?l*2Dw~5=#ZQ-_Y zJGoul9&R7EpF6-E+=oxG(Meg$Y=1Gd=}rB&*5|VrhFcs&o|>+@GbdPd>g(U-=6Qtcj7zqUHGni zH@-XHgYU`r;(PNtUe5!(fd_dbZ{{H$;VnGITX~YFcsoz?4DaMQp63PL#Y=nv--qwV z_vZ)j1NlMxFn%~ck{`tv@?-dM`~-d~KaHQx&*W$Ev-vsvTz($EkYB_v;g|9&_?7%B zel@>_U(2uK*Ym&eMf^s76TgMu#&73$@Vofk{9b+^e}F&8AL5Vj#r#pegg?fg;7{_W z_|yCu{w#lvKhIy}FY#CSYy6-5b^a!Qi@(j^;qUVI_y_z${t^F#f671OpYt#Hm;5XK zHUEZx%fI8_^B?&#{uBS1|H^;kzwI-Q?Lm@+G zBxDNNLXMCtG!gQIe4&}pTxcP*6j}*wg?2)Fp@Yy-=qz**x(VHd9zsu{m(W|#33|aG zfPzsl31$HjU;!1Z0xl2&DcA(N;1Fnm6`TSm@PZ(Sf=iGDSttpcq!T@2QFi03I z3=xJ2!-bK;D4|doBa9Ws2@`~g!X#m`Fh!UuOcSOHGlW^fTw$ItUsxb46c!6hgr&kV zVY#qESShR$)(C5bb;5e#H=#(_Ap9Ucq%*-o(nI8m%=OIweUuGE4&ll3m=4!LYeSM_$+)8 zz6#%j@4^qET=*$e2$e#W@Jpx`Y6L~lh;E|0=plNFwZz(@m*_3}h`yqq=r0C{fntyt zEQW}6#85Fz3>WK)5n`kmB}R)eVyqY^#*6jD6fsq7Af}1wVnZ=QY$RriSz@->Sj-ih zh)u;jv6K*r5@8V$Q4tfZ zA}$glDcVFzCr)rMOC5Ev^;UiR;DR#3FHn_`A4K+$?Spw~E`u?cxq` zr?^YpCms+FiigC*;t{b}JSrX&Pl~6+GvZnCoOoWmApRj<7O#re#5>|W@qzeId?c2N zkHx3rGx53jLVPK{5?_mN#P{L{@uT=j{49PEzllG@a`C5FDOQQU#2Qf%H7+-oyUWAn z>GF2@xO`oHE`L{`tBxze73+#~#k&$*Nv;%ELsy2Yk*l#Q*OlkWcQtplaJ6)`alfbMva7(=*VW%O z&^6dK#5K${+%>{g=o;-B@0#SA>YC=7;hO21RRqv;acfh?ON;l z-L=KF-L=ED$F%Nr&Go12j_a=Lp6h|@ zp{vyO-1XA+%Js(e-u1!t#r4fq;Zj^0$zAf0YDu*vZ^=jUl>($7DOd`TLZvV%T&gQY zO0iO$R8LBf5+$vaBqd9!QUfVX%8(jKSyHytM9P!$rDjqKsjbvb>L7KJx=XzzKr%~^ z1WSm7Nw`Exlw_A^iIJQVCyA0vlB7OTU#XweUm7S4l7>pdq~X#?X_Qnbjh4np1;-=r9BM} zDwd8)$E6d}N$H$)Ub-M%k}gYEq^r`O(sk*EbW^%5-IMN152RA*sq{>GA-$4bOK+sN z(g&$b`XqgkzDeJuAJR{$QmU3}Bt_E5ZnC@VA$!WTWiQ!V_L2SMAi0hlDu>IFa+Dk+ z$I9_?Jy|QK%Jt<2a=M%$XUf@fV>wrDD(A`ha&x(*+)8dOw~^b*?d0}y2f4G{MeZth zle^13!K?Y^B49gZ7m8~)^6S7UFWV`H;X_=8(*(q}}FAK6umgEAtkK9-8 zC-;{J$OGj;@?d$0JX9Vg50^*CBjwTZ7C5ac*AhR6J};+W)#{2OSWZ;Ez6csA(tv6}b)W`N2dD?60}X-3Kog)D z@HfyLXaTeYS^=$rwm>_eJ1Au|RAYd>s1Q-eo z2SxxRfziNNU>q*90CplM}VWiG2l3G5;z5% z2F?Iyfpfrl;1X~dxB^@St^wD98^BHA7H}K51Ka~10*`>lz!Tsp@CKMDwqaV1FM5Iz?xt! zur^o+tP9oy>x1cF1F#|32y6^C1)G6?gDt?8U@NdS*amD1wgcOP9l(xYC$KZv1?&oT z1G|Ggz@A`lun*V|><ZC^!rp4vqjvf}_CE;8<`RI3An;P6Q``lffzA zRB#$N9h?Eq0U;0u5fBA2kN`>02htz|hQKh$f;=dIA{YS`Fbc-NIH-XJXo42#fG#*6 zTmUWv7lDhxCE!wU8Mqu=0j>mBfvdrd;AU_OxE0(6?gICL`@zHD5%4H@3_Jmz0#Acy zz_Z{v@H}_{ya-+bFN0UWtKc>8CU_gX1KtJigAc%m;3Mz}_!4{zz60NbAHa{`C-5`) z1^fp70DpqNzzpyY_!pE3$_!`)FUCzJ=u3+03ILj|BhP+_PjR01jkm4(Vd z<)I2tMW_-~8L9$Rh0>tvPz|UiR12yN)q(0l^`M4OBd9Ud1ZoET4K;^aKrNwGP;00S z)D~(7wTC)D9idK87pN=L4eAc{gnC1Lp?*+*XaF=28Uzi7hCoB1VbE}B1T+#F4UL7y zLF1tb&_rl5G##1&&4gw_vmpQiAqYYt59Ea~h=6<$1^J->6oeQk1cf0E;voSNAqk2= z3KWG@C=O|m4jE7qNFng`8?7D0=lCD2l68MGW)0j+{oLu;UQ(0XVCv=Q0_ zZHBf$+o0{x4rmv&8`=Zyh4w-Fp##vr&_U=hbObsI9fOWTC!mwiDd;qG2090whb}-D zp-a$J=o)k#x&hsUZb7%9JJ4O|9`pcu2t9%xLr{Xnc*yORyZ4+1I`KOf^)-p;Jk1?I6qtfE(jNb z3&Ta=qHr;|I9viQ373LP!)4&IaCx`_ToJAWSB9&=RpB(a8eAQ&3D<_}!u8<#a6`Be z+!$^Fw}RWi?cnxs2e>2L3GNJcfxE*!;GS?FxG&rf?hg-y2f>5kq3|$x1Uw2J1CN6z z!js_1@HBV^JQJP;&xS!5f)N;ny)Xvjun(qS8Vn1gv(fJIn>6U>cMLry*%f zS|}}?#-?#;e43CZrb%gXS|m+Li>9e*u{0wsk(Nx`leRbQVcMg#$7xT}a#c%KE}UL2 zy?pxrMHKwMr&4<5^eX99)6>$crB_d{kzO->Nkg?!tkK*?^BT=>w5ZYHMrRvcXmqjB zl}70q5C1&=--b$+8Z`XM`X4(sCSz>IxQy``6EY@dO!^;lHzi|Q#`KIC88iP!I{g1lj{naK zZo_xrd+@L~cGSA=Qx@NL{2pl8!V)8X--Prbr8ANGGH-(go>?bVIr$J&>MAFQgCB7wL}-LSc8HtQSMk8a8vB-F2 z0x}VqgiJ=JAXAZP$aG`|G837DfCz-Z2!f!92k{~pf+GY%B0hvdXe59H5e5k%VT40? zL_}mnL83?ui6c5 zkbB4jT1f%Zgup}o;Q zXkWA++8-T&4nzl`L(pO9XmlJp9-V+rL?@w>(JAOubQ(Gxoq^6oXQ6XY0EJK(MNky= zpg2mPBldGR7VXofhN%uYN8fuqYmn#^Uww8LUa+j z7+r!cMVFz=(bec0bS=6LU5{=+H=>)+&FDYq7IZ7R4c(6JKzE|M(LLy1bRW7OJ%Ij; z9z+kJhtVVGQS=yk96f=aL{Fio(KF~-^c;E~y?|aqFQZq`tLQcKI(h@WiQYo*p!d)R z=o9oA`W$_MzC>T4uhBQ?JM=yJ0sV-6M!%uo(I4nf^cVUY%|QS1Wb$P8WbtJ4WcTFo z1jPs25 zOz=$fO!7?iO!G|l%=FCi%=XOj03Of-c@U4sCdPt>D&;vU13^jIF(GuJcUv)HrTv%<5|v&ysDv(B^4v)!}Hv)i-ZbHMYj=cwnD z=d|an=bY!f=Yr>w=bGn+=cebj=Z@!|=f3BG=ZWWq=e6gJ=dI^I&j-&(&u7mU&sWbk z&kxT}&u>qLC$l%JH@i27H>Wq3H;*@;H@~-lw~)86w}`i>x45^ox2(6Ex4gHKw~DvA zw}!Wlx1P7Yw}H2zx2d<8x4E~4x23nWx4pN6x0AQCw~M!{x0|=Sw}-c;cY=44cd~bicdB=qce;0mcb0dyca9hILSER5 zcu}v%>-Az@!b^H7Z@?S$GTyM4^GaUXt9YZ{m^bd#y$Ns9YkDoO<8{4rz4N^Dy$iex zy^Fkyy-U2yyvw~Syeqw{ysN!yylcJdyc@h5z5jT(dbfGEdv|zudUttud-r(vdiQw` zc>nbt@*egc^PcdY@}Bly@?P=Y@ZR*^_TKT{_1^bB@ILfD@;>%H^*-}H_rCDH^uF@G z_P+7H^M3Sx_I~kx_5Sew^#1n#@&1Kn#Lz|7>@~05p>@oHfdyc)t z{=?p3@39ZqC+su!75k3;zm#k1kr@f>(gJU5;P&yN?t3*traVt6UM3|=0u zh*!cZ<5lq*crCm(UJtL2H^3X>jqoOTQ@l0a7H^Mtz&qld@Gf{aygS|l?}_)u`{Moa zf%qVN7(N^yfse#T;bZWz_&9t#J^`PIPr@hTQ}C(yG<-S^;2;j+Fpl6T?!mn{juSYE z`*0ff;{iN~Gk6FO<1EhMJTBrg9>HUH9M|y#p2SnQjnBj9;|uY{_)>g1z7k)Bug2Hl zYw>mXdVB-E72k$$$9Len@ZIxA8mpUHl$?AAf*9#2?|0@hA9G{2BfNe~G`s-{5cY|L}MCd;BB*8UKQR z!@uJ{@n86FJOlrO|3zdbvJhE`>_iSCCy|TDP2?f+68VVyL;<28QHUr^6eWrg#fcI` zNum@{nkYk*CCU*Mh>AodqB2p1NF%Bd)rlHJO`;Z2o2Wz7CF&9NiFBd?(U53FG$EQ2 z&4|B==0t0vEzyDKNOU4P6J3cOL{Fj@(VOT)^d4*7t5NIoW?kx7z9Zk0AIOj7C-O7- zh5Sl>BY%>=$PDr?UnXB>Up8M3UoKx>Up`-cUqN4CUlCt%UkP7HUuj=iUpZd|UnO5< zUlm_ucNP%uZypnuZORG~w|uvKcYXJK_k9n2k9?1P&wS5)FMO|juYGTP|M}keKKMTRKKVZT zzWBcRzWaXoe)@j<{`mf)GEteSEL2u18kE&0lQw^wwR3oY})r4wFHKUqS zEvS}ME2=fshU!3dq&iWZsV-DksvFgv>Ou9SdQp9-zEnS|KQ(|FNDZO}Q$whs)G%r| zHG&#RjiN?VW2mvzIBGmKftpB7q9#*QsHxO6YC1K8nn}%~W>a%0fC4Fqf+-K>r7#Mo z2#TcqRDcRn3>Bin6iaawPYIMr$y9_=s3@gUF)B_ORDw!THsw$*wUAmwEuofEE2x#! zDryb2mRd(`pf*xlsIAmCYCE-q+C}ZA_EQI_gVZ7FFm;qVL7k$`Qs=1i)CKAyb&0x6 zU8inRx2QYRUFre#ka|Qtrk+qwsb|y+>LvAxdQH8d-cs+V_tXdKBlU^;OnsrgQs1c` z)Gz8cl|lWX{-QI{ndvNaRyrG>KZ23?b`Mc1M0()H+cx&hsgZbUbxo6t?^X7t~5 zbGilHl5Rz}rrXeM>2`E`x&z&j?nHN{yU<2dUUdICL>o3Q^gdI7zVUPLdZm(WY;W%LSqCB2GXO|PNX((C9A^hSCUy_x=p z-a>Dsx6#|_9rR9m7rmR_L+_>c(fjEG^uP2$`Vf7XK0+U*kI~2J6ZA>?6n&aLL!YJ3 z(dX$4^hNp-eVM*OU!||n*XbMdP5Ksno4!NerSH-A=?C;f`Vsw@enLN`pV80h7xYW| z75$oiL%*f}qu z`YZV>`>Xh?`qTW?{MG$6{5Acx{I&gc{B`~H{Pq3m{s#Vr{zm@B{wDsW{$~Ea{muO? z{H^@0{cZeh{q6i6{2l$B{GI(>{N4QB{XP6W{k{CX{eAp>{r&v?{R8|1{e%32{X_gi z{lomj{UiJ%{iFP&{bT%N{p0-O{S*8X{geEY{Zsr?{nPx@{WJVC{j>bD{d4?)AM`_h z*pK*8zsK+OV}9IE_({LdPx)!T-yiS?{fs~CXZ@U?_X~c}FZpGE#IN|He$^lI$NidL z_Z$9%Kj}~TO~2*0{f>XGf1ZE7f4zT;f46^+|EmA7|F!?SKX;&DpnRZNpn0HWpjDuC zpiQ7{pk1JSpkts*plhI8pnIT4pl6_0pm(58pl@J6U|?WKV0d6;U{qjqU`$|KU}9iW zU~*teU}|7yU{+vu00@8qB;W~n16TkLkO5zS3ebT-AQ%V*!T~nG1^9pv5Cc*m5{L$3 zfp|a*=m8^;45R{PzzWy_H!wG_Ft9kVB(N;7Jg_pbDzG}RCa^ZJF0ekZDezBVOJHkY zTVQ)&S73KwU*JICVBk>TaNua*Sm1czMBr55OyFGLeBeUhV&GEXYT#PnM&M@PR^WEv zPT+3fVc=2Vao}0tdEjN>Rp52tP2j)4hrp-6=fIc1*TA>H_rQ<9??6W2PatzJM=)nF zS1@-lf3QHXP_Rg_bg)dYT(EqwLaO0a6McCb#cZm?dkelR`QFxWWQJlG=GD%d92 zF4#WUDcCvKHP|iKJ=iDMH`p)OKR7TrI5;FYG&npsGB_$YIyfdcHaIRgJ~$ybF*qqW zIXERaH8?FeGdL?aJ2)o@1i>I2M1pA06Z8hLARZ)wWY8C+f^^UyWP+g}7ZihXFd9^Y zv0yx?1@&Mem<*ahJ2*eMB)B}dBDgZRHn=hPPjG8+TX08kXK;7$Nbp$jc<@BA-YkIx(G@u1t5PH`9md%M4(KFhiMP%t&SwGnyI0jAh0% z6PSt2BxVXTjhVsBWM(k{12YKYVZ02+;0(ir8J6J~o)H*{i7*NiWmG24=#0T6m?V>8 zOvYv$W=Im?`5&NCO7i_9hFGINEw%3NcvGdGx<%q`|NbBDRh++*%D z515C{W9A9-lzGm)U|unAng5t~%zNeo^O^a=d}Y2d-R_Mr}; zj-k$>E}?Fr9-&^L-l0CBexd%M0il7RL7~B+A)%q6;h~YCQK8YHF`;px@u3N!iJ?iM z$)PEssiEni8KIe>S)th>DC7xwLs$q8`9f4E7-B-<5EtS@LP!cJp?Js$B|^ziD&&OR z(EQNC(BjaN(2CIJ(ALnl(5}$#(4Nr#(1Fmw(4o+g(9zI|(D~5S(2dZ|(4El3(6i9< z(2LN^(Cg5f(A&_v(1*~+(C5&X(6`W!(67+%P)6ua=&x|@aGr3!aKUilaFKBFaLI6~ zaJg{#aD{NiaHVkNaFuY?a9X%pxMsLkxL!Ct+%ViM+%nuc+$P*M+&sJS03cJS;psJUTof42GdF97e)u*c0}Ki7*-VhXdhYmH( z!eUqsN5V=t8jgkIVJ(~pC&Q_*8MebtcwTrxcu{z9cu9C^cv*OPctv<^cwKmXctdz= zcz1YTcz^g{_)z$8_-Oce_(b?r_)Pe0_7 z2wRjb#ujHwu%+12Y#FvZTY;^}R$?o&RoI$rEw(mWhpo%jW9zf&Y(usY+n8;_Hf5W! z&Dj=gOSTQ$mTkwjXFISR*-mU{wkzB1e>$TcY)`fq+nepf_GSCA1K5G=Aa*c2gdN6? zX2-B&*>UUyb`m?8ox)CKr?E5GIV`|}EX<-T#uBWLrC6HvvjH~9GHjS-S&rpdnT@hB zHqL6S&KhijO|mK0Vjb3H=dttI1?)n0F}s9a$}VG?(FOyM|rMu4C7;8`(|l zKkQa^8@rv|&F*3Mu?N_L>>>6Ddz3xK9%oOnr`faYIrbuZnZ3eZW3RI}*qiJv_BMN$ zeZW3sAG6Qc=j;piCHsnf!@gzzW8bqM*pKWd_A~p1{mOo0zq3EspX_fogZ+!k#AW8P za9O!*Ty`!8my^rI<>vBm`MCUC0j?ldm@CQ^&f-vdUJia zzFa@9KR19I$PMBKb3?gd+z4(YH;Nn0jpfF1>=i$5@#^D^r(OiHFats&Z!W_?uoW#jogj2XEr*d&l<8;p85?qo?aVBSRHs^5j zxcS@yZXvgbTg)xtmT}9u72GOr4Y!tC$8F*^bN_H#xUJkaZU?uE+s*Ca_Hz5U{oDcW zAa{s6%pKv5a>uyi+)3^fcbYrHo#ifY7rD#aRqh&hox8!^_}Y9OzAj&nug|CR4fuw9Bfc@;gm20>_?CQYz75}&Z^yUi zJMbO(PJCy+3*VLR#&_p?@ICon`~ZF+KbRlF59NpP!}*c?D1J0QmLJED=O^-$_{sbf zekwnWpU%(VXY&9L@-UC^DDUCDJjUaEm}hy8=Xrq_d5Kr~7$4^~Ugr~hiZ^+Sw|R$m z`T6_;ej&ezU(7G#m-B1*b^LmMGyf02o!`Ol@KAK{Plr};Dd zMg9_hg}=&Q<8Sh}`8)i5{sI4xf5boGpYqT6=lo0l75|$5kN?bn;lJ`f_@DeQ{x|=J z&m?3OvI*IRJVIU}zfeFZC=?Qk3dMy|LK&f)P(i3DR28ZT)rA^DEupqhN2n{*7t)1> zLL;Gx&{X(aXfCu6S_!R%c0zlhgV0gvBy<+K2t9?jCTtgW2s?${!X9CtuwVFBI4B$v4hu(wW5RLagm79oBb*h^3Fn2&!WH4Fa80-_ z+z@UGw}m^xUE!YaKzJxT5*`arg=fNZ;f3%@crCmU{uAB_?}ZP-N8yw3S@gOUxtY74wPt#R6hMv5;6;EGm`|ONyn$(qdV$ zoLFA0AXXHsh*iZjv6@(2tRdDEYl*eRI$~Y1o>*T@7aNF;#KvM1v8mWh{99}xwiH{7 zZN#=>d$EJqQS2gi6}ySu#U5f$v5(kS>?igY2Z#g3!Qv2cm^eZlDUK3Hi(|yG;y7`N zI8~e>&K3a?5)ly0+GvYb%ym&#pBwiJ-i8sYt;%)JccvrkHJ`kUZ&%_tvOYxQX zT6`nE75@`Ih@ZtT;#cv9_*48X{t^F@GD%satWq{9yOcx9Ddm##NO`4vQhup`R7ff+ z6_bifC8Uy4S*e^Pq#b`cea_q0~rfA~lo#mYPc~ zq?S@EskPKbYAdyqI!GO*&QcettJF>EF7=RlO1-4sQXi?W)KBU!4Uh&(gQUUI5NW71 zOd2kYkVZVO$&eCKQc6jtWJ$KLOsX6YYki?mhRCT*8?NIRun z(r#&wv{%|E?UxQnhom#oCF!zsMY<+kmu^V6q&w0*>Av(pdMG`Xo=MN87t%}Vwe&`M zE4`E6OCO|9(r4+5^i}#MeV2YnKc!#NZz)6iBW02^%UR^CayB`;oKwyv=a%!xdF6a^ zez|~LP%b1FmW#+mWUMw$>m&(iJ zgOTI1N zk?+d)>xkq(iLkxr4$kuH(0k#3Rh zksgtrkzSGBkv@^Wk$#c>kpYo`kwKBcks*4(oyN8bXK}4J(QkGZ>5jYSLvtp zR|Y5pl|jl7WvDVt8Lo^}Mk%9}G0IqFoH9|Fq)b+(C{vYb%5-IxGFzFW01Bu;3ap@t zNAW6{;!`MvR{Tmp2`Y>dR#=5s1VvOLN>ovmm=aesMOO?ZsiYKBu@y&gmAT41WxldN zS*R>h7As4XrOGm8xw1l8sjN~~D{GXs$~tAevO(FXY*IEW|0r9Ot;#lKyRt*ssq9jA zD|?i^%06YkazOc4Ij9^`4l75LqslSmxN<@{shmPF{A=SAm77e*IF7e|*ymqnLHS43AvS4CGx*F@Jw*G1PyH$*o^H%GTcw?}tIcSrX| z4@Ccs9*iD|9*Z82o`{}|o{651UW{IfUXEUgUXR|0-j3dnK8QYyK8Ze!K8wDHzKOn# zzKgz(eu#dGeu@5yW<>u)|57ulnbj<6RyDhtL(Qq?QS+(!)q-jvwXj-5Ev6P%OQR5H0I$oWiPE;qUlhvu}Gst(i`6CSQgxZSTwS5AR9C61)phE6b)&jT{YTxRZdJFb+tnTFPIb4sN8PLLQ}?R} z)PL23>LK;8dPF^{9#fC2C)AVbDfP5^Mm?vVS1+g+)l2GS^@@5`y{2AQZ>TrbTk37~ zj(S(Ur`}f|s1Mag>SOhZ`c!?UK389;FV$D-YxRx#R{c+Xr@mJ|s2|l&>Sy(f`c?g= zepi2}KhN#2UsL#Tv(&#G1yM#r}>pkF|)kjJ1ljjI~6+}I}yBNC~yB50{yB~WHdlY*XdmZ~P_CEF@ z_9^x`_9gZs_A~Y?mJ$0C%Ms5R&l}GlFA^^nFBvZtFB`8CuNqH_SC7|-*NoSS*N)eT zr^g$_8^#;O8^@c)o5x$kTgThR+r>M^JIA}kyT!Z5d&GOjd&T?22gL`+hs1}+N5n_P zN5{v+$HvFS$Hyndr^Khmr^jc+XU1p6fjAh4;&2>^d*fIfj}vh+?u%1#f1HW4aW2ls zg}4-#<4QalSL3mGJg&zR@l@Q3JMp>k`SAtuh4H2FW$_j9mGM>aHSu-v&GGH=J@LKq z{qY0wgYiT0qw(YM6Y*2=)A2L$i}B0xEAgxG>+u`$oAJBxd-416NAbt;C-E2Ym+{x} zxAAxJ_wf($kMYm(FY&MO@9`h;pYdPuKmXI#XVS80*|h9h4lSpaOUte0(ei5fwES8D zt)Ny&E36gKifYBQ;#vukJ^25UpKVcKwQ zq&7+$tBup9Xj8Rm+DvV>hG?Yb(gJAKFjtm-buB(EezD>6!G* zdKNvao=wlL=g@QNx%Aw69zCy~PtUIx&Xr1$dKJB@o~BpRtLruNntCn0wq8fCtJl-(>*;y}y`kPnZ>%@bo9fNizWo`T%{PK1d&| z57CF}!}Q_$2z{hJN*}F{(Z}lJ^zr%xeWE@|pR7;Or|Q%6>G}+PranubtKm z))C#Kdv#35bwVd~pHAtt?$-l)P-paz9@bf%(|KLcMP1TmJ)$dmRFCO#UDI{l&=Y!6 zPwA#^>9+3Zu0B_vr_a|H=nM5l`eJ>FzEoePFV|P-EA>_SYJH8qR$r%Y&^PLv^v(J| z`WAhwzD?h*@6dPZyY$`q9(}LAPv5T}(ErsB>WB2h`Vsx8eoQ~1pVUw3r}Z=XS^b=T zUcaDU)Gz6m^(*>S{hEGVzoFmMZ|S%7JNjMyo_=3{pg+_f>5ug%`cwUx{#<{dztmsp zuk|7Vs4`d9s%{$2l}|I~l!zx53LkN%gD$;fPEF|r!jjO<1Z zBd3we$Zg~?@*4S!{6+zzpi#&uY!oqy8pVv_MhT;&QOYQ7lrhR0<&5%11*4)-$*62p zF{&DAMm3|lQNyTd)G}%tb&R@3J)^#nZZt3&8jXy`MiZl{(aiYUXl}GHS{kj4)<#>S zozdRtV01J(8J&$TMpvVo(cS1_^fY=Iy^TIbU!$MV-xy#FGzJ-ijUmQRW0*1A7-5Vw zMj4}xF~(S9oH5>*U`#Y78Iz4E##CdPG2NJH%ra&ha}2-$4ak5E#6S&?;WaP=Hwc3? zdyG#y`duW2>>v*lz4F zb{e~k-Nqhcud&bAZyYfGH4YkwjKjte)*al^Q2+%j$(cZ|EnJ>$Odz<6jpG9DXGjHkvkswAo=(h}7Y z)e|)mH50WGwG(v`brbax^%Lod28o7=Mv2CWCW)qrW{JNO%@ZvWEfcL0trKk%?Go)1 z9TFWAof4fBT@qar-4fjsJrX?=y%N0>eG+{W{Sy5X0}=xhgA#)iLlQ$1!xF<2BN8JM zqY|SNV-jN%;}YW&6A}{>lM<5?Qxa1X(-PAYGZM2BvlDX?Kmtra2{?fy(1a)9O<)N; zK_tk8FF_^fgg+5T1QSdmln5u-gqBDpti-Xzxx}T!<;2az)5On2*<{6J^<<-D>tx4d zw`9-c;N*zpxa6E9n)D>GB%UOaWYU+Ul62Ca3?`XmC>c(&NiNAJg`}92l5#SVRFcu8 znv5mmNiC@-jbtL3Os0}%(n{J%C+Q~VCg&yRCl@3aCKn|aCzm9bCYL3bCs!m_CRZg_ zC)Xs`Cf6m`CpRQFCO0KFC;v%qNp4MUOKwl@NbXGTO72eXN$ySVOYTn|NdB8Vm^_p` zoIH{|nmm>~o;;B}nLL#|ojj8~n>?31pS+N~n7ov{oV=2}n!J|0p1hH~nY@*}oxGF0 zo4l92pL~#fn0%CcoP3gentYago&1x`kt&iZnJSYipQ@OulB$|YOI1r%Pt{1(Ow~@+ zN!3l&Po<}trT$JePqj$3NwrUPO!Y|hN%c+jPYp;7Obtm5O$|#8PmM^8N{vp9NsUWQ zOifNrNzF{nPR&UHDKG`4kQAOGQe?`PqEd9qp9-XcDJB(4g;Q)wNJ%LWu zp4ySxmD-)!pE{U2lscX|nL3p^pSqB`l)9X{n!1*{p1P5`nYxv_ow}2{o4S{Jkb0PU zlzNYm|e|oW_PoP+0*Q0_BQ*Nea(Jme{+yI z*c@sOGe?-C%+cmpbD}xPoMKKjrJO!renJ1Tyvf|-&|lWG8dam&1L3tbA`Fm zTxG5{*P83ijpiovA9Jg@&D?J8Fn5}}%-!Z5bFaD2+;1K*|1}Sqhs?v~5%Z{d%sg(M zFi)DN%+ux>^Q?K!Ja1kwFPfLk%jOmHs(H=4Zr(6&nzzi`<{k5{dC$CWJ}@7ekIcvB z6Z5(G*8IS*5KqR#~f@Ro<##RkSKum8~jPRV&S^ zW>vRpST(I$R&A?}RoAL#)wj~E23A9>k=590Vl}mzS$|v2trk{GtCiK-YGbvv+F9+b z4pv92lhxVkVs*8;S>3H3R!^&!)!XW0^|kt0{jCAkKx>dS*cxIDwT4;4tr6BpYm_zG z8e@&M##!U73D!hwk~P_yVokNCS<|f<)=X=bHQSnF0TyUM7HlCFYDFy7(ygRrTT85! z)+%eYwZ>X&t+Uo!8?24iCTp|xkF~|xYHhQ&TRW_s)-G$ewa40P?X&h<2dsasgVrJI zuyw>bY8|tVTPLiO)+y_>b;depowqJqSFLN-E$g;*$GUGlupU~EtjE?9>#6m^dTG6~ zUR!Uhx7L5wJL|pm!TM-@vOZg1tgqHL>$~;C`f2^Lep?yVpa12gGTE8!EOu5qo1NXx zVdu1S*}3gJc3wNbUBE767q*MoMeSmCal3?F(k^9}w#(RM?Q(W`yMkTOu4GrXtJqcT zG`pHz-L7HRv}@V5?K*Z{yS|-nH?SMpjqJvD6T7M1%>LVMZnv;o+O6!?b{o5`-Og@r zcd$F!o$Stb7rU$7&F*gZuzT9Q?A~@CyRY5P?r#sU2iimIq4qF)xIMxiX^*l;+hgpp z_BeaIJ;9!2Pq7gjw+Y*4`|Xe&wk2D!Rok&$d#*jto^LO(7ut*L#r6_=slD7@VXv}R z+iUE#_BwmLy}{mSZ?ZSr|JYmXt@bv1yS>BSY45Uk+k5Q2_C9;ReZc4Z58FrV zqxLcTxP8JtX`ixB+h^>v_Bs2!eZjtHU$QUTSM00yHT$}K!@gnmKEd*Cx;fpQ9!^iEm($zn<*hI7!ELmOHDQ)y^7ct+UQq?`&{3JO4OaoUP7IXScK0+2`zc4mpRNqs}qs zxO2ie>6~%SI_I48&PC_4bH%ypTyt(XH=SF~ZRd`2*SYUJbRId6ohQyS=ehI3dFi}% z-a7A`_s$3Bqw~r6?0j*)I^Uch&M)V;li~dNUrsHPo7v6kW^=QM;mYq_=EI&NLJ zo}2DAa2vUe-6n2Rx0(C5+uUv8wszaNZQXWm7q^Go)9vNJ4Yv6p< z=Hf2llCICCT-x=!0XOI}ZpaP0tjoE)E4ZR7xw0E^6*uatZp@9lnyb5pn{bnE$~9ff zwOz+`-MQ{OcfPy8UFa@y7rRT`rS39!xx2z$>8^5DyKCIF?mBn9yTRS)ZgMxf|F~P+ zt?o8=ySu~P>F#oOyL;Td?mlHxO>7q>7H^=yJy_9?m73o zd%?ZvUUDzHSKO=aHTSxE!@cR=a&NnL+`H~Q_rCkUeds=NAG=T7r|vWNx%>ArGb zyKmgL?tkt(_r3eU{pfyjKf7Pt|HIyS$GJ|Nd*8d9o18Q_5YiLQ+Ln7+Ti#y1>-Fwh zR!s^YU;mfu|9bryAdol1&2r~($GCst z9>qPHJI+0Zdo1@j?(y6cxO2JlxD(v@+y&edxeK``aZl!+!abFH8uxVW8Qe3uXK@#C zC%HLJ&M7!02XQJ+&1pC-r{naTfirR@&dkko7S77SoQ+%H7P%#EnOosjxixN`+u%02 zEpD5$b35EF=iv4@C%4ZXaEF|WLpV2wau|nm1n1$roR1?pit}>;F35#AnhSFgF3QEY zIG5lUF3F`hmP>OPF3aV(JXhd~T!|}l6|TzFxH{M1np}%(a~-bB^|(Ga;D+3Yn{Y?m zDee;PQttWO72FHC7jsv0FXyi1Ucp_*@!T7@Te!Dy@8v$oeTch_`!M$r?so1|+?Tj7 zbKmB^!~Kx^5%&}Br`*rDpL2I`zu^{Biy<{A2mY@sH=9z@N*X$DiQO z=P%%&$Y01miGMQx6#l9F)A*YF@)@c^$9k4ZM*z z@n(LWxA0aT=571}zsN7~%lrzz%CGV3{06_tZ}Ho_o!{Yic?ZA8JNbS7fIsA2Ji@zq zl*f3SCwLF<<$XNKQ@o!K@IgMr(|nkZ@KHX-$N2=$@JT+!vwWJ*@L4{`=lKF(+ zukcmA#@G1<-{f0-oA2;lzQ_0Z0YBtN{FtBcNBpz-Q~bsJbNEa6OZm(A=kk~H&*PuZ zU%|hCe<6P*|04dy{7d+k@>lU!^Vje%<6q8S%fEuZj(;V8Je=Glf z{sa66`4928@gL?t!he+i82@qp6Z|Ln+xbuNpXNWqf0q9o|9Sok{1^Ez@n7b@!heZt3bN&wg7yK{zf8&3}|C;{| z|6Bgw`QP!s=l{U}k-w9_i~kdUH~(k;9$w@n{xts={;&KQUM9>4v%)#TG2vf?M+uJ> zjth?w9xFUfc)aig;auT7;e>F$aDnhd;X>g_!jpxk2u~HBCOlnuhVV?`S;9pEBxnS) zU=bFCbzwuW3z*;$d;%#@LO`H}n2-<{At|JUj8GM7LQ`l99ic1qguXBkhQde~3lrg# zaItWSaH(*a@Lb{f!WF^`g)4;@2`?62BD_?%MtGUL%jlwO$n}jzDZxP-qyiIt!@DAZ!!n=j{2=5i%C%j+ykZ_yu zVc{dfM}?0IpAbGN+%9}t_>Ayb;funTg|7%-6TU8dL->~PZQ=XEkA$BHKNWs1{6hGZ z@N3~W!f%D&3BMQqApB9dQ@Bg`lW@22XF(MHBAfvto-@=>^jZr%#$bdHU4p)2GjvK6Co4=|$6%Q~6Xmg{G>hda9Xfr@E5HZ>p1x%I(&<&xtEbmYUp9UD^xEkw zrreaD3ey{>H%(tPef9J;Q{z2@dtP?W9ryhHp2v$%5YH9Q6VDf)C|)Q&RXi!qiE>dX zLZU|0iaPNh&8Gj~_KVH;r7ktM77iAkXMO?53yV)*I(O-X=4;K>)u*oh<;)jWf3VtG z`yxpF`B;@ zv8P~9#h!+}8QZe_ZvOZ4f0+N{{GIc6&Hris?)g8@-!m`HOY;vXASz{$Oa&CpjWUzW zDuZP}s!ayOKV)%P0t80J%F;l&JO@G^gn|q#|0DyG4P?N9@LrwRv-+=ZzE_>}9kMUT zz9>7Z^9lo{*Rxu$3p0x#EP=2L!U_nh_o}|Wapsnp_s!fob8>bL1o^B9XuAG%_Gcjc zeD>F~zX9R5v(P!JbKrAqAS|5o`-}c?(H}3m6NI}i`qM>sU-XxY{(8})PCgoh;~+fd zmY|v23gwYsRs0V!Y9Glj$|4 z*Me}f>5ZmaOm8y1+4N!4M@%0zea!S}(`QVdHGR(XCDWHp-!OgC^f~kA&0jTt&Fq}t zpP#o_EbEpHphdc6Nmv+5-cqm>EhS6YQn7r`@_oy3>tn1iY=dtEYNWToZ-QUH_=d&5 zE}j8P<0qENOO>TFOS0u}Eq{CY&nx$=6jqC?-v=tAKi|A#^8?!-+_u_b`=Wix&e)Sc ze23oo-0tUhf3*AK-J2Y*a@_2Ao#P&d=y=TDWA{Gd{HXIz=UvV}Iq!CgP6>q5&hz$9 z>|e0|#C`3)ZvT$MUmTw6IuGpmN3Qdc3y>7TBJY3BxtE;1(|Pv3;@P`|FTCc;YhDKK z&b{TDw}S9C5Z->xJFj`yHSfFTRuJBQ%?Gae;58ow*R>x5SGKo)KC)E8EY2 zYg-0f*Zl}wGfCGya6CLXMT=n(5#1sxVj?aQqDSbHEDej90;-Tmg z&wA>;;__?n_0qfQ@~bb8h-W?cUJg9>9_%%EaQWfou6un4QQ$p@|A+q|d9N2>NPGeC z|GVs7U%=-9Z@>)j9AqwMfhS=Jco3$62VwT|D)20<0MEj+euYQCQ}9KXUwN-bVeRrd z@Gb0I-oE^j%kyGEEQ%$uELOy-SQl$zQ*4Myu_boJp4buF;!y01192oy#IblJo)Rw> zpCeu(UMgNDJ{L@&zFd5s_oPl~sTpAtVUen$MP_&M?O;+MoP zh+h%EDt=jH#V?9q7r!BXP5hSlZSgzecg63C-xssu55ymdKNf!~{!IM2_!BWL-XZ={ z{FV4?@i*eXi@z0rC;ndigZM}BPVp}BPvW1&yTyA%Q9Lb5qFvgNcBMVZ0d~AYXAmyc^ zRFcY4MXE}#0}ExAlm=)BC3nPam8{PPM_OC4z<9Z9F8=Sa_$ zo-bV`@zPYfL3+LPHt8MGJEiwXUy;5o{hRbB>2B#B$#ps?21H8qiw{0NKR$D*?2|LH z{{|P{+t91Pw)ZppYLI?}oOlhWdq20`JagvEduGmTKlq*9m-B;q56>xC0F?a$>_JfW z0CTd?%qbZSY>$jnd(jyS!+`qCjQv<@W=6(>G~mhEnHhV2W_Gp++AGbR0y^umnJOr& zf_x3c_woAK_RPhy?u_h;!OSt)a7M~R64AIuE6;E?^_;P?$-|GN>i{Ro)73DkS!JRmW?2ljO**!I82oNOO#3pjBA;{QI! zWQSn;L-1Z)ApRR>5s<%+Q!+O=?of~ioWekifnyN|@!xY?MgTkDln2EB_c&kX1MT}} zj>$+6|2=jY1?>OBoch~-cx7f*whI2n-*Zg120s5fD0?ucWE;SCA9mR$NI!&`Ens_i zPRO=F8Q_E+#Q&J%v%530;|@^g!2rWUUh}~85N0f(eJij(m>C%i_75Ad+raO>0OEhl zG1($0zn^1EApOWWC0hpd|DFeqnZNxAuLGI;n3cU=c0%?B*_`Z+!1hMjDRA8=dkCjw zZvr-e{mmf$C(OMCl;6kPvA2QrgPF6x1K8dnJ0^Q4h~FujmAy+gBYU^(V%fif{KGKw zUSR*n9GAThl>c+=vRgr&|5@f_?+0x@JTtNnfU^6U`yfc)kNra+{ZFvp2Ff2fGqWF& z&DlQ&cIi*ZW{=+vw!K|;YWCCMcl?a(xa_ka519QN_$LE{0gxB zJ$Bhwf&C#I{~BoL>%jg1v$Ai1`~#ejeG~ky-vYLOz{TGIWsiWF?}B>wGxI%=elW*m z-v_n_Gb8(f%r5&Oumg_&NOs)*6Oev*E|mQYl>PUx%YF{FeHc#N0qlSizW~FpUxM^6 z!Tb3)5I=-tzXG=VI3fErNIwjxego{k0mtEQK^y-L+WZ~J15W)O#P@OR{5wJVK2FK* zlF2T(8{`2e{tV)W;nY3A{$FI~?2!IG=428`Kfs*qwCo1iUx5uUa|XnJ&m1TL1)x6# z!-3OVXuWRC}B59XBY z3BdL@%$++Un>}x4Pj>#yaoGhkbFwFbKK(*a=fWBL{!>Bx0LNrc19`yg)4_S{86f@e z%*vh#$^fUH1>(Qq)I}iwf6g)4$r)Kl0nRx}(B6NJT?T=A|8-_%DzF{Et_HDs=7dZ$ zBRi%A=||3tOb6=!JtvMEfc<}tS($O>)NwOt^ATbPd+@`)t^?M;$1Zy%us=LAvg^Uo zz=30w2X*epE`anu$1a#=_f??Zf3-|D_ZpCY2EnH8LkEP2RI>n1^E2H^q^M^3_nBk<5N-0_se_Z+`^3&u4@5eOxTN z7^E)-fA2XUelW*mmjK%(;J3IG#Fv84co~QRbI%3wBjniS;Cp@^==Prvws{Drt^l@w zjvdta$FEgT^Z<{V-2nNA=XWzZpzQBCKIf2~m~qNJdmNG3kE5XLBEYxc1$6;^KNyMy z!Os~6W7G(+MPw)DmO%`-0Yoz8Kjh3Ao9w)^Rlv&*zV%rUz?bkJoH^(5vNPvA8RY+S zW-oo3YzDsw9Fr$O{gdE#m;)`zLHYsaWD1$=6fiyLRhKv9O?gY+mUrY`c~9P#59EwI zDNo5+d0L*4XXQD0US5!&UHkgcXJ*e>;U~-G@bsYIinz6I&EB5B z=PD`dOla{R;iqvKaSpLc1c>h>Z3~`ZX-&6POdam)@>G`Gy@ut1J z_k-SFd!OXve6RK0=KGFMMn0N^$R>F;`F8SqTY|R-KN&nv zJRu69w}&1_lR$?)2K47&O}~#0L~e`BcfJXx^7ioY0> z17+J>;ypkYHU<<|uK+rzUt{Kye_+l}E+;KO2lR1OBUfM24%g+V+FW)X711cvqplxys&?xycP#-y6Sq17J8lV^Qq3ZK$ z?*dv4{{plawDrsCZ>*mO6au36uHXM8@xx$+`nQ2q*`d~x#a`^~e7bne z;2GlegD(y57(P?{6?h>2Eb(v>oxEpq16bS4cXaUV8=rlVI0M$5dG;lr1S`87Ui!{U z$;)W4p2tb?t(TpB!un`1v;6`vmw5o@{(cb5$5n`bx`G7rOMeGuF-hp(LR=nuyGgmze%wVX4*#WNxe)Qi5zV24wSAKZSRWJMQ zJvxyGp20TYY3l&Kv;^>@1zxnk=Ta{kM9pcC&a zBtA{}(%Dn%!@mCie*XXW^Z%Fj^RpfY57+1a@BaOv2LS^mp%lbIX($6_p&XQl3Q!R$ zL1m}{RiPSGhZ+#*lAwn>XZ+=i%XXnnVZ&@swP}DOz>>{t3)-GwQ`?j_gAK8*->3e+@a>o3B_$yTI z^;oDI8^)kfFE`)oH(`~N3QD1ptL00I1K>pwk`Hu4-AFgqO>{@PtilCG3Xq0TWE3d{ ztwH2HZC^XmjqMT%}McRgg-hQmZs7txBiTtIm!; zvS0*Kl=~GSMLJY?ba7om$LNx}l#bP{Mzm3FOdHoG zw2U^XO=($eTAR^kwQ{vltx%iPO7)@oKy6k->Rt7YdS0zo@2j0^t6HVrQ#;fawMM<6 zcBv8dvf8ai)v#Kp-cn;~T)nC$)E@N$*pa*Pz)iHHkolrCCq&lT$)oJyTdS8(QBSeSdKyj#WD-eZCfht%qUR+bG zDl%ZqxT08AB;;}Vt|B6j$)oZ;g;Noh({e(AD?AFXf{^3#4aKIyu2@%WDYg}uBBF>Y zVv4Xr4m@&{a;vDKE)kIp_xT3cXSf=~a5QUZdCQb$Y$t zpf~DGdb56BZ_!)zu->L$&@bwj^vn7c{i=RVzpmfVZ|b-7+j_fxN589g==bza{l5M{ zf2eoq5xrZF>M=d8C-fe@SMSr4dP?ut2lPRGNKfm-`iMTNkLlz3gr3nS^(j58PwO-K ztUjmD>kIm#zN9bfEBdOwrmyQ8`li06mm3rYr2#Ui3~GbsY$svR8w>`c!DKKS<_#8u z)c_l8h6Tf-Vac#;STU>`)(q>04a25k%dl;*8+Hu428UtK;56(T4h)9|mjN-j4X6P# z;0D6rF?bC=18JZPenY?zG=vPaA#8{kqK23uZb%pyL(-5ku!giDW5^nEhPlzJ zvY}$A8fu2Rp{*DYr1vahHg{0rQ6oobvwFUokO>$bL#eW2f9O@ONZ#(I#icXShcX$rd`l3YL~Rj z+7<1pc1^pk-Oz4ox3t?@yLLyrt95Aiv`+25_CR~6b!ic;TZ?Mr3YP}axHYH-)2wOM zHQ*9M6W1(hmNhFHO5@iAG(k;BBiAT2N{vcm&=@r)jaf6Vv1qIsSYy*HXfztFMyJth zHZ@zCj3%qeY4Vz+CZ%CD+ZwxON3*MOX!bNt&A#S9bEv^JgvO)sYJ3_}6V^mDtfH(@ zYZy&UlT>VIDw;*js-~zZX%ZSB?5?S5fQW9{UGsI}P^1DUwi4@ub~N2lx0skZ*~cwW zJzHoDvH7u_G&H<9qi=vu8r$);(dxj58(5|^#CvX4CW)X_vdBhFiIRIBNS*XE_PDZ) z6*R?eVSQA{p|z}MCvHrmp~fJALqj+_8g32`QLN_oD@boyllGOZ-4X8fY`Y<#9Jw1$ zb)%I|bd|xW#dd^T3_#^l|xG!3q zbOT7SkTJBdobQ&_FCe$rddEaV*}eQ`YOb~ftNWSw!~ zYo4`UD}?pT=>(PYOv+|ots3;Fi;8{;+YVYsWekp%JrlfM-35Z3z0A0!sM_duXt`j< z6?7v+P@0SnoWK-qpbO{Utb2kUiU<}y>>g8mPaJO`oEu_}QyQBEJXW8GVYTNy&#*K%wjH=SC4x-UP zwAJhn+KussXArRl$8J@9;%@sZm4_3v(u#(9TK7h2D;;g`Mm2SNwt|%M`HUkPuQbUXO5ui_!);B%y%y;s z?VVVnRc+)JCWlR5t6e2iUbL84D+Fn*(`+0J`}8iA={jT0T%zJehLOd*np~W?2C4Ms z2nsrJKb{S2X0Ujx%v8$dtx+k_Pi_rb9zB!FQ>lqhn<42qxzgU~O`_#|F5P3bWuU;3 zX?x~m|XDOoWv2Qiy(+lM0Cqe&(c!$R$H$5YAs zJRv&U)kl~f9Z~`%FmG*Bql}pXqq&3*dhRVhYUQFbP zxZ2mw1-!dimbIi8LaJ`Or3&VI`}yoB8#{`IL&mVBxWej@LDE_*H>*Q`wLK{NMx**< zlVS1wzB%qpY-LQ9;;@RTD`p_~E04`r`r}e)fG%RXVJzuS5fw!Y8RUzVOo^ll!z7wc zClB%w+#g-+0ok|uJigfQ)eiHG66M}v`fQ;HkJ}7GsH*y*BMT=DNSa+Q1X9gbpb8he z9=hxfYYAm662b@mf|uR!8AE7mgax`CAnH0`*L|(li1oxRcrQRVb~<~}^^P~5jr!s# zAUs7BtMxIPAlsxZxsW8=`-woo5K(tmS!YStUcv@GQ<(L6iKu&s#t2=0on2$YOs{H- zc1U$_u^S2clSN9INKASjs-kyC(xarp&5+w^`)DhSrB?&?+Bmt|JxEy7xoAEb7DBg9Bc57J)-X*YgU8$~ZEOuZhB6s1^g4rhvg+Po1N~~GFII^qJOt&J1bj69L@Mh9x*AtKc4B)iML^5`&@Pw)7G{q;Z~zS%RElb#M^ zD+X{C+ASwjTkPSuj&%q1#CB#IPmV1W?_|A848o-yWX0FONH#mEWQVN2?ir-UntmoZ zsCILe;=*{h6AgCi`B;S$DBA`7E^cekGNdx{h~@7A~H3yw~xP>8h}Bma7Q)NTRg4Ry~IBPlJq6ZWHN8X2;g z4YH2xc|3?=SSs~%89L~NS|f@bhlc)^foPS+eu^ApS$dF?r>Ihofzx9&JuR2f@NYArC)TOMx)mp{VBU0CJHA6L5b|usrF1Db4%X^p&_Y2WrJmD@AiFVt&=4&RFlgiYX z%vM~HVLDEDaMIstnR|z|7DjYhnccbY%p#ma`(M0YdmShyCdYGUe?ov{Rv{&0Lm zTjJ$dKFm;qKoASX`^`Yw=`pvpF=r*vqT^XsOIjk~%rIZK>$o$Q`3ROIb4$o-9WDj5Sy9L__

H{CX)Xsu7>WNJry({w%Y>nZD*@X4avXS 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

sRDC6S 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 z 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

)V9yIpKRo_&!JYUI}D8*Y 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 @BdJR@3#dBIGSGDT5@H<+FDvX zhh%lWrzycInpn=VC(aImntlpyLlj@>l;b$Pf#=X9Tven6ggfSc-_aBq%oUp|OAyIX zL)POrO(kHJ;7CoKu4yU>70n?Rb)_Aw@=r81m4sEoxKbPYttewq=85^|z+&dsY9+=H z<=j2@yPjI3Fr$WR8^)v1xsD_sAFlLNVILA!SgW1dF)~$R5Zg zPTlS#_5@X#NsM~viY_k)^iKl%TjIvzo5;}^C&YQe{0OnWcS^G2pDO2o%aoo04RV}| zhQ$XRf@L)Rl#eU?8E%{tLmHLH~;E53aMb!nCw40y&PBSGY0XzMLp@ATbar>6k~Z~9lO zxZ|A4V|$`h%KB6!N~;96r^zdw#qY!GCjO>@O~1s3URj**F9Su*fmhRj9?4S??rO8RI~kX z?3CQq8o7tbl_hrzTCQ=j?IF`pUxw{dkhj_AQLGc#z=i(CmbtM2X;TyRuLDebWY2zAHtOxGMfB`M{Nm$PVi0#egc=V4}4kO1w0@8dKk2TeB=_mEOxOfi9YAvKG!75sKBFIcUSVCz^vSvx` zMG~juBFEjVA?>4{u7yfb%lU>ps7y=y?eb&yUI5d>bTA)ZaY^B{IUS4lpW_fTK5dRq z^`wUvc=Sc=XwMD=;9_*V*BWlmo5?CQw>-0$$3XD=G>^{crg;p4x=yXcwXInemlRjU zVU7~LVT6w_LH5j}FT%Sqa}abiSH9oBnGdoOq+qqQK_Hu@WzTGuHVj~~wBvbZIZ5Q` z4fxy|-K;EahE|C_4~qEzp%No07>eOPw|1D|8C8$9{`>&e%GaO8Mz&Rc5Lu*bU1On} zQWO4tss76i_`spKKUIAE+5c{ZHbZYNW%elq^`(5wD`~dSq6>=^ILuz?Ch?(s9cxkY z^ELGU-35>fcaCV%cp23a?IAAdFcZ=83rpdbe?0x)NL!fz`y*uq%;#Z;Z{|_7u*@9r zb(0#V2;#Gx80~CNRByFD4YOx^sM=+>JAU?>|a{CD525!JbFE6ls2J z`AVj$_54t-V%(c<3p|dAZL`Du7|FzBJn3hg>G1 z*cwD^!UX3IY#|&I;P8;QEsp9<&ZnwFS%btXtyq4s51+K+gFA4d3EPf=Ypcoe2+ zJaR1rAsyF35Iu4%1mV%R2TDHJ_&GIV2fn9~@t||N)T`M};Y`3$-FDRxi@Sy>e%t}W z8!n8ro`ymF@v!zQa)QdzR=qWUOU*{{$!e^s)UbbbZ12n&C(m8zoibzY$-TJZ?}T35 zobEqWURX%*ia)$Ge33JYk1TsR>^RbP4G=Y&DPO6c@tWR`H|A_rM?GoZ1^ z;nEI!IgIG80`t9JGau0b(3OqmlvI9r7;Qs0Wr+_9+v;Gfj$to)5KCHgvqUa0&{Z;f zDlRFmR1I^`TyjSAz?zul8`oSTCYp6QCFoCT$S@^{XKKK(1c>QC%0!#-qB`i(#T{crJtAO#OHTKEhXsLKox_285Y4@+)Mplin zQAv>z)_5F_uj7BB6wuzE0;|IoJ~Z*-iCXZV z;01r(QkquZP)5*>-0%a>MH_7Q?Q2MAmed)_y)MR%UP!u%} zskojJd!&)UP2>QZRpJGZzB~p1aV_C8|1-<3%5PQ*uGF4+^1Ndf&OQ;ZZP~Nz&V)VF zd^8wiGTD;IIRom)M7OLfpr9bL-Wn;b{whN11kl1UtVCPOQ}VxlY_5h8H@Ycx_; z(VTL#!=?H_Z@L5jA6ISAOW5ORD&upacJWb0Z>Hz>E?ju(nD*TD z#notW#D(__@eKhqpXN{*N@B}pOl*5rZ9=pbq}uxXbU>3}ZxOBiMA*Mm2bc_diplm+ z$L04t;$Mu8wvZ*dBOT>n;XS%?J{xn3hP5YI;@eZ|st*n|ax}<|&z5N6?E-^kn{g?f z3Os%tQ_B)A+hWs9J=S7_Mq(H1M|lgsMH=3Z7?@7RUB`o3QU$7boLNAuHmYzLK$Z# zGex>vt0q;t5Z3TihOlo^uN>}amCa*zWZEc<%daJd<8#(z7UZ@g)s7i2 zSif_n*4(OTTnetTw$lRPvS!O0T127XX1Vxgr>k_N>0`xpj<5c)vs;$HRxeoXT$nM`ww2>qY~*ms z-x4|InVOPV>|nSIg#puF?q=2uH{#$+^m%;Qu7J1x(vxH?3$);Bg0sXVqIkX6c#09DeH4A$#wEP%ROTYN39h&%b%bDlyVz;YH^ zWkBCqr7GnjWG1yRs&82GLRunL=zSkQK8O;<)0ElP(iFXYj4&=?vH+^bb1~Y}F$9F2 z+bV#b+61U(wB;c3bPNHO9B2Y8PpOS%U8)^to_qgkILuhus|$9(8zST7x2a76_S_K) zUrQBEygv@`fU>5?_&%?tp;bKhmv)7_r;<~(qK_GIJ$$UV(t6lJML*5lY%0~``Afs=KrErGGZR;vIx5jB!`(}*!Q+xt>Zfd_Rfw|{-A5ZORU*AwagGvO zi{tU@#x2Cz%IbJuTt!&YQ4yW8)!eH|*(#!}SX(=cVI;bdJcwSHXF+G;_?bW2z5->h^M(=ENT+NewK zyLUQX;dj@x3MhqHdVzJxBrenAl_7IAX6WFEmdovFN2}s}2#TCWYx9>V#dZNmq7Qs~dk*8w_2xlQy0rXS} zu;`Dcq48C?-}o4>n?1m0C<4jiBmQ4ws#1W)Y5TQIqEwVshlD zWcz!#rX2G%TpBu!aF#a;?Tu@B-KLch%t3gSfHi~4{b(wO zDq1)xFjEdb{}Vr-iHqkbKOdG10pS_triv8C3U+X;a^=zHrUge%L>r>rN1~0O_P1k= zVBu@Q4&w#uh9hisZFEs0{AbwYt<&-rg$vB)Sb@}NV}x{SwV#A~9w#JJXWnxH8NuTi z5z!@9Bco#mu$gv019Bc?&70C%>ti-s;C= z^O@2j(h>8yrbe#jX;w>O6LFO)DUZ#-LNOP+z#0ijlc8jX+|dg2TlPR-#%vW0r|niKk`f#rA^oeXX~~P$2~_KN6MG*`Wtm@F^yzu1I2t< z{w(&_@;G!zPs9);|D;`{Y_Wi5tTt*2;bxnB1_ui$G;JY8g3z^Tz9<|e%lHwi_yif< zGb$ogYJLa}(l<8z$C-Z8zf5@m`^tXwz9FciFO@VCx+QCVJVt)9oxrt&~=NG*Z0 z5rvT=?FQo$li9{J9REUHk@P|tyT4_cRr!G8u^(QgTofO+=o&y?YT3bBdQ@C3g(JyS zUHSAJIu}TWslAjzIntwaD;{JND}Az=M8`obPfvM`ia27|(U$Ilwh9*f)zL;WItILB z8kKB%&ZxM-kMw~A2!lAf-^`r4olKxy(lkfvdW=CBs&AuAk7${cjCx4ibpBb z$MjUALe<`a{ICImmUK@^%x=?Y=9rbEG7bo+boh@y!gtx$;cwH9;5{n(&t#R77pb9JmB%L2wyZkV8_H zHmVHt@A+e?wXIdb+z!C{W3>w!xOj2*U_Mh7WsUIwv_KT6t=@-=-kbww zGdtZK*viL!qiG16eZq|6dcB3SPM$Z%J9fsx8PiiR)RbITDYGn(t^>oJ#Wkt;Qf@ES zb?6k3FbU>ks*+T4uu@s(RcdIo28IxS#SS7Mbv}wthPs%;y~+7vC6g1Ye!*Mb6tnJS z`jLW1V?Q4H>wU0RxLl!u14^9WwPQ{YZaHEinbN3NDdzfz${3sL`3%M*k}1-kER(l+y6o8*;ql^L0Utf$!&=D zMrb$?Df?NWcR0#JG}@%a$GpA8biNaBPSy#D^O+0$ImKdnjtrJg zHN>gaE^*yN@K8WOC<>~d?xLVSX>21mr_^9U@jHA-!vbCpDM4{Px}6L2rRAs#ikIvv z)1}AsR*m*(fhQhzG)m-?rRN}Vf6>2-q^2k(u=LDf$~e7}Q1s=si|6J;N=rOTMxP}- ziXw_bfx7S>d6oQ1Y8fF+Xd&EC@;OsPto@GU7pYH6_c6V6X?kV>Iit*>Fz5uKZwlvM z`r`SKDm-!jr}#*49u5}_D7l$#4egNe-2v#fK}x|LqJzFj92cMqRu`=@PMjfhx=N74x1r9p^AyW=Ki`?}kVTm|Qq7$JT;SoKEq(+K4G`%8x=F z-RZ9AVMwkh4826=5=;^3ImHuDa!6$e(xy+^8TxdO0khbD01MT0)DJN*E*z^@R!!_>X$^ zVm@D`OyK+7I7|pk)4VdidIGzMB-`mvLjF^HYP>6mETb6#1WpF8$l=SUw2j&7rBg5v zy~mt9e>N^9n6Yr-{MkpJys&pci3(>M+)1Hm@_|d=t7#feTv|m9H{R6~*gPf^^ZG$A zSEw%&ci)O%8O+^BOO+uE*QJuYS`icFjPS3L(@&8bndw@k(LI7232~deD6jrt-a_p` zyB4E&gyP^MNkJ_Bkm3aosp^kGvW@%+$OG05DCW|UQUMC#v~|>q&PcMg*kejCkV&oG zjkHcFEm&ti_G54|8N(5LTX_2QUZKDW(FzZg&Y886zf@pNHwD zgk;(yPV*cU%p%3gOlO@!o9h+MTq6ZD2g&46SrsfM6VZ|x5kd!{P4+X)@5GrCbQ8=G;iKloQ52!K(z?ld zCXX*)i&ifk^@gFKl68>0jy9Lgpw6KkbAW9hYwFce5{l*)*j}Pd0Qd7QykA_QIj<{7 z@SL*WUVzmY91}iBL`;jN>P3>UQtHqd` zjl0(3W6C-+!dPm|2xF-)Bh24bTg^+Ox(XKj$O`BSesQ~@?l|%Vn7?NQ+3H?;`s%Sg zgkh5+^=%q0OQUhC#&m|A5yIIv+Ofp&eiptgh1HEZ_TMN4%LD8*!Flg0)z89=G$*DL z_HbB^99Oth?}+q!t*IqrpCT{tJBqRK#|l9*@B+>lGDHY<>cCPl>db=kA-NXy0lbCf zvJ%aByHXgu54SK%t(JAJN=ONH+|*^p}WDQ!{g~BXe zOt%`xkL*|x7rPk!xpBBx{-%8hx?z;m9dD1(ObaUnbl<03cNU&5 z)ehWY{$z|*3s)48P#Z}LYNuQg%iV~O!{#rlX@0s3@1a)8_!C|WUO5#TR9<7W8neJS z&gjN9TH}frZiJvQ$PumdiMO9^c&OBeSGmcF?$1#*&QG?hwk&1J1uPABU=YJ{jPtcL zxP-W9I}#0F+o0nPar4@7BuP0F&O2IJ+{hf)eT;yS+KWsC%K7DDBH-vv!S)i>3SH`> zX9OF_xRTP|3&VIKkcdZhLj}OxPF_VCA2SF>aq-pbN*U|<(B^v5D^%%x2K7sH$K>*Q zD)>oi>I^FKK)aZt66N){5aY@}3Tg`+sZ2v0O9hHY^)|j#^uYF1R0y%X?O)I)Qf%`x z5?qt#s9F@t2x(8t7bGg5-jAS4qxA8bgzQGHdb5SKOQ9`^@k*hvqM%($KA9p?0?Tcb z7?i^-t6;DimTOtfkkRatgz*+yg|$l|vpsg9r4(u6wI1hR>*#1)zaTP@sH~)q#Jz^` zu_#Eif=PE}1&>v8K}aEiRvAcLXsrXLFFsuvNW=^5LwIXxe9RzNXwL^R@=RubC;7sis6ZI{eh-u#LlFV^l#94%^Nc z&c(MAQp>zTKe}Llx#W~oQw6bwaS#cmfyrZLV z^_jEh_QtJWCgWmtAAR!7ncjlgi+e>ciU}&4MV?8-24zNmBRh?C!r0ZeB%S2N-ntP* zq?Z!w-+rZ~aqkx1CZyU!o#|eL#AB!c-0c6?-n(_TksRsT{bRoCSprE>(w$|AZEJV8 znxCY$*7ydC1VIuKNx%R|O8x8i^F~CT3ROj_$9oPQt!1~s%5!97WSq0FecZluJJg=R zUic){9$r;TYk-?)Hq=Fst}<4$1h7A5_CWhm(P^4NC!yalHcYtj1fN8iS$6vVK<`ye zn_lXHSwGZ60g=_5Ev1rgL6m3rz$~iKnpv>+hh`B_u4)b$VeL7`>HGw>@=r57Q?N-7 zO$%=yJMvBCKkZq<%IBU?t`yPLNJqWZtt-?k$?Ylqi>hLRnHH@`B&a4yR;k|v- zPWmr>W7&b+-)eGsyiVXh;vwo=<{sOXQm^^k@c}iEfP(JE{H%8IHHf4981`E!%$o!ri+^e0nVFVAjg;fx6( z++Mm@JqO3V?DzIAq4w(Iirj5-T3ngFf^~^Zy|p&-NWDAc#)B?kh3OPb$q*GJR$_+Y&KOQ-wi*1KdHKkl94 z9CTgANr}q{9^YVYp8-sZESR|x_&JH8HkXTYJ!lKs=2J+!rhU~?eS`3ti3gFzO!M6){NnruL*y+% zB6y^j7Rc{wA`;oRZL&s8@4UR<3>>fAp&f@n8{kz7?OyZ1hr%l-4)=YV)<;3!)HqAg6kl6pH`n>lE0h42Z z@0ufYiuZwxL}`$Rwzyf{fvU#+S|bLI$XABf2G++SUZ<5!^+42)Ty4{9VwxF|T#J_);^(@!qo z^ivifyzj1|-$>CqYX|Q9m#!JXON3pD(6-`!RQ$S;#N+jbX1+U2Uu#F5$>#PPGyilm zJGt5C4zix{tBTL=m8lNX7gapCA#^K2x}9gRUapWEC(Ma6Qr8ffqUg0lzA zP4S!rbqXN`@DyJC>|BqToi7h>S9r)9Y(^l{Q#;GEg^Jm2GR4Y*Z6&E4jP}aqu~Thm zFb<(~O+(F^zP(F#rzE1z)@cqo8^;-<4ucNC2>tn!%(7Hhg3iJ09TOR9h&Fw^p_W!xDVz3< zefKmpur&lvca<)3VLY=QOLF=20jkqb*on&wej6XXLyWqZex83FhRS1F`^m2;WQ`5= zvQSNmy=qY22*jAE*Un(L2gCoQzfa?wTa>1v44j!5NB@CVw)IJ6o9dKp90Hz*ZUvOG zct63$COhtgz3q4e?<p{ytL}wx>7s@FrWLG?$x0x68lxI5!exex`%4Y z)cQb$Zx)^p(ybr9k|tM-1(&_uhi*;|6@_5h%!oxF&5W)lew4?Z!L9F7Q4sOrCO{`q}j|AUg-E^v}pXYL;6ekcF3)7z}d&V-V zqSQ+dFxyM9zW>@1lbFSU^fNtA6lKD4oU3v2+OS0?W}3yvy>2H1_>j-5bDk}s=6dl> zi#w(*g#p^%Gu>9h{JX4`Wd>Io)MU>5ft#yqr{7Vja<}$=E2c1H=ggP$yi-)DwD;RU zF%i-ozOkpS?`4n7nlGd>3%}CdWvXu7^>8`*K6xSniI=;QBG@T*Q8!n&2Wl-wfxu`- z7cxeRZzYUYoHqU%lE=JR(Uzpe?cNgo3Rq%4c$LdSl^WMG*@ME*zguq>)L5kA)!Cl{4fSay#^j!59mvU z3_ck@7HOt?Cjd!OolK`kgHaCEJUcBkOENI1`}-4U|9Wh(or;e9-$GD=)3_cUq~Mon znf>gghhrAUeOc&74t9X)(OnrdI`pyMt3>3#rlWo~xDt#OD-abm>4>_kThntZS&~<7 zBZW?N*&DY@vr|Euo^cxO5?*Kvj0fnf z4f)-lXm>s=F2BBy<H=;*>7JMUX!K1&z+HF;eOGOqQ$ac53T)Gc|roDX#0j zkSg3qBjUB`6sz++CEgo4yx*#5Z|9nNH+<}joD*XX4GmfjH8Je$6pkcXY$r9bAZ{bI z=Vzw6L}R8N$&)K57@*}zO?D@M4d8?~Zn+Ch)45xrq>nbPAYGrRf5&M3-k@hKdkv}h)`v$*2pPqhMnzE(Iy$Hi7u9Rhk@1{2zP+fk@ z^`yQ$o1}h4K1=-+!|jtH(7XDBoH}RaPxK&Bi!C5oNxdnO;ZdB-aGxNz$q&=z7Aw6p zPylIqij#=aV_hjvhyFzIc)A4KBuK!6V$F*Ay2i~yArqvu;6O8II>;4NF#S6^ zBe|hee}>EQMot>&GFSycr{r*=$yNS#mA~a~bPH77$m7lwKV)D4GOWT*d9rQ1a8Cz@ zKRQ1A>rY4jPJXcCF(D^4gzLx+es8*@POZA2qEXuXX-{ptpXz}ii>b01-*NYm zM#&XCxkPe9Z%KNiT1h}%6ZHuTQZt}S9r%z(m2SBWE3=Sa$!W|3J-Mkao6hVZPD81k zqQZKIohfDa-P;2Vv$MqXGPw=W_t@5qHgn-;LWV8)proL*uIY97t{7+#I+?Week2kc zCKK7}l)?%a@T{u;Kp|&^o(O`hOL+7glC_P0DGFyJ;^8@3{xy}typdW6eY1aw6b%d(2v4%e zEDv%UD|oPHs|6KJ(6Aq5xwCM;y@`KcuMJS<*2vgHowC4z1~2|`dvas^tbt*m7VNL? zYLa?>PD71W-}he0QmiIv5uM4ZhXfUn?h#N)wNi)tJq=bTp^A0-+<`-J2HFs0c59~2 zzb@v==Zq}osa;NH^W$gJDT?F$y~Tq26H6c?@VEImFLL3~P~U>7r1$FWTl103$YkDC zld;*5r-tN@*@Q?qc&agIiI&Q0u#v6s+}1n1q;JzV)0x@9Ki@ezgf8wdT(Lt)}M|JR*`JI`dH0YuP#3@Td&g0_Q6(~ZE6S3Gezvn7!3o7CWmk= ze6;P0^#}s?Gp)2Y_$iq#B#xYuVLbhUjEe8fWm8oy2Fml)q6`x@PL@XKT*+e`1 z$t_RwLzRFTsdfi?f^?r;4HZH!Na8!t($b>WWpJ~K66BL{mHc~@($b{@@j60?)jb?! z&XJA|>Zg>68Q%a>mS5<4cV>9_@OtDR!?+V)>Vd@XN--oN!t=!l8Ml^}5V38xUJ$Id zP6;ZIr~nY-5u?1xYTqNiNVTWpT{o* zIx)d@*`J=+5Kkl>TZVt(Qb64FxEM)iA`Qm})0eM)K0QVMHJOeWX8Y^gq@F1AgYufn z=%hCVu1D=9yR|*mCn@sZSZ|22kf|X|@l3KV8U<=648FkD_!G7sJAr;>B_uboOjr(e z%7Rix@WUjGxonlc&;OC@CQLR3FsEp7yy#WsD`wHK#>C+LO%)9P-CE#f&K-g8NnZ%*dpv-`yQn8i;wu;h_mJ7;l?&biYUBVUNB?r^3a68g;$Ej zl}@$U&)9;!tIY{qk_W7$bE^Cvdt9(>VT#YN^dDA?W_35}#j>Y{zTK-*jkLtuo~pPY zTUuGy@%!vpG07lIEs8p)><;;K`ZEDe3Q%DuEaXGGmF9QfwjDzb zNgkpm*4!^5e|VtnV#E;cF$)g4m_Vm(TDvB@XYt{|AQ=7LS?dta$!SKo^3b96joRCiQ-d-5!tZ!AA=_gkeirR5MoG=p(D!dwee% z^%<$k#j>Sc9PYVW(^{LMY@-D8?>J1moWMwT4>k4k8!@E}p-|TTK_b||kGh%rbvK{^ zZEQrZkKVs}_vZM+ukVgO!M}`BRKFMG#Pz721Pa%uLB5x#pY&cs0tT$cQ*tOzfBp0S zIePVB`r+S?kNQ_J1S&{?O-E|K(&@MLAqL90ia$QRpu2l^`pPo(2>0R?lS9us1I|VV z?Q92V9?>QOkUbpI98z;5Qk;o|YY+DaZ^Z;OCYl?jR--#_-lQV~{%P;PF9K;Ql`~~S z;yuEk?h$sRqcARPfj`Z=PuHogX*HuRK7EU!s(8+NvfRzt^)>h3w;ZTH$l*Ucps!ZE zOG3T^(M5B>N`CPEsT+|q&z}~)u&itiD;_%mnn1Ie543@g9vdpQX1Gqy-~P;GZuj%{ zJ!GSBBwg#OTOmNN65X?|h4>GA6Bj3m?ki z5spa7!zi(0lCfZ0+ZlClI!gY(u_NJi2MBIy-Wk_cJA&mY_|a!SR56Pa@`W&Tnj}7D zeLH{L;??X$v|4_Ce47b@U3y@Om%&%Ntr|qIA*k)6>{jkzg6)YwiQaAg*`04X`#8dA zjWjZ{Gf9eS^XVCatc35TqFb(TDAJ0vvRi$0rgq#O0^5~6^AU;T_Fx0yQ1O3I$i&2) zj7SlV8p_;_79(PP-B{!HG}fecs-e3O8utJBT7DLEt6yucWC(@-ikJR zxAbg(u+?KA(=*tEaM2xSsE>?|M!E}g=Au(>FyR4ojZzoSPMtbAN?9@)1$L!NiqX&1XrJP2cA2U#gpg%ZFK?dx-Jhs*$ zu7k+%aJx?GJKc1Sb^Qai*yD8`g*{OqoN6^8C+miUKy+gz6k{4hlhgG}Z!&@rKRiJv3? z#*cwoxrS4t$AE3O)nnkcZ)cD+pkz;4KK{4^xCdGq9SfqvB32951q=(|LK#>3pDqD8=#f z&E+-b*r8`uC{;&~sz(|=y}d1{_e~gQ^s!=S&Cm-eK8ev{#>Sgv>COj3!+VX9V|jT! zLSs^)%)1`=#k}eVfCg`C9an$fgMfjXrH<>ME}LU8(7Uix^zHH?lB86c!z4=`j1tJF zR5%;zU>tbEG!5W+;bw7hKF7J4gbF{vsGKhBk!QY2!70C4Es+<7#~gbf4^0%CH#}2n zZ?_JCBv&xH`rJeAImWm`Eoav!o6j60o*{iVMl(lR*^{(YZ$``_BHQB;-r*2&VHVUO zsOwA(H3@HfMK(-V7wgsH5#4cdss5A4)Wsowr>+k9GkwKxKnwz4W(njt6r(fXKF%S~ z#>%x2M;Le61+r@B-w3rExf~wR7^<22N>jpKI5H(ww+goN6aHLmxDR+<`}r z`>Egzn;TY#Ui84hl&J`6cK_*_@oThvguwBME^^8R+!dU-QY@vo6|3z(rrdnyF|H|_ zVJvRZy?s7#iZQn-M%G_TR3wF!1BvH0wq*}qT)5yfw*7t8Lt93+fiop$*=#op|Md2m zJOj5^8)AwrYv}zy^rEe3YdC7e>y30ma~X z9H+NBn>ZQ!9EZ_h&ofdGYBE*&8H4B5{48}g-0<-Pl4qVDGso~l*r~g4>*?MTbwZpQ zX?<`FRuCnDS*HR51@WiguhVYA<=S>iY~2%!od)9POE`^Byjgs?z&qFJp{$l8SkboL z>uv1}$-|@U)Qby?DUyjOPf5|G@Ls{^?3CmiuwDjWxxb-N&)P&3npHg2`T9DVEuscl zs=m{YB}^el3}V3$o`_Ma;8L~N>5V)cU_WP{5Y6#KFm;ceRu17V$dt%bNp7a+C?9S~ zuIzywxE?cL5T5J7HE=$|GmYAc*ZH=p&y`&K{_@0$Gr+(>06qlA8fbw(ie_YP2!!GV zd1QXILPo=2NZ=Db{PMx?w14Qxno_P=uwUzPv1Vbp-$53W4!TvHU&M?WG%a^BnJ6e) z{1ys|p_S3$11*EZZBMQ~6HmgkAPn>n7xTQQcA!O2i6C?6%j)*d2+VQYEHwTw|ggdPmNoV z$9e@uoMlGV`NXLE^x_s57(C>DqJR8c#u$Zx7A7djH&nL;`O^mYXe+)_0)U*n=gsu; zh%FNT=8diN?_&!x3NN31+~+2H*NfSDiKiI}3vhWl+9w{#PUS#_y74n%GKg%+tK}6f ztazdLgNUM+=;Gt_Rjr44>dp=1gpE+~H2i_Th+?;}5<$u5IN!*w3XQ6VcRm^Q!L~(; z{wPFCgXfmWh0n)>adZUp6!-40r5LS0k?2XwiynXPcld&{QKu^fPiyEW)8oDEHSrDk ztNnsP!V=q00^j&!X(JtwJz{xqu|7EszQR5{KbigGmPeN?2Ov|lk3{g)`I7uwRCE^C z>v^^$rZO;J1cUkKL-@0EshP#;|1iDXUa!6=kcSBhRPbPDa{__X zW_`{PvTx~^&x^eO_H}5mX_O1W{kNm~({quFp;o&2O>vOHH&m0kc4`U$E`}3Vo8&IbL%mUfJeAPdp$gEFGs{mPTY^2E z(fM;l77i~1h>A)@4@WZO^x1?{37c|vjs(I;CVsDqsZ;h{F8lML3FHcfzYo<;<*NLG zlc%Lk2T5$Mpz2C#IR=TU#)02Ve3_Xfa~6575y1{p94IOvLi+qks_ofgP{TG|AUE+bkyMh@Ur#=N^7$v8uvFp6XlkC+V-@ z)}_V|)AZZgnn1nWgkRXuoE6!UEBPWh7I)`^5~Yz7%DpbhFD}OJOJVg`4Pd@^P2fDQ zsiTpx0K-q8w%d64PE?saB&n62R;+k=%W(V58V(a=(3lOI+e36i%g+_G9Qm$4RNKl8 zzRH-oez5nb0s9rT)z;<(+=l0_d07Q(7{9=3AM~N7$~t7P@7bXI)}Rm)OC&r%l*tdW z!F6ye{f(+WyF>1}xE*{+*N8ZqyIw36!9D`uRK=jCkjnI7s7+NxZT8Q>#;1|#1%%m` zf=F>d=xfkWVvh7U_-Cf0m$I5=6IFGyC3|W5sg9nDy&a=dsa)*5o?u&jg(KD#e7pT} ze4x_fr}{74G;_2e;+LlyV`o>leAiz?i^~;aZeN(EJ)6rI_LEMmbNzL+&(|0tl`6`L zubjHN(D&GayD78@)WvCj=<+ndxG+j3|$d3jk^%@VpZ{%ToWYPqk7eQhc^lwxVSx8^XW6y({GF$2Y^L6 zlV3cY&h?}%3Q;mnaMzoDl2|0^uq=1V@a|BL9dT&h`CmiO zH0c+3_Q0|;uf7`Ty>#>e19(Tw%uJTLQ-rj^Ctf<@Hs~Q|jxQtlwPi$D$Fp$V{u|gs=p>t4{&E0Ax z3<99W2FVplby?nr=491XA*!>4@#;~540PwrWJyv|oqziS6Px|vJcs@9ZumLR**RU6 z_WTj;EB~WsksGvmGh;6$3>6rflEYNOp+Mi$Db4Lv+O&I~+Ib4pot6h}dDC{1%E;*0 z6zr!0OTXF_rDaX6s5=~d6p^7kWjk*hx$mx09Y;iYQ=C_)h!&2m?s8Ih>KdLVkwSNh znUDLvp&Y*vAn7(t(Wc$%5Q2l9h@P_+r+-I*d zqBqdtK?m0Kb@-YwdEjvHV6()bCf?tZbGVhjo*|_#)g3 zJRh&$!o#y;L8+x4(e}0k>Sa6=+79mhV;Z-c{G_A`4n^~%UeV;4`)ZudF>+&%MXri! zX_kk+uFls3nG>-JH=xLguzw`05hj7os`P1qgjZLZ}cs#9jMrr>uyAJ!OUv)h#%A5hyO1cY42;qJ~^^V|Q{w!J($%=aH*PMy@jW zcdoK@!R_!z`~I!~w=_9>QxHJzbT3N%{V6BusqoOtj*fr4yF2pK8>D`($a-*#%_kc{R}D!~Azk?Q^6{?k`(jEoRDXUyr1e$>TW9(+hu?d$29?DM>xfK1bTPp%8~NAW5h>{TE3nPsj#V5jZK3R%E# zVcxGaR6Lq7^xbdCGD;CJJ9DcF`es)Z_sy>=-kFKKtIGrcm21(`0(dY)ULWaCMdz7BU5U7FZrho|z$ zwG6>x5M!DN_;Q*{^jS!+WUS`4 zKG3UBwbDU<8w(~Bp5PKwYuQXh8&XH?)O47%(?*u+n{8j!0;P;*x;2MBXXtgL&r-iz zFxVo4ydAi*$^=$uK0=GhjsjqW#1+gNZtn1ChHp1~XF#>s!-AF&R(+GKSt8nTrBl*p z{%$v=;*G4C8WkkBPnqBvWy761AmF#X!JtQ*Fb0K3cHxldRBmC>GjN%`Ptc@QQ$g&M zxMpJKGl#{M4m&03vrctqUWVPh(`iVpAZk^6cQG^H8FLdio@K=RVHZLjUH7NXc=m*Jcs^wKB(0FF|opzlGJT+AtnR{;h=1WAWa|5`KhC@45$xsm8 z@2k-6TThKNRqQs7O6mGF(Tp}%F_ zy%ZnY&2YW6{G>qYY|V?%I1%-w44%E`tuy-Z(9aGBSQC;x6IAM=k(;CW6!+BCRZd zeTA7Y_7oQ5OkZJcx!(-ek&oNL(qrfQKxdFiT+J0KZcb>zMxIpUHH>$~2x3CmUd-WA zx6YW7pG;Z~oT%xMr-zsbPEXFNUWeH7Z?hEb_Up1iyLw*q*=klwvIAwa2};pA78R*` z{qemRjH0^qbsB6yMs@H+r5d(z>5Mi@f<91+(bCdJn?%4^h~TRG9w#k29EC87lOsaP~QU zJuTmMF(hsMagAj`;(gx}&6u?3uAekTcT3{_unrNej)iTp#KOe(leLqBYR_Iyx5PdC z_~z%M4{v@s8qw^YO$mZ1upQjBZzG4JLuiW6&V3HU zv;5Z3MO@`aRvn7F?eAcUorC9>M9FTrVC1+9w2XedEno31pKV4nYV6dl`@L@ZHFtDP z&k^)+`}_IT3Fe#jTtQ)MUxr~a+4pmnj`skqZ7Q|1nml3E%PU~Dyzw;?^Cr5$}zT@fTp?QBB+P-~` zh0BudP4-O0;br)ZK`OHR?NiPszGi1v@5iI`9(yc&pn>qfiWET-Zi~|7 z4DAJ+j7IL%wq9O1H%nS9B+|hvRsvb62*+q`^V|{P-(aQ zfu)RL$rIZulSu{LyoYcRxbo&t)q+@gu9b0!HRl;u3-sfXkgM#veJ_1>BL8jUCzg>P zor<>Ic3UG?FFydVIM?AWuOOV5?Fh7b>l*I;+`sMaSGuX zthJwNohg-BRNL9s$$_d7vO<`!1@mdp;iYx~-q+gjlPm*gL^eFXQQR#&%#ojt^jYt9 zSxA{OaWJX)esG18iKaRW)*;(~3KQeh8iFE`6mp zx7SDS{D^n^5}bKVRG}~f8~a>UEShkj!sLl+fSjB4U35ZV=GpD_H7q;7maDDBS}I!e zhBM3k%gSK`;u%}tDnownrsPCLLOZ`iJkwxBe44<|F!qz$$tLh3k!)>e1DSv zxY-_TRC;sND0^x@y<^8DFlYLm3jr$?Cx?dWnvptt!M{mGd-P&P;bwX6ht&Z>fi!ECn&hFA^ado7TIGx$&Ien{cpWb^!lh8pYIul#j&4Ms5*P5oU zz+&$1bC%tQGn`7E>$S&|^~K%MJ2EgG&jxS&Z)5-m`?t+!DD=CV%f&g4FgB%X36^}! zzjCO~?5P9Ji>Gqe$Tyz|vI$bTA6+I{gHa*o1~cMo%+b#8@+B*$jBZqf0lg?T)l zU7?z!{D58hb+kA_f^(bOjcID#8#KO3l1LTm*sVRX#w@gwHO_c*LVlcM zMDx-{lpVCynl298GI2S2XH8Otoz$Q9Mrt5xSUQeqFe*8GTStDQbte8?d0C}TMjI87hvjtoa)G5FpshBtafjXtL5md^^FuId5w*dPD}>7PKGgy})v?hEcJx z8FF(;R=gXOR=<%g99&Kw$S;hc8Aq1NkqM3MducsBN>&4n(Y?W?)U6K@6o^hKy4gwY{>Sr+BS$`e;u|l6#5aEN?aKO5H~!0dyqTY@ zPrsTplYdfI3Nd^1p!&&Y+yv1K!I@V-`Mg2EI=#{uikt7mlu;} zEnwcHo&U-bTW9>>&t}fm=`7vmk4;rOu{AL4LtBN=*ro=5TZOGq9>j_ikVE#d`8jyo_I#X2KzdiYZpEwC@lr{91bF2DNa@rC?4 zRg|0?2nE9%755T)zM9GT{XR_ev|z>z~T1|goN6g zQiJ^=2zWlbhGy{_m45s|tu3Q|)|lm&|Fli?pSSkgD&QEc}Nofj{&pN!SsH{1g=jF1}xM5Fc{=NQ1#DvmIIjBulvQ>RwuCf;`z zr?P@m;T(IZ!8Ts0iqw&&Rh_0hlH}Nz@={Ij&h4kpZTe}m()ENIm!qMmwCU!2RsH6@ z!FgbKLU_7L$glcUb$%u<==@zi^ij>r(uXoCXU5XR+vs^N@CTMr-oC~lP0jSJ)bq6( zqchz=;%?&SjW1lQ-NbKtJvV96KyWUbIS8$#DT|pl2$wUndqI(|c>_%53&;^3P`nAI zl);)8Rky#xaVRtX`Bquztp}y6_g`jAPO62b-q<-s9Id>$3A&bG@F8_f>G6?gny zH9-DN6{$;ci3B=Ar!v5F6MykN|F$mgawXi6Bq!@azAO7=G#DFf5M5bgH*-$3f43~C z@keq3bqelIF{Ns9+O*PSaRcIh6DqIShakH)s1aklnlFI6{RS#_(CiQ3v0yH| zKv1^Semd6pXFXA1_~Rr`m_#szEk1rnZ7;AF4Hg*%3?^QAJujp9?`W9*&^W@frPsHg zQ6+wRjWRx$Aalue{0~(U+D13_GpfXI)$j)`gvHEz7Dt@Sw0vnkL4ZOvLnN%h6RkA!gF1WVk_K;NT-`>YU#J#Ir+3-i-JtA=A5&$@{?qb)2}RWdUE#Z zR(UKywBQuBi<_^c_tnj4r_sirdTw8XhLWh$lmEV6$vva~?Hfsb6&Pyjg(?wrdc4IO z2^Uw8oSIz@7=M_dg>~eLhVioL{QDpn2T<=QMZhz>E`u5PF)y{u;QR&7u zuDYI>04|&+IB(Wa;8=`aYWggLwpw1_UTux0O{bTOCy3`({c4$is={KWr%*T!%loJL zTfeW&#LTa2W%z>)2pL7Xi`31@&DW`Hi0%k%5CfI6lc{|;hZl7qznXG+lB8yhdt(Hc zz{A>0lp3%qJi+-Ug`iZQ#pP>4Z7)+_Y5sZ(H*rzgi!S95mRu=!&!j@YsG3xtnyKv6 ztSXua5>rX_MyHZ0RZ|f-*2F2MPc?W-Sv{rlHGq>obcRl!z2^W~1DdvmHe~y|Ch|EY z6fIw(&9^7o8`rN zdAqVKGu%CkF9Dco`mB+S_)g`DVXG<&oW6n~VO8eGCGn9t;IJU>wuT_DKi-`!_EmaY z{p5Vc*Ya!g>HNe`2TmZ;OB18GPi&~!GpAQQrH2Aweh4YG(R)9Yr%Lpcy;o3@!M9+D z7W>16d_TRoTFNPf0-hkYM_GQD9uu1Ri{sEsdx7g-Jg2!Iae)vYLD;2Iqyu&tc6817 zW0>B{$?OVe4IN}Xsv;qLI{gu<`Qu`}+5X5a@zR|Ay|U3t`r_u>-y?O~-Tc?v?fd!m zZ+LOjEpAfpwpVYr?;+B+n-9y^%gvD(Tl3rT9+<`I9_PsE+J=(@2)Cgv_7NeqLTIZ-B5| zysR_dqZF1J85$&gWuz-lr6eqLz`*ouQ5mC%TuWk1Q+c(#!NY(43zwX&K7Dr(Q>rUa zC5}-{zCq;}gJ~fS%JD8ftkAdQKQ3l>($}gjR(lfAZw){8kV3rIx7+{!cFwb(CkE*K zL*#Qj>)m5M_hRS3FXNBzU%t~bzkAF}d!$VCJ>WsX;hDm~znly#%^1CH12_89Btav4 zISg+hW`WGetUvINT>3dT4Ca%R>s(r^`^>qEy%ZTpE_W3)bw_)nawJL^=7R zX0-K_Gbu7 zU*AoCe)Il=O8x0Sc4#IW4tfGdQ;~=d%U|c$e@2*ql#3kuoLrLpVfqW~+s3 z4dsmA)tkG;dU+!+!M~lX7xI^>FN9Uj0uZ`OKDV`JfUcI52d zSuMCiUcP<*MpKEq<|E{=xxT=%^bkj9cRURugM(3%=Y{SsHlJgl-32H7c#j(p&+a7B z2px#dh2*-v{PMDE*q7)a)KU7#|CjeQAb?tWmOXc50b+jJa0zjT6Z^?MC89NOrNmCg z8;!Z6bVwl#9{g<*Qo^YK8zwa&H&l{$y!`s8l&7sEH!`qn|mQ1eX*mcS--jY4Yiyl zEBz}-1hvqC@WcI!@(0HWsZq=5Onq=%O_Y>I9y}0dE@o#!T7uTcxAX0fMw4cv>DbAn?L0|o|ae-Jjw8<${}^~PWk*IyhzXI1{R2XEk`B(BNM zTtze1*G&9}>6;A`Se(I_R97HtjF)usN-MovKCPf#;S3#D_yjw|#`5A4Jm%H>J*iOZ z!y<FA5KR=;B0{Pq{_Iab2tt&JOak3IY3>etgxT(d7Z_SCmK$)PGVs?pRppF^7C zhWv}YspRZnpiI;;I{02T2N=ND^UVxhBY7jlGOd?aHIjRzx512EdVhOb_(rhC!7j`O zc<Or!Ye4<9qWmFd=9M`pY?u;+~Vk;OM zME0YRO|j6yugApSzw|Tj`=GPofJ1mR+e8MezfTgYagMJ@3%cdiuklrh6hRVC=j&h3 z;~>6KBxB%D2HcxX%x}5=kw8lfl*iyMz^ee%*cI$f;Bk(r^fLx6=O4tA=2?JEx6(!- zt2#_XQXj-+bZy0JM=$V|?(=w5t1+bWDqv4fIsugu; zTj7ysmqx2H*`%_QO;Nc3kizmzgWxFg8@IRvTs!IC5-D_|RUeO^px5HlU54`|BwRNv z&l+pZlZt;wH&t&rV^EULvk55TA$;67o7br6E(m5y$W`$C!Wn*TJ8LmKd4oVka0G<& z6`v7tujn@&8`NT<`aq$L7!3QxA#-`_<@vdUlCQt;L{>%VC7b*(eQmj$dwOJ(Hjbvw znf%Pb6U@L|d{b6)lF2}rjL}bMrU$@HMQ6NM>!Lrs-snv!TM4*6dJWRNq(;Mjg+}k3 z{0{bBjcFDLn5asA6fIJ0 zT!MM;ZD&mKerA&W5{|LrWjveS?>sBS+jdG+ZZTxoh!qVG&7LxDMX%*i&fiR#Ci3am|FAgaYPWN0GLTU8MP9j( z+9|VGpFf|Ry*EFPi*kFbIPcds8H>Q-v@xU5?`0t#KuGc~mt2m}BI7 z)^}jo!Q4Nv&emVW4VCTCwM6iO?Z@@WC(OxMc7o-Nn4M~`su#ex`Z>}kSAUU?6=Z@# z>R->R2qXD?^I39(7>)SRn4(0QQ?AZ1H|!jF1Zt-gkx z5wQx6Tf$-vA36tl*7!If-1Nx_PF`5duPpsauP~g!`@ka_l=<$g!E4Oi%EtB8HrIQ# z4f?pljkvC}vwI&GXLA?ZjsN^Jwz(Q?{w{XjJIlzECjV}(I3r^>Uj9issQ?wMu|(#F zAp$fm){weNwty#s4X`KsoV>!wRpiG}d1E5hG1eyW)n|r!k_Mc(`ypxouSobjy^~XB zo#e1!jp(r4SLtlbScifN9jF>EYxYdS@okN}*|mrG8KnBUvh2Do44cbIc2W95TvRj- zkYD6!I-B1(36!#^j0Y7MimpObxDj6ApOO1AB9Dp}HT_A`rh#NfPL%YZ!AlygN73NbAo zEq#yxvkqNcq%RdVT3@&ssG8}%!e)ZEF+SPIscF_Q%MjKwliEEd<5=2BY5)@9MdUa>nx2Mc?aUotpY*=b! z)Ls?@0pfmcq+h2NkTN;bvi^MXb$RO&lOd;pELLX9Jv+oldSrqVSaYUwhIFg7gFk?I zd+jco!4L1=)7||PXYUp*NTM#M0*^$nEIUd<#g2|07NL_)6o?4j`|?EF5}80O@I91p ze&ZLK@%@>+P{$<=p&dF5|Kk@e?N~Wdn~gPhG)A@Ff58dKLG<H55I`-&B?5^+QrLT~w3DjRJsK#{m8 zeZp;R+tOi^qi-}0w;H#uZmv(!9nH(hOsGNk^)oCyZnG+hTqn21Pm>yDx6erKa3+$pWg^^Sf7A zNij(@8f|*?J0^+xRONq}0r7Y#k zuKWn|zHG3%rNg=O&t1sf@i zon0sX^_R`XK!;*qhKOE5D|;t6O|0ckj9JoPE|Y&CVVLWsxY-QqA`(W{4>CSbI|_L z9LTx6bdp`HBIfLx+0yd50SgOOvXT4={Jhc~lVC}YnTWo|n9fZ+H@{bUGwjraowEDt&2}e_%l@7mfrPoG+YgIvYoJzV<~Za41N)V&&_MWV z{dI-4#6l1tsL4x(33202%_CCkm52@U_H0<%jG`6!^`4{c=TCV@(n)j8(cWQrV+b;) z(RD(CK=Jv=^tR@=W8O1B==J>kqv<8I$PoTcNx;OGx!Zy7k1+z;AU_Yr{RmZ&#>~yv zWsGOa<~?0}VH}@+T!Uz!agLi;HdhS0aQClds5dEcuwo!myG97yOj~`wHw<3KsG;Gq9X!9h zLNg=oA#OAC3ad%LISwww6%{Q97!df^!y3I>en9OG_mPONgB^!CY1MwaStzlMYc_

L(7xOZ16Ggpae6@@tuxz$z-Lu7X}e3FPjn7FHT#Xgw8 z9H$oL13ojL!icRi$Ei3-*w9R)?7CrNVytx3gYH&3Eq9~O2$)dY=i45E#(wg(dJ9z>+%iGy4ADxrcO13r&U_Br!K{H%G(CID67M=+CbX!lr z%eh+E0ry;V3LLxPthaW_HdaKtR%XH6#5jTc^7BGQksGCG5+Q5gK0c=Ni$?YF4vlG- zGX%q6JQ_zG7JqBe8F`p?YeayBik#Y$!on4>FgBIQ|Pe7+jx_tBK z757pr2skb29S0GdmD%lnh9+kS`icQEc)|Hfh+eC>aO_@guI6)?O*#*W!>%cT=A3|7 zi;x%lH9dz$!r%hhF(-s#EkW@CN+a1}%P>`zli!cEM&2(!pXggzFFpq;58=+V#?Cz? zItpWHhQ~&A66ki$WqE@_>r%QceaoP1FeF`0%@OiR#GQzZVP1O%APb8z5(}Cp3%n{H zPe9zuA>&sbLqBsR>4tkcW($7#_U11obdB5Ow;P5+jR#$i1{nk?*d$@1@eyZdSdL8e zXEL2H(E)&)Z3}{%YlGI51V~WC^cR(6j&QT(9n0uD4d}HqwWU06Zuc9|^9tbtvUA19LX*lWk7BOq zzIBZ_K}2kA8qlTb3Eue`FexrH;Dpf;a-0=c zMR*4+(ok{$e#YkYvXX{pQpMn5Ymxo%QHf&E;^+AdhH`1f%T5@BY~JAhgm#{PBQZFh zXX|pmNXQ67R#Imd1teiq$FV@fa#dY(GSMR9vIr^f5R!s(^|P`{4oc~$DeeT$d|sKE z6M7}2Z(n9F4UvW!CI0r{NB)G43}p84LK0YJB6DF$73x!Lc}R1o=2c*t1Fw^UPjdyg z42c&xIg68R{$qh{W*f*(1z?YeS#Dg`2_KGVgc3u2gHx6D}}OJ z02~h<^kdCOROb(qT;dL?EE>gtl|iuGQFjwTf$o#j=`c&W+gXi16a3^0twpfl6BwcE z7%NsjvB{>tY}ojq-)1Mr4HPZor79a?$>_kIup#-+x(zHSZ5%Xkb{Y)UP6t}R_wP`L zkJzYBqOBQ!CqDl6hd_J-J#t0R zt-w2~aXX01t1pSH{(#m}8P^wNqCPn<#P9;A z3sE9R#Z16bScIp)VfCQ7oHKBNCS|oTAJKyIURegOKP!|z_h%P+^v&MLe_Tqz>hg+Z z%Z8p?(KClc9!u~4%FyiZX96dFl=?NIpPX~n0~i+;NTYqDCMFR1by}>S#cVjx`=&2t z7($0IJ69ULw-abS<9wNCs$3KpJ|$O2;F1HHliEnRFVOu%BlI>oZI4mSBYk-|wxQQA zC#%W^DXj?jZDgupsU)0OeM+_IX784wlmh6J#m`qZVlxh5-T`T90%xj3z8Eg$&5^d! zlsx^^Y?qLqZP;gr9b@ax2->LW`*)D0A&X3t{gz4qP6sU@3GO8{CaoQaq{yhWNb#I? zIG7_GQWZc?BV-+3ay~|qPLUfHU0cD=j!Bsu)F7M8{`9oSeGH@I?aaalOkNYQB=?c; zIeVE->|C$R$s03q*N4auR2?Fr5x{?ci)!%ZtjG`L-g~9Z2~u=Wtbl)k zSW4S{yAn7IMSVgP1VR327kqWIGo=VQMmQU`5qAiO7UDPDoXmWV#-;%l*Aljc1=;JD zE3!nB&u<0oq<;?`{SoqDPJIc~zulk;@q>|sWob$hq~q?9IOMS_F_}6QPJFV}0QJi4 zuTDSYJALPTW$Fc?jtpf55u!nw0B0~@_hBb~P^YB?P2XT`mJ&6ilz4tA^3QbBr~cTB z9r_hhiM$|Ly`7jniJdpfVDbKbfwSy~W$Zi$Fk0F%H(s;vq(r4Fv8ff?ekXmnOrmd5 zu=nnO!^`vLs3CLT*$m%A(}V`GrJ~>ORNqBt^NP^O*`bN=%T?yqJz;nd!)BmOuArkkpat@#oXqx$Km(n2x ziUx(^Ro>QI3Nq12DjDFZeRgH1KMsfl07_Yg(r)w_-fge|w&}TbO zU_FTg?d^x9#gC;SjHv=>rn#}c`$UP@W_A*a!!iV`6z_ioLInbgQKCbqq;{EBL=nU} zyGz3|P2Fy8%1F$paTIDV3xGGLLx-I!n?{)HKsK+v>n+y0838iWR_47&n=Z~myIslC zoz&}TE`AVO^S_T9f=;mhV%73B>85;Ox5Jv~TIKsuiEV!Gw5bAK&U!?}_uDf^#!5L8 ztDh;?q_mvME>!&G^5NOebV5$q3UmM$9>`n_+w={9O`Z9QbeLww<(p)B$9pc2OME=T zkEjKQU6Ps+Egs=x$l&dDu7Uja-yy`Ro0m|CilVSjzn-8?&V_{k&)3Uh`b~7^6V8pf z5^3}r*H|aT6k9|+@DWGs`^m^YiZLBJO-@arueyWcF;!g;hO=6}H*^%qA5$|$DcvdB z)N64H;^cg62tpZ1qcE!BDYYFm-JmM(49_Y2J7$;J>Am!lbV=0>?#QvmeFocZUKe4q zmc)S%uj>2(G5-Y4FvfXMOPU^nXQRM%5b(9JPn1l4HW{uVcP880lQ9gB1mr9X&yt-O z^mpU=^XjEl&vEN459O*k_S!+QS|acwP7p{X?{P&)%wE|6Oa*{lFRz##=AK;7O{HXA zIQ2@d%uWr=Ipd{gf(&k~(WGCadiOVg(pXA8m9`nw_Kgc^EKW(@sLF7{bcDj;hnTrF z(b!k$;S!zYARc{LaS`qkjaah0G#XTXXbEwy)<`yYGC3v*y@96gnE^MvSU9_Vhhr{; zZ*x-8@_^p16%}J_V2;7t9cmZ)s-*87(*0O@PKBJq@a}p z(e+&~lzSYat&BAhm+P(5NmB@^Cs~O0g)$OV$?mL@6#z&O($oU);qXJm;Epg&}=eFZii83!) zQtBWML>8u#S4hD?g?wNU$z4a1QydP$m*1=_@F+1f+JQ~2Nh&#NZIurY9LHN7KVyf} zH2cNV#&n3831Z5;9WrhDhro(+ZU>0s8M>hGTQl{Cw*Vi4Fm~KMVqs}3{o2anMlu(@ z*?e5yA0AY+HQGfa5C9V9W~CJ8wFtH(MiQZSnvyre{iO|TLe^THdL}1DeM-+` zVo3uamC4nooHQmTuX=n@9W8+lL$>2$^WtLMkpL?OaDB4SOi!+^k#45p<<-lKgRzi8 zHYKe~yVf{*y*U$f`0UF0YGtkT>k0!E8!`ufrnJ))LDLnLZo9GrDOnb)>Zl#8u1<;p z#y4az0y$7PRB0gQ1t707y6uz_L5Kwn)rBa6QQFAcWQVi1}&2*^d@rZ$z>OT%iZA&1S;yy#xKX@Jo%Ke+*`R639xP@87d6*ZICJvrsx~>A=)+iGF52 zNRlBUsTNNiP1qc`yI!BHik+Fk+>;W)bL%p-a(HA^AVpw0CO<>mb?B1D(~-r)#HC8l z>Ol`3(EdEei2#$rQk#~@TT!qTX4;;)$Qv81bxtau3$`;JR*|krEAN<%Jl%mSEUJ#N z^XfhE*b*~u;N2Bv%#-fB>u^XL70Ru&n(7#rJOuf0 z82=hJ2EhxgBMGz=B))^`dNYNfS-+ACrrlzHQVd^A{etkczUniGZ2FV)uqpQZAoX~f@atPq{8qKU2E>J+s;z_ zr2j23tg`B8_YuklB!1=))FJ|Y7$Vjt(l&+N0v-D9=IRifq5C3{b&dVinwvuxXb-$0 zJDTOY;u5wSw(r?OFeMmm%e(5)otT|#ZY7PF&U%ws$j`@6j)2%Ff=V)@HIUzfceLHb zKYNUM&@~I`Y&I*b0zT5cr2V$=-@MV8`*WNujtL^{J3;u?&p>>xMUYhP1Pq~@@v}K{ zI{?_q9WA++3~YlYp^yt_7w9qf(_)QEd}}!nodiuw7%A>P!}kwj`iz6iqEAH>Lze?i z7Jo04`CDC@5 zZI83Xx;kdpsQl{uA9{r#5u$$T;B#_S^KKkjB)6FC8vw9QD#`U31k{^}duBIZmr(S) zGe{QhrsOqET6I^Yf?~OHV<53K^dz58gVgz#e0Q&Ld2>gfM53K_0UMH;zg0NsG$yS1 zd5*5GCuN$?Gb!OxC<&`e#$9&SpL>LY+CI7lB)B#jL2 zA_+cLpc^z?k&pRvB0PL|&Rlw)1j0b+%)K#OV)jbRPxR0IX*@Bb5hsTwVO^AICM}gf zK*T3-)|Ay#9&$0KA`AqP!Vb{AS)uD*m)xH*gsBdzrR(tNOuA6z%f!TBn$>6$FFPeY zk!dgSDJkIrbtaPDP0Q|iWD!@Ut=4T-hr?touFu9WQEPh40`Qml%{%M{Xj&@n)nd3q zBX3@>wH#PQIx#aXwh|=&{54FG5U&#N_}<)DWX&lZ8NqFW6fTkpFhw}QYlv(q;g;k* zGip0H&r^K5pY)6g9PpB@Z}NoA=Xp6|PNk)>N;`&9;Q$!HO0ov$b&BdXHGp(1p+l%A zkn%kS7Mt>3d}_LsT>8z-j$Nt@@)ow6tl52U2q;DiI|-B3Du}|B-wWoZ)i5|5WH%%(m^rL z9UsK<0EmSbQaHUru_R4-anq=S#p6A@bg=O}X*gwOWz3S8vbP+z@P^L!E2z}o)8&4x zs14$doF!wBTwqy9^Jk+C!W^j*E1pdPGcAj}BDtUz3T)wA58db!Frx{v;P2oC>R=ty z$S`Y%l?e_ASwIll`jzlq96gb9Gcb1*SZPm8eHJIlUj@kfUSu8mv1#mtHDB1q2||UG z7954aB}lQMc94@I6~H;IEyaM3&x^yB{>j}^a=gL~_BOfbr^WW#=)4Er3@I9oJ=W!$ z`Nx(K3^CEc_a+$*h+K77ZvW1CXW2X9C>6+LdV){MhsD5=#W)UuC@+k((Ja&jflGus z#Wm0CPl|wqa(~I4B&D1asLHL7`M4^v#2cj!BLkI#!NYOBF6Q#GOZR>l-=aZ*lsOF> zGWO>Hf~u!zF&7{tG!PM~q;`UYgDRc(_iTBatDbwZlYcRtB-8f7L*qDR?^h;z^U~R? zm}#Jsm{aGpV~uET;krB?B&s&g2zu&c4-1X*r0Vq^R&#v?~<6yx_6XT2r_9 z+1M3ME;`>!>J zNIJp$fCav;9X5Q!G~=*yI9*QAAGyV|$OHfgP+_-W^M|T6x%}-D(Uq9?T#JXYaFepGs+!k9b@|h3DDL`@qud7W+$2 z{@313w2HRJ4&ugstjpgG$Z_0UdFC~pVeC!V>gei1LBdLJ1W-rxYXvTO%`q@NZrr#8 zaP6!`khp0f!|9Ms4ONiuxm#(HR!t|<^N9NNd~>9o^uG(il9xojcB_mQVklEqUT>2& zGz(YVdE3KhhK8;)Xpl{J2XlUNUI{|BHg?KxD&s)hgG4uB<&4TEmmq(tYjKU`PSopM z>0~0CH|L(AxJ%Oka+xZ^`<2pwXw{7eXe$eJybyT0xFC`SD&Mu<1kgO0wGoJx>n|v* zR}mbVOhEHYGYD}iQBJ5&4wDHt&02wWfxG%r37&FavDd9+;K-4=m5@@34{jS&zk}_~ zYbSFBQKJ#kvq!PswBdFW37L_D&)`9orF_GSiZ`T+pWZBF2F5^euDj~10oU%+Me(9c z``l_c5-bLgg-vuZCEQ>Okkh`u6n;L92u`y@A-q_7Th3wH=UyrS z4o+_t_>RvzP!xDvliv`D!X#2B9i7+t4Us~>9rK5R?PK*$^khPSXr$i4ejs>0kbonh znL6d@$q(>d!#gF?~8fM*)JD^FqT+k zeY>KKUo1U$zXOEPM;Y)3pemCOR21pZUjhqZve;`wg=R{aVP2^)DMeaJ%#~hR!vbXp z%&zQ`HSnHUeni>5yieK$d*`pV#ZsfIRf{XvbS}=Ng3$YE5ACvjX8$#4IhrK0Vdv$E)Nkbr#<46;06}{UG4fX4M&_B=W>2ziGL=_15}Xn;_zbmS zt>se&=`niaUEM1MGhq^r7W5*V?0MQF(FqjETs3*7X?cZ5(dxQ^H5VAsEOIpyA_1}_ zW>3ekyfU2^WyGO6`jvR-^qeWbEdh55tls3fbd56o&G?0^Ypa-uG^}nbbIpiE6Al?X zX|_10e<=r$@0N|0<&;8MO6w5aXRauwLEIAhIua_YeecTfOTT zW3vZ!P~zFu<|~_0(kV$50iz!)q><$p%pcAPB}jYD^zv>vV}Kz!f{w&5Ng^&B6R#!D zrZeZx6Z}l~m;1hM-Sl_n6fCOra0WX>tgK(9{2R9mlM{>%0q9) z2v_KnTmT{J4)ZEzU*@#9MU(BemX)|&6xu9oN)|R}NE+v_h#^yCn$f2RNIpBGploog z?t zuRM%NdYaF^b(z>eL5JR^b($b;bY5Y4(mj7jQ>$owX4n#bN?<Nn(wOD#cD2NsIK z3tYVEv(}Ara~7JmkijK9{th#puvdTo8FBokdTzvLYIHqS^GraQwX>>=@9r*SdfVIX8l;(%?< zm-dKz}khxR(>?LX_HaH zWJ+j((aS!I*zL_G^2!@eC+^j680!(OQN20lXTF}EU!7cR6xVl}C<9ZP|E4NBG##6;Y*!$hQ5{`v_x&$iBiXJ>C1E|lb z$FnZx-X(z`h;(Nn1HsL6TvBR5e^NU98GK!FtC^4F4fi<Fv-&NtyG@DU@;REGSJ+IeP!WW=&%!)1#x%NK zZwhwD%Oz=E$dGk(*~YE?JiNsGp);|SN`=kS2<(E6a9|m zuaB(`)xYcg^>(A6lBWf_vM$pOc-P~yX8=K-4(>4(A3}O;v<`(viF|v0<~;81~50V;i-kjPq zNHG~F;<=F2XFQ#~-kzT$Rn$zTIC5(UZ?|xB!G%j7TImGZh-yFG7 znu^ILGWnp88E_^I?6(&?o#l)#9I|^1Wx3DuttHzql#m{xm_QtC9O$kM!3%VvL6#5v zBh<0W;dw{=AiOC`%KLzRHF_UTO4A|HuKM?BhhaG*D3yyfvCO}WKC@H~zAGDx=ZqiU zzC^lHOHa+s!US-eR?v+QS{Gj7T@gvIAe}&6wDB+>NVY@K|1WefxxKa}<3%OTnDFvv zqS$X&uEHOnd9N$G$R|v|E5RF)&5)%1#@aHP=mwbTO^NO$vZLizlq* zJ*j;Gw0`RDSMkd75Q_M5ZnaL)Hcm3zVjelZ$|hzOav|>)vxF$im+r$|4Tm@U<>WKG z_tiNpi+h5;cA?1U8DsH$S(Sq&?OIXc1B6Dw%is16D@j1su!=cWk-e}zgZC{2IBk%) zLkhqowpYk@dq%WLzSn(1(9_DSp>a8&k>$n-f1Pq=CoP6|0({7tR`r8dmm5B5oY*<@ zR!K`0NqVaP$YS{y-r)%6FrzD7w2yrq^$C-tb&I8gC?3D3~8BLCC5n2t&xFp+>vWMTV#y7{oQV#`0G3&uFpLf z-CvZ5SUVcEkYA)8^g08{9Hu#2y|HHL()LJTt?n%_3Qf5tUr4NGm^x>Puj)YXm;j1| z(2}!h`2{0~%KN_aOedCi*{GfE^D>nCd6p+B!_k(mv&xxca=5xD9q#IIMX^276w6>;kVO*< zrpucvlp;Y+LcGl|VpeB!L_bJwG({rkCQpdX@-xgVy_Z&>3X?Y%4*=?K;>P|Jvw_lx=|1ty1y!04bj&3`5EepjUyvN;NYC8Tbl}Bnhb)sX-F)0hGbHD5 zA(JbrE6&gKju{}p@*=-q;#k<#9P&N}BZ^mj3e3}MS*CZXQ&LqZZ1;NiQA7h;+!imj z!1}`Wt5_JfomIpcfa=878Ea!BmCp^Hp?ZmB=FV?X9vDFsjK!FCgFU0xG~OW6iLlGO zm>cTbN}8Pvu~ir}K+t_O0XV9fyQq@RZ5F4{R&;cz2guP7frl~Hd0a6%m9=YXI4F!b z>bb)+FNo0;5|8HKu5x0WPUo3+`Y{ByOPb~0M|Ncdc{h~PK@iC=Q4;9Glt*SNCBW?R2o^-CX#7<5lU(blWjPYGKthlx zV+X0MVI1roo(e3Q;a%Sl!kA0}_G$zk(NN6*yd+ZPv3la3qnc05=_WpBN(EmmE{R5l+ogHX|+dsyQb|vKR0?_=svz=tj@sW*`@6Bh#p(Z5#)kih?%=x^*>I}g z#mMglU`*xz3{X`{yk^d2{osaQ$ z`mZ@rI|zJuww%u{m*DGNgthHd`G0<_x@6*C3)?#+WKnDbv{-T&F^_)cQKlh{XP#F+fCfWwNvU6I4J6QNpT zpNe-iJb#1%J|N#vyjD3UZ{Q#u>7#iKed%_T3C|yyRfkyh4gQ~f`2VAq&=8S+)WuQ3 YqXGJVSJ-xuVQ2$~zGvj=cBF#;3yiNt00000 From 43129d17a5dbe3835fa304d0f9ffdd9bd3274773 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Fri, 22 Sep 2017 11:26:58 +0200 Subject: [PATCH 171/351] Update graphicstest.ino - use Adafruit_GFX_AS lib instead of Adafruit_GFX --- .../examples/graphicstest/graphicstest.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/STM32F1/libraries/Adafruit_ILI9341_STM/examples/graphicstest/graphicstest.ino b/STM32F1/libraries/Adafruit_ILI9341_STM/examples/graphicstest/graphicstest.ino index c75c995..872b3e5 100644 --- a/STM32F1/libraries/Adafruit_ILI9341_STM/examples/graphicstest/graphicstest.ino +++ b/STM32F1/libraries/Adafruit_ILI9341_STM/examples/graphicstest/graphicstest.ino @@ -15,7 +15,7 @@ #include "SPI.h" -#include "Adafruit_GFX.h" +#include "Adafruit_GFX_AS.h" #include "Adafruit_ILI9341_STM.h" // For the Adafruit shield, these are the default. @@ -346,4 +346,4 @@ unsigned long testFilledRoundRects() { } return micros() - start; -} \ No newline at end of file +} From 6b2ca7dbe70d7354c26d775f7d83a98cf8d537d8 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Fri, 22 Sep 2017 11:28:08 +0200 Subject: [PATCH 172/351] Update onoffbutton.ino use Adafruit_GFX_AS lib instead of Adafruit_GFX --- .../Adafruit_ILI9341_STM/examples/onoffbutton/onoffbutton.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/libraries/Adafruit_ILI9341_STM/examples/onoffbutton/onoffbutton.ino b/STM32F1/libraries/Adafruit_ILI9341_STM/examples/onoffbutton/onoffbutton.ino index b373835..5f60496 100644 --- a/STM32F1/libraries/Adafruit_ILI9341_STM/examples/onoffbutton/onoffbutton.ino +++ b/STM32F1/libraries/Adafruit_ILI9341_STM/examples/onoffbutton/onoffbutton.ino @@ -3,7 +3,7 @@ // //Thanks to Adafruit forums member Asteroid for the original sketch! // -#include +#include #include #include #include From 5c1708e193962df2b1ad4f39a6a6cb035b41bea4 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Fri, 22 Sep 2017 11:29:41 +0200 Subject: [PATCH 173/351] Update onoffbutton_breakout.ino - use Adafruit_GFX_AS lib instead of Adafruit_GFX --- .../examples/onoffbutton_breakout/onoffbutton_breakout.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/libraries/Adafruit_ILI9341_STM/examples/onoffbutton_breakout/onoffbutton_breakout.ino b/STM32F1/libraries/Adafruit_ILI9341_STM/examples/onoffbutton_breakout/onoffbutton_breakout.ino index 9e35441..ad8fef2 100644 --- a/STM32F1/libraries/Adafruit_ILI9341_STM/examples/onoffbutton_breakout/onoffbutton_breakout.ino +++ b/STM32F1/libraries/Adafruit_ILI9341_STM/examples/onoffbutton_breakout/onoffbutton_breakout.ino @@ -3,7 +3,7 @@ // //Thanks to Adafruit forums member Asteroid for the original sketch! // -#include +#include #include #include #include From db000d1411128e2611a849d394bddc760a731453 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Fri, 22 Sep 2017 11:30:29 +0200 Subject: [PATCH 174/351] Update spitftbitmap.ino - use Adafruit_GFX_AS lib instead of Adafruit_GFX --- .../Adafruit_ILI9341_STM/examples/spitftbitmap/spitftbitmap.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/libraries/Adafruit_ILI9341_STM/examples/spitftbitmap/spitftbitmap.ino b/STM32F1/libraries/Adafruit_ILI9341_STM/examples/spitftbitmap/spitftbitmap.ino index 84ff464..5e46d68 100644 --- a/STM32F1/libraries/Adafruit_ILI9341_STM/examples/spitftbitmap/spitftbitmap.ino +++ b/STM32F1/libraries/Adafruit_ILI9341_STM/examples/spitftbitmap/spitftbitmap.ino @@ -14,7 +14,7 @@ ****************************************************/ -#include // Core graphics library +#include // Core graphics library #include "Adafruit_ILI9341_STM.h" // Hardware-specific library #include #include From c6c53b79ad4a2f89f3fb5b0dd6ddb153d6da3a9d Mon Sep 17 00:00:00 2001 From: stevstrong Date: Fri, 22 Sep 2017 11:31:00 +0200 Subject: [PATCH 175/351] Update touchpaint.ino - use Adafruit_GFX_AS lib instead of Adafruit_GFX --- .../Adafruit_ILI9341_STM/examples/touchpaint/touchpaint.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/libraries/Adafruit_ILI9341_STM/examples/touchpaint/touchpaint.ino b/STM32F1/libraries/Adafruit_ILI9341_STM/examples/touchpaint/touchpaint.ino index e10ecd9..5d09180 100644 --- a/STM32F1/libraries/Adafruit_ILI9341_STM/examples/touchpaint/touchpaint.ino +++ b/STM32F1/libraries/Adafruit_ILI9341_STM/examples/touchpaint/touchpaint.ino @@ -14,7 +14,7 @@ ****************************************************/ -#include // Core graphics library +#include // Core graphics library #include #include // this is needed even tho we aren't using it #include From 7fda02a821dbb962a2ee33c814cd106dc85f1883 Mon Sep 17 00:00:00 2001 From: Bill Greiman Date: Fri, 22 Sep 2017 10:40:05 -0700 Subject: [PATCH 176/351] SPI add const qualifier Add const qualifier to SPI member function arguments for write and transmit buffers. --- STM32F1/libraries/SPI/src/SPI.cpp | 22 +++++++++++----------- STM32F1/libraries/SPI/src/SPI.h | 12 ++++++------ STM32F4/libraries/SPI/src/SPI.cpp | 10 +++++----- STM32F4/libraries/SPI/src/SPI.h | 6 +++--- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/STM32F1/libraries/SPI/src/SPI.cpp b/STM32F1/libraries/SPI/src/SPI.cpp index 34df62e..c07e2ea 100644 --- a/STM32F1/libraries/SPI/src/SPI.cpp +++ b/STM32F1/libraries/SPI/src/SPI.cpp @@ -350,10 +350,10 @@ void SPIClass::write(uint16 data, uint32 n) while ( (regs->SR & SPI_SR_BSY) != 0); // wait until BSY=0 before returning } -void SPIClass::write(void *data, uint32 length) +void SPIClass::write(const void *data, uint32 length) { spi_dev * spi_d = _currentSetting->spi_d; - spi_tx(spi_d, (void*)data, length); // data can be array of bytes or words + spi_tx(spi_d, 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." } @@ -391,7 +391,7 @@ uint16_t SPIClass::transfer16(uint16_t data) const * On exit TX buffer is not modified, and RX buffer cotains the received data. * Still in progress. */ -void SPIClass::dmaTransferSet(void *transmitBuf, void *receiveBuf) { +void SPIClass::dmaTransferSet(const void *transmitBuf, void *receiveBuf) { dma_init(_currentSetting->spiDmaDev); //spi_rx_dma_enable(_currentSetting->spi_d); //spi_tx_dma_enable(_currentSetting->spi_d); @@ -401,11 +401,11 @@ void SPIClass::dmaTransferSet(void *transmitBuf, void *receiveBuf) { if (!transmitBuf) { transmitBuf = &ff; dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size, - transmitBuf, dma_bit_size, (DMA_FROM_MEM));// Transmit FF repeatedly + (volatile void*)transmitBuf, dma_bit_size, (DMA_FROM_MEM));// Transmit FF repeatedly } else { dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size, - transmitBuf, dma_bit_size, (DMA_MINC_MODE | DMA_FROM_MEM ));// Transmit buffer DMA + (volatile void*)transmitBuf, dma_bit_size, (DMA_MINC_MODE | DMA_FROM_MEM ));// Transmit buffer DMA } dma_set_priority(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, DMA_PRIORITY_LOW); dma_set_priority(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, DMA_PRIORITY_VERY_HIGH); @@ -451,7 +451,7 @@ uint8 SPIClass::dmaTransferRepeat(uint16 length) { * Still in progress. */ -uint8 SPIClass::dmaTransfer(void *transmitBuf, void *receiveBuf, uint16 length) { +uint8 SPIClass::dmaTransfer(const void *transmitBuf, void *receiveBuf, uint16 length) { dmaTransferSet(transmitBuf, receiveBuf); return dmaTransferRepeat(length); } @@ -463,12 +463,12 @@ uint8 SPIClass::dmaTransfer(void *transmitBuf, void *receiveBuf, uint16 length) * 2016 - stevstrong - reworked to automatically detect bit size from SPI setting */ -void SPIClass::dmaSendSet(void * transmitBuf, bool minc) { +void SPIClass::dmaSendSet(const void * transmitBuf, bool minc) { uint32 flags = ( (DMA_MINC_MODE*minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT); dma_init(_currentSetting->spiDmaDev); 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 + (volatile void*)transmitBuf, dma_bit_size, flags);// Transmit buffer DMA dma_set_priority(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, DMA_PRIORITY_LOW); } @@ -498,12 +498,12 @@ uint8 SPIClass::dmaSendRepeat(uint16 length) { return b; } -uint8 SPIClass::dmaSend(void * transmitBuf, uint16 length, bool minc) { +uint8 SPIClass::dmaSend(const void * transmitBuf, uint16 length, bool minc) { dmaSendSet(transmitBuf, minc); return dmaSendRepeat(length); } -uint8 SPIClass::dmaSendAsync(void * transmitBuf, uint16 length, bool minc) { +uint8 SPIClass::dmaSendAsync(const void * transmitBuf, uint16 length, bool minc) { uint8 b = 0; if (_currentSetting->state != SPI_STATE_READY) @@ -529,7 +529,7 @@ uint8 SPIClass::dmaSendAsync(void * transmitBuf, uint16 length, bool minc) { // TX 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 + (volatile void*)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 diff --git a/STM32F1/libraries/SPI/src/SPI.h b/STM32F1/libraries/SPI/src/SPI.h index 25eea86..686d23d 100644 --- a/STM32F1/libraries/SPI/src/SPI.h +++ b/STM32F1/libraries/SPI/src/SPI.h @@ -278,7 +278,7 @@ public: * @param buffer Bytes/words to transmit. * @param length Number of bytes/words in buffer to transmit. */ - void write(void * buffer, uint32 length); + void write(const void * buffer, uint32 length); /** * @brief Transmit a byte, then return the next unread byte. @@ -301,8 +301,8 @@ 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); - void dmaTransferSet(void *transmitBuf, void *receiveBuf); + uint8 dmaTransfer(const void * transmitBuf, void * receiveBuf, uint16 length); + void dmaTransferSet(const void *transmitBuf, void *receiveBuf); uint8 dmaTransferRepeat(uint16 length); /** @@ -315,11 +315,11 @@ public: * @param length Number of bytes in buffer to transmit. * @param minc Set to use Memory Increment mode, clear to use Circular mode. */ - uint8 dmaSend(void * transmitBuf, uint16 length, bool minc = 1); - void dmaSendSet(void * transmitBuf, bool minc); + uint8 dmaSend(const void * transmitBuf, uint16 length, bool minc = 1); + void dmaSendSet(const void * transmitBuf, bool minc); uint8 dmaSendRepeat(uint16 length); - uint8 dmaSendAsync(void * transmitBuf, uint16 length, bool minc = 1); + uint8 dmaSendAsync(const void * transmitBuf, uint16 length, bool minc = 1); /* * Pin accessors */ diff --git a/STM32F4/libraries/SPI/src/SPI.cpp b/STM32F4/libraries/SPI/src/SPI.cpp index 45aa366..72a4c48 100644 --- a/STM32F4/libraries/SPI/src/SPI.cpp +++ b/STM32F4/libraries/SPI/src/SPI.cpp @@ -372,7 +372,7 @@ void SPIClass::write(uint16 data, uint32 n) while ( (regs->SR & SPI_SR_BSY) != 0); // wait until BSY=0 before returning } -void SPIClass::write(void *data, uint32 length) +void SPIClass::write(const void *data, uint32 length) { spi_dev * spi_d = _currentSetting->spi_d; spi_tx(spi_d, (void*)data, length); // data can be array of bytes or words @@ -407,7 +407,7 @@ uint16_t SPIClass::transfer16(uint16_t wr_data) const * On exit TX buffer is not modified, and RX buffer contains the received data. * Still in progress. */ -uint8 SPIClass::dmaTransfer(void * transmitBuf, void * receiveBuf, uint16 length) +uint8 SPIClass::dmaTransfer(const void * transmitBuf, void * receiveBuf, uint16 length) { if (length == 0) return 0; @@ -442,7 +442,7 @@ uint8 SPIClass::dmaTransfer(void * transmitBuf, void * receiveBuf, uint16 length _currentSetting->spiDmaChannel, dma_bit_size, &_currentSetting->spi_d->regs->DR, // peripheral address - transmitBuf, // memory bank 0 address + (volatile void*)transmitBuf, // memory bank 0 address NULL, // memory bank 1 address flags ); @@ -477,7 +477,7 @@ 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, bool minc) +uint8 SPIClass::dmaSend(const void * transmitBuf, uint16 length, bool minc) { if (length == 0) return 0; uint8 b = 0; @@ -489,7 +489,7 @@ uint8 SPIClass::dmaSend(void * transmitBuf, uint16 length, bool minc) _currentSetting->spiDmaChannel, dma_bit_size, &_currentSetting->spi_d->regs->DR, // peripheral address - transmitBuf, // memory bank 0 address + (volatile void*)transmitBuf, // memory bank 0 address NULL, // memory bank 1 address ( (DMA_MINC_MODE*minc) | DMA_FROM_MEM ) //| DMA_TRNS_CMPLT ) // flags );// Transmit buffer DMA diff --git a/STM32F4/libraries/SPI/src/SPI.h b/STM32F4/libraries/SPI/src/SPI.h index cabc0c2..f46795c 100644 --- a/STM32F4/libraries/SPI/src/SPI.h +++ b/STM32F4/libraries/SPI/src/SPI.h @@ -248,7 +248,7 @@ public: * @param buffer Bytes/words to transmit. * @param length Number of bytes/words in buffer to transmit. */ - void write(void * buffer, uint32 length); + void write(const void * buffer, uint32 length); /** * @brief Transmit a byte, then return the next unread byte. @@ -272,7 +272,7 @@ 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(const void * transmitBuf, void * receiveBuf, uint16 length); /** * @brief Sets up a DMA Transmit for SPI 8 or 16 bit transfer mode. @@ -283,7 +283,7 @@ public: * @param data buffer half words to transmit, * @param length Number of bytes in buffer to transmit. */ - uint8 dmaSend(void * transmitBuf, uint16 length, bool minc = 1); + uint8 dmaSend(const void * transmitBuf, uint16 length, bool minc = 1); #endif /* From f65e6905e93fb9c844c557aac62233872b34c4a5 Mon Sep 17 00:00:00 2001 From: Peter Edwards Date: Thu, 28 Sep 2017 12:08:59 +0200 Subject: [PATCH 177/351] Removed non standard functionality from Print class for BYTE "base" as this is available via e.g. Serial.write and conflicts with the FatFS library and potentially anything else defining BYTE Fixed sketches using this behaviour --- STM32F1/cores/maple/Print.cpp | 12 +----------- STM32F1/cores/maple/Print.h | 1 - .../examples/Communication/ASCIITable/ASCIITable.ino | 2 +- .../examples/Communication/MIDI/Midi.ino | 6 +++--- .../SerialCallResponse/SerialCallResponse.ino | 8 ++++---- .../SerialPassthrough/SerialPassthrough.ino | 2 +- .../examples/General/USB_ASCII/USB_ASCII.ino | 2 +- STM32F3/cores/maple/wirish/Print.cpp | 10 +--------- STM32F3/cores/maple/wirish/Print.h | 1 - STM32F4/cores/maple/Print.cpp | 12 +----------- STM32F4/cores/maple/Print.h | 1 - 11 files changed, 13 insertions(+), 44 deletions(-) diff --git a/STM32F1/cores/maple/Print.cpp b/STM32F1/cores/maple/Print.cpp index 76f386b..0a71cf0 100644 --- a/STM32F1/cores/maple/Print.cpp +++ b/STM32F1/cores/maple/Print.cpp @@ -99,10 +99,6 @@ size_t Print::print(unsigned long n, int base) { } size_t Print::print(long long n, int base) { - if (base == BYTE) - { - return write((uint8)n); - } if (n < 0) { print('-'); n = -n; @@ -111,13 +107,7 @@ size_t Print::print(long long n, int base) { } size_t Print::print(unsigned long long n, int base) { -size_t c=0; - if (base == BYTE) { - c= write((uint8)n); - } else { - c= printNumber(n, base); - } - return c; + return printNumber(n, base); } size_t Print::print(double n, int digits) { diff --git a/STM32F1/cores/maple/Print.h b/STM32F1/cores/maple/Print.h index bd37385..f265fac 100644 --- a/STM32F1/cores/maple/Print.h +++ b/STM32F1/cores/maple/Print.h @@ -28,7 +28,6 @@ #include "Printable.h" enum { - BYTE = 0, BIN = 2, OCT = 8, DEC = 10, diff --git a/STM32F1/libraries/A_STM32_Examples/examples/Communication/ASCIITable/ASCIITable.ino b/STM32F1/libraries/A_STM32_Examples/examples/Communication/ASCIITable/ASCIITable.ino index fc5e5d7..d647457 100644 --- a/STM32F1/libraries/A_STM32_Examples/examples/Communication/ASCIITable/ASCIITable.ino +++ b/STM32F1/libraries/A_STM32_Examples/examples/Communication/ASCIITable/ASCIITable.ino @@ -47,7 +47,7 @@ void loop() { // Prints value unaltered, i.e. the raw binary version of the // byte. The serial monitor interprets all bytes as // ASCII, so 33, the first number, will show up as '!' - Serial.print(thisByte, BYTE); + Serial.write(thisByte); Serial.print(", dec: "); // Prints value as string as an ASCII-encoded decimal (base 10). diff --git a/STM32F1/libraries/A_STM32_Examples/examples/Communication/MIDI/Midi.ino b/STM32F1/libraries/A_STM32_Examples/examples/Communication/MIDI/Midi.ino index 820ffdc..4feaea7 100644 --- a/STM32F1/libraries/A_STM32_Examples/examples/Communication/MIDI/Midi.ino +++ b/STM32F1/libraries/A_STM32_Examples/examples/Communication/MIDI/Midi.ino @@ -44,8 +44,8 @@ void loop() { // Plays a MIDI note. Doesn't check to see that cmd is greater than // 127, or that data values are less than 127: void noteOn(int cmd, int pitch, int velocity) { - Serial1.print(cmd, BYTE); - Serial1.print(pitch, BYTE); - Serial1.print(velocity, BYTE); + Serial1.write(cmd); + Serial1.write(pitch); + Serial1.write(velocity); } diff --git a/STM32F1/libraries/A_STM32_Examples/examples/Communication/SerialCallResponse/SerialCallResponse.ino b/STM32F1/libraries/A_STM32_Examples/examples/Communication/SerialCallResponse/SerialCallResponse.ino index eee35e3..81270cf 100644 --- a/STM32F1/libraries/A_STM32_Examples/examples/Communication/SerialCallResponse/SerialCallResponse.ino +++ b/STM32F1/libraries/A_STM32_Examples/examples/Communication/SerialCallResponse/SerialCallResponse.ino @@ -50,15 +50,15 @@ void loop() { // read switch, map it to 0 or 255 thirdSensor = map(digitalRead(2), 0, 1, 0, 255); // send sensor values: - Serial.print(firstSensor, BYTE); - Serial.print(secondSensor, BYTE); - Serial.print(thirdSensor, BYTE); + Serial.write(firstSensor); + Serial.write(secondSensor); + Serial.write(thirdSensor); } } void establishContact() { while (Serial.available() <= 0) { - Serial.print('A', BYTE); // send a capital A + Serial.write('A'); // send a capital A delay(300); } } diff --git a/STM32F1/libraries/A_STM32_Examples/examples/Communication/SerialPassthrough/SerialPassthrough.ino b/STM32F1/libraries/A_STM32_Examples/examples/Communication/SerialPassthrough/SerialPassthrough.ino index 71b9e34..0d348f8 100644 --- a/STM32F1/libraries/A_STM32_Examples/examples/Communication/SerialPassthrough/SerialPassthrough.ino +++ b/STM32F1/libraries/A_STM32_Examples/examples/Communication/SerialPassthrough/SerialPassthrough.ino @@ -26,6 +26,6 @@ void loop() { // Read from Serial1, send over USB on Maple (or uses hardware serial 1 and hardware serial 2 on non-maple boards: if (Serial1.available()) { inByte = Serial1.read(); - Serial.print(inByte, BYTE); + Serial.write(inByte); } } diff --git a/STM32F1/libraries/A_STM32_Examples/examples/General/USB_ASCII/USB_ASCII.ino b/STM32F1/libraries/A_STM32_Examples/examples/General/USB_ASCII/USB_ASCII.ino index a884978..8a6fe53 100644 --- a/STM32F1/libraries/A_STM32_Examples/examples/General/USB_ASCII/USB_ASCII.ino +++ b/STM32F1/libraries/A_STM32_Examples/examples/General/USB_ASCII/USB_ASCII.ino @@ -67,7 +67,7 @@ void loop() { // Prints value unaltered, i.e. the raw binary version of the // byte. The serial monitor interprets all bytes as // ASCII, so 33, the first number, will show up as '!' - Serial.print(thisByte, BYTE); + Serial.write(thisByte); Serial.print(", dec: "); // Prints value as string as an ASCII-encoded decimal (base 10). diff --git a/STM32F3/cores/maple/wirish/Print.cpp b/STM32F3/cores/maple/wirish/Print.cpp index f6bc0c6..9a8808d 100644 --- a/STM32F3/cores/maple/wirish/Print.cpp +++ b/STM32F3/cores/maple/wirish/Print.cpp @@ -88,10 +88,6 @@ void Print::print(unsigned long n, int base) { } void Print::print(long long n, int base) { - if (base == BYTE) { - write((uint8)n); - return; - } if (n < 0) { print('-'); n = -n; @@ -100,11 +96,7 @@ void Print::print(long long n, int base) { } void Print::print(unsigned long long n, int base) { - if (base == BYTE) { - write((uint8)n); - } else { - printNumber(n, base); - } + printNumber(n, base); } void Print::print(double n, int digits) { diff --git a/STM32F3/cores/maple/wirish/Print.h b/STM32F3/cores/maple/wirish/Print.h index 5fd0b7a..52203ea 100644 --- a/STM32F3/cores/maple/wirish/Print.h +++ b/STM32F3/cores/maple/wirish/Print.h @@ -26,7 +26,6 @@ #include enum { - BYTE = 0, BIN = 2, OCT = 8, DEC = 10, diff --git a/STM32F4/cores/maple/Print.cpp b/STM32F4/cores/maple/Print.cpp index 76f386b..0a71cf0 100644 --- a/STM32F4/cores/maple/Print.cpp +++ b/STM32F4/cores/maple/Print.cpp @@ -99,10 +99,6 @@ size_t Print::print(unsigned long n, int base) { } size_t Print::print(long long n, int base) { - if (base == BYTE) - { - return write((uint8)n); - } if (n < 0) { print('-'); n = -n; @@ -111,13 +107,7 @@ size_t Print::print(long long n, int base) { } size_t Print::print(unsigned long long n, int base) { -size_t c=0; - if (base == BYTE) { - c= write((uint8)n); - } else { - c= printNumber(n, base); - } - return c; + return printNumber(n, base); } size_t Print::print(double n, int digits) { diff --git a/STM32F4/cores/maple/Print.h b/STM32F4/cores/maple/Print.h index bd37385..f265fac 100644 --- a/STM32F4/cores/maple/Print.h +++ b/STM32F4/cores/maple/Print.h @@ -28,7 +28,6 @@ #include "Printable.h" enum { - BYTE = 0, BIN = 2, OCT = 8, DEC = 10, From 31fa24bdd1cc9d86a96e23f8d21e5a80569273d0 Mon Sep 17 00:00:00 2001 From: victorpv Date: Wed, 4 Oct 2017 00:29:13 -0500 Subject: [PATCH 178/351] Update to util_adc.c file to pass pointer correctly. This was wrong and causing warnings during compilation. --- STM32F1/libraries/STM32ADC/src/utility/util_adc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/STM32F1/libraries/STM32ADC/src/utility/util_adc.c b/STM32F1/libraries/STM32ADC/src/utility/util_adc.c index e64b58e..360b235 100644 --- a/STM32F1/libraries/STM32ADC/src/utility/util_adc.c +++ b/STM32F1/libraries/STM32ADC/src/utility/util_adc.c @@ -137,8 +137,8 @@ void adc_dma_enable(adc_dev * dev) { bb_peri_set_bit(&dev->regs->CR2, ADC_CR2_DMA_BIT, 1); } -uint8 poll_adc_convert(adc_dev *dev) { - return bb_peri_get_bit(dev->regs->SR, ADC_SR_EOC_BIT); +uint8 poll_adc_convert(adc_dev * dev) { + return bb_peri_get_bit(&dev->regs->SR, ADC_SR_EOC_BIT); } From ac7ccee71f90d0f2de28014022fac716956ce686 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Wed, 4 Oct 2017 11:11:05 +0200 Subject: [PATCH 179/351] Update touchpaint.ino changed to correct header file --- .../Adafruit_ILI9341_STM/examples/touchpaint/touchpaint.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/libraries/Adafruit_ILI9341_STM/examples/touchpaint/touchpaint.ino b/STM32F1/libraries/Adafruit_ILI9341_STM/examples/touchpaint/touchpaint.ino index 5d09180..0b29cd4 100644 --- a/STM32F1/libraries/Adafruit_ILI9341_STM/examples/touchpaint/touchpaint.ino +++ b/STM32F1/libraries/Adafruit_ILI9341_STM/examples/touchpaint/touchpaint.ino @@ -17,7 +17,7 @@ #include // Core graphics library #include #include // this is needed even tho we aren't using it -#include +#include #include // This is calibration data for the raw touch data to the screen coordinates From 308b5c410f119a0d901f37fc3b7061d9883624b0 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Fri, 6 Oct 2017 18:04:56 +0200 Subject: [PATCH 180/351] Update boards.cpp - remove repeated call to setup serial USB --- STM32F4/cores/maple/boards.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/STM32F4/cores/maple/boards.cpp b/STM32F4/cores/maple/boards.cpp index 0d55e94..4b0480f 100644 --- a/STM32F4/cores/maple/boards.cpp +++ b/STM32F4/cores/maple/boards.cpp @@ -69,8 +69,7 @@ void init(void) { setupTimers(); #ifdef SERIAL_USB - setupUSB(); - SerialUSB.begin(); + SerialUSB.begin(); // includes { setupUSB(); } #endif } From 84d9c2bd204e34d83fcf848bf4824bbc6e010d04 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Sun, 8 Oct 2017 14:03:20 +1100 Subject: [PATCH 181/351] Fixed issue in OLED_I2C lib caused by change to HardWire as default I2C --- STM32F1/libraries/OLED_I2C/hardware/arm/HW_STM32.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/libraries/OLED_I2C/hardware/arm/HW_STM32.h b/STM32F1/libraries/OLED_I2C/hardware/arm/HW_STM32.h index 7060b44..25967c7 100644 --- a/STM32F1/libraries/OLED_I2C/hardware/arm/HW_STM32.h +++ b/STM32F1/libraries/OLED_I2C/hardware/arm/HW_STM32.h @@ -1,4 +1,4 @@ -#include "HardWire.h" +#include "Wire.h" #define WIRE_WRITE HWIRE.write HardWire HWIRE(2,I2C_FAST_MODE); // stupid compiler From 3c2fce63eed6beb4652ec08b68dd0b7e035949d1 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Sun, 8 Oct 2017 14:26:59 +1100 Subject: [PATCH 182/351] Update ILI9341 STM lib with version from SteveStrong, and also added ReadPixelsRGB24 to steve's version --- .../Adafruit_ILI9341_STM.cpp | 547 ++++++------------ .../Adafruit_ILI9341_STM.h | 80 +-- 2 files changed, 223 insertions(+), 404 deletions(-) diff --git a/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.cpp b/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.cpp index 766b910..914e4d1 100644 --- a/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.cpp +++ b/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.cpp @@ -4,120 +4,27 @@ This library has been modified for the Maple Mini. Includes DMA transfers on DMA1 CH2 and CH3. */ #include -#include -#include -#include -#include "pins_arduino.h" -#include "wiring_private.h" -#include // Using library SPI in folder: D:\Documents\Arduino\hardware\STM32\STM32F1XX\libraries\SPI - - -// Constructor when using software SPI. All output pins are configurable. -Adafruit_ILI9341_STM::Adafruit_ILI9341_STM(int8_t cs, int8_t dc, int8_t mosi, - int8_t sclk, int8_t rst, int8_t miso) : Adafruit_GFX(ILI9341_TFTWIDTH, ILI9341_TFTHEIGHT) { - _cs = cs; - _dc = dc; - _mosi = mosi; - _miso = miso; - _sclk = sclk; - _rst = rst; - hwSPI = false; -} // Constructor when using hardware SPI. Faster, but must use SPI pins // specific to each board type (e.g. 11,13 for Uno, 51,52 for Mega, etc.) -Adafruit_ILI9341_STM::Adafruit_ILI9341_STM(int8_t cs, int8_t dc, int8_t rst) : Adafruit_GFX(ILI9341_TFTWIDTH, ILI9341_TFTHEIGHT) { +Adafruit_ILI9341_STM::Adafruit_ILI9341_STM(int8_t cs, int8_t dc, int8_t rst) : Adafruit_GFX(ILI9341_TFTWIDTH, ILI9341_TFTHEIGHT) +{ _cs = cs; _dc = dc; _rst = rst; - hwSPI = true; - _mosi = _sclk = 0; } -void Adafruit_ILI9341_STM::spiwrite(uint16_t c) { - - //Serial.print("0x"); Serial.print(c, HEX); Serial.print(", "); - - if (hwSPI) - { -#if defined (__AVR__) - uint8_t backupSPCR = SPCR; - SPCR = mySPCR; - SPDR = c; - while (!(SPSR & _BV(SPIF))); - SPCR = backupSPCR; -#elif defined(TEENSYDUINO) - SPI.transfer(c); -#elif defined (__STM32F1__) - SPI.write(c); -#elif defined (__arm__) - SPI.setClockDivider(11); // 8-ish MHz (full! speed!) - SPI.setBitOrder(MSBFIRST); - SPI.setDataMode(SPI_MODE0); - SPI.transfer(c); - -#endif - } else { - // Fast SPI bitbang swiped from LPD8806 library - for (uint8_t bit = 0x80; bit; bit >>= 1) { - if (c & bit) { - //digitalWrite(_mosi, HIGH); - *mosiport |= mosipinmask; - } else { - //digitalWrite(_mosi, LOW); - *mosiport &= ~mosipinmask; - } - //digitalWrite(_sclk, HIGH); - *clkport |= clkpinmask; - //digitalWrite(_sclk, LOW); - *clkport &= ~clkpinmask; - } - } -} - - -void Adafruit_ILI9341_STM::writecommand(uint8_t c) { - *dcport &= ~dcpinmask; - *csport &= ~cspinmask; - +void Adafruit_ILI9341_STM::writecommand(uint8_t c) +{ + dc_command(); + cs_clear(); spiwrite(c); - - *csport |= cspinmask; + dc_data(); } -void Adafruit_ILI9341_STM::writedata(uint8_t c) { - *dcport |= dcpinmask; - *csport &= ~cspinmask; - - spiwrite(c); - - *csport |= cspinmask; -} - -// If the SPI library has transaction support, these functions -// establish settings and protect from interference from other -// libraries. Otherwise, they simply do nothing. -#ifdef SPI_HAS_TRANSACTION -static inline void spi_begin(void) __attribute__((always_inline)); -static inline void spi_begin(void) { -#ifdef __STM32F1__ - SPI.beginTransaction(SPISettings(36000000, MSBFIRST, SPI_MODE0)); -#else - SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0)); -#endif -} -static inline void spi_end(void) __attribute__((always_inline)); -static inline void spi_end(void) { - SPI.endTransaction(); -} -#else -#define spi_begin() -#define spi_end() -#endif - // Rather than a bazillion writecommand() and writedata() calls, screen // initialization commands and arguments are organized in these tables // stored in PROGMEM. The table may look bulky, but that's mostly the @@ -128,8 +35,8 @@ static inline void spi_end(void) { // Companion code to the above tables. Reads and issues // a series of LCD commands stored in PROGMEM byte array. -void Adafruit_ILI9341_STM::commandList(uint8_t *addr) { - +void Adafruit_ILI9341_STM::commandList(uint8_t *addr) +{ uint8_t numCommands, numArgs; uint16_t ms; @@ -152,54 +59,24 @@ void Adafruit_ILI9341_STM::commandList(uint8_t *addr) { } -void Adafruit_ILI9341_STM::begin(void) { - if (_rst > 0) { - pinMode(_rst, OUTPUT); - digitalWrite(_rst, LOW); - } - +void Adafruit_ILI9341_STM::begin(SPIClass & spi, uint32_t freq) +{ + mSPI = spi; + _freq = freq; + _safe_freq = (freq>SAFE_FREQ) ? SAFE_FREQ : _freq; pinMode(_dc, OUTPUT); pinMode(_cs, OUTPUT); - csport = portOutputRegister(digitalPinToPort(_cs)); + csport = portSetRegister(_cs); cspinmask = digitalPinToBitMask(_cs); - dcport = portOutputRegister(digitalPinToPort(_dc)); + cs_set(); // deactivate chip + dcport = portSetRegister(_dc); dcpinmask = digitalPinToBitMask(_dc); - if (hwSPI) { // Using hardware SPI -#if defined (__AVR__) - SPI.begin(); - SPI.setClockDivider(SPI_CLOCK_DIV2); // 8 MHz (full! speed!) - SPI.setBitOrder(MSBFIRST); - SPI.setDataMode(SPI_MODE0); - mySPCR = SPCR; -#elif defined(TEENSYDUINO) - SPI.begin(); - SPI.setClockDivider(SPI_CLOCK_DIV2); // 8 MHz (full! speed!) - SPI.setBitOrder(MSBFIRST); - SPI.setDataMode(SPI_MODE0); -#elif defined (__STM32F1__) - SPI.beginTransaction(SPISettings(36000000)); - -#elif defined (__arm__) - SPI.begin(); - SPI.setClockDivider(11); // 8-ish MHz (full! speed!) - SPI.setBitOrder(MSBFIRST); - SPI.setDataMode(SPI_MODE0); -#endif - } else { - pinMode(_sclk, OUTPUT); - pinMode(_mosi, OUTPUT); - pinMode(_miso, INPUT); - clkport = portOutputRegister(digitalPinToPort(_sclk)); - clkpinmask = digitalPinToBitMask(_sclk); - mosiport = portOutputRegister(digitalPinToPort(_mosi)); - mosipinmask = digitalPinToBitMask(_mosi); - *clkport &= ~clkpinmask; - *mosiport &= ~mosipinmask; - } + mSPI.beginTransaction(SPISettings(_safe_freq, MSBFIRST, SPI_MODE0, DATA_SIZE_8BIT)); // toggle RST low to reset if (_rst > 0) { + pinMode(_rst, OUTPUT); digitalWrite(_rst, HIGH); delay(5); digitalWrite(_rst, LOW); @@ -222,7 +99,6 @@ void Adafruit_ILI9341_STM::begin(void) { */ //if(cmdList) commandList(cmdList); - if (hwSPI) spi_begin(); writecommand(0xEF); writedata(0x03); writedata(0x80); @@ -265,7 +141,7 @@ void Adafruit_ILI9341_STM::begin(void) { writedata(0x10); //SAP[2:0];BT[3:0] writecommand(ILI9341_VMCTR1); //VCM control - writedata(0x3e); //�Աȶȵ��� + writedata(0x3e); writedata(0x28); writecommand(ILI9341_VMCTR2); //VCM control2 @@ -327,182 +203,129 @@ void Adafruit_ILI9341_STM::begin(void) { writedata(0x0F); writecommand(ILI9341_SLPOUT); //Exit Sleep - if (hwSPI) spi_end(); delay(120); - if (hwSPI) spi_begin(); writecommand(ILI9341_DISPON); //Display on - if (hwSPI) spi_end(); - if (hwSPI) SPI.setDataSize(SPI_CR1_DFF); + delay(120); + cs_set(); + + _width = ILI9341_TFTWIDTH; + _height = ILI9341_TFTHEIGHT; + + mSPI.beginTransaction(SPISettings(_freq, MSBFIRST, SPI_MODE0, DATA_SIZE_16BIT)); } -void Adafruit_ILI9341_STM::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, - uint16_t y1) { -#if defined (__STM32F1__) +void Adafruit_ILI9341_STM::setAddrWindow(uint16_t x0, uint16_t y0, + uint16_t x1, uint16_t y1) +{ writecommand(ILI9341_CASET); // Column addr set - *dcport |= dcpinmask; - *csport &= ~cspinmask; - SPI.write(x0); - SPI.write(x1); + spiwrite(x0); + spiwrite(x1); writecommand(ILI9341_PASET); // Row addr set - *dcport |= dcpinmask; - *csport &= ~cspinmask; - SPI.write(y0); - SPI.write(y1); + spiwrite(y0); + spiwrite(y1); writecommand(ILI9341_RAMWR); // write to RAM - -#else - writecommand(ILI9341_CASET); // Column addr set - writedata(x0 >> 8); - writedata(x0 & 0xFF); // XSTART - writedata(x1 >> 8); - writedata(x1 & 0xFF); // XEND - - writecommand(ILI9341_PASET); // Row addr set - writedata(y0 >> 8); - writedata(y0); // YSTART - writedata(y1 >> 8); - writedata(y1); // YEND - - writecommand(ILI9341_RAMWR); // write to RAM -#endif } -void Adafruit_ILI9341_STM::pushColor(uint16_t color) { - if (hwSPI) spi_begin(); - //digitalWrite(_dc, HIGH); - *dcport |= dcpinmask; - //digitalWrite(_cs, LOW); - *csport &= ~cspinmask; - - spiwrite(color); - - *csport |= cspinmask; - //digitalWrite(_cs, HIGH); - if (hwSPI) spi_end(); -} - void Adafruit_ILI9341_STM::pushColors(void * colorBuffer, uint16_t nr_pixels, uint8_t async) { - *dcport |= dcpinmask; - *csport &= ~cspinmask; + cs_clear(); - if (async==0) - { - SPI.dmaSend(colorBuffer, nr_pixels, 1); - *csport |= cspinmask; + if (async==0) { + mSPI.dmaSend(colorBuffer, nr_pixels, 1); + cs_set(); + } else { + mSPI.dmaSendAsync(colorBuffer, nr_pixels, 1); } - else - { - SPI.dmaSendAsync(colorBuffer, nr_pixels, 1); - } - } -void Adafruit_ILI9341_STM::drawPixel(int16_t x, int16_t y, uint16_t color) { +void Adafruit_ILI9341_STM::pushColor(uint16_t color) +{ + cs_clear(); + spiwrite(color); + cs_set(); +} +void Adafruit_ILI9341_STM::drawPixel(int16_t x, int16_t y, uint16_t color) +{ if ((x < 0) || (x >= _width) || (y < 0) || (y >= _height)) return; - if (hwSPI) spi_begin(); setAddrWindow(x, y, x + 1, y + 1); - *dcport |= dcpinmask; - *csport &= ~cspinmask; - spiwrite(color); - *csport |= cspinmask; - if (hwSPI) spi_end(); + cs_set(); } void Adafruit_ILI9341_STM::drawFastVLine(int16_t x, int16_t y, int16_t h, - uint16_t color) { - + uint16_t color) +{ // Rudimentary clipping if ((x >= _width) || (y >= _height || h < 1)) return; - if ((y + h - 1) >= _height) h = _height - y; if (h < 2 ) { - drawPixel(x, y, color); - return; + drawPixel(x, y, color); + return; } - // if (hwSPI) spi_begin(); setAddrWindow(x, y, x, y + h - 1); - *dcport |= dcpinmask; - *csport &= ~cspinmask; - -#if defined (__STM32F1__) - lineBuffer[0] = color; - SPI.dmaSend(lineBuffer, h, 0); - #else - uint8_t hi = color >> 8, lo = color; - while (h--) { - spiwrite(hi); - spiwrite(lo); + if (h>DMA_ON_LIMIT) { + lineBuffer[0] = color; + mSPI.dmaSend(lineBuffer, h, 0); + } else { + mSPI.write(color, h); } -#endif - *csport |= cspinmask; + cs_set(); } void Adafruit_ILI9341_STM::drawFastHLine(int16_t x, int16_t y, int16_t w, - uint16_t color) { - - + uint16_t color) +{ // Rudimentary clipping if ((x >= _width) || (y >= _height || w < 1)) return; if ((x + w - 1) >= _width) w = _width - x; if (w < 2 ) { - drawPixel(x, y, color); - return; + drawPixel(x, y, color); + return; } -// if (hwSPI) spi_begin(); setAddrWindow(x, y, x + w - 1, y); - *dcport |= dcpinmask; - *csport &= ~cspinmask; -#if defined (__STM32F1__) - lineBuffer[0] = color; - SPI.dmaSend(lineBuffer, w, 0); -#else - uint8_t hi = color >> 8, lo = color; - while (w--) { - spiwrite(hi); - spiwrite(lo); - } -#endif - *csport |= cspinmask; - //digitalWrite(_cs, HIGH); -// if (hwSPI) spi_end(); + if (w>DMA_ON_LIMIT) { + lineBuffer[0] = color; + mSPI.dmaSend(lineBuffer, w, 0); + } else { + mSPI.write(color, w); + } + cs_set(); } -void Adafruit_ILI9341_STM::fillScreen(uint16_t color) { -#if defined (__STM32F1__) - setAddrWindow(0, 0, _width - 1, _height - 1); - *dcport |= dcpinmask; - *csport &= ~cspinmask; +void Adafruit_ILI9341_STM::fillScreen(uint16_t color) +{ lineBuffer[0] = color; - SPI.dmaSend(lineBuffer, (65535), 0); - SPI.dmaSend(lineBuffer, ((_width * _height) - 65535), 0); - -#else - fillRect(0, 0, _width, _height, color); -#endif + setAddrWindow(0, 0, _width - 1, _height - 1); + uint32_t nr_bytes = _width * _height; + while ( nr_bytes>65535 ) { + nr_bytes -= 65535; + mSPI.dmaSend(lineBuffer, (65535), 0); + } + mSPI.dmaSend(lineBuffer, nr_bytes, 0); + cs_set(); } // fill a rectangle void Adafruit_ILI9341_STM::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, - uint16_t color) { - + uint16_t color) +{ + lineBuffer[0] = color; // rudimentary clipping (drawChar w/big text requires this) if ((x >= _width) || (y >= _height || h < 1 || w < 1)) return; if ((x + w - 1) >= _width) w = _width - x; @@ -511,41 +334,26 @@ void Adafruit_ILI9341_STM::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, drawPixel(x, y, color); return; } - - if (hwSPI) spi_begin(); - setAddrWindow(x, y, x + w - 1, y + h - 1); - *dcport |= dcpinmask; - *csport &= ~cspinmask; -#if defined (__STM32F1__) - lineBuffer[0] = color; - if (w*h <= 65535) { - SPI.dmaSend(lineBuffer, (w*h), 0); - } - else { - SPI.dmaSend(lineBuffer, (65535), 0); - SPI.dmaSend(lineBuffer, ((w*h) - 65535), 0); - } -#else - uint8_t hi = color >> 8, lo = color; - for(y=h; y>0; y--) - { - for(x=w; x>0; x--) - { - SPI.write(hi); - SPI.write(lo); + setAddrWindow(x, y, x + w - 1, y + h - 1); + uint32_t nr_bytes = w * h; + if ( nr_bytes>DMA_ON_LIMIT ) { + while ( nr_bytes>65535 ) { + nr_bytes -= 65535; + mSPI.dmaSend(lineBuffer, (65535), 0); } + mSPI.dmaSend(lineBuffer, nr_bytes, 0); + } else { + mSPI.write(color, nr_bytes); } -#endif - *csport |= cspinmask; - if (hwSPI) spi_end(); + cs_set(); } /* * Draw lines faster by calculating straight sections and drawing them with fastVline and fastHline. */ -#if defined (__STM32F1__) -void Adafruit_ILI9341_STM::drawLine(int16_t x0, int16_t y0,int16_t x1, int16_t y1, uint16_t color) +void Adafruit_ILI9341_STM::drawLine(int16_t x0, int16_t y0, + int16_t x1, int16_t y1, uint16_t color) { if ((y0 < 0 && y1 <0) || (y0 > _height && y1 > _height)) return; if ((x0 < 0 && x1 <0) || (x0 > _width && x1 > _width)) return; @@ -601,8 +409,6 @@ void Adafruit_ILI9341_STM::drawLine(int16_t x0, int16_t y0,int16_t x1, int16_t y } int16_t xbegin = x0; - lineBuffer[0] = color; - *csport &= ~cspinmask; if (steep) { for (; x0 <= x1; x0++) { err -= dy; @@ -650,11 +456,7 @@ void Adafruit_ILI9341_STM::drawLine(int16_t x0, int16_t y0,int16_t x1, int16_t y drawFastHLine(xbegin, y0, x0 - xbegin, color); } } - *csport |= cspinmask; } -#endif - - // Pass 8-bit (each) R,G,B, get back 16-bit packed color uint16_t Adafruit_ILI9341_STM::color565(uint8_t r, uint8_t g, uint8_t b) { @@ -670,118 +472,133 @@ uint16_t Adafruit_ILI9341_STM::color565(uint8_t r, uint8_t g, uint8_t b) { #define MADCTL_BGR 0x08 #define MADCTL_MH 0x04 -void Adafruit_ILI9341_STM::setRotation(uint8_t m) { - - if (hwSPI) spi_begin(); - if (hwSPI) SPI.setDataSize(0); - writecommand(ILI9341_MADCTL); +void Adafruit_ILI9341_STM::setRotation(uint8_t m) +{ rotation = m % 4; // can't be higher than 3 switch (rotation) { case 0: - writedata(MADCTL_MX | MADCTL_BGR); + m = (MADCTL_MX | MADCTL_BGR); _width = ILI9341_TFTWIDTH; _height = ILI9341_TFTHEIGHT; break; case 1: - writedata(MADCTL_MV | MADCTL_BGR); + m = (MADCTL_MV | MADCTL_BGR); _width = ILI9341_TFTHEIGHT; _height = ILI9341_TFTWIDTH; break; case 2: - writedata(MADCTL_MY | MADCTL_BGR); + m = (MADCTL_MY | MADCTL_BGR); _width = ILI9341_TFTWIDTH; _height = ILI9341_TFTHEIGHT; break; case 3: - writedata(MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR); + m = (MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR); _width = ILI9341_TFTHEIGHT; _height = ILI9341_TFTWIDTH; break; } - if (hwSPI) SPI.setDataSize(SPI_CR1_DFF); - if (hwSPI) spi_end(); + mSPI.setDataSize(DATA_SIZE_8BIT); + writecommand(ILI9341_MADCTL); + writedata(m); + cs_set(); + mSPI.setDataSize(DATA_SIZE_16BIT); } -void Adafruit_ILI9341_STM::invertDisplay(boolean i) { - if (hwSPI) spi_begin(); +void Adafruit_ILI9341_STM::invertDisplay(boolean i) +{ writecommand(i ? ILI9341_INVON : ILI9341_INVOFF); - if (hwSPI) spi_end(); + cs_set(); } -////////// stuff not actively being used, but kept for posterity +uint16_t Adafruit_ILI9341_STM::readPixel(int16_t x, int16_t y) +{ + mSPI.beginTransaction(SPISettings(_safe_freq, MSBFIRST, SPI_MODE0, DATA_SIZE_8BIT)); + writecommand(ILI9341_CASET); // Column addr set + spiwrite16(x); + spiwrite16(x); + writecommand(ILI9341_PASET); // Row addr set + spiwrite16(y); + spiwrite16(y); + writecommand(ILI9341_RAMRD); // read GRAM + (void)spiread(); //dummy read + uint8_t r = spiread(); + uint8_t g = spiread(); + uint8_t b = spiread(); + cs_set(); -uint8_t Adafruit_ILI9341_STM::spiread(void) { - uint8_t r = 0; + mSPI.beginTransaction(SPISettings(_freq, MSBFIRST, SPI_MODE0, DATA_SIZE_16BIT)); - if (hwSPI) { -#if defined (__AVR__) - uint8_t backupSPCR = SPCR; - SPCR = mySPCR; - SPDR = 0x00; - while (!(SPSR & _BV(SPIF))); - r = SPDR; - SPCR = backupSPCR; -#elif defined(TEENSYDUINO) - r = SPI.transfer(0x00); -#elif defined (__STM32F1__) - r = SPI.transfer(0x00); -#elif defined (__arm__) - SPI.setClockDivider(11); // 8-ish MHz (full! speed!) - SPI.setBitOrder(MSBFIRST); - SPI.setDataMode(SPI_MODE0); - r = SPI.transfer(0x00); -#endif - } else { + return color565(r, g, b); +} - for (uint8_t i = 0; i < 8; i++) { - digitalWrite(_sclk, LOW); - digitalWrite(_sclk, HIGH); - r <<= 1; - if (digitalRead(_miso)) - r |= 0x1; - } +uint16_t Adafruit_ILI9341_STM::readPixels(int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t *buf) +{ + mSPI.beginTransaction(SPISettings(_safe_freq, MSBFIRST, SPI_MODE0, DATA_SIZE_8BIT)); + + writecommand(ILI9341_CASET); // Column addr set + spiwrite16(x1); + spiwrite16(x2); + writecommand(ILI9341_PASET); // Row addr set + spiwrite16(y1); + spiwrite16(y2); + writecommand(ILI9341_RAMRD); // read GRAM + (void)spiread(); //dummy read + uint8_t r, g, b; + uint16_t len = (x2-x1+1)*(y2-y1+1); + uint16_t ret = len; + while (len--) { + r = spiread(); + g = spiread(); + b = spiread(); + *buf++ = color565(r, g, b); } - //Serial.print("read: 0x"); Serial.print(r, HEX); + cs_set(); - return r; + mSPI.beginTransaction(SPISettings(_freq, MSBFIRST, SPI_MODE0, DATA_SIZE_16BIT)); + return ret; } -uint8_t Adafruit_ILI9341_STM::readdata(void) { - digitalWrite(_dc, HIGH); - digitalWrite(_cs, LOW); + +uint16_t Adafruit_ILI9341_STM::readPixelsRGB24(int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint8_t *buf) +{ + mSPI.beginTransaction(SPISettings(_safe_freq, MSBFIRST, SPI_MODE0, DATA_SIZE_8BIT)); + + writecommand(ILI9341_CASET); // Column addr set + spiwrite16(x1); + spiwrite16(x2); + writecommand(ILI9341_PASET); // Row addr set + spiwrite16(y1); + spiwrite16(y2); + writecommand(ILI9341_RAMRD); // read GRAM + (void)spiread(); //dummy read + uint8_t r, g, b; + uint16_t len = (x2-x1+1)*(y2-y1+1); + uint16_t ret = len; + + mSPI.dmaTransfer(buf, buf, len*3); + cs_set(); + + mSPI.beginTransaction(SPISettings(_freq, MSBFIRST, SPI_MODE0, DATA_SIZE_16BIT)); + return ret; +} + +uint8_t Adafruit_ILI9341_STM::readcommand8(uint8_t c, uint8_t index) +{ + // the SPI clock must be set lower + mSPI.beginTransaction(SPISettings(_safe_freq, MSBFIRST, SPI_MODE0, DATA_SIZE_8BIT)); + + writecommand(c); uint8_t r = spiread(); - digitalWrite(_cs, HIGH); + cs_set(); + mSPI.beginTransaction(SPISettings(_freq, MSBFIRST, SPI_MODE0, DATA_SIZE_16BIT)); return r; } -uint8_t Adafruit_ILI9341_STM::readcommand8(uint8_t c, uint8_t index) { - if (hwSPI) spi_begin(); - digitalWrite(_dc, LOW); // command - digitalWrite(_cs, LOW); - spiwrite(0xD9); // woo sekret command? - digitalWrite(_dc, HIGH); // data - spiwrite(0x10 + index); - digitalWrite(_cs, HIGH); - - digitalWrite(_dc, LOW); - //if(hwSPI) digitalWrite(_sclk, LOW); - digitalWrite(_cs, LOW); - spiwrite(c); - - digitalWrite(_dc, HIGH); - uint8_t r = spiread(); - digitalWrite(_cs, HIGH); - if (hwSPI) spi_end(); - return r; -} - - - /* uint16_t Adafruit_ILI9341_STM::readcommand16(uint8_t c) { diff --git a/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.h b/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.h index 7ee395c..b77b356 100644 --- a/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.h +++ b/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.h @@ -7,9 +7,8 @@ This library has been modified for the Maple Mini #define _ADAFRUIT_ILI9341H_ #include "Arduino.h" -#include "Print.h" #include -#include +#include #ifndef swap #define swap(a, b) { int16_t t = a; a = b; b = t; } @@ -100,18 +99,15 @@ class Adafruit_ILI9341_STM : public Adafruit_GFX { public: - Adafruit_ILI9341_STM(int8_t _CS, int8_t _DC, int8_t _MOSI, int8_t _SCLK, - int8_t _RST, int8_t _MISO); Adafruit_ILI9341_STM(int8_t _CS, int8_t _DC, int8_t _RST = -1); - - void begin(void), - setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1), + + void begin(SPIClass & spi, uint32_t freq=48000000); + void begin(void) { begin(SPI); } + void setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1), pushColor(uint16_t color), - pushColors(void * colorBuffer, uint16_t nr_pixels, uint8_t async), + pushColors(void * colorBuffer, uint16_t nr_pixels, uint8_t async=0), fillScreen(uint16_t color), - #if defined (__STM32F1__) drawLine(int16_t x0, int16_t y0,int16_t x1, int16_t y1, uint16_t color), - #endif drawPixel(int16_t x, int16_t y, uint16_t color), drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color), drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color), @@ -122,43 +118,49 @@ class Adafruit_ILI9341_STM : public Adafruit_GFX { uint16_t color565(uint8_t r, uint8_t g, uint8_t b); /* These are not for current use, 8-bit protocol only! */ - uint8_t readdata(void), - readcommand8(uint8_t reg, uint8_t index = 0); + uint16_t readPixel(int16_t x, int16_t y); + uint16_t readPixels(int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t *buf); + uint16_t readPixelsRGB24(int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint8_t *buf); + + uint8_t readcommand8(uint8_t reg, uint8_t index = 0); /* uint16_t readcommand16(uint8_t); uint32_t readcommand32(uint8_t); - void dummyclock(void); - */ + */ - void spiwrite(uint16_t), - writecommand(uint8_t c), - writedata(uint8_t d), - commandList(uint8_t *addr); - uint8_t spiread(void); +#define DMA_ON_LIMIT 250 // do DMA only for more data than this +#define SAFE_FREQ 24000000ul // 24MHz for reading +#define writePixel drawPixel + +#define dc_command() ( *dcport =(uint32_t)dcpinmask<<16 ) // 0 +#define dc_data() ( *dcport =(uint32_t)dcpinmask ) // 1 +#define cs_clear() ( *csport =(uint32_t)cspinmask<<16 ) +#define cs_set() ( *csport =(uint32_t)cspinmask ) +#define clk_clear() ( *clkport =(uint32_t)clkpinmask<<16 ) +#define clk_set() ( *clkport =(uint32_t)clkpinmask ) +#define mosi_clear() ( *mosiport=(uint32_t)misopinmask<<16 ) +#define mosi_set() ( *mosiport=(uint32_t)misopinmask ) +#define miso_in() ( (*misoport)&misopinmask ) + + inline uint8_t spiread(void) { return mSPI.transfer(0x00); } + inline uint8_t readdata(void) { return mSPI.transfer(0x00); } + inline void writedata(uint8_t c) { mSPI.write(c); } + inline void spiwrite(uint16_t c) { mSPI.write(c); } + inline void spiwrite16(uint16_t c) { mSPI.write16(c); } // 8 bit mode + + void writecommand(uint8_t c), + commandList(uint8_t *addr); private: - uint8_t tabcolor; + uint32_t _freq, _safe_freq; + SPIClass & mSPI = SPI; - - - - boolean hwSPI; -#if defined (__AVR__) || defined(TEENSYDUINO) - uint8_t mySPCR; - volatile uint8_t *mosiport, *clkport, *dcport, *rsport, *csport; - int8_t _cs, _dc, _rst, _mosi, _miso, _sclk; - uint8_t mosipinmask, clkpinmask, cspinmask, dcpinmask; -#elif defined (__STM32F1__) - volatile uint32 *mosiport, *clkport, *dcport, *rsport, *csport; - uint32_t _cs, _dc, _rst, _mosi, _miso, _sclk; - uint32_t mosipinmask, clkpinmask, cspinmask, dcpinmask; - uint16_t lineBuffer[ILI9341_TFTHEIGHT]; // DMA buffer. 16bit color data per pixel -#elif defined (__arm__) - volatile RwReg *mosiport, *clkport, *dcport, *rsport, *csport; - uint32_t _cs, _dc, _rst, _mosi, _miso, _sclk; - uint32_t mosipinmask, clkpinmask, cspinmask, dcpinmask; -#endif + volatile uint32_t *csport, *dcport; + int8_t _cs, _dc, _rst; + uint16_t cspinmask, dcpinmask; + uint16_t lineBuffer[ILI9341_TFTHEIGHT]; // DMA buffer. 16bit color data per pixel }; + #endif From a89d0b935b6f177ef1eb52e17b3e8c670c5168cc Mon Sep 17 00:00:00 2001 From: csnol Date: Wed, 18 Oct 2017 21:42:31 +0800 Subject: [PATCH 183/351] Half-hour TimeZone supported --- STM32F1/libraries/RTClock/src/RTClock.cpp | 16 ++++++++++++++++ STM32F1/libraries/RTClock/src/RTClock.h | 9 ++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) mode change 100644 => 100755 STM32F1/libraries/RTClock/src/RTClock.cpp mode change 100644 => 100755 STM32F1/libraries/RTClock/src/RTClock.h diff --git a/STM32F1/libraries/RTClock/src/RTClock.cpp b/STM32F1/libraries/RTClock/src/RTClock.cpp old mode 100644 new mode 100755 index e95bead..0bfe7df --- a/STM32F1/libraries/RTClock/src/RTClock.cpp +++ b/STM32F1/libraries/RTClock/src/RTClock.cpp @@ -79,6 +79,22 @@ //to implement } */ + + // Usage: 1. localtime = TimeZone(UnixTime, 9, 1) means SAT +09:30 TimeZone; + // 2. localtime = TimeZone(UnixTime, -3, 1) means NST,NFT -03:30 TimeZone; + // 3. TimeZone(UnixTime, 8, 0) same function as TimeZone(UnixTime, 8) -> CCT +08:00 + + time_t RTClock::TimeZone(time_t t, int TZ, bool HFZ) { // HFZ : Half-hour TimeZone flag + if(HFZ) { + if(TZ > 0 ) + return ( t + (TZ * SECS_PER_HOUR) + 1800); + else + return ( t + (TZ * SECS_PER_HOUR) - 1800); + } + else + return ( t + (TZ * SECS_PER_HOUR)); + } +// void RTClock::setTime (tm_t & tmm) { time_t mktm = makeTime(tmm); // time will be make to mktm diff --git a/STM32F1/libraries/RTClock/src/RTClock.h b/STM32F1/libraries/RTClock/src/RTClock.h old mode 100644 new mode 100755 index 4d8399e..d6b3090 --- a/STM32F1/libraries/RTClock/src/RTClock.h +++ b/STM32F1/libraries/RTClock/src/RTClock.h @@ -15,6 +15,7 @@ #define SECS_PER_YEAR (SECS_PER_WEEK * 52UL) #define SECS_YR_2000 (946684800UL) // the time at the start of y2k #define LEAP_YEAR(Y) ( ((1970+Y)>0) && !((1970+Y)%4) && ( ((1970+Y)%100) || !((1970+Y)%400) ) ) +#define HALFTZ 0 #if !defined(__time_t_defined) // avoid conflict with newlib or other posix libc #warning "Using private time_t definintion" @@ -71,8 +72,14 @@ class RTClock { uint8_t minute(time_t t) { breakTime(t, tmm); return tmm.minute; } uint8_t second(time_t t) { breakTime(t, tmm); return tmm.second; } uint8_t isPM(time_t t) { return (hour(t)>=12); } + + // Usage: localtime = TimeZone(UnixTime, 8); + time_t TimeZone(time_t t, int TZ) { return ( t + (TZ * SECS_PER_HOUR)); } - time_t TimeZone(time_t t, int TZ) { return ( t + (TZ * SECS_PER_HOUR)); } // usage: localtime = TimeZone(UnixTime, 8); // Beijing timezone = 8 + // Usage: 1. localtime = TimeZone(UnixTime, 9, 1) means SAT +09:30 TimeZone; + // 2. localtime = TimeZone(UnixTime, -3, 1) means NST,NFT -03:30 TimeZone; + // 3. TimeZone(UnixTime, 8, 0) same function as TimeZone(UnixTime, 8) -> CCT +08:00 + time_t TimeZone(time_t t, int TZ, bool HFZ); // HFZ : Half-hour TimeZone flag void createAlarm(voidFuncPtr function, time_t alarm_time_t); void createAlarm(voidFuncPtr function, struct tm_t & alarm_tm); From 9f5cdd2d24bf4c0d24f99963221cee5a8fe38f42 Mon Sep 17 00:00:00 2001 From: csnol Date: Wed, 18 Oct 2017 21:45:19 +0800 Subject: [PATCH 184/351] updated --- STM32F1/libraries/RTClock/src/RTClock.h | 1 - 1 file changed, 1 deletion(-) diff --git a/STM32F1/libraries/RTClock/src/RTClock.h b/STM32F1/libraries/RTClock/src/RTClock.h index d6b3090..c0954ea 100755 --- a/STM32F1/libraries/RTClock/src/RTClock.h +++ b/STM32F1/libraries/RTClock/src/RTClock.h @@ -15,7 +15,6 @@ #define SECS_PER_YEAR (SECS_PER_WEEK * 52UL) #define SECS_YR_2000 (946684800UL) // the time at the start of y2k #define LEAP_YEAR(Y) ( ((1970+Y)>0) && !((1970+Y)%4) && ( ((1970+Y)%100) || !((1970+Y)%400) ) ) -#define HALFTZ 0 #if !defined(__time_t_defined) // avoid conflict with newlib or other posix libc #warning "Using private time_t definintion" From 80ae49dd5037315e652eec43d04c25dc57c91364 Mon Sep 17 00:00:00 2001 From: Michel Stempin Date: Wed, 18 Oct 2017 22:04:54 +0200 Subject: [PATCH 185/351] Added missing SDIO pins for F103V and F103Z --- STM32F1/variants/generic_stm32f103v/board/board.h | 10 ++++++++++ STM32F1/variants/generic_stm32f103z/board/board.h | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/STM32F1/variants/generic_stm32f103v/board/board.h b/STM32F1/variants/generic_stm32f103v/board/board.h index 92f2bf8..3bb680a 100644 --- a/STM32F1/variants/generic_stm32f103v/board/board.h +++ b/STM32F1/variants/generic_stm32f103v/board/board.h @@ -109,6 +109,16 @@ #define BOARD_USB_DISC_DEV GPIOC #define BOARD_USB_DISC_BIT 12 +/* + * SDIO Pins + */ +#define BOARD_SDIO_D0 PC8 +#define BOARD_SDIO_D1 PC9 +#define BOARD_SDIO_D2 PC10 +#define BOARD_SDIO_D3 PC11 +#define BOARD_SDIO_CLK PC12 +#define BOARD_SDIO_CMD PD2 + /* Pin aliases: these give the GPIO port/bit for each pin as an * enum. These are optional, but recommended. They make it easier to * write code using low-level GPIO functionality. */ diff --git a/STM32F1/variants/generic_stm32f103z/board/board.h b/STM32F1/variants/generic_stm32f103z/board/board.h index c9bf4b5..fe48567 100644 --- a/STM32F1/variants/generic_stm32f103z/board/board.h +++ b/STM32F1/variants/generic_stm32f103z/board/board.h @@ -102,6 +102,16 @@ #define BOARD_USB_DISC_DEV GPIOC #define BOARD_USB_DISC_BIT 12 +/* + * SDIO Pins + */ +#define BOARD_SDIO_D0 PC8 +#define BOARD_SDIO_D1 PC9 +#define BOARD_SDIO_D2 PC10 +#define BOARD_SDIO_D3 PC11 +#define BOARD_SDIO_CLK PC12 +#define BOARD_SDIO_CMD PD2 + /* Pin aliases: these give the GPIO port/bit for each pin as an * enum. These are optional, but recommended. They make it easier to * write code using low-level GPIO functionality. */ From c741afa74a87c17dafe49f1de3bb3d7f2f17b08d Mon Sep 17 00:00:00 2001 From: csnol Date: Thu, 19 Oct 2017 17:23:48 +0800 Subject: [PATCH 186/351] Update TimeZone function Add TimeZone(UnixTime, HourOffset, MinuteOffset) --- STM32F1/libraries/RTClock/src/RTClock.cpp | 15 --------------- STM32F1/libraries/RTClock/src/RTClock.h | 6 ++---- 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/STM32F1/libraries/RTClock/src/RTClock.cpp b/STM32F1/libraries/RTClock/src/RTClock.cpp index 0bfe7df..5f0467f 100755 --- a/STM32F1/libraries/RTClock/src/RTClock.cpp +++ b/STM32F1/libraries/RTClock/src/RTClock.cpp @@ -80,21 +80,6 @@ } */ - // Usage: 1. localtime = TimeZone(UnixTime, 9, 1) means SAT +09:30 TimeZone; - // 2. localtime = TimeZone(UnixTime, -3, 1) means NST,NFT -03:30 TimeZone; - // 3. TimeZone(UnixTime, 8, 0) same function as TimeZone(UnixTime, 8) -> CCT +08:00 - - time_t RTClock::TimeZone(time_t t, int TZ, bool HFZ) { // HFZ : Half-hour TimeZone flag - if(HFZ) { - if(TZ > 0 ) - return ( t + (TZ * SECS_PER_HOUR) + 1800); - else - return ( t + (TZ * SECS_PER_HOUR) - 1800); - } - else - return ( t + (TZ * SECS_PER_HOUR)); - } -// void RTClock::setTime (tm_t & tmm) { time_t mktm = makeTime(tmm); // time will be make to mktm diff --git a/STM32F1/libraries/RTClock/src/RTClock.h b/STM32F1/libraries/RTClock/src/RTClock.h index c0954ea..60b6fbc 100755 --- a/STM32F1/libraries/RTClock/src/RTClock.h +++ b/STM32F1/libraries/RTClock/src/RTClock.h @@ -75,10 +75,8 @@ class RTClock { // Usage: localtime = TimeZone(UnixTime, 8); time_t TimeZone(time_t t, int TZ) { return ( t + (TZ * SECS_PER_HOUR)); } - // Usage: 1. localtime = TimeZone(UnixTime, 9, 1) means SAT +09:30 TimeZone; - // 2. localtime = TimeZone(UnixTime, -3, 1) means NST,NFT -03:30 TimeZone; - // 3. TimeZone(UnixTime, 8, 0) same function as TimeZone(UnixTime, 8) -> CCT +08:00 - time_t TimeZone(time_t t, int TZ, bool HFZ); // HFZ : Half-hour TimeZone flag + // Usage: 1. localtime = TimeZone(UnixTime, 9, 45) -> UTC +09:45 TimeZone; + time_t TimeZone(time_t t, int HTZ, int MTZ) { return ( t + (HTZ * SECS_PER_HOUR) + (MTZ * 60); } // HTZ = Hour offset, MTZ = Minute offset void createAlarm(voidFuncPtr function, time_t alarm_time_t); void createAlarm(voidFuncPtr function, struct tm_t & alarm_tm); From 4870e27855ade718158ee61d572c9d35072ef4db Mon Sep 17 00:00:00 2001 From: csnol Date: Thu, 19 Oct 2017 17:26:42 +0800 Subject: [PATCH 187/351] Update --- STM32F1/libraries/RTClock/src/RTClock.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/STM32F1/libraries/RTClock/src/RTClock.cpp b/STM32F1/libraries/RTClock/src/RTClock.cpp index 5f0467f..e95bead 100755 --- a/STM32F1/libraries/RTClock/src/RTClock.cpp +++ b/STM32F1/libraries/RTClock/src/RTClock.cpp @@ -79,7 +79,6 @@ //to implement } */ - void RTClock::setTime (tm_t & tmm) { time_t mktm = makeTime(tmm); // time will be make to mktm From 588f9db6976f3f1f5b332955484e4fc22123b71d Mon Sep 17 00:00:00 2001 From: csnol Date: Thu, 19 Oct 2017 18:31:23 +0800 Subject: [PATCH 188/351] update --- STM32F1/libraries/RTClock/src/RTClock.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/libraries/RTClock/src/RTClock.h b/STM32F1/libraries/RTClock/src/RTClock.h index 60b6fbc..71015a5 100755 --- a/STM32F1/libraries/RTClock/src/RTClock.h +++ b/STM32F1/libraries/RTClock/src/RTClock.h @@ -76,7 +76,7 @@ class RTClock { time_t TimeZone(time_t t, int TZ) { return ( t + (TZ * SECS_PER_HOUR)); } // Usage: 1. localtime = TimeZone(UnixTime, 9, 45) -> UTC +09:45 TimeZone; - time_t TimeZone(time_t t, int HTZ, int MTZ) { return ( t + (HTZ * SECS_PER_HOUR) + (MTZ * 60); } // HTZ = Hour offset, MTZ = Minute offset + time_t TimeZone(time_t t, int HTZ, int MTZ) { return ( t + (HTZ * SECS_PER_HOUR) + (MTZ * 60)); } // HTZ = Hour offset, MTZ = Minute offset void createAlarm(voidFuncPtr function, time_t alarm_time_t); void createAlarm(voidFuncPtr function, struct tm_t & alarm_tm); From 4a3e23949b3efde74bf786cf91f78cb6315fed04 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Tue, 31 Oct 2017 20:05:31 +1100 Subject: [PATCH 189/351] Added DMA enable and disable functions to hardware timers, thanks to @stevstrong --- STM32F1/cores/maple/HardwareTimer.cpp | 9 +++++++++ STM32F1/cores/maple/HardwareTimer.h | 6 ++++++ 2 files changed, 15 insertions(+) diff --git a/STM32F1/cores/maple/HardwareTimer.cpp b/STM32F1/cores/maple/HardwareTimer.cpp index ecd1b11..abf1e62 100644 --- a/STM32F1/cores/maple/HardwareTimer.cpp +++ b/STM32F1/cores/maple/HardwareTimer.cpp @@ -138,6 +138,15 @@ void HardwareTimer::detachInterrupt(int channel) { timer_detach_interrupt(this->dev, (uint8)channel); } + +void HardwareTimer::enableDMA(int channel) { + timer_dma_enable_req(this->dev, (uint8)channel); +} + +void HardwareTimer::disableDMA(int channel) { + timer_dma_disable_req(this->dev, (uint8)channel); +} + void HardwareTimer::refresh(void) { timer_generate_update(this->dev); } diff --git a/STM32F1/cores/maple/HardwareTimer.h b/STM32F1/cores/maple/HardwareTimer.h index 75601d0..d5356ca 100644 --- a/STM32F1/cores/maple/HardwareTimer.h +++ b/STM32F1/cores/maple/HardwareTimer.h @@ -245,6 +245,12 @@ public: /* Escape hatch */ + /** + * @brief Enable/disable DMA request for the input channel. + */ + void enableDMA(int channel); + void disableDMA(int channel); + /** * @brief Get a pointer to the underlying libmaple timer_dev for * this HardwareTimer instance. From e14c83fe8d39d7012075f8a98c72a2b0a335c4e8 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Wed, 1 Nov 2017 15:24:04 +0100 Subject: [PATCH 190/351] Update tone.cpp - make tone() blocking for the input duration time --- STM32F1/cores/maple/tone.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/STM32F1/cores/maple/tone.cpp b/STM32F1/cores/maple/tone.cpp index 965bfdd..45cfa0e 100644 --- a/STM32F1/cores/maple/tone.cpp +++ b/STM32F1/cores/maple/tone.cpp @@ -60,7 +60,7 @@ uint8_t tone_ntimer = TONE_TIMER; // timer used to generate freque bool tone_state = true; // last pin state for toggling short tone_pin = -1; // pin for outputting sound short tone_freq = 444; // tone frequency (0=pause) -uint32_t tone_nhw = 0; // tone duration in number of half waves +volatile uint32_t tone_nhw = 0; // tone duration in number of half waves uint16_t tone_tcount = 0; // time between handler calls in 1/36 usec uint16_t tone_ncount = 0; // handler call between toggling uint16_t tone_n = 0; // remaining handler calls before toggling @@ -146,12 +146,12 @@ void tone(uint32_t pin, uint32_t freq, uint32_t duration) { tone_timer->pause(); - if(freq > 0 && duration >0 ){ + if(freq > 0){ uint32_t count = (F_CPU/4)/freq; // timer counts per half wave tone_ncount = tone_n = (count>>16)+1; // number of 16-bit count chunk tone_tcount = count/tone_ncount; // size of count chunk if(duration > 0) // number of half waves to be generated - tone_nhw = ((duration*(freq>0?freq:100))/1000)<<1; + tone_nhw = ((duration*freq)/1000)<<1; else // no duration specified, continuous sound until noTone() called tone_nhw = 0; @@ -186,6 +186,7 @@ void tone(uint32_t pin, uint32_t freq, uint32_t duration) { pinMode(tone_pin, INPUT); } + while(tone_nhw) ; // blocks till duration elapsed } //////////////////////////////////////////////////////////////////////////////// From 2c33a0237134df4d5337fca38c17b9d1d74a4b8a Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Thu, 2 Nov 2017 17:50:34 +1100 Subject: [PATCH 191/351] Correct argument type bug in utoa (itoa.c itoa.h) See PR #271 --- STM32F1/cores/maple/itoa.c | 2 +- STM32F1/cores/maple/itoa.h | 2 +- STM32F4/cores/maple/itoa.c | 2 +- STM32F4/cores/maple/itoa.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/STM32F1/cores/maple/itoa.c b/STM32F1/cores/maple/itoa.c index ee74f82..33efd14 100644 --- a/STM32F1/cores/maple/itoa.c +++ b/STM32F1/cores/maple/itoa.c @@ -124,7 +124,7 @@ extern char* ltoa( long value, char *string, int radix ) (__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 ) +extern char* utoa( unsigned int 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 b88204c..9997b65 100644 --- a/STM32F1/cores/maple/itoa.h +++ b/STM32F1/cores/maple/itoa.h @@ -35,7 +35,7 @@ extern char* ltoa( long value, char *string, int radix ) ; (__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 ) ; +extern char* utoa( unsigned int 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 ee74f82..33efd14 100644 --- a/STM32F4/cores/maple/itoa.c +++ b/STM32F4/cores/maple/itoa.c @@ -124,7 +124,7 @@ extern char* ltoa( long value, char *string, int radix ) (__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 ) +extern char* utoa( unsigned int 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 a6e893d..a317e82 100644 --- a/STM32F4/cores/maple/itoa.h +++ b/STM32F4/cores/maple/itoa.h @@ -35,7 +35,7 @@ extern char* ltoa( long value, char *string, int radix ) ; (__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 ) ; +extern char* utoa( unsigned int value, char *string, int radix ) ; #endif extern char* ultoa( unsigned long value, char *string, int radix ) ; #endif /* 0 */ From 15ce8137b92f5b0cdb3c6e5ac51f02e52eb2c7a4 Mon Sep 17 00:00:00 2001 From: "aka. N[]NE in gaming communities" Date: Mon, 6 Nov 2017 08:55:32 -0500 Subject: [PATCH 192/351] Update BlinkNcount.ino Uses `#define` for LED pin instead of 5 literals --- .../General/BlinkNcount/BlinkNcount.ino | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/STM32F1/libraries/A_STM32_Examples/examples/General/BlinkNcount/BlinkNcount.ino b/STM32F1/libraries/A_STM32_Examples/examples/General/BlinkNcount/BlinkNcount.ino index 1b1f58a..b05ece9 100644 --- a/STM32F1/libraries/A_STM32_Examples/examples/General/BlinkNcount/BlinkNcount.ino +++ b/STM32F1/libraries/A_STM32_Examples/examples/General/BlinkNcount/BlinkNcount.ino @@ -1,35 +1,38 @@ /* - BlinkNcount for Maple Mini by m. ray burnette + BlinkNcount for Maple Mini by m. ray burnette, update by The Lightning Stalker to use #define Sketch uses 13,808 bytes (12%) of program storage space. Maximum is 108,000 bytes. Global variables use 2,592 bytes of dynamic memory. Turns on an LED on for one second, then off for one second, repeatedly. Counts and displays the count on the attached serial monitor This example code is in the public domain. - */ +*/ + +#define LED_PIN PB1 // Maple Mini LED is on PB1, other boards may vary + int n = 0; -void setup() { +void setup() { // initialize the digital pin as an output. - pinMode(33, OUTPUT); + pinMode(LED_PIN, OUTPUT); // Initialize virtual COM over USB on Maple Mini Serial.begin(9600); // BAUD has no effect on USB serial: placeholder for physical UART // wait for serial monitor to be connected. while (!Serial) { - digitalWrite(33,!digitalRead(33));// Turn the LED from off to on, or on to off + digitalWrite(LED_PIN, !digitalRead(LED_PIN)); // Turn the LED from off to on, or on to off delay(100); // fast blink } Serial.println("Blink LED & count Demo"); } void loop() { - digitalWrite(33, HIGH); // set the LED on + digitalWrite(LED_PIN, HIGH); // set the LED on delay(500); // wait for a second - digitalWrite(33, LOW); // set the LED off + digitalWrite(LED_PIN, LOW); // set the LED off Serial.print("Loop #: "); n++; Serial.println(n); - - delay(500); // wait + + delay(500); // wait } From 15d12bee18188a4276b83272bb6545713a3fc697 Mon Sep 17 00:00:00 2001 From: "aka. N[]NE in gaming communities" Date: Mon, 6 Nov 2017 19:00:41 -0500 Subject: [PATCH 193/351] Update BlinkNcount.c Changed pin to PC13 --- .../examples/General/BlinkNcount/BlinkNcount.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/libraries/A_STM32_Examples/examples/General/BlinkNcount/BlinkNcount.ino b/STM32F1/libraries/A_STM32_Examples/examples/General/BlinkNcount/BlinkNcount.ino index b05ece9..60a4c17 100644 --- a/STM32F1/libraries/A_STM32_Examples/examples/General/BlinkNcount/BlinkNcount.ino +++ b/STM32F1/libraries/A_STM32_Examples/examples/General/BlinkNcount/BlinkNcount.ino @@ -7,7 +7,7 @@ This example code is in the public domain. */ -#define LED_PIN PB1 // Maple Mini LED is on PB1, other boards may vary +#define LED_PIN PC13 // Maple Mini LED is on PB1, other boards may vary int n = 0; From c5ed88921ef7228bdd8decf9711e98536c3bd6a1 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Wed, 8 Nov 2017 15:29:25 +1100 Subject: [PATCH 194/351] Changed serial upload speed to 115200 as this speed is compatible with most USB to Serial adaptors --- tools/linux/serial_upload | 2 +- tools/linux64/serial_upload | 2 +- tools/macosx/serial_upload | 2 +- tools/win/serial_upload.bat | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/linux/serial_upload b/tools/linux/serial_upload index 05d17c6..755444a 100755 --- a/tools/linux/serial_upload +++ b/tools/linux/serial_upload @@ -1,2 +1,2 @@ #!/bin/bash -$(dirname $0)/stm32flash/stm32flash -g 0x8000000 -b 230400 -w "$4" /dev/"$1" +$(dirname $0)/stm32flash/stm32flash -g 0x8000000 -b 115200 -w "$4" /dev/"$1" diff --git a/tools/linux64/serial_upload b/tools/linux64/serial_upload index 05d17c6..755444a 100755 --- a/tools/linux64/serial_upload +++ b/tools/linux64/serial_upload @@ -1,2 +1,2 @@ #!/bin/bash -$(dirname $0)/stm32flash/stm32flash -g 0x8000000 -b 230400 -w "$4" /dev/"$1" +$(dirname $0)/stm32flash/stm32flash -g 0x8000000 -b 115200 -w "$4" /dev/"$1" diff --git a/tools/macosx/serial_upload b/tools/macosx/serial_upload index 05d17c6..755444a 100755 --- a/tools/macosx/serial_upload +++ b/tools/macosx/serial_upload @@ -1,2 +1,2 @@ #!/bin/bash -$(dirname $0)/stm32flash/stm32flash -g 0x8000000 -b 230400 -w "$4" /dev/"$1" +$(dirname $0)/stm32flash/stm32flash -g 0x8000000 -b 115200 -w "$4" /dev/"$1" diff --git a/tools/win/serial_upload.bat b/tools/win/serial_upload.bat index d733be7..4c50fb7 100644 --- a/tools/win/serial_upload.bat +++ b/tools/win/serial_upload.bat @@ -8,7 +8,7 @@ cd %~dp0 rem: the two line below are needed to fix path issues with incorrect slashes before the bin file name set str=%4 set str=%str:/=\% -stm32flash -g 0x8000000 -b 230400 -w %str% %1 +stm32flash -g 0x8000000 -b 115200 -w %str% %1 rem: C:\Python27\python.exe stm32loader.py -e -w -p %1 -g -b 115200 %str% rem: ------------- use STM's own uploader From fd00f020722d7f8e69a974d28f4b9de4c5d62fe4 Mon Sep 17 00:00:00 2001 From: LightningStalker Date: Fri, 10 Nov 2017 04:10:31 -0500 Subject: [PATCH 195/351] Update BlinkNcount.ino to use LED_BUILTIN --- .../examples/General/BlinkNcount/BlinkNcount.ino | 15 ++++++--------- STM32F1/variants/generic_stm32f103c/variant.h | 2 +- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/STM32F1/libraries/A_STM32_Examples/examples/General/BlinkNcount/BlinkNcount.ino b/STM32F1/libraries/A_STM32_Examples/examples/General/BlinkNcount/BlinkNcount.ino index 60a4c17..11f88f8 100644 --- a/STM32F1/libraries/A_STM32_Examples/examples/General/BlinkNcount/BlinkNcount.ino +++ b/STM32F1/libraries/A_STM32_Examples/examples/General/BlinkNcount/BlinkNcount.ino @@ -1,35 +1,32 @@ /* - BlinkNcount for Maple Mini by m. ray burnette, update by The Lightning Stalker to use #define + BlinkNcount for Maple Mini by m. ray burnette Sketch uses 13,808 bytes (12%) of program storage space. Maximum is 108,000 bytes. Global variables use 2,592 bytes of dynamic memory. Turns on an LED on for one second, then off for one second, repeatedly. Counts and displays the count on the attached serial monitor This example code is in the public domain. -*/ - -#define LED_PIN PC13 // Maple Mini LED is on PB1, other boards may vary - + */ int n = 0; void setup() { // initialize the digital pin as an output. - pinMode(LED_PIN, OUTPUT); + pinMode(LED_BUILTIN, OUTPUT); // Initialize virtual COM over USB on Maple Mini Serial.begin(9600); // BAUD has no effect on USB serial: placeholder for physical UART // wait for serial monitor to be connected. while (!Serial) { - digitalWrite(LED_PIN, !digitalRead(LED_PIN)); // Turn the LED from off to on, or on to off + digitalWrite(LED_BUILTIN,!digitalRead(LED_BUILTIN)); // Turn the LED from off to on, or on to off delay(100); // fast blink } Serial.println("Blink LED & count Demo"); } void loop() { - digitalWrite(LED_PIN, HIGH); // set the LED on + digitalWrite(LED_BUILTIN, HIGH); // set the LED on delay(500); // wait for a second - digitalWrite(LED_PIN, LOW); // set the LED off + digitalWrite(LED_BUILTIN, LOW); // set the LED off Serial.print("Loop #: "); n++; Serial.println(n); diff --git a/STM32F1/variants/generic_stm32f103c/variant.h b/STM32F1/variants/generic_stm32f103c/variant.h index 4a9cfcd..dc4b894 100644 --- a/STM32F1/variants/generic_stm32f103c/variant.h +++ b/STM32F1/variants/generic_stm32f103c/variant.h @@ -19,4 +19,4 @@ static const uint8_t SCK = BOARD_SPI1_SCK_PIN; #define LED_BUILTIN PC13 -#endif /* _VARIANT_ARDUINO_STM32_ */ \ No newline at end of file +#endif /* _VARIANT_ARDUINO_STM32_ */ From 9b4122ecaf999bd80c1ce6333d001883e44b4556 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Mon, 13 Nov 2017 11:56:13 +1100 Subject: [PATCH 196/351] Fixed exmple for HardTimerAsEncoder being in wrong location --- .../examples}/Sensors/HardTimerAsEncoder/HardTimerAsEncoder.ino | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {examples => STM32F1/libraries/A_STM32_Examples/examples}/Sensors/HardTimerAsEncoder/HardTimerAsEncoder.ino (100%) diff --git a/examples/Sensors/HardTimerAsEncoder/HardTimerAsEncoder.ino b/STM32F1/libraries/A_STM32_Examples/examples/Sensors/HardTimerAsEncoder/HardTimerAsEncoder.ino similarity index 100% rename from examples/Sensors/HardTimerAsEncoder/HardTimerAsEncoder.ino rename to STM32F1/libraries/A_STM32_Examples/examples/Sensors/HardTimerAsEncoder/HardTimerAsEncoder.ino From c5caa5d288ca6c4a08fb8fe7e2125e6988cd1065 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Mon, 13 Nov 2017 12:03:19 +1100 Subject: [PATCH 197/351] Fixed missing definition of digitalPinToInterrupt, by adding macro which simply uses the pin number - as it doesnt need to be mapped --- STM32F1/cores/maple/wirish.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/STM32F1/cores/maple/wirish.h b/STM32F1/cores/maple/wirish.h index 3ffee83..eb07c77 100644 --- a/STM32F1/cores/maple/wirish.h +++ b/STM32F1/cores/maple/wirish.h @@ -104,5 +104,7 @@ typedef unsigned int word; #define clockCyclesToMicroseconds(a) ( ((a) * 1000L) / (F_CPU / 1000L) ) #define microsecondsToClockCycles(a) ( (a) * (F_CPU / 1000000L) ) +#define digitalPinToInterrupt(pin) (pin) + #endif From c66ca2ae9c6429d50d2e73b5fbc9b7c41c1268e6 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Mon, 13 Nov 2017 12:55:05 +1100 Subject: [PATCH 198/351] Fixed #273 --- STM32F1/boards.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/STM32F1/boards.txt b/STM32F1/boards.txt index 10379ec..96d9493 100644 --- a/STM32F1/boards.txt +++ b/STM32F1/boards.txt @@ -299,7 +299,6 @@ nucleo_f103rb.build.core=maple nucleo_f103rb.build.ldscript=ld/jtag.ld nucleo_f103rb.build.variant=nucleo_f103rb nucleo_f103rb.build.variant_system_lib=libmaple.a -nucleo_f103rb.build.vect=VECT_TAB_FLASH nucleo_f103rb.build.density=STM32_MEDIUM_DENSITY nucleo_f103rb.build.error_led_port=GPIOB nucleo_f103rb.build.error_led_pin=1 From dfb5bd4c30f42fa9cf2a0aef6b7d2a50a594fa97 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Mon, 13 Nov 2017 13:02:27 +0100 Subject: [PATCH 199/351] Update timer.h - clear the IRQ flag before enabling the IRQ --- STM32F1/system/libmaple/include/libmaple/timer.h | 1 + 1 file changed, 1 insertion(+) diff --git a/STM32F1/system/libmaple/include/libmaple/timer.h b/STM32F1/system/libmaple/include/libmaple/timer.h index 28b6c95..2c83e5e 100644 --- a/STM32F1/system/libmaple/include/libmaple/timer.h +++ b/STM32F1/system/libmaple/include/libmaple/timer.h @@ -828,6 +828,7 @@ static inline void timer_dma_disable_req(timer_dev *dev, uint8 channel) { * @see timer_channel */ static inline void timer_enable_irq(timer_dev *dev, uint8 interrupt) { + *bb_perip(&(dev->regs).adv->SR, interrupt) = 0; // clear interrupt flag *bb_perip(&(dev->regs).adv->DIER, interrupt) = 1; } From 85f159b3a50bfe867c64ad78b6494f7a57150f5d Mon Sep 17 00:00:00 2001 From: stevstrong Date: Mon, 13 Nov 2017 13:06:52 +0100 Subject: [PATCH 200/351] Update boards.txt remove duplicated lines --- STM32F1/boards.txt | 7 ------- 1 file changed, 7 deletions(-) diff --git a/STM32F1/boards.txt b/STM32F1/boards.txt index 96d9493..49c1293 100644 --- a/STM32F1/boards.txt +++ b/STM32F1/boards.txt @@ -44,13 +44,6 @@ mapleMini.menu.cpu_speed.speed_72mhz.build.f_cpu=72000000L mapleMini.menu.cpu_speed.speed_48mhz=48Mhz (Slow - with USB) mapleMini.menu.cpu_speed.speed_48mhz.build.f_cpu=48000000L -#-- CPU Clock frequency -mapleMini.menu.cpu_speed.speed_72mhz=72Mhz (Normal) -mapleMini.menu.cpu_speed.speed_72mhz.build.f_cpu=72000000L - -mapleMini.menu.cpu_speed.speed_48mhz=48Mhz (Slow - with USB) -mapleMini.menu.cpu_speed.speed_48mhz.build.f_cpu=48000000L - mapleMini.menu.cpu_speed.speed_128mhz=Overclocked 128Mhz NO USB SERIAL. MANUAL RESET NEEDED TO UPLOAD mapleMini.menu.cpu_speed.speed_128mhz.build.f_cpu=128000000L From 9b03f0841d35bdb848701f684c8a85a92dec24e5 Mon Sep 17 00:00:00 2001 From: Alberto Alonso Date: Mon, 13 Nov 2017 12:15:07 -0600 Subject: [PATCH 201/351] Solve race condition with arduino IDE monitoring serial port I encountered a race condition upon which, even though the udev rules were working and uploads succeed, the serial monitor can not re-establish communications. If the serial monitor is left open when doing an upload the error shown is: [...] Copying data from PC to DFU device Starting download: [##################################################] finished! state(8) = dfuMANIFEST-WAIT-RESET, status(0) = No error condition is present Done! Resetting USB to switch back to runtime mode Waiting for /dev/ttyACM0 serial...Done processing.app.SerialException: Error opening serial port '/dev/ttyACM0'. Try consulting the documentation at http://playground.arduino.cc/Linux/All#Permission at processing.app.Serial.(Serial.java:145) at processing.app.Serial.(Serial.java:82) at processing.app.SerialMonitor$4.(SerialMonitor.java:101) at processing.app.SerialMonitor.open(SerialMonitor.java:101) at processing.app.AbstractMonitor.resume(AbstractMonitor.java:104) at processing.app.Editor.resumeOrCloseSerialMonitor(Editor.java:2218) at processing.app.Editor.access$2200(Editor.java:79) at processing.app.Editor$DefaultExportHandler.run(Editor.java:2196) at java.lang.Thread.run(Thread.java:748) Error opening serial port '/dev/ttyACM0'. Try consulting the documentation at http://playground.arduino.cc/Linux/All#Permission I traced it to the device being opened prior to the permissions/ownership changes. When testing via -c the upload script waits for the character device creation, but at that point the udev rules have not changed the permissions. By testing the readability of the device via the -r test, we wait until the new permissions have been applied. I imagine this is specific to the Linux kernel and the speed of the machine being used. In my case: arduino-1.8.5 Linux 4.4.0-98-generic #121-Ubuntu SMP but the change should work on any system with proper udev rules / permissions. --- tools/linux/maple_upload | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/linux/maple_upload b/tools/linux/maple_upload index 1953174..50d2ae5 100755 --- a/tools/linux/maple_upload +++ b/tools/linux/maple_upload @@ -42,7 +42,7 @@ fi echo -n Waiting for ${dummy_port_fullpath} serial... COUNTER=0 -while [ ! -c ${dummy_port_fullpath} ] && ((COUNTER++ < 40)); do +while [ ! -r ${dummy_port_fullpath} ] && ((COUNTER++ < 40)); do sleep 0.1 done From 908a57a28e3e193e9f6070911e6b69b533ce716f Mon Sep 17 00:00:00 2001 From: lacklustrlabs Date: Wed, 15 Nov 2017 22:56:00 +0100 Subject: [PATCH 202/351] Suppressing 'warning: missing initializer for member ... [-Wmissing-field-initializers]' --- STM32F1/variants/STM32VLD/board.cpp | 4 +++- STM32F1/variants/generic_gd32f103c/board.cpp | 6 +++--- STM32F1/variants/generic_stm32f103c/board.cpp | 7 +++---- STM32F1/variants/generic_stm32f103r/board.cpp | 4 +++- STM32F1/variants/generic_stm32f103r8/board.cpp | 4 +++- STM32F1/variants/generic_stm32f103t/board.cpp | 4 +++- STM32F1/variants/generic_stm32f103v/board.cpp | 6 ++++-- STM32F1/variants/generic_stm32f103z/board.cpp | 5 ++++- STM32F1/variants/hytiny_stm32f103t/board.cpp | 4 +++- STM32F1/variants/maple/board.cpp | 3 +++ STM32F1/variants/maple_mini/board.cpp | 5 ++++- STM32F1/variants/maple_ret6/board.cpp | 5 ++++- STM32F1/variants/microduino/board.cpp | 3 +++ STM32F1/variants/nucleo_f103rb/board.cpp | 5 ++++- 14 files changed, 47 insertions(+), 18 deletions(-) diff --git a/STM32F1/variants/STM32VLD/board.cpp b/STM32F1/variants/STM32VLD/board.cpp index 1cecbd9..2561814 100644 --- a/STM32F1/variants/STM32VLD/board.cpp +++ b/STM32F1/variants/STM32VLD/board.cpp @@ -51,7 +51,8 @@ void boardInit(void) { } // Note. See the enum of pin names in board.h - +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { @@ -113,6 +114,7 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { {&gpiod, NULL, NULL, 1, 0, ADCx}, /* PD2 */ {&gpiod, NULL, NULL, 2, 0, ADCx}, /* PD2 */ }; +#pragma GCC diagnostic pop extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { PA0, PA1, PA2, PA3, PA6, PA7, PA8, PA9, PA10, PB0, PB1, PB6, PB7, PB8, PB9 diff --git a/STM32F1/variants/generic_gd32f103c/board.cpp b/STM32F1/variants/generic_gd32f103c/board.cpp index 8b136f2..54f60be 100644 --- a/STM32F1/variants/generic_gd32f103c/board.cpp +++ b/STM32F1/variants/generic_gd32f103c/board.cpp @@ -51,7 +51,8 @@ void boardInit(void) { } // Note. See the enum of pin names in board.h - +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { @@ -93,9 +94,8 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { {&gpioc, NULL, NULL, 14, 0, ADCx}, /* PC14 */ {&gpioc, NULL, NULL, 15, 0, ADCx}, /* PC15 */ - - }; +#pragma GCC diagnostic pop extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { PB0, PA7, PA6, PA3, PA2, PA1, PA0, PB7, PB6, PA10, PA9, PA8 diff --git a/STM32F1/variants/generic_stm32f103c/board.cpp b/STM32F1/variants/generic_stm32f103c/board.cpp index 7102adb..ac786cf 100644 --- a/STM32F1/variants/generic_stm32f103c/board.cpp +++ b/STM32F1/variants/generic_stm32f103c/board.cpp @@ -51,7 +51,8 @@ void boardInit(void) { } // Note. See the enum of pin names in board.h - +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { @@ -92,10 +93,8 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { {&gpioc, NULL, NULL, 13, 0, ADCx}, /* PC13 */ {&gpioc, NULL, NULL, 14, 0, ADCx}, /* PC14 */ {&gpioc, NULL, NULL, 15, 0, ADCx}, /* PC15 */ - - - }; +#pragma GCC diagnostic pop extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { PB0, PA7, PA6, PA3, PA2, PA1, PA0, PB7, PB6, PA10, PA9, PA8 diff --git a/STM32F1/variants/generic_stm32f103r/board.cpp b/STM32F1/variants/generic_stm32f103r/board.cpp index 3e3589c..e50314e 100644 --- a/STM32F1/variants/generic_stm32f103r/board.cpp +++ b/STM32F1/variants/generic_stm32f103r/board.cpp @@ -69,7 +69,8 @@ void boardInit(void) { // - Timer channel (1 to 4, for PWM), or 0 if none // - ADC device, or NULL if none // - ADC channel, or ADCx if none - +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { /* gpio_dev *gpio_device; GPIO device @@ -137,6 +138,7 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { {&gpiod, NULL, NULL, 1, 0, ADCx} , /* PD1 OSC_OUT */ {&gpiod, NULL, NULL, 2, 0, ADCx} , /* PD2 TIM3_ETR/UART5_RX SDIO_CMD */ }; +#pragma GCC diagnostic pop /* Basically everything that is defined as having a timer us PWM */ extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { diff --git a/STM32F1/variants/generic_stm32f103r8/board.cpp b/STM32F1/variants/generic_stm32f103r8/board.cpp index 05f85a5..1987651 100644 --- a/STM32F1/variants/generic_stm32f103r8/board.cpp +++ b/STM32F1/variants/generic_stm32f103r8/board.cpp @@ -51,7 +51,8 @@ void boardInit(void) { } // Note. See the enum of pin names in board.h - +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { @@ -111,6 +112,7 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { {&gpiod, NULL, NULL, 2, 0, ADCx}, /* PD2 */ }; +#pragma GCC diagnostic pop extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { PB0, PA7, PA6, PA3, PA2, PA1, PA0, PB7, PB6, PA10, PA9, PA8, PC6, PC7, PC8, PC9 diff --git a/STM32F1/variants/generic_stm32f103t/board.cpp b/STM32F1/variants/generic_stm32f103t/board.cpp index e7a1dc0..003d225 100644 --- a/STM32F1/variants/generic_stm32f103t/board.cpp +++ b/STM32F1/variants/generic_stm32f103t/board.cpp @@ -51,7 +51,8 @@ void boardInit(void) { } // Note. See the enum of pin names in board.h - +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { @@ -81,6 +82,7 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { {&gpiob, &timer4, NULL, 6, 1, ADCx}, /* PB6 */ {&gpiob, &timer4, NULL, 7, 2, ADCx}, /* PB7 */ }; +#pragma GCC diagnostic pop extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { PB0, PA7, PA6, PA3, PA2, PA1, PA0, PB7, PB6, PA10, PA9, PA8 diff --git a/STM32F1/variants/generic_stm32f103v/board.cpp b/STM32F1/variants/generic_stm32f103v/board.cpp index 9c13772..8b24169 100644 --- a/STM32F1/variants/generic_stm32f103v/board.cpp +++ b/STM32F1/variants/generic_stm32f103v/board.cpp @@ -68,7 +68,8 @@ void boardInit(void) { // - Timer channel (1 to 4, for PWM), or 0 if none // - ADC device, or NULL if none // - ADC channel, or ADCx if none - +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { /* gpio_dev *gpio_device; GPIO device @@ -166,6 +167,7 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { {&gpioe, NULL, NULL, 15, 0, ADCx} , /* PE15 FSMC_D12 */ }; +#pragma GCC diagnostic pop /* Basically everything that is defined as having a timer us PWM */ extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { @@ -196,4 +198,4 @@ extern const uint8 boardUsedPins[BOARD_NR_USED_PINS] __FLASH__ = { DEFINE_HWSERIAL(Serial2, 3); DEFINE_HWSERIAL_UART(Serial3, 4); DEFINE_HWSERIAL_UART(Serial4, 5); -#endif \ No newline at end of file +#endif diff --git a/STM32F1/variants/generic_stm32f103z/board.cpp b/STM32F1/variants/generic_stm32f103z/board.cpp index 830479e..4d2e4e9 100644 --- a/STM32F1/variants/generic_stm32f103z/board.cpp +++ b/STM32F1/variants/generic_stm32f103z/board.cpp @@ -69,6 +69,8 @@ void boardInit(void) { // - ADC device, or NULL if none // - ADC channel, or ADCx if none +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { /* gpio_dev *gpio_device; GPIO device @@ -201,6 +203,7 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { {&gpiog, NULL, NULL, 14, 0, ADCx} , /* PG14 */ {&gpiog, NULL, NULL, 15, 0, ADCx} /* PG15 */ }; +#pragma GCC diagnostic pop /* Basically everything that is defined as having a timer us PWM */ extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { @@ -231,4 +234,4 @@ extern const uint8 boardUsedPins[BOARD_NR_USED_PINS] __FLASH__ = { DEFINE_HWSERIAL(Serial2, 3); DEFINE_HWSERIAL_UART(Serial3, 4); DEFINE_HWSERIAL_UART(Serial4, 5); -#endif \ No newline at end of file +#endif diff --git a/STM32F1/variants/hytiny_stm32f103t/board.cpp b/STM32F1/variants/hytiny_stm32f103t/board.cpp index f1fb44f..d1260a6 100644 --- a/STM32F1/variants/hytiny_stm32f103t/board.cpp +++ b/STM32F1/variants/hytiny_stm32f103t/board.cpp @@ -51,7 +51,8 @@ void boardInit(void) { } // Note. See the enum of pin names in board.h - +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { @@ -82,6 +83,7 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { {&gpiob, &timer4, NULL, 7, 2, ADCx}, /* PB7 */ }; +#pragma GCC diagnostic pop extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { PB0, PA7, PA6, PA3, PA2, PA1, PA0, PB7, PB6, PA10, PA9, PA8 diff --git a/STM32F1/variants/maple/board.cpp b/STM32F1/variants/maple/board.cpp index a4c0335..b1584e7 100644 --- a/STM32F1/variants/maple/board.cpp +++ b/STM32F1/variants/maple/board.cpp @@ -68,6 +68,8 @@ void boardInit(void) { // - Timer channel (1 to 4, for PWM), or 0 if none // - ADC device, or NULL if none // - ADC channel, or ADCx if none +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { /* Top header */ @@ -126,6 +128,7 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { PMAP_ROW(&gpiob, 3, NULL, 0, NULL, ADCx), /* D42/PB3 */ PMAP_ROW(&gpiob, 4, NULL, 0, NULL, ADCx), /* D43/PB4 */ }; +#pragma GCC diagnostic pop // Array of pins you can use for pwmWrite(). Keep it in Flash because // it doesn't change, and so we don't waste RAM. diff --git a/STM32F1/variants/maple_mini/board.cpp b/STM32F1/variants/maple_mini/board.cpp index f49b336..bf63364 100644 --- a/STM32F1/variants/maple_mini/board.cpp +++ b/STM32F1/variants/maple_mini/board.cpp @@ -50,6 +50,8 @@ void boardInit(void) { #endif } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { /* Top header */ @@ -92,6 +94,7 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { {&gpiob, &timer4, NULL, 8, 3, ADCx}, /* D32/PB8 */ {&gpiob, &timer3, &adc1, 1, 4, 9}, /* D33/PB1 */ }; +#pragma GCC diagnostic pop extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { 3, 4, 5, 8, 9, 10, 11, 15, 16, 25, 26, 27 @@ -125,4 +128,4 @@ DEFINE_HWSERIAL(Serial1, 1); DEFINE_HWSERIAL(Serial2, 2); DEFINE_HWSERIAL(Serial3, 3); - \ No newline at end of file + diff --git a/STM32F1/variants/maple_ret6/board.cpp b/STM32F1/variants/maple_ret6/board.cpp index fb92779..dfec977 100644 --- a/STM32F1/variants/maple_ret6/board.cpp +++ b/STM32F1/variants/maple_ret6/board.cpp @@ -69,6 +69,8 @@ void boardInit(void) { // - ADC device, or NULL if none // - ADC channel, or ADCx if none +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { /* gpio_dev *gpio_device; GPIO device @@ -143,6 +145,7 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { { &gpiod, NULL, NULL, 1, 0, ADCx }, /* PD1 OSC_OUT */ { &gpiob, NULL, NULL, 2, 0, ADCx }, /* PB2 */ }; +#pragma GCC diagnostic pop /* Basically everything that is defined as having a timer us PWM */ extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { @@ -175,4 +178,4 @@ DEFINE_HWSERIAL(Serial1, 1); DEFINE_HWSERIAL(Serial2, 2); DEFINE_HWSERIAL(Serial3, 3); DEFINE_HWSERIAL_UART(Serial4, 4); -DEFINE_HWSERIAL_UART(Serial5, 5); \ No newline at end of file +DEFINE_HWSERIAL_UART(Serial5, 5); diff --git a/STM32F1/variants/microduino/board.cpp b/STM32F1/variants/microduino/board.cpp index 2a00288..d7b4a97 100644 --- a/STM32F1/variants/microduino/board.cpp +++ b/STM32F1/variants/microduino/board.cpp @@ -51,6 +51,8 @@ void boardInit(void) { #endif } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { @@ -84,6 +86,7 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { // FIXME: find out which pin is the button, if any {&gpiob, NULL, NULL, 8, 0, ADCx}, /* D24/PB8??/Button */ }; +#pragma GCC diagnostic pop extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { 0, 1, 4, 11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 23 diff --git a/STM32F1/variants/nucleo_f103rb/board.cpp b/STM32F1/variants/nucleo_f103rb/board.cpp index 9f3e08a..9754a2d 100644 --- a/STM32F1/variants/nucleo_f103rb/board.cpp +++ b/STM32F1/variants/nucleo_f103rb/board.cpp @@ -93,6 +93,8 @@ rcc_pll_cfg w_board_pll_cfg = {RCC_PLLSRC_HSI_DIV_2, &pll_data}; // 0 1 3 4 2 5 // 0 1 2 4 2 5 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { /* Arduino-like header, right connectors */ @@ -149,6 +151,7 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { // PMAP_ROW(&gpioa, 14, NULL, 0, NULL, ADCx), /* D42/PA14 do not use*/ // PMAP_ROW(&gpioa, 15, &timer2, 1, NULL, ADCx), /* D43/PA15 do not use*/ }; +#pragma GCC diagnostic pop // Array of pins you can use for pwmWrite(). Keep it in Flash because // it doesn't change, and so we don't waste RAM. @@ -256,4 +259,4 @@ MOSI alternate functions on the GPIO ports. DEFINE_HWSERIAL(Serial, 3);// Use HW Serial 2 as "Serial" DEFINE_HWSERIAL(Serial1, 2); DEFINE_HWSERIAL(Serial2, 1); -#endif \ No newline at end of file +#endif From 8d9e2f24b6cde18363f113c70dc4fdae06941599 Mon Sep 17 00:00:00 2001 From: lacklustrlabs Date: Wed, 15 Nov 2017 23:19:31 +0100 Subject: [PATCH 203/351] Suppressing 'warning: unused parameter ... [-Wunused-parameter]' --- STM32F1/cores/maple/libmaple/adc_f1.c | 2 +- STM32F1/cores/maple/libmaple/spi_f1.c | 2 +- STM32F1/cores/maple/libmaple/timer.c | 2 +- STM32F1/cores/maple/libmaple/util.c | 2 +- .../cores/maple/stm32f1/wiring_pulse_f1.cpp | 2 +- STM32F1/cores/maple/usb_serial.cpp | 4 ++-- STM32F1/libraries/Wire/WireBase.cpp | 2 +- .../libmaple/stm32f1/include/series/i2c.h | 2 +- STM32F1/variants/STM32VLD/wirish/syscalls.c | 22 +++++++++---------- .../generic_gd32f103c/wirish/syscalls.c | 18 +++++++-------- .../generic_stm32f103c/wirish/syscalls.c | 22 +++++++++---------- .../generic_stm32f103r8/wirish/syscalls.c | 22 +++++++++---------- .../generic_stm32f103t/wirish/syscalls.c | 22 +++++++++---------- .../generic_stm32f103v/wirish/syscalls.c | 22 +++++++++---------- .../generic_stm32f103z/wirish/syscalls.c | 22 +++++++++---------- .../hytiny_stm32f103t/wirish/syscalls.c | 22 +++++++++---------- STM32F1/variants/maple/wirish/syscalls.c | 22 +++++++++---------- STM32F1/variants/maple_mini/wirish/syscalls.c | 22 +++++++++---------- STM32F1/variants/maple_ret6/wirish/syscalls.c | 22 +++++++++---------- STM32F1/variants/microduino/wirish/syscalls.c | 22 +++++++++---------- .../variants/nucleo_f103rb/wirish/syscalls.c | 22 +++++++++---------- 21 files changed, 150 insertions(+), 150 deletions(-) diff --git a/STM32F1/cores/maple/libmaple/adc_f1.c b/STM32F1/cores/maple/libmaple/adc_f1.c index d099f6d..5305b02 100644 --- a/STM32F1/cores/maple/libmaple/adc_f1.c +++ b/STM32F1/cores/maple/libmaple/adc_f1.c @@ -203,7 +203,7 @@ void adc_foreach(void (*fn)(adc_dev*)) { #endif } -void adc_config_gpio(adc_dev *ignored, gpio_dev *gdev, uint8 bit) { +void adc_config_gpio(adc_dev *ignored __attribute__((unused)), gpio_dev *gdev, uint8 bit) { gpio_set_mode(gdev, bit, GPIO_INPUT_ANALOG); } diff --git a/STM32F1/cores/maple/libmaple/spi_f1.c b/STM32F1/cores/maple/libmaple/spi_f1.c index bbea5a4..d920761 100644 --- a/STM32F1/cores/maple/libmaple/spi_f1.c +++ b/STM32F1/cores/maple/libmaple/spi_f1.c @@ -54,7 +54,7 @@ spi_dev *SPI3 = &spi3; * Routines */ -void spi_config_gpios(spi_dev *ignored, +void spi_config_gpios(spi_dev *ignored __attribute__((unused)), uint8 as_master, gpio_dev *nss_dev, uint8 nss_bit, diff --git a/STM32F1/cores/maple/libmaple/timer.c b/STM32F1/cores/maple/libmaple/timer.c index daf8e43..70e2065 100644 --- a/STM32F1/cores/maple/libmaple/timer.c +++ b/STM32F1/cores/maple/libmaple/timer.c @@ -327,7 +327,7 @@ static void output_compare_mode(timer_dev *dev, uint8 channel) { } //added by CARLOS. -static void encoder_mode(timer_dev *dev, uint8 channel) { +static void encoder_mode(timer_dev *dev, uint8 channel __attribute__((unused))) { //prescaler. //(dev->regs).gen->PSC = 1; diff --git a/STM32F1/cores/maple/libmaple/util.c b/STM32F1/cores/maple/libmaple/util.c index 4c0b2c8..f488ea4 100644 --- a/STM32F1/cores/maple/libmaple/util.c +++ b/STM32F1/cores/maple/libmaple/util.c @@ -88,7 +88,7 @@ void _fail(const char* file, int line, const char* exp) { * Provide an __assert_func handler to libc so that calls to assert() * get redirected to _fail. */ -void __assert_func(const char* file, int line, const char* method, +void __assert_func(const char* file, int line, const char* method __attribute__((unused)), const char* expression) { _fail(file, line, expression); } diff --git a/STM32F1/cores/maple/stm32f1/wiring_pulse_f1.cpp b/STM32F1/cores/maple/stm32f1/wiring_pulse_f1.cpp index 9ca4d7f..d9287b0 100644 --- a/STM32F1/cores/maple/stm32f1/wiring_pulse_f1.cpp +++ b/STM32F1/cores/maple/stm32f1/wiring_pulse_f1.cpp @@ -26,7 +26,7 @@ * to be slighly more accurate the maxLoops variable really needs to take into account the loop setup code, but its probably as good as necessary * */ -uint32_t pulseIn( uint32_t pin, uint32_t state, uint32_t timeout ) +uint32_t pulseIn( uint32_t pin, uint32_t state __attribute__((unused)), uint32_t timeout ) { // cache the port and bit of the pin in order to speed up the // pulse width measuring loop and achieve finer resolution. calling diff --git a/STM32F1/cores/maple/usb_serial.cpp b/STM32F1/cores/maple/usb_serial.cpp index 0902c50..e6d5cb0 100644 --- a/STM32F1/cores/maple/usb_serial.cpp +++ b/STM32F1/cores/maple/usb_serial.cpp @@ -236,7 +236,7 @@ enum reset_state_t { static reset_state_t reset_state = DTR_UNSET; -static void ifaceSetupHook(unsigned hook, void *requestvp) { +static void ifaceSetupHook(unsigned hook __attribute__((unused)), void *requestvp) { uint8 request = *(uint8*)requestvp; // Ignore requests we're not interested in. @@ -290,7 +290,7 @@ static void wait_reset(void) { #define STACK_TOP 0x20000800 #define EXC_RETURN 0xFFFFFFF9 #define DEFAULT_CPSR 0x61000000 -static void rxHook(unsigned hook, void *ignored) { +static void rxHook(unsigned hook __attribute__((unused)), void *ignored __attribute__((unused))) { /* FIXME this is mad buggy; we need a new reset sequence. E.g. NAK * after each RX means you can't reset if any bytes are waiting. */ if (reset_state == DTR_NEGEDGE) { diff --git a/STM32F1/libraries/Wire/WireBase.cpp b/STM32F1/libraries/Wire/WireBase.cpp index 220d845..eaa7f91 100644 --- a/STM32F1/libraries/Wire/WireBase.cpp +++ b/STM32F1/libraries/Wire/WireBase.cpp @@ -41,7 +41,7 @@ #include "WireBase.h" #include "wirish.h" -void WireBase::begin(uint8 self_addr) { +void WireBase::begin(uint8 self_addr __attribute__((unused))) { tx_buf_idx = 0; tx_buf_overflow = false; rx_buf_idx = 0; diff --git a/STM32F1/system/libmaple/stm32f1/include/series/i2c.h b/STM32F1/system/libmaple/stm32f1/include/series/i2c.h index f407955..3565503 100644 --- a/STM32F1/system/libmaple/stm32f1/include/series/i2c.h +++ b/STM32F1/system/libmaple/stm32f1/include/series/i2c.h @@ -59,7 +59,7 @@ extern i2c_dev* const I2C2; * For internal use */ -static inline uint32 _i2c_bus_clk(i2c_dev *dev) { +static inline uint32 _i2c_bus_clk(i2c_dev *dev __attribute__((unused))) { /* Both I2C peripherals are on APB1 */ return STM32_PCLK1 / (1000 * 1000); } diff --git a/STM32F1/variants/STM32VLD/wirish/syscalls.c b/STM32F1/variants/STM32VLD/wirish/syscalls.c index d42536c..91ed5a1 100644 --- a/STM32F1/variants/STM32VLD/wirish/syscalls.c +++ b/STM32F1/variants/STM32VLD/wirish/syscalls.c @@ -76,28 +76,28 @@ void *_sbrk(int incr) { return ret; } -__weak int _open(const char *path, int flags, ...) { +__weak int _open(const char *path __attribute__((unused)), int flags __attribute__((unused)), ...) { return 1; } -__weak int _close(int fd) { +__weak int _close(int fd __attribute__((unused))) { return 0; } -__weak int _fstat(int fd, struct stat *st) { +__weak int _fstat(int fd __attribute__((unused)), struct stat *st) { st->st_mode = S_IFCHR; return 0; } -__weak int _isatty(int fd) { +__weak int _isatty(int fd __attribute__((unused))) { return 1; } -__weak int isatty(int fd) { +__weak int isatty(int fd __attribute__((unused))) { return 1; } -__weak int _lseek(int fd, off_t pos, int whence) { +__weak int _lseek(int fd __attribute__((unused)), off_t pos __attribute__((unused)), int whence __attribute__((unused))) { return -1; } @@ -106,13 +106,13 @@ __weak unsigned char getch(void) { } -__weak int _read(int fd, char *buf, size_t cnt) { +__weak int _read(int fd __attribute__((unused)), char *buf, size_t cnt __attribute__((unused))) { *buf = getch(); return 1; } -__weak void putch(unsigned char c) { +__weak void putch(unsigned char c __attribute__((unused))) { } __weak void cgets(char *s, int bufsize) { @@ -155,7 +155,7 @@ __weak void cgets(char *s, int bufsize) { return; } -__weak int _write(int fd, const char *buf, size_t cnt) { +__weak int _write(int fd __attribute__((unused)), const char *buf, size_t cnt) { int i; for (i = 0; i < cnt; i++) @@ -165,12 +165,12 @@ __weak int _write(int fd, const char *buf, size_t cnt) { } /* Override fgets() in newlib with a version that does line editing */ -__weak char *fgets(char *s, int bufsize, void *f) { +__weak char *fgets(char *s, int bufsize, void *f __attribute__((unused))) { cgets(s, bufsize); return s; } -__weak void _exit(int exitcode) { +__weak void _exit(int exitcode __attribute__((unused))) { while (1) ; } diff --git a/STM32F1/variants/generic_gd32f103c/wirish/syscalls.c b/STM32F1/variants/generic_gd32f103c/wirish/syscalls.c index d5f2d9f..6558dbd 100644 --- a/STM32F1/variants/generic_gd32f103c/wirish/syscalls.c +++ b/STM32F1/variants/generic_gd32f103c/wirish/syscalls.c @@ -76,15 +76,15 @@ void *_sbrk(int incr) { return ret; } -__weak int _open(const char *path, int flags, ...) { +__weak int _open(const char *path __attribute__((unused)), int flags __attribute__((unused)), ...) { return 1; } -__weak int _close(int fd) { +__weak int _close(int fd __attribute__((unused))) { return 0; } -__weak int _fstat(int fd, struct stat *st) { +__weak int _fstat(int fd __attribute__((unused)), struct stat *st) { st->st_mode = S_IFCHR; return 0; } @@ -97,7 +97,7 @@ __weak int isatty(int fd) { return 1; } -__weak int _lseek(int fd, off_t pos, int whence) { +__weak int _lseek(int fd __attribute__((unused)), off_t pos __attribute__((unused)), int whence __attribute__((unused))) { return -1; } @@ -106,13 +106,13 @@ __weak unsigned char getch(void) { } -__weak int _read(int fd, char *buf, size_t cnt) { +__weak int _read(int fd __attribute__((unused)), char *buf, size_t cnt __attribute__((unused))) { *buf = getch(); return 1; } -__weak void putch(unsigned char c) { +__weak void putch(unsigned char c __attribute__((unused))) { } __weak void cgets(char *s, int bufsize) { @@ -155,7 +155,7 @@ __weak void cgets(char *s, int bufsize) { return; } -__weak int _write(int fd, const char *buf, size_t cnt) { +__weak int _write(int fd __attribute__((unused)), const char *buf, size_t cnt) { int i; for (i = 0; i < cnt; i++) @@ -165,12 +165,12 @@ __weak int _write(int fd, const char *buf, size_t cnt) { } /* Override fgets() in newlib with a version that does line editing */ -__weak char *fgets(char *s, int bufsize, void *f) { +__weak char *fgets(char *s, int bufsize, void *f __attribute__((unused))) { cgets(s, bufsize); return s; } -__weak void _exit(int exitcode) { +__weak void _exit(int exitcode __attribute__((unused))) { while (1) ; } diff --git a/STM32F1/variants/generic_stm32f103c/wirish/syscalls.c b/STM32F1/variants/generic_stm32f103c/wirish/syscalls.c index d42536c..91ed5a1 100644 --- a/STM32F1/variants/generic_stm32f103c/wirish/syscalls.c +++ b/STM32F1/variants/generic_stm32f103c/wirish/syscalls.c @@ -76,28 +76,28 @@ void *_sbrk(int incr) { return ret; } -__weak int _open(const char *path, int flags, ...) { +__weak int _open(const char *path __attribute__((unused)), int flags __attribute__((unused)), ...) { return 1; } -__weak int _close(int fd) { +__weak int _close(int fd __attribute__((unused))) { return 0; } -__weak int _fstat(int fd, struct stat *st) { +__weak int _fstat(int fd __attribute__((unused)), struct stat *st) { st->st_mode = S_IFCHR; return 0; } -__weak int _isatty(int fd) { +__weak int _isatty(int fd __attribute__((unused))) { return 1; } -__weak int isatty(int fd) { +__weak int isatty(int fd __attribute__((unused))) { return 1; } -__weak int _lseek(int fd, off_t pos, int whence) { +__weak int _lseek(int fd __attribute__((unused)), off_t pos __attribute__((unused)), int whence __attribute__((unused))) { return -1; } @@ -106,13 +106,13 @@ __weak unsigned char getch(void) { } -__weak int _read(int fd, char *buf, size_t cnt) { +__weak int _read(int fd __attribute__((unused)), char *buf, size_t cnt __attribute__((unused))) { *buf = getch(); return 1; } -__weak void putch(unsigned char c) { +__weak void putch(unsigned char c __attribute__((unused))) { } __weak void cgets(char *s, int bufsize) { @@ -155,7 +155,7 @@ __weak void cgets(char *s, int bufsize) { return; } -__weak int _write(int fd, const char *buf, size_t cnt) { +__weak int _write(int fd __attribute__((unused)), const char *buf, size_t cnt) { int i; for (i = 0; i < cnt; i++) @@ -165,12 +165,12 @@ __weak int _write(int fd, const char *buf, size_t cnt) { } /* Override fgets() in newlib with a version that does line editing */ -__weak char *fgets(char *s, int bufsize, void *f) { +__weak char *fgets(char *s, int bufsize, void *f __attribute__((unused))) { cgets(s, bufsize); return s; } -__weak void _exit(int exitcode) { +__weak void _exit(int exitcode __attribute__((unused))) { while (1) ; } diff --git a/STM32F1/variants/generic_stm32f103r8/wirish/syscalls.c b/STM32F1/variants/generic_stm32f103r8/wirish/syscalls.c index d42536c..91ed5a1 100644 --- a/STM32F1/variants/generic_stm32f103r8/wirish/syscalls.c +++ b/STM32F1/variants/generic_stm32f103r8/wirish/syscalls.c @@ -76,28 +76,28 @@ void *_sbrk(int incr) { return ret; } -__weak int _open(const char *path, int flags, ...) { +__weak int _open(const char *path __attribute__((unused)), int flags __attribute__((unused)), ...) { return 1; } -__weak int _close(int fd) { +__weak int _close(int fd __attribute__((unused))) { return 0; } -__weak int _fstat(int fd, struct stat *st) { +__weak int _fstat(int fd __attribute__((unused)), struct stat *st) { st->st_mode = S_IFCHR; return 0; } -__weak int _isatty(int fd) { +__weak int _isatty(int fd __attribute__((unused))) { return 1; } -__weak int isatty(int fd) { +__weak int isatty(int fd __attribute__((unused))) { return 1; } -__weak int _lseek(int fd, off_t pos, int whence) { +__weak int _lseek(int fd __attribute__((unused)), off_t pos __attribute__((unused)), int whence __attribute__((unused))) { return -1; } @@ -106,13 +106,13 @@ __weak unsigned char getch(void) { } -__weak int _read(int fd, char *buf, size_t cnt) { +__weak int _read(int fd __attribute__((unused)), char *buf, size_t cnt __attribute__((unused))) { *buf = getch(); return 1; } -__weak void putch(unsigned char c) { +__weak void putch(unsigned char c __attribute__((unused))) { } __weak void cgets(char *s, int bufsize) { @@ -155,7 +155,7 @@ __weak void cgets(char *s, int bufsize) { return; } -__weak int _write(int fd, const char *buf, size_t cnt) { +__weak int _write(int fd __attribute__((unused)), const char *buf, size_t cnt) { int i; for (i = 0; i < cnt; i++) @@ -165,12 +165,12 @@ __weak int _write(int fd, const char *buf, size_t cnt) { } /* Override fgets() in newlib with a version that does line editing */ -__weak char *fgets(char *s, int bufsize, void *f) { +__weak char *fgets(char *s, int bufsize, void *f __attribute__((unused))) { cgets(s, bufsize); return s; } -__weak void _exit(int exitcode) { +__weak void _exit(int exitcode __attribute__((unused))) { while (1) ; } diff --git a/STM32F1/variants/generic_stm32f103t/wirish/syscalls.c b/STM32F1/variants/generic_stm32f103t/wirish/syscalls.c index d42536c..91ed5a1 100644 --- a/STM32F1/variants/generic_stm32f103t/wirish/syscalls.c +++ b/STM32F1/variants/generic_stm32f103t/wirish/syscalls.c @@ -76,28 +76,28 @@ void *_sbrk(int incr) { return ret; } -__weak int _open(const char *path, int flags, ...) { +__weak int _open(const char *path __attribute__((unused)), int flags __attribute__((unused)), ...) { return 1; } -__weak int _close(int fd) { +__weak int _close(int fd __attribute__((unused))) { return 0; } -__weak int _fstat(int fd, struct stat *st) { +__weak int _fstat(int fd __attribute__((unused)), struct stat *st) { st->st_mode = S_IFCHR; return 0; } -__weak int _isatty(int fd) { +__weak int _isatty(int fd __attribute__((unused))) { return 1; } -__weak int isatty(int fd) { +__weak int isatty(int fd __attribute__((unused))) { return 1; } -__weak int _lseek(int fd, off_t pos, int whence) { +__weak int _lseek(int fd __attribute__((unused)), off_t pos __attribute__((unused)), int whence __attribute__((unused))) { return -1; } @@ -106,13 +106,13 @@ __weak unsigned char getch(void) { } -__weak int _read(int fd, char *buf, size_t cnt) { +__weak int _read(int fd __attribute__((unused)), char *buf, size_t cnt __attribute__((unused))) { *buf = getch(); return 1; } -__weak void putch(unsigned char c) { +__weak void putch(unsigned char c __attribute__((unused))) { } __weak void cgets(char *s, int bufsize) { @@ -155,7 +155,7 @@ __weak void cgets(char *s, int bufsize) { return; } -__weak int _write(int fd, const char *buf, size_t cnt) { +__weak int _write(int fd __attribute__((unused)), const char *buf, size_t cnt) { int i; for (i = 0; i < cnt; i++) @@ -165,12 +165,12 @@ __weak int _write(int fd, const char *buf, size_t cnt) { } /* Override fgets() in newlib with a version that does line editing */ -__weak char *fgets(char *s, int bufsize, void *f) { +__weak char *fgets(char *s, int bufsize, void *f __attribute__((unused))) { cgets(s, bufsize); return s; } -__weak void _exit(int exitcode) { +__weak void _exit(int exitcode __attribute__((unused))) { while (1) ; } diff --git a/STM32F1/variants/generic_stm32f103v/wirish/syscalls.c b/STM32F1/variants/generic_stm32f103v/wirish/syscalls.c index d5f2d9f..ec1c34d 100644 --- a/STM32F1/variants/generic_stm32f103v/wirish/syscalls.c +++ b/STM32F1/variants/generic_stm32f103v/wirish/syscalls.c @@ -76,28 +76,28 @@ void *_sbrk(int incr) { return ret; } -__weak int _open(const char *path, int flags, ...) { +__weak int _open(const char *path __attribute__((unused)), int flags __attribute__((unused)), ...) { return 1; } -__weak int _close(int fd) { +__weak int _close(int fd __attribute__((unused))) { return 0; } -__weak int _fstat(int fd, struct stat *st) { +__weak int _fstat(int fd __attribute__((unused)), struct stat *st) { st->st_mode = S_IFCHR; return 0; } -__weak int _isatty(int fd) { +__weak int _isatty(int fd __attribute__((unused))) { return 1; } -__weak int isatty(int fd) { +__weak int isatty(int fd __attribute__((unused))) { return 1; } -__weak int _lseek(int fd, off_t pos, int whence) { +__weak int _lseek(int fd __attribute__((unused)), off_t pos __attribute__((unused)), int whence __attribute__((unused))) { return -1; } @@ -106,13 +106,13 @@ __weak unsigned char getch(void) { } -__weak int _read(int fd, char *buf, size_t cnt) { +__weak int _read(int fd __attribute__((unused)), char *buf, size_t cnt __attribute__((unused))) { *buf = getch(); return 1; } -__weak void putch(unsigned char c) { +__weak void putch(unsigned char c __attribute__((unused))) { } __weak void cgets(char *s, int bufsize) { @@ -155,7 +155,7 @@ __weak void cgets(char *s, int bufsize) { return; } -__weak int _write(int fd, const char *buf, size_t cnt) { +__weak int _write(int fd __attribute__((unused)), const char *buf, size_t cnt) { int i; for (i = 0; i < cnt; i++) @@ -165,12 +165,12 @@ __weak int _write(int fd, const char *buf, size_t cnt) { } /* Override fgets() in newlib with a version that does line editing */ -__weak char *fgets(char *s, int bufsize, void *f) { +__weak char *fgets(char *s, int bufsize, void *f __attribute__((unused))) { cgets(s, bufsize); return s; } -__weak void _exit(int exitcode) { +__weak void _exit(int exitcode __attribute__((unused))) { while (1) ; } diff --git a/STM32F1/variants/generic_stm32f103z/wirish/syscalls.c b/STM32F1/variants/generic_stm32f103z/wirish/syscalls.c index d42536c..91ed5a1 100644 --- a/STM32F1/variants/generic_stm32f103z/wirish/syscalls.c +++ b/STM32F1/variants/generic_stm32f103z/wirish/syscalls.c @@ -76,28 +76,28 @@ void *_sbrk(int incr) { return ret; } -__weak int _open(const char *path, int flags, ...) { +__weak int _open(const char *path __attribute__((unused)), int flags __attribute__((unused)), ...) { return 1; } -__weak int _close(int fd) { +__weak int _close(int fd __attribute__((unused))) { return 0; } -__weak int _fstat(int fd, struct stat *st) { +__weak int _fstat(int fd __attribute__((unused)), struct stat *st) { st->st_mode = S_IFCHR; return 0; } -__weak int _isatty(int fd) { +__weak int _isatty(int fd __attribute__((unused))) { return 1; } -__weak int isatty(int fd) { +__weak int isatty(int fd __attribute__((unused))) { return 1; } -__weak int _lseek(int fd, off_t pos, int whence) { +__weak int _lseek(int fd __attribute__((unused)), off_t pos __attribute__((unused)), int whence __attribute__((unused))) { return -1; } @@ -106,13 +106,13 @@ __weak unsigned char getch(void) { } -__weak int _read(int fd, char *buf, size_t cnt) { +__weak int _read(int fd __attribute__((unused)), char *buf, size_t cnt __attribute__((unused))) { *buf = getch(); return 1; } -__weak void putch(unsigned char c) { +__weak void putch(unsigned char c __attribute__((unused))) { } __weak void cgets(char *s, int bufsize) { @@ -155,7 +155,7 @@ __weak void cgets(char *s, int bufsize) { return; } -__weak int _write(int fd, const char *buf, size_t cnt) { +__weak int _write(int fd __attribute__((unused)), const char *buf, size_t cnt) { int i; for (i = 0; i < cnt; i++) @@ -165,12 +165,12 @@ __weak int _write(int fd, const char *buf, size_t cnt) { } /* Override fgets() in newlib with a version that does line editing */ -__weak char *fgets(char *s, int bufsize, void *f) { +__weak char *fgets(char *s, int bufsize, void *f __attribute__((unused))) { cgets(s, bufsize); return s; } -__weak void _exit(int exitcode) { +__weak void _exit(int exitcode __attribute__((unused))) { while (1) ; } diff --git a/STM32F1/variants/hytiny_stm32f103t/wirish/syscalls.c b/STM32F1/variants/hytiny_stm32f103t/wirish/syscalls.c index d5f2d9f..ec1c34d 100644 --- a/STM32F1/variants/hytiny_stm32f103t/wirish/syscalls.c +++ b/STM32F1/variants/hytiny_stm32f103t/wirish/syscalls.c @@ -76,28 +76,28 @@ void *_sbrk(int incr) { return ret; } -__weak int _open(const char *path, int flags, ...) { +__weak int _open(const char *path __attribute__((unused)), int flags __attribute__((unused)), ...) { return 1; } -__weak int _close(int fd) { +__weak int _close(int fd __attribute__((unused))) { return 0; } -__weak int _fstat(int fd, struct stat *st) { +__weak int _fstat(int fd __attribute__((unused)), struct stat *st) { st->st_mode = S_IFCHR; return 0; } -__weak int _isatty(int fd) { +__weak int _isatty(int fd __attribute__((unused))) { return 1; } -__weak int isatty(int fd) { +__weak int isatty(int fd __attribute__((unused))) { return 1; } -__weak int _lseek(int fd, off_t pos, int whence) { +__weak int _lseek(int fd __attribute__((unused)), off_t pos __attribute__((unused)), int whence __attribute__((unused))) { return -1; } @@ -106,13 +106,13 @@ __weak unsigned char getch(void) { } -__weak int _read(int fd, char *buf, size_t cnt) { +__weak int _read(int fd __attribute__((unused)), char *buf, size_t cnt __attribute__((unused))) { *buf = getch(); return 1; } -__weak void putch(unsigned char c) { +__weak void putch(unsigned char c __attribute__((unused))) { } __weak void cgets(char *s, int bufsize) { @@ -155,7 +155,7 @@ __weak void cgets(char *s, int bufsize) { return; } -__weak int _write(int fd, const char *buf, size_t cnt) { +__weak int _write(int fd __attribute__((unused)), const char *buf, size_t cnt) { int i; for (i = 0; i < cnt; i++) @@ -165,12 +165,12 @@ __weak int _write(int fd, const char *buf, size_t cnt) { } /* Override fgets() in newlib with a version that does line editing */ -__weak char *fgets(char *s, int bufsize, void *f) { +__weak char *fgets(char *s, int bufsize, void *f __attribute__((unused))) { cgets(s, bufsize); return s; } -__weak void _exit(int exitcode) { +__weak void _exit(int exitcode __attribute__((unused))) { while (1) ; } diff --git a/STM32F1/variants/maple/wirish/syscalls.c b/STM32F1/variants/maple/wirish/syscalls.c index d5f2d9f..ec1c34d 100644 --- a/STM32F1/variants/maple/wirish/syscalls.c +++ b/STM32F1/variants/maple/wirish/syscalls.c @@ -76,28 +76,28 @@ void *_sbrk(int incr) { return ret; } -__weak int _open(const char *path, int flags, ...) { +__weak int _open(const char *path __attribute__((unused)), int flags __attribute__((unused)), ...) { return 1; } -__weak int _close(int fd) { +__weak int _close(int fd __attribute__((unused))) { return 0; } -__weak int _fstat(int fd, struct stat *st) { +__weak int _fstat(int fd __attribute__((unused)), struct stat *st) { st->st_mode = S_IFCHR; return 0; } -__weak int _isatty(int fd) { +__weak int _isatty(int fd __attribute__((unused))) { return 1; } -__weak int isatty(int fd) { +__weak int isatty(int fd __attribute__((unused))) { return 1; } -__weak int _lseek(int fd, off_t pos, int whence) { +__weak int _lseek(int fd __attribute__((unused)), off_t pos __attribute__((unused)), int whence __attribute__((unused))) { return -1; } @@ -106,13 +106,13 @@ __weak unsigned char getch(void) { } -__weak int _read(int fd, char *buf, size_t cnt) { +__weak int _read(int fd __attribute__((unused)), char *buf, size_t cnt __attribute__((unused))) { *buf = getch(); return 1; } -__weak void putch(unsigned char c) { +__weak void putch(unsigned char c __attribute__((unused))) { } __weak void cgets(char *s, int bufsize) { @@ -155,7 +155,7 @@ __weak void cgets(char *s, int bufsize) { return; } -__weak int _write(int fd, const char *buf, size_t cnt) { +__weak int _write(int fd __attribute__((unused)), const char *buf, size_t cnt) { int i; for (i = 0; i < cnt; i++) @@ -165,12 +165,12 @@ __weak int _write(int fd, const char *buf, size_t cnt) { } /* Override fgets() in newlib with a version that does line editing */ -__weak char *fgets(char *s, int bufsize, void *f) { +__weak char *fgets(char *s, int bufsize, void *f __attribute__((unused))) { cgets(s, bufsize); return s; } -__weak void _exit(int exitcode) { +__weak void _exit(int exitcode __attribute__((unused))) { while (1) ; } diff --git a/STM32F1/variants/maple_mini/wirish/syscalls.c b/STM32F1/variants/maple_mini/wirish/syscalls.c index d5f2d9f..ec1c34d 100644 --- a/STM32F1/variants/maple_mini/wirish/syscalls.c +++ b/STM32F1/variants/maple_mini/wirish/syscalls.c @@ -76,28 +76,28 @@ void *_sbrk(int incr) { return ret; } -__weak int _open(const char *path, int flags, ...) { +__weak int _open(const char *path __attribute__((unused)), int flags __attribute__((unused)), ...) { return 1; } -__weak int _close(int fd) { +__weak int _close(int fd __attribute__((unused))) { return 0; } -__weak int _fstat(int fd, struct stat *st) { +__weak int _fstat(int fd __attribute__((unused)), struct stat *st) { st->st_mode = S_IFCHR; return 0; } -__weak int _isatty(int fd) { +__weak int _isatty(int fd __attribute__((unused))) { return 1; } -__weak int isatty(int fd) { +__weak int isatty(int fd __attribute__((unused))) { return 1; } -__weak int _lseek(int fd, off_t pos, int whence) { +__weak int _lseek(int fd __attribute__((unused)), off_t pos __attribute__((unused)), int whence __attribute__((unused))) { return -1; } @@ -106,13 +106,13 @@ __weak unsigned char getch(void) { } -__weak int _read(int fd, char *buf, size_t cnt) { +__weak int _read(int fd __attribute__((unused)), char *buf, size_t cnt __attribute__((unused))) { *buf = getch(); return 1; } -__weak void putch(unsigned char c) { +__weak void putch(unsigned char c __attribute__((unused))) { } __weak void cgets(char *s, int bufsize) { @@ -155,7 +155,7 @@ __weak void cgets(char *s, int bufsize) { return; } -__weak int _write(int fd, const char *buf, size_t cnt) { +__weak int _write(int fd __attribute__((unused)), const char *buf, size_t cnt) { int i; for (i = 0; i < cnt; i++) @@ -165,12 +165,12 @@ __weak int _write(int fd, const char *buf, size_t cnt) { } /* Override fgets() in newlib with a version that does line editing */ -__weak char *fgets(char *s, int bufsize, void *f) { +__weak char *fgets(char *s, int bufsize, void *f __attribute__((unused))) { cgets(s, bufsize); return s; } -__weak void _exit(int exitcode) { +__weak void _exit(int exitcode __attribute__((unused))) { while (1) ; } diff --git a/STM32F1/variants/maple_ret6/wirish/syscalls.c b/STM32F1/variants/maple_ret6/wirish/syscalls.c index d5f2d9f..ec1c34d 100644 --- a/STM32F1/variants/maple_ret6/wirish/syscalls.c +++ b/STM32F1/variants/maple_ret6/wirish/syscalls.c @@ -76,28 +76,28 @@ void *_sbrk(int incr) { return ret; } -__weak int _open(const char *path, int flags, ...) { +__weak int _open(const char *path __attribute__((unused)), int flags __attribute__((unused)), ...) { return 1; } -__weak int _close(int fd) { +__weak int _close(int fd __attribute__((unused))) { return 0; } -__weak int _fstat(int fd, struct stat *st) { +__weak int _fstat(int fd __attribute__((unused)), struct stat *st) { st->st_mode = S_IFCHR; return 0; } -__weak int _isatty(int fd) { +__weak int _isatty(int fd __attribute__((unused))) { return 1; } -__weak int isatty(int fd) { +__weak int isatty(int fd __attribute__((unused))) { return 1; } -__weak int _lseek(int fd, off_t pos, int whence) { +__weak int _lseek(int fd __attribute__((unused)), off_t pos __attribute__((unused)), int whence __attribute__((unused))) { return -1; } @@ -106,13 +106,13 @@ __weak unsigned char getch(void) { } -__weak int _read(int fd, char *buf, size_t cnt) { +__weak int _read(int fd __attribute__((unused)), char *buf, size_t cnt __attribute__((unused))) { *buf = getch(); return 1; } -__weak void putch(unsigned char c) { +__weak void putch(unsigned char c __attribute__((unused))) { } __weak void cgets(char *s, int bufsize) { @@ -155,7 +155,7 @@ __weak void cgets(char *s, int bufsize) { return; } -__weak int _write(int fd, const char *buf, size_t cnt) { +__weak int _write(int fd __attribute__((unused)), const char *buf, size_t cnt) { int i; for (i = 0; i < cnt; i++) @@ -165,12 +165,12 @@ __weak int _write(int fd, const char *buf, size_t cnt) { } /* Override fgets() in newlib with a version that does line editing */ -__weak char *fgets(char *s, int bufsize, void *f) { +__weak char *fgets(char *s, int bufsize, void *f __attribute__((unused))) { cgets(s, bufsize); return s; } -__weak void _exit(int exitcode) { +__weak void _exit(int exitcode __attribute__((unused))) { while (1) ; } diff --git a/STM32F1/variants/microduino/wirish/syscalls.c b/STM32F1/variants/microduino/wirish/syscalls.c index d5f2d9f..ec1c34d 100644 --- a/STM32F1/variants/microduino/wirish/syscalls.c +++ b/STM32F1/variants/microduino/wirish/syscalls.c @@ -76,28 +76,28 @@ void *_sbrk(int incr) { return ret; } -__weak int _open(const char *path, int flags, ...) { +__weak int _open(const char *path __attribute__((unused)), int flags __attribute__((unused)), ...) { return 1; } -__weak int _close(int fd) { +__weak int _close(int fd __attribute__((unused))) { return 0; } -__weak int _fstat(int fd, struct stat *st) { +__weak int _fstat(int fd __attribute__((unused)), struct stat *st) { st->st_mode = S_IFCHR; return 0; } -__weak int _isatty(int fd) { +__weak int _isatty(int fd __attribute__((unused))) { return 1; } -__weak int isatty(int fd) { +__weak int isatty(int fd __attribute__((unused))) { return 1; } -__weak int _lseek(int fd, off_t pos, int whence) { +__weak int _lseek(int fd __attribute__((unused)), off_t pos __attribute__((unused)), int whence __attribute__((unused))) { return -1; } @@ -106,13 +106,13 @@ __weak unsigned char getch(void) { } -__weak int _read(int fd, char *buf, size_t cnt) { +__weak int _read(int fd __attribute__((unused)), char *buf, size_t cnt __attribute__((unused))) { *buf = getch(); return 1; } -__weak void putch(unsigned char c) { +__weak void putch(unsigned char c __attribute__((unused))) { } __weak void cgets(char *s, int bufsize) { @@ -155,7 +155,7 @@ __weak void cgets(char *s, int bufsize) { return; } -__weak int _write(int fd, const char *buf, size_t cnt) { +__weak int _write(int fd __attribute__((unused)), const char *buf, size_t cnt) { int i; for (i = 0; i < cnt; i++) @@ -165,12 +165,12 @@ __weak int _write(int fd, const char *buf, size_t cnt) { } /* Override fgets() in newlib with a version that does line editing */ -__weak char *fgets(char *s, int bufsize, void *f) { +__weak char *fgets(char *s, int bufsize, void *f __attribute__((unused))) { cgets(s, bufsize); return s; } -__weak void _exit(int exitcode) { +__weak void _exit(int exitcode __attribute__((unused))) { while (1) ; } diff --git a/STM32F1/variants/nucleo_f103rb/wirish/syscalls.c b/STM32F1/variants/nucleo_f103rb/wirish/syscalls.c index d5f2d9f..ec1c34d 100644 --- a/STM32F1/variants/nucleo_f103rb/wirish/syscalls.c +++ b/STM32F1/variants/nucleo_f103rb/wirish/syscalls.c @@ -76,28 +76,28 @@ void *_sbrk(int incr) { return ret; } -__weak int _open(const char *path, int flags, ...) { +__weak int _open(const char *path __attribute__((unused)), int flags __attribute__((unused)), ...) { return 1; } -__weak int _close(int fd) { +__weak int _close(int fd __attribute__((unused))) { return 0; } -__weak int _fstat(int fd, struct stat *st) { +__weak int _fstat(int fd __attribute__((unused)), struct stat *st) { st->st_mode = S_IFCHR; return 0; } -__weak int _isatty(int fd) { +__weak int _isatty(int fd __attribute__((unused))) { return 1; } -__weak int isatty(int fd) { +__weak int isatty(int fd __attribute__((unused))) { return 1; } -__weak int _lseek(int fd, off_t pos, int whence) { +__weak int _lseek(int fd __attribute__((unused)), off_t pos __attribute__((unused)), int whence __attribute__((unused))) { return -1; } @@ -106,13 +106,13 @@ __weak unsigned char getch(void) { } -__weak int _read(int fd, char *buf, size_t cnt) { +__weak int _read(int fd __attribute__((unused)), char *buf, size_t cnt __attribute__((unused))) { *buf = getch(); return 1; } -__weak void putch(unsigned char c) { +__weak void putch(unsigned char c __attribute__((unused))) { } __weak void cgets(char *s, int bufsize) { @@ -155,7 +155,7 @@ __weak void cgets(char *s, int bufsize) { return; } -__weak int _write(int fd, const char *buf, size_t cnt) { +__weak int _write(int fd __attribute__((unused)), const char *buf, size_t cnt) { int i; for (i = 0; i < cnt; i++) @@ -165,12 +165,12 @@ __weak int _write(int fd, const char *buf, size_t cnt) { } /* Override fgets() in newlib with a version that does line editing */ -__weak char *fgets(char *s, int bufsize, void *f) { +__weak char *fgets(char *s, int bufsize, void *f __attribute__((unused))) { cgets(s, bufsize); return s; } -__weak void _exit(int exitcode) { +__weak void _exit(int exitcode __attribute__((unused))) { while (1) ; } From 29ff4e739d35fda2760784a0c8945ee30ed3cb42 Mon Sep 17 00:00:00 2001 From: lacklustrlabs Date: Thu, 16 Nov 2017 19:20:25 +0100 Subject: [PATCH 204/351] Fixed 'warning: missing initializer for member ... [-Wmissing-field-initializers]' --- STM32F1/cores/maple/boards_private.h | 2 +- STM32F1/variants/STM32VLD/board.cpp | 105 ++++---- STM32F1/variants/generic_gd32f103c/board.cpp | 73 +++--- STM32F1/variants/generic_stm32f103c/board.cpp | 73 +++--- STM32F1/variants/generic_stm32f103r/board.cpp | 105 ++++---- .../variants/generic_stm32f103r8/board.cpp | 101 ++++---- STM32F1/variants/generic_stm32f103t/board.cpp | 51 ++-- STM32F1/variants/generic_stm32f103v/board.cpp | 161 ++++++------- STM32F1/variants/generic_stm32f103z/board.cpp | 227 +++++++++--------- STM32F1/variants/hytiny_stm32f103t/board.cpp | 51 ++-- STM32F1/variants/maple/board.cpp | 3 - STM32F1/variants/maple_mini/board.cpp | 71 +++--- STM32F1/variants/maple_ret6/board.cpp | 101 ++++---- STM32F1/variants/microduino/board.cpp | 53 ++-- STM32F1/variants/nucleo_f103rb/board.cpp | 101 ++++---- STM32F3/cores/maple/wirish/boards_private.h | 2 +- 16 files changed, 619 insertions(+), 661 deletions(-) diff --git a/STM32F1/cores/maple/boards_private.h b/STM32F1/cores/maple/boards_private.h index 49867ca..332843d 100644 --- a/STM32F1/cores/maple/boards_private.h +++ b/STM32F1/cores/maple/boards_private.h @@ -42,7 +42,7 @@ /* Makes the PIN_MAP rows more human-readable. */ #define PMAP_ROW(gpio_dev, gpio_bit, timer_dev, timer_ch, adc_dev, adc_ch) \ - { gpio_dev, timer_dev, adc_dev, gpio_bit, timer_ch, adc_ch } + { gpio_dev, timer_dev, adc_dev, gpio_bit, timer_ch, adc_ch, 0} namespace wirish { namespace priv { diff --git a/STM32F1/variants/STM32VLD/board.cpp b/STM32F1/variants/STM32VLD/board.cpp index 2561814..182e8f7 100644 --- a/STM32F1/variants/STM32VLD/board.cpp +++ b/STM32F1/variants/STM32VLD/board.cpp @@ -51,70 +51,67 @@ void boardInit(void) { } // Note. See the enum of pin names in board.h -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wmissing-field-initializers" extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { - {&gpioa, &timer2, &adc1, 0, 1, 0}, /* PA0 */ - {&gpioa, &timer2, &adc1, 1, 2, 1}, /* PA1 */ - {&gpioa, &timer2, &adc1, 2, 3, 2}, /* PA2 */ - {&gpioa, &timer2, &adc1, 3, 4, 3}, /* PA3 */ - {&gpioa, NULL, &adc1, 4, 0, 4}, /* PA4 */ - {&gpioa, NULL, &adc1, 5, 0, 5}, /* PA5 */ - {&gpioa, &timer3, &adc1, 6, 1, 6}, /* PA6 */ - {&gpioa, &timer3, &adc1, 7, 2, 7}, /* PA7 */ - {&gpioa, &timer1, NULL, 8, 1, ADCx}, /* PA8 */ - {&gpioa, &timer1, NULL, 9, 2, ADCx}, /* PA9 */ - {&gpioa, &timer1, NULL, 10, 3, ADCx}, /* PA10 */ - {&gpioa, NULL, NULL, 11, 0, ADCx}, /* PA11 */ - {&gpioa, NULL, NULL, 12, 0, ADCx}, /* PA12 */ - {&gpioa, NULL, NULL, 13, 0, ADCx}, /* PA13 */ - {&gpioa, NULL, NULL, 14, 0, ADCx}, /* PA14 */ - {&gpioa, NULL, NULL, 15, 0, ADCx}, /* PA15 */ + {&gpioa, &timer2, &adc1, 0, 1, 0, 0}, /* PA0 */ + {&gpioa, &timer2, &adc1, 1, 2, 1, 0}, /* PA1 */ + {&gpioa, &timer2, &adc1, 2, 3, 2, 0}, /* PA2 */ + {&gpioa, &timer2, &adc1, 3, 4, 3, 0}, /* PA3 */ + {&gpioa, NULL, &adc1, 4, 0, 4, 0}, /* PA4 */ + {&gpioa, NULL, &adc1, 5, 0, 5, 0}, /* PA5 */ + {&gpioa, &timer3, &adc1, 6, 1, 6, 0}, /* PA6 */ + {&gpioa, &timer3, &adc1, 7, 2, 7, 0}, /* PA7 */ + {&gpioa, &timer1, NULL, 8, 1, ADCx, 0}, /* PA8 */ + {&gpioa, &timer1, NULL, 9, 2, ADCx, 0}, /* PA9 */ + {&gpioa, &timer1, NULL, 10, 3, ADCx, 0}, /* PA10 */ + {&gpioa, NULL, NULL, 11, 0, ADCx, 0}, /* PA11 */ + {&gpioa, NULL, NULL, 12, 0, ADCx, 0}, /* PA12 */ + {&gpioa, NULL, NULL, 13, 0, ADCx, 0}, /* PA13 */ + {&gpioa, NULL, NULL, 14, 0, ADCx, 0}, /* PA14 */ + {&gpioa, NULL, NULL, 15, 0, ADCx, 0}, /* PA15 */ - {&gpiob, &timer3, &adc1, 0, 3, 8}, /* PB0 */ - {&gpiob, &timer3, &adc1, 1, 4, 9}, /* PB1 */ - {&gpiob, NULL, NULL, 2, 0, ADCx}, /* PB2 */ - {&gpiob, NULL, NULL, 3, 0, ADCx}, /* PB3 */ - {&gpiob, NULL, NULL, 4, 0, ADCx}, /* PB4 */ - {&gpiob, NULL, NULL, 5, 0, ADCx}, /* PB5 */ - {&gpiob, &timer4, NULL, 6, 1, ADCx}, /* PB6 */ - {&gpiob, &timer4, NULL, 7, 2, ADCx}, /* PB7 */ - {&gpiob, &timer4, NULL, 8, 3, ADCx}, /* PB8 */ - {&gpiob, &timer4, NULL, 9, 4, ADCx}, /* PB9 */ - {&gpiob, NULL, NULL, 10, 0, ADCx}, /* PB10 */ - {&gpiob, NULL, NULL, 11, 0, ADCx}, /* PB11 */ - {&gpiob, NULL, NULL, 12, 0, ADCx}, /* PB12 */ - {&gpiob, NULL, NULL, 13, 0, ADCx}, /* PB13 */ - {&gpiob, NULL, NULL, 14, 0, ADCx}, /* PB14 */ - {&gpiob, NULL, NULL, 15, 0, ADCx}, /* PB15 */ + {&gpiob, &timer3, &adc1, 0, 3, 8, 0}, /* PB0 */ + {&gpiob, &timer3, &adc1, 1, 4, 9, 0}, /* PB1 */ + {&gpiob, NULL, NULL, 2, 0, ADCx, 0}, /* PB2 */ + {&gpiob, NULL, NULL, 3, 0, ADCx, 0}, /* PB3 */ + {&gpiob, NULL, NULL, 4, 0, ADCx, 0}, /* PB4 */ + {&gpiob, NULL, NULL, 5, 0, ADCx, 0}, /* PB5 */ + {&gpiob, &timer4, NULL, 6, 1, ADCx, 0}, /* PB6 */ + {&gpiob, &timer4, NULL, 7, 2, ADCx, 0}, /* PB7 */ + {&gpiob, &timer4, NULL, 8, 3, ADCx, 0}, /* PB8 */ + {&gpiob, &timer4, NULL, 9, 4, ADCx, 0}, /* PB9 */ + {&gpiob, NULL, NULL, 10, 0, ADCx, 0}, /* PB10 */ + {&gpiob, NULL, NULL, 11, 0, ADCx, 0}, /* PB11 */ + {&gpiob, NULL, NULL, 12, 0, ADCx, 0}, /* PB12 */ + {&gpiob, NULL, NULL, 13, 0, ADCx, 0}, /* PB13 */ + {&gpiob, NULL, NULL, 14, 0, ADCx, 0}, /* PB14 */ + {&gpiob, NULL, NULL, 15, 0, ADCx, 0}, /* PB15 */ /* Andy Hull - the R8 is similar to the C8 but exposes more GPIO as follows */ - {&gpioc, NULL, &adc1, 0, 0, 10}, /* PC0 */ - {&gpioc, NULL, &adc1, 1, 0, 11}, /* PC1 */ - {&gpioc, NULL, &adc1, 2, 0, 12}, /* PC2 */ - {&gpioc, NULL, &adc1, 3, 0, 13}, /* PC3 */ - {&gpioc, NULL, &adc1, 4, 0, 14}, /* PC4 */ - {&gpioc, NULL, &adc1, 5, 0, 15}, /* PC5 */ + {&gpioc, NULL, &adc1, 0, 0, 10, 0}, /* PC0 */ + {&gpioc, NULL, &adc1, 1, 0, 11, 0}, /* PC1 */ + {&gpioc, NULL, &adc1, 2, 0, 12, 0}, /* PC2 */ + {&gpioc, NULL, &adc1, 3, 0, 13, 0}, /* PC3 */ + {&gpioc, NULL, &adc1, 4, 0, 14, 0}, /* PC4 */ + {&gpioc, NULL, &adc1, 5, 0, 15, 0}, /* PC5 */ - {&gpioc, NULL, NULL, 6, 0, ADCx}, /* PC6 */ - {&gpioc, NULL, NULL, 7, 0, ADCx}, /* PC7 */ - {&gpioc, NULL, NULL, 8, 0, ADCx}, /* PC8 */ - {&gpioc, NULL, NULL, 9, 0, ADCx}, /* PC9 */ + {&gpioc, NULL, NULL, 6, 0, ADCx, 0}, /* PC6 */ + {&gpioc, NULL, NULL, 7, 0, ADCx, 0}, /* PC7 */ + {&gpioc, NULL, NULL, 8, 0, ADCx, 0}, /* PC8 */ + {&gpioc, NULL, NULL, 9, 0, ADCx, 0}, /* PC9 */ - {&gpioc, NULL, NULL, 10, 0, ADCx}, /* PC10 */ - {&gpioc, NULL, NULL, 11, 0, ADCx}, /* PC11 */ - {&gpioc, NULL, NULL, 12, 0, ADCx}, /* PC12 */ - {&gpioc, NULL, NULL, 13, 0, ADCx}, /* PC13 */ - {&gpioc, NULL, NULL, 14, 0, ADCx}, /* PC14 */ - {&gpioc, NULL, NULL, 15, 0, ADCx}, /* PC15 */ + {&gpioc, NULL, NULL, 10, 0, ADCx, 0}, /* PC10 */ + {&gpioc, NULL, NULL, 11, 0, ADCx, 0}, /* PC11 */ + {&gpioc, NULL, NULL, 12, 0, ADCx, 0}, /* PC12 */ + {&gpioc, NULL, NULL, 13, 0, ADCx, 0}, /* PC13 */ + {&gpioc, NULL, NULL, 14, 0, ADCx, 0}, /* PC14 */ + {&gpioc, NULL, NULL, 15, 0, ADCx, 0}, /* PC15 */ - {&gpiod, NULL, NULL, 0, 0, ADCx}, /* PD2 */ - {&gpiod, NULL, NULL, 1, 0, ADCx}, /* PD2 */ - {&gpiod, NULL, NULL, 2, 0, ADCx}, /* PD2 */ + {&gpiod, NULL, NULL, 0, 0, ADCx, 0}, /* PD2 */ + {&gpiod, NULL, NULL, 1, 0, ADCx, 0}, /* PD2 */ + {&gpiod, NULL, NULL, 2, 0, ADCx, 0}, /* PD2 */ }; -#pragma GCC diagnostic pop extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { PA0, PA1, PA2, PA3, PA6, PA7, PA8, PA9, PA10, PB0, PB1, PB6, PB7, PB8, PB9 diff --git a/STM32F1/variants/generic_gd32f103c/board.cpp b/STM32F1/variants/generic_gd32f103c/board.cpp index 54f60be..da22d52 100644 --- a/STM32F1/variants/generic_gd32f103c/board.cpp +++ b/STM32F1/variants/generic_gd32f103c/board.cpp @@ -51,51 +51,48 @@ void boardInit(void) { } // Note. See the enum of pin names in board.h -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wmissing-field-initializers" extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { - {&gpioa, &timer2, &adc1, 0, 1, 0}, /* PA0 */ - {&gpioa, &timer2, &adc1, 1, 2, 1}, /* PA1 */ - {&gpioa, &timer2, &adc1, 2, 3, 2}, /* PA2 */ - {&gpioa, &timer2, &adc1, 3, 4, 3}, /* PA3 */ - {&gpioa, NULL, &adc1, 4, 0, 4}, /* PA4 */ - {&gpioa, NULL, &adc1, 5, 0, 5}, /* PA5 */ - {&gpioa, &timer3, &adc1, 6, 1, 6}, /* PA6 */ - {&gpioa, &timer3, &adc1, 7, 2, 7}, /* PA7 */ - {&gpioa, &timer1, NULL, 8, 1, ADCx}, /* PA8 */ - {&gpioa, &timer1, NULL, 9, 2, ADCx}, /* PA9 */ - {&gpioa, &timer1, NULL, 10, 3, ADCx}, /* PA10 */ - {&gpioa, &timer1, NULL, 11, 4, ADCx}, /* PA11 */ - {&gpioa, NULL, NULL, 12, 0, ADCx}, /* PA12 */ - {&gpioa, NULL, NULL, 13, 0, ADCx}, /* PA13 */ - {&gpioa, NULL, NULL, 14, 0, ADCx}, /* PA14 */ - {&gpioa, NULL, NULL, 15, 0, ADCx}, /* PA15 */ + {&gpioa, &timer2, &adc1, 0, 1, 0, 0}, /* PA0 */ + {&gpioa, &timer2, &adc1, 1, 2, 1, 0}, /* PA1 */ + {&gpioa, &timer2, &adc1, 2, 3, 2, 0}, /* PA2 */ + {&gpioa, &timer2, &adc1, 3, 4, 3, 0}, /* PA3 */ + {&gpioa, NULL, &adc1, 4, 0, 4, 0}, /* PA4 */ + {&gpioa, NULL, &adc1, 5, 0, 5, 0}, /* PA5 */ + {&gpioa, &timer3, &adc1, 6, 1, 6, 0}, /* PA6 */ + {&gpioa, &timer3, &adc1, 7, 2, 7, 0}, /* PA7 */ + {&gpioa, &timer1, NULL, 8, 1, ADCx, 0}, /* PA8 */ + {&gpioa, &timer1, NULL, 9, 2, ADCx, 0}, /* PA9 */ + {&gpioa, &timer1, NULL, 10, 3, ADCx, 0}, /* PA10 */ + {&gpioa, &timer1, NULL, 11, 4, ADCx, 0}, /* PA11 */ + {&gpioa, NULL, NULL, 12, 0, ADCx, 0}, /* PA12 */ + {&gpioa, NULL, NULL, 13, 0, ADCx, 0}, /* PA13 */ + {&gpioa, NULL, NULL, 14, 0, ADCx, 0}, /* PA14 */ + {&gpioa, NULL, NULL, 15, 0, ADCx, 0}, /* PA15 */ - {&gpiob, &timer3, &adc1, 0, 3, 8}, /* PB0 */ - {&gpiob, &timer3, &adc1, 1, 4, 9}, /* PB1 */ - {&gpiob, NULL, NULL, 2, 0, ADCx}, /* PB2 */ - {&gpiob, NULL, NULL, 3, 0, ADCx}, /* PB3 */ - {&gpiob, NULL, NULL, 4, 0, ADCx}, /* PB4 */ - {&gpiob, NULL, NULL, 5, 0, ADCx}, /* PB5 */ - {&gpiob, &timer4, NULL, 6, 1, ADCx}, /* PB6 */ - {&gpiob, &timer4, NULL, 7, 2, ADCx}, /* PB7 */ - {&gpiob, &timer4, NULL, 8, 3, ADCx}, /* PB8 */ - {&gpiob, &timer4, NULL, 9, 4, ADCx}, /* PB9 */ - {&gpiob, NULL, NULL, 10, 0, ADCx}, /* PB10 */ - {&gpiob, NULL, NULL, 11, 0, ADCx}, /* PB11 */ - {&gpiob, NULL, NULL, 12, 0, ADCx}, /* PB12 */ - {&gpiob, NULL, NULL, 13, 0, ADCx}, /* PB13 */ - {&gpiob, NULL, NULL, 14, 0, ADCx}, /* PB14 */ - {&gpiob, NULL, NULL, 15, 0, ADCx}, /* PB15 */ + {&gpiob, &timer3, &adc1, 0, 3, 8, 0}, /* PB0 */ + {&gpiob, &timer3, &adc1, 1, 4, 9, 0}, /* PB1 */ + {&gpiob, NULL, NULL, 2, 0, ADCx, 0}, /* PB2 */ + {&gpiob, NULL, NULL, 3, 0, ADCx, 0}, /* PB3 */ + {&gpiob, NULL, NULL, 4, 0, ADCx, 0}, /* PB4 */ + {&gpiob, NULL, NULL, 5, 0, ADCx, 0}, /* PB5 */ + {&gpiob, &timer4, NULL, 6, 1, ADCx, 0}, /* PB6 */ + {&gpiob, &timer4, NULL, 7, 2, ADCx, 0}, /* PB7 */ + {&gpiob, &timer4, NULL, 8, 3, ADCx, 0}, /* PB8 */ + {&gpiob, &timer4, NULL, 9, 4, ADCx, 0}, /* PB9 */ + {&gpiob, NULL, NULL, 10, 0, ADCx, 0}, /* PB10 */ + {&gpiob, NULL, NULL, 11, 0, ADCx, 0}, /* PB11 */ + {&gpiob, NULL, NULL, 12, 0, ADCx, 0}, /* PB12 */ + {&gpiob, NULL, NULL, 13, 0, ADCx, 0}, /* PB13 */ + {&gpiob, NULL, NULL, 14, 0, ADCx, 0}, /* PB14 */ + {&gpiob, NULL, NULL, 15, 0, ADCx, 0}, /* PB15 */ - {&gpioc, NULL, NULL, 13, 0, ADCx}, /* PC13 */ - {&gpioc, NULL, NULL, 14, 0, ADCx}, /* PC14 */ - {&gpioc, NULL, NULL, 15, 0, ADCx}, /* PC15 */ + {&gpioc, NULL, NULL, 13, 0, ADCx, 0}, /* PC13 */ + {&gpioc, NULL, NULL, 14, 0, ADCx, 0}, /* PC14 */ + {&gpioc, NULL, NULL, 15, 0, ADCx, 0}, /* PC15 */ }; -#pragma GCC diagnostic pop extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { PB0, PA7, PA6, PA3, PA2, PA1, PA0, PB7, PB6, PA10, PA9, PA8 diff --git a/STM32F1/variants/generic_stm32f103c/board.cpp b/STM32F1/variants/generic_stm32f103c/board.cpp index ac786cf..7b33ba8 100644 --- a/STM32F1/variants/generic_stm32f103c/board.cpp +++ b/STM32F1/variants/generic_stm32f103c/board.cpp @@ -51,50 +51,47 @@ void boardInit(void) { } // Note. See the enum of pin names in board.h -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wmissing-field-initializers" extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { - {&gpioa, &timer2, &adc1, 0, 1, 0}, /* PA0 */ - {&gpioa, &timer2, &adc1, 1, 2, 1}, /* PA1 */ - {&gpioa, &timer2, &adc1, 2, 3, 2}, /* PA2 */ - {&gpioa, &timer2, &adc1, 3, 4, 3}, /* PA3 */ - {&gpioa, NULL, &adc1, 4, 0, 4}, /* PA4 */ - {&gpioa, NULL, &adc1, 5, 0, 5}, /* PA5 */ - {&gpioa, &timer3, &adc1, 6, 1, 6}, /* PA6 */ - {&gpioa, &timer3, &adc1, 7, 2, 7}, /* PA7 */ - {&gpioa, &timer1, NULL, 8, 1, ADCx}, /* PA8 */ - {&gpioa, &timer1, NULL, 9, 2, ADCx}, /* PA9 */ - {&gpioa, &timer1, NULL, 10, 3, ADCx}, /* PA10 */ - {&gpioa, &timer1, NULL, 11, 4, ADCx}, /* PA11 */ - {&gpioa, NULL, NULL, 12, 0, ADCx}, /* PA12 */ - {&gpioa, NULL, NULL, 13, 0, ADCx}, /* PA13 */ - {&gpioa, NULL, NULL, 14, 0, ADCx}, /* PA14 */ - {&gpioa, NULL, NULL, 15, 0, ADCx}, /* PA15 */ + {&gpioa, &timer2, &adc1, 0, 1, 0, 0}, /* PA0 */ + {&gpioa, &timer2, &adc1, 1, 2, 1, 0}, /* PA1 */ + {&gpioa, &timer2, &adc1, 2, 3, 2, 0}, /* PA2 */ + {&gpioa, &timer2, &adc1, 3, 4, 3, 0}, /* PA3 */ + {&gpioa, NULL, &adc1, 4, 0, 4, 0}, /* PA4 */ + {&gpioa, NULL, &adc1, 5, 0, 5, 0}, /* PA5 */ + {&gpioa, &timer3, &adc1, 6, 1, 6, 0}, /* PA6 */ + {&gpioa, &timer3, &adc1, 7, 2, 7, 0}, /* PA7 */ + {&gpioa, &timer1, NULL, 8, 1, ADCx, 0}, /* PA8 */ + {&gpioa, &timer1, NULL, 9, 2, ADCx, 0}, /* PA9 */ + {&gpioa, &timer1, NULL, 10, 3, ADCx, 0}, /* PA10 */ + {&gpioa, &timer1, NULL, 11, 4, ADCx, 0}, /* PA11 */ + {&gpioa, NULL, NULL, 12, 0, ADCx, 0}, /* PA12 */ + {&gpioa, NULL, NULL, 13, 0, ADCx, 0}, /* PA13 */ + {&gpioa, NULL, NULL, 14, 0, ADCx, 0}, /* PA14 */ + {&gpioa, NULL, NULL, 15, 0, ADCx, 0}, /* PA15 */ - {&gpiob, &timer3, &adc1, 0, 3, 8}, /* PB0 */ - {&gpiob, &timer3, &adc1, 1, 4, 9}, /* PB1 */ - {&gpiob, NULL, NULL, 2, 0, ADCx}, /* PB2 */ - {&gpiob, NULL, NULL, 3, 0, ADCx}, /* PB3 */ - {&gpiob, NULL, NULL, 4, 0, ADCx}, /* PB4 */ - {&gpiob, NULL, NULL, 5, 0, ADCx}, /* PB5 */ - {&gpiob, &timer4, NULL, 6, 1, ADCx}, /* PB6 */ - {&gpiob, &timer4, NULL, 7, 2, ADCx}, /* PB7 */ - {&gpiob, &timer4, NULL, 8, 3, ADCx}, /* PB8 */ - {&gpiob, &timer4, NULL, 9, 4, ADCx}, /* PB9 */ - {&gpiob, NULL, NULL, 10, 0, ADCx}, /* PB10 */ - {&gpiob, NULL, NULL, 11, 0, ADCx}, /* PB11 */ - {&gpiob, NULL, NULL, 12, 0, ADCx}, /* PB12 */ - {&gpiob, NULL, NULL, 13, 0, ADCx}, /* PB13 */ - {&gpiob, NULL, NULL, 14, 0, ADCx}, /* PB14 */ - {&gpiob, NULL, NULL, 15, 0, ADCx}, /* PB15 */ + {&gpiob, &timer3, &adc1, 0, 3, 8, 0}, /* PB0 */ + {&gpiob, &timer3, &adc1, 1, 4, 9, 0}, /* PB1 */ + {&gpiob, NULL, NULL, 2, 0, ADCx, 0}, /* PB2 */ + {&gpiob, NULL, NULL, 3, 0, ADCx, 0}, /* PB3 */ + {&gpiob, NULL, NULL, 4, 0, ADCx, 0}, /* PB4 */ + {&gpiob, NULL, NULL, 5, 0, ADCx, 0}, /* PB5 */ + {&gpiob, &timer4, NULL, 6, 1, ADCx, 0}, /* PB6 */ + {&gpiob, &timer4, NULL, 7, 2, ADCx, 0}, /* PB7 */ + {&gpiob, &timer4, NULL, 8, 3, ADCx, 0}, /* PB8 */ + {&gpiob, &timer4, NULL, 9, 4, ADCx, 0}, /* PB9 */ + {&gpiob, NULL, NULL, 10, 0, ADCx, 0}, /* PB10 */ + {&gpiob, NULL, NULL, 11, 0, ADCx, 0}, /* PB11 */ + {&gpiob, NULL, NULL, 12, 0, ADCx, 0}, /* PB12 */ + {&gpiob, NULL, NULL, 13, 0, ADCx, 0}, /* PB13 */ + {&gpiob, NULL, NULL, 14, 0, ADCx, 0}, /* PB14 */ + {&gpiob, NULL, NULL, 15, 0, ADCx, 0}, /* PB15 */ - {&gpioc, NULL, NULL, 13, 0, ADCx}, /* PC13 */ - {&gpioc, NULL, NULL, 14, 0, ADCx}, /* PC14 */ - {&gpioc, NULL, NULL, 15, 0, ADCx}, /* PC15 */ + {&gpioc, NULL, NULL, 13, 0, ADCx, 0}, /* PC13 */ + {&gpioc, NULL, NULL, 14, 0, ADCx, 0}, /* PC14 */ + {&gpioc, NULL, NULL, 15, 0, ADCx, 0}, /* PC15 */ }; -#pragma GCC diagnostic pop extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { PB0, PA7, PA6, PA3, PA2, PA1, PA0, PB7, PB6, PA10, PA9, PA8 diff --git a/STM32F1/variants/generic_stm32f103r/board.cpp b/STM32F1/variants/generic_stm32f103r/board.cpp index e50314e..e564425 100644 --- a/STM32F1/variants/generic_stm32f103r/board.cpp +++ b/STM32F1/variants/generic_stm32f103r/board.cpp @@ -69,8 +69,6 @@ void boardInit(void) { // - Timer channel (1 to 4, for PWM), or 0 if none // - ADC device, or NULL if none // - ADC channel, or ADCx if none -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wmissing-field-initializers" extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { /* gpio_dev *gpio_device; GPIO device @@ -82,63 +80,62 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { uint8 pinMode; mode specific by pinMode call (Roger Clark added to optimize compatibility with Arduino API */ - {&gpioa, &timer2, &adc1, 0, 1, 0}, /* PA0 */ - {&gpioa, &timer2, &adc1, 1, 2, 1}, /* PA1 */ - {&gpioa, &timer2, &adc1, 2, 3, 2}, /* PA2 */ - {&gpioa, &timer2, &adc1, 3, 4, 3}, /* PA3 */ - {&gpioa, NULL, &adc1, 4, 0, 4}, /* PA4 */ - {&gpioa, NULL, &adc1, 5, 0, 5}, /* PA5 */ - {&gpioa, &timer3, &adc1, 6, 1, 6}, /* PA6 */ - {&gpioa, &timer3, &adc1, 7, 2, 7}, /* PA7 */ - {&gpioa, &timer1, NULL, 8, 1, ADCx}, /* PA8 */ - {&gpioa, &timer1, NULL, 9, 2, ADCx}, /* PA9 */ - {&gpioa, &timer1, NULL, 10, 3, ADCx}, /* PA10 */ - {&gpioa, NULL, NULL, 11, 0, ADCx}, /* PA11 */ - {&gpioa, NULL, NULL, 12, 0, ADCx}, /* PA12 */ - {&gpioa, NULL, NULL, 13, 0, ADCx}, /* PA13 */ - {&gpioa, NULL, NULL, 14, 0, ADCx}, /* PA14 */ - {&gpioa, NULL, NULL, 15, 0, ADCx}, /* PA15 */ + {&gpioa, &timer2, &adc1, 0, 1, 0, 0}, /* PA0 */ + {&gpioa, &timer2, &adc1, 1, 2, 1, 0}, /* PA1 */ + {&gpioa, &timer2, &adc1, 2, 3, 2, 0}, /* PA2 */ + {&gpioa, &timer2, &adc1, 3, 4, 3, 0}, /* PA3 */ + {&gpioa, NULL, &adc1, 4, 0, 4, 0}, /* PA4 */ + {&gpioa, NULL, &adc1, 5, 0, 5, 0}, /* PA5 */ + {&gpioa, &timer3, &adc1, 6, 1, 6, 0}, /* PA6 */ + {&gpioa, &timer3, &adc1, 7, 2, 7, 0}, /* PA7 */ + {&gpioa, &timer1, NULL, 8, 1, ADCx, 0}, /* PA8 */ + {&gpioa, &timer1, NULL, 9, 2, ADCx, 0}, /* PA9 */ + {&gpioa, &timer1, NULL, 10, 3, ADCx, 0}, /* PA10 */ + {&gpioa, NULL, NULL, 11, 0, ADCx, 0}, /* PA11 */ + {&gpioa, NULL, NULL, 12, 0, ADCx, 0}, /* PA12 */ + {&gpioa, NULL, NULL, 13, 0, ADCx, 0}, /* PA13 */ + {&gpioa, NULL, NULL, 14, 0, ADCx, 0}, /* PA14 */ + {&gpioa, NULL, NULL, 15, 0, ADCx, 0}, /* PA15 */ - {&gpiob, &timer3, &adc1, 0, 3, 8}, /* PB0 */ - {&gpiob, &timer3, &adc1, 1, 4, 9}, /* PB1 */ - {&gpiob, NULL, NULL, 2, 0, ADCx}, /* PB2 */ - {&gpiob, NULL, NULL, 3, 0, ADCx}, /* PB3 */ - {&gpiob, NULL, NULL, 4, 0, ADCx}, /* PB4 */ - {&gpiob, NULL, NULL, 5, 0, ADCx}, /* PB5 */ - {&gpiob, &timer4, NULL, 6, 1, ADCx}, /* PB6 */ - {&gpiob, &timer4, NULL, 7, 2, ADCx}, /* PB7 */ - {&gpiob, &timer4, NULL, 8, 3, ADCx}, /* PB8 */ - {&gpiob, NULL, NULL, 9, 0, ADCx}, /* PB9 */ - {&gpiob, NULL, NULL, 10, 0, ADCx}, /* PB10 */ - {&gpiob, NULL, NULL, 11, 0, ADCx}, /* PB11 */ - {&gpiob, NULL, NULL, 12, 0, ADCx}, /* PB12 */ - {&gpiob, NULL, NULL, 13, 0, ADCx}, /* PB13 */ - {&gpiob, NULL, NULL, 14, 0, ADCx}, /* PB14 */ - {&gpiob, NULL, NULL, 15, 0, ADCx}, /* PB15 */ + {&gpiob, &timer3, &adc1, 0, 3, 8, 0}, /* PB0 */ + {&gpiob, &timer3, &adc1, 1, 4, 9, 0}, /* PB1 */ + {&gpiob, NULL, NULL, 2, 0, ADCx, 0}, /* PB2 */ + {&gpiob, NULL, NULL, 3, 0, ADCx, 0}, /* PB3 */ + {&gpiob, NULL, NULL, 4, 0, ADCx, 0}, /* PB4 */ + {&gpiob, NULL, NULL, 5, 0, ADCx, 0}, /* PB5 */ + {&gpiob, &timer4, NULL, 6, 1, ADCx, 0}, /* PB6 */ + {&gpiob, &timer4, NULL, 7, 2, ADCx, 0}, /* PB7 */ + {&gpiob, &timer4, NULL, 8, 3, ADCx, 0}, /* PB8 */ + {&gpiob, NULL, NULL, 9, 0, ADCx, 0}, /* PB9 */ + {&gpiob, NULL, NULL, 10, 0, ADCx, 0}, /* PB10 */ + {&gpiob, NULL, NULL, 11, 0, ADCx, 0}, /* PB11 */ + {&gpiob, NULL, NULL, 12, 0, ADCx, 0}, /* PB12 */ + {&gpiob, NULL, NULL, 13, 0, ADCx, 0}, /* PB13 */ + {&gpiob, NULL, NULL, 14, 0, ADCx, 0}, /* PB14 */ + {&gpiob, NULL, NULL, 15, 0, ADCx, 0}, /* PB15 */ - {&gpioc, NULL, &adc1, 0, 0, 10}, /* PC0 */ - {&gpioc, NULL, &adc1, 1, 0, 11}, /* PC1 */ - {&gpioc, NULL, &adc1, 2, 0, 12}, /* PC2 */ - {&gpioc, NULL, &adc1, 3, 0, 13}, /* PC3 */ - {&gpioc, NULL, &adc1, 4, 0, 14}, /* PC4 */ - {&gpioc, NULL, &adc1, 5, 0, 15}, /* PC5 */ - {&gpioc, &timer8, NULL, 6, 1, ADCx}, /* PC6 */ - {&gpioc, &timer8, NULL, 7, 2, ADCx}, /* PC7 */ - {&gpioc, &timer8, NULL, 8, 3, ADCx}, /* PC8 */ - {&gpioc, &timer8, NULL, 9, 4, ADCx}, /* PC9 */ - {&gpioc, NULL, NULL, 10, 0, ADCx}, /* PC10 UART4_TX/SDIO_D2 */ - {&gpioc, NULL, NULL, 11, 0, ADCx}, /* PC11 UART4_RX/SDIO_D3 */ - {&gpioc, NULL, NULL, 12, 0, ADCx}, /* PC12 UART5_TX/SDIO_CK */ - {&gpioc, NULL, NULL, 13, 0, ADCx}, /* PC13 TAMPER-RTC */ - {&gpioc, NULL, NULL, 14, 0, ADCx}, /* PC14 OSC32_IN */ - {&gpioc, NULL, NULL, 15, 0, ADCx}, /* PC15 OSC32_OUT */ + {&gpioc, NULL, &adc1, 0, 0, 10, 0}, /* PC0 */ + {&gpioc, NULL, &adc1, 1, 0, 11, 0}, /* PC1 */ + {&gpioc, NULL, &adc1, 2, 0, 12, 0}, /* PC2 */ + {&gpioc, NULL, &adc1, 3, 0, 13, 0}, /* PC3 */ + {&gpioc, NULL, &adc1, 4, 0, 14, 0}, /* PC4 */ + {&gpioc, NULL, &adc1, 5, 0, 15, 0}, /* PC5 */ + {&gpioc, &timer8, NULL, 6, 1, ADCx, 0}, /* PC6 */ + {&gpioc, &timer8, NULL, 7, 2, ADCx, 0}, /* PC7 */ + {&gpioc, &timer8, NULL, 8, 3, ADCx, 0}, /* PC8 */ + {&gpioc, &timer8, NULL, 9, 4, ADCx, 0}, /* PC9 */ + {&gpioc, NULL, NULL, 10, 0, ADCx, 0}, /* PC10 UART4_TX/SDIO_D2 */ + {&gpioc, NULL, NULL, 11, 0, ADCx, 0}, /* PC11 UART4_RX/SDIO_D3 */ + {&gpioc, NULL, NULL, 12, 0, ADCx, 0}, /* PC12 UART5_TX/SDIO_CK */ + {&gpioc, NULL, NULL, 13, 0, ADCx, 0}, /* PC13 TAMPER-RTC */ + {&gpioc, NULL, NULL, 14, 0, ADCx, 0}, /* PC14 OSC32_IN */ + {&gpioc, NULL, NULL, 15, 0, ADCx, 0}, /* PC15 OSC32_OUT */ - {&gpiod, NULL, NULL, 0, 0, ADCx} , /* PD0 OSC_IN */ - {&gpiod, NULL, NULL, 1, 0, ADCx} , /* PD1 OSC_OUT */ - {&gpiod, NULL, NULL, 2, 0, ADCx} , /* PD2 TIM3_ETR/UART5_RX SDIO_CMD */ + {&gpiod, NULL, NULL, 0, 0, ADCx, 0} , /* PD0 OSC_IN */ + {&gpiod, NULL, NULL, 1, 0, ADCx, 0} , /* PD1 OSC_OUT */ + {&gpiod, NULL, NULL, 2, 0, ADCx, 0} , /* PD2 TIM3_ETR/UART5_RX SDIO_CMD */ }; -#pragma GCC diagnostic pop /* Basically everything that is defined as having a timer us PWM */ extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { diff --git a/STM32F1/variants/generic_stm32f103r8/board.cpp b/STM32F1/variants/generic_stm32f103r8/board.cpp index 1987651..f667d2f 100644 --- a/STM32F1/variants/generic_stm32f103r8/board.cpp +++ b/STM32F1/variants/generic_stm32f103r8/board.cpp @@ -51,68 +51,65 @@ void boardInit(void) { } // Note. See the enum of pin names in board.h -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wmissing-field-initializers" extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { - {&gpioa, &timer2, &adc1, 0, 1, 0}, /* PA0 */ - {&gpioa, &timer2, &adc1, 1, 2, 1}, /* PA1 */ - {&gpioa, &timer2, &adc1, 2, 3, 2}, /* PA2 */ - {&gpioa, &timer2, &adc1, 3, 4, 3}, /* PA3 */ - {&gpioa, NULL, &adc1, 4, 0, 4}, /* PA4 */ - {&gpioa, NULL, &adc1, 5, 0, 5}, /* PA5 */ - {&gpioa, &timer3, &adc1, 6, 1, 6}, /* PA6 */ - {&gpioa, &timer3, &adc1, 7, 2, 7}, /* PA7 */ - {&gpioa, &timer1, NULL, 8, 1, ADCx}, /* PA8 */ - {&gpioa, &timer1, NULL, 9, 2, ADCx}, /* PA9 */ - {&gpioa, &timer1, NULL, 10, 3, ADCx}, /* PA10 */ - {&gpioa, &timer1, NULL, 11, 4, ADCx}, /* PA11 */ - {&gpioa, NULL, NULL, 12, 0, ADCx}, /* PA12 */ - {&gpioa, NULL, NULL, 13, 0, ADCx}, /* PA13 */ - {&gpioa, NULL, NULL, 14, 0, ADCx}, /* PA14 */ - {&gpioa, NULL, NULL, 15, 0, ADCx}, /* PA15 */ + {&gpioa, &timer2, &adc1, 0, 1, 0, 0}, /* PA0 */ + {&gpioa, &timer2, &adc1, 1, 2, 1, 0}, /* PA1 */ + {&gpioa, &timer2, &adc1, 2, 3, 2, 0}, /* PA2 */ + {&gpioa, &timer2, &adc1, 3, 4, 3, 0}, /* PA3 */ + {&gpioa, NULL, &adc1, 4, 0, 4, 0}, /* PA4 */ + {&gpioa, NULL, &adc1, 5, 0, 5, 0}, /* PA5 */ + {&gpioa, &timer3, &adc1, 6, 1, 6, 0}, /* PA6 */ + {&gpioa, &timer3, &adc1, 7, 2, 7, 0}, /* PA7 */ + {&gpioa, &timer1, NULL, 8, 1, ADCx, 0}, /* PA8 */ + {&gpioa, &timer1, NULL, 9, 2, ADCx, 0}, /* PA9 */ + {&gpioa, &timer1, NULL, 10, 3, ADCx, 0}, /* PA10 */ + {&gpioa, &timer1, NULL, 11, 4, ADCx, 0}, /* PA11 */ + {&gpioa, NULL, NULL, 12, 0, ADCx, 0}, /* PA12 */ + {&gpioa, NULL, NULL, 13, 0, ADCx, 0}, /* PA13 */ + {&gpioa, NULL, NULL, 14, 0, ADCx, 0}, /* PA14 */ + {&gpioa, NULL, NULL, 15, 0, ADCx, 0}, /* PA15 */ - {&gpiob, &timer3, &adc1, 0, 3, 8}, /* PB0 */ - {&gpiob, &timer3, &adc1, 1, 4, 9}, /* PB1 */ - {&gpiob, NULL, NULL, 2, 0, ADCx}, /* PB2 */ - {&gpiob, NULL, NULL, 3, 0, ADCx}, /* PB3 */ - {&gpiob, NULL, NULL, 4, 0, ADCx}, /* PB4 */ - {&gpiob, NULL, NULL, 5, 0, ADCx}, /* PB5 */ - {&gpiob, &timer4, NULL, 6, 1, ADCx}, /* PB6 */ - {&gpiob, &timer4, NULL, 7, 2, ADCx}, /* PB7 */ - {&gpiob, &timer4, NULL, 8, 3, ADCx}, /* PB8 */ - {&gpiob, &timer4, NULL, 9, 4, ADCx}, /* PB9 */ - {&gpiob, NULL, NULL, 10, 0, ADCx}, /* PB10 */ - {&gpiob, NULL, NULL, 11, 0, ADCx}, /* PB11 */ - {&gpiob, NULL, NULL, 12, 0, ADCx}, /* PB12 */ - {&gpiob, NULL, NULL, 13, 0, ADCx}, /* PB13 */ - {&gpiob, NULL, NULL, 14, 0, ADCx}, /* PB14 */ - {&gpiob, NULL, NULL, 15, 0, ADCx}, /* PB15 */ + {&gpiob, &timer3, &adc1, 0, 3, 8, 0}, /* PB0 */ + {&gpiob, &timer3, &adc1, 1, 4, 9, 0}, /* PB1 */ + {&gpiob, NULL, NULL, 2, 0, ADCx, 0}, /* PB2 */ + {&gpiob, NULL, NULL, 3, 0, ADCx, 0}, /* PB3 */ + {&gpiob, NULL, NULL, 4, 0, ADCx, 0}, /* PB4 */ + {&gpiob, NULL, NULL, 5, 0, ADCx, 0}, /* PB5 */ + {&gpiob, &timer4, NULL, 6, 1, ADCx, 0}, /* PB6 */ + {&gpiob, &timer4, NULL, 7, 2, ADCx, 0}, /* PB7 */ + {&gpiob, &timer4, NULL, 8, 3, ADCx, 0}, /* PB8 */ + {&gpiob, &timer4, NULL, 9, 4, ADCx, 0}, /* PB9 */ + {&gpiob, NULL, NULL, 10, 0, ADCx, 0}, /* PB10 */ + {&gpiob, NULL, NULL, 11, 0, ADCx, 0}, /* PB11 */ + {&gpiob, NULL, NULL, 12, 0, ADCx, 0}, /* PB12 */ + {&gpiob, NULL, NULL, 13, 0, ADCx, 0}, /* PB13 */ + {&gpiob, NULL, NULL, 14, 0, ADCx, 0}, /* PB14 */ + {&gpiob, NULL, NULL, 15, 0, ADCx, 0}, /* PB15 */ /* Andy Hull - the R8 is similar to the C8 but exposes more GPIO as follows */ - {&gpioc, NULL, &adc1, 0, 0, 10}, /* PC0 */ - {&gpioc, NULL, &adc1, 1, 0, 11}, /* PC1 */ - {&gpioc, NULL, &adc1, 2, 0, 12}, /* PC2 */ - {&gpioc, NULL, &adc1, 3, 0, 13}, /* PC3 */ - {&gpioc, NULL, &adc1, 4, 0, 14}, /* PC4 */ - {&gpioc, NULL, &adc1, 5, 0, 15}, /* PC5 */ + {&gpioc, NULL, &adc1, 0, 0, 10, 0}, /* PC0 */ + {&gpioc, NULL, &adc1, 1, 0, 11, 0}, /* PC1 */ + {&gpioc, NULL, &adc1, 2, 0, 12, 0}, /* PC2 */ + {&gpioc, NULL, &adc1, 3, 0, 13, 0}, /* PC3 */ + {&gpioc, NULL, &adc1, 4, 0, 14, 0}, /* PC4 */ + {&gpioc, NULL, &adc1, 5, 0, 15, 0}, /* PC5 */ - {&gpioc, NULL, NULL, 6, 0, ADCx}, /* PC6 */ - {&gpioc, NULL, NULL, 7, 0, ADCx}, /* PC7 */ - {&gpioc, NULL, NULL, 8, 0, ADCx}, /* PC8 */ - {&gpioc, NULL, NULL, 9, 0, ADCx}, /* PC9 */ + {&gpioc, NULL, NULL, 6, 0, ADCx, 0}, /* PC6 */ + {&gpioc, NULL, NULL, 7, 0, ADCx, 0}, /* PC7 */ + {&gpioc, NULL, NULL, 8, 0, ADCx, 0}, /* PC8 */ + {&gpioc, NULL, NULL, 9, 0, ADCx, 0}, /* PC9 */ - {&gpioc, NULL, NULL, 10, 0, ADCx}, /* PC10 */ - {&gpioc, NULL, NULL, 11, 0, ADCx}, /* PC11 */ - {&gpioc, NULL, NULL, 12, 0, ADCx}, /* PC12 */ - {&gpioc, NULL, NULL, 13, 0, ADCx}, /* PC13 */ - {&gpioc, NULL, NULL, 14, 0, ADCx}, /* PC14 */ - {&gpioc, NULL, NULL, 15, 0, ADCx}, /* PC15 */ + {&gpioc, NULL, NULL, 10, 0, ADCx, 0}, /* PC10 */ + {&gpioc, NULL, NULL, 11, 0, ADCx, 0}, /* PC11 */ + {&gpioc, NULL, NULL, 12, 0, ADCx, 0}, /* PC12 */ + {&gpioc, NULL, NULL, 13, 0, ADCx, 0}, /* PC13 */ + {&gpioc, NULL, NULL, 14, 0, ADCx, 0}, /* PC14 */ + {&gpioc, NULL, NULL, 15, 0, ADCx, 0}, /* PC15 */ - {&gpiod, NULL, NULL, 2, 0, ADCx}, /* PD2 */ + {&gpiod, NULL, NULL, 2, 0, ADCx, 0}, /* PD2 */ }; -#pragma GCC diagnostic pop extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { PB0, PA7, PA6, PA3, PA2, PA1, PA0, PB7, PB6, PA10, PA9, PA8, PC6, PC7, PC8, PC9 diff --git a/STM32F1/variants/generic_stm32f103t/board.cpp b/STM32F1/variants/generic_stm32f103t/board.cpp index 003d225..85c252c 100644 --- a/STM32F1/variants/generic_stm32f103t/board.cpp +++ b/STM32F1/variants/generic_stm32f103t/board.cpp @@ -51,38 +51,35 @@ void boardInit(void) { } // Note. See the enum of pin names in board.h -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wmissing-field-initializers" extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { - {&gpioa, &timer2, &adc1, 0, 1, 0}, /* PA0 */ - {&gpioa, &timer2, &adc1, 1, 2, 1}, /* PA1 */ - {&gpioa, &timer2, &adc1, 2, 3, 2}, /* PA2 */ - {&gpioa, &timer2, &adc1, 3, 4, 3}, /* PA3 */ - {&gpioa, NULL, &adc1, 4, 0, 4}, /* PA4 */ - {&gpioa, NULL, &adc1, 5, 0, 5}, /* PA5 */ - {&gpioa, &timer3, &adc1, 6, 1, 6}, /* PA6 */ - {&gpioa, &timer3, &adc1, 7, 2, 7}, /* PA7 */ - {&gpioa, &timer1, NULL, 8, 1, ADCx}, /* PA8 */ - {&gpioa, &timer1, NULL, 9, 2, ADCx}, /* PA9 */ - {&gpioa, &timer1, NULL, 10, 3, ADCx}, /* PA10 */ - {&gpioa, &timer1, NULL, 11, 4, ADCx}, /* PA11 */ - {&gpioa, NULL, NULL, 12, 0, ADCx}, /* PA12 */ - {&gpioa, NULL, NULL, 13, 0, ADCx}, /* PA13 */ - {&gpioa, NULL, NULL, 14, 0, ADCx}, /* PA14 */ - {&gpioa, NULL, NULL, 15, 0, ADCx}, /* PA15 */ + {&gpioa, &timer2, &adc1, 0, 1, 0, 0}, /* PA0 */ + {&gpioa, &timer2, &adc1, 1, 2, 1, 0}, /* PA1 */ + {&gpioa, &timer2, &adc1, 2, 3, 2, 0}, /* PA2 */ + {&gpioa, &timer2, &adc1, 3, 4, 3, 0}, /* PA3 */ + {&gpioa, NULL, &adc1, 4, 0, 4, 0}, /* PA4 */ + {&gpioa, NULL, &adc1, 5, 0, 5, 0}, /* PA5 */ + {&gpioa, &timer3, &adc1, 6, 1, 6, 0}, /* PA6 */ + {&gpioa, &timer3, &adc1, 7, 2, 7, 0}, /* PA7 */ + {&gpioa, &timer1, NULL, 8, 1, ADCx, 0}, /* PA8 */ + {&gpioa, &timer1, NULL, 9, 2, ADCx, 0}, /* PA9 */ + {&gpioa, &timer1, NULL, 10, 3, ADCx, 0}, /* PA10 */ + {&gpioa, &timer1, NULL, 11, 4, ADCx, 0}, /* PA11 */ + {&gpioa, NULL, NULL, 12, 0, ADCx, 0}, /* PA12 */ + {&gpioa, NULL, NULL, 13, 0, ADCx, 0}, /* PA13 */ + {&gpioa, NULL, NULL, 14, 0, ADCx, 0}, /* PA14 */ + {&gpioa, NULL, NULL, 15, 0, ADCx, 0}, /* PA15 */ - {&gpiob, &timer3, &adc1, 0, 3, 8}, /* PB0 */ - {&gpiob, &timer3, &adc1, 1, 4, 9}, /* PB1 */ - {&gpiob, NULL, NULL, 2, 0, ADCx}, /* PB2 */ - {&gpiob, NULL, NULL, 3, 0, ADCx}, /* PB3 */ - {&gpiob, NULL, NULL, 4, 0, ADCx}, /* PB4 */ - {&gpiob, NULL, NULL, 5, 0, ADCx}, /* PB5 */ - {&gpiob, &timer4, NULL, 6, 1, ADCx}, /* PB6 */ - {&gpiob, &timer4, NULL, 7, 2, ADCx}, /* PB7 */ + {&gpiob, &timer3, &adc1, 0, 3, 8, 0}, /* PB0 */ + {&gpiob, &timer3, &adc1, 1, 4, 9, 0}, /* PB1 */ + {&gpiob, NULL, NULL, 2, 0, ADCx, 0}, /* PB2 */ + {&gpiob, NULL, NULL, 3, 0, ADCx, 0}, /* PB3 */ + {&gpiob, NULL, NULL, 4, 0, ADCx, 0}, /* PB4 */ + {&gpiob, NULL, NULL, 5, 0, ADCx, 0}, /* PB5 */ + {&gpiob, &timer4, NULL, 6, 1, ADCx, 0}, /* PB6 */ + {&gpiob, &timer4, NULL, 7, 2, ADCx, 0}, /* PB7 */ }; -#pragma GCC diagnostic pop extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { PB0, PA7, PA6, PA3, PA2, PA1, PA0, PB7, PB6, PA10, PA9, PA8 diff --git a/STM32F1/variants/generic_stm32f103v/board.cpp b/STM32F1/variants/generic_stm32f103v/board.cpp index 8b24169..a6b3165 100644 --- a/STM32F1/variants/generic_stm32f103v/board.cpp +++ b/STM32F1/variants/generic_stm32f103v/board.cpp @@ -68,8 +68,6 @@ void boardInit(void) { // - Timer channel (1 to 4, for PWM), or 0 if none // - ADC device, or NULL if none // - ADC channel, or ADCx if none -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wmissing-field-initializers" extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { /* gpio_dev *gpio_device; GPIO device @@ -80,94 +78,93 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { uint8 adc_channel; Pin ADC channel, or ADCx if none. */ - {&gpioa, &timer2, &adc1, 0, 1, 0}, /* PA0 */ - {&gpioa, &timer2, &adc1, 1, 2, 1}, /* PA1 */ - {&gpioa, &timer2, &adc1, 2, 3, 2}, /* PA2 */ - {&gpioa, &timer2, &adc1, 3, 4, 3}, /* PA3 */ - {&gpioa, NULL, &adc1, 4, 0, 4}, /* PA4 */ - {&gpioa, NULL, &adc1, 5, 0, 5}, /* PA5 */ - {&gpioa, &timer3, &adc1, 6, 1, 6}, /* PA6 */ - {&gpioa, &timer3, &adc1, 7, 2, 7}, /* PA7 */ - {&gpioa, &timer1, NULL, 8, 1, ADCx}, /* PA8 */ - {&gpioa, &timer1, NULL, 9, 2, ADCx}, /* PA9 */ - {&gpioa, &timer1, NULL, 10, 3, ADCx}, /* PA10 */ - {&gpioa, NULL, NULL, 11, 0, ADCx}, /* PA11 */ //Could have &timer1_CH4, but is also CAN_RX and USBDM - {&gpioa, NULL, NULL, 12, 0, ADCx}, /* PA12 */ //Could have &timer1_ETR, but is also CAN_TX and USBDP - {&gpioa, NULL, NULL, 13, 0, ADCx}, /* PA13 */ - {&gpioa, NULL, NULL, 14, 0, ADCx}, /* PA14 */ - {&gpioa, NULL, NULL, 15, 0, ADCx}, /* PA15 */ //SPI3_NSS + {&gpioa, &timer2, &adc1, 0, 1, 0, 0}, /* PA0 */ + {&gpioa, &timer2, &adc1, 1, 2, 1, 0}, /* PA1 */ + {&gpioa, &timer2, &adc1, 2, 3, 2, 0}, /* PA2 */ + {&gpioa, &timer2, &adc1, 3, 4, 3, 0}, /* PA3 */ + {&gpioa, NULL, &adc1, 4, 0, 4, 0}, /* PA4 */ + {&gpioa, NULL, &adc1, 5, 0, 5, 0}, /* PA5 */ + {&gpioa, &timer3, &adc1, 6, 1, 6, 0}, /* PA6 */ + {&gpioa, &timer3, &adc1, 7, 2, 7, 0}, /* PA7 */ + {&gpioa, &timer1, NULL, 8, 1, ADCx, 0}, /* PA8 */ + {&gpioa, &timer1, NULL, 9, 2, ADCx, 0}, /* PA9 */ + {&gpioa, &timer1, NULL, 10, 3, ADCx, 0}, /* PA10 */ + {&gpioa, NULL, NULL, 11, 0, ADCx, 0}, /* PA11 */ //Could have &timer1_CH4, but is also CAN_RX and USBDM + {&gpioa, NULL, NULL, 12, 0, ADCx, 0}, /* PA12 */ //Could have &timer1_ETR, but is also CAN_TX and USBDP + {&gpioa, NULL, NULL, 13, 0, ADCx, 0}, /* PA13 */ + {&gpioa, NULL, NULL, 14, 0, ADCx, 0}, /* PA14 */ + {&gpioa, NULL, NULL, 15, 0, ADCx, 0}, /* PA15 */ //SPI3_NSS - {&gpiob, &timer3, &adc1, 0, 3, 8}, /* PB0 */ - {&gpiob, &timer3, &adc1, 1, 4, 9}, /* PB1 */ + {&gpiob, &timer3, &adc1, 0, 3, 8, 0}, /* PB0 */ + {&gpiob, &timer3, &adc1, 1, 4, 9, 0}, /* PB1 */ /* NOTE PB2 is not included as its Boot 1 */ - {&gpiob, NULL, NULL, 3, 0, ADCx}, /* PB3 */ //JTDO, SPI3_SCK / I2S3_CK/ - {&gpiob, NULL, NULL, 4, 0, ADCx}, /* PB4 */ //NJTRST, SPI3_MISO - {&gpiob, NULL, NULL, 5, 0, ADCx}, /* PB5 */ //I2C1_SMBA/ SPI3_MOSI - {&gpiob, &timer4, NULL, 6, 1, ADCx}, /* PB6 */ //I2C1_SCL(9) - {&gpiob, &timer4, NULL, 7, 2, ADCx}, /* PB7 */ //I2C1_SDA(9) / FSMC_NADV - {&gpiob, &timer4, NULL, 8, 3, ADCx}, /* PB8 */ //SDIO_D4 - {&gpiob, &timer4, NULL, 9, 4, ADCx}, /* PB9 */ //SDIO_D5 - {&gpiob, NULL, NULL, 10, 0, ADCx}, /* PB10 */ //I2C2_SCL/USART3_TX - {&gpiob, NULL, NULL, 11, 0, ADCx}, /* PB11 */ //I2C2_SDA/USART3_RX - {&gpiob, NULL, NULL, 12, 0, ADCx}, /* PB12 */ //SPI2_NSS/I2S2_WS/I2C2_SMBA/USART3_CK - {&gpiob, NULL, NULL, 13, 0, ADCx}, /* PB13 */ //SPI2_SCK/I2S2_CK/USART3_CTS - {&gpiob, NULL, NULL, 14, 0, ADCx}, /* PB14 */ //SPI2_MISO/TIM1_CH2N/USART3_RTS - {&gpiob, NULL, NULL, 15, 0, ADCx}, /* PB15 */ //SPI2_MOSI/I2S2_SD + {&gpiob, NULL, NULL, 3, 0, ADCx, 0}, /* PB3 */ //JTDO, SPI3_SCK / I2S3_CK/ + {&gpiob, NULL, NULL, 4, 0, ADCx, 0}, /* PB4 */ //NJTRST, SPI3_MISO + {&gpiob, NULL, NULL, 5, 0, ADCx, 0}, /* PB5 */ //I2C1_SMBA/ SPI3_MOSI + {&gpiob, &timer4, NULL, 6, 1, ADCx, 0}, /* PB6 */ //I2C1_SCL(9) + {&gpiob, &timer4, NULL, 7, 2, ADCx, 0}, /* PB7 */ //I2C1_SDA(9) / FSMC_NADV + {&gpiob, &timer4, NULL, 8, 3, ADCx, 0}, /* PB8 */ //SDIO_D4 + {&gpiob, &timer4, NULL, 9, 4, ADCx, 0}, /* PB9 */ //SDIO_D5 + {&gpiob, NULL, NULL, 10, 0, ADCx, 0}, /* PB10 */ //I2C2_SCL/USART3_TX + {&gpiob, NULL, NULL, 11, 0, ADCx, 0}, /* PB11 */ //I2C2_SDA/USART3_RX + {&gpiob, NULL, NULL, 12, 0, ADCx, 0}, /* PB12 */ //SPI2_NSS/I2S2_WS/I2C2_SMBA/USART3_CK + {&gpiob, NULL, NULL, 13, 0, ADCx, 0}, /* PB13 */ //SPI2_SCK/I2S2_CK/USART3_CTS + {&gpiob, NULL, NULL, 14, 0, ADCx, 0}, /* PB14 */ //SPI2_MISO/TIM1_CH2N/USART3_RTS + {&gpiob, NULL, NULL, 15, 0, ADCx, 0}, /* PB15 */ //SPI2_MOSI/I2S2_SD - {&gpioc, NULL, &adc1, 0, 0, 10}, /* PC0 */ - {&gpioc, NULL, &adc1, 1, 0, 11}, /* PC1 */ - {&gpioc, NULL, &adc1, 2, 0, 12}, /* PC2 */ - {&gpioc, NULL, &adc1, 3, 0, 13}, /* PC3 */ - {&gpioc, NULL, &adc1, 4, 0, 14}, /* PC4 */ - {&gpioc, NULL, &adc1, 5, 0, 15}, /* PC5 */ - {&gpioc, &timer8, NULL, 6, 1, ADCx}, /* PC6 I2S2_MCK/SDIO_D6*/ - {&gpioc, &timer8, NULL, 7, 2, ADCx}, /* PC7 I2S3_MCK/SDIO_D7*/ - {&gpioc, &timer8, NULL, 8, 3, ADCx}, /* PC8 SDIO_D0*/ - {&gpioc, &timer8, NULL, 9, 4, ADCx}, /* PC9 SDIO_D1*/ - {&gpioc, NULL, NULL, 10, 0, ADCx}, /* PC10 UART4_TX/SDIO_D2 */ - {&gpioc, NULL, NULL, 11, 0, ADCx}, /* PC11 UART4_RX/SDIO_D3 */ - {&gpioc, NULL, NULL, 12, 0, ADCx}, /* PC12 UART5_TX/SDIO_CK */ - {&gpioc, NULL, NULL, 13, 0, ADCx}, /* PC13 TAMPER-RTC/ Limited output*/ - {&gpioc, NULL, NULL, 14, 0, ADCx}, /* PC14 OSC32_IN/ Limited output*/ - {&gpioc, NULL, NULL, 15, 0, ADCx}, /* PC15 OSC32_OUT/ Limited output*/ + {&gpioc, NULL, &adc1, 0, 0, 10, 0}, /* PC0 */ + {&gpioc, NULL, &adc1, 1, 0, 11, 0}, /* PC1 */ + {&gpioc, NULL, &adc1, 2, 0, 12, 0}, /* PC2 */ + {&gpioc, NULL, &adc1, 3, 0, 13, 0}, /* PC3 */ + {&gpioc, NULL, &adc1, 4, 0, 14, 0}, /* PC4 */ + {&gpioc, NULL, &adc1, 5, 0, 15, 0}, /* PC5 */ + {&gpioc, &timer8, NULL, 6, 1, ADCx, 0}, /* PC6 I2S2_MCK/SDIO_D6*/ + {&gpioc, &timer8, NULL, 7, 2, ADCx, 0}, /* PC7 I2S3_MCK/SDIO_D7*/ + {&gpioc, &timer8, NULL, 8, 3, ADCx, 0}, /* PC8 SDIO_D0*/ + {&gpioc, &timer8, NULL, 9, 4, ADCx, 0}, /* PC9 SDIO_D1*/ + {&gpioc, NULL, NULL, 10, 0, ADCx, 0}, /* PC10 UART4_TX/SDIO_D2 */ + {&gpioc, NULL, NULL, 11, 0, ADCx, 0}, /* PC11 UART4_RX/SDIO_D3 */ + {&gpioc, NULL, NULL, 12, 0, ADCx, 0}, /* PC12 UART5_TX/SDIO_CK */ + {&gpioc, NULL, NULL, 13, 0, ADCx, 0}, /* PC13 TAMPER-RTC/ Limited output*/ + {&gpioc, NULL, NULL, 14, 0, ADCx, 0}, /* PC14 OSC32_IN/ Limited output*/ + {&gpioc, NULL, NULL, 15, 0, ADCx, 0}, /* PC15 OSC32_OUT/ Limited output*/ - {&gpiod, NULL, NULL, 0, 0, ADCx} , /* PD0 OSC_IN */ - {&gpiod, NULL, NULL, 1, 0, ADCx} , /* PD1 OSC_OUT */ - {&gpiod, NULL, NULL, 2, 0, ADCx} , /* PD2 TIM3_ETR/UART5_RX SDIO_CMD */ - {&gpiod, NULL, NULL, 3, 0, ADCx} , /* PD3 FSMC_CLK */ - {&gpiod, NULL, NULL, 4, 0, ADCx} , /* PD4 FSMC_NOE */ - {&gpiod, NULL, NULL, 5, 0, ADCx} , /* PD5 FSMC_NWE */ - {&gpiod, NULL, NULL, 6, 0, ADCx} , /* PD6 FSMC_NWAIT */ - {&gpiod, NULL, NULL, 7, 0, ADCx} , /* PD7 FSMC_NE1/FSMC_NCE2 */ - {&gpiod, NULL, NULL, 8, 0, ADCx} , /* PD8 FSMC_D13 */ - {&gpiod, NULL, NULL, 9, 0, ADCx} , /* PD9 FSMC_D14 */ - {&gpiod, NULL, NULL, 10, 0, ADCx} , /* PD10 FSMC_D15 */ - {&gpiod, NULL, NULL, 11, 0, ADCx} , /* PD11 FSMC_A16 */ - {&gpiod, NULL, NULL, 12, 0, ADCx} , /* PD12 FSMC_A17 */ - {&gpiod, NULL, NULL, 13, 0, ADCx} , /* PD13 FSMC_A18 */ - {&gpiod, NULL, NULL, 14, 0, ADCx} , /* PD14 FSMC_D0 */ - {&gpiod, NULL, NULL, 15, 0, ADCx} , /* PD15 FSMC_D1 */ + {&gpiod, NULL, NULL, 0, 0, ADCx, 0} , /* PD0 OSC_IN */ + {&gpiod, NULL, NULL, 1, 0, ADCx, 0} , /* PD1 OSC_OUT */ + {&gpiod, NULL, NULL, 2, 0, ADCx, 0} , /* PD2 TIM3_ETR/UART5_RX SDIO_CMD */ + {&gpiod, NULL, NULL, 3, 0, ADCx, 0} , /* PD3 FSMC_CLK */ + {&gpiod, NULL, NULL, 4, 0, ADCx, 0} , /* PD4 FSMC_NOE */ + {&gpiod, NULL, NULL, 5, 0, ADCx, 0} , /* PD5 FSMC_NWE */ + {&gpiod, NULL, NULL, 6, 0, ADCx, 0} , /* PD6 FSMC_NWAIT */ + {&gpiod, NULL, NULL, 7, 0, ADCx, 0} , /* PD7 FSMC_NE1/FSMC_NCE2 */ + {&gpiod, NULL, NULL, 8, 0, ADCx, 0} , /* PD8 FSMC_D13 */ + {&gpiod, NULL, NULL, 9, 0, ADCx, 0} , /* PD9 FSMC_D14 */ + {&gpiod, NULL, NULL, 10, 0, ADCx, 0} , /* PD10 FSMC_D15 */ + {&gpiod, NULL, NULL, 11, 0, ADCx, 0} , /* PD11 FSMC_A16 */ + {&gpiod, NULL, NULL, 12, 0, ADCx, 0} , /* PD12 FSMC_A17 */ + {&gpiod, NULL, NULL, 13, 0, ADCx, 0} , /* PD13 FSMC_A18 */ + {&gpiod, NULL, NULL, 14, 0, ADCx, 0} , /* PD14 FSMC_D0 */ + {&gpiod, NULL, NULL, 15, 0, ADCx, 0} , /* PD15 FSMC_D1 */ - {&gpioe, NULL, NULL, 0, 0, ADCx} , /* PE0 TIM4_ETR / FSMC_NBL0 */ - {&gpioe, NULL, NULL, 1, 0, ADCx} , /* PE1 FSMC_NBL1 */ - {&gpioe, NULL, NULL, 2, 0, ADCx} , /* PE2 TRACECK/ FSMC_A23 */ - {&gpioe, NULL, NULL, 3, 0, ADCx} , /* PE3 TRACED0/FSMC_A19 */ - {&gpioe, NULL, NULL, 4, 0, ADCx} , /* PE4 TRACED1/FSMC_A20 */ - {&gpioe, NULL, NULL, 5, 0, ADCx} , /* PE5 TRACED2/FSMC_A21 */ - {&gpioe, NULL, NULL, 6, 0, ADCx} , /* PE6 TRACED3/FSMC_A22 */ - {&gpioe, NULL, NULL, 7, 0, ADCx} , /* PE7 FSMC_D4 */ - {&gpioe, NULL, NULL, 8, 0, ADCx} , /* PE8 FSMC_D5 */ - {&gpioe, NULL, NULL, 9, 0, ADCx} , /* PE9 FSMC_D6 */ - {&gpioe, NULL, NULL, 10, 0, ADCx} , /* PE10 FSMC_D7 */ - {&gpioe, NULL, NULL, 11, 0, ADCx} , /* PE11 FSMC_D8 */ - {&gpioe, NULL, NULL, 12, 0, ADCx} , /* PE12 FSMC_D9 */ - {&gpioe, NULL, NULL, 13, 0, ADCx} , /* PE13 FSMC_D10 */ - {&gpioe, NULL, NULL, 14, 0, ADCx} , /* PE14 FSMC_D11 */ - {&gpioe, NULL, NULL, 15, 0, ADCx} , /* PE15 FSMC_D12 */ + {&gpioe, NULL, NULL, 0, 0, ADCx, 0} , /* PE0 TIM4_ETR / FSMC_NBL0 */ + {&gpioe, NULL, NULL, 1, 0, ADCx, 0} , /* PE1 FSMC_NBL1 */ + {&gpioe, NULL, NULL, 2, 0, ADCx, 0} , /* PE2 TRACECK/ FSMC_A23 */ + {&gpioe, NULL, NULL, 3, 0, ADCx, 0} , /* PE3 TRACED0/FSMC_A19 */ + {&gpioe, NULL, NULL, 4, 0, ADCx, 0} , /* PE4 TRACED1/FSMC_A20 */ + {&gpioe, NULL, NULL, 5, 0, ADCx, 0} , /* PE5 TRACED2/FSMC_A21 */ + {&gpioe, NULL, NULL, 6, 0, ADCx, 0} , /* PE6 TRACED3/FSMC_A22 */ + {&gpioe, NULL, NULL, 7, 0, ADCx, 0} , /* PE7 FSMC_D4 */ + {&gpioe, NULL, NULL, 8, 0, ADCx, 0} , /* PE8 FSMC_D5 */ + {&gpioe, NULL, NULL, 9, 0, ADCx, 0} , /* PE9 FSMC_D6 */ + {&gpioe, NULL, NULL, 10, 0, ADCx, 0} , /* PE10 FSMC_D7 */ + {&gpioe, NULL, NULL, 11, 0, ADCx, 0} , /* PE11 FSMC_D8 */ + {&gpioe, NULL, NULL, 12, 0, ADCx, 0} , /* PE12 FSMC_D9 */ + {&gpioe, NULL, NULL, 13, 0, ADCx, 0} , /* PE13 FSMC_D10 */ + {&gpioe, NULL, NULL, 14, 0, ADCx, 0} , /* PE14 FSMC_D11 */ + {&gpioe, NULL, NULL, 15, 0, ADCx, 0} , /* PE15 FSMC_D12 */ }; -#pragma GCC diagnostic pop /* Basically everything that is defined as having a timer us PWM */ extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { diff --git a/STM32F1/variants/generic_stm32f103z/board.cpp b/STM32F1/variants/generic_stm32f103z/board.cpp index 4d2e4e9..0d112a3 100644 --- a/STM32F1/variants/generic_stm32f103z/board.cpp +++ b/STM32F1/variants/generic_stm32f103z/board.cpp @@ -69,8 +69,6 @@ void boardInit(void) { // - ADC device, or NULL if none // - ADC channel, or ADCx if none -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wmissing-field-initializers" extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { /* gpio_dev *gpio_device; GPIO device @@ -82,128 +80,127 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { uint8 pinMode; mode specific by pinMode call (Roger Clark added to optimize compatibility with Arduino API */ - {&gpioa, &timer2, &adc1, 0, 1, 0}, /* PA0 */ - {&gpioa, &timer2, &adc1, 1, 2, 1}, /* PA1 */ - {&gpioa, &timer2, &adc1, 2, 3, 2}, /* PA2 */ - {&gpioa, &timer2, &adc1, 3, 4, 3}, /* PA3 */ - {&gpioa, NULL, &adc1, 4, 0, 4}, /* PA4 */ - {&gpioa, NULL, &adc1, 5, 0, 5}, /* PA5 */ - {&gpioa, &timer3, &adc1, 6, 1, 6}, /* PA6 */ - {&gpioa, &timer3, &adc1, 7, 2, 7}, /* PA7 */ - {&gpioa, &timer1, NULL, 8, 1, ADCx}, /* PA8 */ - {&gpioa, &timer1, NULL, 9, 2, ADCx}, /* PA9 */ - {&gpioa, &timer1, NULL, 10, 3, ADCx}, /* PA10 */ - {&gpioa, NULL, NULL, 11, 0, ADCx}, /* PA11 */ - {&gpioa, NULL, NULL, 12, 0, ADCx}, /* PA12 */ - {&gpioa, NULL, NULL, 13, 0, ADCx}, /* PA13 */ - {&gpioa, NULL, NULL, 14, 0, ADCx}, /* PA14 */ - {&gpioa, NULL, NULL, 15, 0, ADCx}, /* PA15 */ + {&gpioa, &timer2, &adc1, 0, 1, 0, 0}, /* PA0 */ + {&gpioa, &timer2, &adc1, 1, 2, 1, 0}, /* PA1 */ + {&gpioa, &timer2, &adc1, 2, 3, 2, 0}, /* PA2 */ + {&gpioa, &timer2, &adc1, 3, 4, 3, 0}, /* PA3 */ + {&gpioa, NULL, &adc1, 4, 0, 4, 0}, /* PA4 */ + {&gpioa, NULL, &adc1, 5, 0, 5, 0}, /* PA5 */ + {&gpioa, &timer3, &adc1, 6, 1, 6, 0}, /* PA6 */ + {&gpioa, &timer3, &adc1, 7, 2, 7, 0}, /* PA7 */ + {&gpioa, &timer1, NULL, 8, 1, ADCx, 0}, /* PA8 */ + {&gpioa, &timer1, NULL, 9, 2, ADCx, 0}, /* PA9 */ + {&gpioa, &timer1, NULL, 10, 3, ADCx, 0}, /* PA10 */ + {&gpioa, NULL, NULL, 11, 0, ADCx, 0}, /* PA11 */ + {&gpioa, NULL, NULL, 12, 0, ADCx, 0}, /* PA12 */ + {&gpioa, NULL, NULL, 13, 0, ADCx, 0}, /* PA13 */ + {&gpioa, NULL, NULL, 14, 0, ADCx, 0}, /* PA14 */ + {&gpioa, NULL, NULL, 15, 0, ADCx, 0}, /* PA15 */ - {&gpiob, &timer3, &adc1, 0, 3, 8}, /* PB0 */ - {&gpiob, &timer3, &adc1, 1, 4, 9}, /* PB1 */ - {&gpiob, &timer3, &adc1, 2, 4, 9}, /* PB2 */ - {&gpiob, NULL, NULL, 3, 0, ADCx}, /* PB3 */ - {&gpiob, NULL, NULL, 4, 0, ADCx}, /* PB4 */ - {&gpiob, NULL, NULL, 5, 0, ADCx}, /* PB5 */ - {&gpiob, &timer4, NULL, 6, 1, ADCx}, /* PB6 */ - {&gpiob, &timer4, NULL, 7, 2, ADCx}, /* PB7 */ - {&gpiob, &timer4, NULL, 8, 3, ADCx}, /* PB8 */ - {&gpiob, &timer4, NULL, 9, 4, ADCx}, /* PB9 */ - {&gpiob, NULL, NULL, 10, 0, ADCx}, /* PB10 */ - {&gpiob, NULL, NULL, 11, 0, ADCx}, /* PB11 */ - {&gpiob, NULL, NULL, 12, 0, ADCx}, /* PB12 */ - {&gpiob, NULL, NULL, 13, 0, ADCx}, /* PB13 */ - {&gpiob, NULL, NULL, 14, 0, ADCx}, /* PB14 */ - {&gpiob, NULL, NULL, 15, 0, ADCx}, /* PB15 */ + {&gpiob, &timer3, &adc1, 0, 3, 8, 0}, /* PB0 */ + {&gpiob, &timer3, &adc1, 1, 4, 9, 0}, /* PB1 */ + {&gpiob, &timer3, &adc1, 2, 4, 9, 0}, /* PB2 */ + {&gpiob, NULL, NULL, 3, 0, ADCx, 0}, /* PB3 */ + {&gpiob, NULL, NULL, 4, 0, ADCx, 0}, /* PB4 */ + {&gpiob, NULL, NULL, 5, 0, ADCx, 0}, /* PB5 */ + {&gpiob, &timer4, NULL, 6, 1, ADCx, 0}, /* PB6 */ + {&gpiob, &timer4, NULL, 7, 2, ADCx, 0}, /* PB7 */ + {&gpiob, &timer4, NULL, 8, 3, ADCx, 0}, /* PB8 */ + {&gpiob, &timer4, NULL, 9, 4, ADCx, 0}, /* PB9 */ + {&gpiob, NULL, NULL, 10, 0, ADCx, 0}, /* PB10 */ + {&gpiob, NULL, NULL, 11, 0, ADCx, 0}, /* PB11 */ + {&gpiob, NULL, NULL, 12, 0, ADCx, 0}, /* PB12 */ + {&gpiob, NULL, NULL, 13, 0, ADCx, 0}, /* PB13 */ + {&gpiob, NULL, NULL, 14, 0, ADCx, 0}, /* PB14 */ + {&gpiob, NULL, NULL, 15, 0, ADCx, 0}, /* PB15 */ - {&gpioc, NULL, &adc1, 0, 0, 10}, /* PC0 */ - {&gpioc, NULL, &adc1, 1, 0, 11}, /* PC1 */ - {&gpioc, NULL, &adc1, 2, 0, 12}, /* PC2 */ - {&gpioc, NULL, &adc1, 3, 0, 13}, /* PC3 */ - {&gpioc, NULL, &adc1, 4, 0, 14}, /* PC4 */ - {&gpioc, NULL, &adc1, 5, 0, 15}, /* PC5 */ - {&gpioc, &timer8, NULL, 6, 1, ADCx}, /* PC6 */ - {&gpioc, &timer8, NULL, 7, 2, ADCx}, /* PC7 */ - {&gpioc, &timer8, NULL, 8, 3, ADCx}, /* PC8 */ - {&gpioc, &timer8, NULL, 9, 4, ADCx}, /* PC9 */ - {&gpioc, NULL, NULL, 10, 0, ADCx}, /* PC10 UART4_TX/SDIO_D2 */ - {&gpioc, NULL, NULL, 11, 0, ADCx}, /* PC11 UART4_RX/SDIO_D3 */ - {&gpioc, NULL, NULL, 12, 0, ADCx}, /* PC12 UART5_TX/SDIO_CK */ - {&gpioc, NULL, NULL, 13, 0, ADCx}, /* PC13 TAMPER-RTC */ - {&gpioc, NULL, NULL, 14, 0, ADCx}, /* PC14 OSC32_IN */ - {&gpioc, NULL, NULL, 15, 0, ADCx}, /* PC15 OSC32_OUT */ + {&gpioc, NULL, &adc1, 0, 0, 10, 0}, /* PC0 */ + {&gpioc, NULL, &adc1, 1, 0, 11, 0}, /* PC1 */ + {&gpioc, NULL, &adc1, 2, 0, 12, 0}, /* PC2 */ + {&gpioc, NULL, &adc1, 3, 0, 13, 0}, /* PC3 */ + {&gpioc, NULL, &adc1, 4, 0, 14, 0}, /* PC4 */ + {&gpioc, NULL, &adc1, 5, 0, 15, 0}, /* PC5 */ + {&gpioc, &timer8, NULL, 6, 1, ADCx, 0}, /* PC6 */ + {&gpioc, &timer8, NULL, 7, 2, ADCx, 0}, /* PC7 */ + {&gpioc, &timer8, NULL, 8, 3, ADCx, 0}, /* PC8 */ + {&gpioc, &timer8, NULL, 9, 4, ADCx, 0}, /* PC9 */ + {&gpioc, NULL, NULL, 10, 0, ADCx, 0}, /* PC10 UART4_TX/SDIO_D2 */ + {&gpioc, NULL, NULL, 11, 0, ADCx, 0}, /* PC11 UART4_RX/SDIO_D3 */ + {&gpioc, NULL, NULL, 12, 0, ADCx, 0}, /* PC12 UART5_TX/SDIO_CK */ + {&gpioc, NULL, NULL, 13, 0, ADCx, 0}, /* PC13 TAMPER-RTC */ + {&gpioc, NULL, NULL, 14, 0, ADCx, 0}, /* PC14 OSC32_IN */ + {&gpioc, NULL, NULL, 15, 0, ADCx, 0}, /* PC15 OSC32_OUT */ - {&gpiod, NULL, NULL, 0, 0, ADCx} , /* PD0 OSC_IN */ - {&gpiod, NULL, NULL, 1, 0, ADCx} , /* PD1 OSC_OUT */ - {&gpiod, NULL, NULL, 2, 0, ADCx} , /* PD2 TIM3_ETR/UART5_RX SDIO_CMD */ + {&gpiod, NULL, NULL, 0, 0, ADCx, 0} , /* PD0 OSC_IN */ + {&gpiod, NULL, NULL, 1, 0, ADCx, 0} , /* PD1 OSC_OUT */ + {&gpiod, NULL, NULL, 2, 0, ADCx, 0} , /* PD2 TIM3_ETR/UART5_RX SDIO_CMD */ - {&gpiod, NULL, NULL, 3, 0, ADCx} , /* PD3 FSMC_CLK */ - {&gpiod, NULL, NULL, 4, 0, ADCx} , /* PD4 FSMC_NOE */ - {&gpiod, NULL, NULL, 5, 0, ADCx} , /* PD5 FSMC_NWE */ - {&gpiod, NULL, NULL, 6, 0, ADCx} , /* PD6 FSMC_NWAIT */ - {&gpiod, NULL, NULL, 7, 0, ADCx} , /* PD7 FSMC_NE1/FSMC_NCE2 */ - {&gpiod, NULL, NULL, 8, 0, ADCx} , /* PD8 FSMC_D13 */ - {&gpiod, NULL, NULL, 9, 0, ADCx} , /* PD9 FSMC_D14 */ - {&gpiod, NULL, NULL, 10, 0, ADCx} , /* PD10 FSMC_D15 */ - {&gpiod, NULL, NULL, 11, 0, ADCx} , /* PD11 FSMC_A16 */ - {&gpiod, NULL, NULL, 12, 0, ADCx} , /* PD12 FSMC_A17 */ - {&gpiod, NULL, NULL, 13, 0, ADCx} , /* PD13 FSMC_A18 */ - {&gpiod, NULL, NULL, 14, 0, ADCx} , /* PD14 FSMC_D0 */ - {&gpiod, NULL, NULL, 15, 0, ADCx} , /* PD15 FSMC_D1 */ + {&gpiod, NULL, NULL, 3, 0, ADCx, 0} , /* PD3 FSMC_CLK */ + {&gpiod, NULL, NULL, 4, 0, ADCx, 0} , /* PD4 FSMC_NOE */ + {&gpiod, NULL, NULL, 5, 0, ADCx, 0} , /* PD5 FSMC_NWE */ + {&gpiod, NULL, NULL, 6, 0, ADCx, 0} , /* PD6 FSMC_NWAIT */ + {&gpiod, NULL, NULL, 7, 0, ADCx, 0} , /* PD7 FSMC_NE1/FSMC_NCE2 */ + {&gpiod, NULL, NULL, 8, 0, ADCx, 0} , /* PD8 FSMC_D13 */ + {&gpiod, NULL, NULL, 9, 0, ADCx, 0} , /* PD9 FSMC_D14 */ + {&gpiod, NULL, NULL, 10, 0, ADCx, 0} , /* PD10 FSMC_D15 */ + {&gpiod, NULL, NULL, 11, 0, ADCx, 0} , /* PD11 FSMC_A16 */ + {&gpiod, NULL, NULL, 12, 0, ADCx, 0} , /* PD12 FSMC_A17 */ + {&gpiod, NULL, NULL, 13, 0, ADCx, 0} , /* PD13 FSMC_A18 */ + {&gpiod, NULL, NULL, 14, 0, ADCx, 0} , /* PD14 FSMC_D0 */ + {&gpiod, NULL, NULL, 15, 0, ADCx, 0} , /* PD15 FSMC_D1 */ - {&gpioe, NULL, NULL, 0, 0, ADCx} , /* PE0 */ - {&gpioe, NULL, NULL, 1, 0, ADCx} , /* PE1 */ - {&gpioe, NULL, NULL, 2, 0, ADCx} , /* PE2 */ - {&gpioe, NULL, NULL, 3, 0, ADCx} , /* PE3 */ - {&gpioe, NULL, NULL, 4, 0, ADCx} , /* PE4 */ - {&gpioe, NULL, NULL, 5, 0, ADCx} , /* PE5 */ - {&gpioe, NULL, NULL, 6, 0, ADCx} , /* PE6 */ - {&gpioe, NULL, NULL, 7, 0, ADCx} , /* PE7 */ - {&gpioe, NULL, NULL, 8, 0, ADCx} , /* PE8 */ - {&gpioe, NULL, NULL, 9, 0, ADCx} , /* PE9 */ - {&gpioe, NULL, NULL, 10, 0, ADCx} , /* PE10 */ - {&gpioe, NULL, NULL, 11, 0, ADCx} , /* PE11 */ - {&gpioe, NULL, NULL, 12, 0, ADCx} , /* PE12 */ - {&gpioe, NULL, NULL, 13, 0, ADCx} , /* PE13 */ - {&gpioe, NULL, NULL, 14, 0, ADCx} , /* PE14 */ - {&gpioe, NULL, NULL, 15, 0, ADCx} , /* PE15 */ + {&gpioe, NULL, NULL, 0, 0, ADCx, 0} , /* PE0 */ + {&gpioe, NULL, NULL, 1, 0, ADCx, 0} , /* PE1 */ + {&gpioe, NULL, NULL, 2, 0, ADCx, 0} , /* PE2 */ + {&gpioe, NULL, NULL, 3, 0, ADCx, 0} , /* PE3 */ + {&gpioe, NULL, NULL, 4, 0, ADCx, 0} , /* PE4 */ + {&gpioe, NULL, NULL, 5, 0, ADCx, 0} , /* PE5 */ + {&gpioe, NULL, NULL, 6, 0, ADCx, 0} , /* PE6 */ + {&gpioe, NULL, NULL, 7, 0, ADCx, 0} , /* PE7 */ + {&gpioe, NULL, NULL, 8, 0, ADCx, 0} , /* PE8 */ + {&gpioe, NULL, NULL, 9, 0, ADCx, 0} , /* PE9 */ + {&gpioe, NULL, NULL, 10, 0, ADCx, 0} , /* PE10 */ + {&gpioe, NULL, NULL, 11, 0, ADCx, 0} , /* PE11 */ + {&gpioe, NULL, NULL, 12, 0, ADCx, 0} , /* PE12 */ + {&gpioe, NULL, NULL, 13, 0, ADCx, 0} , /* PE13 */ + {&gpioe, NULL, NULL, 14, 0, ADCx, 0} , /* PE14 */ + {&gpioe, NULL, NULL, 15, 0, ADCx, 0} , /* PE15 */ - {&gpiof, NULL, NULL, 0, 0, ADCx} , /* PF0 */ - {&gpiof, NULL, NULL, 1, 0, ADCx} , /* PF1 */ - {&gpiof, NULL, NULL, 2, 0, ADCx} , /* PF2 */ - {&gpiof, NULL, NULL, 3, 0, ADCx} , /* PF3 */ - {&gpiof, NULL, NULL, 4, 0, ADCx} , /* PF4 */ - {&gpiof, NULL, NULL, 5, 0, ADCx} , /* PF5 */ - {&gpiof, NULL, NULL, 6, 0, ADCx} , /* PF6 */ - {&gpiof, NULL, NULL, 7, 0, ADCx} , /* PF7 */ - {&gpiof, NULL, NULL, 8, 0, ADCx} , /* PF8 */ - {&gpiof, NULL, NULL, 9, 0, ADCx} , /* PF9 */ - {&gpiof, NULL, NULL, 10, 0, ADCx} , /* PF10 */ - {&gpiof, NULL, NULL, 11, 0, ADCx} , /* PF11 */ - {&gpiof, NULL, NULL, 12, 0, ADCx} , /* PF12 */ - {&gpiof, NULL, NULL, 13, 0, ADCx} , /* PF13 */ - {&gpiof, NULL, NULL, 14, 0, ADCx} , /* PF14 */ - {&gpiof, NULL, NULL, 15, 0, ADCx} , /* PF15 */ + {&gpiof, NULL, NULL, 0, 0, ADCx, 0} , /* PF0 */ + {&gpiof, NULL, NULL, 1, 0, ADCx, 0} , /* PF1 */ + {&gpiof, NULL, NULL, 2, 0, ADCx, 0} , /* PF2 */ + {&gpiof, NULL, NULL, 3, 0, ADCx, 0} , /* PF3 */ + {&gpiof, NULL, NULL, 4, 0, ADCx, 0} , /* PF4 */ + {&gpiof, NULL, NULL, 5, 0, ADCx, 0} , /* PF5 */ + {&gpiof, NULL, NULL, 6, 0, ADCx, 0} , /* PF6 */ + {&gpiof, NULL, NULL, 7, 0, ADCx, 0} , /* PF7 */ + {&gpiof, NULL, NULL, 8, 0, ADCx, 0} , /* PF8 */ + {&gpiof, NULL, NULL, 9, 0, ADCx, 0} , /* PF9 */ + {&gpiof, NULL, NULL, 10, 0, ADCx, 0} , /* PF10 */ + {&gpiof, NULL, NULL, 11, 0, ADCx, 0} , /* PF11 */ + {&gpiof, NULL, NULL, 12, 0, ADCx, 0} , /* PF12 */ + {&gpiof, NULL, NULL, 13, 0, ADCx, 0} , /* PF13 */ + {&gpiof, NULL, NULL, 14, 0, ADCx, 0} , /* PF14 */ + {&gpiof, NULL, NULL, 15, 0, ADCx, 0} , /* PF15 */ - {&gpiog, NULL, NULL, 0, 0, ADCx} , /* PG0 */ - {&gpiog, NULL, NULL, 1, 0, ADCx} , /* PG1 */ - {&gpiog, NULL, NULL, 2, 0, ADCx} , /* PG2 */ - {&gpiog, NULL, NULL, 3, 0, ADCx} , /* PG3 */ - {&gpiog, NULL, NULL, 4, 0, ADCx} , /* PG4 */ - {&gpiog, NULL, NULL, 5, 0, ADCx} , /* PG5 */ - {&gpiog, NULL, NULL, 6, 0, ADCx} , /* PG6 */ - {&gpiog, NULL, NULL, 7, 0, ADCx} , /* PG7 */ - {&gpiog, NULL, NULL, 8, 0, ADCx} , /* PG8 */ - {&gpiog, NULL, NULL, 9, 0, ADCx} , /* PG9 */ - {&gpiog, NULL, NULL, 10, 0, ADCx} , /* PG10 */ - {&gpiog, NULL, NULL, 11, 0, ADCx} , /* PG11 */ - {&gpiog, NULL, NULL, 12, 0, ADCx} , /* PG12 */ - {&gpiog, NULL, NULL, 13, 0, ADCx} , /* PG13 */ - {&gpiog, NULL, NULL, 14, 0, ADCx} , /* PG14 */ - {&gpiog, NULL, NULL, 15, 0, ADCx} /* PG15 */ + {&gpiog, NULL, NULL, 0, 0, ADCx, 0} , /* PG0 */ + {&gpiog, NULL, NULL, 1, 0, ADCx, 0} , /* PG1 */ + {&gpiog, NULL, NULL, 2, 0, ADCx, 0} , /* PG2 */ + {&gpiog, NULL, NULL, 3, 0, ADCx, 0} , /* PG3 */ + {&gpiog, NULL, NULL, 4, 0, ADCx, 0} , /* PG4 */ + {&gpiog, NULL, NULL, 5, 0, ADCx, 0} , /* PG5 */ + {&gpiog, NULL, NULL, 6, 0, ADCx, 0} , /* PG6 */ + {&gpiog, NULL, NULL, 7, 0, ADCx, 0} , /* PG7 */ + {&gpiog, NULL, NULL, 8, 0, ADCx, 0} , /* PG8 */ + {&gpiog, NULL, NULL, 9, 0, ADCx, 0} , /* PG9 */ + {&gpiog, NULL, NULL, 10, 0, ADCx, 0} , /* PG10 */ + {&gpiog, NULL, NULL, 11, 0, ADCx, 0} , /* PG11 */ + {&gpiog, NULL, NULL, 12, 0, ADCx, 0} , /* PG12 */ + {&gpiog, NULL, NULL, 13, 0, ADCx, 0} , /* PG13 */ + {&gpiog, NULL, NULL, 14, 0, ADCx, 0} , /* PG14 */ + {&gpiog, NULL, NULL, 15, 0, ADCx, 0} /* PG15 */ }; -#pragma GCC diagnostic pop /* Basically everything that is defined as having a timer us PWM */ extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { diff --git a/STM32F1/variants/hytiny_stm32f103t/board.cpp b/STM32F1/variants/hytiny_stm32f103t/board.cpp index d1260a6..b3fdd9b 100644 --- a/STM32F1/variants/hytiny_stm32f103t/board.cpp +++ b/STM32F1/variants/hytiny_stm32f103t/board.cpp @@ -51,39 +51,36 @@ void boardInit(void) { } // Note. See the enum of pin names in board.h -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wmissing-field-initializers" extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { - {&gpioa, &timer2, &adc1, 0, 1, 0}, /* PA0 */ - {&gpioa, &timer2, &adc1, 1, 2, 1}, /* PA1 */ - {&gpioa, &timer2, &adc1, 2, 3, 2}, /* PA2 */ - {&gpioa, &timer2, &adc1, 3, 4, 3}, /* PA3 */ - {&gpioa, NULL, &adc1, 4, 0, 4}, /* PA4 */ - {&gpioa, NULL, &adc1, 5, 0, 5}, /* PA5 */ - {&gpioa, &timer3, &adc1, 6, 1, 6}, /* PA6 */ - {&gpioa, &timer3, &adc1, 7, 2, 7}, /* PA7 */ - {&gpioa, &timer1, NULL, 8, 1, ADCx}, /* PA8 */ - {&gpioa, &timer1, NULL, 9, 2, ADCx}, /* PA9 */ - {&gpioa, &timer1, NULL, 10, 3, ADCx}, /* PA10 */ - {&gpioa, &timer1, NULL, 11, 4, ADCx}, /* PA11 */ - {&gpioa, NULL, NULL, 12, 0, ADCx}, /* PA12 */ - {&gpioa, NULL, NULL, 13, 0, ADCx}, /* PA13 */ - {&gpioa, NULL, NULL, 14, 0, ADCx}, /* PA14 */ - {&gpioa, NULL, NULL, 15, 0, ADCx}, /* PA15 */ + {&gpioa, &timer2, &adc1, 0, 1, 0, 0}, /* PA0 */ + {&gpioa, &timer2, &adc1, 1, 2, 1, 0}, /* PA1 */ + {&gpioa, &timer2, &adc1, 2, 3, 2, 0}, /* PA2 */ + {&gpioa, &timer2, &adc1, 3, 4, 3, 0}, /* PA3 */ + {&gpioa, NULL, &adc1, 4, 0, 4, 0}, /* PA4 */ + {&gpioa, NULL, &adc1, 5, 0, 5, 0}, /* PA5 */ + {&gpioa, &timer3, &adc1, 6, 1, 6, 0}, /* PA6 */ + {&gpioa, &timer3, &adc1, 7, 2, 7, 0}, /* PA7 */ + {&gpioa, &timer1, NULL, 8, 1, ADCx, 0}, /* PA8 */ + {&gpioa, &timer1, NULL, 9, 2, ADCx, 0}, /* PA9 */ + {&gpioa, &timer1, NULL, 10, 3, ADCx, 0}, /* PA10 */ + {&gpioa, &timer1, NULL, 11, 4, ADCx, 0}, /* PA11 */ + {&gpioa, NULL, NULL, 12, 0, ADCx, 0}, /* PA12 */ + {&gpioa, NULL, NULL, 13, 0, ADCx, 0}, /* PA13 */ + {&gpioa, NULL, NULL, 14, 0, ADCx, 0}, /* PA14 */ + {&gpioa, NULL, NULL, 15, 0, ADCx, 0}, /* PA15 */ - {&gpiob, &timer3, &adc1, 0, 3, 8}, /* PB0 */ - {&gpiob, &timer3, &adc1, 1, 4, 9}, /* PB1 */ - {&gpiob, NULL, NULL, 2, 0, ADCx}, /* PB2 */ - {&gpiob, NULL, NULL, 3, 0, ADCx}, /* PB3 */ - {&gpiob, NULL, NULL, 4, 0, ADCx}, /* PB4 */ - {&gpiob, NULL, NULL, 5, 0, ADCx}, /* PB5 */ - {&gpiob, &timer4, NULL, 6, 1, ADCx}, /* PB6 */ - {&gpiob, &timer4, NULL, 7, 2, ADCx}, /* PB7 */ + {&gpiob, &timer3, &adc1, 0, 3, 8, 0}, /* PB0 */ + {&gpiob, &timer3, &adc1, 1, 4, 9, 0}, /* PB1 */ + {&gpiob, NULL, NULL, 2, 0, ADCx, 0}, /* PB2 */ + {&gpiob, NULL, NULL, 3, 0, ADCx, 0}, /* PB3 */ + {&gpiob, NULL, NULL, 4, 0, ADCx, 0}, /* PB4 */ + {&gpiob, NULL, NULL, 5, 0, ADCx, 0}, /* PB5 */ + {&gpiob, &timer4, NULL, 6, 1, ADCx, 0}, /* PB6 */ + {&gpiob, &timer4, NULL, 7, 2, ADCx, 0}, /* PB7 */ }; -#pragma GCC diagnostic pop extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { PB0, PA7, PA6, PA3, PA2, PA1, PA0, PB7, PB6, PA10, PA9, PA8 diff --git a/STM32F1/variants/maple/board.cpp b/STM32F1/variants/maple/board.cpp index b1584e7..a4c0335 100644 --- a/STM32F1/variants/maple/board.cpp +++ b/STM32F1/variants/maple/board.cpp @@ -68,8 +68,6 @@ void boardInit(void) { // - Timer channel (1 to 4, for PWM), or 0 if none // - ADC device, or NULL if none // - ADC channel, or ADCx if none -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wmissing-field-initializers" extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { /* Top header */ @@ -128,7 +126,6 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { PMAP_ROW(&gpiob, 3, NULL, 0, NULL, ADCx), /* D42/PB3 */ PMAP_ROW(&gpiob, 4, NULL, 0, NULL, ADCx), /* D43/PB4 */ }; -#pragma GCC diagnostic pop // Array of pins you can use for pwmWrite(). Keep it in Flash because // it doesn't change, and so we don't waste RAM. diff --git a/STM32F1/variants/maple_mini/board.cpp b/STM32F1/variants/maple_mini/board.cpp index bf63364..72faa17 100644 --- a/STM32F1/variants/maple_mini/board.cpp +++ b/STM32F1/variants/maple_mini/board.cpp @@ -50,51 +50,48 @@ void boardInit(void) { #endif } -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wmissing-field-initializers" extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { /* Top header */ - {&gpiob, NULL, NULL, 11, 0, ADCx}, /* D0/PB11 */ - {&gpiob, NULL, NULL, 10, 0, ADCx}, /* D1/PB10 */ - {&gpiob, NULL, NULL, 2, 0, ADCx}, /* D2/PB2 */ - {&gpiob, &timer3, &adc1, 0, 3, 8}, /* D3/PB0 */ - {&gpioa, &timer3, &adc1, 7, 2, 7}, /* D4/PA7 */ - {&gpioa, &timer3, &adc1, 6, 1, 6}, /* D5/PA6 */ - {&gpioa, NULL, &adc1, 5, 0, 5}, /* D6/PA5 */ - {&gpioa, NULL, &adc1, 4, 0, 4}, /* D7/PA4 */ - {&gpioa, &timer2, &adc1, 3, 4, 3}, /* D8/PA3 */ - {&gpioa, &timer2, &adc1, 2, 3, 2}, /* D9/PA2 */ - {&gpioa, &timer2, &adc1, 1, 2, 1}, /* D10/PA1 */ - {&gpioa, &timer2, &adc1, 0, 1, 0}, /* D11/PA0 */ - {&gpioc, NULL, NULL, 15, 0, ADCx}, /* D12/PC15 */ - {&gpioc, NULL, NULL, 14, 0, ADCx}, /* D13/PC14 */ - {&gpioc, NULL, NULL, 13, 0, ADCx}, /* D14/PC13 */ + {&gpiob, NULL, NULL, 11, 0, ADCx, 0}, /* D0/PB11 */ + {&gpiob, NULL, NULL, 10, 0, ADCx, 0}, /* D1/PB10 */ + {&gpiob, NULL, NULL, 2, 0, ADCx, 0}, /* D2/PB2 */ + {&gpiob, &timer3, &adc1, 0, 3, 8, 0}, /* D3/PB0 */ + {&gpioa, &timer3, &adc1, 7, 2, 7, 0}, /* D4/PA7 */ + {&gpioa, &timer3, &adc1, 6, 1, 6, 0}, /* D5/PA6 */ + {&gpioa, NULL, &adc1, 5, 0, 5, 0}, /* D6/PA5 */ + {&gpioa, NULL, &adc1, 4, 0, 4, 0}, /* D7/PA4 */ + {&gpioa, &timer2, &adc1, 3, 4, 3, 0}, /* D8/PA3 */ + {&gpioa, &timer2, &adc1, 2, 3, 2, 0}, /* D9/PA2 */ + {&gpioa, &timer2, &adc1, 1, 2, 1, 0}, /* D10/PA1 */ + {&gpioa, &timer2, &adc1, 0, 1, 0, 0}, /* D11/PA0 */ + {&gpioc, NULL, NULL, 15, 0, ADCx, 0}, /* D12/PC15 */ + {&gpioc, NULL, NULL, 14, 0, ADCx, 0}, /* D13/PC14 */ + {&gpioc, NULL, NULL, 13, 0, ADCx, 0}, /* D14/PC13 */ /* Bottom header */ - {&gpiob, &timer4, NULL, 7, 2, ADCx}, /* D15/PB7 */ - {&gpiob, &timer4, NULL, 6, 1, ADCx}, /* D16/PB6 */ - {&gpiob, NULL, NULL, 5, 0, ADCx}, /* D17/PB5 */ - {&gpiob, NULL, NULL, 4, 0, ADCx}, /* D18/PB4 */ - {&gpiob, NULL, NULL, 3, 0, ADCx}, /* D19/PB3 */ - {&gpioa, NULL, NULL, 15, 0, ADCx}, /* D20/PA15 */ - {&gpioa, NULL, NULL, 14, 0, ADCx}, /* D21/PA14 */ - {&gpioa, NULL, NULL, 13, 0, ADCx}, /* D22/PA13 */ - {&gpioa, NULL, NULL, 12, 0, ADCx}, /* D23/PA12 */ - {&gpioa, &timer1, NULL, 11, 4, ADCx}, /* D24/PA11 */ - {&gpioa, &timer1, NULL, 10, 3, ADCx}, /* D25/PA10 */ - {&gpioa, &timer1, NULL, 9, 2, ADCx}, /* D26/PA9 */ - {&gpioa, &timer1, NULL, 8, 1, ADCx}, /* D27/PA8 */ - {&gpiob, NULL, NULL, 15, 0, ADCx}, /* D28/PB15 */ - {&gpiob, NULL, NULL, 14, 0, ADCx}, /* D29/PB14 */ - {&gpiob, NULL, NULL, 13, 0, ADCx}, /* D30/PB13 */ - {&gpiob, NULL, NULL, 12, 0, ADCx}, /* D31/PB12 */ - {&gpiob, &timer4, NULL, 8, 3, ADCx}, /* D32/PB8 */ - {&gpiob, &timer3, &adc1, 1, 4, 9}, /* D33/PB1 */ + {&gpiob, &timer4, NULL, 7, 2, ADCx, 0}, /* D15/PB7 */ + {&gpiob, &timer4, NULL, 6, 1, ADCx, 0}, /* D16/PB6 */ + {&gpiob, NULL, NULL, 5, 0, ADCx, 0}, /* D17/PB5 */ + {&gpiob, NULL, NULL, 4, 0, ADCx, 0}, /* D18/PB4 */ + {&gpiob, NULL, NULL, 3, 0, ADCx, 0}, /* D19/PB3 */ + {&gpioa, NULL, NULL, 15, 0, ADCx, 0}, /* D20/PA15 */ + {&gpioa, NULL, NULL, 14, 0, ADCx, 0}, /* D21/PA14 */ + {&gpioa, NULL, NULL, 13, 0, ADCx, 0}, /* D22/PA13 */ + {&gpioa, NULL, NULL, 12, 0, ADCx, 0}, /* D23/PA12 */ + {&gpioa, &timer1, NULL, 11, 4, ADCx, 0}, /* D24/PA11 */ + {&gpioa, &timer1, NULL, 10, 3, ADCx, 0}, /* D25/PA10 */ + {&gpioa, &timer1, NULL, 9, 2, ADCx, 0}, /* D26/PA9 */ + {&gpioa, &timer1, NULL, 8, 1, ADCx, 0}, /* D27/PA8 */ + {&gpiob, NULL, NULL, 15, 0, ADCx, 0}, /* D28/PB15 */ + {&gpiob, NULL, NULL, 14, 0, ADCx, 0}, /* D29/PB14 */ + {&gpiob, NULL, NULL, 13, 0, ADCx, 0}, /* D30/PB13 */ + {&gpiob, NULL, NULL, 12, 0, ADCx, 0}, /* D31/PB12 */ + {&gpiob, &timer4, NULL, 8, 3, ADCx, 0}, /* D32/PB8 */ + {&gpiob, &timer3, &adc1, 1, 4, 9, 0}, /* D33/PB1 */ }; -#pragma GCC diagnostic pop extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { 3, 4, 5, 8, 9, 10, 11, 15, 16, 25, 26, 27 diff --git a/STM32F1/variants/maple_ret6/board.cpp b/STM32F1/variants/maple_ret6/board.cpp index dfec977..82127ff 100644 --- a/STM32F1/variants/maple_ret6/board.cpp +++ b/STM32F1/variants/maple_ret6/board.cpp @@ -69,8 +69,6 @@ void boardInit(void) { // - ADC device, or NULL if none // - ADC channel, or ADCx if none -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wmissing-field-initializers" extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { /* gpio_dev *gpio_device; GPIO device @@ -84,68 +82,67 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { /* Top header */ - { &gpioa, &timer2, &adc1, 3, 4, 3 }, /* D0/PA3 */ - { &gpioa, &timer2, &adc1, 2, 3, 2 }, /* D1/PA2 */ - { &gpioa, &timer2, &adc1, 0, 1, 0 }, /* D2/PA0 */ - { &gpioa, &timer2, &adc1, 1, 2, 1 }, /* D3/PA1 */ - { &gpiob, NULL, NULL, 5, 0, ADCx }, /* D4/PB5 */ - { &gpiob, &timer4, NULL, 6, 1, ADCx }, /* D5/PB6 */ - { &gpioa, &timer1, NULL, 8, 1, ADCx }, /* D6/PA8 */ - { &gpioa, &timer1, NULL, 9, 2, ADCx }, /* D7/PA9 */ - { &gpioa, &timer1, NULL, 10, 3, ADCx }, /* D8/PA10 */ - { &gpiob, &timer4, NULL, 7, 2, ADCx }, /* D9/PB7 */ - { &gpioa, NULL, &adc1, 4, 0, 4 }, /* D10/PA4 */ - { &gpioa, &timer3, &adc1, 7, 2, 7 }, /* D11/PA7 */ - { &gpioa, &timer3, &adc1, 6, 1, 6 }, /* D12/PA6 */ - { &gpioa, NULL, &adc1, 5, 0, 5 }, /* D13/PA5 (LED) */ - { &gpiob, &timer4, NULL, 8, 3, ADCx }, /* D14/PB8 */ + { &gpioa, &timer2, &adc1, 3, 4, 3, 0}, /* D0/PA3 */ + { &gpioa, &timer2, &adc1, 2, 3, 2, 0}, /* D1/PA2 */ + { &gpioa, &timer2, &adc1, 0, 1, 0, 0}, /* D2/PA0 */ + { &gpioa, &timer2, &adc1, 1, 2, 1, 0}, /* D3/PA1 */ + { &gpiob, NULL, NULL, 5, 0, ADCx, 0}, /* D4/PB5 */ + { &gpiob, &timer4, NULL, 6, 1, ADCx, 0}, /* D5/PB6 */ + { &gpioa, &timer1, NULL, 8, 1, ADCx, 0}, /* D6/PA8 */ + { &gpioa, &timer1, NULL, 9, 2, ADCx, 0}, /* D7/PA9 */ + { &gpioa, &timer1, NULL, 10, 3, ADCx, 0}, /* D8/PA10 */ + { &gpiob, &timer4, NULL, 7, 2, ADCx, 0}, /* D9/PB7 */ + { &gpioa, NULL, &adc1, 4, 0, 4, 0}, /* D10/PA4 */ + { &gpioa, &timer3, &adc1, 7, 2, 7, 0}, /* D11/PA7 */ + { &gpioa, &timer3, &adc1, 6, 1, 6, 0}, /* D12/PA6 */ + { &gpioa, NULL, &adc1, 5, 0, 5, 0}, /* D13/PA5 (LED) */ + { &gpiob, &timer4, NULL, 8, 3, ADCx, 0}, /* D14/PB8 */ /* Little header */ - { &gpioc, NULL, &adc1, 0, 0, 10 }, /* D15/PC0 */ - { &gpioc, NULL, &adc1, 1, 0, 11 }, /* D16/PC1 */ - { &gpioc, NULL, &adc1, 2, 0, 12 }, /* D17/PC2 */ - { &gpioc, NULL, &adc1, 3, 0, 13 }, /* D18/PC3 */ - { &gpioc, NULL, &adc1, 4, 0, 14 }, /* D19/PC4 */ - { &gpioc, NULL, &adc1, 5, 0, 15 }, /* D20/PC5 */ + { &gpioc, NULL, &adc1, 0, 0, 10, 0}, /* D15/PC0 */ + { &gpioc, NULL, &adc1, 1, 0, 11, 0}, /* D16/PC1 */ + { &gpioc, NULL, &adc1, 2, 0, 12, 0}, /* D17/PC2 */ + { &gpioc, NULL, &adc1, 3, 0, 13, 0}, /* D18/PC3 */ + { &gpioc, NULL, &adc1, 4, 0, 14, 0}, /* D19/PC4 */ + { &gpioc, NULL, &adc1, 5, 0, 15, 0}, /* D20/PC5 */ /* External header */ - { &gpioc, NULL, NULL, 13, 0, ADCx }, /* D21/PC13 */ - { &gpioc, NULL, NULL, 14, 0, ADCx }, /* D22/PC14 */ - { &gpioc, NULL, NULL, 15, 0, ADCx }, /* D23/PC15 */ - { &gpiob, &timer4, NULL, 9, 4, ADCx }, /* D24/PB9 */ - { &gpiod, NULL, NULL, 2, 0, ADCx }, /* D25/PD2 */ - { &gpioc, NULL, NULL, 10, 0, ADCx }, /* D26/PC10 */ - { &gpiob, &timer3, &adc1, 0, 3, 8 }, /* D27/PB0 */ - { &gpiob, &timer3, &adc1, 1, 4, 9 }, /* D28/PB1 */ - { &gpiob, NULL, NULL, 10, 0, ADCx }, /* D29/PB10 */ - { &gpiob, NULL, NULL, 11, 0, ADCx }, /* D30/PB11 */ - { &gpiob, NULL, NULL, 12, 0, ADCx }, /* D31/PB12 */ - { &gpiob, NULL, NULL, 13, 0, ADCx }, /* D32/PB13 */ - { &gpiob, NULL, NULL, 14, 0, ADCx }, /* D33/PB14 */ - { &gpiob, NULL, NULL, 15, 0, ADCx }, /* D34/PB15 */ - { &gpioc, &timer8, NULL, 6, 1, ADCx }, /* D35/PC6 */ - { &gpioc, &timer8, NULL, 7, 2, ADCx }, /* D36/PC7 */ - { &gpioc, &timer8, NULL, 8, 3, ADCx }, /* D37/PC8 */ - { &gpioc, &timer8, NULL, 9, 4, ADCx }, /* D38/PC9 (BUT) */ + { &gpioc, NULL, NULL, 13, 0, ADCx, 0}, /* D21/PC13 */ + { &gpioc, NULL, NULL, 14, 0, ADCx, 0}, /* D22/PC14 */ + { &gpioc, NULL, NULL, 15, 0, ADCx, 0}, /* D23/PC15 */ + { &gpiob, &timer4, NULL, 9, 4, ADCx, 0}, /* D24/PB9 */ + { &gpiod, NULL, NULL, 2, 0, ADCx, 0}, /* D25/PD2 */ + { &gpioc, NULL, NULL, 10, 0, ADCx, 0}, /* D26/PC10 */ + { &gpiob, &timer3, &adc1, 0, 3, 8, 0}, /* D27/PB0 */ + { &gpiob, &timer3, &adc1, 1, 4, 9, 0}, /* D28/PB1 */ + { &gpiob, NULL, NULL, 10, 0, ADCx, 0}, /* D29/PB10 */ + { &gpiob, NULL, NULL, 11, 0, ADCx, 0}, /* D30/PB11 */ + { &gpiob, NULL, NULL, 12, 0, ADCx, 0}, /* D31/PB12 */ + { &gpiob, NULL, NULL, 13, 0, ADCx, 0}, /* D32/PB13 */ + { &gpiob, NULL, NULL, 14, 0, ADCx, 0}, /* D33/PB14 */ + { &gpiob, NULL, NULL, 15, 0, ADCx, 0}, /* D34/PB15 */ + { &gpioc, &timer8, NULL, 6, 1, ADCx, 0}, /* D35/PC6 */ + { &gpioc, &timer8, NULL, 7, 2, ADCx, 0}, /* D36/PC7 */ + { &gpioc, &timer8, NULL, 8, 3, ADCx, 0}, /* D37/PC8 */ + { &gpioc, &timer8, NULL, 9, 4, ADCx, 0}, /* D38/PC9 (BUT) */ /* JTAG header */ - { &gpioa, NULL, NULL, 13, 0, ADCx }, /* D39/PA13 */ - { &gpioa, NULL, NULL, 14, 0, ADCx }, /* D40/PA14 */ - { &gpioa, NULL, NULL, 15, 0, ADCx }, /* D41/PA15 */ - { &gpiob, NULL, NULL, 3, 0, ADCx }, /* D42/PB3 */ - { &gpiob, NULL, NULL, 4, 0, ADCx }, /* D43/PB4 */ + { &gpioa, NULL, NULL, 13, 0, ADCx, 0}, /* D39/PA13 */ + { &gpioa, NULL, NULL, 14, 0, ADCx, 0}, /* D40/PA14 */ + { &gpioa, NULL, NULL, 15, 0, ADCx, 0}, /* D41/PA15 */ + { &gpiob, NULL, NULL, 3, 0, ADCx, 0}, /* D42/PB3 */ + { &gpiob, NULL, NULL, 4, 0, ADCx, 0}, /* D43/PB4 */ - { &gpioc, NULL, NULL, 11, 0, ADCx }, /* D44/PC11 UART4_RX/SDIO_D3 */ - { &gpioc, NULL, NULL, 12, 0, ADCx }, /* D45/PC12 UART5_TX/SDIO_CK */ + { &gpioc, NULL, NULL, 11, 0, ADCx, 0}, /* D44/PC11 UART4_RX/SDIO_D3 */ + { &gpioc, NULL, NULL, 12, 0, ADCx, 0}, /* D45/PC12 UART5_TX/SDIO_CK */ - { &gpiod, NULL, NULL, 0, 0, ADCx }, /* PD0 OSC_IN */ - { &gpiod, NULL, NULL, 1, 0, ADCx }, /* PD1 OSC_OUT */ - { &gpiob, NULL, NULL, 2, 0, ADCx }, /* PB2 */ + { &gpiod, NULL, NULL, 0, 0, ADCx, 0}, /* PD0 OSC_IN */ + { &gpiod, NULL, NULL, 1, 0, ADCx, 0}, /* PD1 OSC_OUT */ + { &gpiob, NULL, NULL, 2, 0, ADCx, 0}, /* PB2 */ }; -#pragma GCC diagnostic pop /* Basically everything that is defined as having a timer us PWM */ extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { diff --git a/STM32F1/variants/microduino/board.cpp b/STM32F1/variants/microduino/board.cpp index d7b4a97..51c8024 100644 --- a/STM32F1/variants/microduino/board.cpp +++ b/STM32F1/variants/microduino/board.cpp @@ -51,42 +51,39 @@ void boardInit(void) { #endif } -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wmissing-field-initializers" extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { - {&gpioa, &timer1, NULL, 10, 3, ADCx}, /* D0(RxD0)/PA10 */ - {&gpioa, &timer1, NULL, 9, 2, ADCx}, /* D1(TxD1)/PA9 */ - {&gpiob, NULL, NULL, 11, 0, ADCx}, /* D2/PB11 */ - {&gpiob, NULL, NULL, 10, 0, ADCx}, /* D3/PB10 */ - {&gpioa, &timer1, NULL, 8, 1, ADCx}, /* D4/PA8 */ - {&gpioa, NULL, NULL, 13, 0, ADCx}, /* D5/PA13 */ - {&gpioa, NULL, NULL, 14, 0, ADCx}, /* D6/PA14 */ - {&gpioa, NULL, NULL, 15, 0, ADCx}, /* D7/PA15 */ - {&gpiob, NULL, NULL, 3, 0, ADCx}, /* D8/PB3 */ - {&gpiob, NULL, NULL, 4, 0, ADCx}, /* D9/PB4 */ - {&gpioa, NULL, &adc1, 4, 0, 4}, /* D10/PA4 */ - {&gpioa, &timer3, &adc1, 7, 2, 7}, /* D11/PA7 */ - {&gpioa, &timer3, &adc1, 6, 1, 6}, /* D12/PA6 */ - {&gpioa, NULL, &adc1, 5, 0, 5}, /* D13/PA5 */ + {&gpioa, &timer1, NULL, 10, 3, ADCx, 0}, /* D0(RxD0)/PA10 */ + {&gpioa, &timer1, NULL, 9, 2, ADCx, 0}, /* D1(TxD1)/PA9 */ + {&gpiob, NULL, NULL, 11, 0, ADCx, 0}, /* D2/PB11 */ + {&gpiob, NULL, NULL, 10, 0, ADCx, 0}, /* D3/PB10 */ + {&gpioa, &timer1, NULL, 8, 1, ADCx, 0}, /* D4/PA8 */ + {&gpioa, NULL, NULL, 13, 0, ADCx, 0}, /* D5/PA13 */ + {&gpioa, NULL, NULL, 14, 0, ADCx, 0}, /* D6/PA14 */ + {&gpioa, NULL, NULL, 15, 0, ADCx, 0}, /* D7/PA15 */ + {&gpiob, NULL, NULL, 3, 0, ADCx, 0}, /* D8/PB3 */ + {&gpiob, NULL, NULL, 4, 0, ADCx, 0}, /* D9/PB4 */ + {&gpioa, NULL, &adc1, 4, 0, 4, 0}, /* D10/PA4 */ + {&gpioa, &timer3, &adc1, 7, 2, 7, 0}, /* D11/PA7 */ + {&gpioa, &timer3, &adc1, 6, 1, 6, 0}, /* D12/PA6 */ + {&gpioa, NULL, &adc1, 5, 0, 5, 0}, /* D13/PA5 */ - {&gpioa, &timer2, &adc1, 0, 1, 0}, /* D14(A0)/PA0 */ - {&gpioa, &timer2, &adc1, 1, 2, 1}, /* D15(A1)/PA1 */ - {&gpioa, &timer2, &adc1, 2, 3, 2}, /* D16(A2)/PA2 */ - {&gpioa, &timer2, &adc1, 3, 4, 3}, /* D17(A3)/PA3 */ - {&gpiob, &timer4, NULL, 7, 2, ADCx}, /* D18(A4)/PB7 */ - {&gpiob, &timer4, NULL, 6, 1, ADCx}, /* D19(A5)/PB6 */ - {&gpiob, &timer3, &adc1, 0, 3, 8}, /* D20(A6)/PB0 */ - {&gpiob, &timer3, &adc1, 1, 4, 9}, /* D21(A7)/PB1 */ + {&gpioa, &timer2, &adc1, 0, 1, 0, 0}, /* D14(A0)/PA0 */ + {&gpioa, &timer2, &adc1, 1, 2, 1, 0}, /* D15(A1)/PA1 */ + {&gpioa, &timer2, &adc1, 2, 3, 2, 0}, /* D16(A2)/PA2 */ + {&gpioa, &timer2, &adc1, 3, 4, 3, 0}, /* D17(A3)/PA3 */ + {&gpiob, &timer4, NULL, 7, 2, ADCx, 0}, /* D18(A4)/PB7 */ + {&gpiob, &timer4, NULL, 6, 1, ADCx, 0}, /* D19(A5)/PB6 */ + {&gpiob, &timer3, &adc1, 0, 3, 8, 0}, /* D20(A6)/PB0 */ + {&gpiob, &timer3, &adc1, 1, 4, 9, 0}, /* D21(A7)/PB1 */ - {&gpioa, NULL, NULL, 12, 0, ADCx}, /* D22/PA12/USB D+ */ - {&gpioa, &timer1, NULL, 11, 4, ADCx}, /* D23/PA11/USB D- */ + {&gpioa, NULL, NULL, 12, 0, ADCx, 0}, /* D22/PA12/USB D+ */ + {&gpioa, &timer1, NULL, 11, 4, ADCx, 0}, /* D23/PA11/USB D- */ // FIXME: find out which pin is the button, if any - {&gpiob, NULL, NULL, 8, 0, ADCx}, /* D24/PB8??/Button */ + {&gpiob, NULL, NULL, 8, 0, ADCx, 0}, /* D24/PB8??/Button */ }; -#pragma GCC diagnostic pop extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { 0, 1, 4, 11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 23 diff --git a/STM32F1/variants/nucleo_f103rb/board.cpp b/STM32F1/variants/nucleo_f103rb/board.cpp index 9754a2d..5e2672c 100644 --- a/STM32F1/variants/nucleo_f103rb/board.cpp +++ b/STM32F1/variants/nucleo_f103rb/board.cpp @@ -93,65 +93,62 @@ rcc_pll_cfg w_board_pll_cfg = {RCC_PLLSRC_HSI_DIV_2, &pll_data}; // 0 1 3 4 2 5 // 0 1 2 4 2 5 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wmissing-field-initializers" extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { /* Arduino-like header, right connectors */ - {&gpioa, NULL, &adc1, 3, 0, 3}, /* D0/PA3 */ - {&gpioa, NULL, &adc1, 2, 0, 2}, /* D1/PA2 */ - {&gpioa, &timer1, NULL, 10, 3, ADCx}, /* D2/PA10 */ - {&gpiob, &timer2, NULL, 3, 2, ADCx}, /* D3/PB3 */ - {&gpiob, &timer3, NULL, 5, 2, ADCx}, /* D4/PB5 */ - {&gpiob, &timer3, NULL, 4, 1, ADCx}, /* D5/PB4 */ - {&gpiob, &timer2, NULL, 10, 3, ADCx}, /* D6/PB10 */ - {&gpioa, &timer1, NULL, 8, 1, ADCx}, /* D7/PA8 */ + {&gpioa, NULL, &adc1, 3, 0, 3, 0}, /* D0/PA3 */ + {&gpioa, NULL, &adc1, 2, 0, 2, 0}, /* D1/PA2 */ + {&gpioa, &timer1, NULL, 10, 3, ADCx, 0}, /* D2/PA10 */ + {&gpiob, &timer2, NULL, 3, 2, ADCx, 0}, /* D3/PB3 */ + {&gpiob, &timer3, NULL, 5, 2, ADCx, 0}, /* D4/PB5 */ + {&gpiob, &timer3, NULL, 4, 1, ADCx, 0}, /* D5/PB4 */ + {&gpiob, &timer2, NULL, 10, 3, ADCx, 0}, /* D6/PB10 */ + {&gpioa, &timer1, NULL, 8, 1, ADCx, 0}, /* D7/PA8 */ - {&gpioa, &timer1, NULL, 9, 2, ADCx}, /* D8/PA9 */ - {&gpioc, NULL, NULL, 7, 0, ADCx}, /* D9/PC7 */ - {&gpiob, &timer4, NULL, 6, 1, ADCx}, /* D10/PB6 */ - {&gpioa, NULL, &adc1, 7, 0, 7}, /* D11/PA7 */ - {&gpioa, NULL, &adc1, 6, 0, 6}, /* D12/PA6 */ - {&gpioa, NULL, NULL, 5, 0, ADCx}, /* D13/PA5 LED - no &adc12_IN5 !*/ - {&gpiob, &timer4, NULL, 9, 4, ADCx}, /* D14/PB9 */ - {&gpiob, &timer4, NULL, 8, 3, ADCx}, /* D15/PB8 */ + {&gpioa, &timer1, NULL, 9, 2, ADCx, 0}, /* D8/PA9 */ + {&gpioc, NULL, NULL, 7, 0, ADCx, 0}, /* D9/PC7 */ + {&gpiob, &timer4, NULL, 6, 1, ADCx, 0}, /* D10/PB6 */ + {&gpioa, NULL, &adc1, 7, 0, 7, 0}, /* D11/PA7 */ + {&gpioa, NULL, &adc1, 6, 0, 6, 0}, /* D12/PA6 */ + {&gpioa, NULL, NULL, 5, 0, ADCx, 0}, /* D13/PA5 LED - no &adc12_IN5 !*/ + {&gpiob, &timer4, NULL, 9, 4, ADCx, 0}, /* D14/PB9 */ + {&gpiob, &timer4, NULL, 8, 3, ADCx, 0}, /* D15/PB8 */ - {&gpioa, NULL, &adc1, 0, 0, 0}, /* D16/A0/PA0 */ - {&gpioa, NULL, &adc1, 1, 0, 1}, /* D17/A1/PA1 */ - {&gpioa, NULL, &adc1, 4, 0, 4}, /* D18/A2/PA4 */ - {&gpiob, &timer3, &adc1, 0, 3, 8}, /* D19/A3/PB0 */ - {&gpioc, NULL, &adc1, 1, 0, 11}, /* D20/A4/PC1 */ - {&gpioc, NULL, &adc1, 0, 0, 10}, /* D21/A5/PC0 */ + {&gpioa, NULL, &adc1, 0, 0, 0, 0}, /* D16/A0/PA0 */ + {&gpioa, NULL, &adc1, 1, 0, 1, 0}, /* D17/A1/PA1 */ + {&gpioa, NULL, &adc1, 4, 0, 4, 0}, /* D18/A2/PA4 */ + {&gpiob, &timer3, &adc1, 0, 3, 8, 0}, /* D19/A3/PB0 */ + {&gpioc, NULL, &adc1, 1, 0, 11, 0}, /* D20/A4/PC1 */ + {&gpioc, NULL, &adc1, 0, 0, 10, 0}, /* D21/A5/PC0 */ - {&gpioc, NULL, NULL, 10, 0, ADCx}, /* D22/PC10 */ - {&gpioc, NULL, NULL, 12, 0, ADCx}, /* D23/PC12 */ - {&gpiob, &timer4, NULL, 7, 2, ADCx}, /* D24/PB7 */ - {&gpioc, NULL, NULL, 13, 0, ADCx}, /* D25/PC13 USER BLUE BUTTON */ - {&gpioc, NULL, NULL, 14, 0, ADCx}, /* D26/PC14 */ - {&gpioc, NULL, NULL, 15, 0, ADCx}, /* D27/PC15 */ - {&gpioc, NULL, &adc1, 2, 0, 12}, /* D28/PC2 */ - {&gpioc, NULL, &adc1, 3, 0, 13}, /* D29/PC3 */ - {&gpioc, NULL, NULL, 11, 0, ADCx}, /* D30/PC11 */ - {&gpiod, NULL, NULL, 2, 0, ADCx}, /* D31/PD2 */ - {&gpioc, NULL, NULL, 9, 0, ADCx}, /* D32/PC9 */ - {&gpioc, NULL, NULL, 8, 0, ADCx}, /* D33/PC8 */ - {&gpioc, NULL, NULL, 6, 0, ADCx}, /* D34/PC6 */ - {&gpioc, NULL, &adc1, 5, 0, 15}, /* D35/PC5 */ - {&gpioa, NULL, NULL, 12, 0, ADCx}, /* D36/PA12 */ - {&gpioa, &timer1, NULL, 11, 4, ADCx}, /* D37/PA11 */ - {&gpiob, NULL, NULL, 12, 0, ADCx}, /* D38/PB12 */ - {&gpiob, &timer2, NULL, 11, 4, ADCx}, /* D39/PB11 PWM-not working?*/ - {&gpiob, NULL, NULL, 2, 0, ADCx}, /* D40/PB2 BOOT1 !!*/ - {&gpiob, &timer3, &adc1, 1, 4, 9}, /* D41/PB1 */ - {&gpiob, NULL, NULL, 15, 0, ADCx}, /* D42/PB15 */ - {&gpiob, NULL, NULL, 14, 0, ADCx}, /* D43/PB14 */ - {&gpiob, NULL, NULL, 13, 0, ADCx}, /* D44/PB13 */ - {&gpioc, NULL, &adc1, 4, 0, 14}, /* D45/PC4 */ - // PMAP_ROW(&gpioa, 13, NULL, 0, NULL, ADCx), /* D41/PA13 do not use*/ - // PMAP_ROW(&gpioa, 14, NULL, 0, NULL, ADCx), /* D42/PA14 do not use*/ - // PMAP_ROW(&gpioa, 15, &timer2, 1, NULL, ADCx), /* D43/PA15 do not use*/ + {&gpioc, NULL, NULL, 10, 0, ADCx, 0}, /* D22/PC10 */ + {&gpioc, NULL, NULL, 12, 0, ADCx, 0}, /* D23/PC12 */ + {&gpiob, &timer4, NULL, 7, 2, ADCx, 0}, /* D24/PB7 */ + {&gpioc, NULL, NULL, 13, 0, ADCx, 0}, /* D25/PC13 USER BLUE BUTTON */ + {&gpioc, NULL, NULL, 14, 0, ADCx, 0}, /* D26/PC14 */ + {&gpioc, NULL, NULL, 15, 0, ADCx, 0}, /* D27/PC15 */ + {&gpioc, NULL, &adc1, 2, 0, 12, 0}, /* D28/PC2 */ + {&gpioc, NULL, &adc1, 3, 0, 13, 0}, /* D29/PC3 */ + {&gpioc, NULL, NULL, 11, 0, ADCx, 0}, /* D30/PC11 */ + {&gpiod, NULL, NULL, 2, 0, ADCx, 0}, /* D31/PD2 */ + {&gpioc, NULL, NULL, 9, 0, ADCx, 0}, /* D32/PC9 */ + {&gpioc, NULL, NULL, 8, 0, ADCx, 0}, /* D33/PC8 */ + {&gpioc, NULL, NULL, 6, 0, ADCx, 0}, /* D34/PC6 */ + {&gpioc, NULL, &adc1, 5, 0, 15, 0}, /* D35/PC5 */ + {&gpioa, NULL, NULL, 12, 0, ADCx, 0}, /* D36/PA12 */ + {&gpioa, &timer1, NULL, 11, 4, ADCx, 0}, /* D37/PA11 */ + {&gpiob, NULL, NULL, 12, 0, ADCx, 0}, /* D38/PB12 */ + {&gpiob, &timer2, NULL, 11, 4, ADCx, 0}, /* D39/PB11 PWM-not working?*/ + {&gpiob, NULL, NULL, 2, 0, ADCx, 0}, /* D40/PB2 BOOT1 !!*/ + {&gpiob, &timer3, &adc1, 1, 4, 9, 0}, /* D41/PB1 */ + {&gpiob, NULL, NULL, 15, 0, ADCx, 0}, /* D42/PB15 */ + {&gpiob, NULL, NULL, 14, 0, ADCx, 0}, /* D43/PB14 */ + {&gpiob, NULL, NULL, 13, 0, ADCx, 0}, /* D44/PB13 */ + {&gpioc, NULL, &adc1, 4, 0, 14, 0}, /* D45/PC4 */ + // PMAP_ROW(&gpioa, 13, NULL, 0, NULL, ADCx, 0), /* D41/PA13 do not use*/ + // PMAP_ROW(&gpioa, 14, NULL, 0, NULL, ADCx, 0), /* D42/PA14 do not use*/ + // PMAP_ROW(&gpioa, 15, &timer2, 1, NULL, ADCx, 0), /* D43/PA15 do not use*/ }; -#pragma GCC diagnostic pop // Array of pins you can use for pwmWrite(). Keep it in Flash because // it doesn't change, and so we don't waste RAM. diff --git a/STM32F3/cores/maple/wirish/boards_private.h b/STM32F3/cores/maple/wirish/boards_private.h index 49867ca..332843d 100644 --- a/STM32F3/cores/maple/wirish/boards_private.h +++ b/STM32F3/cores/maple/wirish/boards_private.h @@ -42,7 +42,7 @@ /* Makes the PIN_MAP rows more human-readable. */ #define PMAP_ROW(gpio_dev, gpio_bit, timer_dev, timer_ch, adc_dev, adc_ch) \ - { gpio_dev, timer_dev, adc_dev, gpio_bit, timer_ch, adc_ch } + { gpio_dev, timer_dev, adc_dev, gpio_bit, timer_ch, adc_ch, 0} namespace wirish { namespace priv { From 048f15a2db84c44a55ec53d61121b348ce116619 Mon Sep 17 00:00:00 2001 From: lacklustrlabs Date: Fri, 17 Nov 2017 11:16:48 +0100 Subject: [PATCH 205/351] Fixed a comment --- STM32F1/variants/nucleo_f103rb/board.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/STM32F1/variants/nucleo_f103rb/board.cpp b/STM32F1/variants/nucleo_f103rb/board.cpp index 5e2672c..a70a188 100644 --- a/STM32F1/variants/nucleo_f103rb/board.cpp +++ b/STM32F1/variants/nucleo_f103rb/board.cpp @@ -145,9 +145,9 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { {&gpiob, NULL, NULL, 14, 0, ADCx, 0}, /* D43/PB14 */ {&gpiob, NULL, NULL, 13, 0, ADCx, 0}, /* D44/PB13 */ {&gpioc, NULL, &adc1, 4, 0, 14, 0}, /* D45/PC4 */ - // PMAP_ROW(&gpioa, 13, NULL, 0, NULL, ADCx, 0), /* D41/PA13 do not use*/ - // PMAP_ROW(&gpioa, 14, NULL, 0, NULL, ADCx, 0), /* D42/PA14 do not use*/ - // PMAP_ROW(&gpioa, 15, &timer2, 1, NULL, ADCx, 0), /* D43/PA15 do not use*/ + // PMAP_ROW(&gpioa, 13, NULL, 0, NULL, ADCx), /* D41/PA13 do not use*/ + // PMAP_ROW(&gpioa, 14, NULL, 0, NULL, ADCx), /* D42/PA14 do not use*/ + // PMAP_ROW(&gpioa, 15, &timer2, 1, NULL, ADCx), /* D43/PA15 do not use*/ }; // Array of pins you can use for pwmWrite(). Keep it in Flash because From 719ab20a5fb1bd6cc77e300fe32278a48c7ee83f Mon Sep 17 00:00:00 2001 From: lacklustrlabs Date: Fri, 17 Nov 2017 14:44:01 +0100 Subject: [PATCH 206/351] Rollback on __attribute__((unused)) for pulseIn() --- STM32F1/cores/maple/stm32f1/wiring_pulse_f1.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/cores/maple/stm32f1/wiring_pulse_f1.cpp b/STM32F1/cores/maple/stm32f1/wiring_pulse_f1.cpp index d9287b0..9ca4d7f 100644 --- a/STM32F1/cores/maple/stm32f1/wiring_pulse_f1.cpp +++ b/STM32F1/cores/maple/stm32f1/wiring_pulse_f1.cpp @@ -26,7 +26,7 @@ * to be slighly more accurate the maxLoops variable really needs to take into account the loop setup code, but its probably as good as necessary * */ -uint32_t pulseIn( uint32_t pin, uint32_t state __attribute__((unused)), uint32_t timeout ) +uint32_t pulseIn( uint32_t pin, uint32_t state, uint32_t timeout ) { // cache the port and bit of the pin in order to speed up the // pulse width measuring loop and achieve finer resolution. calling From b64029f1db45e22f639bd3b882285dc06a0ed01c Mon Sep 17 00:00:00 2001 From: lacklustrlabs Date: Sat, 18 Nov 2017 12:37:11 +0100 Subject: [PATCH 207/351] Rollback WireBase.begin() --- STM32F1/libraries/Wire/WireBase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/libraries/Wire/WireBase.cpp b/STM32F1/libraries/Wire/WireBase.cpp index eaa7f91..220d845 100644 --- a/STM32F1/libraries/Wire/WireBase.cpp +++ b/STM32F1/libraries/Wire/WireBase.cpp @@ -41,7 +41,7 @@ #include "WireBase.h" #include "wirish.h" -void WireBase::begin(uint8 self_addr __attribute__((unused))) { +void WireBase::begin(uint8 self_addr) { tx_buf_idx = 0; tx_buf_overflow = false; rx_buf_idx = 0; From 4a84203917deb692d65175c7c07c83893732861b Mon Sep 17 00:00:00 2001 From: lacklustrlabs Date: Sat, 18 Nov 2017 21:08:20 +0100 Subject: [PATCH 208/351] Modified pulseIn() to use the state parameter --- .../cores/maple/stm32f1/wiring_pulse_f1.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/STM32F1/cores/maple/stm32f1/wiring_pulse_f1.cpp b/STM32F1/cores/maple/stm32f1/wiring_pulse_f1.cpp index 9ca4d7f..32ecc07 100644 --- a/STM32F1/cores/maple/stm32f1/wiring_pulse_f1.cpp +++ b/STM32F1/cores/maple/stm32f1/wiring_pulse_f1.cpp @@ -1,5 +1,6 @@ #include #include "boards.h" +#include "variant.h" /* Measures the length (in microseconds) of a pulse on the pin; state is HIGH * or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds * to 3 minutes in length, but must be called at least a few dozen microseconds @@ -28,13 +29,13 @@ */ uint32_t pulseIn( uint32_t pin, uint32_t state, uint32_t timeout ) { - // cache the port and bit of the pin in order to speed up the + // cache the reg map and bit of the pin in order to speed up the // pulse width measuring loop and achieve finer resolution. calling // digitalRead() instead yields much coarser resolution. - gpio_dev *dev=PIN_MAP[pin].gpio_device; - uint32_t bit = (1U << PIN_MAP[pin].gpio_bit); - + const gpio_reg_map * const regs = digitalPinToPort(pin)->regs; + const uint32_t bit = digitalPinToBitMask(pin); + const uint32_t stateMask = (state ? bit:0); uint32_t width = 0; // keep initialization out of time critical area @@ -45,23 +46,23 @@ uint32_t pulseIn( uint32_t pin, uint32_t state, uint32_t timeout ) volatile uint32_t dummyWidth=0; // wait for any previous pulse to end - while ( (dev->regs->IDR & bit) == bit) { + while ((regs->IDR & bit) == stateMask) { if (numloops++ == maxloops) { return 0; } - dummyWidth++; + dummyWidth++; } // wait for the pulse to start - while ((dev->regs->IDR & bit) != bit) { + while ((regs->IDR & bit) != stateMask) { if (numloops++ == maxloops) { return 0; } - dummyWidth++; + dummyWidth++; } // wait for the pulse to stop - while ((dev->regs->IDR & bit) == bit) { + while ((regs->IDR & bit) == stateMask) { if (numloops++ == maxloops) { return 0; } From 0f6d90943adcfe12ddd69a998d47e5dc2dabb566 Mon Sep 17 00:00:00 2001 From: lacklustrlabs Date: Sun, 19 Nov 2017 09:39:29 +0100 Subject: [PATCH 209/351] Caching IDR pointer --- STM32F1/cores/maple/stm32f1/wiring_pulse_f1.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/STM32F1/cores/maple/stm32f1/wiring_pulse_f1.cpp b/STM32F1/cores/maple/stm32f1/wiring_pulse_f1.cpp index 32ecc07..5a5d835 100644 --- a/STM32F1/cores/maple/stm32f1/wiring_pulse_f1.cpp +++ b/STM32F1/cores/maple/stm32f1/wiring_pulse_f1.cpp @@ -29,11 +29,11 @@ */ uint32_t pulseIn( uint32_t pin, uint32_t state, uint32_t timeout ) { - // cache the reg map and bit of the pin in order to speed up the + // cache the IDR address and bit of the pin in order to speed up the // pulse width measuring loop and achieve finer resolution. calling // digitalRead() instead yields much coarser resolution. - const gpio_reg_map * const regs = digitalPinToPort(pin)->regs; + __io uint32_t * const idr = portInputRegister(digitalPinToPort(pin)); const uint32_t bit = digitalPinToBitMask(pin); const uint32_t stateMask = (state ? bit:0); @@ -46,7 +46,7 @@ uint32_t pulseIn( uint32_t pin, uint32_t state, uint32_t timeout ) volatile uint32_t dummyWidth=0; // wait for any previous pulse to end - while ((regs->IDR & bit) == stateMask) { + while ((*idr & bit) == stateMask) { if (numloops++ == maxloops) { return 0; } @@ -54,7 +54,7 @@ uint32_t pulseIn( uint32_t pin, uint32_t state, uint32_t timeout ) } // wait for the pulse to start - while ((regs->IDR & bit) != stateMask) { + while ((*idr & bit) != stateMask) { if (numloops++ == maxloops) { return 0; } @@ -62,7 +62,7 @@ uint32_t pulseIn( uint32_t pin, uint32_t state, uint32_t timeout ) } // wait for the pulse to stop - while ((regs->IDR & bit) == stateMask) { + while ((*idr & bit) == stateMask) { if (numloops++ == maxloops) { return 0; } From e961f5bb18971c6b84f2b25986e5b3030ce7d3cd Mon Sep 17 00:00:00 2001 From: topin89 Date: Tue, 21 Nov 2017 16:48:45 +0300 Subject: [PATCH 210/351] Update HardwareTimer.h documentation. "attachInterrupt" and "attachInterrupt" functions can attach ISRs to channel 0, which is overflow interrupt (update interrupt in RMs). --- STM32F1/cores/maple/HardwareTimer.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/STM32F1/cores/maple/HardwareTimer.h b/STM32F1/cores/maple/HardwareTimer.h index d5356ca..bb40dba 100644 --- a/STM32F1/cores/maple/HardwareTimer.h +++ b/STM32F1/cores/maple/HardwareTimer.h @@ -177,7 +177,8 @@ public: * This interrupt handler will be called when the timer's counter * reaches the given channel compare value. * - * @param channel the channel to attach the ISR to, from 1 to 4. + * @param channel the channel to attach the ISR to, from 0 to 4. + * Channel 0 is for overflow interrupt (update interrupt). * @param handler The ISR to attach to the given channel. * @see voidFuncPtr */ @@ -189,7 +190,8 @@ public: * * The handler will no longer be called by this timer. * - * @param channel the channel whose interrupt to detach, from 1 to 4. + * @param channel the channel whose interrupt to detach, from 0 to 4. + * Channel 0 is for overflow interrupt (update interrupt). * @see HardwareTimer::attachInterrupt() */ void detachInterrupt(int channel); From 023fdfb0e9cb6acf367a1fe6b8bccafd815efc8b Mon Sep 17 00:00:00 2001 From: stevstrong Date: Sun, 26 Nov 2017 10:37:22 +0100 Subject: [PATCH 211/351] Update TimerInterrupts.ino - replace deprecated function --- .../Maple/TimerInterrupts/TimerInterrupts.ino | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/STM32F1/libraries/A_STM32_Examples/examples/Maple/TimerInterrupts/TimerInterrupts.ino b/STM32F1/libraries/A_STM32_Examples/examples/Maple/TimerInterrupts/TimerInterrupts.ino index e973358..38eb7d0 100644 --- a/STM32F1/libraries/A_STM32_Examples/examples/Maple/TimerInterrupts/TimerInterrupts.ino +++ b/STM32F1/libraries/A_STM32_Examples/examples/Maple/TimerInterrupts/TimerInterrupts.ino @@ -32,24 +32,24 @@ void setup() pinMode(BUTTON_PIN, INPUT_PULLUP); // Setup LED Timer - Timer2.setChannel1Mode(TIMER_OUTPUTCOMPARE); + Timer2.setMode(TIMER_CH1, TIMER_OUTPUTCOMPARE); Timer2.setPeriod(LED_RATE); // in microseconds - Timer2.setCompare1(1); // overflow might be small - Timer2.attachCompare1Interrupt(handler_led); + Timer2.setCompare(TIMER_CH1, 1); // overflow might be small + Timer2.attachInterrupt(TIMER_CH1, handler_led); // Setup Counting Timers - Timer3.setChannel1Mode(TIMER_OUTPUTCOMPARE); - Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE); + Timer3.setMode(TIMER_CH1, TIMER_OUTPUTCOMPARE); + Timer4.setMode(TIMER_CH1, TIMER_OUTPUTCOMPARE); Timer3.pause(); Timer4.pause(); Timer3.setCount(0); Timer4.setCount(0); Timer3.setOverflow(30000); Timer4.setOverflow(30000); - Timer3.setCompare1(1000); // somewhere in the middle - Timer4.setCompare1(1000); - Timer3.attachCompare1Interrupt(handler1); - Timer4.attachCompare1Interrupt(handler2); + Timer3.setCompare(TIMER_CH1, 1000); // somewhere in the middle + Timer4.setCompare(TIMER_CH1, 1000); + Timer3.attachInterrupt(TIMER_CH1, handler1); + Timer4.attachInterrupt(TIMER_CH1, handler2); Timer3.resume(); Timer4.resume(); From bee82cb7c62be8b109a88c097d79fb9dc98ee206 Mon Sep 17 00:00:00 2001 From: victorpv Date: Sun, 26 Nov 2017 09:29:15 -0600 Subject: [PATCH 212/351] Correct a bug in FreeRTOS As listed in https://www.freertos.org/a00104.html#mailing_list: "The definition of the StaticTask_t structure is incorrect if INCLUDE_xTaskAbortDelay is set to 1, or the MPU is used. The corrected structure definition can be obtained from here." https://sourceforge.net/p/freertos/code/HEAD/tree/trunk/FreeRTOS/Source/include/FreeRTOS.h#l978 --- STM32F1/libraries/FreeRTOS900/utility/FreeRTOS.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/STM32F1/libraries/FreeRTOS900/utility/FreeRTOS.h b/STM32F1/libraries/FreeRTOS900/utility/FreeRTOS.h index f81172d..6838f47 100644 --- a/STM32F1/libraries/FreeRTOS900/utility/FreeRTOS.h +++ b/STM32F1/libraries/FreeRTOS900/utility/FreeRTOS.h @@ -948,6 +948,9 @@ typedef struct xSTATIC_TCB #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) uint8_t uxDummy20; #endif + #if( INCLUDE_xTaskAbortDelay == 1 ) + uint8_t ucDummy21; + #endif } StaticTask_t; From aebb14f26cd8fa90ad3a187085f165f46b7867de Mon Sep 17 00:00:00 2001 From: lacklustrlabs Date: Fri, 1 Dec 2017 16:54:16 +0100 Subject: [PATCH 213/351] Rollback to master --- STM32F1/cores/maple/boards_private.h | 2 +- STM32F1/variants/STM32VLD/board.cpp | 103 ++++---- STM32F1/variants/generic_gd32f103c/board.cpp | 73 +++--- STM32F1/variants/generic_stm32f103c/board.cpp | 74 +++--- STM32F1/variants/generic_stm32f103r/board.cpp | 103 ++++---- .../variants/generic_stm32f103r8/board.cpp | 99 ++++---- STM32F1/variants/generic_stm32f103t/board.cpp | 49 ++-- STM32F1/variants/generic_stm32f103v/board.cpp | 161 ++++++------- STM32F1/variants/generic_stm32f103z/board.cpp | 226 +++++++++--------- STM32F1/variants/hytiny_stm32f103t/board.cpp | 49 ++-- STM32F1/variants/maple_mini/board.cpp | 70 +++--- STM32F1/variants/maple_ret6/board.cpp | 100 ++++---- STM32F1/variants/microduino/board.cpp | 50 ++-- STM32F1/variants/nucleo_f103rb/board.cpp | 94 ++++---- STM32F3/cores/maple/wirish/boards_private.h | 2 +- 15 files changed, 634 insertions(+), 621 deletions(-) diff --git a/STM32F1/cores/maple/boards_private.h b/STM32F1/cores/maple/boards_private.h index 332843d..49867ca 100644 --- a/STM32F1/cores/maple/boards_private.h +++ b/STM32F1/cores/maple/boards_private.h @@ -42,7 +42,7 @@ /* Makes the PIN_MAP rows more human-readable. */ #define PMAP_ROW(gpio_dev, gpio_bit, timer_dev, timer_ch, adc_dev, adc_ch) \ - { gpio_dev, timer_dev, adc_dev, gpio_bit, timer_ch, adc_ch, 0} + { gpio_dev, timer_dev, adc_dev, gpio_bit, timer_ch, adc_ch } namespace wirish { namespace priv { diff --git a/STM32F1/variants/STM32VLD/board.cpp b/STM32F1/variants/STM32VLD/board.cpp index 182e8f7..1cecbd9 100644 --- a/STM32F1/variants/STM32VLD/board.cpp +++ b/STM32F1/variants/STM32VLD/board.cpp @@ -51,66 +51,67 @@ void boardInit(void) { } // Note. See the enum of pin names in board.h + extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { - {&gpioa, &timer2, &adc1, 0, 1, 0, 0}, /* PA0 */ - {&gpioa, &timer2, &adc1, 1, 2, 1, 0}, /* PA1 */ - {&gpioa, &timer2, &adc1, 2, 3, 2, 0}, /* PA2 */ - {&gpioa, &timer2, &adc1, 3, 4, 3, 0}, /* PA3 */ - {&gpioa, NULL, &adc1, 4, 0, 4, 0}, /* PA4 */ - {&gpioa, NULL, &adc1, 5, 0, 5, 0}, /* PA5 */ - {&gpioa, &timer3, &adc1, 6, 1, 6, 0}, /* PA6 */ - {&gpioa, &timer3, &adc1, 7, 2, 7, 0}, /* PA7 */ - {&gpioa, &timer1, NULL, 8, 1, ADCx, 0}, /* PA8 */ - {&gpioa, &timer1, NULL, 9, 2, ADCx, 0}, /* PA9 */ - {&gpioa, &timer1, NULL, 10, 3, ADCx, 0}, /* PA10 */ - {&gpioa, NULL, NULL, 11, 0, ADCx, 0}, /* PA11 */ - {&gpioa, NULL, NULL, 12, 0, ADCx, 0}, /* PA12 */ - {&gpioa, NULL, NULL, 13, 0, ADCx, 0}, /* PA13 */ - {&gpioa, NULL, NULL, 14, 0, ADCx, 0}, /* PA14 */ - {&gpioa, NULL, NULL, 15, 0, ADCx, 0}, /* PA15 */ + {&gpioa, &timer2, &adc1, 0, 1, 0}, /* PA0 */ + {&gpioa, &timer2, &adc1, 1, 2, 1}, /* PA1 */ + {&gpioa, &timer2, &adc1, 2, 3, 2}, /* PA2 */ + {&gpioa, &timer2, &adc1, 3, 4, 3}, /* PA3 */ + {&gpioa, NULL, &adc1, 4, 0, 4}, /* PA4 */ + {&gpioa, NULL, &adc1, 5, 0, 5}, /* PA5 */ + {&gpioa, &timer3, &adc1, 6, 1, 6}, /* PA6 */ + {&gpioa, &timer3, &adc1, 7, 2, 7}, /* PA7 */ + {&gpioa, &timer1, NULL, 8, 1, ADCx}, /* PA8 */ + {&gpioa, &timer1, NULL, 9, 2, ADCx}, /* PA9 */ + {&gpioa, &timer1, NULL, 10, 3, ADCx}, /* PA10 */ + {&gpioa, NULL, NULL, 11, 0, ADCx}, /* PA11 */ + {&gpioa, NULL, NULL, 12, 0, ADCx}, /* PA12 */ + {&gpioa, NULL, NULL, 13, 0, ADCx}, /* PA13 */ + {&gpioa, NULL, NULL, 14, 0, ADCx}, /* PA14 */ + {&gpioa, NULL, NULL, 15, 0, ADCx}, /* PA15 */ - {&gpiob, &timer3, &adc1, 0, 3, 8, 0}, /* PB0 */ - {&gpiob, &timer3, &adc1, 1, 4, 9, 0}, /* PB1 */ - {&gpiob, NULL, NULL, 2, 0, ADCx, 0}, /* PB2 */ - {&gpiob, NULL, NULL, 3, 0, ADCx, 0}, /* PB3 */ - {&gpiob, NULL, NULL, 4, 0, ADCx, 0}, /* PB4 */ - {&gpiob, NULL, NULL, 5, 0, ADCx, 0}, /* PB5 */ - {&gpiob, &timer4, NULL, 6, 1, ADCx, 0}, /* PB6 */ - {&gpiob, &timer4, NULL, 7, 2, ADCx, 0}, /* PB7 */ - {&gpiob, &timer4, NULL, 8, 3, ADCx, 0}, /* PB8 */ - {&gpiob, &timer4, NULL, 9, 4, ADCx, 0}, /* PB9 */ - {&gpiob, NULL, NULL, 10, 0, ADCx, 0}, /* PB10 */ - {&gpiob, NULL, NULL, 11, 0, ADCx, 0}, /* PB11 */ - {&gpiob, NULL, NULL, 12, 0, ADCx, 0}, /* PB12 */ - {&gpiob, NULL, NULL, 13, 0, ADCx, 0}, /* PB13 */ - {&gpiob, NULL, NULL, 14, 0, ADCx, 0}, /* PB14 */ - {&gpiob, NULL, NULL, 15, 0, ADCx, 0}, /* PB15 */ + {&gpiob, &timer3, &adc1, 0, 3, 8}, /* PB0 */ + {&gpiob, &timer3, &adc1, 1, 4, 9}, /* PB1 */ + {&gpiob, NULL, NULL, 2, 0, ADCx}, /* PB2 */ + {&gpiob, NULL, NULL, 3, 0, ADCx}, /* PB3 */ + {&gpiob, NULL, NULL, 4, 0, ADCx}, /* PB4 */ + {&gpiob, NULL, NULL, 5, 0, ADCx}, /* PB5 */ + {&gpiob, &timer4, NULL, 6, 1, ADCx}, /* PB6 */ + {&gpiob, &timer4, NULL, 7, 2, ADCx}, /* PB7 */ + {&gpiob, &timer4, NULL, 8, 3, ADCx}, /* PB8 */ + {&gpiob, &timer4, NULL, 9, 4, ADCx}, /* PB9 */ + {&gpiob, NULL, NULL, 10, 0, ADCx}, /* PB10 */ + {&gpiob, NULL, NULL, 11, 0, ADCx}, /* PB11 */ + {&gpiob, NULL, NULL, 12, 0, ADCx}, /* PB12 */ + {&gpiob, NULL, NULL, 13, 0, ADCx}, /* PB13 */ + {&gpiob, NULL, NULL, 14, 0, ADCx}, /* PB14 */ + {&gpiob, NULL, NULL, 15, 0, ADCx}, /* PB15 */ /* Andy Hull - the R8 is similar to the C8 but exposes more GPIO as follows */ - {&gpioc, NULL, &adc1, 0, 0, 10, 0}, /* PC0 */ - {&gpioc, NULL, &adc1, 1, 0, 11, 0}, /* PC1 */ - {&gpioc, NULL, &adc1, 2, 0, 12, 0}, /* PC2 */ - {&gpioc, NULL, &adc1, 3, 0, 13, 0}, /* PC3 */ - {&gpioc, NULL, &adc1, 4, 0, 14, 0}, /* PC4 */ - {&gpioc, NULL, &adc1, 5, 0, 15, 0}, /* PC5 */ + {&gpioc, NULL, &adc1, 0, 0, 10}, /* PC0 */ + {&gpioc, NULL, &adc1, 1, 0, 11}, /* PC1 */ + {&gpioc, NULL, &adc1, 2, 0, 12}, /* PC2 */ + {&gpioc, NULL, &adc1, 3, 0, 13}, /* PC3 */ + {&gpioc, NULL, &adc1, 4, 0, 14}, /* PC4 */ + {&gpioc, NULL, &adc1, 5, 0, 15}, /* PC5 */ - {&gpioc, NULL, NULL, 6, 0, ADCx, 0}, /* PC6 */ - {&gpioc, NULL, NULL, 7, 0, ADCx, 0}, /* PC7 */ - {&gpioc, NULL, NULL, 8, 0, ADCx, 0}, /* PC8 */ - {&gpioc, NULL, NULL, 9, 0, ADCx, 0}, /* PC9 */ + {&gpioc, NULL, NULL, 6, 0, ADCx}, /* PC6 */ + {&gpioc, NULL, NULL, 7, 0, ADCx}, /* PC7 */ + {&gpioc, NULL, NULL, 8, 0, ADCx}, /* PC8 */ + {&gpioc, NULL, NULL, 9, 0, ADCx}, /* PC9 */ - {&gpioc, NULL, NULL, 10, 0, ADCx, 0}, /* PC10 */ - {&gpioc, NULL, NULL, 11, 0, ADCx, 0}, /* PC11 */ - {&gpioc, NULL, NULL, 12, 0, ADCx, 0}, /* PC12 */ - {&gpioc, NULL, NULL, 13, 0, ADCx, 0}, /* PC13 */ - {&gpioc, NULL, NULL, 14, 0, ADCx, 0}, /* PC14 */ - {&gpioc, NULL, NULL, 15, 0, ADCx, 0}, /* PC15 */ + {&gpioc, NULL, NULL, 10, 0, ADCx}, /* PC10 */ + {&gpioc, NULL, NULL, 11, 0, ADCx}, /* PC11 */ + {&gpioc, NULL, NULL, 12, 0, ADCx}, /* PC12 */ + {&gpioc, NULL, NULL, 13, 0, ADCx}, /* PC13 */ + {&gpioc, NULL, NULL, 14, 0, ADCx}, /* PC14 */ + {&gpioc, NULL, NULL, 15, 0, ADCx}, /* PC15 */ - {&gpiod, NULL, NULL, 0, 0, ADCx, 0}, /* PD2 */ - {&gpiod, NULL, NULL, 1, 0, ADCx, 0}, /* PD2 */ - {&gpiod, NULL, NULL, 2, 0, ADCx, 0}, /* PD2 */ + {&gpiod, NULL, NULL, 0, 0, ADCx}, /* PD2 */ + {&gpiod, NULL, NULL, 1, 0, ADCx}, /* PD2 */ + {&gpiod, NULL, NULL, 2, 0, ADCx}, /* PD2 */ }; extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { diff --git a/STM32F1/variants/generic_gd32f103c/board.cpp b/STM32F1/variants/generic_gd32f103c/board.cpp index da22d52..8b136f2 100644 --- a/STM32F1/variants/generic_gd32f103c/board.cpp +++ b/STM32F1/variants/generic_gd32f103c/board.cpp @@ -51,46 +51,49 @@ void boardInit(void) { } // Note. See the enum of pin names in board.h + extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { - {&gpioa, &timer2, &adc1, 0, 1, 0, 0}, /* PA0 */ - {&gpioa, &timer2, &adc1, 1, 2, 1, 0}, /* PA1 */ - {&gpioa, &timer2, &adc1, 2, 3, 2, 0}, /* PA2 */ - {&gpioa, &timer2, &adc1, 3, 4, 3, 0}, /* PA3 */ - {&gpioa, NULL, &adc1, 4, 0, 4, 0}, /* PA4 */ - {&gpioa, NULL, &adc1, 5, 0, 5, 0}, /* PA5 */ - {&gpioa, &timer3, &adc1, 6, 1, 6, 0}, /* PA6 */ - {&gpioa, &timer3, &adc1, 7, 2, 7, 0}, /* PA7 */ - {&gpioa, &timer1, NULL, 8, 1, ADCx, 0}, /* PA8 */ - {&gpioa, &timer1, NULL, 9, 2, ADCx, 0}, /* PA9 */ - {&gpioa, &timer1, NULL, 10, 3, ADCx, 0}, /* PA10 */ - {&gpioa, &timer1, NULL, 11, 4, ADCx, 0}, /* PA11 */ - {&gpioa, NULL, NULL, 12, 0, ADCx, 0}, /* PA12 */ - {&gpioa, NULL, NULL, 13, 0, ADCx, 0}, /* PA13 */ - {&gpioa, NULL, NULL, 14, 0, ADCx, 0}, /* PA14 */ - {&gpioa, NULL, NULL, 15, 0, ADCx, 0}, /* PA15 */ + {&gpioa, &timer2, &adc1, 0, 1, 0}, /* PA0 */ + {&gpioa, &timer2, &adc1, 1, 2, 1}, /* PA1 */ + {&gpioa, &timer2, &adc1, 2, 3, 2}, /* PA2 */ + {&gpioa, &timer2, &adc1, 3, 4, 3}, /* PA3 */ + {&gpioa, NULL, &adc1, 4, 0, 4}, /* PA4 */ + {&gpioa, NULL, &adc1, 5, 0, 5}, /* PA5 */ + {&gpioa, &timer3, &adc1, 6, 1, 6}, /* PA6 */ + {&gpioa, &timer3, &adc1, 7, 2, 7}, /* PA7 */ + {&gpioa, &timer1, NULL, 8, 1, ADCx}, /* PA8 */ + {&gpioa, &timer1, NULL, 9, 2, ADCx}, /* PA9 */ + {&gpioa, &timer1, NULL, 10, 3, ADCx}, /* PA10 */ + {&gpioa, &timer1, NULL, 11, 4, ADCx}, /* PA11 */ + {&gpioa, NULL, NULL, 12, 0, ADCx}, /* PA12 */ + {&gpioa, NULL, NULL, 13, 0, ADCx}, /* PA13 */ + {&gpioa, NULL, NULL, 14, 0, ADCx}, /* PA14 */ + {&gpioa, NULL, NULL, 15, 0, ADCx}, /* PA15 */ - {&gpiob, &timer3, &adc1, 0, 3, 8, 0}, /* PB0 */ - {&gpiob, &timer3, &adc1, 1, 4, 9, 0}, /* PB1 */ - {&gpiob, NULL, NULL, 2, 0, ADCx, 0}, /* PB2 */ - {&gpiob, NULL, NULL, 3, 0, ADCx, 0}, /* PB3 */ - {&gpiob, NULL, NULL, 4, 0, ADCx, 0}, /* PB4 */ - {&gpiob, NULL, NULL, 5, 0, ADCx, 0}, /* PB5 */ - {&gpiob, &timer4, NULL, 6, 1, ADCx, 0}, /* PB6 */ - {&gpiob, &timer4, NULL, 7, 2, ADCx, 0}, /* PB7 */ - {&gpiob, &timer4, NULL, 8, 3, ADCx, 0}, /* PB8 */ - {&gpiob, &timer4, NULL, 9, 4, ADCx, 0}, /* PB9 */ - {&gpiob, NULL, NULL, 10, 0, ADCx, 0}, /* PB10 */ - {&gpiob, NULL, NULL, 11, 0, ADCx, 0}, /* PB11 */ - {&gpiob, NULL, NULL, 12, 0, ADCx, 0}, /* PB12 */ - {&gpiob, NULL, NULL, 13, 0, ADCx, 0}, /* PB13 */ - {&gpiob, NULL, NULL, 14, 0, ADCx, 0}, /* PB14 */ - {&gpiob, NULL, NULL, 15, 0, ADCx, 0}, /* PB15 */ + {&gpiob, &timer3, &adc1, 0, 3, 8}, /* PB0 */ + {&gpiob, &timer3, &adc1, 1, 4, 9}, /* PB1 */ + {&gpiob, NULL, NULL, 2, 0, ADCx}, /* PB2 */ + {&gpiob, NULL, NULL, 3, 0, ADCx}, /* PB3 */ + {&gpiob, NULL, NULL, 4, 0, ADCx}, /* PB4 */ + {&gpiob, NULL, NULL, 5, 0, ADCx}, /* PB5 */ + {&gpiob, &timer4, NULL, 6, 1, ADCx}, /* PB6 */ + {&gpiob, &timer4, NULL, 7, 2, ADCx}, /* PB7 */ + {&gpiob, &timer4, NULL, 8, 3, ADCx}, /* PB8 */ + {&gpiob, &timer4, NULL, 9, 4, ADCx}, /* PB9 */ + {&gpiob, NULL, NULL, 10, 0, ADCx}, /* PB10 */ + {&gpiob, NULL, NULL, 11, 0, ADCx}, /* PB11 */ + {&gpiob, NULL, NULL, 12, 0, ADCx}, /* PB12 */ + {&gpiob, NULL, NULL, 13, 0, ADCx}, /* PB13 */ + {&gpiob, NULL, NULL, 14, 0, ADCx}, /* PB14 */ + {&gpiob, NULL, NULL, 15, 0, ADCx}, /* PB15 */ + + {&gpioc, NULL, NULL, 13, 0, ADCx}, /* PC13 */ + {&gpioc, NULL, NULL, 14, 0, ADCx}, /* PC14 */ + {&gpioc, NULL, NULL, 15, 0, ADCx}, /* PC15 */ + - {&gpioc, NULL, NULL, 13, 0, ADCx, 0}, /* PC13 */ - {&gpioc, NULL, NULL, 14, 0, ADCx, 0}, /* PC14 */ - {&gpioc, NULL, NULL, 15, 0, ADCx, 0}, /* PC15 */ }; diff --git a/STM32F1/variants/generic_stm32f103c/board.cpp b/STM32F1/variants/generic_stm32f103c/board.cpp index 7b33ba8..7102adb 100644 --- a/STM32F1/variants/generic_stm32f103c/board.cpp +++ b/STM32F1/variants/generic_stm32f103c/board.cpp @@ -51,46 +51,50 @@ void boardInit(void) { } // Note. See the enum of pin names in board.h + extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { - {&gpioa, &timer2, &adc1, 0, 1, 0, 0}, /* PA0 */ - {&gpioa, &timer2, &adc1, 1, 2, 1, 0}, /* PA1 */ - {&gpioa, &timer2, &adc1, 2, 3, 2, 0}, /* PA2 */ - {&gpioa, &timer2, &adc1, 3, 4, 3, 0}, /* PA3 */ - {&gpioa, NULL, &adc1, 4, 0, 4, 0}, /* PA4 */ - {&gpioa, NULL, &adc1, 5, 0, 5, 0}, /* PA5 */ - {&gpioa, &timer3, &adc1, 6, 1, 6, 0}, /* PA6 */ - {&gpioa, &timer3, &adc1, 7, 2, 7, 0}, /* PA7 */ - {&gpioa, &timer1, NULL, 8, 1, ADCx, 0}, /* PA8 */ - {&gpioa, &timer1, NULL, 9, 2, ADCx, 0}, /* PA9 */ - {&gpioa, &timer1, NULL, 10, 3, ADCx, 0}, /* PA10 */ - {&gpioa, &timer1, NULL, 11, 4, ADCx, 0}, /* PA11 */ - {&gpioa, NULL, NULL, 12, 0, ADCx, 0}, /* PA12 */ - {&gpioa, NULL, NULL, 13, 0, ADCx, 0}, /* PA13 */ - {&gpioa, NULL, NULL, 14, 0, ADCx, 0}, /* PA14 */ - {&gpioa, NULL, NULL, 15, 0, ADCx, 0}, /* PA15 */ + {&gpioa, &timer2, &adc1, 0, 1, 0}, /* PA0 */ + {&gpioa, &timer2, &adc1, 1, 2, 1}, /* PA1 */ + {&gpioa, &timer2, &adc1, 2, 3, 2}, /* PA2 */ + {&gpioa, &timer2, &adc1, 3, 4, 3}, /* PA3 */ + {&gpioa, NULL, &adc1, 4, 0, 4}, /* PA4 */ + {&gpioa, NULL, &adc1, 5, 0, 5}, /* PA5 */ + {&gpioa, &timer3, &adc1, 6, 1, 6}, /* PA6 */ + {&gpioa, &timer3, &adc1, 7, 2, 7}, /* PA7 */ + {&gpioa, &timer1, NULL, 8, 1, ADCx}, /* PA8 */ + {&gpioa, &timer1, NULL, 9, 2, ADCx}, /* PA9 */ + {&gpioa, &timer1, NULL, 10, 3, ADCx}, /* PA10 */ + {&gpioa, &timer1, NULL, 11, 4, ADCx}, /* PA11 */ + {&gpioa, NULL, NULL, 12, 0, ADCx}, /* PA12 */ + {&gpioa, NULL, NULL, 13, 0, ADCx}, /* PA13 */ + {&gpioa, NULL, NULL, 14, 0, ADCx}, /* PA14 */ + {&gpioa, NULL, NULL, 15, 0, ADCx}, /* PA15 */ - {&gpiob, &timer3, &adc1, 0, 3, 8, 0}, /* PB0 */ - {&gpiob, &timer3, &adc1, 1, 4, 9, 0}, /* PB1 */ - {&gpiob, NULL, NULL, 2, 0, ADCx, 0}, /* PB2 */ - {&gpiob, NULL, NULL, 3, 0, ADCx, 0}, /* PB3 */ - {&gpiob, NULL, NULL, 4, 0, ADCx, 0}, /* PB4 */ - {&gpiob, NULL, NULL, 5, 0, ADCx, 0}, /* PB5 */ - {&gpiob, &timer4, NULL, 6, 1, ADCx, 0}, /* PB6 */ - {&gpiob, &timer4, NULL, 7, 2, ADCx, 0}, /* PB7 */ - {&gpiob, &timer4, NULL, 8, 3, ADCx, 0}, /* PB8 */ - {&gpiob, &timer4, NULL, 9, 4, ADCx, 0}, /* PB9 */ - {&gpiob, NULL, NULL, 10, 0, ADCx, 0}, /* PB10 */ - {&gpiob, NULL, NULL, 11, 0, ADCx, 0}, /* PB11 */ - {&gpiob, NULL, NULL, 12, 0, ADCx, 0}, /* PB12 */ - {&gpiob, NULL, NULL, 13, 0, ADCx, 0}, /* PB13 */ - {&gpiob, NULL, NULL, 14, 0, ADCx, 0}, /* PB14 */ - {&gpiob, NULL, NULL, 15, 0, ADCx, 0}, /* PB15 */ + {&gpiob, &timer3, &adc1, 0, 3, 8}, /* PB0 */ + {&gpiob, &timer3, &adc1, 1, 4, 9}, /* PB1 */ + {&gpiob, NULL, NULL, 2, 0, ADCx}, /* PB2 */ + {&gpiob, NULL, NULL, 3, 0, ADCx}, /* PB3 */ + {&gpiob, NULL, NULL, 4, 0, ADCx}, /* PB4 */ + {&gpiob, NULL, NULL, 5, 0, ADCx}, /* PB5 */ + {&gpiob, &timer4, NULL, 6, 1, ADCx}, /* PB6 */ + {&gpiob, &timer4, NULL, 7, 2, ADCx}, /* PB7 */ + {&gpiob, &timer4, NULL, 8, 3, ADCx}, /* PB8 */ + {&gpiob, &timer4, NULL, 9, 4, ADCx}, /* PB9 */ + {&gpiob, NULL, NULL, 10, 0, ADCx}, /* PB10 */ + {&gpiob, NULL, NULL, 11, 0, ADCx}, /* PB11 */ + {&gpiob, NULL, NULL, 12, 0, ADCx}, /* PB12 */ + {&gpiob, NULL, NULL, 13, 0, ADCx}, /* PB13 */ + {&gpiob, NULL, NULL, 14, 0, ADCx}, /* PB14 */ + {&gpiob, NULL, NULL, 15, 0, ADCx}, /* PB15 */ + + {&gpioc, NULL, NULL, 13, 0, ADCx}, /* PC13 */ + {&gpioc, NULL, NULL, 14, 0, ADCx}, /* PC14 */ + {&gpioc, NULL, NULL, 15, 0, ADCx}, /* PC15 */ + + - {&gpioc, NULL, NULL, 13, 0, ADCx, 0}, /* PC13 */ - {&gpioc, NULL, NULL, 14, 0, ADCx, 0}, /* PC14 */ - {&gpioc, NULL, NULL, 15, 0, ADCx, 0}, /* PC15 */ }; extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { diff --git a/STM32F1/variants/generic_stm32f103r/board.cpp b/STM32F1/variants/generic_stm32f103r/board.cpp index e564425..3e3589c 100644 --- a/STM32F1/variants/generic_stm32f103r/board.cpp +++ b/STM32F1/variants/generic_stm32f103r/board.cpp @@ -69,6 +69,7 @@ void boardInit(void) { // - Timer channel (1 to 4, for PWM), or 0 if none // - ADC device, or NULL if none // - ADC channel, or ADCx if none + extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { /* gpio_dev *gpio_device; GPIO device @@ -80,61 +81,61 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { uint8 pinMode; mode specific by pinMode call (Roger Clark added to optimize compatibility with Arduino API */ - {&gpioa, &timer2, &adc1, 0, 1, 0, 0}, /* PA0 */ - {&gpioa, &timer2, &adc1, 1, 2, 1, 0}, /* PA1 */ - {&gpioa, &timer2, &adc1, 2, 3, 2, 0}, /* PA2 */ - {&gpioa, &timer2, &adc1, 3, 4, 3, 0}, /* PA3 */ - {&gpioa, NULL, &adc1, 4, 0, 4, 0}, /* PA4 */ - {&gpioa, NULL, &adc1, 5, 0, 5, 0}, /* PA5 */ - {&gpioa, &timer3, &adc1, 6, 1, 6, 0}, /* PA6 */ - {&gpioa, &timer3, &adc1, 7, 2, 7, 0}, /* PA7 */ - {&gpioa, &timer1, NULL, 8, 1, ADCx, 0}, /* PA8 */ - {&gpioa, &timer1, NULL, 9, 2, ADCx, 0}, /* PA9 */ - {&gpioa, &timer1, NULL, 10, 3, ADCx, 0}, /* PA10 */ - {&gpioa, NULL, NULL, 11, 0, ADCx, 0}, /* PA11 */ - {&gpioa, NULL, NULL, 12, 0, ADCx, 0}, /* PA12 */ - {&gpioa, NULL, NULL, 13, 0, ADCx, 0}, /* PA13 */ - {&gpioa, NULL, NULL, 14, 0, ADCx, 0}, /* PA14 */ - {&gpioa, NULL, NULL, 15, 0, ADCx, 0}, /* PA15 */ + {&gpioa, &timer2, &adc1, 0, 1, 0}, /* PA0 */ + {&gpioa, &timer2, &adc1, 1, 2, 1}, /* PA1 */ + {&gpioa, &timer2, &adc1, 2, 3, 2}, /* PA2 */ + {&gpioa, &timer2, &adc1, 3, 4, 3}, /* PA3 */ + {&gpioa, NULL, &adc1, 4, 0, 4}, /* PA4 */ + {&gpioa, NULL, &adc1, 5, 0, 5}, /* PA5 */ + {&gpioa, &timer3, &adc1, 6, 1, 6}, /* PA6 */ + {&gpioa, &timer3, &adc1, 7, 2, 7}, /* PA7 */ + {&gpioa, &timer1, NULL, 8, 1, ADCx}, /* PA8 */ + {&gpioa, &timer1, NULL, 9, 2, ADCx}, /* PA9 */ + {&gpioa, &timer1, NULL, 10, 3, ADCx}, /* PA10 */ + {&gpioa, NULL, NULL, 11, 0, ADCx}, /* PA11 */ + {&gpioa, NULL, NULL, 12, 0, ADCx}, /* PA12 */ + {&gpioa, NULL, NULL, 13, 0, ADCx}, /* PA13 */ + {&gpioa, NULL, NULL, 14, 0, ADCx}, /* PA14 */ + {&gpioa, NULL, NULL, 15, 0, ADCx}, /* PA15 */ - {&gpiob, &timer3, &adc1, 0, 3, 8, 0}, /* PB0 */ - {&gpiob, &timer3, &adc1, 1, 4, 9, 0}, /* PB1 */ - {&gpiob, NULL, NULL, 2, 0, ADCx, 0}, /* PB2 */ - {&gpiob, NULL, NULL, 3, 0, ADCx, 0}, /* PB3 */ - {&gpiob, NULL, NULL, 4, 0, ADCx, 0}, /* PB4 */ - {&gpiob, NULL, NULL, 5, 0, ADCx, 0}, /* PB5 */ - {&gpiob, &timer4, NULL, 6, 1, ADCx, 0}, /* PB6 */ - {&gpiob, &timer4, NULL, 7, 2, ADCx, 0}, /* PB7 */ - {&gpiob, &timer4, NULL, 8, 3, ADCx, 0}, /* PB8 */ - {&gpiob, NULL, NULL, 9, 0, ADCx, 0}, /* PB9 */ - {&gpiob, NULL, NULL, 10, 0, ADCx, 0}, /* PB10 */ - {&gpiob, NULL, NULL, 11, 0, ADCx, 0}, /* PB11 */ - {&gpiob, NULL, NULL, 12, 0, ADCx, 0}, /* PB12 */ - {&gpiob, NULL, NULL, 13, 0, ADCx, 0}, /* PB13 */ - {&gpiob, NULL, NULL, 14, 0, ADCx, 0}, /* PB14 */ - {&gpiob, NULL, NULL, 15, 0, ADCx, 0}, /* PB15 */ + {&gpiob, &timer3, &adc1, 0, 3, 8}, /* PB0 */ + {&gpiob, &timer3, &adc1, 1, 4, 9}, /* PB1 */ + {&gpiob, NULL, NULL, 2, 0, ADCx}, /* PB2 */ + {&gpiob, NULL, NULL, 3, 0, ADCx}, /* PB3 */ + {&gpiob, NULL, NULL, 4, 0, ADCx}, /* PB4 */ + {&gpiob, NULL, NULL, 5, 0, ADCx}, /* PB5 */ + {&gpiob, &timer4, NULL, 6, 1, ADCx}, /* PB6 */ + {&gpiob, &timer4, NULL, 7, 2, ADCx}, /* PB7 */ + {&gpiob, &timer4, NULL, 8, 3, ADCx}, /* PB8 */ + {&gpiob, NULL, NULL, 9, 0, ADCx}, /* PB9 */ + {&gpiob, NULL, NULL, 10, 0, ADCx}, /* PB10 */ + {&gpiob, NULL, NULL, 11, 0, ADCx}, /* PB11 */ + {&gpiob, NULL, NULL, 12, 0, ADCx}, /* PB12 */ + {&gpiob, NULL, NULL, 13, 0, ADCx}, /* PB13 */ + {&gpiob, NULL, NULL, 14, 0, ADCx}, /* PB14 */ + {&gpiob, NULL, NULL, 15, 0, ADCx}, /* PB15 */ - {&gpioc, NULL, &adc1, 0, 0, 10, 0}, /* PC0 */ - {&gpioc, NULL, &adc1, 1, 0, 11, 0}, /* PC1 */ - {&gpioc, NULL, &adc1, 2, 0, 12, 0}, /* PC2 */ - {&gpioc, NULL, &adc1, 3, 0, 13, 0}, /* PC3 */ - {&gpioc, NULL, &adc1, 4, 0, 14, 0}, /* PC4 */ - {&gpioc, NULL, &adc1, 5, 0, 15, 0}, /* PC5 */ - {&gpioc, &timer8, NULL, 6, 1, ADCx, 0}, /* PC6 */ - {&gpioc, &timer8, NULL, 7, 2, ADCx, 0}, /* PC7 */ - {&gpioc, &timer8, NULL, 8, 3, ADCx, 0}, /* PC8 */ - {&gpioc, &timer8, NULL, 9, 4, ADCx, 0}, /* PC9 */ - {&gpioc, NULL, NULL, 10, 0, ADCx, 0}, /* PC10 UART4_TX/SDIO_D2 */ - {&gpioc, NULL, NULL, 11, 0, ADCx, 0}, /* PC11 UART4_RX/SDIO_D3 */ - {&gpioc, NULL, NULL, 12, 0, ADCx, 0}, /* PC12 UART5_TX/SDIO_CK */ - {&gpioc, NULL, NULL, 13, 0, ADCx, 0}, /* PC13 TAMPER-RTC */ - {&gpioc, NULL, NULL, 14, 0, ADCx, 0}, /* PC14 OSC32_IN */ - {&gpioc, NULL, NULL, 15, 0, ADCx, 0}, /* PC15 OSC32_OUT */ + {&gpioc, NULL, &adc1, 0, 0, 10}, /* PC0 */ + {&gpioc, NULL, &adc1, 1, 0, 11}, /* PC1 */ + {&gpioc, NULL, &adc1, 2, 0, 12}, /* PC2 */ + {&gpioc, NULL, &adc1, 3, 0, 13}, /* PC3 */ + {&gpioc, NULL, &adc1, 4, 0, 14}, /* PC4 */ + {&gpioc, NULL, &adc1, 5, 0, 15}, /* PC5 */ + {&gpioc, &timer8, NULL, 6, 1, ADCx}, /* PC6 */ + {&gpioc, &timer8, NULL, 7, 2, ADCx}, /* PC7 */ + {&gpioc, &timer8, NULL, 8, 3, ADCx}, /* PC8 */ + {&gpioc, &timer8, NULL, 9, 4, ADCx}, /* PC9 */ + {&gpioc, NULL, NULL, 10, 0, ADCx}, /* PC10 UART4_TX/SDIO_D2 */ + {&gpioc, NULL, NULL, 11, 0, ADCx}, /* PC11 UART4_RX/SDIO_D3 */ + {&gpioc, NULL, NULL, 12, 0, ADCx}, /* PC12 UART5_TX/SDIO_CK */ + {&gpioc, NULL, NULL, 13, 0, ADCx}, /* PC13 TAMPER-RTC */ + {&gpioc, NULL, NULL, 14, 0, ADCx}, /* PC14 OSC32_IN */ + {&gpioc, NULL, NULL, 15, 0, ADCx}, /* PC15 OSC32_OUT */ - {&gpiod, NULL, NULL, 0, 0, ADCx, 0} , /* PD0 OSC_IN */ - {&gpiod, NULL, NULL, 1, 0, ADCx, 0} , /* PD1 OSC_OUT */ - {&gpiod, NULL, NULL, 2, 0, ADCx, 0} , /* PD2 TIM3_ETR/UART5_RX SDIO_CMD */ + {&gpiod, NULL, NULL, 0, 0, ADCx} , /* PD0 OSC_IN */ + {&gpiod, NULL, NULL, 1, 0, ADCx} , /* PD1 OSC_OUT */ + {&gpiod, NULL, NULL, 2, 0, ADCx} , /* PD2 TIM3_ETR/UART5_RX SDIO_CMD */ }; /* Basically everything that is defined as having a timer us PWM */ diff --git a/STM32F1/variants/generic_stm32f103r8/board.cpp b/STM32F1/variants/generic_stm32f103r8/board.cpp index f667d2f..05f85a5 100644 --- a/STM32F1/variants/generic_stm32f103r8/board.cpp +++ b/STM32F1/variants/generic_stm32f103r8/board.cpp @@ -51,64 +51,65 @@ void boardInit(void) { } // Note. See the enum of pin names in board.h + extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { - {&gpioa, &timer2, &adc1, 0, 1, 0, 0}, /* PA0 */ - {&gpioa, &timer2, &adc1, 1, 2, 1, 0}, /* PA1 */ - {&gpioa, &timer2, &adc1, 2, 3, 2, 0}, /* PA2 */ - {&gpioa, &timer2, &adc1, 3, 4, 3, 0}, /* PA3 */ - {&gpioa, NULL, &adc1, 4, 0, 4, 0}, /* PA4 */ - {&gpioa, NULL, &adc1, 5, 0, 5, 0}, /* PA5 */ - {&gpioa, &timer3, &adc1, 6, 1, 6, 0}, /* PA6 */ - {&gpioa, &timer3, &adc1, 7, 2, 7, 0}, /* PA7 */ - {&gpioa, &timer1, NULL, 8, 1, ADCx, 0}, /* PA8 */ - {&gpioa, &timer1, NULL, 9, 2, ADCx, 0}, /* PA9 */ - {&gpioa, &timer1, NULL, 10, 3, ADCx, 0}, /* PA10 */ - {&gpioa, &timer1, NULL, 11, 4, ADCx, 0}, /* PA11 */ - {&gpioa, NULL, NULL, 12, 0, ADCx, 0}, /* PA12 */ - {&gpioa, NULL, NULL, 13, 0, ADCx, 0}, /* PA13 */ - {&gpioa, NULL, NULL, 14, 0, ADCx, 0}, /* PA14 */ - {&gpioa, NULL, NULL, 15, 0, ADCx, 0}, /* PA15 */ + {&gpioa, &timer2, &adc1, 0, 1, 0}, /* PA0 */ + {&gpioa, &timer2, &adc1, 1, 2, 1}, /* PA1 */ + {&gpioa, &timer2, &adc1, 2, 3, 2}, /* PA2 */ + {&gpioa, &timer2, &adc1, 3, 4, 3}, /* PA3 */ + {&gpioa, NULL, &adc1, 4, 0, 4}, /* PA4 */ + {&gpioa, NULL, &adc1, 5, 0, 5}, /* PA5 */ + {&gpioa, &timer3, &adc1, 6, 1, 6}, /* PA6 */ + {&gpioa, &timer3, &adc1, 7, 2, 7}, /* PA7 */ + {&gpioa, &timer1, NULL, 8, 1, ADCx}, /* PA8 */ + {&gpioa, &timer1, NULL, 9, 2, ADCx}, /* PA9 */ + {&gpioa, &timer1, NULL, 10, 3, ADCx}, /* PA10 */ + {&gpioa, &timer1, NULL, 11, 4, ADCx}, /* PA11 */ + {&gpioa, NULL, NULL, 12, 0, ADCx}, /* PA12 */ + {&gpioa, NULL, NULL, 13, 0, ADCx}, /* PA13 */ + {&gpioa, NULL, NULL, 14, 0, ADCx}, /* PA14 */ + {&gpioa, NULL, NULL, 15, 0, ADCx}, /* PA15 */ - {&gpiob, &timer3, &adc1, 0, 3, 8, 0}, /* PB0 */ - {&gpiob, &timer3, &adc1, 1, 4, 9, 0}, /* PB1 */ - {&gpiob, NULL, NULL, 2, 0, ADCx, 0}, /* PB2 */ - {&gpiob, NULL, NULL, 3, 0, ADCx, 0}, /* PB3 */ - {&gpiob, NULL, NULL, 4, 0, ADCx, 0}, /* PB4 */ - {&gpiob, NULL, NULL, 5, 0, ADCx, 0}, /* PB5 */ - {&gpiob, &timer4, NULL, 6, 1, ADCx, 0}, /* PB6 */ - {&gpiob, &timer4, NULL, 7, 2, ADCx, 0}, /* PB7 */ - {&gpiob, &timer4, NULL, 8, 3, ADCx, 0}, /* PB8 */ - {&gpiob, &timer4, NULL, 9, 4, ADCx, 0}, /* PB9 */ - {&gpiob, NULL, NULL, 10, 0, ADCx, 0}, /* PB10 */ - {&gpiob, NULL, NULL, 11, 0, ADCx, 0}, /* PB11 */ - {&gpiob, NULL, NULL, 12, 0, ADCx, 0}, /* PB12 */ - {&gpiob, NULL, NULL, 13, 0, ADCx, 0}, /* PB13 */ - {&gpiob, NULL, NULL, 14, 0, ADCx, 0}, /* PB14 */ - {&gpiob, NULL, NULL, 15, 0, ADCx, 0}, /* PB15 */ + {&gpiob, &timer3, &adc1, 0, 3, 8}, /* PB0 */ + {&gpiob, &timer3, &adc1, 1, 4, 9}, /* PB1 */ + {&gpiob, NULL, NULL, 2, 0, ADCx}, /* PB2 */ + {&gpiob, NULL, NULL, 3, 0, ADCx}, /* PB3 */ + {&gpiob, NULL, NULL, 4, 0, ADCx}, /* PB4 */ + {&gpiob, NULL, NULL, 5, 0, ADCx}, /* PB5 */ + {&gpiob, &timer4, NULL, 6, 1, ADCx}, /* PB6 */ + {&gpiob, &timer4, NULL, 7, 2, ADCx}, /* PB7 */ + {&gpiob, &timer4, NULL, 8, 3, ADCx}, /* PB8 */ + {&gpiob, &timer4, NULL, 9, 4, ADCx}, /* PB9 */ + {&gpiob, NULL, NULL, 10, 0, ADCx}, /* PB10 */ + {&gpiob, NULL, NULL, 11, 0, ADCx}, /* PB11 */ + {&gpiob, NULL, NULL, 12, 0, ADCx}, /* PB12 */ + {&gpiob, NULL, NULL, 13, 0, ADCx}, /* PB13 */ + {&gpiob, NULL, NULL, 14, 0, ADCx}, /* PB14 */ + {&gpiob, NULL, NULL, 15, 0, ADCx}, /* PB15 */ /* Andy Hull - the R8 is similar to the C8 but exposes more GPIO as follows */ - {&gpioc, NULL, &adc1, 0, 0, 10, 0}, /* PC0 */ - {&gpioc, NULL, &adc1, 1, 0, 11, 0}, /* PC1 */ - {&gpioc, NULL, &adc1, 2, 0, 12, 0}, /* PC2 */ - {&gpioc, NULL, &adc1, 3, 0, 13, 0}, /* PC3 */ - {&gpioc, NULL, &adc1, 4, 0, 14, 0}, /* PC4 */ - {&gpioc, NULL, &adc1, 5, 0, 15, 0}, /* PC5 */ + {&gpioc, NULL, &adc1, 0, 0, 10}, /* PC0 */ + {&gpioc, NULL, &adc1, 1, 0, 11}, /* PC1 */ + {&gpioc, NULL, &adc1, 2, 0, 12}, /* PC2 */ + {&gpioc, NULL, &adc1, 3, 0, 13}, /* PC3 */ + {&gpioc, NULL, &adc1, 4, 0, 14}, /* PC4 */ + {&gpioc, NULL, &adc1, 5, 0, 15}, /* PC5 */ - {&gpioc, NULL, NULL, 6, 0, ADCx, 0}, /* PC6 */ - {&gpioc, NULL, NULL, 7, 0, ADCx, 0}, /* PC7 */ - {&gpioc, NULL, NULL, 8, 0, ADCx, 0}, /* PC8 */ - {&gpioc, NULL, NULL, 9, 0, ADCx, 0}, /* PC9 */ + {&gpioc, NULL, NULL, 6, 0, ADCx}, /* PC6 */ + {&gpioc, NULL, NULL, 7, 0, ADCx}, /* PC7 */ + {&gpioc, NULL, NULL, 8, 0, ADCx}, /* PC8 */ + {&gpioc, NULL, NULL, 9, 0, ADCx}, /* PC9 */ - {&gpioc, NULL, NULL, 10, 0, ADCx, 0}, /* PC10 */ - {&gpioc, NULL, NULL, 11, 0, ADCx, 0}, /* PC11 */ - {&gpioc, NULL, NULL, 12, 0, ADCx, 0}, /* PC12 */ - {&gpioc, NULL, NULL, 13, 0, ADCx, 0}, /* PC13 */ - {&gpioc, NULL, NULL, 14, 0, ADCx, 0}, /* PC14 */ - {&gpioc, NULL, NULL, 15, 0, ADCx, 0}, /* PC15 */ + {&gpioc, NULL, NULL, 10, 0, ADCx}, /* PC10 */ + {&gpioc, NULL, NULL, 11, 0, ADCx}, /* PC11 */ + {&gpioc, NULL, NULL, 12, 0, ADCx}, /* PC12 */ + {&gpioc, NULL, NULL, 13, 0, ADCx}, /* PC13 */ + {&gpioc, NULL, NULL, 14, 0, ADCx}, /* PC14 */ + {&gpioc, NULL, NULL, 15, 0, ADCx}, /* PC15 */ - {&gpiod, NULL, NULL, 2, 0, ADCx, 0}, /* PD2 */ + {&gpiod, NULL, NULL, 2, 0, ADCx}, /* PD2 */ }; extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { diff --git a/STM32F1/variants/generic_stm32f103t/board.cpp b/STM32F1/variants/generic_stm32f103t/board.cpp index 85c252c..e7a1dc0 100644 --- a/STM32F1/variants/generic_stm32f103t/board.cpp +++ b/STM32F1/variants/generic_stm32f103t/board.cpp @@ -51,34 +51,35 @@ void boardInit(void) { } // Note. See the enum of pin names in board.h + extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { - {&gpioa, &timer2, &adc1, 0, 1, 0, 0}, /* PA0 */ - {&gpioa, &timer2, &adc1, 1, 2, 1, 0}, /* PA1 */ - {&gpioa, &timer2, &adc1, 2, 3, 2, 0}, /* PA2 */ - {&gpioa, &timer2, &adc1, 3, 4, 3, 0}, /* PA3 */ - {&gpioa, NULL, &adc1, 4, 0, 4, 0}, /* PA4 */ - {&gpioa, NULL, &adc1, 5, 0, 5, 0}, /* PA5 */ - {&gpioa, &timer3, &adc1, 6, 1, 6, 0}, /* PA6 */ - {&gpioa, &timer3, &adc1, 7, 2, 7, 0}, /* PA7 */ - {&gpioa, &timer1, NULL, 8, 1, ADCx, 0}, /* PA8 */ - {&gpioa, &timer1, NULL, 9, 2, ADCx, 0}, /* PA9 */ - {&gpioa, &timer1, NULL, 10, 3, ADCx, 0}, /* PA10 */ - {&gpioa, &timer1, NULL, 11, 4, ADCx, 0}, /* PA11 */ - {&gpioa, NULL, NULL, 12, 0, ADCx, 0}, /* PA12 */ - {&gpioa, NULL, NULL, 13, 0, ADCx, 0}, /* PA13 */ - {&gpioa, NULL, NULL, 14, 0, ADCx, 0}, /* PA14 */ - {&gpioa, NULL, NULL, 15, 0, ADCx, 0}, /* PA15 */ + {&gpioa, &timer2, &adc1, 0, 1, 0}, /* PA0 */ + {&gpioa, &timer2, &adc1, 1, 2, 1}, /* PA1 */ + {&gpioa, &timer2, &adc1, 2, 3, 2}, /* PA2 */ + {&gpioa, &timer2, &adc1, 3, 4, 3}, /* PA3 */ + {&gpioa, NULL, &adc1, 4, 0, 4}, /* PA4 */ + {&gpioa, NULL, &adc1, 5, 0, 5}, /* PA5 */ + {&gpioa, &timer3, &adc1, 6, 1, 6}, /* PA6 */ + {&gpioa, &timer3, &adc1, 7, 2, 7}, /* PA7 */ + {&gpioa, &timer1, NULL, 8, 1, ADCx}, /* PA8 */ + {&gpioa, &timer1, NULL, 9, 2, ADCx}, /* PA9 */ + {&gpioa, &timer1, NULL, 10, 3, ADCx}, /* PA10 */ + {&gpioa, &timer1, NULL, 11, 4, ADCx}, /* PA11 */ + {&gpioa, NULL, NULL, 12, 0, ADCx}, /* PA12 */ + {&gpioa, NULL, NULL, 13, 0, ADCx}, /* PA13 */ + {&gpioa, NULL, NULL, 14, 0, ADCx}, /* PA14 */ + {&gpioa, NULL, NULL, 15, 0, ADCx}, /* PA15 */ - {&gpiob, &timer3, &adc1, 0, 3, 8, 0}, /* PB0 */ - {&gpiob, &timer3, &adc1, 1, 4, 9, 0}, /* PB1 */ - {&gpiob, NULL, NULL, 2, 0, ADCx, 0}, /* PB2 */ - {&gpiob, NULL, NULL, 3, 0, ADCx, 0}, /* PB3 */ - {&gpiob, NULL, NULL, 4, 0, ADCx, 0}, /* PB4 */ - {&gpiob, NULL, NULL, 5, 0, ADCx, 0}, /* PB5 */ - {&gpiob, &timer4, NULL, 6, 1, ADCx, 0}, /* PB6 */ - {&gpiob, &timer4, NULL, 7, 2, ADCx, 0}, /* PB7 */ + {&gpiob, &timer3, &adc1, 0, 3, 8}, /* PB0 */ + {&gpiob, &timer3, &adc1, 1, 4, 9}, /* PB1 */ + {&gpiob, NULL, NULL, 2, 0, ADCx}, /* PB2 */ + {&gpiob, NULL, NULL, 3, 0, ADCx}, /* PB3 */ + {&gpiob, NULL, NULL, 4, 0, ADCx}, /* PB4 */ + {&gpiob, NULL, NULL, 5, 0, ADCx}, /* PB5 */ + {&gpiob, &timer4, NULL, 6, 1, ADCx}, /* PB6 */ + {&gpiob, &timer4, NULL, 7, 2, ADCx}, /* PB7 */ }; extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { diff --git a/STM32F1/variants/generic_stm32f103v/board.cpp b/STM32F1/variants/generic_stm32f103v/board.cpp index a6b3165..9c13772 100644 --- a/STM32F1/variants/generic_stm32f103v/board.cpp +++ b/STM32F1/variants/generic_stm32f103v/board.cpp @@ -68,6 +68,7 @@ void boardInit(void) { // - Timer channel (1 to 4, for PWM), or 0 if none // - ADC device, or NULL if none // - ADC channel, or ADCx if none + extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { /* gpio_dev *gpio_device; GPIO device @@ -78,91 +79,91 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { uint8 adc_channel; Pin ADC channel, or ADCx if none. */ - {&gpioa, &timer2, &adc1, 0, 1, 0, 0}, /* PA0 */ - {&gpioa, &timer2, &adc1, 1, 2, 1, 0}, /* PA1 */ - {&gpioa, &timer2, &adc1, 2, 3, 2, 0}, /* PA2 */ - {&gpioa, &timer2, &adc1, 3, 4, 3, 0}, /* PA3 */ - {&gpioa, NULL, &adc1, 4, 0, 4, 0}, /* PA4 */ - {&gpioa, NULL, &adc1, 5, 0, 5, 0}, /* PA5 */ - {&gpioa, &timer3, &adc1, 6, 1, 6, 0}, /* PA6 */ - {&gpioa, &timer3, &adc1, 7, 2, 7, 0}, /* PA7 */ - {&gpioa, &timer1, NULL, 8, 1, ADCx, 0}, /* PA8 */ - {&gpioa, &timer1, NULL, 9, 2, ADCx, 0}, /* PA9 */ - {&gpioa, &timer1, NULL, 10, 3, ADCx, 0}, /* PA10 */ - {&gpioa, NULL, NULL, 11, 0, ADCx, 0}, /* PA11 */ //Could have &timer1_CH4, but is also CAN_RX and USBDM - {&gpioa, NULL, NULL, 12, 0, ADCx, 0}, /* PA12 */ //Could have &timer1_ETR, but is also CAN_TX and USBDP - {&gpioa, NULL, NULL, 13, 0, ADCx, 0}, /* PA13 */ - {&gpioa, NULL, NULL, 14, 0, ADCx, 0}, /* PA14 */ - {&gpioa, NULL, NULL, 15, 0, ADCx, 0}, /* PA15 */ //SPI3_NSS + {&gpioa, &timer2, &adc1, 0, 1, 0}, /* PA0 */ + {&gpioa, &timer2, &adc1, 1, 2, 1}, /* PA1 */ + {&gpioa, &timer2, &adc1, 2, 3, 2}, /* PA2 */ + {&gpioa, &timer2, &adc1, 3, 4, 3}, /* PA3 */ + {&gpioa, NULL, &adc1, 4, 0, 4}, /* PA4 */ + {&gpioa, NULL, &adc1, 5, 0, 5}, /* PA5 */ + {&gpioa, &timer3, &adc1, 6, 1, 6}, /* PA6 */ + {&gpioa, &timer3, &adc1, 7, 2, 7}, /* PA7 */ + {&gpioa, &timer1, NULL, 8, 1, ADCx}, /* PA8 */ + {&gpioa, &timer1, NULL, 9, 2, ADCx}, /* PA9 */ + {&gpioa, &timer1, NULL, 10, 3, ADCx}, /* PA10 */ + {&gpioa, NULL, NULL, 11, 0, ADCx}, /* PA11 */ //Could have &timer1_CH4, but is also CAN_RX and USBDM + {&gpioa, NULL, NULL, 12, 0, ADCx}, /* PA12 */ //Could have &timer1_ETR, but is also CAN_TX and USBDP + {&gpioa, NULL, NULL, 13, 0, ADCx}, /* PA13 */ + {&gpioa, NULL, NULL, 14, 0, ADCx}, /* PA14 */ + {&gpioa, NULL, NULL, 15, 0, ADCx}, /* PA15 */ //SPI3_NSS - {&gpiob, &timer3, &adc1, 0, 3, 8, 0}, /* PB0 */ - {&gpiob, &timer3, &adc1, 1, 4, 9, 0}, /* PB1 */ + {&gpiob, &timer3, &adc1, 0, 3, 8}, /* PB0 */ + {&gpiob, &timer3, &adc1, 1, 4, 9}, /* PB1 */ /* NOTE PB2 is not included as its Boot 1 */ - {&gpiob, NULL, NULL, 3, 0, ADCx, 0}, /* PB3 */ //JTDO, SPI3_SCK / I2S3_CK/ - {&gpiob, NULL, NULL, 4, 0, ADCx, 0}, /* PB4 */ //NJTRST, SPI3_MISO - {&gpiob, NULL, NULL, 5, 0, ADCx, 0}, /* PB5 */ //I2C1_SMBA/ SPI3_MOSI - {&gpiob, &timer4, NULL, 6, 1, ADCx, 0}, /* PB6 */ //I2C1_SCL(9) - {&gpiob, &timer4, NULL, 7, 2, ADCx, 0}, /* PB7 */ //I2C1_SDA(9) / FSMC_NADV - {&gpiob, &timer4, NULL, 8, 3, ADCx, 0}, /* PB8 */ //SDIO_D4 - {&gpiob, &timer4, NULL, 9, 4, ADCx, 0}, /* PB9 */ //SDIO_D5 - {&gpiob, NULL, NULL, 10, 0, ADCx, 0}, /* PB10 */ //I2C2_SCL/USART3_TX - {&gpiob, NULL, NULL, 11, 0, ADCx, 0}, /* PB11 */ //I2C2_SDA/USART3_RX - {&gpiob, NULL, NULL, 12, 0, ADCx, 0}, /* PB12 */ //SPI2_NSS/I2S2_WS/I2C2_SMBA/USART3_CK - {&gpiob, NULL, NULL, 13, 0, ADCx, 0}, /* PB13 */ //SPI2_SCK/I2S2_CK/USART3_CTS - {&gpiob, NULL, NULL, 14, 0, ADCx, 0}, /* PB14 */ //SPI2_MISO/TIM1_CH2N/USART3_RTS - {&gpiob, NULL, NULL, 15, 0, ADCx, 0}, /* PB15 */ //SPI2_MOSI/I2S2_SD + {&gpiob, NULL, NULL, 3, 0, ADCx}, /* PB3 */ //JTDO, SPI3_SCK / I2S3_CK/ + {&gpiob, NULL, NULL, 4, 0, ADCx}, /* PB4 */ //NJTRST, SPI3_MISO + {&gpiob, NULL, NULL, 5, 0, ADCx}, /* PB5 */ //I2C1_SMBA/ SPI3_MOSI + {&gpiob, &timer4, NULL, 6, 1, ADCx}, /* PB6 */ //I2C1_SCL(9) + {&gpiob, &timer4, NULL, 7, 2, ADCx}, /* PB7 */ //I2C1_SDA(9) / FSMC_NADV + {&gpiob, &timer4, NULL, 8, 3, ADCx}, /* PB8 */ //SDIO_D4 + {&gpiob, &timer4, NULL, 9, 4, ADCx}, /* PB9 */ //SDIO_D5 + {&gpiob, NULL, NULL, 10, 0, ADCx}, /* PB10 */ //I2C2_SCL/USART3_TX + {&gpiob, NULL, NULL, 11, 0, ADCx}, /* PB11 */ //I2C2_SDA/USART3_RX + {&gpiob, NULL, NULL, 12, 0, ADCx}, /* PB12 */ //SPI2_NSS/I2S2_WS/I2C2_SMBA/USART3_CK + {&gpiob, NULL, NULL, 13, 0, ADCx}, /* PB13 */ //SPI2_SCK/I2S2_CK/USART3_CTS + {&gpiob, NULL, NULL, 14, 0, ADCx}, /* PB14 */ //SPI2_MISO/TIM1_CH2N/USART3_RTS + {&gpiob, NULL, NULL, 15, 0, ADCx}, /* PB15 */ //SPI2_MOSI/I2S2_SD - {&gpioc, NULL, &adc1, 0, 0, 10, 0}, /* PC0 */ - {&gpioc, NULL, &adc1, 1, 0, 11, 0}, /* PC1 */ - {&gpioc, NULL, &adc1, 2, 0, 12, 0}, /* PC2 */ - {&gpioc, NULL, &adc1, 3, 0, 13, 0}, /* PC3 */ - {&gpioc, NULL, &adc1, 4, 0, 14, 0}, /* PC4 */ - {&gpioc, NULL, &adc1, 5, 0, 15, 0}, /* PC5 */ - {&gpioc, &timer8, NULL, 6, 1, ADCx, 0}, /* PC6 I2S2_MCK/SDIO_D6*/ - {&gpioc, &timer8, NULL, 7, 2, ADCx, 0}, /* PC7 I2S3_MCK/SDIO_D7*/ - {&gpioc, &timer8, NULL, 8, 3, ADCx, 0}, /* PC8 SDIO_D0*/ - {&gpioc, &timer8, NULL, 9, 4, ADCx, 0}, /* PC9 SDIO_D1*/ - {&gpioc, NULL, NULL, 10, 0, ADCx, 0}, /* PC10 UART4_TX/SDIO_D2 */ - {&gpioc, NULL, NULL, 11, 0, ADCx, 0}, /* PC11 UART4_RX/SDIO_D3 */ - {&gpioc, NULL, NULL, 12, 0, ADCx, 0}, /* PC12 UART5_TX/SDIO_CK */ - {&gpioc, NULL, NULL, 13, 0, ADCx, 0}, /* PC13 TAMPER-RTC/ Limited output*/ - {&gpioc, NULL, NULL, 14, 0, ADCx, 0}, /* PC14 OSC32_IN/ Limited output*/ - {&gpioc, NULL, NULL, 15, 0, ADCx, 0}, /* PC15 OSC32_OUT/ Limited output*/ + {&gpioc, NULL, &adc1, 0, 0, 10}, /* PC0 */ + {&gpioc, NULL, &adc1, 1, 0, 11}, /* PC1 */ + {&gpioc, NULL, &adc1, 2, 0, 12}, /* PC2 */ + {&gpioc, NULL, &adc1, 3, 0, 13}, /* PC3 */ + {&gpioc, NULL, &adc1, 4, 0, 14}, /* PC4 */ + {&gpioc, NULL, &adc1, 5, 0, 15}, /* PC5 */ + {&gpioc, &timer8, NULL, 6, 1, ADCx}, /* PC6 I2S2_MCK/SDIO_D6*/ + {&gpioc, &timer8, NULL, 7, 2, ADCx}, /* PC7 I2S3_MCK/SDIO_D7*/ + {&gpioc, &timer8, NULL, 8, 3, ADCx}, /* PC8 SDIO_D0*/ + {&gpioc, &timer8, NULL, 9, 4, ADCx}, /* PC9 SDIO_D1*/ + {&gpioc, NULL, NULL, 10, 0, ADCx}, /* PC10 UART4_TX/SDIO_D2 */ + {&gpioc, NULL, NULL, 11, 0, ADCx}, /* PC11 UART4_RX/SDIO_D3 */ + {&gpioc, NULL, NULL, 12, 0, ADCx}, /* PC12 UART5_TX/SDIO_CK */ + {&gpioc, NULL, NULL, 13, 0, ADCx}, /* PC13 TAMPER-RTC/ Limited output*/ + {&gpioc, NULL, NULL, 14, 0, ADCx}, /* PC14 OSC32_IN/ Limited output*/ + {&gpioc, NULL, NULL, 15, 0, ADCx}, /* PC15 OSC32_OUT/ Limited output*/ - {&gpiod, NULL, NULL, 0, 0, ADCx, 0} , /* PD0 OSC_IN */ - {&gpiod, NULL, NULL, 1, 0, ADCx, 0} , /* PD1 OSC_OUT */ - {&gpiod, NULL, NULL, 2, 0, ADCx, 0} , /* PD2 TIM3_ETR/UART5_RX SDIO_CMD */ - {&gpiod, NULL, NULL, 3, 0, ADCx, 0} , /* PD3 FSMC_CLK */ - {&gpiod, NULL, NULL, 4, 0, ADCx, 0} , /* PD4 FSMC_NOE */ - {&gpiod, NULL, NULL, 5, 0, ADCx, 0} , /* PD5 FSMC_NWE */ - {&gpiod, NULL, NULL, 6, 0, ADCx, 0} , /* PD6 FSMC_NWAIT */ - {&gpiod, NULL, NULL, 7, 0, ADCx, 0} , /* PD7 FSMC_NE1/FSMC_NCE2 */ - {&gpiod, NULL, NULL, 8, 0, ADCx, 0} , /* PD8 FSMC_D13 */ - {&gpiod, NULL, NULL, 9, 0, ADCx, 0} , /* PD9 FSMC_D14 */ - {&gpiod, NULL, NULL, 10, 0, ADCx, 0} , /* PD10 FSMC_D15 */ - {&gpiod, NULL, NULL, 11, 0, ADCx, 0} , /* PD11 FSMC_A16 */ - {&gpiod, NULL, NULL, 12, 0, ADCx, 0} , /* PD12 FSMC_A17 */ - {&gpiod, NULL, NULL, 13, 0, ADCx, 0} , /* PD13 FSMC_A18 */ - {&gpiod, NULL, NULL, 14, 0, ADCx, 0} , /* PD14 FSMC_D0 */ - {&gpiod, NULL, NULL, 15, 0, ADCx, 0} , /* PD15 FSMC_D1 */ + {&gpiod, NULL, NULL, 0, 0, ADCx} , /* PD0 OSC_IN */ + {&gpiod, NULL, NULL, 1, 0, ADCx} , /* PD1 OSC_OUT */ + {&gpiod, NULL, NULL, 2, 0, ADCx} , /* PD2 TIM3_ETR/UART5_RX SDIO_CMD */ + {&gpiod, NULL, NULL, 3, 0, ADCx} , /* PD3 FSMC_CLK */ + {&gpiod, NULL, NULL, 4, 0, ADCx} , /* PD4 FSMC_NOE */ + {&gpiod, NULL, NULL, 5, 0, ADCx} , /* PD5 FSMC_NWE */ + {&gpiod, NULL, NULL, 6, 0, ADCx} , /* PD6 FSMC_NWAIT */ + {&gpiod, NULL, NULL, 7, 0, ADCx} , /* PD7 FSMC_NE1/FSMC_NCE2 */ + {&gpiod, NULL, NULL, 8, 0, ADCx} , /* PD8 FSMC_D13 */ + {&gpiod, NULL, NULL, 9, 0, ADCx} , /* PD9 FSMC_D14 */ + {&gpiod, NULL, NULL, 10, 0, ADCx} , /* PD10 FSMC_D15 */ + {&gpiod, NULL, NULL, 11, 0, ADCx} , /* PD11 FSMC_A16 */ + {&gpiod, NULL, NULL, 12, 0, ADCx} , /* PD12 FSMC_A17 */ + {&gpiod, NULL, NULL, 13, 0, ADCx} , /* PD13 FSMC_A18 */ + {&gpiod, NULL, NULL, 14, 0, ADCx} , /* PD14 FSMC_D0 */ + {&gpiod, NULL, NULL, 15, 0, ADCx} , /* PD15 FSMC_D1 */ - {&gpioe, NULL, NULL, 0, 0, ADCx, 0} , /* PE0 TIM4_ETR / FSMC_NBL0 */ - {&gpioe, NULL, NULL, 1, 0, ADCx, 0} , /* PE1 FSMC_NBL1 */ - {&gpioe, NULL, NULL, 2, 0, ADCx, 0} , /* PE2 TRACECK/ FSMC_A23 */ - {&gpioe, NULL, NULL, 3, 0, ADCx, 0} , /* PE3 TRACED0/FSMC_A19 */ - {&gpioe, NULL, NULL, 4, 0, ADCx, 0} , /* PE4 TRACED1/FSMC_A20 */ - {&gpioe, NULL, NULL, 5, 0, ADCx, 0} , /* PE5 TRACED2/FSMC_A21 */ - {&gpioe, NULL, NULL, 6, 0, ADCx, 0} , /* PE6 TRACED3/FSMC_A22 */ - {&gpioe, NULL, NULL, 7, 0, ADCx, 0} , /* PE7 FSMC_D4 */ - {&gpioe, NULL, NULL, 8, 0, ADCx, 0} , /* PE8 FSMC_D5 */ - {&gpioe, NULL, NULL, 9, 0, ADCx, 0} , /* PE9 FSMC_D6 */ - {&gpioe, NULL, NULL, 10, 0, ADCx, 0} , /* PE10 FSMC_D7 */ - {&gpioe, NULL, NULL, 11, 0, ADCx, 0} , /* PE11 FSMC_D8 */ - {&gpioe, NULL, NULL, 12, 0, ADCx, 0} , /* PE12 FSMC_D9 */ - {&gpioe, NULL, NULL, 13, 0, ADCx, 0} , /* PE13 FSMC_D10 */ - {&gpioe, NULL, NULL, 14, 0, ADCx, 0} , /* PE14 FSMC_D11 */ - {&gpioe, NULL, NULL, 15, 0, ADCx, 0} , /* PE15 FSMC_D12 */ + {&gpioe, NULL, NULL, 0, 0, ADCx} , /* PE0 TIM4_ETR / FSMC_NBL0 */ + {&gpioe, NULL, NULL, 1, 0, ADCx} , /* PE1 FSMC_NBL1 */ + {&gpioe, NULL, NULL, 2, 0, ADCx} , /* PE2 TRACECK/ FSMC_A23 */ + {&gpioe, NULL, NULL, 3, 0, ADCx} , /* PE3 TRACED0/FSMC_A19 */ + {&gpioe, NULL, NULL, 4, 0, ADCx} , /* PE4 TRACED1/FSMC_A20 */ + {&gpioe, NULL, NULL, 5, 0, ADCx} , /* PE5 TRACED2/FSMC_A21 */ + {&gpioe, NULL, NULL, 6, 0, ADCx} , /* PE6 TRACED3/FSMC_A22 */ + {&gpioe, NULL, NULL, 7, 0, ADCx} , /* PE7 FSMC_D4 */ + {&gpioe, NULL, NULL, 8, 0, ADCx} , /* PE8 FSMC_D5 */ + {&gpioe, NULL, NULL, 9, 0, ADCx} , /* PE9 FSMC_D6 */ + {&gpioe, NULL, NULL, 10, 0, ADCx} , /* PE10 FSMC_D7 */ + {&gpioe, NULL, NULL, 11, 0, ADCx} , /* PE11 FSMC_D8 */ + {&gpioe, NULL, NULL, 12, 0, ADCx} , /* PE12 FSMC_D9 */ + {&gpioe, NULL, NULL, 13, 0, ADCx} , /* PE13 FSMC_D10 */ + {&gpioe, NULL, NULL, 14, 0, ADCx} , /* PE14 FSMC_D11 */ + {&gpioe, NULL, NULL, 15, 0, ADCx} , /* PE15 FSMC_D12 */ }; @@ -195,4 +196,4 @@ extern const uint8 boardUsedPins[BOARD_NR_USED_PINS] __FLASH__ = { DEFINE_HWSERIAL(Serial2, 3); DEFINE_HWSERIAL_UART(Serial3, 4); DEFINE_HWSERIAL_UART(Serial4, 5); -#endif +#endif \ No newline at end of file diff --git a/STM32F1/variants/generic_stm32f103z/board.cpp b/STM32F1/variants/generic_stm32f103z/board.cpp index 0d112a3..830479e 100644 --- a/STM32F1/variants/generic_stm32f103z/board.cpp +++ b/STM32F1/variants/generic_stm32f103z/board.cpp @@ -80,126 +80,126 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { uint8 pinMode; mode specific by pinMode call (Roger Clark added to optimize compatibility with Arduino API */ - {&gpioa, &timer2, &adc1, 0, 1, 0, 0}, /* PA0 */ - {&gpioa, &timer2, &adc1, 1, 2, 1, 0}, /* PA1 */ - {&gpioa, &timer2, &adc1, 2, 3, 2, 0}, /* PA2 */ - {&gpioa, &timer2, &adc1, 3, 4, 3, 0}, /* PA3 */ - {&gpioa, NULL, &adc1, 4, 0, 4, 0}, /* PA4 */ - {&gpioa, NULL, &adc1, 5, 0, 5, 0}, /* PA5 */ - {&gpioa, &timer3, &adc1, 6, 1, 6, 0}, /* PA6 */ - {&gpioa, &timer3, &adc1, 7, 2, 7, 0}, /* PA7 */ - {&gpioa, &timer1, NULL, 8, 1, ADCx, 0}, /* PA8 */ - {&gpioa, &timer1, NULL, 9, 2, ADCx, 0}, /* PA9 */ - {&gpioa, &timer1, NULL, 10, 3, ADCx, 0}, /* PA10 */ - {&gpioa, NULL, NULL, 11, 0, ADCx, 0}, /* PA11 */ - {&gpioa, NULL, NULL, 12, 0, ADCx, 0}, /* PA12 */ - {&gpioa, NULL, NULL, 13, 0, ADCx, 0}, /* PA13 */ - {&gpioa, NULL, NULL, 14, 0, ADCx, 0}, /* PA14 */ - {&gpioa, NULL, NULL, 15, 0, ADCx, 0}, /* PA15 */ + {&gpioa, &timer2, &adc1, 0, 1, 0}, /* PA0 */ + {&gpioa, &timer2, &adc1, 1, 2, 1}, /* PA1 */ + {&gpioa, &timer2, &adc1, 2, 3, 2}, /* PA2 */ + {&gpioa, &timer2, &adc1, 3, 4, 3}, /* PA3 */ + {&gpioa, NULL, &adc1, 4, 0, 4}, /* PA4 */ + {&gpioa, NULL, &adc1, 5, 0, 5}, /* PA5 */ + {&gpioa, &timer3, &adc1, 6, 1, 6}, /* PA6 */ + {&gpioa, &timer3, &adc1, 7, 2, 7}, /* PA7 */ + {&gpioa, &timer1, NULL, 8, 1, ADCx}, /* PA8 */ + {&gpioa, &timer1, NULL, 9, 2, ADCx}, /* PA9 */ + {&gpioa, &timer1, NULL, 10, 3, ADCx}, /* PA10 */ + {&gpioa, NULL, NULL, 11, 0, ADCx}, /* PA11 */ + {&gpioa, NULL, NULL, 12, 0, ADCx}, /* PA12 */ + {&gpioa, NULL, NULL, 13, 0, ADCx}, /* PA13 */ + {&gpioa, NULL, NULL, 14, 0, ADCx}, /* PA14 */ + {&gpioa, NULL, NULL, 15, 0, ADCx}, /* PA15 */ - {&gpiob, &timer3, &adc1, 0, 3, 8, 0}, /* PB0 */ - {&gpiob, &timer3, &adc1, 1, 4, 9, 0}, /* PB1 */ - {&gpiob, &timer3, &adc1, 2, 4, 9, 0}, /* PB2 */ - {&gpiob, NULL, NULL, 3, 0, ADCx, 0}, /* PB3 */ - {&gpiob, NULL, NULL, 4, 0, ADCx, 0}, /* PB4 */ - {&gpiob, NULL, NULL, 5, 0, ADCx, 0}, /* PB5 */ - {&gpiob, &timer4, NULL, 6, 1, ADCx, 0}, /* PB6 */ - {&gpiob, &timer4, NULL, 7, 2, ADCx, 0}, /* PB7 */ - {&gpiob, &timer4, NULL, 8, 3, ADCx, 0}, /* PB8 */ - {&gpiob, &timer4, NULL, 9, 4, ADCx, 0}, /* PB9 */ - {&gpiob, NULL, NULL, 10, 0, ADCx, 0}, /* PB10 */ - {&gpiob, NULL, NULL, 11, 0, ADCx, 0}, /* PB11 */ - {&gpiob, NULL, NULL, 12, 0, ADCx, 0}, /* PB12 */ - {&gpiob, NULL, NULL, 13, 0, ADCx, 0}, /* PB13 */ - {&gpiob, NULL, NULL, 14, 0, ADCx, 0}, /* PB14 */ - {&gpiob, NULL, NULL, 15, 0, ADCx, 0}, /* PB15 */ + {&gpiob, &timer3, &adc1, 0, 3, 8}, /* PB0 */ + {&gpiob, &timer3, &adc1, 1, 4, 9}, /* PB1 */ + {&gpiob, &timer3, &adc1, 2, 4, 9}, /* PB2 */ + {&gpiob, NULL, NULL, 3, 0, ADCx}, /* PB3 */ + {&gpiob, NULL, NULL, 4, 0, ADCx}, /* PB4 */ + {&gpiob, NULL, NULL, 5, 0, ADCx}, /* PB5 */ + {&gpiob, &timer4, NULL, 6, 1, ADCx}, /* PB6 */ + {&gpiob, &timer4, NULL, 7, 2, ADCx}, /* PB7 */ + {&gpiob, &timer4, NULL, 8, 3, ADCx}, /* PB8 */ + {&gpiob, &timer4, NULL, 9, 4, ADCx}, /* PB9 */ + {&gpiob, NULL, NULL, 10, 0, ADCx}, /* PB10 */ + {&gpiob, NULL, NULL, 11, 0, ADCx}, /* PB11 */ + {&gpiob, NULL, NULL, 12, 0, ADCx}, /* PB12 */ + {&gpiob, NULL, NULL, 13, 0, ADCx}, /* PB13 */ + {&gpiob, NULL, NULL, 14, 0, ADCx}, /* PB14 */ + {&gpiob, NULL, NULL, 15, 0, ADCx}, /* PB15 */ - {&gpioc, NULL, &adc1, 0, 0, 10, 0}, /* PC0 */ - {&gpioc, NULL, &adc1, 1, 0, 11, 0}, /* PC1 */ - {&gpioc, NULL, &adc1, 2, 0, 12, 0}, /* PC2 */ - {&gpioc, NULL, &adc1, 3, 0, 13, 0}, /* PC3 */ - {&gpioc, NULL, &adc1, 4, 0, 14, 0}, /* PC4 */ - {&gpioc, NULL, &adc1, 5, 0, 15, 0}, /* PC5 */ - {&gpioc, &timer8, NULL, 6, 1, ADCx, 0}, /* PC6 */ - {&gpioc, &timer8, NULL, 7, 2, ADCx, 0}, /* PC7 */ - {&gpioc, &timer8, NULL, 8, 3, ADCx, 0}, /* PC8 */ - {&gpioc, &timer8, NULL, 9, 4, ADCx, 0}, /* PC9 */ - {&gpioc, NULL, NULL, 10, 0, ADCx, 0}, /* PC10 UART4_TX/SDIO_D2 */ - {&gpioc, NULL, NULL, 11, 0, ADCx, 0}, /* PC11 UART4_RX/SDIO_D3 */ - {&gpioc, NULL, NULL, 12, 0, ADCx, 0}, /* PC12 UART5_TX/SDIO_CK */ - {&gpioc, NULL, NULL, 13, 0, ADCx, 0}, /* PC13 TAMPER-RTC */ - {&gpioc, NULL, NULL, 14, 0, ADCx, 0}, /* PC14 OSC32_IN */ - {&gpioc, NULL, NULL, 15, 0, ADCx, 0}, /* PC15 OSC32_OUT */ + {&gpioc, NULL, &adc1, 0, 0, 10}, /* PC0 */ + {&gpioc, NULL, &adc1, 1, 0, 11}, /* PC1 */ + {&gpioc, NULL, &adc1, 2, 0, 12}, /* PC2 */ + {&gpioc, NULL, &adc1, 3, 0, 13}, /* PC3 */ + {&gpioc, NULL, &adc1, 4, 0, 14}, /* PC4 */ + {&gpioc, NULL, &adc1, 5, 0, 15}, /* PC5 */ + {&gpioc, &timer8, NULL, 6, 1, ADCx}, /* PC6 */ + {&gpioc, &timer8, NULL, 7, 2, ADCx}, /* PC7 */ + {&gpioc, &timer8, NULL, 8, 3, ADCx}, /* PC8 */ + {&gpioc, &timer8, NULL, 9, 4, ADCx}, /* PC9 */ + {&gpioc, NULL, NULL, 10, 0, ADCx}, /* PC10 UART4_TX/SDIO_D2 */ + {&gpioc, NULL, NULL, 11, 0, ADCx}, /* PC11 UART4_RX/SDIO_D3 */ + {&gpioc, NULL, NULL, 12, 0, ADCx}, /* PC12 UART5_TX/SDIO_CK */ + {&gpioc, NULL, NULL, 13, 0, ADCx}, /* PC13 TAMPER-RTC */ + {&gpioc, NULL, NULL, 14, 0, ADCx}, /* PC14 OSC32_IN */ + {&gpioc, NULL, NULL, 15, 0, ADCx}, /* PC15 OSC32_OUT */ - {&gpiod, NULL, NULL, 0, 0, ADCx, 0} , /* PD0 OSC_IN */ - {&gpiod, NULL, NULL, 1, 0, ADCx, 0} , /* PD1 OSC_OUT */ - {&gpiod, NULL, NULL, 2, 0, ADCx, 0} , /* PD2 TIM3_ETR/UART5_RX SDIO_CMD */ + {&gpiod, NULL, NULL, 0, 0, ADCx} , /* PD0 OSC_IN */ + {&gpiod, NULL, NULL, 1, 0, ADCx} , /* PD1 OSC_OUT */ + {&gpiod, NULL, NULL, 2, 0, ADCx} , /* PD2 TIM3_ETR/UART5_RX SDIO_CMD */ - {&gpiod, NULL, NULL, 3, 0, ADCx, 0} , /* PD3 FSMC_CLK */ - {&gpiod, NULL, NULL, 4, 0, ADCx, 0} , /* PD4 FSMC_NOE */ - {&gpiod, NULL, NULL, 5, 0, ADCx, 0} , /* PD5 FSMC_NWE */ - {&gpiod, NULL, NULL, 6, 0, ADCx, 0} , /* PD6 FSMC_NWAIT */ - {&gpiod, NULL, NULL, 7, 0, ADCx, 0} , /* PD7 FSMC_NE1/FSMC_NCE2 */ - {&gpiod, NULL, NULL, 8, 0, ADCx, 0} , /* PD8 FSMC_D13 */ - {&gpiod, NULL, NULL, 9, 0, ADCx, 0} , /* PD9 FSMC_D14 */ - {&gpiod, NULL, NULL, 10, 0, ADCx, 0} , /* PD10 FSMC_D15 */ - {&gpiod, NULL, NULL, 11, 0, ADCx, 0} , /* PD11 FSMC_A16 */ - {&gpiod, NULL, NULL, 12, 0, ADCx, 0} , /* PD12 FSMC_A17 */ - {&gpiod, NULL, NULL, 13, 0, ADCx, 0} , /* PD13 FSMC_A18 */ - {&gpiod, NULL, NULL, 14, 0, ADCx, 0} , /* PD14 FSMC_D0 */ - {&gpiod, NULL, NULL, 15, 0, ADCx, 0} , /* PD15 FSMC_D1 */ + {&gpiod, NULL, NULL, 3, 0, ADCx} , /* PD3 FSMC_CLK */ + {&gpiod, NULL, NULL, 4, 0, ADCx} , /* PD4 FSMC_NOE */ + {&gpiod, NULL, NULL, 5, 0, ADCx} , /* PD5 FSMC_NWE */ + {&gpiod, NULL, NULL, 6, 0, ADCx} , /* PD6 FSMC_NWAIT */ + {&gpiod, NULL, NULL, 7, 0, ADCx} , /* PD7 FSMC_NE1/FSMC_NCE2 */ + {&gpiod, NULL, NULL, 8, 0, ADCx} , /* PD8 FSMC_D13 */ + {&gpiod, NULL, NULL, 9, 0, ADCx} , /* PD9 FSMC_D14 */ + {&gpiod, NULL, NULL, 10, 0, ADCx} , /* PD10 FSMC_D15 */ + {&gpiod, NULL, NULL, 11, 0, ADCx} , /* PD11 FSMC_A16 */ + {&gpiod, NULL, NULL, 12, 0, ADCx} , /* PD12 FSMC_A17 */ + {&gpiod, NULL, NULL, 13, 0, ADCx} , /* PD13 FSMC_A18 */ + {&gpiod, NULL, NULL, 14, 0, ADCx} , /* PD14 FSMC_D0 */ + {&gpiod, NULL, NULL, 15, 0, ADCx} , /* PD15 FSMC_D1 */ - {&gpioe, NULL, NULL, 0, 0, ADCx, 0} , /* PE0 */ - {&gpioe, NULL, NULL, 1, 0, ADCx, 0} , /* PE1 */ - {&gpioe, NULL, NULL, 2, 0, ADCx, 0} , /* PE2 */ - {&gpioe, NULL, NULL, 3, 0, ADCx, 0} , /* PE3 */ - {&gpioe, NULL, NULL, 4, 0, ADCx, 0} , /* PE4 */ - {&gpioe, NULL, NULL, 5, 0, ADCx, 0} , /* PE5 */ - {&gpioe, NULL, NULL, 6, 0, ADCx, 0} , /* PE6 */ - {&gpioe, NULL, NULL, 7, 0, ADCx, 0} , /* PE7 */ - {&gpioe, NULL, NULL, 8, 0, ADCx, 0} , /* PE8 */ - {&gpioe, NULL, NULL, 9, 0, ADCx, 0} , /* PE9 */ - {&gpioe, NULL, NULL, 10, 0, ADCx, 0} , /* PE10 */ - {&gpioe, NULL, NULL, 11, 0, ADCx, 0} , /* PE11 */ - {&gpioe, NULL, NULL, 12, 0, ADCx, 0} , /* PE12 */ - {&gpioe, NULL, NULL, 13, 0, ADCx, 0} , /* PE13 */ - {&gpioe, NULL, NULL, 14, 0, ADCx, 0} , /* PE14 */ - {&gpioe, NULL, NULL, 15, 0, ADCx, 0} , /* PE15 */ + {&gpioe, NULL, NULL, 0, 0, ADCx} , /* PE0 */ + {&gpioe, NULL, NULL, 1, 0, ADCx} , /* PE1 */ + {&gpioe, NULL, NULL, 2, 0, ADCx} , /* PE2 */ + {&gpioe, NULL, NULL, 3, 0, ADCx} , /* PE3 */ + {&gpioe, NULL, NULL, 4, 0, ADCx} , /* PE4 */ + {&gpioe, NULL, NULL, 5, 0, ADCx} , /* PE5 */ + {&gpioe, NULL, NULL, 6, 0, ADCx} , /* PE6 */ + {&gpioe, NULL, NULL, 7, 0, ADCx} , /* PE7 */ + {&gpioe, NULL, NULL, 8, 0, ADCx} , /* PE8 */ + {&gpioe, NULL, NULL, 9, 0, ADCx} , /* PE9 */ + {&gpioe, NULL, NULL, 10, 0, ADCx} , /* PE10 */ + {&gpioe, NULL, NULL, 11, 0, ADCx} , /* PE11 */ + {&gpioe, NULL, NULL, 12, 0, ADCx} , /* PE12 */ + {&gpioe, NULL, NULL, 13, 0, ADCx} , /* PE13 */ + {&gpioe, NULL, NULL, 14, 0, ADCx} , /* PE14 */ + {&gpioe, NULL, NULL, 15, 0, ADCx} , /* PE15 */ - {&gpiof, NULL, NULL, 0, 0, ADCx, 0} , /* PF0 */ - {&gpiof, NULL, NULL, 1, 0, ADCx, 0} , /* PF1 */ - {&gpiof, NULL, NULL, 2, 0, ADCx, 0} , /* PF2 */ - {&gpiof, NULL, NULL, 3, 0, ADCx, 0} , /* PF3 */ - {&gpiof, NULL, NULL, 4, 0, ADCx, 0} , /* PF4 */ - {&gpiof, NULL, NULL, 5, 0, ADCx, 0} , /* PF5 */ - {&gpiof, NULL, NULL, 6, 0, ADCx, 0} , /* PF6 */ - {&gpiof, NULL, NULL, 7, 0, ADCx, 0} , /* PF7 */ - {&gpiof, NULL, NULL, 8, 0, ADCx, 0} , /* PF8 */ - {&gpiof, NULL, NULL, 9, 0, ADCx, 0} , /* PF9 */ - {&gpiof, NULL, NULL, 10, 0, ADCx, 0} , /* PF10 */ - {&gpiof, NULL, NULL, 11, 0, ADCx, 0} , /* PF11 */ - {&gpiof, NULL, NULL, 12, 0, ADCx, 0} , /* PF12 */ - {&gpiof, NULL, NULL, 13, 0, ADCx, 0} , /* PF13 */ - {&gpiof, NULL, NULL, 14, 0, ADCx, 0} , /* PF14 */ - {&gpiof, NULL, NULL, 15, 0, ADCx, 0} , /* PF15 */ + {&gpiof, NULL, NULL, 0, 0, ADCx} , /* PF0 */ + {&gpiof, NULL, NULL, 1, 0, ADCx} , /* PF1 */ + {&gpiof, NULL, NULL, 2, 0, ADCx} , /* PF2 */ + {&gpiof, NULL, NULL, 3, 0, ADCx} , /* PF3 */ + {&gpiof, NULL, NULL, 4, 0, ADCx} , /* PF4 */ + {&gpiof, NULL, NULL, 5, 0, ADCx} , /* PF5 */ + {&gpiof, NULL, NULL, 6, 0, ADCx} , /* PF6 */ + {&gpiof, NULL, NULL, 7, 0, ADCx} , /* PF7 */ + {&gpiof, NULL, NULL, 8, 0, ADCx} , /* PF8 */ + {&gpiof, NULL, NULL, 9, 0, ADCx} , /* PF9 */ + {&gpiof, NULL, NULL, 10, 0, ADCx} , /* PF10 */ + {&gpiof, NULL, NULL, 11, 0, ADCx} , /* PF11 */ + {&gpiof, NULL, NULL, 12, 0, ADCx} , /* PF12 */ + {&gpiof, NULL, NULL, 13, 0, ADCx} , /* PF13 */ + {&gpiof, NULL, NULL, 14, 0, ADCx} , /* PF14 */ + {&gpiof, NULL, NULL, 15, 0, ADCx} , /* PF15 */ - {&gpiog, NULL, NULL, 0, 0, ADCx, 0} , /* PG0 */ - {&gpiog, NULL, NULL, 1, 0, ADCx, 0} , /* PG1 */ - {&gpiog, NULL, NULL, 2, 0, ADCx, 0} , /* PG2 */ - {&gpiog, NULL, NULL, 3, 0, ADCx, 0} , /* PG3 */ - {&gpiog, NULL, NULL, 4, 0, ADCx, 0} , /* PG4 */ - {&gpiog, NULL, NULL, 5, 0, ADCx, 0} , /* PG5 */ - {&gpiog, NULL, NULL, 6, 0, ADCx, 0} , /* PG6 */ - {&gpiog, NULL, NULL, 7, 0, ADCx, 0} , /* PG7 */ - {&gpiog, NULL, NULL, 8, 0, ADCx, 0} , /* PG8 */ - {&gpiog, NULL, NULL, 9, 0, ADCx, 0} , /* PG9 */ - {&gpiog, NULL, NULL, 10, 0, ADCx, 0} , /* PG10 */ - {&gpiog, NULL, NULL, 11, 0, ADCx, 0} , /* PG11 */ - {&gpiog, NULL, NULL, 12, 0, ADCx, 0} , /* PG12 */ - {&gpiog, NULL, NULL, 13, 0, ADCx, 0} , /* PG13 */ - {&gpiog, NULL, NULL, 14, 0, ADCx, 0} , /* PG14 */ - {&gpiog, NULL, NULL, 15, 0, ADCx, 0} /* PG15 */ + {&gpiog, NULL, NULL, 0, 0, ADCx} , /* PG0 */ + {&gpiog, NULL, NULL, 1, 0, ADCx} , /* PG1 */ + {&gpiog, NULL, NULL, 2, 0, ADCx} , /* PG2 */ + {&gpiog, NULL, NULL, 3, 0, ADCx} , /* PG3 */ + {&gpiog, NULL, NULL, 4, 0, ADCx} , /* PG4 */ + {&gpiog, NULL, NULL, 5, 0, ADCx} , /* PG5 */ + {&gpiog, NULL, NULL, 6, 0, ADCx} , /* PG6 */ + {&gpiog, NULL, NULL, 7, 0, ADCx} , /* PG7 */ + {&gpiog, NULL, NULL, 8, 0, ADCx} , /* PG8 */ + {&gpiog, NULL, NULL, 9, 0, ADCx} , /* PG9 */ + {&gpiog, NULL, NULL, 10, 0, ADCx} , /* PG10 */ + {&gpiog, NULL, NULL, 11, 0, ADCx} , /* PG11 */ + {&gpiog, NULL, NULL, 12, 0, ADCx} , /* PG12 */ + {&gpiog, NULL, NULL, 13, 0, ADCx} , /* PG13 */ + {&gpiog, NULL, NULL, 14, 0, ADCx} , /* PG14 */ + {&gpiog, NULL, NULL, 15, 0, ADCx} /* PG15 */ }; /* Basically everything that is defined as having a timer us PWM */ @@ -231,4 +231,4 @@ extern const uint8 boardUsedPins[BOARD_NR_USED_PINS] __FLASH__ = { DEFINE_HWSERIAL(Serial2, 3); DEFINE_HWSERIAL_UART(Serial3, 4); DEFINE_HWSERIAL_UART(Serial4, 5); -#endif +#endif \ No newline at end of file diff --git a/STM32F1/variants/hytiny_stm32f103t/board.cpp b/STM32F1/variants/hytiny_stm32f103t/board.cpp index b3fdd9b..f1fb44f 100644 --- a/STM32F1/variants/hytiny_stm32f103t/board.cpp +++ b/STM32F1/variants/hytiny_stm32f103t/board.cpp @@ -51,34 +51,35 @@ void boardInit(void) { } // Note. See the enum of pin names in board.h + extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { - {&gpioa, &timer2, &adc1, 0, 1, 0, 0}, /* PA0 */ - {&gpioa, &timer2, &adc1, 1, 2, 1, 0}, /* PA1 */ - {&gpioa, &timer2, &adc1, 2, 3, 2, 0}, /* PA2 */ - {&gpioa, &timer2, &adc1, 3, 4, 3, 0}, /* PA3 */ - {&gpioa, NULL, &adc1, 4, 0, 4, 0}, /* PA4 */ - {&gpioa, NULL, &adc1, 5, 0, 5, 0}, /* PA5 */ - {&gpioa, &timer3, &adc1, 6, 1, 6, 0}, /* PA6 */ - {&gpioa, &timer3, &adc1, 7, 2, 7, 0}, /* PA7 */ - {&gpioa, &timer1, NULL, 8, 1, ADCx, 0}, /* PA8 */ - {&gpioa, &timer1, NULL, 9, 2, ADCx, 0}, /* PA9 */ - {&gpioa, &timer1, NULL, 10, 3, ADCx, 0}, /* PA10 */ - {&gpioa, &timer1, NULL, 11, 4, ADCx, 0}, /* PA11 */ - {&gpioa, NULL, NULL, 12, 0, ADCx, 0}, /* PA12 */ - {&gpioa, NULL, NULL, 13, 0, ADCx, 0}, /* PA13 */ - {&gpioa, NULL, NULL, 14, 0, ADCx, 0}, /* PA14 */ - {&gpioa, NULL, NULL, 15, 0, ADCx, 0}, /* PA15 */ + {&gpioa, &timer2, &adc1, 0, 1, 0}, /* PA0 */ + {&gpioa, &timer2, &adc1, 1, 2, 1}, /* PA1 */ + {&gpioa, &timer2, &adc1, 2, 3, 2}, /* PA2 */ + {&gpioa, &timer2, &adc1, 3, 4, 3}, /* PA3 */ + {&gpioa, NULL, &adc1, 4, 0, 4}, /* PA4 */ + {&gpioa, NULL, &adc1, 5, 0, 5}, /* PA5 */ + {&gpioa, &timer3, &adc1, 6, 1, 6}, /* PA6 */ + {&gpioa, &timer3, &adc1, 7, 2, 7}, /* PA7 */ + {&gpioa, &timer1, NULL, 8, 1, ADCx}, /* PA8 */ + {&gpioa, &timer1, NULL, 9, 2, ADCx}, /* PA9 */ + {&gpioa, &timer1, NULL, 10, 3, ADCx}, /* PA10 */ + {&gpioa, &timer1, NULL, 11, 4, ADCx}, /* PA11 */ + {&gpioa, NULL, NULL, 12, 0, ADCx}, /* PA12 */ + {&gpioa, NULL, NULL, 13, 0, ADCx}, /* PA13 */ + {&gpioa, NULL, NULL, 14, 0, ADCx}, /* PA14 */ + {&gpioa, NULL, NULL, 15, 0, ADCx}, /* PA15 */ - {&gpiob, &timer3, &adc1, 0, 3, 8, 0}, /* PB0 */ - {&gpiob, &timer3, &adc1, 1, 4, 9, 0}, /* PB1 */ - {&gpiob, NULL, NULL, 2, 0, ADCx, 0}, /* PB2 */ - {&gpiob, NULL, NULL, 3, 0, ADCx, 0}, /* PB3 */ - {&gpiob, NULL, NULL, 4, 0, ADCx, 0}, /* PB4 */ - {&gpiob, NULL, NULL, 5, 0, ADCx, 0}, /* PB5 */ - {&gpiob, &timer4, NULL, 6, 1, ADCx, 0}, /* PB6 */ - {&gpiob, &timer4, NULL, 7, 2, ADCx, 0}, /* PB7 */ + {&gpiob, &timer3, &adc1, 0, 3, 8}, /* PB0 */ + {&gpiob, &timer3, &adc1, 1, 4, 9}, /* PB1 */ + {&gpiob, NULL, NULL, 2, 0, ADCx}, /* PB2 */ + {&gpiob, NULL, NULL, 3, 0, ADCx}, /* PB3 */ + {&gpiob, NULL, NULL, 4, 0, ADCx}, /* PB4 */ + {&gpiob, NULL, NULL, 5, 0, ADCx}, /* PB5 */ + {&gpiob, &timer4, NULL, 6, 1, ADCx}, /* PB6 */ + {&gpiob, &timer4, NULL, 7, 2, ADCx}, /* PB7 */ }; diff --git a/STM32F1/variants/maple_mini/board.cpp b/STM32F1/variants/maple_mini/board.cpp index 72faa17..f49b336 100644 --- a/STM32F1/variants/maple_mini/board.cpp +++ b/STM32F1/variants/maple_mini/board.cpp @@ -54,43 +54,43 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { /* Top header */ - {&gpiob, NULL, NULL, 11, 0, ADCx, 0}, /* D0/PB11 */ - {&gpiob, NULL, NULL, 10, 0, ADCx, 0}, /* D1/PB10 */ - {&gpiob, NULL, NULL, 2, 0, ADCx, 0}, /* D2/PB2 */ - {&gpiob, &timer3, &adc1, 0, 3, 8, 0}, /* D3/PB0 */ - {&gpioa, &timer3, &adc1, 7, 2, 7, 0}, /* D4/PA7 */ - {&gpioa, &timer3, &adc1, 6, 1, 6, 0}, /* D5/PA6 */ - {&gpioa, NULL, &adc1, 5, 0, 5, 0}, /* D6/PA5 */ - {&gpioa, NULL, &adc1, 4, 0, 4, 0}, /* D7/PA4 */ - {&gpioa, &timer2, &adc1, 3, 4, 3, 0}, /* D8/PA3 */ - {&gpioa, &timer2, &adc1, 2, 3, 2, 0}, /* D9/PA2 */ - {&gpioa, &timer2, &adc1, 1, 2, 1, 0}, /* D10/PA1 */ - {&gpioa, &timer2, &adc1, 0, 1, 0, 0}, /* D11/PA0 */ - {&gpioc, NULL, NULL, 15, 0, ADCx, 0}, /* D12/PC15 */ - {&gpioc, NULL, NULL, 14, 0, ADCx, 0}, /* D13/PC14 */ - {&gpioc, NULL, NULL, 13, 0, ADCx, 0}, /* D14/PC13 */ + {&gpiob, NULL, NULL, 11, 0, ADCx}, /* D0/PB11 */ + {&gpiob, NULL, NULL, 10, 0, ADCx}, /* D1/PB10 */ + {&gpiob, NULL, NULL, 2, 0, ADCx}, /* D2/PB2 */ + {&gpiob, &timer3, &adc1, 0, 3, 8}, /* D3/PB0 */ + {&gpioa, &timer3, &adc1, 7, 2, 7}, /* D4/PA7 */ + {&gpioa, &timer3, &adc1, 6, 1, 6}, /* D5/PA6 */ + {&gpioa, NULL, &adc1, 5, 0, 5}, /* D6/PA5 */ + {&gpioa, NULL, &adc1, 4, 0, 4}, /* D7/PA4 */ + {&gpioa, &timer2, &adc1, 3, 4, 3}, /* D8/PA3 */ + {&gpioa, &timer2, &adc1, 2, 3, 2}, /* D9/PA2 */ + {&gpioa, &timer2, &adc1, 1, 2, 1}, /* D10/PA1 */ + {&gpioa, &timer2, &adc1, 0, 1, 0}, /* D11/PA0 */ + {&gpioc, NULL, NULL, 15, 0, ADCx}, /* D12/PC15 */ + {&gpioc, NULL, NULL, 14, 0, ADCx}, /* D13/PC14 */ + {&gpioc, NULL, NULL, 13, 0, ADCx}, /* D14/PC13 */ /* Bottom header */ - {&gpiob, &timer4, NULL, 7, 2, ADCx, 0}, /* D15/PB7 */ - {&gpiob, &timer4, NULL, 6, 1, ADCx, 0}, /* D16/PB6 */ - {&gpiob, NULL, NULL, 5, 0, ADCx, 0}, /* D17/PB5 */ - {&gpiob, NULL, NULL, 4, 0, ADCx, 0}, /* D18/PB4 */ - {&gpiob, NULL, NULL, 3, 0, ADCx, 0}, /* D19/PB3 */ - {&gpioa, NULL, NULL, 15, 0, ADCx, 0}, /* D20/PA15 */ - {&gpioa, NULL, NULL, 14, 0, ADCx, 0}, /* D21/PA14 */ - {&gpioa, NULL, NULL, 13, 0, ADCx, 0}, /* D22/PA13 */ - {&gpioa, NULL, NULL, 12, 0, ADCx, 0}, /* D23/PA12 */ - {&gpioa, &timer1, NULL, 11, 4, ADCx, 0}, /* D24/PA11 */ - {&gpioa, &timer1, NULL, 10, 3, ADCx, 0}, /* D25/PA10 */ - {&gpioa, &timer1, NULL, 9, 2, ADCx, 0}, /* D26/PA9 */ - {&gpioa, &timer1, NULL, 8, 1, ADCx, 0}, /* D27/PA8 */ - {&gpiob, NULL, NULL, 15, 0, ADCx, 0}, /* D28/PB15 */ - {&gpiob, NULL, NULL, 14, 0, ADCx, 0}, /* D29/PB14 */ - {&gpiob, NULL, NULL, 13, 0, ADCx, 0}, /* D30/PB13 */ - {&gpiob, NULL, NULL, 12, 0, ADCx, 0}, /* D31/PB12 */ - {&gpiob, &timer4, NULL, 8, 3, ADCx, 0}, /* D32/PB8 */ - {&gpiob, &timer3, &adc1, 1, 4, 9, 0}, /* D33/PB1 */ + {&gpiob, &timer4, NULL, 7, 2, ADCx}, /* D15/PB7 */ + {&gpiob, &timer4, NULL, 6, 1, ADCx}, /* D16/PB6 */ + {&gpiob, NULL, NULL, 5, 0, ADCx}, /* D17/PB5 */ + {&gpiob, NULL, NULL, 4, 0, ADCx}, /* D18/PB4 */ + {&gpiob, NULL, NULL, 3, 0, ADCx}, /* D19/PB3 */ + {&gpioa, NULL, NULL, 15, 0, ADCx}, /* D20/PA15 */ + {&gpioa, NULL, NULL, 14, 0, ADCx}, /* D21/PA14 */ + {&gpioa, NULL, NULL, 13, 0, ADCx}, /* D22/PA13 */ + {&gpioa, NULL, NULL, 12, 0, ADCx}, /* D23/PA12 */ + {&gpioa, &timer1, NULL, 11, 4, ADCx}, /* D24/PA11 */ + {&gpioa, &timer1, NULL, 10, 3, ADCx}, /* D25/PA10 */ + {&gpioa, &timer1, NULL, 9, 2, ADCx}, /* D26/PA9 */ + {&gpioa, &timer1, NULL, 8, 1, ADCx}, /* D27/PA8 */ + {&gpiob, NULL, NULL, 15, 0, ADCx}, /* D28/PB15 */ + {&gpiob, NULL, NULL, 14, 0, ADCx}, /* D29/PB14 */ + {&gpiob, NULL, NULL, 13, 0, ADCx}, /* D30/PB13 */ + {&gpiob, NULL, NULL, 12, 0, ADCx}, /* D31/PB12 */ + {&gpiob, &timer4, NULL, 8, 3, ADCx}, /* D32/PB8 */ + {&gpiob, &timer3, &adc1, 1, 4, 9}, /* D33/PB1 */ }; extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { @@ -125,4 +125,4 @@ DEFINE_HWSERIAL(Serial1, 1); DEFINE_HWSERIAL(Serial2, 2); DEFINE_HWSERIAL(Serial3, 3); - + \ No newline at end of file diff --git a/STM32F1/variants/maple_ret6/board.cpp b/STM32F1/variants/maple_ret6/board.cpp index 82127ff..fb92779 100644 --- a/STM32F1/variants/maple_ret6/board.cpp +++ b/STM32F1/variants/maple_ret6/board.cpp @@ -82,66 +82,66 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { /* Top header */ - { &gpioa, &timer2, &adc1, 3, 4, 3, 0}, /* D0/PA3 */ - { &gpioa, &timer2, &adc1, 2, 3, 2, 0}, /* D1/PA2 */ - { &gpioa, &timer2, &adc1, 0, 1, 0, 0}, /* D2/PA0 */ - { &gpioa, &timer2, &adc1, 1, 2, 1, 0}, /* D3/PA1 */ - { &gpiob, NULL, NULL, 5, 0, ADCx, 0}, /* D4/PB5 */ - { &gpiob, &timer4, NULL, 6, 1, ADCx, 0}, /* D5/PB6 */ - { &gpioa, &timer1, NULL, 8, 1, ADCx, 0}, /* D6/PA8 */ - { &gpioa, &timer1, NULL, 9, 2, ADCx, 0}, /* D7/PA9 */ - { &gpioa, &timer1, NULL, 10, 3, ADCx, 0}, /* D8/PA10 */ - { &gpiob, &timer4, NULL, 7, 2, ADCx, 0}, /* D9/PB7 */ - { &gpioa, NULL, &adc1, 4, 0, 4, 0}, /* D10/PA4 */ - { &gpioa, &timer3, &adc1, 7, 2, 7, 0}, /* D11/PA7 */ - { &gpioa, &timer3, &adc1, 6, 1, 6, 0}, /* D12/PA6 */ - { &gpioa, NULL, &adc1, 5, 0, 5, 0}, /* D13/PA5 (LED) */ - { &gpiob, &timer4, NULL, 8, 3, ADCx, 0}, /* D14/PB8 */ + { &gpioa, &timer2, &adc1, 3, 4, 3 }, /* D0/PA3 */ + { &gpioa, &timer2, &adc1, 2, 3, 2 }, /* D1/PA2 */ + { &gpioa, &timer2, &adc1, 0, 1, 0 }, /* D2/PA0 */ + { &gpioa, &timer2, &adc1, 1, 2, 1 }, /* D3/PA1 */ + { &gpiob, NULL, NULL, 5, 0, ADCx }, /* D4/PB5 */ + { &gpiob, &timer4, NULL, 6, 1, ADCx }, /* D5/PB6 */ + { &gpioa, &timer1, NULL, 8, 1, ADCx }, /* D6/PA8 */ + { &gpioa, &timer1, NULL, 9, 2, ADCx }, /* D7/PA9 */ + { &gpioa, &timer1, NULL, 10, 3, ADCx }, /* D8/PA10 */ + { &gpiob, &timer4, NULL, 7, 2, ADCx }, /* D9/PB7 */ + { &gpioa, NULL, &adc1, 4, 0, 4 }, /* D10/PA4 */ + { &gpioa, &timer3, &adc1, 7, 2, 7 }, /* D11/PA7 */ + { &gpioa, &timer3, &adc1, 6, 1, 6 }, /* D12/PA6 */ + { &gpioa, NULL, &adc1, 5, 0, 5 }, /* D13/PA5 (LED) */ + { &gpiob, &timer4, NULL, 8, 3, ADCx }, /* D14/PB8 */ /* Little header */ - { &gpioc, NULL, &adc1, 0, 0, 10, 0}, /* D15/PC0 */ - { &gpioc, NULL, &adc1, 1, 0, 11, 0}, /* D16/PC1 */ - { &gpioc, NULL, &adc1, 2, 0, 12, 0}, /* D17/PC2 */ - { &gpioc, NULL, &adc1, 3, 0, 13, 0}, /* D18/PC3 */ - { &gpioc, NULL, &adc1, 4, 0, 14, 0}, /* D19/PC4 */ - { &gpioc, NULL, &adc1, 5, 0, 15, 0}, /* D20/PC5 */ + { &gpioc, NULL, &adc1, 0, 0, 10 }, /* D15/PC0 */ + { &gpioc, NULL, &adc1, 1, 0, 11 }, /* D16/PC1 */ + { &gpioc, NULL, &adc1, 2, 0, 12 }, /* D17/PC2 */ + { &gpioc, NULL, &adc1, 3, 0, 13 }, /* D18/PC3 */ + { &gpioc, NULL, &adc1, 4, 0, 14 }, /* D19/PC4 */ + { &gpioc, NULL, &adc1, 5, 0, 15 }, /* D20/PC5 */ /* External header */ - { &gpioc, NULL, NULL, 13, 0, ADCx, 0}, /* D21/PC13 */ - { &gpioc, NULL, NULL, 14, 0, ADCx, 0}, /* D22/PC14 */ - { &gpioc, NULL, NULL, 15, 0, ADCx, 0}, /* D23/PC15 */ - { &gpiob, &timer4, NULL, 9, 4, ADCx, 0}, /* D24/PB9 */ - { &gpiod, NULL, NULL, 2, 0, ADCx, 0}, /* D25/PD2 */ - { &gpioc, NULL, NULL, 10, 0, ADCx, 0}, /* D26/PC10 */ - { &gpiob, &timer3, &adc1, 0, 3, 8, 0}, /* D27/PB0 */ - { &gpiob, &timer3, &adc1, 1, 4, 9, 0}, /* D28/PB1 */ - { &gpiob, NULL, NULL, 10, 0, ADCx, 0}, /* D29/PB10 */ - { &gpiob, NULL, NULL, 11, 0, ADCx, 0}, /* D30/PB11 */ - { &gpiob, NULL, NULL, 12, 0, ADCx, 0}, /* D31/PB12 */ - { &gpiob, NULL, NULL, 13, 0, ADCx, 0}, /* D32/PB13 */ - { &gpiob, NULL, NULL, 14, 0, ADCx, 0}, /* D33/PB14 */ - { &gpiob, NULL, NULL, 15, 0, ADCx, 0}, /* D34/PB15 */ - { &gpioc, &timer8, NULL, 6, 1, ADCx, 0}, /* D35/PC6 */ - { &gpioc, &timer8, NULL, 7, 2, ADCx, 0}, /* D36/PC7 */ - { &gpioc, &timer8, NULL, 8, 3, ADCx, 0}, /* D37/PC8 */ - { &gpioc, &timer8, NULL, 9, 4, ADCx, 0}, /* D38/PC9 (BUT) */ + { &gpioc, NULL, NULL, 13, 0, ADCx }, /* D21/PC13 */ + { &gpioc, NULL, NULL, 14, 0, ADCx }, /* D22/PC14 */ + { &gpioc, NULL, NULL, 15, 0, ADCx }, /* D23/PC15 */ + { &gpiob, &timer4, NULL, 9, 4, ADCx }, /* D24/PB9 */ + { &gpiod, NULL, NULL, 2, 0, ADCx }, /* D25/PD2 */ + { &gpioc, NULL, NULL, 10, 0, ADCx }, /* D26/PC10 */ + { &gpiob, &timer3, &adc1, 0, 3, 8 }, /* D27/PB0 */ + { &gpiob, &timer3, &adc1, 1, 4, 9 }, /* D28/PB1 */ + { &gpiob, NULL, NULL, 10, 0, ADCx }, /* D29/PB10 */ + { &gpiob, NULL, NULL, 11, 0, ADCx }, /* D30/PB11 */ + { &gpiob, NULL, NULL, 12, 0, ADCx }, /* D31/PB12 */ + { &gpiob, NULL, NULL, 13, 0, ADCx }, /* D32/PB13 */ + { &gpiob, NULL, NULL, 14, 0, ADCx }, /* D33/PB14 */ + { &gpiob, NULL, NULL, 15, 0, ADCx }, /* D34/PB15 */ + { &gpioc, &timer8, NULL, 6, 1, ADCx }, /* D35/PC6 */ + { &gpioc, &timer8, NULL, 7, 2, ADCx }, /* D36/PC7 */ + { &gpioc, &timer8, NULL, 8, 3, ADCx }, /* D37/PC8 */ + { &gpioc, &timer8, NULL, 9, 4, ADCx }, /* D38/PC9 (BUT) */ /* JTAG header */ - { &gpioa, NULL, NULL, 13, 0, ADCx, 0}, /* D39/PA13 */ - { &gpioa, NULL, NULL, 14, 0, ADCx, 0}, /* D40/PA14 */ - { &gpioa, NULL, NULL, 15, 0, ADCx, 0}, /* D41/PA15 */ - { &gpiob, NULL, NULL, 3, 0, ADCx, 0}, /* D42/PB3 */ - { &gpiob, NULL, NULL, 4, 0, ADCx, 0}, /* D43/PB4 */ + { &gpioa, NULL, NULL, 13, 0, ADCx }, /* D39/PA13 */ + { &gpioa, NULL, NULL, 14, 0, ADCx }, /* D40/PA14 */ + { &gpioa, NULL, NULL, 15, 0, ADCx }, /* D41/PA15 */ + { &gpiob, NULL, NULL, 3, 0, ADCx }, /* D42/PB3 */ + { &gpiob, NULL, NULL, 4, 0, ADCx }, /* D43/PB4 */ - { &gpioc, NULL, NULL, 11, 0, ADCx, 0}, /* D44/PC11 UART4_RX/SDIO_D3 */ - { &gpioc, NULL, NULL, 12, 0, ADCx, 0}, /* D45/PC12 UART5_TX/SDIO_CK */ + { &gpioc, NULL, NULL, 11, 0, ADCx }, /* D44/PC11 UART4_RX/SDIO_D3 */ + { &gpioc, NULL, NULL, 12, 0, ADCx }, /* D45/PC12 UART5_TX/SDIO_CK */ - { &gpiod, NULL, NULL, 0, 0, ADCx, 0}, /* PD0 OSC_IN */ - { &gpiod, NULL, NULL, 1, 0, ADCx, 0}, /* PD1 OSC_OUT */ - { &gpiob, NULL, NULL, 2, 0, ADCx, 0}, /* PB2 */ + { &gpiod, NULL, NULL, 0, 0, ADCx }, /* PD0 OSC_IN */ + { &gpiod, NULL, NULL, 1, 0, ADCx }, /* PD1 OSC_OUT */ + { &gpiob, NULL, NULL, 2, 0, ADCx }, /* PB2 */ }; /* Basically everything that is defined as having a timer us PWM */ @@ -175,4 +175,4 @@ DEFINE_HWSERIAL(Serial1, 1); DEFINE_HWSERIAL(Serial2, 2); DEFINE_HWSERIAL(Serial3, 3); DEFINE_HWSERIAL_UART(Serial4, 4); -DEFINE_HWSERIAL_UART(Serial5, 5); +DEFINE_HWSERIAL_UART(Serial5, 5); \ No newline at end of file diff --git a/STM32F1/variants/microduino/board.cpp b/STM32F1/variants/microduino/board.cpp index 51c8024..2a00288 100644 --- a/STM32F1/variants/microduino/board.cpp +++ b/STM32F1/variants/microduino/board.cpp @@ -54,35 +54,35 @@ void boardInit(void) { extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { - {&gpioa, &timer1, NULL, 10, 3, ADCx, 0}, /* D0(RxD0)/PA10 */ - {&gpioa, &timer1, NULL, 9, 2, ADCx, 0}, /* D1(TxD1)/PA9 */ - {&gpiob, NULL, NULL, 11, 0, ADCx, 0}, /* D2/PB11 */ - {&gpiob, NULL, NULL, 10, 0, ADCx, 0}, /* D3/PB10 */ - {&gpioa, &timer1, NULL, 8, 1, ADCx, 0}, /* D4/PA8 */ - {&gpioa, NULL, NULL, 13, 0, ADCx, 0}, /* D5/PA13 */ - {&gpioa, NULL, NULL, 14, 0, ADCx, 0}, /* D6/PA14 */ - {&gpioa, NULL, NULL, 15, 0, ADCx, 0}, /* D7/PA15 */ - {&gpiob, NULL, NULL, 3, 0, ADCx, 0}, /* D8/PB3 */ - {&gpiob, NULL, NULL, 4, 0, ADCx, 0}, /* D9/PB4 */ - {&gpioa, NULL, &adc1, 4, 0, 4, 0}, /* D10/PA4 */ - {&gpioa, &timer3, &adc1, 7, 2, 7, 0}, /* D11/PA7 */ - {&gpioa, &timer3, &adc1, 6, 1, 6, 0}, /* D12/PA6 */ - {&gpioa, NULL, &adc1, 5, 0, 5, 0}, /* D13/PA5 */ + {&gpioa, &timer1, NULL, 10, 3, ADCx}, /* D0(RxD0)/PA10 */ + {&gpioa, &timer1, NULL, 9, 2, ADCx}, /* D1(TxD1)/PA9 */ + {&gpiob, NULL, NULL, 11, 0, ADCx}, /* D2/PB11 */ + {&gpiob, NULL, NULL, 10, 0, ADCx}, /* D3/PB10 */ + {&gpioa, &timer1, NULL, 8, 1, ADCx}, /* D4/PA8 */ + {&gpioa, NULL, NULL, 13, 0, ADCx}, /* D5/PA13 */ + {&gpioa, NULL, NULL, 14, 0, ADCx}, /* D6/PA14 */ + {&gpioa, NULL, NULL, 15, 0, ADCx}, /* D7/PA15 */ + {&gpiob, NULL, NULL, 3, 0, ADCx}, /* D8/PB3 */ + {&gpiob, NULL, NULL, 4, 0, ADCx}, /* D9/PB4 */ + {&gpioa, NULL, &adc1, 4, 0, 4}, /* D10/PA4 */ + {&gpioa, &timer3, &adc1, 7, 2, 7}, /* D11/PA7 */ + {&gpioa, &timer3, &adc1, 6, 1, 6}, /* D12/PA6 */ + {&gpioa, NULL, &adc1, 5, 0, 5}, /* D13/PA5 */ - {&gpioa, &timer2, &adc1, 0, 1, 0, 0}, /* D14(A0)/PA0 */ - {&gpioa, &timer2, &adc1, 1, 2, 1, 0}, /* D15(A1)/PA1 */ - {&gpioa, &timer2, &adc1, 2, 3, 2, 0}, /* D16(A2)/PA2 */ - {&gpioa, &timer2, &adc1, 3, 4, 3, 0}, /* D17(A3)/PA3 */ - {&gpiob, &timer4, NULL, 7, 2, ADCx, 0}, /* D18(A4)/PB7 */ - {&gpiob, &timer4, NULL, 6, 1, ADCx, 0}, /* D19(A5)/PB6 */ - {&gpiob, &timer3, &adc1, 0, 3, 8, 0}, /* D20(A6)/PB0 */ - {&gpiob, &timer3, &adc1, 1, 4, 9, 0}, /* D21(A7)/PB1 */ + {&gpioa, &timer2, &adc1, 0, 1, 0}, /* D14(A0)/PA0 */ + {&gpioa, &timer2, &adc1, 1, 2, 1}, /* D15(A1)/PA1 */ + {&gpioa, &timer2, &adc1, 2, 3, 2}, /* D16(A2)/PA2 */ + {&gpioa, &timer2, &adc1, 3, 4, 3}, /* D17(A3)/PA3 */ + {&gpiob, &timer4, NULL, 7, 2, ADCx}, /* D18(A4)/PB7 */ + {&gpiob, &timer4, NULL, 6, 1, ADCx}, /* D19(A5)/PB6 */ + {&gpiob, &timer3, &adc1, 0, 3, 8}, /* D20(A6)/PB0 */ + {&gpiob, &timer3, &adc1, 1, 4, 9}, /* D21(A7)/PB1 */ - {&gpioa, NULL, NULL, 12, 0, ADCx, 0}, /* D22/PA12/USB D+ */ - {&gpioa, &timer1, NULL, 11, 4, ADCx, 0}, /* D23/PA11/USB D- */ + {&gpioa, NULL, NULL, 12, 0, ADCx}, /* D22/PA12/USB D+ */ + {&gpioa, &timer1, NULL, 11, 4, ADCx}, /* D23/PA11/USB D- */ // FIXME: find out which pin is the button, if any - {&gpiob, NULL, NULL, 8, 0, ADCx, 0}, /* D24/PB8??/Button */ + {&gpiob, NULL, NULL, 8, 0, ADCx}, /* D24/PB8??/Button */ }; extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { diff --git a/STM32F1/variants/nucleo_f103rb/board.cpp b/STM32F1/variants/nucleo_f103rb/board.cpp index a70a188..9f3e08a 100644 --- a/STM32F1/variants/nucleo_f103rb/board.cpp +++ b/STM32F1/variants/nucleo_f103rb/board.cpp @@ -96,55 +96,55 @@ rcc_pll_cfg w_board_pll_cfg = {RCC_PLLSRC_HSI_DIV_2, &pll_data}; extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { /* Arduino-like header, right connectors */ - {&gpioa, NULL, &adc1, 3, 0, 3, 0}, /* D0/PA3 */ - {&gpioa, NULL, &adc1, 2, 0, 2, 0}, /* D1/PA2 */ - {&gpioa, &timer1, NULL, 10, 3, ADCx, 0}, /* D2/PA10 */ - {&gpiob, &timer2, NULL, 3, 2, ADCx, 0}, /* D3/PB3 */ - {&gpiob, &timer3, NULL, 5, 2, ADCx, 0}, /* D4/PB5 */ - {&gpiob, &timer3, NULL, 4, 1, ADCx, 0}, /* D5/PB4 */ - {&gpiob, &timer2, NULL, 10, 3, ADCx, 0}, /* D6/PB10 */ - {&gpioa, &timer1, NULL, 8, 1, ADCx, 0}, /* D7/PA8 */ + {&gpioa, NULL, &adc1, 3, 0, 3}, /* D0/PA3 */ + {&gpioa, NULL, &adc1, 2, 0, 2}, /* D1/PA2 */ + {&gpioa, &timer1, NULL, 10, 3, ADCx}, /* D2/PA10 */ + {&gpiob, &timer2, NULL, 3, 2, ADCx}, /* D3/PB3 */ + {&gpiob, &timer3, NULL, 5, 2, ADCx}, /* D4/PB5 */ + {&gpiob, &timer3, NULL, 4, 1, ADCx}, /* D5/PB4 */ + {&gpiob, &timer2, NULL, 10, 3, ADCx}, /* D6/PB10 */ + {&gpioa, &timer1, NULL, 8, 1, ADCx}, /* D7/PA8 */ - {&gpioa, &timer1, NULL, 9, 2, ADCx, 0}, /* D8/PA9 */ - {&gpioc, NULL, NULL, 7, 0, ADCx, 0}, /* D9/PC7 */ - {&gpiob, &timer4, NULL, 6, 1, ADCx, 0}, /* D10/PB6 */ - {&gpioa, NULL, &adc1, 7, 0, 7, 0}, /* D11/PA7 */ - {&gpioa, NULL, &adc1, 6, 0, 6, 0}, /* D12/PA6 */ - {&gpioa, NULL, NULL, 5, 0, ADCx, 0}, /* D13/PA5 LED - no &adc12_IN5 !*/ - {&gpiob, &timer4, NULL, 9, 4, ADCx, 0}, /* D14/PB9 */ - {&gpiob, &timer4, NULL, 8, 3, ADCx, 0}, /* D15/PB8 */ + {&gpioa, &timer1, NULL, 9, 2, ADCx}, /* D8/PA9 */ + {&gpioc, NULL, NULL, 7, 0, ADCx}, /* D9/PC7 */ + {&gpiob, &timer4, NULL, 6, 1, ADCx}, /* D10/PB6 */ + {&gpioa, NULL, &adc1, 7, 0, 7}, /* D11/PA7 */ + {&gpioa, NULL, &adc1, 6, 0, 6}, /* D12/PA6 */ + {&gpioa, NULL, NULL, 5, 0, ADCx}, /* D13/PA5 LED - no &adc12_IN5 !*/ + {&gpiob, &timer4, NULL, 9, 4, ADCx}, /* D14/PB9 */ + {&gpiob, &timer4, NULL, 8, 3, ADCx}, /* D15/PB8 */ - {&gpioa, NULL, &adc1, 0, 0, 0, 0}, /* D16/A0/PA0 */ - {&gpioa, NULL, &adc1, 1, 0, 1, 0}, /* D17/A1/PA1 */ - {&gpioa, NULL, &adc1, 4, 0, 4, 0}, /* D18/A2/PA4 */ - {&gpiob, &timer3, &adc1, 0, 3, 8, 0}, /* D19/A3/PB0 */ - {&gpioc, NULL, &adc1, 1, 0, 11, 0}, /* D20/A4/PC1 */ - {&gpioc, NULL, &adc1, 0, 0, 10, 0}, /* D21/A5/PC0 */ + {&gpioa, NULL, &adc1, 0, 0, 0}, /* D16/A0/PA0 */ + {&gpioa, NULL, &adc1, 1, 0, 1}, /* D17/A1/PA1 */ + {&gpioa, NULL, &adc1, 4, 0, 4}, /* D18/A2/PA4 */ + {&gpiob, &timer3, &adc1, 0, 3, 8}, /* D19/A3/PB0 */ + {&gpioc, NULL, &adc1, 1, 0, 11}, /* D20/A4/PC1 */ + {&gpioc, NULL, &adc1, 0, 0, 10}, /* D21/A5/PC0 */ - {&gpioc, NULL, NULL, 10, 0, ADCx, 0}, /* D22/PC10 */ - {&gpioc, NULL, NULL, 12, 0, ADCx, 0}, /* D23/PC12 */ - {&gpiob, &timer4, NULL, 7, 2, ADCx, 0}, /* D24/PB7 */ - {&gpioc, NULL, NULL, 13, 0, ADCx, 0}, /* D25/PC13 USER BLUE BUTTON */ - {&gpioc, NULL, NULL, 14, 0, ADCx, 0}, /* D26/PC14 */ - {&gpioc, NULL, NULL, 15, 0, ADCx, 0}, /* D27/PC15 */ - {&gpioc, NULL, &adc1, 2, 0, 12, 0}, /* D28/PC2 */ - {&gpioc, NULL, &adc1, 3, 0, 13, 0}, /* D29/PC3 */ - {&gpioc, NULL, NULL, 11, 0, ADCx, 0}, /* D30/PC11 */ - {&gpiod, NULL, NULL, 2, 0, ADCx, 0}, /* D31/PD2 */ - {&gpioc, NULL, NULL, 9, 0, ADCx, 0}, /* D32/PC9 */ - {&gpioc, NULL, NULL, 8, 0, ADCx, 0}, /* D33/PC8 */ - {&gpioc, NULL, NULL, 6, 0, ADCx, 0}, /* D34/PC6 */ - {&gpioc, NULL, &adc1, 5, 0, 15, 0}, /* D35/PC5 */ - {&gpioa, NULL, NULL, 12, 0, ADCx, 0}, /* D36/PA12 */ - {&gpioa, &timer1, NULL, 11, 4, ADCx, 0}, /* D37/PA11 */ - {&gpiob, NULL, NULL, 12, 0, ADCx, 0}, /* D38/PB12 */ - {&gpiob, &timer2, NULL, 11, 4, ADCx, 0}, /* D39/PB11 PWM-not working?*/ - {&gpiob, NULL, NULL, 2, 0, ADCx, 0}, /* D40/PB2 BOOT1 !!*/ - {&gpiob, &timer3, &adc1, 1, 4, 9, 0}, /* D41/PB1 */ - {&gpiob, NULL, NULL, 15, 0, ADCx, 0}, /* D42/PB15 */ - {&gpiob, NULL, NULL, 14, 0, ADCx, 0}, /* D43/PB14 */ - {&gpiob, NULL, NULL, 13, 0, ADCx, 0}, /* D44/PB13 */ - {&gpioc, NULL, &adc1, 4, 0, 14, 0}, /* D45/PC4 */ + {&gpioc, NULL, NULL, 10, 0, ADCx}, /* D22/PC10 */ + {&gpioc, NULL, NULL, 12, 0, ADCx}, /* D23/PC12 */ + {&gpiob, &timer4, NULL, 7, 2, ADCx}, /* D24/PB7 */ + {&gpioc, NULL, NULL, 13, 0, ADCx}, /* D25/PC13 USER BLUE BUTTON */ + {&gpioc, NULL, NULL, 14, 0, ADCx}, /* D26/PC14 */ + {&gpioc, NULL, NULL, 15, 0, ADCx}, /* D27/PC15 */ + {&gpioc, NULL, &adc1, 2, 0, 12}, /* D28/PC2 */ + {&gpioc, NULL, &adc1, 3, 0, 13}, /* D29/PC3 */ + {&gpioc, NULL, NULL, 11, 0, ADCx}, /* D30/PC11 */ + {&gpiod, NULL, NULL, 2, 0, ADCx}, /* D31/PD2 */ + {&gpioc, NULL, NULL, 9, 0, ADCx}, /* D32/PC9 */ + {&gpioc, NULL, NULL, 8, 0, ADCx}, /* D33/PC8 */ + {&gpioc, NULL, NULL, 6, 0, ADCx}, /* D34/PC6 */ + {&gpioc, NULL, &adc1, 5, 0, 15}, /* D35/PC5 */ + {&gpioa, NULL, NULL, 12, 0, ADCx}, /* D36/PA12 */ + {&gpioa, &timer1, NULL, 11, 4, ADCx}, /* D37/PA11 */ + {&gpiob, NULL, NULL, 12, 0, ADCx}, /* D38/PB12 */ + {&gpiob, &timer2, NULL, 11, 4, ADCx}, /* D39/PB11 PWM-not working?*/ + {&gpiob, NULL, NULL, 2, 0, ADCx}, /* D40/PB2 BOOT1 !!*/ + {&gpiob, &timer3, &adc1, 1, 4, 9}, /* D41/PB1 */ + {&gpiob, NULL, NULL, 15, 0, ADCx}, /* D42/PB15 */ + {&gpiob, NULL, NULL, 14, 0, ADCx}, /* D43/PB14 */ + {&gpiob, NULL, NULL, 13, 0, ADCx}, /* D44/PB13 */ + {&gpioc, NULL, &adc1, 4, 0, 14}, /* D45/PC4 */ // PMAP_ROW(&gpioa, 13, NULL, 0, NULL, ADCx), /* D41/PA13 do not use*/ // PMAP_ROW(&gpioa, 14, NULL, 0, NULL, ADCx), /* D42/PA14 do not use*/ // PMAP_ROW(&gpioa, 15, &timer2, 1, NULL, ADCx), /* D43/PA15 do not use*/ @@ -256,4 +256,4 @@ MOSI alternate functions on the GPIO ports. DEFINE_HWSERIAL(Serial, 3);// Use HW Serial 2 as "Serial" DEFINE_HWSERIAL(Serial1, 2); DEFINE_HWSERIAL(Serial2, 1); -#endif +#endif \ No newline at end of file diff --git a/STM32F3/cores/maple/wirish/boards_private.h b/STM32F3/cores/maple/wirish/boards_private.h index 332843d..49867ca 100644 --- a/STM32F3/cores/maple/wirish/boards_private.h +++ b/STM32F3/cores/maple/wirish/boards_private.h @@ -42,7 +42,7 @@ /* Makes the PIN_MAP rows more human-readable. */ #define PMAP_ROW(gpio_dev, gpio_bit, timer_dev, timer_ch, adc_dev, adc_ch) \ - { gpio_dev, timer_dev, adc_dev, gpio_bit, timer_ch, adc_ch, 0} + { gpio_dev, timer_dev, adc_dev, gpio_bit, timer_ch, adc_ch } namespace wirish { namespace priv { From 95dde2ec1017a2ee42561194d8d01a9d69b66957 Mon Sep 17 00:00:00 2001 From: lacklustrlabs Date: Fri, 1 Dec 2017 17:17:28 +0100 Subject: [PATCH 214/351] Removed pinMode from PIN_MAP --- STM32F1/cores/maple/wirish_types.h | 1 - STM32F1/variants/generic_stm32f103r/board.cpp | 1 - STM32F1/variants/generic_stm32f103z/board.cpp | 3 +-- STM32F1/variants/maple_ret6/board.cpp | 3 +-- 4 files changed, 2 insertions(+), 6 deletions(-) diff --git a/STM32F1/cores/maple/wirish_types.h b/STM32F1/cores/maple/wirish_types.h index 195cda8..14fb692 100644 --- a/STM32F1/cores/maple/wirish_types.h +++ b/STM32F1/cores/maple/wirish_types.h @@ -55,7 +55,6 @@ typedef struct stm32_pin_info { uint8 gpio_bit; /**< Pin's GPIO port bit. */ uint8 timer_channel; /**< Timer channel, or 0 if none. */ uint8 adc_channel; /**< Pin ADC channel, or ADCx if none. */ - uint8 pinMode; /**< mode specific by pinMode call (Roger Clark added to optimize compatibility with Arduino API*/ } stm32_pin_info; /** diff --git a/STM32F1/variants/generic_stm32f103r/board.cpp b/STM32F1/variants/generic_stm32f103r/board.cpp index 3e3589c..891e4e9 100644 --- a/STM32F1/variants/generic_stm32f103r/board.cpp +++ b/STM32F1/variants/generic_stm32f103r/board.cpp @@ -78,7 +78,6 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { uint8 gpio_bit; Pin's GPIO port bit. uint8 timer_channel; Timer channel, or 0 if none. uint8 adc_channel; Pin ADC channel, or ADCx if none. - uint8 pinMode; mode specific by pinMode call (Roger Clark added to optimize compatibility with Arduino API */ {&gpioa, &timer2, &adc1, 0, 1, 0}, /* PA0 */ diff --git a/STM32F1/variants/generic_stm32f103z/board.cpp b/STM32F1/variants/generic_stm32f103z/board.cpp index 830479e..500f9b8 100644 --- a/STM32F1/variants/generic_stm32f103z/board.cpp +++ b/STM32F1/variants/generic_stm32f103z/board.cpp @@ -77,7 +77,6 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { uint8 gpio_bit; Pin's GPIO port bit. uint8 timer_channel; Timer channel, or 0 if none. uint8 adc_channel; Pin ADC channel, or ADCx if none. - uint8 pinMode; mode specific by pinMode call (Roger Clark added to optimize compatibility with Arduino API */ {&gpioa, &timer2, &adc1, 0, 1, 0}, /* PA0 */ @@ -231,4 +230,4 @@ extern const uint8 boardUsedPins[BOARD_NR_USED_PINS] __FLASH__ = { DEFINE_HWSERIAL(Serial2, 3); DEFINE_HWSERIAL_UART(Serial3, 4); DEFINE_HWSERIAL_UART(Serial4, 5); -#endif \ No newline at end of file +#endif diff --git a/STM32F1/variants/maple_ret6/board.cpp b/STM32F1/variants/maple_ret6/board.cpp index fb92779..2b4e2e4 100644 --- a/STM32F1/variants/maple_ret6/board.cpp +++ b/STM32F1/variants/maple_ret6/board.cpp @@ -77,7 +77,6 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { uint8 gpio_bit; Pin's GPIO port bit. uint8 timer_channel; Timer channel, or 0 if none. uint8 adc_channel; Pin ADC channel, or ADCx if none. - uint8 pinMode; mode specific by pinMode call (Roger Clark added to optimize compatibility with Arduino API */ /* Top header */ @@ -175,4 +174,4 @@ DEFINE_HWSERIAL(Serial1, 1); DEFINE_HWSERIAL(Serial2, 2); DEFINE_HWSERIAL(Serial3, 3); DEFINE_HWSERIAL_UART(Serial4, 4); -DEFINE_HWSERIAL_UART(Serial5, 5); \ No newline at end of file +DEFINE_HWSERIAL_UART(Serial5, 5); From 595b128cac7b087c3ee96ea662e690f9f38a1520 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Sun, 3 Dec 2017 14:39:35 +1100 Subject: [PATCH 215/351] Modification to allow SSD1306 example to compile, following changes to Wire to use HWire by default. Note this code is only known to compile , it may not work with the SSD1306 display --- .../Adafruit_SSD1306_STM32.cpp | 20 +++++++++---------- .../Adafruit_SSD1306/Adafruit_SSD1306_STM32.h | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/STM32F1/libraries/Adafruit_SSD1306/Adafruit_SSD1306_STM32.cpp b/STM32F1/libraries/Adafruit_SSD1306/Adafruit_SSD1306_STM32.cpp index 3492039..d70aa13 100644 --- a/STM32F1/libraries/Adafruit_SSD1306/Adafruit_SSD1306_STM32.cpp +++ b/STM32F1/libraries/Adafruit_SSD1306/Adafruit_SSD1306_STM32.cpp @@ -22,10 +22,10 @@ All text above, and the splash screen below must be included in any redistributi //#endif #include -//#include -#include +//#include +#include //HardWire HWIRE(1,I2C_FAST_MODE); // I2c1 -HardWire HWIRE(2,I2C_FAST_MODE); // I2c2 +//HardWire HWIRE(2,I2C_FAST_MODE); // I2c2 #include "Adafruit_GFX.h" #include "Adafruit_SSD1306_STM32.h" @@ -197,7 +197,7 @@ void Adafruit_SSD1306::begin(uint8_t vccstate, uint8_t i2caddr, bool reset) { else { // I2C Init - HWIRE.begin(); + Wire.begin(); #ifdef __SAM3X8E__ // Force 400 KHz I2C, rawr! (Uses pins 20, 21 for SDA, SCL) @@ -359,10 +359,10 @@ void Adafruit_SSD1306::ssd1306_command(uint8_t c) { { // I2C uint8_t control = 0x00; // Co = 0, D/C = 0 - HWIRE.beginTransmission(_i2caddr); + Wire.beginTransmission(_i2caddr); WIRE_WRITE(control); WIRE_WRITE(c); - HWIRE.endTransmission(); + Wire.endTransmission(); } } @@ -473,10 +473,10 @@ void Adafruit_SSD1306::ssd1306_data(uint8_t c) { { // I2C uint8_t control = 0x40; // Co = 0, D/C = 1 - HWIRE.beginTransmission(_i2caddr); + Wire.beginTransmission(_i2caddr); WIRE_WRITE(control); WIRE_WRITE(c); - HWIRE.endTransmission(); + Wire.endTransmission(); } } @@ -525,14 +525,14 @@ void Adafruit_SSD1306::display(void) { // I2C for (uint16_t i=0; i<(SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8); i++) { // send a bunch of data in one xmission - HWIRE.beginTransmission(_i2caddr); + Wire.beginTransmission(_i2caddr); WIRE_WRITE(0x40); for (uint8_t x=0; x<16; x++) { WIRE_WRITE(buffer[i]); i++; } i--; - HWIRE.endTransmission(); + Wire.endTransmission(); } /* #ifndef __SAM3X8E__ diff --git a/STM32F1/libraries/Adafruit_SSD1306/Adafruit_SSD1306_STM32.h b/STM32F1/libraries/Adafruit_SSD1306/Adafruit_SSD1306_STM32.h index 0686d76..f91ff1b 100644 --- a/STM32F1/libraries/Adafruit_SSD1306/Adafruit_SSD1306_STM32.h +++ b/STM32F1/libraries/Adafruit_SSD1306/Adafruit_SSD1306_STM32.h @@ -18,10 +18,10 @@ All text above, and the splash screen must be included in any redistribution #if ARDUINO >= 100 #include "Arduino.h" - #define WIRE_WRITE HWIRE.write + #define WIRE_WRITE Wire.write #else #include "WProgram.h" - #define WIRE_WRITE HWIRE.send + #define WIRE_WRITE Wire.send #endif /* #ifdef __SAM3X8E__ From dbfb68cf916f044c83b2bd42aa9aaaf78641a705 Mon Sep 17 00:00:00 2001 From: aster94 Date: Wed, 6 Dec 2017 21:52:00 +0100 Subject: [PATCH 216/351] Add files via upload --- STM32F1/libraries/Wire/SoftWire.cpp | 40 ++++++++++++++--------------- STM32F1/libraries/Wire/SoftWire.h | 12 ++++----- STM32F1/libraries/Wire/Wire.cpp | 18 ++++++------- STM32F1/libraries/Wire/Wire.h | 16 ++++++------ 4 files changed, 43 insertions(+), 43 deletions(-) diff --git a/STM32F1/libraries/Wire/SoftWire.cpp b/STM32F1/libraries/Wire/SoftWire.cpp index 781bb97..4e3cdd5 100644 --- a/STM32F1/libraries/Wire/SoftWire.cpp +++ b/STM32F1/libraries/Wire/SoftWire.cpp @@ -25,7 +25,7 @@ *****************************************************************************/ /** - * @file Wire.cpp + * @file SoftWire.cpp * @author Trystan Jones * @brief Wire library, uses the WireBase to create the primary interface * while keeping low level interactions invisible to the user. @@ -54,7 +54,7 @@ * - always start with i2c_delay rather than end */ -void TwoWire::set_scl(bool state) { +void SoftWire::set_scl(bool state) { I2C_DELAY(this->i2c_delay); gpio_write_bit(sclDevice,sclBit, state); @@ -65,30 +65,30 @@ void TwoWire::set_scl(bool state) { } } -void TwoWire::set_sda(bool state) { +void SoftWire::set_sda(bool state) { I2C_DELAY(this->i2c_delay); gpio_write_bit(sdaDevice,sdaBit, state); //digitalWrite(this->sda_pin, state); } -void TwoWire::i2c_start() { +void SoftWire::i2c_start() { set_sda(LOW); set_scl(LOW); } -void TwoWire::i2c_stop() { +void SoftWire::i2c_stop() { set_sda(LOW); set_scl(HIGH); set_sda(HIGH); } -void TwoWire::i2c_repeated_start() { +void SoftWire::i2c_repeated_start() { set_sda(HIGH); set_scl(HIGH); set_sda(LOW); } -bool TwoWire::i2c_get_ack() { +bool SoftWire::i2c_get_ack() { set_scl(LOW); set_sda(HIGH); set_scl(HIGH); @@ -98,19 +98,19 @@ bool TwoWire::i2c_get_ack() { return ret; } -void TwoWire::i2c_send_ack() { +void SoftWire::i2c_send_ack() { set_sda(LOW); set_scl(HIGH); set_scl(LOW); } -void TwoWire::i2c_send_nack() { +void SoftWire::i2c_send_nack() { set_sda(HIGH); set_scl(HIGH); set_scl(LOW); } -uint8 TwoWire::i2c_shift_in() { +uint8 SoftWire::i2c_shift_in() { uint8 data = 0; set_sda(HIGH); @@ -124,7 +124,7 @@ uint8 TwoWire::i2c_shift_in() { return data; } -void TwoWire::i2c_shift_out(uint8 val) { +void SoftWire::i2c_shift_out(uint8 val) { int i; for (i = 0; i < 8; i++) { set_sda(!!(val & (1 << (7 - i)) ) ); @@ -134,7 +134,7 @@ void TwoWire::i2c_shift_out(uint8 val) { } //process needs to be updated for repeated start. -uint8 TwoWire::process(uint8 stop) { +uint8 SoftWire::process(uint8 stop) { itc_msg.xferred = 0; uint8 sla_addr = (itc_msg.addr << 1); @@ -183,18 +183,18 @@ uint8 TwoWire::process(uint8 stop) { } // For compatibility with legacy code -uint8 TwoWire::process(){ +uint8 SoftWire::process(){ return process(true); } // TODO: Add in Error Handling if pins is out of range for other Maples // TODO: Make delays more capable -TwoWire::TwoWire(uint8 scl, uint8 sda, uint8 delay) : i2c_delay(delay) { +SoftWire::SoftWire(uint8 scl, uint8 sda, uint8 delay) : i2c_delay(delay) { this->scl_pin=scl; this->sda_pin=sda; } -void TwoWire::begin(uint8 self_addr) { +void SoftWire::begin(uint8 self_addr) { tx_buf_idx = 0; tx_buf_overflow = false; rx_buf_idx = 0; @@ -210,7 +210,7 @@ void TwoWire::begin(uint8 self_addr) { set_sda(HIGH); } -void TwoWire::end() +void SoftWire::end() { if (this->scl_pin) { @@ -222,7 +222,7 @@ void TwoWire::end() } } -void TwoWire::setClock(uint32_t frequencyHz) +void SoftWire::setClock(uint32_t frequencyHz) { switch(frequencyHz) { @@ -236,11 +236,11 @@ void TwoWire::setClock(uint32_t frequencyHz) } } -TwoWire::~TwoWire() { +SoftWire::~SoftWire() { this->scl_pin=0; this->sda_pin=0; } // Declare the instance that the users of the library can use -//TwoWire Wire(SCL, SDA, SOFT_STANDARD); -//TwoWire Wire(PB6, PB7, SOFT_FAST); +//SoftWire Wire(SCL, SDA, SOFT_STANDARD); +//SoftWire Wire(PB6, PB7, SOFT_FAST); diff --git a/STM32F1/libraries/Wire/SoftWire.h b/STM32F1/libraries/Wire/SoftWire.h index 136dc3d..b5c43db 100644 --- a/STM32F1/libraries/Wire/SoftWire.h +++ b/STM32F1/libraries/Wire/SoftWire.h @@ -25,7 +25,7 @@ *****************************************************************************/ /** - * @file Wire.h + * @file SoftWire.h * @author Trystan Jones * @brief Wire library, uses the WireBase to create the primary interface * while keeping low level interactions invisible to the user. @@ -60,7 +60,7 @@ -class TwoWire : public WireBase { +class SoftWire : public WireBase { public: uint8 i2c_delay; uint8 scl_pin; @@ -136,7 +136,7 @@ class TwoWire : public WireBase { * Accept pin numbers for SCL and SDA lines. Set the delay needed * to create the timing for I2C's Standard Mode and Fast Mode. */ - TwoWire(uint8 scl=SCL, uint8 sda=SDA, uint8 delay=SOFT_STANDARD); + SoftWire(uint8 scl=SCL, uint8 sda=SDA, uint8 delay=SOFT_STANDARD); /* * Sets pins SDA and SCL to OUPTUT_OPEN_DRAIN, joining I2C bus as @@ -155,9 +155,9 @@ class TwoWire : public WireBase { /* * If object is destroyed, set pin numbers to 0. */ - ~TwoWire(); + ~SoftWire(); }; -//extern TwoWire Wire; +//extern SoftWire Wire; -#endif // _WIRE_H_ +#endif // _SOFTWIRE_H_ diff --git a/STM32F1/libraries/Wire/Wire.cpp b/STM32F1/libraries/Wire/Wire.cpp index a026e2e..dbf4c66 100644 --- a/STM32F1/libraries/Wire/Wire.cpp +++ b/STM32F1/libraries/Wire/Wire.cpp @@ -25,7 +25,7 @@ *****************************************************************************/ /** - * @file HardWire.cpp + * @file TwoWire.cpp * @author Trystan Jones * @brief Wire library, uses the hardware I2C available in the Maple to * interact with I2C slave devices. @@ -38,7 +38,7 @@ #include "Wire.h" -uint8 HardWire::process(uint8 stop) { +uint8 TwoWire::process(uint8 stop) { int8 res = i2c_master_xfer(sel_hard, &itc_msg, 1, 0); if (res == I2C_ERROR_PROTOCOL) { if (sel_hard->error_flags & I2C_SR1_AF) { /* NACK */ @@ -55,12 +55,12 @@ uint8 HardWire::process(uint8 stop) { return res; } -uint8 HardWire::process(){ +uint8 TwoWire::process(){ return process(true); } // TODO: Add in Error Handling if devsel is out of range for other Maples -HardWire::HardWire(uint8 dev_sel, uint8 flags) { +TwoWire::TwoWire(uint8 dev_sel, uint8 flags) { if (dev_sel == 1) { sel_hard = I2C1; } else if (dev_sel == 2) { @@ -71,21 +71,21 @@ HardWire::HardWire(uint8 dev_sel, uint8 flags) { dev_flags = flags; } -HardWire::~HardWire() { +TwoWire::~TwoWire() { i2c_disable(sel_hard); sel_hard = 0; } -void HardWire::begin(uint8 self_addr) { +void TwoWire::begin(uint8 self_addr) { i2c_master_enable(sel_hard, dev_flags); } -void HardWire::end() { +void TwoWire::end() { i2c_disable(sel_hard); sel_hard = 0; } -void HardWire::setClock(uint32_t frequencyHz) +void TwoWire::setClock(uint32_t frequencyHz) { switch(frequencyHz) { @@ -103,4 +103,4 @@ void HardWire::setClock(uint32_t frequencyHz) } } -HardWire Wire(1); +TwoWire Wire(1); diff --git a/STM32F1/libraries/Wire/Wire.h b/STM32F1/libraries/Wire/Wire.h index 88d4a1b..f235aec 100644 --- a/STM32F1/libraries/Wire/Wire.h +++ b/STM32F1/libraries/Wire/Wire.h @@ -25,7 +25,7 @@ *****************************************************************************/ /** - * @file HardWire.h + * @file TwoWire.h * @author Trystan Jones * @brief Wire library, uses the hardware I2C available in the Maple to * interact with I2C slave devices. @@ -36,14 +36,14 @@ * users easy interaction with the I2C Hardware in a familiar method. */ -#ifndef _HARDWIRE_H_ -#define _HARDWIRE_H_ +#ifndef _TWOWIRE_H_ +#define _TWOWIRE_H_ #include "WireBase.h" #include "wirish.h" #include -class HardWire : public WireBase { +class TwoWire : public WireBase { private: i2c_dev* sel_hard; uint8 dev_flags; @@ -59,7 +59,7 @@ public: * Check if devsel is within range and enable selected I2C interface with * passed flags */ - HardWire(uint8, uint8 = 0); + TwoWire(uint8, uint8 = 0); /* * Shuts down (disables) the hardware I2C @@ -70,9 +70,9 @@ public: /* * Disables the I2C device and remove the device address. */ - ~HardWire(); + ~TwoWire(); void begin(uint8 = 0x00); }; -extern HardWire Wire; -#endif // _HARDWIRE_H_ +extern TwoWire Wire; +#endif // _TWOWIRE_H_ From 98ed731df9fdf2516a1cb11c428807379d4763a7 Mon Sep 17 00:00:00 2001 From: aster94 Date: Thu, 7 Dec 2017 20:09:30 +0100 Subject: [PATCH 217/351] Add files via upload --- .../examples/i2c_scanner_softwire/i2c_scanner_softwire.ino | 2 +- STM32F1/libraries/Wire/rules.mk | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/STM32F1/libraries/Wire/examples/i2c_scanner_softwire/i2c_scanner_softwire.ino b/STM32F1/libraries/Wire/examples/i2c_scanner_softwire/i2c_scanner_softwire.ino index 0b4580a..f6bf685 100644 --- a/STM32F1/libraries/Wire/examples/i2c_scanner_softwire/i2c_scanner_softwire.ino +++ b/STM32F1/libraries/Wire/examples/i2c_scanner_softwire/i2c_scanner_softwire.ino @@ -5,7 +5,7 @@ #include -TwoWire SWire(PB6, PB7, SOFT_FAST); +SoftWire SWire(PB6, PB7, SOFT_FAST); void setup() { diff --git a/STM32F1/libraries/Wire/rules.mk b/STM32F1/libraries/Wire/rules.mk index e16f4db..2b33332 100644 --- a/STM32F1/libraries/Wire/rules.mk +++ b/STM32F1/libraries/Wire/rules.mk @@ -1,3 +1,7 @@ +#this makefile may not work since HardWire has been changed to the default Wire (TwoWire) +#anyway this file should be useless + + # Standard things sp := $(sp).x dirstack_$(sp) := $(d) From 2604eb6be242f76416bc89b7129f95f4b4a8598e Mon Sep 17 00:00:00 2001 From: aster94 Date: Thu, 7 Dec 2017 20:10:35 +0100 Subject: [PATCH 218/351] Add files via upload --- STM32F1/libraries/OLED_I2C/OLED_I2C.h | 2 +- STM32F1/libraries/OLED_I2C/hardware/arm/HW_STM32.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/STM32F1/libraries/OLED_I2C/OLED_I2C.h b/STM32F1/libraries/OLED_I2C/OLED_I2C.h index 4bde83f..abad639 100644 --- a/STM32F1/libraries/OLED_I2C/OLED_I2C.h +++ b/STM32F1/libraries/OLED_I2C/OLED_I2C.h @@ -87,7 +87,7 @@ */ #elif defined (__STM32F1__) #include "Arduino.h" -//#include +//#include #include "hardware/arm/HW_STM32_defines.h" #endif diff --git a/STM32F1/libraries/OLED_I2C/hardware/arm/HW_STM32.h b/STM32F1/libraries/OLED_I2C/hardware/arm/HW_STM32.h index 25967c7..a892c43 100644 --- a/STM32F1/libraries/OLED_I2C/hardware/arm/HW_STM32.h +++ b/STM32F1/libraries/OLED_I2C/hardware/arm/HW_STM32.h @@ -1,7 +1,7 @@ #include "Wire.h" #define WIRE_WRITE HWIRE.write - HardWire HWIRE(2,I2C_FAST_MODE); // stupid compiler + TwoWire WIRE(2,I2C_FAST_MODE); // stupid compiler void OLED::_convert_float(char *buf, double num, int width, byte prec) { From acc6cbc371963e9a500b5069223093ac07b5c187 Mon Sep 17 00:00:00 2001 From: aster94 Date: Thu, 7 Dec 2017 20:11:17 +0100 Subject: [PATCH 219/351] Add files via upload --- .../libraries/Adafruit_SSD1306/Adafruit_SSD1306_STM32.cpp | 6 +++--- STM32F1/libraries/Adafruit_SSD1306/STM32 README.txt | 6 +++--- .../ssd1306_128x64_i2c_STM32/ssd1306_128x64_i2c_STM32.ino | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/STM32F1/libraries/Adafruit_SSD1306/Adafruit_SSD1306_STM32.cpp b/STM32F1/libraries/Adafruit_SSD1306/Adafruit_SSD1306_STM32.cpp index d70aa13..34215da 100644 --- a/STM32F1/libraries/Adafruit_SSD1306/Adafruit_SSD1306_STM32.cpp +++ b/STM32F1/libraries/Adafruit_SSD1306/Adafruit_SSD1306_STM32.cpp @@ -22,10 +22,10 @@ All text above, and the splash screen below must be included in any redistributi //#endif #include -//#include + #include -//HardWire HWIRE(1,I2C_FAST_MODE); // I2c1 -//HardWire HWIRE(2,I2C_FAST_MODE); // I2c2 +//TwoWire WIRE(1,I2C_FAST_MODE); // I2c1 +//TwoWire WIRE(2,I2C_FAST_MODE); // I2c2 #include "Adafruit_GFX.h" #include "Adafruit_SSD1306_STM32.h" diff --git a/STM32F1/libraries/Adafruit_SSD1306/STM32 README.txt b/STM32F1/libraries/Adafruit_SSD1306/STM32 README.txt index 54705cf..518aabe 100644 --- a/STM32F1/libraries/Adafruit_SSD1306/STM32 README.txt +++ b/STM32F1/libraries/Adafruit_SSD1306/STM32 README.txt @@ -1,6 +1,6 @@ STM32 adaption by Matthias Diro, 25.03.2015 Things to know: -This adaption uses hardware I2C (hardwire.h), Port: I2c2. SDA=0, SCL=1 on maple mini +This adaption uses hardware I2C (now Wire.h), Port: I2c2. SDA=0, SCL=1 on maple mini To change it to Port I2C1: -//HardWire HWIRE(1,I2C_FAST_MODE); // I2c1 -HardWire HWIRE(2,I2C_FAST_MODE); // I2c2 \ No newline at end of file +//TwoWire WIRE(1,I2C_FAST_MODE); // I2c1 +TwoWire WIRE(2,I2C_FAST_MODE); // I2c2 \ No newline at end of file diff --git a/STM32F1/libraries/Adafruit_SSD1306/examples/ssd1306_128x64_i2c_STM32/ssd1306_128x64_i2c_STM32.ino b/STM32F1/libraries/Adafruit_SSD1306/examples/ssd1306_128x64_i2c_STM32/ssd1306_128x64_i2c_STM32.ino index b11bdc0..5b68b3f 100644 --- a/STM32F1/libraries/Adafruit_SSD1306/examples/ssd1306_128x64_i2c_STM32/ssd1306_128x64_i2c_STM32.ino +++ b/STM32F1/libraries/Adafruit_SSD1306/examples/ssd1306_128x64_i2c_STM32/ssd1306_128x64_i2c_STM32.ino @@ -1,7 +1,7 @@ /* STM32 adaption by Matthias Diro, tested with maple mini and heltec OLED 12864 I2c; adress: 0x3C (SPI should work, but I didn't own one) Things to know: - This adaption uses hardware I2C (hardwire.h), Port: I2c2. SDA=0, SCL=1 on maple mini + This adaption uses hardware I2C (now Wire.h), Port: I2c2. SDA=0, SCL=1 on maple mini further details: STM32_README.txt */ /********************************************************************* From 4ffdce29fe7bfc24b67acf1e4dbacbcd89b203a8 Mon Sep 17 00:00:00 2001 From: aster94 Date: Fri, 8 Dec 2017 10:32:59 +0100 Subject: [PATCH 220/351] Add files via upload --- STM32F1/libraries/Wire/SoftWire.h | 2 +- STM32F1/libraries/Wire/Wire.h | 4 +- STM32F1/libraries/Wire/keywords.txt | 17 +++ STM32F1/libraries/Wire/utility/WireBase.cpp | 145 ++++++++++++++++++++ STM32F1/libraries/Wire/utility/WireBase.h | 145 ++++++++++++++++++++ 5 files changed, 310 insertions(+), 3 deletions(-) create mode 100644 STM32F1/libraries/Wire/keywords.txt create mode 100644 STM32F1/libraries/Wire/utility/WireBase.cpp create mode 100644 STM32F1/libraries/Wire/utility/WireBase.h diff --git a/STM32F1/libraries/Wire/SoftWire.h b/STM32F1/libraries/Wire/SoftWire.h index b5c43db..c42bca4 100644 --- a/STM32F1/libraries/Wire/SoftWire.h +++ b/STM32F1/libraries/Wire/SoftWire.h @@ -40,7 +40,7 @@ #ifndef _SOFTWIRE_H_ #define _SOFTWIRE_H_ -#include "WireBase.h" +#include "utility/WireBase.h" #include "wirish.h" /* diff --git a/STM32F1/libraries/Wire/Wire.h b/STM32F1/libraries/Wire/Wire.h index f235aec..ab05d42 100644 --- a/STM32F1/libraries/Wire/Wire.h +++ b/STM32F1/libraries/Wire/Wire.h @@ -25,7 +25,7 @@ *****************************************************************************/ /** - * @file TwoWire.h + * @file Wire.h * @author Trystan Jones * @brief Wire library, uses the hardware I2C available in the Maple to * interact with I2C slave devices. @@ -39,7 +39,7 @@ #ifndef _TWOWIRE_H_ #define _TWOWIRE_H_ -#include "WireBase.h" +#include "utility/WireBase.h" #include "wirish.h" #include diff --git a/STM32F1/libraries/Wire/keywords.txt b/STM32F1/libraries/Wire/keywords.txt new file mode 100644 index 0000000..3fddb6f --- /dev/null +++ b/STM32F1/libraries/Wire/keywords.txt @@ -0,0 +1,17 @@ +####################################### +# Datatypes (KEYWORD1) +####################################### +TwoWire KEYWORD1 +SoftWire KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + + + +####################################### +# Constants (LITERAL1) +####################################### +SOFT_STANDARD LITERAL1 +SOFT_FAST LITERAL1 \ No newline at end of file diff --git a/STM32F1/libraries/Wire/utility/WireBase.cpp b/STM32F1/libraries/Wire/utility/WireBase.cpp new file mode 100644 index 0000000..220d845 --- /dev/null +++ b/STM32F1/libraries/Wire/utility/WireBase.cpp @@ -0,0 +1,145 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file WireBase.cpp + * @author Trystan Jones + * @brief Wire library, following the majority of the interface from Arduino. + * Provides a 'standard' interface to I2C (two-wire) communication for + * derived classes. + */ + +/* + * Library created by crenn to allow a system which would provide users the + * 'standardised' Arduino method for interfacing with I2C devices regardless of + * whether it is I2C hardware or emulating software. + */ + +#include "WireBase.h" +#include "wirish.h" + +void WireBase::begin(uint8 self_addr) { + tx_buf_idx = 0; + tx_buf_overflow = false; + rx_buf_idx = 0; + rx_buf_len = 0; +} + +void WireBase::beginTransmission(uint8 slave_address) { + itc_msg.addr = slave_address; + itc_msg.data = &tx_buf[tx_buf_idx]; + itc_msg.length = 0; + itc_msg.flags = 0; +} + +void WireBase::beginTransmission(int slave_address) { + beginTransmission((uint8)slave_address); +} + +uint8 WireBase::endTransmission(bool stop) { + uint8 retVal; + if (tx_buf_overflow) { + return EDATA; + } + retVal = process(stop);// Changed so that the return value from process is returned by this function see also the return line below + tx_buf_idx = 0; + tx_buf_overflow = false; + return retVal;//SUCCESS; +} + +uint8 WireBase::endTransmission(){ + endTransmission(true); +} + +//TODO: Add the ability to queue messages (adding a boolean to end of function +// call, allows for the Arduino style to stay while also giving the flexibility +// to bulk send +uint8 WireBase::requestFrom(uint8 address, int num_bytes) { + if (num_bytes > BUFFER_LENGTH) { + num_bytes = BUFFER_LENGTH; + } + itc_msg.addr = address; + itc_msg.flags = I2C_MSG_READ; + itc_msg.length = num_bytes; + itc_msg.data = &rx_buf[rx_buf_idx]; + process(); + rx_buf_len += itc_msg.xferred; + itc_msg.flags = 0; + return rx_buf_len; +} + +uint8 WireBase::requestFrom(int address, int numBytes) { + return WireBase::requestFrom((uint8)address, numBytes); +} + +void WireBase::write(uint8 value) { + if (tx_buf_idx == BUFFER_LENGTH) { + tx_buf_overflow = true; + return; + } + tx_buf[tx_buf_idx++] = value; + itc_msg.length++; +} + +void WireBase::write(uint8* buf, int len) { + for (uint8 i = 0; i < len; i++) { + write(buf[i]); + } +} + +void WireBase::write(int value) { + write((uint8)value); +} + +void WireBase::write(int* buf, int len) { + write((uint8*)buf, (uint8)len); +} + +void WireBase::write(char* buf) { + uint8 *ptr = (uint8*)buf; + while (*ptr) { + write(*ptr); + ptr++; + } +} + +uint8 WireBase::available() { + return rx_buf_len - rx_buf_idx; +} + +uint8 WireBase::read() { + if (rx_buf_idx == rx_buf_len) { + rx_buf_idx = 0; + rx_buf_len = 0; + return 0; + } else if (rx_buf_idx == (rx_buf_len-1)) { + uint8 temp = rx_buf[rx_buf_idx]; + rx_buf_idx = 0; + rx_buf_len = 0; + return temp; + } + return rx_buf[rx_buf_idx++]; +} diff --git a/STM32F1/libraries/Wire/utility/WireBase.h b/STM32F1/libraries/Wire/utility/WireBase.h new file mode 100644 index 0000000..72facde --- /dev/null +++ b/STM32F1/libraries/Wire/utility/WireBase.h @@ -0,0 +1,145 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file WireBase.h + * @author Trystan Jones + * @brief Wire library, following the majority of the interface from Arduino. + * Provides a 'standard' interface to I2C (two-wire) communication for + * derived classes. + */ + +/* + * Library created by crenn to allow a system which would provide users the + * 'standardised' Arduino method for interfacing with I2C devices regardless of + * whether it is I2C hardware or emulating software. + */ + +#ifndef _WIREBASE_H_ +#define _WIREBASE_H_ + +#include "wirish.h" +#include + +#define BUFFER_LENGTH 32 + +/* return codes from endTransmission() */ +#define SUCCESS 0 /* transmission was successful */ +#define EDATA 1 /* too much data */ +#define ENACKADDR 2 /* received nack on transmit of address */ +#define ENACKTRNS 3 /* received nack on transmit of data */ +#define EOTHER 4 /* other error */ + +class WireBase { // Abstraction is awesome! +protected: + i2c_msg itc_msg; + uint8 rx_buf[BUFFER_LENGTH]; /* receive buffer */ + uint8 rx_buf_idx; /* first unread idx in rx_buf */ + uint8 rx_buf_len; /* number of bytes read */ + + uint8 tx_buf[BUFFER_LENGTH]; /* transmit buffer */ + uint8 tx_buf_idx; // next idx available in tx_buf, -1 overflow + boolean tx_buf_overflow; + + // Force derived classes to define process function + virtual uint8 process(uint8) = 0; + virtual uint8 process() = 0; +public: + WireBase() {} + ~WireBase() {} + + /* + * Initialises the class interface + */ + // Allow derived classes to overwrite begin function + virtual void begin(uint8 = 0x00); + + /* + * Sets up the transmission message to be processed + */ + void beginTransmission(uint8); + + /* + * Allow only 8 bit addresses to be used + */ + void beginTransmission(int); + + /* + * Call the process function to process the message if the TX + * buffer has not overflowed. + */ + uint8 endTransmission(bool); + uint8 endTransmission(void); + + /* + * Request bytes from a slave device and process the request, + * storing into the receiving buffer. + */ + uint8 requestFrom(uint8, int); + + /* + * Allow only 8 bit addresses to be used when requesting bytes + */ + uint8 requestFrom(int, int); + + /* + * Stack up bytes to be sent when transmitting + */ + void write(uint8); + + /* + * Stack up bytes from the array to be sent when transmitting + */ + void write(uint8*, int); + + /* + * Ensure that a sending data will only be 8-bit bytes + */ + void write(int); + + /* + * Ensure that an array sending data will only be 8-bit bytes + */ + void write(int*, int); + + /* + * Stack up bytes from a string to be sent when transmitting + */ + void write(char*); + + /* + * Return the amount of bytes that is currently in the receiving buffer + */ + uint8 available(); + + /* + * Return the value of byte in the receiving buffer that is currently being + * pointed to + */ + uint8 read(); +}; + +#endif // _WIREBASE_H_ From 848602e0d6aa45cee6581848878579db34f69a0f Mon Sep 17 00:00:00 2001 From: aster94 Date: Fri, 8 Dec 2017 10:36:00 +0100 Subject: [PATCH 221/351] Delete WireBase.h --- STM32F1/libraries/Wire/WireBase.h | 145 ------------------------------ 1 file changed, 145 deletions(-) delete mode 100644 STM32F1/libraries/Wire/WireBase.h diff --git a/STM32F1/libraries/Wire/WireBase.h b/STM32F1/libraries/Wire/WireBase.h deleted file mode 100644 index 72facde..0000000 --- a/STM32F1/libraries/Wire/WireBase.h +++ /dev/null @@ -1,145 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 LeafLabs LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file WireBase.h - * @author Trystan Jones - * @brief Wire library, following the majority of the interface from Arduino. - * Provides a 'standard' interface to I2C (two-wire) communication for - * derived classes. - */ - -/* - * Library created by crenn to allow a system which would provide users the - * 'standardised' Arduino method for interfacing with I2C devices regardless of - * whether it is I2C hardware or emulating software. - */ - -#ifndef _WIREBASE_H_ -#define _WIREBASE_H_ - -#include "wirish.h" -#include - -#define BUFFER_LENGTH 32 - -/* return codes from endTransmission() */ -#define SUCCESS 0 /* transmission was successful */ -#define EDATA 1 /* too much data */ -#define ENACKADDR 2 /* received nack on transmit of address */ -#define ENACKTRNS 3 /* received nack on transmit of data */ -#define EOTHER 4 /* other error */ - -class WireBase { // Abstraction is awesome! -protected: - i2c_msg itc_msg; - uint8 rx_buf[BUFFER_LENGTH]; /* receive buffer */ - uint8 rx_buf_idx; /* first unread idx in rx_buf */ - uint8 rx_buf_len; /* number of bytes read */ - - uint8 tx_buf[BUFFER_LENGTH]; /* transmit buffer */ - uint8 tx_buf_idx; // next idx available in tx_buf, -1 overflow - boolean tx_buf_overflow; - - // Force derived classes to define process function - virtual uint8 process(uint8) = 0; - virtual uint8 process() = 0; -public: - WireBase() {} - ~WireBase() {} - - /* - * Initialises the class interface - */ - // Allow derived classes to overwrite begin function - virtual void begin(uint8 = 0x00); - - /* - * Sets up the transmission message to be processed - */ - void beginTransmission(uint8); - - /* - * Allow only 8 bit addresses to be used - */ - void beginTransmission(int); - - /* - * Call the process function to process the message if the TX - * buffer has not overflowed. - */ - uint8 endTransmission(bool); - uint8 endTransmission(void); - - /* - * Request bytes from a slave device and process the request, - * storing into the receiving buffer. - */ - uint8 requestFrom(uint8, int); - - /* - * Allow only 8 bit addresses to be used when requesting bytes - */ - uint8 requestFrom(int, int); - - /* - * Stack up bytes to be sent when transmitting - */ - void write(uint8); - - /* - * Stack up bytes from the array to be sent when transmitting - */ - void write(uint8*, int); - - /* - * Ensure that a sending data will only be 8-bit bytes - */ - void write(int); - - /* - * Ensure that an array sending data will only be 8-bit bytes - */ - void write(int*, int); - - /* - * Stack up bytes from a string to be sent when transmitting - */ - void write(char*); - - /* - * Return the amount of bytes that is currently in the receiving buffer - */ - uint8 available(); - - /* - * Return the value of byte in the receiving buffer that is currently being - * pointed to - */ - uint8 read(); -}; - -#endif // _WIREBASE_H_ From 558108d63e1490bc9977643b3a6e037a6ed07124 Mon Sep 17 00:00:00 2001 From: aster94 Date: Fri, 8 Dec 2017 10:36:15 +0100 Subject: [PATCH 222/351] Delete WireBase.cpp --- STM32F1/libraries/Wire/WireBase.cpp | 145 ---------------------------- 1 file changed, 145 deletions(-) delete mode 100644 STM32F1/libraries/Wire/WireBase.cpp diff --git a/STM32F1/libraries/Wire/WireBase.cpp b/STM32F1/libraries/Wire/WireBase.cpp deleted file mode 100644 index 220d845..0000000 --- a/STM32F1/libraries/Wire/WireBase.cpp +++ /dev/null @@ -1,145 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 LeafLabs LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file WireBase.cpp - * @author Trystan Jones - * @brief Wire library, following the majority of the interface from Arduino. - * Provides a 'standard' interface to I2C (two-wire) communication for - * derived classes. - */ - -/* - * Library created by crenn to allow a system which would provide users the - * 'standardised' Arduino method for interfacing with I2C devices regardless of - * whether it is I2C hardware or emulating software. - */ - -#include "WireBase.h" -#include "wirish.h" - -void WireBase::begin(uint8 self_addr) { - tx_buf_idx = 0; - tx_buf_overflow = false; - rx_buf_idx = 0; - rx_buf_len = 0; -} - -void WireBase::beginTransmission(uint8 slave_address) { - itc_msg.addr = slave_address; - itc_msg.data = &tx_buf[tx_buf_idx]; - itc_msg.length = 0; - itc_msg.flags = 0; -} - -void WireBase::beginTransmission(int slave_address) { - beginTransmission((uint8)slave_address); -} - -uint8 WireBase::endTransmission(bool stop) { - uint8 retVal; - if (tx_buf_overflow) { - return EDATA; - } - retVal = process(stop);// Changed so that the return value from process is returned by this function see also the return line below - tx_buf_idx = 0; - tx_buf_overflow = false; - return retVal;//SUCCESS; -} - -uint8 WireBase::endTransmission(){ - endTransmission(true); -} - -//TODO: Add the ability to queue messages (adding a boolean to end of function -// call, allows for the Arduino style to stay while also giving the flexibility -// to bulk send -uint8 WireBase::requestFrom(uint8 address, int num_bytes) { - if (num_bytes > BUFFER_LENGTH) { - num_bytes = BUFFER_LENGTH; - } - itc_msg.addr = address; - itc_msg.flags = I2C_MSG_READ; - itc_msg.length = num_bytes; - itc_msg.data = &rx_buf[rx_buf_idx]; - process(); - rx_buf_len += itc_msg.xferred; - itc_msg.flags = 0; - return rx_buf_len; -} - -uint8 WireBase::requestFrom(int address, int numBytes) { - return WireBase::requestFrom((uint8)address, numBytes); -} - -void WireBase::write(uint8 value) { - if (tx_buf_idx == BUFFER_LENGTH) { - tx_buf_overflow = true; - return; - } - tx_buf[tx_buf_idx++] = value; - itc_msg.length++; -} - -void WireBase::write(uint8* buf, int len) { - for (uint8 i = 0; i < len; i++) { - write(buf[i]); - } -} - -void WireBase::write(int value) { - write((uint8)value); -} - -void WireBase::write(int* buf, int len) { - write((uint8*)buf, (uint8)len); -} - -void WireBase::write(char* buf) { - uint8 *ptr = (uint8*)buf; - while (*ptr) { - write(*ptr); - ptr++; - } -} - -uint8 WireBase::available() { - return rx_buf_len - rx_buf_idx; -} - -uint8 WireBase::read() { - if (rx_buf_idx == rx_buf_len) { - rx_buf_idx = 0; - rx_buf_len = 0; - return 0; - } else if (rx_buf_idx == (rx_buf_len-1)) { - uint8 temp = rx_buf[rx_buf_idx]; - rx_buf_idx = 0; - rx_buf_len = 0; - return temp; - } - return rx_buf[rx_buf_idx++]; -} From 2d8af307dcf110d9bfeb82756f7fbe49ef3ef96f Mon Sep 17 00:00:00 2001 From: aster94 Date: Fri, 8 Dec 2017 10:36:53 +0100 Subject: [PATCH 223/351] Add files via upload --- STM32F1/libraries/Wire/keywords.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/STM32F1/libraries/Wire/keywords.txt b/STM32F1/libraries/Wire/keywords.txt index 3fddb6f..4234cc5 100644 --- a/STM32F1/libraries/Wire/keywords.txt +++ b/STM32F1/libraries/Wire/keywords.txt @@ -14,4 +14,5 @@ SoftWire KEYWORD1 # Constants (LITERAL1) ####################################### SOFT_STANDARD LITERAL1 -SOFT_FAST LITERAL1 \ No newline at end of file +SOFT_FAST LITERAL1 +I2C_FAST_MODE LITERAL1 \ No newline at end of file From b82911742f648970b277a5672f5b003029cbfd81 Mon Sep 17 00:00:00 2001 From: aster94 Date: Fri, 8 Dec 2017 10:37:26 +0100 Subject: [PATCH 224/351] Delete i2c_scanner_hardwire.ino --- .../i2c_scanner_hardwire.ino | 76 ------------------- 1 file changed, 76 deletions(-) delete mode 100644 STM32F1/libraries/Wire/examples/i2c_scanner_hardwire/i2c_scanner_hardwire.ino diff --git a/STM32F1/libraries/Wire/examples/i2c_scanner_hardwire/i2c_scanner_hardwire.ino b/STM32F1/libraries/Wire/examples/i2c_scanner_hardwire/i2c_scanner_hardwire.ino deleted file mode 100644 index d2b3bd4..0000000 --- a/STM32F1/libraries/Wire/examples/i2c_scanner_hardwire/i2c_scanner_hardwire.ino +++ /dev/null @@ -1,76 +0,0 @@ -// -------------------------------------- -// i2c_scanner -// -// Version 1 -// This program (or code that looks like it) -// can be found in many places. -// For example on the Arduino.cc forum. -// The original author is not know. -// Version 2, Juni 2012, Using Arduino 1.0.1 -// Adapted to be as simple as possible by Arduino.cc user Krodal -// Version 3, Feb 26 2013 -// V3 by louarnold -// Version 4, March 3, 2013, Using Arduino 1.0.3 -// by Arduino.cc user Krodal. -// Changes by louarnold removed. -// Scanning addresses changed from 0...127 to 1...119, -// according to the i2c scanner by Nick Gammon -// http://www.gammon.com.au/forum/?id=10896 -// Version 5, March 28, 2013 -// As version 4, but address scans now to 127. -// A sensor seems to use address 120. -// Version 6, August 1, 2015 -// Modified to support HardWire for STM32duino -// -// This sketch tests the standard 7-bit addresses -// Devices with higher bit address might not be seen properly. -// - -#include - -HardWire HWire(1, I2C_FAST_MODE); // I2c1 - -void setup() { - Serial.begin(115200); - HWire.begin(); - Serial.println("\nI2C Scanner"); -} - - -void loop() { - byte error, address; - int nDevices; - - Serial.println("Scanning..."); - - nDevices = 0; - for(address = 1; address < 127; address++) { - // The i2c_scanner uses the return value of - // the Write.endTransmisstion to see if - // a device did acknowledge to the address. - - HWire.beginTransmission(address); - error = HWire.endTransmission(); - - if (error == 0) { - Serial.print("I2C device found at address 0x"); - if (address < 16) - Serial.print("0"); - Serial.println(address, HEX); - - nDevices++; - } - else if (error == 4) { - Serial.print("Unknown error at address 0x"); - if (address < 16) - Serial.print("0"); - Serial.println(address, HEX); - } - } - if (nDevices == 0) - Serial.println("No I2C devices found"); - else - Serial.println("done"); - - delay(5000); // wait 5 seconds for next scan -} \ No newline at end of file From e2a62de0346d469a324603155256f9ac3ee93695 Mon Sep 17 00:00:00 2001 From: aster94 Date: Fri, 8 Dec 2017 10:39:53 +0100 Subject: [PATCH 225/351] Update i2c_scanner_wire.ino --- .../Wire/examples/i2c_scanner_wire/i2c_scanner_wire.ino | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/STM32F1/libraries/Wire/examples/i2c_scanner_wire/i2c_scanner_wire.ino b/STM32F1/libraries/Wire/examples/i2c_scanner_wire/i2c_scanner_wire.ino index 30224d2..0367b4e 100644 --- a/STM32F1/libraries/Wire/examples/i2c_scanner_wire/i2c_scanner_wire.ino +++ b/STM32F1/libraries/Wire/examples/i2c_scanner_wire/i2c_scanner_wire.ino @@ -26,6 +26,10 @@ #include +//use IIC2 +//TwoWire WIRE2 (2,I2C_FAST_MODE); +//#define Wire WIRE2 + void setup() { @@ -71,4 +75,4 @@ void loop() { Serial.println("done"); delay(5000); // wait 5 seconds for next scan -} \ No newline at end of file +} From f245065179976f3c1f265a462a485504598c6f2b Mon Sep 17 00:00:00 2001 From: stevstrong Date: Sat, 9 Dec 2017 20:51:09 +0100 Subject: [PATCH 226/351] Update BluePill-RTClock-test.ino - use build time for RTC - reworked serial monitor output to use sprintf - some fixes + cosmetics --- .../BluePill-RTClock-test.ino | 99 +++++++++++++------ 1 file changed, 67 insertions(+), 32 deletions(-) diff --git a/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino b/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino index d49025a..bf133c2 100644 --- a/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino +++ b/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino @@ -6,7 +6,7 @@ 1. Blink on PC13 per 4s or 7s by attachAlarmInterrupt for 10 times 2. Second counter by attachSecondsInterrpt 3. Serial output on(41s) or off(21s) by creatAlarm - 4. change to your timezone in the sketch; . + 4. change to your timezone in the sketch; 3. get Unix epoch time from https://www.epochconverter.com/ ; 4. last step input the 10 bits number( example: 1503945555) to Serialport ; 5. the clock will be reset to you wanted. @@ -28,10 +28,8 @@ RTClock rtclock (RTCSEL_LSE); // initialise int timezone = 8; // change to your timezone -time_t tt; -time_t tt1; -tm_t mtt = { 47, 9, 13, 3, 11, 22, 30, 30 }; // init time 47+1970 = 2017 Unix epoch Time counted from 00:00:00 1 Jan 1970 -char weekday1[][7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; // 0,1,2,3,4,5,6 +time_t tt, tt1; +tm_t mtt; uint8_t dateread[11]; int globAlmCount = 0; int lastGlobAlmCount; @@ -42,40 +40,87 @@ int alarmcount = 3; uint8_t AlarmExchange = 0; bool dispflag = true; -#define LED_PIN PC13 - +//----------------------------------------------------------------------------- +const char * weekdays[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; +const char * months[] = {"Dummy", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; +//----------------------------------------------------------------------------- +uint8_t str2month(const char * d) +{ + uint8_t i = 13; + while ( (--i) && strcmp(months[i], d)!=0 ); + return i; +} +//----------------------------------------------------------------------------- +const char * delim = " :"; +char s[128]; // for sprintf +//----------------------------------------------------------------------------- +void ParseBuildTimestamp(tm_t & mt) +{ + // Timestamp format: "Dec 8 2017, 22:57:54" + sprintf(s, "Timestamp: %s, %s\n", __DATE__, __TIME__); + //Serial.print(s); + char * token = strtok(s, delim); // get first token + // walk through tokens + while( token != NULL ) { + if ( (uint8_t m = str2month((const char*)token))>0 ) { + mt.month = m; + //Serial.print(" month: "); Serial.println(mt.month); + token = strtok(NULL, delim); // get next token + mt.day = atoi(token); + //Serial.print(" day: "); Serial.println(mt.day); + token = strtok(NULL, delim); // get next token + mt.year = atoi(token) - 1970; + //Serial.print(" year: "); Serial.println(mt.year); + token = strtok(NULL, delim); // get next token + mt.hour = atoi(token); + //Serial.print(" hour: "); Serial.println(mt.hour); + token = strtok(NULL, delim); // get next token + mt.minute = atoi(token); + //Serial.print(" minute: "); Serial.println(mt.minute); + token = strtok(NULL, delim); // get next token + mt.second = atoi(token); + //Serial.print(" second: "); Serial.println(mt.second); + } + token = strtok(NULL, delim); + } +} +//----------------------------------------------------------------------------- // This function is called in the attachSecondsInterrpt +//----------------------------------------------------------------------------- void SecondCount () { tt++; } +//----------------------------------------------------------------------------- // This function is called in the attachAlarmInterrpt +//----------------------------------------------------------------------------- void blink () { - digitalWrite(LED_PIN, !digitalRead(LED_PIN)); + digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); globAlmCount++; - //tt++; } - +//----------------------------------------------------------------------------- void OnOffSerial () { dispflag = !dispflag; SPECAlmCount++; } - +//----------------------------------------------------------------------------- void setup() { lastGlobAlmCount = ~globAlmCount; lastSPECAlmCount = ~SPECAlmCount; Serial.begin(115200); - pinMode(LED_PIN, OUTPUT); - tt = rtclock.makeTime(mtt); - rtclock.setTime(tt); + pinMode(LED_BUILTIN, OUTPUT); + //while (!Serial); delay(1000); + ParseBuildTimestamp(mtt); // get the Unix epoch Time counted from 00:00:00 1 Jan 1970 + tt = rtclock.makeTime(mtt); + rtclock.setTime(tt+25); // additional seconds to compensate build and upload delay tt1 = tt; rtclock.attachAlarmInterrupt(blink);// Call blink rtclock.attachSecondsInterrupt(SecondCount);// Call SecondCount } - +//----------------------------------------------------------------------------- void loop() { while (Serial.available()) @@ -91,7 +136,7 @@ void loop() rtclock.setTime(rtclock.TimeZone(tt, timezone)); } } - if (lastGlobAlmCount != globAlmCount | lastSPECAlmCount != SPECAlmCount ) { + if (lastGlobAlmCount != globAlmCount || lastSPECAlmCount != SPECAlmCount ) { if (globAlmCount == 10) { // to detachAlarmInterrupt and start creatAlarm after 10 times about 110s rtclock.detachAlarmInterrupt(); globAlmCount = 0; @@ -117,23 +162,13 @@ void loop() } } } - if (tt1 != tt & dispflag == true ) + if (tt1 != tt && dispflag == true ) { tt1 = tt; - //rtclock.breakTime(tt, mtt); - Serial.print("Date: "); - Serial.print(rtclock.day()); - Serial.print("- "); - Serial.print(rtclock.month()); - Serial.print(" "); - Serial.print(rtclock.year() + 1970); - Serial.print(" "); - Serial.print(weekday1[rtclock.weekday()]); - Serial.print(" Time: "); - Serial.print(rtclock.hour()); - Serial.print(" : "); - Serial.print(rtclock.minute()); - Serial.print(" : "); - Serial.println(rtclock.second()); + // get and print actual RTC timestamp + rtclock.breakTime(rtclock.now(), mtt); + sprintf(s, "RTC timestamp: %s %u %u, %s, %02u:%02u:%02u\n", + months[mtt.month], mtt.day, mtt.year+1970, weekdays[mtt.weekday], mtt.hour, mtt.minute, mtt.second); + Serial.print(s); } } From e70309ae78d9c84ffec88a1554c3a0daa015225c Mon Sep 17 00:00:00 2001 From: stevstrong Date: Sat, 9 Dec 2017 20:56:48 +0100 Subject: [PATCH 227/351] Update BluePill-RTClock-test.ino - tabs replaced by spaces for a better visual text alignment --- .../BluePill-RTClock-test.ino | 66 +++++++++---------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino b/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino index bf133c2..87213b7 100644 --- a/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino +++ b/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino @@ -46,9 +46,9 @@ const char * months[] = {"Dummy", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul //----------------------------------------------------------------------------- uint8_t str2month(const char * d) { - uint8_t i = 13; - while ( (--i) && strcmp(months[i], d)!=0 ); - return i; + uint8_t i = 13; + while ( (--i) && strcmp(months[i], d)!=0 ); + return i; } //----------------------------------------------------------------------------- const char * delim = " :"; @@ -56,33 +56,33 @@ char s[128]; // for sprintf //----------------------------------------------------------------------------- void ParseBuildTimestamp(tm_t & mt) { - // Timestamp format: "Dec 8 2017, 22:57:54" - sprintf(s, "Timestamp: %s, %s\n", __DATE__, __TIME__); - //Serial.print(s); - char * token = strtok(s, delim); // get first token - // walk through tokens - while( token != NULL ) { - if ( (uint8_t m = str2month((const char*)token))>0 ) { - mt.month = m; - //Serial.print(" month: "); Serial.println(mt.month); - token = strtok(NULL, delim); // get next token - mt.day = atoi(token); - //Serial.print(" day: "); Serial.println(mt.day); - token = strtok(NULL, delim); // get next token - mt.year = atoi(token) - 1970; - //Serial.print(" year: "); Serial.println(mt.year); - token = strtok(NULL, delim); // get next token - mt.hour = atoi(token); - //Serial.print(" hour: "); Serial.println(mt.hour); - token = strtok(NULL, delim); // get next token - mt.minute = atoi(token); - //Serial.print(" minute: "); Serial.println(mt.minute); - token = strtok(NULL, delim); // get next token - mt.second = atoi(token); - //Serial.print(" second: "); Serial.println(mt.second); - } - token = strtok(NULL, delim); - } + // Timestamp format: "Dec 8 2017, 22:57:54" + sprintf(s, "Timestamp: %s, %s\n", __DATE__, __TIME__); + //Serial.print(s); + char * token = strtok(s, delim); // get first token + // walk through tokens + while( token != NULL ) { + if ( (uint8_t m = str2month((const char*)token))>0 ) { + mt.month = m; + //Serial.print(" month: "); Serial.println(mt.month); + token = strtok(NULL, delim); // get next token + mt.day = atoi(token); + //Serial.print(" day: "); Serial.println(mt.day); + token = strtok(NULL, delim); // get next token + mt.year = atoi(token) - 1970; + //Serial.print(" year: "); Serial.println(mt.year); + token = strtok(NULL, delim); // get next token + mt.hour = atoi(token); + //Serial.print(" hour: "); Serial.println(mt.hour); + token = strtok(NULL, delim); // get next token + mt.minute = atoi(token); + //Serial.print(" minute: "); Serial.println(mt.minute); + token = strtok(NULL, delim); // get next token + mt.second = atoi(token); + //Serial.print(" second: "); Serial.println(mt.second); + } + token = strtok(NULL, delim); + } } //----------------------------------------------------------------------------- // This function is called in the attachSecondsInterrpt @@ -165,10 +165,10 @@ void loop() if (tt1 != tt && dispflag == true ) { tt1 = tt; - // get and print actual RTC timestamp + // get and print actual RTC timestamp rtclock.breakTime(rtclock.now(), mtt); - sprintf(s, "RTC timestamp: %s %u %u, %s, %02u:%02u:%02u\n", - months[mtt.month], mtt.day, mtt.year+1970, weekdays[mtt.weekday], mtt.hour, mtt.minute, mtt.second); + sprintf(s, "RTC timestamp: %s %u %u, %s, %02u:%02u:%02u\n", + months[mtt.month], mtt.day, mtt.year+1970, weekdays[mtt.weekday], mtt.hour, mtt.minute, mtt.second); Serial.print(s); } } From f8b7a7ab14ae422835849369b19bccc0d8fea25d Mon Sep 17 00:00:00 2001 From: stevstrong Date: Sat, 9 Dec 2017 21:04:07 +0100 Subject: [PATCH 228/351] Update BluePill-RTClock-test.ino make compiler happy --- .../examples/BluePill-RTClock-test/BluePill-RTClock-test.ino | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino b/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino index 87213b7..394a130 100644 --- a/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino +++ b/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino @@ -62,7 +62,8 @@ void ParseBuildTimestamp(tm_t & mt) char * token = strtok(s, delim); // get first token // walk through tokens while( token != NULL ) { - if ( (uint8_t m = str2month((const char*)token))>0 ) { + uint8_t m = str2month((const char*)token); + if ( m>0 ) { mt.month = m; //Serial.print(" month: "); Serial.println(mt.month); token = strtok(NULL, delim); // get next token From 75f21e3194ebeac17427c066a6b907f6b57099c6 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Sat, 9 Dec 2017 21:05:47 +0100 Subject: [PATCH 229/351] Update BluePill-RTClock-test.ino corrected text alignment (again) --- .../examples/BluePill-RTClock-test/BluePill-RTClock-test.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino b/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino index 394a130..697b094 100644 --- a/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino +++ b/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino @@ -62,8 +62,8 @@ void ParseBuildTimestamp(tm_t & mt) char * token = strtok(s, delim); // get first token // walk through tokens while( token != NULL ) { - uint8_t m = str2month((const char*)token); - if ( m>0 ) { + uint8_t m = str2month((const char*)token); + if ( m>0 ) { mt.month = m; //Serial.print(" month: "); Serial.println(mt.month); token = strtok(NULL, delim); // get next token From f21895e48d0cedbf7645df7fdd42726921795f54 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Sun, 10 Dec 2017 02:07:29 +0100 Subject: [PATCH 230/351] Update BluePill-RTClock-test.ino - corrected typo in comments - reworked serial date input --- .../BluePill-RTClock-test.ino | 28 ++++++++----------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino b/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino index 697b094..5f7b847 100644 --- a/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino +++ b/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino @@ -4,7 +4,7 @@ based on https://github.com/rogerclarkmelbourne/Arduino_STM32 1. Blink on PC13 per 4s or 7s by attachAlarmInterrupt for 10 times - 2. Second counter by attachSecondsInterrpt + 2. Second counter by attachSecondsInterrupt 3. Serial output on(41s) or off(21s) by creatAlarm 4. change to your timezone in the sketch; 3. get Unix epoch time from https://www.epochconverter.com/ ; @@ -35,7 +35,6 @@ int globAlmCount = 0; int lastGlobAlmCount; int SPECAlmCount = 0; int lastSPECAlmCount; -int i = 0; int alarmcount = 3; uint8_t AlarmExchange = 0; bool dispflag = true; @@ -86,14 +85,14 @@ void ParseBuildTimestamp(tm_t & mt) } } //----------------------------------------------------------------------------- -// This function is called in the attachSecondsInterrpt +// This function is called in the attachSecondsInterrupt //----------------------------------------------------------------------------- void SecondCount () { tt++; } //----------------------------------------------------------------------------- -// This function is called in the attachAlarmInterrpt +// This function is called in the attachAlarmInterrupt //----------------------------------------------------------------------------- void blink () { @@ -115,8 +114,8 @@ void setup() pinMode(LED_BUILTIN, OUTPUT); //while (!Serial); delay(1000); ParseBuildTimestamp(mtt); // get the Unix epoch Time counted from 00:00:00 1 Jan 1970 - tt = rtclock.makeTime(mtt); - rtclock.setTime(tt+25); // additional seconds to compensate build and upload delay + tt = rtclock.makeTime(mtt) + 25; // additional seconds to compensate build and upload delay + rtclock.setTime(tt); tt1 = tt; rtclock.attachAlarmInterrupt(blink);// Call blink rtclock.attachSecondsInterrupt(SecondCount);// Call SecondCount @@ -124,18 +123,13 @@ void setup() //----------------------------------------------------------------------------- void loop() { - while (Serial.available()) - { dateread[i] = Serial.read(); - if (i < 11) { - i++; - } - else { - i = 0; - tt = (dateread[0] - '0') * 1000000000 + (dateread[1] - '0') * 100000000 + (dateread[2] - '0') * 10000000 + (dateread[3] - '0') * 1000000 + (dateread[4] - '0') * 100000; - tt += (dateread[5] - '0') * 10000 + (dateread[6] - '0') * 1000 + (dateread[7] - '0') * 100 + (dateread[8] - '0') * 10 + (dateread[9] - '0'); - rtclock.TimeZone(tt, timezone); //adjust to your local date - rtclock.setTime(rtclock.TimeZone(tt, timezone)); + if ( Serial.available()>10 ) { + for (uint8_t i = 0; i<11; i++) { + dateread[i] = Serial.read(); } + Serial.flush(); + tt = atol((char*)dateread); + rtclock.setTime(rtclock.TimeZone(tt, timezone)); //adjust to your local date } if (lastGlobAlmCount != globAlmCount || lastSPECAlmCount != SPECAlmCount ) { if (globAlmCount == 10) { // to detachAlarmInterrupt and start creatAlarm after 10 times about 110s From 000b6ffcd93ebb9a0fe9a745c3d2bf8b124adfc5 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Sun, 10 Dec 2017 02:17:58 +0100 Subject: [PATCH 231/351] Update BluePill-RTClock-test.ino - small alignment fix. --- .../examples/BluePill-RTClock-test/BluePill-RTClock-test.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino b/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino index 5f7b847..d5789db 100644 --- a/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino +++ b/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino @@ -163,7 +163,7 @@ void loop() // get and print actual RTC timestamp rtclock.breakTime(rtclock.now(), mtt); sprintf(s, "RTC timestamp: %s %u %u, %s, %02u:%02u:%02u\n", - months[mtt.month], mtt.day, mtt.year+1970, weekdays[mtt.weekday], mtt.hour, mtt.minute, mtt.second); + months[mtt.month], mtt.day, mtt.year+1970, weekdays[mtt.weekday], mtt.hour, mtt.minute, mtt.second); Serial.print(s); } } From f66b9f10f387e468e3cfb96517beb17911941b3d Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Sun, 10 Dec 2017 17:07:57 +1100 Subject: [PATCH 232/351] Hopefully fixed problem with tone() blocking when it should be non-blocking --- STM32F1/cores/maple/tone.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/STM32F1/cores/maple/tone.cpp b/STM32F1/cores/maple/tone.cpp index 45cfa0e..b249a78 100644 --- a/STM32F1/cores/maple/tone.cpp +++ b/STM32F1/cores/maple/tone.cpp @@ -186,7 +186,8 @@ void tone(uint32_t pin, uint32_t freq, uint32_t duration) { pinMode(tone_pin, INPUT); } - while(tone_nhw) ; // blocks till duration elapsed + + //while(tone_nhw) ; // blocks till duration elapsed } //////////////////////////////////////////////////////////////////////////////// From 87d1b1fdb7505d9605ccb58dee80a3311a300248 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Sun, 10 Dec 2017 09:35:48 +0100 Subject: [PATCH 233/351] Create new file "atomic.h" as discussed here: https://github.com/rogerclarkmelbourne/Arduino_STM32/issues/403, taken from http://www.stm32duino.com/viewtopic.php?f=3&t=258&start=10 --- .../system/libmaple/include/libmaple/atomic.h | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 STM32F1/system/libmaple/include/libmaple/atomic.h diff --git a/STM32F1/system/libmaple/include/libmaple/atomic.h b/STM32F1/system/libmaple/include/libmaple/atomic.h new file mode 100644 index 0000000..db5e489 --- /dev/null +++ b/STM32F1/system/libmaple/include/libmaple/atomic.h @@ -0,0 +1,69 @@ +/* +* This is port of Dean Camera's ATOMIC_BLOCK macros for AVR to ARM Cortex M3 +* v1.0 +* Mark Pendrith, Nov 27, 2012. +* +* From Mark: +* >When I ported the macros I emailed Dean to ask what attribution would be +* >appropriate, and here is his response: +* > +* >>Mark, +* >>I think it's great that you've ported the macros; consider them +* >>public domain, to do with whatever you wish. I hope you find them useful. +* >> +* >>Cheers! +* >>- Dean +*/ + +#ifndef _CORTEX_M3_ATOMIC_H_ +#define _CORTEX_M3_ATOMIC_H_ + +static __inline__ uint32_t __get_primask(void) \ +{ uint32_t primask = 0; \ + __asm__ volatile ("MRS %[result], PRIMASK\n\t":[result]"=r"(primask)::); \ + return primask; } // returns 0 if interrupts enabled, 1 if disabled + +static __inline__ void __set_primask(uint32_t setval) \ +{ __asm__ volatile ("MSR PRIMASK, %[value]\n\t""dmb\n\t""dsb\n\t""isb\n\t"::[value]"r"(setval):); \ + __asm__ volatile ("" ::: "memory");} + +static __inline__ uint32_t __iSeiRetVal(void) \ +{ __asm__ volatile ("CPSIE i\n\t""dmb\n\t""dsb\n\t""isb\n\t"); \ + __asm__ volatile ("" ::: "memory"); return 1; } + +static __inline__ uint32_t __iCliRetVal(void) \ +{ __asm__ volatile ("CPSID i\n\t""dmb\n\t""dsb\n\t""isb\n\t"); \ + __asm__ volatile ("" ::: "memory"); return 1; } + +static __inline__ void __iSeiParam(const uint32_t *__s) \ +{ __asm__ volatile ("CPSIE i\n\t""dmb\n\t""dsb\n\t""isb\n\t"); \ + __asm__ volatile ("" ::: "memory"); (void)__s; } + +static __inline__ void __iCliParam(const uint32_t *__s) \ +{ __asm__ volatile ("CPSID i\n\t""dmb\n\t""dsb\n\t""isb\n\t"); \ + __asm__ volatile ("" ::: "memory"); (void)__s; } + +static __inline__ void __iRestore(const uint32_t *__s) \ +{ __set_primask(*__s); __asm__ volatile ("dmb\n\t""dsb\n\t""isb\n\t"); \ + __asm__ volatile ("" ::: "memory"); } + + +#define ATOMIC_BLOCK(type) \ +for ( type, __ToDo = __iCliRetVal(); __ToDo ; __ToDo = 0 ) + +#define ATOMIC_RESTORESTATE \ +uint32_t primask_save __attribute__((__cleanup__(__iRestore))) = __get_primask() + +#define ATOMIC_FORCEON \ +uint32_t primask_save __attribute__((__cleanup__(__iSeiParam))) = 0 + +#define NONATOMIC_BLOCK(type) \ +for ( type, __ToDo = __iSeiRetVal(); __ToDo ; __ToDo = 0 ) + +#define NONATOMIC_RESTORESTATE \ +uint32_t primask_save __attribute__((__cleanup__(__iRestore))) = __get_primask() + +#define NONATOMIC_FORCEOFF \ +uint32_t primask_save __attribute__((__cleanup__(__iCliParam))) = 0 + +#endif From 3f7db854e4072c98fe435126e49f52e62e816256 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Mon, 11 Dec 2017 09:03:19 +1100 Subject: [PATCH 234/351] Moved atomic.h for better AVR compatibity --- STM32F1/system/libmaple/include/{libmaple => util}/atomic.h | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename STM32F1/system/libmaple/include/{libmaple => util}/atomic.h (100%) diff --git a/STM32F1/system/libmaple/include/libmaple/atomic.h b/STM32F1/system/libmaple/include/util/atomic.h similarity index 100% rename from STM32F1/system/libmaple/include/libmaple/atomic.h rename to STM32F1/system/libmaple/include/util/atomic.h From 1cc4f791914c20e4c562c8778ba3b41e3a0063d7 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Mon, 11 Dec 2017 09:05:38 +1100 Subject: [PATCH 235/351] Moved atomic.h for better AVR compatibility --- STM32F1/system/libmaple/include/util/atomic.h | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 STM32F1/system/libmaple/include/util/atomic.h diff --git a/STM32F1/system/libmaple/include/util/atomic.h b/STM32F1/system/libmaple/include/util/atomic.h new file mode 100644 index 0000000..db5e489 --- /dev/null +++ b/STM32F1/system/libmaple/include/util/atomic.h @@ -0,0 +1,69 @@ +/* +* This is port of Dean Camera's ATOMIC_BLOCK macros for AVR to ARM Cortex M3 +* v1.0 +* Mark Pendrith, Nov 27, 2012. +* +* From Mark: +* >When I ported the macros I emailed Dean to ask what attribution would be +* >appropriate, and here is his response: +* > +* >>Mark, +* >>I think it's great that you've ported the macros; consider them +* >>public domain, to do with whatever you wish. I hope you find them useful. +* >> +* >>Cheers! +* >>- Dean +*/ + +#ifndef _CORTEX_M3_ATOMIC_H_ +#define _CORTEX_M3_ATOMIC_H_ + +static __inline__ uint32_t __get_primask(void) \ +{ uint32_t primask = 0; \ + __asm__ volatile ("MRS %[result], PRIMASK\n\t":[result]"=r"(primask)::); \ + return primask; } // returns 0 if interrupts enabled, 1 if disabled + +static __inline__ void __set_primask(uint32_t setval) \ +{ __asm__ volatile ("MSR PRIMASK, %[value]\n\t""dmb\n\t""dsb\n\t""isb\n\t"::[value]"r"(setval):); \ + __asm__ volatile ("" ::: "memory");} + +static __inline__ uint32_t __iSeiRetVal(void) \ +{ __asm__ volatile ("CPSIE i\n\t""dmb\n\t""dsb\n\t""isb\n\t"); \ + __asm__ volatile ("" ::: "memory"); return 1; } + +static __inline__ uint32_t __iCliRetVal(void) \ +{ __asm__ volatile ("CPSID i\n\t""dmb\n\t""dsb\n\t""isb\n\t"); \ + __asm__ volatile ("" ::: "memory"); return 1; } + +static __inline__ void __iSeiParam(const uint32_t *__s) \ +{ __asm__ volatile ("CPSIE i\n\t""dmb\n\t""dsb\n\t""isb\n\t"); \ + __asm__ volatile ("" ::: "memory"); (void)__s; } + +static __inline__ void __iCliParam(const uint32_t *__s) \ +{ __asm__ volatile ("CPSID i\n\t""dmb\n\t""dsb\n\t""isb\n\t"); \ + __asm__ volatile ("" ::: "memory"); (void)__s; } + +static __inline__ void __iRestore(const uint32_t *__s) \ +{ __set_primask(*__s); __asm__ volatile ("dmb\n\t""dsb\n\t""isb\n\t"); \ + __asm__ volatile ("" ::: "memory"); } + + +#define ATOMIC_BLOCK(type) \ +for ( type, __ToDo = __iCliRetVal(); __ToDo ; __ToDo = 0 ) + +#define ATOMIC_RESTORESTATE \ +uint32_t primask_save __attribute__((__cleanup__(__iRestore))) = __get_primask() + +#define ATOMIC_FORCEON \ +uint32_t primask_save __attribute__((__cleanup__(__iSeiParam))) = 0 + +#define NONATOMIC_BLOCK(type) \ +for ( type, __ToDo = __iSeiRetVal(); __ToDo ; __ToDo = 0 ) + +#define NONATOMIC_RESTORESTATE \ +uint32_t primask_save __attribute__((__cleanup__(__iRestore))) = __get_primask() + +#define NONATOMIC_FORCEOFF \ +uint32_t primask_save __attribute__((__cleanup__(__iCliParam))) = 0 + +#endif From 63f4162c6cbc23b5467ce7ced2bcf5d2bf0bf385 Mon Sep 17 00:00:00 2001 From: Thomas Friedrichsmeier Date: Tue, 12 Dec 2017 10:58:22 +0100 Subject: [PATCH 236/351] Fix compilation with -std=gnu++11 See https://github.com/rogerclarkmelbourne/Arduino_STM32/issues/402 --- STM32F1/libraries/STM32ADC/src/STM32ADC.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/STM32F1/libraries/STM32ADC/src/STM32ADC.h b/STM32F1/libraries/STM32ADC/src/STM32ADC.h index fd0588f..685eeb1 100644 --- a/STM32F1/libraries/STM32ADC/src/STM32ADC.h +++ b/STM32F1/libraries/STM32ADC/src/STM32ADC.h @@ -152,7 +152,7 @@ private: voidFuncPtr _DMA_int; voidFuncPtr _ADC_int; voidFuncPtr _AWD_int; - static const float _AverageSlope = 4.3; // mV/oC //4.0 to 4.6 - static const float _V25 = 1.43; //Volts //1.34 - 1.52 + static constexpr float _AverageSlope = 4.3; // mV/oC //4.0 to 4.6 + static constexpr float _V25 = 1.43; //Volts //1.34 - 1.52 }; From 951d0acf178b28d52919fb777874d90603c88883 Mon Sep 17 00:00:00 2001 From: victorpv Date: Sat, 16 Dec 2017 17:25:57 -0600 Subject: [PATCH 237/351] Adding PB2 as in the Generic R and Z versions. --- STM32F1/variants/generic_stm32f103v/board.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/STM32F1/variants/generic_stm32f103v/board.cpp b/STM32F1/variants/generic_stm32f103v/board.cpp index 9c13772..c24140e 100644 --- a/STM32F1/variants/generic_stm32f103v/board.cpp +++ b/STM32F1/variants/generic_stm32f103v/board.cpp @@ -98,7 +98,7 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { {&gpiob, &timer3, &adc1, 0, 3, 8}, /* PB0 */ {&gpiob, &timer3, &adc1, 1, 4, 9}, /* PB1 */ - /* NOTE PB2 is not included as its Boot 1 */ + {&gpiob, NULL, NULL, 2, 0, ADCx}, /* PB2 */ {&gpiob, NULL, NULL, 3, 0, ADCx}, /* PB3 */ //JTDO, SPI3_SCK / I2S3_CK/ {&gpiob, NULL, NULL, 4, 0, ADCx}, /* PB4 */ //NJTRST, SPI3_MISO {&gpiob, NULL, NULL, 5, 0, ADCx}, /* PB5 */ //I2C1_SMBA/ SPI3_MOSI @@ -196,4 +196,4 @@ extern const uint8 boardUsedPins[BOARD_NR_USED_PINS] __FLASH__ = { DEFINE_HWSERIAL(Serial2, 3); DEFINE_HWSERIAL_UART(Serial3, 4); DEFINE_HWSERIAL_UART(Serial4, 5); -#endif \ No newline at end of file +#endif From e64dbc2d473a671f59f87655249247e34d026ef8 Mon Sep 17 00:00:00 2001 From: victorpv Date: Sat, 16 Dec 2017 17:28:00 -0600 Subject: [PATCH 238/351] Add PB2 to enums as in the R and Z Generic boards Can be used for output --- STM32F1/variants/generic_stm32f103v/board/board.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/STM32F1/variants/generic_stm32f103v/board/board.h b/STM32F1/variants/generic_stm32f103v/board/board.h index 3bb680a..ccd5ecf 100644 --- a/STM32F1/variants/generic_stm32f103v/board/board.h +++ b/STM32F1/variants/generic_stm32f103v/board/board.h @@ -124,10 +124,10 @@ * write code using low-level GPIO functionality. */ enum { PA0,PA1,PA2,PA3,PA4,PA5,PA6,PA7,PA8,PA9,PA10,PA11,PA12,PA13,PA14,PA15, -PB0,PB1,PB3,PB4,PB5,PB6,PB7,PB8,PB9,PB10,PB11,PB12,PB13,PB14,PB15, +PB0,PB1,PB2,PB3,PB4,PB5,PB6,PB7,PB8,PB9,PB10,PB11,PB12,PB13,PB14,PB15, PC0,PC1,PC2,PC3,PC4,PC5,PC6,PC7,PC8,PC9,PC10,PC11,PC12,PC13,PC14,PC15, PD0,PD1,PD2,PD3,PD4,PD5,PD6,PD7,PD8,PD9,PD10,PD11,PD12,PD13,PD14,PD15, PE0,PE1,PE2,PE3,PE4,PE5,PE6,PE7,PE8,PE9,PE10,PE11,PE12,PE13,PE14,PE15, -};/* Note PB2 is skipped as this is Boot1 and is not going to be much use as its likely to be pulled permanently low */ +}; #endif From 09812b48630ff59613cbe1e813b0766f08394296 Mon Sep 17 00:00:00 2001 From: victorpv Date: Sun, 17 Dec 2017 15:20:07 -0600 Subject: [PATCH 239/351] Add comment to PB2 pin about boot1 function. --- STM32F1/variants/generic_stm32f103v/board.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/variants/generic_stm32f103v/board.cpp b/STM32F1/variants/generic_stm32f103v/board.cpp index c24140e..d5596a2 100644 --- a/STM32F1/variants/generic_stm32f103v/board.cpp +++ b/STM32F1/variants/generic_stm32f103v/board.cpp @@ -98,7 +98,7 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { {&gpiob, &timer3, &adc1, 0, 3, 8}, /* PB0 */ {&gpiob, &timer3, &adc1, 1, 4, 9}, /* PB1 */ - {&gpiob, NULL, NULL, 2, 0, ADCx}, /* PB2 */ + {&gpiob, NULL, NULL, 2, 0, ADCx}, /* PB2 */ // Boot1 pin. It affects boot mode (flash, RAM, ROM) {&gpiob, NULL, NULL, 3, 0, ADCx}, /* PB3 */ //JTDO, SPI3_SCK / I2S3_CK/ {&gpiob, NULL, NULL, 4, 0, ADCx}, /* PB4 */ //NJTRST, SPI3_MISO {&gpiob, NULL, NULL, 5, 0, ADCx}, /* PB5 */ //I2C1_SMBA/ SPI3_MOSI From 066dacf797c4ab42d99b9cb9ea1468ed6e6118f4 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Fri, 29 Dec 2017 08:58:57 +0100 Subject: [PATCH 240/351] Update wirish_debug.cpp reserve SWD lines only for debug --- STM32F1/cores/maple/stm32f1/wirish_debug.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/cores/maple/stm32f1/wirish_debug.cpp b/STM32F1/cores/maple/stm32f1/wirish_debug.cpp index f057616..8f6cc98 100644 --- a/STM32F1/cores/maple/stm32f1/wirish_debug.cpp +++ b/STM32F1/cores/maple/stm32f1/wirish_debug.cpp @@ -37,5 +37,5 @@ void disableDebugPorts(void) { } void enableDebugPorts(void) { - afio_cfg_debug_ports(AFIO_DEBUG_FULL_SWJ); + afio_cfg_debug_ports(AFIO_DEBUG_SW_ONLY); } From 63f784ff6f4823d754c0f270ce55a17931456079 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Tue, 2 Jan 2018 16:19:31 +0100 Subject: [PATCH 241/351] Update HW_STM32.h remove static directive --- STM32F1/libraries/OLED_I2C/hardware/arm/HW_STM32.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/libraries/OLED_I2C/hardware/arm/HW_STM32.h b/STM32F1/libraries/OLED_I2C/hardware/arm/HW_STM32.h index a892c43..20c1a16 100644 --- a/STM32F1/libraries/OLED_I2C/hardware/arm/HW_STM32.h +++ b/STM32F1/libraries/OLED_I2C/hardware/arm/HW_STM32.h @@ -109,7 +109,7 @@ void OLED::update() twi->TWI_THR = scrbuf[b]; while ((twi->TWI_SR & TWI_SR_TXRDY) != TWI_SR_TXRDY) {}; */ - static byte aa=scrbuf[b]; + byte aa=scrbuf[b]; WIRE_WRITE(aa); } From ac9237248f23ce6ca9e24abefe9bd368197f5e74 Mon Sep 17 00:00:00 2001 From: "Frederic.Pillon" Date: Tue, 9 Jan 2018 09:18:36 +0100 Subject: [PATCH 242/351] Replace {build.path}/{archive_file} by {archive_file_path} See https://github.com/arduino/Arduino/issues/6757#issuecomment-331861565 From @facchinm: Replacing {build.path}/{archive_file} with archive_file_path should remove the arduino_build_xxxxxx/.. part and make the path a bit shorter. Issue also raised here using BP: http://stm32duino.com/viewtopic.php?f=3&t=3070 Signed-off-by: Frederic.Pillon --- STM32F1/platform.txt | 4 ++-- STM32F3/platform.txt | 6 +++--- STM32F4/platform.txt | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/STM32F1/platform.txt b/STM32F1/platform.txt index de1f206..b52e7df 100644 --- a/STM32F1/platform.txt +++ b/STM32F1/platform.txt @@ -87,7 +87,7 @@ recipe.S.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.S.flags} -mcpu={b recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{archive_file_path}" "{object_file}" ## Combine gc-sections, archives, and objects -recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} -mcpu={build.mcu} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" -lm -lgcc -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols -Wl,--start-group {object_files} "{build.path}/{archive_file}" -Wl,--end-group +recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} -mcpu={build.mcu} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" -lm -lgcc -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols -Wl,--start-group {object_files} "{archive_file_path}" -Wl,--end-group ## Create eeprom recipe.objcopy.eep.pattern= @@ -160,4 +160,4 @@ tools.jlink_upload.path.linux={runtime.hardware.path}/tools/linux tools.jlink_upload.path.linux64={runtime.hardware.path}/tools/linux64 tools.jlink_upload.upload.params.verbose=-d tools.jlink_upload.upload.params.quiet=n -tools.jlink_upload.upload.pattern="{path}/{cmd}" "{build.path}/{build.project_name}.bin" \ No newline at end of file +tools.jlink_upload.upload.pattern="{path}/{cmd}" "{build.path}/{build.project_name}.bin" diff --git a/STM32F3/platform.txt b/STM32F3/platform.txt index 94f787c..60d4042 100644 --- a/STM32F3/platform.txt +++ b/STM32F3/platform.txt @@ -79,10 +79,10 @@ recipe.S.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.S.flags} -mcpu={b recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{archive_file_path}" "{object_file}" ## Combine gc-sections, archives, and objects -##recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} -mcpu={build.mcu} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" -lm -lgcc -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--entry=Reset_Handler -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols -Wl,--start-group "{build.path}/syscalls_sam3.c.o" {object_files} "{build.variant.path}/{build.variant_system_lib}" "{build.path}/{archive_file}" -Wl,--end-group +##recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} -mcpu={build.mcu} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" -lm -lgcc -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--entry=Reset_Handler -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols -Wl,--start-group "{build.path}/syscalls_sam3.c.o" {object_files} "{build.variant.path}/{build.variant_system_lib}" "{archive_file_path}" -Wl,--end-group #-Wl,--entry=__start__ -#recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} -mcpu={build.mcu} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" -lm -lgcc -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols -Wl,--start-group {object_files} "{build.variant.path}/{build.variant_system_lib}" "{build.path}/{archive_file}" -Wl,--end-group -recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} -mcpu={build.mcu} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" -lm -lgcc -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols -Wl,--start-group {object_files} -Wl,--whole-archive "{build.path}/{archive_file}" -Wl,--no-whole-archive -Wl,--end-group +#recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} -mcpu={build.mcu} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" -lm -lgcc -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols -Wl,--start-group {object_files} "{build.variant.path}/{build.variant_system_lib}" "{archive_file_path}" -Wl,--end-group +recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} -mcpu={build.mcu} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" -lm -lgcc -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols -Wl,--start-group {object_files} -Wl,--whole-archive "{archive_file_path}" -Wl,--no-whole-archive -Wl,--end-group ## Create eeprom recipe.objcopy.eep.pattern= diff --git a/STM32F4/platform.txt b/STM32F4/platform.txt index d115210..3c3e833 100755 --- a/STM32F4/platform.txt +++ b/STM32F4/platform.txt @@ -76,10 +76,10 @@ recipe.S.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.S.flags} -mcpu={b recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{archive_file_path}" "{object_file}" ## Combine gc-sections, archives, and objects -##recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} -mcpu={build.mcu} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" -lm -lgcc -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--entry=Reset_Handler -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols -Wl,--start-group "{build.path}/syscalls_sam3.c.o" {object_files} "{build.variant.path}/{build.variant_system_lib}" "{build.path}/{archive_file}" -Wl,--end-group +##recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} -mcpu={build.mcu} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" -lm -lgcc -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--entry=Reset_Handler -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols -Wl,--start-group "{build.path}/syscalls_sam3.c.o" {object_files} "{build.variant.path}/{build.variant_system_lib}" "{archive_file_path}" -Wl,--end-group #-Wl,--entry=__start__ -#recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} -mcpu={build.mcu} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" -lm -lgcc -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols -Wl,--start-group {object_files} "{build.variant.path}/{build.variant_system_lib}" "{build.path}/{archive_file}" -Wl,--end-group -recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} -mcpu={build.mcu} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" -lm -lgcc -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols -Wl,--start-group {object_files} -Wl,--whole-archive "{build.path}/{archive_file}" -Wl,--no-whole-archive -Wl,--end-group +#recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} -mcpu={build.mcu} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" -lm -lgcc -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols -Wl,--start-group {object_files} "{build.variant.path}/{build.variant_system_lib}" "{archive_file_path}" -Wl,--end-group +recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} -mcpu={build.mcu} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" -lm -lgcc -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols -Wl,--start-group {object_files} -Wl,--whole-archive "{archive_file_path}" -Wl,--no-whole-archive -Wl,--end-group ## Create eeprom recipe.objcopy.eep.pattern= From 8540c6b08b20a5cd36964c6d1668269edbd2b5c5 Mon Sep 17 00:00:00 2001 From: BlackBrix-Editor <35255671+BlackBrix-Editor@users.noreply.github.com> Date: Tue, 9 Jan 2018 11:23:16 +0100 Subject: [PATCH 243/351] option XTAL16M for boards with 16MHz-crystal tested on STM32F103VE only but surely can be used on other STM32F103xC, STM32F103xD, STM32F103xE with the same clock PLL structure --- STM32F1/variants/generic_stm32f103v/wirish/boards.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/STM32F1/variants/generic_stm32f103v/wirish/boards.cpp b/STM32F1/variants/generic_stm32f103v/wirish/boards.cpp index 254666f..ddeaa57 100644 --- a/STM32F1/variants/generic_stm32f103v/wirish/boards.cpp +++ b/STM32F1/variants/generic_stm32f103v/wirish/boards.cpp @@ -130,6 +130,12 @@ static void setup_clocks(void) { wirish::priv::board_setup_clock_prescalers(); rcc_configure_pll(&wirish::priv::w_board_pll_cfg); +#ifdef XTAL16M + // 16MHz crystal (HSE) + // in this case we additionally set the Bit 17 (PLLXTPRE=1) => then HSE clock is divided by 2 before PLL entry + RCC_BASE->CFGR |= RCC_CFGR_PLLXTPRE; +#endif + // Enable the PLL, and wait until it's ready. rcc_turn_on_clk(RCC_CLK_PLL); while(!rcc_is_clk_ready(RCC_CLK_PLL)) From d54de1cbb011fb2f4273a365340b2b3a29f23b6e Mon Sep 17 00:00:00 2001 From: BlackBrix-Editor <35255671+BlackBrix-Editor@users.noreply.github.com> Date: Tue, 9 Jan 2018 12:21:48 +0100 Subject: [PATCH 244/351] corrected RAM-length = 48kByte for STM32F103VC --- STM32F1/variants/generic_stm32f103v/ld/stm32f103vc.ld | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/variants/generic_stm32f103v/ld/stm32f103vc.ld b/STM32F1/variants/generic_stm32f103v/ld/stm32f103vc.ld index 7efca5d..6079807 100644 --- a/STM32F1/variants/generic_stm32f103v/ld/stm32f103vc.ld +++ b/STM32F1/variants/generic_stm32f103v/ld/stm32f103vc.ld @@ -16,7 +16,7 @@ */ MEMORY { - ram (rwx) : ORIGIN = 0x20000000, LENGTH = 64K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 48K rom (rx) : ORIGIN = 0x08000000, LENGTH = 256K } From 514cf856aae4e0f391c318d7677b53b4b04270a2 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Thu, 18 Jan 2018 11:39:03 +0100 Subject: [PATCH 245/351] Update boards.txt added error LED pin for generic F103C --- STM32F1/boards.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/STM32F1/boards.txt b/STM32F1/boards.txt index 49c1293..cb9416a 100644 --- a/STM32F1/boards.txt +++ b/STM32F1/boards.txt @@ -346,6 +346,8 @@ genericSTM32F103C.build.variant=generic_stm32f103c genericSTM32F103C.build.vect=VECT_TAB_ADDR=0x8000000 genericSTM32F103C.build.core=maple genericSTM32F103C.build.board=GENERIC_STM32F103C +genericSTM32F103C.build.error_led_port=GPIOC +genericSTM32F103C.build.error_led_pin=13 genericSTM32F103C.upload.use_1200bps_touch=false genericSTM32F103C.upload.file_type=bin genericSTM32F103C.upload.auto_reset=true From 9cd2f3a74366835930c4f3ba94193fc9db42ad10 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Sun, 21 Jan 2018 15:34:24 +1100 Subject: [PATCH 246/351] Manually committed changes from https://github.com/rogerclarkmelbourne/Arduino_STM32/pull/401, as that PR included changes to permissions on unrelated files in the tools --- STM32F1/cores/maple/libmaple/usb/stm32f1/usb.c | 8 ++++++++ STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c | 9 +++++++-- STM32F1/system/libmaple/include/libmaple/usb.h | 2 ++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/STM32F1/cores/maple/libmaple/usb/stm32f1/usb.c b/STM32F1/cores/maple/libmaple/usb/stm32f1/usb.c index f837eb6..0feb745 100644 --- a/STM32F1/cores/maple/libmaple/usb/stm32f1/usb.c +++ b/STM32F1/cores/maple/libmaple/usb/stm32f1/usb.c @@ -120,6 +120,12 @@ static void usb_suspend(void) { USBLIB->state = USB_SUSPENDED; } +void usb_power_off(void) { + USB_BASE->CNTR = USB_CNTR_FRES; + USB_BASE->ISTR = 0; + USB_BASE->CNTR = USB_CNTR_FRES + USB_CNTR_PDWN; +} + static void usb_resume_init(void) { uint16 cntr; @@ -268,6 +274,7 @@ static void handle_out0(void); static void dispatch_ctr_lp() { uint16 istr; + while (((istr = USB_BASE->ISTR) & USB_ISTR_CTR) != 0) { /* TODO WTF, figure this out: RM0008 says CTR is read-only, * but ST's firmware claims it's clear-only, and emphasizes @@ -288,6 +295,7 @@ static void dispatch_ctr_lp() { } } + /* FIXME Dataflow on endpoint 0 RX/TX status is based off of ST's * code, and is ugly/confusing in its use of SaveRState/SaveTState. * Fixing this requires filling in handle_in0(), handle_setup0(), diff --git a/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c b/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c index cba050f..1f0b626 100644 --- a/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c +++ b/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c @@ -80,7 +80,6 @@ static uint8* usbGetConfigDescriptor(uint16 length); static uint8* usbGetStringDescriptor(uint16 length); static void usbSetConfiguration(void); static void usbSetDeviceAddress(void); - /* * Descriptors */ @@ -392,6 +391,8 @@ void usb_cdcacm_enable(gpio_dev *disc_dev, uint8 disc_bit) { } /* Initialize the USB peripheral. */ + /* One of the callbacks that will automatically happen from this will be to usbInit(), + which will power up the USB peripheral. */ usb_init_usblib(USBLIB, ep_int_in, ep_int_out); } @@ -403,6 +404,9 @@ void usb_cdcacm_disable(gpio_dev *disc_dev, uint8 disc_bit) { { gpio_write_bit(disc_dev, disc_bit, 1); } + /* Powerdown the USB peripheral. It gets powered up again with usbInit(), which + gets called when usb_cdcacm_enable() is called. */ + usb_power_off(); } void usb_cdcacm_putc(char ch) { @@ -644,7 +648,8 @@ static uint8* vcomGetSetLineCoding(uint16 length) { static void usbInit(void) { pInformation->Current_Configuration = 0; - USB_BASE->CNTR = USB_CNTR_FRES; + // Reset and power up the peripheral. + USB_BASE->CNTR = USB_CNTR_FRES; USBLIB->irq_mask = 0; USB_BASE->CNTR = USBLIB->irq_mask; diff --git a/STM32F1/system/libmaple/include/libmaple/usb.h b/STM32F1/system/libmaple/include/libmaple/usb.h index ea24030..1ea06e9 100644 --- a/STM32F1/system/libmaple/include/libmaple/usb.h +++ b/STM32F1/system/libmaple/include/libmaple/usb.h @@ -157,6 +157,8 @@ typedef struct usblib_dev { extern usblib_dev *USBLIB; +void usb_power_off(void); + void usb_init_usblib(usblib_dev *dev, void (**ep_int_in)(void), void (**ep_int_out)(void)); From 0f78c266ed2c571e9e48e4236b3721c88752f4db Mon Sep 17 00:00:00 2001 From: lacklustrlabs Date: Thu, 14 Dec 2017 16:32:59 +0100 Subject: [PATCH 247/351] Added Wire_slave.h (no actual i2c slave implementation yet) --- STM32F1/libraries/Wire/Wire_slave.h | 1 + STM32F1/libraries/Wire/library.properties | 10 + .../SFRRanger_reader/SFRRanger_reader.ino | 87 ++ .../digital_potentiometer.ino | 38 + .../i2c_libmaple_slave/i2c_libmaple_slave.ino | 122 +++ .../examples/master_reader/master_reader.ino | 32 + .../examples/master_writer/master_writer.ino | 31 + .../slave_receiver/slave_receiver.ino | 38 + .../examples/slave_sender/slave_sender.ino | 32 + .../libraries/WireSlave/library.properties | 11 + STM32F1/libraries/WireSlave/src/Wire.h | 1 + STM32F1/libraries/WireSlave/src/Wire.h.gch | Bin 0 -> 1819056 bytes .../libraries/WireSlave/src/Wire_slave.cpp | 106 +++ STM32F1/libraries/WireSlave/src/Wire_slave.h | 78 ++ .../libraries/WireSlave/src/Wire_slave.h.gch | Bin 0 -> 9475 bytes STM32F1/libraries/WireSlave/src/i2c_slave.c | 789 ++++++++++++++++++ .../libraries/WireSlave/src/i2c_slave.h.gch | Bin 0 -> 9475 bytes .../WireSlave/src/libmaple/i2c_common_slave.h | 110 +++ .../WireSlave/src/libmaple/i2c_slave.h | 475 +++++++++++ .../WireSlave/src/libmaple/i2c_slave.h.gch | Bin 0 -> 9475 bytes .../WireSlave/src/utility/WireBase_slave.cpp | 145 ++++ .../WireSlave/src/utility/WireBase_slave.h | 145 ++++ .../src/utility/WireBase_slave.h.gch | Bin 0 -> 9475 bytes 23 files changed, 2251 insertions(+) create mode 100644 STM32F1/libraries/Wire/Wire_slave.h create mode 100644 STM32F1/libraries/Wire/library.properties create mode 100644 STM32F1/libraries/WireSlave/examples/SFRRanger_reader/SFRRanger_reader.ino create mode 100644 STM32F1/libraries/WireSlave/examples/digital_potentiometer/digital_potentiometer.ino create mode 100644 STM32F1/libraries/WireSlave/examples/i2c_libmaple_slave/i2c_libmaple_slave.ino create mode 100644 STM32F1/libraries/WireSlave/examples/master_reader/master_reader.ino create mode 100644 STM32F1/libraries/WireSlave/examples/master_writer/master_writer.ino create mode 100644 STM32F1/libraries/WireSlave/examples/slave_receiver/slave_receiver.ino create mode 100644 STM32F1/libraries/WireSlave/examples/slave_sender/slave_sender.ino create mode 100644 STM32F1/libraries/WireSlave/library.properties create mode 100644 STM32F1/libraries/WireSlave/src/Wire.h create mode 100644 STM32F1/libraries/WireSlave/src/Wire.h.gch create mode 100644 STM32F1/libraries/WireSlave/src/Wire_slave.cpp create mode 100644 STM32F1/libraries/WireSlave/src/Wire_slave.h create mode 100644 STM32F1/libraries/WireSlave/src/Wire_slave.h.gch create mode 100644 STM32F1/libraries/WireSlave/src/i2c_slave.c create mode 100644 STM32F1/libraries/WireSlave/src/i2c_slave.h.gch create mode 100644 STM32F1/libraries/WireSlave/src/libmaple/i2c_common_slave.h create mode 100644 STM32F1/libraries/WireSlave/src/libmaple/i2c_slave.h create mode 100644 STM32F1/libraries/WireSlave/src/libmaple/i2c_slave.h.gch create mode 100644 STM32F1/libraries/WireSlave/src/utility/WireBase_slave.cpp create mode 100644 STM32F1/libraries/WireSlave/src/utility/WireBase_slave.h create mode 100644 STM32F1/libraries/WireSlave/src/utility/WireBase_slave.h.gch diff --git a/STM32F1/libraries/Wire/Wire_slave.h b/STM32F1/libraries/Wire/Wire_slave.h new file mode 100644 index 0000000..21b4102 --- /dev/null +++ b/STM32F1/libraries/Wire/Wire_slave.h @@ -0,0 +1 @@ +#error "Something is trying to include Wire.h when Wire_Slave.h is already included, they are mutually exclusive" diff --git a/STM32F1/libraries/Wire/library.properties b/STM32F1/libraries/Wire/library.properties new file mode 100644 index 0000000..1129fa3 --- /dev/null +++ b/STM32F1/libraries/Wire/library.properties @@ -0,0 +1,10 @@ +name=Wire +version=1.0 +author=Arduino +maintainer=Arduino +sentence=Allows the communication between devices or sensors connected via Two Wire Interface Bus. +paragraph= +category=Communication +url=http://www.arduino.cc/en/Reference/Wire +architectures=STM32F1 +include=Wire.h diff --git a/STM32F1/libraries/WireSlave/examples/SFRRanger_reader/SFRRanger_reader.ino b/STM32F1/libraries/WireSlave/examples/SFRRanger_reader/SFRRanger_reader.ino new file mode 100644 index 0000000..5537eca --- /dev/null +++ b/STM32F1/libraries/WireSlave/examples/SFRRanger_reader/SFRRanger_reader.ino @@ -0,0 +1,87 @@ +// I2C SRF10 or SRF08 Devantech Ultrasonic Ranger Finder +// by Nicholas Zambetti +// and James Tichenor + +// Demonstrates use of the Wire library reading data from the +// Devantech Utrasonic Rangers SFR08 and SFR10 + +// Created 29 April 2006 + +// This example code is in the public domain. + + +#include + +void setup() +{ + Wire.begin(); // join i2c bus (address optional for master) + Serial.begin(9600); // start serial communication at 9600bps +} + +int reading = 0; + +void loop() +{ + // step 1: instruct sensor to read echoes + Wire.beginTransmission(112); // transmit to device #112 (0x70) + // the address specified in the datasheet is 224 (0xE0) + // but i2c adressing uses the high 7 bits so it's 112 + Wire.write(byte(0x00)); // sets register pointer to the command register (0x00) + Wire.write(byte(0x50)); // command sensor to measure in "inches" (0x50) + // use 0x51 for centimeters + // use 0x52 for ping microseconds + Wire.endTransmission(); // stop transmitting + + // step 2: wait for readings to happen + delay(70); // datasheet suggests at least 65 milliseconds + + // step 3: instruct sensor to return a particular echo reading + Wire.beginTransmission(112); // transmit to device #112 + Wire.write(byte(0x02)); // sets register pointer to echo #1 register (0x02) + Wire.endTransmission(); // stop transmitting + + // step 4: request reading from sensor + Wire.requestFrom(112, 2); // request 2 bytes from slave device #112 + + // step 5: receive reading from sensor + if(2 <= Wire.available()) // if two bytes were received + { + reading = Wire.read(); // receive high byte (overwrites previous reading) + reading = reading << 8; // shift high byte to be high 8 bits + reading |= Wire.read(); // receive low byte as lower 8 bits + Serial.println(reading); // print the reading + } + + delay(250); // wait a bit since people have to read the output :) +} + + +/* + +// The following code changes the address of a Devantech Ultrasonic Range Finder (SRF10 or SRF08) +// usage: changeAddress(0x70, 0xE6); + +void changeAddress(byte oldAddress, byte newAddress) +{ + Wire.beginTransmission(oldAddress); + Wire.write(byte(0x00)); + Wire.write(byte(0xA0)); + Wire.endTransmission(); + + Wire.beginTransmission(oldAddress); + Wire.write(byte(0x00)); + Wire.write(byte(0xAA)); + Wire.endTransmission(); + + Wire.beginTransmission(oldAddress); + Wire.write(byte(0x00)); + Wire.write(byte(0xA5)); + Wire.endTransmission(); + + Wire.beginTransmission(oldAddress); + Wire.write(byte(0x00)); + Wire.write(newAddress); + Wire.endTransmission(); +} + +*/ diff --git a/STM32F1/libraries/WireSlave/examples/digital_potentiometer/digital_potentiometer.ino b/STM32F1/libraries/WireSlave/examples/digital_potentiometer/digital_potentiometer.ino new file mode 100644 index 0000000..8830ada --- /dev/null +++ b/STM32F1/libraries/WireSlave/examples/digital_potentiometer/digital_potentiometer.ino @@ -0,0 +1,38 @@ +// I2C Digital Potentiometer +// by Nicholas Zambetti +// and Shawn Bonkowski + +// Demonstrates use of the Wire library +// Controls AD5171 digital potentiometer via I2C/TWI + +// Created 31 March 2006 + +// This example code is in the public domain. + +// This example code is in the public domain. + + +#include + +void setup() +{ + Wire.begin(); // join i2c bus (address optional for master) +} + +byte val = 0; + +void loop() +{ + Wire.beginTransmission(44); // transmit to device #44 (0x2c) + // device address is specified in datasheet + Wire.write(byte(0x00)); // sends instruction byte + Wire.write(val); // sends potentiometer value byte + Wire.endTransmission(); // stop transmitting + + val++; // increment value + if(val == 64) // if reached 64th position (max) + { + val = 0; // start over from lowest value + } + delay(500); +} diff --git a/STM32F1/libraries/WireSlave/examples/i2c_libmaple_slave/i2c_libmaple_slave.ino b/STM32F1/libraries/WireSlave/examples/i2c_libmaple_slave/i2c_libmaple_slave.ino new file mode 100644 index 0000000..23456e4 --- /dev/null +++ b/STM32F1/libraries/WireSlave/examples/i2c_libmaple_slave/i2c_libmaple_slave.ino @@ -0,0 +1,122 @@ +/* +* i2c_slave example.cpp +* +* You can use this sketch in combination with master_writer.pde +* +* Created on: 4 Sep 2012 +* Author: Barry Carter +*/ +#include +#include + +#define USE_BUFFERED_EXAMPLE 1 + +i2c_msg msg; +uint8 buffer[255]; +char* const bufferAsChar = (char*)buffer; // ready type casted alias + +volatile bool newMessage = false; + +void funcrx(i2c_msg *msg __attribute__((unused))){ + // Received length will be in msg->length + newMessage = true; +} + +#if USE_BUFFERED_EXAMPLE == 1 +/* We ARE using a buffer to transmit the data out. +* Make sure you fill the buffer with the data AND you set the length correctly +*/ +void functx(i2c_msg *msg){ + // Cheeky. We are using the received byte of the data which is currently in + // byte 0 to echo it back to the master device + //msg->data[0] = 0x01; // We are re-using the rx buffer here to echo the request back + msg->data[1] = 0x02; + msg->data[2] = 0x03; + msg->data[3] = 0x04; + msg->data[4] = 0x05; + msg->length = 5; +} + +#else + +/* We are NOT using the buffered data transmission +* We will get this callback for each outgoing packet. Make sure to call i2c_write +* Strickly speaking, we should be sending a NACk on the last byte we want to send +* but for this test example I am going to assume the master will NACK it when it +* wants to stop. +*/ +void functx(i2c_msg *msg){ + i2c_write(I2C1, msg->data[0]); +} + +#endif + +// #define Serial Serial1 + +void setup() { + Serial.begin(115200); + while(!Serial) + ; + Serial.println("I2C Slave example"); + + // attach the buffer + msg.data = buffer; + + /* Init slave mode. Enables master too + * We are going to configure the slave device to + * - enable fast I2C (400khz) + * - dual addresses (can have 2 addresses per module) + * general call (accepts data writes to 0x00 on a broadcast basis) + * + * If the buffered example is enabled, then we also enable the + * buffer for rx and tx. + * Note you can independently enable/disable RX and TX buffers to + * allow a buffered read and direct writes. Useful if you don't know how + * much the master will read. + */ + #if USE_BUFFERED_EXAMPLE == 1 + i2c_slave_enable(I2C1, I2C_FAST_MODE | I2C_SLAVE_DUAL_ADDRESS | I2C_SLAVE_GENERAL_CALL | I2C_SLAVE_USE_RX_BUFFER | I2C_SLAVE_USE_TX_BUFFER); + #else + i2c_slave_enable(I2C1, I2C_FAST_MODE | I2C_SLAVE_DUAL_ADDRESS | I2C_SLAVE_GENERAL_CALL); + #endif + + // attach receive handler + i2c_slave_attach_recv_handler(I2C1, &msg, funcrx); + // attach transmit handler + i2c_slave_attach_transmit_handler(I2C1, &msg, functx); + + // set addresss to 4 + i2c_slave_set_own_address(I2C1, 4); +} + +void loop() { + static uint32_t lastMessage = millis(); + + // This is potentially dangerous. + // We're reading from the live buffer, the content can change + // in the middle of Serial.println + + if (newMessage && strlen(bufferAsChar)==6) { + for (int i=0; i<5; i++) { + // Print as char + Serial.print(bufferAsChar[i]); + } + // Print as byte + Serial.println(buffer[5]); + lastMessage = millis(); + newMessage = false; + } else { + if(newMessage && strlen(bufferAsChar)!=6) { + // this also happends on the line "x is 0" + Serial.print("Bad data received:"); + Serial.println(bufferAsChar); + Serial.print("strlen:"); + Serial.println(strlen(bufferAsChar)); + newMessage = false; + } else + if(millis() - lastMessage > 3000){ + Serial.println("Nothing received in 3 seconds."); + lastMessage = millis(); + } + } +} diff --git a/STM32F1/libraries/WireSlave/examples/master_reader/master_reader.ino b/STM32F1/libraries/WireSlave/examples/master_reader/master_reader.ino new file mode 100644 index 0000000..4b45d12 --- /dev/null +++ b/STM32F1/libraries/WireSlave/examples/master_reader/master_reader.ino @@ -0,0 +1,32 @@ +// Wire Master Reader +// by Nicholas Zambetti + +// Demonstrates use of the Wire library +// Reads data from an I2C/TWI slave device +// Refer to the "Wire Slave Sender" example for use with this + +// Created 29 March 2006 + +// This example code is in the public domain. + + +#include + +void setup() +{ + Wire.begin(); // join i2c bus (address optional for master) + Serial.begin(9600); // start serial for output +} + +void loop() +{ + Wire.requestFrom(2, 6); // request 6 bytes from slave device #2 + + while(Wire.available()) // slave may send less than requested + { + char c = Wire.read(); // receive a byte as character + Serial.print(c); // print the character + } + + delay(500); +} diff --git a/STM32F1/libraries/WireSlave/examples/master_writer/master_writer.ino b/STM32F1/libraries/WireSlave/examples/master_writer/master_writer.ino new file mode 100644 index 0000000..f997473 --- /dev/null +++ b/STM32F1/libraries/WireSlave/examples/master_writer/master_writer.ino @@ -0,0 +1,31 @@ +// Wire Master Writer +// by Nicholas Zambetti + +// Demonstrates use of the Wire library +// Writes data to an I2C/TWI slave device +// Refer to the "Wire Slave Receiver" example for use with this + +// Created 29 March 2006 + +// This example code is in the public domain. + + +#include + +void setup() +{ + Wire.begin(); // join i2c bus (address optional for master) +} + +byte x = 0; + +void loop() +{ + Wire.beginTransmission(4); // transmit to device #4 + Wire.write("x is "); // sends five bytes + Wire.write(x); // sends one byte + Wire.endTransmission(); // stop transmitting + + x++; + delay(500); +} diff --git a/STM32F1/libraries/WireSlave/examples/slave_receiver/slave_receiver.ino b/STM32F1/libraries/WireSlave/examples/slave_receiver/slave_receiver.ino new file mode 100644 index 0000000..b430c25 --- /dev/null +++ b/STM32F1/libraries/WireSlave/examples/slave_receiver/slave_receiver.ino @@ -0,0 +1,38 @@ +// Wire Slave Receiver +// by Nicholas Zambetti + +// Demonstrates use of the Wire library +// Receives data as an I2C/TWI slave device +// Refer to the "Wire Master Writer" example for use with this + +// Created 29 March 2006 + +// This example code is in the public domain. + + +#include + +void setup() +{ + Wire.begin(4); // join i2c bus with address #4 + Wire.onReceive(receiveEvent); // register event + Serial.begin(9600); // start serial for output +} + +void loop() +{ + delay(100); +} + +// function that executes whenever data is received from master +// this function is registered as an event, see setup() +void receiveEvent(int howMany) +{ + while(1 < Wire.available()) // loop through all but the last + { + char c = Wire.read(); // receive byte as a character + Serial.print(c); // print the character + } + int x = Wire.read(); // receive byte as an integer + Serial.println(x); // print the integer +} diff --git a/STM32F1/libraries/WireSlave/examples/slave_sender/slave_sender.ino b/STM32F1/libraries/WireSlave/examples/slave_sender/slave_sender.ino new file mode 100644 index 0000000..fcdac14 --- /dev/null +++ b/STM32F1/libraries/WireSlave/examples/slave_sender/slave_sender.ino @@ -0,0 +1,32 @@ +// Wire Slave Sender +// by Nicholas Zambetti + +// Demonstrates use of the Wire library +// Sends data as an I2C/TWI slave device +// Refer to the "Wire Master Reader" example for use with this + +// Created 29 March 2006 + +// This example code is in the public domain. + + +#include + +void setup() +{ + Wire.begin(2); // join i2c bus with address #2 + Wire.onRequest(requestEvent); // register event +} + +void loop() +{ + delay(100); +} + +// function that executes whenever data is requested by master +// this function is registered as an event, see setup() +void requestEvent() +{ + Wire.write("hello "); // respond with message of 6 bytes + // as expected by master +} diff --git a/STM32F1/libraries/WireSlave/library.properties b/STM32F1/libraries/WireSlave/library.properties new file mode 100644 index 0000000..2a1c387 --- /dev/null +++ b/STM32F1/libraries/WireSlave/library.properties @@ -0,0 +1,11 @@ +name=Wire_Slave +version=1.0 +author= +email= +sentence=Wire with slave support +paragraph=Experimental Wire with slave support +url= +architectures=STM32F1 +maintainer= +category=Communication +include=src/Wire_Slave.h diff --git a/STM32F1/libraries/WireSlave/src/Wire.h b/STM32F1/libraries/WireSlave/src/Wire.h new file mode 100644 index 0000000..ede963b --- /dev/null +++ b/STM32F1/libraries/WireSlave/src/Wire.h @@ -0,0 +1 @@ +#error "Something is trying to include Wire_slave.h when Wire.h is already included, they are mutually exclusive" diff --git a/STM32F1/libraries/WireSlave/src/Wire.h.gch b/STM32F1/libraries/WireSlave/src/Wire.h.gch new file mode 100644 index 0000000000000000000000000000000000000000..b29a5ea9fd8851ea75533c42ff77077972caf5ce GIT binary patch literal 1819056 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 z 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≠!FX+RNj++pOJ3nHmv#KU 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

h#jNeg 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 literal 0 HcmV?d00001 diff --git a/STM32F1/libraries/WireSlave/src/Wire_slave.cpp b/STM32F1/libraries/WireSlave/src/Wire_slave.cpp new file mode 100644 index 0000000..93cc55f --- /dev/null +++ b/STM32F1/libraries/WireSlave/src/Wire_slave.cpp @@ -0,0 +1,106 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file TwoWire.cpp + * @author Trystan Jones + * @brief Wire library, uses the hardware I2C available in the Maple to + * interact with I2C slave devices. + */ + +/* + * Library created by crenn to use the new WireBase system and allow Arduino + * users easy interaction with the I2C Hardware in a familiar method. + */ + +#include "Wire_slave.h" + +uint8 TwoWire::process(uint8 stop) { + int8 res = i2c_master_xfer(sel_hard, &itc_msg, 1, 0); + if (res == I2C_ERROR_PROTOCOL) { + if (sel_hard->error_flags & I2C_SR1_AF) { /* NACK */ + res = (sel_hard->error_flags & I2C_SR1_ADDR ? ENACKADDR : + ENACKTRNS); + } else if (sel_hard->error_flags & I2C_SR1_OVR) { /* Over/Underrun */ + res = EDATA; + } else { /* Bus or Arbitration error */ + res = EOTHER; + } + i2c_disable(sel_hard); + i2c_master_enable(sel_hard, (I2C_BUS_RESET | dev_flags)); + } + return res; +} + +uint8 TwoWire::process(){ + return process(true); +} + +// TODO: Add in Error Handling if devsel is out of range for other Maples +TwoWire::TwoWire(uint8 dev_sel, uint8 flags) { + if (dev_sel == 1) { + sel_hard = I2C1; + } else if (dev_sel == 2) { + sel_hard = I2C2; + } else { + ASSERT(1); + } + dev_flags = flags; +} + +TwoWire::~TwoWire() { + i2c_disable(sel_hard); + sel_hard = 0; +} + +void TwoWire::begin(uint8 self_addr) { + i2c_master_enable(sel_hard, dev_flags); +} + +void TwoWire::end() { + i2c_disable(sel_hard); + sel_hard = 0; +} + +void TwoWire::setClock(uint32_t frequencyHz) +{ + switch(frequencyHz) + { + case 400000: + dev_flags |= I2C_FAST_MODE;// set FAST_MODE bit + break; + case 100000: + default: + dev_flags &= ~I2C_FAST_MODE;// clear FAST_MODE bit + break; + } + if (sel_hard->regs->CR1 & I2C_CR1_PE){ + i2c_disable(sel_hard); + i2c_master_enable(sel_hard, dev_flags); + } +} + +TwoWire Wire(1); diff --git a/STM32F1/libraries/WireSlave/src/Wire_slave.h b/STM32F1/libraries/WireSlave/src/Wire_slave.h new file mode 100644 index 0000000..dbe2a4e --- /dev/null +++ b/STM32F1/libraries/WireSlave/src/Wire_slave.h @@ -0,0 +1,78 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file Wire.h + * @author Trystan Jones + * @brief Wire library, uses the hardware I2C available in the Maple to + * interact with I2C slave devices. + */ + +/* + * Library created by crenn to use the new WireBase system and allow Arduino + * users easy interaction with the I2C Hardware in a familiar method. + */ + +#ifndef _TWOWIRE_H_ +#define _TWOWIRE_H_ + +#include "utility/WireBase_slave.h" +#include "wirish.h" +#include + +class TwoWire : public WireBase { +private: + i2c_dev* sel_hard; + uint8 dev_flags; +protected: + /* + * Processes the incoming I2C message defined by WireBase to the + * hardware. If an error occured, restart the I2C device. + */ + uint8 process(uint8); + uint8 process(); +public: + /* + * Check if devsel is within range and enable selected I2C interface with + * passed flags + */ + TwoWire(uint8, uint8 = 0); + + /* + * Shuts down (disables) the hardware I2C + */ + void end(); + + void setClock(uint32_t frequencyHz); + /* + * Disables the I2C device and remove the device address. + */ + ~TwoWire(); + + void begin(uint8 = 0x00); +}; +extern TwoWire Wire; +#endif // _TWOWIRE_H_ diff --git a/STM32F1/libraries/WireSlave/src/Wire_slave.h.gch b/STM32F1/libraries/WireSlave/src/Wire_slave.h.gch new file mode 100644 index 0000000000000000000000000000000000000000..5a6345078e7abad4b9211a296cfa52568e2ed238 GIT binary patch literal 9475 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 Y;dI<1)bAmJrq!61Ti)JEJwtc@2OMIdI{*Lx literal 0 HcmV?d00001 diff --git a/STM32F1/libraries/WireSlave/src/i2c_slave.c b/STM32F1/libraries/WireSlave/src/i2c_slave.c new file mode 100644 index 0000000..770cd3a --- /dev/null +++ b/STM32F1/libraries/WireSlave/src/i2c_slave.c @@ -0,0 +1,789 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/i2c.c + * @author Perry Hung + * @author Barry Carter + * @brief Inter-Integrated Circuit (I2C) support. + * + * Master and Slave supported + * I2C slave support added 2012 by Barry Carter. barry.carter@gmail.com, headfuzz.co.uk + */ + +#include "libmaple/i2c_common_slave.h" + +#include "i2c_private.h" + + +#include "libmaple/i2c_slave.h" +#include +#include +#include +#include +#include + +#include + +static inline int32 wait_for_state_change(i2c_dev *dev, + i2c_state state, + uint32 timeout); +static void set_ccr_trise(i2c_dev *dev, uint32 flags); + +/** + * @brief Fill data register with slave address + * @param dev I2C device + * @param addr Slave address + * @param rw Read/write bit + */ +static inline void i2c_send_slave_addr(i2c_dev *dev, uint32 addr, uint32 rw) { + dev->regs->DR = (addr << 1) | rw; +} + +/* + * Simple debugging trail. Define I2C_DEBUG to turn on. + */ +#ifdef I2C_DEBUG + +#define NR_CRUMBS 128 +static struct crumb crumbs[NR_CRUMBS]; +static uint32 cur_crumb = 0; + +static inline void i2c_drop_crumb(uint32 event, uint32 arg0, uint32 arg1) { + if (cur_crumb < NR_CRUMBS) { + struct crumb *crumb = &crumbs[cur_crumb++]; + crumb->event = event; + crumb->arg0 = arg0; + crumb->arg1 = arg1; + } +} +#define I2C_CRUMB(event, arg0, arg1) i2c_drop_crumb(event, arg0, arg1) + +#else +#define I2C_CRUMB(event, arg0, arg1) +#endif + +struct crumb { + uint32 event; + uint32 arg0; + uint32 arg1; +}; + +enum { + IRQ_ENTRY = 1, + TXE_ONLY = 2, + TXE_BTF = 3, + STOP_SENT = 4, + TEST = 5, + RX_ADDR_START = 6, + RX_ADDR_STOP = 7, + RXNE_ONLY = 8, + RXNE_SENDING = 9, + RXNE_START_SENT = 10, + RXNE_STOP_SENT = 11, + RXNE_DONE = 12, + ERROR_ENTRY = 13, +}; + +/** + * @brief Reset an I2C bus. + * + * Reset is accomplished by clocking out pulses until any hung slaves + * release SDA and SCL, then generating a START condition, then a STOP + * condition. + * + * @param dev I2C device + */ +void i2c_bus_reset(const i2c_dev *dev) { + /* Release both lines */ + i2c_master_release_bus(dev); + + /* + * Make sure the bus is free by clocking it until any slaves release the + * bus. + */ + while (!gpio_read_bit(sda_port(dev), dev->sda_pin)) { + /* Wait for any clock stretching to finish */ + while (!gpio_read_bit(scl_port(dev), dev->scl_pin)) + ; + delay_us(10); + + /* Pull low */ + gpio_write_bit(scl_port(dev), dev->scl_pin, 0); + delay_us(10); + + /* Release high again */ + gpio_write_bit(scl_port(dev), dev->scl_pin, 1); + delay_us(10); + } + + /* Generate start then stop condition */ + gpio_write_bit(sda_port(dev), dev->sda_pin, 0); + delay_us(10); + gpio_write_bit(scl_port(dev), dev->scl_pin, 0); + delay_us(10); + gpio_write_bit(scl_port(dev), dev->scl_pin, 1); + delay_us(10); + gpio_write_bit(sda_port(dev), dev->sda_pin, 1); +} + +/** + * @brief Initialize an I2C device and reset its registers to their + * default values. + * @param dev Device to initialize. + */ +void i2c_init(i2c_dev *dev) { + rcc_reset_dev(dev->clk_id); + rcc_clk_enable(dev->clk_id); + _i2c_irq_priority_fixup(dev); +} + +/* Hack for deprecated bit of STM32F1 functionality */ +#ifndef _I2C_HAVE_DEPRECATED_I2C_REMAP +#define _i2c_handle_remap(dev, flags) ((void)0) +#endif + +/** + * @brief Initialize an I2C device as bus master + * @param dev Device to enable + * @param flags Bitwise or of the following I2C options: + * I2C_FAST_MODE: 400 khz operation, + * I2C_DUTY_16_9: 16/9 Tlow/Thigh duty cycle (only applicable for + * fast mode), + * I2C_BUS_RESET: Reset the bus and clock out any hung slaves on + * initialization, + * I2C_10BIT_ADDRESSING: Enable 10-bit addressing, + * I2C_REMAP: (deprecated, STM32F1 only) Remap I2C1 to SCL/PB8 + * SDA/PB9. + */ +void i2c_master_enable(i2c_dev *dev, uint32 flags) { + /* PE must be disabled to configure the device */ + ASSERT(!(dev->regs->CR1 & I2C_CR1_PE)); + + /* Ugh */ + _i2c_handle_remap(dev, flags); + + /* Reset the bus. Clock out any hung slaves. */ + if (flags & I2C_BUS_RESET) { + i2c_bus_reset(dev); + } + + /* Turn on clock and set GPIO modes */ + i2c_init(dev); + i2c_config_gpios(dev); + + /* Configure clock and rise time */ + set_ccr_trise(dev, flags); + + /* Enable event and buffer interrupts */ + nvic_irq_enable(dev->ev_nvic_line); + nvic_irq_enable(dev->er_nvic_line); + i2c_enable_irq(dev, I2C_IRQ_EVENT | I2C_IRQ_BUFFER | I2C_IRQ_ERROR); + + /* Configure the slave unit */ + if (flags & I2C_SLAVE_DUAL_ADDRESS) { + i2c_slave_dual_address_enable(dev); + } + + if (flags & I2C_SLAVE_GENERAL_CALL) { + i2c_slave_general_call_enable(dev); + } + + /* store all of the flags */ + dev->config_flags = flags; + + /* Make it go! */ + i2c_peripheral_enable(dev); + i2c_enable_ack(dev); + + dev->state = I2C_STATE_IDLE; +} + +/** + * @brief Initialize an I2C device as slave (and master) + * @param dev Device to enable + * @param flags Bitwise or of the following I2C options: + * I2C_FAST_MODE: 400 khz operation, + * I2C_DUTY_16_9: 16/9 Tlow/Thigh duty cycle (only applicable for + * fast mode), + * I2C_BUS_RESET: Reset the bus and clock out any hung slaves on + * initialization, + * I2C_10BIT_ADDRESSING: Enable 10-bit addressing, + * I2C_REMAP: (deprecated, STM32F1 only) Remap I2C1 to SCL/PB8 + * SDA/PB9. + * I2C_SLAVE_DUAL_ADDRESS: Slave can respond on 2 i2C addresses + * I2C_SLAVE_GENERAL_CALL: SLA+W broadcast to all general call + * listeners on bus. Addr 0x00 + * I2C_SLAVE_USE_RX_BUFFER: Use a buffer to receive the incoming + * data. Callback at end of recv + * I2C_SLAVE_USE_TX_BUFFER: Use a buffer to transmit data. + * Callback will be called before tx + */ +void i2c_slave_enable(i2c_dev *dev, uint32 flags) { + i2c_disable(dev); + i2c_master_enable(dev, dev->config_flags | flags); +} + +/** + * @brief Process an i2c transaction. + * + * Transactions are composed of one or more i2c_msg's, and may be read + * or write tranfers. Multiple i2c_msg's will generate a repeated + * start in between messages. + * + * @param dev I2C device + * @param msgs Messages to send/receive + * @param num Number of messages to send/receive + * @param timeout Bus idle timeout in milliseconds before aborting the + * transfer. 0 denotes no timeout. + * @return 0 on success, + * I2C_ERROR_PROTOCOL if there was a protocol error, + * I2C_ERROR_TIMEOUT if the transfer timed out. + */ +int32 i2c_master_xfer(i2c_dev *dev, + i2c_msg *msgs, + uint16 num, + uint32 timeout) { + int32 rc; + + ASSERT(dev->state == I2C_STATE_IDLE); + + dev->msg = msgs; + dev->msgs_left = num; + dev->timestamp = systick_uptime(); + dev->state = I2C_STATE_BUSY; + + i2c_enable_irq(dev, I2C_IRQ_EVENT); + i2c_start_condition(dev); + + rc = wait_for_state_change(dev, I2C_STATE_XFER_DONE, timeout); + if (rc < 0) { + goto out; + } + + dev->state = I2C_STATE_IDLE; +out: + return rc; +} + +/** + * @brief Wait for an I2C event, or time out in case of error. + * @param dev I2C device + * @param state I2C_state state to wait for + * @param timeout Timeout, in milliseconds + * @return 0 if target state is reached, a negative value on error. + */ +static inline int32 wait_for_state_change(i2c_dev *dev, + i2c_state state, + uint32 timeout) { + i2c_state tmp; + + while (1) { + tmp = dev->state; + + if (tmp == I2C_STATE_ERROR) { + return I2C_STATE_ERROR; + } + + if (tmp == state) { + return 0; + } + + if (timeout) { + if (systick_uptime() > (dev->timestamp + timeout)) { + /* TODO: overflow? */ + /* TODO: racy? */ + return I2C_ERROR_TIMEOUT; + } + } + } +} + +/* + * Private API + */ + +/* + * IRQ handler for I2C master. Handles transmission/reception. + */ +void _i2c_irq_handler(i2c_dev *dev) { + /* WTFs: + * - Where is I2C_MSG_10BIT_ADDR handled? + */ + i2c_msg *msg = dev->msg; + + uint8 read = msg->flags & I2C_MSG_READ; + + uint32 sr1 = dev->regs->SR1; + uint32 sr2 = dev->regs->SR2; + I2C_CRUMB(IRQ_ENTRY, sr1, sr2); + + /* + * Reset timeout counter + */ + dev->timestamp = systick_uptime(); + + /* + * Add Slave support + */ + + /* Check to see if MSL master slave bit is set */ + if ((sr2 & I2C_SR2_MSL) != I2C_SR2_MSL) { /* 0 = slave mode 1 = master */ + + /* Check for address match */ + if (sr1 & I2C_SR1_ADDR) { + /* Find out which address was matched */ + /* Check the general call address first */ + if (sr2 & I2C_SR2_GENCALL) { + dev->i2c_slave_msg->addr = 0; + } + /* We matched the secondary address */ + else if (sr2 & I2C_SR2_DUALF) { + dev->i2c_slave_msg->addr = dev->regs->OAR2 & 0xFE; + } + /* We matched the primary address */ + else if ((sr2 & I2C_SR2_DUALF) != I2C_SR2_DUALF) { + dev->i2c_slave_msg->addr = dev->regs->OAR1 & 0xFE; + } + /* Shouldn't get here */ + else { + dev->i2c_slave_msg->addr = -1; /* uh oh */ + } + + /* if we have buffered io */ + if ((dev->config_flags & I2C_SLAVE_USE_RX_BUFFER) || + (dev->config_flags & I2C_SLAVE_USE_TX_BUFFER)) { + + /* if receiving then this would be a repeated start + * + *if we have some bytes already + */ + if ((dev->state == I2C_STATE_SL_RX) && + (dev->i2c_slave_msg->xferred > 0) && + (dev->config_flags & I2C_SLAVE_USE_RX_BUFFER)) { + /* Call the callback with the contents of the data */ + if (dev->i2c_slave_recv_callback != NULL) { + (*(dev->i2c_slave_recv_callback))(dev->i2c_slave_msg); + } + } + + /* Reset the message back to defaults. + * We are starting a new message + */ + dev->i2c_slave_msg->flags = 0; + dev->i2c_slave_msg->length = 0; + dev->i2c_slave_msg->xferred = 0; + dev->msgs_left = 0; + dev->timestamp = systick_uptime(); + + /* We have been addressed with SLA+R so + * the master wants us to transmit + */ + if ((sr1 & I2C_SR1_TXE) && + (dev->config_flags & I2C_SLAVE_USE_TX_BUFFER)) { + /* Call the transmit callback so it can populate the msg + * data with the bytes to go + */ + if (dev->i2c_slave_transmit_callback != NULL) { + (*(dev->i2c_slave_transmit_callback))(dev->i2c_slave_msg); + } + } + dev->state = I2C_STATE_BUSY; + } + + sr1 = sr2 = 0; + } + + /* EV3: Master requesting data from slave. Transmit a byte*/ + if (sr1 & I2C_SR1_TXE) { + if (dev->config_flags & I2C_SLAVE_USE_TX_BUFFER) { + if (dev->i2c_slave_msg->xferred >= dev->i2c_slave_msg->length) { + /* End of the transmit buffer? If so we NACK */ + i2c_disable_ack(dev); + /* We have to either issue a STOP or write something here. + * STOP here seems to screw up some masters, + * For now padding with 0 + */ + i2c_write(dev, 0); + /*i2c_stop_condition(dev); // This is causing bus lockups way more than it should !? Seems some I2C master devices freak out here*/ + } + else + { + /* NACk the last byte */ + if (dev->i2c_slave_msg->xferred == dev->i2c_slave_msg->length-1) { + i2c_disable_ack(dev); + } + else { + i2c_enable_ack(dev); + } + i2c_write(dev, dev->i2c_slave_msg->data[dev->i2c_slave_msg->xferred++]); + } + } + else + { + /* Call the callback to get the data we need. + * The callback is expected to write using i2c_write(...) + * If the slave is going to terminate the transfer, this function should + * also do a NACK on the last byte! + */ + if (dev->i2c_slave_transmit_callback != NULL) (*(dev->i2c_slave_transmit_callback))(dev->i2c_slave_msg); + } + + dev->state = I2C_STATE_BUSY; + sr1 = sr2 = 0; + } + + /* EV2: Slave received data from a master. Get from DR */ + if (sr1 & I2C_SR1_RXNE) { + if (dev->config_flags & I2C_SLAVE_USE_RX_BUFFER) { + /* Fill the buffer with the contents of the data register */ + /* These is potential for buffer overflow here, so we should + * really store the size of the array. This is expensive in + * the ISR so left out for now. We must trust the implementor! + */ + dev->i2c_slave_msg->data[dev->i2c_slave_msg->xferred++] = dev->regs->DR; + dev->i2c_slave_msg->length++; + } + else { + /* Call the callback with the contents of the data */ + dev->i2c_slave_msg->data[0] = dev->regs->DR; + if (dev->i2c_slave_recv_callback != NULL) (*(dev->i2c_slave_recv_callback))(dev->i2c_slave_msg); + } + dev->state = I2C_STATE_SL_RX; + sr1 = sr2 = 0; + } + + /* EV4: Slave has detected a STOP condition on the bus */ + if (sr1 & I2C_SR1_STOPF) { + dev->regs->CR1 |= I2C_CR1_PE; + + if ((dev->config_flags & I2C_SLAVE_USE_RX_BUFFER) || + (dev->config_flags & I2C_SLAVE_USE_TX_BUFFER)) { + + /* The callback with the data will happen on a NACK of the last data byte. + * This is handled in the error IRQ (AF bit) + */ + /* Handle the case where the master misbehaves by sending no NACK */ + if (dev->state != I2C_STATE_IDLE) { + if (dev->state == I2C_STATE_SL_RX) { + if (dev->i2c_slave_recv_callback != NULL) (*(dev->i2c_slave_recv_callback))(dev->i2c_slave_msg); + } + else { + if (dev->i2c_slave_transmit_callback != NULL) (*(dev->i2c_slave_transmit_callback))(dev->i2c_slave_msg); + } + } + } + + sr1 = sr2 = 0; + dev->state = I2C_STATE_IDLE; + } + + return; + } + + /* + * EV5: Start condition sent + */ + if (sr1 & I2C_SR1_SB) { + msg->xferred = 0; + i2c_enable_irq(dev, I2C_IRQ_BUFFER); + + /* + * Master receiver + */ + if (read) { + i2c_enable_ack(dev); + } + + i2c_send_slave_addr(dev, msg->addr, read); + sr1 = sr2 = 0; + } + + /* + * EV6: Slave address sent + */ + if (sr1 & I2C_SR1_ADDR) { + /* + * Special case event EV6_1 for master receiver. + * Generate NACK and restart/stop condition after ADDR + * is cleared. + */ + if (read) { + if (msg->length == 1) { + i2c_disable_ack(dev); + if (dev->msgs_left > 1) { + i2c_start_condition(dev); + I2C_CRUMB(RX_ADDR_START, 0, 0); + } else { + i2c_stop_condition(dev); + I2C_CRUMB(RX_ADDR_STOP, 0, 0); + } + } + } else { + /* + * Master transmitter: write first byte to fill shift + * register. We should get another TXE interrupt + * immediately to fill DR again. + */ + if (msg->length > 1) { + i2c_write(dev, msg->data[msg->xferred++]); + } else if (msg->length == 0) { /* We're just sending an address */ + i2c_stop_condition(dev); + /* + * Turn off event interrupts to keep BTF from firing until + * the end of the stop condition. Why on earth they didn't + * have a start/stop condition request clear BTF is beyond + * me. + */ + i2c_disable_irq(dev, I2C_IRQ_EVENT); + I2C_CRUMB(STOP_SENT, 0, 0); + dev->state = I2C_STATE_XFER_DONE; + } /* else we're just sending one byte */ + } + sr1 = sr2 = 0; + } + + /* + * EV8: Master transmitter + * Transmit buffer empty, but we haven't finished transmitting the last + * byte written. + */ + if ((sr1 & I2C_SR1_TXE) && !(sr1 & I2C_SR1_BTF)) { + I2C_CRUMB(TXE_ONLY, 0, 0); + if (dev->msgs_left) { + i2c_write(dev, msg->data[msg->xferred++]); + if (msg->xferred == msg->length) { + /* + * End of this message. Turn off TXE/RXNE and wait for + * BTF to send repeated start or stop condition. + */ + i2c_disable_irq(dev, I2C_IRQ_BUFFER); + dev->msgs_left--; + } + } else { + /* + * This should be impossible... + */ + ASSERT(0); + } + sr1 = sr2 = 0; + } + + /* + * EV8_2: Master transmitter + * Last byte sent, program repeated start/stop + */ + if ((sr1 & I2C_SR1_TXE) && (sr1 & I2C_SR1_BTF)) { + I2C_CRUMB(TXE_BTF, 0, 0); + if (dev->msgs_left) { + I2C_CRUMB(TEST, 0, 0); + /* + * Repeated start insanity: We can't disable ITEVTEN or else SB + * won't interrupt, but if we don't disable ITEVTEN, BTF will + * continually interrupt us. What the fuck ST? + */ + i2c_start_condition(dev); + while (!(dev->regs->SR1 & I2C_SR1_SB)) + ; + dev->msg++; + } else { + i2c_stop_condition(dev); + + /* + * Turn off event interrupts to keep BTF from firing until + * the end of the stop condition. Why on earth they didn't + * have a start/stop condition request clear BTF is beyond + * me. + */ + i2c_disable_irq(dev, I2C_IRQ_EVENT); + I2C_CRUMB(STOP_SENT, 0, 0); + dev->state = I2C_STATE_XFER_DONE; + } + sr1 = sr2 = 0; + } + + /* + * EV7: Master Receiver + */ + if (sr1 & I2C_SR1_RXNE) { + I2C_CRUMB(RXNE_ONLY, 0, 0); + msg->data[msg->xferred++] = dev->regs->DR; + + /* + * EV7_1: Second to last byte in the reception? Set NACK and generate + * stop/restart condition in time for the last byte. We'll get one more + * RXNE interrupt before shutting things down. + */ + if (msg->xferred == (msg->length - 1)) { + i2c_disable_ack(dev); + if (dev->msgs_left > 2) { + i2c_start_condition(dev); + I2C_CRUMB(RXNE_START_SENT, 0, 0); + } else { + i2c_stop_condition(dev); + I2C_CRUMB(RXNE_STOP_SENT, 0, 0); + } + } else if (msg->xferred == msg->length) { + dev->msgs_left--; + if (dev->msgs_left == 0) { + /* + * We're done. + */ + I2C_CRUMB(RXNE_DONE, 0, 0); + dev->state = I2C_STATE_XFER_DONE; + } else { + dev->msg++; + } + } + } +} + +/* + * Interrupt handler for I2C error conditions. Aborts any pending I2C + * transactions. + */ +void _i2c_irq_error_handler(i2c_dev *dev) { + I2C_CRUMB(ERROR_ENTRY, dev->regs->SR1, dev->regs->SR2); + + dev->error_flags = dev->regs->SR1 & (I2C_SR1_BERR | + I2C_SR1_ARLO | + I2C_SR1_AF | + I2C_SR1_OVR); + + /* Are we in slave mode? */ + if ((dev->regs->SR2 & I2C_SR2_MSL) != I2C_SR2_MSL) { + /* Check to see if the master device did a NAK on the last bit + * This is perfectly valid for a master to do this on the bus. + * We ignore this. Any further error processing takes us into dead + * loop waiting for the stop condition that will never arrive + */ + if (dev->regs->SR1 & I2C_SR1_AF) { + /* Clear flags */ + dev->regs->SR1 = 0; + dev->regs->SR2 = 0; + /* We need to write something to CR1 to clear the flag. + * This isn't really mentioned but seems important */ + i2c_enable_ack(dev); + + if (dev->state == I2C_STATE_SL_RX && + dev->config_flags & I2C_SLAVE_USE_RX_BUFFER && + dev->i2c_slave_msg->xferred > 0) { + /* Call the callback with the contents of the data */ + if (dev->i2c_slave_recv_callback != NULL) (*(dev->i2c_slave_recv_callback))(dev->i2c_slave_msg); + } + + dev->state = I2C_STATE_IDLE; + return; + } + /* Catch any other strange errors while in slave mode. + * I have seen BERR caused by an over fast master device + * as well as several overflows and arbitration failures. + * We are going to reset SR flags and carry on at this point which + * is not the best thing to do, but stops the bus locking up completely + * If we carry on below and send the stop bit, the code spins forever */ + /* Clear flags */ + dev->regs->SR1 = 0; + dev->regs->SR2 = 0; + dev->state = I2C_STATE_IDLE; + return; + } + + /* Clear flags */ + dev->regs->SR1 = 0; + dev->regs->SR2 = 0; + + i2c_stop_condition(dev); + i2c_disable_irq(dev, I2C_IRQ_BUFFER | I2C_IRQ_EVENT | I2C_IRQ_ERROR); + dev->state = I2C_STATE_ERROR; +} + +/* + * CCR/TRISE configuration helper + */ +static void set_ccr_trise(i2c_dev *dev, uint32 flags) { + uint32 ccr = 0; + uint32 trise = 0; + uint32 clk_mhz = _i2c_bus_clk(dev); + uint32 clk_hz = clk_mhz * (1000 * 1000); + + i2c_set_input_clk(dev, clk_mhz); + + if (flags & I2C_FAST_MODE) { + ccr |= I2C_CCR_FS; + + if (flags & I2C_DUTY_16_9) { + /* Tlow/Thigh = 16/9 */ + ccr |= I2C_CCR_DUTY_16_9; + ccr |= clk_hz / (400000 * 25); + } else { + /* Tlow/Thigh = 2 */ + ccr |= clk_hz / (400000 * 3); + } + + trise = (300 * clk_mhz / 1000) + 1; + } else { + /* Tlow/Thigh = 1 */ + ccr = clk_hz / (100000 * 2); + trise = clk_mhz + 1; + } + + /* Set minimum required value if CCR < 1*/ + if ((ccr & I2C_CCR_CCR) == 0) { + ccr |= 0x1; + } + + i2c_set_clk_control(dev, ccr); + i2c_set_trise(dev, trise); +} + + +/** + * @brief callback for when the device acts as a slave. If using an rx buffer, this is triggered + * after the last byte, otherwise it is called for every incoming packet. + * @param dev I2C device + * @param msg The dev_msg to pass to the slave init code + * @param func The function pointer to call + */ +void i2c_slave_attach_recv_handler(i2c_dev *dev, i2c_msg *msg, i2c_slave_recv_callback_func func) { + dev->i2c_slave_recv_callback = func; + dev->i2c_slave_msg = msg; + msg->xferred = 0; +} + + +/** + * @brief callback for when the device acts as a slave. If using a tx buffer, this is triggered + * after the device is successsfully addressed with SLA+R. + * @param dev I2C device + * @param msg The dev_msg to pass to the slave init code + * @param func The function pointer to call + */ +void i2c_slave_attach_transmit_handler(i2c_dev *dev, i2c_msg *msg, i2c_slave_transmit_callback_func func) { + dev->i2c_slave_transmit_callback = func; + dev->i2c_slave_msg = msg; + msg->xferred = 0; +} diff --git a/STM32F1/libraries/WireSlave/src/i2c_slave.h.gch b/STM32F1/libraries/WireSlave/src/i2c_slave.h.gch new file mode 100644 index 0000000000000000000000000000000000000000..5a6345078e7abad4b9211a296cfa52568e2ed238 GIT binary patch literal 9475 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 Y;dI<1)bAmJrq!61Ti)JEJwtc@2OMIdI{*Lx literal 0 HcmV?d00001 diff --git a/STM32F1/libraries/WireSlave/src/libmaple/i2c_common_slave.h b/STM32F1/libraries/WireSlave/src/libmaple/i2c_common_slave.h new file mode 100644 index 0000000..605c663 --- /dev/null +++ b/STM32F1/libraries/WireSlave/src/libmaple/i2c_common_slave.h @@ -0,0 +1,110 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung (from ). + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/i2c_common.h + * @author Marti Bolivar + * @brief This file is an implementation detail + * + * CONTENTS UNSTABLE. The existence of this file is an implementation + * detail. Never include it directly. If you need something from + * here, include instead. + * + * I2C slave support added 2012 by Barry Carter. barry.carter@gmail.com, headfuzz.co.uk + * + */ + +#ifndef _LIBMAPLE_I2C_COMMON_H_ +#define _LIBMAPLE_I2C_COMMON_H_ + +#include +#include +#include + +struct gpio_dev; +struct i2c_reg_map; +struct i2c_msg; + +/** I2C device states */ +typedef enum i2c_state { + I2C_STATE_DISABLED = 0, /**< Disabled */ + I2C_STATE_IDLE = 1, /**< Idle */ + I2C_STATE_XFER_DONE = 2, /**< Done with transfer */ + I2C_STATE_BUSY = 3, /**< Busy */ + I2C_STATE_SL_RX = 4, /**< Slave receiving */ + I2C_STATE_ERROR = -1 /**< Error occurred */ +} i2c_state; + +typedef void (*i2c_slave_recv_callback_func)(struct i2c_msg *); +typedef void (*i2c_slave_transmit_callback_func)(struct i2c_msg *); +/** + * @brief I2C device type. + */ +typedef struct i2c_dev { + struct i2c_reg_map *regs; /**< Register map */ + struct i2c_msg *msg; /**< Messages */ + uint32 error_flags; /**< Error flags, set on I2C error condition */ + volatile uint32 timestamp; /**< For internal use */ + + /** + * @brief Deprecated. Use .scl_port or .sda_port instead. + * If non-null, this will be used as SDA, SCL pins' GPIO port. If + * null, then .sda_port will be used for SDA, and .sda_port for + * SDA. */ + struct gpio_dev *gpio_port; + + /** + * @brief SDA GPIO device (but see .gpio_port). + */ + struct gpio_dev *sda_port; + + /** + * @brief SCL GPIO device (but see .gpio_port). + */ + struct gpio_dev *scl_port; + + uint16 msgs_left; /**< Messages left */ + uint8 sda_pin; /**< SDA bit on gpio_port */ + uint8 scl_pin; /**< SCL bit on gpio_port */ + rcc_clk_id clk_id; /**< RCC clock information */ + nvic_irq_num ev_nvic_line; /**< Event IRQ number */ + nvic_irq_num er_nvic_line; /**< Error IRQ number */ + volatile i2c_state state; /**< Device state */ + uint32 config_flags; /**< Configuration flags */ + + /* + * Slave implementation. Callback functions in this struct allow + * for a separate callback function for each I2C unit available onboard + */ + i2c_slave_transmit_callback_func i2c_slave_transmit_callback; + i2c_slave_recv_callback_func i2c_slave_recv_callback; + + struct i2c_msg *i2c_slave_msg; /* the message that the i2c slave will use */ + +} i2c_dev; + +#endif diff --git a/STM32F1/libraries/WireSlave/src/libmaple/i2c_slave.h b/STM32F1/libraries/WireSlave/src/libmaple/i2c_slave.h new file mode 100644 index 0000000..1f290c2 --- /dev/null +++ b/STM32F1/libraries/WireSlave/src/libmaple/i2c_slave.h @@ -0,0 +1,475 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/i2c.h + * @brief Inter-Integrated Circuit (I2C) peripheral support + * + * Supports Master and Slave. + * Master Usage notes: + * + * - Enable an I2C device with i2c_master_enable(). + * - Initialize an array of struct i2c_msg to suit the bus + * transactions (reads/writes) you wish to perform. + * - Call i2c_master_xfer() to do the work. + * + * Slave Usage notes: + * - Enable I2C slave by calling i2c_slave_enable(). + * Check flags for usage. Enabling master also enabled slave. + * - initialise the i2c_msg struct and the data buffer + * - initialise the callback functions + * + * I2C slave support added 2012 by Barry Carter. barry.carter@gmail.com, headfuzz.co.uk + */ + +#ifndef _LIBMAPLE_I2C_H_ +#define _LIBMAPLE_I2C_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Series header must provide: + * + * - uint32 _i2c_bus_clk(i2c_dev*): Clock frequency of dev's bus, in + * MHz. (This is for internal use only). + * + * - (optional) _I2C_HAVE_IRQ_FIXUP: Leave undefined, or define to 1. + * This is for internal use only. It's a hack to work around a + * silicon bug related to I2C IRQ pre-emption on some targets. If 1, + * the series header must also declare and implement a routine with + * this signature (it may also be provided as a macro): + * + * void _i2c_irq_priority_fixup(i2c_dev*) + * + * This will be called by i2c_enable_irq() before actually enabling + * I2C interrupts. + * + * - Reg. map base pointers, device pointer declarations. + */ + + /* Roger clark. Replaced with line below #include */ +#include "libmaple/i2c_common_slave.h" +#include "stm32f1/include/series/i2c.h" + +#include +#include +#include +#include + +/** I2C register map type */ +typedef struct i2c_reg_map { + __io uint32 CR1; /**< Control register 1 */ + __io uint32 CR2; /**< Control register 2 */ + __io uint32 OAR1; /**< Own address register 1 */ + __io uint32 OAR2; /**< Own address register 2 */ + __io uint32 DR; /**< Data register */ + __io uint32 SR1; /**< Status register 1 */ + __io uint32 SR2; /**< Status register 2 */ + __io uint32 CCR; /**< Clock control register */ + __io uint32 TRISE; /**< TRISE (rise time) register */ +} i2c_reg_map; + +/** + * @brief I2C message type + */ +typedef struct i2c_msg { + uint16 addr; /**< Address */ + +#define I2C_MSG_READ 0x1 +#define I2C_MSG_10BIT_ADDR 0x2 + /** + * Bitwise OR of: + * - I2C_MSG_READ (write is default) + * - I2C_MSG_10BIT_ADDR (7-bit is default) */ + uint16 flags; + + uint16 length; /**< Message length */ + uint16 xferred; /**< Messages transferred */ + uint8 *data; /**< Data */ +} i2c_msg; + +/* + * Register bit definitions + */ + +/* Control register 1 */ + +#define I2C_CR1_SWRST (1U << 15) // Software reset +#define I2C_CR1_ALERT (1U << 13) // SMBus alert +#define I2C_CR1_PEC (1U << 12) // Packet error checking +#define I2C_CR1_POS (1U << 11) // Acknowledge/PEC position +#define I2C_CR1_ACK (1U << 10) // Acknowledge enable +#define I2C_CR1_STOP (1U << 9) // Stop generation +#define I2C_CR1_START (1U << 8) // Start generation +#define I2C_CR1_NOSTRETCH (1U << 7) // Clock stretching disable +#define I2C_CR1_ENGC (1U << 6) // General call enable +#define I2C_CR1_ENPEC (1U << 5) // PEC enable +#define I2C_CR1_ENARP (1U << 4) // ARP enable +#define I2C_CR1_SMBTYPE (1U << 3) // SMBus type +#define I2C_CR1_SMBTYPE_DEVICE (0U << 3) // SMBus type: device +#define I2C_CR1_SMBTYPE_HOST (1U << 3) // SMBus type: host +#define I2C_CR1_SMBUS (1U << 1) // SMBus mode +#define I2C_CR1_SMBUS_I2C (0U << 1) // SMBus mode: I2C +#define I2C_CR1_SMBUS_SMBUS (1U << 1) // SMBus mode: SMBus +#define I2C_CR1_PE (1U << 0) // Peripheral Enable + +/* Control register 2 */ + +#define I2C_CR2_LAST (1U << 12) // DMA last transfer +#define I2C_CR2_DMAEN (1U << 11) // DMA requests enable +#define I2C_CR2_ITBUFEN (1U << 10) // Buffer interrupt enable +#define I2C_CR2_ITEVTEN (1U << 9) // Event interupt enable +#define I2C_CR2_ITERREN (1U << 8) // Error interupt enable +#define I2C_CR2_FREQ 0x3F // Peripheral input frequency + +/* Own address register 1 */ + +#define I2C_OAR1_ADDMODE (1U << 15) // Addressing mode +#define I2C_OAR1_ADDMODE_7_BIT (0U << 15) // Addressing mode: 7-bit +#define I2C_OAR1_ADDMODE_10_BIT (1U << 15) // Addressing mode: 10-bit +#define I2C_OAR1_ADD 0x3FF // Interface address + +/* Own address register 2 */ + +#define I2C_OAR2_ADD2 0xFE // Interface address +#define I2C_OAR2_ENDUAL 1U // Dual addressing mode enable + +/* Status register 1 */ + +#define I2C_SR1_SMBALERT (1U << 15) // SMBus alert +#define I2C_SR1_TIMEOUT (1U << 14) // Timeout or Tlow error +#define I2C_SR1_PECERR (1U << 12) // PEC Error in reception +#define I2C_SR1_OVR (1U << 11) // Overrun/underrun +#define I2C_SR1_AF (1U << 10) // Acknowledge failure +#define I2C_SR1_ARLO (1U << 9) // Arbitration lost +#define I2C_SR1_BERR (1U << 8) // Bus error +#define I2C_SR1_TXE (1U << 7) // Data register empty +#define I2C_SR1_RXNE (1U << 6) // Data register not empty +#define I2C_SR1_STOPF (1U << 4) // Stop detection +#define I2C_SR1_ADD10 (1U << 3) // 10-bit header sent +#define I2C_SR1_BTF (1U << 2) // Byte transfer finished +#define I2C_SR1_ADDR (1U << 1) // Address sent/matched +#define I2C_SR1_SB (1U << 0) // Start bit + +/* Status register 2 */ + +#define I2C_SR2_PEC 0xFF00 // Packet error checking register +#define I2C_SR2_DUALF (1U << 7) // Dual flag +#define I2C_SR2_SMBHOST (1U << 6) // SMBus host header +#define I2C_SR2_SMBDEFAULT (1U << 5) // SMBus device default address +#define I2C_SR2_GENCALL (1U << 4) // General call address +#define I2C_SR2_TRA (1U << 2) // Transmitter/receiver +#define I2C_SR2_BUSY (1U << 1) // Bus busy +#define I2C_SR2_MSL (1U << 0) // Master/slave + +/* Clock control register */ + +#define I2C_CCR_FS (1U << 15) // Fast mode selection +#define I2C_CCR_DUTY (1U << 14) // Fast mode duty cycle +#define I2C_CCR_DUTY_2_1 (0U << 14) // Fast mode duty: 2/1 +#define I2C_CCR_DUTY_16_9 (1U << 14) // Fast mode duty: 16/9 +#define I2C_CCR_CCR 0xFFF // Clock control bits + +/* + * Convenience routines + */ + +/* Main I2C API */ + +/* I2C enable options */ +#define I2C_FAST_MODE 0x1 // 400 khz +#define I2C_DUTY_16_9 0x2 // 16/9 duty ratio +/* Flag 0x4 is reserved; DO NOT USE. */ +#define I2C_BUS_RESET 0x8 // Perform a bus reset +#define I2C_SLAVE_USE_RX_BUFFER 0x10 // Use a buffered message when doing a slave recv +#define I2C_SLAVE_USE_TX_BUFFER 0x20 // Use a buffered message when doing a slave transmit +#define I2C_SLAVE_DUAL_ADDRESS 0x40 // Enable the dual slave address scheme +#define I2C_SLAVE_GENERAL_CALL 0x80 // Enable the general call on address 0x00 +void i2c_master_enable(i2c_dev *dev, uint32 flags); +void i2c_slave_enable(i2c_dev *dev, uint32 flags); + +#define I2C_ERROR_PROTOCOL (-1) +#define I2C_ERROR_TIMEOUT (-2) +int32 i2c_master_xfer(i2c_dev *dev, i2c_msg *msgs, uint16 num, uint32 timeout); + +void i2c_bus_reset(const i2c_dev *dev); + +/** + * @brief Disable an I2C device + * + * This function disables the corresponding peripheral and marks dev's + * state as I2C_STATE_DISABLED. + * + * @param dev Device to disable. + */ +static inline void i2c_disable(i2c_dev *dev) { + dev->regs->CR1 &= ~I2C_CR1_PE; + dev->state = I2C_STATE_DISABLED; +} + +/* Start/stop conditions */ + +/** + * @brief Generate a start condition on the bus. + * @param dev I2C device + */ +static inline void i2c_start_condition(i2c_dev *dev) { + uint32 cr1; + while ((cr1 = dev->regs->CR1) & (I2C_CR1_START | + I2C_CR1_STOP | + I2C_CR1_PEC)) { + ; + } + dev->regs->CR1 |= I2C_CR1_START; +} + +/** + * @brief Generate a stop condition on the bus + * @param dev I2C device + */ +static inline void i2c_stop_condition(i2c_dev *dev) { + uint32 cr1; + while ((cr1 = dev->regs->CR1) & (I2C_CR1_START | + I2C_CR1_STOP | + I2C_CR1_PEC)) { + ; + } + dev->regs->CR1 |= I2C_CR1_STOP; + while ((cr1 = dev->regs->CR1) & (I2C_CR1_START | + I2C_CR1_STOP | + I2C_CR1_PEC)) { + ; + } + +} + +/* IRQ enable/disable */ + +#ifndef _I2C_HAVE_IRQ_FIXUP +/* The series header provides this if _I2C_HAVE_IRQ_FIXUP is defined, + * but we need it either way. */ +#define _i2c_irq_priority_fixup(dev) ((void)0) +#endif + +#define I2C_IRQ_ERROR I2C_CR2_ITERREN +#define I2C_IRQ_EVENT I2C_CR2_ITEVTEN +#define I2C_IRQ_BUFFER I2C_CR2_ITBUFEN +/** + * @brief Enable one or more I2C interrupts + * @param dev I2C device + * @param irqs Bitwise or of: + * I2C_IRQ_ERROR (error interrupt), + * I2C_IRQ_EVENT (event interrupt), and + * I2C_IRQ_BUFFER (buffer interrupt). + */ +static inline void i2c_enable_irq(i2c_dev *dev, uint32 irqs) { + _i2c_irq_priority_fixup(dev); + dev->regs->CR2 |= irqs; +} + +/** + * @brief Disable one or more I2C interrupts + * @param dev I2C device + * @param irqs Bitwise or of: + * I2C_IRQ_ERROR (error interrupt), + * I2C_IRQ_EVENT (event interrupt), and + * I2C_IRQ_BUFFER (buffer interrupt). + */ +static inline void i2c_disable_irq(i2c_dev *dev, uint32 irqs) { + dev->regs->CR2 &= ~irqs; +} + +/* ACK/NACK */ + +/** + * @brief Enable I2C acknowledgment + * @param dev I2C device + */ +static inline void i2c_enable_ack(i2c_dev *dev) { + dev->regs->CR1 |= I2C_CR1_ACK; +} + +/** + * @brief Disable I2C acknowledgment + * @param dev I2C device + */ +static inline void i2c_disable_ack(i2c_dev *dev) { + dev->regs->CR1 &= ~I2C_CR1_ACK; +} + +/* GPIO control */ + +/** + * @brief Configure device GPIOs. + * + * Configure GPIO bits dev->sda_pin and dev->scl_pin on GPIO device + * dev->gpio_port for use with I2C device dev. + * + * @param dev I2C Device + * @see i2c_release_gpios() + */ +extern void i2c_config_gpios(const i2c_dev *dev); + +/** + * @brief Release GPIOs controlling an I2C bus + * + * Releases the I2C bus controlled by dev as master, and disconnects + * GPIO bits dev->sda_pin and dev->scl_pin on GPIO device + * dev->gpio_port from I2C device dev. + * + * @param dev I2C device + * @see i2c_config_gpios() + */ +extern void i2c_master_release_bus(const i2c_dev *dev); + +/* Miscellaneous low-level routines */ + +void i2c_init(i2c_dev *dev); + +/** + * @brief Turn on an I2C peripheral + * @param dev Device to enable + */ +static inline void i2c_peripheral_enable(i2c_dev *dev) { + dev->regs->CR1 |= I2C_CR1_PE; +} + +/** + * @brief Turn off an I2C peripheral + * @param dev Device to turn off + */ +static inline void i2c_peripheral_disable(i2c_dev *dev) { + dev->regs->CR1 &= ~I2C_CR1_PE; +} + +/** + * @brief Fill transmit register + * @param dev I2C device + * @param byte Byte to write + */ +static inline void i2c_write(i2c_dev *dev, uint8 byte) { + dev->regs->DR = byte; +} + +/** + * @brief Set input clock frequency, in MHz + * @param dev I2C device + * @param freq Frequency, in MHz. This must be at least 2, and at most + * the APB frequency of dev's bus. (For example, if + * rcc_dev_clk(dev) == RCC_APB1, freq must be at most + * PCLK1, in MHz). There is an additional limit of 46 MHz. + */ +static inline void i2c_set_input_clk(i2c_dev *dev, uint32 freq) { +#define I2C_MAX_FREQ_MHZ 46 + ASSERT(2 <= freq && freq <= _i2c_bus_clk(dev) && freq <= I2C_MAX_FREQ_MHZ); + uint32 cr2 = dev->regs->CR2; + cr2 &= ~I2C_CR2_FREQ; + cr2 |= freq; + dev->regs->CR2 = freq; +#undef I2C_MAX_FREQ_MHZ +} + +/** + * @brief Set I2C clock control register. + * + * See the chip reference manual for the details. + * + * @param dev I2C device + * @param val Value to use for clock control register (in + * Fast/Standard mode) + */ +static inline void i2c_set_clk_control(i2c_dev *dev, uint32 val) { + uint32 ccr = dev->regs->CCR; + ccr &= ~I2C_CCR_CCR; + ccr |= val; + dev->regs->CCR = ccr; +} + +/** + * @brief Set SCL rise time + * @param dev I2C device + * @param trise Maximum rise time in fast/standard mode (see chip + * reference manual for the relevant formulas). + */ +static inline void i2c_set_trise(i2c_dev *dev, uint32 trise) { + dev->regs->TRISE = trise; +} + +/* + * Slave support + */ + +/** + * @brief Enable Dual addressing mode to allow peripheral to have 2 addresses + * @param dev I2C device + */ +static inline void i2c_slave_dual_address_enable(i2c_dev *dev) { + dev->regs->OAR2 |= I2C_OAR2_ENDUAL; +} + +/** + * @brief Enable General Call to allow the unit to respond on addr 0x00 + * @param dev I2C device + */ +static inline void i2c_slave_general_call_enable(i2c_dev *dev) { + dev->regs->CR1 |= I2C_CR1_ENGC; +} + +/* callback functions */ +/* Callback handler for data received over the bus */ +void i2c_slave_attach_recv_handler(i2c_dev *dev, i2c_msg *msg, i2c_slave_recv_callback_func func); + +/* Callback handler for data being requested over the bus + * The callback function must call i2c_write to get the data over the bus + */ +void i2c_slave_attach_transmit_handler(i2c_dev *dev, i2c_msg *msg, i2c_slave_transmit_callback_func func); + +/** + * @brief Set the primary I2c slave address + * @param dev I2C device + * @param address the 8 or 10 bit i2c address + */ +static inline void i2c_slave_set_own_address(i2c_dev *dev, uint16 address) { + dev->regs->OAR1 = address <<1; +} + +/** + * @brief Set the secondary I2c slave address + * @param dev I2C device + * @param address the 8 or 10 bit i2c address + */ +static inline void i2c_slave_set_own_address2(i2c_dev *dev, uint16 address) { +dev->regs->OAR2 = (address <<1 ) | I2C_OAR2_ENDUAL; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/STM32F1/libraries/WireSlave/src/libmaple/i2c_slave.h.gch b/STM32F1/libraries/WireSlave/src/libmaple/i2c_slave.h.gch new file mode 100644 index 0000000000000000000000000000000000000000..5a6345078e7abad4b9211a296cfa52568e2ed238 GIT binary patch literal 9475 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 Y;dI<1)bAmJrq!61Ti)JEJwtc@2OMIdI{*Lx literal 0 HcmV?d00001 diff --git a/STM32F1/libraries/WireSlave/src/utility/WireBase_slave.cpp b/STM32F1/libraries/WireSlave/src/utility/WireBase_slave.cpp new file mode 100644 index 0000000..a309211 --- /dev/null +++ b/STM32F1/libraries/WireSlave/src/utility/WireBase_slave.cpp @@ -0,0 +1,145 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file WireBase.cpp + * @author Trystan Jones + * @brief Wire library, following the majority of the interface from Arduino. + * Provides a 'standard' interface to I2C (two-wire) communication for + * derived classes. + */ + +/* + * Library created by crenn to allow a system which would provide users the + * 'standardised' Arduino method for interfacing with I2C devices regardless of + * whether it is I2C hardware or emulating software. + */ + +#include "WireBase_slave.h" +#include "wirish.h" + +void WireBase::begin(uint8 self_addr) { + tx_buf_idx = 0; + tx_buf_overflow = false; + rx_buf_idx = 0; + rx_buf_len = 0; +} + +void WireBase::beginTransmission(uint8 slave_address) { + itc_msg.addr = slave_address; + itc_msg.data = &tx_buf[tx_buf_idx]; + itc_msg.length = 0; + itc_msg.flags = 0; +} + +void WireBase::beginTransmission(int slave_address) { + beginTransmission((uint8)slave_address); +} + +uint8 WireBase::endTransmission(bool stop) { + uint8 retVal; + if (tx_buf_overflow) { + return EDATA; + } + retVal = process(stop);// Changed so that the return value from process is returned by this function see also the return line below + tx_buf_idx = 0; + tx_buf_overflow = false; + return retVal;//SUCCESS; +} + +uint8 WireBase::endTransmission(){ + endTransmission(true); +} + +//TODO: Add the ability to queue messages (adding a boolean to end of function +// call, allows for the Arduino style to stay while also giving the flexibility +// to bulk send +uint8 WireBase::requestFrom(uint8 address, int num_bytes) { + if (num_bytes > BUFFER_LENGTH) { + num_bytes = BUFFER_LENGTH; + } + itc_msg.addr = address; + itc_msg.flags = I2C_MSG_READ; + itc_msg.length = num_bytes; + itc_msg.data = &rx_buf[rx_buf_idx]; + process(); + rx_buf_len += itc_msg.xferred; + itc_msg.flags = 0; + return rx_buf_len; +} + +uint8 WireBase::requestFrom(int address, int numBytes) { + return WireBase::requestFrom((uint8)address, numBytes); +} + +void WireBase::write(uint8 value) { + if (tx_buf_idx == BUFFER_LENGTH) { + tx_buf_overflow = true; + return; + } + tx_buf[tx_buf_idx++] = value; + itc_msg.length++; +} + +void WireBase::write(uint8* buf, int len) { + for (uint8 i = 0; i < len; i++) { + write(buf[i]); + } +} + +void WireBase::write(int value) { + write((uint8)value); +} + +void WireBase::write(int* buf, int len) { + write((uint8*)buf, (uint8)len); +} + +void WireBase::write(char* buf) { + uint8 *ptr = (uint8*)buf; + while (*ptr) { + write(*ptr); + ptr++; + } +} + +uint8 WireBase::available() { + return rx_buf_len - rx_buf_idx; +} + +uint8 WireBase::read() { + if (rx_buf_idx == rx_buf_len) { + rx_buf_idx = 0; + rx_buf_len = 0; + return 0; + } else if (rx_buf_idx == (rx_buf_len-1)) { + uint8 temp = rx_buf[rx_buf_idx]; + rx_buf_idx = 0; + rx_buf_len = 0; + return temp; + } + return rx_buf[rx_buf_idx++]; +} diff --git a/STM32F1/libraries/WireSlave/src/utility/WireBase_slave.h b/STM32F1/libraries/WireSlave/src/utility/WireBase_slave.h new file mode 100644 index 0000000..31f3f8c --- /dev/null +++ b/STM32F1/libraries/WireSlave/src/utility/WireBase_slave.h @@ -0,0 +1,145 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file WireBase.h + * @author Trystan Jones + * @brief Wire library, following the majority of the interface from Arduino. + * Provides a 'standard' interface to I2C (two-wire) communication for + * derived classes. + */ + +/* + * Library created by crenn to allow a system which would provide users the + * 'standardised' Arduino method for interfacing with I2C devices regardless of + * whether it is I2C hardware or emulating software. + */ + +#ifndef _WIREBASE_H_ +#define _WIREBASE_H_ + +#include "wirish.h" +#include + +#define BUFFER_LENGTH 32 + +/* return codes from endTransmission() */ +#define SUCCESS 0 /* transmission was successful */ +#define EDATA 1 /* too much data */ +#define ENACKADDR 2 /* received nack on transmit of address */ +#define ENACKTRNS 3 /* received nack on transmit of data */ +#define EOTHER 4 /* other error */ + +class WireBase { // Abstraction is awesome! +protected: + i2c_msg itc_msg; + uint8 rx_buf[BUFFER_LENGTH]; /* receive buffer */ + uint8 rx_buf_idx; /* first unread idx in rx_buf */ + uint8 rx_buf_len; /* number of bytes read */ + + uint8 tx_buf[BUFFER_LENGTH]; /* transmit buffer */ + uint8 tx_buf_idx; // next idx available in tx_buf, -1 overflow + boolean tx_buf_overflow; + + // Force derived classes to define process function + virtual uint8 process(uint8) = 0; + virtual uint8 process() = 0; +public: + WireBase() {} + ~WireBase() {} + + /* + * Initialises the class interface + */ + // Allow derived classes to overwrite begin function + virtual void begin(uint8 = 0x00); + + /* + * Sets up the transmission message to be processed + */ + void beginTransmission(uint8); + + /* + * Allow only 8 bit addresses to be used + */ + void beginTransmission(int); + + /* + * Call the process function to process the message if the TX + * buffer has not overflowed. + */ + uint8 endTransmission(bool); + uint8 endTransmission(void); + + /* + * Request bytes from a slave device and process the request, + * storing into the receiving buffer. + */ + uint8 requestFrom(uint8, int); + + /* + * Allow only 8 bit addresses to be used when requesting bytes + */ + uint8 requestFrom(int, int); + + /* + * Stack up bytes to be sent when transmitting + */ + void write(uint8); + + /* + * Stack up bytes from the array to be sent when transmitting + */ + void write(uint8*, int); + + /* + * Ensure that a sending data will only be 8-bit bytes + */ + void write(int); + + /* + * Ensure that an array sending data will only be 8-bit bytes + */ + void write(int*, int); + + /* + * Stack up bytes from a string to be sent when transmitting + */ + void write(char*); + + /* + * Return the amount of bytes that is currently in the receiving buffer + */ + uint8 available(); + + /* + * Return the value of byte in the receiving buffer that is currently being + * pointed to + */ + uint8 read(); +}; + +#endif // _WIREBASE_H_ diff --git a/STM32F1/libraries/WireSlave/src/utility/WireBase_slave.h.gch b/STM32F1/libraries/WireSlave/src/utility/WireBase_slave.h.gch new file mode 100644 index 0000000000000000000000000000000000000000..5a6345078e7abad4b9211a296cfa52568e2ed238 GIT binary patch literal 9475 zcmb7KNps`I6&_{Z7iV9MjFVW3EfyLZfg?nK63P%sli)~`OBaWNG%Qn;LQ>8+m2;|c z%U{T^$R(A3k-v~@Zn>o@@9PJk8>BpTR7EXlp!+S~``!ZG+|Mu8i*5O*r+<9I{`-Ia z{I9?M?Vr#8{ofCs96V89fBDDT>bHaH?iTvE>+)WY!LEDt}h_n3KE{ob5#@C9?t5Xih-|9&1(QZMm@= z+YasMC$#ikwLHxRh0N1_e3AsoPI`J(;CF>HCrF4bMk;dTBXNX=zuK zP!`WeDT(s1+AMBX<&`ymIa^~BNJXZ|ewz;avY!v*BDCo~5nzk2s6|o;dh`zGN7meW z>n$tCLtj^G&^9#G{2^Wanp(Ml9ZdaUgXxcH?K^56X54IN+r?bYHk)$2g(W><|CCmt zp_IdMl8$Ab6-A!PbdY560FpVb_X}F*Qy}=>DL4sV(;VWkpclQfc--9C z-0NAQOXstjfXpNv49DjcO0Mo6UM$N)uM>H8;0K-`dcyGn-}6KlU~#b&en_B6~Sm*-rg@~RZMnm?~ra`fmBTP zDJ03oyO6AqKwtqFw4K2K!fr^wwY!P~_=aXf6Z;5bw#&=eMlM$K<-=8ZNDOmiNoib? zQeA{OOzc50rW`l)vCo(2Bc%#3j=dwgup8O0)d<>GadI}+(FpYardi4r-zlOZ(g~xk zE4;{e{jTGRZs6Na`HmO4j*2D2oQmR1^&iE~$#9sPu0t#_jlzUbxgw_J-RefO(_*## zGTr$_`bdJw>fx0o;PJ*@1c_Fx21y_0LW+>`VYQ(9K{ZVDIEo(F_52i|#9f5;OJ)0X zoSmnGf{@$0ytF~x0$?`@jZi^wo?>IZtfJ#2E9i2ld2zBsH_*F9L~5VIV<}ByI<~|S zObp$X=gGSU?OJsC=V}RoS4HP&NZNrXb$oyx9}OhRNUcEnKHbPsIh|mO_$1BcXq@&l z=ni9ZMw}E0k>7AqqzLA=CjdYrS-PQf1mkc%Q-qZvzX~6STYgzRKfnUmF?zxk%&pu+c7Zl_lMd8#uxy=(79V*6x$Q7;^2E>zo*A9hW zzT?_qex!*Cxo$oCJ=HmDIz#Q-6*d%N8b^3Q;cU>)23heO5+ZmT*BR_yBeBj`stBua zW>jyqg@^LVWJ)tWBku_IVj^$+s4Z^M;%<&@UX<(?vL7f=AFc9`Az^JN zXxR#S#S&3)u95q##p#^C2F*N|5j$H~t;e_q<c4`S%*j?u>5|zH_o9_nTBzE7Le#N6+l`Dxl&}J5zDWU?_{T zaT+HRoDHGbna0_5+Y$J_8?<5;^yUAWo?-B)SX19j`lv<0&pd}8`0gq|RY9(jA;OGf zS9$Wo+47;3>+-r>m#cY+YCjM*0>4JWy@3Z=8-pX|YR% zVMsqvE{CoiQGpM>!MRMJl@IEYfRd3Jf|SFjMPE{!5;QiO0;cy98l6ua%jO88mFfjl^SDR ziQrfkwn~dNAOS+Hel3?~GnidJ_;?o#6tLSUc(OsB4OD8;fkpD}v@=fB>{~0N>gT$o z;KJh3?8aoGIyN{mumd}K3gI}h!XT|GahkW= zBdS;CcUPrE!#|r-!^LUH_HewijUo3+mOY zeqCB0)479K_!-EoQU(cb#y~TiApC*402!K1p!lq-sA|dq;6V1KP^JXHr4pi+PvP;w zC>iP5flJ--9+8{bk(}ck?Z+zZZpumG9nvuz3`&`L-qVUAQys)1J4}(`cDt}d6m^Aw zv#P9tQHFVp`8-mD2C`8WAOg%UZew{zGIIlYW9)-K=17}R6R?h$rK?FRH<3x234w#y~p#W4(#adRP6M-fU233$4ja|nMJ%`3`UB?TlJMcW$ zvqgCfrYD%}U~Hn8(e9uRva5;(fMcgM(L>MF zN|*@1@6#N^h+TlbCfqc+*F|`X+_96c(Q#@s8gWC57Au|60@X6rhOK2&E@R87Y8P`m zDv^eR9Cfdq&@LSC6{UWRJ(N)%|JLLZ?W0;7v%+o{CN)1A!zi1I%tzR2r@%Gg|0@!n zV~&JxqH`}Dq;BXX31$HtPZ$#DT{-uf+v+l8G>%WtW2zg8q>-S~%VH3pQvnG&(}hLN zL#7Y3?`qkaWFrFDVkba%P(twuj@minF z&%hq0mrQ%&_h}9n@h))FRXJa7Ke|`FK=(2KG?8S#+G7)BMD)rn+Z1X7fSEjvC5rJB zQ)o*dGC5a(4w#cwd%zcghFut7g^LR{eS|YWkqsF4g9HJ>X22mDiXkL z8Z_80J;_*szjeK1bbD0m&$i zUAB>LG-Xs;)pZWBHDXGK^A65Ux52rrz8d$9;-W{Rjb}7Lrfj~?wMMnF7t1Z4N9gQ^ zW6dNvDm3j(&KGq#sb6gBYDRfxcf_ViS4qwdM$`D|D1vi{Q;mVE=z{#&JnAtt)T9|f zQ#Z{0%gGp5U;`$MljlYHN$ruI6R8aLu-YzeOF3JwXCG~-R|vbpf!lP~N5>i^Z#x0f zID}q7?Y~`p7GIglFE5gw6xcHl2bkI)!b4cNl#H}90#?ypaYm5=-(cw2)bU-KV+CM!!iB@(II47we^-un12}X;mVA?9X-J?fE;#_TvhLAtlaw_k)D7x_*hEYvbM);PK Y;dI<1)bAmJrq!61Ti)JEJwtc@2OMIdI{*Lx literal 0 HcmV?d00001 From 4157ef37a1ebbb8dd24560158074974663d3b189 Mon Sep 17 00:00:00 2001 From: lacklustrlabs Date: Thu, 14 Dec 2017 16:41:43 +0100 Subject: [PATCH 248/351] Removed some accidental adds --- STM32F1/libraries/Wire/Wire_slave.h | 2 +- STM32F1/libraries/WireSlave/src/Wire.h | 2 +- STM32F1/libraries/WireSlave/src/Wire.h.gch | Bin 1819056 -> 0 bytes .../libraries/WireSlave/src/Wire_slave.h.gch | Bin 9475 -> 0 bytes .../libraries/WireSlave/src/i2c_slave.h.gch | Bin 9475 -> 0 bytes .../WireSlave/src/libmaple/i2c_slave.h.gch | Bin 9475 -> 0 bytes .../src/utility/WireBase_slave.h.gch | Bin 9475 -> 0 bytes 7 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 STM32F1/libraries/WireSlave/src/Wire.h.gch delete mode 100644 STM32F1/libraries/WireSlave/src/Wire_slave.h.gch delete mode 100644 STM32F1/libraries/WireSlave/src/i2c_slave.h.gch delete mode 100644 STM32F1/libraries/WireSlave/src/libmaple/i2c_slave.h.gch delete mode 100644 STM32F1/libraries/WireSlave/src/utility/WireBase_slave.h.gch diff --git a/STM32F1/libraries/Wire/Wire_slave.h b/STM32F1/libraries/Wire/Wire_slave.h index 21b4102..ede963b 100644 --- a/STM32F1/libraries/Wire/Wire_slave.h +++ b/STM32F1/libraries/Wire/Wire_slave.h @@ -1 +1 @@ -#error "Something is trying to include Wire.h when Wire_Slave.h is already included, they are mutually exclusive" +#error "Something is trying to include Wire_slave.h when Wire.h is already included, they are mutually exclusive" diff --git a/STM32F1/libraries/WireSlave/src/Wire.h b/STM32F1/libraries/WireSlave/src/Wire.h index ede963b..2d3ce70 100644 --- a/STM32F1/libraries/WireSlave/src/Wire.h +++ b/STM32F1/libraries/WireSlave/src/Wire.h @@ -1 +1 @@ -#error "Something is trying to include Wire_slave.h when Wire.h is already included, they are mutually exclusive" +#error "Something is trying to include Wire.h when Wire_slave.h is already included, they are mutually exclusive" diff --git a/STM32F1/libraries/WireSlave/src/Wire.h.gch b/STM32F1/libraries/WireSlave/src/Wire.h.gch deleted file mode 100644 index b29a5ea9fd8851ea75533c42ff77077972caf5ce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1819056 zcmeEv37jKUwSEB67DWSYEiNxEXphL4UMGWqJKZ(&?hpJ(EV% zxS$cYX48n`Yh^JgXk5@1QRDV(*B2Kw;?~My0O9p}Jblsk)c-m6yOpX_Rhhx%sefPf z@7MY2JLfLvp1Swey|->vO&Q~<6T;nnuY3B1$A)kD^&9Sb&nIp@=ih#}FK}2u{Vjgx z+3M&p%>z(4D8kx*4-4cY11ApjX_*yXCwv4HtyEp~u)|rT;vHrhgUn$MBDkX2#p<|~ z!(k7#>ud(u#pdy0fvIFRIh!7rS(7?Q|Bs^oczoBck@&9NJ9lh9JsuDBK7nM9R`M;U z4ad*iwmm)+8zDv4iQVCz?scr@sPXu?VZ=x0=4R7l^K;2us3#nbgf~8kRF75aJ=?bL zjt>uQ+O@lTAb#ei7$p(TPtxD9trRxx-f`x(&GAi}U$kf2&Y@7xvq|#^6?yCMZk2UB z)V;oYLx11KzTW<9PjVn7~j0(%#q=t zSg7aeq;i@PiSIsVWQa_e&*suo+2llMJT*GYiLh1Vif!i(?bsUMI=o}k?ns!zbq{b7 zM=2#0h|96LYkXa3JoJobgoZiN(Mrdqjo6CWNzz9u&Drb+d->T1dyXUBW0aoVn424& zOOMA#bGhW~9DA~_JN#tQatY({9Xq!S?Tim^+r4{uC_c1(%eGD1*|MJAzNe8Mxv=4` zTsSBG+cV7Oz|gZdM>p+kh1`GulTRf5F)FhyLz@Ts;zJ|5whix4*$kc7-M?kaGfBw~ zjmO#7(M@L!#dn>veY5iRrkz9aP20D`cb&ayB;FnBe$Zii{)n)Bq3#WoKTZ?Z%q>IP zckDb<*OG~u`LRs0t8e|rzVJZ*Kwp2Pue+yjpuexLdjnUNp1$FA58A9qsQW3D6<1{x zSJzYJx#1m~Ul`xIbBL-dw-PwjR{ughT$^xexfTzdwTW8M(C+AtE!+b5tfJ2Hc^^w> zM`st}ne<$8b~M9nsJl0;&gwsTW!~EprzT|?z=8P8qAl(polTEUP&JxMP8*p~-6l7L z`?@Fy3{q`!D>X?v#m*|JYXVgkt_+r+xd-SDw>p8|@CMZfAV4cYd)?<|48NpCbMbU` zJTpI$?4llKT__&6iQ;i3WOvx>9vg-(r#I5i>2%P4JgyoT+TJ=6I9v8XOT?wu?IgO> zYK>g`pVLwetNu=PRMhE2Hg4$c?%UYk+rOcww|m1tf4C=kLf^*T9@Um??o?fzz4)GW z=d>L=hV7@0+Y-7_b|Dv8cTAa??3C3zrL%Jnr;rb$|2S2X?0i1d&1byjFRBuvtqyG2 z%I@MzL_9v9O;dR8YS7VhRusW`=J#-= zjcNr|=RKS-#Hw|iwrw|wBUZn-%hBC%xkX2$(&;)e9=CT)Cx*J$v5UFv>de#GwRO88 z5yeb`No5mS=)1pzUJW8|hic&cXFeby(Z@`r6&kH4e$C{=w>L*LQF132*F) zZ0x6NT%^0FKTLng6E|$NoXqFv?4eCBL{3*KbsRLmR2`SQiReSIi3qUkTA3xpJ`?Ht*o#N!JZ7sHz00;>vC2 z^_ik@T|@r?&8{8P!wmEdP%P>J`@{Xi>>ti59_KnsrweDFBf)i4fNf_|{oJCQ+M}u` ziZ+#fes>_IO+7+h(%+T)m zc3hY(ADzB^&t@{CpIZou!zXa(?%mr$-B!Ck^Gwyk*jCuX^@3B?mpCd1cge_7k5H78 zx9r$+8Vw0ZKfpGj2A{U=^wWoS?T&96-gf$SZpBJ(bqf0;EZ~bFcT~7^Oe8bODH?)g zr{d!?+1%Xh{P^6=tQyk|g!{r2&Z@?6p}ydDucyJ-z{cM0-oD5H^^^S@!jbO&zbse%DM0IbOcQ`U ztL;(~?Cy!k%TI6b7S(o<;jUdne6`sf<+54@(j9h`s_xDqHhU=4-P;}B(DMv375R?r z-nnJl)~&5em06h9Nw-?h==8(@4Gyi7srr=dJL0>eJBK!H*~NLY(Kwm5yv=FHK!1Pl zfM~Paef2+!;-K=Vwx)jU-G^xk0s&8cP< z2@i1IFpWE(O{Z;(pEa~|*R~zoL*3!Z9^0^g%h{WDZtaP0 z-nuQmY1f&dZp(8tQI7MeU{9k0uvwYW>9L7XWz5F#1|Diybyg2W9nHnj->CYk`~VCpX167Jf9vXCUZYOiwk5um<|><1S8Qdd8xZ$Oln|4{f8N1zz=sgSOT7c6=jc42T z;ceU1rNwGkWUpg7)3dRau2~p0el~{`7+84z4pC|Qwy1W4&RbQ#P1J|#OL`yMj3%M$ zD|zYZ{p=cUUyp~{%-p$SK^(SOT{6gU zdmCsiPEh^hu8XS-txfRY(;P+VRSvE=YX($2Awe#&AP-44R2*fvp>*P za#<~3*zL0#5!dIPo3^MKL=X4WI2)=0=~Xe|CCZU&6B>gWkk}@6>%)=09$J3e(9;*8 z*+E}lZ(q1Od1Cj*VeY@tO4umw53GsOo?)H`K7{_`@qKz#!|Whi1va}7^Aa1P;I7FP zCTF7RbH*r=+1u)Cwz}xCA22UeMM0bHj#vX>TrAkF+#YZhqdtVZx@*sAyt2c~CaPx) zujhGCSdUn^!r`Q~S`WoB3t_JTe7t9v7bBb%^dQa6>fFsixaizDC2Ne%xwe)@dLtoH z>N4{b$h66HtZAD%W$>ID?ee-E4Uu+iALemycnhV12Cuu+HvUjf@&0LDORRHbmc~B9 zmID*Bf3z(|g=vuK(OWqNxc2IQJQdMB_&4r1=6h6x+Rh)0s4YxK34U_CC^m?SFv2pvl z#eEd2yXs#@vs20V*k~>}5ucoycRCSS_rYm(Oo|_)cWVnmqv%_^j zEXV3$d22bA-HT$G?rojl4cwqm)wBcc*B3goR#oI)TtUX!O~iQPN* z@G5kun_DKX72F-5Pgc_d2)Q;ms{v~;xKOK)d@{I;Y*j{gBjE-DH*h9a9jCdXb4)@@ z71o%fueV3dhj9VqA*`)Z_4mpJi*zqSA=s0)k%E2b);-W0>0W1@H#I*t&zsfkl^ymzhRbPBveh|pg0{X(+s4gAJCqw2 z9IE>Q+f|X*9j$WdF&54GH^pe7A>2zbQCIkUTjL$uY>&n|v;?)0W_`5CMDyWDKMi{Z zhS%|u_>uG<=V_UJ5X@eV=s^%$=IGU}VH=$rtIN=(GRHa8TXUPTnzN&x+fN&xTohj| z_l<1Yy_uFa&Y~4$x|+NDTH9#F)s{s+&rQeK9L=6&m`7;V$;9=-98Ov{Hm%W&Iy25C zHmlQBmScj^n)q3*h))jnskQ~z?hV}e!#ye*PpGM6R5h&$^VZm|oh)G=pu;%roZUl* znjTr}MCuAQpPfrjC*z~Dv!e?+nkz&$bocOSvu1sit!>CFFMzZhLbsrtH^kProTvIh z`;Elz^)#^V*%;{?p#G>Y(oNklEy>gRdH+@}F)oCvhFPb^V~AwcGS~eaYZk$y9xI@| zN^uuub=1hImn`dv&`sX~YLERrkx2hWx<^1ut&y#Krf@FUWoiXCnK#tso^JnHCq%8s z(Fx&-)9S%33#dVGJ;r5SH;C2}bA;;>`UlP=nIBIYb7@*E*7G-Ug=LE!S6GgY3QIMK zdkzkR(GN{F`(1s+W*TPf;ej3J31d|yrLJxV*Q!2wx#iU0Cu?oiY%F`!h+Ai_7c{M5 zJ1tmK4z~VF+*s~iPdAfkhT7lT9f|bxZJ^Gmr@xo)r}THLp;2q*O@jthLz};O#x8nm zb6wNn99QXg4ZSG7dDrexKlcdmx;dz@N43|PFok3%$GNFecXg;~15Fat70lMm%@fla zH}&>$Yqa@>FElOJb@5%LZgrOn?Sd~(=5nvqx9FN=t)kL$92W}%I<8FfwC#ZgL6d3P zkYT?W&dZ%8$|RBKd5^*g?6$DW;=sn)w{1g%!{YI&&7r7_pgd#}EnvZTM~ z%uR=8lT*g%>~!FylL9BFv$W=%o(Rntw9A0*>zo?c9N2uq2>~@Kq8%LD>28tk-f5o` z-BJylPJ3u*Z_ms$?IuWOCj_UxDzkHtj8U&l_ag*}kB`!-b_O!{G3`sBP9tv2P-mmV z@HlRKG-G8nZc4JF)bqFUmtvb4Erm^%nVF$+^#Y|pMc{jP$V`Zx!CN`0P{c%8TEgti zfzh-*y{Y;11XWx|E?Vl$WM+1P7XByN+2&NYi|(DL8T$}<&+3b+!(ubGscx4y$$7U@ zo7h_GjBFyULjd>%9GF(|AQP9d(dAok0$kOnV#5RN9)Y0)}D$E;g!fiY%o<`(c0(f&dV%rtF4*>Tf)@w(Yk@z2bnBx zZ~N#CqzX><(rDwoRIt#Y$tB0t&`ycB3sFGbay>Nw>V~u z1zT=5p*yTiLLK{5Qg>`Pj!%rvjiMA#k)O)176Y|FJYgTFk%yC4$usYTG2Q; zeKtuBY}r6gb(&?0gjtr*ZdOZbH>)MIo7EE9%o@)mN9nYgwv5v$ADyL9L!O3KwD{Rx zW4Fv1i|!2{B%;kuS45k+E}h+KhnaDzxMmUDrkfJG$(GD!YD;J{u_d#a){@ywYRPP- z&>n@+bS_CMn(SE?s*@e3+UOy&+t>;x{Ao#TR$4-vnU>IIrxsF|((+hKdu{I?(8A8ogw6}#4ZDr)MbH^x=i3+&#W*=b7t0^J zonB^U)K&wT*$n}=*`Nfr>=n1=thg;x#ceH7)dF>*E&p3Gd)9WT%>bL&W`<2_GsY&h znM7W37+^~5*;_JO<}INu>z2%xaZ6^)mT%b8>~NAdOIc;l(LB~k?Pe&wsQi%F41mCv zI|TNuITL%=%+=E2gO*6-ZibTP_>Di z>p50ny9Q%&ht6E%@fMr27l&4_`*=#l3Xn5|x$?s^hIYEvs?b3LcoxR7QshX$K0(Cl z#=!!3W?(K7IgK~vZT!_z>p7oSzV=mugXr6vWzLkvs)bid&VYwb@=&&!DT;NBgJo?l z7pUp(g9&(O8!1FTvB7Jfv-Afc8lo%9cagzPt2E_uz0T2MWgwj9gD0e&aqvJWXWKC5lAAMtDOU?!4omI2 zHodgN81}V8Z&hm*(Oa$86J1JLS@e)u zYm9A`ZH(9Jjvmpl0_jw!wMa|IJLGK!=~c$oIE(^%j#~9FO{#6 z16gZy>#4TJxkBwR;uU(&v9AolU7H-)3cY(gEY%((<5mEg5YQvk*@^Lt{Vec20pfX2 zab_a#DWA4iE_y6Zr!uQ1Tjto>lIP|;lA-&I{A>YrT?cqA*;W-)a;AFTpgXZr&8wKy zJ&dP#QfuWlY0v|6bCYb1kWVM4$7wR-A)cPu&(Aoxf*WnZ^9gVUZ*+fLC=KIfTh zZqCShSwl|;j*q&nVX;S9Nt|sH+%xt4?R>evjrIH6mUn;7J4#aBW@w$h(J^|4$adOB z$JDG<*Wc0c@i^THpGfXctA!2oq>qlz$Y3)$zK>v6^ZLKwt^oEH!3hdZcM+(P%uZ4* zwI?*Ocb*m)r~*$LGql;$UJ*y9rsz%x-Q(e>`Ds@GJts=5zq84lu$1q4(4B3%_clW} zUn~omkGcf$1L?UGZj{({hLKrta=J}2C32!`nmr6r;Q`{pMa*3Rgi9!donME^=alNSOrA0K!(%OIumsOu^2_#-|ONGsgJlpPlp4fm#GMYm8b! z=(U@zB((LzI%i|_5Fy`&GUJTPy35pF3g&j3s3Q}VSaBJF0@%x~LWqJx;!0Ht993~OWPvk5$bJ|`E<|5Stqq8(&nzWBNCzLG5d*d_n({`sMQ`jw~-pXLF0i>9u+bd$8 zMl!W=)hVPo;{2>5Rmjv{DSFuhZ3eOxfyUmF*@w%d9CxbiM@49QqSS7_yuwr9yd!j81{c$XNty`D;Bpo@ zNl&qg%w{HJ@Ry3BjiOK4uF+XSTSrl&G znDY!sivu(*c1`{Den7L05fy!c;-csrK$LxUW{kQ??nYJe_5$YUZnB7cfbJ5DN~i>0 z_D+pXi`t-g++LrQ#GX0??l5+1RhWznwSFvMP=r;?s& zlh`x#oOkFs&(Im~v`Orhb|&d*H;Fw%ds~ueW67L%+H;<1XWKZOnN?iGGM+b#!a+Q#wBMaA*RhnAv~_D&M5nWSptw|P0Tr1lQ9B^ASCOX?Yxs++Ap zZw1axw3B-qlADn7-{TPja`)NVPt~($ z!tD$t7YlW866Bugq`mVsNbVUv*CyXwn{-I-z7XuE=F;PFfzWdI9wdO~QS`$kxrKgCz0@Ldl z?Kj&HI6uo~_**J~t|6<~kLYxCK+b5>s@KoM!f?Je)=@$fP{do!LK~+vi~f zS8qajlGI(nl-x7Vtj8Edh4#wve7Q)X>Kz64@DmB$C7JiAanmI93h9yNe8!#T%&faq zBy*)`jE?WiZC#4fn!xi z+ezJov)XWAud~QPA~~QQ`kS{Q4A7#1y<8ociIrQjo_|8DuQR}mBwul z#BFkzn)5V?#BC#Znlv@n&ZMb1Pm@UOmBTbu?E~%{Aoh-s_o&-^k!h2DUOj0iF46`C zpZ6>DkSzOC5QG1oS{eN9iver zM?z0CNbb7MtI+9o!Ow4}abFH7S5K$1+%wm|yadAH--tmj!~si!IPWA0vy9@zBkLrLz@fJoRTWe<Liu?QQ&{2Q z5|*|x#cLQusk9jeDUD|aZH7S3r`F91%S( z(WatpikWt{lcIg3cD7TKY9HxfwrASeP71FS=}BBy_fIm9ptPIXJ(nS&dm=<@!PE8| zh-y$fJ298@7TUJ~ASgYVoSe*zPSMRo_uVIcZrRkjXP2`xnUt&ZBB8r)nVp&S3OVZ$ z(z#^@R*H6Hgh@}&oa%6se z2T3#HohEN{iSPGVx#tX_Y-0_S5pUP0y|(*lDQ*VqXJ2xFRohN?_j$kya8Bi8lO-u^@91g#{u8 z&9-T?mHnccoscX3Vp|IB1#(`PNg|y_0_mo#*vm&r2n({4Vvxy|20IyPLt#8eA9{+< zjnZdNg^3g(z%KBl-QS;rk3E?u9nVC&5jyk{|8Bu z^k9>?$eXexe{#+41IMP`G;=x;Vz;#tI%@(4bkqeUlC^%f9;6cn81q@Ny)&Jo7yF4P z3w;I3T<+|}!VyM7&T*QNt*4g zF69A_0_ELSxI}xyw#@d5CnNTT?Pp|fw>_ZP6}wk#iQQ|jBYVYZ-Yd>=M)sH)N9V4% zy^<(_-6Xo#Dz*+PE@E&15yN>opgmrWJ))3^NNNk8t@Ifs5L@~n5_x-U4n!z-+H!kf z#_1TBXWXuF`v&E(TkTO+kHTggoqI+JM9Gvylp^Eo-zgUN_>O2S67j^tI&@JLyTKI~ zDR2Ns{BHY1l4FPm!IZ!eqsQ)(nJKYR^Y)jd%Vk{7r;n6pnr$|6ITJ6IJlJH|znX$d}Jcb&M+T1@wPZA{O)EjWk zMRt1SX`Ek2LE}IAA_u?L*ScLHbn1a|aw<@6;4yAL2~6WCrk+C8hF z9?%nABt0lLN-uyGWBr!Q?vj?!?g$c|KX0%25IEvd5E;qwWSH$42f68*E)#Ng>9}S) zFC)xFPLA1_>l)&^gwRb&&lf?k+_QsKiZ&X0pF~o;qk*2<$k?y5irbx~1ojd@VDH1V z#2riY%PN#Bn&`<9#F3c{K^>FsL);I3QBNi>@(|DiD>S~PlH2O7))36wM=`vDJ1J)B zJZl^i^HnWzT(wN8xN@07arM$d;Von$3Qi*Wia0$}W4{n^TrG9R*J7E5a5ujb#NHxl z*6Mgr7!pSkG9&RQDuowMqB3{H7PQTXAV+fV`pOD#jef_C{gk@;J6<%m2Oug6LtL0g z)lXJ7T6^{y!Q@EpZ51oLHFLb?M{i=`7bV$kQgX+BQF`%?9Np4yiRbdDAhU9$O%hkhNM=vB&G}x)?e`cS=d@T3kWHy$h-`|TgJk*ax8u=o z$CKYo?G>20y#f;#)H!*c!@Ss5U`RwHyr!g&zJ1P1u1-&ZFvGzNU z&s*@Cr|nE=DfJNQqZh61>UhT<-xZ)s8%gbMm~YcRvE19Bw*3=L{^TqMf;iu*uvux7 z#%1$%&mKu4TLuXnje;c3_F%sL%bw|^vt!n;0<(v41u@?WCIY!G5wum=(djRQZ7~+a zs@#HD0a>uG$}NahxdpK*w_xuE7sM52K{Z%?Sn40o(@mfB zem(``3sZ4=#|XUzA{n2get~KoCf{xa-uq^L#+TyK*Nc$IlvB%m+pkRnZk#yRzp za~?9$LnssDY$iXAVjj$y2YDQ*5+v2M+4kueDX?CqPNyfC&GARp_(L@OzJR&O9zLQc zE9S5wq7EZmALTpoR4G*~UW4Z(?BA+ktrS|Bl5TL9Z)O*d>)X})ZdfZsPXL2F3y%;>_*yv|s=2O%`cENJKIixkDR zG%XLOare@pG#0E#^i_H_BHT+~fTB15&(M1^xz__-P_F?{$9nld9pmf4W++wJO@ie( z6^cL1YKqkt=ZVlNJ$-hZTL2bI^_wyELaD{nyR@j^LqNKQnyUE>nloL~(VXc3&6y6+ zoU=6bpm@e4mqQPS;&U^c;~0Gg)82XxqP5ykE0C>kaLH`J)k1={m)A(h3IGDHNo3=!g%A>5eM1(rXT#TN04B26njm6l;`)GbeW>sy9;t6K(pt6PSv zQ>ZMalWH0)gqEQWamzp{Zy6@VErX=k%Mi7gqRx#iEcukj5nf_1LnyeHAtd%Pgv1_( z&`k*sm$1~!6v#bnQ3?-Zl-$D_CHF8#U4tFvr!UiZc!i}NhLG6943c^nK~fJBXlCL* z2Ry&=FhYqvtYEo^87%g&gT)?(V1us186@;FM2S5NVY!DPEcP&j#Vtel?LgGg)Adt5 zPNwXz%Pcdbv}J`5w~P?dmJLEGO>lh0$g;z(a2O+1(juXgW(k$FO{iK1s%q@&oTbz< z%_(o$!d2Ipi&K==8aavCAw|q_ky-5Vy<_(v}fI+A@Lbvdab`w2W|wTUJPU z%M2-Q*&)T2A#}Z_L4TGuy_wCK-mTR3`sJmwEcMp54E9vF?Do{Q%=gr`O2IAC@HJ6~kQOlbOWrahbs?j9HK1#aRIR}t zi_{DR2Wqf4Z=18wEHOEop_}4U=4?Z+-Oxrx9*modG z+8u9a-#n zGX9T9l=?SP`ip+$f5r9y#bWDrA3ZS9idAg%d(?|NKcY1~f z&vcvJq=HEuspv!o)ceQr)^VC6aES=0Y&>D0)~dYDBf7vCrMoXMwxC{6KDI#jl>>Oq z_;^6QUK}qK$E(Eg0&)G?aJ&he0`VD`)R+M>sGTtC)!+QX0r)lFd{2OX$gS#^<;t-D zld6F1TlGF|{IZVSq`{;*i~{-wFTY@0{g7V0TYH@B3-AvKRAo`Wnoul~(Jyaz#vW(> zJ;svrD31)-2^bWi=(d^+&(+ z*)4L!)?w|@_3NbhHQHu$OXP^I753;nXO@sSM;SUR9)D+I7Z1 zv{M2=0TksByn~B>>3D`7pXAj;>Q=_mwD3Wz6qz(NUA3Z!-()_d7ZCI^V+bnxcM|h2XGSZM_@%W+^N>z4o!uFFqega~>LV6b`AAIQnhnqT)ie){jx~C5_#O14~(n1zWOCO6N;=F2mO!)O@n_m zftr8$Zm0TXjk>ovPOT%rKO{jz;a^QC3b9PUdcALJVbnb6;zbbZch?2z39wOGB4OlD zP5>qtbM!-ts4O#Ry`Mh+xe#c*9e5%=O0U$-(MPoc^to((zW7bR0lXd$!3h!v8*Q*B9`&j9R!l_*8hxGKz z0_v*qPF4P80j)#w4~O7)rA}r;Ia<6A@HgM-e;@x$b7l(EjiyN>j;&__y|itjwUY?1 zMRmLkl_@zxZYEN%HO0$J^(#yjkRh{at~L7p(Ij3-3b69QT~hT+`-=4~Qh>=b5c6K) zDf%4DI9F>NAO`o^nvXIv!8CR6IUV@#ui#5pXo zEKmphH~}5tAp$zUqXTq+t@?C;#{}rWG)F%YKoT?bFJO=>`jp|_B0q|6{74PCD3pL#^~OB!qgXD}3@ zj!+R5wug^tQ#b!A!5AOXwr&1Z0(HnoG$6HKl+`g;K6T*1TK8700H!F^iYFyp$beZ? zCX}z*T&IC-(R=Nt=_Wm2)p*+>{ity&kJ@PK3H_&^QXOUjv{{<&QU<2y@%&eIlwbVJ-^E2erAkbU&cCY7txd;)))8r}O~+ZfHJKy9 z0s1$07`Ki%WNSAuAL>2C)*(We`-QVJq5U)TfM0e7wUG|8dU8oe>fQ%E1%&tI(=9tv z&++U>-@OayaX~=r2UdH9g+%WVHf61S!7Twcn{Xd9!=DYGq0)^m1ZHRtiJEtr2O)Ek z))J^e8-{BwnI4BYc<9CFwGs@85k@N@`_xWEl-VRzo#d=R&T!<%(_4}T6wLv9j;&B3i3Sb$V%d*lUmY~tt0!P74~H7&~{`UTGpIu6WXLU@e8bcZKwUE zEfZd9rO>*~Yo4ms{WVi?VJq5&R1JS#F5k3WJx(1Geb$SQkT5H06FPpat>`?b zpnvL~)$b%A!=R4oXm)gpMss@G3&0xr5Z_PFRFayDOgEqDU=Euu_-KZvVF81-64B_L zw_ngtE@j%rhb`my{q?*z+?KT7Db7-w84CrKM!dJ495X==Ei4510An;Y@1afM^yr|P zaPXt%+;5VAo~WhwXu_Su=s^@3Z@C(2Yil^E^ltJ=>oCKIyh|LQG-^lqEIp!0J3l5! z!Sh+OfYkQ+(xCf80Np4*z+VKUD+_N3S63VUp~Td+2A3N3OCmgeMc*p27F%fJ5$(KI zzmtHBhOCLEoQ4M~oL0~k15}9>8_xxDG!0YRDRMM`q{|s8F&M>NbM>pPl{gX?OP?P}78344;+3nVXJD0yHpqw+D+D_$yj;xfq_S4eJ@ByV0RdEqL_>s84UUy!`< zCCQBy$(vu5yzmXl>ov&}-;um=tK>#q^5$)l7k(^xJuof&l{iB3#*va69g;VXlDu%V z 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≠!FX+RNj++pOJ3nHmv#KU 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

h#jNeg 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 diff --git a/STM32F1/libraries/WireSlave/src/Wire_slave.h.gch b/STM32F1/libraries/WireSlave/src/Wire_slave.h.gch deleted file mode 100644 index 5a6345078e7abad4b9211a296cfa52568e2ed238..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9475 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 Y;dI<1)bAmJrq!61Ti)JEJwtc@2OMIdI{*Lx diff --git a/STM32F1/libraries/WireSlave/src/i2c_slave.h.gch b/STM32F1/libraries/WireSlave/src/i2c_slave.h.gch deleted file mode 100644 index 5a6345078e7abad4b9211a296cfa52568e2ed238..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9475 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 Y;dI<1)bAmJrq!61Ti)JEJwtc@2OMIdI{*Lx diff --git a/STM32F1/libraries/WireSlave/src/libmaple/i2c_slave.h.gch b/STM32F1/libraries/WireSlave/src/libmaple/i2c_slave.h.gch deleted file mode 100644 index 5a6345078e7abad4b9211a296cfa52568e2ed238..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9475 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 Y;dI<1)bAmJrq!61Ti)JEJwtc@2OMIdI{*Lx diff --git a/STM32F1/libraries/WireSlave/src/utility/WireBase_slave.h.gch b/STM32F1/libraries/WireSlave/src/utility/WireBase_slave.h.gch deleted file mode 100644 index 5a6345078e7abad4b9211a296cfa52568e2ed238..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9475 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 Y;dI<1)bAmJrq!61Ti)JEJwtc@2OMIdI{*Lx From 730711b80aced608f59020803335e6b2dc482053 Mon Sep 17 00:00:00 2001 From: lacklustrlabs Date: Thu, 14 Dec 2017 16:45:55 +0100 Subject: [PATCH 249/351] Made sure Wire_slave.h is included first --- .../WireSlave/examples/i2c_libmaple_slave/i2c_libmaple_slave.ino | 1 + 1 file changed, 1 insertion(+) diff --git a/STM32F1/libraries/WireSlave/examples/i2c_libmaple_slave/i2c_libmaple_slave.ino b/STM32F1/libraries/WireSlave/examples/i2c_libmaple_slave/i2c_libmaple_slave.ino index 23456e4..51e2dcc 100644 --- a/STM32F1/libraries/WireSlave/examples/i2c_libmaple_slave/i2c_libmaple_slave.ino +++ b/STM32F1/libraries/WireSlave/examples/i2c_libmaple_slave/i2c_libmaple_slave.ino @@ -6,6 +6,7 @@ * Created on: 4 Sep 2012 * Author: Barry Carter */ +#include #include #include From 3425506d1983c7ae41153f80a8ba7651b25492fc Mon Sep 17 00:00:00 2001 From: lacklustrlabs Date: Thu, 14 Dec 2017 17:30:35 +0100 Subject: [PATCH 250/351] spellcheccck --- STM32F1/libraries/WireSlave/library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/libraries/WireSlave/library.properties b/STM32F1/libraries/WireSlave/library.properties index 2a1c387..fd24ab1 100644 --- a/STM32F1/libraries/WireSlave/library.properties +++ b/STM32F1/libraries/WireSlave/library.properties @@ -8,4 +8,4 @@ url= architectures=STM32F1 maintainer= category=Communication -include=src/Wire_Slave.h +include=src/Wire_slave.h From c4fdf5aa63a787ce9a28ddebfab9428e7681a65b Mon Sep 17 00:00:00 2001 From: lacklustrlabs Date: Thu, 14 Dec 2017 21:04:54 +0100 Subject: [PATCH 251/351] keywords.txt Copied from ArduinoCore-sam (Due) --- STM32F1/libraries/WireSlave/keywords.txt | 31 ++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 STM32F1/libraries/WireSlave/keywords.txt diff --git a/STM32F1/libraries/WireSlave/keywords.txt b/STM32F1/libraries/WireSlave/keywords.txt new file mode 100644 index 0000000..47ffd52 --- /dev/null +++ b/STM32F1/libraries/WireSlave/keywords.txt @@ -0,0 +1,31 @@ +####################################### +# Syntax Coloring Map For Wire +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +setClock KEYWORD2 +beginTransmission KEYWORD2 +endTransmission KEYWORD2 +requestFrom KEYWORD2 +onReceive KEYWORD2 +onRequest KEYWORD2 + +####################################### +# Instances (KEYWORD2) +####################################### + +Wire KEYWORD2 +Wire1 KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + From 56e95f2773f10b1dad148d1c5e3f93b45c5b9cd2 Mon Sep 17 00:00:00 2001 From: lacklustrlabs Date: Thu, 14 Dec 2017 22:03:09 +0100 Subject: [PATCH 252/351] Steals any reference to Wire.h and redirects it to Wire_slave.h. This way we don't need to alter third party libraries. Note that Wire_slave.h must be included **before** the real Wire.h for this to work. --- STM32F1/libraries/WireSlave/src/Wire.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/STM32F1/libraries/WireSlave/src/Wire.h b/STM32F1/libraries/WireSlave/src/Wire.h index 2d3ce70..0a47d03 100644 --- a/STM32F1/libraries/WireSlave/src/Wire.h +++ b/STM32F1/libraries/WireSlave/src/Wire.h @@ -1 +1,4 @@ -#error "Something is trying to include Wire.h when Wire_slave.h is already included, they are mutually exclusive" +#pragma once +#include "Wire_slave.h" + +//#error "Something is trying to include Wire.h when Wire_slave.h is already included, they are mutually exclusive" From 6fe4a55922a30cef5f03c6a12897a682d12cf44d Mon Sep 17 00:00:00 2001 From: lacklustrlabs Date: Fri, 15 Dec 2017 11:56:01 +0100 Subject: [PATCH 253/351] Added SoftWire.h --- STM32F1/libraries/Wire/library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/libraries/Wire/library.properties b/STM32F1/libraries/Wire/library.properties index 1129fa3..2d822fe 100644 --- a/STM32F1/libraries/Wire/library.properties +++ b/STM32F1/libraries/Wire/library.properties @@ -7,4 +7,4 @@ paragraph= category=Communication url=http://www.arduino.cc/en/Reference/Wire architectures=STM32F1 -include=Wire.h +include=Wire.h,SoftWire.h From c65ec99a8d206aada5fbdc4be83e6f099c9c2a5e Mon Sep 17 00:00:00 2001 From: lacklustrlabs Date: Fri, 15 Dec 2017 13:19:37 +0100 Subject: [PATCH 254/351] Updated library.properties --- STM32F1/libraries/Wire/library.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/STM32F1/libraries/Wire/library.properties b/STM32F1/libraries/Wire/library.properties index 2d822fe..06b7aee 100644 --- a/STM32F1/libraries/Wire/library.properties +++ b/STM32F1/libraries/Wire/library.properties @@ -1,7 +1,7 @@ name=Wire version=1.0 -author=Arduino -maintainer=Arduino +author=Roger Clark +maintainer= sentence=Allows the communication between devices or sensors connected via Two Wire Interface Bus. paragraph= category=Communication From 987102c8d2d23ee09498c2b9ba36cba1057409a3 Mon Sep 17 00:00:00 2001 From: lacklustrlabs Date: Fri, 15 Dec 2017 16:00:54 +0100 Subject: [PATCH 255/351] Temporarily removed not yet functioning examples --- .../slave_receiver/slave_receiver.ino | 38 ------------------- .../examples/slave_sender/slave_sender.ino | 32 ---------------- 2 files changed, 70 deletions(-) delete mode 100644 STM32F1/libraries/WireSlave/examples/slave_receiver/slave_receiver.ino delete mode 100644 STM32F1/libraries/WireSlave/examples/slave_sender/slave_sender.ino diff --git a/STM32F1/libraries/WireSlave/examples/slave_receiver/slave_receiver.ino b/STM32F1/libraries/WireSlave/examples/slave_receiver/slave_receiver.ino deleted file mode 100644 index b430c25..0000000 --- a/STM32F1/libraries/WireSlave/examples/slave_receiver/slave_receiver.ino +++ /dev/null @@ -1,38 +0,0 @@ -// Wire Slave Receiver -// by Nicholas Zambetti - -// Demonstrates use of the Wire library -// Receives data as an I2C/TWI slave device -// Refer to the "Wire Master Writer" example for use with this - -// Created 29 March 2006 - -// This example code is in the public domain. - - -#include - -void setup() -{ - Wire.begin(4); // join i2c bus with address #4 - Wire.onReceive(receiveEvent); // register event - Serial.begin(9600); // start serial for output -} - -void loop() -{ - delay(100); -} - -// function that executes whenever data is received from master -// this function is registered as an event, see setup() -void receiveEvent(int howMany) -{ - while(1 < Wire.available()) // loop through all but the last - { - char c = Wire.read(); // receive byte as a character - Serial.print(c); // print the character - } - int x = Wire.read(); // receive byte as an integer - Serial.println(x); // print the integer -} diff --git a/STM32F1/libraries/WireSlave/examples/slave_sender/slave_sender.ino b/STM32F1/libraries/WireSlave/examples/slave_sender/slave_sender.ino deleted file mode 100644 index fcdac14..0000000 --- a/STM32F1/libraries/WireSlave/examples/slave_sender/slave_sender.ino +++ /dev/null @@ -1,32 +0,0 @@ -// Wire Slave Sender -// by Nicholas Zambetti - -// Demonstrates use of the Wire library -// Sends data as an I2C/TWI slave device -// Refer to the "Wire Master Reader" example for use with this - -// Created 29 March 2006 - -// This example code is in the public domain. - - -#include - -void setup() -{ - Wire.begin(2); // join i2c bus with address #2 - Wire.onRequest(requestEvent); // register event -} - -void loop() -{ - delay(100); -} - -// function that executes whenever data is requested by master -// this function is registered as an event, see setup() -void requestEvent() -{ - Wire.write("hello "); // respond with message of 6 bytes - // as expected by master -} From 78f8a90a2df3f408cab28764d35113a06263295e Mon Sep 17 00:00:00 2001 From: lacklustrlabs Date: Tue, 19 Dec 2017 23:46:32 +0100 Subject: [PATCH 256/351] Fixed a master/slave mode mixup. Turns out that (sr2&I2C_SR2_MSL)!=I2C_SR2_MSL indicates slave mode after master has requested, and received, data. "MSL - Cleared by hardware after detecting a Stop condition on the bus or a loss of arbitration (ARLO=1), or by hardware when PE=0." -RM0008 --- STM32F1/libraries/WireSlave/src/i2c_slave.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/STM32F1/libraries/WireSlave/src/i2c_slave.c b/STM32F1/libraries/WireSlave/src/i2c_slave.c index 770cd3a..865949b 100644 --- a/STM32F1/libraries/WireSlave/src/i2c_slave.c +++ b/STM32F1/libraries/WireSlave/src/i2c_slave.c @@ -70,6 +70,12 @@ static inline void i2c_send_slave_addr(i2c_dev *dev, uint32 addr, uint32 rw) { #ifdef I2C_DEBUG #define NR_CRUMBS 128 +struct crumb { + uint32 event; + uint32 arg0; + uint32 arg1; + uint32 arg2; // filler to make the data fit GDB memory dump screen +}; static struct crumb crumbs[NR_CRUMBS]; static uint32 cur_crumb = 0; @@ -79,6 +85,7 @@ static inline void i2c_drop_crumb(uint32 event, uint32 arg0, uint32 arg1) { crumb->event = event; crumb->arg0 = arg0; crumb->arg1 = arg1; + crumb->arg2 = cur_crumb-1; } } #define I2C_CRUMB(event, arg0, arg1) i2c_drop_crumb(event, arg0, arg1) @@ -87,12 +94,6 @@ static inline void i2c_drop_crumb(uint32 event, uint32 arg0, uint32 arg1) { #define I2C_CRUMB(event, arg0, arg1) #endif -struct crumb { - uint32 event; - uint32 arg0; - uint32 arg1; -}; - enum { IRQ_ENTRY = 1, TXE_ONLY = 2, @@ -351,8 +352,8 @@ void _i2c_irq_handler(i2c_dev *dev) { * Add Slave support */ - /* Check to see if MSL master slave bit is set */ - if ((sr2 & I2C_SR2_MSL) != I2C_SR2_MSL) { /* 0 = slave mode 1 = master */ + /* Check to see if in slave mode */ + if (dev->config_flags&(I2C_SLAVE_DUAL_ADDRESS|I2C_SLAVE_GENERAL_CALL)) { /* Check for address match */ if (sr1 & I2C_SR1_ADDR) { From b46b7461f401a2b51259fb76b350b5748b2f564a Mon Sep 17 00:00:00 2001 From: lacklustrlabs Date: Fri, 22 Dec 2017 18:52:12 +0100 Subject: [PATCH 257/351] Merged with Wire implementation from stm32duino/Arduino_Core_STM32 --- .../SFRRanger_reader/SFRRanger_reader.ino | 2 +- .../i2c_libmaple_slave_reader.ino} | 5 - .../i2c_scanner_wire/i2c_scanner_wire.ino | 78 +++ .../examples/master_reader/master_reader.ino | 4 +- .../WireSlave/examples/selftest1/code.cpp | 68 ++ .../examples/selftest1/selftest1.ino | 16 + .../slave_receiver/slave_receiver.ino | 37 ++ .../examples/slave_sender/slave_sender.ino | 32 + .../libraries/WireSlave/src/Wire_slave.cpp | 591 +++++++++++++++--- STM32F1/libraries/WireSlave/src/Wire_slave.h | 203 ++++-- .../libraries/WireSlave/src/Wire_slave.h.gch | Bin 0 -> 9475 bytes STM32F1/libraries/WireSlave/src/i2c_slave.c | 15 +- .../WireSlave/src/utility/WireBase_slave.cpp | 145 ----- .../WireSlave/src/utility/WireBase_slave.h | 145 ----- 14 files changed, 885 insertions(+), 456 deletions(-) rename STM32F1/libraries/WireSlave/examples/{i2c_libmaple_slave/i2c_libmaple_slave.ino => i2c_libmaple_slave_reader/i2c_libmaple_slave_reader.ino} (97%) create mode 100644 STM32F1/libraries/WireSlave/examples/i2c_scanner_wire/i2c_scanner_wire.ino create mode 100644 STM32F1/libraries/WireSlave/examples/selftest1/code.cpp create mode 100644 STM32F1/libraries/WireSlave/examples/selftest1/selftest1.ino create mode 100644 STM32F1/libraries/WireSlave/examples/slave_receiver/slave_receiver.ino create mode 100644 STM32F1/libraries/WireSlave/examples/slave_sender/slave_sender.ino create mode 100644 STM32F1/libraries/WireSlave/src/Wire_slave.h.gch delete mode 100644 STM32F1/libraries/WireSlave/src/utility/WireBase_slave.cpp delete mode 100644 STM32F1/libraries/WireSlave/src/utility/WireBase_slave.h diff --git a/STM32F1/libraries/WireSlave/examples/SFRRanger_reader/SFRRanger_reader.ino b/STM32F1/libraries/WireSlave/examples/SFRRanger_reader/SFRRanger_reader.ino index 5537eca..9409bb1 100644 --- a/STM32F1/libraries/WireSlave/examples/SFRRanger_reader/SFRRanger_reader.ino +++ b/STM32F1/libraries/WireSlave/examples/SFRRanger_reader/SFRRanger_reader.ino @@ -15,7 +15,7 @@ void setup() { Wire.begin(); // join i2c bus (address optional for master) - Serial.begin(9600); // start serial communication at 9600bps + Serial.begin(115200); // start serial communication at 9600bps } int reading = 0; diff --git a/STM32F1/libraries/WireSlave/examples/i2c_libmaple_slave/i2c_libmaple_slave.ino b/STM32F1/libraries/WireSlave/examples/i2c_libmaple_slave_reader/i2c_libmaple_slave_reader.ino similarity index 97% rename from STM32F1/libraries/WireSlave/examples/i2c_libmaple_slave/i2c_libmaple_slave.ino rename to STM32F1/libraries/WireSlave/examples/i2c_libmaple_slave_reader/i2c_libmaple_slave_reader.ino index 51e2dcc..a63ff3c 100644 --- a/STM32F1/libraries/WireSlave/examples/i2c_libmaple_slave/i2c_libmaple_slave.ino +++ b/STM32F1/libraries/WireSlave/examples/i2c_libmaple_slave_reader/i2c_libmaple_slave_reader.ino @@ -8,7 +8,6 @@ */ #include #include -#include #define USE_BUFFERED_EXAMPLE 1 @@ -52,12 +51,8 @@ void functx(i2c_msg *msg){ #endif -// #define Serial Serial1 - void setup() { Serial.begin(115200); - while(!Serial) - ; Serial.println("I2C Slave example"); // attach the buffer diff --git a/STM32F1/libraries/WireSlave/examples/i2c_scanner_wire/i2c_scanner_wire.ino b/STM32F1/libraries/WireSlave/examples/i2c_scanner_wire/i2c_scanner_wire.ino new file mode 100644 index 0000000..44af4dc --- /dev/null +++ b/STM32F1/libraries/WireSlave/examples/i2c_scanner_wire/i2c_scanner_wire.ino @@ -0,0 +1,78 @@ +// -------------------------------------- +// i2c_scanner +// +// Version 1 +// This program (or code that looks like it) +// can be found in many places. +// For example on the Arduino.cc forum. +// The original author is not know. +// Version 2, Juni 2012, Using Arduino 1.0.1 +// Adapted to be as simple as possible by Arduino.cc user Krodal +// Version 3, Feb 26 2013 +// V3 by louarnold +// Version 4, March 3, 2013, Using Arduino 1.0.3 +// by Arduino.cc user Krodal. +// Changes by louarnold removed. +// Scanning addresses changed from 0...127 to 1...119, +// according to the i2c scanner by Nick Gammon +// http://www.gammon.com.au/forum/?id=10896 +// Version 5, March 28, 2013 +// As version 4, but address scans now to 127. +// A sensor seems to use address 120. +// +// This sketch tests the standard 7-bit addresses +// Devices with higher bit address might not be seen properly. +// + +#include + +//use IIC2 +//TwoWire WIRE2 (2,I2C_FAST_MODE); +//#define Wire WIRE2 + + +void setup() { + + Serial.begin(115200); + Wire.begin(); + Serial.println("\nI2C Scanner"); +} + + +void loop() { + byte error, address; + int nDevices; + + Serial.println("Scanning..."); + + nDevices = 0; + for(address = 1; address < 127; address++) { + // The i2c_scanner uses the return value of + // the Write.endTransmisstion to see if + // a device did acknowledge to the address. + + Wire.beginTransmission(address); + error = Wire.endTransmission(); + + if (error == 0) { + Serial.print("I2C device found at address 0x"); + if (address < 16) + Serial.print("0"); + Serial.println(address, HEX); + + nDevices++; + } + else if (error == 4) { + Serial.print("Unknown error at address 0x"); + if (address < 16) + Serial.print("0"); + Serial.println(address, HEX); + } + } + if (nDevices == 0) + Serial.println("No I2C devices found"); + else + Serial.println("done"); + + delay(5000); // wait 5 seconds for next scan +} diff --git a/STM32F1/libraries/WireSlave/examples/master_reader/master_reader.ino b/STM32F1/libraries/WireSlave/examples/master_reader/master_reader.ino index 4b45d12..bd914e3 100644 --- a/STM32F1/libraries/WireSlave/examples/master_reader/master_reader.ino +++ b/STM32F1/libraries/WireSlave/examples/master_reader/master_reader.ino @@ -15,12 +15,12 @@ void setup() { Wire.begin(); // join i2c bus (address optional for master) - Serial.begin(9600); // start serial for output + Serial.begin(115200); // start serial for output } void loop() { - Wire.requestFrom(2, 6); // request 6 bytes from slave device #2 + Wire.requestFrom(8, 6); // request 6 bytes from slave device #8 while(Wire.available()) // slave may send less than requested { diff --git a/STM32F1/libraries/WireSlave/examples/selftest1/code.cpp b/STM32F1/libraries/WireSlave/examples/selftest1/code.cpp new file mode 100644 index 0000000..d2bce8c --- /dev/null +++ b/STM32F1/libraries/WireSlave/examples/selftest1/code.cpp @@ -0,0 +1,68 @@ +// Wire Slave Receiver +// by Nicholas Zambetti + +// Demonstrates use of the Wire library +// Receives data as an I2C/TWI slave device +// Refer to the "Wire Master Writer" example for use with this + +// Created 29 March 2006 + +// This example code is in the public domain. + +#include +//#define Serial Serial1 + +#define MasterWire Wire +#define SlaveWire Wire1 +#define ENABLE_SLAVE +#define ENABLE_MASTER + +void receiveEvent(int howMany); + +void setup(){ + Serial.begin(115200); // start serial for output + + #ifdef ENABLE_MASTER + MasterWire.begin(); // join i2c bus #1 as master + Serial.println("Done with MasterWire.begin "); + #endif + + #ifdef ENABLE_SLAVE + SlaveWire.begin(4); // join i2c bus #2 as slave with address #4 + Serial.println("Done with SlaveWire.begin "); + #endif + + #ifdef ENABLE_SLAVE + SlaveWire.onReceive(receiveEvent); // register event + #endif +} + +void loop(){ + #ifdef ENABLE_MASTER + static byte x = 0; + Serial.print("Master writing "); + Serial.println(x); + + MasterWire.beginTransmission(4); // transmit to device #4 + MasterWire.write("x is "); // sends five bytes + MasterWire.write(x); // sends one byte + MasterWire.endTransmission(); // stop transmitting + + x++; + #endif + delay(500); +} + +// function that executes whenever data is received from master +// this function is registered as an event, see setup() +// Note that it is not advicable to call Serial.print() from within an ISR +void receiveEvent(int howMany){ + //Serial.print("Slave receving "); + while(1 < SlaveWire.available()){ // loop through all but the last + char c = SlaveWire.read(); // receive byte as a character + Serial.print(c); // print the character + } + int x = SlaveWire.read(); // receive byte as an integer + Serial.println(x); // print the integer +} + diff --git a/STM32F1/libraries/WireSlave/examples/selftest1/selftest1.ino b/STM32F1/libraries/WireSlave/examples/selftest1/selftest1.ino new file mode 100644 index 0000000..58f1e5c --- /dev/null +++ b/STM32F1/libraries/WireSlave/examples/selftest1/selftest1.ino @@ -0,0 +1,16 @@ +// Wire Slave Receiver +// by Nicholas Zambetti + +// Demonstrates use of the Wire library +// Receives data as an I2C/TWI slave device +// Refer to the "Wire Master Writer" example for use with this + +// Created 29 March 2006 + +// This example code is in the public domain. + +// The code is temporarily moved to the code.cpp. +// This makes it possible to set breakpoints in eclipse IDE. +// I'm sure that there is an Eclipse configuration that makes it +// possible for it to detect .ino files as .cpp, but I'm lazy + diff --git a/STM32F1/libraries/WireSlave/examples/slave_receiver/slave_receiver.ino b/STM32F1/libraries/WireSlave/examples/slave_receiver/slave_receiver.ino new file mode 100644 index 0000000..5d71b9a --- /dev/null +++ b/STM32F1/libraries/WireSlave/examples/slave_receiver/slave_receiver.ino @@ -0,0 +1,37 @@ +// Wire Slave Receiver +// by Nicholas Zambetti + +// Demonstrates use of the Wire library +// Receives data as an I2C/TWI slave device +// Refer to the "Wire Master Writer" example for use with this + +// Created 29 March 2006 + +// This example code is in the public domain. + + +#include +#define Serial Serial1 + +void setup(){ + Serial.begin(115200); // start serial for output + + Wire.begin(4); // join i2c bus with address #4 + Wire.onReceive(receiveEvent); // register event +} + +void loop(){ + delay(100); +} + +// function that executes whenever data is received from master +// this function is registered as an event, see setup() +// Note that it is not advicable to call Serial.print() from within an ISR +void receiveEvent(int howMany){ + while(1 < Wire.available()){ // loop through all but the last + char c = Wire.read(); // receive byte as a character + Serial.print(c); // print the character + } + int x = Wire.read(); // receive byte as an integer + Serial.println(x); // print the integer +} diff --git a/STM32F1/libraries/WireSlave/examples/slave_sender/slave_sender.ino b/STM32F1/libraries/WireSlave/examples/slave_sender/slave_sender.ino new file mode 100644 index 0000000..75add4a --- /dev/null +++ b/STM32F1/libraries/WireSlave/examples/slave_sender/slave_sender.ino @@ -0,0 +1,32 @@ +// Wire Slave Sender +// by Nicholas Zambetti + +// Demonstrates use of the Wire library +// Sends data as an I2C/TWI slave device +// Refer to the "Wire Master Reader" example for use with this + +// Created 29 March 2006 + +// This example code is in the public domain. + + +#include + +void setup() +{ + Wire.begin(8); // join i2c bus with address #8 + Wire.onRequest(requestEvent); // register event +} + +void loop() +{ + delay(100); +} + +// function that executes whenever data is requested by master +// this function is registered as an event, see setup() +void requestEvent() +{ + Wire.write("hello "); // respond with message of 6 bytes + // as expected by master +} diff --git a/STM32F1/libraries/WireSlave/src/Wire_slave.cpp b/STM32F1/libraries/WireSlave/src/Wire_slave.cpp index 93cc55f..75e753f 100644 --- a/STM32F1/libraries/WireSlave/src/Wire_slave.cpp +++ b/STM32F1/libraries/WireSlave/src/Wire_slave.cpp @@ -1,106 +1,523 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 LeafLabs LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file TwoWire.cpp - * @author Trystan Jones - * @brief Wire library, uses the hardware I2C available in the Maple to - * interact with I2C slave devices. - */ - /* - * Library created by crenn to use the new WireBase system and allow Arduino - * users easy interaction with the I2C Hardware in a familiar method. + TwoWire.cpp - TWI/I2C library for Wiring & Arduino + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts */ +extern "C" { + #include + #include + #include +} + #include "Wire_slave.h" +#include "wirish.h" +#include -uint8 TwoWire::process(uint8 stop) { - int8 res = i2c_master_xfer(sel_hard, &itc_msg, 1, 0); - if (res == I2C_ERROR_PROTOCOL) { - if (sel_hard->error_flags & I2C_SR1_AF) { /* NACK */ - res = (sel_hard->error_flags & I2C_SR1_ADDR ? ENACKADDR : - ENACKTRNS); - } else if (sel_hard->error_flags & I2C_SR1_OVR) { /* Over/Underrun */ - res = EDATA; - } else { /* Bus or Arbitration error */ - res = EOTHER; - } - i2c_disable(sel_hard); - i2c_master_enable(sel_hard, (I2C_BUS_RESET | dev_flags)); - } - return res; +#define BUFFER_LENGTH 32 + +#define MASTER_ADDRESS 0x33 +// Constructors //////////////////////////////////////////////////////////////// + +TwoWire::TwoWire(i2c_dev* i2cDevice) : + sel_hard(i2cDevice), + rxBuffer(nullptr), + rxBufferAllocated(0), + rxBufferIndex(0), + rxBufferLength(0), + txBuffer(nullptr), + txBufferAllocated(0), + txBufferIndex(0), + txBufferLength(0), + transmitting(false), + master(true), + dev_flags(0), + itc_msg(), + itc_slave_msg(), + user_onRequest(nullptr), + user_onReceive(nullptr) { } -uint8 TwoWire::process(){ - return process(true); +// Public Methods ////////////////////////////////////////////////////////////// + +void TwoWire::begin(void) { + begin(MASTER_ADDRESS); } -// TODO: Add in Error Handling if devsel is out of range for other Maples -TwoWire::TwoWire(uint8 dev_sel, uint8 flags) { - if (dev_sel == 1) { - sel_hard = I2C1; - } else if (dev_sel == 2) { - sel_hard = I2C2; - } else { - ASSERT(1); - } - dev_flags = flags; -} +void TwoWire::begin(uint8_t address){ -TwoWire::~TwoWire() { - i2c_disable(sel_hard); - sel_hard = 0; -} + rxBufferIndex = 0; + rxBufferLength = 0; + allocateRxBuffer(BUFFER_LENGTH); -void TwoWire::begin(uint8 self_addr) { + txBufferIndex = 0; + txBufferLength = 0; + allocateTxBuffer(BUFFER_LENGTH); + + transmitting = 0; + + master = (address == MASTER_ADDRESS); + + // Set default speed to 100KHz + if (master) { + dev_flags = 0; i2c_master_enable(sel_hard, dev_flags); + } else { + // TODO: I2C_SLAVE_DUAL_ADDRESS ? + dev_flags = I2C_SLAVE_GENERAL_CALL | I2C_SLAVE_USE_RX_BUFFER | + I2C_SLAVE_USE_TX_BUFFER; + + itc_slave_msg.addr = address; + itc_slave_msg.flags = 0; + itc_slave_msg.data = rxBuffer; + itc_slave_msg.length = 0; + itc_slave_msg.flags = 0; + + // TODO why does enable only work before setting IRS and address? + i2c_slave_enable(sel_hard, dev_flags); + + if (sel_hard==I2C1){ + // attach receive handler + i2c_slave_attach_recv_handler(sel_hard, &itc_slave_msg, onReceiveService1); + // attach transmit handler + i2c_slave_attach_transmit_handler(sel_hard, &itc_slave_msg, onRequestService1); + } + #if WIRE_INTERFACES_COUNT > 1 + else if (sel_hard==I2C2){ + // attach receive handler + i2c_slave_attach_recv_handler(sel_hard, &itc_slave_msg, onReceiveService2); + // attach transmit handler + i2c_slave_attach_transmit_handler(sel_hard, &itc_slave_msg, onRequestService2); + } + #endif + + i2c_slave_set_own_address(sel_hard, address); + } } -void TwoWire::end() { +void TwoWire::begin(int address) { + begin((uint8_t) address); +} + +void TwoWire::end(void) { + free(txBuffer); + txBuffer = nullptr; + txBufferAllocated = 0; + free(rxBuffer); + rxBuffer = nullptr; + rxBufferAllocated = 0; + i2c_peripheral_disable(sel_hard); + i2c_master_release_bus(sel_hard); // TODO is this required? +} + +void TwoWire::setClock(uint32_t frequencyHz) { + switch (frequencyHz) { + case 400000: + dev_flags |= I2C_FAST_MODE; // set FAST_MODE bit + break; + case 100000: + default: + dev_flags &= ~I2C_FAST_MODE; // clear FAST_MODE bit + break; + } + if (sel_hard->regs->CR1 & I2C_CR1_PE){ i2c_disable(sel_hard); - sel_hard = 0; + i2c_master_enable(sel_hard, dev_flags); + } } -void TwoWire::setClock(uint32_t frequencyHz) -{ - switch(frequencyHz) - { - case 400000: - dev_flags |= I2C_FAST_MODE;// set FAST_MODE bit - break; - case 100000: - default: - dev_flags &= ~I2C_FAST_MODE;// clear FAST_MODE bit - break; - } - if (sel_hard->regs->CR1 & I2C_CR1_PE){ - i2c_disable(sel_hard); - i2c_master_enable(sel_hard, dev_flags); - } +uint8 TwoWire::process(bool stop) { + int8 res = i2c_master_xfer(sel_hard, &itc_msg, 1, 0); + + if (res == I2C_ERROR_PROTOCOL) { + if (sel_hard->error_flags & I2C_SR1_AF) { /* NACK */ + res = (sel_hard->error_flags & I2C_SR1_ADDR ? ENACKADDR : ENACKTRNS); + } else if (sel_hard->error_flags & I2C_SR1_OVR) { /* Over/Underrun */ + res = EDATA; + } else { /* Bus or Arbitration error */ + res = EOTHER; + } + i2c_disable(sel_hard); + i2c_master_enable(sel_hard, (I2C_BUS_RESET | dev_flags)); + } + + return res; } -TwoWire Wire(1); +//TODO: Add the ability to queue messages (adding a boolean to end of function +// call, allows for the Arduino style to stay while also giving the flexibility +// to bulk send +uint8 TwoWire::requestFrom(uint8_t address, uint8_t num_bytes, + uint32_t iaddress, uint8_t isize, uint8_t sendStop) { + + ASSERT(master); + + allocateRxBuffer(num_bytes); + // error if no memory block available to allocate the buffer + if (rxBuffer == nullptr) { + return EDATA; + } + + // reset tx buffer iterator vars + rxBufferIndex = 0; + rxBufferLength = 0; + + if (num_bytes > BUFFER_LENGTH) { + num_bytes = BUFFER_LENGTH; + } + + itc_msg.addr = address; + itc_msg.flags = I2C_MSG_READ; + itc_msg.length = num_bytes; + itc_msg.data = &rxBuffer[rxBufferIndex]; + process(sendStop); // TODO deal with to the return value + + // TODO handle iaddress & isize + rxBufferLength += itc_msg.xferred; + itc_msg.flags = 0; + + return rxBufferLength; +} + +uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, + uint8_t sendStop) { + // TODO shouldn't this set flag |= I2C_MSG_10BIT_ADDR ??? + return requestFrom((uint8_t) address, (uint8_t) quantity, (uint32_t) 0, + (uint8_t) 0, sendStop); +} + +uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity) { + return requestFrom((uint8_t) address, (uint8_t) quantity, (uint32_t) 0, + (uint8_t) 0, (uint8_t) true); +} + +uint8_t TwoWire::requestFrom(int address, int quantity) { + return requestFrom((uint8_t) address, (uint8_t) quantity, (uint32_t) 0, + (uint8_t) 0, (uint8_t) true); +} + +uint8_t TwoWire::requestFrom(int address, int quantity, + int sendStop) { + return requestFrom((uint8_t) address, (uint8_t) quantity, (uint32_t) 0, + (uint8_t) 0, (bool) sendStop); +} + +void TwoWire::beginTransmission(uint8_t address) { + + // indicate that we are transmitting + transmitting = 1; + + // reset tx buffer iterator vars + txBufferIndex = 0; + txBufferLength = 0; + + itc_msg.addr = address; + itc_msg.data = &txBuffer[txBufferIndex]; + itc_msg.length = 0; + itc_msg.flags = 0; + +} + +void TwoWire::beginTransmission(int address) { + beginTransmission((uint8_t) address); +} + +// +// Originally, 'endTransmission' was an f(void) function. +// It has been modified to take one parameter indicating +// whether or not a STOP should be performed on the bus. +// Calling endTransmission(false) allows a sketch to +// perform a repeated start. +// +// WARNING: Nothing in the library keeps track of whether +// the bus tenure has been properly ended with a STOP. It +// is very possible to leave the bus in a hung state if +// no call to endTransmission(true) is made. Some I2C +// devices will behave oddly if they do not see a STOP. +// +uint8_t TwoWire::endTransmission(uint8_t sendStop) { + //UNUSED(sendStop); + int8_t ret = 4; + + if (master == true) { + + itc_msg.data = txBuffer; + itc_msg.length = txBufferLength; + itc_msg.flags = 0; + ret = process(sendStop); // Changed so that the return value from process is returned by this function see also the return line below + txBufferIndex = 0; + + // reset Tx buffer + resetTxBuffer(); // TODO why? isn't this just unesssesary? + + // reset tx buffer iterator vars + txBufferIndex = 0; + txBufferLength = 0; + + // indicate that we are done transmitting + transmitting = 0; + } + + return ret; +} + +// This provides backwards compatibility with the original +// definition, and expected behaviour, of endTransmission +// + +uint8_t TwoWire::endTransmission(void) { + return endTransmission(true); +} + +// must be called in: +// slave tx event callback +// or after beginTransmission(address) +size_t TwoWire::write(uint8_t data) { + if (!transmitting && master) { + return 0; + } else { + // in master transmitter mode or slave tx event callback + allocateTxBuffer(txBufferLength + 1); + // error if no memory block available to allocate the buffer + if (txBuffer == nullptr) { + setWriteError(); + return 0; + } + // put byte in tx buffer + txBuffer[txBufferIndex] = data; + ++txBufferIndex; + // update amount in buffer + txBufferLength = txBufferIndex; + } + return 1; +} + +/** + * @brief This function must be called in slave Tx event callback or after + * beginTransmission() and before endTransmission(). + * @param pdata: pointer to the buffer data + * @param quantity: number of bytes to write + * @retval number of bytes ready to write. + */ +size_t TwoWire::write(const uint8_t *data, size_t quantity) { + if (!transmitting && master) { + return 0; + } else { + // in master transmitter mode or slave Tx event callback + allocateTxBuffer(txBufferLength + quantity); + // error if no memory block available to allocate the buffer + if (txBuffer == nullptr) { + setWriteError(); + return 0; + } + // put bytes in tx buffer + memcpy(&(txBuffer[txBufferIndex]), data, quantity); + txBufferIndex = txBufferIndex + quantity; + // update amount in buffer + txBufferLength = txBufferIndex; + return quantity; + } + return 0; +} + +// must be called in: +// slave rx event callback +// or after requestFrom(address, numBytes) +int TwoWire::available(void) { + return rxBufferLength - rxBufferIndex; +} + +// must be called in: +// slave rx event callback +// or after requestFrom(address, numBytes) +int TwoWire::read(void) { + int value = -1; + + // get each successive byte on each call + if (rxBufferIndex < rxBufferLength) { + value = rxBuffer[rxBufferIndex]; + ++rxBufferIndex; + + /* Commented as not I think it is not useful + * but kept to show that it is possible to + * reset rx buffer when no more data available */ + /*if(rxBufferIndex == rxBufferLength) { + resetRxBuffer(); + }*/ + } + + return value; +} + +// must be called in: +// slave rx event callback +// or after requestFrom(address, numBytes) +int TwoWire::peek(void) { + int value = -1; + + if (rxBufferIndex < rxBufferLength) { + value = rxBuffer[rxBufferIndex]; + } + + return value; +} + +void TwoWire::flush(void) { + rxBufferIndex = 0; + rxBufferLength = 0; + resetRxBuffer(); + txBufferIndex = 0; + txBufferLength = 0; + resetTxBuffer(); +} + +// behind the scenes function that is called when data is received +void __attribute__((always_inline)) TwoWire::onReceiveService(i2c_msg* msg) { + // don't bother if user hasn't registered a callback + if (!user_onReceive) { + return; + } + + // don't bother if rx buffer is in use by a master requestFrom() op + // i know this drops data, but it allows for slight stupidity + // meaning, they may not have read all the master requestFrom() data yet + if (rxBufferIndex < rxBufferLength) { + return; + } + // copy twi rx buffer into local read buffer + // this enables new reads to happen in parallel + // + // TODO: Something is strange here, isn't msg->data==rxBuffer? nope, itsnot + // + memcpy(rxBuffer, msg->data, msg->length); + // set rx iterator vars + rxBufferIndex = 0; + rxBufferLength = msg->length; + // alert user program + user_onReceive(msg->length); +} + +// behind the scenes function that is called when data is requested +void __attribute__((always_inline)) TwoWire::onRequestService(i2c_msg* msg) { + // don't bother if user hasn't registered a callback + if (!user_onRequest) { + return; + } + + // reset tx buffer iterator vars + // !!! this will kill any pending pre-master sendTo() activity + txBufferIndex = 0; + txBufferLength = 0; + // alert user program + user_onRequest(); + + // update i2c_msg + msg->data = txBuffer; + msg->length = txBufferLength; + msg->xferred = 0; +} + +// sets function called on slave write +void TwoWire::onReceive(void (*function)(int)) { + user_onReceive = function; +} + +// sets function called on slave read +void TwoWire::onRequest(void (*function)(void)) { + user_onRequest = function; +} + +/** + * @brief Allocate the Rx/Tx buffer to the requested length if needed + * @note Minimum allocated size is BUFFER_LENGTH) + * @param length: number of bytes to allocate + */ +inline void TwoWire::allocateRxBuffer(size_t length) { + // By default we allocate BUFFER_LENGTH bytes. It is the min size of the buffer. + if (length < BUFFER_LENGTH) { + length = BUFFER_LENGTH; + } + if (rxBufferAllocated < length) { + rxBuffer = (uint8_t *) realloc(rxBuffer, length * sizeof(uint8_t)); + rxBufferAllocated = (rxBuffer != nullptr) ? length : 0; + } +} + +inline void TwoWire::allocateTxBuffer(size_t length) { + // By default we allocate BUFFER_LENGTH bytes. It is the min size of the buffer. + if (length < BUFFER_LENGTH) { + length = BUFFER_LENGTH; + } + if (txBufferAllocated < length) { + txBuffer = (uint8_t *) realloc(txBuffer, length * sizeof(uint8_t)); + txBufferAllocated = (txBuffer != nullptr) ? length : 0; + } +} + +/** + * @brief Reset Rx/Tx buffer content to 0 + */ +inline void TwoWire::resetRxBuffer(void) { + if (rxBuffer != nullptr) + memset(rxBuffer, 0, rxBufferAllocated); +} + +inline void TwoWire::resetTxBuffer(void) { + if (txBuffer != nullptr) + memset(txBuffer, 0, txBufferAllocated); +} + + +// Preinstantiate Objects ////////////////////////////////////////////////////// +TwoWire& Wire = TwoWire::getInstance(); //SCL:D14 SDA:D15 +#if WIRE_INTERFACES_COUNT > 1 +TwoWire& Wire1 = TwoWire::getInstance1(); //SCL: D1 SDA: D0 +#endif + +// Static methods ////////////////////////////////////////////////////////////// + +TwoWire& TwoWire::getInstance(){ + static TwoWire instance(I2C1); + return instance; +} + +#if WIRE_INTERFACES_COUNT > 1 +TwoWire& TwoWire::getInstance1(){ + static TwoWire instance(I2C2); + return instance; +} +#endif + +// onRequestServiceX and onReceiveServiceX can't be inline since they +// are exclusively called via a function pointer +void TwoWire::onRequestService1(i2c_msg* msg) { + Wire.onRequestService(msg); +} + +void TwoWire::onReceiveService1(i2c_msg* msg) { + Wire.onReceiveService(msg); +} + +#if WIRE_INTERFACES_COUNT > 1 +void TwoWire::onRequestService2(i2c_msg* msg) { + Wire1.onRequestService(msg); +} +void TwoWire::onReceiveService2(i2c_msg* msg) { + Wire1.onReceiveService(msg); +} +#endif diff --git a/STM32F1/libraries/WireSlave/src/Wire_slave.h b/STM32F1/libraries/WireSlave/src/Wire_slave.h index dbe2a4e..ff71228 100644 --- a/STM32F1/libraries/WireSlave/src/Wire_slave.h +++ b/STM32F1/libraries/WireSlave/src/Wire_slave.h @@ -1,78 +1,149 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 LeafLabs LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file Wire.h - * @author Trystan Jones - * @brief Wire library, uses the hardware I2C available in the Maple to - * interact with I2C slave devices. - */ - /* - * Library created by crenn to use the new WireBase system and allow Arduino - * users easy interaction with the I2C Hardware in a familiar method. + TwoWire.h - TWI/I2C library for Arduino & Wiring + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts */ -#ifndef _TWOWIRE_H_ -#define _TWOWIRE_H_ +#ifndef TwoWire_h +#define TwoWire_h -#include "utility/WireBase_slave.h" -#include "wirish.h" +#include +#include "Stream.h" +#include "Arduino.h" #include -class TwoWire : public WireBase { + +// WIRE_HAS_END means Wire has end() +#ifndef WIRE_HAS_END +#define WIRE_HAS_END 1 +#endif + +#ifndef WIRE_INTERFACES_COUNT +#define WIRE_INTERFACES_COUNT 2 +#endif + +/* return codes from endTransmission() */ +typedef enum EndTranmissionCodes { + SUCCESS = 0, /* transmission was successful */ + EDATA = 1, /* too much data */ + ENACKADDR = 2, /* received nack on transmit of address */ + ENACKTRNS = 3, /* received nack on transmit of data */ + EOTHER = 4, /* other error */ +} EndTranmissionCodes; + +class TwoWire: public Stream { private: - i2c_dev* sel_hard; - uint8 dev_flags; -protected: - /* - * Processes the incoming I2C message defined by WireBase to the - * hardware. If an error occured, restart the I2C device. - */ - uint8 process(uint8); - uint8 process(); + i2c_dev* sel_hard; + + uint8_t *rxBuffer; // lazy allocation + uint8_t rxBufferAllocated; + uint8_t rxBufferIndex; + uint8_t rxBufferLength; + + uint8_t *txBuffer; // lazy allocation + uint8_t txBufferAllocated; + uint8_t txBufferIndex; + uint8_t txBufferLength; + + uint8_t transmitting; + + bool master; + + uint8 dev_flags; + i2c_msg itc_msg; + i2c_msg itc_slave_msg; + + void (*user_onRequest)(void); + void (*user_onReceive)(int); + + void allocateRxBuffer(size_t length); + void allocateTxBuffer(size_t length); + + void resetRxBuffer(void); + void resetTxBuffer(void); + uint8 process(bool stop = true); // wrapper for i2c_master_xfer + + inline void __attribute__((always_inline)) onReceiveService(i2c_msg* msg); + inline void __attribute__((always_inline)) onRequestService(i2c_msg* msg); + + static void onRequestService1(i2c_msg*); + static void onReceiveService1(i2c_msg*); + #if WIRE_INTERFACES_COUNT > 1 + static void onRequestService2(i2c_msg*); + static void onReceiveService2(i2c_msg*); + #endif + + TwoWire(i2c_dev* i2cDevice); + TwoWire() = delete; + TwoWire(const TwoWire&) = delete; + TwoWire& operator=(const TwoWire&) = delete; + TwoWire(TwoWire&&) = delete; + TwoWire& operator=(TwoWire&&) = delete; + public: - /* - * Check if devsel is within range and enable selected I2C interface with - * passed flags - */ - TwoWire(uint8, uint8 = 0); + static TwoWire& getInstance(); + #if WIRE_INTERFACES_COUNT > 1 + static TwoWire& getInstance1(); + #endif - /* - * Shuts down (disables) the hardware I2C - */ - void end(); + void begin(); + void begin(uint8_t); + void begin(int); + void end(); + void setClock(uint32_t); + void beginTransmission(uint8_t); + void beginTransmission(int); + uint8_t endTransmission(void); + uint8_t endTransmission(uint8_t); - void setClock(uint32_t frequencyHz); - /* - * Disables the I2C device and remove the device address. - */ - ~TwoWire(); + uint8_t requestFrom(uint8_t, uint8_t); + uint8_t requestFrom(uint8_t, uint8_t, uint8_t); + uint8_t requestFrom(uint8_t, uint8_t, uint32_t, uint8_t, uint8_t); + uint8_t requestFrom(int, int); + uint8_t requestFrom(int, int, int); - void begin(uint8 = 0x00); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *, size_t); + virtual int available(void); + virtual int read(void); + virtual int peek(void); + virtual void flush(void); + void onReceive(void (*)(int)); + void onRequest(void (*)(void)); + + inline size_t write(unsigned long n) { + return write((uint8_t) n); + } + inline size_t write(long n) { + return write((uint8_t) n); + } + inline size_t write(unsigned int n) { + return write((uint8_t) n); + } + inline size_t write(int n) { + return write((uint8_t) n); + } + using Print::write; }; -extern TwoWire Wire; -#endif // _TWOWIRE_H_ + +extern TwoWire& Wire; +#if WIRE_INTERFACES_COUNT > 1 +extern TwoWire& Wire1; +#endif + +#endif // TwoWire_h diff --git a/STM32F1/libraries/WireSlave/src/Wire_slave.h.gch b/STM32F1/libraries/WireSlave/src/Wire_slave.h.gch new file mode 100644 index 0000000000000000000000000000000000000000..5a6345078e7abad4b9211a296cfa52568e2ed238 GIT binary patch literal 9475 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 Y;dI<1)bAmJrq!61Ti)JEJwtc@2OMIdI{*Lx literal 0 HcmV?d00001 diff --git a/STM32F1/libraries/WireSlave/src/i2c_slave.c b/STM32F1/libraries/WireSlave/src/i2c_slave.c index 865949b..82ade9a 100644 --- a/STM32F1/libraries/WireSlave/src/i2c_slave.c +++ b/STM32F1/libraries/WireSlave/src/i2c_slave.c @@ -158,6 +158,7 @@ void i2c_bus_reset(const i2c_dev *dev) { * @param dev Device to initialize. */ void i2c_init(i2c_dev *dev) { + rcc_reset_dev(dev->clk_id); rcc_clk_enable(dev->clk_id); _i2c_irq_priority_fixup(dev); @@ -197,8 +198,10 @@ void i2c_master_enable(i2c_dev *dev, uint32 flags) { i2c_init(dev); i2c_config_gpios(dev); - /* Configure clock and rise time */ - set_ccr_trise(dev, flags); + /* Configure clock and rise time, but only if in master mode */ + if (!(flags & (I2C_SLAVE_DUAL_ADDRESS|I2C_SLAVE_GENERAL_CALL))) { + set_ccr_trise(dev, flags); + } /* Enable event and buffer interrupts */ nvic_irq_enable(dev->ev_nvic_line); @@ -245,8 +248,9 @@ void i2c_master_enable(i2c_dev *dev, uint32 flags) { * Callback will be called before tx */ void i2c_slave_enable(i2c_dev *dev, uint32 flags) { + // TODO: Figure out why i2c_disable(I2C2) causes a crash when I2C1 is enabled i2c_disable(dev); - i2c_master_enable(dev, dev->config_flags | flags); + i2c_master_enable(dev, flags); } /** @@ -329,7 +333,8 @@ static inline int32 wait_for_state_change(i2c_dev *dev, */ /* - * IRQ handler for I2C master. Handles transmission/reception. + * IRQ handler for I2C master and slave. + * Handles transmission/reception. */ void _i2c_irq_handler(i2c_dev *dev) { /* WTFs: @@ -676,7 +681,7 @@ void _i2c_irq_error_handler(i2c_dev *dev) { I2C_SR1_OVR); /* Are we in slave mode? */ - if ((dev->regs->SR2 & I2C_SR2_MSL) != I2C_SR2_MSL) { + if (dev->config_flags & (I2C_SLAVE_DUAL_ADDRESS|I2C_SLAVE_GENERAL_CALL)) { /* Check to see if the master device did a NAK on the last bit * This is perfectly valid for a master to do this on the bus. * We ignore this. Any further error processing takes us into dead diff --git a/STM32F1/libraries/WireSlave/src/utility/WireBase_slave.cpp b/STM32F1/libraries/WireSlave/src/utility/WireBase_slave.cpp deleted file mode 100644 index a309211..0000000 --- a/STM32F1/libraries/WireSlave/src/utility/WireBase_slave.cpp +++ /dev/null @@ -1,145 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 LeafLabs LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file WireBase.cpp - * @author Trystan Jones - * @brief Wire library, following the majority of the interface from Arduino. - * Provides a 'standard' interface to I2C (two-wire) communication for - * derived classes. - */ - -/* - * Library created by crenn to allow a system which would provide users the - * 'standardised' Arduino method for interfacing with I2C devices regardless of - * whether it is I2C hardware or emulating software. - */ - -#include "WireBase_slave.h" -#include "wirish.h" - -void WireBase::begin(uint8 self_addr) { - tx_buf_idx = 0; - tx_buf_overflow = false; - rx_buf_idx = 0; - rx_buf_len = 0; -} - -void WireBase::beginTransmission(uint8 slave_address) { - itc_msg.addr = slave_address; - itc_msg.data = &tx_buf[tx_buf_idx]; - itc_msg.length = 0; - itc_msg.flags = 0; -} - -void WireBase::beginTransmission(int slave_address) { - beginTransmission((uint8)slave_address); -} - -uint8 WireBase::endTransmission(bool stop) { - uint8 retVal; - if (tx_buf_overflow) { - return EDATA; - } - retVal = process(stop);// Changed so that the return value from process is returned by this function see also the return line below - tx_buf_idx = 0; - tx_buf_overflow = false; - return retVal;//SUCCESS; -} - -uint8 WireBase::endTransmission(){ - endTransmission(true); -} - -//TODO: Add the ability to queue messages (adding a boolean to end of function -// call, allows for the Arduino style to stay while also giving the flexibility -// to bulk send -uint8 WireBase::requestFrom(uint8 address, int num_bytes) { - if (num_bytes > BUFFER_LENGTH) { - num_bytes = BUFFER_LENGTH; - } - itc_msg.addr = address; - itc_msg.flags = I2C_MSG_READ; - itc_msg.length = num_bytes; - itc_msg.data = &rx_buf[rx_buf_idx]; - process(); - rx_buf_len += itc_msg.xferred; - itc_msg.flags = 0; - return rx_buf_len; -} - -uint8 WireBase::requestFrom(int address, int numBytes) { - return WireBase::requestFrom((uint8)address, numBytes); -} - -void WireBase::write(uint8 value) { - if (tx_buf_idx == BUFFER_LENGTH) { - tx_buf_overflow = true; - return; - } - tx_buf[tx_buf_idx++] = value; - itc_msg.length++; -} - -void WireBase::write(uint8* buf, int len) { - for (uint8 i = 0; i < len; i++) { - write(buf[i]); - } -} - -void WireBase::write(int value) { - write((uint8)value); -} - -void WireBase::write(int* buf, int len) { - write((uint8*)buf, (uint8)len); -} - -void WireBase::write(char* buf) { - uint8 *ptr = (uint8*)buf; - while (*ptr) { - write(*ptr); - ptr++; - } -} - -uint8 WireBase::available() { - return rx_buf_len - rx_buf_idx; -} - -uint8 WireBase::read() { - if (rx_buf_idx == rx_buf_len) { - rx_buf_idx = 0; - rx_buf_len = 0; - return 0; - } else if (rx_buf_idx == (rx_buf_len-1)) { - uint8 temp = rx_buf[rx_buf_idx]; - rx_buf_idx = 0; - rx_buf_len = 0; - return temp; - } - return rx_buf[rx_buf_idx++]; -} diff --git a/STM32F1/libraries/WireSlave/src/utility/WireBase_slave.h b/STM32F1/libraries/WireSlave/src/utility/WireBase_slave.h deleted file mode 100644 index 31f3f8c..0000000 --- a/STM32F1/libraries/WireSlave/src/utility/WireBase_slave.h +++ /dev/null @@ -1,145 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 LeafLabs LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file WireBase.h - * @author Trystan Jones - * @brief Wire library, following the majority of the interface from Arduino. - * Provides a 'standard' interface to I2C (two-wire) communication for - * derived classes. - */ - -/* - * Library created by crenn to allow a system which would provide users the - * 'standardised' Arduino method for interfacing with I2C devices regardless of - * whether it is I2C hardware or emulating software. - */ - -#ifndef _WIREBASE_H_ -#define _WIREBASE_H_ - -#include "wirish.h" -#include - -#define BUFFER_LENGTH 32 - -/* return codes from endTransmission() */ -#define SUCCESS 0 /* transmission was successful */ -#define EDATA 1 /* too much data */ -#define ENACKADDR 2 /* received nack on transmit of address */ -#define ENACKTRNS 3 /* received nack on transmit of data */ -#define EOTHER 4 /* other error */ - -class WireBase { // Abstraction is awesome! -protected: - i2c_msg itc_msg; - uint8 rx_buf[BUFFER_LENGTH]; /* receive buffer */ - uint8 rx_buf_idx; /* first unread idx in rx_buf */ - uint8 rx_buf_len; /* number of bytes read */ - - uint8 tx_buf[BUFFER_LENGTH]; /* transmit buffer */ - uint8 tx_buf_idx; // next idx available in tx_buf, -1 overflow - boolean tx_buf_overflow; - - // Force derived classes to define process function - virtual uint8 process(uint8) = 0; - virtual uint8 process() = 0; -public: - WireBase() {} - ~WireBase() {} - - /* - * Initialises the class interface - */ - // Allow derived classes to overwrite begin function - virtual void begin(uint8 = 0x00); - - /* - * Sets up the transmission message to be processed - */ - void beginTransmission(uint8); - - /* - * Allow only 8 bit addresses to be used - */ - void beginTransmission(int); - - /* - * Call the process function to process the message if the TX - * buffer has not overflowed. - */ - uint8 endTransmission(bool); - uint8 endTransmission(void); - - /* - * Request bytes from a slave device and process the request, - * storing into the receiving buffer. - */ - uint8 requestFrom(uint8, int); - - /* - * Allow only 8 bit addresses to be used when requesting bytes - */ - uint8 requestFrom(int, int); - - /* - * Stack up bytes to be sent when transmitting - */ - void write(uint8); - - /* - * Stack up bytes from the array to be sent when transmitting - */ - void write(uint8*, int); - - /* - * Ensure that a sending data will only be 8-bit bytes - */ - void write(int); - - /* - * Ensure that an array sending data will only be 8-bit bytes - */ - void write(int*, int); - - /* - * Stack up bytes from a string to be sent when transmitting - */ - void write(char*); - - /* - * Return the amount of bytes that is currently in the receiving buffer - */ - uint8 available(); - - /* - * Return the value of byte in the receiving buffer that is currently being - * pointed to - */ - uint8 read(); -}; - -#endif // _WIREBASE_H_ From 4ad4de080fd87bcdb0f176959bd74c8293ecc3e3 Mon Sep 17 00:00:00 2001 From: lacklustrlabs Date: Fri, 22 Dec 2017 20:04:24 +0100 Subject: [PATCH 258/351] Saved some 50K flash memory by modifying the singleton implementation --- STM32F1/libraries/WireSlave/src/Wire_slave.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/STM32F1/libraries/WireSlave/src/Wire_slave.cpp b/STM32F1/libraries/WireSlave/src/Wire_slave.cpp index 75e753f..2cdb157 100644 --- a/STM32F1/libraries/WireSlave/src/Wire_slave.cpp +++ b/STM32F1/libraries/WireSlave/src/Wire_slave.cpp @@ -492,14 +492,20 @@ TwoWire& Wire1 = TwoWire::getInstance1(); //SCL: D1 SDA: D0 // Static methods ////////////////////////////////////////////////////////////// TwoWire& TwoWire::getInstance(){ - static TwoWire instance(I2C1); - return instance; + static TwoWire* instance = nullptr; + if (!instance) { + instance = new TwoWire(I2C1); + } + return *instance; } #if WIRE_INTERFACES_COUNT > 1 TwoWire& TwoWire::getInstance1(){ - static TwoWire instance(I2C2); - return instance; + static TwoWire* instance = nullptr; + if (!instance) { + instance = new TwoWire(I2C2); + } + return *instance; } #endif From 01c23b6a5828607734f872ddf5861f5df2797175 Mon Sep 17 00:00:00 2001 From: lacklustrlabs Date: Fri, 22 Dec 2017 20:33:00 +0100 Subject: [PATCH 259/351] Changed type of transmitting to bool (from uint8_t) --- STM32F1/libraries/WireSlave/src/Wire_slave.cpp | 6 +++--- STM32F1/libraries/WireSlave/src/Wire_slave.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/STM32F1/libraries/WireSlave/src/Wire_slave.cpp b/STM32F1/libraries/WireSlave/src/Wire_slave.cpp index 2cdb157..9bb9897 100644 --- a/STM32F1/libraries/WireSlave/src/Wire_slave.cpp +++ b/STM32F1/libraries/WireSlave/src/Wire_slave.cpp @@ -69,7 +69,7 @@ void TwoWire::begin(uint8_t address){ txBufferLength = 0; allocateTxBuffer(BUFFER_LENGTH); - transmitting = 0; + transmitting = false; master = (address == MASTER_ADDRESS); @@ -220,7 +220,7 @@ uint8_t TwoWire::requestFrom(int address, int quantity, void TwoWire::beginTransmission(uint8_t address) { // indicate that we are transmitting - transmitting = 1; + transmitting = true; // reset tx buffer iterator vars txBufferIndex = 0; @@ -270,7 +270,7 @@ uint8_t TwoWire::endTransmission(uint8_t sendStop) { txBufferLength = 0; // indicate that we are done transmitting - transmitting = 0; + transmitting = false; } return ret; diff --git a/STM32F1/libraries/WireSlave/src/Wire_slave.h b/STM32F1/libraries/WireSlave/src/Wire_slave.h index ff71228..131aceb 100644 --- a/STM32F1/libraries/WireSlave/src/Wire_slave.h +++ b/STM32F1/libraries/WireSlave/src/Wire_slave.h @@ -60,7 +60,7 @@ private: uint8_t txBufferIndex; uint8_t txBufferLength; - uint8_t transmitting; + bool transmitting; bool master; From b9dbeb69d9dee7330435af9b5e30e99be6423265 Mon Sep 17 00:00:00 2001 From: lacklustrlabs Date: Fri, 29 Dec 2017 12:04:29 +0100 Subject: [PATCH 260/351] Fixed minor example issues --- .../i2c_libmaple_slave_reader/i2c_libmaple_slave_reader.ino | 2 +- .../WireSlave/examples/slave_receiver/slave_receiver.ino | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/STM32F1/libraries/WireSlave/examples/i2c_libmaple_slave_reader/i2c_libmaple_slave_reader.ino b/STM32F1/libraries/WireSlave/examples/i2c_libmaple_slave_reader/i2c_libmaple_slave_reader.ino index a63ff3c..fd059c1 100644 --- a/STM32F1/libraries/WireSlave/examples/i2c_libmaple_slave_reader/i2c_libmaple_slave_reader.ino +++ b/STM32F1/libraries/WireSlave/examples/i2c_libmaple_slave_reader/i2c_libmaple_slave_reader.ino @@ -53,7 +53,7 @@ void functx(i2c_msg *msg){ void setup() { Serial.begin(115200); - Serial.println("I2C Slave example"); + Serial.println("libmaple I2C slave reader example"); // attach the buffer msg.data = buffer; diff --git a/STM32F1/libraries/WireSlave/examples/slave_receiver/slave_receiver.ino b/STM32F1/libraries/WireSlave/examples/slave_receiver/slave_receiver.ino index 5d71b9a..bf9f255 100644 --- a/STM32F1/libraries/WireSlave/examples/slave_receiver/slave_receiver.ino +++ b/STM32F1/libraries/WireSlave/examples/slave_receiver/slave_receiver.ino @@ -11,7 +11,6 @@ #include -#define Serial Serial1 void setup(){ Serial.begin(115200); // start serial for output From 4e820c3649fbe4238bdef67dad393967a76b6873 Mon Sep 17 00:00:00 2001 From: lacklustrlabs Date: Fri, 29 Dec 2017 12:13:17 +0100 Subject: [PATCH 261/351] Full method signatures in header file. I don't understand why anyone wants to remove useful API information from the header file. CPP files describes implementation details, header files describes the API. --- STM32F1/libraries/WireSlave/src/Wire_slave.h | 50 ++++++++++---------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/STM32F1/libraries/WireSlave/src/Wire_slave.h b/STM32F1/libraries/WireSlave/src/Wire_slave.h index 131aceb..a99ab41 100644 --- a/STM32F1/libraries/WireSlave/src/Wire_slave.h +++ b/STM32F1/libraries/WireSlave/src/Wire_slave.h @@ -69,7 +69,7 @@ private: i2c_msg itc_slave_msg; void (*user_onRequest)(void); - void (*user_onReceive)(int); + void (*user_onReceive)(int quantity); void allocateRxBuffer(size_t length); void allocateTxBuffer(size_t length); @@ -96,47 +96,49 @@ private: TwoWire& operator=(TwoWire&&) = delete; public: + // return the 'Wire' instance (using I2C1) static TwoWire& getInstance(); #if WIRE_INTERFACES_COUNT > 1 + // return the 'Wire1' instance (using I2C2) static TwoWire& getInstance1(); #endif - void begin(); - void begin(uint8_t); - void begin(int); + void begin(); // master mode + void begin(uint8_t myAddress); //slave mode + void begin(int myAddress); //slave mode void end(); - void setClock(uint32_t); - void beginTransmission(uint8_t); - void beginTransmission(int); + void setClock(uint32_t frequencyHz); + void beginTransmission(uint8_t slaveAddress); + void beginTransmission(int slaveAddress); uint8_t endTransmission(void); - uint8_t endTransmission(uint8_t); + uint8_t endTransmission(uint8_t sendStop); - uint8_t requestFrom(uint8_t, uint8_t); - uint8_t requestFrom(uint8_t, uint8_t, uint8_t); - uint8_t requestFrom(uint8_t, uint8_t, uint32_t, uint8_t, uint8_t); - uint8_t requestFrom(int, int); - uint8_t requestFrom(int, int, int); + uint8_t requestFrom(uint8_t slaveAddress, uint8_t quantity); + uint8_t requestFrom(uint8_t slaveAddress, uint8_t quantity, uint8_t sendStop); + uint8_t requestFrom(uint8_t slaveAddress, uint8_t num_bytes, uint32_t iaddress, uint8_t isize, uint8_t sendStop); + uint8_t requestFrom(int slaveAddress, int quantity); + uint8_t requestFrom(int slaveAddress, int quantity, int sendStop); - virtual size_t write(uint8_t); - virtual size_t write(const uint8_t *, size_t); + virtual size_t write(uint8_t data); + virtual size_t write(const uint8_t *data, size_t quantity); virtual int available(void); virtual int read(void); virtual int peek(void); virtual void flush(void); - void onReceive(void (*)(int)); + void onReceive(void (*)(int quantity)); void onRequest(void (*)(void)); - inline size_t write(unsigned long n) { - return write((uint8_t) n); + inline size_t write(unsigned long data) { + return write((uint8_t) data); } - inline size_t write(long n) { - return write((uint8_t) n); + inline size_t write(long data) { + return write((uint8_t) data); } - inline size_t write(unsigned int n) { - return write((uint8_t) n); + inline size_t write(unsigned int data) { + return write((uint8_t) data); } - inline size_t write(int n) { - return write((uint8_t) n); + inline size_t write(int data) { + return write((uint8_t) data); } using Print::write; }; From daf62cafcaf044836945a6d6553180b8da00e927 Mon Sep 17 00:00:00 2001 From: lacklustrlabs Date: Fri, 29 Dec 2017 12:15:26 +0100 Subject: [PATCH 262/351] Removed a redundant buffer constraint --- STM32F1/libraries/WireSlave/src/Wire_slave.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/STM32F1/libraries/WireSlave/src/Wire_slave.cpp b/STM32F1/libraries/WireSlave/src/Wire_slave.cpp index 9bb9897..5fb84f5 100644 --- a/STM32F1/libraries/WireSlave/src/Wire_slave.cpp +++ b/STM32F1/libraries/WireSlave/src/Wire_slave.cpp @@ -177,10 +177,6 @@ uint8 TwoWire::requestFrom(uint8_t address, uint8_t num_bytes, rxBufferIndex = 0; rxBufferLength = 0; - if (num_bytes > BUFFER_LENGTH) { - num_bytes = BUFFER_LENGTH; - } - itc_msg.addr = address; itc_msg.flags = I2C_MSG_READ; itc_msg.length = num_bytes; @@ -211,8 +207,7 @@ uint8_t TwoWire::requestFrom(int address, int quantity) { (uint8_t) 0, (uint8_t) true); } -uint8_t TwoWire::requestFrom(int address, int quantity, - int sendStop) { +uint8_t TwoWire::requestFrom(int address, int quantity, int sendStop) { return requestFrom((uint8_t) address, (uint8_t) quantity, (uint32_t) 0, (uint8_t) 0, (bool) sendStop); } From 2b6e1398847561b5604b397c245b01535e1168a3 Mon Sep 17 00:00:00 2001 From: lacklustrlabs Date: Fri, 1 Dec 2017 11:43:42 +0100 Subject: [PATCH 263/351] According to STM32F103 RM0008: TIMx_CCMR1::CC2S=01 -> channel is configured as input, IC2 is mapped on TI2. --- STM32F1/system/libmaple/include/libmaple/timer.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/STM32F1/system/libmaple/include/libmaple/timer.h b/STM32F1/system/libmaple/include/libmaple/timer.h index 2c83e5e..ea7484e 100644 --- a/STM32F1/system/libmaple/include/libmaple/timer.h +++ b/STM32F1/system/libmaple/include/libmaple/timer.h @@ -394,8 +394,8 @@ extern timer_dev timer14; #define TIMER_CCMR1_IC2PSC (0x3 << 10) #define TIMER_CCMR1_CC2S (0x3 << 8) #define TIMER_CCMR1_CC2S_OUTPUT (TIMER_CCMR_CCS_OUTPUT << 8) -#define TIMER_CCMR1_CC2S_INPUT_TI1 (TIMER_CCMR_CCS_INPUT_TI1 << 8) -#define TIMER_CCMR1_CC2S_INPUT_TI2 (TIMER_CCMR_CCS_INPUT_TI2 << 8) +#define TIMER_CCMR1_CC2S_INPUT_TI1 (TIMER_CCMR_CCS_INPUT_TI2 << 8) +#define TIMER_CCMR1_CC2S_INPUT_TI2 (TIMER_CCMR_CCS_INPUT_TI1 << 8) #define TIMER_CCMR1_CC2S_INPUT_TRC (TIMER_CCMR_CCS_INPUT_TRC << 8) #define TIMER_CCMR1_OC1CE (1U << TIMER_CCMR1_OC1CE_BIT) #define TIMER_CCMR1_OC1M (0x3 << 4) From 388995efbba555b742ba7652399c05c1ce1678d3 Mon Sep 17 00:00:00 2001 From: lacklustrlabs Date: Fri, 1 Dec 2017 15:55:27 +0100 Subject: [PATCH 264/351] Adhere to the format of #323 --- STM32F1/system/libmaple/include/libmaple/timer.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/STM32F1/system/libmaple/include/libmaple/timer.h b/STM32F1/system/libmaple/include/libmaple/timer.h index ea7484e..64f458f 100644 --- a/STM32F1/system/libmaple/include/libmaple/timer.h +++ b/STM32F1/system/libmaple/include/libmaple/timer.h @@ -393,10 +393,10 @@ extern timer_dev timer14; #define TIMER_CCMR1_OC2FE (1U << TIMER_CCMR1_OC2FE_BIT) #define TIMER_CCMR1_IC2PSC (0x3 << 10) #define TIMER_CCMR1_CC2S (0x3 << 8) -#define TIMER_CCMR1_CC2S_OUTPUT (TIMER_CCMR_CCS_OUTPUT << 8) -#define TIMER_CCMR1_CC2S_INPUT_TI1 (TIMER_CCMR_CCS_INPUT_TI2 << 8) -#define TIMER_CCMR1_CC2S_INPUT_TI2 (TIMER_CCMR_CCS_INPUT_TI1 << 8) -#define TIMER_CCMR1_CC2S_INPUT_TRC (TIMER_CCMR_CCS_INPUT_TRC << 8) +#define TIMER_CCMR1_CC2S_OUTPUT (0x0 << 8) +#define TIMER_CCMR1_CC2S_INPUT_TI2 (0x1 << 8) +#define TIMER_CCMR1_CC2S_INPUT_TI1 (0x2 << 8) +#define TIMER_CCMR1_CC2S_INPUT_TRC (0x3 << 8) #define TIMER_CCMR1_OC1CE (1U << TIMER_CCMR1_OC1CE_BIT) #define TIMER_CCMR1_OC1M (0x3 << 4) #define TIMER_CCMR1_IC1F (0xF << 4) From 1b8b05c883b9c3713be7ec8210af903220a58667 Mon Sep 17 00:00:00 2001 From: Lacklustrlabs Date: Tue, 23 Jan 2018 13:19:39 +0100 Subject: [PATCH 265/351] Added platform.local.txt and boards.local.txt to .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 078faf6..ef5aee5 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ other/maple-bootloader/*~ *.o *.bak *.1 +platform.local.txt +boards.local.txt From 495f3b9cb5787038eb4a1ad066576fd75fa0a0dc Mon Sep 17 00:00:00 2001 From: lacklustrlabs Date: Wed, 15 Nov 2017 23:23:37 +0100 Subject: [PATCH 266/351] Fixed 'warning: multi-line comment [-Wcomment]' --- STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c b/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c index 1f0b626..7ebd03b 100644 --- a/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c +++ b/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c @@ -62,7 +62,7 @@ #if !(defined(BOARD_maple) || defined(BOARD_maple_RET6) || \ defined(BOARD_maple_mini) || defined(BOARD_maple_native)) -//#warning USB CDC ACM relies on LeafLabs board-specific configuration.\ +//#warning USB CDC ACM relies on LeafLabs board-specific configuration. // You may have problems on non-LeafLabs boards. #endif From 6f1429175cb5723e0bf3ec09c89950ae1f5b9cff Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Wed, 24 Jan 2018 07:39:35 +1100 Subject: [PATCH 267/351] Manually committed RTClock files, due to problems with PR https://github.com/rogerclarkmelbourne/Arduino_STM32/pull/428 --- STM32F1/libraries/RTClock/src/RTClock.cpp | 2 +- STM32F1/libraries/RTClock/src/RTClock.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/STM32F1/libraries/RTClock/src/RTClock.cpp b/STM32F1/libraries/RTClock/src/RTClock.cpp index e95bead..f6907ed 100755 --- a/STM32F1/libraries/RTClock/src/RTClock.cpp +++ b/STM32F1/libraries/RTClock/src/RTClock.cpp @@ -111,7 +111,7 @@ void RTClock::breakTime(time_t timeInput, tm_t & tmm) time /= 60; // now it is hours tmm.hour = time % 24; time /= 24; // now it is days - tmm.weekday = ((time + 4) % 7); // Monday is day 1 // + 1; // Sunday is day 1 + tmm.weekday = ((time + 3) % 7); // Monday is day 1 year = 0; days = 0; diff --git a/STM32F1/libraries/RTClock/src/RTClock.h b/STM32F1/libraries/RTClock/src/RTClock.h index 71015a5..1988c9e 100755 --- a/STM32F1/libraries/RTClock/src/RTClock.h +++ b/STM32F1/libraries/RTClock/src/RTClock.h @@ -27,7 +27,7 @@ typedef struct tm_t { uint8_t year; // years since 1970 uint8_t month; // month of a year - [ 1 to 12 ] uint8_t day; // day of a month - [ 1 to 31 ] - uint8_t weekday; // day of a week (first day is Sunday) - [ 0 to 6 ] + uint8_t weekday; // day of a week (first day is Monday) - [ 0 to 6 ] uint8_t pm; // AM: 0, PM: 1 uint8_t hour; // hour of a day - [ 0 to 23 ] uint8_t minute; // minute of an hour - [ 0 to 59 ] From ccd94bd9fabad1c0d980e9b3970e282051c3bf18 Mon Sep 17 00:00:00 2001 From: aster94 Date: Wed, 24 Jan 2018 19:20:06 +0100 Subject: [PATCH 268/351] Add files via upload --- STM32F1/libraries/A_STM32_Examples/keywords.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/STM32F1/libraries/A_STM32_Examples/keywords.txt b/STM32F1/libraries/A_STM32_Examples/keywords.txt index e40a099..c553422 100644 --- a/STM32F1/libraries/A_STM32_Examples/keywords.txt +++ b/STM32F1/libraries/A_STM32_Examples/keywords.txt @@ -10,3 +10,7 @@ # Constants (LITERAL1) ####################################### +OUTPUT_OPEN_DRAIN LITERAL1 +INPUT_ANALOG LITERAL1 +INPUT_PULLDOWN LITERAL1 +PWM LITERAL1 \ No newline at end of file From 632af3ec9ff9e920b2c6bc198cc2f82fd0e14798 Mon Sep 17 00:00:00 2001 From: Vincenzo Gibiino Date: Wed, 24 Jan 2018 20:33:11 +0100 Subject: [PATCH 269/351] stm32duino now uses __IO --- STM32F1/cores/maple/libmaple/adc_f1.c | 4 +- STM32F1/cores/maple/libmaple/bkp_f1.c | 8 +- STM32F1/cores/maple/libmaple/dma.c | 2 +- STM32F1/cores/maple/libmaple/dma_f1.c | 10 +- STM32F1/cores/maple/libmaple/exti.c | 2 +- STM32F1/cores/maple/libmaple/gpio_f1.c | 4 +- STM32F1/cores/maple/libmaple/rcc.c | 4 +- STM32F1/cores/maple/libmaple/rcc_f1.c | 6 +- .../cores/maple/stm32f1/wiring_pulse_f1.cpp | 2 +- STM32F1/libraries/EEPROM/EEPROM.cpp | 42 +++--- STM32F1/libraries/EEPROM/flash_stm32.c | 4 +- .../libraries/RTClock/src/utility/rtc_util.h | 20 +-- .../WireSlave/src/libmaple/i2c_slave.h | 18 +-- STM32F1/system/libmaple/dma_private.h | 2 +- STM32F1/system/libmaple/exti_private.h | 2 +- .../system/libmaple/include/libmaple/adc.h | 40 +++--- .../system/libmaple/include/libmaple/bkp.h | 90 ++++++------ .../system/libmaple/include/libmaple/dma.h | 8 +- .../system/libmaple/include/libmaple/exti.h | 12 +- .../system/libmaple/include/libmaple/fsmc.h | 60 ++++---- .../system/libmaple/include/libmaple/i2c.h | 18 +-- .../system/libmaple/include/libmaple/iwdg.h | 8 +- .../include/libmaple/libmaple_types.h | 2 +- .../system/libmaple/include/libmaple/nvic.h | 14 +- .../system/libmaple/include/libmaple/pwr.h | 4 +- .../libmaple/include/libmaple/ring_buffer.h | 2 +- .../system/libmaple/include/libmaple/scb.h | 38 +++--- .../system/libmaple/include/libmaple/sdio.h | 28 ++-- .../system/libmaple/include/libmaple/spi.h | 18 +-- .../system/libmaple/include/libmaple/syscfg.h | 8 +- .../libmaple/include/libmaple/systick.h | 8 +- .../system/libmaple/include/libmaple/timer.h | 62 ++++----- .../system/libmaple/include/libmaple/usart.h | 14 +- STM32F1/system/libmaple/rcc_private.h | 12 +- .../libmaple/stm32f1/include/series/dac.h | 26 ++-- .../libmaple/stm32f1/include/series/dma.h | 74 +++++----- .../libmaple/stm32f1/include/series/flash.h | 16 +-- .../libmaple/stm32f1/include/series/gpio.h | 30 ++-- .../libmaple/stm32f1/include/series/rcc.h | 20 +-- .../libmaple/stm32f1/include/series/timer.h | 36 ++--- .../libmaple/stm32f2/include/series/adc.h | 6 +- .../libmaple/stm32f2/include/series/dac.h | 28 ++-- .../libmaple/stm32f2/include/series/dma.h | 128 +++++++++--------- .../libmaple/stm32f2/include/series/flash.h | 12 +- .../libmaple/stm32f2/include/series/gpio.h | 20 +-- .../libmaple/stm32f2/include/series/rcc.h | 46 +++---- .../libmaple/stm32f2/include/series/timer.h | 38 +++--- .../system/libmaple/usb/stm32f1/usb_reg_map.h | 54 ++++---- STM32F3/cores/maple/libmaple/bkp.c | 4 +- STM32F3/cores/maple/libmaple/dma.c | 2 +- STM32F3/cores/maple/libmaple/dma_private.h | 2 +- STM32F3/cores/maple/libmaple/exti.c | 2 +- STM32F3/cores/maple/libmaple/exti_private.h | 2 +- .../maple/libmaple/include/libmaple/bkp.h | 2 +- .../maple/libmaple/include/libmaple/dma.h | 8 +- .../maple/libmaple/include/libmaple/exti.h | 12 +- .../maple/libmaple/include/libmaple/fsmc.h | 60 ++++---- .../maple/libmaple/include/libmaple/iwdg.h | 8 +- .../include/libmaple/libmaple_types.h | 2 +- .../maple/libmaple/include/libmaple/nvic.h | 14 +- .../maple/libmaple/include/libmaple/pwr.h | 4 +- .../libmaple/include/libmaple/ring_buffer.h | 2 +- .../maple/libmaple/include/libmaple/scb.h | 38 +++--- .../maple/libmaple/include/libmaple/spi.h | 18 +-- .../maple/libmaple/include/libmaple/systick.h | 8 +- .../maple/libmaple/include/libmaple/timer.h | 62 ++++----- STM32F3/cores/maple/libmaple/rcc.c | 4 +- STM32F3/cores/maple/libmaple/rcc_private.h | 8 +- STM32F3/cores/maple/libmaple/stm32f3/f3_adc.c | 2 +- STM32F3/cores/maple/libmaple/stm32f3/f3_bkp.c | 2 +- STM32F3/cores/maple/libmaple/stm32f3/f3_dma.c | 6 +- .../cores/maple/libmaple/stm32f3/f3_gpio.c | 2 +- STM32F3/cores/maple/libmaple/stm32f3/f3_rcc.c | 4 +- STM32F3/cores/maple/libmaple/stm32f3/f3_spi.c | 8 +- .../libmaple/stm32f3/include/series/adc.h | 60 ++++---- .../libmaple/stm32f3/include/series/bkp.h | 32 ++--- .../libmaple/stm32f3/include/series/comp.h | 2 +- .../libmaple/stm32f3/include/series/crc.h | 10 +- .../libmaple/stm32f3/include/series/dac.h | 26 ++-- .../libmaple/stm32f3/include/series/dma.h | 70 +++++----- .../libmaple/stm32f3/include/series/flash.h | 16 +-- .../libmaple/stm32f3/include/series/fpu.h | 8 +- .../libmaple/stm32f3/include/series/gpio.h | 22 +-- .../libmaple/stm32f3/include/series/i2c.h | 22 +-- .../libmaple/stm32f3/include/series/opamp.h | 2 +- .../libmaple/stm32f3/include/series/rcc.h | 26 ++-- .../libmaple/stm32f3/include/series/syscfg.h | 8 +- .../libmaple/stm32f3/include/series/timer.h | 36 ++--- .../libmaple/stm32f3/include/series/usart.h | 22 +-- .../cores/maple/libmaple/usb/usb_reg_map.h | 54 ++++---- STM32F4/cores/maple/libmaple/adc.c | 4 +- STM32F4/cores/maple/libmaple/adc.h | 46 +++---- STM32F4/cores/maple/libmaple/bkp.c | 8 +- STM32F4/cores/maple/libmaple/bkp.h | 90 ++++++------ STM32F4/cores/maple/libmaple/dac.h | 26 ++-- STM32F4/cores/maple/libmaple/dmaF4.h | 26 ++-- STM32F4/cores/maple/libmaple/exti.h | 12 +- STM32F4/cores/maple/libmaple/flash.h | 16 +-- STM32F4/cores/maple/libmaple/fsmc.h | 60 ++++---- STM32F4/cores/maple/libmaple/gpio.h | 2 +- STM32F4/cores/maple/libmaple/gpioF4.c | 2 +- STM32F4/cores/maple/libmaple/gpio_def.h | 34 ++--- STM32F4/cores/maple/libmaple/i2c.h | 18 +-- STM32F4/cores/maple/libmaple/iwdg.h | 8 +- STM32F4/cores/maple/libmaple/libmaple_types.h | 2 +- STM32F4/cores/maple/libmaple/nvic.h | 14 +- STM32F4/cores/maple/libmaple/pwr.h | 4 +- STM32F4/cores/maple/libmaple/rccF4.c | 28 ++-- STM32F4/cores/maple/libmaple/rccF4.h | 46 +++---- STM32F4/cores/maple/libmaple/ring_buffer.h | 2 +- STM32F4/cores/maple/libmaple/scb.h | 38 +++--- STM32F4/cores/maple/libmaple/sdio.h | 28 ++-- STM32F4/cores/maple/libmaple/spi.h | 18 +-- STM32F4/cores/maple/libmaple/systick.h | 8 +- STM32F4/cores/maple/libmaple/timer.h | 98 +++++++------- STM32F4/cores/maple/libmaple/usart.h | 14 +- STM32F4/libraries/RTClock/src/RTClock.h | 40 +++--- tools/win/dfu-util-0.9-win64/dfu-prefix.exe | Bin 178765 -> 178765 bytes tools/win/dfu-util-0.9-win64/dfu-suffix.exe | Bin 179276 -> 179276 bytes .../dfu-util-0.9-win64/dfu-util-static.exe | Bin 799602 -> 799602 bytes tools/win/dfu-util-0.9-win64/dfu-util.exe | Bin 290852 -> 290852 bytes tools/win/dfu-util-0.9-win64/libusb-1.0.dll | Bin 638611 -> 638611 bytes tools/win/dfu-util.exe | Bin 1146937 -> 1146937 bytes tools/win/stlink/ST-LINK_CLI.exe | Bin 267264 -> 267264 bytes tools/win/stm32flash.exe | Bin 160128 -> 160128 bytes 125 files changed, 1252 insertions(+), 1252 deletions(-) diff --git a/STM32F1/cores/maple/libmaple/adc_f1.c b/STM32F1/cores/maple/libmaple/adc_f1.c index 5305b02..8cb4b4a 100644 --- a/STM32F1/cores/maple/libmaple/adc_f1.c +++ b/STM32F1/cores/maple/libmaple/adc_f1.c @@ -175,8 +175,8 @@ void adc_attach_interrupt(adc_dev *dev, * @param dev adc device */ void adc_calibrate(adc_dev *dev) { - __io uint32 *rstcal_bit = bb_perip(&(dev->regs->CR2), 3); - __io uint32 *cal_bit = bb_perip(&(dev->regs->CR2), 2); + __IO uint32 *rstcal_bit = bb_perip(&(dev->regs->CR2), 3); + __IO uint32 *cal_bit = bb_perip(&(dev->regs->CR2), 2); *rstcal_bit = 1; while (*rstcal_bit) diff --git a/STM32F1/cores/maple/libmaple/bkp_f1.c b/STM32F1/cores/maple/libmaple/bkp_f1.c index 01ad419..741f5eb 100644 --- a/STM32F1/cores/maple/libmaple/bkp_f1.c +++ b/STM32F1/cores/maple/libmaple/bkp_f1.c @@ -34,7 +34,7 @@ #include #include -static inline __io uint32* data_register(uint8 reg); +static inline __IO uint32* data_register(uint8 reg); bkp_dev bkp = { .regs = BKP_BASE, @@ -78,7 +78,7 @@ void bkp_disable_writes(void) { * medium-density devices, 42 on high-density devices). */ uint16 bkp_read(uint8 reg) { - __io uint32* dr = data_register(reg); + __IO uint32* dr = data_register(reg); if (!dr) { ASSERT(0); /* nonexistent register */ return 0; @@ -97,7 +97,7 @@ uint16 bkp_read(uint8 reg) { * @see bkp_enable_writes() */ void bkp_write(uint8 reg, uint16 val) { - __io uint32* dr = data_register(reg); + __IO uint32* dr = data_register(reg); if (!dr) { ASSERT(0); /* nonexistent register */ return; @@ -112,7 +112,7 @@ void bkp_write(uint8 reg, uint16 val) { */ #define NR_LOW_DRS 10 -static inline __io uint32* data_register(uint8 reg) { +static inline __IO uint32* data_register(uint8 reg) { if (reg < 1 || reg > BKP_NR_DATA_REGS) { return 0; } diff --git a/STM32F1/cores/maple/libmaple/dma.c b/STM32F1/cores/maple/libmaple/dma.c index d13de10..1dc875e 100644 --- a/STM32F1/cores/maple/libmaple/dma.c +++ b/STM32F1/cores/maple/libmaple/dma.c @@ -52,7 +52,7 @@ void dma_init(dma_dev *dev) { * Private API */ -enum dma_atype _dma_addr_type(__io void *addr) { +enum dma_atype _dma_addr_type(__IO void *addr) { switch (stm32_block_purpose((void*)addr)) { /* Notice we're treating the code block as memory here. That's * correct for addresses in Flash and in [0x0, 0x7FFFFFF] diff --git a/STM32F1/cores/maple/libmaple/dma_f1.c b/STM32F1/cores/maple/libmaple/dma_f1.c index c7c3c00..33dc0ef 100644 --- a/STM32F1/cores/maple/libmaple/dma_f1.c +++ b/STM32F1/cores/maple/libmaple/dma_f1.c @@ -86,7 +86,7 @@ static int cfg_dev_ok(dma_dev *dev, dma_tube_config *cfg) { } /* Is addr acceptable for use as DMA src/dst? */ -static int cfg_mem_ok(__io void *addr) { +static int cfg_mem_ok(__IO void *addr) { enum dma_atype atype = _dma_addr_type(addr); return atype == DMA_ATYPE_MEM || atype == DMA_ATYPE_PER; } @@ -293,7 +293,7 @@ dma_irq_cause dma_get_irq_cause(dma_dev *dev, dma_channel channel) { return DMA_TRANSFER_ERROR; } -void dma_set_mem_addr(dma_dev *dev, dma_channel channel, __io void *addr) { +void dma_set_mem_addr(dma_dev *dev, dma_channel channel, __IO void *addr) { dma_channel_reg_map *chan_regs; ASSERT_FAULT(!dma_is_channel_enabled(dev, channel)); @@ -302,7 +302,7 @@ void dma_set_mem_addr(dma_dev *dev, dma_channel channel, __io void *addr) { chan_regs->CMAR = (uint32)addr; } -void dma_set_per_addr(dma_dev *dev, dma_channel channel, __io void *addr) { +void dma_set_per_addr(dma_dev *dev, dma_channel channel, __IO void *addr) { dma_channel_reg_map *chan_regs; ASSERT_FAULT(!dma_is_channel_enabled(dev, channel)); @@ -343,9 +343,9 @@ void dma_set_per_addr(dma_dev *dev, dma_channel channel, __io void *addr) { */ void dma_setup_transfer(dma_dev *dev, dma_channel channel, - __io void *peripheral_address, + __IO void *peripheral_address, dma_xfer_size peripheral_size, - __io void *memory_address, + __IO void *memory_address, dma_xfer_size memory_size, uint32 mode) { dma_channel_reg_map *channel_regs = dma_channel_regs(dev, channel); diff --git a/STM32F1/cores/maple/libmaple/exti.c b/STM32F1/cores/maple/libmaple/exti.c index 402bec6..c8836a7 100644 --- a/STM32F1/cores/maple/libmaple/exti.c +++ b/STM32F1/cores/maple/libmaple/exti.c @@ -200,7 +200,7 @@ void exti_detach_interrupt(exti_num num) { * Private routines */ -void exti_do_select(__io uint32 *exti_cr, exti_num num, exti_cfg port) { +void exti_do_select(__IO uint32 *exti_cr, exti_num num, exti_cfg port) { uint32 shift = 4 * (num % 4); uint32 cr = *exti_cr; cr &= ~(0xF << shift); diff --git a/STM32F1/cores/maple/libmaple/gpio_f1.c b/STM32F1/cores/maple/libmaple/gpio_f1.c index 6de16f5..464683f 100644 --- a/STM32F1/cores/maple/libmaple/gpio_f1.c +++ b/STM32F1/cores/maple/libmaple/gpio_f1.c @@ -123,7 +123,7 @@ void gpio_init_all(void) { */ void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode) { gpio_reg_map *regs = dev->regs; - __io uint32 *cr = ®s->CRL + (pin >> 3); + __IO uint32 *cr = ®s->CRL + (pin >> 3); uint32 shift = (pin & 0x7) * 4; uint32 tmp = *cr; @@ -140,7 +140,7 @@ void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode) { gpio_pin_mode gpio_get_mode(gpio_dev *dev, uint8 pin) { gpio_reg_map *regs = dev->regs; - __io uint32 *cr = ®s->CRL + (pin >> 3); + __IO uint32 *cr = ®s->CRL + (pin >> 3); uint32 shift = (pin & 0x7) * 4; uint32 crMode = (*cr>>shift) & 0x0F; diff --git a/STM32F1/cores/maple/libmaple/rcc.c b/STM32F1/cores/maple/libmaple/rcc.c index 8e7d1ea..aba87c0 100644 --- a/STM32F1/cores/maple/libmaple/rcc.c +++ b/STM32F1/cores/maple/libmaple/rcc.c @@ -94,8 +94,8 @@ void rcc_switch_sysclk(rcc_sysclk_src sysclk_src) { * won't work for you. */ /* Returns the RCC register which controls the clock source. */ -static inline __io uint32* rcc_clk_reg(rcc_clk clock) { - return (__io uint32*)((__io uint8*)RCC_BASE + (clock >> 8)); +static inline __IO uint32* rcc_clk_reg(rcc_clk clock) { + return (__IO uint32*)((__IO uint8*)RCC_BASE + (clock >> 8)); } /* Returns a mask in rcc_clk_reg(clock) to be used for turning the diff --git a/STM32F1/cores/maple/libmaple/rcc_f1.c b/STM32F1/cores/maple/libmaple/rcc_f1.c index f45f670..ca67928 100644 --- a/STM32F1/cores/maple/libmaple/rcc_f1.c +++ b/STM32F1/cores/maple/libmaple/rcc_f1.c @@ -136,7 +136,7 @@ void rcc_configure_pll(rcc_pll_cfg *pll_cfg) { } void rcc_clk_enable(rcc_clk_id id) { - static __io uint32* enable_regs[] = { + static __IO uint32* enable_regs[] = { [APB1] = &RCC_BASE->APB1ENR, [APB2] = &RCC_BASE->APB2ENR, [AHB] = &RCC_BASE->AHBENR, @@ -145,7 +145,7 @@ void rcc_clk_enable(rcc_clk_id id) { } void rcc_reset_dev(rcc_clk_id id) { - static __io uint32* reset_regs[] = { + static __IO uint32* reset_regs[] = { [APB1] = &RCC_BASE->APB1RSTR, [APB2] = &RCC_BASE->APB2RSTR, }; @@ -164,7 +164,7 @@ void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider) { } void rcc_clk_disable(rcc_clk_id id) { - static __io uint32* enable_regs[] = { + static __IO uint32* enable_regs[] = { [APB1] = &RCC_BASE->APB1ENR, [APB2] = &RCC_BASE->APB2ENR, [AHB] = &RCC_BASE->AHBENR, diff --git a/STM32F1/cores/maple/stm32f1/wiring_pulse_f1.cpp b/STM32F1/cores/maple/stm32f1/wiring_pulse_f1.cpp index 5a5d835..bb7e2ad 100644 --- a/STM32F1/cores/maple/stm32f1/wiring_pulse_f1.cpp +++ b/STM32F1/cores/maple/stm32f1/wiring_pulse_f1.cpp @@ -33,7 +33,7 @@ uint32_t pulseIn( uint32_t pin, uint32_t state, uint32_t timeout ) // pulse width measuring loop and achieve finer resolution. calling // digitalRead() instead yields much coarser resolution. - __io uint32_t * const idr = portInputRegister(digitalPinToPort(pin)); + __IO uint32_t * const idr = portInputRegister(digitalPinToPort(pin)); const uint32_t bit = digitalPinToBitMask(pin); const uint32_t stateMask = (state ? bit:0); diff --git a/STM32F1/libraries/EEPROM/EEPROM.cpp b/STM32F1/libraries/EEPROM/EEPROM.cpp index 289a93a..ed4d046 100644 --- a/STM32F1/libraries/EEPROM/EEPROM.cpp +++ b/STM32F1/libraries/EEPROM/EEPROM.cpp @@ -13,10 +13,10 @@ uint16 EEPROMClass::EE_CheckPage(uint32 pageBase, uint16 status) uint32 pageEnd = pageBase + (uint32)PageSize; // Page Status not EEPROM_ERASED and not a "state" - if ((*(__io uint16*)pageBase) != EEPROM_ERASED && (*(__io uint16*)pageBase) != status) + if ((*(__IO uint16*)pageBase) != EEPROM_ERASED && (*(__IO uint16*)pageBase) != status) return EEPROM_BAD_FLASH; for(pageBase += 4; pageBase < pageEnd; pageBase += 4) - if ((*(__io uint32*)pageBase) != 0xFFFFFFFF) // Verify if slot is empty + if ((*(__IO uint32*)pageBase) != 0xFFFFFFFF) // Verify if slot is empty return EEPROM_BAD_FLASH; return EEPROM_OK; } @@ -31,9 +31,9 @@ uint16 EEPROMClass::EE_CheckPage(uint32 pageBase, uint16 status) FLASH_Status EEPROMClass::EE_ErasePage(uint32 pageBase) { FLASH_Status FlashStatus; - uint16 data = (*(__io uint16*)(pageBase)); + uint16 data = (*(__IO uint16*)(pageBase)); if ((data == EEPROM_ERASED) || (data == EEPROM_VALID_PAGE) || (data == EEPROM_RECEIVE_DATA)) - data = (*(__io uint16*)(pageBase + 2)) + 1; + data = (*(__IO uint16*)(pageBase + 2)) + 1; else data = 0; @@ -73,8 +73,8 @@ uint16 EEPROMClass::EE_CheckErasePage(uint32 pageBase, uint16 status) */ uint32 EEPROMClass::EE_FindValidPage(void) { - uint16 status0 = (*(__io uint16*)PageBase0); // Get Page0 actual status - uint16 status1 = (*(__io uint16*)PageBase1); // Get Page1 actual status + uint16 status0 = (*(__IO uint16*)PageBase0); // Get Page0 actual status + uint16 status1 = (*(__IO uint16*)PageBase1); // Get Page1 actual status if (status0 == EEPROM_VALID_PAGE && status1 == EEPROM_ERASED) return PageBase0; @@ -100,14 +100,14 @@ uint16 EEPROMClass::EE_GetVariablesCount(uint32 pageBase, uint16 skipAddress) for (pageBase += 6; pageBase < pageEnd; pageBase += 4) { - varAddress = (*(__io uint16*)pageBase); + varAddress = (*(__IO uint16*)pageBase); if (varAddress == 0xFFFF || varAddress == skipAddress) continue; count++; for(idx = pageBase + 4; idx < pageEnd; idx += 4) { - nextAddress = (*(__io uint16*)idx); + nextAddress = (*(__IO uint16*)idx); if (nextAddress == varAddress) { count--; @@ -140,7 +140,7 @@ uint16 EEPROMClass::EE_PageTransfer(uint32 newPage, uint32 oldPage, uint16 SkipA // Find first free element in new page for (newIdx = newPage + 4; newIdx < newEnd; newIdx += 4) - if ((*(__io uint32*)newIdx) == 0xFFFFFFFF) // Verify if element + if ((*(__IO uint32*)newIdx) == 0xFFFFFFFF) // Verify if element break; // contents are 0xFFFFFFFF if (newIdx >= newEnd) return EEPROM_OUT_SIZE; @@ -150,13 +150,13 @@ uint16 EEPROMClass::EE_PageTransfer(uint32 newPage, uint32 oldPage, uint16 SkipA for (; oldIdx > oldEnd; oldIdx -= 4) { - address = *(__io uint16*)oldIdx; + address = *(__IO uint16*)oldIdx; if (address == 0xFFFF || address == SkipAddress) continue; // it's means that power off after write data found = 0; for (idx = newPage + 6; idx < newIdx; idx += 4) - if ((*(__io uint16*)(idx)) == address) + if ((*(__IO uint16*)(idx)) == address) { found = 1; break; @@ -167,7 +167,7 @@ uint16 EEPROMClass::EE_PageTransfer(uint32 newPage, uint32 oldPage, uint16 SkipA if (newIdx < newEnd) { - data = (*(__io uint16*)(oldIdx - 2)); + data = (*(__IO uint16*)(oldIdx - 2)); FlashStatus = FLASH_ProgramHalfWord(newIdx, data); if (FlashStatus != FLASH_COMPLETE) @@ -223,9 +223,9 @@ uint16 EEPROMClass::EE_VerifyPageFullWriteVariable(uint16 Address, uint16 Data) for (idx = pageEnd - 2; idx > pageBase; idx -= 4) { - if ((*(__io uint16*)idx) == Address) // Find last value for address + if ((*(__IO uint16*)idx) == Address) // Find last value for address { - count = (*(__io uint16*)(idx - 2)); // Read last data + count = (*(__IO uint16*)(idx - 2)); // Read last data if (count == Data) return EEPROM_OK; if (count == 0xFFFF) @@ -240,7 +240,7 @@ uint16 EEPROMClass::EE_VerifyPageFullWriteVariable(uint16 Address, uint16 Data) // Check each active page address starting from begining for (idx = pageBase + 4; idx < pageEnd; idx += 4) - if ((*(__io uint32*)idx) == 0xFFFFFFFF) // Verify if element + if ((*(__IO uint32*)idx) == 0xFFFFFFFF) // Verify if element { // contents are 0xFFFFFFFF FlashStatus = FLASH_ProgramHalfWord(idx, Data); // Set variable data if (FlashStatus != FLASH_COMPLETE) @@ -303,8 +303,8 @@ uint16 EEPROMClass::init(void) FLASH_Unlock(); Status = EEPROM_NO_VALID_PAGE; - status0 = (*(__io uint16 *)PageBase0); - status1 = (*(__io uint16 *)PageBase1); + status0 = (*(__IO uint16 *)PageBase0); + status1 = (*(__IO uint16 *)PageBase1); switch (status0) { @@ -407,7 +407,7 @@ uint16 EEPROMClass::format(void) status = EE_CheckErasePage(PageBase0, EEPROM_VALID_PAGE); if (status != EEPROM_OK) return status; - if ((*(__io uint16*)PageBase0) == EEPROM_ERASED) + if ((*(__IO uint16*)PageBase0) == EEPROM_ERASED) { // Set Page0 as valid page: Write VALID_PAGE at Page0 base address FlashStatus = FLASH_ProgramHalfWord(PageBase0, EEPROM_VALID_PAGE); @@ -437,7 +437,7 @@ uint16 EEPROMClass::erases(uint16 *Erases) if (pageBase == 0) return EEPROM_NO_VALID_PAGE; - *Erases = (*(__io uint16*)pageBase+2); + *Erases = (*(__IO uint16*)pageBase+2); return EEPROM_OK; } @@ -485,9 +485,9 @@ uint16 EEPROMClass::read(uint16 Address, uint16 *Data) // Check each active page address starting from end for (pageBase += 6; pageEnd >= pageBase; pageEnd -= 4) - if ((*(__io uint16*)pageEnd) == Address) // Compare the read address with the virtual address + if ((*(__IO uint16*)pageEnd) == Address) // Compare the read address with the virtual address { - *Data = (*(__io uint16*)(pageEnd - 2)); // Get content of Address-2 which is variable value + *Data = (*(__IO uint16*)(pageEnd - 2)); // Get content of Address-2 which is variable value return EEPROM_OK; } diff --git a/STM32F1/libraries/EEPROM/flash_stm32.c b/STM32F1/libraries/EEPROM/flash_stm32.c index 364e64e..5c7a3fe 100644 --- a/STM32F1/libraries/EEPROM/flash_stm32.c +++ b/STM32F1/libraries/EEPROM/flash_stm32.c @@ -17,7 +17,7 @@ */ static void delay(void) { - __io uint32 i = 0; + __IO uint32 i = 0; for(i = 0xFF; i != 0; i--) { } } @@ -122,7 +122,7 @@ FLASH_Status FLASH_ProgramHalfWord(uint32 Address, uint16 Data) { /* if the previous operation is completed, proceed to program the new data */ FLASH_BASE->CR |= FLASH_CR_PG; - *(__io uint16*)Address = Data; + *(__IO uint16*)Address = Data; /* Wait for last operation to be completed */ status = FLASH_WaitForLastOperation(ProgramTimeout); if(status != FLASH_TIMEOUT) diff --git a/STM32F1/libraries/RTClock/src/utility/rtc_util.h b/STM32F1/libraries/RTClock/src/utility/rtc_util.h index 7084b0d..5432de3 100644 --- a/STM32F1/libraries/RTClock/src/utility/rtc_util.h +++ b/STM32F1/libraries/RTClock/src/utility/rtc_util.h @@ -52,16 +52,16 @@ extern "C" { #endif typedef struct rtc_reg_map { - __io uint32 CRH; /**< Control register high */ - __io uint32 CRL; /**< Control register high */ - __io uint32 PRLH; /**< Prescaler load register high */ - __io uint32 PRLL; /**< Prescaler load register low */ - __io uint32 DIVH; /**< Prescaler divider register high */ - __io uint32 DIVL; /**< Prescaler divider register low */ - __io uint32 CNTH; /**< Counter register high */ - __io uint32 CNTL; /**< Counter register low */ - __io uint32 ALRH; /**< Alarm register high */ - __io uint32 ALRL; /**< Alarm register low */ + __IO uint32 CRH; /**< Control register high */ + __IO uint32 CRL; /**< Control register high */ + __IO uint32 PRLH; /**< Prescaler load register high */ + __IO uint32 PRLL; /**< Prescaler load register low */ + __IO uint32 DIVH; /**< Prescaler divider register high */ + __IO uint32 DIVL; /**< Prescaler divider register low */ + __IO uint32 CNTH; /**< Counter register high */ + __IO uint32 CNTL; /**< Counter register low */ + __IO uint32 ALRH; /**< Alarm register high */ + __IO uint32 ALRL; /**< Alarm register low */ } rtc_reg_map; /** RTC register map base pointer */ diff --git a/STM32F1/libraries/WireSlave/src/libmaple/i2c_slave.h b/STM32F1/libraries/WireSlave/src/libmaple/i2c_slave.h index 1f290c2..cdc3858 100644 --- a/STM32F1/libraries/WireSlave/src/libmaple/i2c_slave.h +++ b/STM32F1/libraries/WireSlave/src/libmaple/i2c_slave.h @@ -84,15 +84,15 @@ extern "C" { /** I2C register map type */ typedef struct i2c_reg_map { - __io uint32 CR1; /**< Control register 1 */ - __io uint32 CR2; /**< Control register 2 */ - __io uint32 OAR1; /**< Own address register 1 */ - __io uint32 OAR2; /**< Own address register 2 */ - __io uint32 DR; /**< Data register */ - __io uint32 SR1; /**< Status register 1 */ - __io uint32 SR2; /**< Status register 2 */ - __io uint32 CCR; /**< Clock control register */ - __io uint32 TRISE; /**< TRISE (rise time) register */ + __IO uint32 CR1; /**< Control register 1 */ + __IO uint32 CR2; /**< Control register 2 */ + __IO uint32 OAR1; /**< Own address register 1 */ + __IO uint32 OAR2; /**< Own address register 2 */ + __IO uint32 DR; /**< Data register */ + __IO uint32 SR1; /**< Status register 1 */ + __IO uint32 SR2; /**< Status register 2 */ + __IO uint32 CCR; /**< Clock control register */ + __IO uint32 TRISE; /**< TRISE (rise time) register */ } i2c_reg_map; /** diff --git a/STM32F1/system/libmaple/dma_private.h b/STM32F1/system/libmaple/dma_private.h index f3765fc..063d157 100644 --- a/STM32F1/system/libmaple/dma_private.h +++ b/STM32F1/system/libmaple/dma_private.h @@ -57,6 +57,6 @@ enum dma_atype { DMA_ATYPE_OTHER, }; -enum dma_atype _dma_addr_type(__io void *addr); +enum dma_atype _dma_addr_type(__IO void *addr); #endif diff --git a/STM32F1/system/libmaple/exti_private.h b/STM32F1/system/libmaple/exti_private.h index 4f0a4cf..221cae4 100644 --- a/STM32F1/system/libmaple/exti_private.h +++ b/STM32F1/system/libmaple/exti_private.h @@ -29,6 +29,6 @@ #include -void exti_do_select(__io uint32 *exti_cr, exti_num num, exti_cfg port); +void exti_do_select(__IO uint32 *exti_cr, exti_num num, exti_cfg port); #endif diff --git a/STM32F1/system/libmaple/include/libmaple/adc.h b/STM32F1/system/libmaple/include/libmaple/adc.h index 21efaf5..9190099 100644 --- a/STM32F1/system/libmaple/include/libmaple/adc.h +++ b/STM32F1/system/libmaple/include/libmaple/adc.h @@ -52,26 +52,26 @@ extern "C"{ /** ADC register map type. */ typedef struct adc_reg_map { - __io uint32 SR; ///< Status register - __io uint32 CR1; ///< Control register 1 - __io uint32 CR2; ///< Control register 2 - __io uint32 SMPR1; ///< Sample time register 1 - __io uint32 SMPR2; ///< Sample time register 2 - __io uint32 JOFR1; ///< Injected channel data offset register 1 - __io uint32 JOFR2; ///< Injected channel data offset register 2 - __io uint32 JOFR3; ///< Injected channel data offset register 3 - __io uint32 JOFR4; ///< Injected channel data offset register 4 - __io uint32 HTR; ///< Watchdog high threshold register - __io uint32 LTR; ///< Watchdog low threshold register - __io uint32 SQR1; ///< Regular sequence register 1 - __io uint32 SQR2; ///< Regular sequence register 2 - __io uint32 SQR3; ///< Regular sequence register 3 - __io uint32 JSQR; ///< Injected sequence register - __io uint32 JDR1; ///< Injected data register 1 - __io uint32 JDR2; ///< Injected data register 2 - __io uint32 JDR3; ///< Injected data register 3 - __io uint32 JDR4; ///< Injected data register 4 - __io uint32 DR; ///< Regular data register + __IO uint32 SR; ///< Status register + __IO uint32 CR1; ///< Control register 1 + __IO uint32 CR2; ///< Control register 2 + __IO uint32 SMPR1; ///< Sample time register 1 + __IO uint32 SMPR2; ///< Sample time register 2 + __IO uint32 JOFR1; ///< Injected channel data offset register 1 + __IO uint32 JOFR2; ///< Injected channel data offset register 2 + __IO uint32 JOFR3; ///< Injected channel data offset register 3 + __IO uint32 JOFR4; ///< Injected channel data offset register 4 + __IO uint32 HTR; ///< Watchdog high threshold register + __IO uint32 LTR; ///< Watchdog low threshold register + __IO uint32 SQR1; ///< Regular sequence register 1 + __IO uint32 SQR2; ///< Regular sequence register 2 + __IO uint32 SQR3; ///< Regular sequence register 3 + __IO uint32 JSQR; ///< Injected sequence register + __IO uint32 JDR1; ///< Injected data register 1 + __IO uint32 JDR2; ///< Injected data register 2 + __IO uint32 JDR3; ///< Injected data register 3 + __IO uint32 JDR4; ///< Injected data register 4 + __IO uint32 DR; ///< Regular data register } adc_reg_map; diff --git a/STM32F1/system/libmaple/include/libmaple/bkp.h b/STM32F1/system/libmaple/include/libmaple/bkp.h index bb63a2f..f57235a 100644 --- a/STM32F1/system/libmaple/include/libmaple/bkp.h +++ b/STM32F1/system/libmaple/include/libmaple/bkp.h @@ -47,54 +47,54 @@ extern "C" { /** Backup peripheral register map type. */ typedef struct bkp_reg_map { const uint32 RESERVED1; ///< Reserved - __io uint32 DR1; ///< Data register 1 - __io uint32 DR2; ///< Data register 2 - __io uint32 DR3; ///< Data register 3 - __io uint32 DR4; ///< Data register 4 - __io uint32 DR5; ///< Data register 5 - __io uint32 DR6; ///< Data register 6 - __io uint32 DR7; ///< Data register 7 - __io uint32 DR8; ///< Data register 8 - __io uint32 DR9; ///< Data register 9 - __io uint32 DR10; ///< Data register 10 - __io uint32 RTCCR; ///< RTC control register - __io uint32 CR; ///< Control register - __io uint32 CSR; ///< Control and status register + __IO uint32 DR1; ///< Data register 1 + __IO uint32 DR2; ///< Data register 2 + __IO uint32 DR3; ///< Data register 3 + __IO uint32 DR4; ///< Data register 4 + __IO uint32 DR5; ///< Data register 5 + __IO uint32 DR6; ///< Data register 6 + __IO uint32 DR7; ///< Data register 7 + __IO uint32 DR8; ///< Data register 8 + __IO uint32 DR9; ///< Data register 9 + __IO uint32 DR10; ///< Data register 10 + __IO uint32 RTCCR; ///< RTC control register + __IO uint32 CR; ///< Control register + __IO uint32 CSR; ///< Control and status register #if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) const uint32 RESERVED2; ///< Reserved const uint32 RESERVED3; ///< Reserved - __io uint32 DR11; ///< Data register 11 - __io uint32 DR12; ///< Data register 12 - __io uint32 DR13; ///< Data register 13 - __io uint32 DR14; ///< Data register 14 - __io uint32 DR15; ///< Data register 15 - __io uint32 DR16; ///< Data register 16 - __io uint32 DR17; ///< Data register 17 - __io uint32 DR18; ///< Data register 18 - __io uint32 DR19; ///< Data register 19 - __io uint32 DR20; ///< Data register 20 - __io uint32 DR21; ///< Data register 21 - __io uint32 DR22; ///< Data register 22 - __io uint32 DR23; ///< Data register 23 - __io uint32 DR24; ///< Data register 24 - __io uint32 DR25; ///< Data register 25 - __io uint32 DR26; ///< Data register 26 - __io uint32 DR27; ///< Data register 27 - __io uint32 DR28; ///< Data register 28 - __io uint32 DR29; ///< Data register 29 - __io uint32 DR30; ///< Data register 30 - __io uint32 DR31; ///< Data register 31 - __io uint32 DR32; ///< Data register 32 - __io uint32 DR33; ///< Data register 33 - __io uint32 DR34; ///< Data register 34 - __io uint32 DR35; ///< Data register 35 - __io uint32 DR36; ///< Data register 36 - __io uint32 DR37; ///< Data register 37 - __io uint32 DR38; ///< Data register 38 - __io uint32 DR39; ///< Data register 39 - __io uint32 DR40; ///< Data register 40 - __io uint32 DR41; ///< Data register 41 - __io uint32 DR42; ///< Data register 42 + __IO uint32 DR11; ///< Data register 11 + __IO uint32 DR12; ///< Data register 12 + __IO uint32 DR13; ///< Data register 13 + __IO uint32 DR14; ///< Data register 14 + __IO uint32 DR15; ///< Data register 15 + __IO uint32 DR16; ///< Data register 16 + __IO uint32 DR17; ///< Data register 17 + __IO uint32 DR18; ///< Data register 18 + __IO uint32 DR19; ///< Data register 19 + __IO uint32 DR20; ///< Data register 20 + __IO uint32 DR21; ///< Data register 21 + __IO uint32 DR22; ///< Data register 22 + __IO uint32 DR23; ///< Data register 23 + __IO uint32 DR24; ///< Data register 24 + __IO uint32 DR25; ///< Data register 25 + __IO uint32 DR26; ///< Data register 26 + __IO uint32 DR27; ///< Data register 27 + __IO uint32 DR28; ///< Data register 28 + __IO uint32 DR29; ///< Data register 29 + __IO uint32 DR30; ///< Data register 30 + __IO uint32 DR31; ///< Data register 31 + __IO uint32 DR32; ///< Data register 32 + __IO uint32 DR33; ///< Data register 33 + __IO uint32 DR34; ///< Data register 34 + __IO uint32 DR35; ///< Data register 35 + __IO uint32 DR36; ///< Data register 36 + __IO uint32 DR37; ///< Data register 37 + __IO uint32 DR38; ///< Data register 38 + __IO uint32 DR39; ///< Data register 39 + __IO uint32 DR40; ///< Data register 40 + __IO uint32 DR41; ///< Data register 41 + __IO uint32 DR42; ///< Data register 42 #endif } bkp_reg_map; diff --git a/STM32F1/system/libmaple/include/libmaple/dma.h b/STM32F1/system/libmaple/include/libmaple/dma.h index a75b314..87e1840 100644 --- a/STM32F1/system/libmaple/include/libmaple/dma.h +++ b/STM32F1/system/libmaple/include/libmaple/dma.h @@ -139,12 +139,12 @@ void dma_init(dma_dev *dev); */ typedef struct dma_tube_config { /** Source of data */ - __io void *tube_src; + __IO void *tube_src; /** Source transfer size */ dma_xfer_size tube_src_size; /** Destination of data */ - __io void *tube_dst; + __IO void *tube_dst; /** Destination transfer size */ dma_xfer_size tube_dst_size; @@ -283,7 +283,7 @@ extern void dma_set_num_transfers(dma_dev *dev, dma_tube tube, * @param tube Tube whose base memory address to set. * @param address Memory base address to use. */ -extern void dma_set_mem_addr(dma_dev *dev, dma_tube tube, __io void *address); +extern void dma_set_mem_addr(dma_dev *dev, dma_tube tube, __IO void *address); /** * @brief Set the base peripheral address where data will be read from @@ -299,7 +299,7 @@ extern void dma_set_mem_addr(dma_dev *dev, dma_tube tube, __io void *address); * @param tube Tube whose peripheral data register base address to set. * @param address Peripheral memory base address to use. */ -extern void dma_set_per_addr(dma_dev *dev, dma_tube tube, __io void *address); +extern void dma_set_per_addr(dma_dev *dev, dma_tube tube, __IO void *address); /* Interrupt handling */ diff --git a/STM32F1/system/libmaple/include/libmaple/exti.h b/STM32F1/system/libmaple/include/libmaple/exti.h index 69362d6..3e914be 100644 --- a/STM32F1/system/libmaple/include/libmaple/exti.h +++ b/STM32F1/system/libmaple/include/libmaple/exti.h @@ -48,12 +48,12 @@ extern "C"{ /** EXTI register map type */ typedef struct exti_reg_map { - __io uint32 IMR; /**< Interrupt mask register */ - __io uint32 EMR; /**< Event mask register */ - __io uint32 RTSR; /**< Rising trigger selection register */ - __io uint32 FTSR; /**< Falling trigger selection register */ - __io uint32 SWIER; /**< Software interrupt event register */ - __io uint32 PR; /**< Pending register */ + __IO uint32 IMR; /**< Interrupt mask register */ + __IO uint32 EMR; /**< Event mask register */ + __IO uint32 RTSR; /**< Rising trigger selection register */ + __IO uint32 FTSR; /**< Falling trigger selection register */ + __IO uint32 SWIER; /**< Software interrupt event register */ + __IO uint32 PR; /**< Pending register */ } exti_reg_map; /* diff --git a/STM32F1/system/libmaple/include/libmaple/fsmc.h b/STM32F1/system/libmaple/include/libmaple/fsmc.h index 6225fee..9dd8a72 100644 --- a/STM32F1/system/libmaple/include/libmaple/fsmc.h +++ b/STM32F1/system/libmaple/include/libmaple/fsmc.h @@ -53,42 +53,42 @@ extern "C"{ /** FSMC register map type */ typedef struct fsmc_reg_map { - __io uint32 BCR1; /**< SRAM/NOR-Flash chip-select control register 1 */ - __io uint32 BTR1; /**< SRAM/NOR-Flash chip-select timing register 1 */ - __io uint32 BCR2; /**< SRAM/NOR-Flash chip-select control register 2 */ - __io uint32 BTR2; /**< SRAM/NOR-Flash chip-select timing register 2 */ - __io uint32 BCR3; /**< SRAM/NOR-Flash chip-select control register 3 */ - __io uint32 BTR3; /**< SRAM/NOR-Flash chip-select timing register 3 */ - __io uint32 BCR4; /**< SRAM/NOR-Flash chip-select control register 4 */ - __io uint32 BTR4; /**< SRAM/NOR-Flash chip-select timing register 4 */ + __IO uint32 BCR1; /**< SRAM/NOR-Flash chip-select control register 1 */ + __IO uint32 BTR1; /**< SRAM/NOR-Flash chip-select timing register 1 */ + __IO uint32 BCR2; /**< SRAM/NOR-Flash chip-select control register 2 */ + __IO uint32 BTR2; /**< SRAM/NOR-Flash chip-select timing register 2 */ + __IO uint32 BCR3; /**< SRAM/NOR-Flash chip-select control register 3 */ + __IO uint32 BTR3; /**< SRAM/NOR-Flash chip-select timing register 3 */ + __IO uint32 BCR4; /**< SRAM/NOR-Flash chip-select control register 4 */ + __IO uint32 BTR4; /**< SRAM/NOR-Flash chip-select timing register 4 */ const uint8 RESERVED1[64]; /**< Reserved */ - __io uint32 PCR2; /**< PC Card/NAND Flash control register 2 */ - __io uint32 SR2; /**< FIFO status and interrupt register 2 */ - __io uint32 PMEM2; /**< Common memory space timing register 2 */ - __io uint32 PATT2; /**< Attribute memory space timing register 2 */ + __IO uint32 PCR2; /**< PC Card/NAND Flash control register 2 */ + __IO uint32 SR2; /**< FIFO status and interrupt register 2 */ + __IO uint32 PMEM2; /**< Common memory space timing register 2 */ + __IO uint32 PATT2; /**< Attribute memory space timing register 2 */ const uint8 RESERVED2[4]; /**< Reserved */ - __io uint32 ECCR2; /**< ECC result register 2 */ + __IO uint32 ECCR2; /**< ECC result register 2 */ const uint8 RESERVED3[2]; - __io uint32 PCR3; /**< PC Card/NAND Flash control register 3 */ - __io uint32 SR3; /**< FIFO status and interrupt register 3 */ - __io uint32 PMEM3; /**< Common memory space timing register 3 */ - __io uint32 PATT3; /**< Attribute memory space timing register 3 */ + __IO uint32 PCR3; /**< PC Card/NAND Flash control register 3 */ + __IO uint32 SR3; /**< FIFO status and interrupt register 3 */ + __IO uint32 PMEM3; /**< Common memory space timing register 3 */ + __IO uint32 PATT3; /**< Attribute memory space timing register 3 */ const uint32 RESERVED4; /**< Reserved */ - __io uint32 ECCR3; /**< ECC result register 3 */ + __IO uint32 ECCR3; /**< ECC result register 3 */ const uint8 RESERVED5[8]; /**< Reserved */ - __io uint32 PCR4; /**< PC Card/NAND Flash control register 4 */ - __io uint32 SR4; /**< FIFO status and interrupt register 4 */ - __io uint32 PMEM4; /**< Common memory space timing register 4 */ - __io uint32 PATT4; /**< Attribute memory space timing register 4 */ - __io uint32 PIO4; /**< I/O space timing register 4 */ + __IO uint32 PCR4; /**< PC Card/NAND Flash control register 4 */ + __IO uint32 SR4; /**< FIFO status and interrupt register 4 */ + __IO uint32 PMEM4; /**< Common memory space timing register 4 */ + __IO uint32 PATT4; /**< Attribute memory space timing register 4 */ + __IO uint32 PIO4; /**< I/O space timing register 4 */ const uint8 RESERVED6[80]; /**< Reserved */ - __io uint32 BWTR1; /**< SRAM/NOR-Flash write timing register 1 */ + __IO uint32 BWTR1; /**< SRAM/NOR-Flash write timing register 1 */ const uint32 RESERVED7; /**< Reserved */ - __io uint32 BWTR2; /**< SRAM/NOR-Flash write timing register 2 */ + __IO uint32 BWTR2; /**< SRAM/NOR-Flash write timing register 2 */ const uint32 RESERVED8; /**< Reserved */ - __io uint32 BWTR3; /**< SRAM/NOR-Flash write timing register 3 */ + __IO uint32 BWTR3; /**< SRAM/NOR-Flash write timing register 3 */ const uint32 RESERVED9; /**< Reserved */ - __io uint32 BWTR4; /**< SRAM/NOR-Flash write timing register 4 */ + __IO uint32 BWTR4; /**< SRAM/NOR-Flash write timing register 4 */ } __attribute__((packed)) fsmc_reg_map; #define __FSMCB 0xA0000000 @@ -98,10 +98,10 @@ typedef struct fsmc_reg_map { /** FSMC NOR/PSRAM register map type */ typedef struct fsmc_nor_psram_reg_map { - __io uint32 BCR; /**< Chip-select control register */ - __io uint32 BTR; /**< Chip-select timing register */ + __IO uint32 BCR; /**< Chip-select control register */ + __IO uint32 BTR; /**< Chip-select timing register */ const uint8 RESERVED[252]; /**< Reserved */ - __io uint32 BWTR; /**< Write timing register */ + __IO uint32 BWTR; /**< Write timing register */ } fsmc_nor_psram_reg_map; /** FSMC NOR/PSRAM base pointer 1 */ diff --git a/STM32F1/system/libmaple/include/libmaple/i2c.h b/STM32F1/system/libmaple/include/libmaple/i2c.h index 92ec29e..a44f6af 100644 --- a/STM32F1/system/libmaple/include/libmaple/i2c.h +++ b/STM32F1/system/libmaple/include/libmaple/i2c.h @@ -75,15 +75,15 @@ extern "C" { /** I2C register map type */ typedef struct i2c_reg_map { - __io uint32 CR1; /**< Control register 1 */ - __io uint32 CR2; /**< Control register 2 */ - __io uint32 OAR1; /**< Own address register 1 */ - __io uint32 OAR2; /**< Own address register 2 */ - __io uint32 DR; /**< Data register */ - __io uint32 SR1; /**< Status register 1 */ - __io uint32 SR2; /**< Status register 2 */ - __io uint32 CCR; /**< Clock control register */ - __io uint32 TRISE; /**< TRISE (rise time) register */ + __IO uint32 CR1; /**< Control register 1 */ + __IO uint32 CR2; /**< Control register 2 */ + __IO uint32 OAR1; /**< Own address register 1 */ + __IO uint32 OAR2; /**< Own address register 2 */ + __IO uint32 DR; /**< Data register */ + __IO uint32 SR1; /**< Status register 1 */ + __IO uint32 SR2; /**< Status register 2 */ + __IO uint32 CCR; /**< Clock control register */ + __IO uint32 TRISE; /**< TRISE (rise time) register */ } i2c_reg_map; /** diff --git a/STM32F1/system/libmaple/include/libmaple/iwdg.h b/STM32F1/system/libmaple/include/libmaple/iwdg.h index 3a16c55..f999439 100644 --- a/STM32F1/system/libmaple/include/libmaple/iwdg.h +++ b/STM32F1/system/libmaple/include/libmaple/iwdg.h @@ -53,10 +53,10 @@ extern "C"{ /** Independent watchdog register map type. */ typedef struct iwdg_reg_map { - __io uint32 KR; /**< Key register. */ - __io uint32 PR; /**< Prescaler register. */ - __io uint32 RLR; /**< Reload register. */ - __io uint32 SR; /**< Status register */ + __IO uint32 KR; /**< Key register. */ + __IO uint32 PR; /**< Prescaler register. */ + __IO uint32 RLR; /**< Reload register. */ + __IO uint32 SR; /**< Status register */ } iwdg_reg_map; /** Independent watchdog base pointer */ diff --git a/STM32F1/system/libmaple/include/libmaple/libmaple_types.h b/STM32F1/system/libmaple/include/libmaple/libmaple_types.h index 398b705..62bf436 100644 --- a/STM32F1/system/libmaple/include/libmaple/libmaple_types.h +++ b/STM32F1/system/libmaple/include/libmaple/libmaple_types.h @@ -52,7 +52,7 @@ typedef long long int64; typedef void (*voidFuncPtr)(void); typedef void (*voidArgumentFuncPtr)(void *); -#define __io volatile +#define __IO volatile #define __attr_flash __attribute__((section (".USER_FLASH"))) #define __packed __attribute__((__packed__)) #define __deprecated __attribute__((__deprecated__)) diff --git a/STM32F1/system/libmaple/include/libmaple/nvic.h b/STM32F1/system/libmaple/include/libmaple/nvic.h index 69d9a91..954fd12 100644 --- a/STM32F1/system/libmaple/include/libmaple/nvic.h +++ b/STM32F1/system/libmaple/include/libmaple/nvic.h @@ -55,31 +55,31 @@ extern "C"{ /** NVIC register map type. */ typedef struct nvic_reg_map { - __io uint32 ISER[8]; /**< Interrupt Set Enable Registers */ + __IO uint32 ISER[8]; /**< Interrupt Set Enable Registers */ /** Reserved */ uint32 RESERVED0[24]; - __io uint32 ICER[8]; /**< Interrupt Clear Enable Registers */ + __IO uint32 ICER[8]; /**< Interrupt Clear Enable Registers */ /** Reserved */ uint32 RESERVED1[24]; - __io uint32 ISPR[8]; /**< Interrupt Set Pending Registers */ + __IO uint32 ISPR[8]; /**< Interrupt Set Pending Registers */ /** Reserved */ uint32 RESERVED2[24]; - __io uint32 ICPR[8]; /**< Interrupt Clear Pending Registers */ + __IO uint32 ICPR[8]; /**< Interrupt Clear Pending Registers */ /** Reserved */ uint32 RESERVED3[24]; - __io uint32 IABR[8]; /**< Interrupt Active bit Registers */ + __IO uint32 IABR[8]; /**< Interrupt Active bit Registers */ /** Reserved */ uint32 RESERVED4[56]; - __io uint8 IP[240]; /**< Interrupt Priority Registers */ + __IO uint8 IP[240]; /**< Interrupt Priority Registers */ /** Reserved */ uint32 RESERVED5[644]; - __io uint32 STIR; /**< Software Trigger Interrupt Registers */ + __IO uint32 STIR; /**< Software Trigger Interrupt Registers */ } nvic_reg_map; /** NVIC register map base pointer. */ diff --git a/STM32F1/system/libmaple/include/libmaple/pwr.h b/STM32F1/system/libmaple/include/libmaple/pwr.h index f711c7c..fada6df 100644 --- a/STM32F1/system/libmaple/include/libmaple/pwr.h +++ b/STM32F1/system/libmaple/include/libmaple/pwr.h @@ -43,8 +43,8 @@ extern "C" { /** Power interface register map. */ typedef struct pwr_reg_map { - __io uint32 CR; /**< Control register */ - __io uint32 CSR; /**< Control and status register */ + __IO uint32 CR; /**< Control register */ + __IO uint32 CSR; /**< Control and status register */ } pwr_reg_map; /** Power peripheral register map base pointer. */ diff --git a/STM32F1/system/libmaple/include/libmaple/ring_buffer.h b/STM32F1/system/libmaple/include/libmaple/ring_buffer.h index e99fe62..854d589 100644 --- a/STM32F1/system/libmaple/include/libmaple/ring_buffer.h +++ b/STM32F1/system/libmaple/include/libmaple/ring_buffer.h @@ -81,7 +81,7 @@ static inline void rb_init(ring_buffer *rb, uint16 size, uint8 *buf) { * @param rb Buffer whose elements to count. */ static inline uint16 rb_full_count(ring_buffer *rb) { - __io ring_buffer *arb = rb; + __IO ring_buffer *arb = rb; int32 size = arb->tail - arb->head; if (arb->tail < arb->head) { size += arb->size + 1; diff --git a/STM32F1/system/libmaple/include/libmaple/scb.h b/STM32F1/system/libmaple/include/libmaple/scb.h index c42a0f2..0b01480 100644 --- a/STM32F1/system/libmaple/include/libmaple/scb.h +++ b/STM32F1/system/libmaple/include/libmaple/scb.h @@ -49,37 +49,37 @@ extern "C" { /** System control block register map type */ typedef struct scb_reg_map { - __io uint32 CPUID; /**< CPU ID Base Register */ - __io uint32 ICSR; /**< Interrupt Control State Register */ - __io uint32 VTOR; /**< Vector Table Offset Register */ - __io uint32 AIRCR; /**< Application Interrupt / Reset Control Register */ - __io uint32 SCR; /**< System Control Register */ - __io uint32 CCR; /**< Configuration and Control Register */ - __io uint8 SHP[12]; /**< System Handler Priority Registers + __IO uint32 CPUID; /**< CPU ID Base Register */ + __IO uint32 ICSR; /**< Interrupt Control State Register */ + __IO uint32 VTOR; /**< Vector Table Offset Register */ + __IO uint32 AIRCR; /**< Application Interrupt / Reset Control Register */ + __IO uint32 SCR; /**< System Control Register */ + __IO uint32 CCR; /**< Configuration and Control Register */ + __IO uint8 SHP[12]; /**< System Handler Priority Registers (4-7, 8-11, 12-15) */ - __io uint32 SHCSR; /**< System Handler Control and State Register */ - __io uint32 CFSR; /**< Configurable Fault Status Register */ - __io uint32 HFSR; /**< Hard Fault Status Register */ + __IO uint32 SHCSR; /**< System Handler Control and State Register */ + __IO uint32 CFSR; /**< Configurable Fault Status Register */ + __IO uint32 HFSR; /**< Hard Fault Status Register */ /* DFSR is not documented by ST in PM0056 (as of Revision 4), but * there's a 4 byte hole in the SCB register map docs right where * it belongs. Since it's specified as "always implemented" in * the ARM v7-M ARM, I'm assuming its absence is a bug in the ST * doc, but I haven't proven it. [mbolivar] */ - __io uint32 DFSR; /**< Debug Fault Status Register */ - __io uint32 MMFAR; /**< Mem Manage Address Register */ - __io uint32 BFAR; /**< Bus Fault Address Register */ + __IO uint32 DFSR; /**< Debug Fault Status Register */ + __IO uint32 MMFAR; /**< Mem Manage Address Register */ + __IO uint32 BFAR; /**< Bus Fault Address Register */ #if 0 /* The following registers are implementation-defined according to * ARM v7-M, and I can't find evidence of their existence in ST's * docs. I'm removing them. Feel free to yell at me if they do * exist. [mbolivar] */ - __io uint32 AFSR; /**< Auxiliary Fault Status Register */ - __io uint32 PFR[2]; /**< Processor Feature Register */ - __io uint32 DFR; /**< Debug Feature Register */ - __io uint32 AFR; /**< Auxiliary Feature Register */ - __io uint32 MMFR[4]; /**< Memory Model Feature Register */ - __io uint32 ISAR[5]; /**< ISA Feature Register */ + __IO uint32 AFSR; /**< Auxiliary Fault Status Register */ + __IO uint32 PFR[2]; /**< Processor Feature Register */ + __IO uint32 DFR; /**< Debug Feature Register */ + __IO uint32 AFR; /**< Auxiliary Feature Register */ + __IO uint32 MMFR[4]; /**< Memory Model Feature Register */ + __IO uint32 ISAR[5]; /**< ISA Feature Register */ #endif } scb_reg_map; diff --git a/STM32F1/system/libmaple/include/libmaple/sdio.h b/STM32F1/system/libmaple/include/libmaple/sdio.h index dec31c8..a9ffc5c 100644 --- a/STM32F1/system/libmaple/include/libmaple/sdio.h +++ b/STM32F1/system/libmaple/include/libmaple/sdio.h @@ -52,23 +52,23 @@ extern "C" { // SDIO register map type typedef struct sdio_reg_map { - __io uint32 POWER; // 0x00 - __io uint32 CLKCR; // 0x04 - __io uint32 ARG; // 0x08 - __io uint32 CMD; // 0x0C - __io uint32 RESPCMD; // 0x10 (0x3F) + __IO uint32 POWER; // 0x00 + __IO uint32 CLKCR; // 0x04 + __IO uint32 ARG; // 0x08 + __IO uint32 CMD; // 0x0C + __IO uint32 RESPCMD; // 0x10 (0x3F) const uint32 RESP[4]; // 0x14 - contain the card status, which is part of the received response. - __io uint32 DTIMER; // 0x24 - contains the data timeout period, in card bus clock periods. - __io uint32 DLEN; // 0x28 (0x01FF FFFF) - contains the number of data bytes to be transferred - __io uint32 DCTRL; // 0x2C - __io uint32 DCOUNT; // 0x30 (0x01FF FFFF) - __io uint32 STA; // 0x34 - __io uint32 ICR; // 0x38 - __io uint32 MASK; // 0x3C + __IO uint32 DTIMER; // 0x24 - contains the data timeout period, in card bus clock periods. + __IO uint32 DLEN; // 0x28 (0x01FF FFFF) - contains the number of data bytes to be transferred + __IO uint32 DCTRL; // 0x2C + __IO uint32 DCOUNT; // 0x30 (0x01FF FFFF) + __IO uint32 STA; // 0x34 + __IO uint32 ICR; // 0x38 + __IO uint32 MASK; // 0x3C const uint32 RESERVED1[2]; - __io uint32 FIFOCNT; // 0x48 (0x01FF FFFF) + __IO uint32 FIFOCNT; // 0x48 (0x01FF FFFF) const uint32 RESERVED2[13]; - __io uint32 FIFO; // 0x80 + __IO uint32 FIFO; // 0x80 } sdio_reg_map; #define sdio_dev sdio_reg_map diff --git a/STM32F1/system/libmaple/include/libmaple/spi.h b/STM32F1/system/libmaple/include/libmaple/spi.h index 0da4129..5d295bb 100644 --- a/STM32F1/system/libmaple/include/libmaple/spi.h +++ b/STM32F1/system/libmaple/include/libmaple/spi.h @@ -54,15 +54,15 @@ extern "C" { /** SPI register map type. */ typedef struct spi_reg_map { - __io uint32 CR1; /**< Control register 1 */ - __io uint32 CR2; /**< Control register 2 */ - __io uint32 SR; /**< Status register */ - __io uint32 DR; /**< Data register */ - __io uint32 CRCPR; /**< CRC polynomial register */ - __io uint32 RXCRCR; /**< RX CRC register */ - __io uint32 TXCRCR; /**< TX CRC register */ - __io uint32 I2SCFGR; /**< I2S configuration register */ - __io uint32 I2SPR; /**< I2S prescaler register */ + __IO uint32 CR1; /**< Control register 1 */ + __IO uint32 CR2; /**< Control register 2 */ + __IO uint32 SR; /**< Status register */ + __IO uint32 DR; /**< Data register */ + __IO uint32 CRCPR; /**< CRC polynomial register */ + __IO uint32 RXCRCR; /**< RX CRC register */ + __IO uint32 TXCRCR; /**< TX CRC register */ + __IO uint32 I2SCFGR; /**< I2S configuration register */ + __IO uint32 I2SPR; /**< I2S prescaler register */ } spi_reg_map; /* diff --git a/STM32F1/system/libmaple/include/libmaple/syscfg.h b/STM32F1/system/libmaple/include/libmaple/syscfg.h index 6b375d3..e39d0b7 100644 --- a/STM32F1/system/libmaple/include/libmaple/syscfg.h +++ b/STM32F1/system/libmaple/include/libmaple/syscfg.h @@ -48,12 +48,12 @@ extern "C" { * @brief SYSCFG register map type. */ typedef struct syscfg_reg_map { - __io uint32 MEMRMP; /**< Memory remap register */ - __io uint32 PMC; /**< Peripheral mode configuration */ - __io uint32 EXTICR[4]; /**< External interrupt configuration registers */ + __IO uint32 MEMRMP; /**< Memory remap register */ + __IO uint32 PMC; /**< Peripheral mode configuration */ + __IO uint32 EXTICR[4]; /**< External interrupt configuration registers */ const uint32 RESERVED1; const uint32 RESERVED2; - __io uint32 CMPCR; /**< Compensation cell control register */ + __IO uint32 CMPCR; /**< Compensation cell control register */ } syscfg_reg_map; /** SYSCFG register map base pointer */ diff --git a/STM32F1/system/libmaple/include/libmaple/systick.h b/STM32F1/system/libmaple/include/libmaple/systick.h index 51d0c56..3f6bd5f 100644 --- a/STM32F1/system/libmaple/include/libmaple/systick.h +++ b/STM32F1/system/libmaple/include/libmaple/systick.h @@ -41,10 +41,10 @@ extern "C"{ /** SysTick register map type */ typedef struct systick_reg_map { - __io uint32 CSR; /**< Control and status register */ - __io uint32 RVR; /**< Reload value register */ - __io uint32 CNT; /**< Current value register ("count") */ - __io uint32 CVR; /**< Calibration value register */ + __IO uint32 CSR; /**< Control and status register */ + __IO uint32 RVR; /**< Reload value register */ + __IO uint32 CNT; /**< Current value register ("count") */ + __IO uint32 CVR; /**< Calibration value register */ } systick_reg_map; /** SysTick register map base pointer */ diff --git a/STM32F1/system/libmaple/include/libmaple/timer.h b/STM32F1/system/libmaple/include/libmaple/timer.h index 64f458f..4d6fd46 100644 --- a/STM32F1/system/libmaple/include/libmaple/timer.h +++ b/STM32F1/system/libmaple/include/libmaple/timer.h @@ -50,26 +50,26 @@ extern "C"{ /** Advanced control timer register map type */ typedef struct timer_adv_reg_map { - __io uint32 CR1; /**< Control register 1 */ - __io uint32 CR2; /**< Control register 2 */ - __io uint32 SMCR; /**< Slave mode control register */ - __io uint32 DIER; /**< DMA/interrupt enable register */ - __io uint32 SR; /**< Status register */ - __io uint32 EGR; /**< Event generation register */ - __io uint32 CCMR1; /**< Capture/compare mode register 1 */ - __io uint32 CCMR2; /**< Capture/compare mode register 2 */ - __io uint32 CCER; /**< Capture/compare enable register */ - __io uint32 CNT; /**< Counter */ - __io uint32 PSC; /**< Prescaler */ - __io uint32 ARR; /**< Auto-reload register */ - __io uint32 RCR; /**< Repetition counter register */ - __io uint32 CCR1; /**< Capture/compare register 1 */ - __io uint32 CCR2; /**< Capture/compare register 2 */ - __io uint32 CCR3; /**< Capture/compare register 3 */ - __io uint32 CCR4; /**< Capture/compare register 4 */ - __io uint32 BDTR; /**< Break and dead-time register */ - __io uint32 DCR; /**< DMA control register */ - __io uint32 DMAR; /**< DMA address for full transfer */ + __IO uint32 CR1; /**< Control register 1 */ + __IO uint32 CR2; /**< Control register 2 */ + __IO uint32 SMCR; /**< Slave mode control register */ + __IO uint32 DIER; /**< DMA/interrupt enable register */ + __IO uint32 SR; /**< Status register */ + __IO uint32 EGR; /**< Event generation register */ + __IO uint32 CCMR1; /**< Capture/compare mode register 1 */ + __IO uint32 CCMR2; /**< Capture/compare mode register 2 */ + __IO uint32 CCER; /**< Capture/compare enable register */ + __IO uint32 CNT; /**< Counter */ + __IO uint32 PSC; /**< Prescaler */ + __IO uint32 ARR; /**< Auto-reload register */ + __IO uint32 RCR; /**< Repetition counter register */ + __IO uint32 CCR1; /**< Capture/compare register 1 */ + __IO uint32 CCR2; /**< Capture/compare register 2 */ + __IO uint32 CCR3; /**< Capture/compare register 3 */ + __IO uint32 CCR4; /**< Capture/compare register 4 */ + __IO uint32 BDTR; /**< Break and dead-time register */ + __IO uint32 DCR; /**< DMA control register */ + __IO uint32 DMAR; /**< DMA address for full transfer */ } timer_adv_reg_map; /* General purpose timer register map type: intentionally omitted. @@ -79,18 +79,18 @@ typedef struct timer_adv_reg_map { /** Basic timer register map type */ typedef struct timer_bas_reg_map { - __io uint32 CR1; /**< Control register 1 */ - __io uint32 CR2; /**< Control register 2 */ + __IO uint32 CR1; /**< Control register 1 */ + __IO uint32 CR2; /**< Control register 2 */ const uint32 RESERVED1; /**< Reserved */ - __io uint32 DIER; /**< DMA/interrupt enable register */ - __io uint32 SR; /**< Status register */ - __io uint32 EGR; /**< Event generation register */ + __IO uint32 DIER; /**< DMA/interrupt enable register */ + __IO uint32 SR; /**< Status register */ + __IO uint32 EGR; /**< Event generation register */ const uint32 RESERVED2; /**< Reserved */ const uint32 RESERVED3; /**< Reserved */ const uint32 RESERVED4; /**< Reserved */ - __io uint32 CNT; /**< Counter */ - __io uint32 PSC; /**< Prescaler */ - __io uint32 ARR; /**< Auto-reload register */ + __IO uint32 CNT; /**< Counter */ + __IO uint32 PSC; /**< Prescaler */ + __IO uint32 ARR; /**< Auto-reload register */ } timer_bas_reg_map; /* @@ -738,7 +738,7 @@ static inline void timer_set_reload(timer_dev *dev, uint16 arr) { * @param channel Channel whose compare value to get. */ static inline uint16 timer_get_compare(timer_dev *dev, uint8 channel) { - __io uint32 *ccr = &(dev->regs).gen->CCR1 + (channel - 1); + __IO uint32 *ccr = &(dev->regs).gen->CCR1 + (channel - 1); return *ccr; } @@ -751,7 +751,7 @@ static inline uint16 timer_get_compare(timer_dev *dev, uint8 channel) { static inline void timer_set_compare(timer_dev *dev, uint8 channel, uint16 value) { - __io uint32 *ccr = &(dev->regs).gen->CCR1 + (channel - 1); + __IO uint32 *ccr = &(dev->regs).gen->CCR1 + (channel - 1); *ccr = value; } @@ -1065,7 +1065,7 @@ static inline void timer_oc_set_mode(timer_dev *dev, timer_oc_mode mode, uint8 flags) { /* channel == 1,2 -> CCMR1; channel == 3,4 -> CCMR2 */ - __io uint32 *ccmr = &(dev->regs).gen->CCMR1 + (((channel - 1) >> 1) & 1); + __IO uint32 *ccmr = &(dev->regs).gen->CCMR1 + (((channel - 1) >> 1) & 1); /* channel == 1,3 -> shift = 0, channel == 2,4 -> shift = 8 */ uint8 shift = 8 * (1 - (channel & 1)); diff --git a/STM32F1/system/libmaple/include/libmaple/usart.h b/STM32F1/system/libmaple/include/libmaple/usart.h index 245ddab..9a868df 100644 --- a/STM32F1/system/libmaple/include/libmaple/usart.h +++ b/STM32F1/system/libmaple/include/libmaple/usart.h @@ -53,13 +53,13 @@ extern "C"{ /** USART register map type */ typedef struct usart_reg_map { - __io uint32 SR; /**< Status register */ - __io uint32 DR; /**< Data register */ - __io uint32 BRR; /**< Baud rate register */ - __io uint32 CR1; /**< Control register 1 */ - __io uint32 CR2; /**< Control register 2 */ - __io uint32 CR3; /**< Control register 3 */ - __io uint32 GTPR; /**< Guard time and prescaler register */ + __IO uint32 SR; /**< Status register */ + __IO uint32 DR; /**< Data register */ + __IO uint32 BRR; /**< Baud rate register */ + __IO uint32 CR1; /**< Control register 1 */ + __IO uint32 CR2; /**< Control register 2 */ + __IO uint32 CR3; /**< Control register 3 */ + __IO uint32 GTPR; /**< Guard time and prescaler register */ } usart_reg_map; /* diff --git a/STM32F1/system/libmaple/rcc_private.h b/STM32F1/system/libmaple/rcc_private.h index afb8a31..a47afca 100644 --- a/STM32F1/system/libmaple/rcc_private.h +++ b/STM32F1/system/libmaple/rcc_private.h @@ -40,16 +40,16 @@ struct rcc_dev_info { extern const struct rcc_dev_info rcc_dev_table[]; -static inline void rcc_do_clk_enable(__io uint32** enable_regs, +static inline void rcc_do_clk_enable(__IO uint32** enable_regs, rcc_clk_id id) { - __io uint32 *enable_reg = enable_regs[rcc_dev_clk(id)]; + __IO uint32 *enable_reg = enable_regs[rcc_dev_clk(id)]; uint8 line_num = rcc_dev_table[id].line_num; bb_peri_set_bit(enable_reg, line_num, 1); } -static inline void rcc_do_reset_dev(__io uint32** reset_regs, +static inline void rcc_do_reset_dev(__IO uint32** reset_regs, rcc_clk_id id) { - __io uint32 *reset_reg = reset_regs[rcc_dev_clk(id)]; + __IO uint32 *reset_reg = reset_regs[rcc_dev_clk(id)]; uint8 line_num = rcc_dev_table[id].line_num; bb_peri_set_bit(reset_reg, line_num, 1); bb_peri_set_bit(reset_reg, line_num, 0); @@ -64,9 +64,9 @@ static inline void rcc_do_set_prescaler(const uint32 *masks, RCC_BASE->CFGR = cfgr; } -static inline void rcc_do_clk_disable(__io uint32** enable_regs, +static inline void rcc_do_clk_disable(__IO uint32** enable_regs, rcc_clk_id id) { - __io uint32 *enable_reg = enable_regs[rcc_dev_clk(id)]; + __IO uint32 *enable_reg = enable_regs[rcc_dev_clk(id)]; uint8 line_num = rcc_dev_table[id].line_num; bb_peri_set_bit(enable_reg, line_num, 0); } diff --git a/STM32F1/system/libmaple/stm32f1/include/series/dac.h b/STM32F1/system/libmaple/stm32f1/include/series/dac.h index c0d026b..5bf4b9e 100644 --- a/STM32F1/system/libmaple/stm32f1/include/series/dac.h +++ b/STM32F1/system/libmaple/stm32f1/include/series/dac.h @@ -40,28 +40,28 @@ extern "C"{ /** STM32F1 DAC register map type. */ typedef struct dac_reg_map { - __io uint32 CR; /**< Control register */ - __io uint32 SWTRIGR; /**< Software trigger register */ - __io uint32 DHR12R1; /**< Channel 1 12-bit right-aligned data + __IO uint32 CR; /**< Control register */ + __IO uint32 SWTRIGR; /**< Software trigger register */ + __IO uint32 DHR12R1; /**< Channel 1 12-bit right-aligned data holding register */ - __io uint32 DHR12L1; /**< Channel 1 12-bit left-aligned data + __IO uint32 DHR12L1; /**< Channel 1 12-bit left-aligned data holding register */ - __io uint32 DHR8R1; /**< Channel 1 8-bit left-aligned data + __IO uint32 DHR8R1; /**< Channel 1 8-bit left-aligned data holding register */ - __io uint32 DHR12R2; /**< Channel 2 12-bit right-aligned data + __IO uint32 DHR12R2; /**< Channel 2 12-bit right-aligned data holding register */ - __io uint32 DHR12L2; /**< Channel 2 12-bit left-aligned data + __IO uint32 DHR12L2; /**< Channel 2 12-bit left-aligned data holding register */ - __io uint32 DHR8R2; /**< Channel 2 8-bit left-aligned data + __IO uint32 DHR8R2; /**< Channel 2 8-bit left-aligned data holding register */ - __io uint32 DHR12RD; /**< Dual DAC 12-bit right-aligned data + __IO uint32 DHR12RD; /**< Dual DAC 12-bit right-aligned data holding register */ - __io uint32 DHR12LD; /**< Dual DAC 12-bit left-aligned data + __IO uint32 DHR12LD; /**< Dual DAC 12-bit left-aligned data holding register */ - __io uint32 DHR8RD; /**< Dual DAC 8-bit right-aligned data holding + __IO uint32 DHR8RD; /**< Dual DAC 8-bit right-aligned data holding register */ - __io uint32 DOR1; /**< Channel 1 data output register */ - __io uint32 DOR2; /**< Channel 2 data output register */ + __IO uint32 DOR1; /**< Channel 1 data output register */ + __IO uint32 DOR2; /**< Channel 2 data output register */ } dac_reg_map; #ifdef __cplusplus diff --git a/STM32F1/system/libmaple/stm32f1/include/series/dma.h b/STM32F1/system/libmaple/stm32f1/include/series/dma.h index 56e559b..84fd228 100644 --- a/STM32F1/system/libmaple/stm32f1/include/series/dma.h +++ b/STM32F1/system/libmaple/stm32f1/include/series/dma.h @@ -57,42 +57,42 @@ extern "C"{ * only supports channels 1--5. */ typedef struct dma_reg_map { - __io uint32 ISR; /**< Interrupt status register */ - __io uint32 IFCR; /**< Interrupt flag clear register */ - __io uint32 CCR1; /**< Channel 1 configuration register */ - __io uint32 CNDTR1; /**< Channel 1 number of data register */ - __io uint32 CPAR1; /**< Channel 1 peripheral address register */ - __io uint32 CMAR1; /**< Channel 1 memory address register */ + __IO uint32 ISR; /**< Interrupt status register */ + __IO uint32 IFCR; /**< Interrupt flag clear register */ + __IO uint32 CCR1; /**< Channel 1 configuration register */ + __IO uint32 CNDTR1; /**< Channel 1 number of data register */ + __IO uint32 CPAR1; /**< Channel 1 peripheral address register */ + __IO uint32 CMAR1; /**< Channel 1 memory address register */ const uint32 RESERVED1; /**< Reserved. */ - __io uint32 CCR2; /**< Channel 2 configuration register */ - __io uint32 CNDTR2; /**< Channel 2 number of data register */ - __io uint32 CPAR2; /**< Channel 2 peripheral address register */ - __io uint32 CMAR2; /**< Channel 2 memory address register */ + __IO uint32 CCR2; /**< Channel 2 configuration register */ + __IO uint32 CNDTR2; /**< Channel 2 number of data register */ + __IO uint32 CPAR2; /**< Channel 2 peripheral address register */ + __IO uint32 CMAR2; /**< Channel 2 memory address register */ const uint32 RESERVED2; /**< Reserved. */ - __io uint32 CCR3; /**< Channel 3 configuration register */ - __io uint32 CNDTR3; /**< Channel 3 number of data register */ - __io uint32 CPAR3; /**< Channel 3 peripheral address register */ - __io uint32 CMAR3; /**< Channel 3 memory address register */ + __IO uint32 CCR3; /**< Channel 3 configuration register */ + __IO uint32 CNDTR3; /**< Channel 3 number of data register */ + __IO uint32 CPAR3; /**< Channel 3 peripheral address register */ + __IO uint32 CMAR3; /**< Channel 3 memory address register */ const uint32 RESERVED3; /**< Reserved. */ - __io uint32 CCR4; /**< Channel 4 configuration register */ - __io uint32 CNDTR4; /**< Channel 4 number of data register */ - __io uint32 CPAR4; /**< Channel 4 peripheral address register */ - __io uint32 CMAR4; /**< Channel 4 memory address register */ + __IO uint32 CCR4; /**< Channel 4 configuration register */ + __IO uint32 CNDTR4; /**< Channel 4 number of data register */ + __IO uint32 CPAR4; /**< Channel 4 peripheral address register */ + __IO uint32 CMAR4; /**< Channel 4 memory address register */ const uint32 RESERVED4; /**< Reserved. */ - __io uint32 CCR5; /**< Channel 5 configuration register */ - __io uint32 CNDTR5; /**< Channel 5 number of data register */ - __io uint32 CPAR5; /**< Channel 5 peripheral address register */ - __io uint32 CMAR5; /**< Channel 5 memory address register */ + __IO uint32 CCR5; /**< Channel 5 configuration register */ + __IO uint32 CNDTR5; /**< Channel 5 number of data register */ + __IO uint32 CPAR5; /**< Channel 5 peripheral address register */ + __IO uint32 CMAR5; /**< Channel 5 memory address register */ const uint32 RESERVED5; /**< Reserved. */ - __io uint32 CCR6; /**< Channel 6 configuration register */ - __io uint32 CNDTR6; /**< Channel 6 number of data register */ - __io uint32 CPAR6; /**< Channel 6 peripheral address register */ - __io uint32 CMAR6; /**< Channel 6 memory address register */ + __IO uint32 CCR6; /**< Channel 6 configuration register */ + __IO uint32 CNDTR6; /**< Channel 6 number of data register */ + __IO uint32 CPAR6; /**< Channel 6 peripheral address register */ + __IO uint32 CMAR6; /**< Channel 6 memory address register */ const uint32 RESERVED6; /**< Reserved. */ - __io uint32 CCR7; /**< Channel 7 configuration register */ - __io uint32 CNDTR7; /**< Channel 7 number of data register */ - __io uint32 CPAR7; /**< Channel 7 peripheral address register */ - __io uint32 CMAR7; /**< Channel 7 memory address register */ + __IO uint32 CCR7; /**< Channel 7 configuration register */ + __IO uint32 CNDTR7; /**< Channel 7 number of data register */ + __IO uint32 CPAR7; /**< Channel 7 peripheral address register */ + __IO uint32 CMAR7; /**< Channel 7 memory address register */ const uint32 RESERVED7; /**< Reserved. */ } dma_reg_map; @@ -107,10 +107,10 @@ typedef struct dma_reg_map { * @see dma_tube_regs() */ typedef struct dma_tube_reg_map { - __io uint32 CCR; /**< Channel configuration register */ - __io uint32 CNDTR; /**< Channel number of data register */ - __io uint32 CPAR; /**< Channel peripheral address register */ - __io uint32 CMAR; /**< Channel memory address register */ + __IO uint32 CCR; /**< Channel configuration register */ + __IO uint32 CNDTR; /**< Channel number of data register */ + __IO uint32 CPAR; /**< Channel peripheral address register */ + __IO uint32 CMAR; /**< Channel memory address register */ } dma_tube_reg_map; /** DMA1 channel 1 register map base pointer */ @@ -516,7 +516,7 @@ typedef enum dma_request_src { #define DMA_CHANNEL_NREGS 5 /* accounts for reserved word */ static inline dma_tube_reg_map* dma_tube_regs(dma_dev *dev, dma_tube tube) { - __io uint32 *ccr1 = &dev->regs->CCR1; + __IO uint32 *ccr1 = &dev->regs->CCR1; return (dma_channel_reg_map*)(ccr1 + DMA_CHANNEL_NREGS * (tube - 1)); } @@ -561,9 +561,9 @@ typedef enum dma_mode_flags { * this information, so this interface is too tied to the F1.) */ void dma_setup_transfer(dma_dev *dev, dma_channel channel, - __io void *peripheral_address, + __IO void *peripheral_address, dma_xfer_size peripheral_size, - __io void *memory_address, + __IO void *memory_address, dma_xfer_size memory_size, uint32 mode); diff --git a/STM32F1/system/libmaple/stm32f1/include/series/flash.h b/STM32F1/system/libmaple/stm32f1/include/series/flash.h index 24efb0b..a0bcd82 100644 --- a/STM32F1/system/libmaple/stm32f1/include/series/flash.h +++ b/STM32F1/system/libmaple/stm32f1/include/series/flash.h @@ -48,14 +48,14 @@ extern "C"{ /** @brief STM32F1 Flash register map type */ typedef struct flash_reg_map { - __io uint32 ACR; /**< Access control register */ - __io uint32 KEYR; /**< Key register */ - __io uint32 OPTKEYR; /**< OPTKEY register */ - __io uint32 SR; /**< Status register */ - __io uint32 CR; /**< Control register */ - __io uint32 AR; /**< Address register */ - __io uint32 OBR; /**< Option byte register */ - __io uint32 WRPR; /**< Write protection register */ + __IO uint32 ACR; /**< Access control register */ + __IO uint32 KEYR; /**< Key register */ + __IO uint32 OPTKEYR; /**< OPTKEY register */ + __IO uint32 SR; /**< Status register */ + __IO uint32 CR; /**< Control register */ + __IO uint32 AR; /**< Address register */ + __IO uint32 OBR; /**< Option byte register */ + __IO uint32 WRPR; /**< Write protection register */ } flash_reg_map; #define FLASH_BASE ((struct flash_reg_map*)0x40022000) diff --git a/STM32F1/system/libmaple/stm32f1/include/series/gpio.h b/STM32F1/system/libmaple/stm32f1/include/series/gpio.h index aff639b..803e2ed 100644 --- a/STM32F1/system/libmaple/stm32f1/include/series/gpio.h +++ b/STM32F1/system/libmaple/stm32f1/include/series/gpio.h @@ -48,13 +48,13 @@ extern "C"{ /** GPIO register map type */ typedef struct gpio_reg_map { - __io uint32 CRL; /**< Port configuration register low */ - __io uint32 CRH; /**< Port configuration register high */ - __io uint32 IDR; /**< Port input data register */ - __io uint32 ODR; /**< Port output data register */ - __io uint32 BSRR; /**< Port bit set/reset register */ - __io uint32 BRR; /**< Port bit reset register */ - __io uint32 LCKR; /**< Port configuration lock register */ + __IO uint32 CRL; /**< Port configuration register low */ + __IO uint32 CRH; /**< Port configuration register high */ + __IO uint32 IDR; /**< Port input data register */ + __IO uint32 ODR; /**< Port output data register */ + __IO uint32 BSRR; /**< Port bit set/reset register */ + __IO uint32 BRR; /**< Port bit reset register */ + __IO uint32 LCKR; /**< Port configuration lock register */ } gpio_reg_map; struct gpio_dev; @@ -145,13 +145,13 @@ typedef enum gpio_pin_mode { /** AFIO register map */ typedef struct afio_reg_map { - __io uint32 EVCR; /**< Event control register. */ - __io uint32 MAPR; /**< AF remap and debug I/O configuration register. */ - __io uint32 EXTICR1; /**< External interrupt configuration register 1. */ - __io uint32 EXTICR2; /**< External interrupt configuration register 2. */ - __io uint32 EXTICR3; /**< External interrupt configuration register 3. */ - __io uint32 EXTICR4; /**< External interrupt configuration register 4. */ - __io uint32 MAPR2; /**< + __IO uint32 EVCR; /**< Event control register. */ + __IO uint32 MAPR; /**< AF remap and debug I/O configuration register. */ + __IO uint32 EXTICR1; /**< External interrupt configuration register 1. */ + __IO uint32 EXTICR2; /**< External interrupt configuration register 2. */ + __IO uint32 EXTICR3; /**< External interrupt configuration register 3. */ + __IO uint32 EXTICR4; /**< External interrupt configuration register 4. */ + __IO uint32 MAPR2; /**< * AF remap and debug I/O configuration register 2. */ } afio_reg_map; @@ -404,7 +404,7 @@ typedef enum afio_debug_cfg { * @see afio_debug_cfg */ static inline void afio_cfg_debug_ports(afio_debug_cfg config) { - __io uint32 *mapr = &AFIO_BASE->MAPR; + __IO uint32 *mapr = &AFIO_BASE->MAPR; *mapr = (*mapr & ~AFIO_MAPR_SWJ_CFG) | config; } diff --git a/STM32F1/system/libmaple/stm32f1/include/series/rcc.h b/STM32F1/system/libmaple/stm32f1/include/series/rcc.h index f40dcba..e6a4a5b 100644 --- a/STM32F1/system/libmaple/stm32f1/include/series/rcc.h +++ b/STM32F1/system/libmaple/stm32f1/include/series/rcc.h @@ -46,16 +46,16 @@ extern "C"{ /** STM32F1 RCC register map type */ typedef struct rcc_reg_map { - __io uint32 CR; /**< Clock control register */ - __io uint32 CFGR; /**< Clock configuration register */ - __io uint32 CIR; /**< Clock interrupt register */ - __io uint32 APB2RSTR; /**< APB2 peripheral reset register */ - __io uint32 APB1RSTR; /**< APB1 peripheral reset register */ - __io uint32 AHBENR; /**< AHB peripheral clock enable register */ - __io uint32 APB2ENR; /**< APB2 peripheral clock enable register */ - __io uint32 APB1ENR; /**< APB1 peripheral clock enable register */ - __io uint32 BDCR; /**< Backup domain control register */ - __io uint32 CSR; /**< Control/status register */ + __IO uint32 CR; /**< Clock control register */ + __IO uint32 CFGR; /**< Clock configuration register */ + __IO uint32 CIR; /**< Clock interrupt register */ + __IO uint32 APB2RSTR; /**< APB2 peripheral reset register */ + __IO uint32 APB1RSTR; /**< APB1 peripheral reset register */ + __IO uint32 AHBENR; /**< AHB peripheral clock enable register */ + __IO uint32 APB2ENR; /**< APB2 peripheral clock enable register */ + __IO uint32 APB1ENR; /**< APB1 peripheral clock enable register */ + __IO uint32 BDCR; /**< Backup domain control register */ + __IO uint32 CSR; /**< Control/status register */ } rcc_reg_map; #define RCC_BASE ((struct rcc_reg_map*)0x40021000) diff --git a/STM32F1/system/libmaple/stm32f1/include/series/timer.h b/STM32F1/system/libmaple/stm32f1/include/series/timer.h index 8c1f8f4..c07b7b4 100644 --- a/STM32F1/system/libmaple/stm32f1/include/series/timer.h +++ b/STM32F1/system/libmaple/stm32f1/include/series/timer.h @@ -41,26 +41,26 @@ /** STM32F1 general purpose timer register map type */ typedef struct timer_gen_reg_map { - __io uint32 CR1; /**< Control register 1 */ - __io uint32 CR2; /**< Control register 2 */ - __io uint32 SMCR; /**< Slave mode control register */ - __io uint32 DIER; /**< DMA/Interrupt enable register */ - __io uint32 SR; /**< Status register */ - __io uint32 EGR; /**< Event generation register */ - __io uint32 CCMR1; /**< Capture/compare mode register 1 */ - __io uint32 CCMR2; /**< Capture/compare mode register 2 */ - __io uint32 CCER; /**< Capture/compare enable register */ - __io uint32 CNT; /**< Counter */ - __io uint32 PSC; /**< Prescaler */ - __io uint32 ARR; /**< Auto-reload register */ + __IO uint32 CR1; /**< Control register 1 */ + __IO uint32 CR2; /**< Control register 2 */ + __IO uint32 SMCR; /**< Slave mode control register */ + __IO uint32 DIER; /**< DMA/Interrupt enable register */ + __IO uint32 SR; /**< Status register */ + __IO uint32 EGR; /**< Event generation register */ + __IO uint32 CCMR1; /**< Capture/compare mode register 1 */ + __IO uint32 CCMR2; /**< Capture/compare mode register 2 */ + __IO uint32 CCER; /**< Capture/compare enable register */ + __IO uint32 CNT; /**< Counter */ + __IO uint32 PSC; /**< Prescaler */ + __IO uint32 ARR; /**< Auto-reload register */ const uint32 RESERVED1; /**< Reserved */ - __io uint32 CCR1; /**< Capture/compare register 1 */ - __io uint32 CCR2; /**< Capture/compare register 2 */ - __io uint32 CCR3; /**< Capture/compare register 3 */ - __io uint32 CCR4; /**< Capture/compare register 4 */ + __IO uint32 CCR1; /**< Capture/compare register 1 */ + __IO uint32 CCR2; /**< Capture/compare register 2 */ + __IO uint32 CCR3; /**< Capture/compare register 3 */ + __IO uint32 CCR4; /**< Capture/compare register 4 */ const uint32 RESERVED2; /**< Reserved */ - __io uint32 DCR; /**< DMA control register */ - __io uint32 DMAR; /**< DMA address for full transfer */ + __IO uint32 DCR; /**< DMA control register */ + __IO uint32 DMAR; /**< DMA address for full transfer */ } timer_gen_reg_map; struct timer_adv_reg_map; diff --git a/STM32F1/system/libmaple/stm32f2/include/series/adc.h b/STM32F1/system/libmaple/stm32f2/include/series/adc.h index 175fe11..3bfa2cc 100644 --- a/STM32F1/system/libmaple/stm32f2/include/series/adc.h +++ b/STM32F1/system/libmaple/stm32f2/include/series/adc.h @@ -49,9 +49,9 @@ extern const struct adc_dev *ADC3; /** ADC common register map type */ typedef struct adc_common_reg_map { - __io uint32 CSR; /**< Common status register */ - __io uint32 CCR; /**< Common control register */ - __io uint32 CDR; /**< + __IO uint32 CSR; /**< Common status register */ + __IO uint32 CCR; /**< Common control register */ + __IO uint32 CDR; /**< * @brief Common regular data register * for dual and triple modes */ } adc_common_reg_map; diff --git a/STM32F1/system/libmaple/stm32f2/include/series/dac.h b/STM32F1/system/libmaple/stm32f2/include/series/dac.h index 0a578ca..0d74a16 100644 --- a/STM32F1/system/libmaple/stm32f2/include/series/dac.h +++ b/STM32F1/system/libmaple/stm32f2/include/series/dac.h @@ -44,29 +44,29 @@ extern "C"{ /** STM32F2 DAC register map type. */ typedef struct dac_reg_map { - __io uint32 CR; /**< Control register */ - __io uint32 SWTRIGR; /**< Software trigger register */ - __io uint32 DHR12R1; /**< Channel 1 12-bit right-aligned data + __IO uint32 CR; /**< Control register */ + __IO uint32 SWTRIGR; /**< Software trigger register */ + __IO uint32 DHR12R1; /**< Channel 1 12-bit right-aligned data holding register */ - __io uint32 DHR12L1; /**< Channel 1 12-bit left-aligned data + __IO uint32 DHR12L1; /**< Channel 1 12-bit left-aligned data holding register */ - __io uint32 DHR8R1; /**< Channel 1 8-bit left-aligned data + __IO uint32 DHR8R1; /**< Channel 1 8-bit left-aligned data holding register */ - __io uint32 DHR12R2; /**< Channel 2 12-bit right-aligned data + __IO uint32 DHR12R2; /**< Channel 2 12-bit right-aligned data holding register */ - __io uint32 DHR12L2; /**< Channel 2 12-bit left-aligned data + __IO uint32 DHR12L2; /**< Channel 2 12-bit left-aligned data holding register */ - __io uint32 DHR8R2; /**< Channel 2 8-bit left-aligned data + __IO uint32 DHR8R2; /**< Channel 2 8-bit left-aligned data holding register */ - __io uint32 DHR12RD; /**< Dual DAC 12-bit right-aligned data + __IO uint32 DHR12RD; /**< Dual DAC 12-bit right-aligned data holding register */ - __io uint32 DHR12LD; /**< Dual DAC 12-bit left-aligned data + __IO uint32 DHR12LD; /**< Dual DAC 12-bit left-aligned data holding register */ - __io uint32 DHR8RD; /**< Dual DAC 8-bit right-aligned data holding + __IO uint32 DHR8RD; /**< Dual DAC 8-bit right-aligned data holding register */ - __io uint32 DOR1; /**< Channel 1 data output register */ - __io uint32 DOR2; /**< Channel 2 data output register */ - __io uint32 SR; /**< Status register */ + __IO uint32 DOR1; /**< Channel 1 data output register */ + __IO uint32 DOR2; /**< Channel 2 data output register */ + __IO uint32 SR; /**< Status register */ } dac_reg_map; /* diff --git a/STM32F1/system/libmaple/stm32f2/include/series/dma.h b/STM32F1/system/libmaple/stm32f2/include/series/dma.h index 56725e5..4c86443 100644 --- a/STM32F1/system/libmaple/stm32f2/include/series/dma.h +++ b/STM32F1/system/libmaple/stm32f2/include/series/dma.h @@ -51,66 +51,66 @@ typedef struct dma_reg_map { /* Isn't it nice how on F1, it's CCR1, but on F2, it's S1CR? */ /* Global DMA registers */ - __io uint32 LISR; /**< Low interrupt status register */ - __io uint32 HISR; /**< High interrupt status register */ - __io uint32 LIFCR; /**< Low interrupt flag clear register */ - __io uint32 HIFCR; /**< High interrupt flag clear register */ + __IO uint32 LISR; /**< Low interrupt status register */ + __IO uint32 HISR; /**< High interrupt status register */ + __IO uint32 LIFCR; /**< Low interrupt flag clear register */ + __IO uint32 HIFCR; /**< High interrupt flag clear register */ /* Stream 0 registers */ - __io uint32 S0CR; /**< Stream 0 control register */ - __io uint32 S0NDTR; /**< Stream 0 number of data register */ - __io uint32 S0PAR; /**< Stream 0 peripheral address register */ - __io uint32 S0M0AR; /**< Stream 0 memory 0 address register */ - __io uint32 S0M1AR; /**< Stream 0 memory 1 address register */ - __io uint32 S0FCR; /**< Stream 0 FIFO control register */ + __IO uint32 S0CR; /**< Stream 0 control register */ + __IO uint32 S0NDTR; /**< Stream 0 number of data register */ + __IO uint32 S0PAR; /**< Stream 0 peripheral address register */ + __IO uint32 S0M0AR; /**< Stream 0 memory 0 address register */ + __IO uint32 S0M1AR; /**< Stream 0 memory 1 address register */ + __IO uint32 S0FCR; /**< Stream 0 FIFO control register */ /* Stream 1 registers */ - __io uint32 S1CR; /**< Stream 1 control register */ - __io uint32 S1NDTR; /**< Stream 1 number of data register */ - __io uint32 S1PAR; /**< Stream 1 peripheral address register */ - __io uint32 S1M0AR; /**< Stream 1 memory 0 address register */ - __io uint32 S1M1AR; /**< Stream 1 memory 1 address register */ - __io uint32 S1FCR; /**< Stream 1 FIFO control register */ + __IO uint32 S1CR; /**< Stream 1 control register */ + __IO uint32 S1NDTR; /**< Stream 1 number of data register */ + __IO uint32 S1PAR; /**< Stream 1 peripheral address register */ + __IO uint32 S1M0AR; /**< Stream 1 memory 0 address register */ + __IO uint32 S1M1AR; /**< Stream 1 memory 1 address register */ + __IO uint32 S1FCR; /**< Stream 1 FIFO control register */ /* Stream 2 registers */ - __io uint32 S2CR; /**< Stream 2 control register */ - __io uint32 S2NDTR; /**< Stream 2 number of data register */ - __io uint32 S2PAR; /**< Stream 2 peripheral address register */ - __io uint32 S2M0AR; /**< Stream 2 memory 0 address register */ - __io uint32 S2M1AR; /**< Stream 2 memory 1 address register */ - __io uint32 S2FCR; /**< Stream 2 FIFO control register */ + __IO uint32 S2CR; /**< Stream 2 control register */ + __IO uint32 S2NDTR; /**< Stream 2 number of data register */ + __IO uint32 S2PAR; /**< Stream 2 peripheral address register */ + __IO uint32 S2M0AR; /**< Stream 2 memory 0 address register */ + __IO uint32 S2M1AR; /**< Stream 2 memory 1 address register */ + __IO uint32 S2FCR; /**< Stream 2 FIFO control register */ /* Stream 3 registers */ - __io uint32 S3CR; /**< Stream 3 control register */ - __io uint32 S3NDTR; /**< Stream 3 number of data register */ - __io uint32 S3PAR; /**< Stream 3 peripheral address register */ - __io uint32 S3M0AR; /**< Stream 3 memory 0 address register */ - __io uint32 S3M1AR; /**< Stream 3 memory 1 address register */ - __io uint32 S3FCR; /**< Stream 3 FIFO control register */ + __IO uint32 S3CR; /**< Stream 3 control register */ + __IO uint32 S3NDTR; /**< Stream 3 number of data register */ + __IO uint32 S3PAR; /**< Stream 3 peripheral address register */ + __IO uint32 S3M0AR; /**< Stream 3 memory 0 address register */ + __IO uint32 S3M1AR; /**< Stream 3 memory 1 address register */ + __IO uint32 S3FCR; /**< Stream 3 FIFO control register */ /* Stream 4 registers */ - __io uint32 S4CR; /**< Stream 4 control register */ - __io uint32 S4NDTR; /**< Stream 4 number of data register */ - __io uint32 S4PAR; /**< Stream 4 peripheral address register */ - __io uint32 S4M0AR; /**< Stream 4 memory 0 address register */ - __io uint32 S4M1AR; /**< Stream 4 memory 1 address register */ - __io uint32 S4FCR; /**< Stream 4 FIFO control register */ + __IO uint32 S4CR; /**< Stream 4 control register */ + __IO uint32 S4NDTR; /**< Stream 4 number of data register */ + __IO uint32 S4PAR; /**< Stream 4 peripheral address register */ + __IO uint32 S4M0AR; /**< Stream 4 memory 0 address register */ + __IO uint32 S4M1AR; /**< Stream 4 memory 1 address register */ + __IO uint32 S4FCR; /**< Stream 4 FIFO control register */ /* Stream 5 registers */ - __io uint32 S5CR; /**< Stream 5 control register */ - __io uint32 S5NDTR; /**< Stream 5 number of data register */ - __io uint32 S5PAR; /**< Stream 5 peripheral address register */ - __io uint32 S5M0AR; /**< Stream 5 memory 0 address register */ - __io uint32 S5M1AR; /**< Stream 5 memory 1 address register */ - __io uint32 S5FCR; /**< Stream 5 FIFO control register */ + __IO uint32 S5CR; /**< Stream 5 control register */ + __IO uint32 S5NDTR; /**< Stream 5 number of data register */ + __IO uint32 S5PAR; /**< Stream 5 peripheral address register */ + __IO uint32 S5M0AR; /**< Stream 5 memory 0 address register */ + __IO uint32 S5M1AR; /**< Stream 5 memory 1 address register */ + __IO uint32 S5FCR; /**< Stream 5 FIFO control register */ /* Stream 6 registers */ - __io uint32 S6CR; /**< Stream 6 control register */ - __io uint32 S6NDTR; /**< Stream 6 number of data register */ - __io uint32 S6PAR; /**< Stream 6 peripheral address register */ - __io uint32 S6M0AR; /**< Stream 6 memory 0 address register */ - __io uint32 S6M1AR; /**< Stream 6 memory 1 address register */ - __io uint32 S6FCR; /**< Stream 6 FIFO control register */ + __IO uint32 S6CR; /**< Stream 6 control register */ + __IO uint32 S6NDTR; /**< Stream 6 number of data register */ + __IO uint32 S6PAR; /**< Stream 6 peripheral address register */ + __IO uint32 S6M0AR; /**< Stream 6 memory 0 address register */ + __IO uint32 S6M1AR; /**< Stream 6 memory 1 address register */ + __IO uint32 S6FCR; /**< Stream 6 FIFO control register */ /* Stream 7 registers */ - __io uint32 S7CR; /**< Stream 7 control register */ - __io uint32 S7NDTR; /**< Stream 7 number of data register */ - __io uint32 S7PAR; /**< Stream 7 peripheral address register */ - __io uint32 S7M0AR; /**< Stream 7 memory 0 address register */ - __io uint32 S7M1AR; /**< Stream 7 memory 1 address register */ - __io uint32 S7FCR; /**< Stream 7 FIFO control register */ + __IO uint32 S7CR; /**< Stream 7 control register */ + __IO uint32 S7NDTR; /**< Stream 7 number of data register */ + __IO uint32 S7PAR; /**< Stream 7 peripheral address register */ + __IO uint32 S7M0AR; /**< Stream 7 memory 0 address register */ + __IO uint32 S7M1AR; /**< Stream 7 memory 1 address register */ + __IO uint32 S7FCR; /**< Stream 7 FIFO control register */ } dma_reg_map; /** DMA controller 1 register map base pointer */ @@ -124,12 +124,12 @@ typedef struct dma_reg_map { * @see dma_tube_regs() */ typedef struct dma_tube_reg_map { - __io uint32 SCR; /**< Stream configuration register */ - __io uint32 SNDTR; /**< Stream number of data register */ - __io uint32 SPAR; /**< Stream peripheral address register */ - __io uint32 SM0AR; /**< Stream memory 0 address register */ - __io uint32 SM1AR; /**< Stream memory 1 address register */ - __io uint32 SFCR; /**< Stream FIFO control register */ + __IO uint32 SCR; /**< Stream configuration register */ + __IO uint32 SNDTR; /**< Stream number of data register */ + __IO uint32 SPAR; /**< Stream peripheral address register */ + __IO uint32 SM0AR; /**< Stream memory 0 address register */ + __IO uint32 SM1AR; /**< Stream memory 1 address register */ + __IO uint32 SFCR; /**< Stream FIFO control register */ } dma_tube_reg_map; /** DMA1 stream 0 register map base pointer */ @@ -697,7 +697,7 @@ static inline uint8 dma_is_enabled(dma_dev *dev, dma_tube tube) { /* F2-only; available because of double-buffering. */ void dma_set_mem_n_addr(dma_dev *dev, dma_tube tube, int n, - __io void *address); + __IO void *address); /** * @brief Set memory 0 address. @@ -708,7 +708,7 @@ void dma_set_mem_n_addr(dma_dev *dev, dma_tube tube, int n, * @param addr Address to use as memory 0 */ static inline __always_inline void -dma_set_mem0_addr(dma_dev *dev, dma_tube tube, __io void *addr) { +dma_set_mem0_addr(dma_dev *dev, dma_tube tube, __IO void *addr) { dma_set_mem_n_addr(dev, tube, 0, addr); } @@ -721,13 +721,13 @@ dma_set_mem0_addr(dma_dev *dev, dma_tube tube, __io void *addr) { * @param addr Address to use as memory 1 */ static inline __always_inline void -dma_set_mem1_addr(dma_dev *dev, dma_tube tube, __io void *addr) { +dma_set_mem1_addr(dma_dev *dev, dma_tube tube, __IO void *addr) { dma_set_mem_n_addr(dev, tube, 1, addr); } /* Assume the user means SM0AR in a non-double-buffered configuration. */ static inline __always_inline void -dma_set_mem_addr(dma_dev *dev, dma_tube tube, __io void *addr) { +dma_set_mem_addr(dma_dev *dev, dma_tube tube, __IO void *addr) { dma_set_mem0_addr(dev, tube, addr); } @@ -791,13 +791,13 @@ static inline __always_inline uint32 _dma_sr_fcr_shift(dma_tube tube) { static inline uint8 dma_get_isr_bits(dma_dev *dev, dma_tube tube) { dma_reg_map *regs = dev->regs; - __io uint32 *isr = tube > DMA_S3 ? ®s->HISR : ®s->LISR; + __IO uint32 *isr = tube > DMA_S3 ? ®s->HISR : ®s->LISR; return (*isr >> _dma_sr_fcr_shift(tube)) & 0x3D; } static inline void dma_clear_isr_bits(dma_dev *dev, dma_tube tube) { dma_reg_map *regs = dev->regs; - __io uint32 *ifcr = tube > DMA_S3 ? ®s->HIFCR : ®s->LIFCR; + __IO uint32 *ifcr = tube > DMA_S3 ? ®s->HIFCR : ®s->LIFCR; *ifcr = (0x3D << _dma_sr_fcr_shift(tube)); } diff --git a/STM32F1/system/libmaple/stm32f2/include/series/flash.h b/STM32F1/system/libmaple/stm32f2/include/series/flash.h index a3c3933..a02d4ca 100644 --- a/STM32F1/system/libmaple/stm32f2/include/series/flash.h +++ b/STM32F1/system/libmaple/stm32f2/include/series/flash.h @@ -48,12 +48,12 @@ extern "C"{ /** @brief STM32F2 Flash register map type */ typedef struct flash_reg_map { - __io uint32 ACR; /**< Access control register */ - __io uint32 KEYR; /**< Key register */ - __io uint32 OPTKEYR; /**< Option key register */ - __io uint32 SR; /**< Status register */ - __io uint32 CR; /**< Control register */ - __io uint32 OPTCR; /**< Option control register */ + __IO uint32 ACR; /**< Access control register */ + __IO uint32 KEYR; /**< Key register */ + __IO uint32 OPTKEYR; /**< Option key register */ + __IO uint32 SR; /**< Status register */ + __IO uint32 CR; /**< Control register */ + __IO uint32 OPTCR; /**< Option control register */ } flash_reg_map; #define FLASH_BASE ((struct flash_reg_map*)0x40023C00) diff --git a/STM32F1/system/libmaple/stm32f2/include/series/gpio.h b/STM32F1/system/libmaple/stm32f2/include/series/gpio.h index 4d0d98c..13d8366 100644 --- a/STM32F1/system/libmaple/stm32f2/include/series/gpio.h +++ b/STM32F1/system/libmaple/stm32f2/include/series/gpio.h @@ -44,16 +44,16 @@ extern "C"{ /** GPIO register map type */ typedef struct gpio_reg_map { - __io uint32 MODER; /**< Mode register */ - __io uint32 OTYPER; /**< Output type register */ - __io uint32 OSPEEDR; /**< Output speed register */ - __io uint32 PUPDR; /**< Pull-up/pull-down register */ - __io uint32 IDR; /**< Input data register */ - __io uint32 ODR; /**< Output data register */ - __io uint32 BSRR; /**< Bit set/reset register */ - __io uint32 LCKR; /**< Configuration lock register */ - __io uint32 AFRL; /**< Alternate function low register */ - __io uint32 AFRH; /**< Alternate function high register */ + __IO uint32 MODER; /**< Mode register */ + __IO uint32 OTYPER; /**< Output type register */ + __IO uint32 OSPEEDR; /**< Output speed register */ + __IO uint32 PUPDR; /**< Pull-up/pull-down register */ + __IO uint32 IDR; /**< Input data register */ + __IO uint32 ODR; /**< Output data register */ + __IO uint32 BSRR; /**< Bit set/reset register */ + __IO uint32 LCKR; /**< Configuration lock register */ + __IO uint32 AFRL; /**< Alternate function low register */ + __IO uint32 AFRH; /**< Alternate function high register */ } gpio_reg_map; /** GPIO port A register map base pointer */ diff --git a/STM32F1/system/libmaple/stm32f2/include/series/rcc.h b/STM32F1/system/libmaple/stm32f2/include/series/rcc.h index 441a5a8..eae4d42 100644 --- a/STM32F1/system/libmaple/stm32f2/include/series/rcc.h +++ b/STM32F1/system/libmaple/stm32f2/include/series/rcc.h @@ -44,46 +44,46 @@ extern "C"{ /** STM32F2 RCC register map type */ typedef struct rcc_reg_map { - __io uint32 CR; /**< Clock control register */ - __io uint32 PLLCFGR; /**< PLL configuration register */ - __io uint32 CFGR; /**< Clock configuration register */ - __io uint32 CIR; /**< Clock interrupt register */ - __io uint32 AHB1RSTR; /**< AHB1 peripheral reset register */ - __io uint32 AHB2RSTR; /**< AHB2 peripheral reset register */ - __io uint32 AHB3RSTR; /**< AHB3 peripheral reset register */ + __IO uint32 CR; /**< Clock control register */ + __IO uint32 PLLCFGR; /**< PLL configuration register */ + __IO uint32 CFGR; /**< Clock configuration register */ + __IO uint32 CIR; /**< Clock interrupt register */ + __IO uint32 AHB1RSTR; /**< AHB1 peripheral reset register */ + __IO uint32 AHB2RSTR; /**< AHB2 peripheral reset register */ + __IO uint32 AHB3RSTR; /**< AHB3 peripheral reset register */ const uint32 RESERVED1; /**< Reserved */ - __io uint32 APB1RSTR; /**< APB1 peripheral reset register */ - __io uint32 APB2RSTR; /**< APB2 peripheral reset register */ + __IO uint32 APB1RSTR; /**< APB1 peripheral reset register */ + __IO uint32 APB2RSTR; /**< APB2 peripheral reset register */ const uint32 RESERVED2; /**< Reserved */ const uint32 RESERVED3; /**< Reserved */ - __io uint32 AHB1ENR; /**< AHB1 peripheral clock enable register */ - __io uint32 AHB2ENR; /**< AHB2 peripheral clock enable register */ - __io uint32 AHB3ENR; /**< AHB3 peripheral clock enable register */ + __IO uint32 AHB1ENR; /**< AHB1 peripheral clock enable register */ + __IO uint32 AHB2ENR; /**< AHB2 peripheral clock enable register */ + __IO uint32 AHB3ENR; /**< AHB3 peripheral clock enable register */ const uint32 RESERVED4; /**< Reserved */ - __io uint32 APB1ENR; /**< APB1 peripheral clock enable register */ - __io uint32 APB2ENR; /**< APB2 peripheral clock enable register */ + __IO uint32 APB1ENR; /**< APB1 peripheral clock enable register */ + __IO uint32 APB2ENR; /**< APB2 peripheral clock enable register */ const uint32 RESERVED5; /**< Reserved */ const uint32 RESERVED6; /**< Reserved */ - __io uint32 AHB1LPENR; /**< AHB1 peripheral clock enable in + __IO uint32 AHB1LPENR; /**< AHB1 peripheral clock enable in low power mode register */ - __io uint32 AHB2LPENR; /**< AHB2 peripheral clock enable in + __IO uint32 AHB2LPENR; /**< AHB2 peripheral clock enable in low power mode register */ - __io uint32 AHB3LPENR; /**< AHB3 peripheral clock enable in + __IO uint32 AHB3LPENR; /**< AHB3 peripheral clock enable in low power mode register */ const uint32 RESERVED7; /**< Reserved */ - __io uint32 APB1LPENR; /**< APB1 peripheral clock enable in + __IO uint32 APB1LPENR; /**< APB1 peripheral clock enable in low power mode register */ - __io uint32 APB2LPENR; /**< APB2 peripheral clock enable in + __IO uint32 APB2LPENR; /**< APB2 peripheral clock enable in low power mode register */ const uint32 RESERVED8; /**< Reserved */ const uint32 RESERVED9; /**< Reserved */ - __io uint32 BDCR; /**< Backup domain control register */ - __io uint32 CSR; /**< Clock control and status register */ + __IO uint32 BDCR; /**< Backup domain control register */ + __IO uint32 CSR; /**< Clock control and status register */ const uint32 RESERVED10; /**< Reserved */ const uint32 RESERVED11; /**< Reserved */ - __io uint32 SSCGR; /**< Spread spectrum clock generation + __IO uint32 SSCGR; /**< Spread spectrum clock generation register */ - __io uint32 PLLI2SCFGR; /**< PLLI2S configuration register */ + __IO uint32 PLLI2SCFGR; /**< PLLI2S configuration register */ } rcc_reg_map; #define RCC_BASE ((struct rcc_reg_map*)0x40023800) diff --git a/STM32F1/system/libmaple/stm32f2/include/series/timer.h b/STM32F1/system/libmaple/stm32f2/include/series/timer.h index a7ac276..94f6547 100644 --- a/STM32F1/system/libmaple/stm32f2/include/series/timer.h +++ b/STM32F1/system/libmaple/stm32f2/include/series/timer.h @@ -47,27 +47,27 @@ * registers. Consult your chip's reference manual for the details. */ typedef struct timer_gen_reg_map { - __io uint32 CR1; /**< Control register 1 */ - __io uint32 CR2; /**< Control register 2 */ - __io uint32 SMCR; /**< Slave mode control register */ - __io uint32 DIER; /**< DMA/Interrupt enable register */ - __io uint32 SR; /**< Status register */ - __io uint32 EGR; /**< Event generation register */ - __io uint32 CCMR1; /**< Capture/compare mode register 1 */ - __io uint32 CCMR2; /**< Capture/compare mode register 2 */ - __io uint32 CCER; /**< Capture/compare enable register */ - __io uint32 CNT; /**< Counter */ - __io uint32 PSC; /**< Prescaler */ - __io uint32 ARR; /**< Auto-reload register */ + __IO uint32 CR1; /**< Control register 1 */ + __IO uint32 CR2; /**< Control register 2 */ + __IO uint32 SMCR; /**< Slave mode control register */ + __IO uint32 DIER; /**< DMA/Interrupt enable register */ + __IO uint32 SR; /**< Status register */ + __IO uint32 EGR; /**< Event generation register */ + __IO uint32 CCMR1; /**< Capture/compare mode register 1 */ + __IO uint32 CCMR2; /**< Capture/compare mode register 2 */ + __IO uint32 CCER; /**< Capture/compare enable register */ + __IO uint32 CNT; /**< Counter */ + __IO uint32 PSC; /**< Prescaler */ + __IO uint32 ARR; /**< Auto-reload register */ const uint32 RESERVED1; /**< Reserved */ - __io uint32 CCR1; /**< Capture/compare register 1 */ - __io uint32 CCR2; /**< Capture/compare register 2 */ - __io uint32 CCR3; /**< Capture/compare register 3 */ - __io uint32 CCR4; /**< Capture/compare register 4 */ + __IO uint32 CCR1; /**< Capture/compare register 1 */ + __IO uint32 CCR2; /**< Capture/compare register 2 */ + __IO uint32 CCR3; /**< Capture/compare register 3 */ + __IO uint32 CCR4; /**< Capture/compare register 4 */ const uint32 RESERVED2; /**< Reserved */ - __io uint32 DCR; /**< DMA control register */ - __io uint32 DMAR; /**< DMA address for full transfer */ - __io uint32 OR; /**< Option register. */ + __IO uint32 DCR; /**< DMA control register */ + __IO uint32 DMAR; /**< DMA address for full transfer */ + __IO uint32 OR; /**< Option register. */ } timer_gen_reg_map; struct timer_adv_reg_map; diff --git a/STM32F1/system/libmaple/usb/stm32f1/usb_reg_map.h b/STM32F1/system/libmaple/usb/stm32f1/usb_reg_map.h index d0423fc..cdb7422 100644 --- a/STM32F1/system/libmaple/usb/stm32f1/usb_reg_map.h +++ b/STM32F1/system/libmaple/usb/stm32f1/usb_reg_map.h @@ -42,13 +42,13 @@ /** USB register map type */ typedef struct usb_reg_map { - __io uint32 EP[USB_NR_EP_REGS]; /**< Endpoint registers */ + __IO uint32 EP[USB_NR_EP_REGS]; /**< Endpoint registers */ const uint32 RESERVED[8]; /**< Reserved */ - __io uint32 CNTR; /**< Control register */ - __io uint32 ISTR; /**< Interrupt status register */ - __io uint32 FNR; /**< Frame number register */ - __io uint32 DADDR; /**< Device address */ - __io uint32 BTABLE; /**< @brief Buffer table address + __IO uint32 CNTR; /**< Control register */ + __IO uint32 ISTR; /**< Interrupt status register */ + __IO uint32 FNR; /**< Frame number register */ + __IO uint32 DADDR; /**< Device address */ + __IO uint32 BTABLE; /**< @brief Buffer table address * * Address offset within the USB * packet memory area which points @@ -340,7 +340,7 @@ static inline void usb_clear_status_out(uint8 ep) { * * The USB PMA is SRAM shared between USB and CAN. The USB peripheral * accesses this memory directly via the packet buffer interface. */ -#define USB_PMA_BASE ((__io void*)0x40006000) +#define USB_PMA_BASE ((__IO void*)0x40006000) /* * PMA conveniences @@ -367,42 +367,42 @@ union usb_btable_ent; /* Bidirectional endpoint BTABLE entry */ typedef struct usb_btable_bidi { - __io uint16 addr_tx; const uint16 PAD1; - __io uint16 count_tx; const uint16 PAD2; - __io uint16 addr_rx; const uint16 PAD3; - __io uint16 count_rx; const uint16 PAD4; + __IO uint16 addr_tx; const uint16 PAD1; + __IO uint16 count_tx; const uint16 PAD2; + __IO uint16 addr_rx; const uint16 PAD3; + __IO uint16 count_rx; const uint16 PAD4; } usb_btable_bidi; /* Unidirectional receive-only endpoint BTABLE entry */ typedef struct usb_btable_uni_rx { - __io uint16 empty1; const uint16 PAD1; - __io uint16 empty2; const uint16 PAD2; - __io uint16 addr_rx; const uint16 PAD3; - __io uint16 count_rx; const uint16 PAD4; + __IO uint16 empty1; const uint16 PAD1; + __IO uint16 empty2; const uint16 PAD2; + __IO uint16 addr_rx; const uint16 PAD3; + __IO uint16 count_rx; const uint16 PAD4; } usb_btable_uni_rx; /* Unidirectional transmit-only endpoint BTABLE entry */ typedef struct usb_btable_uni_tx { - __io uint16 addr_tx; const uint16 PAD1; - __io uint16 count_tx; const uint16 PAD2; - __io uint16 empty1; const uint16 PAD3; - __io uint16 empty2; const uint16 PAD4; + __IO uint16 addr_tx; const uint16 PAD1; + __IO uint16 count_tx; const uint16 PAD2; + __IO uint16 empty1; const uint16 PAD3; + __IO uint16 empty2; const uint16 PAD4; } usb_btable_uni_tx; /* Double-buffered transmission endpoint BTABLE entry */ typedef struct usb_btable_dbl_tx { - __io uint16 addr_tx0; const uint16 PAD1; - __io uint16 count_tx0; const uint16 PAD2; - __io uint16 addr_tx1; const uint16 PAD3; - __io uint16 count_tx1; const uint16 PAD4; + __IO uint16 addr_tx0; const uint16 PAD1; + __IO uint16 count_tx0; const uint16 PAD2; + __IO uint16 addr_tx1; const uint16 PAD3; + __IO uint16 count_tx1; const uint16 PAD4; } usb_btable_dbl_tx; /* Double-buffered reception endpoint BTABLE entry */ typedef struct usb_btable_dbl_rx { - __io uint16 addr_rx0; const uint16 PAD1; - __io uint16 count_rx0; const uint16 PAD2; - __io uint16 addr_rx1; const uint16 PAD3; - __io uint16 count_rx1; const uint16 PAD4; + __IO uint16 addr_rx0; const uint16 PAD1; + __IO uint16 count_rx0; const uint16 PAD2; + __IO uint16 addr_rx1; const uint16 PAD3; + __IO uint16 count_rx1; const uint16 PAD4; } usb_btable_dbl_rx; /* TODO isochronous endpoint entries */ diff --git a/STM32F3/cores/maple/libmaple/bkp.c b/STM32F3/cores/maple/libmaple/bkp.c index c837307..c48440b 100644 --- a/STM32F3/cores/maple/libmaple/bkp.c +++ b/STM32F3/cores/maple/libmaple/bkp.c @@ -50,7 +50,7 @@ void bkp_disable_writes(void) { } uint16 bkp_read(uint8 reg) { - __io uint32* dr = bkp_data_register(reg); + __IO uint32* dr = bkp_data_register(reg); if (!dr) { ASSERT(0); /* nonexistent register */ return 0; @@ -59,7 +59,7 @@ uint16 bkp_read(uint8 reg) { } void bkp_write(uint8 reg, uint16 val) { - __io uint32* dr = bkp_data_register(reg); + __IO uint32* dr = bkp_data_register(reg); if (!dr) { ASSERT(0); /* nonexistent register */ return; diff --git a/STM32F3/cores/maple/libmaple/dma.c b/STM32F3/cores/maple/libmaple/dma.c index d13de10..1dc875e 100644 --- a/STM32F3/cores/maple/libmaple/dma.c +++ b/STM32F3/cores/maple/libmaple/dma.c @@ -52,7 +52,7 @@ void dma_init(dma_dev *dev) { * Private API */ -enum dma_atype _dma_addr_type(__io void *addr) { +enum dma_atype _dma_addr_type(__IO void *addr) { switch (stm32_block_purpose((void*)addr)) { /* Notice we're treating the code block as memory here. That's * correct for addresses in Flash and in [0x0, 0x7FFFFFF] diff --git a/STM32F3/cores/maple/libmaple/dma_private.h b/STM32F3/cores/maple/libmaple/dma_private.h index b25ded2..9338525 100644 --- a/STM32F3/cores/maple/libmaple/dma_private.h +++ b/STM32F3/cores/maple/libmaple/dma_private.h @@ -56,6 +56,6 @@ enum dma_atype { DMA_ATYPE_OTHER, }; -enum dma_atype _dma_addr_type(__io void *addr); +enum dma_atype _dma_addr_type(__IO void *addr); #endif diff --git a/STM32F3/cores/maple/libmaple/exti.c b/STM32F3/cores/maple/libmaple/exti.c index c35072c..f59c0eb 100644 --- a/STM32F3/cores/maple/libmaple/exti.c +++ b/STM32F3/cores/maple/libmaple/exti.c @@ -200,7 +200,7 @@ void exti_detach_interrupt(exti_num num) { * Private routines */ -void exti_do_select(__io uint32 *exti_cr, exti_num num, exti_cfg port) { +void exti_do_select(__IO uint32 *exti_cr, exti_num num, exti_cfg port) { uint32 shift = 4 * (num % 4); uint32 cr = *exti_cr; cr &= ~(0xF << shift); diff --git a/STM32F3/cores/maple/libmaple/exti_private.h b/STM32F3/cores/maple/libmaple/exti_private.h index 4f0a4cf..221cae4 100644 --- a/STM32F3/cores/maple/libmaple/exti_private.h +++ b/STM32F3/cores/maple/libmaple/exti_private.h @@ -29,6 +29,6 @@ #include -void exti_do_select(__io uint32 *exti_cr, exti_num num, exti_cfg port); +void exti_do_select(__IO uint32 *exti_cr, exti_num num, exti_cfg port); #endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/bkp.h b/STM32F3/cores/maple/libmaple/include/libmaple/bkp.h index 7e795dd..9b00470 100644 --- a/STM32F3/cores/maple/libmaple/include/libmaple/bkp.h +++ b/STM32F3/cores/maple/libmaple/include/libmaple/bkp.h @@ -52,7 +52,7 @@ extern const struct bkp_dev *BKP; /* * this function needs to be implemented for each series separately */ -extern inline __io uint32* bkp_data_register(uint8 reg); +extern inline __IO uint32* bkp_data_register(uint8 reg); /** * @brief Initialize backup interface. diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/dma.h b/STM32F3/cores/maple/libmaple/include/libmaple/dma.h index e22cdaf..329e907 100644 --- a/STM32F3/cores/maple/libmaple/include/libmaple/dma.h +++ b/STM32F3/cores/maple/libmaple/include/libmaple/dma.h @@ -136,12 +136,12 @@ void dma_init(dma_dev *dev); */ typedef struct dma_tube_config { /** Source of data */ - __io void *tube_src; + __IO void *tube_src; /** Source transfer size */ dma_xfer_size tube_src_size; /** Destination of data */ - __io void *tube_dst; + __IO void *tube_dst; /** Destination transfer size */ dma_xfer_size tube_dst_size; @@ -280,7 +280,7 @@ extern void dma_set_num_transfers(dma_dev *dev, dma_tube tube, * @param tube Tube whose base memory address to set. * @param address Memory base address to use. */ -extern void dma_set_mem_addr(dma_dev *dev, dma_tube tube, __io void *address); +extern void dma_set_mem_addr(dma_dev *dev, dma_tube tube, __IO void *address); /** * @brief Set the base peripheral address where data will be read from @@ -296,7 +296,7 @@ extern void dma_set_mem_addr(dma_dev *dev, dma_tube tube, __io void *address); * @param tube Tube whose peripheral data register base address to set. * @param address Peripheral memory base address to use. */ -extern void dma_set_per_addr(dma_dev *dev, dma_tube tube, __io void *address); +extern void dma_set_per_addr(dma_dev *dev, dma_tube tube, __IO void *address); /* Interrupt handling */ diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/exti.h b/STM32F3/cores/maple/libmaple/include/libmaple/exti.h index 1d201ac..525cdc7 100644 --- a/STM32F3/cores/maple/libmaple/include/libmaple/exti.h +++ b/STM32F3/cores/maple/libmaple/include/libmaple/exti.h @@ -47,12 +47,12 @@ extern "C"{ /** EXTI register map type */ typedef struct exti_reg_map { - __io uint32 IMR; /**< Interrupt mask register */ - __io uint32 EMR; /**< Event mask register */ - __io uint32 RTSR; /**< Rising trigger selection register */ - __io uint32 FTSR; /**< Falling trigger selection register */ - __io uint32 SWIER; /**< Software interrupt event register */ - __io uint32 PR; /**< Pending register */ + __IO uint32 IMR; /**< Interrupt mask register */ + __IO uint32 EMR; /**< Event mask register */ + __IO uint32 RTSR; /**< Rising trigger selection register */ + __IO uint32 FTSR; /**< Falling trigger selection register */ + __IO uint32 SWIER; /**< Software interrupt event register */ + __IO uint32 PR; /**< Pending register */ } exti_reg_map; /* diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/fsmc.h b/STM32F3/cores/maple/libmaple/include/libmaple/fsmc.h index 6225fee..9dd8a72 100644 --- a/STM32F3/cores/maple/libmaple/include/libmaple/fsmc.h +++ b/STM32F3/cores/maple/libmaple/include/libmaple/fsmc.h @@ -53,42 +53,42 @@ extern "C"{ /** FSMC register map type */ typedef struct fsmc_reg_map { - __io uint32 BCR1; /**< SRAM/NOR-Flash chip-select control register 1 */ - __io uint32 BTR1; /**< SRAM/NOR-Flash chip-select timing register 1 */ - __io uint32 BCR2; /**< SRAM/NOR-Flash chip-select control register 2 */ - __io uint32 BTR2; /**< SRAM/NOR-Flash chip-select timing register 2 */ - __io uint32 BCR3; /**< SRAM/NOR-Flash chip-select control register 3 */ - __io uint32 BTR3; /**< SRAM/NOR-Flash chip-select timing register 3 */ - __io uint32 BCR4; /**< SRAM/NOR-Flash chip-select control register 4 */ - __io uint32 BTR4; /**< SRAM/NOR-Flash chip-select timing register 4 */ + __IO uint32 BCR1; /**< SRAM/NOR-Flash chip-select control register 1 */ + __IO uint32 BTR1; /**< SRAM/NOR-Flash chip-select timing register 1 */ + __IO uint32 BCR2; /**< SRAM/NOR-Flash chip-select control register 2 */ + __IO uint32 BTR2; /**< SRAM/NOR-Flash chip-select timing register 2 */ + __IO uint32 BCR3; /**< SRAM/NOR-Flash chip-select control register 3 */ + __IO uint32 BTR3; /**< SRAM/NOR-Flash chip-select timing register 3 */ + __IO uint32 BCR4; /**< SRAM/NOR-Flash chip-select control register 4 */ + __IO uint32 BTR4; /**< SRAM/NOR-Flash chip-select timing register 4 */ const uint8 RESERVED1[64]; /**< Reserved */ - __io uint32 PCR2; /**< PC Card/NAND Flash control register 2 */ - __io uint32 SR2; /**< FIFO status and interrupt register 2 */ - __io uint32 PMEM2; /**< Common memory space timing register 2 */ - __io uint32 PATT2; /**< Attribute memory space timing register 2 */ + __IO uint32 PCR2; /**< PC Card/NAND Flash control register 2 */ + __IO uint32 SR2; /**< FIFO status and interrupt register 2 */ + __IO uint32 PMEM2; /**< Common memory space timing register 2 */ + __IO uint32 PATT2; /**< Attribute memory space timing register 2 */ const uint8 RESERVED2[4]; /**< Reserved */ - __io uint32 ECCR2; /**< ECC result register 2 */ + __IO uint32 ECCR2; /**< ECC result register 2 */ const uint8 RESERVED3[2]; - __io uint32 PCR3; /**< PC Card/NAND Flash control register 3 */ - __io uint32 SR3; /**< FIFO status and interrupt register 3 */ - __io uint32 PMEM3; /**< Common memory space timing register 3 */ - __io uint32 PATT3; /**< Attribute memory space timing register 3 */ + __IO uint32 PCR3; /**< PC Card/NAND Flash control register 3 */ + __IO uint32 SR3; /**< FIFO status and interrupt register 3 */ + __IO uint32 PMEM3; /**< Common memory space timing register 3 */ + __IO uint32 PATT3; /**< Attribute memory space timing register 3 */ const uint32 RESERVED4; /**< Reserved */ - __io uint32 ECCR3; /**< ECC result register 3 */ + __IO uint32 ECCR3; /**< ECC result register 3 */ const uint8 RESERVED5[8]; /**< Reserved */ - __io uint32 PCR4; /**< PC Card/NAND Flash control register 4 */ - __io uint32 SR4; /**< FIFO status and interrupt register 4 */ - __io uint32 PMEM4; /**< Common memory space timing register 4 */ - __io uint32 PATT4; /**< Attribute memory space timing register 4 */ - __io uint32 PIO4; /**< I/O space timing register 4 */ + __IO uint32 PCR4; /**< PC Card/NAND Flash control register 4 */ + __IO uint32 SR4; /**< FIFO status and interrupt register 4 */ + __IO uint32 PMEM4; /**< Common memory space timing register 4 */ + __IO uint32 PATT4; /**< Attribute memory space timing register 4 */ + __IO uint32 PIO4; /**< I/O space timing register 4 */ const uint8 RESERVED6[80]; /**< Reserved */ - __io uint32 BWTR1; /**< SRAM/NOR-Flash write timing register 1 */ + __IO uint32 BWTR1; /**< SRAM/NOR-Flash write timing register 1 */ const uint32 RESERVED7; /**< Reserved */ - __io uint32 BWTR2; /**< SRAM/NOR-Flash write timing register 2 */ + __IO uint32 BWTR2; /**< SRAM/NOR-Flash write timing register 2 */ const uint32 RESERVED8; /**< Reserved */ - __io uint32 BWTR3; /**< SRAM/NOR-Flash write timing register 3 */ + __IO uint32 BWTR3; /**< SRAM/NOR-Flash write timing register 3 */ const uint32 RESERVED9; /**< Reserved */ - __io uint32 BWTR4; /**< SRAM/NOR-Flash write timing register 4 */ + __IO uint32 BWTR4; /**< SRAM/NOR-Flash write timing register 4 */ } __attribute__((packed)) fsmc_reg_map; #define __FSMCB 0xA0000000 @@ -98,10 +98,10 @@ typedef struct fsmc_reg_map { /** FSMC NOR/PSRAM register map type */ typedef struct fsmc_nor_psram_reg_map { - __io uint32 BCR; /**< Chip-select control register */ - __io uint32 BTR; /**< Chip-select timing register */ + __IO uint32 BCR; /**< Chip-select control register */ + __IO uint32 BTR; /**< Chip-select timing register */ const uint8 RESERVED[252]; /**< Reserved */ - __io uint32 BWTR; /**< Write timing register */ + __IO uint32 BWTR; /**< Write timing register */ } fsmc_nor_psram_reg_map; /** FSMC NOR/PSRAM base pointer 1 */ diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/iwdg.h b/STM32F3/cores/maple/libmaple/include/libmaple/iwdg.h index 3a16c55..f999439 100644 --- a/STM32F3/cores/maple/libmaple/include/libmaple/iwdg.h +++ b/STM32F3/cores/maple/libmaple/include/libmaple/iwdg.h @@ -53,10 +53,10 @@ extern "C"{ /** Independent watchdog register map type. */ typedef struct iwdg_reg_map { - __io uint32 KR; /**< Key register. */ - __io uint32 PR; /**< Prescaler register. */ - __io uint32 RLR; /**< Reload register. */ - __io uint32 SR; /**< Status register */ + __IO uint32 KR; /**< Key register. */ + __IO uint32 PR; /**< Prescaler register. */ + __IO uint32 RLR; /**< Reload register. */ + __IO uint32 SR; /**< Status register */ } iwdg_reg_map; /** Independent watchdog base pointer */ diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/libmaple_types.h b/STM32F3/cores/maple/libmaple/include/libmaple/libmaple_types.h index 60dd2ff..c0a989a 100644 --- a/STM32F3/cores/maple/libmaple/include/libmaple/libmaple_types.h +++ b/STM32F3/cores/maple/libmaple/include/libmaple/libmaple_types.h @@ -50,7 +50,7 @@ typedef long long int64; typedef void (*voidFuncPtr)(void); typedef void (*voidArgumentFuncPtr)(void *); -#define __io volatile +#define __IO volatile #define __attr_flash __attribute__((section (".USER_FLASH"))) #define __packed __attribute__((__packed__)) #define __deprecated __attribute__((__deprecated__)) diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/nvic.h b/STM32F3/cores/maple/libmaple/include/libmaple/nvic.h index ffe385d..7699604 100644 --- a/STM32F3/cores/maple/libmaple/include/libmaple/nvic.h +++ b/STM32F3/cores/maple/libmaple/include/libmaple/nvic.h @@ -55,31 +55,31 @@ extern "C"{ /** NVIC register map type. */ typedef struct nvic_reg_map { - __io uint32 ISER[8]; /**< Interrupt Set Enable Registers */ + __IO uint32 ISER[8]; /**< Interrupt Set Enable Registers */ /** Reserved */ uint32 RESERVED0[24]; - __io uint32 ICER[8]; /**< Interrupt Clear Enable Registers */ + __IO uint32 ICER[8]; /**< Interrupt Clear Enable Registers */ /** Reserved */ uint32 RESERVED1[24]; - __io uint32 ISPR[8]; /**< Interrupt Set Pending Registers */ + __IO uint32 ISPR[8]; /**< Interrupt Set Pending Registers */ /** Reserved */ uint32 RESERVED2[24]; - __io uint32 ICPR[8]; /**< Interrupt Clear Pending Registers */ + __IO uint32 ICPR[8]; /**< Interrupt Clear Pending Registers */ /** Reserved */ uint32 RESERVED3[24]; - __io uint32 IABR[8]; /**< Interrupt Active bit Registers */ + __IO uint32 IABR[8]; /**< Interrupt Active bit Registers */ /** Reserved */ uint32 RESERVED4[56]; - __io uint8 IP[240]; /**< Interrupt Priority Registers */ + __IO uint8 IP[240]; /**< Interrupt Priority Registers */ /** Reserved */ uint32 RESERVED5[644]; - __io uint32 STIR; /**< Software Trigger Interrupt Registers */ + __IO uint32 STIR; /**< Software Trigger Interrupt Registers */ } nvic_reg_map; /** NVIC register map base pointer. */ diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/pwr.h b/STM32F3/cores/maple/libmaple/include/libmaple/pwr.h index e4b5b0d..6087c9b 100644 --- a/STM32F3/cores/maple/libmaple/include/libmaple/pwr.h +++ b/STM32F3/cores/maple/libmaple/include/libmaple/pwr.h @@ -41,8 +41,8 @@ extern "C" { /** Power interface register map. */ typedef struct pwr_reg_map { - __io uint32 CR; /**< Control register */ - __io uint32 CSR; /**< Control and status register */ + __IO uint32 CR; /**< Control register */ + __IO uint32 CSR; /**< Control and status register */ } pwr_reg_map; /** Power peripheral register map base pointer. */ diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/ring_buffer.h b/STM32F3/cores/maple/libmaple/include/libmaple/ring_buffer.h index e02e6e7..633c29a 100644 --- a/STM32F3/cores/maple/libmaple/include/libmaple/ring_buffer.h +++ b/STM32F3/cores/maple/libmaple/include/libmaple/ring_buffer.h @@ -81,7 +81,7 @@ static inline void rb_init(ring_buffer *rb, uint16 size, uint8 *buf) { * @param rb Buffer whose elements to count. */ static inline uint16 rb_full_count(ring_buffer *rb) { - __io ring_buffer *arb = rb; + __IO ring_buffer *arb = rb; int32 size = arb->tail - arb->head; if (arb->tail < arb->head) { size += arb->size + 1; diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/scb.h b/STM32F3/cores/maple/libmaple/include/libmaple/scb.h index c42a0f2..0b01480 100644 --- a/STM32F3/cores/maple/libmaple/include/libmaple/scb.h +++ b/STM32F3/cores/maple/libmaple/include/libmaple/scb.h @@ -49,37 +49,37 @@ extern "C" { /** System control block register map type */ typedef struct scb_reg_map { - __io uint32 CPUID; /**< CPU ID Base Register */ - __io uint32 ICSR; /**< Interrupt Control State Register */ - __io uint32 VTOR; /**< Vector Table Offset Register */ - __io uint32 AIRCR; /**< Application Interrupt / Reset Control Register */ - __io uint32 SCR; /**< System Control Register */ - __io uint32 CCR; /**< Configuration and Control Register */ - __io uint8 SHP[12]; /**< System Handler Priority Registers + __IO uint32 CPUID; /**< CPU ID Base Register */ + __IO uint32 ICSR; /**< Interrupt Control State Register */ + __IO uint32 VTOR; /**< Vector Table Offset Register */ + __IO uint32 AIRCR; /**< Application Interrupt / Reset Control Register */ + __IO uint32 SCR; /**< System Control Register */ + __IO uint32 CCR; /**< Configuration and Control Register */ + __IO uint8 SHP[12]; /**< System Handler Priority Registers (4-7, 8-11, 12-15) */ - __io uint32 SHCSR; /**< System Handler Control and State Register */ - __io uint32 CFSR; /**< Configurable Fault Status Register */ - __io uint32 HFSR; /**< Hard Fault Status Register */ + __IO uint32 SHCSR; /**< System Handler Control and State Register */ + __IO uint32 CFSR; /**< Configurable Fault Status Register */ + __IO uint32 HFSR; /**< Hard Fault Status Register */ /* DFSR is not documented by ST in PM0056 (as of Revision 4), but * there's a 4 byte hole in the SCB register map docs right where * it belongs. Since it's specified as "always implemented" in * the ARM v7-M ARM, I'm assuming its absence is a bug in the ST * doc, but I haven't proven it. [mbolivar] */ - __io uint32 DFSR; /**< Debug Fault Status Register */ - __io uint32 MMFAR; /**< Mem Manage Address Register */ - __io uint32 BFAR; /**< Bus Fault Address Register */ + __IO uint32 DFSR; /**< Debug Fault Status Register */ + __IO uint32 MMFAR; /**< Mem Manage Address Register */ + __IO uint32 BFAR; /**< Bus Fault Address Register */ #if 0 /* The following registers are implementation-defined according to * ARM v7-M, and I can't find evidence of their existence in ST's * docs. I'm removing them. Feel free to yell at me if they do * exist. [mbolivar] */ - __io uint32 AFSR; /**< Auxiliary Fault Status Register */ - __io uint32 PFR[2]; /**< Processor Feature Register */ - __io uint32 DFR; /**< Debug Feature Register */ - __io uint32 AFR; /**< Auxiliary Feature Register */ - __io uint32 MMFR[4]; /**< Memory Model Feature Register */ - __io uint32 ISAR[5]; /**< ISA Feature Register */ + __IO uint32 AFSR; /**< Auxiliary Fault Status Register */ + __IO uint32 PFR[2]; /**< Processor Feature Register */ + __IO uint32 DFR; /**< Debug Feature Register */ + __IO uint32 AFR; /**< Auxiliary Feature Register */ + __IO uint32 MMFR[4]; /**< Memory Model Feature Register */ + __IO uint32 ISAR[5]; /**< ISA Feature Register */ #endif } scb_reg_map; diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/spi.h b/STM32F3/cores/maple/libmaple/include/libmaple/spi.h index e688e4f..5c09170 100644 --- a/STM32F3/cores/maple/libmaple/include/libmaple/spi.h +++ b/STM32F3/cores/maple/libmaple/include/libmaple/spi.h @@ -54,15 +54,15 @@ extern "C" { /** SPI register map type. */ typedef struct spi_reg_map { - __io uint32 CR1; /**< Control register 1 */ - __io uint32 CR2; /**< Control register 2 */ - __io uint32 SR; /**< Status register */ - __io uint32 DR; /**< Data register */ - __io uint32 CRCPR; /**< CRC polynomial register */ - __io uint32 RXCRCR; /**< RX CRC register */ - __io uint32 TXCRCR; /**< TX CRC register */ - __io uint32 I2SCFGR; /**< I2S configuration register */ - __io uint32 I2SPR; /**< I2S prescaler register */ + __IO uint32 CR1; /**< Control register 1 */ + __IO uint32 CR2; /**< Control register 2 */ + __IO uint32 SR; /**< Status register */ + __IO uint32 DR; /**< Data register */ + __IO uint32 CRCPR; /**< CRC polynomial register */ + __IO uint32 RXCRCR; /**< RX CRC register */ + __IO uint32 TXCRCR; /**< TX CRC register */ + __IO uint32 I2SCFGR; /**< I2S configuration register */ + __IO uint32 I2SPR; /**< I2S prescaler register */ } spi_reg_map; /* diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/systick.h b/STM32F3/cores/maple/libmaple/include/libmaple/systick.h index 551f800..815a1c3 100644 --- a/STM32F3/cores/maple/libmaple/include/libmaple/systick.h +++ b/STM32F3/cores/maple/libmaple/include/libmaple/systick.h @@ -41,10 +41,10 @@ extern "C"{ /** SysTick register map type */ typedef struct systick_reg_map { - __io uint32 CSR; /**< Control and status register */ - __io uint32 RVR; /**< Reload value register */ - __io uint32 CNT; /**< Current value register ("count") */ - __io uint32 CVR; /**< Calibration value register */ + __IO uint32 CSR; /**< Control and status register */ + __IO uint32 RVR; /**< Reload value register */ + __IO uint32 CNT; /**< Current value register ("count") */ + __IO uint32 CVR; /**< Calibration value register */ } systick_reg_map; /** SysTick register map base pointer */ diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/timer.h b/STM32F3/cores/maple/libmaple/include/libmaple/timer.h index 9167f7d..51a5623 100644 --- a/STM32F3/cores/maple/libmaple/include/libmaple/timer.h +++ b/STM32F3/cores/maple/libmaple/include/libmaple/timer.h @@ -49,26 +49,26 @@ extern "C"{ /** Advanced control timer register map type */ typedef struct timer_adv_reg_map { - __io uint32 CR1; /**< Control register 1 */ - __io uint32 CR2; /**< Control register 2 */ - __io uint32 SMCR; /**< Slave mode control register */ - __io uint32 DIER; /**< DMA/interrupt enable register */ - __io uint32 SR; /**< Status register */ - __io uint32 EGR; /**< Event generation register */ - __io uint32 CCMR1; /**< Capture/compare mode register 1 */ - __io uint32 CCMR2; /**< Capture/compare mode register 2 */ - __io uint32 CCER; /**< Capture/compare enable register */ - __io uint32 CNT; /**< Counter */ - __io uint32 PSC; /**< Prescaler */ - __io uint32 ARR; /**< Auto-reload register */ - __io uint32 RCR; /**< Repetition counter register */ - __io uint32 CCR1; /**< Capture/compare register 1 */ - __io uint32 CCR2; /**< Capture/compare register 2 */ - __io uint32 CCR3; /**< Capture/compare register 3 */ - __io uint32 CCR4; /**< Capture/compare register 4 */ - __io uint32 BDTR; /**< Break and dead-time register */ - __io uint32 DCR; /**< DMA control register */ - __io uint32 DMAR; /**< DMA address for full transfer */ + __IO uint32 CR1; /**< Control register 1 */ + __IO uint32 CR2; /**< Control register 2 */ + __IO uint32 SMCR; /**< Slave mode control register */ + __IO uint32 DIER; /**< DMA/interrupt enable register */ + __IO uint32 SR; /**< Status register */ + __IO uint32 EGR; /**< Event generation register */ + __IO uint32 CCMR1; /**< Capture/compare mode register 1 */ + __IO uint32 CCMR2; /**< Capture/compare mode register 2 */ + __IO uint32 CCER; /**< Capture/compare enable register */ + __IO uint32 CNT; /**< Counter */ + __IO uint32 PSC; /**< Prescaler */ + __IO uint32 ARR; /**< Auto-reload register */ + __IO uint32 RCR; /**< Repetition counter register */ + __IO uint32 CCR1; /**< Capture/compare register 1 */ + __IO uint32 CCR2; /**< Capture/compare register 2 */ + __IO uint32 CCR3; /**< Capture/compare register 3 */ + __IO uint32 CCR4; /**< Capture/compare register 4 */ + __IO uint32 BDTR; /**< Break and dead-time register */ + __IO uint32 DCR; /**< DMA control register */ + __IO uint32 DMAR; /**< DMA address for full transfer */ } timer_adv_reg_map; /* General purpose timer register map type: intentionally omitted. @@ -78,18 +78,18 @@ typedef struct timer_adv_reg_map { /** Basic timer register map type */ typedef struct timer_bas_reg_map { - __io uint32 CR1; /**< Control register 1 */ - __io uint32 CR2; /**< Control register 2 */ + __IO uint32 CR1; /**< Control register 1 */ + __IO uint32 CR2; /**< Control register 2 */ const uint32 RESERVED1; /**< Reserved */ - __io uint32 DIER; /**< DMA/interrupt enable register */ - __io uint32 SR; /**< Status register */ - __io uint32 EGR; /**< Event generation register */ + __IO uint32 DIER; /**< DMA/interrupt enable register */ + __IO uint32 SR; /**< Status register */ + __IO uint32 EGR; /**< Event generation register */ const uint32 RESERVED2; /**< Reserved */ const uint32 RESERVED3; /**< Reserved */ const uint32 RESERVED4; /**< Reserved */ - __io uint32 CNT; /**< Counter */ - __io uint32 PSC; /**< Prescaler */ - __io uint32 ARR; /**< Auto-reload register */ + __IO uint32 CNT; /**< Counter */ + __IO uint32 PSC; /**< Prescaler */ + __IO uint32 ARR; /**< Auto-reload register */ } timer_bas_reg_map; /* @@ -725,7 +725,7 @@ static inline void timer_set_reload(timer_dev *dev, uint16 arr) { * @param channel Channel whose compare value to get. */ static inline uint16 timer_get_compare(timer_dev *dev, uint8 channel) { - __io uint32 *ccr = &(dev->regs).gen->CCR1 + (channel - 1); + __IO uint32 *ccr = &(dev->regs).gen->CCR1 + (channel - 1); return *ccr; } @@ -738,7 +738,7 @@ static inline uint16 timer_get_compare(timer_dev *dev, uint8 channel) { static inline void timer_set_compare(timer_dev *dev, uint8 channel, uint16 value) { - __io uint32 *ccr = &(dev->regs).gen->CCR1 + (channel - 1); + __IO uint32 *ccr = &(dev->regs).gen->CCR1 + (channel - 1); *ccr = value; } @@ -1035,7 +1035,7 @@ static inline void timer_oc_set_mode(timer_dev *dev, timer_oc_mode mode, uint8 flags) { /* channel == 1,2 -> CCMR1; channel == 3,4 -> CCMR2 */ - __io uint32 *ccmr = &(dev->regs).gen->CCMR1 + (((channel - 1) >> 1) & 1); + __IO uint32 *ccmr = &(dev->regs).gen->CCMR1 + (((channel - 1) >> 1) & 1); /* channel == 1,3 -> shift = 0, channel == 2,4 -> shift = 8 */ uint8 shift = 8 * (1 - (channel & 1)); diff --git a/STM32F3/cores/maple/libmaple/rcc.c b/STM32F3/cores/maple/libmaple/rcc.c index 8e7d1ea..aba87c0 100644 --- a/STM32F3/cores/maple/libmaple/rcc.c +++ b/STM32F3/cores/maple/libmaple/rcc.c @@ -94,8 +94,8 @@ void rcc_switch_sysclk(rcc_sysclk_src sysclk_src) { * won't work for you. */ /* Returns the RCC register which controls the clock source. */ -static inline __io uint32* rcc_clk_reg(rcc_clk clock) { - return (__io uint32*)((__io uint8*)RCC_BASE + (clock >> 8)); +static inline __IO uint32* rcc_clk_reg(rcc_clk clock) { + return (__IO uint32*)((__IO uint8*)RCC_BASE + (clock >> 8)); } /* Returns a mask in rcc_clk_reg(clock) to be used for turning the diff --git a/STM32F3/cores/maple/libmaple/rcc_private.h b/STM32F3/cores/maple/libmaple/rcc_private.h index 66eaf00..b20a2c5 100644 --- a/STM32F3/cores/maple/libmaple/rcc_private.h +++ b/STM32F3/cores/maple/libmaple/rcc_private.h @@ -40,16 +40,16 @@ struct rcc_dev_info { extern const struct rcc_dev_info rcc_dev_table[]; -static inline void rcc_do_clk_enable(__io uint32** enable_regs, +static inline void rcc_do_clk_enable(__IO uint32** enable_regs, rcc_clk_id id) { - __io uint32 *enable_reg = enable_regs[rcc_dev_clk(id)]; + __IO uint32 *enable_reg = enable_regs[rcc_dev_clk(id)]; uint8 line_num = rcc_dev_table[id].line_num; bb_peri_set_bit(enable_reg, line_num, 1); } -static inline void rcc_do_reset_dev(__io uint32** reset_regs, +static inline void rcc_do_reset_dev(__IO uint32** reset_regs, rcc_clk_id id) { - __io uint32 *reset_reg = reset_regs[rcc_dev_clk(id)]; + __IO uint32 *reset_reg = reset_regs[rcc_dev_clk(id)]; uint8 line_num = rcc_dev_table[id].line_num; bb_peri_set_bit(reset_reg, line_num, 1); bb_peri_set_bit(reset_reg, line_num, 0); diff --git a/STM32F3/cores/maple/libmaple/stm32f3/f3_adc.c b/STM32F3/cores/maple/libmaple/stm32f3/f3_adc.c index 982d6ea..23a3b96 100644 --- a/STM32F3/cores/maple/libmaple/stm32f3/f3_adc.c +++ b/STM32F3/cores/maple/libmaple/stm32f3/f3_adc.c @@ -164,7 +164,7 @@ void adc_set_conv_seq(const adc_dev *dev, const uint8 *channels, uint8 len) { uint8 i; uint32 val = 0; uint8 lshift; - __io uint32 *sqr = &dev->regs->SQR1; + __IO uint32 *sqr = &dev->regs->SQR1; for (i=0; i BKP_NR_DATA_REGS) return NULL; else diff --git a/STM32F3/cores/maple/libmaple/stm32f3/f3_dma.c b/STM32F3/cores/maple/libmaple/stm32f3/f3_dma.c index 317c283..10ba37f 100644 --- a/STM32F3/cores/maple/libmaple/stm32f3/f3_dma.c +++ b/STM32F3/cores/maple/libmaple/stm32f3/f3_dma.c @@ -86,7 +86,7 @@ static int cfg_dev_ok(dma_dev *dev, dma_tube_config *cfg) { } /* Is addr acceptable for use as DMA src/dst? */ -static int cfg_mem_ok(__io void *addr) { +static int cfg_mem_ok(__IO void *addr) { enum dma_atype atype = _dma_addr_type(addr); return atype == DMA_ATYPE_MEM || atype == DMA_ATYPE_PER; } @@ -293,7 +293,7 @@ dma_irq_cause dma_get_irq_cause(dma_dev *dev, dma_channel channel) { return DMA_TRANSFER_ERROR; } -void dma_set_mem_addr(dma_dev *dev, dma_channel channel, __io void *addr) { +void dma_set_mem_addr(dma_dev *dev, dma_channel channel, __IO void *addr) { dma_channel_reg_map *chan_regs; ASSERT_FAULT(!dma_is_channel_enabled(dev, channel)); @@ -302,7 +302,7 @@ void dma_set_mem_addr(dma_dev *dev, dma_channel channel, __io void *addr) { chan_regs->CMAR = (uint32)addr; } -void dma_set_per_addr(dma_dev *dev, dma_channel channel, __io void *addr) { +void dma_set_per_addr(dma_dev *dev, dma_channel channel, __IO void *addr) { dma_channel_reg_map *chan_regs; ASSERT_FAULT(!dma_is_channel_enabled(dev, channel)); diff --git a/STM32F3/cores/maple/libmaple/stm32f3/f3_gpio.c b/STM32F3/cores/maple/libmaple/stm32f3/f3_gpio.c index 45992a4..7ca982a 100644 --- a/STM32F3/cores/maple/libmaple/stm32f3/f3_gpio.c +++ b/STM32F3/cores/maple/libmaple/stm32f3/f3_gpio.c @@ -152,7 +152,7 @@ void gpio_set_modef(gpio_dev *dev, * @see gpio_set_modef() */ void gpio_set_af(gpio_dev *dev, uint8 bit, gpio_af af) { - __io uint32 *afr; + __IO uint32 *afr; unsigned shift; uint32 tmp; if (bit >= 8) { diff --git a/STM32F3/cores/maple/libmaple/stm32f3/f3_rcc.c b/STM32F3/cores/maple/libmaple/stm32f3/f3_rcc.c index 4099e80..5ebe2ad 100644 --- a/STM32F3/cores/maple/libmaple/stm32f3/f3_rcc.c +++ b/STM32F3/cores/maple/libmaple/stm32f3/f3_rcc.c @@ -121,7 +121,7 @@ void rcc_configure_pll(rcc_pll_cfg *pll_cfg) { } void rcc_clk_enable(rcc_clk_id id) { - static __io uint32* enable_regs[] = { + static __IO uint32* enable_regs[] = { [APB1] = &RCC_BASE->APB1ENR, [APB2] = &RCC_BASE->APB2ENR, [AHB] = &RCC_BASE->AHBENR, @@ -130,7 +130,7 @@ void rcc_clk_enable(rcc_clk_id id) { } void rcc_reset_dev(rcc_clk_id id) { - static __io uint32* reset_regs[] = { + static __IO uint32* reset_regs[] = { [APB1] = &RCC_BASE->APB1RSTR, [APB2] = &RCC_BASE->APB2RSTR, [AHB] = &RCC_BASE->AHBRSTR, diff --git a/STM32F3/cores/maple/libmaple/stm32f3/f3_spi.c b/STM32F3/cores/maple/libmaple/stm32f3/f3_spi.c index 3fafa52..d5c38a0 100644 --- a/STM32F3/cores/maple/libmaple/stm32f3/f3_spi.c +++ b/STM32F3/cores/maple/libmaple/stm32f3/f3_spi.c @@ -119,10 +119,10 @@ void spi_reconfigure(spi_dev *dev, uint32 cr1_config) { uint16 spi_rx_reg(spi_dev *dev) { uint8 byte_frame = (dev->regs->CR2 & SPI_CR2_DS) <= SPI_DATA_SIZE_8_BIT; if (byte_frame) { - __io uint8 *dr8 = (__io uint8 *)&dev->regs->DR; /* we need to access as byte */ + __IO uint8 *dr8 = (__IO uint8 *)&dev->regs->DR; /* we need to access as byte */ return (uint16)*dr8; } else { - __io uint16 *dr16 = (__io uint16 *)&dev->regs->DR; /* we need to access as half-word */ + __IO uint16 *dr16 = (__IO uint16 *)&dev->regs->DR; /* we need to access as half-word */ return (uint16)*dr16; } } @@ -132,10 +132,10 @@ uint32 spi_tx(spi_dev *dev, const void *buf, uint32 len) { uint8 byte_frame = (dev->regs->CR2 & SPI_CR2_DS) <= SPI_DATA_SIZE_8_BIT; while (spi_is_tx_empty(dev) && (txed < len)) { if (byte_frame) { - __io uint8 *dr8 = (__io uint8 *)&dev->regs->DR; /* we need to access as byte */ + __IO uint8 *dr8 = (__IO uint8 *)&dev->regs->DR; /* we need to access as byte */ *dr8 = ((const uint8 *)buf)[txed++]; } else { - __io uint16 *dr16 = (__io uint16 *)&dev->regs->DR; /* we need to access as half-word */ + __IO uint16 *dr16 = (__IO uint16 *)&dev->regs->DR; /* we need to access as half-word */ *dr16 = ((const uint16 *)buf)[txed++]; } } diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/adc.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/adc.h index 76422f6..8f4edde 100644 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/adc.h +++ b/STM32F3/cores/maple/libmaple/stm32f3/include/series/adc.h @@ -45,51 +45,51 @@ * ADC individual register map type. */ typedef struct adc_reg_map { - __io uint32 ISR; /**< */ - __io uint32 IER; /**< */ - __io uint32 CR; /**< */ - __io uint32 CFGR; /**< */ + __IO uint32 ISR; /**< */ + __IO uint32 IER; /**< */ + __IO uint32 CR; /**< */ + __IO uint32 CFGR; /**< */ uint32 reserved1; - __io uint32 SMPR1; /**< */ - __io uint32 SMPR2; /**< */ + __IO uint32 SMPR1; /**< */ + __IO uint32 SMPR2; /**< */ uint32 reserved2; - __io uint32 TR1; /**< */ - __io uint32 TR2; /**< */ - __io uint32 TR3; /**< */ + __IO uint32 TR1; /**< */ + __IO uint32 TR2; /**< */ + __IO uint32 TR3; /**< */ uint32 reserved3; - __io uint32 SQR1; /**< */ - __io uint32 SQR2; /**< */ - __io uint32 SQR3; /**< */ - __io uint32 SQR4; /**< */ - __io uint32 DR; /**< */ + __IO uint32 SQR1; /**< */ + __IO uint32 SQR2; /**< */ + __IO uint32 SQR3; /**< */ + __IO uint32 SQR4; /**< */ + __IO uint32 DR; /**< */ uint32 reserved4 [2]; - __io uint32 JSQR; /**< */ + __IO uint32 JSQR; /**< */ uint32 reserved5 [4]; - __io uint32 OFR1; /**< */ - __io uint32 OFR2; /**< */ - __io uint32 OFR3; /**< */ - __io uint32 OFR4; /**< */ + __IO uint32 OFR1; /**< */ + __IO uint32 OFR2; /**< */ + __IO uint32 OFR3; /**< */ + __IO uint32 OFR4; /**< */ uint32 reserved6 [4]; - __io uint32 JDR1; /**< */ - __io uint32 JDR2; /**< */ - __io uint32 JDR3; /**< */ - __io uint32 JDR4; /**< */ + __IO uint32 JDR1; /**< */ + __IO uint32 JDR2; /**< */ + __IO uint32 JDR3; /**< */ + __IO uint32 JDR4; /**< */ uint32 reserved7 [4]; - __io uint32 AWD2CR; /**< */ - __io uint32 AWD3CR; /**< */ + __IO uint32 AWD2CR; /**< */ + __IO uint32 AWD3CR; /**< */ uint32 reserved8 [2]; - __io uint32 DIFSEL; /**< */ - __io uint32 CALFACT; /**< */ + __IO uint32 DIFSEL; /**< */ + __IO uint32 CALFACT; /**< */ } adc_reg_map; /* * ADC master and slave common register map type. */ typedef struct adc_common_reg_map { - __io uint32 CSR; /**< */ + __IO uint32 CSR; /**< */ uint32 reserved; - __io uint32 CCR; /**< */ - __io uint32 CDR; /**< */ + __IO uint32 CCR; /**< */ + __IO uint32 CDR; /**< */ } adc_common_reg_map; /** ADC device type. */ diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/bkp.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/bkp.h index 3a49a41..21ab1c1 100644 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/bkp.h +++ b/STM32F3/cores/maple/libmaple/stm32f3/include/series/bkp.h @@ -38,22 +38,22 @@ /** Backup peripheral register map type. */ typedef struct bkp_reg_map { - __io uint32 DR0; ///< Data register 0 - __io uint32 DR1; ///< Data register 1 - __io uint32 DR2; ///< Data register 2 - __io uint32 DR3; ///< Data register 3 - __io uint32 DR4; ///< Data register 4 - __io uint32 DR5; ///< Data register 5 - __io uint32 DR6; ///< Data register 6 - __io uint32 DR7; ///< Data register 7 - __io uint32 DR8; ///< Data register 8 - __io uint32 DR9; ///< Data register 9 - __io uint32 DR10; ///< Data register 10 - __io uint32 DR11; ///< Data register 11 - __io uint32 DR12; ///< Data register 12 - __io uint32 DR13; ///< Data register 13 - __io uint32 DR14; ///< Data register 14 - __io uint32 DR15; ///< Data register 15 + __IO uint32 DR0; ///< Data register 0 + __IO uint32 DR1; ///< Data register 1 + __IO uint32 DR2; ///< Data register 2 + __IO uint32 DR3; ///< Data register 3 + __IO uint32 DR4; ///< Data register 4 + __IO uint32 DR5; ///< Data register 5 + __IO uint32 DR6; ///< Data register 6 + __IO uint32 DR7; ///< Data register 7 + __IO uint32 DR8; ///< Data register 8 + __IO uint32 DR9; ///< Data register 9 + __IO uint32 DR10; ///< Data register 10 + __IO uint32 DR11; ///< Data register 11 + __IO uint32 DR12; ///< Data register 12 + __IO uint32 DR13; ///< Data register 13 + __IO uint32 DR14; ///< Data register 14 + __IO uint32 DR15; ///< Data register 15 } bkp_reg_map; /** Backup peripheral register map base pointer. */ diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/comp.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/comp.h index ca40a96..161f439 100644 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/comp.h +++ b/STM32F3/cores/maple/libmaple/stm32f3/include/series/comp.h @@ -47,7 +47,7 @@ extern "C"{ * COMP individual register map type. */ typedef struct comp_reg_map { - __io uint32 CSR; /**< */ + __IO uint32 CSR; /**< */ } comp_reg_map; /** COMP device type. */ diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/crc.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/crc.h index 72e7995..fa10aa4 100644 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/crc.h +++ b/STM32F3/cores/maple/libmaple/stm32f3/include/series/crc.h @@ -43,12 +43,12 @@ extern "C"{ /** CRC register map type */ typedef struct crc_reg_map { - __io uint32 DR; /**< Data register */ - __io uint32 IDR; /**< Independent data register */ - __io uint32 CR; /**< Control register */ + __IO uint32 DR; /**< Data register */ + __IO uint32 IDR; /**< Independent data register */ + __IO uint32 CR; /**< Control register */ uint32 reserved; - __io uint32 INIT; /**< Initial data register */ - __io uint32 POL; /**< Polynomial register */ + __IO uint32 INIT; /**< Initial data register */ + __IO uint32 POL; /**< Polynomial register */ } crc_reg_map; /* diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/dac.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/dac.h index 7c5e8f5..890e34c 100644 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/dac.h +++ b/STM32F3/cores/maple/libmaple/stm32f3/include/series/dac.h @@ -40,28 +40,28 @@ extern "C"{ /** STM32F3 DAC register map type. */ typedef struct dac_reg_map { - __io uint32 CR; /**< Control register */ - __io uint32 SWTRIGR; /**< Software trigger register */ - __io uint32 DHR12R1; /**< Channel 1 12-bit right-aligned data + __IO uint32 CR; /**< Control register */ + __IO uint32 SWTRIGR; /**< Software trigger register */ + __IO uint32 DHR12R1; /**< Channel 1 12-bit right-aligned data holding register */ - __io uint32 DHR12L1; /**< Channel 1 12-bit left-aligned data + __IO uint32 DHR12L1; /**< Channel 1 12-bit left-aligned data holding register */ - __io uint32 DHR8R1; /**< Channel 1 8-bit left-aligned data + __IO uint32 DHR8R1; /**< Channel 1 8-bit left-aligned data holding register */ - __io uint32 DHR12R2; /**< Channel 2 12-bit right-aligned data + __IO uint32 DHR12R2; /**< Channel 2 12-bit right-aligned data holding register */ - __io uint32 DHR12L2; /**< Channel 2 12-bit left-aligned data + __IO uint32 DHR12L2; /**< Channel 2 12-bit left-aligned data holding register */ - __io uint32 DHR8R2; /**< Channel 2 8-bit left-aligned data + __IO uint32 DHR8R2; /**< Channel 2 8-bit left-aligned data holding register */ - __io uint32 DHR12RD; /**< Dual DAC 12-bit right-aligned data + __IO uint32 DHR12RD; /**< Dual DAC 12-bit right-aligned data holding register */ - __io uint32 DHR12LD; /**< Dual DAC 12-bit left-aligned data + __IO uint32 DHR12LD; /**< Dual DAC 12-bit left-aligned data holding register */ - __io uint32 DHR8RD; /**< Dual DAC 8-bit right-aligned data holding + __IO uint32 DHR8RD; /**< Dual DAC 8-bit right-aligned data holding register */ - __io uint32 DOR1; /**< Channel 1 data output register */ - __io uint32 DOR2; /**< Channel 2 data output register */ + __IO uint32 DOR1; /**< Channel 1 data output register */ + __IO uint32 DOR2; /**< Channel 2 data output register */ } dac_reg_map; //#define DAC1_BASE ((struct dac_reg_map*)0x40007400) diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/dma.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/dma.h index 9bb3b1b..1c73748 100644 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/dma.h +++ b/STM32F3/cores/maple/libmaple/stm32f3/include/series/dma.h @@ -55,42 +55,42 @@ extern "C"{ * only supports channels 1--5. */ typedef struct dma_reg_map { - __io uint32 ISR; /**< Interrupt status register */ - __io uint32 IFCR; /**< Interrupt flag clear register */ - __io uint32 CCR1; /**< Channel 1 configuration register */ - __io uint32 CNDTR1; /**< Channel 1 number of data register */ - __io uint32 CPAR1; /**< Channel 1 peripheral address register */ - __io uint32 CMAR1; /**< Channel 1 memory address register */ + __IO uint32 ISR; /**< Interrupt status register */ + __IO uint32 IFCR; /**< Interrupt flag clear register */ + __IO uint32 CCR1; /**< Channel 1 configuration register */ + __IO uint32 CNDTR1; /**< Channel 1 number of data register */ + __IO uint32 CPAR1; /**< Channel 1 peripheral address register */ + __IO uint32 CMAR1; /**< Channel 1 memory address register */ const uint32 RESERVED1; /**< Reserved. */ - __io uint32 CCR2; /**< Channel 2 configuration register */ - __io uint32 CNDTR2; /**< Channel 2 number of data register */ - __io uint32 CPAR2; /**< Channel 2 peripheral address register */ - __io uint32 CMAR2; /**< Channel 2 memory address register */ + __IO uint32 CCR2; /**< Channel 2 configuration register */ + __IO uint32 CNDTR2; /**< Channel 2 number of data register */ + __IO uint32 CPAR2; /**< Channel 2 peripheral address register */ + __IO uint32 CMAR2; /**< Channel 2 memory address register */ const uint32 RESERVED2; /**< Reserved. */ - __io uint32 CCR3; /**< Channel 3 configuration register */ - __io uint32 CNDTR3; /**< Channel 3 number of data register */ - __io uint32 CPAR3; /**< Channel 3 peripheral address register */ - __io uint32 CMAR3; /**< Channel 3 memory address register */ + __IO uint32 CCR3; /**< Channel 3 configuration register */ + __IO uint32 CNDTR3; /**< Channel 3 number of data register */ + __IO uint32 CPAR3; /**< Channel 3 peripheral address register */ + __IO uint32 CMAR3; /**< Channel 3 memory address register */ const uint32 RESERVED3; /**< Reserved. */ - __io uint32 CCR4; /**< Channel 4 configuration register */ - __io uint32 CNDTR4; /**< Channel 4 number of data register */ - __io uint32 CPAR4; /**< Channel 4 peripheral address register */ - __io uint32 CMAR4; /**< Channel 4 memory address register */ + __IO uint32 CCR4; /**< Channel 4 configuration register */ + __IO uint32 CNDTR4; /**< Channel 4 number of data register */ + __IO uint32 CPAR4; /**< Channel 4 peripheral address register */ + __IO uint32 CMAR4; /**< Channel 4 memory address register */ const uint32 RESERVED4; /**< Reserved. */ - __io uint32 CCR5; /**< Channel 5 configuration register */ - __io uint32 CNDTR5; /**< Channel 5 number of data register */ - __io uint32 CPAR5; /**< Channel 5 peripheral address register */ - __io uint32 CMAR5; /**< Channel 5 memory address register */ + __IO uint32 CCR5; /**< Channel 5 configuration register */ + __IO uint32 CNDTR5; /**< Channel 5 number of data register */ + __IO uint32 CPAR5; /**< Channel 5 peripheral address register */ + __IO uint32 CMAR5; /**< Channel 5 memory address register */ const uint32 RESERVED5; /**< Reserved. */ - __io uint32 CCR6; /**< Channel 6 configuration register */ - __io uint32 CNDTR6; /**< Channel 6 number of data register */ - __io uint32 CPAR6; /**< Channel 6 peripheral address register */ - __io uint32 CMAR6; /**< Channel 6 memory address register */ + __IO uint32 CCR6; /**< Channel 6 configuration register */ + __IO uint32 CNDTR6; /**< Channel 6 number of data register */ + __IO uint32 CPAR6; /**< Channel 6 peripheral address register */ + __IO uint32 CMAR6; /**< Channel 6 memory address register */ const uint32 RESERVED6; /**< Reserved. */ - __io uint32 CCR7; /**< Channel 7 configuration register */ - __io uint32 CNDTR7; /**< Channel 7 number of data register */ - __io uint32 CPAR7; /**< Channel 7 peripheral address register */ - __io uint32 CMAR7; /**< Channel 7 memory address register */ + __IO uint32 CCR7; /**< Channel 7 configuration register */ + __IO uint32 CNDTR7; /**< Channel 7 number of data register */ + __IO uint32 CPAR7; /**< Channel 7 peripheral address register */ + __IO uint32 CMAR7; /**< Channel 7 memory address register */ const uint32 RESERVED7; /**< Reserved. */ } dma_reg_map; @@ -105,10 +105,10 @@ typedef struct dma_reg_map { * @see dma_tube_regs() */ typedef struct dma_tube_reg_map { - __io uint32 CCR; /**< Channel configuration register */ - __io uint32 CNDTR; /**< Channel number of data register */ - __io uint32 CPAR; /**< Channel peripheral address register */ - __io uint32 CMAR; /**< Channel memory address register */ + __IO uint32 CCR; /**< Channel configuration register */ + __IO uint32 CNDTR; /**< Channel number of data register */ + __IO uint32 CPAR; /**< Channel peripheral address register */ + __IO uint32 CMAR; /**< Channel memory address register */ } dma_tube_reg_map; /** DMA1 channel 1 register map base pointer */ @@ -528,7 +528,7 @@ typedef enum dma_request_src { #define DMA_CHANNEL_NREGS 5 /* accounts for reserved word */ static inline dma_tube_reg_map* dma_tube_regs(dma_dev *dev, dma_tube tube) { - __io uint32 *ccr1 = &dev->regs->CCR1; + __IO uint32 *ccr1 = &dev->regs->CCR1; return (dma_channel_reg_map*)(ccr1 + DMA_CHANNEL_NREGS * (tube - 1)); } diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/flash.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/flash.h index 85baf9b..8bc6114 100644 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/flash.h +++ b/STM32F3/cores/maple/libmaple/stm32f3/include/series/flash.h @@ -50,14 +50,14 @@ extern "C"{ /** @brief STM32F3 Flash register map type */ typedef struct flash_reg_map { - __io uint32 ACR; /**< Access control register */ - __io uint32 KEYR; /**< Key register */ - __io uint32 OPTKEYR; /**< OPTKEY register */ - __io uint32 SR; /**< Status register */ - __io uint32 CR; /**< Control register */ - __io uint32 AR; /**< Address register */ - __io uint32 OBR; /**< Option byte register */ - __io uint32 WRPR; /**< Write protection register */ + __IO uint32 ACR; /**< Access control register */ + __IO uint32 KEYR; /**< Key register */ + __IO uint32 OPTKEYR; /**< OPTKEY register */ + __IO uint32 SR; /**< Status register */ + __IO uint32 CR; /**< Control register */ + __IO uint32 AR; /**< Address register */ + __IO uint32 OBR; /**< Option byte register */ + __IO uint32 WRPR; /**< Write protection register */ } flash_reg_map; #define FLASH_BASE ((struct flash_reg_map*)0x40022000) diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/fpu.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/fpu.h index dc5d4ab..ee5d5c1 100644 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/fpu.h +++ b/STM32F3/cores/maple/libmaple/stm32f3/include/series/fpu.h @@ -46,10 +46,10 @@ extern "C"{ /** FPU register map type */ typedef struct fpu_reg_map { - __io uint32 CPACR; /**< coprocessor access control register */ - __io uint32 FPCCR; /**< floating-point context control register */ - __io uint32 FPCAR; /**< floating-point context address register */ - __io uint32 FPDSCR; /**< floating-point default status control register */ + __IO uint32 CPACR; /**< coprocessor access control register */ + __IO uint32 FPCCR; /**< floating-point context control register */ + __IO uint32 FPCAR; /**< floating-point context address register */ + __IO uint32 FPDSCR; /**< floating-point default status control register */ } fpu_reg_map; #define FPU_BASE ((struct fpu_reg_map*)(SCB_BASE + 0x88)) diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/gpio.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/gpio.h index 50e8c09..268c9c2 100644 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/gpio.h +++ b/STM32F3/cores/maple/libmaple/stm32f3/include/series/gpio.h @@ -46,17 +46,17 @@ extern "C"{ /** GPIO register map type */ typedef struct gpio_reg_map { - __io uint32 MODER; /**< Mode register */ - __io uint32 OTYPER; /**< Output type register */ - __io uint32 OSPEEDR; /**< Output speed register */ - __io uint32 PUPDR; /**< Pull-up/pull-down register */ - __io uint32 IDR; /**< Input data register */ - __io uint32 ODR; /**< Output data register */ - __io uint32 BSRR; /**< Bit set/reset register */ - __io uint32 LCKR; /**< Configuration lock register */ - __io uint32 AFRL; /**< Alternate function low register */ - __io uint32 AFRH; /**< Alternate function high register */ - __io uint32 BRR; /**< Port bit reset register */ + __IO uint32 MODER; /**< Mode register */ + __IO uint32 OTYPER; /**< Output type register */ + __IO uint32 OSPEEDR; /**< Output speed register */ + __IO uint32 PUPDR; /**< Pull-up/pull-down register */ + __IO uint32 IDR; /**< Input data register */ + __IO uint32 ODR; /**< Output data register */ + __IO uint32 BSRR; /**< Bit set/reset register */ + __IO uint32 LCKR; /**< Configuration lock register */ + __IO uint32 AFRL; /**< Alternate function low register */ + __IO uint32 AFRH; /**< Alternate function high register */ + __IO uint32 BRR; /**< Port bit reset register */ } gpio_reg_map; /** GPIO port A register map base pointer */ diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/i2c.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/i2c.h index c7be377..ef1b0ff 100644 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/i2c.h +++ b/STM32F3/cores/maple/libmaple/stm32f3/include/series/i2c.h @@ -47,17 +47,17 @@ extern "C"{ /** I2C register map type */ typedef struct i2c_reg_map { - __io uint32 CR1; /**< Control register 1 */ - __io uint32 CR2; /**< Control register 2 */ - __io uint32 OAR1; /**< Own address register 1 */ - __io uint32 OAR2; /**< Own address register 2 */ - __io uint32 TIMINGR; /**< Timing register */ - __io uint32 TIMEOUTR; /**< Timeout register */ - __io uint32 ISR; /**< Interrupt and status register */ - __io uint32 ICR; /**< Interrupt clear register */ - __io uint32 PECR; /**< PEC register */ - __io uint32 RXDR; /**< Receive data register */ - __io uint32 TXDR; /**< Transmit data register */ + __IO uint32 CR1; /**< Control register 1 */ + __IO uint32 CR2; /**< Control register 2 */ + __IO uint32 OAR1; /**< Own address register 1 */ + __IO uint32 OAR2; /**< Own address register 2 */ + __IO uint32 TIMINGR; /**< Timing register */ + __IO uint32 TIMEOUTR; /**< Timeout register */ + __IO uint32 ISR; /**< Interrupt and status register */ + __IO uint32 ICR; /**< Interrupt clear register */ + __IO uint32 PECR; /**< PEC register */ + __IO uint32 RXDR; /**< Receive data register */ + __IO uint32 TXDR; /**< Transmit data register */ } i2c_reg_map; extern i2c_dev* const I2C1; diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/opamp.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/opamp.h index 858f1d8..a5c627b 100644 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/opamp.h +++ b/STM32F3/cores/maple/libmaple/stm32f3/include/series/opamp.h @@ -47,7 +47,7 @@ extern "C"{ * OpAmp individual register map type. */ typedef struct opamp_reg_map { - __io uint32 CSR; /**< */ + __IO uint32 CSR; /**< */ } opamp_reg_map; /** OpAmp device type. */ diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/rcc.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/rcc.h index 80577e9..b8f4b34 100644 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/rcc.h +++ b/STM32F3/cores/maple/libmaple/stm32f3/include/series/rcc.h @@ -47,19 +47,19 @@ extern "C"{ /** STM32F3 RCC register map type */ typedef struct rcc_reg_map { - __io uint32 CR; /**< Clock control register */ - __io uint32 CFGR; /**< Clock configuration register */ - __io uint32 CIR; /**< Clock interrupt register */ - __io uint32 APB2RSTR; /**< APB2 peripheral reset register */ - __io uint32 APB1RSTR; /**< APB1 peripheral reset register */ - __io uint32 AHBENR; /**< AHB peripheral clock enable register */ - __io uint32 APB2ENR; /**< APB2 peripheral clock enable register */ - __io uint32 APB1ENR; /**< APB1 peripheral clock enable register */ - __io uint32 BDCR; /**< Backup domain control register */ - __io uint32 CSR; /**< Control/status register */ - __io uint32 AHBRSTR; /**< AHB peripheral reset register */ - __io uint32 CFGR2; /**< Control/status register 2 */ - __io uint32 CFGR3; /**< Control/status register 3 */ + __IO uint32 CR; /**< Clock control register */ + __IO uint32 CFGR; /**< Clock configuration register */ + __IO uint32 CIR; /**< Clock interrupt register */ + __IO uint32 APB2RSTR; /**< APB2 peripheral reset register */ + __IO uint32 APB1RSTR; /**< APB1 peripheral reset register */ + __IO uint32 AHBENR; /**< AHB peripheral clock enable register */ + __IO uint32 APB2ENR; /**< APB2 peripheral clock enable register */ + __IO uint32 APB1ENR; /**< APB1 peripheral clock enable register */ + __IO uint32 BDCR; /**< Backup domain control register */ + __IO uint32 CSR; /**< Control/status register */ + __IO uint32 AHBRSTR; /**< AHB peripheral reset register */ + __IO uint32 CFGR2; /**< Control/status register 2 */ + __IO uint32 CFGR3; /**< Control/status register 3 */ } rcc_reg_map; #define RCC_BASE ((struct rcc_reg_map*)0x40021000) diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/syscfg.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/syscfg.h index 3519e78..2565290 100644 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/syscfg.h +++ b/STM32F3/cores/maple/libmaple/stm32f3/include/series/syscfg.h @@ -47,10 +47,10 @@ extern "C" { * @brief SYSCFG register map type. */ typedef struct syscfg_reg_map { - __io uint32 CFGR1; /**< Configuration register 1*/ - __io uint32 RCR; /**< CCM SRAM protection register */ - __io uint32 EXTICR[4]; /**< External Interrupt configuration register */ - __io uint32 CFGR2; /**< Configuration register 2 */ + __IO uint32 CFGR1; /**< Configuration register 1*/ + __IO uint32 RCR; /**< CCM SRAM protection register */ + __IO uint32 EXTICR[4]; /**< External Interrupt configuration register */ + __IO uint32 CFGR2; /**< Configuration register 2 */ } syscfg_reg_map; /** SYSCFG register map base pointer */ diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/timer.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/timer.h index fe13e4c..01e2c88 100644 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/timer.h +++ b/STM32F3/cores/maple/libmaple/stm32f3/include/series/timer.h @@ -44,26 +44,26 @@ /** STM32F1 general purpose timer register map type */ typedef struct timer_gen_reg_map { - __io uint32 CR1; /**< Control register 1 */ - __io uint32 CR2; /**< Control register 2 */ - __io uint32 SMCR; /**< Slave mode control register */ - __io uint32 DIER; /**< DMA/Interrupt enable register */ - __io uint32 SR; /**< Status register */ - __io uint32 EGR; /**< Event generation register */ - __io uint32 CCMR1; /**< Capture/compare mode register 1 */ - __io uint32 CCMR2; /**< Capture/compare mode register 2 */ - __io uint32 CCER; /**< Capture/compare enable register */ - __io uint32 CNT; /**< Counter */ - __io uint32 PSC; /**< Prescaler */ - __io uint32 ARR; /**< Auto-reload register */ + __IO uint32 CR1; /**< Control register 1 */ + __IO uint32 CR2; /**< Control register 2 */ + __IO uint32 SMCR; /**< Slave mode control register */ + __IO uint32 DIER; /**< DMA/Interrupt enable register */ + __IO uint32 SR; /**< Status register */ + __IO uint32 EGR; /**< Event generation register */ + __IO uint32 CCMR1; /**< Capture/compare mode register 1 */ + __IO uint32 CCMR2; /**< Capture/compare mode register 2 */ + __IO uint32 CCER; /**< Capture/compare enable register */ + __IO uint32 CNT; /**< Counter */ + __IO uint32 PSC; /**< Prescaler */ + __IO uint32 ARR; /**< Auto-reload register */ const uint32 RESERVED1; /**< Reserved */ - __io uint32 CCR1; /**< Capture/compare register 1 */ - __io uint32 CCR2; /**< Capture/compare register 2 */ - __io uint32 CCR3; /**< Capture/compare register 3 */ - __io uint32 CCR4; /**< Capture/compare register 4 */ + __IO uint32 CCR1; /**< Capture/compare register 1 */ + __IO uint32 CCR2; /**< Capture/compare register 2 */ + __IO uint32 CCR3; /**< Capture/compare register 3 */ + __IO uint32 CCR4; /**< Capture/compare register 4 */ const uint32 RESERVED2; /**< Reserved */ - __io uint32 DCR; /**< DMA control register */ - __io uint32 DMAR; /**< DMA address for full transfer */ + __IO uint32 DCR; /**< DMA control register */ + __IO uint32 DMAR; /**< DMA address for full transfer */ } timer_gen_reg_map; struct timer_adv_reg_map; diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/usart.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/usart.h index d7edcb6..94a25d9 100644 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/usart.h +++ b/STM32F3/cores/maple/libmaple/stm32f3/include/series/usart.h @@ -45,18 +45,18 @@ extern "C"{ /** USART register map type */ typedef struct usart_reg_map { - __io uint32 CR1; /**< Control register 1 */ - __io uint32 CR2; /**< Control register 2 */ - __io uint32 CR3; /**< Control register 3 */ - __io uint32 BRR; /**< Baud rate register */ - __io uint32 GTPR; /**< Guard time and prescaler register */ - __io uint32 RTOR; /**< Receiver timeout register */ - __io uint32 RQR; /**< Request register */ - __io uint32 SR; /**< ISR Interrupt and status register */ - __io uint32 ICR; /**< Interrupt clear register */ - __io uint16 RDR; /**< Receive data register */ + __IO uint32 CR1; /**< Control register 1 */ + __IO uint32 CR2; /**< Control register 2 */ + __IO uint32 CR3; /**< Control register 3 */ + __IO uint32 BRR; /**< Baud rate register */ + __IO uint32 GTPR; /**< Guard time and prescaler register */ + __IO uint32 RTOR; /**< Receiver timeout register */ + __IO uint32 RQR; /**< Request register */ + __IO uint32 SR; /**< ISR Interrupt and status register */ + __IO uint32 ICR; /**< Interrupt clear register */ + __IO uint16 RDR; /**< Receive data register */ uint16 RESERVED1; - __io uint16 TDR; /**< Transmit data register */ + __IO uint16 TDR; /**< Transmit data register */ uint16 RESERVED2; } usart_reg_map; diff --git a/STM32F3/cores/maple/libmaple/usb/usb_reg_map.h b/STM32F3/cores/maple/libmaple/usb/usb_reg_map.h index 2e3f6bc..2cd5e35 100644 --- a/STM32F3/cores/maple/libmaple/usb/usb_reg_map.h +++ b/STM32F3/cores/maple/libmaple/usb/usb_reg_map.h @@ -42,13 +42,13 @@ /** USB register map type */ typedef struct usb_reg_map { - __io uint32 EP[USB_NR_EP_REGS]; /**< Endpoint registers */ + __IO uint32 EP[USB_NR_EP_REGS]; /**< Endpoint registers */ const uint32 RESERVED[8]; /**< Reserved */ - __io uint32 CNTR; /**< Control register */ - __io uint32 ISTR; /**< Interrupt status register */ - __io uint32 FNR; /**< Frame number register */ - __io uint32 DADDR; /**< Device address */ - __io uint32 BTABLE; /**< @brief Buffer table address + __IO uint32 CNTR; /**< Control register */ + __IO uint32 ISTR; /**< Interrupt status register */ + __IO uint32 FNR; /**< Frame number register */ + __IO uint32 DADDR; /**< Device address */ + __IO uint32 BTABLE; /**< @brief Buffer table address * * Address offset within the USB * packet memory area which points @@ -340,7 +340,7 @@ static inline void usb_clear_status_out(uint8 ep) { * * The USB PMA is SRAM shared between USB and CAN. The USB peripheral * accesses this memory directly via the packet buffer interface. */ -#define USB_PMA_BASE ((__io void*)0x40006000) +#define USB_PMA_BASE ((__IO void*)0x40006000) /* * PMA conveniences @@ -367,42 +367,42 @@ union usb_btable_ent; /* Bidirectional endpoint BTABLE entry */ typedef struct usb_btable_bidi { - __io uint16 addr_tx; const uint16 PAD1; - __io uint16 count_tx; const uint16 PAD2; - __io uint16 addr_rx; const uint16 PAD3; - __io uint16 count_rx; const uint16 PAD4; + __IO uint16 addr_tx; const uint16 PAD1; + __IO uint16 count_tx; const uint16 PAD2; + __IO uint16 addr_rx; const uint16 PAD3; + __IO uint16 count_rx; const uint16 PAD4; } usb_btable_bidi; /* Unidirectional receive-only endpoint BTABLE entry */ typedef struct usb_btable_uni_rx { - __io uint16 empty1; const uint16 PAD1; - __io uint16 empty2; const uint16 PAD2; - __io uint16 addr_rx; const uint16 PAD3; - __io uint16 count_rx; const uint16 PAD4; + __IO uint16 empty1; const uint16 PAD1; + __IO uint16 empty2; const uint16 PAD2; + __IO uint16 addr_rx; const uint16 PAD3; + __IO uint16 count_rx; const uint16 PAD4; } usb_btable_uni_rx; /* Unidirectional transmit-only endpoint BTABLE entry */ typedef struct usb_btable_uni_tx { - __io uint16 addr_tx; const uint16 PAD1; - __io uint16 count_tx; const uint16 PAD2; - __io uint16 empty1; const uint16 PAD3; - __io uint16 empty2; const uint16 PAD4; + __IO uint16 addr_tx; const uint16 PAD1; + __IO uint16 count_tx; const uint16 PAD2; + __IO uint16 empty1; const uint16 PAD3; + __IO uint16 empty2; const uint16 PAD4; } usb_btable_uni_tx; /* Double-buffered transmission endpoint BTABLE entry */ typedef struct usb_btable_dbl_tx { - __io uint16 addr_tx0; const uint16 PAD1; - __io uint16 count_tx0; const uint16 PAD2; - __io uint16 addr_tx1; const uint16 PAD3; - __io uint16 count_tx1; const uint16 PAD4; + __IO uint16 addr_tx0; const uint16 PAD1; + __IO uint16 count_tx0; const uint16 PAD2; + __IO uint16 addr_tx1; const uint16 PAD3; + __IO uint16 count_tx1; const uint16 PAD4; } usb_btable_dbl_tx; /* Double-buffered reception endpoint BTABLE entry */ typedef struct usb_btable_dbl_rx { - __io uint16 addr_rx0; const uint16 PAD1; - __io uint16 count_rx0; const uint16 PAD2; - __io uint16 addr_rx1; const uint16 PAD3; - __io uint16 count_rx1; const uint16 PAD4; + __IO uint16 addr_rx0; const uint16 PAD1; + __IO uint16 count_rx0; const uint16 PAD2; + __IO uint16 addr_rx1; const uint16 PAD3; + __IO uint16 count_rx1; const uint16 PAD4; } usb_btable_dbl_rx; /* TODO isochronous endpoint entries */ diff --git a/STM32F4/cores/maple/libmaple/adc.c b/STM32F4/cores/maple/libmaple/adc.c index 0f4c02c..f44156d 100644 --- a/STM32F4/cores/maple/libmaple/adc.c +++ b/STM32F4/cores/maple/libmaple/adc.c @@ -137,8 +137,8 @@ void adc_calibrate(const adc_dev *dev) { /* #ifndef STM32F2 - __io uint32 *rstcal_bit = bb_perip(&(dev->regs->CR2), 3); - __io uint32 *cal_bit = bb_perip(&(dev->regs->CR2), 2); + __IO uint32 *rstcal_bit = bb_perip(&(dev->regs->CR2), 3); + __IO uint32 *cal_bit = bb_perip(&(dev->regs->CR2), 2); *rstcal_bit = 1; while (*rstcal_bit) diff --git a/STM32F4/cores/maple/libmaple/adc.h b/STM32F4/cores/maple/libmaple/adc.h index a4c11ff..398c242 100644 --- a/STM32F4/cores/maple/libmaple/adc.h +++ b/STM32F4/cores/maple/libmaple/adc.h @@ -44,9 +44,9 @@ extern "C"{ typedef struct { - __io uint32 CSR; /*!< ADC Common status register, Address offset: ADC1 base address + 0x300 */ - __io uint32 CCR; /*!< ADC common control register, Address offset: ADC1 base address + 0x304 */ - __io uint32 CDR; /*!< ADC common regular data register for dual + __IO uint32 CSR; /*!< ADC Common status register, Address offset: ADC1 base address + 0x300 */ + __IO uint32 CCR; /*!< ADC common control register, Address offset: ADC1 base address + 0x304 */ + __IO uint32 CDR; /*!< ADC common regular data register for dual AND triple modes, Address offset: ADC1 base address + 0x308 */ } ADC_Common_TypeDef; #define ADC_COMMON ((ADC_Common_TypeDef *) 0x40012300) @@ -54,26 +54,26 @@ typedef struct /** ADC register map type. */ typedef struct adc_reg_map { - __io uint32 SR; ///< Status register - __io uint32 CR1; ///< Control register 1 - __io uint32 CR2; ///< Control register 2 - __io uint32 SMPR1; ///< Sample time register 1 - __io uint32 SMPR2; ///< Sample time register 2 - __io uint32 JOFR1; ///< Injected channel data offset register 1 - __io uint32 JOFR2; ///< Injected channel data offset register 2 - __io uint32 JOFR3; ///< Injected channel data offset register 3 - __io uint32 JOFR4; ///< Injected channel data offset register 4 - __io uint32 HTR; ///< Watchdog high threshold register - __io uint32 LTR; ///< Watchdog low threshold register - __io uint32 SQR1; ///< Regular sequence register 1 - __io uint32 SQR2; ///< Regular sequence register 2 - __io uint32 SQR3; ///< Regular sequence register 3 - __io uint32 JSQR; ///< Injected sequence register - __io uint32 JDR1; ///< Injected data register 1 - __io uint32 JDR2; ///< Injected data register 2 - __io uint32 JDR3; ///< Injected data register 3 - __io uint32 JDR4; ///< Injected data register 4 - __io uint32 DR; ///< Regular data register + __IO uint32 SR; ///< Status register + __IO uint32 CR1; ///< Control register 1 + __IO uint32 CR2; ///< Control register 2 + __IO uint32 SMPR1; ///< Sample time register 1 + __IO uint32 SMPR2; ///< Sample time register 2 + __IO uint32 JOFR1; ///< Injected channel data offset register 1 + __IO uint32 JOFR2; ///< Injected channel data offset register 2 + __IO uint32 JOFR3; ///< Injected channel data offset register 3 + __IO uint32 JOFR4; ///< Injected channel data offset register 4 + __IO uint32 HTR; ///< Watchdog high threshold register + __IO uint32 LTR; ///< Watchdog low threshold register + __IO uint32 SQR1; ///< Regular sequence register 1 + __IO uint32 SQR2; ///< Regular sequence register 2 + __IO uint32 SQR3; ///< Regular sequence register 3 + __IO uint32 JSQR; ///< Injected sequence register + __IO uint32 JDR1; ///< Injected data register 1 + __IO uint32 JDR2; ///< Injected data register 2 + __IO uint32 JDR3; ///< Injected data register 3 + __IO uint32 JDR4; ///< Injected data register 4 + __IO uint32 DR; ///< Regular data register } adc_reg_map; /** ADC device type. */ diff --git a/STM32F4/cores/maple/libmaple/bkp.c b/STM32F4/cores/maple/libmaple/bkp.c index 7d1ad7f..a923e77 100644 --- a/STM32F4/cores/maple/libmaple/bkp.c +++ b/STM32F4/cores/maple/libmaple/bkp.c @@ -34,7 +34,7 @@ #include "rcc.h" #include "bitband.h" -static inline __io uint32* data_register(uint8 reg); +static inline __IO uint32* data_register(uint8 reg); bkp_dev bkp = { .regs = BKP_BASE, @@ -78,7 +78,7 @@ void bkp_disable_writes(void) { * medium-density devices, 42 on high-density devices). */ uint16 bkp_read(uint8 reg) { - __io uint32* dr = data_register(reg); + __IO uint32* dr = data_register(reg); if (!dr) { ASSERT(0); /* nonexistent register */ return 0; @@ -97,7 +97,7 @@ uint16 bkp_read(uint8 reg) { * @see bkp_enable_writes() */ void bkp_write(uint8 reg, uint16 val) { - __io uint32* dr = data_register(reg); + __IO uint32* dr = data_register(reg); if (!dr) { ASSERT(0); /* nonexistent register */ return; @@ -112,7 +112,7 @@ void bkp_write(uint8 reg, uint16 val) { */ #define NR_LOW_DRS 10 -static inline __io uint32* data_register(uint8 reg) { +static inline __IO uint32* data_register(uint8 reg) { if (reg < 1 || reg > BKP_NR_DATA_REGS) { return 0; } diff --git a/STM32F4/cores/maple/libmaple/bkp.h b/STM32F4/cores/maple/libmaple/bkp.h index a81267d..dd378b4 100644 --- a/STM32F4/cores/maple/libmaple/bkp.h +++ b/STM32F4/cores/maple/libmaple/bkp.h @@ -47,54 +47,54 @@ extern "C" { /** Backup peripheral register map type. */ typedef struct bkp_reg_map { const uint32 RESERVED1; ///< Reserved - __io uint32 DR1; ///< Data register 1 - __io uint32 DR2; ///< Data register 2 - __io uint32 DR3; ///< Data register 3 - __io uint32 DR4; ///< Data register 4 - __io uint32 DR5; ///< Data register 5 - __io uint32 DR6; ///< Data register 6 - __io uint32 DR7; ///< Data register 7 - __io uint32 DR8; ///< Data register 8 - __io uint32 DR9; ///< Data register 9 - __io uint32 DR10; ///< Data register 10 - __io uint32 RTCCR; ///< RTC control register - __io uint32 CR; ///< Control register - __io uint32 CSR; ///< Control and status register + __IO uint32 DR1; ///< Data register 1 + __IO uint32 DR2; ///< Data register 2 + __IO uint32 DR3; ///< Data register 3 + __IO uint32 DR4; ///< Data register 4 + __IO uint32 DR5; ///< Data register 5 + __IO uint32 DR6; ///< Data register 6 + __IO uint32 DR7; ///< Data register 7 + __IO uint32 DR8; ///< Data register 8 + __IO uint32 DR9; ///< Data register 9 + __IO uint32 DR10; ///< Data register 10 + __IO uint32 RTCCR; ///< RTC control register + __IO uint32 CR; ///< Control register + __IO uint32 CSR; ///< Control and status register #ifdef STM32_HIGH_DENSITY const uint32 RESERVED2; ///< Reserved const uint32 RESERVED3; ///< Reserved - __io uint32 DR11; ///< Data register 11 - __io uint32 DR12; ///< Data register 12 - __io uint32 DR13; ///< Data register 13 - __io uint32 DR14; ///< Data register 14 - __io uint32 DR15; ///< Data register 15 - __io uint32 DR16; ///< Data register 16 - __io uint32 DR17; ///< Data register 17 - __io uint32 DR18; ///< Data register 18 - __io uint32 DR19; ///< Data register 19 - __io uint32 DR20; ///< Data register 20 - __io uint32 DR21; ///< Data register 21 - __io uint32 DR22; ///< Data register 22 - __io uint32 DR23; ///< Data register 23 - __io uint32 DR24; ///< Data register 24 - __io uint32 DR25; ///< Data register 25 - __io uint32 DR26; ///< Data register 26 - __io uint32 DR27; ///< Data register 27 - __io uint32 DR28; ///< Data register 28 - __io uint32 DR29; ///< Data register 29 - __io uint32 DR30; ///< Data register 30 - __io uint32 DR31; ///< Data register 31 - __io uint32 DR32; ///< Data register 32 - __io uint32 DR33; ///< Data register 33 - __io uint32 DR34; ///< Data register 34 - __io uint32 DR35; ///< Data register 35 - __io uint32 DR36; ///< Data register 36 - __io uint32 DR37; ///< Data register 37 - __io uint32 DR38; ///< Data register 38 - __io uint32 DR39; ///< Data register 39 - __io uint32 DR40; ///< Data register 40 - __io uint32 DR41; ///< Data register 41 - __io uint32 DR42; ///< Data register 42 + __IO uint32 DR11; ///< Data register 11 + __IO uint32 DR12; ///< Data register 12 + __IO uint32 DR13; ///< Data register 13 + __IO uint32 DR14; ///< Data register 14 + __IO uint32 DR15; ///< Data register 15 + __IO uint32 DR16; ///< Data register 16 + __IO uint32 DR17; ///< Data register 17 + __IO uint32 DR18; ///< Data register 18 + __IO uint32 DR19; ///< Data register 19 + __IO uint32 DR20; ///< Data register 20 + __IO uint32 DR21; ///< Data register 21 + __IO uint32 DR22; ///< Data register 22 + __IO uint32 DR23; ///< Data register 23 + __IO uint32 DR24; ///< Data register 24 + __IO uint32 DR25; ///< Data register 25 + __IO uint32 DR26; ///< Data register 26 + __IO uint32 DR27; ///< Data register 27 + __IO uint32 DR28; ///< Data register 28 + __IO uint32 DR29; ///< Data register 29 + __IO uint32 DR30; ///< Data register 30 + __IO uint32 DR31; ///< Data register 31 + __IO uint32 DR32; ///< Data register 32 + __IO uint32 DR33; ///< Data register 33 + __IO uint32 DR34; ///< Data register 34 + __IO uint32 DR35; ///< Data register 35 + __IO uint32 DR36; ///< Data register 36 + __IO uint32 DR37; ///< Data register 37 + __IO uint32 DR38; ///< Data register 38 + __IO uint32 DR39; ///< Data register 39 + __IO uint32 DR40; ///< Data register 40 + __IO uint32 DR41; ///< Data register 41 + __IO uint32 DR42; ///< Data register 42 #endif } bkp_reg_map; diff --git a/STM32F4/cores/maple/libmaple/dac.h b/STM32F4/cores/maple/libmaple/dac.h index dd1b22b..6c5f2e8 100644 --- a/STM32F4/cores/maple/libmaple/dac.h +++ b/STM32F4/cores/maple/libmaple/dac.h @@ -46,28 +46,28 @@ extern "C"{ /** DAC register map. */ typedef struct dac_reg_map { - __io uint32 CR; /**< Control register */ - __io uint32 SWTRIGR; /**< Software trigger register */ - __io uint32 DHR12R1; /**< Channel 1 12-bit right-aligned data + __IO uint32 CR; /**< Control register */ + __IO uint32 SWTRIGR; /**< Software trigger register */ + __IO uint32 DHR12R1; /**< Channel 1 12-bit right-aligned data holding register */ - __io uint32 DHR12L1; /**< Channel 1 12-bit left-aligned data + __IO uint32 DHR12L1; /**< Channel 1 12-bit left-aligned data holding register */ - __io uint32 DHR8R1; /**< Channel 1 8-bit left-aligned data + __IO uint32 DHR8R1; /**< Channel 1 8-bit left-aligned data holding register */ - __io uint32 DHR12R2; /**< Channel 2 12-bit right-aligned data + __IO uint32 DHR12R2; /**< Channel 2 12-bit right-aligned data holding register */ - __io uint32 DHR12L2; /**< Channel 2 12-bit left-aligned data + __IO uint32 DHR12L2; /**< Channel 2 12-bit left-aligned data holding register */ - __io uint32 DHR8R2; /**< Channel 2 8-bit left-aligned data + __IO uint32 DHR8R2; /**< Channel 2 8-bit left-aligned data holding register */ - __io uint32 DHR12RD; /**< Dual DAC 12-bit right-aligned data + __IO uint32 DHR12RD; /**< Dual DAC 12-bit right-aligned data holding register */ - __io uint32 DHR12LD; /**< Dual DAC 12-bit left-aligned data + __IO uint32 DHR12LD; /**< Dual DAC 12-bit left-aligned data holding register */ - __io uint32 DHR8RD; /**< Dual DAC 8-bit right-aligned data holding + __IO uint32 DHR8RD; /**< Dual DAC 8-bit right-aligned data holding register */ - __io uint32 DOR1; /**< Channel 1 data output register */ - __io uint32 DOR2; /**< Channel 2 data output register */ + __IO uint32 DOR1; /**< Channel 1 data output register */ + __IO uint32 DOR2; /**< Channel 2 data output register */ } dac_reg_map; /** DAC register map base address */ diff --git a/STM32F4/cores/maple/libmaple/dmaF4.h b/STM32F4/cores/maple/libmaple/dmaF4.h index cb23760..388c64b 100644 --- a/STM32F4/cores/maple/libmaple/dmaF4.h +++ b/STM32F4/cores/maple/libmaple/dmaF4.h @@ -57,22 +57,22 @@ extern "C"{ * */ typedef struct dma_stream_t { - __io uint32 CR; /**< Stream configuration register */ - __io uint32 NDTR; /**< Stream number of data register */ - __io uint32 PAR; /**< Stream peripheral address register */ - __io uint32 M0AR; /**< Stream memory address register 0 */ - __io uint32 M1AR; /**< Stream memory address register 1 */ - __io uint32 FCR; /**< Stream FIFO configuration register */ + __IO uint32 CR; /**< Stream configuration register */ + __IO uint32 NDTR; /**< Stream number of data register */ + __IO uint32 PAR; /**< Stream peripheral address register */ + __IO uint32 M0AR; /**< Stream memory address register 0 */ + __IO uint32 M1AR; /**< Stream memory address register 1 */ + __IO uint32 FCR; /**< Stream FIFO configuration register */ } dma_stream_t; /** * @brief DMA register map type. * */ typedef struct dma_reg_map { - __io uint32 LISR; /**< Low interrupt status register */ - __io uint32 HISR; /**< High interrupt status register */ - __io uint32 LIFCR; /**< Low interrupt flag clear register */ - __io uint32 HIFCR; /**< High interrupt flag clear register */ + __IO uint32 LISR; /**< Low interrupt status register */ + __IO uint32 HISR; /**< High interrupt status register */ + __IO uint32 LIFCR; /**< Low interrupt flag clear register */ + __IO uint32 HIFCR; /**< High interrupt flag clear register */ dma_stream_t STREAM[8]; } dma_reg_map; @@ -255,9 +255,9 @@ static inline void dma_setup_transfer(dma_dev *dev, dma_stream stream, dma_channel channel, dma_xfer_size trx_size, - __io void *peripheral_address, - __io void *memory_address0, - __io void *memory_address1, + __IO void *peripheral_address, + __IO void *memory_address0, + __IO void *memory_address1, uint32 flags) { dev->regs->STREAM[stream].CR &= ~DMA_CR_EN; // disable diff --git a/STM32F4/cores/maple/libmaple/exti.h b/STM32F4/cores/maple/libmaple/exti.h index 063f2d7..83a3cc2 100644 --- a/STM32F4/cores/maple/libmaple/exti.h +++ b/STM32F4/cores/maple/libmaple/exti.h @@ -43,12 +43,12 @@ extern "C"{ /** EXTI register map type */ typedef struct exti_reg_map { - __io uint32 IMR; /**< Interrupt mask register */ - __io uint32 EMR; /**< Event mask register */ - __io uint32 RTSR; /**< Rising trigger selection register */ - __io uint32 FTSR; /**< Falling trigger selection register */ - __io uint32 SWIER; /**< Software interrupt event register */ - __io uint32 PR; /**< Pending register */ + __IO uint32 IMR; /**< Interrupt mask register */ + __IO uint32 EMR; /**< Event mask register */ + __IO uint32 RTSR; /**< Rising trigger selection register */ + __IO uint32 FTSR; /**< Falling trigger selection register */ + __IO uint32 SWIER; /**< Software interrupt event register */ + __IO uint32 PR; /**< Pending register */ } exti_reg_map; /** EXTI register map base pointer */ diff --git a/STM32F4/cores/maple/libmaple/flash.h b/STM32F4/cores/maple/libmaple/flash.h index 0b4e49b..d9730ca 100644 --- a/STM32F4/cores/maple/libmaple/flash.h +++ b/STM32F4/cores/maple/libmaple/flash.h @@ -41,14 +41,14 @@ extern "C"{ /** Flash register map type */ typedef struct flash_reg_map { - __io uint32 ACR; /**< Access control register */ - __io uint32 KEYR; /**< Key register */ - __io uint32 OPTKEYR; /**< OPTKEY register */ - __io uint32 SR; /**< Status register */ - __io uint32 CR; /**< Control register */ - __io uint32 AR; /**< Address register */ - __io uint32 OBR; /**< Option byte register */ - __io uint32 WRPR; /**< Write protection register */ + __IO uint32 ACR; /**< Access control register */ + __IO uint32 KEYR; /**< Key register */ + __IO uint32 OPTKEYR; /**< OPTKEY register */ + __IO uint32 SR; /**< Status register */ + __IO uint32 CR; /**< Control register */ + __IO uint32 AR; /**< Address register */ + __IO uint32 OBR; /**< Option byte register */ + __IO uint32 WRPR; /**< Write protection register */ } flash_reg_map; /** Flash register map base pointer */ diff --git a/STM32F4/cores/maple/libmaple/fsmc.h b/STM32F4/cores/maple/libmaple/fsmc.h index 03a6acf..d384946 100644 --- a/STM32F4/cores/maple/libmaple/fsmc.h +++ b/STM32F4/cores/maple/libmaple/fsmc.h @@ -55,42 +55,42 @@ extern "C"{ /** FSMC register map type */ typedef struct fsmc_reg_map { - __io uint32 BCR1; /**< SRAM/NOR-Flash chip-select control register 1 */ - __io uint32 BTR1; /**< SRAM/NOR-Flash chip-select timing register 1 */ - __io uint32 BCR2; /**< SRAM/NOR-Flash chip-select control register 2 */ - __io uint32 BTR2; /**< SRAM/NOR-Flash chip-select timing register 2 */ - __io uint32 BCR3; /**< SRAM/NOR-Flash chip-select control register 3 */ - __io uint32 BTR3; /**< SRAM/NOR-Flash chip-select timing register 3 */ - __io uint32 BCR4; /**< SRAM/NOR-Flash chip-select control register 4 */ - __io uint32 BTR4; /**< SRAM/NOR-Flash chip-select timing register 4 */ + __IO uint32 BCR1; /**< SRAM/NOR-Flash chip-select control register 1 */ + __IO uint32 BTR1; /**< SRAM/NOR-Flash chip-select timing register 1 */ + __IO uint32 BCR2; /**< SRAM/NOR-Flash chip-select control register 2 */ + __IO uint32 BTR2; /**< SRAM/NOR-Flash chip-select timing register 2 */ + __IO uint32 BCR3; /**< SRAM/NOR-Flash chip-select control register 3 */ + __IO uint32 BTR3; /**< SRAM/NOR-Flash chip-select timing register 3 */ + __IO uint32 BCR4; /**< SRAM/NOR-Flash chip-select control register 4 */ + __IO uint32 BTR4; /**< SRAM/NOR-Flash chip-select timing register 4 */ const uint32 RESERVED1[16]; /**< Reserved */ - __io uint32 PCR2; /**< PC Card/NAND Flash control register 2 */ - __io uint32 SR2; /**< FIFO status and interrupt register 2 */ - __io uint32 PMEM2; /**< Common memory space timing register 2 */ - __io uint32 PATT2; /**< Attribute memory space timing register 2 */ + __IO uint32 PCR2; /**< PC Card/NAND Flash control register 2 */ + __IO uint32 SR2; /**< FIFO status and interrupt register 2 */ + __IO uint32 PMEM2; /**< Common memory space timing register 2 */ + __IO uint32 PATT2; /**< Attribute memory space timing register 2 */ const uint32 RESERVED2; /**< Reserved */ - __io uint32 ECCR2; /**< ECC result register 2 */ + __IO uint32 ECCR2; /**< ECC result register 2 */ const uint32 RESERVED3[2]; /**< Reserved */ - __io uint32 PCR3; /**< PC Card/NAND Flash control register 3 */ - __io uint32 SR3; /**< FIFO status and interrupt register 3 */ - __io uint32 PMEM3; /**< Common memory space timing register 3 */ - __io uint32 PATT3; /**< Attribute memory space timing register 3 */ + __IO uint32 PCR3; /**< PC Card/NAND Flash control register 3 */ + __IO uint32 SR3; /**< FIFO status and interrupt register 3 */ + __IO uint32 PMEM3; /**< Common memory space timing register 3 */ + __IO uint32 PATT3; /**< Attribute memory space timing register 3 */ const uint32 RESERVED4; /**< Reserved */ - __io uint32 ECCR3; /**< ECC result register 3 */ + __IO uint32 ECCR3; /**< ECC result register 3 */ const uint32 RESERVED5[2]; /**< Reserved */ - __io uint32 PCR4; /**< PC Card/NAND Flash control register 4 */ - __io uint32 SR4; /**< FIFO status and interrupt register 4 */ - __io uint32 PMEM4; /**< Common memory space timing register 4 */ - __io uint32 PATT4; /**< Attribute memory space timing register 4 */ - __io uint32 PIO4; /**< I/O space timing register 4 */ + __IO uint32 PCR4; /**< PC Card/NAND Flash control register 4 */ + __IO uint32 SR4; /**< FIFO status and interrupt register 4 */ + __IO uint32 PMEM4; /**< Common memory space timing register 4 */ + __IO uint32 PATT4; /**< Attribute memory space timing register 4 */ + __IO uint32 PIO4; /**< I/O space timing register 4 */ const uint32 RESERVED6[20]; /**< Reserved */ - __io uint32 BWTR1; /**< SRAM/NOR-Flash write timing register 1 */ + __IO uint32 BWTR1; /**< SRAM/NOR-Flash write timing register 1 */ const uint32 RESERVED7; /**< Reserved */ - __io uint32 BWTR2; /**< SRAM/NOR-Flash write timing register 2 */ + __IO uint32 BWTR2; /**< SRAM/NOR-Flash write timing register 2 */ const uint32 RESERVED8; /**< Reserved */ - __io uint32 BWTR3; /**< SRAM/NOR-Flash write timing register 3 */ + __IO uint32 BWTR3; /**< SRAM/NOR-Flash write timing register 3 */ const uint32 RESERVED9; /**< Reserved */ - __io uint32 BWTR4; /**< SRAM/NOR-Flash write timing register 4 */ + __IO uint32 BWTR4; /**< SRAM/NOR-Flash write timing register 4 */ } __attribute__((packed)) fsmc_reg_map; #define __FSMCB 0xA0000000 @@ -100,10 +100,10 @@ typedef struct fsmc_reg_map { /** FSMC NOR/PSRAM register map type */ typedef struct fsmc_nor_psram_reg_map { - __io uint32 BCR; /**< Chip-select control register */ - __io uint32 BTR; /**< Chip-select timing register */ + __IO uint32 BCR; /**< Chip-select control register */ + __IO uint32 BTR; /**< Chip-select timing register */ const uint32 RESERVED[63]; /**< Reserved */ - __io uint32 BWTR; /**< Write timing register */ + __IO uint32 BWTR; /**< Write timing register */ } fsmc_nor_psram_reg_map; /** FSMC NOR/PSRAM base pointer 1 */ diff --git a/STM32F4/cores/maple/libmaple/gpio.h b/STM32F4/cores/maple/libmaple/gpio.h index f1a141f..79ce7d3 100644 --- a/STM32F4/cores/maple/libmaple/gpio.h +++ b/STM32F4/cores/maple/libmaple/gpio.h @@ -120,7 +120,7 @@ extern void afio_remap(afio_remap_peripheral p); * @see afio_debug_cfg */ static inline void afio_cfg_debug_ports(afio_debug_cfg config) { - //__io uint32 *mapr = &AFIO_BASE->MAPR; + //__IO uint32 *mapr = &AFIO_BASE->MAPR; //*mapr = (*mapr & ~AFIO_MAPR_SWJ_CFG) | config; } diff --git a/STM32F4/cores/maple/libmaple/gpioF4.c b/STM32F4/cores/maple/libmaple/gpioF4.c index af839eb..0409bcc 100644 --- a/STM32F4/cores/maple/libmaple/gpioF4.c +++ b/STM32F4/cores/maple/libmaple/gpioF4.c @@ -194,7 +194,7 @@ void afio_init(void) { * @see afio_exti_port */ void afio_exti_select(afio_exti_num exti, afio_exti_port gpio_port) { - __io uint32 *exti_cr = &SYSCFG_BASE->EXTICR1 + exti / 4; + __IO uint32 *exti_cr = &SYSCFG_BASE->EXTICR1 + exti / 4; uint32 shift = 4 * (exti % 4); uint32 cr = *exti_cr; diff --git a/STM32F4/cores/maple/libmaple/gpio_def.h b/STM32F4/cores/maple/libmaple/gpio_def.h index 4a8e61e..4168969 100644 --- a/STM32F4/cores/maple/libmaple/gpio_def.h +++ b/STM32F4/cores/maple/libmaple/gpio_def.h @@ -47,16 +47,16 @@ extern "C"{ /** GPIO register map type */ typedef struct gpio_reg_map { - __io uint32 MODER; /*!< GPIO port mode register, Address offset: 0x00 */ - __io uint32 OTYPER; /*!< GPIO port output type register, Address offset: 0x04 */ - __io uint32 OSPEEDR; /*!< GPIO port output speed register, Address offset: 0x08 */ - __io uint32 PUPDR; /*!< GPIO port pull-up/pull-down register, Address offset: 0x0C */ - __io uint32 IDR; /*!< GPIO port input data register, Address offset: 0x10 */ - __io uint32 ODR; /*!< GPIO port output data register, Address offset: 0x14 */ - __io uint16 BSRRL; /*!< GPIO port bit set/reset low register, Address offset: 0x18 */ - __io uint16 BSRRH; /*!< GPIO port bit set/reset high register, Address offset: 0x1A */ - __io uint32 LCKR; /*!< GPIO port configuration lock register, Address offset: 0x1C */ - __io uint32 AFR[2]; /*!< GPIO alternate function registers, Address offset: 0x24-0x28 */ + __IO uint32 MODER; /*!< GPIO port mode register, Address offset: 0x00 */ + __IO uint32 OTYPER; /*!< GPIO port output type register, Address offset: 0x04 */ + __IO uint32 OSPEEDR; /*!< GPIO port output speed register, Address offset: 0x08 */ + __IO uint32 PUPDR; /*!< GPIO port pull-up/pull-down register, Address offset: 0x0C */ + __IO uint32 IDR; /*!< GPIO port input data register, Address offset: 0x10 */ + __IO uint32 ODR; /*!< GPIO port output data register, Address offset: 0x14 */ + __IO uint16 BSRRL; /*!< GPIO port bit set/reset low register, Address offset: 0x18 */ + __IO uint16 BSRRH; /*!< GPIO port bit set/reset high register, Address offset: 0x1A */ + __IO uint32 LCKR; /*!< GPIO port configuration lock register, Address offset: 0x1C */ + __IO uint32 AFR[2]; /*!< GPIO alternate function registers, Address offset: 0x24-0x28 */ } gpio_reg_map; @@ -200,13 +200,13 @@ typedef enum gpio_pin_mode { /** AFIO register map */ typedef struct syscfg_reg_map { - __io uint32 MEMRM; /**< memory remap register */ - __io uint32 PMC; /**< peripheral mode configuration register */ - __io uint32 EXTICR1; /**< External interrupt configuration register 1. */ - __io uint32 EXTICR2; /**< External interrupt configuration register 2. */ - __io uint32 EXTICR3; /**< External interrupt configuration register 3. */ - __io uint32 EXTICR4; /**< External interrupt configuration register 4. */ - __io uint32 CMPCR; /**< Compensation cell control register */ + __IO uint32 MEMRM; /**< memory remap register */ + __IO uint32 PMC; /**< peripheral mode configuration register */ + __IO uint32 EXTICR1; /**< External interrupt configuration register 1. */ + __IO uint32 EXTICR2; /**< External interrupt configuration register 2. */ + __IO uint32 EXTICR3; /**< External interrupt configuration register 3. */ + __IO uint32 EXTICR4; /**< External interrupt configuration register 4. */ + __IO uint32 CMPCR; /**< Compensation cell control register */ } syscfg_reg_map; /** AFIO register map base pointer. */ diff --git a/STM32F4/cores/maple/libmaple/i2c.h b/STM32F4/cores/maple/libmaple/i2c.h index 28819a3..674dd35 100644 --- a/STM32F4/cores/maple/libmaple/i2c.h +++ b/STM32F4/cores/maple/libmaple/i2c.h @@ -39,15 +39,15 @@ /** I2C register map type */ typedef struct i2c_reg_map { - __io uint32 CR1; /**< Control register 1 */ - __io uint32 CR2; /**< Control register 2 */ - __io uint32 OAR1; /**< Own address register 1 */ - __io uint32 OAR2; /**< Own address register 2 */ - __io uint32 DR; /**< Data register */ - __io uint32 SR1; /**< Status register 1 */ - __io uint32 SR2; /**< Status register 2 */ - __io uint32 CCR; /**< Clock control register */ - __io uint32 TRISE; /**< TRISE (rise time) register */ + __IO uint32 CR1; /**< Control register 1 */ + __IO uint32 CR2; /**< Control register 2 */ + __IO uint32 OAR1; /**< Own address register 1 */ + __IO uint32 OAR2; /**< Own address register 2 */ + __IO uint32 DR; /**< Data register */ + __IO uint32 SR1; /**< Status register 1 */ + __IO uint32 SR2; /**< Status register 2 */ + __IO uint32 CCR; /**< Clock control register */ + __IO uint32 TRISE; /**< TRISE (rise time) register */ } i2c_reg_map; /** I2C device states */ diff --git a/STM32F4/cores/maple/libmaple/iwdg.h b/STM32F4/cores/maple/libmaple/iwdg.h index 59e8e18..3673e69 100644 --- a/STM32F4/cores/maple/libmaple/iwdg.h +++ b/STM32F4/cores/maple/libmaple/iwdg.h @@ -54,10 +54,10 @@ extern "C"{ /** Independent watchdog register map type. */ typedef struct iwdg_reg_map { - __io uint32 KR; /**< Key register. */ - __io uint32 PR; /**< Prescaler register. */ - __io uint32 RLR; /**< Reload register. */ - __io uint32 SR; /**< Status register */ + __IO uint32 KR; /**< Key register. */ + __IO uint32 PR; /**< Prescaler register. */ + __IO uint32 RLR; /**< Reload register. */ + __IO uint32 SR; /**< Status register */ } iwdg_reg_map; /** Independent watchdog base pointer */ diff --git a/STM32F4/cores/maple/libmaple/libmaple_types.h b/STM32F4/cores/maple/libmaple/libmaple_types.h index 8e765b4..4a6b3ec 100644 --- a/STM32F4/cores/maple/libmaple/libmaple_types.h +++ b/STM32F4/cores/maple/libmaple/libmaple_types.h @@ -47,7 +47,7 @@ typedef long long int64; typedef void (*voidFuncPtr)(void); -#define __io volatile +#define __IO volatile #define __IO volatile #ifndef __attr_flash #define __attr_flash __attribute__((section (".USER_FLASH"))) diff --git a/STM32F4/cores/maple/libmaple/nvic.h b/STM32F4/cores/maple/libmaple/nvic.h index e3b052d..ace2701 100644 --- a/STM32F4/cores/maple/libmaple/nvic.h +++ b/STM32F4/cores/maple/libmaple/nvic.h @@ -55,19 +55,19 @@ extern "C"{ /** NVIC register map type. */ typedef struct nvic_reg_map { - __io uint32 ISER[8]; /**< Interrupt Set Enable Registers */ + __IO uint32 ISER[8]; /**< Interrupt Set Enable Registers */ uint32 RESERVED0[24]; /**< Reserved */ - __io uint32 ICER[8]; /**< Interrupt Clear Enable Registers */ + __IO uint32 ICER[8]; /**< Interrupt Clear Enable Registers */ uint32 RSERVED1[24]; /**< Reserved */ - __io uint32 ISPR[8]; /**< Interrupt Set Pending Registers */ + __IO uint32 ISPR[8]; /**< Interrupt Set Pending Registers */ uint32 RESERVED2[24]; /**< Reserved */ - __io uint32 ICPR[8]; /**< Interrupt Clear Pending Registers */ + __IO uint32 ICPR[8]; /**< Interrupt Clear Pending Registers */ uint32 RESERVED3[24]; /**< Reserved */ - __io uint32 IABR[8]; /**< Interrupt Active bit Registers */ + __IO uint32 IABR[8]; /**< Interrupt Active bit Registers */ uint32 RESERVED4[56]; /**< Reserved */ - __io uint8 IP[240]; /**< Interrupt Priority Registers */ + __IO uint8 IP[240]; /**< Interrupt Priority Registers */ uint32 RESERVED5[644]; /**< Reserved */ - __io uint32 STIR; /**< Software Trigger Interrupt Registers */ + __IO uint32 STIR; /**< Software Trigger Interrupt Registers */ } nvic_reg_map; /** NVIC register map base pointer. */ diff --git a/STM32F4/cores/maple/libmaple/pwr.h b/STM32F4/cores/maple/libmaple/pwr.h index 88b49c0..c8c4899 100644 --- a/STM32F4/cores/maple/libmaple/pwr.h +++ b/STM32F4/cores/maple/libmaple/pwr.h @@ -37,8 +37,8 @@ extern "C" { /** Power interface register map. */ typedef struct pwr_reg_map { - __io uint32 CR; /**< Control register */ - __io uint32 CSR; /**< Control and status register */ + __IO uint32 CR; /**< Control register */ + __IO uint32 CSR; /**< Control and status register */ } pwr_reg_map; /** Power peripheral register map base pointer. */ diff --git a/STM32F4/cores/maple/libmaple/rccF4.c b/STM32F4/cores/maple/libmaple/rccF4.c index c4ff30d..54cef70 100644 --- a/STM32F4/cores/maple/libmaple/rccF4.c +++ b/STM32F4/cores/maple/libmaple/rccF4.c @@ -144,8 +144,8 @@ static const struct rcc_dev_info rcc_dev_table[] = { typedef struct { - __io uint32 CR; /*!< PWR power control register, Address offset: 0x00 */ - __io uint32 CSR; /*!< PWR power control/status register, Address offset: 0x04 */ + __IO uint32 CR; /*!< PWR power control register, Address offset: 0x00 */ + __IO uint32 CSR; /*!< PWR power control/status register, Address offset: 0x04 */ } PWR_TypeDef; #define PWR_BASE (0x40007000) @@ -154,12 +154,12 @@ typedef struct typedef struct { - __io uint32 ACR; /*!< FLASH access control register, Address offset: 0x00 */ - __io uint32 KEYR; /*!< FLASH key register, Address offset: 0x04 */ - __io uint32 OPTKEYR; /*!< FLASH option key register, Address offset: 0x08 */ - __io uint32 SR; /*!< FLASH status register, Address offset: 0x0C */ - __io uint32 CR; /*!< FLASH control register, Address offset: 0x10 */ - __io uint32 OPTCR; /*!< FLASH option control register, Address offset: 0x14 */ + __IO uint32 ACR; /*!< FLASH access control register, Address offset: 0x00 */ + __IO uint32 KEYR; /*!< FLASH key register, Address offset: 0x04 */ + __IO uint32 OPTKEYR; /*!< FLASH option key register, Address offset: 0x08 */ + __IO uint32 SR; /*!< FLASH status register, Address offset: 0x0C */ + __IO uint32 CR; /*!< FLASH control register, Address offset: 0x10 */ + __IO uint32 OPTCR; /*!< FLASH option control register, Address offset: 0x14 */ } FLASH_TypeDef; #define FLASH_R_BASE (0x40023C00) @@ -598,7 +598,7 @@ void rcc_clk_init2(rcc_sysclk_src sysclk_src, * @param id Clock ID of the peripheral to turn on. */ void rcc_clk_enable(rcc_clk_id id) { - static const __io uint32* enable_regs[] = { + static const __IO uint32* enable_regs[] = { [APB1] = &RCC_BASE->APB1ENR, [APB2] = &RCC_BASE->APB2ENR, [AHB1] = &RCC_BASE->AHB1ENR, @@ -607,7 +607,7 @@ void rcc_clk_enable(rcc_clk_id id) { }; rcc_clk_domain clk_domain = rcc_dev_clk(id); - __io uint32* enr = (__io uint32*)enable_regs[clk_domain]; + __IO uint32* enr = (__IO uint32*)enable_regs[clk_domain]; uint8 lnum = rcc_dev_table[id].line_num; bb_peri_set_bit(enr, lnum, 1); @@ -618,7 +618,7 @@ void rcc_clk_enable(rcc_clk_id id) { * @param id Clock ID of the peripheral to turn on. */ void rcc_clk_disable(rcc_clk_id id) { - static const __io uint32* enable_regs[] = { + static const __IO uint32* enable_regs[] = { [APB1] = &RCC_BASE->APB1ENR, [APB2] = &RCC_BASE->APB2ENR, [AHB1] = &RCC_BASE->AHB1ENR, @@ -627,7 +627,7 @@ void rcc_clk_disable(rcc_clk_id id) { }; rcc_clk_domain clk_domain = rcc_dev_clk(id); - __io uint32* enr = (__io uint32*)enable_regs[clk_domain]; + __IO uint32* enr = (__IO uint32*)enable_regs[clk_domain]; uint8 lnum = rcc_dev_table[id].line_num; bb_peri_set_bit(enr, lnum, 0); @@ -638,7 +638,7 @@ void rcc_clk_disable(rcc_clk_id id) { * @param id Clock ID of the peripheral to reset. */ void rcc_reset_dev(rcc_clk_id id) { - static const __io uint32* reset_regs[] = { + static const __IO uint32* reset_regs[] = { [APB1] = &RCC_BASE->APB1RSTR, [APB2] = &RCC_BASE->APB2RSTR, [AHB1] = &RCC_BASE->AHB1RSTR, @@ -647,7 +647,7 @@ void rcc_reset_dev(rcc_clk_id id) { }; rcc_clk_domain clk_domain = rcc_dev_clk(id); - __io void* addr = (__io void*)reset_regs[clk_domain]; + __IO void* addr = (__IO void*)reset_regs[clk_domain]; uint8 lnum = rcc_dev_table[id].line_num; bb_peri_set_bit(addr, lnum, 1); diff --git a/STM32F4/cores/maple/libmaple/rccF4.h b/STM32F4/cores/maple/libmaple/rccF4.h index 99c5ff2..1558bc8 100644 --- a/STM32F4/cores/maple/libmaple/rccF4.h +++ b/STM32F4/cores/maple/libmaple/rccF4.h @@ -42,36 +42,36 @@ extern "C"{ /** RCC register map type */ typedef struct { - __io uint32 CR; /*!< RCC clock control register, Address offset: 0x00 */ - __io uint32 PLLCFGR; /*!< RCC PLL configuration register, Address offset: 0x04 */ - __io uint32 CFGR; /*!< RCC clock configuration register, Address offset: 0x08 */ - __io uint32 CIR; /*!< RCC clock interrupt register, Address offset: 0x0C */ - __io uint32 AHB1RSTR; /*!< RCC AHB1 peripheral reset register, Address offset: 0x10 */ - __io uint32 AHB2RSTR; /*!< RCC AHB2 peripheral reset register, Address offset: 0x14 */ - __io uint32 AHB3RSTR; /*!< RCC AHB3 peripheral reset register, Address offset: 0x18 */ + __IO uint32 CR; /*!< RCC clock control register, Address offset: 0x00 */ + __IO uint32 PLLCFGR; /*!< RCC PLL configuration register, Address offset: 0x04 */ + __IO uint32 CFGR; /*!< RCC clock configuration register, Address offset: 0x08 */ + __IO uint32 CIR; /*!< RCC clock interrupt register, Address offset: 0x0C */ + __IO uint32 AHB1RSTR; /*!< RCC AHB1 peripheral reset register, Address offset: 0x10 */ + __IO uint32 AHB2RSTR; /*!< RCC AHB2 peripheral reset register, Address offset: 0x14 */ + __IO uint32 AHB3RSTR; /*!< RCC AHB3 peripheral reset register, Address offset: 0x18 */ uint32 RESERVED0; /*!< Reserved, 0x1C */ - __io uint32 APB1RSTR; /*!< RCC APB1 peripheral reset register, Address offset: 0x20 */ - __io uint32 APB2RSTR; /*!< RCC APB2 peripheral reset register, Address offset: 0x24 */ + __IO uint32 APB1RSTR; /*!< RCC APB1 peripheral reset register, Address offset: 0x20 */ + __IO uint32 APB2RSTR; /*!< RCC APB2 peripheral reset register, Address offset: 0x24 */ uint32 RESERVED1[2]; /*!< Reserved, 0x28-0x2C */ - __io uint32 AHB1ENR; /*!< RCC AHB1 peripheral clock register, Address offset: 0x30 */ - __io uint32 AHB2ENR; /*!< RCC AHB2 peripheral clock register, Address offset: 0x34 */ - __io uint32 AHB3ENR; /*!< RCC AHB3 peripheral clock register, Address offset: 0x38 */ + __IO uint32 AHB1ENR; /*!< RCC AHB1 peripheral clock register, Address offset: 0x30 */ + __IO uint32 AHB2ENR; /*!< RCC AHB2 peripheral clock register, Address offset: 0x34 */ + __IO uint32 AHB3ENR; /*!< RCC AHB3 peripheral clock register, Address offset: 0x38 */ uint32 RESERVED2; /*!< Reserved, 0x3C */ - __io uint32 APB1ENR; /*!< RCC APB1 peripheral clock enable register, Address offset: 0x40 */ - __io uint32 APB2ENR; /*!< RCC APB2 peripheral clock enable register, Address offset: 0x44 */ + __IO uint32 APB1ENR; /*!< RCC APB1 peripheral clock enable register, Address offset: 0x40 */ + __IO uint32 APB2ENR; /*!< RCC APB2 peripheral clock enable register, Address offset: 0x44 */ uint32 RESERVED3[2]; /*!< Reserved, 0x48-0x4C */ - __io uint32 AHB1LPENR; /*!< RCC AHB1 peripheral clock enable in low power mode register, Address offset: 0x50 */ - __io uint32 AHB2LPENR; /*!< RCC AHB2 peripheral clock enable in low power mode register, Address offset: 0x54 */ - __io uint32 AHB3LPENR; /*!< RCC AHB3 peripheral clock enable in low power mode register, Address offset: 0x58 */ + __IO uint32 AHB1LPENR; /*!< RCC AHB1 peripheral clock enable in low power mode register, Address offset: 0x50 */ + __IO uint32 AHB2LPENR; /*!< RCC AHB2 peripheral clock enable in low power mode register, Address offset: 0x54 */ + __IO uint32 AHB3LPENR; /*!< RCC AHB3 peripheral clock enable in low power mode register, Address offset: 0x58 */ uint32 RESERVED4; /*!< Reserved, 0x5C */ - __io uint32 APB1LPENR; /*!< RCC APB1 peripheral clock enable in low power mode register, Address offset: 0x60 */ - __io uint32 APB2LPENR; /*!< RCC APB2 peripheral clock enable in low power mode register, Address offset: 0x64 */ + __IO uint32 APB1LPENR; /*!< RCC APB1 peripheral clock enable in low power mode register, Address offset: 0x60 */ + __IO uint32 APB2LPENR; /*!< RCC APB2 peripheral clock enable in low power mode register, Address offset: 0x64 */ uint32 RESERVED5[2]; /*!< Reserved, 0x68-0x6C */ - __io uint32 BDCR; /*!< RCC Backup domain control register, Address offset: 0x70 */ - __io uint32 CSR; /*!< RCC clock control & status register, Address offset: 0x74 */ + __IO uint32 BDCR; /*!< RCC Backup domain control register, Address offset: 0x70 */ + __IO uint32 CSR; /*!< RCC clock control & status register, Address offset: 0x74 */ uint32 RESERVED6[2]; /*!< Reserved, 0x78-0x7C */ - __io uint32 SSCGR; /*!< RCC spread spectrum clock generation register, Address offset: 0x80 */ - __io uint32 PLLI2SCFGR; /*!< RCC PLLI2S configuration register, Address offset: 0x84 */ + __IO uint32 SSCGR; /*!< RCC spread spectrum clock generation register, Address offset: 0x80 */ + __IO uint32 PLLI2SCFGR; /*!< RCC PLLI2S configuration register, Address offset: 0x84 */ } rcc_reg_map; /** RCC register map base pointer */ diff --git a/STM32F4/cores/maple/libmaple/ring_buffer.h b/STM32F4/cores/maple/libmaple/ring_buffer.h index b018522..fbe9f4a 100644 --- a/STM32F4/cores/maple/libmaple/ring_buffer.h +++ b/STM32F4/cores/maple/libmaple/ring_buffer.h @@ -81,7 +81,7 @@ static inline void rb_init(ring_buffer *rb, uint16 size, uint8 *buf) { * @param rb Buffer whose elements to count. */ static inline uint16 rb_full_count(ring_buffer *rb) { - __io ring_buffer *arb = rb; + __IO ring_buffer *arb = rb; int32 size = arb->tail - arb->head; if (arb->tail < arb->head) { size += arb->size + 1; diff --git a/STM32F4/cores/maple/libmaple/scb.h b/STM32F4/cores/maple/libmaple/scb.h index d9cd8c9..b8c4628 100644 --- a/STM32F4/cores/maple/libmaple/scb.h +++ b/STM32F4/cores/maple/libmaple/scb.h @@ -36,26 +36,26 @@ /** System control block register map type */ typedef struct scb_reg_map { - __io uint32 CPUID; /**< CPU ID Base Register */ - __io uint32 ICSR; /**< Interrupt Control State Register */ - __io uint32 VTOR; /**< Vector Table Offset Register */ - __io uint32 AIRCR; /**< Application Interrupt / Reset Control Register */ - __io uint32 SCR; /**< System Control Register */ - __io uint32 CCR; /**< Configuration Control Register */ - __io uint8 SHP[12]; /**< System Handlers Priority Registers + __IO uint32 CPUID; /**< CPU ID Base Register */ + __IO uint32 ICSR; /**< Interrupt Control State Register */ + __IO uint32 VTOR; /**< Vector Table Offset Register */ + __IO uint32 AIRCR; /**< Application Interrupt / Reset Control Register */ + __IO uint32 SCR; /**< System Control Register */ + __IO uint32 CCR; /**< Configuration Control Register */ + __IO uint8 SHP[12]; /**< System Handlers Priority Registers (4-7, 8-11, 12-15) */ - __io uint32 SHCSR; /**< System Handler Control and State Register */ - __io uint32 CFSR; /**< Configurable Fault Status Register */ - __io uint32 HFSR; /**< Hard Fault Status Register */ - __io uint32 DFSR; /**< Debug Fault Status Register */ - __io uint32 MMFAR; /**< Mem Manage Address Register */ - __io uint32 BFAR; /**< Bus Fault Address Register */ - __io uint32 AFSR; /**< Auxiliary Fault Status Register */ - __io uint32 PFR[2]; /**< Processor Feature Register */ - __io uint32 DFR; /**< Debug Feature Register */ - __io uint32 ADR; /**< Auxiliary Feature Register */ - __io uint32 MMFR[4]; /**< Memory Model Feature Register */ - __io uint32 ISAR[5]; /**< ISA Feature Register */ + __IO uint32 SHCSR; /**< System Handler Control and State Register */ + __IO uint32 CFSR; /**< Configurable Fault Status Register */ + __IO uint32 HFSR; /**< Hard Fault Status Register */ + __IO uint32 DFSR; /**< Debug Fault Status Register */ + __IO uint32 MMFAR; /**< Mem Manage Address Register */ + __IO uint32 BFAR; /**< Bus Fault Address Register */ + __IO uint32 AFSR; /**< Auxiliary Fault Status Register */ + __IO uint32 PFR[2]; /**< Processor Feature Register */ + __IO uint32 DFR; /**< Debug Feature Register */ + __IO uint32 ADR; /**< Auxiliary Feature Register */ + __IO uint32 MMFR[4]; /**< Memory Model Feature Register */ + __IO uint32 ISAR[5]; /**< ISA Feature Register */ } scb_reg_map; /** System control block register map base pointer */ diff --git a/STM32F4/cores/maple/libmaple/sdio.h b/STM32F4/cores/maple/libmaple/sdio.h index f0afaa16..4096224 100644 --- a/STM32F4/cores/maple/libmaple/sdio.h +++ b/STM32F4/cores/maple/libmaple/sdio.h @@ -34,23 +34,23 @@ extern "C"{ // SDIO register map type typedef struct sdio_reg_map { - __io uint32 POWER; // 0x00 - __io uint32 CLKCR; // 0x04 - __io uint32 ARG; // 0x08 - __io uint32 CMD; // 0x0C - __io uint32 RESPCMD; // 0x10 (0x3F) + __IO uint32 POWER; // 0x00 + __IO uint32 CLKCR; // 0x04 + __IO uint32 ARG; // 0x08 + __IO uint32 CMD; // 0x0C + __IO uint32 RESPCMD; // 0x10 (0x3F) const uint32 RESP[4]; // 0x14 - contain the card status, which is part of the received response. - __io uint32 DTIMER; // 0x24 - contains the data timeout period, in card bus clock periods. - __io uint32 DLEN; // 0x28 (0x01FF FFFF) - contains the number of data bytes to be transferred - __io uint32 DCTRL; // 0x2C - __io uint32 DCOUNT; // 0x30 (0x01FF FFFF) - __io uint32 STA; // 0x34 - __io uint32 ICR; // 0x38 - __io uint32 MASK; // 0x3C + __IO uint32 DTIMER; // 0x24 - contains the data timeout period, in card bus clock periods. + __IO uint32 DLEN; // 0x28 (0x01FF FFFF) - contains the number of data bytes to be transferred + __IO uint32 DCTRL; // 0x2C + __IO uint32 DCOUNT; // 0x30 (0x01FF FFFF) + __IO uint32 STA; // 0x34 + __IO uint32 ICR; // 0x38 + __IO uint32 MASK; // 0x3C const uint32 RESERVED1[2]; - __io uint32 FIFOCNT; // 0x48 (0x01FF FFFF) + __IO uint32 FIFOCNT; // 0x48 (0x01FF FFFF) const uint32 RESERVED2[13]; - __io uint32 FIFO; // 0x80 + __IO uint32 FIFO; // 0x80 } sdio_reg_map; #define sdio_dev sdio_reg_map diff --git a/STM32F4/cores/maple/libmaple/spi.h b/STM32F4/cores/maple/libmaple/spi.h index abed68c..3a18a2e 100644 --- a/STM32F4/cores/maple/libmaple/spi.h +++ b/STM32F4/cores/maple/libmaple/spi.h @@ -53,15 +53,15 @@ extern "C" { /** SPI register map type. */ typedef struct spi_reg_map { - __io uint32 CR1; /**< Control register 1 */ - __io uint32 CR2; /**< Control register 2 */ - __io uint32 SR; /**< Status register */ - __io uint32 DR; /**< Data register */ - __io uint32 CRCPR; /**< CRC polynomial register */ - __io uint32 RXCRCR; /**< RX CRC register */ - __io uint32 TXCRCR; /**< TX CRC register */ - __io uint32 I2SCFGR; /**< I2S configuration register */ - __io uint32 I2SPR; /**< I2S prescaler register */ + __IO uint32 CR1; /**< Control register 1 */ + __IO uint32 CR2; /**< Control register 2 */ + __IO uint32 SR; /**< Status register */ + __IO uint32 DR; /**< Data register */ + __IO uint32 CRCPR; /**< CRC polynomial register */ + __IO uint32 RXCRCR; /**< RX CRC register */ + __IO uint32 TXCRCR; /**< TX CRC register */ + __IO uint32 I2SCFGR; /**< I2S configuration register */ + __IO uint32 I2SPR; /**< I2S prescaler register */ } spi_reg_map; /* diff --git a/STM32F4/cores/maple/libmaple/systick.h b/STM32F4/cores/maple/libmaple/systick.h index 6ec3364..8db8ec0 100644 --- a/STM32F4/cores/maple/libmaple/systick.h +++ b/STM32F4/cores/maple/libmaple/systick.h @@ -42,10 +42,10 @@ extern "C"{ /** SysTick register map type */ typedef struct systick_reg_map { - __io uint32 CSR; /**< Control and status register */ - __io uint32 RVR; /**< Reload value register */ - __io uint32 CNT; /**< Current value register ("count") */ - __io uint32 CVR; /**< Calibration value register */ + __IO uint32 CSR; /**< Control and status register */ + __IO uint32 RVR; /**< Reload value register */ + __IO uint32 CNT; /**< Current value register ("count") */ + __IO uint32 CVR; /**< Calibration value register */ } systick_reg_map; /** SysTick register map base pointer */ diff --git a/STM32F4/cores/maple/libmaple/timer.h b/STM32F4/cores/maple/libmaple/timer.h index 79b7d29..4336397 100644 --- a/STM32F4/cores/maple/libmaple/timer.h +++ b/STM32F4/cores/maple/libmaple/timer.h @@ -50,66 +50,66 @@ extern "C"{ /** Advanced control timer register map type */ typedef struct timer_adv_reg_map { - __io uint32 CR1; /**< Control register 1 */ - __io uint32 CR2; /**< Control register 2 */ - __io uint32 SMCR; /**< Slave mode control register */ - __io uint32 DIER; /**< DMA/Interrupt enable register */ - __io uint32 SR; /**< Status register */ - __io uint32 EGR; /**< Event generation register */ - __io uint32 CCMR1; /**< Capture/compare mode register 1 */ - __io uint32 CCMR2; /**< Capture/compare mode register 2 */ - __io uint32 CCER; /**< Capture/compare enable register */ - __io uint32 CNT; /**< Counter */ - __io uint32 PSC; /**< Prescaler */ - __io uint32 ARR; /**< Auto-reload register */ - __io uint32 RCR; /**< Repetition counter register */ - __io uint32 CCR1; /**< Capture/compare register 1 */ - __io uint32 CCR2; /**< Capture/compare register 2 */ - __io uint32 CCR3; /**< Capture/compare register 3 */ - __io uint32 CCR4; /**< Capture/compare register 4 */ - __io uint32 BDTR; /**< Break and dead-time register */ - __io uint32 DCR; /**< DMA control register */ - __io uint32 DMAR; /**< DMA address for full transfer */ + __IO uint32 CR1; /**< Control register 1 */ + __IO uint32 CR2; /**< Control register 2 */ + __IO uint32 SMCR; /**< Slave mode control register */ + __IO uint32 DIER; /**< DMA/Interrupt enable register */ + __IO uint32 SR; /**< Status register */ + __IO uint32 EGR; /**< Event generation register */ + __IO uint32 CCMR1; /**< Capture/compare mode register 1 */ + __IO uint32 CCMR2; /**< Capture/compare mode register 2 */ + __IO uint32 CCER; /**< Capture/compare enable register */ + __IO uint32 CNT; /**< Counter */ + __IO uint32 PSC; /**< Prescaler */ + __IO uint32 ARR; /**< Auto-reload register */ + __IO uint32 RCR; /**< Repetition counter register */ + __IO uint32 CCR1; /**< Capture/compare register 1 */ + __IO uint32 CCR2; /**< Capture/compare register 2 */ + __IO uint32 CCR3; /**< Capture/compare register 3 */ + __IO uint32 CCR4; /**< Capture/compare register 4 */ + __IO uint32 BDTR; /**< Break and dead-time register */ + __IO uint32 DCR; /**< DMA control register */ + __IO uint32 DMAR; /**< DMA address for full transfer */ } timer_adv_reg_map; /** General purpose timer register map type */ typedef struct timer_gen_reg_map { - __io uint32 CR1; /**< Control register 1 */ - __io uint32 CR2; /**< Control register 2 */ - __io uint32 SMCR; /**< Slave mode control register */ - __io uint32 DIER; /**< DMA/Interrupt enable register */ - __io uint32 SR; /**< Status register */ - __io uint32 EGR; /**< Event generation register */ - __io uint32 CCMR1; /**< Capture/compare mode register 1 */ - __io uint32 CCMR2; /**< Capture/compare mode register 2 */ - __io uint32 CCER; /**< Capture/compare enable register */ - __io uint32 CNT; /**< Counter */ - __io uint32 PSC; /**< Prescaler */ - __io uint32 ARR; /**< Auto-reload register */ + __IO uint32 CR1; /**< Control register 1 */ + __IO uint32 CR2; /**< Control register 2 */ + __IO uint32 SMCR; /**< Slave mode control register */ + __IO uint32 DIER; /**< DMA/Interrupt enable register */ + __IO uint32 SR; /**< Status register */ + __IO uint32 EGR; /**< Event generation register */ + __IO uint32 CCMR1; /**< Capture/compare mode register 1 */ + __IO uint32 CCMR2; /**< Capture/compare mode register 2 */ + __IO uint32 CCER; /**< Capture/compare enable register */ + __IO uint32 CNT; /**< Counter */ + __IO uint32 PSC; /**< Prescaler */ + __IO uint32 ARR; /**< Auto-reload register */ const uint32 RESERVED1; /**< Reserved */ - __io uint32 CCR1; /**< Capture/compare register 1 */ - __io uint32 CCR2; /**< Capture/compare register 2 */ - __io uint32 CCR3; /**< Capture/compare register 3 */ - __io uint32 CCR4; /**< Capture/compare register 4 */ + __IO uint32 CCR1; /**< Capture/compare register 1 */ + __IO uint32 CCR2; /**< Capture/compare register 2 */ + __IO uint32 CCR3; /**< Capture/compare register 3 */ + __IO uint32 CCR4; /**< Capture/compare register 4 */ const uint32 RESERVED2; /**< Reserved */ - __io uint32 DCR; /**< DMA control register */ - __io uint32 DMAR; /**< DMA address for full transfer */ + __IO uint32 DCR; /**< DMA control register */ + __IO uint32 DMAR; /**< DMA address for full transfer */ } timer_gen_reg_map; /** Basic timer register map type */ typedef struct timer_bas_reg_map { - __io uint32 CR1; /**< Control register 1 */ - __io uint32 CR2; /**< Control register 2 */ + __IO uint32 CR1; /**< Control register 1 */ + __IO uint32 CR2; /**< Control register 2 */ const uint32 RESERVED1; /**< Reserved */ - __io uint32 DIER; /**< DMA/Interrupt enable register */ - __io uint32 SR; /**< Status register */ - __io uint32 EGR; /**< Event generation register */ + __IO uint32 DIER; /**< DMA/Interrupt enable register */ + __IO uint32 SR; /**< Status register */ + __IO uint32 EGR; /**< Event generation register */ const uint32 RESERVED2; /**< Reserved */ const uint32 RESERVED3; /**< Reserved */ const uint32 RESERVED4; /**< Reserved */ - __io uint32 CNT; /**< Counter */ - __io uint32 PSC; /**< Prescaler */ - __io uint32 ARR; /**< Auto-reload register */ + __IO uint32 CNT; /**< Counter */ + __IO uint32 PSC; /**< Prescaler */ + __IO uint32 ARR; /**< Auto-reload register */ } timer_bas_reg_map; @@ -695,7 +695,7 @@ static inline void timer_set_reload(timer_dev *dev, uint16 arr) { * @param channel Channel whose compare value to get. */ static inline uint16 timer_get_compare(timer_dev *dev, uint8 channel) { - __io uint32 *ccr = &(dev->regs).gen->CCR1 + (channel - 1); + __IO uint32 *ccr = &(dev->regs).gen->CCR1 + (channel - 1); return *ccr; } @@ -708,7 +708,7 @@ static inline uint16 timer_get_compare(timer_dev *dev, uint8 channel) { static inline void timer_set_compare(timer_dev *dev, uint8 channel, uint16 value) { - __io uint32 *ccr = &(dev->regs).gen->CCR1 + (channel - 1); + __IO uint32 *ccr = &(dev->regs).gen->CCR1 + (channel - 1); *ccr = value; } @@ -999,7 +999,7 @@ static inline void timer_oc_set_mode(timer_dev *dev, //uint8 bit1 = (channel >> 1) & 1; // original uint8 bit1 = ((channel-1) >> 1) & 1; // fixed /* channel == 1,2 -> CCMR1; channel == 3,4 -> CCMR2 */ - __io uint32 *ccmr = &(dev->regs).gen->CCMR1 + bit1; + __IO uint32 *ccmr = &(dev->regs).gen->CCMR1 + bit1; /* channel == 1,3 -> shift = 0, channel == 2,4 -> shift = 8 */ uint8 shift = 8 * (1 - bit0); diff --git a/STM32F4/cores/maple/libmaple/usart.h b/STM32F4/cores/maple/libmaple/usart.h index 282293a..fddb5f2 100644 --- a/STM32F4/cores/maple/libmaple/usart.h +++ b/STM32F4/cores/maple/libmaple/usart.h @@ -52,13 +52,13 @@ extern "C"{ /** USART register map type */ typedef struct usart_reg_map { - __io uint32 SR; /**< Status register */ - __io uint32 DR; /**< Data register */ - __io uint32 BRR; /**< Baud rate register */ - __io uint32 CR1; /**< Control register 1 */ - __io uint32 CR2; /**< Control register 2 */ - __io uint32 CR3; /**< Control register 3 */ - __io uint32 GTPR; /**< Guard time and prescaler register */ + __IO uint32 SR; /**< Status register */ + __IO uint32 DR; /**< Data register */ + __IO uint32 BRR; /**< Baud rate register */ + __IO uint32 CR1; /**< Control register 1 */ + __IO uint32 CR2; /**< Control register 2 */ + __IO uint32 CR3; /**< Control register 3 */ + __IO uint32 GTPR; /**< Guard time and prescaler register */ } usart_reg_map; /** USART1 register map base pointer */ diff --git a/STM32F4/libraries/RTClock/src/RTClock.h b/STM32F4/libraries/RTClock/src/RTClock.h index c13bf5f..e5b788d 100644 --- a/STM32F4/libraries/RTClock/src/RTClock.h +++ b/STM32F4/libraries/RTClock/src/RTClock.h @@ -45,26 +45,26 @@ static const unsigned char monthDays[]={31,28,31,30,31,30,31,31,30,31,30,31}; / typedef struct rtc_reg_map { - __io uint32 TR; /**< Time register */ - __io uint32 DR; /**< Date register */ - __io uint32 CR; /**< Control register */ - __io uint32 ISR; /**< Init Status register */ - __io uint32 PRER; /**< Prescaler register */ - __io uint32 WUTR; /**< Wakeup Timer register */ - __io uint32 CALIBR; /**< Calibration register */ - __io uint32 ALRMAR; /**< Alarm A register */ - __io uint32 ALRMBR; /**< Alarm B register */ - __io uint32 WPR; /**< Write Protect register */ - __io uint32 SSR; /**< SubSecond register */ - __io uint32 SHIFTR; /**< Shift Control register */ - __io uint32 TSTR; /**< TimeStamp Time register */ - __io uint32 TSDR; /**< TimeStamp Date register */ - __io uint32 TSSSR; /**< TimeStamp SubSecond register */ - __io uint32 CALR; /**< Calibration register */ - __io uint32 TAFCR; /**< Tamper and Alternate Function Config register */ - __io uint32 ALRMASSR; /**< Alarm A subSecond register */ - __io uint32 ALRMBSSR; /**< Alarm B subSecond register */ - __io uint32 BKPxR; /**< Backup registers */ + __IO uint32 TR; /**< Time register */ + __IO uint32 DR; /**< Date register */ + __IO uint32 CR; /**< Control register */ + __IO uint32 ISR; /**< Init Status register */ + __IO uint32 PRER; /**< Prescaler register */ + __IO uint32 WUTR; /**< Wakeup Timer register */ + __IO uint32 CALIBR; /**< Calibration register */ + __IO uint32 ALRMAR; /**< Alarm A register */ + __IO uint32 ALRMBR; /**< Alarm B register */ + __IO uint32 WPR; /**< Write Protect register */ + __IO uint32 SSR; /**< SubSecond register */ + __IO uint32 SHIFTR; /**< Shift Control register */ + __IO uint32 TSTR; /**< TimeStamp Time register */ + __IO uint32 TSDR; /**< TimeStamp Date register */ + __IO uint32 TSSSR; /**< TimeStamp SubSecond register */ + __IO uint32 CALR; /**< Calibration register */ + __IO uint32 TAFCR; /**< Tamper and Alternate Function Config register */ + __IO uint32 ALRMASSR; /**< Alarm A subSecond register */ + __IO uint32 ALRMBSSR; /**< Alarm B subSecond register */ + __IO uint32 BKPxR; /**< Backup registers */ } rtc_reg_map; /** RTC register map base pointer */ diff --git a/tools/win/dfu-util-0.9-win64/dfu-prefix.exe b/tools/win/dfu-util-0.9-win64/dfu-prefix.exe index 5ae088804979feab4339592abc9c90e694d2b516..11a60c1447c61e7b2633107b3fce693755589a5b 100644 GIT binary patch delta 65 zcmX^6h3o7Wt_@MSOrHMDF}d4gav4|p0NK;ocQHBx>Fqwd7?l}8jKbZFd)|W>`m33A MctDKU?Mxq-07ust0{{R3 delta 65 zcmX^6h3o7Wt_@MSOqu!3F}d4gav4|p0NK;ocQHBx>Fqwd7?l}8jKbZFd)|W>`m33A MctDKU?Mxq-0Cg7`g8%>k diff --git a/tools/win/dfu-util-0.9-win64/dfu-suffix.exe b/tools/win/dfu-util-0.9-win64/dfu-suffix.exe index e54eb25d97c6508377c8c808a261e98292560a02..1357b06a3e8d7b978019903b83eecd2adfedae20 100644 GIT binary patch delta 74 zcmX@}gX_!>t_@N7OrHMDG5OnL@)_s)0NK-j?`Cuc(%T*OFe)>0c={*Brt_@N7Oqu!3G5OnL@)_s)0NK-j?`Cuc(%T*OFe)>0WacNur?XYc delta 103 zcmZ4TKyb+e!3`QWnKJX6wQja+-DKRZb(6`78OWcWcZbQDBQrlKKCLt_d3tRai`?|< ucbNXeg(e#|E4AHY+IEk5XDv|u_TAAe8Uma!4Ghx*UNA~*XUSnvU;zNDtSCJI diff --git a/tools/win/dfu-util-0.9-win64/libusb-1.0.dll b/tools/win/dfu-util-0.9-win64/libusb-1.0.dll index c8d77172b4c60ae807aaaafd5391acd0066d43c8..d0f1cd78a8983c09f7101db8f5ffc40ad3a8bad3 100644 GIT binary patch delta 85 zcmbRIS8eiNwT2ePElj((m^}U4_i!-*F*6Xe05R+KJzQ+1K0t}-#^G%5K?+nN*npTF ch&i^aL~!PW00p;CTElso7sQC)#c9F<0228eivR!s delta 85 zcmbRIS8eiNwT2ePElj((m@@O*_i!-*F*6Xe05R+KJzQ+1K0t}-#^G%5K?+nN*npTF ch&i^aL~!PW00p;CTElso7sQC)#c9F<06$qB%K!iX diff --git a/tools/win/dfu-util.exe b/tools/win/dfu-util.exe index f735c03f30bcfa8e55361a883b2bb9e94239119e..3ba993938a7f899e80737efda8a38748bcf65ceb 100644 GIT binary patch delta 52 zcmdnl;I^~Dt)Ydng{g(Pg{6hHg{_6Xg`|Lw0U H1pU|n*+UVB delta 52 zcmdnl;I^~Dt)Ydng{g(Pg{6hHg{_6Xg`eFnRiKe_+C_a32733kfU$ delta 24 ecmZozAeFlFX%e_+C_a3274>j`WC diff --git a/tools/win/stm32flash.exe b/tools/win/stm32flash.exe index 911c0cc058b8b9d40cb95e9d83223b998c9f673a..f5cc7eb840a962454df4c3eedda0968cb02b46c2 100644 GIT binary patch delta 22 ccmZp8%-H}$EsR^3rlv7@`fs0}#`Ka40Baiv(f|Me delta 22 ccmZp8%-H}$EsR^3rlv7v=5L>##`Ka40BrjS5&!@I From 37907052efe8f3a5a3f81ad03f9e2cc593bbf9db Mon Sep 17 00:00:00 2001 From: aster94 Date: Thu, 25 Jan 2018 15:20:34 +0100 Subject: [PATCH 270/351] Add files via upload --- tools/win/dfu-util-0.9-win64/dfu-prefix.exe | Bin 178765 -> 178765 bytes tools/win/dfu-util-0.9-win64/dfu-suffix.exe | Bin 179276 -> 179276 bytes .../dfu-util-0.9-win64/dfu-util-static.exe | Bin 799602 -> 799602 bytes tools/win/dfu-util-0.9-win64/dfu-util.exe | Bin 290852 -> 290852 bytes tools/win/dfu-util-0.9-win64/libusb-1.0.dll | Bin 638611 -> 638611 bytes 5 files changed, 0 insertions(+), 0 deletions(-) diff --git a/tools/win/dfu-util-0.9-win64/dfu-prefix.exe b/tools/win/dfu-util-0.9-win64/dfu-prefix.exe index 11a60c1447c61e7b2633107b3fce693755589a5b..5ae088804979feab4339592abc9c90e694d2b516 100644 GIT binary patch delta 65 zcmX^6h3o7Wt_@MSOqu!3F}d4gav4|p0NK;ocQHBx>Fqwd7?l}8jKbZFd)|W>`m33A MctDKU?Mxq-0Cg7`g8%>k delta 65 zcmX^6h3o7Wt_@MSOrHMDF}d4gav4|p0NK;ocQHBx>Fqwd7?l}8jKbZFd)|W>`m33A MctDKU?Mxq-07ust0{{R3 diff --git a/tools/win/dfu-util-0.9-win64/dfu-suffix.exe b/tools/win/dfu-util-0.9-win64/dfu-suffix.exe index 1357b06a3e8d7b978019903b83eecd2adfedae20..e54eb25d97c6508377c8c808a261e98292560a02 100644 GIT binary patch delta 74 zcmX@}gX_!>t_@N7Oqu!3G5OnL@)_s)0NK-j?`Cuc(%T*OFe)>0WacNurt_@N7OrHMDG5OnL@)_s)0NK-j?`Cuc(%T*OFe)>0c={*Br?XYc diff --git a/tools/win/dfu-util-0.9-win64/libusb-1.0.dll b/tools/win/dfu-util-0.9-win64/libusb-1.0.dll index d0f1cd78a8983c09f7101db8f5ffc40ad3a8bad3..c8d77172b4c60ae807aaaafd5391acd0066d43c8 100644 GIT binary patch delta 85 zcmbRIS8eiNwT2ePElj((m@@O*_i!-*F*6Xe05R+KJzQ+1K0t}-#^G%5K?+nN*npTF ch&i^aL~!PW00p;CTElso7sQC)#c9F<06$qB%K!iX delta 85 zcmbRIS8eiNwT2ePElj((m^}U4_i!-*F*6Xe05R+KJzQ+1K0t}-#^G%5K?+nN*npTF ch&i^aL~!PW00p;CTElso7sQC)#c9F<0228eivR!s From 3e1adc26625d24842aaf8ef01b8c469265364b12 Mon Sep 17 00:00:00 2001 From: aster94 Date: Thu, 25 Jan 2018 15:22:03 +0100 Subject: [PATCH 271/351] Add files via upload --- tools/win/dfu-util.exe | Bin 1146937 -> 1146937 bytes tools/win/stm32flash.exe | Bin 160128 -> 160128 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/tools/win/dfu-util.exe b/tools/win/dfu-util.exe index 3ba993938a7f899e80737efda8a38748bcf65ceb..f735c03f30bcfa8e55361a883b2bb9e94239119e 100644 GIT binary patch delta 52 zcmdnl;I^~Dt)Ydng{g(Pg{6hHg{_6Xg`|Lw0U H1pU|n*+UVB diff --git a/tools/win/stm32flash.exe b/tools/win/stm32flash.exe index f5cc7eb840a962454df4c3eedda0968cb02b46c2..911c0cc058b8b9d40cb95e9d83223b998c9f673a 100644 GIT binary patch delta 22 ccmZp8%-H}$EsR^3rlv7v=5L>##`Ka40BrjS5&!@I delta 22 ccmZp8%-H}$EsR^3rlv7@`fs0}#`Ka40Baiv(f|Me From eede5aba0e8b89ec86326edc731b1bd33d4e85ca Mon Sep 17 00:00:00 2001 From: aster94 Date: Thu, 25 Jan 2018 15:24:53 +0100 Subject: [PATCH 272/351] Add files via upload --- tools/win/stlink/ST-LINK_CLI.exe | Bin 267264 -> 267264 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tools/win/stlink/ST-LINK_CLI.exe b/tools/win/stlink/ST-LINK_CLI.exe index 99fca9b28f7863603f783377baaae36214c4b04c..a9452e81a9912d5ce15d250f2c687c33f031bb62 100644 GIT binary patch delta 24 ecmZozAeFlFX%e_+C_a3274>j`WC delta 24 ecmZozAeFnRiKe_+C_a32733kfU$ From 4b6a6e8077e9471a612db51d979628f63660b929 Mon Sep 17 00:00:00 2001 From: Ken Willmott Date: Wed, 31 Jan 2018 08:38:14 -0500 Subject: [PATCH 273/351] Update BluePill-RTClock-test.ino Clarify English documentation by changing all occurrences of "10 bits" to "10 digits", referring to Epoch time. --- .../BluePill-RTClock-test/BluePill-RTClock-test.ino | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino b/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino index d49025a..397b72d 100644 --- a/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino +++ b/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino @@ -8,12 +8,12 @@ 3. Serial output on(41s) or off(21s) by creatAlarm 4. change to your timezone in the sketch; . 3. get Unix epoch time from https://www.epochconverter.com/ ; - 4. last step input the 10 bits number( example: 1503945555) to Serialport ; + 4. last step input the 10 digit number( example: 1503945555) to Serialport ; 5. the clock will be reset to you wanted. - ## Why the 10 bits Unix epoch time be used? + ## Why the 10 digit Unix epoch time be used? ****Because I wanna connect to NTP server by ESP-8266. -****in the library. getNtpTime() will return this 10 bits Unix epoch time. +****in the library. getNtpTime() will return this 10 digit Unix epoch time. * * å—¨ï¼æœ‹å‹ä»¬ï¼Œ 这是一个STM32F10x系列的RTC应用的例å­ï¼Œå¸Œæœ›å¯¹ä½ çš„ç¼–ç æœ‰æ‰€å¸®åŠ© * 这个程åºåŸºäºŽhttps://github.com/rogerclarkmelbourne/Arduino_STM32 , 感谢所有贡献者的付出。 From 42a5e9f9073e1f3b2a479abc4145a32b8e8c9339 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Fri, 2 Feb 2018 09:16:51 +1100 Subject: [PATCH 274/351] Update BOARD_NR_GPIO_PINS for STM32F103V This fixes problem caused by https://github.com/rogerclarkmelbourne/Arduino_STM32/commit/951d0acf178b28d52919fb777874d90603c88883#diff-3df511e94e3cba57d187bb1322b9f6c6 --- STM32F1/variants/generic_stm32f103v/board/board.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/STM32F1/variants/generic_stm32f103v/board/board.h b/STM32F1/variants/generic_stm32f103v/board/board.h index ccd5ecf..e4bd089 100644 --- a/STM32F1/variants/generic_stm32f103v/board/board.h +++ b/STM32F1/variants/generic_stm32f103v/board/board.h @@ -90,8 +90,9 @@ #define BOARD_SPI3_MOSI_PIN PB5 -/* GPIO A to E = 5 * 16 - BOOT1 not used = 79*/ -#define BOARD_NR_GPIO_PINS 79 +/* GPIO A to E = 5 * 16 = 80*/ +/* value is now 80 as boo1 was added via PR to the pinmap but this value was not increased*/ +#define BOARD_NR_GPIO_PINS 80 /* Note: NOT 19. The missing one is D38 a.k.a. BOARD_BUTTON_PIN, which * isn't broken out to a header and is thus unusable for PWM. */ #define BOARD_NR_PWM_PINS 19 From 35e0a6453a845acf22ec6e6d6e09a630bb3232e9 Mon Sep 17 00:00:00 2001 From: Jiri Bilek Date: Sat, 3 Feb 2018 13:15:56 +0100 Subject: [PATCH 275/351] Fixing now() function The now() function was defined using the #define directive. That is wrong as it prevents using the keyword "now" in other situations. --- STM32F1/libraries/RTClock/src/RTClock.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/STM32F1/libraries/RTClock/src/RTClock.h b/STM32F1/libraries/RTClock/src/RTClock.h index 1988c9e..a3ff653 100755 --- a/STM32F1/libraries/RTClock/src/RTClock.h +++ b/STM32F1/libraries/RTClock/src/RTClock.h @@ -52,7 +52,9 @@ class RTClock { time_t getTime(); void getTime(tm_t & tmm ); - #define now getTime + + time_t now() { return getTime(); } + void now(tm_t & tmm ) { getTime(tmm); } // non-standard use of now() function, added for compatibility with previous versions of the library uint8_t year(void) { getTime(tmm); return tmm.year; } uint8_t month(void) { getTime(tmm); return tmm.month; } @@ -100,4 +102,4 @@ class RTClock { #endif // _RTCLOCK_H_ - \ No newline at end of file + From 85e0c9b602e2c5b86a7fe25cc159c9f05dc2f089 Mon Sep 17 00:00:00 2001 From: Jiri Bilek Date: Sat, 3 Feb 2018 13:41:59 +0100 Subject: [PATCH 276/351] Fixing now() in RTClock.h in STMF4 library --- STM32F4/libraries/RTClock/src/RTClock.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/STM32F4/libraries/RTClock/src/RTClock.h b/STM32F4/libraries/RTClock/src/RTClock.h index c13bf5f..27597a5 100644 --- a/STM32F4/libraries/RTClock/src/RTClock.h +++ b/STM32F4/libraries/RTClock/src/RTClock.h @@ -184,7 +184,9 @@ class RTClock { time_t getTime(); void getTime(tm_t & tm); - #define now getTime + + time_t now() { return getTime(); } + void now(tm_t & tmm ) { getTime(tmm); } // non-standard use of now() function, added for compatibility with previous versions of the library uint8_t year(void) { getTime(tm); return tm.year; } uint8_t month(void) { getTime(tm); return tm.month; } From 5f6c8ef670e99a2fc04a599bd1e00642efef9321 Mon Sep 17 00:00:00 2001 From: Jiri Bilek Date: Sat, 3 Feb 2018 14:07:05 +0100 Subject: [PATCH 277/351] Fixed indentation --- STM32F1/libraries/RTClock/src/RTClock.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/libraries/RTClock/src/RTClock.h b/STM32F1/libraries/RTClock/src/RTClock.h index a3ff653..a225c94 100755 --- a/STM32F1/libraries/RTClock/src/RTClock.h +++ b/STM32F1/libraries/RTClock/src/RTClock.h @@ -53,7 +53,7 @@ class RTClock { time_t getTime(); void getTime(tm_t & tmm ); - time_t now() { return getTime(); } + time_t now() { return getTime(); } void now(tm_t & tmm ) { getTime(tmm); } // non-standard use of now() function, added for compatibility with previous versions of the library uint8_t year(void) { getTime(tmm); return tmm.year; } From 771be821c288f74f4106768aca0042d05c0d038d Mon Sep 17 00:00:00 2001 From: victorpv Date: Wed, 20 Dec 2017 18:44:58 -0600 Subject: [PATCH 278/351] Hardware serial corrections --- STM32F1/cores/maple/HardwareSerial.cpp | 2 +- STM32F1/cores/maple/HardwareSerial.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/STM32F1/cores/maple/HardwareSerial.cpp b/STM32F1/cores/maple/HardwareSerial.cpp index 024efbc..fe73339 100644 --- a/STM32F1/cores/maple/HardwareSerial.cpp +++ b/STM32F1/cores/maple/HardwareSerial.cpp @@ -187,7 +187,7 @@ int HardwareSerial::availableForWrite(void) return 1; } -size_t HardwareSerial::write(unsigned char ch) { +size_t HardwareSerial::write(uint8_t ch) { usart_putc(this->usart_device, ch); return 1; diff --git a/STM32F1/cores/maple/HardwareSerial.h b/STM32F1/cores/maple/HardwareSerial.h index b8b8dd6..108d525 100644 --- a/STM32F1/cores/maple/HardwareSerial.h +++ b/STM32F1/cores/maple/HardwareSerial.h @@ -138,7 +138,7 @@ public: virtual int read(void); int availableForWrite(void); virtual void flush(void); - virtual size_t write(uint8_t); + virtual size_t write(uint8_t ch); inline size_t write(unsigned long n) { return write((uint8_t)n); } inline size_t write(long n) { return write((uint8_t)n); } inline size_t write(unsigned int n) { return write((uint8_t)n); } From 36bd1be38738b9e8bd857ee4e1ef6c06d38298ec Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Sat, 10 Feb 2018 14:47:33 +1100 Subject: [PATCH 279/351] Added Timer 'Input Capture' support and example --- STM32F1/cores/maple/libmaple/timer.c | 10 ++- .../HardwareTimerInputCapture.ino | 68 +++++++++++++++++++ .../system/libmaple/include/libmaple/timer.h | 4 +- .../libmaple/stm32f1/include/series/gpio.h | 3 +- 4 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 STM32F1/libraries/A_STM32_Examples/examples/Sensors/HardwareTimerInputCapture/HardwareTimerInputCapture.ino diff --git a/STM32F1/cores/maple/libmaple/timer.c b/STM32F1/cores/maple/libmaple/timer.c index 70e2065..4c972fe 100644 --- a/STM32F1/cores/maple/libmaple/timer.c +++ b/STM32F1/cores/maple/libmaple/timer.c @@ -39,6 +39,7 @@ static void disable_channel(timer_dev *dev, uint8 channel); static void pwm_mode(timer_dev *dev, uint8 channel); static void output_compare_mode(timer_dev *dev, uint8 channel); static void encoder_mode(timer_dev *dev, uint8 channel) ;//CARLOS +static void input_capture_mode(timer_dev *dev, uint8 channel);//@Cesco static inline void enable_irq(timer_dev *dev, timer_interrupt_id iid); @@ -236,6 +237,9 @@ void timer_set_mode(timer_dev *dev, uint8 channel, timer_mode mode) { case TIMER_ENCODER: encoder_mode(dev, channel); //find a way to pass all the needed stuff on the 8bit var break; + case TIMER_INPUT_CAPTURE:// code from @Cesco + input_capture_mode(dev, channel); + break; } } @@ -349,7 +353,11 @@ static void encoder_mode(timer_dev *dev, uint8 channel __attribute__((unused))) timer_resume(dev); } - +// Code supplied by @Cesco (on the forum) +static void input_capture_mode(timer_dev *dev, uint8 channel) { + timer_oc_set_mode(dev, channel, 0, TIMER_CCMR_CCS_INPUT_TI1); + timer_cc_enable(dev, channel); +} static void enable_adv_irq(timer_dev *dev, timer_interrupt_id id); static void enable_bas_gen_irq(timer_dev *dev); diff --git a/STM32F1/libraries/A_STM32_Examples/examples/Sensors/HardwareTimerInputCapture/HardwareTimerInputCapture.ino b/STM32F1/libraries/A_STM32_Examples/examples/Sensors/HardwareTimerInputCapture/HardwareTimerInputCapture.ino new file mode 100644 index 0000000..e628d69 --- /dev/null +++ b/STM32F1/libraries/A_STM32_Examples/examples/Sensors/HardwareTimerInputCapture/HardwareTimerInputCapture.ino @@ -0,0 +1,68 @@ +/* Example of the Timer Input Capture mode + * + * Thanks to @cesco on the stm32duino.com + * + * This example uses Timer2. Other timers also support this mode, bnt on the F103C + * only Timer 2 has usable external trigger pins. PA0 and PA15 + * Because the only other usable pin on the F103C is one of the USB pins. + * + * Upload to your favourite F103Cx + * Open the Serial plotter + * Put your finger on either PA0 or PA15 (depenidng whether you USE the pin remapping) + * + * Observe your local mains frequency in terms of pulse width time. + * + */ + +/* Timer2 external trigger can be ether PA0 or PA15. + To use use afio_remap(FIO_REMAP_TIM2_PARTIAL_1) or afio_remap(AFIO_REMAP_TIM2_FULL) + Note. using afio_remap also changes the pins used by Timer2 CH1,CH2,CH3 amd CH4 + * See page 184 of the STM32F10x Refernce manual (PDF downloadable from ST.com + */ + +//#define USE_REMAP_PIN +#ifdef USE_REMAP_PIN +const int timer2ExternalTriggerPin = PA15; +#else +const int timer2ExternalTriggerPin = PA0; +#endif + +volatile boolean hasCapture; +volatile uint16_t captureValue; +volatile uint16_t lastCaptureValue=0; +volatile uint16_t captureDifference=0; + +void captureCallback(void) { + + hasCapture=true; + captureValue = Timer2.getCompare(1); + captureDifference = captureValue-lastCaptureValue; + lastCaptureValue=captureValue; +} + +void setup() { + + pinMode(timer2ExternalTriggerPin,INPUT); + + #ifdef USE_REMAP_PIN + afio_remap(AFIO_REMAP_TIM2_PARTIAL_1); + #endif + + hasCapture = false; + + Timer2.setPrescaleFactor(72); // prescaler to count 72,000,000 / 72 counts per second. i.e count microseconds + Timer2.setMode(TIMER_CH1, TIMER_INPUT_CAPTURE); + Timer2.attachCompare1Interrupt(captureCallback); + +} + +void loop() { + + // Printing inside the callback is not a good idea. + // Hence the capture callback sets a flag , which is detected here + if (hasCapture) + { + Serial.println(captureDifference); + hasCapture=false; + } +} \ No newline at end of file diff --git a/STM32F1/system/libmaple/include/libmaple/timer.h b/STM32F1/system/libmaple/include/libmaple/timer.h index 64f458f..c915f4e 100644 --- a/STM32F1/system/libmaple/include/libmaple/timer.h +++ b/STM32F1/system/libmaple/include/libmaple/timer.h @@ -564,13 +564,15 @@ typedef enum timer_mode { * values, the corresponding interrupt is fired. */ TIMER_OUTPUT_COMPARE, - /* TIMER_INPUT_CAPTURE, TODO: In this mode, the timer can measure the + + /* TIMER_INPUT_CAPTURE, UNDER DEVELOPMENT: In this mode, the timer can measure the * pulse lengths of input signals */ /* TIMER_ONE_PULSE, TODO: In this mode, the timer can generate a single * pulse on a GPIO pin for a specified amount of * time. */ TIMER_ENCODER, //CARLOS Change + TIMER_INPUT_CAPTURE,// code from @cesco } timer_mode; /** Timer channel numbers */ diff --git a/STM32F1/system/libmaple/stm32f1/include/series/gpio.h b/STM32F1/system/libmaple/stm32f1/include/series/gpio.h index aff639b..a20c021 100644 --- a/STM32F1/system/libmaple/stm32f1/include/series/gpio.h +++ b/STM32F1/system/libmaple/stm32f1/include/series/gpio.h @@ -351,7 +351,8 @@ typedef enum afio_remap_peripheral { * Timer 2 partial remapping 2 (CH1 and ETR on PA0, CH2 on PA1, * CH3 on PB10, CH4 on PB11) */ AFIO_REMAP_TIM2_PARTIAL_2 = AFIO_MAPR_TIM2_REMAP_PA0_PA1_PB10_PB11, - /** Timer 2 full remapping */ + /** Timer 2 full remapping + (CH1/ETR/PA15, CH2/PB3, CH3/PB10, CH4/PB11) */ AFIO_REMAP_TIM2_FULL = AFIO_MAPR_TIM2_REMAP_FULL, /** USART 3 part remapping */ AFIO_REMAP_USART3_PARTIAL = AFIO_MAPR_USART3_REMAP_PARTIAL, From 66092e6e39648f1800011c84b9219d2a4fff8abe Mon Sep 17 00:00:00 2001 From: stevstrong Date: Sat, 10 Feb 2018 18:45:03 +0100 Subject: [PATCH 280/351] Update timer.h corrected mask for OCxM bits in CCMR1/2 registers (see RM0008 rev.16 p. 413) --- STM32F1/system/libmaple/include/libmaple/timer.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/STM32F1/system/libmaple/include/libmaple/timer.h b/STM32F1/system/libmaple/include/libmaple/timer.h index c915f4e..3d91a2d 100644 --- a/STM32F1/system/libmaple/include/libmaple/timer.h +++ b/STM32F1/system/libmaple/include/libmaple/timer.h @@ -387,7 +387,7 @@ extern timer_dev timer14; #define TIMER_CCMR1_OC1FE_BIT 2 #define TIMER_CCMR1_OC2CE (1U << TIMER_CCMR1_OC2CE_BIT) -#define TIMER_CCMR1_OC2M (0x3 << 12) +#define TIMER_CCMR1_OC2M (0x7 << 12) #define TIMER_CCMR1_IC2F (0xF << 12) #define TIMER_CCMR1_OC2PE (1U << TIMER_CCMR1_OC2PE_BIT) #define TIMER_CCMR1_OC2FE (1U << TIMER_CCMR1_OC2FE_BIT) @@ -398,7 +398,7 @@ extern timer_dev timer14; #define TIMER_CCMR1_CC2S_INPUT_TI1 (0x2 << 8) #define TIMER_CCMR1_CC2S_INPUT_TRC (0x3 << 8) #define TIMER_CCMR1_OC1CE (1U << TIMER_CCMR1_OC1CE_BIT) -#define TIMER_CCMR1_OC1M (0x3 << 4) +#define TIMER_CCMR1_OC1M (0x7 << 4) #define TIMER_CCMR1_IC1F (0xF << 4) #define TIMER_CCMR1_OC1PE (1U << TIMER_CCMR1_OC1PE_BIT) #define TIMER_CCMR1_OC1FE (1U << TIMER_CCMR1_OC1FE_BIT) @@ -419,7 +419,7 @@ extern timer_dev timer14; #define TIMER_CCMR2_OC3FE_BIT 2 #define TIMER_CCMR2_OC4CE (1U << TIMER_CCMR2_OC4CE_BIT) -#define TIMER_CCMR2_OC4M (0x3 << 12) +#define TIMER_CCMR2_OC4M (0x7 << 12) #define TIMER_CCMR2_IC4F (0xF << 12) #define TIMER_CCMR2_OC4PE (1U << TIMER_CCMR2_OC4PE_BIT) #define TIMER_CCMR2_OC4FE (1U << TIMER_CCMR2_OC4FE_BIT) @@ -430,7 +430,7 @@ extern timer_dev timer14; #define TIMER_CCMR2_CC4S_INPUT_TI2 (TIMER_CCMR_CCS_INPUT_TI2 << 8) #define TIMER_CCMR2_CC4S_INPUT_TRC (TIMER_CCMR_CCS_INPUT_TRC << 8) #define TIMER_CCMR2_OC3CE (1U << TIMER_CCMR2_OC3CE_BIT) -#define TIMER_CCMR2_OC3M (0x3 << 4) +#define TIMER_CCMR2_OC3M (0x7 << 4) #define TIMER_CCMR2_IC3F (0xF << 4) #define TIMER_CCMR2_OC3PE (1U << TIMER_CCMR2_OC3PE_BIT) #define TIMER_CCMR2_OC3FE (1U << TIMER_CCMR2_OC3FE_BIT) From c6ef07affed27af470504f5cf85f248f3c781ef1 Mon Sep 17 00:00:00 2001 From: Ken Willmott Date: Sat, 10 Feb 2018 18:52:15 -0500 Subject: [PATCH 281/351] Update rtc_util.c Modify rtc_get_count() and rtc_get_divider() to fix non-atomic accesses to RTC counter registers --- STM32F1/libraries/RTClock/src/utility/rtc_util.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/STM32F1/libraries/RTClock/src/utility/rtc_util.c b/STM32F1/libraries/RTClock/src/utility/rtc_util.c index 3c8b7d5..c730ba1 100644 --- a/STM32F1/libraries/RTClock/src/utility/rtc_util.c +++ b/STM32F1/libraries/RTClock/src/utility/rtc_util.c @@ -182,8 +182,10 @@ void rtc_set_count(uint32 value) { rtc_wait_sync(); rtc_wait_finished(); rtc_enter_config_mode(); - RTC->regs->CNTH = (value >> 16) & 0xffff; - RTC->regs->CNTL = value & 0xffff; + do { + h = RTC->regs->CNTH & 0xffff; + l = RTC->regs->CNTL & 0xffff; + } while (h ^ (RTC->regs->CNTH & 0xffff)); rtc_exit_config_mode(); rtc_wait_finished(); } @@ -211,8 +213,10 @@ uint32 rtc_get_divider() { rtc_clear_sync(); rtc_wait_sync(); rtc_wait_finished(); - h = RTC->regs->DIVH & 0x000f; - l = RTC->regs->DIVL & 0xffff; + do { + h = RTC->regs->DIVH & 0x000f; + l = RTC->regs->DIVL & 0xffff; + } while (h ^ (RTC->regs->DIVH & 0x000f)); return (h << 16) | l; } @@ -229,4 +233,4 @@ void rtc_set_alarm(uint32 value) { RTC->regs->ALRL = value & 0xffff; rtc_exit_config_mode(); rtc_wait_finished(); -} \ No newline at end of file +} From c063a916fddee6b38257d69893bb6c28517b8495 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Sun, 11 Feb 2018 21:35:31 +1100 Subject: [PATCH 282/351] Revert "Added Timer 'Input Capture' support and example" This reverts commit 36bd1be38738b9e8bd857ee4e1ef6c06d38298ec. --- STM32F1/cores/maple/libmaple/timer.c | 10 +-- .../HardwareTimerInputCapture.ino | 68 ------------------- .../system/libmaple/include/libmaple/timer.h | 4 +- .../libmaple/stm32f1/include/series/gpio.h | 3 +- 4 files changed, 3 insertions(+), 82 deletions(-) delete mode 100644 STM32F1/libraries/A_STM32_Examples/examples/Sensors/HardwareTimerInputCapture/HardwareTimerInputCapture.ino diff --git a/STM32F1/cores/maple/libmaple/timer.c b/STM32F1/cores/maple/libmaple/timer.c index 4c972fe..70e2065 100644 --- a/STM32F1/cores/maple/libmaple/timer.c +++ b/STM32F1/cores/maple/libmaple/timer.c @@ -39,7 +39,6 @@ static void disable_channel(timer_dev *dev, uint8 channel); static void pwm_mode(timer_dev *dev, uint8 channel); static void output_compare_mode(timer_dev *dev, uint8 channel); static void encoder_mode(timer_dev *dev, uint8 channel) ;//CARLOS -static void input_capture_mode(timer_dev *dev, uint8 channel);//@Cesco static inline void enable_irq(timer_dev *dev, timer_interrupt_id iid); @@ -237,9 +236,6 @@ void timer_set_mode(timer_dev *dev, uint8 channel, timer_mode mode) { case TIMER_ENCODER: encoder_mode(dev, channel); //find a way to pass all the needed stuff on the 8bit var break; - case TIMER_INPUT_CAPTURE:// code from @Cesco - input_capture_mode(dev, channel); - break; } } @@ -353,11 +349,7 @@ static void encoder_mode(timer_dev *dev, uint8 channel __attribute__((unused))) timer_resume(dev); } -// Code supplied by @Cesco (on the forum) -static void input_capture_mode(timer_dev *dev, uint8 channel) { - timer_oc_set_mode(dev, channel, 0, TIMER_CCMR_CCS_INPUT_TI1); - timer_cc_enable(dev, channel); -} + static void enable_adv_irq(timer_dev *dev, timer_interrupt_id id); static void enable_bas_gen_irq(timer_dev *dev); diff --git a/STM32F1/libraries/A_STM32_Examples/examples/Sensors/HardwareTimerInputCapture/HardwareTimerInputCapture.ino b/STM32F1/libraries/A_STM32_Examples/examples/Sensors/HardwareTimerInputCapture/HardwareTimerInputCapture.ino deleted file mode 100644 index e628d69..0000000 --- a/STM32F1/libraries/A_STM32_Examples/examples/Sensors/HardwareTimerInputCapture/HardwareTimerInputCapture.ino +++ /dev/null @@ -1,68 +0,0 @@ -/* Example of the Timer Input Capture mode - * - * Thanks to @cesco on the stm32duino.com - * - * This example uses Timer2. Other timers also support this mode, bnt on the F103C - * only Timer 2 has usable external trigger pins. PA0 and PA15 - * Because the only other usable pin on the F103C is one of the USB pins. - * - * Upload to your favourite F103Cx - * Open the Serial plotter - * Put your finger on either PA0 or PA15 (depenidng whether you USE the pin remapping) - * - * Observe your local mains frequency in terms of pulse width time. - * - */ - -/* Timer2 external trigger can be ether PA0 or PA15. - To use use afio_remap(FIO_REMAP_TIM2_PARTIAL_1) or afio_remap(AFIO_REMAP_TIM2_FULL) - Note. using afio_remap also changes the pins used by Timer2 CH1,CH2,CH3 amd CH4 - * See page 184 of the STM32F10x Refernce manual (PDF downloadable from ST.com - */ - -//#define USE_REMAP_PIN -#ifdef USE_REMAP_PIN -const int timer2ExternalTriggerPin = PA15; -#else -const int timer2ExternalTriggerPin = PA0; -#endif - -volatile boolean hasCapture; -volatile uint16_t captureValue; -volatile uint16_t lastCaptureValue=0; -volatile uint16_t captureDifference=0; - -void captureCallback(void) { - - hasCapture=true; - captureValue = Timer2.getCompare(1); - captureDifference = captureValue-lastCaptureValue; - lastCaptureValue=captureValue; -} - -void setup() { - - pinMode(timer2ExternalTriggerPin,INPUT); - - #ifdef USE_REMAP_PIN - afio_remap(AFIO_REMAP_TIM2_PARTIAL_1); - #endif - - hasCapture = false; - - Timer2.setPrescaleFactor(72); // prescaler to count 72,000,000 / 72 counts per second. i.e count microseconds - Timer2.setMode(TIMER_CH1, TIMER_INPUT_CAPTURE); - Timer2.attachCompare1Interrupt(captureCallback); - -} - -void loop() { - - // Printing inside the callback is not a good idea. - // Hence the capture callback sets a flag , which is detected here - if (hasCapture) - { - Serial.println(captureDifference); - hasCapture=false; - } -} \ No newline at end of file diff --git a/STM32F1/system/libmaple/include/libmaple/timer.h b/STM32F1/system/libmaple/include/libmaple/timer.h index c915f4e..64f458f 100644 --- a/STM32F1/system/libmaple/include/libmaple/timer.h +++ b/STM32F1/system/libmaple/include/libmaple/timer.h @@ -564,15 +564,13 @@ typedef enum timer_mode { * values, the corresponding interrupt is fired. */ TIMER_OUTPUT_COMPARE, - - /* TIMER_INPUT_CAPTURE, UNDER DEVELOPMENT: In this mode, the timer can measure the + /* TIMER_INPUT_CAPTURE, TODO: In this mode, the timer can measure the * pulse lengths of input signals */ /* TIMER_ONE_PULSE, TODO: In this mode, the timer can generate a single * pulse on a GPIO pin for a specified amount of * time. */ TIMER_ENCODER, //CARLOS Change - TIMER_INPUT_CAPTURE,// code from @cesco } timer_mode; /** Timer channel numbers */ diff --git a/STM32F1/system/libmaple/stm32f1/include/series/gpio.h b/STM32F1/system/libmaple/stm32f1/include/series/gpio.h index a20c021..aff639b 100644 --- a/STM32F1/system/libmaple/stm32f1/include/series/gpio.h +++ b/STM32F1/system/libmaple/stm32f1/include/series/gpio.h @@ -351,8 +351,7 @@ typedef enum afio_remap_peripheral { * Timer 2 partial remapping 2 (CH1 and ETR on PA0, CH2 on PA1, * CH3 on PB10, CH4 on PB11) */ AFIO_REMAP_TIM2_PARTIAL_2 = AFIO_MAPR_TIM2_REMAP_PA0_PA1_PB10_PB11, - /** Timer 2 full remapping - (CH1/ETR/PA15, CH2/PB3, CH3/PB10, CH4/PB11) */ + /** Timer 2 full remapping */ AFIO_REMAP_TIM2_FULL = AFIO_MAPR_TIM2_REMAP_FULL, /** USART 3 part remapping */ AFIO_REMAP_USART3_PARTIAL = AFIO_MAPR_USART3_REMAP_PARTIAL, From f928acf19336e1d1f1ae146d3f9f9d8d18e19033 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Tue, 13 Feb 2018 18:34:15 +1100 Subject: [PATCH 283/351] Add InputCapture and OnePulse functionality from @stevestrong --- STM32F1/cores/maple/HardwareTimer.cpp | 23 +--- STM32F1/cores/maple/HardwareTimer.h | 47 +++++-- STM32F1/cores/maple/libmaple/timer.c | 9 +- .../HardwareTimerOnePulseMode.ino | 67 ++++++++++ .../HardwareTimerPWMInput.ino | 77 ++++++++++++ .../system/libmaple/include/libmaple/timer.h | 119 ++++++------------ 6 files changed, 225 insertions(+), 117 deletions(-) create mode 100644 STM32F1/libraries/A_STM32_Examples/examples/Sensors/HardwareTimerOnePulseMode/HardwareTimerOnePulseMode.ino create mode 100644 STM32F1/libraries/A_STM32_Examples/examples/Sensors/HardwareTimerPWMInput/HardwareTimerPWMInput.ino diff --git a/STM32F1/cores/maple/HardwareTimer.cpp b/STM32F1/cores/maple/HardwareTimer.cpp index abf1e62..dd96d05 100644 --- a/STM32F1/cores/maple/HardwareTimer.cpp +++ b/STM32F1/cores/maple/HardwareTimer.cpp @@ -30,6 +30,7 @@ #include "ext_interrupts.h" // for noInterrupts(), interrupts() #include "wirish_math.h" #include // for CYCLES_PER_MICROSECOND +#include // TODO [0.1.0] Remove deprecated pieces @@ -138,7 +139,6 @@ void HardwareTimer::detachInterrupt(int channel) { timer_detach_interrupt(this->dev, (uint8)channel); } - void HardwareTimer::enableDMA(int channel) { timer_dma_enable_req(this->dev, (uint8)channel); } @@ -156,28 +156,7 @@ void HardwareTimer::setMasterModeTrGo(uint32_t mode) { this->dev->regs.bas->CR2 |= mode; } -/* CARLOS Changes to add encoder mode.*/ - -//direction of movement. (to be better described). - uint8 HardwareTimer::getDirection(){ - return get_direction(this->dev); - } -//set if the encoder will count edges on one, which or both channels. - void HardwareTimer::setEdgeCounting(uint32 counting) { - (dev->regs).gen->SMCR = counting;//TIMER_SMCR_SMS_ENCODER3; //choose encoder 3, counting on - - } - - uint8 HardwareTimer::getEdgeCounting() { - return (dev->regs).gen->SMCR; - } - - - -//set the polarity of counting... not sure how interesting this is.. - void HardwareTimer::setPolarity(){} - /* -- Deprecated predefined instances -------------------------------------- */ HardwareTimer Timer1(1); diff --git a/STM32F1/cores/maple/HardwareTimer.h b/STM32F1/cores/maple/HardwareTimer.h index bb40dba..f715bbc 100644 --- a/STM32F1/cores/maple/HardwareTimer.h +++ b/STM32F1/cores/maple/HardwareTimer.h @@ -227,32 +227,53 @@ public: * TIMER_CR2_MMS_COMPARE_OC4REF */ void setMasterModeTrGo(uint32_t mode); - + + void setSlaveFlags(uint32 flags) { + ((this->dev)->regs).gen->SMCR = flags; + } + //CARLOS. /* added these functions to make sense for the encoder mode. */ //direction of movement. (to be better described). - uint8 getDirection(); - + uint8 getDirection() { + return get_direction(this->dev); + } + //set if the encoder will count edges on one, which or both channels. - void setEdgeCounting(uint32 counting); - uint8 getEdgeCounting(); //not sure if needed. + void setEdgeCounting(uint32 counting) { + setSlaveFlags(counting); + } //set the polarity of counting... not sure how interesting this is.. - void setPolarity(); - + void setPolarity(uint8 channel, uint8 pol) { + timer_cc_set_pol(this->dev, channel, pol); + } + + void setInputCaptureMode(uint8 channel, timer_ic_input_select input) { + input_capture_mode(this->dev, channel, input); + } + + uint8_t getInputCaptureFlag(uint8 channel) { + return ( timer_get_status(this->dev) >> channel ) & 0x1; + } + + uint8_t getInputCaptureFlagOverflow(uint8 channel) { + uint8 ret = ( timer_get_status(this->dev) >> (8+channel) ) & 0x1; + if ( ret ) timer_reset_status_bit(this->dev, (8+channel)); // clear flag + return ret; + } + //add the filtering definition for the input channel. - /* Escape hatch */ - - /** + /** * @brief Enable/disable DMA request for the input channel. */ - void enableDMA(int channel); - void disableDMA(int channel); - + void enableDMA(int channel); + void disableDMA(int channel); + /** * @brief Get a pointer to the underlying libmaple timer_dev for * this HardwareTimer instance. diff --git a/STM32F1/cores/maple/libmaple/timer.c b/STM32F1/cores/maple/libmaple/timer.c index 70e2065..fa50c20 100644 --- a/STM32F1/cores/maple/libmaple/timer.c +++ b/STM32F1/cores/maple/libmaple/timer.c @@ -40,7 +40,6 @@ static void pwm_mode(timer_dev *dev, uint8 channel); static void output_compare_mode(timer_dev *dev, uint8 channel); static void encoder_mode(timer_dev *dev, uint8 channel) ;//CARLOS - static inline void enable_irq(timer_dev *dev, timer_interrupt_id iid); /* @@ -236,6 +235,9 @@ void timer_set_mode(timer_dev *dev, uint8 channel, timer_mode mode) { case TIMER_ENCODER: encoder_mode(dev, channel); //find a way to pass all the needed stuff on the 8bit var break; + case TIMER_INPUT_CAPTURE:// code from @Cesco + input_capture_mode(dev, channel, TIMER_IC_INPUT_DEFAULT); + break; } } @@ -349,7 +351,10 @@ static void encoder_mode(timer_dev *dev, uint8 channel __attribute__((unused))) timer_resume(dev); } - +void input_capture_mode(timer_dev *dev, uint8 channel, timer_ic_input_select input) { + timer_oc_set_mode(dev, channel, 0, input); + timer_cc_enable(dev, channel); +} static void enable_adv_irq(timer_dev *dev, timer_interrupt_id id); static void enable_bas_gen_irq(timer_dev *dev); diff --git a/STM32F1/libraries/A_STM32_Examples/examples/Sensors/HardwareTimerOnePulseMode/HardwareTimerOnePulseMode.ino b/STM32F1/libraries/A_STM32_Examples/examples/Sensors/HardwareTimerOnePulseMode/HardwareTimerOnePulseMode.ino new file mode 100644 index 0000000..348e321 --- /dev/null +++ b/STM32F1/libraries/A_STM32_Examples/examples/Sensors/HardwareTimerOnePulseMode/HardwareTimerOnePulseMode.ino @@ -0,0 +1,67 @@ +/* + * Example of the Timer Input Capture mode combined with one pulse mode + * + * This example uses: + * - Timer2 channel 1 as capture input + * - Timer2 channel 2 to generate the pulses, + * - Timer 3 to generate a PWM trigger signal for capture input + */ + +#include + +const uint16_t pulseDelay = 200; +const uint16_t pulseWidth = 200; +//----------------------------------------------------------------------------- +void toggle_led() +{ + digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); +} +//----------------------------------------------------------------------------- +void setup() +{ + // setup PA1 (Timer2 channel 2) to PWM (one pulse mode) + pinMode(PA1, PWM); + // setup PA0 (Timer 2 channel 1) as input (capture input mode) + pinMode(PA0, INPUT); + + // stop the timers before configuring them + Timer2.pause(); + + Timer2.setPrescaleFactor(72); // 1 µs resolution + Timer2.setCompare(TIMER_CH2, pulseDelay); + Timer2.setOverflow(pulseWidth + pulseDelay-1); + + // counter setup in one pulse mode, as slave triggered by TI1 + TIMER2_BASE->CR1 = ( TIMER_CR1_OPM ); // one pulse mode + Timer2.setSlaveFlags( TIMER_SMCR_TS_TI1FP1 | TIMER_SMCR_SMS_TRIGGER ); + + // channel 1: capture input on rising edge + Timer2.setMode(TIMER_CH1, TIMER_INPUT_CAPTURE); + //Timer2.setPolarity(TIMER_CH1, 1); // trigger on falling edge + // channel 2: invert polarity (we want low for CNT=1000 ) + { + t = millis(); + toggle_led(); + } +} diff --git a/STM32F1/libraries/A_STM32_Examples/examples/Sensors/HardwareTimerPWMInput/HardwareTimerPWMInput.ino b/STM32F1/libraries/A_STM32_Examples/examples/Sensors/HardwareTimerPWMInput/HardwareTimerPWMInput.ino new file mode 100644 index 0000000..2cc962a --- /dev/null +++ b/STM32F1/libraries/A_STM32_Examples/examples/Sensors/HardwareTimerPWMInput/HardwareTimerPWMInput.ino @@ -0,0 +1,77 @@ +/* + * Example of the Timer Input Capture mode to measure PWM pulse width and period. + * + * This example uses: + * - Timer2 channel 1 as capture input + * - Timer3 to generate a PWM trigger signal for capture input + */ + +#include + +const uint8_t pwmPulse = 20; // ms +const uint8_t pwmPeriod = 50; // ms +//----------------------------------------------------------------------------- +void toggle_led() +{ + digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); +} +//----------------------------------------------------------------------------- +void setup() +{ + pinMode(LED_BUILTIN, OUTPUT); + + // setup PA0 (Timer 2 channel 1) as input capture mode + pinMode(PA0, INPUT); + + while (!Serial); delay(1000); + + Serial << "Example of the Timer Input Capture mode to measure PWM pulse width and period\n\n"; + + // stop the timers before configuring them + Timer2.pause(); + Timer3.pause(); + + Timer2.setPrescaleFactor(72); // 1 microsecond resolution + + // setup timer 2 channel 1 capture on rising edge + Timer2.setInputCaptureMode(TIMER_CH1, TIMER_IC_INPUT_DEFAULT); // use default input TI1 + // setup timer 2 channel 2 capture on falling edge + Timer2.setInputCaptureMode(TIMER_CH2, TIMER_IC_INPUT_SWITCH); // use switched input TI1 + Timer2.setPolarity(TIMER_CH2, 1); // trigger on falling edge + + // counter setup as slave triggered by TI1 in reset mode + Timer2.setSlaveFlags( TIMER_SMCR_TS_TI1FP1 | TIMER_SMCR_SMS_RESET ); + + Timer2.refresh(); + Timer2.getCompare(TIMER_CH1); // clear capture flag + Timer2.getCompare(TIMER_CH2); // clear capture flag + Timer2.resume(); // let timer 2 run + + // setup PA6 (Timer3 channel 1) to generate 1 ms period PWM with 10% DC + pinMode(PA6, PWM); + Timer3.setPrescaleFactor(72); // 1 µs resolution + Timer3.setCompare(TIMER_CH1, pwmPulse*1000); + Timer3.setOverflow(pwmPeriod*1000); + Timer3.refresh(); + + Timer3.resume(); // let timer 3 run + + // discard first reading + // wait for first period end + while ( !Timer2.getInputCaptureFlag(TIMER_CH1) ); + Timer2.getCompare(TIMER_CH1); // clear capture flag +} +//----------------------------------------------------------------------------- +void loop() +{ + if ( Timer2.getInputCaptureFlag(TIMER_CH2) ) // high pulse end + { + Serial << "PWM pulse width: " << Timer2.getCompare(TIMER_CH2); + } + if ( Timer2.getInputCaptureFlag(TIMER_CH1) ) // period end + { + Serial << ", period: " << Timer2.getCompare(TIMER_CH1) << endl; + toggle_led(); + //delay(500); // read the values only 2 times per second + } +} diff --git a/STM32F1/system/libmaple/include/libmaple/timer.h b/STM32F1/system/libmaple/include/libmaple/timer.h index 64f458f..07764c6 100644 --- a/STM32F1/system/libmaple/include/libmaple/timer.h +++ b/STM32F1/system/libmaple/include/libmaple/timer.h @@ -372,7 +372,6 @@ extern timer_dev timer14; /* Capture/compare mode registers, common values */ -#define TIMER_CCMR_CCS_OUTPUT 0x0 #define TIMER_CCMR_CCS_INPUT_TI1 0x1 #define TIMER_CCMR_CCS_INPUT_TI2 0x2 #define TIMER_CCMR_CCS_INPUT_TRC 0x3 @@ -387,7 +386,7 @@ extern timer_dev timer14; #define TIMER_CCMR1_OC1FE_BIT 2 #define TIMER_CCMR1_OC2CE (1U << TIMER_CCMR1_OC2CE_BIT) -#define TIMER_CCMR1_OC2M (0x3 << 12) +#define TIMER_CCMR1_OC2M (0x7 << 12) #define TIMER_CCMR1_IC2F (0xF << 12) #define TIMER_CCMR1_OC2PE (1U << TIMER_CCMR1_OC2PE_BIT) #define TIMER_CCMR1_OC2FE (1U << TIMER_CCMR1_OC2FE_BIT) @@ -398,16 +397,16 @@ extern timer_dev timer14; #define TIMER_CCMR1_CC2S_INPUT_TI1 (0x2 << 8) #define TIMER_CCMR1_CC2S_INPUT_TRC (0x3 << 8) #define TIMER_CCMR1_OC1CE (1U << TIMER_CCMR1_OC1CE_BIT) -#define TIMER_CCMR1_OC1M (0x3 << 4) +#define TIMER_CCMR1_OC1M (0x7 << 4) #define TIMER_CCMR1_IC1F (0xF << 4) #define TIMER_CCMR1_OC1PE (1U << TIMER_CCMR1_OC1PE_BIT) #define TIMER_CCMR1_OC1FE (1U << TIMER_CCMR1_OC1FE_BIT) #define TIMER_CCMR1_IC1PSC (0x3 << 2) #define TIMER_CCMR1_CC1S 0x3 -#define TIMER_CCMR1_CC1S_OUTPUT TIMER_CCMR_CCS_OUTPUT -#define TIMER_CCMR1_CC1S_INPUT_TI1 TIMER_CCMR_CCS_INPUT_TI1 -#define TIMER_CCMR1_CC1S_INPUT_TI2 TIMER_CCMR_CCS_INPUT_TI2 -#define TIMER_CCMR1_CC1S_INPUT_TRC TIMER_CCMR_CCS_INPUT_TRC +#define TIMER_CCMR1_CC1S_OUTPUT 0x0 +#define TIMER_CCMR1_CC1S_INPUT_TI1 0x1 +#define TIMER_CCMR1_CC1S_INPUT_TI2 0x2 +#define TIMER_CCMR1_CC1S_INPUT_TRC 0x3 /* Capture/compare mode register 2 (CCMR2) */ @@ -425,10 +424,10 @@ extern timer_dev timer14; #define TIMER_CCMR2_OC4FE (1U << TIMER_CCMR2_OC4FE_BIT) #define TIMER_CCMR2_IC4PSC (0x3 << 10) #define TIMER_CCMR2_CC4S (0x3 << 8) -#define TIMER_CCMR2_CC4S_OUTPUT (TIMER_CCMR_CCS_OUTPUT << 8) -#define TIMER_CCMR2_CC4S_INPUT_TI1 (TIMER_CCMR_CCS_INPUT_TI1 << 8) -#define TIMER_CCMR2_CC4S_INPUT_TI2 (TIMER_CCMR_CCS_INPUT_TI2 << 8) -#define TIMER_CCMR2_CC4S_INPUT_TRC (TIMER_CCMR_CCS_INPUT_TRC << 8) +#define TIMER_CCMR2_CC4S_OUTPUT (0x0 << 8) +#define TIMER_CCMR2_CC4S_INPUT_TI4 (0x1 << 8) +#define TIMER_CCMR2_CC4S_INPUT_TI3 (0x2 << 8) +#define TIMER_CCMR2_CC4S_INPUT_TRC (0x3 << 8) #define TIMER_CCMR2_OC3CE (1U << TIMER_CCMR2_OC3CE_BIT) #define TIMER_CCMR2_OC3M (0x3 << 4) #define TIMER_CCMR2_IC3F (0xF << 4) @@ -436,10 +435,10 @@ extern timer_dev timer14; #define TIMER_CCMR2_OC3FE (1U << TIMER_CCMR2_OC3FE_BIT) #define TIMER_CCMR2_IC3PSC (0x3 << 2) #define TIMER_CCMR2_CC3S 0x3 -#define TIMER_CCMR2_CC3S_OUTPUT TIMER_CCMR_CCS_OUTPUT -#define TIMER_CCMR2_CC3S_INPUT_TI1 TIMER_CCMR_CCS_INPUT_TI1 -#define TIMER_CCMR2_CC3S_INPUT_TI2 TIMER_CCMR_CCS_INPUT_TI2 -#define TIMER_CCMR2_CC3S_INPUT_TRC TIMER_CCMR_CCS_INPUT_TRC +#define TIMER_CCMR2_CC3S_OUTPUT 0x0 +#define TIMER_CCMR2_CC3S_INPUT_TI3 0x1 +#define TIMER_CCMR2_CC3S_INPUT_TI4 0x2 +#define TIMER_CCMR2_CC3S_INPUT_TRC 0x3 /* Capture/compare enable register (CCER) */ @@ -564,13 +563,15 @@ typedef enum timer_mode { * values, the corresponding interrupt is fired. */ TIMER_OUTPUT_COMPARE, - /* TIMER_INPUT_CAPTURE, TODO: In this mode, the timer can measure the + + /* TIMER_INPUT_CAPTURE, UNDER DEVELOPMENT: In this mode, the timer can measure the * pulse lengths of input signals */ /* TIMER_ONE_PULSE, TODO: In this mode, the timer can generate a single * pulse on a GPIO pin for a specified amount of * time. */ TIMER_ENCODER, //CARLOS Change + TIMER_INPUT_CAPTURE,// code from @cesco } timer_mode; /** Timer channel numbers */ @@ -663,6 +664,19 @@ static inline void timer_resume(timer_dev *dev) { *bb_perip(&(dev->regs).bas->CR1, TIMER_CR1_CEN_BIT) = 1; } +/** + * @brief Get the status register. + * @param dev Timer device + * @return Status register value (16bits). + */ +static inline uint16 timer_get_status(timer_dev *dev) { + return (dev->regs).gen->SR; +} + +static inline void timer_reset_status_bit(timer_dev *dev, uint8 bit) { + *bb_perip(&(dev->regs).gen->SR, bit) = 0; +} + /** * @brief Returns the timer's counter value. * @@ -1071,76 +1085,21 @@ static inline void timer_oc_set_mode(timer_dev *dev, uint32 tmp = *ccmr; tmp &= ~(0xFF << shift); - tmp |= (mode | flags | TIMER_CCMR_CCS_OUTPUT) << shift; + tmp |= (mode | flags) << shift; *ccmr = tmp; } -/* - * Old, erroneous bit definitions from previous releases, kept for - * backwards compatibility: +/** + * Timer output compare modes. */ +typedef enum timer_ic_input_select { + TIMER_IC_INPUT_DEFAULT = TIMER_CCMR_CCS_INPUT_TI1, + TIMER_IC_INPUT_SWITCH = TIMER_CCMR_CCS_INPUT_TI2, + TIMER_IC_INPUT_TRC = TIMER_CCMR_CCS_INPUT_TRC, +} timer_ic_input_select; -/** Deprecated. Use TIMER_CCMR1_CC4S_OUTPUT instead. */ -#define TIMER_CCMR1_CC4S_OUTPUT TIMER_CCMR2_CC4S_OUTPUT -/** Deprecated. Use TIMER_CCMR1_CC4S_INPUT_TI1 instead. */ -#define TIMER_CCMR1_CC4S_INPUT_TI1 TIMER_CCMR2_CC4S_INPUT_TI1 -/** Deprecated. Use TIMER_CCMR1_CC4S_INPUT_TI2 instead. */ -#define TIMER_CCMR1_CC4S_INPUT_TI2 TIMER_CCMR2_CC4S_INPUT_TI2 -/** Deprecated. Use TIMER_CCMR1_CC4S_INPUT_TRC instead. */ -#define TIMER_CCMR1_CC4S_INPUT_TRC TIMER_CCMR2_CC4S_INPUT_TRC -/** Deprecated. Use TIMER_CCMR2_IC4F instead. */ -#define TIMER_CCMR2_IC2F TIMER_CCMR2_IC4F -/** Deprecated. Use TIMER_CCMR2_IC4PSC instead. */ -#define TIMER_CCMR2_IC2PSC TIMER_CCMR2_IC4PSC -/** Deprecated. Use TIMER_CCMR2_IC3F instead. */ -#define TIMER_CCMR2_IC1F TIMER_CCMR2_IC3F -/** Deprecated. Use TIMER_CCMR2_IC3PSC instead. */ -#define TIMER_CCMR2_IC1PSC TIMER_CCMR2_IC3PSC -/** Deprecated. Use TIMER_CCMR1_CC3S_OUTPUT instead. */ -#define TIMER_CCMR1_CC3S_OUTPUT TIMER_CCMR2_CC3S_OUTPUT -/** Deprecated. Use TIMER_CCMR1_CC3S_INPUT_TI1 instead. */ -#define TIMER_CCMR1_CC3S_INPUT_TI1 TIMER_CCMR2_CC3S_INPUT_TI1 -/** Deprecated. Use TIMER_CCMR1_CC3S_INPUT_TI2 instead. */ -#define TIMER_CCMR1_CC3S_INPUT_TI2 TIMER_CCMR2_CC3S_INPUT_TI2 -/** Deprecated. Use TIMER_CCMR1_CC3S_INPUT_TRC instead. */ -#define TIMER_CCMR1_CC3S_INPUT_TRC TIMER_CCMR2_CC3S_INPUT_TRC +extern void input_capture_mode(timer_dev *dev, uint8 channel, timer_ic_input_select input); -/** Deprecated. Use TIMER_DCR_DBL_1_XFER instead. */ -#define TIMER_DCR_DBL_1BYTE TIMER_DCR_DBL_1_XFER -/** Deprecated. Use TIMER_DCR_DBL_2_XFER instead. */ -#define TIMER_DCR_DBL_2BYTE TIMER_DCR_DBL_2_XFER -/** Deprecated. Use TIMER_DCR_DBL_3_XFER instead. */ -#define TIMER_DCR_DBL_3BYTE TIMER_DCR_DBL_3_XFER -/** Deprecated. Use TIMER_DCR_DBL_4_XFER instead. */ -#define TIMER_DCR_DBL_4BYTE TIMER_DCR_DBL_4_XFER -/** Deprecated. Use TIMER_DCR_DBL_5_XFER instead. */ -#define TIMER_DCR_DBL_5BYTE TIMER_DCR_DBL_5_XFER -/** Deprecated. Use TIMER_DCR_DBL_6_XFER instead. */ -#define TIMER_DCR_DBL_6BYTE TIMER_DCR_DBL_6_XFER -/** Deprecated. Use TIMER_DCR_DBL_7_XFER instead. */ -#define TIMER_DCR_DBL_7BYTE TIMER_DCR_DBL_7_XFER -/** Deprecated. Use TIMER_DCR_DBL_8_XFER instead. */ -#define TIMER_DCR_DBL_8BYTE TIMER_DCR_DBL_8_XFER -/** Deprecated. Use TIMER_DCR_DBL_9_XFER instead. */ -#define TIMER_DCR_DBL_9BYTE TIMER_DCR_DBL_9_XFER -/** Deprecated. Use TIMER_DCR_DBL_10_XFER instead. */ -#define TIMER_DCR_DBL_10BYTE TIMER_DCR_DBL_10_XFER -/** Deprecated. Use TIMER_DCR_DBL_11_XFER instead. */ -#define TIMER_DCR_DBL_11BYTE TIMER_DCR_DBL_11_XFER -/** Deprecated. Use TIMER_DCR_DBL_12_XFER instead. */ -#define TIMER_DCR_DBL_12BYTE TIMER_DCR_DBL_12_XFER -/** Deprecated. Use TIMER_DCR_DBL_13_XFER instead. */ -#define TIMER_DCR_DBL_13BYTE TIMER_DCR_DBL_13_XFER -/** Deprecated. Use TIMER_DCR_DBL_14_XFER instead. */ -#define TIMER_DCR_DBL_14BYTE TIMER_DCR_DBL_14_XFER -/** Deprecated. Use TIMER_DCR_DBL_15_XFER instead. */ -#define TIMER_DCR_DBL_15BYTE TIMER_DCR_DBL_15_XFER -/** Deprecated. Use TIMER_DCR_DBL_16_XFER instead. */ -#define TIMER_DCR_DBL_16BYTE TIMER_DCR_DBL_16_XFER -/** Deprecated. Use TIMER_DCR_DBL_17_XFER instead. */ -#define TIMER_DCR_DBL_17BYTE TIMER_DCR_DBL_17_XFER -/** Deprecated. Use TIMER_DCR_DBL_18_XFER instead. */ -#define TIMER_DCR_DBL_18BYTE TIMER_DCR_DBL_18_XFER #ifdef __cplusplus } // extern "C" From 33736462f657436b1d42807c10cbd20b4efc409a Mon Sep 17 00:00:00 2001 From: MackPi Date: Thu, 15 Feb 2018 22:36:42 -0800 Subject: [PATCH 284/351] Added Variant STM32F103VB Added Board Varient STM32F103B. Replaced #ifdef STM32_HIGH_DENSITY with #if STM32_NR_PORTS > 4 Where it makes sense for High Pin count medium density parts like the STM32F103VB. --- STM32F1/boards.txt | 12 +- STM32F1/cores/maple/libmaple/gpio_f1.c | 4 +- STM32F1/cores/maple/libmaple/rcc_f1.c | 4 +- .../libmaple/stm32f1/include/series/gpio.h | 4 +- .../variants/generic_stm32f103vb/board.cpp | 190 +++++++++++++++ .../generic_stm32f103vb/board/board.h | 84 +++++++ .../generic_stm32f103vb/ld/bootloader.ld | 18 ++ .../generic_stm32f103vb/ld/bootloader_20.ld | 30 +++ .../generic_stm32f103vb/ld/common.inc | 220 +++++++++++++++++ .../generic_stm32f103vb/ld/extra_libs.inc | 7 + .../variants/generic_stm32f103vb/ld/flash.ld | 26 ++ .../generic_stm32f103vb/ld/flash_c8.ld | 33 +++ .../variants/generic_stm32f103vb/ld/jtag.ld | 31 +++ .../generic_stm32f103vb/ld/jtag_c8.ld | 36 +++ .../generic_stm32f103vb/ld/mem-flash.inc | 5 + .../generic_stm32f103vb/ld/mem-jtag.inc | 5 + .../generic_stm32f103vb/ld/mem-ram.inc | 5 + .../variants/generic_stm32f103vb/ld/ram.ld | 25 ++ .../variants/generic_stm32f103vb/ld/ram_c8.ld | 31 +++ .../generic_stm32f103vb/ld/stm32f103vb.ld | 30 +++ .../generic_stm32f103vb/ld/vector_symbols.inc | 78 ++++++ .../generic_stm32f103vb/pins_arduino.h | 6 + .../variants/generic_stm32f103vb/variant.h | 20 ++ .../generic_stm32f103vb/wirish/boards.cpp | 229 ++++++++++++++++++ .../wirish/boards_setup.cpp | 111 +++++++++ .../generic_stm32f103vb/wirish/start.S | 57 +++++ .../generic_stm32f103vb/wirish/start_c.c | 95 ++++++++ .../generic_stm32f103vb/wirish/syscalls.c | 176 ++++++++++++++ 28 files changed, 1567 insertions(+), 5 deletions(-) create mode 100644 STM32F1/variants/generic_stm32f103vb/board.cpp create mode 100644 STM32F1/variants/generic_stm32f103vb/board/board.h create mode 100644 STM32F1/variants/generic_stm32f103vb/ld/bootloader.ld create mode 100644 STM32F1/variants/generic_stm32f103vb/ld/bootloader_20.ld create mode 100644 STM32F1/variants/generic_stm32f103vb/ld/common.inc create mode 100644 STM32F1/variants/generic_stm32f103vb/ld/extra_libs.inc create mode 100644 STM32F1/variants/generic_stm32f103vb/ld/flash.ld create mode 100644 STM32F1/variants/generic_stm32f103vb/ld/flash_c8.ld create mode 100644 STM32F1/variants/generic_stm32f103vb/ld/jtag.ld create mode 100644 STM32F1/variants/generic_stm32f103vb/ld/jtag_c8.ld create mode 100644 STM32F1/variants/generic_stm32f103vb/ld/mem-flash.inc create mode 100644 STM32F1/variants/generic_stm32f103vb/ld/mem-jtag.inc create mode 100644 STM32F1/variants/generic_stm32f103vb/ld/mem-ram.inc create mode 100644 STM32F1/variants/generic_stm32f103vb/ld/ram.ld create mode 100644 STM32F1/variants/generic_stm32f103vb/ld/ram_c8.ld create mode 100644 STM32F1/variants/generic_stm32f103vb/ld/stm32f103vb.ld create mode 100644 STM32F1/variants/generic_stm32f103vb/ld/vector_symbols.inc create mode 100644 STM32F1/variants/generic_stm32f103vb/pins_arduino.h create mode 100644 STM32F1/variants/generic_stm32f103vb/variant.h create mode 100644 STM32F1/variants/generic_stm32f103vb/wirish/boards.cpp create mode 100644 STM32F1/variants/generic_stm32f103vb/wirish/boards_setup.cpp create mode 100644 STM32F1/variants/generic_stm32f103vb/wirish/start.S create mode 100644 STM32F1/variants/generic_stm32f103vb/wirish/start_c.c create mode 100644 STM32F1/variants/generic_stm32f103vb/wirish/syscalls.c diff --git a/STM32F1/boards.txt b/STM32F1/boards.txt index cb9416a..75d4562 100644 --- a/STM32F1/boards.txt +++ b/STM32F1/boards.txt @@ -648,7 +648,7 @@ genericSTM32F103T.menu.opt.ogstd.build.flags.ldspecs= genericSTM32F103V.name=Generic STM32F103V series genericSTM32F103V.vid.0=0x1EAF genericSTM32F103V.pid.0=0x0004 -genericSTM32F103V.build.variant=generic_stm32f103v +#genericSTM32F103V.build.variant=generic_stm32f103v genericSTM32F103V.build.vect=VECT_TAB_ADDR=0x8000000 genericSTM32F103V.build.core=maple genericSTM32F103V.build.board=GENERIC_STM32F103V @@ -661,19 +661,29 @@ genericSTM32F103V.upload.protocol=maple_dfu genericSTM32F103V.build.error_led_port=GPIOE genericSTM32F103V.build.error_led_pin=6 +genericSTM32F103V.menu.device_variant.STM32F103VB=STM32F103VB +genericSTM32F103V.menu.device_variant.STM32F103VB.build.variant=generic_stm32f103vb +genericSTM32F103V.menu.device_variant.STM32F103VB.build.cpu_flags=-DMCU_STM32F103VB +genericSTM32F103V.menu.device_variant.STM32F103VB.upload.maximum_size=131072 +genericSTM32F103V.menu.device_variant.STM32F103VB.upload.maximum_data_size=20480 +genericSTM32F103V.menu.device_variant.STM32F103VB.build.ldscript=ld/stm32f103vb.ld + genericSTM32F103V.menu.device_variant.STM32F103VC=STM32F103VC +genericSTM32F103V.menu.device_variant.STM32F103VC.build.variant=generic_stm32f103v genericSTM32F103V.menu.device_variant.STM32F103VC.build.cpu_flags=-DMCU_STM32F103VC genericSTM32F103V.menu.device_variant.STM32F103VC.upload.maximum_size=262144 genericSTM32F103V.menu.device_variant.STM32F103VC.upload.maximum_data_size=49152 genericSTM32F103V.menu.device_variant.STM32F103VC.build.ldscript=ld/stm32f103vc.ld genericSTM32F103V.menu.device_variant.STM32F103VD=STM32F103VD +genericSTM32F103V.menu.device_variant.STM32F103VD.build.variant=generic_stm32f103v genericSTM32F103V.menu.device_variant.STM32F103VD.build.cpu_flags=-DMCU_STM32F103VD genericSTM32F103V.menu.device_variant.STM32F103VD.upload.maximum_size=393216 genericSTM32F103V.menu.device_variant.STM32F103VD.upload.maximum_data_size=65536 genericSTM32F103V.menu.device_variant.STM32F103VD.build.ldscript=ld/stm32f103vd.ld genericSTM32F103V.menu.device_variant.STM32F103VE=STM32F103VE +genericSTM32F103V.menu.device_variant.STM32F103VE.build.variant=generic_stm32f103v genericSTM32F103V.menu.device_variant.STM32F103VE.build.cpu_flags=-DMCU_STM32F103VE genericSTM32F103V.menu.device_variant.STM32F103VE.upload.maximum_size=524288 genericSTM32F103V.menu.device_variant.STM32F103VE.upload.maximum_data_size=65536 diff --git a/STM32F1/cores/maple/libmaple/gpio_f1.c b/STM32F1/cores/maple/libmaple/gpio_f1.c index 6de16f5..3d24c46 100644 --- a/STM32F1/cores/maple/libmaple/gpio_f1.c +++ b/STM32F1/cores/maple/libmaple/gpio_f1.c @@ -68,7 +68,7 @@ gpio_dev gpiod = { /** GPIO port D device. */ gpio_dev* const GPIOD = &gpiod; -#ifdef STM32_HIGH_DENSITY +#if STM32_NR_GPIO_PORTS > 4 gpio_dev gpioe = { .regs = GPIOE_BASE, .clk_id = RCC_GPIOE, @@ -106,7 +106,7 @@ void gpio_init_all(void) { gpio_init(GPIOB); gpio_init(GPIOC); gpio_init(GPIOD); -#ifdef STM32_HIGH_DENSITY +#if STM32_NR_GPIO_PORTS > 4 gpio_init(GPIOE); gpio_init(GPIOF); gpio_init(GPIOG); diff --git a/STM32F1/cores/maple/libmaple/rcc_f1.c b/STM32F1/cores/maple/libmaple/rcc_f1.c index f45f670..e52e709 100644 --- a/STM32F1/cores/maple/libmaple/rcc_f1.c +++ b/STM32F1/cores/maple/libmaple/rcc_f1.c @@ -69,10 +69,12 @@ const struct rcc_dev_info rcc_dev_table[] = { [RCC_FLITF] = { .clk_domain = AHB, .line_num = 4}, [RCC_SRAM] = { .clk_domain = AHB, .line_num = 2}, [RCC_USB] = { .clk_domain = APB1, .line_num = 23}, -#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) +#if STM32_NR_GPIO_PORTS > 4 [RCC_GPIOE] = { .clk_domain = APB2, .line_num = 6 }, [RCC_GPIOF] = { .clk_domain = APB2, .line_num = 7 }, [RCC_GPIOG] = { .clk_domain = APB2, .line_num = 8 }, +#endif +#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) [RCC_UART4] = { .clk_domain = APB1, .line_num = 19 }, [RCC_UART5] = { .clk_domain = APB1, .line_num = 20 }, [RCC_TIMER5] = { .clk_domain = APB1, .line_num = 3 }, diff --git a/STM32F1/system/libmaple/stm32f1/include/series/gpio.h b/STM32F1/system/libmaple/stm32f1/include/series/gpio.h index aff639b..467128b 100644 --- a/STM32F1/system/libmaple/stm32f1/include/series/gpio.h +++ b/STM32F1/system/libmaple/stm32f1/include/series/gpio.h @@ -31,6 +31,7 @@ * General purpose I/O (GPIO) and Alternate Function I/O (AFIO). */ + #ifndef _LIBMAPLE_STM32F1_GPIO_H_ #define _LIBMAPLE_STM32F1_GPIO_H_ @@ -57,6 +58,7 @@ typedef struct gpio_reg_map { __io uint32 LCKR; /**< Port configuration lock register */ } gpio_reg_map; + struct gpio_dev; extern struct gpio_dev gpioa; extern struct gpio_dev* const GPIOA; @@ -66,7 +68,7 @@ extern struct gpio_dev gpioc; extern struct gpio_dev* const GPIOC; extern struct gpio_dev gpiod; extern struct gpio_dev* const GPIOD; -#ifdef STM32_HIGH_DENSITY +#if STM32_NR_GPIO_PORTS > 4 extern struct gpio_dev gpioe; extern struct gpio_dev* const GPIOE; extern struct gpio_dev gpiof; diff --git a/STM32F1/variants/generic_stm32f103vb/board.cpp b/STM32F1/variants/generic_stm32f103vb/board.cpp new file mode 100644 index 0000000..e0b03b8 --- /dev/null +++ b/STM32F1/variants/generic_stm32f103vb/board.cpp @@ -0,0 +1,190 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ +#warning "vb" +/** + * @file wirish/boards/maple_mini/board.cpp + * @author Marti Bolivar + * @brief Maple Mini board file. + */ + +#include + +#include +#include + +/* Roger Clark. Added next to includes for changes to Serial */ +#include +#include + +#include +#include + +/* Since we want the Serial Wire/JTAG pins as GPIOs, disable both SW + * and JTAG debug support, unless configured otherwise. */ +void boardInit(void) { +#ifndef CONFIG_MAPLE_MINI_NO_DISABLE_DEBUG + disableDebugPorts(); +#endif +} + +// Note. See the enum of pin names in board.h + +extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { + + + {&gpioa, &timer2, &adc1, 0, 1, 0}, /* PA0 */ + {&gpioa, &timer2, &adc1, 1, 2, 1}, /* PA1 */ + {&gpioa, &timer2, &adc1, 2, 3, 2}, /* PA2 */ + {&gpioa, &timer2, &adc1, 3, 4, 3}, /* PA3 */ + {&gpioa, NULL, &adc1, 4, 0, 4}, /* PA4 */ + {&gpioa, NULL, &adc1, 5, 0, 5}, /* PA5 */ + {&gpioa, &timer3, &adc1, 6, 1, 6}, /* PA6 */ + {&gpioa, &timer3, &adc1, 7, 2, 7}, /* PA7 */ + {&gpioa, &timer1, NULL, 8, 1, ADCx}, /* PA8 */ + {&gpioa, &timer1, NULL, 9, 2, ADCx}, /* PA9 */ + {&gpioa, &timer1, NULL, 10, 3, ADCx}, /* PA10 */ + {&gpioa, &timer1, NULL, 11, 4, ADCx}, /* PA11 */ + {&gpioa, NULL, NULL, 12, 0, ADCx}, /* PA12 */ + {&gpioa, NULL, NULL, 13, 0, ADCx}, /* PA13 */ + {&gpioa, NULL, NULL, 14, 0, ADCx}, /* PA14 */ + {&gpioa, NULL, NULL, 15, 0, ADCx}, /* PA15 */ + + {&gpiob, &timer3, &adc1, 0, 3, 8}, /* PB0 */ + {&gpiob, &timer3, &adc1, 1, 4, 9}, /* PB1 */ + {&gpiob, NULL, NULL, 2, 0, ADCx}, /* PB2 */ + {&gpiob, NULL, NULL, 3, 0, ADCx}, /* PB3 */ + {&gpiob, NULL, NULL, 4, 0, ADCx}, /* PB4 */ + {&gpiob, NULL, NULL, 5, 0, ADCx}, /* PB5 */ + {&gpiob, &timer4, NULL, 6, 1, ADCx}, /* PB6 */ + {&gpiob, &timer4, NULL, 7, 2, ADCx}, /* PB7 */ + {&gpiob, &timer4, NULL, 8, 3, ADCx}, /* PB8 */ + {&gpiob, &timer4, NULL, 9, 4, ADCx}, /* PB9 */ + {&gpiob, NULL, NULL, 10, 0, ADCx}, /* PB10 */ + {&gpiob, NULL, NULL, 11, 0, ADCx}, /* PB11 */ + {&gpiob, NULL, NULL, 12, 0, ADCx}, /* PB12 */ + {&gpiob, NULL, NULL, 13, 0, ADCx}, /* PB13 */ + {&gpiob, NULL, NULL, 14, 0, ADCx}, /* PB14 */ + {&gpiob, NULL, NULL, 15, 0, ADCx}, /* PB15 */ + + {&gpioc, NULL, &adc1, 0, 0, 10}, /* PC0 */ + {&gpioc, NULL, &adc1, 1, 0, 11}, /* PC1 */ + {&gpioc, NULL, &adc1, 2, 0, 12}, /* PC2 */ + {&gpioc, NULL, &adc1, 3, 0, 13}, /* PC3 */ + {&gpioc, NULL, &adc1, 4, 0, 14}, /* PC4 */ + {&gpioc, NULL, &adc1, 5, 0, 15}, /* PC5 */ + + {&gpioc, NULL, NULL, 6, 0, ADCx}, /* PC6 */ + {&gpioc, NULL, NULL, 7, 0, ADCx}, /* PC7 */ + {&gpioc, NULL, NULL, 8, 0, ADCx}, /* PC8 */ + {&gpioc, NULL, NULL, 9, 0, ADCx}, /* PC9 */ + + {&gpioc, NULL, NULL, 10, 0, ADCx}, /* PC10 */ + {&gpioc, NULL, NULL, 11, 0, ADCx}, /* PC11 */ + {&gpioc, NULL, NULL, 12, 0, ADCx}, /* PC12 */ + {&gpioc, NULL, NULL, 13, 0, ADCx}, /* PC13 */ + {&gpioc, NULL, NULL, 14, 0, ADCx}, /* PC14 */ + {&gpioc, NULL, NULL, 15, 0, ADCx}, /* PC15 */ + +/* the VB is similar to the RB but exposes more GPIO as follows */ + {&gpiod, NULL, NULL, 0, 0, ADCx} , /* PD0 N */ + {&gpiod, NULL, NULL, 1, 0, ADCx} , /* PD1 */ + {&gpiod, NULL, NULL, 2, 0, ADCx} , /* PD2 TIM3_ETR */ + {&gpiod, NULL, NULL, 3, 0, ADCx} , /* PD3 */ + {&gpiod, NULL, NULL, 4, 0, ADCx} , /* PD4 */ + {&gpiod, NULL, NULL, 5, 0, ADCx} , /* PD5 */ + {&gpiod, NULL, NULL, 6, 0, ADCx} , /* PD6 */ + {&gpiod, NULL, NULL, 7, 0, ADCx} , /* PD7 */ + {&gpiod, NULL, NULL, 8, 0, ADCx} , /* PD8 */ + {&gpiod, NULL, NULL, 9, 0, ADCx} , /* PD9 */ + {&gpiod, NULL, NULL, 10, 0, ADCx} , /* PD10 */ + {&gpiod, NULL, NULL, 11, 0, ADCx} , /* PD11 */ + {&gpiod, NULL, NULL, 12, 0, ADCx} , /* PD12 */ + {&gpiod, NULL, NULL, 13, 0, ADCx} , /* PD13 */ + {&gpiod, NULL, NULL, 14, 0, ADCx} , /* PD14 */ + {&gpiod, NULL, NULL, 15, 0, ADCx} , /* PD15 */ + + {&gpioe, NULL, NULL, 0, 0, ADCx} , /* PE0 TIM4_ETR / FSMC_NBL0 */ + {&gpioe, NULL, NULL, 1, 0, ADCx} , /* PE1 FSMC_NBL1 */ + {&gpioe, NULL, NULL, 2, 0, ADCx} , /* PE2 TRACECK */ + {&gpioe, NULL, NULL, 3, 0, ADCx} , /* PE3 TRACED0 */ + {&gpioe, NULL, NULL, 4, 0, ADCx} , /* PE4 TRACED1 */ + {&gpioe, NULL, NULL, 5, 0, ADCx} , /* PE5 TRACED2 */ + {&gpioe, NULL, NULL, 6, 0, ADCx} , /* PE6 TRACED3 */ + {&gpioe, NULL, NULL, 7, 0, ADCx} , /* PE7 */ + {&gpioe, NULL, NULL, 8, 0, ADCx} , /* PE8 */ + {&gpioe, NULL, NULL, 9, 0, ADCx} , /* PE9 */ + {&gpioe, NULL, NULL, 10, 0, ADCx} , /* PE10 */ + {&gpioe, NULL, NULL, 11, 0, ADCx} , /* PE11 */ + {&gpioe, NULL, NULL, 12, 0, ADCx} , /* PE12 */ + {&gpioe, NULL, NULL, 13, 0, ADCx} , /* PE13 */ + {&gpioe, NULL, NULL, 14, 0, ADCx} , /* PE14 */ + {&gpioe, NULL, NULL, 15, 0, ADCx} , /* PE15 */ + +}; + +extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { + PB0, PA7, PA6, PA3, PA2, PA1, PA0, PB7, PB6, PA10, PA9, PA8, PC6, PC7, PC8, PC9 +}; + +extern const uint8 boardADCPins[BOARD_NR_ADC_PINS] __FLASH__ = { + PB0, PA7, PA6 , PA5 , PA4 , PA3 , PA2 , PA1 , PA0 , PC0, PC1, PC2, PC3, PC4, PC5 +}; + +// Note. These defines are not really used by generic boards. They are for Maple Serial USB +#define USB_DP PA12 +#define USB_DM PA11 + +// NOte. These definitions are not really used for generic boards, they only relate to boards modified to behave like Maple boards +extern const uint8 boardUsedPins[BOARD_NR_USED_PINS] __FLASH__ = { + USB_DP, USB_DM +}; + + +/* + * Roger Clark + * + * 2015/05/28 + * + * Moved definitions for Hardware Serial devices from HardwareSerial.cpp so that each board can define which Arduino "Serial" instance + * Maps to which hardware serial port on the microprocessor + */ + +#ifdef SERIAL_USB + DEFINE_HWSERIAL(Serial1, 1); + + DEFINE_HWSERIAL(Serial2, 2); + + DEFINE_HWSERIAL(Serial3, 3); + +#else + DEFINE_HWSERIAL(Serial, 1); + + DEFINE_HWSERIAL(Serial1, 2); + + DEFINE_HWSERIAL(Serial2, 3); + + +#endif diff --git a/STM32F1/variants/generic_stm32f103vb/board/board.h b/STM32F1/variants/generic_stm32f103vb/board/board.h new file mode 100644 index 0000000..1271bb0 --- /dev/null +++ b/STM32F1/variants/generic_stm32f103vb/board/board.h @@ -0,0 +1,84 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file wirish/boards/maple_mini/include/board/board.h + * @author Marti Bolivar + * @brief Maple Mini board header. + * + * See wirish/boards/maple/include/board/board.h for more information + * on these definitions. + */ +#ifndef _BOARD_GENERIC_STM32F103VB_H_ +#define _BOARD_GENERIC_STM32F103VB_H_ + +#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 +#define BOARD_USART1_TX_PIN PA9 +#define BOARD_USART1_RX_PIN PA10 +#define BOARD_USART2_TX_PIN PA2 +#define BOARD_USART2_RX_PIN PA3 +#define BOARD_USART3_TX_PIN PB10 +#define BOARD_USART3_RX_PIN PB11 + +#define BOARD_NR_SPI 2 +#define BOARD_SPI1_NSS_PIN PA4 +#define BOARD_SPI1_MOSI_PIN PA7 +#define BOARD_SPI1_MISO_PIN PA6 +#define BOARD_SPI1_SCK_PIN PA5 + +#define BOARD_SPI2_NSS_PIN PB12 +#define BOARD_SPI2_MOSI_PIN PB15 +#define BOARD_SPI2_MISO_PIN PB14 +#define BOARD_SPI2_SCK_PIN PB13 + +#define BOARD_NR_GPIO_PINS 80 +#define BOARD_NR_PWM_PINS 16 +#define BOARD_NR_ADC_PINS 15 +#define BOARD_NR_USED_PINS 4 + + +#define BOARD_JTMS_SWDIO_PIN 22 +#define BOARD_JTCK_SWCLK_PIN 21 +#define BOARD_JTDI_PIN 20 +#define BOARD_JTDO_PIN 19 +#define BOARD_NJTRST_PIN 18 + +#define BOARD_USB_DISC_DEV NULL +#define BOARD_USB_DISC_BIT NULL + +// 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, + PB0, PB1, PB2, PB3, PB4, PB5, PB6, PB7, PB8, PB9, PB10, PB11, PB12, PB13, PB14, PB15, + PC0, PC1, PC2, PC3, PC4, PC5, PC6, PC7, PC8, PC9, PC10, PC11, PC12, PC13, PC14, PC15, + PD0, PD1, PD2, PD3, PD4, PD5, PD6, PD7, PD8, PD9, PD10, PD11, PD12, PD13, PD14, PD15, + PE0, PE1, PE2, PE3, PE4, PE5, PE6, PE7, PE8, PE9, PE10, PE11, PE12, PE13, PE14, PE15 +}; + +#endif diff --git a/STM32F1/variants/generic_stm32f103vb/ld/bootloader.ld b/STM32F1/variants/generic_stm32f103vb/ld/bootloader.ld new file mode 100644 index 0000000..348b19c --- /dev/null +++ b/STM32F1/variants/generic_stm32f103vb/ld/bootloader.ld @@ -0,0 +1,18 @@ +/* + * Linker script for Generic STM32F103RE boards, using the generic bootloader (which takes the lower 8k of memory) + */ +MEMORY +{ + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K + rom (rx) : ORIGIN = 0x08002000, LENGTH = 120K +} + + +/* Provide memory region aliases for common.inc */ +REGION_ALIAS("REGION_TEXT", rom); +REGION_ALIAS("REGION_DATA", ram); +REGION_ALIAS("REGION_BSS", ram); +REGION_ALIAS("REGION_RODATA", rom); + +/* Let common.inc handle the real work. */ +INCLUDE common.inc diff --git a/STM32F1/variants/generic_stm32f103vb/ld/bootloader_20.ld b/STM32F1/variants/generic_stm32f103vb/ld/bootloader_20.ld new file mode 100644 index 0000000..4de3a08 --- /dev/null +++ b/STM32F1/variants/generic_stm32f103vb/ld/bootloader_20.ld @@ -0,0 +1,30 @@ +/* + * libmaple linker script for "Flash" builds. + * + * A Flash build puts .text (and .rodata) in Flash, and + * .data/.bss/heap (of course) in SRAM, but offsets the sections by + * enough space to store the Maple bootloader, which lives in low + * Flash and uses low memory. + */ + +/* + * This pulls in the appropriate MEMORY declaration from the right + * subdirectory of stm32/mem/ (the environment must call ld with the + * right include directory flags to make this happen). Boards can also + * use this file to use any of libmaple's memory-related hooks (like + * where the heap should live). + */ +MEMORY +{ + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K + rom (rx) : ORIGIN = 0x08002000, LENGTH = 120K +} + +/* Provide memory region aliases for common.inc */ +REGION_ALIAS("REGION_TEXT", rom); +REGION_ALIAS("REGION_DATA", ram); +REGION_ALIAS("REGION_BSS", ram); +REGION_ALIAS("REGION_RODATA", rom); + +/* Let common.inc handle the real work. */ +INCLUDE common.inc diff --git a/STM32F1/variants/generic_stm32f103vb/ld/common.inc b/STM32F1/variants/generic_stm32f103vb/ld/common.inc new file mode 100644 index 0000000..e086a58 --- /dev/null +++ b/STM32F1/variants/generic_stm32f103vb/ld/common.inc @@ -0,0 +1,220 @@ +/* + * Linker script for libmaple. + * + * Original author "lanchon" from ST forums, with modifications by LeafLabs. + */ + +OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") + +/* + * Configure other libraries we want in the link. + * + * libgcc, libc, and libm are common across supported toolchains. + * However, some toolchains require additional archives which aren't + * present everywhere (e.g. ARM's gcc-arm-embedded releases). + * + * To hack around this, we let the build system specify additional + * archives by putting the right extra_libs.inc (in a directory under + * toolchains/) in our search path. + */ +GROUP(libgcc.a libc.a libm.a) +INCLUDE extra_libs.inc + +/* + * These force the linker to search for vector table symbols. + * + * These symbols vary by STM32 family (and also within families). + * It's up to the build system to configure the link's search path + * properly for the target MCU. + */ +INCLUDE vector_symbols.inc + +/* STM32 vector table. */ +EXTERN(__stm32_vector_table) + +/* C runtime initialization function. */ +EXTERN(start_c) + +/* main entry point */ +EXTERN(main) + +/* Initial stack pointer value. */ +EXTERN(__msp_init) +PROVIDE(__msp_init = ORIGIN(ram) + LENGTH(ram)); + +/* Reset vector and chip reset entry point */ +EXTERN(__start__) +ENTRY(__start__) +PROVIDE(__exc_reset = __start__); + +/* Heap boundaries, for libmaple */ +EXTERN(_lm_heap_start); +EXTERN(_lm_heap_end); + +SECTIONS +{ + .text : + { + __text_start__ = .; + /* + * STM32 vector table. Leave this here. Yes, really. + */ + *(.stm32.interrupt_vector) + + /* + * Program code and vague linking + */ + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + *(.gnu.warning) + *(.glue_7t) *(.glue_7) *(.vfp11_veneer) + + *(.ARM.extab* .gnu.linkonce.armextab.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + . = ALIGN(4); + KEEP(*(.init)) + + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + + . = ALIGN(0x4); + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + + . = ALIGN(4); + KEEP(*(.fini)) + + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + } > REGION_TEXT + + /* + * End of text + */ + .text.align : + { + . = ALIGN(8); + __text_end__ = .; + } > REGION_TEXT + + /* + * .ARM.exidx exception unwinding; mandated by ARM's C++ ABI + */ + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > REGION_RODATA + __exidx_end = .; + + /* + * .data + */ + .data : + { + __data_start__ = .; + LONG(0) + . = ALIGN(8); + + *(.got.plt) *(.got) + *(.data .data.* .gnu.linkonce.d.*) + + . = ALIGN(8); + __data_end__ = .; + } > REGION_DATA AT> REGION_RODATA + + /* + * Read-only data + */ + .rodata : + { + *(.rodata .rodata.* .gnu.linkonce.r.*) + /* .USER_FLASH: We allow users to allocate into Flash here */ + *(.USER_FLASH) + /* ROM image configuration; for C startup */ + . = ALIGN(4); + _lm_rom_img_cfgp = .; + LONG(LOADADDR(.data)); + /* + * Heap: Linker scripts may choose a custom heap by overriding + * _lm_heap_start and _lm_heap_end. Otherwise, the heap is in + * internal SRAM, beginning after .bss, and growing towards + * the stack. + * + * I'm shoving these here naively; there's probably a cleaner way + * to go about this. [mbolivar] + */ + _lm_heap_start = DEFINED(_lm_heap_start) ? _lm_heap_start : _end; + _lm_heap_end = DEFINED(_lm_heap_end) ? _lm_heap_end : __msp_init; + } > REGION_RODATA + + /* + * .bss + */ + .bss : + { + . = ALIGN(8); + __bss_start__ = .; + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN (8); + __bss_end__ = .; + _end = __bss_end__; + } > REGION_BSS + + /* + * Debugging sections + */ + .stab 0 (NOLOAD) : { *(.stab) } + .stabstr 0 (NOLOAD) : { *(.stabstr) } + /* DWARF debug sections. + * Symbols in the DWARF debugging sections are relative to the beginning + * of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + + .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) } + .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) } + /DISCARD/ : { *(.note.GNU-stack) } +} diff --git a/STM32F1/variants/generic_stm32f103vb/ld/extra_libs.inc b/STM32F1/variants/generic_stm32f103vb/ld/extra_libs.inc new file mode 100644 index 0000000..dd2c84f --- /dev/null +++ b/STM32F1/variants/generic_stm32f103vb/ld/extra_libs.inc @@ -0,0 +1,7 @@ +/* + * Extra archives needed by ARM's GCC ARM Embedded arm-none-eabi- + * releases (https://launchpad.net/gcc-arm-embedded/). + */ + +/* This is for the provided newlib. */ +GROUP(libnosys.a) diff --git a/STM32F1/variants/generic_stm32f103vb/ld/flash.ld b/STM32F1/variants/generic_stm32f103vb/ld/flash.ld new file mode 100644 index 0000000..9e250cd --- /dev/null +++ b/STM32F1/variants/generic_stm32f103vb/ld/flash.ld @@ -0,0 +1,26 @@ +/* + * libmaple linker script for "Flash" builds. + * + * A Flash build puts .text (and .rodata) in Flash, and + * .data/.bss/heap (of course) in SRAM, but offsets the sections by + * enough space to store the Maple bootloader, which lives in low + * Flash and uses low memory. + */ + +/* + * This pulls in the appropriate MEMORY declaration from the right + * subdirectory of stm32/mem/ (the environment must call ld with the + * right include directory flags to make this happen). Boards can also + * use this file to use any of libmaple's memory-related hooks (like + * where the heap should live). + */ +INCLUDE mem-flash.inc + +/* Provide memory region aliases for common.inc */ +REGION_ALIAS("REGION_TEXT", rom); +REGION_ALIAS("REGION_DATA", ram); +REGION_ALIAS("REGION_BSS", ram); +REGION_ALIAS("REGION_RODATA", rom); + +/* Let common.inc handle the real work. */ +INCLUDE common.inc diff --git a/STM32F1/variants/generic_stm32f103vb/ld/flash_c8.ld b/STM32F1/variants/generic_stm32f103vb/ld/flash_c8.ld new file mode 100644 index 0000000..4603923 --- /dev/null +++ b/STM32F1/variants/generic_stm32f103vb/ld/flash_c8.ld @@ -0,0 +1,33 @@ +/* + * libmaple linker script for "Flash" builds. + * + * A Flash build puts .text (and .rodata) in Flash, and + * .data/.bss/heap (of course) in SRAM, but offsets the sections by + * enough space to store the Maple bootloader, which lives in low + * Flash and uses low memory. + */ + +/* + * This pulls in the appropriate MEMORY declaration from the right + * subdirectory of stm32/mem/ (the environment must call ld with the + * right include directory flags to make this happen). Boards can also + * use this file to use any of libmaple's memory-related hooks (like + * where the heap should live). + */ +/*INCLUDE mem-flash.inc*/ + +MEMORY +{ + ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 17K + rom (rx) : ORIGIN = 0x08000000, LENGTH = 44K +} + + +/* Provide memory region aliases for common.inc */ +REGION_ALIAS("REGION_TEXT", rom); +REGION_ALIAS("REGION_DATA", ram); +REGION_ALIAS("REGION_BSS", ram); +REGION_ALIAS("REGION_RODATA", rom); + +/* Let common.inc handle the real work. */ +INCLUDE common.inc diff --git a/STM32F1/variants/generic_stm32f103vb/ld/jtag.ld b/STM32F1/variants/generic_stm32f103vb/ld/jtag.ld new file mode 100644 index 0000000..0612f95 --- /dev/null +++ b/STM32F1/variants/generic_stm32f103vb/ld/jtag.ld @@ -0,0 +1,31 @@ +/* + * libmaple linker script for "JTAG" builds. + * + * A "JTAG" build puts .text (and .rodata) in Flash, and + * .data/.bss/heap (of course) in SRAM, but links starting at the + * Flash and SRAM starting addresses (0x08000000 and 0x20000000 + * respectively). This will wipe out a Maple bootloader if there's one + * on the board, so only use this if you know what you're doing. + * + * Of course, a "JTAG" build is perfectly usable for upload over SWD, + * the system memory bootloader, etc. The name is just a historical + * artifact. + */ + +/* + * This pulls in the appropriate MEMORY declaration from the right + * subdirectory of stm32/mem/ (the environment must call ld with the + * right include directory flags to make this happen). Boards can also + * use this file to use any of libmaple's memory-related hooks (like + * where the heap should live). + */ +INCLUDE mem-jtag.inc + +/* Provide memory region aliases for common.inc */ +REGION_ALIAS("REGION_TEXT", rom); +REGION_ALIAS("REGION_DATA", ram); +REGION_ALIAS("REGION_BSS", ram); +REGION_ALIAS("REGION_RODATA", rom); + +/* Let common.inc handle the real work. */ +INCLUDE common.inc diff --git a/STM32F1/variants/generic_stm32f103vb/ld/jtag_c8.ld b/STM32F1/variants/generic_stm32f103vb/ld/jtag_c8.ld new file mode 100644 index 0000000..d9d4a0f --- /dev/null +++ b/STM32F1/variants/generic_stm32f103vb/ld/jtag_c8.ld @@ -0,0 +1,36 @@ +/* + * libmaple linker script for "JTAG" builds. + * + * A "JTAG" build puts .text (and .rodata) in Flash, and + * .data/.bss/heap (of course) in SRAM, but links starting at the + * Flash and SRAM starting addresses (0x08000000 and 0x20000000 + * respectively). This will wipe out a Maple bootloader if there's one + * on the board, so only use this if you know what you're doing. + * + * Of course, a "JTAG" build is perfectly usable for upload over SWD, + * the system memory bootloader, etc. The name is just a historical + * artifact. + */ + +/* + * This pulls in the appropriate MEMORY declaration from the right + * subdirectory of stm32/mem/ (the environment must call ld with the + * right include directory flags to make this happen). Boards can also + * use this file to use any of libmaple's memory-related hooks (like + * where the heap should live). + */ + +MEMORY +{ + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K + rom (rx) : ORIGIN = 0x08000000, LENGTH = 64K +} + +/* Provide memory region aliases for common.inc */ +REGION_ALIAS("REGION_TEXT", rom); +REGION_ALIAS("REGION_DATA", ram); +REGION_ALIAS("REGION_BSS", ram); +REGION_ALIAS("REGION_RODATA", rom); + +/* Let common.inc handle the real work. */ +INCLUDE common.inc diff --git a/STM32F1/variants/generic_stm32f103vb/ld/mem-flash.inc b/STM32F1/variants/generic_stm32f103vb/ld/mem-flash.inc new file mode 100644 index 0000000..a9091ca --- /dev/null +++ b/STM32F1/variants/generic_stm32f103vb/ld/mem-flash.inc @@ -0,0 +1,5 @@ +MEMORY +{ + ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 17K + rom (rx) : ORIGIN = 0x08005000, LENGTH = 108K +} diff --git a/STM32F1/variants/generic_stm32f103vb/ld/mem-jtag.inc b/STM32F1/variants/generic_stm32f103vb/ld/mem-jtag.inc new file mode 100644 index 0000000..20fbec0 --- /dev/null +++ b/STM32F1/variants/generic_stm32f103vb/ld/mem-jtag.inc @@ -0,0 +1,5 @@ +MEMORY +{ + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K + rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K +} diff --git a/STM32F1/variants/generic_stm32f103vb/ld/mem-ram.inc b/STM32F1/variants/generic_stm32f103vb/ld/mem-ram.inc new file mode 100644 index 0000000..f02453b --- /dev/null +++ b/STM32F1/variants/generic_stm32f103vb/ld/mem-ram.inc @@ -0,0 +1,5 @@ +MEMORY +{ + ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 17K + rom (rx) : ORIGIN = 0x08005000, LENGTH = 0K +} diff --git a/STM32F1/variants/generic_stm32f103vb/ld/ram.ld b/STM32F1/variants/generic_stm32f103vb/ld/ram.ld new file mode 100644 index 0000000..34b468e --- /dev/null +++ b/STM32F1/variants/generic_stm32f103vb/ld/ram.ld @@ -0,0 +1,25 @@ +/* + * libmaple linker script for RAM builds. + * + * A Flash build puts .text, .rodata, and .data/.bss/heap (of course) + * in SRAM, but offsets the sections by enough space to store the + * Maple bootloader, which uses low memory. + */ + +/* + * This pulls in the appropriate MEMORY declaration from the right + * subdirectory of stm32/mem/ (the environment must call ld with the + * right include directory flags to make this happen). Boards can also + * use this file to use any of libmaple's memory-related hooks (like + * where the heap should live). + */ +INCLUDE mem-ram.inc + +/* Provide memory region aliases for common.inc */ +REGION_ALIAS("REGION_TEXT", ram); +REGION_ALIAS("REGION_DATA", ram); +REGION_ALIAS("REGION_BSS", ram); +REGION_ALIAS("REGION_RODATA", ram); + +/* Let common.inc handle the real work. */ +INCLUDE common.inc diff --git a/STM32F1/variants/generic_stm32f103vb/ld/ram_c8.ld b/STM32F1/variants/generic_stm32f103vb/ld/ram_c8.ld new file mode 100644 index 0000000..71e081e --- /dev/null +++ b/STM32F1/variants/generic_stm32f103vb/ld/ram_c8.ld @@ -0,0 +1,31 @@ +/* + * libmaple linker script for RAM builds. + * + * A Flash build puts .text, .rodata, and .data/.bss/heap (of course) + * in SRAM, but offsets the sections by enough space to store the + * Maple bootloader, which uses low memory. + */ + +/* + * This pulls in the appropriate MEMORY declaration from the right + * subdirectory of stm32/mem/ (the environment must call ld with the + * right include directory flags to make this happen). Boards can also + * use this file to use any of libmaple's memory-related hooks (like + * where the heap should live). + */ +/*INCLUDE mem-ram.inc*/ +MEMORY +{ + ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 17K + rom (rx) : ORIGIN = 0x08005000, LENGTH = 0 +} + + +/* Provide memory region aliases for common.inc */ +REGION_ALIAS("REGION_TEXT", ram); +REGION_ALIAS("REGION_DATA", ram); +REGION_ALIAS("REGION_BSS", ram); +REGION_ALIAS("REGION_RODATA", ram); + +/* Let common.inc handle the real work. */ +INCLUDE common.inc diff --git a/STM32F1/variants/generic_stm32f103vb/ld/stm32f103vb.ld b/STM32F1/variants/generic_stm32f103vb/ld/stm32f103vb.ld new file mode 100644 index 0000000..814d508 --- /dev/null +++ b/STM32F1/variants/generic_stm32f103vb/ld/stm32f103vb.ld @@ -0,0 +1,30 @@ +/* + * libmaple linker script for "Flash" builds. + * + * A Flash build puts .text (and .rodata) in Flash, and + * .data/.bss/heap (of course) in SRAM, but offsets the sections by + * enough space to store the Maple bootloader, which lives in low + * Flash and uses low memory. + */ + +/* + * This pulls in the appropriate MEMORY declaration from the right + * subdirectory of stm32/mem/ (the environment must call ld with the + * right include directory flags to make this happen). Boards can also + * use this file to use any of libmaple's memory-related hooks (like + * where the heap should live). + */ +MEMORY +{ + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K + rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K +} + +/* Provide memory region aliases for common.inc */ +REGION_ALIAS("REGION_TEXT", rom); +REGION_ALIAS("REGION_DATA", ram); +REGION_ALIAS("REGION_BSS", ram); +REGION_ALIAS("REGION_RODATA", rom); + +/* Let common.inc handle the real work. */ +INCLUDE common.inc diff --git a/STM32F1/variants/generic_stm32f103vb/ld/vector_symbols.inc b/STM32F1/variants/generic_stm32f103vb/ld/vector_symbols.inc new file mode 100644 index 0000000..f8519bb --- /dev/null +++ b/STM32F1/variants/generic_stm32f103vb/ld/vector_symbols.inc @@ -0,0 +1,78 @@ +EXTERN(__msp_init) +EXTERN(__exc_reset) +EXTERN(__exc_nmi) +EXTERN(__exc_hardfault) +EXTERN(__exc_memmanage) +EXTERN(__exc_busfault) +EXTERN(__exc_usagefault) +EXTERN(__stm32reservedexception7) +EXTERN(__stm32reservedexception8) +EXTERN(__stm32reservedexception9) +EXTERN(__stm32reservedexception10) +EXTERN(__exc_svc) +EXTERN(__exc_debug_monitor) +EXTERN(__stm32reservedexception13) +EXTERN(__exc_pendsv) +EXTERN(__exc_systick) + +EXTERN(__irq_wwdg) +EXTERN(__irq_pvd) +EXTERN(__irq_tamper) +EXTERN(__irq_rtc) +EXTERN(__irq_flash) +EXTERN(__irq_rcc) +EXTERN(__irq_exti0) +EXTERN(__irq_exti1) +EXTERN(__irq_exti2) +EXTERN(__irq_exti3) +EXTERN(__irq_exti4) +EXTERN(__irq_dma1_channel1) +EXTERN(__irq_dma1_channel2) +EXTERN(__irq_dma1_channel3) +EXTERN(__irq_dma1_channel4) +EXTERN(__irq_dma1_channel5) +EXTERN(__irq_dma1_channel6) +EXTERN(__irq_dma1_channel7) +EXTERN(__irq_adc) +EXTERN(__irq_usb_hp_can_tx) +EXTERN(__irq_usb_lp_can_rx0) +EXTERN(__irq_can_rx1) +EXTERN(__irq_can_sce) +EXTERN(__irq_exti9_5) +EXTERN(__irq_tim1_brk) +EXTERN(__irq_tim1_up) +EXTERN(__irq_tim1_trg_com) +EXTERN(__irq_tim1_cc) +EXTERN(__irq_tim2) +EXTERN(__irq_tim3) +EXTERN(__irq_tim4) +EXTERN(__irq_i2c1_ev) +EXTERN(__irq_i2c1_er) +EXTERN(__irq_i2c2_ev) +EXTERN(__irq_i2c2_er) +EXTERN(__irq_spi1) +EXTERN(__irq_spi2) +EXTERN(__irq_usart1) +EXTERN(__irq_usart2) +EXTERN(__irq_usart3) +EXTERN(__irq_exti15_10) +EXTERN(__irq_rtcalarm) +EXTERN(__irq_usbwakeup) + +EXTERN(__irq_tim8_brk) +EXTERN(__irq_tim8_up) +EXTERN(__irq_tim8_trg_com) +EXTERN(__irq_tim8_cc) +EXTERN(__irq_adc3) +EXTERN(__irq_fsmc) +EXTERN(__irq_sdio) +EXTERN(__irq_tim5) +EXTERN(__irq_spi3) +EXTERN(__irq_uart4) +EXTERN(__irq_uart5) +EXTERN(__irq_tim6) +EXTERN(__irq_tim7) +EXTERN(__irq_dma2_channel1) +EXTERN(__irq_dma2_channel2) +EXTERN(__irq_dma2_channel3) +EXTERN(__irq_dma2_channel4_5) diff --git a/STM32F1/variants/generic_stm32f103vb/pins_arduino.h b/STM32F1/variants/generic_stm32f103vb/pins_arduino.h new file mode 100644 index 0000000..3052f2e --- /dev/null +++ b/STM32F1/variants/generic_stm32f103vb/pins_arduino.h @@ -0,0 +1,6 @@ + + + + +// API compatibility +#include "variant.h" \ No newline at end of file diff --git a/STM32F1/variants/generic_stm32f103vb/variant.h b/STM32F1/variants/generic_stm32f103vb/variant.h new file mode 100644 index 0000000..8a88623 --- /dev/null +++ b/STM32F1/variants/generic_stm32f103vb/variant.h @@ -0,0 +1,20 @@ +#ifndef _VARIANT_ARDUINO_STM32_ +#define _VARIANT_ARDUINO_STM32_ + +#define digitalPinToPort(P) ( PIN_MAP[P].gpio_device ) +#define digitalPinToBitMask(P) ( BIT(PIN_MAP[P].gpio_bit) ) +#define portOutputRegister(port) ( &(port->regs->ODR) ) +#define portInputRegister(port) ( &(port->regs->IDR) ) + +#define portSetRegister(pin) ( &(PIN_MAP[pin].gpio_device->regs->BSRR) ) +#define portClearRegister(pin) ( &(PIN_MAP[pin].gpio_device->regs->BRR) ) + +#define portConfigRegister(pin) ( &(PIN_MAP[pin].gpio_device->regs->CRL) ) + +static const uint8_t SS = BOARD_SPI1_NSS_PIN; +static const uint8_t SS1 = BOARD_SPI2_NSS_PIN; +static const uint8_t MOSI = BOARD_SPI1_MOSI_PIN; +static const uint8_t MISO = BOARD_SPI1_MISO_PIN; +static const uint8_t SCK = BOARD_SPI1_SCK_PIN; + +#endif /* _VARIANT_ARDUINO_STM32_ */ \ No newline at end of file diff --git a/STM32F1/variants/generic_stm32f103vb/wirish/boards.cpp b/STM32F1/variants/generic_stm32f103vb/wirish/boards.cpp new file mode 100644 index 0000000..ddeaa57 --- /dev/null +++ b/STM32F1/variants/generic_stm32f103vb/wirish/boards.cpp @@ -0,0 +1,229 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2011, 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file wirish/boards.cpp + * @brief init() and board routines. + * + * This file is mostly interesting for the init() function, which + * configures Flash, the core clocks, and a variety of other available + * peripherals on the board so the rest of Wirish doesn't have to turn + * things on before using them. + * + * Prior to returning, init() calls boardInit(), which allows boards + * to perform any initialization they need to. This file includes a + * weak no-op definition of boardInit(), so boards that don't need any + * special initialization don't have to define their own. + * + * How init() works is chip-specific. See the boards_setup.cpp files + * under e.g. wirish/stm32f1/, wirish/stmf32f2 for the details, but be + * advised: their contents are unstable, and can/will change without + * notice. + */ + +#include +#include +#include +#include +#include +#include "boards_private.h" + +static void setup_flash(void); +static void setup_clocks(void); +static void setup_nvic(void); +static void setup_adcs(void); +static void setup_timers(void); + +/* + * Exported functions + */ + +void init(void) { + setup_flash(); + setup_clocks(); + setup_nvic(); + systick_init(SYSTICK_RELOAD_VAL); + wirish::priv::board_setup_gpio(); + setup_adcs(); + setup_timers(); + wirish::priv::board_setup_usb(); + wirish::priv::series_init(); + boardInit(); +} + +/* Provide a default no-op boardInit(). */ +__weak void boardInit(void) { +} + +/* You could farm this out to the files in boards/ if e.g. it takes + * too long to test on boards with lots of pins. */ +bool boardUsesPin(uint8 pin) { + for (int i = 0; i < BOARD_NR_USED_PINS; i++) { + if (pin == boardUsedPins[i]) { + return true; + } + } + return false; +} + +/* + * Auxiliary routines + */ + +static void setup_flash(void) { + // Turn on as many Flash "go faster" features as + // possible. flash_enable_features() just ignores any flags it + // can't support. + flash_enable_features(FLASH_PREFETCH | FLASH_ICACHE | FLASH_DCACHE); + // Configure the wait states, assuming we're operating at "close + // enough" to 3.3V. + flash_set_latency(FLASH_SAFE_WAIT_STATES); +} + +static void setup_clocks(void) { + // Turn on HSI. We'll switch to and run off of this while we're + // setting up the main PLL. + rcc_turn_on_clk(RCC_CLK_HSI); + + // Turn off and reset the clock subsystems we'll be using, as well + // as the clock security subsystem (CSS). Note that resetting CFGR + // to its default value of 0 implies a switch to HSI for SYSCLK. + RCC_BASE->CFGR = 0x00000000; + rcc_disable_css(); + rcc_turn_off_clk(RCC_CLK_PLL); + rcc_turn_off_clk(RCC_CLK_HSE); + wirish::priv::board_reset_pll(); + // Clear clock readiness interrupt flags and turn off clock + // readiness interrupts. + RCC_BASE->CIR = 0x00000000; + + // Enable HSE, and wait until it's ready. + rcc_turn_on_clk(RCC_CLK_HSE); + while (!rcc_is_clk_ready(RCC_CLK_HSE)) + ; + + // Configure AHBx, APBx, etc. prescalers and the main PLL. + wirish::priv::board_setup_clock_prescalers(); + rcc_configure_pll(&wirish::priv::w_board_pll_cfg); + +#ifdef XTAL16M + // 16MHz crystal (HSE) + // in this case we additionally set the Bit 17 (PLLXTPRE=1) => then HSE clock is divided by 2 before PLL entry + RCC_BASE->CFGR |= RCC_CFGR_PLLXTPRE; +#endif + + // Enable the PLL, and wait until it's ready. + rcc_turn_on_clk(RCC_CLK_PLL); + while(!rcc_is_clk_ready(RCC_CLK_PLL)) + ; + + // Finally, switch to the now-ready PLL as the main clock source. + rcc_switch_sysclk(RCC_CLKSRC_PLL); +} + +/* + * These addresses are where usercode starts when a bootloader is + * present. If no bootloader is present, the user NVIC usually starts + * at the Flash base address, 0x08000000. + */ +#if defined(BOOTLOADER_maple) + #define USER_ADDR_ROM 0x08005000 +#else + #if defined(BOOTLOADER_robotis) + #define USER_ADDR_ROM 0x08003000 + #else + #define USER_ADDR_ROM 0x08000000 + #endif +#endif +#define USER_ADDR_RAM 0x20000C00 +extern char __text_start__; + +static void setup_nvic(void) { +#ifdef VECT_TAB_FLASH + nvic_init(USER_ADDR_ROM, 0); +#elif defined VECT_TAB_RAM + nvic_init(USER_ADDR_RAM, 0); +#elif defined VECT_TAB_BASE + nvic_init((uint32)0x08000000, 0); +#elif defined VECT_TAB_ADDR + // A numerically supplied value + nvic_init((uint32)VECT_TAB_ADDR, 0); +#else + // Use the __text_start__ value from the linker script; this + // should be the start of the vector table. + nvic_init((uint32)&__text_start__, 0); +#endif +} + +static void adc_default_config(adc_dev *dev) { + adc_enable_single_swstart(dev); + adc_set_sample_rate(dev, wirish::priv::w_adc_smp); +} + +static void setup_adcs(void) { + adc_set_prescaler(wirish::priv::w_adc_pre); + adc_foreach(adc_default_config); +} + +static void timer_default_config(timer_dev *dev) { + timer_adv_reg_map *regs = (dev->regs).adv; + const uint16 full_overflow = 0xFFFF; + const uint16 half_duty = 0x8FFF; + + timer_init(dev); + timer_pause(dev); + + regs->CR1 = TIMER_CR1_ARPE; + regs->PSC = 1; + regs->SR = 0; + regs->DIER = 0; + regs->EGR = TIMER_EGR_UG; + switch (dev->type) { + case TIMER_ADVANCED: + regs->BDTR = TIMER_BDTR_MOE | TIMER_BDTR_LOCK_OFF; + // fall-through + case TIMER_GENERAL: + timer_set_reload(dev, full_overflow); + for (uint8 channel = 1; channel <= 4; channel++) { + if (timer_has_cc_channel(dev, channel)) { + timer_set_compare(dev, channel, half_duty); + timer_oc_set_mode(dev, channel, TIMER_OC_MODE_PWM_1, + TIMER_OC_PE); + } + } + // fall-through + case TIMER_BASIC: + break; + } + + timer_generate_update(dev); + timer_resume(dev); +} + +static void setup_timers(void) { + timer_foreach(timer_default_config); +} diff --git a/STM32F1/variants/generic_stm32f103vb/wirish/boards_setup.cpp b/STM32F1/variants/generic_stm32f103vb/wirish/boards_setup.cpp new file mode 100644 index 0000000..dba014b --- /dev/null +++ b/STM32F1/variants/generic_stm32f103vb/wirish/boards_setup.cpp @@ -0,0 +1,111 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. +*****************************************************************************/ + +/** + * @file wirish/stm32f1/boards_setup.cpp + * @author Marti Bolivar + * @brief STM32F1 chip setup. + * + * This file controls how init() behaves on the STM32F1. Be very + * careful when changing anything here. Many of these values depend + * upon each other. + */ + +#include "boards_private.h" + +#include +#include + +#include +#include + +// Allow boards to provide a PLL multiplier. This is useful for +// e.g. STM32F100 value line MCUs, which use slower multipliers. +// (We're leaving the default to RCC_PLLMUL_9 for now, since that +// works for F103 performance line MCUs, which is all that LeafLabs +// currently officially supports). +#ifndef BOARD_RCC_PLLMUL + #if F_CPU==128000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_16 + #elif F_CPU==72000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 + #elif F_CPU==48000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 + #endif +#endif + +namespace wirish { + namespace priv { + + static stm32f1_rcc_pll_data pll_data = {BOARD_RCC_PLLMUL}; + __weak rcc_pll_cfg w_board_pll_cfg = {RCC_PLLSRC_HSE, &pll_data}; + __weak adc_prescaler w_adc_pre = ADC_PRE_PCLK2_DIV_6; + __weak adc_smp_rate w_adc_smp = ADC_SMPR_55_5; + + __weak void board_reset_pll(void) { + // TODO + } + + __weak void board_setup_clock_prescalers(void) { + rcc_set_prescaler(RCC_PRESCALER_AHB, RCC_AHB_SYSCLK_DIV_1); + rcc_set_prescaler(RCC_PRESCALER_APB1, RCC_APB1_HCLK_DIV_2); + rcc_set_prescaler(RCC_PRESCALER_APB2, RCC_APB2_HCLK_DIV_1); + rcc_clk_disable(RCC_USB); + #if F_CPU == 72000000 + rcc_set_prescaler(RCC_PRESCALER_USB, RCC_USB_SYSCLK_DIV_1_5); + #elif F_CPU == 48000000 + rcc_set_prescaler(RCC_PRESCALER_USB, RCC_USB_SYSCLK_DIV_1); + #endif + } + + __weak void board_setup_gpio(void) { + gpio_init_all(); + } + + __weak void board_setup_usb(void) { +#ifdef SERIAL_USB + + +#ifdef GENERIC_BOOTLOADER + //Reset the USB interface on generic boards - developed by Victor PV + gpio_set_mode(PIN_MAP[PA12].gpio_device, PIN_MAP[PA12].gpio_bit, GPIO_OUTPUT_PP); + gpio_write_bit(PIN_MAP[PA12].gpio_device, PIN_MAP[PA12].gpio_bit,0); + + for(volatile unsigned int i=0;i<512;i++);// Only small delay seems to be needed, and USB pins will get configured in Serial.begin + gpio_set_mode(PIN_MAP[PA12].gpio_device, PIN_MAP[PA12].gpio_bit, GPIO_INPUT_FLOATING); +#endif + Serial.begin();// Roger Clark. Changed SerialUSB to Serial for Arduino sketch compatibility +#endif + } + + __weak void series_init(void) { + // Initialize AFIO here, too, so peripheral remaps and external + // interrupts work out of the box. + afio_init(); + } + + } +} diff --git a/STM32F1/variants/generic_stm32f103vb/wirish/start.S b/STM32F1/variants/generic_stm32f103vb/wirish/start.S new file mode 100644 index 0000000..8b181aa --- /dev/null +++ b/STM32F1/variants/generic_stm32f103vb/wirish/start.S @@ -0,0 +1,57 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/* + * This file is a modified version of a file obtained from + * CodeSourcery Inc. (now part of Mentor Graphics Corp.), in which the + * following text appeared: + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + */ + + .text + .code 16 + .thumb_func + + .globl __start__ + .type __start__, %function +__start__: + .fnstart + ldr r1,=__msp_init + mov sp,r1 + ldr r1,=start_c + bx r1 + .pool + .cantunwind + .fnend diff --git a/STM32F1/variants/generic_stm32f103vb/wirish/start_c.c b/STM32F1/variants/generic_stm32f103vb/wirish/start_c.c new file mode 100644 index 0000000..655fefb --- /dev/null +++ b/STM32F1/variants/generic_stm32f103vb/wirish/start_c.c @@ -0,0 +1,95 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/* + * This file is a modified version of a file obtained from + * CodeSourcery Inc. (now part of Mentor Graphics Corp.), in which the + * following text appeared: + * + * Copyright (c) 2006, 2007 CodeSourcery Inc + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + */ + +#include + +extern void __libc_init_array(void); + +extern int main(int, char**, char**); + +extern void exit(int) __attribute__((noreturn, weak)); + +/* The linker must ensure that these are at least 4-byte aligned. */ +extern char __data_start__, __data_end__; +extern char __bss_start__, __bss_end__; + +struct rom_img_cfg { + int *img_start; +}; + +extern char _lm_rom_img_cfgp; + +void __attribute__((noreturn)) start_c(void) { + struct rom_img_cfg *img_cfg = (struct rom_img_cfg*)&_lm_rom_img_cfgp; + int *src = img_cfg->img_start; + int *dst = (int*)&__data_start__; + int exit_code; + + /* Initialize .data, if necessary. */ + if (src != dst) { + int *end = (int*)&__data_end__; + while (dst < end) { + *dst++ = *src++; + } + } + + /* Zero .bss. */ + dst = (int*)&__bss_start__; + while (dst < (int*)&__bss_end__) { + *dst++ = 0; + } + + /* Run initializers. */ + __libc_init_array(); + + /* Jump to main. */ + exit_code = main(0, 0, 0); + if (exit) { + exit(exit_code); + } + + /* If exit is NULL, make sure we don't return. */ + for (;;) + continue; +} diff --git a/STM32F1/variants/generic_stm32f103vb/wirish/syscalls.c b/STM32F1/variants/generic_stm32f103vb/wirish/syscalls.c new file mode 100644 index 0000000..ec1c34d --- /dev/null +++ b/STM32F1/variants/generic_stm32f103vb/wirish/syscalls.c @@ -0,0 +1,176 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2011, 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file wirish/syscalls.c + * @brief newlib stubs + * + * Low level system routines used by newlib for basic I/O and memory + * allocation. You can override most of these. + */ + +#include + +#include +#include +#include + +/* If CONFIG_HEAP_START (or CONFIG_HEAP_END) isn't defined, then + * assume _lm_heap_start (resp. _lm_heap_end) is appropriately set by + * the linker */ +#ifndef CONFIG_HEAP_START +extern char _lm_heap_start; +#define CONFIG_HEAP_START ((void *)&_lm_heap_start) +#endif +#ifndef CONFIG_HEAP_END +extern char _lm_heap_end; +#define CONFIG_HEAP_END ((void *)&_lm_heap_end) +#endif + +/* + * _sbrk -- Increment the program break. + * + * Get incr bytes more RAM (for use by the heap). malloc() and + * friends call this function behind the scenes. + */ +void *_sbrk(int incr) { + static void * pbreak = NULL; /* current program break */ + void * ret; + + if (pbreak == NULL) { + pbreak = CONFIG_HEAP_START; + } + + if ((CONFIG_HEAP_END - pbreak < incr) || + (pbreak - CONFIG_HEAP_START < -incr)) { + errno = ENOMEM; + return (void *)-1; + } + + ret = pbreak; + pbreak += incr; + return ret; +} + +__weak int _open(const char *path __attribute__((unused)), int flags __attribute__((unused)), ...) { + return 1; +} + +__weak int _close(int fd __attribute__((unused))) { + return 0; +} + +__weak int _fstat(int fd __attribute__((unused)), struct stat *st) { + st->st_mode = S_IFCHR; + return 0; +} + +__weak int _isatty(int fd __attribute__((unused))) { + return 1; +} + +__weak int isatty(int fd __attribute__((unused))) { + return 1; +} + +__weak int _lseek(int fd __attribute__((unused)), off_t pos __attribute__((unused)), int whence __attribute__((unused))) { + return -1; +} + +__weak unsigned char getch(void) { + return 0; +} + + +__weak int _read(int fd __attribute__((unused)), char *buf, size_t cnt __attribute__((unused))) { + *buf = getch(); + + return 1; +} + +__weak void putch(unsigned char c __attribute__((unused))) { +} + +__weak void cgets(char *s, int bufsize) { + char *p; + int c; + int i; + + for (i = 0; i < bufsize; i++) { + *(s+i) = 0; + } +// memset(s, 0, bufsize); + + p = s; + + for (p = s; p < s + bufsize-1;) { + c = getch(); + switch (c) { + case '\r' : + case '\n' : + putch('\r'); + putch('\n'); + *p = '\n'; + return; + + case '\b' : + if (p > s) { + *p-- = 0; + putch('\b'); + putch(' '); + putch('\b'); + } + break; + + default : + putch(c); + *p++ = c; + break; + } + } + return; +} + +__weak int _write(int fd __attribute__((unused)), const char *buf, size_t cnt) { + int i; + + for (i = 0; i < cnt; i++) + putch(buf[i]); + + return cnt; +} + +/* Override fgets() in newlib with a version that does line editing */ +__weak char *fgets(char *s, int bufsize, void *f __attribute__((unused))) { + cgets(s, bufsize); + return s; +} + +__weak void _exit(int exitcode __attribute__((unused))) { + while (1) + ; +} From 5287d8626857ef6145f5bb31023a59da8928e3a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maik=20W=C3=B6hl?= Date: Sun, 25 Feb 2018 14:00:13 +0100 Subject: [PATCH 285/351] Use useradd instead of adduser ``adduser`` isn't available on all linux systems. usermod is available. --- tools/linux64/install.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/linux64/install.sh b/tools/linux64/install.sh index 29ddb2f..9d4caad 100755 --- a/tools/linux64/install.sh +++ b/tools/linux64/install.sh @@ -17,7 +17,8 @@ if sudo [ -w /etc/udev/rules.d ]; then echo "Reloading udev rules" sudo udevadm control --reload-rules echo "Adding current user to dialout group" - sudo adduser $USER dialout + #sudo adduser $USER dialout + sudo usermod -aG dialout $USER else echo "Couldn't copy to /etc/udev/rules.d/; you probably have to run this script as root? Or your distribution of Linux doesn't include udev; try running the IDE itself as root." fi From 78123aa8fed6a780acb43fb1e50bcb8125c953e0 Mon Sep 17 00:00:00 2001 From: per1234 Date: Mon, 26 Feb 2018 17:36:11 -0800 Subject: [PATCH 286/351] Fix formatting and typos in README.md --- README.md | 39 ++++++++++++++++----------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 9493be9..4f6f377 100644 --- a/README.md +++ b/README.md @@ -1,50 +1,43 @@ -Arduino STM32 -============= +Arduino STM32 +============= ## Notice - This software is experimental and a work in progress. Under no circumstances should these files be used in relation to any critical system(s). Use of these files is at your own risk. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -## Summary: -This repo contains, the "Hardware" files to support STM32 based boards on Arduino version 1.8.x (some older versions may also work) including [LeafLabs Maple, and Maple mini](http://www.leaflabs.com/about-maple/), and other generic STM32F103 boards +## Summary: +This repo contains the "Hardware" files to support STM32 based boards on Arduino version 1.8.x (some older versions may also work) including [LeafLabs Maple, and Maple mini](http://www.leaflabs.com/about-maple/), and other generic STM32F103 boards. ***PRIMARY SUPPORT FORUM: http://www.stm32duino.com/*** ***We are also on Gitter https://gitter.im/stm32duino/Lobby/*** [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/stm32duino/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -## Background & Support: -* Based on https://github.com/bobc/maple-asp, which is in turn based on LibMaple by Leaflabs +## Background & Support: +* Based on https://github.com/bobc/maple-asp, which is in turn based on LibMaple by Leaflabs * **Please read the wiki (https://github.com/rogerclarkmelbourne/Arduino_STM32/wiki) for full details** -* See also my blog: http://www.rogerclark.net/stm32f103-and-maple-maple-mini-with-arduino-1-5-x-ide/ -* **NEW: Main support site for using STM32 boards with the Arduino IDE: http://www.stm32duino.com/** +* See also my blog: http://www.rogerclark.net/stm32f103-and-maple-maple-mini-with-arduino-1-5-x-ide/ +* **NEW: Main support site for using STM32 boards with the Arduino IDE: http://www.stm32duino.com/** * Original LeafLabs "Docs:" http://docs.leaflabs.com/docs.leaflabs.com/index.html -**YouTube Videos:** +**YouTube Videos:** * 20141116: [Arduino 1.5.8 IDE with STM32 board](https://www.youtube.com/watch?v=-zwGnytGT8M) * 20150413: [STM32 for Arduino 1.6.2 or newer (update)](https://www.youtube.com/watch?v=TePglhSkghg) * 20150419: [Uploading via USB to Serial to STM32F103 boards](https://www.youtube.com/watch?v=G_RF0a0hrak) -## Additional Links & Info: -* https://www.hackster.io/rayburne/4-dollar-90-mips-32-bit-72-mhz-arm-arduino +## Additional Links & Info: +* https://www.hackster.io/rayburne/4-dollar-90-mips-32-bit-72-mhz-arm-arduino -## Purchase info: +## Purchase info: ### Entry level boards - * [Ebay search for "arduino maple"](http://www.ebay.com/sch/i.html?_from=R40&_sacat=0&LH_BIN=1&_nkw=arduino+maple&_sop=15) (currently costs <$5 with shipping) -* [AliExpress search for "leaflabs maple"] (http://www.aliexpress.com/wholesale?catId=0&initiative_id=SB_20150607085526&SearchText=leaflabs+maple) +* [AliExpress search for "leaflabs maple"](http://www.aliexpress.com/wholesale?catId=0&initiative_id=SB_20150607085526&SearchText=leaflabs+maple) ### Bigger boards (You need to load the stm32duino bootloader) - -Some supplier have this board e.g. - -*[ STM32F103VET ](http://www.ebay.com.au/itm/1PCS-STM32F103VET6-ARM-STM32-Minimum-System-Development-Board-Arduino-M77-/301433302819) - -*[There is also a STM32F103ZET board which also works, however they are not always available. They have been listed as "STM32F103ZET6 Minimum System Development Board ARM STM32 Cortex-m3 M75"] -(http://www.ebay.com.au/itm/1pcs-STM32F103ZET6-Minimum-System-Development-Board-ARM-STM32-Cortex-m3-M75-/291305557264) - +Some suppliers have this board e.g. +* [ STM32F103VET ](http://www.ebay.com.au/itm/1PCS-STM32F103VET6-ARM-STM32-Minimum-System-Development-Board-Arduino-M77-/301433302819) +* [There is also a STM32F103ZET board which also works, however they are not always available. They have been listed as "STM32F103ZET6 Minimum System Development Board ARM STM32 Cortex-m3 M75"](http://www.ebay.com.au/itm/1pcs-STM32F103ZET6-Minimum-System-Development-Board-ARM-STM32-Cortex-m3-M75-/291305557264) From 075eae588504184591583cc2ff189cf62874f8e9 Mon Sep 17 00:00:00 2001 From: MackPi Date: Sat, 3 Mar 2018 17:40:14 -0800 Subject: [PATCH 287/351] Added Variant STM32F103VB Added Board Varient STM32F103VB. Replaced #ifdef STM32_HIGH_DENSITY with #if STM32_NR_PORTS > 4 Where it makes sense for High Pin count medium density parts like the STM32F103VB. --- .../generic_stm32f103vb/ld/flash_c8.ld | 33 ----------------- .../generic_stm32f103vb/ld/jtag_c8.ld | 36 ------------------- .../variants/generic_stm32f103vb/ld/ram_c8.ld | 31 ---------------- 3 files changed, 100 deletions(-) delete mode 100644 STM32F1/variants/generic_stm32f103vb/ld/flash_c8.ld delete mode 100644 STM32F1/variants/generic_stm32f103vb/ld/jtag_c8.ld delete mode 100644 STM32F1/variants/generic_stm32f103vb/ld/ram_c8.ld diff --git a/STM32F1/variants/generic_stm32f103vb/ld/flash_c8.ld b/STM32F1/variants/generic_stm32f103vb/ld/flash_c8.ld deleted file mode 100644 index 4603923..0000000 --- a/STM32F1/variants/generic_stm32f103vb/ld/flash_c8.ld +++ /dev/null @@ -1,33 +0,0 @@ -/* - * libmaple linker script for "Flash" builds. - * - * A Flash build puts .text (and .rodata) in Flash, and - * .data/.bss/heap (of course) in SRAM, but offsets the sections by - * enough space to store the Maple bootloader, which lives in low - * Flash and uses low memory. - */ - -/* - * This pulls in the appropriate MEMORY declaration from the right - * subdirectory of stm32/mem/ (the environment must call ld with the - * right include directory flags to make this happen). Boards can also - * use this file to use any of libmaple's memory-related hooks (like - * where the heap should live). - */ -/*INCLUDE mem-flash.inc*/ - -MEMORY -{ - ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 17K - rom (rx) : ORIGIN = 0x08000000, LENGTH = 44K -} - - -/* Provide memory region aliases for common.inc */ -REGION_ALIAS("REGION_TEXT", rom); -REGION_ALIAS("REGION_DATA", ram); -REGION_ALIAS("REGION_BSS", ram); -REGION_ALIAS("REGION_RODATA", rom); - -/* Let common.inc handle the real work. */ -INCLUDE common.inc diff --git a/STM32F1/variants/generic_stm32f103vb/ld/jtag_c8.ld b/STM32F1/variants/generic_stm32f103vb/ld/jtag_c8.ld deleted file mode 100644 index d9d4a0f..0000000 --- a/STM32F1/variants/generic_stm32f103vb/ld/jtag_c8.ld +++ /dev/null @@ -1,36 +0,0 @@ -/* - * libmaple linker script for "JTAG" builds. - * - * A "JTAG" build puts .text (and .rodata) in Flash, and - * .data/.bss/heap (of course) in SRAM, but links starting at the - * Flash and SRAM starting addresses (0x08000000 and 0x20000000 - * respectively). This will wipe out a Maple bootloader if there's one - * on the board, so only use this if you know what you're doing. - * - * Of course, a "JTAG" build is perfectly usable for upload over SWD, - * the system memory bootloader, etc. The name is just a historical - * artifact. - */ - -/* - * This pulls in the appropriate MEMORY declaration from the right - * subdirectory of stm32/mem/ (the environment must call ld with the - * right include directory flags to make this happen). Boards can also - * use this file to use any of libmaple's memory-related hooks (like - * where the heap should live). - */ - -MEMORY -{ - ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K - rom (rx) : ORIGIN = 0x08000000, LENGTH = 64K -} - -/* Provide memory region aliases for common.inc */ -REGION_ALIAS("REGION_TEXT", rom); -REGION_ALIAS("REGION_DATA", ram); -REGION_ALIAS("REGION_BSS", ram); -REGION_ALIAS("REGION_RODATA", rom); - -/* Let common.inc handle the real work. */ -INCLUDE common.inc diff --git a/STM32F1/variants/generic_stm32f103vb/ld/ram_c8.ld b/STM32F1/variants/generic_stm32f103vb/ld/ram_c8.ld deleted file mode 100644 index 71e081e..0000000 --- a/STM32F1/variants/generic_stm32f103vb/ld/ram_c8.ld +++ /dev/null @@ -1,31 +0,0 @@ -/* - * libmaple linker script for RAM builds. - * - * A Flash build puts .text, .rodata, and .data/.bss/heap (of course) - * in SRAM, but offsets the sections by enough space to store the - * Maple bootloader, which uses low memory. - */ - -/* - * This pulls in the appropriate MEMORY declaration from the right - * subdirectory of stm32/mem/ (the environment must call ld with the - * right include directory flags to make this happen). Boards can also - * use this file to use any of libmaple's memory-related hooks (like - * where the heap should live). - */ -/*INCLUDE mem-ram.inc*/ -MEMORY -{ - ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 17K - rom (rx) : ORIGIN = 0x08005000, LENGTH = 0 -} - - -/* Provide memory region aliases for common.inc */ -REGION_ALIAS("REGION_TEXT", ram); -REGION_ALIAS("REGION_DATA", ram); -REGION_ALIAS("REGION_BSS", ram); -REGION_ALIAS("REGION_RODATA", ram); - -/* Let common.inc handle the real work. */ -INCLUDE common.inc From 25e2945cd811af0d5b7cc9893258ef3c6063b216 Mon Sep 17 00:00:00 2001 From: madias123 Date: Mon, 12 Mar 2018 23:46:29 +0100 Subject: [PATCH 288/351] Update TouchButtons.ino Compatibility: Using Serial instead of Serial1 --- .../examples/TouchButtons/TouchButtons.ino | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/STM32F1/libraries/Serasidis_XPT2046_touch/examples/TouchButtons/TouchButtons.ino b/STM32F1/libraries/Serasidis_XPT2046_touch/examples/TouchButtons/TouchButtons.ino index 5ca9606..c710c6a 100644 --- a/STM32F1/libraries/Serasidis_XPT2046_touch/examples/TouchButtons/TouchButtons.ino +++ b/STM32F1/libraries/Serasidis_XPT2046_touch/examples/TouchButtons/TouchButtons.ino @@ -32,12 +32,12 @@ XPT2046_touch ts(CS_PIN, mySPI); // Chip Select pin, SPI port uint16_t xy[2]; void setup() { - Serial1.begin(9600); - Serial1.println("-------------------------------------------------"); - Serial1.println("XPT2046 touch screen buttons"); - Serial1.println("Copyright (c) 02 Dec 2015 by Vassilis Serasidis"); - Serial1.println("Home: http://www.serasidis.gr"); - Serial1.println("-------------------------------------------------"); + Serial.begin(9600); + Serial.println("-------------------------------------------------"); + Serial.println("XPT2046 touch screen buttons"); + Serial.println("Copyright (c) 02 Dec 2015 by Vassilis Serasidis"); + Serial.println("Home: http://www.serasidis.gr"); + Serial.println("-------------------------------------------------"); ts.begin(); //Begin TouchScreen. ts.setButtonsNumber(COLUMNS, LINES); //Divide the Touch screen area into 4 columns and 2 lines and make them act as buttons. } @@ -46,15 +46,15 @@ void loop() { if(ts.read_XY(xy)){ //If the touch screen is preesed, read the X,Y coordinates and print them on Serial port. uint8_t buttonNumber = ts.getButtonNumber(); if(buttonNumber > 0){ - Serial1.print("Button: "); - Serial1.println(buttonNumber); + Serial.print("Button: "); + Serial.println(buttonNumber); - Serial1.print("X: "); - Serial1.println(xy[0]); //Print X value - Serial1.print("Y: "); - Serial1.println(xy[1]); //Print Y value - Serial1.println(); + Serial.print("X: "); + Serial.println(xy[0]); //Print X value + Serial.print("Y: "); + Serial.println(xy[1]); //Print Y value + Serial.println(); } delay(500); } -} \ No newline at end of file +} From 7e13702bcbf77d29fdfea0a5fe5efdb0b7737984 Mon Sep 17 00:00:00 2001 From: Thomas Friedrichsmeier Date: Tue, 13 Mar 2018 17:48:20 +0100 Subject: [PATCH 289/351] Some updates to the XPT2046 touchscreen library: - Add TS_Point-class and getter for better compatibility with various other touchscreen libraries out there - Add oversampling for better accuracy. Default is seven samples per point - Use SPI.beginTransaction() / endTransaction() to set proper SPI speed (as supported by XPT2046) --- .../src/XPT2046_touch.cpp | 132 ++++++++++-------- .../src/XPT2046_touch.h | 40 +++++- 2 files changed, 110 insertions(+), 62 deletions(-) diff --git a/STM32F1/libraries/Serasidis_XPT2046_touch/src/XPT2046_touch.cpp b/STM32F1/libraries/Serasidis_XPT2046_touch/src/XPT2046_touch.cpp index d1b0bdf..71160b1 100644 --- a/STM32F1/libraries/Serasidis_XPT2046_touch/src/XPT2046_touch.cpp +++ b/STM32F1/libraries/Serasidis_XPT2046_touch/src/XPT2046_touch.cpp @@ -8,81 +8,97 @@ #include "Arduino.h" #include "XPT2046_touch.h" +XPT2046_touch::XPT2046_touch(uint8_t _cs_pin, SPIClass _spiChan) : cs_pin(_cs_pin), my_SPI(_spiChan){ + setOversampling(); + setThreshold(); +} -/****************************************************************************/ - XPT2046_touch::XPT2046_touch(uint8_t _cs_pin, SPIClass _spiChan) : cs_pin(_cs_pin), my_SPI(_spiChan){ - } - - -/****************************************************************************/ - - void XPT2046_touch::begin(){ +void XPT2046_touch::begin(){ pinMode(cs_pin, OUTPUT); digitalWrite(cs_pin, HIGH); my_SPI.begin(); - } +} - /****************************************************************************/ +uint16_t XPT2046_touch::gatherSamples(uint8_t command) { + uint32_t sample_sum = 0; + uint16_t samples[MAX_OVERSAMPLING]; - boolean XPT2046_touch::read_XY(uint16_t *xy){ - int z1, z2, tmpH, tmpL; + my_SPI.transfer16(command); // discard first reading after switching MUX + for (int i = 0; i < oversampling; ++i) { + samples[i] = my_SPI.transfer16(command); + sample_sum += samples[i]; + } + int32_t avg = sample_sum / oversampling; + if (oversampling < 3) { + return avg >> 3; + } + + // occasionally, we get a reading that is a _far_ outlier. + // checking for, and removing those improves quality a lot. + uint8_t n = oversampling; + for (int i = 0; i < oversampling; ++i) { + if (abs(avg - samples[i]) > 80) { // NOTE: data is left shifted by 3 at this point. I.e. the test is for 10+ pixels deviation from average + sample_sum -= samples[i]; + --n; + } + } + if (n < 2) return avg >> 3; + else return (sample_sum / n) >> 3; +} + +TS_Point XPT2046_touch::getPoint() { + uint16_t z1, z2; + + my_SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0)); // max clock freq for XPT2046 digitalWrite(cs_pin, LOW); + TS_Point ret; //Check if touch screen is pressed. - SPI.transfer(B10110011); // Z1 - delay(10); - tmpH = (my_SPI.transfer(0) << 5); - tmpL = (my_SPI.transfer(0) >> 3); - z1 = tmpH | tmpL; + SPI.transfer(B10110011); // trigger Z1 reading + z1 = my_SPI.transfer16(B11000011) >> 3; // read Z1, and trigger Z2 reading + z2 = my_SPI.transfer16(B10010011) >> 3; // read Z2, and trigger Y reading + ret.z = z1 + 4095 - z2; - SPI.transfer(B11000011); // Z2 - delay(10); - tmpH = (my_SPI.transfer(0) << 5); - tmpL = (my_SPI.transfer(0) >> 3); - z2 = tmpH | tmpL; - - if((z2 - z1) < Z_THRESHOLD){ //If the touch screen is pressed, read the X,Y coordinates from XPT2046. - my_SPI.transfer(B11010011); // X - delay(10); - tmpH = (my_SPI.transfer(0) << 5); - tmpL = (my_SPI.transfer(0) >> 3); - xy[0] = tmpH | tmpL; - - my_SPI.transfer(B10010011); // Y - delay(10); - tmpH = (my_SPI.transfer(0) << 5); - tmpL = (my_SPI.transfer(0) >> 3); - xy[1] = tmpH | tmpL; - digitalWrite(cs_pin, HIGH); - return true; + if(ret.z >= threshold){ //If the touch screen is pressed, read the X,Y coordinates from XPT2046. + ret.z = z1 + 4095 - z2; + ret.x = gatherSamples(B10010011); + ret.y = gatherSamples(B11010011); + } else { + ret.z = 0; } + digitalWrite(cs_pin, HIGH); - return false; - } - - /****************************************************************************/ - void XPT2046_touch::setButtonsNumber(byte columnButtons, byte rowButtons ){ - _rowButtons = rowButtons; - _columnButtons = columnButtons; - } - - /****************************************************************************/ - uint8_t XPT2046_touch::getButtonNumber(){ + my_SPI.endTransaction(); + return ret; +} + +boolean XPT2046_touch::read_XY(uint16_t *xy) { + TS_Point p = getPoint(); + xy[0] = p.x; + xy[1] = p.y; + return p.z > 0; +} + +////////////////// Buttons //////////////// +void XPT2046_touch::setButtonsNumber(byte columnButtons, byte rowButtons ){ + _rowButtons = rowButtons; + _columnButtons = columnButtons; +} + +uint8_t XPT2046_touch::getButtonNumber(){ uint16_t xy[2]; uint8_t tmp, buttonNum; int div; if(read_XY(xy)){ - - div = (X_MAX + X_MIN) / (_columnButtons + 1); - buttonNum = ((xy[1] / div)); - - div = (Y_MAX + Y_MIN) / _rowButtons; - tmp = ((xy[0] / div)); - - return ((buttonNum * _rowButtons) + tmp + 1); //Return the button number. + div = (X_MAX + X_MIN) / (_columnButtons + 1); + buttonNum = ((xy[1] / div)); + + div = (Y_MAX + Y_MIN) / _rowButtons; + tmp = ((xy[0] / div)); + + return ((buttonNum * _rowButtons) + tmp + 1); //Return the button number. } return 0; //Touch screen is not pressed. - } -/****************************************************************************/ +} diff --git a/STM32F1/libraries/Serasidis_XPT2046_touch/src/XPT2046_touch.h b/STM32F1/libraries/Serasidis_XPT2046_touch/src/XPT2046_touch.h index 0830162..9fbea6a 100644 --- a/STM32F1/libraries/Serasidis_XPT2046_touch/src/XPT2046_touch.h +++ b/STM32F1/libraries/Serasidis_XPT2046_touch/src/XPT2046_touch.h @@ -11,7 +11,8 @@ #include #include -#define Z_THRESHOLD 3000 +#define Z_THRESHOLD 3500 // Note: reversed for backwards compatiblity: 4095-x +#define MAX_OVERSAMPLING 32 // Pre-defined touch screen calibration for using the 2.4" ILI9341 LCD #define X_MIN 830 @@ -19,23 +20,54 @@ #define Y_MIN 550 #define Y_MAX 3550 + +class TS_Point { +public: + TS_Point(void) : x(0), y(0), z(0) {} + TS_Point(int16_t x, int16_t y, int16_t z) : x(x), y(y), z(z) {} + bool operator==(TS_Point p) { return ((p.x == x) && (p.y == y) && (p.z == z)); } + bool operator!=(TS_Point p) { return ((p.x != x) || (p.y != y) || (p.z != z)); } + int16_t x, y, z; +}; + /** * */ - -class XPT2046_touch{ +class XPT2046_touch { private: uint8_t cs_pin; SPIClass my_SPI; uint8_t _rowButtons = 1; uint8_t _columnButtons = 1; + uint8_t oversampling; + uint16_t threshold; + uint16_t gatherSamples(uint8_t command); public: - XPT2046_touch(uint8_t _cs_pin, SPIClass _spiChan); //Contructor. + /** c'tor. Note that no IRQ pin is supported, here. You can easily do that yourself: + * \code if(digitalRead(irq_pin)) { + * // no press: skip + * } else { + * // _may_ be touched, but not necessarily reach the threshold + * TS_Point p = ts.getPoint(); + * if (p.z > 0) { + * // do something + * } + * } + * \endcode */ + XPT2046_touch(uint8_t _cs_pin, SPIClass _spiChan); //Contructor void begin(); void setButtonsNumber(byte rowButtons, byte columnButtons); + /** Number of samples to average per point 0..32 */ + void setOversampling(uint8_t num_readings = 7) { + oversampling = max(1, min(num_readings, MAX_OVERSAMPLING)); + } + void setThreshold(uint16_t threshold = 4095 - Z_THRESHOLD) { + XPT2046_touch::threshold = threshold; + } uint8_t getButtonNumber(); boolean read_XY(uint16_t *xy); + TS_Point getPoint(); }; #endif From 97dbf08a5eee98faf7d5db682219802dffa9c13b Mon Sep 17 00:00:00 2001 From: Thomas Friedrichsmeier Date: Tue, 13 Mar 2018 20:55:45 +0100 Subject: [PATCH 290/351] Small fixes --- .../libraries/Serasidis_XPT2046_touch/src/XPT2046_touch.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/STM32F1/libraries/Serasidis_XPT2046_touch/src/XPT2046_touch.cpp b/STM32F1/libraries/Serasidis_XPT2046_touch/src/XPT2046_touch.cpp index 71160b1..f24c67a 100644 --- a/STM32F1/libraries/Serasidis_XPT2046_touch/src/XPT2046_touch.cpp +++ b/STM32F1/libraries/Serasidis_XPT2046_touch/src/XPT2046_touch.cpp @@ -54,18 +54,18 @@ TS_Point XPT2046_touch::getPoint() { TS_Point ret; //Check if touch screen is pressed. - SPI.transfer(B10110011); // trigger Z1 reading + my_SPI.transfer(B10110011); // trigger Z1 reading z1 = my_SPI.transfer16(B11000011) >> 3; // read Z1, and trigger Z2 reading z2 = my_SPI.transfer16(B10010011) >> 3; // read Z2, and trigger Y reading ret.z = z1 + 4095 - z2; if(ret.z >= threshold){ //If the touch screen is pressed, read the X,Y coordinates from XPT2046. - ret.z = z1 + 4095 - z2; ret.x = gatherSamples(B10010011); ret.y = gatherSamples(B11010011); } else { ret.z = 0; } + my_SPI.transfer(B00000000); // enter power saving (and IRQ enable) digitalWrite(cs_pin, HIGH); my_SPI.endTransaction(); From ca3ead06b3fb50722555754488f89fbe16b5aa45 Mon Sep 17 00:00:00 2001 From: Thomas Friedrichsmeier Date: Wed, 14 Mar 2018 21:45:27 +0100 Subject: [PATCH 291/351] Base Adafruit_GFX_AS on Adafruit_GFX, keeping only the additiona in a derived class. The point of this is to make drivers based on Adafruit_GFX_AS compatible with Adafruit_GFX, without breaking existing code written for Adafruit_GFX_AS. See also http://stm32duino.com/viewtopic.php?f=9&t=3352 --- .../Adafruit_GFX_AS/Adafruit_GFX_AS.cpp | 452 +----------------- .../Adafruit_GFX_AS/Adafruit_GFX_AS.h | 94 +--- .../Adafruit_ILI9341_STM.cpp | 2 +- .../Adafruit_ILI9341_STM.h | 2 +- 4 files changed, 22 insertions(+), 528 deletions(-) diff --git a/STM32F1/libraries/Adafruit_GFX_AS/Adafruit_GFX_AS.cpp b/STM32F1/libraries/Adafruit_GFX_AS/Adafruit_GFX_AS.cpp index 333b122..7d561f8 100644 --- a/STM32F1/libraries/Adafruit_GFX_AS/Adafruit_GFX_AS.cpp +++ b/STM32F1/libraries/Adafruit_GFX_AS/Adafruit_GFX_AS.cpp @@ -59,451 +59,15 @@ POSSIBILITY OF SUCH DAMAGE. #define pgm_read_byte(addr) (*(const unsigned char *)(addr)) #endif -Adafruit_GFX::Adafruit_GFX(int16_t w, int16_t h): - WIDTH(w), HEIGHT(h) +Adafruit_GFX_AS::Adafruit_GFX_AS(int16_t w, int16_t h): Adafruit_GFX(w, h) { - _width = WIDTH; - _height = HEIGHT; - rotation = 0; - cursor_y = cursor_x = 0; - textsize = 1; - textcolor = textbgcolor = 0xFFFF; - wrap = true; -} - -// Draw a circle outline -void Adafruit_GFX::drawCircle(int16_t x0, int16_t y0, int16_t r, - uint16_t color) { - int16_t f = 1 - r; - int16_t ddF_x = 1; - int16_t ddF_y = -2 * r; - int16_t x = 0; - int16_t y = r; - - drawPixel(x0 , y0+r, color); - drawPixel(x0 , y0-r, color); - drawPixel(x0+r, y0 , color); - drawPixel(x0-r, y0 , color); - - while (x= 0) { - y--; - ddF_y += 2; - f += ddF_y; - } - x++; - ddF_x += 2; - f += ddF_x; - - drawPixel(x0 + x, y0 + y, color); - drawPixel(x0 - x, y0 + y, color); - drawPixel(x0 + x, y0 - y, color); - drawPixel(x0 - x, y0 - y, color); - drawPixel(x0 + y, y0 + x, color); - drawPixel(x0 - y, y0 + x, color); - drawPixel(x0 + y, y0 - x, color); - drawPixel(x0 - y, y0 - x, color); - } -} - -void Adafruit_GFX::drawCircleHelper( int16_t x0, int16_t y0, - int16_t r, uint8_t cornername, uint16_t color) { - int16_t f = 1 - r; - int16_t ddF_x = 1; - int16_t ddF_y = -2 * r; - int16_t x = 0; - int16_t y = r; - - while (x= 0) { - y--; - ddF_y += 2; - f += ddF_y; - } - x++; - ddF_x += 2; - f += ddF_x; - if (cornername & 0x4) { - drawPixel(x0 + x, y0 + y, color); - drawPixel(x0 + y, y0 + x, color); - } - if (cornername & 0x2) { - drawPixel(x0 + x, y0 - y, color); - drawPixel(x0 + y, y0 - x, color); - } - if (cornername & 0x8) { - drawPixel(x0 - y, y0 + x, color); - drawPixel(x0 - x, y0 + y, color); - } - if (cornername & 0x1) { - drawPixel(x0 - y, y0 - x, color); - drawPixel(x0 - x, y0 - y, color); - } - } -} - -void Adafruit_GFX::fillCircle(int16_t x0, int16_t y0, int16_t r, - uint16_t color) { - drawFastVLine(x0, y0-r, 2*r+1, color); - fillCircleHelper(x0, y0, r, 3, 0, color); -} - -// Used to do circles and roundrects -void Adafruit_GFX::fillCircleHelper(int16_t x0, int16_t y0, int16_t r, - uint8_t cornername, int16_t delta, uint16_t color) { - - int16_t f = 1 - r; - int16_t ddF_x = 1; - int16_t ddF_y = -2 * r; - int16_t x = 0; - int16_t y = r; - - while (x= 0) { - y--; - ddF_y += 2; - f += ddF_y; - } - x++; - ddF_x += 2; - f += ddF_x; - - if (cornername & 0x1) { - drawFastVLine(x0+x, y0-y, 2*y+1+delta, color); - drawFastVLine(x0+y, y0-x, 2*x+1+delta, color); - } - if (cornername & 0x2) { - drawFastVLine(x0-x, y0-y, 2*y+1+delta, color); - drawFastVLine(x0-y, y0-x, 2*x+1+delta, color); - } - } -} - -// Bresenham's algorithm - thx wikpedia -void Adafruit_GFX::drawLine(int16_t x0, int16_t y0, - int16_t x1, int16_t y1, - uint16_t color) { - int16_t steep = abs(y1 - y0) > abs(x1 - x0); - if (steep) { - swap(x0, y0); - swap(x1, y1); - } - - if (x0 > x1) { - swap(x0, x1); - swap(y0, y1); - } - - int16_t dx, dy; - dx = x1 - x0; - dy = abs(y1 - y0); - - int16_t err = dx / 2; - int16_t ystep; - - if (y0 < y1) { - ystep = 1; - } else { - ystep = -1; - } - - for (; x0<=x1; x0++) { - if (steep) { - drawPixel(y0, x0, color); - } else { - drawPixel(x0, y0, color); - } - err -= dy; - if (err < 0) { - y0 += ystep; - err += dx; - } - } -} - -// Draw a rectangle -void Adafruit_GFX::drawRect(int16_t x, int16_t y, - int16_t w, int16_t h, - uint16_t color) { - drawFastHLine(x, y, w, color); - drawFastHLine(x, y+h-1, w, color); - drawFastVLine(x, y, h, color); - drawFastVLine(x+w-1, y, h, color); -} - -void Adafruit_GFX::drawFastVLine(int16_t x, int16_t y, - int16_t h, uint16_t color) { - // Update in subclasses if desired! - drawLine(x, y, x, y+h-1, color); -} - -void Adafruit_GFX::drawFastHLine(int16_t x, int16_t y, - int16_t w, uint16_t color) { - // Update in subclasses if desired! - drawLine(x, y, x+w-1, y, color); -} - -void Adafruit_GFX::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, - uint16_t color) { - // Update in subclasses if desired! - for (int16_t i=x; i= y1 >= y0) - if (y0 > y1) { - swap(y0, y1); swap(x0, x1); - } - if (y1 > y2) { - swap(y2, y1); swap(x2, x1); - } - if (y0 > y1) { - swap(y0, y1); swap(x0, x1); - } - - if(y0 == y2) { // Handle awkward all-on-same-line case as its own thing - a = b = x0; - if(x1 < a) a = x1; - else if(x1 > b) b = x1; - if(x2 < a) a = x2; - else if(x2 > b) b = x2; - drawFastHLine(a, y0, b-a+1, color); - return; - } - - int16_t - dx01 = x1 - x0, - dy01 = y1 - y0, - dx02 = x2 - x0, - dy02 = y2 - y0, - dx12 = x2 - x1, - dy12 = y2 - y1, - sa = 0, - sb = 0; - - // For upper part of triangle, find scanline crossings for segments - // 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1 - // is included here (and second loop will be skipped, avoiding a /0 - // error there), otherwise scanline y1 is skipped here and handled - // in the second loop...which also avoids a /0 error here if y0=y1 - // (flat-topped triangle). - if(y1 == y2) last = y1; // Include y1 scanline - else last = y1-1; // Skip it - - for(y=y0; y<=last; y++) { - a = x0 + sa / dy01; - b = x0 + sb / dy02; - sa += dx01; - sb += dx02; - /* longhand: - a = x0 + (x1 - x0) * (y - y0) / (y1 - y0); - b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); - */ - if(a > b) swap(a,b); - drawFastHLine(a, y, b-a+1, color); - } - - // For lower part of triangle, find scanline crossings for segments - // 0-2 and 1-2. This loop is skipped if y1=y2. - sa = dx12 * (y - y1); - sb = dx02 * (y - y0); - for(; y<=y2; y++) { - a = x1 + sa / dy12; - b = x0 + sb / dy02; - sa += dx12; - sb += dx02; - /* longhand: - a = x1 + (x2 - x1) * (y - y1) / (y2 - y1); - b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); - */ - if(a > b) swap(a,b); - drawFastHLine(a, y, b-a+1, color); - } -} - -void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, - const uint8_t *bitmap, int16_t w, int16_t h, - uint16_t color) { - - int16_t i, j, byteWidth = (w + 7) / 8; - - for(j=0; j> (i & 7))) { - drawPixel(x+i, y+j, color); - } - } - } -} - -//#if ARDUINO >= 100 -size_t Adafruit_GFX::write(uint8_t c) { -//#else -//void Adafruit_GFX::write(uint8_t c) { -//#endif - if (c == '\n') { - cursor_y += textsize*8; - cursor_x = 0; - } else if (c == '\r') { - // skip em - } else { - drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize); - cursor_x += textsize*6; - if (wrap && (cursor_x > (_width - textsize*6))) { - cursor_y += textsize*8; - cursor_x = 0; - } - } -//#if ARDUINO >= 100 - return 1; -//#endif -} - -// Draw a character -void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c, - uint16_t color, uint16_t bg, uint8_t size) { -#ifdef LOAD_GLCD - if((x >= _width) || // Clip right - (y >= _height) || // Clip bottom - ((x + 6 * size - 1) < 0) || // Clip left - ((y + 8 * size - 1) < 0)) // Clip top - return; - - for (int8_t i=0; i<6; i++ ) { - uint8_t line; - if (i == 5) - line = 0x0; - else - line = pgm_read_byte(font+(c*5)+i); - for (int8_t j = 0; j<8; j++) { - if (line & 0x1) { - if (size == 1) // default size - drawPixel(x+i, y+j, color); - else { // big size - fillRect(x+(i*size), y+(j*size), size, size, color); - } - } else if (bg != color) { - if (size == 1) // default size - drawPixel(x+i, y+j, bg); - else { // big size - fillRect(x+i*size, y+j*size, size, size, bg); - } - } - line >>= 1; - } - } -#endif -} - -void Adafruit_GFX::setCursor(int16_t x, int16_t y) { - cursor_x = x; - cursor_y = y; -} - -void Adafruit_GFX::setTextSize(uint8_t s) { - textsize = (s > 0) ? s : 1; -} - -void Adafruit_GFX::setTextColor(uint16_t c) { - // For 'transparent' background, we'll set the bg - // to the same as fg instead of using a flag - textcolor = textbgcolor = c; -} - -void Adafruit_GFX::setTextColor(uint16_t c, uint16_t b) { - textcolor = c; - textbgcolor = b; -} - -void Adafruit_GFX::setTextWrap(boolean w) { - wrap = w; -} - -uint8_t Adafruit_GFX::getRotation(void) { - return rotation; -} - -void Adafruit_GFX::setRotation(uint8_t x) { - rotation = (x & 3); - switch(rotation) { - case 0: - case 2: - _width = WIDTH; - _height = HEIGHT; - break; - case 1: - case 3: - _width = HEIGHT; - _height = WIDTH; - break; - } -} - -// Return the size of the display (per current rotation) -int16_t Adafruit_GFX::width(void) { - return _width; -} - -int16_t Adafruit_GFX::height(void) { - return _height; -} - -void Adafruit_GFX::invertDisplay(boolean i) { - // Do nothing, must be subclassed if supported } /*************************************************************************************** ** Function name: drawUnicode ** Descriptions: draw a unicode ***************************************************************************************/ -int16_t Adafruit_GFX::drawUnicode(uint16_t uniCode, int16_t x, int16_t y, int16_t size) +int16_t Adafruit_GFX_AS::drawUnicode(uint16_t uniCode, int16_t x, int16_t y, int16_t size) { if (size) uniCode -= 32; @@ -615,7 +179,7 @@ return (width+gap)*textsize; // x + ** Function name: drawNumber unsigned with size ** Descriptions: drawNumber ***************************************************************************************/ -int16_t Adafruit_GFX::drawNumber(long long_num,int16_t poX, int16_t poY, int16_t size) +int16_t Adafruit_GFX_AS::drawNumber(long long_num,int16_t poX, int16_t poY, int16_t size) { char tmp[10]; if (long_num < 0) sprintf(tmp, "%li", long_num); @@ -627,7 +191,7 @@ int16_t Adafruit_GFX::drawNumber(long long_num,int16_t poX, int16_t poY, int16_t ** Function name: drawChar ** Descriptions: draw char ***************************************************************************************/ -int16_t Adafruit_GFX::drawChar(char c, int16_t x, int16_t y, int16_t size) +int16_t Adafruit_GFX_AS::drawChar(char c, int16_t x, int16_t y, int16_t size) { return drawUnicode(c, x, y, size); } @@ -636,7 +200,7 @@ int16_t Adafruit_GFX::drawChar(char c, int16_t x, int16_t y, int16_t size) ** Function name: drawString ** Descriptions: draw string ***************************************************************************************/ -int16_t Adafruit_GFX::drawString(char *string, int16_t poX, int16_t poY, int16_t size) +int16_t Adafruit_GFX_AS::drawString(char *string, int16_t poX, int16_t poY, int16_t size) { int16_t sumX = 0; @@ -654,7 +218,7 @@ int16_t Adafruit_GFX::drawString(char *string, int16_t poX, int16_t poY, int16_t ** Function name: drawCentreString ** Descriptions: draw string across centre ***************************************************************************************/ -int16_t Adafruit_GFX::drawCentreString(char *string, int16_t dX, int16_t poY, int16_t size) +int16_t Adafruit_GFX_AS::drawCentreString(char *string, int16_t dX, int16_t poY, int16_t size) { int16_t sumX = 0; int16_t len = 0; @@ -703,7 +267,7 @@ int16_t Adafruit_GFX::drawCentreString(char *string, int16_t dX, int16_t poY, in ** Function name: drawRightString ** Descriptions: draw string right justified ***************************************************************************************/ -int16_t Adafruit_GFX::drawRightString(char *string, int16_t dX, int16_t poY, int16_t size) +int16_t Adafruit_GFX_AS::drawRightString(char *string, int16_t dX, int16_t poY, int16_t size) { int16_t sumX = 0; int16_t len = 0; @@ -754,7 +318,7 @@ int16_t Adafruit_GFX::drawRightString(char *string, int16_t dX, int16_t poY, int ** Function name: drawFloat ** Descriptions: drawFloat ***************************************************************************************/ -int16_t Adafruit_GFX::drawFloat(float floatNumber, int16_t decimal, int16_t poX, int16_t poY, int16_t size) +int16_t Adafruit_GFX_AS::drawFloat(float floatNumber, int16_t decimal, int16_t poX, int16_t poY, int16_t size) { unsigned long temp=0; float decy=0.0; diff --git a/STM32F1/libraries/Adafruit_GFX_AS/Adafruit_GFX_AS.h b/STM32F1/libraries/Adafruit_GFX_AS/Adafruit_GFX_AS.h index 974c47c..93055a5 100644 --- a/STM32F1/libraries/Adafruit_GFX_AS/Adafruit_GFX_AS.h +++ b/STM32F1/libraries/Adafruit_GFX_AS/Adafruit_GFX_AS.h @@ -1,64 +1,20 @@ -#ifndef _ADAFRUIT_GFX_H -#define _ADAFRUIT_GFX_H +#ifndef _ADAFRUIT_GFX_AS_H +#define _ADAFRUIT_GFX_AS_H #include "Load_fonts.h" -#if ARDUINO >= 100 - #include "Arduino.h" - #include "Print.h" -#else - #include "WProgram.h" -#endif +#include #define swap(a, b) { int16_t t = a; a = b; b = t; } -class Adafruit_GFX : public Print { - - public: - - Adafruit_GFX(int16_t w, int16_t h); // Constructor - - // This MUST be defined by the subclass: - virtual void drawPixel(int16_t x, int16_t y, uint16_t color) = 0; - - // These MAY be overridden by the subclass to provide device-specific - // optimized code. Otherwise 'generic' versions are used. - virtual void - drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color), - drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color), - drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color), - drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color), - fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color), - fillScreen(uint16_t color), - invertDisplay(boolean i); - - // These exist only with Adafruit_GFX (no subclass overrides) - void - drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color), - drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, - uint16_t color), - fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color), - fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, - int16_t delta, uint16_t color), - drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, - int16_t x2, int16_t y2, uint16_t color), - fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, - int16_t x2, int16_t y2, uint16_t color), - drawRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, - int16_t radius, uint16_t color), - fillRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, - int16_t radius, uint16_t color), - drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, - int16_t w, int16_t h, uint16_t color), - drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, - uint16_t bg, uint8_t size), - setCursor(int16_t x, int16_t y), - setTextColor(uint16_t c), - setTextColor(uint16_t c, uint16_t bg), - setTextSize(uint8_t s), - setTextWrap(boolean w), - setRotation(uint8_t r); - +/** This class provides a few extensions to Adafruit_GFX, mostly for compatibility with + * existing code. Note that the fonts ("size" parameter) are not the same ones use as the + * ones provided by Adafruit_GFX. Using any of the functions defined in this class will + * therefore pull additional font tables into flash. If that is an issue, try to stick + * to the base class, or trim down the fonts loaded in Load_fonts.h . */ +class Adafruit_GFX_AS : public Adafruit_GFX { +public: + Adafruit_GFX_AS(int16_t w, int16_t h); // Constructor int16_t drawUnicode(uint16_t uniCode, int16_t x, int16_t y, int16_t size); int16_t drawNumber(long long_num,int16_t poX, int16_t poY, int16_t size); int16_t drawChar(char c, int16_t x, int16_t y, int16_t size); @@ -66,32 +22,6 @@ class Adafruit_GFX : public Print { int16_t drawCentreString(char *string, int16_t dX, int16_t poY, int16_t size); int16_t drawRightString(char *string, int16_t dX, int16_t poY, int16_t size); int16_t drawFloat(float floatNumber,int16_t decimal,int16_t poX, int16_t poY, int16_t size); - -#if ARDUINO >= 100 - virtual size_t write(uint8_t); -#else - virtual void write(uint8_t); -#endif - - int16_t - height(void), - width(void); - - uint8_t getRotation(void); - - protected: - const int16_t - WIDTH, HEIGHT; // This is the 'raw' display w/h - never changes - int16_t - _width, _height, // Display w/h as modified by current rotation - cursor_x, cursor_y; - uint16_t - textcolor, textbgcolor; - uint8_t - textsize, - rotation; - boolean - wrap; // If set, 'wrap' text at right edge of display }; -#endif // _ADAFRUIT_GFX_H +#endif // _ADAFRUIT_GFX_AS_H diff --git a/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.cpp b/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.cpp index 914e4d1..20d434f 100644 --- a/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.cpp +++ b/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.cpp @@ -8,7 +8,7 @@ Includes DMA transfers on DMA1 CH2 and CH3. // Constructor when using hardware SPI. Faster, but must use SPI pins // specific to each board type (e.g. 11,13 for Uno, 51,52 for Mega, etc.) -Adafruit_ILI9341_STM::Adafruit_ILI9341_STM(int8_t cs, int8_t dc, int8_t rst) : Adafruit_GFX(ILI9341_TFTWIDTH, ILI9341_TFTHEIGHT) +Adafruit_ILI9341_STM::Adafruit_ILI9341_STM(int8_t cs, int8_t dc, int8_t rst) : Adafruit_GFX_AS(ILI9341_TFTWIDTH, ILI9341_TFTHEIGHT) { _cs = cs; _dc = dc; diff --git a/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.h b/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.h index b77b356..692015c 100644 --- a/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.h +++ b/STM32F1/libraries/Adafruit_ILI9341_STM/Adafruit_ILI9341_STM.h @@ -95,7 +95,7 @@ This library has been modified for the Maple Mini #define ILI9341_GREENYELLOW 0xAFE5 /* 173, 255, 47 */ #define ILI9341_PINK 0xF81F -class Adafruit_ILI9341_STM : public Adafruit_GFX { +class Adafruit_ILI9341_STM : public Adafruit_GFX_AS { public: From ffc0b29880f24ec7f79955697688bd38c8db06d3 Mon Sep 17 00:00:00 2001 From: Thomas Friedrichsmeier Date: Thu, 15 Mar 2018 08:16:42 +0100 Subject: [PATCH 292/351] Update README --- STM32F1/libraries/Adafruit_GFX_AS/README.txt | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/STM32F1/libraries/Adafruit_GFX_AS/README.txt b/STM32F1/libraries/Adafruit_GFX_AS/README.txt index 43cf08a..f5ccf00 100644 --- a/STM32F1/libraries/Adafruit_GFX_AS/README.txt +++ b/STM32F1/libraries/Adafruit_GFX_AS/README.txt @@ -1,14 +1,22 @@ -This library has minor modifications to support STM32. -It also was modified to include additional fonts. +This library adds a few font-related functions on top of the Adafruit_GFX library (which you need to install, separately). -This is the core graphics library for all our displays, providing a common set of graphics primitives (points, lines, circles, etc.). It needs to be paired with a hardware-specific library for each display device we carry (to handle the lower-level functions). +Historically, Adafruit_GFX_AS started as a fork of Adafruit_GFX. Most importantly, it added support for using additional fonts, +before similar functionality became available in Adafruit_GFX. + +Today, the main point of this library is to continue supporting projects that have made use of the functions added in Adafruit_GFX_AS, +while also being fully compatible with Adafruit_GFX (which is used as the base class). It is not recommended to use the functions +provided by the Adafruit_GFX_AS class in newly developed code. + +To use this library with a driver that is not based on Adafruit_GFX_AS, all you will have to do is to replace "Adafrui_GFX" with "Adafruit_GFX_AS" +in your driver code. This will usually be three places: The #include-directive, the base-class declaration, and the call to the base-contstructor. Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! -Written by Limor Fried/Ladyada for Adafruit Industries. +Adafruit_GFX Written by Limor Fried/Ladyada for Adafruit Industries. +Adafruit_GFX_AS funtions added by "Bodmer"(?) BSD license, check license.txt for more information. All text above must be included in any redistribution. -To download, click the DOWNLOAD ZIP button, uncompress and rename the uncompressed folder Adafruit_GFX. Confirm that the Adafruit_GFX folder contains Adafruit_GFX.cpp and Adafruit_GFX.h +To download, click the DOWNLOAD ZIP button, uncompress and rename the uncompressed folder Adafruit_GFX_AS. Confirm that the Adafruit_GFX_AS folder contains Adafruit_GFX_AS.cpp and Adafruit_GFX_AS.h -Place the Adafruit_GFX library folder your /Libraries/ folder. You may need to create the Libraries subfolder if its your first library. Restart the IDE. +Place the Adafruit_GFX_AS library folder your /Libraries/ folder. You may need to create the Libraries subfolder if its your first library. Restart the IDE. From ad0090bc1bc76c23dd1e4f5ec45de7f4d87aa8ba Mon Sep 17 00:00:00 2001 From: stevstrong Date: Thu, 15 Mar 2018 19:23:49 +0100 Subject: [PATCH 293/351] Update i2c.c fix for unrecognized devices having ID 0x7.. --- STM32F1/cores/maple/libmaple/i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/cores/maple/libmaple/i2c.c b/STM32F1/cores/maple/libmaple/i2c.c index c4ed245..6724d16 100644 --- a/STM32F1/cores/maple/libmaple/i2c.c +++ b/STM32F1/cores/maple/libmaple/i2c.c @@ -324,7 +324,7 @@ void _i2c_irq_handler(i2c_dev *dev) { /* * EV6: Slave address sent */ - if (sr1 & I2C_SR1_ADDR) { + if (sr1 & (I2C_SR1_ADDR|I2C_SR1_ADD10)) { /* * Special case event EV6_1 for master receiver. * Generate NACK and restart/stop condition after ADDR From 41b165cae0d2c0493f178e0ebfff89a1afe5ed7a Mon Sep 17 00:00:00 2001 From: stevstrong Date: Tue, 20 Mar 2018 11:53:03 +0100 Subject: [PATCH 294/351] Increase tone resolution Small change to increase tone resolution by multiplying before dividing. --- STM32F1/cores/maple/tone.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/STM32F1/cores/maple/tone.cpp b/STM32F1/cores/maple/tone.cpp index b249a78..9d0b846 100644 --- a/STM32F1/cores/maple/tone.cpp +++ b/STM32F1/cores/maple/tone.cpp @@ -60,7 +60,7 @@ uint8_t tone_ntimer = TONE_TIMER; // timer used to generate freque bool tone_state = true; // last pin state for toggling short tone_pin = -1; // pin for outputting sound short tone_freq = 444; // tone frequency (0=pause) -volatile uint32_t tone_nhw = 0; // tone duration in number of half waves +volatile uint32_t tone_nhw = 0; // tone duration in number of half waves uint16_t tone_tcount = 0; // time between handler calls in 1/36 usec uint16_t tone_ncount = 0; // handler call between toggling uint16_t tone_n = 0; // remaining handler calls before toggling @@ -151,7 +151,7 @@ void tone(uint32_t pin, uint32_t freq, uint32_t duration) { tone_ncount = tone_n = (count>>16)+1; // number of 16-bit count chunk tone_tcount = count/tone_ncount; // size of count chunk if(duration > 0) // number of half waves to be generated - tone_nhw = ((duration*freq)/1000)<<1; + tone_nhw = (2*duration*freq)/1000; else // no duration specified, continuous sound until noTone() called tone_nhw = 0; From e76e8adb5254aa48bb04e483a3eb77e032331cea Mon Sep 17 00:00:00 2001 From: stevstrong Date: Fri, 23 Mar 2018 10:55:26 +0100 Subject: [PATCH 295/351] F1 tone resolution: try to force compiler optimisation --- STM32F1/cores/maple/tone.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/cores/maple/tone.cpp b/STM32F1/cores/maple/tone.cpp index 9d0b846..c179c34 100644 --- a/STM32F1/cores/maple/tone.cpp +++ b/STM32F1/cores/maple/tone.cpp @@ -151,7 +151,7 @@ void tone(uint32_t pin, uint32_t freq, uint32_t duration) { tone_ncount = tone_n = (count>>16)+1; // number of 16-bit count chunk tone_tcount = count/tone_ncount; // size of count chunk if(duration > 0) // number of half waves to be generated - tone_nhw = (2*duration*freq)/1000; + tone_nhw = duration*freq*2/1000; else // no duration specified, continuous sound until noTone() called tone_nhw = 0; From 9e19f0ecc34b5500451d7948a8cd78fcb31b9547 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Sat, 24 Mar 2018 00:13:27 +0100 Subject: [PATCH 296/351] Update platform.txt cosmetics: remove unnecessary blank space --- STM32F1/platform.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/STM32F1/platform.txt b/STM32F1/platform.txt index de1f206..5cc1841 100644 --- a/STM32F1/platform.txt +++ b/STM32F1/platform.txt @@ -57,7 +57,7 @@ compiler.ar.extra_flags= compiler.elf2hex.extra_flags= -compiler.libs.c.flags="-I{build.system.path}/libmaple" "-I{build.system.path}/libmaple/include" "-I{build.system.path}/libmaple/stm32f1/include" "-I{build.system.path}/libmaple/usb/stm32f1" "-I{build.system.path}/libmaple/usb/usb_lib" +compiler.libs.c.flags="-I{build.system.path}/libmaple" "-I{build.system.path}/libmaple/include" "-I{build.system.path}/libmaple/stm32f1/include" "-I{build.system.path}/libmaple/usb/stm32f1" "-I{build.system.path}/libmaple/usb/usb_lib" @@ -160,4 +160,4 @@ tools.jlink_upload.path.linux={runtime.hardware.path}/tools/linux tools.jlink_upload.path.linux64={runtime.hardware.path}/tools/linux64 tools.jlink_upload.upload.params.verbose=-d tools.jlink_upload.upload.params.quiet=n -tools.jlink_upload.upload.pattern="{path}/{cmd}" "{build.path}/{build.project_name}.bin" \ No newline at end of file +tools.jlink_upload.upload.pattern="{path}/{cmd}" "{build.path}/{build.project_name}.bin" From 3821c3ab97685fa276d5646e46f7477735633653 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Sat, 24 Mar 2018 10:09:47 +0100 Subject: [PATCH 297/351] F4: adds the macro "word" similar to already existing solution for F1 --- STM32F4/cores/maple/wirish_math.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/STM32F4/cores/maple/wirish_math.h b/STM32F4/cores/maple/wirish_math.h index e037372..1510273 100644 --- a/STM32F4/cores/maple/wirish_math.h +++ b/STM32F4/cores/maple/wirish_math.h @@ -149,4 +149,11 @@ double sqrt(double x); */ double pow(double x, double y); +inline uint16_t makeWord( uint16_t w ) { return w; } + +inline uint16_t makeWord( uint8_t h, uint8_t l ) { return (h << 8) | l; } + +#define word(...) makeWord(__VA_ARGS__) + + #endif From 0a88fe3cfa08af4b655620e71d3809ea14fdd948 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Tue, 27 Mar 2018 20:13:04 +0200 Subject: [PATCH 298/351] F1 SPI slave: remove RXONLY flag to enable data transmission see https://github.com/rogerclarkmelbourne/Arduino_STM32/issues/471 --- STM32F1/libraries/SPI/src/SPI.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/libraries/SPI/src/SPI.cpp b/STM32F1/libraries/SPI/src/SPI.cpp index c07e2ea..4d8787d 100644 --- a/STM32F1/libraries/SPI/src/SPI.cpp +++ b/STM32F1/libraries/SPI/src/SPI.cpp @@ -161,7 +161,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_RX_ONLY); + uint32 flags = ((_currentSetting->bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | _currentSetting->dataSize); spi_slave_enable(_currentSetting->spi_d, (spi_mode)_currentSetting->dataMode, flags); // added for DMA callbacks. _currentSetting->state = SPI_STATE_READY; From 7dce451ebc9ec79dd2157913202fa0c03daf74ae Mon Sep 17 00:00:00 2001 From: victorpv Date: Wed, 28 Mar 2018 21:50:49 -0500 Subject: [PATCH 299/351] SDIO updates Increase performance and compatibility with cards. --- STM32F1/cores/maple/sdio.cpp | 51 ++- STM32F1/libraries/SDIO/SdioF1.cpp | 577 +++++++++++++++++++++++------- STM32F1/libraries/SDIO/SdioF1.h | 4 +- 3 files changed, 485 insertions(+), 147 deletions(-) diff --git a/STM32F1/cores/maple/sdio.cpp b/STM32F1/cores/maple/sdio.cpp index 8bd9491..2edf501 100644 --- a/STM32F1/cores/maple/sdio.cpp +++ b/STM32F1/cores/maple/sdio.cpp @@ -32,8 +32,8 @@ sdio_dev * SDIO = SDIO_BASE; -#define DELAY_LONG 10 -#define DELAY_SHORT 1 +#define DELAY_LONG 20 +#define DELAY_SHORT 2 uint8_t dly = DELAY_LONG; // microseconds delay after accessing registers @@ -43,9 +43,13 @@ uint8_t dly = DELAY_LONG; // microseconds delay after accessing registers void sdio_gpios_init(void) { gpio_set_mode(PIN_MAP[BOARD_SDIO_D0].gpio_device, PIN_MAP[BOARD_SDIO_D0].gpio_bit, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PIN_MAP[BOARD_SDIO_D1].gpio_device, PIN_MAP[BOARD_SDIO_D1].gpio_bit, GPIO_AF_OUTPUT_PP); +/* gpio_set_mode(PIN_MAP[BOARD_SDIO_D1].gpio_device, PIN_MAP[BOARD_SDIO_D1].gpio_bit, GPIO_AF_OUTPUT_PP); gpio_set_mode(PIN_MAP[BOARD_SDIO_D2].gpio_device, PIN_MAP[BOARD_SDIO_D2].gpio_bit, GPIO_AF_OUTPUT_PP); gpio_set_mode(PIN_MAP[BOARD_SDIO_D3].gpio_device, PIN_MAP[BOARD_SDIO_D3].gpio_bit, GPIO_AF_OUTPUT_PP); +*/ + gpio_set_mode(PIN_MAP[BOARD_SDIO_D1].gpio_device, PIN_MAP[BOARD_SDIO_D1].gpio_bit, GPIO_INPUT_PU); + gpio_set_mode(PIN_MAP[BOARD_SDIO_D2].gpio_device, PIN_MAP[BOARD_SDIO_D2].gpio_bit, GPIO_INPUT_PU); + gpio_set_mode(PIN_MAP[BOARD_SDIO_D3].gpio_device, PIN_MAP[BOARD_SDIO_D3].gpio_bit, GPIO_INPUT_PU); gpio_set_mode(PIN_MAP[BOARD_SDIO_CLK].gpio_device, PIN_MAP[BOARD_SDIO_CLK].gpio_bit, GPIO_AF_OUTPUT_PP); gpio_set_mode(PIN_MAP[BOARD_SDIO_CMD].gpio_device, PIN_MAP[BOARD_SDIO_CMD].gpio_bit, GPIO_AF_OUTPUT_PP); /* @@ -63,12 +67,12 @@ void sdio_gpios_init(void) void sdio_gpios_deinit(void) { - gpio_set_mode(PIN_MAP[BOARD_SDIO_D0].gpio_device, PIN_MAP[BOARD_SDIO_D0].gpio_bit, GPIO_INPUT_FLOATING); - gpio_set_mode(PIN_MAP[BOARD_SDIO_D1].gpio_device, PIN_MAP[BOARD_SDIO_D1].gpio_bit, GPIO_INPUT_FLOATING); - gpio_set_mode(PIN_MAP[BOARD_SDIO_D2].gpio_device, PIN_MAP[BOARD_SDIO_D2].gpio_bit, GPIO_INPUT_FLOATING); - gpio_set_mode(PIN_MAP[BOARD_SDIO_D3].gpio_device, PIN_MAP[BOARD_SDIO_D3].gpio_bit, GPIO_INPUT_FLOATING); - gpio_set_mode(PIN_MAP[BOARD_SDIO_CLK].gpio_device, PIN_MAP[BOARD_SDIO_CLK].gpio_bit, GPIO_INPUT_FLOATING); - gpio_set_mode(PIN_MAP[BOARD_SDIO_CMD].gpio_device, PIN_MAP[BOARD_SDIO_CMD].gpio_bit, GPIO_INPUT_FLOATING); + gpio_set_mode(PIN_MAP[BOARD_SDIO_D0].gpio_device, PIN_MAP[BOARD_SDIO_D0].gpio_bit, GPIO_INPUT_PU); + gpio_set_mode(PIN_MAP[BOARD_SDIO_D1].gpio_device, PIN_MAP[BOARD_SDIO_D1].gpio_bit, GPIO_INPUT_PU); + gpio_set_mode(PIN_MAP[BOARD_SDIO_D2].gpio_device, PIN_MAP[BOARD_SDIO_D2].gpio_bit, GPIO_INPUT_PU); + gpio_set_mode(PIN_MAP[BOARD_SDIO_D3].gpio_device, PIN_MAP[BOARD_SDIO_D3].gpio_bit, GPIO_INPUT_PU); + gpio_set_mode(PIN_MAP[BOARD_SDIO_CLK].gpio_device, PIN_MAP[BOARD_SDIO_CLK].gpio_bit, GPIO_INPUT_PU); + gpio_set_mode(PIN_MAP[BOARD_SDIO_CMD].gpio_device, PIN_MAP[BOARD_SDIO_CMD].gpio_bit, GPIO_INPUT_PU); /* * Todo just remove it, not needed for F1. @@ -110,19 +114,35 @@ void sdio_power_off(void) void sdio_set_clock(uint32_t clk) { - if (clk>24000000UL) clk = 24000000UL; // limit the SDIO master clock to 24MHz + /* + * limit the SDIO master clock to 8/3 of PCLK2.See RM 22.3 + * Also limited to no more than 48Mhz + */ + clk = min(clk,(SDIOCLK/3)*8); + clk = min(clk,36000000); if (clk<1000000) dly = DELAY_LONG; else dly = DELAY_SHORT; + /* + * round up divider, so we don't run the card over the speed supported. + + */ + uint32 div = SDIOCLK/clk + (SDIOCLK % clk != 0) - 2; + + sdio_disable(); - SDIO->CLKCR = (SDIO->CLKCR & (~(SDIO_CLKCR_CLKDIV|SDIO_CLKCR_BYPASS))) | SDIO_CLKCR_CLKEN | (((SDIOCLK/clk)-2)&SDIO_CLKCR_CLKDIV); + //Serial.println(div,DEC); + SDIO->CLKCR = (SDIO->CLKCR & (~(SDIO_CLKCR_CLKDIV|SDIO_CLKCR_BYPASS))) | SDIO_CLKCR_PWRSAV | SDIO_CLKCR_HWFC_EN | SDIO_CLKCR_CLKEN | (div & SDIO_CLKCR_CLKDIV); delay_us(dly); } void sdio_set_dbus_width(uint16_t bus_w) { SDIO->CLKCR = (SDIO->CLKCR & (~SDIO_CLKCR_WIDBUS)) | bus_w; + gpio_set_mode(PIN_MAP[BOARD_SDIO_D1].gpio_device, PIN_MAP[BOARD_SDIO_D1].gpio_bit, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PIN_MAP[BOARD_SDIO_D2].gpio_device, PIN_MAP[BOARD_SDIO_D2].gpio_bit, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PIN_MAP[BOARD_SDIO_D3].gpio_device, PIN_MAP[BOARD_SDIO_D3].gpio_bit, GPIO_AF_OUTPUT_PP); delay_us(dly); } @@ -149,9 +169,10 @@ void sdio_disable(void) */ void sdio_begin(void) { - sdio_gpios_init(); + sdio_init(); sdio_power_on(); + sdio_gpios_init(); // Set initial SCK rate. sdio_set_clock(400000); delay_us(200); // generate 80 pulses at 400kHz @@ -162,11 +183,12 @@ void sdio_begin(void) */ void sdio_end(void) { + while ( sdio_cmd_xfer_ongoing() ); sdio_disable(); - while ( sdio_cmd_xfer_ongoing() ); + sdio_gpios_deinit(); sdio_power_off(); rcc_clk_disable(RCC_SDIO); - sdio_gpios_deinit(); + } /** @@ -187,6 +209,7 @@ uint8_t sdio_cmd_send(uint16_t cmd_index_resp_type, uint32_t arg) while ( !(SDIO->STA&(SDIO_STA_CMDREND|SDIO_STA_CMD_ERROR_FLAGS)) ) ; } else break; // no response required if ( SDIO->STA&(SDIO_STA_CMDREND|SDIO_STA_CTIMEOUT) ) + //if ( SDIO->STA&(SDIO_STA_CMDREND) ) break; // response received or timeout // ignore CRC error for CMD5 and ACMD41 if ( ((cmd_index_resp_type&SDIO_CMD_CMDINDEX)==5) || ((cmd_index_resp_type&SDIO_CMD_CMDINDEX)==41) ) diff --git a/STM32F1/libraries/SDIO/SdioF1.cpp b/STM32F1/libraries/SDIO/SdioF1.cpp index 8957b37..c0e5eae 100644 --- a/STM32F1/libraries/SDIO/SdioF1.cpp +++ b/STM32F1/libraries/SDIO/SdioF1.cpp @@ -61,6 +61,12 @@ #define CMD38_XFERTYP (uint16_t)( CMD38 | CMD_RESP_R1b ) #define ACMD41_XFERTYP (uint16_t)( ACMD41 | CMD_RESP_R3 ) +/* + * AMD42 to enable disable CD/D3 pull up. Needed for 4bit mode. + */ +const uint8_t ACMD42 = 0X2A; +#define ACMD42_XFERTYP (uint16_t)( ACMD41 | CMD_RESP_R1 ) + #define CMD55_XFERTYP (uint16_t)( CMD55 | CMD_RESP_R1 ) //============================================================================= @@ -69,14 +75,27 @@ static void initSDHC(void); static bool isBusyCMD13(void); static bool isBusyTransferComplete(void); +static bool isBusyTransferCRC(void); //static bool isBusyCommandComplete(); //static bool isBusyCommandInhibit(); static bool readReg16(uint32_t xfertyp, void* data); //static void setSdclk(uint32_t kHzMax); static bool yieldTimeout(bool (*fcn)(void)); +static bool yieldDmaStatus(void); static bool waitDmaStatus(void); static bool waitTimeout(bool (*fcn)(void)); //----------------------------------------------------------------------------- +static const uint32_t IDLE_STATE = 0; +static const uint32_t READ_STATE = 1; +static const uint32_t WRITE_STATE = 2; +volatile uint32_t m_curLba; +volatile uint32_t m_limitLba; +volatile uint8_t m_curState; +volatile uint64_t m_totalReadLbas = 0; +volatile uint64_t m_readErrors = 0; +volatile uint64_t m_writeErrors = 0; +volatile uint64_t m_totalWriteLbas = 0; + #define TRX_RD 0 #define TRX_WR 1 static uint8_t m_dir = TRX_RD; @@ -97,27 +116,26 @@ static cid_t m_cid; static csd_t m_csd; static uint32_t t = 0; //============================================================================= -/* - * Todo Remove this or change it, but rather remove since this can be checked with debugger. - */ + #if USE_DEBUG_MODE #define DBG_PRINT() { \ Serial.write('_'); Serial.print(__FUNCTION__); Serial.write('_'); Serial.print(__LINE__); Serial.print(": "); \ - Serial.print("DMA->LISR: "); Serial.print(SDIO_DMA_DEV->regs->LISR, HEX); \ + Serial.print("DMA->ISR: 0x"); Serial.print(SDIO_DMA_DEV->regs->ISR, HEX); \ /*Serial.print("DMA->HISR: "); Serial.println(SDIO_DMA_DEV->regs->HISR, HEX);*/ \ - Serial.print(", DMA->CR: "); Serial.print(SDIO_DMA_DEV->regs->STREAM[SDIO_DMA_CHANNEL].CR, HEX); \ - Serial.print(", DMA->NDTR: "); Serial.print(SDIO_DMA_DEV->regs->STREAM[SDIO_DMA_CHANNEL].NDTR, HEX); \ - /**/Serial.print(", DMA->PAR: "); Serial.print(SDIO_DMA_DEV->regs->STREAM[SDIO_DMA_CHANNEL].PAR, HEX); \ - /**/Serial.print(", DMA->M0AR: "); Serial.print(SDIO_DMA_DEV->regs->STREAM[SDIO_DMA_CHANNEL].M0AR, HEX); \ - Serial.print(", DMA->FCR: "); Serial.print(SDIO_DMA_DEV->regs->STREAM[SDIO_DMA_CHANNEL].FCR, HEX); \ + Serial.print(", DMA->CCR: 0x"); Serial.print(SDIO_DMA_DEV->regs->CCR4, HEX); \ + Serial.print(", DMA->CNDTR: "); Serial.print(SDIO_DMA_DEV->regs->CNDTR4,DEC); \ + /**/Serial.print(", DMA->CPAR: 0x"); Serial.print(SDIO_DMA_DEV->regs->CPAR4, HEX); \ + /**/Serial.print(", DMA->CMAR: 0x"); Serial.print(SDIO_DMA_DEV->regs->CMAR4, HEX); \ + Serial.print(", DMA->IFCR: 0x"); Serial.print(SDIO_DMA_DEV->regs->IFCR, HEX); \ \ /*Serial.print(" SDIO->POWER: "); Serial.println(SDIO->POWER, HEX);*/ \ - Serial.print(", SDIO->CLKCR: "); Serial.print(SDIO->CLKCR, HEX); \ - Serial.print(", SDIO->DTIMER: "); Serial.print(SDIO->DTIMER, HEX); \ - Serial.print(", SDIO->DCTRL: "); Serial.print(SDIO->DCTRL, HEX); \ + Serial.print(", SDIO->CLKCR: 0x"); Serial.print(SDIO->CLKCR, HEX); \ + Serial.print(", SDIO->DTIMER: 0x"); Serial.print(SDIO->DTIMER, HEX); \ + Serial.print(", SDIO->DCTRL: 0x"); Serial.print(SDIO->DCTRL, HEX); \ /**/Serial.print(", SDIO->DLEN: "); Serial.print(SDIO->DLEN); \ Serial.print(", SDIO->DCOUNT: "); Serial.print(SDIO->DCOUNT); \ - Serial.print(", SDIO->STA: "); Serial.println(SDIO->STA, HEX); \ + Serial.print(", SDIO->STA: 0x"); Serial.println(SDIO->STA, HEX); \ + Serial.print(", SDIO->FIFOCNT: "); Serial.println(SDIO->FIFOCNT); \ /*delay(1);*/ \ } #define DBG_PIN PD0 @@ -131,7 +149,7 @@ static void _panic(const char *message, uint32_t code) { Serial.print(message); Serial.println(code, HEX); //Block the execution with blinky leds - while (1); + while (1) {delay (1);}; /* pinMode(BOARD_LED_PIN, OUTPUT); //pinMode(BOARD_LED2_PIN, OUTPUT); @@ -171,13 +189,14 @@ void yield(void) } val = dma_get_isr_bits(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); - if ( val & DMA_ISR_FEIF ) { +/* if ( val & DMA_ISR_FEIF ) { val ^= DMA_ISR_FEIF; dma_clear_isr_bits(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); } +*/ if ( val ) { if (val & DMA_ISR_TEIF) Serial.print(" TEIF"); - if (val & DMA_ISR_DMEIF) Serial.print(" DMEIF"); + //if (val & DMA_ISR_DMEIF) Serial.print(" DMEIF"); //if (val & DMA_ISR_FEIF) Serial.print(" FEIF"); _panic(" - DMA: Data Transmission Error ", val); } @@ -208,7 +227,7 @@ static bool cardCommand(uint16_t xfertyp, uint32_t arg) #if USE_DEBUG_MODE==2 Serial.print("cardCommand: "); Serial.print(xfertyp&SDIO_CMD_CMDINDEX); Serial.print(", arg: "); Serial.print(arg, HEX); #endif - uint8_t resp = sdio_cmd_send(xfertyp, arg); // returns non-zero if fails, zero if OK + uint8_t resp = sdio_cmd_send(xfertyp, arg); // returns non-zero if OK, zero if it fails #if USE_DEBUG_MODE==2 Serial.print(", resp: "); Serial.print(resp, HEX); Serial.print(", SDIO->STA: "); Serial.print(SDIO->STA, HEX); Serial.print(", cmd_resp: "); Serial.print(SDIO->RESP[0], HEX); @@ -264,19 +283,38 @@ static bool isBusyCMD13(void) { } return !(SDIO->RESP[0] & CARD_STATUS_READY_FOR_DATA); } -/*---------------------------------------------------------------------------*/ + +/* + * Returns False if DMA transfer disabled. + * True otherwise + */ +static bool inline isEnabledDMA(void) +{ + return dma_is_enabled(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); +} + +/* + * Returns False if DMA transfer is completed or in error. + * True otherwise + */ static bool isBusyDMA(void) { + if (!isEnabledDMA()) return false; uint8_t isr = dma_get_isr_bits(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); - isr &= DMA_ISR_TCIF | DMA_ISR_TEIF; + isr &= DMA_ISR_TCIF | DMA_ISR_TEIF; //if (isr&DMA_ISR_TCIF) dma_disable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); return !(isr); // ignore transfer error flag } + /*---------------------------------------------------------------------------*/ +/* + * Returns true while the transfer has not completed + * False when it has completed. + */ static bool isBusyTransferComplete(void) { uint32_t mask = SDIO->STA &(SDIO_STA_DATAEND | SDIO_STA_TRX_ERROR_FLAGS); -#if USE_DEBUG_MODE +//#if USE_DEBUG_MODE if ( mask & SDIO_STA_TRX_ERROR_FLAGS ) { Serial.print("XFER ERROR: SDIO->STA: "); Serial.print(SDIO->STA, HEX); if (mask & SDIO_STA_STBITERR) Serial.print(" STBITERR"); @@ -286,13 +324,43 @@ static bool isBusyTransferComplete(void) if (mask & SDIO_STA_DCRCFAIL) Serial.print(" DCRCFAIL"); Serial.println(); } -#endif +//#endif if (mask) { dma_disable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); return false; } return true; } + + +/* + * New function, to follow Reference Manual sequence. + * Returns true if still not confirmed DBCKEND: Data block sent/received (CRC check passed) + * False when it has completed the transfer with CRC check. + */ +static bool isBusyTransferCRC(void) +{ + uint32_t mask = SDIO->STA &(SDIO_STA_DBCKEND | SDIO_STA_TRX_ERROR_FLAGS); +#if USE_DEBUG_MODE + if ( mask & SDIO_STA_TRX_ERROR_FLAGS ) { + Serial.print("XFER ERROR: SDIO->STA: "); Serial.print(SDIO->STA, HEX); + if (mask & SDIO_STA_STBITERR) Serial.print(" STBITERR"); + if (mask & SDIO_STA_RXOVERR) Serial.print(" RXOVERR"); + if (mask & SDIO_STA_TXUNDERR) Serial.print(" TXUNDERR"); + if (mask & SDIO_STA_DTIMEOUT) Serial.print(" DTIMEOUT"); + if (mask & SDIO_STA_DCRCFAIL) Serial.print(" DCRCFAIL"); + Serial.println(); + } +#endif + if (mask) { + //dma_disable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); + //Serial.print("SDIO->STA SDIO_STA_DBCKEND"); Serial.println(SDIO->STA && SDIO_STA_DBCKEND, HEX); + return false; + } + return true; +} + + /*---------------------------------------------------------------------------*/ static void trxStart(uint8_t* buf, uint32_t n, uint8_t dir) { @@ -308,6 +376,12 @@ static bool trxStop() if (!cardCommand(CMD12_XFERTYP, 0)) { return sdError(SD_CARD_ERROR_CMD12); } + /* + * Added this to wait to complete on sync. + */ + if (waitTimeout(isBusyCMD13)) { + return sdError(SD_CARD_ERROR_CMD13); + } if ( t ) { Serial.print(", in "); Serial.println(millis()-t); t = 0; @@ -315,52 +389,70 @@ static bool trxStop() return true; } /*---------------------------------------------------------------------------*/ -static bool dmaTrxStart(uint8_t* buf, uint32_t n, uint8_t dir) +static bool dmaTrxStart(uint32_t n, uint8_t dir) { - m_dir = dir; - if ((3 & (uint32_t)buf) || n == 0) { // check alignment - _panic("- transferStart: unaligned buffer address ", (uint32_t)buf); - return sdError(SD_CARD_ERROR_DMA); - } - if (dir==TRX_RD && yieldTimeout(isBusyCMD13)) { - return sdError(SD_CARD_ERROR_CMD13); - } - uint32_t flags = (SDIO_BLOCKSIZE_512 | SDIO_DCTRL_DMAEN | SDIO_DCTRL_DTEN); + uint32_t flags = (SDIO_BLOCKSIZE_512 | SDIO_DCTRL_DMAEN | SDIO_DCTRL_DTEN); if (dir==TRX_RD) flags |= SDIO_DIR_RX; // setup SDIO to transfer n blocks of 512 bytes sdio_setup_transfer(0x00FFFFFF, n, flags); - // setup SDIO_DMA_DEV stream 3 channel 4 - /* - * Moved to begin. - */ - //dma_init(SDIO_DMA_DEV); - /* - * Todo. Check this, channel must be disabled to change DMA priority, and seems like channel is not completing transfers - */ - //dma_set_priority(SDIO_DMA_DEV, SDIO_DMA_CHANNEL, DMA_PRIORITY_VERY_HIGH); - flags = (DMA_MINC_MODE); - // not extra flag if read - if (dir!=TRX_RD) flags |= DMA_FROM_MEM;// write - dma_setup_transfer(SDIO_DMA_DEV, SDIO_DMA_CHANNEL, &SDIO->FIFO, DMA_SIZE_32BITS, buf, DMA_SIZE_32BITS, flags); - dma_set_num_transfers(SDIO_DMA_DEV, SDIO_DMA_CHANNEL, n>>2); // F1 DMA controller counts each word as 1 data item. - //dma_set_fifo_flags(SDIO_DMA_DEV, SDIO_DMA_CHANNEL, (DMA_FCR_DMDIS | DMA_FCR_FTH_FULL)); // disable direct mode | threshold FULL - dma_clear_isr_bits(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); - dma_enable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); + return true; } + +/* + * This one replaces dmaTrxStart, and will just prepare the DMA part, then a new + * one will enable the DMA reception as per the RM. + */ +static bool dmaTrxPrepare(uint8_t* buf, uint32_t n, uint8_t dir) +{ + uint32_t flags; + m_dir = dir; + if ((3 & (uint32_t)buf) || n == 0) { // check alignment + _panic("- transferStart: unaligned buffer address ", (uint32_t)buf); + return sdError(SD_CARD_ERROR_DMA); + } + /* + * No point to wait here again if we always wait before calling this. + if (dir==TRX_RD && yieldTimeout(isBusyCMD13)) { + return sdError(SD_CARD_ERROR_CMD13); + } + */ + + /* + * Following RM 22.3.2. Setup DMA first, SDIO peripheral next + * + */ + flags = (DMA_MINC_MODE); + // not extra flag if read + if (dir!=TRX_RD) flags |= DMA_FROM_MEM;// write + dma_setup_transfer(SDIO_DMA_DEV, SDIO_DMA_CHANNEL, &SDIO->FIFO, DMA_SIZE_32BITS, buf, DMA_SIZE_32BITS, flags); + dma_set_num_transfers(SDIO_DMA_DEV, SDIO_DMA_CHANNEL, n>>2); // F1 DMA controller counts each word as 1 data item. + //dma_set_fifo_flags(SDIO_DMA_DEV, SDIO_DMA_CHANNEL, (DMA_FCR_DMDIS | DMA_FCR_FTH_FULL)); // disable direct mode | threshold FULL + dma_clear_isr_bits(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); + dma_enable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); + + return true; +} + + /*---------------------------------------------------------------------------*/ static bool dmaTrxEnd(bool multi_block) { - if ( !waitDmaStatus() ) { + if(m_curState != READ_STATE){ + if ( yieldTimeout(isBusyTransferComplete) ) { + DBG_PRINT(); + if (m_dir==TRX_RD) + return sdError(SD_CARD_ERROR_READ_CRC); + else + return sdError(SD_CARD_ERROR_WRITE); + } + } + + if ( !yieldDmaStatus() ) { DBG_PRINT(); return sdError(SD_CARD_ERROR_DMA); } - if ( waitTimeout(isBusyTransferComplete) ) { - if (m_dir==TRX_RD) - return sdError(SD_CARD_ERROR_READ_TIMEOUT); - else - return sdError(SD_CARD_ERROR_WRITE_TIMEOUT); - } + if (multi_block) { return trxStop(); } else { @@ -389,21 +481,38 @@ static bool readReg16(uint32_t xfertyp, void* data) /*---------------------------------------------------------------------------*/ // Return true if timeout occurs. static bool yieldTimeout(bool (*fcn)()) { + m_busyFcn = fcn; uint32_t m = millis(); while (fcn()) { if ((millis() - m) > BUSY_TIMEOUT_MILLIS) { + m_busyFcn = 0; return true; } yield(); } + m_busyFcn = 0; return false; // Caller will set errorCode. } /*---------------------------------------------------------------------------*/ +static bool yieldDmaStatus(void) +{ + if (yieldTimeout(isBusyDMA)) { + dma_disable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); + return false; // Caller will set errorCode. + } + // Did not time out. Disable it and return true. + dma_disable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); + return true; +} +/*---------------------------------------------------------------------------*/ static bool waitDmaStatus(void) { - if (yieldTimeout(isBusyDMA)) { + if (waitTimeout(isBusyDMA)) { + dma_disable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); return false; // Caller will set errorCode. } + // Did not time out. Disable it and return true + dma_disable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); return true; } /*---------------------------------------------------------------------------*/ @@ -423,6 +532,8 @@ uint32_t aligned[128]; // temporary buffer for misaligned buffers //============================================================================= bool SdioCard::begin(void) { + + uint32_t arg; m_initDone = false; m_errorCode = SD_CARD_ERROR_NONE; m_highCapacity = false; @@ -447,6 +558,7 @@ delay(100); if (!cardCommand(CMD0_XFERTYP, 0)) { return sdError(SD_CARD_ERROR_CMD0); } + delay(50); //small pause after reset command // Try several times for case of reset delay. for (uint32_t i = 0; i < CMD8_RETRIES; i++) { if (cardCommand(CMD8_XFERTYP, 0X1AA)) { @@ -457,7 +569,7 @@ delay(100); break; } } - uint32_t arg = m_version2 ? 0X40300000 : 0x00300000; + arg = m_version2 ? 0X50300000 : 0x00300000; uint32_t m = millis(); do { if (!cardAcmd(0, ACMD41_XFERTYP, arg) || @@ -478,6 +590,7 @@ delay(100); return sdError(SD_CARD_ERROR_CMD3); } m_rca = SDIO->RESP[0] & 0xFFFF0000; + if (!readReg16(CMD9_XFERTYP, &m_csd)) { return sdError(SD_CARD_ERROR_CMD9); } @@ -487,14 +600,21 @@ delay(100); if (!cardCommand(CMD7_XFERTYP, m_rca)) { return sdError(SD_CARD_ERROR_CMD7); } + + arg = 0x00; //bit 0, Connect[1]/Disconnect[0] the 50 KOhm pull-up resistor on CD/DAT3 + if (!cardAcmd(m_rca, ACMD42_XFERTYP, arg)) { + _panic("*** ACMD42 to disconnect D3 pullup failed! ***", 0); + } + // Set card to bus width four. - /* if (!cardAcmd(m_rca, ACMD6_XFERTYP, 2)) { return sdError(SD_CARD_ERROR_ACMD6); } - sdio_set_dbus_width(SDIO_CLKCR_WIDBUS_4BIT); - */ + // Set SDHC to bus width four. + sdio_set_dbus_width(SDIO_CLKCR_WIDBUS_4BIT); + +/* // Determine if High Speed mode is supported and set frequency. uint8_t status[64]; // see "Physical Layer Simplified Specification Version 6.00", chapter 4.3.10, Table 4-13. @@ -502,15 +622,16 @@ delay(100); // Function Selection of Function Group 1: bits 379:376, which is low nibble of byte [16] if (cardCMD6(0X00FFFFFF, status) && (2 & status[13]) && cardCMD6(0X80FFFFF1, status) && (status[16] & 0XF) == 1) { - //Serial.println("\n*** 50MHz clock supported ***"); + Serial.println("\n*** 50MHz clock supported ***"); + m_sdClkKhz = 24000; // set clock to 24MHz } else { //_panic("*** Only 25MHz clock supported! ***", 0); + m_sdClkKhz = 8000; // set clock to 24MHz } - - /* - * Todo Raise clock to 24Mhz once transfers work - */ - m_sdClkKhz = 24000; // set clock to 24MHz + // delay seems to be needed for cards that take some time to adjust + delay(1); +*/ + m_sdClkKhz = 18000; // set clock to 24MHz sdio_set_clock(m_sdClkKhz*1000); m_initDone = true; @@ -570,55 +691,160 @@ uint32_t SdioCard::kHzSdClk() { return m_sdClkKhz; } /*---------------------------------------------------------------------------*/ -bool SdioCard::readBlock(uint32_t lba, uint8_t* buf) +bool __attribute__((optimize("0"))) SdioCard::readBlock(uint32_t lba, uint8_t* buf) { #if USE_DEBUG_MODE - Serial.print("readBlock: "); Serial.println(lba); //Serial.print(", buf: "); Serial.println((uint32_t)buf, HEX); + Serial.print("readBlock: "); Serial.println(lba); //Serial.print(", buf: "); Serial.println((uint32_t)buf, HEX); #endif - // prepare SDIO and DMA for data read transfer - dmaTrxStart((uint32_t)buf & 3 ? (uint8_t*)aligned : buf, 512, TRX_RD); - // send command to start data transfer - if ( !cardCommand(CMD17_XFERTYP, (m_highCapacity ? lba : 512*lba)) ) { - return sdError(SD_CARD_ERROR_CMD17); - } - if ( dmaTrxEnd(0)) { - if ( (uint32_t)buf & 3 ) { - //memcpy(buf, aligned, 512); - register uint8_t * dst = buf; - register uint8_t * src = (uint8_t *)aligned; - register uint16_t i = 64; - while ( i-- ) { // do 8 byte copies, is much faster than single byte copy - *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; - *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; - } - } - return true; - } - return false; + volatile bool _state = false; + volatile uint16_t retries = 3; + while ( retries-- ){ + /*if (yieldTimeout(isBusyCMD13)) { // wait for previous transmission end + return sdError(SD_CARD_ERROR_CMD13); + } + */ + + if (m_curState != READ_STATE || m_curLba != lba) { +#if USE_DEBUG_MODE + Serial.print("New lba, syncing :"); + Serial.println(lba); +#endif + _state = syncBlocks(); + DBG_PRINT(); + if (!_state) { + return false; + } + m_limitLba = (lba + 1024); //arbitrary limit, tested with 32KB before and worked fine. + // prepare DMA for data read transfer + _state = dmaTrxPrepare((uint32_t)buf & 3 ? (uint8_t*)aligned : buf, 512, TRX_RD); + DBG_PRINT(); + + // prepare SDIO data read transfer 0x8000 = 64*512 + _state = dmaTrxStart(512, TRX_RD); + DBG_PRINT(); + + // send command to start data transfer + _state = cardCommand(CMD18_XFERTYP, (m_highCapacity ? lba : 512*lba)); + DBG_PRINT(); + if ( !_state ) { + return sdError(SD_CARD_ERROR_CMD18); + } + + m_curLba = lba; + m_curState = READ_STATE; + } + else { + // prepare DMA for data read transfer + _state = dmaTrxPrepare((uint32_t)buf & 3 ? (uint8_t*)aligned : buf, 512, TRX_RD); + + // prepare SDIO data read transfer + _state = dmaTrxStart(512, TRX_RD); + } + + + _state = dmaTrxEnd(0); + + if ( _state ) { + if ( (uint32_t)buf & 3 ) { + //memcpy(buf, aligned, 512); + register uint8_t * dst = buf; + register uint8_t * src = (uint8_t *)aligned; + register uint16_t i = 64; + while ( i-- ) { // do 8 byte copies, is much faster than single byte copy + *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; + *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; + } + } + m_totalReadLbas++; + m_curLba++; + if (m_curLba >= m_limitLba) { + syncBlocks(); + } + sdError(SD_CARD_ERROR_NONE); + return true; + } + syncBlocks(); + m_readErrors++; + + } + DBG_PRINT() + syncBlocks(); + m_readErrors++; + return false; } /*---------------------------------------------------------------------------*/ bool SdioCard::readBlocks(uint32_t lba, uint8_t* buf, size_t n) { #if USE_DEBUG_MODE - Serial.print("readBlocks: "); Serial.print(lba); - //Serial.print(", buf: "); Serial.print((uint32_t)buf, HEX); - Serial.print(", "); Serial.println(n); + Serial.print("readBlocks: "); Serial.print(lba); + //Serial.print(", buf: "); Serial.print((uint32_t)buf, HEX); + Serial.print(", "); Serial.println(n); #endif - if ((uint32_t)buf & 3) { - for (size_t i = 0; i < n; i++, lba++, buf += 512) { - if (!readBlock(lba, buf)) { - return false; // readBlock will set errorCode. - } - } - return true; - } - // prepare SDIO and DMA for data read transfer - dmaTrxStart(buf, 512*n, TRX_RD); - // send command to start data transfer - if ( !cardCommand(CMD18_XFERTYP, (m_highCapacity ? lba : 512*lba)) ) { - return sdError(SD_CARD_ERROR_CMD18); - } - return dmaTrxEnd(1); + volatile bool _state = false; + volatile uint16_t retries = 3; + while ( retries-- ){ + + if ((uint32_t)buf & 3) { + for (size_t i = 0; i < n; i++, lba++, buf += 512) { + if (!readBlock(lba, buf)) { + return false; // readBlock will set errorCode. + } + } + return true; + } + + if (m_curState != READ_STATE || m_curLba != lba) { + #if USE_DEBUG_MODE + Serial.print("New lba, syncing :"); + Serial.println(lba); + #endif + _state = syncBlocks(); + DBG_PRINT(); + if (!_state) { + return false; + } + m_limitLba = (lba + 1024); //arbitrary limit + // prepare DMA for data read transfer + _state = dmaTrxPrepare(buf, 512*n, TRX_RD); + + // prepare SDIO for data read transfer + _state = dmaTrxStart(512*n, TRX_RD); + + // send command to start data transfer + _state = cardCommand(CMD18_XFERTYP, (m_highCapacity ? lba : 512*lba)); + if ( !_state ) { + return sdError(SD_CARD_ERROR_CMD18); + } + m_curLba = lba; + m_curState = READ_STATE; + } + + else { + // prepare DMA for data read transfer + _state = dmaTrxPrepare(buf, 512*n, TRX_RD); + + // prepare SDIO data read transfer + _state = dmaTrxStart(512*n, TRX_RD); + } + + _state = dmaTrxEnd(0); + + if (_state){ + m_totalReadLbas += n; + m_curLba += n; + if (m_curLba >= m_limitLba) { + syncBlocks(); + } + sdError(SD_CARD_ERROR_NONE); + return true; + } + syncBlocks(); + m_readErrors++; + } + DBG_PRINT() + syncBlocks(); + m_readErrors++; + return false; } //----------------------------------------------------------------------------- bool SdioCard::readCID(void* cid) { @@ -699,13 +925,36 @@ bool SdioCard::readStart(uint32_t lba, uint32_t count) /*---------------------------------------------------------------------------*/ bool SdioCard::readStop() { + + sdio_setup_transfer(0x00FFFFFF, 0, 0); + while ( SDIO->STA & SDIO_STA_RXDAVL) { + volatile uint32 _unused = SDIO->FIFO; + } //Serial.println("readStop."); - m_lba = 0; - m_cnt = 0; - return true; + m_lba = 0; + if (!trxStop()) { + return false; + } + return true; } //----------------------------------------------------------------------------- -bool SdioCard::syncBlocks() { +inline bool SdioCard::syncBlocks() { + if ( isEnabledDMA()){ + waitDmaStatus(); + } + if (m_curState == READ_STATE) { + /* if ( isEnabledDMA()){ + waitDmaStatus(); + } + */ + m_curState = IDLE_STATE; + if (!readStop()) { + return false; + } + } else if (m_curState == WRITE_STATE) { + m_curState = IDLE_STATE; + return writeStop(); + } return true; } //----------------------------------------------------------------------------- @@ -733,17 +982,48 @@ bool SdioCard::writeBlock(uint32_t lba, const uint8_t* buf) *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; } } - if (yieldTimeout(isBusyCMD13)) { // wait for previous transmission end - return sdError(SD_CARD_ERROR_CMD13); - } - // send command to start data transfer - if ( !cardCommand(CMD24_XFERTYP, (m_highCapacity ? lba : 512*lba)) ) { - return sdError(SD_CARD_ERROR_CMD24); - } - // prepare SDIO and DMA for data transfer - dmaTrxStart(ptr, 512, TRX_WR); // 1 block, write transfer - return dmaTrxEnd(0); + + + if (m_curState != WRITE_STATE || m_curLba != lba) { + if (!syncBlocks()) { + return false; + } + + m_limitLba = (lba + 1024); //arbitrary limit + + // prepare DMA for data transfer + dmaTrxPrepare(ptr, 512, TRX_WR); // 1 block, write transfer + + // send command to start data transfer + if ( !cardCommand(CMD25_XFERTYP, (m_highCapacity ? lba : 512*lba)) ) { + return sdError(SD_CARD_ERROR_CMD25); + } + m_curLba = lba; + m_curState = WRITE_STATE; + + } + else { + if (yieldTimeout(isBusyCMD13)) { // wait for previous transmission end + return sdError(SD_CARD_ERROR_CMD13); + } + // prepare DMA for data transfer + dmaTrxPrepare(ptr, 512, TRX_WR); // 1 block, write transfer + } + + // prepare SDIO for data transfer + dmaTrxStart(512, TRX_WR); // 1 block, write transfer + + if (!dmaTrxEnd(0)){ + m_curState = IDLE_STATE; + m_writeErrors++; + return false; + } + m_curLba++; + if (m_curLba >= m_limitLba) { + syncBlocks(); + } + return true; } /*---------------------------------------------------------------------------*/ bool SdioCard::writeBlocks(uint32_t lba, const uint8_t* buf, size_t n) @@ -770,14 +1050,43 @@ bool SdioCard::writeBlocks(uint32_t lba, const uint8_t* buf, size_t n) return sdError(SD_CARD_ERROR_ACMD23); } #endif - // send command to start data transfer - if ( !cardCommand(CMD25_XFERTYP, (m_highCapacity ? lba : 512*lba)) ) { - return sdError(SD_CARD_ERROR_CMD25); - } - // prepare SDIO and DMA for data transfer - dmaTrxStart((uint8_t *)buf, 512*n, TRX_WR); // n blocks, write transfer - return dmaTrxEnd(1); + if (m_curState != WRITE_STATE || m_curLba != lba) { + if (!syncBlocks()) { + return false; + } + + m_limitLba = (lba + 1024); //arbitrary limit, 512KB + // prepare DMA for data transfer + dmaTrxPrepare((uint8_t *)buf, 512*n, TRX_WR); // n blocks, write transfer + + // send command to start data transfer + if ( !cardCommand(CMD25_XFERTYP, (m_highCapacity ? lba : 512*lba)) ) { + return sdError(SD_CARD_ERROR_CMD25); + } + m_curLba = lba; + m_curState = WRITE_STATE; + + } + else { + // prepare DMA for data transfer + dmaTrxPrepare((uint8_t *)buf, 512*n, TRX_WR); // n blocks, write transfer + } + + // prepare SDIO for data transfer + dmaTrxStart(512*n, TRX_WR); // n blocks, write transfer + + if (!dmaTrxEnd(0)){ + m_writeErrors++; + m_curState = IDLE_STATE; + return false; + } + m_curLba += n; + if (m_curLba >= m_limitLba) { + syncBlocks(); + } + return true; + } /*---------------------------------------------------------------------------*/ bool SdioCard::writeData(const uint8_t* src) @@ -845,8 +1154,14 @@ bool SdioCard::writeStart(uint32_t lba, uint32_t count) /*---------------------------------------------------------------------------*/ bool SdioCard::writeStop() { - //Serial.println("writeStop."); - m_lba = 0; - m_cnt = 0; - return true; + if ( isEnabledDMA()){ + if ( !waitDmaStatus() ) { + DBG_PRINT(); + return sdError(SD_CARD_ERROR_DMA); + } + } + m_lba = 0; + m_curState = IDLE_STATE; + return trxStop(); + //Serial.println("writeStop."); } diff --git a/STM32F1/libraries/SDIO/SdioF1.h b/STM32F1/libraries/SDIO/SdioF1.h index c995b1c..efa4774 100644 --- a/STM32F1/libraries/SDIO/SdioF1.h +++ b/STM32F1/libraries/SDIO/SdioF1.h @@ -1,6 +1,6 @@ -#ifndef _SDIOF4_H_ -#define _SDIOF4_H_ +#ifndef _SDIOF1_H_ +#define _SDIOF1_H_ #include From 58ccf76c2a7b85ab1c038b983af2c72af39a62ac Mon Sep 17 00:00:00 2001 From: victorpv Date: Wed, 28 Mar 2018 22:01:48 -0500 Subject: [PATCH 300/351] stm_fft library With extra fft 16 bins function --- .../libraries/stm_fft/cr4_fft_1024_stm32.asm | 577 ++++++++++++++++++ .../libraries/stm_fft/cr4_fft_16_stm33.asm | 250 ++++++++ .../libraries/stm_fft/cr4_fft_256_stm32.asm | 318 ++++++++++ .../libraries/stm_fft/cr4_fft_64_stm32.asm | 249 ++++++++ STM32F1/libraries/stm_fft/cr4_fft_stm32.h | 39 ++ STM32F1/libraries/stm_fft/table_fft.h | 377 ++++++++++++ 6 files changed, 1810 insertions(+) create mode 100644 STM32F1/libraries/stm_fft/cr4_fft_1024_stm32.asm create mode 100644 STM32F1/libraries/stm_fft/cr4_fft_16_stm33.asm create mode 100644 STM32F1/libraries/stm_fft/cr4_fft_256_stm32.asm create mode 100644 STM32F1/libraries/stm_fft/cr4_fft_64_stm32.asm create mode 100644 STM32F1/libraries/stm_fft/cr4_fft_stm32.h create mode 100644 STM32F1/libraries/stm_fft/table_fft.h diff --git a/STM32F1/libraries/stm_fft/cr4_fft_1024_stm32.asm b/STM32F1/libraries/stm_fft/cr4_fft_1024_stm32.asm new file mode 100644 index 0000000..26c1726 --- /dev/null +++ b/STM32F1/libraries/stm_fft/cr4_fft_1024_stm32.asm @@ -0,0 +1,577 @@ +/*;******************** (C) COPYRIGHT 2009 STMicroelectronics ******************** +;* File Name : cr4_fft_1024_stm32.s +;* Author : MCD Application Team +;* Version : V2.0.0 +;* Date : 04/27/2009 +;* Description : Optimized 1024-point radix-4 complex FFT for Cortex-M3 +;******************************************************************************** +;* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS +;* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. +;* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, +;* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE +;* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING +;* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. +;*******************************************************************************/ + +.cpu cortex-m3 +.fpu softvfp +.syntax unified +.thumb +.text + +.global cr4_fft_1024_stm32 +.extern TableFFT + +.equ NPT, 1024 + + +/*;******************************************************************************* +;* Function Name : cr4_fft_1024_stm32 +;* Description : complex radix-4 1024 points FFT +;* Input : - R0 = pssOUT: Output array . +;* - R1 = pssIN: Input array +;* - R2 = Nbin: =1024 number of points, this optimized FFT function +;* can only convert 1024 points. +;* Output : None +;* Return : None +;*********************************************************************************/ +.thumb_func +cr4_fft_1024_stm32: + + STMFD SP!, {R4-R11, LR} + + MOV r12, #0 + MOV r3, r0 + MOV r0,#0 + +preloop_v7: + ADD r14, r1, r12, LSR#22 /*1024pts*/ + + LDRSH r5, [r14, #2] + LDRSH r4, [r14] + ADD r14, #NPT + LDRSH r9, [r14, #2] + LDRSH r8, [r14] + ADD r14, #NPT + LDRSH r7, [r14, #2] + LDRSH r6, [r14] + ADD r14, #NPT + LDRSH r11, [r14, #2] + LDRSH r10, [r14] + ADD r14, #NPT + + + ADD r8, r8, r10 + ADD r9, r9, r11 + SUB r10, r8, r10, LSL#1 + SUB r11, r9, r11, LSL#1 + + MOV r4, r4, ASR#2 + MOV r5, r5, ASR#2 + ADD r4, r4, r6, ASR#2 + ADD r5, r5, r7, ASR#2 + SUB r6, r4, r6, ASR#1 + SUB r7, r5, r7, ASR#1 + + ADD r4, r4, r8, ASR#2 + ADD r5, r5, r9, ASR#2 + SUB r8, r4, r8, ASR#1 + SUB r9, r5, r9, ASR#1 + + ADD r6, r6, r11, ASR#2 + SUB r7, r7, r10, ASR#2 + SUB r11, r6, r11, ASR#1 + ADD r10, r7, r10, ASR#1 + + STRH r5, [r3, #2] + STRH r4, [r3], #4 + STRH r7, [r3, #2] + STRH r6, [r3], #4 + STRH r9, [r3, #2] + STRH r8, [r3], #4 + STRH r10, [r3, #2] + STRH r11, [r3], #4 + + ADD r0, r0, #1 + + RBIT r12, r0 + + CMP r0,#256 /*1024pts*/ + BNE preloop_v7 + + SUB r1, r3, r2, LSL#2 + MOV r0, #16 + MOVS r2, r2, LSR#4 + +/*;------------------------------------------------------------------------------ +; The FFT coefficients table can be stored into Flash or RAM. +; The following two lines of code allow selecting the method for coefficients +; storage. +; In the case of choosing coefficients in RAM, you have to: +; 1. Include the file table_fft.h, which is a part of the DSP library, +; in your main file. +; 2. Decomment the line LDR.W pssK, =TableFFT and comment the line +; ADRL pssK, TableFFT_V7 +; 3. Comment all the TableFFT_V7 data. +;------------------------------------------------------------------------------*/ + ADR r3, TableFFT_V7 + /*LDR.W r3, =TableFFT*/ + + +passloop_v7: + STMFD SP!, {r1,r2} + ADD r12, r0, r0, LSL#1 + ADD r1, r1, r12 + SUB r2, r2, #1<<16 + +grouploop_v7: + ADD r2,r2,r0,LSL#(16-2) + +butterloop_v7: + + LDRSH r5, [r1, #2] + LDRSH r4, [r1] + SUB r1, r1, r0 + + LDRSH r11, [r3, #2] + LDRSH r10, [r3] + ADD r3, r3, #4 + + SUB r14, r5, r4 + MUL r12, r14, r11 + ADD r14, r10, r11, LSL#1 + MLA r11, r5, r10, r12 + MLA r10, r4, r14, r12 + + LDRSH r5, [r1, #2] + LDRSH r4, [r1] + SUB r1, r1, r0 + + LDRSH r9, [r3, #2] + LDRSH r8, [r3] + ADD r3, r3, #4 + + SUB r14, r5, r4 + MUL r12, r14, r9 + ADD r14, r8, r9, LSL#1 + MLA r9, r5, r8, r12 + MLA r8, r4, r14, r12 + + LDRSH r5, [r1, #2] + LDRSH r4, [r1] + SUB r1, r1, r0 + + LDRSH r7, [r3, #2] + LDRSH r6, [r3] + ADD r3, r3, #4 + + SUB r14, r5, r4 + MUL r12, r14, r7 + ADD r14, r6, r7, LSL#1 + MLA r7, r5, r6, r12 + MLA r6, r4, r14, r12 + + LDRSH r5, [r1, #2] + LDRSH r4, [r1] + + ADD r8, r8, r10 + ADD r9, r9, r11 + SUB r10, r8, r10, LSL#1 + SUB r11, r9, r11, LSL#1 + + MOV r4, r4, ASR#2 + MOV r5, r5, ASR#2 + ADD r4, r4, r6, ASR#(2+14) + ADD r5, r5, r7, ASR#(2+14) + SUB r6, r4, r6, ASR#(1+14) + SUB r7, r5, r7, ASR#(1+14) + + ADD r4, r4, r8, ASR#(2+14) + ADD r5, r5, r9, ASR#(2+14) + SUB r8, r4, r8, ASR#(1+14) + SUB r9, r5, r9, ASR#(1+14) + + ADD r6, r6, r11, ASR#(2+14) + SUB r7, r7, r10, ASR#(2+14) + SUB r11, r6, r11, ASR#(1+14) + ADD r10, r7, r10, ASR#(1+14) + + STRH r5, [r1, #2] + STRH r4, [r1] + ADD r1, r1, r0 + STRH r7, [r1, #2] + STRH r6, [r1] + ADD r1, r1, r0 + STRH r9, [r1, #2] + STRH r8, [r1] + ADD r1, r1, r0 + STRH r10, [r1, #2] + STRH r11, [r1], #4 + SUBS r2,r2, #1<<16 + BGE butterloop_v7 + ADD r12, r0, r0, LSL#1 + ADD r1, r1, r12 + + SUB r2, r2, #1 + MOVS r14, r2, LSL#16 + IT ne + SUBNE r3, r3, r12 + BNE grouploop_v7 + + LDMFD sp!, {r1, r2} + MOV r0,r0,LSL#2 + MOVS r2, r2, LSR#2 + BNE passloop_v7 + LDMFD SP!, {R4-R11, PC} + + +TableFFT_V7: + + /*N=16*/ + .short 0x4000,0x0000, 0x4000,0x0000, 0x4000,0x0000 + .short 0xdd5d,0x3b21, 0x22a3,0x187e, 0x0000,0x2d41 + .short 0xa57e,0x2d41, 0x0000,0x2d41, 0xc000,0x4000 + .short 0xdd5d,0xe782, 0xdd5d,0x3b21, 0xa57e,0x2d41 + /*N=64*/ + .short 0x4000,0x0000, 0x4000,0x0000, 0x4000,0x0000 + .short 0x2aaa,0x1294, 0x396b,0x0646, 0x3249,0x0c7c + .short 0x11a8,0x238e, 0x3249,0x0c7c, 0x22a3,0x187e + .short 0xf721,0x3179, 0x2aaa,0x1294, 0x11a8,0x238e + .short 0xdd5d,0x3b21, 0x22a3,0x187e, 0x0000,0x2d41 + .short 0xc695,0x3fb1, 0x1a46,0x1e2b, 0xee58,0x3537 + .short 0xb4be,0x3ec5, 0x11a8,0x238e, 0xdd5d,0x3b21 + .short 0xa963,0x3871, 0x08df,0x289a, 0xcdb7,0x3ec5 + .short 0xa57e,0x2d41, 0x0000,0x2d41, 0xc000,0x4000 + .short 0xa963,0x1e2b, 0xf721,0x3179, 0xb4be,0x3ec5 + .short 0xb4be,0x0c7c, 0xee58,0x3537, 0xac61,0x3b21 + .short 0xc695,0xf9ba, 0xe5ba,0x3871, 0xa73b,0x3537 + .short 0xdd5d,0xe782, 0xdd5d,0x3b21, 0xa57e,0x2d41 + .short 0xf721,0xd766, 0xd556,0x3d3f, 0xa73b,0x238e + .short 0x11a8,0xcac9, 0xcdb7,0x3ec5, 0xac61,0x187e + .short 0x2aaa,0xc2c1, 0xc695,0x3fb1, 0xb4be,0x0c7c + /*N=256*/ + .short 0x4000,0x0000, 0x4000,0x0000, 0x4000,0x0000 + .short 0x3b1e,0x04b5, 0x3e69,0x0192, 0x3cc8,0x0324 + .short 0x35eb,0x0964, 0x3cc8,0x0324, 0x396b,0x0646 + .short 0x306c,0x0e06, 0x3b1e,0x04b5, 0x35eb,0x0964 + .short 0x2aaa,0x1294, 0x396b,0x0646, 0x3249,0x0c7c + .short 0x24ae,0x1709, 0x37af,0x07d6, 0x2e88,0x0f8d + .short 0x1e7e,0x1b5d, 0x35eb,0x0964, 0x2aaa,0x1294 + .short 0x1824,0x1f8c, 0x341e,0x0af1, 0x26b3,0x1590 + .short 0x11a8,0x238e, 0x3249,0x0c7c, 0x22a3,0x187e + .short 0x0b14,0x2760, 0x306c,0x0e06, 0x1e7e,0x1b5d + .short 0x0471,0x2afb, 0x2e88,0x0f8d, 0x1a46,0x1e2b + .short 0xfdc7,0x2e5a, 0x2c9d,0x1112, 0x15fe,0x20e7 + .short 0xf721,0x3179, 0x2aaa,0x1294, 0x11a8,0x238e + .short 0xf087,0x3453, 0x28b2,0x1413, 0x0d48,0x2620 + .short 0xea02,0x36e5, 0x26b3,0x1590, 0x08df,0x289a + .short 0xe39c,0x392b, 0x24ae,0x1709, 0x0471,0x2afb + .short 0xdd5d,0x3b21, 0x22a3,0x187e, 0x0000,0x2d41 + .short 0xd74e,0x3cc5, 0x2093,0x19ef, 0xfb8f,0x2f6c + .short 0xd178,0x3e15, 0x1e7e,0x1b5d, 0xf721,0x3179 + .short 0xcbe2,0x3f0f, 0x1c64,0x1cc6, 0xf2b8,0x3368 + .short 0xc695,0x3fb1, 0x1a46,0x1e2b, 0xee58,0x3537 + .short 0xc197,0x3ffb, 0x1824,0x1f8c, 0xea02,0x36e5 + .short 0xbcf0,0x3fec, 0x15fe,0x20e7, 0xe5ba,0x3871 + .short 0xb8a6,0x3f85, 0x13d5,0x223d, 0xe182,0x39db + .short 0xb4be,0x3ec5, 0x11a8,0x238e, 0xdd5d,0x3b21 + .short 0xb140,0x3daf, 0x0f79,0x24da, 0xd94d,0x3c42 + .short 0xae2e,0x3c42, 0x0d48,0x2620, 0xd556,0x3d3f + .short 0xab8e,0x3a82, 0x0b14,0x2760, 0xd178,0x3e15 + .short 0xa963,0x3871, 0x08df,0x289a, 0xcdb7,0x3ec5 + .short 0xa7b1,0x3612, 0x06a9,0x29ce, 0xca15,0x3f4f + .short 0xa678,0x3368, 0x0471,0x2afb, 0xc695,0x3fb1 + .short 0xa5bc,0x3076, 0x0239,0x2c21, 0xc338,0x3fec + .short 0xa57e,0x2d41, 0x0000,0x2d41, 0xc000,0x4000 + .short 0xa5bc,0x29ce, 0xfdc7,0x2e5a, 0xbcf0,0x3fec + .short 0xa678,0x2620, 0xfb8f,0x2f6c, 0xba09,0x3fb1 + .short 0xa7b1,0x223d, 0xf957,0x3076, 0xb74d,0x3f4f + .short 0xa963,0x1e2b, 0xf721,0x3179, 0xb4be,0x3ec5 + .short 0xab8e,0x19ef, 0xf4ec,0x3274, 0xb25e,0x3e15 + .short 0xae2e,0x1590, 0xf2b8,0x3368, 0xb02d,0x3d3f + .short 0xb140,0x1112, 0xf087,0x3453, 0xae2e,0x3c42 + .short 0xb4be,0x0c7c, 0xee58,0x3537, 0xac61,0x3b21 + .short 0xb8a6,0x07d6, 0xec2b,0x3612, 0xaac8,0x39db + .short 0xbcf0,0x0324, 0xea02,0x36e5, 0xa963,0x3871 + .short 0xc197,0xfe6e, 0xe7dc,0x37b0, 0xa834,0x36e5 + .short 0xc695,0xf9ba, 0xe5ba,0x3871, 0xa73b,0x3537 + .short 0xcbe2,0xf50f, 0xe39c,0x392b, 0xa678,0x3368 + .short 0xd178,0xf073, 0xe182,0x39db, 0xa5ed,0x3179 + .short 0xd74e,0xebed, 0xdf6d,0x3a82, 0xa599,0x2f6c + .short 0xdd5d,0xe782, 0xdd5d,0x3b21, 0xa57e,0x2d41 + .short 0xe39c,0xe33a, 0xdb52,0x3bb6, 0xa599,0x2afb + .short 0xea02,0xdf19, 0xd94d,0x3c42, 0xa5ed,0x289a + .short 0xf087,0xdb26, 0xd74e,0x3cc5, 0xa678,0x2620 + .short 0xf721,0xd766, 0xd556,0x3d3f, 0xa73b,0x238e + .short 0xfdc7,0xd3df, 0xd363,0x3daf, 0xa834,0x20e7 + .short 0x0471,0xd094, 0xd178,0x3e15, 0xa963,0x1e2b + .short 0x0b14,0xcd8c, 0xcf94,0x3e72, 0xaac8,0x1b5d + .short 0x11a8,0xcac9, 0xcdb7,0x3ec5, 0xac61,0x187e + .short 0x1824,0xc850, 0xcbe2,0x3f0f, 0xae2e,0x1590 + .short 0x1e7e,0xc625, 0xca15,0x3f4f, 0xb02d,0x1294 + .short 0x24ae,0xc44a, 0xc851,0x3f85, 0xb25e,0x0f8d + .short 0x2aaa,0xc2c1, 0xc695,0x3fb1, 0xb4be,0x0c7c + .short 0x306c,0xc18e, 0xc4e2,0x3fd4, 0xb74d,0x0964 + .short 0x35eb,0xc0b1, 0xc338,0x3fec, 0xba09,0x0646 + .short 0x3b1e,0xc02c, 0xc197,0x3ffb, 0xbcf0,0x0324 + /*N=1024*/ + .short 0x4000,0x0000, 0x4000,0x0000, 0x4000,0x0000 + .short 0x3ed0,0x012e, 0x3f9b,0x0065, 0x3f36,0x00c9 + .short 0x3d9a,0x025b, 0x3f36,0x00c9, 0x3e69,0x0192 + .short 0x3c5f,0x0388, 0x3ed0,0x012e, 0x3d9a,0x025b + .short 0x3b1e,0x04b5, 0x3e69,0x0192, 0x3cc8,0x0324 + .short 0x39d9,0x05e2, 0x3e02,0x01f7, 0x3bf4,0x03ed + .short 0x388e,0x070e, 0x3d9a,0x025b, 0x3b1e,0x04b5 + .short 0x373f,0x0839, 0x3d31,0x02c0, 0x3a46,0x057e + .short 0x35eb,0x0964, 0x3cc8,0x0324, 0x396b,0x0646 + .short 0x3492,0x0a8e, 0x3c5f,0x0388, 0x388e,0x070e + .short 0x3334,0x0bb7, 0x3bf4,0x03ed, 0x37af,0x07d6 + .short 0x31d2,0x0cdf, 0x3b8a,0x0451, 0x36ce,0x089d + .short 0x306c,0x0e06, 0x3b1e,0x04b5, 0x35eb,0x0964 + .short 0x2f02,0x0f2b, 0x3ab2,0x051a, 0x3505,0x0a2b + .short 0x2d93,0x1050, 0x3a46,0x057e, 0x341e,0x0af1 + .short 0x2c21,0x1173, 0x39d9,0x05e2, 0x3334,0x0bb7 + .short 0x2aaa,0x1294, 0x396b,0x0646, 0x3249,0x0c7c + .short 0x2931,0x13b4, 0x38fd,0x06aa, 0x315b,0x0d41 + .short 0x27b3,0x14d2, 0x388e,0x070e, 0x306c,0x0e06 + .short 0x2632,0x15ee, 0x381f,0x0772, 0x2f7b,0x0eca + .short 0x24ae,0x1709, 0x37af,0x07d6, 0x2e88,0x0f8d + .short 0x2326,0x1821, 0x373f,0x0839, 0x2d93,0x1050 + .short 0x219c,0x1937, 0x36ce,0x089d, 0x2c9d,0x1112 + .short 0x200e,0x1a4b, 0x365d,0x0901, 0x2ba4,0x11d3 + .short 0x1e7e,0x1b5d, 0x35eb,0x0964, 0x2aaa,0x1294 + .short 0x1ceb,0x1c6c, 0x3578,0x09c7, 0x29af,0x1354 + .short 0x1b56,0x1d79, 0x3505,0x0a2b, 0x28b2,0x1413 + .short 0x19be,0x1e84, 0x3492,0x0a8e, 0x27b3,0x14d2 + .short 0x1824,0x1f8c, 0x341e,0x0af1, 0x26b3,0x1590 + .short 0x1688,0x2091, 0x33a9,0x0b54, 0x25b1,0x164c + .short 0x14ea,0x2193, 0x3334,0x0bb7, 0x24ae,0x1709 + .short 0x134a,0x2292, 0x32bf,0x0c1a, 0x23a9,0x17c4 + .short 0x11a8,0x238e, 0x3249,0x0c7c, 0x22a3,0x187e + .short 0x1005,0x2488, 0x31d2,0x0cdf, 0x219c,0x1937 + .short 0x0e61,0x257e, 0x315b,0x0d41, 0x2093,0x19ef + .short 0x0cbb,0x2671, 0x30e4,0x0da4, 0x1f89,0x1aa7 + .short 0x0b14,0x2760, 0x306c,0x0e06, 0x1e7e,0x1b5d + .short 0x096d,0x284c, 0x2ff4,0x0e68, 0x1d72,0x1c12 + .short 0x07c4,0x2935, 0x2f7b,0x0eca, 0x1c64,0x1cc6 + .short 0x061b,0x2a1a, 0x2f02,0x0f2b, 0x1b56,0x1d79 + .short 0x0471,0x2afb, 0x2e88,0x0f8d, 0x1a46,0x1e2b + .short 0x02c7,0x2bd8, 0x2e0e,0x0fee, 0x1935,0x1edc + .short 0x011c,0x2cb2, 0x2d93,0x1050, 0x1824,0x1f8c + .short 0xff72,0x2d88, 0x2d18,0x10b1, 0x1711,0x203a + .short 0xfdc7,0x2e5a, 0x2c9d,0x1112, 0x15fe,0x20e7 + .short 0xfc1d,0x2f28, 0x2c21,0x1173, 0x14ea,0x2193 + .short 0xfa73,0x2ff2, 0x2ba4,0x11d3, 0x13d5,0x223d + .short 0xf8ca,0x30b8, 0x2b28,0x1234, 0x12bf,0x22e7 + .short 0xf721,0x3179, 0x2aaa,0x1294, 0x11a8,0x238e + .short 0xf579,0x3236, 0x2a2d,0x12f4, 0x1091,0x2435 + .short 0xf3d2,0x32ef, 0x29af,0x1354, 0x0f79,0x24da + .short 0xf22c,0x33a3, 0x2931,0x13b4, 0x0e61,0x257e + .short 0xf087,0x3453, 0x28b2,0x1413, 0x0d48,0x2620 + .short 0xeee3,0x34ff, 0x2833,0x1473, 0x0c2e,0x26c1 + .short 0xed41,0x35a5, 0x27b3,0x14d2, 0x0b14,0x2760 + .short 0xeba1,0x3648, 0x2733,0x1531, 0x09fa,0x27fe + .short 0xea02,0x36e5, 0x26b3,0x1590, 0x08df,0x289a + .short 0xe865,0x377e, 0x2632,0x15ee, 0x07c4,0x2935 + .short 0xe6cb,0x3812, 0x25b1,0x164c, 0x06a9,0x29ce + .short 0xe532,0x38a1, 0x252f,0x16ab, 0x058d,0x2a65 + .short 0xe39c,0x392b, 0x24ae,0x1709, 0x0471,0x2afb + .short 0xe208,0x39b0, 0x242b,0x1766, 0x0355,0x2b8f + .short 0xe077,0x3a30, 0x23a9,0x17c4, 0x0239,0x2c21 + .short 0xdee9,0x3aab, 0x2326,0x1821, 0x011c,0x2cb2 + .short 0xdd5d,0x3b21, 0x22a3,0x187e, 0x0000,0x2d41 + .short 0xdbd5,0x3b92, 0x221f,0x18db, 0xfee4,0x2dcf + .short 0xda4f,0x3bfd, 0x219c,0x1937, 0xfdc7,0x2e5a + .short 0xd8cd,0x3c64, 0x2117,0x1993, 0xfcab,0x2ee4 + .short 0xd74e,0x3cc5, 0x2093,0x19ef, 0xfb8f,0x2f6c + .short 0xd5d3,0x3d21, 0x200e,0x1a4b, 0xfa73,0x2ff2 + .short 0xd45c,0x3d78, 0x1f89,0x1aa7, 0xf957,0x3076 + .short 0xd2e8,0x3dc9, 0x1f04,0x1b02, 0xf83c,0x30f9 + .short 0xd178,0x3e15, 0x1e7e,0x1b5d, 0xf721,0x3179 + .short 0xd00c,0x3e5c, 0x1df8,0x1bb8, 0xf606,0x31f8 + .short 0xcea5,0x3e9d, 0x1d72,0x1c12, 0xf4ec,0x3274 + .short 0xcd41,0x3ed8, 0x1ceb,0x1c6c, 0xf3d2,0x32ef + .short 0xcbe2,0x3f0f, 0x1c64,0x1cc6, 0xf2b8,0x3368 + .short 0xca88,0x3f40, 0x1bdd,0x1d20, 0xf19f,0x33df + .short 0xc932,0x3f6b, 0x1b56,0x1d79, 0xf087,0x3453 + .short 0xc7e1,0x3f91, 0x1ace,0x1dd3, 0xef6f,0x34c6 + .short 0xc695,0x3fb1, 0x1a46,0x1e2b, 0xee58,0x3537 + .short 0xc54e,0x3fcc, 0x19be,0x1e84, 0xed41,0x35a5 + .short 0xc40c,0x3fe1, 0x1935,0x1edc, 0xec2b,0x3612 + .short 0xc2cf,0x3ff1, 0x18ad,0x1f34, 0xeb16,0x367d + .short 0xc197,0x3ffb, 0x1824,0x1f8c, 0xea02,0x36e5 + .short 0xc065,0x4000, 0x179b,0x1fe3, 0xe8ef,0x374b + .short 0xbf38,0x3fff, 0x1711,0x203a, 0xe7dc,0x37b0 + .short 0xbe11,0x3ff8, 0x1688,0x2091, 0xe6cb,0x3812 + .short 0xbcf0,0x3fec, 0x15fe,0x20e7, 0xe5ba,0x3871 + .short 0xbbd4,0x3fdb, 0x1574,0x213d, 0xe4aa,0x38cf + .short 0xbabf,0x3fc4, 0x14ea,0x2193, 0xe39c,0x392b + .short 0xb9af,0x3fa7, 0x145f,0x21e8, 0xe28e,0x3984 + .short 0xb8a6,0x3f85, 0x13d5,0x223d, 0xe182,0x39db + .short 0xb7a2,0x3f5d, 0x134a,0x2292, 0xe077,0x3a30 + .short 0xb6a5,0x3f30, 0x12bf,0x22e7, 0xdf6d,0x3a82 + .short 0xb5af,0x3efd, 0x1234,0x233b, 0xde64,0x3ad3 + .short 0xb4be,0x3ec5, 0x11a8,0x238e, 0xdd5d,0x3b21 + .short 0xb3d5,0x3e88, 0x111d,0x23e2, 0xdc57,0x3b6d + .short 0xb2f2,0x3e45, 0x1091,0x2435, 0xdb52,0x3bb6 + .short 0xb215,0x3dfc, 0x1005,0x2488, 0xda4f,0x3bfd + .short 0xb140,0x3daf, 0x0f79,0x24da, 0xd94d,0x3c42 + .short 0xb071,0x3d5b, 0x0eed,0x252c, 0xd84d,0x3c85 + .short 0xafa9,0x3d03, 0x0e61,0x257e, 0xd74e,0x3cc5 + .short 0xaee8,0x3ca5, 0x0dd4,0x25cf, 0xd651,0x3d03 + .short 0xae2e,0x3c42, 0x0d48,0x2620, 0xd556,0x3d3f + .short 0xad7b,0x3bda, 0x0cbb,0x2671, 0xd45c,0x3d78 + .short 0xacd0,0x3b6d, 0x0c2e,0x26c1, 0xd363,0x3daf + .short 0xac2b,0x3afa, 0x0ba1,0x2711, 0xd26d,0x3de3 + .short 0xab8e,0x3a82, 0x0b14,0x2760, 0xd178,0x3e15 + .short 0xaaf8,0x3a06, 0x0a87,0x27af, 0xd085,0x3e45 + .short 0xaa6a,0x3984, 0x09fa,0x27fe, 0xcf94,0x3e72 + .short 0xa9e3,0x38fd, 0x096d,0x284c, 0xcea5,0x3e9d + .short 0xa963,0x3871, 0x08df,0x289a, 0xcdb7,0x3ec5 + .short 0xa8eb,0x37e1, 0x0852,0x28e7, 0xcccc,0x3eeb + .short 0xa87b,0x374b, 0x07c4,0x2935, 0xcbe2,0x3f0f + .short 0xa812,0x36b1, 0x0736,0x2981, 0xcafb,0x3f30 + .short 0xa7b1,0x3612, 0x06a9,0x29ce, 0xca15,0x3f4f + .short 0xa757,0x356e, 0x061b,0x2a1a, 0xc932,0x3f6b + .short 0xa705,0x34c6, 0x058d,0x2a65, 0xc851,0x3f85 + .short 0xa6bb,0x3419, 0x04ff,0x2ab0, 0xc772,0x3f9c + .short 0xa678,0x3368, 0x0471,0x2afb, 0xc695,0x3fb1 + .short 0xa63e,0x32b2, 0x03e3,0x2b45, 0xc5ba,0x3fc4 + .short 0xa60b,0x31f8, 0x0355,0x2b8f, 0xc4e2,0x3fd4 + .short 0xa5e0,0x3139, 0x02c7,0x2bd8, 0xc40c,0x3fe1 + .short 0xa5bc,0x3076, 0x0239,0x2c21, 0xc338,0x3fec + .short 0xa5a1,0x2faf, 0x01aa,0x2c6a, 0xc266,0x3ff5 + .short 0xa58d,0x2ee4, 0x011c,0x2cb2, 0xc197,0x3ffb + .short 0xa581,0x2e15, 0x008e,0x2cfa, 0xc0ca,0x3fff + .short 0xa57e,0x2d41, 0x0000,0x2d41, 0xc000,0x4000 + .short 0xa581,0x2c6a, 0xff72,0x2d88, 0xbf38,0x3fff + .short 0xa58d,0x2b8f, 0xfee4,0x2dcf, 0xbe73,0x3ffb + .short 0xa5a1,0x2ab0, 0xfe56,0x2e15, 0xbdb0,0x3ff5 + .short 0xa5bc,0x29ce, 0xfdc7,0x2e5a, 0xbcf0,0x3fec + .short 0xa5e0,0x28e7, 0xfd39,0x2e9f, 0xbc32,0x3fe1 + .short 0xa60b,0x27fe, 0xfcab,0x2ee4, 0xbb77,0x3fd4 + .short 0xa63e,0x2711, 0xfc1d,0x2f28, 0xbabf,0x3fc4 + .short 0xa678,0x2620, 0xfb8f,0x2f6c, 0xba09,0x3fb1 + .short 0xa6bb,0x252c, 0xfb01,0x2faf, 0xb956,0x3f9c + .short 0xa705,0x2435, 0xfa73,0x2ff2, 0xb8a6,0x3f85 + .short 0xa757,0x233b, 0xf9e5,0x3034, 0xb7f8,0x3f6b + .short 0xa7b1,0x223d, 0xf957,0x3076, 0xb74d,0x3f4f + .short 0xa812,0x213d, 0xf8ca,0x30b8, 0xb6a5,0x3f30 + .short 0xa87b,0x203a, 0xf83c,0x30f9, 0xb600,0x3f0f + .short 0xa8eb,0x1f34, 0xf7ae,0x3139, 0xb55e,0x3eeb + .short 0xa963,0x1e2b, 0xf721,0x3179, 0xb4be,0x3ec5 + .short 0xa9e3,0x1d20, 0xf693,0x31b9, 0xb422,0x3e9d + .short 0xaa6a,0x1c12, 0xf606,0x31f8, 0xb388,0x3e72 + .short 0xaaf8,0x1b02, 0xf579,0x3236, 0xb2f2,0x3e45 + .short 0xab8e,0x19ef, 0xf4ec,0x3274, 0xb25e,0x3e15 + .short 0xac2b,0x18db, 0xf45f,0x32b2, 0xb1cd,0x3de3 + .short 0xacd0,0x17c4, 0xf3d2,0x32ef, 0xb140,0x3daf + .short 0xad7b,0x16ab, 0xf345,0x332c, 0xb0b5,0x3d78 + .short 0xae2e,0x1590, 0xf2b8,0x3368, 0xb02d,0x3d3f + .short 0xaee8,0x1473, 0xf22c,0x33a3, 0xafa9,0x3d03 + .short 0xafa9,0x1354, 0xf19f,0x33df, 0xaf28,0x3cc5 + .short 0xb071,0x1234, 0xf113,0x3419, 0xaea9,0x3c85 + .short 0xb140,0x1112, 0xf087,0x3453, 0xae2e,0x3c42 + .short 0xb215,0x0fee, 0xeffb,0x348d, 0xadb6,0x3bfd + .short 0xb2f2,0x0eca, 0xef6f,0x34c6, 0xad41,0x3bb6 + .short 0xb3d5,0x0da4, 0xeee3,0x34ff, 0xacd0,0x3b6d + .short 0xb4be,0x0c7c, 0xee58,0x3537, 0xac61,0x3b21 + .short 0xb5af,0x0b54, 0xedcc,0x356e, 0xabf6,0x3ad3 + .short 0xb6a5,0x0a2b, 0xed41,0x35a5, 0xab8e,0x3a82 + .short 0xb7a2,0x0901, 0xecb6,0x35dc, 0xab29,0x3a30 + .short 0xb8a6,0x07d6, 0xec2b,0x3612, 0xaac8,0x39db + .short 0xb9af,0x06aa, 0xeba1,0x3648, 0xaa6a,0x3984 + .short 0xbabf,0x057e, 0xeb16,0x367d, 0xaa0f,0x392b + .short 0xbbd4,0x0451, 0xea8c,0x36b1, 0xa9b7,0x38cf + .short 0xbcf0,0x0324, 0xea02,0x36e5, 0xa963,0x3871 + .short 0xbe11,0x01f7, 0xe978,0x3718, 0xa912,0x3812 + .short 0xbf38,0x00c9, 0xe8ef,0x374b, 0xa8c5,0x37b0 + .short 0xc065,0xff9b, 0xe865,0x377e, 0xa87b,0x374b + .short 0xc197,0xfe6e, 0xe7dc,0x37b0, 0xa834,0x36e5 + .short 0xc2cf,0xfd40, 0xe753,0x37e1, 0xa7f1,0x367d + .short 0xc40c,0xfc13, 0xe6cb,0x3812, 0xa7b1,0x3612 + .short 0xc54e,0xfae6, 0xe642,0x3842, 0xa774,0x35a5 + .short 0xc695,0xf9ba, 0xe5ba,0x3871, 0xa73b,0x3537 + .short 0xc7e1,0xf88e, 0xe532,0x38a1, 0xa705,0x34c6 + .short 0xc932,0xf763, 0xe4aa,0x38cf, 0xa6d3,0x3453 + .short 0xca88,0xf639, 0xe423,0x38fd, 0xa6a4,0x33df + .short 0xcbe2,0xf50f, 0xe39c,0x392b, 0xa678,0x3368 + .short 0xcd41,0xf3e6, 0xe315,0x3958, 0xa650,0x32ef + .short 0xcea5,0xf2bf, 0xe28e,0x3984, 0xa62c,0x3274 + .short 0xd00c,0xf198, 0xe208,0x39b0, 0xa60b,0x31f8 + .short 0xd178,0xf073, 0xe182,0x39db, 0xa5ed,0x3179 + .short 0xd2e8,0xef4f, 0xe0fc,0x3a06, 0xa5d3,0x30f9 + .short 0xd45c,0xee2d, 0xe077,0x3a30, 0xa5bc,0x3076 + .short 0xd5d3,0xed0c, 0xdff2,0x3a59, 0xa5a9,0x2ff2 + .short 0xd74e,0xebed, 0xdf6d,0x3a82, 0xa599,0x2f6c + .short 0xd8cd,0xeacf, 0xdee9,0x3aab, 0xa58d,0x2ee4 + .short 0xda4f,0xe9b4, 0xde64,0x3ad3, 0xa585,0x2e5a + .short 0xdbd5,0xe89a, 0xdde1,0x3afa, 0xa57f,0x2dcf + .short 0xdd5d,0xe782, 0xdd5d,0x3b21, 0xa57e,0x2d41 + .short 0xdee9,0xe66d, 0xdcda,0x3b47, 0xa57f,0x2cb2 + .short 0xe077,0xe559, 0xdc57,0x3b6d, 0xa585,0x2c21 + .short 0xe208,0xe448, 0xdbd5,0x3b92, 0xa58d,0x2b8f + .short 0xe39c,0xe33a, 0xdb52,0x3bb6, 0xa599,0x2afb + .short 0xe532,0xe22d, 0xdad1,0x3bda, 0xa5a9,0x2a65 + .short 0xe6cb,0xe124, 0xda4f,0x3bfd, 0xa5bc,0x29ce + .short 0xe865,0xe01d, 0xd9ce,0x3c20, 0xa5d3,0x2935 + .short 0xea02,0xdf19, 0xd94d,0x3c42, 0xa5ed,0x289a + .short 0xeba1,0xde18, 0xd8cd,0x3c64, 0xa60b,0x27fe + .short 0xed41,0xdd19, 0xd84d,0x3c85, 0xa62c,0x2760 + .short 0xeee3,0xdc1e, 0xd7cd,0x3ca5, 0xa650,0x26c1 + .short 0xf087,0xdb26, 0xd74e,0x3cc5, 0xa678,0x2620 + .short 0xf22c,0xda31, 0xd6cf,0x3ce4, 0xa6a4,0x257e + .short 0xf3d2,0xd93f, 0xd651,0x3d03, 0xa6d3,0x24da + .short 0xf579,0xd851, 0xd5d3,0x3d21, 0xa705,0x2435 + .short 0xf721,0xd766, 0xd556,0x3d3f, 0xa73b,0x238e + .short 0xf8ca,0xd67f, 0xd4d8,0x3d5b, 0xa774,0x22e7 + .short 0xfa73,0xd59b, 0xd45c,0x3d78, 0xa7b1,0x223d + .short 0xfc1d,0xd4bb, 0xd3df,0x3d93, 0xa7f1,0x2193 + .short 0xfdc7,0xd3df, 0xd363,0x3daf, 0xa834,0x20e7 + .short 0xff72,0xd306, 0xd2e8,0x3dc9, 0xa87b,0x203a + .short 0x011c,0xd231, 0xd26d,0x3de3, 0xa8c5,0x1f8c + .short 0x02c7,0xd161, 0xd1f2,0x3dfc, 0xa912,0x1edc + .short 0x0471,0xd094, 0xd178,0x3e15, 0xa963,0x1e2b + .short 0x061b,0xcfcc, 0xd0fe,0x3e2d, 0xa9b7,0x1d79 + .short 0x07c4,0xcf07, 0xd085,0x3e45, 0xaa0f,0x1cc6 + .short 0x096d,0xce47, 0xd00c,0x3e5c, 0xaa6a,0x1c12 + .short 0x0b14,0xcd8c, 0xcf94,0x3e72, 0xaac8,0x1b5d + .short 0x0cbb,0xccd4, 0xcf1c,0x3e88, 0xab29,0x1aa7 + .short 0x0e61,0xcc21, 0xcea5,0x3e9d, 0xab8e,0x19ef + .short 0x1005,0xcb73, 0xce2e,0x3eb1, 0xabf6,0x1937 + .short 0x11a8,0xcac9, 0xcdb7,0x3ec5, 0xac61,0x187e + .short 0x134a,0xca24, 0xcd41,0x3ed8, 0xacd0,0x17c4 + .short 0x14ea,0xc983, 0xcccc,0x3eeb, 0xad41,0x1709 + .short 0x1688,0xc8e8, 0xcc57,0x3efd, 0xadb6,0x164c + .short 0x1824,0xc850, 0xcbe2,0x3f0f, 0xae2e,0x1590 + .short 0x19be,0xc7be, 0xcb6e,0x3f20, 0xaea9,0x14d2 + .short 0x1b56,0xc731, 0xcafb,0x3f30, 0xaf28,0x1413 + .short 0x1ceb,0xc6a8, 0xca88,0x3f40, 0xafa9,0x1354 + .short 0x1e7e,0xc625, 0xca15,0x3f4f, 0xb02d,0x1294 + .short 0x200e,0xc5a7, 0xc9a3,0x3f5d, 0xb0b5,0x11d3 + .short 0x219c,0xc52d, 0xc932,0x3f6b, 0xb140,0x1112 + .short 0x2326,0xc4b9, 0xc8c1,0x3f78, 0xb1cd,0x1050 + .short 0x24ae,0xc44a, 0xc851,0x3f85, 0xb25e,0x0f8d + .short 0x2632,0xc3e0, 0xc7e1,0x3f91, 0xb2f2,0x0eca + .short 0x27b3,0xc37b, 0xc772,0x3f9c, 0xb388,0x0e06 + .short 0x2931,0xc31c, 0xc703,0x3fa7, 0xb422,0x0d41 + .short 0x2aaa,0xc2c1, 0xc695,0x3fb1, 0xb4be,0x0c7c + .short 0x2c21,0xc26d, 0xc627,0x3fbb, 0xb55e,0x0bb7 + .short 0x2d93,0xc21d, 0xc5ba,0x3fc4, 0xb600,0x0af1 + .short 0x2f02,0xc1d3, 0xc54e,0x3fcc, 0xb6a5,0x0a2b + .short 0x306c,0xc18e, 0xc4e2,0x3fd4, 0xb74d,0x0964 + .short 0x31d2,0xc14f, 0xc476,0x3fdb, 0xb7f8,0x089d + .short 0x3334,0xc115, 0xc40c,0x3fe1, 0xb8a6,0x07d6 + .short 0x3492,0xc0e0, 0xc3a1,0x3fe7, 0xb956,0x070e + .short 0x35eb,0xc0b1, 0xc338,0x3fec, 0xba09,0x0646 + .short 0x373f,0xc088, 0xc2cf,0x3ff1, 0xbabf,0x057e + .short 0x388e,0xc064, 0xc266,0x3ff5, 0xbb77,0x04b5 + .short 0x39d9,0xc045, 0xc1fe,0x3ff8, 0xbc32,0x03ed + .short 0x3b1e,0xc02c, 0xc197,0x3ffb, 0xbcf0,0x0324 + .short 0x3c5f,0xc019, 0xc130,0x3ffd, 0xbdb0,0x025b + .short 0x3d9a,0xc00b, 0xc0ca,0x3fff, 0xbe73,0x0192 + .short 0x3ed0,0xc003, 0xc065,0x4000, 0xbf38,0x00c9 + + +.end +/******************* (C) COPYRIGHT 2009 STMicroelectronics *****END OF FILE****/ diff --git a/STM32F1/libraries/stm_fft/cr4_fft_16_stm33.asm b/STM32F1/libraries/stm_fft/cr4_fft_16_stm33.asm new file mode 100644 index 0000000..1d60179 --- /dev/null +++ b/STM32F1/libraries/stm_fft/cr4_fft_16_stm33.asm @@ -0,0 +1,250 @@ +/*;******************** (C) COPYRIGHT 2009 STMicroelectronics ******************** +;* File Name : cr4_fft_64_stm32.s +;* Author : MCD Application Team +;* Version : V2.0.0 +;* Date : 04/27/2009 +;* Description : Optimized 64-point radix-4 complex FFT for Cortex-M3 +;******************************************************************************** +;* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS +;* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. +;* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, +;* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE +;* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING +;* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. +;*******************************************************************************/ + +.cpu cortex-m3 +.fpu softvfp +.syntax unified +.thumb +.text + +.global cr4_fft_16_stm32 +.extern TableFFT + +.equ NPT, 16 + + +/*;******************************************************************************* +;* Function Name : cr4_fft_16_stm32 +;* Description : complex radix-4 16 points FFT +;* Input : - R0 = pssOUT: Output array . +;* - R1 = pssIN: Input array +;* - R2 = Nbin: = 16 number of points, this optimized FFT function +;* can only convert 16 points. +;* Output : None +;* Return : None +;********************************************************************************/ +.thumb_func +cr4_fft_16_stm32: + + STMFD SP!, {R4-R11, LR} + + MOV r12, #0 + MOV r3, r0 + MOV r0,#0 + +preloop_v7: + ADD r14, r1, r12, LSR#28 + + LDRSH r5, [r14, #2] + LDRSH r4, [r14],#NPT + LDRSH r9, [r14, #2] + LDRSH r8, [r14],#NPT + LDRSH r7, [r14, #2] + LDRSH r6, [r14],#NPT + LDRSH r11, [r14, #2] + LDRSH r10, [r14],#NPT + + ADD r8, r8, r10 + ADD r9, r9, r11 + SUB r10, r8, r10, LSL#1 + SUB r11, r9, r11, LSL#1 + + MOV r4, r4, ASR#2 + MOV r5, r5, ASR#2 + ADD r4, r4, r6, ASR#2 + ADD r5, r5, r7, ASR#2 + SUB r6, r4, r6, ASR#1 + SUB r7, r5, r7, ASR#1 + + ADD r4, r4, r8, ASR#2 + ADD r5, r5, r9, ASR#2 + SUB r8, r4, r8, ASR#1 + SUB r9, r5, r9, ASR#1 + + ADD r6, r6, r11, ASR#2 + SUB r7, r7, r10, ASR#2 + SUB r11, r6, r11, ASR#1 + ADD r10, r7, r10, ASR#1 + + STRH r5, [r3, #2] + STRH r4, [r3], #4 + STRH r7, [r3, #2] + STRH r6, [r3], #4 + STRH r9, [r3, #2] + STRH r8, [r3], #4 + STRH r10, [r3, #2] + STRH r11, [r3], #4 + + ADD r0, r0, #1 + + RBIT r12, r0 + + CMP r0,#4 + BNE preloop_v7 + + SUB r1, r3, r2, LSL#2 + MOV r0, #16 + MOVS r2, r2, LSR#4 + +/*;------------------------------------------------------------------------------ +; The FFT coefficients table can be stored into Flash or RAM. +; The following two lines of code allow selecting the method for coefficients +; storage. +; In the case of choosing coefficients in RAM, you have to: +; 1. Include the file table_fft.h, which is a part of the DSP library, +; in your main file. +; 2. Decomment the line LDR.W pssK, =TableFFT and comment the line +; ADRL pssK, TableFFT_V7 +; 3. Comment all the TableFFT_V7 data. +;------------------------------------------------------------------------------*/ + ADR r3, TableFFT_V7 + /*LDR.W r3, =TableFFT*/ + + +passloop_v7: + STMFD SP!, {r1,r2} + ADD r12, r0, r0, LSL#1 + ADD r1, r1, r12 + SUB r2, r2, #1<<16 + +grouploop_v7: + ADD r2,r2,r0,LSL#(16-2) + +butterloop_v7: + + LDRSH r5, [r1, #2] + LDRSH r4, [r1] + SUB r1, r1, r0 + + LDRSH r11, [r3, #2] + LDRSH r10, [r3] + ADD r3, r3, #4 + + SUB r14, r5, r4 + MUL r12, r14, r11 + ADD r14, r10, r11, LSL#1 + MLA r11, r5, r10, r12 + MLA r10, r4, r14, r12 + + LDRSH r5, [r1, #2] + LDRSH r4, [r1] + SUB r1, r1, r0 + + LDRSH r9, [r3, #2] + LDRSH r8, [r3] + ADD r3, r3, #4 + + SUB r14, r5, r4 + MUL r12, r14, r9 + ADD r14, r8, r9, LSL#1 + MLA r9, r5, r8, r12 + MLA r8, r4, r14, r12 + + LDRSH r5, [r1, #2] + LDRSH r4, [r1] + SUB r1, r1, r0 + + LDRSH r7, [r3, #2] + LDRSH r6, [r3] + ADD r3, r3, #4 + + SUB r14, r5, r4 + MUL r12, r14, r7 + ADD r14, r6, r7, LSL#1 + MLA r7, r5, r6, r12 + MLA r6, r4, r14, r12 + + LDRSH r5, [r1, #2] + LDRSH r4, [r1] + + ADD r8, r8, r10 + ADD r9, r9, r11 + SUB r10, r8, r10, LSL#1 + SUB r11, r9, r11, LSL#1 + + MOV r4, r4, ASR#2 + MOV r5, r5, ASR#2 + ADD r4, r4, r6, ASR#(2+14) + ADD r5, r5, r7, ASR#(2+14) + SUB r6, r4, r6, ASR#(1+14) + SUB r7, r5, r7, ASR#(1+14) + + ADD r4, r4, r8, ASR#(2+14) + ADD r5, r5, r9, ASR#(2+14) + SUB r8, r4, r8, ASR#(1+14) + SUB r9, r5, r9, ASR#(1+14) + + ADD r6, r6, r11, ASR#(2+14) + SUB r7, r7, r10, ASR#(2+14) + SUB r11, r6, r11, ASR#(1+14) + ADD r10, r7, r10, ASR#(1+14) + + STRH r5, [r1, #2] + STRH r4, [r1] + ADD r1, r1, r0 + STRH r7, [r1, #2] + STRH r6, [r1] + ADD r1, r1, r0 + STRH r9, [r1, #2] + STRH r8, [r1] + ADD r1, r1, r0 + STRH r10, [r1, #2] + STRH r11, [r1], #4 + SUBS r2,r2, #1<<16 + BGE butterloop_v7 + ADD r12, r0, r0, LSL#1 + ADD r1, r1, r12 + + SUB r2, r2, #1 + MOVS r14, r2, LSL#16 + IT ne + SUBNE r3, r3, r12 + BNE grouploop_v7 + + LDMFD sp!, {r1, r2} + MOV r0,r0,LSL#2 + MOVS r2, r2, LSR#2 + BNE passloop_v7 + LDMFD SP!, {R4-R11, PC} + + +TableFFT_V7: + /*N=16*/ + .short 0x4000,0x0000, 0x4000,0x0000, 0x4000,0x0000 + .short 0xdd5d,0x3b21, 0x22a3,0x187e, 0x0000,0x2d41 + .short 0xa57e,0x2d41, 0x0000,0x2d41, 0xc000,0x4000 + .short 0xdd5d,0xe782, 0xdd5d,0x3b21, 0xa57e,0x2d41 + /*N=64*/ + /* + .short 0x4000,0x0000, 0x4000,0x0000, 0x4000,0x0000 + .short 0x2aaa,0x1294, 0x396b,0x0646, 0x3249,0x0c7c + .short 0x11a8,0x238e, 0x3249,0x0c7c, 0x22a3,0x187e + .short 0xf721,0x3179, 0x2aaa,0x1294, 0x11a8,0x238e + .short 0xdd5d,0x3b21, 0x22a3,0x187e, 0x0000,0x2d41 + .short 0xc695,0x3fb1, 0x1a46,0x1e2b, 0xee58,0x3537 + .short 0xb4be,0x3ec5, 0x11a8,0x238e, 0xdd5d,0x3b21 + .short 0xa963,0x3871, 0x08df,0x289a, 0xcdb7,0x3ec5 + .short 0xa57e,0x2d41, 0x0000,0x2d41, 0xc000,0x4000 + .short 0xa963,0x1e2b, 0xf721,0x3179, 0xb4be,0x3ec5 + .short 0xb4be,0x0c7c, 0xee58,0x3537, 0xac61,0x3b21 + .short 0xc695,0xf9ba, 0xe5ba,0x3871, 0xa73b,0x3537 + .short 0xdd5d,0xe782, 0xdd5d,0x3b21, 0xa57e,0x2d41 + .short 0xf721,0xd766, 0xd556,0x3d3f, 0xa73b,0x238e + .short 0x11a8,0xcac9, 0xcdb7,0x3ec5, 0xac61,0x187e + .short 0x2aaa,0xc2c1, 0xc695,0x3fb1, 0xb4be,0x0c7c + */ + +.end +/******************* (C) COPYRIGHT 2009 STMicroelectronics *****END OF FILE****/ diff --git a/STM32F1/libraries/stm_fft/cr4_fft_256_stm32.asm b/STM32F1/libraries/stm_fft/cr4_fft_256_stm32.asm new file mode 100644 index 0000000..15e4b0c --- /dev/null +++ b/STM32F1/libraries/stm_fft/cr4_fft_256_stm32.asm @@ -0,0 +1,318 @@ +/*;******************** (C) COPYRIGHT 2009 STMicroelectronics ******************** +;* File Name : cr4_fft_256_stm32.s +;* Author : MCD Application Team +;* Version : V2.0.0 +;* Date : 04/27/2009 +;* Description : Optimized 256-point radix-4 complex FFT for Cortex-M3 +;******************************************************************************** +;* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS +;* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. +;* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, +;* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE +;* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING +;* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. +;*******************************************************************************/ + +.cpu cortex-m3 +.fpu softvfp +.syntax unified +.thumb +.text + +.global cr4_fft_256_stm32 +.extern TableFFT + +.equ NPT, 256 + + +/*;******************************************************************************* +;* Function Name : cr4_fft_256_stm32 +;* Description : complex radix-4 256 points FFT +;* Input : - R0 = pssOUT: Output array . +;* - R1 = pssIN: Input array +;* - R2 = Nbin: =256 number of points, this optimized FFT function +;* can only convert 256 points. +;* Output : None +;* Return : None +;********************************************************************************/ +.thumb_func +cr4_fft_256_stm32: + + STMFD SP!, {R4-R11, LR} + + MOV r12, #0 + MOV r3, r0 + MOV r0,#0 + +preloop_v7: + ADD r14, r1, r12, LSR#24 /*256pts*/ + + LDRSH r5, [r14, #2] + LDRSH r4, [r14] + ADD r14, #NPT + LDRSH r9, [r14, #2] + LDRSH r8, [r14] + ADD r14, #NPT + LDRSH r7, [r14, #2] + LDRSH r6, [r14] + ADD r14, #NPT + LDRSH r11, [r14, #2] + LDRSH r10, [r14] + ADD r14, #NPT + + ADD r8, r8, r10 + ADD r9, r9, r11 + SUB r10, r8, r10, LSL#1 + SUB r11, r9, r11, LSL#1 + + MOV r4, r4, ASR#2 + MOV r5, r5, ASR#2 + ADD r4, r4, r6, ASR#2 + ADD r5, r5, r7, ASR#2 + SUB r6, r4, r6, ASR#1 + SUB r7, r5, r7, ASR#1 + + ADD r4, r4, r8, ASR#2 + ADD r5, r5, r9, ASR#2 + SUB r8, r4, r8, ASR#1 + SUB r9, r5, r9, ASR#1 + + ADD r6, r6, r11, ASR#2 + SUB r7, r7, r10, ASR#2 + SUB r11, r6, r11, ASR#1 + ADD r10, r7, r10, ASR#1 + + STRH r5, [r3, #2] + STRH r4, [r3], #4 + STRH r7, [r3, #2] + STRH r6, [r3], #4 + STRH r9, [r3, #2] + STRH r8, [r3], #4 + STRH r10, [r3, #2] + STRH r11, [r3], #4 + + ADD r0, r0, #1 + + RBIT r12, r0 + + CMP r0,#64 /*256pts*/ + BNE preloop_v7 + + SUB r1, r3, r2, LSL#2 + MOV r0, #16 + MOVS r2, r2, LSR#4 + +/*;------------------------------------------------------------------------------ +; The FFT coefficients table can be stored into Flash or RAM. +; The following two lines of code allow selecting the method for coefficients +; storage. +; In the case of choosing coefficients in RAM, you have to: +; 1. Include the file table_fft.h, which is a part of the DSP library, +; in your main file. +; 2. Decomment the line LDR.W pssK, =TableFFT and comment the line +; ADRL pssK, TableFFT_V7 +; 3. Comment all the TableFFT_V7 data. +;------------------------------------------------------------------------------*/ + ADR r3, TableFFT_V7 + /*LDR.W r3, =TableFFT*/ + + +passloop_v7: + STMFD SP!, {r1,r2} + ADD r12, r0, r0, LSL#1 + ADD r1, r1, r12 + SUB r2, r2, #1<<16 + +grouploop_v7: + ADD r2,r2,r0,LSL#(16-2) + +butterloop_v7: + + LDRSH r5, [r1, #2] + LDRSH r4, [r1] + SUB r1, r1, r0 + + LDRSH r11, [r3, #2] + LDRSH r10, [r3] + ADD r3, r3, #4 + + SUB r14, r5, r4 + MUL r12, r14, r11 + ADD r14, r10, r11, LSL#1 + MLA r11, r5, r10, r12 + MLA r10, r4, r14, r12 + + LDRSH r5, [r1, #2] + LDRSH r4, [r1] + SUB r1, r1, r0 + + LDRSH r9, [r3, #2] + LDRSH r8, [r3] + ADD r3, r3, #4 + + SUB r14, r5, r4 + MUL r12, r14, r9 + ADD r14, r8, r9, LSL#1 + MLA r9, r5, r8, r12 + MLA r8, r4, r14, r12 + + LDRSH r5, [r1, #2] + LDRSH r4, [r1] + SUB r1, r1, r0 + + LDRSH r7, [r3, #2] + LDRSH r6, [r3] + ADD r3, r3, #4 + + SUB r14, r5, r4 + MUL r12, r14, r7 + ADD r14, r6, r7, LSL#1 + MLA r7, r5, r6, r12 + MLA r6, r4, r14, r12 + + LDRSH r5, [r1, #2] + LDRSH r4, [r1] + + ADD r8, r8, r10 + ADD r9, r9, r11 + SUB r10, r8, r10, LSL#1 + SUB r11, r9, r11, LSL#1 + + MOV r4, r4, ASR#2 + MOV r5, r5, ASR#2 + ADD r4, r4, r6, ASR#(2+14) + ADD r5, r5, r7, ASR#(2+14) + SUB r6, r4, r6, ASR#(1+14) + SUB r7, r5, r7, ASR#(1+14) + + ADD r4, r4, r8, ASR#(2+14) + ADD r5, r5, r9, ASR#(2+14) + SUB r8, r4, r8, ASR#(1+14) + SUB r9, r5, r9, ASR#(1+14) + + ADD r6, r6, r11, ASR#(2+14) + SUB r7, r7, r10, ASR#(2+14) + SUB r11, r6, r11, ASR#(1+14) + ADD r10, r7, r10, ASR#(1+14) + + STRH r5, [r1, #2] + STRH r4, [r1] + ADD r1, r1, r0 + STRH r7, [r1, #2] + STRH r6, [r1] + ADD r1, r1, r0 + STRH r9, [r1, #2] + STRH r8, [r1] + ADD r1, r1, r0 + STRH r10, [r1, #2] + STRH r11, [r1], #4 + SUBS r2,r2, #1<<16 + BGE butterloop_v7 + ADD r12, r0, r0, LSL#1 + ADD r1, r1, r12 + + SUB r2, r2, #1 + MOVS r14, r2, LSL#16 + IT ne + SUBNE r3, r3, r12 + BNE grouploop_v7 + + LDMFD sp!, {r1, r2} + MOV r0,r0,LSL#2 + MOVS r2, r2, LSR#2 + BNE passloop_v7 + LDMFD SP!, {R4-R11, PC} + + +TableFFT_V7: + /*N=16*/ + .short 0x4000,0x0000, 0x4000,0x0000, 0x4000,0x0000 + .short 0xdd5d,0x3b21, 0x22a3,0x187e, 0x0000,0x2d41 + .short 0xa57e,0x2d41, 0x0000,0x2d41, 0xc000,0x4000 + .short 0xdd5d,0xe782, 0xdd5d,0x3b21, 0xa57e,0x2d41 + /*N=64*/ + .short 0x4000,0x0000, 0x4000,0x0000, 0x4000,0x0000 + .short 0x2aaa,0x1294, 0x396b,0x0646, 0x3249,0x0c7c + .short 0x11a8,0x238e, 0x3249,0x0c7c, 0x22a3,0x187e + .short 0xf721,0x3179, 0x2aaa,0x1294, 0x11a8,0x238e + .short 0xdd5d,0x3b21, 0x22a3,0x187e, 0x0000,0x2d41 + .short 0xc695,0x3fb1, 0x1a46,0x1e2b, 0xee58,0x3537 + .short 0xb4be,0x3ec5, 0x11a8,0x238e, 0xdd5d,0x3b21 + .short 0xa963,0x3871, 0x08df,0x289a, 0xcdb7,0x3ec5 + .short 0xa57e,0x2d41, 0x0000,0x2d41, 0xc000,0x4000 + .short 0xa963,0x1e2b, 0xf721,0x3179, 0xb4be,0x3ec5 + .short 0xb4be,0x0c7c, 0xee58,0x3537, 0xac61,0x3b21 + .short 0xc695,0xf9ba, 0xe5ba,0x3871, 0xa73b,0x3537 + .short 0xdd5d,0xe782, 0xdd5d,0x3b21, 0xa57e,0x2d41 + .short 0xf721,0xd766, 0xd556,0x3d3f, 0xa73b,0x238e + .short 0x11a8,0xcac9, 0xcdb7,0x3ec5, 0xac61,0x187e + .short 0x2aaa,0xc2c1, 0xc695,0x3fb1, 0xb4be,0x0c7c + /*N=256*/ + .short 0x4000,0x0000, 0x4000,0x0000, 0x4000,0x0000 + .short 0x3b1e,0x04b5, 0x3e69,0x0192, 0x3cc8,0x0324 + .short 0x35eb,0x0964, 0x3cc8,0x0324, 0x396b,0x0646 + .short 0x306c,0x0e06, 0x3b1e,0x04b5, 0x35eb,0x0964 + .short 0x2aaa,0x1294, 0x396b,0x0646, 0x3249,0x0c7c + .short 0x24ae,0x1709, 0x37af,0x07d6, 0x2e88,0x0f8d + .short 0x1e7e,0x1b5d, 0x35eb,0x0964, 0x2aaa,0x1294 + .short 0x1824,0x1f8c, 0x341e,0x0af1, 0x26b3,0x1590 + .short 0x11a8,0x238e, 0x3249,0x0c7c, 0x22a3,0x187e + .short 0x0b14,0x2760, 0x306c,0x0e06, 0x1e7e,0x1b5d + .short 0x0471,0x2afb, 0x2e88,0x0f8d, 0x1a46,0x1e2b + .short 0xfdc7,0x2e5a, 0x2c9d,0x1112, 0x15fe,0x20e7 + .short 0xf721,0x3179, 0x2aaa,0x1294, 0x11a8,0x238e + .short 0xf087,0x3453, 0x28b2,0x1413, 0x0d48,0x2620 + .short 0xea02,0x36e5, 0x26b3,0x1590, 0x08df,0x289a + .short 0xe39c,0x392b, 0x24ae,0x1709, 0x0471,0x2afb + .short 0xdd5d,0x3b21, 0x22a3,0x187e, 0x0000,0x2d41 + .short 0xd74e,0x3cc5, 0x2093,0x19ef, 0xfb8f,0x2f6c + .short 0xd178,0x3e15, 0x1e7e,0x1b5d, 0xf721,0x3179 + .short 0xcbe2,0x3f0f, 0x1c64,0x1cc6, 0xf2b8,0x3368 + .short 0xc695,0x3fb1, 0x1a46,0x1e2b, 0xee58,0x3537 + .short 0xc197,0x3ffb, 0x1824,0x1f8c, 0xea02,0x36e5 + .short 0xbcf0,0x3fec, 0x15fe,0x20e7, 0xe5ba,0x3871 + .short 0xb8a6,0x3f85, 0x13d5,0x223d, 0xe182,0x39db + .short 0xb4be,0x3ec5, 0x11a8,0x238e, 0xdd5d,0x3b21 + .short 0xb140,0x3daf, 0x0f79,0x24da, 0xd94d,0x3c42 + .short 0xae2e,0x3c42, 0x0d48,0x2620, 0xd556,0x3d3f + .short 0xab8e,0x3a82, 0x0b14,0x2760, 0xd178,0x3e15 + .short 0xa963,0x3871, 0x08df,0x289a, 0xcdb7,0x3ec5 + .short 0xa7b1,0x3612, 0x06a9,0x29ce, 0xca15,0x3f4f + .short 0xa678,0x3368, 0x0471,0x2afb, 0xc695,0x3fb1 + .short 0xa5bc,0x3076, 0x0239,0x2c21, 0xc338,0x3fec + .short 0xa57e,0x2d41, 0x0000,0x2d41, 0xc000,0x4000 + .short 0xa5bc,0x29ce, 0xfdc7,0x2e5a, 0xbcf0,0x3fec + .short 0xa678,0x2620, 0xfb8f,0x2f6c, 0xba09,0x3fb1 + .short 0xa7b1,0x223d, 0xf957,0x3076, 0xb74d,0x3f4f + .short 0xa963,0x1e2b, 0xf721,0x3179, 0xb4be,0x3ec5 + .short 0xab8e,0x19ef, 0xf4ec,0x3274, 0xb25e,0x3e15 + .short 0xae2e,0x1590, 0xf2b8,0x3368, 0xb02d,0x3d3f + .short 0xb140,0x1112, 0xf087,0x3453, 0xae2e,0x3c42 + .short 0xb4be,0x0c7c, 0xee58,0x3537, 0xac61,0x3b21 + .short 0xb8a6,0x07d6, 0xec2b,0x3612, 0xaac8,0x39db + .short 0xbcf0,0x0324, 0xea02,0x36e5, 0xa963,0x3871 + .short 0xc197,0xfe6e, 0xe7dc,0x37b0, 0xa834,0x36e5 + .short 0xc695,0xf9ba, 0xe5ba,0x3871, 0xa73b,0x3537 + .short 0xcbe2,0xf50f, 0xe39c,0x392b, 0xa678,0x3368 + .short 0xd178,0xf073, 0xe182,0x39db, 0xa5ed,0x3179 + .short 0xd74e,0xebed, 0xdf6d,0x3a82, 0xa599,0x2f6c + .short 0xdd5d,0xe782, 0xdd5d,0x3b21, 0xa57e,0x2d41 + .short 0xe39c,0xe33a, 0xdb52,0x3bb6, 0xa599,0x2afb + .short 0xea02,0xdf19, 0xd94d,0x3c42, 0xa5ed,0x289a + .short 0xf087,0xdb26, 0xd74e,0x3cc5, 0xa678,0x2620 + .short 0xf721,0xd766, 0xd556,0x3d3f, 0xa73b,0x238e + .short 0xfdc7,0xd3df, 0xd363,0x3daf, 0xa834,0x20e7 + .short 0x0471,0xd094, 0xd178,0x3e15, 0xa963,0x1e2b + .short 0x0b14,0xcd8c, 0xcf94,0x3e72, 0xaac8,0x1b5d + .short 0x11a8,0xcac9, 0xcdb7,0x3ec5, 0xac61,0x187e + .short 0x1824,0xc850, 0xcbe2,0x3f0f, 0xae2e,0x1590 + .short 0x1e7e,0xc625, 0xca15,0x3f4f, 0xb02d,0x1294 + .short 0x24ae,0xc44a, 0xc851,0x3f85, 0xb25e,0x0f8d + .short 0x2aaa,0xc2c1, 0xc695,0x3fb1, 0xb4be,0x0c7c + .short 0x306c,0xc18e, 0xc4e2,0x3fd4, 0xb74d,0x0964 + .short 0x35eb,0xc0b1, 0xc338,0x3fec, 0xba09,0x0646 + .short 0x3b1e,0xc02c, 0xc197,0x3ffb, 0xbcf0,0x0324 + + +.end +/******************* (C) COPYRIGHT 2009 STMicroelectronics *****END OF FILE****/ diff --git a/STM32F1/libraries/stm_fft/cr4_fft_64_stm32.asm b/STM32F1/libraries/stm_fft/cr4_fft_64_stm32.asm new file mode 100644 index 0000000..bff4548 --- /dev/null +++ b/STM32F1/libraries/stm_fft/cr4_fft_64_stm32.asm @@ -0,0 +1,249 @@ +/*;******************** (C) COPYRIGHT 2009 STMicroelectronics ******************** +;* File Name : cr4_fft_64_stm32.s +;* Author : MCD Application Team +;* Version : V2.0.0 +;* Date : 04/27/2009 +;* Description : Optimized 64-point radix-4 complex FFT for Cortex-M3 +;******************************************************************************** +;* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS +;* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. +;* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, +;* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE +;* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING +;* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. +;*******************************************************************************/ + +.cpu cortex-m3 +.fpu softvfp +.syntax unified +.thumb +.text + +.global cr4_fft_64_stm32 +.extern TableFFT + +.equ NPT, 64 + + +/*;******************************************************************************* +;* Function Name : cr4_fft_64_stm32 +;* Description : complex radix-4 64 points FFT +;* Input : - R0 = pssOUT: Output array . +;* - R1 = pssIN: Input array +;* - R2 = Nbin: =64 number of points, this optimized FFT function +;* can only convert 64 points. +;* Output : None +;* Return : None +;********************************************************************************/ +.thumb_func +cr4_fft_64_stm32: + + STMFD SP!, {R4-R11, LR} + + MOV r12, #0 + MOV r3, r0 + MOV r0,#0 + +preloop_v7: + ADD r14, r1, r12, LSR#26 + + LDRSH r5, [r14, #2] + LDRSH r4, [r14],#NPT + LDRSH r9, [r14, #2] + LDRSH r8, [r14],#NPT + LDRSH r7, [r14, #2] + LDRSH r6, [r14],#NPT + LDRSH r11, [r14, #2] + LDRSH r10, [r14],#NPT + + ADD r8, r8, r10 + ADD r9, r9, r11 + SUB r10, r8, r10, LSL#1 + SUB r11, r9, r11, LSL#1 + + MOV r4, r4, ASR#2 + MOV r5, r5, ASR#2 + ADD r4, r4, r6, ASR#2 + ADD r5, r5, r7, ASR#2 + SUB r6, r4, r6, ASR#1 + SUB r7, r5, r7, ASR#1 + + ADD r4, r4, r8, ASR#2 + ADD r5, r5, r9, ASR#2 + SUB r8, r4, r8, ASR#1 + SUB r9, r5, r9, ASR#1 + + ADD r6, r6, r11, ASR#2 + SUB r7, r7, r10, ASR#2 + SUB r11, r6, r11, ASR#1 + ADD r10, r7, r10, ASR#1 + + STRH r5, [r3, #2] + STRH r4, [r3], #4 + STRH r7, [r3, #2] + STRH r6, [r3], #4 + STRH r9, [r3, #2] + STRH r8, [r3], #4 + STRH r10, [r3, #2] + STRH r11, [r3], #4 + + ADD r0, r0, #1 + + RBIT r12, r0 + + CMP r0,#16 + BNE preloop_v7 + + SUB r1, r3, r2, LSL#2 + MOV r0, #16 + MOVS r2, r2, LSR#4 + +/*;------------------------------------------------------------------------------ +; The FFT coefficients table can be stored into Flash or RAM. +; The following two lines of code allow selecting the method for coefficients +; storage. +; In the case of choosing coefficients in RAM, you have to: +; 1. Include the file table_fft.h, which is a part of the DSP library, +; in your main file. +; 2. Decomment the line LDR.W pssK, =TableFFT and comment the line +; ADRL pssK, TableFFT_V7 +; 3. Comment all the TableFFT_V7 data. +;------------------------------------------------------------------------------*/ + ADR r3, TableFFT_V7 + /*LDR.W r3, =TableFFT*/ + + +passloop_v7: + STMFD SP!, {r1,r2} + ADD r12, r0, r0, LSL#1 + ADD r1, r1, r12 + SUB r2, r2, #1<<16 + +grouploop_v7: + ADD r2,r2,r0,LSL#(16-2) + +butterloop_v7: + + LDRSH r5, [r1, #2] + LDRSH r4, [r1] + SUB r1, r1, r0 + + LDRSH r11, [r3, #2] + LDRSH r10, [r3] + ADD r3, r3, #4 + + SUB r14, r5, r4 + MUL r12, r14, r11 + ADD r14, r10, r11, LSL#1 + MLA r11, r5, r10, r12 + MLA r10, r4, r14, r12 + + LDRSH r5, [r1, #2] + LDRSH r4, [r1] + SUB r1, r1, r0 + + LDRSH r9, [r3, #2] + LDRSH r8, [r3] + ADD r3, r3, #4 + + SUB r14, r5, r4 + MUL r12, r14, r9 + ADD r14, r8, r9, LSL#1 + MLA r9, r5, r8, r12 + MLA r8, r4, r14, r12 + + LDRSH r5, [r1, #2] + LDRSH r4, [r1] + SUB r1, r1, r0 + + LDRSH r7, [r3, #2] + LDRSH r6, [r3] + ADD r3, r3, #4 + + SUB r14, r5, r4 + MUL r12, r14, r7 + ADD r14, r6, r7, LSL#1 + MLA r7, r5, r6, r12 + MLA r6, r4, r14, r12 + + LDRSH r5, [r1, #2] + LDRSH r4, [r1] + + ADD r8, r8, r10 + ADD r9, r9, r11 + SUB r10, r8, r10, LSL#1 + SUB r11, r9, r11, LSL#1 + + MOV r4, r4, ASR#2 + MOV r5, r5, ASR#2 + ADD r4, r4, r6, ASR#(2+14) + ADD r5, r5, r7, ASR#(2+14) + SUB r6, r4, r6, ASR#(1+14) + SUB r7, r5, r7, ASR#(1+14) + + ADD r4, r4, r8, ASR#(2+14) + ADD r5, r5, r9, ASR#(2+14) + SUB r8, r4, r8, ASR#(1+14) + SUB r9, r5, r9, ASR#(1+14) + + ADD r6, r6, r11, ASR#(2+14) + SUB r7, r7, r10, ASR#(2+14) + SUB r11, r6, r11, ASR#(1+14) + ADD r10, r7, r10, ASR#(1+14) + + STRH r5, [r1, #2] + STRH r4, [r1] + ADD r1, r1, r0 + STRH r7, [r1, #2] + STRH r6, [r1] + ADD r1, r1, r0 + STRH r9, [r1, #2] + STRH r8, [r1] + ADD r1, r1, r0 + STRH r10, [r1, #2] + STRH r11, [r1], #4 + SUBS r2,r2, #1<<16 + BGE butterloop_v7 + ADD r12, r0, r0, LSL#1 + ADD r1, r1, r12 + + SUB r2, r2, #1 + MOVS r14, r2, LSL#16 + IT ne + SUBNE r3, r3, r12 + BNE grouploop_v7 + + LDMFD sp!, {r1, r2} + MOV r0,r0,LSL#2 + MOVS r2, r2, LSR#2 + BNE passloop_v7 + LDMFD SP!, {R4-R11, PC} + + +TableFFT_V7: + + .short 0x4000,0x0000, 0x4000,0x0000, 0x4000,0x0000 + .short 0xdd5d,0x3b21, 0x22a3,0x187e, 0x0000,0x2d41 + .short 0xa57e,0x2d41, 0x0000,0x2d41, 0xc000,0x4000 + .short 0xdd5d,0xe782, 0xdd5d,0x3b21, 0xa57e,0x2d41 + + .short 0x4000,0x0000, 0x4000,0x0000, 0x4000,0x0000 + .short 0x2aaa,0x1294, 0x396b,0x0646, 0x3249,0x0c7c + .short 0x11a8,0x238e, 0x3249,0x0c7c, 0x22a3,0x187e + .short 0xf721,0x3179, 0x2aaa,0x1294, 0x11a8,0x238e + .short 0xdd5d,0x3b21, 0x22a3,0x187e, 0x0000,0x2d41 + .short 0xc695,0x3fb1, 0x1a46,0x1e2b, 0xee58,0x3537 + .short 0xb4be,0x3ec5, 0x11a8,0x238e, 0xdd5d,0x3b21 + .short 0xa963,0x3871, 0x08df,0x289a, 0xcdb7,0x3ec5 + .short 0xa57e,0x2d41, 0x0000,0x2d41, 0xc000,0x4000 + .short 0xa963,0x1e2b, 0xf721,0x3179, 0xb4be,0x3ec5 + .short 0xb4be,0x0c7c, 0xee58,0x3537, 0xac61,0x3b21 + .short 0xc695,0xf9ba, 0xe5ba,0x3871, 0xa73b,0x3537 + .short 0xdd5d,0xe782, 0xdd5d,0x3b21, 0xa57e,0x2d41 + .short 0xf721,0xd766, 0xd556,0x3d3f, 0xa73b,0x238e + .short 0x11a8,0xcac9, 0xcdb7,0x3ec5, 0xac61,0x187e + .short 0x2aaa,0xc2c1, 0xc695,0x3fb1, 0xb4be,0x0c7c + + +.end +/******************* (C) COPYRIGHT 2009 STMicroelectronics *****END OF FILE****/ diff --git a/STM32F1/libraries/stm_fft/cr4_fft_stm32.h b/STM32F1/libraries/stm_fft/cr4_fft_stm32.h new file mode 100644 index 0000000..a899430 --- /dev/null +++ b/STM32F1/libraries/stm_fft/cr4_fft_stm32.h @@ -0,0 +1,39 @@ +/* + +x[N] be the time signal samples. To use the FFT functions of the DSP library, the +following conditions must be satisfied: +? All the signal samples must be 32-bit data containing the 16-bit real part followed by the +16-bit imaginary part (in the little Endian order: imaginary_real). + + +*/ + +#ifndef __STM32F10x_DSP_H +#define __STM32F10x_DSP_H +/* + * The assembly files can be modified to use a table in RAM rather than ROM. + * Check the assembly files comments. + * + * #include "table_fft.h" + */ + + +extern "C" { + +/* Radix-4 complex FFT for STM32, in assembly */ +/* 16 points*/ +void cr4_fft_16_stm32(void *pssOUT, void *pssIN, uint16_t Nbin); + +/* 64 points*/ +void cr4_fft_64_stm32(void *pssOUT, void *pssIN, uint16_t Nbin); + +/* 256 points */ +void cr4_fft_256_stm32(void *pssOUT, void *pssIN, uint16_t Nbin); + +/* 1024 points */ +void cr4_fft_1024_stm32(void *pssOUT, void *pssIN, uint16_t Nbin); + + +} + +#endif /* __STM32F10x_DSP_H */ diff --git a/STM32F1/libraries/stm_fft/table_fft.h b/STM32F1/libraries/stm_fft/table_fft.h new file mode 100644 index 0000000..27d3d39 --- /dev/null +++ b/STM32F1/libraries/stm_fft/table_fft.h @@ -0,0 +1,377 @@ +/** + ****************************************************************************** + * @file STM32F10x_DSP_Lib/inc/table_fft.h + * @author MCD Application Team + * @version V2.0.0 + * @date 04/27/2009 + * @brief Contains the coefficients required for FFT computation. + ****************************************************************************** + * @copy + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + *

© COPYRIGHT 2009 STMicroelectronics

+ */ + + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __TABLE_FFT_H +#define __TABLE_FFT_H + +/* Includes ------------------------------------------------------------------*/ + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +uint16_t TableFFT[]= {0x4000,0x0000, 0x4000,0x0000, 0x4000,0x0000, + 0xdd5d,0x3b21, 0x22a3,0x187e, 0x0000,0x2d41, + 0xa57e,0x2d41, 0x0000,0x2d41, 0xc000,0x4000, + 0xdd5d,0xe782, 0xdd5d,0x3b21, 0xa57e,0x2d41, + 0x4000,0x0000, 0x4000,0x0000, 0x4000,0x0000, /* N=64 */ + 0x2aaa,0x1294, 0x396b,0x0646, 0x3249,0x0c7c, + 0x11a8,0x238e, 0x3249,0x0c7c, 0x22a3,0x187e, + 0xf721,0x3179, 0x2aaa,0x1294, 0x11a8,0x238e, + 0xdd5d,0x3b21, 0x22a3,0x187e, 0x0000,0x2d41, + 0xc695,0x3fb1, 0x1a46,0x1e2b, 0xee58,0x3537, + 0xb4be,0x3ec5, 0x11a8,0x238e, 0xdd5d,0x3b21, + 0xa963,0x3871, 0x08df,0x289a, 0xcdb7,0x3ec5, + 0xa57e,0x2d41, 0x0000,0x2d41, 0xc000,0x4000, + 0xa963,0x1e2b, 0xf721,0x3179, 0xb4be,0x3ec5, + 0xb4be,0x0c7c, 0xee58,0x3537, 0xac61,0x3b21, + 0xc695,0xf9ba, 0xe5ba,0x3871, 0xa73b,0x3537, + 0xdd5d,0xe782, 0xdd5d,0x3b21, 0xa57e,0x2d41, + 0xf721,0xd766, 0xd556,0x3d3f, 0xa73b,0x238e, + 0x11a8,0xcac9, 0xcdb7,0x3ec5, 0xac61,0x187e, + 0x2aaa,0xc2c1, 0xc695,0x3fb1, 0xb4be,0x0c7c, + 0x4000,0x0000, 0x4000,0x0000, 0x4000,0x0000, /* N=256 */ + 0x3b1e,0x04b5, 0x3e69,0x0192, 0x3cc8,0x0324, + 0x35eb,0x0964, 0x3cc8,0x0324, 0x396b,0x0646, + 0x306c,0x0e06, 0x3b1e,0x04b5, 0x35eb,0x0964, + 0x2aaa,0x1294, 0x396b,0x0646, 0x3249,0x0c7c, + 0x24ae,0x1709, 0x37af,0x07d6, 0x2e88,0x0f8d, + 0x1e7e,0x1b5d, 0x35eb,0x0964, 0x2aaa,0x1294, + 0x1824,0x1f8c, 0x341e,0x0af1, 0x26b3,0x1590, + 0x11a8,0x238e, 0x3249,0x0c7c, 0x22a3,0x187e, + 0x0b14,0x2760, 0x306c,0x0e06, 0x1e7e,0x1b5d, + 0x0471,0x2afb, 0x2e88,0x0f8d, 0x1a46,0x1e2b, + 0xfdc7,0x2e5a, 0x2c9d,0x1112, 0x15fe,0x20e7, + 0xf721,0x3179, 0x2aaa,0x1294, 0x11a8,0x238e, + 0xf087,0x3453, 0x28b2,0x1413, 0x0d48,0x2620, + 0xea02,0x36e5, 0x26b3,0x1590, 0x08df,0x289a, + 0xe39c,0x392b, 0x24ae,0x1709, 0x0471,0x2afb, + 0xdd5d,0x3b21, 0x22a3,0x187e, 0x0000,0x2d41, + 0xd74e,0x3cc5, 0x2093,0x19ef, 0xfb8f,0x2f6c, + 0xd178,0x3e15, 0x1e7e,0x1b5d, 0xf721,0x3179, + 0xcbe2,0x3f0f, 0x1c64,0x1cc6, 0xf2b8,0x3368, + 0xc695,0x3fb1, 0x1a46,0x1e2b, 0xee58,0x3537, + 0xc197,0x3ffb, 0x1824,0x1f8c, 0xea02,0x36e5, + 0xbcf0,0x3fec, 0x15fe,0x20e7, 0xe5ba,0x3871, + 0xb8a6,0x3f85, 0x13d5,0x223d, 0xe182,0x39db, + 0xb4be,0x3ec5, 0x11a8,0x238e, 0xdd5d,0x3b21, + 0xb140,0x3daf, 0x0f79,0x24da, 0xd94d,0x3c42, + 0xae2e,0x3c42, 0x0d48,0x2620, 0xd556,0x3d3f, + 0xab8e,0x3a82, 0x0b14,0x2760, 0xd178,0x3e15, + 0xa963,0x3871, 0x08df,0x289a, 0xcdb7,0x3ec5, + 0xa7b1,0x3612, 0x06a9,0x29ce, 0xca15,0x3f4f, + 0xa678,0x3368, 0x0471,0x2afb, 0xc695,0x3fb1, + 0xa5bc,0x3076, 0x0239,0x2c21, 0xc338,0x3fec, + 0xa57e,0x2d41, 0x0000,0x2d41, 0xc000,0x4000, + 0xa5bc,0x29ce, 0xfdc7,0x2e5a, 0xbcf0,0x3fec, + 0xa678,0x2620, 0xfb8f,0x2f6c, 0xba09,0x3fb1, + 0xa7b1,0x223d, 0xf957,0x3076, 0xb74d,0x3f4f, + 0xa963,0x1e2b, 0xf721,0x3179, 0xb4be,0x3ec5, + 0xab8e,0x19ef, 0xf4ec,0x3274, 0xb25e,0x3e15, + 0xae2e,0x1590, 0xf2b8,0x3368, 0xb02d,0x3d3f, + 0xb140,0x1112, 0xf087,0x3453, 0xae2e,0x3c42, + 0xb4be,0x0c7c, 0xee58,0x3537, 0xac61,0x3b21, + 0xb8a6,0x07d6, 0xec2b,0x3612, 0xaac8,0x39db, + 0xbcf0,0x0324, 0xea02,0x36e5, 0xa963,0x3871, + 0xc197,0xfe6e, 0xe7dc,0x37b0, 0xa834,0x36e5, + 0xc695,0xf9ba, 0xe5ba,0x3871, 0xa73b,0x3537, + 0xcbe2,0xf50f, 0xe39c,0x392b, 0xa678,0x3368, + 0xd178,0xf073, 0xe182,0x39db, 0xa5ed,0x3179, + 0xd74e,0xebed, 0xdf6d,0x3a82, 0xa599,0x2f6c, + 0xdd5d,0xe782, 0xdd5d,0x3b21, 0xa57e,0x2d41, + 0xe39c,0xe33a, 0xdb52,0x3bb6, 0xa599,0x2afb, + 0xea02,0xdf19, 0xd94d,0x3c42, 0xa5ed,0x289a, + 0xf087,0xdb26, 0xd74e,0x3cc5, 0xa678,0x2620, + 0xf721,0xd766, 0xd556,0x3d3f, 0xa73b,0x238e, + 0xfdc7,0xd3df, 0xd363,0x3daf, 0xa834,0x20e7, + 0x0471,0xd094, 0xd178,0x3e15, 0xa963,0x1e2b, + 0x0b14,0xcd8c, 0xcf94,0x3e72, 0xaac8,0x1b5d, + 0x11a8,0xcac9, 0xcdb7,0x3ec5, 0xac61,0x187e, + 0x1824,0xc850, 0xcbe2,0x3f0f, 0xae2e,0x1590, + 0x1e7e,0xc625, 0xca15,0x3f4f, 0xb02d,0x1294, + 0x24ae,0xc44a, 0xc851,0x3f85, 0xb25e,0x0f8d, + 0x2aaa,0xc2c1, 0xc695,0x3fb1, 0xb4be,0x0c7c, + 0x306c,0xc18e, 0xc4e2,0x3fd4, 0xb74d,0x0964, + 0x35eb,0xc0b1, 0xc338,0x3fec, 0xba09,0x0646, + 0x3b1e,0xc02c, 0xc197,0x3ffb, 0xbcf0,0x0324, + 0x4000,0x0000, 0x4000,0x0000, 0x4000,0x0000, /* N=1024*/ + 0x3ed0,0x012e, 0x3f9b,0x0065, 0x3f36,0x00c9, + 0x3d9a,0x025b, 0x3f36,0x00c9, 0x3e69,0x0192, + 0x3c5f,0x0388, 0x3ed0,0x012e, 0x3d9a,0x025b, + 0x3b1e,0x04b5, 0x3e69,0x0192, 0x3cc8,0x0324, + 0x39d9,0x05e2, 0x3e02,0x01f7, 0x3bf4,0x03ed, + 0x388e,0x070e, 0x3d9a,0x025b, 0x3b1e,0x04b5, + 0x373f,0x0839, 0x3d31,0x02c0, 0x3a46,0x057e, + 0x35eb,0x0964, 0x3cc8,0x0324, 0x396b,0x0646, + 0x3492,0x0a8e, 0x3c5f,0x0388, 0x388e,0x070e, + 0x3334,0x0bb7, 0x3bf4,0x03ed, 0x37af,0x07d6, + 0x31d2,0x0cdf, 0x3b8a,0x0451, 0x36ce,0x089d, + 0x306c,0x0e06, 0x3b1e,0x04b5, 0x35eb,0x0964, + 0x2f02,0x0f2b, 0x3ab2,0x051a, 0x3505,0x0a2b, + 0x2d93,0x1050, 0x3a46,0x057e, 0x341e,0x0af1, + 0x2c21,0x1173, 0x39d9,0x05e2, 0x3334,0x0bb7, + 0x2aaa,0x1294, 0x396b,0x0646, 0x3249,0x0c7c, + 0x2931,0x13b4, 0x38fd,0x06aa, 0x315b,0x0d41, + 0x27b3,0x14d2, 0x388e,0x070e, 0x306c,0x0e06, + 0x2632,0x15ee, 0x381f,0x0772, 0x2f7b,0x0eca, + 0x24ae,0x1709, 0x37af,0x07d6, 0x2e88,0x0f8d, + 0x2326,0x1821, 0x373f,0x0839, 0x2d93,0x1050, + 0x219c,0x1937, 0x36ce,0x089d, 0x2c9d,0x1112, + 0x200e,0x1a4b, 0x365d,0x0901, 0x2ba4,0x11d3, + 0x1e7e,0x1b5d, 0x35eb,0x0964, 0x2aaa,0x1294, + 0x1ceb,0x1c6c, 0x3578,0x09c7, 0x29af,0x1354, + 0x1b56,0x1d79, 0x3505,0x0a2b, 0x28b2,0x1413, + 0x19be,0x1e84, 0x3492,0x0a8e, 0x27b3,0x14d2, + 0x1824,0x1f8c, 0x341e,0x0af1, 0x26b3,0x1590, + 0x1688,0x2091, 0x33a9,0x0b54, 0x25b1,0x164c, + 0x14ea,0x2193, 0x3334,0x0bb7, 0x24ae,0x1709, + 0x134a,0x2292, 0x32bf,0x0c1a, 0x23a9,0x17c4, + 0x11a8,0x238e, 0x3249,0x0c7c, 0x22a3,0x187e, + 0x1005,0x2488, 0x31d2,0x0cdf, 0x219c,0x1937, + 0x0e61,0x257e, 0x315b,0x0d41, 0x2093,0x19ef, + 0x0cbb,0x2671, 0x30e4,0x0da4, 0x1f89,0x1aa7, + 0x0b14,0x2760, 0x306c,0x0e06, 0x1e7e,0x1b5d, + 0x096d,0x284c, 0x2ff4,0x0e68, 0x1d72,0x1c12, + 0x07c4,0x2935, 0x2f7b,0x0eca, 0x1c64,0x1cc6, + 0x061b,0x2a1a, 0x2f02,0x0f2b, 0x1b56,0x1d79, + 0x0471,0x2afb, 0x2e88,0x0f8d, 0x1a46,0x1e2b, + 0x02c7,0x2bd8, 0x2e0e,0x0fee, 0x1935,0x1edc, + 0x011c,0x2cb2, 0x2d93,0x1050, 0x1824,0x1f8c, + 0xff72,0x2d88, 0x2d18,0x10b1, 0x1711,0x203a, + 0xfdc7,0x2e5a, 0x2c9d,0x1112, 0x15fe,0x20e7, + 0xfc1d,0x2f28, 0x2c21,0x1173, 0x14ea,0x2193, + 0xfa73,0x2ff2, 0x2ba4,0x11d3, 0x13d5,0x223d, + 0xf8ca,0x30b8, 0x2b28,0x1234, 0x12bf,0x22e7, + 0xf721,0x3179, 0x2aaa,0x1294, 0x11a8,0x238e, + 0xf579,0x3236, 0x2a2d,0x12f4, 0x1091,0x2435, + 0xf3d2,0x32ef, 0x29af,0x1354, 0x0f79,0x24da, + 0xf22c,0x33a3, 0x2931,0x13b4, 0x0e61,0x257e, + 0xf087,0x3453, 0x28b2,0x1413, 0x0d48,0x2620, + 0xeee3,0x34ff, 0x2833,0x1473, 0x0c2e,0x26c1, + 0xed41,0x35a5, 0x27b3,0x14d2, 0x0b14,0x2760, + 0xeba1,0x3648, 0x2733,0x1531, 0x09fa,0x27fe, + 0xea02,0x36e5, 0x26b3,0x1590, 0x08df,0x289a, + 0xe865,0x377e, 0x2632,0x15ee, 0x07c4,0x2935, + 0xe6cb,0x3812, 0x25b1,0x164c, 0x06a9,0x29ce, + 0xe532,0x38a1, 0x252f,0x16ab, 0x058d,0x2a65, + 0xe39c,0x392b, 0x24ae,0x1709, 0x0471,0x2afb, + 0xe208,0x39b0, 0x242b,0x1766, 0x0355,0x2b8f, + 0xe077,0x3a30, 0x23a9,0x17c4, 0x0239,0x2c21, + 0xdee9,0x3aab, 0x2326,0x1821, 0x011c,0x2cb2, + 0xdd5d,0x3b21, 0x22a3,0x187e, 0x0000,0x2d41, + 0xdbd5,0x3b92, 0x221f,0x18db, 0xfee4,0x2dcf, + 0xda4f,0x3bfd, 0x219c,0x1937, 0xfdc7,0x2e5a, + 0xd8cd,0x3c64, 0x2117,0x1993, 0xfcab,0x2ee4, + 0xd74e,0x3cc5, 0x2093,0x19ef, 0xfb8f,0x2f6c, + 0xd5d3,0x3d21, 0x200e,0x1a4b, 0xfa73,0x2ff2, + 0xd45c,0x3d78, 0x1f89,0x1aa7, 0xf957,0x3076, + 0xd2e8,0x3dc9, 0x1f04,0x1b02, 0xf83c,0x30f9, + 0xd178,0x3e15, 0x1e7e,0x1b5d, 0xf721,0x3179, + 0xd00c,0x3e5c, 0x1df8,0x1bb8, 0xf606,0x31f8, + 0xcea5,0x3e9d, 0x1d72,0x1c12, 0xf4ec,0x3274, + 0xcd41,0x3ed8, 0x1ceb,0x1c6c, 0xf3d2,0x32ef, + 0xcbe2,0x3f0f, 0x1c64,0x1cc6, 0xf2b8,0x3368, + 0xca88,0x3f40, 0x1bdd,0x1d20, 0xf19f,0x33df, + 0xc932,0x3f6b, 0x1b56,0x1d79, 0xf087,0x3453, + 0xc7e1,0x3f91, 0x1ace,0x1dd3, 0xef6f,0x34c6, + 0xc695,0x3fb1, 0x1a46,0x1e2b, 0xee58,0x3537, + 0xc54e,0x3fcc, 0x19be,0x1e84, 0xed41,0x35a5, + 0xc40c,0x3fe1, 0x1935,0x1edc, 0xec2b,0x3612, + 0xc2cf,0x3ff1, 0x18ad,0x1f34, 0xeb16,0x367d, + 0xc197,0x3ffb, 0x1824,0x1f8c, 0xea02,0x36e5, + 0xc065,0x4000, 0x179b,0x1fe3, 0xe8ef,0x374b, + 0xbf38,0x3fff, 0x1711,0x203a, 0xe7dc,0x37b0, + 0xbe11,0x3ff8, 0x1688,0x2091, 0xe6cb,0x3812, + 0xbcf0,0x3fec, 0x15fe,0x20e7, 0xe5ba,0x3871, + 0xbbd4,0x3fdb, 0x1574,0x213d, 0xe4aa,0x38cf, + 0xbabf,0x3fc4, 0x14ea,0x2193, 0xe39c,0x392b, + 0xb9af,0x3fa7, 0x145f,0x21e8, 0xe28e,0x3984, + 0xb8a6,0x3f85, 0x13d5,0x223d, 0xe182,0x39db, + 0xb7a2,0x3f5d, 0x134a,0x2292, 0xe077,0x3a30, + 0xb6a5,0x3f30, 0x12bf,0x22e7, 0xdf6d,0x3a82, + 0xb5af,0x3efd, 0x1234,0x233b, 0xde64,0x3ad3, + 0xb4be,0x3ec5, 0x11a8,0x238e, 0xdd5d,0x3b21, + 0xb3d5,0x3e88, 0x111d,0x23e2, 0xdc57,0x3b6d, + 0xb2f2,0x3e45, 0x1091,0x2435, 0xdb52,0x3bb6, + 0xb215,0x3dfc, 0x1005,0x2488, 0xda4f,0x3bfd, + 0xb140,0x3daf, 0x0f79,0x24da, 0xd94d,0x3c42, + 0xb071,0x3d5b, 0x0eed,0x252c, 0xd84d,0x3c85, + 0xafa9,0x3d03, 0x0e61,0x257e, 0xd74e,0x3cc5, + 0xaee8,0x3ca5, 0x0dd4,0x25cf, 0xd651,0x3d03, + 0xae2e,0x3c42, 0x0d48,0x2620, 0xd556,0x3d3f, + 0xad7b,0x3bda, 0x0cbb,0x2671, 0xd45c,0x3d78, + 0xacd0,0x3b6d, 0x0c2e,0x26c1, 0xd363,0x3daf, + 0xac2b,0x3afa, 0x0ba1,0x2711, 0xd26d,0x3de3, + 0xab8e,0x3a82, 0x0b14,0x2760, 0xd178,0x3e15, + 0xaaf8,0x3a06, 0x0a87,0x27af, 0xd085,0x3e45, + 0xaa6a,0x3984, 0x09fa,0x27fe, 0xcf94,0x3e72, + 0xa9e3,0x38fd, 0x096d,0x284c, 0xcea5,0x3e9d, + 0xa963,0x3871, 0x08df,0x289a, 0xcdb7,0x3ec5, + 0xa8eb,0x37e1, 0x0852,0x28e7, 0xcccc,0x3eeb, + 0xa87b,0x374b, 0x07c4,0x2935, 0xcbe2,0x3f0f, + 0xa812,0x36b1, 0x0736,0x2981, 0xcafb,0x3f30, + 0xa7b1,0x3612, 0x06a9,0x29ce, 0xca15,0x3f4f, + 0xa757,0x356e, 0x061b,0x2a1a, 0xc932,0x3f6b, + 0xa705,0x34c6, 0x058d,0x2a65, 0xc851,0x3f85, + 0xa6bb,0x3419, 0x04ff,0x2ab0, 0xc772,0x3f9c, + 0xa678,0x3368, 0x0471,0x2afb, 0xc695,0x3fb1, + 0xa63e,0x32b2, 0x03e3,0x2b45, 0xc5ba,0x3fc4, + 0xa60b,0x31f8, 0x0355,0x2b8f, 0xc4e2,0x3fd4, + 0xa5e0,0x3139, 0x02c7,0x2bd8, 0xc40c,0x3fe1, + 0xa5bc,0x3076, 0x0239,0x2c21, 0xc338,0x3fec, + 0xa5a1,0x2faf, 0x01aa,0x2c6a, 0xc266,0x3ff5, + 0xa58d,0x2ee4, 0x011c,0x2cb2, 0xc197,0x3ffb, + 0xa581,0x2e15, 0x008e,0x2cfa, 0xc0ca,0x3fff, + 0xa57e,0x2d41, 0x0000,0x2d41, 0xc000,0x4000, + 0xa581,0x2c6a, 0xff72,0x2d88, 0xbf38,0x3fff, + 0xa58d,0x2b8f, 0xfee4,0x2dcf, 0xbe73,0x3ffb, + 0xa5a1,0x2ab0, 0xfe56,0x2e15, 0xbdb0,0x3ff5, + 0xa5bc,0x29ce, 0xfdc7,0x2e5a, 0xbcf0,0x3fec, + 0xa5e0,0x28e7, 0xfd39,0x2e9f, 0xbc32,0x3fe1, + 0xa60b,0x27fe, 0xfcab,0x2ee4, 0xbb77,0x3fd4, + 0xa63e,0x2711, 0xfc1d,0x2f28, 0xbabf,0x3fc4, + 0xa678,0x2620, 0xfb8f,0x2f6c, 0xba09,0x3fb1, + 0xa6bb,0x252c, 0xfb01,0x2faf, 0xb956,0x3f9c, + 0xa705,0x2435, 0xfa73,0x2ff2, 0xb8a6,0x3f85, + 0xa757,0x233b, 0xf9e5,0x3034, 0xb7f8,0x3f6b, + 0xa7b1,0x223d, 0xf957,0x3076, 0xb74d,0x3f4f, + 0xa812,0x213d, 0xf8ca,0x30b8, 0xb6a5,0x3f30, + 0xa87b,0x203a, 0xf83c,0x30f9, 0xb600,0x3f0f, + 0xa8eb,0x1f34, 0xf7ae,0x3139, 0xb55e,0x3eeb, + 0xa963,0x1e2b, 0xf721,0x3179, 0xb4be,0x3ec5, + 0xa9e3,0x1d20, 0xf693,0x31b9, 0xb422,0x3e9d, + 0xaa6a,0x1c12, 0xf606,0x31f8, 0xb388,0x3e72, + 0xaaf8,0x1b02, 0xf579,0x3236, 0xb2f2,0x3e45, + 0xab8e,0x19ef, 0xf4ec,0x3274, 0xb25e,0x3e15, + 0xac2b,0x18db, 0xf45f,0x32b2, 0xb1cd,0x3de3, + 0xacd0,0x17c4, 0xf3d2,0x32ef, 0xb140,0x3daf, + 0xad7b,0x16ab, 0xf345,0x332c, 0xb0b5,0x3d78, + 0xae2e,0x1590, 0xf2b8,0x3368, 0xb02d,0x3d3f, + 0xaee8,0x1473, 0xf22c,0x33a3, 0xafa9,0x3d03, + 0xafa9,0x1354, 0xf19f,0x33df, 0xaf28,0x3cc5, + 0xb071,0x1234, 0xf113,0x3419, 0xaea9,0x3c85, + 0xb140,0x1112, 0xf087,0x3453, 0xae2e,0x3c42, + 0xb215,0x0fee, 0xeffb,0x348d, 0xadb6,0x3bfd, + 0xb2f2,0x0eca, 0xef6f,0x34c6, 0xad41,0x3bb6, + 0xb3d5,0x0da4, 0xeee3,0x34ff, 0xacd0,0x3b6d, + 0xb4be,0x0c7c, 0xee58,0x3537, 0xac61,0x3b21, + 0xb5af,0x0b54, 0xedcc,0x356e, 0xabf6,0x3ad3, + 0xb6a5,0x0a2b, 0xed41,0x35a5, 0xab8e,0x3a82, + 0xb7a2,0x0901, 0xecb6,0x35dc, 0xab29,0x3a30, + 0xb8a6,0x07d6, 0xec2b,0x3612, 0xaac8,0x39db, + 0xb9af,0x06aa, 0xeba1,0x3648, 0xaa6a,0x3984, + 0xbabf,0x057e, 0xeb16,0x367d, 0xaa0f,0x392b, + 0xbbd4,0x0451, 0xea8c,0x36b1, 0xa9b7,0x38cf, + 0xbcf0,0x0324, 0xea02,0x36e5, 0xa963,0x3871, + 0xbe11,0x01f7, 0xe978,0x3718, 0xa912,0x3812, + 0xbf38,0x00c9, 0xe8ef,0x374b, 0xa8c5,0x37b0, + 0xc065,0xff9b, 0xe865,0x377e, 0xa87b,0x374b, + 0xc197,0xfe6e, 0xe7dc,0x37b0, 0xa834,0x36e5, + 0xc2cf,0xfd40, 0xe753,0x37e1, 0xa7f1,0x367d, + 0xc40c,0xfc13, 0xe6cb,0x3812, 0xa7b1,0x3612, + 0xc54e,0xfae6, 0xe642,0x3842, 0xa774,0x35a5, + 0xc695,0xf9ba, 0xe5ba,0x3871, 0xa73b,0x3537, + 0xc7e1,0xf88e, 0xe532,0x38a1, 0xa705,0x34c6, + 0xc932,0xf763, 0xe4aa,0x38cf, 0xa6d3,0x3453, + 0xca88,0xf639, 0xe423,0x38fd, 0xa6a4,0x33df, + 0xcbe2,0xf50f, 0xe39c,0x392b, 0xa678,0x3368, + 0xcd41,0xf3e6, 0xe315,0x3958, 0xa650,0x32ef, + 0xcea5,0xf2bf, 0xe28e,0x3984, 0xa62c,0x3274, + 0xd00c,0xf198, 0xe208,0x39b0, 0xa60b,0x31f8, + 0xd178,0xf073, 0xe182,0x39db, 0xa5ed,0x3179, + 0xd2e8,0xef4f, 0xe0fc,0x3a06, 0xa5d3,0x30f9, + 0xd45c,0xee2d, 0xe077,0x3a30, 0xa5bc,0x3076, + 0xd5d3,0xed0c, 0xdff2,0x3a59, 0xa5a9,0x2ff2, + 0xd74e,0xebed, 0xdf6d,0x3a82, 0xa599,0x2f6c, + 0xd8cd,0xeacf, 0xdee9,0x3aab, 0xa58d,0x2ee4, + 0xda4f,0xe9b4, 0xde64,0x3ad3, 0xa585,0x2e5a, + 0xdbd5,0xe89a, 0xdde1,0x3afa, 0xa57f,0x2dcf, + 0xdd5d,0xe782, 0xdd5d,0x3b21, 0xa57e,0x2d41, + 0xdee9,0xe66d, 0xdcda,0x3b47, 0xa57f,0x2cb2, + 0xe077,0xe559, 0xdc57,0x3b6d, 0xa585,0x2c21, + 0xe208,0xe448, 0xdbd5,0x3b92, 0xa58d,0x2b8f, + 0xe39c,0xe33a, 0xdb52,0x3bb6, 0xa599,0x2afb, + 0xe532,0xe22d, 0xdad1,0x3bda, 0xa5a9,0x2a65, + 0xe6cb,0xe124, 0xda4f,0x3bfd, 0xa5bc,0x29ce, + 0xe865,0xe01d, 0xd9ce,0x3c20, 0xa5d3,0x2935, + 0xea02,0xdf19, 0xd94d,0x3c42, 0xa5ed,0x289a, + 0xeba1,0xde18, 0xd8cd,0x3c64, 0xa60b,0x27fe, + 0xed41,0xdd19, 0xd84d,0x3c85, 0xa62c,0x2760, + 0xeee3,0xdc1e, 0xd7cd,0x3ca5, 0xa650,0x26c1, + 0xf087,0xdb26, 0xd74e,0x3cc5, 0xa678,0x2620, + 0xf22c,0xda31, 0xd6cf,0x3ce4, 0xa6a4,0x257e, + 0xf3d2,0xd93f, 0xd651,0x3d03, 0xa6d3,0x24da, + 0xf579,0xd851, 0xd5d3,0x3d21, 0xa705,0x2435, + 0xf721,0xd766, 0xd556,0x3d3f, 0xa73b,0x238e, + 0xf8ca,0xd67f, 0xd4d8,0x3d5b, 0xa774,0x22e7, + 0xfa73,0xd59b, 0xd45c,0x3d78, 0xa7b1,0x223d, + 0xfc1d,0xd4bb, 0xd3df,0x3d93, 0xa7f1,0x2193, + 0xfdc7,0xd3df, 0xd363,0x3daf, 0xa834,0x20e7, + 0xff72,0xd306, 0xd2e8,0x3dc9, 0xa87b,0x203a, + 0x011c,0xd231, 0xd26d,0x3de3, 0xa8c5,0x1f8c, + 0x02c7,0xd161, 0xd1f2,0x3dfc, 0xa912,0x1edc, + 0x0471,0xd094, 0xd178,0x3e15, 0xa963,0x1e2b, + 0x061b,0xcfcc, 0xd0fe,0x3e2d, 0xa9b7,0x1d79, + 0x07c4,0xcf07, 0xd085,0x3e45, 0xaa0f,0x1cc6, + 0x096d,0xce47, 0xd00c,0x3e5c, 0xaa6a,0x1c12, + 0x0b14,0xcd8c, 0xcf94,0x3e72, 0xaac8,0x1b5d, + 0x0cbb,0xccd4, 0xcf1c,0x3e88, 0xab29,0x1aa7, + 0x0e61,0xcc21, 0xcea5,0x3e9d, 0xab8e,0x19ef, + 0x1005,0xcb73, 0xce2e,0x3eb1, 0xabf6,0x1937, + 0x11a8,0xcac9, 0xcdb7,0x3ec5, 0xac61,0x187e, + 0x134a,0xca24, 0xcd41,0x3ed8, 0xacd0,0x17c4, + 0x14ea,0xc983, 0xcccc,0x3eeb, 0xad41,0x1709, + 0x1688,0xc8e8, 0xcc57,0x3efd, 0xadb6,0x164c, + 0x1824,0xc850, 0xcbe2,0x3f0f, 0xae2e,0x1590, + 0x19be,0xc7be, 0xcb6e,0x3f20, 0xaea9,0x14d2, + 0x1b56,0xc731, 0xcafb,0x3f30, 0xaf28,0x1413, + 0x1ceb,0xc6a8, 0xca88,0x3f40, 0xafa9,0x1354, + 0x1e7e,0xc625, 0xca15,0x3f4f, 0xb02d,0x1294, + 0x200e,0xc5a7, 0xc9a3,0x3f5d, 0xb0b5,0x11d3, + 0x219c,0xc52d, 0xc932,0x3f6b, 0xb140,0x1112, + 0x2326,0xc4b9, 0xc8c1,0x3f78, 0xb1cd,0x1050, + 0x24ae,0xc44a, 0xc851,0x3f85, 0xb25e,0x0f8d, + 0x2632,0xc3e0, 0xc7e1,0x3f91, 0xb2f2,0x0eca, + 0x27b3,0xc37b, 0xc772,0x3f9c, 0xb388,0x0e06, + 0x2931,0xc31c, 0xc703,0x3fa7, 0xb422,0x0d41, + 0x2aaa,0xc2c1, 0xc695,0x3fb1, 0xb4be,0x0c7c, + 0x2c21,0xc26d, 0xc627,0x3fbb, 0xb55e,0x0bb7, + 0x2d93,0xc21d, 0xc5ba,0x3fc4, 0xb600,0x0af1, + 0x2f02,0xc1d3, 0xc54e,0x3fcc, 0xb6a5,0x0a2b, + 0x306c,0xc18e, 0xc4e2,0x3fd4, 0xb74d,0x0964, + 0x31d2,0xc14f, 0xc476,0x3fdb, 0xb7f8,0x089d, + 0x3334,0xc115, 0xc40c,0x3fe1, 0xb8a6,0x07d6, + 0x3492,0xc0e0, 0xc3a1,0x3fe7, 0xb956,0x070e, + 0x35eb,0xc0b1, 0xc338,0x3fec, 0xba09,0x0646, + 0x373f,0xc088, 0xc2cf,0x3ff1, 0xbabf,0x057e, + 0x388e,0xc064, 0xc266,0x3ff5, 0xbb77,0x04b5, + 0x39d9,0xc045, 0xc1fe,0x3ff8, 0xbc32,0x03ed, + 0x3b1e,0xc02c, 0xc197,0x3ffb, 0xbcf0,0x0324, + 0x3c5f,0xc019, 0xc130,0x3ffd, 0xbdb0,0x025b, + 0x3d9a,0xc00b, 0xc0ca,0x3fff, 0xbe73,0x0192, + 0x3ed0,0xc003, 0xc065,0x4000, 0xbf38,0x00c9 +}; + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ + +#endif /* __TABLE_FFT_H */ + +/******************* (C) COPYRIGHT 2009 STMicroelectronics *****END OF FILE****/ From c693d0038e0e02ceccfc268596223c765ea407fd Mon Sep 17 00:00:00 2001 From: victorpv Date: Wed, 28 Mar 2018 22:19:47 -0500 Subject: [PATCH 301/351] Some more SDIO corrections and improvements --- STM32F1/system/libmaple/include/libmaple/sdio.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/STM32F1/system/libmaple/include/libmaple/sdio.h b/STM32F1/system/libmaple/include/libmaple/sdio.h index dec31c8..64e71c2 100644 --- a/STM32F1/system/libmaple/include/libmaple/sdio.h +++ b/STM32F1/system/libmaple/include/libmaple/sdio.h @@ -57,7 +57,7 @@ typedef struct sdio_reg_map { __io uint32 ARG; // 0x08 __io uint32 CMD; // 0x0C __io uint32 RESPCMD; // 0x10 (0x3F) - const uint32 RESP[4]; // 0x14 - contain the card status, which is part of the received response. + __io const uint32 RESP[4]; // 0x14 - contain the card status, which is part of the received response. __io uint32 DTIMER; // 0x24 - contains the data timeout period, in card bus clock periods. __io uint32 DLEN; // 0x28 (0x01FF FFFF) - contains the number of data bytes to be transferred __io uint32 DCTRL; // 0x2C @@ -95,7 +95,7 @@ extern sdio_dev * SDIO; // After a data write, data cannot be written to this register for three SDIOCLK clock periods // plus two PCLK2 clock periods. SDIO_CK can also be stopped during the read wait interval // for SD I/O cards: in this case the SDIO_CLKCR register does not control SDIO_CK. -#define SDIO_CLKCR_HWFC_EN (1<<14) // HW Flow Control enable - DON'T USE!!! (see errata sheet 2.12.1) +#define SDIO_CLKCR_HWFC_EN (1<<14) // HW Flow Control enable - DON'T USE in F4!!! (see errata sheet 2.12.1) // Overrun errors (Rx mode) and FIFO underrun (Tx mode) // should be managed by the application software. #define SDIO_CLKCR_NEGEDGE (1<<13) // SDIO_CK de-phasing selection bit - DON'T USE!!! (see errata sheet 2.12.4) @@ -106,7 +106,7 @@ extern sdio_dev * SDIO; #define SDIO_CLKCR_PWRSAV (1<<9) // 0: SDIO_CK clock is always enabled, 1: SDIO_CK is only enabled when the bus is active #define SDIO_CLKCR_CLKEN (1<<8) // Clock enable #define SDIO_CLKCR_CLKDIV (0xFF) // SDIO_CK = SDIOCLK / [CLKDIV + 2] -#define SDIOCLK 72000000UL // SDIO master clock frequency +#define SDIOCLK PCLK2 // SDIO master clock frequency // SDIO_CMD register bits // After a data write, data cannot be written to this register for three SDIOCLK clock periods From 5c3c9af24137eb36307534513b60918214717a77 Mon Sep 17 00:00:00 2001 From: victorpv Date: Wed, 28 Mar 2018 22:23:41 -0500 Subject: [PATCH 302/351] Revert "Hardware serial corrections" This reverts commit 771be821c288f74f4106768aca0042d05c0d038d. --- STM32F1/cores/maple/HardwareSerial.cpp | 2 +- STM32F1/cores/maple/HardwareSerial.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/STM32F1/cores/maple/HardwareSerial.cpp b/STM32F1/cores/maple/HardwareSerial.cpp index fe73339..024efbc 100644 --- a/STM32F1/cores/maple/HardwareSerial.cpp +++ b/STM32F1/cores/maple/HardwareSerial.cpp @@ -187,7 +187,7 @@ int HardwareSerial::availableForWrite(void) return 1; } -size_t HardwareSerial::write(uint8_t ch) { +size_t HardwareSerial::write(unsigned char ch) { usart_putc(this->usart_device, ch); return 1; diff --git a/STM32F1/cores/maple/HardwareSerial.h b/STM32F1/cores/maple/HardwareSerial.h index 108d525..b8b8dd6 100644 --- a/STM32F1/cores/maple/HardwareSerial.h +++ b/STM32F1/cores/maple/HardwareSerial.h @@ -138,7 +138,7 @@ public: virtual int read(void); int availableForWrite(void); virtual void flush(void); - virtual size_t write(uint8_t ch); + virtual size_t write(uint8_t); inline size_t write(unsigned long n) { return write((uint8_t)n); } inline size_t write(long n) { return write((uint8_t)n); } inline size_t write(unsigned int n) { return write((uint8_t)n); } From e3510b76eb0680cca87df4c9bfeef096300b61a7 Mon Sep 17 00:00:00 2001 From: victorpv Date: Wed, 28 Mar 2018 22:27:39 -0500 Subject: [PATCH 303/351] Revert "SDIO updates" This reverts commit 7dce451ebc9ec79dd2157913202fa0c03daf74ae. --- STM32F1/cores/maple/sdio.cpp | 51 +-- STM32F1/libraries/SDIO/SdioF1.cpp | 571 +++++++----------------------- STM32F1/libraries/SDIO/SdioF1.h | 4 +- 3 files changed, 144 insertions(+), 482 deletions(-) diff --git a/STM32F1/cores/maple/sdio.cpp b/STM32F1/cores/maple/sdio.cpp index 2edf501..8bd9491 100644 --- a/STM32F1/cores/maple/sdio.cpp +++ b/STM32F1/cores/maple/sdio.cpp @@ -32,8 +32,8 @@ sdio_dev * SDIO = SDIO_BASE; -#define DELAY_LONG 20 -#define DELAY_SHORT 2 +#define DELAY_LONG 10 +#define DELAY_SHORT 1 uint8_t dly = DELAY_LONG; // microseconds delay after accessing registers @@ -43,13 +43,9 @@ uint8_t dly = DELAY_LONG; // microseconds delay after accessing registers void sdio_gpios_init(void) { gpio_set_mode(PIN_MAP[BOARD_SDIO_D0].gpio_device, PIN_MAP[BOARD_SDIO_D0].gpio_bit, GPIO_AF_OUTPUT_PP); -/* gpio_set_mode(PIN_MAP[BOARD_SDIO_D1].gpio_device, PIN_MAP[BOARD_SDIO_D1].gpio_bit, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PIN_MAP[BOARD_SDIO_D1].gpio_device, PIN_MAP[BOARD_SDIO_D1].gpio_bit, GPIO_AF_OUTPUT_PP); gpio_set_mode(PIN_MAP[BOARD_SDIO_D2].gpio_device, PIN_MAP[BOARD_SDIO_D2].gpio_bit, GPIO_AF_OUTPUT_PP); gpio_set_mode(PIN_MAP[BOARD_SDIO_D3].gpio_device, PIN_MAP[BOARD_SDIO_D3].gpio_bit, GPIO_AF_OUTPUT_PP); -*/ - gpio_set_mode(PIN_MAP[BOARD_SDIO_D1].gpio_device, PIN_MAP[BOARD_SDIO_D1].gpio_bit, GPIO_INPUT_PU); - gpio_set_mode(PIN_MAP[BOARD_SDIO_D2].gpio_device, PIN_MAP[BOARD_SDIO_D2].gpio_bit, GPIO_INPUT_PU); - gpio_set_mode(PIN_MAP[BOARD_SDIO_D3].gpio_device, PIN_MAP[BOARD_SDIO_D3].gpio_bit, GPIO_INPUT_PU); gpio_set_mode(PIN_MAP[BOARD_SDIO_CLK].gpio_device, PIN_MAP[BOARD_SDIO_CLK].gpio_bit, GPIO_AF_OUTPUT_PP); gpio_set_mode(PIN_MAP[BOARD_SDIO_CMD].gpio_device, PIN_MAP[BOARD_SDIO_CMD].gpio_bit, GPIO_AF_OUTPUT_PP); /* @@ -67,12 +63,12 @@ void sdio_gpios_init(void) void sdio_gpios_deinit(void) { - gpio_set_mode(PIN_MAP[BOARD_SDIO_D0].gpio_device, PIN_MAP[BOARD_SDIO_D0].gpio_bit, GPIO_INPUT_PU); - gpio_set_mode(PIN_MAP[BOARD_SDIO_D1].gpio_device, PIN_MAP[BOARD_SDIO_D1].gpio_bit, GPIO_INPUT_PU); - gpio_set_mode(PIN_MAP[BOARD_SDIO_D2].gpio_device, PIN_MAP[BOARD_SDIO_D2].gpio_bit, GPIO_INPUT_PU); - gpio_set_mode(PIN_MAP[BOARD_SDIO_D3].gpio_device, PIN_MAP[BOARD_SDIO_D3].gpio_bit, GPIO_INPUT_PU); - gpio_set_mode(PIN_MAP[BOARD_SDIO_CLK].gpio_device, PIN_MAP[BOARD_SDIO_CLK].gpio_bit, GPIO_INPUT_PU); - gpio_set_mode(PIN_MAP[BOARD_SDIO_CMD].gpio_device, PIN_MAP[BOARD_SDIO_CMD].gpio_bit, GPIO_INPUT_PU); + gpio_set_mode(PIN_MAP[BOARD_SDIO_D0].gpio_device, PIN_MAP[BOARD_SDIO_D0].gpio_bit, GPIO_INPUT_FLOATING); + gpio_set_mode(PIN_MAP[BOARD_SDIO_D1].gpio_device, PIN_MAP[BOARD_SDIO_D1].gpio_bit, GPIO_INPUT_FLOATING); + gpio_set_mode(PIN_MAP[BOARD_SDIO_D2].gpio_device, PIN_MAP[BOARD_SDIO_D2].gpio_bit, GPIO_INPUT_FLOATING); + gpio_set_mode(PIN_MAP[BOARD_SDIO_D3].gpio_device, PIN_MAP[BOARD_SDIO_D3].gpio_bit, GPIO_INPUT_FLOATING); + gpio_set_mode(PIN_MAP[BOARD_SDIO_CLK].gpio_device, PIN_MAP[BOARD_SDIO_CLK].gpio_bit, GPIO_INPUT_FLOATING); + gpio_set_mode(PIN_MAP[BOARD_SDIO_CMD].gpio_device, PIN_MAP[BOARD_SDIO_CMD].gpio_bit, GPIO_INPUT_FLOATING); /* * Todo just remove it, not needed for F1. @@ -114,35 +110,19 @@ void sdio_power_off(void) void sdio_set_clock(uint32_t clk) { - /* - * limit the SDIO master clock to 8/3 of PCLK2.See RM 22.3 - * Also limited to no more than 48Mhz - */ - clk = min(clk,(SDIOCLK/3)*8); - clk = min(clk,36000000); + if (clk>24000000UL) clk = 24000000UL; // limit the SDIO master clock to 24MHz if (clk<1000000) dly = DELAY_LONG; else dly = DELAY_SHORT; - /* - * round up divider, so we don't run the card over the speed supported. - - */ - uint32 div = SDIOCLK/clk + (SDIOCLK % clk != 0) - 2; - - sdio_disable(); - //Serial.println(div,DEC); - SDIO->CLKCR = (SDIO->CLKCR & (~(SDIO_CLKCR_CLKDIV|SDIO_CLKCR_BYPASS))) | SDIO_CLKCR_PWRSAV | SDIO_CLKCR_HWFC_EN | SDIO_CLKCR_CLKEN | (div & SDIO_CLKCR_CLKDIV); + SDIO->CLKCR = (SDIO->CLKCR & (~(SDIO_CLKCR_CLKDIV|SDIO_CLKCR_BYPASS))) | SDIO_CLKCR_CLKEN | (((SDIOCLK/clk)-2)&SDIO_CLKCR_CLKDIV); delay_us(dly); } void sdio_set_dbus_width(uint16_t bus_w) { SDIO->CLKCR = (SDIO->CLKCR & (~SDIO_CLKCR_WIDBUS)) | bus_w; - gpio_set_mode(PIN_MAP[BOARD_SDIO_D1].gpio_device, PIN_MAP[BOARD_SDIO_D1].gpio_bit, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PIN_MAP[BOARD_SDIO_D2].gpio_device, PIN_MAP[BOARD_SDIO_D2].gpio_bit, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PIN_MAP[BOARD_SDIO_D3].gpio_device, PIN_MAP[BOARD_SDIO_D3].gpio_bit, GPIO_AF_OUTPUT_PP); delay_us(dly); } @@ -169,10 +149,9 @@ void sdio_disable(void) */ void sdio_begin(void) { - + sdio_gpios_init(); sdio_init(); sdio_power_on(); - sdio_gpios_init(); // Set initial SCK rate. sdio_set_clock(400000); delay_us(200); // generate 80 pulses at 400kHz @@ -183,12 +162,11 @@ void sdio_begin(void) */ void sdio_end(void) { - while ( sdio_cmd_xfer_ongoing() ); sdio_disable(); - sdio_gpios_deinit(); + while ( sdio_cmd_xfer_ongoing() ); sdio_power_off(); rcc_clk_disable(RCC_SDIO); - + sdio_gpios_deinit(); } /** @@ -209,7 +187,6 @@ uint8_t sdio_cmd_send(uint16_t cmd_index_resp_type, uint32_t arg) while ( !(SDIO->STA&(SDIO_STA_CMDREND|SDIO_STA_CMD_ERROR_FLAGS)) ) ; } else break; // no response required if ( SDIO->STA&(SDIO_STA_CMDREND|SDIO_STA_CTIMEOUT) ) - //if ( SDIO->STA&(SDIO_STA_CMDREND) ) break; // response received or timeout // ignore CRC error for CMD5 and ACMD41 if ( ((cmd_index_resp_type&SDIO_CMD_CMDINDEX)==5) || ((cmd_index_resp_type&SDIO_CMD_CMDINDEX)==41) ) diff --git a/STM32F1/libraries/SDIO/SdioF1.cpp b/STM32F1/libraries/SDIO/SdioF1.cpp index c0e5eae..8957b37 100644 --- a/STM32F1/libraries/SDIO/SdioF1.cpp +++ b/STM32F1/libraries/SDIO/SdioF1.cpp @@ -61,12 +61,6 @@ #define CMD38_XFERTYP (uint16_t)( CMD38 | CMD_RESP_R1b ) #define ACMD41_XFERTYP (uint16_t)( ACMD41 | CMD_RESP_R3 ) -/* - * AMD42 to enable disable CD/D3 pull up. Needed for 4bit mode. - */ -const uint8_t ACMD42 = 0X2A; -#define ACMD42_XFERTYP (uint16_t)( ACMD41 | CMD_RESP_R1 ) - #define CMD55_XFERTYP (uint16_t)( CMD55 | CMD_RESP_R1 ) //============================================================================= @@ -75,27 +69,14 @@ const uint8_t ACMD42 = 0X2A; static void initSDHC(void); static bool isBusyCMD13(void); static bool isBusyTransferComplete(void); -static bool isBusyTransferCRC(void); //static bool isBusyCommandComplete(); //static bool isBusyCommandInhibit(); static bool readReg16(uint32_t xfertyp, void* data); //static void setSdclk(uint32_t kHzMax); static bool yieldTimeout(bool (*fcn)(void)); -static bool yieldDmaStatus(void); static bool waitDmaStatus(void); static bool waitTimeout(bool (*fcn)(void)); //----------------------------------------------------------------------------- -static const uint32_t IDLE_STATE = 0; -static const uint32_t READ_STATE = 1; -static const uint32_t WRITE_STATE = 2; -volatile uint32_t m_curLba; -volatile uint32_t m_limitLba; -volatile uint8_t m_curState; -volatile uint64_t m_totalReadLbas = 0; -volatile uint64_t m_readErrors = 0; -volatile uint64_t m_writeErrors = 0; -volatile uint64_t m_totalWriteLbas = 0; - #define TRX_RD 0 #define TRX_WR 1 static uint8_t m_dir = TRX_RD; @@ -116,26 +97,27 @@ static cid_t m_cid; static csd_t m_csd; static uint32_t t = 0; //============================================================================= - +/* + * Todo Remove this or change it, but rather remove since this can be checked with debugger. + */ #if USE_DEBUG_MODE #define DBG_PRINT() { \ Serial.write('_'); Serial.print(__FUNCTION__); Serial.write('_'); Serial.print(__LINE__); Serial.print(": "); \ - Serial.print("DMA->ISR: 0x"); Serial.print(SDIO_DMA_DEV->regs->ISR, HEX); \ + Serial.print("DMA->LISR: "); Serial.print(SDIO_DMA_DEV->regs->LISR, HEX); \ /*Serial.print("DMA->HISR: "); Serial.println(SDIO_DMA_DEV->regs->HISR, HEX);*/ \ - Serial.print(", DMA->CCR: 0x"); Serial.print(SDIO_DMA_DEV->regs->CCR4, HEX); \ - Serial.print(", DMA->CNDTR: "); Serial.print(SDIO_DMA_DEV->regs->CNDTR4,DEC); \ - /**/Serial.print(", DMA->CPAR: 0x"); Serial.print(SDIO_DMA_DEV->regs->CPAR4, HEX); \ - /**/Serial.print(", DMA->CMAR: 0x"); Serial.print(SDIO_DMA_DEV->regs->CMAR4, HEX); \ - Serial.print(", DMA->IFCR: 0x"); Serial.print(SDIO_DMA_DEV->regs->IFCR, HEX); \ + Serial.print(", DMA->CR: "); Serial.print(SDIO_DMA_DEV->regs->STREAM[SDIO_DMA_CHANNEL].CR, HEX); \ + Serial.print(", DMA->NDTR: "); Serial.print(SDIO_DMA_DEV->regs->STREAM[SDIO_DMA_CHANNEL].NDTR, HEX); \ + /**/Serial.print(", DMA->PAR: "); Serial.print(SDIO_DMA_DEV->regs->STREAM[SDIO_DMA_CHANNEL].PAR, HEX); \ + /**/Serial.print(", DMA->M0AR: "); Serial.print(SDIO_DMA_DEV->regs->STREAM[SDIO_DMA_CHANNEL].M0AR, HEX); \ + Serial.print(", DMA->FCR: "); Serial.print(SDIO_DMA_DEV->regs->STREAM[SDIO_DMA_CHANNEL].FCR, HEX); \ \ /*Serial.print(" SDIO->POWER: "); Serial.println(SDIO->POWER, HEX);*/ \ - Serial.print(", SDIO->CLKCR: 0x"); Serial.print(SDIO->CLKCR, HEX); \ - Serial.print(", SDIO->DTIMER: 0x"); Serial.print(SDIO->DTIMER, HEX); \ - Serial.print(", SDIO->DCTRL: 0x"); Serial.print(SDIO->DCTRL, HEX); \ + Serial.print(", SDIO->CLKCR: "); Serial.print(SDIO->CLKCR, HEX); \ + Serial.print(", SDIO->DTIMER: "); Serial.print(SDIO->DTIMER, HEX); \ + Serial.print(", SDIO->DCTRL: "); Serial.print(SDIO->DCTRL, HEX); \ /**/Serial.print(", SDIO->DLEN: "); Serial.print(SDIO->DLEN); \ Serial.print(", SDIO->DCOUNT: "); Serial.print(SDIO->DCOUNT); \ - Serial.print(", SDIO->STA: 0x"); Serial.println(SDIO->STA, HEX); \ - Serial.print(", SDIO->FIFOCNT: "); Serial.println(SDIO->FIFOCNT); \ + Serial.print(", SDIO->STA: "); Serial.println(SDIO->STA, HEX); \ /*delay(1);*/ \ } #define DBG_PIN PD0 @@ -149,7 +131,7 @@ static void _panic(const char *message, uint32_t code) { Serial.print(message); Serial.println(code, HEX); //Block the execution with blinky leds - while (1) {delay (1);}; + while (1); /* pinMode(BOARD_LED_PIN, OUTPUT); //pinMode(BOARD_LED2_PIN, OUTPUT); @@ -189,14 +171,13 @@ void yield(void) } val = dma_get_isr_bits(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); -/* if ( val & DMA_ISR_FEIF ) { + if ( val & DMA_ISR_FEIF ) { val ^= DMA_ISR_FEIF; dma_clear_isr_bits(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); } -*/ if ( val ) { if (val & DMA_ISR_TEIF) Serial.print(" TEIF"); - //if (val & DMA_ISR_DMEIF) Serial.print(" DMEIF"); + if (val & DMA_ISR_DMEIF) Serial.print(" DMEIF"); //if (val & DMA_ISR_FEIF) Serial.print(" FEIF"); _panic(" - DMA: Data Transmission Error ", val); } @@ -227,7 +208,7 @@ static bool cardCommand(uint16_t xfertyp, uint32_t arg) #if USE_DEBUG_MODE==2 Serial.print("cardCommand: "); Serial.print(xfertyp&SDIO_CMD_CMDINDEX); Serial.print(", arg: "); Serial.print(arg, HEX); #endif - uint8_t resp = sdio_cmd_send(xfertyp, arg); // returns non-zero if OK, zero if it fails + uint8_t resp = sdio_cmd_send(xfertyp, arg); // returns non-zero if fails, zero if OK #if USE_DEBUG_MODE==2 Serial.print(", resp: "); Serial.print(resp, HEX); Serial.print(", SDIO->STA: "); Serial.print(SDIO->STA, HEX); Serial.print(", cmd_resp: "); Serial.print(SDIO->RESP[0], HEX); @@ -283,38 +264,19 @@ static bool isBusyCMD13(void) { } return !(SDIO->RESP[0] & CARD_STATUS_READY_FOR_DATA); } - -/* - * Returns False if DMA transfer disabled. - * True otherwise - */ -static bool inline isEnabledDMA(void) -{ - return dma_is_enabled(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); -} - -/* - * Returns False if DMA transfer is completed or in error. - * True otherwise - */ +/*---------------------------------------------------------------------------*/ static bool isBusyDMA(void) { - if (!isEnabledDMA()) return false; uint8_t isr = dma_get_isr_bits(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); - isr &= DMA_ISR_TCIF | DMA_ISR_TEIF; + isr &= DMA_ISR_TCIF | DMA_ISR_TEIF; //if (isr&DMA_ISR_TCIF) dma_disable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); return !(isr); // ignore transfer error flag } - /*---------------------------------------------------------------------------*/ -/* - * Returns true while the transfer has not completed - * False when it has completed. - */ static bool isBusyTransferComplete(void) { uint32_t mask = SDIO->STA &(SDIO_STA_DATAEND | SDIO_STA_TRX_ERROR_FLAGS); -//#if USE_DEBUG_MODE +#if USE_DEBUG_MODE if ( mask & SDIO_STA_TRX_ERROR_FLAGS ) { Serial.print("XFER ERROR: SDIO->STA: "); Serial.print(SDIO->STA, HEX); if (mask & SDIO_STA_STBITERR) Serial.print(" STBITERR"); @@ -324,43 +286,13 @@ static bool isBusyTransferComplete(void) if (mask & SDIO_STA_DCRCFAIL) Serial.print(" DCRCFAIL"); Serial.println(); } -//#endif +#endif if (mask) { dma_disable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); return false; } return true; } - - -/* - * New function, to follow Reference Manual sequence. - * Returns true if still not confirmed DBCKEND: Data block sent/received (CRC check passed) - * False when it has completed the transfer with CRC check. - */ -static bool isBusyTransferCRC(void) -{ - uint32_t mask = SDIO->STA &(SDIO_STA_DBCKEND | SDIO_STA_TRX_ERROR_FLAGS); -#if USE_DEBUG_MODE - if ( mask & SDIO_STA_TRX_ERROR_FLAGS ) { - Serial.print("XFER ERROR: SDIO->STA: "); Serial.print(SDIO->STA, HEX); - if (mask & SDIO_STA_STBITERR) Serial.print(" STBITERR"); - if (mask & SDIO_STA_RXOVERR) Serial.print(" RXOVERR"); - if (mask & SDIO_STA_TXUNDERR) Serial.print(" TXUNDERR"); - if (mask & SDIO_STA_DTIMEOUT) Serial.print(" DTIMEOUT"); - if (mask & SDIO_STA_DCRCFAIL) Serial.print(" DCRCFAIL"); - Serial.println(); - } -#endif - if (mask) { - //dma_disable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); - //Serial.print("SDIO->STA SDIO_STA_DBCKEND"); Serial.println(SDIO->STA && SDIO_STA_DBCKEND, HEX); - return false; - } - return true; -} - - /*---------------------------------------------------------------------------*/ static void trxStart(uint8_t* buf, uint32_t n, uint8_t dir) { @@ -376,12 +308,6 @@ static bool trxStop() if (!cardCommand(CMD12_XFERTYP, 0)) { return sdError(SD_CARD_ERROR_CMD12); } - /* - * Added this to wait to complete on sync. - */ - if (waitTimeout(isBusyCMD13)) { - return sdError(SD_CARD_ERROR_CMD13); - } if ( t ) { Serial.print(", in "); Serial.println(millis()-t); t = 0; @@ -389,70 +315,52 @@ static bool trxStop() return true; } /*---------------------------------------------------------------------------*/ -static bool dmaTrxStart(uint32_t n, uint8_t dir) +static bool dmaTrxStart(uint8_t* buf, uint32_t n, uint8_t dir) { - uint32_t flags = (SDIO_BLOCKSIZE_512 | SDIO_DCTRL_DMAEN | SDIO_DCTRL_DTEN); + m_dir = dir; + if ((3 & (uint32_t)buf) || n == 0) { // check alignment + _panic("- transferStart: unaligned buffer address ", (uint32_t)buf); + return sdError(SD_CARD_ERROR_DMA); + } + if (dir==TRX_RD && yieldTimeout(isBusyCMD13)) { + return sdError(SD_CARD_ERROR_CMD13); + } + uint32_t flags = (SDIO_BLOCKSIZE_512 | SDIO_DCTRL_DMAEN | SDIO_DCTRL_DTEN); if (dir==TRX_RD) flags |= SDIO_DIR_RX; // setup SDIO to transfer n blocks of 512 bytes sdio_setup_transfer(0x00FFFFFF, n, flags); - + // setup SDIO_DMA_DEV stream 3 channel 4 + /* + * Moved to begin. + */ + //dma_init(SDIO_DMA_DEV); + /* + * Todo. Check this, channel must be disabled to change DMA priority, and seems like channel is not completing transfers + */ + //dma_set_priority(SDIO_DMA_DEV, SDIO_DMA_CHANNEL, DMA_PRIORITY_VERY_HIGH); + flags = (DMA_MINC_MODE); + // not extra flag if read + if (dir!=TRX_RD) flags |= DMA_FROM_MEM;// write + dma_setup_transfer(SDIO_DMA_DEV, SDIO_DMA_CHANNEL, &SDIO->FIFO, DMA_SIZE_32BITS, buf, DMA_SIZE_32BITS, flags); + dma_set_num_transfers(SDIO_DMA_DEV, SDIO_DMA_CHANNEL, n>>2); // F1 DMA controller counts each word as 1 data item. + //dma_set_fifo_flags(SDIO_DMA_DEV, SDIO_DMA_CHANNEL, (DMA_FCR_DMDIS | DMA_FCR_FTH_FULL)); // disable direct mode | threshold FULL + dma_clear_isr_bits(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); + dma_enable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); return true; } - -/* - * This one replaces dmaTrxStart, and will just prepare the DMA part, then a new - * one will enable the DMA reception as per the RM. - */ -static bool dmaTrxPrepare(uint8_t* buf, uint32_t n, uint8_t dir) -{ - uint32_t flags; - m_dir = dir; - if ((3 & (uint32_t)buf) || n == 0) { // check alignment - _panic("- transferStart: unaligned buffer address ", (uint32_t)buf); - return sdError(SD_CARD_ERROR_DMA); - } - /* - * No point to wait here again if we always wait before calling this. - if (dir==TRX_RD && yieldTimeout(isBusyCMD13)) { - return sdError(SD_CARD_ERROR_CMD13); - } - */ - - /* - * Following RM 22.3.2. Setup DMA first, SDIO peripheral next - * - */ - flags = (DMA_MINC_MODE); - // not extra flag if read - if (dir!=TRX_RD) flags |= DMA_FROM_MEM;// write - dma_setup_transfer(SDIO_DMA_DEV, SDIO_DMA_CHANNEL, &SDIO->FIFO, DMA_SIZE_32BITS, buf, DMA_SIZE_32BITS, flags); - dma_set_num_transfers(SDIO_DMA_DEV, SDIO_DMA_CHANNEL, n>>2); // F1 DMA controller counts each word as 1 data item. - //dma_set_fifo_flags(SDIO_DMA_DEV, SDIO_DMA_CHANNEL, (DMA_FCR_DMDIS | DMA_FCR_FTH_FULL)); // disable direct mode | threshold FULL - dma_clear_isr_bits(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); - dma_enable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); - - return true; -} - - /*---------------------------------------------------------------------------*/ static bool dmaTrxEnd(bool multi_block) { - if(m_curState != READ_STATE){ - if ( yieldTimeout(isBusyTransferComplete) ) { - DBG_PRINT(); - if (m_dir==TRX_RD) - return sdError(SD_CARD_ERROR_READ_CRC); - else - return sdError(SD_CARD_ERROR_WRITE); - } - } - - if ( !yieldDmaStatus() ) { + if ( !waitDmaStatus() ) { DBG_PRINT(); return sdError(SD_CARD_ERROR_DMA); } - + if ( waitTimeout(isBusyTransferComplete) ) { + if (m_dir==TRX_RD) + return sdError(SD_CARD_ERROR_READ_TIMEOUT); + else + return sdError(SD_CARD_ERROR_WRITE_TIMEOUT); + } if (multi_block) { return trxStop(); } else { @@ -481,38 +389,21 @@ static bool readReg16(uint32_t xfertyp, void* data) /*---------------------------------------------------------------------------*/ // Return true if timeout occurs. static bool yieldTimeout(bool (*fcn)()) { - m_busyFcn = fcn; uint32_t m = millis(); while (fcn()) { if ((millis() - m) > BUSY_TIMEOUT_MILLIS) { - m_busyFcn = 0; return true; } yield(); } - m_busyFcn = 0; return false; // Caller will set errorCode. } /*---------------------------------------------------------------------------*/ -static bool yieldDmaStatus(void) -{ - if (yieldTimeout(isBusyDMA)) { - dma_disable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); - return false; // Caller will set errorCode. - } - // Did not time out. Disable it and return true. - dma_disable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); - return true; -} -/*---------------------------------------------------------------------------*/ static bool waitDmaStatus(void) { - if (waitTimeout(isBusyDMA)) { - dma_disable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); + if (yieldTimeout(isBusyDMA)) { return false; // Caller will set errorCode. } - // Did not time out. Disable it and return true - dma_disable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); return true; } /*---------------------------------------------------------------------------*/ @@ -532,8 +423,6 @@ uint32_t aligned[128]; // temporary buffer for misaligned buffers //============================================================================= bool SdioCard::begin(void) { - - uint32_t arg; m_initDone = false; m_errorCode = SD_CARD_ERROR_NONE; m_highCapacity = false; @@ -558,7 +447,6 @@ delay(100); if (!cardCommand(CMD0_XFERTYP, 0)) { return sdError(SD_CARD_ERROR_CMD0); } - delay(50); //small pause after reset command // Try several times for case of reset delay. for (uint32_t i = 0; i < CMD8_RETRIES; i++) { if (cardCommand(CMD8_XFERTYP, 0X1AA)) { @@ -569,7 +457,7 @@ delay(100); break; } } - arg = m_version2 ? 0X50300000 : 0x00300000; + uint32_t arg = m_version2 ? 0X40300000 : 0x00300000; uint32_t m = millis(); do { if (!cardAcmd(0, ACMD41_XFERTYP, arg) || @@ -590,7 +478,6 @@ delay(100); return sdError(SD_CARD_ERROR_CMD3); } m_rca = SDIO->RESP[0] & 0xFFFF0000; - if (!readReg16(CMD9_XFERTYP, &m_csd)) { return sdError(SD_CARD_ERROR_CMD9); } @@ -600,21 +487,14 @@ delay(100); if (!cardCommand(CMD7_XFERTYP, m_rca)) { return sdError(SD_CARD_ERROR_CMD7); } - - arg = 0x00; //bit 0, Connect[1]/Disconnect[0] the 50 KOhm pull-up resistor on CD/DAT3 - if (!cardAcmd(m_rca, ACMD42_XFERTYP, arg)) { - _panic("*** ACMD42 to disconnect D3 pullup failed! ***", 0); - } - // Set card to bus width four. + /* if (!cardAcmd(m_rca, ACMD6_XFERTYP, 2)) { return sdError(SD_CARD_ERROR_ACMD6); } - - // Set SDHC to bus width four. sdio_set_dbus_width(SDIO_CLKCR_WIDBUS_4BIT); + */ -/* // Determine if High Speed mode is supported and set frequency. uint8_t status[64]; // see "Physical Layer Simplified Specification Version 6.00", chapter 4.3.10, Table 4-13. @@ -622,16 +502,15 @@ delay(100); // Function Selection of Function Group 1: bits 379:376, which is low nibble of byte [16] if (cardCMD6(0X00FFFFFF, status) && (2 & status[13]) && cardCMD6(0X80FFFFF1, status) && (status[16] & 0XF) == 1) { - Serial.println("\n*** 50MHz clock supported ***"); - m_sdClkKhz = 24000; // set clock to 24MHz + //Serial.println("\n*** 50MHz clock supported ***"); } else { //_panic("*** Only 25MHz clock supported! ***", 0); - m_sdClkKhz = 8000; // set clock to 24MHz } - // delay seems to be needed for cards that take some time to adjust - delay(1); -*/ - m_sdClkKhz = 18000; // set clock to 24MHz + + /* + * Todo Raise clock to 24Mhz once transfers work + */ + m_sdClkKhz = 24000; // set clock to 24MHz sdio_set_clock(m_sdClkKhz*1000); m_initDone = true; @@ -691,160 +570,55 @@ uint32_t SdioCard::kHzSdClk() { return m_sdClkKhz; } /*---------------------------------------------------------------------------*/ -bool __attribute__((optimize("0"))) SdioCard::readBlock(uint32_t lba, uint8_t* buf) +bool SdioCard::readBlock(uint32_t lba, uint8_t* buf) { #if USE_DEBUG_MODE - Serial.print("readBlock: "); Serial.println(lba); //Serial.print(", buf: "); Serial.println((uint32_t)buf, HEX); + Serial.print("readBlock: "); Serial.println(lba); //Serial.print(", buf: "); Serial.println((uint32_t)buf, HEX); #endif - volatile bool _state = false; - volatile uint16_t retries = 3; - while ( retries-- ){ - /*if (yieldTimeout(isBusyCMD13)) { // wait for previous transmission end - return sdError(SD_CARD_ERROR_CMD13); - } - */ - - if (m_curState != READ_STATE || m_curLba != lba) { -#if USE_DEBUG_MODE - Serial.print("New lba, syncing :"); - Serial.println(lba); -#endif - _state = syncBlocks(); - DBG_PRINT(); - if (!_state) { - return false; - } - m_limitLba = (lba + 1024); //arbitrary limit, tested with 32KB before and worked fine. - // prepare DMA for data read transfer - _state = dmaTrxPrepare((uint32_t)buf & 3 ? (uint8_t*)aligned : buf, 512, TRX_RD); - DBG_PRINT(); - - // prepare SDIO data read transfer 0x8000 = 64*512 - _state = dmaTrxStart(512, TRX_RD); - DBG_PRINT(); - - // send command to start data transfer - _state = cardCommand(CMD18_XFERTYP, (m_highCapacity ? lba : 512*lba)); - DBG_PRINT(); - if ( !_state ) { - return sdError(SD_CARD_ERROR_CMD18); - } - - m_curLba = lba; - m_curState = READ_STATE; - } - else { - // prepare DMA for data read transfer - _state = dmaTrxPrepare((uint32_t)buf & 3 ? (uint8_t*)aligned : buf, 512, TRX_RD); - - // prepare SDIO data read transfer - _state = dmaTrxStart(512, TRX_RD); - } - - - _state = dmaTrxEnd(0); - - if ( _state ) { - if ( (uint32_t)buf & 3 ) { - //memcpy(buf, aligned, 512); - register uint8_t * dst = buf; - register uint8_t * src = (uint8_t *)aligned; - register uint16_t i = 64; - while ( i-- ) { // do 8 byte copies, is much faster than single byte copy - *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; - *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; - } - } - m_totalReadLbas++; - m_curLba++; - if (m_curLba >= m_limitLba) { - syncBlocks(); - } - sdError(SD_CARD_ERROR_NONE); - return true; - } - syncBlocks(); - m_readErrors++; - - } - DBG_PRINT() - syncBlocks(); - m_readErrors++; - return false; + // prepare SDIO and DMA for data read transfer + dmaTrxStart((uint32_t)buf & 3 ? (uint8_t*)aligned : buf, 512, TRX_RD); + // send command to start data transfer + if ( !cardCommand(CMD17_XFERTYP, (m_highCapacity ? lba : 512*lba)) ) { + return sdError(SD_CARD_ERROR_CMD17); + } + if ( dmaTrxEnd(0)) { + if ( (uint32_t)buf & 3 ) { + //memcpy(buf, aligned, 512); + register uint8_t * dst = buf; + register uint8_t * src = (uint8_t *)aligned; + register uint16_t i = 64; + while ( i-- ) { // do 8 byte copies, is much faster than single byte copy + *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; + *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; + } + } + return true; + } + return false; } /*---------------------------------------------------------------------------*/ bool SdioCard::readBlocks(uint32_t lba, uint8_t* buf, size_t n) { #if USE_DEBUG_MODE - Serial.print("readBlocks: "); Serial.print(lba); - //Serial.print(", buf: "); Serial.print((uint32_t)buf, HEX); - Serial.print(", "); Serial.println(n); + Serial.print("readBlocks: "); Serial.print(lba); + //Serial.print(", buf: "); Serial.print((uint32_t)buf, HEX); + Serial.print(", "); Serial.println(n); #endif - volatile bool _state = false; - volatile uint16_t retries = 3; - while ( retries-- ){ - - if ((uint32_t)buf & 3) { - for (size_t i = 0; i < n; i++, lba++, buf += 512) { - if (!readBlock(lba, buf)) { - return false; // readBlock will set errorCode. - } - } - return true; - } - - if (m_curState != READ_STATE || m_curLba != lba) { - #if USE_DEBUG_MODE - Serial.print("New lba, syncing :"); - Serial.println(lba); - #endif - _state = syncBlocks(); - DBG_PRINT(); - if (!_state) { - return false; - } - m_limitLba = (lba + 1024); //arbitrary limit - // prepare DMA for data read transfer - _state = dmaTrxPrepare(buf, 512*n, TRX_RD); - - // prepare SDIO for data read transfer - _state = dmaTrxStart(512*n, TRX_RD); - - // send command to start data transfer - _state = cardCommand(CMD18_XFERTYP, (m_highCapacity ? lba : 512*lba)); - if ( !_state ) { - return sdError(SD_CARD_ERROR_CMD18); - } - m_curLba = lba; - m_curState = READ_STATE; - } - - else { - // prepare DMA for data read transfer - _state = dmaTrxPrepare(buf, 512*n, TRX_RD); - - // prepare SDIO data read transfer - _state = dmaTrxStart(512*n, TRX_RD); - } - - _state = dmaTrxEnd(0); - - if (_state){ - m_totalReadLbas += n; - m_curLba += n; - if (m_curLba >= m_limitLba) { - syncBlocks(); - } - sdError(SD_CARD_ERROR_NONE); - return true; - } - syncBlocks(); - m_readErrors++; - } - DBG_PRINT() - syncBlocks(); - m_readErrors++; - return false; + if ((uint32_t)buf & 3) { + for (size_t i = 0; i < n; i++, lba++, buf += 512) { + if (!readBlock(lba, buf)) { + return false; // readBlock will set errorCode. + } + } + return true; + } + // prepare SDIO and DMA for data read transfer + dmaTrxStart(buf, 512*n, TRX_RD); + // send command to start data transfer + if ( !cardCommand(CMD18_XFERTYP, (m_highCapacity ? lba : 512*lba)) ) { + return sdError(SD_CARD_ERROR_CMD18); + } + return dmaTrxEnd(1); } //----------------------------------------------------------------------------- bool SdioCard::readCID(void* cid) { @@ -925,36 +699,13 @@ bool SdioCard::readStart(uint32_t lba, uint32_t count) /*---------------------------------------------------------------------------*/ bool SdioCard::readStop() { - - sdio_setup_transfer(0x00FFFFFF, 0, 0); - while ( SDIO->STA & SDIO_STA_RXDAVL) { - volatile uint32 _unused = SDIO->FIFO; - } //Serial.println("readStop."); - m_lba = 0; - if (!trxStop()) { - return false; - } - return true; + m_lba = 0; + m_cnt = 0; + return true; } //----------------------------------------------------------------------------- -inline bool SdioCard::syncBlocks() { - if ( isEnabledDMA()){ - waitDmaStatus(); - } - if (m_curState == READ_STATE) { - /* if ( isEnabledDMA()){ - waitDmaStatus(); - } - */ - m_curState = IDLE_STATE; - if (!readStop()) { - return false; - } - } else if (m_curState == WRITE_STATE) { - m_curState = IDLE_STATE; - return writeStop(); - } +bool SdioCard::syncBlocks() { return true; } //----------------------------------------------------------------------------- @@ -982,48 +733,17 @@ bool SdioCard::writeBlock(uint32_t lba, const uint8_t* buf) *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; } } - - - - if (m_curState != WRITE_STATE || m_curLba != lba) { - if (!syncBlocks()) { - return false; - } - - m_limitLba = (lba + 1024); //arbitrary limit - - // prepare DMA for data transfer - dmaTrxPrepare(ptr, 512, TRX_WR); // 1 block, write transfer - - // send command to start data transfer - if ( !cardCommand(CMD25_XFERTYP, (m_highCapacity ? lba : 512*lba)) ) { - return sdError(SD_CARD_ERROR_CMD25); - } - m_curLba = lba; - m_curState = WRITE_STATE; - + if (yieldTimeout(isBusyCMD13)) { // wait for previous transmission end + return sdError(SD_CARD_ERROR_CMD13); } - else { - if (yieldTimeout(isBusyCMD13)) { // wait for previous transmission end - return sdError(SD_CARD_ERROR_CMD13); - } - // prepare DMA for data transfer - dmaTrxPrepare(ptr, 512, TRX_WR); // 1 block, write transfer + // send command to start data transfer + if ( !cardCommand(CMD24_XFERTYP, (m_highCapacity ? lba : 512*lba)) ) { + return sdError(SD_CARD_ERROR_CMD24); } + // prepare SDIO and DMA for data transfer + dmaTrxStart(ptr, 512, TRX_WR); // 1 block, write transfer - // prepare SDIO for data transfer - dmaTrxStart(512, TRX_WR); // 1 block, write transfer - - if (!dmaTrxEnd(0)){ - m_curState = IDLE_STATE; - m_writeErrors++; - return false; - } - m_curLba++; - if (m_curLba >= m_limitLba) { - syncBlocks(); - } - return true; + return dmaTrxEnd(0); } /*---------------------------------------------------------------------------*/ bool SdioCard::writeBlocks(uint32_t lba, const uint8_t* buf, size_t n) @@ -1050,43 +770,14 @@ bool SdioCard::writeBlocks(uint32_t lba, const uint8_t* buf, size_t n) return sdError(SD_CARD_ERROR_ACMD23); } #endif + // send command to start data transfer + if ( !cardCommand(CMD25_XFERTYP, (m_highCapacity ? lba : 512*lba)) ) { + return sdError(SD_CARD_ERROR_CMD25); + } + // prepare SDIO and DMA for data transfer + dmaTrxStart((uint8_t *)buf, 512*n, TRX_WR); // n blocks, write transfer - if (m_curState != WRITE_STATE || m_curLba != lba) { - if (!syncBlocks()) { - return false; - } - - m_limitLba = (lba + 1024); //arbitrary limit, 512KB - // prepare DMA for data transfer - dmaTrxPrepare((uint8_t *)buf, 512*n, TRX_WR); // n blocks, write transfer - - // send command to start data transfer - if ( !cardCommand(CMD25_XFERTYP, (m_highCapacity ? lba : 512*lba)) ) { - return sdError(SD_CARD_ERROR_CMD25); - } - m_curLba = lba; - m_curState = WRITE_STATE; - - } - else { - // prepare DMA for data transfer - dmaTrxPrepare((uint8_t *)buf, 512*n, TRX_WR); // n blocks, write transfer - } - - // prepare SDIO for data transfer - dmaTrxStart(512*n, TRX_WR); // n blocks, write transfer - - if (!dmaTrxEnd(0)){ - m_writeErrors++; - m_curState = IDLE_STATE; - return false; - } - m_curLba += n; - if (m_curLba >= m_limitLba) { - syncBlocks(); - } - return true; - + return dmaTrxEnd(1); } /*---------------------------------------------------------------------------*/ bool SdioCard::writeData(const uint8_t* src) @@ -1154,14 +845,8 @@ bool SdioCard::writeStart(uint32_t lba, uint32_t count) /*---------------------------------------------------------------------------*/ bool SdioCard::writeStop() { - if ( isEnabledDMA()){ - if ( !waitDmaStatus() ) { - DBG_PRINT(); - return sdError(SD_CARD_ERROR_DMA); - } - } - m_lba = 0; - m_curState = IDLE_STATE; - return trxStop(); - //Serial.println("writeStop."); + //Serial.println("writeStop."); + m_lba = 0; + m_cnt = 0; + return true; } diff --git a/STM32F1/libraries/SDIO/SdioF1.h b/STM32F1/libraries/SDIO/SdioF1.h index efa4774..c995b1c 100644 --- a/STM32F1/libraries/SDIO/SdioF1.h +++ b/STM32F1/libraries/SDIO/SdioF1.h @@ -1,6 +1,6 @@ -#ifndef _SDIOF1_H_ -#define _SDIOF1_H_ +#ifndef _SDIOF4_H_ +#define _SDIOF4_H_ #include From d5399c3e0218f0334831f8f709aa72d1bf0fbb41 Mon Sep 17 00:00:00 2001 From: victorpv Date: Wed, 28 Mar 2018 22:27:50 -0500 Subject: [PATCH 304/351] Revert "Hardware serial corrections" This reverts commit 771be821c288f74f4106768aca0042d05c0d038d. --- STM32F1/cores/maple/HardwareSerial.cpp | 2 +- STM32F1/cores/maple/HardwareSerial.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/STM32F1/cores/maple/HardwareSerial.cpp b/STM32F1/cores/maple/HardwareSerial.cpp index fe73339..024efbc 100644 --- a/STM32F1/cores/maple/HardwareSerial.cpp +++ b/STM32F1/cores/maple/HardwareSerial.cpp @@ -187,7 +187,7 @@ int HardwareSerial::availableForWrite(void) return 1; } -size_t HardwareSerial::write(uint8_t ch) { +size_t HardwareSerial::write(unsigned char ch) { usart_putc(this->usart_device, ch); return 1; diff --git a/STM32F1/cores/maple/HardwareSerial.h b/STM32F1/cores/maple/HardwareSerial.h index 108d525..b8b8dd6 100644 --- a/STM32F1/cores/maple/HardwareSerial.h +++ b/STM32F1/cores/maple/HardwareSerial.h @@ -138,7 +138,7 @@ public: virtual int read(void); int availableForWrite(void); virtual void flush(void); - virtual size_t write(uint8_t ch); + virtual size_t write(uint8_t); inline size_t write(unsigned long n) { return write((uint8_t)n); } inline size_t write(long n) { return write((uint8_t)n); } inline size_t write(unsigned int n) { return write((uint8_t)n); } From 59a216ba66bdb389a64c04e80847eafc5507d887 Mon Sep 17 00:00:00 2001 From: victorpv Date: Thu, 29 Mar 2018 22:19:06 -0500 Subject: [PATCH 305/351] Help file describing the fft functions. --- .../libraries/stm_fft/stm32f10x_DSP_lib.chm | Bin 0 -> 887334 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 STM32F1/libraries/stm_fft/stm32f10x_DSP_lib.chm diff --git a/STM32F1/libraries/stm_fft/stm32f10x_DSP_lib.chm b/STM32F1/libraries/stm_fft/stm32f10x_DSP_lib.chm new file mode 100644 index 0000000000000000000000000000000000000000..a27742dfd65efe35d7d99cb0a9bdef81a102de3a GIT binary patch literal 887334 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 >KZE}cGdb@0&*TDS*bV-x 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
qv>~*xnNTqjd`{*BDg( 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%0Ao%!wQc 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�<2%+G;bt&M9J=a$cYF^Is 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

U@L0AG)9xSO;s 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

FnV& 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%0A(4Dn~w7&7|-8%3e-LF?HMIqbQM}@TIpptCN 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�VfE*%ERT(qH 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%0D-LhI{ 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 IdjQ~n0T&blmjD0& literal 0 HcmV?d00001 From f660163a6fa856fcfb246b35b8400d749c1f7840 Mon Sep 17 00:00:00 2001 From: edogaldo Date: Wed, 4 Apr 2018 16:04:42 +0200 Subject: [PATCH 306/351] Fix SCB_AIRCR_PRIGROUP As per Issue #479 --- STM32F1/system/libmaple/include/libmaple/scb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/system/libmaple/include/libmaple/scb.h b/STM32F1/system/libmaple/include/libmaple/scb.h index 0b01480..d58434c 100644 --- a/STM32F1/system/libmaple/include/libmaple/scb.h +++ b/STM32F1/system/libmaple/include/libmaple/scb.h @@ -122,7 +122,7 @@ typedef struct scb_reg_map { #define SCB_AIRCR_VECTKEYSTAT (0x5FA << 16) #define SCB_AIRCR_VECTKEY (0x5FA << 16) #define SCB_AIRCR_ENDIANNESS (1U << 15) -#define SCB_AIRCR_PRIGROUP (0x3 << 8) +#define SCB_AIRCR_PRIGROUP (0x7 << 8) #define SCB_AIRCR_SYSRESETREQ (1U << 2) #define SCB_AIRCR_VECTCLRACTIVE (1U << 1) #define SCB_AIRCR_VECTRESET (1U << 0) From 21bdc4ad135b6e6187ce85af0035c69358a78688 Mon Sep 17 00:00:00 2001 From: victorpv Date: Thu, 5 Apr 2018 21:54:05 -0500 Subject: [PATCH 307/351] Update to fix FSMC inclusion in Rx devices The FSMC is only available in high density and XL density devices with more than 4 ports. Basically excluded in the RC/D/E/F/G models, since they dont have enough pins. Page 11 in the Datasheet references this. The table shows what is present, and shows the FSMC is NOT present in Rx MCUs: http://www.st.com/content/ccc/resource/technical/document/datasheet/59/f6/fa/84/20/4e/4c/59/CD00191185.pdf/files/CD00191185.pdf/jcr:content/translations/en.CD00191185.pdf Recent changes to other files highlight this issue during compilation time. The issue was already there, but GPIO E and GPIO F were declared and defined, while they don't actually exist in Rx MCUs, so FSMC was being included for those MCU even though they don't actually have an FSMC device, or at least no external ports to use it. With the recent changes GPIO E and F and correctly excluded from the build, but since FSMC was still included and needs GPIO E and F, it was failing to compile. I.e.: C:/Users/Victor/Documents/Arduino/Hardware/Arduino_STM32/STM32F1/cores/maple/libmaple/fsmc_f1.c:51:19: error: 'GPIOE' undeclared (first use in this function) Since the FSMC is not available (I suspect the silicon is there, but there is no IO pins to use it), the correct solution is to include FSMC only when using an MCU with more than 4 GPIO ports, which is what matches the datasheet. --- STM32F1/system/libmaple/stm32f1/include/series/stm32.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/STM32F1/system/libmaple/stm32f1/include/series/stm32.h b/STM32F1/system/libmaple/stm32f1/include/series/stm32.h index 9386dc3..467d308 100644 --- a/STM32F1/system/libmaple/stm32f1/include/series/stm32.h +++ b/STM32F1/system/libmaple/stm32f1/include/series/stm32.h @@ -185,12 +185,16 @@ extern "C" { # elif defined(STM32_HIGH_DENSITY) # define STM32_NR_INTERRUPTS 60 # define STM32_TIMER_MASK 0x1FE /* TIMER1--TIMER8 */ -# define STM32_HAVE_FSMC 1 +# if STM32_NR_GPIO_PORTS > 4 +# define STM32_HAVE_FSMC 1 +# endif # define STM32_HAVE_DAC 1 # elif defined(STM32_XL_DENSITY) # define STM32_NR_INTERRUPTS 60 # define STM32_TIMER_MASK 0x7FFE /* TIMER1--TIMER14 */ -# define STM32_HAVE_FSMC 1 +# if STM32_NR_GPIO_PORTS > 4 +# define STM32_HAVE_FSMC 1 +# endif # define STM32_HAVE_DAC 1 # endif From ef2f5b53d7dff51ac3d9ec34769b8b8b395dc2bd Mon Sep 17 00:00:00 2001 From: victorpv Date: Thu, 5 Apr 2018 22:04:28 -0500 Subject: [PATCH 308/351] Need to define STM32_HAVE_FSMC as 0 Forgot to include that. --- STM32F1/system/libmaple/stm32f1/include/series/stm32.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/STM32F1/system/libmaple/stm32f1/include/series/stm32.h b/STM32F1/system/libmaple/stm32f1/include/series/stm32.h index 467d308..1346885 100644 --- a/STM32F1/system/libmaple/stm32f1/include/series/stm32.h +++ b/STM32F1/system/libmaple/stm32f1/include/series/stm32.h @@ -187,6 +187,8 @@ extern "C" { # define STM32_TIMER_MASK 0x1FE /* TIMER1--TIMER8 */ # if STM32_NR_GPIO_PORTS > 4 # define STM32_HAVE_FSMC 1 +# else +# define STM32_HAVE_FSMC 0 # endif # define STM32_HAVE_DAC 1 # elif defined(STM32_XL_DENSITY) @@ -194,6 +196,8 @@ extern "C" { # define STM32_TIMER_MASK 0x7FFE /* TIMER1--TIMER14 */ # if STM32_NR_GPIO_PORTS > 4 # define STM32_HAVE_FSMC 1 +# else +# define STM32_HAVE_FSMC 0 # endif # define STM32_HAVE_DAC 1 # endif From 307a0e2472b0e9869f4e7ca22712c861a9c1c031 Mon Sep 17 00:00:00 2001 From: Laurent Haas - F6FVY Date: Mon, 9 Apr 2018 19:16:56 +0200 Subject: [PATCH 309/351] Frequency unit typo (was Mhz instead of MHz) --- STM32F1/boards.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/STM32F1/boards.txt b/STM32F1/boards.txt index 75d4562..84ce01d 100644 --- a/STM32F1/boards.txt +++ b/STM32F1/boards.txt @@ -38,13 +38,13 @@ mapleMini.menu.bootloader_version.bootloader20.upload.maximum_data_size=20480 mapleMini.menu.bootloader_version.bootloader20.upload.altID=2 #-- CPU Clock frequency -mapleMini.menu.cpu_speed.speed_72mhz=72Mhz (Normal) +mapleMini.menu.cpu_speed.speed_72mhz=72MHz (Normal) mapleMini.menu.cpu_speed.speed_72mhz.build.f_cpu=72000000L -mapleMini.menu.cpu_speed.speed_48mhz=48Mhz (Slow - with USB) +mapleMini.menu.cpu_speed.speed_48mhz=48MHz (Slow - with USB) mapleMini.menu.cpu_speed.speed_48mhz.build.f_cpu=48000000L -mapleMini.menu.cpu_speed.speed_128mhz=Overclocked 128Mhz NO USB SERIAL. MANUAL RESET NEEDED TO UPLOAD +mapleMini.menu.cpu_speed.speed_128mhz=Overclocked 128MHz NO USB SERIAL. MANUAL RESET NEEDED TO UPLOAD mapleMini.menu.cpu_speed.speed_128mhz.build.f_cpu=128000000L #-- Optimizations From 463db9b0bfa891ae905c747e8e7040e54ca4599f Mon Sep 17 00:00:00 2001 From: Ken Willmott Date: Tue, 10 Apr 2018 09:55:04 -0400 Subject: [PATCH 310/351] fix PR #487 Implements the needed correction in PR #487, modifies get method with no change to set method. Exor comparison changed to equality comparison for readability. --- STM32F1/libraries/RTClock/src/utility/rtc_util.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/STM32F1/libraries/RTClock/src/utility/rtc_util.c b/STM32F1/libraries/RTClock/src/utility/rtc_util.c index c730ba1..3a49e42 100644 --- a/STM32F1/libraries/RTClock/src/utility/rtc_util.c +++ b/STM32F1/libraries/RTClock/src/utility/rtc_util.c @@ -168,8 +168,10 @@ uint32 rtc_get_count() { rtc_clear_sync(); rtc_wait_sync(); rtc_wait_finished(); + do { h = RTC->regs->CNTH & 0xffff; l = RTC->regs->CNTL & 0xffff; + } while (h != (RTC->regs->CNTH & 0xffff)); return (h << 16) | l; } @@ -182,10 +184,8 @@ void rtc_set_count(uint32 value) { rtc_wait_sync(); rtc_wait_finished(); rtc_enter_config_mode(); - do { h = RTC->regs->CNTH & 0xffff; l = RTC->regs->CNTL & 0xffff; - } while (h ^ (RTC->regs->CNTH & 0xffff)); rtc_exit_config_mode(); rtc_wait_finished(); } @@ -216,7 +216,7 @@ uint32 rtc_get_divider() { do { h = RTC->regs->DIVH & 0x000f; l = RTC->regs->DIVL & 0xffff; - } while (h ^ (RTC->regs->DIVH & 0x000f)); + } while (h != (RTC->regs->DIVH & 0x000f)); return (h << 16) | l; } From 7374108bd434a7421939977b83e3d9d7de3e5c7a Mon Sep 17 00:00:00 2001 From: Ken Willmott Date: Tue, 10 Apr 2018 10:37:26 -0400 Subject: [PATCH 311/351] fix PR#487 and #488 --- STM32F1/libraries/RTClock/src/utility/rtc_util.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/STM32F1/libraries/RTClock/src/utility/rtc_util.c b/STM32F1/libraries/RTClock/src/utility/rtc_util.c index 3a49e42..3d7a262 100644 --- a/STM32F1/libraries/RTClock/src/utility/rtc_util.c +++ b/STM32F1/libraries/RTClock/src/utility/rtc_util.c @@ -169,8 +169,8 @@ uint32 rtc_get_count() { rtc_wait_sync(); rtc_wait_finished(); do { - h = RTC->regs->CNTH & 0xffff; - l = RTC->regs->CNTL & 0xffff; + h = RTC->regs->CNTH & 0xffff; + l = RTC->regs->CNTL & 0xffff; } while (h != (RTC->regs->CNTH & 0xffff)); return (h << 16) | l; } @@ -184,8 +184,8 @@ void rtc_set_count(uint32 value) { rtc_wait_sync(); rtc_wait_finished(); rtc_enter_config_mode(); - h = RTC->regs->CNTH & 0xffff; - l = RTC->regs->CNTL & 0xffff; + RTC->regs->CNTH = (value >> 16) & 0xffff; + RTC->regs->CNTL = value & 0xffff; rtc_exit_config_mode(); rtc_wait_finished(); } From 407df21dfba5474255d7a4e06ffe2574cec561c2 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Thu, 12 Apr 2018 08:29:49 +0200 Subject: [PATCH 312/351] Update timer.h fix for https://github.com/rogerclarkmelbourne/Arduino_STM32/commit/dfb5bd4c30f42fa9cf2a0aef6b7d2a50a594fa97, see issue #412 [https://github.com/rogerclarkmelbourne/Arduino_STM32/issues/412] --- STM32F1/system/libmaple/include/libmaple/timer.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/STM32F1/system/libmaple/include/libmaple/timer.h b/STM32F1/system/libmaple/include/libmaple/timer.h index 76c4165..e9a49e9 100644 --- a/STM32F1/system/libmaple/include/libmaple/timer.h +++ b/STM32F1/system/libmaple/include/libmaple/timer.h @@ -842,7 +842,9 @@ static inline void timer_dma_disable_req(timer_dev *dev, uint8 channel) { * @see timer_channel */ static inline void timer_enable_irq(timer_dev *dev, uint8 interrupt) { - *bb_perip(&(dev->regs).adv->SR, interrupt) = 0; // clear interrupt flag + // clear interrupt flag, use different masks for reserved bits + dev->regs->SR = (~BIT(interrupt)) & ( (dev->type==TIMER_ADVANCED) ? 0x1EFF : + ( (dev->type==TIMER_GENERAL) ? 0x1E5F : 0x0001) ); *bb_perip(&(dev->regs).adv->DIER, interrupt) = 1; } From c9a694b779a0c328ea37a402c804ab7bae7a6c85 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Thu, 12 Apr 2018 17:59:03 +1000 Subject: [PATCH 313/351] Revert #491 --- STM32F1/system/libmaple/include/libmaple/timer.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/STM32F1/system/libmaple/include/libmaple/timer.h b/STM32F1/system/libmaple/include/libmaple/timer.h index e9a49e9..0c2e027 100644 --- a/STM32F1/system/libmaple/include/libmaple/timer.h +++ b/STM32F1/system/libmaple/include/libmaple/timer.h @@ -843,8 +843,7 @@ static inline void timer_dma_disable_req(timer_dev *dev, uint8 channel) { */ static inline void timer_enable_irq(timer_dev *dev, uint8 interrupt) { // clear interrupt flag, use different masks for reserved bits - dev->regs->SR = (~BIT(interrupt)) & ( (dev->type==TIMER_ADVANCED) ? 0x1EFF : - ( (dev->type==TIMER_GENERAL) ? 0x1E5F : 0x0001) ); + *bb_perip(&(dev->regs).adv->SR, interrupt) = 0; // clear interrupt flag *bb_perip(&(dev->regs).adv->DIER, interrupt) = 1; } From f56c37e97e03333a539d9f9b5ca51df994121506 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Thu, 12 Apr 2018 18:17:45 +1000 Subject: [PATCH 314/351] Fix for https://github.com/rogerclarkmelbourne/Arduino_STM32/issues/486 --- STM32F1/cores/maple/Print.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/STM32F1/cores/maple/Print.cpp b/STM32F1/cores/maple/Print.cpp index 0a71cf0..a8aa07d 100644 --- a/STM32F1/cores/maple/Print.cpp +++ b/STM32F1/cores/maple/Print.cpp @@ -47,12 +47,8 @@ */ size_t Print::write(const char *str) { - size_t n = 0; - while (*str) { - write(*str++); - n++; - } - return n; + if (str == NULL) return 0; + return write((const uint8_t *)str, strlen(str)); } size_t Print::write(const void *buffer, uint32 size) { From 18d1654195c30c3a2ab913574f487c94f3967ffc Mon Sep 17 00:00:00 2001 From: arpruss Date: Thu, 12 Apr 2018 20:45:59 -0500 Subject: [PATCH 315/351] usbcomposite library --- STM32F1/libraries/USBComposite/AbsMouse.cpp | 56 ++ .../libraries/USBComposite/BootKeyboard.cpp | 7 + STM32F1/libraries/USBComposite/Consumer.cpp | 13 + STM32F1/libraries/USBComposite/HIDReports.cpp | 14 + STM32F1/libraries/USBComposite/Joystick.cpp | 118 ++++ STM32F1/libraries/USBComposite/Keyboard.cpp | 258 ++++++++ STM32F1/libraries/USBComposite/LICENSE | 45 ++ STM32F1/libraries/USBComposite/MidiSpecs.h | 151 +++++ STM32F1/libraries/USBComposite/MinSysex.c | 306 +++++++++ STM32F1/libraries/USBComposite/MinSysex.h | 37 ++ STM32F1/libraries/USBComposite/Mouse.cpp | 57 ++ STM32F1/libraries/USBComposite/README.md | 88 +++ .../libraries/USBComposite/USBComposite.cpp | 147 +++++ STM32F1/libraries/USBComposite/USBComposite.h | 64 ++ .../USBComposite/USBCompositeSerial.cpp | 274 ++++++++ .../USBComposite/USBCompositeSerial.h | 40 ++ STM32F1/libraries/USBComposite/USBHID.cpp | 180 ++++++ STM32F1/libraries/USBComposite/USBHID.h | 608 ++++++++++++++++++ STM32F1/libraries/USBComposite/USBMIDI.cpp | 469 ++++++++++++++ STM32F1/libraries/USBComposite/USBMIDI.h | 186 ++++++ .../libraries/USBComposite/USBMassStorage.cpp | 45 ++ .../libraries/USBComposite/USBMassStorage.h | 25 + STM32F1/libraries/USBComposite/USBXBox360.cpp | 173 +++++ STM32F1/libraries/USBComposite/USBXBox360.h | 58 ++ .../examples/BootKeyboard/BootKeyboard.ino | 15 + .../examples/absmouse/absmouse.ino | 25 + .../examples/consumer/consumer.ino | 18 + .../keyboardwithleds/keyboardwithleds.ino | 14 + .../USBComposite/examples/mass/image.h | 67 ++ .../USBComposite/examples/mass/mass.ino | 65 ++ .../USBComposite/examples/midiin/midiin.ino | 27 + .../USBComposite/examples/midiout/midiout.ino | 17 + .../USBComposite/examples/rawhid/rawhid.ino | 24 + .../USBComposite/examples/rawhid/send.py | 26 + .../examples/sdreader/sdreader.ino | 52 ++ .../simplejoystick/simplejoystick.ino | 13 + .../simplekeyboard/simplekeyboard.ino | 13 + .../examples/softjoystick/send.py | 60 ++ .../examples/softjoystick/softjoystick.ino | 47 ++ .../examples/twojoysticks/twojoysticks.ino | 40 ++ .../USBComposite/examples/x360/x360.ino | 15 + STM32F1/libraries/USBComposite/keywords.txt | 89 +++ .../libraries/USBComposite/library.properties | 10 + STM32F1/libraries/USBComposite/usb_generic.c | 531 +++++++++++++++ STM32F1/libraries/USBComposite/usb_generic.h | 60 ++ STM32F1/libraries/USBComposite/usb_hid.c | 578 +++++++++++++++++ STM32F1/libraries/USBComposite/usb_hid.h | 153 +++++ STM32F1/libraries/USBComposite/usb_mass.c | 464 +++++++++++++ STM32F1/libraries/USBComposite/usb_mass.h | 112 ++++ .../USBComposite/usb_mass_internal.h | 12 + STM32F1/libraries/USBComposite/usb_mass_mal.c | 42 ++ STM32F1/libraries/USBComposite/usb_mass_mal.h | 39 ++ .../libraries/USBComposite/usb_midi_device.c | 532 +++++++++++++++ .../libraries/USBComposite/usb_midi_device.h | 189 ++++++ STM32F1/libraries/USBComposite/usb_scsi.c | 333 ++++++++++ STM32F1/libraries/USBComposite/usb_scsi.h | 96 +++ .../libraries/USBComposite/usb_scsi_data.c | 120 ++++ STM32F1/libraries/USBComposite/usb_serial.c | 580 +++++++++++++++++ STM32F1/libraries/USBComposite/usb_serial.h | 157 +++++ STM32F1/libraries/USBComposite/usb_setup.cpp | 61 ++ STM32F1/libraries/USBComposite/usb_x360.c | 486 ++++++++++++++ STM32F1/libraries/USBComposite/usb_x360.h | 75 +++ 62 files changed, 8676 insertions(+) create mode 100644 STM32F1/libraries/USBComposite/AbsMouse.cpp create mode 100644 STM32F1/libraries/USBComposite/BootKeyboard.cpp create mode 100644 STM32F1/libraries/USBComposite/Consumer.cpp create mode 100644 STM32F1/libraries/USBComposite/HIDReports.cpp create mode 100644 STM32F1/libraries/USBComposite/Joystick.cpp create mode 100644 STM32F1/libraries/USBComposite/Keyboard.cpp create mode 100644 STM32F1/libraries/USBComposite/LICENSE create mode 100644 STM32F1/libraries/USBComposite/MidiSpecs.h create mode 100644 STM32F1/libraries/USBComposite/MinSysex.c create mode 100644 STM32F1/libraries/USBComposite/MinSysex.h create mode 100644 STM32F1/libraries/USBComposite/Mouse.cpp create mode 100644 STM32F1/libraries/USBComposite/README.md create mode 100644 STM32F1/libraries/USBComposite/USBComposite.cpp create mode 100644 STM32F1/libraries/USBComposite/USBComposite.h create mode 100644 STM32F1/libraries/USBComposite/USBCompositeSerial.cpp create mode 100644 STM32F1/libraries/USBComposite/USBCompositeSerial.h create mode 100644 STM32F1/libraries/USBComposite/USBHID.cpp create mode 100644 STM32F1/libraries/USBComposite/USBHID.h create mode 100644 STM32F1/libraries/USBComposite/USBMIDI.cpp create mode 100644 STM32F1/libraries/USBComposite/USBMIDI.h create mode 100644 STM32F1/libraries/USBComposite/USBMassStorage.cpp create mode 100644 STM32F1/libraries/USBComposite/USBMassStorage.h create mode 100644 STM32F1/libraries/USBComposite/USBXBox360.cpp create mode 100644 STM32F1/libraries/USBComposite/USBXBox360.h create mode 100644 STM32F1/libraries/USBComposite/examples/BootKeyboard/BootKeyboard.ino create mode 100644 STM32F1/libraries/USBComposite/examples/absmouse/absmouse.ino create mode 100644 STM32F1/libraries/USBComposite/examples/consumer/consumer.ino create mode 100644 STM32F1/libraries/USBComposite/examples/keyboardwithleds/keyboardwithleds.ino create mode 100644 STM32F1/libraries/USBComposite/examples/mass/image.h create mode 100644 STM32F1/libraries/USBComposite/examples/mass/mass.ino create mode 100644 STM32F1/libraries/USBComposite/examples/midiin/midiin.ino create mode 100644 STM32F1/libraries/USBComposite/examples/midiout/midiout.ino create mode 100644 STM32F1/libraries/USBComposite/examples/rawhid/rawhid.ino create mode 100644 STM32F1/libraries/USBComposite/examples/rawhid/send.py create mode 100644 STM32F1/libraries/USBComposite/examples/sdreader/sdreader.ino create mode 100644 STM32F1/libraries/USBComposite/examples/simplejoystick/simplejoystick.ino create mode 100644 STM32F1/libraries/USBComposite/examples/simplekeyboard/simplekeyboard.ino create mode 100644 STM32F1/libraries/USBComposite/examples/softjoystick/send.py create mode 100644 STM32F1/libraries/USBComposite/examples/softjoystick/softjoystick.ino create mode 100644 STM32F1/libraries/USBComposite/examples/twojoysticks/twojoysticks.ino create mode 100644 STM32F1/libraries/USBComposite/examples/x360/x360.ino create mode 100644 STM32F1/libraries/USBComposite/keywords.txt create mode 100644 STM32F1/libraries/USBComposite/library.properties create mode 100644 STM32F1/libraries/USBComposite/usb_generic.c create mode 100644 STM32F1/libraries/USBComposite/usb_generic.h create mode 100644 STM32F1/libraries/USBComposite/usb_hid.c create mode 100644 STM32F1/libraries/USBComposite/usb_hid.h create mode 100644 STM32F1/libraries/USBComposite/usb_mass.c create mode 100644 STM32F1/libraries/USBComposite/usb_mass.h create mode 100644 STM32F1/libraries/USBComposite/usb_mass_internal.h create mode 100644 STM32F1/libraries/USBComposite/usb_mass_mal.c create mode 100644 STM32F1/libraries/USBComposite/usb_mass_mal.h create mode 100644 STM32F1/libraries/USBComposite/usb_midi_device.c create mode 100644 STM32F1/libraries/USBComposite/usb_midi_device.h create mode 100644 STM32F1/libraries/USBComposite/usb_scsi.c create mode 100644 STM32F1/libraries/USBComposite/usb_scsi.h create mode 100644 STM32F1/libraries/USBComposite/usb_scsi_data.c create mode 100644 STM32F1/libraries/USBComposite/usb_serial.c create mode 100644 STM32F1/libraries/USBComposite/usb_serial.h create mode 100644 STM32F1/libraries/USBComposite/usb_setup.cpp create mode 100644 STM32F1/libraries/USBComposite/usb_x360.c create mode 100644 STM32F1/libraries/USBComposite/usb_x360.h diff --git a/STM32F1/libraries/USBComposite/AbsMouse.cpp b/STM32F1/libraries/USBComposite/AbsMouse.cpp new file mode 100644 index 0000000..91a27d0 --- /dev/null +++ b/STM32F1/libraries/USBComposite/AbsMouse.cpp @@ -0,0 +1,56 @@ +#include "USBHID.h" + +//================================================================================ +//================================================================================ +// Mouse + +void HIDAbsMouse::begin(void){ +} + +void HIDAbsMouse::end(void){ +} + +void HIDAbsMouse::click(uint8_t b) +{ + report.wheel = 0; + report.buttons = b; + sendReport(); + report.buttons = 0; + sendReport(); +} + +void HIDAbsMouse::move(int16 x, int16 y, int8 wheel) +{ + report.x = x; + report.y = y; + report.wheel = wheel; + + sendReport(); +} + +void HIDAbsMouse::buttons(uint8_t b) +{ + if (b != report.buttons) + { + report.wheel = 0; + report.buttons = b; + sendReport(); + } +} + +void HIDAbsMouse::press(uint8_t b) +{ + buttons(report.buttons | b); +} + +void HIDAbsMouse::release(uint8_t b) +{ + buttons(report.buttons & ~b); +} + +bool HIDAbsMouse::isPressed(uint8_t b) +{ + if ((b & report.buttons) != 0) + return true; + return false; +} diff --git a/STM32F1/libraries/USBComposite/BootKeyboard.cpp b/STM32F1/libraries/USBComposite/BootKeyboard.cpp new file mode 100644 index 0000000..195f4ac --- /dev/null +++ b/STM32F1/libraries/USBComposite/BootKeyboard.cpp @@ -0,0 +1,7 @@ +#include "USBHID.h" + +//================================================================================ +//================================================================================ +// Keyboard + +HIDKeyboard BootKeyboard(0); diff --git a/STM32F1/libraries/USBComposite/Consumer.cpp b/STM32F1/libraries/USBComposite/Consumer.cpp new file mode 100644 index 0000000..6c896b0 --- /dev/null +++ b/STM32F1/libraries/USBComposite/Consumer.cpp @@ -0,0 +1,13 @@ +#include "USBHID.h" + +void HIDConsumer::begin(void) {} +void HIDConsumer::end(void) {} +void HIDConsumer::press(uint16_t button) { + report.button = button; + sendReport(); +} + +void HIDConsumer::release() { + report.button = 0; + sendReport(); +} diff --git a/STM32F1/libraries/USBComposite/HIDReports.cpp b/STM32F1/libraries/USBComposite/HIDReports.cpp new file mode 100644 index 0000000..bd00b54 --- /dev/null +++ b/STM32F1/libraries/USBComposite/HIDReports.cpp @@ -0,0 +1,14 @@ +#include "USBHID.h" + +#define REPORT(name, ...) \ + static uint8_t raw_ ## name[] = { __VA_ARGS__ }; \ + static const HIDReportDescriptor desc_ ## name = { raw_ ##name, sizeof(raw_ ##name) }; \ + const HIDReportDescriptor* hidReport ## name = & desc_ ## name; + +REPORT(KeyboardMouseJoystick, HID_MOUSE_REPORT_DESCRIPTOR(), HID_KEYBOARD_REPORT_DESCRIPTOR(), HID_JOYSTICK_REPORT_DESCRIPTOR()); +REPORT(KeyboardMouse, HID_MOUSE_REPORT_DESCRIPTOR(), HID_KEYBOARD_REPORT_DESCRIPTOR()); +REPORT(Keyboard, HID_KEYBOARD_REPORT_DESCRIPTOR()); +REPORT(Mouse, HID_MOUSE_REPORT_DESCRIPTOR()); +REPORT(KeyboardJoystick, HID_KEYBOARD_REPORT_DESCRIPTOR(), HID_JOYSTICK_REPORT_DESCRIPTOR()); +REPORT(Joystick, HID_JOYSTICK_REPORT_DESCRIPTOR()); +REPORT(BootKeyboard, HID_BOOT_KEYBOARD_REPORT_DESCRIPTOR()); diff --git a/STM32F1/libraries/USBComposite/Joystick.cpp b/STM32F1/libraries/USBComposite/Joystick.cpp new file mode 100644 index 0000000..969cac5 --- /dev/null +++ b/STM32F1/libraries/USBComposite/Joystick.cpp @@ -0,0 +1,118 @@ +#include "USBHID.h" + +// This code requires gcc on low-endian devices. + +//================================================================================ +//================================================================================ +// Joystick + +void HIDJoystick::begin(void){ +} + +void HIDJoystick::end(void){ +} + +void HIDJoystick::setManualReportMode(bool mode) { + manualReport = mode; +} + +bool HIDJoystick::getManualReportMode() { + return manualReport; +} + +void HIDJoystick::safeSendReport() { + if (!manualReport) { + sendReport(); + } +} + +void HIDJoystick::button(uint8_t button, bool val){ + uint32_t mask = ((uint32_t)1 << (button-1)); + + if (val) { + joyReport.buttons |= mask; + } else { + joyReport.buttons &= ~mask; + } + + safeSendReport(); +} + +void HIDJoystick::X(uint16_t val){ + if (val > 1023) val = 1023; + joyReport.x = val; + + safeSendReport(); +} + +void HIDJoystick::Y(uint16_t val){ + if (val > 1023) val = 1023; + joyReport.y = val; + + safeSendReport(); +} + +void HIDJoystick::position(uint16_t x, uint16_t y){ + if (x > 1023) x = 1023; + if (y > 1023) y = 1023; + joyReport.x = x; + joyReport.y = y; + + safeSendReport(); +} + +void HIDJoystick::Xrotate(uint16_t val){ + if (val > 1023) val = 1023; + joyReport.rx = val; + + safeSendReport(); +} + +void HIDJoystick::Yrotate(uint16_t val){ + if (val > 1023) val = 1023; + joyReport.ry = val; + + safeSendReport(); +} + +void HIDJoystick::sliderLeft(uint16_t val){ + if (val > 1023) val = 1023; + joyReport.sliderLeft = val; + + safeSendReport(); +} + +void HIDJoystick::sliderRight(uint16_t val){ + if (val > 1023) val = 1023; + joyReport.sliderRight = val; + + safeSendReport(); +} + +void HIDJoystick::slider(uint16_t val){ + if (val > 1023) val = 1023; + joyReport.sliderLeft = val; + joyReport.sliderRight = val; + + safeSendReport(); +} + +void HIDJoystick::hat(int16_t dir){ + uint8_t val; + if (dir < 0) val = 15; + else if (dir < 23) val = 0; + else if (dir < 68) val = 1; + else if (dir < 113) val = 2; + else if (dir < 158) val = 3; + else if (dir < 203) val = 4; + else if (dir < 245) val = 5; + else if (dir < 293) val = 6; + else if (dir < 338) val = 7; + else val = 15; + + joyReport.hat = val; + + safeSendReport(); +} + +HIDJoystick Joystick; diff --git a/STM32F1/libraries/USBComposite/Keyboard.cpp b/STM32F1/libraries/USBComposite/Keyboard.cpp new file mode 100644 index 0000000..a658cc5 --- /dev/null +++ b/STM32F1/libraries/USBComposite/Keyboard.cpp @@ -0,0 +1,258 @@ +#include "USBHID.h" +#include + +//================================================================================ +//================================================================================ +// Keyboard + +#define SHIFT 0x80 +static const uint8_t ascii_to_hid[128] = +{ + 0x00, // NUL + 0x00, // SOH + 0x00, // STX + 0x00, // ETX + 0x00, // EOT + 0x00, // ENQ + 0x00, // ACK + 0x00, // BEL + 0x2a, // BS Backspace + 0x2b, // TAB Tab + 0x28, // LF Enter + 0x00, // VT + 0x00, // FF + 0x00, // CR + 0x00, // SO + 0x00, // SI + 0x00, // DEL + 0x00, // DC1 + 0x00, // DC2 + 0x00, // DC3 + 0x00, // DC4 + 0x00, // NAK + 0x00, // SYN + 0x00, // ETB + 0x00, // CAN + 0x00, // EM + 0x00, // SUB + 0x00, // ESC + 0x00, // FS + 0x00, // GS + 0x00, // RS + 0x00, // US + + 0x2c, // ' ' + 0x1e|SHIFT, // ! + 0x34|SHIFT, // " + 0x20|SHIFT, // # + 0x21|SHIFT, // $ + 0x22|SHIFT, // % + 0x24|SHIFT, // & + 0x34, // ' + 0x26|SHIFT, // ( + 0x27|SHIFT, // ) + 0x25|SHIFT, // * + 0x2e|SHIFT, // + + 0x36, // , + 0x2d, // - + 0x37, // . + 0x38, // / + 0x27, // 0 + 0x1e, // 1 + 0x1f, // 2 + 0x20, // 3 + 0x21, // 4 + 0x22, // 5 + 0x23, // 6 + 0x24, // 7 + 0x25, // 8 + 0x26, // 9 + 0x33|SHIFT, // : + 0x33, // ; + 0x36|SHIFT, // < + 0x2e, // = + 0x37|SHIFT, // > + 0x38|SHIFT, // ? + 0x1f|SHIFT, // @ + 0x04|SHIFT, // A + 0x05|SHIFT, // B + 0x06|SHIFT, // C + 0x07|SHIFT, // D + 0x08|SHIFT, // E + 0x09|SHIFT, // F + 0x0a|SHIFT, // G + 0x0b|SHIFT, // H + 0x0c|SHIFT, // I + 0x0d|SHIFT, // J + 0x0e|SHIFT, // K + 0x0f|SHIFT, // L + 0x10|SHIFT, // M + 0x11|SHIFT, // N + 0x12|SHIFT, // O + 0x13|SHIFT, // P + 0x14|SHIFT, // Q + 0x15|SHIFT, // R + 0x16|SHIFT, // S + 0x17|SHIFT, // T + 0x18|SHIFT, // U + 0x19|SHIFT, // V + 0x1a|SHIFT, // W + 0x1b|SHIFT, // X + 0x1c|SHIFT, // Y + 0x1d|SHIFT, // Z + 0x2f, // [ + 0x31, // bslash + 0x30, // ] + 0x23|SHIFT, // ^ + 0x2d|SHIFT, // _ + 0x35, // ` + 0x04, // a + 0x05, // b + 0x06, // c + 0x07, // d + 0x08, // e + 0x09, // f + 0x0a, // g + 0x0b, // h + 0x0c, // i + 0x0d, // j + 0x0e, // k + 0x0f, // l + 0x10, // m + 0x11, // n + 0x12, // o + 0x13, // p + 0x14, // q + 0x15, // r + 0x16, // s + 0x17, // t + 0x18, // u + 0x19, // v + 0x1a, // w + 0x1b, // x + 0x1c, // y + 0x1d, // z + 0x2f|SHIFT, // + 0x31|SHIFT, // | + 0x30|SHIFT, // } + 0x35|SHIFT, // ~ + 0 // DEL +}; + +void HIDKeyboard::begin(void){ + USBHID.addOutputBuffer(&ledData); +} + +void HIDKeyboard::end(void) { +} + +// 136: non-printing key +// shift -> 0x02 +// modifiers: 128 --> bit shift + +uint8_t HIDKeyboard::getKeyCode(uint8_t k, uint8_t* modifiersP) +{ + *modifiersP = 0; + + if (adjustForHostCapsLock && (getLEDs() & 0x02)) { // capslock is down on host OS, so host will reverse + if ('a' <= k && k <= 'z') + k += 'A'-'a'; + else if ('A' <= k && k <= 'Z') + k += 'a'-'A'; + } + + if (k < 0x80) { + k = ascii_to_hid[k]; + if (k & SHIFT) { + k &= 0x7f; + *modifiersP = 0x02; + } + return k; + } + if (k >= 0x88) { // non-printing key, Arduino format + return k - 0x88; + } + else { // shift key + *modifiersP = 1<<(k-0x80); + return 0; + } +} + +size_t HIDKeyboard::press(uint8_t k) { + uint8_t modifiers; + + k = getKeyCode(k, &modifiers); + + if (k == 0) { + if (modifiers == 0) { + return 0; + } + } + else { + for (unsigned i = 0; i. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + \ No newline at end of file diff --git a/STM32F1/libraries/USBComposite/MidiSpecs.h b/STM32F1/libraries/USBComposite/MidiSpecs.h new file mode 100644 index 0000000..6d2acbe --- /dev/null +++ b/STM32F1/libraries/USBComposite/MidiSpecs.h @@ -0,0 +1,151 @@ +/*--------------------------------------------------------------------------MidiSpecs.h + * + * These defines are based on specs created by the USB and MMA standards organizations. + * There are not a lot of other ways to code them so licensing this is rather ludicrous. + * However, in order to be able to embed this in client projects, and avoid the stupidity + * of enforced open everything I will declare the following about this file. + * + * Copyright (c) 2011 Donald Delmar Davis, Suspect Devices + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the "Software"), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +/* + * USB midi commands from + * MIDI10.pdf "Universal Serial Bus Device Class Definition for MIDI Devices" + * REV 1. (1999) + * http://www.usb.org/developers/devclass_docs/midi10.pdf + * + */ + +#ifndef __LETS_MIDI_SPECS_H__ +#define __LETS_MIDI_SPECS_H__ +#include +#include +// rework this for the different architectures.... +#if defined(__GNUC__) +typedef struct +{ + unsigned cin : 4; // this is the low nibble. + unsigned cable : 4; +// uint8_t cin; + uint8_t midi0; + uint8_t midi1; + uint8_t midi2; +} __attribute__ ((__packed__)) MIDI_EVENT_PACKET_t ; +#else +typedef struct // may need to be adjusted for other compilers and bitfield order... +{ + unsigned cable : 4; + unsigned cin : 4; + uint8_t midi0; + uint8_t midi1; + uint8_t midi2; +} MIDI_EVENT_PACKET_t ; +#endif + + +#define CIN_MISC_FUNCTION 0x00 /* Reserved for future extension. */ +#define CIN_CABLE_EVENT 0x01 /* Reserved for future extension. */ +#define CIN_2BYTE_SYS_COMMON 0x02 /* 2Bytes -- MTC, SongSelect, etc. */ +#define CIN_3BYTE_SYS_COMMON 0x03 /* 3Bytes -- SPP, etc. */ +#define CIN_SYSEX 0x04 /* 3Bytes */ +#define CIN_SYSEX_ENDS_IN_1 0x05 /* 1Bytes */ +#define CIN_SYSEX_ENDS_IN_2 0x06 /* 2Bytes */ +#define CIN_SYSEX_ENDS_IN_3 0x07 /* 3Bytes */ +#define CIN_NOTE_OFF 0x08 /* 3Bytes */ +#define CIN_NOTE_ON 0x09 /* 3Bytes */ +#define CIN_AFTER_TOUCH 0x0A /* 3Bytes */ +#define CIN_CONTROL_CHANGE 0x0B /* 3Bytes */ +#define CIN_PROGRAM_CHANGE 0x0C /* 2Bytes */ +#define CIN_CHANNEL_PRESSURE 0x0D /* 2Bytes */ +#define CIN_PITCH_WHEEL 0x0E /* 3Bytes */ +#define CIN_1BYTE 0x0F /* 1Bytes */ +//#define CIN_IS_SYSEX(cin) ((cin == CIN_SYSEX)||(cin == CIN_SYSEX_ENDS_IN_1)||(cin == CIN_SYSEX_ENDS_IN_2)||(cin == CIN_SYSEX_ENDS_IN_3)) +#define CIN_IS_SYSEX(cin) ( ((cin) & ~(0x08)) && ((cin) &0x04) ) + +/* + * MIDI V1 message definitions these are from the MMA document + * http://www.midi.org/techspecs/midimessages.php + */ +#define MIDIv1_BAUD_RATE 31250 + +/* + * parse midi (v1) message macros + */ +#define MIDIv1_IS_STATUS(b) ((b) & 0x80) +#define MIDIv1_IS_VOICE(b) ((b) <= 0xEF) +#define MIDIv1_VOICE_COMMAND(b) ((b) & 0xF0) +#define MIDIv1_VOICE_CHANNEL(b) ((b) & 0x0F) +#define MIDIv1_IS_SYSCOMMON(b) (((b) >= 0xF0) & ((b) < 0xF8)) +#define MIDIv1_IS_REALTIME(b) ((b) >= 0xF8) + +/* + * Voice category messages + */ +#define MIDIv1_NOTE_OFF 0x80 /* 2 bytes data -- CIN_NOTE_OFF */ +#define MIDIv1_NOTE_ON 0x90 /* 2 bytes data -- CIN_NOTE_ON */ +#define MIDIv1_AFTER_TOUCH 0xA0 /* 2 bytes data -- CIN_AFTER_TOUCH */ +#define MIDIv1_CONTROL_CHANGE 0xB0 /* 2 bytes data -- CIN_CONTROL_CHANGE */ +#define MIDIv1_PROGRAM_CHANGE 0xC0 /* 1 byte data -- CIN_PROGRAM_CHANGE */ +#define MIDIv1_CHANNEL_PRESSURE 0xD0 /* 1 byte data -- CIN_CHANNEL_PRESSURE */ +#define MIDIv1_PITCH_WHEEL 0xE0 /* 2 bytes data -- CIN_PITCH_WHEEL */ + +/* + * System common category messages + */ +#define MIDIv1_SYSEX_START 0xF0 +#define MIDIv1_SYSEX_END 0xF7 +#define MIDIv1_MTC_QUARTER_FRAME 0xF1 /* 1 byte data -- CIN_2BYTE_SYS_COMMON */ +#define MIDIv1_SONG_POSITION_PTR 0xF2 /* 2 bytes data -- CIN_3BYTE_SYS_COMMON */ +#define MIDIv1_SONG_SELECT 0xF3 /* 1 byte data -- CIN_2BYTE_SYS_COMMON */ +#define MIDIv1_TUNE_REQUEST 0xF6 /* no data -- CIN_1BYTE */ + +/* + * Realtime category messages, can be sent anytime + */ +#define MIDIv1_CLOCK 0xF8 /* no data -- CIN_1BYTE */ +#define MIDIv1_TICK 0xF9 /* no data -- CIN_1BYTE */ +#define MIDIv1_START 0xFA /* no data -- CIN_1BYTE */ +#define MIDIv1_CONTINUE 0xFB /* no data -- CIN_1BYTE */ +#define MIDIv1_STOP 0xFC /* no data -- CIN_1BYTE */ +#define MIDIv1_ACTIVE_SENSE 0xFE /* no data -- CIN_1BYTE */ +#define MIDIv1_RESET 0xFF /* no data -- CIN_1BYTE */ + +/* + * sysex universal id's + */ +#define MIDIv1_UNIVERSAL_REALTIME_ID 0x7F +#define MIDIv1_UNIVERSAL_NON_REALTIME_ID 0x7E +#define MIDIv1_UNIVERSAL_ALL_CHANNELS 0x7F +/* + * Susbset of universal sysex (general info request) + * As described http://www.blitter.com/~russtopia/MIDI/~jglatt/tech/midispec.htm + */ +#define USYSEX_NON_REAL_TIME 0x7E +#define USYSEX_REAL_TIME 0x7F +#define USYSEX_ALL_CHANNELS 0x7F +#define USYSEX_GENERAL_INFO 0x06 +#define USYSEX_GI_ID_REQUEST 0x01 +#define USYSEX_GI_ID_RESPONSE 0x02 + + +#endif + + diff --git a/STM32F1/libraries/USBComposite/MinSysex.c b/STM32F1/libraries/USBComposite/MinSysex.c new file mode 100644 index 0000000..f9a54d3 --- /dev/null +++ b/STM32F1/libraries/USBComposite/MinSysex.c @@ -0,0 +1,306 @@ +// +// MinSysex.c +// LibMaple4Midi +// +// Created by Donald D Davis on 4/11/13. +// Copyright (c) 2013 Suspect Devices. All rights reserved. +// Modified BSD Liscense +/* + 0xF0 SysEx + 0x7E Non-Realtime + 0x7F The SysEx channel. Could be from 0x00 to 0x7F. + Here we set it to "disregard channel". + 0x06 Sub-ID -- General Information + 0x01 Sub-ID2 -- Identity Request + 0xF7 End of SysEx +---- response + 0xF0 SysEx + 0x7E Non-Realtime + 0x7F The SysEx channel. Could be from 0x00 to 0x7F. + Here we set it to "disregard channel". + 0x06 Sub-ID -- General Information + 0x02 Sub-ID2 -- Identity Reply + 0xID Manufacturer's ID + 0xf1 The f1 and f2 bytes make up the family code. Each + 0xf2 manufacturer assigns different family codes to his products. + 0xp1 The p1 and p2 bytes make up the model number. Each + 0xp2 manufacturer assigns different model numbers to his products. + 0xv1 The v1, v2, v3 and v4 bytes make up the version number. + 0xv2 + 0xv3 + 0xv4 + 0xF7 End of SysEx +*/ + +#define USB_MIDI +#ifdef USB_MIDI + +// change this to packets +#define STANDARD_ID_RESPONSE_LENGTH 7 + +#include "usb_midi_device.h" +#include +#include +#include +//#include + + +#define MAX_SYSEX_SIZE 256 + +/********************************* ACHTUNG! ignores usbmidi cable ********************************/ +/*const MIDI_EVENT_PACKET_t standardIDResponse[]={ + { DEFAULT_MIDI_CABLE, + CIN_SYSEX, + MIDIv1_SYSEX_START, + USYSEX_NON_REAL_TIME, + USYSEX_ALL_CHANNELS}, + { DEFAULT_MIDI_CABLE, + CIN_SYSEX, + USYSEX_GENERAL_INFO, + USYSEX_GI_ID_RESPONSE, + LEAFLABS_MMA_VENDOR_1}, + { DEFAULT_MIDI_CABLE, + CIN_SYSEX, + LEAFLABS_MMA_VENDOR_2, // extended ID + LEAFLABS_MMA_VENDOR_3, // extended ID + 1}, // family #1 + { DEFAULT_MIDI_CABLE, + CIN_SYSEX, + 2, // family #2 + 1, // part #1 + 2}, // part #2 + { DEFAULT_MIDI_CABLE, + CIN_SYSEX, + 0, // version 1 + 0, // version 2 + 1}, // version 3 + { DEFAULT_MIDI_CABLE, + CIN_SYSEX_ENDS_IN_2, + '!', // lgl compatible + MIDIv1_SYSEX_END, + 0} +}; +*/ +const uint8 standardIDResponse[]={ + CIN_SYSEX, + MIDIv1_SYSEX_START, + USYSEX_NON_REAL_TIME, + USYSEX_ALL_CHANNELS, + CIN_SYSEX, + USYSEX_GENERAL_INFO, + USYSEX_GI_ID_RESPONSE, + LEAFLABS_MMA_VENDOR_1, + CIN_SYSEX, + LEAFLABS_MMA_VENDOR_2, // extended ID + LEAFLABS_MMA_VENDOR_3, // extended ID + 1, // family #1 + CIN_SYSEX, + 2, // family #2 + 1, // part #1 + 2, // part #2 + CIN_SYSEX, + 0, // version 1 + 0, // version 2 + 1, // version 3 + CIN_SYSEX_ENDS_IN_2, + '!', // lgl compatible + MIDIv1_SYSEX_END, + 0 +}; +//#define STANDARD_ID_RESPONSE_LENGTH (sizeof(standardIDResponse)) + +typedef enum {NOT_IN_SYSEX=0,COULD_BE_MY_SYSEX,YUP_ITS_MY_SYSEX,ITS_NOT_MY_SYSEX} sysexStates; +volatile uint8 sysexBuffer[MAX_SYSEX_SIZE]; +volatile sysexStates sysexState; +volatile int sysexFinger=0; + +/* + 0xF0 SysEx + 0x?? LEAFLABS_MMA_VENDOR_1 + 0x?? LEAFLABS_MMA_VENDOR_2 + + 0x?? LEAFLABS_MMA_VENDOR_3 + 0x10 LGL_DEVICE_NUMBER + 0xLE CMD: REBOOT + + 0xf7 EOSysEx +*/ +#define STACK_TOP 0x20000800 +#define EXC_RETURN 0xFFFFFFF9 +#define DEFAULT_CPSR 0x61000000 +#define RESET_DELAY 100000 +#if 0 +static void wait_reset(void) { + delay_us(RESET_DELAY); + nvic_sys_reset(); +} +#endif + +/* -----------------------------------------------------------------------------dealWithItQuickly() + * Note: at this point we have established that the sysex belongs to us. + * So we need to respond to any generic requests like information requests. + * We also need to handle requests which are meant for us. At the moment this is just the + * reset request. + * + */ +void dealWithItQuickly(){ + switch (sysexBuffer[1]) { + case USYSEX_NON_REAL_TIME: + switch (sysexBuffer[3]) { + case USYSEX_GENERAL_INFO: + if (sysexBuffer[4]==USYSEX_GI_ID_REQUEST) { + usb_midi_tx((uint32 *) standardIDResponse, STANDARD_ID_RESPONSE_LENGTH); + } + } + case USYSEX_REAL_TIME: + break; +#if 0 + case LEAFLABS_MMA_VENDOR_1: + if (sysexBuffer[5]==LGL_RESET_CMD) { + uintptr_t target = (uintptr_t)wait_reset | 0x1; + asm volatile("mov r0, %[stack_top] \n\t" // Reset stack + "mov sp, r0 \n\t" + "mov r0, #1 \n\t" + "mov r1, %[target_addr] \n\t" + "mov r2, %[cpsr] \n\t" + "push {r2} \n\t" // Fake xPSR + "push {r1} \n\t" // PC target addr + "push {r0} \n\t" // Fake LR + "push {r0} \n\t" // Fake R12 + "push {r0} \n\t" // Fake R3 + "push {r0} \n\t" // Fake R2 + "push {r0} \n\t" // Fake R1 + "push {r0} \n\t" // Fake R0 + "mov lr, %[exc_return] \n\t" + "bx lr" + : + : [stack_top] "r" (STACK_TOP), + [target_addr] "r" (target), + [exc_return] "r" (EXC_RETURN), + [cpsr] "r" (DEFAULT_CPSR) + : "r0", "r1", "r2"); + /* Can't happen. */ + ASSERT_FAULT(0); + + } +#endif + default: + break; + } + ;//turn the led on? +} + +/* -----------------------------------------------------------------------------LglSysexHandler() + * The idea here is to identify which Sysex's belong to us and deal with them. + */ +void LglSysexHandler(uint32 *midiBufferRx, uint32 *rx_offset, uint32 *n_unread_packets) { + MIDI_EVENT_PACKET_t * midiPackets = (MIDI_EVENT_PACKET_t *) (midiBufferRx+(*rx_offset)); + uint8 nPackets=((*n_unread_packets)-(*rx_offset)); + int cPacket; + uint8 soPackets=0; + /********************************* ACHTUNG! ignores usbmidi cable ********************************/ + MIDI_EVENT_PACKET_t *packet; + for (cPacket=0;cPacketcin)) { + continue; + } // else { + if (!soPackets) { + soPackets=cPacket*4; + } + if ((sysexState==YUP_ITS_MY_SYSEX) && ((sysexFinger+3)>=MAX_SYSEX_SIZE)){ + sysexState=ITS_NOT_MY_SYSEX; //eisenhower policy. Even if its mine I cant deal with it. + } + switch (packet->cin) { + case CIN_SYSEX: + switch (sysexState) { + case NOT_IN_SYSEX : // new sysex. + sysexFinger=0; + if (packet->midi0 == MIDIv1_SYSEX_START) { + if (packet->midi1==USYSEX_REAL_TIME + ||packet->midi1==USYSEX_NON_REAL_TIME) { + if ((packet->midi2==myMidiChannel) + ||(packet->midi2==USYSEX_ALL_CHANNELS) + ) { + sysexState=YUP_ITS_MY_SYSEX; + sysexBuffer[sysexFinger++]=MIDIv1_SYSEX_START; + sysexBuffer[sysexFinger++]=packet->midi1; + sysexBuffer[sysexFinger++]=packet->midi2; + break; + } + } else if ((packet->midi1==myMidiID[0]) + && (packet->midi2==myMidiID[1]) + ){ + sysexState=COULD_BE_MY_SYSEX; + sysexBuffer[sysexFinger++]=MIDIv1_SYSEX_START; + sysexBuffer[sysexFinger++]=packet->midi1; + sysexBuffer[sysexFinger++]=packet->midi2; + break; + } + } + break; + + case COULD_BE_MY_SYSEX: + if (packet->midi0==myMidiID[2]) { + sysexState=YUP_ITS_MY_SYSEX; + sysexBuffer[sysexFinger++]=packet->midi0; + sysexBuffer[sysexFinger++]=packet->midi1; + sysexBuffer[sysexFinger++]=packet->midi2; + } else { + sysexState=ITS_NOT_MY_SYSEX; + sysexFinger=0; + } + break; + default: + break; + + } + + break; + case CIN_SYSEX_ENDS_IN_1: + case CIN_SYSEX_ENDS_IN_2: + case CIN_SYSEX_ENDS_IN_3: + sysexBuffer[sysexFinger++]=packet->midi0; + sysexBuffer[sysexFinger++]=packet->midi1; + sysexBuffer[sysexFinger++]=packet->midi2; + if (sysexState==YUP_ITS_MY_SYSEX) { + if(cPacket>=(int32)(*n_unread_packets)){ + *n_unread_packets = soPackets; + *rx_offset = soPackets; + } else { + uint8 c = cPacket; + uint32 *s; + uint32 *d = midiBufferRx + soPackets; + for (s = midiBufferRx+c; + ((*n_unread_packets) && (s <= midiBufferRx+(USB_MIDI_RX_EPSIZE/4))); + d++,s++ + ) { + (*d)=(*s); + (*n_unread_packets)--; + (*rx_offset)++; + + } + // we need to reset the for loop variables to re process remaining data. + nPackets=((*n_unread_packets)-(*rx_offset)); + cPacket=(*rx_offset); + } + dealWithItQuickly(); + + } + sysexFinger=0; + sysexState=NOT_IN_SYSEX; + + break; + default: + return; + } + //} + + + + } + // its our sysex and we will cry if we want to + return; +} + +#endif diff --git a/STM32F1/libraries/USBComposite/MinSysex.h b/STM32F1/libraries/USBComposite/MinSysex.h new file mode 100644 index 0000000..958eded --- /dev/null +++ b/STM32F1/libraries/USBComposite/MinSysex.h @@ -0,0 +1,37 @@ +// +// lgl_min_sysex.h +// LibMaple4Midi +// +// Created by Donald D Davis on 4/11/13. +// Copyright (c) 2013 Suspect Devices. All rights reserved. +// + +#ifndef __LGL_MIN_SYSEX_H__ +#define __LGL_MIN_SYSEX_H__ 1 + + +#include "MidiSpecs.h" +//#include "LGL.h" + +#define LEAFLABS_MMA_VENDOR_1 0x7D +#define LEAFLABS_MMA_VENDOR_2 0x1E +#define LEAFLABS_MMA_VENDOR_3 0x4F + +// move to LGL.h +#define LGL_RESET_CMD 0x1e + +#define DEFAULT_MIDI_CHANNEL 0x0A +#define DEFAULT_MIDI_DEVICE 0x0A +#define DEFAULT_MIDI_CABLE 0x00 + +// eventually all of this should be in a place for settings which can be written to flash. +extern volatile uint8 myMidiChannel; +extern volatile uint8 myMidiDevice; +extern volatile uint8 myMidiCable; +extern volatile uint8 myMidiID[]; + + +void LglSysexHandler(uint32 *midiBufferRx,uint32 *rx_offset,uint32 *n_unread_bytes); + +#endif + diff --git a/STM32F1/libraries/USBComposite/Mouse.cpp b/STM32F1/libraries/USBComposite/Mouse.cpp new file mode 100644 index 0000000..2f3abb9 --- /dev/null +++ b/STM32F1/libraries/USBComposite/Mouse.cpp @@ -0,0 +1,57 @@ +#include "USBHID.h" + +//================================================================================ +//================================================================================ +// Mouse + +void HIDMouse::begin(void){ +} + +void HIDMouse::end(void){ +} + +void HIDMouse::click(uint8_t b) +{ + _buttons = b; + move(0,0,0); + _buttons = 0; + move(0,0,0); +} + +void HIDMouse::move(signed char x, signed char y, signed char wheel) +{ + reportBuffer[1] = _buttons; + reportBuffer[2] = x; + reportBuffer[3] = y; + reportBuffer[4] = wheel; + + sendReport(); +} + +void HIDMouse::buttons(uint8_t b) +{ + if (b != _buttons) + { + _buttons = b; + move(0,0,0); + } +} + +void HIDMouse::press(uint8_t b) +{ + buttons(_buttons | b); +} + +void HIDMouse::release(uint8_t b) +{ + buttons(_buttons & ~b); +} + +bool HIDMouse::isPressed(uint8_t b) +{ + if ((b & _buttons) > 0) + return true; + return false; +} + +HIDMouse Mouse; diff --git a/STM32F1/libraries/USBComposite/README.md b/STM32F1/libraries/USBComposite/README.md new file mode 100644 index 0000000..8c80c13 --- /dev/null +++ b/STM32F1/libraries/USBComposite/README.md @@ -0,0 +1,88 @@ +# USB Composite library for STM32F1 + +## Protocols supported + +- standard USB HID, with many built-in profiles, and customizable with more + +- MIDI over USB + +- XBox360 controller (only controller-to-host is currently supported) + +- Mass storage + +## Basic concepts + +Start with: +``` +#include +``` + +The library defines several crucial objects. The central object is: + +``` +extern USBCompositeDevice USBComposite; +``` + +This controls USB device identification as well as registers the plugins that are connected to it. + +Plugin objects included in the library are: + +``` +extern USBHIDDevice USBHID; +extern USBMidi USBMIDI; +extern USBXBox360 XBox360; +extern USBMassStorageDevice MassStorage; +extern USBCompositeSerial CompositeSerial; +``` + +You can also create your own customized instances of these plugin classes or their subclasses. + +If you want to make a simple (non-composite) USB device, you can just call the plugin's `begin()` +method, and it will take care of registering itself with `USBComposite` and starting up +`USBComposite`. If you want to make a composite USB device, however, +you need to control the device with `USBComposite`: + +``` +USBComposite.clear(); // clear any plugins previously registered +plugin1.registerComponent(); +plugin2.registerComponent(); +USBComposite.begin(); +``` + +Of course, you may need to do some further configuring of the plugins or the `USBComposite` device +before the `USBComposite.begin()` call. + +Finally, there are a number of objects that implement particular protocols for the `USBHID` plugin: +``` +extern HIDMouse Mouse; +extern HIDKeyboard Keyboard; +extern HIDJoystick Joystick; +extern HIDKeyboard BootKeyboard; +``` +And you can customize with more. Moreover, the `USBHID` plugin itself allows for compositing +multiple HID profiles, e.g., Mouse / Keyboard / three joysticks. + +Not all combinations will fit within the constraints of the STM32F1 USB system, and not all +combinations will be supported by all operating systems. + +## Simple USB device configuration + +A simple USB device uses a single plugin. You just need to call any setup methods for the plugin +and the `begin()` method for the plugin. For instance, to inject keyboard data, you can do: + +``` +USBHID.begin(HID_KEYBOARD); +``` + +and then call `Keyboard.print("TextToInject")` to inject keyboard data. Some plugin configurations +may require further initialization code or further code that needs to be called inside the Arduino +`loop()` function. + +See the `BootKeyboard`, `midiout` and `x360` example code for this procedure. + +Additionally, for backwards compatibility reasons, the `USBHID` plugin has a convenience +`USBHID_begin_with_serial()` function which works just like `USBHID.begin()` except that it also +composites a `CompositeSerial` plugin. + +However, if you want a USB device using more than one plugin, then you will NOT call the plugin's +`begin()` method. \ No newline at end of file diff --git a/STM32F1/libraries/USBComposite/USBComposite.cpp b/STM32F1/libraries/USBComposite/USBComposite.cpp new file mode 100644 index 0000000..b659f11 --- /dev/null +++ b/STM32F1/libraries/USBComposite/USBComposite.cpp @@ -0,0 +1,147 @@ +#include "USBComposite.h" + +#define DEFAULT_VENDOR_ID 0x1EAF +#define DEFAULT_PRODUCT_ID 0x0004 + +static char* putSerialNumber(char* out, int nibbles, uint32 id) { + for (int i=0; i>= 4) { + uint8 nibble = id & 0xF; + if (nibble <= 9) + *out++ = nibble + '0'; + else + *out++ = nibble - 10 + 'a'; + } + return out; +} + +const char* getDeviceIDString() { + static char string[80/4+1]; + char* p = string; + + uint32 id = (uint32) *(uint16*) (0x1FFFF7E8+0x02); + p = putSerialNumber(p, 4, id); + + id = *(uint32*) (0x1FFFF7E8+0x04); + p = putSerialNumber(p, 8, id); + + id = *(uint32*) (0x1FFFF7E8+0x08); + p = putSerialNumber(p, 8, id); + + *p = 0; + + return string; +} + +USBCompositeDevice::USBCompositeDevice(void) { + vendorId = 0; + productId = 0; + numParts = 0; + setManufacturerString(NULL); + setProductString(NULL); + setSerialString(DEFAULT_SERIAL_STRING); + iManufacturer[0] = 0; + iProduct[0] = 0; + iSerialNumber[0] = 0; + } + +void USBCompositeDevice::setVendorId(uint16 _vendorId) { + if (_vendorId != 0) + vendorId = _vendorId; + else + vendorId = DEFAULT_VENDOR_ID; +} + +void USBCompositeDevice::setProductId(uint16 _productId) { + if (_productId != 0) + productId = _productId; + else + productId = DEFAULT_PRODUCT_ID; +} + +void setString(uint8* out, const usb_descriptor_string* defaultDescriptor, const char* s, uint32 maxLength) { + if (s == NULL) { + uint8 n = defaultDescriptor->bLength; + uint8 m = USB_DESCRIPTOR_STRING_LEN(maxLength); + if (n > m) + n = m; + memcpy(out, defaultDescriptor, n); + out[0] = n; + } + else { + uint32 n = strlen(s); + if (n > maxLength) + n = maxLength; + out[0] = (uint8)USB_DESCRIPTOR_STRING_LEN(n); + out[1] = USB_DESCRIPTOR_TYPE_STRING; + for (uint32 i=0; i= USB_COMPOSITE_MAX_PARTS) + return false; + parts[i] = part; + init[i] = _init; + stop[i] = _stop; + plugin[i] = _plugin; + if (i >= numParts) + numParts++; + return true; +} + +USBCompositeDevice USBComposite; diff --git a/STM32F1/libraries/USBComposite/USBComposite.h b/STM32F1/libraries/USBComposite/USBComposite.h new file mode 100644 index 0000000..152c3c3 --- /dev/null +++ b/STM32F1/libraries/USBComposite/USBComposite.h @@ -0,0 +1,64 @@ +#ifndef _USBCOMPOSITE_H_ +#define _USBCOMPOSITE_H_ + +#include +#include "Stream.h" +#include "usb_generic.h" +//#include + +#include +#include +#include +#include + +#define USB_MAX_PRODUCT_LENGTH 32 +#define USB_MAX_MANUFACTURER_LENGTH 32 +#define USB_MAX_SERIAL_NUMBER_LENGTH 20 + + +// You could use this for a serial number, but you'll be revealing the device ID to the host, +// and hence burning it for cryptographic purposes. +const char* getDeviceIDString(); + +#define USB_COMPOSITE_MAX_PARTS 6 + +class USBCompositeDevice; + +#define DEFAULT_SERIAL_STRING "00000000000000000001" + +typedef bool(*USBPartInitializer)(void*); +typedef void(*USBPartStopper)(void*); + +class USBCompositeDevice { +private: + bool enabled = false; + bool haveSerialNumber = false; + uint8_t iManufacturer[USB_DESCRIPTOR_STRING_LEN(USB_MAX_MANUFACTURER_LENGTH)]; + uint8_t iProduct[USB_DESCRIPTOR_STRING_LEN(USB_MAX_PRODUCT_LENGTH)]; + uint8_t iSerialNumber[USB_DESCRIPTOR_STRING_LEN(USB_MAX_SERIAL_NUMBER_LENGTH)]; + uint16 vendorId; + uint16 productId; + USBCompositePart* parts[USB_COMPOSITE_MAX_PARTS]; + USBPartInitializer init[USB_COMPOSITE_MAX_PARTS]; + USBPartStopper stop[USB_COMPOSITE_MAX_PARTS]; + void* plugin[USB_COMPOSITE_MAX_PARTS]; + uint32 numParts; +public: + USBCompositeDevice(void); + void setVendorId(uint16 vendor=0); + void setProductId(uint16 product=0); + void setManufacturerString(const char* manufacturer=NULL); + void setProductString(const char* product=NULL); + void setSerialString(const char* serialNumber=DEFAULT_SERIAL_STRING); + bool begin(void); + void end(void); + void clear(); + bool isReady() { + return enabled && usb_is_connected(USBLIB) && usb_is_configured(USBLIB); + } + bool add(USBCompositePart* part, void* plugin, USBPartInitializer init = NULL, USBPartStopper stop = NULL); +}; + +extern USBCompositeDevice USBComposite; +#endif + \ No newline at end of file diff --git a/STM32F1/libraries/USBComposite/USBCompositeSerial.cpp b/STM32F1/libraries/USBComposite/USBCompositeSerial.cpp new file mode 100644 index 0000000..9da0f19 --- /dev/null +++ b/STM32F1/libraries/USBComposite/USBCompositeSerial.cpp @@ -0,0 +1,274 @@ +/* Copyright (c) 2011, Peter Barrett +** +** Permission to use, copy, modify, and/or distribute this software for +** any purpose with or without fee is hereby granted, provided that the +** above copyright notice and this permission notice appear in all copies. +** +** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR +** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES +** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +** SOFTWARE. +*/ + +#include + +#include +#include +#include +#include +#include +#include + +#include "usb_serial.h" + +#define USB_TIMEOUT 50 + +#if defined(SERIAL_USB) +static void rxHook(unsigned, void*); +static void ifaceSetupHook(unsigned, void*); +#endif + +bool USBCompositeSerial::init(USBCompositeSerial* me) { + (void)me; +#if defined(SERIAL_USB) + composite_cdcacm_set_hooks(USBHID_CDCACM_HOOK_RX, rxHook); + composite_cdcacm_set_hooks(USBHID_CDCACM_HOOK_IFACE_SETUP, ifaceSetupHook); +#endif + return true; +} + +void USBCompositeSerial::begin(long speed) { + (void)speed; + if (!enabled) { + USBComposite.clear(); + registerComponent(); + USBComposite.begin(); + enabled = true; + } +} + +void USBCompositeSerial::end() { + if (enabled) { + USBComposite.end(); + enabled = false; + } +} + +size_t USBCompositeSerial::write(uint8 ch) { +size_t n = 0; + this->write(&ch, 1); + return n; +} + +size_t USBCompositeSerial::write(const char *str) { +size_t n = 0; + this->write((const uint8*)str, strlen(str)); + return n; +} + +size_t USBCompositeSerial::write(const uint8 *buf, uint32 len) +{ + size_t n = 0; + + if (!this->isConnected() || !buf) { + return 0; + } + + uint32 txed = 0; + while (txed < len) { + txed += composite_cdcacm_tx((const uint8*)buf + txed, len - txed); + } + + return n; +} + +int USBCompositeSerial::available(void) { + return composite_cdcacm_data_available(); +} + +int USBCompositeSerial::peek(void) +{ + uint8 b; + if (composite_cdcacm_peek(&b, 1)==1) + { + return b; + } + else + { + return -1; + } +} + +bool USBCompositeSerial::registerComponent() { + return USBComposite.add(&usbSerialPart, this, (USBPartInitializer)&USBCompositeSerial::init); +} + +void USBCompositeSerial::flush(void) +{ +/*Roger Clark. Rather slow method. Need to improve this */ + uint8 b; + while(composite_cdcacm_data_available()) + { + this->read(&b, 1); + } + return; +} + +uint32 USBCompositeSerial::read(uint8 * buf, uint32 len) { + uint32 rxed = 0; + while (rxed < len) { + rxed += composite_cdcacm_rx(buf + rxed, len - rxed); + } + + return rxed; +} + +/* Blocks forever until 1 byte is received */ +int USBCompositeSerial::read(void) { + uint8 b; + /* + this->read(&b, 1); + return b; + */ + + if (composite_cdcacm_rx(&b, 1)==0) + { + return -1; + } + else + { + return b; + } +} + +uint8 USBCompositeSerial::pending(void) { + return composite_cdcacm_get_pending(); +} + +uint8 USBCompositeSerial::isConnected(void) { + return usb_is_connected(USBLIB) && usb_is_configured(USBLIB) && composite_cdcacm_get_dtr(); +} + +uint8 USBCompositeSerial::getDTR(void) { + return composite_cdcacm_get_dtr(); +} + +uint8 USBCompositeSerial::getRTS(void) { + return composite_cdcacm_get_rts(); +} + +#if defined(SERIAL_USB) + +enum reset_state_t { + DTR_UNSET, + DTR_HIGH, + DTR_NEGEDGE, + DTR_LOW +}; + +static reset_state_t reset_state = DTR_UNSET; + +static void ifaceSetupHook(unsigned hook, void *requestvp) { + (void)hook; + uint8 request = *(uint8*)requestvp; + + // Ignore requests we're not interested in. + if (request != USBHID_CDCACM_SET_CONTROL_LINE_STATE) { + return; + } + + // We need to see a negative edge on DTR before we start looking + // for the in-band magic reset byte sequence. + uint8 dtr = composite_cdcacm_get_dtr(); + switch (reset_state) { + case DTR_UNSET: + reset_state = dtr ? DTR_HIGH : DTR_LOW; + break; + case DTR_HIGH: + reset_state = dtr ? DTR_HIGH : DTR_NEGEDGE; + break; + case DTR_NEGEDGE: + reset_state = dtr ? DTR_HIGH : DTR_LOW; + break; + case DTR_LOW: + reset_state = dtr ? DTR_HIGH : DTR_LOW; + break; + } + + if ((composite_cdcacm_get_baud() == 1200) && (reset_state == DTR_NEGEDGE)) { + iwdg_init(IWDG_PRE_4, 10); + while (1); + } +} + +#define RESET_DELAY 100000 +static void wait_reset(void) { + delay_us(RESET_DELAY); + nvic_sys_reset(); +} + +#define STACK_TOP 0x20000800 +#define EXC_RETURN 0xFFFFFFF9 +#define DEFAULT_CPSR 0x61000000 +static void rxHook(unsigned hook, void *ignored) { + (void)hook; + (void)ignored; + /* FIXME this is mad buggy; we need a new reset sequence. E.g. NAK + * after each RX means you can't reset if any bytes are waiting. */ + if (reset_state == DTR_NEGEDGE) { + reset_state = DTR_LOW; + + if (composite_cdcacm_data_available() >= 4) { + // The magic reset sequence is "1EAF". + static const uint8 magic[4] = {'1', 'E', 'A', 'F'}; + + uint8 chkBuf[4]; + + // Peek at the waiting bytes, looking for reset sequence, + // bailing on mismatch. + composite_cdcacm_peek_ex(chkBuf, composite_cdcacm_data_available() - 4, 4); + for (unsigned i = 0; i < sizeof(magic); i++) { + if (chkBuf[i] != magic[i]) { + return; + } + } + + // Got the magic sequence -> reset, presumably into the bootloader. + // Return address is wait_reset, but we must set the thumb bit. + uintptr_t target = (uintptr_t)wait_reset | 0x1; + asm volatile("mov r0, %[stack_top] \n\t" // Reset stack + "mov sp, r0 \n\t" + "mov r0, #1 \n\t" + "mov r1, %[target_addr] \n\t" + "mov r2, %[cpsr] \n\t" + "push {r2} \n\t" // Fake xPSR + "push {r1} \n\t" // PC target addr + "push {r0} \n\t" // Fake LR + "push {r0} \n\t" // Fake R12 + "push {r0} \n\t" // Fake R3 + "push {r0} \n\t" // Fake R2 + "push {r0} \n\t" // Fake R1 + "push {r0} \n\t" // Fake R0 + "mov lr, %[exc_return] \n\t" + "bx lr" + : + : [stack_top] "r" (STACK_TOP), + [target_addr] "r" (target), + [exc_return] "r" (EXC_RETURN), + [cpsr] "r" (DEFAULT_CPSR) + : "r0", "r1", "r2"); + + /* Can't happen. */ + ASSERT_FAULT(0); + } + } +} +#endif + + +USBCompositeSerial CompositeSerial; + diff --git a/STM32F1/libraries/USBComposite/USBCompositeSerial.h b/STM32F1/libraries/USBComposite/USBCompositeSerial.h new file mode 100644 index 0000000..4112617 --- /dev/null +++ b/STM32F1/libraries/USBComposite/USBCompositeSerial.h @@ -0,0 +1,40 @@ +#ifndef _COMPOSITE_SERIAL_H_ +#define _COMPOSITE_SERIAL_H_ + +#include "USBComposite.h" +#include "usb_serial.h" + +class USBCompositeSerial : public Stream { +private: + bool enabled = false; +public: + void begin(long speed=9600); + void end(); + static bool init(USBCompositeSerial* me); + bool registerComponent(); + + operator bool() { return true; } // Roger Clark. This is needed because in cardinfo.ino it does if (!Serial) . It seems to be a work around for the Leonardo that we needed to implement just to be compliant with the API + + virtual int available(void);// Changed to virtual + + uint32 read(uint8 * buf, uint32 len); + // uint8 read(void); + + // Roger Clark. added functions to support Arduino 1.0 API + virtual int peek(void); + virtual int read(void); + int availableForWrite(void); + virtual void flush(void); + + size_t write(uint8); + size_t write(const char *str); + size_t write(const uint8*, uint32); + + uint8 getRTS(); + uint8 getDTR(); + uint8 isConnected(); + uint8 pending(); +}; + +extern USBCompositeSerial CompositeSerial; +#endif diff --git a/STM32F1/libraries/USBComposite/USBHID.cpp b/STM32F1/libraries/USBComposite/USBHID.cpp new file mode 100644 index 0000000..e0b69b4 --- /dev/null +++ b/STM32F1/libraries/USBComposite/USBHID.cpp @@ -0,0 +1,180 @@ +/* Copyright (c) 2011, Peter Barrett +** +** Permission to use, copy, modify, and/or distribute this software for +** any purpose with or without fee is hereby granted, provided that the +** above copyright notice and this permission notice appear in all copies. +** +** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR +** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES +** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +** SOFTWARE. +*/ + +#include "USBHID.h" +#include "USBCompositeSerial.h" + +#include +#include +#include +#include "usb_hid.h" +#include "usb_serial.h" +#include "usb_generic.h" +#include +#include +#include + +#include + +/* + * USB HID interface + */ + +bool USBHIDDevice::registerComponent() { + return USBComposite.add(&usbHIDPart, this); +} + +void USBHIDDevice::setReportDescriptor(const uint8_t* report_descriptor, uint16_t report_descriptor_length) { + usb_hid_set_report_descriptor(report_descriptor, report_descriptor_length); +} + +void USBHIDDevice::setReportDescriptor(const HIDReportDescriptor* report) { + setReportDescriptor(report->descriptor, report->length); +} + +void USBHIDDevice::begin(const uint8_t* report_descriptor, uint16_t report_descriptor_length, uint16_t idVendor, uint16_t idProduct, + const char* manufacturer, const char* product, const char* serialNumber) { + + if (enabledHID) + return; + + setReportDescriptor(report_descriptor, report_descriptor_length); + + USBComposite.clear(); + USBComposite.setVendorId(idVendor); + USBComposite.setProductId(idProduct); + USBComposite.setManufacturerString(manufacturer); + USBComposite.setProductString(product); + USBComposite.setSerialString(serialNumber); + registerComponent(); + + USBComposite.begin(); + + enabledHID = true; +} + +void USBHIDDevice::begin(const HIDReportDescriptor* report, uint16_t idVendor, uint16_t idProduct, + const char* manufacturer, const char* product, const char* serialNumber) { + begin(report->descriptor, report->length, idVendor, idProduct, manufacturer, product, serialNumber); +} + +void USBHIDDevice::setBuffers(uint8_t type, volatile HIDBuffer_t* fb, int count) { + usb_hid_set_buffers(type, fb, count); +} + +bool USBHIDDevice::addBuffer(uint8_t type, volatile HIDBuffer_t* buffer) { + return 0 != usb_hid_add_buffer(type, buffer); +} + +void USBHIDDevice::clearBuffers(uint8_t type) { + usb_hid_clear_buffers(type); +} + +void USBHIDDevice::clearBuffers() { + clearBuffers(HID_REPORT_TYPE_OUTPUT); + clearBuffers(HID_REPORT_TYPE_FEATURE); +} + +void USBHIDDevice::end(void){ + if(enabledHID){ + USBComposite.end(); + enabledHID = false; + } +} + +void HIDReporter::sendReport() { +// while (usb_is_transmitting() != 0) { +// } + + unsigned toSend = bufferSize; + uint8* b = buffer; + + while (toSend) { + unsigned delta = usb_hid_tx(b, toSend); + toSend -= delta; + b += delta; + } + +// while (usb_is_transmitting() != 0) { +// } + + /* flush out to avoid having the pc wait for more data */ + usb_hid_tx(NULL, 0); +} + +HIDReporter::HIDReporter(uint8_t* _buffer, unsigned _size, uint8_t _reportID) { + if (_reportID == 0) { + buffer = _buffer+1; + bufferSize = _size-1; + } + else { + buffer = _buffer; + bufferSize = _size; + } + memset(buffer, 0, bufferSize); + reportID = _reportID; + if (_size > 0 && reportID != 0) + buffer[0] = _reportID; +} + +HIDReporter::HIDReporter(uint8_t* _buffer, unsigned _size) { + buffer = _buffer; + bufferSize = _size; + memset(buffer, 0, _size); + reportID = 0; +} + +void HIDReporter::setFeature(uint8_t* in) { + return usb_hid_set_feature(reportID, in); +} + +uint16_t HIDReporter::getData(uint8_t type, uint8_t* out, uint8_t poll) { + return usb_hid_get_data(type, reportID, out, poll); +} + +uint16_t HIDReporter::getFeature(uint8_t* out, uint8_t poll) { + return usb_hid_get_data(HID_REPORT_TYPE_FEATURE, reportID, out, poll); +} + +uint16_t HIDReporter::getOutput(uint8_t* out, uint8_t poll) { + return usb_hid_get_data(HID_REPORT_TYPE_OUTPUT, reportID, out, poll); +} + +USBHIDDevice USBHID; + +void USBHID_begin_with_serial(const uint8_t* report_descriptor, uint16_t report_descriptor_length, uint16_t idVendor, uint16_t idProduct, + const char* manufacturer, const char* product, const char* serialNumber) { + + USBComposite.clear(); + USBComposite.setVendorId(idVendor); + USBComposite.setProductId(idProduct); + USBComposite.setManufacturerString(manufacturer); + USBComposite.setProductString(product); + USBComposite.setSerialString(serialNumber); + + USBHID.setReportDescriptor(report_descriptor, report_descriptor_length); + USBHID.registerComponent(); + + CompositeSerial.registerComponent(); + + USBComposite.begin(); +} + +void USBHID_begin_with_serial(const HIDReportDescriptor* report, uint16_t idVendor, uint16_t idProduct, + const char* manufacturer, const char* product, const char* serialNumber) { + USBHID_begin_with_serial(report->descriptor, report->length, idVendor, idProduct, manufacturer, product, serialNumber); +} + diff --git a/STM32F1/libraries/USBComposite/USBHID.h b/STM32F1/libraries/USBComposite/USBHID.h new file mode 100644 index 0000000..0362f4e --- /dev/null +++ b/STM32F1/libraries/USBComposite/USBHID.h @@ -0,0 +1,608 @@ +/* Copyright (c) 2011, Peter Barrett +** +** Permission to use, copy, modify, and/or distribute this software for +** any purpose with or without fee is hereby granted, provided that the +** above copyright notice and this permission notice appear in all copies. +** +** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR +** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES +** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +** SOFTWARE. +*/ + +#ifndef _USBHID_H_ +#define _USBHID_H_ + +#include +#include +#include +#include +#include "Stream.h" +#include "usb_hid.h" + +#define USB_HID_MAX_PRODUCT_LENGTH 32 +#define USB_HID_MAX_MANUFACTURER_LENGTH 32 +#define USB_HID_MAX_SERIAL_NUMBER_LENGTH 20 + +#define HID_MOUSE_REPORT_ID 1 +#define HID_KEYBOARD_REPORT_ID 2 +#define HID_CONSUMER_REPORT_ID 3 +#define HID_JOYSTICK_REPORT_ID 20 + +#define HID_KEYBOARD_ROLLOVER 6 + +#define MACRO_GET_ARGUMENT_2(x, y, ...) y +#define MACRO_GET_ARGUMENT_1_WITH_DEFAULT(default, ...) MACRO_GET_ARGUMENT_2(placeholder, ## __VA_ARGS__, default) +#define MACRO_ARGUMENT_2_TO_END(skip, ...) __VA_ARGS__ + +// HIDBuffer_t data buffers must have even memory length because of how PMA transfers work +#define HID_DATA_BUFFER_SIZE(n) (((n)+1)/2*2) + +/* note that featureSize must be 1 less than the buffer size for the feature, + since the latter must include the reportId */ +/* this only works in a collection with a report_id */ +#define HID_FEATURE_REPORT_DESCRIPTOR(dataSize) \ + 0x06, 0x00, 0xFF, /* USAGE_PAGE (Vendor Defined Page 1) */ \ + 0x09, 0x01, /* USAGE (Vendor Usage 1) */ \ + 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \ + 0x26, 0xff, 0x00, /* LOGICAL_MAXIMUM (255) */ \ + 0x75, 0x08, /* REPORT_SIZE (8) */ \ + 0x95, dataSize, /* REPORT_COUNT (xx) */ \ + 0xB1, 0x02, /* FEATURE (Data,Var,Abs) */ \ + +#define HID_OUTPUT_REPORT_DESCRIPTOR(dataSize) \ + 0x06, 0x00, 0xFF, /* USAGE_PAGE (Vendor Defined Page 1) */ \ + 0x09, 0x01, /* USAGE (Vendor Usage 1) */ \ + 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \ + 0x26, 0xff, 0x00, /* LOGICAL_MAXIMUM (255) */ \ + 0x75, 0x08, /* REPORT_SIZE (8) */ \ + 0x95, dataSize, /* REPORT_COUNT (32) */ \ + 0x91, 0x02, /* OUTPUT (Data,Var,Abs) */ \ + +#define HID_CONSUMER_REPORT_DESCRIPTOR(...) \ + 0x05, 0x0C, /* usage page (consumer device) */ \ + 0x09, 0x01, /* usage -- consumer control */ \ + 0xA1, 0x01, /* collection (application) */ \ + 0x85, MACRO_GET_ARGUMENT_1_WITH_DEFAULT(HID_CONSUMER_REPORT_ID, ## __VA_ARGS__), /* REPORT_ID */ \ + 0x15, 0x00, /* logical minimum */ \ + 0x26, 0xFF, 0x03, /* logical maximum (3ff) */ \ + 0x19, 0x00, /* usage minimum (0) */ \ + 0x2A, 0xFF, 0x03, /* usage maximum (3ff) */ \ + 0x75, 0x10, /* report size (16) */ \ + 0x95, 0x01, /* report count (1) */ \ + 0x81, 0x00, /* input */ \ + MACRO_ARGUMENT_2_TO_END(__VA_ARGS__) \ + 0xC0 /* end collection */ + +#define HID_MOUSE_REPORT_DESCRIPTOR(...) \ + 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) // 54 */ \ + 0x09, 0x02, /* USAGE (Mouse) */ \ + 0xa1, 0x01, /* COLLECTION (Application) */ \ + 0x85, MACRO_GET_ARGUMENT_1_WITH_DEFAULT(HID_MOUSE_REPORT_ID, ## __VA_ARGS__), /* REPORT_ID */ \ + 0x09, 0x01, /* USAGE (Pointer) */ \ + 0xa1, 0x00, /* COLLECTION (Physical) */ \ + 0x05, 0x09, /* USAGE_PAGE (Button) */ \ + 0x19, 0x01, /* USAGE_MINIMUM (Button 1) */ \ + 0x29, 0x08, /* USAGE_MAXIMUM (Button 8) */ \ + 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \ + 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ \ + 0x95, 0x08, /* REPORT_COUNT (8) */ \ + 0x75, 0x01, /* REPORT_SIZE (1) */ \ + 0x81, 0x02, /* INPUT (Data,Var,Abs) */ \ + 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ \ + 0x09, 0x30, /* USAGE (X) */ \ + 0x09, 0x31, /* USAGE (Y) */ \ + 0x09, 0x38, /* USAGE (Wheel) */ \ + 0x15, 0x81, /* LOGICAL_MINIMUM (-127) */ \ + 0x25, 0x7f, /* LOGICAL_MAXIMUM (127) */ \ + 0x75, 0x08, /* REPORT_SIZE (8) */ \ + 0x95, 0x03, /* REPORT_COUNT (3) */ \ + 0x81, 0x06, /* INPUT (Data,Var,Rel) */ \ + 0xc0, /* END_COLLECTION */ \ + MACRO_ARGUMENT_2_TO_END(__VA_ARGS__) \ + 0xc0 /* END_COLLECTION */ + +#define HID_ABS_MOUSE_REPORT_DESCRIPTOR(...) \ + 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) // 54 */ \ + 0x09, 0x02, /* USAGE (Mouse) */ \ + 0xa1, 0x01, /* COLLECTION (Application) */ \ + 0x85, MACRO_GET_ARGUMENT_1_WITH_DEFAULT(HID_MOUSE_REPORT_ID, ## __VA_ARGS__), /* REPORT_ID */ \ + 0x09, 0x01, /* USAGE (Pointer) */ \ + 0xa1, 0x00, /* COLLECTION (Physical) */ \ + 0x05, 0x09, /* USAGE_PAGE (Button) */ \ + 0x19, 0x01, /* USAGE_MINIMUM (Button 1) */ \ + 0x29, 0x08, /* USAGE_MAXIMUM (Button 8) */ \ + 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \ + 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ \ + 0x95, 0x08, /* REPORT_COUNT (8) */ \ + 0x75, 0x01, /* REPORT_SIZE (1) */ \ + 0x81, 0x02, /* INPUT (Data,Var,Abs) */ \ + 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ \ + 0x09, 0x30, /* USAGE (X) */ \ + 0x09, 0x31, /* USAGE (Y) */ \ + 0x16, 0x00, 0x80, /* LOGICAL_MINIMUM (-32768) */ \ + 0x26, 0xFF, 0x7f, /* LOGICAL_MAXIMUM (32767) */ \ + 0x75, 0x10, /* REPORT_SIZE (16) */ \ + 0x95, 0x02, /* REPORT_COUNT (2) */ \ + 0x81, 0x02, /* INPUT (Data,Var,Abs) */ \ + 0x09, 0x38, /* USAGE (Wheel) */ \ + 0x15, 0x81, /* LOGICAL_MINIMUM (-127) */ \ + 0x25, 0x7f, /* LOGICAL_MAXIMUM (127) */ \ + 0x75, 0x08, /* REPORT_SIZE (8) */ \ + 0x95, 0x01, /* REPORT_COUNT (1) */ \ + 0x81, 0x06, /* INPUT (Data,Var,Rel) */ \ + 0xc0, /* END_COLLECTION */ \ + MACRO_ARGUMENT_2_TO_END(__VA_ARGS__) \ + 0xc0 /* END_COLLECTION */ + +#define HID_KEYBOARD_REPORT_DESCRIPTOR(...) \ + 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) // 47 */ \ + 0x09, 0x06, /* USAGE (Keyboard) */ \ + 0xa1, 0x01, /* COLLECTION (Application) */ \ + 0x85, MACRO_GET_ARGUMENT_1_WITH_DEFAULT(HID_KEYBOARD_REPORT_ID, ## __VA_ARGS__), /* REPORT_ID */ \ + 0x05, 0x07, /* USAGE_PAGE (Keyboard) */ \ + 0x19, 0xe0, /* USAGE_MINIMUM (Keyboard LeftControl) */ \ + 0x29, 0xe7, /* USAGE_MAXIMUM (Keyboard Right GUI) */ \ + 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \ + 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ \ + 0x75, 0x01, /* REPORT_SIZE (1) */ \ + 0x95, 0x08, /* REPORT_COUNT (8) */ \ + 0x81, 0x02, /* INPUT (Data,Var,Abs) */ \ +\ + 0x95, 0x01, /* REPORT_COUNT (1) */ \ + 0x75, 0x08, /* REPORT_SIZE (8) */ \ + 0x81, 0x03, /* INPUT (Cnst,Var,Abs) */ \ +\ + 0x95, HID_KEYBOARD_ROLLOVER, /* REPORT_COUNT (6) */ \ + 0x75, 0x08, /* REPORT_SIZE (8) */ \ + 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \ + 0x25, 0x65, /* LOGICAL_MAXIMUM (101) */ \ + 0x05, 0x07, /* USAGE_PAGE (Keyboard) */ \ +\ + 0x19, 0x00, /* USAGE_MINIMUM (Reserved (no event indicated)) */ \ + 0x29, 0x65, /* USAGE_MAXIMUM (Keyboard Application) */ \ + 0x81, 0x00, /* INPUT (Data,Ary,Abs) */ \ +\ + 0x05, 0x08, /* USAGE_PAGE (LEDs) */ \ + 0x19, 0x01, /* USAGE_MINIMUM (Num Lock) */ \ + 0x29, 0x08, /* USAGE_MAXIMUM (Kana + 3 custom)*/ \ + 0x95, 0x08, /* REPORT_COUNT (8) */ \ + 0x75, 0x01, /* REPORT_SIZE (1) */ \ + 0x91, 0x02, /* OUTPUT (Data,Var,Abs) */ \ + MACRO_ARGUMENT_2_TO_END(__VA_ARGS__) \ + 0xc0 /* END_COLLECTION */ + +#define HID_BOOT_KEYBOARD_REPORT_DESCRIPTOR(...) \ + 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) // 47 */ \ + 0x09, 0x06, /* USAGE (Keyboard) */ \ + 0xa1, 0x01, /* COLLECTION (Application) */ \ + 0x05, 0x07, /* USAGE_PAGE (Keyboard) */ \ + 0x19, 0xe0, /* USAGE_MINIMUM (Keyboard LeftControl) */ \ + 0x29, 0xe7, /* USAGE_MAXIMUM (Keyboard Right GUI) */ \ + 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \ + 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ \ + 0x75, 0x01, /* REPORT_SIZE (1) */ \ + 0x95, 0x08, /* REPORT_COUNT (8) */ \ + 0x81, 0x02, /* INPUT (Data,Var,Abs) */ \ +\ + 0x95, 0x01, /* REPORT_COUNT (1) */ \ + 0x75, 0x08, /* REPORT_SIZE (8) */ \ + 0x81, 0x03, /* INPUT (Cnst,Var,Abs) */ \ +\ + 0x95, 0x06, /* REPORT_COUNT (6) */ \ + 0x75, 0x08, /* REPORT_SIZE (8) */ \ + 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \ + 0x25, 0x65, /* LOGICAL_MAXIMUM (101) */ \ + 0x05, 0x07, /* USAGE_PAGE (Keyboard) */ \ +\ + 0x19, 0x00, /* USAGE_MINIMUM (Reserved (no event indicated)) */ \ + 0x29, 0x65, /* USAGE_MAXIMUM (Keyboard Application) */ \ + 0x81, 0x00, /* INPUT (Data,Ary,Abs) */ \ +\ + 0x05, 0x08, /* USAGE_PAGE (LEDs) */ \ + 0x19, 0x01, /* USAGE_MINIMUM (Num Lock) */ \ + 0x29, 0x08, /* USAGE_MAXIMUM (Kana + 3 custom)*/ \ + 0x95, 0x08, /* REPORT_COUNT (8) */ \ + 0x75, 0x01, /* REPORT_SIZE (1) */ \ + 0x91, 0x02, /* OUTPUT (Data,Var,Abs) */ \ + __VA_ARGS__ \ + 0xc0 /* END_COLLECTION */ + +#define HID_JOYSTICK_REPORT_DESCRIPTOR(...) \ + 0x05, 0x01, /* Usage Page (Generic Desktop) */ \ + 0x09, 0x04, /* Usage (Joystick) */ \ + 0xA1, 0x01, /* Collection (Application) */ \ + 0x85, MACRO_GET_ARGUMENT_1_WITH_DEFAULT(HID_JOYSTICK_REPORT_ID, ## __VA_ARGS__), /* REPORT_ID */ \ + 0x15, 0x00, /* Logical Minimum (0) */ \ + 0x25, 0x01, /* Logical Maximum (1) */ \ + 0x75, 0x01, /* Report Size (1) */ \ + 0x95, 0x20, /* Report Count (32) */ \ + 0x05, 0x09, /* Usage Page (Button) */ \ + 0x19, 0x01, /* Usage Minimum (Button #1) */ \ + 0x29, 0x20, /* Usage Maximum (Button #32) */ \ + 0x81, 0x02, /* Input (variable,absolute) */ \ + 0x15, 0x00, /* Logical Minimum (0) */ \ + 0x25, 0x07, /* Logical Maximum (7) */ \ + 0x35, 0x00, /* Physical Minimum (0) */ \ + 0x46, 0x3B, 0x01, /* Physical Maximum (315) */ \ + 0x75, 0x04, /* Report Size (4) */ \ + 0x95, 0x01, /* Report Count (1) */ \ + 0x65, 0x14, /* Unit (20) */ \ + 0x05, 0x01, /* Usage Page (Generic Desktop) */ \ + 0x09, 0x39, /* Usage (Hat switch) */ \ + 0x81, 0x42, /* Input (variable,absolute,null_state) */ \ + 0x05, 0x01, /* Usage Page (Generic Desktop) */ \ + 0x09, 0x01, /* Usage (Pointer) */ \ + 0xA1, 0x00, /* Collection () */ \ + 0x15, 0x00, /* Logical Minimum (0) */ \ + 0x26, 0xFF, 0x03, /* Logical Maximum (1023) */ \ + 0x75, 0x0A, /* Report Size (10) */ \ + 0x95, 0x04, /* Report Count (4) */ \ + 0x09, 0x30, /* Usage (X) */ \ + 0x09, 0x31, /* Usage (Y) */ \ + 0x09, 0x33, /* Usage (Rx) */ \ + 0x09, 0x34, /* Usage (Ry) */ \ + 0x81, 0x02, /* Input (variable,absolute) */ \ + 0xC0, /* End Collection */ \ + 0x15, 0x00, /* Logical Minimum (0) */ \ + 0x26, 0xFF, 0x03, /* Logical Maximum (1023) */ \ + 0x75, 0x0A, /* Report Size (10) */ \ + 0x95, 0x02, /* Report Count (2) */ \ + 0x09, 0x36, /* Usage (Slider) */ \ + 0x09, 0x36, /* Usage (Slider) */ \ + 0x81, 0x02, /* Input (variable,absolute) */ \ + MACRO_ARGUMENT_2_TO_END(__VA_ARGS__) \ + 0xC0 + +#define RAWHID_USAGE_PAGE 0xFFC0 // recommended: 0xFF00 to 0xFFFF +#define RAWHID_USAGE 0x0C00 // recommended: 0x0100 to 0xFFFF + +#define LSB(x) ((x) & 0xFF) +#define MSB(x) (((x) & 0xFF00) >> 8) +// TODO: make this work for txSize > 255 +#define HID_RAW_REPORT_DESCRIPTOR(txSize, rxSize) \ + 0x06, LSB(RAWHID_USAGE_PAGE), MSB(RAWHID_USAGE_PAGE), \ + 0x0A, LSB(RAWHID_USAGE), MSB(RAWHID_USAGE), \ + 0xA1, 0x01, /* Collection 0x01 */ \ +/* 0x85, 10, */ /* REPORT_ID (1) */ \ + 0x75, 0x08, /* report size = 8 bits */ \ + 0x15, 0x00, /* logical minimum = 0 */ \ + 0x26, 0xFF, 0x00, /* logical maximum = 255 */ \ +\ + 0x96, LSB(txSize), MSB(txSize), /* report count TX */ \ + 0x09, 0x01, /* usage */ \ + 0x81, 0x02, /* Input (array) */ \ +\ + 0x75, 0x08, /* report size = 8 bits */ \ + 0x15, 0x00, /* logical minimum = 0 */ \ + 0x26, 0xFF, 0x00, /* logical maximum = 255 */ \ + 0x96, LSB(rxSize), MSB(rxSize), /* report count RX */ \ + 0x09, 0x02, /* usage */ \ + 0x91, 0x02, /* OUTPUT (0x91) */ \ + 0xC0 /* end collection */ + +typedef struct { + uint8_t* descriptor; + uint16_t length; +} HIDReportDescriptor; + +class USBHIDDevice { +private: + bool enabledHID = false; +public: + bool registerComponent(); + void setReportDescriptor(const uint8_t* report_descriptor, uint16_t report_descriptor_length); + void setReportDescriptor(const HIDReportDescriptor* reportDescriptor); + // All the strings are zero-terminated ASCII strings. Use NULL for defaults. + void begin(const uint8_t* report_descriptor, uint16_t length, uint16_t idVendor=0, uint16_t idProduct=0, + const char* manufacturer=NULL, const char* product=NULL, const char* serialNumber="00000000000000000001"); + void begin(const HIDReportDescriptor* reportDescriptor, uint16_t idVendor=0, uint16_t idProduct=0, + const char* manufacturer=NULL, const char* product=NULL, const char* serialNumber="00000000000000000001"); + void setSerial(uint8 serialSupport=true); + void setBuffers(uint8_t buffers, volatile HIDBuffer_t* fb=NULL, int count=0); // type = HID_REPORT_TYPE_FEATURE or HID_REPORT_TYPE_OUTPUT + bool addBuffer(uint8_t type, volatile HIDBuffer_t* buffer); + void clearBuffers(uint8_t type); + void clearBuffers(); + inline bool addFeatureBuffer(volatile HIDBuffer_t* buffer) { + return addBuffer(HID_REPORT_TYPE_FEATURE, buffer); + } + inline bool addOutputBuffer(volatile HIDBuffer_t* buffer) { + return addBuffer(HID_REPORT_TYPE_OUTPUT, buffer); + } + inline void setFeatureBuffers(volatile HIDBuffer_t* fb=NULL, int count=0) { + setBuffers(HID_REPORT_TYPE_FEATURE, fb, count); + } + inline void setOutputBuffers(volatile HIDBuffer_t* fb=NULL, int count=0) { + setBuffers(HID_REPORT_TYPE_OUTPUT, fb, count); + } + void end(void); +}; + +void USBHID_begin_with_serial(const uint8_t* report_descriptor, uint16_t length, uint16_t idVendor=0, uint16_t idProduct=0, + const char* manufacturer=NULL, const char* product=NULL, const char* serialNumber="00000000000000000001"); +void USBHID_begin_with_serial(const HIDReportDescriptor* reportDescriptor, uint16_t idVendor=0, uint16_t idProduct=0, + const char* manufacturer=NULL, const char* product=NULL, const char* serialNumber="00000000000000000001"); + +class HIDReporter { + private: + uint8_t* buffer; + unsigned bufferSize; + uint8_t reportID; + + public: + void sendReport(); + + public: + // if you use this init function, the buffer starts with a reportID, even if the reportID is zero, + // and bufferSize includes the reportID; if reportID is zero, sendReport() will skip the initial + // reportID byte + HIDReporter(uint8_t* _buffer, unsigned _size, uint8_t _reportID); + // if you use this init function, the buffer has no reportID byte in it + HIDReporter(uint8_t* _buffer, unsigned _size); + uint16_t getFeature(uint8_t* out=NULL, uint8_t poll=1); + uint16_t getOutput(uint8_t* out=NULL, uint8_t poll=1); + uint16_t getData(uint8_t type, uint8_t* out, uint8_t poll=1); // type = HID_REPORT_TYPE_FEATURE or HID_REPORT_TYPE_OUTPUT + void setFeature(uint8_t* feature); +}; + +//================================================================================ +//================================================================================ +// Mouse + +#define MOUSE_LEFT 1 +#define MOUSE_RIGHT 2 +#define MOUSE_MIDDLE 4 +#define MOUSE_ALL (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE) + +class HIDMouse : public HIDReporter { +protected: + uint8_t _buttons; + void buttons(uint8_t b); + uint8_t reportBuffer[5]; +public: + HIDMouse(uint8_t reportID=HID_MOUSE_REPORT_ID) : HIDReporter(reportBuffer, sizeof(reportBuffer), reportID), _buttons(0) {} + void begin(void); + void end(void); + void click(uint8_t b = MOUSE_LEFT); + void move(signed char x, signed char y, signed char wheel = 0); + void press(uint8_t b = MOUSE_LEFT); // press LEFT by default + void release(uint8_t b = MOUSE_LEFT); // release LEFT by default + bool isPressed(uint8_t b = MOUSE_ALL); // check all buttons by default +}; + +typedef struct { + uint8_t reportID; + uint8_t buttons; + int16_t x; + int16_t y; + uint8_t wheel; +} __packed AbsMouseReport_t; + +class HIDAbsMouse : public HIDReporter { +protected: + void buttons(uint8_t b); + AbsMouseReport_t report; +public: + HIDAbsMouse(uint8_t reportID=HID_MOUSE_REPORT_ID) : HIDReporter((uint8_t*)&report, sizeof(report), reportID) { + report.buttons = 0; + report.x = 0; + report.y = 0; + report.wheel = 0; + } + void begin(void); + void end(void); + void click(uint8_t b = MOUSE_LEFT); + void move(int16_t x, int16_t y, int8_t wheel = 0); + void press(uint8_t b = MOUSE_LEFT); // press LEFT by default + void release(uint8_t b = MOUSE_LEFT); // release LEFT by default + bool isPressed(uint8_t b = MOUSE_ALL); // check all buttons by default +}; + +typedef struct { + uint8_t reportID; + uint16_t button; +} __packed ConsumerReport_t; + +class HIDConsumer : public HIDReporter { +protected: + ConsumerReport_t report; +public: + enum { + BRIGHTNESS_UP = 0x6F, + BRIGHTNESS_DOWN = 0x70, + VOLUME_UP = 0xE9, + VOLUME_DOWN = 0xEA, + MUTE = 0xE2, + PLAY_OR_PAUSE = 0xCD + // see pages 75ff of http://www.usb.org/developers/hidpage/Hut1_12v2.pdf + }; + HIDConsumer(uint8_t reportID=HID_CONSUMER_REPORT_ID) : HIDReporter((uint8_t*)&report, sizeof(report), reportID) { + report.button = 0; + } + void begin(void); + void end(void); + void press(uint16_t button); + void release(); +}; + +#define KEY_LEFT_CTRL 0x80 +#define KEY_LEFT_SHIFT 0x81 +#define KEY_LEFT_ALT 0x82 +#define KEY_LEFT_GUI 0x83 +#define KEY_RIGHT_CTRL 0x84 +#define KEY_RIGHT_SHIFT 0x85 +#define KEY_RIGHT_ALT 0x86 +#define KEY_RIGHT_GUI 0x87 + +#define KEY_UP_ARROW 0xDA +#define KEY_DOWN_ARROW 0xD9 +#define KEY_LEFT_ARROW 0xD8 +#define KEY_RIGHT_ARROW 0xD7 +#define KEY_BACKSPACE 0xB2 +#define KEY_TAB 0xB3 +#define KEY_RETURN 0xB0 +#define KEY_ESC 0xB1 +#define KEY_INSERT 0xD1 +#define KEY_DELETE 0xD4 +#define KEY_PAGE_UP 0xD3 +#define KEY_PAGE_DOWN 0xD6 +#define KEY_HOME 0xD2 +#define KEY_END 0xD5 +#define KEY_CAPS_LOCK 0xC1 +#define KEY_F1 0xC2 +#define KEY_F2 0xC3 +#define KEY_F3 0xC4 +#define KEY_F4 0xC5 +#define KEY_F5 0xC6 +#define KEY_F6 0xC7 +#define KEY_F7 0xC8 +#define KEY_F8 0xC9 +#define KEY_F9 0xCA +#define KEY_F10 0xCB +#define KEY_F11 0xCC +#define KEY_F12 0xCD + +typedef struct{ + uint8_t reportID; + uint8_t modifiers; + uint8_t reserved; + uint8_t keys[HID_KEYBOARD_ROLLOVER]; +} __packed KeyReport_t; + +class HIDKeyboard : public Print, public HIDReporter { +public: + KeyReport_t keyReport; + +protected: + uint8_t leds[HID_BUFFER_ALLOCATE_SIZE(1,1)]; + HIDBuffer_t ledData; + uint8_t reportID; + uint8_t getKeyCode(uint8_t k, uint8_t* modifiersP); + bool adjustForHostCapsLock = true; + +public: + HIDKeyboard(uint8_t _reportID=HID_KEYBOARD_REPORT_ID) : + HIDReporter((uint8*)&keyReport, sizeof(KeyReport_t), _reportID), + ledData(leds, HID_BUFFER_SIZE(1,_reportID), _reportID, HID_BUFFER_MODE_NO_WAIT), + reportID(_reportID) + {} + void begin(void); + void end(void); + void setAdjustForHostCapsLock(bool state) { + adjustForHostCapsLock = state; + } + inline uint8 getLEDs(void) { + return leds[reportID != 0 ? 1 : 0]; + } + virtual size_t write(uint8_t k); + virtual size_t press(uint8_t k); + virtual size_t release(uint8_t k); + virtual void releaseAll(void); +}; + + +//================================================================================ +//================================================================================ +// Joystick + +// only works for little-endian machines, but makes the code so much more +// readable +typedef struct { + uint8_t reportID; + uint32_t buttons; + unsigned hat:4; + unsigned x:10; + unsigned y:10; + unsigned rx:10; + unsigned ry:10; + unsigned sliderLeft:10; + unsigned sliderRight:10; +} __packed JoystickReport_t; + +static_assert(sizeof(JoystickReport_t)==13, "Wrong endianness/packing!"); + +class HIDJoystick : public HIDReporter { +protected: + JoystickReport_t joyReport; + bool manualReport = false; + void safeSendReport(void); +public: + inline void send(void) { + sendReport(); + } + void setManualReportMode(bool manualReport); // in manual report mode, reports only sent when send() is called + bool getManualReportMode(); + void begin(void); + void end(void); + void button(uint8_t button, bool val); + void X(uint16_t val); + void Y(uint16_t val); + void position(uint16_t x, uint16_t y); + void Xrotate(uint16_t val); + void Yrotate(uint16_t val); + void sliderLeft(uint16_t val); + void sliderRight(uint16_t val); + void slider(uint16_t val); + void hat(int16_t dir); + HIDJoystick(uint8_t reportID=HID_JOYSTICK_REPORT_ID) : HIDReporter((uint8_t*)&joyReport, sizeof(joyReport), reportID) { + joyReport.buttons = 0; + joyReport.hat = 15; + joyReport.x = 512; + joyReport.y = 512; + joyReport.rx = 512; + joyReport.ry = 512; + joyReport.sliderLeft = 0; + joyReport.sliderRight = 0; + } +}; + +extern USBHIDDevice USBHID; + +templateclass HIDRaw : public HIDReporter { +private: + uint8_t txBuffer[txSize]; + uint8_t rxBuffer[HID_BUFFER_ALLOCATE_SIZE(rxSize,0)]; + HIDBuffer_t buf; +public: + HIDRaw() : HIDReporter(txBuffer, sizeof(txBuffer)) {} + void begin(void) { + buf.buffer = rxBuffer; + buf.bufferSize = HID_BUFFER_SIZE(rxSize,0); + buf.reportID = 0; + USBHID.addOutputBuffer(&buf); + } + void end(void); + void send(const uint8_t* data, unsigned n=sizeof(txBuffer)) { + memset(txBuffer, 0, sizeof(txBuffer)); + memcpy(txBuffer, data, n>sizeof(txBuffer)?sizeof(txBuffer):n); + sendReport(); + } +}; + +extern HIDMouse Mouse; +extern HIDKeyboard Keyboard; +extern HIDJoystick Joystick; +extern HIDKeyboard BootKeyboard; + +extern const HIDReportDescriptor* hidReportMouse; +extern const HIDReportDescriptor* hidReportKeyboard; +extern const HIDReportDescriptor* hidReportJoystick; +extern const HIDReportDescriptor* hidReportKeyboardMouse; +extern const HIDReportDescriptor* hidReportKeyboardJoystick; +extern const HIDReportDescriptor* hidReportKeyboardMouseJoystick; +extern const HIDReportDescriptor* hidReportBootKeyboard; + +#define HID_MOUSE hidReportMouse +#define HID_KEYBOARD hidReportKeyboard +#define HID_JOYSTICK hidReportJoystick +#define HID_KEYBOARD_MOUSE hidReportKeyboardMouse +#define HID_KEYBOARD_JOYSTICK hidReportKeyboardJoystick +#define HID_KEYBOARD_MOUSE_JOYSTICK hidReportKeyboardMouseJoystick +#define HID_BOOT_KEYBOARD hidReportBootKeyboard + +#endif + \ No newline at end of file diff --git a/STM32F1/libraries/USBComposite/USBMIDI.cpp b/STM32F1/libraries/USBComposite/USBMIDI.cpp new file mode 100644 index 0000000..ba0e895 --- /dev/null +++ b/STM32F1/libraries/USBComposite/USBMIDI.cpp @@ -0,0 +1,469 @@ +/****************************************************************************** + * This started out as a munging of Tymm Twillman's arduino Midi Library into the Libusb class, + * though by now very little of the original code is left, except for the class API and + * comments. Tymm Twillman kindly gave Alexander Pruss permission to relicense his code under the MIT + * license, which fixed a nasty licensing mess. + * + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2013 Magnus Lundin. + * Copyright (c) 2013 Donald Delmar Davis, Suspect Devices. + * (c) 2003-2008 Tymm Twillman + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + *****************************************************************************/ + +/** + * @brief USB MIDI device with a class compatible with maplemidi + */ + +#include "USBMIDI.h" + +#include +#include +#include +#include +#include "usb_midi_device.h" +#include +#include "usb_generic.h" + + +/* + * USBMidi interface + */ + +#define USB_TIMEOUT 50 + +void USBMidi::setChannel(unsigned int channel) { + channelIn_ = channel; + +} + +/*bool USBMidi::init(USBMidi* me) { + return true; +}*/ + +bool USBMidi::registerComponent() { + return USBComposite.add(&usbMIDIPart, this); +} + +void USBMidi::begin(unsigned channel) { + setChannel(channel); + + if (enabled) + return; + + USBComposite.clear(); + registerComponent(); + USBComposite.begin(); + + enabled = true; +} + +void USBMidi::end(void) { + if (enabled) { + USBComposite.end(); + enabled = false; + } +} + +void USBMidi::writePacket(uint32 p) { + this->writePackets(&p, 1); +} + +void USBMidi::writePackets(const void *buf, uint32 len) { + if (!this->isConnected() || !buf) { + return; + } + + uint32 txed = 0; + uint32 old_txed = 0; + uint32 start = millis(); + + uint32 sent = 0; + + while (txed < len && (millis() - start < USB_TIMEOUT)) { + sent = usb_midi_tx((const uint32*)buf + txed, len - txed); + txed += sent; + if (old_txed != txed) { + start = millis(); + } + old_txed = txed; + } + + + if (sent == USB_MIDI_TX_EPSIZE) { + while (usb_midi_is_transmitting() != 0) { + } + /* flush out to avoid having the pc wait for more data */ + usb_midi_tx(NULL, 0); + } +} + +uint32 USBMidi::available(void) { + return usb_midi_data_available(); +} + +uint32 USBMidi::readPackets(void *buf, uint32 len) { + if (!buf) { + return 0; + } + + uint32 rxed = 0; + while (rxed < len) { + rxed += usb_midi_rx((uint32*)buf + rxed, len - rxed); + } + + return rxed; +} + +/* Blocks forever until 1 byte is received */ +uint32 USBMidi::readPacket(void) { + uint32 p; + this->readPackets(&p, 1); + return p; +} + +uint8 USBMidi::pending(void) { + return usb_midi_get_pending(); +} + +uint8 USBMidi::isConnected(void) { + return usb_is_connected(USBLIB) && usb_is_configured(USBLIB); +} + + +USBMidi USBMIDI; + + +// These are midi status message types are defined in MidiSpec.h + +union EVENT_t { + uint32 i; + uint8 b[4]; + MIDI_EVENT_PACKET_t p; +}; + +// Handle decoding incoming MIDI traffic a word at a time -- remembers +// what it needs to from one call to the next. +// +// This is a private function & not meant to be called from outside this class. +// It's used whenever data is available from the USB port. +// +void USBMidi::dispatchPacket(uint32 p) +{ + union EVENT_t e; + + e.i=p; + + switch (e.p.cin) { + case CIN_3BYTE_SYS_COMMON: + if (e.p.midi0 == MIDIv1_SONG_POSITION_PTR) { + handleSongPosition(((uint16)e.p.midi2)<<7|((uint16)e.p.midi1)); + } + break; + + case CIN_2BYTE_SYS_COMMON: + switch (e.p.midi0) { + case MIDIv1_SONG_SELECT: + handleSongSelect(e.p.midi1); + break; + case MIDIv1_MTC_QUARTER_FRAME: + // reference library doesnt handle quarter frame. + break; + } + break; + case CIN_NOTE_OFF: + handleNoteOff(MIDIv1_VOICE_CHANNEL(e.p.midi0), e.p.midi1, e.p.midi2); + break; + case CIN_NOTE_ON: + handleNoteOn(MIDIv1_VOICE_CHANNEL(e.p.midi0), e.p.midi1, e.p.midi2); + break; + case CIN_AFTER_TOUCH: + handleVelocityChange(MIDIv1_VOICE_CHANNEL(e.p.midi0), e.p.midi1, e.p.midi2); + break; + case CIN_CONTROL_CHANGE: + handleControlChange(MIDIv1_VOICE_CHANNEL(e.p.midi0), e.p.midi1, e.p.midi2); + break; + case CIN_PROGRAM_CHANGE: + handleProgramChange(MIDIv1_VOICE_CHANNEL(e.p.midi0), e.p.midi1); + break; + case CIN_CHANNEL_PRESSURE: + handleAfterTouch(MIDIv1_VOICE_CHANNEL(e.p.midi0), e.p.midi1); + break; + + case CIN_PITCH_WHEEL: + handlePitchChange(((uint16)e.p.midi2)<<7|((uint16)e.p.midi1)); + break; + case CIN_1BYTE: + switch (e.p.midi0) { + case MIDIv1_CLOCK: + handleSync(); + break; + case MIDIv1_TICK: + break; + case MIDIv1_START: + handleStart(); + break; + case MIDIv1_CONTINUE: + handleContinue(); + break; + case MIDIv1_STOP: + handleStop(); + break; + case MIDIv1_ACTIVE_SENSE: + handleActiveSense(); + break; + case MIDIv1_RESET: + handleReset(); + break; + case MIDIv1_TUNE_REQUEST: + handleTuneRequest(); + break; + + default: + break; + } + break; + } +} + + +// Try to read data from USB port & pass anything read to processing function +void USBMidi::poll(void) +{ while(available()) { + dispatchPacket(readPacket()); + } +} + +static union EVENT_t outPacket; // since we only use one at a time no point in reallocating it + +// Send Midi NOTE OFF message to a given channel, with note 0-127 and velocity 0-127 +void USBMidi::sendNoteOff(unsigned int channel, unsigned int note, unsigned int velocity) +{ + outPacket.p.cable=DEFAULT_MIDI_CABLE; + outPacket.p.cin=CIN_NOTE_OFF; + outPacket.p.midi0=MIDIv1_NOTE_OFF|(channel & 0x0f); + outPacket.p.midi1=note; + outPacket.p.midi2=velocity; + writePacket(outPacket.i); + +} + + +// Send Midi NOTE ON message to a given channel, with note 0-127 and velocity 0-127 +void USBMidi::sendNoteOn(unsigned int channel, unsigned int note, unsigned int velocity) +{ + outPacket.p.cable=DEFAULT_MIDI_CABLE; + outPacket.p.cin=CIN_NOTE_ON; + outPacket.p.midi0=MIDIv1_NOTE_ON|(channel & 0x0f); + outPacket.p.midi1=note; + outPacket.p.midi2=velocity; + writePacket(outPacket.i); + +} + +// Send a Midi VELOCITY CHANGE message to a given channel, with given note 0-127, +// and new velocity 0-127 +// Note velocity change == polyphonic aftertouch. +// Note aftertouch == channel pressure. +void USBMidi::sendVelocityChange(unsigned int channel, unsigned int note, unsigned int velocity) +{ + outPacket.p.cable=DEFAULT_MIDI_CABLE; + outPacket.p.cin=CIN_AFTER_TOUCH; + outPacket.p.midi0=MIDIv1_AFTER_TOUCH |(channel & 0x0f); + outPacket.p.midi1=note; + outPacket.p.midi2=velocity; + writePacket(outPacket.i); + +} + + +// Send a Midi CC message to a given channel, as a given controller 0-127, with given +// value 0-127 +void USBMidi::sendControlChange(unsigned int channel, unsigned int controller, unsigned int value) +{ + outPacket.p.cable=DEFAULT_MIDI_CABLE; + outPacket.p.cin=CIN_CONTROL_CHANGE; + outPacket.p.midi0=MIDIv1_CONTROL_CHANGE |(channel & 0x0f); + outPacket.p.midi1=controller; + outPacket.p.midi2=value; + writePacket(outPacket.i); + +} + +// Send a Midi PROGRAM CHANGE message to given channel, with program ID 0-127 +void USBMidi::sendProgramChange(unsigned int channel, unsigned int program) +{ + outPacket.p.cable=DEFAULT_MIDI_CABLE; + outPacket.p.cin=CIN_PROGRAM_CHANGE; + outPacket.p.midi0=MIDIv1_PROGRAM_CHANGE |(channel & 0x0f); + outPacket.p.midi1=program; + writePacket(outPacket.i); + +} + +// Send a Midi AFTER TOUCH message to given channel, with velocity 0-127 +void USBMidi::sendAfterTouch(unsigned int channel, unsigned int velocity) +{ + outPacket.p.cable=DEFAULT_MIDI_CABLE; + outPacket.p.cin=CIN_CHANNEL_PRESSURE; + outPacket.p.midi0=MIDIv1_CHANNEL_PRESSURE |(channel & 0x0f); + outPacket.p.midi1=velocity; + writePacket(outPacket.i); + +} + +// Send a Midi PITCH CHANGE message, with a 14-bit pitch (always for all channels) +void USBMidi::sendPitchChange(unsigned int pitch) +{ + outPacket.p.cable=DEFAULT_MIDI_CABLE; + outPacket.p.cin=CIN_PITCH_WHEEL; + outPacket.p.midi0=MIDIv1_PITCH_WHEEL; + outPacket.p.midi1= (uint8) pitch & 0x07F; + outPacket.p.midi2= (uint8) (pitch>>7) & 0x7f; + writePacket(outPacket.i); + +} + +// Send a Midi SONG POSITION message, with a 14-bit position (always for all channels) +void USBMidi::sendSongPosition(unsigned int position) +{ + outPacket.p.cable=DEFAULT_MIDI_CABLE; + outPacket.p.cin=CIN_3BYTE_SYS_COMMON; + outPacket.p.midi0=MIDIv1_SONG_POSITION_PTR; + outPacket.p.midi1= (uint8) position & 0x07F; + outPacket.p.midi2= (uint8) (position>>7) & 0x7f; + writePacket(outPacket.i); + +} + +// Send a Midi SONG SELECT message, with a song ID of 0-127 (always for all channels) +void USBMidi::sendSongSelect(unsigned int song) +{ + outPacket.p.cable=DEFAULT_MIDI_CABLE; + outPacket.p.cin=CIN_2BYTE_SYS_COMMON; + outPacket.p.midi0=MIDIv1_SONG_SELECT; + outPacket.p.midi1= (uint8) song & 0x07F; + writePacket(outPacket.i); + +} + +// Send a Midi TUNE REQUEST message (TUNE REQUEST is always for all channels) +void USBMidi::sendTuneRequest(void) +{ + outPacket.p.cable=DEFAULT_MIDI_CABLE; + outPacket.p.cin=CIN_1BYTE; + outPacket.p.midi0=MIDIv1_TUNE_REQUEST; + writePacket(outPacket.i); +} + + +// Send a Midi SYNC message (SYNC is always for all channels) +void USBMidi::sendSync(void) +{ + outPacket.p.cable=DEFAULT_MIDI_CABLE; + outPacket.p.cin=CIN_1BYTE; + outPacket.p.midi0=MIDIv1_CLOCK; + writePacket(outPacket.i); +} + +// Send a Midi START message (START is always for all channels) +void USBMidi::sendStart(void) +{ + outPacket.p.cable=DEFAULT_MIDI_CABLE; + outPacket.p.cin=CIN_1BYTE; + outPacket.p.midi0=MIDIv1_START ; + writePacket(outPacket.i); +} + + +// Send a Midi CONTINUE message (CONTINUE is always for all channels) +void USBMidi::sendContinue(void) +{ + outPacket.p.cable=DEFAULT_MIDI_CABLE; + outPacket.p.cin=CIN_1BYTE; + outPacket.p.midi0=MIDIv1_CONTINUE ; + writePacket(outPacket.i); +} + + +// Send a Midi STOP message (STOP is always for all channels) +void USBMidi::sendStop(void) +{ + outPacket.p.cable=DEFAULT_MIDI_CABLE; + outPacket.p.cin=CIN_1BYTE; + outPacket.p.midi0=MIDIv1_STOP ; + writePacket(outPacket.i); +} + +// Send a Midi ACTIVE SENSE message (ACTIVE SENSE is always for all channels) +void USBMidi::sendActiveSense(void) +{ + outPacket.p.cable=DEFAULT_MIDI_CABLE; + outPacket.p.cin=CIN_1BYTE; + outPacket.p.midi0=MIDIv1_ACTIVE_SENSE ; + writePacket(outPacket.i); +} + +// Send a Midi RESET message (RESET is always for all channels) +void USBMidi::sendReset(void) +{ + outPacket.p.cable=DEFAULT_MIDI_CABLE; + outPacket.p.cin=CIN_1BYTE; + outPacket.p.midi0=MIDIv1_RESET ; + writePacket(outPacket.i); +} + +const uint32 midiNoteFrequency_10ths[128] = { + 82, 87, 92, 97, 103, 109, 116, 122, 130, 138, 146, 154, 164, 173, 184, 194, + 206, 218, 231, 245, 260, 275, 291, 309, 327, 346, 367, 389, 412, 437, 462, 490, + 519, 550, 583, 617, 654, 693, 734, 778, 824, 873, 925, 980, 1038, 1100, 1165, 1235, + 1308, 1386, 1468, 1556, 1648, 1746, 1850, 1960, 2077, 2200, 2331, 2469, 2616, 2772, 2937, 3111, + 3296, 3492, 3700, 3920, 4153, 4400, 4662, 4939, 5233, 5544, 5873, 6223, 6593, 6985, 7400, 7840, + 8306, 8800, 9323, 9878, 10465, 11087, 11747, 12445, 13185, 13969, 14800, 15680, 16612, 17600, 18647, 19755, + 20930, 22175, 23493, 24890, 26370, 27938, 29600, 31360, 33224, 35200, 37293, 39511, 41860, 44349, 46986, 49780, + 52740, 55877, 59199, 62719, 66449, 70400, 74586, 79021, 83720, 88698, 93973, 99561, 105481, 111753, 118398, 125439 }; + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +// Placeholders. You should subclass the Midi base class and define these to have your +// version called. +void USBMidi::handleNoteOff(unsigned int channel, unsigned int note, unsigned int velocity) {} +void USBMidi::handleNoteOn(unsigned int channel, unsigned int note, unsigned int velocity) {} +void USBMidi::handleVelocityChange(unsigned int channel, unsigned int note, unsigned int velocity) {} +void USBMidi::handleControlChange(unsigned int channel, unsigned int controller, unsigned int value) {} +void USBMidi::handleProgramChange(unsigned int channel, unsigned int program) {} +void USBMidi::handleAfterTouch(unsigned int channel, unsigned int velocity) {} +void USBMidi::handlePitchChange(unsigned int pitch) {} +void USBMidi::handleSongPosition(unsigned int position) {} +void USBMidi::handleSongSelect(unsigned int song) {} +void USBMidi::handleTuneRequest(void) {} +void USBMidi::handleSync(void) {} +void USBMidi::handleStart(void) {} +void USBMidi::handleContinue(void) {} +void USBMidi::handleStop(void) {} +void USBMidi::handleActiveSense(void) {} +void USBMidi::handleReset(void) {} +#pragma GCC diagnostic pop diff --git a/STM32F1/libraries/USBComposite/USBMIDI.h b/STM32F1/libraries/USBComposite/USBMIDI.h new file mode 100644 index 0000000..e770047 --- /dev/null +++ b/STM32F1/libraries/USBComposite/USBMIDI.h @@ -0,0 +1,186 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2013 Magnus Lundin. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @brief Wirish USB MIDI port (MidiUSB). + */ + +#ifndef _USBMIDI_H_ +#define _USBMIDI_H_ + +//#include +#include +#include +#include "usb_generic.h" + +/* + * This is the Midi class. If you are just sending Midi data, you only need to make an + * instance of the class, passing it your USB port -- in most cases it looks like + * + * USBMidi midi; + * + * then you don't need to do anything else; you can start using it to send Midi messages, + * e.g. + * + * midi.sendNoteOn(1, note, velocity); + * + * If you are using it to receive Midi data, it's a little more complex & you will need + * to subclass the Midi class. + * + * For people not used to C++ this may look confusing, but it's actually pretty easy. + * Note that you only need to write the functions for event types you want to handle. + * They should match the names & prototypes of the functions in the class; look at + * the functions in the Midi class below that have the keyword "virtual" to see which + * ones you can use. + * + * Here's an example of one that takes NOTE ON, NOTE OFF, and CONTROL CHANGE: + * + * class MyMidi : public USBMidi { + * public: + * + * // Need this to compile; it just hands things off to the Midi class. + * MyMidi() : USBMidi(s) {} + * + * void handleNoteOn(unsigned int channel, unsigned int note, unsigned int velocity) + * { + * if (note == 40) {digitalWrite(13, HIGH); } + * } + * + * void handleNoteOff(unsigned int channel, unsigned int note, unsigned int velocity) + * { + * if (note == 40) { digitalWrite(13, LOW); } + * } + * + * void handleControlChange(unsigned int channel, unsigned int controller, + * unsigned int value) + * { + * analogWrite(6, value * 2); + * } + * + * Then you need to make an instance of this class: + * + * MyMidi midi(); + * + * If receiving Midi data, you also need to call the poll function every time through + * loop(); e.g. + * + * void loop() { + * midi.poll(); + * } + * + * This causes the Midi class to read data from the USB port and process it. + */ + +class USBMidi { +private: + bool enabled = false; + + /* Private Receive Parameters */ + + // The channel this Midi instance receives data for (0 means all channels) + int channelIn_; + + /* Internal functions */ + + // Called whenever data is read from the USB port + void dispatchPacket(uint32 packet); + +public: + //static bool init(USBMidi* me); + // This registers this USB composite device component with the USBComposite class instance. + bool registerComponent(); + void setChannel(unsigned channel=0); + unsigned getChannel() { + return channelIn_; + } + + // Call to start the USB port, at given baud. For many applications + // the default parameters are just fine (which will cause messages for all + // MIDI channels to be delivered) + void begin(unsigned int channel = 0); + //void begin(); + void end(); + + uint32 available(void); + + uint32 readPackets(void *buf, uint32 len); + uint32 readPacket(void); + + void writePacket(uint32); +// void write(const char *str); + void writePackets(const void*, uint32); + + uint8 isConnected(); + uint8 pending(); + + // poll() should be called every time through loop() IF dealing with incoming MIDI + // (if you're only SENDING MIDI events from the Arduino, you don't need to call + // poll); it causes data to be read from the USB port and processed. + void poll(); + + // Call these to send MIDI messages of the given types + void sendNoteOff(unsigned int channel, unsigned int note, unsigned int velocity); + void sendNoteOn(unsigned int channel, unsigned int note, unsigned int velocity); + void sendVelocityChange(unsigned int channel, unsigned int note, unsigned int velocity); + void sendControlChange(unsigned int channel, unsigned int controller, unsigned int value); + void sendProgramChange(unsigned int channel, unsigned int program); + void sendAfterTouch(unsigned int channel, unsigned int velocity); + void sendPitchChange(unsigned int pitch); + void sendSongPosition(unsigned int position); + void sendSongSelect(unsigned int song); + void sendTuneRequest(void); + void sendSync(void); + void sendStart(void); + void sendContinue(void); + void sendStop(void); + void sendActiveSense(void); + void sendReset(void); + + // Overload these in a subclass to get MIDI messages when they come in + virtual void handleNoteOff(unsigned int channel, unsigned int note, unsigned int velocity); + virtual void handleNoteOn(unsigned int channel, unsigned int note, unsigned int velocity); + virtual void handleVelocityChange(unsigned int channel, unsigned int note, unsigned int velocity); + virtual void handleControlChange(unsigned int channel, unsigned int controller, unsigned int value); + virtual void handleProgramChange(unsigned int channel, unsigned int program); + virtual void handleAfterTouch(unsigned int channel, unsigned int velocity); + virtual void handlePitchChange(unsigned int pitch); + virtual void handleSongPosition(unsigned int position); + virtual void handleSongSelect(unsigned int song); + virtual void handleTuneRequest(void); + virtual void handleSync(void); + virtual void handleStart(void); + virtual void handleContinue(void); + virtual void handleStop(void); + virtual void handleActiveSense(void); + virtual void handleReset(void); +}; + +extern USBMidi USBMIDI; + +extern const uint32 midiNoteFrequency_10ths[128]; + +#endif \ No newline at end of file diff --git a/STM32F1/libraries/USBComposite/USBMassStorage.cpp b/STM32F1/libraries/USBComposite/USBMassStorage.cpp new file mode 100644 index 0000000..c376e69 --- /dev/null +++ b/STM32F1/libraries/USBComposite/USBMassStorage.cpp @@ -0,0 +1,45 @@ +#include "USBMassStorage.h" +#include "usb_mass.h" +#include "usb_mass_mal.h" +#include "usb_serial.h" +#include + +void USBMassStorageDevice::begin() { + if(!enabled) { + USBComposite.clear(); + registerComponent(); + USBComposite.begin(); + + enabled = true; + } +} + +void USBMassStorageDevice::end() { + USBComposite.end(); +} + +void USBMassStorageDevice::loop() { + usb_mass_loop(); +} + +bool USBMassStorageDevice::registerComponent() { + return USBComposite.add(&usbMassPart, this); +} + +void USBMassStorageDevice::setDrive(uint32 driveNumber, uint32 byteSize, MassStorageReader reader, + MassStorageWriter writer, MassStorageStatuser statuser, MassStorageInitializer initializer) { + if (driveNumber >= USB_MASS_MAX_DRIVES) + return; + usb_mass_drives[driveNumber].blockCount = byteSize/512; + usb_mass_drives[driveNumber].read = reader; + usb_mass_drives[driveNumber].write = writer; + usb_mass_drives[driveNumber].status = statuser; + usb_mass_drives[driveNumber].init = initializer; + usb_mass_drives[driveNumber].format = initializer; +} + +void USBMassStorageDevice::clearDrives() { + memset(usb_mass_drives, 0, sizeof(usb_mass_drives)); +} + +USBMassStorageDevice MassStorage; diff --git a/STM32F1/libraries/USBComposite/USBMassStorage.h b/STM32F1/libraries/USBComposite/USBMassStorage.h new file mode 100644 index 0000000..02663ab --- /dev/null +++ b/STM32F1/libraries/USBComposite/USBMassStorage.h @@ -0,0 +1,25 @@ +#ifndef USBMASSSTORAGE_H +#define USBMASSSTORAGE_H + +#include +#include "USBComposite.h" +#include "usb_generic.h" +#include "usb_mass_mal.h" + +class USBMassStorageDevice { +private: + bool enabled = false; +public: + void begin(); + void end(); + void loop(); + void clearDrives(void); + bool registerComponent(); + void setDrive(uint32 driveNumber, uint32 byteSize, MassStorageReader reader, + MassStorageWriter writer = NULL, MassStorageStatuser = NULL, MassStorageInitializer = NULL); +}; + +extern USBMassStorageDevice MassStorage; + +#endif /* USBMASSSTORAGE_H */ + diff --git a/STM32F1/libraries/USBComposite/USBXBox360.cpp b/STM32F1/libraries/USBComposite/USBXBox360.cpp new file mode 100644 index 0000000..83237c0 --- /dev/null +++ b/STM32F1/libraries/USBComposite/USBXBox360.cpp @@ -0,0 +1,173 @@ +/* Copyright (c) 2011, Peter Barrett +** +** Permission to use, copy, modify, and/or distribute this software for +** any purpose with or without fee is hereby granted, provided that the +** above copyright notice and this permission notice appear in all copies. +** +** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR +** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES +** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +** SOFTWARE. +*/ + +/** + * @brief USB HID Keyboard device + */ + +#include +#include +#include +#include +#include "USBXBox360.h" +#include "usb_x360.h" + +void USBXBox360::sendReport(void){ + x360_tx(xbox360_Report, sizeof(xbox360_Report)); + + while (x360_is_transmitting() != 0) { + } + /* flush out to avoid having the pc wait for more data */ + x360_tx(NULL, 0); +} + +void USBXBox360::setRumbleCallback(void (*callback)(uint8 left, uint8 right)) { + x360_set_rumble_callback(callback); +} + +void USBXBox360::setLEDCallback(void (*callback)(uint8 pattern)) { + x360_set_led_callback(callback); +} + + +bool USBXBox360::init(void* ignore) { + (void)ignore; + usb_generic_set_info(0x045e, 0x028e, NULL, NULL, NULL); + return true; +} + +bool USBXBox360::registerComponent() { + return USBComposite.add(&usbX360Part, this, init); +} + +void USBXBox360::begin(void){ + if(!enabled){ + USBComposite.clear(); + registerComponent(); + USBComposite.begin(); + + enabled = true; + } +} + +void USBXBox360::end() { + if (enabled) { + enabled = false; + USBComposite.end(); + } +} + +void USBXBox360::stop(void){ + setRumbleCallback(NULL); + setLEDCallback(NULL); +} + +void USBXBox360::setManualReportMode(bool mode) { + manualReport = mode; +} + +bool USBXBox360::getManualReportMode() { + return manualReport; +} + +void USBXBox360::safeSendReport() { + if (!manualReport) { + while (x360_is_transmitting() != 0) { + } + sendReport(); + } +} + +void USBXBox360::send() { + while (x360_is_transmitting() != 0) { + } + sendReport(); +} + +void USBXBox360::button(uint8_t button, bool val){ + button--; + uint8_t mask = (1 << (button & 7)); + if (val) { + if (button < 8) xbox360_Report[2] |= mask; + else if (button < 16) xbox360_Report[3] |= mask; + } else { + mask = ~mask; + if (button < 8) xbox360_Report[2] &= mask; + else if (button < 16) xbox360_Report[3] &= mask; + } + + safeSendReport(); +} + +void USBXBox360::X(int16_t val){ + xbox360_Report[6] = val; + xbox360_Report[7] = (uint16)val >> 8; + + safeSendReport(); +} + +void USBXBox360::Y(int16_t val){ + xbox360_Report[8] = val; + xbox360_Report[9] = (uint16)val >> 8; + + safeSendReport(); +} + +void USBXBox360::XRight(int16_t val){ + xbox360_Report[0xA] = val; + xbox360_Report[0xB] = (uint16)val >> 8; + + safeSendReport(); +} + +void USBXBox360::YRight(int16_t val){ + xbox360_Report[0xC] = val; + xbox360_Report[0xD] = (uint16)val >> 8; + + safeSendReport(); +} + +void USBXBox360::position(int16_t x, int16_t y){ + xbox360_Report[6] = x; + xbox360_Report[7] = (uint16)x >> 8; + xbox360_Report[8] = y; + xbox360_Report[9] = (uint16)y >> 8; + + safeSendReport(); +} + +void USBXBox360::positionRight(int16_t x, int16_t y){ + xbox360_Report[0xA] = x; + xbox360_Report[0xB] = (uint16)x >> 8; + xbox360_Report[0xC] = y; + xbox360_Report[0xD] = (uint16)y >> 8; + + safeSendReport(); +} + +void USBXBox360::sliderLeft(uint8_t val){ + xbox360_Report[4] = val; + + safeSendReport(); +} + +void USBXBox360::sliderRight(uint8_t val){ + xbox360_Report[5] = val; + + safeSendReport(); +} + +USBXBox360 XBox360; diff --git a/STM32F1/libraries/USBComposite/USBXBox360.h b/STM32F1/libraries/USBComposite/USBXBox360.h new file mode 100644 index 0000000..e48e7a7 --- /dev/null +++ b/STM32F1/libraries/USBComposite/USBXBox360.h @@ -0,0 +1,58 @@ +/* Copyright (c) 2011, Peter Barrett +** +** Permission to use, copy, modify, and/or distribute this software for +** any purpose with or without fee is hereby granted, provided that the +** above copyright notice and this permission notice appear in all copies. +** +** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR +** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES +** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +** SOFTWARE. +*/ + +#ifndef _USBXBox360_H +#define _USBXBox360_H + +#include +#include +#include "USBComposite.h" +#include "usb_generic.h" + +class USBXBox360 { +private: + uint8_t xbox360_Report[20] = {0,0x14};// 3,0,0,0,0,0x0F,0x20,0x80,0x00,0x02,0x08,0x20,0x80}; + bool manualReport = false; + bool enabled; + void safeSendReport(void); + void sendReport(void); +public: + void send(void); + static bool init(void* ignore); + bool registerComponent(); + void stop(); + void setManualReportMode(bool manualReport); + bool getManualReportMode(); + void begin(void); + void end(void); + void button(uint8_t button, bool val); + void X(int16_t val); + void Y(int16_t val); + void position(int16_t x, int16_t y); + void positionRight(int16_t x, int16_t y); + void XRight(int16_t val); + void YRight(int16_t val); + void sliderLeft(uint8_t val); + void sliderRight(uint8_t val); + void hat(int16_t dir); + void setLEDCallback(void (*callback)(uint8 pattern)); + void setRumbleCallback(void (*callback)(uint8 left, uint8 right)); +}; + +extern USBXBox360 XBox360; + +#endif + diff --git a/STM32F1/libraries/USBComposite/examples/BootKeyboard/BootKeyboard.ino b/STM32F1/libraries/USBComposite/examples/BootKeyboard/BootKeyboard.ino new file mode 100644 index 0000000..72b42f5 --- /dev/null +++ b/STM32F1/libraries/USBComposite/examples/BootKeyboard/BootKeyboard.ino @@ -0,0 +1,15 @@ +#include + +void setup() +{ + USBHID_begin_with_serial(HID_BOOT_KEYBOARD); + BootKeyboard.begin(); // needed just in case you need LED support +} + +void loop() +{ + BootKeyboard.press(KEY_F12); + delay(100); + BootKeyboard.release(KEY_F12); + delay(1000); +} diff --git a/STM32F1/libraries/USBComposite/examples/absmouse/absmouse.ino b/STM32F1/libraries/USBComposite/examples/absmouse/absmouse.ino new file mode 100644 index 0000000..29368ea --- /dev/null +++ b/STM32F1/libraries/USBComposite/examples/absmouse/absmouse.ino @@ -0,0 +1,25 @@ +#include + +const uint8_t reportDescription[] = { + HID_ABS_MOUSE_REPORT_DESCRIPTOR(HID_MOUSE_REPORT_ID) +}; + +HIDAbsMouse mouse; + +void setup(){ + USBHID_begin_with_serial(reportDescription, sizeof(reportDescription)); + delay(1000); + mouse.move(0,0); + delay(1000); + mouse.press(MOUSE_LEFT); + mouse.move(500,500); + mouse.release(MOUSE_ALL); + mouse.click(MOUSE_RIGHT); +} + +void loop(){ + mouse.move(0,0); + delay(1000); + mouse.move(16384,16384); + delay(1000); +} diff --git a/STM32F1/libraries/USBComposite/examples/consumer/consumer.ino b/STM32F1/libraries/USBComposite/examples/consumer/consumer.ino new file mode 100644 index 0000000..9cf9c9f --- /dev/null +++ b/STM32F1/libraries/USBComposite/examples/consumer/consumer.ino @@ -0,0 +1,18 @@ +#include + +const uint8_t reportDescription[] = { + HID_CONSUMER_REPORT_DESCRIPTOR() +}; + +HIDConsumer Consumer; + +void setup(){ + USBHID_begin_with_serial(reportDescription, sizeof(reportDescription)); +} + +void loop() { + Consumer.press(HIDConsumer::BRIGHTNESS_DOWN); + Consumer.release(); + delay(500); +} + diff --git a/STM32F1/libraries/USBComposite/examples/keyboardwithleds/keyboardwithleds.ino b/STM32F1/libraries/USBComposite/examples/keyboardwithleds/keyboardwithleds.ino new file mode 100644 index 0000000..d45a312 --- /dev/null +++ b/STM32F1/libraries/USBComposite/examples/keyboardwithleds/keyboardwithleds.ino @@ -0,0 +1,14 @@ +#include + + +void setup() { + USBHID_begin_with_serial(HID_KEYBOARD); + Keyboard.begin(); // needed for LED support + delay(1000); +} + +void loop() { + CompositeSerial.println(Keyboard.getLEDs()); +} + + diff --git a/STM32F1/libraries/USBComposite/examples/mass/image.h b/STM32F1/libraries/USBComposite/examples/mass/image.h new file mode 100644 index 0000000..f96b941 --- /dev/null +++ b/STM32F1/libraries/USBComposite/examples/mass/image.h @@ -0,0 +1,67 @@ +uint8 image[11776] = { +0xEB,0x3C,0x90,0x6D,0x6B,0x64,0x6F,0x73,0x66,0x73,0x00,0x00,0x02,0x04,0x01,0x00, +0x02,0x10,0x00,0x17,0x00,0xF8,0x01,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x29,0xDB,0x32,0x73,0x5A,0x20,0x20,0x20,0x20,0x20, +0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x41,0x54,0x31,0x32,0x20,0x20,0x20,0x0E,0x1F, +0xBE,0x5B,0x7C,0xAC,0x22,0xC0,0x74,0x0B,0x56,0xB4,0x0E,0xBB,0x07,0x00,0xCD,0x10, +0x5E,0xEB,0xF0,0x32,0xE4,0xCD,0x16,0xCD,0x19,0xEB,0xFE,0x54,0x68,0x69,0x73,0x20, +0x69,0x73,0x20,0x6E,0x6F,0x74,0x20,0x61,0x20,0x62,0x6F,0x6F,0x74,0x61,0x62,0x6C, +0x65,0x20,0x64,0x69,0x73,0x6B,0x2E,0x20,0x20,0x50,0x6C,0x65,0x61,0x73,0x65,0x20, +0x69,0x6E,0x73,0x65,0x72,0x74,0x20,0x61,0x20,0x62,0x6F,0x6F,0x74,0x61,0x62,0x6C, +0x65,0x20,0x66,0x6C,0x6F,0x70,0x70,0x79,0x20,0x61,0x6E,0x64,0x0D,0x0A,0x70,0x72, +0x65,0x73,0x73,0x20,0x61,0x6E,0x79,0x20,0x6B,0x65,0x79,0x20,0x74,0x6F,0x20,0x74, +0x72,0x79,0x20,0x61,0x67,0x61,0x69,0x6E,0x20,0x2E,0x2E,0x2E,0x20,0x0D,0x0A,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x55,0xAA, +0xF8,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xF8,0xFF,0xFF, +}; diff --git a/STM32F1/libraries/USBComposite/examples/mass/mass.ino b/STM32F1/libraries/USBComposite/examples/mass/mass.ino new file mode 100644 index 0000000..e10c04e --- /dev/null +++ b/STM32F1/libraries/USBComposite/examples/mass/mass.ino @@ -0,0 +1,65 @@ +#include + +#include "image.h" + +bool write(uint32_t memoryOffset, const uint8_t *writebuff, uint16_t transferLength) { + memcpy(image+memoryOffset, writebuff, transferLength); + + return true; +} + +bool read(uint32_t memoryOffset, uint8_t *readbuff, uint16_t transferLength) { + memcpy(readbuff, image+memoryOffset, transferLength); + + return true; +} + +char hexNibble(uint8 x) { + return x < 10 ? x + '0' : x + 'A' - 10; +} + +char* format16(uint16 c) { + static char str[6]; + str[5] = 0; + char *p = str+5; + do { + *--p = (c % 10) + '0'; + c /= 10; + } while(c); + return p; +} + +void dumpDrive() { + char hex[7] = "0x11,"; + CompositeSerial.print("uint8 image["); + CompositeSerial.print(format16(sizeof(image))); + CompositeSerial.println("] = {"); + int last; + for (last=sizeof(image)-1;last>=0 && image[last] == 0;last--); + if (last<0) last=0; + + for (int i=0; i<=last; i++) { + if (i && i % 16 == 0) + CompositeSerial.println(""); + hex[2] = hexNibble(image[i]>>4); + hex[3] = hexNibble(image[i]&0xF); + CompositeSerial.print(hex); + } + CompositeSerial.println("\n};\n"); +} + +void setup() { + MassStorage.setDrive(0, sizeof(image), read, write); + MassStorage.registerComponent(); + CompositeSerial.registerComponent(); + USBComposite.begin(); + delay(2000); +} + +void loop() { + MassStorage.loop(); + if (CompositeSerial.available() && 'd' == CompositeSerial.read()) { + dumpDrive(); + } +} + diff --git a/STM32F1/libraries/USBComposite/examples/midiin/midiin.ino b/STM32F1/libraries/USBComposite/examples/midiin/midiin.ino new file mode 100644 index 0000000..20da70a --- /dev/null +++ b/STM32F1/libraries/USBComposite/examples/midiin/midiin.ino @@ -0,0 +1,27 @@ +#include + +#define SPEAKER_PIN PA0 + +class myMidi : public USBMidi { + virtual void handleNoteOff(unsigned int channel, unsigned int note, unsigned int velocity) { + noTone(SPEAKER_PIN); + } + virtual void handleNoteOn(unsigned int channel, unsigned int note, unsigned int velocity) { + tone(SPEAKER_PIN, (midiNoteFrequency_10ths[note]+5)/10); + } + +}; + +myMidi midi; + +void setup() { + pinMode(SPEAKER_PIN, OUTPUT); + midi.registerComponent(); + CompositeSerial.registerComponent(); + USBComposite.begin(); +} + +void loop() { + midi.poll(); +} + diff --git a/STM32F1/libraries/USBComposite/examples/midiout/midiout.ino b/STM32F1/libraries/USBComposite/examples/midiout/midiout.ino new file mode 100644 index 0000000..3fe98b0 --- /dev/null +++ b/STM32F1/libraries/USBComposite/examples/midiout/midiout.ino @@ -0,0 +1,17 @@ +#include + +const uint8_t notes[] = {60, 62, 64, 65, 67, 69, 71, 72, 61, 63, 66, 68, 70}; +const int numNotes = sizeof(notes)/sizeof(*notes); + +void setup() { + USBMIDI.begin(); + delay(1000); +} + +void loop() { + for (int i=0;i + +#define TXSIZE 256 +#define RXSIZE 300 + +HIDRaw raw; +uint8 buf[RXSIZE]; + +const uint8_t reportDescription[] = { + HID_RAW_REPORT_DESCRIPTOR(TXSIZE,RXSIZE) +}; + +void setup(){ + USBHID_begin_with_serial(reportDescription, sizeof(reportDescription)); + raw.begin(); +} + +void loop() { + if (raw.getOutput(buf)) { + for (int i=0;i +#include +#include "SdFat.h" + +#define LED_PIN PB12 + +SdFatEX sd; +const uint32_t speed = SPI_CLOCK_DIV2 ; +const uint8_t SD_CHIP_SELECT = SS; +bool enabled = false; +uint32 cardSize; + +bool write(uint32_t memoryOffset, const uint8_t *writebuff, uint16_t transferLength) { + return sd.card()->writeBlocks(memoryOffset/512, writebuff, transferLength/512); +} + +bool read(uint32_t memoryOffset, uint8_t *readbuff, uint16_t transferLength) { + return sd.card()->readBlocks(memoryOffset/512, readbuff, transferLength/512); +} + +void setup() { + pinMode(LED_PIN,OUTPUT); + digitalWrite(LED_PIN,1); +} + +void initReader() { + digitalWrite(LED_PIN,0); + cardSize = sd.card()->cardSize(); + MassStorage.setDrive(0, cardSize*512, read, write); + MassStorage.registerComponent(); + CompositeSerial.registerComponent(); + USBComposite.begin(); + enabled=true; +} + +void loop() { + if (!enabled) { + if (sd.begin(SD_CHIP_SELECT)) { + initReader(); + } + else { + delay(50); + } + } + else { + MassStorage.loop(); + } +} + diff --git a/STM32F1/libraries/USBComposite/examples/simplejoystick/simplejoystick.ino b/STM32F1/libraries/USBComposite/examples/simplejoystick/simplejoystick.ino new file mode 100644 index 0000000..f0c75df --- /dev/null +++ b/STM32F1/libraries/USBComposite/examples/simplejoystick/simplejoystick.ino @@ -0,0 +1,13 @@ +#include + +void setup() { + USBHID_begin_with_serial(HID_JOYSTICK); +} + +void loop() { + Joystick.X(0); + delay(500); + Joystick.X(1023); + delay(500); +} + diff --git a/STM32F1/libraries/USBComposite/examples/simplekeyboard/simplekeyboard.ino b/STM32F1/libraries/USBComposite/examples/simplekeyboard/simplekeyboard.ino new file mode 100644 index 0000000..80c296f --- /dev/null +++ b/STM32F1/libraries/USBComposite/examples/simplekeyboard/simplekeyboard.ino @@ -0,0 +1,13 @@ +#include + +void setup() { + USBHID_begin_with_serial(HID_KEYBOARD); + Keyboard.begin(); // useful to detect host capslock state and LEDs + delay(1000); +} + +void loop() { + Keyboard.println("Hello world"); + delay(10000); +} + diff --git a/STM32F1/libraries/USBComposite/examples/softjoystick/send.py b/STM32F1/libraries/USBComposite/examples/softjoystick/send.py new file mode 100644 index 0000000..5025db9 --- /dev/null +++ b/STM32F1/libraries/USBComposite/examples/softjoystick/send.py @@ -0,0 +1,60 @@ +from pywinusb import hid +from time import sleep + +REPORT_ID = 20 +HID_REPORT_FEATURE = 3 + +device = hid.HidDeviceFilter(vendor_id = 0x1EAF).get_devices()[0] # , product_id = 0x0024 +print(device) +device.open() + +""" + uint8_t reportID; + uint32_t buttons; + unsigned hat:4; + unsigned x:10; + unsigned y:10; + unsigned rx:10; + unsigned ry:10; + unsigned sliderLeft:10; + unsigned sliderRight:10; +""" + +def toBits(n,bits): + return tuple((n>>i)&1 for i in range(bits)) + +def getByteFromBits(bits,n): + out = 0 + for i in range(8): + out += bits[8*n+i] << i + return out + +def joystickData(reportID=REPORT_ID, buttons=0, hat=15, x=512, y=512, rx=512, ry=512, sliderLeft=512, sliderRight=512): + joyData = ( toBits(reportID,8) + toBits(buttons,32) + toBits(hat,4) + toBits(x,10) + toBits(y,10) + + toBits(rx,10) + toBits(ry,10) + toBits(sliderLeft,10) + toBits(sliderRight,10) ) + out = [getByteFromBits(joyData,n) for n in range(13)] + print(out) + return out + +myReport = None + +for report in device.find_feature_reports(): + if report.report_id == REPORT_ID and report.report_type == "Feature": + myReport = report + break +if myReport is None: + for report in device.find_output_reports(): + if report.report_id == REPORT_ID and report.report_type == "Output": + myReport = report + break + +assert myReport is not None + +while True: + myReport.set_raw_data(joystickData(buttons=7,x=0,y=0)) + + myReport.send() + sleep(0.5) + myReport.set_raw_data(joystickData(buttons=0,x=1023,y=1023)) + myReport.send() + sleep(0.5) diff --git a/STM32F1/libraries/USBComposite/examples/softjoystick/softjoystick.ino b/STM32F1/libraries/USBComposite/examples/softjoystick/softjoystick.ino new file mode 100644 index 0000000..0fe9b55 --- /dev/null +++ b/STM32F1/libraries/USBComposite/examples/softjoystick/softjoystick.ino @@ -0,0 +1,47 @@ +// This is a silly project: you send a feature +// report from the PC, and it becomes a joystick setting. +// I guess it's not completely useless as it lets you +// get vJoy functionality without special vJoy drivers. + +#include + +#define DATA_SIZE (sizeof(JoystickReport_t)-1) + +class HIDJoystickRawData : public HIDJoystick { + private: + uint8_t featureData[HID_BUFFER_ALLOCATE_SIZE(DATA_SIZE,1)]; + HIDBuffer_t fb { featureData, HID_BUFFER_SIZE(DATA_SIZE,1), HID_JOYSTICK_REPORT_ID }; + public: + HIDJoystickRawData(uint8_t reportID=HID_JOYSTICK_REPORT_ID) : HIDJoystick(reportID) {} + + void begin() { + USBHID.setFeatureBuffers(&fb, 1); + } + + void setRawData(JoystickReport_t* p) { + joyReport = *p; + send(); + } +}; + +HIDJoystickRawData joy; +JoystickReport_t report = {HID_JOYSTICK_REPORT_ID}; + +const uint8_t reportDescription[] = { + HID_JOYSTICK_REPORT_DESCRIPTOR(HID_JOYSTICK_REPORT_ID, + HID_FEATURE_REPORT_DESCRIPTOR(DATA_SIZE)) +}; + +void setup() { + USBHID_begin_with_serial(reportDescription, sizeof(reportDescription)); + joy.begin(); +} + +void loop() { + if (joy.getFeature(1+(uint8_t*)&report)) { + joy.setRawData(&report); + } + + delay(5); +} + diff --git a/STM32F1/libraries/USBComposite/examples/twojoysticks/twojoysticks.ino b/STM32F1/libraries/USBComposite/examples/twojoysticks/twojoysticks.ino new file mode 100644 index 0000000..7cf929d --- /dev/null +++ b/STM32F1/libraries/USBComposite/examples/twojoysticks/twojoysticks.ino @@ -0,0 +1,40 @@ +#include + +const uint8_t reportDescription[] = { + HID_MOUSE_REPORT_DESCRIPTOR(), + HID_KEYBOARD_REPORT_DESCRIPTOR(), + HID_JOYSTICK_REPORT_DESCRIPTOR(), + HID_JOYSTICK_REPORT_DESCRIPTOR(HID_JOYSTICK_REPORT_ID+1), +}; + +HIDJoystick Joystick2(HID_JOYSTICK_REPORT_ID+1); + +void setup(){ + USBHID_begin_with_serial(reportDescription, sizeof(reportDescription)); + Joystick.setManualReportMode(true); + Joystick2.setManualReportMode(true); +} + +void loop(){ + Joystick.X(0); + Joystick.Y(0); + Joystick.sliderRight(1023); + Joystick.send(); + delay(400); + Joystick.X(1023); + Joystick.Y(1023); + Joystick.sliderRight(0); + Joystick.send(); + delay(400); + Joystick2.X(0); + Joystick2.Y(0); + Joystick2.sliderRight(1023); + Joystick2.send(); + delay(400); + Joystick2.X(1023); + Joystick2.Y(1023); + Joystick2.sliderRight(0); + Joystick2.send(); + delay(400); +} + diff --git a/STM32F1/libraries/USBComposite/examples/x360/x360.ino b/STM32F1/libraries/USBComposite/examples/x360/x360.ino new file mode 100644 index 0000000..d97a7f3 --- /dev/null +++ b/STM32F1/libraries/USBComposite/examples/x360/x360.ino @@ -0,0 +1,15 @@ +#include + +void setup() { + XBox360.begin(); + delay(1000); +} + +void loop() { + XBox360.X(-32767); + XBox360.Y(-32767); + delay(1000); + XBox360.X(32767); + XBox360.Y(32767); + delay(1000); +} diff --git a/STM32F1/libraries/USBComposite/keywords.txt b/STM32F1/libraries/USBComposite/keywords.txt new file mode 100644 index 0000000..3092c00 --- /dev/null +++ b/STM32F1/libraries/USBComposite/keywords.txt @@ -0,0 +1,89 @@ +####################################### +# Syntax Coloring Map USBHID +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +HID KEYWORD1 +Joystick KEYWORD1 +Keyboard KEYWORD1 +Mouse KEYWORD1 +CompositeSerial KEYWORD1 +XBox360 KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +begin KEYWORD2 +end KEYWORD2 +XRight KEYWORD2 +YRight KEYWORD2 +Yrotate KEYWORD2 +Y KEYWORD2 +Xrotate KEYWORD2 +X KEYWORD2 +sliderLeft KEYWORD2 +sliderRight KEYWORD2 +button KEYWORD2 +hat KEYWORD2 +setManualReportMode KEYWORD2 +getManualReportMode KEYWORD2 +release KEYWORD2 +press KEYWORD2 +releaseAll KEYWORD2 +move KEYWORD2 +send KEYWORD2 +click KEYWORD2 + + +####################################### +# Constants (LITERAL1) +####################################### +USB_HID_MOUSE LITERAL1 +USB_HID_KEYBOARD LITERAL1 +USB_HID_JOYSTICK LITERAL1 +USB_HID_KEYBOARD_MOUSE LITERAL1 +USB_HID_KEYBOARD_MOUSE_JOYSTICK LITERAL1 +USB_HID_KEYBOARD_JOYSTICK LITERAL1 +KEY_LEFT_CTRL LITERAL1 +KEY_LEFT_SHIFT LITERAL1 +KEY_LEFT_ALT LITERAL1 +KEY_LEFT_GUI LITERAL1 +KEY_RIGHT_CTRL LITERAL1 +KEY_RIGHT_SHIFT LITERAL1 +KEY_RIGHT_ALT LITERAL1 +KEY_RIGHT_GUI LITERAL1 +KEY_UP_ARROW LITERAL1 +KEY_DOWN_ARROW LITERAL1 +KEY_LEFT_ARROW LITERAL1 +KEY_RIGHT_ARROW LITERAL1 +KEY_BACKSPACE LITERAL1 +KEY_TAB LITERAL1 +KEY_RETURN LITERAL1 +KEY_ESC LITERAL1 +KEY_INSERT LITERAL1 +KEY_DELETE LITERAL1 +KEY_PAGE_UP LITERAL1 +KEY_PAGE_DOWN LITERAL1 +KEY_HOME LITERAL1 +KEY_END LITERAL1 +KEY_CAPS_LOCK LITERAL1 +KEY_F1 LITERAL1 +KEY_F2 LITERAL1 +KEY_F3 LITERAL1 +KEY_F4 LITERAL1 +KEY_F5 LITERAL1 +KEY_F6 LITERAL1 +KEY_F7 LITERAL1 +KEY_F8 LITERAL1 +KEY_F9 LITERAL1 +KEY_F10 LITERAL1 +KEY_F11 LITERAL1 +KEY_F12 LITERAL1 +MOUSE_LEFT LITERAL1 +MOUSE_MIDDLE LITERAL1 +MOUSE_RIGHT LITERAL1 +MOUSE_ALL LITERAL1 +HIDConsumer LITERAL1 diff --git a/STM32F1/libraries/USBComposite/library.properties b/STM32F1/libraries/USBComposite/library.properties new file mode 100644 index 0000000..1d8c2cb --- /dev/null +++ b/STM32F1/libraries/USBComposite/library.properties @@ -0,0 +1,10 @@ +name=USBComposite for STM32F1 +version=0.64 +author=Various +email=arpruss@gmail.com +sentence=USB HID / MIDI / mass storage library for STM32F1 +paragraph=USB HID / MIDI / mass storage library for STM32F1 +url=https://github.com/arpruss/USBHID_stm32f1 +architectures=STM32F1 +maintainer=arpruss@gmail.com +category=Communication \ No newline at end of file diff --git a/STM32F1/libraries/USBComposite/usb_generic.c b/STM32F1/libraries/USBComposite/usb_generic.c new file mode 100644 index 0000000..c9ed0b3 --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_generic.c @@ -0,0 +1,531 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/usb/stm32f1/usb_hid.c + * @brief USB HID (human interface device) support + * + * FIXME: this works on the STM32F1 USB peripherals, and probably no + * place else. Nonportable bits really need to be factored out, and + * the result made cleaner. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include + + +//uint16 GetEPTxAddr(uint8 /*bEpNum*/); + +/* usb_lib headers */ +#include "usb_type.h" +#include "usb_core.h" +#include "usb_def.h" + +#include "usb_generic.h" + +// Are we currently sending an IN packet? +volatile int8 usbGenericTransmitting = -1; + +static uint8* usbGetConfigDescriptor(uint16 length); +static void usbInit(void); +static void usbReset(void); +static void usbClearFeature(void); +static void usbSetConfiguration(void); +static RESULT usbDataSetup(uint8 request); +static RESULT usbNoDataSetup(uint8 request); +static RESULT usbGetInterfaceSetting(uint8 interface, uint8 alt_setting); +static uint8* usbGetStringDescriptor(uint16 length); +static uint8* usbGetConfigDescriptor(uint16 length); +static uint8* usbGetDeviceDescriptor(uint16 length); +static void usbSetConfiguration(void); +static void usbSetDeviceAddress(void); + +#define LEAFLABS_ID_VENDOR 0x1EAF +#define MAPLE_ID_PRODUCT 0x0004 // was 0x0024 +#define USB_DEVICE_CLASS 0x00 +#define USB_DEVICE_SUBCLASS 0x00 +#define DEVICE_PROTOCOL 0x01 +#define HID_DESCRIPTOR_TYPE 0x21 + +static usb_descriptor_device usbGenericDescriptor_Device = + { + .bLength = sizeof(usb_descriptor_device), + .bDescriptorType = USB_DESCRIPTOR_TYPE_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = USB_DEVICE_CLASS, + .bDeviceSubClass = USB_DEVICE_SUBCLASS, + .bDeviceProtocol = DEVICE_PROTOCOL, + .bMaxPacketSize0 = 0x40, + .idVendor = LEAFLABS_ID_VENDOR, + .idProduct = MAPLE_ID_PRODUCT, + .bcdDevice = 0x0200, + .iManufacturer = 0x01, + .iProduct = 0x02, + .iSerialNumber = 0x00, + .bNumConfigurations = 0x01, +}; + +typedef struct { + usb_descriptor_config_header Config_Header; + uint8 descriptorData[MAX_USB_DESCRIPTOR_DATA_SIZE]; +} __packed usb_descriptor_config; + +static usb_descriptor_config usbConfig; + +#define MAX_POWER (100 >> 1) + +static const usb_descriptor_config_header Base_Header = { + .bLength = sizeof(usb_descriptor_config_header), + .bDescriptorType = USB_DESCRIPTOR_TYPE_CONFIGURATION, + .wTotalLength = 0, + .bNumInterfaces = 0, + .bConfigurationValue = 0x01, + .iConfiguration = 0x00, + .bmAttributes = (USB_CONFIG_ATTR_BUSPOWERED | + USB_CONFIG_ATTR_SELF_POWERED), + .bMaxPower = MAX_POWER, +}; + +static ONE_DESCRIPTOR Device_Descriptor = { + (uint8*)&usbGenericDescriptor_Device, + sizeof(usb_descriptor_device) +}; + +static ONE_DESCRIPTOR Config_Descriptor = { + (uint8*)&usbConfig, + 0 +}; + +static DEVICE my_Device_Table = { + .Total_Endpoint = 0, + .Total_Configuration = 1 +}; + +/* Unicode language identifier: 0x0409 is US English */ +/* FIXME move to Wirish */ +static const usb_descriptor_string usbHIDDescriptor_LangID = { + .bLength = USB_DESCRIPTOR_STRING_LEN(1), + .bDescriptorType = USB_DESCRIPTOR_TYPE_STRING, + .bString = {0x09, 0x04}, +}; + +#define default_iManufacturer_length 8 +const usb_descriptor_string usb_generic_default_iManufacturer = { + .bLength = USB_DESCRIPTOR_STRING_LEN(default_iManufacturer_length), + .bDescriptorType = USB_DESCRIPTOR_TYPE_STRING, + .bString = {'L', 0, 'e', 0, 'a', 0, 'f', 0, 'L', 0, 'a', 0, 'b', 0, 's', 0}, +}; + +#define default_iProduct_length 5 +const usb_descriptor_string usb_generic_default_iProduct = { + .bLength = USB_DESCRIPTOR_STRING_LEN(default_iProduct_length), + .bDescriptorType = USB_DESCRIPTOR_TYPE_STRING, + .bString = {'M', 0, 'a', 0, 'p', 0, 'l', 0, 'e', 0}, +}; + + +#define MAX_PACKET_SIZE 0x40 /* 64B, maximum for USB FS Devices */ +static DEVICE_PROP my_Device_Property = { + .Init = usbInit, + .Reset = usbReset, + .Process_Status_IN = NOP_Process, + .Process_Status_OUT = NOP_Process, + .Class_Data_Setup = usbDataSetup, + .Class_NoData_Setup = usbNoDataSetup, + .Class_Get_Interface_Setting = usbGetInterfaceSetting, + .GetDeviceDescriptor = usbGetDeviceDescriptor, + .GetConfigDescriptor = usbGetConfigDescriptor, + .GetStringDescriptor = usbGetStringDescriptor, + .RxEP_buffer = NULL, + .MaxPacketSize = MAX_PACKET_SIZE +}; + +static const USER_STANDARD_REQUESTS my_User_Standard_Requests = { + .User_GetConfiguration = NOP_Process, + .User_SetConfiguration = usbSetConfiguration, + .User_GetInterface = NOP_Process, + .User_SetInterface = NOP_Process, + .User_GetStatus = NOP_Process, + .User_ClearFeature = usbClearFeature, + .User_SetEndPointFeature = NOP_Process, + .User_SetDeviceFeature = NOP_Process, + .User_SetDeviceAddress = usbSetDeviceAddress +}; + +static uint8 numStringDescriptors = 3; + + +#define MAX_STRING_DESCRIPTORS 4 +static ONE_DESCRIPTOR String_Descriptor[MAX_STRING_DESCRIPTORS] = { + {(uint8*)&usbHIDDescriptor_LangID, USB_DESCRIPTOR_STRING_LEN(1)}, + {(uint8*)&usb_generic_default_iManufacturer, USB_DESCRIPTOR_STRING_LEN(default_iManufacturer_length)}, + {(uint8*)&usb_generic_default_iProduct, USB_DESCRIPTOR_STRING_LEN(default_iProduct_length)}, + {NULL, 0}, +}; + +static USBCompositePart** parts; +static uint32 numParts; +static DEVICE saved_Device_Table; +static DEVICE_PROP saved_Device_Property; +static USER_STANDARD_REQUESTS saved_User_Standard_Requests; + +static void (*ep_int_in[7])(void); +static void (*ep_int_out[7])(void); + +uint8 usb_generic_set_parts(USBCompositePart** _parts, unsigned _numParts) { + parts = _parts; + numParts = _numParts; + unsigned numInterfaces = 0; + unsigned numEndpoints = 1; + uint16 usbDescriptorSize = 0; + uint16 pmaOffset = USB_EP0_RX_BUFFER_ADDRESS + USB_EP0_BUFFER_SIZE; + + for (unsigned i = 0 ; i < 7 ; i++) { + ep_int_in[i] = NOP_Process; + ep_int_out[i] = NOP_Process; + } + + usbDescriptorSize = 0; + for (unsigned i = 0 ; i < _numParts ; i++ ) { + parts[i]->startInterface = numInterfaces; + numInterfaces += parts[i]->numInterfaces; + if (numEndpoints + parts[i]->numEndpoints > 8) { + return 0; + } + if (usbDescriptorSize + parts[i]->descriptorSize > MAX_USB_DESCRIPTOR_DATA_SIZE) { + return 0; + } + parts[i]->startEndpoint = numEndpoints; + USBEndpointInfo* ep = parts[i]->endpoints; + for (unsigned j = 0 ; j < parts[i]->numEndpoints ; j++) { + if (ep[j].bufferSize + pmaOffset > PMA_MEMORY_SIZE) { + return 0; + } + ep[j].pmaAddress = pmaOffset; + pmaOffset += ep[j].bufferSize; + ep[j].address = numEndpoints; + if (ep[j].callback == NULL) + ep[j].callback = NOP_Process; + if (ep[j].tx) { + ep_int_in[numEndpoints - 1] = ep[j].callback; + } + else { + ep_int_out[numEndpoints - 1] = ep[j].callback; + } + numEndpoints++; + } + parts[i]->getPartDescriptor(usbConfig.descriptorData + usbDescriptorSize); + usbDescriptorSize += parts[i]->descriptorSize; + } + + usbConfig.Config_Header = Base_Header; + usbConfig.Config_Header.bNumInterfaces = numInterfaces; + usbConfig.Config_Header.wTotalLength = usbDescriptorSize + sizeof(Base_Header); + Config_Descriptor.Descriptor_Size = usbConfig.Config_Header.wTotalLength; + + my_Device_Table.Total_Endpoint = numEndpoints; + + return 1; +} + +void usb_generic_set_info( uint16 idVendor, uint16 idProduct, const uint8* iManufacturer, const uint8* iProduct, const uint8* iSerialNumber) { + if (idVendor != 0) + usbGenericDescriptor_Device.idVendor = idVendor; + else + usbGenericDescriptor_Device.idVendor = LEAFLABS_ID_VENDOR; + + if (idProduct != 0) + usbGenericDescriptor_Device.idProduct = idProduct; + else + usbGenericDescriptor_Device.idProduct = MAPLE_ID_PRODUCT; + + if (iManufacturer == NULL) { + iManufacturer = (uint8*)&usb_generic_default_iManufacturer; + } + + String_Descriptor[1].Descriptor = (uint8*)iManufacturer; + String_Descriptor[1].Descriptor_Size = iManufacturer[0]; + + if (iProduct == NULL) { + iProduct = (uint8*)&usb_generic_default_iProduct; + } + + String_Descriptor[2].Descriptor = (uint8*)iProduct; + String_Descriptor[2].Descriptor_Size = iProduct[0]; + + if (iSerialNumber == NULL) { + numStringDescriptors = 3; + usbGenericDescriptor_Device.iSerialNumber = 0; + } + else { + String_Descriptor[3].Descriptor = (uint8*)iSerialNumber; + String_Descriptor[3].Descriptor_Size = iSerialNumber[0]; + numStringDescriptors = 4; + usbGenericDescriptor_Device.iSerialNumber = 3; + } +} + +void usb_generic_enable(void) { + /* Present ourselves to the host. Writing 0 to "disc" pin must + * pull USB_DP pin up while leaving USB_DM pulled down by the + * transceiver. See USB 2.0 spec, section 7.1.7.3. */ + +#ifdef GENERIC_BOOTLOADER + //Reset the USB interface on generic boards - developed by Victor PV + gpio_set_mode(GPIOA, 12, GPIO_OUTPUT_PP); + gpio_write_bit(GPIOA, 12, 0); + + for(volatile unsigned int i=0;i<512;i++);// Only small delay seems to be needed + gpio_set_mode(GPIOA, 12, GPIO_INPUT_FLOATING); +#endif + + if (BOARD_USB_DISC_DEV != NULL) { + gpio_set_mode(BOARD_USB_DISC_DEV, (uint8)(uint32)BOARD_USB_DISC_BIT, GPIO_OUTPUT_PP); + gpio_write_bit(BOARD_USB_DISC_DEV, (uint8)(uint32)BOARD_USB_DISC_BIT, 0); + } + + saved_Device_Table = Device_Table; + saved_Device_Property = Device_Property; + saved_User_Standard_Requests = User_Standard_Requests; + Device_Table = my_Device_Table; + Device_Property = my_Device_Property; + User_Standard_Requests = my_User_Standard_Requests; + + /* Initialize the USB peripheral. */ + usb_init_usblib(USBLIB, ep_int_in, ep_int_out); +} + +static void usbInit(void) { + pInformation->Current_Configuration = 0; + + USB_BASE->CNTR = USB_CNTR_FRES; + + USBLIB->irq_mask = 0; + USB_BASE->CNTR = USBLIB->irq_mask; + USB_BASE->ISTR = 0; + USBLIB->irq_mask = USB_CNTR_RESETM | USB_CNTR_SUSPM | USB_CNTR_WKUPM; + USB_BASE->CNTR = USBLIB->irq_mask; + + USB_BASE->ISTR = 0; + USBLIB->irq_mask = USB_ISR_MSK; + USB_BASE->CNTR = USBLIB->irq_mask; + + nvic_irq_enable(NVIC_USB_LP_CAN_RX0); + + for (unsigned i = 0 ; i < numParts ; i++) + if(parts[i]->usbInit != NULL) + parts[i]->usbInit(); + + USBLIB->state = USB_UNCONNECTED; +} + +#define BTABLE_ADDRESS 0x00 + +static void usbReset(void) { + pInformation->Current_Configuration = 0; + + /* current feature is current bmAttributes */ + pInformation->Current_Feature = (USB_CONFIG_ATTR_BUSPOWERED | + USB_CONFIG_ATTR_SELF_POWERED); + + USB_BASE->BTABLE = BTABLE_ADDRESS; + + /* setup control endpoint 0 */ + usb_set_ep_type(USB_EP0, USB_EP_EP_TYPE_CONTROL); + usb_set_ep_tx_stat(USB_EP0, USB_EP_STAT_TX_STALL); + usb_set_ep_rx_addr(USB_EP0, USB_EP0_RX_BUFFER_ADDRESS); + usb_set_ep_tx_addr(USB_EP0, USB_EP0_TX_BUFFER_ADDRESS); + usb_clear_status_out(USB_EP0); + + usb_set_ep_rx_count(USB_EP0, USB_EP0_BUFFER_SIZE); + usb_set_ep_rx_stat(USB_EP0, USB_EP_STAT_RX_VALID); + + for (unsigned i = 0 ; i < numParts ; i++) { + for (unsigned j = 0 ; j < parts[i]->numEndpoints ; j++) { + USBEndpointInfo* e = &(parts[i]->endpoints[j]); + uint8 address = e->address; + usb_set_ep_type(address, e->type); + if (parts[i]->endpoints[j].tx) { + usb_set_ep_tx_addr(address, e->pmaAddress); + usb_set_ep_tx_stat(address, USB_EP_STAT_TX_NAK); + usb_set_ep_rx_stat(address, USB_EP_STAT_RX_DISABLED); + } + else { + usb_set_ep_rx_addr(address, e->pmaAddress); + usb_set_ep_rx_count(address, e->bufferSize); + usb_set_ep_rx_stat(address, USB_EP_STAT_RX_VALID); + } + } + if (parts[i]->usbReset != NULL) + parts[i]->usbReset(); + } + + usbGenericTransmitting = -1; + + USBLIB->state = USB_ATTACHED; + SetDeviceAddress(0); + +} + +static void usb_power_down(void) { + USB_BASE->CNTR = USB_CNTR_FRES; + USB_BASE->ISTR = 0; + USB_BASE->CNTR = USB_CNTR_FRES + USB_CNTR_PDWN; +} + +void usb_generic_disable(void) { + /* Turn off the interrupt and signal disconnect (see e.g. USB 2.0 + * spec, section 7.1.7.3). */ + nvic_irq_disable(NVIC_USB_LP_CAN_RX0); + + if (BOARD_USB_DISC_DEV != NULL) { + gpio_write_bit(BOARD_USB_DISC_DEV, (uint8)(uint32)BOARD_USB_DISC_BIT, 1); + } + + usb_power_down(); + + Device_Table = saved_Device_Table; + Device_Property = saved_Device_Property; + User_Standard_Requests = saved_User_Standard_Requests; +} + +static RESULT usbDataSetup(uint8 request) { + uint8* (*CopyRoutine)(uint16) = 0; + + if(Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT) && request == GET_DESCRIPTOR && + pInformation->USBwValue1 == HID_DESCRIPTOR_TYPE){ + CopyRoutine = usbGetConfigDescriptor; + } + + if (CopyRoutine == NULL){ + for (unsigned i = 0 ; i < numParts ; i++) { + RESULT r = parts[i]->usbDataSetup(request); + if (USB_UNSUPPORT != r) + return r; + } + return USB_UNSUPPORT; + } + + pInformation->Ctrl_Info.CopyData = CopyRoutine; + pInformation->Ctrl_Info.Usb_wOffset = 0; + (*CopyRoutine)(0); + return USB_SUCCESS; +} + +static RESULT usbNoDataSetup(uint8 request) { + for (unsigned i = 0 ; i < numParts ; i++) { + RESULT r = parts[i]->usbNoDataSetup(request); + if (USB_UNSUPPORT != r) + return r; + } + + return USB_UNSUPPORT; +} + +static void usbSetConfiguration(void) { + if (pInformation->Current_Configuration != 0) { + USBLIB->state = USB_CONFIGURED; + } + for (unsigned i = 0 ; i < numParts ; i++) { + if (parts[i]->usbSetConfiguration != NULL) + parts[i]->usbSetConfiguration(); + } +} + +static void usbClearFeature(void) { + for (unsigned i = 0 ; i < numParts ; i++) { + if (parts[i]->usbClearFeature != NULL) + parts[i]->usbClearFeature(); + } +} + +static void usbSetDeviceAddress(void) { + USBLIB->state = USB_ADDRESSED; +} + +static uint8* usbGetDeviceDescriptor(uint16 length) { + return Standard_GetDescriptorData(length, &Device_Descriptor); +} + +static uint8* usbGetConfigDescriptor(uint16 length) { + return Standard_GetDescriptorData(length, &Config_Descriptor); +} + +static uint8* usbGetStringDescriptor(uint16 length) { + uint8 wValue0 = pInformation->USBwValue0; + + if (wValue0 >= numStringDescriptors) { + return NULL; + } + return Standard_GetDescriptorData(length, &String_Descriptor[wValue0]); +} + + +static RESULT usbGetInterfaceSetting(uint8 interface, uint8 alt_setting) { + if (alt_setting > 0) { + return USB_UNSUPPORT; + } else if (interface >= usbConfig.Config_Header.bNumInterfaces) { + return USB_UNSUPPORT; + } + + return USB_SUCCESS; +} + +void usb_copy_to_pma(const uint8 *buf, uint16 len, uint16 pma_offset) { + uint16 *dst = (uint16*)usb_pma_ptr(pma_offset); + uint16 n = len >> 1; + uint16 i; + for (i = 0; i < n; i++) { + *dst = (uint16)(*buf) | *(buf + 1) << 8; + buf += 2; + dst += 2; + } + if (len & 1) { + *dst = *buf; + } +} + +void usb_copy_from_pma(uint8 *buf, uint16 len, uint16 pma_offset) { + uint32 *src = (uint32*)usb_pma_ptr(pma_offset); + uint16 *dst = (uint16*)buf; + uint16 n = len >> 1; + uint16 i; + for (i = 0; i < n; i++) { + *dst++ = *src++; + } + if (len & 1) { + *dst = *src & 0xFF; + } +} + diff --git a/STM32F1/libraries/USBComposite/usb_generic.h b/STM32F1/libraries/USBComposite/usb_generic.h new file mode 100644 index 0000000..d665d8f --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_generic.h @@ -0,0 +1,60 @@ +#ifndef _USB_GENERIC_H +#define _USB_GENERIC_H +#include +typedef unsigned short u16; +typedef unsigned char u8; +#include +#include + +#define PMA_MEMORY_SIZE 512 +#define MAX_USB_DESCRIPTOR_DATA_SIZE 200 + +#define USB_EP0_BUFFER_SIZE 0x40 +#define USB_EP0_TX_BUFFER_ADDRESS 0x40 +#define USB_EP0_RX_BUFFER_ADDRESS (USB_EP0_TX_BUFFER_ADDRESS+USB_EP0_BUFFER_SIZE) + +#ifdef __cplusplus +extern "C" { +#endif + +extern const usb_descriptor_string usb_generic_default_iManufacturer; +extern const usb_descriptor_string usb_generic_default_iProduct; + +typedef struct USBEndpointInfo { + void (*callback)(void); + uint16 bufferSize; + uint16 type; // bulk, interrupt, etc. + uint8 tx; // 1 if TX, 0 if RX + uint8 address; + uint16 pmaAddress; +} USBEndpointInfo; + +typedef struct USBCompositePart { + uint8 numInterfaces; + uint8 numEndpoints; + uint8 startInterface; + uint8 startEndpoint; + uint16 descriptorSize; + void (*getPartDescriptor)(uint8* out); + void (*usbInit)(void); + void (*usbReset)(void); + void (*usbSetConfiguration)(void); + void (*usbClearFeature)(void); + RESULT (*usbDataSetup)(uint8 request); + RESULT (*usbNoDataSetup)(uint8 request); + USBEndpointInfo* endpoints; +} USBCompositePart; + +void usb_generic_set_info(uint16 idVendor, uint16 idProduct, const uint8* iManufacturer, const uint8* iProduct, const uint8* iSerialNumber); +uint8 usb_generic_set_parts(USBCompositePart** _parts, unsigned _numParts); +void usb_generic_disable(void); +void usb_generic_enable(void); +extern volatile int8 usbGenericTransmitting; +void usb_copy_from_pma(uint8 *buf, uint16 len, uint16 pma_offset); +void usb_copy_to_pma(const uint8 *buf, uint16 len, uint16 pma_offset); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/STM32F1/libraries/USBComposite/usb_hid.c b/STM32F1/libraries/USBComposite/usb_hid.c new file mode 100644 index 0000000..162cd4a --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_hid.c @@ -0,0 +1,578 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/usb/stm32f1/usb_hid.c + * @brief USB HID (human interface device) support + * + * FIXME: this works on the STM32F1 USB peripherals, and probably no + * place else. Nonportable bits really need to be factored out, and + * the result made cleaner. + */ + +#include "usb_hid.h" +#include +#include +#include +#include + +/* Private headers */ +#include "usb_lib_globals.h" +#include "usb_reg_map.h" + +uint16 GetEPTxAddr(uint8 /*bEpNum*/); + +/* usb_lib headers */ +#include "usb_type.h" +#include "usb_core.h" +#include "usb_def.h" + +static uint32 ProtocolValue = 0; + +static void hidDataTxCb(void); +static void hidUSBReset(void); +static RESULT hidUSBDataSetup(uint8 request); +static RESULT hidUSBNoDataSetup(uint8 request); +//static RESULT usbGetInterfaceSetting(uint8 interface, uint8 alt_setting); +static uint8* HID_GetReportDescriptor(uint16 Length); +static uint8* HID_GetProtocolValue(uint16 Length); + +static volatile HIDBuffer_t hidBuffers[MAX_HID_BUFFERS] = {{ 0 }}; +static volatile HIDBuffer_t* currentHIDBuffer = NULL; + +//#define DUMMY_BUFFER_SIZE 0x40 // at least as big as a buffer size + +#define HID_INTERFACE_OFFSET 0x00 +#define NUM_HID_ENDPOINTS 1 +#define HID_INTERFACE_NUMBER (HID_INTERFACE_OFFSET+usbHIDPart.startInterface) + +/* + * Descriptors + */ + +static ONE_DESCRIPTOR HID_Report_Descriptor = { + (uint8*)NULL, + 0 +}; + + +#define HID_ENDPOINT_TX 0 + +typedef struct { + //HID + usb_descriptor_interface HID_Interface; + HIDDescriptor HID_Descriptor; + usb_descriptor_endpoint HIDDataInEndpoint; +} __packed hid_part_config; + +static const hid_part_config hidPartConfigData = { + .HID_Interface = { + .bLength = sizeof(usb_descriptor_interface), + .bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE, + .bInterfaceNumber = HID_INTERFACE_OFFSET, // PATCH + .bAlternateSetting = 0x00, + .bNumEndpoints = NUM_HID_ENDPOINTS, + .bInterfaceClass = USB_INTERFACE_CLASS_HID, + .bInterfaceSubClass = USB_INTERFACE_SUBCLASS_HID, + .bInterfaceProtocol = 0x00, /* Common AT Commands */ + .iInterface = 0x00, + }, + .HID_Descriptor = { + .len = 9,//sizeof(HIDDescDescriptor), + .dtype = HID_DESCRIPTOR_TYPE, + .versionL = 0x10, + .versionH = 0x01, + .country = 0x00, + .numDesc = 0x01, + .desctype = REPORT_DESCRIPTOR,//0x22, + .descLenL = 0x00, //PATCH + .descLenH = 0x00, //PATCH + }, + .HIDDataInEndpoint = { + .bLength = sizeof(usb_descriptor_endpoint), + .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT, + .bEndpointAddress = USB_DESCRIPTOR_ENDPOINT_IN | HID_ENDPOINT_TX, // PATCH + .bmAttributes = USB_ENDPOINT_TYPE_INTERRUPT, + .wMaxPacketSize = USB_HID_TX_EPSIZE,//0x40,//big enough for a keyboard 9 byte packet and for a mouse 5 byte packet + .bInterval = 0x0A, + } +}; + +static USBEndpointInfo hidEndpoints[1] = { + { + .callback = hidDataTxCb, + .bufferSize = USB_HID_TX_EPSIZE, + .type = USB_EP_EP_TYPE_INTERRUPT, // TODO: interrupt??? + .tx = 1, + } +}; + +#define OUT_BYTE(s,v) out[(uint8*)&(s.v)-(uint8*)&s] + +static void getHIDPartDescriptor(uint8* out) { + memcpy(out, &hidPartConfigData, sizeof(hid_part_config)); + // patch to reflect where the part goes in the descriptor + OUT_BYTE(hidPartConfigData, HID_Interface.bInterfaceNumber) += usbHIDPart.startInterface; + OUT_BYTE(hidPartConfigData, HIDDataInEndpoint.bEndpointAddress) += usbHIDPart.startEndpoint; + OUT_BYTE(hidPartConfigData, HID_Descriptor.descLenL) = (uint8)HID_Report_Descriptor.Descriptor_Size; + OUT_BYTE(hidPartConfigData, HID_Descriptor.descLenH) = (uint8)(HID_Report_Descriptor.Descriptor_Size>>8); +} + +USBCompositePart usbHIDPart = { + .numInterfaces = 1, + .numEndpoints = sizeof(hidEndpoints)/sizeof(*hidEndpoints), + .descriptorSize = sizeof(hid_part_config), + .getPartDescriptor = getHIDPartDescriptor, + .usbInit = NULL, + .usbReset = hidUSBReset, + .usbDataSetup = hidUSBDataSetup, + .usbNoDataSetup = hidUSBNoDataSetup, + .usbClearFeature = NULL, + .usbSetConfiguration = NULL, + .endpoints = hidEndpoints +}; + + +#define HID_TX_BUFFER_SIZE 256 // must be power of 2 +#define HID_TX_BUFFER_SIZE_MASK (HID_TX_BUFFER_SIZE-1) +// Tx data +static volatile uint8 hidBufferTx[HID_TX_BUFFER_SIZE]; +// Write index to hidBufferTx +static volatile uint32 hid_tx_head = 0; +// Read index from hidBufferTx +static volatile uint32 hid_tx_tail = 0; + +#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) + + + + +void usb_hid_putc(char ch) { + while (!usb_hid_tx((uint8*)&ch, 1)) + ; +} + + /* +static void hidStatusIn() { + if (pInformation->ControlState == WAIT_STATUS_IN) { + if (currentInFeature >= 0) { + if (featureBuffers[currentInFeature].bufferSize == featureBuffers[currentInFeature].currentDataSize) + featureBuffers[currentInFeature].state = HID_BUFFER_UNREAD; + currentInFeature = -1; + } + if (currentOutput >= 0) { + if (outputBuffers[currentOutput].bufferSize == outputBuffers[currentOutput].currentDataSize) + outputBuffers[currentOutput].state = HID_BUFFER_UNREAD; + currentOutput = -1; + } + } +} + */ + +void usb_hid_set_report_descriptor(const uint8* report_descriptor, uint16 report_descriptor_length) { + HID_Report_Descriptor.Descriptor = (uint8*)report_descriptor; + HID_Report_Descriptor.Descriptor_Size = report_descriptor_length; +} + + +static volatile HIDBuffer_t* usb_hid_find_buffer(uint8 type, uint8 reportID) { + uint8 typeTest = type == HID_REPORT_TYPE_OUTPUT ? HID_BUFFER_MODE_OUTPUT : 0; + for (int i=0; ibuffer+delta, data, buffer->bufferSize-delta); + if (reportID) + buffer->buffer[0] = reportID; + buffer->currentDataSize = buffer->bufferSize; + buffer->state = HID_BUFFER_READ; + usb_set_ep_rx_stat(USB_EP0, USB_EP_STAT_RX_VALID); + return; + } +} + +static uint8 have_unread_data_in_hid_buffer() { + for (int i=0;ireportID == reportID && buffer->state != HID_BUFFER_EMPTY && !(poll && buffer->state == HID_BUFFER_READ)) { + if (buffer->bufferSize != buffer->currentDataSize) { + buffer->state = HID_BUFFER_EMPTY; + ret = 0; + } + else { + unsigned delta = reportID != 0; + if (out != NULL) + memcpy(out, (uint8*)buffer->buffer+delta, buffer->bufferSize-delta); + + if (poll) { + buffer->state = HID_BUFFER_READ; + } + + ret = buffer->bufferSize-delta; + } + } + + if (! have_unread_data_in_hid_buffer() ) { + usb_set_ep_rx_stat(USB_EP0, USB_EP_STAT_RX_VALID); + } + + nvic_irq_enable(NVIC_USB_LP_CAN_RX0); + + return ret; +} + +void usb_hid_clear_buffers(uint8 type) { + uint8 typeTest = type == HID_REPORT_TYPE_OUTPUT ? HID_BUFFER_MODE_OUTPUT : 0; + for (int i=0; imode |= HID_BUFFER_MODE_OUTPUT; + else + buf->mode &= ~HID_BUFFER_MODE_OUTPUT; + memset((void*)buf->buffer, 0, buf->bufferSize); + buf->buffer[0] = buf->reportID; + + volatile HIDBuffer_t* buffer = usb_hid_find_buffer(type, buf->reportID); + + if (buffer != NULL) { + *buffer = *buf; + return 1; + } + else { + for (int i=0; i (HID_TX_BUFFER_SIZE-tx_unsent-1) ) { + len = (HID_TX_BUFFER_SIZE-tx_unsent-1); + } + if (len==0) return 0; // buffer full + + uint16 i; + // copy data from user buffer to USB Tx buffer + for (i=0; i= 0); + + if (usbGenericTransmitting<0) { + hidDataTxCb(); // initiate data transmission + } + + return len; +} + + + +uint16 usb_hid_get_pending(void) { + return (hid_tx_head - hid_tx_tail) & HID_TX_BUFFER_SIZE_MASK; +} + +static void hidDataTxCb(void) +{ + uint32 tail = hid_tx_tail; // load volatile variable + uint32 tx_unsent = (hid_tx_head - tail) & HID_TX_BUFFER_SIZE_MASK; + if (tx_unsent==0) { + if ( (--usbGenericTransmitting)==0) goto flush_hid; // no more data to send + return; // it was already flushed, keep Tx endpoint disabled + } + usbGenericTransmitting = 1; + // We can only send up to USBHID_CDCACM_TX_EPSIZE bytes in the endpoint. + if (tx_unsent > USB_HID_TX_EPSIZE) { + tx_unsent = USB_HID_TX_EPSIZE; + } + // copy the bytes from USB Tx buffer to PMA buffer + uint32 *dst = usb_pma_ptr(usbHIDPart.endpoints[HID_ENDPOINT_TX].pmaAddress); + uint16 tmp = 0; + uint16 val; + unsigned i; + for (i = 0; i < tx_unsent; i++) { + val = hidBufferTx[tail]; + tail = (tail + 1) & HID_TX_BUFFER_SIZE_MASK; + if (i&1) { + *dst++ = tmp | (val<<8); + } else { + tmp = val; + } + } + if ( tx_unsent&1 ) { + *dst = tmp; + } + hid_tx_tail = tail; // store volatile variable + +flush_hid: + // enable Tx endpoint + usb_set_ep_tx_count(usbHIDPart.endpoints[HID_ENDPOINT_TX].address, tx_unsent); + usb_set_ep_tx_stat(usbHIDPart.endpoints[HID_ENDPOINT_TX].address, USB_EP_STAT_TX_VALID); +} + + + +static void hidUSBReset(void) { + /* Reset the RX/TX state */ + hid_tx_head = 0; + hid_tx_tail = 0; + + currentHIDBuffer = NULL; +} + +static uint8* HID_Set(uint16 length) { + if (currentHIDBuffer == NULL) + return NULL; + + if (length ==0) { + if ( (0 == (currentHIDBuffer->mode & HID_BUFFER_MODE_NO_WAIT)) && + currentHIDBuffer->state == HID_BUFFER_UNREAD && + pInformation->Ctrl_Info.Usb_wOffset < pInformation->USBwLengths.w) { + pInformation->Ctrl_Info.Usb_wLength = 0xFFFF; + return NULL; + } + + uint16 len = pInformation->USBwLengths.w; + if (len > currentHIDBuffer->bufferSize) + len = currentHIDBuffer->bufferSize; + + currentHIDBuffer->currentDataSize = len; + + currentHIDBuffer->state = HID_BUFFER_EMPTY; + + if (pInformation->Ctrl_Info.Usb_wOffset < len) { + pInformation->Ctrl_Info.Usb_wLength = len - pInformation->Ctrl_Info.Usb_wOffset; + } + else { + pInformation->Ctrl_Info.Usb_wLength = 0; + } + + return NULL; + } + + if (pInformation->USBwLengths.w <= pInformation->Ctrl_Info.Usb_wOffset + pInformation->Ctrl_Info.PacketSize) { + currentHIDBuffer->state = HID_BUFFER_UNREAD; + } + + return (uint8*)currentHIDBuffer->buffer + pInformation->Ctrl_Info.Usb_wOffset; +} + +static uint8* HID_GetFeature(uint16 length) { + if (currentHIDBuffer == NULL) + return NULL; + + unsigned wOffset = pInformation->Ctrl_Info.Usb_wOffset; + + if (length == 0) + { + pInformation->Ctrl_Info.Usb_wLength = currentHIDBuffer->bufferSize - wOffset; + return NULL; + } + + return (uint8*)currentHIDBuffer->buffer + wOffset; +} + +static RESULT hidUSBDataSetup(uint8 request) { + uint8* (*CopyRoutine)(uint16) = 0; + + if (pInformation->USBwIndex0 != HID_INTERFACE_NUMBER) + return USB_UNSUPPORT; + + if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) { + switch (request) { + case SET_REPORT: + if (pInformation->USBwValue1 == HID_REPORT_TYPE_FEATURE) { + volatile HIDBuffer_t* buffer = usb_hid_find_buffer(HID_REPORT_TYPE_FEATURE, pInformation->USBwValue0); + + if (buffer == NULL) { + return USB_UNSUPPORT; + } + + if (0 == (buffer->mode & HID_BUFFER_MODE_NO_WAIT) && buffer->state == HID_BUFFER_UNREAD) { + return USB_NOT_READY; + } + else + { + currentHIDBuffer = buffer; + CopyRoutine = HID_Set; + } + } + else if (pInformation->USBwValue1 == HID_REPORT_TYPE_OUTPUT) { + volatile HIDBuffer_t* buffer = usb_hid_find_buffer(HID_REPORT_TYPE_OUTPUT, pInformation->USBwValue0); + + if (buffer == NULL) { + return USB_UNSUPPORT; + } + + if (0 == (buffer->mode & HID_BUFFER_MODE_NO_WAIT) && buffer->state == HID_BUFFER_UNREAD) { + return USB_NOT_READY; + } + else + { + currentHIDBuffer = buffer; + CopyRoutine = HID_Set; + } + } + break; + case GET_REPORT: + if (pInformation->USBwValue1 == HID_REPORT_TYPE_FEATURE) { + volatile HIDBuffer_t* buffer = usb_hid_find_buffer(HID_REPORT_TYPE_FEATURE, pInformation->USBwValue0); + + if (buffer == NULL || buffer->state == HID_BUFFER_EMPTY) { + return USB_UNSUPPORT; + } + + currentHIDBuffer = buffer; + CopyRoutine = HID_GetFeature; + break; + } + default: + break; + } + } + + if(Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT)){ + switch (request){ + case GET_DESCRIPTOR: + if (pInformation->USBwValue1 == REPORT_DESCRIPTOR){ + CopyRoutine = HID_GetReportDescriptor; + } + break; + case GET_PROTOCOL: // TODO: check for interface number? + CopyRoutine = HID_GetProtocolValue; + break; + } + } + + if (CopyRoutine == NULL){ + return USB_UNSUPPORT; + } + + pInformation->Ctrl_Info.CopyData = CopyRoutine; + pInformation->Ctrl_Info.Usb_wOffset = 0; + (*CopyRoutine)(0); + return USB_SUCCESS; +} + +static RESULT hidUSBNoDataSetup(uint8 request) { + if (pInformation->USBwIndex0 != HID_INTERFACE_NUMBER) + return USB_UNSUPPORT; + + RESULT ret = USB_UNSUPPORT; + + if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) { + switch(request) { + case SET_PROTOCOL: + ProtocolValue = pInformation->USBwValue0; + ret = USB_SUCCESS; + break; + } + } + return ret; +} + +/* +static RESULT HID_SetProtocol(void){ + uint8 wValue0 = pInformation->USBwValue0; + ProtocolValue = wValue0; + return USB_SUCCESS; +} +*/ +static uint8* HID_GetProtocolValue(uint16 Length){ + if (Length == 0){ + pInformation->Ctrl_Info.Usb_wLength = 1; + return NULL; + } else { + return (uint8 *)(&ProtocolValue); + } +} + +static uint8* HID_GetReportDescriptor(uint16 Length){ + return Standard_GetDescriptorData(Length, &HID_Report_Descriptor); +} + diff --git a/STM32F1/libraries/USBComposite/usb_hid.h b/STM32F1/libraries/USBComposite/usb_hid.h new file mode 100644 index 0000000..856fd3e --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_hid.h @@ -0,0 +1,153 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/usb_device.h + * @brief USB Composite with CDC ACM and HID support + * + * IMPORTANT: this API is unstable, and may change without notice. + */ + +#ifndef _USB_HID_H_ +#define _USB_HID_H_ + +#include +#include +#include "usb_generic.h" + +#define MAX_HID_BUFFERS 8 +#define HID_BUFFER_SIZE(n,reportID) ((n)+((reportID)!=0)) +#define HID_BUFFER_ALLOCATE_SIZE(n,reportID) ((HID_BUFFER_SIZE((n),(reportID))+1)/2*2) + +#define HID_BUFFER_MODE_NO_WAIT 1 +#define HID_BUFFER_MODE_OUTPUT 2 + +#define HID_BUFFER_EMPTY 0 +#define HID_BUFFER_UNREAD 1 +#define HID_BUFFER_READ 2 + +extern USBCompositePart usbHIDPart; + +typedef struct HIDBuffer_t { + volatile uint8_t* buffer; // use HID_BUFFER_ALLOCATE_SIZE() to calculate amount of memory to allocate + uint16_t bufferSize; // this should match HID_BUFFER_SIZE + uint8_t reportID; + uint8_t mode; + uint16_t currentDataSize; + uint8_t state; // HID_BUFFER_EMPTY, etc. +#ifdef __cplusplus + inline HIDBuffer_t(volatile uint8_t* _buffer=NULL, uint16_t _bufferSize=0, uint8_t _reportID=0, uint8_t _mode=0) { + reportID = _reportID; + buffer = _buffer; + bufferSize = _bufferSize; + mode = _mode; + } +#endif +} HIDBuffer_t; + +#ifdef __cplusplus +extern "C" { +#endif + +#define USB_HID_TX_EPSIZE 0x40 + +void usb_hid_set_report_descriptor(const uint8* report_descriptor, uint16 report_descriptor_length); +void usb_hid_clear_buffers(uint8_t type); +uint8_t usb_hid_add_buffer(uint8_t type, volatile HIDBuffer_t* buf); +void usb_hid_set_buffers(uint8_t type, volatile HIDBuffer_t* featureBuffers, int count); +uint16_t usb_hid_get_data(uint8_t type, uint8_t reportID, uint8_t* out, uint8_t poll); +void usb_hid_set_feature(uint8_t reportID, uint8_t* data); + + + +/* + * HID Requests + */ + +typedef enum _HID_REQUESTS +{ + + GET_REPORT = 1, + GET_IDLE, + GET_PROTOCOL, + + SET_REPORT = 9, + SET_IDLE, + SET_PROTOCOL + +} HID_REQUESTS; + +#define HID_REPORT_TYPE_INPUT 0x01 +#define HID_REPORT_TYPE_OUTPUT 0x02 +#define HID_REPORT_TYPE_FEATURE 0x03 + + +/* + * HID Descriptors, etc. + */ + +#define HID_ENDPOINT_INT 1 + +#define HID_DESCRIPTOR_TYPE 0x21 +#define REPORT_DESCRIPTOR 0x22 + + +typedef struct +{ + uint8_t len; // 9 + uint8_t dtype; // 0x21 + uint8_t versionL; // 0x101 + uint8_t versionH; // 0x101 + uint8_t country; + uint8_t numDesc; + uint8_t desctype; // 0x22 report + uint8_t descLenL; + uint8_t descLenH; +} HIDDescriptor; + + +#define USB_ENDPOINT_TYPE_INTERRUPT 0x03 + +#define USB_INTERFACE_CLASS_HID 0x03 +#define USB_INTERFACE_SUBCLASS_HID 0x01 + + /* + * HID interface + */ + +void usb_hid_putc(char ch); +uint32 usb_hid_tx(const uint8* buf, uint32 len); +uint32 usb_hid_tx_mod(const uint8* buf, uint32 len); + +uint32 usb_hid_data_available(void); /* in RX buffer */ +uint16 usb_hid_get_pending(void); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/STM32F1/libraries/USBComposite/usb_mass.c b/STM32F1/libraries/USBComposite/usb_mass.c new file mode 100644 index 0000000..5ef053e --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_mass.c @@ -0,0 +1,464 @@ +#include + +#include "usb_generic.h" +#include "usb_mass.h" +#include "usb_scsi.h" +#include "usb_mass_internal.h" + +#include +#include +#include + +/* Private headers */ +#include "usb_lib_globals.h" +#include "usb_reg_map.h" +#include "usb_regs.h" + +/* usb_lib headers */ +#include "usb_type.h" +#include "usb_core.h" +#include "usb_def.h" + +static void usb_mass_bot_cbw_decode(); + +static void usb_mass_set_configuration(); +static void usb_mass_clear_feature(); +static RESULT usb_mass_data_setup(uint8 request); +static RESULT usb_mass_no_data_setup(uint8 request); +static void usb_mass_reset(); +static uint8_t* usb_mass_get_max_lun(uint16_t Length); +static void usb_mass_in(void); +static void usb_mass_out(void); +uint32_t usb_mass_sil_write(uint8_t* pBufferPointer, uint32_t wBufferSize); +uint32_t usb_mass_sil_read(uint8_t* pBufferPointer); + +#define MASS_INTERFACE_OFFSET 0x00 +#define MASS_INTERFACE_NUMBER (MASS_INTERFACE_OFFSET+usbMassPart.startInterface) + + +#define LUN_DATA_LENGTH 1 + +static uint32_t maxLun = 0; +static uint32_t deviceState = DEVICE_STATE_UNCONNECTED; +uint8_t usb_mass_botState = BOT_STATE_IDLE; +BulkOnlyCBW usb_mass_CBW; +BulkOnlyCSW usb_mass_CSW; +uint8_t usb_mass_bulkDataBuff[MAX_BULK_PACKET_SIZE]; +uint16_t usb_mass_dataLength; +static uint8_t inRequestPending; +static uint8_t outRequestPending; + +typedef struct mass_descriptor_config { +// usb_descriptor_config_header Config_Header; + usb_descriptor_interface MASS_Interface; + usb_descriptor_endpoint DataInEndpoint; + usb_descriptor_endpoint DataOutEndpoint; +} __packed mass_descriptor_config; + + +#define MAX_POWER (500 >> 1) +const mass_descriptor_config usbMassConfigDescriptor = { + /*.Config_Header = + { + .bLength = sizeof (usb_descriptor_config_header), + .bDescriptorType = USB_DESCRIPTOR_TYPE_CONFIGURATION, + .wTotalLength = sizeof (usb_descriptor_config), + .bNumInterfaces = 0x01, + .bConfigurationValue = 0x01, + .iConfiguration = 0x00, + .bmAttributes = (USB_CONFIG_ATTR_BUSPOWERED | USB_CONFIG_ATTR_SELF_POWERED), + .bMaxPower = MAX_POWER, + }, */ + + .MASS_Interface = + { + .bLength = sizeof (usb_descriptor_interface), + .bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE, + .bInterfaceNumber = 0x00, // PATCH + .bAlternateSetting = 0x00, + .bNumEndpoints = 0x02, + .bInterfaceClass = 8, // mass storage + .bInterfaceSubClass = 6, // SCSI + .bInterfaceProtocol = 0x50, // Bulk-Only + .iInterface = 0, + }, + + .DataInEndpoint = + { + .bLength = sizeof (usb_descriptor_endpoint), + .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT, + .bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_IN | MASS_ENDPOINT_TX), // PATCH + .bmAttributes = USB_EP_TYPE_BULK, + .wMaxPacketSize = MAX_BULK_PACKET_SIZE, + .bInterval = 0, + }, + + .DataOutEndpoint = + { + .bLength = sizeof (usb_descriptor_endpoint), + .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT, + .bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_OUT | MASS_ENDPOINT_RX), // PATCH + .bmAttributes = USB_EP_TYPE_BULK, + .wMaxPacketSize = MAX_BULK_PACKET_SIZE, + .bInterval = 1, + } +}; + +USBEndpointInfo usbMassEndpoints[2] = { + { + .callback = usb_mass_in, + .bufferSize = MAX_BULK_PACKET_SIZE, + .type = USB_EP_EP_TYPE_BULK, + .tx = 1, + }, + { + .callback = usb_mass_out, + .bufferSize = MAX_BULK_PACKET_SIZE, + .type = USB_EP_EP_TYPE_BULK, + .tx = 0, + }, +}; + +#define OUT_BYTE(s,v) out[(uint8*)&(s.v)-(uint8*)&s] + +static void getMassPartDescriptor(uint8* out) { + memcpy(out, &usbMassConfigDescriptor, sizeof(mass_descriptor_config)); + // patch to reflect where the part goes in the descriptor + OUT_BYTE(usbMassConfigDescriptor, MASS_Interface.bInterfaceNumber) += usbMassPart.startInterface; + OUT_BYTE(usbMassConfigDescriptor, DataInEndpoint.bEndpointAddress) += usbMassPart.startEndpoint; + OUT_BYTE(usbMassConfigDescriptor, DataOutEndpoint.bEndpointAddress) += usbMassPart.startEndpoint; +} + + + +USBCompositePart usbMassPart = { + .numInterfaces = 1, + .numEndpoints = sizeof(usbMassEndpoints)/sizeof(*usbMassEndpoints), + .descriptorSize = sizeof(mass_descriptor_config), + .getPartDescriptor = getMassPartDescriptor, + .usbInit = NULL, + .usbReset = usb_mass_reset, + .usbDataSetup = usb_mass_data_setup, + .usbNoDataSetup = usb_mass_no_data_setup, + .usbClearFeature = usb_mass_clear_feature, + .usbSetConfiguration = usb_mass_set_configuration, + .endpoints = usbMassEndpoints +}; + +static void usb_mass_reset(void) { + usb_mass_mal_init(0); + + pInformation->Current_Configuration = 0; // TODO: remove? + + /* current feature is current bmAttributes */ + pInformation->Current_Feature = (USB_CONFIG_ATTR_BUSPOWERED | USB_CONFIG_ATTR_SELF_POWERED); // usbMassConfigDescriptor.Config_Header.bmAttributes; // TODO: remove? + + deviceState = DEVICE_STATE_ATTACHED; + usb_mass_CBW.dSignature = BOT_CBW_SIGNATURE; + usb_mass_botState = BOT_STATE_IDLE; +} + +static void usb_mass_set_configuration(void) { + if (pInformation->Current_Configuration != 0) { + deviceState = USB_CONFIGURED; + ClearDTOG_TX(USB_MASS_TX_ENDP); + ClearDTOG_RX(USB_MASS_RX_ENDP); + usb_mass_botState = BOT_STATE_IDLE; + } +} + +static void usb_mass_clear_feature(void) { + /* when the host send a usb_mass_CBW with invalid signature or invalid length the two + Endpoints (IN & OUT) shall stall until receiving a Mass Storage Reset */ + if (usb_mass_CBW.dSignature != BOT_CBW_SIGNATURE) { + usb_mass_bot_abort(BOT_DIR_BOTH); + } +} + +static RESULT usb_mass_data_setup(uint8 request) { + uint8_t * (*copy_routine)(uint16_t); + + copy_routine = NULL; + if ((Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) + && (request == REQUEST_GET_MAX_LUN) && (pInformation->USBwValue == 0) + && (pInformation->USBwIndex == MASS_INTERFACE_NUMBER) && (pInformation->USBwLength == 0x01)) { + copy_routine = usb_mass_get_max_lun; + } else { + return USB_UNSUPPORT; + } + + if (copy_routine == NULL) { + return USB_UNSUPPORT; + } + + pInformation->Ctrl_Info.CopyData = copy_routine; + pInformation->Ctrl_Info.Usb_wOffset = 0; + (*copy_routine)(0); + + return USB_SUCCESS; +} + +static uint8_t* usb_mass_get_max_lun(uint16_t length) { + if (length == 0) { + pInformation->Ctrl_Info.Usb_wLength = LUN_DATA_LENGTH; + return 0; + } else { + return ((uint8_t*) (&maxLun)); + } +} + +static RESULT usb_mass_no_data_setup(uint8 request) { + if ((Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) + && (request == REQUEST_MASS_STORAGE_RESET) && (pInformation->USBwValue == 0) + && (pInformation->USBwIndex == MASS_INTERFACE_NUMBER) && (pInformation->USBwLength == 0x00)) { + + /* Initialize Endpoint 1 */ + ClearDTOG_TX(USB_MASS_TX_ENDP); + + /* Initialize Endpoint 2 */ + ClearDTOG_RX(USB_MASS_RX_ENDP); + + /*initialize the usb_mass_CBW signature to enable the clear feature*/ + usb_mass_CBW.dSignature = BOT_CBW_SIGNATURE; + usb_mass_botState = BOT_STATE_IDLE; + + return USB_SUCCESS; + } + return USB_UNSUPPORT; +} + + +void usb_mass_loop() { + if (inRequestPending) { + inRequestPending = 0; + + switch (usb_mass_botState) { + case BOT_STATE_CSW_Send: + case BOT_STATE_ERROR: + usb_mass_botState = BOT_STATE_IDLE; + SetEPRxStatus(USB_MASS_RX_ENDP, USB_EP_ST_RX_VAL); /* enable the Endpoint to receive the next cmd*/ + break; + case BOT_STATE_DATA_IN: + switch (usb_mass_CBW.CB[0]) { + case SCSI_READ10: + scsi_read10_cmd(usb_mass_CBW.bLUN, SCSI_lba, SCSI_blkLen); + break; + } + break; + case BOT_STATE_DATA_IN_LAST: + usb_mass_bot_set_csw(BOT_CSW_CMD_PASSED, BOT_SEND_CSW_ENABLE); + SetEPRxStatus(USB_MASS_RX_ENDP, USB_EP_ST_RX_VAL); + break; + + default: + break; + } + } + + if (outRequestPending) { + outRequestPending = 0; + + uint8_t CMD; + CMD = usb_mass_CBW.CB[0]; + + switch (usb_mass_botState) { + case BOT_STATE_IDLE: + usb_mass_bot_cbw_decode(); + break; + case BOT_STATE_DATA_OUT: + if (CMD == SCSI_WRITE10) { + scsi_write10_cmd(usb_mass_CBW.bLUN, SCSI_lba, SCSI_blkLen); + break; + } + usb_mass_bot_abort(BOT_DIR_OUT); + scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_ILLEGAL_REQUEST, SCSI_INVALID_FIELED_IN_COMMAND); + usb_mass_bot_set_csw(BOT_CSW_PHASE_ERROR, BOT_SEND_CSW_DISABLE); + break; + default: + usb_mass_bot_abort(BOT_DIR_BOTH); + scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_ILLEGAL_REQUEST, SCSI_INVALID_FIELED_IN_COMMAND); + usb_mass_bot_set_csw(BOT_CSW_PHASE_ERROR, BOT_SEND_CSW_DISABLE); + break; + } + } +} + +/* + * IN + */ +static void usb_mass_in(void) { + inRequestPending = 1; +} + +/* + * OUT + */ +static void usb_mass_out(void) { + usb_mass_dataLength = usb_mass_sil_read(usb_mass_bulkDataBuff); + outRequestPending = 1; +} + +static void usb_mass_bot_cbw_decode() { + uint32_t counter; + + for (counter = 0; counter < usb_mass_dataLength; counter++) { + *((uint8_t *) & usb_mass_CBW + counter) = usb_mass_bulkDataBuff[counter]; + } + usb_mass_CSW.dTag = usb_mass_CBW.dTag; + usb_mass_CSW.dDataResidue = usb_mass_CBW.dDataLength; + if (usb_mass_dataLength != BOT_CBW_PACKET_LENGTH) { + usb_mass_bot_abort(BOT_DIR_BOTH); + /* reset the usb_mass_CBW.dSignature to disable the clear feature until receiving a Mass storage reset*/ + usb_mass_CBW.dSignature = 0; + scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_ILLEGAL_REQUEST, SCSI_PARAMETER_LIST_LENGTH_ERROR); + usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_DISABLE); + return; + } + + if ((usb_mass_CBW.CB[0] == SCSI_READ10) || (usb_mass_CBW.CB[0] == SCSI_WRITE10)) { + /* Calculate Logical Block Address */ + SCSI_lba = (usb_mass_CBW.CB[2] << 24) | (usb_mass_CBW.CB[3] << 16) | (usb_mass_CBW.CB[4] << 8) | usb_mass_CBW.CB[5]; + /* Calculate the Number of Blocks to transfer */ + SCSI_blkLen = (usb_mass_CBW.CB[7] << 8) | usb_mass_CBW.CB[8]; + } + + if (usb_mass_CBW.dSignature == BOT_CBW_SIGNATURE) { + /* Valid usb_mass_CBW */ + if ((usb_mass_CBW.bLUN > maxLun) || (usb_mass_CBW.bCBLength < 1) || (usb_mass_CBW.bCBLength > 16)) { + usb_mass_bot_abort(BOT_DIR_BOTH); + scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_ILLEGAL_REQUEST, SCSI_INVALID_FIELED_IN_COMMAND); + usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_DISABLE); + } else { + switch (usb_mass_CBW.CB[0]) { + case SCSI_REQUEST_SENSE: + scsi_request_sense_cmd(usb_mass_CBW.bLUN); + break; + case SCSI_INQUIRY: + scsi_inquiry_cmd(usb_mass_CBW.bLUN); + break; + case SCSI_START_STOP_UNIT: + scsi_start_stop_unit_cmd(usb_mass_CBW.bLUN); + break; + case SCSI_ALLOW_MEDIUM_REMOVAL: + scsi_start_stop_unit_cmd(usb_mass_CBW.bLUN); + break; + case SCSI_MODE_SENSE6: + scsi_mode_sense6_cmd(usb_mass_CBW.bLUN); + break; + case SCSI_MODE_SENSE10: + scsi_mode_sense10_cmd(usb_mass_CBW.bLUN); + break; + case SCSI_READ_FORMAT_CAPACITIES: + scsi_read_format_capacity_cmd(usb_mass_CBW.bLUN); + break; + case SCSI_READ_CAPACITY10: + scsi_read_capacity10_cmd(usb_mass_CBW.bLUN); + break; + case SCSI_TEST_UNIT_READY: + scsi_test_unit_ready_cmd(usb_mass_CBW.bLUN); + break; + case SCSI_READ10: + scsi_read10_cmd(usb_mass_CBW.bLUN, SCSI_lba, SCSI_blkLen); + break; + case SCSI_WRITE10: + scsi_write10_cmd(usb_mass_CBW.bLUN, SCSI_lba, SCSI_blkLen); + break; + case SCSI_VERIFY10: + scsi_verify10_cmd(usb_mass_CBW.bLUN); + break; + case SCSI_FORMAT_UNIT: + scsi_format_cmd(usb_mass_CBW.bLUN); + break; + + case SCSI_MODE_SELECT10: + case SCSI_MODE_SELECT6: + case SCSI_SEND_DIAGNOSTIC: + case SCSI_READ6: + case SCSI_READ12: + case SCSI_READ16: + case SCSI_READ_CAPACITY16: + case SCSI_WRITE6: + case SCSI_WRITE12: + case SCSI_VERIFY12: + case SCSI_VERIFY16: + case SCSI_WRITE16: + scsi_invalid_cmd(usb_mass_CBW.bLUN); + break; + + default: + { + usb_mass_bot_abort(BOT_DIR_BOTH); + scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_ILLEGAL_REQUEST, SCSI_INVALID_COMMAND); + usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_DISABLE); + } + } + } + } else { + /* Invalid usb_mass_CBW */ + usb_mass_bot_abort(BOT_DIR_BOTH); + scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_ILLEGAL_REQUEST, SCSI_INVALID_COMMAND); + usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_DISABLE); + } +} + +void usb_mass_bot_abort(uint8_t direction) { + switch (direction) { + case BOT_DIR_IN: + SetEPTxStatus(USB_MASS_TX_ENDP, USB_EP_ST_TX_STL); + break; + case BOT_DIR_OUT: + SetEPRxStatus(USB_MASS_RX_ENDP, USB_EP_ST_RX_STL); + break; + case BOT_DIR_BOTH: + SetEPTxStatus(USB_MASS_TX_ENDP, USB_EP_ST_TX_STL); + SetEPRxStatus(USB_MASS_RX_ENDP, USB_EP_ST_RX_STL); + break; + default: + break; + } +} + +void usb_mass_transfer_data_request(uint8_t* dataPointer, uint16_t dataLen) { + usb_mass_sil_write(dataPointer, dataLen); + + SetEPTxStatus(USB_MASS_TX_ENDP, USB_EP_ST_TX_VAL); + usb_mass_botState = BOT_STATE_DATA_IN_LAST; + usb_mass_CSW.dDataResidue -= dataLen; + usb_mass_CSW.bStatus = BOT_CSW_CMD_PASSED; +} + +void usb_mass_bot_set_csw(uint8_t status, uint8_t sendPermission) { + usb_mass_CSW.dSignature = BOT_CSW_SIGNATURE; + usb_mass_CSW.bStatus = status; + + usb_mass_sil_write(((uint8_t *) & usb_mass_CSW), BOT_CSW_DATA_LENGTH); + + usb_mass_botState = BOT_STATE_ERROR; + if (sendPermission) { + usb_mass_botState = BOT_STATE_CSW_Send; + SetEPTxStatus(USB_MASS_TX_ENDP, USB_EP_ST_TX_VAL); + } +} + +uint32_t usb_mass_sil_write(uint8_t* pBufferPointer, uint32_t wBufferSize) { + /* Use the memory interface function to write to the selected endpoint */ + usb_copy_to_pma(pBufferPointer, wBufferSize, USB_MASS_TX_ADDR); + + /* Update the data length in the control register */ + SetEPTxCount(USB_MASS_TX_ENDP, wBufferSize); + + return 0; +} + +uint32_t usb_mass_sil_read(uint8_t* pBufferPointer) { + uint32_t usb_mass_dataLength = 0; + + /* Get the number of received data on the selected Endpoint */ + usb_mass_dataLength = GetEPRxCount(USB_MASS_RX_ENDP); + + /* Use the memory interface function to write to the selected endpoint */ + usb_copy_from_pma(pBufferPointer, usb_mass_dataLength, USB_MASS_RX_ADDR); + + /* Return the number of received data */ + return usb_mass_dataLength; +} diff --git a/STM32F1/libraries/USBComposite/usb_mass.h b/STM32F1/libraries/USBComposite/usb_mass.h new file mode 100644 index 0000000..7d4f7ce --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_mass.h @@ -0,0 +1,112 @@ + +#ifndef _LIBMAPLE_USB_MASS_H_ +#define _LIBMAPLE_USB_MASS_H_ + +#include +#include +#include +#include +#include "usb_generic.h" +#include "usb_mass_mal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define N_STRING_DESCRIPTORS 4 + +#define MAX_PACKET_SIZE 0x40 /* 64B, maximum for USB FS Devices */ +#define MAX_BULK_PACKET_SIZE 0x40 /* 64B, max bulk Can't use 512 because the internal buffers for USB is only 512B */ + + + /* MASS Storage Requests */ +#define REQUEST_GET_MAX_LUN 0xFE +#define REQUEST_MASS_STORAGE_RESET 0xFF + + /* USB device state */ + typedef enum _DEVICE_STATE { + DEVICE_STATE_UNCONNECTED, + DEVICE_STATE_ATTACHED, + DEVICE_STATE_POWERED, + DEVICE_STATE_SUSPENDED, + DEVICE_STATE_ADDRESSED, + DEVICE_STATE_CONFIGURED + } DEVICE_STATE; + +#define BOT_DIR_IN 0 +#define BOT_DIR_OUT 1 +#define BOT_DIR_BOTH 2 + + /*****************************************************************************/ + /*********************** Bulk-Only Transfer State machine ********************/ + /*****************************************************************************/ +#define BOT_STATE_IDLE 0 /* Idle state */ +#define BOT_STATE_DATA_OUT 1 /* Data Out state */ +#define BOT_STATE_DATA_IN 2 /* Data In state */ +#define BOT_STATE_DATA_IN_LAST 3 /* Last Data In Last */ +#define BOT_STATE_CSW_Send 4 /* Command Status Wrapper */ +#define BOT_STATE_ERROR 5 /* error state */ + +#define BOT_CBW_SIGNATURE 0x43425355 +#define BOT_CSW_SIGNATURE 0x53425355 +#define BOT_CBW_PACKET_LENGTH 31 + +#define BOT_CSW_DATA_LENGTH 0x000D + + /* CSW Status Definitions */ +#define BOT_CSW_CMD_PASSED 0x00 +#define BOT_CSW_CMD_FAILED 0x01 +#define BOT_CSW_PHASE_ERROR 0x02 + +#define BOT_SEND_CSW_DISABLE 0 +#define BOT_SEND_CSW_ENABLE 1 + +#define USB_EP1_IN 0x81 + + /* Bulk-only Command Block Wrapper */ + typedef struct _BulkOnlyCBW { + uint32_t dSignature; + uint32_t dTag; + uint32_t dDataLength; + uint8_t bmFlags; + uint8_t bLUN; + uint8_t bCBLength; + uint8_t CB[16]; + } BulkOnlyCBW; + + /* Bulk-only Command Status Wrapper */ + typedef struct _BulkOnlyCSW { + uint32_t dSignature; + uint32_t dTag; + uint32_t dDataResidue; + uint8_t bStatus; + } BulkOnlyCSW; + + typedef struct _usb_descriptor_config { + usb_descriptor_config_header Config_Header; + usb_descriptor_interface MASS_Interface; + usb_descriptor_endpoint DataInEndpoint; + usb_descriptor_endpoint DataOutEndpoint; + } __packed usb_descriptor_config; + + void usb_mass_enable(gpio_dev *disc_dev, uint8 disc_bit); + void usb_mass_disable(gpio_dev *disc_dev, uint8 disc_bit); + void usb_mass_loop(); + + void usb_mass_bot_set_csw(uint8_t cswStatus, uint8_t sendPermission); + void usb_mass_transfer_data_request(uint8_t* dataPointer, uint16_t dataLen); + void usb_mass_bot_abort(uint8_t direction); + + extern USBCompositePart usbMassPart; + +extern uint8_t usb_mass_botState; +extern BulkOnlyCBW usb_mass_CBW; +extern BulkOnlyCSW usb_mass_CSW; +extern uint8_t usb_mass_bulkDataBuff[MAX_BULK_PACKET_SIZE]; +extern uint16_t usb_mass_dataLength; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/STM32F1/libraries/USBComposite/usb_mass_internal.h b/STM32F1/libraries/USBComposite/usb_mass_internal.h new file mode 100644 index 0000000..c3405a8 --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_mass_internal.h @@ -0,0 +1,12 @@ +#ifndef _USB_MASS_INTERNAL_H_ +#define _USB_MASS_INTERNAL_H_ + +extern USBEndpointInfo usbMassEndpoints[]; + +#define MASS_ENDPOINT_TX 0 +#define MASS_ENDPOINT_RX 1 +#define USB_MASS_RX_ENDP (usbMassEndpoints[MASS_ENDPOINT_RX].address) +#define USB_MASS_TX_ENDP (usbMassEndpoints[MASS_ENDPOINT_TX].address) +#define USB_MASS_RX_ADDR (usbMassEndpoints[MASS_ENDPOINT_RX].pmaAddress) +#define USB_MASS_TX_ADDR (usbMassEndpoints[MASS_ENDPOINT_TX].pmaAddress) +#endif \ No newline at end of file diff --git a/STM32F1/libraries/USBComposite/usb_mass_mal.c b/STM32F1/libraries/USBComposite/usb_mass_mal.c new file mode 100644 index 0000000..b3a79c3 --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_mass_mal.c @@ -0,0 +1,42 @@ +#include +#include "usb_mass_mal.h" + + +#define USB_MASS_MAL_FAIL 1 +#define USB_MASS_MAL_SUCCESS 0 + +MassStorageDriveInfo usb_mass_drives[USB_MASS_MAX_DRIVES] = { { 0 } }; + +uint16_t usb_mass_mal_init(uint8_t lun) { + if (lun >= USB_MASS_MAX_DRIVES || (usb_mass_drives[lun].init != NULL && ! usb_mass_drives[lun].init())) + return USB_MASS_MAL_FAIL; + else + return USB_MASS_MAL_SUCCESS; +} + +void usb_mass_mal_format(uint8_t lun) { + if (lun < USB_MASS_MAX_DRIVES && usb_mass_drives[lun].format != NULL) + usb_mass_drives[lun].format(); +} + +uint16_t usb_mass_mal_get_status(uint8_t lun) { + if (lun >= USB_MASS_MAX_DRIVES || (usb_mass_drives[lun].status != NULL && ! usb_mass_drives[lun].status())) + return USB_MASS_MAL_FAIL; + else + return USB_MASS_MAL_SUCCESS; +} + +uint16_t usb_mass_mal_read_memory(uint8_t lun, uint32_t memoryOffset, uint8_t *readbuff, uint16_t transferLength) { + if (lun >= USB_MASS_MAX_DRIVES || ! usb_mass_drives[lun].read(memoryOffset, readbuff, transferLength)) + return USB_MASS_MAL_FAIL; + else + return USB_MASS_MAL_SUCCESS; +} + +uint16_t usb_mass_mal_write_memory(uint8_t lun, uint32_t memoryOffset, uint8_t *writebuff, uint16_t transferLength) { + if (lun >= USB_MASS_MAX_DRIVES || usb_mass_drives[lun].write == NULL + || ! usb_mass_drives[lun].write(memoryOffset, writebuff, transferLength)) + return USB_MASS_MAL_FAIL; + else + return USB_MASS_MAL_SUCCESS; +} diff --git a/STM32F1/libraries/USBComposite/usb_mass_mal.h b/STM32F1/libraries/USBComposite/usb_mass_mal.h new file mode 100644 index 0000000..455fd71 --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_mass_mal.h @@ -0,0 +1,39 @@ +#ifndef __USB_MASS_MAL_H +#define __USB_MASS_MAL_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define USB_MASS_MAX_DRIVES 2 + +typedef bool (*MassStorageWriter)(uint32_t memoryOffset, const uint8_t *writebuff, uint16_t transferLength); +typedef bool (*MassStorageReader)(uint32_t memoryOffset, uint8_t *readbuff, uint16_t transferLength); +typedef bool (*MassStorageStatuser)(void); +typedef bool (*MassStorageInitializer)(void); +typedef bool (*MassStorageFormatter)(void); + +typedef struct { + uint32_t blockCount; + MassStorageReader read; + MassStorageWriter write; + MassStorageStatuser status; + MassStorageInitializer init; + MassStorageFormatter format; +} MassStorageDriveInfo; + +extern MassStorageDriveInfo usb_mass_drives[USB_MASS_MAX_DRIVES]; +uint16_t usb_mass_mal_init(uint8_t lun); +uint16_t usb_mass_mal_get_status(uint8_t lun); +uint16_t usb_mass_mal_read_memory(uint8_t lun, uint32_t memoryOffset, uint8_t *readbuff, uint16_t transferLength); +uint16_t usb_mass_mal_write_memory(uint8_t lun, uint32_t memoryOffset, uint8_t *writebuff, uint16_t transferLength); +void usb_mass_mal_format(uint8_t lun); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/STM32F1/libraries/USBComposite/usb_midi_device.c b/STM32F1/libraries/USBComposite/usb_midi_device.c new file mode 100644 index 0000000..549d581 --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_midi_device.c @@ -0,0 +1,532 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs LLC. + * Copyright (c) 2013 Magnus Lundin. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/usb/stm32f1/usb_midi_device.c + * @brief USB MIDI. + * + * FIXME: this works on the STM32F1 USB peripherals, and probably no + * place else. Nonportable bits really need to be factored out, and + * the result made cleaner. + */ + +#include +#include "usb_generic.h" +#include "usb_midi_device.h" +#include +#include + +#include +#include +#include + +/* Private headers */ +#include "usb_lib_globals.h" +#include "usb_reg_map.h" + +/* usb_lib headers */ +#include "usb_type.h" +#include "usb_core.h" +#include "usb_def.h" + +static void midiDataTxCb(void); +static void midiDataRxCb(void); + +static void usbMIDIReset(void); +static RESULT usbMIDIDataSetup(uint8 request); +static RESULT usbMIDINoDataSetup(uint8 request); + +#define MIDI_ENDPOINT_RX 0 +#define MIDI_ENDPOINT_TX 1 +#define USB_MIDI_RX_ENDP (midiEndpoints[MIDI_ENDPOINT_RX].address) +#define USB_MIDI_TX_ENDP (midiEndpoints[MIDI_ENDPOINT_TX].address) +#define USB_MIDI_RX_ADDR (midiEndpoints[MIDI_ENDPOINT_RX].pmaAddress) +#define USB_MIDI_TX_ADDR (midiEndpoints[MIDI_ENDPOINT_TX].pmaAddress) + +/* + * Descriptors + */ + +typedef struct { +// usb_descriptor_config_header Config_Header; + /* Control Interface */ + usb_descriptor_interface AC_Interface; + AC_CS_INTERFACE_DESCRIPTOR(1) AC_CS_Interface; + /* Control Interface */ + usb_descriptor_interface MS_Interface; + MS_CS_INTERFACE_DESCRIPTOR MS_CS_Interface; + MIDI_IN_JACK_DESCRIPTOR MIDI_IN_JACK_1; + MIDI_IN_JACK_DESCRIPTOR MIDI_IN_JACK_2; + MIDI_OUT_JACK_DESCRIPTOR(1) MIDI_OUT_JACK_3; + MIDI_OUT_JACK_DESCRIPTOR(1) MIDI_OUT_JACK_4; + usb_descriptor_endpoint DataOutEndpoint; + MS_CS_BULK_ENDPOINT_DESCRIPTOR(1) MS_CS_DataOutEndpoint; + usb_descriptor_endpoint DataInEndpoint; + MS_CS_BULK_ENDPOINT_DESCRIPTOR(1) MS_CS_DataInEndpoint; +} __packed usb_descriptor_config; + +static const usb_descriptor_config usbMIDIDescriptor_Config = { + /* .Config_Header = { + .bLength = sizeof(usb_descriptor_config_header), + .bDescriptorType = USB_DESCRIPTOR_TYPE_CONFIGURATION, + .wTotalLength = sizeof(usb_descriptor_config), + .bNumInterfaces = 0x02, + .bConfigurationValue = 0x01, + .iConfiguration = 0x00, + .bmAttributes = (USB_CONFIG_ATTR_BUSPOWERED | + USB_CONFIG_ATTR_SELF_POWERED), + .bMaxPower = MAX_POWER, + }, */ + + .AC_Interface = { + .bLength = sizeof(usb_descriptor_interface), + .bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE, + .bInterfaceNumber = 0x00, // PATCH + .bAlternateSetting = 0x00, + .bNumEndpoints = 0x00, + .bInterfaceClass = USB_INTERFACE_CLASS_AUDIO, + .bInterfaceSubClass = USB_INTERFACE_AUDIOCONTROL, + .bInterfaceProtocol = 0x00, + .iInterface = 0x00, + }, + + .AC_CS_Interface = { + .bLength = AC_CS_INTERFACE_DESCRIPTOR_SIZE(1), + .bDescriptorType = USB_DESCRIPTOR_TYPE_CS_INTERFACE, + .SubType = 0x01, + .bcdADC = 0x0100, + .wTotalLength = AC_CS_INTERFACE_DESCRIPTOR_SIZE(1), + .bInCollection = 0x01, + .baInterfaceNr = {0x01}, + }, + + .MS_Interface = { + .bLength = sizeof(usb_descriptor_interface), + .bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE, + .bInterfaceNumber = 0x01, // PATCH + .bAlternateSetting = 0x00, + .bNumEndpoints = 0x02, + .bInterfaceClass = USB_INTERFACE_CLASS_AUDIO, + .bInterfaceSubClass = USB_INTERFACE_MIDISTREAMING, + .bInterfaceProtocol = 0x00, + .iInterface = 0, // was 0x04 + }, + + .MS_CS_Interface = { + .bLength = sizeof(MS_CS_INTERFACE_DESCRIPTOR), + .bDescriptorType = USB_DESCRIPTOR_TYPE_CS_INTERFACE, + .SubType = 0x01, + .bcdADC = 0x0100, + .wTotalLength = sizeof(MS_CS_INTERFACE_DESCRIPTOR) + +sizeof(MIDI_IN_JACK_DESCRIPTOR) + +sizeof(MIDI_IN_JACK_DESCRIPTOR) + +MIDI_OUT_JACK_DESCRIPTOR_SIZE(1) + +MIDI_OUT_JACK_DESCRIPTOR_SIZE(1) + +sizeof(usb_descriptor_endpoint) + +MS_CS_BULK_ENDPOINT_DESCRIPTOR_SIZE(1) + +sizeof(usb_descriptor_endpoint) + +MS_CS_BULK_ENDPOINT_DESCRIPTOR_SIZE(1) + /* 0x41-4 */, + }, + + .MIDI_IN_JACK_1 = { + .bLength = sizeof(MIDI_IN_JACK_DESCRIPTOR), + .bDescriptorType = USB_DESCRIPTOR_TYPE_CS_INTERFACE, + .SubType = MIDI_IN_JACK, + .bJackType = MIDI_JACK_EMBEDDED, + .bJackId = 0x01, + .iJack = 0x05, + }, + + .MIDI_IN_JACK_2 = { + .bLength = sizeof(MIDI_IN_JACK_DESCRIPTOR), + .bDescriptorType = USB_DESCRIPTOR_TYPE_CS_INTERFACE, + .SubType = MIDI_IN_JACK, + .bJackType = MIDI_JACK_EXTERNAL, + .bJackId = 0x02, + .iJack = 0x00, + }, + + .MIDI_OUT_JACK_3 = { + .bLength = MIDI_OUT_JACK_DESCRIPTOR_SIZE(1), + .bDescriptorType = USB_DESCRIPTOR_TYPE_CS_INTERFACE, + .SubType = MIDI_OUT_JACK, + .bJackType = MIDI_JACK_EMBEDDED, + .bJackId = 0x03, + .bNrInputPins = 0x01, + .baSourceId = {0x02}, + .baSourcePin = {0x01}, + .iJack = 0x00, + }, + + .MIDI_OUT_JACK_4 = { + .bLength = MIDI_OUT_JACK_DESCRIPTOR_SIZE(1), + .bDescriptorType = USB_DESCRIPTOR_TYPE_CS_INTERFACE, + .SubType = MIDI_OUT_JACK, + .bJackType = MIDI_JACK_EXTERNAL, +// .bJackId = 0x04, + .bJackId = 0x03, + .bNrInputPins = 0x01, + .baSourceId = {0x01}, + .baSourcePin = {0x01}, + .iJack = 0x00, + }, + + .DataOutEndpoint = { + .bLength = sizeof(usb_descriptor_endpoint), + .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT, + .bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_OUT | + MIDI_ENDPOINT_RX), // PATCH + .bmAttributes = USB_EP_TYPE_BULK, + .wMaxPacketSize = USB_MIDI_RX_EPSIZE, + .bInterval = 0x00, + }, + + .MS_CS_DataOutEndpoint = { + .bLength = MS_CS_BULK_ENDPOINT_DESCRIPTOR_SIZE(1), + .bDescriptorType = USB_DESCRIPTOR_TYPE_CS_ENDPOINT, + .SubType = 0x01, + .bNumEmbMIDIJack = 0x01, + .baAssocJackID = {0x01}, + }, + + .DataInEndpoint = { + .bLength = sizeof(usb_descriptor_endpoint), + .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT, + .bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_IN | MIDI_ENDPOINT_TX), // PATCH + .bmAttributes = USB_EP_TYPE_BULK, + .wMaxPacketSize = USB_MIDI_TX_EPSIZE, + .bInterval = 0x00, + }, + + .MS_CS_DataInEndpoint = { + .bLength = MS_CS_BULK_ENDPOINT_DESCRIPTOR_SIZE(1), + .bDescriptorType = USB_DESCRIPTOR_TYPE_CS_ENDPOINT, + .SubType = 0x01, + .bNumEmbMIDIJack = 0x01, + .baAssocJackID = {0x03}, + }, + +}; + +/* I/O state */ + +/* Received data */ +static volatile uint32 midiBufferRx[USB_MIDI_RX_EPSIZE/4]; +/* Read index into midiBufferRx */ +static volatile uint32 rx_offset = 0; +/* Transmit data */ +static volatile uint32 midiBufferTx[USB_MIDI_TX_EPSIZE/4]; +/* Write index into midiBufferTx */ +static volatile uint32 tx_offset = 0; +/* Number of bytes left to transmit */ +static volatile uint32 n_unsent_packets = 0; +/* Are we currently sending an IN packet? */ +static volatile uint8 transmitting = 0; +/* Number of unread bytes */ +static volatile uint32 n_unread_packets = 0; + + +// eventually all of this should be in a place for settings which can be written to flash. +volatile uint8 myMidiChannel = DEFAULT_MIDI_CHANNEL; +volatile uint8 myMidiDevice = DEFAULT_MIDI_DEVICE; +volatile uint8 myMidiCable = DEFAULT_MIDI_CABLE; +volatile uint8 myMidiID[] = { LEAFLABS_MMA_VENDOR_1,LEAFLABS_MMA_VENDOR_2,LEAFLABS_MMA_VENDOR_3,0}; + +#define OUT_BYTE(s,v) out[(uint8*)&(s.v)-(uint8*)&s] + +static void getMIDIPartDescriptor(uint8* out) { + memcpy(out, &usbMIDIDescriptor_Config, sizeof(usbMIDIDescriptor_Config)); + // patch to reflect where the part goes in the descriptor + OUT_BYTE(usbMIDIDescriptor_Config, AC_Interface.bInterfaceNumber) += usbMIDIPart.startInterface; + OUT_BYTE(usbMIDIDescriptor_Config, MS_Interface.bInterfaceNumber) += usbMIDIPart.startInterface; + OUT_BYTE(usbMIDIDescriptor_Config, DataOutEndpoint.bEndpointAddress) += usbMIDIPart.startEndpoint; + OUT_BYTE(usbMIDIDescriptor_Config, DataInEndpoint.bEndpointAddress) += usbMIDIPart.startEndpoint; +} + +static USBEndpointInfo midiEndpoints[2] = { + { + .callback = midiDataRxCb, + .bufferSize = USB_MIDI_RX_EPSIZE, + .type = USB_EP_EP_TYPE_BULK, + .tx = 0 + }, + { + .callback = midiDataTxCb, + .bufferSize = USB_MIDI_TX_EPSIZE, + .type = USB_EP_EP_TYPE_BULK, + .tx = 1, + } +}; + +USBCompositePart usbMIDIPart = { + .numInterfaces = 2, + .numEndpoints = sizeof(midiEndpoints)/sizeof(*midiEndpoints), + .descriptorSize = sizeof(usbMIDIDescriptor_Config), + .getPartDescriptor = getMIDIPartDescriptor, + .usbInit = NULL, + .usbReset = usbMIDIReset, + .usbDataSetup = usbMIDIDataSetup, + .usbNoDataSetup = usbMIDINoDataSetup, + .endpoints = midiEndpoints +}; + +/* + * MIDI interface + */ + +/* This function is non-blocking. + * + * It copies data from a usercode buffer into the USB peripheral TX + * buffer, and returns the number of bytes copied. */ +uint32 usb_midi_tx(const uint32* buf, uint32 packets) { + uint32 bytes=packets*4; + /* Last transmission hasn't finished, so abort. */ + if (usb_midi_is_transmitting()) { + /* Copy to TxBuffer */ + + return 0; /* return len */ + } + + /* We can only put USB_MIDI_TX_EPSIZE bytes in the buffer. */ + if (bytes > USB_MIDI_TX_EPSIZE) { + bytes = USB_MIDI_TX_EPSIZE; + packets=bytes/4; + } + + /* Queue bytes for sending. */ + if (packets) { + usb_copy_to_pma((uint8 *)buf, bytes, USB_MIDI_TX_ADDR); + } + // 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_MIDI_TX_ENDP, bytes); + n_unsent_packets = packets; + transmitting = 1; + usb_set_ep_tx_stat(USB_MIDI_TX_ENDP, USB_EP_STAT_TX_VALID); + + return packets; +} + +uint32 usb_midi_data_available(void) { + return n_unread_packets; +} + +uint8 usb_midi_is_transmitting(void) { + return transmitting; +} + +uint16 usb_midi_get_pending(void) { + return n_unsent_packets; +} + +/* Nonblocking byte receive. + * + * Copies up to len bytes from our private data buffer (*NOT* the PMA) + * into buf and deq's the FIFO. */ +uint32 usb_midi_rx(uint32* buf, uint32 packets) { + /* Copy bytes to buffer. */ + uint32 n_copied = usb_midi_peek(buf, packets); + + /* Mark bytes as read. */ + n_unread_packets -= n_copied; + rx_offset += n_copied; + + /* 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_packets == 0) { + usb_set_ep_rx_count(USB_MIDI_RX_ENDP, USB_MIDI_RX_EPSIZE); + usb_set_ep_rx_stat(USB_MIDI_RX_ENDP, USB_EP_STAT_RX_VALID); + rx_offset = 0; + } + + return n_copied; +} + +/* Nonblocking byte lookahead. + * + * Looks at unread bytes without marking them as read. */ +uint32 usb_midi_peek(uint32* buf, uint32 packets) { + uint32 i; + if (packets > n_unread_packets) { + packets = n_unread_packets; + } + + for (i = 0; i < packets; i++) { + buf[i] = midiBufferRx[i + rx_offset]; + } + + return packets; +} + +/* + * Callbacks + */ + +static void midiDataTxCb(void) { + n_unsent_packets = 0; + transmitting = 0; +} + +static void midiDataRxCb(void) { + usb_set_ep_rx_stat(USB_MIDI_RX_ENDP, USB_EP_STAT_RX_NAK); + n_unread_packets = usb_get_ep_rx_count(USB_MIDI_RX_ENDP) / 4; + /* 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*)midiBufferRx, n_unread_packets * 4, + USB_MIDI_RX_ADDR); + + // discard volatile + LglSysexHandler((uint32*)midiBufferRx,(uint32*)&rx_offset,(uint32*)&n_unread_packets); + + if (n_unread_packets == 0) { + usb_set_ep_rx_count(USB_MIDI_RX_ENDP, USB_MIDI_RX_EPSIZE); + usb_set_ep_rx_stat(USB_MIDI_RX_ENDP, USB_EP_STAT_RX_VALID); + rx_offset = 0; + } + +} + +static void usbMIDIReset(void) { + /* Reset the RX/TX state */ + n_unread_packets = 0; + n_unsent_packets = 0; + rx_offset = 0; +} + +static RESULT usbMIDIDataSetup(uint8 request) { + (void)request;//unused +#if 0 + uint8* (*CopyRoutine)(uint16) = 0; + + if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) { + } + + if (CopyRoutine == NULL) { + return USB_UNSUPPORT; + } + + pInformation->Ctrl_Info.CopyData = CopyRoutine; + pInformation->Ctrl_Info.Usb_wOffset = 0; + (*CopyRoutine)(0); + return USB_SUCCESS; +#endif + return USB_UNSUPPORT; +} + +static RESULT usbMIDINoDataSetup(uint8 request) { + (void)request;//unused +#if 0 + RESULT ret = USB_UNSUPPORT; + + if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) { + } + return ret; +#endif + return USB_UNSUPPORT; +} + +// .............THIS IS NOT WORKING YET................ +// send debugging information to +static uint8_t sysexbuffer[80]={CIN_SYSEX,0xF0,0x7D,0x33,CIN_SYSEX,0x33,0x00,0xf7}; // !!!bad hardcoded number foo !!! +uint8_t iSysHexLine(uint8_t rectype, uint16_t address, uint8_t *payload,uint8_t payloadlength, uint8_t *buffer); +void sendThroughSysex(char *printbuffer, int bufferlength) { + int n; + n = iSysHexLine(1, 0 , (uint8_t *) printbuffer, (uint8_t) bufferlength , sysexbuffer+6); + usb_midi_tx((uint32*)sysexbuffer,n/4); +} + +#define HIGHBYTE(x) ((uint8_t) (((x) >> 8) & 0x00ff) ) +#define LOWBYTE(x) ((uint8_t) ((x) & 0x00ff) ) +#define HIGHNIBBLE(x) ((((uint8_t)(x)) & 0xF0) >> 4) +#define LOWNIBBLE(x) (((uint8_t)(x)) & 0x0F) +#define HEXCHAR(c) ((c>9)?55+c:48+c) + + +uint8_t iSysHexLine(uint8_t rectype, uint16_t address, uint8_t *payload,uint8_t payloadlength, uint8_t *buffer) { + + int i=0; int j; int thirdone; + uint8_t n=0; + uint16_t checksum=0; + //uint16_t length=0; + + buffer[i++]=':'; + + checksum+=payloadlength; + buffer[i++]=HEXCHAR(HIGHNIBBLE(payloadlength)); + buffer[i++]=HEXCHAR(LOWNIBBLE(payloadlength)); + buffer[i++]=CIN_SYSEX; + + n=HIGHBYTE(address); + checksum+=n; + buffer[i++]=HEXCHAR(HIGHNIBBLE(n)); + buffer[i++]=HEXCHAR(LOWNIBBLE(n)); + + n=LOWBYTE(address); + checksum+=n; + buffer[i++]=HEXCHAR(HIGHNIBBLE(n)); + buffer[i++]=CIN_SYSEX; + buffer[i++]=HEXCHAR(LOWNIBBLE(n)); + + n=rectype; + checksum+=n; + buffer[i++]=HEXCHAR(HIGHNIBBLE(n)); + buffer[i++]=HEXCHAR(LOWNIBBLE(n)); + buffer[i++]=CIN_SYSEX; + thirdone=0; + for (j=0; j +#include +#include +#include +#include "usb_generic.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern USBCompositePart usbMIDIPart; + +typedef union { + uint8 byte[4]; + uint32 data; +} USB_MIDI_Event_Packet; + +/* + * USB MIDI Requests + */ + +/* + * Descriptors, etc. + */ +#define USB_DESCRIPTOR_TYPE_CS_INTERFACE 0x24 +#define USB_DESCRIPTOR_TYPE_CS_ENDPOINT 0x25 + + +#define USB_DEVICE_CLASS_UNDEFINED 0x00 +#define USB_DEVICE_CLASS_CDC 0x02 +#define USB_DEVICE_SUBCLASS_UNDEFINED 0x00 + +#define USB_INTERFACE_CLASS_AUDIO 0x01 +#define USB_INTERFACE_SUBCLASS_UNDEFINED 0x00 +#define USB_INTERFACE_AUDIOCONTROL 0x01 +#define USB_INTERFACE_AUDIOSTREAMING 0x02 +#define USB_INTERFACE_MIDISTREAMING 0x03 + +/* MIDI Streaming class specific interfaces */ +#define MIDI_IN_JACK 0x02 +#define MIDI_OUT_JACK 0x03 + +#define MIDI_JACK_EMBEDDED 0x01 +#define MIDI_JACK_EXTERNAL 0x02 + + +#define AC_CS_INTERFACE_DESCRIPTOR_SIZE(DataSize) (8 + DataSize) +#define AC_CS_INTERFACE_DESCRIPTOR(DataSize) \ + struct { \ + uint8 bLength; \ + uint8 bDescriptorType; \ + uint8 SubType; \ + uint16 bcdADC; \ + uint16 wTotalLength; \ + uint8 bInCollection; \ + uint8 baInterfaceNr[DataSize]; \ + } __packed + +typedef struct { + uint8 bLength; + uint8 bDescriptorType; + uint8 SubType; + uint16 bcdADC; + uint16 wTotalLength; + } __packed MS_CS_INTERFACE_DESCRIPTOR; + +typedef struct { + uint8 bLength; + uint8 bDescriptorType; + uint8 SubType; + uint8 bJackType; + uint8 bJackId; + uint8 iJack; + } __packed MIDI_IN_JACK_DESCRIPTOR; + +#define MIDI_OUT_JACK_DESCRIPTOR_SIZE(DataSize) (7 + 2*DataSize) +#define MIDI_OUT_JACK_DESCRIPTOR(DataSize) \ + struct { \ + uint8 bLength; \ + uint8 bDescriptorType; \ + uint8 SubType; \ + uint8 bJackType; \ + uint8 bJackId; \ + uint8 bNrInputPins; \ + uint8 baSourceId[DataSize]; \ + uint8 baSourcePin[DataSize]; \ + uint8 iJack; \ + } __packed + + +#define MS_CS_BULK_ENDPOINT_DESCRIPTOR_SIZE(DataSize) (4 + DataSize) +#define MS_CS_BULK_ENDPOINT_DESCRIPTOR(DataSize) \ + struct { \ + uint8 bLength; \ + uint8 bDescriptorType; \ + uint8 SubType; \ + uint8 bNumEmbMIDIJack; \ + uint8 baAssocJackID[DataSize]; \ + } __packed + +/* + * Endpoint configuration + */ + +#define USB_MIDI_TX_EPSIZE 0x40 + +#define USB_MIDI_RX_EPSIZE 0x40 + +#ifndef __cplusplus +#define USB_MIDI_DECLARE_DEV_DESC(vid, pid) \ + { \ + .bLength = sizeof(usb_descriptor_device), \ + .bDescriptorType = USB_DESCRIPTOR_TYPE_DEVICE, \ + .bcdUSB = 0x0110, \ + .bDeviceClass = USB_DEVICE_CLASS_UNDEFINED, \ + .bDeviceSubClass = USB_DEVICE_SUBCLASS_UNDEFINED, \ + .bDeviceProtocol = 0x00, \ + .bMaxPacketSize0 = 0x40, \ + .idVendor = vid, \ + .idProduct = pid, \ + .bcdDevice = 0x0200, \ + .iManufacturer = 0x01, \ + .iProduct = 0x02, \ + .iSerialNumber = 0x00, \ + .bNumConfigurations = 0x01, \ + } +#endif + +/* + * Sysex Stuff. + */ + +#define SYSEX_BUFFER_LENGTH 256 + + + /* + * MIDI interface + */ + + void usb_midi_putc(char ch); + uint32 usb_midi_tx(const uint32* buf, uint32 len); + uint32 usb_midi_rx(uint32* buf, uint32 len); + uint32 usb_midi_peek(uint32* buf, uint32 len); + + uint32 usb_midi_data_available(void); /* in RX buffer */ + uint16 usb_midi_get_pending(void); + uint8 usb_midi_is_transmitting(void); + + void sendThroughSysex(char *printbuffer, int bufferlength); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/STM32F1/libraries/USBComposite/usb_scsi.c b/STM32F1/libraries/USBComposite/usb_scsi.c new file mode 100644 index 0000000..2ff3dfd --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_scsi.c @@ -0,0 +1,333 @@ +#include "usb_mass.h" +#include "usb_mass_mal.h" +#include "usb_mass_internal.h" +#include "usb_scsi.h" + +#include +#include +#include + +/* Private headers */ +#include "usb_lib_globals.h" +#include "usb_reg_map.h" +#include "usb_regs.h" + +/* usb_lib headers */ +#include "usb_type.h" +#include "usb_core.h" +#include "usb_def.h" + +#define SCSI_READ_FORMAT_CAPACITY_DATA_LEN 0x0C +#define SCSI_READ_FORMAT_CAPACITY10_DATA_LEN 0x08 +#define SCSI_MODE_SENSE6_DATA_LEN 0x04 +#define SCSI_MODE_SENSE10_DATA_LEN 0x08 + +#define SCSI_TXFR_IDLE 0 +#define SCSI_TXFR_ONGOING 1 + +extern uint32_t usb_mass_sil_write(uint8_t* pBufferPointer, uint32_t wBufferSize); + +/* See usb_scsi_data.c */ +extern uint8_t SCSI_page00InquiryData[]; +extern uint8_t SCSI_standardInquiryData[]; +extern uint8_t SCSI_standardInquiryData2[]; +extern uint8_t SCSI_senseData[]; +extern uint8_t SCSI_modeSense6Data[]; +extern uint8_t SCSI_modeSense10Data[]; +extern uint8_t SCSI_readFormatCapacityData[]; +extern uint8_t SCSI_readFormatCapacity10Data[]; + +uint32_t SCSI_lba; +uint32_t SCSI_blkLen; +uint8_t SCSI_transferState = SCSI_TXFR_IDLE; +uint32_t SCSI_blockReadCount = 0; +uint32_t SCSI_blockOffset; +uint32_t SCSI_counter = 0; +uint8_t SCSI_dataBuffer[512]; /* 512 bytes (SDCard block size) */ + +uint8_t scsi_address_management(uint8_t lun, uint8_t cmd, uint32_t lba, uint32_t blockNbr); +void scsi_read_memory(uint8_t lun, uint32_t memoryOffset, uint32_t transferLength); +void scsi_write_memory(uint8_t lun, uint32_t memoryOffset, uint32_t transferLength); + +void scsi_inquiry_cmd(uint8_t lun) { + uint8_t* inquiryData; + uint16_t inquiryDataLength; + + if (usb_mass_CBW.CB[1] & 0x01) /*Evpd is set*/ { + inquiryData = SCSI_page00InquiryData; + inquiryDataLength = 5; + } else { + if (lun == 0) { + inquiryData = SCSI_standardInquiryData; + } else { + inquiryData = SCSI_standardInquiryData2; + } + + if (usb_mass_CBW.CB[4] <= SCSI_STANDARD_INQUIRY_DATA_LEN) { + inquiryDataLength = usb_mass_CBW.CB[4]; + } else { + inquiryDataLength = SCSI_STANDARD_INQUIRY_DATA_LEN; + } + } + usb_mass_transfer_data_request(inquiryData, inquiryDataLength); +} + +void scsi_request_sense_cmd(uint8_t lun) { + uint8_t requestSenseDataLength; + if (usb_mass_CBW.CB[4] <= SCSI_REQUEST_SENSE_DATA_LEN) { + requestSenseDataLength = usb_mass_CBW.CB[4]; + } else { + requestSenseDataLength = SCSI_REQUEST_SENSE_DATA_LEN; + } + usb_mass_transfer_data_request(SCSI_senseData, requestSenseDataLength); +} + +void scsi_start_stop_unit_cmd(uint8_t lun) { + usb_mass_bot_set_csw(BOT_CSW_CMD_PASSED, BOT_SEND_CSW_ENABLE); +} + +void scsi_mode_sense6_cmd(uint8_t lun) { + usb_mass_transfer_data_request(SCSI_modeSense6Data, SCSI_MODE_SENSE6_DATA_LEN); +} + +void scsi_mode_sense10_cmd(uint8_t lun) { + usb_mass_transfer_data_request(SCSI_modeSense10Data, SCSI_MODE_SENSE10_DATA_LEN); +} + +void scsi_read_format_capacity_cmd(uint8_t lun) { + if (usb_mass_mal_get_status(lun)) { + scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_NOT_READY, SCSI_MEDIUM_NOT_PRESENT); + usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_ENABLE); + usb_mass_bot_abort(BOT_DIR_IN); + return; + } + SCSI_readFormatCapacityData[4] = (uint8_t) (usb_mass_drives[lun].blockCount >> 24); + SCSI_readFormatCapacityData[5] = (uint8_t) (usb_mass_drives[lun].blockCount >> 16); + SCSI_readFormatCapacityData[6] = (uint8_t) (usb_mass_drives[lun].blockCount >> 8); + SCSI_readFormatCapacityData[7] = (uint8_t) (usb_mass_drives[lun].blockCount); + + SCSI_readFormatCapacityData[9] = (uint8_t) (SCSI_BLOCK_SIZE >> 16); + SCSI_readFormatCapacityData[10] = (uint8_t) (SCSI_BLOCK_SIZE >> 8); + SCSI_readFormatCapacityData[11] = (uint8_t) (SCSI_BLOCK_SIZE); + usb_mass_transfer_data_request(SCSI_readFormatCapacityData, SCSI_READ_FORMAT_CAPACITY_DATA_LEN); +} + +void scsi_read_capacity10_cmd(uint8_t lun) { + if (usb_mass_mal_get_status(lun)) { + scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_NOT_READY, SCSI_MEDIUM_NOT_PRESENT); + usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_ENABLE); + usb_mass_bot_abort(BOT_DIR_IN); + return; + } + + SCSI_readFormatCapacity10Data[0] = (uint8_t) ((usb_mass_drives[lun].blockCount - 1) >> 24); + SCSI_readFormatCapacity10Data[1] = (uint8_t) ((usb_mass_drives[lun].blockCount - 1) >> 16); + SCSI_readFormatCapacity10Data[2] = (uint8_t) ((usb_mass_drives[lun].blockCount - 1) >> 8); + SCSI_readFormatCapacity10Data[3] = (uint8_t) (usb_mass_drives[lun].blockCount - 1); + + SCSI_readFormatCapacity10Data[4] = (uint8_t) (SCSI_BLOCK_SIZE >> 24); + SCSI_readFormatCapacity10Data[5] = (uint8_t) (SCSI_BLOCK_SIZE >> 16); + SCSI_readFormatCapacity10Data[6] = (uint8_t) (SCSI_BLOCK_SIZE >> 8); + SCSI_readFormatCapacity10Data[7] = (uint8_t) (SCSI_BLOCK_SIZE); + usb_mass_transfer_data_request(SCSI_readFormatCapacity10Data, SCSI_READ_FORMAT_CAPACITY10_DATA_LEN); +} + +void scsi_read10_cmd(uint8_t lun, uint32_t lba, uint32_t blockNbr) { + if (usb_mass_botState == BOT_STATE_IDLE) { + if (!(scsi_address_management(usb_mass_CBW.bLUN, SCSI_READ10, lba, blockNbr))) /*address out of range*/ { + return; + } + + if ((usb_mass_CBW.bmFlags & 0x80) != 0) { + usb_mass_botState = BOT_STATE_DATA_IN; + scsi_read_memory(lun, lba, blockNbr); + } else { + usb_mass_bot_abort(BOT_DIR_BOTH); + scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_ILLEGAL_REQUEST, SCSI_INVALID_FIELED_IN_COMMAND); + usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_ENABLE); + } + return; + } else if (usb_mass_botState == BOT_STATE_DATA_IN) { + scsi_read_memory(lun, lba, blockNbr); + } +} + +void scsi_write10_cmd(uint8_t lun, uint32_t lba, uint32_t blockNbr) { + if (usb_mass_botState == BOT_STATE_IDLE) { + if (!(scsi_address_management(usb_mass_CBW.bLUN, SCSI_WRITE10, lba, blockNbr)))/*address out of range*/ { + return; + } + + if ((usb_mass_CBW.bmFlags & 0x80) == 0) { + usb_mass_botState = BOT_STATE_DATA_OUT; + SetEPRxStatus(USB_MASS_RX_ENDP, USB_EP_ST_RX_VAL); + } else { + usb_mass_bot_abort(BOT_DIR_IN); + scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_ILLEGAL_REQUEST, SCSI_INVALID_FIELED_IN_COMMAND); + usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_DISABLE); + } + return; + } else if (usb_mass_botState == BOT_STATE_DATA_OUT) { + scsi_write_memory(lun, lba, blockNbr); + } +} + +void scsi_test_unit_ready_cmd(uint8_t lun) { + if (usb_mass_mal_get_status(lun)) { + scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_NOT_READY, SCSI_MEDIUM_NOT_PRESENT); + usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_ENABLE); + usb_mass_bot_abort(BOT_DIR_IN); + return; + } else { + usb_mass_bot_set_csw(BOT_CSW_CMD_PASSED, BOT_SEND_CSW_ENABLE); + } +} + +void scsi_verify10_cmd(uint8_t lun) { + if ((usb_mass_CBW.dDataLength == 0) && !(usb_mass_CBW.CB[1] & SCSI_BLKVFY))/* BLKVFY not set*/ { + usb_mass_bot_set_csw(BOT_CSW_CMD_PASSED, BOT_SEND_CSW_ENABLE); + } else { + usb_mass_bot_abort(BOT_DIR_BOTH); + scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_ILLEGAL_REQUEST, SCSI_INVALID_FIELED_IN_COMMAND); + usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_DISABLE); + } +} + +void scsi_format_cmd(uint8_t lun) { + if (usb_mass_mal_get_status(lun)) { + scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_NOT_READY, SCSI_MEDIUM_NOT_PRESENT); + usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_ENABLE); + usb_mass_bot_abort(BOT_DIR_IN); + return; + } + usb_mass_mal_format(lun); + usb_mass_bot_set_csw(BOT_CSW_CMD_PASSED, BOT_SEND_CSW_ENABLE); +} + +void scsi_set_sense_data(uint8_t lun, uint8_t sensKey, uint8_t asc) { + SCSI_senseData[2] = sensKey; + SCSI_senseData[12] = asc; +} + +void scsi_invalid_cmd(uint8_t lun) { + if (usb_mass_CBW.dDataLength == 0) { + usb_mass_bot_abort(BOT_DIR_IN); + } else { + if ((usb_mass_CBW.bmFlags & 0x80) != 0) { + usb_mass_bot_abort(BOT_DIR_IN); + } else { + usb_mass_bot_abort(BOT_DIR_BOTH); + } + } + scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_ILLEGAL_REQUEST, SCSI_INVALID_COMMAND); + usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_DISABLE); +} + +uint8_t scsi_address_management(uint8_t lun, uint8_t cmd, uint32_t lba, uint32_t blockNbr) { + + if ((lba + blockNbr) > usb_mass_drives[lun].blockCount) { + if (cmd == SCSI_WRITE10) { + usb_mass_bot_abort(BOT_DIR_BOTH); + } + usb_mass_bot_abort(BOT_DIR_IN); + scsi_set_sense_data(lun, SCSI_ILLEGAL_REQUEST, SCSI_ADDRESS_OUT_OF_RANGE); + usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_DISABLE); + return (FALSE); + } + + + if (usb_mass_CBW.dDataLength != blockNbr * SCSI_BLOCK_SIZE) { + if (cmd == SCSI_WRITE10) { + usb_mass_bot_abort(BOT_DIR_BOTH); + } else { + usb_mass_bot_abort(BOT_DIR_IN); + } + scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_ILLEGAL_REQUEST, SCSI_INVALID_FIELED_IN_COMMAND); + usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_DISABLE); + return (FALSE); + } + return (TRUE); +} + +void scsi_read_memory(uint8_t lun, uint32_t memoryOffset, uint32_t transferLength) { + static uint32_t offset, length; + + if (SCSI_transferState == SCSI_TXFR_IDLE) { + offset = memoryOffset * SCSI_BLOCK_SIZE; + length = transferLength * SCSI_BLOCK_SIZE; + SCSI_transferState = SCSI_TXFR_ONGOING; + } + + if (SCSI_transferState == SCSI_TXFR_ONGOING) { + if (SCSI_blockReadCount == 0) { + usb_mass_mal_read_memory(lun, offset, SCSI_dataBuffer, SCSI_BLOCK_SIZE); + + usb_mass_sil_write(SCSI_dataBuffer, MAX_BULK_PACKET_SIZE); + + SCSI_blockReadCount = SCSI_BLOCK_SIZE - MAX_BULK_PACKET_SIZE; + SCSI_blockOffset = MAX_BULK_PACKET_SIZE; + } else { + usb_mass_sil_write(SCSI_dataBuffer + SCSI_blockOffset, MAX_BULK_PACKET_SIZE); + + SCSI_blockReadCount -= MAX_BULK_PACKET_SIZE; + SCSI_blockOffset += MAX_BULK_PACKET_SIZE; + } + + SetEPTxStatus(USB_MASS_TX_ENDP, USB_EP_ST_TX_VAL); + + offset += MAX_BULK_PACKET_SIZE; + length -= MAX_BULK_PACKET_SIZE; + + usb_mass_CSW.dDataResidue -= MAX_BULK_PACKET_SIZE; + usb_mass_CSW.bStatus = BOT_CSW_CMD_PASSED; + // TODO: Led_RW_ON(); + } + + if (length == 0) { + SCSI_blockReadCount = 0; + SCSI_blockOffset = 0; + offset = 0; + usb_mass_botState = BOT_STATE_DATA_IN_LAST; + SCSI_transferState = SCSI_TXFR_IDLE; + // TODO: Led_RW_OFF(); + } +} + +void scsi_write_memory(uint8_t lun, uint32_t memoryOffset, uint32_t transferLength) { + static uint32_t offset, length; + uint32_t idx; + uint32_t temp = SCSI_counter + 64; + + if (SCSI_transferState == SCSI_TXFR_IDLE) { + offset = memoryOffset * SCSI_BLOCK_SIZE; + length = transferLength * SCSI_BLOCK_SIZE; + SCSI_transferState = SCSI_TXFR_ONGOING; + } + + if (SCSI_transferState == SCSI_TXFR_ONGOING) { + + for (idx = 0; SCSI_counter < temp; SCSI_counter++) { + *((uint8_t *) SCSI_dataBuffer + SCSI_counter) = usb_mass_bulkDataBuff[idx++]; + } + + offset += usb_mass_dataLength; + length -= usb_mass_dataLength; + + if (!(length % SCSI_BLOCK_SIZE)) { + SCSI_counter = 0; + usb_mass_mal_write_memory(lun, offset - SCSI_BLOCK_SIZE, SCSI_dataBuffer, SCSI_BLOCK_SIZE); + } + + usb_mass_CSW.dDataResidue -= usb_mass_dataLength; + SetEPRxStatus(USB_MASS_RX_ENDP, USB_EP_ST_RX_VAL); /* enable the next transaction*/ + + // TODO: Led_RW_ON(); + } + + if ((length == 0) || (usb_mass_botState == BOT_STATE_CSW_Send)) { + SCSI_counter = 0; + usb_mass_bot_set_csw(BOT_CSW_CMD_PASSED, BOT_SEND_CSW_ENABLE); + SCSI_transferState = SCSI_TXFR_IDLE; + // TODO: Led_RW_OFF(); + } +} \ No newline at end of file diff --git a/STM32F1/libraries/USBComposite/usb_scsi.h b/STM32F1/libraries/USBComposite/usb_scsi.h new file mode 100644 index 0000000..a5b121a --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_scsi.h @@ -0,0 +1,96 @@ +#ifndef __USB_SCSI_H +#define __USB_SCSI_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define SCSI_BLOCK_SIZE 512 + + /* SCSI Commands */ +#define SCSI_FORMAT_UNIT 0x04 +#define SCSI_INQUIRY 0x12 +#define SCSI_MODE_SELECT6 0x15 +#define SCSI_MODE_SELECT10 0x55 +#define SCSI_MODE_SENSE6 0x1A +#define SCSI_MODE_SENSE10 0x5A +#define SCSI_ALLOW_MEDIUM_REMOVAL 0x1E +#define SCSI_READ6 0x08 +#define SCSI_READ10 0x28 +#define SCSI_READ12 0xA8 +#define SCSI_READ16 0x88 + +#define SCSI_READ_CAPACITY10 0x25 +#define SCSI_READ_CAPACITY16 0x9E + +#define SCSI_REQUEST_SENSE 0x03 +#define SCSI_START_STOP_UNIT 0x1B +#define SCSI_TEST_UNIT_READY 0x00 +#define SCSI_WRITE6 0x0A +#define SCSI_WRITE10 0x2A +#define SCSI_WRITE12 0xAA +#define SCSI_WRITE16 0x8A + +#define SCSI_VERIFY10 0x2F +#define SCSI_VERIFY12 0xAF +#define SCSI_VERIFY16 0x8F + +#define SCSI_SEND_DIAGNOSTIC 0x1D +#define SCSI_READ_FORMAT_CAPACITIES 0x23 + +#define SCSI_NO_SENSE 0 +#define SCSI_RECOVERED_ERROR 1 +#define SCSI_NOT_READY 2 +#define SCSI_MEDIUM_ERROR 3 +#define SCSI_HARDWARE_ERROR 4 +#define SCSI_ILLEGAL_REQUEST 5 +#define SCSI_UNIT_ATTENTION 6 +#define SCSI_DATA_PROTECT 7 +#define SCSI_BLANK_CHECK 8 +#define SCSI_VENDOR_SPECIFIC 9 +#define SCSI_COPY_ABORTED 10 +#define SCSI_ABORTED_COMMAND 11 +#define SCSI_VOLUME_OVERFLOW 13 +#define SCSI_MISCOMPARE 14 + +#define SCSI_INVALID_COMMAND 0x20 +#define SCSI_INVALID_FIELED_IN_COMMAND 0x24 +#define SCSI_PARAMETER_LIST_LENGTH_ERROR 0x1A +#define SCSI_INVALID_FIELD_IN_PARAMETER_LIST 0x26 +#define SCSI_ADDRESS_OUT_OF_RANGE 0x21 +#define SCSI_MEDIUM_NOT_PRESENT 0x3A +#define SCSI_MEDIUM_HAVE_CHANGED 0x28 + +#define SCSI_READ_FORMAT_CAPACITY_DATA_LEN 0x0C +#define SCSI_READ_CAPACITY10_DATA_LEN 0x08 +#define SCSI_MODE_SENSE10_DATA_LEN 0x08 +#define SCSI_MODE_SENSE6_DATA_LEN 0x04 +#define SCSI_REQUEST_SENSE_DATA_LEN 0x12 +#define SCSI_STANDARD_INQUIRY_DATA_LEN 0x24 +#define SCSI_BLKVFY 0x04 + + extern uint32_t SCSI_lba; + extern uint32_t SCSI_blkLen; + + void scsi_inquiry_cmd(uint8_t lun); + void scsi_request_sense_cmd(uint8_t lun); + void scsi_start_stop_unit_cmd(uint8_t lun); + void scsi_mode_sense6_cmd(uint8_t lun); + void scsi_mode_sense10_cmd(uint8_t lun); + void scsi_read_format_capacity_cmd(uint8_t lun); + void scsi_read_capacity10_cmd(uint8_t lun); + void scsi_read10_cmd(uint8_t lun, uint32_t lba, uint32_t blockNbr); + void scsi_write10_cmd(uint8_t lun, uint32_t lba, uint32_t blockNbr); + void scsi_test_unit_ready_cmd(uint8_t lun); + void scsi_verify10_cmd(uint8_t lun); + void scsi_format_cmd(uint8_t lun); + void scsi_set_sense_data(uint8_t lun, uint8_t sensKey, uint8_t asc); + void scsi_invalid_cmd(uint8_t lun); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/STM32F1/libraries/USBComposite/usb_scsi_data.c b/STM32F1/libraries/USBComposite/usb_scsi_data.c new file mode 100644 index 0000000..a692fd7 --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_scsi_data.c @@ -0,0 +1,120 @@ + +#include "usb_scsi.h" + +uint8_t SCSI_page00InquiryData[] = { + 0x00, /* PERIPHERAL QUALIFIER & PERIPHERAL DEVICE TYPE*/ + 0x00, + 0x00, + 0x00, + 0x00 /* Supported Pages 00*/ +}; + +uint8_t SCSI_standardInquiryData[] = { + 0x00, /* Direct Access Device */ + 0x80, /* RMB = 1: Removable Medium */ + 0x02, /* Version: No conformance claim to standard */ + 0x02, + + 36 - 4, /* Additional Length */ + 0x00, /* SCCS = 1: Storage Controller Component */ + 0x00, + 0x00, + /* Vendor Identification */ + 'S', 'T', 'M', ' ', ' ', ' ', ' ', ' ', + /* Product Identification */ + 'S', 'D', ' ', 'F', 'l', 'a', 's', 'h', ' ', + 'D', 'i', 's', 'k', ' ', ' ', ' ', + /* Product Revision Level */ + '1', '.', '0', ' ' +}; + +uint8_t SCSI_standardInquiryData2[] = { + 0x00, /* Direct Access Device */ + 0x80, /* RMB = 1: Removable Medium */ + 0x02, /* Version: No conformance claim to standard */ + 0x02, + + 36 - 4, /* Additional Length */ + 0x00, /* SCCS = 1: Storage Controller Component */ + 0x00, + 0x00, + /* Vendor Identification */ + 'S', 'T', 'M', ' ', ' ', ' ', ' ', ' ', + /* Product Identification */ + 'N', 'A', 'N', 'D', ' ', 'F', 'l', 'a', 's', 'h', ' ', + 'D', 'i', 's', 'k', ' ', + /* Product Revision Level */ + '1', '.', '0', ' ' +}; + +uint8_t SCSI_senseData[] = { + 0x70, /*RespCode*/ + 0x00, /*SegmentNumber*/ + SCSI_NO_SENSE, /* Sens_Key*/ + 0x00, + 0x00, + 0x00, + 0x00, /*Information*/ + 0x0A, /*AdditionalSenseLength*/ + 0x00, + 0x00, + 0x00, + 0x00, /*CmdInformation*/ + SCSI_NO_SENSE, /*Asc*/ + 0x00, /*ASCQ*/ + 0x00, /*FRUC*/ + 0x00, /*TBD*/ + 0x00, + 0x00 /*SenseKeySpecific*/ +}; + +uint8_t SCSI_modeSense6Data[] = { + 0x03, + 0x00, + 0x00, + 0x00, +}; + +uint8_t SCSI_modeSense10Data[] = { + 0x00, + 0x06, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00 +}; + +uint8_t SCSI_readFormatCapacityData[] = { + 0x00, + 0x00, + 0x00, + 0x08, /* Capacity List Length */ + + /* Block Count */ + 0, + 0, + 0, + 0, + + /* Block Length */ + 0x02, /* Descriptor Code: Formatted Media */ + 0, + 0, + 0 +}; + +uint8_t SCSI_readFormatCapacity10Data[] = { + /* Last Logical Block */ + 0, + 0, + 0, + 0, + + /* Block Length */ + 0, + 0, + 0, + 0 +}; \ No newline at end of file diff --git a/STM32F1/libraries/USBComposite/usb_serial.c b/STM32F1/libraries/USBComposite/usb_serial.c new file mode 100644 index 0000000..390d256 --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_serial.c @@ -0,0 +1,580 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/usb/stm32f1/usb_hid.c + * @brief USB HID (human interface device) support + * + * FIXME: this works on the STM32F1 USB peripherals, and probably no + * place else. Nonportable bits really need to be factored out, and + * the result made cleaner. + */ + +#include "usb_serial.h" +#include "usb_generic.h" +#include +#include +#include +#include + +/* Private headers */ +#include "usb_lib_globals.h" +#include "usb_reg_map.h" + +#define CDCACM_ENDPOINT_TX 0 +#define CDCACM_ENDPOINT_MANAGEMENT 1 +#define CDCACM_ENDPOINT_RX 2 + +uint16 GetEPTxAddr(uint8 /*bEpNum*/); + +/* usb_lib headers */ +#include "usb_type.h" +#include "usb_core.h" +#include "usb_def.h" + +static void serialUSBReset(void); +static RESULT serialUSBDataSetup(uint8 request); +static RESULT serialUSBNoDataSetup(uint8 request); +static void vcomDataTxCb(void); +static void vcomDataRxCb(void); + +#define NUM_SERIAL_ENDPOINTS 3 +#define CCI_INTERFACE_OFFSET 0x00 +#define DCI_INTERFACE_OFFSET 0x01 +#define SERIAL_MANAGEMENT_INTERFACE_NUMBER (CCI_INTERFACE_OFFSET+usbSerialPart.startInterface) + +/* + * Descriptors + */ + + +typedef struct { + //CDCACM + IADescriptor IAD; + usb_descriptor_interface CCI_Interface; + CDC_FUNCTIONAL_DESCRIPTOR(2) CDC_Functional_IntHeader; + CDC_FUNCTIONAL_DESCRIPTOR(2) CDC_Functional_CallManagement; + CDC_FUNCTIONAL_DESCRIPTOR(1) CDC_Functional_ACM; + CDC_FUNCTIONAL_DESCRIPTOR(2) CDC_Functional_Union; + usb_descriptor_endpoint ManagementEndpoint; + usb_descriptor_interface DCI_Interface; + usb_descriptor_endpoint DataOutEndpoint; + usb_descriptor_endpoint DataInEndpoint; +} __packed serial_part_config; + + +static const serial_part_config serialPartConfigData = { + .IAD = { + .bLength = 0x08, + .bDescriptorType = 0x0B, + .bFirstInterface = CCI_INTERFACE_OFFSET, // PATCH + .bInterfaceCount = 0x02, + .bFunctionClass = 0x02, + .bFunctionSubClass = 0x02, + .bFunctionProtocol = 0x01, + .iFunction = 0x02, + }, + .CCI_Interface = { + .bLength = sizeof(usb_descriptor_interface), + .bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE, + .bInterfaceNumber = CCI_INTERFACE_OFFSET, // PATCH + .bAlternateSetting = 0x00, + .bNumEndpoints = 0x01, + .bInterfaceClass = USB_INTERFACE_CLASS_CDC, + .bInterfaceSubClass = USB_INTERFACE_SUBCLASS_CDC_ACM, + .bInterfaceProtocol = 0x01, /* Common AT Commands */ + .iInterface = 0x00, + }, + + .CDC_Functional_IntHeader = { + .bLength = CDC_FUNCTIONAL_DESCRIPTOR_SIZE(2), + .bDescriptorType = 0x24, + .SubType = 0x00, + .Data = {0x01, 0x10}, + }, + + .CDC_Functional_CallManagement = { + .bLength = CDC_FUNCTIONAL_DESCRIPTOR_SIZE(2), + .bDescriptorType = 0x24, + .SubType = 0x01, + .Data = {0x03, DCI_INTERFACE_OFFSET}, // PATCH + }, + + .CDC_Functional_ACM = { + .bLength = CDC_FUNCTIONAL_DESCRIPTOR_SIZE(1), + .bDescriptorType = 0x24, + .SubType = 0x02, + .Data = {0x06}, + }, + + .CDC_Functional_Union = { + .bLength = CDC_FUNCTIONAL_DESCRIPTOR_SIZE(2), + .bDescriptorType = 0x24, + .SubType = 0x06, + .Data = {CCI_INTERFACE_OFFSET, DCI_INTERFACE_OFFSET}, // PATCH, PATCH + }, + + .ManagementEndpoint = { + .bLength = sizeof(usb_descriptor_endpoint), + .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT, + .bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_IN | + CDCACM_ENDPOINT_MANAGEMENT), // PATCH + .bmAttributes = USB_EP_TYPE_INTERRUPT, + .wMaxPacketSize = USBHID_CDCACM_MANAGEMENT_EPSIZE, + .bInterval = 0xFF, + }, + + .DCI_Interface = { + .bLength = sizeof(usb_descriptor_interface), + .bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE, + .bInterfaceNumber = DCI_INTERFACE_OFFSET, // PATCH + .bAlternateSetting = 0x00, + .bNumEndpoints = 0x02, + .bInterfaceClass = USB_INTERFACE_CLASS_DIC, + .bInterfaceSubClass = 0x00, /* None */ + .bInterfaceProtocol = 0x00, /* None */ + .iInterface = 0x00, + }, + + .DataOutEndpoint = { + .bLength = sizeof(usb_descriptor_endpoint), + .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT, + .bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_OUT | + CDCACM_ENDPOINT_RX), // patch + .bmAttributes = USB_EP_TYPE_BULK, + .wMaxPacketSize = USBHID_CDCACM_RX_EPSIZE, + .bInterval = 0x00, + }, + + .DataInEndpoint = { + .bLength = sizeof(usb_descriptor_endpoint), + .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT, + .bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_IN | CDCACM_ENDPOINT_TX), // PATCH + .bmAttributes = USB_EP_TYPE_BULK, + .wMaxPacketSize = USBHID_CDCACM_TX_EPSIZE, + .bInterval = 0x00, + } +}; + +#define OUT_BYTE(s,v) out[(uint8*)&(s.v)-(uint8*)&s] + +static USBEndpointInfo serialEndpoints[3] = { + { + .callback = vcomDataTxCb, + .bufferSize = USBHID_CDCACM_TX_EPSIZE, + .type = USB_EP_EP_TYPE_BULK, + .tx = 1, + }, + { + .callback = NULL, + .bufferSize = USBHID_CDCACM_MANAGEMENT_EPSIZE, + .type = USB_EP_EP_TYPE_INTERRUPT, + .tx = 1, + }, + { + .callback = vcomDataRxCb, + .bufferSize = USBHID_CDCACM_RX_EPSIZE, + .type = USB_EP_EP_TYPE_BULK, + .tx = 0, + }, +}; + +static void getSerialPartDescriptor(uint8* out) { + memcpy(out, &serialPartConfigData, sizeof(serial_part_config)); + + // patch to reflect where the part goes in the descriptor + OUT_BYTE(serialPartConfigData, ManagementEndpoint.bEndpointAddress) += usbSerialPart.startEndpoint; + OUT_BYTE(serialPartConfigData, DataOutEndpoint.bEndpointAddress) += usbSerialPart.startEndpoint; + OUT_BYTE(serialPartConfigData, DataInEndpoint.bEndpointAddress) += usbSerialPart.startEndpoint; + + OUT_BYTE(serialPartConfigData, IAD.bFirstInterface) += usbSerialPart.startInterface; + OUT_BYTE(serialPartConfigData, CCI_Interface.bInterfaceNumber) += usbSerialPart.startInterface; + OUT_BYTE(serialPartConfigData, DCI_Interface.bInterfaceNumber) += usbSerialPart.startInterface; + OUT_BYTE(serialPartConfigData, CDC_Functional_CallManagement.Data[1]) += usbSerialPart.startInterface; + OUT_BYTE(serialPartConfigData, CDC_Functional_Union.Data[0]) += usbSerialPart.startInterface; + OUT_BYTE(serialPartConfigData, CDC_Functional_Union.Data[1]) += usbSerialPart.startInterface; +} + +USBCompositePart usbSerialPart = { + .numInterfaces = 2, + .numEndpoints = sizeof(serialEndpoints)/sizeof(*serialEndpoints), + .descriptorSize = sizeof(serial_part_config), + .getPartDescriptor = getSerialPartDescriptor, + .usbInit = NULL, + .usbReset = serialUSBReset, + .usbDataSetup = serialUSBDataSetup, + .usbNoDataSetup = serialUSBNoDataSetup, + .endpoints = serialEndpoints +}; + +#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_RX_BUFFER_SIZE]; +/* Write index to vcomBufferRx */ +static volatile uint32 vcom_rx_head; +/* Read index from vcomBufferRx */ +static volatile uint32 vcom_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 vcom_tx_head; +// Read index from vcomBufferTx +static volatile uint32 vcom_tx_tail; + + + +/* Other state (line coding, DTR/RTS) */ + +static volatile composite_cdcacm_line_coding line_coding = { + /* This default is 115200 baud, 8N1. */ + .dwDTERate = 115200, + .bCharFormat = USBHID_CDCACM_STOP_BITS_1, + .bParityType = USBHID_CDCACM_PARITY_NONE, + .bDataBits = 8, +}; + +/* DTR in bit 0, RTS in bit 1. */ +static volatile uint8 line_dtr_rts = 0; + + +static void (*rx_hook)(unsigned, void*) = 0; +static void (*iface_setup_hook)(unsigned, void*) = 0; + +void composite_cdcacm_set_hooks(unsigned hook_flags, void (*hook)(unsigned, void*)) { + if (hook_flags & USBHID_CDCACM_HOOK_RX) { + rx_hook = hook; + } + if (hook_flags & USBHID_CDCACM_HOOK_IFACE_SETUP) { + iface_setup_hook = hook; + } +} + +void composite_cdcacm_putc(char ch) { + while (!composite_cdcacm_tx((uint8*)&ch, 1)) + ; +} + +/* This function is non-blocking. + * + * It copies data from a user buffer into the USB peripheral TX + * buffer, and returns the number of bytes copied. */ +uint32 composite_cdcacm_tx(const uint8* buf, uint32 len) +{ + if (len==0) return 0; // no data to send + + uint32 head = vcom_tx_head; // load volatile variable + uint32 tx_unsent = (head - vcom_tx_tail) & CDC_SERIAL_TX_BUFFER_SIZE_MASK; + + // 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); + } + if (len==0) return 0; // buffer full + + uint16 i; + // copy data from user buffer to USB Tx buffer + for (i=0; i= 0); + + if (usbGenericTransmitting<0) { + vcomDataTxCb(); // initiate data transmission + } + + return len; +} + + + +uint32 composite_cdcacm_data_available(void) { + return (vcom_rx_head - vcom_rx_tail) & CDC_SERIAL_RX_BUFFER_SIZE_MASK; +} + +uint16 composite_cdcacm_get_pending(void) { + return (vcom_tx_head - vcom_tx_tail) & CDC_SERIAL_TX_BUFFER_SIZE_MASK; +} + +/* 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 composite_cdcacm_rx(uint8* buf, uint32 len) +{ + /* Copy bytes to buffer. */ + uint32 n_copied = composite_cdcacm_peek(buf, len); + + /* Mark bytes as read. */ + uint16 tail = vcom_rx_tail; // load volatile variable + tail = (tail + n_copied) & CDC_SERIAL_RX_BUFFER_SIZE_MASK; + vcom_rx_tail = tail; // store volatile variable + + uint32 rx_unread = (vcom_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(usbSerialPart.endpoints[CDCACM_ENDPOINT_RX].address, USB_EP_STAT_RX_VALID); + } + return n_copied; +} + +/* Non-blocking byte lookahead. + * + * Looks at unread bytes without marking them as read. */ +uint32 composite_cdcacm_peek(uint8* buf, uint32 len) +{ + unsigned i; + uint32 tail = vcom_rx_tail; + uint32 rx_unread = (vcom_rx_head-tail) & CDC_SERIAL_RX_BUFFER_SIZE_MASK; + + if (len > rx_unread) { + len = rx_unread; + } + + for (i = 0; i < len; i++) { + buf[i] = vcomBufferRx[tail]; + tail = (tail + 1) & CDC_SERIAL_RX_BUFFER_SIZE_MASK; + } + + return len; +} + +uint32 composite_cdcacm_peek_ex(uint8* buf, uint32 offset, uint32 len) +{ + unsigned i; + uint32 tail = (vcom_rx_tail + offset) & CDC_SERIAL_RX_BUFFER_SIZE_MASK ; + uint32 rx_unread = (vcom_rx_head-tail) & CDC_SERIAL_RX_BUFFER_SIZE_MASK; + + if (len + offset > rx_unread) { + len = rx_unread - offset; + } + + for (i = 0; i < len; i++) { + buf[i] = vcomBufferRx[tail]; + tail = (tail + 1) & CDC_SERIAL_RX_BUFFER_SIZE_MASK; + } + + return len; +} + +/* Roger Clark. Added. for Arduino 1.0 API support of Serial.peek() */ +int composite_cdcacm_peek_char() +{ + if (composite_cdcacm_data_available() == 0) + { + return -1; + } + + return vcomBufferRx[vcom_rx_tail]; +} + +uint8 composite_cdcacm_get_dtr() { + return ((line_dtr_rts & USBHID_CDCACM_CONTROL_LINE_DTR) != 0); +} + +uint8 composite_cdcacm_get_rts() { + return ((line_dtr_rts & USBHID_CDCACM_CONTROL_LINE_RTS) != 0); +} + +void composite_cdcacm_get_line_coding(composite_cdcacm_line_coding *ret) { + ret->dwDTERate = line_coding.dwDTERate; + ret->bCharFormat = line_coding.bCharFormat; + ret->bParityType = line_coding.bParityType; + ret->bDataBits = line_coding.bDataBits; +} + +int composite_cdcacm_get_baud(void) { + return line_coding.dwDTERate; +} + +int composite_cdcacm_get_stop_bits(void) { + return line_coding.bCharFormat; +} + +int composite_cdcacm_get_parity(void) { + return line_coding.bParityType; +} + +int composite_cdcacm_get_n_data_bits(void) { + return line_coding.bDataBits; +} + +/* + * Callbacks + */ +static void vcomDataTxCb(void) +{ + uint32 tail = vcom_tx_tail; // load volatile variable + uint32 tx_unsent = (vcom_tx_head - tail) & CDC_SERIAL_TX_BUFFER_SIZE_MASK; + if (tx_unsent==0) { + if ( (--usbGenericTransmitting)==0) goto flush_vcom; // no more data to send + return; // it was already flushed, keep Tx endpoint disabled + } + usbGenericTransmitting = 1; + // We can only send up to USBHID_CDCACM_TX_EPSIZE bytes in the endpoint. + if (tx_unsent > USBHID_CDCACM_TX_EPSIZE) { + tx_unsent = USBHID_CDCACM_TX_EPSIZE; + } + // copy the bytes from USB Tx buffer to PMA buffer + uint32 *dst = usb_pma_ptr(usbSerialPart.endpoints[CDCACM_ENDPOINT_TX].pmaAddress); + uint16 tmp = 0; + uint16 val; + unsigned 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; + } + vcom_tx_tail = tail; // store volatile variable +flush_vcom: + // enable Tx endpoint + usb_set_ep_tx_count(usbSerialPart.endpoints[CDCACM_ENDPOINT_TX].address, tx_unsent); + usb_set_ep_tx_stat(usbSerialPart.endpoints[CDCACM_ENDPOINT_TX].address, USB_EP_STAT_TX_VALID); +} + + +static void vcomDataRxCb(void) +{ + uint32 head = vcom_rx_head; // load volatile variable + + uint32 ep_rx_size = usb_get_ep_rx_count(usbSerialPart.endpoints[CDCACM_ENDPOINT_RX].address); + // 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(usbSerialPart.endpoints[CDCACM_ENDPOINT_RX].pmaAddress); + uint16 tmp = 0; + uint8 val; + uint32 i; + for (i = 0; i < ep_rx_size; i++) { + if (i&1) { + val = tmp>>8; + } else { + tmp = *src++; + val = tmp&0xFF; + } + vcomBufferRx[head] = val; + head = (head + 1) & CDC_SERIAL_RX_BUFFER_SIZE_MASK; + } + vcom_rx_head = head; // store volatile variable + + uint32 rx_unread = (head - vcom_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-USBHID_CDCACM_RX_EPSIZE) ) { + usb_set_ep_rx_stat(usbSerialPart.endpoints[CDCACM_ENDPOINT_RX].address, USB_EP_STAT_RX_VALID); + } + + if (rx_hook) { + rx_hook(USBHID_CDCACM_HOOK_RX, 0); + } +} + +static uint8* vcomGetSetLineCoding(uint16 length) { + if (length == 0) { + pInformation->Ctrl_Info.Usb_wLength = sizeof(struct composite_cdcacm_line_coding); + } + return (uint8*)&line_coding; +} + +static void serialUSBReset(void) { + //VCOM + vcom_rx_head = 0; + vcom_rx_tail = 0; + vcom_tx_head = 0; + vcom_tx_tail = 0; +} + +static RESULT serialUSBDataSetup(uint8 request) { + uint8* (*CopyRoutine)(uint16) = 0; + + if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT) && + pInformation->USBwIndex0 == SERIAL_MANAGEMENT_INTERFACE_NUMBER) { + switch (request) { + case USBHID_CDCACM_GET_LINE_CODING: + CopyRoutine = vcomGetSetLineCoding; + break; + case USBHID_CDCACM_SET_LINE_CODING: + CopyRoutine = vcomGetSetLineCoding; + break; + default: + break; + } + /* Call the user hook. */ + if (iface_setup_hook) { + uint8 req_copy = request; + iface_setup_hook(USBHID_CDCACM_HOOK_IFACE_SETUP, &req_copy); + } + } + + if (CopyRoutine == NULL){ + return USB_UNSUPPORT; + } + + pInformation->Ctrl_Info.CopyData = CopyRoutine; + pInformation->Ctrl_Info.Usb_wOffset = 0; + (*CopyRoutine)(0); + return USB_SUCCESS; +} + +static RESULT serialUSBNoDataSetup(uint8 request) { + RESULT ret = USB_UNSUPPORT; + + if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT) && + pInformation->USBwIndex0 == SERIAL_MANAGEMENT_INTERFACE_NUMBER) { + switch(request) { + case USBHID_CDCACM_SET_COMM_FEATURE: + /* We support set comm. feature, but don't handle it. */ + ret = USB_SUCCESS; + break; + case USBHID_CDCACM_SET_CONTROL_LINE_STATE: + /* Track changes to DTR and RTS. */ + line_dtr_rts = (pInformation->USBwValues.bw.bb0 & + (USBHID_CDCACM_CONTROL_LINE_DTR | + USBHID_CDCACM_CONTROL_LINE_RTS)); + ret = USB_SUCCESS; + break; + } + /* Call the user hook. */ + if (iface_setup_hook) { + uint8 req_copy = request; + iface_setup_hook(USBHID_CDCACM_HOOK_IFACE_SETUP, &req_copy); + } + } + return ret; +} + diff --git a/STM32F1/libraries/USBComposite/usb_serial.h b/STM32F1/libraries/USBComposite/usb_serial.h new file mode 100644 index 0000000..926901b --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_serial.h @@ -0,0 +1,157 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/usb_device.h + * @brief USB Composite with CDC ACM and HID support + * + * IMPORTANT: this API is unstable, and may change without notice. + */ + +#ifndef _USB_SERIAL_H_ +#define _USB_SERIAL_H_ + +#include +#include +#include "usb_generic.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern USBCompositePart usbSerialPart; + +/* + * CDC ACM Requests + */ + +#define USBHID_CDCACM_SET_LINE_CODING 0x20 +#define USBHID_CDCACM_GET_LINE_CODING 0x21 +#define USBHID_CDCACM_SET_COMM_FEATURE 0x02 +#define USBHID_CDCACM_SET_CONTROL_LINE_STATE 0x22 +#define USBHID_CDCACM_CONTROL_LINE_DTR (0x01) +#define USBHID_CDCACM_CONTROL_LINE_RTS (0x02) + +#define USBHID_CDCACM_MANAGEMENT_EPSIZE 0x10 +#define USBHID_CDCACM_RX_EPSIZE 0x40 +#define USBHID_CDCACM_TX_EPSIZE 0x40 +/* + * Descriptors, etc. + */ + + + +#define USBHID_CDCACM_CTRL_ENDP 0 + +typedef struct +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bFirstInterface; + uint8_t bInterfaceCount; + uint8_t bFunctionClass; + uint8_t bFunctionSubClass; + uint8_t bFunctionProtocol; + uint8_t iFunction; +} IADescriptor; + +#define CDC_FUNCTIONAL_DESCRIPTOR_SIZE(DataSize) (3 + DataSize) +#define CDC_FUNCTIONAL_DESCRIPTOR(DataSize) \ + struct { \ + uint8 bLength; \ + uint8 bDescriptorType; \ + uint8 SubType; \ + uint8 Data[DataSize]; \ + } __packed + +#define USB_DEVICE_CLASS_CDC 0x02 +#define USB_DEVICE_SUBCLASS_CDC 0x00 +#define USB_INTERFACE_CLASS_CDC 0x02 +#define USB_INTERFACE_SUBCLASS_CDC_ACM 0x02 +#define USB_INTERFACE_CLASS_DIC 0x0A + +/* + * CDC ACM interface + */ + +void composite_cdcacm_putc(char ch); +uint32 composite_cdcacm_tx(const uint8* buf, uint32 len); +uint32 composite_cdcacm_rx(uint8* buf, uint32 len); +uint32 composite_cdcacm_peek(uint8* buf, uint32 len); +uint32 composite_cdcacm_peek_ex(uint8* buf, uint32 offset, uint32 len); + +uint32 composite_cdcacm_data_available(void); /* in RX buffer */ +uint16 composite_cdcacm_get_pending(void); +uint8 usb_is_transmitting(void); + +uint8 composite_cdcacm_get_dtr(void); +uint8 composite_cdcacm_get_rts(void); + +typedef struct composite_cdcacm_line_coding { + uint32 dwDTERate; /* Baud rate */ + +#define USBHID_CDCACM_STOP_BITS_1 0 +#define USBHID_CDCACM_STOP_BITS_1_5 1 +#define USBHID_CDCACM_STOP_BITS_2 2 + uint8 bCharFormat; /* Stop bits */ + +#define USBHID_CDCACM_PARITY_NONE 0 +#define USBHID_CDCACM_PARITY_ODD 1 +#define USBHID_CDCACM_PARITY_EVEN 2 +#define USBHID_CDCACM_PARITY_MARK 3 +#define USBHID_CDCACM_PARITY_SPACE 4 + uint8 bParityType; /* Parity type */ + + uint8 bDataBits; /* Data bits: 5, 6, 7, 8, or 16 */ +} __packed composite_cdcacm_line_coding; + +/* Retrieve a copy of the current line coding structure. */ +void composite_cdcacm_get_line_coding(composite_cdcacm_line_coding*); + +/* Line coding conveniences. */ +int composite_cdcacm_get_baud(void); /* dwDTERate */ +int composite_cdcacm_get_stop_bits(void); /* bCharFormat */ +int composite_cdcacm_get_parity(void); /* bParityType */ +int composite_cdcacm_get_n_data_bits(void); /* bDataBits */ + +/* + * Hack: hooks for bootloader reset signalling + */ + +#define USBHID_CDCACM_HOOK_RX 0x1 +#define USBHID_CDCACM_HOOK_IFACE_SETUP 0x2 + +void composite_cdcacm_set_hooks(unsigned hook_flags, void (*hook)(unsigned, void*)); + +static inline __always_inline void composite_cdcacm_remove_hooks(unsigned hook_flags) { + composite_cdcacm_set_hooks(hook_flags, 0); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/STM32F1/libraries/USBComposite/usb_setup.cpp b/STM32F1/libraries/USBComposite/usb_setup.cpp new file mode 100644 index 0000000..2136bf0 --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_setup.cpp @@ -0,0 +1,61 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. +*****************************************************************************/ + +/** + * @file wirish/stm32f1/boards_setup.cpp + * @author Marti Bolivar + * @brief STM32F1 chip setup. + * + * This file controls how init() behaves on the STM32F1. Be very + * careful when changing anything here. Many of these values depend + * upon each other. + */ + +#include "boards_private.h" +#include "USBHID.h" +#include +#include + +#include +#include + +namespace wirish { + namespace priv { + + void board_setup_usb(void) { + //Serial = CompositeSerial; +#ifdef GENERIC_BOOTLOADER + //Reset the USB interface on generic boards - developed by Victor PV + gpio_set_mode(PIN_MAP[PA12].gpio_device, PIN_MAP[PA12].gpio_bit, GPIO_OUTPUT_PP); + gpio_write_bit(PIN_MAP[PA12].gpio_device, PIN_MAP[PA12].gpio_bit,0); + + for(volatile unsigned int i=0;i<512;i++);// Only small delay seems to be needed, and USB pins will get configured in Serial.begin + gpio_set_mode(PIN_MAP[PA12].gpio_device, PIN_MAP[PA12].gpio_bit, GPIO_INPUT_FLOATING); +#endif + } + + } +} diff --git a/STM32F1/libraries/USBComposite/usb_x360.c b/STM32F1/libraries/USBComposite/usb_x360.c new file mode 100644 index 0000000..9c5bfd7 --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_x360.c @@ -0,0 +1,486 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * FIXME: this works on the STM32F1 USB peripherals, and probably no + * place else. Nonportable bits really need to be factored out, and + * the result made cleaner. + */ + +#include "usb_generic.h" +#include "usb_x360.h" + +#include + +#include +#include +#include + +/* Private headers */ +#include "usb_lib_globals.h" +#include "usb_reg_map.h" + +/* usb_lib headers */ +#include "usb_type.h" +#include "usb_core.h" +#include "usb_def.h" + +typedef enum _HID_REQUESTS +{ + + GET_REPORT = 1, + GET_IDLE, + GET_PROTOCOL, + + SET_REPORT = 9, + SET_IDLE, + SET_PROTOCOL + +} HID_REQUESTS; + +#define USB_ENDPOINT_IN(addr) ((addr) | 0x80) +#define HID_ENDPOINT_INT 1 +#define USB_ENDPOINT_TYPE_INTERRUPT 0x03 + +#define HID_DESCRIPTOR_TYPE 0x21 + +#define REPORT_DESCRIPTOR 0x22 + + +typedef struct +{ + uint8_t len; // 9 + uint8_t dtype; // 0x21 + uint8_t versionL; // 0x101 + uint8_t versionH; // 0x101 + uint8_t country; + uint8_t numDesc; + uint8_t desctype; // 0x22 report + uint8_t descLenL; + uint8_t descLenH; +} HIDDescriptor; + +#define X360_INTERFACE_OFFSET 0 +#define X360_INTERFACE_NUMBER (X360_INTERFACE_OFFSET+usbX360Part.startInterface) +#define X360_ENDPOINT_TX 0 +#define X360_ENDPOINT_RX 1 +#define USB_X360_RX_ADDR x360Endpoints[X360_ENDPOINT_RX].pmaAddress +#define USB_X360_TX_ADDR x360Endpoints[X360_ENDPOINT_TX].pmaAddress +#define USB_X360_RX_ENDP x360Endpoints[X360_ENDPOINT_RX].address +#define USB_X360_TX_ENDP x360Endpoints[X360_ENDPOINT_TX].address + +u16 GetEPTxAddr(u8 bEpNum); + +static uint32 ProtocolValue; + +static void x360DataTxCb(void); +static void x360DataRxCb(void); +static void (*x360_rumble_callback)(uint8 left, uint8 right); +static void (*x360_led_callback)(uint8 pattern); + +static void x360Reset(void); +static RESULT x360DataSetup(uint8 request); +static RESULT x360NoDataSetup(uint8 request); +static uint8 *HID_GetProtocolValue(uint16 Length); + +/* + * Descriptors + */ + +#if 0 +const uint8_t hid_report_descriptor[] = { + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x05, // USAGE (Game Pad) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x3a, // USAGE (Counted Buffer) + 0xa1, 0x02, // COLLECTION (Logical) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x3f, // USAGE (Reserved) + 0x09, 0x3b, // USAGE (Byte Count) + 0x81, 0x01, // INPUT (Cnst,Ary,Abs) + 0x75, 0x01, // REPORT_SIZE (1) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x45, 0x01, // PHYSICAL_MAXIMUM (1) + 0x95, 0x04, // REPORT_COUNT (4) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x0c, // USAGE_MINIMUM (Button 12) + 0x29, 0x0f, // USAGE_MAXIMUM (Button 15) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x75, 0x01, // REPORT_SIZE (1) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x45, 0x01, // PHYSICAL_MAXIMUM (1) + 0x95, 0x04, // REPORT_COUNT (4) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x09, 0x09, // USAGE (Button 9) + 0x09, 0x0a, // USAGE (Button 10) + 0x09, 0x07, // USAGE (Button 7) + 0x09, 0x08, // USAGE (Button 8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x75, 0x01, // REPORT_SIZE (1) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x45, 0x01, // PHYSICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x09, 0x05, // USAGE (Button 5) + 0x09, 0x06, // USAGE (Button 6) + 0x09, 0x0b, // USAGE (Button 11) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x01, // INPUT (Cnst,Ary,Abs) + 0x75, 0x01, // REPORT_SIZE (1) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x45, 0x01, // PHYSICAL_MAXIMUM (1) + 0x95, 0x04, // REPORT_COUNT (4) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x04, // USAGE_MAXIMUM (Button 4) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x46, 0xff, 0x00, // PHYSICAL_MAXIMUM (255) + 0x95, 0x02, // REPORT_COUNT (2) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x32, // USAGE (Z) + 0x09, 0x35, // USAGE (Rz) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x75, 0x10, // REPORT_SIZE (16) + 0x16, 0x00, 0x80, // LOGICAL_MINIMUM (-32768) + 0x26, 0xff, 0x7f, // LOGICAL_MAXIMUM (32767) + 0x36, 0x00, 0x80, // PHYSICAL_MINIMUM (-32768) + 0x46, 0xff, 0x7f, // PHYSICAL_MAXIMUM (32767) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x95, 0x02, // REPORT_COUNT (2) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x95, 0x02, // REPORT_COUNT (2) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x33, // USAGE (Rx) + 0x09, 0x34, // USAGE (Ry) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; +#endif + +typedef struct { +// usb_descriptor_config_header Config_Header; + usb_descriptor_interface HID_Interface; + uint8 unknown_descriptor1[17]; + usb_descriptor_endpoint DataInEndpoint; + usb_descriptor_endpoint DataOutEndpoint; +} __packed usb_descriptor_config; + + +#define MAX_POWER (100 >> 1) +static const usb_descriptor_config X360Descriptor_Config = +{ +#if 0 + .Config_Header = { + .bLength = sizeof(usb_descriptor_config_header), + .bDescriptorType = USB_DESCRIPTOR_TYPE_CONFIGURATION, + .wTotalLength = sizeof(usb_descriptor_config),//0, + .bNumInterfaces = 0x01, + .bConfigurationValue = 0x01, + .iConfiguration = 0x00, + .bmAttributes = (USB_CONFIG_ATTR_BUSPOWERED | + USB_CONFIG_ATTR_SELF_POWERED), + .bMaxPower = MAX_POWER, + }, +#endif + + .HID_Interface = { + .bLength = sizeof(usb_descriptor_interface), + .bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE, + .bInterfaceNumber = X360_INTERFACE_OFFSET, // PATCH + .bAlternateSetting = 0x00, + .bNumEndpoints = 0x02, + .bInterfaceClass = 0xFF, + .bInterfaceSubClass = 0x5D, + .bInterfaceProtocol = 0x01, + .iInterface = 0x00, + }, + + .unknown_descriptor1 = { + 17,33,0,1,1,37,129,20,0,0,0,0,19,2,8,0,0, + }, + + .DataInEndpoint = { + .bLength = sizeof(usb_descriptor_endpoint), + .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT, + .bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_IN | X360_ENDPOINT_TX),//PATCH + .bmAttributes = USB_EP_TYPE_INTERRUPT, + .wMaxPacketSize = 0x20, + .bInterval = 4, + }, + + .DataOutEndpoint = { + .bLength = sizeof(usb_descriptor_endpoint), + .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT, + .bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_OUT | X360_ENDPOINT_RX),//PATCH + .bmAttributes = USB_EP_TYPE_INTERRUPT, + .wMaxPacketSize = 0x20, + .bInterval = 8, + }, +}; + +static USBEndpointInfo x360Endpoints[2] = { + { + .callback = x360DataTxCb, + .bufferSize = 0x20, + .type = USB_EP_EP_TYPE_INTERRUPT, + .tx = 1 + }, + { + .callback = x360DataRxCb, + .bufferSize = 0x20, + .type = USB_EP_EP_TYPE_INTERRUPT, + .tx = 0, + } +}; + +#define OUT_BYTE(s,v) out[(uint8*)&(s.v)-(uint8*)&s] + +static void getX360PartDescriptor(uint8* out) { + memcpy(out, &X360Descriptor_Config, sizeof(X360Descriptor_Config)); + // patch to reflect where the part goes in the descriptor + OUT_BYTE(X360Descriptor_Config, HID_Interface.bInterfaceNumber) += usbX360Part.startInterface; + OUT_BYTE(X360Descriptor_Config, DataOutEndpoint.bEndpointAddress) += usbX360Part.startEndpoint; + OUT_BYTE(X360Descriptor_Config, DataInEndpoint.bEndpointAddress) += usbX360Part.startEndpoint; +} + +USBCompositePart usbX360Part = { + .numInterfaces = 1, + .numEndpoints = sizeof(x360Endpoints)/sizeof(*x360Endpoints), + .descriptorSize = sizeof(X360Descriptor_Config), + .getPartDescriptor = getX360PartDescriptor, + .usbInit = NULL, + .usbReset = x360Reset, + .usbDataSetup = x360DataSetup, + .usbNoDataSetup = x360NoDataSetup, + .endpoints = x360Endpoints +}; + + +/* + * Etc. + */ + +/* I/O state */ + +/* Received data */ +static volatile uint8 hidBufferRx[USB_X360_RX_EPSIZE]; + + +/* 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; + + +/* + * HID interface + */ + +void x360_set_rumble_callback(void (*callback)(uint8 left, uint8 right)) { + x360_rumble_callback = callback; +} + +void x360_set_led_callback(void (*callback)(uint8 pattern)) { + x360_led_callback = callback; +} + +/*void x360_disable(void) { + x360_set_rumble_callback(NULL); + x360_set_led_callback(NULL); + usb_generic_disable(); +}*/ + +void x360_putc(char ch) { + while (!x360_tx((uint8*)&ch, 1)) + ; +} + + +/* This function is non-blocking. + * + * It copies data from a usercode buffer into the USB peripheral TX + * buffer, and returns the number of bytes copied. */ +uint32 x360_tx(const uint8* buf, uint32 len) { + /* Last transmission hasn't finished, so abort. */ + if (x360_is_transmitting()) { + return 0; + } + + /* We can only put USB_X360_TX_EPSIZE bytes in the buffer. */ + if (len > USB_X360_TX_EPSIZE) { + len = USB_X360_TX_EPSIZE; + } + + /* Queue bytes for sending. */ + if (len) { + usb_copy_to_pma(buf, len, GetEPTxAddr(USB_X360_TX_ENDP));//USB_X360_TX_ADDR); + } + // 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_X360_TX_ENDP, len); + n_unsent_bytes = len; + transmitting = 1; + usb_set_ep_tx_stat(USB_X360_TX_ENDP, USB_EP_STAT_TX_VALID); + + return len; +} + +uint8 x360_is_transmitting(void) { + return transmitting; +} + +uint16 x360_get_pending(void) { + return n_unsent_bytes; +} + +static void x360DataRxCb(void) +{ + uint32 ep_rx_size = usb_get_ep_rx_count(USB_X360_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_X360_RX_ADDR); + uint16 tmp = 0; + uint8 val; + uint32 i; + for (i = 0; i < ep_rx_size; i++) { + if (i&1) { + val = tmp>>8; + } else { + tmp = *src++; + val = tmp&0xFF; + } + hidBufferRx[i] = val; + } + + if (ep_rx_size == 3) { + if (x360_led_callback != NULL && hidBufferRx[0] == 1 && hidBufferRx[1] == 3) + x360_led_callback(hidBufferRx[2]); + } + else if (ep_rx_size == 8) { + if (x360_rumble_callback != NULL && hidBufferRx[0] == 0 && hidBufferRx[1] == 8) + x360_rumble_callback(hidBufferRx[3],hidBufferRx[4]); + } + usb_set_ep_rx_stat(USB_X360_RX_ENDP, USB_EP_STAT_RX_VALID); +} + +/* + * Callbacks + */ + +static void x360DataTxCb(void) { + n_unsent_bytes = 0; + transmitting = 0; +} + +static RESULT x360DataSetup(uint8 request) { + uint8* (*CopyRoutine)(uint16) = 0; + +#if 0 + if (request == GET_DESCRIPTOR + && pInformation->USBwIndex0 == X360_INTERFACE_NUMBER && + && (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT)) + && (pInformation->USBwIndex0 == 0)){ + if (pInformation->USBwValue1 == REPORT_DESCRIPTOR){ + CopyRoutine = HID_GetReportDescriptor; + } else + if (pInformation->USBwValue1 == HID_DESCRIPTOR_TYPE){ + CopyRoutine = HID_GetHIDDescriptor; + } + + } /* End of GET_DESCRIPTOR */ + /*** GET_PROTOCOL ***/ + else +#endif + if(pInformation->USBwIndex0 == X360_INTERFACE_NUMBER && + (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) + && request == GET_PROTOCOL){ + CopyRoutine = HID_GetProtocolValue; + } + + if (CopyRoutine == NULL){ + return USB_UNSUPPORT; + } + + pInformation->Ctrl_Info.CopyData = CopyRoutine; + pInformation->Ctrl_Info.Usb_wOffset = 0; + (*CopyRoutine)(0); + return USB_SUCCESS; +} + +static RESULT x360NoDataSetup(uint8 request) { + if ((Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) + && (request == SET_PROTOCOL)){ + uint8 wValue0 = pInformation->USBwValue0; + ProtocolValue = wValue0; + return USB_SUCCESS; + }else{ + return USB_UNSUPPORT; + } +} + +static uint8* HID_GetProtocolValue(uint16 Length){ + if (Length == 0){ + pInformation->Ctrl_Info.Usb_wLength = 1; + return NULL; + } else { + return (uint8 *)(&ProtocolValue); + } +} + +static void x360Reset(void) { + /* Reset the RX/TX state */ + n_unsent_bytes = 0; + transmitting = 0; +} \ No newline at end of file diff --git a/STM32F1/libraries/USBComposite/usb_x360.h b/STM32F1/libraries/USBComposite/usb_x360.h new file mode 100644 index 0000000..7d2d3e1 --- /dev/null +++ b/STM32F1/libraries/USBComposite/usb_x360.h @@ -0,0 +1,75 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +#ifndef _USB_X360_H +#define _USB_X360_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* + * Descriptors, etc. + */ + +//extern const uint8_t hid_report_descriptor[]; + +/* + * Endpoint configuration + */ + +#define USB_X360_TX_EPSIZE 0x20 +#define USB_X360_RX_EPSIZE 0x20 + +/* + * HID interface + */ + +extern USBCompositePart usbX360Part; +void x360_enable(); +void x360_disable(); + +void x360_putc(char ch); +uint32 x360_tx(const uint8* buf, uint32 len); +uint32 x360_rx(uint8* buf, uint32 len); +uint32 x360_hid_peek(uint8* buf, uint32 len); +uint32 x360_data_available(void); /* in RX buffer */ +uint16 x360_get_pending(void); +uint8 x360_is_transmitting(void); +void x360_set_rx_callback(void (*callback)(const uint8* buffer, uint32 size)); +void x360_set_rumble_callback(void (*callback)(uint8 left, uint8 right)); +void x360_set_led_callback(void (*callback)(uint8 pattern)); + +#ifdef __cplusplus +} +#endif + +#endif From 0197d63dc0dcefe48874af853bd82cf7b2ce1199 Mon Sep 17 00:00:00 2001 From: victorpv Date: Thu, 12 Apr 2018 22:30:37 -0500 Subject: [PATCH 316/351] Multiple updates to SDIO library Changes __io for __IO Increase the time for some delays Adds compatibility with SdSdioEX class while using DMA Implement a retry mechanism (needs further testing) Implement command ACMD42 to disconnect the sd internal pullup in D3 in 4bit mode --- STM32F1/cores/maple/sdio.cpp | 51 +- STM32F1/libraries/SDIO/SdioF1.cpp | 735 ++++++++++++++---- STM32F1/libraries/SDIO/SdioF1.h | 4 +- .../system/libmaple/include/libmaple/sdio.h | 26 +- 4 files changed, 646 insertions(+), 170 deletions(-) diff --git a/STM32F1/cores/maple/sdio.cpp b/STM32F1/cores/maple/sdio.cpp index 8bd9491..23dfa4e 100644 --- a/STM32F1/cores/maple/sdio.cpp +++ b/STM32F1/cores/maple/sdio.cpp @@ -32,8 +32,8 @@ sdio_dev * SDIO = SDIO_BASE; -#define DELAY_LONG 10 -#define DELAY_SHORT 1 +#define DELAY_LONG 20 +#define DELAY_SHORT 2 uint8_t dly = DELAY_LONG; // microseconds delay after accessing registers @@ -43,9 +43,13 @@ uint8_t dly = DELAY_LONG; // microseconds delay after accessing registers void sdio_gpios_init(void) { gpio_set_mode(PIN_MAP[BOARD_SDIO_D0].gpio_device, PIN_MAP[BOARD_SDIO_D0].gpio_bit, GPIO_AF_OUTPUT_PP); - gpio_set_mode(PIN_MAP[BOARD_SDIO_D1].gpio_device, PIN_MAP[BOARD_SDIO_D1].gpio_bit, GPIO_AF_OUTPUT_PP); +/* gpio_set_mode(PIN_MAP[BOARD_SDIO_D1].gpio_device, PIN_MAP[BOARD_SDIO_D1].gpio_bit, GPIO_AF_OUTPUT_PP); gpio_set_mode(PIN_MAP[BOARD_SDIO_D2].gpio_device, PIN_MAP[BOARD_SDIO_D2].gpio_bit, GPIO_AF_OUTPUT_PP); gpio_set_mode(PIN_MAP[BOARD_SDIO_D3].gpio_device, PIN_MAP[BOARD_SDIO_D3].gpio_bit, GPIO_AF_OUTPUT_PP); +*/ + gpio_set_mode(PIN_MAP[BOARD_SDIO_D1].gpio_device, PIN_MAP[BOARD_SDIO_D1].gpio_bit, GPIO_INPUT_PU); + gpio_set_mode(PIN_MAP[BOARD_SDIO_D2].gpio_device, PIN_MAP[BOARD_SDIO_D2].gpio_bit, GPIO_INPUT_PU); + gpio_set_mode(PIN_MAP[BOARD_SDIO_D3].gpio_device, PIN_MAP[BOARD_SDIO_D3].gpio_bit, GPIO_INPUT_PU); gpio_set_mode(PIN_MAP[BOARD_SDIO_CLK].gpio_device, PIN_MAP[BOARD_SDIO_CLK].gpio_bit, GPIO_AF_OUTPUT_PP); gpio_set_mode(PIN_MAP[BOARD_SDIO_CMD].gpio_device, PIN_MAP[BOARD_SDIO_CMD].gpio_bit, GPIO_AF_OUTPUT_PP); /* @@ -63,12 +67,12 @@ void sdio_gpios_init(void) void sdio_gpios_deinit(void) { - gpio_set_mode(PIN_MAP[BOARD_SDIO_D0].gpio_device, PIN_MAP[BOARD_SDIO_D0].gpio_bit, GPIO_INPUT_FLOATING); - gpio_set_mode(PIN_MAP[BOARD_SDIO_D1].gpio_device, PIN_MAP[BOARD_SDIO_D1].gpio_bit, GPIO_INPUT_FLOATING); - gpio_set_mode(PIN_MAP[BOARD_SDIO_D2].gpio_device, PIN_MAP[BOARD_SDIO_D2].gpio_bit, GPIO_INPUT_FLOATING); - gpio_set_mode(PIN_MAP[BOARD_SDIO_D3].gpio_device, PIN_MAP[BOARD_SDIO_D3].gpio_bit, GPIO_INPUT_FLOATING); - gpio_set_mode(PIN_MAP[BOARD_SDIO_CLK].gpio_device, PIN_MAP[BOARD_SDIO_CLK].gpio_bit, GPIO_INPUT_FLOATING); - gpio_set_mode(PIN_MAP[BOARD_SDIO_CMD].gpio_device, PIN_MAP[BOARD_SDIO_CMD].gpio_bit, GPIO_INPUT_FLOATING); + gpio_set_mode(PIN_MAP[BOARD_SDIO_D0].gpio_device, PIN_MAP[BOARD_SDIO_D0].gpio_bit, GPIO_INPUT_PU); + gpio_set_mode(PIN_MAP[BOARD_SDIO_D1].gpio_device, PIN_MAP[BOARD_SDIO_D1].gpio_bit, GPIO_INPUT_PU); + gpio_set_mode(PIN_MAP[BOARD_SDIO_D2].gpio_device, PIN_MAP[BOARD_SDIO_D2].gpio_bit, GPIO_INPUT_PU); + gpio_set_mode(PIN_MAP[BOARD_SDIO_D3].gpio_device, PIN_MAP[BOARD_SDIO_D3].gpio_bit, GPIO_INPUT_PU); + gpio_set_mode(PIN_MAP[BOARD_SDIO_CLK].gpio_device, PIN_MAP[BOARD_SDIO_CLK].gpio_bit, GPIO_INPUT_PU); + gpio_set_mode(PIN_MAP[BOARD_SDIO_CMD].gpio_device, PIN_MAP[BOARD_SDIO_CMD].gpio_bit, GPIO_INPUT_PU); /* * Todo just remove it, not needed for F1. @@ -110,19 +114,35 @@ void sdio_power_off(void) void sdio_set_clock(uint32_t clk) { - if (clk>24000000UL) clk = 24000000UL; // limit the SDIO master clock to 24MHz + /* + * limit the SDIO master clock to 8/3 of PCLK2.See RM 22.3 + * Also limited to no more than 48Mhz + */ + clk = min(clk,(SDIOCLK/3)*8); + clk = min(clk,36000000); if (clk<1000000) dly = DELAY_LONG; else dly = DELAY_SHORT; + /* + * round up divider, so we don't run the card over the speed supported. + + */ + uint32 div = SDIOCLK/clk + (SDIOCLK % clk != 0) - 2; + + sdio_disable(); - SDIO->CLKCR = (SDIO->CLKCR & (~(SDIO_CLKCR_CLKDIV|SDIO_CLKCR_BYPASS))) | SDIO_CLKCR_CLKEN | (((SDIOCLK/clk)-2)&SDIO_CLKCR_CLKDIV); + //Serial.println(div,DEC); + SDIO->CLKCR = (SDIO->CLKCR & (~(SDIO_CLKCR_CLKDIV|SDIO_CLKCR_BYPASS))) | SDIO_CLKCR_PWRSAV | SDIO_CLKCR_HWFC_EN | SDIO_CLKCR_CLKEN | (div & SDIO_CLKCR_CLKDIV); delay_us(dly); } void sdio_set_dbus_width(uint16_t bus_w) { SDIO->CLKCR = (SDIO->CLKCR & (~SDIO_CLKCR_WIDBUS)) | bus_w; + gpio_set_mode(PIN_MAP[BOARD_SDIO_D1].gpio_device, PIN_MAP[BOARD_SDIO_D1].gpio_bit, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PIN_MAP[BOARD_SDIO_D2].gpio_device, PIN_MAP[BOARD_SDIO_D2].gpio_bit, GPIO_AF_OUTPUT_PP); + gpio_set_mode(PIN_MAP[BOARD_SDIO_D3].gpio_device, PIN_MAP[BOARD_SDIO_D3].gpio_bit, GPIO_AF_OUTPUT_PP); delay_us(dly); } @@ -149,9 +169,10 @@ void sdio_disable(void) */ void sdio_begin(void) { - sdio_gpios_init(); + sdio_init(); sdio_power_on(); + sdio_gpios_init(); // Set initial SCK rate. sdio_set_clock(400000); delay_us(200); // generate 80 pulses at 400kHz @@ -162,11 +183,11 @@ void sdio_begin(void) */ void sdio_end(void) { - sdio_disable(); - while ( sdio_cmd_xfer_ongoing() ); + while ( sdio_cmd_xfer_ongoing() ); + sdio_disable(); + sdio_gpios_deinit(); sdio_power_off(); rcc_clk_disable(RCC_SDIO); - sdio_gpios_deinit(); } /** diff --git a/STM32F1/libraries/SDIO/SdioF1.cpp b/STM32F1/libraries/SDIO/SdioF1.cpp index 8957b37..e8a15f9 100644 --- a/STM32F1/libraries/SDIO/SdioF1.cpp +++ b/STM32F1/libraries/SDIO/SdioF1.cpp @@ -30,7 +30,7 @@ //============================================================================== //#define SDHC_PROCTL_DTW_4BIT 0x01 #define CMD8_RETRIES 10 -#define BUSY_TIMEOUT_MILLIS 1500 +#define BUSY_TIMEOUT_MILLIS 1000 //============================================================================== #define CMD_RESP_NONE SDIO_CMD_WAIT_NO_RESP #define CMD_RESP_R1 SDIO_CMD_WAIT_SHORT_RESP // normal response @@ -61,6 +61,12 @@ #define CMD38_XFERTYP (uint16_t)( CMD38 | CMD_RESP_R1b ) #define ACMD41_XFERTYP (uint16_t)( ACMD41 | CMD_RESP_R3 ) +/* + * ACMD42 to enable disable CD/D3 pull up. Needed for 4bit mode. + */ +const uint8_t ACMD42 = 0X2A; +#define ACMD42_XFERTYP (uint16_t)( ACMD41 | CMD_RESP_R1 ) + #define CMD55_XFERTYP (uint16_t)( CMD55 | CMD_RESP_R1 ) //============================================================================= @@ -69,20 +75,33 @@ static void initSDHC(void); static bool isBusyCMD13(void); static bool isBusyTransferComplete(void); +static bool isBusyTransferCRC(void); //static bool isBusyCommandComplete(); //static bool isBusyCommandInhibit(); static bool readReg16(uint32_t xfertyp, void* data); //static void setSdclk(uint32_t kHzMax); static bool yieldTimeout(bool (*fcn)(void)); +static bool yieldDmaStatus(void); static bool waitDmaStatus(void); static bool waitTimeout(bool (*fcn)(void)); //----------------------------------------------------------------------------- +static const uint32_t IDLE_STATE = 0; +static const uint32_t READ_STATE = 1; +static const uint32_t WRITE_STATE = 2; +volatile uint32_t m_curLba; +volatile uint32_t m_limitLba; +volatile uint8_t m_curState; +volatile uint64_t m_totalReadLbas = 0; +volatile uint64_t m_readErrors = 0; +volatile uint64_t m_writeErrors = 0; +volatile uint64_t m_totalWriteLbas = 0; + #define TRX_RD 0 #define TRX_WR 1 static uint8_t m_dir = TRX_RD; static bool (*m_busyFcn)() = 0; static bool m_initDone = false; -static uint32_t m_lba; // for raw non-DMA read(write)Start, read(write)Data, read(write)Stop +//static uint32_t m_lba; // for raw non-DMA read(write)Start, read(write)Data, read(write)Stop static uint32_t m_cnt; // for raw non-DMA read(write)Start, read(write)Data, read(write)Stop static bool m_version2; static bool m_highCapacity; @@ -96,28 +115,29 @@ static uint32_t m_ocr; static cid_t m_cid; static csd_t m_csd; static uint32_t t = 0; + +uint32_t aligned[128]; // temporary buffer for misaligned buffers //============================================================================= -/* - * Todo Remove this or change it, but rather remove since this can be checked with debugger. - */ + #if USE_DEBUG_MODE #define DBG_PRINT() { \ Serial.write('_'); Serial.print(__FUNCTION__); Serial.write('_'); Serial.print(__LINE__); Serial.print(": "); \ - Serial.print("DMA->LISR: "); Serial.print(SDIO_DMA_DEV->regs->LISR, HEX); \ + Serial.print("DMA->ISR: 0x"); Serial.print(SDIO_DMA_DEV->regs->ISR, HEX); \ /*Serial.print("DMA->HISR: "); Serial.println(SDIO_DMA_DEV->regs->HISR, HEX);*/ \ - Serial.print(", DMA->CR: "); Serial.print(SDIO_DMA_DEV->regs->STREAM[SDIO_DMA_CHANNEL].CR, HEX); \ - Serial.print(", DMA->NDTR: "); Serial.print(SDIO_DMA_DEV->regs->STREAM[SDIO_DMA_CHANNEL].NDTR, HEX); \ - /**/Serial.print(", DMA->PAR: "); Serial.print(SDIO_DMA_DEV->regs->STREAM[SDIO_DMA_CHANNEL].PAR, HEX); \ - /**/Serial.print(", DMA->M0AR: "); Serial.print(SDIO_DMA_DEV->regs->STREAM[SDIO_DMA_CHANNEL].M0AR, HEX); \ - Serial.print(", DMA->FCR: "); Serial.print(SDIO_DMA_DEV->regs->STREAM[SDIO_DMA_CHANNEL].FCR, HEX); \ + Serial.print(", DMA->CCR: 0x"); Serial.print(SDIO_DMA_DEV->regs->CCR4, HEX); \ + Serial.print(", DMA->CNDTR: "); Serial.print(SDIO_DMA_DEV->regs->CNDTR4,DEC); \ + /**/Serial.print(", DMA->CPAR: 0x"); Serial.print(SDIO_DMA_DEV->regs->CPAR4, HEX); \ + /**/Serial.print(", DMA->CMAR: 0x"); Serial.print(SDIO_DMA_DEV->regs->CMAR4, HEX); \ + Serial.print(", DMA->IFCR: 0x"); Serial.print(SDIO_DMA_DEV->regs->IFCR, HEX); \ \ /*Serial.print(" SDIO->POWER: "); Serial.println(SDIO->POWER, HEX);*/ \ - Serial.print(", SDIO->CLKCR: "); Serial.print(SDIO->CLKCR, HEX); \ - Serial.print(", SDIO->DTIMER: "); Serial.print(SDIO->DTIMER, HEX); \ - Serial.print(", SDIO->DCTRL: "); Serial.print(SDIO->DCTRL, HEX); \ + Serial.print(", SDIO->CLKCR: 0x"); Serial.print(SDIO->CLKCR, HEX); \ + Serial.print(", SDIO->DTIMER: 0x"); Serial.print(SDIO->DTIMER, HEX); \ + Serial.print(", SDIO->DCTRL: 0x"); Serial.print(SDIO->DCTRL, HEX); \ /**/Serial.print(", SDIO->DLEN: "); Serial.print(SDIO->DLEN); \ Serial.print(", SDIO->DCOUNT: "); Serial.print(SDIO->DCOUNT); \ - Serial.print(", SDIO->STA: "); Serial.println(SDIO->STA, HEX); \ + Serial.print(", SDIO->STA: 0x"); Serial.println(SDIO->STA, HEX); \ + Serial.print(", SDIO->FIFOCNT: "); Serial.println(SDIO->FIFOCNT); \ /*delay(1);*/ \ } #define DBG_PIN PD0 @@ -131,7 +151,7 @@ static void _panic(const char *message, uint32_t code) { Serial.print(message); Serial.println(code, HEX); //Block the execution with blinky leds - while (1); + while (1) {delay (1);}; /* pinMode(BOARD_LED_PIN, OUTPUT); //pinMode(BOARD_LED2_PIN, OUTPUT); @@ -171,13 +191,14 @@ void yield(void) } val = dma_get_isr_bits(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); - if ( val & DMA_ISR_FEIF ) { +/* if ( val & DMA_ISR_FEIF ) { val ^= DMA_ISR_FEIF; dma_clear_isr_bits(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); } +*/ if ( val ) { if (val & DMA_ISR_TEIF) Serial.print(" TEIF"); - if (val & DMA_ISR_DMEIF) Serial.print(" DMEIF"); + //if (val & DMA_ISR_DMEIF) Serial.print(" DMEIF"); //if (val & DMA_ISR_FEIF) Serial.print(" FEIF"); _panic(" - DMA: Data Transmission Error ", val); } @@ -208,7 +229,7 @@ static bool cardCommand(uint16_t xfertyp, uint32_t arg) #if USE_DEBUG_MODE==2 Serial.print("cardCommand: "); Serial.print(xfertyp&SDIO_CMD_CMDINDEX); Serial.print(", arg: "); Serial.print(arg, HEX); #endif - uint8_t resp = sdio_cmd_send(xfertyp, arg); // returns non-zero if fails, zero if OK + uint8_t resp = sdio_cmd_send(xfertyp, arg); // returns non-zero if OK, zero if it fails #if USE_DEBUG_MODE==2 Serial.print(", resp: "); Serial.print(resp, HEX); Serial.print(", SDIO->STA: "); Serial.print(SDIO->STA, HEX); Serial.print(", cmd_resp: "); Serial.print(SDIO->RESP[0], HEX); @@ -264,19 +285,38 @@ static bool isBusyCMD13(void) { } return !(SDIO->RESP[0] & CARD_STATUS_READY_FOR_DATA); } -/*---------------------------------------------------------------------------*/ + +/* + * Returns False if DMA transfer disabled. + * True otherwise + */ +static bool inline isEnabledDMA(void) +{ + return dma_is_enabled(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); +} + +/* + * Returns False if DMA transfer is completed or in error. + * True otherwise + */ static bool isBusyDMA(void) { + if (!isEnabledDMA()) return false; uint8_t isr = dma_get_isr_bits(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); - isr &= DMA_ISR_TCIF | DMA_ISR_TEIF; + isr &= DMA_ISR_TCIF | DMA_ISR_TEIF; //if (isr&DMA_ISR_TCIF) dma_disable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); return !(isr); // ignore transfer error flag } + /*---------------------------------------------------------------------------*/ +/* + * Returns true while the transfer has not completed + * False when it has completed. + */ static bool isBusyTransferComplete(void) { uint32_t mask = SDIO->STA &(SDIO_STA_DATAEND | SDIO_STA_TRX_ERROR_FLAGS); -#if USE_DEBUG_MODE +//#if USE_DEBUG_MODE if ( mask & SDIO_STA_TRX_ERROR_FLAGS ) { Serial.print("XFER ERROR: SDIO->STA: "); Serial.print(SDIO->STA, HEX); if (mask & SDIO_STA_STBITERR) Serial.print(" STBITERR"); @@ -286,13 +326,43 @@ static bool isBusyTransferComplete(void) if (mask & SDIO_STA_DCRCFAIL) Serial.print(" DCRCFAIL"); Serial.println(); } -#endif +//#endif if (mask) { dma_disable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); return false; } return true; } + + +/* + * New function, to follow Reference Manual sequence. + * Returns true if still not confirmed DBCKEND: Data block sent/received (CRC check passed) + * False when it has completed the transfer with CRC check. + */ +static bool isBusyTransferCRC(void) +{ + uint32_t mask = SDIO->STA &(SDIO_STA_DBCKEND | SDIO_STA_TRX_ERROR_FLAGS); +#if USE_DEBUG_MODE + if ( mask & SDIO_STA_TRX_ERROR_FLAGS ) { + Serial.print("XFER ERROR: SDIO->STA: "); Serial.print(SDIO->STA, HEX); + if (mask & SDIO_STA_STBITERR) Serial.print(" STBITERR"); + if (mask & SDIO_STA_RXOVERR) Serial.print(" RXOVERR"); + if (mask & SDIO_STA_TXUNDERR) Serial.print(" TXUNDERR"); + if (mask & SDIO_STA_DTIMEOUT) Serial.print(" DTIMEOUT"); + if (mask & SDIO_STA_DCRCFAIL) Serial.print(" DCRCFAIL"); + Serial.println(); + } +#endif + if (mask) { + //dma_disable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); + //Serial.print("SDIO->STA SDIO_STA_DBCKEND"); Serial.println(SDIO->STA && SDIO_STA_DBCKEND, HEX); + return false; + } + return true; +} + + /*---------------------------------------------------------------------------*/ static void trxStart(uint8_t* buf, uint32_t n, uint8_t dir) { @@ -305,62 +375,86 @@ static void trxStart(uint8_t* buf, uint32_t n, uint8_t dir) /*---------------------------------------------------------------------------*/ static bool trxStop() { - if (!cardCommand(CMD12_XFERTYP, 0)) { - return sdError(SD_CARD_ERROR_CMD12); - } - if ( t ) { - Serial.print(", in "); Serial.println(millis()-t); - t = 0; - } - return true; + if (!cardCommand(CMD12_XFERTYP, 0)) { + return sdError(SD_CARD_ERROR_CMD12); + } + /* + * Added this to wait to complete on sync. + */ + if (yieldTimeout(isBusyCMD13)) { + return sdError(SD_CARD_ERROR_CMD13); + } + if ( t ) { + Serial.print(", in "); Serial.println(millis()-t); + t = 0; + } + return true; } /*---------------------------------------------------------------------------*/ -static bool dmaTrxStart(uint8_t* buf, uint32_t n, uint8_t dir) +static bool dmaTrxStart(uint32_t n, uint8_t dir) { - m_dir = dir; - if ((3 & (uint32_t)buf) || n == 0) { // check alignment - _panic("- transferStart: unaligned buffer address ", (uint32_t)buf); - return sdError(SD_CARD_ERROR_DMA); - } - if (dir==TRX_RD && yieldTimeout(isBusyCMD13)) { - return sdError(SD_CARD_ERROR_CMD13); - } - uint32_t flags = (SDIO_BLOCKSIZE_512 | SDIO_DCTRL_DMAEN | SDIO_DCTRL_DTEN); + uint32_t flags = (SDIO_BLOCKSIZE_512 | SDIO_DCTRL_DMAEN | SDIO_DCTRL_DTEN); if (dir==TRX_RD) flags |= SDIO_DIR_RX; // setup SDIO to transfer n blocks of 512 bytes sdio_setup_transfer(0x00FFFFFF, n, flags); - // setup SDIO_DMA_DEV stream 3 channel 4 - /* - * Moved to begin. - */ - //dma_init(SDIO_DMA_DEV); - /* - * Todo. Check this, channel must be disabled to change DMA priority, and seems like channel is not completing transfers - */ - //dma_set_priority(SDIO_DMA_DEV, SDIO_DMA_CHANNEL, DMA_PRIORITY_VERY_HIGH); - flags = (DMA_MINC_MODE); - // not extra flag if read - if (dir!=TRX_RD) flags |= DMA_FROM_MEM;// write - dma_setup_transfer(SDIO_DMA_DEV, SDIO_DMA_CHANNEL, &SDIO->FIFO, DMA_SIZE_32BITS, buf, DMA_SIZE_32BITS, flags); - dma_set_num_transfers(SDIO_DMA_DEV, SDIO_DMA_CHANNEL, n>>2); // F1 DMA controller counts each word as 1 data item. - //dma_set_fifo_flags(SDIO_DMA_DEV, SDIO_DMA_CHANNEL, (DMA_FCR_DMDIS | DMA_FCR_FTH_FULL)); // disable direct mode | threshold FULL - dma_clear_isr_bits(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); - dma_enable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); + return true; } + +/* + * This one replaces dmaTrxStart, and will just prepare the DMA part, then a new + * one will enable the DMA reception as per the RM. + */ +static bool dmaTrxPrepare(uint8_t* buf, uint32_t n, uint8_t dir) +{ + uint32_t flags; + m_dir = dir; + if ((3 & (uint32_t)buf) || n == 0) { // check alignment + _panic("- transferStart: unaligned buffer address ", (uint32_t)buf); + return sdError(SD_CARD_ERROR_DMA); + } + /* + * No point to wait here again if we always wait before calling this. + if (dir==TRX_RD && yieldTimeout(isBusyCMD13)) { + return sdError(SD_CARD_ERROR_CMD13); + } + */ + + /* + * Following RM 22.3.2. Setup DMA first, SDIO peripheral next + * + */ + flags = (DMA_MINC_MODE); + // not extra flag if read + if (dir!=TRX_RD) flags |= DMA_FROM_MEM;// write + dma_setup_transfer(SDIO_DMA_DEV, SDIO_DMA_CHANNEL, &SDIO->FIFO, DMA_SIZE_32BITS, buf, DMA_SIZE_32BITS, flags); + dma_set_num_transfers(SDIO_DMA_DEV, SDIO_DMA_CHANNEL, n>>2); // F1 DMA controller counts each word as 1 data item. + //dma_set_fifo_flags(SDIO_DMA_DEV, SDIO_DMA_CHANNEL, (DMA_FCR_DMDIS | DMA_FCR_FTH_FULL)); // disable direct mode | threshold FULL + dma_clear_isr_bits(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); + dma_enable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); + + return true; +} + + /*---------------------------------------------------------------------------*/ static bool dmaTrxEnd(bool multi_block) { - if ( !waitDmaStatus() ) { + if(m_curState != READ_STATE){ + if ( yieldTimeout(isBusyTransferComplete) ) { + DBG_PRINT(); + if (m_dir==TRX_RD) + return sdError(SD_CARD_ERROR_READ_CRC); + else + return sdError(SD_CARD_ERROR_WRITE); + } + } + + if ( !yieldDmaStatus() ) { DBG_PRINT(); return sdError(SD_CARD_ERROR_DMA); } - if ( waitTimeout(isBusyTransferComplete) ) { - if (m_dir==TRX_RD) - return sdError(SD_CARD_ERROR_READ_TIMEOUT); - else - return sdError(SD_CARD_ERROR_WRITE_TIMEOUT); - } + if (multi_block) { return trxStop(); } else { @@ -375,6 +469,10 @@ static bool dmaTrxEnd(bool multi_block) // Read 16 byte CID or CSD register. static bool readReg16(uint32_t xfertyp, void* data) { + // It's not safe to call this function if a multiblock read/write is going on. + if (m_curState != IDLE_STATE) { + return false; + } uint8_t* d = reinterpret_cast(data); if (!cardCommand(xfertyp, m_rca)) { return false; // Caller will set errorCode. @@ -389,21 +487,38 @@ static bool readReg16(uint32_t xfertyp, void* data) /*---------------------------------------------------------------------------*/ // Return true if timeout occurs. static bool yieldTimeout(bool (*fcn)()) { + m_busyFcn = fcn; uint32_t m = millis(); while (fcn()) { if ((millis() - m) > BUSY_TIMEOUT_MILLIS) { + m_busyFcn = 0; return true; } yield(); } + m_busyFcn = 0; return false; // Caller will set errorCode. } /*---------------------------------------------------------------------------*/ +static bool yieldDmaStatus(void) +{ + if (yieldTimeout(isBusyDMA)) { + dma_disable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); + return false; // Caller will set errorCode. + } + // Did not time out. Disable it and return true. + dma_disable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); + return true; +} +/*---------------------------------------------------------------------------*/ static bool waitDmaStatus(void) { - if (yieldTimeout(isBusyDMA)) { + if (waitTimeout(isBusyDMA)) { + dma_disable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); return false; // Caller will set errorCode. } + // Did not time out. Disable it and return true + dma_disable(SDIO_DMA_DEV, SDIO_DMA_CHANNEL); return true; } /*---------------------------------------------------------------------------*/ @@ -419,10 +534,12 @@ static bool waitTimeout(bool (*fcn)(void)) { return false; // Caller will set errorCode. } -uint32_t aligned[128]; // temporary buffer for misaligned buffers + //============================================================================= bool SdioCard::begin(void) { + + uint32_t arg; m_initDone = false; m_errorCode = SD_CARD_ERROR_NONE; m_highCapacity = false; @@ -447,6 +564,7 @@ delay(100); if (!cardCommand(CMD0_XFERTYP, 0)) { return sdError(SD_CARD_ERROR_CMD0); } + delay(50); //small pause after reset command // Try several times for case of reset delay. for (uint32_t i = 0; i < CMD8_RETRIES; i++) { if (cardCommand(CMD8_XFERTYP, 0X1AA)) { @@ -457,7 +575,7 @@ delay(100); break; } } - uint32_t arg = m_version2 ? 0X40300000 : 0x00300000; + arg = m_version2 ? 0X50300000 : 0x00300000; uint32_t m = millis(); do { if (!cardAcmd(0, ACMD41_XFERTYP, arg) || @@ -478,6 +596,7 @@ delay(100); return sdError(SD_CARD_ERROR_CMD3); } m_rca = SDIO->RESP[0] & 0xFFFF0000; + if (!readReg16(CMD9_XFERTYP, &m_csd)) { return sdError(SD_CARD_ERROR_CMD9); } @@ -487,14 +606,21 @@ delay(100); if (!cardCommand(CMD7_XFERTYP, m_rca)) { return sdError(SD_CARD_ERROR_CMD7); } + + arg = 0x00; //bit 0, Connect[1]/Disconnect[0] the 50 KOhm pull-up resistor on CD/DAT3 + if (!cardAcmd(m_rca, ACMD42_XFERTYP, arg)) { + _panic("*** ACMD42 to disconnect D3 pullup failed! ***", 0); + } + // Set card to bus width four. - /* if (!cardAcmd(m_rca, ACMD6_XFERTYP, 2)) { return sdError(SD_CARD_ERROR_ACMD6); } - sdio_set_dbus_width(SDIO_CLKCR_WIDBUS_4BIT); - */ + // Set SDHC to bus width four. + sdio_set_dbus_width(SDIO_CLKCR_WIDBUS_4BIT); + +/* // Determine if High Speed mode is supported and set frequency. uint8_t status[64]; // see "Physical Layer Simplified Specification Version 6.00", chapter 4.3.10, Table 4-13. @@ -502,15 +628,17 @@ delay(100); // Function Selection of Function Group 1: bits 379:376, which is low nibble of byte [16] if (cardCMD6(0X00FFFFFF, status) && (2 & status[13]) && cardCMD6(0X80FFFFF1, status) && (status[16] & 0XF) == 1) { - //Serial.println("\n*** 50MHz clock supported ***"); + Serial.println("\n*** 50MHz clock supported ***"); + m_sdClkKhz = 24000; // set clock to 24MHz } else { //_panic("*** Only 25MHz clock supported! ***", 0); + m_sdClkKhz = 8000; // set clock to 24MHz } + */ + // delay seems to be needed for cards that take some time to adjust */ + delay(1); - /* - * Todo Raise clock to 24Mhz once transfers work - */ - m_sdClkKhz = 24000; // set clock to 24MHz + m_sdClkKhz = 18000; // set clock to 24MHz sdio_set_clock(m_sdClkKhz*1000); m_initDone = true; @@ -573,52 +701,157 @@ uint32_t SdioCard::kHzSdClk() { bool SdioCard::readBlock(uint32_t lba, uint8_t* buf) { #if USE_DEBUG_MODE - Serial.print("readBlock: "); Serial.println(lba); //Serial.print(", buf: "); Serial.println((uint32_t)buf, HEX); + Serial.print("readBlock: "); Serial.println(lba); //Serial.print(", buf: "); Serial.println((uint32_t)buf, HEX); #endif - // prepare SDIO and DMA for data read transfer - dmaTrxStart((uint32_t)buf & 3 ? (uint8_t*)aligned : buf, 512, TRX_RD); - // send command to start data transfer - if ( !cardCommand(CMD17_XFERTYP, (m_highCapacity ? lba : 512*lba)) ) { - return sdError(SD_CARD_ERROR_CMD17); - } - if ( dmaTrxEnd(0)) { - if ( (uint32_t)buf & 3 ) { - //memcpy(buf, aligned, 512); - register uint8_t * dst = buf; - register uint8_t * src = (uint8_t *)aligned; - register uint16_t i = 64; - while ( i-- ) { // do 8 byte copies, is much faster than single byte copy - *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; - *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; - } - } - return true; - } - return false; + volatile bool _state = false; + uint16_t retries = 3; + while ( retries-- ){ + /*if (yieldTimeout(isBusyCMD13)) { // wait for previous transmission end + return sdError(SD_CARD_ERROR_CMD13); + } + */ + + if (m_curState != READ_STATE || m_curLba != lba) { +#if USE_DEBUG_MODE + Serial.print("New lba, syncing :"); + Serial.println(lba); +#endif + _state = syncBlocks(); + DBG_PRINT(); + if (!_state) { + return false; + } + m_limitLba = (lba + 1024); //arbitrary limit, tested with 32KB before and worked fine. + // prepare DMA for data read transfer + _state = dmaTrxPrepare((uint32_t)buf & 3 ? (uint8_t*)aligned : buf, 512, TRX_RD); + DBG_PRINT(); + + // prepare SDIO data read transfer 0x8000 = 64*512 + _state = dmaTrxStart(512, TRX_RD); + DBG_PRINT(); + + // send command to start data transfer + _state = cardCommand(CMD18_XFERTYP, (m_highCapacity ? lba : 512*lba)); + DBG_PRINT(); + if ( !_state ) { + return sdError(SD_CARD_ERROR_CMD18); + } + + m_curLba = lba; + m_curState = READ_STATE; + } + else { + // prepare DMA for data read transfer + _state = dmaTrxPrepare((uint32_t)buf & 3 ? (uint8_t*)aligned : buf, 512, TRX_RD); + + // prepare SDIO data read transfer + _state = dmaTrxStart(512, TRX_RD); + } + + + _state = dmaTrxEnd(0); + + if ( _state ) { + if ( (uint32_t)buf & 3 ) { + //memcpy(buf, aligned, 512); + register uint8_t * dst = buf; + register uint8_t * src = (uint8_t *)aligned; + register uint16_t i = 64; + while ( i-- ) { // do 8 byte copies, is much faster than single byte copy + *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; + *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; + } + } + m_totalReadLbas++; + m_curLba++; + if (m_curLba >= m_limitLba) { + syncBlocks(); + } + sdError(SD_CARD_ERROR_NONE); + return true; + } + syncBlocks(); + m_readErrors++; + + } + DBG_PRINT() + syncBlocks(); + m_readErrors++; + return false; } /*---------------------------------------------------------------------------*/ bool SdioCard::readBlocks(uint32_t lba, uint8_t* buf, size_t n) { #if USE_DEBUG_MODE - Serial.print("readBlocks: "); Serial.print(lba); - //Serial.print(", buf: "); Serial.print((uint32_t)buf, HEX); - Serial.print(", "); Serial.println(n); + Serial.print("readBlocks: "); Serial.print(lba); + //Serial.print(", buf: "); Serial.print((uint32_t)buf, HEX); + Serial.print(", "); Serial.println(n); #endif - if ((uint32_t)buf & 3) { - for (size_t i = 0; i < n; i++, lba++, buf += 512) { - if (!readBlock(lba, buf)) { - return false; // readBlock will set errorCode. - } - } - return true; - } - // prepare SDIO and DMA for data read transfer - dmaTrxStart(buf, 512*n, TRX_RD); - // send command to start data transfer - if ( !cardCommand(CMD18_XFERTYP, (m_highCapacity ? lba : 512*lba)) ) { - return sdError(SD_CARD_ERROR_CMD18); - } - return dmaTrxEnd(1); + volatile bool _state = false; + uint16_t retries = 3; + while ( retries-- ){ + + if ((uint32_t)buf & 3) { + for (size_t i = 0; i < n; i++, lba++, buf += 512) { + if (!readBlock(lba, buf)) { + return false; // readBlock will set errorCode. + } + } + return true; + } + + if (m_curState != READ_STATE || m_curLba != lba) { + #if USE_DEBUG_MODE + Serial.print("New lba, syncing :"); + Serial.println(lba); + #endif + _state = syncBlocks(); + DBG_PRINT(); + if (!_state) { + return false; + } + m_limitLba = (lba + 1024); //arbitrary limit + // prepare DMA for data read transfer + _state = dmaTrxPrepare(buf, 512*n, TRX_RD); + + // prepare SDIO for data read transfer + _state = dmaTrxStart(512*n, TRX_RD); + + // send command to start data transfer + _state = cardCommand(CMD18_XFERTYP, (m_highCapacity ? lba : 512*lba)); + if ( !_state ) { + return sdError(SD_CARD_ERROR_CMD18); + } + m_curLba = lba; + m_curState = READ_STATE; + } + + else { + // prepare DMA for data read transfer + _state = dmaTrxPrepare(buf, 512*n, TRX_RD); + + // prepare SDIO data read transfer + _state = dmaTrxStart(512*n, TRX_RD); + } + + _state = dmaTrxEnd(0); + + if (_state){ + m_totalReadLbas += n; + m_curLba += n; + if (m_curLba >= m_limitLba) { + syncBlocks(); + } + sdError(SD_CARD_ERROR_NONE); + return true; + } + syncBlocks(); + m_readErrors++; + } + DBG_PRINT() + syncBlocks(); + m_readErrors++; + return false; } //----------------------------------------------------------------------------- bool SdioCard::readCID(void* cid) { @@ -631,6 +864,7 @@ bool SdioCard::readCSD(void* csd) { return true; } /*---------------------------------------------------------------------------*/ +/* replacing this one with DMA support. bool SdioCard::readData(uint8_t *dst) { //Serial.print("readData: "); Serial.print(m_lba); Serial.print(", m_cnt: "); Serial.println(m_cnt); @@ -675,6 +909,51 @@ bool SdioCard::readData(uint8_t *dst) m_cnt--; return !(SDIO->STA&SDIO_STA_TRX_ERROR_FLAGS); } +*/ +bool SdioCard::readData(uint8_t *buf) +{ + + volatile bool _state = false; + uint16_t retries = 3; + while ( retries-- ){ + // prepare DMA for data read transfer + _state = dmaTrxPrepare((uint32_t)buf & 3 ? (uint8_t*)aligned : buf, 512, TRX_RD); + + // prepare SDIO data read transfer + _state = dmaTrxStart(512, TRX_RD); + _state = dmaTrxEnd(0); + + if ( _state ) { + if ( (uint32_t)buf & 3 ) { + //memcpy(buf, aligned, 512); + register uint8_t * dst = buf; + register uint8_t * src = (uint8_t *)aligned; + register uint16_t i = 64; + while ( i-- ) { // do 8 byte copies, is much faster than single byte copy + *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; + *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; + } + } + m_curLba += 1; + return true; + } + else { + readStop(); + //_state = dmaTrxPrepare((uint32_t)buf & 3 ? (uint8_t*)aligned : buf, 512, TRX_RD); + //_state = dmaTrxStart(512, TRX_RD); + _state = cardCommand(CMD18_XFERTYP, (m_highCapacity ? m_curLba : 512*m_curLba)); + if ( !_state ) { + return sdError(SD_CARD_ERROR_CMD18); + } + } + } + DBG_PRINT() + m_readErrors++; + return sdError(SD_CARD_ERROR_READ); + +} + + //----------------------------------------------------------------------------- bool SdioCard::readOCR(uint32_t* ocr) { *ocr = m_ocr; @@ -683,29 +962,80 @@ bool SdioCard::readOCR(uint32_t* ocr) { //----------------------------------------------------------------------------- bool SdioCard::readStart(uint32_t lba) { + m_curLba = lba; + /* m_lba = lba; m_cnt = 1024; return true; + */ + volatile bool _state = false; + if (yieldTimeout(isBusyCMD13)) { // wait for previous transmission end + return sdError(SD_CARD_ERROR_CMD13); + } + _state = cardCommand(CMD18_XFERTYP, (m_highCapacity ? lba : 512*lba)); + DBG_PRINT(); + if ( !_state ) { + return sdError(SD_CARD_ERROR_CMD18); + } + m_curState = READ_STATE; + return true; } /*---------------------------------------------------------------------------*/ // SDHC will do Auto CMD12 after count blocks. bool SdioCard::readStart(uint32_t lba, uint32_t count) { //Serial.print("readStart: "); Serial.print(lba); Serial.print(", cnt: "); Serial.println(count); + m_curLba = lba; +/* m_lba = lba; m_cnt = count; return true; +*/ + volatile bool _state = false; + if (yieldTimeout(isBusyCMD13)) { // wait for previous transmission end + return sdError(SD_CARD_ERROR_CMD13); + } + _state = cardCommand(CMD18_XFERTYP, (m_highCapacity ? lba : 512*lba)); + DBG_PRINT(); + if ( !_state ) { + return sdError(SD_CARD_ERROR_CMD18); + } + m_curState = READ_STATE; + return true; } /*---------------------------------------------------------------------------*/ bool SdioCard::readStop() { - //Serial.println("readStop."); - m_lba = 0; - m_cnt = 0; + if ( isEnabledDMA()){ + yieldDmaStatus(); + } + sdio_setup_transfer(0x00FFFFFF, 0, 0); + // Empty SDIO FIFO + while ( SDIO->STA & SDIO_STA_RXDAVL) { + volatile uint32 _unused = SDIO->FIFO; + } + //Serial.println("readStop."); + //m_lba = 0; + if (!trxStop()) { + return false; + } return true; } //----------------------------------------------------------------------------- -bool SdioCard::syncBlocks() { +inline bool SdioCard::syncBlocks() { +/* if ( isEnabledDMA()){ + waitDmaStatus(); + } +*/ + if (m_curState == READ_STATE) { + m_curState = IDLE_STATE; + if (!readStop()) { + return false; + } + } else if (m_curState == WRITE_STATE) { + m_curState = IDLE_STATE; + return writeStop(); + } return true; } //----------------------------------------------------------------------------- @@ -733,17 +1063,48 @@ bool SdioCard::writeBlock(uint32_t lba, const uint8_t* buf) *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; } } - if (yieldTimeout(isBusyCMD13)) { // wait for previous transmission end - return sdError(SD_CARD_ERROR_CMD13); - } - // send command to start data transfer - if ( !cardCommand(CMD24_XFERTYP, (m_highCapacity ? lba : 512*lba)) ) { - return sdError(SD_CARD_ERROR_CMD24); - } - // prepare SDIO and DMA for data transfer - dmaTrxStart(ptr, 512, TRX_WR); // 1 block, write transfer - return dmaTrxEnd(0); + + + if (m_curState != WRITE_STATE || m_curLba != lba) { + if (!syncBlocks()) { + return false; + } + + m_limitLba = (lba + 1024); //arbitrary limit + + // prepare DMA for data transfer + dmaTrxPrepare(ptr, 512, TRX_WR); // 1 block, write transfer + + // send command to start data transfer + if ( !cardCommand(CMD25_XFERTYP, (m_highCapacity ? lba : 512*lba)) ) { + return sdError(SD_CARD_ERROR_CMD25); + } + m_curLba = lba; + m_curState = WRITE_STATE; + + } + else { + if (yieldTimeout(isBusyCMD13)) { // wait for previous transmission end + return sdError(SD_CARD_ERROR_CMD13); + } + // prepare DMA for data transfer + dmaTrxPrepare(ptr, 512, TRX_WR); // 1 block, write transfer + } + + // prepare SDIO for data transfer + dmaTrxStart(512, TRX_WR); // 1 block, write transfer + + if (!dmaTrxEnd(0)){ + m_curState = IDLE_STATE; + m_writeErrors++; + return false; + } + m_curLba++; + if (m_curLba >= m_limitLba) { + syncBlocks(); + } + return true; } /*---------------------------------------------------------------------------*/ bool SdioCard::writeBlocks(uint32_t lba, const uint8_t* buf, size_t n) @@ -770,16 +1131,46 @@ bool SdioCard::writeBlocks(uint32_t lba, const uint8_t* buf, size_t n) return sdError(SD_CARD_ERROR_ACMD23); } #endif - // send command to start data transfer - if ( !cardCommand(CMD25_XFERTYP, (m_highCapacity ? lba : 512*lba)) ) { - return sdError(SD_CARD_ERROR_CMD25); - } - // prepare SDIO and DMA for data transfer - dmaTrxStart((uint8_t *)buf, 512*n, TRX_WR); // n blocks, write transfer - return dmaTrxEnd(1); + if (m_curState != WRITE_STATE || m_curLba != lba) { + if (!syncBlocks()) { + return false; + } + + m_limitLba = (lba + 1024); //arbitrary limit, 512KB + // prepare DMA for data transfer + dmaTrxPrepare((uint8_t *)buf, 512*n, TRX_WR); // n blocks, write transfer + + // send command to start data transfer + if ( !cardCommand(CMD25_XFERTYP, (m_highCapacity ? lba : 512*lba)) ) { + return sdError(SD_CARD_ERROR_CMD25); + } + m_curLba = lba; + m_curState = WRITE_STATE; + + } + else { + // prepare DMA for data transfer + dmaTrxPrepare((uint8_t *)buf, 512*n, TRX_WR); // n blocks, write transfer + } + + // prepare SDIO for data transfer + dmaTrxStart(512*n, TRX_WR); // n blocks, write transfer + + if (!dmaTrxEnd(0)){ + m_writeErrors++; + m_curState = IDLE_STATE; + return false; + } + m_curLba += n; + if (m_curLba >= m_limitLba) { + syncBlocks(); + } + return true; + } /*---------------------------------------------------------------------------*/ +/* bool SdioCard::writeData(const uint8_t* src) { //Serial.print("writeData: "); Serial.print(m_lba); Serial.print(", cnt: "); Serial.println(m_cnt); @@ -826,27 +1217,91 @@ bool SdioCard::writeData(const uint8_t* src) } return !(SDIO->STA&SDIO_STA_TRX_ERROR_FLAGS); } +*/ +bool SdioCard::writeData(const uint8_t* src) +{ + uint8_t * ptr = (uint8_t *)src; + if (3 & (uint32_t)ptr) { + Serial.print("writeBlock: "); Serial.print(m_curLba); + Serial.print(", buf: "); Serial.print((uint32_t)ptr, HEX); + //memcpy(aligned, buf, 512); + register uint8_t * src = (uint8_t *)ptr; + ptr = (uint8_t *)aligned; + register uint8_t * dst = ptr; + register uint16_t i = 64; + while ( i-- ) { // do 8 byte copies, is much faster than single byte copy + *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; + *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; + } + } + + if (yieldTimeout(isBusyCMD13)) { // wait for previous transmission end + return sdError(SD_CARD_ERROR_CMD13); + } + // prepare DMA for data transfer + dmaTrxPrepare(ptr, 512, TRX_WR); // 1 block, write transfer + DBG_PRINT(); + + // prepare SDIO for data transfer + dmaTrxStart(512, TRX_WR); // 1 block, write transfer + DBG_PRINT(); + + if (!dmaTrxEnd(0)){ + m_writeErrors++; + return false; + } + return true; +} //----------------------------------------------------------------------------- bool SdioCard::writeStart(uint32_t lba) { + /* m_lba = lba; m_cnt = 1024; return true; + */ + DBG_PRINT(); + m_curLba = lba; + if (yieldTimeout(isBusyCMD13)) { + return sdError(SD_CARD_ERROR_CMD13); + } + if ( !cardCommand(CMD25_XFERTYP, (m_highCapacity ? lba : 512*lba)) ) { + return sdError(SD_CARD_ERROR_CMD25); + } + m_curState = WRITE_STATE; + return true; } /*---------------------------------------------------------------------------*/ // SDHC will do Auto CMD12 after count blocks. bool SdioCard::writeStart(uint32_t lba, uint32_t count) { //Serial.print("writeStart: "); Serial.print(lba); Serial.print(", cnt: "); Serial.println(count); + /* m_lba = lba; m_cnt = count; return true; + */ + m_curLba = lba; + if (yieldTimeout(isBusyCMD13)) { + return sdError(SD_CARD_ERROR_CMD13); + } + if ( !cardCommand(CMD25_XFERTYP, (m_highCapacity ? lba : 512*lba)) ) { + return sdError(SD_CARD_ERROR_CMD25); + } + m_curState = WRITE_STATE; + return true; } /*---------------------------------------------------------------------------*/ bool SdioCard::writeStop() { - //Serial.println("writeStop."); - m_lba = 0; - m_cnt = 0; - return true; + if ( isEnabledDMA()){ + if ( !yieldDmaStatus() ) { + DBG_PRINT(); + return sdError(SD_CARD_ERROR_DMA); + } + } + //m_lba = 0; + m_curState = IDLE_STATE; + return trxStop(); + //Serial.println("writeStop."); } diff --git a/STM32F1/libraries/SDIO/SdioF1.h b/STM32F1/libraries/SDIO/SdioF1.h index c995b1c..efa4774 100644 --- a/STM32F1/libraries/SDIO/SdioF1.h +++ b/STM32F1/libraries/SDIO/SdioF1.h @@ -1,6 +1,6 @@ -#ifndef _SDIOF4_H_ -#define _SDIOF4_H_ +#ifndef _SDIOF1_H_ +#define _SDIOF1_H_ #include diff --git a/STM32F1/system/libmaple/include/libmaple/sdio.h b/STM32F1/system/libmaple/include/libmaple/sdio.h index 3a5a9c3..11ec986 100644 --- a/STM32F1/system/libmaple/include/libmaple/sdio.h +++ b/STM32F1/system/libmaple/include/libmaple/sdio.h @@ -52,19 +52,19 @@ extern "C" { // SDIO register map type typedef struct sdio_reg_map { - __io uint32 POWER; // 0x00 - __io uint32 CLKCR; // 0x04 - __io uint32 ARG; // 0x08 - __io uint32 CMD; // 0x0C - __io uint32 RESPCMD; // 0x10 (0x3F) - __io const uint32 RESP[4]; // 0x14 - contain the card status, which is part of the received response. - __io uint32 DTIMER; // 0x24 - contains the data timeout period, in card bus clock periods. - __io uint32 DLEN; // 0x28 (0x01FF FFFF) - contains the number of data bytes to be transferred - __io uint32 DCTRL; // 0x2C - __io uint32 DCOUNT; // 0x30 (0x01FF FFFF) - __io uint32 STA; // 0x34 - __io uint32 ICR; // 0x38 - __io uint32 MASK; // 0x3C + __IO uint32 POWER; // 0x00 + __IO uint32 CLKCR; // 0x04 + __IO uint32 ARG; // 0x08 + __IO uint32 CMD; // 0x0C + __IO uint32 RESPCMD; // 0x10 (0x3F) + __IO const uint32 RESP[4]; // 0x14 - contain the card status, which is part of the received response. + __IO uint32 DTIMER; // 0x24 - contains the data timeout period, in card bus clock periods. + __IO uint32 DLEN; // 0x28 (0x01FF FFFF) - contains the number of data bytes to be transferred + __IO uint32 DCTRL; // 0x2C + __IO uint32 DCOUNT; // 0x30 (0x01FF FFFF) + __IO uint32 STA; // 0x34 + __IO uint32 ICR; // 0x38 + __IO uint32 MASK; // 0x3C const uint32 RESERVED1[2]; __IO uint32 FIFOCNT; // 0x48 (0x01FF FFFF) const uint32 RESERVED2[13]; From df96076900320869328302aacff8bb79a35a8198 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Fri, 13 Apr 2018 14:10:49 +1000 Subject: [PATCH 317/351] Added missing F103V linker file, included in https://github.com/rogerclarkmelbourne/Arduino_STM32/pull/489 --- .../generic_stm32f103vb/ld/stm32f103veDFU.ld | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 STM32F1/variants/generic_stm32f103vb/ld/stm32f103veDFU.ld diff --git a/STM32F1/variants/generic_stm32f103vb/ld/stm32f103veDFU.ld b/STM32F1/variants/generic_stm32f103vb/ld/stm32f103veDFU.ld new file mode 100644 index 0000000..5782fb9 --- /dev/null +++ b/STM32F1/variants/generic_stm32f103vb/ld/stm32f103veDFU.ld @@ -0,0 +1,30 @@ +/* + * libmaple linker script for "Flash" builds. + * + * A Flash build puts .text (and .rodata) in Flash, and + * .data/.bss/heap (of course) in SRAM, but offsets the sections by + * enough space to store the Maple bootloader, which lives in low + * Flash and uses low memory. + */ + +/* + * This pulls in the appropriate MEMORY declaration from the right + * subdirectory of stm32/mem/ (the environment must call ld with the + * right include directory flags to make this happen). Boards can also + * use this file to use any of libmaple's memory-related hooks (like + * where the heap should live). + */ +MEMORY +{ + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 64K + rom (rx) : ORIGIN = 0x08002000, LENGTH = 504K +} + +/* Provide memory region aliases for common.inc */ +REGION_ALIAS("REGION_TEXT", rom); +REGION_ALIAS("REGION_DATA", ram); +REGION_ALIAS("REGION_BSS", ram); +REGION_ALIAS("REGION_RODATA", rom); + +/* Let common.inc handle the real work. */ +INCLUDE common.inc From 7ef6e71a781270f69b50e0c113b8ed9e1aa8c15a Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Fri, 13 Apr 2018 14:52:55 +1000 Subject: [PATCH 318/351] Add flash wait state optimisation from @tomtor --- STM32F1/system/libmaple/stm32f1/include/series/flash.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/system/libmaple/stm32f1/include/series/flash.h b/STM32F1/system/libmaple/stm32f1/include/series/flash.h index a0bcd82..0ed43c6 100644 --- a/STM32F1/system/libmaple/stm32f1/include/series/flash.h +++ b/STM32F1/system/libmaple/stm32f1/include/series/flash.h @@ -132,7 +132,7 @@ typedef struct flash_reg_map { * Series-specific configuration values. */ -#define FLASH_SAFE_WAIT_STATES FLASH_WAIT_STATE_2 +#define FLASH_SAFE_WAIT_STATES (F_CPU > 48000000 ? FLASH_WAIT_STATE_2 : F_CPU > 24000000 ? FLASH_WAIT_STATE_1 : FLASH_WAIT_STATE_0) /* Flash memory features available via ACR */ enum { From 1f85ecb3b9f940d2e0eabab0f3d9989d4ff98a35 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Fri, 13 Apr 2018 15:03:03 +1000 Subject: [PATCH 319/351] Added PLL Mulplier setting for 16MHz. Note this change does not add 16Mhz menu options to any boards, it simply supports them if they were added --- STM32F1/variants/generic_stm32f103c/wirish/boards_setup.cpp | 2 ++ STM32F1/variants/generic_stm32f103r/wirish/boards_setup.cpp | 2 ++ STM32F1/variants/generic_stm32f103r8/wirish/boards_setup.cpp | 2 ++ STM32F1/variants/generic_stm32f103t/wirish/boards_setup.cpp | 2 ++ STM32F1/variants/generic_stm32f103v/wirish/boards_setup.cpp | 2 ++ STM32F1/variants/generic_stm32f103vb/wirish/boards_setup.cpp | 2 ++ STM32F1/variants/generic_stm32f103z/wirish/boards_setup.cpp | 2 ++ STM32F1/variants/hytiny_stm32f103t/wirish/boards_setup.cpp | 2 ++ STM32F1/variants/maple/wirish/boards_setup.cpp | 2 ++ STM32F1/variants/maple_mini/wirish/boards_setup.cpp | 2 ++ STM32F1/variants/maple_ret6/wirish/boards_setup.cpp | 2 ++ STM32F1/variants/microduino/wirish/boards_setup.cpp | 2 ++ 12 files changed, 24 insertions(+) diff --git a/STM32F1/variants/generic_stm32f103c/wirish/boards_setup.cpp b/STM32F1/variants/generic_stm32f103c/wirish/boards_setup.cpp index 9e8332e..5f595ee 100644 --- a/STM32F1/variants/generic_stm32f103c/wirish/boards_setup.cpp +++ b/STM32F1/variants/generic_stm32f103c/wirish/boards_setup.cpp @@ -54,6 +54,8 @@ #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 #elif F_CPU==48000000 #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 + #elif F_CPU==16000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_2 #endif #endif diff --git a/STM32F1/variants/generic_stm32f103r/wirish/boards_setup.cpp b/STM32F1/variants/generic_stm32f103r/wirish/boards_setup.cpp index 0413015..1632caa 100644 --- a/STM32F1/variants/generic_stm32f103r/wirish/boards_setup.cpp +++ b/STM32F1/variants/generic_stm32f103r/wirish/boards_setup.cpp @@ -54,6 +54,8 @@ #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 #elif F_CPU==48000000 #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 + #elif F_CPU==16000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_2 #endif #endif diff --git a/STM32F1/variants/generic_stm32f103r8/wirish/boards_setup.cpp b/STM32F1/variants/generic_stm32f103r8/wirish/boards_setup.cpp index 8da724d..13d7b89 100644 --- a/STM32F1/variants/generic_stm32f103r8/wirish/boards_setup.cpp +++ b/STM32F1/variants/generic_stm32f103r8/wirish/boards_setup.cpp @@ -54,6 +54,8 @@ #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 #elif F_CPU==48000000 #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 + #elif F_CPU==16000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_2 #endif #endif diff --git a/STM32F1/variants/generic_stm32f103t/wirish/boards_setup.cpp b/STM32F1/variants/generic_stm32f103t/wirish/boards_setup.cpp index 9e8332e..5f595ee 100644 --- a/STM32F1/variants/generic_stm32f103t/wirish/boards_setup.cpp +++ b/STM32F1/variants/generic_stm32f103t/wirish/boards_setup.cpp @@ -54,6 +54,8 @@ #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 #elif F_CPU==48000000 #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 + #elif F_CPU==16000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_2 #endif #endif diff --git a/STM32F1/variants/generic_stm32f103v/wirish/boards_setup.cpp b/STM32F1/variants/generic_stm32f103v/wirish/boards_setup.cpp index dba014b..0b96261 100644 --- a/STM32F1/variants/generic_stm32f103v/wirish/boards_setup.cpp +++ b/STM32F1/variants/generic_stm32f103v/wirish/boards_setup.cpp @@ -54,6 +54,8 @@ #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 #elif F_CPU==48000000 #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 + #elif F_CPU==16000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_2 #endif #endif diff --git a/STM32F1/variants/generic_stm32f103vb/wirish/boards_setup.cpp b/STM32F1/variants/generic_stm32f103vb/wirish/boards_setup.cpp index dba014b..0b96261 100644 --- a/STM32F1/variants/generic_stm32f103vb/wirish/boards_setup.cpp +++ b/STM32F1/variants/generic_stm32f103vb/wirish/boards_setup.cpp @@ -54,6 +54,8 @@ #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 #elif F_CPU==48000000 #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 + #elif F_CPU==16000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_2 #endif #endif diff --git a/STM32F1/variants/generic_stm32f103z/wirish/boards_setup.cpp b/STM32F1/variants/generic_stm32f103z/wirish/boards_setup.cpp index 3d4e4e8..0f6fd0f 100644 --- a/STM32F1/variants/generic_stm32f103z/wirish/boards_setup.cpp +++ b/STM32F1/variants/generic_stm32f103z/wirish/boards_setup.cpp @@ -54,6 +54,8 @@ #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 #elif F_CPU==48000000 #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 + #elif F_CPU==16000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_2 #endif #endif diff --git a/STM32F1/variants/hytiny_stm32f103t/wirish/boards_setup.cpp b/STM32F1/variants/hytiny_stm32f103t/wirish/boards_setup.cpp index f10fcf8..9051989 100644 --- a/STM32F1/variants/hytiny_stm32f103t/wirish/boards_setup.cpp +++ b/STM32F1/variants/hytiny_stm32f103t/wirish/boards_setup.cpp @@ -54,6 +54,8 @@ #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 #elif F_CPU==48000000 #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 + #elif F_CPU==16000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_2 #endif #endif diff --git a/STM32F1/variants/maple/wirish/boards_setup.cpp b/STM32F1/variants/maple/wirish/boards_setup.cpp index c4b55c0..d1170cd 100644 --- a/STM32F1/variants/maple/wirish/boards_setup.cpp +++ b/STM32F1/variants/maple/wirish/boards_setup.cpp @@ -54,6 +54,8 @@ #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 #elif F_CPU==48000000 #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 + #elif F_CPU==16000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_2 #endif #endif diff --git a/STM32F1/variants/maple_mini/wirish/boards_setup.cpp b/STM32F1/variants/maple_mini/wirish/boards_setup.cpp index f10fcf8..9051989 100644 --- a/STM32F1/variants/maple_mini/wirish/boards_setup.cpp +++ b/STM32F1/variants/maple_mini/wirish/boards_setup.cpp @@ -54,6 +54,8 @@ #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 #elif F_CPU==48000000 #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 + #elif F_CPU==16000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_2 #endif #endif diff --git a/STM32F1/variants/maple_ret6/wirish/boards_setup.cpp b/STM32F1/variants/maple_ret6/wirish/boards_setup.cpp index c4b55c0..d1170cd 100644 --- a/STM32F1/variants/maple_ret6/wirish/boards_setup.cpp +++ b/STM32F1/variants/maple_ret6/wirish/boards_setup.cpp @@ -54,6 +54,8 @@ #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 #elif F_CPU==48000000 #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 + #elif F_CPU==16000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_2 #endif #endif diff --git a/STM32F1/variants/microduino/wirish/boards_setup.cpp b/STM32F1/variants/microduino/wirish/boards_setup.cpp index 785753a..1f1ec5e 100644 --- a/STM32F1/variants/microduino/wirish/boards_setup.cpp +++ b/STM32F1/variants/microduino/wirish/boards_setup.cpp @@ -54,6 +54,8 @@ #define BOARD_RCC_PLLMUL RCC_PLLMUL_9 #elif F_CPU==48000000 #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 + #elif F_CPU==16000000 + #define BOARD_RCC_PLLMUL RCC_PLLMUL_2 #endif #endif From 4f691b9eebfcd63fa6f918cc02171e127ac9f246 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Fri, 13 Apr 2018 16:32:56 +1000 Subject: [PATCH 320/351] Add support for boards with 16MHz HSE crystal. Note to use this feature users must add -D XTAL16M to the appropriate build options in boards.txt, as there are too few boards with 16MHz crystals to warrant adding this as a separate menu to each board in boards.txt --- STM32F1/cores/maple/libmaple/rcc_f1.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/STM32F1/cores/maple/libmaple/rcc_f1.c b/STM32F1/cores/maple/libmaple/rcc_f1.c index 04dfb7f..3fc916a 100644 --- a/STM32F1/cores/maple/libmaple/rcc_f1.c +++ b/STM32F1/cores/maple/libmaple/rcc_f1.c @@ -134,6 +134,12 @@ void rcc_configure_pll(rcc_pll_cfg *pll_cfg) { cfgr &= ~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLMUL); cfgr |= pll_cfg->pllsrc | pll_mul; +#ifdef XTAL16M + // 16MHz crystal (HSE) + // in this case we additionally set the Bit 17 (PLLXTPRE=1) => then HSE clock is divided by 2 before PLL entry + cfgr |= RCC_CFGR_PLLXTPRE; +#endif + RCC_BASE->CFGR = cfgr; } From 479cfc1fb4a39cb8398b309805eef93ba33e76fe Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Fri, 13 Apr 2018 16:47:15 +1000 Subject: [PATCH 321/351] Removed unused ErrorStatus enum from usb_type.h as its redundant and the definition of SUCCESS clashed with other definitions --- STM32F1/system/libmaple/usb/usb_lib/usb_type.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/system/libmaple/usb/usb_lib/usb_type.h b/STM32F1/system/libmaple/usb/usb_lib/usb_type.h index 34b3bf5..02bd5ef 100644 --- a/STM32F1/system/libmaple/usb/usb_lib/usb_type.h +++ b/STM32F1/system/libmaple/usb/usb_lib/usb_type.h @@ -62,7 +62,7 @@ typedef enum { RESET = 0, SET = !RESET } FlagStatus, ITStatus; typedef enum { DISABLE = 0, ENABLE = !DISABLE} FunctionalState; -typedef enum { ERROR = 0, SUCCESS = !ERROR} ErrorStatus; +//typedef enum { ERROR = 0, SUCCESS = !ERROR} ErrorStatus; /* Exported macro ------------------------------------------------------------*/ /* Exported functions ------------------------------------------------------- */ From 50ed00effc17ca2c7c4df4c780c2fbe0da29be39 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Fri, 13 Apr 2018 18:26:45 +0200 Subject: [PATCH 322/351] Update timer.h fix compile error --- STM32F1/system/libmaple/include/libmaple/timer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/system/libmaple/include/libmaple/timer.h b/STM32F1/system/libmaple/include/libmaple/timer.h index e9a49e9..87b83e5 100644 --- a/STM32F1/system/libmaple/include/libmaple/timer.h +++ b/STM32F1/system/libmaple/include/libmaple/timer.h @@ -843,7 +843,7 @@ static inline void timer_dma_disable_req(timer_dev *dev, uint8 channel) { */ static inline void timer_enable_irq(timer_dev *dev, uint8 interrupt) { // clear interrupt flag, use different masks for reserved bits - dev->regs->SR = (~BIT(interrupt)) & ( (dev->type==TIMER_ADVANCED) ? 0x1EFF : + (dev->regs).adv->SR = (~BIT(interrupt)) & ( (dev->type==TIMER_ADVANCED) ? 0x1EFF : ( (dev->type==TIMER_GENERAL) ? 0x1E5F : 0x0001) ); *bb_perip(&(dev->regs).adv->DIER, interrupt) = 1; } From d33e50ab0d95bdce5abfabb78ae76091486350b7 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Fri, 13 Apr 2018 23:42:46 +0200 Subject: [PATCH 323/351] Update BluePill-RTClock-test.ino fix weekday, see #498. --- .../examples/BluePill-RTClock-test/BluePill-RTClock-test.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino b/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino index f6b4495..cc78ec5 100644 --- a/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino +++ b/STM32F1/libraries/RTClock/examples/BluePill-RTClock-test/BluePill-RTClock-test.ino @@ -40,7 +40,7 @@ uint8_t AlarmExchange = 0; bool dispflag = true; //----------------------------------------------------------------------------- -const char * weekdays[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; +const char * weekdays[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}; const char * months[] = {"Dummy", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; //----------------------------------------------------------------------------- uint8_t str2month(const char * d) From 84b1c8c1fe3edb8d0bb7ea8c0310c9dad6a44399 Mon Sep 17 00:00:00 2001 From: stevstrong Date: Tue, 17 Apr 2018 08:28:51 +0200 Subject: [PATCH 324/351] F4: update Print.cpp port from #486. --- STM32F4/cores/maple/Print.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/STM32F4/cores/maple/Print.cpp b/STM32F4/cores/maple/Print.cpp index 0a71cf0..2e6e154 100644 --- a/STM32F4/cores/maple/Print.cpp +++ b/STM32F4/cores/maple/Print.cpp @@ -47,12 +47,8 @@ */ size_t Print::write(const char *str) { - size_t n = 0; - while (*str) { - write(*str++); - n++; - } - return n; + if (str == NULL) return 0; + return write((const uint8_t *)str, strlen(str)); } size_t Print::write(const void *buffer, uint32 size) { From b16686a06ac71f3e636a47af04ed930e13af665a Mon Sep 17 00:00:00 2001 From: edogaldo Date: Tue, 17 Apr 2018 11:19:36 +0200 Subject: [PATCH 325/351] Allow IRQ overriding --- STM32F1/cores/maple/libmaple/adc_f1.c | 4 +- STM32F1/cores/maple/libmaple/dma_f1.c | 22 +- STM32F1/cores/maple/libmaple/exc.S | 1 - STM32F1/cores/maple/libmaple/exti.c | 14 +- STM32F1/cores/maple/libmaple/i2c_f1.c | 8 +- .../maple/libmaple/stm32f1/performance/isrs.S | 268 +++++++++--------- STM32F1/cores/maple/libmaple/systick.c | 2 +- STM32F1/cores/maple/libmaple/timer.c | 28 +- STM32F1/cores/maple/libmaple/usart_f1.c | 10 +- .../cores/maple/libmaple/usb/stm32f1/usb.c | 2 +- 10 files changed, 179 insertions(+), 180 deletions(-) diff --git a/STM32F1/cores/maple/libmaple/adc_f1.c b/STM32F1/cores/maple/libmaple/adc_f1.c index 8cb4b4a..a8ea30b 100644 --- a/STM32F1/cores/maple/libmaple/adc_f1.c +++ b/STM32F1/cores/maple/libmaple/adc_f1.c @@ -72,7 +72,7 @@ adc_dev *ADC3 = &adc3; adc irq routine. Added by bubulindo. */ -void __irq_adc() { +__weak void __irq_adc() { //get status uint32 adc_sr = ADC1->regs->SR; //End Of Conversion @@ -107,7 +107,7 @@ void __irq_adc() { added by bubulindo */ #if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) -void __irq_adc3() { +__weak void __irq_adc3() { //get status uint32 adc_sr = ADC3->regs->SR; //End Of Conversion diff --git a/STM32F1/cores/maple/libmaple/dma_f1.c b/STM32F1/cores/maple/libmaple/dma_f1.c index 33dc0ef..fb5b03c 100644 --- a/STM32F1/cores/maple/libmaple/dma_f1.c +++ b/STM32F1/cores/maple/libmaple/dma_f1.c @@ -360,48 +360,48 @@ void dma_setup_transfer(dma_dev *dev, * IRQ handlers */ -void __irq_dma1_channel1(void) { +__weak void __irq_dma1_channel1(void) { dma_irq_handler(DMA1, DMA_CH1); } -void __irq_dma1_channel2(void) { +__weak void __irq_dma1_channel2(void) { dma_irq_handler(DMA1, DMA_CH2); } -void __irq_dma1_channel3(void) { +__weak void __irq_dma1_channel3(void) { dma_irq_handler(DMA1, DMA_CH3); } -void __irq_dma1_channel4(void) { +__weak void __irq_dma1_channel4(void) { dma_irq_handler(DMA1, DMA_CH4); } -void __irq_dma1_channel5(void) { +__weak void __irq_dma1_channel5(void) { dma_irq_handler(DMA1, DMA_CH5); } -void __irq_dma1_channel6(void) { +__weak void __irq_dma1_channel6(void) { dma_irq_handler(DMA1, DMA_CH6); } -void __irq_dma1_channel7(void) { +__weak void __irq_dma1_channel7(void) { dma_irq_handler(DMA1, DMA_CH7); } #if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) -void __irq_dma2_channel1(void) { +__weak void __irq_dma2_channel1(void) { dma_irq_handler(DMA2, DMA_CH1); } -void __irq_dma2_channel2(void) { +__weak void __irq_dma2_channel2(void) { dma_irq_handler(DMA2, DMA_CH2); } -void __irq_dma2_channel3(void) { +__weak void __irq_dma2_channel3(void) { dma_irq_handler(DMA2, DMA_CH3); } -void __irq_dma2_channel4_5(void) { +__weak void __irq_dma2_channel4_5(void) { if ((DMA2_BASE->CCR4 & DMA_CCR_EN) && (DMA2_BASE->ISR & DMA_ISR_GIF4)) { dma_irq_handler(DMA2, DMA_CH4); } diff --git a/STM32F1/cores/maple/libmaple/exc.S b/STM32F1/cores/maple/libmaple/exc.S index 7631e48..24153fc 100644 --- a/STM32F1/cores/maple/libmaple/exc.S +++ b/STM32F1/cores/maple/libmaple/exc.S @@ -41,7 +41,6 @@ # SP--> r0 .text -.globl __exc_hardfault .globl __exc_nmi .globl __exc_hardfault .globl __exc_memmanage diff --git a/STM32F1/cores/maple/libmaple/exti.c b/STM32F1/cores/maple/libmaple/exti.c index c8836a7..982ba06 100644 --- a/STM32F1/cores/maple/libmaple/exti.c +++ b/STM32F1/cores/maple/libmaple/exti.c @@ -212,31 +212,31 @@ void exti_do_select(__IO uint32 *exti_cr, exti_num num, exti_cfg port) { * Interrupt handlers */ -void __irq_exti0(void) { +__weak void __irq_exti0(void) { dispatch_single_exti(EXTI0); } -void __irq_exti1(void) { +__weak void __irq_exti1(void) { dispatch_single_exti(EXTI1); } -void __irq_exti2(void) { +__weak void __irq_exti2(void) { dispatch_single_exti(EXTI2); } -void __irq_exti3(void) { +__weak void __irq_exti3(void) { dispatch_single_exti(EXTI3); } -void __irq_exti4(void) { +__weak void __irq_exti4(void) { dispatch_single_exti(EXTI4); } -void __irq_exti9_5(void) { +__weak void __irq_exti9_5(void) { dispatch_extis(5, 9); } -void __irq_exti15_10(void) { +__weak void __irq_exti15_10(void) { dispatch_extis(10, 15); } diff --git a/STM32F1/cores/maple/libmaple/i2c_f1.c b/STM32F1/cores/maple/libmaple/i2c_f1.c index 8439793..3b1cc36 100644 --- a/STM32F1/cores/maple/libmaple/i2c_f1.c +++ b/STM32F1/cores/maple/libmaple/i2c_f1.c @@ -76,19 +76,19 @@ void i2c_master_release_bus(const i2c_dev *dev) { * IRQ handlers */ -void __irq_i2c1_ev(void) { +__weak void __irq_i2c1_ev(void) { _i2c_irq_handler(I2C1); } -void __irq_i2c2_ev(void) { +__weak void __irq_i2c2_ev(void) { _i2c_irq_handler(I2C2); } -void __irq_i2c1_er(void) { +__weak void __irq_i2c1_er(void) { _i2c_irq_error_handler(I2C1); } -void __irq_i2c2_er(void) { +__weak void __irq_i2c2_er(void) { _i2c_irq_error_handler(I2C2); } diff --git a/STM32F1/cores/maple/libmaple/stm32f1/performance/isrs.S b/STM32F1/cores/maple/libmaple/stm32f1/performance/isrs.S index 8c1a44f..7a9b4aa 100644 --- a/STM32F1/cores/maple/libmaple/stm32f1/performance/isrs.S +++ b/STM32F1/cores/maple/libmaple/stm32f1/performance/isrs.S @@ -76,9 +76,9 @@ __default_handler: .weak __exc_pendsv .globl __exc_pendsv .set __exc_pendsv, __default_handler - .weak __exc_systick - .globl __exc_systick - .set __exc_systick, __default_handler +// .weak __exc_systick // __exc_systick() defined in STM32F1/cores/maple/libmaple/systick.c +// .globl __exc_systick +// .set __exc_systick, __default_handler .weak __irq_wwdg .globl __irq_wwdg .set __irq_wwdg, __default_handler @@ -97,110 +97,110 @@ __default_handler: .weak __irq_rcc .globl __irq_rcc .set __irq_rcc, __default_handler - .weak __irq_exti0 - .globl __irq_exti0 - .set __irq_exti0, __default_handler - .weak __irq_exti1 - .globl __irq_exti1 - .set __irq_exti1, __default_handler - .weak __irq_exti2 - .globl __irq_exti2 - .set __irq_exti2, __default_handler - .weak __irq_exti3 - .globl __irq_exti3 - .set __irq_exti3, __default_handler - .weak __irq_exti4 - .globl __irq_exti4 - .set __irq_exti4, __default_handler - .weak __irq_dma1_channel1 - .globl __irq_dma1_channel1 - .set __irq_dma1_channel1, __default_handler - .weak __irq_dma1_channel2 - .globl __irq_dma1_channel2 - .set __irq_dma1_channel2, __default_handler - .weak __irq_dma1_channel3 - .globl __irq_dma1_channel3 - .set __irq_dma1_channel3, __default_handler - .weak __irq_dma1_channel4 - .globl __irq_dma1_channel4 - .set __irq_dma1_channel4, __default_handler - .weak __irq_dma1_channel5 - .globl __irq_dma1_channel5 - .set __irq_dma1_channel5, __default_handler - .weak __irq_dma1_channel6 - .globl __irq_dma1_channel6 - .set __irq_dma1_channel6, __default_handler - .weak __irq_dma1_channel7 - .globl __irq_dma1_channel7 - .set __irq_dma1_channel7, __default_handler - .weak __irq_adc - .globl __irq_adc - .set __irq_adc, __default_handler +// .weak __irq_exti0 // __irq_exti0() defined in STM32F1/cores/maple/libmaple/exti.c +// .globl __irq_exti0 +// .set __irq_exti0, __default_handler +// .weak __irq_exti1 // __irq_exti1() defined in STM32F1/cores/maple/libmaple/exti.c +// .globl __irq_exti1 +// .set __irq_exti1, __default_handler +// .weak __irq_exti2 // __irq_exti2() defined in STM32F1/cores/maple/libmaple/exti.c +// .globl __irq_exti2 +// .set __irq_exti2, __default_handler +// .weak __irq_exti3 // __irq_exti3() defined in STM32F1/cores/maple/libmaple/exti.c +// .globl __irq_exti3 +// .set __irq_exti3, __default_handler +// .weak __irq_exti4 // __irq_exti4() defined in STM32F1/cores/maple/libmaple/exti.c +// .globl __irq_exti4 +// .set __irq_exti4, __default_handler +// .weak __irq_dma1_channel1 // __irq_dma1_channel1() defined in STM32F1/cores/maple/libmaple/dma_f1.c +// .globl __irq_dma1_channel1 +// .set __irq_dma1_channel1, __default_handler +// .weak __irq_dma1_channel2 // __irq_dma1_channel2() defined in STM32F1/cores/maple/libmaple/dma_f1.c +// .globl __irq_dma1_channel2 +// .set __irq_dma1_channel2, __default_handler +// .weak __irq_dma1_channel3 // __irq_dma1_channel3() defined in STM32F1/cores/maple/libmaple/dma_f1.c +// .globl __irq_dma1_channel3 +// .set __irq_dma1_channel3, __default_handler +// .weak __irq_dma1_channel4 // __irq_dma1_channel4() defined in STM32F1/cores/maple/libmaple/dma_f1.c +// .globl __irq_dma1_channel4 +// .set __irq_dma1_channel4, __default_handler +// .weak __irq_dma1_channel5 // __irq_dma1_channel5() defined in STM32F1/cores/maple/libmaple/dma_f1.c +// .globl __irq_dma1_channel5 +// .set __irq_dma1_channel5, __default_handler +// .weak __irq_dma1_channel6 // __irq_dma1_channel6() defined in STM32F1/cores/maple/libmaple/dma_f1.c +// .globl __irq_dma1_channel6 +// .set __irq_dma1_channel6, __default_handler +// .weak __irq_dma1_channel7 // __irq_dma1_channel7() defined in STM32F1/cores/maple/libmaple/dma_f1.c +// .globl __irq_dma1_channel7 +// .set __irq_dma1_channel7, __default_handler +// .weak __irq_adc // __irq_adc() defined in STM32F1/cores/maple/libmaple/adc_f1.c +// .globl __irq_adc +// .set __irq_adc, __default_handler .weak __irq_usb_hp_can_tx .globl __irq_usb_hp_can_tx .set __irq_usb_hp_can_tx, __default_handler - .weak __irq_usb_lp_can_rx0 - .globl __irq_usb_lp_can_rx0 - .set __irq_usb_lp_can_rx0, __default_handler +// .weak __irq_usb_lp_can_rx0 // __irq_usb_lp_can_rx0() defined in STM32F1/cores/maple/libmaple/usb/stm32f1/usb.c +// .globl __irq_usb_lp_can_rx0 +// .set __irq_usb_lp_can_rx0, __default_handler .weak __irq_can_rx1 .globl __irq_can_rx1 .set __irq_can_rx1, __default_handler .weak __irq_can_sce .globl __irq_can_sce .set __irq_can_sce, __default_handler - .weak __irq_exti9_5 - .globl __irq_exti9_5 - .set __irq_exti9_5, __default_handler - .weak __irq_tim1_brk - .globl __irq_tim1_brk - .set __irq_tim1_brk, __default_handler - .weak __irq_tim1_up - .globl __irq_tim1_up - .set __irq_tim1_up, __default_handler - .weak __irq_tim1_trg_com - .globl __irq_tim1_trg_com - .set __irq_tim1_trg_com, __default_handler - .weak __irq_tim1_cc - .globl __irq_tim1_cc - .set __irq_tim1_cc, __default_handler - - .weakref __irq_tim2, __default_handler - .globl __irq_tim2 - .weakref __irq_tim3, __default_handler - .globl __irq_tim3 - .weakref __irq_tim4, __default_handler - .globl __irq_tim4 - - .weak __irq_i2c1_ev - .globl __irq_i2c1_ev - .set __irq_i2c1_ev, __default_handler - .weak __irq_i2c1_er - .globl __irq_i2c1_er - .set __irq_i2c1_er, __default_handler - .weak __irq_i2c2_ev - .globl __irq_i2c2_ev - .set __irq_i2c2_ev, __default_handler - .weak __irq_i2c2_er - .globl __irq_i2c2_er - .set __irq_i2c2_er, __default_handler +// .weak __irq_exti9_5 // __irq_exti9_5() defined in STM32F1/cores/maple/libmaple/exti.c +// .globl __irq_exti9_5 +// .set __irq_exti9_5, __default_handler +// .weak __irq_tim1_brk // __irq_tim1_brk() defined in STM32F1/cores/maple/libmaple/timer.c +// .globl __irq_tim1_brk +// .set __irq_tim1_brk, __default_handler +// .weak __irq_tim1_up // __irq_tim1_up() defined in STM32F1/cores/maple/libmaple/timer.c +// .globl __irq_tim1_up +// .set __irq_tim1_up, __default_handler +// .weak __irq_tim1_trg_com // __irq_tim1_trg_com() defined in STM32F1/cores/maple/libmaple/timer.c +// .globl __irq_tim1_trg_com +// .set __irq_tim1_trg_com, __default_handler +// .weak __irq_tim1_cc // __irq_tim1_cc() defined in STM32F1/cores/maple/libmaple/timer.c +// .globl __irq_tim1_cc +// .set __irq_tim1_cc, __default_handler +// +// .weakref __irq_tim2, __default_handler // __irq_tim2() defined in STM32F1/cores/maple/libmaple/timer.c +// .globl __irq_tim2 +// .weakref __irq_tim3, __default_handler // __irq_tim3() defined in STM32F1/cores/maple/libmaple/timer.c +// .globl __irq_tim3 +// .weakref __irq_tim4, __default_handler // __irq_tim4() defined in STM32F1/cores/maple/libmaple/timer.c +// .globl __irq_tim4 +// +// .weak __irq_i2c1_ev // __irq_i2c1_ev() defined in STM32F1/cores/maple/libmaple/i2c_f1.c +// .globl __irq_i2c1_ev +// .set __irq_i2c1_ev, __default_handler +// .weak __irq_i2c1_er // __irq_i2c1_er() defined in STM32F1/cores/maple/libmaple/i2c_f1.c +// .globl __irq_i2c1_er +// .set __irq_i2c1_er, __default_handler +// .weak __irq_i2c2_ev // __irq_i2c2_ev() defined in STM32F1/cores/maple/libmaple/i2c_f1.c +// .globl __irq_i2c2_ev +// .set __irq_i2c2_ev, __default_handler +// .weak __irq_i2c2_er // __irq_i2c2_er() defined in STM32F1/cores/maple/libmaple/i2c_f1.c +// .globl __irq_i2c2_er +// .set __irq_i2c2_er, __default_handler .weak __irq_spi1 .globl __irq_spi1 .set __irq_spi1, __default_handler .weak __irq_spi2 .globl __irq_spi2 .set __irq_spi2, __default_handler - .weak __irq_usart1 - .globl __irq_usart1 - .set __irq_usart1, __default_handler - .weak __irq_usart2 - .globl __irq_usart2 - .set __irq_usart2, __default_handler - .weak __irq_usart3 - .globl __irq_usart3 - .set __irq_usart3, __default_handler - .weak __irq_exti15_10 - .globl __irq_exti15_10 - .set __irq_exti15_10, __default_handler +// .weak __irq_usart1 // __irq_usart1() defined in STM32F1/cores/maple/libmaple/usart_f1.c +// .globl __irq_usart1 +// .set __irq_usart1, __default_handler +// .weak __irq_usart2 // __irq_usart2() defined in STM32F1/cores/maple/libmaple/usart_f1.c +// .globl __irq_usart2 +// .set __irq_usart2, __default_handler +// .weak __irq_usart3 // __irq_usart3() defined in STM32F1/cores/maple/libmaple/usart_f1.c +// .globl __irq_usart3 +// .set __irq_usart3, __default_handler +// .weak __irq_exti15_10 // __irq_exti15_10() defined in STM32F1/cores/maple/libmaple/exti.c +// .globl __irq_exti15_10 +// .set __irq_exti15_10, __default_handler .weak __irq_rtcalarm .globl __irq_rtcalarm .set __irq_rtcalarm, __default_handler @@ -208,55 +208,55 @@ __default_handler: .globl __irq_usbwakeup .set __irq_usbwakeup, __default_handler #if defined (STM32_HIGH_DENSITY) - .weak __irq_tim8_brk - .globl __irq_tim8_brk - .set __irq_tim8_brk, __default_handler - .weak __irq_tim8_up - .globl __irq_tim8_up - .set __irq_tim8_up, __default_handler - .weak __irq_tim8_trg_com - .globl __irq_tim8_trg_com - .set __irq_tim8_trg_com, __default_handler - .weak __irq_tim8_cc - .globl __irq_tim8_cc - .set __irq_tim8_cc, __default_handler - .weak __irq_adc3 - .globl __irq_adc3 - .set __irq_adc3, __default_handler +// .weak __irq_tim8_brk // __irq_tim8_brk() defined in STM32F1/cores/maple/libmaple/timer.c +// .globl __irq_tim8_brk +// .set __irq_tim8_brk, __default_handler +// .weak __irq_tim8_up // __irq_tim8_up() defined in STM32F1/cores/maple/libmaple/timer.c +// .globl __irq_tim8_up +// .set __irq_tim8_up, __default_handler +// .weak __irq_tim8_trg_com // __irq_tim8_trg_com() defined in STM32F1/cores/maple/libmaple/timer.c +// .globl __irq_tim8_trg_com +// .set __irq_tim8_trg_com, __default_handler +// .weak __irq_tim8_cc // __irq_tim8_cc() defined in STM32F1/cores/maple/libmaple/timer.c +// .globl __irq_tim8_cc +// .set __irq_tim8_cc, __default_handler +// .weak __irq_adc3 // __irq_adc3() defined in STM32F1/cores/maple/libmaple/adc_f1.c +// .globl __irq_adc3 +// .set __irq_adc3, __default_handler .weak __irq_fsmc .globl __irq_fsmc .set __irq_fsmc, __default_handler .weak __irq_sdio .globl __irq_sdio .set __irq_sdio, __default_handler - .weak __irq_tim5 - .globl __irq_tim5 - .set __irq_tim5, __default_handler +// .weak __irq_tim5 // __irq_tim5() defined in STM32F1/cores/maple/libmaple/timer.c +// .globl __irq_tim5 +// .set __irq_tim5, __default_handler .weak __irq_spi3 .globl __irq_spi3 .set __irq_spi3, __default_handler - .weak __irq_uart4 - .globl __irq_uart4 - .set __irq_uart4, __default_handler - .weak __irq_uart5 - .globl __irq_uart5 - .set __irq_uart5, __default_handler - .weak __irq_tim6 - .globl __irq_tim6 - .set __irq_tim6, __default_handler - .weak __irq_tim7 - .globl __irq_tim7 - .set __irq_tim7, __default_handler - .weak __irq_dma2_channel1 - .globl __irq_dma2_channel1 - .set __irq_dma2_channel1, __default_handler - .weak __irq_dma2_channel2 - .globl __irq_dma2_channel2 - .set __irq_dma2_channel2, __default_handler - .weak __irq_dma2_channel3 - .globl __irq_dma2_channel3 - .set __irq_dma2_channel3, __default_handler - .weak __irq_dma2_channel4_5 - .globl __irq_dma2_channel4_5 - .set __irq_dma2_channel4_5, __default_handler +// .weak __irq_uart4 // __irq_uart4() defined in STM32F1/cores/maple/libmaple/usart_f1.c +// .globl __irq_uart4 +// .set __irq_uart4, __default_handler +// .weak __irq_uart5 // __irq_uart5() defined in STM32F1/cores/maple/libmaple/usart_f1.c +// .globl __irq_uart5 +// .set __irq_uart5, __default_handler +// .weak __irq_tim6 // __irq_tim6() defined in STM32F1/cores/maple/libmaple/timer.c +// .globl __irq_tim6 +// .set __irq_tim6, __default_handler +// .weak __irq_tim7 // __irq_tim7() defined in STM32F1/cores/maple/libmaple/timer.c +// .globl __irq_tim7 +// .set __irq_tim7, __default_handler +// .weak __irq_dma2_channel1 // __irq_dma2_channel1() defined in STM32F1/cores/maple/libmaple/dma_f1.c +// .globl __irq_dma2_channel1 +// .set __irq_dma2_channel1, __default_handler +// .weak __irq_dma2_channel2 // __irq_dma2_channel2() defined in STM32F1/cores/maple/libmaple/dma_f1.c +// .globl __irq_dma2_channel2 +// .set __irq_dma2_channel2, __default_handler +// .weak __irq_dma2_channel3 // __irq_dma2_channel3() defined in STM32F1/cores/maple/libmaple/dma_f1.c +// .globl __irq_dma2_channel3 +// .set __irq_dma2_channel3, __default_handler +// .weak __irq_dma2_channel4_5 // __irq_dma2_channel4_5() defined in STM32F1/cores/maple/libmaple/dma_f1.c +// .globl __irq_dma2_channel4_5 +// .set __irq_dma2_channel4_5, __default_handler #endif /* STM32_HIGH_DENSITY */ \ No newline at end of file diff --git a/STM32F1/cores/maple/libmaple/systick.c b/STM32F1/cores/maple/libmaple/systick.c index 7568abe..1ac92f1 100644 --- a/STM32F1/cores/maple/libmaple/systick.c +++ b/STM32F1/cores/maple/libmaple/systick.c @@ -80,7 +80,7 @@ void systick_attach_callback(void (*callback)(void)) { * SysTick ISR */ -void __exc_systick(void) { +__weak void __exc_systick(void) { systick_uptime_millis++; if (systick_user_callback) { systick_user_callback(); diff --git a/STM32F1/cores/maple/libmaple/timer.c b/STM32F1/cores/maple/libmaple/timer.c index fa50c20..5f12430 100644 --- a/STM32F1/cores/maple/libmaple/timer.c +++ b/STM32F1/cores/maple/libmaple/timer.c @@ -478,78 +478,78 @@ static void enable_bas_gen_irq(timer_dev *dev) { * file. */ -void __irq_tim1_brk(void) { +__weak void __irq_tim1_brk(void) { dispatch_adv_brk(TIMER1); #if STM32_HAVE_TIMER(9) dispatch_tim_9_12(TIMER9); #endif } -void __irq_tim1_up(void) { +__weak void __irq_tim1_up(void) { dispatch_adv_up(TIMER1); #if STM32_HAVE_TIMER(10) dispatch_tim_10_11_13_14(TIMER10); #endif } -void __irq_tim1_trg_com(void) { +__weak void __irq_tim1_trg_com(void) { dispatch_adv_trg_com(TIMER1); #if STM32_HAVE_TIMER(11) dispatch_tim_10_11_13_14(TIMER11); #endif } -void __irq_tim1_cc(void) { +__weak void __irq_tim1_cc(void) { dispatch_adv_cc(TIMER1); } -void __irq_tim2(void) { +__weak void __irq_tim2(void) { dispatch_general(TIMER2); } -void __irq_tim3(void) { +__weak void __irq_tim3(void) { dispatch_general(TIMER3); } -void __irq_tim4(void) { +__weak void __irq_tim4(void) { dispatch_general(TIMER4); } #if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) -void __irq_tim5(void) { +__weak void __irq_tim5(void) { dispatch_general(TIMER5); } -void __irq_tim6(void) { +__weak void __irq_tim6(void) { dispatch_basic(TIMER6); } -void __irq_tim7(void) { +__weak void __irq_tim7(void) { dispatch_basic(TIMER7); } -void __irq_tim8_brk(void) { +__weak void __irq_tim8_brk(void) { dispatch_adv_brk(TIMER8); #if STM32_HAVE_TIMER(12) dispatch_tim_9_12(TIMER12); #endif } -void __irq_tim8_up(void) { +__weak void __irq_tim8_up(void) { dispatch_adv_up(TIMER8); #if STM32_HAVE_TIMER(13) dispatch_tim_10_11_13_14(TIMER13); #endif } -void __irq_tim8_trg_com(void) { +__weak void __irq_tim8_trg_com(void) { dispatch_adv_trg_com(TIMER8); #if STM32_HAVE_TIMER(14) dispatch_tim_10_11_13_14(TIMER14); #endif } -void __irq_tim8_cc(void) { +__weak void __irq_tim8_cc(void) { dispatch_adv_cc(TIMER8); } #endif /* defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) */ \ No newline at end of file diff --git a/STM32F1/cores/maple/libmaple/usart_f1.c b/STM32F1/cores/maple/libmaple/usart_f1.c index 2b590fc..30ce000 100644 --- a/STM32F1/cores/maple/libmaple/usart_f1.c +++ b/STM32F1/cores/maple/libmaple/usart_f1.c @@ -200,24 +200,24 @@ void usart_foreach(void (*fn)(usart_dev*)) { * Interrupt handlers. */ -void __irq_usart1(void) { +__weak void __irq_usart1(void) { usart_irq(&usart1_rb, &usart1_wb, USART1_BASE); } -void __irq_usart2(void) { +__weak void __irq_usart2(void) { usart_irq(&usart2_rb, &usart2_wb, USART2_BASE); } -void __irq_usart3(void) { +__weak void __irq_usart3(void) { usart_irq(&usart3_rb, &usart3_wb, USART3_BASE); } #ifdef STM32_HIGH_DENSITY -void __irq_uart4(void) { +__weak void __irq_uart4(void) { usart_irq(&uart4_rb, &uart4_wb, UART4_BASE); } -void __irq_uart5(void) { +__weak void __irq_uart5(void) { usart_irq(&uart5_rb, &uart5_wb, UART5_BASE); } #endif diff --git a/STM32F1/cores/maple/libmaple/usb/stm32f1/usb.c b/STM32F1/cores/maple/libmaple/usb/stm32f1/usb.c index 0feb745..4f6c823 100644 --- a/STM32F1/cores/maple/libmaple/usb/stm32f1/usb.c +++ b/STM32F1/cores/maple/libmaple/usb/stm32f1/usb.c @@ -190,7 +190,7 @@ static void usb_resume(RESUME_STATE eResumeSetVal) { } #define SUSPEND_ENABLED 1 -void __irq_usb_lp_can_rx0(void) { +__weak void __irq_usb_lp_can_rx0(void) { uint16 istr = USB_BASE->ISTR; /* Use USB_ISR_MSK to only include code for bits we care about. */ From 4bb4ce913b0c26dd016e0de4bbd072656c79fda7 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Thu, 19 Apr 2018 18:09:09 +1000 Subject: [PATCH 326/351] Removed STM32F3 folder as it was only included as an archive, and is still available in the STM32F3 branch --- STM32F3/README.md | 45 - STM32F3/boards.txt | 62 - STM32F3/cores/maple/Arduino.h | 4 - STM32F3/cores/maple/WProgram.h | 35 - STM32F3/cores/maple/libmaple/adc.c | 52 - STM32F3/cores/maple/libmaple/bkp.c | 69 - STM32F3/cores/maple/libmaple/dac.c | 120 -- STM32F3/cores/maple/libmaple/dma.c | 82 -- STM32F3/cores/maple/libmaple/dma_private.h | 61 - STM32F3/cores/maple/libmaple/exc.S | 101 -- STM32F3/cores/maple/libmaple/exti.c | 293 ----- STM32F3/cores/maple/libmaple/exti_private.h | 34 - STM32F3/cores/maple/libmaple/flash.c | 55 - STM32F3/cores/maple/libmaple/gpio.c | 50 - STM32F3/cores/maple/libmaple/i2c.c | 52 - STM32F3/cores/maple/libmaple/i2c_private.h | 75 -- .../maple/libmaple/include/libmaple/adc.h | 319 ----- .../maple/libmaple/include/libmaple/bitband.h | 128 -- .../maple/libmaple/include/libmaple/bkp.h | 100 -- .../maple/libmaple/include/libmaple/comp.h | 46 - .../maple/libmaple/include/libmaple/dac.h | 158 --- .../maple/libmaple/include/libmaple/delay.h | 65 - .../maple/libmaple/include/libmaple/dma.h | 444 ------- .../libmaple/include/libmaple/dma_common.h | 112 -- .../maple/libmaple/include/libmaple/dsp.h | 131 -- .../maple/libmaple/include/libmaple/exti.h | 143 --- .../maple/libmaple/include/libmaple/flash.h | 106 -- .../maple/libmaple/include/libmaple/fpu.h | 56 - .../maple/libmaple/include/libmaple/fsmc.h | 340 ----- .../maple/libmaple/include/libmaple/gpio.h | 121 -- .../maple/libmaple/include/libmaple/i2c.h | 304 ----- .../libmaple/include/libmaple/i2c_common.h | 93 -- .../maple/libmaple/include/libmaple/iwdg.h | 115 -- .../libmaple/include/libmaple/libmaple.h | 48 - .../include/libmaple/libmaple_types.h | 73 -- .../maple/libmaple/include/libmaple/nvic.h | 155 --- .../maple/libmaple/include/libmaple/opamp.h | 46 - .../maple/libmaple/include/libmaple/pwr.h | 115 -- .../maple/libmaple/include/libmaple/rcc.h | 175 --- .../libmaple/include/libmaple/ring_buffer.h | 188 --- .../maple/libmaple/include/libmaple/scb.h | 214 ---- .../maple/libmaple/include/libmaple/spi.h | 487 ------- .../maple/libmaple/include/libmaple/stm32.h | 239 ---- .../maple/libmaple/include/libmaple/syscfg.h | 116 -- .../maple/libmaple/include/libmaple/systick.h | 115 -- .../maple/libmaple/include/libmaple/timer.h | 1119 ----------------- .../maple/libmaple/include/libmaple/usart.h | 464 ------- .../maple/libmaple/include/libmaple/usb.h | 176 --- .../libmaple/include/libmaple/usb_cdcacm.h | 179 --- .../maple/libmaple/include/libmaple/util.h | 111 -- STM32F3/cores/maple/libmaple/iwdg.c | 62 - STM32F3/cores/maple/libmaple/nvic.c | 103 -- STM32F3/cores/maple/libmaple/pwr.c | 41 - STM32F3/cores/maple/libmaple/rcc.c | 169 --- STM32F3/cores/maple/libmaple/rcc_private.h | 67 - STM32F3/cores/maple/libmaple/rules.mk | 53 - STM32F3/cores/maple/libmaple/spi.c | 129 -- STM32F3/cores/maple/libmaple/spi_private.h | 37 - STM32F3/cores/maple/libmaple/stm32_private.h | 45 - STM32F3/cores/maple/libmaple/stm32f3/f3_adc.c | 412 ------ STM32F3/cores/maple/libmaple/stm32f3/f3_bkp.c | 49 - .../cores/maple/libmaple/stm32f3/f3_comp.c | 61 - STM32F3/cores/maple/libmaple/stm32f3/f3_dma.c | 364 ------ .../cores/maple/libmaple/stm32f3/f3_exti.c | 40 - STM32F3/cores/maple/libmaple/stm32f3/f3_fpu.c | 57 - .../cores/maple/libmaple/stm32f3/f3_gpio.c | 169 --- STM32F3/cores/maple/libmaple/stm32f3/f3_i2c.c | 319 ----- .../cores/maple/libmaple/stm32f3/f3_opamp.c | 46 - STM32F3/cores/maple/libmaple/stm32f3/f3_rcc.c | 149 --- STM32F3/cores/maple/libmaple/stm32f3/f3_spi.c | 143 --- .../cores/maple/libmaple/stm32f3/f3_syscfg.c | 43 - .../cores/maple/libmaple/stm32f3/f3_timer.c | 147 --- .../cores/maple/libmaple/stm32f3/f3_usart.c | 210 ---- .../libmaple/stm32f3/include/series/adc.h | 696 ---------- .../libmaple/stm32f3/include/series/bkp.h | 62 - .../libmaple/stm32f3/include/series/comp.h | 119 -- .../libmaple/stm32f3/include/series/crc.h | 94 -- .../libmaple/stm32f3/include/series/dac.h | 74 -- .../libmaple/stm32f3/include/series/dma.h | 557 -------- .../libmaple/stm32f3/include/series/exti.h | 49 - .../libmaple/stm32f3/include/series/flash.h | 164 --- .../libmaple/stm32f3/include/series/fpu.h | 65 - .../libmaple/stm32f3/include/series/gpio.h | 255 ---- .../libmaple/stm32f3/include/series/i2c.h | 315 ----- .../libmaple/stm32f3/include/series/nvic.h | 153 --- .../libmaple/stm32f3/include/series/opamp.h | 123 -- .../libmaple/stm32f3/include/series/pwr.h | 52 - .../libmaple/stm32f3/include/series/rcc.h | 632 ---------- .../libmaple/stm32f3/include/series/simd.h | 109 -- .../libmaple/stm32f3/include/series/spi.h | 178 --- .../libmaple/stm32f3/include/series/stm32.h | 238 ---- .../libmaple/stm32f3/include/series/syscfg.h | 138 -- .../libmaple/stm32f3/include/series/timer.h | 123 -- .../libmaple/stm32f3/include/series/usart.h | 277 ---- STM32F3/cores/maple/libmaple/stm32f3/rules.mk | 48 - STM32F3/cores/maple/libmaple/syscfg.c | 41 - STM32F3/cores/maple/libmaple/systick.c | 88 -- STM32F3/cores/maple/libmaple/timer.c | 456 ------- STM32F3/cores/maple/libmaple/timer_private.h | 235 ---- STM32F3/cores/maple/libmaple/usart.c | 122 -- STM32F3/cores/maple/libmaple/usart_private.c | 41 - STM32F3/cores/maple/libmaple/usart_private.h | 42 - STM32F3/cores/maple/libmaple/usb/README | 63 - STM32F3/cores/maple/libmaple/usb/usb.c | 387 ------ STM32F3/cores/maple/libmaple/usb/usb_cdcacm.c | 723 ----------- .../maple/libmaple/usb/usb_lib/usb_core.c | 1013 --------------- .../maple/libmaple/usb/usb_lib/usb_core.h | 251 ---- .../maple/libmaple/usb/usb_lib/usb_def.h | 88 -- .../maple/libmaple/usb/usb_lib/usb_init.c | 64 - .../maple/libmaple/usb/usb_lib/usb_init.h | 57 - .../maple/libmaple/usb/usb_lib/usb_lib.h | 36 - .../maple/libmaple/usb/usb_lib/usb_mem.c | 73 -- .../maple/libmaple/usb/usb_lib/usb_mem.h | 40 - .../maple/libmaple/usb/usb_lib/usb_regs.c | 748 ----------- .../maple/libmaple/usb/usb_lib/usb_regs.h | 627 --------- .../maple/libmaple/usb/usb_lib/usb_type.h | 77 -- .../maple/libmaple/usb/usb_lib_globals.h | 55 - .../cores/maple/libmaple/usb/usb_reg_map.c | 88 -- .../cores/maple/libmaple/usb/usb_reg_map.h | 617 --------- STM32F3/cores/maple/libmaple/util.c | 150 --- STM32F3/cores/maple/main.cpp | 44 - STM32F3/cores/maple/wirish/HardwareSPI.cpp | 320 ----- STM32F3/cores/maple/wirish/HardwareSPI.h | 225 ---- STM32F3/cores/maple/wirish/HardwareSerial.cpp | 139 -- STM32F3/cores/maple/wirish/HardwareSerial.h | 102 -- STM32F3/cores/maple/wirish/HardwareTimer.cpp | 156 --- STM32F3/cores/maple/wirish/HardwareTimer.h | 337 ----- STM32F3/cores/maple/wirish/Print.cpp | 244 ---- STM32F3/cores/maple/wirish/Print.h | 66 - STM32F3/cores/maple/wirish/bit_constants.h | 579 --------- STM32F3/cores/maple/wirish/bits.h | 35 - STM32F3/cores/maple/wirish/boards.cpp | 215 ---- STM32F3/cores/maple/wirish/boards.h | 173 --- STM32F3/cores/maple/wirish/boards_private.h | 71 -- STM32F3/cores/maple/wirish/cxxabi-compat.cpp | 6 - STM32F3/cores/maple/wirish/ext_interrupts.cpp | 90 -- STM32F3/cores/maple/wirish/ext_interrupts.h | 128 -- STM32F3/cores/maple/wirish/io.h | 222 ---- STM32F3/cores/maple/wirish/main.cxx | 40 - STM32F3/cores/maple/wirish/pwm.cpp | 48 - STM32F3/cores/maple/wirish/pwm.h | 56 - STM32F3/cores/maple/wirish/rules.mk | 66 - .../maple/wirish/stm32f3/boards_setup.cpp | 92 -- .../wirish/stm32f3/f3_wirish_digital.cpp | 99 -- .../cores/maple/wirish/stm32f3/util_hooks.c | 45 - .../maple/wirish/stm32f3/wirish_debug.cpp | 70 -- STM32F3/cores/maple/wirish/syscalls.c | 175 --- STM32F3/cores/maple/wirish/usb_serial.cpp | 260 ---- STM32F3/cores/maple/wirish/usb_serial.h | 67 - STM32F3/cores/maple/wirish/wirish.h | 77 -- STM32F3/cores/maple/wirish/wirish_analog.cpp | 47 - STM32F3/cores/maple/wirish/wirish_debug.h | 57 - STM32F3/cores/maple/wirish/wirish_digital.cpp | 94 -- STM32F3/cores/maple/wirish/wirish_math.cpp | 49 - STM32F3/cores/maple/wirish/wirish_math.h | 151 --- STM32F3/cores/maple/wirish/wirish_shift.cpp | 37 - STM32F3/cores/maple/wirish/wirish_time.cpp | 45 - STM32F3/cores/maple/wirish/wirish_time.h | 95 -- STM32F3/cores/maple/wirish/wirish_types.h | 68 - STM32F3/examples/Blinkf3/Blinkf3.ino | 38 - .../examples/f3_buttondemo/f3_buttondemo.ino | 54 - .../f3_functionTimer/f3_functionTimer.ino | 144 --- STM32F3/examples/f3_gyrodemo/f3_gyrodemo.ino | 100 -- .../examples/f3_lsm303demo/f3_lsm303demo.ino | 111 -- .../examples/f3_ultrasonic/f3_ultrasonic.ino | 137 -- STM32F3/libraries/gyro/gyro.cpp | 337 ----- STM32F3/libraries/gyro/gyro.h | 118 -- STM32F3/libraries/gyro/l3gd20.h | 93 -- STM32F3/libraries/lsm303/lsm303.cpp | 225 ---- STM32F3/libraries/lsm303/lsm303.h | 77 -- STM32F3/libraries/lsm303/lsm303reg.h | 131 -- STM32F3/libraries/ringbuffer/ringbuffer.cpp | 320 ----- STM32F3/libraries/ringbuffer/ringbuffer.h | 155 --- STM32F3/libraries/roboter/debug.cpp | 196 --- STM32F3/libraries/roboter/debug.h | 58 - STM32F3/libraries/roboter/eeprom.cpp | 169 --- STM32F3/libraries/roboter/eeprom.h | 53 - STM32F3/libraries/roboter/functiontimer.cpp | 234 ---- STM32F3/libraries/roboter/functiontimer.h | 51 - STM32F3/libraries/roboter/motor.cpp | 259 ---- STM32F3/libraries/roboter/motor.h | 58 - STM32F3/libraries/roboter/sound.cpp | 30 - STM32F3/libraries/roboter/sound.h | 33 - STM32F3/libraries/roboter/ultraschall.cpp | 536 -------- STM32F3/libraries/roboter/ultraschall.h | 156 --- STM32F3/platform.txt | 144 --- STM32F3/variants/discovery_f3/board/board.h | 138 -- .../variants/discovery_f3/discovery_f3.cpp | 193 --- STM32F3/variants/discovery_f3/ld/common.inc | 229 ---- .../variants/discovery_f3/ld/extra_libs.inc | 7 - STM32F3/variants/discovery_f3/ld/flash.ld | 28 - STM32F3/variants/discovery_f3/ld/jtag.ld | 33 - .../variants/discovery_f3/ld/mem-flash.inc | 6 - STM32F3/variants/discovery_f3/ld/mem-jtag.inc | 6 - STM32F3/variants/discovery_f3/ld/mem-ram.inc | 6 - STM32F3/variants/discovery_f3/ld/names.inc | 78 -- STM32F3/variants/discovery_f3/ld/ram.ld | 27 - .../discovery_f3/ld/vector_symbols.inc | 98 -- STM32F3/variants/discovery_f3/stm32_isrs.S | 331 ----- .../discovery_f3/stm32_vector_table.S | 134 -- STM32F3/variants/discovery_f3/wirish/start.S | 57 - .../variants/discovery_f3/wirish/start_c.c | 95 -- 202 files changed, 31982 deletions(-) delete mode 100644 STM32F3/README.md delete mode 100644 STM32F3/boards.txt delete mode 100644 STM32F3/cores/maple/Arduino.h delete mode 100644 STM32F3/cores/maple/WProgram.h delete mode 100644 STM32F3/cores/maple/libmaple/adc.c delete mode 100644 STM32F3/cores/maple/libmaple/bkp.c delete mode 100644 STM32F3/cores/maple/libmaple/dac.c delete mode 100644 STM32F3/cores/maple/libmaple/dma.c delete mode 100644 STM32F3/cores/maple/libmaple/dma_private.h delete mode 100644 STM32F3/cores/maple/libmaple/exc.S delete mode 100644 STM32F3/cores/maple/libmaple/exti.c delete mode 100644 STM32F3/cores/maple/libmaple/exti_private.h delete mode 100644 STM32F3/cores/maple/libmaple/flash.c delete mode 100644 STM32F3/cores/maple/libmaple/gpio.c delete mode 100644 STM32F3/cores/maple/libmaple/i2c.c delete mode 100644 STM32F3/cores/maple/libmaple/i2c_private.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/adc.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/bitband.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/bkp.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/comp.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/dac.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/delay.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/dma.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/dma_common.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/dsp.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/exti.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/flash.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/fpu.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/fsmc.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/gpio.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/i2c.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/i2c_common.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/iwdg.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/libmaple.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/libmaple_types.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/nvic.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/opamp.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/pwr.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/rcc.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/ring_buffer.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/scb.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/spi.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/stm32.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/syscfg.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/systick.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/timer.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/usart.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/usb.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/usb_cdcacm.h delete mode 100644 STM32F3/cores/maple/libmaple/include/libmaple/util.h delete mode 100644 STM32F3/cores/maple/libmaple/iwdg.c delete mode 100644 STM32F3/cores/maple/libmaple/nvic.c delete mode 100644 STM32F3/cores/maple/libmaple/pwr.c delete mode 100644 STM32F3/cores/maple/libmaple/rcc.c delete mode 100644 STM32F3/cores/maple/libmaple/rcc_private.h delete mode 100644 STM32F3/cores/maple/libmaple/rules.mk delete mode 100644 STM32F3/cores/maple/libmaple/spi.c delete mode 100644 STM32F3/cores/maple/libmaple/spi_private.h delete mode 100644 STM32F3/cores/maple/libmaple/stm32_private.h delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/f3_adc.c delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/f3_bkp.c delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/f3_comp.c delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/f3_dma.c delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/f3_exti.c delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/f3_fpu.c delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/f3_gpio.c delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/f3_i2c.c delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/f3_opamp.c delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/f3_rcc.c delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/f3_spi.c delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/f3_syscfg.c delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/f3_timer.c delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/f3_usart.c delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/include/series/adc.h delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/include/series/bkp.h delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/include/series/comp.h delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/include/series/crc.h delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/include/series/dac.h delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/include/series/dma.h delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/include/series/exti.h delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/include/series/flash.h delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/include/series/fpu.h delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/include/series/gpio.h delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/include/series/i2c.h delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/include/series/nvic.h delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/include/series/opamp.h delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/include/series/pwr.h delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/include/series/rcc.h delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/include/series/simd.h delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/include/series/spi.h delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/include/series/stm32.h delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/include/series/syscfg.h delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/include/series/timer.h delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/include/series/usart.h delete mode 100644 STM32F3/cores/maple/libmaple/stm32f3/rules.mk delete mode 100644 STM32F3/cores/maple/libmaple/syscfg.c delete mode 100644 STM32F3/cores/maple/libmaple/systick.c delete mode 100644 STM32F3/cores/maple/libmaple/timer.c delete mode 100644 STM32F3/cores/maple/libmaple/timer_private.h delete mode 100644 STM32F3/cores/maple/libmaple/usart.c delete mode 100644 STM32F3/cores/maple/libmaple/usart_private.c delete mode 100644 STM32F3/cores/maple/libmaple/usart_private.h delete mode 100644 STM32F3/cores/maple/libmaple/usb/README delete mode 100644 STM32F3/cores/maple/libmaple/usb/usb.c delete mode 100644 STM32F3/cores/maple/libmaple/usb/usb_cdcacm.c delete mode 100644 STM32F3/cores/maple/libmaple/usb/usb_lib/usb_core.c delete mode 100644 STM32F3/cores/maple/libmaple/usb/usb_lib/usb_core.h delete mode 100644 STM32F3/cores/maple/libmaple/usb/usb_lib/usb_def.h delete mode 100644 STM32F3/cores/maple/libmaple/usb/usb_lib/usb_init.c delete mode 100644 STM32F3/cores/maple/libmaple/usb/usb_lib/usb_init.h delete mode 100644 STM32F3/cores/maple/libmaple/usb/usb_lib/usb_lib.h delete mode 100644 STM32F3/cores/maple/libmaple/usb/usb_lib/usb_mem.c delete mode 100644 STM32F3/cores/maple/libmaple/usb/usb_lib/usb_mem.h delete mode 100644 STM32F3/cores/maple/libmaple/usb/usb_lib/usb_regs.c delete mode 100644 STM32F3/cores/maple/libmaple/usb/usb_lib/usb_regs.h delete mode 100644 STM32F3/cores/maple/libmaple/usb/usb_lib/usb_type.h delete mode 100644 STM32F3/cores/maple/libmaple/usb/usb_lib_globals.h delete mode 100644 STM32F3/cores/maple/libmaple/usb/usb_reg_map.c delete mode 100644 STM32F3/cores/maple/libmaple/usb/usb_reg_map.h delete mode 100644 STM32F3/cores/maple/libmaple/util.c delete mode 100644 STM32F3/cores/maple/main.cpp delete mode 100644 STM32F3/cores/maple/wirish/HardwareSPI.cpp delete mode 100644 STM32F3/cores/maple/wirish/HardwareSPI.h delete mode 100644 STM32F3/cores/maple/wirish/HardwareSerial.cpp delete mode 100644 STM32F3/cores/maple/wirish/HardwareSerial.h delete mode 100644 STM32F3/cores/maple/wirish/HardwareTimer.cpp delete mode 100644 STM32F3/cores/maple/wirish/HardwareTimer.h delete mode 100644 STM32F3/cores/maple/wirish/Print.cpp delete mode 100644 STM32F3/cores/maple/wirish/Print.h delete mode 100644 STM32F3/cores/maple/wirish/bit_constants.h delete mode 100644 STM32F3/cores/maple/wirish/bits.h delete mode 100644 STM32F3/cores/maple/wirish/boards.cpp delete mode 100644 STM32F3/cores/maple/wirish/boards.h delete mode 100644 STM32F3/cores/maple/wirish/boards_private.h delete mode 100644 STM32F3/cores/maple/wirish/cxxabi-compat.cpp delete mode 100644 STM32F3/cores/maple/wirish/ext_interrupts.cpp delete mode 100644 STM32F3/cores/maple/wirish/ext_interrupts.h delete mode 100644 STM32F3/cores/maple/wirish/io.h delete mode 100644 STM32F3/cores/maple/wirish/main.cxx delete mode 100644 STM32F3/cores/maple/wirish/pwm.cpp delete mode 100644 STM32F3/cores/maple/wirish/pwm.h delete mode 100644 STM32F3/cores/maple/wirish/rules.mk delete mode 100644 STM32F3/cores/maple/wirish/stm32f3/boards_setup.cpp delete mode 100644 STM32F3/cores/maple/wirish/stm32f3/f3_wirish_digital.cpp delete mode 100644 STM32F3/cores/maple/wirish/stm32f3/util_hooks.c delete mode 100644 STM32F3/cores/maple/wirish/stm32f3/wirish_debug.cpp delete mode 100644 STM32F3/cores/maple/wirish/syscalls.c delete mode 100644 STM32F3/cores/maple/wirish/usb_serial.cpp delete mode 100644 STM32F3/cores/maple/wirish/usb_serial.h delete mode 100644 STM32F3/cores/maple/wirish/wirish.h delete mode 100644 STM32F3/cores/maple/wirish/wirish_analog.cpp delete mode 100644 STM32F3/cores/maple/wirish/wirish_debug.h delete mode 100644 STM32F3/cores/maple/wirish/wirish_digital.cpp delete mode 100644 STM32F3/cores/maple/wirish/wirish_math.cpp delete mode 100644 STM32F3/cores/maple/wirish/wirish_math.h delete mode 100644 STM32F3/cores/maple/wirish/wirish_shift.cpp delete mode 100644 STM32F3/cores/maple/wirish/wirish_time.cpp delete mode 100644 STM32F3/cores/maple/wirish/wirish_time.h delete mode 100644 STM32F3/cores/maple/wirish/wirish_types.h delete mode 100644 STM32F3/examples/Blinkf3/Blinkf3.ino delete mode 100644 STM32F3/examples/f3_buttondemo/f3_buttondemo.ino delete mode 100644 STM32F3/examples/f3_functionTimer/f3_functionTimer.ino delete mode 100644 STM32F3/examples/f3_gyrodemo/f3_gyrodemo.ino delete mode 100644 STM32F3/examples/f3_lsm303demo/f3_lsm303demo.ino delete mode 100644 STM32F3/examples/f3_ultrasonic/f3_ultrasonic.ino delete mode 100644 STM32F3/libraries/gyro/gyro.cpp delete mode 100644 STM32F3/libraries/gyro/gyro.h delete mode 100644 STM32F3/libraries/gyro/l3gd20.h delete mode 100644 STM32F3/libraries/lsm303/lsm303.cpp delete mode 100644 STM32F3/libraries/lsm303/lsm303.h delete mode 100644 STM32F3/libraries/lsm303/lsm303reg.h delete mode 100644 STM32F3/libraries/ringbuffer/ringbuffer.cpp delete mode 100644 STM32F3/libraries/ringbuffer/ringbuffer.h delete mode 100644 STM32F3/libraries/roboter/debug.cpp delete mode 100644 STM32F3/libraries/roboter/debug.h delete mode 100644 STM32F3/libraries/roboter/eeprom.cpp delete mode 100644 STM32F3/libraries/roboter/eeprom.h delete mode 100644 STM32F3/libraries/roboter/functiontimer.cpp delete mode 100644 STM32F3/libraries/roboter/functiontimer.h delete mode 100644 STM32F3/libraries/roboter/motor.cpp delete mode 100644 STM32F3/libraries/roboter/motor.h delete mode 100644 STM32F3/libraries/roboter/sound.cpp delete mode 100644 STM32F3/libraries/roboter/sound.h delete mode 100644 STM32F3/libraries/roboter/ultraschall.cpp delete mode 100644 STM32F3/libraries/roboter/ultraschall.h delete mode 100644 STM32F3/platform.txt delete mode 100644 STM32F3/variants/discovery_f3/board/board.h delete mode 100644 STM32F3/variants/discovery_f3/discovery_f3.cpp delete mode 100644 STM32F3/variants/discovery_f3/ld/common.inc delete mode 100644 STM32F3/variants/discovery_f3/ld/extra_libs.inc delete mode 100644 STM32F3/variants/discovery_f3/ld/flash.ld delete mode 100644 STM32F3/variants/discovery_f3/ld/jtag.ld delete mode 100644 STM32F3/variants/discovery_f3/ld/mem-flash.inc delete mode 100644 STM32F3/variants/discovery_f3/ld/mem-jtag.inc delete mode 100644 STM32F3/variants/discovery_f3/ld/mem-ram.inc delete mode 100644 STM32F3/variants/discovery_f3/ld/names.inc delete mode 100644 STM32F3/variants/discovery_f3/ld/ram.ld delete mode 100644 STM32F3/variants/discovery_f3/ld/vector_symbols.inc delete mode 100644 STM32F3/variants/discovery_f3/stm32_isrs.S delete mode 100644 STM32F3/variants/discovery_f3/stm32_vector_table.S delete mode 100644 STM32F3/variants/discovery_f3/wirish/start.S delete mode 100644 STM32F3/variants/discovery_f3/wirish/start_c.c diff --git a/STM32F3/README.md b/STM32F3/README.md deleted file mode 100644 index 75cd5a4..0000000 --- a/STM32F3/README.md +++ /dev/null @@ -1,45 +0,0 @@ -STM32F3 files have been supplied by Frank-Michael Krause. - -The API is not as up to date as in the STM F103 files. -It looks like this port is as the F103 files orginally were when I started work on the project. -The API is for pre- Arduino 1.0 and doesn't include a lot of functions in the 1.0 API, and the class inheritance will -be different in a number of places, most importantly in the Serial class. -Specifically Stream.cpp / .h are not present in this port. - - - --------------------- Details from Frank-Michael ---------------------------- - -This port of libmaple for Arduino-IDE is based on the inofficial F3 branch -of libmaple found on -https://github.com/ventosus/libmaple/tree/F3 -and supports at the moment the STM32F3Discovery board with programming via ST-link. -Linker is configured for linking to flash, not to RAM - -Changes by Frank-Michael Krause (mich dot krause at web dot de): - -- renaming some stm32f3 related files because the Arduino build system copy all objects to same directory so the source file names must be different -- selected the correct startup modules and linker scripts for board variant stm32f3discovery - -Notes: - -- the pin names as noted on stm32f3discovery board (PA0, PA1, ..., PF10) can be used as pin id -- usb is untested because I haven't used it really -- There are some libraries and examples related to the STM32F3discovery board. - They are commented mostly in german only because I wrote them for use at robotic club of a secondary school - and the kids like to have the documentation in german. - - gyro: Interface library for the gyro-chip of the stm32f3discovery, setup the gyro in FIFO mode and so - requiring update calls only every < 120ms - lsm303: Interface library for Acceleration sensor of the stm32f3discovery, magnetometer not yet supported (writing this driver is currently under work by a student at school) - ringbuffer: Class impelentig a ringbuffer with functions for adding time stampes per added element, averaging functions, accessing the stored data like an array - roboter: several functionalities needed to program a robot: - - dc motor control as known from Lego NXC language - - support for HC-SR04 ultrasonic sensors driven by interrupt or blocking direct measurement - - function timers based on timer interrupt - - modul for interfacing a 24Cxx I2C eeprom chip - - - - - diff --git a/STM32F3/boards.txt b/STM32F3/boards.txt deleted file mode 100644 index 98a184d..0000000 --- a/STM32F3/boards.txt +++ /dev/null @@ -1,62 +0,0 @@ -# - -menu.opt=Optimize - -############################################################## -discovery_f3.name=STM32F3Discovery - -discovery_f3.upload.tool=stlink -discovery_f3.upload.protocol=stlink - -#discovery_f407.upload.use_1200bps_touch=false -discovery_f3.upload.file_type=bin -discovery_f3.upload.maximum_size=262144 -discovery_f3.upload.maximum_data_size=49152 - -#discovery_f3.upload.usbID=1EAF:0003 -#discovery_f3.upload.altID=1 -#discovery_f3.upload.auto_reset=true - -discovery_f3.build.mcu=cortex-m3 -discovery_f3.build.f_cpu=72000000L -discovery_f3.build.core=maple -discovery_f3.build.extra_flags=-DMCU_STM32F303VC -mthumb -DSTM32_XL_DENSITY -march=armv7-m -DSTM32F3 -DF303VC -DBOARD_discovery_f3 -discovery_f3.build.ldscript=ld/jtag.ld -discovery_f3.build.variant=discovery_f3 -discovery_f3.build.variant_system_lib=lib_f3.a -discovery_f3.build.vect=VECT_TAB_BASE -discovery_f3.build.density=STM32_XL_DENSITY -discovery_f3.build.error_led_port=GPIOE -discovery_f3.build.error_led_pin=8 -discovery_f3.build.board=STM32F3Discovery - -#-- Optimizations -discovery_f3.menu.opt.osstd=Smallest (default) -discovery_f3.menu.opt.osstd.build.flags.optimize=-Os -discovery_f3.menu.opt.osstd.build.flags.ldspecs= -discovery_f3.menu.opt.oslto=Smallest Code with LTO -discovery_f3.menu.opt.oslto.build.flags.optimize=-Os -flto -discovery_f3.menu.opt.oslto.build.flags.ldspecs=-flto -discovery_f3.menu.opt.o1std=Fast (-O1) -discovery_f3.menu.opt.o1std.build.flags.optimize=-O1 -discovery_f3.menu.opt.o1std.build.flags.ldspecs= -discovery_f3.menu.opt.o1lto=Fast (-O1) with LTO -discovery_f3.menu.opt.o1lto.build.flags.optimize=-O1 -flto -discovery_f3.menu.opt.o1lto.build.flags.ldspecs=-flto -discovery_f3.menu.opt.o2std=Faster (-O2) -discovery_f3.menu.opt.o2std.build.flags.optimize=-O2 -discovery_f3.menu.opt.o2std.build.flags.ldspecs= -discovery_f3.menu.opt.o2lto=Faster (-O2) with LTO -discovery_f3.menu.opt.o2lto.build.flags.optimize=-O2 -flto -discovery_f3.menu.opt.o2lto.build.flags.ldspecs=-flto -discovery_f3.menu.opt.o3std=Fastest (-O3) -discovery_f3.menu.opt.o3std.build.flags.optimize=-O3 -discovery_f3.menu.opt.o3std.build.flags.ldspecs= -discovery_f3.menu.opt.o3lto=Fastest (-O3) with LTO -discovery_f3.menu.opt.o3lto.build.flags.optimize=-O3 -flto -discovery_f3.menu.opt.o3lto.build.flags.ldspecs=-flto -discovery_f3.menu.opt.ogstd=Debug (-g) -discovery_f3.menu.opt.ogstd.build.flags.optimize=-Og -discovery_f3.menu.opt.ogstd.build.flags.ldspecs= -############################################################## - diff --git a/STM32F3/cores/maple/Arduino.h b/STM32F3/cores/maple/Arduino.h deleted file mode 100644 index 7278f89..0000000 --- a/STM32F3/cores/maple/Arduino.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef Arduino_h -#define Arduino_h -#include "WProgram.h" -#endif diff --git a/STM32F3/cores/maple/WProgram.h b/STM32F3/cores/maple/WProgram.h deleted file mode 100644 index b24ec2a..0000000 --- a/STM32F3/cores/maple/WProgram.h +++ /dev/null @@ -1,35 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 LeafLabs LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -#ifndef _WIRISH_WPROGRAM_H_ -#define _WIRISH_WPROGRAM_H_ - -#include - -void setup(); -void loop(); - -#endif diff --git a/STM32F3/cores/maple/libmaple/adc.c b/STM32F3/cores/maple/libmaple/adc.c deleted file mode 100644 index 630a8a8..0000000 --- a/STM32F3/cores/maple/libmaple/adc.c +++ /dev/null @@ -1,52 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * Copyright (c) 2011, 2012 LeafLabs, LLC. - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/adc.c - * @author Marti Bolivar , - * Perry Hung , - * F3-port by Hanspeter Portner - * @brief Analog to digital converter routines - */ - -#include -#include -#include - -/** - * @brief Initialize an ADC peripheral. - * - * Initializes the RCC clock line for the given peripheral. Resets - * ADC device registers. - * - * @param dev ADC peripheral to initialize - */ -void adc_init(const adc_dev *dev) { - rcc_clk_enable(dev->clk_id); - rcc_reset_dev(dev->clk_id); -} diff --git a/STM32F3/cores/maple/libmaple/bkp.c b/STM32F3/cores/maple/libmaple/bkp.c deleted file mode 100644 index c48440b..0000000 --- a/STM32F3/cores/maple/libmaple/bkp.c +++ /dev/null @@ -1,69 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 LeafLabs, LLC. - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/bkp.c - * @author F3-port by Hanspeter Portner - * @brief Backup register support (STM32F1 & STM32F3 only). - */ - -#include -#include -#include - -bkp_dev bkp = { - .regs = BKP_BASE, -}; -/** Backup device. */ -const bkp_dev *BKP = &bkp; - -void bkp_enable_writes(void) { - *bb_perip(&PWR_BASE->CR, PWR_CR_DBP_BIT) = 1; -} - -void bkp_disable_writes(void) { - *bb_perip(&PWR_BASE->CR, PWR_CR_DBP_BIT) = 0; -} - -uint16 bkp_read(uint8 reg) { - __IO uint32* dr = bkp_data_register(reg); - if (!dr) { - ASSERT(0); /* nonexistent register */ - return 0; - } - return (uint16)*dr; -} - -void bkp_write(uint8 reg, uint16 val) { - __IO uint32* dr = bkp_data_register(reg); - if (!dr) { - ASSERT(0); /* nonexistent register */ - return; - } - *dr = (uint32)val; -} - diff --git a/STM32F3/cores/maple/libmaple/dac.c b/STM32F3/cores/maple/libmaple/dac.c deleted file mode 100644 index d802d2b..0000000 --- a/STM32F3/cores/maple/libmaple/dac.c +++ /dev/null @@ -1,120 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Bryan Newbold. - * Copyright (c) 2011, 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/dac.c - * @brief Digital to analog converter support. - */ - -#include -#include -#include - -#if STM32_HAVE_DAC -dac_dev dac = { - .regs = DAC_BASE, -}; -const dac_dev *DAC = &dac; -#endif - -/** - * @brief Initialize the digital to analog converter - * @param dev DAC device - * @param flags Flags: - * DAC_CH1: Enable channel 1 - * DAC_CH2: Enable channel 2 - * @sideeffect May set PA4 or PA5 to INPUT_ANALOG - */ -void dac_init(const dac_dev *dev, uint32 flags) { - /* First turn on the clock */ - rcc_clk_enable(RCC_DAC); - rcc_reset_dev(RCC_DAC); - - if (flags & DAC_CH1) { - dac_enable_channel(dev, 1); - } - - if (flags & DAC_CH2) { - dac_enable_channel(dev, 2); - } -} - -/** - * @brief Write a 12-bit value to the DAC to output - * @param dev DAC device - * @param channel channel to select (1 or 2) - * @param val value to write - */ -void dac_write_channel(const dac_dev *dev, uint8 channel, uint16 val) { - switch(channel) { - case 1: - dev->regs->DHR12R1 = DAC_DHR12R1_DACC1DHR & val; - break; - case 2: - dev->regs->DHR12R2 = DAC_DHR12R2_DACC2DHR & val; - break; - } -} - -/** - * @brief Enable a DAC channel - * @param dev DAC device - * @param channel channel to enable, either 1 or 2 - * @sideeffect May change pin mode of PA4 or PA5 - */ -void dac_enable_channel(const dac_dev *dev, uint8 channel) { - /* - * Setup ANALOG mode on PA4 and PA5. This mapping is consistent - * across all supported STM32s with a DAC. - */ - switch (channel) { - case 1: - gpio_set_mode(GPIOA, 4, GPIO_MODE_ANALOG); - dev->regs->CR |= DAC_CR_EN1; - break; - case 2: - gpio_set_mode(GPIOA, 5, GPIO_MODE_ANALOG); - dev->regs->CR |= DAC_CR_EN2; - break; - } -} - -/** - * @brief Disable a DAC channel - * @param dev DAC device - * @param channel channel to disable, either 1 or 2 - */ -void dac_disable_channel(const dac_dev *dev, uint8 channel) { - switch (channel) { - case 1: - dev->regs->CR &= ~DAC_CR_EN1; - break; - case 2: - dev->regs->CR &= ~DAC_CR_EN2; - break; - } -} diff --git a/STM32F3/cores/maple/libmaple/dma.c b/STM32F3/cores/maple/libmaple/dma.c deleted file mode 100644 index 1dc875e..0000000 --- a/STM32F3/cores/maple/libmaple/dma.c +++ /dev/null @@ -1,82 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Michael Hope. - * Copyright (c) 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/dma.c - * @author Marti Bolivar ; - * Original implementation by Michael Hope - * @brief Portable DMA routines. - */ - -#include -#include "dma_private.h" -#include "stm32_private.h" - -/* - * Convenience routines - */ - -/** - * @brief Initialize a DMA device. - * @param dev Device to initialize. - */ -void dma_init(dma_dev *dev) { - rcc_clk_enable(dev->clk_id); -} - -/* - * Private API - */ - -enum dma_atype _dma_addr_type(__IO void *addr) { - switch (stm32_block_purpose((void*)addr)) { - /* Notice we're treating the code block as memory here. That's - * correct for addresses in Flash and in [0x0, 0x7FFFFFF] - * (provided that those addresses are aliased to Flash, SRAM, or - * FSMC, depending on BOOT[01] and possibly SYSCFG_MEMRMP). It's - * not correct for other addresses in the code block, but those - * will (hopefully) just fail-fast with transfer or bus errors. If - * lots of people get confused, it might be worth being more - * careful here. */ - case STM32_BLOCK_CODE: /* Fall through */ - case STM32_BLOCK_SRAM: /* ... */ - case STM32_BLOCK_FSMC_1_2: /* ... */ - case STM32_BLOCK_FSMC_3_4: - return DMA_ATYPE_MEM; - case STM32_BLOCK_PERIPH: - return DMA_ATYPE_PER; - case STM32_BLOCK_FSMC_REG: /* Fall through */ - /* Is this right? I can't think of a reason to DMA into or out - * of the FSMC registers. [mbolivar] */ - case STM32_BLOCK_UNUSED: /* ... */ - case STM32_BLOCK_CORTEX_INTERNAL: /* ... */ - return DMA_ATYPE_OTHER; - default: - ASSERT(0); /* Can't happen */ - return DMA_ATYPE_OTHER; - } -} diff --git a/STM32F3/cores/maple/libmaple/dma_private.h b/STM32F3/cores/maple/libmaple/dma_private.h deleted file mode 100644 index 9338525..0000000 --- a/STM32F3/cores/maple/libmaple/dma_private.h +++ /dev/null @@ -1,61 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -*****************************************************************************/ - -#ifndef _LIBMAPLE_DMA_PRIVATE_H_ -#define _LIBMAPLE_DMA_PRIVATE_H_ - -#include -#include - -/* - * IRQ handling - */ - -/* Wrap this in an ifdef to shut up GCC. (We provide DMA_GET_HANDLER - * in the series support files, which need dma_irq_handler().) */ -#ifdef DMA_GET_HANDLER -static __always_inline void dma_irq_handler(dma_dev *dev, dma_tube tube) { - void (*handler)(void) = DMA_GET_HANDLER(dev, tube); - if (handler) { - handler(); - dma_clear_isr_bits(dev, tube); /* in case handler doesn't */ - } -} -#endif - -/* - * Conveniences for dealing with tube sources/destinations - */ - -enum dma_atype { - DMA_ATYPE_MEM, - DMA_ATYPE_PER, - DMA_ATYPE_OTHER, -}; - -enum dma_atype _dma_addr_type(__IO void *addr); - -#endif diff --git a/STM32F3/cores/maple/libmaple/exc.S b/STM32F3/cores/maple/libmaple/exc.S deleted file mode 100644 index 7631e48..0000000 --- a/STM32F3/cores/maple/libmaple/exc.S +++ /dev/null @@ -1,101 +0,0 @@ -/* ***************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * ****************************************************************************/ - -# On an exception, push a fake stack thread mode stack frame and redirect -# thread execution to a thread mode error handler - -# From RM008: -# The SP is decremented by eight words by the completion of the stack push. -# Figure 5-1 shows the contents of the stack after an exception pre-empts the -# current program flow. -# -# Old SP--> -# xPSR -# PC -# LR -# r12 -# r3 -# r2 -# r1 -# SP--> r0 - -.text -.globl __exc_hardfault -.globl __exc_nmi -.globl __exc_hardfault -.globl __exc_memmanage -.globl __exc_busfault -.globl __exc_usagefault - -.code 16 -.thumb_func -__exc_nmi: - mov r0, #1 - b __default_exc - -.thumb_func -__exc_hardfault: - mov r0, #2 - b __default_exc - -.thumb_func -__exc_memmanage: - mov r0, #3 - b __default_exc - -.thumb_func -__exc_busfault: - mov r0, #4 - b __default_exc - -.thumb_func -__exc_usagefault: - mov r0, #5 - b __default_exc - -.thumb_func -__default_exc: - ldr r2, NVIC_CCR @ Enable returning to thread mode even if there are - mov r1 ,#1 @ pending exceptions. See flag NONEBASETHRDENA. - str r1, [r2] - cpsid i @ Disable global interrupts - ldr r2, SYSTICK_CSR @ Disable systick handler - mov r1, #0 - str r1, [r2] - ldr r1, CPSR_MASK @ Set default CPSR - push {r1} - ldr r1, TARGET_PC @ Set target pc - push {r1} - sub sp, sp, #24 @ Don't care - ldr r1, EXC_RETURN @ Return to thread mode - mov lr, r1 - bx lr @ Exception exit - -.align 4 -CPSR_MASK: .word 0x61000000 -EXC_RETURN: .word 0xFFFFFFF9 -TARGET_PC: .word __error -NVIC_CCR: .word 0xE000ED14 @ NVIC configuration control register -SYSTICK_CSR: .word 0xE000E010 @ Systick control register - diff --git a/STM32F3/cores/maple/libmaple/exti.c b/STM32F3/cores/maple/libmaple/exti.c deleted file mode 100644 index f59c0eb..0000000 --- a/STM32F3/cores/maple/libmaple/exti.c +++ /dev/null @@ -1,293 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * Copyright (c) 2011, 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/exti.c - * @brief External interrupt control routines - */ - -#include -#include -#include -#include - -static inline void dispatch_single_exti(uint32 exti_num); -static inline void dispatch_extis(uint32 start, uint32 stop); - -/* - * Internal state - */ - -typedef struct exti_channel { - void (*handler)(void *); - void *arg; -} exti_channel; - -static exti_channel exti_channels[] = { - { .handler = NULL, .arg = NULL }, // EXTI0 - { .handler = NULL, .arg = NULL }, // EXTI1 - { .handler = NULL, .arg = NULL }, // EXTI2 - { .handler = NULL, .arg = NULL }, // EXTI3 - { .handler = NULL, .arg = NULL }, // EXTI4 - { .handler = NULL, .arg = NULL }, // EXTI5 - { .handler = NULL, .arg = NULL }, // EXTI6 - { .handler = NULL, .arg = NULL }, // EXTI7 - { .handler = NULL, .arg = NULL }, // EXTI8 - { .handler = NULL, .arg = NULL }, // EXTI9 - { .handler = NULL, .arg = NULL }, // EXTI10 - { .handler = NULL, .arg = NULL }, // EXTI11 - { .handler = NULL, .arg = NULL }, // EXTI12 - { .handler = NULL, .arg = NULL }, // EXTI13 - { .handler = NULL, .arg = NULL }, // EXTI14 - { .handler = NULL, .arg = NULL }, // EXTI15 -}; - -/* - * Portable routines - */ - -/** - * @brief Register a handler to run upon external interrupt. - * - * This function assumes that the interrupt request corresponding to - * the given external interrupt is masked. - * - * @param num External interrupt line number. - * @param port Port to use as source input for external interrupt. - * @param handler Function handler to execute when interrupt is triggered. - * @param mode Type of transition to trigger on, one of: - * EXTI_RISING, EXTI_FALLING, EXTI_RISING_FALLING. - * @see exti_num - * @see exti_cfg - * @see voidFuncPtr - * @see exti_trigger_mode - */ -void exti_attach_interrupt(exti_num num, - exti_cfg port, - voidFuncPtr handler, - exti_trigger_mode mode) { - // Call callback version with arg being null - exti_attach_callback(num, port, (voidArgumentFuncPtr)handler, NULL, mode); -} - -/** - * @brief Register a handler with an argument to run upon external interrupt. - * - * This function assumes that the interrupt request corresponding to - * the given external interrupt is masked. - * - * @param num External interrupt line number. - * @param port Port to use as source input for external interrupt. - * @param handler Function handler to execute when interrupt is triggered. - * @param arg Argument to pass to the interrupt handler. - * @param mode Type of transition to trigger on, one of: - * EXTI_RISING, EXTI_FALLING, EXTI_RISING_FALLING. - * @see exti_num - * @see exti_cfg - * @see voidFuncPtr - * @see exti_trigger_mode - */ -void exti_attach_callback(exti_num num, - exti_cfg port, - voidArgumentFuncPtr handler, - void *arg, - exti_trigger_mode mode) { - ASSERT(handler); - - /* Register the handler */ - exti_channels[num].handler = handler; - exti_channels[num].arg = arg; - - /* Set trigger mode */ - switch (mode) { - case EXTI_RISING: - bb_peri_set_bit(&EXTI_BASE->RTSR, num, 1); - break; - case EXTI_FALLING: - bb_peri_set_bit(&EXTI_BASE->FTSR, num, 1); - break; - case EXTI_RISING_FALLING: - bb_peri_set_bit(&EXTI_BASE->RTSR, num, 1); - bb_peri_set_bit(&EXTI_BASE->FTSR, num, 1); - break; - } - - /* Use the chip-specific exti_select() to map num to port */ - exti_select(num, port); - - /* Unmask external interrupt request */ - bb_peri_set_bit(&EXTI_BASE->IMR, num, 1); - - /* Enable the interrupt line */ - switch(num) - { - case EXTI0: - nvic_irq_enable(NVIC_EXTI0); - break; - case EXTI1: - nvic_irq_enable(NVIC_EXTI1); - break; - case EXTI2: - nvic_irq_enable(NVIC_EXTI2); - break; - case EXTI3: - nvic_irq_enable(NVIC_EXTI3); - break; - case EXTI4: - nvic_irq_enable(NVIC_EXTI4); - break; - case EXTI5: - case EXTI6: - case EXTI7: - case EXTI8: - case EXTI9: - nvic_irq_enable(NVIC_EXTI_9_5); - break; - case EXTI10: - case EXTI11: - case EXTI12: - case EXTI13: - case EXTI14: - case EXTI15: - nvic_irq_enable(NVIC_EXTI_15_10); - break; - } -} - -/** - * @brief Unregister an external interrupt handler - * @param num External interrupt line to disable. - * @see exti_num - */ -void exti_detach_interrupt(exti_num num) { - /* First, mask the interrupt request */ - bb_peri_set_bit(&EXTI_BASE->IMR, num, 0); - - /* Then, clear the trigger selection registers */ - bb_peri_set_bit(&EXTI_BASE->FTSR, num, 0); - bb_peri_set_bit(&EXTI_BASE->RTSR, num, 0); - - /* Finally, unregister the user's handler */ - exti_channels[num].handler = NULL; - exti_channels[num].arg = NULL; -} - -/* - * Private routines - */ - -void exti_do_select(__IO uint32 *exti_cr, exti_num num, exti_cfg port) { - uint32 shift = 4 * (num % 4); - uint32 cr = *exti_cr; - cr &= ~(0xF << shift); - cr |= port << shift; - *exti_cr = cr; -} - -/* - * Interrupt handlers - */ - -void __irq_exti0(void) { - dispatch_single_exti(EXTI0); -} - -void __irq_exti1(void) { - dispatch_single_exti(EXTI1); -} - -void __irq_exti2(void) { - dispatch_single_exti(EXTI2); - // FIXME handle capatitive touch IRQ on F302/303 -} - -void __irq_exti3(void) { - dispatch_single_exti(EXTI3); -} - -void __irq_exti4(void) { - dispatch_single_exti(EXTI4); -} - -void __irq_exti9_5(void) { - dispatch_extis(5, 9); -} - -void __irq_exti15_10(void) { - dispatch_extis(10, 15); -} - -/* - * Auxiliary functions - */ - -/* Clear the pending bits for EXTIs whose bits are set in exti_msk. - * - * If a pending bit is cleared as the last instruction in an ISR, it - * won't actually be cleared in time and the ISR will fire again. To - * compensate, this function NOPs for 2 cycles after clearing the - * pending bits to ensure it takes effect. */ -static __always_inline void clear_pending_msk(uint32 exti_msk) { - EXTI_BASE->PR = exti_msk; - asm volatile("nop"); - asm volatile("nop"); -} - -/* This dispatch routine is for non-multiplexed EXTI lines only; i.e., - * it doesn't check EXTI_PR. */ -static __always_inline void dispatch_single_exti(uint32 exti) { - voidArgumentFuncPtr handler = exti_channels[exti].handler; - - if (!handler) { - return; - } - - handler(exti_channels[exti].arg); - clear_pending_msk(1U << exti); -} - -/* Dispatch routine for EXTIs which share an IRQ. */ -static __always_inline void dispatch_extis(uint32 start, uint32 stop) { - uint32 pr = EXTI_BASE->PR; - uint32 handled_msk = 0; - uint32 exti; - - /* Dispatch user handlers for pending EXTIs. */ - for (exti = start; exti <= stop; exti++) { - uint32 eb = (1U << exti); - if (pr & eb) { - voidArgumentFuncPtr handler = exti_channels[exti].handler; - if (handler) { - handler(exti_channels[exti].arg); - handled_msk |= eb; - } - } - } - - /* Clear the pending bits for handled EXTIs. */ - clear_pending_msk(handled_msk); -} diff --git a/STM32F3/cores/maple/libmaple/exti_private.h b/STM32F3/cores/maple/libmaple/exti_private.h deleted file mode 100644 index 221cae4..0000000 --- a/STM32F3/cores/maple/libmaple/exti_private.h +++ /dev/null @@ -1,34 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -*****************************************************************************/ - -#ifndef _LIBMAPLE_EXTI_PRIVATE_H_ -#define _LIBMAPLE_EXTI_PRIVATE_H_ - -#include - -void exti_do_select(__IO uint32 *exti_cr, exti_num num, exti_cfg port); - -#endif diff --git a/STM32F3/cores/maple/libmaple/flash.c b/STM32F3/cores/maple/libmaple/flash.c deleted file mode 100644 index c57bbbf..0000000 --- a/STM32F3/cores/maple/libmaple/flash.c +++ /dev/null @@ -1,55 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * Copyright (c) 2011, 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/flash.c - * @brief Flash management functions - */ - -#include -#include - -/** - * @brief Set flash wait states - * - * Note that not all wait states are available on every MCU. See the - * Flash programming manual for your MCU for restrictions on the - * allowed value of wait_states for a given system clock (SYSCLK) - * frequency. - * - * @param wait_states number of wait states (one of - * FLASH_WAIT_STATE_0, FLASH_WAIT_STATE_1, - * ..., FLASH_WAIT_STATE_7). - */ -void flash_set_latency(uint32 wait_states) { - uint32 val = FLASH_BASE->ACR; - - val &= ~FLASH_ACR_LATENCY; - val |= wait_states; - - FLASH_BASE->ACR = val; -} diff --git a/STM32F3/cores/maple/libmaple/gpio.c b/STM32F3/cores/maple/libmaple/gpio.c deleted file mode 100644 index 6e63d2f..0000000 --- a/STM32F3/cores/maple/libmaple/gpio.c +++ /dev/null @@ -1,50 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * Copyright (c) 2011, 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/gpio.c - * @brief Generic STM32 GPIO support. - */ - -#include -#include - -/* - * GPIO routines - */ - -/** - * Initialize a GPIO device. - * - * Enables the clock for and resets the given device. - * - * @param dev GPIO device to initialize. - */ -void gpio_init(gpio_dev *dev) { - rcc_clk_enable(dev->clk_id); - rcc_reset_dev(dev->clk_id); -} diff --git a/STM32F3/cores/maple/libmaple/i2c.c b/STM32F3/cores/maple/libmaple/i2c.c deleted file mode 100644 index 87b96d1..0000000 --- a/STM32F3/cores/maple/libmaple/i2c.c +++ /dev/null @@ -1,52 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * Copyright (c) 2012 LeafLabs, LLC. - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/i2c.c - * @author Perry Hung , - * F3-port by Hanspeter Portner - * @brief Inter-Integrated Circuit (I2C) support. - * - * Currently, only master mode is supported. - */ - -#include "i2c_private.h" - -#include -#include -#include -#include -#include -#include - -#include - -void i2c_init(i2c_dev *dev) { - rcc_reset_dev(dev->clk_id); - rcc_clk_enable(dev->clk_id); -} diff --git a/STM32F3/cores/maple/libmaple/i2c_private.h b/STM32F3/cores/maple/libmaple/i2c_private.h deleted file mode 100644 index 4857955..0000000 --- a/STM32F3/cores/maple/libmaple/i2c_private.h +++ /dev/null @@ -1,75 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -#ifndef _LIBMAPLE_I2C_PRIVATE_H_ -#define _LIBMAPLE_I2C_PRIVATE_H_ - -#include - -/* For old-style definitions (SDA/SCL on same GPIO device) */ -#define I2C_DEV_OLD(num, port, sda, scl) \ - { \ - .regs = I2C##num##_BASE, \ - .gpio_port = port, \ - .scl_port = NULL, \ - .sda_port = NULL, \ - .sda_pin = sda, \ - .scl_pin = scl, \ - .clk_id = RCC_I2C##num, \ - .ev_nvic_line = NVIC_I2C##num##_EV, \ - .er_nvic_line = NVIC_I2C##num##_ER, \ - .state = I2C_STATE_DISABLED, \ - } - -/* For new-style definitions (SDA/SCL may be on different GPIO devices) */ -#define I2C_DEV_NEW(num, sdaport, sdabit, sclport, sclbit) \ - { \ - .regs = I2C##num##_BASE, \ - .gpio_port = NULL, \ - .scl_port = sclport, \ - .scl_pin = sclbit, \ - .sda_port = sdaport, \ - .sda_pin = sdabit, \ - .clk_id = RCC_I2C##num, \ - .ev_nvic_line = NVIC_I2C##num##_EV, \ - .er_nvic_line = NVIC_I2C##num##_ER, \ - .state = I2C_STATE_DISABLED, \ - } - -void _i2c_irq_handler(i2c_dev *dev); -void _i2c_irq_error_handler(i2c_dev *dev); - -struct gpio_dev; - -static inline struct gpio_dev* scl_port(const i2c_dev *dev) { - return (dev->gpio_port == NULL) ? dev->scl_port : dev->gpio_port; -} - -static inline struct gpio_dev* sda_port(const i2c_dev *dev) { - return (dev->gpio_port == NULL) ? dev->sda_port : dev->gpio_port; -} - -#endif /* _LIBMAPLE_I2C_PRIVATE_H_ */ diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/adc.h b/STM32F3/cores/maple/libmaple/include/libmaple/adc.h deleted file mode 100644 index e2d711d..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/adc.h +++ /dev/null @@ -1,319 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2012 LeafLabs, LLC. - * Copyright (c) 2010 Perry Hung. - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/include/libmaple/adc.h - * @author Marti Bolivar , - * Perry Hung , - * F3-port by Hanspeter Portner - * @brief Analog-to-Digital Conversion (ADC) header. - */ - -#ifndef _LIBMAPLE_ADC_H_ -#define _LIBMAPLE_ADC_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -#include -#include -#include - -/** - * TODO document - */ -typedef struct adc_callback_data { - uint32 irq_flags; - void *arg; -} adc_callback_data; - -/** - * TODO document - */ -typedef struct adc_private_data { - void (*handler)(adc_callback_data*); - uint32 handler_flags; - adc_callback_data cb_data; -} adc_private_data; - -/* Pull in the series header - * - * IMPORTANT: The series header must define the following: - * - * - enum adc_extsel_event (and typedef to adc_extsel_event): One per - * external event used to trigger start of conversion of a regular - * group. If two different series support the same event as a - * trigger, they must use the same token for the enumerator for that - * event. (The value of the enumerator is of course allowed to be - * different). - * - * - enum adc_smp_rate (and typedef to adc_smp_rate): One per - * available sampling time. These must be in the form ADC_SMPR_X_Y - * for X.Y cycles (e.g. ADC_SMPR_1_5 means 1.5 cycles), or - * ADC_SMPR_X for X cycles (e.g. ADC_SMPR_3 means 3 cycles). - * - * - enum adc_prescaler (and typedef): One per available prescaler, - * suitable for adc_set_prescaler. Series which have the same - * prescaler dividers (e.g. STM32F1 and STM32F2 both divide PCLK2 by - * 2, 4, 6, or 8) must provide the same tokens as enumerators, for - * portability. - */ - -#include - -/* - * Routines - */ - -extern void adc_init(const adc_dev *dev); - -/** - * @brief Set external event select for regular group - * @param dev ADC device - * @param event Event used to trigger the start of conversion. - * @see adc_extsel_event - */ -extern void adc_set_extsel(const adc_dev *dev, adc_extsel_event event); - -/** - * @brief Set the sample rate for all channels on an ADC device. - * - * Don't call this during conversion. - * - * @param dev adc device - * @param smp_rate sample rate to set - * @see adc_smp_rate - */ -extern void adc_set_sample_rate(const adc_dev *dev, adc_smp_rate smp_rate); - -/** - * @brief Enable scan mode for an ADC. - * - * In scan mode, the ADC converts all channels in a regular or - * injected sequence. After each conversion is done, the ADC - * automatically starts converting the next channel in the sequence. - * - * Scan mode is disabled by default. - * - * @see adc_disable_scan() - */ -extern void adc_enable_scan(const adc_dev *dev); - -/** - * @brief Disable scan mode for an ADC. - * - * This is the default setting. - * - * @see adc_enable_scan() - */ -extern void adc_disable_scan(const adc_dev *dev); - -/** - * @brief Enable continuous mode for an ADC. - * - * In this mode, the ADC will automatically perform conversions - * continuously until taken out of this mode or disabled. - * - * Continuous mode is disabled by default. - * - * @see adc_disable_continuous() - */ -extern void adc_enable_continuous(const adc_dev *dev); - -/** - * @brief Disable continuous mode for an ADC. - * - * This is the default setting. - * - * @see adc_enable_continuous() - */ -extern void adc_disable_continuous(const adc_dev *dev); - -/** - * @brief Set the sequence of channels to convert. - * - * This sets the (regular) sequence of up to 16 channels to convert. - * - * @param dev ADC device - * @param channels ADC channels to convert; these can repeat and may - * be in any order. - * @param len Length of `channels', from 1 to 16. - * @see adc_start_conv() - */ -extern void adc_set_conv_seq(const adc_dev *dev, const uint8 *channels, uint8 len); - -/** - * @brief Attach an interrupt handler and enable its interrupts. - * - * This function sets `handler' as the function to be called when any - * ADC interrupts for `dev' occur. At most one ADC interrupt handler - * may be attached at any time. Subsequent calls to this function will - * overwrite any previously attached handler. - * - * When `handler' is called, its argument will point to a struct - * adc_callback_data. The .irq_flags field in this struct will be a - * logical OR of adc_interrupt_id values encoding the reason(s) for - * the call. Its .arg field will be the `arg' argument to this - * function. - * - * The interrupt bits set in the adc_callback_data's .irq_flags will - * always be a subset of those set in the `interrupt_flags' argument - * to this function. That is, interrupts not given here in the - * `interrupt_flags' argument will never cause `handler' to be - * called. This has the effect that any enabled ADC interrupts not - * specified in `interrupt_flags' will be ignored. - * - * This function additionally enables the ADC interrupts specified by - * `interrupt_flags'. - * - * @param dev ADC device whose interrupts to attach to. - * @param interrupt_flags Logical or of adc_interrupt_id values - * specifying interrupts to enable. - * @param handler Interrupt handler to call when any interrupt in - * interrupt_flags occurs. - * @param arg Value to store in .arg field of handler's callback data. - * @see enum adc_interrupt_id - * @see struct adc_callback_data - */ -extern void adc_attach_interrupt(const adc_dev *dev, uint32 interrupt_flags, - void (*handler)(adc_callback_data*), void *arg); - -/** - * @brief Disable ADC interrupts and detach interrupt handlers. - * - * This function disables all interrupts for `dev', and unsets any - * handler attached with adc_attach_interrupt(). - * - * @param dev ADC device whose handler to detach. - */ -extern void adc_detach_interrupt(const adc_dev *dev); - -/** - * @brief Enable ADC interrupts - * @param dev ADC device - * @param interrupt_flags Logical or of adc_interrupt_id values to enable. - * @see adc_disable_interrupt() - * @see adc_attach_interrupt() - */ -extern void adc_enable_interrupts(const adc_dev *dev, uint32 interrupt_flags); - -/** - * @brief Disable ADC interrupts. - * @param dev ADC device - * @param interrupt_flags Logical or of adc_interrupt_id values to disable. - * @brief adc_enable_interrupt() - */ -extern void adc_disable_interrupts(const adc_dev *dev, uint32 interrupt_flags); - -/** - * @brief Perform a single synchronous software triggered conversion on a - * channel. - * @param dev ADC device to use for reading. - * @param channel channel to convert - * @return conversion result - */ -extern uint16 adc_read(const adc_dev *dev, uint8 channel); - -/** - * @brief Set the ADC prescaler. - * - * This determines the ADC clock for all devices. - */ -extern void adc_set_prescaler(adc_prescaler pre); - -/** - * @brief Call a function on all ADC devices. - * @param fn Function to call on each ADC device. - */ -extern void adc_foreach(void (*fn)(const adc_dev*)); - -struct gpio_dev; -/** - * @brief Configure a GPIO pin for ADC conversion. - * @param dev ADC device to use for conversion (currently ignored on - * all targets). - * @param gdev GPIO device to configure. - * @param bit Bit on gdev to configure for ADC conversion. - */ -extern void adc_config_gpio(const struct adc_dev *dev, - struct gpio_dev *gdev, - uint8 bit); - -/** - * @brief Enable an ADC and configure it for single conversion mode. - * - * This function performs any initialization necessary to allow the - * ADC device to perform a single synchronous regular software - * triggered conversion, using adc_read(). - * - * @param dev Device to enable. - * @see adc_read() - */ -extern void adc_enable_single_swstart(const adc_dev* dev); - -/** - * @brief Set the regular channel sequence length. - * - * Defines the total number of conversions in the regular channel - * conversion sequence. - * - * @param dev ADC device. - * @param length Regular channel sequence length, from 1 to 16. - */ -extern void adc_set_reg_seqlen(const adc_dev *dev, uint8 length); - -/** - * @brief Enable an adc peripheral - * @param dev ADC device to enable - */ -extern void adc_enable(const adc_dev *dev); - -/** - * @brief Disable an ADC peripheral - * @param dev ADC device to disable - */ -extern void adc_disable(const adc_dev *dev); - -/** - * @brief Disable all ADC peripherals. - */ -static inline void adc_disable_all(void) { - adc_foreach(adc_disable); -} - -/* - * private - */ -extern void _adc_enable_dev_irq(const adc_dev *dev); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/bitband.h b/STM32F3/cores/maple/libmaple/include/libmaple/bitband.h deleted file mode 100644 index 6e77991..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/bitband.h +++ /dev/null @@ -1,128 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2011 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/include/libmaple/bitband.h - * - * @brief Bit-banding utility functions - */ - -#ifndef _LIBMAPLE_BITBAND_H_ -#define _LIBMAPLE_BITBAND_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#define BB_SRAM_REF 0x20000000 -#define BB_SRAM_BASE 0x22000000 -#define BB_PERI_REF 0x40000000 -#define BB_PERI_BASE 0x42000000 - -static inline volatile uint32* __bb_addr(volatile void*, - uint32, - uint32, - uint32); - -/** - * @brief Obtain a pointer to the bit-band address corresponding to a - * bit in a volatile SRAM address. - * @param address Address in the bit-banded SRAM region - * @param bit Bit in address to bit-band - */ -static inline volatile uint32* bb_sramp(volatile void *address, uint32 bit) { - return __bb_addr(address, bit, BB_SRAM_BASE, BB_SRAM_REF); -} - -/** - * @brief Get a bit from an address in the SRAM bit-band region. - * @param address Address in the SRAM bit-band region to read from - * @param bit Bit in address to read - * @return bit's value in address. - */ -static inline uint8 bb_sram_get_bit(volatile void *address, uint32 bit) { - return *bb_sramp(address, bit); -} - -/** - * @brief Set a bit in an address in the SRAM bit-band region. - * @param address Address in the SRAM bit-band region to write to - * @param bit Bit in address to write to - * @param val Value to write for bit, either 0 or 1. - */ -static inline void bb_sram_set_bit(volatile void *address, - uint32 bit, - uint8 val) { - *bb_sramp(address, bit) = val; -} - -/** - * @brief Obtain a pointer to the bit-band address corresponding to a - * bit in a peripheral address. - * @param address Address in the bit-banded peripheral region - * @param bit Bit in address to bit-band - */ -static inline volatile uint32* bb_perip(volatile void *address, uint32 bit) { - return __bb_addr(address, bit, BB_PERI_BASE, BB_PERI_REF); -} - -/** - * @brief Get a bit from an address in the peripheral bit-band region. - * @param address Address in the peripheral bit-band region to read from - * @param bit Bit in address to read - * @return bit's value in address. - */ -static inline uint8 bb_peri_get_bit(volatile void *address, uint32 bit) { - return *bb_perip(address, bit); -} - -/** - * @brief Set a bit in an address in the peripheral bit-band region. - * @param address Address in the peripheral bit-band region to write to - * @param bit Bit in address to write to - * @param val Value to write for bit, either 0 or 1. - */ -static inline void bb_peri_set_bit(volatile void *address, - uint32 bit, - uint8 val) { - *bb_perip(address, bit) = val; -} - -static inline volatile uint32* __bb_addr(volatile void *address, - uint32 bit, - uint32 bb_base, - uint32 bb_ref) { - return (volatile uint32*)(bb_base + ((uint32)address - bb_ref) * 32 + - bit * 4); -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/bkp.h b/STM32F3/cores/maple/libmaple/include/libmaple/bkp.h deleted file mode 100644 index 9b00470..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/bkp.h +++ /dev/null @@ -1,100 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 LeafLabs, LLC. - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/include/libmaple/bkp.h - * @author F3-port by Hanspeter Portner - * @brief Backup register support (STM32F1 & STM32F3 only). - */ - -#ifndef _LIBMAPLE_BKP_H_ -#define _LIBMAPLE_BKP_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#include - -/** Backup peripheral device type. */ -typedef struct bkp_dev { - bkp_reg_map *regs; /**< Register map */ -} bkp_dev; - -extern const struct bkp_dev *BKP; - -/* - * this function needs to be implemented for each series separately - */ -extern inline __IO uint32* bkp_data_register(uint8 reg); - -/** - * @brief Initialize backup interface. - * - * Enables the power and backup interface clocks, and resets the - * backup device. - */ -void bkp_init(void); - -/** - * Enable write access to the backup registers. Backup interface must - * be initialized for subsequent register writes to work. - * @see bkp_init() - */ -void bkp_enable_writes(void); - -/** - * Disable write access to the backup registers. - */ -void bkp_disable_writes(void); - -/** - * Read a value from given backup data register. - * @param reg Data register to read, from 1 to BKP_NR_DATA_REGS (10 on - * medium-density devices, 42 on high-density devices). - */ -uint16 bkp_read(uint8 reg); - -/** - * @brief Write a value to given data register. - * - * Write access to backup registers must be enabled. - * - * @param reg Data register to write, from 1 to BKP_NR_DATA_REGS (10 - * on medium-density devices, 42 on high-density devices). - * @param val Value to write into the register. - * @see bkp_enable_writes() - */ -void bkp_write(uint8 reg, uint16 val); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/comp.h b/STM32F3/cores/maple/libmaple/include/libmaple/comp.h deleted file mode 100644 index 508ba63..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/comp.h +++ /dev/null @@ -1,46 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -*****************************************************************************/ - -/** - * @file libmaple/include/libmaple/fpu.h - * @author F3-port by Hanspeter Portner - * @brief Floating Point Unit (COMP) interace. - */ - -#ifndef _LIBMAPLE_COMP_H_ -#define _LIBMAPLE_COMP_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -#include - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/dac.h b/STM32F3/cores/maple/libmaple/include/libmaple/dac.h deleted file mode 100644 index 56bfdc4..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/dac.h +++ /dev/null @@ -1,158 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2011, 2012 LeafLabs, LLC. - * Copyright (c) 2010 Bryan Newbold. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/include/libmaple/dac.h - * @brief Digital to analog converter support. - */ - -/* See notes/dac.txt for more info */ - -#ifndef _LIBMAPLE_DAC_H_ -#define _LIBMAPLE_DAC_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -#include -#include -#include -#include - -/* - * Register map base and device pointers. - * - * The DACs are the same on all supported targets, so it's not worth - * repeating these in the series headers. - */ - -#define DAC_BASE ((struct dac_reg_map*)0x40007400) - -/** DAC device type. */ -typedef struct dac_dev { - dac_reg_map *regs; /**< Register map */ -} dac_dev; - -#if STM32_HAVE_DAC -extern const dac_dev *DAC; -#endif - -/* - * Register bit definitions - */ - -/* Control register */ - -/* Channel 1 control */ -#define DAC_CR_EN1 (1U << 0) /* Enable */ -#define DAC_CR_BOFF1 (1U << 1) /* Output buffer disable */ -#define DAC_CR_TEN1 (1U << 2) /* Trigger enable */ -#define DAC_CR_TSEL1 (0x7 << 3) /* Trigger selection */ -#define DAC_CR_WAVE1 (0x3 << 6) /* Noise/triangle wave */ -#define DAC_CR_MAMP1 (0xF << 8) /* Mask/amplitude selector */ -#define DAC_CR_DMAEN1 (1U << 12) /* DMA enable */ -/* Channel 2 control */ -#define DAC_CR_EN2 (1U << 16) /* Enable */ -#define DAC_CR_BOFF2 (1U << 17) /* Output buffer disable */ -#define DAC_CR_TEN2 (1U << 18) /* Trigger enable */ -#define DAC_CR_TSEL2 (0x7 << 19) /* Trigger selection */ -#define DAC_CR_WAVE2 (0x3 << 22) /* Noise/triangle wave */ -#define DAC_CR_MAMP2 (0xF << 24) /* Mask/amplitude selector */ -#define DAC_CR_DMAEN2 (1U << 28) /* DMA enable */ - -/* Software trigger register */ - -#define DAC_SWTRIGR_SWTRIG1 (1U << 0) /* Channel 1 software trigger */ -#define DAC_SWTRIGR_SWTRIG2 (1U << 1) /* Channel 2 software trigger */ - -/* Channel 1 12-bit right-aligned data holding register */ - -#define DAC_DHR12R1_DACC1DHR 0x00000FFF - -/* Channel 1 12-bit left-aligned data holding register */ - -#define DAC_DHR12L1_DACC1DHR 0x0000FFF0 - -/* Channel 1 8-bit left-aligned data holding register */ - -#define DAC_DHR8R1_DACC1DHR 0x000000FF - -/* Channel 2 12-bit right-aligned data holding register */ - -#define DAC_DHR12R2_DACC2DHR 0x00000FFF - -/* Channel 2 12-bit left-aligned data holding register */ - -#define DAC_DHR12L2_DACC2DHR 0x0000FFF0 - -/* Channel 2 8-bit left-aligned data holding register */ - -#define DAC_DHR8R2_DACC2DHR 0x000000FF - -/* Dual DAC 12-bit right-aligned data holding register */ - -#define DAC_DHR12RD_DACC1DHR 0x00000FFF -#define DAC_DHR12RD_DACC2DHR 0x0FFF0000 - -/* Dual DAC 12-bit left-aligned data holding register */ - -#define DAC_DHR12LD_DACC1DHR 0x0000FFF0 -#define DAC_DHR12LD_DACC2DHR 0xFFF00000 - -/* Dual DAC 8-bit left-aligned data holding register */ - -#define DAC_DHR8RD_DACC1DHR 0x000000FF -#define DAC_DHR8RD_DACC2DHR 0x0000FF00 - -/* Channel 1 data output register */ - -#define DAC_DOR1_DACC1DOR 0x00000FFF - -/* Channel 1 data output register */ - -#define DAC_DOR2_DACC2DOR 0x00000FFF - -/* - * Routines - */ - -/* We take the dev argument in these for future-proofing */ - -#define DAC_CH1 0x1 -#define DAC_CH2 0x2 -void dac_init(const dac_dev *dev, uint32 flags); - -void dac_write_channel(const dac_dev *dev, uint8 channel, uint16 val); -void dac_enable_channel(const dac_dev *dev, uint8 channel); -void dac_disable_channel(const dac_dev *dev, uint8 channel); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/delay.h b/STM32F3/cores/maple/libmaple/include/libmaple/delay.h deleted file mode 100644 index 472a208..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/delay.h +++ /dev/null @@ -1,65 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * Copyright (c) 2011 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/include/libmaple/delay.h - * @brief Delay implementation - */ - -#ifndef _LIBMAPLE_DELAY_H_ -#define _LIBMAPLE_DELAY_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -/** - * @brief Delay the given number of microseconds. - * - * @param us Number of microseconds to delay. - */ -static inline void delay_us(uint32 us) { - us *= STM32_DELAY_US_MULT; - - /* fudge for function call overhead */ - us--; - asm volatile(" mov r0, %[us] \n\t" - "1: subs r0, #1 \n\t" - " bhi 1b \n\t" - : - : [us] "r" (us) - : "r0"); -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/dma.h b/STM32F3/cores/maple/libmaple/include/libmaple/dma.h deleted file mode 100644 index 329e907..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/dma.h +++ /dev/null @@ -1,444 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Michael Hope. - * Copyright (c) 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/include/libmaple/dma.h - * - * @author Marti Bolivar ; - * Original implementation by Michael Hope - * - * @brief Direct Memory Access peripheral support - */ - -#ifndef _LIBMAPLE_DMA_H_ -#define _LIBMAPLE_DMA_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -/* provides: - * - * - An opaque dma_tube type, and predefined rvalues for each tube - * supported by the series. - * - * A "DMA tube" is a series-specific (hopefully integer) datatype - * that abstracts the conduit through which DMA-ed data flow. - * - * Examples: On STM32F1, dma_tube is just an alias for dma_channel, - * and the tube values are just DMA_CH1 (=1), DMA_CH2 (=2), etc. - * - * Note that a dma_tube doesn't have to be an enum, and its values - * don't have to be integral. They _do_ need to be cheap to pass as - * arguments, though. - * - * - struct dma_tube_reg_map (and typedef to dma_tube_reg_map). DMA - * register maps tend to be split into global registers and per-tube - * registers. It's convenient to pass around pointers to a tube's - * registers, since that makes it possible to configure or otherwise - * mess with a tube without knowing which one you're dealing with. - * - * - Base pointers to the various dma_tube_reg_maps. - * - * Examples: On STM32F1, these are DMAxCHy_BASE. You can access - * registers like DMAxCHy_BASE->CPAR, etc. - * - * - enum dma_request_src (and typedef to dma_request_src). This - * specifies the peripheral DMA request sources (e.g. USART TX DMA - * requests, etc.). - * - * - enum dma_mode_flags (and typedef to dma_mode_flags). Used in - * dma_tube_config. If two series both support the same mode flags, - * they must use the same enumerator names for those flags (the - * values of those enumerators are of course allowed to differ). - * - * - Normal stuff: dma_reg_map and base pointers, register bit - * definitions, dma_dev pointer declarations, and any other - * convenience functions useful for the series. */ -#include -/* buys us dma_dev and other necessities. */ -#include -#include - -/* - * Declarations/documentation for some of the series-provided types. - */ - -/** - * @brief (Series-dependent) DMA request sources. - * - * These specify the various pieces of peripheral functionality which - * may make DMA requests. Use them to set up a DMA transfer (see - * struct dma_tube_config, dma_tube_cfg()). - */ -enum dma_request_src; - -/** - * @brief (Series-dependent) DMA tube configuration flags. - * These specify miscellaneous bits of configuration for a DMA tube. - * @see struct dma_mode_config - */ -enum dma_cfg_flags; - -/** - * @brief (Series-dependent) DMA tube register map type. - * This allows you to access a tube's registers as a group. - * @see dma_tube_regs() - */ -struct dma_tube_reg_map; - -/* - * Convenience functions - */ - -/* Initialization */ - -void dma_init(dma_dev *dev); - -/* dma_tube configuration - * - * Use these types and functions to set up DMA transfers, handle - * interrupts, etc. The main function of interest is dma_tube_cfg(), - * which the various series implement separately. */ - -/** - * @brief Specifies a DMA tube configuration. - * - * Use one of these to set up a DMA transfer by passing it to - * dma_tube_cfg(). - * - * @see dma_tube_cfg() - * @see dma_xfer_size - */ -typedef struct dma_tube_config { - /** Source of data */ - __IO void *tube_src; - /** Source transfer size */ - dma_xfer_size tube_src_size; - - /** Destination of data */ - __IO void *tube_dst; - /** Destination transfer size */ - dma_xfer_size tube_dst_size; - - /** - * Number of data to transfer (0 to 65,535). - * - * Note that this is NOT measured in bytes; it's measured in - * number of data, which occur in multiples of tube_src_size. For - * example, if tube_src_size is DMA_SIZE_32BITS and tube_nr_xfers - * is 2, then 8 total bytes will be transferred. - */ - unsigned tube_nr_xfers; - - /** - * Target-specific configuration flags. - * - * These are an OR of series-specific enum dma_mode_flags values. - * Consult the documentation for your target for what flags you - * can use here. - * - * Typical flag examples: DMA_CFG_SRC_INC, DMA_CFG_DST_INC, - * DMA_CFG_CIRC, DMA_CFG_CMPLT_IE, etc. - */ - unsigned tube_flags; - - /** - * Currently unused. You must set this to 0 or something valid for - * your target. */ - void *target_data; - - /** - * Hardware DMA request source. - * - * This is ignored for memory-to-memory transfers. - */ - enum dma_request_src tube_req_src; -} dma_tube_config; - -#define DMA_TUBE_CFG_SUCCESS 0 -#define DMA_TUBE_CFG_EREQ 1 -#define DMA_TUBE_CFG_ENDATA 2 -#define DMA_TUBE_CFG_EDEV 3 -#define DMA_TUBE_CFG_ESRC 4 -#define DMA_TUBE_CFG_EDST 5 -#define DMA_TUBE_CFG_EDIR 6 -#define DMA_TUBE_CFG_ESIZE 7 -#define DMA_TUBE_CFG_ECFG 0xFF -/** - * @brief Configure a DMA tube. - * - * Use this function to set up a DMA transfer. The tube will be - * disabled before being reconfigured. The transfer will have low - * priority by default. You can choose another priority before the - * transfer begins using dma_set_priority(). You can manage your - * interrupt handlers for the tube using dma_attach_interrupt() and - * dma_detach_interrupt(). - * - * After calling dma_tube_cfg() and performing any other desired - * configuration, start the transfer using dma_enable(). - * - * @param dev DMA device. - * @param tube DMA tube to configure. - * @param cfg Configuration to apply to tube. - * - * @return DMA_TUBE_CFG_SUCCESS (0) on success, <0 on failure. On - * failure, returned value will be the opposite (-) of one of: - * - * - DMA_TUBE_CFG_EREQ: tube doesn't work with cfg->tube_req_src - * - DMA_TUBE_CFG_ENDATA: cfg->tube_[src,dst]_size are - * incompatible with cfg->tube_nr_xfers, or cfg->tube_nr_xfers - * is out of bounds. - * - DMA_TUBE_CFG_EDEV: dev does not support cfg - * - DMA_TUBE_CFG_ESRC: bad cfg->tube_src - * - DMA_TUBE_CFG_EDST: bad cfg->tube_dst - * - DMA_TUBE_CFG_EDIR: dev can't transfer from cfg->tube_src to - * cfg->tube_dst - * - DMA_TUBE_CFG_ESIZE: something ended up wrong due to MSIZE/PSIZE - * - DMA_TUBE_CFG_ECFG: generic "something's wrong" - * - * @sideeffect Disables tube. May alter tube's registers even when an - * error occurs. - * @see struct dma_tube_config - * @see dma_attach_interrupt() - * @see dma_detach_interrupt() - * @see dma_enable() - */ -extern int dma_tube_cfg(dma_dev *dev, dma_tube tube, dma_tube_config *cfg); - -/* Other tube configuration functions. You can use these if - * dma_tube_cfg() isn't enough, or to adjust parts of an existing tube - * configuration. */ - -/** DMA transfer priority. */ -typedef enum dma_priority { - DMA_PRIORITY_LOW = 0, /**< Low priority */ - DMA_PRIORITY_MEDIUM = 1, /**< Medium priority */ - DMA_PRIORITY_HIGH = 2, /**< High priority */ - DMA_PRIORITY_VERY_HIGH = 3, /**< Very high priority */ -} dma_priority; - -/** - * @brief Set the priority of a DMA transfer. - * - * You may not call this function while the tube is enabled. - * - * @param dev DMA device - * @param tube DMA tube - * @param priority priority to set. - */ -extern void dma_set_priority(dma_dev *dev, dma_tube tube, - dma_priority priority); - -/** - * @brief Set the number of data transfers on a DMA tube. - * - * You may not call this function while the tube is enabled. - * - * @param dev DMA device - * @param tube Tube through which the transfer will occur. - * @param num_transfers Number of DMA transactions to set. - */ -extern void dma_set_num_transfers(dma_dev *dev, dma_tube tube, - uint16 num_transfers); - -/** - * @brief Set the base memory address where data will be read from or - * written to. - * - * You must not call this function while the tube is enabled. - * - * If the DMA memory size is 16 bits, the address is automatically - * aligned to a half-word. If the DMA memory size is 32 bits, the - * address is aligned to a word. - * - * @param dev DMA Device - * @param tube Tube whose base memory address to set. - * @param address Memory base address to use. - */ -extern void dma_set_mem_addr(dma_dev *dev, dma_tube tube, __IO void *address); - -/** - * @brief Set the base peripheral address where data will be read from - * or written to. - * - * You must not call this function while the channel is enabled. - * - * If the DMA peripheral size is 16 bits, the address is automatically - * aligned to a half-word. If the DMA peripheral size is 32 bits, the - * address is aligned to a word. - * - * @param dev DMA Device - * @param tube Tube whose peripheral data register base address to set. - * @param address Peripheral memory base address to use. - */ -extern void dma_set_per_addr(dma_dev *dev, dma_tube tube, __IO void *address); - -/* Interrupt handling */ - -/** - * @brief Attach an interrupt to a DMA transfer. - * - * Interrupts are enabled using series-specific mode flags in - * dma_tube_cfg(). - * - * @param dev DMA device - * @param tube Tube to attach handler to - * @param handler Interrupt handler to call when tube interrupt fires. - * @see dma_tube_cfg() - * @see dma_get_irq_cause() - * @see dma_detach_interrupt() - */ -extern void dma_attach_interrupt(dma_dev *dev, dma_tube tube, - void (*handler)(void)); - - -/** - * @brief Detach a DMA transfer interrupt handler. - * - * After calling this function, the given tube's interrupts will be - * disabled. - * - * @param dev DMA device - * @param tube Tube whose handler to detach - * @sideeffect Clears the tube's interrupt enable bits. - * @see dma_attach_interrupt() - */ -extern void dma_detach_interrupt(dma_dev *dev, dma_tube tube); - -/* Tube enable/disable */ - -/** - * @brief Enable a DMA tube. - * - * If the tube has been properly configured, calling this function - * allows it to start serving DMA requests. - * - * @param dev DMA device - * @param tube Tube to enable - * @see dma_tube_cfg() - */ -extern void dma_enable(dma_dev *dev, dma_tube tube); - -/** - * @brief Disable a DMA channel. - * - * Calling this function makes the tube stop serving DMA requests. - * - * @param dev DMA device - * @param tube Tube to disable - */ -extern void dma_disable(dma_dev *dev, dma_tube tube); - -/** - * @brief Check if a DMA tube is enabled. - * @param dev DMA device. - * @param tube Tube to check. - * @return 0 if the tube is disabled, >0 if it is enabled. - */ -static inline uint8 dma_is_enabled(dma_dev *dev, dma_tube tube); - -/* Other conveniences */ - -/** - * @brief Obtain a pointer to an individual DMA tube's registers. - * - * Examples: - * - * - On STM32F1, dma_channel_regs(DMA1, DMA_CH1)->CCR is DMA1_BASE->CCR1. - * - * @param dev DMA device. - * @param tube DMA tube whose register map to obtain. - * @return (Series-specific) tube register map. - */ -static inline dma_tube_reg_map* dma_tube_regs(dma_dev *dev, dma_tube tube); - -/** - * Encodes the reason why a DMA interrupt was called. - * @see dma_get_irq_cause() - */ -typedef enum dma_irq_cause { - DMA_TRANSFER_COMPLETE, /**< Transfer is complete. */ - DMA_TRANSFER_HALF_COMPLETE, /**< Transfer is half complete. */ - DMA_TRANSFER_ERROR, /**< Error occurred during transfer. */ - DMA_TRANSFER_DME_ERROR, /**< - * @brief Direct mode error occurred during - * transfer. */ - DMA_TRANSFER_FIFO_ERROR, /**< FIFO error occurred during transfer. */ -} dma_irq_cause; - -/** - * @brief Discover the reason why a DMA interrupt was called. - * - * You may only call this function within an attached interrupt - * handler for the given channel. - * - * This function resets the internal DMA register state which encodes - * the cause of the interrupt; consequently, it can only be called - * once per interrupt handler invocation. - * - * @param dev DMA device - * @param tube Tube whose interrupt is being handled. - * @return Reason why the interrupt fired. - * @sideeffect Clears flags in dev's interrupt status registers. - * @see dma_attach_interrupt() - * @see dma_irq_cause - */ -extern dma_irq_cause dma_get_irq_cause(dma_dev *dev, dma_tube tube); - -/** - * @brief Get the ISR status bits for a DMA channel. - * - * The bits are returned right-aligned, in the order they appear in - * the corresponding ISR register. - * - * If you're trying to figure out why a DMA interrupt fired, you may - * find dma_get_irq_cause() more convenient. - * - * @param dev DMA device - * @param tube Tube whose ISR bits to return. - * @see dma_get_irq_cause(). - */ -static inline uint8 dma_get_isr_bits(dma_dev *dev, dma_tube tube); - -/** - * @brief Clear the ISR status bits for a given DMA tube. - * - * If you're trying to clean up after yourself in a DMA interrupt, you - * may find dma_get_irq_cause() more convenient. - * - * @param dev DMA device - * @param tube Tube whose ISR bits to clear. - * @see dma_get_irq_cause() - */ -static inline void dma_clear_isr_bits(dma_dev *dev, dma_tube tube); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/dma_common.h b/STM32F3/cores/maple/libmaple/include/libmaple/dma_common.h deleted file mode 100644 index 3765cd5..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/dma_common.h +++ /dev/null @@ -1,112 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/include/libmaple/dma_common.h - * @author Marti Bolivar - * @brief Common DMA sub-header for and . - * - * CONTENTS UNSTABLE. The existence of this file is an implementation - * detail. Never include it directly. If you need something from - * here, include instead. - */ - -/* - * There's a fair amount of common DMA functionality needed by each - * and . This header exists in order - * to provide it to both, avoiding some hacks and circular - * dependencies. - */ - -#ifndef _LIBMAPLE_DMA_COMMON_H_ -#define _LIBMAPLE_DMA_COMMON_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -#include -#include -#include - -/* - * Devices - */ - -struct dma_reg_map; - -/* Encapsulates state related to user interrupt handlers. You - * shouldn't touch these directly; use dma_attach_interrupt() and - * dma_detach_interupt() instead. */ -typedef struct dma_handler_config { - void (*handler)(void); /* User handler */ - nvic_irq_num irq_line; /* IRQ line for interrupt */ -} dma_handler_config; - -/** DMA device type */ -typedef struct dma_dev { - struct dma_reg_map *regs; /**< Register map */ - rcc_clk_id clk_id; /**< Clock ID */ - struct dma_handler_config handlers[]; /**< For internal use */ -} dma_dev; - -/** - * @brief DMA channels - * - * Notes: - * - This is also the dma_tube type for STM32F1. - * - Channel 0 is not available on all STM32 series. - * - * @see dma_tube - */ -typedef enum dma_channel { - DMA_CH0 = 0, /**< Channel 0 */ - DMA_CH1 = 1, /**< Channel 1 */ - DMA_CH2 = 2, /**< Channel 2 */ - DMA_CH3 = 3, /**< Channel 3 */ - DMA_CH4 = 4, /**< Channel 4 */ - DMA_CH5 = 5, /**< Channel 5 */ - DMA_CH6 = 6, /**< Channel 6 */ - DMA_CH7 = 7, /**< Channel 7 */ -} dma_channel; - -/** - * @brief Source and destination transfer sizes. - * Use these when initializing a struct dma_tube_config. - * @see struct dma_tube_config - * @see dma_tube_cfg - */ -typedef enum dma_xfer_size { - DMA_SIZE_8BITS = 0, /**< 8-bit transfers */ - DMA_SIZE_16BITS = 1, /**< 16-bit transfers */ - DMA_SIZE_32BITS = 2, /**< 32-bit transfers */ -} dma_xfer_size; - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/dsp.h b/STM32F3/cores/maple/libmaple/include/libmaple/dsp.h deleted file mode 100644 index 435c801..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/dsp.h +++ /dev/null @@ -1,131 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -*****************************************************************************/ - -/** - * @file libmaple/include/libmaple/dsp.h - * @author F3-port by Hanspeter Portner - * @brief Convenience macros for the digital signal processing (DSP) - * instruction set of the ARM Cortex M4 microcontroller. - */ - -#ifndef _LIBMAPLE_DSP_H_ -#define _LIBMAPLE_DSP_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -#define DSP3(ID, A, B, C) \ -({ \ - uint32_t X; \ - asm volatile (ID" %[res], %[val1], %[val2], %[val3]" \ - : [res]"=r" (X) \ - : [val1]"r" (A), [val2]"r" (B), [val3]"r" (C) \ - ); \ - (uint32_t)X; \ -}) - -#define DSP2(ID, A, B) \ -({ \ - uint32_t X; \ - asm volatile (ID" %[res], %[val1], %[val2]" \ - : [res]"=r" (X) \ - : [val1]"r" (A), [val2]"r" (B) \ - );\ - (uint32_t)X; \ -}) - -#define DSP1(ID, A) \ -({ \ - uint32_t X; \ - asm volatile (ID" %[res], %[val1]" \ - : [res]"=r" (X) \ - : [val1]"r" (A) \ - ); \ - (uint32_t)X; \ -}) - -/* General data processing instructions */ -#define __rev16(A) DSP1("REV16", A) -//TODO - -/* Multiply and divide instructions */ -//TODO - -/* Saturating instructions */ -//TODO - -/* Packing and unpacking instructions */ -//TODO - -/* Bitfield instructions */ -//TODO - -/* Floating-point instructions */ -//TODO - -/* Miscellaneous instructions */ -//TODO - -/* SIMD instructions (single instruction multiple data) */ -#define __sadd16(A, B) DSP2("SADD16", A, B) -#define __shadd16(A, B) DSP2("SHADD16", A, B) -#define __ssub16(A, B) DSP2("SSUB16", A, B) -#define __shsub16(A, B) DSP2("SHSUB16", A, B) -#define __uadd16(A, B) DSP2("UADD16", A, B) -#define __uhadd16(A, B) DSP2("UHADD16", A, B) -#define __usub16(A, B) DSP2("USUB16", A, B) -#define __uhsub16(A, B) DSP2("UHSUB16", A, B) - -#define __sadd8(A, B) DSP2("SADD8", A, B) -#define __shadd8(A, B) DSP2("SHADD8", A, B) -#define __ssub8(A, B) DSP2("SSUB8", A, B) -#define __shsub8(A, B) DSP2("SHSUB8", A, B) -#define __uadd8(A, B) DSP2("UADD8", A, B) -#define __uhadd8(A, B) DSP2("UHADD8", A, B) -#define __usub8(A, B) DSP2("USUB8", A, B) -#define __uhsub8(A, B) DSP2("UHSUB8", A, B) - -#define __sasx(A, B) DSP2("SASX", A, B) -#define __ssax(A, B) DSP2("SSAX", A, B) -#define __shasx(A, B) DSP2("SHASX", A, B) -#define __shsax(A, B) DSP2("SHSAX", A, B) -#define __uasx(A, B) DSP2("UASX", A, B) -#define __usax(A, B) DSP2("USAX", A, B) -#define __uhasx(A, B) DSP2("UHASX", A, B) -#define __uhsax(A, B) DSP2("UHSAX", A, B) - -#define __usad8(A, B) DSP2("USAD8", A, B) -#define __usada8(A, B, C) DSP3("USADA8", A, B, C) - -/* MAC instructions (multiply and accumulate) */ -/* TODO */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/exti.h b/STM32F3/cores/maple/libmaple/include/libmaple/exti.h deleted file mode 100644 index 525cdc7..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/exti.h +++ /dev/null @@ -1,143 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/include/libmaple/exti.h - * @brief External interrupt control - */ - -/* See notes/exti.txt for more info */ - -#ifndef _LIBMAPLE_EXTI_H_ -#define _LIBMAPLE_EXTI_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -#include /* provides EXTI_BASE */ -#include - -/* - * Register map and base pointer. - */ - -/** EXTI register map type */ -typedef struct exti_reg_map { - __IO uint32 IMR; /**< Interrupt mask register */ - __IO uint32 EMR; /**< Event mask register */ - __IO uint32 RTSR; /**< Rising trigger selection register */ - __IO uint32 FTSR; /**< Falling trigger selection register */ - __IO uint32 SWIER; /**< Software interrupt event register */ - __IO uint32 PR; /**< Pending register */ -} exti_reg_map; - -/* - * Types: exti_num, exti_cfg, exti_trigger_mode. - * - * A combination of these three specifies an external interrupt - * configuration (see exti_attach_interrupt()). - */ - -/** EXTI line. */ -typedef enum exti_num { - EXTI0, /**< EXTI line 0 */ - EXTI1, /**< EXTI line 1 */ - EXTI2, /**< EXTI line 2 */ - EXTI3, /**< EXTI line 3 */ - EXTI4, /**< EXTI line 4 */ - EXTI5, /**< EXTI line 5 */ - EXTI6, /**< EXTI line 6 */ - EXTI7, /**< EXTI line 7 */ - EXTI8, /**< EXTI line 8 */ - EXTI9, /**< EXTI line 9 */ - EXTI10, /**< EXTI line 10 */ - EXTI11, /**< EXTI line 11 */ - EXTI12, /**< EXTI line 12 */ - EXTI13, /**< EXTI line 13 */ - EXTI14, /**< EXTI line 14 */ - EXTI15, /**< EXTI line 15 */ -} exti_num; - -/** - * @brief EXTI port configuration - * - * These specify which GPIO port an external interrupt line should be - * connected to. - */ -typedef enum exti_cfg { - EXTI_PA, /**< Use PAx pin */ - EXTI_PB, /**< Use PBx pin */ - EXTI_PC, /**< Use PCx pin */ - EXTI_PD, /**< Use PDx pin */ - EXTI_PE, /**< Use PEx pin */ - EXTI_PF, /**< Use PFx pin */ - EXTI_PG, /**< Use PGx pin */ - EXTI_PH, /**< Use PHx pin */ - EXTI_PI, /**< Use PIx pin */ -} exti_cfg; - -/** External interrupt trigger mode */ -typedef enum exti_trigger_mode { - EXTI_RISING, /**< Trigger on the rising edge */ - EXTI_FALLING, /**< Trigger on the falling edge */ - EXTI_RISING_FALLING /**< Trigger on both the rising and falling edges */ -} exti_trigger_mode; - -/* - * Routines - */ - -void exti_attach_interrupt(exti_num num, - exti_cfg port, - voidFuncPtr handler, - exti_trigger_mode mode); -void exti_attach_callback(exti_num num, - exti_cfg port, - voidArgumentFuncPtr handler, - void *arg, - exti_trigger_mode mode); -void exti_detach_interrupt(exti_num num); - -/** - * @brief Set the GPIO port for an EXTI line. - * - * This is a low-level routine that most users will not - * need. exti_attach_interrupt() handles calling this function - * appropriately. - * - * @param num EXTI line - * @param port EXTI configuration for GPIO port to connect to num. - * @see exti_num - * @see exti_cfg - */ -extern void exti_select(exti_num num, exti_cfg port); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/flash.h b/STM32F3/cores/maple/libmaple/include/libmaple/flash.h deleted file mode 100644 index 943e466..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/flash.h +++ /dev/null @@ -1,106 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/include/libmaple/flash.h - * @brief Flash support. - */ - -#ifndef _LIBMAPLE_FLASH_H_ -#define _LIBMAPLE_FLASH_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -#include - -#define FLASH_WAIT_STATE_0 0x0 -#define FLASH_WAIT_STATE_1 0x1 -#define FLASH_WAIT_STATE_2 0x2 -#define FLASH_WAIT_STATE_3 0x3 -#define FLASH_WAIT_STATE_4 0x4 -#define FLASH_WAIT_STATE_5 0x5 -#define FLASH_WAIT_STATE_6 0x6 -#define FLASH_WAIT_STATE_7 0x7 - -/* The series header must define: - * - * - FLASH_SAFE_WAIT_STATES, the smallest number of wait states that - * it is safe to use when SYSCLK is at its fastest documented rate - * and the MCU is powered at 3.3V (i.e. this doesn't consider - * overclocking or low voltage operation). - * - * - The following bit flags, for flash_enable_features(): - * - * -- FLASH_PREFETCH: prefetcher - * -- FLASH_ICACHE: instruction cache - * -- FLASH_DCACHE: data cache - * - * See that function's Doxygen for more restrictions. - */ -#include - -#ifdef __DOXYGEN__ -/** Flash register map base pointer. */ -#define FLASH_BASE -#endif - -/* - * Flash routines - */ - -void flash_set_latency(uint32 wait_states); - -/** - * @brief Enable Flash memory features - * - * If the target MCU doesn't provide a feature (e.g. instruction and - * data caches on the STM32F1), the flag will be ignored. This allows - * using these flags unconditionally, with the desired effect taking - * place on targets that support them. - * - * @param feature_flags Bitwise OR of the following: - * FLASH_PREFETCH (turns on prefetcher), - * FLASH_ICACHE (turns on instruction cache), - * FLASH_DCACHE (turns on data cache). - */ -static inline void flash_enable_features(uint32 feature_flags) { - FLASH_BASE->ACR |= feature_flags; -} - -/** - * @brief Deprecated. Use flash_enable_features(FLASH_PREFETCH) instead. - */ -static inline void flash_enable_prefetch(void) { - flash_enable_features(FLASH_PREFETCH); -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/fpu.h b/STM32F3/cores/maple/libmaple/include/libmaple/fpu.h deleted file mode 100644 index f8e2037..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/fpu.h +++ /dev/null @@ -1,56 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -*****************************************************************************/ - -/** - * @file libmaple/include/libmaple/fpu.h - * @author F3-port by Hanspeter Portner - * @brief Floating Point Unit (FPU) interace. - */ - -#ifndef _LIBMAPLE_FPU_H_ -#define _LIBMAPLE_FPU_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -#include - -/** - * @brief Enable floating point unit. - */ -void fpu_enable(void); - -/** - * @brief Disable floating point unit. - */ -void fpu_disable(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/fsmc.h b/STM32F3/cores/maple/libmaple/include/libmaple/fsmc.h deleted file mode 100644 index 9dd8a72..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/fsmc.h +++ /dev/null @@ -1,340 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Bryan Newbold. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/include/libmaple/fsmc.h - * @brief Flexible static memory controller support. - */ - -/* - * See ../notes/fsmc.txt for more info - */ - -#ifndef _LIBMAPLE_FSMC_H_ -#define _LIBMAPLE_FSMC_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -#include -#include - -#if !STM32_HAVE_FSMC -#error "FSMC is unavailable on your MCU" -#endif - -/* - * Register maps and devices - */ - -/** FSMC register map type */ -typedef struct fsmc_reg_map { - __IO uint32 BCR1; /**< SRAM/NOR-Flash chip-select control register 1 */ - __IO uint32 BTR1; /**< SRAM/NOR-Flash chip-select timing register 1 */ - __IO uint32 BCR2; /**< SRAM/NOR-Flash chip-select control register 2 */ - __IO uint32 BTR2; /**< SRAM/NOR-Flash chip-select timing register 2 */ - __IO uint32 BCR3; /**< SRAM/NOR-Flash chip-select control register 3 */ - __IO uint32 BTR3; /**< SRAM/NOR-Flash chip-select timing register 3 */ - __IO uint32 BCR4; /**< SRAM/NOR-Flash chip-select control register 4 */ - __IO uint32 BTR4; /**< SRAM/NOR-Flash chip-select timing register 4 */ - const uint8 RESERVED1[64]; /**< Reserved */ - __IO uint32 PCR2; /**< PC Card/NAND Flash control register 2 */ - __IO uint32 SR2; /**< FIFO status and interrupt register 2 */ - __IO uint32 PMEM2; /**< Common memory space timing register 2 */ - __IO uint32 PATT2; /**< Attribute memory space timing register 2 */ - const uint8 RESERVED2[4]; /**< Reserved */ - __IO uint32 ECCR2; /**< ECC result register 2 */ - const uint8 RESERVED3[2]; - __IO uint32 PCR3; /**< PC Card/NAND Flash control register 3 */ - __IO uint32 SR3; /**< FIFO status and interrupt register 3 */ - __IO uint32 PMEM3; /**< Common memory space timing register 3 */ - __IO uint32 PATT3; /**< Attribute memory space timing register 3 */ - const uint32 RESERVED4; /**< Reserved */ - __IO uint32 ECCR3; /**< ECC result register 3 */ - const uint8 RESERVED5[8]; /**< Reserved */ - __IO uint32 PCR4; /**< PC Card/NAND Flash control register 4 */ - __IO uint32 SR4; /**< FIFO status and interrupt register 4 */ - __IO uint32 PMEM4; /**< Common memory space timing register 4 */ - __IO uint32 PATT4; /**< Attribute memory space timing register 4 */ - __IO uint32 PIO4; /**< I/O space timing register 4 */ - const uint8 RESERVED6[80]; /**< Reserved */ - __IO uint32 BWTR1; /**< SRAM/NOR-Flash write timing register 1 */ - const uint32 RESERVED7; /**< Reserved */ - __IO uint32 BWTR2; /**< SRAM/NOR-Flash write timing register 2 */ - const uint32 RESERVED8; /**< Reserved */ - __IO uint32 BWTR3; /**< SRAM/NOR-Flash write timing register 3 */ - const uint32 RESERVED9; /**< Reserved */ - __IO uint32 BWTR4; /**< SRAM/NOR-Flash write timing register 4 */ -} __attribute__((packed)) fsmc_reg_map; - -#define __FSMCB 0xA0000000 - -/** FSMC register map base pointer */ -#define FSMC_BASE ((struct fsmc_reg_map*)__FSMCB) - -/** FSMC NOR/PSRAM register map type */ -typedef struct fsmc_nor_psram_reg_map { - __IO uint32 BCR; /**< Chip-select control register */ - __IO uint32 BTR; /**< Chip-select timing register */ - const uint8 RESERVED[252]; /**< Reserved */ - __IO uint32 BWTR; /**< Write timing register */ -} fsmc_nor_psram_reg_map; - -/** FSMC NOR/PSRAM base pointer 1 */ -#define FSMC_NOR_PSRAM1_BASE ((struct fsmc_nor_psram_reg_map*)__FSMCB) - -/** FSMC NOR/PSRAM base pointer 2 */ -#define FSMC_NOR_PSRAM2_BASE ((struct fsmc_nor_psram_reg_map*)(__FSMCB + 0x8)) - -/** FSMC NOR/PSRAM base pointer 3 */ -#define FSMC_NOR_PSRAM3_BASE ((struct fsmc_nor_psram_reg_map*)(__FSMCB + 0x10)) - -/** FSMC NOR/PSRAM base pointer 4 */ -#define FSMC_NOR_PSRAM4_BASE ((struct fsmc_nor_psram_reg_map*)(__FSMCB + 0x18)) - -/* - * Register bit definitions - */ - -/* NOR/PSRAM chip-select control registers */ - -#define FSMC_BCR_CBURSTRW_BIT 19 -#define FSMC_BCR_ASYNCWAIT_BIT 15 -#define FSMC_BCR_EXTMOD_BIT 14 -#define FSMC_BCR_WAITEN_BIT 13 -#define FSMC_BCR_WREN_BIT 12 -#define FSMC_BCR_WAITCFG_BIT 11 -#define FSMC_BCR_WRAPMOD_BIT 10 -#define FSMC_BCR_WAITPOL_BIT 9 -#define FSMC_BCR_BURSTEN_BIT 8 -#define FSMC_BCR_FACCEN_BIT 6 -#define FSMC_BCR_MUXEN_BIT 1 -#define FSMC_BCR_MBKEN_BIT 0 - -#define FSMC_BCR_CBURSTRW (1U << FSMC_BCR_CBURSTRW_BIT) -#define FSMC_BCR_ASYNCWAIT (1U << FSMC_BCR_ASYNCWAIT_BIT) -#define FSMC_BCR_EXTMOD (1U << FSMC_BCR_EXTMOD_BIT) -#define FSMC_BCR_WAITEN (1U << FSMC_BCR_WAITEN_BIT) -#define FSMC_BCR_WREN (1U << FSMC_BCR_WREN_BIT) -#define FSMC_BCR_WAITCFG (1U << FSMC_BCR_WAITCFG_BIT) -#define FSMC_BCR_WRAPMOD (1U << FSMC_BCR_WRAPMOD_BIT) -#define FSMC_BCR_WAITPOL (1U << FSMC_BCR_WAITPOL_BIT) -#define FSMC_BCR_BURSTEN (1U << FSMC_BCR_BURSTEN_BIT) -#define FSMC_BCR_FACCEN (1U << FSMC_BCR_FACCEN_BIT) -#define FSMC_BCR_MWID (0x3 << 4) -#define FSMC_BCR_MWID_8BITS (0x0 << 4) -#define FSMC_BCR_MWID_16BITS (0x1 << 4) -#define FSMC_BCR_MTYP (0x3 << 2) -#define FSMC_BCR_MTYP_SRAM (0x0 << 2) -#define FSMC_BCR_MTYP_PSRAM (0x1 << 2) -#define FSMC_BCR_MTYP_NOR_FLASH (0x2 << 2) -#define FSMC_BCR_MUXEN (1U << FSMC_BCR_MUXEN_BIT) -#define FSMC_BCR_MBKEN (1U << FSMC_BCR_MBKEN_BIT) - -/* SRAM/NOR-Flash chip-select timing registers */ - -#define FSMC_BTR_ACCMOD (0x3 << 28) -#define FSMC_BTR_ACCMOD_A (0x0 << 28) -#define FSMC_BTR_ACCMOD_B (0x1 << 28) -#define FSMC_BTR_ACCMOD_C (0x2 << 28) -#define FSMC_BTR_ACCMOD_D (0x3 << 28) -#define FSMC_BTR_DATLAT (0xF << 24) -#define FSMC_BTR_CLKDIV (0xF << 20) -#define FSMC_BTR_BUSTURN (0xF << 16) -#define FSMC_BTR_DATAST (0xFF << 8) -#define FSMC_BTR_ADDHLD (0xF << 4) -#define FSMC_BTR_ADDSET 0xF - -/* SRAM/NOR-Flash write timing registers */ - -#define FSMC_BWTR_ACCMOD (0x3 << 28) -#define FSMC_BWTR_ACCMOD_A (0x0 << 28) -#define FSMC_BWTR_ACCMOD_B (0x1 << 28) -#define FSMC_BWTR_ACCMOD_C (0x2 << 28) -#define FSMC_BWTR_ACCMOD_D (0x3 << 28) -#define FSMC_BWTR_DATLAT (0xF << 24) -#define FSMC_BWTR_CLKDIV (0xF << 20) -#define FSMC_BWTR_DATAST (0xFF << 8) -#define FSMC_BWTR_ADDHLD (0xF << 4) -#define FSMC_BWTR_ADDSET 0xF - -/* NAND Flash/PC Card controller registers */ - -#define FSMC_PCR_ECCEN_BIT 6 -#define FSMC_PCR_PTYP_BIT 3 -#define FSMC_PCR_PBKEN_BIT 2 -#define FSMC_PCR_PWAITEN_BIT 1 - -#define FSMC_PCR_ECCPS (0x7 << 17) -#define FSMC_PCR_ECCPS_256B (0x0 << 17) -#define FSMC_PCR_ECCPS_512B (0x1 << 17) -#define FSMC_PCR_ECCPS_1024B (0x2 << 17) -#define FSMC_PCR_ECCPS_2048B (0x3 << 17) -#define FSMC_PCR_ECCPS_4096B (0x4 << 17) -#define FSMC_PCR_ECCPS_8192B (0x5 << 17) -#define FSMC_PCR_TAR (0xF << 13) -#define FSMC_PCR_TCLR (0xF << 9) -#define FSMC_PCR_ECCEN (1U << FSMC_PCR_ECCEN_BIT) -#define FSMC_PCR_PWID (0x3 << 4) -#define FSMC_PCR_PWID_8BITS (0x0 << 4) -#define FSMC_PCR_PWID_16BITS (0x1 << 4) -#define FSMC_PCR_PTYP (1U << FSMC_PCR_PTYP_BIT) -#define FSMC_PCR_PTYP_PC_CF_PCMCIA (0x0 << FSMC_PCR_PTYP_BIT) -#define FSMC_PCR_PTYP_NAND (0x1 << FSMC_PCR_PTYP_BIT) -#define FSMC_PCR_PBKEN (1U << FSMC_PCR_PBKEN_BIT) -#define FSMC_PCR_PWAITEN (1U << FSMC_PCR_PWAITEN_BIT) - -/* FIFO status and interrupt registers */ - -#define FSMC_SR_FEMPT_BIT 6 -#define FSMC_SR_IFEN_BIT 5 -#define FSMC_SR_ILEN_BIT 4 -#define FSMC_SR_IREN_BIT 3 -#define FSMC_SR_IFS_BIT 2 -#define FSMC_SR_ILS_BIT 1 -#define FSMC_SR_IRS_BIT 0 - -#define FSMC_SR_FEMPT (1U << FSMC_SR_FEMPT_BIT) -#define FSMC_SR_IFEN (1U << FSMC_SR_IFEN_BIT) -#define FSMC_SR_ILEN (1U << FSMC_SR_ILEN_BIT) -#define FSMC_SR_IREN (1U << FSMC_SR_IREN_BIT) -#define FSMC_SR_IFS (1U << FSMC_SR_IFS_BIT) -#define FSMC_SR_ILS (1U << FSMC_SR_ILS_BIT) -#define FSMC_SR_IRS (1U << FSMC_SR_IRS_BIT) - -/* Common memory space timing registers */ - -#define FSMC_PMEM_MEMHIZ (0xFF << 24) -#define FSMC_PMEM_MEMHOLD (0xFF << 16) -#define FSMC_PMEM_MEMWAIT (0xFF << 8) -#define FSMC_PMEM_MEMSET 0xFF - -/* Attribute memory space timing registers */ - -#define FSMC_PATT_ATTHIZ (0xFF << 24) -#define FSMC_PATT_ATTHOLD (0xFF << 16) -#define FSMC_PATT_ATTWAIT (0xFF << 8) -#define FSMC_PATT_ATTSET 0xFF - -/* I/O space timing register 4 */ - -#define FSMC_PIO_IOHIZ (0xFF << 24) -#define FSMC_PIO_IOHOLD (0xFF << 16) -#define FSMC_PIO_IOWAIT (0xFF << 8) -#define FSMC_PIO_IOSET 0xFF - -/* - * Memory bank boundary addresses - */ - -/** - * @brief Void pointer to base address of FSMC memory bank 1 (NOR/PSRAM). - * - * This bank is split into 4 regions. Each region supports interfacing - * with 1 NOR Flash, SRAM, or PSRAM chip. The base addresses of these - * regions are FSMC_NOR_PSRAM_REGIONx, for x = 1, 2, 3, 4. - */ -#define FSMC_BANK1 ((void*)0x60000000) - -/** - * @brief Void pointer to base address of FSMC memory bank 1, region 1 - * (NOR/PSRAM). - */ -#define FSMC_NOR_PSRAM_REGION1 FSMC_BANK1 - -/** - * @brief Void pointer to base address of FSMC memory bank 1, region 2 - * (NOR/PSRAM). - */ -#define FSMC_NOR_PSRAM_REGION2 ((void*)0x64000000) - -/** - * @brief Void pointer to base address of FSMC memory bank 1, region 3 - * (NOR/PSRAM). - */ -#define FSMC_NOR_PSRAM_REGION3 ((void*)0x68000000) - -/** - * @brief Void pointer to base address of FSMC memory bank 1, region 4 - * (NOR/PSRAM). - */ -#define FSMC_NOR_PSRAM_REGION4 ((void*)0x6C000000) - -/** Void pointer to base address of FSMC memory bank 2 (NAND Flash). */ -#define FSMC_BANK2 ((void*)0x70000000) - -/** Void pointer to base address of FSMC memory bank 3 (NAND Flash). */ -#define FSMC_BANK3 ((void*)0x80000000) - -/** - * @brief Void pointer to base address of FSMC memory bank 4 (PC card - * devices). - */ -#define FSMC_BANK4 ((void*)0x90000000) - -/* - * SRAM/NOR Flash routines - */ - -/** - * @brief Configure FSMC GPIOs for use with SRAM. - */ -void fsmc_sram_init_gpios(void); - -/** - * Set the DATAST bits in the given NOR/PSRAM register map's - * chip-select timing register (FSMC_BTR). - * - * @param regs NOR Flash/PSRAM register map whose chip-select timing - * register to set. - * @param datast Value to use for DATAST bits. - */ -static inline void fsmc_nor_psram_set_datast(fsmc_nor_psram_reg_map *regs, - uint8 datast) { - regs->BTR &= ~FSMC_BTR_DATAST; - regs->BTR |= datast << 8; -} - -/** - * Set the ADDHLD bits in the given NOR/PSRAM register map's chip - * select timing register (FSMC_BTRx). - * - * @param regs NOR Flash/PSRAM register map whose chip-select timing - * register to set. - * @param addset Value to use for ADDSET bits. - */ -static inline void fsmc_nor_psram_set_addset(fsmc_nor_psram_reg_map *regs, - uint8 addset) { - regs->BTR &= ~FSMC_BTR_ADDSET; - regs->BTR |= addset & 0xF; -} - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/gpio.h b/STM32F3/cores/maple/libmaple/include/libmaple/gpio.h deleted file mode 100644 index 0cc3746..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/gpio.h +++ /dev/null @@ -1,121 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * Copyright (c) 2011, 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -*****************************************************************************/ - -/** - * @file libmaple/include/libmaple/gpio.h - * @brief General Purpose I/O (GPIO) interace. - */ - -#ifndef _LIBMAPLE_GPIO_H_ -#define _LIBMAPLE_GPIO_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -/* - * Note: Series header must define: - * - enum gpio_pin_mode (TODO think harder about portability here) - */ -#include -#include -#include -#include - -/* - * Device type - */ - -/** GPIO device type */ -typedef struct gpio_dev { - gpio_reg_map *regs; /**< Register map */ - rcc_clk_id clk_id; /**< RCC clock information */ - /** - * @brief (Deprecated) External interrupt port. - * Instead of dev->exti_port, use gpio_exti_port(dev). - */ - exti_cfg exti_port; -} gpio_dev; - -/* - * Portable routines - */ - -void gpio_init(gpio_dev *dev); -void gpio_init_all(void); -/* TODO flags argument version? */ -void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode); - -/** - * @brief Get a GPIO port's corresponding EXTI port configuration. - * @param dev GPIO port whose exti_cfg to return. - */ -static inline exti_cfg gpio_exti_port(gpio_dev *dev) { - return (exti_cfg)(EXTI_PA + (dev->clk_id - RCC_GPIOA)); -} - -/** - * Set or reset a GPIO pin. - * - * Pin must have previously been configured to output mode. - * - * @param dev GPIO device whose pin to set. - * @param pin Pin on to set or reset - * @param val If true, set the pin. If false, reset the pin. - */ -static inline void gpio_write_bit(gpio_dev *dev, uint8 pin, uint8 val) { - val = !val; /* "set" bits are lower than "reset" bits */ - dev->regs->BSRR = (1U << pin) << (16 * val); -} - -/** - * Determine whether or not a GPIO pin is set. - * - * Pin must have previously been configured to input mode. - * - * @param dev GPIO device whose pin to test. - * @param pin Pin on dev to test. - * @return True if the pin is set, false otherwise. - */ -static inline uint32 gpio_read_bit(gpio_dev *dev, uint8 pin) { - return dev->regs->IDR & (1U << pin); -} - -/** - * Toggle a pin configured as output push-pull. - * @param dev GPIO device. - * @param pin Pin on dev to toggle. - */ -static inline void gpio_toggle_bit(gpio_dev *dev, uint8 pin) { - dev->regs->ODR = dev->regs->ODR ^ (1U << pin); -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/i2c.h b/STM32F3/cores/maple/libmaple/include/libmaple/i2c.h deleted file mode 100644 index 8452c2a..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/i2c.h +++ /dev/null @@ -1,304 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * Copyright (c) 2012 LeafLabs, LLC. - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/include/libmaple/i2c.h - * @author F3-port by Hanspeter Portner - * @brief Inter-Integrated Circuit (I2C) peripheral support - * - * Currently master-only. Usage notes: - * - * - Enable an I2C device with i2c_master_enable(). - * - Initialize an array of struct i2c_msg to suit the bus - * transactions (reads/writes) you wish to perform. - * - Call i2c_master_xfer() to do the work. - */ - -#ifndef _LIBMAPLE_I2C_H_ -#define _LIBMAPLE_I2C_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Series header must provide: - * - * - uint32 _i2c_bus_clk(i2c_dev*): Clock frequency of dev's bus, in - * MHz. (This is for internal use only). - * - * - (optional) _I2C_HAVE_IRQ_FIXUP: Leave undefined, or define to 1. - * This is for internal use only. It's a hack to work around a - * silicon bug related to I2C IRQ pre-emption on some targets. If 1, - * the series header must also declare and implement a routine with - * this signature (it may also be provided as a macro): - * - * void _i2c_irq_priority_fixup(i2c_dev*) - * - * This will be called by i2c_enable_irq() before actually enabling - * I2C interrupts. - * - * - Reg. map base pointers, device pointer declarations. - */ - -#include -#include - -#include -#include -#include -#include - -/** - * @brief I2C message type - */ -typedef struct i2c_msg { - uint16 addr; /**< Address */ - -#define I2C_MSG_READ 0x1 -#define I2C_MSG_10BIT_ADDR 0x2 - /** - * Bitwise OR of: - * - I2C_MSG_READ (write is default) - * - I2C_MSG_10BIT_ADDR (7-bit is default) */ - uint16 flags; - - uint16 length; /**< Message length */ - uint16 xferred; /**< Messages transferred */ - uint8 *data; /**< Data */ -} i2c_msg; - -/* I2C enable options */ -#define I2C_FAST_MODE 0x1 // 400 khz -#define I2C_DUTY_16_9 0x2 // 16/9 duty ratio -/* Flag 0x4 is reserved; DO NOT USE. */ -#define I2C_BUS_RESET 0x8 // Perform a bus reset - -/* I2C error flags */ -#define I2C_ERROR_PROTOCOL (-1) -#define I2C_ERROR_TIMEOUT (-2) - -/* Main I2C API */ - -/** - * @brief Disable an I2C device - * - * This function disables the corresponding peripheral and marks dev's - * state as I2C_STATE_DISABLED. - * - * @param dev Device to disable. - */ -static inline void i2c_disable(i2c_dev *dev) { - dev->regs->CR1 &= ~I2C_CR1_PE; - dev->state = I2C_STATE_DISABLED; -} - -/** - * @brief Wait for an I2C event, or time out in case of error. - * @param dev I2C device - * @param state I2C_state state to wait for - * @param timeout Timeout, in milliseconds - * @return 0 if target state is reached, a negative value on error. - */ -extern int32 wait_for_state_change(i2c_dev *dev, - i2c_state state, - uint32 timeout); - -/** - * @brief Reset an I2C bus. - * - * Reset is accomplished by clocking out pulses until any hung slaves - * release SDA and SCL, then generating a START condition, then a STOP - * condition. - * - * @param dev I2C device - */ -extern void i2c_bus_reset(const i2c_dev *dev); - -/** - * @brief Initialize an I2C device as bus master - * @param dev Device to enable - * @param flags Bitwise or of the following I2C options: - * I2C_FAST_MODE: 400 khz operation, - * I2C_DUTY_16_9: 16/9 Tlow/Thigh duty cycle (only applicable for - * fast mode), - * I2C_BUS_RESET: Reset the bus and clock out any hung slaves on - * initialization, - * I2C_10BIT_ADDRESSING: Enable 10-bit addressing, - * I2C_REMAP: (deprecated, STM32F1 only) Remap I2C1 to SCL/PB8 - * SDA/PB9. - */ -extern void i2c_master_enable(i2c_dev *dev, uint32 flags); - -/** - * @brief Process an i2c transaction. - * - * Transactions are composed of one or more i2c_msg's, and may be read - * or write tranfers. Multiple i2c_msg's will generate a repeated - * start in between messages. - * - * @param dev I2C device - * @param msgs Messages to send/receive - * @param num Number of messages to send/receive - * @param timeout Bus idle timeout in milliseconds before aborting the - * transfer. 0 denotes no timeout. - * @return 0 on success, - * I2C_ERROR_PROTOCOL if there was a protocol error, - * I2C_ERROR_TIMEOUT if the transfer timed out. - */ -extern int32 i2c_master_xfer(i2c_dev *dev, - i2c_msg *msgs, - uint16 num, - uint32 timeout); - -/** - * @brief Fill data register with slave address - * @param dev I2C device - * @param addr Slave address - * @param rw Read/write bit - */ -extern void i2c_send_slave_addr(i2c_dev *dev, uint32 addr, uint32 rw); - -/* Start/stop conditions */ - -/** - * @brief Generate a start condition on the bus. - * @param dev I2C device - */ -extern void i2c_start_condition(i2c_dev *dev); - -/** - * @brief Generate a stop condition on the bus - * @param dev I2C device - */ -extern void i2c_stop_condition(i2c_dev *dev); - -/* IRQ enable/disable */ - -#ifndef _I2C_HAVE_IRQ_FIXUP -/* The series header provides this if _I2C_HAVE_IRQ_FIXUP is defined, - * but we need it either way. */ -#define _i2c_irq_priority_fixup(dev) ((void)0) -#endif - -/** - * @brief Enable one or more I2C interrupts - * @param dev I2C device - * @param irqs Bitwise or of: - * I2C_IRQ_ERROR (error interrupt), - * I2C_IRQ_EVENT (event interrupt), and - * I2C_IRQ_BUFFER (buffer interrupt). - */ -extern void i2c_enable_irq(i2c_dev *dev, uint32 irqs); - -/** - * @brief Disable one or more I2C interrupts - * @param dev I2C device - * @param irqs Bitwise or of: - * I2C_IRQ_ERROR (error interrupt), - * I2C_IRQ_EVENT (event interrupt), and - * I2C_IRQ_BUFFER (buffer interrupt). - */ -extern void i2c_disable_irq(i2c_dev *dev, uint32 irqs); - -/* ACK/NACK */ - -/** - * @brief Enable I2C acknowledgment - * @param dev I2C device - */ -extern void i2c_enable_ack(i2c_dev *dev); - -/** - * @brief Disable I2C acknowledgment - * @param dev I2C device - */ -extern void i2c_disable_ack(i2c_dev *dev); - -/* GPIO control */ - -/** - * @brief Configure device GPIOs. - * - * Configure GPIO bits dev->sda_pin and dev->scl_pin on GPIO device - * dev->gpio_port for use with I2C device dev. - * - * @param dev I2C Device - * @see i2c_release_gpios() - */ -extern void i2c_config_gpios(const i2c_dev *dev); - -/** - * @brief Release GPIOs controlling an I2C bus - * - * Releases the I2C bus controlled by dev as master, and disconnects - * GPIO bits dev->sda_pin and dev->scl_pin on GPIO device - * dev->gpio_port from I2C device dev. - * - * @param dev I2C device - * @see i2c_config_gpios() - */ -extern void i2c_master_release_bus(const i2c_dev *dev); - -/* Miscellaneous low-level routines */ - -/** - * @brief Initialize an I2C device and reset its registers to their - * default values. - * @param dev Device to initialize. - */ -void i2c_init(i2c_dev *dev); - -/** - * @brief Turn on an I2C peripheral - * @param dev Device to enable - */ -static inline void i2c_peripheral_enable(i2c_dev *dev) { - dev->regs->CR1 |= I2C_CR1_PE; -} - -/** - * @brief Turn off an I2C peripheral - * @param dev Device to turn off - */ -static inline void i2c_peripheral_disable(i2c_dev *dev) { - dev->regs->CR1 &= ~I2C_CR1_PE; -} - -/** - * @brief Fill transmit register - * @param dev I2C device - * @param byte Byte to write - */ -extern void i2c_write(i2c_dev *dev, uint8 byte); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/i2c_common.h b/STM32F3/cores/maple/libmaple/include/libmaple/i2c_common.h deleted file mode 100644 index 17cabe3..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/i2c_common.h +++ /dev/null @@ -1,93 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung (from ). - * Copyright (c) 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/include/libmaple/i2c_common.h - * @author Marti Bolivar - * @brief This file is an implementation detail - * - * CONTENTS UNSTABLE. The existence of this file is an implementation - * detail. Never include it directly. If you need something from - * here, include instead. - */ - -#ifndef _LIBMAPLE_I2C_COMMON_H_ -#define _LIBMAPLE_I2C_COMMON_H_ - -#include -#include -#include - -struct gpio_dev; -struct i2c_reg_map; -struct i2c_msg; - -/** I2C device states */ -typedef enum i2c_state { - I2C_STATE_DISABLED = 0, /**< Disabled */ - I2C_STATE_IDLE = 1, /**< Idle */ - I2C_STATE_XFER_DONE = 2, /**< Done with transfer */ - I2C_STATE_BUSY = 3, /**< Busy */ - I2C_STATE_ERROR = -1 /**< Error occurred */ -} i2c_state; - -/** - * @brief I2C device type. - */ -typedef struct i2c_dev { - struct i2c_reg_map *regs; /**< Register map */ - struct i2c_msg *msg; /**< Messages */ - uint32 error_flags; /**< Error flags, set on I2C error condition */ - volatile uint32 timestamp; /**< For internal use */ - - /** - * @brief Deprecated. Use .scl_port or .sda_port instead. - * If non-null, this will be used as SDA, SCL pins' GPIO port. If - * null, then .sda_port will be used for SDA, and .sda_port for - * SDA. */ - struct gpio_dev *gpio_port; - - /** - * @brief SDA GPIO device (but see .gpio_port). - */ - struct gpio_dev *sda_port; - - /** - * @brief SCL GPIO device (but see .gpio_port). - */ - struct gpio_dev *scl_port; - - uint16 msgs_left; /**< Messages left */ - uint8 sda_pin; /**< SDA bit on gpio_port */ - uint8 scl_pin; /**< SCL bit on gpio_port */ - rcc_clk_id clk_id; /**< RCC clock information */ - nvic_irq_num ev_nvic_line; /**< Event IRQ number */ - nvic_irq_num er_nvic_line; /**< Error IRQ number */ - volatile i2c_state state; /**< Device state */ -} i2c_dev; - -#endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/iwdg.h b/STM32F3/cores/maple/libmaple/include/libmaple/iwdg.h deleted file mode 100644 index f999439..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/iwdg.h +++ /dev/null @@ -1,115 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Michael Hope. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/include/libmaple/iwdg.h - * @author Michael Hope, Marti Bolivar - * @brief Independent watchdog support. - * - * To use the independent watchdog, first call iwdg_init() with the - * appropriate prescaler and IWDG counter reload values for your - * application. Afterwards, you must periodically call iwdg_feed() - * before the IWDG counter reaches 0 to reset the counter to its - * reload value. If you do not, the chip will reset. - * - * Once started, the independent watchdog cannot be turned off. - */ - -#ifndef _LIBMAPLE_IWDG_H_ -#define _LIBMAPLE_IWDG_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -#include - -/* - * Register map - */ - -/** Independent watchdog register map type. */ -typedef struct iwdg_reg_map { - __IO uint32 KR; /**< Key register. */ - __IO uint32 PR; /**< Prescaler register. */ - __IO uint32 RLR; /**< Reload register. */ - __IO uint32 SR; /**< Status register */ -} iwdg_reg_map; - -/** Independent watchdog base pointer */ -#define IWDG_BASE ((struct iwdg_reg_map*)0x40003000) - -/* - * Register bit definitions - */ - -/* Key register */ - -#define IWDG_KR_UNLOCK 0x5555 -#define IWDG_KR_FEED 0xAAAA -#define IWDG_KR_START 0xCCCC - -/* Prescaler register */ - -#define IWDG_PR_DIV_4 0x0 -#define IWDG_PR_DIV_8 0x1 -#define IWDG_PR_DIV_16 0x2 -#define IWDG_PR_DIV_32 0x3 -#define IWDG_PR_DIV_64 0x4 -#define IWDG_PR_DIV_128 0x5 -#define IWDG_PR_DIV_256 0x6 - -/* Status register */ - -#define IWDG_SR_RVU_BIT 1 -#define IWDG_SR_PVU_BIT 0 - -#define IWDG_SR_RVU (1U << IWDG_SR_RVU_BIT) -#define IWDG_SR_PVU (1U << IWDG_SR_PVU_BIT) - -/** - * @brief Independent watchdog prescalers. - * - * These divide the 40 kHz IWDG clock. - */ -typedef enum iwdg_prescaler { - IWDG_PRE_4 = IWDG_PR_DIV_4, /**< Divide by 4 */ - IWDG_PRE_8 = IWDG_PR_DIV_8, /**< Divide by 8 */ - IWDG_PRE_16 = IWDG_PR_DIV_16, /**< Divide by 16 */ - IWDG_PRE_32 = IWDG_PR_DIV_32, /**< Divide by 32 */ - IWDG_PRE_64 = IWDG_PR_DIV_64, /**< Divide by 64 */ - IWDG_PRE_128 = IWDG_PR_DIV_128, /**< Divide by 128 */ - IWDG_PRE_256 = IWDG_PR_DIV_256 /**< Divide by 256 */ -} iwdg_prescaler; - -void iwdg_init(iwdg_prescaler prescaler, uint16 reload); -void iwdg_feed(void); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/libmaple.h b/STM32F3/cores/maple/libmaple/include/libmaple/libmaple.h deleted file mode 100644 index c9034d7..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/libmaple.h +++ /dev/null @@ -1,48 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/include/libmaple/libmaple.h - * @brief General include file for libmaple - */ - -#ifndef _LIBMAPLE_LIBMAPLE_H_ -#define _LIBMAPLE_LIBMAPLE_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include -#include - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/libmaple_types.h b/STM32F3/cores/maple/libmaple/include/libmaple/libmaple_types.h deleted file mode 100644 index c0a989a..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/libmaple_types.h +++ /dev/null @@ -1,73 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/include/libmaple/libmaple_types.h - * - * @brief libmaple's types, and operations on types. - */ - -#ifndef _LIBMAPLE_LIBMAPLE_TYPES_H_ -#define _LIBMAPLE_LIBMAPLE_TYPES_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef unsigned char uint8; -typedef unsigned short uint16; -typedef unsigned int uint32; -typedef unsigned long long uint64; - -typedef signed char int8; -typedef short int16; -typedef int int32; -typedef long long int64; - -typedef void (*voidFuncPtr)(void); -typedef void (*voidArgumentFuncPtr)(void *); - -#define __IO volatile -#define __attr_flash __attribute__((section (".USER_FLASH"))) -#define __packed __attribute__((__packed__)) -#define __deprecated __attribute__((__deprecated__)) -#define __weak __attribute__((weak)) -#define __always_inline inline __attribute__((always_inline)) -#define __unused __attribute__((unused)) - -#ifndef NULL -#define NULL 0 -#endif - -#ifndef offsetof -#define offsetof(type, member) __builtin_offsetof(type, member) -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/nvic.h b/STM32F3/cores/maple/libmaple/include/libmaple/nvic.h deleted file mode 100644 index 7699604..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/nvic.h +++ /dev/null @@ -1,155 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/include/libmaple/nvic.h - * @brief Nested vectored interrupt controller support. - * - * Basic usage: - * - * @code - * // Initialise the interrupt controller and point to the vector - * // table at the start of flash. - * nvic_init(0x08000000, 0); - * // Bind in a timer interrupt handler - * timer_attach_interrupt(TIMER_CC1_INTERRUPT, handler); - * // Optionally set the priority - * nvic_irq_set_priority(NVIC_TIMER1_CC, 5); - * // All done, enable all interrupts - * nvic_globalirq_enable(); - * @endcode - */ - -#ifndef _LIBMAPLE_NVIC_H_ -#define _LIBMAPLE_NVIC_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -#include -#include - -/** NVIC register map type. */ -typedef struct nvic_reg_map { - __IO uint32 ISER[8]; /**< Interrupt Set Enable Registers */ - /** Reserved */ - uint32 RESERVED0[24]; - - __IO uint32 ICER[8]; /**< Interrupt Clear Enable Registers */ - /** Reserved */ - uint32 RESERVED1[24]; - - __IO uint32 ISPR[8]; /**< Interrupt Set Pending Registers */ - /** Reserved */ - uint32 RESERVED2[24]; - - __IO uint32 ICPR[8]; /**< Interrupt Clear Pending Registers */ - /** Reserved */ - uint32 RESERVED3[24]; - - __IO uint32 IABR[8]; /**< Interrupt Active bit Registers */ - /** Reserved */ - uint32 RESERVED4[56]; - - __IO uint8 IP[240]; /**< Interrupt Priority Registers */ - /** Reserved */ - uint32 RESERVED5[644]; - - __IO uint32 STIR; /**< Software Trigger Interrupt Registers */ -} nvic_reg_map; - -/** NVIC register map base pointer. */ -#define NVIC_BASE ((struct nvic_reg_map*)0xE000E100) - -/* - * Note: The series header must define enum nvic_irq_num, which gives - * descriptive names to the interrupts and exceptions from NMI (-14) - * to the largest interrupt available in the series, where the value - * for nonnegative enumerators corresponds to its position in the - * vector table. - * - * It also must define a static inline nvic_irq_disable_all(), which - * writes 0xFFFFFFFF to all ICE registers available in the series. (We - * place the include here to give the series header access to - * NVIC_BASE, in order to let it do so). - */ -#include - -void nvic_init(uint32 address, uint32 offset); -void nvic_set_vector_table(uint32 address, uint32 offset); -void nvic_irq_set_priority(nvic_irq_num irqn, uint8 priority); -void nvic_sys_reset(); - -/** - * Enables interrupts and configurable fault handlers (clear PRIMASK). - */ -static __always_inline void nvic_globalirq_enable() { - asm volatile("cpsie i"); -} - -/** - * Disable interrupts and configurable fault handlers (set PRIMASK). - */ -static __always_inline void nvic_globalirq_disable() { - asm volatile("cpsid i"); -} - -/** - * @brief Enable interrupt irq_num - * @param irq_num Interrupt to enable - */ -static inline void nvic_irq_enable(nvic_irq_num irq_num) { - if (irq_num < 0) { - return; - } - NVIC_BASE->ISER[irq_num / 32] = BIT(irq_num % 32); -} - -/** - * @brief Disable interrupt irq_num - * @param irq_num Interrupt to disable - */ -static inline void nvic_irq_disable(nvic_irq_num irq_num) { - if (irq_num < 0) { - return; - } - NVIC_BASE->ICER[irq_num / 32] = BIT(irq_num % 32); -} - -/** - * @brief Quickly disable all interrupts. - * - * Calling this function is significantly faster than calling - * nvic_irq_disable() in a loop. - */ -static inline void nvic_irq_disable_all(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/opamp.h b/STM32F3/cores/maple/libmaple/include/libmaple/opamp.h deleted file mode 100644 index 2a0be62..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/opamp.h +++ /dev/null @@ -1,46 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -*****************************************************************************/ - -/** - * @file libmaple/include/libmaple/fpu.h - * @author F3-port by Hanspeter Portner - * @brief Floating Point Unit (OPAMP) interace. - */ - -#ifndef _LIBMAPLE_OPAMP_H_ -#define _LIBMAPLE_OPAMP_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -#include - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/pwr.h b/STM32F3/cores/maple/libmaple/include/libmaple/pwr.h deleted file mode 100644 index 6087c9b..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/pwr.h +++ /dev/null @@ -1,115 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/include/libmaple/pwr.h - * @brief Power control (PWR). - */ - -#ifndef _LIBMAPLE_PWR_H_ -#define _LIBMAPLE_PWR_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -/** Power interface register map. */ -typedef struct pwr_reg_map { - __IO uint32 CR; /**< Control register */ - __IO uint32 CSR; /**< Control and status register */ -} pwr_reg_map; - -/** Power peripheral register map base pointer. */ -#define PWR_BASE ((struct pwr_reg_map*)0x40007000) - -/* - * Register bit definitions - */ - -/* Control register */ - -/** Disable backup domain write protection bit */ -#define PWR_CR_DBP_BIT 8 -/** Power voltage detector enable bit */ -#define PWR_CR_PVDE_BIT 4 -/** Clear standby flag bit */ -#define PWR_CR_CSBF_BIT 3 -/** Clear wakeup flag bit */ -#define PWR_CR_CWUF_BIT 2 -/** Power down deepsleep bit */ -#define PWR_CR_PDDS_BIT 1 -/** Low-power deepsleep bit */ -#define PWR_CR_LPDS_BIT 0 - -/** Disable backup domain write protection */ -#define PWR_CR_DBP (1U << PWR_CR_DBP_BIT) -/** Power voltage detector (PVD) level selection */ -#define PWR_CR_PLS (0x7 << 5) -/** Power voltage detector enable */ -#define PWR_CR_PVDE (1U << PWR_CR_PVDE_BIT) -/** Clear standby flag */ -#define PWR_CR_CSBF (1U << PWR_CR_CSBF_BIT) -/** Clear wakeup flag */ -#define PWR_CR_CWUF (1U << PWR_CR_CWUF_BIT) -/** Power down deepsleep */ -#define PWR_CR_PDDS (1U << PWR_CR_PDDS_BIT) -/** Low-power deepsleep */ -#define PWR_CR_LPDS (1U << PWR_CR_LPDS_BIT) - -/* Control and status register */ - -/** Enable wakeup pin bit */ -#define PWR_CSR_EWUP_BIT 8 -/** PVD output bit */ -#define PWR_CSR_PVDO_BIT 2 -/** Standby flag bit */ -#define PWR_CSR_SBF_BIT 1 -/** Wakeup flag bit */ -#define PWR_CSR_WUF_BIT 0 - -/** Enable wakeup pin */ -#define PWR_CSR_EWUP (1U << PWR_CSR_EWUP_BIT) -/** PVD output */ -#define PWR_CSR_PVDO (1U << PWR_CSR_PVDO_BIT) -/** Standby flag */ -#define PWR_CSR_SBF (1U << PWR_CSR_SBF_BIT) -/** Wakeup flag */ -#define PWR_CSR_WUF (1U << PWR_CSR_WUF_BIT) - -/* - * Convenience functions - */ - -void pwr_init(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/rcc.h b/STM32F3/cores/maple/libmaple/include/libmaple/rcc.h deleted file mode 100644 index ea16803..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/rcc.h +++ /dev/null @@ -1,175 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/include/libmaple/rcc.h - * @brief Reset and Clock Control (RCC) interface. - */ - -#ifndef _LIBMAPLE_RCC_H_ -#define _LIBMAPLE_RCC_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -#include - -/* Put the SYSCLK sources before the series header is included, as it - * might need them. */ -/** - * @brief SYSCLK sources - * @see rcc_switch_sysclk() - */ -typedef enum rcc_sysclk_src { - RCC_CLKSRC_HSI = 0x0, - RCC_CLKSRC_HSE = 0x1, - RCC_CLKSRC_PLL = 0x2, -} rcc_sysclk_src; - -#include - -/* Note: Beyond the usual (registers, etc.), it's up to the series - * header to define the following types: - * - * - enum rcc_clk: Available system and secondary clock sources, - * e.g. RCC_CLK_HSE, RCC_CLK_PLL, RCC_CLK_LSE. - * - * Note that the inclusion of secondary clock sources (like LSI and - * LSE) makes enum rcc_clk different from the SYSCLK sources, which - * are defined in this header as enum rcc_sysclk_src. - * - * IMPORTANT NOTE TO IMPLEMENTORS: If you are adding support for a - * new STM32 series, see the comment near rcc_clk_reg() in - * libmaple/rcc.c for information on how to choose these values so - * that rcc_turn_on_clk() etc. will work on your series. - * - * - enum rcc_clk_id: For each available peripheral. These are widely used - * as unique IDs (TODO extricate from RCC?). Peripherals which are - * common across STM32 series should use the same token for their - * rcc_clk_id in each series header. - * - * - enum rcc_clk_domain: For each clock domain. This is returned by - * rcc_dev_clk(). For instance, each AHB and APB is a clock domain. - * - * - enum rcc_prescaler: And a suitable set of dividers for - * rcc_set_prescaler(). - * - * - enum rcc_pllsrc: For each PLL source. Same source, same token. - * - * - A target-dependent type to be pointed to by the data field in a - * struct rcc_pll_cfg. - */ - -#ifdef __DOXYGEN__ -/** RCC register map base pointer */ -#define RCC_BASE -#endif - -/* Clock prescaler management. */ - -/** - * @brief Set the divider on a peripheral prescaler - * @param prescaler prescaler to set - * @param divider prescaler divider - */ -extern void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider); - -/* SYSCLK. */ - -void rcc_switch_sysclk(rcc_sysclk_src sysclk_src); - -/* PLL configuration */ - -/** - * @brief Specifies a configuration for the main PLL. - */ -typedef struct rcc_pll_cfg { - rcc_pllsrc pllsrc; /**< PLL source */ - - /** Series-specific configuration data. */ - void *data; -} rcc_pll_cfg; - -/** - * @brief Configure the main PLL. - * - * You may only call this function while the PLL is disabled. - * - * @param pll_cfg Desired PLL configuration. The contents of this - * struct depend entirely on the target. - */ -extern void rcc_configure_pll(rcc_pll_cfg *pll_cfg); - -/* System and secondary clock sources. */ - -void rcc_turn_on_clk(rcc_clk clock); -void rcc_turn_off_clk(rcc_clk clock); -int rcc_is_clk_on(rcc_clk clock); -int rcc_is_clk_ready(rcc_clk clock); - -/* Peripheral clock lines and clock domains. */ - -/** - * @brief Turn on the clock line on a peripheral - * @param id Clock ID of the peripheral to turn on. - */ -extern void rcc_clk_enable(rcc_clk_id id); - -/** - * @brief Reset a peripheral. - * - * Caution: not all rcc_clk_id values refer to a peripheral which can - * be reset. (Only rcc_clk_ids for peripherals with bits in an RCC - * reset register can be used here.) - * - * @param id Clock ID of the peripheral to reset. - */ -extern void rcc_reset_dev(rcc_clk_id id); - -rcc_clk_domain rcc_dev_clk(rcc_clk_id id); - -/* Clock security system */ - -/** - * @brief Enable the clock security system (CSS). - */ -static inline void rcc_enable_css() { - RCC_BASE->CR |= RCC_CR_CSSON; -} - -/** - * @brief Disable the clock security system (CSS). - */ -static inline void rcc_disable_css() { - RCC_BASE->CR &= ~RCC_CR_CSSON; -} - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/ring_buffer.h b/STM32F3/cores/maple/libmaple/include/libmaple/ring_buffer.h deleted file mode 100644 index 633c29a..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/ring_buffer.h +++ /dev/null @@ -1,188 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2011 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/include/libmaple/ring_buffer.h - * @brief Simple circular buffer - * - * This implementation is not thread-safe. In particular, none of - * these functions is guaranteed re-entrant. - */ - -#ifndef _LIBMAPLE_RING_BUFFER_H_ -#define _LIBMAPLE_RING_BUFFER_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -#include - -/** - * Ring buffer type. - * - * The buffer is empty when head == tail. - * - * The buffer is full when the head is one byte in front of the tail, - * modulo buffer length. - * - * One byte is left free to distinguish empty from full. */ -typedef struct ring_buffer { - volatile uint8 *buf; /**< Buffer items are stored into */ - uint16 head; /**< Index of the next item to remove */ - uint16 tail; /**< Index where the next item will get inserted */ - uint16 size; /**< Buffer capacity minus one */ -} ring_buffer; - -/** - * Initialise a ring buffer. - * - * @param rb Instance to initialise - * - * @param size Number of items in buf. The ring buffer will always - * leave one element unoccupied, so the maximum number of - * elements it can store will be size - 1. Thus, size - * must be at least 2. - * - * @param buf Buffer to store items into - */ -static inline void rb_init(ring_buffer *rb, uint16 size, uint8 *buf) { - rb->head = 0; - rb->tail = 0; - rb->size = size - 1; - rb->buf = buf; -} - -/** - * @brief Return the number of elements stored in the ring buffer. - * @param rb Buffer whose elements to count. - */ -static inline uint16 rb_full_count(ring_buffer *rb) { - __IO ring_buffer *arb = rb; - int32 size = arb->tail - arb->head; - if (arb->tail < arb->head) { - size += arb->size + 1; - } - return (uint16)size; -} - -/** - * @brief Returns true if and only if the ring buffer is full. - * @param rb Buffer to test. - */ -static inline int rb_is_full(ring_buffer *rb) { - return (rb->tail + 1 == rb->head) || - (rb->tail == rb->size && rb->head == 0); -} - -/** - * @brief Returns true if and only if the ring buffer is empty. - * @param rb Buffer to test. - */ -static inline int rb_is_empty(ring_buffer *rb) { - return rb->head == rb->tail; -} - -/** - * Append element onto the end of a ring buffer. - * @param rb Buffer to append onto. - * @param element Value to append. - */ -static inline void rb_insert(ring_buffer *rb, uint8 element) { - rb->buf[rb->tail] = element; - rb->tail = (rb->tail == rb->size) ? 0 : rb->tail + 1; -} - -/** - * @brief Remove and return the first item from a ring buffer. - * @param rb Buffer to remove from, must contain at least one element. - */ -static inline uint8 rb_remove(ring_buffer *rb) { - uint8 ch = rb->buf[rb->head]; - rb->head = (rb->head == rb->size) ? 0 : rb->head + 1; - return ch; -} - -/** - * @brief Attempt to remove the first item from a ring buffer. - * - * If the ring buffer is nonempty, removes and returns its first item. - * If it is empty, does nothing and returns a negative value. - * - * @param rb Buffer to attempt to remove from. - */ -static inline int16 rb_safe_remove(ring_buffer *rb) { - return rb_is_empty(rb) ? -1 : rb_remove(rb); -} - -/** - * @brief Attempt to insert an element into a ring buffer. - * - * @param rb Buffer to insert into. - * @param element Value to insert into rb. - * @sideeffect If rb is not full, appends element onto buffer. - * @return If element was appended, then true; otherwise, false. */ -static inline int rb_safe_insert(ring_buffer *rb, uint8 element) { - if (rb_is_full(rb)) { - return 0; - } - rb_insert(rb, element); - return 1; -} - -/** - * @brief Append an item onto the end of a non-full ring buffer. - * - * If the buffer is full, removes its first item, then inserts the new - * element at the end. - * - * @param rb Ring buffer to insert into. - * @param element Value to insert into ring buffer. - * @return On success, returns -1. If an element was popped, returns - * the popped value. - */ -static inline int rb_push_insert(ring_buffer *rb, uint8 element) { - int ret = -1; - if (rb_is_full(rb)) { - ret = rb_remove(rb); - } - rb_insert(rb, element); - return ret; -} - -/** - * @brief Discard all items from a ring buffer. - * @param rb Ring buffer to discard all items from. - */ -static inline void rb_reset(ring_buffer *rb) { - rb->tail = rb->head; -} - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/scb.h b/STM32F3/cores/maple/libmaple/include/libmaple/scb.h deleted file mode 100644 index 0b01480..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/scb.h +++ /dev/null @@ -1,214 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * Copyright (c) 2011-2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/include/libmaple/scb.h - * @brief System control block header - */ - -/* - * FIXME: STM32F2? - */ - -#ifndef _LIBMAPLE_SCB_H_ -#define _LIBMAPLE_SCB_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/* - * Register map and base pointer - */ - -/** System control block register map type */ -typedef struct scb_reg_map { - __IO uint32 CPUID; /**< CPU ID Base Register */ - __IO uint32 ICSR; /**< Interrupt Control State Register */ - __IO uint32 VTOR; /**< Vector Table Offset Register */ - __IO uint32 AIRCR; /**< Application Interrupt / Reset Control Register */ - __IO uint32 SCR; /**< System Control Register */ - __IO uint32 CCR; /**< Configuration and Control Register */ - __IO uint8 SHP[12]; /**< System Handler Priority Registers - (4-7, 8-11, 12-15) */ - __IO uint32 SHCSR; /**< System Handler Control and State Register */ - __IO uint32 CFSR; /**< Configurable Fault Status Register */ - __IO uint32 HFSR; /**< Hard Fault Status Register */ - /* DFSR is not documented by ST in PM0056 (as of Revision 4), but - * there's a 4 byte hole in the SCB register map docs right where - * it belongs. Since it's specified as "always implemented" in - * the ARM v7-M ARM, I'm assuming its absence is a bug in the ST - * doc, but I haven't proven it. [mbolivar] */ - __IO uint32 DFSR; /**< Debug Fault Status Register */ - __IO uint32 MMFAR; /**< Mem Manage Address Register */ - __IO uint32 BFAR; /**< Bus Fault Address Register */ -#if 0 - /* The following registers are implementation-defined according to - * ARM v7-M, and I can't find evidence of their existence in ST's - * docs. I'm removing them. Feel free to yell at me if they do - * exist. [mbolivar] - */ - __IO uint32 AFSR; /**< Auxiliary Fault Status Register */ - __IO uint32 PFR[2]; /**< Processor Feature Register */ - __IO uint32 DFR; /**< Debug Feature Register */ - __IO uint32 AFR; /**< Auxiliary Feature Register */ - __IO uint32 MMFR[4]; /**< Memory Model Feature Register */ - __IO uint32 ISAR[5]; /**< ISA Feature Register */ -#endif -} scb_reg_map; - -/** System control block register map base pointer */ -#define SCB_BASE ((struct scb_reg_map*)0xE000ED00) - -/* - * Register bit definitions - */ - -/* No SCB_REG_FIELD_BIT macros as the relevant addresses are not in a - * bit-band region. */ - -/* CPUID base register (SCB_CPUID) */ - -#define SCB_CPUID_IMPLEMENTER (0xFF << 24) -#define SCB_CPUID_VARIANT (0xF << 20) -#define SCB_CPUID_CONSTANT (0xF << 16) -#define SCB_CPUID_PARTNO (0xFFF << 4) -#define SCB_CPUID_REVISION 0xF - -/* Interrupt control state register (SCB_ICSR) */ - -#define SCB_ICSR_NMIPENDSET (1U << 31) -#define SCB_ICSR_PENDSVSET (1U << 28) -#define SCB_ICSR_PENDSVCLR (1U << 27) -#define SCB_ICSR_PENDSTSET (1U << 26) -#define SCB_ICSR_PENDSTCLR (1U << 25) -#define SCB_ICSR_ISRPENDING (1U << 22) -#define SCB_ICSR_VECTPENDING (0x3FF << 12) -#define SCB_ICSR_RETOBASE (1U << 11) -#define SCB_ICSR_VECTACTIVE 0xFF - -/* Vector table offset register (SCB_VTOR) */ - -#define SCB_VTOR_TBLOFF (0x1FFFFF << 9) - -/* Application interrupt and reset control register (SCB_AIRCR) */ - -#define SCB_AIRCR_VECTKEYSTAT (0x5FA << 16) -#define SCB_AIRCR_VECTKEY (0x5FA << 16) -#define SCB_AIRCR_ENDIANNESS (1U << 15) -#define SCB_AIRCR_PRIGROUP (0x3 << 8) -#define SCB_AIRCR_SYSRESETREQ (1U << 2) -#define SCB_AIRCR_VECTCLRACTIVE (1U << 1) -#define SCB_AIRCR_VECTRESET (1U << 0) - -/* System control register (SCB_SCR) */ - -#define SCB_SCR_SEVONPEND (1U << 4) -#define SCB_SCR_SLEEPDEEP (1U << 2) -#define SCB_SCR_SLEEPONEXIT (1U << 1) - -/* Configuration and Control Register (SCB_CCR) */ - -#define SCB_CCR_STKALIGN (1U << 9) -#define SCB_CCR_BFHFNMIGN (1U << 8) -#define SCB_CCR_DIV_0_TRP (1U << 4) -#define SCB_CCR_UNALIGN_TRP (1U << 3) -#define SCB_CCR_USERSETMPEND (1U << 1) -#define SCB_CCR_NONBASETHRDENA (1U << 0) - -/* System handler priority registers (SCB_SHPRx) */ - -#define SCB_SHPR1_PRI6 (0xFF << 16) -#define SCB_SHPR1_PRI5 (0xFF << 8) -#define SCB_SHPR1_PRI4 0xFF - -#define SCB_SHPR2_PRI11 (0xFF << 24) - -#define SCB_SHPR3_PRI15 (0xFF << 24) -#define SCB_SHPR3_PRI14 (0xFF << 16) - -/* System Handler Control and state register (SCB_SHCSR) */ - -#define SCB_SHCSR_USGFAULTENA (1U << 18) -#define SCB_SHCSR_BUSFAULTENA (1U << 17) -#define SCB_SHCSR_MEMFAULTENA (1U << 16) -#define SCB_SHCSR_SVCALLPENDED (1U << 15) -#define SCB_SHCSR_BUSFAULTPENDED (1U << 14) -#define SCB_SHCSR_MEMFAULTPENDED (1U << 13) -#define SCB_SHCSR_USGFAULTPENDED (1U << 12) -#define SCB_SHCSR_SYSTICKACT (1U << 11) -#define SCB_SHCSR_PENDSVACT (1U << 10) -#define SCB_SHCSR_MONITORACT (1U << 8) -#define SCB_SHCSR_SVCALLACT (1U << 7) -#define SCB_SHCSR_USGFAULTACT (1U << 3) -#define SCB_SHCSR_BUSFAULTACT (1U << 1) -#define SCB_SHCSR_MEMFAULTACT (1U << 0) - -/* Configurable fault status register (SCB_CFSR) */ - -#define SCB_CFSR_DIVBYZERO (1U << 25) -#define SCB_CFSR_UNALIGNED (1U << 24) -#define SCB_CFSR_NOCP (1U << 19) -#define SCB_CFSR_INVPC (1U << 18) -#define SCB_CFSR_INVSTATE (1U << 17) -#define SCB_CFSR_UNDEFINSTR (1U << 16) -#define SCB_CFSR_BFARVALID (1U << 15) -#define SCB_CFSR_STKERR (1U << 12) -#define SCB_CFSR_UNSTKERR (1U << 11) -#define SCB_CFSR_IMPRECISERR (1U << 10) -#define SCB_CFSR_PRECISERR (1U << 9) -#define SCB_CFSR_IBUSERR (1U << 8) -#define SCB_CFSR_MMARVALID (1U << 7) -#define SCB_CFSR_MSTKERR (1U << 4) -#define SCB_CFSR_MUNSTKERR (1U << 3) -#define SCB_CFSR_DACCVIOL (1U << 1) -#define SCB_CFSR_IACCVIOL (1U << 0) - -/* Hard Fault Status Register (SCB_HFSR) */ - -#define SCB_HFSR_DEBUG_VT (1U << 31) -#define SCB_CFSR_FORCED (1U << 30) -#define SCB_CFSR_VECTTBL (1U << 1) - -/* Debug Fault Status Register */ - -/* Not specified by PM0056, but required by ARM. The bit definitions - * here are based on the names given in the ARM v7-M ARM. */ - -#define SCB_DFSR_EXTERNAL (1U << 4) -#define SCB_DFSR_VCATCH (1U << 3) -#define SCB_DFSR_DWTTRAP (1U << 2) -#define SCB_DFSR_BKPT (1U << 1) -#define SCB_DFSR_HALTED (1U << 0) - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/spi.h b/STM32F3/cores/maple/libmaple/include/libmaple/spi.h deleted file mode 100644 index 5c09170..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/spi.h +++ /dev/null @@ -1,487 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2011, 2012 LeafLabs, LLC. - * Copyright (c) 2010 Perry Hung. - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/include/libmaple/spi.h - * @author Marti Bolivar , - * F3-port by Hanspeter Portner - * @brief Serial Peripheral Interface (SPI) and Integrated - * Interchip Sound (I2S) peripheral support. - * - * I2S support is currently limited to register maps and bit definitions. - */ - -#ifndef _LIBMAPLE_SPI_H_ -#define _LIBMAPLE_SPI_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include -#include - -/* - * Register maps - */ - -/** SPI register map type. */ -typedef struct spi_reg_map { - __IO uint32 CR1; /**< Control register 1 */ - __IO uint32 CR2; /**< Control register 2 */ - __IO uint32 SR; /**< Status register */ - __IO uint32 DR; /**< Data register */ - __IO uint32 CRCPR; /**< CRC polynomial register */ - __IO uint32 RXCRCR; /**< RX CRC register */ - __IO uint32 TXCRCR; /**< TX CRC register */ - __IO uint32 I2SCFGR; /**< I2S configuration register */ - __IO uint32 I2SPR; /**< I2S prescaler register */ -} spi_reg_map; - -/* - * Register bit definitions - */ - -/* Control register 1 */ - -#define SPI_CR1_BIDIMODE_BIT 15 -#define SPI_CR1_BIDIOE_BIT 14 -#define SPI_CR1_CRCEN_BIT 13 -#define SPI_CR1_CRCNEXT_BIT 12 -#define SPI_CR1_DFF_BIT 11 /* FIXME F3 incompatibility */ -#define SPI_CR1_RXONLY_BIT 10 -#define SPI_CR1_SSM_BIT 9 -#define SPI_CR1_SSI_BIT 8 -#define SPI_CR1_LSBFIRST_BIT 7 -#define SPI_CR1_SPE_BIT 6 -#define SPI_CR1_MSTR_BIT 2 -#define SPI_CR1_CPOL_BIT 1 -#define SPI_CR1_CPHA_BIT 0 - -#define SPI_CR1_BIDIMODE (1U << SPI_CR1_BIDIMODE_BIT) -#define SPI_CR1_BIDIMODE_2_LINE (0x0 << SPI_CR1_BIDIMODE_BIT) -#define SPI_CR1_BIDIMODE_1_LINE (0x1 << SPI_CR1_BIDIMODE_BIT) -#define SPI_CR1_BIDIOE (1U << SPI_CR1_BIDIOE_BIT) -#define SPI_CR1_CRCEN (1U << SPI_CR1_CRCEN_BIT) -#define SPI_CR1_CRCNEXT (1U << SPI_CR1_CRCNEXT_BIT) -#define SPI_CR1_DFF (1U << SPI_CR1_DFF_BIT) -#define SPI_CR1_DFF_8_BIT (0x0 << SPI_CR1_DFF_BIT) -#define SPI_CR1_DFF_16_BIT (0x1 << SPI_CR1_DFF_BIT) -#define SPI_CR1_RXONLY (1U << SPI_CR1_RXONLY_BIT) -#define SPI_CR1_SSM (1U << SPI_CR1_SSM_BIT) -#define SPI_CR1_SSI (1U << SPI_CR1_SSI_BIT) -#define SPI_CR1_LSBFIRST (1U << SPI_CR1_LSBFIRST_BIT) -#define SPI_CR1_SPE (1U << SPI_CR1_SPE_BIT) -#define SPI_CR1_BR (0x7 << 3) -#define SPI_CR1_BR_PCLK_DIV_2 (0x0 << 3) -#define SPI_CR1_BR_PCLK_DIV_4 (0x1 << 3) -#define SPI_CR1_BR_PCLK_DIV_8 (0x2 << 3) -#define SPI_CR1_BR_PCLK_DIV_16 (0x3 << 3) -#define SPI_CR1_BR_PCLK_DIV_32 (0x4 << 3) -#define SPI_CR1_BR_PCLK_DIV_64 (0x5 << 3) -#define SPI_CR1_BR_PCLK_DIV_128 (0x6 << 3) -#define SPI_CR1_BR_PCLK_DIV_256 (0x7 << 3) -#define SPI_CR1_MSTR (1U << SPI_CR1_MSTR_BIT) -#define SPI_CR1_CPOL (1U << SPI_CR1_CPOL_BIT) -#define SPI_CR1_CPOL_LOW (0x0 << SPI_CR1_CPOL_BIT) -#define SPI_CR1_CPOL_HIGH (0x1 << SPI_CR1_CPOL_BIT) -#define SPI_CR1_CPHA (1U << SPI_CR1_CPHA_BIT) - -/* Control register 2 */ - -#define SPI_CR2_TXEIE_BIT 7 -#define SPI_CR2_RXNEIE_BIT 6 -#define SPI_CR2_ERRIE_BIT 5 -#define SPI_CR2_SSOE_BIT 2 -#define SPI_CR2_TXDMAEN_BIT 1 -#define SPI_CR2_RXDMAEN_BIT 0 - -#define SPI_CR2_TXEIE (1U << SPI_CR2_TXEIE_BIT) -#define SPI_CR2_RXNEIE (1U << SPI_CR2_RXNEIE_BIT) -#define SPI_CR2_ERRIE (1U << SPI_CR2_ERRIE_BIT) -#define SPI_CR2_SSOE (1U << SPI_CR2_SSOE_BIT) -#define SPI_CR2_TXDMAEN (1U << SPI_CR2_TXDMAEN_BIT) -#define SPI_CR2_RXDMAEN (1U << SPI_CR2_RXDMAEN_BIT) - -/* Status register */ - -#define SPI_SR_BSY_BIT 7 -#define SPI_SR_OVR_BIT 6 -#define SPI_SR_MODF_BIT 5 -#define SPI_SR_CRCERR_BIT 4 -#define SPI_SR_UDR_BIT 3 -#define SPI_SR_CHSIDE_BIT 2 -#define SPI_SR_TXE_BIT 1 -#define SPI_SR_RXNE_BIT 0 - -#define SPI_SR_BSY (1U << SPI_SR_BSY_BIT) -#define SPI_SR_OVR (1U << SPI_SR_OVR_BIT) -#define SPI_SR_MODF (1U << SPI_SR_MODF_BIT) -#define SPI_SR_CRCERR (1U << SPI_SR_CRCERR_BIT) -#define SPI_SR_UDR (1U << SPI_SR_UDR_BIT) -#define SPI_SR_CHSIDE (1U << SPI_SR_CHSIDE_BIT) -#define SPI_SR_CHSIDE_LEFT (0x0 << SPI_SR_CHSIDE_BIT) -#define SPI_SR_CHSIDE_RIGHT (0x1 << SPI_SR_CHSIDE_BIT) -#define SPI_SR_TXE (1U << SPI_SR_TXE_BIT) -#define SPI_SR_RXNE (1U << SPI_SR_RXNE_BIT) - -/* I2S configuration register */ - -#define SPI_I2SCFGR_I2SMOD_BIT 11 -#define SPI_I2SCFGR_I2SE_BIT 10 -#define SPI_I2SCFGR_PCMSYNC_BIT 7 -#define SPI_I2SCFGR_CKPOL_BIT 3 -#define SPI_I2SCFGR_CHLEN_BIT 0 - -#define SPI_I2SCFGR_I2SMOD (1U << SPI_I2SCFGR_I2SMOD_BIT) -#define SPI_I2SCFGR_I2SMOD_SPI (0x0 << SPI_I2SCFGR_I2SMOD_BIT) -#define SPI_I2SCFGR_I2SMOD_I2S (0x1 << SPI_I2SCFGR_I2SMOD_BIT) -#define SPI_I2SCFGR_I2SE (1U << SPI_I2SCFGR_I2SE_BIT) -#define SPI_I2SCFGR_I2SCFG (0x3 << 8) -#define SPI_I2SCFGR_I2SCFG_SLAVE_TX (0x0 << 8) -#define SPI_I2SCFGR_I2SCFG_SLAVE_RX (0x1 << 8) -#define SPI_I2SCFGR_I2SCFG_MASTER_TX (0x2 << 8) -#define SPI_I2SCFGR_I2SCFG_MASTER_RX (0x3 << 8) -#define SPI_I2SCFGR_PCMSYNC (1U << SPI_I2SCFGR_PCMSYNC_BIT) -#define SPI_I2SCFGR_PCMSYNC_SHORT (0x0 << SPI_I2SCFGR_PCMSYNC_BIT) -#define SPI_I2SCFGR_PCMSYNC_LONG (0x1 << SPI_I2SCFGR_PCMSYNC_BIT) -#define SPI_I2SCFGR_I2SSTD (0x3 << 4) -#define SPI_I2SCFGR_I2SSTD_PHILLIPS (0x0 << 4) -#define SPI_I2SCFGR_I2SSTD_MSB (0x1 << 4) -#define SPI_I2SCFGR_I2SSTD_LSB (0x2 << 4) -#define SPI_I2SCFGR_I2SSTD_PCM (0x3 << 4) -#define SPI_I2SCFGR_CKPOL (1U << SPI_I2SCFGR_CKPOL_BIT) -#define SPI_I2SCFGR_CKPOL_LOW (0x0 << SPI_I2SCFGR_CKPOL_BIT) -#define SPI_I2SCFGR_CKPOL_HIGH (0x1 << SPI_I2SCFGR_CKPOL_BIT) -#define SPI_I2SCFGR_DATLEN (0x3 << 1) -#define SPI_I2SCFGR_DATLEN_16_BIT (0x0 << 1) -#define SPI_I2SCFGR_DATLEN_24_BIT (0x1 << 1) -#define SPI_I2SCFGR_DATLEN_32_BIT (0x2 << 1) -#define SPI_I2SCFGR_CHLEN (1U << SPI_I2SCFGR_CHLEN_BIT) -#define SPI_I2SCFGR_CHLEN_16_BIT (0x0 << SPI_I2SCFGR_CHLEN_BIT) -#define SPI_I2SCFGR_CHLEN_32_BIT (0x1 << SPI_I2SCFGR_CHLEN_BIT) - -/* I2S prescaler register */ - -#define SPI_I2SPR_MCKOE_BIT 9 -#define SPI_I2SPR_ODD_BIT 8 - -#define SPI_I2SPR_MCKOE (1U << SPI_I2SPR_MCKOE_BIT) -#define SPI_I2SPR_ODD (1U << SPI_I2SPR_ODD_BIT) -#define SPI_I2SPR_I2SDIV 0xFF - -/* - * Devices - */ - -/** SPI device type */ -typedef struct spi_dev { - spi_reg_map *regs; /**< Register map */ - rcc_clk_id clk_id; /**< RCC clock information */ - nvic_irq_num irq_num; /**< NVIC interrupt number */ -} spi_dev; - -/* - * SPI Convenience functions - */ - -void spi_init(spi_dev *dev); - -struct gpio_dev; -/** - * @brief Configure GPIO bit modes for use as a SPI port's pins. - * - * @param dev SPI device - * @param as_master If true, configure as bus master; otherwise, as slave. - * @param nss_dev NSS pin's GPIO device - * @param nss_bit NSS pin's GPIO bit on nss_dev - * @param comm_dev SCK, MISO, MOSI pins' GPIO device - * @param sck_bit SCK pin's GPIO bit on comm_dev - * @param miso_bit MISO pin's GPIO bit on comm_dev - * @param mosi_bit MOSI pin's GPIO bit on comm_dev - */ -extern void spi_config_gpios(spi_dev *dev, - uint8 as_master, - struct gpio_dev *nss_dev, - uint8 nss_bit, - struct gpio_dev *comm_dev, - uint8 sck_bit, - uint8 miso_bit, - uint8 mosi_bit); - -/** - * @brief SPI mode configuration. - * - * A SPI mode determines a combination of the idle state of the clock - * line (the clock polarity, or "CPOL"), and which clock edge triggers - * data capture (the clock phase, or "CPHA"). - */ -typedef enum spi_mode { - /** Clock idles low, data captured on rising edge (first transition) */ - SPI_MODE_LOW_RISING = 0, - /** Clock idles low, data captured on falling edge (second transition) */ - SPI_MODE_LOW_FALLING = 1, - /** Clock idles high, data captured on falling edge (first transition) */ - SPI_MODE_HIGH_FALLING = 2, - /** Clock idles high, data captured on rising edge (second transition) */ - SPI_MODE_HIGH_RISING = 3, - - SPI_MODE_0 = SPI_MODE_LOW_RISING, /**< Same as SPI_MODE_LOW_RISING */ - SPI_MODE_1 = SPI_MODE_LOW_FALLING, /**< Same as SPI_MODE_LOW_FALLING */ - SPI_MODE_2 = SPI_MODE_HIGH_FALLING, /**< Same as SPI_MODE_HIGH_FALLING */ - SPI_MODE_3 = SPI_MODE_HIGH_RISING, /**< Same as SPI_MODE_HIGH_RISING */ -} spi_mode; - -/** - * @brief SPI baud rate configuration, as a divisor of f_PCLK, the - * PCLK clock frequency. - */ -typedef enum spi_baud_rate { - SPI_BAUD_PCLK_DIV_2 = SPI_CR1_BR_PCLK_DIV_2, /**< f_PCLK/2 */ - SPI_BAUD_PCLK_DIV_4 = SPI_CR1_BR_PCLK_DIV_4, /**< f_PCLK/4 */ - SPI_BAUD_PCLK_DIV_8 = SPI_CR1_BR_PCLK_DIV_8, /**< f_PCLK/8 */ - SPI_BAUD_PCLK_DIV_16 = SPI_CR1_BR_PCLK_DIV_16, /**< f_PCLK/16 */ - SPI_BAUD_PCLK_DIV_32 = SPI_CR1_BR_PCLK_DIV_32, /**< f_PCLK/32 */ - SPI_BAUD_PCLK_DIV_64 = SPI_CR1_BR_PCLK_DIV_64, /**< f_PCLK/64 */ - SPI_BAUD_PCLK_DIV_128 = SPI_CR1_BR_PCLK_DIV_128, /**< f_PCLK/128 */ - SPI_BAUD_PCLK_DIV_256 = SPI_CR1_BR_PCLK_DIV_256, /**< f_PCLK/256 */ -} spi_baud_rate; - -/** - * @brief SPI initialization flags. - * @see spi_master_enable() - * @see spi_slave_enable() - */ -typedef enum spi_cfg_flag { - SPI_BIDIMODE = SPI_CR1_BIDIMODE, /**< Bidirectional mode enable */ - SPI_BIDIOE = SPI_CR1_BIDIOE, /**< Output enable in bidirectional - mode */ - SPI_CRCEN = SPI_CR1_CRCEN, /**< Cyclic redundancy check (CRC) - enable */ - SPI_DFF_8_BIT = SPI_CR1_DFF_8_BIT, /**< 8-bit data frame format (this is - the default) */ - SPI_DFF_16_BIT = SPI_CR1_DFF_16_BIT, /**< 16-bit data frame format */ - SPI_RX_ONLY = SPI_CR1_RXONLY, /**< Receive only */ - SPI_SW_SLAVE = SPI_CR1_SSM, /**< Software slave management */ - SPI_SOFT_SS = SPI_CR1_SSI, /**< Software (internal) slave - select. This flag only has an - effect when used in combination - with SPI_SW_SLAVE. */ - SPI_FRAME_LSB = SPI_CR1_LSBFIRST, /**< LSB-first (little-endian) frame - format */ - SPI_FRAME_MSB = 0, /**< MSB-first (big-endian) frame - format (this is the default) */ -} spi_cfg_flag; - -void spi_master_enable(spi_dev *dev, - spi_baud_rate baud, - spi_mode mode, - uint32 flags); - -void spi_slave_enable(spi_dev *dev, - spi_mode mode, - uint32 flags); - -uint32 spi_tx(spi_dev *dev, const void *buf, uint32 len); - -/** - * @brief Call a function on each SPI port - * @param fn Function to call. - */ -extern void spi_foreach(void (*fn)(spi_dev*)); - -void spi_peripheral_enable(spi_dev *dev); -void spi_peripheral_disable(spi_dev *dev); - -void spi_tx_dma_enable(spi_dev *dev); -void spi_tx_dma_disable(spi_dev *dev); - -void spi_rx_dma_enable(spi_dev *dev); -void spi_rx_dma_disable(spi_dev *dev); - -/** - * @brief Determine if a SPI peripheral is enabled. - * @param dev SPI device - * @return True, if and only if dev's peripheral is enabled. - */ -static inline uint8 spi_is_enabled(spi_dev *dev) { - return dev->regs->CR1 & SPI_CR1_SPE_BIT; -} - -/** - * @brief Disable all SPI peripherals - */ -static inline void spi_peripheral_disable_all(void) { - spi_foreach(spi_peripheral_disable); -} - -/** Available SPI interrupts */ -typedef enum spi_interrupt { - SPI_TXE_INTERRUPT = SPI_CR2_TXEIE, /**< TX buffer empty interrupt */ - SPI_RXNE_INTERRUPT = SPI_CR2_RXNEIE, /**< RX buffer not empty interrupt */ - SPI_ERR_INTERRUPT = SPI_CR2_ERRIE /**< - * Error interrupt (CRC, overrun, - * and mode fault errors for SPI; - * underrun, overrun errors for I2S) - */ -} spi_interrupt; - -/** - * @brief Mask for all spi_interrupt values - * @see spi_interrupt - */ -#define SPI_INTERRUPTS_ALL (SPI_TXE_INTERRUPT | \ - SPI_RXNE_INTERRUPT | \ - SPI_ERR_INTERRUPT) - -/** - * @brief Enable SPI interrupt requests - * @param dev SPI device - * @param interrupt_flags Bitwise OR of spi_interrupt values to enable - * @see spi_interrupt - */ -static inline void spi_irq_enable(spi_dev *dev, uint32 interrupt_flags) { - dev->regs->CR2 |= interrupt_flags; - nvic_irq_enable(dev->irq_num); -} - -/** - * @brief Disable SPI interrupt requests - * @param dev SPI device - * @param interrupt_flags Bitwise OR of spi_interrupt values to disable - * @see spi_interrupt - */ -static inline void spi_irq_disable(spi_dev *dev, uint32 interrupt_flags) { - dev->regs->CR2 &= ~interrupt_flags; -} - -/** - * @brief Get the data frame format flags with which a SPI port is - * configured. - * @param dev SPI device whose data frame format to get. - * @return SPI_DFF_8_BIT, if dev has an 8-bit data frame format. - * Otherwise, SPI_DFF_16_BIT. - */ -static inline spi_cfg_flag spi_dff(spi_dev *dev) { - return ((dev->regs->CR1 & SPI_CR1_DFF) == SPI_CR1_DFF_8_BIT ? - SPI_DFF_8_BIT : - SPI_DFF_16_BIT); -} - -/** - * @brief Determine whether the device's peripheral receive (RX) - * register is empty. - * @param dev SPI device - * @return true, iff dev's RX register is empty. - */ -static inline uint8 spi_is_rx_nonempty(spi_dev *dev) { - return dev->regs->SR & SPI_SR_RXNE; -} - -/** - * @brief Retrieve the contents of the device's peripheral receive - * (RX) register. - * - * You may only call this function when the RX register is nonempty. - * Calling this function clears the contents of the RX register. - * - * @param dev SPI device - * @return Contents of dev's peripheral RX register - * @see spi_is_rx_reg_nonempty() - */ -extern uint16 spi_rx_reg(spi_dev *dev); - -/** - * @brief Determine whether the device's peripheral transmit (TX) - * register is empty. - * @param dev SPI device - * @return true, iff dev's TX register is empty. - */ -static inline uint8 spi_is_tx_empty(spi_dev *dev) { - return dev->regs->SR & SPI_SR_TXE; -} - -/** - * @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 - * correctly treated as 8-bit or 16-bit quantities). - * @param len Maximum number of elements to transmit. - * @return Number of elements transmitted. - */ -extern uint32 spi_tx(spi_dev *dev, const void *buf, uint32 len); - -/** - * @brief Load a value into the device's peripheral transmit (TX) register. - * - * You may only call this function when the TX register is empty. - * Calling this function loads val into the peripheral's TX register. - * If the device is properly configured, this will initiate a - * transmission, the completion of which will cause the TX register to - * be empty again. - * - * @param dev SPI device - * @param val Value to load into the TX register. If the SPI data - * frame format is 8 bit, the value must be right-aligned. - * @see spi_is_tx_reg_empty() - * @see spi_init() - * @see spi_master_enable() - * @see spi_slave_enable() - */ -static inline void spi_tx_reg(spi_dev *dev, uint16 val) { - dev->regs->DR = val; /* FIXME F3 incompatibility */ -} - -/** - * @brief Determine whether the device's peripheral busy (SPI_SR_BSY) - * flag is set. - * @param dev SPI device - * @return true, iff dev's BSY flag is set. - */ -static inline uint8 spi_is_busy(spi_dev *dev) { - return dev->regs->SR & SPI_SR_BSY; -} - -/* - * SPI auxiliary routines - */ - -extern void spi_reconfigure(spi_dev *dev, uint32 cr1_config); - -/* - * I2S convenience functions (TODO) - */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/stm32.h b/STM32F3/cores/maple/libmaple/include/libmaple/stm32.h deleted file mode 100644 index f7ced23..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/stm32.h +++ /dev/null @@ -1,239 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010, 2011, 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/include/libmaple/stm32.h - * @brief STM32 chip header - * - * This header supplies various chip-specific values for the current - * build target. It's useful both to abstract away hardware details - * (e.g. through use of STM32_NR_INTERRUPTS) and to decide what to do - * when you want something nonportable (e.g. by checking - * STM32_MCU_SERIES). - */ - -#ifndef _LIBMAPLE_STM32_H_ -#define _LIBMAPLE_STM32_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * STM32 series identifiers. - * - * Don't make these into an enum; the preprocessor needs them. - */ - -/** STM32F1 series. */ -#define STM32_SERIES_F1 0 -/** STM32F2 series. */ -#define STM32_SERIES_F2 1 -/** STM32L1 series. */ -#define STM32_SERIES_L1 2 -/** STM32F3 series. */ -#define STM32_SERIES_F3 3 -/** STM32F4 series. */ -#define STM32_SERIES_F4 4 - -/* The series header is responsible for defining: - * - * - Everything in the following __DOXYGEN__ conditional block. - * - * - STM32_HAVE_FSMC: 1 if the MCU has the FSMC peripheral, and 0 - * otherwise. - * - * - STM32_HAVE_USB: 1 if the MCU has a USB peripheral, and 0 - * otherwise. - */ -#include - -/* Ensure the series header isn't broken. */ -#if (!defined(STM32_PCLK1) || \ - !defined(STM32_PCLK2) || \ - !defined(STM32_MCU_SERIES) || \ - !defined(STM32_NR_INTERRUPTS) || \ - !defined(STM32_NR_GPIO_PORTS) || \ - !defined(STM32_TIMER_MASK) || \ - !defined(STM32_DELAY_US_MULT) || \ - !defined(STM32_SRAM_END) || \ - !defined(STM32_HAVE_DAC) || \ - !defined(STM32_HAVE_FSMC) || \ - !defined(STM32_HAVE_USB)) -#error "Bad STM32F1 configuration. Check header for your MCU." -#endif - -/* - * Derived macros - */ - -/* FIXME [0.0.13] add this to ReST API page */ -/** - * @brief Statically determine whether a timer is present. - * - * Given a constant timer number n (starting from 1), this macro has a - * nonzero value exactly when TIMERn is available. - */ -#define STM32_HAVE_TIMER(n) (STM32_TIMER_MASK & (1 << (n))) - -/* - * Doxygen for functionality provided by series header. - */ - -#ifdef __DOXYGEN__ - -/* - * Clock configuration. - * - * These defines depend upon how the MCU is configured. Because of - * the potential for a mismatch between them and the actual clock - * configuration, keep their number to a minimum. - */ - -/** - * @brief APB1 clock speed, in Hz. - */ -#define STM32_PCLK1 - -/** - * @brief APB2 clock speed, in Hz. - */ -#define STM32_PCLK2 - -/** @brief Deprecated. Use STM32_PCLK1 instead. */ -#define PCLK1 -/** @brief Deprecated. Use STM32_PCLK2 instead. */ -#define PCLK2 - -/* - * Series- and MCU-specific values. - */ - -/** - * @brief STM32 series value for the MCU being targeted. - * - * At time of writing, allowed values are: STM32_SERIES_F1, - * STM32_SERIES_F2. This set of values will expand as libmaple adds - * support for more STM32 series MCUs. - */ -#define STM32_MCU_SERIES - -/** - * @brief Number of interrupts in the vector table. - * - * This does not include Cortex-M interrupts (NMI, HardFault, etc.). - */ -#define STM32_NR_INTERRUPTS - -/** - * Number of GPIO ports. - */ -#define STM32_NR_GPIO_PORTS - -/* FIXME [0.0.13] add this to ReST API page */ -/** - * @brief Bitmask of timers available on the MCU. - * - * That is, if TIMERn is available, then STM32_TIMER_MASK & (1 << n) - * will be nonzero. For example, a nonzero value of "STM32_TIMER_MASK - * & 0x2" means TIMER1 is available. - * - * A bitmask is necessary as some STM32 MCUs have "holes" in the range - * of available timers. - */ -#define STM32_TIMER_MASK - -/** - * @brief Multiplier to convert microseconds into loop iterations - * in delay_us(). - * - * @see delay_us() - */ -#define STM32_DELAY_US_MULT - -/** - * @brief Pointer to end of built-in SRAM. - * - * Points to the address which is 1 byte past the last valid - * SRAM address. - */ -#define STM32_SRAM_END - -/** - * @brief 1 if the target MCU has a DAC, and 0 otherwise. - */ -#define STM32_HAVE_DAC - -/** - * @brief 1 if the target MCU has the FSMC peripheral, and 0 otherwise. - * - * Note that the feature set of the FSMC peripheral is restricted on - * some MCUs. - */ -#define STM32_HAVE_FSMC - -/** - * @brief 1 if the target MCU has a USB peripheral, and 0 otherwise. - * - * Note that a variety of USB peripherals are available across the - * different series, with widely varying feature sets and programming - * interfaces. This macro will be 1 if any such peripheral is present. - */ -#define STM32_HAVE_USB - -#endif /* __DOXYGEN__ */ - -/* - * The following are for backwards compatibility only. - */ - -/* PCLK1 and PCLK2 are for backwards compatibility only; don't use in - * new code. */ -#ifndef PCLK1 -#define PCLK1 STM32_PCLK1 -#endif -#if PCLK1 != STM32_PCLK1 -#error "PCLK1 (which is deprecated) differs from STM32_PCLK1." -#endif -#ifndef PCLK2 -#define PCLK2 STM32_PCLK2 -#endif -#if PCLK2 != STM32_PCLK2 -#error "PCLK2 (which is deprecated) differs from STM32_PCLK2." -#endif - -/** @brief Deprecated. Use STM32_NR_INTERRUPTS instead. */ -#define NR_INTERRUPTS STM32_NR_INTERRUPTS -/** @brief Deprecated. Use STM32_NR_GPIO_PORTS instead. */ -#define NR_GPIO_PORTS STM32_NR_GPIO_PORTS -/** @brief Deprecated. Use STM32_DELAY_US_MULT instead. */ -#define DELAY_US_MULT STM32_DELAY_US_MULT - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/syscfg.h b/STM32F3/cores/maple/libmaple/include/libmaple/syscfg.h deleted file mode 100644 index b8c901f..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/syscfg.h +++ /dev/null @@ -1,116 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2012 LeafLabs, LLC. - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/include/libmaple/syscfg.h - * @author F3-port by Hanspeter Portner - * @brief System configuration controller (SYSCFG) - * - * Availability: STM32F2, STM32F3, STM32F4. - */ - -#ifndef _LIBMAPLE_SYSCFG_H_ -#define _LIBMAPLE_SYSCFG_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -/* External interrupt configuration register 1 */ - -#define SYSCFG_EXTICR1_EXTI0 0xF -#define SYSCFG_EXTICR1_EXTI1 0xF0 -#define SYSCFG_EXTICR1_EXTI2 0xF00 -#define SYSCFG_EXTICR1_EXTI3 0xF000 - -/* External interrupt configuration register 2 */ - -#define SYSCFG_EXTICR2_EXTI4 0xF -#define SYSCFG_EXTICR2_EXTI5 0xF0 -#define SYSCFG_EXTICR2_EXTI6 0xF00 -#define SYSCFG_EXTICR2_EXTI7 0xF000 - -/* External interrupt configuration register 3 */ - -#define SYSCFG_EXTICR3_EXTI8 0xF -#define SYSCFG_EXTICR3_EXTI9 0xF0 -#define SYSCFG_EXTICR3_EXTI10 0xF00 -#define SYSCFG_EXTICR3_EXTI11 0xF000 - -/* External interrupt configuration register 4 */ - -#define SYSCFG_EXTICR4_EXTI12 0xF -#define SYSCFG_EXTICR4_EXTI13 0xF0 -#define SYSCFG_EXTICR4_EXTI14 0xF00 -#define SYSCFG_EXTICR4_EXTI15 0xF000 - -/* - * Routines - */ - -/** - * @brief Initialize the SYSCFG peripheral. - */ -void syscfg_init(void); - -/** - * @brief System memory mode - * These values specify what memory to map to address 0x00000000. - * @see syscfg_set_mem_mode - */ -typedef enum syscfg_mem_mode { - /** Main flash memory is mapped at 0x0. */ - SYSCFG_MEM_MODE_FLASH = 0x0, - /** System flash (i.e. ST's baked-in bootloader) is mapped at 0x0. */ - SYSCFG_MEM_MODE_SYSTEM_FLASH = 0x1, - /** FSMC bank 1 (NOR/PSRAM 1 and 2) is mapped at 0x0. */ - SYSCFG_MEM_MODE_FSMC_BANK_1 = 0x2, - /** Embedded SRAM (i.e., not backup SRAM) is mapped at 0x0. */ - SYSCFG_MEM_MODE_SRAM = 0x3, -} syscfg_mem_mode; - - -/** - * @brief Set the memory to be mapped at address 0x00000000. - * - * This function can be used to override the BOOT pin - * configuration. Some restrictions apply; see your chip's reference - * manual for the details. - * - * @param mode Mode to set - * @see syscfg_mem_mode - */ -void syscfg_set_mem_mode(syscfg_mem_mode); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/systick.h b/STM32F3/cores/maple/libmaple/include/libmaple/systick.h deleted file mode 100644 index 815a1c3..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/systick.h +++ /dev/null @@ -1,115 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/include/libmaple/systick.h - * @brief System timer definitions - */ - -#ifndef _LIBMAPLE_SYSTICK_H_ -#define _LIBMAPLE_SYSTICK_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -#include -#include - -/** SysTick register map type */ -typedef struct systick_reg_map { - __IO uint32 CSR; /**< Control and status register */ - __IO uint32 RVR; /**< Reload value register */ - __IO uint32 CNT; /**< Current value register ("count") */ - __IO uint32 CVR; /**< Calibration value register */ -} systick_reg_map; - -/** SysTick register map base pointer */ -#define SYSTICK_BASE ((struct systick_reg_map*)0xE000E010) - -/* - * Register bit definitions. - */ - -/* Control and status register */ - -#define SYSTICK_CSR_COUNTFLAG BIT(16) -#define SYSTICK_CSR_CLKSOURCE BIT(2) -#define SYSTICK_CSR_CLKSOURCE_EXTERNAL 0 -#define SYSTICK_CSR_CLKSOURCE_CORE BIT(2) -#define SYSTICK_CSR_TICKINT BIT(1) -#define SYSTICK_CSR_TICKINT_PEND BIT(1) -#define SYSTICK_CSR_TICKINT_NO_PEND 0 -#define SYSTICK_CSR_ENABLE BIT(0) -#define SYSTICK_CSR_ENABLE_MULTISHOT BIT(0) -#define SYSTICK_CSR_ENABLE_DISABLED 0 - -/* Calibration value register */ - -#define SYSTICK_CVR_NOREF BIT(31) -#define SYSTICK_CVR_SKEW BIT(30) -#define SYSTICK_CVR_TENMS 0xFFFFFF - -/** System elapsed time, in milliseconds */ -extern volatile uint32 systick_uptime_millis; - -/** - * @brief Returns the system uptime, in milliseconds. - */ -static inline uint32 systick_uptime(void) { - return systick_uptime_millis; -} - - -void systick_init(uint32 reload_val); -void systick_disable(); -void systick_enable(); - -/** - * @brief Returns the current value of the SysTick counter. - */ -static inline uint32 systick_get_count(void) { - return SYSTICK_BASE->CNT; -} - -/** - * @brief Check for underflow. - * - * This function returns 1 if the SysTick timer has counted to 0 since - * the last time it was called. However, any reads of any part of the - * SysTick Control and Status Register SYSTICK_BASE->CSR will - * interfere with this functionality. See the ARM Cortex M3 Technical - * Reference Manual for more details (e.g. Table 8-3 in revision r1p1). - */ -static inline uint32 systick_check_underflow(void) { - return SYSTICK_BASE->CSR & SYSTICK_CSR_COUNTFLAG; -} - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/timer.h b/STM32F3/cores/maple/libmaple/include/libmaple/timer.h deleted file mode 100644 index 51a5623..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/timer.h +++ /dev/null @@ -1,1119 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2011, 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/include/libmaple/timer.h - * @author Marti Bolivar - * @brief Timer interface. - */ - -#ifndef _LIBMAPLE_TIMER_H_ -#define _LIBMAPLE_TIMER_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -#include -#include -#include -#include -#include - -/* - * Register maps - */ - -/** Advanced control timer register map type */ -typedef struct timer_adv_reg_map { - __IO uint32 CR1; /**< Control register 1 */ - __IO uint32 CR2; /**< Control register 2 */ - __IO uint32 SMCR; /**< Slave mode control register */ - __IO uint32 DIER; /**< DMA/interrupt enable register */ - __IO uint32 SR; /**< Status register */ - __IO uint32 EGR; /**< Event generation register */ - __IO uint32 CCMR1; /**< Capture/compare mode register 1 */ - __IO uint32 CCMR2; /**< Capture/compare mode register 2 */ - __IO uint32 CCER; /**< Capture/compare enable register */ - __IO uint32 CNT; /**< Counter */ - __IO uint32 PSC; /**< Prescaler */ - __IO uint32 ARR; /**< Auto-reload register */ - __IO uint32 RCR; /**< Repetition counter register */ - __IO uint32 CCR1; /**< Capture/compare register 1 */ - __IO uint32 CCR2; /**< Capture/compare register 2 */ - __IO uint32 CCR3; /**< Capture/compare register 3 */ - __IO uint32 CCR4; /**< Capture/compare register 4 */ - __IO uint32 BDTR; /**< Break and dead-time register */ - __IO uint32 DCR; /**< DMA control register */ - __IO uint32 DMAR; /**< DMA address for full transfer */ -} timer_adv_reg_map; - -/* General purpose timer register map type: intentionally omitted. - * - * General purpose timers differ slightly across series, so leave it - * up to the series header to define struct timer_gen_reg_map. */ - -/** Basic timer register map type */ -typedef struct timer_bas_reg_map { - __IO uint32 CR1; /**< Control register 1 */ - __IO uint32 CR2; /**< Control register 2 */ - const uint32 RESERVED1; /**< Reserved */ - __IO uint32 DIER; /**< DMA/interrupt enable register */ - __IO uint32 SR; /**< Status register */ - __IO uint32 EGR; /**< Event generation register */ - const uint32 RESERVED2; /**< Reserved */ - const uint32 RESERVED3; /**< Reserved */ - const uint32 RESERVED4; /**< Reserved */ - __IO uint32 CNT; /**< Counter */ - __IO uint32 PSC; /**< Prescaler */ - __IO uint32 ARR; /**< Auto-reload register */ -} timer_bas_reg_map; - -/* - * Timer devices - */ - -/** - * @brief Timer register map type. - * - * Just holds a pointer to the correct type of register map, based on - * the timer's type. - */ -typedef union timer_reg_map { - timer_adv_reg_map *adv; /**< Advanced register map */ - timer_gen_reg_map *gen; /**< General purpose register map */ - timer_bas_reg_map *bas; /**< Basic register map */ -} timer_reg_map; - -/** - * @brief Timer type - * - * Type marker for timer_dev. - * - * @see timer_dev - */ -typedef enum timer_type { - TIMER_ADVANCED, /**< Advanced type */ - TIMER_GENERAL, /**< General purpose type */ - TIMER_BASIC, /**< Basic type */ -} timer_type; - -/** Timer device type */ -typedef struct timer_dev { - timer_reg_map regs; /**< Register map */ - rcc_clk_id clk_id; /**< RCC clock information */ - timer_type type; /**< Timer's type */ - voidFuncPtr handlers[]; /**< - * Don't touch these. Use these instead: - * @see timer_attach_interrupt() - * @see timer_detach_interrupt() */ -} timer_dev; - -#if STM32_HAVE_TIMER(1) -extern timer_dev *TIMER1; -#endif -#if STM32_HAVE_TIMER(2) -extern timer_dev *TIMER2; -#endif -#if STM32_HAVE_TIMER(3) -extern timer_dev *TIMER3; -#endif -#if STM32_HAVE_TIMER(4) -extern timer_dev *TIMER4; -#endif -#if STM32_HAVE_TIMER(5) -extern timer_dev *TIMER5; -#endif -#if STM32_HAVE_TIMER(6) -extern timer_dev *TIMER6; -#endif -#if STM32_HAVE_TIMER(7) -extern timer_dev *TIMER7; -#endif -#if STM32_HAVE_TIMER(8) -extern timer_dev *TIMER8; -#endif -#if STM32_HAVE_TIMER(9) -extern timer_dev *TIMER9; -#endif -#if STM32_HAVE_TIMER(10) -extern timer_dev *TIMER10; -#endif -#if STM32_HAVE_TIMER(11) -extern timer_dev *TIMER11; -#endif -#if STM32_HAVE_TIMER(12) -extern timer_dev *TIMER12; -#endif -#if STM32_HAVE_TIMER(13) -extern timer_dev *TIMER13; -#endif -#if STM32_HAVE_TIMER(14) -extern timer_dev *TIMER14; -#endif -#if STM32_HAVE_TIMER(15) -extern timer_dev *TIMER15; -#endif -#if STM32_HAVE_TIMER(16) -extern timer_dev *TIMER16; -#endif -#if STM32_HAVE_TIMER(17) -extern timer_dev *TIMER17; -#endif - -/* - * Register bit definitions - */ - -/* Control register 1 (CR1) */ - -#define TIMER_CR1_ARPE_BIT 7 -#define TIMER_CR1_DIR_BIT 4 -#define TIMER_CR1_OPM_BIT 3 -#define TIMER_CR1_URS_BIT 2 -#define TIMER_CR1_UDIS_BIT 1 -#define TIMER_CR1_CEN_BIT 0 - -#define TIMER_CR1_CKD (0x3 << 8) -#define TIMER_CR1_CKD_1TCKINT (0x0 << 8) -#define TIMER_CR1_CKD_2TCKINT (0x1 << 8) -#define TIMER_CR1_CKD_4TICKINT (0x2 << 8) -#define TIMER_CR1_ARPE (1U << TIMER_CR1_ARPE_BIT) -#define TIMER_CR1_CKD_CMS (0x3 << 5) -#define TIMER_CR1_CKD_CMS_EDGE (0x0 << 5) -#define TIMER_CR1_CKD_CMS_CENTER1 (0x1 << 5) -#define TIMER_CR1_CKD_CMS_CENTER2 (0x2 << 5) -#define TIMER_CR1_CKD_CMS_CENTER3 (0x3 << 5) -#define TIMER_CR1_DIR (1U << TIMER_CR1_DIR_BIT) -#define TIMER_CR1_OPM (1U << TIMER_CR1_OPM_BIT) -#define TIMER_CR1_URS (1U << TIMER_CR1_URS_BIT) -#define TIMER_CR1_UDIS (1U << TIMER_CR1_UDIS_BIT) -#define TIMER_CR1_CEN (1U << TIMER_CR1_CEN_BIT) - -/* Control register 2 (CR2) */ - -#define TIMER_CR2_OIS4_BIT 14 -#define TIMER_CR2_OIS3N_BIT 13 -#define TIMER_CR2_OIS3_BIT 12 -#define TIMER_CR2_OIS2N_BIT 11 -#define TIMER_CR2_OIS2_BIT 10 -#define TIMER_CR2_OIS1N_BIT 9 -#define TIMER_CR2_OIS1_BIT 8 -#define TIMER_CR2_TI1S_BIT 7 -#define TIMER_CR2_CCDS_BIT 3 -#define TIMER_CR2_CCUS_BIT 2 -#define TIMER_CR2_CCPC_BIT 0 - -#define TIMER_CR2_OIS4 (1U << TIMER_CR2_OIS4_BIT) -#define TIMER_CR2_OIS3N (1U << TIMER_CR2_OIS3N_BIT) -#define TIMER_CR2_OIS3 (1U << TIMER_CR2_OIS3_BIT) -#define TIMER_CR2_OIS2N (1U << TIMER_CR2_OIS2N_BIT) -#define TIMER_CR2_OIS2 (1U << TIMER_CR2_OIS2_BIT) -#define TIMER_CR2_OIS1N (1U << TIMER_CR2_OIS1N_BIT) -#define TIMER_CR2_OIS1 (1U << TIMER_CR2_OIS1_BIT) -#define TIMER_CR2_TI1S (1U << TIMER_CR2_TI1S_BIT) -#define TIMER_CR2_MMS (0x7 << 4) -#define TIMER_CR2_MMS_RESET (0x0 << 4) -#define TIMER_CR2_MMS_ENABLE (0x1 << 4) -#define TIMER_CR2_MMS_UPDATE (0x2 << 4) -#define TIMER_CR2_MMS_COMPARE_PULSE (0x3 << 4) -#define TIMER_CR2_MMS_COMPARE_OC1REF (0x4 << 4) -#define TIMER_CR2_MMS_COMPARE_OC2REF (0x5 << 4) -#define TIMER_CR2_MMS_COMPARE_OC3REF (0x6 << 4) -#define TIMER_CR2_MMS_COMPARE_OC4REF (0x7 << 4) -#define TIMER_CR2_CCDS (1U << TIMER_CR2_CCDS_BIT) -#define TIMER_CR2_CCUS (1U << TIMER_CR2_CCUS_BIT) -#define TIMER_CR2_CCPC (1U << TIMER_CR2_CCPC_BIT) - -/* Slave mode control register (SMCR) */ - -#define TIMER_SMCR_ETP_BIT 15 -#define TIMER_SMCR_ECE_BIT 14 -#define TIMER_SMCR_MSM_BIT 7 - -#define TIMER_SMCR_ETP (1U << TIMER_SMCR_ETP_BIT) -#define TIMER_SMCR_ECE (1U << TIMER_SMCR_ECE_BIT) -#define TIMER_SMCR_ETPS (0x3 << 12) -#define TIMER_SMCR_ETPS_OFF (0x0 << 12) -#define TIMER_SMCR_ETPS_DIV2 (0x1 << 12) -#define TIMER_SMCR_ETPS_DIV4 (0x2 << 12) -#define TIMER_SMCR_ETPS_DIV8 (0x3 << 12) -#define TIMER_SMCR_ETF (0xF << 12) -#define TIMER_SMCR_MSM (1U << TIMER_SMCR_MSM_BIT) -#define TIMER_SMCR_TS (0x3 << 4) -#define TIMER_SMCR_TS_ITR0 (0x0 << 4) -#define TIMER_SMCR_TS_ITR1 (0x1 << 4) -#define TIMER_SMCR_TS_ITR2 (0x2 << 4) -#define TIMER_SMCR_TS_ITR3 (0x3 << 4) -#define TIMER_SMCR_TS_TI1F_ED (0x4 << 4) -#define TIMER_SMCR_TS_TI1FP1 (0x5 << 4) -#define TIMER_SMCR_TS_TI2FP2 (0x6 << 4) -#define TIMER_SMCR_TS_ETRF (0x7 << 4) -#define TIMER_SMCR_SMS 0x3 -#define TIMER_SMCR_SMS_DISABLED 0x0 -#define TIMER_SMCR_SMS_ENCODER1 0x1 -#define TIMER_SMCR_SMS_ENCODER2 0x2 -#define TIMER_SMCR_SMS_ENCODER3 0x3 -#define TIMER_SMCR_SMS_RESET 0x4 -#define TIMER_SMCR_SMS_GATED 0x5 -#define TIMER_SMCR_SMS_TRIGGER 0x6 -#define TIMER_SMCR_SMS_EXTERNAL 0x7 - -/* DMA/Interrupt enable register (DIER) */ - -#define TIMER_DIER_TDE_BIT 14 -#define TIMER_DIER_COMDE_BIT 13 -#define TIMER_DIER_CC4DE_BIT 12 -#define TIMER_DIER_CC3DE_BIT 11 -#define TIMER_DIER_CC2DE_BIT 10 -#define TIMER_DIER_CC1DE_BIT 9 -#define TIMER_DIER_UDE_BIT 8 -#define TIMER_DIER_BIE_BIT 7 -#define TIMER_DIER_TIE_BIT 6 -#define TIMER_DIER_COMIE_BIT 5 -#define TIMER_DIER_CC4IE_BIT 4 -#define TIMER_DIER_CC3IE_BIT 3 -#define TIMER_DIER_CC2IE_BIT 2 -#define TIMER_DIER_CC1IE_BIT 1 -#define TIMER_DIER_UIE_BIT 0 - -#define TIMER_DIER_TDE (1U << TIMER_DIER_TDE_BIT) -#define TIMER_DIER_COMDE (1U << TIMER_DIER_COMDE_BIT) -#define TIMER_DIER_CC4DE (1U << TIMER_DIER_CC4DE_BIT) -#define TIMER_DIER_CC3DE (1U << TIMER_DIER_CC3DE_BIT) -#define TIMER_DIER_CC2DE (1U << TIMER_DIER_CC2DE_BIT) -#define TIMER_DIER_CC1DE (1U << TIMER_DIER_CC1DE_BIT) -#define TIMER_DIER_UDE (1U << TIMER_DIER_UDE_BIT) -#define TIMER_DIER_BIE (1U << TIMER_DIER_BIE_BIT) -#define TIMER_DIER_TIE (1U << TIMER_DIER_TIE_BIT) -#define TIMER_DIER_COMIE (1U << TIMER_DIER_COMIE_BIT) -#define TIMER_DIER_CC4IE (1U << TIMER_DIER_CC4IE_BIT) -#define TIMER_DIER_CC3IE (1U << TIMER_DIER_CC3IE_BIT) -#define TIMER_DIER_CC2IE (1U << TIMER_DIER_CC2IE_BIT) -#define TIMER_DIER_CC1IE (1U << TIMER_DIER_CC1IE_BIT) -#define TIMER_DIER_UIE (1U << TIMER_DIER_UIE_BIT) - -/* Status register (SR) */ - -#define TIMER_SR_CC4OF_BIT 12 -#define TIMER_SR_CC3OF_BIT 11 -#define TIMER_SR_CC2OF_BIT 10 -#define TIMER_SR_CC1OF_BIT 9 -#define TIMER_SR_BIF_BIT 7 -#define TIMER_SR_TIF_BIT 6 -#define TIMER_SR_COMIF_BIT 5 -#define TIMER_SR_CC4IF_BIT 4 -#define TIMER_SR_CC3IF_BIT 3 -#define TIMER_SR_CC2IF_BIT 2 -#define TIMER_SR_CC1IF_BIT 1 -#define TIMER_SR_UIF_BIT 0 - -#define TIMER_SR_CC4OF (1U << TIMER_SR_CC4OF_BIT) -#define TIMER_SR_CC3OF (1U << TIMER_SR_CC3OF_BIT) -#define TIMER_SR_CC2OF (1U << TIMER_SR_CC2OF_BIT) -#define TIMER_SR_CC1OF (1U << TIMER_SR_CC1OF_BIT) -#define TIMER_SR_BIF (1U << TIMER_SR_BIF_BIT) -#define TIMER_SR_TIF (1U << TIMER_SR_TIF_BIT) -#define TIMER_SR_COMIF (1U << TIMER_SR_COMIF_BIT) -#define TIMER_SR_CC4IF (1U << TIMER_SR_CC4IF_BIT) -#define TIMER_SR_CC3IF (1U << TIMER_SR_CC3IF_BIT) -#define TIMER_SR_CC2IF (1U << TIMER_SR_CC2IF_BIT) -#define TIMER_SR_CC1IF (1U << TIMER_SR_CC1IF_BIT) -#define TIMER_SR_UIF (1U << TIMER_SR_UIF_BIT) - -/* Event generation register (EGR) */ - -#define TIMER_EGR_BG_BIT 7 -#define TIMER_EGR_TG_BIT 6 -#define TIMER_EGR_COMG_BIT 5 -#define TIMER_EGR_CC4G_BIT 4 -#define TIMER_EGR_CC3G_BIT 3 -#define TIMER_EGR_CC2G_BIT 2 -#define TIMER_EGR_CC1G_BIT 1 -#define TIMER_EGR_UG_BIT 0 - -#define TIMER_EGR_BG (1U << TIMER_EGR_BG_BIT) -#define TIMER_EGR_TG (1U << TIMER_EGR_TG_BIT) -#define TIMER_EGR_COMG (1U << TIMER_EGR_COMG_BIT) -#define TIMER_EGR_CC4G (1U << TIMER_EGR_CC4G_BIT) -#define TIMER_EGR_CC3G (1U << TIMER_EGR_CC3G_BIT) -#define TIMER_EGR_CC2G (1U << TIMER_EGR_CC2G_BIT) -#define TIMER_EGR_CC1G (1U << TIMER_EGR_CC1G_BIT) -#define TIMER_EGR_UG (1U << TIMER_EGR_UG_BIT) - -/* Capture/compare mode registers, common values */ - -#define TIMER_CCMR_CCS_OUTPUT 0x0 -#define TIMER_CCMR_CCS_INPUT_TI1 0x1 -#define TIMER_CCMR_CCS_INPUT_TI2 0x2 -#define TIMER_CCMR_CCS_INPUT_TRC 0x3 - -/* Capture/compare mode register 1 (CCMR1) */ - -#define TIMER_CCMR1_OC2CE_BIT 15 -#define TIMER_CCMR1_OC2PE_BIT 11 -#define TIMER_CCMR1_OC2FE_BIT 10 -#define TIMER_CCMR1_OC1CE_BIT 7 -#define TIMER_CCMR1_OC1PE_BIT 3 -#define TIMER_CCMR1_OC1FE_BIT 2 - -#define TIMER_CCMR1_OC2CE (1U << TIMER_CCMR1_OC2CE_BIT) -#define TIMER_CCMR1_OC2M (0x3 << 12) -#define TIMER_CCMR1_IC2F (0xF << 12) -#define TIMER_CCMR1_OC2PE (1U << TIMER_CCMR1_OC2PE_BIT) -#define TIMER_CCMR1_OC2FE (1U << TIMER_CCMR1_OC2FE_BIT) -#define TIMER_CCMR1_IC2PSC (0x3 << 10) -#define TIMER_CCMR1_CC2S (0x3 << 8) -#define TIMER_CCMR1_CC2S_OUTPUT (TIMER_CCMR_CCS_OUTPUT << 8) -#define TIMER_CCMR1_CC2S_INPUT_TI1 (TIMER_CCMR_CCS_INPUT_TI1 << 8) -#define TIMER_CCMR1_CC2S_INPUT_TI2 (TIMER_CCMR_CCS_INPUT_TI2 << 8) -#define TIMER_CCMR1_CC2S_INPUT_TRC (TIMER_CCMR_CCS_INPUT_TRC << 8) -#define TIMER_CCMR1_OC1CE (1U << TIMER_CCMR1_OC1CE_BIT) -#define TIMER_CCMR1_OC1M (0x3 << 4) -#define TIMER_CCMR1_IC1F (0xF << 4) -#define TIMER_CCMR1_OC1PE (1U << TIMER_CCMR1_OC1PE_BIT) -#define TIMER_CCMR1_OC1FE (1U << TIMER_CCMR1_OC1FE_BIT) -#define TIMER_CCMR1_IC1PSC (0x3 << 2) -#define TIMER_CCMR1_CC1S 0x3 -#define TIMER_CCMR1_CC1S_OUTPUT TIMER_CCMR_CCS_OUTPUT -#define TIMER_CCMR1_CC1S_INPUT_TI1 TIMER_CCMR_CCS_INPUT_TI1 -#define TIMER_CCMR1_CC1S_INPUT_TI2 TIMER_CCMR_CCS_INPUT_TI2 -#define TIMER_CCMR1_CC1S_INPUT_TRC TIMER_CCMR_CCS_INPUT_TRC - -/* Capture/compare mode register 2 (CCMR2) */ - -#define TIMER_CCMR2_OC4CE_BIT 15 -#define TIMER_CCMR2_OC4PE_BIT 11 -#define TIMER_CCMR2_OC4FE_BIT 10 -#define TIMER_CCMR2_OC3CE_BIT 7 -#define TIMER_CCMR2_OC3PE_BIT 3 -#define TIMER_CCMR2_OC3FE_BIT 2 - -#define TIMER_CCMR2_OC4CE (1U << TIMER_CCMR2_OC4CE_BIT) -#define TIMER_CCMR2_OC4M (0x3 << 12) -#define TIMER_CCMR2_IC4F (0xF << 12) -#define TIMER_CCMR2_OC4PE (1U << TIMER_CCMR2_OC4PE_BIT) -#define TIMER_CCMR2_OC4FE (1U << TIMER_CCMR2_OC4FE_BIT) -#define TIMER_CCMR2_IC4PSC (0x3 << 10) -#define TIMER_CCMR2_CC4S (0x3 << 8) -#define TIMER_CCMR2_CC4S_OUTPUT (TIMER_CCMR_CCS_OUTPUT << 8) -#define TIMER_CCMR2_CC4S_INPUT_TI1 (TIMER_CCMR_CCS_INPUT_TI1 << 8) -#define TIMER_CCMR2_CC4S_INPUT_TI2 (TIMER_CCMR_CCS_INPUT_TI2 << 8) -#define TIMER_CCMR2_CC4S_INPUT_TRC (TIMER_CCMR_CCS_INPUT_TRC << 8) -#define TIMER_CCMR2_OC3CE (1U << TIMER_CCMR2_OC3CE_BIT) -#define TIMER_CCMR2_OC3M (0x3 << 4) -#define TIMER_CCMR2_IC3F (0xF << 4) -#define TIMER_CCMR2_OC3PE (1U << TIMER_CCMR2_OC3PE_BIT) -#define TIMER_CCMR2_OC3FE (1U << TIMER_CCMR2_OC3FE_BIT) -#define TIMER_CCMR2_IC3PSC (0x3 << 2) -#define TIMER_CCMR2_CC3S 0x3 -#define TIMER_CCMR2_CC3S_OUTPUT TIMER_CCMR_CCS_OUTPUT -#define TIMER_CCMR2_CC3S_INPUT_TI1 TIMER_CCMR_CCS_INPUT_TI1 -#define TIMER_CCMR2_CC3S_INPUT_TI2 TIMER_CCMR_CCS_INPUT_TI2 -#define TIMER_CCMR2_CC3S_INPUT_TRC TIMER_CCMR_CCS_INPUT_TRC - -/* Capture/compare enable register (CCER) */ - -#define TIMER_CCER_CC4P_BIT 13 -#define TIMER_CCER_CC4E_BIT 12 -#define TIMER_CCER_CC3NP_BIT 11 -#define TIMER_CCER_CC3NE_BIT 10 -#define TIMER_CCER_CC3P_BIT 9 -#define TIMER_CCER_CC3E_BIT 8 -#define TIMER_CCER_CC2NP_BIT 7 -#define TIMER_CCER_CC2NE_BIT 6 -#define TIMER_CCER_CC2P_BIT 5 -#define TIMER_CCER_CC2E_BIT 4 -#define TIMER_CCER_CC1NP_BIT 3 -#define TIMER_CCER_CC1NE_BIT 2 -#define TIMER_CCER_CC1P_BIT 1 -#define TIMER_CCER_CC1E_BIT 0 - -#define TIMER_CCER_CC4P (1U << TIMER_CCER_CC4P_BIT) -#define TIMER_CCER_CC4E (1U << TIMER_CCER_CC4E_BIT) -#define TIMER_CCER_CC3NP (1U << TIMER_CCER_CC3NP_BIT) -#define TIMER_CCER_CC3NE (1U << TIMER_CCER_CC3NE_BIT) -#define TIMER_CCER_CC3P (1U << TIMER_CCER_CC3P_BIT) -#define TIMER_CCER_CC3E (1U << TIMER_CCER_CC3E_BIT) -#define TIMER_CCER_CC2NP (1U << TIMER_CCER_CC2NP_BIT) -#define TIMER_CCER_CC2NE (1U << TIMER_CCER_CC2NE_BIT) -#define TIMER_CCER_CC2P (1U << TIMER_CCER_CC2P_BIT) -#define TIMER_CCER_CC2E (1U << TIMER_CCER_CC2E_BIT) -#define TIMER_CCER_CC1NP (1U << TIMER_CCER_CC1NP_BIT) -#define TIMER_CCER_CC1NE (1U << TIMER_CCER_CC1NE_BIT) -#define TIMER_CCER_CC1P (1U << TIMER_CCER_CC1P_BIT) -#define TIMER_CCER_CC1E (1U << TIMER_CCER_CC1E_BIT) - -/* Break and dead-time register (BDTR) */ - -#define TIMER_BDTR_MOE_BIT 15 -#define TIMER_BDTR_AOE_BIT 14 -#define TIMER_BDTR_BKP_BIT 13 -#define TIMER_BDTR_BKE_BIT 12 -#define TIMER_BDTR_OSSR_BIT 11 -#define TIMER_BDTR_OSSI_BIT 10 - -#define TIMER_BDTR_MOE (1U << TIMER_BDTR_MOE_BIT) -#define TIMER_BDTR_AOE (1U << TIMER_BDTR_AOE_BIT) -#define TIMER_BDTR_BKP (1U << TIMER_BDTR_BKP_BIT) -#define TIMER_BDTR_BKE (1U << TIMER_BDTR_BKE_BIT) -#define TIMER_BDTR_OSSR (1U << TIMER_BDTR_OSSR_BIT) -#define TIMER_BDTR_OSSI (1U << TIMER_BDTR_OSSI_BIT) -#define TIMER_BDTR_LOCK (0x3 << 8) -#define TIMER_BDTR_LOCK_OFF (0x0 << 8) -#define TIMER_BDTR_LOCK_LEVEL1 (0x1 << 8) -#define TIMER_BDTR_LOCK_LEVEL2 (0x2 << 8) -#define TIMER_BDTR_LOCK_LEVEL3 (0x3 << 8) -#define TIMER_BDTR_DTG 0xFF - -/* DMA control register (DCR) */ - -#define TIMER_DCR_DBL (0x1F << 8) -#define TIMER_DCR_DBL_1_XFER (0x0 << 8) -#define TIMER_DCR_DBL_2_XFER (0x1 << 8) -#define TIMER_DCR_DBL_3_XFER (0x2 << 8) -#define TIMER_DCR_DBL_4_XFER (0x3 << 8) -#define TIMER_DCR_DBL_5_XFER (0x4 << 8) -#define TIMER_DCR_DBL_6_XFER (0x5 << 8) -#define TIMER_DCR_DBL_7_XFER (0x6 << 8) -#define TIMER_DCR_DBL_8_XFER (0x7 << 8) -#define TIMER_DCR_DBL_9_XFER (0x8 << 8) -#define TIMER_DCR_DBL_10_XFER (0x9 << 8) -#define TIMER_DCR_DBL_11_XFER (0xA << 8) -#define TIMER_DCR_DBL_12_XFER (0xB << 8) -#define TIMER_DCR_DBL_13_XFER (0xC << 8) -#define TIMER_DCR_DBL_14_XFER (0xD << 8) -#define TIMER_DCR_DBL_15_XFER (0xE << 8) -#define TIMER_DCR_DBL_16_XFER (0xF << 8) -#define TIMER_DCR_DBL_17_XFER (0x10 << 8) -#define TIMER_DCR_DBL_18_XFER (0x11 << 8) -#define TIMER_DCR_DBA 0x1F -#define TIMER_DCR_DBA_CR1 0x0 -#define TIMER_DCR_DBA_CR2 0x1 -#define TIMER_DCR_DBA_SMCR 0x2 -#define TIMER_DCR_DBA_DIER 0x3 -#define TIMER_DCR_DBA_SR 0x4 -#define TIMER_DCR_DBA_EGR 0x5 -#define TIMER_DCR_DBA_CCMR1 0x6 -#define TIMER_DCR_DBA_CCMR2 0x7 -#define TIMER_DCR_DBA_CCER 0x8 -#define TIMER_DCR_DBA_CNT 0x9 -#define TIMER_DCR_DBA_PSC 0xA -#define TIMER_DCR_DBA_ARR 0xB -#define TIMER_DCR_DBA_RCR 0xC -#define TIMER_DCR_DBA_CCR1 0xD -#define TIMER_DCR_DBA_CCR2 0xE -#define TIMER_DCR_DBA_CCR3 0xF -#define TIMER_DCR_DBA_CCR4 0x10 -#define TIMER_DCR_DBA_BDTR 0x11 -#define TIMER_DCR_DBA_DCR 0x12 -#define TIMER_DCR_DBA_DMAR 0x13 - -/* - * Convenience routines - */ - -/** - * @brief Used to configure the behavior of a timer channel. - * - * Be careful: not all timers can be configured in every mode. - */ -typedef enum timer_mode { - /** - * The timer stops counting, channel interrupts are detached, and - * no state changes are output. */ - TIMER_DISABLED, - - /** PWM output. */ - TIMER_PWM, - - /* TIMER_PWM_CENTER_ALIGNED, TODO: Center-aligned PWM output mode. */ - - /** - * The timer counts from 0 to its reload value repeatedly; every - * time the counter value reaches one of the channel compare - * values, the corresponding interrupt is fired. */ - TIMER_OUTPUT_COMPARE, - - /* TIMER_INPUT_CAPTURE, TODO: In this mode, the timer can measure the - * pulse lengths of input signals */ - /* TIMER_ONE_PULSE, TODO: In this mode, the timer can generate a single - * pulse on a GPIO pin for a specified amount of - * time. */ -} timer_mode; - -/** Timer channel numbers */ -typedef enum timer_channel { - TIMER_CH1 = 1, /**< Channel 1 */ - TIMER_CH2 = 2, /**< Channel 2 */ - TIMER_CH3 = 3, /**< Channel 3 */ - TIMER_CH4 = 4 /**< Channel 4 */ -} timer_channel; - -/* - * Note: Don't require timer_channel arguments! We want to be able to say - * - * for (int channel = 1; channel <= 4; channel++) { - * ... - * } - * - * without the compiler yelling at us. - */ - -void timer_init(timer_dev *dev); -void timer_disable(timer_dev *dev); -void timer_set_mode(timer_dev *dev, uint8 channel, timer_mode mode); -void timer_foreach(void (*fn)(timer_dev*)); -int timer_has_cc_channel(timer_dev *dev, uint8 channel); - -/** - * @brief Timer interrupt number. - * - * Not all timers support all of these values. All timers support - * TIMER_UPDATE_INTERRUPT. "General purpose" timers can be a special - * nuisance in this regard, as they individually support different - * subsets of the available interupts. Consult your target's reference - * manual for the details. - */ -typedef enum timer_interrupt_id { - TIMER_UPDATE_INTERRUPT, /**< Update interrupt. */ - TIMER_CC1_INTERRUPT, /**< Capture/compare 1 interrupt. */ - TIMER_CC2_INTERRUPT, /**< Capture/compare 2 interrupt. */ - TIMER_CC3_INTERRUPT, /**< Capture/compare 3 interrupt. */ - TIMER_CC4_INTERRUPT, /**< Capture/compare 4 interrupt. */ - TIMER_COM_INTERRUPT, /**< COM interrupt. */ - TIMER_TRG_INTERRUPT, /**< Trigger interrupt. */ - TIMER_BREAK_INTERRUPT, /**< Break interrupt. */ -} timer_interrupt_id; - -void timer_attach_interrupt(timer_dev *dev, - uint8 interrupt, - voidFuncPtr handler); -void timer_detach_interrupt(timer_dev *dev, uint8 interrupt); - -/** - * Initialize all timer devices on the chip. - */ -static inline void timer_init_all(void) { - timer_foreach(timer_init); -} - -/** - * Disables all timers on the device. - */ -static inline void timer_disable_all(void) { - timer_foreach(timer_disable); -} - -/** - * @brief Stop a timer's counter from changing. - * - * Does not affect the timer's mode or other settings. - * - * @param dev Device whose counter to pause. - */ -static inline void timer_pause(timer_dev *dev) { - *bb_perip(&(dev->regs).bas->CR1, TIMER_CR1_CEN_BIT) = 0; -} - -/** - * @brief Start a timer's counter. - * - * Does not affect the timer's mode or other settings. - * - * @param dev Device whose counter to resume - */ -static inline void timer_resume(timer_dev *dev) { - *bb_perip(&(dev->regs).bas->CR1, TIMER_CR1_CEN_BIT) = 1; -} - -/** - * @brief Returns the timer's counter value. - * - * This value is likely to be inaccurate if the counter is running - * with a low prescaler. - * - * @param dev Timer whose counter to return - */ -static inline uint16 timer_get_count(timer_dev *dev) { - return (uint16)(dev->regs).bas->CNT; -} - -/** - * @brief Sets the counter value for the given timer. - * @param dev Timer whose counter to set - * @param value New counter value - */ -static inline void timer_set_count(timer_dev *dev, uint16 value) { - (dev->regs).bas->CNT = value; -} - -/** - * @brief Returns the given timer's prescaler. - * - * Note that if the timer's prescaler is set (e.g. via - * timer_set_prescaler() or accessing a TIMx_PSC register), the value - * returned by this function will reflect the new setting, but the - * timer's counter will only reflect the new prescaler at the next - * update event. - * - * @param dev Timer whose prescaler to return - * @see timer_generate_update() - */ -static inline uint16 timer_get_prescaler(timer_dev *dev) { - return (uint16)(dev->regs).bas->PSC; -} - -/** - * @brief Set a timer's prescale value. - * - * Divides the input clock by (PSC+1). The new value will not take - * effect until the next update event. - * - * @param dev Timer whose prescaler to set - * @param psc New prescaler value - * @see timer_generate_update() - */ -static inline void timer_set_prescaler(timer_dev *dev, uint16 psc) { - (dev->regs).bas->PSC = psc; -} - -/** - * @brief Returns a timer's reload value. - * @param dev Timer whose reload value to return - */ -static inline uint16 timer_get_reload(timer_dev *dev) { - return (uint16)(dev->regs).bas->ARR; -} - -/** - * @brief Set a timer's reload value. - * @param dev Timer whose reload value to set - * @param arr New reload value to use. Takes effect at next update event. - * @see timer_generate_update() - */ -static inline void timer_set_reload(timer_dev *dev, uint16 arr) { - (dev->regs).bas->ARR = arr; -} - -/** - * @brief Get the compare value for the given timer channel. - * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. - * @param channel Channel whose compare value to get. - */ -static inline uint16 timer_get_compare(timer_dev *dev, uint8 channel) { - __IO uint32 *ccr = &(dev->regs).gen->CCR1 + (channel - 1); - return *ccr; -} - -/** - * @brief Set the compare value for the given timer channel. - * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. - * @param channel Channel whose compare value to set. - * @param value New compare value. - */ -static inline void timer_set_compare(timer_dev *dev, - uint8 channel, - uint16 value) { - __IO uint32 *ccr = &(dev->regs).gen->CCR1 + (channel - 1); - *ccr = value; -} - -/** - * @brief Generate an update event for the given timer. - * - * Normally, this will cause the prescaler and auto-reload values in - * the PSC and ARR registers to take immediate effect. However, this - * function will do nothing if the UDIS bit is set in the timer's CR1 - * register (UDIS is cleared by default). - * - * @param dev Timer device to generate an update for. - */ -static inline void timer_generate_update(timer_dev *dev) { - *bb_perip(&(dev->regs).bas->EGR, TIMER_EGR_UG_BIT) = 1; -} - -/** - * @brief Enable a timer's trigger DMA request - * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL - */ -static inline void timer_dma_enable_trg_req(timer_dev *dev) { - *bb_perip(&(dev->regs).gen->DIER, TIMER_DIER_TDE_BIT) = 1; -} - -/** - * @brief Disable a timer's trigger DMA request - * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL - */ -static inline void timer_dma_disable_trg_req(timer_dev *dev) { - *bb_perip(&(dev->regs).gen->DIER, TIMER_DIER_TDE_BIT) = 0; -} - -/** - * @brief Enable a timer channel's DMA request. - * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL - * @param channel Channel whose DMA request to enable. - */ -static inline void timer_dma_enable_req(timer_dev *dev, uint8 channel) { - *bb_perip(&(dev->regs).gen->DIER, channel + 8) = 1; -} - -/** - * @brief Disable a timer channel's DMA request. - * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. - * @param channel Channel whose DMA request to disable. - */ -static inline void timer_dma_disable_req(timer_dev *dev, uint8 channel) { - *bb_perip(&(dev->regs).gen->DIER, channel + 8) = 0; -} - -/** - * @brief Enable a timer interrupt. - * @param dev Timer device. - * @param interrupt Interrupt number to enable; this may be any - * timer_interrupt_id value appropriate for the timer. - * @see timer_interrupt_id - * @see timer_channel - */ -static inline void timer_enable_irq(timer_dev *dev, uint8 interrupt) { - *bb_perip(&(dev->regs).adv->DIER, interrupt) = 1; -} - -/** - * @brief Disable a timer interrupt. - * @param dev Timer device. - * @param interrupt Interrupt number to disable; this may be any - * timer_interrupt_id value appropriate for the timer. - * @see timer_interrupt_id - * @see timer_channel - */ -static inline void timer_disable_irq(timer_dev *dev, uint8 interrupt) { - *bb_perip(&(dev->regs).adv->DIER, interrupt) = 0; -} - -/** - * @brief Enable a timer channel's capture/compare signal. - * - * If the channel is configured as output, the corresponding output - * compare signal will be output on the corresponding output pin. If - * the channel is configured as input, enables capture of the counter - * value into the input capture/compare register. - * - * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. - * @param channel Channel to enable, from 1 to 4. - */ -static inline void timer_cc_enable(timer_dev *dev, uint8 channel) { - *bb_perip(&(dev->regs).gen->CCER, 4 * (channel - 1)) = 1; -} - -/** - * @brief Disable a timer channel's output compare or input capture signal. - * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. - * @param channel Channel to disable, from 1 to 4. - * @see timer_cc_enable() - */ -static inline void timer_cc_disable(timer_dev *dev, uint8 channel) { - *bb_perip(&(dev->regs).gen->CCER, 4 * (channel - 1)) = 0; -} - -/** - * @brief Get a channel's capture/compare output polarity - * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. - * @param channel Channel whose capture/compare output polarity to get. - * @return Polarity, either 0 or 1. - * @see timer_cc_set_polarity() - */ -static inline uint8 timer_cc_get_pol(timer_dev *dev, uint8 channel) { - return *bb_perip(&(dev->regs).gen->CCER, 4 * (channel - 1) + 1); -} - -/** - * @brief Set a timer channel's capture/compare output polarity. - * - * If the timer channel is configured as output: polarity == 0 means - * the output channel will be active high; polarity == 1 means active - * low. - * - * If the timer channel is configured as input: polarity == 0 means - * capture is done on the rising edge of ICn; when used as an external - * trigger, ICn is non-inverted. polarity == 1 means capture is done - * on the falling edge of ICn; when used as an external trigger, ICn - * is inverted. - * - * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. - * @param channel Channel whose capture/compare output polarity to set. - * @param pol New polarity, 0 or 1. - */ -static inline void timer_cc_set_pol(timer_dev *dev, uint8 channel, uint8 pol) { - *bb_perip(&(dev->regs).gen->CCER, 4 * (channel - 1) + 1) = pol; -} - -/** - * @brief Get a timer's DMA burst length. - * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. - * @return Number of transfers per read or write to timer DMA register, - * from 1 to 18. - */ -static inline uint8 timer_dma_get_burst_len(timer_dev *dev) { - uint32 dbl = ((dev->regs).gen->DCR & TIMER_DCR_DBL) >> 8; - return dbl + 1; /* 0 means 1 transfer, etc. */ -} - -/** - * @brief Set a timer's DMA burst length. - * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. - * @param length DMA burst length; i.e., number of DMA transfers per - * read/write to timer DMA register, from 1 to 18. - */ -static inline void timer_dma_set_burst_len(timer_dev *dev, uint8 length) { - uint32 tmp = (dev->regs).gen->DCR; - tmp &= ~TIMER_DCR_DBL; - tmp |= (length - 1) << 8; - (dev->regs).gen->DCR = tmp; -} - -/** - * @brief Timer DMA base address. - * - * Defines the base address for DMA transfers. - */ -typedef enum timer_dma_base_addr { - /** Base is control register 1 */ - TIMER_DMA_BASE_CR1 = TIMER_DCR_DBA_CR1, - /** Base is control register 2 */ - TIMER_DMA_BASE_CR2 = TIMER_DCR_DBA_CR2, - /** Base is slave mode control register */ - TIMER_DMA_BASE_SMCR = TIMER_DCR_DBA_SMCR, - /** Base is DMA interrupt enable register */ - TIMER_DMA_BASE_DIER = TIMER_DCR_DBA_DIER, - /** Base is status register */ - TIMER_DMA_BASE_SR = TIMER_DCR_DBA_SR, - /** Base is event generation register */ - TIMER_DMA_BASE_EGR = TIMER_DCR_DBA_EGR, - /** Base is capture/compare mode register 1 */ - TIMER_DMA_BASE_CCMR1 = TIMER_DCR_DBA_CCMR1, - /** Base is capture/compare mode register 2 */ - TIMER_DMA_BASE_CCMR2 = TIMER_DCR_DBA_CCMR2, - /** Base is capture/compare enable register */ - TIMER_DMA_BASE_CCER = TIMER_DCR_DBA_CCER, - /** Base is counter */ - TIMER_DMA_BASE_CNT = TIMER_DCR_DBA_CNT, - /** Base is prescaler */ - TIMER_DMA_BASE_PSC = TIMER_DCR_DBA_PSC, - /** Base is auto-reload register */ - TIMER_DMA_BASE_ARR = TIMER_DCR_DBA_ARR, - /** Base is repetition counter register */ - TIMER_DMA_BASE_RCR = TIMER_DCR_DBA_RCR, - /** Base is capture/compare register 1 */ - TIMER_DMA_BASE_CCR1 = TIMER_DCR_DBA_CCR1, - /** Base is capture/compare register 2 */ - TIMER_DMA_BASE_CCR2 = TIMER_DCR_DBA_CCR2, - /** Base is capture/compare register 3 */ - TIMER_DMA_BASE_CCR3 = TIMER_DCR_DBA_CCR3, - /** Base is capture/compare register 4 */ - TIMER_DMA_BASE_CCR4 = TIMER_DCR_DBA_CCR4, - /** Base is break and dead-time register */ - TIMER_DMA_BASE_BDTR = TIMER_DCR_DBA_BDTR, - /** Base is DMA control register */ - TIMER_DMA_BASE_DCR = TIMER_DCR_DBA_DCR, - /** Base is DMA address for full transfer */ - TIMER_DMA_BASE_DMAR = TIMER_DCR_DBA_DMAR, -} timer_dma_base_addr; - -/** - * @brief Get the timer's DMA base address. - * - * Some restrictions apply; see the reference manual for your chip. - * - * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. - * @return DMA base address - */ -static inline timer_dma_base_addr timer_dma_get_base_addr(timer_dev *dev) { - uint32 dcr = (dev->regs).gen->DCR; - return (timer_dma_base_addr)(dcr & TIMER_DCR_DBA); -} - -/** - * @brief Set the timer's DMA base address. - * - * Some restrictions apply; see the reference manual for your chip. - * - * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. - * @param dma_base DMA base address. - */ -static inline void timer_dma_set_base_addr(timer_dev *dev, - timer_dma_base_addr dma_base) { - uint32 tmp = (dev->regs).gen->DCR; - tmp &= ~TIMER_DCR_DBA; - tmp |= dma_base; - (dev->regs).gen->DCR = tmp; -} - -/** - * Timer output compare modes. - */ -typedef enum timer_oc_mode { - /** - * Frozen: comparison between output compare register and counter - * has no effect on the outputs. */ - TIMER_OC_MODE_FROZEN = 0 << 4, - /** - * OCxREF signal is forced high when the count matches the channel - * capture/compare register. */ - TIMER_OC_MODE_ACTIVE_ON_MATCH = 1 << 4, - /** - * OCxREF signal is forced low when the counter matches the - * channel capture/compare register. */ - TIMER_OC_MODE_INACTIVE_ON_MATCH = 2 << 4, - /** - * OCxREF toggles when counter matches the channel capture/compare - * register. */ - TIMER_OC_MODE_TOGGLE = 3 << 4, - /** OCxREF is forced low. */ - TIMER_OC_MODE_FORCE_INACTIVE = 4 << 4, - /** OCxREF is forced high. */ - TIMER_OC_MODE_FORCE_ACTIVE = 5 << 4, - /** - * PWM mode 1. In upcounting, channel is active as long as count - * is less than channel capture/compare register, else inactive. - * In downcounting, channel is inactive as long as count exceeds - * capture/compare register, else active. */ - TIMER_OC_MODE_PWM_1 = 6 << 4, - /** - * PWM mode 2. In upcounting, channel is inactive as long as count - * is less than capture/compare register, else active. In - * downcounting, channel is active as long as count exceeds - * capture/compare register, else inactive. */ - TIMER_OC_MODE_PWM_2 = 7 << 4, -} timer_oc_mode; - -/** - * Timer output compare mode flags. - * @see timer_oc_set_mode() - */ -typedef enum timer_oc_mode_flags { - TIMER_OC_CE = 1U << 7, /**< Output compare clear enable. */ - TIMER_OC_PE = 1U << 3, /**< Output compare preload enable. */ - TIMER_OC_FE = 1U << 2, /**< Output compare fast enable. */ -} timer_oc_mode_flags; - -/** - * @brief Configure a channel's output compare mode. - * - * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. - * @param channel Channel to configure in output compare mode. - * @param mode Timer mode to set. - * @param flags OR of timer_oc_mode_flags. - * @see timer_oc_mode - * @see timer_oc_mode_flags - */ -static inline void timer_oc_set_mode(timer_dev *dev, - uint8 channel, - timer_oc_mode mode, - uint8 flags) { - /* channel == 1,2 -> CCMR1; channel == 3,4 -> CCMR2 */ - __IO uint32 *ccmr = &(dev->regs).gen->CCMR1 + (((channel - 1) >> 1) & 1); - /* channel == 1,3 -> shift = 0, channel == 2,4 -> shift = 8 */ - uint8 shift = 8 * (1 - (channel & 1)); - - uint32 tmp = *ccmr; - tmp &= ~(0xFF << shift); - tmp |= (mode | flags | TIMER_CCMR_CCS_OUTPUT) << shift; - *ccmr = tmp; -} - -/* - * Old, erroneous bit definitions from previous releases, kept for - * backwards compatibility: - */ - -/** Deprecated. Use TIMER_CCMR1_CC4S_OUTPUT instead. */ -#define TIMER_CCMR1_CC4S_OUTPUT TIMER_CCMR2_CC4S_OUTPUT -/** Deprecated. Use TIMER_CCMR1_CC4S_INPUT_TI1 instead. */ -#define TIMER_CCMR1_CC4S_INPUT_TI1 TIMER_CCMR2_CC4S_INPUT_TI1 -/** Deprecated. Use TIMER_CCMR1_CC4S_INPUT_TI2 instead. */ -#define TIMER_CCMR1_CC4S_INPUT_TI2 TIMER_CCMR2_CC4S_INPUT_TI2 -/** Deprecated. Use TIMER_CCMR1_CC4S_INPUT_TRC instead. */ -#define TIMER_CCMR1_CC4S_INPUT_TRC TIMER_CCMR2_CC4S_INPUT_TRC -/** Deprecated. Use TIMER_CCMR2_IC4F instead. */ -#define TIMER_CCMR2_IC2F TIMER_CCMR2_IC4F -/** Deprecated. Use TIMER_CCMR2_IC4PSC instead. */ -#define TIMER_CCMR2_IC2PSC TIMER_CCMR2_IC4PSC -/** Deprecated. Use TIMER_CCMR2_IC3F instead. */ -#define TIMER_CCMR2_IC1F TIMER_CCMR2_IC3F -/** Deprecated. Use TIMER_CCMR2_IC3PSC instead. */ -#define TIMER_CCMR2_IC1PSC TIMER_CCMR2_IC3PSC -/** Deprecated. Use TIMER_CCMR1_CC3S_OUTPUT instead. */ -#define TIMER_CCMR1_CC3S_OUTPUT TIMER_CCMR2_CC3S_OUTPUT -/** Deprecated. Use TIMER_CCMR1_CC3S_INPUT_TI1 instead. */ -#define TIMER_CCMR1_CC3S_INPUT_TI1 TIMER_CCMR2_CC3S_INPUT_TI1 -/** Deprecated. Use TIMER_CCMR1_CC3S_INPUT_TI2 instead. */ -#define TIMER_CCMR1_CC3S_INPUT_TI2 TIMER_CCMR2_CC3S_INPUT_TI2 -/** Deprecated. Use TIMER_CCMR1_CC3S_INPUT_TRC instead. */ -#define TIMER_CCMR1_CC3S_INPUT_TRC TIMER_CCMR2_CC3S_INPUT_TRC - -/** Deprecated. Use TIMER_DCR_DBL_1_XFER instead. */ -#define TIMER_DCR_DBL_1BYTE TIMER_DCR_DBL_1_XFER -/** Deprecated. Use TIMER_DCR_DBL_2_XFER instead. */ -#define TIMER_DCR_DBL_2BYTE TIMER_DCR_DBL_2_XFER -/** Deprecated. Use TIMER_DCR_DBL_3_XFER instead. */ -#define TIMER_DCR_DBL_3BYTE TIMER_DCR_DBL_3_XFER -/** Deprecated. Use TIMER_DCR_DBL_4_XFER instead. */ -#define TIMER_DCR_DBL_4BYTE TIMER_DCR_DBL_4_XFER -/** Deprecated. Use TIMER_DCR_DBL_5_XFER instead. */ -#define TIMER_DCR_DBL_5BYTE TIMER_DCR_DBL_5_XFER -/** Deprecated. Use TIMER_DCR_DBL_6_XFER instead. */ -#define TIMER_DCR_DBL_6BYTE TIMER_DCR_DBL_6_XFER -/** Deprecated. Use TIMER_DCR_DBL_7_XFER instead. */ -#define TIMER_DCR_DBL_7BYTE TIMER_DCR_DBL_7_XFER -/** Deprecated. Use TIMER_DCR_DBL_8_XFER instead. */ -#define TIMER_DCR_DBL_8BYTE TIMER_DCR_DBL_8_XFER -/** Deprecated. Use TIMER_DCR_DBL_9_XFER instead. */ -#define TIMER_DCR_DBL_9BYTE TIMER_DCR_DBL_9_XFER -/** Deprecated. Use TIMER_DCR_DBL_10_XFER instead. */ -#define TIMER_DCR_DBL_10BYTE TIMER_DCR_DBL_10_XFER -/** Deprecated. Use TIMER_DCR_DBL_11_XFER instead. */ -#define TIMER_DCR_DBL_11BYTE TIMER_DCR_DBL_11_XFER -/** Deprecated. Use TIMER_DCR_DBL_12_XFER instead. */ -#define TIMER_DCR_DBL_12BYTE TIMER_DCR_DBL_12_XFER -/** Deprecated. Use TIMER_DCR_DBL_13_XFER instead. */ -#define TIMER_DCR_DBL_13BYTE TIMER_DCR_DBL_13_XFER -/** Deprecated. Use TIMER_DCR_DBL_14_XFER instead. */ -#define TIMER_DCR_DBL_14BYTE TIMER_DCR_DBL_14_XFER -/** Deprecated. Use TIMER_DCR_DBL_15_XFER instead. */ -#define TIMER_DCR_DBL_15BYTE TIMER_DCR_DBL_15_XFER -/** Deprecated. Use TIMER_DCR_DBL_16_XFER instead. */ -#define TIMER_DCR_DBL_16BYTE TIMER_DCR_DBL_16_XFER -/** Deprecated. Use TIMER_DCR_DBL_17_XFER instead. */ -#define TIMER_DCR_DBL_17BYTE TIMER_DCR_DBL_17_XFER -/** Deprecated. Use TIMER_DCR_DBL_18_XFER instead. */ -#define TIMER_DCR_DBL_18BYTE TIMER_DCR_DBL_18_XFER - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/usart.h b/STM32F3/cores/maple/libmaple/include/libmaple/usart.h deleted file mode 100644 index 82b1b7d..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/usart.h +++ /dev/null @@ -1,464 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/include/libmaple/usart.h - * @author Marti Bolivar , - * Perry Hung , - * F3-port by Hanspeter Portner - * @brief USART definitions and prototypes - */ - -#ifndef _LIBMAPLE_USART_H_ -#define _LIBMAPLE_USART_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -#include -#include -#include -#include -#include -#include - -/* - * Register bit definitions - */ - -/* Status register */ - -/** Line break detection bit */ -#define USART_SR_LBD_BIT 8 -/** Transmit data register empty bit */ -#define USART_SR_TXE_BIT 7 -/** Transmission complete bit */ -#define USART_SR_TC_BIT 6 -/** Read data register not empty bit */ -#define USART_SR_RXNE_BIT 5 -/** IDLE line detected bit */ -#define USART_SR_IDLE_BIT 4 -/** Overrun error bit */ -#define USART_SR_ORE_BIT 3 -/** Noise error bit */ -#define USART_SR_NE_BIT 2 -/** - * @brief Synonym for USART_SR_NE_BIT. - * - * Some series (e.g. STM32F2) use "NF" for "noise flag" instead of the - * original "NE" for "noise error". The meaning of the bit is - * unchanged, but the NF flag can be disabled when the line is - * noise-free. - * - * @see USART_SR_NE_BIT - */ -#define USART_SR_NF_BIT USART_SR_NE_BIT -/** Framing error bit */ -#define USART_SR_FE_BIT 1 -/** Parity error bit */ -#define USART_SR_PE_BIT 0 - -/** Line break detected mask */ -#define USART_SR_LBD BIT(USART_SR_LBD_BIT) -/** Transmit data register empty mask */ -#define USART_SR_TXE BIT(USART_SR_TXE_BIT) -/** Transmission complete mask */ -#define USART_SR_TC BIT(USART_SR_TC_BIT) -/** Read data register not empty mask */ -#define USART_SR_RXNE BIT(USART_SR_RXNE_BIT) -/** IDLE line detected mask */ -#define USART_SR_IDLE BIT(USART_SR_IDLE_BIT) -/** Overrun error mask */ -#define USART_SR_ORE BIT(USART_SR_ORE_BIT) -/** Noise error mask */ -#define USART_SR_NE BIT(USART_SR_NE_BIT) -/** - * @brief Synonym for USART_SR_NE. - * @see USART_SR_NF_BIT - */ -#define USART_SR_NF USART_SR_NE -/** Framing error mask */ -#define USART_SR_FE BIT(USART_SR_FE_BIT) -/** Parity error mask */ -#define USART_SR_PE BIT(USART_SR_PE_BIT) - -/* Data register */ - -/** Data register data value mask */ -#define USART_DR_DR 0xFF - -/* Baud rate register */ - -/** Mantissa of USARTDIV mask */ -#define USART_BRR_DIV_MANTISSA (0xFFF << 4) -/** Fraction of USARTDIV mask */ -#define USART_BRR_DIV_FRACTION 0xF - -/* Control register 1 */ - -/** Word length bit */ -#define USART_CR1_M_BIT 12 -/** Wakeup method bit */ -#define USART_CR1_WAKE_BIT 11 -/** Parity control enable bit */ -#define USART_CR1_PCE_BIT 10 -/** Parity selection bit */ -#define USART_CR1_PS_BIT 9 -/** Parity error interrupt enable bit */ -#define USART_CR1_PEIE_BIT 8 -/** Transmit data regsiter not empty interrupt enable bit */ -#define USART_CR1_TXEIE_BIT 7 -/** Transmission complete interrupt enable bit */ -#define USART_CR1_TCIE_BIT 6 -/** RXNE interrupt enable bit */ -#define USART_CR1_RXNEIE_BIT 5 -/** IDLE interrupt enable bit */ -#define USART_CR1_IDLEIE_BIT 4 -/** Transmitter enable bit */ -#define USART_CR1_TE_BIT 3 -/** Receiver enable bit */ -#define USART_CR1_RE_BIT 2 - -/** Word length mask */ -#define USART_CR1_M BIT(USART_CR1_M_BIT) -/** Word length: 1 start bit, 8 data bits, n stop bit */ -#define USART_CR1_M_8N1 (0 << USART_CR1_M_BIT) -/** Word length: 1 start bit, 9 data bits, n stop bit */ -#define USART_CR1_M_9N1 (1 << USART_CR1_M_BIT) -/** Wakeup method mask */ -#define USART_CR1_WAKE BIT(USART_CR1_WAKE_BIT) -/** Wakeup on idle line */ -#define USART_CR1_WAKE_IDLE (0 << USART_CR1_WAKE_BIT) -/** Wakeup on address mark */ -#define USART_CR1_WAKE_ADDR (1 << USART_CR1_WAKE_BIT) -/** Parity control enable mask */ -#define USART_CR1_PCE BIT(USART_CR1_PCE_BIT) -/** Parity selection mask */ -#define USART_CR1_PS BIT(USART_CR1_PS_BIT) -/** Parity selection: even parity */ -#define USART_CR1_PS_EVEN (0 << USART_CR1_PS_BIT) -/** Parity selection: odd parity */ -#define USART_CR1_PS_ODD (1 << USART_CR1_PS_BIT) -/** Parity error interrupt enable mask */ -#define USART_CR1_PEIE BIT(USART_CR1_PEIE_BIT) -/** Transmit data register empty interrupt enable mask */ -#define USART_CR1_TXEIE BIT(USART_CR1_TXEIE_BIT) -/** Transmission complete interrupt enable mask */ -#define USART_CR1_TCIE BIT(USART_CR1_TCIE_BIT) -/** RXNE interrupt enable mask */ -#define USART_CR1_RXNEIE BIT(USART_CR1_RXNEIE_BIT) -/** IDLE line interrupt enable mask */ -#define USART_CR1_IDLEIE BIT(USART_CR1_IDLEIE_BIT) -/** Transmitter enable mask */ -#define USART_CR1_TE BIT(USART_CR1_TE_BIT) -/** Receiver enable mask */ -#define USART_CR1_RE BIT(USART_CR1_RE_BIT) - -/* Control register 2 */ - -/** LIN mode enable bit */ -#define USART_CR2_LINEN_BIT 14 -/** Clock enable bit */ -#define USART_CR2_CLKEN_BIT 11 -/** Clock polarity bit */ -#define USART_CR2_CPOL_BIT 10 -/** Clock phase bit */ -#define USART_CR2_CPHA_BIT 9 -/** Last bit clock pulse bit */ -#define USART_CR2_LBCL_BIT 8 -/** LIN break detection interrupt enable bit */ -#define USART_CR2_LBDIE_BIT 6 -/** LIN break detection length bit */ -#define USART_CR2_LBDL_BIT 5 - -/** LIN mode enable mask */ -#define USART_CR2_LINEN BIT(USART_CR2_LINEN_BIT) -/** STOP bits mask */ -#define USART_CR2_STOP (0x3 << 12) -/** STOP bits: 1 stop bit */ -#define USART_CR2_STOP_BITS_1 (0x0 << 12) -/** - * @brief STOP bits: 0.5 stop bits - * Not available on UART4, UART5. */ -#define USART_CR2_STOP_BITS_POINT_5 (0x1 << 12) -/** STOP bits: 2 stop bits */ -#define USART_CR2_STOP_BITS_2 (0x2 << 12) -/** - * @brief STOP bits: 1.5 stop bits - * Not available on UART4, UART5. */ -#define USART_CR2_STOP_BITS_1_POINT_5 (0x3 << 12) -/** - * @brief Clock enable. - * Not available on UART4, UART5 */ -#define USART_CR2_CLKEN BIT(USART_CR2_CLKEN_BIT) -/** - * @brief Clock polarity mask. - * Not available on UART4, UART5 */ -#define USART_CR2_CPOL BIT(USART_CR2_CPOL_BIT) -/** Clock polarity: low */ -#define USART_CR2_CPOL_LOW (0x0 << USART_CR2_CLKEN_BIT) -/** Clock polarity: high */ -#define USART_CR2_CPOL_HIGH (0x1 << USART_CR2_CLKEN_BIT) -/** - * @brief Clock phase mask. - * Not available on UART4, UART5 */ -#define USART_CR2_CPHA BIT(USART_CR2_CPHA_BIT) -/** - * @brief Clock phase: first - * First clock transition is the first data capture edge. */ -#define USART_CR2_CPHA_FIRST (0x0 << USART_CR2_CPHA_BIT) -/** - * @brief Clock phase: second - * Second clock transition is the first data capture edge. */ -#define USART_CR2_CPHA_SECOND (0x1 << USART_CR2_CPHA_BIT) -/** - * @brief Last bit clock pulse mask. - * - * When set, the last bit transmitted causes a clock pulse in - * synchronous mode. - * - * Not available on UART4, UART5 */ -#define USART_CR2_LBCL BIT(USART_CR2_LBCL_BIT) -/** LIN break detection interrupt enable mask. */ -#define USART_CR2_LBDIE BIT(USART_CR2_LBDIE_BIT) -/** LIN break detection length. */ -#define USART_CR2_LBDL BIT(USART_CR2_LBDL_BIT) -/** LIN break detection length: 10 bits */ -#define USART_CR2_LBDL_10_BIT (0 << USART_CR2_LBDL_BIT) -/** LIN break detection length: 11 bits */ -#define USART_CR2_LBDL_11_BIT (1 << USART_CR2_LBDL_BIT) - -/* Control register 3 */ - -/** Clear to send interrupt enable bit */ -#define USART_CR3_CTSIE_BIT 10 -/** Clear to send enable bit */ -#define USART_CR3_CTSE_BIT 9 -/** Ready to send enable bit */ -#define USART_CR3_RTSE_BIT 8 -/** DMA enable transmitter bit */ -#define USART_CR3_DMAT_BIT 7 -/** DMA enable receiver bit */ -#define USART_CR3_DMAR_BIT 6 -/** Smartcard mode enable bit */ -#define USART_CR3_SCEN_BIT 5 -/** Smartcard NACK enable bit */ -#define USART_CR3_NACK_BIT 4 -/** Half-duplex selection bit */ -#define USART_CR3_HDSEL_BIT 3 -/** IrDA low power bit */ -#define USART_CR3_IRLP_BIT 2 -/** IrDA mode enable bit */ -#define USART_CR3_IREN_BIT 1 -/** Error interrupt enable bit */ -#define USART_CR3_EIE_BIT 0 - -/** - * @brief Clear to send interrupt enable - * Not available on UART4, UART5. */ -#define USART_CR3_CTSIE BIT(USART_CR3_CTSIE_BIT) -/** - * @brief Clear to send enable - * Not available on UART4, UART5. */ -#define USART_CR3_CTSE BIT(USART_CR3_CTSE_BIT) -/** - * @brief Ready to send enable - * Not available on UART4, UART5. */ -#define USART_CR3_RTSE BIT(USART_CR3_RTSE_BIT) -/** - * @brief DMA enable transmitter - * Not available on UART5. */ -#define USART_CR3_DMAT BIT(USART_CR3_DMAT_BIT) -/** - * @brief DMA enable receiver - * Not available on UART5. */ -#define USART_CR3_DMAR BIT(USART_CR3_DMAR_BIT) -/** - * @brief Smartcard mode enable - * Not available on UART4, UART5. */ -#define USART_CR3_SCEN BIT(USART_CR3_SCEN_BIT) -/** - * @brief Smartcard NACK enable - * Not available on UART4, UART5. */ -#define USART_CR3_NACK BIT(USART_CR3_NACK_BIT) -/** - * @brief Half-duplex selection - * When set, single-wire half duplex mode is selected. - */ -#define USART_CR3_HDSEL BIT(USART_CR3_HDSEL_BIT) -/** IrDA low power mode */ -#define USART_CR3_IRLP BIT(USART_CR3_IRLP_BIT) -/** IrDA mode: normal */ -#define USART_CR3_IRLP_NORMAL (0U << USART_CR3_IRLP_BIT) -/** IrDA mode: low power */ -#define USART_CR3_IRLP_LOW_POWER (1U << USART_CR3_IRLP_BIT) -/** IrDA mode enable */ -#define USART_CR3_IREN BIT(USART_CR3_IREN_BIT) -/** Error interrupt enable */ -#define USART_CR3_EIE BIT(USART_CR3_EIE_BIT) - -/* Guard time and prescaler register */ - -/** - * @brief Guard time value mask - * Used in Smartcard mode. Not available on UART4, UART5. */ -#define USART_GTPR_GT (0xFF << 8) -/** - * @brief Prescaler value mask - * Restrictions on this value apply, depending on the USART mode. Not - * available on UART4, UART5. */ -#define USART_GTPR_PSC 0xFF - -/* - * Devices - */ - -#ifndef USART_RX_BUF_SIZE -#define USART_RX_BUF_SIZE 64 -#endif - -/** USART device type */ -typedef struct usart_dev { - usart_reg_map *regs; /**< Register map */ - ring_buffer *rb; /**< RX ring buffer */ - uint32 max_baud; /**< @brief Deprecated. - * Maximum baud rate. */ - uint8 rx_buf[USART_RX_BUF_SIZE]; /**< @brief Deprecated. - * Actual RX buffer used by rb. - * This field will be removed in - * a future release. */ - rcc_clk_id clk_id; /**< RCC clock information */ - nvic_irq_num irq_num; /**< USART NVIC interrupt */ -} usart_dev; - -void usart_init(usart_dev *dev); - -struct gpio_dev; /* forward declaration */ -/* FIXME [PRE 0.0.13] decide if flags are necessary */ -/** - * @brief Configure GPIOs for use as USART TX/RX. - * @param udev USART device to use - * @param rx_dev RX pin gpio_dev - * @param rx RX pin bit on rx_dev - * @param tx_dev TX pin gpio_dev - * @param tx TX pin bit on tx_dev - * @param flags Currently ignored - */ -extern void usart_config_gpios_async(usart_dev *udev, - struct gpio_dev *rx_dev, uint8 rx, - struct gpio_dev *tx_dev, uint8 tx, - unsigned flags); - -#define USART_USE_PCLK 0 -void usart_set_baud_rate(usart_dev *dev, uint32 clock_speed, uint32 baud); - -void usart_enable(usart_dev *dev); -void usart_disable(usart_dev *dev); -void usart_foreach(void (*fn)(usart_dev *dev)); -/** - * @brief Nonblocking USART transmit - * @param dev Serial port to transmit over - * @param buf Buffer to transmit - * @param len Maximum number of bytes to transmit - * @return Number of bytes transmitted - */ -uint32 usart_tx(usart_dev *dev, const uint8 *buf, uint32 len); -uint32 usart_rx(usart_dev *dev, uint8 *buf, uint32 len); -void usart_putudec(usart_dev *dev, uint32 val); - -/** - * @brief Disable all serial ports. - */ -static inline void usart_disable_all(void) { - usart_foreach(usart_disable); -} - -/** - * @brief Transmit one character on a serial port. - * - * This function blocks until the character has been successfully - * transmitted. - * - * @param dev Serial port to send on. - * @param byte Byte to transmit. - */ -static inline void usart_putc(usart_dev* dev, uint8 byte) { - while (!usart_tx(dev, &byte, 1)) - ; -} - -/** - * @brief Transmit a character string on a serial port. - * - * This function blocks until str is completely transmitted. - * - * @param dev Serial port to send on - * @param str String to send - */ -static inline void usart_putstr(usart_dev *dev, const char* str) { - uint32 i = 0; - while (str[i] != '\0') { - usart_putc(dev, str[i++]); - } -} - -/** - * @brief Read one character from a serial port. - * - * It's not safe to call this function if the serial port has no data - * available. - * - * @param dev Serial port to read from - * @return byte read - * @see usart_data_available() - */ -static inline uint8 usart_getc(usart_dev *dev) { - return rb_remove(dev->rb); -} - -/** - * @brief Return the amount of data available in a serial port's RX buffer. - * @param dev Serial port to check - * @return Number of bytes in dev's RX buffer. - */ -static inline uint32 usart_data_available(usart_dev *dev) { - return rb_full_count(dev->rb); -} - -/** - * @brief Discard the contents of a serial port's RX buffer. - * @param dev Serial port whose buffer to empty. - */ -static inline void usart_reset_rx(usart_dev *dev) { - rb_reset(dev->rb); -} - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/usb.h b/STM32F3/cores/maple/libmaple/include/libmaple/usb.h deleted file mode 100644 index ea24030..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/usb.h +++ /dev/null @@ -1,176 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010, 2011, 2012 LeafLabs LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/* - * NOTE: This API is _unstable_ and will change drastically over time. - */ - -#ifndef _LIBMAPLE_USB_H_ -#define _LIBMAPLE_USB_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -/* - * Descriptors and other paraphernalia - */ - -/* Descriptor types */ - -#define USB_DESCRIPTOR_TYPE_DEVICE 0x01 -#define USB_DESCRIPTOR_TYPE_CONFIGURATION 0x02 -#define USB_DESCRIPTOR_TYPE_STRING 0x03 -#define USB_DESCRIPTOR_TYPE_INTERFACE 0x04 -#define USB_DESCRIPTOR_TYPE_ENDPOINT 0x05 - -/* Descriptor structs and declaration helpers */ - -#define USB_DESCRIPTOR_STRING_LEN(x) (2 + (x << 1)) - -#define USB_DESCRIPTOR_STRING(len) \ - struct { \ - uint8 bLength; \ - uint8 bDescriptorType; \ - uint16 bString[len]; \ - } __packed - -typedef struct usb_descriptor_device { - uint8 bLength; - uint8 bDescriptorType; - uint16 bcdUSB; - uint8 bDeviceClass; - uint8 bDeviceSubClass; - uint8 bDeviceProtocol; - uint8 bMaxPacketSize0; - uint16 idVendor; - uint16 idProduct; - uint16 bcdDevice; - uint8 iManufacturer; - uint8 iProduct; - uint8 iSerialNumber; - uint8 bNumConfigurations; -} __packed usb_descriptor_device; - -typedef struct usb_descriptor_config_header { - uint8 bLength; - uint8 bDescriptorType; - uint16 wTotalLength; - uint8 bNumInterfaces; - uint8 bConfigurationValue; - uint8 iConfiguration; - uint8 bmAttributes; - uint8 bMaxPower; -} __packed usb_descriptor_config_header; - -typedef struct usb_descriptor_interface { - uint8 bLength; - uint8 bDescriptorType; - uint8 bInterfaceNumber; - uint8 bAlternateSetting; - uint8 bNumEndpoints; - uint8 bInterfaceClass; - uint8 bInterfaceSubClass; - uint8 bInterfaceProtocol; - uint8 iInterface; -} __packed usb_descriptor_interface; - -typedef struct usb_descriptor_endpoint { - uint8 bLength; - uint8 bDescriptorType; - uint8 bEndpointAddress; - uint8 bmAttributes; - uint16 wMaxPacketSize; - uint8 bInterval; -} __packed usb_descriptor_endpoint; - -typedef struct usb_descriptor_string { - uint8 bLength; - uint8 bDescriptorType; - uint8 bString[]; -} usb_descriptor_string; - -/* Common values that go inside descriptors */ - -#define USB_CONFIG_ATTR_BUSPOWERED 0b10000000 -#define USB_CONFIG_ATTR_SELF_POWERED 0b11000000 - -#define USB_EP_TYPE_INTERRUPT 0x03 -#define USB_EP_TYPE_BULK 0x02 - -#define USB_DESCRIPTOR_ENDPOINT_IN 0x80 -#define USB_DESCRIPTOR_ENDPOINT_OUT 0x00 - -/* - * USB module core - */ - -#ifndef USB_ISR_MSK -/* Handle CTRM, WKUPM, SUSPM, ERRM, SOFM, ESOFM, RESETM */ -#define USB_ISR_MSK 0xBF00 -#endif - -typedef enum usb_dev_state { - USB_UNCONNECTED, - USB_ATTACHED, - USB_POWERED, - USB_SUSPENDED, - USB_ADDRESSED, - USB_CONFIGURED -} usb_dev_state; - -/* Encapsulates global state formerly handled by usb_lib/ */ -typedef struct usblib_dev { - uint32 irq_mask; - void (**ep_int_in)(void); - void (**ep_int_out)(void); - usb_dev_state state; - usb_dev_state prevState; - rcc_clk_id clk_id; -} usblib_dev; - -extern usblib_dev *USBLIB; - -void usb_init_usblib(usblib_dev *dev, - void (**ep_int_in)(void), - void (**ep_int_out)(void)); - -static inline uint8 usb_is_connected(usblib_dev *dev) { - return dev->state != USB_UNCONNECTED; -} - -static inline uint8 usb_is_configured(usblib_dev *dev) { - return dev->state == USB_CONFIGURED; -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/usb_cdcacm.h b/STM32F3/cores/maple/libmaple/include/libmaple/usb_cdcacm.h deleted file mode 100644 index 5fe832c..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/usb_cdcacm.h +++ /dev/null @@ -1,179 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2011 LeafLabs LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/include/libmaple/usb_cdcacm.h - * @brief USB CDC ACM (virtual serial terminal) support - * - * IMPORTANT: this API is unstable, and may change without notice. - */ - -#ifndef _LIBMAPLE_USB_CDCACM_H_ -#define _LIBMAPLE_USB_CDCACM_H_ - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * CDC ACM Requests - */ - -#define USB_CDCACM_SET_LINE_CODING 0x20 -#define USB_CDCACM_GET_LINE_CODING 0x21 -#define USB_CDCACM_SET_COMM_FEATURE 0x02 -#define USB_CDCACM_SET_CONTROL_LINE_STATE 0x22 -#define USB_CDCACM_CONTROL_LINE_DTR (0x01) -#define USB_CDCACM_CONTROL_LINE_RTS (0x02) - -/* - * Descriptors, etc. - */ - -#define CDC_FUNCTIONAL_DESCRIPTOR_SIZE(DataSize) (3 + DataSize) -#define CDC_FUNCTIONAL_DESCRIPTOR(DataSize) \ - struct { \ - uint8 bLength; \ - uint8 bDescriptorType; \ - uint8 SubType; \ - uint8 Data[DataSize]; \ - } __packed - -#define USB_DEVICE_CLASS_CDC 0x02 -#define USB_DEVICE_SUBCLASS_CDC 0x00 -#define USB_INTERFACE_CLASS_CDC 0x02 -#define USB_INTERFACE_SUBCLASS_CDC_ACM 0x02 -#define USB_INTERFACE_CLASS_DIC 0x0A - -/* - * Endpoint configuration - */ - -#define USB_CDCACM_CTRL_ENDP 0 -#define USB_CDCACM_CTRL_RX_ADDR 0x40 -#define USB_CDCACM_CTRL_TX_ADDR 0x80 -#define USB_CDCACM_CTRL_EPSIZE 0x40 - -#define USB_CDCACM_TX_ENDP 1 -#define USB_CDCACM_TX_ADDR 0xC0 -#define USB_CDCACM_TX_EPSIZE 0x40 - -#define USB_CDCACM_MANAGEMENT_ENDP 2 -#define USB_CDCACM_MANAGEMENT_ADDR 0x100 -#define USB_CDCACM_MANAGEMENT_EPSIZE 0x40 - -#define USB_CDCACM_RX_ENDP 3 -#define USB_CDCACM_RX_ADDR 0x110 -#define USB_CDCACM_RX_EPSIZE 0x40 - -#ifndef __cplusplus -#define USB_CDCACM_DECLARE_DEV_DESC(vid, pid) \ - { \ - .bLength = sizeof(usb_descriptor_device), \ - .bDescriptorType = USB_DESCRIPTOR_TYPE_DEVICE, \ - .bcdUSB = 0x0200, \ - .bDeviceClass = USB_DEVICE_CLASS_CDC, \ - .bDeviceSubClass = USB_DEVICE_SUBCLASS_CDC, \ - .bDeviceProtocol = 0x00, \ - .bMaxPacketSize0 = 0x40, \ - .idVendor = vid, \ - .idProduct = pid, \ - .bcdDevice = 0x0200, \ - .iManufacturer = 0x01, \ - .iProduct = 0x02, \ - .iSerialNumber = 0x00, \ - .bNumConfigurations = 0x01, \ - } -#endif - -/* - * CDC ACM interface - */ - -void usb_cdcacm_enable(gpio_dev*, uint8); -void usb_cdcacm_disable(gpio_dev*, uint8); - -void usb_cdcacm_putc(char ch); -uint32 usb_cdcacm_tx(const uint8* buf, uint32 len); -uint32 usb_cdcacm_rx(uint8* buf, uint32 len); -uint32 usb_cdcacm_peek(uint8* buf, uint32 len); - -uint32 usb_cdcacm_data_available(void); /* in RX buffer */ -uint16 usb_cdcacm_get_pending(void); -uint8 usb_cdcacm_is_transmitting(void); - -uint8 usb_cdcacm_get_dtr(void); -uint8 usb_cdcacm_get_rts(void); - -typedef struct usb_cdcacm_line_coding { - uint32 dwDTERate; /* Baud rate */ - -#define USB_CDCACM_STOP_BITS_1 0 -#define USB_CDCACM_STOP_BITS_1_5 1 -#define USB_CDCACM_STOP_BITS_2 2 - uint8 bCharFormat; /* Stop bits */ - -#define USB_CDCACM_PARITY_NONE 0 -#define USB_CDCACM_PARITY_ODD 1 -#define USB_CDCACM_PARITY_EVEN 2 -#define USB_CDCACM_PARITY_MARK 3 -#define USB_CDCACM_PARITY_SPACE 4 - uint8 bParityType; /* Parity type */ - - uint8 bDataBits; /* Data bits: 5, 6, 7, 8, or 16 */ -} __packed usb_cdcacm_line_coding; - -/* Retrieve a copy of the current line coding structure. */ -void usb_cdcacm_get_line_coding(usb_cdcacm_line_coding*); - -/* Line coding conveniences. */ -int usb_cdcacm_get_baud(void); /* dwDTERate */ -int usb_cdcacm_get_stop_bits(void); /* bCharFormat */ -int usb_cdcacm_get_parity(void); /* bParityType */ -int usb_cdcacm_get_n_data_bits(void); /* bDataBits */ - -/* - * Hack: hooks for bootloader reset signalling - */ - -#define USB_CDCACM_HOOK_RX 0x1 -#define USB_CDCACM_HOOK_IFACE_SETUP 0x2 - -void usb_cdcacm_set_hooks(unsigned hook_flags, void (*hook)(unsigned, void*)); - -static __always_inline void usb_cdcacm_remove_hooks(unsigned hook_flags) { - usb_cdcacm_set_hooks(hook_flags, 0); -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/include/libmaple/util.h b/STM32F3/cores/maple/libmaple/include/libmaple/util.h deleted file mode 100644 index 5a70348..0000000 --- a/STM32F3/cores/maple/libmaple/include/libmaple/util.h +++ /dev/null @@ -1,111 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/include/libmaple/util.h - * @brief Miscellaneous utility macros and procedures. - */ - -#ifndef _LIBMAPLE_UTIL_H_ -#define _LIBMAPLE_UTIL_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -#include - -/* - * Bit manipulation - */ - -/** 1UL shifted left by 'shift' */ -#define BIT(shift) (1UL << (shift)) -/** 'Mask' shifted left by 'shift' */ -#define BIT_MASK_SHIFT(mask, shift) ((mask) << (shift)) -/** Bits m to n of x */ -#define GET_BITS(x, m, n) ((((uint32)x) << (31 - (n))) >> ((31 - (n)) + (m))) -/** True iff v is a power of two (1, 2, 4, 8, ...) */ -#define IS_POWER_OF_TWO(v) ((v) && !((v) & ((v) - 1))) - -/* - * Failure routines - */ - -void __error(void); -void _fail(const char*, int, const char*); -void throb(void); - -/* - * Asserts and debug levels - */ - -#define DEBUG_NONE 0 -#define DEBUG_FAULT 1 -#define DEBUG_ALL 2 - -/** - * \def DEBUG_LEVEL - * - * Controls the level of assertion checking. - * - * The higher the debug level, the more assertions will be compiled - * in. This increases the amount of debugging information, but slows - * down (and increases the size of) the binary. - * - * The debug levels, from lowest to highest, are DEBUG_NONE, - * DEBUG_FAULT, and DEBUG_ALL. The default level is DEBUG_ALL. - */ - -#ifndef DEBUG_LEVEL -#define DEBUG_LEVEL DEBUG_ALL -#endif - -#if DEBUG_LEVEL >= DEBUG_ALL -#define ASSERT(exp) \ - if (exp) { \ - } else { \ - _fail(__FILE__, __LINE__, #exp); \ - } -#else -#define ASSERT(exp) (void)((0)) -#endif - -#if DEBUG_LEVEL >= DEBUG_FAULT -#define ASSERT_FAULT(exp) \ - if (exp) { \ - } else { \ - _fail(__FILE__, __LINE__, #exp); \ - } -#else -#define ASSERT_FAULT(exp) (void)((0)) -#endif - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/iwdg.c b/STM32F3/cores/maple/libmaple/iwdg.c deleted file mode 100644 index 2456235..0000000 --- a/STM32F3/cores/maple/libmaple/iwdg.c +++ /dev/null @@ -1,62 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Michael Hope. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/iwdg.c - * @brief Independent watchdog (IWDG) support - */ - -#include - -/** - * @brief Initialise and start the watchdog - * - * The prescaler and reload set the timeout. For example, a prescaler - * of IWDG_PRE_32 divides the 40 kHz clock by 32 and gives roughly 1 - * ms per reload. - * - * @param prescaler Prescaler for the 40 kHz IWDG clock. - * @param reload Independent watchdog counter reload value. - */ -void iwdg_init(iwdg_prescaler prescaler, uint16 reload) { - IWDG_BASE->KR = IWDG_KR_UNLOCK; - IWDG_BASE->PR = prescaler; - IWDG_BASE->RLR = reload; - - /* Start things off */ - IWDG_BASE->KR = IWDG_KR_START; - iwdg_feed(); -} - -/** - * @brief Reset the IWDG counter. - * - * Calling this function will cause the IWDG counter to be reset to - * its reload value. - */ -void iwdg_feed(void) { - IWDG_BASE->KR = IWDG_KR_FEED; -} diff --git a/STM32F3/cores/maple/libmaple/nvic.c b/STM32F3/cores/maple/libmaple/nvic.c deleted file mode 100644 index 149e780..0000000 --- a/STM32F3/cores/maple/libmaple/nvic.c +++ /dev/null @@ -1,103 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * Copyright (c) 2011 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/nvic.c - * @brief Nested vector interrupt controller support. - */ - -#include -#include -#include - -/** - * @brief Set interrupt priority for an interrupt line - * - * Note: The STM32 only implements 4 bits of priority, ignoring the - * lower 4 bits. This means there are only 16 levels of priority. - * Bits[3:0] read as zero and ignore writes. - * - * @param irqn device to set - * @param priority Priority to set, 0 being highest priority and 15 - * being lowest. - */ -void nvic_irq_set_priority(nvic_irq_num irqn, uint8 priority) { - if (irqn < 0) { - /* This interrupt is in the system handler block */ - SCB_BASE->SHP[((uint32)irqn & 0xF) - 4] = (priority & 0xF) << 4; - } else { - NVIC_BASE->IP[irqn] = (priority & 0xF) << 4; - } -} - -/** - * @brief Initialize the NVIC, setting interrupts to a default priority. - */ -void nvic_init(uint32 address, uint32 offset) { - uint32 i; - - nvic_set_vector_table(address, offset); - - /* - * Lower priority level for all peripheral interrupts to lowest - * possible. - */ - for (i = 0; i < STM32_NR_INTERRUPTS; i++) { - nvic_irq_set_priority((nvic_irq_num)i, 0xF); - } - - /* Lower systick interrupt priority to lowest level */ - nvic_irq_set_priority(NVIC_SYSTICK, 0xF); -} - -/** - * @brief Set the vector table base address. - * - * For stand-alone products, the vector table base address is normally - * the start of Flash (0x08000000). - * - * @param address Vector table base address. - * @param offset Offset from address. Some restrictions apply to the - * use of nonzero offsets; see the ARM Cortex M3 - * Technical Reference Manual. - */ -void nvic_set_vector_table(uint32 address, uint32 offset) { - SCB_BASE->VTOR = address | (offset & 0x1FFFFF80); -} - -/** - * @brief Force a system reset. - * - * Resets all major system components, excluding debug. - */ -void nvic_sys_reset() { - uint32 prigroup = SCB_BASE->AIRCR & SCB_AIRCR_PRIGROUP; - SCB_BASE->AIRCR = SCB_AIRCR_VECTKEY | SCB_AIRCR_SYSRESETREQ | prigroup; - asm volatile("dsb"); - while (1) - ; -} diff --git a/STM32F3/cores/maple/libmaple/pwr.c b/STM32F3/cores/maple/libmaple/pwr.c deleted file mode 100644 index 3cf170f..0000000 --- a/STM32F3/cores/maple/libmaple/pwr.c +++ /dev/null @@ -1,41 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2011 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/pwr.c - * @brief Power control (PWR) support. - */ - -#include -#include - -/** - * Enables the power interface clock, and resets the power device. - */ -void pwr_init(void) { - rcc_clk_enable(RCC_PWR); - rcc_reset_dev(RCC_PWR); -} diff --git a/STM32F3/cores/maple/libmaple/rcc.c b/STM32F3/cores/maple/libmaple/rcc.c deleted file mode 100644 index aba87c0..0000000 --- a/STM32F3/cores/maple/libmaple/rcc.c +++ /dev/null @@ -1,169 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * Copyright (c) 2011 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/rcc.c - * @brief Portable RCC routines. - */ - -#include - -#include "rcc_private.h" - -/** - * @brief Get a peripheral's clock domain - * @param id Clock ID of the peripheral whose clock domain to return - * @return Clock source for the given clock ID - */ -rcc_clk_domain rcc_dev_clk(rcc_clk_id id) { - return rcc_dev_table[id].clk_domain; -} - -/** - * @brief Switch the clock used as the source of the system clock. - * - * After switching the source, this function blocks until the new - * clock source is in use. - * - * @param sysclk_src New system clock source. - * @see rcc_sysclk_src - */ -void rcc_switch_sysclk(rcc_sysclk_src sysclk_src) { - uint32 cfgr = RCC_BASE->CFGR; - cfgr &= ~RCC_CFGR_SW; - cfgr |= sysclk_src; - - /* Switch SYSCLK source. */ - RCC_BASE->CFGR = cfgr; - - /* Wait for new source to come into use. */ - while ((RCC_BASE->CFGR & RCC_CFGR_SWS) != (sysclk_src << 2)) - ; -} - -/* - * Turning clocks off and on, querying their status. - */ - -/* IMPORTANT NOTE FOR IMPLEMENTORS: - * - * libmaple assumes that enum rcc_clk enumerators are two-byte - * values, stored in a uint16, in the following way: - * - * - The high-order byte is the byte offset (from RCC_BASE) of the register - * to touch when turning on or off the given clock. - * - * - The low-order byte is the bit in that register that turns the - * clock on or off. - * - * Example for STM32F1: Turning on the high-speed external clock (HSE) - * involves setting HSEON, bit 16, of RCC_CR. The high-order byte is - * then offsetof(struct rcc_reg_map, CR) = 0, and the low-order byte - * is 16. - * - * The corresponding value of RCC_CLK_HSE is thus (0 << 8) | 16 = 16. - * - * On all known STM32 series, this encoding has the property that - * adding one to the low byte also gives the bit to check to determine - * if the clock is ready. For example, on STM32F1, RCC_CR_HSERDY is - * bit 17. If that's not the case on your series, rcc_is_clk_ready() - * won't work for you. */ - -/* Returns the RCC register which controls the clock source. */ -static inline __IO uint32* rcc_clk_reg(rcc_clk clock) { - return (__IO uint32*)((__IO uint8*)RCC_BASE + (clock >> 8)); -} - -/* Returns a mask in rcc_clk_reg(clock) to be used for turning the - * clock on and off */ -static inline uint32 rcc_clk_on_mask(rcc_clk clock) { - return 1 << (clock & 0xFF); -} - -/* Returns a mask in rcc_clk_reg(clock) to be used when checking the - * readiness of the clock. */ -static inline uint32 rcc_clk_ready_mask(rcc_clk clock) { - return rcc_clk_on_mask(clock) << 1; -} - -/** - * @brief Turn on a clock source. - * - * After this routine exits, callers should ensure that the clock - * source is ready by waiting until rcc_is_clk_ready(clock) returns - * true. - * - * @param clock Clock to turn on. - * @see rcc_turn_off_clk() - * @see rcc_is_clk_ready() - */ -void rcc_turn_on_clk(rcc_clk clock) { - *rcc_clk_reg(clock) |= rcc_clk_on_mask(clock); -} - -/** - * @brief Turn off a clock source. - * - * In certain configurations, certain clock sources cannot be safely - * turned off. (For example, the main PLL on STM32F1 devices cannot be - * turned off if it has been selected as the SYSCLK source). Consult - * the reference material for your MCU to ensure it is safe to call - * this function. - * - * @param clock Clock to turn off. - * @see rcc_turn_on_clk() - * @see rcc_is_clk_ready() - */ -void rcc_turn_off_clk(rcc_clk clock) { - *rcc_clk_reg(clock) &= ~rcc_clk_on_mask(clock); -} - -/** - * @brief Check if a clock is on. - * @param clock Clock to check. - * @return 1 if the clock is on, 0 if the clock is off. - */ -int rcc_is_clk_on(rcc_clk clock) { - return !!(*rcc_clk_reg(clock) & rcc_clk_on_mask(clock)); -} - -/** - * @brief Check if a clock source is ready. - * - * In general, it is not safe to rely on a clock source unless this - * function returns nonzero. Also note that this function may return - * nonzero for a short period of time after a clock has been turned - * off. Consult the reference material for your MCU for more details. - * - * @param clock Clock whose readiness to check for. - * @return Nonzero if the clock is ready, zero otherwise. - * @see rcc_turn_on_clk() - * @see rcc_turn_off_clk() - */ -int rcc_is_clk_ready(rcc_clk clock) { - return (int)(*rcc_clk_reg(clock) & rcc_clk_ready_mask(clock)); -} diff --git a/STM32F3/cores/maple/libmaple/rcc_private.h b/STM32F3/cores/maple/libmaple/rcc_private.h deleted file mode 100644 index b20a2c5..0000000 --- a/STM32F3/cores/maple/libmaple/rcc_private.h +++ /dev/null @@ -1,67 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2011 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/* - * RCC private header. - */ - -#ifndef _LIBMAPLE_PRIVATE_RCC_H_ -#define _LIBMAPLE_PRIVATE_RCC_H_ - -#include - -struct rcc_dev_info { - const rcc_clk_domain clk_domain; - const uint8 line_num; -}; - -extern const struct rcc_dev_info rcc_dev_table[]; - -static inline void rcc_do_clk_enable(__IO uint32** enable_regs, - rcc_clk_id id) { - __IO uint32 *enable_reg = enable_regs[rcc_dev_clk(id)]; - uint8 line_num = rcc_dev_table[id].line_num; - bb_peri_set_bit(enable_reg, line_num, 1); -} - -static inline void rcc_do_reset_dev(__IO uint32** reset_regs, - rcc_clk_id id) { - __IO uint32 *reset_reg = reset_regs[rcc_dev_clk(id)]; - uint8 line_num = rcc_dev_table[id].line_num; - bb_peri_set_bit(reset_reg, line_num, 1); - bb_peri_set_bit(reset_reg, line_num, 0); -} - -static inline void rcc_do_set_prescaler(const uint32 *masks, - rcc_prescaler prescaler, - uint32 divider) { - uint32 cfgr = RCC_BASE->CFGR; - cfgr &= ~masks[prescaler]; - cfgr |= divider; - RCC_BASE->CFGR = cfgr; -} - -#endif diff --git a/STM32F3/cores/maple/libmaple/rules.mk b/STM32F3/cores/maple/libmaple/rules.mk deleted file mode 100644 index 0b541ed..0000000 --- a/STM32F3/cores/maple/libmaple/rules.mk +++ /dev/null @@ -1,53 +0,0 @@ -# Standard things -sp := $(sp).x -dirstack_$(sp) := $(d) -d := $(dir) -BUILDDIRS += $(BUILD_PATH)/$(d) - -LIBMAPLE_INCLUDES := -I$(LIBMAPLE_PATH)/include -I$(LIBMAPLE_MODULE_SERIES)/include -LIBMAPLE_PRIVATE_INCLUDES := -I$(LIBMAPLE_PATH) - -# Local flags -CFLAGS_$(d) = $(LIBMAPLE_PRIVATE_INCLUDES) $(LIBMAPLE_INCLUDES) -Wall -Werror - -# Local rules and targets -cSRCS_$(d) := adc.c -cSRCS_$(d) += dac.c -cSRCS_$(d) += dma.c -cSRCS_$(d) += exti.c -cSRCS_$(d) += flash.c -cSRCS_$(d) += gpio.c -cSRCS_$(d) += iwdg.c -cSRCS_$(d) += nvic.c -cSRCS_$(d) += pwr.c -cSRCS_$(d) += rcc.c -cSRCS_$(d) += spi.c -cSRCS_$(d) += systick.c -ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),stm32f2 stm32f3)) # SYSCFG peripheral available only on F2, F3 -cSRCS_$(d) += syscfg.c -endif -cSRCS_$(d) += timer.c -cSRCS_$(d) += usart.c -cSRCS_$(d) += usart_private.c -cSRCS_$(d) += util.c -sSRCS_$(d) := exc.S -ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),stm32f1 stm32f3)) # TODO port I2C to F2 -cSRCS_$(d) += i2c.c -cSRCS_$(d) += bkp.c -endif - -cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%) -sFILES_$(d) := $(sSRCS_$(d):%=$(d)/%) - -OBJS_$(d) := $(cFILES_$(d):%.c=$(BUILD_PATH)/%.o) $(sFILES_$(d):%.S=$(BUILD_PATH)/%.o) -DEPS_$(d) := $(OBJS_$(d):%.o=%.d) - -$(OBJS_$(d)): TGT_CFLAGS := $(CFLAGS_$(d)) -$(OBJS_$(d)): TGT_ASFLAGS := - -TGT_BIN += $(OBJS_$(d)) - -# Standard things --include $(DEPS_$(d)) -d := $(dirstack_$(sp)) -sp := $(basename $(sp)) diff --git a/STM32F3/cores/maple/libmaple/spi.c b/STM32F3/cores/maple/libmaple/spi.c deleted file mode 100644 index ec008d4..0000000 --- a/STM32F3/cores/maple/libmaple/spi.c +++ /dev/null @@ -1,129 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2011, 2012 LeafLabs, LLC. - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/spi.c - * @author Marti Bolivar - * @brief Serial Peripheral Interface (SPI) support. - * Currently, there is no Integrated Interchip Sound (I2S) support. - */ - -#include -#include - -/* - * SPI convenience routines - */ - -/** - * @brief Initialize and reset a SPI device. - * @param dev Device to initialize and reset. - */ -void spi_init(spi_dev *dev) { - rcc_clk_enable(dev->clk_id); - rcc_reset_dev(dev->clk_id); -} - -/** - * @brief Configure and enable a SPI device as bus master. - * - * The device's peripheral will be disabled before being reconfigured. - * - * @param dev Device to configure as bus master - * @param baud Bus baud rate - * @param mode SPI mode - * @param flags Logical OR of spi_cfg_flag values. - * @see spi_cfg_flag - */ -void spi_master_enable(spi_dev *dev, - spi_baud_rate baud, - spi_mode mode, - uint32 flags) { - spi_reconfigure(dev, baud | flags | SPI_CR1_MSTR | mode); -} - -/** - * @brief Configure and enable a SPI device as a bus slave. - * - * The device's peripheral will be disabled before being reconfigured. - * - * @param dev Device to configure as a bus slave - * @param mode SPI mode - * @param flags Logical OR of spi_cfg_flag values. - * @see spi_cfg_flag - */ -void spi_slave_enable(spi_dev *dev, spi_mode mode, uint32 flags) { - spi_reconfigure(dev, flags | mode); -} - -/** - * @brief Enable a SPI peripheral - * @param dev Device to enable - */ -void spi_peripheral_enable(spi_dev *dev) { - bb_peri_set_bit(&dev->regs->CR1, SPI_CR1_SPE_BIT, 1); -} - -/** - * @brief Disable a SPI peripheral - * @param dev Device to disable - */ -void spi_peripheral_disable(spi_dev *dev) { - bb_peri_set_bit(&dev->regs->CR1, SPI_CR1_SPE_BIT, 0); -} - -/** - * @brief Enable DMA requests whenever the transmit buffer is empty - * @param dev SPI device on which to enable TX DMA requests - */ -void spi_tx_dma_enable(spi_dev *dev) { - bb_peri_set_bit(&dev->regs->CR2, SPI_CR2_TXDMAEN_BIT, 1); -} - -/** - * @brief Disable DMA requests whenever the transmit buffer is empty - * @param dev SPI device on which to disable TX DMA requests - */ -void spi_tx_dma_disable(spi_dev *dev) { - bb_peri_set_bit(&dev->regs->CR2, SPI_CR2_TXDMAEN_BIT, 0); -} - -/** - * @brief Enable DMA requests whenever the receive buffer is empty - * @param dev SPI device on which to enable RX DMA requests - */ -void spi_rx_dma_enable(spi_dev *dev) { - bb_peri_set_bit(&dev->regs->CR2, SPI_CR2_RXDMAEN_BIT, 1); -} - -/** - * @brief Disable DMA requests whenever the receive buffer is empty - * @param dev SPI device on which to disable RX DMA requests - */ -void spi_rx_dma_disable(spi_dev *dev) { - bb_peri_set_bit(&dev->regs->CR2, SPI_CR2_RXDMAEN_BIT, 0); -} diff --git a/STM32F3/cores/maple/libmaple/spi_private.h b/STM32F3/cores/maple/libmaple/spi_private.h deleted file mode 100644 index f0e0bd1..0000000 --- a/STM32F3/cores/maple/libmaple/spi_private.h +++ /dev/null @@ -1,37 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -#ifndef _LIBMAPLE_SPI_PRIVATE_H_ -#define _LIBMAPLE_SPI_PRIVATE_H_ - -#define SPI_DEV(num) \ - { \ - .regs = SPI##num##_BASE, \ - .clk_id = RCC_SPI##num, \ - .irq_num = NVIC_SPI##num, \ - } - -#endif diff --git a/STM32F3/cores/maple/libmaple/stm32_private.h b/STM32F3/cores/maple/libmaple/stm32_private.h deleted file mode 100644 index 427417a..0000000 --- a/STM32F3/cores/maple/libmaple/stm32_private.h +++ /dev/null @@ -1,45 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -*****************************************************************************/ - -#ifndef _LIBMAPLE_STM32_PRIVATE_H_ -#define _LIBMAPLE_STM32_PRIVATE_H_ - -typedef enum stm32_mem_block_purpose { - STM32_BLOCK_CODE, - STM32_BLOCK_SRAM, - STM32_BLOCK_PERIPH, - STM32_BLOCK_FSMC_1_2, - STM32_BLOCK_FSMC_3_4, - STM32_BLOCK_FSMC_REG, - STM32_BLOCK_UNUSED, - STM32_BLOCK_CORTEX_INTERNAL, -} stm32_mem_block_purpose; - -static inline stm32_mem_block_purpose stm32_block_purpose(void *addr) { - return (stm32_mem_block_purpose)((unsigned)addr >> 29); -} - -#endif diff --git a/STM32F3/cores/maple/libmaple/stm32f3/f3_adc.c b/STM32F3/cores/maple/libmaple/stm32f3/f3_adc.c deleted file mode 100644 index 23a3b96..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/f3_adc.c +++ /dev/null @@ -1,412 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2012 LeafLabs, LLC. - * Copyright (c) 2010 Perry Hung. - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/stm32f3/adc.c - * @author Marti Bolivar , - * Perry Hung , - * F3-port by Hanspeter Portner - * @brief STM32F3 ADC support. - */ - -#include -#include -#include - -/* - * Devices - */ - -static adc_private_data adc1_priv; -static adc_dev adc1 = { - .regs = ADC1_BASE, - .clk_id = RCC_ADC12, - .priv = &adc1_priv -}; -/** ADC1 device. */ -const adc_dev *ADC1 = &adc1; - -static adc_private_data adc2_priv; -static adc_dev adc2 = { - .regs = ADC2_BASE, - .clk_id = RCC_ADC12, - .priv = &adc2_priv -}; -/** ADC2 device. */ -const adc_dev *ADC2 = &adc2; - -#if STM32_F3_LINE == STM32_F3_LINE_303 -static adc_private_data adc3_priv; -static adc_dev adc3 = { - .regs = ADC3_BASE, - .clk_id = RCC_ADC34, - .priv = &adc3_priv -}; -/** ADC3 device. */ -const adc_dev *ADC3 = &adc3; - -static adc_private_data adc4_priv; -static adc_dev adc4 = { - .regs = ADC4_BASE, - .clk_id = RCC_ADC34, - .priv = &adc4_priv -}; -/** ADC4 device. */ -const adc_dev *ADC4 = &adc4; -#endif - -/* - * STM32F3 routines - */ - -static inline void adc_check_regular_notongoing(const adc_dev *dev) { - adc_reg_map *regs = dev->regs; - if(regs->CR & ADC_CR_ADSTART) /* check for ongoing regular channel conversion */ - { - regs->CR |= ADC_CR_ADSTP; /* stop regular channel conversion */ - while(regs->CR & ADC_CR_ADSTP) - ; /* wait for conversion to stop */ - } -} - -static inline void adc_check_injected_notongoing(const adc_dev *dev) { - adc_reg_map *regs = dev->regs; - if(regs->CR & ADC_CR_JADSTART) /* check for ongoing injected channel conversion */ - { - regs->CR |= ADC_CR_JADSTP; /* stop injected channel conversion */ - while(regs->CR & ADC_CR_JADSTP) - ; /* wait for conversion to stop */ - } -} - -void adc_set_extsel(const adc_dev *dev, adc_extsel_event event) { - adc_check_regular_notongoing(dev); - - uint32 cfgr = dev->regs->CFGR; - cfgr &= ~ADC_CFGR_EXTSEL; - cfgr |= event; - dev->regs->CFGR = cfgr; -} - -void adc_set_resolution(const adc_dev *dev, adc_resolution res) { - adc_check_regular_notongoing(dev); - adc_check_injected_notongoing(dev); - - uint32 cfgr = dev->regs->CFGR; - cfgr &= ~ADC_CFGR_RES; - cfgr |= res; - dev->regs->CFGR = cfgr; -} - -void adc_set_sample_rate(const adc_dev *dev, adc_smp_rate smp_rate) { - adc_check_regular_notongoing(dev); - adc_check_injected_notongoing(dev); - - uint32 adc_smpr1_val = 0, adc_smpr2_val = 0; - int i; - - for(i = 0; i < 9; i++) { - /* ADC_SMPR1 determines sample time for channels [1,9] */ - adc_smpr1_val |= smp_rate << (i * 3 + 3); - /* ADC_SMPR2 determines sample time for channels [10,18] */ - adc_smpr2_val |= smp_rate << (i * 3); - } - - dev->regs->SMPR1 = adc_smpr1_val; - dev->regs->SMPR2 = adc_smpr2_val; -} - -void adc_enable_scan(const adc_dev *dev) { - /* FIXME nonexistent in F3 series */ -} - -void adc_disable_scan(const adc_dev *dev) { - /* FIXME nonexistent in F3 series*/ -} - -void adc_enable_continuous(const adc_dev *dev) { - bb_peri_set_bit(&dev->regs->CFGR, ADC_CFGR_CONT_BIT, 1); -} - -void adc_disable_continuous(const adc_dev *dev) { - bb_peri_set_bit(&dev->regs->CFGR, ADC_CFGR_CONT_BIT, 0); -} - -#define BITS_PER_SQ 6 -#define SQs_PER_SQR 5 -void adc_set_conv_seq(const adc_dev *dev, const uint8 *channels, uint8 len) { - ASSERT( (0 < len) && (len <= 16) ); - uint8 i; - uint32 val = 0; - uint8 lshift; - __IO uint32 *sqr = &dev->regs->SQR1; - - for (i=0; iregs; - - adc_set_conv_seq(dev, &channel, 1); - - regs->CR |= ADC_CR_ADSTART; /* start conversion */ - while (!(regs->ISR & ADC_ISR_EOC)) - ; /* wait until done */ - - return (uint16)(regs->DR & ADC_DR_RDATA); -} - -void adc_attach_interrupt(const adc_dev *dev, uint32 interrupt_flags, - void (*handler)(adc_callback_data*), void *arg) { - adc_private_data *priv = dev->priv; - priv->handler = handler; - priv->handler_flags = interrupt_flags; - priv->cb_data.arg = arg; - adc_enable_interrupts(dev, interrupt_flags); -} - -void adc_detach_interrupt(const adc_dev *dev) { - adc_private_data *priv; - adc_disable_interrupts(dev, ADC_ALL_INTERRUPTS); - priv = dev->priv; - priv->handler = NULL; - priv->handler_flags = 0; -} - -void adc_enable_interrupts(const adc_dev *dev, uint32 interrupt_flags) { - uint32 ier = dev->regs->IER; - ier |= interrupt_flags; - dev->regs->IER = ier; - _adc_enable_dev_irq(dev); -} - -void adc_disable_interrupts(const adc_dev *dev, uint32 interrupt_flags) { - /* Don't use nvic_irq_disable()! IRQs are shared among ADCs. */ - uint32 ier = dev->regs->IER; - ier &= ~interrupt_flags; - dev->regs->IER = ier; -} - -void adc_calibrate(const adc_dev *dev) { - adc_reg_map *regs = dev->regs; - - if( (regs->CR & ADC_CR_ADVREGEN) != ADC_CR_ADVREGEN_ENABLE) - adc_regulator_enable(dev); /* ensure that voltage regulator is enabled */ - - if(regs->CR & ADC_CR_ADEN) - adc_disable(dev); /* ensure that ADC is disabled */ - - regs->CR &= ~ADC_CR_ADCALDIF; /* calibrate in single-ended mode */ - regs->CR |= ADC_CR_ADCAL; /* start calibration */ - while (regs->CR & ADC_CR_ADCAL) - ; /* wait until done */ - - regs->CR |= ADC_CR_ADCALDIF; /* calibrate in differential mode */ - regs->CR |= ADC_CR_ADCAL; /* start calibration */ - while (regs->CR & ADC_CR_ADCAL) - ; /* wait until done */ -} - -void adc_set_exttrig(const adc_dev *dev, adc_exttrig_mode mode) { - adc_reg_map *regs = dev->regs; - regs->CFGR &= ~ADC_CFGR_EXTEN; - regs->CFGR |= mode; -} - -void adc_set_prescaler(adc_prescaler pre) { - if (pre & 0x10) { /* PLL is used as clock source */ - ADC12_BASE->CCR &= ~ADC_CCR_CKMODE; -#if STM32_F3_LINE == STM32_F3_LINE_303 - ADC34_BASE->CCR &= ~ADC_CCR_CKMODE; -#endif - - uint32 cfgr2 = RCC_BASE->CFGR2; - - cfgr2 &= ~RCC_CFGR2_ADC12PRES; // clear register - cfgr2 |= (uint32)pre << RCC_CFGR2_ADC12PRES_SHIFT; // set register - -#if STM32_F3_LINE == STM32_F3_LINE_303 - cfgr2 &= ~RCC_CFGR2_ADC34PRES; // clear register - cfgr2 |= (uint32)pre << RCC_CFGR2_ADC34PRES_SHIFT; // set register -#endif - - RCC_BASE->CFGR2 = cfgr2; - } else { /* AHB bus is used as clock source */ - /* FIXME does not work with current wirish booting routine */ - uint32 tmp; - - tmp = ADC12_BASE->CCR; - tmp &= ~ADC_CCR_CKMODE; - tmp |= pre << ADC_CCR_CKMODE_SHIFT; - ADC12_BASE->CCR = tmp; - -#if STM32_F3_LINE == STM32_F3_LINE_303 - tmp = ADC34_BASE->CCR; - tmp &= ~ADC_CCR_CKMODE; - tmp |= pre << ADC_CCR_CKMODE_SHIFT; - ADC34_BASE->CCR = tmp; -#endif - } -} - -void adc_foreach(void (*fn)(const adc_dev*)) { - fn(ADC1); - fn(ADC2); -#if STM32_F3_LINE == STM32_F3_LINE_303 - fn(ADC3); - fn(ADC4); -#endif -} - -void adc_config_gpio(const adc_dev *ignored, gpio_dev *gdev, uint8 bit) { - gpio_set_modef(gdev, bit, GPIO_MODE_ANALOG, GPIO_MODEF_PUPD_NONE); -} - -void adc_enable_single_swstart(const adc_dev *dev) { - int check_dev_adc = dev == ADC1; -#if STM32_F3_LINE == STM32_F3_LINE_303 - check_dev_adc = (check_dev_adc || dev == ADC3); -#endif - if (check_dev_adc) - adc_init(dev); /* FIXME hack needed for wirish, as master and slave ADC share the same reset register */ - adc_set_exttrig(dev, ADC_EXTTRIG_MODE_SOFTWARE); - adc_regulator_enable(dev); - adc_calibrate(dev); - adc_enable(dev); -} - -void adc_set_reg_seqlen(const adc_dev *dev, uint8 length) { - adc_check_regular_notongoing(dev); - - uint32 tmp = dev->regs->SQR1; - tmp &= ~ADC_SQR1_L; - tmp |= (length - 1) & ADC_SQR1_L; - dev->regs->SQR1 = tmp; -} - -void adc_enable(const adc_dev *dev) { - adc_reg_map *regs = dev->regs; - - while( (regs->CR & ADC_CR_ADVREGEN) != ADC_CR_ADVREGEN_ENABLE) - adc_regulator_enable(dev); /* ensure that voltage regulator is enabled */ - - regs->CR |= ADC_CR_ADEN; /* enable ADC */ - while (!(regs->ISR & ADC_ISR_ADRDY)) - ; /* wait until ADC is ready */ -} - -void adc_disable(const adc_dev *dev) { - adc_reg_map *regs = dev->regs; - - adc_check_regular_notongoing(dev); - adc_check_injected_notongoing(dev); - - regs->CR |= ADC_CR_ADDIS; /* disable ADC */ - while(regs->CR & ADC_CR_ADEN) - ; /* wait until ADC is effectively disabled */ -} - -void adc_regulator_enable(const adc_dev *dev) { - adc_reg_map *regs = dev->regs; - - regs->CR &= ~ADC_CR_ADVREGEN; - regs->CR |= ADC_CR_ADVREGEN_ENABLE; - - delay_us(10); /* 10us are worst case */ -} - -void adc_regulator_disable(const adc_dev *dev) { - adc_reg_map *regs = dev->regs; - - regs->CR &= ~ADC_CR_ADVREGEN; - regs->CR |= ADC_CR_ADVREGEN_DISABLE; -} - -/* - * Private API - */ - -void _adc_enable_dev_irq(const adc_dev *dev) { - if ( (dev == ADC1) || (dev == ADC2) ) - nvic_irq_enable(NVIC_ADC1_2); -#if STM32_F3_LINE == STM32_F3_LINE_303 - else { - if (dev == ADC3) - nvic_irq_enable(NVIC_ADC3); - else // dev == ADC4 - nvic_irq_enable(NVIC_ADC4); - } -#endif -} - -/* IRQ handler for adc_attach_interrupt() */ -static __always_inline void adc_irq(const adc_dev *dev) { - adc_private_data *priv = dev->priv; - uint32 irq_flags = dev->regs->ISR & priv->handler_flags; - - if (!irq_flags) { - /* The user isn't interested in this IRQ. */ - return; - } else if (priv->handler) { - priv->cb_data.irq_flags = irq_flags; - priv->handler(&priv->cb_data); - } -} - -/* - * IRQ handlers for adc_attach_interrupt() - */ -/* -void __irq_adc1_2(void) { - adc_irq(ADC1); - adc_irq(ADC2); -} - -#if STM32_F3_LINE == STM32_F3_LINE_303 -void __irq_adc3(void) { - adc_irq(ADC3); -} - -void __irq_adc4(void) { - adc_irq(ADC4); -} -#endif -*/ diff --git a/STM32F3/cores/maple/libmaple/stm32f3/f3_bkp.c b/STM32F3/cores/maple/libmaple/stm32f3/f3_bkp.c deleted file mode 100644 index 5ce70ae..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/f3_bkp.c +++ /dev/null @@ -1,49 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 LeafLabs, LLC. - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/stm32f3/bkp.c - * @author F3-port by Hanspeter Portner - * @brief STM32F3 backup register support. - */ - -#include -#include -#include - -void bkp_init(void) { - /* Don't call pwr_init(), or you'll reset the device. We just - * need the clock. */ - rcc_clk_enable(RCC_PWR); -} - -inline __IO uint32* bkp_data_register(uint8 reg) { - if (reg < 1 || reg > BKP_NR_DATA_REGS) - return NULL; - else - return (uint32*)BKP_BASE + (reg-1); // regs are accessed from 1-16 -} diff --git a/STM32F3/cores/maple/libmaple/stm32f3/f3_comp.c b/STM32F3/cores/maple/libmaple/stm32f3/f3_comp.c deleted file mode 100644 index 527be71..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/f3_comp.c +++ /dev/null @@ -1,61 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/stm32f3/comp.c - * @author F3-port by Hanspeter Portner - * @brief STM32F3 Comparator support. - */ - -#include - -/* - * Devices - */ - -static comp_dev comp1 = { .regs = COMP1_BASE }; const comp_dev *COMP1 = &comp1; -static comp_dev comp2 = { .regs = COMP2_BASE }; const comp_dev *COMP2 = &comp2; -static comp_dev comp3 = { .regs = COMP3_BASE }; const comp_dev *COMP3 = &comp3; -static comp_dev comp4 = { .regs = COMP4_BASE }; const comp_dev *COMP4 = &comp4; -static comp_dev comp5 = { .regs = COMP5_BASE }; const comp_dev *COMP5 = &comp5; -static comp_dev comp6 = { .regs = COMP6_BASE }; const comp_dev *COMP6 = &comp6; -static comp_dev comp7 = { .regs = COMP7_BASE }; const comp_dev *COMP7 = &comp7; - -void __irq_comp123(void) { - //TODO -} - -void __irq_com456(void) { - //TODO -} - -void __irq_comp7(void) { - //TODO -} - -/* TODO - * actually implement me ;-) - */ diff --git a/STM32F3/cores/maple/libmaple/stm32f3/f3_dma.c b/STM32F3/cores/maple/libmaple/stm32f3/f3_dma.c deleted file mode 100644 index 10ba37f..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/f3_dma.c +++ /dev/null @@ -1,364 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Michael Hope. - * Copyright (c) 2012 LeafLabs, LLC. - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/stm32f3/dma.c - * @author Marti Bolivar , - * Original implementation by Michael Hope, - * F3-port by Hanspeter Portner - * @brief STM32F3 DMA support. - */ - -#include -#include - -/* Hack to ensure inlining in dma_irq_handler() */ -#define DMA_GET_HANDLER(dev, tube) (dev->handlers[tube - 1].handler) -#include "dma_private.h" - -/* - * Devices - */ - -static dma_dev dma1 = { - .regs = DMA1_BASE, - .clk_id = RCC_DMA1, - .handlers = {{ .handler = NULL, .irq_line = NVIC_DMA_CH1 }, - { .handler = NULL, .irq_line = NVIC_DMA_CH2 }, - { .handler = NULL, .irq_line = NVIC_DMA_CH3 }, - { .handler = NULL, .irq_line = NVIC_DMA_CH4 }, - { .handler = NULL, .irq_line = NVIC_DMA_CH5 }, - { .handler = NULL, .irq_line = NVIC_DMA_CH6 }, - { .handler = NULL, .irq_line = NVIC_DMA_CH7 }}, -}; -/** STM32F3 DMA1 device */ -dma_dev *DMA1 = &dma1; - -static dma_dev dma2 = { - .regs = DMA2_BASE, - .clk_id = RCC_DMA2, - .handlers = {{ .handler = NULL, .irq_line = NVIC_DMA2_CH1 }, - { .handler = NULL, .irq_line = NVIC_DMA2_CH2 }, - { .handler = NULL, .irq_line = NVIC_DMA2_CH3 }, - { .handler = NULL, .irq_line = NVIC_DMA2_CH4 }, - { .handler = NULL, .irq_line = NVIC_DMA2_CH5 }}, -}; -/** STM32F3 DMA2 device */ -dma_dev *DMA2 = &dma2; - -/* - * Auxiliary routines - */ - -/* Can channel serve cfg->tube_req_src? */ -static int cfg_req_ok(dma_channel channel, dma_tube_config *cfg) { - return (cfg->tube_req_src & 0x7) == channel; -} - -/* Can dev serve cfg->tube_req_src? */ -static int cfg_dev_ok(dma_dev *dev, dma_tube_config *cfg) { - return (rcc_clk_id)(cfg->tube_req_src >> 3) == dev->clk_id; -} - -/* Is addr acceptable for use as DMA src/dst? */ -static int cfg_mem_ok(__IO void *addr) { - enum dma_atype atype = _dma_addr_type(addr); - return atype == DMA_ATYPE_MEM || atype == DMA_ATYPE_PER; -} - -/* Is the direction implied by src->dst supported? */ -static int cfg_dir_ok(dma_tube_config *cfg) { - /* We can't do peripheral->peripheral transfers. */ - return ((_dma_addr_type(cfg->tube_src) == DMA_ATYPE_MEM) || - (_dma_addr_type(cfg->tube_dst) == DMA_ATYPE_MEM)); -} - -static int preconfig_check(dma_dev *dev, dma_channel channel, - dma_tube_config *cfg) { - if (!cfg_req_ok(channel, cfg)) { - return -DMA_TUBE_CFG_EREQ; - } - if (cfg->tube_nr_xfers > 65535) { - return -DMA_TUBE_CFG_ENDATA; - } - if (!cfg_dev_ok(dev, cfg)) { - return -DMA_TUBE_CFG_EDEV; - } - if (!cfg_mem_ok(cfg->tube_src)) { - return -DMA_TUBE_CFG_ESRC; - } - if (!cfg_mem_ok(cfg->tube_dst)) { - return -DMA_TUBE_CFG_EDST; - } - if (!cfg_dir_ok(cfg)) { - return -DMA_TUBE_CFG_EDIR; - } - return DMA_TUBE_CFG_SUCCESS; -} - -static inline void set_ccr(dma_tube_reg_map *chregs, - dma_xfer_size msize, int minc, - dma_xfer_size psize, int pinc, - uint32 other_flags) { - chregs->CCR = ((msize << 10) | (psize << 8) | - (minc ? DMA_CCR_MINC : 0) | (pinc ? DMA_CCR_PINC : 0) | - other_flags); -} - -static inline uint32 cfg_ccr_flags(unsigned tube_flags) { - /* DMA_CFG_SRC_INC and DMA_CFG_DST_INC are special */ - return tube_flags & ~(DMA_CFG_SRC_INC | DMA_CFG_DST_INC); -} - -/* Configure chregs according to cfg, where cfg->tube_dst is peripheral. */ -static int config_to_per(dma_tube_reg_map *chregs, dma_tube_config *cfg) { - /* Check that ->tube_src is memory (if it's anything else, we - * shouldn't have been called). */ - ASSERT(_dma_addr_type(cfg->tube_src) == DMA_ATYPE_MEM); - - set_ccr(chregs, - cfg->tube_src_size, cfg->tube_flags & DMA_CFG_SRC_INC, - cfg->tube_dst_size, cfg->tube_flags & DMA_CFG_DST_INC, - (cfg_ccr_flags(cfg->tube_flags) | DMA_CCR_DIR_FROM_MEM)); - chregs->CNDTR = cfg->tube_nr_xfers; - chregs->CMAR = (uint32)cfg->tube_src; - chregs->CPAR = (uint32)cfg->tube_dst; - return DMA_TUBE_CFG_SUCCESS; -} - -/* Configure chregs according to cfg, where cfg->tube_dst is memory. */ -static int config_to_mem(dma_tube_reg_map *chregs, dma_tube_config *cfg) { - uint32 mem2mem; - - if ((_dma_addr_type(cfg->tube_src) == DMA_ATYPE_MEM) && - (cfg->tube_flags & DMA_CFG_CIRC)) { - /* Can't do mem-to-mem and circular mode */ - return -DMA_TUBE_CFG_ECFG; - } - - mem2mem = (_dma_addr_type(cfg->tube_src) == DMA_ATYPE_MEM ? - DMA_CCR_MEM2MEM : 0); - set_ccr(chregs, - cfg->tube_dst_size, cfg->tube_flags & DMA_CFG_DST_INC, - cfg->tube_src_size, cfg->tube_flags & DMA_CFG_SRC_INC, - (cfg_ccr_flags(cfg->tube_flags) | - DMA_CCR_DIR_FROM_PER | - mem2mem)); - chregs->CNDTR = cfg->tube_nr_xfers; - chregs->CMAR = (uint32)cfg->tube_dst; - chregs->CPAR = (uint32)cfg->tube_src; - return DMA_TUBE_CFG_SUCCESS; -} - -/* - * Routines - */ - -int dma_tube_cfg(dma_dev *dev, dma_channel channel, dma_tube_config *cfg) { - dma_tube_reg_map *chregs; - int ret = preconfig_check(dev, channel, cfg); - - if (ret < 0) { - return ret; - } - - dma_disable(dev, channel); /* Must disable before reconfiguring */ - dma_clear_isr_bits(dev, channel); /* For sanity and consistency - * with STM32F2. */ - - chregs = dma_tube_regs(dev, channel); - switch (_dma_addr_type(cfg->tube_dst)) { - case DMA_ATYPE_PER: - ret = config_to_per(chregs, cfg); - break; - case DMA_ATYPE_MEM: - ret = config_to_mem(chregs, cfg); - break; - default: - /* Can't happen */ - ASSERT(0); - return -DMA_TUBE_CFG_ECFG; - } - if (ret < 0) { - return ret; - } - chregs->CNDTR = cfg->tube_nr_xfers; - return DMA_TUBE_CFG_SUCCESS; -} - -void dma_set_priority(dma_dev *dev, - dma_channel channel, - dma_priority priority) { - dma_channel_reg_map *channel_regs; - uint32 ccr; - - ASSERT_FAULT(!dma_is_channel_enabled(dev, channel)); - - channel_regs = dma_channel_regs(dev, channel); - ccr = channel_regs->CCR; - ccr &= ~DMA_CCR_PL; - ccr |= (priority << 12); - channel_regs->CCR = ccr; -} - -void dma_set_num_transfers(dma_dev *dev, - dma_channel channel, - uint16 num_transfers) { - dma_channel_reg_map *channel_regs; - - ASSERT_FAULT(!dma_is_channel_enabled(dev, channel)); - - channel_regs = dma_channel_regs(dev, channel); - channel_regs->CNDTR = num_transfers; -} - -void dma_attach_interrupt(dma_dev *dev, dma_channel channel, - void (*handler)(void)) { - DMA_GET_HANDLER(dev, channel) = handler; - nvic_irq_enable(dev->handlers[channel - 1].irq_line); -} - -void dma_detach_interrupt(dma_dev *dev, dma_channel channel) { - /* Don't use nvic_irq_disable()! Think about DMA2 channels 4 and 5. */ - dma_channel_regs(dev, channel)->CCR &= ~0xF; - DMA_GET_HANDLER(dev, channel) = NULL; -} - -void dma_enable(dma_dev *dev, dma_channel channel) { - dma_channel_reg_map *chan_regs = dma_channel_regs(dev, channel); - bb_peri_set_bit(&chan_regs->CCR, DMA_CCR_EN_BIT, 1); -} - -void dma_disable(dma_dev *dev, dma_channel channel) { - dma_channel_reg_map *chan_regs = dma_channel_regs(dev, channel); - bb_peri_set_bit(&chan_regs->CCR, DMA_CCR_EN_BIT, 0); -} - -dma_irq_cause dma_get_irq_cause(dma_dev *dev, dma_channel channel) { - /* Grab and clear the ISR bits. */ - uint8 status_bits = dma_get_isr_bits(dev, channel); - dma_clear_isr_bits(dev, channel); - - /* If the channel global interrupt flag is cleared, then - * something's very wrong. */ - ASSERT(status_bits & 0x1); - /* If GIF is set, then some other flag should be set, barring - * something unexpected (e.g. the user making an unforeseen IFCR - * write). */ - ASSERT(status_bits != 0x1); - - /* ISR flags get set even if the corresponding interrupt enable - * bits in the channel's configuration register are cleared, so we - * can't use a switch here. - * - * Don't change the order of these if statements. */ - if (status_bits & 0x8) { - return DMA_TRANSFER_ERROR; - } else if (status_bits & 0x2) { - return DMA_TRANSFER_COMPLETE; - } else if (status_bits & 0x4) { - return DMA_TRANSFER_HALF_COMPLETE; - } - - /* If we get here, one of our assumptions has been violated, but - * the debug level is too low for the above ASSERTs() to have had - * any effect. In order to fail fast, mimic the DMA controller's - * behavior when an error occurs. */ - dma_disable(dev, channel); - return DMA_TRANSFER_ERROR; -} - -void dma_set_mem_addr(dma_dev *dev, dma_channel channel, __IO void *addr) { - dma_channel_reg_map *chan_regs; - - ASSERT_FAULT(!dma_is_channel_enabled(dev, channel)); - - chan_regs = dma_channel_regs(dev, channel); - chan_regs->CMAR = (uint32)addr; -} - -void dma_set_per_addr(dma_dev *dev, dma_channel channel, __IO void *addr) { - dma_channel_reg_map *chan_regs; - - ASSERT_FAULT(!dma_is_channel_enabled(dev, channel)); - - chan_regs = dma_channel_regs(dev, channel); - chan_regs->CPAR = (uint32)addr; -} - -/* - * IRQ handlers - */ - -void __irq_dma1_ch1(void) { - dma_irq_handler(DMA1, DMA_CH1); -} - -void __irq_dma1_ch2(void) { - dma_irq_handler(DMA1, DMA_CH2); -} - -void __irq_dma1_ch3(void) { - dma_irq_handler(DMA1, DMA_CH3); -} - -void __irq_dma1_ch4(void) { - dma_irq_handler(DMA1, DMA_CH4); -} - -void __irq_dma1_ch5(void) { - dma_irq_handler(DMA1, DMA_CH5); -} - -void __irq_dma1_ch6(void) { - dma_irq_handler(DMA1, DMA_CH6); -} - -void __irq_dma1_ch7(void) { - dma_irq_handler(DMA1, DMA_CH7); -} - -void __irq_dma2_ch1(void) { - dma_irq_handler(DMA2, DMA_CH1); -} - -void __irq_dma2_ch2(void) { - dma_irq_handler(DMA2, DMA_CH2); -} - -void __irq_dma2_ch3(void) { - dma_irq_handler(DMA2, DMA_CH3); -} - -void __irq_dma2_ch4(void) { - dma_irq_handler(DMA2, DMA_CH4); -} - -void __irq_dma2_ch5(void) { - dma_irq_handler(DMA2, DMA_CH5); -} diff --git a/STM32F3/cores/maple/libmaple/stm32f3/f3_exti.c b/STM32F3/cores/maple/libmaple/stm32f3/f3_exti.c deleted file mode 100644 index 44f0057..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/f3_exti.c +++ /dev/null @@ -1,40 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2012 LeafLabs, LLC. - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -*****************************************************************************/ - -/** - * @file libmaple/stm32f3/exti.c - * @author F3-port by Hanspeter Portner - * @brief STM32F3 EXTI. - */ - -#include -#include -#include "exti_private.h" - -void exti_select(exti_num num, exti_cfg cfg) { - exti_do_select(&SYSCFG_BASE->EXTICR[num / 4], num, cfg); -} diff --git a/STM32F3/cores/maple/libmaple/stm32f3/f3_fpu.c b/STM32F3/cores/maple/libmaple/stm32f3/f3_fpu.c deleted file mode 100644 index 7ea5277..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/f3_fpu.c +++ /dev/null @@ -1,57 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/stm32f3/fpu.c - * @author F3-port by Hanspeter Portner - * @brief STM32F3 FPU. - */ - -#include - -void fpu_enable(void) { - /* - * set coprocessor access control registers - */ - asm("\tLDR.W R0, =0xE000ED88\n" - "\tLDR R1, [R0]\n" - "\tORR R1, R1, #(0xF << 20)\n" - "\tSTR R1, [R0]\n" - "\tDSB\n" - "\tISB"); -} - -void fpu_disable(void) { - /* - * clear coprocessor access control registers - */ - asm("\tLDR.W R0, =0xE000ED88\n" - "\tLDR R1, [R0]\n" - "\tORR R1, R1, #(0x0 << 20)\n" - "\tSTR R1, [R0]\n" - "\tDSB\n" - "\tISB"); -} diff --git a/STM32F3/cores/maple/libmaple/stm32f3/f3_gpio.c b/STM32F3/cores/maple/libmaple/stm32f3/f3_gpio.c deleted file mode 100644 index 7ca982a..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/f3_gpio.c +++ /dev/null @@ -1,169 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2011 LeafLabs, LLC. - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/stm32f3/gpio.c - * @author F3-port by Hanspeter Portner - * @brief STM32F3 GPIO. - */ - -#include -#include -#include - -/* - * GPIO devices - */ - -gpio_dev gpioa = { - .regs = GPIOA_BASE, - .clk_id = RCC_GPIOA, - .exti_port = EXTI_PA, -}; -/** GPIO port A device. */ -gpio_dev* const GPIOA = &gpioa; - -gpio_dev gpiob = { - .regs = GPIOB_BASE, - .clk_id = RCC_GPIOB, - .exti_port = EXTI_PB, -}; -/** GPIO port B device. */ -gpio_dev* const GPIOB = &gpiob; - -gpio_dev gpioc = { - .regs = GPIOC_BASE, - .clk_id = RCC_GPIOC, - .exti_port = EXTI_PC, -}; -/** GPIO port C device. */ -gpio_dev* const GPIOC = &gpioc; - -gpio_dev gpiod = { - .regs = GPIOD_BASE, - .clk_id = RCC_GPIOD, - .exti_port = EXTI_PD, -}; -/** GPIO port D device. */ -gpio_dev* const GPIOD = &gpiod; - -gpio_dev gpioe = { - .regs = GPIOE_BASE, - .clk_id = RCC_GPIOE, - .exti_port = EXTI_PE, -}; -/** GPIO port E device. */ -gpio_dev* const GPIOE = &gpioe; - -gpio_dev gpiof = { - .regs = GPIOF_BASE, - .clk_id = RCC_GPIOF, - .exti_port = EXTI_PF, -}; -/** GPIO port F device. */ -gpio_dev* const GPIOF = &gpiof; - -/* - * GPIO routines - */ - -/** - * Initialize and reset all available GPIO devices. - */ -void gpio_init_all(void) { - gpio_init(GPIOA); - gpio_init(GPIOB); - gpio_init(GPIOC); - gpio_init(GPIOD); - gpio_init(GPIOE); - gpio_init(GPIOF); -} - -/** - * @brief Set the mode of a GPIO pin. - * @param dev GPIO device. - * @param bit Bit on dev whose mode to set, 0--15. - * @param mode Mode to set the pin to. - * @param flags Flags to modify basic mode configuration - */ -void gpio_set_modef(gpio_dev *dev, - uint8 bit, - gpio_pin_mode mode, - unsigned flags) { - gpio_reg_map *regs = dev->regs; - unsigned shift = bit * 2; - uint32 tmp; - - /* Mode */ - tmp = regs->MODER; - tmp &= ~(0x3 << shift); - tmp |= mode << shift; - regs->MODER = tmp; - - /* Output type */ - bb_peri_set_bit(®s->OTYPER, bit, flags & 0x1); - - /* Speed */ - tmp = regs->OSPEEDR; - tmp &= ~(0x3 << shift); - tmp |= ((flags >> 1) & 0x3) << shift; - regs->OSPEEDR = tmp; - - /* Pull-up/pull-down */ - tmp = regs->PUPDR; - tmp &= ~(0x3 << shift); - tmp |= ((flags >> 3) & 0x3) << shift; - regs->PUPDR = tmp; -} - -/** - * @brief Set a pin's alternate function. - * - * The pin must have its mode set to GPIO_MODE_AF for this to take - * effect. - * - * @param dev Device whose pin to configure. - * @param bit Pin whose alternate function to set. - * @param af Alternate function to use for pin. - * @see gpio_set_modef() - */ -void gpio_set_af(gpio_dev *dev, uint8 bit, gpio_af af) { - __IO uint32 *afr; - unsigned shift; - uint32 tmp; - if (bit >= 8) { - afr = &dev->regs->AFRH; - shift = 4 * (bit - 8); - } else{ - afr = &dev->regs->AFRL; - shift = 4 * bit; - } - tmp = *afr; - tmp &= ~(0xF << shift); - tmp |= (af << shift); - *afr = tmp; -} diff --git a/STM32F3/cores/maple/libmaple/stm32f3/f3_i2c.c b/STM32F3/cores/maple/libmaple/stm32f3/f3_i2c.c deleted file mode 100644 index 2412987..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/f3_i2c.c +++ /dev/null @@ -1,319 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/stm32f3/i2c.c - * @author F3-port by Hanspeter Portner - * @brief STM32F3 I2C support - */ - -#include "i2c_private.h" -#include -#include - -/* - * Devices - */ - -/* on GPIO_AF_4 (PA14,PA15) (PB7,PB6) (PB9,PB8)*/ -static i2c_dev i2c1 = I2C_DEV_OLD(1, &gpiob, 7, 6); -/** STM32F3 I2C device 1 */ -i2c_dev* const I2C1 = &i2c1; - -/* on GPIO_AF_4 (PA10,PA9) (PF0,PF1) (PF0,PF6)*/ -static i2c_dev i2c2 = I2C_DEV_OLD(2, &gpioa, 10, 9); -/** STM32F3 I2C device 2 */ -i2c_dev* const I2C2 = &i2c2; - -/* - * Routines - */ - -void i2c_config_gpios(const i2c_dev *dev) { - gpio_set_modef(sda_port(dev), dev->sda_pin, GPIO_MODE_AF, GPIO_MODEF_TYPE_OD); - gpio_set_modef(scl_port(dev), dev->scl_pin, GPIO_MODE_AF, GPIO_MODEF_TYPE_OD); - - gpio_set_af(sda_port(dev), dev->sda_pin, GPIO_AF_4); - gpio_set_af(scl_port(dev), dev->scl_pin, GPIO_AF_4); -} - -void i2c_master_release_bus(const i2c_dev *dev) { - gpio_write_bit(scl_port(dev), dev->scl_pin, 1); /* TODO check this */ - gpio_write_bit(sda_port(dev), dev->sda_pin, 1); - - i2c_config_gpios(dev); -} - -int32 wait_for_state_change(i2c_dev *dev, - i2c_state state, - uint32 timeout) { - //FIXME not yet used on F3 - return 1; -} - -void i2c_bus_reset(const i2c_dev *dev) { - //FIXME not yet used on F3 -} - -void _i2c_software_reset(i2c_dev *dev) { - dev->regs->CR1 &= ~I2C_CR1_PE; - while(dev->regs->CR1 & I2C_CR1_PE) - ; - dev->regs->CR1 |= I2C_CR1_PE; -} - -void i2c_master_enable(i2c_dev *dev, uint32 flags) { - /* Bring the peripheral down for configuration */ - i2c_peripheral_disable(dev); - - /* Reset the bus when requested so */ - if (flags & I2C_BUS_RESET) - i2c_bus_reset(dev); - - /* Turn on the clock and set GPIO modes */ - i2c_init(dev); - i2c_config_gpios(dev); - - /* Configure analog and digital filters */ - /* TODO ANFOFF, DNF */ - - /* Configure the clock and rise time */ - dev->regs->TIMINGR = I2C_TIMING_10_kHz; - - /* Configure NOSTRETCH behaviour */ - /* TODO NOSTRETCH */ - - /* Enable all interrupts */ /* FIXME not yet used on F3 */ - //nvic_irq_enable(dev->ev_nvic_line); - //nvic_irq_enable(dev->er_nvic_line); - //i2c_enable_irq(dev, 0xFE); /* All interrupts */ - - /* Make it go! */ - i2c_peripheral_enable(dev); - - dev->state = I2C_STATE_IDLE; -} - -static void _i2c_master_xmit(i2c_dev *dev, i2c_msg *msg) { - uint32 cr2; - uint32 isr; - uint16 remaining = msg->length; - msg->xferred = 0; - uint8 *ptr = msg->data; /* pointer to data buffer */ - - while (remaining > 0) { - uint32 reload = remaining > 0xFF ? I2C_CR2_RELOAD : 0U; - uint16 size = remaining >= 0xFF ? 0xFF : remaining & 0xFF; - uint32 nbytes = size << I2C_CR2_NBYTES_SHIFT; - - cr2 = dev->regs->CR2; - cr2 &= ~(I2C_CR2_RELOAD | I2C_CR2_NBYTES | I2C_CR2_RD_WRN); - cr2 |= reload | nbytes; - dev->regs->CR2 = cr2; - - if (msg->xferred == 0) /* first loop iteration? */ - dev->regs->CR2 |= I2C_CR2_START; /* generate START condition */ - - while (ptr < msg->data + msg->xferred + size) { - while ( !( (isr = dev->regs->ISR) & (I2C_ISR_NACKF | I2C_ISR_TXIS) ) ) - ; /* wait until ready for the next byte or NACK*/ - - if (isr & I2C_ISR_TXIS) - dev->regs->TXDR = *ptr++; /* byte to send */ - else { /* NACKF */ - dev->regs->ICR |= I2C_ICR_NACKCF; /* clear NACK flag */ - dev->regs->CR2 |= I2C_CR2_STOP; /* generate STOP condition */ - return; /* STOP condition is automatically generated */ - } - } - - if (reload) - while ( !(dev->regs->ISR & I2C_ISR_TCR) ) - ; /* wait for transmission reload complete */ - - remaining -= size; - msg->xferred += size; - } - - while ( !(dev->regs->ISR & I2C_ISR_TC) ) - ; /* wait for transmission complete */ - - dev->regs->CR2 |= I2C_CR2_STOP; /* generate STOP condition */ - - while ( !(dev->regs->ISR & I2C_ISR_STOPF) ) - ; /* wait for STOP flag */ - - dev->regs->ICR |= I2C_ICR_STOPCF; /* clear STOP flag */ -} - -static void _i2c_master_recv(i2c_dev *dev, i2c_msg *msg) { - uint32 cr2; - uint16 remaining = msg->length; - msg->xferred = 0; - uint8 *ptr = msg->data; /* pointer to data buffer */ - - while (remaining > 0) { - uint32 reload = remaining > 0xFF ? I2C_CR2_RELOAD : 0U; - uint16 size = remaining >= 0xFF ? 0xFF : remaining & 0xFF; - uint32 nbytes = size << I2C_CR2_NBYTES_SHIFT; - - cr2 = dev->regs->CR2; - cr2 &= ~(I2C_CR2_RELOAD | I2C_CR2_NBYTES | I2C_CR2_RD_WRN); - cr2 |= reload | nbytes | I2C_CR2_RD_WRN; - dev->regs->CR2 = cr2; - - if (msg->xferred == 0) /* first loop iteration? */ - dev->regs->CR2 |= I2C_CR2_START; /* generate START condition */ - - while (ptr < msg->data + msg->xferred + size) { - while ( !(dev->regs->ISR & I2C_ISR_RXNE) ) - ; /* wait for next byte */ - - *ptr++ = dev->regs->RXDR & I2C_RXDR_RXDATA; /* read byte */ - } - - if (reload) - while ( !(dev->regs->ISR & I2C_ISR_TCR) ) - ; /* wait for transmission reload complete */ - - remaining -= size; - msg->xferred += size; - } - - while ( !(dev->regs->ISR & I2C_ISR_TC)) - ; /* wait for transmission complete */ - - dev->regs->CR2 |= I2C_CR2_STOP; /* generate STOP condition */ - - while ( !(dev->regs->ISR & I2C_ISR_STOPF) ) - ; /* wait for STOP flag */ - - dev->regs->ICR |= I2C_ICR_STOPCF; /* clear STOP flag */ -} - -int32 i2c_master_xfer(i2c_dev *dev, - i2c_msg *msgs, - uint16 num, - uint32 timeout) { - i2c_msg *msg; - - ASSERT(dev->state == I2C_STATE_IDLE); - - dev->msg = msgs; - dev->msgs_left = num; - dev->timestamp = systick_uptime(); /* FIXME implement handling of timeout */ - dev->state = I2C_STATE_BUSY; - - /* loop over messages */ - for (msg = dev->msg; dev->msgs_left; dev->msgs_left--, msg++) { - /* set slave address and direction*/ - uint32 addr = msg->flags & I2C_MSG_10BIT_ADDR - ? I2C_CR2_ADD10 | (msg->addr << I2C_CR2_SADD_10_BIT_SHIFT) - : msg->addr << I2C_CR2_SADD_7_BIT_SHIFT; - uint32 rd = msg->flags & I2C_MSG_READ ? I2C_CR2_RD_WRN : 0U; - uint32 cr2 = dev->regs->CR2; - cr2 &= ~(I2C_CR2_HEAD10R | I2C_CR2_ADD10 | I2C_CR2_SADD_10_BIT | I2C_CR2_RD_WRN); - cr2 |= rd | addr; - dev->regs->CR2 = cr2; - - if (rd) - _i2c_master_recv(dev, msg); - else - _i2c_master_xmit(dev, msg); - } - - dev->state = I2C_STATE_IDLE; - - return 0; /* FIXME implement error handling*/ -} - -void i2c_start_condition(i2c_dev *dev) { - dev->regs->CR2 |= I2C_CR2_START; /* generate START condition */ -} - -void i2c_stop_condition(i2c_dev *dev) { - dev->regs->CR2 |= I2C_CR2_STOP; /* generate STOP condition */ - - while ( !(dev->regs->ISR & I2C_ISR_STOPF) ) - ; /* wait for STOP flag */ - - dev->regs->ICR |= I2C_ICR_STOPCF; /* clear STOP flag */ -} - -void i2c_enable_irq(i2c_dev *dev, uint32 irqs) { - dev->regs->CR1 |= irqs; -} - -void i2c_disable_irq(i2c_dev *dev, uint32 irqs) { - dev->regs->CR1 &= ~irqs; -} - -/* ACK/NACK */ -void i2c_enable_ack(i2c_dev *dev) { - //FIXME nonexistant on F3 -} - -void i2c_disable_ack(i2c_dev *dev) { - //FIXME nonexistant on F3 -} - -void i2c_write(i2c_dev *dev, uint8 byte) { - //FIXME proper handling of ISR - dev->regs->TXDR = byte; -} - -uint8 i2c_read(i2c_dev *dev) { - //FIXME proper handling of ISR - return dev->regs->RXDR & I2C_RXDR_RXDATA; -} - -void _i2c_irq_handler(i2c_dev *dev) { - //FIXME not yet used on F3 -} - -void _i2c_irq_error_handler(i2c_dev *dev) { - //FIXME not yet used on F3 -} - -/* - * IRQ handlers - */ - -void __irq_i2c1_ev(void) { - _i2c_irq_handler(I2C1); -} - -void __irq_i2c2_ev(void) { - _i2c_irq_handler(I2C2); -} - -void __irq_i2c1_er(void) { - _i2c_irq_error_handler(I2C1); -} - -void __irq_i2c2_er(void) { - _i2c_irq_error_handler(I2C2); -} diff --git a/STM32F3/cores/maple/libmaple/stm32f3/f3_opamp.c b/STM32F3/cores/maple/libmaple/stm32f3/f3_opamp.c deleted file mode 100644 index c6ec0d5..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/f3_opamp.c +++ /dev/null @@ -1,46 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/stm32f3/opamp.c - * @author F3-port by Hanspeter Portner - * @brief STM32F3 OpAmp support. - */ - -#include - -/* - * Devices - */ - -static opamp_dev opamp1 = { .regs = OPAMP1_BASE }; const opamp_dev *OPAMP1 = &opamp1; -static opamp_dev opamp2 = { .regs = OPAMP2_BASE }; const opamp_dev *OPAMP2 = &opamp2; -static opamp_dev opamp3 = { .regs = OPAMP3_BASE }; const opamp_dev *OPAMP3 = &opamp3; -static opamp_dev opamp4 = { .regs = OPAMP4_BASE }; const opamp_dev *OPAMP4 = &opamp4; - -/* TODO - * actually implement me ;-) - */ diff --git a/STM32F3/cores/maple/libmaple/stm32f3/f3_rcc.c b/STM32F3/cores/maple/libmaple/stm32f3/f3_rcc.c deleted file mode 100644 index 5ebe2ad..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/f3_rcc.c +++ /dev/null @@ -1,149 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * Copyright (c) 2011 LeafLabs, LLC. - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/stm32f3/rcc.c - * @author F3-port by Hanspeter Portner - * @brief STM32F3 RCC. - */ - -#include -#include -#include - -#include "rcc_private.h" - -#define APB1 RCC_APB1 -#define APB2 RCC_APB2 -#define AHB RCC_AHB - -/* Device descriptor table, maps rcc_clk_id onto bus and enable/reset - * register bit numbers. */ -const struct rcc_dev_info rcc_dev_table[] = { - [RCC_GPIOA] = { .clk_domain = AHB, .line_num = RCC_AHBENR_IOPAEN_BIT }, - [RCC_GPIOB] = { .clk_domain = AHB, .line_num = RCC_AHBENR_IOPBEN_BIT }, - [RCC_GPIOC] = { .clk_domain = AHB, .line_num = RCC_AHBENR_IOPCEN_BIT }, - [RCC_GPIOD] = { .clk_domain = AHB, .line_num = RCC_AHBENR_IOPDEN_BIT }, - [RCC_GPIOE] = { .clk_domain = AHB, .line_num = RCC_AHBENR_IOPEEN_BIT }, - [RCC_GPIOF] = { .clk_domain = AHB, .line_num = RCC_AHBENR_IOPFEN_BIT }, - - [RCC_ADC12] = { .clk_domain = AHB, .line_num = RCC_AHBENR_ADC12EN_BIT}, -#if STM32_F3_LINE == STM32_F3_LINE_303 - [RCC_ADC34] = { .clk_domain = AHB, .line_num = RCC_AHBENR_ADC34EN_BIT }, -#endif - - [RCC_DAC] = { .clk_domain = APB1, .line_num = RCC_APB1ENR_DACEN_BIT }, - - [RCC_DMA1] = { .clk_domain = AHB, .line_num = RCC_AHBENR_DMA1EN_BIT }, - [RCC_DMA2] = { .clk_domain = AHB, .line_num = RCC_AHBENR_DMA2EN_BIT }, - - [RCC_I2C1] = { .clk_domain = APB1, .line_num = RCC_APB1ENR_I2C1EN_BIT }, - [RCC_I2C2] = { .clk_domain = APB1, .line_num = RCC_APB1ENR_I2C2EN_BIT }, - - [RCC_SPI1] = { .clk_domain = APB2, .line_num = RCC_APB2ENR_SPI1EN_BIT }, - [RCC_SPI2] = { .clk_domain = APB1, .line_num = RCC_APB1ENR_SPI2EN_BIT }, - [RCC_SPI3] = { .clk_domain = APB1, .line_num = RCC_APB1ENR_SPI3EN_BIT }, - - [RCC_USART1] = { .clk_domain = APB2, .line_num = RCC_APB2ENR_USART1EN_BIT }, - [RCC_USART2] = { .clk_domain = APB1, .line_num = RCC_APB1ENR_USART2EN_BIT }, - [RCC_USART3] = { .clk_domain = APB1, .line_num = RCC_APB1ENR_USART3EN_BIT }, -#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) - [RCC_UART4] = { .clk_domain = APB1, .line_num = RCC_APB1ENR_UART4EN_BIT }, - [RCC_UART5] = { .clk_domain = APB1, .line_num = RCC_APB1ENR_UART5EN_BIT }, -#endif - - [RCC_TIMER1] = { .clk_domain = APB2, .line_num = RCC_APB2ENR_TIM1EN_BIT }, - [RCC_TIMER2] = { .clk_domain = APB1, .line_num = RCC_APB1ENR_TIM2EN_BIT }, - [RCC_TIMER3] = { .clk_domain = APB1, .line_num = RCC_APB1ENR_TIM3EN_BIT }, - [RCC_TIMER4] = { .clk_domain = APB1, .line_num = RCC_APB1ENR_TIM4EN_BIT }, - [RCC_TIMER6] = { .clk_domain = APB1, .line_num = RCC_APB1ENR_TIM6EN_BIT }, -#if STM32_F3_LINE == STM32_F3_LINE_303 - [RCC_TIMER7] = { .clk_domain = APB1, .line_num = RCC_APB1ENR_TIM7EN_BIT }, - [RCC_TIMER8] = { .clk_domain = APB2, .line_num = RCC_APB2ENR_TIM8EN_BIT }, -#endif - [RCC_TIMER15] = { .clk_domain = APB2, .line_num = RCC_APB2ENR_TIM15EN_BIT }, - [RCC_TIMER16] = { .clk_domain = APB2, .line_num = RCC_APB2ENR_TIM16EN_BIT }, - [RCC_TIMER17] = { .clk_domain = APB2, .line_num = RCC_APB2ENR_TIM17EN_BIT }, - - [RCC_SYSCFG] = { .clk_domain = APB2, .line_num = RCC_APB2ENR_SYSCFGEN_BIT }, - [RCC_PWR] = { .clk_domain = APB1, .line_num = RCC_APB1ENR_PWREN_BIT }, - [RCC_CRC] = { .clk_domain = AHB, .line_num = RCC_AHBENR_CRCEN_BIT }, - [RCC_FLITF] = { .clk_domain = AHB, .line_num = RCC_AHBENR_FLITFEN_BIT }, - [RCC_SRAM] = { .clk_domain = AHB, .line_num = RCC_AHBENR_SRAMEN_BIT }, - [RCC_USB] = { .clk_domain = APB1, .line_num = RCC_APB1ENR_USBEN_BIT }, -}; - -/* pll_cfg->data must point to a valid struct stm32f3_rcc_pll_data. */ -void rcc_configure_pll(rcc_pll_cfg *pll_cfg) { - stm32f3_rcc_pll_data *data = pll_cfg->data; - rcc_pll_multiplier pll_mul = data->pll_mul; - rcc_prediv_divider pclk_prediv = data->pclk_prediv; //TODO use this!!! - uint32 cfgr; - uint32 cfgr2; - - /* Check that the PLL is disabled. */ - ASSERT_FAULT(!rcc_is_clk_on(RCC_CLK_PLL)); - - cfgr2 = RCC_BASE->CFGR2; - cfgr2 &= ~(RCC_CFGR2_PREDIV); - cfgr2 |= pclk_prediv; - RCC_BASE->CFGR2 = cfgr2; - - cfgr = RCC_BASE->CFGR; - cfgr &= ~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLMUL); - cfgr |= pll_cfg->pllsrc | pll_mul; - RCC_BASE->CFGR = cfgr; -} - -void rcc_clk_enable(rcc_clk_id id) { - static __IO uint32* enable_regs[] = { - [APB1] = &RCC_BASE->APB1ENR, - [APB2] = &RCC_BASE->APB2ENR, - [AHB] = &RCC_BASE->AHBENR, - }; - rcc_do_clk_enable(enable_regs, id); -} - -void rcc_reset_dev(rcc_clk_id id) { - static __IO uint32* reset_regs[] = { - [APB1] = &RCC_BASE->APB1RSTR, - [APB2] = &RCC_BASE->APB2RSTR, - [AHB] = &RCC_BASE->AHBRSTR, - }; - rcc_do_reset_dev(reset_regs, id); -} - -void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider) { - static const uint32 masks[] = { - [RCC_PRESCALER_AHB] = RCC_CFGR_HPRE, - [RCC_PRESCALER_APB1] = RCC_CFGR_PPRE1, - [RCC_PRESCALER_APB2] = RCC_CFGR_PPRE2, - [RCC_PRESCALER_USB] = RCC_CFGR_USBPRE, - }; - rcc_do_set_prescaler(masks, prescaler, divider); -} diff --git a/STM32F3/cores/maple/libmaple/stm32f3/f3_spi.c b/STM32F3/cores/maple/libmaple/stm32f3/f3_spi.c deleted file mode 100644 index d5c38a0..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/f3_spi.c +++ /dev/null @@ -1,143 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2011, 2012 LeafLabs, LLC. - * Copyright (c) 2010 Perry Hung. - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/stm32f3/spi.c - * @author Marti Bolivar , - * F3-port by Hanspeter Portner - * @brief STM32F3 SPI/I2S. - */ - -#include -#include -#include "spi_private.h" - -/* - * Devices - */ - -static spi_dev spi1 = SPI_DEV(1); -static spi_dev spi2 = SPI_DEV(2); -static spi_dev spi3 = SPI_DEV(3); - -spi_dev *SPI1 = &spi1; -spi_dev *SPI2 = &spi2; -spi_dev *SPI3 = &spi3; - -/* - * Routines - */ - -void spi_config_gpios(spi_dev *dev, - uint8 as_master, - gpio_dev *nss_dev, - uint8 nss_bit, - gpio_dev *comm_dev, - uint8 sck_bit, - uint8 miso_bit, - uint8 mosi_bit) { - gpio_set_modef(nss_dev, nss_bit, GPIO_MODE_AF, GPIO_MODEF_TYPE_PP); - gpio_set_modef(comm_dev, sck_bit, GPIO_MODE_AF, GPIO_MODEF_TYPE_PP); - gpio_set_modef(comm_dev, miso_bit, GPIO_MODE_AF, GPIO_MODEF_PUPD_NONE); - gpio_set_modef(comm_dev, mosi_bit, GPIO_MODE_AF, GPIO_MODEF_TYPE_PP); - - if ( (dev == SPI1) || (dev == SPI2) ) - { - gpio_set_af(nss_dev, nss_bit, GPIO_AF_5); - gpio_set_af(comm_dev, sck_bit, GPIO_AF_5); - gpio_set_af(comm_dev, miso_bit, GPIO_AF_5); - gpio_set_af(comm_dev, mosi_bit, GPIO_AF_5); - } - else if (dev == SPI3) - { - gpio_set_af(nss_dev, nss_bit, GPIO_AF_6); - gpio_set_af(comm_dev, sck_bit, GPIO_AF_6); - gpio_set_af(comm_dev, miso_bit, GPIO_AF_6); - gpio_set_af(comm_dev, mosi_bit, GPIO_AF_6); - } -} - -void spi_foreach(void (*fn)(spi_dev*)) { - fn(SPI1); - fn(SPI2); - fn(SPI3); -} - -void spi_data_size(struct spi_dev *dev, spi_ds ds) { - uint8 byte_frame = ds <= SPI_DATA_SIZE_8_BIT; - uint32 cr2 = dev->regs->CR2; - cr2 &= ~(SPI_CR2_DS | SPI_CR2_FRXTH); - cr2 |= ds; - if (byte_frame) - cr2 |= SPI_CR2_FRXTH; - dev->regs->CR2 = cr2; -} - -/* - * SPI auxiliary routines - */ -void spi_reconfigure(spi_dev *dev, uint32 cr1_config) { - spi_irq_disable(dev, SPI_INTERRUPTS_ALL); - spi_peripheral_disable(dev); - - uint8 byte_frame = (dev->regs->CR2 & SPI_CR2_DS) <= SPI_DATA_SIZE_8_BIT; - uint32 cr2 = dev->regs->CR2; - cr2 &= ~SPI_CR2_FRXTH; - if (byte_frame) - cr2 |= SPI_CR2_FRXTH; - dev->regs->CR2 = cr2; - - dev->regs->CR1 = cr1_config; - spi_peripheral_enable(dev); -} - -uint16 spi_rx_reg(spi_dev *dev) { - uint8 byte_frame = (dev->regs->CR2 & SPI_CR2_DS) <= SPI_DATA_SIZE_8_BIT; - if (byte_frame) { - __IO uint8 *dr8 = (__IO uint8 *)&dev->regs->DR; /* we need to access as byte */ - return (uint16)*dr8; - } else { - __IO uint16 *dr16 = (__IO uint16 *)&dev->regs->DR; /* we need to access as half-word */ - return (uint16)*dr16; - } -} - -uint32 spi_tx(spi_dev *dev, const void *buf, uint32 len) { - uint32 txed = 0; - uint8 byte_frame = (dev->regs->CR2 & SPI_CR2_DS) <= SPI_DATA_SIZE_8_BIT; - while (spi_is_tx_empty(dev) && (txed < len)) { - if (byte_frame) { - __IO uint8 *dr8 = (__IO uint8 *)&dev->regs->DR; /* we need to access as byte */ - *dr8 = ((const uint8 *)buf)[txed++]; - } else { - __IO uint16 *dr16 = (__IO uint16 *)&dev->regs->DR; /* we need to access as half-word */ - *dr16 = ((const uint16 *)buf)[txed++]; - } - } - return txed; -} diff --git a/STM32F3/cores/maple/libmaple/stm32f3/f3_syscfg.c b/STM32F3/cores/maple/libmaple/stm32f3/f3_syscfg.c deleted file mode 100644 index 9421b2d..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/f3_syscfg.c +++ /dev/null @@ -1,43 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2012 LeafLabs, LLC. - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/stm32f3/syscfg.c - * @author F3-port by Hanspeter Portner - * @brief SYSCFG routines. - */ - -#include -#include -#include - -void syscfg_set_mem_mode(syscfg_mem_mode mode) { - uint32 memrmp = SYSCFG_BASE->CFGR1; - memrmp &= ~SYSCFG_CFGR1_MEM_MODE; - memrmp |= (uint32)mode; - SYSCFG_BASE->CFGR1 = memrmp; -} diff --git a/STM32F3/cores/maple/libmaple/stm32f3/f3_timer.c b/STM32F3/cores/maple/libmaple/stm32f3/f3_timer.c deleted file mode 100644 index 08b9063..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/f3_timer.c +++ /dev/null @@ -1,147 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2011, 2012 LeafLabs, LLC. - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/stm32f3/timer.c - * @author Marti Bolivar , - * F3-port by Hanspeter Portner - * @brief STM32F3 timer. - */ - -#include -#include -#include -#include "timer_private.h" - -/** - * @brief Get the GPIO alternate function corresponding to a timer. - * - * For example, if dev is TIMER1, this function returns - * GPIO_AF_TIM_1_2. This is useful for e.g. using gpio_set_af() to set - * a pin's alternate function to a timer. - * - * @param dev Timer device, must not be TIMER6 or TIMER7. - * @return gpio_af corresponding to dev - * @see gpio_set_af - * @see gpio_af - */ - /* FIXME this has to be inline with the PIN_MAP, but some timers are accessible on different alternate function lanes based on the used pin... */ -gpio_af timer_get_af(timer_dev *dev) { - rcc_clk_id clk_id = dev->clk_id; - /* Timers 6 and 7 don't have any capture/compare, so they can't do - * PWM (and in fact have no AF values). */ - ASSERT(clk_id != RCC_TIMER6 && clk_id != RCC_TIMER7); - switch(dev->clk_id) { - case RCC_TIMER1: - return GPIO_AF_6; - case RCC_TIMER2: // fall-through - case RCC_TIMER3: // fall-through - case RCC_TIMER4: - return GPIO_AF_2; - case RCC_TIMER8: - return GPIO_AF_4; - case RCC_TIMER15: - return GPIO_AF_3; - case RCC_TIMER16: // fall-through - case RCC_TIMER17: - return GPIO_AF_1; - default: - ASSERT(0); // Can't happen - return (gpio_af)-1; - } -} - -/* - * IRQ handlers - * - * Defer to the timer_private dispatch API. - * - * FIXME: The names of these handlers are inaccurate since XL-density - * devices came out. Update these to match the STM32F3 names, maybe - * using some weak symbol magic to preserve backwards compatibility if - * possible. Once that's done, we can just move the IRQ handlers into - * the top-level libmaple/timer.c, and there will be no need for this - * file. - */ - -void __irq_tim1_brk_tim15(void) { - dispatch_adv_brk(TIMER1); - dispatch_tim_9_12(TIMER15); -} - -void __irq_tim1_up_tim16(void) { - dispatch_adv_up(TIMER1); - dispatch_tim_10_11_13_14(TIMER16); -} - -void __irq_tim1_trg_com_tim17(void) { - dispatch_adv_trg_com(TIMER1); - dispatch_tim_10_11_13_14(TIMER17); -} - -void __irq_tim1_cc(void) { - dispatch_adv_cc(TIMER1); -} - -void __irq_tim2(void) { - dispatch_general(TIMER2); -} - -void __irq_tim3(void) { - dispatch_general(TIMER3); -} - -void __irq_tim4(void) { - dispatch_general(TIMER4); -} - -void __irq_tim6_dacunder(void) { - dispatch_basic(TIMER6); - /* FIXME handle DAC12 underrun */ -} - -#if STM32_F3_LINE == STM32_F3_LINE_303 -void __irq_tim7(void) { - dispatch_basic(TIMER7); -} - -void __irq_tim8_brk(void) { - dispatch_adv_brk(TIMER8); -} - -void __irq_tim8_up(void) { - dispatch_adv_up(TIMER8); -} - -void __irq_tim8_trg_com(void) { - dispatch_adv_trg_com(TIMER8); -} - -void __irq_tim8_cc(void) { - dispatch_adv_cc(TIMER8); -} -#endif diff --git a/STM32F3/cores/maple/libmaple/stm32f3/f3_usart.c b/STM32F3/cores/maple/libmaple/stm32f3/f3_usart.c deleted file mode 100644 index 4d466b3..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/f3_usart.c +++ /dev/null @@ -1,210 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/stm32f3/usart.c - * @author F3-port by Hanspeter Portner - * @brief STM32F3 USART. - */ - -#include -#include -#include -#include "usart_private.h" - -/* - * Devices - */ - -static ring_buffer usart1_rb; -static usart_dev usart1 = { - .regs = USART1_BASE, - .rb = &usart1_rb, - .max_baud = 4500000UL, - .clk_id = RCC_USART1, - .irq_num = NVIC_USART1, -}; -/** USART1 device */ -usart_dev *USART1 = &usart1; - -static ring_buffer usart2_rb; -static usart_dev usart2 = { - .regs = USART2_BASE, - .rb = &usart2_rb, - .max_baud = 2250000UL, - .clk_id = RCC_USART2, - .irq_num = NVIC_USART2, -}; -/** USART2 device */ -usart_dev *USART2 = &usart2; - -static ring_buffer usart3_rb; -static usart_dev usart3 = { - .regs = USART3_BASE, - .rb = &usart3_rb, - .max_baud = 2250000UL, - .clk_id = RCC_USART3, - .irq_num = NVIC_USART3, -}; -/** USART3 device */ -usart_dev *USART3 = &usart3; - -#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) -static ring_buffer uart4_rb; -static usart_dev uart4 = { - .regs = UART4_BASE, - .rb = &uart4_rb, - .max_baud = 2250000UL, - .clk_id = RCC_UART4, - .irq_num = NVIC_UART4, -}; -/** UART4 device */ -usart_dev *UART4 = &uart4; - -static ring_buffer uart5_rb; -static usart_dev uart5 = { - .regs = UART5_BASE, - .rb = &uart5_rb, - .max_baud = 2250000UL, - .clk_id = RCC_UART5, - .irq_num = NVIC_UART5, -}; -/** UART5 device */ -usart_dev *UART5 = &uart5; -#endif - -/* - * Routines - */ - -void usart_config_gpios_async(usart_dev *udev, - gpio_dev *rx_dev, uint8 rx, - gpio_dev *tx_dev, uint8 tx, - unsigned flags) { - gpio_af af = usart_get_af(udev); - gpio_set_modef(rx_dev, rx, GPIO_MODE_AF, GPIO_MODEF_PUPD_NONE); - //gpio_set_modef(tx_dev, tx, GPIO_MODE_AF, GPIO_MODEF_TYPE_PP); - gpio_set_modef(tx_dev, tx, GPIO_MODE_AF, GPIO_MODEF_TYPE_OD); - gpio_set_af(rx_dev, rx, af); - gpio_set_af(tx_dev, tx, af); -} - -void usart_set_baud_rate(usart_dev *dev, uint32 clock_speed, uint32 baud) { - /* Figure out the clock speed, if the user doesn't give one. */ - if (clock_speed == 0) { - clock_speed = _usart_clock_freq(dev); - } - ASSERT(clock_speed); - - uint32 divider = clock_speed / baud; - uint32 tmpreg = clock_speed % baud; - /* round divider : if fractional part i greater than 0.5 increment divider */ - if (tmpreg >= baud / 2) - divider++; - dev->regs->BRR = (uint16)divider; -} - -uint32 usart_tx(usart_dev *dev, const uint8 *buf, uint32 len) { - usart_reg_map *regs = dev->regs; - uint32 txed = 0; - while ((regs->SR & USART_SR_TXE) && (txed < len)) { - regs->TDR = buf[txed++] & USART_TDR_TDR; - } - return txed; -} - -/** - * @brief Call a function on each USART. - * @param fn Function to call. - */ -void usart_foreach(void (*fn)(usart_dev*)) { - fn(USART1); - fn(USART2); - fn(USART3); -#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) - fn(UART4); - fn(UART5); -#endif -} - -/** - * @brief Get GPIO alternate function mode for a USART. - * @param dev USART whose gpio_af to get. - * @return gpio_af corresponding to dev. - */ -gpio_af usart_get_af(usart_dev *dev) { - switch (dev->clk_id) { - case RCC_USART1: - case RCC_USART2: - case RCC_USART3: - return GPIO_AF_7; -#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) - case RCC_UART4: - case RCC_UART5: - return GPIO_AF_5; -#endif - default: - ASSERT(0); /* Can't happen */ - return (gpio_af)-1; - } -} - -/* - * Interrupt handlers. - */ - -static __always_inline void usart_irq(ring_buffer *rb, usart_reg_map *regs) { -#ifdef USART_SAFE_INSERT - /* If the buffer is full and the user defines USART_SAFE_INSERT, - * ignore new bytes. */ - rb_safe_insert(rb, regs->RDR & USART_RDR_RDR); -#else - /* By default, push bytes around in the ring buffer. */ - rb_push_insert(rb, regs->RDR & USART_RDR_RDR); -#endif -} - -void __irq_usart1(void) { - usart_irq(&usart1_rb, USART1_BASE); -} - -void __irq_usart2(void) { - usart_irq(&usart2_rb, USART2_BASE); -} - -void __irq_usart3(void) { - usart_irq(&usart3_rb, USART3_BASE); -} - -#ifdef STM32_HIGH_DENSITY -void __irq_uart4(void) { - usart_irq(&uart4_rb, UART4_BASE); -} - -void __irq_uart5(void) { - usart_irq(&uart5_rb, UART5_BASE); -} -#endif diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/adc.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/adc.h deleted file mode 100644 index 8f4edde..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/adc.h +++ /dev/null @@ -1,696 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/stm32f3/include/series/adc.h - * @author F3-port by Hanspeter Portner - * @brief STM32F3 ADC support. - */ - -#ifndef _LIBMAPLE_STM32F3_ADC_H_ -#define _LIBMAPLE_STM32F3_ADC_H_ - -#include -#include -#include /* For the prescalers */ - -/* - * Register map - */ - -/* - * ADC individual register map type. - */ -typedef struct adc_reg_map { - __IO uint32 ISR; /**< */ - __IO uint32 IER; /**< */ - __IO uint32 CR; /**< */ - __IO uint32 CFGR; /**< */ - uint32 reserved1; - __IO uint32 SMPR1; /**< */ - __IO uint32 SMPR2; /**< */ - uint32 reserved2; - __IO uint32 TR1; /**< */ - __IO uint32 TR2; /**< */ - __IO uint32 TR3; /**< */ - uint32 reserved3; - __IO uint32 SQR1; /**< */ - __IO uint32 SQR2; /**< */ - __IO uint32 SQR3; /**< */ - __IO uint32 SQR4; /**< */ - __IO uint32 DR; /**< */ - uint32 reserved4 [2]; - __IO uint32 JSQR; /**< */ - uint32 reserved5 [4]; - __IO uint32 OFR1; /**< */ - __IO uint32 OFR2; /**< */ - __IO uint32 OFR3; /**< */ - __IO uint32 OFR4; /**< */ - uint32 reserved6 [4]; - __IO uint32 JDR1; /**< */ - __IO uint32 JDR2; /**< */ - __IO uint32 JDR3; /**< */ - __IO uint32 JDR4; /**< */ - uint32 reserved7 [4]; - __IO uint32 AWD2CR; /**< */ - __IO uint32 AWD3CR; /**< */ - uint32 reserved8 [2]; - __IO uint32 DIFSEL; /**< */ - __IO uint32 CALFACT; /**< */ -} adc_reg_map; - -/* - * ADC master and slave common register map type. - */ -typedef struct adc_common_reg_map { - __IO uint32 CSR; /**< */ - uint32 reserved; - __IO uint32 CCR; /**< */ - __IO uint32 CDR; /**< */ -} adc_common_reg_map; - -/** ADC device type. */ -typedef struct adc_dev { - adc_reg_map *regs; /**< Register map */ - rcc_clk_id clk_id; /**< RCC clock information */ - adc_private_data *priv; /**< ADC private data */ -} adc_dev; - -/* - * Devices - */ - -extern const struct adc_dev *ADC1; /* master */ -extern const struct adc_dev *ADC2; /* slave */ -#if STM32_F3_LINE == STM32_F3_LINE_303 -extern const struct adc_dev *ADC3; /* master */ -extern const struct adc_dev *ADC4; /* slave */ -#endif - -/* - * Register map base pointers - */ - -/** STM32F3 ADC1 individual register map base pointer. */ -#define ADC1_BASE ((struct adc_reg_map*)0x50000000) -/** STM32F3 ADC2 individual register map base pointer. */ -#define ADC2_BASE ((struct adc_reg_map*)0x50000100) -/** STM32F3 ADC1/ADC2 common register map base pointer. */ -#define ADC12_BASE ((struct adc_common_reg_map*)0x50000300) -#if STM32_F3_LINE == STM32_F3_LINE_303 -/** STM32F3 ADC3 individual register map base pointer. */ -#define ADC3_BASE ((struct adc_reg_map*)0x50000400) -/** STM32F3 ADC4 individual register map base pointer. */ -#define ADC4_BASE ((struct adc_reg_map*)0x50000500) -/** STM32F3 ADC3/ADC4 common register map base pointer. */ -#define ADC34_BASE ((struct adc_common_reg_map*)0x50000700) -#endif - -/* - * Register bit definitions - */ - -/* Interrupt and status register */ -#define ADC_ISR_JQOVF_BIT 10 -#define ADC_ISR_AWD3_BIT 9 -#define ADC_ISR_AWD2_BIT 8 -#define ADC_ISR_AWD1_BIT 7 -#define ADC_ISR_JEOS_BIT 6 -#define ADC_ISR_JEOC_BIT 5 -#define ADC_ISR_OVR_BIT 4 -#define ADC_ISR_EOS_BIT 3 -#define ADC_ISR_EOC_BIT 2 -#define ADC_ISR_EOSMP_BIT 1 -#define ADC_ISR_ADRDY_BIT 0 - -#define ADC_ISR_JQOVF (1U << ADC_ISR_JQOVF_BIT) -#define ADC_ISR_AWD3 (1U << ADC_ISR_AWD3_BIT) -#define ADC_ISR_AWD2 (1U << ADC_ISR_AWD2_BIT) -#define ADC_ISR_AWD1 (1U << ADC_ISR_AWD1_BIT) -#define ADC_ISR_JEOS (1U << ADC_ISR_JEOS_BIT) -#define ADC_ISR_JEOC (1U << ADC_ISR_JEOC_BIT) -#define ADC_ISR_OVR (1U << ADC_ISR_OVR_BIT) -#define ADC_ISR_EOS (1U << ADC_ISR_EOS_BIT) -#define ADC_ISR_EOC (1U << ADC_ISR_EOC_BIT) -#define ADC_ISR_EOSMP (1U << ADC_ISR_EOSMP_BIT) -#define ADC_ISR_ADRDY (1U << ADC_ISR_ADRDY_BIT) - -/* FIXME make an enum out of this */ -#define ADC_WATCHDOG_1_INTERRUPT ADC_ISR_AWD1 -#define ADC_WATCHDOG_2_INTERRUPT ADC_ISR_AWD2 -#define ADC_WATCHDOG_3_INTERRUPT ADC_ISR_AWD3 -#define ADC_CONV_INTERRUPT ADC_ISR_EOC -#define ADC_INJ_CONV_INTERRUPT ADC_ISR_JEOC -#define ADC_OVERRUN_INTERRUPT ADC_ISR_OVR -#define ADC_ALL_INTERRUPTS (ADC_CONV_INTERRUPT | ADC_WATCHDOG_1_INTERRUPT | ADC_WATCHDOG_2_INTERRUPT | ADC_WATCHDOG_3_INTERRUPT | ADC_INJ_CONV_INTERRUPT | ADC_OVERRUN_INTERRUPT) - -/* Interrupt enable register */ -#define ADC_IER_JQOVF_BIT 10 -#define ADC_IER_AWD3_BIT 9 -#define ADC_IER_AWD2_BIT 8 -#define ADC_IER_AWD1_BIT 7 -#define ADC_IER_JEOS_BIT 6 -#define ADC_IER_JEOC_BIT 5 -#define ADC_IER_OVR_BIT 4 -#define ADC_IER_EOS_BIT 3 -#define ADC_IER_EOC_BIT 2 -#define ADC_IER_EOSMP_BIT 1 -#define ADC_IER_ADRDY_BIT 0 - -#define ADC_IER_JQOVF (1U << ADC_IER_JQOVF_BIT) -#define ADC_IER_AWD3 (1U << ADC_IER_AWD3_BIT) -#define ADC_IER_AWD2 (1U << ADC_IER_AWD2_BIT) -#define ADC_IER_AWD1 (1U << ADC_IER_AWD1_BIT) -#define ADC_IER_JEOS (1U << ADC_IER_JEOS_BIT) -#define ADC_IER_JEOC (1U << ADC_IER_JEOC_BIT) -#define ADC_IER_OVR (1U << ADC_IER_OVR_BIT) -#define ADC_IER_EOS (1U << ADC_IER_EOS_BIT) -#define ADC_IER_EOC (1U << ADC_IER_EOC_BIT) -#define ADC_IER_EOSMP (1U << ADC_IER_EOSMP_BIT) -#define ADC_IER_ADRDY (1U << ADC_IER_ADRDY_BIT) - -/* Control register */ -#define ADC_CR_ADCAL_BIT 31 -#define ADC_CR_ADCALDIF_BIT 30 -#define ADC_CR_ADVREGEN_SHIFT 28 -#define ADC_CR_JADSTP_BIT 5 -#define ADC_CR_ADSTP_BIT 4 -#define ADC_CR_JADSTART_BIT 3 -#define ADC_CR_ADSTART_BIT 2 -#define ADC_CR_ADDIS_BIT 1 -#define ADC_CR_ADEN_BIT 0 - -#define ADC_CR_ADCAL (1U << ADC_CR_ADCAL_BIT) -#define ADC_CR_ADCALDIF (1U << ADC_CR_ADCALDIF_BIT) -#define ADC_CR_ADVREGEN (0x3 << ADC_CR_ADVREGEN_SHIFT) -#define ADC_CR_ADVREGEN_ENABLE (0x1 << ADC_CR_ADVREGEN_SHIFT) -#define ADC_CR_ADVREGEN_DISABLE (0x2 << ADC_CR_ADVREGEN_SHIFT) -#define ADC_CR_JADSTP (1U << ADC_CR_JADSTP_BIT) -#define ADC_CR_ADSTP (1U << ADC_CR_ADSTP_BIT) -#define ADC_CR_JADSTART (1U << ADC_CR_JADSTART_BIT) -#define ADC_CR_ADSTART (1U << ADC_CR_ADSTART_BIT) -#define ADC_CR_ADDIS (1U << ADC_CR_ADDIS_BIT) -#define ADC_CR_ADEN (1U << ADC_CR_ADEN_BIT) - -/* Configuration register */ -#define ADC_CFGR_AWD1CH_SHIFT 26 -#define ADC_CFGR_JAUTO_BIT 25 -#define ADC_CFGR_JAWD1EN_BIT 24 -#define ADC_CFGR_AWD1EN_BIT 23 -#define ADC_CFGR_AWD1SGL_BIT 22 -#define ADC_CFGR_JQM_BIT 21 -#define ADC_CFGR_JDISCEN_BIT 20 -#define ADC_CFGR_JDISCNUM_SHIFT 17 -#define ADC_CFGR_DISCEN_BIT 16 -#define ADC_CFGR_AUTDLY_BIT 14 -#define ADC_CFGR_CONT_BIT 13 -#define ADC_CFGR_OVRMOD_BIT 12 -#define ADC_CFGR_EXTEN_SHIFT 10 -#define ADC_CFGR_EXTSEL_SHIFT 6 -#define ADC_CFGR_ALIGN_BIT 5 -#define ADC_CFGR_RES_SHIFT 3 -#define ADC_CFGR_DMACFG_BIT 1 -#define ADC_CFGR_DMAEN_BIT 0 - -#define ADC_CFGR_AWD1CH (0x1F << ADC_CFGR_AWD1CH_SHIFT) -#define ADC_CFGR_JAUTO (1U << ADC_CFGR_JAUTO_BIT) -#define ADC_CFGR_JAWD1EN (1U << ADC_CFGR_JAWD1EN_BIT) -#define ADC_CFGR_AWD1EN (1U << ADC_CFGR_AWD1EN_BIT) -#define ADC_CFGR_AWD1SGL (1U << ADC_CFGR_AWD1SGL_BIT) -#define ADC_CFGR_JQM (1U << ADC_CFGR_JQM_BIT) -#define ADC_CFGR_JDISCEN (1U << ADC_CFGR_JDISCEN_BIT) -#define ADC_CFGR_JDISCNUM (0x7 << ADC_CFGR_JDISCNUM_SHIFT) -#define ADC_CFGR_DISCEN (1U << ADC_CFGR_DISCEN_BIT) -#define ADC_CFGR_AUTODLY (1U << ADC_CFGR_AUTODLY_BIT) -#define ADC_CFGR_CONT (1U << ADC_CFGR_CONT_BIT) -#define ADC_CFGR_OVRMOD (1U << ADC_CFGR_OVRMOD_BIT) -#define ADC_CFGR_EXTEN (0x3 << ADC_CFGR_EXTEN_SHIFT) -#define ADC_CFGR_EXTSEL (0xF << ADC_CFGR_EXTSEL_SHIFT) -#define ADC_CFGR_ALIGN (1U << ADC_CFGR_ALIGN_BIT) -#define ADC_CFGR_RES (0x3 << ADC_CFGR_RES_SHIFT) -#define ADC_CFGR_DMACFG (1U << ADC_CFGR_DMACFG_BIT) -#define ADC_CFGR_DMAEN (1U << ADC_CFGR_DMAEN_BIT) - -/* Sample time register 1 */ -#define ADC_SMPR1_SMP9 (0x7 << 27) -#define ADC_SMPR1_SMP8 (0x7 << 24) -#define ADC_SMPR1_SMP7 (0x7 << 21) -#define ADC_SMPR1_SMP6 (0x7 << 18) -#define ADC_SMPR1_SMP5 (0x7 << 15) -#define ADC_SMPR1_SMP4 (0x7 << 12) -#define ADC_SMPR1_SMP3 (0x7 << 9) -#define ADC_SMPR1_SMP2 (0x7 << 6) -#define ADC_SMPR1_SMP1 (0x7 << 3) - -/* Sample time register 2 */ -#define ADC_SMPR2_SMP18 (0x7 << 24) -#define ADC_SMPR2_SMP17 (0x7 << 21) -#define ADC_SMPR2_SMP16 (0x7 << 18) -#define ADC_SMPR2_SMP15 (0x7 << 15) -#define ADC_SMPR2_SMP14 (0x7 << 12) -#define ADC_SMPR2_SMP13 (0x7 << 9) -#define ADC_SMPR2_SMP12 (0x7 << 6) -#define ADC_SMPR2_SMP11 (0x7 << 3) -#define ADC_SMPR2_SMP10 0x7 - -/* Analog watchdog 1 threshold register */ -#define ADC_TR1_HT1 (0xFFF << 16) /* 12bit watchdog */ -#define ADC_TR1_LT1 0xFFF - -/* Analog watchdog 2 threshold register */ -#define ADC_TR2_HT2 (0xFF << 16) /* 8bit watchdog */ -#define ADC_TR2_LT2 0xFF - -/* Analog watchdog 3 threshold register */ -#define ADC_TR3_HT3 (0xFF << 16) /* 8bit watchdog */ -#define ADC_TR3_LT3 0xFF - -/* Regular sequence register 1 */ -#define ADC_SQR1_SQ4 (0x1F << 24) -#define ADC_SQR1_SQ3 (0x1F << 18) -#define ADC_SQR1_SQ2 (0x1F << 12) -#define ADC_SQR1_SQ1 (0x1F << 6) -#define ADC_SQR1_L 0xF - -/* Regular sequence register 2 */ -#define ADC_SQR2_SQ9 (0x1F << 24) -#define ADC_SQR2_SQ8 (0x1F << 18) -#define ADC_SQR2_SQ7 (0x1F << 12) -#define ADC_SQR2_SQ6 (0x1F << 6) -#define ADC_SQR2_SQ5 0x1F - -/* Regular sequence register 3 */ -#define ADC_SQR3_SQ14 (0x1F << 24) -#define ADC_SQR3_SQ13 (0x1F << 18) -#define ADC_SQR3_SQ12 (0x1F << 12) -#define ADC_SQR3_SQ11 (0x1F << 6) -#define ADC_SQR3_SQ10 0x1F - -/* Regular sequence register 4 */ -#define ADC_SQR4_SQ16 (0x1F << 6) -#define ADC_SQR4_SQ15 0x1F - -/* Regular data register */ -#define ADC_DR_RDATA 0xFFFF - -/* Injected sequence register */ -#define ADC_JSQR_JEXTEN_SHIFT 6 -#define ADC_JSQR_JEXTSEL_SHIFT 2 - -#define ADC_JSQR_SQ4 (0x1F << 26) -#define ADC_JSQR_SQ3 (0x1F << 20) -#define ADC_JSQR_SQ2 (0x1F << 14) -#define ADC_JSQR_SQ1 (0x1F << 8) -#define ADC_JSQR_JEXTEN (0x3 << ADC_JSQR_JEXTEN_SHIFT) -#define ADC_JSQR_JEXTSEL (0xF << ADC_JSQR_JEXTSEL_SHIFT) -#define ADC_JSQR_JL 0x3 - -/* Offset register 1 */ -#define ADC_OFR1_OFFSET1EN_BIT 31 - -#define ADC_OFR1_OFFSET1ENT (1U << ADC_OFR1_OFFSET1EN_BIT) -#define ADC_OFR1_OFFSET1_CH (0x1F << 26) -#define ADC_OFR1_OFFSET1 0xFFF - -/* Offset register 2 */ -#define ADC_OFR2_OFFSET2EN_BIT 31 - -#define ADC_OFR2_OFFSET2EN (1U << ADC_OFR2_OFFSET2EN_BIT) -#define ADC_OFR2_OFFSET2_CH (0x1F << 26) -#define ADC_OFR2_OFFSET2 0xFFF - -/* Offset register 3 */ -#define ADC_OFR3_OFFSET3EN_BIT 31 - -#define ADC_OFR3_OFFSET3EN (1U << ADC_OFR3_OFFSET3EN_BIT) -#define ADC_OFR3_OFFSET3_CH (0x1F << 26) -#define ADC_OFR3_OFFSET3 0xFFF - -/* Offset register 4 */ -#define ADC_OFR4_OFFSET4EN_BIT 31 - -#define ADC_OFR4_OFFSET4EN (1U << ADC_OFR4_OFFSET4EN_BIT) -#define ADC_OFR4_OFFSET4_CH (0x1F << 26) -#define ADC_OFR4_OFFSET4 0xFFF - -/* Injected data register 1 */ -#define ADC_JDR1_JDATA1 0xFFFF - -/* Injected data register 2 */ -#define ADC_JDR2_JDATA2 0xFFFF - -/* Injected data register 3 */ -#define ADC_JDR3_JDATA3 0xFFFF - -/* Injected data register 4 */ -#define ADC_JDR4_JDATA4 0xFFFF - -/* Analog watchdog 2 configuration register */ -#define ADC_AWD2CR_AWD2CH (0x1FFFF << 1) - -/* Analog watchdog 3 configuration register */ -#define ADC_AWD3CR_AWD3CH (0x1FFFF << 1) - -/* Differential mode selection register */ -#define ADC_DIFSEL_DIFSEL (0x1FFFF << 1) - -/* Calibration factors */ -#define ADC_CALFACT_CALFACT_D (0x7F << 16) -#define ADC_CALFACT_CALFACT_S 0x7F - -/* Common status register */ -#define ADC_CSR_JQOVF_SLV_BIT 26 -#define ADC_CSR_AWD3_SLV_BIT 25 -#define ADC_CSR_AWD2_SLV_BIT 24 -#define ADC_CSR_AWD1_SLV_BIT 23 -#define ADC_CSR_JEOS_SLV_BIT 22 -#define ADC_CSR_JEOC_SLV_BIT 21 -#define ADC_CSR_OVR_SLV_BIT 20 -#define ADC_CSR_EOS_SLV_BIT 19 -#define ADC_CSR_EOC_SLV_BIT 18 -#define ADC_CSR_EOSMP_SLV_BIT 17 -#define ADC_CSR_ADRDY_SLV_BIT 16 - -#define ADC_CSR_JQOVF_MST_BIT 10 -#define ADC_CSR_AWD3_MST_BIT 9 -#define ADC_CSR_AWD2_MST_BIT 8 -#define ADC_CSR_AWD1_MST_BIT 7 -#define ADC_CSR_JEOS_MST_BIT 6 -#define ADC_CSR_JEOC_MST_BIT 5 -#define ADC_CSR_OVR_MST_BIT 4 -#define ADC_CSR_EOS_MST_BIT 3 -#define ADC_CSR_EOC_MST_BIT 2 -#define ADC_CSR_EOSMP_MST_BIT 1 -#define ADC_CSR_ADRDY_MST_BIT 0 - -#define ADC_CSR_JQOVF_SLV (1U << ADC_CSR_JQOVF_SLV_BIT) -#define ADC_CSR_AWD3_SLV (1U << ADC_CSR_AWD3_SLV_BIT) -#define ADC_CSR_AWD2_SLV (1U << ADC_CSR_AWD2_SLV_BIT) -#define ADC_CSR_AWD1_SLV (1U << ADC_CSR_AWD1_SLV_BIT) -#define ADC_CSR_JEOS_SLV (1U << ADC_CSR_JEOS_SLV_BIT) -#define ADC_CSR_JEOC_SLV (1U << ADC_CSR_JEOC_SLV_BIT) -#define ADC_CSR_OVR_SLV (1U << ADC_CSR_OVR_SLV_BIT) -#define ADC_CSR_EOS_SLV (1U << ADC_CSR_EOS_SLV_BIT) -#define ADC_CSR_EOC_SLV (1U << ADC_CSR_EOC_SLV_BIT) -#define ADC_CSR_EOSMP_SLV (1U << ADC_CSR_EOS_MP_SLV_BIT) -#define ADC_CSR_ADRDY_SLV (1U << ADC_CSR_ADRDY_SLV_BIT) - -#define ADC_CSR_JQOVF_MST (1U << ADC_CSR_JQOVF_MST_BIT) -#define ADC_CSR_AWD3_MST (1U << ADC_CSR_AWD3_MST_BIT) -#define ADC_CSR_AWD2_MST (1U << ADC_CSR_AWD2_MST_BIT) -#define ADC_CSR_AWD1_MST (1U << ADC_CSR_AWD1_MST_BIT) -#define ADC_CSR_JEOS_MST (1U << ADC_CSR_JEOS_MST_BIT) -#define ADC_CSR_JEOC_MST (1U << ADC_CSR_JEOC_MST_BIT) -#define ADC_CSR_OVR_MST (1U << ADC_CSR_OVR_MST_BIT) -#define ADC_CSR_EOS_MST (1U << ADC_CSR_EOS_MST_BIT) -#define ADC_CSR_EOC_MST (1U << ADC_CSR_EOC_MST_BIT) -#define ADC_CSR_EOSMP_MST (1U << ADC_CSR_EOS_MP_MST_BIT) -#define ADC_CSR_ADRDY_MST (1U << ADC_CSR_ADRDY_MST_BIT) - -/* Common control register */ -#define ADC_CCR_VBATEN_BIT 24 -#define ADC_CCR_TSEN_BIT 23 -#define ADC_CCR_VREFEN_BIT 22 -#define ADC_CCR_CKMODE_SHIFT 16 -#define ADC_CCR_MDMA_SHIFT 14 -#define ADC_CCR_DMACFG_BIT 13 -#define ADC_CCR_DELAY_SHIFT 8 -#define ADC_CCR_DUAL_SHIFT 0 - -#define ADC_CCR_VBATEN (1U << ADC_CCR_VBATEN_BIT) -#define ADC_CCR_TSEN (1U << ADC_CCR_TSEN_BIT) -#define ADC_CCR_VREFEN (1U << ADC_CCR_VREFEN_BIT) -#define ADC_CCR_CKMODE (0x3 << ADC_CCR_CKMODE_SHIFT) -#define ADC_CCR_MDMA (0x3 << ADC_CCR_MDMA_SHIFT) -#define ADC_CCR_DMACFG (1U << ADC_CCR_DMACFG_BIT) -#define ADC_CCR_DELAY (0xF << ADC_CCR_DELAY_SHIFT) -#define ADC_CCR_DUAL 0X1F - -/* Common regular data register for dual mode */ -#define ADC_CDR_RDATA_SLV (0xFFFF << 16) -#define ADC_CDR_RDATA_MST 0xFFFF - -/* - * Other types - */ - -/** - * @brief STM32F3 external event selectors for regular group - * conversion. - * - * For ease of use, each event selector is given along with the ADCs - * it's available on, along with any other availability restrictions. - * - * @see adc_set_extsel() - */ -typedef enum adc_extsel_event { - /* ADC1 (master) and ADC2 (slave) regular channels */ - ADC12_EXT_EV_TIM1_CC1 = 0x0 << ADC_CFGR_EXTSEL_SHIFT, - ADC12_EXT_EV_TIM1_CC2 = 0x1 << ADC_CFGR_EXTSEL_SHIFT, - ADC12_EXT_EV_TIM1_CC3 = 0x2 << ADC_CFGR_EXTSEL_SHIFT, - ADC12_EXT_EV_TIM2_CC2 = 0x3 << ADC_CFGR_EXTSEL_SHIFT, - ADC12_EXT_EV_TIM3_TRGO = 0x4 << ADC_CFGR_EXTSEL_SHIFT, - ADC12_EXT_EV_TIM4_CC4 = 0x5 << ADC_CFGR_EXTSEL_SHIFT, - ADC12_EXT_EV_EXTI_11 = 0x6 << ADC_CFGR_EXTSEL_SHIFT, - ADC12_EXT_EV_TIM8_TRGO = 0x7 << ADC_CFGR_EXTSEL_SHIFT, - ADC12_EXT_EV_TIM8_TRGO2 = 0x8 << ADC_CFGR_EXTSEL_SHIFT, - ADC12_EXT_EV_TIM1_TRGO = 0x9 << ADC_CFGR_EXTSEL_SHIFT, - ADC12_EXT_EV_TIM1_TRGO2 = 0xA << ADC_CFGR_EXTSEL_SHIFT, - ADC12_EXT_EV_TIM2_TRGO = 0xB << ADC_CFGR_EXTSEL_SHIFT, - ADC12_EXT_EV_TIM4_TRGO = 0xC << ADC_CFGR_EXTSEL_SHIFT, - ADC12_EXT_EV_TIM6_TRGO = 0xD << ADC_CFGR_EXTSEL_SHIFT, - ADC12_EXT_EV_TIM15_TRGO = 0xE << ADC_CFGR_EXTSEL_SHIFT, - ADC12_EXT_EV_TIM3_CC4 = 0xF << ADC_CFGR_EXTSEL_SHIFT, - - /* ADC1 (master) and ADC2 (slave) injected channels */ - ADC12_JEXT_EV_TIM1_TRGO = 0x0 << ADC_JSQR_JEXTSEL_SHIFT, - ADC12_JEXT_EV_TIM1_CC4 = 0x1 << ADC_JSQR_JEXTSEL_SHIFT, - ADC12_JEXT_EV_TIM2_TRGO = 0x2 << ADC_JSQR_JEXTSEL_SHIFT, - ADC12_JEXT_EV_TIM2_CC1 = 0x3 << ADC_JSQR_JEXTSEL_SHIFT, - ADC12_JEXT_EV_TIM3_CC4 = 0x4 << ADC_JSQR_JEXTSEL_SHIFT, - ADC12_JEXT_EV_TIM4_TRGO = 0x5 << ADC_JSQR_JEXTSEL_SHIFT, - ADC12_JEXT_EV_EXTI_15 = 0x6 << ADC_JSQR_JEXTSEL_SHIFT, - ADC12_JEXT_EV_TIM8_CC4 = 0x7 << ADC_JSQR_JEXTSEL_SHIFT, - ADC12_JEXT_EV_TIM1_TRGO2 = 0x8 << ADC_JSQR_JEXTSEL_SHIFT, - ADC12_JEXT_EV_TIM8_TRGO = 0x9 << ADC_JSQR_JEXTSEL_SHIFT, - ADC12_JEXT_EV_TIM8_TRGO2 = 0xA << ADC_JSQR_JEXTSEL_SHIFT, - ADC12_JEXT_EV_TIM3_CC3 = 0xB << ADC_JSQR_JEXTSEL_SHIFT, - ADC12_JEXT_EV_TIM3_TRGO = 0xC << ADC_JSQR_JEXTSEL_SHIFT, - ADC12_JEXT_EV_TIM3_CC1 = 0xD << ADC_JSQR_JEXTSEL_SHIFT, - ADC12_JEXT_EV_TIM6_TRGO = 0xE << ADC_JSQR_JEXTSEL_SHIFT, - ADC12_JEXT_EV_TIM15_TRGO = 0xF << ADC_JSQR_JEXTSEL_SHIFT, - - /* ADC3 (master) and ADC4 (slave) injected channels */ - ADC34_EXT_EV_TIM3_CC1 = 0x0 << ADC_CFGR_EXTSEL_SHIFT, - ADC34_EXT_EV_TIM3_CC3 = 0x1 << ADC_CFGR_EXTSEL_SHIFT, - ADC34_EXT_EV_TIM1_cc3 = 0x2 << ADC_CFGR_EXTSEL_SHIFT, - ADC34_EXT_EV_TIM8_CC1 = 0x3 << ADC_CFGR_EXTSEL_SHIFT, - ADC34_EXT_EV_TIM8_TRGO = 0x4 << ADC_CFGR_EXTSEL_SHIFT, - ADC34_EXT_EV_EXTI_2 = 0x5 << ADC_CFGR_EXTSEL_SHIFT, - ADC34_EXT_EV_TIM4_CC1 = 0x6 << ADC_CFGR_EXTSEL_SHIFT, - ADC34_EXT_EV_TIM2_TRGO = 0x7 << ADC_CFGR_EXTSEL_SHIFT, - ADC34_EXT_EV_TIM8_TRGO2 = 0x8 << ADC_CFGR_EXTSEL_SHIFT, - ADC34_EXT_EV_TIM1_TRGO = 0x9 << ADC_CFGR_EXTSEL_SHIFT, - ADC34_EXT_EV_TIM1_TRGO2 = 0xA << ADC_CFGR_EXTSEL_SHIFT, - ADC34_EXT_EV_TIM3_TRGO = 0xB << ADC_CFGR_EXTSEL_SHIFT, - ADC34_EXT_EV_TIM4_TRGO = 0xC << ADC_CFGR_EXTSEL_SHIFT, - ADC34_EXT_EV_TIM7_TRGO = 0xD << ADC_CFGR_EXTSEL_SHIFT, - ADC34_EXT_EV_TIM15_TRGO = 0xE << ADC_CFGR_EXTSEL_SHIFT, - ADC34_EXT_EV_TIM2_CC1 = 0xF << ADC_CFGR_EXTSEL_SHIFT, - - /* ADC3 (master) and ADC4 (slave) injected channels */ - ADC34_JEXT_EV_TIM1_TRGO = 0x0 << ADC_JSQR_JEXTSEL_SHIFT, - ADC34_JEXT_EV_TIM1_CC4 = 0x1 << ADC_JSQR_JEXTSEL_SHIFT, - ADC34_JEXT_EV_TIM4_CC3 = 0x2 << ADC_JSQR_JEXTSEL_SHIFT, - ADC34_JEXT_EV_TIM8_CC2 = 0x3 << ADC_JSQR_JEXTSEL_SHIFT, - ADC34_JEXT_EV_TIM8_CC4 = 0x4 << ADC_JSQR_JEXTSEL_SHIFT, - /* ADC34_JEXT_EV_TIM4_CC3 = 0x5 << ADC_JSQR_JEXTSEL_SHIFT, */ /* FIXME duplicate or typo in manual? */ - ADC34_JEXT_EV_TIM4_CC4 = 0x6 << ADC_JSQR_JEXTSEL_SHIFT, - ADC34_JEXT_EV_TIM4_TRGO = 0x7 << ADC_JSQR_JEXTSEL_SHIFT, - ADC34_JEXT_EV_TIM1_TRGO2 = 0x8 << ADC_JSQR_JEXTSEL_SHIFT, - ADC34_JEXT_EV_TIM8_TRGO = 0x9 << ADC_JSQR_JEXTSEL_SHIFT, - ADC34_JEXT_EV_TIM8_TRGO2 = 0xA << ADC_JSQR_JEXTSEL_SHIFT, - ADC34_JEXT_EV_TIM1_CC3 = 0xB << ADC_JSQR_JEXTSEL_SHIFT, - ADC34_JEXT_EV_TIM3_TRGO = 0xC << ADC_JSQR_JEXTSEL_SHIFT, - ADC34_JEXT_EV_TIM2_TRGO = 0xD << ADC_JSQR_JEXTSEL_SHIFT, - ADC34_JEXT_EV_TIM7_TRGO = 0xE << ADC_JSQR_JEXTSEL_SHIFT, - ADC34_JEXT_EV_TIM15_TRGO = 0xF << ADC_JSQR_JEXTSEL_SHIFT, -} adc_extsel_event; - -/** - * @brief STM32F3 ADC trigger mode. - * - * These control the trigger mode of the ADC, which can be set to: - * Software trigger, hardware trigger on rising, falling or both edges. - */ -typedef enum adc_exttrig_mode { - ADC_EXTTRIG_MODE_SOFTWARE = 0x0 << ADC_CFGR_EXTEN_SHIFT, /**< .. */ - ADC_EXTTRIG_MODE_HARDWARE_RISING = 0x1 << ADC_CFGR_EXTEN_SHIFT, /**< .. */ - ADC_EXTTRIG_MODE_HARDWARE_FALLING = 0x2 << ADC_CFGR_EXTEN_SHIFT, /**< .. */ - ADC_EXTTRIG_MODE_HARDWARE_BOTH = 0x3 << ADC_CFGR_EXTEN_SHIFT, /**< .. */ -} adc_exttrig_mode; - -/** - * @brief STM32F3 ADC resolution. - * - * These control the ADC resolution, which can be set to: - * 6, 8, 10 or 12 bit. - */ -typedef enum adc_resolution { - ADC_RESOLUTION_12_BIT = 0x0 << ADC_CFGR_RES_SHIFT, /**< .. */ - ADC_RESOLUTION_10_BIT = 0x1 << ADC_CFGR_RES_SHIFT, /**< .. */ - ADC_RESOLUTION_8_BIT = 0x2 << ADC_CFGR_RES_SHIFT, /**< .. */ - ADC_RESOLUTION_6_BIT = 0x3 << ADC_CFGR_RES_SHIFT, /**< .. */ -} adc_resolution; - -/** - * @brief STM32F3 sample times, in ADC clock cycles. - * - * These control the amount of time spent sampling the input voltage. - */ -typedef enum adc_smp_rate { - ADC_SMPR_1_5 = 0x0, /**< 1.5 ADC cycles */ - ADC_SMPR_2_5 = 0x1, /**< 2.5 ADC cycles */ - ADC_SMPR_4_5 = 0x2, /**< 4.5 ADC cycles */ - ADC_SMPR_7_5 = 0x3, /**< 7.5 ADC cycles */ - ADC_SMPR_19_5 = 0x4, /**< 19.5 ADC cycles */ - ADC_SMPR_61_5 = 0x5, /**< 61.5 ADC cycles */ - ADC_SMPR_181_5 = 0x6, /**< 181.5 ADC cycles */ - ADC_SMPR_601_5 = 0x7, /**< 601.5 ADC cycles */ -} adc_smp_rate; - -/* - * FIXME SHIFT - */ - -/** - * @brief STM32F3 ADC clock mode. - */ -typedef enum adc_clock_mode { - ADC_CLOCK_MODE_ASYNCHRONOUS = 0x0, /**< . */ - ADC_CLOCK_MODE_SYNCHRONOUS_DIV_1 = 0x1, /**< . */ - ADC_CLOCK_MODE_SYNCHRONOUS_DIV_2 = 0x2, /**< . */ - ADC_CLOCK_MODE_SYNCHRONOUS_DIV_4 = 0x3, /**< . */ -} adc_clock_mode; - -/** - * @brief STM32F3 ADC DMA mode. - */ -typedef enum adc_dma_mode { - ADC_MDMA_MODE_DISABLE = (0x0 << ADC_CCR_MDMA_SHIFT), /**< . */ - ADC_MDMA_MODE_ENABLE_12_10_BIT = (0x2 << ADC_CCR_MDMA_SHIFT), /**< . */ - ADC_MDMA_MODE_ENABLE_8_6_BIT = (0x3 << ADC_CCR_MDMA_SHIFT), /**< . */ -} adc_dma_mode; - -/** - * @brief STM32F3 ADC mode. - */ -typedef enum adc_mode { - ADC_MODE_INDEPENDENT = 0x0, /**< . */ - ADC_MODE_DUAL_REGULAR_INJECTED = 0x1, /**< . */ - ADC_MODE_DUAL_REGULAR_ALTERNATE_TRIGGER = 0x2, /**< . */ - ADC_MODE_DUAL_INJECTED_ONLY = 0x5, /**< . */ - ADC_MODE_DUAL_REGULAR_ONLY = 0x6, /**< . */ - ADC_MODE_DUAL_INTERLEAVED_ONLY = 0x7, /**< . */ - ADC_MODE_DUAL_ALTERNATE_TRIGGER_ONLY = 0x9, /**< . */ -} adc_mode; - -/** - * @brief STM32F3 ADC prescalers, as divisors of PCLK2. - */ -typedef enum adc_prescaler { - /** ADC clock disabled, AHB clock enabled */ - ADC_PRE_AHBCLK_DIV_1 = ADC_CLOCK_MODE_SYNCHRONOUS_DIV_1, - ADC_PRE_AHBCLK_DIV_2 = ADC_CLOCK_MODE_SYNCHRONOUS_DIV_2, - ADC_PRE_AHBCLK_DIV_4 = ADC_CLOCK_MODE_SYNCHRONOUS_DIV_4, - - /** ADC clock enabled, AHB clock disabled */ - ADC_PRE_PCLK_DIV_1 = RCC_ADCPRE_PCLK_DIV_1, /** PCLK divided by 1 */ - ADC_PRE_PCLK_DIV_2 = RCC_ADCPRE_PCLK_DIV_2, /** PCLK divided by 2 */ - ADC_PRE_PCLK_DIV_4 = RCC_ADCPRE_PCLK_DIV_4, /** PCLK divided by 4 */ - ADC_PRE_PCLK_DIV_6 = RCC_ADCPRE_PCLK_DIV_6, /** PCLK divided by 6 */ - ADC_PRE_PCLK_DIV_8 = RCC_ADCPRE_PCLK_DIV_8, /** PCLK divided by 8 */ - ADC_PRE_PCLK_DIV_10 = RCC_ADCPRE_PCLK_DIV_10, /** PCLK divided by 10 */ - ADC_PRE_PCLK_DIV_12 = RCC_ADCPRE_PCLK_DIV_12, /** PCLK divided by 12 */ - ADC_PRE_PCLK_DIV_16 = RCC_ADCPRE_PCLK_DIV_16, /** PCLK divided by 16 */ - ADC_PRE_PCLK_DIV_32 = RCC_ADCPRE_PCLK_DIV_32, /** PCLK divided by 32 */ - ADC_PRE_PCLK_DIV_64 = RCC_ADCPRE_PCLK_DIV_64, /** PCLK divided by 64 */ - ADC_PRE_PCLK_DIV_128 = RCC_ADCPRE_PCLK_DIV_128, /** PCLK divided by 128 */ - ADC_PRE_PCLK_DIV_256 = RCC_ADCPRE_PCLK_DIV_256, /** PCLK divided by 256 */ -} adc_prescaler; - -/* - * Routines - */ - -/** - * @brief Calibrate an ADC peripheral - * - * Availability: STM32F1, STM32F3. - * - * @param dev adc device - */ -void adc_calibrate(const adc_dev *dev); - -/** - * @brief Set external trigger conversion mode event for regular channels - * - * Availability: STM32F1, STM32F3. - * - * @param dev ADC device - * @param mode external trigger disabled, on rising edge, on falling edge or on both - */ -void adc_set_exttrig(const adc_dev *dev, adc_exttrig_mode mode); - -/** - * @brief Set ADC resolution of an ADC peripheral - * - * Availability: STM32F3. - * - * @param dev adc device - * @param resolution ADC resolution (6, 8, 10 or 12 bit) - */ -void adc_set_resolution(const adc_dev *dev, adc_resolution res); - -/** - * @brief Enable the voltage regulatr of an ADC peripheral - * - * Availability: STM32F3. - * - * @param dev adc device - */ -void adc_regulator_enable(const adc_dev *dev); - -/** - * @brief Disable the voltage regulatr of an ADC peripheral - * - * Availability: STM32F3. - * - * @param dev adc device - */ -void adc_regulator_disable(const adc_dev *dev); - -#endif diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/bkp.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/bkp.h deleted file mode 100644 index 21ab1c1..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/bkp.h +++ /dev/null @@ -1,62 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 LeafLabs, LLC. - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/stm32f3/include/series/bkp.h - * @author F3-port by Hanspeter Portner - * @brief STM32F3 backup register support. - */ - -#ifndef _LIBMAPLE_STM32F3_BKP_H_ -#define _LIBMAPLE_STM32F3_BKP_H_ - -#define BKP_NR_DATA_REGS 16 - -/** Backup peripheral register map type. */ -typedef struct bkp_reg_map { - __IO uint32 DR0; ///< Data register 0 - __IO uint32 DR1; ///< Data register 1 - __IO uint32 DR2; ///< Data register 2 - __IO uint32 DR3; ///< Data register 3 - __IO uint32 DR4; ///< Data register 4 - __IO uint32 DR5; ///< Data register 5 - __IO uint32 DR6; ///< Data register 6 - __IO uint32 DR7; ///< Data register 7 - __IO uint32 DR8; ///< Data register 8 - __IO uint32 DR9; ///< Data register 9 - __IO uint32 DR10; ///< Data register 10 - __IO uint32 DR11; ///< Data register 11 - __IO uint32 DR12; ///< Data register 12 - __IO uint32 DR13; ///< Data register 13 - __IO uint32 DR14; ///< Data register 14 - __IO uint32 DR15; ///< Data register 15 -} bkp_reg_map; - -/** Backup peripheral register map base pointer. */ -#define BKP_BASE ((struct bkp_reg_map*)0x40002850) //is part of RTC memory map - -#endif diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/comp.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/comp.h deleted file mode 100644 index 161f439..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/comp.h +++ /dev/null @@ -1,119 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/stm32f3/include/series/comp.h - * @author F3-port by Hanspeter Portner - * @brief STM32F3 Comparator support. - */ - -#ifndef _LIBMAPLE_STM32F3_COMP_H_ -#define _LIBMAPLE_STM32F3_COMP_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -#include - -/* - * Register map - */ - -/* - * COMP individual register map type. - */ -typedef struct comp_reg_map { - __IO uint32 CSR; /**< */ -} comp_reg_map; - -/** COMP device type. */ -typedef struct comp_dev { - comp_reg_map *regs; /**< Register map */ -} comp_dev; - -/* - * Devices - */ - -extern const struct comp_dev *COMP1; /* comparator 1 */ -extern const struct comp_dev *COMP2; /* comparator 2 */ -extern const struct comp_dev *COMP3; /* comparator 3 */ -extern const struct comp_dev *COMP4; /* comparator 4 */ -extern const struct comp_dev *COMP5; /* comparator 5 */ -extern const struct comp_dev *COMP6; /* comparator 6 */ -extern const struct comp_dev *COMP7; /* comparator 7 */ - -/* - * Register map base pointers - */ - -#define COMP1_BASE ((struct comp_reg_map*)0x4001001C) -#define COMP2_BASE ((struct comp_reg_map*)0x40010020) -#define COMP3_BASE ((struct comp_reg_map*)0x40010024) -#define COMP4_BASE ((struct comp_reg_map*)0x40010028) -#define COMP5_BASE ((struct comp_reg_map*)0x4001002C) -#define COMP6_BASE ((struct comp_reg_map*)0x40010030) -#define COMP7_BASE ((struct comp_reg_map*)0x40010034) - -/* - * Register bit definitions - */ - -/* Control and status register */ -#define COMP_CSR_LOCK_BIT 31 -#define COMP_CSR_OUT_BIT 30 -#define COMP_CSR_BLANKING_SHIFT 18 -#define COMP_CSR_HIST_SHIFT 16 -#define COMP_CSR_POL_BIT 15 -#define COMP_CSR_OUTSEL_SHIFT 10 -#define COMP_CSR_WINMODE_BIT 9 -#define COMP_CSR_INPSEL_BIT 7 -#define COMP_CSR_INMSEL_SHIFT 4 -#define COMP_CSR_MODE_SHIFT 2 -#define COMP_CSR_EN_BIT 0 - -#define COMP_CSR_LOCK (1U << COMP_CSR_LOCK_BIT) -#define COMP_CSR_OUT (1U << COMP_CSR_OUT_BIT) -#define COMP_CSR_BLANKING (0x7 << COMP_CSR_BLANKING_SHIFT) -#define COMP_CSR_HIST (0x3 << COMP_CSR_HIST_SHIFT) -#define COMP_CSR_POL (1U << COMP_CSR_POL_BIT) -#define COMP_CSR_OUTSEL (0xF << COMP_CSR_OUTSEL_SHIFT) -#define COMP_CSR_WINMODE (0xF << COMP_CSR_WINMODE_SHIFT) -#define COMP_CSR_INPSEL (1U << COMP_CSR_INPSEL_BIT) -#define COMP_CSR_INMSEL (0x7 << COMP_CSR_INMSEL_SHIFT) -#define COMP_CSR_MODE (0x3 << COMP_CSR_MODE_SHIFT) -#define COMP_CSR_EN (1U << COMP_CSR_EN_BIT) - -/* TODO - * actually implement me ;-) - */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/crc.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/crc.h deleted file mode 100644 index fa10aa4..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/crc.h +++ /dev/null @@ -1,94 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/stm32f3/include/series/crc.h - * @author F3-port by Hanspeter Portner - * @brief STM32F3 Cylic Redundancy Check (CRC) support. - */ - -#ifndef _LIBMAPLE_STM32F3_CRC_H_ -#define _LIBMAPLE_STM32F3_CRC_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -/* - * Register maps - */ - -/** CRC register map type */ -typedef struct crc_reg_map { - __IO uint32 DR; /**< Data register */ - __IO uint32 IDR; /**< Independent data register */ - __IO uint32 CR; /**< Control register */ - uint32 reserved; - __IO uint32 INIT; /**< Initial data register */ - __IO uint32 POL; /**< Polynomial register */ -} crc_reg_map; - -/* - * Register map base pointers - */ - -/** CRC register map base pointer */ -#define CRC_BASE ((struct crc_reg_map*)0x40013800) //TODO - -/* - * Register bit definitions - */ - -/* Data register */ -#define CRC_DR_DATA 0xFFFFFFFF - -/* Independent data register */ -#define CRC_IDR_DATA 0xFF - -/* Control register */ -#define CRC_CR_REV_OUT_BIT 7 -#define CRC_CR_REV_IN_SHIFT 5 -#define CRC_CR_POLYSIZE_SHIFT 3 -#define CRC_CR_RESET_BIT 0 - -#define CRC_CR_REV_OUT (1U << CRC_CR_REV_OUT_BIT) -#define CRC_CR_REV_IN (0x3 << CRC_CR_REV_IN_SHIFT) -#define CRC_CR_POLYSIZE (0x3 << CRC_CR_POLYSIZE_SHIFT) -#define CRC_CR_RESET (1U << CRC_CR_RESET_BIT) - -/* Initial data register */ -#define CRC_INIT_DATA 0xFFFFFFFF - -/* Polynomial register */ -#define CRC_POL_DATA 0xFFFFFFFF - -/* TODO add some routines */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/dac.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/dac.h deleted file mode 100644 index 890e34c..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/dac.h +++ /dev/null @@ -1,74 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/stm32f3/include/series/dac.h - * @brief STM32F3 DAC support - */ - -#ifndef _LIBMAPLE_STM32F3_DAC_H_ -#define _LIBMAPLE_STM32F3_DAC_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -#include - -/** STM32F3 DAC register map type. */ -typedef struct dac_reg_map { - __IO uint32 CR; /**< Control register */ - __IO uint32 SWTRIGR; /**< Software trigger register */ - __IO uint32 DHR12R1; /**< Channel 1 12-bit right-aligned data - holding register */ - __IO uint32 DHR12L1; /**< Channel 1 12-bit left-aligned data - holding register */ - __IO uint32 DHR8R1; /**< Channel 1 8-bit left-aligned data - holding register */ - __IO uint32 DHR12R2; /**< Channel 2 12-bit right-aligned data - holding register */ - __IO uint32 DHR12L2; /**< Channel 2 12-bit left-aligned data - holding register */ - __IO uint32 DHR8R2; /**< Channel 2 8-bit left-aligned data - holding register */ - __IO uint32 DHR12RD; /**< Dual DAC 12-bit right-aligned data - holding register */ - __IO uint32 DHR12LD; /**< Dual DAC 12-bit left-aligned data - holding register */ - __IO uint32 DHR8RD; /**< Dual DAC 8-bit right-aligned data holding - register */ - __IO uint32 DOR1; /**< Channel 1 data output register */ - __IO uint32 DOR2; /**< Channel 2 data output register */ -} dac_reg_map; - -//#define DAC1_BASE ((struct dac_reg_map*)0x40007400) -//#define DAC2_BASE ((struct dac_reg_map*)0x40009800) //TODO STM32F37/38xx - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/dma.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/dma.h deleted file mode 100644 index 1c73748..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/dma.h +++ /dev/null @@ -1,557 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Michael Hope. - * Copyright (c) 2012 LeafLabs, LLC - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/stm32f3/include/series/dma.h - * @author Marti Bolivar , - * Original implementation by Michael Hope, - * F3-port by Hanspeter Portner - * @brief STM32F3 DMA series header. - */ - -#ifndef _LIBMAPLE_STM32F3_DMA_H_ -#define _LIBMAPLE_STM32F3_DMA_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -#include -#include - -/* - * Register maps and base pointers - */ - -/** - * @brief STM32F3 DMA register map type. - * - * Note that DMA controller 2 (register map base pointer DMA2_BASE) - * only supports channels 1--5. - */ -typedef struct dma_reg_map { - __IO uint32 ISR; /**< Interrupt status register */ - __IO uint32 IFCR; /**< Interrupt flag clear register */ - __IO uint32 CCR1; /**< Channel 1 configuration register */ - __IO uint32 CNDTR1; /**< Channel 1 number of data register */ - __IO uint32 CPAR1; /**< Channel 1 peripheral address register */ - __IO uint32 CMAR1; /**< Channel 1 memory address register */ - const uint32 RESERVED1; /**< Reserved. */ - __IO uint32 CCR2; /**< Channel 2 configuration register */ - __IO uint32 CNDTR2; /**< Channel 2 number of data register */ - __IO uint32 CPAR2; /**< Channel 2 peripheral address register */ - __IO uint32 CMAR2; /**< Channel 2 memory address register */ - const uint32 RESERVED2; /**< Reserved. */ - __IO uint32 CCR3; /**< Channel 3 configuration register */ - __IO uint32 CNDTR3; /**< Channel 3 number of data register */ - __IO uint32 CPAR3; /**< Channel 3 peripheral address register */ - __IO uint32 CMAR3; /**< Channel 3 memory address register */ - const uint32 RESERVED3; /**< Reserved. */ - __IO uint32 CCR4; /**< Channel 4 configuration register */ - __IO uint32 CNDTR4; /**< Channel 4 number of data register */ - __IO uint32 CPAR4; /**< Channel 4 peripheral address register */ - __IO uint32 CMAR4; /**< Channel 4 memory address register */ - const uint32 RESERVED4; /**< Reserved. */ - __IO uint32 CCR5; /**< Channel 5 configuration register */ - __IO uint32 CNDTR5; /**< Channel 5 number of data register */ - __IO uint32 CPAR5; /**< Channel 5 peripheral address register */ - __IO uint32 CMAR5; /**< Channel 5 memory address register */ - const uint32 RESERVED5; /**< Reserved. */ - __IO uint32 CCR6; /**< Channel 6 configuration register */ - __IO uint32 CNDTR6; /**< Channel 6 number of data register */ - __IO uint32 CPAR6; /**< Channel 6 peripheral address register */ - __IO uint32 CMAR6; /**< Channel 6 memory address register */ - const uint32 RESERVED6; /**< Reserved. */ - __IO uint32 CCR7; /**< Channel 7 configuration register */ - __IO uint32 CNDTR7; /**< Channel 7 number of data register */ - __IO uint32 CPAR7; /**< Channel 7 peripheral address register */ - __IO uint32 CMAR7; /**< Channel 7 memory address register */ - const uint32 RESERVED7; /**< Reserved. */ -} dma_reg_map; - -/** DMA controller 1 register map base pointer */ -#define DMA1_BASE ((struct dma_reg_map*)0x40020000) -/** DMA controller 2 register map base pointer */ -#define DMA2_BASE ((struct dma_reg_map*)0x40020400) - -/** - * @brief STM32F3 DMA channel (i.e. tube) register map type. - * Provides access to an individual channel's registers. - * @see dma_tube_regs() - */ -typedef struct dma_tube_reg_map { - __IO uint32 CCR; /**< Channel configuration register */ - __IO uint32 CNDTR; /**< Channel number of data register */ - __IO uint32 CPAR; /**< Channel peripheral address register */ - __IO uint32 CMAR; /**< Channel memory address register */ -} dma_tube_reg_map; - -/** DMA1 channel 1 register map base pointer */ -#define DMA1CH1_BASE ((struct dma_tube_reg_map*)0x40020008) -/** DMA1 channel 2 register map base pointer */ -#define DMA1CH2_BASE ((struct dma_tube_reg_map*)0x4002001C) -/** DMA1 channel 3 register map base pointer */ -#define DMA1CH3_BASE ((struct dma_tube_reg_map*)0x40020030) -/** DMA1 channel 4 register map base pointer */ -#define DMA1CH4_BASE ((struct dma_tube_reg_map*)0x40020044) -/** DMA1 channel 5 register map base pointer */ -#define DMA1CH5_BASE ((struct dma_tube_reg_map*)0x40020058) -/** DMA1 channel 6 register map base pointer */ -#define DMA1CH6_BASE ((struct dma_tube_reg_map*)0x4002006C) -/** DMA1 channel 7 register map base pointer */ -#define DMA1CH7_BASE ((struct dma_tube_reg_map*)0x40020080) - -/** DMA2 channel 1 register map base pointer */ -#define DMA2CH1_BASE ((struct dma_tube_reg_map*)0x40020408) -/** DMA2 channel 2 register map base pointer */ -#define DMA2CH2_BASE ((struct dma_tube_reg_map*)0x4002041C) -/** DMA2 channel 3 register map base pointer */ -#define DMA2CH3_BASE ((struct dma_tube_reg_map*)0x40020430) -/** DMA2 channel 4 register map base pointer */ -#define DMA2CH4_BASE ((struct dma_tube_reg_map*)0x40020444) -/** DMA2 channel 5 register map base pointer */ -#define DMA2CH5_BASE ((struct dma_tube_reg_map*)0x40020458) - -/* - * Register bit definitions - */ - -/* Interrupt status register */ - -#define DMA_ISR_TEIF_BIT 3 -#define DMA_ISR_HTIF_BIT 2 -#define DMA_ISR_TCIF_BIT 1 -#define DMA_ISR_GIF_BIT 0 - -#define DMA_ISR_TEIF (1 << DMA_ISR_TEIF_BIT) -#define DMA_ISR_HTIF (1 << DMA_ISR_HTIF_BIT) -#define DMA_ISR_TCIF (1 << DMA_ISR_TCIF_BIT) -#define DMA_ISR_GIF (1 << DMA_ISR_GIF_BIT) - -#define DMA_ISR_TEIF7_BIT 27 -#define DMA_ISR_HTIF7_BIT 26 -#define DMA_ISR_TCIF7_BIT 25 -#define DMA_ISR_GIF7_BIT 24 -#define DMA_ISR_TEIF6_BIT 23 -#define DMA_ISR_HTIF6_BIT 22 -#define DMA_ISR_TCIF6_BIT 21 -#define DMA_ISR_GIF6_BIT 20 -#define DMA_ISR_TEIF5_BIT 19 -#define DMA_ISR_HTIF5_BIT 18 -#define DMA_ISR_TCIF5_BIT 17 -#define DMA_ISR_GIF5_BIT 16 -#define DMA_ISR_TEIF4_BIT 15 -#define DMA_ISR_HTIF4_BIT 14 -#define DMA_ISR_TCIF4_BIT 13 -#define DMA_ISR_GIF4_BIT 12 -#define DMA_ISR_TEIF3_BIT 11 -#define DMA_ISR_HTIF3_BIT 10 -#define DMA_ISR_TCIF3_BIT 9 -#define DMA_ISR_GIF3_BIT 8 -#define DMA_ISR_TEIF2_BIT 7 -#define DMA_ISR_HTIF2_BIT 6 -#define DMA_ISR_TCIF2_BIT 5 -#define DMA_ISR_GIF2_BIT 4 -#define DMA_ISR_TEIF1_BIT 3 -#define DMA_ISR_HTIF1_BIT 2 -#define DMA_ISR_TCIF1_BIT 1 -#define DMA_ISR_GIF1_BIT 0 - -#define DMA_ISR_TEIF7 (1U << DMA_ISR_TEIF7_BIT) -#define DMA_ISR_HTIF7 (1U << DMA_ISR_HTIF7_BIT) -#define DMA_ISR_TCIF7 (1U << DMA_ISR_TCIF7_BIT) -#define DMA_ISR_GIF7 (1U << DMA_ISR_GIF7_BIT) -#define DMA_ISR_TEIF6 (1U << DMA_ISR_TEIF6_BIT) -#define DMA_ISR_HTIF6 (1U << DMA_ISR_HTIF6_BIT) -#define DMA_ISR_TCIF6 (1U << DMA_ISR_TCIF6_BIT) -#define DMA_ISR_GIF6 (1U << DMA_ISR_GIF6_BIT) -#define DMA_ISR_TEIF5 (1U << DMA_ISR_TEIF5_BIT) -#define DMA_ISR_HTIF5 (1U << DMA_ISR_HTIF5_BIT) -#define DMA_ISR_TCIF5 (1U << DMA_ISR_TCIF5_BIT) -#define DMA_ISR_GIF5 (1U << DMA_ISR_GIF5_BIT) -#define DMA_ISR_TEIF4 (1U << DMA_ISR_TEIF4_BIT) -#define DMA_ISR_HTIF4 (1U << DMA_ISR_HTIF4_BIT) -#define DMA_ISR_TCIF4 (1U << DMA_ISR_TCIF4_BIT) -#define DMA_ISR_GIF4 (1U << DMA_ISR_GIF4_BIT) -#define DMA_ISR_TEIF3 (1U << DMA_ISR_TEIF3_BIT) -#define DMA_ISR_HTIF3 (1U << DMA_ISR_HTIF3_BIT) -#define DMA_ISR_TCIF3 (1U << DMA_ISR_TCIF3_BIT) -#define DMA_ISR_GIF3 (1U << DMA_ISR_GIF3_BIT) -#define DMA_ISR_TEIF2 (1U << DMA_ISR_TEIF2_BIT) -#define DMA_ISR_HTIF2 (1U << DMA_ISR_HTIF2_BIT) -#define DMA_ISR_TCIF2 (1U << DMA_ISR_TCIF2_BIT) -#define DMA_ISR_GIF2 (1U << DMA_ISR_GIF2_BIT) -#define DMA_ISR_TEIF1 (1U << DMA_ISR_TEIF1_BIT) -#define DMA_ISR_HTIF1 (1U << DMA_ISR_HTIF1_BIT) -#define DMA_ISR_TCIF1 (1U << DMA_ISR_TCIF1_BIT) -#define DMA_ISR_GIF1 (1U << DMA_ISR_GIF1_BIT) - -/* Interrupt flag clear register */ - -#define DMA_IFCR_CTEIF7_BIT 27 -#define DMA_IFCR_CHTIF7_BIT 26 -#define DMA_IFCR_CTCIF7_BIT 25 -#define DMA_IFCR_CGIF7_BIT 24 -#define DMA_IFCR_CTEIF6_BIT 23 -#define DMA_IFCR_CHTIF6_BIT 22 -#define DMA_IFCR_CTCIF6_BIT 21 -#define DMA_IFCR_CGIF6_BIT 20 -#define DMA_IFCR_CTEIF5_BIT 19 -#define DMA_IFCR_CHTIF5_BIT 18 -#define DMA_IFCR_CTCIF5_BIT 17 -#define DMA_IFCR_CGIF5_BIT 16 -#define DMA_IFCR_CTEIF4_BIT 15 -#define DMA_IFCR_CHTIF4_BIT 14 -#define DMA_IFCR_CTCIF4_BIT 13 -#define DMA_IFCR_CGIF4_BIT 12 -#define DMA_IFCR_CTEIF3_BIT 11 -#define DMA_IFCR_CHTIF3_BIT 10 -#define DMA_IFCR_CTCIF3_BIT 9 -#define DMA_IFCR_CGIF3_BIT 8 -#define DMA_IFCR_CTEIF2_BIT 7 -#define DMA_IFCR_CHTIF2_BIT 6 -#define DMA_IFCR_CTCIF2_BIT 5 -#define DMA_IFCR_CGIF2_BIT 4 -#define DMA_IFCR_CTEIF1_BIT 3 -#define DMA_IFCR_CHTIF1_BIT 2 -#define DMA_IFCR_CTCIF1_BIT 1 -#define DMA_IFCR_CGIF1_BIT 0 - -#define DMA_IFCR_CTEIF7 (1U << DMA_IFCR_CTEIF7_BIT) -#define DMA_IFCR_CHTIF7 (1U << DMA_IFCR_CHTIF7_BIT) -#define DMA_IFCR_CTCIF7 (1U << DMA_IFCR_CTCIF7_BIT) -#define DMA_IFCR_CGIF7 (1U << DMA_IFCR_CGIF7_BIT) -#define DMA_IFCR_CTEIF6 (1U << DMA_IFCR_CTEIF6_BIT) -#define DMA_IFCR_CHTIF6 (1U << DMA_IFCR_CHTIF6_BIT) -#define DMA_IFCR_CTCIF6 (1U << DMA_IFCR_CTCIF6_BIT) -#define DMA_IFCR_CGIF6 (1U << DMA_IFCR_CGIF6_BIT) -#define DMA_IFCR_CTEIF5 (1U << DMA_IFCR_CTEIF5_BIT) -#define DMA_IFCR_CHTIF5 (1U << DMA_IFCR_CHTIF5_BIT) -#define DMA_IFCR_CTCIF5 (1U << DMA_IFCR_CTCIF5_BIT) -#define DMA_IFCR_CGIF5 (1U << DMA_IFCR_CGIF5_BIT) -#define DMA_IFCR_CTEIF4 (1U << DMA_IFCR_CTEIF4_BIT) -#define DMA_IFCR_CHTIF4 (1U << DMA_IFCR_CHTIF4_BIT) -#define DMA_IFCR_CTCIF4 (1U << DMA_IFCR_CTCIF4_BIT) -#define DMA_IFCR_CGIF4 (1U << DMA_IFCR_CGIF4_BIT) -#define DMA_IFCR_CTEIF3 (1U << DMA_IFCR_CTEIF3_BIT) -#define DMA_IFCR_CHTIF3 (1U << DMA_IFCR_CHTIF3_BIT) -#define DMA_IFCR_CTCIF3 (1U << DMA_IFCR_CTCIF3_BIT) -#define DMA_IFCR_CGIF3 (1U << DMA_IFCR_CGIF3_BIT) -#define DMA_IFCR_CTEIF2 (1U << DMA_IFCR_CTEIF2_BIT) -#define DMA_IFCR_CHTIF2 (1U << DMA_IFCR_CHTIF2_BIT) -#define DMA_IFCR_CTCIF2 (1U << DMA_IFCR_CTCIF2_BIT) -#define DMA_IFCR_CGIF2 (1U << DMA_IFCR_CGIF2_BIT) -#define DMA_IFCR_CTEIF1 (1U << DMA_IFCR_CTEIF1_BIT) -#define DMA_IFCR_CHTIF1 (1U << DMA_IFCR_CHTIF1_BIT) -#define DMA_IFCR_CTCIF1 (1U << DMA_IFCR_CTCIF1_BIT) -#define DMA_IFCR_CGIF1 (1U << DMA_IFCR_CGIF1_BIT) - -/* Channel configuration register */ - -#define DMA_CCR_MEM2MEM_BIT 14 -#define DMA_CCR_MINC_BIT 7 -#define DMA_CCR_PINC_BIT 6 -#define DMA_CCR_CIRC_BIT 5 -#define DMA_CCR_DIR_BIT 4 -#define DMA_CCR_TEIE_BIT 3 -#define DMA_CCR_HTIE_BIT 2 -#define DMA_CCR_TCIE_BIT 1 -#define DMA_CCR_EN_BIT 0 - -#define DMA_CCR_MEM2MEM (1U << DMA_CCR_MEM2MEM_BIT) -#define DMA_CCR_PL (0x3 << 12) -#define DMA_CCR_PL_LOW (0x0 << 12) -#define DMA_CCR_PL_MEDIUM (0x1 << 12) -#define DMA_CCR_PL_HIGH (0x2 << 12) -#define DMA_CCR_PL_VERY_HIGH (0x3 << 12) -#define DMA_CCR_MSIZE (0x3 << 10) -#define DMA_CCR_MSIZE_8BITS (0x0 << 10) -#define DMA_CCR_MSIZE_16BITS (0x1 << 10) -#define DMA_CCR_MSIZE_32BITS (0x2 << 10) -#define DMA_CCR_PSIZE (0x3 << 8) -#define DMA_CCR_PSIZE_8BITS (0x0 << 8) -#define DMA_CCR_PSIZE_16BITS (0x1 << 8) -#define DMA_CCR_PSIZE_32BITS (0x2 << 8) -#define DMA_CCR_MINC (1U << DMA_CCR_MINC_BIT) -#define DMA_CCR_PINC (1U << DMA_CCR_PINC_BIT) -#define DMA_CCR_CIRC (1U << DMA_CCR_CIRC_BIT) -#define DMA_CCR_DIR (1U << DMA_CCR_DIR_BIT) -#define DMA_CCR_DIR_FROM_PER (0U << DMA_CCR_DIR_BIT) -#define DMA_CCR_DIR_FROM_MEM (1U << DMA_CCR_DIR_BIT) -#define DMA_CCR_TEIE (1U << DMA_CCR_TEIE_BIT) -#define DMA_CCR_HTIE (1U << DMA_CCR_HTIE_BIT) -#define DMA_CCR_TCIE (1U << DMA_CCR_TCIE_BIT) -#define DMA_CCR_EN (1U << DMA_CCR_EN_BIT) - -/* - * Devices - */ - -extern dma_dev *DMA1; -extern dma_dev *DMA2; - -/* - * Other types needed by, or useful for, . - */ - -/** - * @brief STM32F3 dma_tube. - * On STM32F3, DMA tubes are just channels. - */ -#define dma_tube dma_channel - -/** - * @brief On STM32F3, dma_channel_reg_map is an alias for dma_tube_reg_map. - * This is for backwards compatibility. */ -#define dma_channel_reg_map dma_tube_reg_map - -/** - * @brief STM32F3 configuration flags for dma_tube_config - * @see struct dma_tube_config - */ -typedef enum dma_cfg_flags { - /** - * Source address increment mode - * - * If this flag is set, the source address is incremented (by the - * source size) after each DMA transfer. - */ - DMA_CFG_SRC_INC = 1U << 31, - - /** - * Destination address increment mode - * - * If this flag is set, the destination address is incremented (by - * the destination size) after each DMA transfer. - */ - DMA_CFG_DST_INC = 1U << 30, - - /** - * Circular mode - * - * This mode is not available for memory-to-memory transfers. - */ - DMA_CFG_CIRC = DMA_CCR_CIRC, - - /** Transfer complete interrupt enable */ - DMA_CFG_CMPLT_IE = DMA_CCR_TCIE, - /** Transfer half-complete interrupt enable */ - DMA_CFG_HALF_CMPLT_IE = DMA_CCR_HTIE, - /** Transfer error interrupt enable */ - DMA_CFG_ERR_IE = DMA_CCR_TEIE, -} dma_cfg_flags; - -/** - * @brief STM32F3 DMA request sources. - * - * IMPORTANT: - * - * 1. On STM32F3, each dma_request_src can only be used by a - * particular tube on a particular DMA controller. For example, - * DMA_REQ_SRC_ADC1 belongs to DMA1, tube 1. DMA2 cannot serve - * requests from ADC1, nor can DMA1 tube 2, etc. If you try to use a - * request source with the wrong DMA controller or tube on STM32F3, - * dma_tube_cfg() will fail. - * - * 2. In general, a DMA tube can only serve a single request source at - * a time, and on STM32F3, Terrible Super-Bad Things will happen if - * two request sources are active for a single tube. - * - * To make all this easier to sort out, these dma_request_src - * enumerators are grouped by DMA controller and tube. - * - * @see struct dma_tube_config - * @see dma_tube_cfg() - */ -typedef enum dma_request_src { - /* Each request source encodes the DMA controller and channel it - * belongs to, for error checking in dma_tube_cfg(). */ - - /* DMA1 request sources */ - - /**@{*/ - /** (DMA1, tube 1) */ - DMA_REQ_SRC_ADC1 = (RCC_DMA1 << 3) | 1, - DMA_REQ_SRC_TIM2_CH3 = (RCC_DMA1 << 3) | 1, - DMA_REQ_SRC_TIM4_CH1 = (RCC_DMA1 << 3) | 1, - DMA_REQ_SRC_TIM17_CH1 = (RCC_DMA1 << 3) | 1, - DMA_REQ_SRC_TIM17_UP = (RCC_DMA1 << 3) | 1, - /**@}*/ - - /**@{*/ - /** (DMA1, tube 2)*/ - DMA_REQ_SRC_SPI1_RX = (RCC_DMA1 << 3) | 2, - DMA_REQ_SRC_USART3_TX = (RCC_DMA1 << 3) | 2, - DMA_REQ_SRC_TIM1_CH1 = (RCC_DMA1 << 3) | 2, - DMA_REQ_SRC_TIM2_UP = (RCC_DMA1 << 3) | 2, - DMA_REQ_SRC_TIM3_CH3 = (RCC_DMA1 << 3) | 2, - /**@}*/ - - /**@{*/ - /** (DMA1, tube 3)*/ - DMA_REQ_SRC_SPI1_TX = (RCC_DMA1 << 3) | 3, - DMA_REQ_SRC_USART3_RX = (RCC_DMA1 << 3) | 3, - DMA_REQ_SRC_TIM1_CH2 = (RCC_DMA1 << 3) | 3, - DMA_REQ_SRC_TIM3_CH4 = (RCC_DMA1 << 3) | 3, - DMA_REQ_SRC_TIM3_UP = (RCC_DMA1 << 3) | 3, - /*DMA_REQ_SRC_TIM6_UP = (RCC_DMA1 << 3) | 3,*/ /* remap in SYSCFGR */ - /*DMA_REQ_SRC_DAC_CH1 = (RCC_DMA1 << 3) | 3,*/ /* remap in SYSCFGR */ - DMA_REQ_SRC_TIM16_CH1 = (RCC_DMA1 << 3) | 3, - DMA_REQ_SRC_TIM16_UP = (RCC_DMA1 << 3) | 3, - /**@}*/ - - /**@{*/ - /** (DMA1, tube 4)*/ - DMA_REQ_SRC_SPI2_RX = (RCC_DMA1 << 3) | 4, - DMA_REQ_SRC_USART1_TX = (RCC_DMA1 << 3) | 4, - DMA_REQ_SRC_I2C2_TX = (RCC_DMA1 << 3) | 4, - DMA_REQ_SRC_TIM1_CH4 = (RCC_DMA1 << 3) | 4, - DMA_REQ_SRC_TIM1_TRIG = (RCC_DMA1 << 3) | 4, - DMA_REQ_SRC_TIM1_COM = (RCC_DMA1 << 3) | 4, - DMA_REQ_SRC_TIM4_CH2 = (RCC_DMA1 << 3) | 4, - /*DMA_REQ_SRC_TIM7_UP = (RCC_DMA1 << 3) | 4,*/ /* remap in SYSCFGR */ - /*DMA_REQ_SRC_DAC_CH2 = (RCC_DMA1 << 3) | 4,*/ /* remap in SYSCFGR */ - /**@}*/ - - /**@{*/ - /** (DMA1, tube 5)*/ - DMA_REQ_SRC_SPI2_TX = (RCC_DMA1 << 3) | 5, - DMA_REQ_SRC_USART1_RX = (RCC_DMA1 << 3) | 5, - DMA_REQ_SRC_I2C2_RX = (RCC_DMA1 << 3) | 5, - DMA_REQ_SRC_TIM1_UP = (RCC_DMA1 << 3) | 5, - DMA_REQ_SRC_TIM2_CH1 = (RCC_DMA1 << 3) | 5, - DMA_REQ_SRC_TIM4_CH3 = (RCC_DMA1 << 3) | 5, - DMA_REQ_SRC_TIM15_CH1 = (RCC_DMA1 << 3) | 5, - DMA_REQ_SRC_TIM15_UP = (RCC_DMA1 << 3) | 5, - DMA_REQ_SRC_TIM15_TRIG = (RCC_DMA1 << 3) | 5, - DMA_REQ_SRC_TIM15_COM = (RCC_DMA1 << 3) | 5, - /**@}*/ - - /**@{*/ - /** (DMA1, tube 6)*/ - DMA_REQ_SRC_USART2_RX = (RCC_DMA1 << 3) | 6, - DMA_REQ_SRC_I2C1_TX = (RCC_DMA1 << 3) | 6, - DMA_REQ_SRC_TIM1_CH3 = (RCC_DMA1 << 3) | 6, - DMA_REQ_SRC_TIM3_CH1 = (RCC_DMA1 << 3) | 6, - DMA_REQ_SRC_TIM3_TRIG = (RCC_DMA1 << 3) | 6, - /*DMA_REQ_SRC_TIM16_CH1 = (RCC_DMA1 << 3) | 6,*/ /* remap in SYSCFGR */ - /*DMA_REQ_SRC_TIM16_UP = (RCC_DMA1 << 3) | 6,*/ /* remap in SYSCFGR */ - /**@}*/ - - /**@{*/ - /* Tube 7 */ - DMA_REQ_SRC_USART2_TX = (RCC_DMA1 << 3) | 7, - DMA_REQ_SRC_I2C1_RX = (RCC_DMA1 << 3) | 7, - DMA_REQ_SRC_TIM2_CH2 = (RCC_DMA1 << 3) | 7, - DMA_REQ_SRC_TIM2_CH4 = (RCC_DMA1 << 3) | 7, - DMA_REQ_SRC_TIM4_UP = (RCC_DMA1 << 3) | 7, - /**@}*/ - - /* DMA2 request sources */ - - /**@{*/ - /** (DMA2, tube 1)*/ - DMA_REQ_SRC_ADC2 = (RCC_DMA2 << 3) | 1, - DMA_REQ_SRC_SPI3_RX = (RCC_DMA2 << 3) | 1, - DMA_REQ_SRC_TIM8_CH3 = (RCC_DMA2 << 3) | 1, - DMA_REQ_SRC_TIM8_UP = (RCC_DMA2 << 3) | 1, - /**@}*/ - - /**@{*/ - /** (DMA2, tube 2)*/ - DMA_REQ_SRC_ADC4 = (RCC_DMA2 << 3) | 2, - DMA_REQ_SRC_SPI3_TX = (RCC_DMA2 << 3) | 2, - DMA_REQ_SRC_TIM8_CH4 = (RCC_DMA2 << 3) | 2, - DMA_REQ_SRC_TIM8_TRIG = (RCC_DMA2 << 3) | 2, - DMA_REQ_SRC_TIM8_COM = (RCC_DMA2 << 3) | 2, - /**@}*/ - - /**@{*/ - /** (DMA2, tube 3)*/ - /* DMA_REQ_SRC_ADC2 = (RCC_DMA2 << 3) | 3,*/ /* remap in SYSCFGR */ - DMA_REQ_SRC_UART4_RX = (RCC_DMA2 << 3) | 3, - DMA_REQ_SRC_TIM6_UP = (RCC_DMA2 << 3) | 3, - DMA_REQ_SRC_DAC1_CH1 = (RCC_DMA2 << 3) | 3, - DMA_REQ_SRC_TIM8_CH1 = (RCC_DMA2 << 3) | 3, - /**@}*/ - - /**@{*/ - /** (DMA2, tube 4)*/ - /*DMA_REQ_SRC_ADC4 = (RCC_DMA2 << 3) | 4,*/ /* remap in SYSCFGR */ - DMA_REQ_SRC_TIM7_UP = (RCC_DMA2 << 3) | 4, - DMA_REQ_SRC_DAC1_CH2 = (RCC_DMA2 << 3) | 4, - /**@}*/ - - /**@{*/ - /** (DMA2, tube 5)*/ - DMA_REQ_SRC_ADC3 = (RCC_DMA2 << 3) | 5, - DMA_REQ_SRC_UART4_TX = (RCC_DMA2 << 3) | 5, - DMA_REQ_SRC_TIM8_CH2 = (RCC_DMA2 << 3) | 5, - /**@}*/ -} dma_request_src; - -/* - * Convenience routines. - */ - -/** - * @brief On STM32F3, dma_is_channel_enabled() is an alias for - * dma_is_enabled(). - * This is for backwards compatibility. - */ -#define dma_is_channel_enabled dma_is_enabled - -#define DMA_CHANNEL_NREGS 5 /* accounts for reserved word */ -static inline dma_tube_reg_map* dma_tube_regs(dma_dev *dev, dma_tube tube) { - __IO uint32 *ccr1 = &dev->regs->CCR1; - return (dma_channel_reg_map*)(ccr1 + DMA_CHANNEL_NREGS * (tube - 1)); -} - -/** - * @brief On STM32F3, dma_channel_regs() is an alias for dma_tube_regs(). - * This is for backwards compatibility. */ -#define dma_channel_regs(dev, ch) dma_tube_regs(dev, ch) - -static inline uint8 dma_is_enabled(dma_dev *dev, dma_tube tube) { - return (uint8)(dma_tube_regs(dev, tube)->CCR & DMA_CCR_EN); -} - -static inline uint8 dma_get_isr_bits(dma_dev *dev, dma_tube tube) { - uint8 shift = (tube - 1) * 4; - return (dev->regs->ISR >> shift) & 0xF; -} - -static inline void dma_clear_isr_bits(dma_dev *dev, dma_tube tube) { - dev->regs->IFCR = (1U << (4 * (tube - 1))); -} - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/exti.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/exti.h deleted file mode 100644 index 05ed1e6..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/exti.h +++ /dev/null @@ -1,49 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2012 LeafLabs, LLC. - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/stm32f3/include/series/exti.h - * @author F3-port by Hanspeter Portner - * @brief STM32F3 external interrupts - */ - -#ifndef _LIBMAPLE_STM32F3_EXTI_H_ -#define _LIBMAPLE_STM32F3_EXTI_H_ - -#ifdef __cpluspus -extern "C" { -#endif - -//FIXME F3 has up to 36 EXTIs, expose and handle internal EXTIs 16-35 -struct exti_reg_map; -#define EXTI_BASE ((struct exti_reg_map*)0x40010400) - -#ifdef __cpluspus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/flash.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/flash.h deleted file mode 100644 index 8bc6114..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/flash.h +++ /dev/null @@ -1,164 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/stm32f3/include/series/flash.h - * @author F3-port by Hanspeter Portner - * @brief STM32F3 Flash header. - * - * Provides register map, base pointer, and register bit definitions - * for the Flash controller on the STM32F3 line, along with - * series-specific configuration values. - */ - -#ifndef _LIBMAPLE_STM32F3_FLASH_H_ -#define _LIBMAPLE_STM32F3_FLASH_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -#include - -/* - * Register map - */ - -/** @brief STM32F3 Flash register map type */ -typedef struct flash_reg_map { - __IO uint32 ACR; /**< Access control register */ - __IO uint32 KEYR; /**< Key register */ - __IO uint32 OPTKEYR; /**< OPTKEY register */ - __IO uint32 SR; /**< Status register */ - __IO uint32 CR; /**< Control register */ - __IO uint32 AR; /**< Address register */ - __IO uint32 OBR; /**< Option byte register */ - __IO uint32 WRPR; /**< Write protection register */ -} flash_reg_map; - -#define FLASH_BASE ((struct flash_reg_map*)0x40022000) - -/* - * Register bit definitions - */ - -/* Access control register */ - -#define FLASH_ACR_PRFTBS_BIT 5 -#define FLASH_ACR_PRFTBE_BIT 4 -#define FLASH_ACR_HLFCYA_BIT 3 - -#define FLASH_ACR_PRFTBS (1U << FLASH_ACR_PRFTBS_BIT) -#define FLASH_ACR_PRFTBE (1U << FLASH_ACR_PRFTBE_BIT) -#define FLASH_ACR_HLFCYA (1U << FLASH_ACR_HLFCYA_BIT) -#define FLASH_ACR_LATENCY 0x7 - -/* Status register */ - -#define FLASH_SR_EOP_BIT 5 -#define FLASH_SR_WRPRTERR_BIT 4 -#define FLASH_SR_PGERR_BIT 2 -#define FLASH_SR_BSY_BIT 0 - -#define FLASH_SR_EOP (1U << FLASH_SR_EOP_BIT) -#define FLASH_SR_WRPRTERR (1U << FLASH_SR_WRPRTERR_BIT) -#define FLASH_SR_PGERR (1U << FLASH_SR_PGERR_BIT) -#define FLASH_SR_BSY (1U << FLASH_SR_BSY_BIT) - -/* Control register */ - -#define FLASH_CR_OBL_LAUNCH_BIT 13 -#define FLASH_CR_EOPIE_BIT 12 -#define FLASH_CR_ERRIE_BIT 10 -#define FLASH_CR_OPTWRE_BIT 9 -#define FLASH_CR_LOCK_BIT 7 -#define FLASH_CR_STRT_BIT 6 -#define FLASH_CR_OPTER_BIT 5 -#define FLASH_CR_OPTPG_BIT 4 -#define FLASH_CR_MER_BIT 2 -#define FLASH_CR_PER_BIT 1 -#define FLASH_CR_PG_BIT 0 - -#define FLASH_CR_OBL_LAUNCH (1U << FLASH_CR_OBL_LAUNCH_BIT) -#define FLASH_CR_EOPIE (1U << FLASH_CR_EOPIE_BIT) -#define FLASH_CR_ERRIE (1U << FLASH_CR_ERRIE_BIT) -#define FLASH_CR_OPTWRE (1U << FLASH_CR_OPTWRE_BIT) -#define FLASH_CR_LOCK (1U << FLASH_CR_LOCK_BIT) -#define FLASH_CR_STRT (1U << FLASH_CR_STRT_BIT) -#define FLASH_CR_OPTER (1U << FLASH_CR_OPTER_BIT) -#define FLASH_CR_OPTPG (1U << FLASH_CR_OPTPG_BIT) -#define FLASH_CR_MER (1U << FLASH_CR_MER_BIT) -#define FLASH_CR_PER (1U << FLASH_CR_PER_BIT) -#define FLASH_CR_PG (1U << FLASH_CR_PG_BIT) - -/* Option byte register */ - -#define FLASH_OBR_DATA1_SHIFT 24 -#define FLASH_OBR_DATA0_SHIFT 16 -#define FLASH_OBR_BYTE_SHIFT 8 -#define FLASH_OBR_SRAM_PE_BIT 14 -#define FLASH_OBR_VDDA_MONITOR_BIT 13 -#define FLASH_OBR_nBOOT1_BIT 12 -#define FLASH_OBR_nRST_STDBY_BIT 10 -#define FLASH_OBR_nRST_STOP_BIT 9 -#define FLASH_OBR_WDG_SW_BIT 8 -#define FLASH_OBR_RDPRT_SHIFT 1 -#define FLASH_OBR_OPTERR_BIT 0 - -#define FLASH_OBR_DATA1 (0xFF << FLASH_OBR_DATA1_SHIFT) -#define FLASH_OBR_DATA0 (0xFF << FLASH_OBR_DATA0_SHIFT) -#define FLASH_OBR_BYTE (0xFF << FLASH_OBR_BYTE_SHIFT) -#define FLASH_OBR_SRAM_PE_STDBY (1U << FLASH_OBR_SRAM_PE_STDBY_BIT) -#define FLASH_OBR_VDDA_MONITOR_STDBY (1U << FLASH_OBR_VDDA_MONITOR_STDBY_BIT) -#define FLASH_OBR_nBOOT1_STDBY (1U << FLASH_OBR_nBOOT1_STDBY_BIT) -#define FLASH_OBR_nRST_STDBY (1U << FLASH_OBR_nRST_STDBY_BIT) -#define FLASH_OBR_nRST_STOP (1U << FLASH_OBR_nRST_STOP_BIT) -#define FLASH_OBR_WDG_SW (1U << FLASH_OBR_WDG_SW_BIT) -#define FLASH_OBR_RDPRT (0x3 << FLASH_OBR_RDPRT_SHIFT) -#define FLASH_OBR_OPTERR (1U << FLASH_OBR_OPTERR_BIT) - -/* - * Series-specific configuration values. - */ - -#define FLASH_SAFE_WAIT_STATES FLASH_WAIT_STATE_2 - -/* Flash memory features available via ACR */ -enum { - FLASH_PREFETCH = 0x10, - FLASH_HALF_CYCLE = 0x8, - FLASH_ICACHE = 0x0, /* Not available on STM32F3 */ - FLASH_DCACHE = 0x0, /* Not available on STM32F3 */ -}; - -/* TODO add routines for option byte handling, e.g. nBoot1 */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/fpu.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/fpu.h deleted file mode 100644 index ee5d5c1..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/fpu.h +++ /dev/null @@ -1,65 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/stm32f3/include/series/fpu.h - * @author F3-port by Hanspeter Portner - * @brief STM32F3 Floating Point Unit support. - */ - -#ifndef _LIBMAPLE_STM32F3_FPU_H_ -#define _LIBMAPLE_STM32F3_FPU_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -#include -#include - -/* - * FPU register maps and devices - */ - -/** FPU register map type */ -typedef struct fpu_reg_map { - __IO uint32 CPACR; /**< coprocessor access control register */ - __IO uint32 FPCCR; /**< floating-point context control register */ - __IO uint32 FPCAR; /**< floating-point context address register */ - __IO uint32 FPDSCR; /**< floating-point default status control register */ -} fpu_reg_map; - -#define FPU_BASE ((struct fpu_reg_map*)(SCB_BASE + 0x88)) - -/* TODO - * give registry bitfields here - */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/gpio.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/gpio.h deleted file mode 100644 index 268c9c2..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/gpio.h +++ /dev/null @@ -1,255 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2011, 2012 LeafLabs, LLC. - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -*****************************************************************************/ - -/** - * @file libmaple/stm32f3/include/series/gpio.h - * @author F3-port by Hanspeter Portner - * @brief STM32F3 GPIO support. - */ - -#ifndef _LIBMAPLE_STM32F3_GPIO_H_ -#define _LIBMAPLE_STM32F3_GPIO_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -#include - -/* - * GPIO register maps and devices - */ - -/** GPIO register map type */ -typedef struct gpio_reg_map { - __IO uint32 MODER; /**< Mode register */ - __IO uint32 OTYPER; /**< Output type register */ - __IO uint32 OSPEEDR; /**< Output speed register */ - __IO uint32 PUPDR; /**< Pull-up/pull-down register */ - __IO uint32 IDR; /**< Input data register */ - __IO uint32 ODR; /**< Output data register */ - __IO uint32 BSRR; /**< Bit set/reset register */ - __IO uint32 LCKR; /**< Configuration lock register */ - __IO uint32 AFRL; /**< Alternate function low register */ - __IO uint32 AFRH; /**< Alternate function high register */ - __IO uint32 BRR; /**< Port bit reset register */ -} gpio_reg_map; - -/** GPIO port A register map base pointer */ -#define GPIOA_BASE ((struct gpio_reg_map*)0x48000000) -/** GPIO port B register map base pointer */ -#define GPIOB_BASE ((struct gpio_reg_map*)0x48000400) -/** GPIO port C register map base pointer */ -#define GPIOC_BASE ((struct gpio_reg_map*)0x48000800) -/** GPIO port D register map base pointer */ -#define GPIOD_BASE ((struct gpio_reg_map*)0x48000C00) -/** GPIO port E register map base pointer */ -#define GPIOE_BASE ((struct gpio_reg_map*)0x48001000) -/** GPIO port F register map base pointer */ -#define GPIOF_BASE ((struct gpio_reg_map*)0x48001400) - -struct gpio_dev; -extern struct gpio_dev* const GPIOA; -extern struct gpio_dev gpioa; -extern struct gpio_dev* const GPIOB; -extern struct gpio_dev gpiob; -extern struct gpio_dev* const GPIOC; -extern struct gpio_dev gpioc; -extern struct gpio_dev* const GPIOD; -extern struct gpio_dev gpiod; -extern struct gpio_dev* const GPIOE; -extern struct gpio_dev gpioe; -extern struct gpio_dev* const GPIOF; -extern struct gpio_dev gpiof; - -/* - * Register bit definitions - * - * Currently, we only provide masks to be used for shifting for some - * registers, rather than repeating the same values 16 times. - */ - -/* Mode register */ - -#define GPIO_MODER_INPUT 0x0 -#define GPIO_MODER_OUTPUT 0x1 -#define GPIO_MODER_AF 0x2 -#define GPIO_MODER_ANALOG 0x3 - -/* Output type register */ - -#define GPIO_OTYPER_PP 0x0 -#define GPIO_OTYPER_OD 0x1 - -/* Output speed register */ - -#define GPIO_OSPEEDR_LOW 0x0 -#define GPIO_OSPEEDR_MED 0x1 -#define GPIO_OSPEEDR_FAST 0x2 -#define GPIO_OSPEEDR_HIGH 0x3 - -/* Pull-up/pull-down register */ - -#define GPIO_PUPDR_NOPUPD 0x0 -#define GPIO_PUPDR_PU 0x1 -#define GPIO_PUPDR_PD 0x2 - -/* Alternate function register low */ - -#define GPIO_AFRL_AF0 (0xFU << 0) -#define GPIO_AFRL_AF1 (0xFU << 4) -#define GPIO_AFRL_AF2 (0xFU << 8) -#define GPIO_AFRL_AF3 (0xFU << 12) -#define GPIO_AFRL_AF4 (0xFU << 16) -#define GPIO_AFRL_AF5 (0xFU << 20) -#define GPIO_AFRL_AF6 (0xFU << 24) -#define GPIO_AFRL_AF7 (0xFU << 28) - -/* Alternate function register high */ - -#define GPIO_AFRH_AF8 (0xFU << 0) -#define GPIO_AFRH_AF9 (0xFU << 4) -#define GPIO_AFRH_AF10 (0xFU << 8) -#define GPIO_AFRH_AF11 (0xFU << 12) -#define GPIO_AFRH_AF12 (0xFU << 16) -#define GPIO_AFRH_AF13 (0xFU << 20) -#define GPIO_AFRH_AF14 (0xFU << 24) -#define GPIO_AFRH_AF15 (0xFU << 28) - -/* - * GPIO routines - */ - -/** - * @brief GPIO pin modes - */ -typedef enum gpio_pin_mode { - GPIO_MODE_INPUT = GPIO_MODER_INPUT, /**< Input mode */ - GPIO_MODE_OUTPUT = GPIO_MODER_OUTPUT, /**< Output mode */ - GPIO_MODE_AF = GPIO_MODER_AF, /**< Alternate function mode */ - GPIO_MODE_ANALOG = GPIO_MODER_ANALOG, /**< Analog mode */ -} gpio_pin_mode; - -/** - * @brief Additional flags to be used when setting a pin's mode. - * - * Beyond the basic modes (input, general purpose output, alternate - * function, and analog), there are three parameters that can affect a - * pin's mode: - * - * 1. Output type: push/pull or open-drain. This only has an effect - * for output modes. Choices are: GPIO_MODEF_TYPE_PP (the default) - * and GPIO_MODEF_TYPE_OD. - * - * 2. Output speed: specifies the frequency at which a pin changes - * state. This only has an effect for output modes. Choices are: - * GPIO_MODEF_SPEED_LOW (default), GPIO_MODEF_SPEED_MED, - * GPIO_MODEF_SPEED_FAST, and GPIO_MODEF_SPEED_HIGH. - * - * 3. Push/pull setting: All GPIO pins have weak pull-up and pull-down - * resistors that can be enabled when the pin's mode is - * set. Choices are: GPIO_MODEF_PUPD_NONE (default), - * GPIO_MODEF_PUPD_PU, and GPIO_MODEF_PUPD_PD. - */ -typedef enum gpio_mode_flags { - /* Output type in bit 0 */ - GPIO_MODEF_TYPE_PP = GPIO_OTYPER_PP, /**< Output push/pull (default). - Applies only when the mode - specifies output. */ - GPIO_MODEF_TYPE_OD = GPIO_OTYPER_OD, /**< Output open drain. - Applies only when the mode - specifies output. */ - - /* Speed in bits 2:1 */ - GPIO_MODEF_SPEED_LOW = GPIO_OSPEEDR_LOW << 1, /**< Low speed (default): - 2 MHz. */ - GPIO_MODEF_SPEED_MED = GPIO_OSPEEDR_MED << 1, /**< Medium speed: 25 MHz. */ - GPIO_MODEF_SPEED_FAST = GPIO_OSPEEDR_FAST << 1, /**< Fast speed: 50 MHz. */ - GPIO_MODEF_SPEED_HIGH = GPIO_OSPEEDR_HIGH << 1, /**< High speed: FIXME one of those does not exist on the F3 - 100 MHz on 30 pF, - 80 MHz on 15 pF. */ - - /* Pull-up/pull-down in bits 4:3 */ - GPIO_MODEF_PUPD_NONE = GPIO_PUPDR_NOPUPD << 3, /**< No pull-up/pull-down - (default). */ - GPIO_MODEF_PUPD_PU = GPIO_PUPDR_PU << 3, /**< Pull-up */ - GPIO_MODEF_PUPD_PD = GPIO_PUPDR_PD << 3, /**< Pull-down */ -} gpio_mode_flags; - -void gpio_set_modef(struct gpio_dev *dev, - uint8 bit, - gpio_pin_mode mode, - unsigned flags); - -/** - * @brief Set the mode of a GPIO pin. - * - * Calling this function is equivalent to calling gpio_set_modef(dev, - * pin, mode, GPIO_MODE_SPEED_HIGH). Note that this overrides the - * default speed. - * - * @param dev GPIO device. - * @param bit Bit on the device whose mode to set, 0--15. - * @param mode Mode to set the pin to. - */ -static inline void gpio_set_mode(struct gpio_dev *dev, - uint8 bit, - gpio_pin_mode mode) { - gpio_set_modef(dev, bit, mode, GPIO_MODEF_SPEED_HIGH); -} - -/** - * @brief GPIO alternate functions. - * Use these to select an alternate function for a pin. - * @see gpio_set_af() - */ -typedef enum gpio_af { - GPIO_AF_0 = 0x0, /**< alternate function 0. */ - GPIO_AF_1 = 0x1, /**< alternate function 1. */ - GPIO_AF_2 = 0x2, /**< alternate function 2. */ - GPIO_AF_3 = 0x3, /**< alternate function 3. */ - GPIO_AF_4 = 0x4, /**< alternate function 4. */ - GPIO_AF_5 = 0x5, /**< alternate function 5. */ - GPIO_AF_6 = 0x6, /**< alternate function 6. */ - GPIO_AF_7 = 0x7, /**< alternate function 7. */ - GPIO_AF_8 = 0x8, /**< alternate function 8. */ - GPIO_AF_9 = 0x9, /**< alternate function 9. */ - GPIO_AF_10 = 0xA, /**< alternate function 10. */ - GPIO_AF_11 = 0xB, /**< alternate function 11. */ - GPIO_AF_12 = 0xC, /**< alternate function 12. */ - GPIO_AF_13 = 0xD, /**< alternate function 13. */ - GPIO_AF_14 = 0xE, /**< alternate function 14. */ - GPIO_AF_15 = 0xF, /**< alternate function 14. */ -} gpio_af; - -void gpio_set_af(struct gpio_dev *dev, uint8 bit, gpio_af af); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/i2c.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/i2c.h deleted file mode 100644 index ef1b0ff..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/i2c.h +++ /dev/null @@ -1,315 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/stm32f3/include/series/i2c.h - * @author F3-port by Hanspeter Portner - * @brief STM32F3 I2C - */ - -#ifndef _LIBMAPLE_STM32F3_I2C_H_ -#define _LIBMAPLE_STM32F3_I2C_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -#include -#include -#include - -/* - * Register maps - */ - -/** I2C register map type */ -typedef struct i2c_reg_map { - __IO uint32 CR1; /**< Control register 1 */ - __IO uint32 CR2; /**< Control register 2 */ - __IO uint32 OAR1; /**< Own address register 1 */ - __IO uint32 OAR2; /**< Own address register 2 */ - __IO uint32 TIMINGR; /**< Timing register */ - __IO uint32 TIMEOUTR; /**< Timeout register */ - __IO uint32 ISR; /**< Interrupt and status register */ - __IO uint32 ICR; /**< Interrupt clear register */ - __IO uint32 PECR; /**< PEC register */ - __IO uint32 RXDR; /**< Receive data register */ - __IO uint32 TXDR; /**< Transmit data register */ -} i2c_reg_map; - -extern i2c_dev* const I2C1; -extern i2c_dev* const I2C2; - -/* - * Register map base pointers - */ - -/** STM32F3 I2C1 register map base pointer */ -#define I2C1_BASE ((struct i2c_reg_map*)0x40005400) -/** STM32F3 I2C2 register map base pointer */ -#define I2C2_BASE ((struct i2c_reg_map*)0x40005800) - -/* - * Register bit definitions - */ - -/* Control register 1 */ -#define I2C_CR1_PECEN_BIT 23 -#define I2C_CR1_ALERTEN_BIT 22 -#define I2C_CR1_SMBDEN_BIT 21 -#define I2C_CR1_SMBHEN_BIT 20 -#define I2C_CR1_GCEN_BIT 19 -#define I2C_CR1_WUPEN_BIT 18 -#define I2C_CR1_NOSTRETCH_BIT 17 -#define I2C_CR1_SBC_BIT 16 -#define I2C_CR1_RXDMAEN_BIT 15 -#define I2C_CR1_TXDMAEN_BIT 14 -#define I2C_CR1_ANFOFF_BIT 12 -#define I2C_CR1_DNF_SHIFT 8 -#define I2C_CR1_ERRIE_BIT 7 -#define I2C_CR1_TCIE_BIT 6 -#define I2C_CR1_STOPIE_BIT 5 -#define I2C_CR1_NACKIE_BIT 4 -#define I2C_CR1_ADDRIE_BIT 3 -#define I2C_CR1_RXIE_BIT 2 -#define I2C_CR1_TXIE_BIT 1 -#define I2C_CR1_PE_BIT 0 - -#define I2C_CR1_PECEN (1U << I2C_CR1_PECEN_BIT) -#define I2C_CR1_ALERTEN (1U << I2C_CR1_ALERTEN_BIT) -#define I2C_CR1_SMBDEN (1U << I2C_CR1_SMBDEN_BIT) -#define I2C_CR1_SMBHEN (1U << I2C_CR1_SMBHEN_BIT) -#define I2C_CR1_GCEN (1U << I2C_CR1_GCEN_BIT) -#define I2C_CR1_WUPEN (1U << I2C_CR1_WUPEN_BIT) -#define I2C_CR1_NOSTRETCH (1U << I2C_CR1_NOSTRETCH_BIT) -#define I2C_CR1_SBC (1U << I2C_CR1_SBC_BIT) -#define I2C_CR1_RXDMAEN (1U << I2C_CR1_RXDMAEN_BIT) -#define I2C_CR1_TXDMAEN (1U << I2C_CR1_TXDMAEN_BIT) -#define I2C_CR1_ANFOFF (1U << I2C_CR1_ANFOFF_BIT) -#define I2C_CR1_DNF (0xF << I2C_CR1_DNF_SHIFT) -#define I2C_CR1_ERRIE (1U << I2C_CR1_ERRIE_BIT) -#define I2C_CR1_TCIE (1U << I2C_CR1_TCIE_BIT) -#define I2C_CR1_STOPIE (1U << I2C_CR1_STOPIE_BIT) -#define I2C_CR1_NACKIE (1U << I2C_CR1_NACKIE_BIT) -#define I2C_CR1_ADDRIE (1U << I2C_CR1_ADDRIE_BIT) -#define I2C_CR1_RXIE (1U << I2C_CR1_RXIE_BIT) -#define I2C_CR1_TXIE (1U << I2C_CR1_TXIE_BIT) -#define I2C_CR1_PE (1U << I2C_CR1_PE_BIT) - -/* Control register 2 */ -#define I2C_CR2_PECBYTE_BIT 26 -#define I2C_CR2_AUTOEND_BIT 25 -#define I2C_CR2_RELOAD_BIT 24 -#define I2C_CR2_NBYTES_SHIFT 16 -#define I2C_CR2_NACK_BIT 15 -#define I2C_CR2_STOP_BIT 14 -#define I2C_CR2_START_BIT 13 -#define I2C_CR2_HEAD10R_BIT 12 -#define I2C_CR2_ADD10_BIT 11 -#define I2C_CR2_RD_WRN_BIT 10 -#define I2C_CR2_SADD_7_BIT_SHIFT 1 -#define I2C_CR2_SADD_10_BIT_SHIFT 0 - -#define I2C_CR2_PECBYTE (1U << I2C_CR2_PECBYTE_BIT) -#define I2C_CR2_AUTOEND (1U << I2C_CR2_AUTOEND_BIT) -#define I2C_CR2_RELOAD (1U << I2C_CR2_RELOAD_BIT) -#define I2C_CR2_NBYTES (0xFF << I2C_CR2_NBYTES_SHIFT) -#define I2C_CR2_NACK (1U << I2C_CR2_NACK_BIT) -#define I2C_CR2_STOP (1U << I2C_CR2_STOP_BIT) -#define I2C_CR2_START (1U << I2C_CR2_START_BIT) -#define I2C_CR2_HEAD10R (1U << I2C_CR2_HEAD10R_BIT) -#define I2C_CR2_ADD10 (1U << I2C_CR2_ADD10_BIT) -#define I2C_CR2_RD_WRN (1U << I2C_CR2_RD_WRN_BIT) -#define I2C_CR2_SADD_7_BIT (0x7F << I2C_CR2_SADD_7_BIT_SHIFT) -#define I2C_CR2_SADD_10_BIT (0x3FF << I2C_CR2_SADD_10_BIT_SHIFT) - -/* Own address register 1 */ -#define I2C_OAR1_OA1EN_BIT 15 -#define I2C_OAR1_OA1MODE_BIT 10 -#define I2C_OAR1_OA1_7_BIT_SHIFT 1 -#define I2C_OAR1_OA1_10_BIT_SHIFT 0 - -#define I2C_OAR1_OA1EN (1U << I2C_OAR1_OA1EN_BIT) -#define I2C_OAR1_OA1MODE (1U << I2C_OAR1_OA1MODE_BIT) -#define I2C_OAR1_OA1_7_BIT (0x7F << I2C_OAR1_OA1_7_BIT_SHIFT) -#define I2C_OAR1_OA1_10_BIT (0x3FF << I2C_OAR1_OA1_10_BIT_SHIFT) - -/* Own address register 2 */ -#define I2C_OAR2_OA2EN_BIT 15 -#define I2C_OAR2_OA2MSK_SHIFT 8 -#define I2C_OAR2_OA2_7_BIT_SHIFT 1 - -#define I2C_OAR2_OA2EN (1U << I2C_OAR2_OA2EN_BIT) -#define I2C_OAR2_OA2MSK (0x7 << I2C_OAR2_OA2MSK_SHIFT) -#define I2C_OAR2_OA2_7_BIT (0x7F << I2C_OAR2_OA2_7_BIT_SHIFT) - -/* Timing register */ -#define I2C_TIMINGR_PRESC_SHIFT 28 -#define I2C_TIMINGR_SCLDEL_SHIFT 20 -#define I2C_TIMINGR_SDADEL_SHIFT 16 -#define I2C_TIMINGR_SCLH_SHIFT 8 -#define I2C_TIMINGR_SCLL_SHIFT 0 - -#define I2C_TIMINGR_PRESC (0xF << I2C_TIMINGR_PRESC_SHIFT) -#define I2C_TIMINGR_SCLDEL (0xF << I2C_TIMINGR_SCLDEL_SHIFT) -#define I2C_TIMINGR_SCADEL (0xF << I2C_TIMINGR_SCADEL_SHIFT) -#define I2C_TIMINGR_SCLH (0xFF << I2C_TIMINGR_SCLH_SHIFT) -#define I2C_TIMINGR_SCLL (0xFF << I2C_TIMINGR_SCLL_SHIFT) - -/* Timeout register */ -#define I2C_TIMEOUTR_TEXTEN_BIT 31 -#define I2C_TIMEOUTR_TIMEOUTB_SHIFT 16 -#define I2C_TIMEOUTR_TIMOUTEN_BIT 15 -#define I2C_TIMEOUTR_TIDLE_BIT 12 -#define I2C_TIMEOUTR_TIMEOUTA_SHIFT 0 - -#define I2C_TIMEOUTR_TEXTEN (1U << I2C_TIMEOUTR_TEXTEN_BIT) -#define I2C_TIMEOUTR_TIMEOUTB (0xFFF << I2C_TIMEOUTR_TIMEOUTB_SHIFT) -#define I2C_TIMEOUTR_TIMOUTEN (1U << I2C_TIMEOUTR_TIMOUTEN_BIT) -#define I2C_TIMEOUTR_TIDLE (1U << I2C_TIMEOUTR_TIDLE_BIT) -#define I2C_TIMEOUTR_TIMEOUTA (0xFFF << I2C_TIMEOUTR_TIMEOUTA_SHIFT) - -/* Interrupt and status register */ -#define I2C_ISR_ADDCODE_SHIFT 17 -#define I2C_ISR_DIR_BIT 16 -#define I2C_ISR_BUSY_BIT 15 -#define I2C_ISR_ALERT_BIT 13 -#define I2C_ISR_TIMEOUT_BIT 12 -#define I2C_ISR_PECERR_BIT 11 -#define I2C_ISR_OVR_BIT 10 -#define I2C_ISR_ARLO_BIT 9 -#define I2C_ISR_BERR_BIT 8 -#define I2C_ISR_TCR_BIT 7 -#define I2C_ISR_TC_BIT 6 -#define I2C_ISR_STOPF_BIT 5 -#define I2C_ISR_NACKF_BIT 4 -#define I2C_ISR_ADDR_BIT 3 -#define I2C_ISR_RXNE_BIT 2 -#define I2C_ISR_TXIS_BIT 1 -#define I2C_ISR_TXE_BIT 0 - -#define I2C_ISR_ADDCODE (0x7F << I2C_ISR_ADDCODE_SHIFT) -#define I2C_ISR_ALERTCF (1U << I2C_ISR_ALERTCF_BIT) -#define I2C_ISR_DIR (1U << I2C_ISR_DIR_BIT) -#define I2C_ISR_BUSY (1U << I2C_ISR_BUSY_BIT) -#define I2C_ISR_ALERT (1U << I2C_ISR_ALERT_BIT) -#define I2C_ISR_TIMEOUT (1U << I2C_ISR_TIMEOUT_BIT) -#define I2C_ISR_PECERR (1U << I2C_ISR_PECERR_BIT) -#define I2C_ISR_OVR (1U << I2C_ISR_OVR_BIT) -#define I2C_ISR_ARLO (1U << I2C_ISR_ARLO_BIT) -#define I2C_ISR_BERR (1U << I2C_ISR_BERR_BIT) -#define I2C_ISR_TCR (1U << I2C_ISR_TCR_BIT) -#define I2C_ISR_TC (1U << I2C_ISR_TC_BIT) -#define I2C_ISR_STOPF (1U << I2C_ISR_STOPF_BIT) -#define I2C_ISR_NACKF (1U << I2C_ISR_NACKF_BIT) -#define I2C_ISR_ADDR (1U << I2C_ISR_ADDR_BIT) -#define I2C_ISR_RXNE (1U << I2C_ISR_RXNE_BIT) -#define I2C_ISR_TXIS (1U << I2C_ISR_TXIS_BIT) -#define I2C_ISR_TXE (1U << I2C_ISR_TXE_BIT) - -/* Interrupt clear register */ -#define I2C_ICR_ALERTCF_BIT 13 -#define I2C_ICR_TIMOUTCF_BIT 12 -#define I2C_ICR_PECCF_BIT 11 -#define I2C_ICR_OVRCF_BIT 10 -#define I2C_ICR_ARLOCF_BIT 9 -#define I2C_ICR_BERRCF_BIT 8 -#define I2C_ICR_STOPCF_BIT 5 -#define I2C_ICR_NACKCF_BIT 4 -#define I2C_ICR_ADDRCF_BIT 3 - -#define I2C_ICR_ALERTCF (1U << I2C_ICR_ALERTCF_BIT) -#define I2C_ICR_TIMOUTCF (1U << I2C_ICR_TIMOUTCF_BIT) -#define I2C_ICR_PECCF (1U << I2C_ICR_PECERRCF_BIT) -#define I2C_ICR_OVRCF (1U << I2C_ICR_OVRCF_BIT) -#define I2C_ICR_ARLOCF (1U << I2C_ICR_ARLOCF_BIT) -#define I2C_ICR_BERRCF (1U << I2C_ICR_BERRCF_BIT) -#define I2C_ICR_STOPCF (1U << I2C_ICR_STOPCF_BIT) -#define I2C_ICR_NACKCF (1U << I2C_ICR_NACKCF_BIT) -#define I2C_ICR_ADDRCF (1U << I2C_ICR_ADDRCF_BIT) - -/* PEC register */ -#define I2C_PEC_PEC 0xFF - -/* Receive data register */ -#define I2C_RXDR_RXDATA 0xFF - -/* Transmit data register */ -#define I2C_TXDR_TXDATA 0xFF - -/* - * Timing configurations - */ - -/* Timing configuration for I2C clock running at 8MHz */ - -/* NOTE: - * I2C is clocked by HSI (8MHz) by default - * if clock source is changed with RCC_CFGR_I2C1SW/I2C2SW, - * these values have to be adapted - */ -typedef enum i2c_timing { - I2C_TIMING_10_kHz = (0x01 << I2C_TIMINGR_PRESC_SHIFT) - + (0x04 << I2C_TIMINGR_SCLDEL_SHIFT) - + (0x02 << I2C_TIMINGR_SDADEL_SHIFT) - + (0xC3 << I2C_TIMINGR_SCLH_SHIFT) - + (0xC7 << I2C_TIMINGR_SCLL_SHIFT), - - I2C_TIMING_100_kHz = (0x01 << I2C_TIMINGR_PRESC_SHIFT) - + (0x04 << I2C_TIMINGR_SCLDEL_SHIFT) - + (0x02 << I2C_TIMINGR_SDADEL_SHIFT) - + (0x0F << I2C_TIMINGR_SCLH_SHIFT) - + (0x13 << I2C_TIMINGR_SCLL_SHIFT), - - I2C_TIMING_400_kHz = (0x00 << I2C_TIMINGR_PRESC_SHIFT) - + (0x03 << I2C_TIMINGR_SCLDEL_SHIFT) - + (0x01 << I2C_TIMINGR_SDADEL_SHIFT) - + (0x03 << I2C_TIMINGR_SCLH_SHIFT) - + (0x09 << I2C_TIMINGR_SCLL_SHIFT), - - I2C_TIMING_500_kHz = (0x00 << I2C_TIMINGR_PRESC_SHIFT) - + (0x01 << I2C_TIMINGR_SCLDEL_SHIFT) - + (0x01 << I2C_TIMINGR_SDADEL_SHIFT) - + (0x03 << I2C_TIMINGR_SCLH_SHIFT) - + (0x06 << I2C_TIMINGR_SCLL_SHIFT), -} i2c_timing; - -/* - * For internal use - */ - -static inline uint32 _i2c_bus_clk(i2c_dev *dev) { /* FIXME remove, is a remainder of F1 code */ - /* Both I2C peripherals are on APB1 */ - return STM32_PCLK1 / (1000 * 1000); -} - -extern uint8 i2c_read(i2c_dev *dev); - -#ifdef __cplusplus -} -#endif - -#endif /* _LIBMAPLE_STM32F3_I2C_H_ */ diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/nvic.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/nvic.h deleted file mode 100644 index 7643c32..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/nvic.h +++ /dev/null @@ -1,153 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/stm32f3/include/series/nvic.h - * @author F3-port by Hanspeter Portner - * @brief STM32F3 Nested Vectored Interrupt Controller (NVIC) support. - */ - -#ifndef _LIBMAPLE_STM32F3_NVIC_H_ -#define _LIBMAPLE_STM32F3_NVIC_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -#include -#include - -/** - * @brief STM32F1 interrupt vector table interrupt numbers. - * @see - */ -typedef enum nvic_irq_num { - NVIC_NMI = -14, /**< Non-maskable interrupt */ - NVIC_HARDFAULT = -13, /**< Hard fault (all class of fault) */ - NVIC_MEM_MANAGE = -12, /**< Memory management */ - NVIC_BUS_FAULT = -11, /**< Bus fault: prefetch fault, memory - access fault. */ - NVIC_USAGE_FAULT = -10, /**< Usage fault: Undefined instruction or - illegal state. */ - NVIC_SVC = -5, /**< System service call via SWI insruction */ - NVIC_DEBUG_MON = -4, /**< Debug monitor */ - NVIC_PEND_SVC = -2, /**< Pendable request for system service */ - NVIC_SYSTICK = -1, /**< System tick timer */ - - NVIC_WWDG = 0, /**< Window watchdog interrupt */ - NVIC_PVD = 1, /**< PVD through EXTI line detection */ - NVIC_TAMP_STAMP = 2, /**< Tamper */ - NVIC_RTC_WKUP = 3, /**< Real-time clock */ - NVIC_FLASH = 4, /**< Flash */ - NVIC_RCC = 5, /**< Reset and clock control */ - NVIC_EXTI0 = 6, /**< EXTI line 0 */ - NVIC_EXTI1 = 7, /**< EXTI line 1 */ - NVIC_EXTI2 = 8, /**< EXTI line 2 */ //FIXME capacitive touch - NVIC_EXTI3 = 9, /**< EXTI line 3 */ - NVIC_EXTI4 = 10, /**< EXTI line 4 */ - NVIC_DMA_CH1 = 11, /**< DMA1 channel 1 */ - NVIC_DMA_CH2 = 12, /**< DMA1 channel 2 */ - NVIC_DMA_CH3 = 13, /**< DMA1 channel 3 */ - NVIC_DMA_CH4 = 14, /**< DMA1 channel 4 */ - NVIC_DMA_CH5 = 15, /**< DMA1 channel 5 */ - NVIC_DMA_CH6 = 16, /**< DMA1 channel 6 */ - NVIC_DMA_CH7 = 17, /**< DMA1 channel 7 */ - NVIC_ADC1_2 = 18, /**< ADC1 and ADC2 */ - NVIC_USB_HP_CAN_TX = 19, /**< USB high priority or CAN TX */ - NVIC_USB_LP_CAN_RX0 = 20, /**< USB low priority or CAN RX0 */ - NVIC_CAN_RX1 = 21, /**< CAN RX1 */ - NVIC_CAN_SCE = 22, /**< CAN SCE */ - NVIC_EXTI_9_5 = 23, /**< EXTI line [9:5] */ - //NVIC_TIMER1_BRK_TIMER15 = 24, // FIXME hack - NVIC_TIMER1_BRK_TIMER9 = 24, /**< Timer 1 break, Timer 9. */ // FIXME rm - //NVIC_TIMER1_UP_TIMER16 = 25, // FIXME hack - NVIC_TIMER1_UP_TIMER10 = 25, /**< Timer 1 update, Timer 10. */ //FIXME rm - //NVIC_TIMER1_TRG_COM_TIMER17 = 26, // FIXME hack - NVIC_TIMER1_TRG_COM_TIMER11 = 26, /**< - * Timer 1 trigger and commutation, - * Timer 11. */ // FIXME rm - NVIC_TIMER1_CC = 27, /**< Timer 1 capture/compare */ - NVIC_TIMER2 = 28, /**< Timer 2 */ - NVIC_TIMER3 = 29, /**< Timer 3 */ - NVIC_TIMER4 = 30, /**< Timer 4 */ - NVIC_I2C1_EV = 31, /**< I2C1 event */ - NVIC_I2C1_ER = 32, /**< I2C1 error */ - NVIC_I2C2_EV = 33, /**< I2C2 event */ - NVIC_I2C2_ER = 34, /**< I2C2 error */ - NVIC_SPI1 = 35, /**< SPI1 */ - NVIC_SPI2 = 36, /**< SPI2 */ - NVIC_USART1 = 37, /**< USART1 */ - NVIC_USART2 = 38, /**< USART2 */ - NVIC_USART3 = 39, /**< USART3 */ - NVIC_EXTI_15_10 = 40, /**< EXTI line [15:10] */ - NVIC_RTC_ALARM = 41, /**< RTC alarm through EXTI line */ - NVIC_USB_WKUP = 42, /**< USB wakeup from suspend through - EXTI line */ - NVIC_TIMER8_BRK_TIMER12 = 43, /**< Timer 8 break, timer 12 */ //TODO rm TIMER12 - NVIC_TIMER8_UP_TIMER13 = 44, /**< Timer 8 update, timer 13 */ // TODO rm TIMER13 - NVIC_TIMER8_TRG_COM_TIMER14 = 45, /**< - * Timer 8 trigger and commutation, - * Timer 14. */ //TODO rm TIMER14 - NVIC_TIMER8_CC = 46, /**< Timer 8 capture/compare */ - NVIC_ADC3 = 47, /**< ADC3 */ - - NVIC_SPI3 = 51, /**< SPI3 */ - NVIC_UART4 = 52, /**< UART4 */ - NVIC_UART5 = 53, /**< UART5 */ - //NVIC_TIMER6_DAC = 54, // TODO hack - NVIC_TIMER6 = 54, /**< Timer 6 */ //TODO add DAC - NVIC_TIMER7 = 55, /**< Timer 7 */ - NVIC_DMA2_CH1 = 56, /**< DMA2 channel 1 */ - NVIC_DMA2_CH2 = 57, /**< DMA2 channel 2 */ - NVIC_DMA2_CH3 = 58, /**< DMA2 channel 3 */ - NVIC_DMA2_CH4 = 59, /**< DMA2 channel 4 */ - NVIC_DMA2_CH5 = 60, /**< DMA2 channel 5 */ - - NVIC_ADC4 = 61, /**< DMA2 channels 4 and 5 */ - - NVIC_COMP123 = 64, /**< DMA2 channels 4 and 5 */ - NVIC_COMP456 = 65, /**< DMA2 channels 4 and 5 */ - NVIC_COMP7 = 66, /**< DMA2 channels 4 and 5 */ - - NVIC_USB_HP = 74, /**< DMA2 channels 4 and 5 */ - NVIC_USB_LP = 75, /**< DMA2 channels 4 and 5 */ - NVIC_USB_WKUP2 = 76, /**< DMA2 channels 4 and 5 */ - - NVIC_FPU = 81, /**< DMA2 channels 4 and 5 */ -} nvic_irq_num; - -static inline void nvic_irq_disable_all(void) { - NVIC_BASE->ICER[0] = 0xFFFFFFFF; - NVIC_BASE->ICER[1] = 0xFFFFFFFF; - NVIC_BASE->ICER[2] = 0xFFFFFFFF; -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/opamp.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/opamp.h deleted file mode 100644 index a5c627b..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/opamp.h +++ /dev/null @@ -1,123 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/stm32f3/include/series/ompamp.h - * @author F3-port by Hanspeter Portner - * @brief STM32F3 Operational Amplifier support. - */ - -#ifndef _LIBMAPLE_STM32F3_OPAMP_H_ -#define _LIBMAPLE_STM32F3_OPAMP_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -#include - -/* - * Register map - */ - -/* - * OpAmp individual register map type. - */ -typedef struct opamp_reg_map { - __IO uint32 CSR; /**< */ -} opamp_reg_map; - -/** OpAmp device type. */ -typedef struct opamp_dev { - opamp_reg_map *regs; /**< Register map */ -} opamp_dev; - -/* - * Devices - */ - -extern const struct opamp_dev *OPAMP1; /* OpAmp amplifier 1 */ -extern const struct opamp_dev *OPAMP2; /* OpAmp amplifier 2 */ -extern const struct opamp_dev *OPAMP3; /* OpAmp amplifier 3 */ -extern const struct opamp_dev *OPAMP4; /* OpAmp amplifier 4 */ - -/* - * Register map base pointers - */ - -#define OPAMP1_BASE ((struct opamp_reg_map*)0x40010038) -#define OPAMP2_BASE ((struct opamp_reg_map*)0x4001003C) -#define OPAMP3_BASE ((struct opamp_reg_map*)0x40010040) -#define OPAMP4_BASE ((struct opamp_reg_map*)0x40010044) - -/* - * Register bit definitions - */ - -/* Control and status register */ -#define OPAMP_CSR_LOCK_BIT 31 -#define OPAMP_CSR_OUTCAL_BIT 30 -#define OPAMP_CSR_TSTREF_BIT 29 -#define OPAMP_CSR_TRIMOFFSETN_SHIFT 24 -#define OPAMP_CSR_TRIMOFFSETP_SHIFT 19 -#define OPAMP_CSR_USER_TRIM_BIT 18 -#define OPAMP_CSR_PGA_GAIN_SHIFT 14 -#define OPAMP_CSR_CAL_SEL_SHIFT 12 -#define OPAMP_CSR_CAL_ON_BIT 11 -#define OPAMP_CSR_VPS_SEL_SHIFT 9 -#define OPAMP_CSR_VMS_SEL_BIT 8 -#define OPAMP_CSR_TCM_EN_BIT 7 -#define OPAMP_CSR_VM_SEL_SHIFT 5 -#define OPAMP_CSR_VP_SEL_SHIFT 2 -#define OPAMP_CSR_FORCE_VP_BIT 1 -#define OPAMP_CSR_EN_BIT 0 - -#define OPAMP_CSR_LOCK (1U << OPAMP_CSR_LOCK_BIT) -#define OPAMP_CSR_OUTCAL (1U << OPAMP_CSR_OUTCAL_BIT) -#define OPAMP_CSR_TSTREF (1U << OPAMP_CSR_TSTREF_BIT) -#define COMP_CSR_TRIMOFFSETN (0x1F << COMP_CSR_TRIMOFFSETN_SHIFT) -#define COMP_CSR_TRIMOFFSETP (0x1F << COMP_CSR_TRIMOFFSETP_SHIFT) -#define OPAMP_CSR_USER_TRIM (1U << OPAMP_CSR_USER_TRIM_BIT) -#define COMP_CSR_PGA_GAIN (0xF << COMP_CSR_PGA_GAIN_SHIFT) -#define COMP_CSR_CAL_SEL (0x3 << COMP_CSR_CAL_SEL_SHIFT) -#define OPAMP_CSR_CAL_ON (1U << OPAMP_CSR_CAL_ON_BIT) -#define COMP_CSR_VPS_SEL (0x3 << COMP_CSR_VPS_SEL_SHIFT) -#define OPAMP_CSR_VMS_SEL (1U << OPAMP_CSR_VMS_SEL_BIT) -#define OPAMP_CSR_TCM_EN (1U << OPAMP_CSR_TCM_EN_BIT) -#define COMP_CSR_VM_SEL (0x3 << COMP_CSR_VM_SEL_SHIFT) -#define COMP_CSR_VP_SEL (0x3 << COMP_CSR_VP_SEL_SHIFT) -#define OPAMP_CSR_FORCE_VP (1U << OPAMP_CSR_FORCE_VP_BIT) -#define OPAMP_CSR_EN (1U << OPAMP_CSR_EN_BIT) - -/* TODO - * actually implement me ;-) - */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/pwr.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/pwr.h deleted file mode 100644 index d3564e8..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/pwr.h +++ /dev/null @@ -1,52 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/stm32f1/include/series/pwr.h - * @author Marti Bolivar - * @brief STM32F3 Power control (PWR) support. - */ - -#ifndef _LIBMAPLE_STM32F3_PWR_H_ -#define _LIBMAPLE_STM32F3_PWR_H_ - -/* - * Register bit definitions - */ - -/* Control register */ - -/* PVD level selection */ -#define PWR_CR_PLS_2_2V (0x0 << 5) -#define PWR_CR_PLS_2_3V (0x1 << 5) -#define PWR_CR_PLS_2_4V (0x2 << 5) -#define PWR_CR_PLS_2_5V (0x3 << 5) -#define PWR_CR_PLS_2_6V (0x4 << 5) -#define PWR_CR_PLS_2_7V (0x5 << 5) -#define PWR_CR_PLS_2_8V (0x6 << 5) -#define PWR_CR_PLS_2_9V (0x7 << 5) - -#endif diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/rcc.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/rcc.h deleted file mode 100644 index b8f4b34..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/rcc.h +++ /dev/null @@ -1,632 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * Copyright (c) 2011 LeafLabs, LLC. - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/stm32f3/include/series/rcc.h - * @author F3-port by Hanspeter Portner - * @brief STM32F3 reset and clock control (RCC) support. - */ - -#ifndef _LIBMAPLE_STM32F3_RCC_H_ -#define _LIBMAPLE_STM32F3_RCC_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -#include - -/* - * Register map - */ - -/** STM32F3 RCC register map type */ -typedef struct rcc_reg_map { - __IO uint32 CR; /**< Clock control register */ - __IO uint32 CFGR; /**< Clock configuration register */ - __IO uint32 CIR; /**< Clock interrupt register */ - __IO uint32 APB2RSTR; /**< APB2 peripheral reset register */ - __IO uint32 APB1RSTR; /**< APB1 peripheral reset register */ - __IO uint32 AHBENR; /**< AHB peripheral clock enable register */ - __IO uint32 APB2ENR; /**< APB2 peripheral clock enable register */ - __IO uint32 APB1ENR; /**< APB1 peripheral clock enable register */ - __IO uint32 BDCR; /**< Backup domain control register */ - __IO uint32 CSR; /**< Control/status register */ - __IO uint32 AHBRSTR; /**< AHB peripheral reset register */ - __IO uint32 CFGR2; /**< Control/status register 2 */ - __IO uint32 CFGR3; /**< Control/status register 3 */ -} rcc_reg_map; - -#define RCC_BASE ((struct rcc_reg_map*)0x40021000) - -/* - * Register bit definitions - */ - -/* Clock control register */ - -#define RCC_CR_PLLRDY_BIT 25 -#define RCC_CR_PLLON_BIT 24 -#define RCC_CR_CSSON_BIT 19 -#define RCC_CR_HSEBYP_BIT 18 -#define RCC_CR_HSERDY_BIT 17 -#define RCC_CR_HSEON_BIT 16 -#define RCC_CR_HSIRDY_BIT 1 -#define RCC_CR_HSION_BIT 0 - -#define RCC_CR_PLLRDY (1U << RCC_CR_PLLRDY_BIT) -#define RCC_CR_PLLON (1U << RCC_CR_PLLON_BIT) -#define RCC_CR_CSSON (1U << RCC_CR_CSSON_BIT) -#define RCC_CR_HSEBYP (1U << RCC_CR_HSEBYP_BIT) -#define RCC_CR_HSERDY (1U << RCC_CR_HSERDY_BIT) -#define RCC_CR_HSEON (1U << RCC_CR_HSEON_BIT) -#define RCC_CR_HSICAL (0xFF << 8) -#define RCC_CR_HSITRIM (0x1F << 3) -#define RCC_CR_HSIRDY (1U << RCC_CR_HSIRDY_BIT) -#define RCC_CR_HSION (1U << RCC_CR_HSION_BIT) - -/* Clock configuration register */ - -#define RCC_CFGR_I2SSRC_BIT 23 -#define RCC_CFGR_USBPRE_BIT 22 -#define RCC_CFGR_PLLMUL_BIT 18 -#define RCC_CFGR_PLLXTPRE_BIT 17 -#define RCC_CFGR_PLLSRC_BIT 16 -#define RCC_CFGR_PPRE2_BIT 11 -#define RCC_CFGR_PPRE1_BIT 8 -#define RCC_CFGR_HPRE_BIT 4 - -#define RCC_CFGR_MCO (0x3 << 24) -#define RCC_CFGR_I2SSRC (1U << RCC_CFGR_I2CSRC_BIT) -#define RCC_CFGR_USBPRE (1U << RCC_CFGR_USBPRE_BIT) -#define RCC_CFGR_PLLMUL (0xF << RCC_CFGR_PLLMUL_BIT) -#define RCC_CFGR_PLLXTPRE (1U << RCC_CFGR_PLLXTPRE_BIT) -#define RCC_CFGR_PLLSRC (1U << RCC_CFGR_PLLSRC_BIT) -#define RCC_CFGR_PPRE2 (0x7 << RCC_CFGR_PPRE2_BIT) -#define RCC_CFGR_PPRE1 (0x7 << RCC_CFGR_PPRE1_BIT) -#define RCC_CFGR_HPRE (0xF << RCC_CFGR_HPRE_BIT) -#define RCC_CFGR_SWS (0x3 << 2) -#define RCC_CFGR_SWS_PLL (0x2 << 2) -#define RCC_CFGR_SWS_HSE (0x1 << 2) -#define RCC_CFGR_SW 0x3 -#define RCC_CFGR_SW_PLL 0x2 -#define RCC_CFGR_SW_HSE 0x1 - -/* Clock interrupt register */ - -#define RCC_CIR_CSSC_BIT 23 -#define RCC_CIR_PLLRDYC_BIT 20 -#define RCC_CIR_HSERDYC_BIT 19 -#define RCC_CIR_HSIRDYC_BIT 18 -#define RCC_CIR_LSERDYC_BIT 17 -#define RCC_CIR_LSIRDYC_BIT 16 -#define RCC_CIR_PLLRDYIE_BIT 12 -#define RCC_CIR_HSERDYIE_BIT 11 -#define RCC_CIR_HSIRDYIE_BIT 10 -#define RCC_CIR_LSERDYIE_BIT 9 -#define RCC_CIR_LSIRDYIE_BIT 8 -#define RCC_CIR_CSSF_BIT 7 -#define RCC_CIR_PLLRDYF_BIT 4 -#define RCC_CIR_HSERDYF_BIT 3 -#define RCC_CIR_HSIRDYF_BIT 2 -#define RCC_CIR_LSERDYF_BIT 1 -#define RCC_CIR_LSIRDYF_BIT 0 - -#define RCC_CIR_CSSC (1U << RCC_CIR_CSSC_BIT) -#define RCC_CIR_PLLRDYC (1U << RCC_CIR_PLLRDYC_BIT) -#define RCC_CIR_HSERDYC (1U << RCC_CIR_HSERDYC_BIT) -#define RCC_CIR_HSIRDYC (1U << RCC_CIR_HSIRDYC_BIT) -#define RCC_CIR_LSERDYC (1U << RCC_CIR_LSERDYC_BIT) -#define RCC_CIR_LSIRDYC (1U << RCC_CIR_LSIRDYC_BIT) -#define RCC_CIR_PLLRDYIE (1U << RCC_CIR_PLLRDYIE_BIT) -#define RCC_CIR_HSERDYIE (1U << RCC_CIR_HSERDYIE_BIT) -#define RCC_CIR_HSIRDYIE (1U << RCC_CIR_HSIRDYIE_BIT) -#define RCC_CIR_LSERDYIE (1U << RCC_CIR_LSERDYIE_BIT) -#define RCC_CIR_LSIRDYIE (1U << RCC_CIR_LSIRDYIE_BIT) -#define RCC_CIR_CSSF (1U << RCC_CIR_CSSF_BIT) -#define RCC_CIR_PLLRDYF (1U << RCC_CIR_PLLRDYF_BIT) -#define RCC_CIR_HSERDYF (1U << RCC_CIR_HSERDYF_BIT) -#define RCC_CIR_HSIRDYF (1U << RCC_CIR_HSIRDYF_BIT) -#define RCC_CIR_LSERDYF (1U << RCC_CIR_LSERDYF_BIT) -#define RCC_CIR_LSIRDYF (1U << RCC_CIR_LSIRDYF_BIT) - -/* APB2 peripheral reset register */ - -#define RCC_APB2RSTR_TIM17RST_BIT 18 -#define RCC_APB2RSTR_TIM16RST_BIT 17 -#define RCC_APB2RSTR_TIM15RST_BIT 16 -#define RCC_APB2RSTR_USART1RST_BIT 14 -#define RCC_APB2RSTR_TIM8RST_BIT 13 -#define RCC_APB2RSTR_SPI1RST_BIT 12 -#define RCC_APB2RSTR_TIM1RST_BIT 11 -#define RCC_APB2RSTR_SYSCFGRST_BIT 0 - -#define RCC_APB2RSTR_TIM17RST (1U << RCC_APB2RSTR_TIM17RST_BIT) -#define RCC_APB2RSTR_TIM16RST (1U << RCC_APB2RSTR_TIM16RST_BIT) -#define RCC_APB2RSTR_TIM15RST (1U << RCC_APB2RSTR_TIM15RST_BIT) -#define RCC_APB2RSTR_USART1RST (1U << RCC_APB2RSTR_USART1RST_BIT) -#define RCC_APB2RSTR_TIM8RST (1U << RCC_APB2RSTR_TIM8RST_BIT) -#define RCC_APB2RSTR_SPI1RST (1U << RCC_APB2RSTR_SPI1RST_BIT) -#define RCC_APB2RSTR_TIM1RST (1U << RCC_APB2RSTR_TIM1RST_BIT) -#define RCC_APB2RSTR_SYSCFGRST (1U << RCC_APB2RSTR_SYSCFGRST_BIT) - -/* APB1 peripheral reset register */ - -#define RCC_APB1RSTR_DACRST_BIT 29 -#define RCC_APB1RSTR_PWRRST_BIT 28 -#define RCC_APB1RSTR_CANRST_BIT 25 -#define RCC_APB1RSTR_USBRST_BIT 23 -#define RCC_APB1RSTR_I2C2RST_BIT 22 -#define RCC_APB1RSTR_I2C1RST_BIT 21 -#define RCC_APB1RSTR_UART5RST_BIT 20 -#define RCC_APB1RSTR_UART4RST_BIT 19 -#define RCC_APB1RSTR_USART3RST_BIT 18 -#define RCC_APB1RSTR_USART2RST_BIT 17 -#define RCC_APB1RSTR_SPI3RST_BIT 15 -#define RCC_APB1RSTR_SPI2RST_BIT 14 -#define RCC_APB1RSTR_WWDRST_BIT 11 -#define RCC_APB1RSTR_TIM7RST_BIT 5 -#define RCC_APB1RSTR_TIM6RST_BIT 4 -#define RCC_APB1RSTR_TIM4RST_BIT 2 -#define RCC_APB1RSTR_TIM3RST_BIT 1 -#define RCC_APB1RSTR_TIM2RST_BIT 0 - -#define RCC_APB1RSTR_DACRST (1U << RCC_APB1RSTR_DACRST_BIT) -#define RCC_APB1RSTR_PWRRST (1U << RCC_APB1RSTR_PWRRST_BIT) -#define RCC_APB1RSTR_CANRST (1U << RCC_APB1RSTR_CANRST_BIT) -#define RCC_APB1RSTR_USBRST (1U << RCC_APB1RSTR_USBRST_BIT) -#define RCC_APB1RSTR_I2C2RST (1U << RCC_APB1RSTR_I2C2RST_BIT) -#define RCC_APB1RSTR_I2C1RST (1U << RCC_APB1RSTR_I2C1RST_BIT) -#define RCC_APB1RSTR_UART5RST (1U << RCC_APB1RSTR_UART5RST_BIT) -#define RCC_APB1RSTR_UART4RST (1U << RCC_APB1RSTR_UART4RST_BIT) -#define RCC_APB1RSTR_USART3RST (1U << RCC_APB1RSTR_USART3RST_BIT) -#define RCC_APB1RSTR_USART2RST (1U << RCC_APB1RSTR_USART2RST_BIT) -#define RCC_APB1RSTR_SPI3RST (1U << RCC_APB1RSTR_SPI3RST_BIT) -#define RCC_APB1RSTR_SPI2RST (1U << RCC_APB1RSTR_SPI2RST_BIT) -#define RCC_APB1RSTR_WWDRST (1U << RCC_APB1RSTR_WWDRST_BIT) -#define RCC_APB1RSTR_TIM7RST (1U << RCC_APB1RSTR_TIM7RST_BIT) -#define RCC_APB1RSTR_TIM6RST (1U << RCC_APB1RSTR_TIM6RST_BIT) -#define RCC_APB1RSTR_TIM4RST (1U << RCC_APB1RSTR_TIM4RST_BIT) -#define RCC_APB1RSTR_TIM3RST (1U << RCC_APB1RSTR_TIM3RST_BIT) -#define RCC_APB1RSTR_TIM2RST (1U << RCC_APB1RSTR_TIM2RST_BIT) - -/* AHB peripheral clock enable register */ - -#define RCC_AHBENR_ADC34EN_BIT 29 -#define RCC_AHBENR_ADC12EN_BIT 28 -#define RCC_AHBENR_TSCEN_BIT 24 -#define RCC_AHBENR_IOPFEN_BIT 22 -#define RCC_AHBENR_IOPEEN_BIT 21 -#define RCC_AHBENR_IOPDEN_BIT 20 -#define RCC_AHBENR_IOPCEN_BIT 19 -#define RCC_AHBENR_IOPBEN_BIT 18 -#define RCC_AHBENR_IOPAEN_BIT 17 -#define RCC_AHBENR_CRCEN_BIT 6 -#define RCC_AHBENR_FLITFEN_BIT 4 -#define RCC_AHBENR_SRAMEN_BIT 2 -#define RCC_AHBENR_DMA2EN_BIT 1 -#define RCC_AHBENR_DMA1EN_BIT 0 - -#define RCC_AHBENR_ADC34EN (1U << RCC_AHBENR_ADC34EN_BIT) -#define RCC_AHBENR_ADC12EN (1U << RCC_AHBENR_ADC12EN_BIT) -#define RCC_AHBENR_TSCEN (1U << RCC_AHBENR_TSCEN_BIT) -#define RCC_AHBENR_IOPFEN (1U << RCC_AHBENR_IOPFEN_BIT) -#define RCC_AHBENR_IOPEEN (1U << RCC_AHBENR_IOPEEN_BIT) -#define RCC_AHBENR_IOPDEN (1U << RCC_AHBENR_IOPDEN_BIT) -#define RCC_AHBENR_IOPCEN (1U << RCC_AHBENR_IOPCEN_BIT) -#define RCC_AHBENR_IOPBEN (1U << RCC_AHBENR_IOPBEN_BIT) -#define RCC_AHBENR_IOPAEN (1U << RCC_AHBENR_IOPAEN_BIT) -#define RCC_AHBENR_CRCEN (1U << RCC_AHBENR_CRCEN_BIT) -#define RCC_AHBENR_FLITFEN (1U << RCC_AHBENR_FLITFEN_BIT) -#define RCC_AHBENR_SRAMEN (1U << RCC_AHBENR_SRAMEN_BIT) -#define RCC_AHBENR_DMA2EN (1U << RCC_AHBENR_DMA2EN_BIT) -#define RCC_AHBENR_DMA1EN (1U << RCC_AHBENR_DMA1EN_BIT) - -/* APB2 peripheral clock enable register */ - -#define RCC_APB2ENR_TIM17EN_BIT 18 -#define RCC_APB2ENR_TIM16EN_BIT 17 -#define RCC_APB2ENR_TIM15EN_BIT 16 -#define RCC_APB2ENR_USART1EN_BIT 14 -#define RCC_APB2ENR_TIM8EN_BIT 13 -#define RCC_APB2ENR_SPI1EN_BIT 12 -#define RCC_APB2ENR_TIM1EN_BIT 11 -#define RCC_APB2ENR_SYSCFGEN_BIT 0 - -#define RCC_APB2ENR_TIM17EN (1U << RCC_APB2ENR_TIM17EN_BIT) -#define RCC_APB2ENR_TIM16EN (1U << RCC_APB2ENR_TIM16EN_BIT) -#define RCC_APB2ENR_TIM15EN (1U << RCC_APB2ENR_TIM15EN_BIT) -#define RCC_APB2ENR_USART1EN (1U << RCC_APB2ENR_USART1EN_BIT) -#define RCC_APB2ENR_TIM8EN (1U << RCC_APB2ENR_TIM8EN_BIT) -#define RCC_APB2ENR_SPI1EN (1U << RCC_APB2ENR_SPI1EN_BIT) -#define RCC_APB2ENR_TIM1EN (1U << RCC_APB2ENR_TIM1EN_BIT) -#define RCC_APB2ENR_SYSCFGEN (1U << RCC_APB2ENR_SYSCFGEN_BIT) - -/* APB1 peripheral clock enable register */ - -#define RCC_APB1ENR_DACEN_BIT 29 -#define RCC_APB1ENR_PWREN_BIT 28 -#define RCC_APB1ENR_CANEN_BIT 25 -#define RCC_APB1ENR_USBEN_BIT 23 -#define RCC_APB1ENR_I2C2EN_BIT 22 -#define RCC_APB1ENR_I2C1EN_BIT 21 -#define RCC_APB1ENR_UART5EN_BIT 20 -#define RCC_APB1ENR_UART4EN_BIT 19 -#define RCC_APB1ENR_USART3EN_BIT 18 -#define RCC_APB1ENR_USART2EN_BIT 17 -#define RCC_APB1ENR_SPI3EN_BIT 15 -#define RCC_APB1ENR_SPI2EN_BIT 14 -#define RCC_APB1ENR_WWDEN_BIT 11 -#define RCC_APB1ENR_TIM7EN_BIT 5 -#define RCC_APB1ENR_TIM6EN_BIT 4 -#define RCC_APB1ENR_TIM4EN_BIT 2 -#define RCC_APB1ENR_TIM3EN_BIT 1 -#define RCC_APB1ENR_TIM2EN_BIT 0 - -#define RCC_APB1ENR_DACEN (1U << RCC_APB1ENR_DACEN_BIT) -#define RCC_APB1ENR_PWREN (1U << RCC_APB1ENR_PWREN_BIT) -#define RCC_APB1ENR_CANEN (1U << RCC_APB1ENR_CANEN_BIT) -#define RCC_APB1ENR_USBEN (1U << RCC_APB1ENR_USBEN_BIT) -#define RCC_APB1ENR_I2C2EN (1U << RCC_APB1ENR_I2C2EN_BIT) -#define RCC_APB1ENR_I2C1EN (1U << RCC_APB1ENR_I2C1EN_BIT) -#define RCC_APB1ENR_UART5EN (1U << RCC_APB1ENR_UART5EN_BIT) -#define RCC_APB1ENR_UART4EN (1U << RCC_APB1ENR_UART4EN_BIT) -#define RCC_APB1ENR_USART3EN (1U << RCC_APB1ENR_USART3EN_BIT) -#define RCC_APB1ENR_USART2EN (1U << RCC_APB1ENR_USART2EN_BIT) -#define RCC_APB1ENR_SPI3EN (1U << RCC_APB1ENR_SPI3EN_BIT) -#define RCC_APB1ENR_SPI2EN (1U << RCC_APB1ENR_SPI2EN_BIT) -#define RCC_APB1ENR_WWDEN (1U << RCC_APB1ENR_WWDEN_BIT) -#define RCC_APB1ENR_TIM7EN (1U << RCC_APB1ENR_TIM7EN_BIT) -#define RCC_APB1ENR_TIM6EN (1U << RCC_APB1ENR_TIM6EN_BIT) -#define RCC_APB1ENR_TIM4EN (1U << RCC_APB1ENR_TIM4EN_BIT) -#define RCC_APB1ENR_TIM3EN (1U << RCC_APB1ENR_TIM3EN_BIT) -#define RCC_APB1ENR_TIM2EN (1U << RCC_APB1ENR_TIM2EN_BIT) - -/* Backup domain control register */ - -#define RCC_BDCR_BDRST_BIT 16 -#define RCC_BDCR_RTCEN_BIT 15 -#define RCC_BDCR_LSEBYP_BIT 2 -#define RCC_BDCR_LSERDY_BIT 1 -#define RCC_BDCR_LSEON_BIT 0 - -#define RCC_BDCR_BDRST (1U << RCC_BDCR_BDRST_BIT) -#define RCC_BDCR_RTCEN (1U << RCC_BDCR_RTC_BIT) -#define RCC_BDCR_RTCSEL (0x3 << 8) -#define RCC_BDCR_RTCSEL_NONE (0x0 << 8) -#define RCC_BDCR_RTCSEL_LSE (0x1 << 8) -#define RCC_BDCR_RTCSEL_HSE (0x3 << 8) -#define RCC_BDCR_LSEBYP (1U << RCC_BDCR_LSEBYP_BIT) -#define RCC_BDCR_LSERDY (1U << RCC_BDCR_LSERDY_BIT) -#define RCC_BDCR_LSEON (1U << RCC_BDCR_LSEON_BIT) - -/* Control/status register */ - -#define RCC_CSR_LPWRRSTF_BIT 31 -#define RCC_CSR_WWDGRSTF_BIT 30 -#define RCC_CSR_IWDGRSTF_BIT 29 -#define RCC_CSR_SFTRSTF_BIT 28 -#define RCC_CSR_PORRSTF_BIT 27 -#define RCC_CSR_PINRSTF_BIT 26 -#define RCC_CSR_OBLRSTF_BIT 25 -#define RCC_CSR_RMVF_BIT 24 -#define RCC_CSR_LSIRDY_BIT 1 -#define RCC_CSR_LSION_BIT 0 - -#define RCC_CSR_LPWRRSTF (1U << RCC_CSR_LPWRRSTF_BIT) -#define RCC_CSR_WWDGRSTF (1U << RCC_CSR_WWDGRSTF_BIT) -#define RCC_CSR_IWDGRSTF (1U << RCC_CSR_IWDGRSTF_BIT) -#define RCC_CSR_SFTRSTF (1U << RCC_CSR_SFTRSTF_BIT) -#define RCC_CSR_PORRSTF (1U << RCC_CSR_PORRSTF_BIT) -#define RCC_CSR_PINRSTF (1U << RCC_CSR_PINRSTF_BIT) -#define RCC_CSR_OBLRSTF (1U << RCC_CSR_OBLRSTF_BIT) -#define RCC_CSR_RMVF (1U << RCC_CSR_RMVF_BIT) -#define RCC_CSR_LSIRDY (1U << RCC_CSR_LSIRDY_BIT) -#define RCC_CSR_LSION (1U << RCC_CSR_LSION_BIT) - -/* AHB peripheral reset register */ - -#define RCC_AHBRSTR_ADC34RST_BIT 29 -#define RCC_AHBRSTR_ADC12RST_BIT 28 -#define RCC_AHBRSTR_TSCRST_BIT 24 -#define RCC_AHBRSTR_IOPFRST_BIT 22 -#define RCC_AHBRSTR_IOPERST_BIT 21 -#define RCC_AHBRSTR_IOPDRST_BIT 20 -#define RCC_AHBRSTR_IOPCRST_BIT 19 -#define RCC_AHBRSTR_IOPBRST_BIT 18 -#define RCC_AHBRSTR_IOPARST_BIT 17 - -#define RCC_AHBRSTR_ADC34RST (1U << RCC_AHBRSTR_ADC34RST_BIT) -#define RCC_AHBRSTR_ADC12RST (1U << RCC_AHBRSTR_ADC12RST_BIT) -#define RCC_AHBRSTR_TSCRST (1U << RCC_AHBRSTR_TSCRST_BIT) -#define RCC_AHBRSTR_IOPFRST (1U << RCC_AHBRSTR_IOPFRST_BIT) -#define RCC_AHBRSTR_IOPERST (1U << RCC_AHBRSTR_IOPERST_BIT) -#define RCC_AHBRSTR_IOPDRST (1U << RCC_AHBRSTR_IOPDRST_BIT) -#define RCC_AHBRSTR_IOPCRST (1U << RCC_AHBRSTR_IOPCRST_BIT) -#define RCC_AHBRSTR_IOPBRST (1U << RCC_AHBRSTR_IOPBRST_BIT) -#define RCC_AHBRSTR_IOPARST (1U << RCC_AHBRSTR_IOPARST_BIT) - -/* Clock configuration register 2 */ - -#define RCC_CFGR2_ADC34PRES_SHIFT 9 -#define RCC_CFGR2_ADC12PRES_SHIFT 4 - -#define RCC_CFGR2_ADC34PRES (0x1f << RCC_CFGR2_ADC34PRES_SHIFT) -#define RCC_CFGR2_ADC12PRES (0x1f << RCC_CFGR2_ADC12PRES_SHIFT) -#define RCC_CFGR2_PREDIV 0xf - -/* Clock configuration register 3 */ //TODO make clock sources configurable - -#define RCC_CFGR3_TIM8SW_BIT 9 -#define RCC_CFGR3_TIM1SW_BIT 8 -#define RCC_CFGR3_I2C2SW_BIT 5 -#define RCC_CFGR3_I2C1SW_BIT 4 - -#define RCC_CFGR3_UART5SW (0x3 << 22) -#define RCC_CFGR3_UART4SW (0x3 << 20) -#define RCC_CFGR3_USART3SW (0x3 << 18) -#define RCC_CFGR3_USART2SW (0x3 << 16) -#define RCC_CFGR_TIM8SW (1U << RCC_CFGR3_TIM8SW_BIT) -#define RCC_CFGR_TIM1SW (1U << RCC_CFGR3_TIM1SW_BIT) -#define RCC_CFGR_I2C2SW (1U << RCC_CFGR3_I2C2SW_BIT) -#define RCC_CFGR_I2C1SW (1U << RCC_CFGR3_I2C1SW_BIT) -#define RCC_CFGR3_USART1SW 0x3 - -/* - * libmaple-mandated enumeration types. - */ - -/** - * @brief STM32F3 rcc_clk_id. - */ -typedef enum rcc_clk_id { - RCC_GPIOA, - RCC_GPIOB, - RCC_GPIOC, - RCC_GPIOD, - RCC_GPIOE, - RCC_GPIOF, - - RCC_ADC12, - RCC_ADC34, - - RCC_DAC, - - RCC_DMA1, - RCC_DMA2, - - RCC_I2C1, - RCC_I2C2, - - RCC_SPI1, - RCC_SPI2, - RCC_SPI3, - - RCC_USART1, - RCC_USART2, - RCC_USART3, - RCC_UART4, - RCC_UART5, - - RCC_TIMER1, - RCC_TIMER2, - RCC_TIMER3, - RCC_TIMER4, - RCC_TIMER5, - RCC_TIMER6, - RCC_TIMER7, - RCC_TIMER8, - RCC_TIMER9, - RCC_TIMER10, - RCC_TIMER11, - RCC_TIMER12, - RCC_TIMER13, - RCC_TIMER14, - RCC_TIMER15, - RCC_TIMER16, - RCC_TIMER17, - - RCC_SYSCFG, - RCC_CRC, - RCC_FLITF, - RCC_PWR, - RCC_SRAM, - RCC_USB, -} rcc_clk_id; - -/** - * @brief STM32F3 PLL clock sources. - * @see rcc_configure_pll() - */ -typedef enum rcc_pllsrc { - RCC_PLLSRC_HSE = (0x1 << RCC_CFGR_PLLSRC_BIT), - RCC_PLLSRC_HSI_DIV_2 = (0x0 << RCC_CFGR_PLLSRC_BIT) -} rcc_pllsrc; - -/** - * @brief STM32F3 clock domains. - * @see rcc_dev_clk() - */ -typedef enum rcc_clk_domain { - RCC_APB1, - RCC_APB2, - RCC_AHB -} rcc_clk_domain; - -/** - * @brief STM32F3 Prescaler identifiers - * @see rcc_set_prescaler() - */ -typedef enum rcc_prescaler { - RCC_PRESCALER_AHB, - RCC_PRESCALER_APB1, - RCC_PRESCALER_APB2, - RCC_PRESCALER_USB, -} rcc_prescaler; - -/** - * @brief STM32F3 ADC prescaler dividers - * @see rcc_set_prescaler() - */ -typedef enum rcc_adc_divider { - RCC_ADCPRE_PCLK_DISABLED = 0x00, - RCC_ADCPRE_PCLK_DIV_1 = 0x10, - RCC_ADCPRE_PCLK_DIV_2 = 0x11, - RCC_ADCPRE_PCLK_DIV_4 = 0x12, - RCC_ADCPRE_PCLK_DIV_6 = 0x13, - RCC_ADCPRE_PCLK_DIV_8 = 0x14, - RCC_ADCPRE_PCLK_DIV_10 = 0x15, - RCC_ADCPRE_PCLK_DIV_12 = 0x16, - RCC_ADCPRE_PCLK_DIV_16 = 0x17, - RCC_ADCPRE_PCLK_DIV_32 = 0x18, - RCC_ADCPRE_PCLK_DIV_64 = 0x19, - RCC_ADCPRE_PCLK_DIV_128 = 0x1A, - RCC_ADCPRE_PCLK_DIV_256 = 0x1B, -} rcc_adc_divider; - -/** - * @brief STM32F3 PREDIV prescaler dividers - * @see rcc_set_prescaler() - */ -typedef enum rcc_prediv_divider { - RCC_PREDIV_PCLK_DIV_1 = 0x0, - RCC_PREDIV_PCLK_DIV_2 = 0x1, - RCC_PREDIV_PCLK_DIV_3 = 0x2, - RCC_PREDIV_PCLK_DIV_4 = 0x3, - RCC_PREDIV_PCLK_DIV_5 = 0x4, - RCC_PREDIV_PCLK_DIV_6 = 0x5, - RCC_PREDIV_PCLK_DIV_7 = 0x6, - RCC_PREDIV_PCLK_DIV_8 = 0x7, - RCC_PREDIV_PCLK_DIV_9 = 0x8, - RCC_PREDIV_PCLK_DIV_10 = 0x9, - RCC_PREDIV_PCLK_DIV_11 = 0xA, - RCC_PREDIV_PCLK_DIV_12 = 0xB, - RCC_PREDIV_PCLK_DIV_13 = 0xC, - RCC_PREDIV_PCLK_DIV_14 = 0xD, - RCC_PREDIV_PCLK_DIV_15 = 0xE, - RCC_PREDIV_PCLK_DIV_16 = 0xF, -} rcc_prediv_divider; - -/** - * @brief STM32F3 APB1 prescaler dividers - * @see rcc_set_prescaler() - */ -typedef enum rcc_apb1_divider { - RCC_APB1_HCLK_DIV_1 = 0x0 << RCC_CFGR_PPRE1_BIT, - RCC_APB1_HCLK_DIV_2 = 0x4 << RCC_CFGR_PPRE1_BIT, - RCC_APB1_HCLK_DIV_4 = 0x5 << RCC_CFGR_PPRE1_BIT, - RCC_APB1_HCLK_DIV_8 = 0x6 << RCC_CFGR_PPRE1_BIT, - RCC_APB1_HCLK_DIV_16 = 0x7 << RCC_CFGR_PPRE1_BIT, -} rcc_apb1_divider; - -/** - * @brief STM32F3 APB2 prescaler dividers - * @see rcc_set_prescaler() - */ -typedef enum rcc_apb2_divider { - RCC_APB2_HCLK_DIV_1 = 0x0 << RCC_CFGR_PPRE2_BIT, - RCC_APB2_HCLK_DIV_2 = 0x4 << RCC_CFGR_PPRE2_BIT, - RCC_APB2_HCLK_DIV_4 = 0x5 << RCC_CFGR_PPRE2_BIT, - RCC_APB2_HCLK_DIV_8 = 0x6 << RCC_CFGR_PPRE2_BIT, - RCC_APB2_HCLK_DIV_16 = 0x7 << RCC_CFGR_PPRE2_BIT, -} rcc_apb2_divider; - -/** - * @brief STM32F3 AHB prescaler dividers - * @see rcc_set_prescaler() - */ -typedef enum rcc_ahb_divider { - RCC_AHB_SYSCLK_DIV_1 = 0x0 << RCC_CFGR_HPRE_BIT, - RCC_AHB_SYSCLK_DIV_2 = 0x8 << RCC_CFGR_HPRE_BIT, - RCC_AHB_SYSCLK_DIV_4 = 0x9 << RCC_CFGR_HPRE_BIT, - RCC_AHB_SYSCLK_DIV_8 = 0xA << RCC_CFGR_HPRE_BIT, - RCC_AHB_SYSCLK_DIV_16 = 0xB << RCC_CFGR_HPRE_BIT, - RCC_AHB_SYSCLK_DIV_32 = 0xC << RCC_CFGR_HPRE_BIT, - RCC_AHB_SYSCLK_DIV_64 = 0xD << RCC_CFGR_HPRE_BIT, - RCC_AHB_SYSCLK_DIV_128 = 0xD << RCC_CFGR_HPRE_BIT, - RCC_AHB_SYSCLK_DIV_256 = 0xE << RCC_CFGR_HPRE_BIT, - RCC_AHB_SYSCLK_DIV_512 = 0xF << RCC_CFGR_HPRE_BIT, -} rcc_ahb_divider; - -/** - * @brief STM32F3 clock sources. - */ -typedef enum rcc_clk { - RCC_CLK_PLL = (uint16)((offsetof(struct rcc_reg_map, CR) << 8) | - RCC_CR_PLLON_BIT), /**< Main PLL, clocked by - HSI or HSE. */ - RCC_CLK_HSE = (uint16)((offsetof(struct rcc_reg_map, CR) << 8) | - RCC_CR_HSEON_BIT), /**< High speed external. */ - RCC_CLK_HSI = (uint16)((offsetof(struct rcc_reg_map, CR) << 8) | - RCC_CR_HSION_BIT), /**< High speed internal. */ - RCC_CLK_LSE = (uint16)((offsetof(struct rcc_reg_map, BDCR) << 8) | - RCC_BDCR_LSEON_BIT), /**< Low-speed external - * (32.768 KHz). */ - RCC_CLK_LSI = (uint16)((offsetof(struct rcc_reg_map, CSR) << 8) | - RCC_CSR_LSION_BIT), /**< Low-speed internal - * (approximately 32 KHz). */ -} rcc_clk; - -/** - * @brief STM32F3 PLL multipliers. - */ -typedef enum rcc_pll_multiplier { - RCC_PLLMUL_2 = (0x0 << RCC_CFGR_PLLMUL_BIT), - RCC_PLLMUL_3 = (0x1 << RCC_CFGR_PLLMUL_BIT), - RCC_PLLMUL_4 = (0x2 << RCC_CFGR_PLLMUL_BIT), - RCC_PLLMUL_5 = (0x3 << RCC_CFGR_PLLMUL_BIT), - RCC_PLLMUL_6 = (0x4 << RCC_CFGR_PLLMUL_BIT), - RCC_PLLMUL_7 = (0x5 << RCC_CFGR_PLLMUL_BIT), - RCC_PLLMUL_8 = (0x6 << RCC_CFGR_PLLMUL_BIT), - RCC_PLLMUL_9 = (0x7 << RCC_CFGR_PLLMUL_BIT), - RCC_PLLMUL_10 = (0x8 << RCC_CFGR_PLLMUL_BIT), - RCC_PLLMUL_11 = (0x9 << RCC_CFGR_PLLMUL_BIT), - RCC_PLLMUL_12 = (0xA << RCC_CFGR_PLLMUL_BIT), - RCC_PLLMUL_13 = (0xB << RCC_CFGR_PLLMUL_BIT), - RCC_PLLMUL_14 = (0xC << RCC_CFGR_PLLMUL_BIT), - RCC_PLLMUL_15 = (0xD << RCC_CFGR_PLLMUL_BIT), - RCC_PLLMUL_16 = (0xE << RCC_CFGR_PLLMUL_BIT), -} rcc_pll_multiplier; - -/* FIXME [0.0.13] Just have data point to an rcc_pll_multiplier! */ - -/** - * @brief STM32F3 PLL configuration values. - * Point to one of these with the "data" field in a struct rcc_pll_cfg. - * @see struct rcc_pll_cfg. - */ -typedef struct stm32f3_rcc_pll_data { - rcc_pll_multiplier pll_mul; /**< PLL multiplication factor. */ - rcc_prediv_divider pclk_prediv; /**< PCLK predivider. */ -} stm32f3_rcc_pll_data; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/simd.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/simd.h deleted file mode 100644 index 8325d5d..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/simd.h +++ /dev/null @@ -1,109 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -*****************************************************************************/ - -/** - * @file libmaple/include/libmaple/simd.h - * @author F3-port by Hanspeter Portner - * @brief Convenience macros for the digital signal processing (DSP) - * instruction set of the ARM Cortex M4 microcontroller. - */ - -#ifndef _LIBMAPLE_DSP_H_ -#define _LIBMAPLE_DSP_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -#define DSP3(ID, A, B, C) \ -({ \ - uint32_t X; \ - asm volatile (ID" %[res], %[val1], %[val2], %[val3]" \ - : [res]"=r" (X) \ - : [val1]"r" (A), [val2]"r" (B), [val3]"r" (C) \ - ); \ - (uint32_t)X; \ -}) - -#define DSP2(ID, A, B) \ -({ \ - uint32_t X; \ - asm volatile (ID" %[res], %[val1], %[val2]" \ - : [res]"=r" (X) \ - : [val1]"r" (A), [val2]"r" (B) \ - );\ - (uint32_t)X; \ -}) - -#define DSP1(ID, A) \ -({ \ - uint32_t X; \ - asm volatile (ID" %[res], %[val1]" \ - : [res]"=r" (X) \ - : [val1]"r" (A) \ - ); \ - (uint32_t)X; \ -}) - -/* General data processing instructions */ -#define __rev16(A) DSP1("REV16", A) - -/* SIMD instructions (single instruction multiple data) */ -#define __sadd16(A, B) DSP2("SADD16", A, B) -#define __shadd16(A, B) DSP2("SHADD16", A, B) -#define __ssub16(A, B) DSP2("SSUB16", A, B) -#define __shsub16(A, B) DSP2("SHSUB16", A, B) -#define __uadd16(A, B) DSP2("UADD16", A, B) -#define __uhadd16(A, B) DSP2("UHADD16", A, B) -#define __usub16(A, B) DSP2("USUB16", A, B) -#define __uhsub16(A, B) DSP2("UHSUB16", A, B) - -#define __sadd8(A, B) DSP2("SADD8", A, B) -#define __shadd8(A, B) DSP2("SHADD8", A, B) -#define __ssub8(A, B) DSP2("SSUB8", A, B) -#define __shsub8(A, B) DSP2("SHSUB8", A, B) -#define __uadd8(A, B) DSP2("UADD8", A, B) -#define __uhadd8(A, B) DSP2("UHADD8", A, B) -#define __usub8(A, B) DSP2("USUB8", A, B) -#define __uhsub8(A, B) DSP2("UHSUB8", A, B) - -#define __sasx(A, B) DSP2("SASX", A, B) -#define __ssax(A, B) DSP2("SSAX", A, B) -#define __shasx(A, B) DSP2("SHASX", A, B) -#define __shsax(A, B) DSP2("SHSAX", A, B) -#define __uasx(A, B) DSP2("UASX", A, B) -#define __usax(A, B) DSP2("USAX", A, B) -#define __uhasx(A, B) DSP2("UHASX", A, B) -#define __uhsax(A, B) DSP2("UHSAX", A, B) - -#define __usad8(A, B) DSP2("USAD8", A, B) -#define __usada8(A, B, C) DSP3("USADA8", A, B, C) - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/spi.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/spi.h deleted file mode 100644 index 5b1de09..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/spi.h +++ /dev/null @@ -1,178 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2011, 2012 LeafLabs, LLC. - * Copyright (c) 2010 Perry Hung. - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/stm32f3/include/series/spi.h - * @author Marti Bolivar , - * F3-port by Hanspeter Portner - * @brief STM32F3 SPI/I2S series header. - */ - -#ifndef _LIBMAPLE_STM32F3_SPI_H_ -#define _LIBMAPLE_STM32F3_SPI_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Register map base pointers - */ - -struct spi_reg_map; - -#define SPI1_BASE ((struct spi_reg_map*)0x40013000) -#define SPI2_BASE ((struct spi_reg_map*)0x40003800) -#define SPI3_BASE ((struct spi_reg_map*)0x40003C00) - -/* - * F3 additional registry items - */ - -/* Control register 1 */ -/* CRC length bitfield in F3 overwrites the data length field in F1/F2 */ -#define SPI_CR1_CRCL_BIT 11 - -#define SPI_CR1_CRCL (1U << SPI_CR1_CRCL_BIT) - -/* Control register 2 */ -#define SPI_CR2_LDMA_TX_BIT 14 -#define SPI_CR2_LDMA_RX_BIT 13 -#define SPI_CR2_FRXTH_BIT 12 -#define SPI_CR2_DS_SHIFT 8 -#define SPI_CR2_FRF_BIT 4 -#define SPI_CR2_NSSP_BIT 3 - -#define SPI_CR2_LDMA_TX (1U << SPI_CR2_LDMA_TX_BIT) -#define SPI_CR2_LDMA_RX (1U << SPI_CR2_LDMA_RX_BIT) -#define SPI_CR2_FRXTH (1U << SPI_CR2_FRXTH_BIT) -#define SPI_CR2_DS (0x7 << SPI_CR2_DS_SHIFT) -#define SPI_CR2_FRF (1U << SPI_CR2_FRF_BIT) -#define SPI_CR2_NSSP (1U << SPI_CR2_NSSP_BIT) - -/* Status register */ -#define SPI_SR_FTLVL_SHIFT 11 -#define SPI_SR_FRLVL_SHIFT 9 -#define SPI_SR_FRE_BIT 8 - -#define SPI_SR_FTLVL (0x3 << SPI_SR_FTLVL_SHIFT) -#define SPI_SR_FRLVL (0x3 << SPI_SR_FRLVL_SHIFT) -#define SPI_SR_FRE (1U << SPI_SR_FRE_SHIFT) - -/** - * @brief TODO document me - */ -typedef enum spi_crc_size { - SPI_CRC_SIZE_8_BIT = (0x0 << SPI_CR1_CRCL_BIT), - SPI_CRC_SIZE_16_BIT = (0x1 << SPI_CR1_CRCL_BIT), -} spi_crc_size; - -/** - * @brief TODO document me - */ -typedef enum spi_frame_format { - SPI_FRAME_FORMAT_MOTOROLA = (0x0 << SPI_CR2_FRF_BIT), - SPI_FRAME_FORMAT_TI = (0x1 << SPI_CR2_FRF_BIT), -} spi_frame_format; - -/** - * @brief TODO document me - */ -typedef enum spi_ds { - SPI_DATA_SIZE_DEFAULT = (0x0 << SPI_CR2_DS_SHIFT), - SPI_DATA_SIZE_4_BIT = (0x3 << SPI_CR2_DS_SHIFT), - SPI_DATA_SIZE_5_BIT = (0x4 << SPI_CR2_DS_SHIFT), - SPI_DATA_SIZE_6_BIT = (0x5 << SPI_CR2_DS_SHIFT), - SPI_DATA_SIZE_7_BIT = (0x6 << SPI_CR2_DS_SHIFT), - SPI_DATA_SIZE_8_BIT = (0x7 << SPI_CR2_DS_SHIFT), - SPI_DATA_SIZE_9_BIT = (0x8 << SPI_CR2_DS_SHIFT), - SPI_DATA_SIZE_10_BIT = (0x9 << SPI_CR2_DS_SHIFT), - SPI_DATA_SIZE_11_BIT = (0xA << SPI_CR2_DS_SHIFT), - SPI_DATA_SIZE_12_BIT = (0xB << SPI_CR2_DS_SHIFT), - SPI_DATA_SIZE_13_BIT = (0xC << SPI_CR2_DS_SHIFT), - SPI_DATA_SIZE_14_BIT = (0xD << SPI_CR2_DS_SHIFT), - SPI_DATA_SIZE_15_BIT = (0xE << SPI_CR2_DS_SHIFT), - SPI_DATA_SIZE_16_BIT = (0xF << SPI_CR2_DS_SHIFT), -} spi_ds; - -/** - * @brief TODO document me - */ -typedef enum spi_fifo_transmission_level { - SPI_FIFO_TRANSMISSION_LEVEL_EMPTY = (0x0 << SPI_SR_FTLVL_SHIFT), - SPI_FIFO_TRANSMISSION_LEVEL_QUARTER = (0x1 << SPI_SR_FTLVL_SHIFT), - SPI_FIFO_TRANSMISSION_LEVEL_HALF = (0x2 << SPI_SR_FTLVL_SHIFT), - SPI_FIFO_TRANSMISSION_LEVEL_FULL = (0x3 << SPI_SR_FTLVL_SHIFT), -} spi_fifo_transmission_level; - -/** - * @brief TODO document me - */ -typedef enum spi_fifo_reception_level { - SPI_FIFO_RECEPTION_LEVEL_EMPTY = (0x0 << SPI_SR_FRLVL_SHIFT), - SPI_FIFO_RECEPTION_LEVEL_QUARTER = (0x1 << SPI_SR_FRLVL_SHIFT), - SPI_FIFO_RECEPTION_LEVEL_HALF = (0x2 << SPI_SR_FRLVL_SHIFT), - SPI_FIFO_RECEPTION_LEVEL_FULL = (0x3 << SPI_SR_FRLVL_SHIFT), -} spi_fifo_reception_level; - -/* - * Device pointers - */ - -struct spi_dev; - -extern struct spi_dev *SPI1; -extern struct spi_dev *SPI2; -extern struct spi_dev *SPI3; - -/* - * Routines - */ - -struct gpio_dev; -extern void spi_config_gpios(struct spi_dev*, uint8, - struct gpio_dev*, uint8, - struct gpio_dev*, uint8, uint8, uint8); - -/** - * @brief Set the data size of the given SPI device. - * - * @param dev SPI device - * @param ds SPI data size - * @see spi_ds - * @see spi_reconfigure() - */ -extern void spi_data_size(struct spi_dev *, spi_ds); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/stm32.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/stm32.h deleted file mode 100644 index c40627c..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/stm32.h +++ /dev/null @@ -1,238 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010, 2011 LeafLabs, LLC. - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/stm32f1/include/series/stm32.h - * @author F3-port by Hanspeter Portner - * @brief STM32F3 chip- and series-specific definitions. - */ - -#ifndef _LIBMAPLE_STM32F3_H_ -#define _LIBMAPLE_STM32F3_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#define __CCM__ __attribute__((section(".CCM"))) - -#define STM32_MCU_SERIES STM32_SERIES_F3 - -/* The STM32F3 series is subdivided into "lines". libmaple currently - * officially supports STM32F303 performance line MCUs (see the - * MCU-specific value section below). - * - * You can use these F3 line defines if porting libmaple to support - * MCUs on other lines. */ -/** STM32F3 302 line (STM32F302 MCUs). */ -#define STM32_F3_LINE_302 0 -/** STM32F3 303 line (STM32F303 MCUs). */ -#define STM32_F3_LINE_303 1 - -/* - * MCU-specific values. - * - * You can use this section to override any of the below settings on a - * per-MCU basis. For example, if your MCU has different STM32_PCLK1 - * or STM32_PCLK2 values, you can set them here and the values for - * STM32F303 microcontrollers set below won't take effect. - */ - -#if defined(MCU_STM32F302CB) -# define STM32_F3_LINE STM32_F3_LINE_302 -# define STM32_NR_GPIO_PORTS 20 -# define STM32_SRAM_END ((void*)0x20008000) -# define STM32_MEDIUM_DENSITY // 48pin package - -#elif defined(MCU_STM32F302RB) -# define STM32_F3_LINE STM32_F3_LINE_302 -# define STM32_NR_GPIO_PORTS 27 -# define STM32_SRAM_END ((void*)0x20008000) -# define STM32_HIGH_DENSITY // 64pin package - -#elif defined(MCU_STM32F302VB) -# define STM32_F3_LINE STM32_F3_LINE_302 -# define STM32_NR_GPIO_PORTS 45 -# define STM32_SRAM_END ((void*)0x20008000) -# define STM32_XL_DENSITY // 100pin package - -#elif defined(MCU_STM32F302CC) -# define STM32_F3_LINE STM32_F3_LINE_302 -# define STM32_NR_GPIO_PORTS 20 -# define STM32_SRAM_END ((void*)0x2000A000) -# define STM32_MEDIUM_DENSITY // 48pin package - -#elif defined(MCU_STM32F302RC) -# define STM32_F3_LINE STM32_F3_LINE_302 -# define STM32_NR_GPIO_PORTS 27 -# define STM32_SRAM_END ((void*)0x2000A000) -# define STM32_HIGH_DENSITY // 64pin package - -#elif defined(MCU_STM32F302VC) -# define STM32_F3_LINE STM32_F3_LINE_302 -# define STM32_NR_GPIO_PORTS 45 -# define STM32_SRAM_END ((void*)0x2000A000) -# define STM32_XL_DENSITY // 100pin package - -#elif defined(MCU_STM32F303CB) -# define STM32_F3_LINE STM32_F3_LINE_303 -# define STM32_NR_GPIO_PORTS 20 -# define STM32_SRAM_END ((void*)0x2000A000) -# define STM32_MEDIUM_DENSITY // 48pin package - -#elif defined(MCU_STM32F303RB) -# define STM32_F3_LINE STM32_F3_LINE_303 -# define STM32_NR_GPIO_PORTS 27 -# define STM32_SRAM_END ((void*)0x2000A000) -# define STM32_HIGH_DENSITY // 64pin package - -#elif defined(MCU_STM32F303VB) -# define STM32_F3_LINE STM32_F3_LINE_303 -# define STM32_NR_GPIO_PORTS 45 -# define STM32_SRAM_END ((void*)0x2000A000) -# define STM32_XL_DENSITY // 100pin package - -#elif defined(MCU_STM32F303CC) -# define STM32_F3_LINE STM32_F3_LINE_303 -# define STM32_NR_GPIO_PORTS 20 -# define STM32_SRAM_END ((void*)0x2000C000) -# define STM32_MEDIUM_DENSITY // 48pin package - -#elif defined(MCU_STM32F303RC) -# define STM32_F3_LINE STM32_F3_LINE_303 -# define STM32_NR_GPIO_PORTS 27 -# define STM32_SRAM_END ((void*)0x2000C000) -# define STM32_HIGH_DENSITY // 64pin package - -#elif defined(MCU_STM32F303VC) -# define STM32_F3_LINE STM32_F3_LINE_303 -# define STM32_NR_GPIO_PORTS 45 -# define STM32_SRAM_END ((void*)0x2000C000) -// # define STM32_XL_DENSITY // 100pin package - -#else -#warning "Unsupported or unspecified STM32F3 MCU." -#endif - -/* - * Derived values. - */ - -#if STM32_F3_LINE == STM32_F3_LINE_302 -# define STM32_HAVE_USB 1 - -# ifdef STM32_MEDIUM_DENSITY -# define STM32_NR_INTERRUPTS 82 -# define STM32_TIMER_MASK 0b111000000001011110 -# define STM32_HAVE_FSMC 0 -# define STM32_HAVE_DAC 1 -# elif defined(STM32_HIGH_DENSITY) -# define STM32_NR_INTERRUPTS 82 -# define STM32_TIMER_MASK 0b111000000001011110 -# define STM32_HAVE_FSMC 0 -# define STM32_HAVE_DAC 1 -# elif defined(STM32_XL_DENSITY) -# define STM32_NR_INTERRUPTS 82 -# define STM32_TIMER_MASK 0b111000000001011110 -# define STM32_HAVE_FSMC 0 -# define STM32_HAVE_DAC 1 -# endif - -#elif STM32_F3_LINE == STM32_F3_LINE_303 -# define STM32_HAVE_USB 1 - -# ifdef STM32_MEDIUM_DENSITY -# define STM32_NR_INTERRUPTS 82 -# define STM32_TIMER_MASK 0b111000000111011110 -# define STM32_HAVE_FSMC 0 -# define STM32_HAVE_DAC 1 -# elif defined(STM32_HIGH_DENSITY) -# define STM32_NR_INTERRUPTS 82 -# define STM32_TIMER_MASK 0b111000000111011110 -# define STM32_HAVE_FSMC 0 -# define STM32_HAVE_DAC 1 -# elif defined(STM32_XL_DENSITY) -# define STM32_NR_INTERRUPTS 82 -# define STM32_TIMER_MASK 0b111000000111011110 -# define STM32_HAVE_FSMC 0 -# define STM32_HAVE_DAC 1 -# endif - -#endif - -/* - * Clock configuration. - * - * You can patch these for your line, MCU, clock configuration, - * etc. here or by setting cflags when compiling libmaple. - */ - -#ifndef STM32_PCLK1 -#define STM32_PCLK1 36000000U -#endif - -#ifndef STM32_PCLK2 -#define STM32_PCLK2 72000000U -#endif - -#ifndef STM32_DELAY_US_MULT -#define STM32_DELAY_US_MULT 12 /* FIXME: value is incorrect. */ -#endif - -/* - * Sanity checks. - * - * Make sure we have the F3-specific defines we need. - * will check that we've defined everything it needs. - */ - -#if !defined(STM32_F3_LINE) -#error "Bad STM32F3 configuration. Check STM32F3 header." -#endif - -/* - * Doxygen - */ - -#ifdef __DOXYGEN__ - -/** - * @brief STM32 line value for the STM32F3 MCU being targeted. - * - * At time of writing, allowed values are: STM32_F3_LINE_303, - * STM32_F3_LINE_302. This set of values may expand as libmaple adds - * support for more STM32F3 lines. - */ -#define STM32_F3_LINE - -#endif /* __DOXYGEN__ */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/syscfg.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/syscfg.h deleted file mode 100644 index 2565290..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/syscfg.h +++ /dev/null @@ -1,138 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/stm32f3/include/series/syscfg.h - * @author F3-port by Hanspeter Portner - * @brief System configuration controller (SYSCFG) - */ - -#ifndef _LIBMAPLE_STM32F3_SYSCFG_H_ -#define _LIBMAPLE_STM32F3_SYSCFG_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/* - * Register map and base pointer - */ - -/** - * @brief SYSCFG register map type. - */ -typedef struct syscfg_reg_map { - __IO uint32 CFGR1; /**< Configuration register 1*/ - __IO uint32 RCR; /**< CCM SRAM protection register */ - __IO uint32 EXTICR[4]; /**< External Interrupt configuration register */ - __IO uint32 CFGR2; /**< Configuration register 2 */ -} syscfg_reg_map; - -/** SYSCFG register map base pointer */ -#define SYSCFG_BASE ((struct syscfg_reg_map*)0x40010000) - -/* - * Register bit definitions - */ - -/* Configuration register 1 */ - -#define SYSCFG_CFGR1_FPU_IE_SHIFT 26 -#define SYSCFG_CFGR1_ENCODE_MODE_SHIFT 22 -#define SYSCFG_CFGR1_I2C2_FM_PLUS_BIT 21 -#define SYSCFG_CFGR1_I2C1_FM_PLUS_BIT 20 -#define SYSCFG_CFGR1_I2C_PB9_FM_PLUS_BIT 19 -#define SYSCFG_CFGR1_I2C_PB8_FM_PLUS_BIT 18 -#define SYSCFG_CFGR1_I2C_PB7_FM_PLUS_BIT 17 -#define SYSCFG_CFGR1_I2C_PB6_FM_PLUS_BIT 16 -#define SYSCFG_CFGR1_TIM7_DAC2_DMA_RMP_BIT 14 -#define SYSCFG_CFGR1_TIM6_DAC1_DMA_RMP_BIT 13 -#define SYSCFG_CFGR1_TIM17_DMA_RMP_BIT 12 -#define SYSCFG_CFGR1_TIM16_DMA_RMP_BIT 11 -#define SYSCFG_CFGR1_ADC24_DMA_RMP_BIT 8 -#define SYSCFG_CFGR1_DAC_TRIG_RMP_BIT 7 -#define SYSCFG_CFGR1_TIM1_ITR3_RMP_BIT 6 -#define SYSCFG_CFGR1_USB_IT_RMP_BIT 5 - -//FIXME FPU_IE -//FIXME ENCODE_MODE -#define SYSCFG_CFGR1_I2C2_FM_PLUS (1U << SYSCFG_CFGR1_I2C2_FM_PLUS_BIT) -#define SYSCFG_CFGR1_I2C1_FM_PLUS (1U << SYSCFG_CFGR1_I2C1_FM_PLUS_BIT) -#define SYSCFG_CFGR1_I2C1_PB9_FM_PLUS (1U << SYSCFG_CFGR1_I2C1_PB9_FM_PLUS_BIT) -#define SYSCFG_CFGR1_I2C1_PB8_FM_PLUS (1U << SYSCFG_CFGR1_I2C1_PB8_FM_PLUS_BIT) -#define SYSCFG_CFGR1_I2C1_PB7_FM_PLUS (1U << SYSCFG_CFGR1_I2C1_PB7_FM_PLUS_BIT) -#define SYSCFG_CFGR1_I2C1_PB6_FM_PLUS (1U << SYSCFG_CFGR1_I2C1_PB6_FM_PLUS_BIT) -#define SYSCFG_CFGR1_TIM7_DAC2_DMA_RMP (1U << SYSCFG_CFGR1_TIM7_DAC2_DMA_RMP_BIT) -#define SYSCFG_CFGR1_TIM6_DAC1_DMA_RMP (1U << SYSCFG_CFGR1_TIM6_DAC1_DMA_RMP_BIT) -#define SYSCFG_CFGR1_TIM17_DMA_RMP (1U << SYSCFG_CFGR1_TIM17_DMA_RMP_BIT) -#define SYSCFG_CFGR1_TIM16_DMA_RMP (1U << SYSCFG_CFGR1_TIM16_DMA_RMP_BIT) -#define SYSCFG_CFGR1_ADC23_DMA_RMP (1U << SYSCFG_CFGR1_ADC23_DMA_RMP_BIT) -#define SYSCFG_CFGR1_DAC_TRIG_RMP (1U << SYSCFG_CFGR1_DAC_TRIG_RMP_BIT) -#define SYSCFG_CFGR1_TIM1_ITR3_RMP (1U << SYSCFG_CFGR1_TIM1_ITR3_RMP_BIT) -#define SYSCFG_CFGR1_USB_IT_RMP (1U << SYSCFG_CFGR1_USB_IT_RMP_BIT) -#define SYSCFG_CFGR1_MEM_MODE 0X3 - -/* CCM SRAM protection register */ - -#define SYSCFG_RCR_PAGE7_WP_BIT 7 -#define SYSCFG_RCR_PAGE6_WP_BIT 6 -#define SYSCFG_RCR_PAGE5_WP_BIT 5 -#define SYSCFG_RCR_PAGE4_WP_BIT 4 -#define SYSCFG_RCR_PAGE3_WP_BIT 3 -#define SYSCFG_RCR_PAGE2_WP_BIT 2 -#define SYSCFG_RCR_PAGE1_WP_BIT 1 -#define SYSCFG_RCR_PAGE0_WP_BIT 0 - -#define SYSCFG_RCR_PAGE_7 (1U << SYSCFG_RCR_PAGE7_WP_BIT) -#define SYSCFG_RCR_PAGE_6 (1U << SYSCFG_RCR_PAGE6_WP_BIT) -#define SYSCFG_RCR_PAGE_5 (1U << SYSCFG_RCR_PAGE5_WP_BIT) -#define SYSCFG_RCR_PAGE_4 (1U << SYSCFG_RCR_PAGE4_WP_BIT) -#define SYSCFG_RCR_PAGE_3 (1U << SYSCFG_RCR_PAGE3_WP_BIT) -#define SYSCFG_RCR_PAGE_2 (1U << SYSCFG_RCR_PAGE2_WP_BIT) -#define SYSCFG_RCR_PAGE_1 (1U << SYSCFG_RCR_PAGE1_WP_BIT) -#define SYSCFG_RCR_PAGE_0 (1U << SYSCFG_RCR_PAGE0_WP_BIT) - -/* Configuration register 2 */ - -#define SYSCFG_CFGR2_SRAM_PEF_BIT 8 -#define SYSCFG_CFGR2_BYP_ADDR_PAR_BIT 4 -#define SYSCFG_CFGR2_PVD_LOCK_BIT 2 -#define SYSCFG_CFGR2_SRAM_PARITY_LOCK_BIT 1 -#define SYSCFG_CFGR2_LOCKUP_LOCK_BIT 0 - -#define SYSCFG_CFGR2_SRAM_PEF (1U << SYSCFG_CFGR2_SRAM_PEF_BIT) -#define SYSCFG_CFGR2_BYP_ADDR_PAR (1U << SYSCFG_CFGR2_BYP_ADDR_PAR_BIT) -#define SYSCFG_CFGR2_PVD_LOCK (1U << SYSCFG_CFGR2_PVD_LOCK_BIT) -#define SYSCFG_CFGR2_SRAM_PARITY_LOCK (1U << SYSCFG_CFGR2_SRAM_PARITY_LOCK_BIT) -#define SYSCFG_CFGR2_LOCKUP_LOCK (1U << SYSCFG_CFGR2_LOCKUP_LOCK_BIT) - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/timer.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/timer.h deleted file mode 100644 index 01e2c88..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/timer.h +++ /dev/null @@ -1,123 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2012 LeafLabs, LLC. - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/stm32f3/include/series/timer.h - * @author Marti Bolivar , - * F3-port by Hanspeter Portner - * @brief STM32F3 timer support. - */ - -#ifndef _LIBMAPLE_STM32F3_TIMER_H_ -#define _LIBMAPLE_STM32F3_TIMER_H_ - -#include -#include - -/* - * Register maps and base pointers - */ - -/** STM32F1 general purpose timer register map type */ -typedef struct timer_gen_reg_map { - __IO uint32 CR1; /**< Control register 1 */ - __IO uint32 CR2; /**< Control register 2 */ - __IO uint32 SMCR; /**< Slave mode control register */ - __IO uint32 DIER; /**< DMA/Interrupt enable register */ - __IO uint32 SR; /**< Status register */ - __IO uint32 EGR; /**< Event generation register */ - __IO uint32 CCMR1; /**< Capture/compare mode register 1 */ - __IO uint32 CCMR2; /**< Capture/compare mode register 2 */ - __IO uint32 CCER; /**< Capture/compare enable register */ - __IO uint32 CNT; /**< Counter */ - __IO uint32 PSC; /**< Prescaler */ - __IO uint32 ARR; /**< Auto-reload register */ - const uint32 RESERVED1; /**< Reserved */ - __IO uint32 CCR1; /**< Capture/compare register 1 */ - __IO uint32 CCR2; /**< Capture/compare register 2 */ - __IO uint32 CCR3; /**< Capture/compare register 3 */ - __IO uint32 CCR4; /**< Capture/compare register 4 */ - const uint32 RESERVED2; /**< Reserved */ - __IO uint32 DCR; /**< DMA control register */ - __IO uint32 DMAR; /**< DMA address for full transfer */ -} timer_gen_reg_map; - -struct timer_adv_reg_map; -struct timer_bas_reg_map; - -/** Timer 1 register map base pointer */ -#define TIMER1_BASE ((struct timer_adv_reg_map*)0x40012C00) -/** Timer 2 register map base pointer */ -#define TIMER2_BASE ((struct timer_gen_reg_map*)0x40000000) -/** Timer 3 register map base pointer */ -#define TIMER3_BASE ((struct timer_gen_reg_map*)0x40000400) -/** Timer 4 register map base pointer */ -#define TIMER4_BASE ((struct timer_gen_reg_map*)0x40000800) - -/** Timer 6 register map base pointer */ -#define TIMER6_BASE ((struct timer_bas_reg_map*)0x40001000) -/** Timer 7 register map base pointer */ -#define TIMER7_BASE ((struct timer_bas_reg_map*)0x40001400) -/** Timer 8 register map base pointer */ -#define TIMER8_BASE ((struct timer_adv_reg_map*)0x40013400) - -/** Timer 15 register map base pointer */ -#define TIMER15_BASE ((struct timer_gen_reg_map*)0x40014000) -/** Timer 16 register map base pointer */ -#define TIMER16_BASE ((struct timer_gen_reg_map*)0x40014400) -/** Timer 17 register map base pointer */ -#define TIMER17_BASE ((struct timer_gen_reg_map*)0x40014800) - -/* - * Device pointers - * - * We only declare device pointers to timers which actually exist on - * the target MCU. - */ - -struct timer_dev; - -extern struct timer_dev *TIMER1; -extern struct timer_dev *TIMER2; /* FIXME 32bit-capable counter */ -extern struct timer_dev *TIMER3; -extern struct timer_dev *TIMER4; -extern struct timer_dev *TIMER6; -#if STM32_F3_LINE == STM32_F3_LINE_303 -extern struct timer_dev *TIMER7; -extern struct timer_dev *TIMER8; -#endif -extern struct timer_dev *TIMER15; -extern struct timer_dev *TIMER16; -extern struct timer_dev *TIMER17; - -/* - * Routines - */ - -gpio_af timer_get_af(struct timer_dev *dev); - -#endif diff --git a/STM32F3/cores/maple/libmaple/stm32f3/include/series/usart.h b/STM32F3/cores/maple/libmaple/stm32f3/include/series/usart.h deleted file mode 100644 index 94a25d9..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/include/series/usart.h +++ /dev/null @@ -1,277 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/stm32f3/include/series/usart.h - * @author F3-port by Hanspeter Portner - * @brief STM32F3 USART support. - */ - -#ifndef _LIBMAPLE_STM32F3_USART_H_ -#define _LIBMAPLE_STM32F3_USART_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -#include /* for gpio_af */ - -/* - * Register maps - */ - -/** USART register map type */ -typedef struct usart_reg_map { - __IO uint32 CR1; /**< Control register 1 */ - __IO uint32 CR2; /**< Control register 2 */ - __IO uint32 CR3; /**< Control register 3 */ - __IO uint32 BRR; /**< Baud rate register */ - __IO uint32 GTPR; /**< Guard time and prescaler register */ - __IO uint32 RTOR; /**< Receiver timeout register */ - __IO uint32 RQR; /**< Request register */ - __IO uint32 SR; /**< ISR Interrupt and status register */ - __IO uint32 ICR; /**< Interrupt clear register */ - __IO uint16 RDR; /**< Receive data register */ - uint16 RESERVED1; - __IO uint16 TDR; /**< Transmit data register */ - uint16 RESERVED2; -} usart_reg_map; - -/* - * Register map base pointers - */ - -/** USART1 register map base pointer */ -#define USART1_BASE ((struct usart_reg_map*)0x40013800) -/** USART2 register map base pointer */ -#define USART2_BASE ((struct usart_reg_map*)0x40004400) -/** USART3 register map base pointer */ -#define USART3_BASE ((struct usart_reg_map*)0x40004800) - -#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) -/** UART4 register map base pointer */ -#define UART4_BASE ((struct usart_reg_map*)0x40004C00) -/** UART5 register map base pointer */ -#define UART5_BASE ((struct usart_reg_map*)0x40005000) -#endif - -/* - * Devices - */ - -struct usart_dev; -extern struct usart_dev *USART1; -extern struct usart_dev *USART2; -extern struct usart_dev *USART3; -#ifdef STM32_HIGH_DENSITY -extern struct usart_dev *UART4; -extern struct usart_dev *UART5; -#endif - -/* - * F3-only register bit definitions. - */ - -/* Control register 1 */ -#define USART_CR1_EOBIE_BIT 27 -#define USART_CR1_RTOIE_BIT 26 -#define USART_CR1_DEAT4_BIT 25 -#define USART_CR1_DEAT3_BIT 24 -#define USART_CR1_DEAT2_BIT 23 -#define USART_CR1_DEAT1_BIT 22 -#define USART_CR1_DEAT0_BIT 21 -#define USART_CR1_DEDT4_BIT 20 -#define USART_CR1_DEDT3_BIT 19 -#define USART_CR1_DEDT2_BIT 18 -#define USART_CR1_DEDT1_BIT 17 -#define USART_CR1_DEDT0_BIT 16 -#define USART_CR1_OVER8_BIT 15 -#define USART_CR1_CMIE_BIT 14 -#define USART_CR1_MME_BIT 13 -#define USART_CR1_UESM_BIT 1 -#define USART_CR1_UE_BIT 0 - -#define USART_CR1_EOBIE (1UL << USART_CR1_EOBIE_BIT) -#define USART_CR1_RTOIE (1UL << USART_CR1_RTOIE_BIT) -#define USART_CR1_DEAT4 (1UL << USART_CR1_DEAT4_BIT) -#define USART_CR1_DEAT3 (1UL << USART_CR1_DEAT3_BIT) -#define USART_CR1_DEAT2 (1UL << USART_CR1_DEAT2_BIT) -#define USART_CR1_DEAT1 (1UL << USART_CR1_DEAT1_BIT) -#define USART_CR1_DEAT0 (1UL << USART_CR1_DEAT0_BIT) -#define USART_CR1_DEDT4 (1UL << USART_CR1_DEDT4_BIT) -#define USART_CR1_DEDT3 (1UL << USART_CR1_DEDT3_BIT) -#define USART_CR1_DEDT2 (1UL << USART_CR1_DEDT2_BIT) -#define USART_CR1_DEDT1 (1UL << USART_CR1_DEDT1_BIT) -#define USART_CR1_DEDT0 (1UL << USART_CR1_DEDT0_BIT) -#define USART_CR1_OVER8 (1UL << USART_CR1_OVER8_BIT) -#define USART_CR1_CMIE (1UL << USART_CR1_CMIE_BIT) -#define USART_CR1_MME (1UL << USART_CR1_MME_BIT) -#define USART_CR1_UESM (1UL << USART_CR1_UESM_BIT) -#define USART_CR1_UE (1UL << USART_CR1_UE_BIT) - -/* Control register 2 */ -#define USART_CR2_ADD_SHIFT 24 -#define USART_CR2_RTOEN_BIT 23 -#define USART_CR2_ABRMOD1_BIT 22 -#define USART_CR2_ABRMOD0_BIT 21 -#define USART_CR2_ABREN_BIT 20 -#define USART_CR2_MSBFIRST_BIT 19 -#define USART_CR2_DATAINV_BIT 18 -#define USART_CR2_TXINV_BIT 17 -#define USART_CR2_RXINV_BIT 16 -#define USART_CR2_SWAP_BIT 15 -#define USART_CR2_ADDM7_BIT 4 - -#define USART_CR2_ADD (0xFF << USART_CR2_ADD_SHIFT) -#define USART_CR2_RTOEN (1UL << USART_CR2_RTOEN_BIT) -#define USART_CR2_ABRMOD1 (1UL << USART_CR2_ABRMOD1_BIT) -#define USART_CR2_ABRMOD0 (1UL << USART_CR2_ABRMOD0_BIT) -#define USART_CR2_ABREN (1UL << USART_CR2_ABREN_BIT) -#define USART_CR2_MSBFIRST (1UL << USART_CR2_MSBFIRST_BIT) -#define USART_CR2_DATAINV (1UL << USART_CR2_DATAINV_BIT) -#define USART_CR2_TXINV (1UL << USART_CR2_TXINV_BIT) -#define USART_CR2_RXINV (1UL << USART_CR2_RXINV_BIT) -#define USART_CR2_SWAP (1UL << USART_CR2_SWAP_BIT) -#define USART_CR2_ADDM7 (1UL << USART_CR2_ADDM7_BIT) - -/* Control register 3 */ -#define USART_CR3_WUFIE_BIT 22 -#define USART_CR3_WUS_SHIFT 20 -#define USART_CR3_SCAR_SHIFT 17 -#define USART_CR3_DEP_BIT 15 -#define USART_CR3_DEM_BIT 14 -#define USART_CR3_DDRE_BIT 13 -#define USART_CR3_OVRDIS_BIT 12 -#define USART_CR3_ONEBIT_BIT 11 - -#define USART_CR3_WUFIE (1UL << USART_CR3_WUFIE_BIT) -#define USART_CR3_WUS (0x3 << USART_CR3_WUS_SHIFT) -#define USART_CR3_SCAR (0x7 << USART_CR3_SCAR_SHIFT) -#define USART_CR3_DEP (1UL << USART_CR3_DEP_BIT) -#define USART_CR3_DEM (1UL << USART_CR3_DEM_BIT) -#define USART_CR3_DDRE (1UL << USART_CR3_DDRE_BIT) -#define USART_CR3_OVRDIS (1UL << USART_CR3_OVRDIS_BIT) -#define USART_CR3_ONEBIT (1UL << USART_CR3_ONEBIT_BIT) - -/* Receive timeout register */ -#define USART_RTOR_BLEN_SHIFT 24 -#define USART_RTOR_RTO_SHIFT 0 - -#define USART_RTOR_BLEN (0xF << USART_RTOR_BLEN_SHIFT) -#define USART_RTOR_RTO (0xFFF << USART_RTOR_RTO_SHIFT) - -/* Request register */ -#define USART_RQR_TXFRQ_BIT 4 -#define USART_RQR_RXFRQ_BIT 3 -#define USART_RQR_MMRQ_BIT 2 -#define USART_RQR_SBKRQ_BIT 1 -#define USART_RQR_ABRRQ_BIT 0 - -#define USART_RQR_TXFRQ (1UL << USART_RQR_TXFRQ_BIT) -#define USART_RQR_RXFRQ (1UL << USART_RQR_RXFRQ_BIT) -#define USART_RQR_MMRQ (1UL << USART_RQR_MMRQ_BIT) -#define USART_RQR_SBKRQ (1UL << USART_RQR_SBKRQ_BIT) -#define USART_RQR_ABRRQ (1UL << USART_RQR_ABRRQ_BIT) - -/* Interrupt and status register */ -// common register bits with other STM32 series are defined as USART_SR_* for compatibility -#define USART_SR_REACK_BIT 22 -#define USART_SR_TEACK_BIT 21 -#define USART_SR_WUF_BIT 20 -#define USART_SR_RWU_BIT 19 -#define USART_SR_SBKF_BIT 18 -#define USART_SR_CMF_BIT 17 -#define USART_SR_BUSY_BIT 16 -#define USART_SR_ABRF_BIT 15 -#define USART_SR_ABRE_BIT 14 -#define USART_SR_EOBF_BIT 12 -#define USART_SR_RTOF_BIT 11 -#define USART_SR_CTS_BIT 10 -#define USART_SR_CTSIF_BIT 9 - -#define USART_SR_REACK (1UL << USART_ISR_REACK_BIT) -#define USART_SR_TEACK (1UL << USART_ISR_TEACK_BIT) -#define USART_SR_WUF (1UL << USART_ISR_WUF_BIT) -#define USART_SR_RWU (1UL << USART_ISR_RWU_BIT) -#define USART_SR_SBKF (1UL << USART_ISR_SBKF_BIT) -#define USART_SR_CMF (1UL << USART_ISR_CMF_BIT) -#define USART_SR_BUSY (1UL << USART_ISR_BUSY_BIT) -#define USART_SR_ABRF (1UL << USART_ISR_ABRF_BIT) -#define USART_SR_ABRE (1UL << USART_ISR_ABRE_BIT) -#define USART_SR_EOBF (1UL << USART_ISR_EOBF_BIT) -#define USART_SR_RTOF (1UL << USART_ISR_RTOF_BIT) -#define USART_SR_CTS (1UL << USART_ISR_CTS_BIT) -#define USART_SR_CTSIF (1UL << USART_ISR_CTSIF_BIT) - -/* Interrupt clear register */ -#define USART_ICR_WUFCF_BIT 20 -#define USART_ICR_CMCF_BIT 17 -#define USART_ICR_EOBCF_BIT 12 -#define USART_ICR_RTOCF_BIT 11 -#define USART_ICR_CTSCF_BIT 9 -#define USART_ICR_LBDCF_BIT 8 -#define USART_ICR_TCCF_BIT 6 -#define USART_ICR_IDLECF_BIT 4 -#define USART_ICR_ORECF_BIT 3 -#define USART_ICR_NCF_BIT 2 -#define USART_ICR_FECF_BIT 1 -#define USART_ICR_PECF_BIT 0 - -#define USART_ICR_WUFCF (1UL << USART_ICR_WUFCF_BIT) -#define USART_ICR_CMCF (1UL << USART_ICR_CMCF_BIT) -#define USART_ICR_EOBCF (1UL << USART_ICR_EOBCF_BIT) -#define USART_ICR_RTOCF (1UL << USART_ICR_RTOCF_BIT) -#define USART_ICR_CTSCF (1UL << USART_ICR_CTSCF_BIT) -#define USART_ICR_LBDCF (1UL << USART_ICR_LBDCF_BIT) -#define USART_ICR_TCCF (1UL << USART_ICR_TCCF_BIT) -#define USART_ICR_IDLECF (1UL << USART_ICR_IDLECF_BIT) -#define USART_ICR_ORECF (1UL << USART_ICR_ORECF_BIT) -#define USART_ICR_NCF (1UL << USART_ICR_NCF_BIT) -#define USART_ICR_FECF (1UL << USART_ICR_FECF_BIT) -#define USART_ICR_PECF (1UL << USART_ICR_PECF_BIT) - -/* Receive data register */ -#define USART_RDR_RDR_SHIFT 0 - -#define USART_RDR_RDR (0x1FF << USART_RDR_RDR_SHIFT) - - -/* Transmit data register */ -#define USART_TDR_TDR_SHIFT 0 - -#define USART_TDR_TDR (0x1FF << USART_TDR_TDR_SHIFT) - -/* - * Routines - */ - -gpio_af usart_get_af(struct usart_dev *dev); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/stm32f3/rules.mk b/STM32F3/cores/maple/libmaple/stm32f3/rules.mk deleted file mode 100644 index f17f745..0000000 --- a/STM32F3/cores/maple/libmaple/stm32f3/rules.mk +++ /dev/null @@ -1,48 +0,0 @@ -# Standard things -sp := $(sp).x -dirstack_$(sp) := $(d) -d := $(dir) -BUILDDIRS += $(BUILD_PATH)/$(d) - -# Local flags -CFLAGS_$(d) = -I$(d) $(LIBMAPLE_PRIVATE_INCLUDES) $(LIBMAPLE_INCLUDES) -Wall -Werror -ASFLAGS_$(d) = -I$(d) $(LIBMAPLE_PRIVATE_INCLUDES) $(LIBMAPLE_INCLUDES) -Wall -Werror - -# Extra BUILDDIRS -BUILDDIRS += $(BUILD_PATH)/$(d)/F30xxx - -# Local rules and targets -sSRCS_$(d) := F30xxx/isrs.S -sSRCS_$(d) += F30xxx/vector_table.S - -cSRCS_$(d) := adc.c -cSRCS_$(d) += dma.c -cSRCS_$(d) += exti.c -cSRCS_$(d) += gpio.c -cSRCS_$(d) += i2c.c -cSRCS_$(d) += rcc.c -cSRCS_$(d) += spi.c -cSRCS_$(d) += timer.c -cSRCS_$(d) += usart.c -cSRCS_$(d) += syscfg.c -cSRCS_$(d) += fpu.c -cSRCS_$(d) += comp.c -cSRCS_$(d) += opamp.c -cSRCS_$(d) += bkp.c - -sFILES_$(d) := $(sSRCS_$(d):%=$(d)/%) -cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%) - -OBJS_$(d) := $(sFILES_$(d):%.S=$(BUILD_PATH)/%.o) \ - $(cFILES_$(d):%.c=$(BUILD_PATH)/%.o) -DEPS_$(d) := $(OBJS_$(d):%.o=%.d) - -$(OBJS_$(d)): TGT_ASFLAGS := $(ASFLAGS_$(d)) -$(OBJS_$(d)): TGT_CFLAGS := $(CFLAGS_$(d)) - -TGT_BIN += $(OBJS_$(d)) - -# Standard things --include $(DEPS_$(d)) -d := $(dirstack_$(sp)) -sp := $(basename $(sp)) diff --git a/STM32F3/cores/maple/libmaple/syscfg.c b/STM32F3/cores/maple/libmaple/syscfg.c deleted file mode 100644 index 8b3c963..0000000 --- a/STM32F3/cores/maple/libmaple/syscfg.c +++ /dev/null @@ -1,41 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/syscfg.c - * @brief System configuration controller (SYSCFG) - * @author F3-port by Hanspeter Portner - * - * Availability: STM32F2, STM32F3, STM32F4. - */ - -#include -#include - -void syscfg_init(void) { - rcc_clk_enable(RCC_SYSCFG); - rcc_reset_dev(RCC_SYSCFG); -} diff --git a/STM32F3/cores/maple/libmaple/systick.c b/STM32F3/cores/maple/libmaple/systick.c deleted file mode 100644 index 7568abe..0000000 --- a/STM32F3/cores/maple/libmaple/systick.c +++ /dev/null @@ -1,88 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * Copyright (c) 2010, 2011 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/systick.c - * @brief System timer (SysTick). - */ - -#include - -volatile uint32 systick_uptime_millis; -static void (*systick_user_callback)(void); - -/** - * @brief Initialize and enable SysTick. - * - * Clocks the system timer with the core clock, turns it on, and - * enables interrupts. - * - * @param reload_val Appropriate reload counter to tick every 1 ms. - */ -void systick_init(uint32 reload_val) { - SYSTICK_BASE->RVR = reload_val; - systick_enable(); -} - -/** - * Clock the system timer with the core clock, but don't turn it - * on or enable interrupt. - */ -void systick_disable() { - SYSTICK_BASE->CSR = SYSTICK_CSR_CLKSOURCE_CORE; -} - -/** - * Clock the system timer with the core clock and turn it on; - * interrupt every 1 ms, for systick_timer_millis. - */ -void systick_enable() { - /* re-enables init registers without changing reload val */ - SYSTICK_BASE->CSR = (SYSTICK_CSR_CLKSOURCE_CORE | - SYSTICK_CSR_ENABLE | - SYSTICK_CSR_TICKINT_PEND); -} - -/** - * @brief Attach a callback to be called from the SysTick exception handler. - * - * To detach a callback, call this function again with a null argument. - */ -void systick_attach_callback(void (*callback)(void)) { - systick_user_callback = callback; -} - -/* - * SysTick ISR - */ - -void __exc_systick(void) { - systick_uptime_millis++; - if (systick_user_callback) { - systick_user_callback(); - } -} diff --git a/STM32F3/cores/maple/libmaple/timer.c b/STM32F3/cores/maple/libmaple/timer.c deleted file mode 100644 index e48cb1a..0000000 --- a/STM32F3/cores/maple/libmaple/timer.c +++ /dev/null @@ -1,456 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2011 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/timer.c - * @author Marti Bolivar - * @brief Portable timer routines. - */ - -#include -#include -#include "timer_private.h" - -static void disable_channel(timer_dev *dev, uint8 channel); -static void pwm_mode(timer_dev *dev, uint8 channel); -static void output_compare_mode(timer_dev *dev, uint8 channel); - -static inline void enable_irq(timer_dev *dev, uint8 interrupt); - -/* - * Devices - * - * Defer to the timer_private API for declaring these. - */ - -#if STM32_HAVE_TIMER(1) -static timer_dev timer1 = ADVANCED_TIMER(1); -/** Timer 1 device (advanced) */ -timer_dev *TIMER1 = &timer1; -#endif -#if STM32_HAVE_TIMER(2) -static timer_dev timer2 = GENERAL_TIMER(2); -/** Timer 2 device (general-purpose) */ -timer_dev *TIMER2 = &timer2; -#endif -#if STM32_HAVE_TIMER(3) -static timer_dev timer3 = GENERAL_TIMER(3); -/** Timer 3 device (general-purpose) */ -timer_dev *TIMER3 = &timer3; -#endif -#if STM32_HAVE_TIMER(4) -static timer_dev timer4 = GENERAL_TIMER(4); -/** Timer 4 device (general-purpose) */ -timer_dev *TIMER4 = &timer4; -#endif -#if STM32_HAVE_TIMER(5) -static timer_dev timer5 = GENERAL_TIMER(5); -/** Timer 5 device (general-purpose) */ -timer_dev *TIMER5 = &timer5; -#endif -#if STM32_HAVE_TIMER(6) -static timer_dev timer6 = BASIC_TIMER(6); -/** Timer 6 device (basic) */ -timer_dev *TIMER6 = &timer6; -#endif -#if STM32_HAVE_TIMER(7) -static timer_dev timer7 = BASIC_TIMER(7); -/** Timer 7 device (basic) */ -timer_dev *TIMER7 = &timer7; -#endif -#if STM32_HAVE_TIMER(8) -static timer_dev timer8 = ADVANCED_TIMER(8); -/** Timer 8 device (advanced) */ -timer_dev *TIMER8 = &timer8; -#endif -#if STM32_HAVE_TIMER(9) -static timer_dev timer9 = RESTRICTED_GENERAL_TIMER(9, TIMER_DIER_TIE_BIT); -/** Timer 9 device (general-purpose) */ -timer_dev *TIMER9 = &timer9; -#endif -#if STM32_HAVE_TIMER(10) -static timer_dev timer10 = RESTRICTED_GENERAL_TIMER(10, TIMER_DIER_CC1IE_BIT); -/** Timer 10 device (general-purpose) */ -timer_dev *TIMER10 = &timer10; -#endif -#if STM32_HAVE_TIMER(11) -static timer_dev timer11 = RESTRICTED_GENERAL_TIMER(11, TIMER_DIER_CC1IE_BIT); -/** Timer 11 device (general-purpose) */ -timer_dev *TIMER11 = &timer11; -#endif -#if STM32_HAVE_TIMER(12) -static timer_dev timer12 = RESTRICTED_GENERAL_TIMER(12, TIMER_DIER_TIE_BIT); -/** Timer 12 device (general-purpose) */ -timer_dev *TIMER12 = &timer12; -#endif -#if STM32_HAVE_TIMER(13) -static timer_dev timer13 = RESTRICTED_GENERAL_TIMER(13, TIMER_DIER_CC1IE_BIT); -/** Timer 13 device (general-purpose) */ -timer_dev *TIMER13 = &timer13; -#endif -#if STM32_HAVE_TIMER(14) -static timer_dev timer14 = RESTRICTED_GENERAL_TIMER(14, TIMER_DIER_CC1IE_BIT); -/** Timer 14 device (general-purpose) */ -timer_dev *TIMER14 = &timer14; -#endif -#if STM32_HAVE_TIMER(15) -static timer_dev timer15 = RESTRICTED_GENERAL_TIMER(15, TIMER_DIER_TIE_BIT); //XXX -/** Timer 15 device (general-purpose) */ -timer_dev *TIMER15 = &timer15; -#endif -#if STM32_HAVE_TIMER(16) -static timer_dev timer16 = RESTRICTED_GENERAL_TIMER(16, TIMER_DIER_CC1IE_BIT); //XXX -/** Timer 16 device (general-purpose) */ -timer_dev *TIMER16 = &timer16; -#endif -#if STM32_HAVE_TIMER(17) -static timer_dev timer17 = RESTRICTED_GENERAL_TIMER(17, TIMER_DIER_CC1IE_BIT); //XXX -/** Timer 17 device (general-purpose) */ -timer_dev *TIMER17 = &timer17; -#endif - -/* - * Routines - */ - -/** - * @brief Call a function on timer devices. - * @param fn Function to call on each timer device. - */ -void timer_foreach(void (*fn)(timer_dev*)) { -#if STM32_HAVE_TIMER(1) - fn(TIMER1); -#endif -#if STM32_HAVE_TIMER(2) - fn(TIMER2); -#endif -#if STM32_HAVE_TIMER(3) - fn(TIMER3); -#endif -#if STM32_HAVE_TIMER(4) - fn(TIMER4); -#endif -#if STM32_HAVE_TIMER(5) - fn(TIMER5); -#endif -#if STM32_HAVE_TIMER(6) - fn(TIMER6); -#endif -#if STM32_HAVE_TIMER(7) - fn(TIMER7); -#endif -#if STM32_HAVE_TIMER(8) - fn(TIMER8); -#endif -#if STM32_HAVE_TIMER(9) - fn(TIMER9); -#endif -#if STM32_HAVE_TIMER(10) - fn(TIMER10); -#endif -#if STM32_HAVE_TIMER(11) - fn(TIMER11); -#endif -#if STM32_HAVE_TIMER(12) - fn(TIMER12); -#endif -#if STM32_HAVE_TIMER(13) - fn(TIMER13); -#endif -#if STM32_HAVE_TIMER(14) - fn(TIMER14); -#endif -#if STM32_HAVE_TIMER(15) - fn(TIMER15); -#endif -#if STM32_HAVE_TIMER(16) - fn(TIMER16); -#endif -#if STM32_HAVE_TIMER(17) - fn(TIMER17); -#endif -} - -/** - * Initialize a timer, and reset its register map. - * @param dev Timer to initialize - */ -void timer_init(timer_dev *dev) { - rcc_clk_enable(dev->clk_id); - rcc_reset_dev(dev->clk_id); -} - -/** - * @brief Disable a timer. - * - * The timer will stop counting, all DMA requests and interrupts will - * be disabled, and no state changes will be output. - * - * @param dev Timer to disable. - */ -void timer_disable(timer_dev *dev) { - (dev->regs).bas->CR1 = 0; - (dev->regs).bas->DIER = 0; - switch (dev->type) { - case TIMER_ADVANCED: /* fall-through */ - case TIMER_GENERAL: - (dev->regs).gen->CCER = 0; - break; - case TIMER_BASIC: - break; - } -} - -/** - * Sets the mode of an individual timer channel. - * - * Note that not all timers can be configured in every mode. For - * example, basic timers cannot be configured to output compare mode. - * Be sure to use a timer which is appropriate for the mode you want. - * - * @param dev Timer whose channel mode to set - * @param channel Relevant channel - * @param mode New timer mode for channel - */ -void timer_set_mode(timer_dev *dev, uint8 channel, timer_mode mode) { - ASSERT_FAULT(channel > 0 && channel <= 4); - - /* TODO decide about the basic timers */ - ASSERT(dev->type != TIMER_BASIC); - if (dev->type == TIMER_BASIC) - return; - - switch (mode) { - case TIMER_DISABLED: - disable_channel(dev, channel); - break; - case TIMER_PWM: - pwm_mode(dev, channel); - break; - case TIMER_OUTPUT_COMPARE: - output_compare_mode(dev, channel); - break; - } -} - -/** - * @brief Determine whether a timer has a particular capture/compare channel. - * - * Different timers have different numbers of capture/compare channels - * (and some have none at all). Use this function to test whether a - * given timer/channel combination will work. - * - * @param dev Timer device - * @param channel Capture/compare channel, from 1 to 4 - * @return Nonzero if dev has channel, zero otherwise. - */ -int timer_has_cc_channel(timer_dev *dev, uint8 channel) { - /* On all currently supported series: advanced and "full-featured" - * general purpose timers have all four channels. Of the - * restricted general timers, timers 9, 12 and 15 have channels 1 and - * 2; the others have channel 1 only. Basic timers have none. */ - rcc_clk_id id = dev->clk_id; - ASSERT((1 <= channel) && (channel <= 4)); - if (id <= RCC_TIMER5 || id == RCC_TIMER8) { - return 1; /* 1 and 8 are advanced, 2-5 are "full" general */ - } else if (id <= RCC_TIMER7) { - return 0; /* 6 and 7 are basic */ - } - /* The rest are restricted general. */ - return (((id == RCC_TIMER9 || id == RCC_TIMER12 || id == RCC_TIMER15) && channel <= 2) || - channel == 1); -} - -/** - * @brief Attach a timer interrupt. - * @param dev Timer device - * @param interrupt Interrupt number to attach to; this may be any - * timer_interrupt_id or timer_channel value appropriate - * for the timer. - * @param handler Handler to attach to the given interrupt. - * @see timer_interrupt_id - * @see timer_channel - */ -void timer_attach_interrupt(timer_dev *dev, - uint8 interrupt, - voidFuncPtr handler) { - dev->handlers[interrupt] = handler; - timer_enable_irq(dev, interrupt); - enable_irq(dev, interrupt); -} - -/** - * @brief Detach a timer interrupt. - * @param dev Timer device - * @param interrupt Interrupt number to detach; this may be any - * timer_interrupt_id or timer_channel value appropriate - * for the timer. - * @see timer_interrupt_id - * @see timer_channel - */ -void timer_detach_interrupt(timer_dev *dev, uint8 interrupt) { - timer_disable_irq(dev, interrupt); - dev->handlers[interrupt] = NULL; -} - -/* - * Utilities - */ - -static void disable_channel(timer_dev *dev, uint8 channel) { - timer_detach_interrupt(dev, channel); - timer_cc_disable(dev, channel); -} - -static void pwm_mode(timer_dev *dev, uint8 channel) { - timer_disable_irq(dev, channel); - timer_oc_set_mode(dev, channel, TIMER_OC_MODE_PWM_1, TIMER_OC_PE); - timer_cc_enable(dev, channel); -} - -static void output_compare_mode(timer_dev *dev, uint8 channel) { - timer_oc_set_mode(dev, channel, TIMER_OC_MODE_ACTIVE_ON_MATCH, 0); - timer_cc_enable(dev, channel); -} - -static void enable_adv_irq(timer_dev *dev, timer_interrupt_id id); -static void enable_bas_gen_irq(timer_dev *dev); - -static inline void enable_irq(timer_dev *dev, timer_interrupt_id iid) { - if (dev->type == TIMER_ADVANCED) { - enable_adv_irq(dev, iid); - } else { - enable_bas_gen_irq(dev); - } -} - -/* Advanced control timers have several IRQ lines corresponding to - * different timer interrupts. - * - * Note: This function assumes that the only advanced timers are TIM1 - * and TIM8, and needs the obvious changes if that assumption is - * violated by a later STM32 series. */ -static void enable_adv_irq(timer_dev *dev, timer_interrupt_id id) { - uint8 is_tim1 = dev->clk_id == RCC_TIMER1; - nvic_irq_num irq_num; - switch (id) { - case TIMER_UPDATE_INTERRUPT: - irq_num = (is_tim1 ? - NVIC_TIMER1_UP_TIMER10 : - NVIC_TIMER8_UP_TIMER13); - break; - case TIMER_CC1_INTERRUPT: /* Fall through */ - case TIMER_CC2_INTERRUPT: /* ... */ - case TIMER_CC3_INTERRUPT: /* ... */ - case TIMER_CC4_INTERRUPT: - irq_num = is_tim1 ? NVIC_TIMER1_CC : NVIC_TIMER8_CC; - break; - case TIMER_COM_INTERRUPT: /* Fall through */ - case TIMER_TRG_INTERRUPT: - irq_num = (is_tim1 ? - NVIC_TIMER1_TRG_COM_TIMER11 : - NVIC_TIMER8_TRG_COM_TIMER14); - break; - case TIMER_BREAK_INTERRUPT: - irq_num = (is_tim1 ? - NVIC_TIMER1_BRK_TIMER9 : - NVIC_TIMER8_BRK_TIMER12); - break; - default: - /* Can't happen, but placate the compiler */ - ASSERT(0); - return; - } - nvic_irq_enable(irq_num); -} - -/* Basic and general purpose timers have a single IRQ line, which is - * shared by all interrupts supported by a particular timer. */ -static void enable_bas_gen_irq(timer_dev *dev) { - nvic_irq_num irq_num; - switch (dev->clk_id) { - case RCC_TIMER2: - irq_num = NVIC_TIMER2; - break; - case RCC_TIMER3: - irq_num = NVIC_TIMER3; - break; - case RCC_TIMER4: - irq_num = NVIC_TIMER4; - break; -#if STM32_HAVE_TIMER(5) - case RCC_TIMER5: - irq_num = NVIC_TIMER5; - break; -#endif - case RCC_TIMER6: - irq_num = NVIC_TIMER6; - break; - case RCC_TIMER7: - irq_num = NVIC_TIMER7; - break; - case RCC_TIMER9: - irq_num = NVIC_TIMER1_BRK_TIMER9; - break; - case RCC_TIMER10: - irq_num = NVIC_TIMER1_UP_TIMER10; - break; - case RCC_TIMER11: - irq_num = NVIC_TIMER1_TRG_COM_TIMER11; - break; - case RCC_TIMER12: - irq_num = NVIC_TIMER8_BRK_TIMER12; - break; - case RCC_TIMER13: - irq_num = NVIC_TIMER8_UP_TIMER13; - break; - case RCC_TIMER14: - irq_num = NVIC_TIMER8_TRG_COM_TIMER14; - break; -#if STM32_HAVE_TIMER(15) - case RCC_TIMER15: - //irq_num = NVIC_TIMER1_BRK_TIMER15; - irq_num = NVIC_TIMER1_BRK_TIMER9; - break; -#endif -#if STM32_HAVE_TIMER(16) - case RCC_TIMER16: - //irq_num = NVIC_TIMER1_UP_TIMER16; - irq_num = NVIC_TIMER1_UP_TIMER10; - break; -#endif -#if STM32_HAVE_TIMER(17) - case RCC_TIMER17: - //irq_num = NVIC_TIMER1_TRG_COM_TIMER17; - irq_num = NVIC_TIMER1_TRG_COM_TIMER11; - break; -#endif - default: - ASSERT_FAULT(0); - return; - } - nvic_irq_enable(irq_num); -} diff --git a/STM32F3/cores/maple/libmaple/timer_private.h b/STM32F3/cores/maple/libmaple/timer_private.h deleted file mode 100644 index 320c636..0000000 --- a/STM32F3/cores/maple/libmaple/timer_private.h +++ /dev/null @@ -1,235 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2011, 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/timer_private.h - * @author Marti Bolivar - * @brief Private, internal timer APIs. - */ - -#ifndef _LIBMAPLE_TIMER_PRIVATE_H_ -#define _LIBMAPLE_TIMER_PRIVATE_H_ - -/* - * Helper macros for declaring timer_devs of various timer_types - */ - -/* The indexes of user handlers in a timer_dev.handlers are just like - * the corresponding DIER bits, as follows: */ - -/* Advanced timers: - * [0] = Update handler; - * [1,2,3,4] = capture/compare 1,2,3,4 handlers, respectively; - * [5] = COM; - * [6] = TRG; - * [7] = BRK. */ -#define NR_ADV_HANDLERS 8 -/* General purpose timers: - * [0] = update; - * [1,2,3,4] = capture/compare 1,2,3,4; - * [5] = ; - * [6] = trigger. */ -#define NR_GEN_HANDLERS 7 -/* Basic timers: - * [0] = update. */ -#define NR_BAS_HANDLERS 1 - -/* For declaring advanced timers. */ -#define ADVANCED_TIMER(num) \ - { \ - .regs = { .adv = TIMER##num##_BASE }, \ - .clk_id = RCC_TIMER##num, \ - .type = TIMER_ADVANCED, \ - .handlers = { [NR_ADV_HANDLERS - 1] = 0 }, \ - } - -/* For declaring full-featured general purpose timers. */ -#define GENERAL_TIMER(num) \ - { \ - .regs = { .gen = TIMER##num##_BASE }, \ - .clk_id = RCC_TIMER##num, \ - .type = TIMER_GENERAL, \ - .handlers = { [NR_GEN_HANDLERS - 1] = 0 }, \ - } - -/* For declaring general purpose timers with limited interrupt - * capability (e.g. timers 9 through 14 on STM32F2 and XL-density - * STM32F1). */ -#define RESTRICTED_GENERAL_TIMER(num, max_dier_bit) \ - { \ - .regs = { .gen = TIMER##num##_BASE }, \ - .clk_id = RCC_TIMER##num, \ - .type = TIMER_GENERAL, \ - .handlers = { [max_dier_bit] = 0 }, \ - } - -/* For declaring basic timers (e.g. TIM6 and TIM7). */ -#define BASIC_TIMER(num) \ - { \ - .regs = { .bas = TIMER##num##_BASE }, \ - .clk_id = RCC_TIMER##num, \ - .type = TIMER_BASIC, \ - .handlers = { [NR_BAS_HANDLERS - 1] = 0 }, \ - } - -/* - * IRQ handlers - * - * These decode TIMx_DIER and TIMx_SR, then dispatch to the user-level - * IRQ handlers. They also clean up TIMx_SR afterwards, so the user - * doesn't have to deal with register details. - * - * Notes: - * - * - These dispatch routines make use of the fact that DIER interrupt - * enable bits and SR interrupt flags have common bit positions. - * Thus, ANDing DIER and SR lets us check if an interrupt is enabled - * and if it has occurred simultaneously. - * - * - We force these routines to inline to avoid call overhead, but - * there aren't any measurements to prove that this is actually a - * good idea. Profile-directed optimizations are definitely wanted. */ - -/* A special-case dispatch routine for timers which only serve a - * single interrupt on a given IRQ line. - * - * This function still checks DIER & SR, as in some cases, a timer may - * only serve a single interrupt on a particular NVIC line, but that - * line may be shared with another timer. For example, the timer 1 - * update interrupt shares an IRQ line with the timer 10 interrupt on - * STM32F1 (XL-density), STM32F2, and STM32F4. */ -static __always_inline void dispatch_single_irq(timer_dev *dev, - timer_interrupt_id iid, - uint32 irq_mask) { - timer_bas_reg_map *regs = (dev->regs).bas; - if (regs->DIER & regs->SR & irq_mask) { - void (*handler)(void) = dev->handlers[iid]; - if (handler) { - handler(); - regs->SR &= ~irq_mask; - } - } -} - -/* Helper macro for dispatch routines which service multiple interrupts. */ -#define handle_irq(dier_sr, irq_mask, handlers, iid, handled_irq) do { \ - if ((dier_sr) & (irq_mask)) { \ - void (*__handler)(void) = (handlers)[iid]; \ - if (__handler) { \ - __handler(); \ - handled_irq |= (irq_mask); \ - } \ - } \ - } while (0) - -static __always_inline void dispatch_adv_brk(timer_dev *dev) { - dispatch_single_irq(dev, TIMER_BREAK_INTERRUPT, TIMER_SR_BIF); -} - -static __always_inline void dispatch_adv_up(timer_dev *dev) { - dispatch_single_irq(dev, TIMER_UPDATE_INTERRUPT, TIMER_SR_UIF); -} - -static __always_inline void dispatch_adv_trg_com(timer_dev *dev) { - timer_adv_reg_map *regs = (dev->regs).adv; - uint32 dsr = regs->DIER & regs->SR; - void (**hs)(void) = dev->handlers; - uint32 handled = 0; /* Logical OR of SR interrupt flags we end up - * handling. We clear these. User handlers - * must clear overcapture flags, to avoid - * wasting time in output mode. */ - - handle_irq(dsr, TIMER_SR_TIF, hs, TIMER_TRG_INTERRUPT, handled); - handle_irq(dsr, TIMER_SR_COMIF, hs, TIMER_COM_INTERRUPT, handled); - - regs->SR &= ~handled; -} - -static __always_inline void dispatch_adv_cc(timer_dev *dev) { - timer_adv_reg_map *regs = (dev->regs).adv; - uint32 dsr = regs->DIER & regs->SR; - void (**hs)(void) = dev->handlers; - uint32 handled = 0; - - handle_irq(dsr, TIMER_SR_CC4IF, hs, TIMER_CC4_INTERRUPT, handled); - handle_irq(dsr, TIMER_SR_CC3IF, hs, TIMER_CC3_INTERRUPT, handled); - handle_irq(dsr, TIMER_SR_CC2IF, hs, TIMER_CC2_INTERRUPT, handled); - handle_irq(dsr, TIMER_SR_CC1IF, hs, TIMER_CC1_INTERRUPT, handled); - - regs->SR &= ~handled; -} - -static __always_inline void dispatch_general(timer_dev *dev) { - timer_gen_reg_map *regs = (dev->regs).gen; - uint32 dsr = regs->DIER & regs->SR; - void (**hs)(void) = dev->handlers; - uint32 handled = 0; - - handle_irq(dsr, TIMER_SR_TIF, hs, TIMER_TRG_INTERRUPT, handled); - handle_irq(dsr, TIMER_SR_CC4IF, hs, TIMER_CC4_INTERRUPT, handled); - handle_irq(dsr, TIMER_SR_CC3IF, hs, TIMER_CC3_INTERRUPT, handled); - handle_irq(dsr, TIMER_SR_CC2IF, hs, TIMER_CC2_INTERRUPT, handled); - handle_irq(dsr, TIMER_SR_CC1IF, hs, TIMER_CC1_INTERRUPT, handled); - handle_irq(dsr, TIMER_SR_UIF, hs, TIMER_UPDATE_INTERRUPT, handled); - - regs->SR &= ~handled; -} - -/* On F1 (XL-density), F2, and F4, TIM9 and TIM12 are restricted - * general-purpose timers with update, CC1, CC2, and TRG interrupts. */ -static __always_inline void dispatch_tim_9_12(timer_dev *dev) { - timer_gen_reg_map *regs = (dev->regs).gen; - uint32 dsr = regs->DIER & regs->SR; - void (**hs)(void) = dev->handlers; - uint32 handled = 0; - - handle_irq(dsr, TIMER_SR_TIF, hs, TIMER_TRG_INTERRUPT, handled); - handle_irq(dsr, TIMER_SR_CC2IF, hs, TIMER_CC2_INTERRUPT, handled); - handle_irq(dsr, TIMER_SR_CC1IF, hs, TIMER_CC1_INTERRUPT, handled); - handle_irq(dsr, TIMER_SR_UIF, hs, TIMER_UPDATE_INTERRUPT, handled); - - regs->SR &= ~handled; -} - -/* On F1 (XL-density), F2, and F4, timers 10, 11, 13, and 14 are - * restricted general-purpose timers with update and CC1 interrupts. */ -static __always_inline void dispatch_tim_10_11_13_14(timer_dev *dev) { - timer_gen_reg_map *regs = (dev->regs).gen; - uint32 dsr = regs->DIER & regs->SR; - void (**hs)(void) = dev->handlers; - uint32 handled = 0; - - handle_irq(dsr, TIMER_SR_CC1IF, hs, TIMER_CC1_INTERRUPT, handled); - handle_irq(dsr, TIMER_SR_UIF, hs, TIMER_UPDATE_INTERRUPT, handled); - - regs->SR &= ~handled; -} - -static __always_inline void dispatch_basic(timer_dev *dev) { - dispatch_single_irq(dev, TIMER_UPDATE_INTERRUPT, TIMER_SR_UIF); -} - -#endif diff --git a/STM32F3/cores/maple/libmaple/usart.c b/STM32F3/cores/maple/libmaple/usart.c deleted file mode 100644 index 52da4d1..0000000 --- a/STM32F3/cores/maple/libmaple/usart.c +++ /dev/null @@ -1,122 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * Copyright (c) 2011 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/usart.c - * @author Marti Bolivar , - * Perry Hung - * @brief Portable USART routines - */ - -#include - -/** - * @brief Initialize a serial port. - * @param dev Serial port to be initialized - */ -void usart_init(usart_dev *dev) { - rb_init(dev->rb, USART_RX_BUF_SIZE, dev->rx_buf); - rcc_clk_enable(dev->clk_id); - nvic_irq_enable(dev->irq_num); -} - -/** - * @brief Enable a serial port. - * - * USART is enabled in single buffer transmission mode, multibuffer - * receiver mode, 8n1. - * - * Serial port must have a baud rate configured to work properly. - * - * @param dev Serial port to enable. - * @see usart_set_baud_rate() - */ -void usart_enable(usart_dev *dev) { - usart_reg_map *regs = dev->regs; - regs->CR1 = (USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE | - USART_CR1_M_8N1); - regs->CR1 |= USART_CR1_UE; -} - -/** - * @brief Turn off a serial port. - * @param dev Serial port to be disabled - */ -void usart_disable(usart_dev *dev) { - /* FIXME this misbehaves (on F1) if you try to use PWM on TX afterwards */ - usart_reg_map *regs = dev->regs; - - /* TC bit must be high before disabling the USART */ - while((regs->CR1 & USART_CR1_UE) && !(regs->SR & USART_SR_TC)) - ; - - /* Disable UE */ - regs->CR1 &= ~USART_CR1_UE; - - /* Clean up buffer */ - usart_reset_rx(dev); -} - -/** - * @brief Nonblocking USART receive. - * @param dev Serial port to receive bytes from - * @param buf Buffer to store received bytes into - * @param len Maximum number of bytes to store - * @return Number of bytes received - */ -uint32 usart_rx(usart_dev *dev, uint8 *buf, uint32 len) { - uint32 rxed = 0; - while (usart_data_available(dev) && rxed < len) { - *buf++ = usart_getc(dev); - rxed++; - } - return rxed; -} - -/** - * @brief Transmit an unsigned integer to the specified serial port in - * decimal format. - * - * This function blocks until the integer's digits have been - * completely transmitted. - * - * @param dev Serial port to send on - * @param val Number to print - */ -void usart_putudec(usart_dev *dev, uint32 val) { - char digits[12]; - int i = 0; - - do { - digits[i++] = val % 10 + '0'; - val /= 10; - } while (val > 0); - - while (--i >= 0) { - usart_putc(dev, digits[i]); - } -} diff --git a/STM32F3/cores/maple/libmaple/usart_private.c b/STM32F3/cores/maple/libmaple/usart_private.c deleted file mode 100644 index 0eaacdf..0000000 --- a/STM32F3/cores/maple/libmaple/usart_private.c +++ /dev/null @@ -1,41 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/usart_private.c - * @author Marti Bolivar - * @brief Private USART routines. - */ - -#include "usart_private.h" -#include -#include - -uint32 _usart_clock_freq(usart_dev *dev) { - rcc_clk_domain domain = rcc_dev_clk(dev->clk_id); - return (domain == RCC_APB1 ? STM32_PCLK1 : - (domain == RCC_APB2 ? STM32_PCLK2 : 0)); -} diff --git a/STM32F3/cores/maple/libmaple/usart_private.h b/STM32F3/cores/maple/libmaple/usart_private.h deleted file mode 100644 index e6044d8..0000000 --- a/STM32F3/cores/maple/libmaple/usart_private.h +++ /dev/null @@ -1,42 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2012 LeafLabs, LLC. - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/usart_private.h - * @author Marti Bolivar - * @brief Private USART header. - */ - -#ifndef _LIBMAPLE_USART_PRIVATE_H_ -#define _LIBMAPLE_USART_PRIVATE_H_ - -#include -#include - -uint32 _usart_clock_freq(usart_dev *dev); - -#endif diff --git a/STM32F3/cores/maple/libmaple/usb/README b/STM32F3/cores/maple/libmaple/usb/README deleted file mode 100644 index d0fca8d..0000000 --- a/STM32F3/cores/maple/libmaple/usb/README +++ /dev/null @@ -1,63 +0,0 @@ -The USB submodule of libmaple is a separate piece of the codebase for -reasons that are largely historical. - -Current Status: - - There's only support for the USB device peripheral found on - STM32F103s. - - We rely on the low level core library provided by ST to implement - the USB transfer protocol for control endpoint transfers. - - The virtual com port (which is exposed via - ) serves two important purposes. - - 1) It allows serial data transfers between user sketches an a - host computer. - - 2) It allows the host PC to issue a system reset into the DFU - bootloader with the DTR + RTS + "1EAF" sequence (see - leaflabs.com/docs/bootloader.html for more information on - this). - - After reset, Maple will run the DFU bootloader for a few seconds, - during which the user can begin a DFU upload operation (uploads - application binary into RAM/FLASH). Thus, without this virtual com - port, it would be necessary to find an alternative means to reset - the chip in order to enable the bootloader. - - If you would like to develop your own USB application for whatever - reason (e.g. to use faster isochronous enpoints for streaming - audio, or implement the USB HID or Mass Storage specs), then - ensure that you leave some hook for resetting Maple remotely in - order to spin up the DFU bootloader. Please make sure to get - yourself a unique vendor/product ID pair for your application, as - some operating systems will assign a host-side driver based on - these tags. - - It would be possible to build a compound USB device, that - implements endpoints for both the virtual COM port as well as some - other components (mass storage etc.). However, this turns out to - be a burden from the host driver side, as Windows and *nix handle - compound USB devices quite differently. - - Be mindful that enabling the USB peripheral isn't "free." The - device must respond to periodic bus activity (every few - milliseconds) by servicing an ISR. Therefore, the USB application - should be disabled inside of timing critical applications. - - In order to disconnect the device from the host, a USB_DISC pin is - asserted (e.g. on Maple, this is PC12). Alternatively, the NVIC - can be directly configured to disable the USB LP/HP IRQ's. - - The files inside of usb_lib were provided by ST and are subject to - their own license, all other files were written by the LeafLabs - team and fall under the MIT license. - -TODO: - - - Generic USB driver core with series-provided backends, like - libopencm3 has. - - Strip out ST code. - - Integration with a high level USB library (like LUFA/MyUSB) to - allow users to write custom USB applications. diff --git a/STM32F3/cores/maple/libmaple/usb/usb.c b/STM32F3/cores/maple/libmaple/usb/usb.c deleted file mode 100644 index f694f04..0000000 --- a/STM32F3/cores/maple/libmaple/usb/usb.c +++ /dev/null @@ -1,387 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 LeafLabs LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/usb/stm32f1/usb.c - * @brief USB support. - * - * This is a mess. - */ - -#include - -#include -#include - -/* Private headers */ -#include "usb_reg_map.h" -#include "usb_lib_globals.h" - -/* usb_lib headers */ -#include "usb_type.h" -#include "usb_core.h" - -static void dispatch_ctr_lp(void); - -/* - * usb_lib/ globals - */ - -uint16 SaveTState; /* caches TX status for later use */ -uint16 SaveRState; /* caches RX status for later use */ - -/* - * Other state - */ - -typedef enum { - RESUME_EXTERNAL, - RESUME_INTERNAL, - RESUME_LATER, - RESUME_WAIT, - RESUME_START, - RESUME_ON, - RESUME_OFF, - RESUME_ESOF -} RESUME_STATE; - -struct { - volatile RESUME_STATE eState; - volatile uint8 bESOFcnt; -} ResumeS; - -static usblib_dev usblib = { - .irq_mask = USB_ISR_MSK, - .state = USB_UNCONNECTED, - .prevState = USB_UNCONNECTED, - .clk_id = RCC_USB, -}; -usblib_dev *USBLIB = &usblib; - -/* - * Routines - */ - -void usb_init_usblib(usblib_dev *dev, - void (**ep_int_in)(void), - void (**ep_int_out)(void)) { - rcc_clk_enable(dev->clk_id); - - dev->ep_int_in = ep_int_in; - dev->ep_int_out = ep_int_out; - - /* usb_lib/ declares both and then assumes that pFoo points to Foo - * (even though the names don't always match), which is stupid for - * all of the obvious reasons, but whatever. Here we are. */ - pInformation = &Device_Info; - pProperty = &Device_Property; - pUser_Standard_Requests = &User_Standard_Requests; - - pInformation->ControlState = 2; /* FIXME [0.0.12] use - CONTROL_STATE enumerator */ - pProperty->Init(); -} - -static void usb_suspend(void) { - uint16 cntr; - - /* TODO decide if read/modify/write is really what we want - * (e.g. usb_resume_init() reconfigures CNTR). */ - cntr = USB_BASE->CNTR; - cntr |= USB_CNTR_FSUSP; - USB_BASE->CNTR = cntr; - cntr |= USB_CNTR_LP_MODE; - USB_BASE->CNTR = cntr; - - USBLIB->prevState = USBLIB->state; - USBLIB->state = USB_SUSPENDED; -} - -static void usb_resume_init(void) { - uint16 cntr; - - cntr = USB_BASE->CNTR; - cntr &= ~USB_CNTR_LP_MODE; - USB_BASE->CNTR = cntr; - - /* Enable interrupt lines */ - USB_BASE->CNTR = USB_ISR_MSK; -} - -static void usb_resume(RESUME_STATE eResumeSetVal) { - uint16 cntr; - - if (eResumeSetVal != RESUME_ESOF) { - ResumeS.eState = eResumeSetVal; - } - - switch (ResumeS.eState) { - case RESUME_EXTERNAL: - usb_resume_init(); - ResumeS.eState = RESUME_OFF; - USBLIB->state = USBLIB->prevState; - break; - case RESUME_INTERNAL: - usb_resume_init(); - ResumeS.eState = RESUME_START; - break; - case RESUME_LATER: - ResumeS.bESOFcnt = 2; - ResumeS.eState = RESUME_WAIT; - break; - case RESUME_WAIT: - ResumeS.bESOFcnt--; - if (ResumeS.bESOFcnt == 0) { - ResumeS.eState = RESUME_START; - } - break; - case RESUME_START: - cntr = USB_BASE->CNTR; - cntr |= USB_CNTR_RESUME; - USB_BASE->CNTR = cntr; - ResumeS.eState = RESUME_ON; - ResumeS.bESOFcnt = 10; - break; - case RESUME_ON: - ResumeS.bESOFcnt--; - if (ResumeS.bESOFcnt == 0) { - cntr = USB_BASE->CNTR; - cntr &= ~USB_CNTR_RESUME; - USB_BASE->CNTR = cntr; - USBLIB->state = USBLIB->prevState; - ResumeS.eState = RESUME_OFF; - } - break; - case RESUME_OFF: - case RESUME_ESOF: - default: - ResumeS.eState = RESUME_OFF; - break; - } -} - -#define SUSPEND_ENABLED 1 -void __irq_usb_lp_can_rx0(void) { - uint16 istr = USB_BASE->ISTR; - - /* Use USB_ISR_MSK to only include code for bits we care about. */ - -#if (USB_ISR_MSK & USB_ISTR_RESET) - if (istr & USB_ISTR_RESET & USBLIB->irq_mask) { - USB_BASE->ISTR = ~USB_ISTR_RESET; - pProperty->Reset(); - } -#endif - -#if (USB_ISR_MSK & USB_ISTR_PMAOVR) - if (istr & ISTR_PMAOVR & USBLIB->irq_mask) { - USB_BASE->ISTR = ~USB_ISTR_PMAOVR; - } -#endif - -#if (USB_ISR_MSK & USB_ISTR_ERR) - if (istr & USB_ISTR_ERR & USBLIB->irq_mask) { - USB_BASE->ISTR = ~USB_ISTR_ERR; - } -#endif - -#if (USB_ISR_MSK & USB_ISTR_WKUP) - if (istr & USB_ISTR_WKUP & USBLIB->irq_mask) { - USB_BASE->ISTR = ~USB_ISTR_WKUP; - usb_resume(RESUME_EXTERNAL); - } -#endif - -#if (USB_ISR_MSK & USB_ISTR_SUSP) - if (istr & USB_ISTR_SUSP & USBLIB->irq_mask) { - /* check if SUSPEND is possible */ - if (SUSPEND_ENABLED) { - usb_suspend(); - } else { - /* if not possible then resume after xx ms */ - usb_resume(RESUME_LATER); - } - /* clear of the ISTR bit must be done after setting of CNTR_FSUSP */ - USB_BASE->ISTR = ~USB_ISTR_SUSP; - } -#endif - -#if (USB_ISR_MSK & USB_ISTR_SOF) - if (istr & USB_ISTR_SOF & USBLIB->irq_mask) { - USB_BASE->ISTR = ~USB_ISTR_SOF; - } -#endif - -#if (USB_ISR_MSK & USB_ISTR_ESOF) - if (istr & USB_ISTR_ESOF & USBLIB->irq_mask) { - USB_BASE->ISTR = ~USB_ISTR_ESOF; - /* resume handling timing is made with ESOFs */ - usb_resume(RESUME_ESOF); /* request without change of the machine state */ - } -#endif - - /* - * Service the correct transfer interrupt. - */ - -#if (USB_ISR_MSK & USB_ISTR_CTR) - if (istr & USB_ISTR_CTR & USBLIB->irq_mask) { - dispatch_ctr_lp(); - } -#endif -} - -/* - * Auxiliary routines - */ - -static inline uint8 dispatch_endpt_zero(uint16 istr_dir); -static inline void dispatch_endpt(uint8 ep); -static inline void set_rx_tx_status0(uint16 rx, uint16 tx); - -static void handle_setup0(void); -static void handle_in0(void); -static void handle_out0(void); - -static void dispatch_ctr_lp() { - uint16 istr; - while (((istr = USB_BASE->ISTR) & USB_ISTR_CTR) != 0) { - /* TODO WTF, figure this out: RM0008 says CTR is read-only, - * but ST's firmware claims it's clear-only, and emphasizes - * the importance of clearing it in more than one place. */ - USB_BASE->ISTR = ~USB_ISTR_CTR; - uint8 ep_id = istr & USB_ISTR_EP_ID; - if (ep_id == 0) { - /* TODO figure out why it's OK to break out of the loop - * once we're done serving endpoint zero, but not okay if - * there are multiple nonzero endpoint transfers to - * handle. */ - if (dispatch_endpt_zero(istr & USB_ISTR_DIR)) { - return; - } - } else { - dispatch_endpt(ep_id); - } - } -} - -/* FIXME Dataflow on endpoint 0 RX/TX status is based off of ST's - * code, and is ugly/confusing in its use of SaveRState/SaveTState. - * Fixing this requires filling in handle_in0(), handle_setup0(), - * handle_out0(). */ -static inline uint8 dispatch_endpt_zero(uint16 istr_dir) { - uint32 epr = (uint16)USB_BASE->EP[0]; - - if (!(epr & (USB_EP_CTR_TX | USB_EP_SETUP | USB_EP_CTR_RX))) { - return 0; - } - - /* Cache RX/TX statuses in SaveRState/SaveTState, respectively. - * The various handle_foo0() may clobber these values - * before we reset them at the end of this routine. */ - SaveRState = epr & USB_EP_STAT_RX; - SaveTState = epr & USB_EP_STAT_TX; - - /* Set actual RX/TX statuses to NAK while we're thinking */ - set_rx_tx_status0(USB_EP_STAT_RX_NAK, USB_EP_STAT_TX_NAK); - - if (istr_dir == 0) { - /* ST RM0008: "If DIR bit=0, CTR_TX bit is set in the USB_EPnR - * register related to the interrupting endpoint. The - * interrupting transaction is of IN type (data transmitted by - * the USB peripheral to the host PC)." */ - ASSERT_FAULT(epr & USB_EP_CTR_TX); - usb_clear_ctr_tx(USB_EP0); - handle_in0(); - } else { - /* RM0008: "If DIR bit=1, CTR_RX bit or both CTR_TX/CTR_RX - * are set in the USB_EPnR register related to the - * interrupting endpoint. The interrupting transaction is of - * OUT type (data received by the USB peripheral from the host - * PC) or two pending transactions are waiting to be - * processed." - * - * [mbolivar] Note how the following control flow (which - * replicates ST's) doesn't seem to actually handle both - * interrupts that are ostensibly pending when both CTR_RX and - * CTR_TX are set. - * - * TODO sort this mess out. - */ - if (epr & USB_EP_CTR_TX) { - usb_clear_ctr_tx(USB_EP0); - handle_in0(); - } else { /* SETUP or CTR_RX */ - /* SETUP is held constant while CTR_RX is set, so clear it - * either way */ - usb_clear_ctr_rx(USB_EP0); - if (epr & USB_EP_SETUP) { - handle_setup0(); - } else { /* CTR_RX */ - handle_out0(); - } - } - } - - set_rx_tx_status0(SaveRState, SaveTState); - return 1; -} - -static inline void dispatch_endpt(uint8 ep) { - uint32 epr = USB_BASE->EP[ep]; - /* If ISTR_CTR is set and the ISTR gave us this EP_ID to handle, - * then presumably at least one of CTR_RX and CTR_TX is set, but - * again, ST's control flow allows for the possibility of neither. - * - * TODO try to find out if neither being set is possible. */ - if (epr & USB_EP_CTR_RX) { - usb_clear_ctr_rx(ep); - (USBLIB->ep_int_out[ep - 1])(); - } - if (epr & USB_EP_CTR_TX) { - usb_clear_ctr_tx(ep); - (USBLIB->ep_int_in[ep - 1])(); - } -} - -static inline void set_rx_tx_status0(uint16 rx, uint16 tx) { - usb_set_ep_rx_stat(USB_EP0, rx); - usb_set_ep_tx_stat(USB_EP0, tx); -} - -/* TODO Rip out usb_lib/ dependency from the following functions: */ - -static void handle_setup0(void) { - Setup0_Process(); -} - -static void handle_in0(void) { - In0_Process(); -} - -static void handle_out0(void) { - Out0_Process(); -} diff --git a/STM32F3/cores/maple/libmaple/usb/usb_cdcacm.c b/STM32F3/cores/maple/libmaple/usb/usb_cdcacm.c deleted file mode 100644 index bafb90b..0000000 --- a/STM32F3/cores/maple/libmaple/usb/usb_cdcacm.c +++ /dev/null @@ -1,723 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2011 LeafLabs LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/usb/stm32f1/usb_cdcacm.c - * @brief USB CDC ACM (a.k.a. virtual serial terminal, VCOM). - * - * FIXME: this works on the STM32F1 USB peripherals, and probably no - * place else. Nonportable bits really need to be factored out, and - * the result made cleaner. - */ - -#include - -#include -#include -#include - -/* Private headers */ -#include "usb_lib_globals.h" -#include "usb_reg_map.h" - -/* usb_lib headers */ -#include "usb_type.h" -#include "usb_core.h" -#include "usb_def.h" - -/****************************************************************************** - ****************************************************************************** - *** - *** HACK ALERT! FIXME FIXME FIXME FIXME! - *** - *** A bunch of LeafLabs-specific configuration lives in here for - *** now. This mess REALLY needs to get teased apart, with - *** appropriate pieces moved into Wirish. - *** - ****************************************************************************** - *****************************************************************************/ - -#if !(defined(BOARD_maple_mini_f3)) -#warning USB CDC ACM relies on LeafLabs board-specific configuration.\ - You may have problems on non-LeafLabs boards. -#endif - -static void vcomDataTxCb(void); -static void vcomDataRxCb(void); -static uint8* vcomGetSetLineCoding(uint16); - -static void usbInit(void); -static void usbReset(void); -static RESULT usbDataSetup(uint8 request); -static RESULT usbNoDataSetup(uint8 request); -static RESULT usbGetInterfaceSetting(uint8 interface, uint8 alt_setting); -static uint8* usbGetDeviceDescriptor(uint16 length); -static uint8* usbGetConfigDescriptor(uint16 length); -static uint8* usbGetStringDescriptor(uint16 length); -static void usbSetConfiguration(void); -static void usbSetDeviceAddress(void); - -/* - * Descriptors - */ - -/* FIXME move to Wirish */ -#define LEAFLABS_ID_VENDOR 0x1EAF -#define MAPLE_ID_PRODUCT 0x0004 -static const usb_descriptor_device usbVcomDescriptor_Device = - USB_CDCACM_DECLARE_DEV_DESC(LEAFLABS_ID_VENDOR, MAPLE_ID_PRODUCT); - -typedef struct { - usb_descriptor_config_header Config_Header; - usb_descriptor_interface CCI_Interface; - CDC_FUNCTIONAL_DESCRIPTOR(2) CDC_Functional_IntHeader; - CDC_FUNCTIONAL_DESCRIPTOR(2) CDC_Functional_CallManagement; - CDC_FUNCTIONAL_DESCRIPTOR(1) CDC_Functional_ACM; - CDC_FUNCTIONAL_DESCRIPTOR(2) CDC_Functional_Union; - usb_descriptor_endpoint ManagementEndpoint; - usb_descriptor_interface DCI_Interface; - usb_descriptor_endpoint DataOutEndpoint; - usb_descriptor_endpoint DataInEndpoint; -} __packed usb_descriptor_config; - -#define MAX_POWER (100 >> 1) -static const usb_descriptor_config usbVcomDescriptor_Config = { - .Config_Header = { - .bLength = sizeof(usb_descriptor_config_header), - .bDescriptorType = USB_DESCRIPTOR_TYPE_CONFIGURATION, - .wTotalLength = sizeof(usb_descriptor_config), - .bNumInterfaces = 0x02, - .bConfigurationValue = 0x01, - .iConfiguration = 0x00, - .bmAttributes = (USB_CONFIG_ATTR_BUSPOWERED | - USB_CONFIG_ATTR_SELF_POWERED), - .bMaxPower = MAX_POWER, - }, - - .CCI_Interface = { - .bLength = sizeof(usb_descriptor_interface), - .bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE, - .bInterfaceNumber = 0x00, - .bAlternateSetting = 0x00, - .bNumEndpoints = 0x01, - .bInterfaceClass = USB_INTERFACE_CLASS_CDC, - .bInterfaceSubClass = USB_INTERFACE_SUBCLASS_CDC_ACM, - .bInterfaceProtocol = 0x01, /* Common AT Commands */ - .iInterface = 0x00, - }, - - .CDC_Functional_IntHeader = { - .bLength = CDC_FUNCTIONAL_DESCRIPTOR_SIZE(2), - .bDescriptorType = 0x24, - .SubType = 0x00, - .Data = {0x01, 0x10}, - }, - - .CDC_Functional_CallManagement = { - .bLength = CDC_FUNCTIONAL_DESCRIPTOR_SIZE(2), - .bDescriptorType = 0x24, - .SubType = 0x01, - .Data = {0x03, 0x01}, - }, - - .CDC_Functional_ACM = { - .bLength = CDC_FUNCTIONAL_DESCRIPTOR_SIZE(1), - .bDescriptorType = 0x24, - .SubType = 0x02, - .Data = {0x06}, - }, - - .CDC_Functional_Union = { - .bLength = CDC_FUNCTIONAL_DESCRIPTOR_SIZE(2), - .bDescriptorType = 0x24, - .SubType = 0x06, - .Data = {0x00, 0x01}, - }, - - .ManagementEndpoint = { - .bLength = sizeof(usb_descriptor_endpoint), - .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT, - .bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_IN | - USB_CDCACM_MANAGEMENT_ENDP), - .bmAttributes = USB_EP_TYPE_INTERRUPT, - .wMaxPacketSize = USB_CDCACM_MANAGEMENT_EPSIZE, - .bInterval = 0xFF, - }, - - .DCI_Interface = { - .bLength = sizeof(usb_descriptor_interface), - .bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE, - .bInterfaceNumber = 0x01, - .bAlternateSetting = 0x00, - .bNumEndpoints = 0x02, - .bInterfaceClass = USB_INTERFACE_CLASS_DIC, - .bInterfaceSubClass = 0x00, /* None */ - .bInterfaceProtocol = 0x00, /* None */ - .iInterface = 0x00, - }, - - .DataOutEndpoint = { - .bLength = sizeof(usb_descriptor_endpoint), - .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT, - .bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_OUT | - USB_CDCACM_RX_ENDP), - .bmAttributes = USB_EP_TYPE_BULK, - .wMaxPacketSize = USB_CDCACM_RX_EPSIZE, - .bInterval = 0x00, - }, - - .DataInEndpoint = { - .bLength = sizeof(usb_descriptor_endpoint), - .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT, - .bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_IN | USB_CDCACM_TX_ENDP), - .bmAttributes = USB_EP_TYPE_BULK, - .wMaxPacketSize = USB_CDCACM_TX_EPSIZE, - .bInterval = 0x00, - }, -}; - -/* - String Descriptors: - - we may choose to specify any or none of the following string - identifiers: - - iManufacturer: LeafLabs - iProduct: Maple - iSerialNumber: NONE - iConfiguration: NONE - iInterface(CCI): NONE - iInterface(DCI): NONE - -*/ - -/* Unicode language identifier: 0x0409 is US English */ -/* FIXME move to Wirish */ -static const usb_descriptor_string usbVcomDescriptor_LangID = { - .bLength = USB_DESCRIPTOR_STRING_LEN(1), - .bDescriptorType = USB_DESCRIPTOR_TYPE_STRING, - .bString = {0x09, 0x04}, -}; - -/* FIXME move to Wirish */ -static const usb_descriptor_string usbVcomDescriptor_iManufacturer = { - .bLength = USB_DESCRIPTOR_STRING_LEN(8), - .bDescriptorType = USB_DESCRIPTOR_TYPE_STRING, - .bString = {'L', 0, 'e', 0, 'a', 0, 'f', 0, - 'L', 0, 'a', 0, 'b', 0, 's', 0}, -}; - -/* FIXME move to Wirish */ -static const usb_descriptor_string usbVcomDescriptor_iProduct = { - .bLength = USB_DESCRIPTOR_STRING_LEN(5), - .bDescriptorType = USB_DESCRIPTOR_TYPE_STRING, - .bString = {'M', 0, 'a', 0, 'p', 0, 'l', 0, 'e', 0}, -}; - -static ONE_DESCRIPTOR Device_Descriptor = { - (uint8*)&usbVcomDescriptor_Device, - sizeof(usb_descriptor_device) -}; - -static ONE_DESCRIPTOR Config_Descriptor = { - (uint8*)&usbVcomDescriptor_Config, - sizeof(usb_descriptor_config) -}; - -#define N_STRING_DESCRIPTORS 3 -static ONE_DESCRIPTOR String_Descriptor[N_STRING_DESCRIPTORS] = { - {(uint8*)&usbVcomDescriptor_LangID, USB_DESCRIPTOR_STRING_LEN(1)}, - {(uint8*)&usbVcomDescriptor_iManufacturer,USB_DESCRIPTOR_STRING_LEN(8)}, - {(uint8*)&usbVcomDescriptor_iProduct, USB_DESCRIPTOR_STRING_LEN(5)} -}; - -/* - * Etc. - */ - -/* I/O state */ - -/* Received data */ -static volatile uint8 vcomBufferRx[USB_CDCACM_RX_EPSIZE]; -/* 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; - -/* Other state (line coding, DTR/RTS) */ - -static volatile usb_cdcacm_line_coding line_coding = { - /* This default is 115200 baud, 8N1. */ - .dwDTERate = 115200, - .bCharFormat = USB_CDCACM_STOP_BITS_1, - .bParityType = USB_CDCACM_PARITY_NONE, - .bDataBits = 8, -}; - -/* DTR in bit 0, RTS in bit 1. */ -static volatile uint8 line_dtr_rts = 0; - -/* - * Endpoint callbacks - */ - -static void (*ep_int_in[7])(void) = - {vcomDataTxCb, - NOP_Process, - NOP_Process, - NOP_Process, - NOP_Process, - NOP_Process, - NOP_Process}; - -static void (*ep_int_out[7])(void) = - {NOP_Process, - NOP_Process, - vcomDataRxCb, - NOP_Process, - NOP_Process, - NOP_Process, - NOP_Process}; - -/* - * Globals required by usb_lib/ - * - * Mark these weak so they can be overriden to implement other USB - * functionality. - */ - -#define NUM_ENDPTS 0x04 -__weak DEVICE Device_Table = { - .Total_Endpoint = NUM_ENDPTS, - .Total_Configuration = 1 -}; - -#define MAX_PACKET_SIZE 0x40 /* 64B, maximum for USB FS Devices */ -__weak DEVICE_PROP Device_Property = { - .Init = usbInit, - .Reset = usbReset, - .Process_Status_IN = NOP_Process, - .Process_Status_OUT = NOP_Process, - .Class_Data_Setup = usbDataSetup, - .Class_NoData_Setup = usbNoDataSetup, - .Class_Get_Interface_Setting = usbGetInterfaceSetting, - .GetDeviceDescriptor = usbGetDeviceDescriptor, - .GetConfigDescriptor = usbGetConfigDescriptor, - .GetStringDescriptor = usbGetStringDescriptor, - .RxEP_buffer = NULL, - .MaxPacketSize = MAX_PACKET_SIZE -}; - -__weak USER_STANDARD_REQUESTS User_Standard_Requests = { - .User_GetConfiguration = NOP_Process, - .User_SetConfiguration = usbSetConfiguration, - .User_GetInterface = NOP_Process, - .User_SetInterface = NOP_Process, - .User_GetStatus = NOP_Process, - .User_ClearFeature = NOP_Process, - .User_SetEndPointFeature = NOP_Process, - .User_SetDeviceFeature = NOP_Process, - .User_SetDeviceAddress = usbSetDeviceAddress -}; - -/* - * User hooks - */ - -static void (*rx_hook)(unsigned, void*) = 0; -static void (*iface_setup_hook)(unsigned, void*) = 0; - -void usb_cdcacm_set_hooks(unsigned hook_flags, void (*hook)(unsigned, void*)) { - if (hook_flags & USB_CDCACM_HOOK_RX) { - rx_hook = hook; - } - if (hook_flags & USB_CDCACM_HOOK_IFACE_SETUP) { - iface_setup_hook = hook; - } -} - -/* - * CDC ACM interface - */ - -void usb_cdcacm_enable(gpio_dev *disc_dev, uint8 disc_bit) { - /* Present ourselves to the host. Writing 0 to "disc" pin must - * pull USB_DP pin up while leaving USB_DM pulled down by the - * transceiver. See USB 2.0 spec, section 7.1.7.3. */ - gpio_set_modef(disc_dev, disc_bit, GPIO_MODE_OUTPUT, GPIO_MODEF_TYPE_PP); - gpio_write_bit(disc_dev, disc_bit, 0); - - /* - * set USB_DP and USB_DM pins to alternate mode and set alternate function to USB - */ - gpio_set_modef(GPIOA, 12, GPIO_MODE_AF, GPIO_MODEF_TYPE_PP); - gpio_set_modef(GPIOA, 11, GPIO_MODE_AF, GPIO_MODEF_TYPE_PP); - gpio_set_af(GPIOA, 12, GPIO_AF_14); - gpio_set_af(GPIOA, 11, GPIO_AF_14); - - /* Initialize the USB peripheral. */ - usb_init_usblib(USBLIB, ep_int_in, ep_int_out); -} - -void usb_cdcacm_disable(gpio_dev *disc_dev, uint8 disc_bit) { - /* Turn off the interrupt and signal disconnect (see e.g. USB 2.0 - * spec, section 7.1.7.3). */ - nvic_irq_disable(NVIC_USB_LP_CAN_RX0); - gpio_write_bit(disc_dev, disc_bit, 1); - - /* - * set USB_DP and USB_DM pins to input floating mode, reset alternate function to system default - */ - gpio_set_modef(GPIOA, 12, GPIO_MODE_INPUT, GPIO_MODEF_PUPD_NONE); - gpio_set_modef(GPIOA, 11, GPIO_MODE_INPUT, GPIO_MODEF_PUPD_NONE); - gpio_set_af(GPIOA, 12, GPIO_AF_0); - gpio_set_af(GPIOA, 11, GPIO_AF_0); -} - -void usb_cdcacm_putc(char ch) { - while (!usb_cdcacm_tx((uint8*)&ch, 1)) - ; -} - -/* This function is non-blocking. - * - * It copies data from a usercode 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. */ - if (usb_cdcacm_is_transmitting()) { - return 0; - } - - /* We can only put USB_CDCACM_TX_EPSIZE bytes in the buffer. */ - if (len > USB_CDCACM_TX_EPSIZE) { - len = USB_CDCACM_TX_EPSIZE; - } - - /* Queue bytes for sending. */ - if (len) { - usb_copy_to_pma(buf, len, USB_CDCACM_TX_ADDR); - } - // 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); - - return len; -} - -uint32 usb_cdcacm_data_available(void) { - return n_unread_bytes; -} - -uint8 usb_cdcacm_is_transmitting(void) { - return transmitting; -} - -uint16 usb_cdcacm_get_pending(void) { - return n_unsent_bytes; -} - -/* Nonblocking 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) { - /* Copy bytes to buffer. */ - uint32 n_copied = usb_cdcacm_peek(buf, len); - - /* Mark bytes as read. */ - n_unread_bytes -= n_copied; - rx_offset += n_copied; - - /* 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); - usb_set_ep_rx_stat(USB_CDCACM_RX_ENDP, USB_EP_STAT_RX_VALID); - rx_offset = 0; - } - - return n_copied; -} - -/* Nonblocking byte lookahead. - * - * Looks at unread bytes without marking them as read. */ -uint32 usb_cdcacm_peek(uint8* buf, uint32 len) { - int i; - - if (len > n_unread_bytes) { - len = n_unread_bytes; - } - - for (i = 0; i < len; i++) { - buf[i] = vcomBufferRx[i + rx_offset]; - } - - return len; -} - -uint8 usb_cdcacm_get_dtr() { - return ((line_dtr_rts & USB_CDCACM_CONTROL_LINE_DTR) != 0); -} - -uint8 usb_cdcacm_get_rts() { - return ((line_dtr_rts & USB_CDCACM_CONTROL_LINE_RTS) != 0); -} - -void usb_cdcacm_get_line_coding(usb_cdcacm_line_coding *ret) { - ret->dwDTERate = line_coding.dwDTERate; - ret->bCharFormat = line_coding.bCharFormat; - ret->bParityType = line_coding.bParityType; - ret->bDataBits = line_coding.bDataBits; -} - -int usb_cdcacm_get_baud(void) { - return line_coding.dwDTERate; -} - -int usb_cdcacm_get_stop_bits(void) { - return line_coding.bCharFormat; -} - -int usb_cdcacm_get_parity(void) { - return line_coding.bParityType; -} - -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 vcomDataRxCb(void) { - usb_set_ep_rx_stat(USB_CDCACM_RX_ENDP, USB_EP_STAT_RX_NAK); - n_unread_bytes = 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*)vcomBufferRx, n_unread_bytes, - USB_CDCACM_RX_ADDR); - - - 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); - rx_offset = 0; - } - - if (rx_hook) { - rx_hook(USB_CDCACM_HOOK_RX, 0); - } -} - -static uint8* vcomGetSetLineCoding(uint16 length) { - if (length == 0) { - pInformation->Ctrl_Info.Usb_wLength = sizeof(struct usb_cdcacm_line_coding); - } - return (uint8*)&line_coding; -} - -static void usbInit(void) { - pInformation->Current_Configuration = 0; - - USB_BASE->CNTR = USB_CNTR_FRES; - - USBLIB->irq_mask = 0; - USB_BASE->CNTR = USBLIB->irq_mask; - USB_BASE->ISTR = 0; - USBLIB->irq_mask = USB_CNTR_RESETM | USB_CNTR_SUSPM | USB_CNTR_WKUPM; - USB_BASE->CNTR = USBLIB->irq_mask; - - USB_BASE->ISTR = 0; - USBLIB->irq_mask = USB_ISR_MSK; - USB_BASE->CNTR = USBLIB->irq_mask; - - nvic_irq_enable(NVIC_USB_LP_CAN_RX0); - USBLIB->state = USB_UNCONNECTED; -} - -#define BTABLE_ADDRESS 0x00 -static void usbReset(void) { - pInformation->Current_Configuration = 0; - - /* current feature is current bmAttributes */ - pInformation->Current_Feature = (USB_CONFIG_ATTR_BUSPOWERED | - USB_CONFIG_ATTR_SELF_POWERED); - - USB_BASE->BTABLE = BTABLE_ADDRESS; - - /* setup control endpoint 0 */ - usb_set_ep_type(USB_EP0, USB_EP_EP_TYPE_CONTROL); - usb_set_ep_tx_stat(USB_EP0, USB_EP_STAT_TX_STALL); - usb_set_ep_rx_addr(USB_EP0, USB_CDCACM_CTRL_RX_ADDR); - usb_set_ep_tx_addr(USB_EP0, USB_CDCACM_CTRL_TX_ADDR); - usb_clear_status_out(USB_EP0); - - usb_set_ep_rx_count(USB_EP0, pProperty->MaxPacketSize); - usb_set_ep_rx_stat(USB_EP0, USB_EP_STAT_RX_VALID); - - /* setup management endpoint 1 */ - usb_set_ep_type(USB_CDCACM_MANAGEMENT_ENDP, USB_EP_EP_TYPE_INTERRUPT); - usb_set_ep_tx_addr(USB_CDCACM_MANAGEMENT_ENDP, - USB_CDCACM_MANAGEMENT_ADDR); - usb_set_ep_tx_stat(USB_CDCACM_MANAGEMENT_ENDP, USB_EP_STAT_TX_NAK); - usb_set_ep_rx_stat(USB_CDCACM_MANAGEMENT_ENDP, USB_EP_STAT_RX_DISABLED); - - /* TODO figure out differences in style between RX/TX EP setup */ - - /* set up data endpoint OUT (RX) */ - usb_set_ep_type(USB_CDCACM_RX_ENDP, USB_EP_EP_TYPE_BULK); - usb_set_ep_rx_addr(USB_CDCACM_RX_ENDP, USB_CDCACM_RX_ADDR); - 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); - - /* set up data endpoint IN (TX) */ - usb_set_ep_type(USB_CDCACM_TX_ENDP, USB_EP_EP_TYPE_BULK); - usb_set_ep_tx_addr(USB_CDCACM_TX_ENDP, USB_CDCACM_TX_ADDR); - usb_set_ep_tx_stat(USB_CDCACM_TX_ENDP, USB_EP_STAT_TX_NAK); - usb_set_ep_rx_stat(USB_CDCACM_TX_ENDP, USB_EP_STAT_RX_DISABLED); - - USBLIB->state = USB_ATTACHED; - SetDeviceAddress(0); - - /* Reset the RX/TX state */ - n_unread_bytes = 0; - n_unsent_bytes = 0; - rx_offset = 0; -} - -static RESULT usbDataSetup(uint8 request) { - uint8* (*CopyRoutine)(uint16) = 0; - - if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) { - switch (request) { - case USB_CDCACM_GET_LINE_CODING: - CopyRoutine = vcomGetSetLineCoding; - break; - case USB_CDCACM_SET_LINE_CODING: - CopyRoutine = vcomGetSetLineCoding; - break; - default: - break; - } - - /* Call the user hook. */ - if (iface_setup_hook) { - uint8 req_copy = request; - iface_setup_hook(USB_CDCACM_HOOK_IFACE_SETUP, &req_copy); - } - } - - if (CopyRoutine == NULL) { - return USB_UNSUPPORT; - } - - pInformation->Ctrl_Info.CopyData = CopyRoutine; - pInformation->Ctrl_Info.Usb_wOffset = 0; - (*CopyRoutine)(0); - return USB_SUCCESS; -} - -static RESULT usbNoDataSetup(uint8 request) { - RESULT ret = USB_UNSUPPORT; - - if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) { - switch (request) { - case USB_CDCACM_SET_COMM_FEATURE: - /* We support set comm. feature, but don't handle it. */ - ret = USB_SUCCESS; - break; - case USB_CDCACM_SET_CONTROL_LINE_STATE: - /* Track changes to DTR and RTS. */ - line_dtr_rts = (pInformation->USBwValues.bw.bb0 & - (USB_CDCACM_CONTROL_LINE_DTR | - USB_CDCACM_CONTROL_LINE_RTS)); - ret = USB_SUCCESS; - break; - } - - /* Call the user hook. */ - if (iface_setup_hook) { - uint8 req_copy = request; - iface_setup_hook(USB_CDCACM_HOOK_IFACE_SETUP, &req_copy); - } - } - return ret; -} - -static RESULT usbGetInterfaceSetting(uint8 interface, uint8 alt_setting) { - if (alt_setting > 0) { - return USB_UNSUPPORT; - } else if (interface > 1) { - return USB_UNSUPPORT; - } - - return USB_SUCCESS; -} - -static uint8* usbGetDeviceDescriptor(uint16 length) { - return Standard_GetDescriptorData(length, &Device_Descriptor); -} - -static uint8* usbGetConfigDescriptor(uint16 length) { - return Standard_GetDescriptorData(length, &Config_Descriptor); -} - -static uint8* usbGetStringDescriptor(uint16 length) { - uint8 wValue0 = pInformation->USBwValue0; - - if (wValue0 > N_STRING_DESCRIPTORS) { - return NULL; - } - return Standard_GetDescriptorData(length, &String_Descriptor[wValue0]); -} - -static void usbSetConfiguration(void) { - if (pInformation->Current_Configuration != 0) { - USBLIB->state = USB_CONFIGURED; - } -} - -static void usbSetDeviceAddress(void) { - USBLIB->state = USB_ADDRESSED; -} diff --git a/STM32F3/cores/maple/libmaple/usb/usb_lib/usb_core.c b/STM32F3/cores/maple/libmaple/usb/usb_lib/usb_core.c deleted file mode 100644 index 5cf9e87..0000000 --- a/STM32F3/cores/maple/libmaple/usb/usb_lib/usb_core.c +++ /dev/null @@ -1,1013 +0,0 @@ -/******************** (C) COPYRIGHT 2008 STMicroelectronics ******************** -* File Name : usb_core.c -* Author : MCD Application Team -* Version : V2.2.1 -* Date : 09/22/2008 -* Description : Standard protocol processing (USB v2.0) -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Includes ------------------------------------------------------------------*/ -#include "usb_lib.h" -/* Private typedef -----------------------------------------------------------*/ -/* Private define ------------------------------------------------------------*/ -#define ValBit(VAR,Place) (VAR & (1 << Place)) -#define SetBit(VAR,Place) (VAR |= (1 << Place)) -#define ClrBit(VAR,Place) (VAR &= ((1 << Place) ^ 255)) - -#define Send0LengthData() { _SetEPTxCount(ENDP0, 0); \ - vSetEPTxStatus(EP_TX_VALID); \ - } - -#define vSetEPRxStatus(st) (SaveRState = st) -#define vSetEPTxStatus(st) (SaveTState = st) - -#define USB_StatusIn() Send0LengthData() -#define USB_StatusOut() vSetEPRxStatus(EP_RX_VALID) - -#define StatusInfo0 StatusInfo.bw.bb1 /* Reverse bb0 & bb1 */ -#define StatusInfo1 StatusInfo.bw.bb0 - -/* Private macro -------------------------------------------------------------*/ -/* Private variables ---------------------------------------------------------*/ -u16_u8 StatusInfo; -USB_Bool Data_Mul_MaxPacketSize = FALSE; -/* Private function prototypes -----------------------------------------------*/ -static void DataStageOut(void); -static void DataStageIn(void); -static void NoData_Setup0(void); -static void Data_Setup0(void); -/* Private functions ---------------------------------------------------------*/ - -/******************************************************************************* -* Function Name : Standard_GetConfiguration. -* Description : Return the current configuration variable address. -* Input : Length - How many bytes are needed. -* Output : None. -* Return : Return 1 , if the request is invalid when "Length" is 0. -* Return "Buffer" if the "Length" is not 0. -*******************************************************************************/ -u8 *Standard_GetConfiguration(u16 Length) -{ - if (Length == 0) - { - pInformation->Ctrl_Info.Usb_wLength = - sizeof(pInformation->Current_Configuration); - return 0; - } - pUser_Standard_Requests->User_GetConfiguration(); - return (u8 *)&pInformation->Current_Configuration; -} - -/******************************************************************************* -* Function Name : Standard_SetConfiguration. -* Description : This routine is called to set the configuration value -* Then each class should configure device themself. -* Input : None. -* Output : None. -* Return : Return USB_SUCCESS, if the request is performed. -* Return USB_UNSUPPORT, if the request is invalid. -*******************************************************************************/ -RESULT Standard_SetConfiguration(void) -{ - - if ((pInformation->USBwValue0 <= - Device_Table.Total_Configuration) && (pInformation->USBwValue1 == 0) - && (pInformation->USBwIndex == 0)) /*call Back usb spec 2.0*/ - { - pInformation->Current_Configuration = pInformation->USBwValue0; - pUser_Standard_Requests->User_SetConfiguration(); - return USB_SUCCESS; - } - else - { - return USB_UNSUPPORT; - } -} - -/******************************************************************************* -* Function Name : Standard_GetInterface. -* Description : Return the Alternate Setting of the current interface. -* Input : Length - How many bytes are needed. -* Output : None. -* Return : Return 0, if the request is invalid when "Length" is 0. -* Return "Buffer" if the "Length" is not 0. -*******************************************************************************/ -u8 *Standard_GetInterface(u16 Length) -{ - if (Length == 0) - { - pInformation->Ctrl_Info.Usb_wLength = - sizeof(pInformation->Current_AlternateSetting); - return 0; - } - pUser_Standard_Requests->User_GetInterface(); - return (u8 *)&pInformation->Current_AlternateSetting; -} - -/******************************************************************************* -* Function Name : Standard_SetInterface. -* Description : This routine is called to set the interface. -* Then each class should configure the interface them self. -* Input : None. -* Output : None. -* Return : - Return USB_SUCCESS, if the request is performed. -* - Return USB_UNSUPPORT, if the request is invalid. -*******************************************************************************/ -RESULT Standard_SetInterface(void) -{ - RESULT Re; - /*Test if the specified Interface and Alternate Setting are supported by - the application Firmware*/ - Re = (*pProperty->Class_Get_Interface_Setting)(pInformation->USBwIndex0, pInformation->USBwValue0); - - if (pInformation->Current_Configuration != 0) - { - if ((Re != USB_SUCCESS) || (pInformation->USBwIndex1 != 0) - || (pInformation->USBwValue1 != 0)) - { - return USB_UNSUPPORT; - } - else if (Re == USB_SUCCESS) - { - pUser_Standard_Requests->User_SetInterface(); - pInformation->Current_Interface = pInformation->USBwIndex0; - pInformation->Current_AlternateSetting = pInformation->USBwValue0; - return USB_SUCCESS; - } - - } - - return USB_UNSUPPORT; -} - -/******************************************************************************* -* Function Name : Standard_GetStatus. -* Description : Copy the device request data to "StatusInfo buffer". -* Input : - Length - How many bytes are needed. -* Output : None. -* Return : Return 0, if the request is at end of data block, -* or is invalid when "Length" is 0. -*******************************************************************************/ -u8 *Standard_GetStatus(u16 Length) -{ - if (Length == 0) - { - pInformation->Ctrl_Info.Usb_wLength = 2; - return 0; - } - - StatusInfo.w = 0; - /* Reset Status Information */ - - if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)) - { - /*Get Device Status */ - u8 Feature = pInformation->Current_Feature; - - /* Remote Wakeup enabled */ - if (ValBit(Feature, 5)) - { - SetBit(StatusInfo0, 1); - } - - /* Bus-powered */ - if (ValBit(Feature, 6)) - { - ClrBit(StatusInfo0, 0); - } - else /* Self-powered */ - { - SetBit(StatusInfo0, 0); - } - } - /*Interface Status*/ - else if (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT)) - { - return (u8 *)&StatusInfo; - } - /*Get EndPoint Status*/ - else if (Type_Recipient == (STANDARD_REQUEST | ENDPOINT_RECIPIENT)) - { - u8 Related_Endpoint; - u8 wIndex0 = pInformation->USBwIndex0; - - Related_Endpoint = (wIndex0 & 0x0f); - if (ValBit(wIndex0, 7)) - { - /* IN endpoint */ - if (_GetTxStallStatus(Related_Endpoint)) - { - SetBit(StatusInfo0, 0); /* IN Endpoint stalled */ - } - } - else - { - /* OUT endpoint */ - if (_GetRxStallStatus(Related_Endpoint)) - { - SetBit(StatusInfo0, 0); /* OUT Endpoint stalled */ - } - } - - } - else - { - return NULL; - } - pUser_Standard_Requests->User_GetStatus(); - return (u8 *)&StatusInfo; -} - -/******************************************************************************* -* Function Name : Standard_ClearFeature. -* Description : Clear or disable a specific feature. -* Input : None. -* Output : None. -* Return : - Return USB_SUCCESS, if the request is performed. -* - Return USB_UNSUPPORT, if the request is invalid. -*******************************************************************************/ -RESULT Standard_ClearFeature(void) -{ - u32 Type_Rec = Type_Recipient; - u32 Status; - - - if (Type_Rec == (STANDARD_REQUEST | DEVICE_RECIPIENT)) - {/*Device Clear Feature*/ - ClrBit(pInformation->Current_Feature, 5); - return USB_SUCCESS; - } - else if (Type_Rec == (STANDARD_REQUEST | ENDPOINT_RECIPIENT)) - {/*EndPoint Clear Feature*/ - DEVICE* pDev; - u32 Related_Endpoint; - u32 wIndex0; - u32 rEP; - - if ((pInformation->USBwValue != ENDPOINT_STALL) - || (pInformation->USBwIndex1 != 0)) - { - return USB_UNSUPPORT; - } - - pDev = &Device_Table; - wIndex0 = pInformation->USBwIndex0; - rEP = wIndex0 & ~0x80; - Related_Endpoint = ENDP0 + rEP; - - if (ValBit(pInformation->USBwIndex0, 7)) - { - /*Get Status of endpoint & stall the request if the related_ENdpoint - is Disabled*/ - Status = _GetEPTxStatus(Related_Endpoint); - } - else - { - Status = _GetEPRxStatus(Related_Endpoint); - } - - if ((rEP >= pDev->Total_Endpoint) || (Status == 0) - || (pInformation->Current_Configuration == 0)) - { - return USB_UNSUPPORT; - } - - - if (wIndex0 & 0x80) - { - /* IN endpoint */ - if (_GetTxStallStatus(Related_Endpoint )) - { - ClearDTOG_TX(Related_Endpoint); - SetEPTxStatus(Related_Endpoint, EP_TX_VALID); - } - } - else - { - /* OUT endpoint */ - if (_GetRxStallStatus(Related_Endpoint)) - { - if (Related_Endpoint == ENDP0) - { - /* After clear the STALL, enable the default endpoint receiver */ - SetEPRxCount(Related_Endpoint, Device_Property.MaxPacketSize); - _SetEPRxStatus(Related_Endpoint, EP_RX_VALID); - } - else - { - ClearDTOG_RX(Related_Endpoint); - _SetEPRxStatus(Related_Endpoint, EP_RX_VALID); - } - } - } - pUser_Standard_Requests->User_ClearFeature(); - return USB_SUCCESS; - } - - return USB_UNSUPPORT; -} - -/******************************************************************************* -* Function Name : Standard_SetEndPointFeature -* Description : Set or enable a specific feature of EndPoint -* Input : None. -* Output : None. -* Return : - Return USB_SUCCESS, if the request is performed. -* - Return USB_UNSUPPORT, if the request is invalid. -*******************************************************************************/ -RESULT Standard_SetEndPointFeature(void) -{ - u32 wIndex0; - u32 Related_Endpoint; - u32 rEP; - u32 Status; - - wIndex0 = pInformation->USBwIndex0; - rEP = wIndex0 & ~0x80; - Related_Endpoint = ENDP0 + rEP; - - if (ValBit(pInformation->USBwIndex0, 7)) - { - /* get Status of endpoint & stall the request if the related_ENdpoint - is Disabled*/ - Status = _GetEPTxStatus(Related_Endpoint); - } - else - { - Status = _GetEPRxStatus(Related_Endpoint); - } - - if (Related_Endpoint >= Device_Table.Total_Endpoint - || pInformation->USBwValue != 0 || Status == 0 - || pInformation->Current_Configuration == 0) - { - return USB_UNSUPPORT; - } - else - { - if (wIndex0 & 0x80) - { - /* IN endpoint */ - _SetEPTxStatus(Related_Endpoint, EP_TX_STALL); - } - - else - { - /* OUT endpoint */ - _SetEPRxStatus(Related_Endpoint, EP_RX_STALL); - } - } - pUser_Standard_Requests->User_SetEndPointFeature(); - return USB_SUCCESS; -} - -/******************************************************************************* -* Function Name : Standard_SetDeviceFeature. -* Description : Set or enable a specific feature of Device. -* Input : None. -* Output : None. -* Return : - Return USB_SUCCESS, if the request is performed. -* - Return USB_UNSUPPORT, if the request is invalid. -*******************************************************************************/ -RESULT Standard_SetDeviceFeature(void) -{ - SetBit(pInformation->Current_Feature, 5); - pUser_Standard_Requests->User_SetDeviceFeature(); - return USB_SUCCESS; -} - -/******************************************************************************* -* Function Name : Standard_GetDescriptorData. -* Description : Standard_GetDescriptorData is used for descriptors transfer. -* : This routine is used for the descriptors resident in Flash -* or RAM -* pDesc can be in either Flash or RAM -* The purpose of this routine is to have a versatile way to -* response descriptors request. It allows user to generate -* certain descriptors with software or read descriptors from -* external storage part by part. -* Input : - Length - Length of the data in this transfer. -* - pDesc - A pointer points to descriptor struct. -* The structure gives the initial address of the descriptor and -* its original size. -* Output : None. -* Return : Address of a part of the descriptor pointed by the Usb_ -* wOffset The buffer pointed by this address contains at least -* Length bytes. -*******************************************************************************/ -u8 *Standard_GetDescriptorData(u16 Length, ONE_DESCRIPTOR *pDesc) -{ - u32 wOffset; - - wOffset = pInformation->Ctrl_Info.Usb_wOffset; - if (Length == 0) - { - pInformation->Ctrl_Info.Usb_wLength = pDesc->Descriptor_Size - wOffset; - return 0; - } - - return pDesc->Descriptor + wOffset; -} - -/******************************************************************************* -* Function Name : DataStageOut. -* Description : Data stage of a Control Write Transfer. -* Input : None. -* Output : None. -* Return : None. -*******************************************************************************/ -void DataStageOut(void) -{ - ENDPOINT_INFO *pEPinfo = &pInformation->Ctrl_Info; - u32 save_rLength; - - save_rLength = pEPinfo->Usb_rLength; - - if (pEPinfo->CopyData && save_rLength) - { - u8 *Buffer; - u32 Length; - - Length = pEPinfo->PacketSize; - if (Length > save_rLength) - { - Length = save_rLength; - } - - Buffer = (*pEPinfo->CopyData)(Length); - pEPinfo->Usb_rLength -= Length; - pEPinfo->Usb_rOffset += Length; - - PMAToUserBufferCopy(Buffer, GetEPRxAddr(ENDP0), Length); - } - - if (pEPinfo->Usb_rLength != 0) - { - vSetEPRxStatus(EP_RX_VALID);/* re-enable for next data reception */ - SetEPTxCount(ENDP0, 0); - vSetEPTxStatus(EP_TX_VALID);/* Expect the host to abort the data OUT stage */ - } - /* Set the next State*/ - if (pEPinfo->Usb_rLength >= pEPinfo->PacketSize) - { - pInformation->ControlState = OUT_DATA; - } - else - { - if (pEPinfo->Usb_rLength > 0) - { - pInformation->ControlState = LAST_OUT_DATA; - } - else if (pEPinfo->Usb_rLength == 0) - { - pInformation->ControlState = WAIT_STATUS_IN; - USB_StatusIn(); - } - } -} - -/******************************************************************************* -* Function Name : DataStageIn. -* Description : Data stage of a Control Read Transfer. -* Input : None. -* Output : None. -* Return : None. -*******************************************************************************/ -void DataStageIn(void) -{ - ENDPOINT_INFO *pEPinfo = &pInformation->Ctrl_Info; - u32 save_wLength = pEPinfo->Usb_wLength; - u32 ControlState = pInformation->ControlState; - - u8 *DataBuffer; - u32 Length; - - if ((save_wLength == 0) && (ControlState == LAST_IN_DATA)) - { - if(Data_Mul_MaxPacketSize == TRUE) - { - /* No more data to send and empty packet */ - Send0LengthData(); - ControlState = LAST_IN_DATA; - Data_Mul_MaxPacketSize = FALSE; - } - else - { - /* No more data to send so STALL the TX Status*/ - ControlState = WAIT_STATUS_OUT; - vSetEPTxStatus(EP_TX_STALL); - } - - goto Expect_Status_Out; - } - - Length = pEPinfo->PacketSize; - ControlState = (save_wLength <= Length) ? LAST_IN_DATA : IN_DATA; - - if (Length > save_wLength) - { - Length = save_wLength; - } - - DataBuffer = (*pEPinfo->CopyData)(Length); - - UserToPMABufferCopy(DataBuffer, GetEPTxAddr(ENDP0), Length); - - SetEPTxCount(ENDP0, Length); - - pEPinfo->Usb_wLength -= Length; - pEPinfo->Usb_wOffset += Length; - vSetEPTxStatus(EP_TX_VALID); - - USB_StatusOut();/* Expect the host to abort the data IN stage */ - -Expect_Status_Out: - pInformation->ControlState = ControlState; -} - -/******************************************************************************* -* Function Name : NoData_Setup0. -* Description : Proceed the processing of setup request without data stage. -* Input : None. -* Output : None. -* Return : None. -*******************************************************************************/ -void NoData_Setup0(void) -{ - RESULT Result = USB_UNSUPPORT; - u32 RequestNo = pInformation->USBbRequest; - u32 ControlState; - - if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)) - { - /* Device Request*/ - /* SET_CONFIGURATION*/ - if (RequestNo == SET_CONFIGURATION) - { - Result = Standard_SetConfiguration(); - } - - /*SET ADDRESS*/ - else if (RequestNo == SET_ADDRESS) - { - if ((pInformation->USBwValue0 > 127) || (pInformation->USBwValue1 != 0) - || (pInformation->USBwIndex != 0) - || (pInformation->Current_Configuration != 0)) - /* Device Address should be 127 or less*/ - { - ControlState = STALLED; - goto exit_NoData_Setup0; - } - else - { - Result = USB_SUCCESS; - } - } - /*SET FEATURE for Device*/ - else if (RequestNo == SET_FEATURE) - { - if ((pInformation->USBwValue0 == DEVICE_REMOTE_WAKEUP) - && (pInformation->USBwIndex == 0) - && (ValBit(pInformation->Current_Feature, 5))) - { - Result = Standard_SetDeviceFeature(); - } - else - { - Result = USB_UNSUPPORT; - } - } - /*Clear FEATURE for Device */ - else if (RequestNo == CLEAR_FEATURE) - { - if (pInformation->USBwValue0 == DEVICE_REMOTE_WAKEUP - && pInformation->USBwIndex == 0 - && ValBit(pInformation->Current_Feature, 5)) - { - Result = Standard_ClearFeature(); - } - else - { - Result = USB_UNSUPPORT; - } - } - - } - - /* Interface Request*/ - else if (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT)) - { - /*SET INTERFACE*/ - if (RequestNo == SET_INTERFACE) - { - Result = Standard_SetInterface(); - } - } - - /* EndPoint Request*/ - else if (Type_Recipient == (STANDARD_REQUEST | ENDPOINT_RECIPIENT)) - { - /*CLEAR FEATURE for EndPoint*/ - if (RequestNo == CLEAR_FEATURE) - { - Result = Standard_ClearFeature(); - } - /* SET FEATURE for EndPoint*/ - else if (RequestNo == SET_FEATURE) - { - Result = Standard_SetEndPointFeature(); - } - } - else - { - Result = USB_UNSUPPORT; - } - - - if (Result != USB_SUCCESS) - { - Result = (*pProperty->Class_NoData_Setup)(RequestNo); - if (Result == USB_NOT_READY) - { - ControlState = PAUSE; - goto exit_NoData_Setup0; - } - } - - if (Result != USB_SUCCESS) - { - ControlState = STALLED; - goto exit_NoData_Setup0; - } - - ControlState = WAIT_STATUS_IN;/* After no data stage SETUP */ - - USB_StatusIn(); - -exit_NoData_Setup0: - pInformation->ControlState = ControlState; - return; -} - -/******************************************************************************* -* Function Name : Data_Setup0. -* Description : Proceed the processing of setup request with data stage. -* Input : None. -* Output : None. -* Return : None. -*******************************************************************************/ -void Data_Setup0(void) -{ - u8 *(*CopyRoutine)(u16); - RESULT Result; - u32 Request_No = pInformation->USBbRequest; - - u32 Related_Endpoint, Reserved; - u32 wOffset, Status; - - - - CopyRoutine = NULL; - wOffset = 0; - - if (Request_No == GET_DESCRIPTOR) - { - if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)) - { - u8 wValue1 = pInformation->USBwValue1; - if (wValue1 == DEVICE_DESCRIPTOR) - { - CopyRoutine = pProperty->GetDeviceDescriptor; - } - else if (wValue1 == CONFIG_DESCRIPTOR) - { - CopyRoutine = pProperty->GetConfigDescriptor; - } - else if (wValue1 == STRING_DESCRIPTOR) - { - CopyRoutine = pProperty->GetStringDescriptor; - } /* End of GET_DESCRIPTOR */ - } - } - - /*GET STATUS*/ - else if ((Request_No == GET_STATUS) && (pInformation->USBwValue == 0) - && (pInformation->USBwLength == 0x0002) - && (pInformation->USBwIndex1 == 0)) - { - /* GET STATUS for Device*/ - if ((Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)) - && (pInformation->USBwIndex == 0)) - { - CopyRoutine = Standard_GetStatus; - } - - /* GET STATUS for Interface*/ - else if (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT)) - { - if (((*pProperty->Class_Get_Interface_Setting)(pInformation->USBwIndex0, 0) == USB_SUCCESS) - && (pInformation->Current_Configuration != 0)) - { - CopyRoutine = Standard_GetStatus; - } - } - - /* GET STATUS for EndPoint*/ - else if (Type_Recipient == (STANDARD_REQUEST | ENDPOINT_RECIPIENT)) - { - Related_Endpoint = (pInformation->USBwIndex0 & 0x0f); - Reserved = pInformation->USBwIndex0 & 0x70; - - if (ValBit(pInformation->USBwIndex0, 7)) - { - /*Get Status of endpoint & stall the request if the related_ENdpoint - is Disabled*/ - Status = _GetEPTxStatus(Related_Endpoint); - } - else - { - Status = _GetEPRxStatus(Related_Endpoint); - } - - if ((Related_Endpoint < Device_Table.Total_Endpoint) && (Reserved == 0) - && (Status != 0)) - { - CopyRoutine = Standard_GetStatus; - } - } - - } - - /*GET CONFIGURATION*/ - else if (Request_No == GET_CONFIGURATION) - { - if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)) - { - CopyRoutine = Standard_GetConfiguration; - } - } - /*GET INTERFACE*/ - else if (Request_No == GET_INTERFACE) - { - if ((Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT)) - && (pInformation->Current_Configuration != 0) && (pInformation->USBwValue == 0) - && (pInformation->USBwIndex1 == 0) && (pInformation->USBwLength == 0x0001) - && ((*pProperty->Class_Get_Interface_Setting)(pInformation->USBwIndex0, 0) == USB_SUCCESS)) - { - CopyRoutine = Standard_GetInterface; - } - - } - - if (CopyRoutine) - { - pInformation->Ctrl_Info.Usb_wOffset = wOffset; - pInformation->Ctrl_Info.CopyData = CopyRoutine; - /* sb in the original the cast to word was directly */ - /* now the cast is made step by step */ - (*CopyRoutine)(0); - Result = USB_SUCCESS; - } - else - { - Result = (*pProperty->Class_Data_Setup)(pInformation->USBbRequest); - if (Result == USB_NOT_READY) - { - pInformation->ControlState = PAUSE; - return; - } - } - - if (pInformation->Ctrl_Info.Usb_wLength == 0xFFFF) - { - /* Data is not ready, wait it */ - pInformation->ControlState = PAUSE; - return; - } - if ((Result == USB_UNSUPPORT) || (pInformation->Ctrl_Info.Usb_wLength == 0)) - { - /* Unsupported request */ - pInformation->ControlState = STALLED; - return; - } - - - if (ValBit(pInformation->USBbmRequestType, 7)) - { - /* Device ==> Host */ - vu32 wLength = pInformation->USBwLength; - - /* Restrict the data length to be the one host asks */ - if (pInformation->Ctrl_Info.Usb_wLength > wLength) - { - pInformation->Ctrl_Info.Usb_wLength = wLength; - } - - else if (pInformation->Ctrl_Info.Usb_wLength < pInformation->USBwLength) - { - if (pInformation->Ctrl_Info.Usb_wLength < pProperty->MaxPacketSize) - { - Data_Mul_MaxPacketSize = FALSE; - } - else if ((pInformation->Ctrl_Info.Usb_wLength % pProperty->MaxPacketSize) == 0) - { - Data_Mul_MaxPacketSize = TRUE; - } - } - - pInformation->Ctrl_Info.PacketSize = pProperty->MaxPacketSize; - DataStageIn(); - } - else - { - pInformation->ControlState = OUT_DATA; - vSetEPRxStatus(EP_RX_VALID); /* enable for next data reception */ - } - - return; -} - -/******************************************************************************* -* Function Name : Setup0_Process -* Description : Get the device request data and dispatch to individual process. -* Input : None. -* Output : None. -* Return : Post0_Process. -*******************************************************************************/ -u8 Setup0_Process(void) -{ - - union - { - u8* b; - u16* w; - } pBuf; - - pBuf.b = PMAAddr + (u8 *)(_GetEPRxAddr(ENDP0) * 2); /* *2 for 32 bits addr */ - - if (pInformation->ControlState != PAUSE) - { - pInformation->USBbmRequestType = *pBuf.b++; /* bmRequestType */ - pInformation->USBbRequest = *pBuf.b++; /* bRequest */ - pBuf.w++; /* word not accessed because of 32 bits addressing */ - pInformation->USBwValue = ByteSwap(*pBuf.w++); /* wValue */ - pBuf.w++; /* word not accessed because of 32 bits addressing */ - pInformation->USBwIndex = ByteSwap(*pBuf.w++); /* wIndex */ - pBuf.w++; /* word not accessed because of 32 bits addressing */ - pInformation->USBwLength = *pBuf.w; /* wLength */ - } - - pInformation->ControlState = SETTING_UP; - if (pInformation->USBwLength == 0) - { - /* Setup with no data stage */ - NoData_Setup0(); - } - else - { - /* Setup with data stage */ - Data_Setup0(); - } - return Post0_Process(); -} - -/******************************************************************************* -* Function Name : In0_Process -* Description : Process the IN token on all default endpoint. -* Input : None. -* Output : None. -* Return : Post0_Process. -*******************************************************************************/ -u8 In0_Process(void) -{ - u32 ControlState = pInformation->ControlState; - - if ((ControlState == IN_DATA) || (ControlState == LAST_IN_DATA)) - { - DataStageIn(); - /* ControlState may be changed outside the function */ - ControlState = pInformation->ControlState; - } - - else if (ControlState == WAIT_STATUS_IN) - { - if ((pInformation->USBbRequest == SET_ADDRESS) && - (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))) - { - SetDeviceAddress(pInformation->USBwValue0); - pUser_Standard_Requests->User_SetDeviceAddress(); - } - (*pProperty->Process_Status_IN)(); - ControlState = STALLED; - } - - else - { - ControlState = STALLED; - } - - pInformation->ControlState = ControlState; - - return Post0_Process(); -} - -/******************************************************************************* -* Function Name : Out0_Process -* Description : Process the OUT token on all default endpoint. -* Input : None. -* Output : None. -* Return : Post0_Process. -*******************************************************************************/ -u8 Out0_Process(void) -{ - u32 ControlState = pInformation->ControlState; - - if ((ControlState == OUT_DATA) || (ControlState == LAST_OUT_DATA)) - { - DataStageOut(); - ControlState = pInformation->ControlState; /* may be changed outside the function */ - } - - else if (ControlState == WAIT_STATUS_OUT) - { - (*pProperty->Process_Status_OUT)(); - ControlState = STALLED; - } - - else if ((ControlState == IN_DATA) || (ControlState == LAST_IN_DATA)) - { - /* host aborts the transfer before finish */ - ControlState = STALLED; - } - - /* Unexpect state, STALL the endpoint */ - else - { - ControlState = STALLED; - } - - pInformation->ControlState = ControlState; - - return Post0_Process(); -} - -/******************************************************************************* -* Function Name : Post0_Process -* Description : Stall the Endpoint 0 in case of error. -* Input : None. -* Output : None. -* Return : - 0 if the control State is in PAUSE -* - 1 if not. -*******************************************************************************/ -u8 Post0_Process(void) -{ - SetEPRxCount(ENDP0, Device_Property.MaxPacketSize); - - if (pInformation->ControlState == STALLED) - { - vSetEPRxStatus(EP_RX_STALL); - vSetEPTxStatus(EP_TX_STALL); - } - - return (pInformation->ControlState == PAUSE); -} - -/******************************************************************************* -* Function Name : SetDeviceAddress. -* Description : Set the device and all the used Endpoints addresses. -* Input : - Val: device adress. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetDeviceAddress(u8 Val) -{ - u32 i; - u32 nEP = Device_Table.Total_Endpoint; - - /* set address in every used endpoint */ - for (i = 0; i < nEP; i++) - { - _SetEPAddress((u8)i, (u8)i); - } /* for */ - _SetDADDR(Val | DADDR_EF); /* set device address and enable function */ -} - -/******************************************************************************* -* Function Name : NOP_Process -* Description : No operation function. -* Input : None. -* Output : None. -* Return : None. -*******************************************************************************/ -void NOP_Process(void) -{ -} - -/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/ diff --git a/STM32F3/cores/maple/libmaple/usb/usb_lib/usb_core.h b/STM32F3/cores/maple/libmaple/usb/usb_lib/usb_core.h deleted file mode 100644 index fa29a18..0000000 --- a/STM32F3/cores/maple/libmaple/usb/usb_lib/usb_core.h +++ /dev/null @@ -1,251 +0,0 @@ -/******************** (C) COPYRIGHT 2008 STMicroelectronics ******************** -* File Name : usb_core.h -* Author : MCD Application Team -* Version : V2.2.1 -* Date : 09/22/2008 -* Description : Standard protocol processing functions prototypes -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __USB_CORE_H -#define __USB_CORE_H - -#if defined(__cplusplus) -extern "C" { -#endif - -/* Includes ------------------------------------------------------------------*/ -/* Exported types ------------------------------------------------------------*/ -typedef enum _CONTROL_STATE -{ - WAIT_SETUP, /* 0 */ - SETTING_UP, /* 1 */ - IN_DATA, /* 2 */ - OUT_DATA, /* 3 */ - LAST_IN_DATA, /* 4 */ - LAST_OUT_DATA, /* 5 */ - WAIT_STATUS_IN, /* 7 */ - WAIT_STATUS_OUT, /* 8 */ - STALLED, /* 9 */ - PAUSE /* 10 */ -} CONTROL_STATE; /* The state machine states of a control pipe */ - -typedef struct OneDescriptor -{ - u8 *Descriptor; - u16 Descriptor_Size; -} -ONE_DESCRIPTOR, *PONE_DESCRIPTOR; -/* All the request process routines return a value of this type - If the return value is not SUCCESS or NOT_READY, - the software will STALL the correspond endpoint */ -typedef enum _RESULT -{ - USB_SUCCESS = 0, /* Process sucessfully */ - USB_ERROR, - USB_UNSUPPORT, - USB_NOT_READY /* The process has not been finished, endpoint will be - NAK to further rquest */ -} RESULT; - - -/*-*-*-*-*-*-*-*-*-*-* Definitions for endpoint level -*-*-*-*-*-*-*-*-*-*-*-*/ -typedef struct _ENDPOINT_INFO -{ - /* When send data out of the device, - CopyData() is used to get data buffer 'Length' bytes data - if Length is 0, - CopyData() returns the total length of the data - if the request is not supported, returns 0 - (NEW Feature ) - if CopyData() returns -1, the calling routine should not proceed - further and will resume the SETUP process by the class device - if Length is not 0, - CopyData() returns a pointer to indicate the data location - Usb_wLength is the data remain to be sent, - Usb_wOffset is the Offset of original data - When receive data from the host, - CopyData() is used to get user data buffer which is capable - of Length bytes data to copy data from the endpoint buffer. - if Length is 0, - CopyData() returns the available data length, - if Length is not 0, - CopyData() returns user buffer address - Usb_rLength is the data remain to be received, - Usb_rPointer is the Offset of data buffer - */ - u16 Usb_wLength; - u16 Usb_wOffset; - u16 PacketSize; - u8 *(*CopyData)(u16 Length); -}ENDPOINT_INFO; - -/*-*-*-*-*-*-*-*-*-*-*-* Definitions for device level -*-*-*-*-*-*-*-*-*-*-*-*/ - -typedef struct _DEVICE -{ - u8 Total_Endpoint; /* Number of endpoints that are used */ - u8 Total_Configuration;/* Number of configuration available */ -} -DEVICE; - -typedef union -{ - u16 w; - struct BW - { - u8 bb1; - u8 bb0; - } - bw; -} u16_u8; - -typedef struct _DEVICE_INFO -{ - u8 USBbmRequestType; /* bmRequestType */ - u8 USBbRequest; /* bRequest */ - u16_u8 USBwValues; /* wValue */ - u16_u8 USBwIndexs; /* wIndex */ - u16_u8 USBwLengths; /* wLength */ - - u8 ControlState; /* of type CONTROL_STATE */ - u8 Current_Feature; - u8 Current_Configuration; /* Selected configuration */ - u8 Current_Interface; /* Selected interface of current configuration */ - u8 Current_AlternateSetting;/* Selected Alternate Setting of current - interface*/ - - ENDPOINT_INFO Ctrl_Info; -}DEVICE_INFO; - -typedef struct _DEVICE_PROP -{ - void (*Init)(void); /* Initialize the device */ - void (*Reset)(void); /* Reset routine of this device */ - - /* Device dependent process after the status stage */ - void (*Process_Status_IN)(void); - void (*Process_Status_OUT)(void); - - /* Procedure of process on setup stage of a class specified request with data stage */ - /* All class specified requests with data stage are processed in Class_Data_Setup - Class_Data_Setup() - responses to check all special requests and fills ENDPOINT_INFO - according to the request - If IN tokens are expected, then wLength & wOffset will be filled - with the total transferring bytes and the starting position - If OUT tokens are expected, then rLength & rOffset will be filled - with the total expected bytes and the starting position in the buffer - - If the request is valid, Class_Data_Setup returns SUCCESS, else UNSUPPORT - - CAUTION: - Since GET_CONFIGURATION & GET_INTERFACE are highly related to - the individual classes, they will be checked and processed here. - */ - RESULT (*Class_Data_Setup)(u8 RequestNo); - - /* Procedure of process on setup stage of a class specified request without data stage */ - /* All class specified requests without data stage are processed in Class_NoData_Setup - Class_NoData_Setup - responses to check all special requests and perform the request - - CAUTION: - Since SET_CONFIGURATION & SET_INTERFACE are highly related to - the individual classes, they will be checked and processed here. - */ - RESULT (*Class_NoData_Setup)(u8 RequestNo); - - /*Class_Get_Interface_Setting - This function is used by the file usb_core.c to test if the selected Interface - and Alternate Setting (u8 Interface, u8 AlternateSetting) are supported by - the application. - This function is writing by user. It should return "SUCCESS" if the Interface - and Alternate Setting are supported by the application or "UNSUPPORT" if they - are not supported. */ - - RESULT (*Class_Get_Interface_Setting)(u8 Interface, u8 AlternateSetting); - - u8* (*GetDeviceDescriptor)(u16 Length); - u8* (*GetConfigDescriptor)(u16 Length); - u8* (*GetStringDescriptor)(u16 Length); - - u8* RxEP_buffer; - u8 MaxPacketSize; - -}DEVICE_PROP; - -typedef struct _USER_STANDARD_REQUESTS -{ - void (*User_GetConfiguration)(void); /* Get Configuration */ - void (*User_SetConfiguration)(void); /* Set Configuration */ - void (*User_GetInterface)(void); /* Get Interface */ - void (*User_SetInterface)(void); /* Set Interface */ - void (*User_GetStatus)(void); /* Get Status */ - void (*User_ClearFeature)(void); /* Clear Feature */ - void (*User_SetEndPointFeature)(void); /* Set Endpoint Feature */ - void (*User_SetDeviceFeature)(void); /* Set Device Feature */ - void (*User_SetDeviceAddress)(void); /* Set Device Address */ -} -USER_STANDARD_REQUESTS; - -/* Exported constants --------------------------------------------------------*/ -#define Type_Recipient (pInformation->USBbmRequestType & (REQUEST_TYPE | RECIPIENT)) - -#define Usb_rLength Usb_wLength -#define Usb_rOffset Usb_wOffset - -#define USBwValue USBwValues.w -#define USBwValue0 USBwValues.bw.bb0 -#define USBwValue1 USBwValues.bw.bb1 -#define USBwIndex USBwIndexs.w -#define USBwIndex0 USBwIndexs.bw.bb0 -#define USBwIndex1 USBwIndexs.bw.bb1 -#define USBwLength USBwLengths.w -#define USBwLength0 USBwLengths.bw.bb0 -#define USBwLength1 USBwLengths.bw.bb1 - -/* Exported macro ------------------------------------------------------------*/ -/* Exported functions ------------------------------------------------------- */ -u8 Setup0_Process(void); -u8 Post0_Process(void); -u8 Out0_Process(void); -u8 In0_Process(void); - -RESULT Standard_SetEndPointFeature(void); -RESULT Standard_SetDeviceFeature(void); - -u8 *Standard_GetConfiguration(u16 Length); -RESULT Standard_SetConfiguration(void); -u8 *Standard_GetInterface(u16 Length); -RESULT Standard_SetInterface(void); -u8 *Standard_GetDescriptorData(u16 Length, PONE_DESCRIPTOR pDesc); - -u8 *Standard_GetStatus(u16 Length); -RESULT Standard_ClearFeature(void); -void SetDeviceAddress(u8); -void NOP_Process(void); - -extern DEVICE_PROP Device_Property; -extern USER_STANDARD_REQUESTS User_Standard_Requests; -extern DEVICE Device_Table; -extern DEVICE_INFO Device_Info; - -/* cells saving status during interrupt servicing */ -extern u16 SaveRState; -extern u16 SaveTState; - -#if defined(__cplusplus) -} -#endif - -#endif /* __USB_CORE_H */ - -/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/ diff --git a/STM32F3/cores/maple/libmaple/usb/usb_lib/usb_def.h b/STM32F3/cores/maple/libmaple/usb/usb_lib/usb_def.h deleted file mode 100644 index 80aa303..0000000 --- a/STM32F3/cores/maple/libmaple/usb/usb_lib/usb_def.h +++ /dev/null @@ -1,88 +0,0 @@ -/******************** (C) COPYRIGHT 2008 STMicroelectronics ******************** -* File Name : usb_def.h -* Author : MCD Application Team -* Version : V2.2.1 -* Date : 09/22/2008 -* Description : Definitions related to USB Core -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __USB_DEF_H -#define __USB_DEF_H - -#if defined(__cplusplus) -extern "C" { -#endif - -/* Includes ------------------------------------------------------------------*/ -/* Exported types ------------------------------------------------------------*/ -typedef enum _RECIPIENT_TYPE -{ - DEVICE_RECIPIENT, /* Recipient device */ - INTERFACE_RECIPIENT, /* Recipient interface */ - ENDPOINT_RECIPIENT, /* Recipient endpoint */ - OTHER_RECIPIENT -} RECIPIENT_TYPE; - - -typedef enum _STANDARD_REQUESTS -{ - GET_STATUS = 0, - CLEAR_FEATURE, - RESERVED1, - SET_FEATURE, - RESERVED2, - SET_ADDRESS, - GET_DESCRIPTOR, - SET_DESCRIPTOR, - GET_CONFIGURATION, - SET_CONFIGURATION, - GET_INTERFACE, - SET_INTERFACE, - TOTAL_sREQUEST, /* Total number of Standard request */ - SYNCH_FRAME = 12 -} STANDARD_REQUESTS; - -/* Definition of "USBwValue" */ -typedef enum _DESCRIPTOR_TYPE -{ - DEVICE_DESCRIPTOR = 1, - CONFIG_DESCRIPTOR, - STRING_DESCRIPTOR, - INTERFACE_DESCRIPTOR, - ENDPOINT_DESCRIPTOR -} DESCRIPTOR_TYPE; - -/* Feature selector of a SET_FEATURE or CLEAR_FEATURE */ -typedef enum _FEATURE_SELECTOR -{ - ENDPOINT_STALL, - DEVICE_REMOTE_WAKEUP -} FEATURE_SELECTOR; - -/* Exported constants --------------------------------------------------------*/ -/* Definition of "USBbmRequestType" */ -#define REQUEST_TYPE 0x60 /* Mask to get request type */ -#define STANDARD_REQUEST 0x00 /* Standard request */ -#define CLASS_REQUEST 0x20 /* Class request */ -#define VENDOR_REQUEST 0x40 /* Vendor request */ - -#define RECIPIENT 0x1F /* Mask to get recipient */ - -/* Exported macro ------------------------------------------------------------*/ -/* Exported functions ------------------------------------------------------- */ - -#if defined(__cplusplus) -} -#endif - -#endif /* __USB_DEF_H */ - -/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/ diff --git a/STM32F3/cores/maple/libmaple/usb/usb_lib/usb_init.c b/STM32F3/cores/maple/libmaple/usb/usb_lib/usb_init.c deleted file mode 100644 index 94f3a83..0000000 --- a/STM32F3/cores/maple/libmaple/usb/usb_lib/usb_init.c +++ /dev/null @@ -1,64 +0,0 @@ -/******************** (C) COPYRIGHT 2008 STMicroelectronics ******************** -* File Name : usb_init.c -* Author : MCD Application Team -* Version : V2.2.1 -* Date : 09/22/2008 -* Description : Initialization routines & global variables -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Includes ------------------------------------------------------------------*/ -#include "usb_lib.h" - -/* Private typedef -----------------------------------------------------------*/ -/* Private define ------------------------------------------------------------*/ -/* Private macro -------------------------------------------------------------*/ -/* Private variables ---------------------------------------------------------*/ -/* The number of current endpoint, it will be used to specify an endpoint */ - u8 EPindex; -/* The number of current device, it is an index to the Device_Table */ -/* u8 Device_no; */ -/* Points to the DEVICE_INFO structure of current device */ -/* The purpose of this register is to speed up the execution */ -DEVICE_INFO *pInformation; -/* Points to the DEVICE_PROP structure of current device */ -/* The purpose of this register is to speed up the execution */ -DEVICE_PROP *pProperty; -/* Temporary save the state of Rx & Tx status. */ -/* Whenever the Rx or Tx state is changed, its value is saved */ -/* in this variable first and will be set to the EPRB or EPRA */ -/* at the end of interrupt process */ -u16 SaveState ; -u16 wInterrupt_Mask; -DEVICE_INFO Device_Info; -USER_STANDARD_REQUESTS *pUser_Standard_Requests; - -/* Extern variables ----------------------------------------------------------*/ -/* Private function prototypes -----------------------------------------------*/ -/* Private functions ---------------------------------------------------------*/ - -/******************************************************************************* -* Function Name : USB_Init -* Description : USB system initialization -* Input : None. -* Output : None. -* Return : None. -*******************************************************************************/ -void USB_Init(void) -{ - pInformation = &Device_Info; - pInformation->ControlState = 2; - pProperty = &Device_Property; - pUser_Standard_Requests = &User_Standard_Requests; - /* Initialize devices one by one */ - - pProperty->Init(); -} - -/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/ diff --git a/STM32F3/cores/maple/libmaple/usb/usb_lib/usb_init.h b/STM32F3/cores/maple/libmaple/usb/usb_lib/usb_init.h deleted file mode 100644 index 80ee2fb..0000000 --- a/STM32F3/cores/maple/libmaple/usb/usb_lib/usb_init.h +++ /dev/null @@ -1,57 +0,0 @@ -/******************** (C) COPYRIGHT 2008 STMicroelectronics ******************** -* File Name : usb_init.h -* Author : MCD Application Team -* Version : V2.2.1 -* Date : 09/22/2008 -* Description : Initialization routines & global variables -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __USB_INIT_H -#define __USB_INIT_H - -#if defined(__cplusplus) -extern "C" { -#endif - -/* Includes ------------------------------------------------------------------*/ -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ -/* Exported macro ------------------------------------------------------------*/ -/* Exported functions ------------------------------------------------------- */ -void USB_Init(void); - -/* External variables --------------------------------------------------------*/ -/* The number of current endpoint, it will be used to specify an endpoint */ -extern u8 EPindex; -/* The number of current device, it is an index to the Device_Table */ -/*extern u8 Device_no; */ -/* Points to the DEVICE_INFO structure of current device */ -/* The purpose of this register is to speed up the execution */ -extern DEVICE_INFO* pInformation; -/* Points to the DEVICE_PROP structure of current device */ -/* The purpose of this register is to speed up the execution */ -extern DEVICE_PROP* pProperty; -/* Temporary save the state of Rx & Tx status. */ -/* Whenever the Rx or Tx state is changed, its value is saved */ -/* in this variable first and will be set to the EPRB or EPRA */ -/* at the end of interrupt process */ -extern USER_STANDARD_REQUESTS *pUser_Standard_Requests; - -extern u16 SaveState ; -extern u16 wInterrupt_Mask; - -#if defined(__cplusplus) -} -#endif - -#endif /* __USB_INIT_H */ - -/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/ diff --git a/STM32F3/cores/maple/libmaple/usb/usb_lib/usb_lib.h b/STM32F3/cores/maple/libmaple/usb/usb_lib/usb_lib.h deleted file mode 100644 index 85f94ab..0000000 --- a/STM32F3/cores/maple/libmaple/usb/usb_lib/usb_lib.h +++ /dev/null @@ -1,36 +0,0 @@ -/******************** (C) COPYRIGHT 2008 STMicroelectronics ******************** -* File Name : usb_lib.h -* Author : MCD Application Team -* Version : V2.2.1 -* Date : 09/22/2008 -* Description : USB library include files -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __USB_LIB_H -#define __USB_LIB_H - -/* Includes ------------------------------------------------------------------*/ -#include "usb_type.h" -#include "usb_regs.h" -#include "usb_def.h" -#include "usb_core.h" -#include "usb_init.h" -#include "usb_mem.h" - -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ -/* Exported macro ------------------------------------------------------------*/ -/* Exported functions ------------------------------------------------------- */ -/* External variables --------------------------------------------------------*/ - -#endif /* __USB_LIB_H */ - -/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/ diff --git a/STM32F3/cores/maple/libmaple/usb/usb_lib/usb_mem.c b/STM32F3/cores/maple/libmaple/usb/usb_lib/usb_mem.c deleted file mode 100644 index ad9740a..0000000 --- a/STM32F3/cores/maple/libmaple/usb/usb_lib/usb_mem.c +++ /dev/null @@ -1,73 +0,0 @@ -/******************** (C) COPYRIGHT 2008 STMicroelectronics ******************** -* File Name : usb_mem.c -* Author : MCD Application Team -* Version : V2.2.1 -* Date : 09/22/2008 -* Description : Utility functions for memory transfers to/from PMA -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Includes ------------------------------------------------------------------*/ -#include "usb_lib.h" - -/* Private typedef -----------------------------------------------------------*/ -/* Private define ------------------------------------------------------------*/ -/* Private macro -------------------------------------------------------------*/ -/* Private variables ---------------------------------------------------------*/ -/* Extern variables ----------------------------------------------------------*/ -/* Private function prototypes -----------------------------------------------*/ -/* Private functions ---------------------------------------------------------*/ -/******************************************************************************* -* Function Name : UserToPMABufferCopy -* Description : Copy a buffer from user memory area to packet memory area (PMA) -* Input : - pbUsrBuf: pointer to user memory area. -* - wPMABufAddr: address into PMA. -* - wNBytes: no. of bytes to be copied. -* Output : None. -* Return : None . -*******************************************************************************/ -void UserToPMABufferCopy(const u8 *pbUsrBuf, u16 wPMABufAddr, u16 wNBytes) -{ - u32 n = (wNBytes + 1) >> 1; /* n = (wNBytes + 1) / 2 */ - u32 i, temp1, temp2; - u16 *pdwVal; - pdwVal = (u16 *)(wPMABufAddr * 2 + PMAAddr); - for (i = n; i != 0; i--) - { - temp1 = (u16) * pbUsrBuf; - pbUsrBuf++; - temp2 = temp1 | (u16) * pbUsrBuf << 8; - *pdwVal++ = temp2; - pdwVal++; - pbUsrBuf++; - } -} -/******************************************************************************* -* Function Name : PMAToUserBufferCopy -* Description : Copy a buffer from user memory area to packet memory area (PMA) -* Input : - pbUsrBuf = pointer to user memory area. -* - wPMABufAddr = address into PMA. -* - wNBytes = no. of bytes to be copied. -* Output : None. -* Return : None. -*******************************************************************************/ -void PMAToUserBufferCopy(u8 *pbUsrBuf, u16 wPMABufAddr, u16 wNBytes) -{ - u32 n = (wNBytes + 1) >> 1;/* /2*/ - u32 i; - u32 *pdwVal; - pdwVal = (u32 *)(wPMABufAddr * 2 + PMAAddr); - for (i = n; i != 0; i--) - { - *(u16*)pbUsrBuf++ = *pdwVal++; - pbUsrBuf++; - } -} - -/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/ diff --git a/STM32F3/cores/maple/libmaple/usb/usb_lib/usb_mem.h b/STM32F3/cores/maple/libmaple/usb/usb_lib/usb_mem.h deleted file mode 100644 index b0e0474..0000000 --- a/STM32F3/cores/maple/libmaple/usb/usb_lib/usb_mem.h +++ /dev/null @@ -1,40 +0,0 @@ -/******************** (C) COPYRIGHT 2008 STMicroelectronics ******************** -* File Name : usb_mem.h -* Author : MCD Application Team -* Version : V2.2.1 -* Date : 09/22/2008 -* Description : Utility prototypes functions for memory/PMA transfers -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __USB_MEM_H -#define __USB_MEM_H - -/* Includes ------------------------------------------------------------------*/ -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ -/* Exported macro ------------------------------------------------------------*/ -/* Exported functions ------------------------------------------------------- */ -#if defined(__cplusplus) -extern "C" { -#endif - -void UserToPMABufferCopy(const u8 *pbUsrBuf, u16 wPMABufAddr, u16 wNBytes); -void PMAToUserBufferCopy(u8 *pbUsrBuf, u16 wPMABufAddr, u16 wNBytes); - -#if defined(__cplusplus) -} -#endif - -/* External variables --------------------------------------------------------*/ - -#endif /*__USB_MEM_H*/ - -/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/ diff --git a/STM32F3/cores/maple/libmaple/usb/usb_lib/usb_regs.c b/STM32F3/cores/maple/libmaple/usb/usb_lib/usb_regs.c deleted file mode 100644 index c7e0276..0000000 --- a/STM32F3/cores/maple/libmaple/usb/usb_lib/usb_regs.c +++ /dev/null @@ -1,748 +0,0 @@ -/******************** (C) COPYRIGHT 2008 STMicroelectronics ******************** -* File Name : usb_regs.c -* Author : MCD Application Team -* Version : V2.2.1 -* Date : 09/22/2008 -* Description : Interface functions to USB cell registers -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Includes ------------------------------------------------------------------*/ -#include "usb_lib.h" - -/* Private typedef -----------------------------------------------------------*/ -/* Private define ------------------------------------------------------------*/ -/* Private macro -------------------------------------------------------------*/ -/* Private variables ---------------------------------------------------------*/ -/* Extern variables ----------------------------------------------------------*/ -/* Private function prototypes -----------------------------------------------*/ -/* Private functions ---------------------------------------------------------*/ - -/******************************************************************************* -* Function Name : SetCNTR. -* Description : Set the CNTR register value. -* Input : wRegValue: new register value. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetCNTR(u16 wRegValue) -{ - _SetCNTR(wRegValue); -} - -/******************************************************************************* -* Function Name : GetCNTR. -* Description : returns the CNTR register value. -* Input : None. -* Output : None. -* Return : CNTR register Value. -*******************************************************************************/ -u16 GetCNTR(void) -{ - return(_GetCNTR()); -} - -/******************************************************************************* -* Function Name : SetISTR. -* Description : Set the ISTR register value. -* Input : wRegValue: new register value. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetISTR(u16 wRegValue) -{ - _SetISTR(wRegValue); -} - -/******************************************************************************* -* Function Name : GetISTR -* Description : Returns the ISTR register value. -* Input : None. -* Output : None. -* Return : ISTR register Value -*******************************************************************************/ -u16 GetISTR(void) -{ - return(_GetISTR()); -} - -/******************************************************************************* -* Function Name : GetFNR -* Description : Returns the FNR register value. -* Input : None. -* Output : None. -* Return : FNR register Value -*******************************************************************************/ -u16 GetFNR(void) -{ - return(_GetFNR()); -} - -/******************************************************************************* -* Function Name : SetDADDR -* Description : Set the DADDR register value. -* Input : wRegValue: new register value. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetDADDR(u16 wRegValue) -{ - _SetDADDR(wRegValue); -} - -/******************************************************************************* -* Function Name : GetDADDR -* Description : Returns the DADDR register value. -* Input : None. -* Output : None. -* Return : DADDR register Value -*******************************************************************************/ -u16 GetDADDR(void) -{ - return(_GetDADDR()); -} - -/******************************************************************************* -* Function Name : SetBTABLE -* Description : Set the BTABLE. -* Input : wRegValue: New register value. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetBTABLE(u16 wRegValue) -{ - _SetBTABLE(wRegValue); -} - -/******************************************************************************* -* Function Name : GetBTABLE. -* Description : Returns the BTABLE register value. -* Input : None. -* Output : None. -* Return : BTABLE address. -*******************************************************************************/ -u16 GetBTABLE(void) -{ - return(_GetBTABLE()); -} - -/******************************************************************************* -* Function Name : SetENDPOINT -* Description : Setthe Endpoint register value. -* Input : bEpNum: Endpoint Number. -* wRegValue. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetENDPOINT(u8 bEpNum, u16 wRegValue) -{ - _SetENDPOINT(bEpNum, wRegValue); -} - -/******************************************************************************* -* Function Name : GetENDPOINT -* Description : Return the Endpoint register value. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : Endpoint register value. -*******************************************************************************/ -u16 GetENDPOINT(u8 bEpNum) -{ - return(_GetENDPOINT(bEpNum)); -} - -/******************************************************************************* -* Function Name : SetEPType -* Description : sets the type in the endpoint register. -* Input : bEpNum: Endpoint Number. -* wType: type definition. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPType(u8 bEpNum, u16 wType) -{ - _SetEPType(bEpNum, wType); -} - -/******************************************************************************* -* Function Name : GetEPType -* Description : Returns the endpoint type. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : Endpoint Type -*******************************************************************************/ -u16 GetEPType(u8 bEpNum) -{ - return(_GetEPType(bEpNum)); -} - -/******************************************************************************* -* Function Name : SetEPTxStatus -* Description : Set the status of Tx endpoint. -* Input : bEpNum: Endpoint Number. -* wState: new state. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPTxStatus(u8 bEpNum, u16 wState) -{ - _SetEPTxStatus(bEpNum, wState); -} - -/******************************************************************************* -* Function Name : SetEPRxStatus -* Description : Set the status of Rx endpoint. -* Input : bEpNum: Endpoint Number. -* wState: new state. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPRxStatus(u8 bEpNum, u16 wState) -{ - _SetEPRxStatus(bEpNum, wState); -} - -/******************************************************************************* -* Function Name : SetDouBleBuffEPStall -* Description : sets the status for Double Buffer Endpoint to STALL -* Input : bEpNum: Endpoint Number. -* bDir: Endpoint direction. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetDouBleBuffEPStall(u8 bEpNum, u8 bDir) -{ - u16 Endpoint_DTOG_Status; - Endpoint_DTOG_Status = GetENDPOINT(bEpNum); - if (bDir == EP_DBUF_OUT) - { /* OUT double buffered endpoint */ - _SetENDPOINT(bEpNum, Endpoint_DTOG_Status & ~EPRX_DTOG1); - } - else if (bDir == EP_DBUF_IN) - { /* IN double buffered endpoint */ - _SetENDPOINT(bEpNum, Endpoint_DTOG_Status & ~EPTX_DTOG1); - } -} - -/******************************************************************************* -* Function Name : GetEPTxStatus -* Description : Returns the endpoint Tx status. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : Endpoint TX Status -*******************************************************************************/ -u16 GetEPTxStatus(u8 bEpNum) -{ - return(_GetEPTxStatus(bEpNum)); -} - -/******************************************************************************* -* Function Name : GetEPRxStatus -* Description : Returns the endpoint Rx status. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : Endpoint RX Status -*******************************************************************************/ -u16 GetEPRxStatus(u8 bEpNum) -{ - return(_GetEPRxStatus(bEpNum)); -} - -/******************************************************************************* -* Function Name : SetEPTxValid -* Description : Valid the endpoint Tx Status. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPTxValid(u8 bEpNum) -{ - _SetEPTxStatus(bEpNum, EP_TX_VALID); -} - -/******************************************************************************* -* Function Name : SetEPRxValid -* Description : Valid the endpoint Rx Status. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPRxValid(u8 bEpNum) -{ - _SetEPRxStatus(bEpNum, EP_RX_VALID); -} - -/******************************************************************************* -* Function Name : SetEP_KIND -* Description : Clear the EP_KIND bit. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEP_KIND(u8 bEpNum) -{ - _SetEP_KIND(bEpNum); -} - -/******************************************************************************* -* Function Name : ClearEP_KIND -* Description : set the EP_KIND bit. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -void ClearEP_KIND(u8 bEpNum) -{ - _ClearEP_KIND(bEpNum); -} -/******************************************************************************* -* Function Name : Clear_Status_Out -* Description : Clear the Status Out of the related Endpoint -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -void Clear_Status_Out(u8 bEpNum) -{ - _ClearEP_KIND(bEpNum); -} -/******************************************************************************* -* Function Name : Set_Status_Out -* Description : Set the Status Out of the related Endpoint -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -void Set_Status_Out(u8 bEpNum) -{ - _SetEP_KIND(bEpNum); -} -/******************************************************************************* -* Function Name : SetEPDoubleBuff -* Description : Enable the double buffer feature for the endpoint. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPDoubleBuff(u8 bEpNum) -{ - _SetEP_KIND(bEpNum); -} -/******************************************************************************* -* Function Name : ClearEPDoubleBuff -* Description : Disable the double buffer feature for the endpoint. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -void ClearEPDoubleBuff(u8 bEpNum) -{ - _ClearEP_KIND(bEpNum); -} -/******************************************************************************* -* Function Name : GetTxStallStatus -* Description : Returns the Stall status of the Tx endpoint. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : Tx Stall status. -*******************************************************************************/ -u16 GetTxStallStatus(u8 bEpNum) -{ - return(_GetTxStallStatus(bEpNum)); -} -/******************************************************************************* -* Function Name : GetRxStallStatus -* Description : Returns the Stall status of the Rx endpoint. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : Rx Stall status. -*******************************************************************************/ -u16 GetRxStallStatus(u8 bEpNum) -{ - return(_GetRxStallStatus(bEpNum)); -} -/******************************************************************************* -* Function Name : ClearEP_CTR_RX -* Description : Clear the CTR_RX bit. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -void ClearEP_CTR_RX(u8 bEpNum) -{ - _ClearEP_CTR_RX(bEpNum); -} -/******************************************************************************* -* Function Name : ClearEP_CTR_TX -* Description : Clear the CTR_TX bit. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -void ClearEP_CTR_TX(u8 bEpNum) -{ - _ClearEP_CTR_TX(bEpNum); -} -/******************************************************************************* -* Function Name : ToggleDTOG_RX -* Description : Toggle the DTOG_RX bit. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -void ToggleDTOG_RX(u8 bEpNum) -{ - _ToggleDTOG_RX(bEpNum); -} -/******************************************************************************* -* Function Name : ToggleDTOG_TX -* Description : Toggle the DTOG_TX bit. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -void ToggleDTOG_TX(u8 bEpNum) -{ - _ToggleDTOG_TX(bEpNum); -} -/******************************************************************************* -* Function Name : ClearDTOG_RX. -* Description : Clear the DTOG_RX bit. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -void ClearDTOG_RX(u8 bEpNum) -{ - _ClearDTOG_RX(bEpNum); -} -/******************************************************************************* -* Function Name : ClearDTOG_TX. -* Description : Clear the DTOG_TX bit. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -void ClearDTOG_TX(u8 bEpNum) -{ - _ClearDTOG_TX(bEpNum); -} -/******************************************************************************* -* Function Name : SetEPAddress -* Description : Set the endpoint address. -* Input : bEpNum: Endpoint Number. -* bAddr: New endpoint address. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPAddress(u8 bEpNum, u8 bAddr) -{ - _SetEPAddress(bEpNum, bAddr); -} -/******************************************************************************* -* Function Name : GetEPAddress -* Description : Get the endpoint address. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : Endpoint address. -*******************************************************************************/ -u8 GetEPAddress(u8 bEpNum) -{ - return(_GetEPAddress(bEpNum)); -} -/******************************************************************************* -* Function Name : SetEPTxAddr -* Description : Set the endpoint Tx buffer address. -* Input : bEpNum: Endpoint Number. -* wAddr: new address. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPTxAddr(u8 bEpNum, u16 wAddr) -{ - _SetEPTxAddr(bEpNum, wAddr); -} -/******************************************************************************* -* Function Name : SetEPRxAddr -* Description : Set the endpoint Rx buffer address. -* Input : bEpNum: Endpoint Number. -* wAddr: new address. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPRxAddr(u8 bEpNum, u16 wAddr) -{ - _SetEPRxAddr(bEpNum, wAddr); -} -/******************************************************************************* -* Function Name : GetEPTxAddr -* Description : Returns the endpoint Tx buffer address. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : Rx buffer address. -*******************************************************************************/ -u16 GetEPTxAddr(u8 bEpNum) -{ - return(_GetEPTxAddr(bEpNum)); -} -/******************************************************************************* -* Function Name : GetEPRxAddr. -* Description : Returns the endpoint Rx buffer address. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : Rx buffer address. -*******************************************************************************/ -u16 GetEPRxAddr(u8 bEpNum) -{ - return(_GetEPRxAddr(bEpNum)); -} -/******************************************************************************* -* Function Name : SetEPTxCount. -* Description : Set the Tx count. -* Input : bEpNum: Endpoint Number. -* wCount: new count value. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPTxCount(u8 bEpNum, u16 wCount) -{ - _SetEPTxCount(bEpNum, wCount); -} -/******************************************************************************* -* Function Name : SetEPCountRxReg. -* Description : Set the Count Rx Register value. -* Input : *pdwReg: point to the register. -* wCount: the new register value. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPCountRxReg(u32 *pdwReg, u16 wCount) -{ - _SetEPCountRxReg(dwReg, wCount); -} -/******************************************************************************* -* Function Name : SetEPRxCount -* Description : Set the Rx count. -* Input : bEpNum: Endpoint Number. -* wCount: the new count value. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPRxCount(u8 bEpNum, u16 wCount) -{ - _SetEPRxCount(bEpNum, wCount); -} -/******************************************************************************* -* Function Name : GetEPTxCount -* Description : Get the Tx count. -* Input : bEpNum: Endpoint Number. -* Output : None -* Return : Tx count value. -*******************************************************************************/ -u16 GetEPTxCount(u8 bEpNum) -{ - return(_GetEPTxCount(bEpNum)); -} -/******************************************************************************* -* Function Name : GetEPRxCount -* Description : Get the Rx count. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : Rx count value. -*******************************************************************************/ -u16 GetEPRxCount(u8 bEpNum) -{ - return(_GetEPRxCount(bEpNum)); -} -/******************************************************************************* -* Function Name : SetEPDblBuffAddr -* Description : Set the addresses of the buffer 0 and 1. -* Input : bEpNum: Endpoint Number. -* wBuf0Addr: new address of buffer 0. -* wBuf1Addr: new address of buffer 1. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPDblBuffAddr(u8 bEpNum, u16 wBuf0Addr, u16 wBuf1Addr) -{ - _SetEPDblBuffAddr(bEpNum, wBuf0Addr, wBuf1Addr); -} -/******************************************************************************* -* Function Name : SetEPDblBuf0Addr -* Description : Set the Buffer 1 address. -* Input : bEpNum: Endpoint Number -* wBuf0Addr: new address. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPDblBuf0Addr(u8 bEpNum, u16 wBuf0Addr) -{ - _SetEPDblBuf0Addr(bEpNum, wBuf0Addr); -} -/******************************************************************************* -* Function Name : SetEPDblBuf1Addr -* Description : Set the Buffer 1 address. -* Input : bEpNum: Endpoint Number -* wBuf1Addr: new address. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPDblBuf1Addr(u8 bEpNum, u16 wBuf1Addr) -{ - _SetEPDblBuf1Addr(bEpNum, wBuf1Addr); -} -/******************************************************************************* -* Function Name : GetEPDblBuf0Addr -* Description : Returns the address of the Buffer 0. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -u16 GetEPDblBuf0Addr(u8 bEpNum) -{ - return(_GetEPDblBuf0Addr(bEpNum)); -} -/******************************************************************************* -* Function Name : GetEPDblBuf1Addr -* Description : Returns the address of the Buffer 1. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : Address of the Buffer 1. -*******************************************************************************/ -u16 GetEPDblBuf1Addr(u8 bEpNum) -{ - return(_GetEPDblBuf1Addr(bEpNum)); -} -/******************************************************************************* -* Function Name : SetEPDblBuffCount -* Description : Set the number of bytes for a double Buffer -* endpoint. -* Input : bEpNum,bDir, wCount -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPDblBuffCount(u8 bEpNum, u8 bDir, u16 wCount) -{ - _SetEPDblBuffCount(bEpNum, bDir, wCount); -} -/******************************************************************************* -* Function Name : SetEPDblBuf0Count -* Description : Set the number of bytes in the buffer 0 of a double Buffer -* endpoint. -* Input : bEpNum, bDir, wCount -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPDblBuf0Count(u8 bEpNum, u8 bDir, u16 wCount) -{ - _SetEPDblBuf0Count(bEpNum, bDir, wCount); -} -/******************************************************************************* -* Function Name : SetEPDblBuf1Count -* Description : Set the number of bytes in the buffer 0 of a double Buffer -* endpoint. -* Input : bEpNum, bDir, wCount -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPDblBuf1Count(u8 bEpNum, u8 bDir, u16 wCount) -{ - _SetEPDblBuf1Count(bEpNum, bDir, wCount); -} -/******************************************************************************* -* Function Name : GetEPDblBuf0Count -* Description : Returns the number of byte received in the buffer 0 of a double -* Buffer endpoint. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : Endpoint Buffer 0 count -*******************************************************************************/ -u16 GetEPDblBuf0Count(u8 bEpNum) -{ - return(_GetEPDblBuf0Count(bEpNum)); -} -/******************************************************************************* -* Function Name : GetEPDblBuf1Count -* Description : Returns the number of data received in the buffer 1 of a double -* Buffer endpoint. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : Endpoint Buffer 1 count. -*******************************************************************************/ -u16 GetEPDblBuf1Count(u8 bEpNum) -{ - return(_GetEPDblBuf1Count(bEpNum)); -} -/******************************************************************************* -* Function Name : GetEPDblBufDir -* Description : gets direction of the double buffered endpoint -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : EP_DBUF_OUT, EP_DBUF_IN, -* EP_DBUF_ERR if the endpoint counter not yet programmed. -*******************************************************************************/ -EP_DBUF_DIR GetEPDblBufDir(u8 bEpNum) -{ - if ((u16)(*_pEPRxCount(bEpNum) & 0xFC00) != 0) - return(EP_DBUF_OUT); - else if (((u16)(*_pEPTxCount(bEpNum)) & 0x03FF) != 0) - return(EP_DBUF_IN); - else - return(EP_DBUF_ERR); -} -/******************************************************************************* -* Function Name : FreeUserBuffer -* Description : free buffer used from the application realizing it to the line - toggles bit SW_BUF in the double buffered endpoint register -* Input : bEpNum, bDir -* Output : None. -* Return : None. -*******************************************************************************/ -void FreeUserBuffer(u8 bEpNum, u8 bDir) -{ - if (bDir == EP_DBUF_OUT) - { /* OUT double buffered endpoint */ - _ToggleDTOG_TX(bEpNum); - } - else if (bDir == EP_DBUF_IN) - { /* IN double buffered endpoint */ - _ToggleDTOG_RX(bEpNum); - } -} - -/******************************************************************************* -* Function Name : ToWord -* Description : merge two byte in a word. -* Input : bh: byte high, bl: bytes low. -* Output : None. -* Return : resulted word. -*******************************************************************************/ -u16 ToWord(u8 bh, u8 bl) -{ - u16 wRet; - wRet = (u16)bl | ((u16)bh << 8); - return(wRet); -} -/******************************************************************************* -* Function Name : ByteSwap -* Description : Swap two byte in a word. -* Input : wSwW: word to Swap. -* Output : None. -* Return : resulted word. -*******************************************************************************/ -u16 ByteSwap(u16 wSwW) -{ - u8 bTemp; - u16 wRet; - bTemp = (u8)(wSwW & 0xff); - wRet = (wSwW >> 8) | ((u16)bTemp << 8); - return(wRet); -} - -/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/ diff --git a/STM32F3/cores/maple/libmaple/usb/usb_lib/usb_regs.h b/STM32F3/cores/maple/libmaple/usb/usb_lib/usb_regs.h deleted file mode 100644 index b63cc5f..0000000 --- a/STM32F3/cores/maple/libmaple/usb/usb_lib/usb_regs.h +++ /dev/null @@ -1,627 +0,0 @@ -/******************** (C) COPYRIGHT 2008 STMicroelectronics ******************** -* File Name : usb_regs.h -* Author : MCD Application Team -* Version : V2.2.1 -* Date : 09/22/2008 -* Description : Interface prototype functions to USB cell registers -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __USB_REGS_H -#define __USB_REGS_H - -/* Includes ------------------------------------------------------------------*/ -/* Exported types ------------------------------------------------------------*/ -#if defined(__cplusplus) -extern "C" { -#endif - -typedef enum _EP_DBUF_DIR -{ - /* double buffered endpoint direction */ - EP_DBUF_ERR, - EP_DBUF_OUT, - EP_DBUF_IN -}EP_DBUF_DIR; - -/* endpoint buffer number */ -enum EP_BUF_NUM -{ - EP_NOBUF, - EP_BUF0, - EP_BUF1 -}; - -/* Exported constants --------------------------------------------------------*/ -#define RegBase (0x40005C00L) /* USB_IP Peripheral Registers base address */ -#define PMAAddr (0x40006000L) /* USB_IP Packet Memory Area base address */ - -/******************************************************************************/ -/* General registers */ -/******************************************************************************/ - -/* Control register */ -#define CNTR ((volatile unsigned *)(RegBase + 0x40)) -/* Interrupt status register */ -#define ISTR ((volatile unsigned *)(RegBase + 0x44)) -/* Frame number register */ -#define FNR ((volatile unsigned *)(RegBase + 0x48)) -/* Device address register */ -#define DADDR ((volatile unsigned *)(RegBase + 0x4C)) -/* Buffer Table address register */ -#define BTABLE ((volatile unsigned *)(RegBase + 0x50)) -/******************************************************************************/ -/* Endpoint registers */ -/******************************************************************************/ -#define EP0REG ((volatile unsigned *)(RegBase)) /* endpoint 0 register address */ - -/* endpoints enumeration */ -#define ENDP0 ((u8)0) -#define ENDP1 ((u8)1) -#define ENDP2 ((u8)2) -#define ENDP3 ((u8)3) -#define ENDP4 ((u8)4) -#define ENDP5 ((u8)5) -#define ENDP6 ((u8)6) -#define ENDP7 ((u8)7) -/******************************************************************************/ -/* ISTR interrupt events */ -/******************************************************************************/ -#define ISTR_CTR (0x8000) /* Correct TRansfer (clear-only bit) */ -#define ISTR_DOVR (0x4000) /* DMA OVeR/underrun (clear-only bit) */ -#define ISTR_ERR (0x2000) /* ERRor (clear-only bit) */ -#define ISTR_WKUP (0x1000) /* WaKe UP (clear-only bit) */ -#define ISTR_SUSP (0x0800) /* SUSPend (clear-only bit) */ -#define ISTR_RESET (0x0400) /* RESET (clear-only bit) */ -#define ISTR_SOF (0x0200) /* Start Of Frame (clear-only bit) */ -#define ISTR_ESOF (0x0100) /* Expected Start Of Frame (clear-only bit) */ - - -#define ISTR_DIR (0x0010) /* DIRection of transaction (read-only bit) */ -#define ISTR_EP_ID (0x000F) /* EndPoint IDentifier (read-only bit) */ - -#define CLR_CTR (~ISTR_CTR) /* clear Correct TRansfer bit */ -#define CLR_DOVR (~ISTR_DOVR) /* clear DMA OVeR/underrun bit*/ -#define CLR_ERR (~ISTR_ERR) /* clear ERRor bit */ -#define CLR_WKUP (~ISTR_WKUP) /* clear WaKe UP bit */ -#define CLR_SUSP (~ISTR_SUSP) /* clear SUSPend bit */ -#define CLR_RESET (~ISTR_RESET) /* clear RESET bit */ -#define CLR_SOF (~ISTR_SOF) /* clear Start Of Frame bit */ -#define CLR_ESOF (~ISTR_ESOF) /* clear Expected Start Of Frame bit */ - -/******************************************************************************/ -/* CNTR control register bits definitions */ -/******************************************************************************/ -#define CNTR_CTRM (0x8000) /* Correct TRansfer Mask */ -#define CNTR_DOVRM (0x4000) /* DMA OVeR/underrun Mask */ -#define CNTR_ERRM (0x2000) /* ERRor Mask */ -#define CNTR_WKUPM (0x1000) /* WaKe UP Mask */ -#define CNTR_SUSPM (0x0800) /* SUSPend Mask */ -#define CNTR_RESETM (0x0400) /* RESET Mask */ -#define CNTR_SOFM (0x0200) /* Start Of Frame Mask */ -#define CNTR_ESOFM (0x0100) /* Expected Start Of Frame Mask */ - - -#define CNTR_RESUME (0x0010) /* RESUME request */ -#define CNTR_FSUSP (0x0008) /* Force SUSPend */ -#define CNTR_LPMODE (0x0004) /* Low-power MODE */ -#define CNTR_PDWN (0x0002) /* Power DoWN */ -#define CNTR_FRES (0x0001) /* Force USB RESet */ - -/******************************************************************************/ -/* FNR Frame Number Register bit definitions */ -/******************************************************************************/ -#define FNR_RXDP (0x8000) /* status of D+ data line */ -#define FNR_RXDM (0x4000) /* status of D- data line */ -#define FNR_LCK (0x2000) /* LoCKed */ -#define FNR_LSOF (0x1800) /* Lost SOF */ -#define FNR_FN (0x07FF) /* Frame Number */ -/******************************************************************************/ -/* DADDR Device ADDRess bit definitions */ -/******************************************************************************/ -#define DADDR_EF (0x80) -#define DADDR_ADD (0x7F) -/******************************************************************************/ -/* Endpoint register */ -/******************************************************************************/ -/* bit positions */ -#define EP_CTR_RX (0x8000) /* EndPoint Correct TRansfer RX */ -#define EP_DTOG_RX (0x4000) /* EndPoint Data TOGGLE RX */ -#define EPRX_STAT (0x3000) /* EndPoint RX STATus bit field */ -#define EP_SETUP (0x0800) /* EndPoint SETUP */ -#define EP_T_FIELD (0x0600) /* EndPoint TYPE */ -#define EP_KIND (0x0100) /* EndPoint KIND */ -#define EP_CTR_TX (0x0080) /* EndPoint Correct TRansfer TX */ -#define EP_DTOG_TX (0x0040) /* EndPoint Data TOGGLE TX */ -#define EPTX_STAT (0x0030) /* EndPoint TX STATus bit field */ -#define EPADDR_FIELD (0x000F) /* EndPoint ADDRess FIELD */ - -/* EndPoint REGister MASK (no toggle fields) */ -#define EPREG_MASK (EP_CTR_RX|EP_SETUP|EP_T_FIELD|EP_KIND|EP_CTR_TX|EPADDR_FIELD) - -/* EP_TYPE[1:0] EndPoint TYPE */ -#define EP_TYPE_MASK (0x0600) /* EndPoint TYPE Mask */ -#define EP_BULK (0x0000) /* EndPoint BULK */ -#define EP_CONTROL (0x0200) /* EndPoint CONTROL */ -#define EP_ISOCHRONOUS (0x0400) /* EndPoint ISOCHRONOUS */ -#define EP_INTERRUPT (0x0600) /* EndPoint INTERRUPT */ -#define EP_T_MASK (~EP_T_FIELD & EPREG_MASK) - - -/* EP_KIND EndPoint KIND */ -#define EPKIND_MASK (~EP_KIND & EPREG_MASK) - -/* STAT_TX[1:0] STATus for TX transfer */ -#define EP_TX_DIS (0x0000) /* EndPoint TX DISabled */ -#define EP_TX_STALL (0x0010) /* EndPoint TX STALLed */ -#define EP_TX_NAK (0x0020) /* EndPoint TX NAKed */ -#define EP_TX_VALID (0x0030) /* EndPoint TX VALID */ -#define EPTX_DTOG1 (0x0010) /* EndPoint TX Data TOGgle bit1 */ -#define EPTX_DTOG2 (0x0020) /* EndPoint TX Data TOGgle bit2 */ -#define EPTX_DTOGMASK (EPTX_STAT|EPREG_MASK) - -/* STAT_RX[1:0] STATus for RX transfer */ -#define EP_RX_DIS (0x0000) /* EndPoint RX DISabled */ -#define EP_RX_STALL (0x1000) /* EndPoint RX STALLed */ -#define EP_RX_NAK (0x2000) /* EndPoint RX NAKed */ -#define EP_RX_VALID (0x3000) /* EndPoint RX VALID */ -#define EPRX_DTOG1 (0x1000) /* EndPoint RX Data TOGgle bit1 */ -#define EPRX_DTOG2 (0x2000) /* EndPoint RX Data TOGgle bit1 */ -#define EPRX_DTOGMASK (EPRX_STAT|EPREG_MASK) -/* Exported macro ------------------------------------------------------------*/ -/* SetCNTR */ -#define _SetCNTR(wRegValue) (*CNTR = (u16)wRegValue) - -/* SetISTR */ -#define _SetISTR(wRegValue) (*ISTR = (u16)wRegValue) - -/* SetDADDR */ -#define _SetDADDR(wRegValue) (*DADDR = (u16)wRegValue) - -/* SetBTABLE */ -#define _SetBTABLE(wRegValue)(*BTABLE = (u16)(wRegValue & 0xFFF8)) - -/* GetCNTR */ -#define _GetCNTR() ((u16) *CNTR) - -/* GetISTR */ -#define _GetISTR() ((u16) *ISTR) - -/* GetFNR */ -#define _GetFNR() ((u16) *FNR) - -/* GetDADDR */ -#define _GetDADDR() ((u16) *DADDR) - -/* GetBTABLE */ -#define _GetBTABLE() ((u16) *BTABLE) - -/* SetENDPOINT */ -#define _SetENDPOINT(bEpNum,wRegValue) (*(EP0REG + bEpNum)= \ - (u16)wRegValue) - -/* GetENDPOINT */ -#define _GetENDPOINT(bEpNum) ((u16)(*(EP0REG + bEpNum))) - -/******************************************************************************* -* Macro Name : SetEPType -* Description : sets the type in the endpoint register(bits EP_TYPE[1:0]) -* Input : bEpNum: Endpoint Number. -* wType -* Output : None. -* Return : None. -*******************************************************************************/ -#define _SetEPType(bEpNum,wType) (_SetENDPOINT(bEpNum,\ - ((_GetENDPOINT(bEpNum) & EP_T_MASK) | wType))) - -/******************************************************************************* -* Macro Name : GetEPType -* Description : gets the type in the endpoint register(bits EP_TYPE[1:0]) -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : Endpoint Type -*******************************************************************************/ -#define _GetEPType(bEpNum) (_GetENDPOINT(bEpNum) & EP_T_FIELD) - -/******************************************************************************* -* Macro Name : SetEPTxStatus -* Description : sets the status for tx transfer (bits STAT_TX[1:0]). -* Input : bEpNum: Endpoint Number. -* wState: new state -* Output : None. -* Return : None. -*******************************************************************************/ -#define _SetEPTxStatus(bEpNum,wState) {\ - register u16 _wRegVal; \ - _wRegVal = _GetENDPOINT(bEpNum) & EPTX_DTOGMASK;\ - /* toggle first bit ? */ \ - if((EPTX_DTOG1 & wState)!= 0) \ - _wRegVal ^= EPTX_DTOG1; \ - /* toggle second bit ? */ \ - if((EPTX_DTOG2 & wState)!= 0) \ - _wRegVal ^= EPTX_DTOG2; \ - _SetENDPOINT(bEpNum, _wRegVal); \ - } /* _SetEPTxStatus */ - -/******************************************************************************* -* Macro Name : SetEPRxStatus -* Description : sets the status for rx transfer (bits STAT_TX[1:0]) -* Input : bEpNum: Endpoint Number. -* wState: new state. -* Output : None. -* Return : None. -*******************************************************************************/ -#define _SetEPRxStatus(bEpNum,wState) {\ - register u16 _wRegVal; \ - \ - _wRegVal = _GetENDPOINT(bEpNum) & EPRX_DTOGMASK;\ - /* toggle first bit ? */ \ - if((EPRX_DTOG1 & wState)!= 0) \ - _wRegVal ^= EPRX_DTOG1; \ - /* toggle second bit ? */ \ - if((EPRX_DTOG2 & wState)!= 0) \ - _wRegVal ^= EPRX_DTOG2; \ - _SetENDPOINT(bEpNum, _wRegVal); \ - } /* _SetEPRxStatus */ -/******************************************************************************* -* Macro Name : GetEPTxStatus / GetEPRxStatus -* Description : gets the status for tx/rx transfer (bits STAT_TX[1:0] -* /STAT_RX[1:0]) -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : status . -*******************************************************************************/ -#define _GetEPTxStatus(bEpNum) ((u16)_GetENDPOINT(bEpNum) & EPTX_STAT) - -#define _GetEPRxStatus(bEpNum) ((u16)_GetENDPOINT(bEpNum) & EPRX_STAT) - -/******************************************************************************* -* Macro Name : SetEPTxValid / SetEPRxValid -* Description : sets directly the VALID tx/rx-status into the enpoint register -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -#define _SetEPTxValid(bEpNum) (_SetEPTxStatus(bEpNum, EP_TX_VALID)) - -#define _SetEPRxValid(bEpNum) (_SetEPRxStatus(bEpNum, EP_RX_VALID)) - -/******************************************************************************* -* Macro Name : GetTxStallStatus / GetRxStallStatus. -* Description : checks stall condition in an endpoint. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : TRUE = endpoint in stall condition. -*******************************************************************************/ -#define _GetTxStallStatus(bEpNum) (_GetEPTxStatus(bEpNum) \ - == EP_TX_STALL) -#define _GetRxStallStatus(bEpNum) (_GetEPRxStatus(bEpNum) \ - == EP_RX_STALL) - -/******************************************************************************* -* Macro Name : SetEP_KIND / ClearEP_KIND. -* Description : set & clear EP_KIND bit. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -#define _SetEP_KIND(bEpNum) (_SetENDPOINT(bEpNum, \ - (_GetENDPOINT(bEpNum) | EP_KIND) & EPREG_MASK)) -#define _ClearEP_KIND(bEpNum) (_SetENDPOINT(bEpNum, \ - (_GetENDPOINT(bEpNum) & EPKIND_MASK))) - -/******************************************************************************* -* Macro Name : Set_Status_Out / Clear_Status_Out. -* Description : Sets/clears directly STATUS_OUT bit in the endpoint register. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -#define _Set_Status_Out(bEpNum) _SetEP_KIND(bEpNum) -#define _Clear_Status_Out(bEpNum) _ClearEP_KIND(bEpNum) - -/******************************************************************************* -* Macro Name : SetEPDoubleBuff / ClearEPDoubleBuff. -* Description : Sets/clears directly EP_KIND bit in the endpoint register. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -#define _SetEPDoubleBuff(bEpNum) _SetEP_KIND(bEpNum) -#define _ClearEPDoubleBuff(bEpNum) _ClearEP_KIND(bEpNum) - -/******************************************************************************* -* Macro Name : ClearEP_CTR_RX / ClearEP_CTR_TX. -* Description : Clears bit CTR_RX / CTR_TX in the endpoint register. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -#define _ClearEP_CTR_RX(bEpNum) (_SetENDPOINT(bEpNum,\ - _GetENDPOINT(bEpNum) & 0x7FFF & EPREG_MASK)) -#define _ClearEP_CTR_TX(bEpNum) (_SetENDPOINT(bEpNum,\ - _GetENDPOINT(bEpNum) & 0xFF7F & EPREG_MASK)) - -/******************************************************************************* -* Macro Name : ToggleDTOG_RX / ToggleDTOG_TX . -* Description : Toggles DTOG_RX / DTOG_TX bit in the endpoint register. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -#define _ToggleDTOG_RX(bEpNum) (_SetENDPOINT(bEpNum, \ - EP_DTOG_RX | (_GetENDPOINT(bEpNum) & EPREG_MASK))) -#define _ToggleDTOG_TX(bEpNum) (_SetENDPOINT(bEpNum, \ - EP_DTOG_TX | (_GetENDPOINT(bEpNum) & EPREG_MASK))) - -/******************************************************************************* -* Macro Name : ClearDTOG_RX / ClearDTOG_TX. -* Description : Clears DTOG_RX / DTOG_TX bit in the endpoint register. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -#define _ClearDTOG_RX(bEpNum) if((_GetENDPOINT(bEpNum) & EP_DTOG_RX) != 0)\ - _ToggleDTOG_RX(bEpNum) -#define _ClearDTOG_TX(bEpNum) if((_GetENDPOINT(bEpNum) & EP_DTOG_TX) != 0)\ - _ToggleDTOG_TX(bEpNum) -/******************************************************************************* -* Macro Name : SetEPAddress. -* Description : Sets address in an endpoint register. -* Input : bEpNum: Endpoint Number. -* bAddr: Address. -* Output : None. -* Return : None. -*******************************************************************************/ -#define _SetEPAddress(bEpNum,bAddr) _SetENDPOINT(bEpNum,\ - (_GetENDPOINT(bEpNum) & EPREG_MASK) | bAddr) - -/******************************************************************************* -* Macro Name : GetEPAddress. -* Description : Gets address in an endpoint register. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -#define _GetEPAddress(bEpNum) ((u8)(_GetENDPOINT(bEpNum) & EPADDR_FIELD)) - -#define _pEPTxAddr(bEpNum) ((u32 *)((_GetBTABLE()+bEpNum*8 )*2 + PMAAddr)) -#define _pEPTxCount(bEpNum) ((u32 *)((_GetBTABLE()+bEpNum*8+2)*2 + PMAAddr)) -#define _pEPRxAddr(bEpNum) ((u32 *)((_GetBTABLE()+bEpNum*8+4)*2 + PMAAddr)) -#define _pEPRxCount(bEpNum) ((u32 *)((_GetBTABLE()+bEpNum*8+6)*2 + PMAAddr)) - -/******************************************************************************* -* Macro Name : SetEPTxAddr / SetEPRxAddr. -* Description : sets address of the tx/rx buffer. -* Input : bEpNum: Endpoint Number. -* wAddr: address to be set (must be word aligned). -* Output : None. -* Return : None. -*******************************************************************************/ -#define _SetEPTxAddr(bEpNum,wAddr) (*_pEPTxAddr(bEpNum) = ((wAddr >> 1) << 1)) -#define _SetEPRxAddr(bEpNum,wAddr) (*_pEPRxAddr(bEpNum) = ((wAddr >> 1) << 1)) - -/******************************************************************************* -* Macro Name : GetEPTxAddr / GetEPRxAddr. -* Description : Gets address of the tx/rx buffer. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : address of the buffer. -*******************************************************************************/ -#define _GetEPTxAddr(bEpNum) ((u16)*_pEPTxAddr(bEpNum)) -#define _GetEPRxAddr(bEpNum) ((u16)*_pEPRxAddr(bEpNum)) - -/******************************************************************************* -* Macro Name : SetEPCountRxReg. -* Description : Sets counter of rx buffer with no. of blocks. -* Input : pdwReg: pointer to counter. -* wCount: Counter. -* Output : None. -* Return : None. -*******************************************************************************/ -#define _BlocksOf32(dwReg,wCount,wNBlocks) {\ - wNBlocks = wCount >> 5;\ - if((wCount & 0x1f) == 0)\ - wNBlocks--;\ - *pdwReg = (u32)((wNBlocks << 10) | 0x8000);\ - }/* _BlocksOf32 */ - -#define _BlocksOf2(dwReg,wCount,wNBlocks) {\ - wNBlocks = wCount >> 1;\ - if((wCount & 0x1) != 0)\ - wNBlocks++;\ - *pdwReg = (u32)(wNBlocks << 10);\ - }/* _BlocksOf2 */ - -#define _SetEPCountRxReg(dwReg,wCount) {\ - u16 wNBlocks;\ - if(wCount > 62){_BlocksOf32(dwReg,wCount,wNBlocks);}\ - else {_BlocksOf2(dwReg,wCount,wNBlocks);}\ - }/* _SetEPCountRxReg */ - - - -#define _SetEPRxDblBuf0Count(bEpNum,wCount) {\ - u32 *pdwReg = _pEPTxCount(bEpNum); \ - _SetEPCountRxReg(pdwReg, wCount);\ - } -/******************************************************************************* -* Macro Name : SetEPTxCount / SetEPRxCount. -* Description : sets counter for the tx/rx buffer. -* Input : bEpNum: endpoint number. -* wCount: Counter value. -* Output : None. -* Return : None. -*******************************************************************************/ -#define _SetEPTxCount(bEpNum,wCount) (*_pEPTxCount(bEpNum) = wCount) -#define _SetEPRxCount(bEpNum,wCount) {\ - u32 *pdwReg = _pEPRxCount(bEpNum); \ - _SetEPCountRxReg(pdwReg, wCount);\ - } -/******************************************************************************* -* Macro Name : GetEPTxCount / GetEPRxCount. -* Description : gets counter of the tx buffer. -* Input : bEpNum: endpoint number. -* Output : None. -* Return : Counter value. -*******************************************************************************/ -#define _GetEPTxCount(bEpNum)((u16)(*_pEPTxCount(bEpNum)) & 0x3ff) -#define _GetEPRxCount(bEpNum)((u16)(*_pEPRxCount(bEpNum)) & 0x3ff) - -/******************************************************************************* -* Macro Name : SetEPDblBuf0Addr / SetEPDblBuf1Addr. -* Description : Sets buffer 0/1 address in a double buffer endpoint. -* Input : bEpNum: endpoint number. -* : wBuf0Addr: buffer 0 address. -* Output : None. -* Return : None. -*******************************************************************************/ -#define _SetEPDblBuf0Addr(bEpNum,wBuf0Addr) {_SetEPTxAddr(bEpNum, wBuf0Addr);} -#define _SetEPDblBuf1Addr(bEpNum,wBuf1Addr) {_SetEPRxAddr(bEpNum, wBuf1Addr);} - -/******************************************************************************* -* Macro Name : SetEPDblBuffAddr. -* Description : Sets addresses in a double buffer endpoint. -* Input : bEpNum: endpoint number. -* : wBuf0Addr: buffer 0 address. -* : wBuf1Addr = buffer 1 address. -* Output : None. -* Return : None. -*******************************************************************************/ -#define _SetEPDblBuffAddr(bEpNum,wBuf0Addr,wBuf1Addr) { \ - _SetEPDblBuf0Addr(bEpNum, wBuf0Addr);\ - _SetEPDblBuf1Addr(bEpNum, wBuf1Addr);\ - } /* _SetEPDblBuffAddr */ - -/******************************************************************************* -* Macro Name : GetEPDblBuf0Addr / GetEPDblBuf1Addr. -* Description : Gets buffer 0/1 address of a double buffer endpoint. -* Input : bEpNum: endpoint number. -* Output : None. -* Return : None. -*******************************************************************************/ -#define _GetEPDblBuf0Addr(bEpNum) (_GetEPTxAddr(bEpNum)) -#define _GetEPDblBuf1Addr(bEpNum) (_GetEPRxAddr(bEpNum)) - -/******************************************************************************* -* Macro Name : SetEPDblBuffCount / SetEPDblBuf0Count / SetEPDblBuf1Count. -* Description : Gets buffer 0/1 address of a double buffer endpoint. -* Input : bEpNum: endpoint number. -* : bDir: endpoint dir EP_DBUF_OUT = OUT -* EP_DBUF_IN = IN -* : wCount: Counter value -* Output : None. -* Return : None. -*******************************************************************************/ -#define _SetEPDblBuf0Count(bEpNum, bDir, wCount) { \ - if(bDir == EP_DBUF_OUT)\ - /* OUT endpoint */ \ - {_SetEPRxDblBuf0Count(bEpNum,wCount);} \ - else if(bDir == EP_DBUF_IN)\ - /* IN endpoint */ \ - *_pEPTxCount(bEpNum) = (u32)wCount; \ - } /* SetEPDblBuf0Count*/ - -#define _SetEPDblBuf1Count(bEpNum, bDir, wCount) { \ - if(bDir == EP_DBUF_OUT)\ - /* OUT endpoint */ \ - {_SetEPRxCount(bEpNum,wCount);}\ - else if(bDir == EP_DBUF_IN)\ - /* IN endpoint */\ - *_pEPRxCount(bEpNum) = (u32)wCount; \ - } /* SetEPDblBuf1Count */ - -#define _SetEPDblBuffCount(bEpNum, bDir, wCount) {\ - _SetEPDblBuf0Count(bEpNum, bDir, wCount); \ - _SetEPDblBuf1Count(bEpNum, bDir, wCount); \ - } /* _SetEPDblBuffCount */ - -/******************************************************************************* -* Macro Name : GetEPDblBuf0Count / GetEPDblBuf1Count. -* Description : Gets buffer 0/1 rx/tx counter for double buffering. -* Input : bEpNum: endpoint number. -* Output : None. -* Return : None. -*******************************************************************************/ -#define _GetEPDblBuf0Count(bEpNum) (_GetEPTxCount(bEpNum)) -#define _GetEPDblBuf1Count(bEpNum) (_GetEPRxCount(bEpNum)) - - -/* External variables --------------------------------------------------------*/ -extern volatile u16 wIstr; /* ISTR register last read value */ - -/* Exported functions ------------------------------------------------------- */ -void SetCNTR(u16 /*wRegValue*/); -void SetISTR(u16 /*wRegValue*/); -void SetDADDR(u16 /*wRegValue*/); -void SetBTABLE(u16 /*wRegValue*/); -u16 GetCNTR(void); -u16 GetISTR(void); -u16 GetFNR(void); -u16 GetDADDR(void); -u16 GetBTABLE(void); -void SetENDPOINT(u8 /*bEpNum*/, u16 /*wRegValue*/); -u16 GetENDPOINT(u8 /*bEpNum*/); -void SetEPType(u8 /*bEpNum*/, u16 /*wType*/); -u16 GetEPType(u8 /*bEpNum*/); -void SetEPTxStatus(u8 /*bEpNum*/, u16 /*wState*/); -void SetEPRxStatus(u8 /*bEpNum*/, u16 /*wState*/); -void SetDouBleBuffEPStall(u8 /*bEpNum*/, u8 bDir); -u16 GetEPTxStatus(u8 /*bEpNum*/); -u16 GetEPRxStatus(u8 /*bEpNum*/); -void SetEPTxValid(u8 /*bEpNum*/); -void SetEPRxValid(u8 /*bEpNum*/); -u16 GetTxStallStatus(u8 /*bEpNum*/); -u16 GetRxStallStatus(u8 /*bEpNum*/); -void SetEP_KIND(u8 /*bEpNum*/); -void ClearEP_KIND(u8 /*bEpNum*/); -void Set_Status_Out(u8 /*bEpNum*/); -void Clear_Status_Out(u8 /*bEpNum*/); -void SetEPDoubleBuff(u8 /*bEpNum*/); -void ClearEPDoubleBuff(u8 /*bEpNum*/); -void ClearEP_CTR_RX(u8 /*bEpNum*/); -void ClearEP_CTR_TX(u8 /*bEpNum*/); -void ToggleDTOG_RX(u8 /*bEpNum*/); -void ToggleDTOG_TX(u8 /*bEpNum*/); -void ClearDTOG_RX(u8 /*bEpNum*/); -void ClearDTOG_TX(u8 /*bEpNum*/); -void SetEPAddress(u8 /*bEpNum*/, u8 /*bAddr*/); -u8 GetEPAddress(u8 /*bEpNum*/); -void SetEPTxAddr(u8 /*bEpNum*/, u16 /*wAddr*/); -void SetEPRxAddr(u8 /*bEpNum*/, u16 /*wAddr*/); -u16 GetEPTxAddr(u8 /*bEpNum*/); -u16 GetEPRxAddr(u8 /*bEpNum*/); -void SetEPCountRxReg(u32 * /*pdwReg*/, u16 /*wCount*/); -void SetEPTxCount(u8 /*bEpNum*/, u16 /*wCount*/); -void SetEPRxCount(u8 /*bEpNum*/, u16 /*wCount*/); -u16 GetEPTxCount(u8 /*bEpNum*/); -u16 GetEPRxCount(u8 /*bEpNum*/); -void SetEPDblBuf0Addr(u8 /*bEpNum*/, u16 /*wBuf0Addr*/); -void SetEPDblBuf1Addr(u8 /*bEpNum*/, u16 /*wBuf1Addr*/); -void SetEPDblBuffAddr(u8 /*bEpNum*/, u16 /*wBuf0Addr*/, u16 /*wBuf1Addr*/); -u16 GetEPDblBuf0Addr(u8 /*bEpNum*/); -u16 GetEPDblBuf1Addr(u8 /*bEpNum*/); -void SetEPDblBuffCount(u8 /*bEpNum*/, u8 /*bDir*/, u16 /*wCount*/); -void SetEPDblBuf0Count(u8 /*bEpNum*/, u8 /*bDir*/, u16 /*wCount*/); -void SetEPDblBuf1Count(u8 /*bEpNum*/, u8 /*bDir*/, u16 /*wCount*/); -u16 GetEPDblBuf0Count(u8 /*bEpNum*/); -u16 GetEPDblBuf1Count(u8 /*bEpNum*/); -EP_DBUF_DIR GetEPDblBufDir(u8 /*bEpNum*/); -void FreeUserBuffer(u8 bEpNum/*bEpNum*/, u8 bDir); -u16 ToWord(u8, u8); -u16 ByteSwap(u16); - -#if defined(__cplusplus) -} -#endif - -#endif /* __USB_REGS_H */ - -/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/ diff --git a/STM32F3/cores/maple/libmaple/usb/usb_lib/usb_type.h b/STM32F3/cores/maple/libmaple/usb/usb_lib/usb_type.h deleted file mode 100644 index 34b3bf5..0000000 --- a/STM32F3/cores/maple/libmaple/usb/usb_lib/usb_type.h +++ /dev/null @@ -1,77 +0,0 @@ -/******************** (C) COPYRIGHT 2008 STMicroelectronics ******************** -* File Name : usb_type.h -* Author : MCD Application Team -* Version : V2.2.1 -* Date : 09/22/2008 -* Description : Type definitions used by the USB Library -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __USB_TYPE_H -#define __USB_TYPE_H - -#if defined(__cplusplus) -extern "C" { -#endif - -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ -#ifndef NULL -#define NULL ((void *)0) -#endif - -typedef signed long s32; -typedef signed short s16; -typedef signed char s8; - -typedef volatile signed long vs32; -typedef volatile signed short vs16; -typedef volatile signed char vs8; - -typedef unsigned long u32; -typedef unsigned short u16; -typedef unsigned char u8; - -typedef unsigned long const uc32; /* Read Only */ -typedef unsigned short const uc16; /* Read Only */ -typedef unsigned char const uc8; /* Read Only */ - -typedef volatile unsigned long vu32; -typedef volatile unsigned short vu16; -typedef volatile unsigned char vu8; - -typedef volatile unsigned long const vuc32; /* Read Only */ -typedef volatile unsigned short const vuc16; /* Read Only */ -typedef volatile unsigned char const vuc8; /* Read Only */ - - -typedef enum -{ - FALSE = 0, TRUE = !FALSE -} -USB_Bool; - -typedef enum { RESET = 0, SET = !RESET } FlagStatus, ITStatus; - -typedef enum { DISABLE = 0, ENABLE = !DISABLE} FunctionalState; - -typedef enum { ERROR = 0, SUCCESS = !ERROR} ErrorStatus; - -/* Exported macro ------------------------------------------------------------*/ -/* Exported functions ------------------------------------------------------- */ -/* External variables --------------------------------------------------------*/ - -#if defined(__cplusplus) -} -#endif - -#endif /* __USB_TYPE_H */ - -/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/ diff --git a/STM32F3/cores/maple/libmaple/usb/usb_lib_globals.h b/STM32F3/cores/maple/libmaple/usb/usb_lib_globals.h deleted file mode 100644 index 1cd2754..0000000 --- a/STM32F3/cores/maple/libmaple/usb/usb_lib_globals.h +++ /dev/null @@ -1,55 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2011 LeafLabs LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -#ifndef _USB_LIB_GLOBALS_H_ -#define _USB_LIB_GLOBALS_H_ - -/* usb_lib headers */ -#include "usb_type.h" -#include "usb_core.h" - -#ifdef __cplusplus -extern "C" { -#endif - -extern USER_STANDARD_REQUESTS User_Standard_Requests; -extern USER_STANDARD_REQUESTS *pUser_Standard_Requests; - -extern DEVICE_PROP Device_Property; -extern DEVICE_PROP *pProperty; - -extern DEVICE_INFO Device_Info; -extern DEVICE_INFO *pInformation; - -extern DEVICE Device_Table; -extern u16 SaveRState; -extern u16 SaveTState; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/STM32F3/cores/maple/libmaple/usb/usb_reg_map.c b/STM32F3/cores/maple/libmaple/usb/usb_reg_map.c deleted file mode 100644 index ea60cb3..0000000 --- a/STM32F3/cores/maple/libmaple/usb/usb_reg_map.c +++ /dev/null @@ -1,88 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2011 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -#include "usb_reg_map.h" - -/* 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. */ - -void usb_copy_to_pma(const uint8 *buf, uint16 len, uint16 pma_offset) { - uint16 *dst = (uint16*)usb_pma_ptr(pma_offset); - uint16 n = len >> 1; - uint16 i; - for (i = 0; i < n; i++) { - *dst = (uint16)(*buf) | *(buf + 1) << 8; - buf += 2; - dst += 2; - } - if (len & 1) { - *dst = *buf; - } -} - -void usb_copy_from_pma(uint8 *buf, uint16 len, uint16 pma_offset) { - uint32 *src = (uint32*)usb_pma_ptr(pma_offset); - uint16 *dst = (uint16*)buf; - uint16 n = len >> 1; - uint16 i; - for (i = 0; i < n; i++) { - *dst++ = *src++; - } - if (len & 1) { - *dst = *src & 0xFF; - } -} - -static void usb_set_ep_rx_count_common(uint32 *rxc, uint16 count) { - uint16 nblocks; - if (count > 62) { - /* use 32-byte memory block size */ - nblocks = count >> 5; - if ((count & 0x1F) == 0) { - nblocks--; - } - *rxc = (nblocks << 10) | 0x8000; - } else { - /* use 2-byte memory block size */ - nblocks = count >> 1; - if ((count & 0x1) != 0) { - nblocks++; - } - *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/STM32F3/cores/maple/libmaple/usb/usb_reg_map.h b/STM32F3/cores/maple/libmaple/usb/usb_reg_map.h deleted file mode 100644 index 2cd5e35..0000000 --- a/STM32F3/cores/maple/libmaple/usb/usb_reg_map.h +++ /dev/null @@ -1,617 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2011 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -#include -#include - -#ifndef _USB_REG_MAP_H_ -#define _USB_REG_MAP_H_ - -/* TODO: - * - Pick one of "endp", "ep" "endpt" - */ - -/* - * Register map and base pointer - */ - -#define USB_NR_EP_REGS 8 - -/** USB register map type */ -typedef struct usb_reg_map { - __IO uint32 EP[USB_NR_EP_REGS]; /**< Endpoint registers */ - const uint32 RESERVED[8]; /**< Reserved */ - __IO uint32 CNTR; /**< Control register */ - __IO uint32 ISTR; /**< Interrupt status register */ - __IO uint32 FNR; /**< Frame number register */ - __IO uint32 DADDR; /**< Device address */ - __IO uint32 BTABLE; /**< @brief Buffer table address - * - * Address offset within the USB - * packet memory area which points - * to the base of the buffer - * descriptor table. Must be - * aligned to an 8 byte boundary. - */ -} usb_reg_map; - -/** USB register map base pointer */ -#define USB_BASE ((struct usb_reg_map*)0x40005C00) - -/* - * Register bit definitions - */ - -/* Endpoint registers (USB_EPnR) */ - -#define USB_EP_CTR_RX_BIT 15 -#define USB_EP_DTOG_RX_BIT 14 -#define USB_EP_SETUP_BIT 11 -#define USB_EP_EP_KIND_BIT 8 -#define USB_EP_CTR_TX_BIT 7 -#define USB_EP_DTOG_TX_BIT 6 - -#define USB_EP_CTR_RX BIT(USB_EP_CTR_RX_BIT) -#define USB_EP_DTOG_RX BIT(USB_EP_DTOG_RX_BIT) -#define USB_EP_STAT_RX (0x3 << 12) -#define USB_EP_STAT_RX_DISABLED (0x0 << 12) -#define USB_EP_STAT_RX_STALL (0x1 << 12) -#define USB_EP_STAT_RX_NAK (0x2 << 12) -#define USB_EP_STAT_RX_VALID (0x3 << 12) -#define USB_EP_SETUP BIT(USB_EP_SETUP_BIT) -#define USB_EP_EP_TYPE (0x3 << 9) -#define USB_EP_EP_TYPE_BULK (0x0 << 9) -#define USB_EP_EP_TYPE_CONTROL (0x1 << 9) -#define USB_EP_EP_TYPE_ISO (0x2 << 9) -#define USB_EP_EP_TYPE_INTERRUPT (0x3 << 9) -#define USB_EP_EP_KIND BIT(USB_EP_EP_KIND_BIT) -#define USB_EP_EP_KIND_DBL_BUF (0x1 << USB_EP_EP_KIND_BIT) -#define USB_EP_CTR_TX BIT(USB_EP_CTR_TX_BIT) -#define USB_EP_DTOG_TX BIT(USB_EP_DTOG_TX_BIT) -#define USB_EP_STAT_TX (0x3 << 4) -#define USB_EP_STAT_TX_DISABLED (0x0 << 4) -#define USB_EP_STAT_TX_STALL (0x1 << 4) -#define USB_EP_STAT_TX_NAK (0x2 << 4) -#define USB_EP_STAT_TX_VALID (0x3 << 4) -#define USB_EP_EA 0xF - -/* Control register (USB_CNTR) */ - -#define USB_CNTR_CTRM_BIT 15 -#define USB_CNTR_PMAOVERM_BIT 14 -#define USB_CNTR_ERRM_BIT 13 -#define USB_CNTR_WKUPM_BIT 12 -#define USB_CNTR_SUSPM_BIT 11 -#define USB_CNTR_RESETM_BIT 10 -#define USB_CNTR_SOFM_BIT 9 -#define USB_CNTR_ESOFM_BIT 8 -#define USB_CNTR_RESUME_BIT 4 -#define USB_CNTR_FSUSP_BIT 3 -#define USB_CNTR_LP_MODE_BIT 2 -#define USB_CNTR_PDWN_BIT 1 -#define USB_CNTR_FRES_BIT 0 - -#define USB_CNTR_CTRM BIT(USB_CNTR_CTRM_BIT) -#define USB_CNTR_PMAOVERM BIT(USB_CNTR_PMAOVERM_BIT) -#define USB_CNTR_ERRM BIT(USB_CNTR_ERRM_BIT) -#define USB_CNTR_WKUPM BIT(USB_CNTR_WKUPM_BIT) -#define USB_CNTR_SUSPM BIT(USB_CNTR_SUSPM_BIT) -#define USB_CNTR_RESETM BIT(USB_CNTR_RESETM_BIT) -#define USB_CNTR_SOFM BIT(USB_CNTR_SOFM_BIT) -#define USB_CNTR_ESOFM BIT(USB_CNTR_ESOFM_BIT) -#define USB_CNTR_RESUME BIT(USB_CNTR_RESUME_BIT) -#define USB_CNTR_FSUSP BIT(USB_CNTR_FSUSP_BIT) -#define USB_CNTR_LP_MODE BIT(USB_CNTR_LP_MODE_BIT) -#define USB_CNTR_PDWN BIT(USB_CNTR_PDWN_BIT) -#define USB_CNTR_FRES BIT(USB_CNTR_FRES_BIT) - -/* Interrupt status register (USB_ISTR) */ - -#define USB_ISTR_CTR_BIT 15 -#define USB_ISTR_PMAOVR_BIT 14 -#define USB_ISTR_ERR_BIT 13 -#define USB_ISTR_WKUP_BIT 12 -#define USB_ISTR_SUSP_BIT 11 -#define USB_ISTR_RESET_BIT 10 -#define USB_ISTR_SOF_BIT 9 -#define USB_ISTR_ESOF_BIT 8 -#define USB_ISTR_DIR_BIT 4 - -#define USB_ISTR_CTR BIT(USB_ISTR_CTR_BIT) -#define USB_ISTR_PMAOVR BIT(USB_ISTR_PMAOVR_BIT) -#define USB_ISTR_ERR BIT(USB_ISTR_ERR_BIT) -#define USB_ISTR_WKUP BIT(USB_ISTR_WKUP_BIT) -#define USB_ISTR_SUSP BIT(USB_ISTR_SUSP_BIT) -#define USB_ISTR_RESET BIT(USB_ISTR_RESET_BIT) -#define USB_ISTR_SOF BIT(USB_ISTR_SOF_BIT) -#define USB_ISTR_ESOF BIT(USB_ISTR_ESOF_BIT) -#define USB_ISTR_DIR BIT(USB_ISTR_DIR_BIT) -#define USB_ISTR_EP_ID 0xF - -/* Frame number register (USB_FNR) */ - -#define USB_FNR_RXDP_BIT 15 -#define USB_FNR_RXDM_BIT 14 -#define USB_FNR_LCK_BIT 13 - -#define USB_FNR_RXDP BIT(USB_FNR_RXDP_BIT) -#define USB_FNR_RXDM BIT(USB_FNR_RXDM_BIT) -#define USB_FNR_LCK BIT(USB_FNR_LCK_BIT) -#define USB_FNR_LSOF (0x3 << 11) -#define USB_FNR_FN 0x7FF - -/* Device address (USB_DADDR) */ - -#define USB_DADDR_EF_BIT 7 -#define USB_DADDR_ADD6_BIT 6 -#define USB_DADDR_ADD5_BIT 5 -#define USB_DADDR_ADD4_BIT 4 -#define USB_DADDR_ADD3_BIT 3 -#define USB_DADDR_ADD2_BIT 2 -#define USB_DADDR_ADD1_BIT 1 -#define USB_DADDR_ADD0_BIT 0 - -#define USB_DADDR_EF BIT(USB_DADDR_EF_BIT) -#define USB_DADDR_ADD6 BIT(USB_DADDR_ADD6_BIT) -#define USB_DADDR_ADD5 BIT(USB_DADDR_ADD5_BIT) -#define USB_DADDR_ADD4 BIT(USB_DADDR_ADD4_BIT) -#define USB_DADDR_ADD3 BIT(USB_DADDR_ADD3_BIT) -#define USB_DADDR_ADD2 BIT(USB_DADDR_ADD2_BIT) -#define USB_DADDR_ADD1 BIT(USB_DADDR_ADD1_BIT) -#define USB_DADDR_ADD0 BIT(USB_DADDR_ADD0_BIT) - -/* Buffer table address (USB_BTABLE) */ - -#define USB_BTABLE_BTABLE (0x1FFF << 3) - -/* - * Register convenience routines - */ - -#define __EP_CTR_NOP (USB_EP_CTR_RX | USB_EP_CTR_TX) -#define __EP_NONTOGGLE (USB_EP_CTR_RX | USB_EP_SETUP | \ - USB_EP_EP_TYPE | USB_EP_EP_KIND | \ - USB_EP_CTR_TX | USB_EP_EA) - -static inline void usb_clear_ctr_rx(uint8 ep) { - uint32 epr = USB_BASE->EP[ep]; - USB_BASE->EP[ep] = epr & ~USB_EP_CTR_RX & __EP_NONTOGGLE; -} - -static inline void usb_clear_ctr_tx(uint8 ep) { - uint32 epr = USB_BASE->EP[ep]; - USB_BASE->EP[ep] = epr & ~USB_EP_CTR_TX & __EP_NONTOGGLE; -} - -static inline uint32 usb_get_ep_dtog_tx(uint8 ep) { - uint32 epr = USB_BASE->EP[ep]; - return epr & USB_EP_DTOG_TX; -} - -static inline uint32 usb_get_ep_dtog_rx(uint8 ep) { - uint32 epr = USB_BASE->EP[ep]; - return epr & USB_EP_DTOG_RX; -} - -static inline uint32 usb_get_ep_tx_sw_buf(uint8 ep) { - return usb_get_ep_dtog_rx(ep); -} - -static inline uint32 usb_get_ep_rx_sw_buf(uint8 ep) { - return usb_get_ep_dtog_tx(ep); -} - -static inline void usb_toggle_ep_dtog_tx(uint8 ep) { - uint32 epr = USB_BASE->EP[ep]; - epr &= __EP_NONTOGGLE; - epr |= USB_EP_DTOG_TX; - USB_BASE->EP[ep] = epr; -} - -static inline void usb_toggle_ep_dtog_rx(uint8 ep) { - uint32 epr = USB_BASE->EP[ep]; - epr &= __EP_NONTOGGLE; - epr |= USB_EP_DTOG_RX; - USB_BASE->EP[ep] = epr; -} - -static inline void usb_clear_ep_dtog_tx(uint8 ep) { - if (usb_get_ep_dtog_tx(ep) != 0) { - usb_toggle_ep_dtog_tx(ep); - } -} - -static inline void usb_clear_ep_dtog_rx(uint8 ep) { - if (usb_get_ep_dtog_rx(ep) != 0) { - usb_toggle_ep_dtog_rx(ep); - } -} - -static inline void usb_set_ep_dtog_tx(uint8 ep) { - if (usb_get_ep_dtog_tx(ep) == 0) { - usb_toggle_ep_dtog_tx(ep); - } -} - -static inline void usb_set_ep_dtog_rx(uint8 ep) { - if (usb_get_ep_dtog_rx(ep) == 0) { - usb_toggle_ep_dtog_rx(ep); - } -} - -static inline void usb_toggle_ep_rx_sw_buf(uint8 ep) { - usb_toggle_ep_dtog_tx(ep); -} - -static inline void usb_toggle_ep_tx_sw_buf(uint8 ep) { - usb_toggle_ep_dtog_rx(ep); -} - -static inline void usb_clear_ep_rx_sw_buf(uint8 ep) { - usb_clear_ep_dtog_tx(ep); -} - -static inline void usb_clear_ep_tx_sw_buf(uint8 ep) { - usb_clear_ep_dtog_rx(ep); -} - -static inline void usb_set_ep_rx_sw_buf(uint8 ep) { - usb_set_ep_dtog_tx(ep); -} - -static inline void usb_set_ep_tx_sw_buf(uint8 ep) { - usb_set_ep_dtog_rx(ep); -} - -static inline void usb_set_ep_rx_stat(uint8 ep, uint32 status) { - uint32 epr = USB_BASE->EP[ep]; - epr &= ~(USB_EP_STAT_TX | USB_EP_DTOG_RX | USB_EP_DTOG_TX); - epr |= __EP_CTR_NOP; - epr ^= status; - USB_BASE->EP[ep] = epr; -} - -static inline void usb_set_ep_tx_stat(uint8 ep, uint32 status) { - uint32 epr = USB_BASE->EP[ep]; - epr &= ~(USB_EP_STAT_RX | USB_EP_DTOG_RX | USB_EP_DTOG_TX); - epr |= __EP_CTR_NOP; - epr ^= status; - USB_BASE->EP[ep] = epr; -} - -static inline void usb_set_ep_type(uint8 ep, uint32 type) { - uint32 epr = USB_BASE->EP[ep]; - epr &= ~USB_EP_EP_TYPE & __EP_NONTOGGLE; - epr |= type; - USB_BASE->EP[ep] = epr; -} - -static inline void usb_set_ep_kind(uint8 ep, uint32 kind) { - uint32 epr = USB_BASE->EP[ep]; - epr &= ~USB_EP_EP_KIND & __EP_NONTOGGLE; - epr |= kind; - USB_BASE->EP[ep] = epr; -} - -static inline uint32 usb_get_ep_type(uint8 ep) { - uint32 epr = USB_BASE->EP[ep]; - return epr & USB_EP_EP_TYPE; -} - -static inline uint32 usb_get_ep_kind(uint8 ep) { - uint32 epr = USB_BASE->EP[ep]; - return epr & USB_EP_EP_TYPE; -} - - -static inline void usb_clear_status_out(uint8 ep) { - usb_set_ep_kind(ep, 0); -} - -/* - * Packet memory area (PMA) base pointer - */ - -/** - * @brief USB packet memory area (PMA) base pointer. - * - * The USB PMA is SRAM shared between USB and CAN. The USB peripheral - * accesses this memory directly via the packet buffer interface. */ -#define USB_PMA_BASE ((__IO void*)0x40006000) - -/* - * 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 void* usb_pma_ptr(uint32 offset) { - return (void*)(USB_PMA_BASE + 2 * offset); -} - -/* - * BTABLE - */ - -/* (Forward-declared) BTABLE entry. - * - * The BTABLE can be viewed as an array of usb_btable_ent values; - * these vary in structure according to the configuration of the - * endpoint. - */ -union usb_btable_ent; - -/* Bidirectional endpoint BTABLE entry */ -typedef struct usb_btable_bidi { - __IO uint16 addr_tx; const uint16 PAD1; - __IO uint16 count_tx; const uint16 PAD2; - __IO uint16 addr_rx; const uint16 PAD3; - __IO uint16 count_rx; const uint16 PAD4; -} usb_btable_bidi; - -/* Unidirectional receive-only endpoint BTABLE entry */ -typedef struct usb_btable_uni_rx { - __IO uint16 empty1; const uint16 PAD1; - __IO uint16 empty2; const uint16 PAD2; - __IO uint16 addr_rx; const uint16 PAD3; - __IO uint16 count_rx; const uint16 PAD4; -} usb_btable_uni_rx; - -/* Unidirectional transmit-only endpoint BTABLE entry */ -typedef struct usb_btable_uni_tx { - __IO uint16 addr_tx; const uint16 PAD1; - __IO uint16 count_tx; const uint16 PAD2; - __IO uint16 empty1; const uint16 PAD3; - __IO uint16 empty2; const uint16 PAD4; -} usb_btable_uni_tx; - -/* Double-buffered transmission endpoint BTABLE entry */ -typedef struct usb_btable_dbl_tx { - __IO uint16 addr_tx0; const uint16 PAD1; - __IO uint16 count_tx0; const uint16 PAD2; - __IO uint16 addr_tx1; const uint16 PAD3; - __IO uint16 count_tx1; const uint16 PAD4; -} usb_btable_dbl_tx; - -/* Double-buffered reception endpoint BTABLE entry */ -typedef struct usb_btable_dbl_rx { - __IO uint16 addr_rx0; const uint16 PAD1; - __IO uint16 count_rx0; const uint16 PAD2; - __IO uint16 addr_rx1; const uint16 PAD3; - __IO uint16 count_rx1; const uint16 PAD4; -} usb_btable_dbl_rx; - -/* TODO isochronous endpoint entries */ - -/* Definition for above forward-declared BTABLE entry. */ -typedef union usb_btable_ent { - usb_btable_bidi bidi; - usb_btable_uni_rx u_rx; - usb_btable_uni_tx u_tx; - usb_btable_dbl_tx d_tx; - usb_btable_dbl_rx d_rx; -} usb_btable_ent; - -/* - * BTABLE conveniences - */ - -/* TODO (?) Convert usages of the many (and lengthily-named) - * accessors/mutators below to just manipulating usb_btable_entry - * values. */ - -static inline uint32* usb_btable_ptr(uint32 offset) { - return (uint32*)usb_pma_ptr(USB_BASE->BTABLE + offset); -} - -/* TX address */ - -static inline uint32* usb_ep_tx_addr_ptr(uint8 ep) { - return usb_btable_ptr(ep * 8); -} - -static inline uint16 usb_get_ep_tx_addr(uint8 ep) { - return (uint16)*usb_ep_tx_addr_ptr(ep); -} - -static inline void usb_set_ep_tx_addr(uint8 ep, uint16 addr) { - uint32 *tx_addr = usb_ep_tx_addr_ptr(ep); - *tx_addr = addr & ~0x1; -} - -/* RX address */ - -static inline uint32* usb_ep_rx_addr_ptr(uint8 ep) { - return usb_btable_ptr(ep * 8 + 4); -} - -static inline uint16 usb_get_ep_rx_addr(uint8 ep) { - return (uint16)*usb_ep_rx_addr_ptr(ep); -} - -static inline void usb_set_ep_rx_addr(uint8 ep, uint16 addr) { - uint32 *rx_addr = usb_ep_rx_addr_ptr(ep); - *rx_addr = addr & ~0x1; -} - -/* TX count (doesn't cover double-buffered and isochronous in) */ - -static inline uint32* usb_ep_tx_count_ptr(uint8 ep) { - return usb_btable_ptr(ep * 8 + 2); -} - -static inline uint16 usb_get_ep_tx_count(uint8 ep) { - /* FIXME: this is broken somehow; calling it seems to - * confuse/crash the chip. */ - return (uint16)(*usb_ep_tx_count_ptr(ep) & 0x3FF); -} - -static inline void usb_set_ep_tx_count(uint8 ep, uint16 count) { - uint32 *txc = usb_ep_tx_count_ptr(ep); - *txc = count; -} - -/* RX count */ - -static inline uint32* usb_ep_rx_count_ptr(uint8 ep) { - return usb_btable_ptr(ep * 8 + 6); -} - -static inline uint16 usb_get_ep_rx_count(uint8 ep) { - return (uint16)*usb_ep_rx_count_ptr(ep) & 0x3FF; -} - -void usb_set_ep_rx_count(uint8 ep, uint16 count); - -/* double buffer definitions */ -static inline uint32* usb_get_ep_tx_buf0_addr_ptr(uint8 ep) { - return usb_ep_tx_addr_ptr(ep); -} - -static inline uint16 usb_get_ep_tx_buf0_addr(uint8 ep) { - return usb_get_ep_tx_addr(ep); -} - -static inline void usb_set_ep_tx_buf0_addr(uint8 ep, uint16 addr) { - usb_set_ep_tx_addr(ep, addr); -} - -static inline uint32* usb_get_ep_tx_buf1_addr_ptr(uint8 ep) { - return usb_ep_rx_addr_ptr(ep); -} - -static inline uint16 usb_get_ep_tx_buf1_addr(uint8 ep) { - return usb_get_ep_rx_addr(ep); -} - -static inline void usb_set_ep_tx_buf1_addr(uint8 ep, uint16 addr) { - usb_set_ep_rx_addr(ep, addr); -} - -static inline uint32* usb_ep_tx_buf0_count_ptr(uint8 ep) { - return usb_ep_tx_count_ptr(ep); -} - -static inline uint16 usb_get_ep_tx_buf0_count(uint8 ep) { - return usb_get_ep_tx_count(ep); -} - -static inline void usb_set_ep_tx_buf0_count(uint8 ep, uint16 count) { - usb_set_ep_tx_count(ep, count); -} - -static inline uint32* usb_ep_tx_buf1_count_ptr(uint8 ep) { - return usb_ep_rx_count_ptr(ep); -} - -static inline uint16 usb_get_ep_tx_buf1_count(uint8 ep) { - return usb_get_ep_rx_count(ep); -} - -static inline void usb_set_ep_tx_buf1_count(uint8 ep, uint16 count) { - usb_set_ep_rx_count(ep, count); -} -static inline uint32* usb_get_ep_rx_buf0_addr_ptr(uint8 ep) { - return usb_ep_tx_addr_ptr(ep); -} - -static inline uint16 usb_get_ep_rx_buf0_addr(uint8 ep) { - return usb_get_ep_tx_addr(ep); -} - -static inline void usb_set_ep_rx_buf0_addr(uint8 ep, uint16 addr) { - usb_set_ep_tx_addr(ep, addr); -} - -static inline uint32* usb_get_ep_rx_buf1_addr_ptr(uint8 ep) { - return usb_ep_rx_addr_ptr(ep); -} - -static inline uint16 usb_get_ep_rx_buf1_addr(uint8 ep) { - return usb_get_ep_rx_addr(ep); -} - -static inline void usb_set_ep_rx_buf1_addr(uint8 ep, uint16 addr) { - usb_set_ep_rx_addr(ep, addr); -} - -static inline uint32* usb_ep_rx_buf0_count_ptr(uint8 ep) { - return usb_ep_tx_count_ptr(ep); -} - -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); - -static inline uint32* usb_ep_rx_buf1_count_ptr(uint8 ep) { - return usb_ep_rx_count_ptr(ep); -} - -static inline uint16 usb_get_ep_rx_buf1_count(uint8 ep) { - return usb_get_ep_rx_count(ep); -} - -static inline void usb_set_ep_rx_buf1_count(uint8 ep, uint16 count) { - usb_set_ep_rx_count(ep, count); -} - -/* - * Misc. types - */ - -typedef enum usb_ep { - USB_EP0, - USB_EP1, - USB_EP2, - USB_EP3, - USB_EP4, - USB_EP5, - USB_EP6, - USB_EP7, -} usb_ep; - -typedef enum usb_ep_type { - USB_EP_T_CTL = USB_EP_EP_TYPE_CONTROL, - USB_EP_T_BULK = USB_EP_EP_TYPE_BULK, - USB_EP_T_INT = USB_EP_EP_TYPE_INTERRUPT, - USB_EP_T_ISO = USB_EP_EP_TYPE_ISO -} usb_ep_type; - -typedef enum usb_ep_stat { - USB_EP_ST_RX_DIS = USB_EP_STAT_RX_DISABLED, - USB_EP_ST_RX_STL = USB_EP_STAT_RX_STALL, - USB_EP_ST_RX_NAK = USB_EP_STAT_RX_NAK, - USB_EP_ST_RX_VAL = USB_EP_STAT_RX_VALID, - USB_EP_ST_TX_DIS = USB_EP_STAT_TX_DISABLED, - USB_EP_ST_TX_STL = USB_EP_STAT_TX_STALL, - USB_EP_ST_TX_NAK = USB_EP_STAT_TX_NAK, - USB_EP_ST_TX_VAL = USB_EP_STAT_TX_VALID -} usb_ep_stat; - -#endif diff --git a/STM32F3/cores/maple/libmaple/util.c b/STM32F3/cores/maple/libmaple/util.c deleted file mode 100644 index 4c0b2c8..0000000 --- a/STM32F3/cores/maple/libmaple/util.c +++ /dev/null @@ -1,150 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * Copyright (c) 2011, 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file libmaple/util.c - * @brief Utility procedures for debugging - */ - -#include -#include -#include -#include - -/* (Undocumented) hooks used by Wirish to direct our behavior here */ -extern __weak void __lm_error(void); -extern __weak usart_dev* __lm_enable_error_usart(void); - -/* If you define ERROR_LED_PORT and ERROR_LED_PIN, then a failed - * ASSERT() will also throb() an LED connected to that port and pin. - */ -#if defined(ERROR_LED_PORT) && defined(ERROR_LED_PIN) -#define HAVE_ERROR_LED -#endif - -/* (Called from exc.S with global interrupts disabled.) */ -__attribute__((noreturn)) void __error(void) { - if (__lm_error) { - __lm_error(); - } - /* Reenable global interrupts */ - nvic_globalirq_enable(); - throb(); -} - -/* - * Print an error message on a UART upon a failed assertion (if one is - * available), and punt to __error(). - * - * @param file Source file of failed assertion - * @param line Source line of failed assertion - * @param exp String representation of failed assertion - * @sideeffect Turns of all peripheral interrupts except USB. - */ -void _fail(const char* file, int line, const char* exp) { - if (__lm_enable_error_usart) { - /* Initialize the error USART */ - usart_dev *err_usart = __lm_enable_error_usart(); - - /* Print failed assert message */ - usart_putstr(err_usart, "ERROR: FAILED ASSERT("); - usart_putstr(err_usart, exp); - usart_putstr(err_usart, "): "); - usart_putstr(err_usart, file); - usart_putstr(err_usart, ": "); - usart_putudec(err_usart, line); - usart_putc(err_usart, '\n'); - usart_putc(err_usart, '\r'); - } - /* Shutdown and error fade */ - __error(); -} - -/* - * Provide an __assert_func handler to libc so that calls to assert() - * get redirected to _fail. - */ -void __assert_func(const char* file, int line, const char* method, - const char* expression) { - _fail(file, line, expression); -} - -/* - * Provide an abort() implementation that aborts execution and punts - * to __error(). - */ -void abort() { - if (__lm_enable_error_usart) { - /* Initialize the error USART */ - usart_dev *err_usart = __lm_enable_error_usart(); - /* Print abort message. */ - usart_putstr(err_usart, "ERROR: PROGRAM ABORTED VIA abort()\r\n"); - } - - /* Shutdown and error fade */ - __error(); -} - -/* This was public as of v0.0.12, so we've got to keep it public. */ -/** - * @brief Fades the error LED on and off - * @sideeffect Sets output push-pull on ERROR_LED_PIN. - */ -__attribute__((noreturn)) void throb(void) { -#ifdef HAVE_ERROR_LED - int32 slope = 1; - uint32 CC = 0x0000; - uint32 TOP_CNT = 0x0200; - uint32 i = 0; - - gpio_set_mode(ERROR_LED_PORT, ERROR_LED_PIN, GPIO_MODE_OUTPUT); - /* Error fade. */ - while (1) { - if (CC == TOP_CNT) { - slope = -1; - } else if (CC == 0) { - slope = 1; - } - - if (i == TOP_CNT) { - CC += slope; - i = 0; - } - - if (i < CC) { - gpio_write_bit(ERROR_LED_PORT, ERROR_LED_PIN, 1); - } else { - gpio_write_bit(ERROR_LED_PORT, ERROR_LED_PIN, 0); - } - i++; - } -#else - /* No error LED is defined; do nothing. */ - while (1) - ; -#endif -} diff --git a/STM32F3/cores/maple/main.cpp b/STM32F3/cores/maple/main.cpp deleted file mode 100644 index 7305100..0000000 --- a/STM32F3/cores/maple/main.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 LeafLabs LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -extern void setup(void); -extern void loop(void); -extern void init(void); - -// Force init to be called *first*, i.e. before static object allocation. -// Otherwise, statically allocated objects that need libmaple may fail. - __attribute__(( constructor )) void premain() { - init(); -} - -int main(void) { - setup(); - - while (1) { - loop(); - } - return 0; -} diff --git a/STM32F3/cores/maple/wirish/HardwareSPI.cpp b/STM32F3/cores/maple/wirish/HardwareSPI.cpp deleted file mode 100644 index 60d210f..0000000 --- a/STM32F3/cores/maple/wirish/HardwareSPI.cpp +++ /dev/null @@ -1,320 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @author Marti Bolivar - * @brief Wirish SPI implementation. - */ - -#include - -#include -#include -#include - -#include -#include - -#if CYCLES_PER_MICROSECOND != 72 -/* TODO [0.2.0?] something smarter than this */ -#warning "Unexpected clock speed; SPI frequency calculation will be incorrect" -#endif - -struct spi_pins { - uint8 nss; - uint8 sck; - uint8 miso; - uint8 mosi; -}; - -static const spi_pins* dev_to_spi_pins(spi_dev *dev); - -static void enable_device(spi_dev *dev, - bool as_master, - SPIFrequency frequency, - spi_cfg_flag endianness, - spi_mode mode); - -static const spi_pins board_spi_pins[] __FLASH__ = { - {BOARD_SPI1_NSS_PIN, - BOARD_SPI1_SCK_PIN, - BOARD_SPI1_MISO_PIN, - BOARD_SPI1_MOSI_PIN}, - {BOARD_SPI2_NSS_PIN, - BOARD_SPI2_SCK_PIN, - BOARD_SPI2_MISO_PIN, - BOARD_SPI2_MOSI_PIN}, -#if defined(STM32_HIGH_DENSITY) || (STM32_MCU_SERIES == STM32_SERIES_F3) - {BOARD_SPI3_NSS_PIN, - BOARD_SPI3_SCK_PIN, - BOARD_SPI3_MISO_PIN, - BOARD_SPI3_MOSI_PIN}, -#endif -}; - - -/* - * Constructor - */ - -HardwareSPI::HardwareSPI(uint32 spi_num) { - switch (spi_num) { - case 1: - this->spi_d = SPI1; - break; - case 2: - this->spi_d = SPI2; - break; -#if defined(STM32_HIGH_DENSITY) || (STM32_MCU_SERIES == STM32_SERIES_F3) - case 3: - this->spi_d = SPI3; - break; -#endif - default: - ASSERT(0); - } -} - -/* - * Set up/tear down - */ - -void HardwareSPI::begin(SPIFrequency frequency, uint32 bitOrder, uint32 mode) { - if (mode >= 4) { - ASSERT(0); - return; - } - spi_cfg_flag end = bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB; - spi_mode m = (spi_mode)mode; - enable_device(this->spi_d, true, frequency, end, m); -} - -void HardwareSPI::begin(void) { - this->begin(SPI_1_125MHZ, MSBFIRST, 0); -} - -void HardwareSPI::beginSlave(uint32 bitOrder, uint32 mode) { - if (mode >= 4) { - ASSERT(0); - return; - } - spi_cfg_flag end = bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB; - spi_mode m = (spi_mode)mode; - enable_device(this->spi_d, false, (SPIFrequency)0, end, m); -} - -void HardwareSPI::beginSlave(void) { - this->beginSlave(MSBFIRST, 0); -} - -void HardwareSPI::end(void) { - if (!spi_is_enabled(this->spi_d)) { - return; - } - - // Follows RM0008's sequence for disabling a SPI in master/slave - // full duplex mode. - while (spi_is_rx_nonempty(this->spi_d)) { - // FIXME [0.1.0] remove this once you have an interrupt based driver - volatile uint16 rx __attribute__((unused)) = spi_rx_reg(this->spi_d); - } - while (!spi_is_tx_empty(this->spi_d)) - ; - while (spi_is_busy(this->spi_d)) - ; - spi_peripheral_disable(this->spi_d); -} - -/* - * I/O - */ - -uint8 HardwareSPI::read(void) { - uint8 buf[1]; - this->read(buf, 1); - return buf[0]; -} - -void HardwareSPI::read(uint8 *buf, uint32 len) { - uint32 rxed = 0; - while (rxed < len) { - while (!spi_is_rx_nonempty(this->spi_d)) - ; - buf[rxed++] = (uint8)spi_rx_reg(this->spi_d); - } -} - -void HardwareSPI::write(uint8 byte) { - this->write(&byte, 1); -} - -void HardwareSPI::write(const uint8 *data, uint32 length) { - uint32 txed = 0; - while (txed < length) { - txed += spi_tx(this->spi_d, data + txed, length - txed); - } -} - -uint8 HardwareSPI::transfer(uint8 byte) { - this->write(byte); - return this->read(); -} - -/* - * Pin accessors - */ - -uint8 HardwareSPI::misoPin(void) { - return dev_to_spi_pins(this->spi_d)->miso; -} - -uint8 HardwareSPI::mosiPin(void) { - return dev_to_spi_pins(this->spi_d)->mosi; -} - -uint8 HardwareSPI::sckPin(void) { - return dev_to_spi_pins(this->spi_d)->sck; -} - -uint8 HardwareSPI::nssPin(void) { - return dev_to_spi_pins(this->spi_d)->nss; -} - -/* - * Deprecated functions - */ - -uint8 HardwareSPI::send(uint8 data) { - uint8 buf[] = {data}; - return this->send(buf, 1); -} - -uint8 HardwareSPI::send(uint8 *buf, uint32 len) { - uint32 txed = 0; - uint8 ret = 0; - while (txed < len) { - this->write(buf[txed++]); - ret = this->read(); - } - return ret; -} - -uint8 HardwareSPI::recv(void) { - return this->read(); -} - -/* - * Auxiliary functions - */ - -static void configure_gpios(spi_dev *dev, bool as_master); -static spi_baud_rate determine_baud_rate(spi_dev *dev, SPIFrequency freq); - -static const spi_pins* dev_to_spi_pins(spi_dev *dev) { - switch (dev->clk_id) { - case RCC_SPI1: return board_spi_pins; - case RCC_SPI2: return board_spi_pins + 1; -#if defined(STM32_HIGH_DENSITY) || (STM32_MCU_SERIES == STM32_SERIES_F3) - case RCC_SPI3: return board_spi_pins + 2; -#endif - default: return NULL; - } -} - -/* Enables the device in master or slave full duplex mode. If you - * change this code, you must ensure that appropriate changes are made - * to HardwareSPI::end(). */ -static void enable_device(spi_dev *dev, - bool as_master, - SPIFrequency freq, - spi_cfg_flag endianness, - spi_mode mode) { - spi_baud_rate baud = determine_baud_rate(dev, freq); - uint32 cfg_flags = (endianness | SPI_DFF_8_BIT | SPI_SW_SLAVE | - (as_master ? SPI_SOFT_SS : 0)); - - spi_init(dev); - configure_gpios(dev, as_master); - if (as_master) { - spi_master_enable(dev, baud, mode, cfg_flags); - } else { - spi_slave_enable(dev, mode, cfg_flags); - } -} - -static void disable_pwm(const stm32_pin_info *i) { - if (i->timer_device) { - timer_set_mode(i->timer_device, i->timer_channel, TIMER_DISABLED); - } -} - -static void configure_gpios(spi_dev *dev, bool as_master) { - const spi_pins *pins = dev_to_spi_pins(dev); - - if (!pins) { - return; - } - - const stm32_pin_info *nssi = &PIN_MAP[pins->nss]; - const stm32_pin_info *scki = &PIN_MAP[pins->sck]; - const stm32_pin_info *misoi = &PIN_MAP[pins->miso]; - const stm32_pin_info *mosii = &PIN_MAP[pins->mosi]; - - disable_pwm(nssi); - disable_pwm(scki); - disable_pwm(misoi); - disable_pwm(mosii); - - spi_config_gpios(dev, as_master, nssi->gpio_device, nssi->gpio_bit, - scki->gpio_device, scki->gpio_bit, misoi->gpio_bit, - mosii->gpio_bit); -} - -static const spi_baud_rate baud_rates[MAX_SPI_FREQS] __FLASH__ = { - SPI_BAUD_PCLK_DIV_2, - SPI_BAUD_PCLK_DIV_4, - SPI_BAUD_PCLK_DIV_8, - SPI_BAUD_PCLK_DIV_16, - SPI_BAUD_PCLK_DIV_32, - SPI_BAUD_PCLK_DIV_64, - SPI_BAUD_PCLK_DIV_128, - SPI_BAUD_PCLK_DIV_256, -}; - -/* - * Note: This assumes you're on a LeafLabs-style board - * (CYCLES_PER_MICROSECOND == 72, APB2 at 72MHz, APB1 at 36MHz). - */ -static spi_baud_rate determine_baud_rate(spi_dev *dev, SPIFrequency freq) { - if (rcc_dev_clk(dev->clk_id) == RCC_APB2 && freq == SPI_140_625KHZ) { - /* APB2 peripherals are too fast for 140.625 KHz */ - ASSERT(0); - return (spi_baud_rate)~0; - } - return (rcc_dev_clk(dev->clk_id) == RCC_APB2 ? - baud_rates[freq + 1] : - baud_rates[freq]); -} diff --git a/STM32F3/cores/maple/wirish/HardwareSPI.h b/STM32F3/cores/maple/wirish/HardwareSPI.h deleted file mode 100644 index 4b61b58..0000000 --- a/STM32F3/cores/maple/wirish/HardwareSPI.h +++ /dev/null @@ -1,225 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file wirish/include/wirish/HardwareSPI.h - * @brief High-level SPI interface - * - * This is a "bare essentials" polling driver for now. - */ - -/* TODO [0.1.0] Remove deprecated methods. */ - -#include -#include - -#include - -#ifndef _WIRISH_HARDWARESPI_H_ -#define _WIRISH_HARDWARESPI_H_ - -/** - * @brief Defines the possible SPI communication speeds. - */ -typedef enum SPIFrequency { - SPI_18MHZ = 0, /**< 18 MHz */ - SPI_9MHZ = 1, /**< 9 MHz */ - SPI_4_5MHZ = 2, /**< 4.5 MHz */ - SPI_2_25MHZ = 3, /**< 2.25 MHz */ - SPI_1_125MHZ = 4, /**< 1.125 MHz */ - SPI_562_500KHZ = 5, /**< 562.500 KHz */ - SPI_281_250KHZ = 6, /**< 281.250 KHz */ - SPI_140_625KHZ = 7, /**< 140.625 KHz */ -} SPIFrequency; - -#define MAX_SPI_FREQS 8 - -/** - * @brief Wirish SPI interface. - * - * This implementation uses software slave management, so the caller - * is responsible for controlling the slave select line. - */ -class HardwareSPI { -public: - /** - * @param spiPortNumber Number of the SPI port to manage. - */ - HardwareSPI(uint32 spiPortNumber); - - /* - * Set up/tear down - */ - - /** - * @brief Turn on a SPI port and set its GPIO pin modes for use as master. - * - * SPI port is enabled in full duplex mode, with software slave management. - * - * @param frequency Communication frequency - * @param bitOrder Either LSBFIRST (little-endian) or MSBFIRST (big-endian) - * @param mode SPI mode to use, one of SPI_MODE_0, SPI_MODE_1, - * SPI_MODE_2, and SPI_MODE_3. - */ - void begin(SPIFrequency frequency, uint32 bitOrder, uint32 mode); - - /** - * @brief Equivalent to begin(SPI_1_125MHZ, MSBFIRST, 0). - */ - void begin(void); - - /** - * @brief Turn on a SPI port and set its GPIO pin modes for use as a slave. - * - * SPI port is enabled in full duplex mode, with software slave management. - * - * @param bitOrder Either LSBFIRST (little-endian) or MSBFIRST(big-endian) - * @param mode SPI mode to use - */ - void beginSlave(uint32 bitOrder, uint32 mode); - - /** - * @brief Equivalent to beginSlave(MSBFIRST, 0). - */ - void beginSlave(void); - - /** - * @brief Disables the SPI port, but leaves its GPIO pin modes unchanged. - */ - void end(void); - - /* - * I/O - */ - - /** - * @brief Return the next unread byte. - * - * If there is no unread byte waiting, this function will block - * until one is received. - */ - uint8 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 - * 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 multiple bytes. - * @param buffer Bytes to transmit. - * @param length Number of bytes in buffer to transmit. - */ - void write(const uint8 *buffer, uint32 length); - - /** - * @brief Transmit a byte, then return the next unread byte. - * - * This function transmits before receiving. - * - * @param data Byte to transmit. - * @return Next unread byte. - */ - uint8 transfer(uint8 data); - - /* - * Pin accessors - */ - - /** - * @brief Return the number of the MISO (master in, slave out) pin - */ - uint8 misoPin(void); - - /** - * @brief Return the number of the MOSI (master out, slave in) pin - */ - uint8 mosiPin(void); - - /** - * @brief Return the number of the SCK (serial clock) pin - */ - uint8 sckPin(void); - - /** - * @brief Return the number of the NSS (slave select) pin - */ - uint8 nssPin(void); - - /* Escape hatch */ - - /** - * @brief Get a pointer to the underlying libmaple spi_dev for - * this HardwareSPI instance. - */ - spi_dev* c_dev(void) { return this->spi_d; } - - /* -- The following methods are deprecated --------------------------- */ - - /** - * @brief Deprecated. - * - * Use HardwareSPI::transfer() instead. - * - * @see HardwareSPI::transfer() - */ - uint8 send(uint8 data); - - /** - * @brief Deprecated. - * - * Use HardwareSPI::write() in combination with - * HardwareSPI::read() (or HardwareSPI::transfer()) instead. - * - * @see HardwareSPI::write() - * @see HardwareSPI::read() - * @see HardwareSPI::transfer() - */ - uint8 send(uint8 *data, uint32 length); - - /** - * @brief Deprecated. - * - * Use HardwareSPI::read() instead. - * - * @see HardwareSPI::read() - */ - uint8 recv(void); -private: - spi_dev *spi_d; -}; - -#endif diff --git a/STM32F3/cores/maple/wirish/HardwareSerial.cpp b/STM32F3/cores/maple/wirish/HardwareSerial.cpp deleted file mode 100644 index 87f80d1..0000000 --- a/STM32F3/cores/maple/wirish/HardwareSerial.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * Copyright (c) 2011, 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file wirish/HardwareSerial.cpp - * @brief Wirish serial port implementation. - */ - -#include - -#include -#include -#include -#include - -#define DEFINE_HWSERIAL(name, n) \ - HardwareSerial name(USART##n, \ - BOARD_USART##n##_TX_PIN, \ - BOARD_USART##n##_RX_PIN) - -#if BOARD_HAVE_USART1 -DEFINE_HWSERIAL(Serial1, 1); -#endif -#if BOARD_HAVE_USART2 -DEFINE_HWSERIAL(Serial2, 2); -#endif -#if BOARD_HAVE_USART3 -DEFINE_HWSERIAL(Serial3, 3); -#endif -#if BOARD_HAVE_UART4 -DEFINE_HWSERIAL(Serial4, 4); -#endif -#if BOARD_HAVE_UART5 -DEFINE_HWSERIAL(Serial5, 5); -#endif -#if BOARD_HAVE_USART6 -DEFINE_HWSERIAL(Serial6, 6); -#endif - -HardwareSerial::HardwareSerial(usart_dev *usart_device, - uint8 tx_pin, - uint8 rx_pin) { - this->usart_device = usart_device; - this->tx_pin = tx_pin; - this->rx_pin = rx_pin; -} - -/* - * Set up/tear down - */ - -#if STM32_MCU_SERIES == STM32_SERIES_F1 -/* F1 MCUs have no GPIO_AFR[HL], so turn off PWM if there's a conflict - * on this GPIO bit. */ -static void disable_timer_if_necessary(timer_dev *dev, uint8 ch) { - if (dev != NULL) { - timer_set_mode(dev, ch, TIMER_DISABLED); - } -} -#elif (STM32_MCU_SERIES == STM32_SERIES_F2) || \ - (STM32_MCU_SERIES == STM32_SERIES_F3) || \ - (STM32_MCU_SERIES == STM32_SERIES_F4) -#define disable_timer_if_necessary(dev, ch) ((void)0) -#else -#warning "Unsupported STM32 series; timer conflicts are possible" -#endif - -void HardwareSerial::begin(uint32 baud) { - ASSERT(baud <= this->usart_device->max_baud); - - if (baud > this->usart_device->max_baud) { - return; - } - - const stm32_pin_info *txi = &PIN_MAP[this->tx_pin]; - const stm32_pin_info *rxi = &PIN_MAP[this->rx_pin]; - - disable_timer_if_necessary(txi->timer_device, txi->timer_channel); - - usart_config_gpios_async(this->usart_device, - rxi->gpio_device, rxi->gpio_bit, - txi->gpio_device, txi->gpio_bit, - 0); - usart_init(this->usart_device); - usart_set_baud_rate(this->usart_device, USART_USE_PCLK, baud); - usart_enable(this->usart_device); -} - -void HardwareSerial::end(void) { - usart_disable(this->usart_device); -} - -/* - * I/O - */ - -int HardwareSerial::read(void) { - if(usart_data_available(usart_device) > 0) { - return usart_getc(usart_device); - } else { - return -1; - } -} - -uint32 HardwareSerial::available(void) { - return usart_data_available(this->usart_device); -} - -void HardwareSerial::write(unsigned char ch) { - usart_putc(this->usart_device, ch); -} - -void HardwareSerial::flush(void) { - usart_reset_rx(this->usart_device); -} diff --git a/STM32F3/cores/maple/wirish/HardwareSerial.h b/STM32F3/cores/maple/wirish/HardwareSerial.h deleted file mode 100644 index 260a99e..0000000 --- a/STM32F3/cores/maple/wirish/HardwareSerial.h +++ /dev/null @@ -1,102 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * Copyright (c) 2011, 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file wirish/include/wirish/HardwareSerial.h - * @brief Wirish serial port interface. - */ - -#ifndef _WIRISH_HARDWARESERIAL_H_ -#define _WIRISH_HARDWARESERIAL_H_ - -#include - -#include -#include - -/* - * IMPORTANT: - * - * This class documented "by hand" (i.e., not using Doxygen) in the - * leaflabs-docs/ repository. - * - * If you alter the public HardwareSerial interface, you MUST update - * the documentation accordingly. - */ - -struct usart_dev; - -class HardwareSerial : public Print { -public: - HardwareSerial(struct usart_dev *usart_device, - uint8 tx_pin, - uint8 rx_pin); - - /* Set up/tear down */ - void begin(uint32 baud); - void end(void); - - /* I/O */ - uint32 available(void); - int read(void); - void flush(void); - virtual void write(unsigned char); - using Print::write; - - /* Pin accessors */ - int txPin(void) { return this->tx_pin; } - int rxPin(void) { return this->rx_pin; } - - /* Escape hatch into libmaple */ - /* FIXME [0.0.13] documentation */ - struct usart_dev* c_dev(void) { return this->usart_device; } -private: - struct usart_dev *usart_device; - uint8 tx_pin; - uint8 rx_pin; -}; - -#if BOARD_HAVE_USART1 -extern HardwareSerial Serial1; -#endif -#if BOARD_HAVE_USART2 -extern HardwareSerial Serial2; -#endif -#if BOARD_HAVE_USART3 -extern HardwareSerial Serial3; -#endif -#if BOARD_HAVE_UART4 -extern HardwareSerial Serial4; -#endif -#if BOARD_HAVE_UART5 -extern HardwareSerial Serial5; -#endif -#if BOARD_HAVE_USART6 -extern HardwareSerial Serial6; -#endif - -#endif diff --git a/STM32F3/cores/maple/wirish/HardwareTimer.cpp b/STM32F3/cores/maple/wirish/HardwareTimer.cpp deleted file mode 100644 index 4f68ad7..0000000 --- a/STM32F3/cores/maple/wirish/HardwareTimer.cpp +++ /dev/null @@ -1,156 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Bryan Newbold. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -#include - -#include -#include // for noInterrupts(), interrupts() -#include -#include // for CYCLES_PER_MICROSECOND - -// TODO [0.1.0] Remove deprecated pieces - -/* - * Evil hack to infer this->dev from timerNum in the HardwareTimer - * constructor. See: - * - * http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.2 - * http://yosefk.com/c++fqa/function.html#fqa-33.2 - */ - -extern "C" { - static timer_dev **this_devp; - static rcc_clk_id this_id; - static void set_this_dev(timer_dev *dev) { - if (dev->clk_id == this_id) { - *this_devp = dev; - } - } -} - -/* - * HardwareTimer routines - */ - -HardwareTimer::HardwareTimer(uint8 timerNum) { - rcc_clk_id timerID = (rcc_clk_id)(RCC_TIMER1 + (timerNum - 1)); - this->dev = NULL; - noInterrupts(); // Hack to ensure we're the only ones using - // set_this_dev() and friends. TODO: use a lock. - this_id = timerID; - this_devp = &this->dev; - timer_foreach(set_this_dev); - interrupts(); - ASSERT(this->dev != NULL); -} - -void HardwareTimer::pause(void) { - timer_pause(this->dev); -} - -void HardwareTimer::resume(void) { - timer_resume(this->dev); -} - -uint32 HardwareTimer::getPrescaleFactor(void) { - return timer_get_prescaler(this->dev) + 1; -} - -void HardwareTimer::setPrescaleFactor(uint32 factor) { - timer_set_prescaler(this->dev, (uint16)(factor - 1)); -} - -uint16 HardwareTimer::getOverflow() { - return timer_get_reload(this->dev); -} - -void HardwareTimer::setOverflow(uint16 val) { - timer_set_reload(this->dev, val); -} - -uint16 HardwareTimer::getCount(void) { - return timer_get_count(this->dev); -} - -void HardwareTimer::setCount(uint16 val) { - uint16 ovf = this->getOverflow(); - timer_set_count(this->dev, min(val, ovf)); -} - -#define MAX_RELOAD ((1 << 16) - 1) -uint16 HardwareTimer::setPeriod(uint32 microseconds) { - // Not the best way to handle this edge case? - if (!microseconds) { - this->setPrescaleFactor(1); - this->setOverflow(1); - return this->getOverflow(); - } - - uint32 period_cyc = microseconds * CYCLES_PER_MICROSECOND; - uint16 prescaler = (uint16)(period_cyc / MAX_RELOAD + 1); - uint16 overflow = (uint16)((period_cyc + (prescaler / 2)) / prescaler); - this->setPrescaleFactor(prescaler); - this->setOverflow(overflow); - return overflow; -} - -void HardwareTimer::setMode(int channel, timer_mode mode) { - timer_set_mode(this->dev, (uint8)channel, (timer_mode)mode); -} - -uint16 HardwareTimer::getCompare(int channel) { - return timer_get_compare(this->dev, (uint8)channel); -} - -void HardwareTimer::setCompare(int channel, uint16 val) { - uint16 ovf = this->getOverflow(); - timer_set_compare(this->dev, (uint8)channel, min(val, ovf)); -} - -void HardwareTimer::attachInterrupt(int channel, voidFuncPtr handler) { - timer_attach_interrupt(this->dev, (uint8)channel, handler); -} - -void HardwareTimer::detachInterrupt(int channel) { - timer_detach_interrupt(this->dev, (uint8)channel); -} - -void HardwareTimer::refresh(void) { - timer_generate_update(this->dev); -} - -/* -- Deprecated predefined instances -------------------------------------- */ - -HardwareTimer Timer1(1); -HardwareTimer Timer2(2); -HardwareTimer Timer3(3); -HardwareTimer Timer4(4); -#ifdef STM32_HIGH_DENSITY -HardwareTimer Timer5(5); -HardwareTimer Timer6(6); -HardwareTimer Timer7(7); -HardwareTimer Timer8(8); -#endif diff --git a/STM32F3/cores/maple/wirish/HardwareTimer.h b/STM32F3/cores/maple/wirish/HardwareTimer.h deleted file mode 100644 index 22aa010..0000000 --- a/STM32F3/cores/maple/wirish/HardwareTimer.h +++ /dev/null @@ -1,337 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Bryan Newbold. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @brief Wirish timer class. - */ - -#ifndef _WIRISH_HARDWARETIMER_H_ -#define _WIRISH_HARDWARETIMER_H_ - -// TODO [0.1.0] Remove deprecated pieces, pick a better API - -#include - -/** Timer mode. */ -typedef timer_mode TimerMode; - -/** - * @brief Interface to one of the 16-bit timer peripherals. - */ -class HardwareTimer { -private: - timer_dev *dev; - -public: - /** - * @brief Construct a new HardwareTimer instance. - * @param timerNum number of the timer to control. - */ - HardwareTimer(uint8 timerNum); - - /** - * @brief Stop the counter, without affecting its configuration. - * - * @see HardwareTimer::resume() - */ - void pause(void); - - /** - * @brief Resume a paused timer, without affecting its configuration. - * - * The timer will resume counting and firing interrupts as - * appropriate. - * - * Note that there is some function call overhead associated with - * using this method, so using it in concert with - * HardwareTimer::pause() is not a robust way to align multiple - * timers to the same count value. - * - * @see HardwareTimer::pause() - */ - void resume(void); - - /** - * @brief Get the timer's prescale factor. - * @return Timer prescaler, from 1 to 65,536. - * @see HardwareTimer::setPrescaleFactor() - */ - uint32 getPrescaleFactor(); - - /** - * @brief Set the timer's prescale factor. - * - * The new value won't take effect until the next time the counter - * overflows. You can force the counter to reset using - * HardwareTimer::refresh(). - * - * @param factor The new prescale value to set, from 1 to 65,536. - * @see HardwareTimer::refresh() - */ - void setPrescaleFactor(uint32 factor); - - /** - * @brief Get the timer overflow value. - * @see HardwareTimer::setOverflow() - */ - uint16 getOverflow(); - - /** - * @brief Set the timer overflow (or "reload") value. - * - * The new value won't take effect until the next time the counter - * overflows. You can force the counter to reset using - * HardwareTimer::refresh(). - * - * @param val The new overflow value to set - * @see HardwareTimer::refresh() - */ - void setOverflow(uint16 val); - - /** - * @brief Get the current timer count. - * - * @return The timer's current count value - */ - uint16 getCount(void); - - /** - * @brief Set the current timer count. - * - * @param val The new count value to set. If this value exceeds - * the timer's overflow value, it is truncated to the - * overflow value. - */ - void setCount(uint16 val); - - /** - * @brief Set the timer's period in microseconds. - * - * Configures the prescaler and overflow values to generate a timer - * reload with a period as close to the given number of - * microseconds as possible. - * - * @param microseconds The desired period of the timer. This must be - * greater than zero. - * @return The new overflow value. - */ - uint16 setPeriod(uint32 microseconds); - - /** - * @brief Configure a timer channel's mode. - * @param channel Timer channel, from 1 to 4 - * @param mode Mode to set - */ - void setMode(int channel, timer_mode mode); - - /** - * @brief Get the compare value for the given channel. - * @see HardwareTimer::setCompare() - */ - uint16 getCompare(int channel); - - /** - * @brief Set the compare value for the given channel. - * - * @param channel the channel whose compare to set, from 1 to 4. - * @param compare The compare value to set. If greater than this - * timer's overflow value, it will be truncated to - * the overflow value. - * - * @see timer_mode - * @see HardwareTimer::setMode() - * @see HardwareTimer::attachInterrupt() - */ - void setCompare(int channel, uint16 compare); - - /** - * @brief Attach an interrupt handler to the given channel. - * - * This interrupt handler will be called when the timer's counter - * reaches the given channel compare value. - * - * @param channel the channel to attach the ISR to, from 1 to 4. - * @param handler The ISR to attach to the given channel. - * @see voidFuncPtr - */ - void attachInterrupt(int channel, voidFuncPtr handler); - - /** - * @brief Remove the interrupt handler attached to the given - * channel, if any. - * - * The handler will no longer be called by this timer. - * - * @param channel the channel whose interrupt to detach, from 1 to 4. - * @see HardwareTimer::attachInterrupt() - */ - void detachInterrupt(int channel); - - /** - * @brief Reset the counter, and update the prescaler and overflow - * values. - * - * This will reset the counter to 0 in upcounting mode (the - * default). It will also update the timer's prescaler and - * overflow, if you have set them up to be changed using - * HardwareTimer::setPrescaleFactor() or - * HardwareTimer::setOverflow(). - * - * @see HardwareTimer::setPrescaleFactor() - * @see HardwareTimer::setOverflow() - */ - void refresh(void); - - /* Escape hatch */ - - /** - * @brief Get a pointer to the underlying libmaple timer_dev for - * this HardwareTimer instance. - */ - timer_dev* c_dev(void) { return this->dev; } - -/* -- The rest of this file is deprecated. --------------------------------- */ - - /** @brief Deprecated; use setMode(channel, mode) instead. */ - void setChannelMode(int channel, timer_mode mode) { - setMode(channel, mode); - } - - /** @brief Deprecated; use setMode(TIMER_CH1, mode) instead. */ - void setChannel1Mode(timer_mode mode) { setMode(TIMER_CH1, mode); } - - /** @brief Deprecated; use setMode(TIMER_CH2, mode) instead. */ - void setChannel2Mode(timer_mode mode) { setMode(TIMER_CH2, mode); } - - /** @brief Deprecated; use setMode(TIMER_CH3, mode) instead. */ - void setChannel3Mode(timer_mode mode) { setMode(TIMER_CH3, mode); } - - /** @brief Deprecated; use setMode(TIMER_CH4, mode) instead. */ - void setChannel4Mode(timer_mode mode) { setMode(TIMER_CH4, mode); } - - /** @brief Deprecated; use return getCompare(TIMER_CH1) instead. */ - uint16 getCompare1() { return getCompare(TIMER_CH1); } - - /** @brief Deprecated; use return getCompare(TIMER_CH2) instead. */ - uint16 getCompare2() { return getCompare(TIMER_CH2); } - - /** @brief Deprecated; use return getCompare(TIMER_CH3) instead. */ - uint16 getCompare3() { return getCompare(TIMER_CH3); } - - /** @brief Deprecated; use return getCompare(TIMER_CH4) instead. */ - uint16 getCompare4() { return getCompare(TIMER_CH4); } - - /** @brief Deprecated; use setCompare(TIMER_CH1, compare) instead. */ - void setCompare1(uint16 compare) { setCompare(TIMER_CH1, compare); } - - /** @brief Deprecated; use setCompare(TIMER_CH2, compare) instead. */ - void setCompare2(uint16 compare) { setCompare(TIMER_CH2, compare); } - - /** @brief Deprecated; use setCompare(TIMER_CH3, compare) instead. */ - void setCompare3(uint16 compare) { setCompare(TIMER_CH3, compare); } - - /** @brief Deprecated; use setCompare(TIMER_CH4, compare) instead. */ - void setCompare4(uint16 compare) { setCompare(TIMER_CH4, compare); } - - /** @brief Deprecated; use attachInterrupt(TIMER_CH1, handler) instead. */ - void attachCompare1Interrupt(voidFuncPtr handler) { - attachInterrupt(TIMER_CH1, handler); - } - - /** @brief Deprecated; use attachInterrupt(TIMER_CH2, handler) instead. */ - void attachCompare2Interrupt(voidFuncPtr handler) { - attachInterrupt(TIMER_CH2, handler); - } - - /** @brief Deprecated; use attachInterrupt(TIMER_CH3, handler) instead. */ - void attachCompare3Interrupt(voidFuncPtr handler) { - attachInterrupt(TIMER_CH3, handler); - } - - /** @brief Deprecated; use attachInterrupt(TIMER_CH4, handler) instead. */ - void attachCompare4Interrupt(voidFuncPtr handler) { - attachInterrupt(TIMER_CH4, handler); - } - - /** @brief Deprecated; use detachInterrupt(TIMER_CH1) instead. */ - void detachCompare1Interrupt(void) { detachInterrupt(TIMER_CH1); } - - /** @brief Deprecated; use detachInterrupt(TIMER_CH2) instead. */ - void detachCompare2Interrupt(void) { detachInterrupt(TIMER_CH2); } - - /** @brief Deprecated; use detachInterrupt(TIMER_CH3) instead. */ - void detachCompare3Interrupt(void) { detachInterrupt(TIMER_CH3); } - - /** @brief Deprecated; use detachInterrupt(TIMER_CH4) instead. */ - void detachCompare4Interrupt(void) { detachInterrupt(TIMER_CH4); } - - /** @brief Deprecated; use refresh() instead. */ - void generateUpdate(void) { refresh(); } -}; - -/** @brief Deprecated; use TIMER_OUTPUT_COMPARE instead. */ -#define TIMER_OUTPUTCOMPARE TIMER_OUTPUT_COMPARE - -/** - * @brief Deprecated. - * - * Pre-instantiated timer. - */ -extern HardwareTimer Timer1; -/** - * @brief Deprecated. - * - * Pre-instantiated timer. - */ -extern HardwareTimer Timer2; -/** - * @brief Deprecated. - * - * Pre-instantiated timer. - */ -extern HardwareTimer Timer3; -/** - * @brief Deprecated. - * - * Pre-instantiated timer. - */ -extern HardwareTimer Timer4; -#if (STM32_MCU_SERIES == STM32_SERIES_F1) && defined(STM32_HIGH_DENSITY) -/** - * @brief Deprecated. - * - * Pre-instantiated timer. - */ -extern HardwareTimer Timer5; -/** - * @brief Deprecated. - * - * Pre-instantiated timer. - */ -extern HardwareTimer Timer8; -#endif - -#endif diff --git a/STM32F3/cores/maple/wirish/Print.cpp b/STM32F3/cores/maple/wirish/Print.cpp deleted file mode 100644 index 9a8808d..0000000 --- a/STM32F3/cores/maple/wirish/Print.cpp +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Print.cpp - Base class that provides print() and println() - * Copyright (c) 2008 David A. Mellis. All right reserved. - * Copyright (c) 2011 LeafLabs, LLC. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - * Modified 23 November 2006 by David A. Mellis - * Modified 12 April 2011 by Marti Bolivar - */ - -#include - -#include -#include - -#ifndef LLONG_MAX -/* - * Note: - * - * At time of writing (12 April 2011), the limits.h that came with the - * newlib we distributed didn't include LLONG_MAX. Because we're - * staying away from using templates (see /notes/coding_standard.rst, - * "Language Features and Compiler Extensions"), this value was - * copy-pasted from a println() of the value - * - * std::numeric_limits::max(). - */ -#define LLONG_MAX 9223372036854775807LL -#endif - -/* - * Public methods - */ - -void Print::write(const char *str) { - while (*str) { - write(*str++); - } -} - -void Print::write(const void *buffer, uint32 size) { - uint8 *ch = (uint8*)buffer; - while (size--) { - write(*ch++); - } -} - -void Print::print(uint8 b, int base) { - print((uint64)b, base); -} - -void Print::print(char c) { - write(c); -} - -void Print::print(const char str[]) { - write(str); -} - -void Print::print(int n, int base) { - print((long long)n, base); -} - -void Print::print(unsigned int n, int base) { - print((unsigned long long)n, base); -} - -void Print::print(long n, int base) { - print((long long)n, base); -} - -void Print::print(unsigned long n, int base) { - print((unsigned long long)n, base); -} - -void Print::print(long long n, int base) { - if (n < 0) { - print('-'); - n = -n; - } - printNumber(n, base); -} - -void Print::print(unsigned long long n, int base) { - printNumber(n, base); -} - -void Print::print(double n, int digits) { - printFloat(n, digits); -} - -void Print::println(void) { - print('\r'); - print('\n'); -} - -void Print::println(char c) { - print(c); - println(); -} - -void Print::println(const char c[]) { - print(c); - println(); -} - -void Print::println(uint8 b, int base) { - print(b, base); - println(); -} - -void Print::println(int n, int base) { - print(n, base); - println(); -} - -void Print::println(unsigned int n, int base) { - print(n, base); - println(); -} - -void Print::println(long n, int base) { - print((long long)n, base); - println(); -} - -void Print::println(unsigned long n, int base) { - print((unsigned long long)n, base); - println(); -} - -void Print::println(long long n, int base) { - print(n, base); - println(); -} - -void Print::println(unsigned long long n, int base) { - print(n, base); - println(); -} - -void Print::println(double n, int digits) { - print(n, digits); - println(); -} - -/* - * Private methods - */ - -void Print::printNumber(unsigned long long n, uint8 base) { - unsigned char buf[CHAR_BIT * sizeof(long long)]; - unsigned long i = 0; - - if (n == 0) { - print('0'); - return; - } - - while (n > 0) { - buf[i++] = n % base; - n /= base; - } - - for (; i > 0; i--) { - print((char)(buf[i - 1] < 10 ? - '0' + buf[i - 1] : - 'A' + buf[i - 1] - 10)); - } -} - -/* According to snprintf(), - * - * nextafter((double)numeric_limits::max(), 0.0) ~= 9.22337e+18 - * - * This slightly smaller value was picked semi-arbitrarily. */ -#define LARGE_DOUBLE_TRESHOLD (9.1e18) - -/* THIS FUNCTION SHOULDN'T BE USED IF YOU NEED ACCURATE RESULTS. - * - * This implementation is meant to be simple and not occupy too much - * code size. However, printing floating point values accurately is a - * subtle task, best left to a well-tested library function. - * - * See Steele and White 2003 for more details: - * - * http://kurtstephens.com/files/p372-steele.pdf - */ -void Print::printFloat(double number, uint8 digits) { - // Hackish fail-fast behavior for large-magnitude doubles - if (abs(number) >= LARGE_DOUBLE_TRESHOLD) { - if (number < 0.0) { - print('-'); - } - print(""); - return; - } - - // Handle negative numbers - if (number < 0.0) { - print('-'); - number = -number; - } - - // Simplistic rounding strategy so that e.g. print(1.999, 2) - // prints as "2.00" - double rounding = 0.5; - for (uint8 i = 0; i < digits; i++) { - rounding /= 10.0; - } - number += rounding; - - // Extract the integer part of the number and print it - long long int_part = (long long)number; - double remainder = number - int_part; - print(int_part); - - // Print the decimal point, but only if there are digits beyond - if (digits > 0) { - print("."); - } - - // Extract digits from the remainder one at a time - while (digits-- > 0) { - remainder *= 10.0; - int to_print = (int)remainder; - print(to_print); - remainder -= to_print; - } -} diff --git a/STM32F3/cores/maple/wirish/Print.h b/STM32F3/cores/maple/wirish/Print.h deleted file mode 100644 index 52203ea..0000000 --- a/STM32F3/cores/maple/wirish/Print.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Print.h - Base class that provides print() and println() - * Copyright (c) 2008 David A. Mellis. All right reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA. - * - * Modified 12 April 2011 by Marti Bolivar - */ - -#ifndef _WIRISH_PRINT_H_ -#define _WIRISH_PRINT_H_ - -#include - -enum { - BIN = 2, - OCT = 8, - DEC = 10, - HEX = 16 -}; - -class Print { -public: - virtual void write(uint8 ch) = 0; - virtual void write(const char *str); - virtual void write(const void *buf, uint32 len); - void print(char); - void print(const char[]); - void print(uint8, int=DEC); - void print(int, int=DEC); - void print(unsigned int, int=DEC); - void print(long, int=DEC); - void print(unsigned long, int=DEC); - void print(long long, int=DEC); - void print(unsigned long long, int=DEC); - void print(double, int=2); - void println(void); - void println(char); - void println(const char[]); - void println(uint8, int=DEC); - void println(int, int=DEC); - void println(unsigned int, int=DEC); - void println(long, int=DEC); - void println(unsigned long, int=DEC); - void println(long long, int=DEC); - void println(unsigned long long, int=DEC); - void println(double, int=2); -private: - void printNumber(unsigned long long, uint8); - void printFloat(double, uint8); -}; - -#endif diff --git a/STM32F3/cores/maple/wirish/bit_constants.h b/STM32F3/cores/maple/wirish/bit_constants.h deleted file mode 100644 index 4638f76..0000000 --- a/STM32F3/cores/maple/wirish/bit_constants.h +++ /dev/null @@ -1,579 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @brief BIT[n] and binary literal defines, for Arduino - * compatibility. - */ - -#ifndef _WIRISH_BIT_CONSTANTS_H_ -#define _WIRISH_BIT_CONSTANTS_H_ - -#define BIT0 (1 << 0) -#define BIT1 (1 << 1) -#define BIT2 (1 << 2) -#define BIT3 (1 << 3) -#define BIT4 (1 << 4) -#define BIT5 (1 << 5) -#define BIT6 (1 << 6) -#define BIT7 (1 << 7) -#define BIT8 (1 << 8) -#define BIT9 (1 << 9) -#define BIT10 (1 << 10) -#define BIT11 (1 << 11) -#define BIT12 (1 << 12) -#define BIT13 (1 << 13) -#define BIT14 (1 << 14) -#define BIT15 (1 << 15) -#define BIT16 (1 << 16) -#define BIT17 (1 << 17) -#define BIT18 (1 << 18) -#define BIT19 (1 << 19) -#define BIT20 (1 << 20) -#define BIT21 (1 << 21) -#define BIT22 (1 << 22) -#define BIT23 (1 << 23) -#define BIT24 (1 << 24) -#define BIT25 (1 << 25) -#define BIT26 (1 << 26) -#define BIT27 (1 << 27) -#define BIT28 (1 << 28) -#define BIT29 (1 << 29) -#define BIT30 (1 << 30) -#define BIT31 (1 << 31) - -#define B0 0 -#define B00 0 -#define B000 0 -#define B0000 0 -#define B00000 0 -#define B000000 0 -#define B0000000 0 -#define B00000000 0 -#define B1 1 -#define B01 1 -#define B001 1 -#define B0001 1 -#define B00001 1 -#define B000001 1 -#define B0000001 1 -#define B00000001 1 -#define B10 2 -#define B010 2 -#define B0010 2 -#define B00010 2 -#define B000010 2 -#define B0000010 2 -#define B00000010 2 -#define B11 3 -#define B011 3 -#define B0011 3 -#define B00011 3 -#define B000011 3 -#define B0000011 3 -#define B00000011 3 -#define B100 4 -#define B0100 4 -#define B00100 4 -#define B000100 4 -#define B0000100 4 -#define B00000100 4 -#define B101 5 -#define B0101 5 -#define B00101 5 -#define B000101 5 -#define B0000101 5 -#define B00000101 5 -#define B110 6 -#define B0110 6 -#define B00110 6 -#define B000110 6 -#define B0000110 6 -#define B00000110 6 -#define B111 7 -#define B0111 7 -#define B00111 7 -#define B000111 7 -#define B0000111 7 -#define B00000111 7 -#define B1000 8 -#define B01000 8 -#define B001000 8 -#define B0001000 8 -#define B00001000 8 -#define B1001 9 -#define B01001 9 -#define B001001 9 -#define B0001001 9 -#define B00001001 9 -#define B1010 10 -#define B01010 10 -#define B001010 10 -#define B0001010 10 -#define B00001010 10 -#define B1011 11 -#define B01011 11 -#define B001011 11 -#define B0001011 11 -#define B00001011 11 -#define B1100 12 -#define B01100 12 -#define B001100 12 -#define B0001100 12 -#define B00001100 12 -#define B1101 13 -#define B01101 13 -#define B001101 13 -#define B0001101 13 -#define B00001101 13 -#define B1110 14 -#define B01110 14 -#define B001110 14 -#define B0001110 14 -#define B00001110 14 -#define B1111 15 -#define B01111 15 -#define B001111 15 -#define B0001111 15 -#define B00001111 15 -#define B10000 16 -#define B010000 16 -#define B0010000 16 -#define B00010000 16 -#define B10001 17 -#define B010001 17 -#define B0010001 17 -#define B00010001 17 -#define B10010 18 -#define B010010 18 -#define B0010010 18 -#define B00010010 18 -#define B10011 19 -#define B010011 19 -#define B0010011 19 -#define B00010011 19 -#define B10100 20 -#define B010100 20 -#define B0010100 20 -#define B00010100 20 -#define B10101 21 -#define B010101 21 -#define B0010101 21 -#define B00010101 21 -#define B10110 22 -#define B010110 22 -#define B0010110 22 -#define B00010110 22 -#define B10111 23 -#define B010111 23 -#define B0010111 23 -#define B00010111 23 -#define B11000 24 -#define B011000 24 -#define B0011000 24 -#define B00011000 24 -#define B11001 25 -#define B011001 25 -#define B0011001 25 -#define B00011001 25 -#define B11010 26 -#define B011010 26 -#define B0011010 26 -#define B00011010 26 -#define B11011 27 -#define B011011 27 -#define B0011011 27 -#define B00011011 27 -#define B11100 28 -#define B011100 28 -#define B0011100 28 -#define B00011100 28 -#define B11101 29 -#define B011101 29 -#define B0011101 29 -#define B00011101 29 -#define B11110 30 -#define B011110 30 -#define B0011110 30 -#define B00011110 30 -#define B11111 31 -#define B011111 31 -#define B0011111 31 -#define B00011111 31 -#define B100000 32 -#define B0100000 32 -#define B00100000 32 -#define B100001 33 -#define B0100001 33 -#define B00100001 33 -#define B100010 34 -#define B0100010 34 -#define B00100010 34 -#define B100011 35 -#define B0100011 35 -#define B00100011 35 -#define B100100 36 -#define B0100100 36 -#define B00100100 36 -#define B100101 37 -#define B0100101 37 -#define B00100101 37 -#define B100110 38 -#define B0100110 38 -#define B00100110 38 -#define B100111 39 -#define B0100111 39 -#define B00100111 39 -#define B101000 40 -#define B0101000 40 -#define B00101000 40 -#define B101001 41 -#define B0101001 41 -#define B00101001 41 -#define B101010 42 -#define B0101010 42 -#define B00101010 42 -#define B101011 43 -#define B0101011 43 -#define B00101011 43 -#define B101100 44 -#define B0101100 44 -#define B00101100 44 -#define B101101 45 -#define B0101101 45 -#define B00101101 45 -#define B101110 46 -#define B0101110 46 -#define B00101110 46 -#define B101111 47 -#define B0101111 47 -#define B00101111 47 -#define B110000 48 -#define B0110000 48 -#define B00110000 48 -#define B110001 49 -#define B0110001 49 -#define B00110001 49 -#define B110010 50 -#define B0110010 50 -#define B00110010 50 -#define B110011 51 -#define B0110011 51 -#define B00110011 51 -#define B110100 52 -#define B0110100 52 -#define B00110100 52 -#define B110101 53 -#define B0110101 53 -#define B00110101 53 -#define B110110 54 -#define B0110110 54 -#define B00110110 54 -#define B110111 55 -#define B0110111 55 -#define B00110111 55 -#define B111000 56 -#define B0111000 56 -#define B00111000 56 -#define B111001 57 -#define B0111001 57 -#define B00111001 57 -#define B111010 58 -#define B0111010 58 -#define B00111010 58 -#define B111011 59 -#define B0111011 59 -#define B00111011 59 -#define B111100 60 -#define B0111100 60 -#define B00111100 60 -#define B111101 61 -#define B0111101 61 -#define B00111101 61 -#define B111110 62 -#define B0111110 62 -#define B00111110 62 -#define B111111 63 -#define B0111111 63 -#define B00111111 63 -#define B1000000 64 -#define B01000000 64 -#define B1000001 65 -#define B01000001 65 -#define B1000010 66 -#define B01000010 66 -#define B1000011 67 -#define B01000011 67 -#define B1000100 68 -#define B01000100 68 -#define B1000101 69 -#define B01000101 69 -#define B1000110 70 -#define B01000110 70 -#define B1000111 71 -#define B01000111 71 -#define B1001000 72 -#define B01001000 72 -#define B1001001 73 -#define B01001001 73 -#define B1001010 74 -#define B01001010 74 -#define B1001011 75 -#define B01001011 75 -#define B1001100 76 -#define B01001100 76 -#define B1001101 77 -#define B01001101 77 -#define B1001110 78 -#define B01001110 78 -#define B1001111 79 -#define B01001111 79 -#define B1010000 80 -#define B01010000 80 -#define B1010001 81 -#define B01010001 81 -#define B1010010 82 -#define B01010010 82 -#define B1010011 83 -#define B01010011 83 -#define B1010100 84 -#define B01010100 84 -#define B1010101 85 -#define B01010101 85 -#define B1010110 86 -#define B01010110 86 -#define B1010111 87 -#define B01010111 87 -#define B1011000 88 -#define B01011000 88 -#define B1011001 89 -#define B01011001 89 -#define B1011010 90 -#define B01011010 90 -#define B1011011 91 -#define B01011011 91 -#define B1011100 92 -#define B01011100 92 -#define B1011101 93 -#define B01011101 93 -#define B1011110 94 -#define B01011110 94 -#define B1011111 95 -#define B01011111 95 -#define B1100000 96 -#define B01100000 96 -#define B1100001 97 -#define B01100001 97 -#define B1100010 98 -#define B01100010 98 -#define B1100011 99 -#define B01100011 99 -#define B1100100 100 -#define B01100100 100 -#define B1100101 101 -#define B01100101 101 -#define B1100110 102 -#define B01100110 102 -#define B1100111 103 -#define B01100111 103 -#define B1101000 104 -#define B01101000 104 -#define B1101001 105 -#define B01101001 105 -#define B1101010 106 -#define B01101010 106 -#define B1101011 107 -#define B01101011 107 -#define B1101100 108 -#define B01101100 108 -#define B1101101 109 -#define B01101101 109 -#define B1101110 110 -#define B01101110 110 -#define B1101111 111 -#define B01101111 111 -#define B1110000 112 -#define B01110000 112 -#define B1110001 113 -#define B01110001 113 -#define B1110010 114 -#define B01110010 114 -#define B1110011 115 -#define B01110011 115 -#define B1110100 116 -#define B01110100 116 -#define B1110101 117 -#define B01110101 117 -#define B1110110 118 -#define B01110110 118 -#define B1110111 119 -#define B01110111 119 -#define B1111000 120 -#define B01111000 120 -#define B1111001 121 -#define B01111001 121 -#define B1111010 122 -#define B01111010 122 -#define B1111011 123 -#define B01111011 123 -#define B1111100 124 -#define B01111100 124 -#define B1111101 125 -#define B01111101 125 -#define B1111110 126 -#define B01111110 126 -#define B1111111 127 -#define B01111111 127 -#define B10000000 128 -#define B10000001 129 -#define B10000010 130 -#define B10000011 131 -#define B10000100 132 -#define B10000101 133 -#define B10000110 134 -#define B10000111 135 -#define B10001000 136 -#define B10001001 137 -#define B10001010 138 -#define B10001011 139 -#define B10001100 140 -#define B10001101 141 -#define B10001110 142 -#define B10001111 143 -#define B10010000 144 -#define B10010001 145 -#define B10010010 146 -#define B10010011 147 -#define B10010100 148 -#define B10010101 149 -#define B10010110 150 -#define B10010111 151 -#define B10011000 152 -#define B10011001 153 -#define B10011010 154 -#define B10011011 155 -#define B10011100 156 -#define B10011101 157 -#define B10011110 158 -#define B10011111 159 -#define B10100000 160 -#define B10100001 161 -#define B10100010 162 -#define B10100011 163 -#define B10100100 164 -#define B10100101 165 -#define B10100110 166 -#define B10100111 167 -#define B10101000 168 -#define B10101001 169 -#define B10101010 170 -#define B10101011 171 -#define B10101100 172 -#define B10101101 173 -#define B10101110 174 -#define B10101111 175 -#define B10110000 176 -#define B10110001 177 -#define B10110010 178 -#define B10110011 179 -#define B10110100 180 -#define B10110101 181 -#define B10110110 182 -#define B10110111 183 -#define B10111000 184 -#define B10111001 185 -#define B10111010 186 -#define B10111011 187 -#define B10111100 188 -#define B10111101 189 -#define B10111110 190 -#define B10111111 191 -#define B11000000 192 -#define B11000001 193 -#define B11000010 194 -#define B11000011 195 -#define B11000100 196 -#define B11000101 197 -#define B11000110 198 -#define B11000111 199 -#define B11001000 200 -#define B11001001 201 -#define B11001010 202 -#define B11001011 203 -#define B11001100 204 -#define B11001101 205 -#define B11001110 206 -#define B11001111 207 -#define B11010000 208 -#define B11010001 209 -#define B11010010 210 -#define B11010011 211 -#define B11010100 212 -#define B11010101 213 -#define B11010110 214 -#define B11010111 215 -#define B11011000 216 -#define B11011001 217 -#define B11011010 218 -#define B11011011 219 -#define B11011100 220 -#define B11011101 221 -#define B11011110 222 -#define B11011111 223 -#define B11100000 224 -#define B11100001 225 -#define B11100010 226 -#define B11100011 227 -#define B11100100 228 -#define B11100101 229 -#define B11100110 230 -#define B11100111 231 -#define B11101000 232 -#define B11101001 233 -#define B11101010 234 -#define B11101011 235 -#define B11101100 236 -#define B11101101 237 -#define B11101110 238 -#define B11101111 239 -#define B11110000 240 -#define B11110001 241 -#define B11110010 242 -#define B11110011 243 -#define B11110100 244 -#define B11110101 245 -#define B11110110 246 -#define B11110111 247 -#define B11111000 248 -#define B11111001 249 -#define B11111010 250 -#define B11111011 251 -#define B11111100 252 -#define B11111101 253 -#define B11111110 254 -#define B11111111 255 - -#endif /* _BIT_CONSTANTS_H_ */ diff --git a/STM32F3/cores/maple/wirish/bits.h b/STM32F3/cores/maple/wirish/bits.h deleted file mode 100644 index 0a63c58..0000000 --- a/STM32F3/cores/maple/wirish/bits.h +++ /dev/null @@ -1,35 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/* Note: Use of this header file is deprecated. Use bit_constants.h - instead. */ - -#ifndef _WIRISH_BITS_H_ -#define _WIRISH_BITS_H_ - -#include - -#endif diff --git a/STM32F3/cores/maple/wirish/boards.cpp b/STM32F3/cores/maple/wirish/boards.cpp deleted file mode 100644 index a693fa6..0000000 --- a/STM32F3/cores/maple/wirish/boards.cpp +++ /dev/null @@ -1,215 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * Copyright (c) 2011, 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file wirish/boards.cpp - * @brief init() and board routines. - * - * This file is mostly interesting for the init() function, which - * configures Flash, the core clocks, and a variety of other available - * peripherals on the board so the rest of Wirish doesn't have to turn - * things on before using them. - * - * Prior to returning, init() calls boardInit(), which allows boards - * to perform any initialization they need to. This file includes a - * weak no-op definition of boardInit(), so boards that don't need any - * special initialization don't have to define their own. - * - * How init() works is chip-specific. See the boards_setup.cpp files - * under e.g. wirish/stm32f1/, wirish/stmf32f2 for the details, but be - * advised: their contents are unstable, and can/will change without - * notice. - */ - -#include -#include -#include -#include -#include -#include "boards_private.h" - -static void setup_flash(void); -static void setup_clocks(void); -static void setup_nvic(void); -static void setup_adcs(void); -static void setup_timers(void); - -/* - * Exported functions - */ - -void init(void) { - setup_flash(); - setup_clocks(); - setup_nvic(); - systick_init(SYSTICK_RELOAD_VAL); - wirish::priv::board_setup_gpio(); - setup_adcs(); - setup_timers(); - wirish::priv::board_setup_usb(); - wirish::priv::series_init(); - boardInit(); -} - -/* Provide a default no-op boardInit(). */ -__weak void boardInit(void) { -} - -/* You could farm this out to the files in boards/ if e.g. it takes - * too long to test on boards with lots of pins. */ -bool boardUsesPin(uint8 pin) { - for (int i = 0; i < BOARD_NR_USED_PINS; i++) { - if (pin == boardUsedPins[i]) { - return true; - } - } - return false; -} - -/* - * Auxiliary routines - */ - -static void setup_flash(void) { - // Turn on as many Flash "go faster" features as - // possible. flash_enable_features() just ignores any flags it - // can't support. - flash_enable_features(FLASH_PREFETCH | FLASH_ICACHE | FLASH_DCACHE); - // Configure the wait states, assuming we're operating at "close - // enough" to 3.3V. - flash_set_latency(FLASH_SAFE_WAIT_STATES); -} - -static void setup_clocks(void) { - // Turn on HSI. We'll switch to and run off of this while we're - // setting up the main PLL. - rcc_turn_on_clk(RCC_CLK_HSI); - - // Turn off and reset the clock subsystems we'll be using, as well - // as the clock security subsystem (CSS). Note that resetting CFGR - // to its default value of 0 implies a switch to HSI for SYSCLK. - RCC_BASE->CFGR = 0x00000000; - rcc_disable_css(); - rcc_turn_off_clk(RCC_CLK_PLL); - rcc_turn_off_clk(RCC_CLK_HSE); - wirish::priv::board_reset_pll(); - // Clear clock readiness interrupt flags and turn off clock - // readiness interrupts. - RCC_BASE->CIR = 0x00000000; - - // Enable HSE, and wait until it's ready. - rcc_turn_on_clk(RCC_CLK_HSE); - while (!rcc_is_clk_ready(RCC_CLK_HSE)) - ; - - // Configure AHBx, APBx, etc. prescalers and the main PLL. - wirish::priv::board_setup_clock_prescalers(); - rcc_configure_pll(&wirish::priv::w_board_pll_cfg); - - // Enable the PLL, and wait until it's ready. - rcc_turn_on_clk(RCC_CLK_PLL); - while(!rcc_is_clk_ready(RCC_CLK_PLL)) - ; - - // Finally, switch to the now-ready PLL as the main clock source. - rcc_switch_sysclk(RCC_CLKSRC_PLL); -} - -/* - * These addresses are where usercode starts when a bootloader is - * present. If no bootloader is present, the user NVIC usually starts - * at the Flash base address, 0x08000000. - */ -#define USER_ADDR_ROM 0x08005000 -#define USER_ADDR_RAM 0x20000C00 -extern char __text_start__; - -static void setup_nvic(void) { -#ifdef VECT_TAB_FLASH - nvic_init(USER_ADDR_ROM, 0); -#elif defined VECT_TAB_RAM - nvic_init(USER_ADDR_RAM, 0); -#elif defined VECT_TAB_BASE - nvic_init((uint32)0x08000000, 0); -#elif defined VECT_TAB_ADDR - // A numerically supplied value - nvic_init((uint32)VECT_TAB_ADDR, 0); -#else - // Use the __text_start__ value from the linker script; this - // should be the start of the vector table. - nvic_init((uint32)&__text_start__, 0); -#endif -} - -static void adc_default_config(const adc_dev *dev) { - adc_enable_single_swstart(dev); - adc_set_sample_rate(dev, wirish::priv::w_adc_smp); -} - -static void setup_adcs(void) { - adc_set_prescaler(wirish::priv::w_adc_pre); - adc_foreach(adc_default_config); -} - -static void timer_default_config(timer_dev *dev) { - timer_adv_reg_map *regs = (dev->regs).adv; - const uint16 full_overflow = 0xFFFF; - const uint16 half_duty = 0x8FFF; - - timer_init(dev); - timer_pause(dev); - - regs->CR1 = TIMER_CR1_ARPE; - regs->PSC = 1; - regs->SR = 0; - regs->DIER = 0; - regs->EGR = TIMER_EGR_UG; - switch (dev->type) { - case TIMER_ADVANCED: - regs->BDTR = TIMER_BDTR_MOE | TIMER_BDTR_LOCK_OFF; - // fall-through - case TIMER_GENERAL: - timer_set_reload(dev, full_overflow); - for (uint8 channel = 1; channel <= 4; channel++) { - if (timer_has_cc_channel(dev, channel)) { - timer_set_compare(dev, channel, half_duty); - timer_oc_set_mode(dev, channel, TIMER_OC_MODE_PWM_1, - TIMER_OC_PE); - } - } - // fall-through - case TIMER_BASIC: - break; - } - - timer_generate_update(dev); - timer_resume(dev); -} - -static void setup_timers(void) { - timer_foreach(timer_default_config); -} diff --git a/STM32F3/cores/maple/wirish/boards.h b/STM32F3/cores/maple/wirish/boards.h deleted file mode 100644 index 6676a02..0000000 --- a/STM32F3/cores/maple/wirish/boards.h +++ /dev/null @@ -1,173 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Bryan Newbold. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file wirish/include/wirish/boards.h - * @author Bryan Newbold , - * Marti Bolivar - * @brief init() and board-specific pin information. - */ - -#ifndef _WIRISH_BOARDS_H_ -#define _WIRISH_BOARDS_H_ - -#include -#include -#include - -/* Set of all possible pin names; not all boards have all these (note - * that we use the Dx convention since all of the Maple's pins are - * "digital" pins (e.g. can be used with digitalRead() and - * digitalWrite()), but not all of them are connected to ADCs. */ -enum { - D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15, D16, - D17, D18, D19, D20, D21, D22, D23, D24, D25, D26, D27, D28, D29, D30, D31, - D32, D33, D34, D35, D36, D37, D38, D39, D40, D41, D42, D43, D44, D45, D46, - D47, D48, D49, D50, D51, D52, D53, D54, D55, D56, D57, D58, D59, D60, D61, - D62, D63, D64, D65, D66, D67, D68, D69, D70, D71, D72, D73, D74, D75, D76, - D77, D78, D79, D80, D81, D82, D83, D84, D85, D86, D87, D88, D89, D90, D91, - D92, D93, D94, D95, D96, D97, D98, D99, D100, D101, D102, D103, D104, D105, - D106, D107, D108, D109, D110, D111, }; - -/** - * @brief Maps each Maple pin to a corresponding stm32_pin_info. - * @see stm32_pin_info - */ -extern const stm32_pin_info PIN_MAP[]; - -/** - * @brief Pins capable of PWM output. - * - * Its length is BOARD_NR_PWM_PINS. - */ -extern const uint8 boardPWMPins[]; - -/** - * @brief Array of pins capable of analog input. - * - * Its length is BOARD_NR_ADC_PINS. - */ -extern const uint8 boardADCPins[]; - -/** - * @brief Pins which are connected to external hardware. - * - * For example, on Maple boards, it always at least includes - * BOARD_LED_PIN. Its length is BOARD_NR_USED_PINS. - */ -extern const uint8 boardUsedPins[]; - -/** - * @brief Generic board initialization function. - * - * This function is called before main(). It ensures that the clocks - * and peripherals are configured properly for use with wirish, then - * calls boardInit(). - * - * @see boardInit() - */ -void init(void); - -/** - * @brief Board-specific initialization function. - * - * This function is called from init() after all generic board - * initialization has been performed. Each board is required to - * define its own. - * - * @see init() - */ -extern void boardInit(void); - -/** - * @brief Test if a pin is used for a special purpose on your board. - * @param pin Pin to test - * @return true if the given pin is in boardUsedPins, and false otherwise. - * @see boardUsedPins - */ -bool boardUsesPin(uint8 pin); - -/* - * Derived and default board definitions - */ - -#define CLOCK_SPEED_MHZ CYCLES_PER_MICROSECOND -#define CLOCK_SPEED_HZ (CLOCK_SPEED_MHZ * 1000000UL) - -#ifndef SYSTICK_RELOAD_VAL -#define SYSTICK_RELOAD_VAL (1000 * CYCLES_PER_MICROSECOND - 1) -#endif - -#ifndef BOARD_BUTTON_PRESSED_LEVEL -#define BOARD_BUTTON_PRESSED_LEVEL HIGH -#endif - -/** - * @brief Does the board break out a USART/UART's RX and TX pins? - * - * BOARD_HAVE_USART(n) is nonzero iff USARTn is available (n must be - * an integer literal, 1 through 6). Also see BOARD_HAVE_USART1, ..., - * BOARD_HAVE_UART4 (sic), etc. - */ -#define BOARD_HAVE_USART(n) (defined(BOARD_USART##n##_TX_PIN) && \ - defined(BOARD_USART##n##_RX_PIN)) -/** Feature test: nonzero iff the board has USART1. */ -#define BOARD_HAVE_USART1 BOARD_HAVE_USART(1) -/** Feature test: nonzero iff the board has USART2, 0 otherwise. */ -#define BOARD_HAVE_USART2 BOARD_HAVE_USART(2) -/** Feature test: nonzero iff the board has USART3, 0 otherwise. */ -#define BOARD_HAVE_USART3 BOARD_HAVE_USART(3) -/** Feature test: nonzero iff the board has UART4, 0 otherwise. */ -#define BOARD_HAVE_UART4 BOARD_HAVE_USART(4) -/** Feature test: nonzero iff the board has UART5, 0 otherwise. */ -#define BOARD_HAVE_UART5 BOARD_HAVE_USART(5) -/** Feature test: nonzero iff the board has USART6, 0 otherwise. */ -#define BOARD_HAVE_USART6 BOARD_HAVE_USART(6) - -/** - * @brief Does the board break out a SPI peripheral's pins? - * - * BOARD_HAVE_SPI(n) is nonzero iff SPIn is available (n must be an - * integer literal: 1, 2, or 3). Also see BOARD_HAVE_SPI1, - * BOARD_HAVE_SPI2, BOARD_HAVE_SPI3. */ -#define BOARD_HAVE_SPI(n) (defined(BOARD_SPI##n##_NSS_PIN) && \ - defined(BOARD_SPI##n##_SCK_PIN) && \ - defined(BOARD_SPI##n##_MISO_PIN) && \ - defined(BOARD_SPI##n##_MOSI_PIN)) -/** Feature test: nonzero iff the board has SPI1. */ -#define BOARD_HAVE_SPI1 BOARD_HAVE_SPI(1) -/** Feature test: nonzero iff the board has SPI2. */ -#define BOARD_HAVE_SPI2 BOARD_HAVE_SPI(2) -/** Feature test: nonzero iff the board has SPI3. */ -#define BOARD_HAVE_SPI3 BOARD_HAVE_SPI(3) - -/** - * @brief Feature test: nonzero iff the board has SerialUSB. - */ -#define BOARD_HAVE_SERIALUSB (defined(BOARD_USB_DISC_DEV) && \ - defined(BOARD_USB_DISC_BIT)) - -#endif diff --git a/STM32F3/cores/maple/wirish/boards_private.h b/STM32F3/cores/maple/wirish/boards_private.h deleted file mode 100644 index 49867ca..0000000 --- a/STM32F3/cores/maple/wirish/boards_private.h +++ /dev/null @@ -1,71 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file wirish/boards_private.h - * @author Marti Bolivar - * @brief Private board support header. - * - * This file declares chip-specific variables and functions which - * determine how init() behaves. It is not part of the public Wirish - * API, and can change without notice. - */ - -#ifndef _WIRISH_BOARDS_PRIVATE_H_ -#define _WIRISH_BOARDS_PRIVATE_H_ - -#include -#include - -/* Makes the PIN_MAP rows more human-readable. */ -#define PMAP_ROW(gpio_dev, gpio_bit, timer_dev, timer_ch, adc_dev, adc_ch) \ - { gpio_dev, timer_dev, adc_dev, gpio_bit, timer_ch, adc_ch } - -namespace wirish { - namespace priv { - - /* - * Chip-specific initialization data - */ - - extern rcc_pll_cfg w_board_pll_cfg; - extern adc_prescaler w_adc_pre; - extern adc_smp_rate w_adc_smp; - - /* - * Chip-specific initialization routines and helper functions. - */ - - void board_reset_pll(void); - void board_setup_clock_prescalers(void); - void board_setup_gpio(void); - void board_setup_usb(void); - void series_init(void); - - } -} - -#endif diff --git a/STM32F3/cores/maple/wirish/cxxabi-compat.cpp b/STM32F3/cores/maple/wirish/cxxabi-compat.cpp deleted file mode 100644 index 516b112..0000000 --- a/STM32F3/cores/maple/wirish/cxxabi-compat.cpp +++ /dev/null @@ -1,6 +0,0 @@ -/* We compile with nodefaultlibs, so we need to provide an error - * handler for an empty pure virtual function */ -extern "C" void __cxa_pure_virtual(void) { - while(1) - ; -} diff --git a/STM32F3/cores/maple/wirish/ext_interrupts.cpp b/STM32F3/cores/maple/wirish/ext_interrupts.cpp deleted file mode 100644 index 1195ea9..0000000 --- a/STM32F3/cores/maple/wirish/ext_interrupts.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * Copyright (c) 2011, 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file wirish/ext_interrupts.cpp - * @brief Wiring-like interface for external interrupts - */ - -#include - -#include -#include - -#include - -static inline exti_trigger_mode exti_out_mode(ExtIntTriggerMode mode); - -void attachInterrupt(uint8 pin, voidFuncPtr handler, ExtIntTriggerMode mode) { - if (pin >= BOARD_NR_GPIO_PINS || !handler) { - return; - } - - exti_trigger_mode outMode = exti_out_mode(mode); - - exti_attach_interrupt((exti_num)(PIN_MAP[pin].gpio_bit), - gpio_exti_port(PIN_MAP[pin].gpio_device), - handler, - outMode); -} - -void attachInterrupt(uint8 pin, voidArgumentFuncPtr handler, void *arg, - ExtIntTriggerMode mode) { - if (pin >= BOARD_NR_GPIO_PINS || !handler) { - return; - } - - exti_trigger_mode outMode = exti_out_mode(mode); - - exti_attach_callback((exti_num)(PIN_MAP[pin].gpio_bit), - gpio_exti_port(PIN_MAP[pin].gpio_device), - handler, - arg, - outMode); -} - -void detachInterrupt(uint8 pin) { - if (pin >= BOARD_NR_GPIO_PINS) { - return; - } - - exti_detach_interrupt((exti_num)(PIN_MAP[pin].gpio_bit)); -} - -static inline exti_trigger_mode exti_out_mode(ExtIntTriggerMode mode) { - switch (mode) { - case RISING: - return EXTI_RISING; - case FALLING: - return EXTI_FALLING; - case CHANGE: - return EXTI_RISING_FALLING; - } - // Can't happen - ASSERT(0); - return (exti_trigger_mode)0; -} diff --git a/STM32F3/cores/maple/wirish/ext_interrupts.h b/STM32F3/cores/maple/wirish/ext_interrupts.h deleted file mode 100644 index ce1ca03..0000000 --- a/STM32F3/cores/maple/wirish/ext_interrupts.h +++ /dev/null @@ -1,128 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file wirish/include/wirish/ext_interrupts.h - * @brief Wiring-like external interrupt prototypes and types. - */ - -#ifndef _WIRISH_EXT_INTERRUPTS_H_ -#define _WIRISH_EXT_INTERRUPTS_H_ - -#include -#include - -/** - * The kind of transition on an external pin which should trigger an - * interrupt. - */ -typedef enum ExtIntTriggerMode { - RISING, /**< To trigger an interrupt when the pin transitions LOW - to HIGH */ - FALLING, /**< To trigger an interrupt when the pin transitions - HIGH to LOW */ - CHANGE /**< To trigger an interrupt when the pin transitions from - LOW to HIGH or HIGH to LOW (i.e., when the pin - changes). */ -} ExtIntTriggerMode; - -/** - * @brief Registers an interrupt handler on a pin. - * - * The interrupt will be triggered on a given transition on the pin, - * as specified by the mode parameter. The handler runs in interrupt - * context. The new handler will replace whatever handler is - * currently registered for the pin, if any. - * - * @param pin Pin number - * @param handler Function to run upon external interrupt trigger. - * The handler should take no arguments, and have void - * return type. - * @param mode Type of transition to trigger on, e.g. falling, rising, etc. - * - * @sideeffect Registers a handler - * @see detachInterrupt() - */ -void attachInterrupt(uint8 pin, voidFuncPtr handler, ExtIntTriggerMode mode); - -/** - * @brief Registers an interrupt handler on a pin. - * - * The interrupt will be triggered on a given transition on the pin, - * as specified by the mode parameter. The handler runs in interrupt - * context. The new handler will replace whatever handler is - * currently registered for the pin, if any. - * - * @param pin Pin number - * @param handler Static class member function to run upon external interrupt - * trigger. The handler should take 1 argument and return void - * @param arg Argument that the handler will be passed when it's called. One - * use of this is to pass the specific instance of the class that - * will handle the interrupt. - * @param mode Type of transition to trigger on, e.g. falling, rising, etc. - * - * @sideeffect Registers a handler - * @see detachInterrupt() - */ -void attachInterrupt(uint8 pin, voidArgumentFuncPtr handler, void *arg, - ExtIntTriggerMode mode); - -/** - * @brief Disable any registered external interrupt. - * @param pin Maple pin number - * @sideeffect unregisters external interrupt handler - * @see attachInterrupt() - */ -void detachInterrupt(uint8 pin); - -/** - * Re-enable interrupts. - * - * Call this after noInterrupts() to re-enable interrupt handling, - * after you have finished with a timing-critical section of code. - * - * @see noInterrupts() - */ -static __always_inline void interrupts() { - nvic_globalirq_enable(); -} - -/** - * Disable interrupts. - * - * After calling this function, all user-programmable interrupts will - * be disabled. You can call this function before a timing-critical - * section of code, then call interrupts() to re-enable interrupt - * handling. - * - * @see interrupts() - */ -static __always_inline void noInterrupts() { - nvic_globalirq_disable(); -} - -#endif - diff --git a/STM32F3/cores/maple/wirish/io.h b/STM32F3/cores/maple/wirish/io.h deleted file mode 100644 index 08bbc06..0000000 --- a/STM32F3/cores/maple/wirish/io.h +++ /dev/null @@ -1,222 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file wirish/include/wirish/io.h - * @brief Wiring-style pin I/O interface. - */ - -#ifndef _WIRISH_IO_H_ -#define _WIRISH_IO_H_ - -#include -#include - -/** - * Specifies a GPIO pin behavior. - * @see pinMode() - */ -typedef enum WiringPinMode { - OUTPUT, /**< Basic digital output: when the pin is HIGH, the - voltage is held at +3.3v (Vcc) and when it is LOW, it - is pulled down to ground. */ - - OUTPUT_OPEN_DRAIN, /**< In open drain mode, the pin indicates - "low" by accepting current flow to ground - and "high" by providing increased - impedance. An example use would be to - connect a pin to a bus line (which is pulled - up to a positive voltage by a separate - supply through a large resistor). When the - pin is high, not much current flows through - to ground and the line stays at positive - voltage; when the pin is low, the bus - "drains" to ground with a small amount of - current constantly flowing through the large - resistor from the external supply. In this - mode, no current is ever actually sourced - from the pin. */ - - INPUT, /**< Basic digital input. The pin voltage is sampled; when - it is closer to 3.3v (Vcc) the pin status is high, and - when it is closer to 0v (ground) it is low. If no - external circuit is pulling the pin voltage to high or - low, it will tend to randomly oscillate and be very - sensitive to noise (e.g., a breath of air across the pin - might cause the state to flip). */ - - INPUT_ANALOG, /**< This is a special mode for when the pin will be - used for analog (not digital) reads. Enables ADC - conversion to be performed on the voltage at the - pin. */ - - INPUT_PULLUP, /**< The state of the pin in this mode is reported - the same way as with INPUT, but the pin voltage - is gently "pulled up" towards +3.3v. This means - the state will be high unless an external device - is specifically pulling the pin down to ground, - in which case the "gentle" pull up will not - affect the state of the input. */ - - INPUT_PULLDOWN, /**< The state of the pin in this mode is reported - the same way as with INPUT, but the pin voltage - is gently "pulled down" towards 0v. This means - the state will be low unless an external device - is specifically pulling the pin up to 3.3v, in - which case the "gentle" pull down will not - affect the state of the input. */ - - INPUT_FLOATING, /**< Synonym for INPUT. */ - - PWM, /**< This is a special mode for when the pin will be used for - PWM output (a special case of digital output). */ - - PWM_OPEN_DRAIN, /**< Like PWM, except that instead of alternating - cycles of LOW and HIGH, the voltage on the pin - consists of alternating cycles of LOW and - floating (disconnected). */ -} WiringPinMode; - -/** - * Configure behavior of a GPIO pin. - * - * @param pin Number of pin to configure. - * @param mode Mode corresponding to desired pin behavior. - * @see WiringPinMode - */ -void pinMode(uint8 pin, WiringPinMode mode); - -#define HIGH 0x1 -#define LOW 0x0 - -/** - * Writes a (digital) value to a pin. The pin must have its - * mode set to OUTPUT or OUTPUT_OPEN_DRAIN. - * - * @param pin Pin to write to. - * @param value Either LOW (write a 0) or HIGH (write a 1). - * @see pinMode() - */ -void digitalWrite(uint8 pin, uint8 value); - -/** - * Read a digital value from a pin. The pin must have its mode set to - * one of INPUT, INPUT_PULLUP, and INPUT_PULLDOWN. - * - * @param pin Pin to read from. - * @return LOW or HIGH. - * @see pinMode() - */ -uint32 digitalRead(uint8 pin); - -/** - * Read an analog value from pin. This function blocks during ADC - * conversion, and has 12 bits of resolution. The pin must have its - * mode set to INPUT_ANALOG. - * - * @param pin Pin to read from. - * @return Converted voltage, in the range 0--4095, (i.e. a 12-bit ADC - * conversion). - * @see pinMode() - */ -uint16 analogRead(uint8 pin); - -/** - * Toggles the digital value at the given pin. - * - * The pin must have its mode set to OUTPUT. - * - * @param pin the pin to toggle. If the pin is HIGH, set it LOW. If - * it is LOW, set it HIGH. - * - * @see pinMode() - */ -void togglePin(uint8 pin); - -/** - * Toggle the LED. - * - * If the LED is on, turn it off. If it is off, turn it on. - * - * The LED must its mode set to OUTPUT. This can be accomplished - * portably over all LeafLabs boards by calling pinMode(BOARD_LED_PIN, - * OUTPUT) before calling this function. - * - * @see pinMode() - */ -static inline void toggleLED() { - togglePin(BOARD_LED_PIN); -} - -/** - * If the button is currently pressed, waits until the button is no - * longer being pressed, and returns true. Otherwise, returns false. - * - * The button pin must have its mode set to INPUT. This can be - * accomplished portably over all LeafLabs boards by calling - * pinMode(BOARD_BUTTON_PIN, INPUT). - * - * @see pinMode() - */ -uint8 isButtonPressed(uint8 pin=BOARD_BUTTON_PIN, - uint32 pressedLevel=BOARD_BUTTON_PRESSED_LEVEL); - -/** - * Wait until the button is pressed and released, timing out if no - * press occurs. - * - * The button pin must have its mode set to INPUT. This can be - * accomplished portably over all LeafLabs boards by calling - * pinMode(BOARD_BUTTON_PIN, INPUT). - * - * @param timeout_millis Number of milliseconds to wait until the - * button is pressed. If timeout_millis is left out (or 0), wait - * forever. - * - * @return true, if the button was pressed; false, if the timeout was - * reached. - * - * @see pinMode() - */ -uint8 waitForButtonPress(uint32 timeout_millis=0); - -/** - * Shift out a byte of data, one bit at a time. - * - * This function starts at either the most significant or least - * significant bit in a byte value, and shifts out each byte in order - * onto a data pin. After each bit is written to the data pin, a - * separate clock pin is pulsed to indicate that the new bit is - * available. - * - * @param dataPin Pin to shift data out on - * @param clockPin Pin to pulse after each bit is shifted out - * @param bitOrder Either MSBFIRST (big-endian) or LSBFIRST (little-endian). - * @param value Value to shift out - */ -void shiftOut(uint8 dataPin, uint8 clockPin, uint8 bitOrder, uint8 value); - -#endif diff --git a/STM32F3/cores/maple/wirish/main.cxx b/STM32F3/cores/maple/wirish/main.cxx deleted file mode 100644 index 9c0b9cc..0000000 --- a/STM32F3/cores/maple/wirish/main.cxx +++ /dev/null @@ -1,40 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 LeafLabs LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -// Force init to be called *first*, i.e. before static object allocation. -// Otherwise, statically allocated objects that need libmaple may fail. - __attribute__(( constructor )) void premain() { - init(); -} - -int main(void) { - setup(); - - while (1) { - loop(); - } - return 0; -} diff --git a/STM32F3/cores/maple/wirish/pwm.cpp b/STM32F3/cores/maple/wirish/pwm.cpp deleted file mode 100644 index 44884cd..0000000 --- a/STM32F3/cores/maple/wirish/pwm.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * Copyright (c) 2011, 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file wirish/pwm.cpp - * @brief Wiring-style pwmWrite(). - */ - -#include - -#include -#include - -#include - -void pwmWrite(uint8 pin, uint16 duty_cycle) { - if (pin >= BOARD_NR_GPIO_PINS) { - return; - } - timer_dev *dev = PIN_MAP[pin].timer_device; - uint8 cc_channel = PIN_MAP[pin].timer_channel; - ASSERT(dev && cc_channel); - timer_set_compare(dev, cc_channel, duty_cycle); -} diff --git a/STM32F3/cores/maple/wirish/pwm.h b/STM32F3/cores/maple/wirish/pwm.h deleted file mode 100644 index 6631d42..0000000 --- a/STM32F3/cores/maple/wirish/pwm.h +++ /dev/null @@ -1,56 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file wirish/include/wirish/pwm.h - * @brief Wiring-style PWM interface. - */ - -#ifndef _WIRISH_PWM_H_ -#define _WIRISH_PWM_H_ - -#include - -/** - * As a convenience, analogWrite is an alias of pwmWrite to ease - * porting Arduino code. However, period and duty will have to be - * recalibrated. - */ -#define analogWrite pwmWrite - -/** - * Set the PWM duty on the given pin. - * - * User code is expected to determine and honor the maximum value - * (based on the configured period). - * - * @param pin PWM output pin - * @param duty_cycle Duty cycle to set. - */ -void pwmWrite(uint8 pin, uint16 duty_cycle); - -#endif - diff --git a/STM32F3/cores/maple/wirish/rules.mk b/STM32F3/cores/maple/wirish/rules.mk deleted file mode 100644 index 539e966..0000000 --- a/STM32F3/cores/maple/wirish/rules.mk +++ /dev/null @@ -1,66 +0,0 @@ -# Standard things -sp := $(sp).x -dirstack_$(sp) := $(d) -d := $(dir) -BUILDDIRS += $(BUILD_PATH)/$(d) - -# Add board directory and MCU-specific directory to BUILDDIRS. These -# are in subdirectories, but they're logically part of the Wirish -# submodule. -ifeq ($(MCU_SERIES), stm32f3) -WIRISH_BOARD_PATH := boards/$(MCU_F3_LINE) -else -WIRISH_BOARD_PATH := boards/$(BOARD) -endif -BUILDDIRS += $(BUILD_PATH)/$(d)/$(WIRISH_BOARD_PATH) -BUILDDIRS += $(BUILD_PATH)/$(d)/$(MCU_SERIES) - -# Safe includes for Wirish. -WIRISH_INCLUDES := -I$(d)/include -I$(d)/$(WIRISH_BOARD_PATH)/include - -# Local flags. Add -I$(d) to allow for private includes. -CFLAGS_$(d) := $(LIBMAPLE_INCLUDES) $(WIRISH_INCLUDES) -I$(d) - -# Local rules and targets -sSRCS_$(d) := start.S -cSRCS_$(d) := start_c.c -cSRCS_$(d) += syscalls.c -cSRCS_$(d) += $(MCU_SERIES)/util_hooks.c -cppSRCS_$(d) := boards.cpp -cppSRCS_$(d) += cxxabi-compat.cpp -cppSRCS_$(d) += ext_interrupts.cpp -cppSRCS_$(d) += HardwareSerial.cpp -cppSRCS_$(d) += HardwareTimer.cpp -cppSRCS_$(d) += Print.cpp -cppSRCS_$(d) += pwm.cpp -ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),stm32f1 stm32f3)) # TODO port USB serial to F2 -cppSRCS_$(d) += usb_serial.cpp -cppSRCS_$(d) += HardwareSPI.cpp -endif -cppSRCS_$(d) += wirish_analog.cpp -cppSRCS_$(d) += wirish_digital.cpp -cppSRCS_$(d) += wirish_math.cpp -cppSRCS_$(d) += wirish_shift.cpp -cppSRCS_$(d) += wirish_time.cpp -cppSRCS_$(d) += $(MCU_SERIES)/boards_setup.cpp -cppSRCS_$(d) += $(MCU_SERIES)/wirish_digital.cpp -cppSRCS_$(d) += $(MCU_SERIES)/wirish_debug.cpp -cppSRCS_$(d) += $(WIRISH_BOARD_PATH)/board.cpp - -sFILES_$(d) := $(sSRCS_$(d):%=$(d)/%) -cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%) -cppFILES_$(d) := $(cppSRCS_$(d):%=$(d)/%) - -OBJS_$(d) := $(sFILES_$(d):%.S=$(BUILD_PATH)/%.o) \ - $(cFILES_$(d):%.c=$(BUILD_PATH)/%.o) \ - $(cppFILES_$(d):%.cpp=$(BUILD_PATH)/%.o) -DEPS_$(d) := $(OBJS_$(d):%.o=%.d) - -$(OBJS_$(d)): TGT_CFLAGS := $(CFLAGS_$(d)) - -TGT_BIN += $(OBJS_$(d)) - -# Standard things --include $(DEPS_$(d)) -d := $(dirstack_$(sp)) -sp := $(basename $(sp)) diff --git a/STM32F3/cores/maple/wirish/stm32f3/boards_setup.cpp b/STM32F3/cores/maple/wirish/stm32f3/boards_setup.cpp deleted file mode 100644 index 6984419..0000000 --- a/STM32F3/cores/maple/wirish/stm32f3/boards_setup.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2012 LeafLabs, LLC. - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -*****************************************************************************/ - -/** - * @file wirish/stm32f3/boards_setup.cpp - * @author Marti Bolivar , - * Hanspeter Portner - * @brief STM32F3 chip setup. - * - * This file controls how init() behaves on the STM32F3. Be very - * careful when changing anything here. Many of these values depend - * upon each other. - */ - -#include "boards_private.h" - -#include -#include - -#include -#include -#include -#include - -// Allow boards to provide a PLL multiplier. This is useful for -// e.g. STM32F300 value line MCUs, which use slower multipliers. -// (We're leaving the default to RCC_PLLMUL_9 for now, since that -// works for F303 performance line MCUs, which is all that LeafLabs -// currently officially supports). -#ifndef BOARD_RCC_PLLMUL -#define BOARD_RCC_PLLMUL RCC_PLLMUL_9 -#endif - -namespace wirish { - namespace priv { - - static stm32f3_rcc_pll_data pll_data = {.pll_mul=BOARD_RCC_PLLMUL, .pclk_prediv=RCC_PREDIV_PCLK_DIV_1}; - __weak rcc_pll_cfg w_board_pll_cfg = {RCC_PLLSRC_HSE, &pll_data}; - __weak adc_prescaler w_adc_pre = ADC_PRE_PCLK_DIV_1; - __weak adc_smp_rate w_adc_smp = ADC_SMPR_181_5; - - __weak void board_reset_pll(void) { - // TODO - } - - __weak void board_setup_clock_prescalers(void) { - rcc_set_prescaler(RCC_PRESCALER_AHB, RCC_AHB_SYSCLK_DIV_1); - rcc_set_prescaler(RCC_PRESCALER_APB1, RCC_APB1_HCLK_DIV_2); - rcc_set_prescaler(RCC_PRESCALER_APB2, RCC_APB2_HCLK_DIV_1); - } - - __weak void board_setup_gpio(void) { - gpio_init_all(); - } - - __weak void board_setup_usb(void) { - SerialUSB.begin(); - } - - __weak void series_init(void) { - /* We need SYSCFG for external interrupts */ - syscfg_init(); - - /* enable floating point unit */ - fpu_enable(); - } - } -} diff --git a/STM32F3/cores/maple/wirish/stm32f3/f3_wirish_digital.cpp b/STM32F3/cores/maple/wirish/stm32f3/f3_wirish_digital.cpp deleted file mode 100644 index 50cda60..0000000 --- a/STM32F3/cores/maple/wirish/stm32f3/f3_wirish_digital.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/* - * STM32F3 implementations for basic GPIO functionality. - */ - -#include - -#include -#include - -#include - -void pinMode(uint8 pin, WiringPinMode w_mode) { - if (pin >= BOARD_NR_GPIO_PINS) { - return; - } - - gpio_pin_mode mode; - // People always do the silly pin-toggle speed benchmark, so let's - // accomodate them: - unsigned flags = GPIO_MODEF_SPEED_HIGH; - bool pwm = false; - switch(w_mode) { - case OUTPUT: - mode = GPIO_MODE_OUTPUT; - break; - case OUTPUT_OPEN_DRAIN: - mode = GPIO_MODE_OUTPUT; - flags |= GPIO_MODEF_TYPE_OD; - break; - case INPUT: - case INPUT_FLOATING: - mode = GPIO_MODE_INPUT; - break; - case INPUT_ANALOG: - mode = GPIO_MODE_ANALOG; - break; - case INPUT_PULLUP: - mode = GPIO_MODE_INPUT; - flags |= GPIO_MODEF_PUPD_PU; - break; - case INPUT_PULLDOWN: - mode = GPIO_MODE_INPUT; - flags |= GPIO_MODEF_PUPD_PD; - break; - case PWM: - mode = GPIO_MODE_AF; - pwm = true; - break; - case PWM_OPEN_DRAIN: - mode = GPIO_MODE_AF; - flags |= GPIO_MODEF_TYPE_OD; - pwm = true; - break; - default: - ASSERT(0); // Can't happen - return; - } - - const stm32_pin_info *info = &PIN_MAP[pin]; - - if (pwm) { - /* If enabling PWM, tell the timer to do PWM, and tell the pin - * to listen to the right timer. */ - ASSERT(info->timer_device != NULL); - if (info->timer_device == NULL) { - return; - } - gpio_af timer_af = timer_get_af(info->timer_device); - timer_set_mode(info->timer_device, info->timer_channel, TIMER_PWM); - gpio_set_af(info->gpio_device, info->gpio_bit, timer_af); - } - gpio_set_modef(info->gpio_device, info->gpio_bit, mode, flags); -} diff --git a/STM32F3/cores/maple/wirish/stm32f3/util_hooks.c b/STM32F3/cores/maple/wirish/stm32f3/util_hooks.c deleted file mode 100644 index 2387cf7..0000000 --- a/STM32F3/cores/maple/wirish/stm32f3/util_hooks.c +++ /dev/null @@ -1,45 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/* - * STM32F3 implementations for libmaple util.c hooks - * FIXME these are just minimal stubs - */ - -#include - -/* - * Disables all peripheral interrupts. Called by __error() with global - * interrupts disabled. - */ -void __lm_error(void) { - nvic_irq_disable_all(); -} - -/* - * Enable the error USART for writing. - */ -/* usart_dev* __lm_enable_error_usart(void) { (TODO) } */ diff --git a/STM32F3/cores/maple/wirish/stm32f3/wirish_debug.cpp b/STM32F3/cores/maple/wirish/stm32f3/wirish_debug.cpp deleted file mode 100644 index 6a6e1c1..0000000 --- a/STM32F3/cores/maple/wirish/stm32f3/wirish_debug.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file wirish/stm32f3/wirish_debug.cpp - * @brief High level debug port configuration - */ - -#include -#include -#include - -void disableDebugPorts(void) { - // BOARD_JTMS_SWDIO_PIN-BOARD_JTDI_PIN and BOARD_JTDO_PIN-BOARD_NJTRST_PIN are in system alternate function mode on - // reset, to support JTAG. Just put them in input mode to release - // them. - gpio_set_modef(PIN_MAP[BOARD_JTMS_SWDIO_PIN].gpio_device, PIN_MAP[BOARD_JTMS_SWDIO_PIN].gpio_bit, - GPIO_MODE_INPUT, GPIO_MODEF_PUPD_NONE); - gpio_set_modef(PIN_MAP[BOARD_JTCK_SWCLK_PIN].gpio_device, PIN_MAP[BOARD_JTCK_SWCLK_PIN].gpio_bit, - GPIO_MODE_INPUT, GPIO_MODEF_PUPD_NONE); - gpio_set_modef(PIN_MAP[BOARD_JTDI_PIN].gpio_device, PIN_MAP[BOARD_JTDI_PIN].gpio_bit, - GPIO_MODE_INPUT, GPIO_MODEF_PUPD_NONE); - gpio_set_modef(PIN_MAP[BOARD_JTDO_PIN].gpio_device, PIN_MAP[BOARD_JTDO_PIN].gpio_bit, - GPIO_MODE_INPUT, GPIO_MODEF_PUPD_NONE); - gpio_set_modef(PIN_MAP[BOARD_NJTRST_PIN].gpio_device, PIN_MAP[BOARD_NJTRST_PIN].gpio_bit, - GPIO_MODE_INPUT, GPIO_MODEF_PUPD_NONE); -} - -void enableDebugPorts(void) { - // Put BOARD_JTMS_SWDIO_PIN-BOARD_JTDI_PIN and BOARD_JTDO_PIN-BOARD_NJTRST_PIN back in system AF mode. - gpio_set_modef(PIN_MAP[BOARD_JTMS_SWDIO_PIN].gpio_device, PIN_MAP[BOARD_JTMS_SWDIO_PIN].gpio_bit, - GPIO_MODE_AF, GPIO_MODEF_TYPE_PP); - gpio_set_modef(PIN_MAP[BOARD_JTCK_SWCLK_PIN].gpio_device, PIN_MAP[BOARD_JTCK_SWCLK_PIN].gpio_bit, - GPIO_MODE_AF, GPIO_MODEF_TYPE_PP); - gpio_set_modef(PIN_MAP[BOARD_JTDI_PIN].gpio_device, PIN_MAP[BOARD_JTDI_PIN].gpio_bit, - GPIO_MODE_AF, GPIO_MODEF_TYPE_PP); - gpio_set_modef(PIN_MAP[BOARD_JTDO_PIN].gpio_device, PIN_MAP[BOARD_JTDO_PIN].gpio_bit, - GPIO_MODE_AF, GPIO_MODEF_TYPE_PP); - gpio_set_modef(PIN_MAP[BOARD_NJTRST_PIN].gpio_device, PIN_MAP[BOARD_NJTRST_PIN].gpio_bit, - GPIO_MODE_AF, GPIO_MODEF_TYPE_PP); - - gpio_set_af(PIN_MAP[BOARD_JTMS_SWDIO_PIN].gpio_device, PIN_MAP[BOARD_JTMS_SWDIO_PIN].gpio_bit, GPIO_AF_0); - gpio_set_af(PIN_MAP[BOARD_JTCK_SWCLK_PIN].gpio_device, PIN_MAP[BOARD_JTCK_SWCLK_PIN].gpio_bit, GPIO_AF_0); - gpio_set_af(PIN_MAP[BOARD_JTDI_PIN].gpio_device, PIN_MAP[BOARD_JTDI_PIN].gpio_bit, GPIO_AF_0); - gpio_set_af(PIN_MAP[BOARD_JTDO_PIN].gpio_device, PIN_MAP[BOARD_JTDO_PIN].gpio_bit, GPIO_AF_0); - gpio_set_af(PIN_MAP[BOARD_NJTRST_PIN].gpio_device, PIN_MAP[BOARD_NJTRST_PIN].gpio_bit, GPIO_AF_0); -} diff --git a/STM32F3/cores/maple/wirish/syscalls.c b/STM32F3/cores/maple/wirish/syscalls.c deleted file mode 100644 index a3b6d2c..0000000 --- a/STM32F3/cores/maple/wirish/syscalls.c +++ /dev/null @@ -1,175 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * Copyright (c) 2011, 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file wirish/syscalls.c - * @brief newlib stubs - * - * Low level system routines used by newlib for basic I/O and memory - * allocation. You can override most of these. - */ - -#include - -#include -#include - -/* If CONFIG_HEAP_START (or CONFIG_HEAP_END) isn't defined, then - * assume _lm_heap_start (resp. _lm_heap_end) is appropriately set by - * the linker */ -#ifndef CONFIG_HEAP_START -extern char _lm_heap_start; -#define CONFIG_HEAP_START ((caddr_t)&_lm_heap_start) -#endif -#ifndef CONFIG_HEAP_END -extern char _lm_heap_end; -#define CONFIG_HEAP_END ((caddr_t)&_lm_heap_end) -#endif - -/* - * _sbrk -- Increment the program break. - * - * Get incr bytes more RAM (for use by the heap). malloc() and - * friends call this function behind the scenes. - */ -caddr_t _sbrk(int incr) { - static caddr_t pbreak = NULL; /* current program break */ - caddr_t ret; - - if (pbreak == NULL) { - pbreak = CONFIG_HEAP_START; - } - - if ((CONFIG_HEAP_END - pbreak < incr) || - (pbreak - CONFIG_HEAP_START < -incr)) { - errno = ENOMEM; - return (caddr_t)-1; - } - - ret = pbreak; - pbreak += incr; - return ret; -} - -__weak int _open(const char *path, int flags, ...) { - return 1; -} - -__weak int _close(int fd) { - return 0; -} - -__weak int _fstat(int fd, struct stat *st) { - st->st_mode = S_IFCHR; - return 0; -} - -__weak int _isatty(int fd) { - return 1; -} - -__weak int isatty(int fd) { - return 1; -} - -__weak int _lseek(int fd, off_t pos, int whence) { - return -1; -} - -__weak unsigned char getch(void) { - return 0; -} - - -__weak int _read(int fd, char *buf, size_t cnt) { - *buf = getch(); - - return 1; -} - -__weak void putch(unsigned char c) { -} - -__weak void cgets(char *s, int bufsize) { - char *p; - int c; - int i; - - for (i = 0; i < bufsize; i++) { - *(s+i) = 0; - } -// memset(s, 0, bufsize); - - p = s; - - for (p = s; p < s + bufsize-1;) { - c = getch(); - switch (c) { - case '\r' : - case '\n' : - putch('\r'); - putch('\n'); - *p = '\n'; - return; - - case '\b' : - if (p > s) { - *p-- = 0; - putch('\b'); - putch(' '); - putch('\b'); - } - break; - - default : - putch(c); - *p++ = c; - break; - } - } - return; -} - -__weak int _write(int fd, const char *buf, size_t cnt) { - int i; - - for (i = 0; i < cnt; i++) - putch(buf[i]); - - return cnt; -} - -/* Override fgets() in newlib with a version that does line editing */ -__weak char *fgets(char *s, int bufsize, void *f) { - cgets(s, bufsize); - return s; -} - -__weak void _exit(int exitcode) { - while (1) - ; -} diff --git a/STM32F3/cores/maple/wirish/usb_serial.cpp b/STM32F3/cores/maple/wirish/usb_serial.cpp deleted file mode 100644 index d21766f..0000000 --- a/STM32F3/cores/maple/wirish/usb_serial.cpp +++ /dev/null @@ -1,260 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @brief USB virtual serial terminal - */ - -#include - -#include -#include - -#include -#include -#include - -#include - -/* - * Hooks used for bootloader reset signalling - */ - -#if BOARD_HAVE_SERIALUSB -static void rxHook(unsigned, void*); -static void ifaceSetupHook(unsigned, void*); -#endif - -/* - * USBSerial interface - */ - -#define USB_TIMEOUT 50 - -USBSerial::USBSerial(void) { -#if !BOARD_HAVE_SERIALUSB - ASSERT(0); -#endif -} - -void USBSerial::begin(void) { -#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); -#endif -} - -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); -#endif -} - -void USBSerial::write(uint8 ch) { - this->write(&ch, 1); -} - -void USBSerial::write(const char *str) { - this->write(str, strlen(str)); -} - -void USBSerial::write(const void *buf, uint32 len) { - if (!this->isConnected() || !buf) { - return; - } - - 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; - } - - - 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); - } -} - -uint32 USBSerial::available(void) { - return usb_cdcacm_data_available(); -} - -uint32 USBSerial::read(void *buf, uint32 len) { - if (!buf) { - return 0; - } - - uint32 rxed = 0; - while (rxed < len) { - rxed += usb_cdcacm_rx((uint8*)buf + rxed, len - rxed); - } - - return rxed; -} - -/* Blocks forever until 1 byte is received */ -uint8 USBSerial::read(void) { - uint8 b; - this->read(&b, 1); - return b; -} - -uint8 USBSerial::pending(void) { - return usb_cdcacm_get_pending(); -} - -uint8 USBSerial::isConnected(void) { - return usb_is_connected(USBLIB) && usb_is_configured(USBLIB); -} - -uint8 USBSerial::getDTR(void) { - return usb_cdcacm_get_dtr(); -} - -uint8 USBSerial::getRTS(void) { - return usb_cdcacm_get_rts(); -} - -#if BOARD_HAVE_SERIALUSB -USBSerial SerialUSB; -#endif - -/* - * Bootloader hook implementations - */ - -#if BOARD_HAVE_SERIALUSB - -enum reset_state_t { - DTR_UNSET, - DTR_HIGH, - DTR_NEGEDGE, - DTR_LOW -}; - -static reset_state_t reset_state = DTR_UNSET; - -static void ifaceSetupHook(unsigned hook, void *requestvp) { - uint8 request = *(uint8*)requestvp; - - // Ignore requests we're not interested in. - if (request != USB_CDCACM_SET_CONTROL_LINE_STATE) { - return; - } - - // We need to see a negative edge on DTR before we start looking - // for the in-band magic reset byte sequence. - uint8 dtr = usb_cdcacm_get_dtr(); - switch (reset_state) { - case DTR_UNSET: - reset_state = dtr ? DTR_HIGH : DTR_LOW; - break; - case DTR_HIGH: - reset_state = dtr ? DTR_HIGH : DTR_NEGEDGE; - break; - case DTR_NEGEDGE: - reset_state = dtr ? DTR_HIGH : DTR_LOW; - break; - case DTR_LOW: - reset_state = dtr ? DTR_HIGH : DTR_LOW; - break; - } -} - -#define RESET_DELAY 100000 -static void wait_reset(void) { - delay_us(RESET_DELAY); - nvic_sys_reset(); -} - -#define STACK_TOP 0x20000800 -#define EXC_RETURN 0xFFFFFFF9 -#define DEFAULT_CPSR 0x61000000 -static void rxHook(unsigned hook, void *ignored) { - /* FIXME this is mad buggy; we need a new reset sequence. E.g. NAK - * after each RX means you can't reset if any bytes are waiting. */ - if (reset_state == DTR_NEGEDGE) { - reset_state = DTR_LOW; - - if (usb_cdcacm_data_available() >= 4) { - // The magic reset sequence is "1EAF". - static const uint8 magic[4] = {'1', 'E', 'A', 'F'}; - uint8 chkBuf[4]; - - // Peek at the waiting bytes, looking for reset sequence, - // bailing on mismatch. - usb_cdcacm_peek(chkBuf, 4); - for (unsigned i = 0; i < sizeof(magic); i++) { - if (chkBuf[i] != magic[i]) { - return; - } - } - - // Got the magic sequence -> reset, presumably into the bootloader. - // Return address is wait_reset, but we must set the thumb bit. - uintptr_t target = (uintptr_t)wait_reset | 0x1; - asm volatile("mov r0, %[stack_top] \n\t" // Reset stack - "mov sp, r0 \n\t" - "mov r0, #1 \n\t" - "mov r1, %[target_addr] \n\t" - "mov r2, %[cpsr] \n\t" - "push {r2} \n\t" // Fake xPSR - "push {r1} \n\t" // PC target addr - "push {r0} \n\t" // Fake LR - "push {r0} \n\t" // Fake R12 - "push {r0} \n\t" // Fake R3 - "push {r0} \n\t" // Fake R2 - "push {r0} \n\t" // Fake R1 - "push {r0} \n\t" // Fake R0 - "mov lr, %[exc_return] \n\t" - "bx lr" - : - : [stack_top] "r" (STACK_TOP), - [target_addr] "r" (target), - [exc_return] "r" (EXC_RETURN), - [cpsr] "r" (DEFAULT_CPSR) - : "r0", "r1", "r2"); - /* Can't happen. */ - ASSERT_FAULT(0); - } - } -} - -#endif // BOARD_HAVE_SERIALUSB diff --git a/STM32F3/cores/maple/wirish/usb_serial.h b/STM32F3/cores/maple/wirish/usb_serial.h deleted file mode 100644 index f36671b..0000000 --- a/STM32F3/cores/maple/wirish/usb_serial.h +++ /dev/null @@ -1,67 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @brief Wirish USB virtual serial port (SerialUSB). - */ - -#ifndef _WIRISH_USB_SERIAL_H_ -#define _WIRISH_USB_SERIAL_H_ - -#include -#include - -/** - * @brief Virtual serial terminal. - */ -class USBSerial : public Print { -public: - USBSerial(void); - - void begin(void); - void end(void); - - uint32 available(void); - - uint32 read(void *buf, uint32 len); - uint8 read(void); - - void write(uint8); - void write(const char *str); - void write(const void*, uint32); - - uint8 getRTS(); - uint8 getDTR(); - uint8 isConnected(); - uint8 pending(); -}; - -#if BOARD_HAVE_SERIALUSB -extern USBSerial SerialUSB; -#endif - -#endif - diff --git a/STM32F3/cores/maple/wirish/wirish.h b/STM32F3/cores/maple/wirish/wirish.h deleted file mode 100644 index f1884b5..0000000 --- a/STM32F3/cores/maple/wirish/wirish.h +++ /dev/null @@ -1,77 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @brief Main include file for the Wirish core. - * - * Includes most of Wirish, and (transitively or otherwise) - * substantial pieces of libmaple proper. - */ - -#ifndef _WIRISH_WIRISH_H_ -#define _WIRISH_WIRISH_H_ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#if (STM32_MCU_SERIES == STM32_SERIES_F1) || (STM32_MCU_SERIES == STM32_SERIES_F3) /* FIXME [0.0.13?] port to F2 */ -#include -#endif -#include -#include -#include -#include - -#include - -#include - -/* Wiring macros and bit defines */ - -#define true 0x1 -#define false 0x0 - -#define LSBFIRST 0 -#define MSBFIRST 1 - -#define lowByte(w) ((w) & 0xFF) -#define highByte(w) (((w) >> 8) & 0xFF) -#define bitRead(value, bit) (((value) >> (bit)) & 0x01) -#define bitSet(value, bit) ((value) |= (1UL << (bit))) -#define bitClear(value, bit) ((value) &= ~(1UL << (bit))) -#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : \ - bitClear(value, bit)) -#define bit(b) (1UL << (b)) - -#endif - diff --git a/STM32F3/cores/maple/wirish/wirish_analog.cpp b/STM32F3/cores/maple/wirish/wirish_analog.cpp deleted file mode 100644 index 91ca0e2..0000000 --- a/STM32F3/cores/maple/wirish/wirish_analog.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * Copyright (c) 2011, 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file wirish/wirish_analog.cpp - * @brief Wiring-style analogRead() implementation. - */ - -#include -#include -#include - -/* Unlike Wiring and Arduino, this assumes that the pin's mode is set - * to INPUT_ANALOG. That's faster, but it does require some extra work - * on the user's part. Not too much, we think ;). */ -uint16 analogRead(uint8 pin) { - const adc_dev *dev = PIN_MAP[pin].adc_device; - if (dev == NULL) { - return 0; - } - - return adc_read(dev, PIN_MAP[pin].adc_channel); -} diff --git a/STM32F3/cores/maple/wirish/wirish_debug.h b/STM32F3/cores/maple/wirish/wirish_debug.h deleted file mode 100644 index 4edfd27..0000000 --- a/STM32F3/cores/maple/wirish/wirish_debug.h +++ /dev/null @@ -1,57 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2011 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file wirish/include/wirish/wirish_debug.h - * @brief High level debug port configuration - */ - -#ifndef _WIRISH_WIRISH_DEBUG_H_ -#define _WIRISH_WIRISH_DEBUG_H_ - -#include - -/** - * @brief Disable the JTAG and Serial Wire (SW) debug ports. - * - * You can call this function in order to use the JTAG and SW debug - * pins as ordinary GPIOs. - * - * @see enableDebugPorts() - */ -void disableDebugPorts(void); - -/** - * @brief Enable the JTAG and Serial Wire (SW) debug ports. - * - * After you call this function, the JTAG and SW debug pins will no - * longer be usable as GPIOs. - * - * @see disableDebugPorts() - */ -void enableDebugPorts(void); - -#endif diff --git a/STM32F3/cores/maple/wirish/wirish_digital.cpp b/STM32F3/cores/maple/wirish/wirish_digital.cpp deleted file mode 100644 index 2711a33..0000000 --- a/STM32F3/cores/maple/wirish/wirish_digital.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * Copyright (c) 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/* - * Arduino-compatible digital I/O implementation. - */ - -#include - -#include -#include - -#include -#include - -uint32 digitalRead(uint8 pin) { - if (pin >= BOARD_NR_GPIO_PINS) { - return 0; - } - - return gpio_read_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit) ? - HIGH : LOW; -} - -void digitalWrite(uint8 pin, uint8 val) { - if (pin >= BOARD_NR_GPIO_PINS) { - return; - } - - gpio_write_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit, val); -} - -void togglePin(uint8 pin) { - if (pin >= BOARD_NR_GPIO_PINS) { - return; - } - - gpio_toggle_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit); -} - -#define BUTTON_DEBOUNCE_DELAY 1 - -uint8 isButtonPressed(uint8 pin, uint32 pressedLevel) { - if (digitalRead(pin) == pressedLevel) { - delay(BUTTON_DEBOUNCE_DELAY); - while (digitalRead(pin) == pressedLevel) - ; - return true; - } - return false; -} - -uint8 waitForButtonPress(uint32 timeout) { - uint32 start = millis(); - uint32 time; - if (timeout == 0) { - while (!isButtonPressed()) - ; - return true; - } - do { - time = millis(); - /* properly handle wrap-around */ - if ((start > time && time + (0xffffffffU - start) > timeout) || - time - start > timeout) { - return false; - } - } while (!isButtonPressed()); - return true; -} diff --git a/STM32F3/cores/maple/wirish/wirish_math.cpp b/STM32F3/cores/maple/wirish/wirish_math.cpp deleted file mode 100644 index 1443b3c..0000000 --- a/STM32F3/cores/maple/wirish/wirish_math.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Modified by LeafLabs, LLC. - * - * Part of the Wiring project - http://wiring.org.co Copyright (c) - * 2004-06 Hernando Barragan Modified 13 August 2006, David A. Mellis - * for Arduino - http://www.arduino.cc/ - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - */ - -#include -#include - -void randomSeed(unsigned int seed) { - if (seed != 0) { - srand(seed); - } -} - -long random(long howbig) { - if (howbig == 0) { - return 0; - } - - return rand() % howbig; -} - -long random(long howsmall, long howbig) { - if (howsmall >= howbig) { - return howsmall; - } - - long diff = howbig - howsmall; - return random(diff) + howsmall; -} - diff --git a/STM32F3/cores/maple/wirish/wirish_math.h b/STM32F3/cores/maple/wirish/wirish_math.h deleted file mode 100644 index 39f16a0..0000000 --- a/STM32F3/cores/maple/wirish/wirish_math.h +++ /dev/null @@ -1,151 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file wirish/include/wirish/wirish_math.h - * @brief Includes ; provides Wiring-compatible math routines. - */ - -#ifndef _WIRISH_WIRISH_MATH_H_ -#define _WIRISH_WIRISH_MATH_H_ - -#include - -/** - * @brief Initialize the pseudo-random number generator. - * @param seed the number used to initialize the seed; cannot be zero. - */ -void randomSeed(unsigned int seed); - -/** - * @brief Generate a pseudo-random number with upper bound. - * @param max An upper bound on the returned value, exclusive. - * @return A pseudo-random number in the range [0,max). - * @see randomSeed() - */ -long random(long max); - -/** - * @brief Generate a pseudo-random number with lower and upper bounds. - * @param min Lower bound on the returned value, inclusive. - * @param max Upper bound on the returned value, exclusive. - * @return A pseudo-random number in the range [min, max). - * @see randomSeed() - */ -long random(long min, long max); - -/** - * @brief Remap a number from one range to another. - * - * That is, a value equal to fromStart gets mapped to toStart, a value - * of fromEnd to toEnd, and other values are mapped proportionately. - * - * Does not constrain value to lie within [fromStart, fromEnd]. - * - * If a "start" value is larger than its corresponding "end", the - * ranges are reversed, so map(n, 1, 10, 10, 1) would reverse the - * range [1,10]. - * - * Negative numbers may appear as any argument. - * - * @param value the value to map. - * @param fromStart the beginning of the value's current range. - * @param fromEnd the end of the value's current range. - * @param toStart the beginning of the value's mapped range. - * @param toEnd the end of the value's mapped range. - * @return the mapped value. - */ -static inline long map(long value, long fromStart, long fromEnd, - long toStart, long toEnd) { - return (value - fromStart) * (toEnd - toStart) / (fromEnd - fromStart) + - toStart; -} - -#define PI 3.1415926535897932384626433832795 -#define HALF_PI 1.5707963267948966192313216916398 -#define TWO_PI 6.283185307179586476925286766559 -#define DEG_TO_RAD 0.017453292519943295769236907684886 -#define RAD_TO_DEG 57.295779513082320876798154814105 - -#define min(a,b) ((a)<(b)?(a):(b)) -#define max(a,b) ((a)>(b)?(a):(b)) -#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt))) -#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5)) -#define radians(deg) ((deg)*DEG_TO_RAD) -#define degrees(rad) ((rad)*RAD_TO_DEG) -#define sq(x) ((x)*(x)) - -/* undefine stdlib's abs if encountered */ -#ifdef abs -#undef abs -#endif -#define abs(x) (((x) > 0) ? (x) : -(x)) - -/* Following are duplicate declarations (with Doxygen comments) for - * some of the math.h functions; this is for the convenience of the - * Sphinx docs. - */ - -/** - * Compute the cosine of an angle, in radians. - * @param x The radian measure of the angle. - * @return The cosine of x. This value will be between -1 and 1. - */ -double cos(double x); - -/** - * Compute the sine of an angle, in radians. - * @param x The radian measure of the angle. - * @return The sine of x. This value will be between -1 and 1. - */ -double sin(double x); - -/** - * Compute the tangent of an angle, in radians. - * @param x The radian measure of the angle. - * @return The tangent of x. There are no limits on the return value - * of this function. - */ -double tan(double x); - -/** - * Compute the square root of a number. - * @param x The number whose square root to find. This value cannot - * be negative. - * @return The square root of x. The return value is never negative. - */ -double sqrt(double x); - -/** - * Compute an exponentiation. - * @param x the base. This value cannot be zero if y <= 0. This value - * cannot be negative if y is not an integral value. - * @param y the exponent. - * @return x raised to the power y. - */ -double pow(double x, double y); - -#endif diff --git a/STM32F3/cores/maple/wirish/wirish_shift.cpp b/STM32F3/cores/maple/wirish/wirish_shift.cpp deleted file mode 100644 index a032d50..0000000 --- a/STM32F3/cores/maple/wirish/wirish_shift.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2012 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -#include - -void shiftOut(uint8 dataPin, uint8 clockPin, uint8 bitOrder, uint8 value) { - digitalWrite(clockPin, LOW); - for (int i = 0; i < 8; i++) { - int bit = bitOrder == LSBFIRST ? i : (7 - i); - digitalWrite(dataPin, (value >> bit) & 0x1); - togglePin(clockPin); - togglePin(clockPin); - } -} diff --git a/STM32F3/cores/maple/wirish/wirish_time.cpp b/STM32F3/cores/maple/wirish/wirish_time.cpp deleted file mode 100644 index 9ce934b..0000000 --- a/STM32F3/cores/maple/wirish/wirish_time.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @brief Delay implementation. - */ - -#include - -#include -#include - -void delay(unsigned long ms) { - uint32 i; - for (i = 0; i < ms; i++) { - delayMicroseconds(1000); - } -} - -void delayMicroseconds(uint32 us) { - delay_us(us); -} diff --git a/STM32F3/cores/maple/wirish/wirish_time.h b/STM32F3/cores/maple/wirish/wirish_time.h deleted file mode 100644 index eb6c68f..0000000 --- a/STM32F3/cores/maple/wirish/wirish_time.h +++ /dev/null @@ -1,95 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file wirish/include/wirish/wirish_time.h - * @brief Timing and delay functions. - */ - -#ifndef _WIRISH_WIRISH_TIME_H_ -#define _WIRISH_WIRISH_TIME_H_ - -#include -#include - -#include - -/** - * Returns time (in milliseconds) since the beginning of program - * execution. On overflow, restarts at 0. - * @see micros() - */ -static inline uint32 millis(void) { - return systick_uptime(); -} - -/** - * Returns time (in microseconds) since the beginning of program - * execution. On overflow, restarts at 0. - * @see millis() - */ -static inline uint32 micros(void) { - uint32 ms; - uint32 cycle_cnt; - - do { - ms = millis(); - cycle_cnt = systick_get_count(); - } while (ms != millis()); - -#define US_PER_MS 1000 - /* SYSTICK_RELOAD_VAL is 1 less than the number of cycles it - * actually takes to complete a SysTick reload */ - return ((ms * US_PER_MS) + - (SYSTICK_RELOAD_VAL + 1 - cycle_cnt) / CYCLES_PER_MICROSECOND); -#undef US_PER_MS -} - -/** - * Delay for at least the given number of milliseconds. - * - * Interrupts, etc. may cause the actual number of milliseconds to - * exceed ms. However, this function will return no less than ms - * milliseconds from the time it is called. - * - * @param ms the number of milliseconds to delay. - * @see delayMicroseconds() - */ -void delay(unsigned long ms); - -/** - * Delay for at least the given number of microseconds. - * - * Interrupts, etc. may cause the actual number of microseconds to - * exceed us. However, this function will return no less than us - * microseconds from the time it is called. - * - * @param us the number of microseconds to delay. - * @see delay() - */ -void delayMicroseconds(uint32 us); - -#endif diff --git a/STM32F3/cores/maple/wirish/wirish_types.h b/STM32F3/cores/maple/wirish/wirish_types.h deleted file mode 100644 index fce895e..0000000 --- a/STM32F3/cores/maple/wirish/wirish_types.h +++ /dev/null @@ -1,68 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2011 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file wirish/include/wirish/wirish_types.h - * @author Marti Bolivar - * @brief Wirish library type definitions. - */ - -#ifndef _WIRISH_WIRISH_TYPES_H_ -#define _WIRISH_WIRISH_TYPES_H_ - -#include -#include -#include -#include - -/** - * Invalid stm32_pin_info adc_channel value. - * @see stm32_pin_info - */ -#define ADCx 0xFF - -/** - * @brief Stores STM32-specific information related to a given Maple pin. - * @see PIN_MAP - */ -typedef struct stm32_pin_info { - gpio_dev *gpio_device; /**< Maple pin's GPIO device */ - timer_dev *timer_device; /**< Pin's timer device, if any. */ - const adc_dev *adc_device; /**< ADC device, if any. */ - uint8 gpio_bit; /**< Pin's GPIO port bit. */ - uint8 timer_channel; /**< Timer channel, or 0 if none. */ - uint8 adc_channel; /**< Pin ADC channel, or ADCx if none. */ -} stm32_pin_info; - -/** - * Variable attribute, instructs the linker to place the marked - * variable in Flash instead of RAM. */ -#define __FLASH__ __attr_flash - -typedef uint8 boolean; -typedef uint8 byte; - -#endif diff --git a/STM32F3/examples/Blinkf3/Blinkf3.ino b/STM32F3/examples/Blinkf3/Blinkf3.ino deleted file mode 100644 index 2bcb929..0000000 --- a/STM32F3/examples/Blinkf3/Blinkf3.ino +++ /dev/null @@ -1,38 +0,0 @@ -/* - Blink - Turns on an LED on for one second, then off for one second, repeatedly. - - Most Arduinos have an on-board LED you can control. On the Uno and - Leonardo, it is attached to digital pin 13. If you're unsure what - pin the on-board LED is connected to on your Arduino model, check - the documentation at http://arduino.cc - - This example code is in the public domain. - - modified 8 May 2014 - by Scott Fitzgerald - - modified for stm32f3discovery - 2015/02 by Frank-Michael Krause - */ - - -// the setup function runs once when you press reset or power the board -void setup() { - // initialize pins PE8, PE9 as an output. - pinMode(PE8, OUTPUT); - pinMode(PE9, OUTPUT); - Serial2.begin(9600); - Serial2.println("Hello world"); - -} - -// the loop function runs over and over again forever -void loop() { - digitalWrite(PE8, HIGH); // turn the LED on (HIGH is the voltage level) - digitalWrite(PE9, LOW); // turn the LED off by making the voltage LOW - delay(100); // wait for a second - digitalWrite(PE8, LOW); // turn the LED off by making the voltage LOW - digitalWrite(PE9, HIGH); // turn the LED on (HIGH is the voltage level) - delay(300); // wait for a second -} diff --git a/STM32F3/examples/f3_buttondemo/f3_buttondemo.ino b/STM32F3/examples/f3_buttondemo/f3_buttondemo.ino deleted file mode 100644 index c6a9c0d..0000000 --- a/STM32F3/examples/f3_buttondemo/f3_buttondemo.ino +++ /dev/null @@ -1,54 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2015 Frank-Michael Krause - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - - -/* - * This demo shows how to handle the blue button of the stm32f3discovery board - * - * Dieses Beispiel zeigt, wie die blaue Taste des Boards abgefragt werden kann. - * Es wird eine LED ein- bzw. ausgeschaltet. - */ - - -void setup() // Init-Funktion -{ - // BOARD_LED_PIN ist PE10 - pinMode(BOARD_LED_PIN, OUTPUT); - - // BOARD_BUTTTON_PIN ist PA0 - pinMode(BOARD_BUTTON_PIN, INPUT); - -} - - -void loop() -{ - if (isButtonPressed()) - togglePin(BOARD_LED_PIN); -} - - - diff --git a/STM32F3/examples/f3_functionTimer/f3_functionTimer.ino b/STM32F3/examples/f3_functionTimer/f3_functionTimer.ino deleted file mode 100644 index ca8fce9..0000000 --- a/STM32F3/examples/f3_functionTimer/f3_functionTimer.ino +++ /dev/null @@ -1,144 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2015 Frank-Michael Krause - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - - -#include -#include - -/* - * Demo program function timer - * - * You can define functions register those functions at the timer system - * to be called after the time in ms given at timer start - * - * - there are 10 timers with id from 0 to 9 - * - the id has to be given at timer start - * - there can only be running one instance of a timer id at one time - * - at each timer start another function can be registered - * - time resolution is 5ms - * - * The registered function will be executed in interrupt context. - * Therefore the timer funtion shall be execute very fast. - * - * If using functtion timer and ultrasonic sensors in parallel the measurement results of - * the sensors can be slightly wrong. - * - * This demo controls three LEDs with different blinking rythms - */ - - -/* - * Demoprogramm fuer Funktions-Timer - * - * Es koennen Funktionen definiert und dem Timersystem-uebergeben werden, - * die nach einer uebergebenen Zeit aufgerufen werden. - * - * - Jeder Timer hat eine id zwischen 0 und 9, die beim Start angegeben werden muss. - * - Es kann nur ein Timer pro Id zu gleichen Zeit laufen - * - Es kann bei jedem Start eines Timers eine andere Funktion uebergeben werden. - * - * Die uebergebene Funktion wird im Interrupt-Kontext ausgefuehrt und unterbricht das - * normal in setup/loop ausgefuehrte Programm an beliebiger Stelle. - * Es ist darauf zu achten, dass die Timerfuntion moeglichst kurz, d.h. schnell ausfuehrbar, ist. - * - * Die parallele Ausfuehrung von Funktionstimern kann die Messergebnisse von Ultraschallsensoren - * leicht verfaelschen! - * - * Das Demoprogramm steuert drei LEDs mit unterschiedlichen Blink-Zeiten an. - * - */ - - - -// 500ms Bink mit Steuerung ueber Timer-Id 0 -#define LED PE9 -int LEDState = 0; -void TimerFunction(int arg) -{ - if (LEDState) - LEDState = 0; - else - LEDState = 1; - digitalWrite(LED, LEDState); - timerStart(0, 500, TimerFunction, 0 ); // restart Timer -} - - -// 900ms Bink mit Steuerung ueber Timer-Id 1 -#define LED1 PE10 -int LED1State = 0; -void Timer1Function(int arg) -{ - if (LED1State) - LED1State = 0; - else - LED1State = 1; - digitalWrite(LED1, LED1State); - timerStart(1, 900, Timer1Function, 0 ); // restart Timer -} - - -// 1300ms Bink mit Steuerung ueber Timer-Id 2 -#define LED2 PE11 -int LED2State = 0; -void Timer2Function(int arg) -{ - if (LED2State) - LED2State = 0; - else - LED2State = 1; - digitalWrite(LED2, LED2State); - timerStart(2, 1300, Timer2Function, 0 ); // restart Timer -} - - - - -void setup() -{ - pinMode(LED, OUTPUT); - pinMode(LED1, OUTPUT); - pinMode(LED2, OUTPUT); - - // Timer-System initialisieren - timerInit(); - - // Timer starten - timerStart(0, 500, TimerFunction, 0 ); - timerStart(1, 900, Timer1Function, 0 ); - timerStart(2, 1300, Timer2Function, 0 ); -} - -void loop() -{ - // Die Programmabarbeitung erfolgt komplett im Interrupt, - // daher muss in loop nichts getan werden - while (1) - ; -} - - - diff --git a/STM32F3/examples/f3_gyrodemo/f3_gyrodemo.ino b/STM32F3/examples/f3_gyrodemo/f3_gyrodemo.ino deleted file mode 100644 index 8e3ca2b..0000000 --- a/STM32F3/examples/f3_gyrodemo/f3_gyrodemo.ino +++ /dev/null @@ -1,100 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2015 Frank-Michael Krause - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ -#include - -#include -#include - - - -/** - * Dieses Beispiel benutzt die Z-Achse des Gyro-Sensors, um eine Drehung des Boards - * zu messen und anzuzeigen. - * Wenn das Board um seine Z-Achse gedreht wird, so zeigt die jeweils aktive LED - * immer in die gleiche Richtung. - * Mit der Zeit ändert sich die angezeigte Richtung, da die Messwerte kleine - * Fehler haben, die sich mit der Zeit aufsummieren und das Programm keine - * Kalibrierung und Fehlerkorrektur enthält. Die Größe des Fehlers ist von - * Board zu Board unterschiedlich. - * - */ - -// Array mit den LED-Pins -int leds[] = { PE9, PE10, PE11, PE12, PE13, PE14, PE15, PE8 }; - - -void setup() // Init-Funktion -{ - // Die 8 LED-Pins auf Ausgang setzen - pinMode (leds[0], OUTPUT); - pinMode (leds[1], OUTPUT); - pinMode (leds[2], OUTPUT); - pinMode (leds[3], OUTPUT); - pinMode (leds[4], OUTPUT); - pinMode (leds[5], OUTPUT); - pinMode (leds[6], OUTPUT); - pinMode (leds[7], OUTPUT); - - // SPI1-Interface initialisieren - gyroSpiInit(); - - // den Gyrochip initialisieren - gyroInit(); - - // Gyro aktivieren - gyroStart(); -} - - -int led_idx; - -void loop() -{ - // Auslesen der Gyro-Messwerte und Berechnen des aktuellen Drehwinkels - gyroUpdate(); - - // Wenn der Winkel 360° überschreitet oder 0° unterschreitet - // werden 360° abgezogen bzw. addiert - if (winkelz>360) - winkelz -= 360; - else if (winkelz<0) - winkelz += 360; - - // aktuell aktive LED abschalten - digitalWrite(leds[led_idx], LOW); - - // anhand des Winkels die neue Aktive LED bestimmen. - // Dazu wird mit Dreisatz der Winkel (0..360) auf die LED (0..7) abgebildet - led_idx = (winkelz*8)/360; - - // aktive LED anschalten - digitalWrite(leds[led_idx], HIGH); - - delay(50); -} - - - diff --git a/STM32F3/examples/f3_lsm303demo/f3_lsm303demo.ino b/STM32F3/examples/f3_lsm303demo/f3_lsm303demo.ino deleted file mode 100644 index 63251aa..0000000 --- a/STM32F3/examples/f3_lsm303demo/f3_lsm303demo.ino +++ /dev/null @@ -1,111 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2015 Frank-Michael Krause - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ -#include -#include -#include - -#include -#include - - -/** - * Dieses Beispiel wertet die x und y Werte des Beschleunigungssensors aus - * und zeigt über die 8 LEDs an, in welche Richtung das Board gekippt wurde. - * Die z-Komponente wird nicht ausgewertet. - */ - - -// Array mit den LED-Pins -int leds[] = { PE9, PE10, PE11, PE12, PE13, PE14, PE15, PE8 }; - - -void setup() // Init-Funktion -{ - // Die 8 LED-Pins auf Ausgang setzen - pinMode (leds[0], OUTPUT); - pinMode (leds[1], OUTPUT); - pinMode (leds[2], OUTPUT); - pinMode (leds[3], OUTPUT); - pinMode (leds[4], OUTPUT); - pinMode (leds[5], OUTPUT); - pinMode (leds[6], OUTPUT); - pinMode (leds[7], OUTPUT); - - // I2C-Interface initialisieren, mit dem der - // Beschleunigungssensor verbunden ist - i2c_master_enable(I2C1, 0); - - // Beschleunigungssensor initialisieren - lsm303Init(); - -} - -// Speicher für die aktuell aktive LED -int led_idx; - -void loop() -{ - float winkel; - - // Beschleunigungssensor lesen - readAccValues(); - - // Winkel entsprechend der gemessenen x und y Komponente - // berechnen - // atan2 gibt den Winkel im Bogenmass zurueck, 2*Pi entsprechen 360° - winkel = atan2(accy*-1.0,accx*1.0); - - // Umrechnung des Winkels auf die 8 LEDs, aus denen der Vollkreis (2*Pi) - // besteht (Dreisatz, Umrechnung mit 4 und Pi) - winkel = (winkel*4)/3.14; - - // Falls der Winkel negativ ist, eine Vollkreis-Wert hinzurechnen - // für unser Beispiel 8 - if (winkel<0) - winkel += 8; - - // alte aktive LED ausschalten - digitalWrite(leds[led_idx], LOW); - - // der Ganzzahl-Anteil des Winkels ist der Index der neuen LED - // Das (int) vor winkel führt die Umwandlung der Kommanzahl in einen Integer-Wert - // durch. Das nennt man einen Type-Cast. Der ist hier nötig, da eine - // float Variable nicht direkt einer Integervariable zugewiesen werden kann - led_idx = (int)winkel; - - // nochmal prüfen, ob der neue Led-Index nicht zu groß ist - // wenn ja auf maximalwert setzen - if (led_idx>7) - led_idx=7; - - // neue LED anschalten - digitalWrite(leds[led_idx], HIGH); - - delay(50); -} - - - diff --git a/STM32F3/examples/f3_ultrasonic/f3_ultrasonic.ino b/STM32F3/examples/f3_ultrasonic/f3_ultrasonic.ino deleted file mode 100644 index aa8bc5c..0000000 --- a/STM32F3/examples/f3_ultrasonic/f3_ultrasonic.ino +++ /dev/null @@ -1,137 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2015 Frank-Michael Krause - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -#include -#include -#include - -/* - * Demoprogramm für den Betrieb von Ultraschallsensoren über Interrupts. - * - * Diese Betriebsart hat den Vorteil, dass während der Messung (die einige 10ms dauern kann) - * andere Dinge erledigt werden können. - * - * Es kann ständig im Hintergrund gemessen werden und der letzte gültige oder der aktuelle - * Messwert per Funktion abgefragt werden. - * - * Außerdem kann eine Callbackfunktion pro Sensor registriert werden, die nach einer erfolgten - * Messung aufgerufen wird. ZU beachten ist, dass diese Funktion im Interrupt-Kontext aufgerufen wird - * und daher möglichst kurz (d.h. schnell abarbeitbar) sein. - * Bei Debug-Ausgaben in der Handler-Funktion können sich die Ausgaben in Ausgaben aus loop() heraus "hineindrängeln" - * - */ - - -//----------------- Ultraschall ----------------------- -// 3x HC-SR04 - -#define US1_ECHO PD4 -#define US1_TRIGGER PB4 - -#define US2_ECHO PD5 -#define US2_TRIGGER PB5 - -#define US3_ECHO PD6 -#define US3_TRIGGER PB8 - - - -void UsHandler(int id, int entfernung) -{ - Print2Number("Sensor", id, entfernung); -} - - -void setup() -{ - delay(150); - debugInit(); - debugSetTimeStamp(DDEBUG_TIME_STAMP_ON); - - // Ultraschallsensoren definieren - addUSSensor(0, US1_TRIGGER, US1_ECHO, 220); - addUSSensor(1, US2_TRIGGER, US2_ECHO, 220); - addUSSensor(2, US3_TRIGGER, US3_ECHO); - - UsAttachHandler(0, UsHandler); - UsSetMessPause(100); // Pause von 100 ms nach jeder Messung - // damit die Ausgabe im Terminal nicht zu schnell wird - // Im Normalfall würde keine so lange Pause programmiert werden. - // Die Pause ist nur nötig, wenn festgestellt wird, dass sich - // die Sensoren gegenseitig durch nachfolgende mehrfache Echos beeinflussen. - // Das ist Umgebungsabhängig. - - debugPrint("activate Sensor 0 ---------------"); - aktiviereUSSensor(0); - PrintUsSensorList(); - debugPrint("activate Sensor 1 ---------------"); - aktiviereUSSensor(1); - PrintUsSensorList(); - - debugPrint("activate Sensor 2 ---------------"); - aktiviereUSSensor(2); - PrintUsSensorList(); - - // ab jetzt wird im Hintergrund gemessen - - delay(1000); - debugPrint("deactivate Sensor 2 ---------------"); - deaktiviereUSSensor(2); - PrintUsSensorList(); - - delay(1000); - debugPrint("deactivate Sensor 1 ---------------"); - deaktiviereUSSensor(1); - PrintUsSensorList(); - - delay(1000); - debugPrint("deactivate Sensor 0 ---------------"); - deaktiviereUSSensor(0); - PrintUsSensorList(); - - delay(1000); - debugPrint("activate Sensor 0 ---------------"); - aktiviereUSSensor(0); - PrintUsSensorList(); - - delay(1000); - debugPrint("activate Sensor 1 ---------------"); - aktiviereUSSensor(1); - PrintUsSensorList(); - - - debugPrint("Programm gestartet"); -} - -void loop() -{ - Print2Number("Sensor 1", UsLetzterGueltigerMesswert(1), UsLetzterGueltigerMesswertAlter(1)); - delay(300); -} - - - - diff --git a/STM32F3/libraries/gyro/gyro.cpp b/STM32F3/libraries/gyro/gyro.cpp deleted file mode 100644 index ef3722c..0000000 --- a/STM32F3/libraries/gyro/gyro.cpp +++ /dev/null @@ -1,337 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2015 Frank-Michael Krause - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @brief functions for accessing l3g20 gyro on stm32f3discovery board - * - * SPI1 is set up to be a master - * at 9 MHz (SPI_1_125MHZ), - * 8 Bit - * MSB first in/out (MSBFIRST) - * MODE 0 // following the datasheet it should be MODE 3 but 0 is working too - * - * Pin PE3 is used as slave select, as defined for SPI1 in board.h - * - * There is no interrupt support because I was not able to get out any int2-output of the chip - * - */ - -#include -#include "l3gd20.h" -#include "../ringbuffer/ringbuffer.h" -#include "gyro.h" - - -#define NSS PE3 -#define GYRO_FIFO_WATERMARK 10 - -HardwareSPI spi1(1); -static uint8 gyroValuesSingle[6]; - -static int GYRO_BIAS_X = -75; -static int GYRO_BIAS_Y = 94; -static int GYRO_BIAS_Z = 0; - -float winkelx, winkely, winkelz; -int gyroxRaw, gyroyRaw, gyrozRaw; // bei jedem Update wird ein Datensatz der gelesenen - // Werte in den Raw-Variablen gespeichert um den Bias prüfen zu - // können - -#define RB_SIZE 256 -#define GYRO_AVERAGE_X 120 -#define GYRO_AVERAGE_Y 120 -#define GYRO_AVERAGE_Z 120 - -static int rbvx[RB_SIZE]; -static int rbvy[RB_SIZE]; -static int rbvz[RB_SIZE]; -static RingBufferAverage rbx(RB_SIZE, rbvx, NULL, GYRO_AVERAGE_X); -static RingBufferAverage rby(RB_SIZE, rbvy, NULL, GYRO_AVERAGE_Y); -static RingBufferAverage rbz(RB_SIZE, rbvz, NULL, GYRO_AVERAGE_Z); - -static int averageActiveX = 0; -static int averageActiveY = 0; -static int averageActiveZ = 0; - -void readGyroValues() -{ - int j; - digitalWrite(NSS, LOW); - spi1.transfer(0xA8|0x40); - - for (j=0; j<6; j++) - gyroValuesSingle[j] = spi1.transfer(0); - - digitalWrite(NSS, HIGH); -} - -uint8 gyroReadRegister(uint8 reg) -{ - digitalWrite(NSS, LOW); - spi1.transfer(reg|0x80); - - uint8 val = spi1.transfer(0); - - digitalWrite(NSS, HIGH); - return val; -} - -void gyroWriteRegister(uint8 reg, uint8 val) -{ - digitalWrite(NSS, LOW); - spi1.transfer(reg); - spi1.transfer(val); - digitalWrite(NSS, HIGH); -} - -/** - * Initialisiert das spi1 interface des stm32f3discovery - */ -void gyroSpiInit() -{ - spi1.begin(SPI_9MHZ, MSBFIRST, 0); - /* NSS is usually active LOW, so initialize it HIGH */ - pinMode(NSS, OUTPUT); - digitalWrite(NSS, HIGH); -} - -#define GYRO_OP_PARAMS (GYRO_ODR_190|GYRO_LP_BW1|GYRO_ENABLE) - -/** - * konfiguriert den Gyro. - * der Gyro ist nach dem Aufruf der Funktion aktiv. Wird er nicht mehr benötigt, kann er - * mir gyroStop() wieder deaktiviert werden. Für eine Reaktivierung kann die Funktion - * gyroStart() verwendet werden. - * - * Im aktiven Zustand muss im Abstand von höchstens 120ms die Funktion gyroUpdate() - * aufgerufen werden. - * - * Die globalen Variablen winkelx, winkely und winkelz enthalten den jeweils aktuellen winkel. - * Die Funktion gyroResetWinkel setzt die globalen Variablen wieder auf 0. - */ -void gyroInit() -{ - /* Initialize SPI */ - // gyroSpiInit(); --> called aus dem Anwendungsmodul, - // da an SPI1 noch weitere Geräte betrieben werden - - // Initialize GyroChip - // 190Hz data Rate, 50Hz Bandwidth - gyroWriteRegister(GYRO_REG_CTRL_REG1, GYRO_OP_PARAMS); - - // CTRL_REG2 --> no High Pass --> nothing to change - - // enable Watermark interrupt on INT2 --> not working no int pulse - // gyroWriteRegister(GYRO_REG_CTRL_REG3, GYRO_I2_EN|GYRO_I2_WTM); - - // set resolution to 500 dps - gyroWriteRegister(GYRO_REG_CTRL_REG4, GYRO_FULL_SCALE_500); - - // enable FIFO, Output after second LP-Filter, no HP - gyroWriteRegister(GYRO_REG_CTRL_REG5, GYRO_FIFO_ENABLE|GYRO_OUT_SELECT2); - //gyroWriteRegister(GYRO_REG_CTRL_REG5, GYRO_OUT_SELECT2); - - //Fifomode and watermark - gyroWriteRegister(GYRO_REG_FIFO_CTRL, GYRO_FIFO_MODE_STREAM|GYRO_FIFO_WATERMARK); -} - -/** - * Es werden 1000 Werte eingelesen (ca. 5,5s) und aus den Werten die Drift-Kompensations- - * werte gemittelt. Der Gyro darf während der Zeit nicht bewegt werden. - */ -void gyroCalibrate() { - int count = 0; - int sumx=0,sumy=0,sumz=0; - - #ifdef DEBUG_GYRO - SerialUSB.print("Biaswerte ermitteln "); - #endif - while (count < 1000) - { - delay(100); - uint8 anz = gyroReadRegister(GYRO_REG_FIFO_SRC) & 0x1F; - for (int i=0; i -#include -#include "lsm303reg.h" -#include "../ringbuffer/ringbuffer.h" -#include "lsm303.h" - -#define ACC_FIFO_WATERMARK 10 - -static int ACC_BIAS_X; -static int ACC_BIAS_Y; -static int ACC_BIAS_Z; - - -int accx, accy, accz; - -#define RB_SIZE 64 -#define ACC_AVERAGE_X 60 -#define ACC_AVERAGE_Y 60 -#define ACC_AVERAGE_Z 60 - -static int rbvx[RB_SIZE]; -static long unsigned int rbtx[RB_SIZE]; -static int rbvy[RB_SIZE]; -static long unsigned int rbty[RB_SIZE]; -static int rbvz[RB_SIZE]; -static long unsigned int rbtz[RB_SIZE]; -static RingBuffer rbx(RB_SIZE, rbvx, rbtx); -static RingBuffer rby(RB_SIZE, rbvy, rbty); -static RingBuffer rbz(RB_SIZE, rbvz, rbtz); - -//static int averageActiveX = 0; -//static int averageActiveY = 0; -//static int averageActiveZ = 0; - - -static uint8 write_msg_data[3]; -static i2c_msg write_msg; - -static uint8 read_msg_data[7]; -static i2c_msg read_msg; - - -void readAccValues() -{ - int16 *p; - write_msg_data[0] = LSM303_REG_OUT_X_L_A|LSM303_READ_MULTI_BYTES; // 0x80 -> AutoIncrement address on read - write_msg.length = 1; - i2c_master_xfer(I2C1, &write_msg, 1, 0); - - read_msg.length = 6; - i2c_master_xfer(I2C1, &read_msg, 1, 2); - - p = (int16*)read_msg_data; - accx = *p++ - ACC_BIAS_X; - accy = *p++ - ACC_BIAS_Y; - accz = *p++ - ACC_BIAS_Z; -} - -uint8 accReadRegister(uint8 reg) -{ - write_msg_data[0] = reg; - write_msg.length = 1; - i2c_master_xfer(I2C1, &write_msg, 1, 0); - - read_msg.length = 1; - i2c_master_xfer(I2C1, &read_msg, 1, 2); - - return read_msg_data[0]; -} - -void accWriteRegister(uint8 reg, uint8 val) -{ - write_msg_data[0] = reg; - write_msg_data[1] = val; - write_msg.length = 2; - i2c_master_xfer(I2C1, &write_msg, 1, 0); -} - - -void lsm303I2CInit() -{ - //i2c_master_enable(I2C1, 0); - // Aktivierung des I2C-Busses muss im Hauptprogramm erfolgen, - // da mehrere Komponenten das I2C-Interface benutzen können - // und eine mehrfache Initialisierung nicht funktioniert - - write_msg.addr = LSM303_ADDR_A; - write_msg.flags = 0; // write, 7 bit address - write_msg.length = sizeof(write_msg_data); - write_msg.xferred = 0; - write_msg.data = write_msg_data; - - read_msg.addr = LSM303_ADDR_A; - read_msg.flags = I2C_MSG_READ; - read_msg.length = sizeof(read_msg_data); - read_msg.xferred = 0; - read_msg.data = read_msg_data; - -} - -/** - * Initialisiert und aktiviert den Beschleunigungssensor - * Aktivierung des I2C-Busses muss im Hauptprogramm erfolgen, - * da mehrere Komponenten das I2C-Interface benutzen können - * und eine mehrfache Initialisierung nicht funktioniert - */ -void lsm303Init() -{ - /* Initialize I2C Transfer-Strukturen für den lsm303*/ - lsm303I2CInit(); - - // Initialize ACC-Chip - // 50Hz data Rate - accWriteRegister(LSM303_REG_CTRL_REG1_A, LSM303_A_ODR_50HZ|LSM303_A_ALL_AXIS_EN); - - // CTRL_REG2 --> no High Pass --> nothing to change - - // enable Watermark interrupt on INT2 --> not working no int pulse - // gyroWriteRegister(GYRO_REG_CTRL_REG3, GYRO_I2_EN|GYRO_I2_WTM); - - // sensitivity 2G is default - - // enable FIFO ? - - //Fifomode and watermark -} - - -void accCalibrate() { - int count = 0; - int sumx=0,sumy=0,sumz=0; - - #ifdef DEBUG_ACC - SerialUSB.print("Biaswerte ermitteln "); - #endif - while (count < 100) - { - delay(3); - readAccValues(); - sumx += accx; - sumy += accy; - sumz += accz; - #ifdef DEBUG_ACC - SerialUSB.print("*"); - #endif - count += 1; - } - ACC_BIAS_X = sumx/count; - ACC_BIAS_Y = sumy/count; - ACC_BIAS_Z = sumz/count; - - #ifdef DEBUG_ACC - SerialUSB.println(""); - SerialUSB.print("ACC-BIAS "); - SerialUSB.print(ACC_BIAS_X); SerialUSB.print(" "); - SerialUSB.print(ACC_BIAS_Y); SerialUSB.print(" "); - SerialUSB.println(ACC_BIAS_Z); - #endif -} - - - -void accUpdate() -{ - //uint8 gyroFifoStatus = gyroReadRegister(GYRO_REG_FIFO_SRC); - //uint8 anz = gyroFifoStatus & 0x1F; - - #ifdef DEBUG_ACC -// SerialUSB.print("fifo anz = "); -// SerialUSB.print(anz); -// SerialUSB.print(" "); - #endif - - readAccValues(); - - rbx.addValue(accx); - rby.addValue(accy); - rbz.addValue(accz); - - #ifdef DEBUG_ACC - SerialUSB.print(accx); SerialUSB.print(" "); - SerialUSB.print(accy); SerialUSB.print(" "); - SerialUSB.print(accz); SerialUSB.print(" "); - SerialUSB.println(""); - #endif -} - -void accStart() -{ - rbx.reset(); - rby.reset(); - rbz.reset(); -} - -void accStop() -{ -} - diff --git a/STM32F3/libraries/lsm303/lsm303.h b/STM32F3/libraries/lsm303/lsm303.h deleted file mode 100644 index 78a9d16..0000000 --- a/STM32F3/libraries/lsm303/lsm303.h +++ /dev/null @@ -1,77 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2015 Frank-Michael Krause - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ -#ifndef LSM303_H -#define LSM303_H - - -#define ACC_AXIS_X 1 -#define ACC_AXIS_Y 2 -#define ACC_AXIS_Z 3 - - -/** - * Initialisiert das spi1 interface des stm32f3discovery und konfiguriert den Gyro. - * der Gyro ist nach dem Aufruf der Funktion aktiv. Wird er nicht mehr benötigt, kann er - * mir gyroStop() wieder deaktiviert werden. Für eine Reaktivierung kann die Funktion - * gyroStart() verwendet werden. - * - * Im aktiven Zustand muss im Abstand von höchstens 120ms die Funktion gyroUpdate() - * aufgerufen werden. - * - * Die globalen Variablen winkelx, winkely und winkelz enthalten den jeweils aktuellen winkel. - * Die Funktion gyroResetWinkel setzt die globalen Variablen wieder auf 0. - */ -extern void lsm303Init(); - - -/** - */ -extern void lsm303Calibrate(); - - -/** - */ -extern void accUpdate(); - -/** - */ -extern void accStart(); - -/** - * Versetzt den Beschleunigungssensor in den Power Down mode - */ -extern void accStop(); - - -//---------------------------------------------------------------------------------- -// gobale Variablen - -extern int accx, accy, accz; - - -extern void readAccValues(); - -#endif diff --git a/STM32F3/libraries/lsm303/lsm303reg.h b/STM32F3/libraries/lsm303/lsm303reg.h deleted file mode 100644 index 7bf3f80..0000000 --- a/STM32F3/libraries/lsm303/lsm303reg.h +++ /dev/null @@ -1,131 +0,0 @@ -#ifndef __LSM303REG_H_ -#define __LSM303REG_H_ - -#define LSM303_ADDR_A (0x32>>1) -#define LSM303_ADDR_M (0x3C>>1) - -#define LSM303_REG_CTRL_REG1_A 0x20 -#define LSM303_REG_CTRL_REG2_A 0x21 -#define LSM303_REG_CTRL_REG3_A 0x22 -#define LSM303_REG_CTRL_REG4_A 0x23 -#define LSM303_REG_CTRL_REG5_A 0x24 -#define LSM303_REG_CTRL_REG6_A 0x25 -#define LSM303_REG_REFERENCE_A 0x26 -#define LSM303_REG_STATUS_A 0x27 -#define LSM303_REG_OUT_X_L_A 0x28 -#define LSM303_REG_OUT_X_H_A 0x29 -#define LSM303_REG_OUT_Y_L_A 0x2A -#define LSM303_REG_OUT_Y_H_A 0x2B -#define LSM303_REG_OUT_Z_L_A 0x2C -#define LSM303_REG_OUT_Z_H_A 0x2D -#define LSM303_REG_FIFO_CTRL_A 0x2E -#define LSM303_REG_FIFO_SRC_A 0x2F -#define LSM303_REG_INT1_CFG_A 0x30 -#define LSM303_REG_INT1_SRC_A 0x31 -#define LSM303_REG_INT1_THS_A 0x32 -#define LSM303_REG_INT1_DUARATION_A 0x33 -#define LSM303_REG_INT2_CFG_A 0x34 -#define LSM303_REG_INT2_SRC_A 0x35 -#define LSM303_REG_INT2_THS_A 0x36 -#define LSM303_REG_INT2_DURATION_A 0x37 -#define LSM303_REG_CLICK_CFG_A 0x38 -#define LSM303_REG_CLICK_SRC_A 0x39 -#define LSM303_REG_CLICK_THS_A 0x3A -#define LSM303_REG_TIME_LIMIT_A 0x3B -#define LSM303_REG_TIME_LATENCY_A 0x3C -#define LSM303_REG_TIME_WINDOW_A 0x3D - -#define LSM303_READ_MULTI_BYTES 0x80 - - -//================================================================== -// CTRL_REG1 - -#define LSM303_A_ODR_1HZ 0x10 -#define LSM303_A_ODR_10HZ 0x20 -#define LSM303_A_ODR_25HZ 0x30 -#define LSM303_A_ODR_50HZ 0x40 -#define LSM303_A_ODR_100HZ 0x50 -#define LSM303_A_ODR_200HZ 0x60 -#define LSM303_A_ODR_400HZ 0x70 -#define LSM303_A_ODR_1620HZ 0x80 -#define LSM303_A_ODR_1344Hz 0x90 - -#define LSM303_A_LOWPOWER_EN 0x08 -#define LSM303_A_X_EN 0x01 -#define LSM303_A_Y_EN 0x02 -#define LSM303_A_Z_EN 0x04 -#define LSM303_A_ALL_AXIS_EN 0x07 - - -//================================================================== -// CTRL_REG2 - HP-Filter config - -//================================================================== -// CTRL_REG3 - Int1 config - -#define LSM303_A_I1_CLICK 0x80 -#define LSM303_A_I1_AOI1 0x40 -#define LSM303_A_I1_AOI2 0x20 -#define LSM303_A_I1_DRDY1 0x10 -#define LSM303_A_I1_DRDY2 0x08 -#define LSM303_A_I1_WTM 0x04 -#define LSM303_A_I1_OVERRUN 0x02 - - -//================================================================== -// CTRL_REG4 - Sensitivity, Endianess and SPI config - -#define LSM303_A_FS_2G 0x00 // default -#define LSM303_A_FS_4G 0x10 -#define LSM303_A_FS_8G 0x20 -#define LSM303_A_FS_16G 0x30 - - - -//================================================================== -// CTRL_REG5 - Fifo and other - -#define LSM303_A_FIFO_EN 0x40 - -//================================================================== -// CTRL_REG6 - INT2 config - -//================================================================== -// FIFO_CTRL - -#define LSM303_A_FIFO_MODE_BYPASS 0b00000000 -#define LSM303_A_FIFO_MODE_FIFO 0b01000000 -#define LSM303_A_FIFO_MODE_STREAM 0b10000000 -#define LSM303_A_FIFO_MODE_TRIGGER 0b11000000 - -#define LSM303_A_FIFO_TR 0b00100000 - - -//================================================================== -//================================================================== -//================================================================== -// Magnetometer register -//================================================================== -//================================================================== -//================================================================== - -#define LSM303_REG_CRA_M 0x00 -#define LSM303_REG_CRB_M 0x01 -#define LSM303_REG_MR_M 0x02 -#define LSM303_REG_OUTX_H_M 0x03 -#define LSM303_REG_OUTX_L_M 0x04 -#define LSM303_REG_OUTY_H_M 0x05 -#define LSM303_REG_OUTY_L_M 0x06 -#define LSM303_REG_OUTZ_H_M 0x07 -#define LSM303_REG_OUTZ_L_M 0x08 -#define LSM303_REG_Mg_M 0x09 -#define LSM303_REG_IRA_M 0x0A -#define LSM303_REG_IRB_M 0x0B -#define LSM303_REG_IRC_M 0x0C -#define LSM303_REG_TEMP_H_M 0x31 -#define LSM303_REG_TEMP_L_M 0x32 - - -#endif - diff --git a/STM32F3/libraries/ringbuffer/ringbuffer.cpp b/STM32F3/libraries/ringbuffer/ringbuffer.cpp deleted file mode 100644 index 852b2de..0000000 --- a/STM32F3/libraries/ringbuffer/ringbuffer.cpp +++ /dev/null @@ -1,320 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2015 Frank-Michael Krause - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ -#include "ringbuffer.h" - -#ifdef WIN32 - -int tmcnt=10; - -unsigned long millis() { return tmcnt++; } -#define NULL 0 - -#else -#include -#endif - - -RingBuffer::RingBuffer(int _size, int *_values, unsigned long *_timeStamps) -{ - size = _size; // muss ZweierPotenz sein - values = _values; // Pointer auf Speicher für Werte - timeStamps = _timeStamps; // optional Pointer auf Speicher für ms timestamps - mask = 0; - int t = size/2; - while (t) - { - mask = (mask<<1)|1; - t = t/2; - } - reset(); -} - - -void RingBuffer::addValue(int value) -{ - values[wrIdx] = value; - - if (timeStamps != NULL) - timeStamps[wrIdx] = millis(); - - if (anz < size) - anz++; - - wrIdx++; - wrIdx &= mask; -} - - -void RingBuffer::reset() -{ - anz = 0; - wrIdx = 0; - rdIdx = 0; - - for (int i=0; i anz) - return 0; - - rdIdx = (wrIdx - distance) & mask; - - lastRead = 0; - - return 1; -} - - -/* - * Setzt rdIdx auf den ersten Wert, für den der zugehörige timeStamp mindestens zurückliegt, - * Es wird das Alter des betreffenden Wertes in ms zurückgegeben - * = wird zurückgegeben, wenn kein Wert mindestens so alt wie gefordert ist oder keine timestamps vorhanden sind - */ -int RingBuffer::setReadIdxDt(int ms) -{ - if (timeStamps == NULL) // keine timeStamps vorhanden - return 0; - - unsigned long aktTime = millis(); - unsigned long dt=0; - int count = 0; - rdIdx = (wrIdx - 1)&mask; // auf letzten eingetragenen Wert setzen - - lastRead = 0; - - while (count ms) - return dt; - count++; - - rdIdx = (rdIdx-1)&mask; - } - - return 0; -} - - -/* - * gibt Wert für rdIdx zurück und incrementiert rdIdx, solange rdIdx < (wrIdx-1) - * ACHTUNG: wird wrPtr erreicht, so wird immer wieder der letzte Wert zurückgegeben! - */ -int RingBuffer::getValue() -{ - int ret = values[rdIdx]; - - if (((rdIdx+1)&mask) == wrIdx) - lastRead = 1; - else - rdIdx = (rdIdx+1)&mask; - - return ret; -} - -/* - * gibt Wert für rdIdx zurück, trägt den zugehörigen timestamp - * in time ein und incrementiert rdIdx, solange rdIdx < wrIdx - * ACHTUNG: wird wrPtr erreicht, so wird immer wieder der letzte Wert zurückgegeben! - */ -int RingBuffer::getValue(unsigned long *time) -{ - int ret = values[rdIdx]; - if ((time != NULL) && (timeStamps!=NULL)) - *time = timeStamps[rdIdx]; - - if (((rdIdx+1)&mask) == wrIdx) - lastRead = 1; - else - rdIdx = (rdIdx+1)&mask; - - return ret; -} - - -/* - * gibt den Wert von rdIdx-1 zurück und decrementiert rdIdx wenn rdIdx-1 != wrIdx - * - */ -int RingBuffer::getPreviousValue() -{ - int idx = (rdIdx-1)&mask; - int ret = values[idx]; - if (idx != wrIdx) // rdIdx darf nicht kleiner als wrIdx werden - rdIdx = idx; - else - lastRead = 1; - return ret; -} - - -/* -`* decrementiert rdPtr und gibt den zugehörigen Wert zurück - */ -int RingBuffer::getPreviousValue(unsigned long *time) -{ - int idx = (rdIdx-1)&mask; - int ret = values[idx]; - rdIdx = (rdIdx-1)&mask; - if ((time != NULL) && (timeStamps!=NULL)) - *time = timeStamps[idx]; - if (idx != wrIdx) // rdIdx darf nicht kleiner als wrIdx werden - rdIdx = idx; - else - lastRead = 1; - return ret; -} - - -int RingBuffer::getPreviousValueDt(unsigned long *dt) -{ - int idx = (rdIdx-1)&mask; - int ret = values[idx]; - if ((dt != NULL) && (timeStamps!=NULL)) - { - unsigned long aktTime = millis(); - *dt = aktTime - timeStamps[idx]; - } - if (idx != wrIdx) // rdIdx darf nicht kleiner als wrIdx werden - rdIdx = idx; - else - lastRead = 1; - return ret; -} - - -/* - * gibt eins zurück, sobald der älteste Wert mit einer PreviousValue-Funktion - * gelesen wurde - * wird durch jeden Aufruf einer SetReadIdx-Funktion zurückgesetzt - */ -int RingBuffer::lastValueRead() -{ - return lastRead; -} - - -/* - * gibt 1 zurück, wenn rdPtr != wrPtr - * gibt 0 zurück, wenn rdPtr == wrPtr - * - * --> funktioniert nur, wenn zuvor SetReadIdx() aufgerufen wurde - */ -int RingBuffer::valueAvailable() -{ - return !lastRead; -} - - -int RingBuffer::getValueAt(int idx) -{ - return values[(wrIdx+idx)&mask]; -} - - -int RingBuffer::getValueAt(int idx, unsigned long *time) -{ - int valueIdx = (wrIdx+idx)&mask; - if ((time != NULL) && (timeStamps!=NULL)) - *time = timeStamps[valueIdx]; - return values[valueIdx]; -} - - -int RingBuffer::getPreviousValueAt(int idx) -{ - return values[(wrIdx-1-idx)&mask]; -} - - -int RingBuffer::getPreviousValueAt(int idx, unsigned long *time) -{ - int valueIdx = (wrIdx-1-idx)&mask; - if ((time != NULL) && (timeStamps!=NULL)) - *time = timeStamps[valueIdx]; - return values[valueIdx]; -} - -//***************************************************************** - - -RingBufferAverage::RingBufferAverage(int _size, int *_values, unsigned long *_timeStamps, int _averageSize):RingBuffer(_size, _values, _timeStamps) -{ - averageSize = _averageSize; - averageSum = 0; -} - -void RingBufferAverage::addValue(int val) -{ - RingBuffer::addValue(val); - averageSum += val; - if (anz > averageSize) - averageSum -= getPreviousValueAt(averageSize); -} - - -void RingBufferAverage::reset() -{ - RingBuffer::reset(); - averageSum = 0; -} - - -void RingBufferAverage::setAverageLen(int len) -{ - averageSize = len; - reset(); -} - -int RingBufferAverage::getAverage() -{ - if (anz>averageSize) - return averageSum/averageSize; - return averageSum/anz; -} - - -int RingBufferAverage::getAverageSum() -{ - return averageSum; -} - - diff --git a/STM32F3/libraries/ringbuffer/ringbuffer.h b/STM32F3/libraries/ringbuffer/ringbuffer.h deleted file mode 100644 index 3fce4c2..0000000 --- a/STM32F3/libraries/ringbuffer/ringbuffer.h +++ /dev/null @@ -1,155 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2015 Frank-Michael Krause - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -#ifndef RINGBUFFER_H_ -#define RINGBUFFER_H_ - -class RingBuffer { -public: - int size; // muss ZweierPotenz sein - int *values; // Pointer auf Speicher für Werte - unsigned long *timeStamps; // optional Pointer auf Speicher für ms timestamps - int rdIdx; // Leseindex - Benutzung optional - int wrIdx; // Schreibindex - int mask; - - int anz; // Aktuelle Anzahl an Werten im Puffer - int lastRead; // wird auf eins gesetz, wenn letzter vorhandener Wert gelesen wurde - - - RingBuffer(int _size, int *_values, unsigned long *_timeStamps); - - /* - * fügt einen Wert zum Ringpuffer hinzu und erzeugt einen zugehörigen Timestamp - * wenn timeStamps != NULL ist - */ - void addValue(int val); - - /* - * setzt rdIdx auf distance Werte vor den letzten Wert (wrPtr-1) - * Mit getValue können die letzten Werte bis zum letzten wert abgefragt werden - * - * gibt 1 zurück, wenn genügend Werte im Puffer sind - * gibt 0 zurück, wenn noch nicht genügend Werte im Puffer sind oder distance - * größer als die Pufferlänge ist - */ - int setReadIdx(int distance); - - /* - * Setzt rdIdx auf den ersten Wert, für den der zugehörige timeStamp mindestens zurückliegt, - * Es wird das Alter des betreffenden Wertes in ms zurückgegeben - * = wird zurückgegeben, wenn kein Wert mindestens so alt wie gefordert ist oder keine timestamps vorhanden sind - */ - int setReadIdxDt(int ms); - - /* - * gibt Wert für rdIdx zurück und incrementiert rdIdx, solange rdIdx < wrIdx - * ACHTUNG: wird wrPtr erreicht, so wird immer wieder der letzte Wert zurückgegeben! - */ - int getValue(); - - /* - * gibt Wert für rdIdx zurück, trägt den zugehörigen timestamp - * in time ein und incrementiert rdIdx, solange rdIdx < wrIdx - * ACHTUNG: wird wrPtr erreicht, so wird immer wieder der letzte Wert zurückgegeben! - */ - int getValue(unsigned long *time); - - /* - * gibt 1 zurück, wenn rdPtr != wrPtr - * gibt 0 zurück, wenn rdPtr == wrPtr - * - * --> funktioniert nur, wenn zuvor SetReadIdx() aufgerufen wurde - */ - int valueAvailable(); - - /* - * Setzt den Ringbuffer zurück - */ - void reset(); - - /* - `* decrementiert rdPtr und gibt den zugehörigen Wert zurück - */ - int getPreviousValue(); - int getPreviousValue(unsigned long *time); - - /* - `* decrementiert rdPtr und gibt den zugehörigen Wert zurück - * schreibt Zeiitdifferenz zur aktuellen Zeit in dt - */ - int getPreviousValueDt(unsigned long *dt); - - - /* - * gibt eins zurück, sobald der älteste Wert mit einer PreviousValue-Funktion - * gelesen wurde - * wird durch jeden Aufruf einer SetReadIdx-Funktion zurückgesetzt - */ - int lastValueRead(); - - /* - * Diese Funktion erlaubt den Zugriff auf den Ringbuffer wie auf ein Array. - * Der älteste Wert hat immer den Index 0, der aktuellste Wert den Index size-1 - * Der rdIdx des Puffers wird nicht verändert. - */ - int getValueAt(int idx); - int getValueAt(int idx, unsigned long *time); - - /* - * Diese Funktion erlaubt den Zugriff auf den Ringbuffer wie auf ein Array. - * Der neueste Wert hat immer den Index 0, der älteste Wert den Index size-1 - * Der rdIdx des Puffers wird nicht verändert. - */ - int getPreviousValueAt(int idx); - int getPreviousValueAt(int idx, unsigned long *time); - - -}; - - - -class RingBufferAverage : public RingBuffer -{ -public: - int averageSize; - int averageSum; - - RingBufferAverage(int _size, int *_values, unsigned long *_timeStamps, int _averageSize); - - void setAverageLen(int len); - - void addValue(int val); - void reset(); - - int getAverage(); - int getAverageSum(); - - -}; - - -#endif /* RINGBUFFER_H_ */ diff --git a/STM32F3/libraries/roboter/debug.cpp b/STM32F3/libraries/roboter/debug.cpp deleted file mode 100644 index fa0a3e7..0000000 --- a/STM32F3/libraries/roboter/debug.cpp +++ /dev/null @@ -1,196 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2015 Frank-Michael Krause - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ -#include -#include "debug.h" - -#define DEBUG - -#ifndef DEBUGPORTID -#define DEBUGPORTID 2 -// TX-PIN ist PA2 -#endif - -#ifndef DEBUGPORT -#if DEBUGPORTID == 0 - #define DEBUGPORT SerialUSB -#endif -#if DEBUGPORTID == 1 - #define DEBUGPORT Serial1 -#endif -#if DEBUGPORTID == 2 - #define DEBUGPORT Serial2 -#endif -#if DEBUGPORTID == 3 - #define DEBUGPORT Serial3 -#endif -#endif - - -void debugInit() -{ -#ifdef DEBUG -#if (DEBUGPORTID != 0) - DEBUGPORT.begin(57600); -#endif - DEBUGPORT.println("Debug Init"); -#endif -} - - -static int printTimeStamp = 0; - -void debugSetTimeStamp(int OnOff) { - printTimeStamp = OnOff; -} - -static inline void addTimeStamp() { - if (printTimeStamp) { - DEBUGPORT.print(millis()); - DEBUGPORT.print(" "); - } -} - -void debugPrint(const char *s) -{ -#ifdef DEBUG - addTimeStamp(); - DEBUGPORT.println(s); -#endif -} - -void PrintNumber(const char *name, int num) -{ -#ifdef DEBUG - addTimeStamp(); - DEBUGPORT.print(name); - DEBUGPORT.print(" "); - DEBUGPORT.println(num); -#endif -} - -void PrintNumber(const char *name, byte num) -{ -#ifdef DEBUG - addTimeStamp(); - DEBUGPORT.print(name); - DEBUGPORT.print(" "); - DEBUGPORT.println(num); -#endif -} - -void PrintNumber(const char *name, float num) -{ -#ifdef DEBUG - addTimeStamp(); - DEBUGPORT.print(name); - DEBUGPORT.print(" "); - DEBUGPORT.println(num); -#endif -} - - - -void Print2Number(const char *name, int num1, int num2) -{ -#ifdef DEBUG - addTimeStamp(); - DEBUGPORT.print(name); - DEBUGPORT.print(" "); - DEBUGPORT.print(num1); - DEBUGPORT.print("\t"); - DEBUGPORT.println(num2); -#endif -} - -void Print2Number(const char *name, byte num1, byte num2) -{ -#ifdef DEBUG - addTimeStamp(); - DEBUGPORT.print(name); - DEBUGPORT.print(" "); - DEBUGPORT.print(num1); - DEBUGPORT.print("\t"); - DEBUGPORT.println(num2); -#endif -} - -void Print2Number(const char *name, float num1, float num2) -{ -#ifdef DEBUG - addTimeStamp(); - DEBUGPORT.print(name); - DEBUGPORT.print(" "); - DEBUGPORT.print(num1); - DEBUGPORT.print("\t"); - DEBUGPORT.println(num2); -#endif -} - -void PrintArray(const char *name, int len, int *arr) -{ -#ifdef DEBUG - int i; - addTimeStamp(); - DEBUGPORT.print(name); - for (i=0; i -#include -#include -#include "eeprom.h" -#include "debug.h" - - -/* - Source Code fuer 24C128 EEPROM (16Kbyte) -* - __ __ - A0 -| |- VCC - A1 -| |- WP --> unconnected low: write enabled - A2 -| |- SCL - VSS -|_____|- SDA - - -*/ - -#define EEPROM_I2C_BASE_ADDR (0xA0>>1) -#define EEPROM_I2C_ADDR(mem_addr) EEPROM_I2C_BASE_ADDR -#define EEPROM_I2C_CHANNEL I2C1 - -#define EEPROM_MAX_BUF 3 - -static uint8 msg_wr_data[EEPROM_MAX_BUF]; -static i2c_msg msg[2]; -static uint8 msg_rd_data[EEPROM_MAX_BUF]; - - -static void writeDataByte(int device_address, byte memory_address, byte data) -// write one byte of data 'data' to eeprom memory address 'memory_address' to chip with I2C address 'device_address' -{ -/* Arduino Code - Wire.beginTransmission(device_address); // device address - Wire.write(memory_address ); // memory address - Wire.write(data); // data to send - Wire.endTransmission(); // end - delay(10); -*/ - msg[0].addr = device_address; - msg[0].flags = 0; // write, 7 bit address - msg[0].xferred = 0; - msg[0].length = 3; - msg[0].data = msg_wr_data; - - msg_wr_data[0] = (memory_address>>8)&0xFF; - msg_wr_data[1] = memory_address&0xFF; - msg_wr_data[2] = data; - - i2c_master_xfer(EEPROM_I2C_CHANNEL, msg, 1, 10); - - delay(10); -} - - -static byte readDataByte(int device_address, byte memory_address) -// reads one byte of data from memory location 'memory_address' in chip at I2C address 'device_address' -{ - -/* Arduino Code - byte result; // return value - Wire.beginTransmission(device_address); // device address - Wire.write(memory_address); // memory address - Wire.endTransmission(); // end - Wire.requestFrom(device_address,1); // get one byte of data from device - if (Wire.available()) - result = Wire.read(); - return result; // return the read data byte - delay(10); -*/ - msg[0].addr = device_address; - msg[0].flags = 0; // write, 7 bit address - msg[0].xferred = 0; - msg[0].length = 2; - msg[0].data = msg_wr_data; - - msg_wr_data[0] = (memory_address>>8)&0xFF; - msg_wr_data[1] = memory_address&0xFF; - - msg[1].addr = device_address; - msg[1].flags = I2C_MSG_READ; - msg[1].xferred = 0; - msg[1].length = 1; - msg[1].data = msg_rd_data; - - i2c_master_xfer(EEPROM_I2C_CHANNEL, msg, 2, 10); - return msg_rd_data[0]; -} - -//--------------------------------------------------------------------------------- -int eepromWriteBytes(int addr, int len, unsigned char *pData) -{ - for (int i = 0; i -#include "functiontimer.h" -#include "debug.h" - - -//#define TMR_DEBUG - -typedef void (*tmrFuncPtr)(int arg); - - -typedef struct timerDaten { - struct timerDaten *pNext; - struct timerDaten *pPrev; - int time; - int state; - int arg; - int id; - tmrFuncPtr handler; -}TimerData_t; - - -TimerData_t timerArray[TIMER_ANZAHL]; -TimerData_t *pNextTimer = NULL; - - - -#define TIMEOUT_RATE 5000 // in microseconds - -HardwareTimer timer(2); - - -static void timeoutHandler() { - if (pNextTimer) { - pNextTimer->time -= 5; - if (pNextTimer->time <= 0) { -#ifdef TMR_DEBUG - PrintNumber("to", pNextTimer->id); -#endif - TimerData_t *p = pNextTimer; - pNextTimer = pNextTimer->pNext; - if (pNextTimer) - pNextTimer->pPrev = NULL; - p->state = 0; - //p->pNext = NULL; - //p->pPrev = NULL; - p->handler(p->arg); - } - } -} - -static bool timerInitialized = false; - -void timerInit() { - if (timerInitialized == false) { - for (int i=0; i= TIMER_ANZAHL) - return; - if (timerArray[id].state) // is already running? - return; - - TimerData_t *pNew = timerArray + id; - pNew->time = ms+5; - pNew->state = 1; - pNew->handler = handler; - pNew->pNext = NULL; - pNew->pPrev = NULL; - pNew->arg = arg; - if (pNextTimer == NULL) { - pNextTimer = pNew; -#ifdef TMR_DEBUG - PrintNumber("st", id); -#endif - } - else { -#ifdef TMR_DEBUG - Print2Number("sta", id, ms); -#endif - noInterrupts(); - TimerData_t *p = pNextTimer; - TimerData_t *last = NULL; - while (p) { - if (pNew->time < p->time) // vorher einhaengen - break; - else - pNew->time -= p->time; - last = p; - p = p->pNext; - } - - if (p==NULL) { - // hinter Last mit Restzeit einhängen - last->pNext = pNew; - pNew->pPrev = last; -#ifdef TMR_DEBUG - debugPrint("at end"); -#endif - } - else { // vor p einhängen und p->time um pNew->time verkleinern - p->time -= pNew->time; - pNew->pNext = p; - - if (p==pNextTimer) { - pNextTimer = pNew; - p->pPrev = pNew; -#ifdef TMR_DEBUG - PrintNumber("at begin", p->id); -#endif - } - else { - pNew->pPrev = p->pPrev; - p->pPrev = pNew; - if (pNew->pPrev) - pNew->pPrev->pNext = pNew; -#ifdef TMR_DEBUG - Print2Number("between", pNew->pPrev->id, pNew->pNext->id); -#endif - } - } - interrupts(); - } -#ifdef TMR_DEBUG - PrintTimerList(); -#endif -} - - -void timerStop(int id) { - if (id < 0) - return; - if (id>= TIMER_ANZAHL) - return; - if (timerArray[id].state==0) // is timer running? - return; - - TimerData_t *pTimer = timerArray + id; - noInterrupts(); - if (pTimer->pNext == NULL) { - // ist letzter in der queue - if (pTimer->pPrev == NULL) { - // ist einziger Timer - pTimer->state = 0; - pNextTimer = NULL; - } - else { - pTimer->pPrev->pNext = NULL; - pTimer->pPrev = NULL; - pTimer->state = 0; - } - } - else { - // Restzeit des zu löschenden Timers auf den nächsten in der Queue addieren - pTimer->pNext->time += pTimer->time; - if (pTimer == pNextTimer) {// erster Timer in der queue - pNextTimer = pTimer->pNext; - pTimer->pNext->pPrev = NULL; - pTimer->pNext = NULL; - } - else { - TimerData_t *pPrev = pTimer->pPrev; - pPrev->pNext = pTimer->pNext; - pTimer->pNext->pPrev = pPrev; - pTimer->pNext = NULL; - pTimer->pPrev = NULL; - } - } - interrupts(); - -} - - -void PrintTimerList() { - TimerData_t *p = pNextTimer; - - while (p) { - Print2Number("tmr",p->id, p->time); - if (p->pNext) - PrintNumber(" nxt", p->pNext->id); - if (p->pPrev) - PrintNumber(" prv", p->pPrev->id); - p = p->pNext; - } -} diff --git a/STM32F3/libraries/roboter/functiontimer.h b/STM32F3/libraries/roboter/functiontimer.h deleted file mode 100644 index 1a31f88..0000000 --- a/STM32F3/libraries/roboter/functiontimer.h +++ /dev/null @@ -1,51 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2015 Frank-Michael Krause - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - /* - * Das Timer-Modul stellt Funktionen bereit, mit denen andere Funktionen - * später aufgerufen werden können. Diese Funktionen sollten eine - * kurze Laufzeit haben, da sie im Interrupt aufgerufen werden. - * - * - Die Timer arbeiten mit einer Auflösung von 5 ms. - * - Es können maximal 10 Timer gleichzeitig aktiv sein. - * - Stoppen eines Timers ist möglich - * - */ - -#ifndef FUNCTION_TIMER_H_ -#define FUNCTION_TIMER_H_ - -#define TIMER_ANZAHL 10 - -typedef void (*tmrFuncPtr)(int arg); - -extern void timerInit(); -extern void timerStart(int id, int ms, tmrFuncPtr handler, int arg); -extern void timerStop(int id); - - - - -#endif /* TIMER_H_ */ diff --git a/STM32F3/libraries/roboter/motor.cpp b/STM32F3/libraries/roboter/motor.cpp deleted file mode 100644 index 57b6171..0000000 --- a/STM32F3/libraries/roboter/motor.cpp +++ /dev/null @@ -1,259 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2015 Frank-Michael Krause - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ -#include -#include "motor.h" -#include "../gyro/gyro.h" -#include "debug.h" - - -#define TB6612 - -#define MOTOR_ANZ 3 - - -typedef struct { - int dir; - int pwm; - int sensor; - int led; -} MotorPins_t; - -static MotorPins_t mpins[MOTOR_ANZ]; - -#define IDX_A 0 -#define IDX_B 1 -#define IDX_C 2 - -// Umwandlung MotorIds to Index, wenn nur ein Motor addressiert ist -#define MIDX(id) ((id&OUT_A)?IDX_A:(id&OUT_B)?IDX_B:IDX_C) - - -static volatile int RadCount0; -void CountRad0() -{ - RadCount0++; -} - -static volatile int RadCount1; -void CountRad1() -{ - RadCount1++; -} - -static volatile int RadCount2; -void CountRad2() -{ - RadCount2++; -} - - -void InitMotor(int id, int PinDir, int PinPWM, int PinSensor, int PinLED) -{ - MotorPins_t *p = mpins+MIDX(id); - p->dir = PinDir; - p->pwm = PinPWM; - p->sensor = PinSensor; - p->led = PinLED; - - pinMode (p->pwm, PWM); - pinMode (p->dir, OUTPUT); - analogWrite(p->pwm, 0); - - if (p->sensor != -1) - { - if (p->led != -1) - pinMode(p->led, OUTPUT); - - pinMode(p->sensor, INPUT); - } -} - - -static inline void RadSensorAn(int motor) -{ - MotorPins_t *p = mpins; - - for (int idx=0; idxled != -1) - digitalWrite(p->led, HIGH); - if (p->sensor != -1) { - if (idx == 0) - attachInterrupt(p->sensor, CountRad0, CHANGE); - else if (idx == 1) - attachInterrupt(p->sensor, CountRad1, CHANGE); - else - attachInterrupt(p->sensor, CountRad2, CHANGE); - } - } - p++; - } - delayMicroseconds(50); // Damit ggf. ein Interrupt beim Einschalten ausgeführt wird -} - - -static inline void RadSensoren(int motor) -{ - MotorPins_t *p = mpins; - - for (int idx=0; idxled != -1) - digitalWrite(p->led, LOW); - if (p->sensor != -1) { - detachInterrupt(p->sensor); - } - } - p++; - } -} - - -void OnFwd(int Motor, int Geschwindigkeit) -{ - if(Geschwindigkeit>0) - Geschwindigkeit+=13; - else if(Geschwindigkeit<0) - Geschwindigkeit-=13; - - MotorPins_t *p = mpins; - Geschwindigkeit = constrain(Geschwindigkeit,-100, 100); // Geschwindigkeit auf Bereich -100 ... +100 begrenzen - Geschwindigkeit = (65535*Geschwindigkeit)/100; - PrintNumber("v ",Geschwindigkeit ); - - for (int i=0; i0) - { - digitalWrite(p->dir, HIGH); - v = Geschwindigkeit; - } - else - { - digitalWrite(p->dir, LOW); - v = -Geschwindigkeit; - } - analogWrite(p->pwm, v); - #endif - } - p++; - } -} - - -void OnRev(int m, int v) -{ - OnFwd(m, -v); -} - -void Off(int Motor) -{ - MotorPins_t *p = mpins; - for (int i=0; ipwm, 0); -#endif - } - p++; - } -} - - - -#if 0 - -// gyro-Funktionen nicht in diesem Modul - -void DreheRechts(int v, int Winkel) -{ - gyroResetWinkel(); - OnFwd(OUT_A, v); - OnFwd(OUT_B, -v); - while (winkelz>=-Winkel) - gyroUpdate(); - Off (OUT_AB); - -} - - -void DreheLinks(int v, int Winkel) -{ - gyroResetWinkel(); - OnFwd(OUT_A, -v); - OnFwd(OUT_B, v); - while (winkelz<=Winkel) - gyroUpdate(); - Off (OUT_AB); - -} - - -void FahreVor(int v, int Strecke) -{ - RadSensorenAn(); - RadCountR = 0; // 0 Setzen erst NACH Einschalten des Sensors, eventuell kommt schon ein Interrupt -// RadCountL = 0; - OnFwd(OUT_AB, v); - while (Strecke>RadCountR) - { -// PrintNumber("RC", RadCountR); -// delay (1); - } - Off(OUT_AB); - RadSensorenAus(); -} - -#endif - - -#if 0 -void TestRadSensoren() -{ - RadSensorenAn(); - RadCountR = 0; - RadCountL = 0; - OnFwd(OUT_AB,10); - while(1) - { - lcd.clear(); - lcd.setCursor(0,0); - lcd.print(RadCountL); - lcd.setCursor(4,0); - lcd.print(RadCountR); - delay(300); - } -} - -#endif diff --git a/STM32F3/libraries/roboter/motor.h b/STM32F3/libraries/roboter/motor.h deleted file mode 100644 index c63470e..0000000 --- a/STM32F3/libraries/roboter/motor.h +++ /dev/null @@ -1,58 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2015 Frank-Michael Krause - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - /* - * Das Modul Motor stellt Funktionen und Makros zur Steuerung der - * Fahrmotoren zur verfügung sowie Funktionen zur Steuerung und - * Abfrage der Wegsensoren. - */ - -#ifndef MOTOR_H_ -#define MOTOR_H_ - -#define OUT_A 1 -#define OUT_B 2 -#define OUT_C 4 -#define OUT_AB (OUT_A|OUT_B) -#define OUT_BC (OUT_B|OUT_C) -#define OUT_AC (OUT_A|OUT_C) -#define OUT_ABC (OUT_A|OUT_B|OUT_C) - - -extern void InitMotor(int id, int PinDir, int PinPWM, int PinSensor, int PinLED); - -extern void OnFwd(int Motor, int Geschwindigkeit); -extern void OnRev(int Motor, int Geschwindigkeit); -extern void Off (int Motor); - -#if 0 -extern void DreheRechts(int v, int Winkel); -extern void DreheLinks(int v, int Winkel); - -extern void FahreVor(int v, int Strecke); -#endif - - -#endif /* MOTOR_H_ */ diff --git a/STM32F3/libraries/roboter/sound.cpp b/STM32F3/libraries/roboter/sound.cpp deleted file mode 100644 index 09ca894..0000000 --- a/STM32F3/libraries/roboter/sound.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2015 Frank-Michael Krause - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ -#include -#include "sound.h" - - -/* todo */ \ No newline at end of file diff --git a/STM32F3/libraries/roboter/sound.h b/STM32F3/libraries/roboter/sound.h deleted file mode 100644 index 54c5723..0000000 --- a/STM32F3/libraries/roboter/sound.h +++ /dev/null @@ -1,33 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2015 Frank-Michael Krause - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -#ifndef SOUND_H_ -#define SOUND_H_ - - - - -#endif /* SOUND_H_ */ diff --git a/STM32F3/libraries/roboter/ultraschall.cpp b/STM32F3/libraries/roboter/ultraschall.cpp deleted file mode 100644 index 871c6ac..0000000 --- a/STM32F3/libraries/roboter/ultraschall.cpp +++ /dev/null @@ -1,536 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2015 Frank-Michael Krause - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ -#include -#include "ultraschall.h" -#include "debug.h" - -/* - * Für jeden Ultraschallsensor gibt es eine Struktur USSensor, die im Array USSensoren - * angelegt wird. - * Für jeden Sensor muss einmal die Funktion addUSSensor() mit den richtigen Anschluss - * Pins aufgerufen werden. - * - * Zum Messen muss ein Sensor aktiviert werden. Es können alle Sensoren aktiv sein. - * Sie werden dann abwechselnd für Messungen getriggert. Nicht mehr benötigte Sensoren - * sollten deaktiviert werden. - * Im aktiven Zustand wird durch die Funktion UltraschallMessen() die Messung - * jeweils eines aktiven Sensors gestartet, wenn keine Messung aktiv ist. - * UltraschallMessen() koordiniert nur die Messungen (es darf immer nur ein - * Ultraschallsensor aktiv sein) und wartet nicht, bis die Messung erfolgt ist. - * UltraschallMessen sollte alle 25ms oder kürzer aufgerufen werden, - * wenn Ultraschallmesswerte benötigt werden. - * --> ggf. Aktivieren der nächsten Messung im Interrupt? --> testen - * - * Das Messen selbst erfolgt asynchron zur Programmausführung. Eine spezielle - * Messroutine wird aufgerufen, wenn der Echo-Pin des Sensors seinen Zustand ändert. - * Diese Routine trägt die gemessene Entfernung und einen Zeitstempel in die Sensor- - * struktur ein und setzt ein Flag in der Struktur, dass ein neuer Messwert zur - * Verfügung steht. - * - * Mit der Funktion UltraschallMessenFertig(id) kann abgefragt werden, ob ein neuer - * Messwert vorliegt. Dieser kann mit UltraschallMesswert(id) abgefragt werden. - * Mit UltraschallMesswertAlter(id) kann abgefragt werden, wie alt der ausgelesene - * Messwert ist. Alternativ zu den Funktionsaufrufen können die Werte auch direkt aus - * den Sensorstrukturen ausgelesen werden. - * - * Alternativ zum automatischen Messen im Hintergrund kann statt UltraschallMessen() - * die Funktion UltraschallMessenEinzel(id) aufgerufen werden. Diese Funktion blockiert - * solange bis ein Messwert vorliegt (max. 50ms falls kein Wert ermittelt werden kann) - * und gibt diesen zurück. Eine Aktivierung des Sensors ist nicht erforderlich. - * Eventuell laufende Messungen werden abgebrochen. Eine noch laufende Messung wird - * jedoch zu Ende geführt. - * - * Zeitüberwachung: - * Es kann eine maximale Laufzeit für das zu erwartende Echo gesetzt werden (z.B. 30ms). - * Für diese Laufzeit wird ein Timer mit eigenem Interrupt gestartet. - * Gestoppt wird der Timer, wenn die Echo-Interrupt-Funktion vor Ablauf des Timers ausgeführt wird - * (der Echo-Puls ist in diesem Fall innerhalb des zulässigen Zeitfensters gekommen. - * Läuft der Timer ab, ist die aktuelle Messung ungültig und es wird versucht eine neue Messung - * mit dem nächsten Sensor zu starten. - * Eine Messung kann nur gestartet werden, wenn der Echo-Pin auf LOW ist. - * Gibt es keinen Sensor, der bei Startanforderung echo==LOW hat, so wird nichts unternommen und - * auf die nächste fallende Flanke einer Echo-Leitung (Interrupt) gewartet. Die fallende Flanke startet - * dann eine neue Messung per Interrupt. - * Gibt es einen Sensor, der bereit für eine neue Messung ist, so wird bei diesem die Messung - * gestartet. - * Damit das funktioniert, muss für jeden Echo-Pin eine eigene Interrupt-Funktion attached werden. - * - * Wenn auf die Zeitüberwachung verzeichtet wird blockiert eine ungültige Messung weitere Messungen - * anderer Sensoren um die Zeit bis zum HIGH-LOW-Übergang des Echopins - * --> bei nur einem Sensor ist eine Zeitüberwachung nicht nötig, da kein Neustart einer Messung - * stattfinden kann bevor der Echo-Pin wieder Low ist. - * - * HC-SR04: Wenn kein Echo kommt, wird das ECHO-Signal nach ca. 235ms (entspricht ca. 4m) wieder nach - * LOW gezogen. - * - * Um das Suchen nach einem messbereiten Sensor zu vereinfachen werden die aktiven Sensorstrukturen in einer - * doppelt verketteten Liste verwaltet. - * - * Der Aufruf von micros() im Interrupt funktioniert nicht sicher, deshalb muss die Timing-Information auf anderm Wege - * beschafft werden: - * Eigener Hardwaretimer für Ultraschallsensoren (ist auch schneller bei der Vewaltung) - * - */ - - -#define IDLE_CHECK_TMO 25 // ms - -// global state -#define US_GLOBAL_IDLE 0 -#define US_GLOBAL_MESSUNG_AKTIV 1 - -static int state = US_GLOBAL_IDLE; - -// Prototypen -static void TimerIntRangeTimeout(); -static void TimerIntWaitIdle(); -static inline void startMessung(); -static void USInt(); - -// globale Variablen -USSensor USSensoren[MAX_US_SENSOR]; - -// static Variablen -static USSensor *pAktiverSensor = NULL; -static int SensorAktivAnzahl=0; -static int MessPause = 0; - - -//-------------------------------------------------------------------------- -// Timer-Funktionen -//-------------------------------------------------------------------------- - -static HardwareTimer usTimer(15); -static int usTimerCount; // Beim Starten wird sofort ein Interrupt ausgelöst, - // der ausgeblendet werden muss - - -static void startUsTimer(int ms, voidFuncPtr handler) -{ - usTimer.pause(); - - // Set up period - usTimer.setPeriod(ms*1000); // in microseconds - - usTimerCount = 1; - - // Set up an interrupt on channel 1S - usTimer.setChannel1Mode(TIMER_OUTPUT_COMPARE); - usTimer.setCompare(TIMER_CH1, 1); // Interrupt 1 count after each update - usTimer.attachCompare1Interrupt(handler); - - // Refresh the timer's count, prescale, and overflow - usTimer.refresh(); - - // Start the timer counting - usTimer.resume(); -} - - -static void stopUsTimer() { - usTimer.pause(); -} - -//-------------------------------------------------------------------------- - - - -/** - * Startet die Messung beim nächsten IDLE-Sensor. - * Wenn keine Messung aktiv ist (US_GLOBAL_IDLE) und kein Sensor gefunden wird, - * wird der IDLE-Wait-Timer gestartet - */ -static inline void startMessung() -{ - if (state != US_GLOBAL_IDLE) - return; // Es kann keine Messung gestartet werden - - int anz = SensorAktivAnzahl; - - while (anz) { - pAktiverSensor = pAktiverSensor->pNext; // erstmal auf den nächsten Sensor stellen - if (pAktiverSensor->state==US_IDLE) - { - //PrintNumber(" nis", pAktiverSensor->id); - // nur wenn EchoPin Low ist, kann die nächste Messung erfolgen - if (digitalRead(pAktiverSensor->echoPin) == LOW) { - state = US_GLOBAL_MESSUNG_AKTIV; // globalen Zustand setzen - pAktiverSensor->state = US_ACTIVE; - //PrintNumber("sel", pAktiverSensor->id); - digitalWrite(pAktiverSensor->triggerPin, HIGH); - delayMicroseconds(10); // FIXME: funktioniert das im Interrupt ??? - // sollte gehen, ist eine Assemblerschleife - // muss aber mal gemessen werden!! - digitalWrite(pAktiverSensor->triggerPin, LOW); - attachInterrupt(pAktiverSensor->echoPin, USInt, CHANGE); - return; - } - //else - //PrintNumber("ns2", pAktiverSensor->id); - } - //else - // PrintNumber("ns1", pAktiverSensor->id); - - anz--; - } - startUsTimer(IDLE_CHECK_TMO, TimerIntWaitIdle); -} - -// Interrupt-Routinen - -/** - * Interrupt-Routine für Echo-Pin - */ -static void USInt() -{ - int time = usTimer.getCount(); - int pin = digitalRead(pAktiverSensor->echoPin); - if (pin==HIGH) - { - if (pAktiverSensor->state == US_ACTIVE) { - startUsTimer(pAktiverSensor->maxTime, TimerIntRangeTimeout); - //PrintNumber(" eh",pSensor->id); - } - } - else - { - stopUsTimer(); - detachInterrupt(pAktiverSensor->echoPin); - pAktiverSensor->entfernung = time/pAktiverSensor->timerTicksPerCm; - //Print2Number("usi", pAktiverSensor->id, pAktiverSensor->entfernung); - pAktiverSensor->messZeit = millis(); - pAktiverSensor->lastValidRange = pAktiverSensor->entfernung; - pAktiverSensor->lastValidTime = pAktiverSensor->messZeit; - pAktiverSensor->neuerMesswert = 1; - pAktiverSensor->state = US_IDLE; - state = US_GLOBAL_IDLE; - if (pAktiverSensor->handler) - pAktiverSensor->handler(pAktiverSensor->id, pAktiverSensor->entfernung); - if (MessPause) - startUsTimer(MessPause, TimerIntWaitIdle); - else - startMessung(); - } -} - -static void TimerIntWaitIdle() { - if (usTimerCount) - usTimerCount--; - else { - //debugPrint("twi"); - stopUsTimer(); - startMessung(); - } -} - -static void TimerIntRangeTimeout() { - if (usTimerCount) - usTimerCount--; - else { - stopUsTimer(); - if (pAktiverSensor) { - detachInterrupt(pAktiverSensor->echoPin); - //debugPrint(" tmo"); - if (pAktiverSensor->state == US_ACTIVE) { - pAktiverSensor->state = US_IDLE; - state = US_GLOBAL_IDLE; // Es kann eine Messung mit einem anderen Sensor gestartet werden - pAktiverSensor->entfernung = ENTFERNUNG_INVALID; - pAktiverSensor->messZeit = millis(); - if (pAktiverSensor->handler) - pAktiverSensor->handler(pAktiverSensor->id, pAktiverSensor->entfernung); - startMessung(); - } - else - { - if (state == US_GLOBAL_IDLE) - startMessung(); - } - } - } -} - - -//----------------------------------------------------------------- -// extern aufrufbare Funktionen -//----------------------------------------------------------------- - -/** - * Definiert und initialisiert einen Ultraschallsensor - * maxRange in cm - */ -void addUSSensor(int id, int trigger, int echo, int maxRange) -{ - if ((id < 0) || (id >= MAX_US_SENSOR)) - return; - USSensor *pSensor = &USSensoren[id]; - pSensor->triggerPin = trigger; - pSensor->echoPin = echo; - pSensor->enabled = 0; - pSensor->state = US_IDLE; - pSensor->id = id; - pSensor->maxTime = (maxRange*US_ROUNDTRIP_CM)/1000; - - // Timer-Wertebereich für maxRange ermitteln - usTimer.setPeriod(pSensor->maxTime*1000); // in microseconds - pSensor->timerTicksPerCm = usTimer.getOverflow()/maxRange; - - // pins initialisieren - pinMode(trigger, OUTPUT); - pinMode(echo, INPUT); -} - -/** - * aktiviert einen Sensor zum Messen im Hintergrund - */ -void aktiviereUSSensor(int id) -{ - if (USSensoren[id].enabled) // ist bereits enabled - return; - - USSensoren[id].enabled = 1; - - if (pAktiverSensor == NULL) { // ist der erste Sensor - pAktiverSensor = USSensoren + id; - pAktiverSensor->pNext = pAktiverSensor; // zeigt auf sich selbst! - pAktiverSensor->pPrev = pAktiverSensor; - SensorAktivAnzahl = 1; - // Über den Timer wird erreicht, dass die Messung gestartet wird. - startUsTimer(IDLE_CHECK_TMO, TimerIntWaitIdle); - } - else { - noInterrupts(); - USSensor *pSensor = USSensoren + id; - pSensor->state = US_IDLE; - - pSensor->pNext = pAktiverSensor->pNext; - pSensor->pPrev = pAktiverSensor; - pAktiverSensor->pNext->pPrev = pSensor; - pAktiverSensor->pNext = pSensor; - - SensorAktivAnzahl++; - interrupts(); - } -} - - -void UsAttachHandler(int id, usFuncPtr fkt){ - USSensoren[id].handler = fkt; -} - - -void UsSetMessPause(int ms) { - MessPause = ms; -} - - -/** - * deaktiviert einen Sensor - */ -void deaktiviereUSSensor(int id) -{ - /* - * Problem: - * für den aktuellen Sensor könnte aktuell eine Messung laufen! - */ - if (!USSensoren[id].enabled) - return; - - noInterrupts(); - USSensor *pSensor = USSensoren + id; - pSensor->enabled = 0; - pSensor->neuerMesswert = 0; - - if (SensorAktivAnzahl>1) { - pSensor->pPrev->pNext = pSensor->pNext; - pSensor->pNext->pPrev = pSensor->pPrev; - if (pAktiverSensor == pSensor) - pAktiverSensor = pSensor->pNext; - } - else - pAktiverSensor = NULL; - - SensorAktivAnzahl--; - - if (pSensor->state == US_ACTIVE) { - detachInterrupt(pSensor->echoPin); - pSensor->state = US_IDLE; - state = US_GLOBAL_IDLE; - - if (SensorAktivAnzahl) - // Über den Timer wird erreicht, dass eine neue Messung gestartet wird. - startUsTimer(IDLE_CHECK_TMO, TimerIntWaitIdle); - } - interrupts(); -} - -/** - * gibt 1 zurück, wenn ein neuer Messwert vorliegt. - * Es wird nur einmal eine 1 zurückgegeben, das Flag wird beim Auslesen zurückgesetzt - */ -int UltraschallMessenFertig(int id) -{ - if (USSensoren[id].neuerMesswert) - { - USSensoren[id].neuerMesswert = 0; - return 1; - } - return 0; -} - - -/** - * gibt aktuellstes Messergebnis zurück - */ -int16 UsAktuellerMesswert(int id) -{ - return USSensoren[id].entfernung; -} - -/** - * Gibt das Alter der aktuellsten Messung in ms zurück - */ -int UsAktuellerMesswertAlter(int id) -{ - return (millis() - USSensoren[id].messZeit); -} - -/** - * gibt den letzten gueltigen Wert zurück - */ -int16 UsLetzterGueltigerMesswert(int id) -{ - return USSensoren[id].lastValidRange; -} - -/** - * Gibt das Alter der letzten Messung in ms zurück - */ -int UsLetzterGueltigerMesswertAlter(int id) -{ - return (millis() - USSensoren[id].lastValidTime); -} - - -/** - * ----------------------------------------------------------- - * blockierende Messung - * ----------------------------------------------------------- - */ -int16 UltraschallMessenEinzel(int id) -{ - uint32 t1; - uint32 t2=0; - if ((id<0) || (id >= MAX_US_SENSOR)) - return ENTFERNUNG_INVALID; - - // alle Sensoren deaktivieren - for (int i=0; iechoPin) == HIGH ) - { - t2 = micros(); - if (t2-t1 > 100000) // Wenn 100ms lang kein LOW am Echo-Pin Fehler zurückgeben - return ERROR_SENSOR_BUSY; - } - - // trigger-Impuls generieren - digitalWrite(pSensor->triggerPin, HIGH); - delayMicroseconds(10); - digitalWrite(pSensor->triggerPin, LOW); - - // auf HIGH am Echo-Pin warten - t1 = micros(); - - while (digitalRead(pSensor->echoPin) == LOW ) - { - t2 = micros(); - if (t2-t1 > 1000) - return ERROR_NO_SENSOR; // kein LOW-HIGH-Übergang innerhalb 1ms detektiert -> Fehler - } - t1 = micros(); - - // auf LOW am Echo-Pin warten - while (digitalRead(pSensor->echoPin) == HIGH ) - { - t2 = micros(); - if ((t2-t1) > (uint32)(pSensor->maxTime*1000)) - return ENTFERNUNG_INVALID; // Messentfernung größer maxRange - } - - return (t2-t1)/US_ROUNDTRIP_CM; -} - - -//------------------------------------------------------------------------ -void PrintUsSensorList() { - USSensor *pSensor = pAktiverSensor; - - for (int i = 0; i < SensorAktivAnzahl; i++){ - if (pSensor == NULL) - return; - PrintNumber("Sensor", pSensor->id); - if (pSensor->pNext == NULL) - debugPrint(" next NULL"); - else - PrintNumber(" next", pSensor->pNext->id); - if (pSensor->pPrev == NULL) - debugPrint(" prev NULL"); - else - PrintNumber(" prev", pSensor->pPrev->id); - pSensor = pSensor->pNext; - } -} - -#if 0 -// Timer Test-Funktionen - -static void testHandler() { - debugPrint("usi"); - - if (usTimerCount) - usTimerCount--; - else { - stopUsTimer(); - debugPrint("---"); - startUsTimer(300, testHandler); - } -} - -void TestUsTimer() { - startUsTimer(100, testHandler); -} - -int GetUsTimerCount() { - return usTimer.getCount(); -} -#endif - diff --git a/STM32F3/libraries/roboter/ultraschall.h b/STM32F3/libraries/roboter/ultraschall.h deleted file mode 100644 index a03af40..0000000 --- a/STM32F3/libraries/roboter/ultraschall.h +++ /dev/null @@ -1,156 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2015 Frank-Michael Krause - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -#ifndef ULTRASCHALL_H_ -#define ULTRASCHALL_H_ - -#define US_IDLE 0 -#define US_ACTIVE 1 - - -#define US_ROUNDTRIP_CM 57 // Microseconds (uS) it takes sound to travel round-trip 1cm (2cm total), uses integer to save compiled code space. - -typedef void (*usFuncPtr)(int id, int entfernung); - -typedef struct USSensor_s { - int8 id; - int triggerPin; - int echoPin; - int8 enabled; - int8 state; // IDLE, ACTIVE - int8 neuerMesswert; - int16 maxTime; //Zeit für maximal zu messende Entfernung in ms - int timerTicksPerCm; - int16 entfernung; // in cm - uint32 messZeit; // Systemzeit der Messung in ms - int16 lastValidRange; - uint32 lastValidTime; -// uint32 startZeit; // Startzeit der aktuellen Messung - usFuncPtr handler; - struct USSensor_s *pNext; - struct USSensor_s *pPrev; -} USSensor; - -#define MAX_US_SENSOR 4 - -#define ENTFERNUNG_INVALID -1 -#define ERROR_NO_SENSOR -2 -#define ERROR_SENSOR_BUSY -3 - -extern USSensor USSensoren[MAX_US_SENSOR]; - - -/***************************************************** - * Funktionen zur Initialisierung - ****************************************************/ - -/** - * id: Index zwischen 0 und MAX_US_SENSOR-1 - * trigger: IO-Pin, der mit dem Trigger-Eingang des Sensors verbunden ist - * echo: IO-Pin, der mit dem Echo-Ausgang des Sensors verbunden ist. - * !!! der Echo-IO-Pin muss 5V tolerant sein oder mit einem - * Spannungsteiler versehen werden. - * maxRange: Maximal zu messende Entfernung in cm; optional - */ -extern void addUSSensor(int id, int trigger, int echo, int maxRange=150); - -/** - * setzt die Zeit der Pause, die nach erfolgreicher Messung vor der nächsten - * Messung eingefügt wird. - * Default ist 0, d.h. keine Pause - */ -extern void UsSetMessPause(int ms); - - - -/***************************************************** - * Funktionen für blockierende Messung - * Bei Aufruf der blockierenden Einzelmessfunktion werden - * alle über Interrupt akktivierten Sensoren deaktiviert - * - * gibt Entfernung in cm zurück - * bzw. die Fehlerwerte - * ENTFERNUNG_INVALID -1 - * ERROR_NO_SENSOR -2 - * ERROR_SENSOR_BUSY -3 - *****************************************************/ -extern int16 UltraschallMessenEinzel(int id); - - - - -/***************************************************** - * Funktionen für nicht blockierende, interrupt-basierte Messung - * - * Durch Zustandsvariablen gesteuert werden auf allen aktiven Sensoren - * immer wieder abwechselnd Messungen angestossen. - * Die Messergebnisse werden in Variablen der Sensorstruktur abgelegt - * und können über Funktionen aus dem Hauptptogramm abgefragt werden. - * - * Es kann pro Sensor eine Handler-Funktion registriert werden, - * die aufgerufen wird, sobald ein neuer Messwert vorliegt. - *****************************************************/ - - -extern void aktiviereUSSensor(int id); -extern void deaktiviereUSSensor(int id); - -extern void UsAttachHandler(int id, usFuncPtr fkt); - - -/** - * gibt das Ergebnis der letzten Messung zurück. - * Kann ENTFERNUNG_INVALID sein. - */ -extern int16 UsAktuellerMesswert(int id); - -/** - * gibt das Alter des letzen Messergebnisses in ms an. - */ -extern int UsAktuellerMesswertAlter(int id); - -/** - * gibt den letzten Messwert des Sensors zurück, der nicht - * ENTFERNUNG_INVALID ist. - */ -extern int16 UsLetzterGueltigerMesswert(int id); - - -/** - * gibt das Alter des letzen gültigen Messergebnisses in ms an. - */ -extern int UsLetzterGueltigerMesswertAlter(int id); - - - -/***************************************************** - * Debug-Funktionen - ****************************************************/ - -extern void PrintUsSensorList(); - - -#endif /* ULTRASCHALL_H_ */ diff --git a/STM32F3/platform.txt b/STM32F3/platform.txt deleted file mode 100644 index 60d4042..0000000 --- a/STM32F3/platform.txt +++ /dev/null @@ -1,144 +0,0 @@ -# -# -# For more info: -# https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification - -name=STM32F3 boards -version=0.1.0 - -# compiler variables -# ---------------------- -#build.gcc_ver=gcc-arm-none-eabi-4.8.3-2014q1 - -compiler.path={runtime.tools.arm-none-eabi-gcc.path}/bin/ -compiler.c.cmd=arm-none-eabi-gcc -compiler.c.flags=-c -g {build.flags.optimize} -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.elf.cmd=arm-none-eabi-g++ -compiler.c.elf.flags={build.flags.optimize} -Wl,--gc-sections {build.flags.ldspecs} -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 {build.flags.optimize} -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.ar.cmd=arm-none-eabi-ar -compiler.ar.flags=rcs -compiler.objcopy.cmd=arm-none-eabi-objcopy -compiler.objcopy.eep.flags=-O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 -compiler.elf2hex.flags=-O binary -compiler.elf2hex.cmd=arm-none-eabi-objcopy -compiler.ldflags={build.flags.ldspecs} -compiler.size.cmd=arm-none-eabi-size -compiler.define=-DARDUINO= - -# this can be overriden in boards.txt -build.cpu_flags= -build.hs_flag= -build.common_flags= -build.extra_flags= {build.cpu_flags} {build.hs_flag} {build.common_flags} - -# These can be overridden in platform.local.txt -compiler.c.extra_flags= -compiler.c.elf.extra_flags="-L{build.variant.path}/ld" -compiler.cpp.extra_flags= -compiler.S.extra_flags= -compiler.ar.extra_flags= -compiler.elf2hex.extra_flags= - - - -compiler.libs.c.flags="-I{build.core.path}/libmaple" "-I{build.core.path}/libmaple/include" "-I{build.core.path}/libmaple/stm32f3/include" "-I{build.core.path}/libmaple/usb" "-I{build.core.path}/libmaple/usb/usb_lib" "-I{build.core.path}/wirish/include" "-I{build.core.path}/wirish" -#compiler.libs.c.flags="-I{build.system.path}/libmaple" "-I{build.system.path}/libmaple/include" "-I{build.system.path}/libmaple/stm32f1/include" "-I{build.system.path}/libmaple/usb/stm32f1" "-I{build.system.path}/libmaple/usb/usb_lib" "-I{build.system.path}/wirish/include" - - -#compiler.libs.c.flags="-I{build.core.path}/libmaple" -I{build.core.path}/libmaple/usbF4 -I{build.core.path}/libmaple/usbF4/STM32_USB_Device_Library/Core/inc -I{build.core.path}/libmaple/usbF4/STM32_USB_Device_Library/Class/cdc/inc -I{build.core.path}/libmaple/usbF4/STM32_USB_OTG_Driver/inc -I{build.core.path}/libmaple/usbF4/VCP - - - -# USB Flags -# --------- -## build.usb_flags=-DUSB_VID={build.vid} -DUSB_PID={build.pid} -DUSBCON '-DUSB_MANUFACTURER={build.usb_manufacturer}' '-DUSB_PRODUCT={build.usb_product}' - -# Default usb manufacturer will be replaced at compile time using -# numeric vendor ID if available or by board's specific value. -## build.usb_manufacturer="Unknown" - - -# build patterns -# --------------------- - -## Compile c files -recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.flags} -mcpu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.c.extra_flags} {build.extra_flags} {compiler.libs.c.flags} {includes} "{source_file}" -o "{object_file}" - -## Compile c++ files -recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} -mcpu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {build.cpu_flags} {build.hs_flag} {build.common_flags} {compiler.libs.c.flags} {includes} "{source_file}" -o "{object_file}" - -## Compile S files -recipe.S.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.S.flags} -mcpu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.S.extra_flags} {build.extra_flags} {build.cpu_flags} {build.hs_flag} {build.common_flags} {compiler.libs.c.flags} {includes} "{source_file}" -o "{object_file}" -#recipe.S.o.pattern="{compiler.path}{compiler.c.cmd}" "{source_file}" -o "{object_file}" - -## Create archives -recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{archive_file_path}" "{object_file}" - -## Combine gc-sections, archives, and objects -##recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} -mcpu={build.mcu} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" -lm -lgcc -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--entry=Reset_Handler -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols -Wl,--start-group "{build.path}/syscalls_sam3.c.o" {object_files} "{build.variant.path}/{build.variant_system_lib}" "{archive_file_path}" -Wl,--end-group -#-Wl,--entry=__start__ -#recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} -mcpu={build.mcu} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" -lm -lgcc -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols -Wl,--start-group {object_files} "{build.variant.path}/{build.variant_system_lib}" "{archive_file_path}" -Wl,--end-group -recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} -mcpu={build.mcu} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" -lm -lgcc -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols -Wl,--start-group {object_files} -Wl,--whole-archive "{archive_file_path}" -Wl,--no-whole-archive -Wl,--end-group - -## Create eeprom -recipe.objcopy.eep.pattern= - -## Create hex -recipe.objcopy.hex.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf2hex.flags} {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.bin" - -## Compute size -recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.elf" -#recipe.size.regex=\.text\s+([0-9]+).* -recipe.size.regex=^(?:\.text|\.rodata|\.ARM.exidx)\s+([0-9]+).* -recipe.size.regex.data=^(?:\.data|\.bss|\.noinit)\s+([0-9]+).* - -# Uploader tools -# ------------------- - -# Upload using Maple bootloader over DFU -tools.maple_upload.cmd=maple_upload -tools.maple_upload.cmd.windows=maple_upload.bat -#tools.maple_upload.cmd.linux= -tools.maple_upload.path={runtime.hardware.path}/tools/win -tools.maple_upload.path.macosx={runtime.hardware.path}/tools/macosx - -tools.maple_upload.upload.params.verbose=-d -tools.maple_upload.upload.params.quiet= -tools.maple_upload.upload.pattern="{path}/{cmd}" {serial.port.file} {upload.altID} {upload.usbID} "{build.path}/{build.project_name}.bin" - -# Generic STM32 upload via serial to Serial Port 1 (pins PA9 and PA10) - note. Boot0 line needs to high on board reset to enable upload via serial -# at the end of the upload the program is automatically run, without the board being reset - -tools.serial_upload.cmd=serial_upload -tools.serial_upload.cmd.windows=serial_upload.bat -#tools.serial_upload.cmd.linux= -tools.serial_upload.path={runtime.hardware.path}/tools/win - -tools.serial_upload.upload.params.verbose=-d -tools.serial_upload.upload.params.quiet= -tools.serial_upload.upload.pattern="{path}/{cmd}" {serial.port.file} {upload.altID} {upload.usbID} "{build.path}/{build.project_name}.bin" - -# -tools.upload_router.cmd=upload_router -tools.upload_router.cmd.windows=upload_router.bat -#tools.upload_router.cmd.linux= -tools.upload_router.path={runtime.hardware.path}/tools/win - -tools.upload_router.upload.params.verbose=-d -tools.upload_router.upload.params.quiet= -tools.upload_router.upload.pattern="{path}/{cmd}" {serial.port.file} {upload.altID} {upload.usbID} "{build.path}/{build.project_name}" {upload.protocol} {build.debuggingMode} "{runtime.ide.path}/hardware/tools/{build.gcc_ver}/bin/" - -# STLINK/V2 - -tools.stlink.cmd=stlink -tools.stlink.cmd.windows=stlink_upload.bat -#tools.stlink.cmd.linux= -tools.stlink.path={runtime.hardware.path}/tools/win -tools.stlink.upload.params.verbose=-d -tools.stlink.upload.params.quiet= -tools.stlink.upload.pattern="{path}/{cmd}" {serial.port.file} {upload.altID} {upload.usbID} "{build.path}/{build.project_name}.bin" - diff --git a/STM32F3/variants/discovery_f3/board/board.h b/STM32F3/variants/discovery_f3/board/board.h deleted file mode 100644 index 6b04a8b..0000000 --- a/STM32F3/variants/discovery_f3/board/board.h +++ /dev/null @@ -1,138 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file wirish/boards/48F3/include/board/board.h - * @author F3-port: Hanspeter Portner - * @brief F303xx board header (F303CB, F303CC, F303RB, F303RC, F303VB, F303VC). - * - * See wirish/boards/maple/include/board/board.h for more information - * on these definitions. - */ - -#ifndef _BOARD_F303xx_H_ -#define _BOARD_F303xx_H_ - -#include - -#define CYCLES_PER_MICROSECOND (F_CPU / 1000000U) -#define SYSTICK_RELOAD_VAL (F_CPU/1000) - 1 /* takes a cycle to reload */ - -enum { - PC13, PC14, PC15, - PF0, PF1, - PA0, PA1, PA2, PA3, PA4, PA5, PA6, PA7, - PB0, PB1, PB2, - PB10, PB11, PB12, PB13, PB14, PB15, - PA8, PA9, PA10, PA11, PA12, PA13, PA14, PA15, - PB3, PB4, PB5, PB6, PB7, PB8, PB9, -#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) - PC0, PC1, PC2, PC3, - PF4, - PC4, PC5, PC6, PC7, PC8, PC9, PC10, PC11, PC12, - PD2, -# if defined(STM32_XL_DENSITY) - PE2, PE3, PE4, PE5, PE6, - PF9, PF10, - PF2, - PE7, PE8, PE9, PE10, PE11, PE12, PE13, PE14, PE15, - PD8, PD9, PD10, PD11, PD12, PD13, PD14, PD15, - PF6, - PD0, PD1, - PD3, PD4, PD5, PD6, PD7, - PE0, PE1, -# endif -#endif -}; - -#define BOARD_USART1_TX_PIN PA9 /* also PB6 */ -#define BOARD_USART1_RX_PIN PA10 /* also PB7 */ - -#define BOARD_USART2_TX_PIN PA2 /* also PA14, PB3 */ -#define BOARD_USART2_RX_PIN PA3 /* also PA15, PB4 */ - -#define BOARD_USART3_TX_PIN PB10 -#define BOARD_USART3_RX_PIN PB11 - -#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) -# define BOARD_UART4_TX_PIN PC10 -# define BOARD_UART4_RX_PIN PC11 - -# define BOARD_UART5_TX_PIN PC12 -# define BOARD_UART5_RX_PIN PD2 -#endif - -#define BOARD_NR_SPI 3 - -#define BOARD_SPI1_NSS_PIN PA4 -#define BOARD_SPI1_SCK_PIN PA5 -#define BOARD_SPI1_MISO_PIN PA6 -#define BOARD_SPI1_MOSI_PIN PA7 - -#define BOARD_SPI2_NSS_PIN PB12 -#define BOARD_SPI2_SCK_PIN PB13 -#define BOARD_SPI2_MISO_PIN PB14 -#define BOARD_SPI2_MOSI_PIN PB15 - -#define BOARD_SPI3_NSS_PIN PA15 -#define BOARD_SPI3_SCK_PIN PB3 -#define BOARD_SPI3_MISO_PIN PB4 -#define BOARD_SPI3_MOSI_PIN PB5 - -#define BOARD_JTMS_SWDIO_PIN PA13 -#define BOARD_JTCK_SWCLK_PIN PA14 -#define BOARD_JTDI_PIN PA15 -#define BOARD_JTDO_PIN PB3 -#define BOARD_NJTRST_PIN PB4 - -#if defined(STM32_MEDIUM_DENSITY) -# define BOARD_NR_USARTS 3 -# define BOARD_NR_GPIO_PINS 37 -# define BOARD_NR_PWM_PINS 28 -# define BOARD_NR_ADC_PINS 15 -# define BOARD_NR_USED_PINS 4 -#elif defined(STM32_HIGH_DENSITY) -# define BOARD_NR_USARTS 5 -# define BOARD_NR_GPIO_PINS 52 -# define BOARD_NR_PWM_PINS 32 -# define BOARD_NR_ADC_PINS 22 -# define BOARD_NR_USED_PINS 4 -#elif defined(STM32_XL_DENSITY) -# define BOARD_NR_USARTS 5 -# define BOARD_NR_GPIO_PINS 87 -# define BOARD_NR_PWM_PINS 53 -# define BOARD_NR_ADC_PINS 39 -# define BOARD_NR_USED_PINS 7 -#endif - -/* redefine the following ones to match your hardware design */ -#define BOARD_BUTTON_PIN PA0 -#define BOARD_LED_PIN PE10 - -#define BOARD_USB_DISC_DEV GPIOA -#define BOARD_USB_DISC_BIT 13 - -#endif diff --git a/STM32F3/variants/discovery_f3/discovery_f3.cpp b/STM32F3/variants/discovery_f3/discovery_f3.cpp deleted file mode 100644 index c3c2542..0000000 --- a/STM32F3/variants/discovery_f3/discovery_f3.cpp +++ /dev/null @@ -1,193 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2013 OpenMusicKontrollers. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file wirish/boards/48F3/board.c - * @author F3-port: Hanspeter Portner - * @brief F303xx board file (F303CB, F303CC, F303RB, F303RC, F303VB, F303VC). - */ - -#include "board/board.h" - -#include "libmaple/gpio.h" -#include "libmaple/timer.h" - -#include "wirish/wirish_debug.h" -#include "wirish/wirish_types.h" - -/* Since we want the Serial Wire/JTAG pins as GPIOs, disable both SW - * and JTAG debug support on the packages with low pin-count (e.g. MEDIUM_DENSITY), - * unless configured otherwise. */ -void boardInit(void) { -#if defined(STM32_MEDIUM_DENSITY) - //disableDebugPorts(); -#endif - enableDebugPorts(); - -} - -extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { - [PC13]= {GPIOC, NULL, NULL, 13, 0, ADCx}, /* PC13 */ - [PC14]= {GPIOC, NULL, NULL, 14, 0, ADCx}, /* PC14 */ /* OSC32_IN */ - [PC15]= {GPIOC, NULL, NULL, 15, 0, ADCx}, /* PC15 */ /* OSC32_OUT */ - - [PF0] = {GPIOF, NULL, NULL, 0, 0, ADCx}, /* PF0 */ /* OSC_IN */ - [PF1] = {GPIOF, NULL, NULL, 1, 0, ADCx}, /* PF1 */ /* OSC_OUT */ - - [PA0] = {GPIOA, TIMER2, ADC1, 0, 1, 1}, /* PA0 */ - [PA1] = {GPIOA, TIMER2, ADC1, 1, 2, 2}, /* PA1 */ - [PA2] = {GPIOA, TIMER2, ADC1, 2, 3, 3}, /* PA2 */ /* also TIMER15 CH1 */ - [PA3] = {GPIOA, TIMER2, ADC1, 3, 4, 4}, /* PA3 */ /* also TIMER15 CH2 */ - [PA4] = {GPIOA, TIMER3, ADC2, 4, 2, 1}, /* PA4 */ - [PA5] = {GPIOA, NULL, ADC2, 5, 0, 2}, /* PA5 */ - [PA6] = {GPIOA, TIMER3, ADC2, 6, 1, 3}, /* PA6 */ /* also TIMER16 CH1 */ - [PA7] = {GPIOA, TIMER3, ADC2, 7, 2, 4}, /* PA7 */ /* also TIMER17 CH1 */ - - [PB0] = {GPIOB, TIMER3, ADC3, 0, 3, 12}, /* PB0 */ - [PB1] = {GPIOB, TIMER3, ADC3, 1, 4, 1}, /* PB1 */ - [PB2] = {GPIOB, NULL, ADC2, 2, 0, 12}, /* PB2 */ - - [PB10]= {GPIOB, TIMER2, NULL, 10, 3, ADCx}, /* PB10 */ - [PB11]= {GPIOB, TIMER2, NULL, 11, 4, ADCx}, /* PB11 */ - [PB12]= {GPIOB, NULL, ADC4, 12, 0, 3}, /* PB12 */ - [PB13]= {GPIOB, NULL, ADC3, 13, 0, 5}, /* PB13 */ - [PB14]= {GPIOB, TIMER15,ADC4, 14, 1, 4}, /* PB14 */ - [PB15]= {GPIOB, TIMER15,ADC4, 15, 2, 5}, /* PB15 */ - - [PA8] = {GPIOA, TIMER1, NULL, 8, 1, ADCx}, /* PA8 */ - [PA9] = {GPIOA, TIMER1, NULL, 9, 2, ADCx}, /* PA9 */ /* also TIMER2_CH3 */ - [PA10]= {GPIOA, TIMER1, NULL, 10, 3, ADCx}, /* PA10 */ /* also TIMER2 CH4 */ - [PA11]= {GPIOA, TIMER4, NULL, 11, 1, ADCx}, /* PA11 */ /* also TIMER1 CH4 */ - [PA12]= {GPIOA, TIMER4, NULL, 12, 2, ADCx}, /* PA12 */ /* also TIMER16 CH1 */ - [PA13]= {GPIOA, TIMER4, NULL, 13, 3, ADCx}, /* PA13 */ - [PA14]= {GPIOA, TIMER8, NULL, 14, 2, ADCx}, /* PA14 */ - [PA15]= {GPIOA, TIMER8, NULL, 15, 1, ADCx}, /* PA15 */ - - [PB3] = {GPIOB, TIMER2, NULL, 3, 2, ADCx}, /* PB3 */ - [PB4] = {GPIOB, TIMER3, NULL, 4, 1, ADCx}, /* PB4 */ /* also TIMER16 CH1 */ - [PB5] = {GPIOB, TIMER3, NULL, 5, 2, ADCx}, /* PB5 */ /* also TIMER17 CH1 */ - [PB6] = {GPIOB, TIMER4, NULL, 6, 1, ADCx}, /* PB6 */ /* also TIMER8 CH1 */ - [PB7] = {GPIOB, TIMER4, NULL, 7, 2, ADCx}, /* PB7 */ /* also TIMER3 CH4 */ - [PB8] = {GPIOB, TIMER4, NULL, 8, 3, ADCx}, /* PB8 */ /* also TIMER16 CH1 */ - [PB9] = {GPIOB, TIMER4, NULL, 9, 4, ADCx}, /* PB9 */ /* also TIMER17 CH1 */ - -#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) - [PC0] = {GPIOC, NULL, ADC1, 0, 0, 6}, /* PC0 */ - [PC1] = {GPIOC, NULL, ADC1, 1, 0, 7}, /* PC1 */ - [PC2] = {GPIOC, NULL, ADC1, 2, 0, 8}, /* PC2 */ - [PC3] = {GPIOC, NULL, ADC1, 3, 0, 9}, /* PC3 */ - - [PF4] = {GPIOF, NULL, ADC1, 4, 0, 5}, /* PF4 */ - - [PC4] = {GPIOC, NULL, ADC2, 4, 0, 5}, /* PC4 */ - [PC5] = {GPIOC, NULL, ADC2, 5, 0, 11}, /* PC5 */ - [PC6] = {GPIOC, TIMER8, NULL, 6, 1, ADCx}, /* PC6 */ /* also TIMER3_CH1 */ - [PC7] = {GPIOC, TIMER8, NULL, 7, 2, ADCx}, /* PC7 */ /* also TIMER3_CH2 */ - [PC8] = {GPIOC, TIMER8, NULL, 8, 3, ADCx}, /* PC8 */ /* also TIMER3_CH3 */ - [PC9] = {GPIOC, TIMER8, NULL, 9, 4, ADCx}, /* PC9 */ /* also TIMER3_CH4 */ - [PC10]= {GPIOC, NULL, NULL, 10, 0, ADCx}, /* PC10 */ - [PC11]= {GPIOC, NULL, NULL, 11, 0, ADCx}, /* PC11 */ - [PC12]= {GPIOC, NULL, NULL, 12, 0, ADCx}, /* PC12 */ - - [PD2] = {GPIOD, NULL, NULL, 2, 0, ADCx}, /* PD2 */ - -# if defined(STM32_XL_DENSITY) - [PE2] = {GPIOE, TIMER3, NULL, 2, 1, ADCx}, /* PE2 */ - [PE3] = {GPIOE, TIMER3, NULL, 3, 2, ADCx}, /* PE3 */ - [PE4] = {GPIOE, TIMER3, NULL, 4, 3, ADCx}, /* PE4 */ - [PE5] = {GPIOE, TIMER3, NULL, 5, 4, ADCx}, /* PE5 */ - [PE6] = {GPIOE, NULL, NULL, 6, 0, ADCx}, /* PE6 */ - - [PF9] = {GPIOF,TIMER15, NULL, 9, 1, ADCx}, /* PF9 */ - [PF10]= {GPIOF,TIMER15, NULL, 10, 2, ADCx}, /* PF10 */ - - [PF2] = {GPIOF, NULL, ADC1, 2, 0, 10}, /* PF2 */ - - [PE7] = {GPIOE, NULL, ADC3, 7, 0, 13}, /* PE7 */ - [PE8] = {GPIOE, NULL, ADC3, 8, 0, 6}, /* PE8 */ - [PE9] = {GPIOE, TIMER1, ADC3, 9, 1, 2}, /* PE9 */ - [PE10]= {GPIOE, NULL, ADC3, 10, 0, 14}, /* PE10 */ - [PE11]= {GPIOE, TIMER1, ADC3, 11, 2, 15}, /* PE11 */ - [PE12]= {GPIOE, NULL, ADC3, 12, 0, 15}, /* PE12 */ - [PE13]= {GPIOE, TIMER1, ADC3, 13, 3, 3}, /* PE13 */ - [PE14]= {GPIOE, TIMER1, ADC4, 14, 4, 1}, /* PE14 */ - [PE15]= {GPIOE, NULL, ADC4, 15, 0, 2}, /* PE15 */ - - [PD8] = {GPIOD, NULL, ADC4, 8, 0, 12}, /* PD8 */ - [PD9] = {GPIOD, NULL, ADC4, 9, 0, 13}, /* PD0 */ - [PD10]= {GPIOD, NULL, ADC3, 10, 0, 7}, /* PD10 */ - [PD11]= {GPIOD, NULL, ADC3, 11, 0, 8}, /* PD11 */ - [PD12]= {GPIOD, TIMER4, ADC3, 12, 1, 9}, /* PD12 */ - [PD13]= {GPIOD, TIMER4, ADC3, 13, 2, 10}, /* PD13 */ - [PD14]= {GPIOD, TIMER4, ADC3, 14, 3, 11}, /* PD14 */ - [PD15]= {GPIOD, TIMER4, NULL, 15, 4, ADCx}, /* PD15 */ - - [PF6] = {GPIOF, TIMER4, NULL, 6, 4, ADCx}, /* PF6 */ - - [PD0] = {GPIOD, NULL, NULL, 0, 0, ADCx}, /* PD0 */ - [PD1] = {GPIOD, TIMER8, NULL, 1, 4, ADCx}, /* PD1 */ - - [PD3] = {GPIOD, NULL, NULL, 3, 0, ADCx}, /* PD3 */ - [PD4] = {GPIOD, TIMER2, NULL, 4, 2, ADCx}, /* PD4 */ - [PD5] = {GPIOD, NULL, NULL, 5, 0, ADCx}, /* PD5 */ - [PD6] = {GPIOD, TIMER2, NULL, 6, 4, ADCx}, /* PD6 */ - [PD7] = {GPIOD, TIMER2, NULL, 7, 3, ADCx}, /* PD7 */ - - [PE0] = {GPIOE,TIMER16, NULL, 0, 1, ADCx}, /* PE0 */ - [PE1] = {GPIOE,TIMER17, NULL, 1, 1, ADCx}, /* PE1 */ -# endif -#endif -}; - -extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { - PA0, PA1, PA2, PA3, PA4, PA6, PA7, PB0, PB1, PB10, PB11, PB14, PB15, PA8, PA9, PA10, PA11, PA12, PA13, PA14, PA15, PB3, PB4, PB5, PB6, PB7, PB8, PB9, -#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) - PC6, PC7, PC8, PC9, -# if defined(STM32_XL_DENSITY) - PE2, PE3, PE4, PE5, PF9, PF10, PE9, PE11, PE13, PE14, PD12, PD13, PD14, PD15, PF6, PD1, PD4, PD6, PD7, PE0, PE1, -# endif -#endif -}; - -extern const uint8 boardADCPins[BOARD_NR_ADC_PINS] __FLASH__ = { - PA0, PA1, PA2, PA3, PA4, PA5, PA6, PA7, PB0, PB1, PB2, PB12, PB13, PB14, PB15, -#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) - PC0, PC1, PC2, PC3, PF4, PC4, PC5, -# if defined(STM32_XL_DENSITY) - PF2, PE7, PE8, PE9, PE10, PE11, PE12, PE13, PE14, PE15, PD8, PD9, PD10, PD11, PD12, PD13, PD14, -# endif -#endif -}; - -#define OSC_IN PF0 -#define OSC_OUT PF1 - -#define USB_DM PA11 -#define USB_DP PA12 - -extern const uint8 boardUsedPins[BOARD_NR_USED_PINS] __FLASH__ = { - OSC_IN, OSC_OUT, USB_DP, USB_DM,PB3, PA13, PA14 -}; diff --git a/STM32F3/variants/discovery_f3/ld/common.inc b/STM32F3/variants/discovery_f3/ld/common.inc deleted file mode 100644 index 49aaf6f..0000000 --- a/STM32F3/variants/discovery_f3/ld/common.inc +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Linker script for libmaple. - * - * Original author "lanchon" from ST forums, with modifications by LeafLabs. - */ - -OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") - -/* - * Configure other libraries we want in the link. - * - * libgcc, libc, and libm are common across supported toolchains. - * However, some toolchains require additional archives which aren't - * present everywhere (e.g. ARM's gcc-arm-embedded releases). - * - * To hack around this, we let the build system specify additional - * archives by putting the right extra_libs.inc (in a directory under - * toolchains/) in our search path. - */ -GROUP(libgcc.a libc.a libm.a) -INCLUDE extra_libs.inc - -/* - * These force the linker to search for vector table symbols. - * - * These symbols vary by STM32 family (and also within families). - * It's up to the build system to configure the link's search path - * properly for the target MCU. - */ -INCLUDE vector_symbols.inc - -/* STM32 vector table. */ -EXTERN(__stm32_vector_table) - -/* C runtime initialization function. */ -EXTERN(start_c) - -/* main entry point */ -EXTERN(main) - -/* Initial stack pointer value. */ -EXTERN(__msp_init) -PROVIDE(__msp_init = ORIGIN(ram) + LENGTH(ram)); - -/* Reset vector and chip reset entry point */ -EXTERN(__start__) -ENTRY(__start__) -PROVIDE(__exc_reset = __start__); - -/* Heap boundaries, for libmaple */ -EXTERN(_lm_heap_start); -EXTERN(_lm_heap_end); - -SECTIONS -{ - .text : - { - __text_start__ = .; - /* - * STM32 vector table. Leave this here. Yes, really. - */ - *(.stm32.interrupt_vector) - - /* - * Program code and vague linking - */ - *(.text .text.* .gnu.linkonce.t.*) - *(.plt) - *(.gnu.warning) - *(.glue_7t) *(.glue_7) *(.vfp11_veneer) - - *(.ARM.extab* .gnu.linkonce.armextab.*) - *(.gcc_except_table) - *(.eh_frame_hdr) - *(.eh_frame) - - . = ALIGN(4); - KEEP(*(.init)) - - . = ALIGN(4); - __preinit_array_start = .; - KEEP (*(.preinit_array)) - __preinit_array_end = .; - - . = ALIGN(4); - __init_array_start = .; - KEEP (*(SORT(.init_array.*))) - KEEP (*(.init_array)) - __init_array_end = .; - - . = ALIGN(0x4); - KEEP (*crtbegin.o(.ctors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) - KEEP (*(SORT(.ctors.*))) - KEEP (*crtend.o(.ctors)) - - . = ALIGN(4); - KEEP(*(.fini)) - - . = ALIGN(4); - __fini_array_start = .; - KEEP (*(.fini_array)) - KEEP (*(SORT(.fini_array.*))) - __fini_array_end = .; - - KEEP (*crtbegin.o(.dtors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) - KEEP (*(SORT(.dtors.*))) - KEEP (*crtend.o(.dtors)) - } > REGION_TEXT - - /* - * End of text - */ - .text.align : - { - . = ALIGN(8); - __text_end__ = .; - } > REGION_TEXT - - /* - * .ARM.exidx exception unwinding; mandated by ARM's C++ ABI - */ - __exidx_start = .; - .ARM.exidx : - { - *(.ARM.exidx* .gnu.linkonce.armexidx.*) - } > REGION_RODATA - __exidx_end = .; - - /* - * .data - */ - .data : - { - . = ALIGN(8); - __data_start__ = .; - - *(.got.plt) *(.got) - *(.data .data.* .gnu.linkonce.d.*) - - . = ALIGN(8); - __data_end__ = .; - } > REGION_DATA AT> REGION_RODATA - - /* - * Read-only data - */ - .rodata : - { - *(.rodata .rodata.* .gnu.linkonce.r.*) - /* .USER_FLASH: We allow users to allocate into Flash here */ - *(.USER_FLASH) - /* ROM image configuration; for C startup */ - . = ALIGN(4); - _lm_rom_img_cfgp = .; - LONG(LOADADDR(.data)); - /* - * Heap: Linker scripts may choose a custom heap by overriding - * _lm_heap_start and _lm_heap_end. Otherwise, the heap is in - * internal SRAM, beginning after .bss, and growing towards - * the stack. - * - * I'm shoving these here naively; there's probably a cleaner way - * to go about this. [mbolivar] - */ - _lm_heap_start = DEFINED(_lm_heap_start) ? _lm_heap_start : _end; - _lm_heap_end = DEFINED(_lm_heap_end) ? _lm_heap_end : __msp_init; - } > REGION_RODATA - - /* - * .bss - */ - .bss : - { - . = ALIGN(8); - __bss_start__ = .; - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) - . = ALIGN (8); - __bss_end__ = .; - _end = __bss_end__; - } > REGION_BSS - - /* - * .ccm - */ - .ccm (NOLOAD) : - { - . = ALIGN(4); - *(.CCM) - . = ALIGN(4); - } > REGION_CCM - - /* - * Debugging sections - */ - .stab 0 (NOLOAD) : { *(.stab) } - .stabstr 0 (NOLOAD) : { *(.stabstr) } - /* DWARF debug sections. - * Symbols in the DWARF debugging sections are relative to the beginning - * of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } - - .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) } - .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) } - /DISCARD/ : { *(.note.GNU-stack) } -} diff --git a/STM32F3/variants/discovery_f3/ld/extra_libs.inc b/STM32F3/variants/discovery_f3/ld/extra_libs.inc deleted file mode 100644 index dd2c84f..0000000 --- a/STM32F3/variants/discovery_f3/ld/extra_libs.inc +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Extra archives needed by ARM's GCC ARM Embedded arm-none-eabi- - * releases (https://launchpad.net/gcc-arm-embedded/). - */ - -/* This is for the provided newlib. */ -GROUP(libnosys.a) diff --git a/STM32F3/variants/discovery_f3/ld/flash.ld b/STM32F3/variants/discovery_f3/ld/flash.ld deleted file mode 100644 index 2fa9035..0000000 --- a/STM32F3/variants/discovery_f3/ld/flash.ld +++ /dev/null @@ -1,28 +0,0 @@ -/* - * libmaple linker script for "Flash" builds. - * - * A Flash build puts .text (and .rodata) in Flash, and - * .data/.bss/heap (of course) in SRAM, but offsets the sections by - * enough space to store the Maple bootloader, which lives in low - * Flash and uses low memory. - */ - -/* - * This pulls in the appropriate MEMORY declaration from the right - * subdirectory of stm32/mem/ (the environment must call ld with the - * right include directory flags to make this happen). Boards can also - * use this file to use any of libmaple's memory-related hooks (like - * where the heap should live). - */ - -INCLUDE mem-flash.inc - -/* Provide memory region aliases for common.inc */ -REGION_ALIAS("REGION_TEXT", rom); -REGION_ALIAS("REGION_DATA", ram); -REGION_ALIAS("REGION_BSS", ram); -REGION_ALIAS("REGION_RODATA", rom); -REGION_ALIAS("REGION_CCM", ccm); - -/* Let common.inc handle the real work. */ -INCLUDE common.inc diff --git a/STM32F3/variants/discovery_f3/ld/jtag.ld b/STM32F3/variants/discovery_f3/ld/jtag.ld deleted file mode 100644 index cf08b20..0000000 --- a/STM32F3/variants/discovery_f3/ld/jtag.ld +++ /dev/null @@ -1,33 +0,0 @@ -/* - * libmaple linker script for "JTAG" builds. - * - * A "JTAG" build puts .text (and .rodata) in Flash, and - * .data/.bss/heap (of course) in SRAM, but links starting at the - * Flash and SRAM starting addresses (0x08000000 and 0x20000000 - * respectively). This will wipe out a Maple bootloader if there's one - * on the board, so only use this if you know what you're doing. - * - * Of course, a "JTAG" build is perfectly usable for upload over SWD, - * the system memory bootloader, etc. The name is just a historical - * artifact. - */ - -/* - * This pulls in the appropriate MEMORY declaration from the right - * subdirectory of stm32/mem/ (the environment must call ld with the - * right include directory flags to make this happen). Boards can also - * use this file to use any of libmaple's memory-related hooks (like - * where the heap should live). - */ - -INCLUDE mem-jtag.inc - -/* Provide memory region aliases for common.inc */ -REGION_ALIAS("REGION_TEXT", rom); -REGION_ALIAS("REGION_DATA", ram); -REGION_ALIAS("REGION_BSS", ram); -REGION_ALIAS("REGION_RODATA", rom); -REGION_ALIAS("REGION_CCM", ccm); - -/* Let common.inc handle the real work. */ -INCLUDE common.inc diff --git a/STM32F3/variants/discovery_f3/ld/mem-flash.inc b/STM32F3/variants/discovery_f3/ld/mem-flash.inc deleted file mode 100644 index a683808..0000000 --- a/STM32F3/variants/discovery_f3/ld/mem-flash.inc +++ /dev/null @@ -1,6 +0,0 @@ -MEMORY -{ - ccm (rwx) : ORIGIN = 0x10000000, LENGTH = 8K - ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 37K - rom (rx) : ORIGIN = 0x08005000, LENGTH = 236K -} diff --git a/STM32F3/variants/discovery_f3/ld/mem-jtag.inc b/STM32F3/variants/discovery_f3/ld/mem-jtag.inc deleted file mode 100644 index 9fb4452..0000000 --- a/STM32F3/variants/discovery_f3/ld/mem-jtag.inc +++ /dev/null @@ -1,6 +0,0 @@ -MEMORY -{ - ccm (rwx) : ORIGIN = 0x10000000, LENGTH = 8K - ram (rwx) : ORIGIN = 0x20000000, LENGTH = 40K - rom (rx) : ORIGIN = 0x08000000, LENGTH = 256K -} diff --git a/STM32F3/variants/discovery_f3/ld/mem-ram.inc b/STM32F3/variants/discovery_f3/ld/mem-ram.inc deleted file mode 100644 index 08d7608..0000000 --- a/STM32F3/variants/discovery_f3/ld/mem-ram.inc +++ /dev/null @@ -1,6 +0,0 @@ -MEMORY -{ - ccm (rwx) : ORIGIN = 0x10000000, LENGTH = 8K - ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 37K - rom (rx) : ORIGIN = 0x08005000, LENGTH = 0K -} diff --git a/STM32F3/variants/discovery_f3/ld/names.inc b/STM32F3/variants/discovery_f3/ld/names.inc deleted file mode 100644 index 6d7ff6e..0000000 --- a/STM32F3/variants/discovery_f3/ld/names.inc +++ /dev/null @@ -1,78 +0,0 @@ -EXTERN(__cs3_stack) -EXTERN(__cs3_reset) -EXTERN(__exc_nmi) -EXTERN(__exc_hardfault) -EXTERN(__exc_memmanage) -EXTERN(__exc_busfault) -EXTERN(__exc_usagefault) -EXTERN(__stm32reservedexception7) -EXTERN(__stm32reservedexception8) -EXTERN(__stm32reservedexception9) -EXTERN(__stm32reservedexception10) -EXTERN(__exc_svc) -EXTERN(__exc_debug_monitor) -EXTERN(__stm32reservedexception13) -EXTERN(__exc_pendsv) -EXTERN(__exc_systick) - -EXTERN(__irq_wwdg) -EXTERN(__irq_pvd) -EXTERN(__irq_tamper) -EXTERN(__irq_rtc) -EXTERN(__irq_flash) -EXTERN(__irq_rcc) -EXTERN(__irq_exti0) -EXTERN(__irq_exti1) -EXTERN(__irq_exti2) -EXTERN(__irq_exti3) -EXTERN(__irq_exti4) -EXTERN(__irq_dma1_channel1) -EXTERN(__irq_dma1_channel2) -EXTERN(__irq_dma1_channel3) -EXTERN(__irq_dma1_channel4) -EXTERN(__irq_dma1_channel5) -EXTERN(__irq_dma1_channel6) -EXTERN(__irq_dma1_channel7) -EXTERN(__irq_adc) -EXTERN(__irq_usb_hp_can_tx) -EXTERN(__irq_usb_lp_can_rx0) -EXTERN(__irq_can_rx1) -EXTERN(__irq_can_sce) -EXTERN(__irq_exti9_5) -EXTERN(__irq_tim1_brk) -EXTERN(__irq_tim1_up) -EXTERN(__irq_tim1_trg_com) -EXTERN(__irq_tim1_cc) -EXTERN(__irq_tim2) -EXTERN(__irq_tim3) -EXTERN(__irq_tim4) -EXTERN(__irq_i2c1_ev) -EXTERN(__irq_i2c1_er) -EXTERN(__irq_i2c2_ev) -EXTERN(__irq_i2c2_er) -EXTERN(__irq_spi1) -EXTERN(__irq_spi2) -EXTERN(__irq_usart1) -EXTERN(__irq_usart2) -EXTERN(__irq_usart3) -EXTERN(__irq_exti15_10) -EXTERN(__irq_rtcalarm) -EXTERN(__irq_usbwakeup) - -EXTERN(__irq_tim8_brk) -EXTERN(__irq_tim8_up) -EXTERN(__irq_tim8_trg_com) -EXTERN(__irq_tim8_cc) -EXTERN(__irq_adc3) -EXTERN(__irq_fsmc) -EXTERN(__irq_sdio) -EXTERN(__irq_tim5) -EXTERN(__irq_spi3) -EXTERN(__irq_uart4) -EXTERN(__irq_uart5) -EXTERN(__irq_tim6) -EXTERN(__irq_tim7) -EXTERN(__irq_dma2_channel1) -EXTERN(__irq_dma2_channel2) -EXTERN(__irq_dma2_channel3) -EXTERN(__irq_dma2_channel4_5) diff --git a/STM32F3/variants/discovery_f3/ld/ram.ld b/STM32F3/variants/discovery_f3/ld/ram.ld deleted file mode 100644 index 0484423..0000000 --- a/STM32F3/variants/discovery_f3/ld/ram.ld +++ /dev/null @@ -1,27 +0,0 @@ -/* - * libmaple linker script for RAM builds. - * - * A Flash build puts .text, .rodata, and .data/.bss/heap (of course) - * in SRAM, but offsets the sections by enough space to store the - * Maple bootloader, which uses low memory. - */ - -/* - * This pulls in the appropriate MEMORY declaration from the right - * subdirectory of stm32/mem/ (the environment must call ld with the - * right include directory flags to make this happen). Boards can also - * use this file to use any of libmaple's memory-related hooks (like - * where the heap should live). - */ - -INCLUDE mem-ram.inc - -/* Provide memory region aliases for common.inc */ -REGION_ALIAS("REGION_TEXT", ram); -REGION_ALIAS("REGION_DATA", ram); -REGION_ALIAS("REGION_BSS", ram); -REGION_ALIAS("REGION_RODATA", ram); -REGION_ALIAS("REGION_CCM", ccm); - -/* Let common.inc handle the real work. */ -INCLUDE common.inc diff --git a/STM32F3/variants/discovery_f3/ld/vector_symbols.inc b/STM32F3/variants/discovery_f3/ld/vector_symbols.inc deleted file mode 100644 index a9d18f4..0000000 --- a/STM32F3/variants/discovery_f3/ld/vector_symbols.inc +++ /dev/null @@ -1,98 +0,0 @@ -EXTERN(__msp_init) -EXTERN(__exc_reset) -EXTERN(__exc_nmi) -EXTERN(__exc_hardfault) -EXTERN(__exc_memmanage) -EXTERN(__exc_busfault) -EXTERN(__exc_usagefault) -EXTERN(__stm32reservedexception7) -EXTERN(__stm32reservedexception8) -EXTERN(__stm32reservedexception9) -EXTERN(__stm32reservedexception10) -EXTERN(__exc_svc) -EXTERN(__exc_debug_monitor) -EXTERN(__stm32reservedexception13) -EXTERN(__exc_pendsv) -EXTERN(__exc_systick) -EXTERN(__irq_wwdg) -EXTERN(__irq_pvd) -EXTERN(__irq_tamp_stamp) -EXTERN(__irq_rtc_wkup) -EXTERN(__irq_flash) -EXTERN(__irq_rcc) -EXTERN(__irq_exti0) -EXTERN(__irq_exti1) -EXTERN(__irq_exti2) -EXTERN(__irq_exti3) -EXTERN(__irq_exti4) -EXTERN(__irq_dma1_ch1) -EXTERN(__irq_dma1_ch2) -EXTERN(__irq_dma1_ch3) -EXTERN(__irq_dma1_ch4) -EXTERN(__irq_dma1_ch5) -EXTERN(__irq_dma1_ch6) -EXTERN(__irq_dma1_ch7) -EXTERN(__irq_adc1_2) -EXTERN(__irq_usb_hp_can_tx) -EXTERN(__irq_usb_lp_can_rx0) -EXTERN(__irq_can_rx1) -EXTERN(__irq_can_sce) -EXTERN(__irq_exti9_5) -EXTERN(__irq_tim1_brk_tim15) -EXTERN(__irq_tim1_up_tim16) -EXTERN(__irq_tim1_trg_com_tim17) -EXTERN(__irq_tim1_cc) -EXTERN(__irq_tim2) -EXTERN(__irq_tim3) -EXTERN(__irq_tim4) -EXTERN(__irq_i2c1_ev) -EXTERN(__irq_i2c1_er) -EXTERN(__irq_i2c2_ev) -EXTERN(__irq_i2c2_er) -EXTERN(__irq_spi1) -EXTERN(__irq_spi2) -EXTERN(__irq_usart1) -EXTERN(__irq_usart2) -EXTERN(__irq_usart3) -EXTERN(__irq_exti15_10) -EXTERN(__irq_rtc_alarm) -EXTERN(__irq_usb_wkup) -EXTERN(__irq_tim8_brk) -EXTERN(__irq_tim8_up) -EXTERN(__irq_tim8_trg_com) -EXTERN(__irq_tim8_cc) -EXTERN(__irq_adc3) -EXTERN(__stm32reservedexception48) -EXTERN(__stm32reservedexception49) -EXTERN(__stm32reservedexception50) -EXTERN(__irq_spi3) -EXTERN(__irq_uart4) -EXTERN(__irq_uart5) -EXTERN(__irq_tim6_dacunder) -EXTERN(__irq_tim7) -EXTERN(__irq_dma2_ch1) -EXTERN(__irq_dma2_ch2) -EXTERN(__irq_dma2_ch3) -EXTERN(__irq_dma2_ch4) -EXTERN(__irq_dma2_ch5) -EXTERN(__irq_adc4) -EXTERN(__stm32reservedexception62) -EXTERN(__stm32reservedexception63) -EXTERN(__irq_comp123) -EXTERN(__irq_comp456) -EXTERN(__irq_comp7) -EXTERN(__stm32reservedexception67) -EXTERN(__stm32reservedexception68) -EXTERN(__stm32reservedexception69) -EXTERN(__stm32reservedexception70) -EXTERN(__stm32reservedexception71) -EXTERN(__stm32reservedexception72) -EXTERN(__stm32reservedexception73) -EXTERN(__irq_usb_hp) -EXTERN(__irq_usb_lp) -EXTERN(__irq_usb_wkup2) -EXTERN(__stm32reservedexception77) -EXTERN(__stm32reservedexception78) -EXTERN(__stm32reservedexception79) -EXTERN(__stm32reservedexception80) -EXTERN(__irq_fpu) diff --git a/STM32F3/variants/discovery_f3/stm32_isrs.S b/STM32F3/variants/discovery_f3/stm32_isrs.S deleted file mode 100644 index f236387..0000000 --- a/STM32F3/variants/discovery_f3/stm32_isrs.S +++ /dev/null @@ -1,331 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2011 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/* STM32F3 performance line ISR weak declarations */ - -#include - - .thumb - -/* Default handler for all non-overridden interrupts and exceptions */ - .globl __default_handler - .type __default_handler, %function - -__default_handler: - b . - - .weak __exc_nmi - .globl __exc_nmi - .set __exc_nmi, __default_handler - .weak __exc_hardfault - .globl __exc_hardfault - .set __exc_hardfault, __default_handler - .weak __exc_memmanage - .globl __exc_memmanage - .set __exc_memmanage, __default_handler - .weak __exc_busfault - .globl __exc_busfault - .set __exc_busfault, __default_handler - .weak __exc_usagefault - .globl __exc_usagefault - .set __exc_usagefault, __default_handler - .weak __stm32reservedexception7 - .globl __stm32reservedexception7 - .set __stm32reservedexception7, __default_handler - .weak __stm32reservedexception8 - .globl __stm32reservedexception8 - .set __stm32reservedexception8, __default_handler - .weak __stm32reservedexception9 - .globl __stm32reservedexception9 - .set __stm32reservedexception9, __default_handler - .weak __stm32reservedexception10 - .globl __stm32reservedexception10 - .set __stm32reservedexception10, __default_handler - .weak __exc_svc - .globl __exc_svc - .set __exc_svc, __default_handler - .weak __exc_debug_monitor - .globl __exc_debug_monitor - .set __exc_debug_monitor, __default_handler - .weak __stm32reservedexception13 - .globl __stm32reservedexception13 - .set __stm32reservedexception13, __default_handler - .weak __exc_pendsv - .globl __exc_pendsv - .set __exc_pendsv, __default_handler - .weak __exc_systick - .globl __exc_systick - .set __exc_systick, __default_handler - .weak __irq_wwdg - .globl __irq_wwdg - .set __irq_wwdg, __default_handler - .weak __irq_pvd - .globl __irq_pvd - .set __irq_pvd, __default_handler - .weak __irq_tamp_stamp - .globl __irq_tamp_stamp - .set __irq_tamp_stamp, __default_handler - .weak __irq_rtc_wkup - .globl __irq_rtc_wkup - .set __irq_rtc_wkup, __default_handler - .weak __irq_flash - .globl __irq_flash - .set __irq_flash, __default_handler - .weak __irq_rcc - .globl __irq_rcc - .set __irq_rcc, __default_handler - .weak __irq_exti0 - .globl __irq_exti0 - .set __irq_exti0, __default_handler - .weak __irq_exti1 - .globl __irq_exti1 - .set __irq_exti1, __default_handler - .weak __irq_exti2 - .globl __irq_exti2 - .set __irq_exti2, __default_handler - .weak __irq_exti3 - .globl __irq_exti3 - .set __irq_exti3, __default_handler - .weak __irq_exti4 - .globl __irq_exti4 - .set __irq_exti4, __default_handler - .weak __irq_dma1_ch1 - .globl __irq_dma1_ch1 - .set __irq_dma1_ch1, __default_handler - .weak __irq_dma1_ch2 - .globl __irq_dma1_ch2 - .set __irq_dma1_ch2, __default_handler - .weak __irq_dma1_ch3 - .globl __irq_dma1_ch3 - .set __irq_dma1_ch3, __default_handler - .weak __irq_dma1_ch4 - .globl __irq_dma1_ch4 - .set __irq_dma1_ch4, __default_handler - .weak __irq_dma1_ch5 - .globl __irq_dma1_ch5 - .set __irq_dma1_ch5, __default_handler - .weak __irq_dma1_ch6 - .globl __irq_dma1_ch6 - .set __irq_dma1_ch6, __default_handler - .weak __irq_dma1_ch7 - .globl __irq_dma1_ch7 - .set __irq_dma1_ch7, __default_handler - .weak __irq_adc1_2 - .globl __irq_adc1_2 - .set __irq_adc1_2, __default_handler - .weak __irq_usb_hp_can_tx - .globl __irq_usb_hp_can_tx - .set __irq_usb_hp_can_tx, __default_handler - .weak __irq_usb_lp_can_rx0 - .globl __irq_usb_lp_can_rx0 - .set __irq_usb_lp_can_rx0, __default_handler - .weak __irq_can_rx1 - .globl __irq_can_rx1 - .set __irq_can_rx1, __default_handler - .weak __irq_can_sce - .globl __irq_can_sce - .set __irq_can_sce, __default_handler - .weak __irq_exti9_5 - .globl __irq_exti9_5 - .set __irq_exti9_5, __default_handler - .weak __irq_tim1_brk_tim15 - .globl __irq_tim1_brk_tim15 - .set __irq_tim1_brk_tim15, __default_handler - .weak __irq_tim1_up_tim16 - .globl __irq_tim1_up_tim16 - .set __irq_tim1_up_tim16, __default_handler - .weak __irq_tim1_trg_com_tim17 - .globl __irq_tim1_trg_com_tim17 - .set __irq_tim1_trg_com_tim17, __default_handler - .weak __irq_tim1_cc - .globl __irq_tim1_cc - .set __irq_tim1_cc, __default_handler - .weak __irq_tim2 - .globl __irq_tim2 - .set __irq_tim2, __default_handler - .weak __irq_tim3 - .globl __irq_tim3 - .set __irq_tim3, __default_handler - .weak __irq_tim4 - .globl __irq_tim4 - .set __irq_tim4, __default_handler - .weak __irq_i2c1_ev - .globl __irq_i2c1_ev - .set __irq_i2c1_ev, __default_handler - .weak __irq_i2c1_er - .globl __irq_i2c1_er - .set __irq_i2c1_er, __default_handler - .weak __irq_i2c2_ev - .globl __irq_i2c2_ev - .set __irq_i2c2_ev, __default_handler - .weak __irq_i2c2_er - .globl __irq_i2c2_er - .set __irq_i2c2_er, __default_handler - .weak __irq_spi1 - .globl __irq_spi1 - .set __irq_spi1, __default_handler - .weak __irq_spi2 - .globl __irq_spi2 - .set __irq_spi2, __default_handler - .weak __irq_usart1 - .globl __irq_usart1 - .set __irq_usart1, __default_handler - .weak __irq_usart2 - .globl __irq_usart2 - .set __irq_usart2, __default_handler - .weak __irq_usart3 - .globl __irq_usart3 - .set __irq_usart3, __default_handler - .weak __irq_exti15_10 - .globl __irq_exti15_10 - .set __irq_exti15_10, __default_handler - .weak __irq_rtc_alarm - .globl __irq_rtc_alarm - .set __irq_rtc_alarm, __default_handler - .weak __irq_usb_wkup - .globl __irq_usb_wkup - .set __irq_usb_wkup, __default_handler - - .weak __irq_tim8_brk - .globl __irq_tim8_brk - .set __irq_tim8_brk, __default_handler - .weak __irq_tim8_up - .globl __irq_tim8_up - .set __irq_tim8_up, __default_handler - .weak __irq_tim8_trg_com - .globl __irq_tim8_trg_com - .set __irq_tim8_trg_com, __default_handler - .weak __irq_tim8_cc - .globl __irq_tim8_cc - .set __irq_tim8_cc, __default_handler - .weak __irq_adc3 - .globl __irq_adc3 - .set __irq_adc3, __default_handler - .weak __stm32reservedexception48 - .globl __stm32reservedexception48 - .set __stm32reservedexception48, __default_handler - .weak __stm32reservedexception49 - .globl __stm32reservedexception49 - .set __stm32reservedexception49, __default_handler - .weak __stm32reservedexception50 - .globl __stm32reservedexception50 - .set __stm32reservedexception50, __default_handler - .weak __irq_spi3 - .globl __irq_spi3 - .set __irq_spi3, __default_handler - .weak __irq_uart4 - .globl __irq_uart4 - .set __irq_uart4, __default_handler - .weak __irq_uart5 - .globl __irq_uart5 - .set __irq_uart5, __default_handler - .weak __irq_tim6_dacunder - .globl __irq_tim6_dacunder - .set __irq_tim6_dac, __default_handler - .weak __irq_tim7 - .globl __irq_tim7 - .set __irq_tim7, __default_handler - .weak __irq_dma2_ch1 - .globl __irq_dma2_ch1 - .set __irq_dma2_ch1, __default_handler - .weak __irq_dma2_ch2 - .globl __irq_dma2_ch2 - .set __irq_dma2_ch2, __default_handler - .weak __irq_dma2_ch3 - .globl __irq_dma2_ch3 - .set __irq_dma2_ch3, __default_handler - .weak __irq_dma2_ch4 - .globl __irq_dma2_ch4 - .set __irq_dma2_ch4, __default_handler - .weak __irq_dma2_ch5 - .globl __irq_dma2_ch5 - .set __irq_dma2_ch5, __default_handler - .weak __irq_adc4 - .globl __irq_adc4 - .set __irq_adc4, __default_handler - .weak __stm32reservedexception62 - .globl __stm32reservedexception62 - .set __stm32reservedexception62, __default_handler - .weak __stm32reservedexception63 - .globl __stm32reservedexception63 - .set __stm32reservedexception63, __default_handler - .weak __irq_comp123 - .globl __irq_comp123 - .set __irq_comp123, __default_handler - .weak __irq_comp456 - .globl __irq_comp456 - .set __irq_comp456, __default_handler - .weak __irq_comp7 - .globl __irq_comp7 - .set __irq_comp7, __default_handler - .weak __stm32reservedexception67 - .globl __stm32reservedexception67 - .set __stm32reservedexception67, __default_handler - .weak __stm32reservedexception68 - .globl __stm32reservedexception68 - .set __stm32reservedexception68, __default_handler - .weak __stm32reservedexception69 - .globl __stm32reservedexception69 - .set __stm32reservedexception69, __default_handler - .weak __stm32reservedexception70 - .globl __stm32reservedexception70 - .set __stm32reservedexception70, __default_handler - .weak __stm32reservedexception71 - .globl __stm32reservedexception71 - .set __stm32reservedexception71, __default_handler - .weak __stm32reservedexception72 - .globl __stm32reservedexception72 - .set __stm32reservedexception72, __default_handler - .weak __stm32reservedexception73 - .globl __stm32reservedexception73 - .set __stm32reservedexception73, __default_handler - .weak __irq_usb_hp - .globl __irq_usb_hp - .set __irq_usb_hp, __default_handler - .weak __irq_usb_lp - .globl __irq_usb_lp - .set __irq_usb_lp, __default_handler - .weak __irq_usb_wkup2 - .globl __irq_usb_wkup2 - .set __irq_usb_wkup2, __default_handler - .weak __stm32reservedexception77 - .globl __stm32reservedexception77 - .set __stm32reservedexception77, __default_handler - .weak __stm32reservedexception78 - .globl __stm32reservedexception78 - .set __stm32reservedexception78, __default_handler - .weak __stm32reservedexception79 - .globl __stm32reservedexception79 - .set __stm32reservedexception79, __default_handler - .weak __stm32reservedexception80 - .globl __stm32reservedexception80 - .set __stm32reservedexception80, __default_handler - .weak __irq_fpu - .globl __irq_fpu - .set __irq_fpu, __default_handler - .weak __reserved - .globl __reserved - .set __reserved, __default_handler diff --git a/STM32F3/variants/discovery_f3/stm32_vector_table.S b/STM32F3/variants/discovery_f3/stm32_vector_table.S deleted file mode 100644 index f68fa4b..0000000 --- a/STM32F3/variants/discovery_f3/stm32_vector_table.S +++ /dev/null @@ -1,134 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2011 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ /* STM32F3 performance line vector table */ #include - .section ".stm32.interrupt_vector" - - .globl __stm32_vector_table - .type __stm32_vector_table, %object - -__stm32_vector_table: -/* CM4 core interrupts */ - .long __msp_init - .long __exc_reset - .long __exc_nmi - .long __exc_hardfault - .long __exc_memmanage - .long __exc_busfault - .long __exc_usagefault - .long __stm32reservedexception7 - .long __stm32reservedexception8 - .long __stm32reservedexception9 - .long __stm32reservedexception10 - .long __exc_svc - .long __exc_debug_monitor - .long __stm32reservedexception13 - .long __exc_pendsv - .long __exc_systick -/* Peripheral interrupts */ - .long __irq_wwdg - .long __irq_pvd - .long __irq_tamp_stamp - .long __irq_rtc_wkup - .long __irq_flash - .long __irq_rcc - .long __irq_exti0 - .long __irq_exti1 - .long __irq_exti2 - .long __irq_exti3 - .long __irq_exti4 - .long __irq_dma1_ch1 - .long __irq_dma1_ch2 - .long __irq_dma1_ch3 - .long __irq_dma1_ch4 - .long __irq_dma1_ch5 - .long __irq_dma1_ch6 - .long __irq_dma1_ch7 - .long __irq_adc1_2 - .long __irq_usb_hp_can_tx - .long __irq_usb_lp_can_rx0 - .long __irq_can_rx1 - .long __irq_can_sce - .long __irq_exti9_5 - .long __irq_tim1_brk_tim15 - .long __irq_tim1_up_tim16 - .long __irq_tim1_trg_com_tim17 - .long __irq_tim1_cc - .long __irq_tim2 - .long __irq_tim3 - .long __irq_tim4 - .long __irq_i2c1_ev - .long __irq_i2c1_er - .long __irq_i2c2_ev - .long __irq_i2c2_er - .long __irq_spi1 - .long __irq_spi2 - .long __irq_usart1 - .long __irq_usart2 - .long __irq_usart3 - .long __irq_exti15_10 - .long __irq_rtc_alarm - .long __irq_usb_wkup - - .long __irq_tim8_brk - .long __irq_tim8_up - .long __irq_tim8_trg_com - .long __irq_tim8_cc - .long __irq_adc3 - .long __stm32reservedexception48 - .long __stm32reservedexception49 - .long __stm32reservedexception50 - .long __irq_spi3 - .long __irq_uart4 - .long __irq_uart5 - .long __irq_tim6_dacunder - .long __irq_tim7 - .long __irq_dma2_ch1 - .long __irq_dma2_ch2 - .long __irq_dma2_ch3 - .long __irq_dma2_ch4 - .long __irq_dma2_ch5 - .long __irq_adc4 - .long __stm32reservedexception62 - .long __stm32reservedexception63 - .long __irq_comp123 - .long __irq_comp456 - .long __irq_comp7 - .long __stm32reservedexception67 - .long __stm32reservedexception68 - .long __stm32reservedexception69 - .long __stm32reservedexception70 - .long __stm32reservedexception71 - .long __stm32reservedexception72 - .long __stm32reservedexception73 - .long __irq_usb_hp - .long __irq_usb_lp - .long __irq_usb_wkup2 - .long __stm32reservedexception77 - .long __stm32reservedexception78 - .long __stm32reservedexception79 - .long __stm32reservedexception80 - .long __irq_fpu - - .size __stm32_vector_table, . - __stm32_vector_table diff --git a/STM32F3/variants/discovery_f3/wirish/start.S b/STM32F3/variants/discovery_f3/wirish/start.S deleted file mode 100644 index 8b181aa..0000000 --- a/STM32F3/variants/discovery_f3/wirish/start.S +++ /dev/null @@ -1,57 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2011 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/* - * This file is a modified version of a file obtained from - * CodeSourcery Inc. (now part of Mentor Graphics Corp.), in which the - * following text appeared: - * - * The authors hereby grant permission to use, copy, modify, distribute, - * and license this software and its documentation for any purpose, provided - * that existing copyright notices are retained in all copies and that this - * notice is included verbatim in any distributions. No written agreement, - * license, or royalty fee is required for any of the authorized uses. - * Modifications to this software may be copyrighted by their authors - * and need not follow the licensing terms described here, provided that - * the new terms are clearly indicated on the first page of each file where - * they apply. - */ - - .text - .code 16 - .thumb_func - - .globl __start__ - .type __start__, %function -__start__: - .fnstart - ldr r1,=__msp_init - mov sp,r1 - ldr r1,=start_c - bx r1 - .pool - .cantunwind - .fnend diff --git a/STM32F3/variants/discovery_f3/wirish/start_c.c b/STM32F3/variants/discovery_f3/wirish/start_c.c deleted file mode 100644 index 655fefb..0000000 --- a/STM32F3/variants/discovery_f3/wirish/start_c.c +++ /dev/null @@ -1,95 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2011 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/* - * This file is a modified version of a file obtained from - * CodeSourcery Inc. (now part of Mentor Graphics Corp.), in which the - * following text appeared: - * - * Copyright (c) 2006, 2007 CodeSourcery Inc - * - * The authors hereby grant permission to use, copy, modify, distribute, - * and license this software and its documentation for any purpose, provided - * that existing copyright notices are retained in all copies and that this - * notice is included verbatim in any distributions. No written agreement, - * license, or royalty fee is required for any of the authorized uses. - * Modifications to this software may be copyrighted by their authors - * and need not follow the licensing terms described here, provided that - * the new terms are clearly indicated on the first page of each file where - * they apply. - */ - -#include - -extern void __libc_init_array(void); - -extern int main(int, char**, char**); - -extern void exit(int) __attribute__((noreturn, weak)); - -/* The linker must ensure that these are at least 4-byte aligned. */ -extern char __data_start__, __data_end__; -extern char __bss_start__, __bss_end__; - -struct rom_img_cfg { - int *img_start; -}; - -extern char _lm_rom_img_cfgp; - -void __attribute__((noreturn)) start_c(void) { - struct rom_img_cfg *img_cfg = (struct rom_img_cfg*)&_lm_rom_img_cfgp; - int *src = img_cfg->img_start; - int *dst = (int*)&__data_start__; - int exit_code; - - /* Initialize .data, if necessary. */ - if (src != dst) { - int *end = (int*)&__data_end__; - while (dst < end) { - *dst++ = *src++; - } - } - - /* Zero .bss. */ - dst = (int*)&__bss_start__; - while (dst < (int*)&__bss_end__) { - *dst++ = 0; - } - - /* Run initializers. */ - __libc_init_array(); - - /* Jump to main. */ - exit_code = main(0, 0, 0); - if (exit) { - exit(exit_code); - } - - /* If exit is NULL, make sure we don't return. */ - for (;;) - continue; -} From 45b51dea1208fec87077ce48808481b1d7a02406 Mon Sep 17 00:00:00 2001 From: Victor Lamoine Date: Fri, 20 Apr 2018 14:38:57 +0200 Subject: [PATCH 327/351] Add simple SPI slave example --- .../SPI/examples/spi_slave/spi_slave.ino | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 STM32F1/libraries/SPI/examples/spi_slave/spi_slave.ino diff --git a/STM32F1/libraries/SPI/examples/spi_slave/spi_slave.ino b/STM32F1/libraries/SPI/examples/spi_slave/spi_slave.ino new file mode 100644 index 0000000..f0122d6 --- /dev/null +++ b/STM32F1/libraries/SPI/examples/spi_slave/spi_slave.ino @@ -0,0 +1,46 @@ +// SPI slave example +// STM32 acts as a SPI slave an reads 8 bit data frames over SPI +// The data sent to the master is a simple count (0, 1, 2, 3) that is incremented +// each time a data frame is received. +// Serial output is here for debug + +#include +#include + +void setupSPI(void) +{ + pinMode(PA7, INPUT); // MOSI1 + pinMode(PA6, INPUT); // MISO1 + pinMode(PA5, INPUT); // SCK + pinMode(BOARD_SPI_DEFAULT_SS, INPUT); // SS + + // Select SPI1 + SPI.setModule(1); + // The clock value is not used + SPI.beginTransactionSlave(SPISettings(18000000, MSBFIRST, SPI_MODE0, DATA_SIZE_8BIT)); +} + +void setup() +{ + Serial.begin(115200); + delay(100); + + // Data that master will receive when transferring a data frame over SPI + SPI.dev()->regs->DR = 0; + setupSPI(); +} + +uint8_t count(0); +void loop() +{ + // Blocking call to read SPI message + uint8_t msg(SPI.read()); + Serial.print("Received = 0b"); + Serial.print(msg, BIN); + Serial.print(", 0x"); + Serial.print(msg, HEX); + Serial.print(", "); + Serial.println(msg); + // Next data frame that will be received by master + SPI.dev()->regs->DR = ++count; +} From 6e814ad5ca0b34e5f21e85cecb51e8df0f11e34f Mon Sep 17 00:00:00 2001 From: Victor Lamoine Date: Fri, 20 Apr 2018 17:27:45 +0200 Subject: [PATCH 328/351] Add simple SPI slave example --- .../SPI/examples/spi_slave/spi_slave.ino | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/STM32F1/libraries/SPI/examples/spi_slave/spi_slave.ino b/STM32F1/libraries/SPI/examples/spi_slave/spi_slave.ino index f0122d6..2a26c8b 100644 --- a/STM32F1/libraries/SPI/examples/spi_slave/spi_slave.ino +++ b/STM32F1/libraries/SPI/examples/spi_slave/spi_slave.ino @@ -9,14 +9,11 @@ void setupSPI(void) { - pinMode(PA7, INPUT); // MOSI1 - pinMode(PA6, INPUT); // MISO1 - pinMode(PA5, INPUT); // SCK + // MOSI, MISO, SCK PINs are set by the library pinMode(BOARD_SPI_DEFAULT_SS, INPUT); // SS - // Select SPI1 - SPI.setModule(1); // The clock value is not used + // SPI1 is selected by default SPI.beginTransactionSlave(SPISettings(18000000, MSBFIRST, SPI_MODE0, DATA_SIZE_8BIT)); } @@ -24,9 +21,6 @@ void setup() { Serial.begin(115200); delay(100); - - // Data that master will receive when transferring a data frame over SPI - SPI.dev()->regs->DR = 0; setupSPI(); } @@ -34,13 +28,12 @@ uint8_t count(0); void loop() { // Blocking call to read SPI message - uint8_t msg(SPI.read()); - Serial.print("Received = 0b"); + uint8_t msg = SPI.transfer(++count); + Serial.print("a Received = 0b"); Serial.print(msg, BIN); Serial.print(", 0x"); Serial.print(msg, HEX); Serial.print(", "); Serial.println(msg); - // Next data frame that will be received by master - SPI.dev()->regs->DR = ++count; } + From a3ae580d192e7e53f6a5023fcac75253ef0cc050 Mon Sep 17 00:00:00 2001 From: Victor Lamoine Date: Fri, 20 Apr 2018 17:42:31 +0200 Subject: [PATCH 329/351] Add simple SPI slave example --- STM32F1/libraries/SPI/examples/spi_slave/spi_slave.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/libraries/SPI/examples/spi_slave/spi_slave.ino b/STM32F1/libraries/SPI/examples/spi_slave/spi_slave.ino index 2a26c8b..64f8d50 100644 --- a/STM32F1/libraries/SPI/examples/spi_slave/spi_slave.ino +++ b/STM32F1/libraries/SPI/examples/spi_slave/spi_slave.ino @@ -29,7 +29,7 @@ void loop() { // Blocking call to read SPI message uint8_t msg = SPI.transfer(++count); - Serial.print("a Received = 0b"); + Serial.print("Received = 0b"); Serial.print(msg, BIN); Serial.print(", 0x"); Serial.print(msg, HEX); From 652569c079dbe9230e30ebd445a04d67dec6c4d8 Mon Sep 17 00:00:00 2001 From: Victor Lamoine Date: Fri, 20 Apr 2018 19:01:32 +0200 Subject: [PATCH 330/351] Add simple SPI slave example --- STM32F1/libraries/SPI/examples/spi_slave/spi_slave.ino | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/STM32F1/libraries/SPI/examples/spi_slave/spi_slave.ino b/STM32F1/libraries/SPI/examples/spi_slave/spi_slave.ino index 64f8d50..71865c5 100644 --- a/STM32F1/libraries/SPI/examples/spi_slave/spi_slave.ino +++ b/STM32F1/libraries/SPI/examples/spi_slave/spi_slave.ino @@ -1,7 +1,7 @@ -// SPI slave example -// STM32 acts as a SPI slave an reads 8 bit data frames over SPI -// The data sent to the master is a simple count (0, 1, 2, 3) that is incremented -// each time a data frame is received. +// SPI full-duplex slave example +// STM32 acts as a SPI slave and reads 8 bit data frames over SPI. +// Master also gets a reply from the slave, which is a a simple count (0, 1, 2, 3) +// that is incremented each time a data frame is received. // Serial output is here for debug #include From 5664dbc7aa32667a836b1c09b121ad7fa6e194e6 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Sun, 22 Apr 2018 14:31:56 +1000 Subject: [PATCH 331/351] Add hold in bootloader using bkp register 10 --- STM32F1/cores/maple/usb_serial.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/STM32F1/cores/maple/usb_serial.cpp b/STM32F1/cores/maple/usb_serial.cpp index e6d5cb0..40eaa65 100644 --- a/STM32F1/cores/maple/usb_serial.cpp +++ b/STM32F1/cores/maple/usb_serial.cpp @@ -37,7 +37,7 @@ #include #include #include - +#include #include "wirish.h" /* @@ -322,6 +322,11 @@ static void rxHook(unsigned hook __attribute__((unused)), void *ignored __attrib #ifdef SERIAL_USB // Got the magic sequence -> reset, presumably into the bootloader. // Return address is wait_reset, but we must set the thumb bit. + bkp_init(); + bkp_enable_writes(); + bkp_write(10, 0x424C); + bkp_disable_writes(); + uintptr_t target = (uintptr_t)wait_reset | 0x1; asm volatile("mov r0, %[stack_top] \n\t" // Reset stack "mov sp, r0 \n\t" From cb8b30bd6fe91964a0e7461d144977434f555c0b Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Sun, 22 Apr 2018 17:06:22 +1000 Subject: [PATCH 332/351] add partial support for the new USB HID bootloader --- STM32F1/platform.txt | 12 ++++++++++++ tools/win/hid_flash/hid-flash.exe | Bin 0 -> 75156 bytes 2 files changed, 12 insertions(+) create mode 100644 tools/win/hid_flash/hid-flash.exe diff --git a/STM32F1/platform.txt b/STM32F1/platform.txt index 627e5da..b1cf69d 100644 --- a/STM32F1/platform.txt +++ b/STM32F1/platform.txt @@ -161,3 +161,15 @@ tools.jlink_upload.path.linux64={runtime.hardware.path}/tools/linux64 tools.jlink_upload.upload.params.verbose=-d tools.jlink_upload.upload.params.quiet=n tools.jlink_upload.upload.pattern="{path}/{cmd}" "{build.path}/{build.project_name}.bin" + +# HID upload +tools.hid_upload.cmd=hid_upload +tools.hid_upload.cmd.windows=hid_upload.bat +tools.hid_upload.cmd.macosx=hid_upload +tools.hid_upload.path={runtime.hardware.path}/tools/win +tools.hid_upload.path.macosx={runtime.hardware.path}/tools/macosx +tools.hid_upload.path.linux={runtime.hardware.path}/tools/linux +tools.hid_upload.path.linux64={runtime.hardware.path}/tools/linux64 +tools.hid_upload.upload.params.verbose=-d +tools.hid_upload.upload.params.quiet=n +tools.hid_upload.upload.pattern="{path}/{cmd}" {serial.port.file} {upload.altID} {upload.usbID} "{build.path}/{build.project_name}.bin" \ No newline at end of file diff --git a/tools/win/hid_flash/hid-flash.exe b/tools/win/hid_flash/hid-flash.exe new file mode 100644 index 0000000000000000000000000000000000000000..9808b20284a485f8f941adf0ff422adbc0ccebf3 GIT binary patch literal 75156 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 g*f|?LrW#fYdRSG31X~0{D{Q^#A|> literal 0 HcmV?d00001 From 6e4a80f1068fd88aa27ad33237cfd3d2c2db72f5 Mon Sep 17 00:00:00 2001 From: Victor Lamoine Date: Mon, 23 Apr 2018 19:27:37 +0200 Subject: [PATCH 333/351] Add simple SPI slave example --- STM32F1/libraries/SPI/examples/spi_slave/spi_slave.ino | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/STM32F1/libraries/SPI/examples/spi_slave/spi_slave.ino b/STM32F1/libraries/SPI/examples/spi_slave/spi_slave.ino index 71865c5..fa2930a 100644 --- a/STM32F1/libraries/SPI/examples/spi_slave/spi_slave.ino +++ b/STM32F1/libraries/SPI/examples/spi_slave/spi_slave.ino @@ -9,11 +9,9 @@ void setupSPI(void) { - // MOSI, MISO, SCK PINs are set by the library - pinMode(BOARD_SPI_DEFAULT_SS, INPUT); // SS - // The clock value is not used // SPI1 is selected by default + // MOSI, MISO, SCK and NSS PINs are set by the library SPI.beginTransactionSlave(SPISettings(18000000, MSBFIRST, SPI_MODE0, DATA_SIZE_8BIT)); } From 1abb3f1ca53bb4a7cd8738d3a6d2676589b4a22e Mon Sep 17 00:00:00 2001 From: stevstrong Date: Wed, 25 Apr 2018 23:22:17 +0200 Subject: [PATCH 334/351] Update Wire.cpp bugfix hw I2C unrecognized addresses 0x76, 0x77 --- STM32F1/libraries/Wire/Wire.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/libraries/Wire/Wire.cpp b/STM32F1/libraries/Wire/Wire.cpp index dbf4c66..192b133 100644 --- a/STM32F1/libraries/Wire/Wire.cpp +++ b/STM32F1/libraries/Wire/Wire.cpp @@ -50,7 +50,7 @@ uint8 TwoWire::process(uint8 stop) { res = EOTHER; } i2c_disable(sel_hard); - i2c_master_enable(sel_hard, (I2C_BUS_RESET | dev_flags)); + i2c_master_enable(sel_hard, dev_flags); } return res; } From e1ae43c826af67e45207414ddd67769738ec1d76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Fri, 27 Apr 2018 14:48:41 +0100 Subject: [PATCH 335/351] Fixed missing return value. --- STM32F1/libraries/Wire/utility/WireBase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/libraries/Wire/utility/WireBase.cpp b/STM32F1/libraries/Wire/utility/WireBase.cpp index 220d845..02c8ed3 100644 --- a/STM32F1/libraries/Wire/utility/WireBase.cpp +++ b/STM32F1/libraries/Wire/utility/WireBase.cpp @@ -71,7 +71,7 @@ uint8 WireBase::endTransmission(bool stop) { } uint8 WireBase::endTransmission(){ - endTransmission(true); + return endTransmission(true); } //TODO: Add the ability to queue messages (adding a boolean to end of function From 6c33d73f63418b46a0c71385fdd6c67e60ce416a Mon Sep 17 00:00:00 2001 From: victorpv Date: Thu, 3 May 2018 11:39:17 -0500 Subject: [PATCH 336/351] Add SDIO pin definitions to the Maple RET6 variant It was missing, but needed since that variant (RET6) includes the SDIO peripheral, so the files are included in the compilation. --- STM32F1/variants/maple_ret6/board/board.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/STM32F1/variants/maple_ret6/board/board.h b/STM32F1/variants/maple_ret6/board/board.h index 86d94f0..4f6fae7 100644 --- a/STM32F1/variants/maple_ret6/board/board.h +++ b/STM32F1/variants/maple_ret6/board/board.h @@ -102,6 +102,16 @@ #define BOARD_USB_DISC_DEV GPIOC #define BOARD_USB_DISC_BIT 12 +/* + * SDIO Pins + */ +#define BOARD_SDIO_D0 PC8 +#define BOARD_SDIO_D1 PC9 +#define BOARD_SDIO_D2 PC10 +#define BOARD_SDIO_D3 PC11 +#define BOARD_SDIO_CLK PC12 +#define BOARD_SDIO_CMD PD2 + /* Pin aliases: these give the GPIO port/bit for each pin as an * enum. These are optional, but recommended. They make it easier to * write code using low-level GPIO functionality. */ @@ -117,4 +127,4 @@ enum { //15 16 17 18 19 20 21 22 23 24 25 26 27 28 -//29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 \ No newline at end of file +//29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 From 4ec1b0f0cd3835e743ecc1835ba144f4230f5534 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Thu, 10 May 2018 20:25:02 +1000 Subject: [PATCH 337/351] Removed references to robotis bootloader, and also redundant usb reset code that used the wdt (possibly used by the robotis bootloader) --- STM32F1/cores/maple/usb_serial.cpp | 50 ++++++------------- STM32F1/variants/STM32VLD/wirish/boards.cpp | 6 +-- .../generic_gd32f103c/wirish/boards.cpp | 6 +-- .../generic_stm32f103c/wirish/boards.cpp | 6 +-- .../generic_stm32f103r/wirish/boards.cpp | 6 +-- .../generic_stm32f103r8/wirish/boards.cpp | 6 +-- .../generic_stm32f103t/wirish/boards.cpp | 6 +-- .../generic_stm32f103v/wirish/boards.cpp | 6 +-- .../generic_stm32f103vb/wirish/boards.cpp | 6 +-- .../generic_stm32f103z/wirish/boards.cpp | 6 +-- .../hytiny_stm32f103t/wirish/boards.cpp | 6 +-- STM32F1/variants/maple/wirish/boards.cpp | 6 +-- STM32F1/variants/maple_mini/wirish/boards.cpp | 6 +-- STM32F1/variants/maple_ret6/wirish/boards.cpp | 6 +-- STM32F1/variants/microduino/wirish/boards.cpp | 6 +-- .../variants/nucleo_f103rb/wirish/boards.cpp | 6 +-- 16 files changed, 30 insertions(+), 110 deletions(-) diff --git a/STM32F1/cores/maple/usb_serial.cpp b/STM32F1/cores/maple/usb_serial.cpp index 40eaa65..9f52177 100644 --- a/STM32F1/cores/maple/usb_serial.cpp +++ b/STM32F1/cores/maple/usb_serial.cpp @@ -263,20 +263,12 @@ static void ifaceSetupHook(unsigned hook __attribute__((unused)), void *requestv break; } #endif - -#if defined(BOOTLOADER_robotis) - uint8 dtr = usb_cdcacm_get_dtr(); - uint8 rts = usb_cdcacm_get_rts(); - - if (rts && !dtr) { - reset_state = DTR_NEGEDGE; - } -#endif - +#if false if ((usb_cdcacm_get_baud() == 1200) && (reset_state == DTR_NEGEDGE)) { iwdg_init(IWDG_PRE_4, 10); while (1); } +#endif } #define RESET_DELAY 100000 @@ -287,45 +279,39 @@ static void wait_reset(void) { } #endif + #define STACK_TOP 0x20000800 #define EXC_RETURN 0xFFFFFFF9 #define DEFAULT_CPSR 0x61000000 static void rxHook(unsigned hook __attribute__((unused)), void *ignored __attribute__((unused))) { +static const uint8 magic[4] = {'1', 'E', 'A', 'F'}; /* FIXME this is mad buggy; we need a new reset sequence. E.g. NAK * after each RX means you can't reset if any bytes are waiting. */ if (reset_state == DTR_NEGEDGE) { - reset_state = DTR_LOW; - - if (usb_cdcacm_data_available() >= 4) { - // The magic reset sequence is "1EAF". -#ifdef SERIAL_USB - static const uint8 magic[4] = {'1', 'E', 'A', 'F'}; -#else - #if defined(BOOTLOADER_robotis) - static const uint8 magic[4] = {'C', 'M', '9', 'X'}; - #else - static const uint8 magic[4] = {'1', 'E', 'A', 'F'}; - #endif -#endif + if (usb_cdcacm_data_available() >= 4) + { uint8 chkBuf[4]; // Peek at the waiting bytes, looking for reset sequence, // bailing on mismatch. usb_cdcacm_peek_ex(chkBuf, usb_cdcacm_data_available() - 4, 4); for (unsigned i = 0; i < sizeof(magic); i++) { - if (chkBuf[i] != magic[i]) { + if (chkBuf[i] != magic[i]) + { + reset_state = DTR_LOW; return; } } #ifdef SERIAL_USB + // The magic reset sequence is "1EAF". // Got the magic sequence -> reset, presumably into the bootloader. // Return address is wait_reset, but we must set the thumb bit. - bkp_init(); - bkp_enable_writes(); - bkp_write(10, 0x424C); - bkp_disable_writes(); + bkp_init(); + bkp_enable_writes(); + bkp_write(10, 0x424C); + bkp_disable_writes(); uintptr_t target = (uintptr_t)wait_reset | 0x1; asm volatile("mov r0, %[stack_top] \n\t" // Reset stack @@ -350,15 +336,9 @@ static void rxHook(unsigned hook __attribute__((unused)), void *ignored __attrib [cpsr] "r" (DEFAULT_CPSR) : "r0", "r1", "r2"); #endif - -#if defined(BOOTLOADER_robotis) - iwdg_init(IWDG_PRE_4, 10); -#endif - /* Can't happen. */ ASSERT_FAULT(0); } } } - -#endif // BOARD_HAVE_SERIALUSB +#endif // BOARD_HAVE_SERIALUSB \ No newline at end of file diff --git a/STM32F1/variants/STM32VLD/wirish/boards.cpp b/STM32F1/variants/STM32VLD/wirish/boards.cpp index 5274e7a..7b7e9a6 100644 --- a/STM32F1/variants/STM32VLD/wirish/boards.cpp +++ b/STM32F1/variants/STM32VLD/wirish/boards.cpp @@ -147,11 +147,7 @@ static void setup_clocks(void) { #if defined(BOOTLOADER_maple) #define USER_ADDR_ROM 0x08005000 #else - #if defined(BOOTLOADER_robotis) - #define USER_ADDR_ROM 0x08003000 - #else - #define USER_ADDR_ROM 0x08000000 - #endif + #define USER_ADDR_ROM 0x08000000 #endif #define USER_ADDR_RAM 0x20000C00 extern char __text_start__; diff --git a/STM32F1/variants/generic_gd32f103c/wirish/boards.cpp b/STM32F1/variants/generic_gd32f103c/wirish/boards.cpp index fcb85b2..ef1f2ad 100644 --- a/STM32F1/variants/generic_gd32f103c/wirish/boards.cpp +++ b/STM32F1/variants/generic_gd32f103c/wirish/boards.cpp @@ -147,11 +147,7 @@ static void setup_clocks(void) { #if defined(BOOTLOADER_maple) #define USER_ADDR_ROM 0x08005000 #else - #if defined(BOOTLOADER_robotis) - #define USER_ADDR_ROM 0x08003000 - #else - #define USER_ADDR_ROM 0x08000000 - #endif + #define USER_ADDR_ROM 0x08000000 #endif #define USER_ADDR_RAM 0x20000C00 extern char __text_start__; diff --git a/STM32F1/variants/generic_stm32f103c/wirish/boards.cpp b/STM32F1/variants/generic_stm32f103c/wirish/boards.cpp index 36fcb3e..08c34d1 100644 --- a/STM32F1/variants/generic_stm32f103c/wirish/boards.cpp +++ b/STM32F1/variants/generic_stm32f103c/wirish/boards.cpp @@ -147,11 +147,7 @@ static void setup_clocks(void) { #if defined(BOOTLOADER_maple) #define USER_ADDR_ROM 0x08005000 #else - #if defined(BOOTLOADER_robotis) - #define USER_ADDR_ROM 0x08003000 - #else - #define USER_ADDR_ROM 0x08000000 - #endif + #define USER_ADDR_ROM 0x08000000 #endif #define USER_ADDR_RAM 0x20000C00 extern char __text_start__; diff --git a/STM32F1/variants/generic_stm32f103r/wirish/boards.cpp b/STM32F1/variants/generic_stm32f103r/wirish/boards.cpp index fcb85b2..ef1f2ad 100644 --- a/STM32F1/variants/generic_stm32f103r/wirish/boards.cpp +++ b/STM32F1/variants/generic_stm32f103r/wirish/boards.cpp @@ -147,11 +147,7 @@ static void setup_clocks(void) { #if defined(BOOTLOADER_maple) #define USER_ADDR_ROM 0x08005000 #else - #if defined(BOOTLOADER_robotis) - #define USER_ADDR_ROM 0x08003000 - #else - #define USER_ADDR_ROM 0x08000000 - #endif + #define USER_ADDR_ROM 0x08000000 #endif #define USER_ADDR_RAM 0x20000C00 extern char __text_start__; diff --git a/STM32F1/variants/generic_stm32f103r8/wirish/boards.cpp b/STM32F1/variants/generic_stm32f103r8/wirish/boards.cpp index 5274e7a..7b7e9a6 100644 --- a/STM32F1/variants/generic_stm32f103r8/wirish/boards.cpp +++ b/STM32F1/variants/generic_stm32f103r8/wirish/boards.cpp @@ -147,11 +147,7 @@ static void setup_clocks(void) { #if defined(BOOTLOADER_maple) #define USER_ADDR_ROM 0x08005000 #else - #if defined(BOOTLOADER_robotis) - #define USER_ADDR_ROM 0x08003000 - #else - #define USER_ADDR_ROM 0x08000000 - #endif + #define USER_ADDR_ROM 0x08000000 #endif #define USER_ADDR_RAM 0x20000C00 extern char __text_start__; diff --git a/STM32F1/variants/generic_stm32f103t/wirish/boards.cpp b/STM32F1/variants/generic_stm32f103t/wirish/boards.cpp index 5274e7a..7b7e9a6 100644 --- a/STM32F1/variants/generic_stm32f103t/wirish/boards.cpp +++ b/STM32F1/variants/generic_stm32f103t/wirish/boards.cpp @@ -147,11 +147,7 @@ static void setup_clocks(void) { #if defined(BOOTLOADER_maple) #define USER_ADDR_ROM 0x08005000 #else - #if defined(BOOTLOADER_robotis) - #define USER_ADDR_ROM 0x08003000 - #else - #define USER_ADDR_ROM 0x08000000 - #endif + #define USER_ADDR_ROM 0x08000000 #endif #define USER_ADDR_RAM 0x20000C00 extern char __text_start__; diff --git a/STM32F1/variants/generic_stm32f103v/wirish/boards.cpp b/STM32F1/variants/generic_stm32f103v/wirish/boards.cpp index ddeaa57..fc90f36 100644 --- a/STM32F1/variants/generic_stm32f103v/wirish/boards.cpp +++ b/STM32F1/variants/generic_stm32f103v/wirish/boards.cpp @@ -153,11 +153,7 @@ static void setup_clocks(void) { #if defined(BOOTLOADER_maple) #define USER_ADDR_ROM 0x08005000 #else - #if defined(BOOTLOADER_robotis) - #define USER_ADDR_ROM 0x08003000 - #else - #define USER_ADDR_ROM 0x08000000 - #endif + #define USER_ADDR_ROM 0x08000000 #endif #define USER_ADDR_RAM 0x20000C00 extern char __text_start__; diff --git a/STM32F1/variants/generic_stm32f103vb/wirish/boards.cpp b/STM32F1/variants/generic_stm32f103vb/wirish/boards.cpp index ddeaa57..fc90f36 100644 --- a/STM32F1/variants/generic_stm32f103vb/wirish/boards.cpp +++ b/STM32F1/variants/generic_stm32f103vb/wirish/boards.cpp @@ -153,11 +153,7 @@ static void setup_clocks(void) { #if defined(BOOTLOADER_maple) #define USER_ADDR_ROM 0x08005000 #else - #if defined(BOOTLOADER_robotis) - #define USER_ADDR_ROM 0x08003000 - #else - #define USER_ADDR_ROM 0x08000000 - #endif + #define USER_ADDR_ROM 0x08000000 #endif #define USER_ADDR_RAM 0x20000C00 extern char __text_start__; diff --git a/STM32F1/variants/generic_stm32f103z/wirish/boards.cpp b/STM32F1/variants/generic_stm32f103z/wirish/boards.cpp index fcb85b2..ef1f2ad 100644 --- a/STM32F1/variants/generic_stm32f103z/wirish/boards.cpp +++ b/STM32F1/variants/generic_stm32f103z/wirish/boards.cpp @@ -147,11 +147,7 @@ static void setup_clocks(void) { #if defined(BOOTLOADER_maple) #define USER_ADDR_ROM 0x08005000 #else - #if defined(BOOTLOADER_robotis) - #define USER_ADDR_ROM 0x08003000 - #else - #define USER_ADDR_ROM 0x08000000 - #endif + #define USER_ADDR_ROM 0x08000000 #endif #define USER_ADDR_RAM 0x20000C00 extern char __text_start__; diff --git a/STM32F1/variants/hytiny_stm32f103t/wirish/boards.cpp b/STM32F1/variants/hytiny_stm32f103t/wirish/boards.cpp index 0a358ee..d7b6edc 100644 --- a/STM32F1/variants/hytiny_stm32f103t/wirish/boards.cpp +++ b/STM32F1/variants/hytiny_stm32f103t/wirish/boards.cpp @@ -147,11 +147,7 @@ static void setup_clocks(void) { #if defined(BOOTLOADER_maple) #define USER_ADDR_ROM 0x08005000 #else - #if defined(BOOTLOADER_robotis) - #define USER_ADDR_ROM 0x08003000 - #else - #define USER_ADDR_ROM 0x08000000 - #endif + #define USER_ADDR_ROM 0x08000000 #endif #define USER_ADDR_RAM 0x20000C00 extern char __text_start__; diff --git a/STM32F1/variants/maple/wirish/boards.cpp b/STM32F1/variants/maple/wirish/boards.cpp index fcb85b2..ef1f2ad 100644 --- a/STM32F1/variants/maple/wirish/boards.cpp +++ b/STM32F1/variants/maple/wirish/boards.cpp @@ -147,11 +147,7 @@ static void setup_clocks(void) { #if defined(BOOTLOADER_maple) #define USER_ADDR_ROM 0x08005000 #else - #if defined(BOOTLOADER_robotis) - #define USER_ADDR_ROM 0x08003000 - #else - #define USER_ADDR_ROM 0x08000000 - #endif + #define USER_ADDR_ROM 0x08000000 #endif #define USER_ADDR_RAM 0x20000C00 extern char __text_start__; diff --git a/STM32F1/variants/maple_mini/wirish/boards.cpp b/STM32F1/variants/maple_mini/wirish/boards.cpp index 5274e7a..7b7e9a6 100644 --- a/STM32F1/variants/maple_mini/wirish/boards.cpp +++ b/STM32F1/variants/maple_mini/wirish/boards.cpp @@ -147,11 +147,7 @@ static void setup_clocks(void) { #if defined(BOOTLOADER_maple) #define USER_ADDR_ROM 0x08005000 #else - #if defined(BOOTLOADER_robotis) - #define USER_ADDR_ROM 0x08003000 - #else - #define USER_ADDR_ROM 0x08000000 - #endif + #define USER_ADDR_ROM 0x08000000 #endif #define USER_ADDR_RAM 0x20000C00 extern char __text_start__; diff --git a/STM32F1/variants/maple_ret6/wirish/boards.cpp b/STM32F1/variants/maple_ret6/wirish/boards.cpp index fcb85b2..ef1f2ad 100644 --- a/STM32F1/variants/maple_ret6/wirish/boards.cpp +++ b/STM32F1/variants/maple_ret6/wirish/boards.cpp @@ -147,11 +147,7 @@ static void setup_clocks(void) { #if defined(BOOTLOADER_maple) #define USER_ADDR_ROM 0x08005000 #else - #if defined(BOOTLOADER_robotis) - #define USER_ADDR_ROM 0x08003000 - #else - #define USER_ADDR_ROM 0x08000000 - #endif + #define USER_ADDR_ROM 0x08000000 #endif #define USER_ADDR_RAM 0x20000C00 extern char __text_start__; diff --git a/STM32F1/variants/microduino/wirish/boards.cpp b/STM32F1/variants/microduino/wirish/boards.cpp index fcb85b2..ef1f2ad 100644 --- a/STM32F1/variants/microduino/wirish/boards.cpp +++ b/STM32F1/variants/microduino/wirish/boards.cpp @@ -147,11 +147,7 @@ static void setup_clocks(void) { #if defined(BOOTLOADER_maple) #define USER_ADDR_ROM 0x08005000 #else - #if defined(BOOTLOADER_robotis) - #define USER_ADDR_ROM 0x08003000 - #else - #define USER_ADDR_ROM 0x08000000 - #endif + #define USER_ADDR_ROM 0x08000000 #endif #define USER_ADDR_RAM 0x20000C00 extern char __text_start__; diff --git a/STM32F1/variants/nucleo_f103rb/wirish/boards.cpp b/STM32F1/variants/nucleo_f103rb/wirish/boards.cpp index f38cbf6..61368ce 100644 --- a/STM32F1/variants/nucleo_f103rb/wirish/boards.cpp +++ b/STM32F1/variants/nucleo_f103rb/wirish/boards.cpp @@ -149,11 +149,7 @@ static void setup_clocks(void) { #if defined(BOOTLOADER_maple) #define USER_ADDR_ROM 0x08005000 #else - #if defined(BOOTLOADER_robotis) - #define USER_ADDR_ROM 0x08003000 - #else - #define USER_ADDR_ROM 0x08000000 - #endif + #define USER_ADDR_ROM 0x08000000 #endif #define USER_ADDR_RAM 0x20000C00 extern char __text_start__; From 8fa6bb45960097be75b6df6fc08705c85d4e4a09 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Fri, 11 May 2018 09:03:04 +1000 Subject: [PATCH 338/351] Remove redundant #if'ed out code from maple hardware_serial.cpp --- STM32F1/cores/maple/HardwareSerial.cpp | 53 -------------------------- 1 file changed, 53 deletions(-) diff --git a/STM32F1/cores/maple/HardwareSerial.cpp b/STM32F1/cores/maple/HardwareSerial.cpp index 024efbc..b25dafc 100644 --- a/STM32F1/cores/maple/HardwareSerial.cpp +++ b/STM32F1/cores/maple/HardwareSerial.cpp @@ -37,59 +37,6 @@ #include #include -#if 0 - - #define DEFINE_HWSERIAL(name, n) \ - HardwareSerial name(USART##n, \ - BOARD_USART##n##_TX_PIN, \ - BOARD_USART##n##_RX_PIN) - - #define DEFINE_HWSERIAL_UART(name, n) \ - HardwareSerial name(UART##n, \ - BOARD_USART##n##_TX_PIN, \ - BOARD_USART##n##_RX_PIN) - - #ifdef SERIAL_USB - #if BOARD_HAVE_USART1 - DEFINE_HWSERIAL(Serial1, 1); - #endif - #if BOARD_HAVE_USART2 - DEFINE_HWSERIAL(Serial2, 2); - #endif - #if BOARD_HAVE_USART3 - DEFINE_HWSERIAL(Serial3, 3); - #endif - #if BOARD_HAVE_UART4 - DEFINE_HWSERIAL_UART(Serial4, 4); - #endif - #if BOARD_HAVE_UART5 - DEFINE_HWSERIAL_UART(Serial5, 5); - #endif - #if BOARD_HAVE_USART6 - DEFINE_HWSERIAL_UART(Serial6, 6); - #endif - #else - #if BOARD_HAVE_USART1 - DEFINE_HWSERIAL(Serial, 1); - #endif - #if BOARD_HAVE_USART2 - DEFINE_HWSERIAL(Serial1, 2); - #endif - #if BOARD_HAVE_USART3 - DEFINE_HWSERIAL(Serial2, 3); - #endif - #if BOARD_HAVE_UART4 - DEFINE_HWSERIAL_UART(Serial3, 4); - #endif - #if BOARD_HAVE_UART5 - DEFINE_HWSERIAL_UART(Serial4, 5); - #endif - #if BOARD_HAVE_USART6 - DEFINE_HWSERIAL_UART(Serial5, 6); - #endif - #endif - -#endif HardwareSerial::HardwareSerial(usart_dev *usart_device, uint8 tx_pin, uint8 rx_pin) { From 84c5a86109c085cf2d4a5a325273351a9078ee28 Mon Sep 17 00:00:00 2001 From: Alexandr Zarubkin Date: Mon, 21 May 2018 11:47:38 +0300 Subject: [PATCH 339/351] Changed prescaler variable type to uint32. Fixes #520. Signed-off-by: Alexandr Zarubkin --- STM32F1/libraries/RTClock/src/RTClock.cpp | 2 +- STM32F1/libraries/RTClock/src/RTClock.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/STM32F1/libraries/RTClock/src/RTClock.cpp b/STM32F1/libraries/RTClock/src/RTClock.cpp index f6907ed..8d65c1c 100755 --- a/STM32F1/libraries/RTClock/src/RTClock.cpp +++ b/STM32F1/libraries/RTClock/src/RTClock.cpp @@ -39,7 +39,7 @@ }//end RTC - RTClock::RTClock(rtc_clk_src src, uint16 prescaler ) { + RTClock::RTClock(rtc_clk_src src, uint32 prescaler ) { switch (src) { case RTCSEL_LSE : { diff --git a/STM32F1/libraries/RTClock/src/RTClock.h b/STM32F1/libraries/RTClock/src/RTClock.h index a225c94..7e758db 100755 --- a/STM32F1/libraries/RTClock/src/RTClock.h +++ b/STM32F1/libraries/RTClock/src/RTClock.h @@ -41,7 +41,7 @@ class RTClock { public: RTClock(); RTClock(rtc_clk_src src ); - RTClock(rtc_clk_src src, uint16 prescaler ); + RTClock(rtc_clk_src src, uint32 prescaler ); //~RTClock(); //to implement void breakTime(time_t epoch_time, tm_t & tmm); From 134dad770c4da01557366f40cdd29c727b24cb37 Mon Sep 17 00:00:00 2001 From: Alexandr Zarubkin Date: Mon, 21 May 2018 17:02:24 +0300 Subject: [PATCH 340/351] Added preprocessor symbol USE_HSI_CLOCK which enables HSI clocking for generic variants. By default, HSE clocking scheme is used, as before this change. Signed-off-by: Alexandr Zarubkin --- STM32F1/variants/generic_gd32f103c/wirish/boards.cpp | 4 ++-- .../variants/generic_gd32f103c/wirish/boards_setup.cpp | 9 ++++++++- STM32F1/variants/generic_stm32f103c/wirish/boards.cpp | 4 ++-- .../variants/generic_stm32f103c/wirish/boards_setup.cpp | 8 ++++++++ STM32F1/variants/generic_stm32f103r/wirish/boards.cpp | 4 ++-- .../variants/generic_stm32f103r/wirish/boards_setup.cpp | 8 ++++++++ STM32F1/variants/generic_stm32f103r8/wirish/boards.cpp | 4 ++-- .../variants/generic_stm32f103r8/wirish/boards_setup.cpp | 8 ++++++++ STM32F1/variants/generic_stm32f103t/wirish/boards.cpp | 4 ++-- .../variants/generic_stm32f103t/wirish/boards_setup.cpp | 8 ++++++++ STM32F1/variants/generic_stm32f103v/wirish/boards.cpp | 4 ++-- .../variants/generic_stm32f103v/wirish/boards_setup.cpp | 8 ++++++++ STM32F1/variants/generic_stm32f103vb/wirish/boards.cpp | 4 ++-- .../variants/generic_stm32f103vb/wirish/boards_setup.cpp | 8 ++++++++ STM32F1/variants/generic_stm32f103z/wirish/boards.cpp | 4 ++-- .../variants/generic_stm32f103z/wirish/boards_setup.cpp | 8 ++++++++ 16 files changed, 80 insertions(+), 17 deletions(-) diff --git a/STM32F1/variants/generic_gd32f103c/wirish/boards.cpp b/STM32F1/variants/generic_gd32f103c/wirish/boards.cpp index ef1f2ad..93ae231 100644 --- a/STM32F1/variants/generic_gd32f103c/wirish/boards.cpp +++ b/STM32F1/variants/generic_gd32f103c/wirish/boards.cpp @@ -120,12 +120,12 @@ static void setup_clocks(void) { // Clear clock readiness interrupt flags and turn off clock // readiness interrupts. RCC_BASE->CIR = 0x00000000; - +#if !USE_HSI_CLOCK // Enable HSE, and wait until it's ready. rcc_turn_on_clk(RCC_CLK_HSE); while (!rcc_is_clk_ready(RCC_CLK_HSE)) ; - +#endif // Configure AHBx, APBx, etc. prescalers and the main PLL. wirish::priv::board_setup_clock_prescalers(); rcc_configure_pll(&wirish::priv::w_board_pll_cfg); diff --git a/STM32F1/variants/generic_gd32f103c/wirish/boards_setup.cpp b/STM32F1/variants/generic_gd32f103c/wirish/boards_setup.cpp index 3df1fe7..a297de1 100644 --- a/STM32F1/variants/generic_gd32f103c/wirish/boards_setup.cpp +++ b/STM32F1/variants/generic_gd32f103c/wirish/boards_setup.cpp @@ -46,6 +46,7 @@ // Additionally the GD32 has a 4 USB PLL divider settings, rather than the 2 settings in the STM32, which allow it to operate on frequencies of 48,72,96 and 120Mhz and still have USB functioning #ifndef BOARD_RCC_PLLMUL +#if !USE_HSI_CLOCK #if F_CPU==120000000 #define BOARD_RCC_PLLMUL RCC_PLLMUL_10 #elif F_CPU==96000000 @@ -53,14 +54,20 @@ #elif F_CPU==72000000 #define BOARD_RCC_PLLMUL RCC_PLLMUL_6 #endif - +#else + #define BOARD_RCC_PLLMUL RCC_PLLMUL_16 +#endif #endif namespace wirish { namespace priv { static stm32f1_rcc_pll_data pll_data = {BOARD_RCC_PLLMUL}; +#if !USE_HSI_CLOCK __weak rcc_pll_cfg w_board_pll_cfg = {RCC_PLLSRC_HSE, &pll_data}; +#else + __weak rcc_pll_cfg w_board_pll_cfg = {RCC_PLLSRC_HSI_DIV_2, &pll_data}; +#endif __weak adc_prescaler w_adc_pre = ADC_PRE_PCLK2_DIV_6; __weak adc_smp_rate w_adc_smp = ADC_SMPR_55_5; diff --git a/STM32F1/variants/generic_stm32f103c/wirish/boards.cpp b/STM32F1/variants/generic_stm32f103c/wirish/boards.cpp index 08c34d1..53f3469 100644 --- a/STM32F1/variants/generic_stm32f103c/wirish/boards.cpp +++ b/STM32F1/variants/generic_stm32f103c/wirish/boards.cpp @@ -120,12 +120,12 @@ static void setup_clocks(void) { // Clear clock readiness interrupt flags and turn off clock // readiness interrupts. RCC_BASE->CIR = 0x00000000; - +#if !USE_HSI_CLOCK // Enable HSE, and wait until it's ready. rcc_turn_on_clk(RCC_CLK_HSE); while (!rcc_is_clk_ready(RCC_CLK_HSE)) ; - +#endif // Configure AHBx, APBx, etc. prescalers and the main PLL. wirish::priv::board_setup_clock_prescalers(); rcc_configure_pll(&wirish::priv::w_board_pll_cfg); diff --git a/STM32F1/variants/generic_stm32f103c/wirish/boards_setup.cpp b/STM32F1/variants/generic_stm32f103c/wirish/boards_setup.cpp index 5f595ee..59e8228 100644 --- a/STM32F1/variants/generic_stm32f103c/wirish/boards_setup.cpp +++ b/STM32F1/variants/generic_stm32f103c/wirish/boards_setup.cpp @@ -48,6 +48,7 @@ // works for F103 performance line MCUs, which is all that LeafLabs // currently officially supports). #ifndef BOARD_RCC_PLLMUL + #if !USE_HSI_CLOCK #if F_CPU==128000000 #define BOARD_RCC_PLLMUL RCC_PLLMUL_16 #elif F_CPU==72000000 @@ -57,13 +58,20 @@ #elif F_CPU==16000000 #define BOARD_RCC_PLLMUL RCC_PLLMUL_2 #endif + #else + #define BOARD_RCC_PLLMUL RCC_PLLMUL_16 + #endif #endif namespace wirish { namespace priv { static stm32f1_rcc_pll_data pll_data = {BOARD_RCC_PLLMUL}; +#if !USE_HSI_CLOCK __weak rcc_pll_cfg w_board_pll_cfg = {RCC_PLLSRC_HSE, &pll_data}; +#else + __weak rcc_pll_cfg w_board_pll_cfg = {RCC_PLLSRC_HSI_DIV_2, &pll_data}; +#endif __weak adc_prescaler w_adc_pre = ADC_PRE_PCLK2_DIV_6; __weak adc_smp_rate w_adc_smp = ADC_SMPR_55_5; diff --git a/STM32F1/variants/generic_stm32f103r/wirish/boards.cpp b/STM32F1/variants/generic_stm32f103r/wirish/boards.cpp index ef1f2ad..93ae231 100644 --- a/STM32F1/variants/generic_stm32f103r/wirish/boards.cpp +++ b/STM32F1/variants/generic_stm32f103r/wirish/boards.cpp @@ -120,12 +120,12 @@ static void setup_clocks(void) { // Clear clock readiness interrupt flags and turn off clock // readiness interrupts. RCC_BASE->CIR = 0x00000000; - +#if !USE_HSI_CLOCK // Enable HSE, and wait until it's ready. rcc_turn_on_clk(RCC_CLK_HSE); while (!rcc_is_clk_ready(RCC_CLK_HSE)) ; - +#endif // Configure AHBx, APBx, etc. prescalers and the main PLL. wirish::priv::board_setup_clock_prescalers(); rcc_configure_pll(&wirish::priv::w_board_pll_cfg); diff --git a/STM32F1/variants/generic_stm32f103r/wirish/boards_setup.cpp b/STM32F1/variants/generic_stm32f103r/wirish/boards_setup.cpp index 1632caa..c804d7f 100644 --- a/STM32F1/variants/generic_stm32f103r/wirish/boards_setup.cpp +++ b/STM32F1/variants/generic_stm32f103r/wirish/boards_setup.cpp @@ -48,6 +48,7 @@ // works for F103 performance line MCUs, which is all that LeafLabs // currently officially supports). #ifndef BOARD_RCC_PLLMUL + #if !USE_HSI_CLOCK #if F_CPU==128000000 #define BOARD_RCC_PLLMUL RCC_PLLMUL_16 #elif F_CPU==72000000 @@ -57,13 +58,20 @@ #elif F_CPU==16000000 #define BOARD_RCC_PLLMUL RCC_PLLMUL_2 #endif + #else + #define BOARD_RCC_PLLMUL RCC_PLLMUL_16 + #endif #endif namespace wirish { namespace priv { static stm32f1_rcc_pll_data pll_data = {BOARD_RCC_PLLMUL}; +#if !USE_HSI_CLOCK __weak rcc_pll_cfg w_board_pll_cfg = {RCC_PLLSRC_HSE, &pll_data}; +#else + __weak rcc_pll_cfg w_board_pll_cfg = {RCC_PLLSRC_HSI_DIV_2, &pll_data}; +#endif __weak adc_prescaler w_adc_pre = ADC_PRE_PCLK2_DIV_6; __weak adc_smp_rate w_adc_smp = ADC_SMPR_55_5; diff --git a/STM32F1/variants/generic_stm32f103r8/wirish/boards.cpp b/STM32F1/variants/generic_stm32f103r8/wirish/boards.cpp index 7b7e9a6..8806343 100644 --- a/STM32F1/variants/generic_stm32f103r8/wirish/boards.cpp +++ b/STM32F1/variants/generic_stm32f103r8/wirish/boards.cpp @@ -120,12 +120,12 @@ static void setup_clocks(void) { // Clear clock readiness interrupt flags and turn off clock // readiness interrupts. RCC_BASE->CIR = 0x00000000; - +#if !USE_HSI_CLOCK // Enable HSE, and wait until it's ready. rcc_turn_on_clk(RCC_CLK_HSE); while (!rcc_is_clk_ready(RCC_CLK_HSE)) ; - +#endif // Configure AHBx, APBx, etc. prescalers and the main PLL. wirish::priv::board_setup_clock_prescalers(); rcc_configure_pll(&wirish::priv::w_board_pll_cfg); diff --git a/STM32F1/variants/generic_stm32f103r8/wirish/boards_setup.cpp b/STM32F1/variants/generic_stm32f103r8/wirish/boards_setup.cpp index 13d7b89..9e9c3c0 100644 --- a/STM32F1/variants/generic_stm32f103r8/wirish/boards_setup.cpp +++ b/STM32F1/variants/generic_stm32f103r8/wirish/boards_setup.cpp @@ -48,6 +48,7 @@ // works for F103 performance line MCUs, which is all that LeafLabs // currently officially supports). #ifndef BOARD_RCC_PLLMUL + #if !USE_HSI_CLOCK #if F_CPU==128000000 #define BOARD_RCC_PLLMUL RCC_PLLMUL_16 #elif F_CPU==72000000 @@ -57,13 +58,20 @@ #elif F_CPU==16000000 #define BOARD_RCC_PLLMUL RCC_PLLMUL_2 #endif + #else + #define BOARD_RCC_PLLMUL RCC_PLLMUL_16 + #endif #endif namespace wirish { namespace priv { static stm32f1_rcc_pll_data pll_data = {BOARD_RCC_PLLMUL}; +#if !USE_HSI_CLOCK __weak rcc_pll_cfg w_board_pll_cfg = {RCC_PLLSRC_HSE, &pll_data}; +#else + __weak rcc_pll_cfg w_board_pll_cfg = {RCC_PLLSRC_HSI_DIV_2, &pll_data}; +#endif __weak adc_prescaler w_adc_pre = ADC_PRE_PCLK2_DIV_6; __weak adc_smp_rate w_adc_smp = ADC_SMPR_55_5; diff --git a/STM32F1/variants/generic_stm32f103t/wirish/boards.cpp b/STM32F1/variants/generic_stm32f103t/wirish/boards.cpp index 7b7e9a6..8806343 100644 --- a/STM32F1/variants/generic_stm32f103t/wirish/boards.cpp +++ b/STM32F1/variants/generic_stm32f103t/wirish/boards.cpp @@ -120,12 +120,12 @@ static void setup_clocks(void) { // Clear clock readiness interrupt flags and turn off clock // readiness interrupts. RCC_BASE->CIR = 0x00000000; - +#if !USE_HSI_CLOCK // Enable HSE, and wait until it's ready. rcc_turn_on_clk(RCC_CLK_HSE); while (!rcc_is_clk_ready(RCC_CLK_HSE)) ; - +#endif // Configure AHBx, APBx, etc. prescalers and the main PLL. wirish::priv::board_setup_clock_prescalers(); rcc_configure_pll(&wirish::priv::w_board_pll_cfg); diff --git a/STM32F1/variants/generic_stm32f103t/wirish/boards_setup.cpp b/STM32F1/variants/generic_stm32f103t/wirish/boards_setup.cpp index 5f595ee..59e8228 100644 --- a/STM32F1/variants/generic_stm32f103t/wirish/boards_setup.cpp +++ b/STM32F1/variants/generic_stm32f103t/wirish/boards_setup.cpp @@ -48,6 +48,7 @@ // works for F103 performance line MCUs, which is all that LeafLabs // currently officially supports). #ifndef BOARD_RCC_PLLMUL + #if !USE_HSI_CLOCK #if F_CPU==128000000 #define BOARD_RCC_PLLMUL RCC_PLLMUL_16 #elif F_CPU==72000000 @@ -57,13 +58,20 @@ #elif F_CPU==16000000 #define BOARD_RCC_PLLMUL RCC_PLLMUL_2 #endif + #else + #define BOARD_RCC_PLLMUL RCC_PLLMUL_16 + #endif #endif namespace wirish { namespace priv { static stm32f1_rcc_pll_data pll_data = {BOARD_RCC_PLLMUL}; +#if !USE_HSI_CLOCK __weak rcc_pll_cfg w_board_pll_cfg = {RCC_PLLSRC_HSE, &pll_data}; +#else + __weak rcc_pll_cfg w_board_pll_cfg = {RCC_PLLSRC_HSI_DIV_2, &pll_data}; +#endif __weak adc_prescaler w_adc_pre = ADC_PRE_PCLK2_DIV_6; __weak adc_smp_rate w_adc_smp = ADC_SMPR_55_5; diff --git a/STM32F1/variants/generic_stm32f103v/wirish/boards.cpp b/STM32F1/variants/generic_stm32f103v/wirish/boards.cpp index fc90f36..a2867b8 100644 --- a/STM32F1/variants/generic_stm32f103v/wirish/boards.cpp +++ b/STM32F1/variants/generic_stm32f103v/wirish/boards.cpp @@ -120,12 +120,12 @@ static void setup_clocks(void) { // Clear clock readiness interrupt flags and turn off clock // readiness interrupts. RCC_BASE->CIR = 0x00000000; - +#if !USE_HSI_CLOCK // Enable HSE, and wait until it's ready. rcc_turn_on_clk(RCC_CLK_HSE); while (!rcc_is_clk_ready(RCC_CLK_HSE)) ; - +#endif // Configure AHBx, APBx, etc. prescalers and the main PLL. wirish::priv::board_setup_clock_prescalers(); rcc_configure_pll(&wirish::priv::w_board_pll_cfg); diff --git a/STM32F1/variants/generic_stm32f103v/wirish/boards_setup.cpp b/STM32F1/variants/generic_stm32f103v/wirish/boards_setup.cpp index 0b96261..5ea718b 100644 --- a/STM32F1/variants/generic_stm32f103v/wirish/boards_setup.cpp +++ b/STM32F1/variants/generic_stm32f103v/wirish/boards_setup.cpp @@ -48,6 +48,7 @@ // works for F103 performance line MCUs, which is all that LeafLabs // currently officially supports). #ifndef BOARD_RCC_PLLMUL + #if !USE_HSI_CLOCK #if F_CPU==128000000 #define BOARD_RCC_PLLMUL RCC_PLLMUL_16 #elif F_CPU==72000000 @@ -57,13 +58,20 @@ #elif F_CPU==16000000 #define BOARD_RCC_PLLMUL RCC_PLLMUL_2 #endif + #else + #define BOARD_RCC_PLLMUL RCC_PLLMUL_16 + #endif #endif namespace wirish { namespace priv { static stm32f1_rcc_pll_data pll_data = {BOARD_RCC_PLLMUL}; +#if !USE_HSI_CLOCK __weak rcc_pll_cfg w_board_pll_cfg = {RCC_PLLSRC_HSE, &pll_data}; +#else + __weak rcc_pll_cfg w_board_pll_cfg = {RCC_PLLSRC_HSI_DIV_2, &pll_data}; +#endif __weak adc_prescaler w_adc_pre = ADC_PRE_PCLK2_DIV_6; __weak adc_smp_rate w_adc_smp = ADC_SMPR_55_5; diff --git a/STM32F1/variants/generic_stm32f103vb/wirish/boards.cpp b/STM32F1/variants/generic_stm32f103vb/wirish/boards.cpp index fc90f36..a2867b8 100644 --- a/STM32F1/variants/generic_stm32f103vb/wirish/boards.cpp +++ b/STM32F1/variants/generic_stm32f103vb/wirish/boards.cpp @@ -120,12 +120,12 @@ static void setup_clocks(void) { // Clear clock readiness interrupt flags and turn off clock // readiness interrupts. RCC_BASE->CIR = 0x00000000; - +#if !USE_HSI_CLOCK // Enable HSE, and wait until it's ready. rcc_turn_on_clk(RCC_CLK_HSE); while (!rcc_is_clk_ready(RCC_CLK_HSE)) ; - +#endif // Configure AHBx, APBx, etc. prescalers and the main PLL. wirish::priv::board_setup_clock_prescalers(); rcc_configure_pll(&wirish::priv::w_board_pll_cfg); diff --git a/STM32F1/variants/generic_stm32f103vb/wirish/boards_setup.cpp b/STM32F1/variants/generic_stm32f103vb/wirish/boards_setup.cpp index 0b96261..5ea718b 100644 --- a/STM32F1/variants/generic_stm32f103vb/wirish/boards_setup.cpp +++ b/STM32F1/variants/generic_stm32f103vb/wirish/boards_setup.cpp @@ -48,6 +48,7 @@ // works for F103 performance line MCUs, which is all that LeafLabs // currently officially supports). #ifndef BOARD_RCC_PLLMUL + #if !USE_HSI_CLOCK #if F_CPU==128000000 #define BOARD_RCC_PLLMUL RCC_PLLMUL_16 #elif F_CPU==72000000 @@ -57,13 +58,20 @@ #elif F_CPU==16000000 #define BOARD_RCC_PLLMUL RCC_PLLMUL_2 #endif + #else + #define BOARD_RCC_PLLMUL RCC_PLLMUL_16 + #endif #endif namespace wirish { namespace priv { static stm32f1_rcc_pll_data pll_data = {BOARD_RCC_PLLMUL}; +#if !USE_HSI_CLOCK __weak rcc_pll_cfg w_board_pll_cfg = {RCC_PLLSRC_HSE, &pll_data}; +#else + __weak rcc_pll_cfg w_board_pll_cfg = {RCC_PLLSRC_HSI_DIV_2, &pll_data}; +#endif __weak adc_prescaler w_adc_pre = ADC_PRE_PCLK2_DIV_6; __weak adc_smp_rate w_adc_smp = ADC_SMPR_55_5; diff --git a/STM32F1/variants/generic_stm32f103z/wirish/boards.cpp b/STM32F1/variants/generic_stm32f103z/wirish/boards.cpp index ef1f2ad..93ae231 100644 --- a/STM32F1/variants/generic_stm32f103z/wirish/boards.cpp +++ b/STM32F1/variants/generic_stm32f103z/wirish/boards.cpp @@ -120,12 +120,12 @@ static void setup_clocks(void) { // Clear clock readiness interrupt flags and turn off clock // readiness interrupts. RCC_BASE->CIR = 0x00000000; - +#if !USE_HSI_CLOCK // Enable HSE, and wait until it's ready. rcc_turn_on_clk(RCC_CLK_HSE); while (!rcc_is_clk_ready(RCC_CLK_HSE)) ; - +#endif // Configure AHBx, APBx, etc. prescalers and the main PLL. wirish::priv::board_setup_clock_prescalers(); rcc_configure_pll(&wirish::priv::w_board_pll_cfg); diff --git a/STM32F1/variants/generic_stm32f103z/wirish/boards_setup.cpp b/STM32F1/variants/generic_stm32f103z/wirish/boards_setup.cpp index 0f6fd0f..6cc457e 100644 --- a/STM32F1/variants/generic_stm32f103z/wirish/boards_setup.cpp +++ b/STM32F1/variants/generic_stm32f103z/wirish/boards_setup.cpp @@ -48,6 +48,7 @@ // works for F103 performance line MCUs, which is all that LeafLabs // currently officially supports). #ifndef BOARD_RCC_PLLMUL + #if !USE_HSI_CLOCK #if F_CPU==128000000 #define BOARD_RCC_PLLMUL RCC_PLLMUL_16 #elif F_CPU==72000000 @@ -57,13 +58,20 @@ #elif F_CPU==16000000 #define BOARD_RCC_PLLMUL RCC_PLLMUL_2 #endif + #else + #define BOARD_RCC_PLLMUL RCC_PLLMUL_16 + #endif #endif namespace wirish { namespace priv { static stm32f1_rcc_pll_data pll_data = {BOARD_RCC_PLLMUL}; +#if !USE_HSI_CLOCK __weak rcc_pll_cfg w_board_pll_cfg = {RCC_PLLSRC_HSE, &pll_data}; +#else + __weak rcc_pll_cfg w_board_pll_cfg = {RCC_PLLSRC_HSI_DIV_2, &pll_data}; +#endif __weak adc_prescaler w_adc_pre = ADC_PRE_PCLK2_DIV_6; __weak adc_smp_rate w_adc_smp = ADC_SMPR_55_5; From 6a551bd9abcc632632d7c9e71a49e341a1600399 Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Tue, 22 May 2018 09:29:23 +1000 Subject: [PATCH 341/351] Ranemed FreeRTOS to FreeRTOS701 to prevent name clashes. see https://github.com/rogerclarkmelbourne/Arduino_STM32/issues/500 --- STM32F1/libraries/{FreeRTOS => FreeRTOS701}/MapleFreeRTOS.cpp | 0 STM32F1/libraries/{FreeRTOS => FreeRTOS701}/MapleFreeRTOS.h | 0 STM32F1/libraries/{FreeRTOS => FreeRTOS701}/keywords.txt | 0 STM32F1/libraries/{FreeRTOS => FreeRTOS701}/rules.mk | 0 STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/FreeRTOS.h | 0 .../libraries/{FreeRTOS => FreeRTOS701}/utility/FreeRTOSConfig.h | 0 STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/StackMacros.h | 0 STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/croutine.c | 0 STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/croutine.h | 0 STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/heap_2.c | 0 STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/list.c | 0 STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/list.h | 0 .../libraries/{FreeRTOS => FreeRTOS701}/utility/mpu_wrappers.h | 0 STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/port.c | 0 STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/portable.h | 0 STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/portmacro.h | 0 STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/projdefs.h | 0 STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/queue.c | 0 STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/queue.h | 0 STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/semphr.h | 0 STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/task.h | 0 STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/tasks.c | 0 STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/timers.c | 0 STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/timers.h | 0 24 files changed, 0 insertions(+), 0 deletions(-) rename STM32F1/libraries/{FreeRTOS => FreeRTOS701}/MapleFreeRTOS.cpp (100%) rename STM32F1/libraries/{FreeRTOS => FreeRTOS701}/MapleFreeRTOS.h (100%) rename STM32F1/libraries/{FreeRTOS => FreeRTOS701}/keywords.txt (100%) rename STM32F1/libraries/{FreeRTOS => FreeRTOS701}/rules.mk (100%) rename STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/FreeRTOS.h (100%) rename STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/FreeRTOSConfig.h (100%) rename STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/StackMacros.h (100%) rename STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/croutine.c (100%) rename STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/croutine.h (100%) rename STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/heap_2.c (100%) rename STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/list.c (100%) rename STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/list.h (100%) rename STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/mpu_wrappers.h (100%) rename STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/port.c (100%) rename STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/portable.h (100%) rename STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/portmacro.h (100%) rename STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/projdefs.h (100%) rename STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/queue.c (100%) rename STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/queue.h (100%) rename STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/semphr.h (100%) rename STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/task.h (100%) rename STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/tasks.c (100%) rename STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/timers.c (100%) rename STM32F1/libraries/{FreeRTOS => FreeRTOS701}/utility/timers.h (100%) diff --git a/STM32F1/libraries/FreeRTOS/MapleFreeRTOS.cpp b/STM32F1/libraries/FreeRTOS701/MapleFreeRTOS.cpp similarity index 100% rename from STM32F1/libraries/FreeRTOS/MapleFreeRTOS.cpp rename to STM32F1/libraries/FreeRTOS701/MapleFreeRTOS.cpp diff --git a/STM32F1/libraries/FreeRTOS/MapleFreeRTOS.h b/STM32F1/libraries/FreeRTOS701/MapleFreeRTOS.h similarity index 100% rename from STM32F1/libraries/FreeRTOS/MapleFreeRTOS.h rename to STM32F1/libraries/FreeRTOS701/MapleFreeRTOS.h diff --git a/STM32F1/libraries/FreeRTOS/keywords.txt b/STM32F1/libraries/FreeRTOS701/keywords.txt similarity index 100% rename from STM32F1/libraries/FreeRTOS/keywords.txt rename to STM32F1/libraries/FreeRTOS701/keywords.txt diff --git a/STM32F1/libraries/FreeRTOS/rules.mk b/STM32F1/libraries/FreeRTOS701/rules.mk similarity index 100% rename from STM32F1/libraries/FreeRTOS/rules.mk rename to STM32F1/libraries/FreeRTOS701/rules.mk diff --git a/STM32F1/libraries/FreeRTOS/utility/FreeRTOS.h b/STM32F1/libraries/FreeRTOS701/utility/FreeRTOS.h similarity index 100% rename from STM32F1/libraries/FreeRTOS/utility/FreeRTOS.h rename to STM32F1/libraries/FreeRTOS701/utility/FreeRTOS.h diff --git a/STM32F1/libraries/FreeRTOS/utility/FreeRTOSConfig.h b/STM32F1/libraries/FreeRTOS701/utility/FreeRTOSConfig.h similarity index 100% rename from STM32F1/libraries/FreeRTOS/utility/FreeRTOSConfig.h rename to STM32F1/libraries/FreeRTOS701/utility/FreeRTOSConfig.h diff --git a/STM32F1/libraries/FreeRTOS/utility/StackMacros.h b/STM32F1/libraries/FreeRTOS701/utility/StackMacros.h similarity index 100% rename from STM32F1/libraries/FreeRTOS/utility/StackMacros.h rename to STM32F1/libraries/FreeRTOS701/utility/StackMacros.h diff --git a/STM32F1/libraries/FreeRTOS/utility/croutine.c b/STM32F1/libraries/FreeRTOS701/utility/croutine.c similarity index 100% rename from STM32F1/libraries/FreeRTOS/utility/croutine.c rename to STM32F1/libraries/FreeRTOS701/utility/croutine.c diff --git a/STM32F1/libraries/FreeRTOS/utility/croutine.h b/STM32F1/libraries/FreeRTOS701/utility/croutine.h similarity index 100% rename from STM32F1/libraries/FreeRTOS/utility/croutine.h rename to STM32F1/libraries/FreeRTOS701/utility/croutine.h diff --git a/STM32F1/libraries/FreeRTOS/utility/heap_2.c b/STM32F1/libraries/FreeRTOS701/utility/heap_2.c similarity index 100% rename from STM32F1/libraries/FreeRTOS/utility/heap_2.c rename to STM32F1/libraries/FreeRTOS701/utility/heap_2.c diff --git a/STM32F1/libraries/FreeRTOS/utility/list.c b/STM32F1/libraries/FreeRTOS701/utility/list.c similarity index 100% rename from STM32F1/libraries/FreeRTOS/utility/list.c rename to STM32F1/libraries/FreeRTOS701/utility/list.c diff --git a/STM32F1/libraries/FreeRTOS/utility/list.h b/STM32F1/libraries/FreeRTOS701/utility/list.h similarity index 100% rename from STM32F1/libraries/FreeRTOS/utility/list.h rename to STM32F1/libraries/FreeRTOS701/utility/list.h diff --git a/STM32F1/libraries/FreeRTOS/utility/mpu_wrappers.h b/STM32F1/libraries/FreeRTOS701/utility/mpu_wrappers.h similarity index 100% rename from STM32F1/libraries/FreeRTOS/utility/mpu_wrappers.h rename to STM32F1/libraries/FreeRTOS701/utility/mpu_wrappers.h diff --git a/STM32F1/libraries/FreeRTOS/utility/port.c b/STM32F1/libraries/FreeRTOS701/utility/port.c similarity index 100% rename from STM32F1/libraries/FreeRTOS/utility/port.c rename to STM32F1/libraries/FreeRTOS701/utility/port.c diff --git a/STM32F1/libraries/FreeRTOS/utility/portable.h b/STM32F1/libraries/FreeRTOS701/utility/portable.h similarity index 100% rename from STM32F1/libraries/FreeRTOS/utility/portable.h rename to STM32F1/libraries/FreeRTOS701/utility/portable.h diff --git a/STM32F1/libraries/FreeRTOS/utility/portmacro.h b/STM32F1/libraries/FreeRTOS701/utility/portmacro.h similarity index 100% rename from STM32F1/libraries/FreeRTOS/utility/portmacro.h rename to STM32F1/libraries/FreeRTOS701/utility/portmacro.h diff --git a/STM32F1/libraries/FreeRTOS/utility/projdefs.h b/STM32F1/libraries/FreeRTOS701/utility/projdefs.h similarity index 100% rename from STM32F1/libraries/FreeRTOS/utility/projdefs.h rename to STM32F1/libraries/FreeRTOS701/utility/projdefs.h diff --git a/STM32F1/libraries/FreeRTOS/utility/queue.c b/STM32F1/libraries/FreeRTOS701/utility/queue.c similarity index 100% rename from STM32F1/libraries/FreeRTOS/utility/queue.c rename to STM32F1/libraries/FreeRTOS701/utility/queue.c diff --git a/STM32F1/libraries/FreeRTOS/utility/queue.h b/STM32F1/libraries/FreeRTOS701/utility/queue.h similarity index 100% rename from STM32F1/libraries/FreeRTOS/utility/queue.h rename to STM32F1/libraries/FreeRTOS701/utility/queue.h diff --git a/STM32F1/libraries/FreeRTOS/utility/semphr.h b/STM32F1/libraries/FreeRTOS701/utility/semphr.h similarity index 100% rename from STM32F1/libraries/FreeRTOS/utility/semphr.h rename to STM32F1/libraries/FreeRTOS701/utility/semphr.h diff --git a/STM32F1/libraries/FreeRTOS/utility/task.h b/STM32F1/libraries/FreeRTOS701/utility/task.h similarity index 100% rename from STM32F1/libraries/FreeRTOS/utility/task.h rename to STM32F1/libraries/FreeRTOS701/utility/task.h diff --git a/STM32F1/libraries/FreeRTOS/utility/tasks.c b/STM32F1/libraries/FreeRTOS701/utility/tasks.c similarity index 100% rename from STM32F1/libraries/FreeRTOS/utility/tasks.c rename to STM32F1/libraries/FreeRTOS701/utility/tasks.c diff --git a/STM32F1/libraries/FreeRTOS/utility/timers.c b/STM32F1/libraries/FreeRTOS701/utility/timers.c similarity index 100% rename from STM32F1/libraries/FreeRTOS/utility/timers.c rename to STM32F1/libraries/FreeRTOS701/utility/timers.c diff --git a/STM32F1/libraries/FreeRTOS/utility/timers.h b/STM32F1/libraries/FreeRTOS701/utility/timers.h similarity index 100% rename from STM32F1/libraries/FreeRTOS/utility/timers.h rename to STM32F1/libraries/FreeRTOS701/utility/timers.h From 6548456957c232c128ada378d5cefcb81beced9e Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Wed, 23 May 2018 18:03:38 +1000 Subject: [PATCH 342/351] Change Wire.write() return types from void to size_t to be compatible with the Arduino API --- STM32F1/libraries/Wire/utility/WireBase.cpp | 22 +++++++++++++-------- STM32F1/libraries/Wire/utility/WireBase.h | 8 ++++---- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/STM32F1/libraries/Wire/utility/WireBase.cpp b/STM32F1/libraries/Wire/utility/WireBase.cpp index 02c8ed3..5d4f63b 100644 --- a/STM32F1/libraries/Wire/utility/WireBase.cpp +++ b/STM32F1/libraries/Wire/utility/WireBase.cpp @@ -95,27 +95,33 @@ uint8 WireBase::requestFrom(int address, int numBytes) { return WireBase::requestFrom((uint8)address, numBytes); } -void WireBase::write(uint8 value) { +size_t WireBase::write(uint8 value) { if (tx_buf_idx == BUFFER_LENGTH) { tx_buf_overflow = true; - return; + return 0; } tx_buf[tx_buf_idx++] = value; itc_msg.length++; + return 1; } -void WireBase::write(uint8* buf, int len) { +size_t WireBase::write(uint8* buf, int len) { for (uint8 i = 0; i < len; i++) { - write(buf[i]); + if (!write(buf[i])) + { + return i; + } } + return len; } -void WireBase::write(int value) { - write((uint8)value); + +size_t WireBase::write(int value) { + return write((uint8)value); } -void WireBase::write(int* buf, int len) { - write((uint8*)buf, (uint8)len); +size_t WireBase::write(int* buf, int len) { + return write((uint8*)buf, (uint8)len); } void WireBase::write(char* buf) { diff --git a/STM32F1/libraries/Wire/utility/WireBase.h b/STM32F1/libraries/Wire/utility/WireBase.h index 72facde..b543a15 100644 --- a/STM32F1/libraries/Wire/utility/WireBase.h +++ b/STM32F1/libraries/Wire/utility/WireBase.h @@ -108,22 +108,22 @@ public: /* * Stack up bytes to be sent when transmitting */ - void write(uint8); + size_t write(uint8); /* * Stack up bytes from the array to be sent when transmitting */ - void write(uint8*, int); + size_t write(uint8*, int); /* * Ensure that a sending data will only be 8-bit bytes */ - void write(int); + size_t write(int); /* * Ensure that an array sending data will only be 8-bit bytes */ - void write(int*, int); + size_t write(int*, int); /* * Stack up bytes from a string to be sent when transmitting From 2208bcbc5bcff8c25feb3713cdb72f546366957c Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Wed, 23 May 2018 19:37:08 +1000 Subject: [PATCH 343/351] Add define for ARDUINO_ARCH_STM32 to correspond with the official STM core and also with Adadfuit STM32 products --- STM32F1/platform.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/platform.txt b/STM32F1/platform.txt index b1cf69d..418ad28 100644 --- a/STM32F1/platform.txt +++ b/STM32F1/platform.txt @@ -36,7 +36,7 @@ compiler.define=-DARDUINO= # this can be overriden in boards.txt build.f_cpu=72000000L build.mcu=cortex-m3 -build.common_flags=-mthumb -march=armv7-m -D__STM32F1__ +build.common_flags=-mthumb -march=armv7-m -D__STM32F1__ -DARDUINO_ARCH_STM32 build.variant_system_lib=libmaple.a ## LED stuff is not really used but is still required in the code build.error_led_port=GPIOB From e08d2eb1cc114341b5f87c6fb29014b31d697c8e Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Sun, 27 May 2018 15:52:53 +1000 Subject: [PATCH 344/351] minor change to SPI slave example --- STM32F1/libraries/SPI/examples/spi_slave/spi_slave.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/libraries/SPI/examples/spi_slave/spi_slave.ino b/STM32F1/libraries/SPI/examples/spi_slave/spi_slave.ino index fa2930a..1e26db3 100644 --- a/STM32F1/libraries/SPI/examples/spi_slave/spi_slave.ino +++ b/STM32F1/libraries/SPI/examples/spi_slave/spi_slave.ino @@ -22,7 +22,7 @@ void setup() setupSPI(); } -uint8_t count(0); +uint8_t count = 0; void loop() { // Blocking call to read SPI message From 141bcd2ad1bd4907c61c8f536bcb566b15c36d3c Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Sun, 27 May 2018 16:26:19 +1000 Subject: [PATCH 345/351] Attempt to add availableForWrite() to USB Serial --- STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c | 5 +++++ STM32F1/cores/maple/usb_serial.cpp | 2 ++ STM32F1/system/libmaple/include/libmaple/usb_cdcacm.h | 3 +++ 3 files changed, 10 insertions(+) diff --git a/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c b/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c index 7ebd03b..d4cd8b7 100644 --- a/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c +++ b/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c @@ -456,6 +456,11 @@ uint8 usb_cdcacm_is_transmitting(void) { return ( transmitting>0 ? transmitting : 0); } +int usb_cdcacm_tx_available() +{ + return CDC_SERIAL_TX_BUFFER_SIZE - usb_cdcacm_get_pending(); +} + uint16 usb_cdcacm_get_pending(void) { return (tx_head - tx_tail) & CDC_SERIAL_TX_BUFFER_SIZE_MASK; } diff --git a/STM32F1/cores/maple/usb_serial.cpp b/STM32F1/cores/maple/usb_serial.cpp index 9f52177..1cca589 100644 --- a/STM32F1/cores/maple/usb_serial.cpp +++ b/STM32F1/cores/maple/usb_serial.cpp @@ -148,6 +148,8 @@ int USBSerial::peek(void) } } +int USBSerial::availableForWrite(void) { return usb_cdcacm_tx_available(); } + void USBSerial::flush(void) { /*Roger Clark. Rather slow method. Need to improve this */ diff --git a/STM32F1/system/libmaple/include/libmaple/usb_cdcacm.h b/STM32F1/system/libmaple/include/libmaple/usb_cdcacm.h index 62c9181..53551a7 100644 --- a/STM32F1/system/libmaple/include/libmaple/usb_cdcacm.h +++ b/STM32F1/system/libmaple/include/libmaple/usb_cdcacm.h @@ -129,10 +129,13 @@ uint32 usb_cdcacm_peek_ex(uint8* buf, uint32 offset, uint32 len); uint32 usb_cdcacm_data_available(void); /* in RX buffer */ uint16 usb_cdcacm_get_pending(void); uint8 usb_cdcacm_is_transmitting(void); +int usb_cdcacm_tx_available(); uint8 usb_cdcacm_get_dtr(void); uint8 usb_cdcacm_get_rts(void); + + typedef struct usb_cdcacm_line_coding { uint32 dwDTERate; /* Baud rate */ From 4db3994d1c42a45eb7b8fd298347128765f09e7f Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Sun, 27 May 2018 16:35:06 +1000 Subject: [PATCH 346/351] Second attempt to add availableForWrite() to USB Serial --- STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c b/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c index d4cd8b7..dbf82c1 100644 --- a/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c +++ b/STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c @@ -458,7 +458,7 @@ uint8 usb_cdcacm_is_transmitting(void) { int usb_cdcacm_tx_available() { - return CDC_SERIAL_TX_BUFFER_SIZE - usb_cdcacm_get_pending(); + return CDC_SERIAL_TX_BUFFER_SIZE - usb_cdcacm_get_pending() - 1; } uint16 usb_cdcacm_get_pending(void) { From e8d8cdb75ef1e9f2e73014a5d62011ae27d1ac0c Mon Sep 17 00:00:00 2001 From: arpruss Date: Wed, 13 Jun 2018 15:28:36 -0500 Subject: [PATCH 347/351] update to latest version of USBComposite --- .../USBComposite/USBCompositeSerial.cpp | 2 +- .../USBComposite/USBCompositeSerial.h | 2 +- STM32F1/libraries/USBComposite/USBHID.cpp | 2 +- .../libraries/USBComposite/USBMassStorage.cpp | 2 +- .../examples/jigglemouse/jigglemouse.ino | 23 +++++++++++++++++++ .../USBComposite/examples/mass/mass.ino | 3 +++ .../examples/sdreader/sdreader.ino | 2 ++ .../libraries/USBComposite/library.properties | 2 +- .../{usb_serial.c => usb_composite_serial.c} | 2 +- .../{usb_serial.h => usb_composite_serial.h} | 0 .../libraries/USBComposite/usb_midi_device.c | 1 + STM32F1/libraries/USBComposite/usb_setup.cpp | 3 --- 12 files changed, 35 insertions(+), 9 deletions(-) create mode 100755 STM32F1/libraries/USBComposite/examples/jigglemouse/jigglemouse.ino rename STM32F1/libraries/USBComposite/{usb_serial.c => usb_composite_serial.c} (99%) rename STM32F1/libraries/USBComposite/{usb_serial.h => usb_composite_serial.h} (100%) diff --git a/STM32F1/libraries/USBComposite/USBCompositeSerial.cpp b/STM32F1/libraries/USBComposite/USBCompositeSerial.cpp index 9da0f19..8fa6c98 100644 --- a/STM32F1/libraries/USBComposite/USBCompositeSerial.cpp +++ b/STM32F1/libraries/USBComposite/USBCompositeSerial.cpp @@ -23,7 +23,7 @@ #include #include -#include "usb_serial.h" +#include "usb_composite_serial.h" #define USB_TIMEOUT 50 diff --git a/STM32F1/libraries/USBComposite/USBCompositeSerial.h b/STM32F1/libraries/USBComposite/USBCompositeSerial.h index 4112617..80f110a 100644 --- a/STM32F1/libraries/USBComposite/USBCompositeSerial.h +++ b/STM32F1/libraries/USBComposite/USBCompositeSerial.h @@ -2,7 +2,7 @@ #define _COMPOSITE_SERIAL_H_ #include "USBComposite.h" -#include "usb_serial.h" +#include "usb_composite_serial.h" class USBCompositeSerial : public Stream { private: diff --git a/STM32F1/libraries/USBComposite/USBHID.cpp b/STM32F1/libraries/USBComposite/USBHID.cpp index e0b69b4..ca35396 100644 --- a/STM32F1/libraries/USBComposite/USBHID.cpp +++ b/STM32F1/libraries/USBComposite/USBHID.cpp @@ -21,7 +21,7 @@ #include #include #include "usb_hid.h" -#include "usb_serial.h" +#include "usb_composite_serial.h" #include "usb_generic.h" #include #include diff --git a/STM32F1/libraries/USBComposite/USBMassStorage.cpp b/STM32F1/libraries/USBComposite/USBMassStorage.cpp index c376e69..9c96359 100644 --- a/STM32F1/libraries/USBComposite/USBMassStorage.cpp +++ b/STM32F1/libraries/USBComposite/USBMassStorage.cpp @@ -1,7 +1,7 @@ #include "USBMassStorage.h" #include "usb_mass.h" #include "usb_mass_mal.h" -#include "usb_serial.h" +#include "usb_composite_serial.h" #include void USBMassStorageDevice::begin() { diff --git a/STM32F1/libraries/USBComposite/examples/jigglemouse/jigglemouse.ino b/STM32F1/libraries/USBComposite/examples/jigglemouse/jigglemouse.ino new file mode 100755 index 0000000..633db0c --- /dev/null +++ b/STM32F1/libraries/USBComposite/examples/jigglemouse/jigglemouse.ino @@ -0,0 +1,23 @@ +#include + +#define LED PB12 + +void setup(){ + pinMode(LED,OUTPUT); + digitalWrite(LED,1); + USBHID_begin_with_serial(HID_MOUSE); + delay(1000); +} + +void loop(){ + digitalWrite(LED,0); + Mouse.move(4,0); + delay(500); + digitalWrite(LED,1); + delay(30000); + digitalWrite(LED,0); + Mouse.move(-4,0); + delay(500); + digitalWrite(LED,1); + delay(30000); +} diff --git a/STM32F1/libraries/USBComposite/examples/mass/mass.ino b/STM32F1/libraries/USBComposite/examples/mass/mass.ino index e10c04e..e64e40d 100644 --- a/STM32F1/libraries/USBComposite/examples/mass/mass.ino +++ b/STM32F1/libraries/USBComposite/examples/mass/mass.ino @@ -1,5 +1,7 @@ #include +#define PRODUCT_ID 0x29 + #include "image.h" bool write(uint32_t memoryOffset, const uint8_t *writebuff, uint16_t transferLength) { @@ -49,6 +51,7 @@ void dumpDrive() { } void setup() { + USBComposite.setProductId(PRODUCT_ID); MassStorage.setDrive(0, sizeof(image), read, write); MassStorage.registerComponent(); CompositeSerial.registerComponent(); diff --git a/STM32F1/libraries/USBComposite/examples/sdreader/sdreader.ino b/STM32F1/libraries/USBComposite/examples/sdreader/sdreader.ino index a5f4a61..0d5631a 100644 --- a/STM32F1/libraries/USBComposite/examples/sdreader/sdreader.ino +++ b/STM32F1/libraries/USBComposite/examples/sdreader/sdreader.ino @@ -6,6 +6,7 @@ #include "SdFat.h" #define LED_PIN PB12 +#define PRODUCT_ID 0x29 SdFatEX sd; const uint32_t speed = SPI_CLOCK_DIV2 ; @@ -22,6 +23,7 @@ bool read(uint32_t memoryOffset, uint8_t *readbuff, uint16_t transferLength) { } void setup() { + USBComposite.setProductId(PRODUCT_ID); pinMode(LED_PIN,OUTPUT); digitalWrite(LED_PIN,1); } diff --git a/STM32F1/libraries/USBComposite/library.properties b/STM32F1/libraries/USBComposite/library.properties index 1d8c2cb..3fd8bca 100644 --- a/STM32F1/libraries/USBComposite/library.properties +++ b/STM32F1/libraries/USBComposite/library.properties @@ -1,5 +1,5 @@ name=USBComposite for STM32F1 -version=0.64 +version=0.66 author=Various email=arpruss@gmail.com sentence=USB HID / MIDI / mass storage library for STM32F1 diff --git a/STM32F1/libraries/USBComposite/usb_serial.c b/STM32F1/libraries/USBComposite/usb_composite_serial.c similarity index 99% rename from STM32F1/libraries/USBComposite/usb_serial.c rename to STM32F1/libraries/USBComposite/usb_composite_serial.c index 390d256..51fc3ac 100644 --- a/STM32F1/libraries/USBComposite/usb_serial.c +++ b/STM32F1/libraries/USBComposite/usb_composite_serial.c @@ -33,7 +33,7 @@ * the result made cleaner. */ -#include "usb_serial.h" +#include "usb_composite_serial.h" #include "usb_generic.h" #include #include diff --git a/STM32F1/libraries/USBComposite/usb_serial.h b/STM32F1/libraries/USBComposite/usb_composite_serial.h similarity index 100% rename from STM32F1/libraries/USBComposite/usb_serial.h rename to STM32F1/libraries/USBComposite/usb_composite_serial.h diff --git a/STM32F1/libraries/USBComposite/usb_midi_device.c b/STM32F1/libraries/USBComposite/usb_midi_device.c index 549d581..f8a4fba 100644 --- a/STM32F1/libraries/USBComposite/usb_midi_device.c +++ b/STM32F1/libraries/USBComposite/usb_midi_device.c @@ -264,6 +264,7 @@ static void getMIDIPartDescriptor(uint8* out) { // patch to reflect where the part goes in the descriptor OUT_BYTE(usbMIDIDescriptor_Config, AC_Interface.bInterfaceNumber) += usbMIDIPart.startInterface; OUT_BYTE(usbMIDIDescriptor_Config, MS_Interface.bInterfaceNumber) += usbMIDIPart.startInterface; + OUT_BYTE(usbMIDIDescriptor_Config, AC_CS_Interface.baInterfaceNr) += usbMIDIPart.startInterface; OUT_BYTE(usbMIDIDescriptor_Config, DataOutEndpoint.bEndpointAddress) += usbMIDIPart.startEndpoint; OUT_BYTE(usbMIDIDescriptor_Config, DataInEndpoint.bEndpointAddress) += usbMIDIPart.startEndpoint; } diff --git a/STM32F1/libraries/USBComposite/usb_setup.cpp b/STM32F1/libraries/USBComposite/usb_setup.cpp index 2136bf0..47fd3db 100644 --- a/STM32F1/libraries/USBComposite/usb_setup.cpp +++ b/STM32F1/libraries/USBComposite/usb_setup.cpp @@ -35,18 +35,15 @@ */ #include "boards_private.h" -#include "USBHID.h" #include #include #include -#include namespace wirish { namespace priv { void board_setup_usb(void) { - //Serial = CompositeSerial; #ifdef GENERIC_BOOTLOADER //Reset the USB interface on generic boards - developed by Victor PV gpio_set_mode(PIN_MAP[PA12].gpio_device, PIN_MAP[PA12].gpio_bit, GPIO_OUTPUT_PP); From 2f4eaa7979c78d12ab0dadafa308d279ad2b2721 Mon Sep 17 00:00:00 2001 From: Vassilis Serasidis Date: Fri, 22 Jun 2018 19:49:05 +0300 Subject: [PATCH 348/351] STM32F407 BKPSRAM Boundary address fix Fix for the Backup RAM. Example code: ... #include ... bkp_init(); bkp_enable_writes(); bkp_write(1, 0x1234); //Writes the value 0x1234 at Backup RAM address 1 bkp_disable_writes(); Serial.print(bkp_read(1)); //Print the value of the Backup RAM address 1 ... --- STM32F4/cores/maple/libmaple/bkp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32F4/cores/maple/libmaple/bkp.h b/STM32F4/cores/maple/libmaple/bkp.h index dd378b4..44754a3 100644 --- a/STM32F4/cores/maple/libmaple/bkp.h +++ b/STM32F4/cores/maple/libmaple/bkp.h @@ -99,7 +99,7 @@ typedef struct bkp_reg_map { } bkp_reg_map; /** Backup peripheral register map base pointer. */ -#define BKP_BASE ((struct bkp_reg_map*)0x40006C00) +#define BKP_BASE ((struct bkp_reg_map*)0x40024000) /** Backup peripheral device type. */ typedef struct bkp_dev { From 9d46a1c27d4dc9dd4df06b76a1d81684519d8acc Mon Sep 17 00:00:00 2001 From: Roger Clark Date: Sat, 23 Jun 2018 17:00:17 +1000 Subject: [PATCH 349/351] Alternative fix for issue #532 --- STM32F1/system/libmaple/include/libmaple/delay.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/STM32F1/system/libmaple/include/libmaple/delay.h b/STM32F1/system/libmaple/include/libmaple/delay.h index 472a208..64bb510 100644 --- a/STM32F1/system/libmaple/include/libmaple/delay.h +++ b/STM32F1/system/libmaple/include/libmaple/delay.h @@ -46,6 +46,10 @@ extern "C" { * @param us Number of microseconds to delay. */ static inline void delay_us(uint32 us) { + if (us==0) + { + return; + } us *= STM32_DELAY_US_MULT; /* fudge for function call overhead */ From 8050dbfa580b97bf375b8f6f83894c4c2ce6478e Mon Sep 17 00:00:00 2001 From: stevstrong Date: Mon, 2 Jul 2018 10:30:17 +0200 Subject: [PATCH 350/351] F1: added function dma_get_count --- STM32F1/system/libmaple/stm32f1/include/series/dma.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/STM32F1/system/libmaple/stm32f1/include/series/dma.h b/STM32F1/system/libmaple/stm32f1/include/series/dma.h index 84fd228..8feebc6 100644 --- a/STM32F1/system/libmaple/stm32f1/include/series/dma.h +++ b/STM32F1/system/libmaple/stm32f1/include/series/dma.h @@ -538,7 +538,12 @@ static inline void dma_clear_isr_bits(dma_dev *dev, dma_tube tube) { dev->regs->IFCR = (1U << (4 * (tube - 1))); } -/** + +static inline uint16 dma_get_count(dma_dev *dev, dma_tube tube) { + return dma_channel_regs(dev, tube)->CNDTR; +} + + /** * @brief Deprecated * STM32F1 mode flags for dma_setup_xfer(). Use dma_tube_cfg() instead. * @see dma_tube_cfg() From 2ae184754b387f67dd7647fc620ea9ccac152eff Mon Sep 17 00:00:00 2001 From: stevstrong Date: Mon, 2 Jul 2018 10:32:21 +0200 Subject: [PATCH 351/351] Update dma.h small correction --- STM32F1/system/libmaple/stm32f1/include/series/dma.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/STM32F1/system/libmaple/stm32f1/include/series/dma.h b/STM32F1/system/libmaple/stm32f1/include/series/dma.h index 8feebc6..5260f8e 100644 --- a/STM32F1/system/libmaple/stm32f1/include/series/dma.h +++ b/STM32F1/system/libmaple/stm32f1/include/series/dma.h @@ -538,12 +538,11 @@ static inline void dma_clear_isr_bits(dma_dev *dev, dma_tube tube) { dev->regs->IFCR = (1U << (4 * (tube - 1))); } - static inline uint16 dma_get_count(dma_dev *dev, dma_tube tube) { return dma_channel_regs(dev, tube)->CNDTR; } - /** +/** * @brief Deprecated * STM32F1 mode flags for dma_setup_xfer(). Use dma_tube_cfg() instead. * @see dma_tube_cfg()

{{%xUuR*4SSTBZ4Hd5mQtmIPFJ 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⋐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

Q9T_#ffn{3$${L-kERM?k97Ch~lq%QpZ;_*M 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�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 A)b@nC4 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 diff --git a/tools/win/cygwin1.dll b/tools/win/cygwin1.dll deleted file mode 100644 index 83e58ea0cb220378ac4a125f9cb63c2e88ef5d9e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1872821 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