Please comment on my code. I'm I "getting" it ?
Bean
Posts: 8,129
Here is a small library of code I'm working on.
I think I've gotten my head around this C stuff, but I'd like you comments.
Library "stuff.c"
Main code for SimpleIDE "test.c"
Thanks,
Bean
I think I've gotten my head around this C stuff, but I'd like you comments.
Library "stuff.c"
/*
high(value) - Makes pin an output and high
low(value) - Makes pin an output and low
input(value) - Makes pin an input
output(value) - Makes pin an output
pausems(value) - Pause for "value" milliseconds
serinit(pin, baud) - Setup serial parameters
serout(byte) - Send a byte to serial pin
serstr(string) - Send a string to serial pin
serint(value) - Send an integer converted to ascii to the serial pin
*/
#ifndef _PROPELLER_H_
#include <propeller.h>
#endif
#ifndef _STUFF_C_
#define _STUFF_C_
long int _serPinMask = 1 << 30;
long int _serBaudCnt = 19200;
void high(int given) {
given = 1 << given; // Create bit mask
DIRA |= given; // Make pin an output
OUTA |= given; // Make pin high
}
void low(int given) {
given = 1 << given; // Create bit mask
DIRA |= given; // Make pin an output
OUTA &= ~given; // Make pin low
}
void input(int given) {
DIRA &= ~(1 << given); // Make pin an input
}
void output(int given) {
DIRA |= 1 << given; // Make pin an output
}
void pausems(long int given) {
if (given > 0) waitcnt(CNT + (CLKFREQ / 1000) * given); // Wait "given" milliseconds
}
void serinit(int g_serPin, long int g_serBaud) {
_serPinMask = 1 << g_serPin; // Remember pin mask
_serBaudCnt = CLKFREQ / g_serBaud; // Remember baud rate
DIRA |= _serPinMask; // Make pin an output
OUTA |= _serPinMask; // Make pin high
}
void serout(char given) {
// Serial LCD character output
int temp = (given << 1) + 512; // bit 0=start bit(0), bit9=stop bit(1)
long int tempcnt;
tempcnt = CNT + _serBaudCnt; // Setup for waitcnt
int i;
for (i=0; i < 10; i++) { // Sending 10 bits (start, 8-data, stop)
if ((temp & 1) == 1) { // Send bit in bit0 position
OUTA |= _serPinMask;
} else {
OUTA &= ~_serPinMask;
} // if
tempcnt = waitcnt2(tempcnt, _serBaudCnt); // Bit delay
temp >>= 1; // Shift to get next bit in bit0 position
} // for i
} // serout
void serstr(const char *given) {
while (*given != 0) serout(*given++); // Send characters until zero
} // serstr
void serint(long int given) {
if (given < 0) { // Check if negative value
given = -given; // Use abs if negative
serout('-'); // Emit a "-" if negative
}
int sum = 0; // Sum of digits (used to emit leading spaces)
char temp = '0'; // current digit
// Must do highest digit as a special case because it can only be 0-4
while (given >= 1000000000) {
given -= 1000000000;
temp++;
sum++;
}
if (sum > 0) serout(temp); // If is's not zero, emit it
// Do rest of digits the same way
int i;
for (i = 0; i < 9; i++) {
char temp = '0';
while (given >= 100000000) {
given -= 100000000;
temp++;
sum++;
}
if ((sum > 0) || (i == 8)) serout(temp); // If last digit(i==8) always emit
given *= 10;
} // for i
} // serint
#endif // ifndef _STUFF_C_
Main code for SimpleIDE "test.c"
#include "stuff.c"
void main(void)
{
pausems(1000);
serinit(30, 115200); // Setup for SimpleIDE terminal
pausems(10); // Give pin time to settle
serstr("Here we go...\n");
pausems(1000);
int i;
for (i=0; i < 100; i++) {
serint(i);
serout(10);
} // for i
serstr("All done...\n");
} // main
Thanks,
Bean

Comments
When I view the assembly for the test.c code it contains functions that are never called.
I though the compiler would strip those out ?
Is there any way to make it strip them out ?
Bean
I did some searching and found that if I prefix the function with "static" then they do get stripped out like I wanted.
Bean
Anyway, I'm glad to hear you're making so much progress learning GCC!
I would probably structure the project a little differently.
That is add stuff.c to the project rather than including it in test.c.
Also by doing that you don't need to add the #ifdef ... #define ... #endif block in stuff.c
The propeller.h include already has a #ifdef ... #define ... #endif block.
Here's an improvement on serout() ... What you have is very close.
The difference is placement of the tempcnt bit delay calculation.
This one works with the 115200 terminal.
void serout(char given) { // Serial LCD character output int i; int temp = (given << 1) + 512; // bit 0=start bit(0), bit9=stop bit(1) long int tempcnt; tempcnt = CNT + _serBaudCnt; // Setup for waitcnt for (i=0; i < 10; i++) { // Sending 10 bits (start, 8-data, stop) tempcnt = waitcnt2(tempcnt, _serBaudCnt); // Bit delay if ((temp & 1) == 1) { // Send bit in bit0 position OUTA |= _serPinMask; } else { OUTA &= ~_serPinMask; } // if temp >>= 1; // Shift to get next bit in bit0 position } // for i } // seroutI changed your test.c slightly to get this output.
void main(void) { pausems(1000); serinit(30, 115200); // Setup for SimpleIDE terminal pausems(10); // Give pin time to settle serstr("Here we go...\n"); pausems(1000); int i; for (i=1; i <= 100; i++) { serint(i); serout(' '); if((i % 10) == 0) serout('\n'); } // for i serstr("All done...\n"); } // mainWith that, there are implementations of Printf, simple serial (inline serial like above) and full duplex serial (cog based), as well as DOS FAT filesystem support
I'm mentioning this because I am hoping that we can encourage more code reuse than in the past. It seems that OBEX is incredibly fragmented and has a lot of redundant code because of the fragmentation and lack of moderation or stewardship.
I love to see Bean contributing. My first Propeller project was to port the Arduino runtime to SPIN so Arduinites could have a familiar set of functions. It's funny because much of that same high level code is being rewritten here.
I *might* suggest starting with the Arduino SDK and porting their code to run on the Propeller with PGCC, it is license compatible and would save a lot of debugging effort. Obviously there are some significant architectural differences between the AVR and Propeller, but much of the SDK is agnostic and does things /the hard way/,in software
Oh, another thing to point out, with GCC, you can take advantage of a lot of optimizations that SPIN can't do. When implementing many of the pin/bit functions, you layer function calls for code compactness, but in SPIN you lose performance. In GCC you can gain that performance back by inlining functions, so the multiple stack frames get smashed, effectively reiterating the same code, but with the high level source management.