发 帖  
原厂入驻New
[问答] DSPIC33EP128GM604无法使SPI芯片选择正常工作
355 SPI DSP
分享
最近,我对微€€芯片通用DSP产品印象深刻,并决定让它成为DSP提供商。在使用上述芯片进行相当复杂的项目后,我假定标准SPI总线将是一种微不足道的设置。我错了。在尝试了数据表中的代码和提供的(经常是冲突的)代码示例之后,我似乎无法使spi在正确的时间正确地切换芯片选择行。WriteSPI3()外围库函数不能控制正常传输,因此在切换CS线路之前,检查相关标志是我的职责;故障似乎没什么作用,CS提前切换。以下是我的代码:SPI3配置:void Init_SPI3(void){IFS5)SPI3IF=0;//清除中断标志IEC5bits.SPI3IE=0;//禁用中断//SPI1CON1寄存器设置6位)SPI3CON1bits.SSEN=0;//No CSSPI3CON1bits.MSTEN=1;//主模式禁用SPI3CON1bits.PPRE=2;//Pre-scalerSPI3CON1bits.SPRE=8;//Pre-scaler 2SPI3CON1bits.SMP=1;//Input数据是在数据输出时间SPI3CON1bits.CKE=0;//在转换时串行输出数据更改SPI3CON1bits.CKP=0;//时钟的空闲状态是低电平;SPI3STATbits.SPIEN=1;//启用SPI模块//中断控制器设置IFS5bits.SPI3IF=0;//清除中断标志IEC5bits.SPI3IE=1;//启用中断}SPI 3 Pin配置:TRISBbits.TRIsb10=0;//将SPI3CLK设置为oUTPutTrISBITS.tiSISB11=0;//Sp3DATAOUT作为OutPurrPrime4位;R/P43CK OUTROPOR4BITS。RP43R=31;//SPI3X数据片外选择线引脚配置:TrISBITS.TISBB4=0;/SPI3 CS在引脚B4上,设置为输出简单主例程:(1=1){ PbBITB.RB4=0;//集CS线到L。WO WrrestPi3(0xAA);//这是来自外围图书馆的安全……同时(!)SPI3STATBITS。SpBBF)。BRB4。RB4=1;//设置CS线到高}以上代码不工作,CS通过传输一半到1。我很困惑,这就是他们在示例代码中也是如何做到的!

以上来自于百度翻译


      以下为原文

    Recently i was very impressed by microchips general DSP offerings and decided to make it my go to DSP provider. After using the above chip for fairly complicated projects i assumed the standard SPI bus would be a breeze to set up. Boy was i wrong.

After trying out code from the datasheet and the provided (and often conflicting) code examples i cannot seem to make the spi properly toggle the chip select line at the correct time.

The WriteSPI3() peripheral library function does not take control uptil transmission is complete so its my duty to check the relevent flags after, before i toggle the CS line; trouble is nothing seems work, the CS toggles premarturly.

Here is my code:

SPI 3 configuration:

void Init_SPI3 ( void )
{
IFS5bits.SPI3IF = 0; // Clear the Interrupt flag
IEC5bits.SPI3IE = 0; // Disable the interrupt
// SPI1CON1 Register Settings
SPI3CON1bits.DISSCK = 0; // Internal serial clock is enabLED
SPI3CON1bits.DISSDO = 0; // SDOx pin is controlled by the module
SPI3CON1bits.MODE16 = 0; // Communication is word-wide (16 bits)
SPI3CON1bits.SSEN = 0; //No CS
SPI3CON1bits.MSTEN = 1; // Master mode disabled
SPI3CON1bits.PPRE = 2; //Pre-scaler
SPI3CON1bits.SPRE = 8;//Pre-scaler 2
SPI3CON1bits.SMP =1; // Input data is sampled at the middle of data output time
SPI3CON1bits.CKE =0; // Serial output data changes on transition from
SPI3CON1bits.CKP = 0; // Idle state for clock is a low level;
SPI3STATbits.SPIEN = 1; // Enable SPI module
// Interrupt Controller Settings
IFS5bits.SPI3IF = 0; // Clear the Interrupt flag
IEC5bits.SPI3IE = 1; // Enable the interrupt
}
SPI 3 Pin configuration:

TRISBbits.TRISB10 = 0; //Set SPI3CLK as output
TRISBbits.TRISB11 = 0; //Set SPI3DATAOUT as output

RPOR4bits.RP42R=32; //SPI3_CLK out
RPOR4bits.RP43R=31; //SPI3_DATA out
Chip select line pin configuration:

TRISBbits.TRISB4 = 0; //SPI3 CS is on Pin B4, set it to Output
Simple main routine:

while(1==1){

PORTBbits.RB4 = 0;//Set CS line to low
WriteSPI3(0xaa); //This is from the peripheral library to be safe....
while(!SPI3STATbits.SPIRBF)
PORTBbits.RB4 = 1; //Set CS line to high
}

The above code does not work, the CS goes to 1 half way through transmission. Im quite perplexed, this is how they do it in the example code too!
0
2019-7-17 12:05:07   评论 分享淘帖 邀请回答

相关问题

19个回答
LATBbits.LATB4=1;//Init as deselectedTRISBbits.TRISB4=0;//SPI3 CS在Pin B4上,设置为OutputNop();Nop();Nop();Nop();Nop();Nop();/*,如果您有其他代码,则不需要延迟,但是您需要确保行足够高,以便从属看到它,如果CS有上拉,则不需要这样做。T需要NoP,因为线路在上电时会很高。有些奴隶可能需要上拉。*/简单主例程:.(1==1){LATBbits.LATB4=0;//将CS行设置为lowNop();WriteSPI3(0xaa);//这是从外围库获得的,以便安全.....(!SPI3STATbits.SPIRBF)LATBbits.LATB4=1;//将CS行设置为高}从PORT读取,写入LAT(除非您需要读取您所写的内容),端口可能与锁存器不匹配。参见

以上来自于百度翻译


      以下为原文

    LATBbits.LATB4 = 1;   // Init as deselected 
TRISBbits.TRISB4 = 0; //SPI3 CS is on Pin B4, set it to Output
Nop();
Nop();
Nop();
Nop();
Nop();/* if you had other code you would not need a delay, but you need to insure the line is high ling enough for the slave to see it, if the CS has a pullup you would not need the NOPs since the line would be high at power up.  Some slaves may need the pullup. */

Simple main routine:

while(1==1){

LATBbits.LATB4 = 0;//Set CS line to low
Nop(); 
WriteSPI3(0xaa); //This is from the peripheral library to be safe....
while(!SPI3STATbits.SPIRBF)
LATBbits.LATB4 = 1; //Set CS line to high
}
 
Read from PORT, write to LAT ( unless you need to read what you wrote) the Port may not match the Latch.
See Read-Modify-Write Issues with PIC (R-M-W)
2019-7-17 12:11:04 评论

举报

谢谢你的回复,这是唯一的选择吗?我看到了很多标志检查等例子,以确保传输完成?我的DSPIC33的问题是发送缓冲区和接收缓冲区标志不能按预期工作!我很沮丧。经过一点调试,我注意到了这一点:接收缓冲区标志,示例代码和Web上的其他代码用来检查完成的TX事件,它没有被设置,因此中断不会被触发,除非我搞乱了SPI模块的ClockIn管脚,它不应该做任何事情。主模式。对我来说好像很像虫子。数据表中确实指出,在主模式下,您仍然需要指定一个CLKOUT PPS引脚,因为事物的RX端从那里派生出它的时钟:这在我看来不起作用。正如我所说,如果我手动脉冲CROCKIN引脚,完成了TX事件的ISR触发等,代码进行。否则代码被卡住。不知道为什么…/最后,我使用了和你说的一样的东西,而不是nop-(),我只写了一个空for循环。我仍然想知道“适当的方式”如果有…

以上来自于百度翻译


      以下为原文

   


Thankyou for your reply, is that the only option? I saw a lot of examples of flag checking etc to make sure transmission is complete? The problem with the my DSPIC33E is that the transmit buffer and receive buffer flags dont seen to work as intended! Im so frustrated. After a bit of debugging ive noticed this:
The receive buffer flag which the example code and others on the web use to check for a finished TX event does not get set and thus the interrupt does not get triggered unless i mess around with the ClockIn pin of the SPI module, which should do nothing in master mode. Seems a lot like a bug to me. The datasheet does say that in master mode you still need to designate a CLKOUT PPS pin because the RX side of things derives its clock from there: this does not seem to work in my case. As i said, if i manually pulse the CLOCKIN pin the ISR for finished TX event triggers etc and the code proceeds. Otherwise the code is stuck.. No idea why... :/ 

In the end im using something just like you said, instead of Nop() I just write a empty For loop. I still want to know the "proper way" if there is any....
2019-7-17 12:27:36 评论

举报

您需要遵循几个非常简单的规则:-写到LAT并从PORT寄存器读取-在启用它之前配置外围设备-对于简单的外围设备,除非您确切地知道它们正在做什么,否则不要麻烦使用库函数-如果SPI外围设备通过PPS连接然后将SCK作为输入和输出映射到引脚——确保MCU连接了所有的功率引脚,并且旁路电容器都在适当的位置。其中一些是非常通用的,我并不是说你没有遵循任何特定的一个。根据我的经验,NOP是不需要的。这些论坛中有关于如何编写通用SPI交换函数的详细信息,在这里您可以确切地看到正在发生的事情——我已经在各种论坛中写了几篇,包括SPI/IIC/etc论坛。

以上来自于百度翻译


      以下为原文

    There are several really simple rules you need to follow:
- write to the LAT and read from the PORT registers
- configure the peripheral BEFORE you enable it
- for simple peripherals, don't bother with library function unless you know EXACTLY what they are doing
- if the SPI peripheral connects via PPS then map the SCK as both input and output to the pin
- make sure that the MCU has all of the power pins connected and bypass capacitors are in place
Some of these are very general and I'm not saying that you are not following any particular one.
In my experience NOP's are not needed.
There are many examples in these forums about how to write a general purpose SPI exchange function where you can see exactly what is going on - I've written several in various forums, including the SPI/IIC/etc forum.
Susan
2019-7-17 12:40:46 评论

举报

谢谢你的指点。我似乎正在遵循所有这些,但我不能让SPIS CS线工作正常,如果我使用标志。我必须检查哪些标志才能确保TX事件完成?示例代码有很多拼写错误,所以我不知道我必须检查什么标志。数据表中没有任何特定的标志来指示TX事件何时完成。关于规则4:是的,我熟悉这个问题/点。我在一些地方的论坛上见过它。许多人声称他们的代码在这样做之后工作,我注意到我的代码没有变化。这是代码,虽然没有标志。关于这个问题,我不知道如果我改变时钟速度,固定延迟ive代码是否可靠。uint16_t Write_SPI_1(uint16_t命令){uint16_t垃圾;SPI1BUF=命令;//通过SPI发送数据(j=0;j<32;j+){};//TX标志修复垃圾=SPI1BUF;//读取伪数据(j=0;j&lt;5;j++){};//rx标志修复返回SPI1BUF;}

以上来自于百度翻译


      以下为原文

   
Thankyou for these pointers. I seem to be following all of these yet i cannot get the SPIs CS line to work properly if im using flags. What flags must i check to make sure a TX event has completed? The example code has a lot of typos so im unsure what flag i must check. The datasheet does not have any specific flags that indicate when a TX event has been completed.

Regarding rule 4: yes i am familiar of this issue/point. Ive seen it around in the forums in a few places. A lot of people claim their code works after doing that, I notice no change in mine.
 
Here is the code that works albeit without flags. One problem with this i i dont know if the fixed delays ive code will be reliable if i change the clock speed.
 
uint16_t Write_SPI_1(uint16_t command) {
uint16_t garbage;
SPI1BUF = command; // send data over SPI
for (j = 0; j < 32; j++) {
}; // TX flag fix 
garbage = SPI1BUF; // read dummy data
for (j = 0; j < 5; j++) {
}; //RX flag fix
return SPI1BUF;
}
2019-7-17 12:54:09 评论

举报

您的原始代码缺少一个重要的细节。您必须始终从SSPBUF寄存器执行READ来清除SPIRBF标志,即使您不想要数据。现在,您永远不会清除标志,所以它总是被设置,这导致过早的循环退出。

以上来自于百度翻译


      以下为原文

    Your original code is missing one vital detail.
You must always do a READ from the SSPBUF register to clear the SPIRBF flag, even if you don't want the data.
Right now, you are never clearing the flag, so it is always set, which is causing the premature loop exit.
 
2019-7-17 13:08:14 评论

举报

好吧,这个代码能正确地减去标志吗?uint16_t Write_SPI_1(uint16_t命令){uint16_t垃圾;SPI1BUF=命令;//通过SPIfor发送数据(j=0;j<32;j+){};//TX标志修复,在这里检查标志?垃圾= SPI1BUF;//读取哑DATAOF(j=0;j&lt;5;j++){};//rx标志修复,在这里检查标志吗?你能告诉我要检查什么旗吗?示例代码为同一个写例程做了2个不同的事情,这是非常混乱的。

以上来自于百度翻译


      以下为原文

   
Okay so is this code correct minus the flags?
uint16_t Write_SPI_1(uint16_t command) {
uint16_t garbage;
SPI1BUF = command; // send data over SPI
for (j = 0; j < 32; j++) {
}; // TX flag fix, check the flag here instead?
garbage = SPI1BUF; // read dummy data
for (j = 0; j < 5; j++) {
}; //RX flag fix, check the flag here instead?
return SPI1BUF;
}
 
Could you please tell me what flags to check? the example code does 2 different things for the same Write routine which is very confusing.
2019-7-17 13:21:03 评论

举报

这是一个猜测,没有使用那张照片。

以上来自于百度翻译


      以下为原文

    This is a guess, haven't used that PIC.

uint16_t Write_SPI_1(uint16_t command) {
    SPI1BUF = command; // send data over SPI
    while(!SPI3STATbits.SPIRBF)    //wait until SPIRBF goes high
        ;
    return SPI1BUF;    //this will clear SPIRBF
}
2019-7-17 13:31:57 评论

举报

它起作用了!我不敢相信,因为这让我非常沮丧。我原来的版本代码试图检查国旗,但没有作出回报,所以我猜这就是为什么它不工作!你能解释一下为什么我要花这么多钱来做这件事吗?我想知道。谢谢!!!!

以上来自于百度翻译


      以下为原文

   


It works! I cant believe it because this had been frustrating me so much. My original version of the code tried to check for the flag but did not make a return so i guess thats why it didnt not work! Can you please explain why this works as i  have spent so much on this I want to know.
Thanks!!!
2019-7-17 13:38:51 评论

举报

在设置标志之后,读取SPI1BUF(在这种情况下使用返回)。

以上来自于百度翻译


      以下为原文

   
After the flag is set, then read the SPI1BUF ( in this case using return. )
2019-7-17 13:53:25 评论

举报

所以事情是这样的:void Write_SPI1(uint8_t命令){//Does不工作,CS的早期切换,最初尝试过这个代码....uint8_t垃圾;SPI1BUF=命令;//通过SPI.()发送数据!SPI1STATbits.SPIRBF);//等待直到SPIRBF变为高垃圾=SPI1BUF;//读取虚拟数据}但是随后这起作用是:uint8_t Write_SPI1(uint8_t命令){//Does workSPI1BUF=命令;//同时通过SPI发送数据(!SIP1STATBITS.SIPBF);//等待直到SpBBF高返回SPI1BUF;/ /返回接收到的实际数据}这是为什么?我相信垃圾=SP1BUF应该以同样的方式清除SP1BUF返回的标志吗?

以上来自于百度翻译


      以下为原文

    So here is the thing:
 
 
void Write_SPI1(uint8_t command) { //Does not work, premature toggle of CS, tried this code initially....
uint8_t garbage;
SPI1BUF = command; // send data over SPI
while(!SPI1STATbits.SPIRBF) ; //wait until SPIRBF goes high
 garbage = SPI1BUF; // read dummy data
}
 
but then this works:
 
uint8_t Write_SPI1(uint8_t command) { //Does work
SPI1BUF = command; // send data over SPI
while(!SPI1STATbits.SPIRBF) ; //wait until SPIRBF goes high
return SPI1BUF; //Return the actual data received
}
 
Why is this?, I believe garbage = SP1BUF should clear the flag in the same way return SP1BUF does?
 
 
2019-7-17 13:58:58 评论

举报

我使用SPI线路上的逻辑分析器来确认正在发生的事情,https://www.saleae.com/我非常喜欢早期的,所以当它出来时我买了模拟的,现在我可以看到!

以上来自于百度翻译


      以下为原文

    I use a Logic analyzer on the SPI lines to confirm what is going on https://www.saleae.com/
I liked the early one so much I bought the analog one when it came out, now I can see !
2019-7-17 14:15:15 评论

举报

是的,我也有旧的8 CH版本!但我用我的范围来看看这条线的情况!

以上来自于百度翻译


      以下为原文

   


Yes i have the old 8 Ch version of that too! But im using my scope to look at the lines in this case!
2019-7-17 14:29:11 评论

举报

好的坏消息,上面的代码只适用于SPI1(没有PPS)!所有其他基于PPS的SPI模块挂在while循环上。这太奇怪了。有什么想法吗?

以上来自于百度翻译


      以下为原文

    Ok more bad news, the above code works for SPI1 (no PPS) only! All other PPS based SPI modules hang on the while loop. This is so weird. Any ideas?
2019-7-17 14:48:04 评论

举报

您确信上面的红色冒号是否存在于您的测试代码中?我注意到在你的第一篇文章中的例子中缺少了它。这就是为什么我把它放在一个单独的行上,使它更加可见。

以上来自于百度翻译


      以下为原文

   
Are you sure the red colon above was present in your test code?
I note it was missing in the example in your first post.
That's why I put it on a seperate line, to make it more visible. 
2019-7-17 15:07:18 评论

举报

您确信上面的红色冒号是否存在于您的测试代码中?我注意到在你的第一篇文章的例子中没有提到它。这就是为什么我把它放在一个单独的线上,使它更加明显。我现在找到了一个完整的解决方案:这里肯定有编译器Pyk/Grip。正如我所说的,设置垃圾=SPIXBUF不起作用,但是返回SPIXBUF。我不知道这是为什么,我也关闭了所有优化。所以这就是。现在在后面的线程中,我说这对SPI3无效,但对SPI1有效。两者的区别在于前者是PPS,后者不是,所以问题就在这里。问题是依赖PPS的SPI模块从管脚导出它们的RX时钟,所以即使在主模式下,也必须定义与时钟输出相同的管脚的SPI时钟输入管脚。然后,允许RX侧时钟,从而标志设置等。这是在数据表中提到,但在相当模糊的术语。我遵循这一点,但不知怎的,我没有意识到CROCKIN和时钟锁定必须通过PPS定义到同一个引脚上。现在一切都好了……现在…

以上来自于百度翻译


      以下为原文

   
Are you sure the red colon above was present in your test code?
I note it was missing in the example in your first post.
That's why I put it on a seperate line, to make it more visible. 

</blockquote>
It wasnt, adding it made no difference. Ive found a complete solution now:

There is most certainly a compiler perk/glitch here. As i said setting garbage = SPIXBUF does not work but return SPIXBUF does. I have no clue why this is so, i have all optimizations turned off also.So thats that.

Now in a later thread i said that this is not working for SPI3 but does for SPI1. The difference between the two is that the former is PPS and the later is not, so the problem lies therein. The problem was that the SPI modules that rely on PPS derive their RX clocks from the pin, so even in master mode one must define a SPI clock-in pin that is the same pin as the clock out. This then allows the RX side to be clocked and thus the flag to set etc. This is mentioned in the datasheet but in rather ambiguous terminology. I was following this but somehow i did not realize that both ClockIN and ClockOut must be defined via PPS onto the same pin. It all works now..for now...
2019-7-17 15:16:00 评论

举报

嗯,也许“垃圾”得到优化…

以上来自于百度翻译


      以下为原文

    Hmmm, maybe "garbage" gets optimized out...
2019-7-17 15:32:51 评论

举报

它不在XC8中,甚至JISTIS足以触发XC8中的读(因为SPI1BUF被定义为易失性),但是XC16是另一种动物。查看编译器输出的汇编程序应该确认它正在做什么。

以上来自于百度翻译


      以下为原文

   


It wouldn't be in XC8, even just
SPI1BUF;
is enough to trigger a read in XC8 (because SPI1BUF is defined as volatile), but XC16 is another animal.
Looking at the assembler output from the compiler should confirm what it is doing.
 
2019-7-17 15:40:03 评论

举报

这就是我的想法,但我已经关闭了优化。此外,官方代码示例使用“垃圾”。非常奇怪。

以上来自于百度翻译


      以下为原文

   
That is what i thought but i have optimizations turned off. Furthermore, the official code examples do it using "garbage". Very odd.
2019-7-17 15:58:41 评论

举报

它不在XC8中,甚至只是触发XC8中的读取(因为SPI1BUF被定义为volatile),但是XC16是另一种动物。查看编译器的汇编器输出应该确认它正在做什么。

以上来自于百度翻译


      以下为原文

   


It wouldn't be in XC8, even just
SPI1BUF;
is enough to trigger a read in XC8 (because SPI1BUF is defined as volatile), but XC16 is another animal.
Looking at the assembler output from the compiler should confirm what it is doing.
 

</blockquote>


Yeah, but "garbage" was not volatile
2019-7-17 16:13:19 评论

举报

只有小组成员才能发言,加入小组>>

65个成员聚集在这个小组

加入小组

创建小组步骤

关闭

站长推荐 上一条 /7 下一条

快速回复 返回顶部 返回列表