Embedded 从STK600上的外部dataflash获取垃圾数据

Embedded 从STK600上的外部dataflash获取垃圾数据,embedded,spi,eeprom,Embedded,Spi,Eeprom,你好,, 我正在使用STK600,我已经使用SPI为外部dataflash编写了代码。当我从dataflash读取数据时,我正确地接收到第一个数据字节,但随后我将所有数据字节作为垃圾值接收。我在SPI中断中读取的数据,将相同的数据放在PWM中断中的UART上。SPI和PWM中断均正常工作。 我还尝试在SPI中断中的LED端口上放置数据字节值,以确认在PWM中断中进入UART之前是否存在任何数据损坏。但我发现LED端口上的数据值和超级终端上的数据值都相同,所以没有数据损坏。 我直接从SPI中断本身

你好,, 我正在使用STK600,我已经使用SPI为外部dataflash编写了代码。当我从dataflash读取数据时,我正确地接收到第一个数据字节,但随后我将所有数据字节作为垃圾值接收。我在SPI中断中读取的数据,将相同的数据放在PWM中断中的UART上。SPI和PWM中断均正常工作。 我还尝试在SPI中断中的LED端口上放置数据字节值,以确认在PWM中断中进入UART之前是否存在任何数据损坏。但我发现LED端口上的数据值和超级终端上的数据值都相同,所以没有数据损坏。 我直接从SPI中断本身接收垃圾值。请帮帮我,这是我的代码文件

      #include <asf.h>


      //Slave select low

      #define cs_low() \
      delay_us(10);\
      PORTB=(0<<PB0);\
      delay_us(10);

      //Slave select high

      #define cs_high() \
      delay_us(10);\
      PORTB=(1<<PB0);\
      delay_us(10);


      char opcode_cnt=0;               //Counts number bytes required before start reading actual data
      unsigned char data;         //Array to save save received data
      unsigned int dummy_byte_cnt=0;            //total dummy bytes sent to receive data
      volatile char rd_cmplete_flg=0;   //Flag is set after read operation completed
      int pg_addr;                     //Indicates address of page
      int buff_addr;                   //Indicates starting address of buffer
      unsigned int i=0;
      int array[3];
      char sample_count=4,pwm_init=0;


      void init_pwm(void);
      void spimstr_init(void);
      void spi_tx(unsigned char byte);
      void spi_tx_ISR(unsigned char byte);
      unsigned char spi_rx_ISR(void);
      unsigned char spi_rx(void);
      unsigned char get_status(void);
      void init_uart(void);
      void pg_erase(unsigned int pg_addr);
      void continuous_pg_read(unsigned int page_address,unsigned int buffer_address);




      int main (void)
    {
      // Insert system clock initialization code here (sysclk_init()).

      board_init();

      init_uart();

      spimstr_init();

      continuous_pg_read(0x00,0x00);

      while(1)
    {
       if(rd_cmplete_flg)

          init_pwm();            
    }

     // Insert application code here, after the board has been initialized.
   }



    void spimstr_init()
   {
    //Master Mode Selected
    //MSB out first
    //Clock Polarity and Clock Phase selected as 1
    //Clock Frequency 8MHz/2 selected

    SPCR|=(1<<SPE)|(0<<DORD)|(1<<MSTR)|(1<<CPOL)|(1<<CPHA)|(0<<SPR1)|  (0<<SPR0);

    SPSR=(1<<SPI2X);             //Doubles the clock frequency
   }



    void spi_tx(unsigned char byte)
   {
    SPDR=byte;

    while(!(SPSR&(1<<SPIF)));        //wait until transmission is completed
   }



    void spi_tx_ISR(unsigned char byte)
   {
    SPDR=byte;
   }


    unsigned char spi_rx()
   {
    spi_tx(0x00);                    //sending dummy byte

    while(!(SPSR&(1<<SPIF)));        //wait until reception is completed

    return SPDR;
   }


    unsigned char spi_rx_ISR()
   {
    return SPDR;
   }




     unsigned char get_status()
   {
     unsigned char status;

     //high to low transition made on SS

     cs_low();

     spi_tx(0xd7);            //opcode to read status register of EEPROM

     status=spi_rx();         //Received the value of status register of EEPROM

     status=status & 0x80;

     //low to high transition made on SS

     cs_high();

     return status;
    }


     void pg_erase(unsigned int pg_addr)
    {
     while(get_status()==0x00);

     cs_low();

     spi_tx(0x81);

     spi_tx((0x00)|(pg_addr>>7));

     spi_tx((pg_addr<<1)|0x00);

     spi_tx(0x00);

     cs_high();
    }


     void init_uart()
    {
     UBRR1H=0x00;

     UBRR1L=0x01;          //Baud rate 256000 selected      

     UCSR1B|=(1<<RXEN1)|(1<<TXEN1);

     UCSR1C|=(1<<UCSZ11)|(1<<UCSZ10);
    }



     void continuous_pg_read(unsigned int page_address,unsigned int buffer_address)
    {
     pg_addr=page_address;

     buff_addr=buffer_address;

     while(get_status()==0x00);

     cs_low();

     spi_tx(0xe8);                           //opcode to read page

     SREG=0x80;

     SPCR|=(1<<SPIE);
   }



     void init_pwm()
   {
      if(!pwm_init)
     {
      pwm_init=1;

      DDRB = (1<<PB5);                          // set OC1A as output

      TCCR1A = (1<<COM1A1)|(1<<COM1A0)|(1<<WGM10);// set OC1A on compare match,clear OC1A at bottom
      // 8 bit fast PWM

      TCCR1B = (1<<WGM12)|(1<<CS10);               // 8bit fast PWM and clock=8Mhz   
     }

      TIMSK1|=(1<<TOIE1);                     // enable timer 1 overflow interrupt
    }





      ISR(TIMER1_OVF_vect)
    {
      //PORTA=0x55;

      //delay_ms(15000);

      sample_count--;

      if(sample_count==0)
     {
        sample_count=4;

        if(rd_cmplete_flg)
       {
          TIMSK1=(0<<TOIE1);

          rd_cmplete_flg=0;

          UDR1=data;

          while(!(UCSR1A & (1<<UDRE1)));

           i++;

           if(i>=23923)
          {
           SREG=0x00;
          }

           cs_low();

           spi_tx_ISR(0xe8);
         }
       } 
        //PORTA=~PORTA;

        //delay_ms(15000);
      }





      //ISR for Continuous Array Read mode

        ISR(SPI_STC_vect)
   {
         //PORTA=0xff;

         //delay_ms(15000);

         opcode_cnt++;

         switch(opcode_cnt)
       {
         case 1:

              //PORTA=0X11;

              //delay_ms(15000);

              spi_tx_ISR((0x00)|(pg_addr>>7));

              break;

         case 2:

             //PORTA=0X22;

             //delay_ms(15000);

             spi_tx_ISR((pg_addr<<1)|(buff_addr>>8));

             break;

         case 3:

            //PORTA=0X33;

            //delay_ms(15000);

            spi_tx_ISR(buff_addr & 0x00ff);

            break;

         case 4:

            //PORTA=0X44;

            //delay_ms(15000);

             spi_tx_ISR(0x00);

             break;

         case 5:

            //PORTA=0X55;

            //delay_ms(15000);

            spi_tx_ISR(0x00);

            break;

        case 6:

            //PORTA=0X66;

            //delay_ms(15000);

            spi_tx_ISR(0x00);

            break;

        case 7:

            //PORTA=0X77;

            //delay_ms(15000);

            spi_tx_ISR(0x00);

            break;

        case 8:

            spi_tx_ISR(0x00);

            break;  
       }


           if(opcode_cnt>=9)
        {
            opcode_cnt=0;                //Reset to zero to repeat switch case

            if(rd_cmplete_flg==0)
           {
             data=spi_rx_ISR();

             //PORTA=data;

             //delay_ms(15000);     

             rd_cmplete_flg=1;
            }
             //Important Note

             //The buffer address and page address has to be incremented before cs_high() only then only this mode works

             if(buff_addr<263)
            {
             buff_addr++;
            }

             else
            {
             buff_addr=0;

             pg_addr++;
            }

           cs_high();

           //PORTA=0x30;

           dummy_byte_cnt++;

           //PORTA=0x40;

           //cs_low();

           //spi_tx_ISR(0xe8);            //Resend page read opcode to    read next  byte of data

            if(dummy_byte_cnt>=23923)
           {
            SREG=0x00;

            buff_addr=0;

            pg_addr=0;

            dummy_byte_cnt=0;
           }
         }
        //PORTA=~PORTA;

        //delay_ms(15000);
       }



        void board_init(void)
       {
        DDRA|=0xff;                          //optput port for LED

        DDRB|=(1<<DDB2)|(1<<DDB1)|(1<<DDB0);     //Direction of SS,MISO,SCK,MOSI  pin selected
       }

