uSD I/O
I am working with SimpleIDE 0-9-28 on my Windows 7 PC, and below is a simple program example that is found in the Propeller C Tutorials(online). This is a very straight forward program that captures a keypress and then writes to the uSD card. The data that is captured is in byte form, that is handled by a '%d' or '%s' to be presentable on the screen, while on the uSD card it appears as gibberish symbols that is byte code. This is all well and good.
Since I am working on a program that will be obtaining data from a Sensirion SHT11 module, I am wondering how I can manipulate the input data so it would be in a readable form when opened by notepad, or any other such program, when stored on the uSD card. Specifically the form would be a database, so I can present it in graph style or anything else. Another problem arises is when the data is now in a non-byte form, then using an fread command runs into some problems. Any easy solutions for this?
Thanks
Ray
Since I am working on a program that will be obtaining data from a Sensirion SHT11 module, I am wondering how I can manipulate the input data so it would be in a readable form when opened by notepad, or any other such program, when stored on the uSD card. Specifically the form would be a database, so I can present it in graph style or anything else. Another problem arises is when the data is now in a non-byte form, then using an fread command runs into some problems. Any easy solutions for this?
Thanks
Ray
/*
SDio.c
*/
#include "simpletools.h"
/* Activity Board */
int DO = 22, CLK = 23, DI = 24, CS = 25;
FILE* fp;
int main()
{
// Add startup code here.
pause(300);
printf("uSD I/O test program.\n");
sd_mount(DO, CLK, DI, CS);
fp = fopen("test.txt", "a");
int n,status,m;
while(1)
{
// Add main loop code here.
printf("> ");
status = scanf("%s", &n);
if(!status) break;
fwrite(&n, 4, 1, fp);
}
fclose(fp);
/* Display contents of file. */
printf("\nYou entered:\n");
fp = fopen("test.txt", "r");
while(1)
{
status = fread(&m,4, 1, fp);
if(!status) break;
printf("n = %d\n", m);
}
fclose(fp);
}

