搜索
bottom↓
回复: 11

SPI 通信,Atmega128 作为从端,中断方式发数据不成功

[复制链接]

出0入0汤圆

发表于 2007-11-10 16:35:58 | 显示全部楼层 |阅读模式
各位好,这两天在弄 ADF7020,它的数据接口只有两根线,clk 和 data,符合串行口的时序,所以想用 SPI 来访问,ADF7020 做主端,Atmega128 做从端,时钟由 ADF7020 提供,采用中断方式接收和发送数据,接收没有问题,但发送却失败,从示波器上看,发送时 data 上没有电平变化,在 AVR Studio 中和 led 灯上可以判断已经进了 SPI 中断服务程序,但数据总是发送不成功。

MISO 和 MOSI 通过 10K 电阻接在一块,然后再接到 ADF7020 的 data 线上,ss 接低电平

MISO 为输出,MOSI、SS、SClk 配置为输入,带上拉

把坛子上的帖子和手册都看了不少,至今没有解决,请大家帮帮忙,多谢~

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

发表于 2007-11-10 18:50:20 | 显示全部楼层
楼上兄弟
 主发送时,“从”必须事先将数据准备好,然后在“从”的中断服务程序中发送即可。

出0入0汤圆

 楼主| 发表于 2007-11-10 19:19:56 | 显示全部楼层
多谢 ba_wang_mao 的回答。。

这个过程我是了解的,从 SPI 的时序图可以看出来,就一个完整的 SPI 通信过程来说,应该是由主端发起,然后从端先把数据准备好,在采样完成后放到移位寄存器中,不知道我理解的对不对??

刚刚我又跟踪了一下代码,从示波器上看,在发送的时候,data 线上已经有个电平变化,但现在还判断不了数据通信有没有成功,不知道有没有什么办法来测试,哪位介绍一个方法。

可能问题在 ADF7020 的通信方式上,我是在采样到一个高低电平变化后就往 SPDR 送数据的,不知道这样是不是符合 SPI 的要求。

出0入0汤圆

 楼主| 发表于 2007-11-10 19:23:33 | 显示全部楼层
刚刚在 2lib 上找到一个帖子,提到了一点,还没有测试,不知道是不是,先请大家确认一下,帖子内容如下:
关于8515的SPI的问题

最近在用到8515的SPI时,发现一个问题,觉得有些怪,说出来,大家讨论一下:

我一般将其SPI做为从机方式输入同步数据,数据速率一般是64K-384Kbps。以前都是收数据,一直没出现问题。最近这个项目要求在收取数据的同时要将数据从SPI口发送出去。由于要求同步,所以只能工作在从机方式。我用的是中断方式。这样问题就出来了,接收还是没有问题,但发送出现了问题:在从机模式下,发送数据必须在中断后的半个时钟周期内发送出去,否则发送的只是FFH,而不是只要保证在下一个中断来之前添入就行。我是通过程序中加入NOP用数字示波器测试到的。
这样处理就比较麻烦,因为如果是工作在384Kbps,那么半个时钟周期就是1.3us,这个时间是非常短的。除了单片机响应中断的时间,就所剩无几了,况且如果有timer中断的话,就根本不能保证了。
我仔细看了一下8515的SPI的资料,发现它实际上并没有发送缓冲寄存器,只有一个接收缓冲寄存器。发送和接收同时使用一个移位寄存器。这样当中断的时候,移位寄存器的数据装入接收缓冲器,由于没有发送寄存器,所以要求单片机尽快把数据装载入移位寄存器内,因为单片机在下一个时钟沿就要发送数据了。我想它是在中断后的半个时钟沿时对移位寄存器内的数据进行保护。所以导致了上面出现的问题。
但是当工作于主机方式时,却没有问题,因为SPI要等到数据装载入移位寄存器后才启动发送时钟。
所以我想,SPI的这种结构和UART不同,在发送方向没有缓冲器。它本来不是为了在从机模式下,而且是同步时钟,发送数据的。

出0入0汤圆

 楼主| 发表于 2007-11-10 19:35:23 | 显示全部楼层
