Loading...
 

SW4STM32 and SW4Linux fully supports the STM32MP1 asymmetric multicore Cortex/A7+M4 MPUs

   With System Workbench for Linux, Embedded Linux on the STM32MP1 family of MPUs from ST was never as simple to build and maintain, even for newcomers in the Linux world. And, if you install System Workbench for Linux in System Workbench for STM32 you can seamlessly develop and debug asymmetric applications running partly on Linux, partly on the Cortex-M4.
You can get more information from the ac6-tools website and download (registration required) various documents highlighting:

System Workbench for STM32


Redirecting printf with a custom, non-global, callback

On an AVR microcontroller, I do this:

int printCHAR(char character, FILE *stream)
{
BOARD_TypeDef_t* udata = (BOARD_TypeDef_t*) fdev_get_udata(stream);
display_write(&udata->display[displayA], character);
return 0;
}

void main()
{
/* Declare BOARD typedef. */
BOARD_TypeDef_t board;

/* Initialize BOARD typedef. */
board_init(&board);

/* Initialize display */
display_init(&board.display[displayA]);

FILE uart_str = FDEV_SETUP_STREAM(printCHAR, NULL, _FDEV_SETUP_RW);
fdev_setup_stream(&uart_str, printCHAR, NULL, _FDEV_SETUP_RW);
fdev_set_udata(&uart_str, &board);
stdout = &uart_str;

printf(“%s”, “ABC”);
}

This prints the letters “ABC” on the memory lcd via the display_write function in printCHAR, with the non-global parameter &udata->display[displayA].

I’d like to achieve something similar on an STM32 microcontroller (on the G071RB Nucleo board) to which an spi display is attached. The FDEV set of functions appear to be customized, lightweight workarounds for the avr-libc library and are hence unavailable for STM32 processors.

For now, my main on the STM32 looks something like this:

void main(void)
{
/* Declare BOARD typedef. */
BOARD_TypeDef_t board;

/* Initialize BOARD typedef. */
board_init(&board);

/* Initialize display */
display_init(&board.display[displayA]);

/* Writes a “B” to the display */
display_write(&board.display[displayA], 0x42);
}

What I would like to do is to use my display_write function and the display destination in a retargetted printf.

The options I have seen are:

1. Using __io_putchar function: This is available to be externed from the syscalls.c file. However, the only parameter it takes is the character to be printed, so I’m not sure and don’t think I can get my BOARD_TypeDef_t in there.

2. Using write function: This is available in the syscalls.c file. However, I would rather use this the canonical way via __io_putchar and not by directly editing the write function.

3. Using fopencookie: I think this is the way I would like to do this but I’m having some difficulty, with my cookie_write_function_t function defined inside of the cookie_io_functions_t array of functions not getting called at all but rather getting fwrite being called instead. That quickly degenerates into nothing getting printed to the spi display. However, subsequent calls via the display_write primitive do continue to print to the spi display.

Also, it would be good to know if this could be achieved perhaps with fputc or some other way.

Any ideas of what I might be doing wrong, or guidance on how I might do this right, are appreciated.

Regards,
J

France

Hi,

The simplest way to go is through __io_putchar that you can define, e.g. in the file in which you place the display initialization code, as it is declared as weak in syscalls.c. To print on your display you can write it as
int __io_putchar(char c) {
    return display_write(&board.display[displayA], c); 
}

For this to work, of course, you must declare the board variable as a global static variable (not in the display initialization function) and move the display_init (and perhaps board_init) call in the display initialization function.

Then any printf/write with go to your display

HTH

Bernard (Ac6)

Hi,

Thanks for the suggestion.

A key requirement is that there are no global variables and this proposal suggests one. Thanks.

Regards,
J


After a bit of investigating, I found a workable solution.

The full post is here, including an image of the final product: https://zfembedded.wordpress.com/2020/02/27/redirecting-printf-on-stm32-using-fopencookie/Question

Starting with the basic program that prints a “B” to the screen, I did the following:

1. The fopencookie function is in stdio.h so this needs to be included.
2. In order to activate it, _GNU_SOURCE must be defined before this include.
3. We create a stream for our display, my_stream0. We can also create one for stdout.
4. The fopencookie function needs cookie_io_functions so we define them. These don’t appear to participate in the action but without them things don’t work for me. Hints on why this is so are helpful.
5. We write out the function for a component of the cookie_io_functions, in this case for .write. For me, this function need not do anything.
6. We write the stream write function.
7. We pass the stream write function and the board definition to the streams defined.
8. We modify the buffering of the streams.
9. We test out both fprintfs and the printf of the created streams.

/* 2 */
#define _GNU_SOURCE
        
/* 1 */
#include <stdio.h>

/* 5 */
static ssize_t dummy_cookie_write(void *c, const char *buf, size_t size)
{
    return size;
}
    
/* 6 */
int displayA_stream_write(struct _reent *q1, void *q2, const char *q3, int q4)
{
    (void)q1;
    BOARD_TypeDef_t* q5 = (BOARD_TypeDef_t*)q2;
    
    int DataIdx;
    
    for (DataIdx = 0; DataIdx < q4; DataIdx++)
    {
    	display_write(&q5->display[displayA], *q3++);
    }
    
    return q4;
}
    
void main(void)
{
    /* Declare BOARD typedef. */
    BOARD_TypeDef_t board;
    
    /* Initialize BOARD typedef. */
    board_init(&board);
    
    /* Initialize display */
    display_init(&board.display[displayA]);
    
    /* Writes a "B" to the display */
    display_write(&board.display[displayA], 0x42);
    
    /* 4 */
    cookie_io_functions_t dummy_cookie_funcs = {
            .read  = 0,
            .write = dummy_cookie_write, /* Setting this to 0 breaks the solution. */
            .seek  = 0,
            .close = 0
            };
    
    /* 3 */
    FILE *my_stream0 = fopencookie(NULL,"w", dummy_cookie_funcs); /* Replacing dummy_cookie_funcs with NULL breaks the solution. */
    stdout = fopencookie(NULL,"w", dummy_cookie_funcs);
    
    /* 8 */
    setbuf(my_stream0, NULL);
    setbuf(stdout, NULL);
    
    /* 7 */
    my_stream0->_write = displayA_stream_write;
    my_stream0->_cookie = (void *)&board;
    stdout->_write = displayA_stream_write;
    stdout->_cookie = (void *)&board;
    
    /* 9 */
    fprintf(my_stream0, "\nNowhere");
    fprintf(stdout, "\nSomewhere");
    printf("\nHere");
    
}


The key find that made this all possible was finding out that #7 write was more important than #4 write.

Regards,
J