Comments
I'm trying to decide between fixing FSRW to work in xmm-split mode or using the stardard I/O...
But, I can't find a simple example of using standard I/O to just read a file...
Is there one?
Maybe I'll try this example with your changes.
Can I just use stdio.h instead of simpletools.h?
Do I need the simpletools.h to make it work like in this example?
The actual example uses %d, and all that it allows are numbers on the keyboard; I wanted to also capture letters, hence %s. I guess I am breaking SOP with this.
Ray
I noticed the C++ style of variable declaration and wondered it C had added that style since I last used C back in the Turbo C days.
The examples on Parallax site use it and I like it.
I do not think it needs to be pure ANSI C to be a good teaching tool for C and C++ programming and for sure for programming propeller code.
I guess it could also be a bug and we are using the C++ part to the compiler as a default and that was not what was selected in the IDE.
Tom
Ray
/* SD Datalogger.side Application prompts you to type numbers into SimpleIDE Terminal, and records to SD. Plays back all numbers after you type q and press Enter. http://learn.parallax.com/propeller-c-simple-devices/sd-card-data */ #include "simpletools.h" // Include simpletools header . int DO = 22, CLK = 23, DI = 24, CS = 25; // SD card pins on Propeller BOE int main(void) // Main function { pause(1000); // Delay for terminal printf("Enter several values.\n"); // User instructions printf("To exit, type q then Enter\n"); sd_mount(DO, CLK, DI, CS); // Mount SD card FILE* fp = fopen("test.txt", "w"); // Open a file for writing int n, status; // Number & status variables while(1) // Endless loop { printf("> "); // User prompt status = scanf("%d", &n); // Get number & status if(!status) break; // Status 0? Break out of loop fwrite(&n, 4, 1, fp); // Write number to SD card } fclose(fp); // Close the file printf("\nYou entered:\n"); // List heading fp = fopen("test.txt", "r"); // Open a file for writing while(1) { status = fread(&n, 4, 1, fp); // Read from SD & get status if(!status) break; // If no more, break loop printf("n = %d\n", n); // Display value } fclose(fp); // Close the file }I think you are able to include inline declarations in this code because the "Other Compiler Options" has been set to "-std=c99". I think I remember removing that option and having to move all my declarations to the top of functions or as globals... Just a guess as I'm not positive that was the issue.
dgately
dgately
Ray
Yes. Parallax requested that -std=c99 be included on any Simple Projects. If folks don't understand what is trying to be achieved with Simple View and SImple Libraries, they should spend time with the Parallax Propeller C Web Site and Educational Tutorials.
Also, it would be nice to know if things are missing from the User Guide. For example, some of the Simple View -vs- Project View behaviors are not documented. The Propeller-Load document describes using config files and _cfg_ variable patching; it was not included in the User Guide and is available as a separate document. The User Guide content is owned by Parallax. All SimpleIDE Simple View decisions are owned by Parallax.
Simple View is the Parallax version of Project View. You can choose between one view and another with the Menu Tools -> Set Simple/Project View. Simple View is designed for Educational customers. Project View operates the way 0-8-5 did except for some enhancements I thought were useful that were introduced in Simple View such as the New Project methodology (Project View New Project gives a small template for the main file where as Simple View New Project uses the educational templates); the Add Library, Add Tab, and Open Tab tools; the Create Project Library.
As far as C versions, it depends on the requirements and coding standard if any of an organization. Some people are pedantic, uptight, and argumentative; others don't care (people you won't mind working with). If you want a job writing C programs, it's good to know what are the basic extensions to C89 that C99 brings so that you can deal with the pedantic C89 types.
Ray
Ardunio to teach programming in a C or C++ syntax for microcontrollers ie propeller.
For pure ANSI C that should be a seperate class taken by students.
Second back to the original question asked I created an example and attached the
file it created on the SD card and an excel file that used it.
/* Write a simple comma seperated file to SD Card */ #include "simpletools.h" // Include simple tools int DO = 22, CLK = 23, DI = 24, CS = 25; int main() // Main function { int count = 0; int yval = 0; sd_mount(DO, CLK, DI, CS); FILE* fp = fopen("data.csv","w"); // Wait for a key to be pressed on the terminal char ch = getchar(); // Write a text file printf("Writing file\n"); for(int idx = 0;idx < 11;idx++) { count = idx; yval = 10 * count; fprintf(fp,"%d,%d\n",count,yval); pause(500); } fclose(fp); printf("Done Writing File\n"); }For some reason the file with an extention of csv would not add here so I renamed it txt
Tom
Hopefully as more interest gets stirred up for C, somebody will create some specific C code for using the Sensirion module that Parallax sells, hint, hint. I have a similar prototype with a Sensirion module that uses a GG PPUSB board and it is written in Spin. I want to create something similar that is written in C, then I can do some comparisons.
Ray
/* * MyTempLog.c * * May 11, 2013 * * Uses JLocke ThermoProp Spin examples that are converted * to C using spin2cpp. * */ #include "simpletools.h" #include "sensirion.h" /* This is for Activity Board */ #define Sht11Data 15 #define Sht11Clk 14 // Use a 4.7k resistor for pulldown /* Forward declarations */ void sht11(void); void DisplayFile(void); int DO = 22, CLK = 23, DI = 24, CS = 25; int fTemp, Humid; FILE *pab; FILE *txt; /* Main function */ int main() { // Add startup code here. int status, n; sd_mount(DO, CLK, DI, CS); pause(300); printf("My Temp/Humidity Log Program\n"); printf("Menu: 0 - Quit, 1 - Get info, 2 - Display Info\n"); while(1) { printf("> "); scanf("%d", &n); if(n == 1) // 1 = Get temp { sht11(); } if(n == 2) // 2 = Read and display { //printf("Nothing yet\n"); DisplayFile(); } if(n == 0) break; // 0 = Quit } printf("Program stoped.\n"); fclose(txt); } void sht11() { char tbuff[4]; int tTemp; sensirionSpin_Start(Sht11Data,Sht11Clk); sensirionSpin_Config(33,NULL,NULL,NULL); pause(100); fTemp = sensirionSpin_Gettemperaturef(); Humid = sensirionSpin_Gethumidity(); pause(100); printf("Temp: %d\n", fTemp); printf("Humidity: %d\n", Humid); // Add a write to the uSD card pab = fopen("TempLog.pab", "a"); fwrite(&fTemp, 1, 2, pab); fwrite(&Humid, 1, 2, pab); fclose(pab); txt = fopen("TempLog.txt", "a"); fprintf(txt,"T%d ", fTemp); fprintf(txt,"H%d;", Humid); fclose(txt); } void DisplayFile() { int status; pab = fopen("TempLog.pab", "r"); while(1) { status = fread(&fTemp, 1, 2, pab); if(!status) break; printf("Temp: %d\n", fTemp); status = fread(&Humid, 1, 2, pab); if(!status) break; printf("Humidity: %d\n", Humid); } fclose(pab); }What board type are you using when removing the mount? Can you copy/paste the build status here?
Ray
Ray
# Propeller activity board configuration. # IDE:SDXMMC clkfreq: 80000000 clkmode: XTAL1+PLL16X baudrate: 115200 rxpin: 31 txpin: 30 cache-driver: eeprom_cache.dat cache-size: 8K cache-param1: 0 cache-param2: 0 eeprom-first: TRUE sd-driver: sd_driver.dat sdspi-do: 22 sdspi-clk: 23 sdspi-di: 24 sdspi-cs: 25#include <propeller.h> #include <stdio.h> extern _Driver _SimpleSerialDriver; extern _Driver _FileDriver; _Driver *_driverlist[] = { &_SimpleSerialDriver, &_FileDriver, NULL };Ray
/* * MyTempLog.c * * May 11, 2013 * * Uses the Activity Board. * * Uses JLocke ThermoProp Spin examples that are converted * to C using spin2cpp. * Added a Time Stamp with a capture of temp/humidity. * */ #include "simpletools.h" #include "sensirion.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <unistd.h> #include <sys/rtc.h> #include <propeller.h> /* This is for Activity Board */ #define Sht11Data 15 #define Sht11Clk 14 // Use a 4.7k resistor for pulldown /* Use for prompttime buffer size. */ #define BUFFERLEN 10 /* Forward declarations */ void sht11(void); void DisplayFile(void); void settime(void); void printtime(void); int getdst(void); int prompttime(char *prompt); int DO = 22, CLK = 23, DI = 24, CS = 25; int fTemp, Humid; FILE *pab; FILE *txt; /* Main function */ int main() { // Add startup code here. int status, n; _rtc_start_timekeeping_cog(); // Runs asm function, // works in LMM,CMM,XMM modes sd_mount(DO, CLK, DI, CS); pause(300); printf("My Temp/Humidity Log Program\n"); printf("Menu: 0 - Quit, 1 - Get info, 2 - Display Info\n"); printf(" 3 - Set Time, 4 - Time\n"); printtime(); while(1) { printf("> "); scanf("%d", &n); if(n == 1) sht11(); // 1 = Get temp if(n == 2) DisplayFile(); // 2 = Read and display if(n == 3) settime(); // Set the time if(n == 4) printtime(); // Print the time if(n == 0) break; // 0 = Quit } printf("Program stoped.\n"); // fclose(txt); } void sht11() { time_t now; now = time(NULL); sensirionSpin_Start(Sht11Data,Sht11Clk); sensirionSpin_Config(33,NULL,NULL,NULL); pause(100); fTemp = sensirionSpin_Gettemperaturef(); Humid = sensirionSpin_Gethumidity(); pause(100); printf("Temp: %d\n", fTemp); printf("Humidity: %d\n", Humid); // Add a write to the uSD card pab = fopen("TempLog.pab", "a"); fwrite(&fTemp, 1, 2, pab); fwrite(&Humid, 1, 2, pab); fclose(pab); txt = fopen("TempLog.txt", "a"); fprintf(txt,"%s", asctime(localtime(&now))); fprintf(txt,"T%d ", fTemp); fprintf(txt,"H%d;", Humid); fclose(txt); } void DisplayFile() { int status; pab = fopen("TempLog.pab", "r"); while(1) { status = fread(&fTemp, 1, 2, pab); if(!status) break; printf("Temp: %d\n", fTemp); status = fread(&Humid, 1, 2, pab); if(!status) break; printf("Humidity: %d\n", Humid); } fclose(pab); } void printtime(void) { time_t now; now = time(NULL); printf("%s", asctime(localtime(&now))); } int getdst(void) { int rc = 0; printf("Use daylight savings time [y/n] ?"); fflush(stdout); rc = (getchar() == 'y') ? 1 : 0; // getchar(); return rc; } int prompttime(char *prompt) { int rc = 0; char *endp; char buffer[BUFFERLEN]; do { printf("Enter %s: ",prompt); fflush(stdout); fgets(buffer,BUFFERLEN,stdin); fflush(stdin); rc = strtol(buffer, &endp, 10); if(endp == buffer) { if('\n' == *endp) { rc = 0; break; } printf("Invalid entry \"%c....\" Please enter a number.\n", *endp); } } while(endp == buffer); return rc; } void settime(void) { struct timeval tv; struct tm t; t.tm_isdst = getdst(); t.tm_year = prompttime("Year")-1900; t.tm_mon = prompttime("Month")-1; t.tm_mday = prompttime("Day of the month"); t.tm_hour = prompttime("Hour"); t.tm_min = prompttime("Minute"); t.tm_sec = prompttime("Second"); tv.tv_sec = mktime(&t); settimeofday(&tv, 0); printf("Set time all done.\n"); }Andy
Andy
Ray
1) In Simple View, click the lower-left Show Project Manager button if it isn't already in view.
2) Set Board type to ACTIVITYBOARD-SDXMMC.
3) Set Memory Model to XMMC External Flash Code Main Ram.
After that, you can Run with Terminal, or Load EEPROM & Run. If you use Load EEPROM & Run, make sure to Click Program -> Open Terminal, then Program -> Reset Port.
Andy
Ray
fTemp = sensirionSpin_Gettemperaturef();
Humid = sensirionSpin_Gethumidity();
These two functions are what is causing the problem, which are part of the spin2cpp conversion of the Spin sensirion examples that I used. I guess I could look at the sensirion.c code, but I am not sure what I would be looking for. Maybe somebody can spot the problem, I attached the sensirion stuff.
Ray
sensirion.c
// // automatically generated by spin2cpp v1.03 on Sat May 11 07:56:31 2013 // spin2cpp --ccode sensirion.spin // #include <propeller.h> #include "sensirion.h" #ifdef __GNUC__ #define INLINE__ static inline #define Yield__() __asm__ volatile( "" ::: "memory" ) #define PostEffect__(X, Y) __extension__({ int32_t tmp__ = (X); (X) = (Y); tmp__; }) #else #define INLINE__ static static int32_t tmp__; #define PostEffect__(X, Y) (tmp__ = (X), (X) = (Y), tmp__) #define Yield__() #define waitcnt(n) _waitcnt(n) #define locknew() _locknew() #define lockret(i) _lockret(i) #define lockset(i) _lockset(i) #define lockclr(i) _lockclr(i) #define coginit(id, code, par) _coginit((unsigned)(par)>>2, (unsigned)(code)>>2, id) #define cognew(code, par) coginit(0x8, (code), (par)) #define cogstop(i) _cogstop(i) #endif INLINE__ int32_t Min__(int32_t a, int32_t b) { return a < b ? a : b; } INLINE__ int32_t Max__(int32_t a, int32_t b) { return a > b ? a : b; } INLINE__ int32_t Shr__(uint32_t a, uint32_t b) { return (a>>b); } INLINE__ int32_t Lookup__(int32_t x, int32_t b, int32_t a[], int32_t n) { int32_t i = (x)-(b); return ((unsigned)i >= n) ? 0 : (a)[i]; } static int32_t sensirionSpin_Sendcommand(int32_t Cmd); static int32_t sensirionSpin_Readword(void); static int32_t sensirionSpin_Readbyte(int32_t Ack); static int32_t sensirionSpin_Writebyte(int32_t Value); static int32_t sensirionSpin_Wait(void); static sensirionSpin thisobj; static uint8_t dat[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x40, 0xdf, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; int32_t sensirionSpin_Start(int32_t Data_pin, int32_t Clock_pin) { thisobj.Dpin = Data_pin; thisobj.Cpin = Clock_pin; OUTA &= ~(1<<thisobj.Cpin); DIRA = ((DIRA & (~(1 << thisobj.Cpin))) | (1 << thisobj.Cpin)); { int32_t _idx__0000; for(_idx__0000 = 1; _idx__0000 <= 9; (_idx__0000 = (_idx__0000 + 1))) { OUTA ^= (1<<thisobj.Cpin); OUTA ^= (1<<thisobj.Cpin); } } return 0; } int32_t sensirionSpin_Config(int32_t Volt, int32_t Heater, int32_t Otpreload, int32_t Measres) { static int32_t look__0001[] = {164, 655, }; static int32_t look__0002[] = {38483, 615724, }; static int32_t look__0003[] = {(-2), (-428), }; static int32_t look__0004[] = {84, 1342, }; Volt = (Min__((Max__(20, Volt)), 55)); Measres = (Min__((Max__(0, Measres)), 1)); ((int32_t *)&dat[0])[0] = (((-438) * Volt) + (-634991)); ((int32_t *)&dat[4])[0] = Lookup__(Measres, 0, look__0001, 2); ((int32_t *)&dat[12])[0] = Lookup__(Measres, 0, look__0002, 2); ((int32_t *)&dat[16])[0] = Lookup__(Measres, 0, look__0003, 2); ((int32_t *)&dat[24])[0] = Lookup__(Measres, 0, look__0004, 2); sensirionSpin_Writestatus((((Heater << 2) + (Otpreload << 1)) + Measres)); return 0; } int32_t sensirionSpin_Gettemperaturec(void) { thisobj.Tc = (((*(int32_t *)&dat[0]) + ((*(int32_t *)&dat[4]) * sensirionSpin_Readtemperature())) >> 14); return thisobj.Tc; } int32_t sensirionSpin_Gettemperaturef(void) { sensirionSpin_Gettemperaturec(); // return (((((thisobj.Tc << 12) * 9) / 5) + (32 << 12)) >> 12); /* This is adjusted code to get a reading that is closer to actual. */ return(((((thisobj.Tc << 12) * 9) / 5) + (31 << 12)) >> 12); } int32_t sensirionSpin_Gethumidity(void) { int32_t Raw_rh, Linear_rh, Tmp; Raw_rh = sensirionSpin_Readhumidity(); Linear_rh = (((*(int32_t *)&dat[8]) + ((*(int32_t *)&dat[12]) * Raw_rh)) + ((Raw_rh * (*(int32_t *)&dat[16])) * Raw_rh)); Tmp = (Linear_rh + ((thisobj.Tc - 25) * ((*(int32_t *)&dat[20]) + ((*(int32_t *)&dat[24]) * Raw_rh)))); return (Tmp >> 20); } int32_t sensirionSpin_Readtemperature(void) { int32_t Ack; Ack = sensirionSpin_Sendcommand(Cmd_temperature); sensirionSpin_Wait(); return sensirionSpin_Readword(); } int32_t sensirionSpin_Readhumidity(void) { int32_t Ack; Ack = sensirionSpin_Sendcommand(Cmd_humidity); sensirionSpin_Wait(); return sensirionSpin_Readword(); } int32_t sensirionSpin_Readstatus(void) { int32_t Ack; Ack = sensirionSpin_Sendcommand(Cmd_readstatus); return sensirionSpin_Readbyte(1); } int32_t sensirionSpin_Writestatus(int32_t N) { int32_t Ack; Ack = sensirionSpin_Sendcommand(Cmd_writestatus); sensirionSpin_Writebyte((N & 0x47)); return 0; } int32_t sensirionSpin_Reset(void) { int32_t Ack; Ack = sensirionSpin_Sendcommand(Cmd_reset); waitcnt((CNT + ((CLKFREQ * 15) / 1000))); return 0; } int32_t sensirionSpin_Sendcommand(int32_t Cmd) { DIRA &= ~(1<<thisobj.Dpin); OUTA &= ~(1<<thisobj.Cpin); OUTA = ((OUTA & (~(1 << thisobj.Cpin))) | (1 << thisobj.Cpin)); OUTA &= ~(1<<thisobj.Dpin); DIRA = ((DIRA & (~(1 << thisobj.Dpin))) | (1 << thisobj.Dpin)); OUTA &= ~(1<<thisobj.Cpin); OUTA = ((OUTA & (~(1 << thisobj.Cpin))) | (1 << thisobj.Cpin)); DIRA &= ~(1<<thisobj.Dpin); OUTA &= ~(1<<thisobj.Cpin); return sensirionSpin_Writebyte(Cmd); } int32_t sensirionSpin_Readword(void) { return ((sensirionSpin_Readbyte(0) << 8) + sensirionSpin_Readbyte(1)); } int32_t sensirionSpin_Readbyte(int32_t Ack) { int32_t result = 0; DIRA &= ~(1<<thisobj.Dpin); { int32_t _idx__0005; for(_idx__0005 = 1; _idx__0005 <= 8; (_idx__0005 = (_idx__0005 + 1))) { result = ((result << 1) | ((INA >> thisobj.Dpin) & 0x1)); OUTA ^= (1<<thisobj.Cpin); OUTA ^= (1<<thisobj.Cpin); } } DIRA = ((DIRA & (~(1 << thisobj.Dpin))) | (1 << thisobj.Dpin)); OUTA = ((OUTA & (~(1 << thisobj.Dpin))) | ((Ack & 0x1) << thisobj.Dpin)); OUTA ^= (1<<thisobj.Cpin); OUTA ^= (1<<thisobj.Cpin); DIRA &= ~(1<<thisobj.Dpin); return result; } int32_t sensirionSpin_Writebyte(int32_t Value) { int32_t result = 0; Value = (0xffffffff ^ Value); OUTA &= ~(1<<thisobj.Dpin); { int32_t _idx__0006; for(_idx__0006 = 1; _idx__0006 <= 8; (_idx__0006 = (_idx__0006 + 1))) { DIRA = ((DIRA & (~(1 << thisobj.Dpin))) | (((Shr__(Value, 7)) & 0x1) << thisobj.Dpin)); Value = (Value << 1); OUTA ^= (1<<thisobj.Cpin); OUTA ^= (1<<thisobj.Cpin); } } DIRA &= ~(1<<thisobj.Dpin); result = ((INA >> thisobj.Dpin) & 0x1); OUTA ^= (1<<thisobj.Cpin); OUTA ^= (1<<thisobj.Cpin); return result; } int32_t sensirionSpin_Wait(void) { int32_t T; T = CNT; while (!(!((((INA >> thisobj.Dpin) & 0x1)) || (((CNT - T) / (CLKFREQ / 1000)) > 250)))) { Yield__(); } return 0; }seisirion.h
// // automatically generated by spin2cpp v1.03 on Sat May 11 07:56:31 2013 // spin2cpp --ccode sensirion.spin // #ifndef sensirionSpin_Class_Defined__ #define sensirionSpin_Class_Defined__ #include <stdint.h> #define Cmd_temperature (3) #define Cmd_humidity (5) #define Cmd_readstatus (7) #define Cmd_writestatus (6) #define Cmd_reset (30) #define Hires (0) #define Lores (1) #define Off (0) #define On (1) #define Yes (0) #define No (1) typedef struct sensirionSpin { int32_t Tc; uint16_t Dpin, Cpin; char dummy__; } sensirionSpin; int32_t sensirionSpin_Start(int32_t Data_pin, int32_t Clock_pin); int32_t sensirionSpin_Config(int32_t Volt, int32_t Heater, int32_t Otpreload, int32_t Measres); int32_t sensirionSpin_Gettemperaturec(void); int32_t sensirionSpin_Gettemperaturef(void); int32_t sensirionSpin_Gethumidity(void); int32_t sensirionSpin_Readtemperature(void); int32_t sensirionSpin_Readhumidity(void); int32_t sensirionSpin_Readstatus(void); int32_t sensirionSpin_Writestatus(int32_t N); int32_t sensirionSpin_Reset(void); #endif