ISR( SPI_STC_vect)
{
    UINT8 temp;

    // Handle SPI interrupt
    if (dd_data_port_state == DATA_PORT_TRANSMITTING)   // 数据发送
    {
        switch (dd_data_packet_phase)
        {
            case PACKET_PHASE_PREAMBLE: // 前导码
            case PACKET_PHASE_SYNCWORD: // 同步字符
                temp = p_mac_active_tx_frame[dd_port_data_tx_frame_idx];
                SPDR = temp;

                dd_port_data_tx_frame_idx++;
                if (dd_port_data_tx_frame_idx >= 8 )       
                {
                    dd_data_packet_phase = PACKET_PHASE_HEADER;
                    p_mac_active_tx_frame = ((pUINT8) &mac_tx_packet_header.payload_length) - 3;
                    dd_port_data_tx_frame_idx = 0;
                    break;
                }
                break;

            case PACKET_PHASE_HEADER:
                temp = p_mac_active_tx_frame[dd_port_data_tx_frame_idx++];
                SPDR = temp;
                crc16(temp);

                if (dd_port_data_tx_frame_idx >= sizeof(MAC_PACKET_HEADER_T) )       
                {
                    dd_data_packet_phase = PACKET_PHASE_PAYLOAD;
                    p_mac_active_tx_frame = &dd_port_data_tx_buffer[0];
                    dd_port_data_tx_frame_idx = 0;
                    break;
                }
                break;

            case PACKET_PHASE_LENGTH:
                break;

            case PACKET_PHASE_PAYLOAD:
                temp = p_mac_active_tx_frame[dd_port_data_tx_frame_idx++];
                SPDR = temp;
                crc16(temp);

                if (dd_port_data_tx_frame_idx >= mac_tx_packet_header.payload_length)
                {
                    dd_data_packet_phase = PACKET_PHASE_CRC;
                    dd_port_data_tx_frame_idx = 0;
                    break;
                }
                break;

            case PACKET_PHASE_CRC:
                if (dd_port_data_tx_frame_idx == 0)
                {
                    SPDR = crc_lo;
                    dd_port_data_tx_frame_idx++;
                }
                else if (dd_port_data_tx_frame_idx == 1)
                {
                    SPDR = crc_hi;
                    dd_port_data_tx_frame_idx++;
                }
                else if (dd_port_data_tx_frame_idx >= 2)
                {       
                    dd_port_data_tx_frame_idx = 0;
                    DISABLE_SPI_INT();
                    DISABLE_SPI();
                }
                break;

            default:                                       
                break;
        }// switch
    }//DATA_PORT_TRANSMITTING

    if (dd_data_port_state == DATA_PORT_RECEIVING)  
    {
        SPDR = 0xFF;
        switch (dd_data_packet_phase)
        {
            case PACKET_PHASE_HEADER:
                temp = SPDR;
                dd_port_data_rx_buffer[dd_port_data_rx_frame_idx] = temp;
                crc16(temp);

                dd_port_data_rx_frame_idx++;
                if (dd_port_data_rx_frame_idx >= sizeof(MAC_PACKET_HEADER_T) )       
                {
                    dd_port_data_rx_payload_length = temp;
                    dd_data_packet_phase = PACKET_PHASE_PAYLOAD;
                    dd_port_data_rx_frame_idx = 0;
                    break;
                }
                break;

            case PACKET_PHASE_PAYLOAD:
                temp = SPDR;
                dd_port_data_rx_buffer[dd_port_data_rx_frame_idx] = temp;
                crc16(temp);
                dd_port_data_rx_frame_idx++;

                if (dd_port_data_rx_frame_idx >  dd_port_data_rx_payload_length )
                {
                    dd_data_packet_phase = PACKET_PHASE_CRC;
                    dd_port_data_tx_frame_idx = 0;
                    break;
                }
                break;

            case PACKET_PHASE_CRC:
                temp = SPDR;
                dd_port_data_rx_buffer[dd_port_data_rx_frame_idx] = temp;
               
                crc16(temp);
                dd_port_data_rx_frame_idx++;
                if (dd_port_data_rx_frame_idx >=  2 )       
                {
                    DISABLE_SPI_INT();         // Disable SPI interrupt                                               
                    DISABLE_SPI();                // Disable SPI
                    dd_has_received_whole_frame = TRUE;
                    break;
                }
                break;
            default:                                       
                break;
        }// for switch.. case..
    }// DATA_PORT_RECEIVING
}

出0入0汤圆

 楼主| 发表于 2007-11-12 08:45:19 | 显示全部楼层
各位,帮帮忙啊,上面是 SPI 中断服务程序,也参照了 Paul 的那份代码,结构上应该没有问题,触发的那部分代码如下:

/*****************************************************************************
Function:                    transmit_constant_frame
==============================================================================
Description:
Transmit a frame including preamble & sync word, payload length,
payload and CRC
*****************************************************************************/
void transmit_constant_frame(void
{
    ENABLE_SPI_INT();          // Enable SPI interrupt       

    /* This prevents stray interrupts and SPDR overruns when priming */
    while ( get_sclock() );  // 采样 clk 时钟
    while ( !get_sclock() );

    /* Enable SPI  */
    ENABLE_SPI();

    p_mac_active_tx_frame = &mac_preamble_syncword[0];  // 同步字符
    dd_port_data_tx_frame_idx = 1;
    // 启动 SPI,数据已经放在 p_mac_active_tx_frame 里面
    SPDR = p_mac_active_tx_frame[dd_port_data_tx_frame_idx];
    dd_port_data_tx_frame_idx++;

    INTERRUPTS_ON;
}

出0入0汤圆

 楼主| 发表于 2007-11-12 18:10:32 | 显示全部楼层
看样子这个问题又要和以前一样了,我不知道怎么回事,本来坛子里人气不错,可每次的问题都没有人帮忙,让我很怀疑是不是我的问题太菜了,可我看到许多比的问题更菜的,也有人回答,还是说水平菜的太多,真正的高手一般不上来,现在浮在上面的都是跟我一样的菜鸟。

说实话,坛子上的资料不少,不过新东西不多,比较适合入门,想进步还是得自己下工夫,我看来看去,真正起到帮助作用的,还是前两年的帖子,像马老师的、HJJOURAVR、菜农的,还有很多,我记不上名了,我相信高手是有的,只是我运气不好,没遇到,呵呵。。

我向来喜欢自力更生,信奉自已动手,丰衣足食,Linus 不是有句话嘛,“让我们看代码吧!”。

本来就没报什么希望,没想到竟和想的一样,看样子以后还是尽量潜水,顺便帮帮比我更菜的兄弟,推他们一把,毕竟咱也算是入门了,以前走的弯路,不要让别人再走,能帮的就帮吧!!

路漫漫兮其修远,吾将上下而求索!!

自助者天助,相信自己永远也不会错!!

出0入0汤圆

 楼主| 发表于 2007-11-12 18:13:36 | 显示全部楼层
顺便说一句,前面的关于 SPI 的论述,我手头上没有数据示波器,也没有逻辑分析仪,所以不知道对不对,也没心情做实验,哪位如果看到了,请先确认一下,不要拿来就用,不加思考的接收,出了问题别找我,呵呵。。

出0入0汤圆

发表于 2007-11-13 12:58:47 | 显示全部楼层
这是我写的TLV5617-SPI发送程序

/////////////////////////////////////////////////////////////////
//模出芯片TLC5617,SCK在闲置时是高电平(时序图上有一根SCK为高时持平的线),
//由于模出芯片在下降沿锁存数据,由于CPOL=1,因此CPHA=0
/////////////////////////////////////////////////////////////////
void TLV5617_SPI_Init(void)
{
        SPCR = (1<<SPE) | (1<<MSTR) | (1<<CPOL) | (0<<CPHA) | (0 <<SPR1) | (1<<SPR0);
        SPSR = (1<<SPI2X);
}

//////////////////////////////////////////////////////////////////////////////
//操作步骤:
//        1.写重叠缓冲区锁存器
//        2.把串行接口寄存器的数据写入锁存器A并用缓冲区锁存数据更新锁存器B
//////////////////////////////////////////////////////////////////////////////
void SPI_TLV5617(unsigned int cha_num,unsigned int chb_num)
{
        unsigned char i;
        unsigned int cha_COMMAND = (cha_num << 2) | 0x8000;
        unsigned int chb_COMMAND = (chb_num << 2) | 0x1000;

        ADS7841_CS_1();
        TLV5617_SPI_Init();       
        TLV5617_CS_0();
        SPDR = chb_COMMAND >> 8;
        for (i = 0 ; i < 200 ; i++)        if (SPSR & 0x80) break;
        SPDR = chb_COMMAND & 0xff;
        for (i = 0 ; i < 200 ; i++)        if (SPSR & 0x80) break;
        TLV5617_CS_1();
         
        TLV5617_CS_0();
        SPDR = cha_COMMAND >> 8;
        for (i = 0 ; i < 200 ; i++)        if (SPSR & 0x80) break;
        SPDR = cha_COMMAND & 0xff;
        for (i = 0 ; i < 200 ; i++)        if (SPSR & 0x80) break;
        TLV5617_CS_1();
}

出0入0汤圆

 楼主| 发表于 2007-11-13 14:18:18 | 显示全部楼层
呵呵,又是 ba_wang_mao 兄,谢谢关注!!

仔细看了一下您的代码,代码结构上不错,尤其是 CPOL 和 CPHA 的说明让我长了见识,稍微的把代码修改一下,就可以作为 SPI 发送数据或命令的典型函数。

代码中用的是查询方式来发送数据的,配置成主端,通过 CS 引脚来发起通信。

如果是这样的话,我没有问题,问题的关键就在从端、中断、发送,接收也没有问题,已经实现了,就是通过中断发送没有搞定。

出0入0汤圆

 楼主| 发表于 2007-11-13 17:44:53 | 显示全部楼层
呵呵,问题搞定,没时间了在这个问题上深究了,最后还是用查询方式,不明白为什么中断发送就是失败,有空再测试一下

出0入0汤圆

发表于 2014-10-15 12:22:06 | 显示全部楼层
老兄,你的ADF7020采用什么调制方式啊,如果是GFSK,那么在发送时,时钟管脚是没有时钟的,这时发送会失败!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-23 18:55

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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