Silicon小蜜蜂系列MCU SPI驱动

上传人:ba****u 文档编号:184014507 上传时间:2023-02-01 格式:DOCX 页数:47 大小:51.73KB
返回 下载 相关 举报
Silicon小蜜蜂系列MCU SPI驱动_第1页
第1页 / 共47页
Silicon小蜜蜂系列MCU SPI驱动_第2页
第2页 / 共47页
Silicon小蜜蜂系列MCU SPI驱动_第3页
第3页 / 共47页
点击查看更多>>
资源描述
silicon Simplicity Studio中提供的SPI操作,扩展性差,不支持读写cmd变长操作,下面根据SPI控制器的基本原理,重新封装了 SPI的驱动,并提供SPI NOR flash驱动进行验证。spi.c内容如下:* Copyright (c) 2015 by Silicon Laboratories Inc. All rights reserved.* #include efm8_config.h#include SI_EFM8UB2_Register_Enums.h#include spi_0.h/ Runtime API/ Flag to indicate if driver should control Nss (chip select) static bool useNss = false;/ flag to indicate we are in master mode (else slave) static bool modeIsMaster = false;/ flag to indicate that init vars (above) are valid. If they are/ not valid then a special one-time init will be called to set them static bool initIsValid = false;uint8_t FlashWriteFlag=0;uint8_t FlashReadFlag=0;/All Gpio Initvoid SPICsInit()P1MDIN |= 2; /p1.1 outP1MDOUT |= 2;P1_B1=1;P1MDIN | = 8; /p1.7 outP1MDOUT | = 8;P1_B7=1;P2MDIN | = 0x3; /p2.0 p2.1outP2MDOUT | = 0x3;P2_B0=1;P2_B1=0;P2MDIN | = 0xF0; /p2.4 p2.5 p2.6 p2.7 outP2MDOUT | = 0xF0;P2 &=0xF0;P0MDIN |=0xFC;/p0.2 p0.3 p0.4 p0.5 outP0MDOUT |=0xFC;P0 &=0xFC;P0MDIN |=0x3;/p0.1 p0.0 inP0MDIN &= 0x3;P0 |=0x3;P2MDIN | = 0xC; /p2.2 p2.3outP2MDOUT &= 0xC;P2_B2=1;P2_B3=1;/ Initialize internal state variables. This is used if init API is/ not called./static void SPI0_internalInit(void)/ figure out if we are master mode, and using 4-wire or not modeIsMaster = SPI0CFG & SPI0CFG_MSTEN_MASTER_ENABLED;useNss = SPI0CN0 & SPI0CN0_NSSMD_FMASK;/ indicate that init has now been doneinitIsValid = true;/ / Write a byte if transmit buffer is not full./ bool SPI0_writeByte(uint8_t value)bool ret = false;/ check to see if transmit buffer is not fullif (SPI0CN0_TXBMT)SPI0DAT = value;ret = true;return ret;/ Write a byte, waiting for transmit buffer to be empty/void SPI0_pollWriteByte(uint8_t value)/ wait for TX emptywhile (!SPI0CN0_TXBMT)SPI0DAT = value;#if 0/ Perform a multi-byte transfer, waiting for each byte to complete./uint8_tSPI0_pollTransfer(SI_VARIABLE_SEGMENT_POINTER(pTxBuffer, uint8_t,EFM8PDL_SPI0_TX_SEGTYPE),SI_VARIABLE_SEGMENT_POINTER(pRxBuffer, uint8_t,EFM8PDL_SPI0_RX_SEGTYPE),SPI0_TransferDirection_t dir,uint8_t xferCount)uint8_t txCount = xferCount;bool checkNss = false;/ This function is not interrupt driven and if SPI interrupts are/ enabled, it can cause interference.SPI0_disableInt();/ make sure SPI is not already busywhile (SPI0CFG & SPI0CFG_SPIBSY_BMASK)/ Check to see if run-time mode variables have been set up if (!initIsValid)SPI0_internalInit();/ Flush the RX buffer in case something is in thereuint8_t dummy = SPI0DAT;/ Clear the interrupt flag that is used to indicate transfer complete SPI0CN0_SPIF = 0;/ assert NSS (if used)if (modeIsMaster & useNss)SPI0CN0_NSSMD0 = 0;/ Wait in loop until the requested number of transfers are complete/ Note: xferCount tracks the number of bytes receivedwhile (xferCount)/ If the transmit buffer is empty and there are still bytes to/ write, then write a byte outif (SPI0CN0_TXBMT & txCount)/ If user provided a write buffer then use thatif (dir & SPI0_TRANSFER_TX)SPI0DAT = *pTxBuffer;+pTxBuffer;/ else user did not provide write buffer so just use zeroeselseSPI0DAT = 0;-txCount;/ If the interrupt flag is set it means a transfer has completed/ so read a byteif (SPI0CN0_SPIF)SPI0CN0_SPIF = 0;/ If user provided RX buffer, then read byte into bufferif (dir & SPI0_TRANSFER_RX)*pRxBuffer = SPI0DAT;+pRxBuffer;/ else there is no RX buffer so just throw away the incoming byte elseuint8_t dummy = SPI0DAT;-xferCount;/ If we are in slave mode and 4-wire, then check to make sure/ slave is selected. If not it means the spi master stopped/ the transfer. Bust out of the polling loop so we dont hang/ here forever.if (!modeIsMaster & useNss)/ wait for nss to be asserted the first time before we/ start checking itif (!checkNss)if (SPI0CFG & SPI0CFG_SLVSEL_BMASK)checkNss = true;elseif (!(SPI0CFG & SPI0CFG_SLVSEL_BMASK)break;/ Transfer is done. Deassert NSS (if used) if (modelsMaster & useNss)SPI0CN0_NSSMD0 = 1;return xferCount;#endif void CS_Ctrl(SPI_CS PinNO,uint8_t pinlevel)switch(PinNO)case CS_FLASH:P2_B0=pinlevel;break;case CS_TXPLL:P1_B1=pinlevel;break;case CS_RXPLL:P1_B7=pinlevel;break;default:break;uint8_tSPI0_pollTransfer(SI_VARIABLE_SEGMENT_POINTER(pTxBuffer,uint8_t,EFM8PDL_SPI0_TX_SEGTYPE),SI_VARIABLE_SEGMENT_POINTER(pRxBuffer,uint8_t,EFM8PDL_SPI0_RX_SEGTYPE),uint32_t txCount, uint32_t rxCount,uint8_t PinNO)uint32_t uloop=0;uint8_t trytimes =0;/ This function is not interrupt driven and if SPI interrupts are / enabled, it can cause interference.SPI0_disableInt();/ make sure SPI is not already busywhile (SPI0CFG & SPI0CFG_SPIBSY_BMASK)/ Check to see if run-time mode variables have been set upif (!initIsValid)SPI0_internalInit();/ Clear the interrupt flag that is used to indicate transfer complete SPI0CN0_SPIF = 0;/ assert NSS (if used)if (modeIsMaster & useNss)SPI0CN0_NSSMD0 = 0;/ P1_B1=0;CS_Ctrl(PinNO,0);for(uloop=0; ulooptxCount; uloop+)while(!SPI0CN0_TXBMT);SPI0DAT = *pTxBuffer;+pTxBuffer;trytimes=0;for(uloop=0; uloop10)FlashReadFlag=0;break;*pRxBuffer = SPI0DAT;+pRxBuffer;/ while (SPI0FCT & SPI0FCT_TXCNT_FMASK) SPI0FCT_TXCNT_SHIFT);while (!(SPI0CFG & 0x2);/ Wait until the last byte in the shift register is transferredwhile (SPI0CFG & SPI0CFG_SPIBSY_SET);/ P1_B1=1;CS_Ctrl(PinNO,1);return 0;#if 0/ Check if SPI is busy with a transfer in progress./bool SPI0_isBusy(void)uint8_t count = 0;bool ret = false;/ the SPI busy bit can drop between bytes so you cant just poll/ it to find out when all the bytes have been transferred. Or sometimes/ you will catch it not set, between bytes when it is really still/ busy. To make busy test useful, we need to know when it is done/ with all bytes. That is why there is a loop below./ Read it several times and if the bit is ever marked busy, then/ return busy indication.for (count = 0; count 512)divider = 512;if (divider 2)divider = 2;/ make even valuedivider &= 1;/ Transform the divider to the form needed by SFR./ See equation in the data sheet for more informationdivider /= 2;divider -= 1;/ disable SPI before configuring, then update the valueSPI0CN0_SPIEN = 0;SPI0CKR = (uint8_t)divider;SPI0CN0_SPIEN = 1;#if EFM8PDL_SPI0_USE_BUFFER = 1/ flag to indicate that RX buffer should be used for buffered transfers static bool useRx = false;/ flag to indicate that TX buffer should be used for buffered transfersstatic bool useTx = false;static uint8_t rxCountRemaining = 0;static uint8_t txCountRemaining = 0;static uint8_t bytesRemaining = 0;static SI_VARIABLE_SEGMENT_POINTER(pTxBuf, uint8_t, EFM8PDL_SPI0_TX_SEGTYPE) = NULL; static SI_VARIABLE_SEGMENT_POINTER(pRxBuf, uint8_t, EFM8PDL_SPI0_RX_SEGTYPE) = NULL;/ / Set up an interrupt driven SPI transfer./ voidSPI0_transfer(SI_VARIABLE_SEGMENT_POINTER(pTxBuffer, uint8_t,EFM8PDL_SPI0_TX_SEGTYPE),SI_VARIABLE_SEGMENT_POINTER(pRxBuffer, uint8_t,EFM8PDL_SPI0_RX_SEGTYPE),SPI0_TransferDirection_t dir, uint8_t xferCount)rxCountRemaining = xferCount;txCountRemaining = xferCount;bytesRemaining = xferCount;pTxBuf = pTxBuffer;pRxBuf = pRxBuffer;useRx = dir & SPI0_TRANSFER_RX;useTx = dir & SPI0_TRANSFER_TX;/ Check to see if run-time mode variables have been set up if (!initIsValid)SPI0_internalInit();/ Flush the RX buffer in case something is in thereuint8_t dummy = SPI0DAT;/ Clear all the interrupt flagsSPI0CN0 &= 0xF0;/ assert NSS (if used)if (modeIsMaster & useNss)SPI0CN0_NSSMD0 = 0;#if EFM8PDL_SPI0_USE_PIPELINE = 0/ Write the first byte to get the transfer startedif (SPI0CN0_TXBMT & txCountRemaining)/ If user provided tx data, then use thatif (useTx)SPI0DAT = *pTxBuf;+pTxBuf;/ Otherwise no tx data, so just stuff zeroeselseSPI0DAT = 0;-txCountRemaining;#else/ Stuff as many bytes as we can in the tx buffer to start.while (SPI0CN0_TXBMT & txCountRemaining)/ If user provided tx data, then use thatif (useTx)SPI0DAT = *pTxBuf;+pTxBuf;/ Otherwise no tx data, so just stuff zeroeselseSPI0DAT = 0;-txCountRemaining;#endif/ At this point SPI should be running and the rest will be handled / in the interrupt service routine/ / Stop a running SPI transfer./ void SPI0_abortTransfer(void)/ Resetting the counters will cause the ISR to ignore any remaining / SPI interrupts.txCountRemaining = 0;rxCountRemaining = 0;useTx = false;useRx = false;pTxBuf = NULL;pRxBuf = NULL;/ drop the chip select if used if (modeIsMaster & useNss)SPI0CN0_NSSMD0 = 1;/ Get the number of bytes remaining in the transfer. This will really/ be the number of RX bytes./uint8_t SPI0_bytesRemaining(void)return bytesRemaining;/ Handler for interrupt driven SPI data transfers./SI_INTERRUPT(SPI0_ISR, SPI0_IRQn)uint8_t intFlags;/ Get the interrupt flags and then clear any that are pending intFlags = SPI0CN0 & 0xF0;SPI0CN0 = (SPI0CN0 & (intFlags | 0x0F);/ Handle completion of one frame (byte) of data transferred./ This means we are ready to read a received byte, and write/ the next TX byte.if (intFlags & SPI0_INT_IF)/ Read bytes as long as the read count is non-zeroif (rxCountRemaining)/ If the user provided an RX buffer then read a byte into that.if (useRx)*pRxBuf = SPI0DAT;+pRxBuf;/ Else, user does not care about RX data so do a dummy read. elseuint8_t dummy = SPI0DAT;-rxCountRemaining;/ If we get to zero remaining, it means that all the/ bytes have been transferred.if (rxCountRemaining = 0)/ deassert NSS (if used)if (modeIsMaster & useNss)SPI0CN0_NSSMD0 = 1;/ Tell user that the transfer is complete.SPI0_transferCompleteCb();/ If there are more RX bytes to receive, then remember the/ current count to be used by _bytesRemaining()elsebytesRemaining = rxCountRemaining;/ Write bytes if there are more TX bytes to send and the/ TX buffer is not fullif (txCountRemaining & SPI0CN0_TXBMT)/ If user provided a TX buffer then write the next byteif (useTx)SPI0DAT = *pTxBuf;+pTxBuf;/ Otherwise user did not provide a buffer so just write a zero. elseSPI0DAT = 0;-txCountRemaining;#if EFM8PDL_SPI0_USE_ERR_CALLBACK = 1/ Check for errors and notify userif (intFlags & (SPI0_MODF_IF | SPI0_RXOVR_IF)/ Note, the RXOVRN bit only happens in slave mode, and the MODF/ bit is not very likely, so in master mode this block will/ probably not ever be used.SPI0_transferErrorCb(intFlags & (SPI0_MODF_IF | SPI0_RXOVR_IF);#endif / EFM8PDL_SPI0_USE_ERR_CALLBACK#endif / EFM8PDL_SPI0_USE_BUFFER/* basic API to provide simple access to the SPI features, and a more advanced (end spi_0_group) * addtogroup spi_0_group SPI0 Driver* * brief Peripheral driver for SPI 0* # Introduction #* This module provides an API for using the SPI0 peripheral. There is a/#endifspi.h内容如下:* Copyright (c) 2015 by Silicon Laboratories Inc. All rights reserved.* #ifndef _SPI_0_H_#define _SPI_0_H_#include efm8_config.h#include SI_EFM8UB2_Register_Enums.h* buffered API that provides interrupt based transfers. The user can also* choose to configure the SPI peripheral at run-time using the initialization* API or to bypass the initialization API and configure the peripheral during* a central system initialization function.* # Multibyte Transfers #* There are two methods of performing multibyte transfers, using a polling* (blocking) method or an interrupt (non-blocking) method. The setup and* function call signature is the same for both. In each case the caller* provides buffers for transmit and receive data. The transmit data buffer* must be pre-filled with the data to be sent, while the receive buffer will* be filled with received data bytes. The caller must provide pointers to* buffers of sufficient size to complete the transfer.* If you want to only perform a transfer in one direction, then you can supply* a NULL pointer for the unused buffer. For transmit-only transfers, all* received bytes are discarded. For receive-only transfers, zero bytes will* be transmitted.* For bidirectional transfers, the same number of bytes are transmitted and* received. For a transfer where the number of transmitted and received bytes* are not the same, you must chain together transfers as needed to get the* number of bytes needed in each direction.* # Chip Select #* The SPI interface can be used in 3-wire or 4-wire mode. If 3-wire mode* is used, then the SPI interface can be used with no chip select, or the* application can use a separate GPIO for the chip select. For example, if* a SPI master needs to control several SPI slaves, then you would choose* 3-wire mode, and use a separate GPIO as the chip select for each SPI* slave. In this case, the application must control the GPIO as chip select,* asserting it before starting a transfer and de-asserting when the transfer* is complete.* If 4-wire mode is used, then the chip select is managed by the driver and* the peripheral. When a SPI master, the chip select signal (NSS) will be* asserted automatically at the start of the transfer and de-asserted when* complete. If a SPI slave, then the NSS signal is monitored and used to* gate SPI transfers.*/ The following section is used to document configuration options* addtogroup spi0_config SPI Driver Configuration* * brief Driver configuration constants read from efm8_config.h* This peripheral driver will look for configuration constants in* *efm8_config.h*. This file is provided/written by the user and should be* located in a directory that is part of the include path.* def EFM8PDL_SPI0_USE_BUFFER* brief Controls inclusion of SPI0 Buffer Access API.* The Buffer Access API includes code in the SPI driver to buffer incoming* and outgoing SPI data including an interrupt handler that makes callbacks.* When set to 1 the SPI0 Buffered Access API is included in the driver.* note When this feature is enabled, a SPI0 interrupt handler will be* included in the driver. If you want to manage SPI interrupts with* application code, then this option should be disabled.* The default setting is 0 and may be overridden by defining the value* in efm8_config.h.* def EFM8PDL_SPI0_USE_ERR_CALLBACK* brief Controls whether buffered API uses an error callback function.* This option is only meaningful if ref EFM8PDL_SPI0_USE_BUFFER is enabled.* If this option is enabled, when an error is detected in the SPI interrupt* handler, the callback function SPI0_transferErrorCallback() will be called.* If this option is not enabled, then the error callback will not be called* and it does not need to be provided by the application.* note This feature is only useful if the SPI peripheral is to be used* in slave mode.* The default setting is 0 and may be overridden by defining the value* in efm8_config.h.* def EFM8PDL_SPI0_USE_PIPELINE* brief Controls buffered mode data pipelining.* When using a buffered transfer with SPI0_transfer() the data can be* pipelined such that the driver attempts to keep the transmit buffer as* full as possible. This will use the full bandwidth of the hardware* peripheral, but can cause data loss if system interrupt latency is too* high. The SPI interrupt must be serviced within 2 byte-times or received* data can be lost. If this feature is disabled, then writes and reads* will be matched to ensure that no receive data is lost. However then* there can be irregular timing gaps between bytes and the full bandwidth* of the SPI bus is not used.* note This applies to master mode. If you intend to use slave mode,* then this feature must be turned on.* If you are using slave mode then this feature should be enabled. If you* are only using master mode then you can leave this disabled if you are* concerned about interrupt latency in your system and SPI bus performance* is not important. You can enable this if the interrupt latency in your* system is not too high, or if the SPI interrupt priority is set high* enough that it cannot miss SPI interrupts.* The default setting is 0 and may be overridden by defining the value* in efm8_config.h.* def EFM8PDL_SPI0_RX_SEGTYPE* brief Controls the type of pointer used for receive buffers.* Sets the memory segment type for the receive buffer pointer when using* SPI0_pollTransfer() or SPI0_transfer(). Valid values are:* - SI_SEG_XDATA (default)* - SI_SEG_PDATA* - SI_SEG_IDATA* - SI_SEG_CODE* - SI_SEG_GENERIC* warning Use of generic pointers will increase the code size and reduce* performance of buffering functions. The specific memory segment should* always be specified if possible.* def EFM8PDL_SPI0_TX_SEGTYPE* brief Controls the type of pointer used for transmit buffers.* Sets the memory segment type for the transmit buffer pointer when using* SPI0_pollTransfer() or SPI0_transfer(). Valid values are:* - SI_SEG_XDATA (default)* - SI_SEG_PDATA* - SI_SEG_IDATA* - SI_SEG_CODE* - SI_SEG_GENERIC/* (end addtogroup spi0_config */ Option macro default values#ifdef IS_DOXYGEN#define EFM8PDL_SPI0_USE_BUFFER 1#define EFM8PDL_SPI0_USE_ERR_CALLBACK 1#endif #ifndef EFM8PDL_SPI0_USE_BUFFER#define EFM8PDL_SPI0_USE_BUFFER 0#endif#ifndef EFM8PDL_SPI0_TX_SEGTYPE#define EFM8PDL_SPI0_TX_SEGTYPE SI_SEG_XDATA#endif#ifndef EFM8PDL_SPI0_RX_SEGTYPE#define EFM8PDL_SPI
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 图纸设计 > 毕设全套


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!