完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
问候语,
我正在熟悉SPI主中断,所以我启动了一个项目,通过SPI利用SPI TX FIFO和中断的方式发送数据,这样我就不会拖延CPU等待传输完成,在这个例子中,CPU触发SPI传输并留下中断。s来处理它,同时CPU对数字输出(愚蠢但说明点;p)进行图示,这在使用没有DMA的PSoC时是有用的。 仅使用SPIXXFILASYNC函数发送3个字节(小于FIFO深度): 主(空) { const UIT88T数据DATASPI [ 10 ]={0x01,0x02,0x03,0x04,0x05, 0x06,0x07,0x08,0x09,0x0a}; iSrxSPIXTXYSTARTEX(SPIXTXY-HANDER); /启用中断 囊状的; //配置和启用外围设备 SPIX START(); UARTHART START(); UARTHI PUTCHAR(0x0C);/ /清除屏幕 UARTH PoStand(“中断测试SPI。RN”); (1){ 如果(TxSIDID==TXSY状态){ SpxxxFier-AssiCh(DATAYSPI,3); } CydelayUS(10); LeDIX写(~LeDyRad()); } } 用LA捕获的数据传输(你可以看到LED在顶部跟踪): 仅发送10字节(超过FIFO深度): 主(空) { const UIT88T数据DATASPI [ 10 ]={0x01,0x02,0x03,0x04,0x05, 0x06,0x07,0x08,0x09,0x0a}; iSrxSPIXTXYSTARTEX(SPIXTXY-HANDER); /启用中断 囊状的; //配置和启用外围设备 SPIX START(); UARTHART START(); UARTHI PUTCHAR(0x0C);/ /清除屏幕 UARTH PoStand(“中断测试SPI。RN”); (1){ 如果(TxSIDID==TXSY状态){ SpxxxFier-AssiCh(DATAYSPI,10); } CydelayUS(10); LeDIX写(~LeDyRad()); } } 用LA捕获的数据传输(你可以看到LED在顶部跟踪): 希望对你有用(找到附加的项目,它使用基于UDB的SPI,但是这个原理也适用于SCB),如果你看到错误的东西,让我知道。 当做, 卡洛斯 SIPUDBYAXYNCXXFE.CYPRJ.SARVEVE01.ZIP 1.5兆字节 以上来自于百度翻译 以下为原文 Greetings, I was getting familiar with the SPI Master interrupts, so i started a project to send data via SPI taking advantage of the SPI TX FIFO and interrupts, so that way i don't stall the CPU waiting for the transfer to be completed, in the example the cpu triggers the SPI transfer and leave the interrupts to handle it, meanwhile the CPU toogles a digital output (silly but illustrate the point ;P), this can be useful when using PSoCs with no DMA. To send just 3 bytes (less than the FIFO depth) using the spi_xfer_async function: int main(void){ const uint8_t data_spi[10] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A}; isr_SPI_Tx_StartEx(SPI_tx_handler); // Enable interrupts CyGlobalIntEnable; // Configure and enable the peripherals SPI_Start(); UART_Start(); UART_PutChar(0x0C); // clear the screen UART_PutString("Test SPI with interrupts.rn"); while (1) { if (TX_IDLE == tx_state) { spi_xfer_asynch(data_spi, 3); } CyDelayUs(10); LED_Write(~LED_Read()); }} The data transfer captured with a LA (you can see the LED toogling on the top trace): To send just 10 bytes (more than the FIFO depth): int main(void){ const uint8_t data_spi[10] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A}; isr_SPI_Tx_StartEx(SPI_tx_handler); // Enable interrupts CyGlobalIntEnable; // Configure and enable the peripherals SPI_Start(); UART_Start(); UART_PutChar(0x0C); // clear the screen UART_PutString("Test SPI with interrupts.rn"); while (1) { if (TX_IDLE == tx_state) { spi_xfer_asynch(data_spi, 10); } CyDelayUs(10); LED_Write(~LED_Read()); }} The data transfer captured with a LA (you can see the LED toogling on the top trace): Hope is useful to you (find the project attached, it use SPI based on UDB, but the principle apply to SCB as well), if you see something wrong let me know. Regards, Carlos |
|
相关推荐
5个回答
|
|
我倾向于“重新发明轮子”,我知道有一种方法让组件内部实现比SPI FIFO(大于4字节)更大的传输处理,但是该实现使用软件,而这一个尝试利用FIFO HW的优势。
以上来自于百度翻译 以下为原文 I tend to 'reinvent the wheel', i know there's a way to let the component internal implementation to handle transfers bigger than the SPI FIFO (bigger than 4bytes), but that implementation use software and this one try to take advantage of the FIFO hw |
|
|
|
ggfx 发表于 2018-11-19 08:28 是的,因为现有的实现已经使用了FIFO和中断,所以您确实重新发明了轮子。(实际上,在没有使用TX FIFO的情况下,您不能发送SPI上的任何东西。 但是你的函数以更好的方式处理CS信号,并且更容易使用。 以上来自于百度翻译 以下为原文 Yes, you certainly did reinvent the wheel since the existing implementation already uses the FIFO and interrupts. (Actually you cannot send anything over SPI without using the TX FIFO But your function handles the CS signal in a better way and is easier to use. |
|
|
|
lxhzx 发表于 2018-11-19 08:44 嗨,谢谢你看, 我没有检查他们的所有实现,我只是看到大量的代码处理软件缓冲器和Irc的实现,等待直到所有的数据被发送,而我的只是触发转移和叶子,它可能是有用的,当“画”在显示器上的东西,触发转移和L屋檐,不必等到画满显示器。 这个项目没有处理(接收)数据,也许我可以在下个周末工作。 图片在这里看到小,但我控制两个/ SS线,一个软件(蓝色通道)和一个与SS信号的SPI组件的含义控制硬件(橙色通道),似乎他们几乎相同的性能,硬件控制/ SS得到断言R.THO,我记得使用SPI和/SS控制硬件时,使用它们的实现(或者我没有正确使用它)存在很多问题。 希望你和其他人能参与这个项目 这是一个有趣的宠物项目工作,我希望在其他项目上使用它。 以上来自于百度翻译 以下为原文 Hi, thanks for taking a look, I didn't check all their implementation, i just saw a big amount of code handling the software buffer and iirc their implementation waits until all the data is sent, while mine just triggers the transfers and leaves, it may be useful when "drawing" something on a display, trigger the transfer and leave, without having to wait to draw the full display. This project doesn't handle (yet) receiving data, may be i can work on that the next weekend. The pictures saw small on here but i controlled two /SS lines, one with software (the blue channel) and one with the /SS signal of the SPI component meaning controlled with hardware (orange channel), it seems like they got almost the same performance, the hardware controlled /SS gets asserted faster tho, i remember having a lot of problems when using the SPI and the /SS controlled by hardware using their implementation (or i wasn't using it correctly). Hope you and others can play around with the project It was a fun pet project to work on , i hope to use it on another projects. |
|
|
|
该项目是基于SPIXXFILASYANC函数和SPI完成的中断和SPI主机的字节事务完成标志触发的。SPI主组件被配置为具有4字节深度TX FIFO,这样我们避免使用软件缓冲器。
SPIXXFYLASYNC函数检查要传输的数据的大小,并相应地填充SPI TX FIFO,如果SPI TX FIFO未被填充(例如发送一个字节),则在每个字节之间传输4US(CPU 24MHz)的间隙,我们不希望这样,我们喜欢作为FA运行。ST,所以如果我们填写SPI TX先进先出超过1字节,我们没有差距,如在第一个帖子的图片显示。 空隙SPIXXFLYAXYCH(const UIT88T*数据,consisisit大小) { 环磷酸脂; 如果(TxSIDID==TXSY状态){ TXYSTATE = TXX转移; If(size & lt;= SpIsFIFOIX大小){ SSX编写(0); //填充SPI TX FIFO 对于(Unt8It t i=0;i & lt;大小;i++){ SPIXWORTEXDATA(数据[I]); } }否则{ TXI Buffel.CNT=0; Txl Buffer-LeftTytoxxFER=大小-SPixFIFOH大小; MeMCPY(TxxBuff.Fuffor,and DATA [SPIXFIFOZYSIZE),TXYBuffel.LeftTytox XFER); SSX编写(0); //填充SPI TX FIFO 对于(Unt8It t i=0;i & lt;SpiffFioSosig;i++){ SPIXWORTEXDATA(数据[I]); } } } 囊状的; } ToDo:当大小参数大于4时,用两个字节代替4来填充SPI TXFIFO。 ToDO2:删除软件控制/ SS线,并与硬件控制的一个,HW控制一个/ SS信号低和高一点更快(待测量)。 中断处理程序如下,它清除SPI中断标志,并检查中断是否由SPI字节传输完成或SPI完成的中断源触发。 空隙SPIX TXX处理程序(无效) { //通过读取SPIXTXSTSTS寄存器清除中断标志 易失性UIT88T STS = SPICARADTXXSTATUS(); /todo:从MISO获取数据 (空)SPILRADRXSTATUS(); 如果(TXIDIDLE)!= txSt态){ 如果(SPIOSSTSYBYTEX完成和STS){ 如果(TXIDIDLE)!= txSt态){ 我们还有数据要发送吗? 如果(TxlBuff.LeftTytox xFER & gt;TxxBuff.CNT){ SpxWruteXDATA(Txx缓冲器,缓冲器[TxxPuff.CNT]); TXX缓冲液,CNT++; } }否则{ 我们不应该进来。 } } //中断是由SpIOSO完成的标志触发的。 //当TX FIFO上检测到数据时,SPICAL空闲标志被设置为0。 /SPIGHIDLE设置为1是SPI状态机的默认状态, 如果(SPIXSTSSPILIDLE和STS){ SSX编写(1); TXYSTATE = TXIDLE; } } } todo:获取必要的数据。 Txx缓冲区是一个具有三个成员的Buffer-Hyt类型变量(TyPulfStrut): TyBuffsStult{ UIT88T缓冲区[马克斯项目]; uTN8T; UIT88T LexTytotoxFER; } Buffelyt; 其中缓冲部件是一个缓冲器,用来保存要用中断传输的数据的副本,CNT成员是要传输的数据量,而LefftTytox传输只是用SPIXXFILASYANC函数传输的数据之后要传输的字节数。前面定义了Max项目常数。 这里我看到两种改进方法: -拥有全局用户数据缓冲区和缓冲区成员将只是指向它的指针。 -使用缓冲成员作为用户数据缓冲区,这样我们就避免了另一个缓冲区。 但是有很多方法来改进这个项目,如果你有什么想法,请告诉我们。 当做, 卡洛斯 以上来自于百度翻译 以下为原文 The project is based on the spi_xfer_async function and the interrupt triggered by the SPI Done and Byte Transaction Complete flags of the SPI Master. The SPI Master component is configured to have 4byte depth TX FIFO, this way we avoid using the software buffer. The spi_xfer_async function checks the size of the data to be transferred and fills the SPI TX FIFO accordingly, if the SPI TX FIFO is not filled (for example sending just one byte) we got gaps of 4us (with the CPU @ 24MHz) between the each byte transferred, we don't want that, we like to run as fast as possible so if we fill the SPI TX FIFO with more than 1 byte we have no gaps as shown on the pictures of the first post. void spi_xfer_asynch(const uint8_t *data, const size_t size){ CyGlobalIntDisable; if (TX_IDLE == tx_state) { tx_state = TX_TRANSFERING; if (size <= SPI_FIFO_SIZE) { SS_Write(0); // fill the spi tx fifo for (uint8_t i = 0; i < size; i++) { SPI_WriteTxData(data); } } else { tx_buffer.cnt = 0; tx_buffer.left_to_xfer = size - SPI_FIFO_SIZE; memcpy(tx_buffer.buffer, &data[SPI_FIFO_SIZE], tx_buffer.left_to_xfer); SS_Write(0); // fill the spi tx fifo for (uint8_t i = 0; i < SPI_FIFO_SIZE; i++) { SPI_WriteTxData(data); } } } CyGlobalIntEnable;} TODO: Test filling the SPI TX FIFO with just two bytes instead of 4 when the size parameter is bigger than 4. TODO2: Remove the software controlled /SS line and work with the hardware controlled one, the hw controlled one set the /SS signal low and high a bit faster (to be measured). The interrupt handler is as follows, it clears the SPI interrupt flag and checks if the interrupt was triggered by the SPI Byte Transfer Complete or SPI Done interrupt sources. void SPI_tx_handler(void){ // clear interrupt flag by reading the SPI_TX_STS register volatile uint8_t sts = SPI_ReadTxStatus(); // TODO: Get the data from MISO (void)SPI_ReadRxStatus(); if (TX_IDLE != tx_state) { if (SPI_STS_BYTE_COMPLETE & sts) { if (TX_IDLE != tx_state) { // do we still have data to send? if (tx_buffer.left_to_xfer > tx_buffer.cnt) { SPI_WriteTxData(tx_buffer.buffer[tx_buffer.cnt]); tx_buffer.cnt++; } } else { // we shouldn't get in here } } // the interrupt was triggered by the SPI_DONE flag // the SPI_IDLE flag is set to 0 when data is detected on the TX FIFO // SPI_IDLE set to 1 is the default state of the SPI state machine, if (SPI_STS_SPI_IDLE & sts) { SS_Write(1); tx_state = TX_IDLE; } }} TODO: Get the data received if necessary. The tx_buffer is a buffer_t type variable (typedef struct) with three members: typedef struct { uint8_t buffer[MAX_ITEMS]; uint8_t cnt; uint8_t left_to_xfer;} buffer_t; where the buffer member is a buffer to hold a copy of the data to be transferred with the interrupt, the cnt member is the amount of data to be transferred and the left_to_transfer is just a count of byte to be transferred after the data transferred with the spi_xfer_async function. the MAX_ITEMS constant is defined previously. Here i see two ways to improve it: - Having a global user data buffer and the buffer member will be just a pointer to it. - Using the buffer member as our user data buffer, so we avoid having another buffers. But there are a lot of ways to improve the project, if you have some ideas to do so please let us know Regards, Carlos |
|
|
|
我工作了一点,并更新了Buffryt结构,现在它只有一个指向UIT88T的指针,而不是UIT88T的数组,所以现在我们必须有一个具有全局范围的UIT88T数组来处理它,这样就避免了以前的实现中使用MycPy(关于SPixxFixAsiNC函数)。
这是新的Meal.C文件 包括“项目H” 枚举{ Max项目=10, }; 枚举枚举 TX_IDLE, TXX转移, TXGSTATEYTAG标签; 易失性TXJSTATEYTAG TXYSTATE=TXSIDLE; TyBuffsStult{ UIT88T*const缓冲器; uTN8T; UIT88T LexTytotoxFER; } Buffelyt; UIT88T DATAYSPI[Max项目]={0x01,0x02,0x03,0x04,0x05, 0x06,0x07,0x08,0x09,0x0a}; Buffelyt TxSpHuff= { 缓冲器=DATAYSPI, CNT=0, LeftTytox xFER=0, }; 空隙SPIXXFILYASYC(UIT88T**数据,consisisit大小); 空隙尖头处理器(空隙); 主(空) { 斯皮特斯塔克斯(斯皮尔汉德勒); 囊状的; SPIX START(); UARTHART START(); UARTHI PUTCHAR(0x0C);/ /清除屏幕 UARTH PoStand(“中断测试SPI。RN”); (1){ 如果(TxSIDID==TXSY状态){ SpxxFixAsic(Txl Buffel.Puffic,3); } CydelayUS(50); LeDIX写(~LeDyRad()); 如果(TxSIDID==TXSY状态){ SpxxFixAsic(Txl Buffel.Puffic,10); } CydelayUS(100); LeDIX写(~LeDyRad()); } } SpxxFixAsiNC函数: 空隙SPIXXFILYASYC(UIT88T**数据,consisisit大小) { 如果(NULL!=数据){ 环磷酸脂; 如果(TxSIDID==TXSY状态){ TXYSTATE = TXX转移; If(size & lt;= SpIsFIFOIX大小){ //填充SPI TX FIFO 对于(Unt8It t i=0;i & lt;大小;i++){ SPIXWORTEXDATA(数据[I]); } }否则{ TXI Buffel.CNT=2; Tx.Buffer-LeftTytox xFER=大小; //在SPI TX FIFO中放入至少2个字节 对于(UIT88T i=0;I & lt;2;i++){ SPIXWORTEXDATA(数据[I]); } } } 囊状的; } } 中断处理程序: 空隙处理程序(无效) { //清除中断标志 易失性UIT88T STS = SPICARADTXXSTATUS(); /todo:从MISO获取数据 (空)SPILRADRXSTATUS(); 如果(TXIDIDLE)!= txSt态){ 如果(SPIOSSTSYBYTEX完成和STS){ 我们还有数据要发送吗? 如果(TxlBuff.LeftTytox xFER & gt;TxxBuff.CNT){ SpxWruteXDATA(Txx缓冲器,缓冲器[TxxPuff.CNT]); TXX缓冲液,CNT++; } } //中断是由SpIOSO完成的标志触发的。 如果(SPIXSTSSPILIDLE和STS){ TXYSTATE = TXIDLE; } } } 当传输不在过程中时,我们应该小心更新全局DATAYSPI数组。 该项目是附加的(PSoC Creator 4.1)。 当做, 卡洛斯 UBB-BuffrytToPoTr.Cyrj.CaseVo.01.Zip 2.6兆字节 以上来自于百度翻译 以下为原文 I worked a bit more and updated the buffer_t struct, now it just have a pointer to a uint8_t instead of the array of uint8_t, so now we must have an array of uint8_t with global scope to work with it, this avoid using memcpy (on the spi_xfer_async function) from the previous implementation. This is the new main.c file #include "project.h"enum { MAX_ITEMS = 10,};typedef enum { TX_IDLE, TX_TRANSFERING,} tx_state_tag;volatile tx_state_tag tx_state = TX_IDLE;typedef struct { uint8_t *const buffer; uint8_t cnt; uint8_t left_to_xfer;} buffer_t;uint8_t data_spi[MAX_ITEMS] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A};buffer_t tx_buffer = { .buffer = data_spi, .cnt = 0, .left_to_xfer = 0,};void spi_xfer_async(uint8_t *data, const size_t size);void SPI_handler(void);int main(void){ isr_SPI_StartEx(SPI_handler); CyGlobalIntEnable; SPI_Start(); UART_Start(); UART_PutChar(0x0C); // clear the screen UART_PutString("Test SPI with interrupts.rn"); while (1) { if (TX_IDLE == tx_state) { spi_xfer_async(tx_buffer.buffer, 3); } CyDelayUs(50); LED_Write(~LED_Read()); if (TX_IDLE == tx_state) { spi_xfer_async(tx_buffer.buffer, 10); } CyDelayUs(100); LED_Write(~LED_Read()); }} The spi_xfer_async function: void spi_xfer_async(uint8_t *data, const size_t size){ if (NULL != data) { CyGlobalIntDisable; if (TX_IDLE == tx_state) { tx_state = TX_TRANSFERING; if (size <= SPI_FIFO_SIZE) { // fill the spi tx fifo for (uint8_t i = 0; i < size; i++) { SPI_WriteTxData(data); } } else { tx_buffer.cnt = 2; tx_buffer.left_to_xfer = size; // put at least 2 bytes into the spi tx fifo for (uint8_t i = 0; i < 2; i++) { SPI_WriteTxData(data); } } } CyGlobalIntEnable; }} The interrupt handler: void SPI_handler(void){ // clear interrupt flag volatile uint8_t sts = SPI_ReadTxStatus(); // TODO: Get the data from MISO (void)SPI_ReadRxStatus(); if (TX_IDLE != tx_state) { if (SPI_STS_BYTE_COMPLETE & sts) { // do we still have data to send? if (tx_buffer.left_to_xfer > tx_buffer.cnt) { SPI_WriteTxData(tx_buffer.buffer[tx_buffer.cnt]); tx_buffer.cnt++; } } // the interrupt was triggered by the SPI_DONE flag if (SPI_STS_SPI_IDLE & sts) { tx_state = TX_IDLE; } }} We should be careful when updating the global data_spi array doing it when a transfer is not in process. The project is attached (PSoC Creator 4.1). Regards, Carlos |
|
|
|
只有小组成员才能发言,加入小组>>
754个成员聚集在这个小组
加入小组2111 浏览 1 评论
1858 浏览 1 评论
3673 浏览 1 评论
请问可以直接使用来自FX2LP固件的端点向主机FIFO写入数据吗?
1792 浏览 6 评论
1540 浏览 1 评论
CY8C4025LQI在程序中调用函数,通过示波器观察SCL引脚波形,无法将pin0.4(SCL)下拉是什么原因导致?
579浏览 2评论
CYUSB3065焊接到USB3.0 TYPE-B口的焊接触点就无法使用是什么原因导致的?
432浏览 2评论
CX3连接Camera修改分辨率之后,播放器无法播出camera的画面怎么解决?
442浏览 2评论
391浏览 2评论
使用stm32+cyw43438 wifi驱动whd,WHD驱动固件加载失败的原因?
980浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-29 13:50 , Processed in 0.951637 second(s), Total 56, Slave 50 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号