这可能有问题:

无符号字符数据//用于保存接收到的数据的数组

首先,这不是一个数组,而是一个字符的存储,但是您似乎没有试图在那里存储数组,所以它只是被错误地描述了

但是,您似乎正在从ISR和主线程访问它,如果要这样做,您需要将其声明为volatile。否则,编译器可以自由地将值缓存在寄存器中,这可能会使它成为给定线程的私有值,甚至更糟糕的是,它会决定没有人使用该值,因此拒绝存储该值


您已经用这种方式保护了您的标志,但您也需要保护数据。

对预期值和接收值进行十六进制比较会很有帮助。也许您可以退一步,暂时尝试非中断忙等待SPI访问,看看是否获得了正确的数据。另外,试一下慢一点的时钟,确保你有去耦帽。该部件是否允许您在同一访问中多次读取状态寄存器?这可能也是一个很好的测试。示波器或廉价的逻辑分析仪可以很好地验证线路上实际发生的事情是您从接收到的数据中认为应该是或想象的事情。实际上,数据是可变的,我最初将其用作数组,但忘了从注释中删除。即使我在PWM和SPI ISR中都使用它,我是否需要声明它为易失性?它通过轮询方法工作正常,读取状态寄存器也在我的脑海中,但有点困难,它需要发送一个操作码和几个字节。硬件很好,并且通过改变SPI和PWM频率进行了尝试,我心中的一个疑问是,即使我使用中断,我是否每次都需要检查状态寄存器。忽略将其声明为易失性的后果将因编译器和月相而异,但原则上,是的,你必须对你从中断和程序流的主线程访问的任何东西都这样做——你对那个变量这么做。克里斯,你是对的,我改变了我的逻辑以便读取状态寄存器,我第一次准备好状态,然后它给了我忙状态,在这种情况下我该怎么办????我非常需要你的帮助。