implemented SDIO
+ small changes in DMA - reworked get and clear ISR bits + wirish_time compatible with "C"
This commit is contained in:
parent
6dde3d39b4
commit
f58a96e0f6
|
@ -7,3 +7,4 @@ other/maple-bootloader/build
|
|||
other/maple-bootloader/*~
|
||||
*.o
|
||||
tools/src/stm32flash_serial/src/parsers/parsers.a
|
||||
*.bak
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -36,6 +36,10 @@
|
|||
#include <libmaple/nvic.h>
|
||||
#include <libmaple/systick.h>
|
||||
|
||||
#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
|
||||
|
|
Loading…
Reference in New Issue