This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

LPC935 seems a lazy cow in software SPI(?)

Hello to all friends, once again

Simple issue. Connect an Atmel 45DB321 flash and try to make an emulated SPI software flow just to read this little budy's device ID. aAll good but when the timer interrupt hits the core, sending 4 bytes makes this system to crawl like a lazy cow (About 100us to send all bytes). Also there is the A/D Single conversion mode enabled started by timer overflow with auto reload. It also reads 4 bits from port P0 and do or not do the SPI transaction. Simple but still fuzzy to understand why it take so long :( Internal clock is enabled :)

Take a look of entire code (Sorry for any inconvenience about C mistakes )

Ty all, just to see this post,
Best regards
Timothy


#include <REG936.H>
#define READ_STATUS 0xD7
#define READ_DEVID 0x9F


sbit Status_LED = P2^0;                                 // Initialize P2.0 as the status led
sbit REC_LED    = P0^7;                                 // Initialize P0.7 as the record led
sbit BUSY_LED   = P0^6;                                 // Initialize P0.5 as the busy led
sbit PLAY_LED   = P0^5;                                 // Initialize P0.6 as the play led

sbit SPI_MOSI   = P2^2;                 // Initialize P2.2 as the MOSI signal (Output)
sbit SPI_MISO   = P2^3;                 // Initialize P2.3 as the MISO signal (Input)
sbit SPI_SS     = P2^4;                 // Initialize P2.4 as the SS signal (Output)
sbit SPI_SPICLK = P2^5;                 // Initialize P2.5 as the SPICLK signal (Output)


unsigned char data overflow_count;      // Define system interrupt as a variable
unsigned char data keyb_input    ;      // Keyboard input register(8bit)
unsigned int  data Counter_us    ;      // Microsecond counter(16bit)-ISR usage
unsigned char data Task          ;      // Special user register (8bit)-Task manager usage
unsigned char data SPI_DATA      ;      // SPI data register (8bit)
unsigned char data AD_Sample     ;      // Current 8bit sample from A/D module
unsigned char data Readout       ;      // Current SPI Byte recieved


void Delay_20ms(void);
void Write_SPI(unsigned char Temp1);

main (void)
{

  P0M1 = 0x00;
  P0M2 = 0x00;
//Port1 configuration
  P1M1 = 0x00;
  P1M2 = 0x00;
//Port2 configuration
  P2M1 = 0x02;
  P2M2 = 0x00;


  TMOD = 0x02;
  TAMOD= 0x00;
  TL0  = 0x44;
  TH0  = 0x44;
  IEN0 = 0x82;
  TCON = 0x10;


  ADINS  = 0x40;
  ADCON1 = 0x24;
  ADMODA = 0x10;
  ADMODB = 0x60;
  ADCON0 = 0x00;
  Task   = 0;
  P2     = 0;


Delay_20ms();                                                   // Startup delay for 20ms to let flash memory to recover
while (1)                                                               // Loop forever ("Super loop")
  {


          if (keyb_input == 0x04)                       // Rec key pressed (?) - (Press Suspected)
                        {
                          REC_LED  = 1;
                          BUSY_LED = 0;
                          PLAY_LED = 0;
                          Task     = 0x01;                      // Modify Task register (TaskID:0x01)
                     }
                        else

                          Task     = 0x00;                      // Modify Task register (TaskID:0x00)
                          REC_LED  = 0;
                          BUSY_LED = 0;
                          PLAY_LED = 0;
  }
}


void timer0_ISR (void) interrupt 1
        {
     IEN0 = 0x82;                                       // Enable interrupts on timer0/Disable global interrupts
         Status_LED = 1;                                        // Open Status led
         Counter_us++;                                          // Increment microsecond counter(16bit)
         keyb_input = P0;                       // Read keyboard
         keyb_input = keyb_input & 0x07;    // Isolate keyboard input bit pattern
         ADMODB = 0x60;                                         // ADC mode for AD-Module1
          while((ADCON1 & 0x08) == 0);              // Wait for end of conversion
                  {
                  }
           if ( Task == 0x01)
            {
                   ADCON1 &= 0xF7;                          // Clear EOC flag
           SPI_SS =0;                                   // Open communication with flash
                   Readout = READ_DEVID;
                   Write_SPI(Readout);
                   Readout = 0X00;
                   Write_SPI(Readout);
                   Readout = 0X00;
                   Write_SPI(Readout);
                   Readout = 0X00;
                   Write_SPI(Readout);
                   SPI_SS =1;                                   // Close communication with flash
            }
        else
           P1 = Readout;
           Status_LED = 0;                                      // Close status led
     IEN0 = 0x82;                                       // Enable interrupts on timer0/Disable global interrupts
        }


