From this forum, I copied the code shown below, to try to get printf() or kin to work on Teensy3 latest.
though Serial.print works OK to the USB virtual serial COM port, using the code below causes the CPU to crash/reset.
I also tried a version of printf() in C that I have. It doesn't work right either. It is all standalone code; doesn't use stdio.h or the va_list and others.
My kingdom for printf() !! (no floats needed).
This code seems of AVR vintage, rather than T3, but anyway...
With apologies for the length, here's the stand-alone printf() that doesn't work right. I suspect it's a GCC command line option that's not in Arduino, considering how stack frames are built, w.r.t. how the variable length arg list is handled by the compiler as setup by Arduino's IDE.
sorry for the length...Maybe this code is useful to someone else... the printf() and sprintf() are near the end. I renamed them kprintf() because printf() conflicts with the GCC compiler defaults - there needs to be a command line option invoked, something like -no-printf is what I've used on other systems.
though Serial.print works OK to the USB virtual serial COM port, using the code below causes the CPU to crash/reset.
I also tried a version of printf() in C that I have. It doesn't work right either. It is all standalone code; doesn't use stdio.h or the va_list and others.
My kingdom for printf() !! (no floats needed).
This code seems of AVR vintage, rather than T3, but anyway...
Code:
/*
vsnprintf() test sketch for Teensy3
Jan 2, 2013
*/
#undef __STRICT_ANSI__
#ifdef ARDUINO
#if (ARDUINO >= 100)
#include <Arduino.h>
#else
#include <WProgram.h>
#endif
#endif
#include<stdio.h>
#include<stdarg.h>
#define FPRINTF_BUFSZE 256
char buf[FPRINTF_BUFSZE];
void serial_out_len(int len,char* b)
{
b[len] = 0; // null terminate string
Serial.print(b);
}
int test_vsnprintf(const char format[],...)
{
// program memory version of printf - copy of format string and result share a buffer
// so as to avoid too much memory use
char *fptr, *rptr;
int rlen = sizeof(buf);
// buf just used for result string
fptr = (char *)&format[0];
rptr = &buf[0];
va_list args;
va_start (args,format);
int len = vsnprintf(rptr, rlen, fptr, args );
va_end (args);
serial_out_len(len,rptr);
return len;
}
With apologies for the length, here's the stand-alone printf() that doesn't work right. I suspect it's a GCC command line option that's not in Arduino, considering how stack frames are built, w.r.t. how the variable length arg list is handled by the compiler as setup by Arduino's IDE.
sorry for the length...Maybe this code is useful to someone else... the printf() and sprintf() are near the end. I renamed them kprintf() because printf() conflicts with the GCC compiler defaults - there needs to be a command line option invoked, something like -no-printf is what I've used on other systems.
Code:
void printchar(char **str, int ch)
{
//extern int putchar(int c);
if (str) { // if str is not null, store ch into that buffer as in sprintf()
**str = ch;
++(*str);
}
else
Serial.write((char)ch); //CHAR_OUT(ch);
//(void)uart0Putch(ch);
}
#define PAD_RIGHT 1
#define PAD_ZERO 2
int prints(char **out, const char *string, int width, int pad)
{
int pc = 0, padchar = ' ';
int len = 0;
const char *ptr;
if (width > 0) {
for (ptr = string; *ptr; ++ptr) ++len;
if (len >= width) width = 0;
else width -= len;
if (pad & PAD_ZERO) padchar = '0';
}
if (!(pad & PAD_RIGHT)) {
for ( ; width > 0; --width) {
printchar (out, padchar);
++pc;
}
}
for ( ; *string ; ++string) {
printchar (out, *string);
++pc;
}
for ( ; width > 0; --width) {
printchar (out, padchar);
++pc;
}
return pc;
}
/* the following should be enough for 32 bit int */
#define PRINT_BUF_LEN 12
int printi(char **out, int i, int b, int sg, int width, int pad, int letbase)
{
char print_buf[PRINT_BUF_LEN];
register char *s;
register int t, neg = 0, pc = 0;
register unsigned int u = i;
if (i == 0) {
print_buf[0] = '0';
print_buf[1] = '\0';
return prints (out, print_buf, width, pad);
}
if (sg && b == 10 && i < 0) {
neg = 1;
u = -i;
}
s = print_buf + PRINT_BUF_LEN-1;
*s = '\0';
while (u) {
t = u % b;
if( t >= 10 )
t += letbase - '0' - 10;
*--s = t + '0';
u /= b;
}
if (neg) {
if( width && (pad & PAD_ZERO) ) {
printchar (out, '-');
++pc;
--width;
}
else {
*--s = '-';
}
}
return pc + prints (out, s, width, pad);
}
int print(char **out, int *varg)
{
int width, pad;
int pc = 0;
char *format = (char *)(*varg++);
char scr[2];
for (; *format != 0; ++format) {
if (*format == '%') {
++format;
width = pad = 0;
if (*format == '\0') break;
if (*format == '%') goto out;
if (*format == '-') {
++format;
pad = PAD_RIGHT;
}
while (*format == '0') {
++format;
pad |= PAD_ZERO;
}
for ( ; *format >= '0' && *format <= '9'; ++format) {
width *= 10;
width += *format - '0';
}
if( *format == 's' ) {
register char *s = *((char **)varg++);
pc += prints (out, s?s:"(null)", width, pad);
continue;
}
if( *format == 'd' ) {
pc += printi (out, *varg++, 10, 1, width, pad, 'a'); // can be signed
continue;
}
if( *format == 'x' ) {
pc += printi (out, *varg++, 16, 0, width, pad, 'a');
continue;
}
if( *format == 'X' ) {
pc += printi (out, *varg++, 16, 0, width, pad, 'A');
continue;
}
if( *format == 'u' ) {
pc += printi (out, *varg++, 10, 0, width, pad, 'a'); // unsigned int
continue;
}
if( *format == 'c' ) {
/* char are converted to int then pushed on the stack */
scr[0] = *varg++;
scr[1] = '\0';
pc += prints (out, scr, width, pad);
continue;
}
}
else {
out:
printchar (out, *format);
++pc;
}
}
if (out) **out = '\0';
return pc;
}
/* assuming sizeof(void *) == sizeof(int) */
int kprintf(const char *format, ...)
{
int *varg = (int *)(&format);
return print(0, varg); // 0 means stdout
}
int ksprintf(char *out, const char *format, ...)
{
int *varg = (int *)(&format);
return print(&out, varg);
}
#define TEST_PRINTF
#ifdef TEST_PRINTF
int testPrintf(void)
{
char *ptr = "Hello world!";
char *np = 0;
int i = 5;
unsigned int bs = sizeof(int)*8;
unsigned int x = 0x40000500;
int mi;
mi = (1 << (bs-1)) + 1;
kprintf("%s\n", ptr);
kprintf("printf test\n");
kprintf("%s is null pointer\n", np);
kprintf("%d = 5\n", i);
kprintf("%d = - max int\n", mi);
kprintf("char %c = 'a'\n", 'a');
kprintf("hex %x = fff\n", 0xfff);
kprintf("hex addr %x\n", x);
kprintf("hex %02x = 00\n", 0);
kprintf("hex %X = 0xABCDEF\n", 0xABCDEF);
kprintf("signed %d = unsigned %u = hex %x\n", -3, -3, -3);
kprintf("%d %s(s)%", 0, "message");
kprintf("\n");
kprintf("%d %s(s) with %%\n", 0, "message");
ksprintf(buf, "justif: \"%-10s\"\n", "left"); kprintf("%s", buf);
ksprintf(buf, "justif: \"%10s\"\n", "right"); kprintf("%s", buf);
ksprintf(buf, " 3: %04d zero padded\n", 3); kprintf("%s", buf);
ksprintf(buf, " 3: %-4d left justif.\n", 3); kprintf("%s", buf);
ksprintf(buf, " 3: %4d right justif.\n", 3); kprintf("%s", buf);
ksprintf(buf, "-3: %04d zero padded\n", -3); kprintf("%s", buf);
ksprintf(buf, "-3: %-4d left justif.\n", -3); kprintf("%s", buf);
ksprintf(buf, "-3: %4d right justif.\n", -3); kprintf("%s", buf);
return 0;
}
/*
* if you compile this file with
* gcc -Wall $(YOUR_C_OPTIONS) -DTEST_PRINTF -c printf.c
* you will get a normal warning:
* printf.c:214: warning: spurious trailing `%' in format
* this line is testing an invalid % at the end of the format string.
*
* this should display (on 32bit int machine) :
*
* Hello world!
* printf test
* (null) is null pointer
* 5 = 5
* -2147483647 = - max int
* char a = 'a'
* hex ff = ff
* hex 00 = 00
* signed -3 = unsigned 4294967293 = hex fffffffd
* 0 message(s)
* 0 message(s) with %
* justif: "left "
* justif: " right"
* 3: 0003 zero padded
* 3: 3 left justif.
* 3: 3 right justif.
* -3: -003 zero padded
* -3: -3 left justif.
* -3: -3 right justif.
*/
//#ifdef __cplusplus
//}
//#endif
#endif
Last edited: