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