|
|
View previous topic :: View next topic |
Author |
Message |
rigomm
Joined: 17 Mar 2010 Posts: 13
|
Concatenating arrays |
Posted: Wed May 19, 2010 7:28 pm |
|
|
Hi!
I'm trying to make an array of 512 bytes. The array must contains the result of several ADC conversions, enough to fill the 512 bytes array.
The data of the array must be in ascii code.
So, what I'm doing is:
1.- Read the data from the ADC
2.- Convert into floating
3.- Convert into ASCII and save the result in a 8 bytes array
4.- Concatenate this array with the main array of 512 byte.
I got some data but is not correct.
How can I know when the array is fill?
The position of the initial data?
Also I tried save the data by pointing the position on which the 8byte array should be stored but I got just "j" in my results
I need this 512 array in ASCII to store in a SDcard
Below my part of my code.
I'm sorry my English and my programming skills are bad. I hope somebody can help me!
Code: |
char Texto1[512]={"******ADC data**********\r\n"};
char Data_ADC[512]; //Array to store the read data
/*******************************************************************************/
void Save_ADC_sector (void){
int m; //Determines number of samples
int16 value; //Store the ADC value, 10Bits
float voltaje; /Store the ADC result converted into float
char Temp_ADC[8]; //Array to save the data of each conversion
for (m=0;m<50;m++)
{
delay_ms(10); //Delay between samples
value=read_adc(); //Read the ADC
voltaje=3.3*value/1024; //Making conversion to voltage
sprintf (Temp_ADC,"\r\n%f",voltaje); //Saving sampled voltage in the array, ASCII format
strcat (Data_ADC,Temp_ADC); //Concatenating data of this sample with the main storage array
// Data_ADC [(m*8)]=Temp_ADC;
// Data_ADC[j*2]=value/256;
// Data_ADC[j*2+1]=value%256;
printf("\r\n %4Lu \r\n ",value); //Send decimal value od ADC to screen just to control
}
}
|
|
|
|
Wayne_
Joined: 10 Oct 2007 Posts: 681
|
|
Posted: Thu May 20, 2010 2:12 am |
|
|
I see several problems but first you don't say what data is incorrect so I don't know where your main problem is ?
Is it the ADC value that you read ?
Your Temp_ADC array is only 8 chars, you use 2 for return and newline, you use 1 for null termination char, that leaves 5 for your float, I am not sure what the maximum output of %f is you would be best to force it to a fixed length.
2 Ways to work out if the array is full.
the first is to do strlen on the array each time, this is time consuming and does not get past another problem in your code.
How do you know there is enough space left for the next value ?
The second way will fix this problem,
Code: |
#define ARRAY_SIZE 512
char Data_ADC[ARRAY_SIZE];
int8 len;
int16 totalLen = 0;
sprintf (Temp_ADC,"\r\n%5.4f",voltaje);
len = strlen(Temp_ADC);
if ((totalLen + len) < ARRAY_SIZE)
{
totalLen += len;
strcat (Data_ADC,Temp_ADC);
}
|
You should also change 512 to a #define or a const. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Thu May 20, 2010 2:26 am |
|
|
The first comment is 'why'?.
It is far simpler, just to save the ADC values, and convert them when you output. This way you only have 50*2 byte values. Saving things in memory in ASCII, is really a silly way to do things....
Then you come to the problem. The size of your output, is undefined. You may well get values like 1.275643 as the result of your output. This would be too large to fit in your temporary storage for a single value. By the time you add the line feed, carriage return, and the terminating '\0', this would occupy 11 locations...
So, the first thing to do, is to limit the number of decimals being generated by the output. So something like:
sprintf (Temp_ADC,"\r\n%5.3f",voltaje);
This should ensure that the value just fits into eight bytes.
In fact the code can be made faster, and less likely to have problems, by staying with integers. So:
Code: |
int32 voltaje; //Store the ADC result as a scaled integer
char Temp_ADC[8]; //Array to save the data of each conversion
for (m=0;m<50;m++)
{
delay_ms(10); //Delay between samples
value=read_adc(); //Read the ADC
voltaje=((3300*value)/1024)+1; //Making conversion to voltage
sprintf (Temp_ADC,"\r\n5.3lw",voltaje);
//Saving sampled voltage in the array, ASCII format
|
With this, the adc value, is scaled to give an integer, 1000* the float value you want. Then CCS has the ability to output such values with a correctly placed decimal, 'as if' they were a float. This is faster than float arithmetiic, and avoids any possibility of more decimals than wanted.
Do a read on the PIC adc, to see why I added the '1' (you actually want to add 0.5 bit, but this is as close as you can get in integer).
Then, with the size now limited, you should fit inside the 512 byte array. However if you want to 'keep track' of the size, then the solution is to maintain a counter. So, have an int16 value set to '0' when you enter the routine, and each time you generate 'Temp_ADC', add the strlen of this, to the value. You then know just how many bytes have been added to the array at any time.
Best Wishes |
|
|
rigomm
Joined: 17 Mar 2010 Posts: 13
|
Concatenating arrays |
Posted: Thu May 20, 2010 6:59 am |
|
|
Thank you Wayne_ and Ttelmah for your hints and quickly reply.
I think I should explain a litle more about what I´m aiming to do.
My goal is to make a data logger which should read data from the ADC, several channels but for now I´m trying the simplest code using only one channel.
The data must be stored into a SDCard.
You are right, Ttelmah, it´s easier and quicker saving the data directly from the ADC but I´m trying to save the data in a txt file ready to see the voltage values. Maybe, if I realized it takes a lot of time enough to reduce significantly the maximum sampling rate I want, then I will consider to save the data in a simpler format.
Now, I´m using a SDCard driver library and a FAT16 library which is lighter than that included with the CCS compiler.
Well, after this brief explanation here again my problem.
I must appoint that the the ADC conversion, read and conversion to float is OK. The problem is saving those data in the 512 bytes array.
Below my code.
I tried the solution Code: |
#include <18F2550.h> //Choose the microtroller to use
#device adc=10 //ADC output 10 bits
#fuses HS,NOWDT,NOPROTECT,PLL5, CPUDIV1,NOLVP //Hig frequency, no WDT, No code protection, No low voltage programming
#use delay(clock=20000000) //Xtal frequency = 20MHz
#use rs232(baud=115200, xmit=PIN_B5, rcv=PIN_B4, FORCE_SW) //Set-up RS232 module, 11.5kbps
#include <SDCard_hard.c>
#include <FAT16_SDCard.c>
#include <string.h> //Library for strings management
#define ARRAY_SIZE 512 //Array size according to the sector of SDcard size
//**************************************************************************************
void Save_ADC_sector (void);
//**************************************************************************************
char Texto1[ARRAY_SIZE]={"******ADC Data**********\r\n"};
char Data_ADC[ARRAY_SIZE];//
/*******************************************************************************/
//Read and ADC, convert values to ASCII and store them in an ARRAY 512 bytes size
//That ARRAY will be stored in one sector of the SD
void Save_ADC_sector (void){
Data_ADC [ARRAY_SIZE];
int8 len; //Variable for controlling the temporal length of the conversion
int m; //Variable for counting the number of samples
int16 value; //Store the ADC reads
float voltaje; //Store the ADC conversion into voltaje
char Temp_ADC[10]; //Store the ASCII data of each conversion
int16 totalLen =0; //Counting the total length of the intended 512 bytes size ARRAY
//Start reading the ADC
for (m=0;m<63;m++) //Number of readings to fill the ARRAY 512
{
delay_ms(500); //Delay between samples
value=read_adc(); //Read the ADc value
voltaje=3.3*value/1024; //Converting read into voltage
sprintf (Temp_ADC,"\r\n%1.3f",voltaje); //Creating a miniarray with the data in ASCII including \r\n
printf("\r\n %1.3f \r\n ",voltaje); //Sending the converted value to a PC via RS232, just for control
len=strlen(Temp_ADC)+1; //Length of temporal array
printf("Length Temp_ADC %u\r\n", len);//showing the length of the array
printf("Total length %lu\r\n", totalLen); //Showing the length of the ARRAY 512
if ((totalLen+len)<ARRAY_SIZE) //Controlling the total length, no more than 512
{
totalLen+=len;
strcat (Data_ADC, Temp_ADC);
}
else
{
printf("Length before out %lu\r\n", totalLen);
break;
}
}
printf("Length before out %lu\r\n", totalLen);
}
//***********************************************************************//
//Main program
//Creates a file "Datos.txt" into a file named LOGGER already in the SDcard
//Call a function to read the data form the ADC until fill an 512 bytes ARRAY.
//Add the ARRAY to the created file 10 times
void main(){
char NombreArchivo[13]="Datos.txt"; //Name of the file to create
char Carpetas[20]={"/LOGGER"}; //Name of the file existent in the SDcard
int16 UbicacionFolder;
//Setting up the ADC module
Unsigned int16 value; //Defines the variable to save the data from the ADC
setup_adc_ports (AN0); //Defines which ports will be used for the ADC module
setup_adc(ADC_CLOCK_DIV_32);//Selects the TAD=1.6uS (XTAL=20MHZ) total adq time=17.6us/10bits
set_adc_channel(0); //Selects the channel from where the measures will be taken
setup_wdt(WDT_OFF);
setup_timer_1(T1_DISABLED|T1_DIV_BY_1);
setup_timer_2(T2_DISABLED,0,1);
setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
setup_comparator(NC_NC_NC_NC);
delay_ms(1000);
printf("Starting SD card\r\n");
if(SDCard_init()==0){
printf("Error initializing the card\r\n");
}else{
printf("The SD card has been correctly initialized!!!\r\n\r\n");
FAT_init();
if(FAT_FindDirectory(Carpetas,DirectorioRaiz,UbicacionFolder)==0){
printf("Error, the file CARPETA can not be found\r\n");
}else{
printf("Creating the TXT file\r\n");
if(FAT_CreateFile(NombreArchivo,NombreArchivo,UbicacionFolder,Texto1)==0){
printf("Error creating the TXT file\r\n");
}
int r;
for (r=0;r<10;r++)
{
Save_ADC_sector();
printf("Appending data: %2u \r\n",r);
if(FAT_OpenAddFile(NombreArchivo,UbicacionFolder,Data_ADC)==0)
{
printf("Error the file can't be found");
}
}
}
}
while(1){} //Infinite loop doing nothing
} |
Using this I can save the first block of data, (My code tries to save 10 blocks by repeating the function ¨Save_ADC_sector¨).
The counter of length seems correct.
But I have a question here, Should I take into account the null data of the string? Now I´m taking into account in the temporal counting (var len) but not in the total length.
Anyway, the code save correctly the first block and starts reading the ADC for the next block, The total length variable re-start as expected but suddenly, after some readings, 18, 24, or something like that, surprisingly, the totalLen counter jumps from hundreds to thousands!!! According to my code, then the function finish and tries to save the data but there is an error, I think it´s due the size of the array that is actually impossible because even the PIC does not have that size of RAM memory.
Attached is a figure with the data saved, and the terminal screen when the counter jumps and the subsequent error.
[img]
[/img]
I think the problem is the array filling, maybe I need to restart the array, clean it or something but I don´t know.
I´m sorry, probably my code is really dirty and it´s a very simple problem for you but I´m trying to learning by doing. Any help will be welcomed! |
|
|
Wayne_
Joined: 10 Oct 2007 Posts: 681
|
|
Posted: Thu May 20, 2010 7:35 am |
|
|
Two things,
You define Data_ADC [ARRAY_SIZE]; as a global but also define it locally to the routine. The compiler does not complain about this but I have run into problems with this myself.
Actually you don't define it again, it is just there. Must be a copy/paste error ?
Secondly, you can speed things up quite a lot by changing 2 lines of code:-
Code: |
totalLen+=len;
strcat (Data_ADC, Temp_ADC);
|
You can do
Code: |
You must remove the +1 from
len=strlen(Temp_ADC); //Length of temporal array
...
strcpy(&Data_ADC[totalLen], Temp_ADC);
totalLen+=len;
|
Which should speed things up quite a lot.
I problem I have just noticed is that totalLen does not include the null terminating char so you may have to do the check
if ((totalLen + len + 1)<ARRAY_SIZE)
To cater for it. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Thu May 20, 2010 7:59 am |
|
|
One tiny little extra saving here.
It is always better to do the subtraction/addition, from the constant.
So:
if ((totalLen + len + 1)<ARRAY_SIZE)
Will result in the compiler having to add, total_len, to len, then subtract one for the test. However if instead you write:
if ((totalLen + len)<(ARRAY_SIZE-1))
Since 'ARRAY_SIZE' is a constant, as is the '1', the compiler calculates this at compile time, and the sum doesn't have to be done in the code at all!...
Just a general 'way of saving time'.
Best Wishes |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Fri May 21, 2010 7:47 am |
|
|
Quote: | I think the problem is the array filling, maybe I need to restart the array, clean it or something but I don´t know. | Yes, now you continue adding data to the already full Data_ADC buffer and corrupt other variables in RAM.
For example at the start of Save_ADC_Sector(), before the loop, add:This writes a string terminating zero at the first position in the buffer.
And as already mentioned, get rid of the line: Code: | Data_ADC [ARRAY_SIZE]; | I'm surprised the compiler does not complain about this line as it is doing nothing. |
|
|
Wayne_
Joined: 10 Oct 2007 Posts: 681
|
|
Posted: Fri May 21, 2010 7:58 am |
|
|
ckielstra wrote: | Quote: | I think the problem is the array filling, maybe I need to restart the array, clean it or something but I don´t know. | Yes, now you continue adding data to the already full Data_ADC buffer and corrupt other variables in RAM.
For example at the start of Save_ADC_Sector(), before the loop, add:This writes a string terminating zero at the first position in the buffer. |
Good point, but not required if he implements the change where:-
strcpy(&Data_ADC[totalLen], Temp_ADC);
As totalLen is initialised to 0 each time. |
|
|
rigomm
Joined: 17 Mar 2010 Posts: 13
|
Concatenating arrays |
Posted: Fri May 21, 2010 11:26 pm |
|
|
Hi everyone, thank you for your time and advices.
Wayne_ I implemented the solution that you propose.
The compiler does not complain, and apparently the program is saving the data, at least the data after the conversion is showed correctly the length of both arrays is showed correctly but something happens because at the end of the program, only the first value is stored for each time I fill the array.
I mean, It should be around 63 values ten times (630 values) according to my code but What I got is just ten values, the first value of each loop of ADC readings.
I checked the FAT and SDCard libraries and they work OK, I tested them by saving the same array several times and it work fine. So, the problem is still creating that array of 512 bytes.
below my code this time.
Code: |
#include <18F2550.h> //Choose the microcontroller to use
#device adc=10 //ADC output 10 bits
#fuses HS,NOWDT,NOPROTECT,PLL5, CPUDIV1,NOLVP //Hig frequency, no WDT, No code protection, No low voltage programming
#use delay(clock=20000000) //Xtal frequency = 20MHz
#use rs232(baud=115200, xmit=PIN_B5, rcv=PIN_B4, FORCE_SW) //Set-up RS232 module, 11.5kbps
#include <SDCard_hard.c>
#include <FAT16_SDCard.c>
#include <string.h> //Library for strings management
#define ARRAY_SIZE 512 //Array size according to the sector of SDcard size
//**************************************************************************************
void Save_ADC_sector (void);
//**************************************************************************************
char Texto1[ARRAY_SIZE]={"******ADC Data**********\r\n"};
char Data_ADC[ARRAY_SIZE];//
/*******************************************************************************/
//Read and ADC, convert values to ASCII and store them in an ARRAY 512 bytes size
//That ARRAY will be stored in one sector of the SD
void Save_ADC_sector (void){
int16 len; //Variable for controlling the temporal length of the conversion
int m; //Variable for counting the number of samples
int16 value; //Store the ADC reads
float voltaje; //Store the ADC conversion into voltaje
char Temp_ADC[10]; //Store the ASCII data of each conversion
int16 totalLen =0; //Counting the total length of the intended 512 bytes size ARRAY
//Start reading the ADC
Data_ADC [0]=0;
for (m=0;m<63;m++) //Number of readings to fill the ARRAY 512
{
delay_ms(100); //Delay between samples
value=read_adc(); //Read the ADC value
voltaje=3.3*value/1024; //Converting read into voltage
sprintf (Temp_ADC,"\r\n%1.3f",voltaje); //Creating a miniarray with the data in ASCII including \r\n
printf("\r\n %1.3f \r\n ",voltaje); //Sending the converted value to a PC via RS232, just for control
len=strlen(Temp_ADC); //Length of temporal array
printf("Length Temp_ADC %lu\r\n", len);//showing the length of the array
printf("Total length %lu\r\n", totalLen); //Showing the length of the ARRAY 512
if ((totalLen+len+1)<ARRAY_SIZE) //Controlling the total length, no more than 512
{
strcpy (Data_ADC [totalLen],Temp_ADC);
totalLen+=(len+1);
// strcat (Data_ADC, Temp_ADC);
}
else
{
printf("Length before out %lu\r\n", totalLen);
break;
}
}
printf("Length before out %lu\r\n", totalLen);
}
//***********************************************************************//
//Main program
//Creates a file "Datos.txt" into a file named LOGGER already in the SDcard
//Call a function to read the data form the ADC until fill an 512 bytes ARRAY.
//Add the ARRAY to the created file 10 times
void main(){
char NombreArchivo[13]="Datos.txt"; //Name of the file to create
char Carpetas[20]={"/LOGGER"}; //Name of the file existent in the SDcard
int16 UbicacionFolder;
//Setting up the ADC module
Unsigned int16 value; //Defines the variable to save the data from the ADC
setup_adc_ports (AN0); //Defines which ports will be used for the ADC module
setup_adc(ADC_CLOCK_DIV_32);//Selects the TAD=1.6uS (XTAL=20MHZ) total adq time=17.6us/10bits
set_adc_channel(0); //Selects the channel from where the measures will be taken
setup_wdt(WDT_OFF);
setup_timer_1(T1_DISABLED|T1_DIV_BY_1);
setup_timer_2(T2_DISABLED,0,1);
setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
setup_comparator(NC_NC_NC_NC);
delay_ms(1000);
printf("Starting SD card\r\n");
if(SDCard_init()==0){
printf("Error initializing the card\r\n");
}else{
printf("The SD card has been correctly initialized!!!\r\n\r\n");
FAT_init();
if(FAT_FindDirectory(Carpetas,DirectorioRaiz,UbicacionFolder)==0){
printf("Error, the file CARPETA can not be found\r\n");
}else{
printf("Creating the TXT file\r\n");
if(FAT_CreateFile(NombreArchivo,NombreArchivo,UbicacionFolder,Texto1)==0){
printf("Error creating the TXT file\r\n");
}
int16 r;
for (r=0;r<10;r++)
{
Save_ADC_sector();
printf("Appending data: %lu \r\n",r);
output_high (PIN_B7);
if(FAT_OpenAddFile(NombreArchivo,UbicacionFolder,Data_ADC)==0)
{
printf("Error the file can't be found");
output_high (PIN_B6);
}
output_low(PIN_B7);
}
}
}
while(1){} //Infinite loop doing nothing
} |
ckielstra
Thanks for your hint.
I implemented also, even when apparently is not necessary by doing the implementation that Wayne_ suggested, but after realize that it doesn't work I decided add that line:
Data_ADC[0]=0;
I thought, its better two to ensure but, I only get the same results, so the problem is still there.
Ah! of course, I erased the line where I was defining twice. It was my attempt for re-start the array, now I know it was incorrect :-)
Ttelmah
Thanks for your advice for saving time, I´m taking note of these tricks to improve the execution time. I soon as it works! :-)
Well, I'm trying to find more explanations about what exactly do the strcat, strcpy, etc., I mean, the limits, errors, time consuming, etc but the manual of CCS compiler lacks of many important points. I think.
Now, I'm reading a basic tutorial about C and strings.
If you know any good tutorial or site where can I find more information I really appreciate you let me know.
A very important question.
I read in the manual of CCS that the maximum size of an array in RAM is 256 bytes, because of the size of the memory bank. However I'm declaring a 512 bytes array and the compiler does not complain, Also, the first time I fill that buffer I don't get any problem. So, How can I understand this?
Thanks to all for your time reading this. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Sat May 22, 2010 2:39 pm |
|
|
The 256 byte limitation, was with the PIC16 chips. With the PIC18 this disappeared.
Best Wishes |
|
|
rigomm
Joined: 17 Mar 2010 Posts: 13
|
Solved |
Posted: Sun May 23, 2010 10:33 pm |
|
|
Well I want to thank all of you who reply my message.
Finally I got successful readings and recordings.
Below is the code in case somebody wants to implement it. Unfortunately for me, the time consumed by the SD card to save the data is too much, and depends on the fragmentation of the memory. Then, my required sampling rates are not achievable .
I´ll try another method.
Ttelmah wrote: | The 256 byte limitation, was with the PIC16 chips. With the PIC18 this disappeared.
Best Wishes |
Thanks Ttelmah, I didn´t know and I downloaded the last manual but I think is not updated on that point.
Regards!
Rigo
Code: | #include <18F2550.h> //Choose the microtroller to use
#device adc=10 //ADC output 10 bits
#fuses HSPLL,NOWDT,NOPROTECT,USBDIV,PLL5, CPUDIV1,NOLVP //Hig frequency, no WDT, No code protection, No low voltage programming
#use delay(clock=48000000) //Xtal frequency = 20MHz
#use rs232(baud=115200, xmit=PIN_B5, rcv=PIN_B4, FORCE_SW) //Set-up RS232 module, 11.5kbps
#include <SDCard_hard.c>
#include <FAT16_SDCard.c>
#include <string.h> //Library for strings management
#define ARRAY_SIZE 512 //Array size according to the sector of SDcard size
//**************************************************************************************
void Save_ADC_sector (void);
//**************************************************************************************
char Texto1[50]={"******ADC Data**********\r\n"};
char Data_ADC[ARRAY_SIZE];//
/*******************************************************************************/
//Read and ADC, convert values to ASCII and store them in an ARRAY 512 bytes size
//That ARRAY will be stored in one sector of the SD
void Save_ADC_sector (void){
int16 len; //Variable for controlling the temporal length of the conversion
int m; //Variable for counting the number of samples
int16 value; //Store the ADC reads
float voltaje; //Store the ADC conversion into voltaje
char Temp_ADC[10]; //Store the ASCII data of each conversion
int16 totalLen =0; //Counting the total length of the intended 512 bytes size ARRAY
Data_ADC [0]=0;
for (m=0;m<63;m++) //Number of readings to fill the ARRAY 512
{
delay_ms(10); //Delay between samples
value=read_adc(); //Read the ADc value
voltaje=3.3*value/1024; //Converting read into voltage
sprintf (Temp_ADC,"\r\n%1.3f",voltaje); //Creating a miniarray with the data in ASCII including \r\n
printf("\r\n %1.3f \r\n ",voltaje); //Sending the converted value to a PC via RS232, just for control
len=strlen(Temp_ADC); //Length of temporal array
// printf("Length Temp_ADC %lu\r\n", len);//showing the length of the array
// printf("Total length %lu\r\n", totalLen); //Showing the length of the ARRAY 512
if ((totalLen+len+1)<ARRAY_SIZE) //Controlling the total length, no more than 512
{
totalLen+=(len+1);
strcat (Data_ADC, Temp_ADC);
}
else
{
printf("Length before out %lu\r\n", totalLen);
break;
}
}
printf("Length before out %lu\r\n", totalLen);
}
//***********************************************************************//
//Main program
//Creates a file "Datos.txt" into a file named LOGGER already in the SDcard
//Call a function to read the data form the ADC until fill an 512 bytes ARRAY.
//Add the ARRAY to the created file 10 times
void main(){
char NombreArchivo[13]="Datos.txt"; //Name of the file to create
char Carpetas[20]={"/LOGGER"}; //Name of the file existent in the SDcard
int16 UbicacionFolder;
//Setting up the ADC module
Unsigned int16 value; //Defines the variable to save the data from the ADC
setup_adc_ports (AN0); //Defines which ports will be used for the ADC module
setup_adc(ADC_CLOCK_DIV_32);//Selects the TAD=1.6uS (XTAL=20MHZ) total adq time=17.6us/10bits
set_adc_channel(0); //Selects the channel from where the measures will be taken
setup_wdt(WDT_OFF);
setup_timer_1(T1_DISABLED|T1_DIV_BY_1);
setup_timer_2(T2_DISABLED,0,1);
setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
setup_comparator(NC_NC_NC_NC);
delay_ms(1000);
printf("Starting SD card\r\n");
if(SDCard_init()==0){
printf("Error initializing the card\r\n");
}else{
printf("The SD card has been correctly initialized!!!\r\n\r\n");
FAT_init();
if(FAT_FindDirectory(Carpetas,DirectorioRaiz,UbicacionFolder)==0){
printf("Error, the file CARPETA can not be found\r\n");
}else{
printf("Creating the TXT file\r\n");
if(FAT_CreateFile(NombreArchivo,NombreArchivo,UbicacionFolder,Texto1)==0){
printf("Error creating the TXT file\r\n");
break;
}
int16 r;
for (r=0;r<100;r++)
{
Save_ADC_sector();
printf("Appending data: %lu \r\n",r);
output_high (PIN_B7);
if(FAT_OpenAddFile(NombreArchivo,UbicacionFolder,Data_ADC)==0)
{
printf("Error the file can't be found");
output_high (PIN_B6);
break;
}
output_low(PIN_B7);
// delay_ms(10);
}
}
}
while(1){
delay_ms(200);
output_high (PIN_B6);
delay_ms(200);
output_low (PIN_B6);
} //Infinite loop doing nothing
}
|
|
|
|
Wayne_
Joined: 10 Oct 2007 Posts: 681
|
|
Posted: Mon May 24, 2010 2:31 am |
|
|
What sample rate are you trying to acheive ?
The problem is more likely to be your Fat16 routines rather than the SD card. I am working on a similar project and I did notice the routines that come with CCS for SD card and FAT use software SPI. They should be easy to modify to use hardware but depending on your sample rate you may still struggle to reach the frequency you require.
I am not using FAT, I am writing to the card as sequential data and then writing an app on the PC to retrieve it via USB and format it.
I am using a 18F46J50 and have been trying to get the SPI-DMA working, to some extent it is but I have some problems.
With the device running using a standard timer interrupt for the sampling and then using the DMA to transfer the data I can get 44.1KB sample rate.
My problems are getting the spi2 interface to work reliably, and what appears to be a bug in CCS which has hinderd my progress.
I have also recently become awhere of Licensing requirements for using the SD cards which means I am looking at other options for storage (has to have a small footprint with > 1GB of storage). |
|
|
rigomm
Joined: 17 Mar 2010 Posts: 13
|
My requirements |
Posted: Mon May 24, 2010 10:45 pm |
|
|
Hi Wayne_
Actually, my requirements are not so high like in your project.
I just need, for now, 1KHz. It's a very low frequency compared with your (44KHz)?.
In fact, now I'm doing the same as you, saving the data in raw mode in the SDcard, and after that I will send the data via bluetooth (RS232) to a computer where I should re-arrange the data to get a TXT or CSV file.
As my requirements are relatively easy to achieve I think I can get it done using the normal SPI without the DMA.
By the way, The FAT routines I was using, take between 160ms and 700ms saving one sector (512 bytes) depending on the grade of fragmentation of the SD. Definitely, not useful for me. :-(
Regards! |
|
|
Wayne_
Joined: 10 Oct 2007 Posts: 681
|
|
Posted: Tue May 25, 2010 2:17 am |
|
|
Hi,
First I would confirm that the SPI routines are using hardware SPI and not software by looking at the code.
Also, if you have decided to format the data on the PC then you may as well do away with the conversion to ASCII and store the values as a 16 bit number, this will speed up that routine quite alot.
Next, you will proberbly loose a lot of samples during the writing of the data to the card, you can minimise this by doing it a sample at a time. the SD reaquirement is to write a datablock of 512 bytes, I don't have access to the Full spec but there may not be any issues with having a fairly large gap between byte writes.
So you would do this:-
Code: |
init the card,
Main Loop
Set the card for writing 1 block at block x
ADC Loop
read ADC
Write data
After 512 bytes written break out of loop
ADC End
Finish the datablock with dummy checksum
Read result from card
Read Card status Loop Until data has been written to flash
increment block number x
Main loop End
|
This will do away with the buffer and you will proberbly be able to get it up to the speed you require. |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Tue May 25, 2010 4:48 am |
|
|
Quote: | I don't have access to the Full spec but there may not be any issues with having a fairly large gap between byte writes. | A simplified specification can be obtained for free from the SD Card Association.
Last time I looked into it there was no maximum time for the delay between sending data bytes as long as you keep the CS pin asserted. The method described by Wayne has been discussed before on this forum as a mechanism to increase speed. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|