void Delay_20ms(void)
        {
                Counter_us = 0;                                 // Reset Counter_us 16bit register
                        while (Counter_us <= 400)    // Wait until 20ms elapsed
                                {

                                }
        }


void Write_SPI(unsigned char Readout)
        {
          unsigned char i;                                      // Local variable
      SPI_SPICLK = 0;                                   // SPI Mode0
          SPI_MOSI = 0;                             //
                   for(i = 8; i >0 ; i--)
            {
             if (Readout & 0x80)            // Current bit7 is "1" (?)
              SPI_MOSI = 1;                             // Set SPI_MOSI line
               else                                             // Else
              SPI_MOSI = 0;                             // Reset SPI_MOSI line
              Readout <<= 1;                      // Shift next bit into bit7

              SPI_SPICLK = 1;                   // SPI Slave latches input data bit
               if (SPI_MISO)                    // Check if SPI_MISO line is set
               Readout |= 0x01;                 // Modify Readout register
              SPI_SPICLK = 0;                   // SPI Slave shifts out next output data bit
                        }
          SPI_MOSI = 0;                             // Clear SPI_MOSI line
        }

  • 1) Look at the indent in your post. Try to avoid mixing indent with tab and indent with space. It is often an advantage to just use spaces when indenting. It doesn't significantly affect the compilation speed, and the size of the source file will still be tiny compared to the size of a modern HDD. But you will always get the same amount of indent whatever tool you use to view the file.

    2) Properly document your code. Your ISR updates a variable called Counter_us. From the name, I would think that this variable ticks every us. You don't have any comment about that frequency you initialize your timer with. But your Delay_20ms() function seem to assume that Count_us is ticked 20 times/ms, i.e every 50us. Why can't I see that in the variable name or in the documentation of the timer initialization or in a comment in the timer ISR or in a comment in the Delay_20ms() function?

    3) Do not call your SPI code from an ISR. An ISR should be short and quick, not generate bursts of many SPI bits. The timing of SPI is fully controlled by the master, so it doesn't matter if you get an interrupt while doing the communication. The extra delay will not destroy anything. The important thing is that you are not too fast, not that you are too slow. You already have a main loop - do use it.

    In your case, the time needed to perform the 32-bit SPI communication may make you miss an ADC read - if 20kHz sampling rate is important for you.

    4) Don't busy-loop in an ISR. If you write:

    while((ADCON1 & 0x08) == 0);
    


    in your ISR, how many percent of your processor will be consumed not doing anything? Remember that every percent CPU time consumed in an ISR is a percent not available for the main task, so an improper ISR can quickly eat up all your processor capacity, leaving you with a processor that can't do any "real" work in the main loop. Are you needing 20 000 AD conversions / second? Can't you configure the processor to perform continuous conversions, and just generate an interrupt when a value is ready to pick up?

  • Thanks Per for your advice.

    If you can send me a personal email i could give you a detailed code, cause i "tailored the documentation per instruction cause 7000 chars is the limit of the code i can post here :(

    Anyway, i am glad that you read my code :)
    The goal is to take 20000 samples per sec and store them to this little flash Atmel monster. I wish i knew how to succesfully setup the on chip SPI module, but for now on all my efforts are in vain. Thts why i try the Software SPI method.

    Any suggestions are very welcomed
    Btw, the time that the A/D takes one sample, according to my oscilloscope is about 3us :) .If i loop and SPI too, 10000000's of us :(

    The counter_us is incremented and calculated from the delay loop (20ms) just clearing and counting 50usx400 interrupt times :)

    Thanks again

  • "If i loop and SPI too, 10000000's of us"

    Your previous claim was that it took 100us for the SPI communication - why the difference?

    How much extra spam do you think I would get if I post my email address?

    20kHz sampling rate times 32 bits means that you need to write 640kbit/s data to the flash.

    Based on the clock frequency of your chip, come back with how many CPU instructions you may consume for each written bit - excluding the clock cycles needed by the other code in the ISR. You have less than 1.5us/bit available...

    You do need hardware SPI.

    Another thing: The flash chip isn't infinitely fast. The datasheet claims that it takes 10ms to write a flash page, but your code gets a new result to write every 50us.

    During the 10ms page write, you produce 200 new samples. A page is 512 bytes so the time needed for a page write represents a large part of the time you take to fill a new page - especially if you have more than 8 bits/sample.

    If the flash is fast enough for you requirements, then you need to think about buffering data. You have verified that the flash is fast enough, haven't you?

  • I wish i knew how to succesfully setup the on chip SPI module, but for now on all my efforts are in vain. Thts why i try the Software SPI method.
    WRONG APPROACH!!!
    If you can not "succesfully setup" find out why and learn, do not 'escape' to some other method. In your case (need speed) it is particularily unhealthy to use software where hardware is available.
    Why not use CodeArchitect, free from http://www.esacademy.com it will show you how.

    Erik