• AM335X平台下的mcspi源代码详解中断模式下的初始化、收发数据


    AM335X简介:

    AM335X是TI(德州仪器)基于 ARM Cortex-A8内核的AM335X微处理器在图像、图形处理、外设和诸如 EtherCAT 和 PROFIBUS 的工业接口选项方面进行了增强。AM335X的优点有如下几个:
    第一:该器件是最便宜的Cortex A8 处理芯片,这个对中国市场至关重要 ,甚至是决定性的因素。
    第二:TI 史上公开资料最全的一个芯片,包含starterware裸机系统,android2.3-4.1系统,linux3.2系统。
    第三:产品定位最清晰的一个,工业控制MCU
    第四:唯一一个集成2个MAC的 MCU.
    第五:目前唯一支持Androd 4.0, 而且同时支持3个操作系统 Linux,Android,WinCE.另外支持第三方实时操作系统如QNX、VxWorks等系统

    以下源码来源于TI提供的starterware工程中的spiflash例子。

    内容通过翻译总结,加上自己的理解试验而成。单片机挺好玩的,比起信息系统开发,工作量并不大。

    mcspi模块:

    mcspi即SPI接口的flash,支持从芯片选择引脚最大频率为48MHzmcspi可以配置,生成DMA事件到EDMA控制器,用于传输数据mcspi设备抽象层提供一些

    接口API,来配置和使用mcspi模块进行数据传输。传输数据可以用中断模式或DMA模式。今天学习Mcspi中断模式的源码看看如何使用

    一、初始化配置:

    1,mcspi外围时钟使能,调用McSPI0ModuleClkConfig().

    2,引脚复用spi_clkspi_d0spi_d1,调用mcspipinmuxsetup()

    3,引脚复用CS,调用mcspi0cspinmuxsetup()

    4,MCSPI本地复位,调用McSPIReset().

    5,mcspi可以配置在4针模式(CLKD0D1CS),即CS使能,调用mcspicsenable()

    6,操作主模式启用,调用mcspimastermodeenable()

    7,配置单/多通道模式发送/接收模式,设置 IS, DPE0, DPE1dpe0dpe1。调mcspimastermodeconfig() APIdpe0dpe1将配置方向

    spid0spid1引脚为输入或输出请参阅验证SPI数据引脚连接并做相应设置。这个函数是主模式下必须要配置的。

    8,spi总线时钟配置,调用mcspiclkconfig()。粒度可设定1个时钟周期或2 ^ n时钟周期,时钟极性也在这里配置

    9,mcspi字长,用mcspiwordlengthset()

    10,极性spien芯片选择),mcspicspolarityconfig()

    11,启用/禁用transmitter and receiver FIFOs,mcspitxfifoconfig()mcspirxfifoconfig()

     1 int main(void)
     2 {
     3     volatile unsigned int count = 0x0FFFu;
     4     unsigned int retVal = FALSE;
     5     unsigned char choice = 0;
     6 
     7     /* Enable the clocks for McSPI0 module.*/
     8     McSPI0ModuleClkConfig();
     9 
    10     /* Perform Pin-Muxing for SPI0 Instance */
    11     McSPIPinMuxSetup(0);
    12 
    13     /* Perform Pin-Muxing for CS0 of SPI0 Instance */
    14     McSPI0CSPinMuxSetup(chNum);
    15 
    16     /* Initialize the UART utility functions */
    17     UARTStdioInit();
    18 
    19     UARTPuts("Here the McSPI controller on the SoC communicates with", -1);
    20     UARTPuts(" the SPI Flash.\r\n\r\n", -1);
    21 
    22     /* Enable IRQ in CPSR.*/
    23     IntMasterIRQEnable();
    24 
    25     /* Map McSPI Interrupts to AINTC */
    26     McSPI0AintcConfigure();
    27                     
    28     /* Do the necessary set up configurations for McSPI.*/
    29     McSPISetUp();
    30 
    31     /* Pass the write enable command to flash.*/
    32     WriteEnable();
    33 
    34     /* Wait until write enable command is successfully written to flash.*/
    35     while(FALSE == retVal)
    36     {
    37         retVal = IsWriteSuccess();
    38     }
    39 
    40     retVal = FALSE;
    41 
    42     UARTPuts("Do you want to erase a sector of the flash before ", -1);
    43     UARTPuts("writing to it ?.", -1);
    44     UARTPuts("\r\nInput y(Y)/n(N) to proceed.\r\n", -1);
    45 
    46     choice = UARTGetc();
    47     UARTPutc(choice);
    48 
    49     if(('Y' == choice) || ('y' == choice))
    50     {
    51         /* Erase a sector of flash.*/
    52         SectorErase();
    53     }
    54 
    55     /* Pass the write enable command to flash.*/
    56     WriteEnable();
    57 
    58     /* Wait until write enable command is successfully written to flash.*/
    59     while(FALSE == retVal)
    60     {
    61         retVal = IsWriteSuccess();
    62     }
    63 
    64     /* Write data of 1 page size to flash.*/
    65     WriteToFlash();
    66 
    67     while(count--);
    68     count = 0x0FFFu;
    69 
    70     /* Read data of 1 page size from flash.*/
    71     ReadFromFlash();
    72 
    73     while(count--);
    74 
    75     /* Verify the data written to and read from flash are same or not.*/
    76     VerifyData();
    77 
    78     while(1);
    79 }
    View Code
     1 /*
     2 ** This function will call the necessary McSPI APIs which will configure the 
     3 ** McSPI controller. 
     4 */
     5 static void McSPISetUp(void)
     6 {
     7 
     8     /* Reset the McSPI instance.*/
     9     McSPIReset(SOC_SPI_0_REGS);
    10 
    11     /* Enable chip select pin.*/
    12     McSPICSEnable(SOC_SPI_0_REGS);
    13 
    14     /* Enable master mode of operation.*/
    15     McSPIMasterModeEnable(SOC_SPI_0_REGS);
    16 
    17     /* Perform the necessary configuration for master mode.*/
    18     McSPIMasterModeConfig(SOC_SPI_0_REGS, MCSPI_SINGLE_CH, 
    19                           MCSPI_TX_RX_MODE, MCSPI_DATA_LINE_COMM_MODE_1,
    20                           chNum);
    21 
    22     /* Configure the McSPI bus clock depending on clock mode. */
    23     McSPIClkConfig(SOC_SPI_0_REGS, MCSPI_IN_CLK, MCSPI_OUT_FREQ, chNum, 
    24                    MCSPI_CLK_MODE_0);
    25 
    26     /* Configure the word length.*/
    27     McSPIWordLengthSet(SOC_SPI_0_REGS, MCSPI_WORD_LENGTH(8), chNum);
    28 
    29     /* Set polarity of SPIEN to low.*/
    30     McSPICSPolarityConfig(SOC_SPI_0_REGS, MCSPI_CS_POL_LOW, chNum);
    31 
    32     /* Enable the transmitter FIFO of McSPI peripheral.*/
    33     McSPITxFIFOConfig(SOC_SPI_0_REGS, MCSPI_TX_FIFO_ENABLE, chNum);
    34 
    35     /* Enable the receiver FIFO of McSPI peripheral.*/
    36     McSPIRxFIFOConfig(SOC_SPI_0_REGS, MCSPI_RX_FIFO_ENABLE, chNum);
    37 }
    McSPISetUp

    二、传输数据:

    初始化完毕后,可以传输数据了,看看发送数据的实现

    1,spien线强制拉低(即处于活动状态),mcspicsassert()

    2.中断使能,调用mcspiintenable()

    3,mcspi通道使能,mcspichannelenable(),mcspi一调用这个函数就会产生中断,取决于设置

    4,while(flag);//前面产生了中断,等待中断处理。中断的处理见McSPIIsr中断处理代码块

    5,在第三块中断处理结束后,返回flag=0,然后执行前面相反的工作,恢复为发送数据时的状态。即SPIEN拉高(禁止状态)mcspicsdeassert(),mcspi通道禁用mcspichanneldisable()

     1 /*
     2 ** This function will activate/deactivate CS line and also enable Tx and Rx
     3 ** interrupts of McSPI peripheral.
     4 */
     5 static void McSPITransfer(void)
     6 {
     7     p_tx = txBuffer;
     8     p_rx = rxBuffer;
     9 
    10     /* SPIEN line is forced to low state.*/
    11     McSPICSAssert(SOC_SPI_0_REGS, chNum);
    12 
    13     /* Enable the Tx/Rx interrupts of McSPI.*/
    14     McSPIIntEnable(SOC_SPI_0_REGS, MCSPI_INT_TX_EMPTY(chNum) | 
    15                    MCSPI_INT_RX_FULL(chNum));
    16 
    17     /* Enable the McSPI channel for communication.*/
    18     McSPIChannelEnable(SOC_SPI_0_REGS, chNum);
    19 
    20     /* Wait until control returns back from McSPI ISR.*/
    21     while(flag);
    22 
    23     flag = 1;
    24 
    25     /* Force SPIEN line to the inactive state.*/
    26     McSPICSDeAssert(SOC_SPI_0_REGS, chNum);
    27 
    28     /* Disable the McSPI channel.*/
    29     McSPIChannelDisable(SOC_SPI_0_REGS, chNum);
    30 }
    McSPITransfer

    三、中断处理:

    1,获取中断状态,mcspiintstatusget()

    2,处理完毕自然要清除,清除中断用mcspiintstatusclear()

    3,mcspi传输数据,mcspitransmitdata(),读取或接收数据,mcspireceivedata()

    4,传输完毕,用mcspiintdisable()发送处理完毕的标识。在第二块传输数据那,while(flag);flag=0,跳出了循环,继续执行。

     1 /*
     2 ** McSPI Interrupt Service Routine. This function will clear the status of the
     3 ** Tx/Rx interrupts when generated. Will write the Tx data on transmit data
     4 ** register and also will put the received data from receive data register to
     5 ** a location in memory.
     6 */
     7 static void McSPIIsr(void)
     8 {
     9     unsigned int intCode = 0;
    10 
    11     intCode = McSPIIntStatusGet(SOC_SPI_0_REGS);
    12 
    13     while(intCode)
    14     {
    15         if(MCSPI_INT_TX_EMPTY(chNum) == (intCode & MCSPI_INT_TX_EMPTY(chNum)))
    16         {
    17             McSPIIntStatusClear(SOC_SPI_0_REGS, MCSPI_INT_TX_EMPTY(chNum));
    18 
    19             length--;
    20 
    21             McSPITransmitData(SOC_SPI_0_REGS,(unsigned int)(*p_tx++), chNum);
    22 
    23             if(!length)
    24             {
    25                 McSPIIntDisable(SOC_SPI_0_REGS, MCSPI_INT_TX_EMPTY(chNum));
    26 
    27                 McSPIIntStatusClear(SOC_SPI_0_REGS, MCSPI_INT_TX_EMPTY(chNum));
    28             }
    29         }
    30 
    31         if(MCSPI_INT_RX_FULL(chNum) == (intCode & MCSPI_INT_RX_FULL(chNum)))
    32         {
    33             McSPIIntStatusClear(SOC_SPI_0_REGS, MCSPI_INT_RX_FULL(chNum));
    34 
    35             *p_rx++ = (unsigned char) McSPIReceiveData(SOC_SPI_0_REGS, chNum);
    36 
    37             if(!(length))
    38             {
    39                 McSPIIntDisable(SOC_SPI_0_REGS, MCSPI_INT_RX_FULL(chNum));
    40 
    41                 flag = 0;
    42             }
    43         }
    44 
    45         intCode = McSPIIntStatusGet(SOC_SPI_0_REGS);
    46     }
    47 }
    48 /********************************* End Of File ******************************/
    McSPIIsr中断处理

    四、写入Flash:

    1,有了前面的准备,就很简单了,直接调用McSPITransfer(),要按页写入,测试程序flash的页大小是256字节。稍微包装一下即可,这里只是一个例子,地址是写死的

    24位地址(第234字节,即高中低3个8位,最大地址2^24=16M).第一个字节是命令,写入flash是FLASH_PAGE_PROGRAM,而读取是FLASH_DATA_READ。

     1 static void WriteToFlash(void)
     2 {
     3     unsigned int index = 0;
     4 
     5     txBuffer[0] = FLASH_PAGE_PROGRAM;
     6     txBuffer[1] = FLASH_SECTOR_ADD_HIGH;
     7     txBuffer[2] = FLASH_SECTOR_ADD_MID;
     8     txBuffer[3] = FLASH_SECTOR_ADD_LOW;
     9 
    10     for(index = 0; index < 256; index++)
    11     {
    12         txBuffer[index + 4] = (unsigned char) index;
    13         vrfyData[index] = (unsigned char) index;
    14     }
    15 
    16     length = 260;
    17     
    18     McSPITransfer();
    19 }
    WriteToFlash

    四、从Flash读取:

     1,和写入类似,前四个字节,为命令+地址,FLASH_DATA_READ,地址高8位,地址中8位,地址低8位

     1 /*
     2 ** This function will read data of 1 page size from a specific sector of flash.
     3 */
     4 static void ReadFromFlash(void)
     5 {
     6     unsigned int index = 0;
     7 
     8     txBuffer[0] = FLASH_DATA_READ;
     9     txBuffer[1] = FLASH_SECTOR_ADD_HIGH;
    10     txBuffer[2] = FLASH_SECTOR_ADD_MID;
    11     txBuffer[3] = FLASH_SECTOR_ADD_LOW;
    12 
    13     for(index = 4; index < 260; index++)
    14     {
    15         txBuffer[index] = 0;
    16     }    
    17 
    18     length = 260;
    19 
    20     McSPITransfer();
    21 }
    ReadFromFlash

    ------------------------------------------------------------------------------------------------------------------------

     至此,例子分析完毕,用到实际项目中,需要适应改写一下。我的AM335X测试平台,要实现如下接口:

    B32 D_DF_Read( U8* p, U32 addr, U32 Size ),把addr处Size大小的内容读到* p中。因为是最底层的驱动,按页面读取。SIZE固定为256byte(这里是8位byte,用字节有歧义),上层调用者传入指针 p和地址即可。

  • 相关阅读:
    ie6 fixed 实现
    javascript 数组 prototype疑问
    深入了解CLR的加载过程
    sql
    关于 vue2.x 的 $attrs 和 $listeners
    VS Code 状态栏颜色修改
    vueelementadmin 安装第三包(npm install)时报错
    前端 JS 问题记录
    浏览器调试工具调试css样式
    浏览器调试固定鼠标悬浮的样式
  • 原文地址:https://www.cnblogs.com/zkp2010/p/3107437.html
Copyright © 2020-2023  润新知