User Tools

Site Tools


img_20180519_161315-cut-640.jpg

FreeRTOS STM32-F407 OpenCM3

https://github.com/onborodin/stm32-f4-freertos-opencm3

Code based on FreeRTOS v10, opencm3 and STM32F407 MCU

Released

  1. FSMC bus inteface w register tools
  2. ILI934 based console over FSMC bus
  3. USART buffered interface
  4. newlib minimal syscalls
  5. Board RTC timer driver
  6. Random generator driver
  7. XPT2060 touchscreen driver over SPI
  8. Pen button IRQ handler
  9. ADC one-time and regural w/wo DMA

No guarantees. This code is given only as an sample.

But must work good. =) I try to publish a good code.

Makefile

Makefile
#
# Author, Copyright: Oleg Borodin <onborodin@gmail.com> 2018
#
.SECONDARY:
 
RTOS_LOC = RTOS
 
CFLAGS+= -I. -Os -DSTM32F4 -std=c99
CFLAGS+= -mthumb -march=armv7e-m
CFLAGS+= -mfloat-abi=hard -mfpu=fpv4-sp-d16
CFLAGS+= -mcpu=cortex-m4
CFLAGS+= -fno-common -ffunction-sections -fdata-sections
CFLAGS+= -g -gdwarf-2
CFLAGS+= -I${RTOS_LOC}
 
 
LDFLAGS+= ${CFLAGS}
LDFLAGS+= --static
LDFLAGS+= -nostartfiles
LDFLAGS+= -T master.ld
 
LDFLAGS+= -Wl,-Map=master.map
LDFLAGS+= -Wl,--cref -Wl,--gc-sections
LDFLAGS+= -Wl,--start-group -lc -lm -lgcc -lnosys -Wl,--end-group
LDFLAGS+= -lopencm3_stm32f4
LDFLAGS+= -L${RTOS_LOC} -lrtos
 
 
RTOS_OBJS+= $(RTOS_LOC)/croutine.o
RTOS_OBJS+= $(RTOS_LOC)/event_groups.o
RTOS_OBJS+= $(RTOS_LOC)/heap_3.o
RTOS_OBJS+= $(RTOS_LOC)/list.o
RTOS_OBJS+= $(RTOS_LOC)/port.o
RTOS_OBJS+= $(RTOS_LOC)/queue.o
RTOS_OBJS+= $(RTOS_LOC)/stream_buffer.o
RTOS_OBJS+= $(RTOS_LOC)/tasks.o
RTOS_OBJS+= $(RTOS_LOC)/timers.o
 
MASTER_OBJS+= master.o 
MASTER_OBJS+= syscall.o
MASTER_OBJS+= buffer.o
MASTER_OBJS+= uastdio.o
 
MASTER_OBJS+= fsmcwr.o
MASTER_OBJS+= ili9341.o
MASTER_OBJS+= console.o
MASTER_OBJS+= random.o
MASTER_OBJS+= rtc4xx.o
MASTER_OBJS+= xpt2046.o
MASTER_OBJS+= opencm3.o
 
 
all: rtos master.bin
 
rtos:  $(RTOS_LOC)/librtos.a
 
${RTOS_OBJS}: FreeRTOSConfig.h
 
$(RTOS_LOC)/librtos.a: $(RTOS_OBJS)
	cd $(@D) && arm-eabi-ar rcv $(@F) $(^F)
 
master.elf: $(MASTER_OBJS)
	arm-eabi-gcc $(^F) $(LDFLAGS) -o $@ 
	arm-eabi-size --format=berkeley $@
 
%.o: %.c
	arm-eabi-gcc $(CFLAGS) -c -o $@ $<
 
%.o: %.S
	arm-eabi-as $(ASFLAGS) -o $@ $<
 
%.bin: %.elf
	arm-eabi-objcopy -O binary $< $@
 
%.elf: %.o
	arm-eabi-gcc $(^F) $(LDFLAGS) -o $@ 
	arm-eabi-size --format=berkeley $@
 
clean:
	rm -f *.i *.o *.elf *.bin *.map *~ *.hex *.d *.s
	cd $(RTOS_LOC) && rm -f *.o *.d *~ lib*.a
 
upload: all master.upl
 
%.upl: %.bin
	@openocd \
	    -c 'puts "--- START --------------------"' \
	    -f 'interface/stlink-v2.cfg' \
	    -f 'target/stm32f4x.cfg'  \
	    -c 'puts "--- INIT --------------------"' \
	    -c "init" \
	    -c "reset halt" \
	    -c 'puts "--- WRITE --------------------"' \
	    -c "flash write_image erase $< 0x08000000"\
	    -c 'puts "--- VERIFY --------------------"' \
	    -c "verify_image $<" \
	    -c 'puts "--- RESET --------------------"' \
	    -c "reset" \
	    -c 'puts "--- DONE --------------------"' \
	    -c "shutdown"
 
debug:
	@openocd \
	    -c 'puts "--- START --------------------"' \
	    -f 'interface/stlink-v2.cfg' \
	    -f 'target/stm32f4x.cfg'  \
	    -c 'puts "--- INIT --------------------"' \
	    -c "init" \
	    -c "halt" \
	    -c "poll"
#EOF

adc-dma.c

adc-dma.c
volatile static uint16_t adc_res[17];
 
void adc1_setup(void) {
 
    static uint8_t channel_seq[16];
 
    gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO0);
    gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO1);
 
    adc_set_clk_prescale(ADC_CCR_ADCPRE_BY2);
 
    //adc_power_off(ADC1);
 
    adc_enable_scan_mode(ADC1);
    adc_set_continuous_conversion_mode(ADC1);
    adc_disable_discontinuous_mode_regular(ADC1);
 
    //adc_enable_temperature_sensor();
 
    adc_enable_external_trigger_regular(ADC1, ADC_CR2_SWSTART, ADC_CR2_EXTEN_DISABLED);
    adc_set_right_aligned(ADC1);
    adc_set_sample_time_on_all_channels(ADC1, ADC_SMPR_SMP_28CYC);
    adc_set_resolution(ADC1, 8);
 
 
    channel_seq[0] = ADC_CHANNEL0;
    channel_seq[1] = ADC_CHANNEL1;
 
    adc_set_multi_mode(ADC_CCR_MULTI_INDEPENDENT);
 
    adc_set_regular_sequence(ADC1, 1, channel_seq);
    adc_enable_dma(ADC1);
 
    adc_power_on(ADC1);
 
    adc_start_conversion_regular(ADC1);
}
 
/*** DMA2 ***/
static void dma2_setup(void) {
 
    dma_stream_reset(DMA2, DMA_STREAM4);
    dma_set_priority(DMA2, DMA_STREAM4, DMA_SxCR_PL_LOW);
 
    dma_set_memory_size(DMA2, DMA_STREAM4, DMA_SxCR_MSIZE_16BIT);
    dma_set_peripheral_size(DMA2, DMA_STREAM4, DMA_SxCR_PSIZE_16BIT);
 
    dma_enable_memory_increment_mode(DMA2, DMA_STREAM4);
    dma_enable_circular_mode(DMA2, DMA_STREAM4);
 
    dma_set_transfer_mode(DMA2, DMA_STREAM4, DMA_SxCR_DIR_PERIPHERAL_TO_MEM);
    dma_set_peripheral_address(DMA2, DMA_STREAM4, (uint32_t) & ADC_DR(ADC1));
    dma_set_memory_address(DMA2, DMA_STREAM4, (uint32_t) &adc_res);
    dma_set_number_of_data(DMA2, DMA_STREAM4, 1);
 
 
    dma_channel_select(DMA2, DMA_STREAM4, DMA_SxCR_CHSEL_0);
 
    //nvic_enable_irq(NVIC_DMA2_STREAM4_IRQ);
    //dma_enable_transfer_complete_interrupt(DMA2, DMA_STREAM4);
    dma_enable_stream(DMA2, DMA_STREAM4);
}
 
void dma2_stream4_isr(void) {
    //dma_clear_interrupt_flags(DMA2, DMA_CHANNEL4, DMA_IFCR_CGIF1);
}
 
void dma2_stream0_isr(void) {
    //dma_clear_interrupt_flags(DMA2, DMA_CHANNEL4, DMA_IFCR_CGIF1);
}
 
 
float get_mcu_temp(void) {
    float temp;
    temp = adc_res[0];  //((((adc_res[2] * 3300.0f) / 0xFFF) / 1000.0f) - 0.760f) / .0025f;
    return temp;
}

buffer.c

buffer.c
/* Author, Copyright: Oleg Borodin <onborodin@gmail.com> 2018 */
 
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
 
#include <buffer.h>
 
void buffer_init(buffer_t * buffer, uint8_t * data, uint16_t length) {
    if (buffer && buffer) {
        memset((void **)buffer, 0, length);
        buffer->length = length;
        buffer->data = data;
        buffer->head = 0;
        buffer->tail = 0;
    }
}
 
uint16_t buffer_count(const buffer_t * buffer) {
    if (buffer) {
        return (buffer->head - buffer->tail);
    }
    return 0;
}
 
bool buffer_full(const buffer_t * buffer) {
    if (buffer) {
        return (buffer_count(buffer) == buffer->length);
    }
    return true;
}
 
bool buffer_empty(const buffer_t * buffer) {
    if (buffer) {
        return (buffer_count(buffer) == 0);
    }
    return true;
}
 
uint16_t buffer_peek(const buffer_t * buffer) {
    uint8_t data = 0;
 
    if (!buffer_empty(buffer)) {
        data = buffer->data[buffer->tail % buffer->length];
    }
    return data;
}
 
bool buffer_back(buffer_t * buffer) {
    if (!buffer_empty(buffer)) {
        buffer->head--;
        return true;
    }
    return false;
}
 
uint8_t buffer_get_byte(buffer_t * buffer) {
    uint8_t data = 0;
 
    if (!buffer_empty(buffer)) {
        data = buffer->data[buffer->tail % buffer->length];
        buffer->tail++;
    }
    return data;
}
 
bool buffer_put_byte(buffer_t * buffer, uint8_t data) {
    bool status = false;
 
    if (buffer) {
        if (!buffer_full(buffer)) {
            buffer->data[buffer->head % buffer->length] = data;
            buffer->head++;
            status = true;
        }
    }
    return status;
}
 
uint8_t buffer_put_string(buffer_t * buffer, uint8_t * string) {
    if (buffer) {
        for (uint8_t i = 0; i < strlen(string); i++) {
            if (!buffer_put_byte(buffer, string[i]))
                return i;
        }
    }
    return 0;
}
 
bool buffer_scan_byte(buffer_t * buffer, uint8_t c) {
    if (buffer) {
        if (!buffer_empty(buffer)) {
            uint8_t tail = buffer->tail;
 
            for (uint8_t i = 0; i < buffer_count(buffer); i++) {
                uint8_t data = buffer->data[tail % buffer->length];
 
                if (data == c) {
                    return true;
                }
                tail++;
            }
        }
        return false;
    }
    return false;
}
 
uint16_t buffer_get_token(buffer_t * buffer, uint8_t * str, uint16_t len, uint8_t term) {
    if (buffer) {
        memset((void *)str, 0, len);
 
        if (buffer_scan_byte(buffer, term) && str) {
            uint8_t i = 0, c = 0;
 
            while ((c = buffer_get_byte(buffer)) != 0 && c != term && i < len) {
                str[i] = c;
                i++;
            }
            return i;
        }
        return 0;
    }
    return 0;
}
 
/* EOF */

buffer.h

buffer.h
/* Author, Copyright: Oleg Borodin <onborodin@gmail.com> 2018 */
 
#ifndef BUFFER_H_ITU
#define BUFFER_H_ITU
 
typedef struct buffer {
    volatile uint16_t head;
    volatile uint16_t tail;
    volatile uint8_t *data;
    uint16_t length;
} buffer_t;
 
bool buffer_back(buffer_t *buffer);
bool buffer_empty(const buffer_t *buffer);
bool buffer_full(const buffer_t *buffer);
bool buffer_put_byte(buffer_t *buffer, uint8_t data);
bool buffer_scan_byte(buffer_t *buffer, uint8_t c);
 
uint16_t buffer_count(const buffer_t *buffer);
uint16_t buffer_get_token(buffer_t *buffer, uint8_t * str, uint16_t len, uint8_t term);
uint16_t buffer_peek(const buffer_t *buffer);
uint8_t buffer_get_byte(buffer_t *buffer);
uint8_t buffer_put_string(buffer_t *buffer, uint8_t * string);
 
void buffer_init(buffer_t *buffer, uint8_t * data, uint16_t length);
 
#endif
/* EOF */

console.c

console.c
/* Author, Copyright: Oleg Borodin <onborodin@gmail.com> 2018 */
 
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
 
#include <ili9341.h>
#include <console.h>
#include <font8x14.h>
 
font_t basefont = {
    .width = 8,
    .height = 14,
    .start = 0, //32,
    .length = 255, //0x5F,
    .bitmap = basefont_bitmap
};
 
console_t console = {
    .width = CONSOLE_WIDTH,
    .height = CONSOLE_HEIGHT,
    .line = 0,
    .row = 0,
    .xmax = LCD_WIDTH,
    .ymax = LCD_HEIGHT,
    .xshift = 0,
    .yshift = 0,
    .font = &basefont,
};
 
void _console_setup(console_t *console, uint16_t xmax, uint16_t ymax, font_t *font) {
    console->xmax = xmax;
    console->ymax = ymax;
    console->font = font;
    console->width = ymax/font->width;
    console->height = ymax/font->height;
    console->buffer_len = console->width * console->height + 1;
    console->buffer = malloc(console->buffer_len);
}
 
void console_setup(void) {
    _console_setup(&console, LCD_WIDTH, LCD_HEIGHT, &basefont);
}
 
void console_render_char(console_t *console, uint8_t line, uint8_t row) {
    uint8_t c = console->buffer[(console->width * line) + row];
    lcd_draw_char(
        (console->xmax - (console->font->height * (line + 1))) + console->yshift,
        (console->font->width * row) + console->xshift,
        console->font, c);
}
 
 
void console_render(console_t *console) {
#if 0
    for (uint8_t line = console->height; line > 0; --line) {
        for (uint8_t row = console->width; row > 0; --row) {
            console_render_char(console, line - 1, row - 1);
        }
    }
#endif
    for (uint8_t line = 0; line < console->height; line++) {
        for (uint8_t row = 0; row < console->width; row++) {
            console_render_char(console, line, row);
        }
    }
}
 
void console_shift(console_t *console) {
    uint16_t i = 0;
    uint16_t pos = console->width * (console->line - 1) + console->row;
    uint16_t end = console->width * console->height;
 
    while (i < (end - console->width)) {
        console->buffer[i] = console->buffer[i + console->width];
        i++;
    }
    while (i < end) {
        console->buffer[i] = ' ';
        i++;
    }
 
    if (console->line > 0) 
        console->line--;
    else 
        console->line = 0;
}
 
void console_putc(console_t *console, uint8_t c) {
 
    if ((console->row + 1) > console->width) {
        console->line++;
        console->row = 0;
    }
 
    if (console->line >= console->height) {
        console_shift(console);
        console_render(console);
    }
    console->buffer[(console->line * console->width) + console->row] = c;
    console_render_char(console, console->line, console->row);
    console->row++;
}
 
int console_puts(console_t *console, uint8_t *str) {
    uint8_t i = 0;
    while (str[i] != 0) {
        console_putc(console, str[i]);
        i++;
    }
    return i;
}
 
void console_render_xychar(console_t *console, uint8_t line, uint8_t row, uint8_t c) {
    lcd_draw_char(
        (console->xmax - (console->font->height * (line + 1))) + console->yshift,
        (console->font->width * row) + console->xshift,
        console->font, c);
}
 
void console_xyputc(console_t *console, uint16_t line, uint16_t row, uint8_t c) {
    if (row < console->width && line < console->height) {
        console_render_xychar(console, line, row, c);
    }
}
 
int console_xyputs(console_t *console, uint16_t line, uint16_t row, uint8_t *str) {
    uint8_t i = 0;
    while (str[i] != 0 && row < console->width && line < console->height) {
        console_render_xychar(console, line, row, str[i]);
        i++;
        row++;
    }
    return i;
}
 
/* EOF */

console.h

console.h
/* Author, Copyright: Oleg Borodin <onborodin@gmail.com> 2018 */
 
 
#ifndef CONSOLE_H_ITU
#define CONSOLE_H_ITU
 
#include <ili9341.h>
 
typedef struct console {
    uint8_t width;
    uint8_t height;
    uint8_t line;
    uint8_t row;
    uint16_t xmax;
    uint16_t ymax;
    uint16_t xshift;
    uint16_t yshift;
    font_t *font;
    uint8_t *buffer;
    uint16_t buffer_len;
} console_t;
 
#define CONSOLE_WIDTH   (LCD_HEIGHT/8)
#define CONSOLE_HEIGHT  (LCD_WIDTH/14)
 
extern console_t console;
 
void _console_setup(console_t *console, uint16_t xmax, uint16_t ymax, font_t *font);
void console_setup(void);
void console_render_char(console_t *console, uint8_t line, uint8_t row);
void console_render(console_t *console);
void console_shift(console_t *console);
void console_putc(console_t *console, uint8_t c);
int console_puts(console_t *console, uint8_t *str);
void console_render_xychar(console_t *console, uint8_t line, uint8_t row, uint8_t c);
void console_xyputc(console_t *console, uint16_t line, uint16_t row, uint8_t c);
int console_xyputs(console_t *console, uint16_t line, uint16_t row, uint8_t *str);
 
#endif

datetime.c

datetime.c
/* Author, Copyright: Oleg Borodin <onborodin@gmail.com> 2018 */
 
#include <stdint.h>
#include <time.h>
 
#include <datetime.h>
 
time_t date_to_unixtime(const struct tm * date) {
    uint32_t year;
    uint32_t mon;
    uint32_t day;
    uint32_t time;
 
    year = date->tm_year;
    mon = date->tm_mon;
    day = date->tm_mday;
 
    /* January and February are counted as months 13 and 14 of the previous year */
    if (mon <= 2) {
        mon += 12;
        year -= 1;
    }
 
    /* Convert years to days */
    time = (365 * year) + (year / 4) - (year / 100) + (year / 400);
    /* Convert months to days */
    time += (30 * mon) + (3 * (mon + 1) / 5) + day;
    /* Unix time starts on January 1st, 1970 */
    time -= 719561;
    /* Convert days to seconds */
    time *= 86400;
    /* Add hours, minutes and seconds */
    time += (3600 * date->tm_hour) + (60 * date->tm_min) + date->tm_sec;
 
    /* Return Unix time */
    return (time_t)time;
}
 
uint8_t day_of_week(uint16_t year, uint8_t mon, uint8_t mday) {
    uint16_t h;
    uint16_t j;
    uint16_t k;
 
    /* January and February are counted as months 13 and 14 of the previous year */
    if (mon <= 2) {
        mon += 12;
        year -= 1;
    }
    /* J is the century */
    j = year / 100;
    /* K the year of the century */
    k = year % 100;
 
    /* Compute H using Zeller's congruence */
    h = mday + (26 * (mon + 1) / 10) + k + (k / 4) + (5 * j) + (j / 4);
 
    /* Return the day of the week */
    return ((h + 5) % 7) + 1;
}
 
void unixtime_to_date(time_t time, struct tm * date) {
    uint32_t a;
    uint32_t b;
    uint32_t c;
    uint32_t d;
    uint32_t e;
    uint32_t f;
 
    /* Negative Unix time values are not supported */
    if (time < 1)
        time = 0;
 
    /* Retrieve hours, minutes and seconds */
    date->tm_sec = time % 60;
    time /= 60;
    date->tm_min = time % 60;
    time /= 60;
    date->tm_hour = time % 24;
    time /= 24;
 
    /* Convert Unix time to date */
    a = (uint32_t) ((4 * time + 102032) / 146097 + 15);
    b = (uint32_t) (time + 2442113 + a - (a / 4));
    c = (20 * b - 2442) / 7305;
    d = b - 365 * c - (c / 4);
    e = d * 1000 / 30601;
    f = d - e * 30 - e * 601 / 1000;
 
    /* January and February are counted as months 13 and 14 of the previous year */
    if (e <= 13) {
        c -= 4716;
        e -= 1;
    } else {
        c -= 4715;
        e -= 13;
    }
 
    /* Retrieve year, month and day */
    date->tm_year = c;
    date->tm_mon = e;
    date->tm_mday = f;
 
    /* Calculate day of week */
    date->tm_wday = day_of_week(c, e, f);
}
 
/* EOF */

datetime.h

datetime.h
/* Author, Copyright: Oleg Borodin <onborodin@gmail.com> 2018 */
 
#ifndef DATETIME_H_ITU
#define DATETIME_H_ITU
 
time_t date_to_unixtime(const struct tm * date);
uint8_t day_of_week(uint16_t year, uint8_t mon, uint8_t mday);
void unixtime_to_date(time_t time, struct tm * date);
 
#endif
/* EOF */

font8x14.h

font8x14.h
/* Author, Copyright: Oleg Borodin <onborodin@gmail.com> 2018 */
 
#ifndef FONT8x14_H
#define FONT8x14_H
 
const uint8_t basefont_bitmap[] = {
 
//   0x72, 0xb5, 0x4a, 0x86,   /* Magic */
//   0x00, 0x00, 0x00, 0x00,   /* Version */
//   0x20, 0x00, 0x00, 0x00,   /* Header size */
//   0x00, 0x00, 0x00, 0x00,   /* Flags */
//   0x00, 0x01, 0x00, 0x00,   /* No. of chars */
//   0x0e, 0x00, 0x00, 0x00,   /* Char length */
//   0x0e, 0x00, 0x00, 0x00,   /* Char width */
//   0x08, 0x00, 0x00, 0x00,   /* Char height */
 
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   /* 0 */
   0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x7e, 0x00, 0x00, 0x00,   /* 1 */
   0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0x7e, 0x00, 0x00, 0x00,   /* 2 */
   0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00,   /* 3 */
   0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,   /* 4 */
   0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,   /* 5 */
...
   0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   /* 253 */
   0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00,   /* 254 */
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   /* 255 */
 
};
 
#endif

FreeRTOSConfig.h

FreeRTOSConfig.h
/* Author, Copyright: Oleg Borodin <onborodin@gmail.com> 2018 */
 
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
 
extern size_t __rtos_heap_size;
extern uint32_t rcc_ahb_frequency;
 
 
#define configMINIMAL_STACK_SIZE        ((unsigned short) 128)
#define configSYSTICK_CLOCK_HZ          (configCPU_CLOCK_HZ / 8) /* fix for vTaskDelay() */
#define configTICK_RATE_HZ              ((TickType_t) 1000)
#define configTOTAL_HEAP_SIZE           ((size_t) __rtos_heap_size)
#define configCPU_CLOCK_HZ              ((unsigned long) rcc_ahb_frequency)
 
#define configIDLE_SHOULD_YIELD         1
#define configMAX_PRIORITIES            5
#define configMAX_TASK_NAME_LEN         5
#define configUSE_16_BIT_TICKS          0
 
 
#define configUSE_COUNTING_SEMAPHORES   1
#define configUSE_MUTEXES               1
#define configUSE_NEWLIB_REENTRANT      1
#define configUSE_PREEMPTION            1
 
#define configUSE_CO_ROUTINES           0
#define configMAX_CO_ROUTINE_PRIORITIES 2
 
#define configUSE_TICK_HOOK             0
#define configUSE_IDLE_HOOK             0
#define configUSE_TRACE_FACILITY        1
 
#define INCLUDE_uxTaskPriorityGet       1
#define INCLUDE_vTaskCleanUpResources   0
#define INCLUDE_vTaskDelay              1
#define INCLUDE_vTaskDelayUntil         1
#define INCLUDE_vTaskDelete             1
#define INCLUDE_vTaskPrioritySet        1
#define INCLUDE_vTaskSuspend            1
 
#define INCLUDE_eTaskGetState                   1
#define INCLUDE_uxTaskGetStackHighWaterMark     1
#define INCLUDE_xQueueGetMutexHolder            1
//#define INCLUDE_xSemaphoreGetMutexHolder INCLUDE_xQueueGetMutexHolder
//#define INCLUDE_xTaskAbortDelay                 0
#define INCLUDE_xTaskGetCurrentTaskHandle       1
#define INCLUDE_xTaskGetHandle                  1
#define INCLUDE_xTaskGetIdleTaskHandle          1
#define INCLUDE_xTaskGetSchedulerState          0
#define INCLUDE_xTaskResumeFromISR              1
#define INCLUDE_xTimerPendFunctionCall          0
 
#define IRQ2NVIC_PRIOR(x)       ((x) << 4)
#define configKERNEL_INTERRUPT_PRIORITY         IRQ2NVIC_PRIOR(15)
#define configMAX_SYSCALL_INTERRUPT_PRIORITY    IRQ2NVIC_PRIOR(5)
 
 
#define configSUPPORT_DYNAMIC_ALLOCATION        1
#define configSUPPORT_STATIC_ALLOCATION         0
 
#define configUSE_TIMERS                        1
#define configTIMER_TASK_PRIORITY               (configMAX_PRIORITIES - 1)
#define configTIMER_QUEUE_LENGTH                32
#define configTIMER_TASK_STACK_DEPTH            configMINIMAL_STACK_SIZE
 
 
#define configGENERATE_RUN_TIME_STATS           1
#define configUSE_TRACE_FACILITY                1
#define portGET_RUN_TIME_COUNTER_VALUE          xTaskGetTickCount
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() /* */
#define configUSE_STATS_FORMATTING_FUNCTIONS    1
 
//#define configAPPLICATION_ALLOCATED_HEAP              0
//#define configASSERT(x)
//#define configASSERT_DEFINED                          0
//#define configCHECK_FOR_STACK_OVERFLOW                0
//#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP         2
//#define configNUM_THREAD_LOCAL_STORAGE_POINTERS       0
//#define configPOST_SLEEP_PROCESSING(x)
//#define configPRE_SLEEP_PROCESSING(x)
//#define configQUEUE_REGISTRY_SIZE                     0U
//#define configUSE_APPLICATION_TASK_TAG                0
//#define configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES     0
//#define configUSE_MALLOC_FAILED_HOOK                  0
//#define configUSE_PORT_OPTIMISED_TASK_SELECTION       0
//#define configUSE_QUEUE_SETS                          0
//#define configUSE_RECURSIVE_MUTEXES                   0
//#define configUSE_STATS_FORMATTING_FUNCTIONS          1
//#define configUSE_TASK_NOTIFICATIONS                  1
//#define configUSE_TICKLESS_IDLE                       0
//#define configUSE_TIME_SLICING                        1
 
#endif
/* EOF */

fsmcwr.c

fsmcwr.c
/* Author, Copyright: Oleg Borodin <onborodin@gmail.com> 2018 */
 
#include <libopencm3/stm32/fsmc.h>
 
void fsmc_write_burst_disable(uint32_t bcr) {
    FSMC_BCR(bcr) &= ~FSMC_BCR_CBURSTRW;
}
 
void fsmc_write_burst_enable(uint32_t bcr) {
    FSMC_BCR(bcr) |= FSMC_BCR_CBURSTRW;
}
 
void fsmc_extended_mode_disable(uint32_t bcr) {
    FSMC_BCR(bcr) &= ~FSMC_BCR_EXTMOD;
}
void fsmc_extended_mode_enable(uint32_t bcr) {
    FSMC_BCR(bcr) |= FSMC_BCR_EXTMOD;
}
 
 
void fsmc_write_disable(uint32_t bcr) {
    FSMC_BCR(bcr) &= ~FSMC_BCR_WREN;
}
void fsmc_write_enable(uint32_t bcr) {
    FSMC_BCR(bcr) |= FSMC_BCR_WREN;
}
 
void fsmc_wait_disable(uint32_t bcr) {
    FSMC_BCR(bcr) &= ~FSMC_BCR_WAITEN;
}
void fsmc_wait_enable(uint32_t bcr) {
    FSMC_BCR(bcr) |= FSMC_BCR_WAITEN;
}
 
 
void fsmc_wait_signal_polarity_low(uint32_t bcr) {
    FSMC_BCR(bcr) &= ~FSMC_BCR_WAITPOL;
}
void fsmc_wait_signal_polarity_high(uint32_t bcr) {
    FSMC_BCR(bcr) |= FSMC_BCR_WAITPOL;
}
 
void fsmc_wrapped_burst_mode_disable(uint32_t bcr) {
    FSMC_BCR(bcr) &= ~FSMC_BCR_WRAPMOD;
}
void fsmc_wrapped_burst_mode_enable(uint32_t bcr) {
    FSMC_BCR(bcr) |= FSMC_BCR_WRAPMOD;
}
 
 
void fsmc_burst_disable(uint32_t bcr) {
    FSMC_BCR(bcr) &= ~FSMC_BCR_BURSTEN;
}
void fsmc_burst_enable(uint32_t bcr) {
    FSMC_BCR(bcr) |= FSMC_BCR_BURSTEN;
}
 
 
void fsmc_wait_timing_configuration_disable(uint32_t bcr) {
    FSMC_BCR(bcr) &= ~FSMC_BCR_WAITEN;
}
void fsmc_wait_timing_configuration_enable(uint32_t bcr) {
    FSMC_BCR(bcr) |= FSMC_BCR_WAITEN;
}
 
void fsmc_address_data_multiplexing_disable(uint32_t bcr) {
    FSMC_BCR(bcr) &= ~FSMC_BCR_MUXEN;
}
void fsmc_address_data_multiplexing_enable(uint32_t bcr) {
    FSMC_BCR(bcr) |= FSMC_BCR_MUXEN;
}
 
void fsmc_memory_bank_enable(uint32_t bcr) {
    FSMC_BCR(bcr) |= FSMC_BCR_MBKEN;
}
 
void fsmc_memory_bank_disable(uint32_t bcr) {
    FSMC_BCR(bcr) &= ~FSMC_BCR_MBKEN;
}
 
void fsmc_set_access_mode(uint32_t bank, uint32_t mode) {
     FSMC_BTR(bank) |= FSMC_BTR_ACCMODx(mode);
}
 
void fsmc_set_data_latency(uint32_t bank, uint32_t lat) {
     FSMC_BTR(bank) |= FSMC_BTR_DATLATx(lat);
}
 
void fsmc_set_clock_divide_ratio(uint32_t bank, uint32_t div) {
     FSMC_BTR(bank) |= FSMC_BTR_CLKDIVx(div);
}
 
void fsmc_set_turnaround_phase_duration(uint32_t bank, uint32_t duration) {
     FSMC_BTR(bank) |= FSMC_BTR_BUSTURNx(duration);
}
 
void fsmc_set_data_phase_duration(uint32_t bank, uint32_t duration) {
     FSMC_BTR(bank) |= FSMC_BTR_DATASTx(duration);
}
 
void fsmc_set_address_hold_phase_duration(uint32_t bank, uint32_t duration) {
     FSMC_BTR(bank) |= FSMC_BTR_ADDHLDx(duration);
}
 
void fsmc_set_address_setup_phase_duration(uint32_t bank, uint32_t duration) {
     FSMC_BTR(bank) |= FSMC_BTR_ADDSETx(duration);
}

fsmcwr.h

fsmcwr.h
/* Author, Copyright: Oleg Borodin <onborodin@gmail.com> 2018 */
 
#ifndef FSMCWR_H
#define FSMCWR_H
 
#define BANK1 0
 
void fsmc_write_burst_disable(uint32_t bcr);
void fsmc_write_burst_enable(uint32_t bcr);
void fsmc_extended_mode_disable(uint32_t bcr);
void fsmc_extended_mode_enable(uint32_t bcr);
void fsmc_write_disable(uint32_t bcr);
void fsmc_write_enable(uint32_t bcr);
void fsmc_wait_disable(uint32_t bcr);
void fsmc_wait_enable(uint32_t bcr);
void fsmc_wait_signal_polarity_low(uint32_t bcr);
void fsmc_wait_signal_polarity_high(uint32_t bcr);
void fsmc_wrapped_burst_mode_disable(uint32_t bcr);
void fsmc_wrapped_burst_mode_enable(uint32_t bcr);
void fsmc_burst_disable(uint32_t bcr);
void fsmc_burst_enable(uint32_t bcr);
void fsmc_wait_timing_configuration_disable(uint32_t bcr);
void fsmc_wait_timing_configuration_enable(uint32_t bcr);
void fsmc_address_data_multiplexing_disable(uint32_t bcr);
void fsmc_address_data_multiplexing_enable(uint32_t bcr);
void fsmc_memory_bank_enable(uint32_t bcr);
void fsmc_memory_bank_disable(uint32_t bcr);
void fsmc_set_access_mode(uint32_t bank, uint32_t mode);
void fsmc_set_data_latency(uint32_t bank, uint32_t lat);
void fsmc_set_clock_divide_ratio(uint32_t bank, uint32_t div);
void fsmc_set_turnaround_phase_duration(uint32_t bank, uint32_t duration);
void fsmc_set_data_phase_duration(uint32_t bank, uint32_t duration);
void fsmc_set_address_hold_phase_duration(uint32_t bank, uint32_t duration);
void fsmc_set_address_setup_phase_duration(uint32_t bank, uint32_t duration);
 
#endif

ili9341.c

ili9341.c
/* $Id$ */
 
#include <stdlib.h>
#include <stdint.h>
 
#include <ili9341.h>
 
#include <FreeRTOS.h>
#include <task.h>
 
 
#define LCD_COMM   *(volatile uint16_t *)(0x60000000)
#define LCD_DATA   *(volatile uint16_t *)(0x60080000)
 
 
inline void _delay_ms(uint32_t n) {
    for (volatile int i = 0; i < n * 80000; i++)
        __asm__("nop");
}
 
inline void delay_ms(uint32_t n) {
    for (volatile int i = 0; i < n * 80000; i++)
        __asm__("nop");
}
 
inline void lcd_write_command(uint8_t comm) {
    taskENTER_CRITICAL();
    LCD_COMM = (uint16_t) (comm & 0xFF);
    taskEXIT_CRITICAL();
}
 
inline void lcd_write_data(uint16_t data) {
    LCD_DATA = data;
}
 
inline void lcd_write_byte(uint8_t data) {
    taskENTER_CRITICAL();
    LCD_DATA = (uint16_t) (data && 0xFF);
    taskEXIT_CRITICAL();
}
 
inline inline void lcd_write_word(uint16_t w) {
    lcd_write_data((w >> 8) & 0xFF);
    lcd_write_data(w & 0xFF);
}
 
 
void lcd_soft_reset(void) {
    lcd_write_command(LCD_SWRESET);
}
 
void lcd_sleep_out(void) {
    lcd_write_command(LCD_SLPOUT);
}
 
void lcd_set_color_mode(uint8_t mode) {
    lcd_write_command(LCD_COLMOD);
    lcd_write_byte(mode);
}
void lcd_set_normal_mode(void) {
    lcd_write_command(LCD_NORON);
}
 
void lcd_set_display_on(void) {
    lcd_write_command(LCD_DISPON);
}
 
void lcd_set_display_off(void) {
    lcd_write_command(LCD_DISPOFF);
}
 
void lcd_set_brightness(uint8_t level) {
    lcd_write_command(LCD_WRDISBV);
    lcd_write_byte(level);
}
 
void lcd_set_frame_rate_normal(uint8_t divb, uint8_t rtnb) {
    lcd_write_command(LCD_FRMCTR1);
    lcd_write_byte(divb);
    lcd_write_byte(rtnb);
}
 
void lcd_set_frame_rate_idle(uint8_t divb, uint8_t rtnb) {
    lcd_write_command(LCD_FRMCTR2);
    lcd_write_byte(divb);
    lcd_write_byte(rtnb);
}
 
void lcd_set_frame_rate_partial(uint8_t divb, uint8_t rtnb) {
    lcd_write_command(LCD_FRMCTR3);
    lcd_write_byte(divb);
    lcd_write_byte(rtnb);
}
 
 
void lcd_set_memory_access(uint8_t mode) {
    lcd_write_command(LCD_MADCTL);
    lcd_write_byte(mode);
}
 
void lcd_setup(void) {
 
    lcd_soft_reset();
    _delay_ms(150);
 
    lcd_sleep_out();
    _delay_ms(250);
 
    lcd_write_command(LCD_PWCTR1);
    lcd_write_data(0x1B);
 
    lcd_write_command(LCD_PWCTR2);
    lcd_write_data(0x01);
 
    lcd_write_command(LCD_VMCTR1);
    lcd_write_data(0x30);
    lcd_write_data(0x30);
 
    lcd_write_command(LCD_VMOFCTR);
    lcd_write_data(0XB7);
 
 
    lcd_write_command(LCD_COLMOD);
    lcd_write_data(0x55);
 
    lcd_write_command(LCD_DISSET5);
    lcd_write_data(0x0A);
    lcd_write_data(0xA2);
 
 
    lcd_write_command(LCD_GAMSET);
    lcd_write_data(0x01);
 
    lcd_write_command(LCD_GMCTRP1);
    lcd_write_data(0x0F);
    lcd_write_data(0x2A);
    lcd_write_data(0x28);
    lcd_write_data(0x08);
    lcd_write_data(0x0E);
    lcd_write_data(0x08);
    lcd_write_data(0x54);
    lcd_write_data(0XA9);
    lcd_write_data(0x43);
    lcd_write_data(0x0A);
    lcd_write_data(0x0F);
    lcd_write_data(0x00);
    lcd_write_data(0x00);
    lcd_write_data(0x00);
    lcd_write_data(0x00);
 
    lcd_write_command(LCD_GMCTRN1);
    lcd_write_data(0x00);
    lcd_write_data(0x15);
    lcd_write_data(0x17);
    lcd_write_data(0x07);
    lcd_write_data(0x11);
    lcd_write_data(0x06);
    lcd_write_data(0x2B);
    lcd_write_data(0x56);
    lcd_write_data(0x3C);
    lcd_write_data(0x05);
    lcd_write_data(0x10);
    lcd_write_data(0x0F);
    lcd_write_data(0x3F);
    lcd_write_data(0x3F);
    lcd_write_data(0x0F);
 
    lcd_write_command(LCD_RASET);
    lcd_write_data(0x00);
    lcd_write_data(0x00);
    lcd_write_data(0x01);
    lcd_write_data(0x3f);
 
    lcd_write_command(LCD_CASET);
    lcd_write_data(0x00);
    lcd_write_data(0x00);
    lcd_write_data(0x00);
    lcd_write_data(0xef);
 
    lcd_write_command(LCD_IDMOFF);
 
    lcd_set_normal_mode();
 
    lcd_write_command(LCD_COLMOD);
    lcd_write_data(0x55);
 
    lcd_write_command(LCD_FRMCTR1);
    lcd_write_data(0x00);
    lcd_write_data(0x18);
 
    lcd_sleep_out();
    delay_ms(120);
    lcd_set_display_on();
 
    _delay_ms(100);
 
}
 
void lcd_addr_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {
    lcd_write_command(LCD_CASET);
    lcd_write_word(x0);
    lcd_write_word(x1);
 
    lcd_write_command(LCD_RASET);
    lcd_write_word(y0);
    lcd_write_word(y1);
}
 
void lcd_write_ram(uint16_t w, uint16_t n) {
    lcd_write_command(LCD_RAMWR);
    while (n--)
        lcd_write_data(w);
}
 
void lcd_write_rect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint32_t color) {
    lcd_addr_window(x, y, (x + w), (y + h));
    uint16_t c565 = lcd_rgb2c(color);
    lcd_write_ram(c565, (w + 1) * (h + 1 ) );
}
 
void lcd_clear(void) {
    lcd_write_rect(0, 0, LCD_WIDTH/2, LCD_HEIGHT, LCD_BLACK);
    lcd_write_rect(LCD_WIDTH/2, 0, LCD_WIDTH/2 + 1, LCD_HEIGHT, LCD_BLACK);
}
 
void lcd_draw_pixel(uint16_t x, uint16_t y, uint32_t color) {
    lcd_addr_window(x, y, x, y);
    uint16_t c565 = lcd_rgb2c(color);
    lcd_write_command(LCD_RAMWR);
    lcd_write_data(c565);
}
 
#define swap(a, b) { int16_t t = a; a = b; b = t; }
 
void lcd_draw_line(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint32_t color) {
    int16_t steep = abs(y1 - y0) > abs(x1 - x0);
 
    if (steep) {
        swap(x0, y0);
        swap(x1, y1);
    }
 
    if (x0 > x1) {
        swap(x0, x1);
        swap(y0, y1);
    }
 
    int16_t dx, dy;
    dx = x1 - x0;
    dy = abs(y1 - y0);
 
    int16_t err = dx / 2;
    int16_t ystep;
 
    if (y0 < y1)
        ystep = 1;
    else
        ystep = -1;
 
    while (x0 <= x1) {
        if (steep) {
            lcd_draw_pixel(y0, x0, color);
        } else {
            lcd_draw_pixel(x0, y0, color);
        }
        err -= dy;
        if (err < 0) {
            y0 += ystep;
            err += dx;
        }
        x0++;
    }
}
 
void lcd_draw_vline(int16_t x, int16_t y, int16_t l, uint16_t color) {
    lcd_write_rect(x, y, (l - 1), 0, color);
}
 
void lcd_draw_hline(int16_t x, int16_t y, int16_t l, uint16_t color) {
    lcd_write_rect(x, y, 0, (l - 1), color);
}
 
void lcd_draw_rest(uint16_t x1, uint16_t y1, uint16_t w, uint16_t h, uint32_t color) {
    lcd_draw_hline(x1, y1, w, color);
    lcd_draw_vline(x1, y1, h, color);
    lcd_draw_hline((x1 + h) - 0, y1, w, color);
    lcd_draw_vline(x1, (y1 + w) - 0, h, color);
}
 
uint16_t lcd_rgb2c(uint32_t rgb) {
    return (uint16_t) 
        (((rgb & 0xF80000) >> 19)|
         ((rgb & 0x00F800) >> 6) |
         ((rgb & 0x0000F8) << 8));
}
 
void lcd_draw_char(uint16_t xbase, uint16_t ybase, font_t *font, uint8_t c) {
    if (c < font->start || c > (font->start + font->length))
        c = ' ';
    c = c - font->start;
 
    uint16_t fg = lcd_rgb2c(LCD_WHITE);
    uint16_t bg = lcd_rgb2c(LCD_BLACK);
 
    lcd_addr_window(xbase, ybase, xbase + font->height - 1, ybase + font->width - 1);
 
    lcd_write_command(LCD_RAMWR);
 
    for (uint8_t w = font->width; w > 0; w--) {
        for (uint8_t h = font->height; h > 0; h--) {
            if ((font->bitmap[(c) * font->height + (h - 1)]) & (1 << (w - 1)))
                lcd_write_data(0xEFEF);
            else
                lcd_write_data(0x0000);
        }
    }
}
 
 
/* EOF */

ili9341.h

ili9341.h
#ifndef ILI9341_H
#define ILI9341_H
 
//#define LCD_COMM   *(volatile uint8_t *)(0x60000000)
//#define LCD_DATA   *(volatile uint8_t *)(0x600E0000)
 
#define LCD_SWRESET  0x01    /* Software Reset */
#define LCD_RDDID    0x04    /* Read Display ID */
#define LCD_RDDST    0x09    /* Read Display Status */
#define LCD_RDDPM    0x0A    /* Read Display Power Mode */
#define LCD_RDDMADCTL 0x0B    /* Read Display MADCTL */
#define LCD_RDDCOLMOD 0x0C    /* Read Display Pixel Format */
#define LCD_RDDIM     0x0D    /* Read Display Image Mode */
#define LCD_RDDSM     0x0E    /* Read Display Signal Mode */
#define LCD_RDDSDR    0x0F    /* Read Display Self-Diagnostic Result */
#define LCD_SLPIN     0x10    /* Sleep In */
#define LCD_SLPOUT    0x11    /* Sleep Out */
#define LCD_PTLON     0x12    /* Partial Display Mode On */
#define LCD_NORON     0x13    /* Normal Display Mode On */
#define LCD_DINVOFF   0x20    /* Display Inversion Off */
#define LCD_DINVON    0x21    /* Display Inversion On */
#define LCD_GAMSET    0x26    /* Gamma Set */
#define LCD_DISPOFF   0x28    /* Display Off */
#define LCD_DISPON    0x29    /* Display On */
#define LCD_CASET     0x2A    /* Column Address Set */
#define LCD_RASET     0x2B    /* Row Address Set */
#define LCD_RAMWR     0x2C    /* Memory Write */
#define LCD_RGBSET    0x2D    /* Color Setting for 4K, 65K and 262K */
#define LCD_RAMRD     0x2E    /* Memory Read */
#define LCD_PTLAR     0x30    /* Partial Area */
#define LCD_VSCRDEF   0x33    /* Vertical Scrolling Definition */
#define LCD_TEOFF     0x34    /* Tearing Effect Line OFF */
#define LCD_TEON      0x35    /* Tearing Effect Line ON */
#define LCD_MADCTL    0x36    /* Memory Data Access Control */
#define LCD_VSCRSADD  0x37    /* Vertical Scrolling Start Address */
#define LCD_IDMOFF    0x38    /* Idle Mode Off */
#define LCD_IDMON     0x39    /* Idle Mode On */
#define LCD_COLMOD    0x3A    /* Interface Pixel Format */
 
 
#define LCD_IFCTL     0xF6
#define LCD_DISCTRL   0xB6
 
 
// 0x3C Write_Memory_Continue
// 0x3E Read_Memory_Continue
// 0x44 Set_Tear_Scanline
// 0x45 Get_Scanline
// 0x51 Write Display Brightness
#define LCD_WRDISBV    0x51    /* Write Display Brightness */
// 0x52 Read Display Brightness
#define LCD_WRCTRLD   0x53    /* Write CTRL Display */
 
#define LCD_RDID1     0xDA    /* Read ID1 Value */
#define LCD_RDID2     0xDB    /* Read ID2 Value */
#define LCD_RDID3     0xDC    /* Read ID3 Value */
 
 
#define LCD_IFMODE    0xB0    /* RGB Interface Signal Control */ 
#define LCD_FRMCTR1   0xB1    /* Frame Rate Control 0xIn normal mode/ Full colors) */
#define LCD_FRMCTR2   0xB2    /* Frame Rate Control (In Idle mode/ 8-colors) */
#define LCD_FRMCTR3   0xB3    /* Frame Rate Control 0xIn Partial mode/ full colors) */
#define LCD_DINVCTR   0xB4    /* Display Inversion Control */
// 0xB5 Blanking Porch Control
#define LCD_DISSET5   0xB6    /* Display Function set 5 */
// 0xB7 Entry Mode Set
#define LCD_PWCTR1    0xC0    /* Power Control 1 */
#define LCD_PWCTR2    0xC1    /* Power Control 2 */
#define LCD_PWCTR3    0xC2    /* Power Control 3 0xin Normal mode/ Full colors) */
#define LCD_PWCTR4    0xC3    /* Power Control 4 0xin Idle mode/ 8-colors) */
#define LCD_PWCTR5    0xC4    /* Power Control 5 0xin Partial mode/ full-colors) */
#define LCD_VMCTR1    0xC5    /* VCOM Control 1 */
#define LCD_VMOFCTR   0xC7    /* VCOM Offset Control */
#define LCD_WRID2     0xD1    /* Write ID2 Value */
#define LCD_WRID3     0xD2    /* Write ID3 Value */
#define LCD_NVFCTR1   0xD9    /* NVM Control Status */
#define LCD_NVFCTR2   0xDE    /* NVM Read Command */
#define LCD_NVFCTR3   0xDF    /* NVM Write Command */
#define LCD_GMCTRP1   0xE0    /* Gamma `+'polarity) Correction Characteristics Setting */
#define LCD_GMCTRN1   0xE1    /* Gamma `-'polarity Correction Characteristics Setting */
 
#define LCD_COLOR_MODE_RGB   5
 
#define LCD_FRAME_RATE_DIV0     0
#define LCD_FRAME_RATE_DIV2     1
#define LCD_FRAME_RATE_DIV4     2
#define LCD_FRAME_RATE_DIV8     3
 
#define LCD_FRAME_RATE_119HZ   0x10
#define LCD_FRAME_RATE_112HZ   0x11
#define LCD_FRAME_RATE_106HZ   0x12
#define LCD_FRAME_RATE_100HZ   0x13
#define LCD_FRAME_RATE_95HZ    0x14
#define LCD_FRAME_RATE_90HZ    0x15
#define LCD_FRAME_RATE_86HZ    0x16
#define LCD_FRAME_RATE_83HZ    0x17
#define LCD_FRAME_RATE_79HZ    0x18
#define LCD_FRAME_RATE_76HZ    0x19
#define LCD_FRAME_RATE_73HZ    0x1A
#define LCD_FRAME_RATE_70HZ    0x1B
#define LCD_FRAME_RATE_68HZ    0x1C
#define LCD_FRAME_RATE_65HZ    0x1D
#define LCD_FRAME_RATE_63HZ    0x1E
#define LCD_FRAME_RATE_61HZ    0x1F
 
#define LCD_MADCTL_MY       0x80
#define LCD_MADCTL_MX       0x40
#define LCD_MADCTL_MV       0x20
#define LCD_MADCTL_ML       0x10
#define LCD_MADCTL_RGB      0x08
#define LCD_MADCTL_BGR      0x00
#define LCD_MADCTL_MH       0x04
 
 
#define LCD_565BLACK     0x0000
#define LCD_565BLUE      0x001F
#define LCD_565RED       0xF800
#define LCD_565GREEN     0x07E0
#define LCD_565CYAN      0x07FF
#define LCD_565MAGENTA   0xF81F
#define LCD_565YELLOW    0xFFE0
#define LCD_565WHITE     0xFFFF
 
#define LCD_BLACK	0x000000
#define LCD_BLUE	0x0000FF
#define LCD_BROWN	0xA05000
#define LCD_CHARCOAL	0x4F4F4F
#define LCD_CREAM	0xE8D898
#define LCD_CYAN	0x00FFFF
#define LCD_GOLD	0xFFAA00
#define LCD_GRAY	0x808080
#define LCD_GREEN	0x00FF00
#define LCD_LILAC	0xE06090
#define LCD_LIME	0xC0FF81
#define LCD_MAGENTA	0xFF00FF
#define LCD_MAROON	0x700000
#define LCD_OLIVE	0x2A8307
#define LCD_ORANGE	0xFF8000
#define LCD_PINK	0xFF0080
#define LCD_PURPLE	0x703070
#define LCD_RED	0xFF0000
#define LCD_ROSE	0xFF6060
#define LCD_SALMON	0xFF0055
#define LCD_STEEL	0x3883A8
#define LCD_TAN	0xE0A860
#define LCD_VIOLET	0xB090D0
#define LCD_WHITE	0xFFFFFF
#define LCD_YELLOW	0xFFFF00
 
 
#define LCD_WIDTH   240
#define LCD_HEIGHT  320
 
typedef struct font {
    uint8_t width;
    uint8_t height;
    uint8_t start;
    uint8_t length;
    const uint8_t *bitmap;
} font_t;
 
void lcd_soft_reset(void);
void lcd_sleep_out(void);
void lcd_set_color_mode(uint8_t mode);
void lcd_set_normal_mode(void);
void lcd_set_display_on(void);
void lcd_set_display_off(void);
void lcd_set_brightness(uint8_t level);
void lcd_set_frame_rate_normal(uint8_t divb, uint8_t rtnb);
void lcd_set_frame_rate_idle(uint8_t divb, uint8_t rtnb);
void lcd_set_frame_rate_partial(uint8_t divb, uint8_t rtnb);
void lcd_setup(void);
void lcd_addr_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);
void lcd_write_ram(uint16_t w, uint16_t n);
void lcd_write_rect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint32_t color);
void lcd_clear(void);
void lcd_draw_pixel(uint16_t x, uint16_t y, uint32_t color);
void lcd_draw_line(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint32_t color);
void lcd_draw_vline(int16_t x, int16_t y, int16_t l, uint16_t color);
void lcd_draw_hline(int16_t x, int16_t y, int16_t l, uint16_t color);
void lcd_draw_rest(uint16_t x1, uint16_t y1, uint16_t w, uint16_t h, uint32_t color);
uint16_t lcd_rgb2c(uint32_t rgb);
void lcd_draw_char(uint16_t xbase, uint16_t ybase, font_t *font, uint8_t c);
 
#endif
 
/* EOF */

master.c

master.c
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/cm3/systick.h>
 
#include <libopencm3/cm3/dwt.h>
#include <libopencm3/cm3/scb.h>
 
#include <libopencm3/stm32/syscfg.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/usart.h>
#include <libopencm3/stm32/timer.h>
#include <libopencm3/stm32/i2c.h>
#include <libopencm3/stm32/spi.h>
#include <libopencm3/stm32/rtc.h>
#include <libopencm3/stm32/adc.h>
#include <libopencm3/stm32/dma.h>
#include <libopencm3/stm32/fsmc.h>
#include <libopencm3/stm32/pwr.h>
#include <libopencm3/stm32/rng.h>
#include <libopencm3/stm32/can.h>
#include <libopencm3/stm32/exti.h>
 
 
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <wctype.h>
#include <ctype.h>
#include <locale.h>
#include <wchar.h>
#include <time.h>
 
#include <syscall.h>
#include <fsmcwr.h>
 
#include <buffer.h>
#include <uastdio.h>
#include <ili9341.h>
#include <console.h>
#include <random.h>
 
#include <rtc4xx.h>
#include <xpt2046.h>
 
#include <FreeRTOS.h>
#include <task.h>
#include <queue.h>
#include <timers.h>
 
 
void send_console_msg(uint8_t row, uint8_t col, uint8_t * str);
void send_console_msg_from_isr(uint8_t row, uint8_t col, uint8_t * str);
 
 
/* Object definition */
 
#define _IRQ2NVIC_PRIOR(x)       ((x) << 4)
#define UART_QUEUE_LEN      512
#define CONSOLE_QUEUE_LEN   8
 
xTaskHandle usart1_task_h;
xTaskHandle usart3_task_h;
xTaskHandle counter_task_h;
xTaskHandle console_task_h;
 
 
volatile QueueHandle_t usart1_q;
volatile QueueHandle_t usart3_q;
volatile QueueHandle_t console_q;
 
#define CONSOLE_STR_LEN 32
#define STR_LEN 16
 
typedef struct console_message_t {
    uint8_t row;
    uint8_t col;
    uint8_t str[CONSOLE_STR_LEN + 1];
} console_message_t;
 
 
/* Generic */
void delay(uint32_t n) {
    for (volatile int i = 0; i < n * 10; i++)
        __asm__("nop");
}
 
void _delay_ms(uint32_t n) {
    for (volatile int i = 0; i < n * 80000; i++)
        __asm__("nop");
}
 
/* RCC CLOCK */
static void clock_setup(void) {
    rcc_clock_setup_hse_3v3(&rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_168MHZ]);
 
    rcc_periph_clock_enable(RCC_GPIOA);
    rcc_periph_clock_enable(RCC_GPIOB);
    rcc_periph_clock_enable(RCC_GPIOC);
    rcc_periph_clock_enable(RCC_GPIOD);
    rcc_periph_clock_enable(RCC_GPIOE);
 
    rcc_periph_clock_enable(RCC_SPI2);
    rcc_periph_clock_enable(RCC_SYSCFG);
 
    rcc_periph_clock_enable(RCC_FSMC);
 
    rcc_periph_clock_enable(RCC_TIM2);
    rcc_periph_clock_enable(RCC_TIM7);
    rcc_periph_clock_enable(RCC_USART1);
    rcc_periph_clock_enable(RCC_USART3);
 
    rcc_periph_clock_enable(RCC_PWR);
    rcc_periph_clock_enable(RCC_RTC);
    rcc_periph_clock_enable(RCC_RNG);
 
    rcc_periph_clock_enable(RCC_DAC);
    rcc_periph_clock_enable(RCC_DMA1);
    rcc_periph_clock_enable(RCC_DMA2);
    rcc_periph_clock_enable(RCC_ADC1);
}
 
/* USART generic */
 
inline bool usart_recv_is_ready(uint32_t usart) {
    return (USART_SR(usart) & USART_SR_RXNE);
}
 
inline bool usart_rx_int_is_enable(uint32_t usart) {
    return (USART_CR1(USART1) & USART_CR1_RXNEIE);
}
 
/* USART1 */
 
void usart1_setup(void) {
 
    usart_disable(USART1);
    nvic_enable_irq(NVIC_USART1_IRQ);
 
    gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO9 | GPIO10);
    gpio_set_af(GPIOA, GPIO_AF7, GPIO9 | GPIO10);
 
    usart_set_baudrate(USART1, 115200);
    usart_set_databits(USART1, 8);
    usart_set_stopbits(USART1, USART_STOPBITS_1);
    usart_set_parity(USART1, USART_PARITY_NONE);
    usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE);
    usart_set_mode(USART1, USART_MODE_TX_RX);
    usart_enable_rx_interrupt(USART1);
    usart_enable(USART1);
}
 
void usart1_isr(void) {
    uint8_t data = 0;
 
    BaseType_t xHigherPriorityTaskWoken;
    xHigherPriorityTaskWoken = pdTRUE;
 
    if (usart_rx_int_is_enable(USART1) && usart_recv_is_ready(USART1)) {
        data = usart_recv_blocking(USART1);
        xQueueSendFromISR(usart1_q, &data, &xHigherPriorityTaskWoken);
    }
    portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
}
 
/* USART3 */
 
void usart3_setup(void) {
 
    usart_disable(USART3);
    nvic_enable_irq(NVIC_USART3_IRQ);
 
    gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO10 | GPIO11);
    gpio_set_af(GPIOB, GPIO_AF7, GPIO10 | GPIO11);
 
    usart_set_baudrate(USART3, 9600);
    usart_set_databits(USART3, 8);
    usart_set_stopbits(USART3, USART_STOPBITS_1);
    usart_set_parity(USART3, USART_PARITY_NONE);
    usart_set_flow_control(USART3, USART_FLOWCONTROL_NONE);
    usart_set_mode(USART3, USART_MODE_TX_RX);
    usart_enable_rx_interrupt(USART3);
    usart_enable(USART3);
}
 
void usart3_isr(void) {
    uint8_t data = 0;
 
    BaseType_t xHigherPriorityTaskWoken;
    xHigherPriorityTaskWoken = pdTRUE;
 
    if (usart_rx_int_is_enable(USART3) && usart_recv_is_ready(USART3)) {
        data = usart_recv_blocking(USART3);
        xQueueSendFromISR(usart3_q, &data, &xHigherPriorityTaskWoken);
    }
    portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
}
 
 
/* FSMC */
 
#define FSMC_PD (GPIO4 | GPIO5 | GPIO7 | GPIO13 | GPIO14 | GPIO15 | GPIO0 | GPIO1 | GPIO8 | GPIO9 | GPIO10)
#define FSMC_PE (GPIO7 | GPIO8 | GPIO9 | GPIO10 | GPIO11 | GPIO12 | GPIO13 | GPIO14 | GPIO15)
 
void fsmc_setup(void) {
 
    gpio_mode_setup(GPIOD, GPIO_MODE_AF, GPIO_PUPD_NONE, FSMC_PD);
    gpio_set_output_options(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_100MHZ, FSMC_PD);
    gpio_set_af(GPIOD, GPIO_AF12, FSMC_PD);
 
    gpio_mode_setup(GPIOE, GPIO_MODE_AF, GPIO_PUPD_NONE, FSMC_PE);
    gpio_set_output_options(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_100MHZ, FSMC_PE);
    gpio_set_af(GPIOE, GPIO_AF12, FSMC_PE);
 
    fsmc_set_access_mode(BANK1, FSMC_BTx_ACCMOD_B);
    fsmc_set_data_latency(BANK1, 0);
    fsmc_set_clock_divide_ratio(BANK1, 0);
    fsmc_set_turnaround_phase_duration(BANK1, 0);
    fsmc_set_data_phase_duration(BANK1, 5);
    fsmc_set_address_hold_phase_duration(BANK1, 0);
    fsmc_set_address_setup_phase_duration(BANK1, 1);
 
    fsmc_address_data_multiplexing_disable(BANK1);
    fsmc_write_burst_disable(BANK1);
    fsmc_wrapped_burst_mode_disable(BANK1);
    fsmc_extended_mode_disable(BANK1);
    fsmc_write_enable(BANK1);
 
    fsmc_wait_signal_polarity_low(BANK1);
    fsmc_wait_timing_configuration_enable(BANK1);
    fsmc_wait_disable(BANK1);
    fsmc_memory_bank_enable(BANK1);
}
 
 
/* ADC1 */
static void __adc1_setup(void) {
    gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO0);
    gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO1);
 
    rcc_periph_clock_enable(RCC_ADC1);
 
    adc_set_clk_prescale(ADC_CCR_ADCPRE_BY2);
    adc_disable_scan_mode(ADC1);
 
    adc_set_single_conversion_mode(ADC1);
    adc_set_sample_time(ADC1, ADC_CHANNEL0, ADC_SMPR_SMP_3CYC);
 
    adc_enable_temperature_sensor();
 
    uint8_t channels[16];
    channels[0] = ADC_CHANNEL16;
    adc_set_resolution(ADC1, 12);
 
 
    adc_set_regular_sequence(ADC1, 1, channels);
    adc_set_multi_mode(ADC_CCR_MULTI_INDEPENDENT);
    adc_power_on(ADC1);
 
    //adc_start_conversion_regular(ADC1);
    //while (!adc_eoc(ADC1));
    //reg16 = adc_read_regular(ADC1);
}
 
static void adc1_setup(void) {
    gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO0);
    gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO1);
 
    adc_set_clk_prescale(ADC_CCR_ADCPRE_BY2);
    adc_enable_scan_mode(ADC1);
    adc_set_continuous_conversion_mode(ADC1);
    adc_set_sample_time_on_all_channels(ADC1, ADC_SMPR_SMP_28CYC);
 
    adc_enable_temperature_sensor();
 
    uint8_t channels[16];
    channels[0] = ADC_CHANNEL0;
    channels[1] = ADC_CHANNEL1;
 
    adc_set_resolution(ADC1, 12);
 
    adc_set_regular_sequence(ADC1, 2, channels);
    adc_set_multi_mode(ADC_CCR_MULTI_INDEPENDENT);
 
    adc_enable_dma(ADC1);
    adc_set_dma_continue(ADC1);
 
    adc_power_on(ADC1);
    adc_start_conversion_regular(ADC1);
}
 
uint16_t adc_res[32];
 
static void dma2_setup(void) {
 
    dma_stream_reset(DMA2, DMA_STREAM0);
    dma_set_peripheral_address(DMA2, DMA_STREAM0, (uint32_t) & ADC_DR(ADC1));
 
    dma_set_memory_address(DMA2, DMA_STREAM0, (uint32_t) &adc_res[0]);
 
    dma_set_number_of_data(DMA2, DMA_STREAM0, 2);
    dma_set_dma_flow_control(DMA2, DMA_STREAM0);
 
    dma_channel_select(DMA2, DMA_STREAM0, DMA_SxCR_CHSEL_0);
    dma_set_priority(DMA2, DMA_STREAM0, DMA_SxCR_PL_HIGH);
 
    dma_set_peripheral_size(DMA2, DMA_STREAM0, DMA_SxCR_PSIZE_16BIT);
    dma_set_memory_size(DMA2, DMA_STREAM0, DMA_SxCR_MSIZE_16BIT);
 
    dma_enable_memory_increment_mode(DMA2, DMA_STREAM0);
    dma_enable_circular_mode(DMA2, DMA_STREAM0);
 
    //dma_clear_interrupt_flags(DMA2, DMA_STREAM0, DMA_ISR_FLAGS);
    //nvic_enable_irq(NVIC_DMA2_STREAM0_IRQ);
    //dma_enable_transfer_complete_interrupt(DMA2, DMA_STREAM0);
 
    dma_enable_stream(DMA2, DMA_STREAM0);
}
 
 
/* TASKs */
 
static void usart1_task(void *args __attribute__ ((unused))) {
    uint8_t c;
    while (1) {
        if (xQueueReceive(usart1_q, &c, 10) == pdPASS) {
            while (!usart_get_flag(USART1, USART_SR_TXE))
                taskYIELD();
            usart_send_blocking(USART1, c);
        } else {
            taskYIELD();
        }
    }
}
 
#if 0
typedef struct location {
    float latitude,
    float longitude,
    float timestamp
} loc_t;
#endif
 
static void usart_puts(uint32_t usart, uint8_t * str) {
    uint16_t i = 0;
 
    while (str[i] != 0) {
        usart_send_blocking(usart, str[i]);
        i++;
    }
}
 
uint16_t get_substr(uint8_t * src, uint8_t *dst, uint16_t len, uint8_t delim, uint8_t num) {
 
    uint16_t i = 0;
    uint16_t n = 0;
    uint16_t d = 0;
 
    while (src[i] != 0 || src[i] != '\r' || src[i] != '\n') {
        if (src[i] == delim) {
            n++;
            i++;
        }
        if (n > num) {
            dst[d] = 0;
            break;
        }
        if (src[i] == delim)
            continue;
        if (n == num && d < len) {
            dst[d] = src[i];
            d++;
        }
        i++;
    }
    return d;
}
 
 
#define MAX_BUF_LEN 128
 
static void usart3_task(void *args __attribute__ ((unused))) {
    uint8_t c;
 
    static uint8_t buf[MAX_BUF_LEN + 2];
    static uint8_t i = 0;
    static uint8_t dst[MAX_BUF_LEN];
 
    float lon, lan = 0;
 
    while (1) {
        if (xQueueReceive(usart3_q, &c, 10) == pdPASS) {
            if (c == '\n' || c == '\r' || i >= MAX_BUF_LEN) {
                buf[i] = 0;
                i = 0;
                if (strlen(buf) > 0 && strstr(buf, "$GPGLL") != NULL) {
                    //usart_puts(USART1, buf);
                    //usart_puts(USART1, "\r\n");
                    //printf("%s\r\n", buf);
 
                    get_substr(buf, dst, MAX_BUF_LEN - 1, ',', 1);
                    lan = strtof(dst, NULL);
                    get_substr(buf, dst, MAX_BUF_LEN - 1, ',', 2);
                    if (dst[0] == 'N')
                        lan = -lan;
 
                    get_substr(buf, dst, MAX_BUF_LEN - 1, ',', 3);
                    lon = strtof(dst, NULL);
                    get_substr(buf, dst, MAX_BUF_LEN - 1, ',', 4);
                    if (dst[0] == 'E')
                        lon = -lon;
 
                    //printf("%d %d\r\n", (int32_t) (lan * 10000), (int32_t) (lon * 10000));
 
                    console_message_t msg;
                    msg.row = 11;
                    msg.col = 0;
                    snprintf(msg.str, CONSOLE_STR_LEN, "%+6d %+6d", (int32_t) (lan * 10), (int32_t) (lon * 10));
                    xQueueSend(console_q, &msg, portMAX_DELAY);
 
                }
            } else {
                buf[i] = c;
                i++;
            }
        } else {
            taskYIELD();
        }
    }
}
 
 
 
 
void send_console_msg(uint8_t row, uint8_t col, uint8_t * str) {
    console_message_t msg;
    msg.row = row;
    msg.col = col;
    memcpy(msg.str, str, CONSOLE_STR_LEN);
    xQueueSend(console_q, &msg, portMAX_DELAY);
}
 
 
void send_console_msg_from_isr(uint8_t row, uint8_t col, uint8_t * str) {
    console_message_t msg;
    msg.row = row;
    msg.col = col;
    //memcpy(msg.str, str, CONSOLE_STR_LEN);
 
    uint8_t i = 0;
    while ((i < CONSOLE_STR_LEN) || (str[i] != 0)) {
        msg.str[i] = str[i];
        i++;
    }
 
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
 
    xQueueSendFromISR(console_q, &msg, &xHigherPriorityTaskWoken);
    if (xHigherPriorityTaskWoken) {
        //taskYIELD_FROM_ISR();
    }
}
 
#define MAX_TASK_COUNT  7
 
void print_stats(void) {
    volatile UBaseType_t task_count = MAX_TASK_COUNT;
    TaskStatus_t *status_array = pvPortMalloc(task_count * sizeof(TaskStatus_t));
 
    if (status_array != NULL) {
        uint32_t total_time, stat_as_percentage;
        task_count = uxTaskGetSystemState(status_array, task_count, &total_time);
 
        total_time /= 100UL;
        if (total_time > 0) {
            uint16_t row = 3;
            for (UBaseType_t x = 0; x < task_count; x++) {
                stat_as_percentage = status_array[x].ulRunTimeCounter / total_time;
 
                if (stat_as_percentage >= 0UL) {
                    #define CONSOLE_MAX_STAT_ROW 8
                    if (row < CONSOLE_MAX_STAT_ROW) {
                        console_message_t msg;
                        msg.row = row;
                        msg.col = 0;
                        snprintf(msg.str, CONSOLE_STR_LEN, "%-5s %3d %3u",
                                 status_array[x].pcTaskName, stat_as_percentage, status_array[x].usStackHighWaterMark);
                        xQueueSend(console_q, &msg, portMAX_DELAY);
                    }
                    row++;
                }
            }
        }
    }
    vPortFree(status_array);
}
 
static void counter_task(void *args __attribute__ ((unused))) {
    uint32_t i = 0;
    uint8_t str[CONSOLE_STR_LEN + 1];
    while (1) {
        print_stats();
 
        //adc_start_conversion_regular(ADC1);
        //while (!adc_eoc(ADC1));
        //uint16_t reg16 = adc_read_regular(ADC1);
 
        snprintf(str, CONSOLE_STR_LEN, "0x%08X %4u  %4u", i, adc_res[0], adc_res[1]);
        send_console_msg(16, 0, str);
 
        vTaskDelay(pdMS_TO_TICKS(250));
        i++;
    }
}
 
static void console_task(void *args __attribute__ ((unused))) {
    console_message_t msg;
    while (1) {
        if (xQueueReceive(console_q, &msg, 10) == pdPASS) {
            console_xyputs(&console, msg.row, msg.col, msg.str);
        } else {
            taskYIELD();
        }
    }
}
 
 
/* MAIN */
int main(void) {
    clock_setup();
 
    dma2_setup();
    adc1_setup();
 
    delay(100);
 
    fsmc_setup();
    lcd_setup();
    lcd_clear();
 
    uint32_t i = 1;
    uint8_t str[STR_LEN + 1];
 
    console_xyputs(&console, 0, 0, "FreeRTOS STM32-F4 CONSOLE V0.2");
    console_xyputs(&console, 1, 0, "SYS READY>");
 
    usart1_setup();
    usart3_setup();
 
    scb_set_priority_grouping(SCB_AIRCR_PRIGROUP_GROUP16_NOSUB);
    nvic_set_priority(NVIC_SYSTICK_IRQ, _IRQ2NVIC_PRIOR(15));
    nvic_set_priority(NVIC_USART1_IRQ, configMAX_SYSCALL_INTERRUPT_PRIORITY + _IRQ2NVIC_PRIOR(1));
    nvic_set_priority(NVIC_USART3_IRQ, configMAX_SYSCALL_INTERRUPT_PRIORITY + _IRQ2NVIC_PRIOR(2));
 
    usart1_q = xQueueCreate(UART_QUEUE_LEN, sizeof(uint8_t));
    usart3_q = xQueueCreate(UART_QUEUE_LEN, sizeof(uint8_t));
    console_q = xQueueCreate(CONSOLE_QUEUE_LEN, sizeof(console_message_t));
 
    xTaskCreate(usart1_task, "UAR1", configMINIMAL_STACK_SIZE, NULL, configMAX_PRIORITIES - 2, usart1_task_h);
    xTaskCreate(usart3_task, "UAR3", configMINIMAL_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, usart3_task_h);
    xTaskCreate(counter_task, "CNTR", configMINIMAL_STACK_SIZE, NULL, configMAX_PRIORITIES - 2, counter_task_h);
    xTaskCreate(console_task, "CONS", configMINIMAL_STACK_SIZE, NULL, configMAX_PRIORITIES - 2, console_task_h);
 
 
    vTaskStartScheduler();
 
    return 0;
}
 
/* EOF */

opencm3.c

opencm3.c
/* Author, Copyright: Oleg Borodin <onborodin@gmail.com> 2018 */
 
#include <FreeRTOS.h>
#include <task.h>
 
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/cm3/nvic.h>
 
 
extern void vPortSVCHandler(void) __attribute__ ((naked));
extern void xPortPendSVHandler(void) __attribute__ ((naked));
extern void xPortSysTickHandler(void);
 
__attribute__((used)) void sv_call_handler(void) {
    vPortSVCHandler();
}
 
__attribute__((used)) void pend_sv_handler(void) {
    xPortPendSVHandler();
}
 
__attribute__((used)) void sys_tick_handler(void) {
    xPortSysTickHandler();
}
 
/* EOF */

random.c

random.c
/* Author, Copyright: Oleg Borodin <onborodin@gmail.com> 2018 */
 
#include <libopencm3/stm32/rng.h>
 
#include <stdlib.h>
 
void rng_enable_interrupt(void) {
    RNG_CR |= RNG_CR_IE;
}
 
void rng_disable_interrupt(void) {
    RNG_CR &= ~RNG_CR_IE;
}
 
 
#if 0
void rng_enable(void) {
    RNG_CR |= RNG_CR_RNGEN;
}
 
void rng_disable(void) {
    RNG_CR &= ~RNG_CR_RNGEN;
}
#endif
 
uint32_t rng_random(void) {
    static uint32_t last_value;
    static uint32_t new_value;
 
    uint32_t error = 0;
    error = RNG_SR_SEIS | RNG_SR_CEIS;
    while (new_value == last_value) {
        if (((RNG_SR & error) == 0) && ((RNG_SR & RNG_SR_DRDY) == 1)) {
            new_value = RNG_DR;
        }
    }
    last_value = new_value;
    return new_value;
}
 
/* EOF */

random.h

random.h
/* Author, Copyright: Oleg Borodin <onborodin@gmail.com> 2018 */
 
#ifndef _RANDOM_H_ICU_
#define _RANDOM_H_ICU_
 
void rng_enable_interrupt(void);
void rng_disable_interrupt(void);
#if 0
void rng_enable(void);
void rng_disable(void);
#endif
uint32_t rng_random(void);
#endif
 
/* EOF */

rtc4xx.c

rtc4xx.c
/* Author, Copyright: Oleg Borodin <onborodin@gmail.com> 2018 */
 
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/rtc.h>
#include <libopencm3/stm32/pwr.h>
 
#include <stdlib.h>
 
#include <rtc4xx.h>
 
 
/*
  Sample:
    void rtc_init(void) {
        pwr_backup_domain_enable_write();
        rcc_backup_domain_software_reset();
 
        rcc_external_lowspeed_oscillator_enable();
        rcc_rtc_clock_enable();
        rcc_rtc_clock_source_selection(RCC_BDCR_RTCSEL_LSE);
 
        rtc_write_protection_disable();
        rtc_set_calibration_output_1hz();
 
        rtc_write_protection_disable();
        rtc_calibration_output_enable();
 
        rtc_init_mode_enable();
 
        rtc_write_prescaler(0x07, 0xFF);
        rtc_set_24h_format();
 
        rtc_init_mode_disable();
 
        rtc_write_protection_enable();
        pwr_backup_domain_disable_write();
}
 */
 
 
 
void pwr_backup_domain_enable_write(void) {
    PWR_CR |= PWR_CR_DBP;
}
 
void pwr_backup_domain_disable_write(void) {
    PWR_CR &= ~PWR_CR_DBP;
}
 
void rcc_backup_domain_software_reset(void) {
    RCC_BDCR |= RCC_BDCR_BDRST;
    RCC_BDCR &= ~RCC_BDCR_BDRST;
}
 
void rcc_external_lowspeed_oscillator_enable(void) {
    RCC_BDCR |= RCC_BDCR_LSEON;
    while (!(RCC_BDCR & RCC_BDCR_LSERDY));
}
 
void rcc_rtc_clock_enable(void) {
    RCC_BDCR |= RCC_BDCR_RTCEN;
}
 
void rcc_rtc_clock_disable(void) {
    RCC_BDCR &= ~RCC_BDCR_RTCEN;
}
 
 
void rcc_rtc_clock_source_selection(uint32_t source) {
    uint32_t reg = RCC_BDCR;
    reg &= ~(RCC_BDCR_RTCSEL_MASK << RCC_BDCR_RTCSEL_SHIFT);
    reg |= (source & RCC_BDCR_RTCSEL_MASK) << RCC_BDCR_RTCSEL_SHIFT;
    RCC_BDCR = reg;
}
 
void rtc_write_protection_disable(void) {
    RTC_WPR = 0xCA;
    RTC_WPR = 0x53;
}
 
void rtc_write_protection_enable(void) {
    RTC_WPR = 0xFF;
}
 
void rtc_set_calibration_output_1hz(void) {
    RTC_CR |= RTC_CR_COSEL;
}
 
void rtc_set_calibration_output_512hz(void) {
    RTC_CR &= ~RTC_CR_COSEL;
}
 
 
void rtc_calibration_output_enable(void) {
    RTC_CR |= RTC_CR_COE;
}
 
void rtc_calibration_output_disable(void) {
    RTC_CR &= ~RTC_CR_COE;
}
 
 
void rtc_write_prescaler(uint32_t sync, uint32_t async) {
    RTC_PRER = (sync << RTC_PRER_PREDIV_S_SHIFT);
    RTC_PRER |= (async << RTC_PRER_PREDIV_A_SHIFT);
}
 
void rtc_set_24h_format(void) {
    uint32_t reg = RTC_TR;
    reg &= ~RTC_TR_PM;
    RTC_TR = reg;
}
 
void rtc_set_12h_format(void) {
    uint32_t reg = RTC_TR;
    reg |= RTC_TR_PM;
    RTC_TR = reg;
}
 
void rtc_init_mode_enable(void) {
    RTC_ISR |= RTC_ISR_INIT;
    while (!(RTC_ISR & RTC_ISR_INITF));
}
 
void rtc_init_mode_disable(void) {
    RTC_ISR &= ~RTC_ISR_INIT;
    while (RTC_ISR & RTC_ISR_INITF);
}
 
void rtc_register_synchronization(void) {
    RTC_ISR &= ~(RTC_ISR_RSF);
    while (RTC_ISR & RTC_ISR_RSF);
}
 
 
void rtc_set_time_register(uint32_t tr) {
    pwr_backup_domain_enable_write();
    rtc_write_protection_disable();
    rtc_init_mode_enable();
 
    RTC_TR = tr;
 
    rtc_register_synchronization();
    rtc_init_mode_disable();
    rtc_write_protection_enable();
    pwr_backup_domain_disable_write();
}
 
void rtc_set_date_register(uint32_t dr) {
    pwr_backup_domain_enable_write();
    rtc_write_protection_disable();
    rtc_init_mode_enable();
 
    RTC_DR = dr;
 
    rtc_register_synchronization();
    rtc_init_mode_disable();
    rtc_write_protection_enable();
    pwr_backup_domain_disable_write();
}
 
 
/* EOF */

rtc4xx.h

rtc4xx.h
/* Author, Copyright: Oleg Borodin <onborodin@gmail.com> 2018 */
 
#ifndef RTC4XX_H_XYZ
#define RTC4XX_H_XYZ
 
void pwr_backup_domain_enable_write(void);
void pwr_backup_domain_disable_write(void);
void rcc_backup_domain_software_reset(void);
void rcc_external_lowspeed_oscillator_enable(void);
void rcc_rtc_clock_enable(void);
void rcc_rtc_clock_disable(void);
void rcc_rtc_clock_source_selection(uint32_t source);
void rtc_write_protection_disable(void);
void rtc_write_protection_enable(void);
void rtc_set_calibration_output_1hz(void);
void rtc_set_calibration_output_512hz(void);
void rtc_calibration_output_enable(void);
void rtc_calibration_output_disable(void);
void rtc_write_prescaler(uint32_t async, uint32_t sync);
void rtc_set_24h_format(void);
void rtc_set_12h_format(void);
void rtc_init_mode_enable(void);
void rtc_init_mode_disable(void);
void rtc_register_synchronization(void);
void rtc_set_time_register(uint32_t tr);
void rtc_set_date_register(uint32_t dr);
 
#endif
 
/* EOF */

syscall.c

syscall.c
/* Author, Copyright: Oleg Borodin <onborodin@gmail.com> 2018 */
 
#include <stdlib.h>
#include <reent.h>
#include <sys/stat.h>
#include <sys/errno.h>
#include <libopencm3/stm32/usart.h>
#include <errno.h>
 
#include <FreeRTOS.h>
#include <task.h>
#include <queue.h>
 
#include <syscall.h>
 
extern QueueHandle_t usart1_q;
 
#undef errno
extern int errno;
 
char *__env[1] = { 0 };
 
char **environ = __env;
 
int _execve(char *name, char **argv, char **env) {
    errno = ENOMEM;
    return -1;
}
 
int _fork(void) {
    errno = EAGAIN;
    return -1;
}
 
int _getpid(void) {
    return 1;
}
 
int _kill(int pid, int sig) {
    errno = EINVAL;
    return -1;
}
 
int _exit() {
    while(1);
}
 
int _isatty(int file) {
    return 1;
}
 
int _fstat(int file, struct stat *st) {
    st->st_mode = S_IFCHR;
    return 0;
}
 
int _link(char *old, char *new) {
    errno = EMLINK;
    return -1;
}
 
int _lseek(int file, int ptr, int dir) {
    return 0;
}
 
int _open(const char *name, int flags, int mode) {
    return -1;
}
 
#define STDIN   0
#define STDOUT  1
#define STDERR  3
 
 
int _read(int file, char *ptr, int len) {
    uint8_t data = 0;
    int i = 0;
    while (i < len) {
        ptr[i++] = 0;
    }
    return i;
}
 
int _write(int file, char *ptr, int len) {
    int i;
    if (file == STDOUT | file == STDERR) {
        for (i = 0; i < len; i++) {
            xQueueSend(usart1_q, &ptr[i], portMAX_DELAY);
        }
        return len;
    }
    return 0;
}
 
int _stat(char *file, struct stat *st) {
    st->st_mode = S_IFCHR;
    return 0;
}
 
int _close(int file) {
    return -1;
}
 
 
int _times(struct tms *buf) {
    return -1;
}
 
int _unlink(char *name) {
    errno = ENOENT;
    return -1;
}
 
int _wait(int *status) {
    errno = ECHILD;
    return -1;
}
 
 
void *_sbrk(int incr) {
 
    extern const void *_heap;
    extern const void *_eheap;
 
    void *prev_heap_ptr;
    static void *heap_ptr;
 
    if (heap_ptr == 0) {
        heap_ptr = (void *)&_heap;
    }
 
    void * next_heap_ptr = heap_ptr + incr;
 
    if (next_heap_ptr >= (void *) &_eheap) {
        errno = ENOMEM;
        return NULL;
    }
 
    prev_heap_ptr = heap_ptr;
    heap_ptr = next_heap_ptr;
 
    return (void *)prev_heap_ptr;
}
 
/* EOF */

syscall.h

syscall.h
#include <stdlib.h>
 
__attribute__((always_inline)) static inline uint32_t __get_LR(void) { 
    register uint32_t result;
    __asm volatile ("mov %0, lp\n" : "=r" (result)); 
    return result;
}
 
__attribute__((always_inline)) static inline uint32_t __get_SP(void) { 
    register uint32_t result;
    __asm volatile ("mov %0, sp\n" : "=r" (result)); 
    return result;
}
 
/* EOF */

uastdio.c

uastdio.c
/* Author, Copyright: Oleg Borodin <onborodin@gmail.com> 2018 */
 
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <wctype.h>
#include <ctype.h>
#include <locale.h>
#include <wchar.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
 
 
#include <syscall.h>
#include <buffer.h>
 
#include <uastdio.h>
 
#define BUFFER_SIZE 256
 
buffer_t stdin_buffer;
buffer_t stdout_buffer;
 
static uint8_t stdin_buffer_data[BUFFER_SIZE];
static uint8_t stdout_buffer_data[BUFFER_SIZE];
 
void io_setup(void) {
    buffer_init(&stdin_buffer, stdin_buffer_data, sizeof(stdin_buffer_data));
    buffer_init(&stdout_buffer, stdout_buffer_data, sizeof(stdout_buffer_data));
}
 
/* EOF */

uastdio.h

uastdio.h
#ifndef UART_STDIO_H_ITU 
#define UART_STDIO_H_ITU
 
#define BUFFER_SIZE 256
 
extern buffer_t stdin_buffer;
extern buffer_t stdout_buffer;
 
void io_setup(void);
 
#endif

xpt2046.c

xpt2046.c
/* Author, Copyright: Oleg Borodin <onborodin@gmail.com> 2018 */
 
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/spi.h>
 
#include <stdlib.h>
#include <xpt2046.h>
 
void ts_spi_setup(void) {
 
    gpio_mode_setup(TS_SPI_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE,
                    TS_SCL_PIN | TS_CS_PIN | TS_MO_PIN | TS_MI_PIN);
    gpio_set_af(TS_SPI_PORT, GPIO_AF5, TS_SCL_PIN | TS_CS_PIN | TS_MO_PIN | TS_MI_PIN);
    gpio_set_output_options(TS_SPI_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,
                            TS_MO_PIN | TS_SCL_PIN | TS_CS_PIN);
 
    spi_reset(TS_SPI);
 
    spi_disable(TS_SPI);
    spi_init_master(TS_SPI,
                    SPI_CR1_BAUDRATE_FPCLK_DIV_128,
                    SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE,
                    SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT, SPI_CR1_MSBFIRST);
 
    spi_set_full_duplex_mode(TS_SPI);
    spi_disable_software_slave_management(TS_SPI);
    spi_set_nss_high(TS_SPI);
    spi_set_master_mode(TS_SPI);
    spi_enable_ss_output(TS_SPI);
    spi_disable_crc(TS_SPI);
 
    spi_enable(TS_SPI);
}
 
 
 
uint16_t ts_get_data16(uint8_t command) {
    spi_xfer(TS_SPI, command);
    uint16_t res1 = spi_xfer(TS_SPI, 0x00);
    uint16_t res2 = spi_xfer(TS_SPI, 0x00);
    return ((res1 << 8) | (res2 && 0xFF)) >> 4;
}
 
 
uint16_t ts_get_x_raw(void) {
    int16_t res = 0;
    for (uint8_t i = 0; i < TS_EVAL_COUNT; i++) {
        res += ts_get_data16(TS_COMM_X_DPOS);
    }
    return res / TS_EVAL_COUNT;
}
 
uint16_t ts_get_y_raw(void) {
    int16_t res = 0;
    for (uint8_t i = 0; i < TS_EVAL_COUNT; i++) {
        res += ts_get_data16(TS_COMM_Y_DPOS);
    }
    return res / TS_EVAL_COUNT;
}
 
uint16_t ts_get_x(void) {
 
    uint16_t res = ts_get_x_raw();
 
    if (res >= TS_X_MAX_EDGE)
        return TS_X_SCREEN_MAX;
    if (res <= TS_X_MIN_EDGE)
        return TS_X_SCREEN_MIN;
 
    res = (TS_X_SCREEN_MAX * (res - TS_X_MIN_EDGE)) / (TS_X_MAX_EDGE - TS_X_MIN_EDGE);
    return TS_X_SCREEN_MAX - res;
 
}
 
uint16_t ts_get_y(void) {
 
    uint16_t res = ts_get_y_raw();
 
    if (res >= TS_Y_MAX_EDGE)
        return TS_Y_SCREEN_MIN;
    if (res <= TS_Y_MIN_EDGE)
        return TS_Y_SCREEN_MIN;
 
    res = (TS_Y_SCREEN_MAX * (res - TS_Y_MIN_EDGE)) / (TS_Y_MAX_EDGE - TS_Y_MIN_EDGE);
    return res;
}
 
uint16_t ts_get_z1_raw(void) {
    uint16_t res = 0;
    for (uint8_t i = 0; i < TS_EVAL_COUNT; i++) {
        res += ts_get_data16(TS_COMM_Z1_POS);
    }
    return res / TS_EVAL_COUNT;
}
 
uint16_t ts_get_z2_raw(void) {
    uint16_t res = 0;
    for (uint8_t i = 0; i < TS_EVAL_COUNT; i++) {
        res += ts_get_data16(TS_COMM_Z2_POS);
    }
    return res / TS_EVAL_COUNT;
}
 
/* EOF */

xpt2046.h

xpt2046.h
/* Author, Copyright: Oleg Borodin <onborodin@gmail.com> 2018 */
 
#ifndef XPT2046_H_XYZ
#define XPT2046_H_XYZ
 
#define TS_SPI          SPI2
#define TS_SPI_PORT     GPIOB
#define TS_MO_PIN       GPIO15
#define TS_MI_PIN       GPIO14
#define TS_SCL_PIN      GPIO13
#define TS_CS_PIN       GPIO12
 
 
#define TS_SB       (1 << 7)
#define TS_A2       (1 << 6)
#define TS_A1       (1 << 5)
#define TS_A0       (1 << 4)
#define TS_MODE8    (1 << 3)
#define TS_MODE12   (0 << 3)
#define TS_SER      (1 << 2)
#define TS_DFR      (0 << 2)
#define TS_PD1      (1 << 1)
#define TS_PD0      (1 << 0)
 
#define TS_COMM_Y_SPOS    (TS_MODE12 | TS_SER | TS_SB | TS_A0)
#define TS_COMM_X_SPOS    (TS_MODE12 | TS_SER | TS_SB | TS_A2 | TS_A0)
#define TS_COMM_Y_DPOS    (TS_MODE12 | TS_SB | TS_A0)
#define TS_COMM_X_DPOS    (TS_MODE12 | TS_SB | TS_A2 | TS_A0)
#define TS_COMM_Z1_POS    (TS_MODE12 | TS_SB | TS_A1 | TS_A0)
#define TS_COMM_Z2_POS    (TS_MODE12 | TS_SB | TS_A2)
#define TS_COMM_TEMP      (TS_MODE12 | TS_SB)
 
#define TS_EVAL_COUNT 5
 
#define TS_X_MIN_EDGE 128
#define TS_X_MAX_EDGE 1904
#define TS_Y_MIN_EDGE 96
#define TS_Y_MAX_EDGE 1856
 
#define TS_X_SCREEN_MIN 0
#define TS_X_SCREEN_MAX 239
#define TS_Y_SCREEN_MIN 0
#define TS_Y_SCREEN_MAX 319
 
void ts_spi_setup(void);
uint16_t ts_get_data16(uint8_t command);
uint16_t ts_get_x_raw(void);
uint16_t ts_get_y_raw(void);
uint16_t ts_get_x(void);
uint16_t ts_get_y(void);
uint16_t ts_get_z1_raw(void);
uint16_t ts_get_z2_raw(void);
 
#endif
 
/* EOF */

master.ld

/* Generic linker script for STM32 targets using libopencm3. */
 
MEMORY {
    FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K
    CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K
    SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128K
}
 
/* Enforce emmition of the vector table. */
EXTERN(vector_table)
 
/* Define the entry point of the output file. */
ENTRY(reset_handler)
 
SECTIONS {
    .text : {
        KEEP(*(.vectors))       /* Vector table */
        *(.text*)               /* Program code */
        . = ALIGN(4);
        *(.rodata*)             /* Read-only data */
        . = ALIGN(4);
    } >FLASH
 
    /* C++ Static constructors/destructors, also used for __attribute__
     * ((constructor)) and the likes */
 
    .preinit_array : {
        . = ALIGN(4);
        __preinit_array_start = .;
        KEEP (*(.preinit_array))
        __preinit_array_end = .;
    } >FLASH
 
    .init_array : {
        . = ALIGN(4);
        __init_array_start = .;
        KEEP (*(SORT(.init_array.*)))
        KEEP (*(.init_array))
        __init_array_end = .;
    } >FLASH
 
    .fini_array : {
        . = ALIGN(4);
        __fini_array_start = .;
        KEEP (*(.fini_array))
        KEEP (*(SORT(.fini_array.*)))
        __fini_array_end = .;
    } >FLASH
 
    /*
     * Another section used by C++ stuff, appears when using newlib with
     * 64bit (long long) printf support
     */
 
    .ARM.extab : {
        *(.ARM.extab*)
    } >FLASH
 
    .ARM.exidx : {
        __exidx_start = .;
        *(.ARM.exidx*)
        __exidx_end = .;
    } >FLASH
 
    . = ALIGN(4);
    __text_end = .;
 
    .data : {
        __data_start = .;
        _sdata = .;
        _data = .;
        *(.data*)               /* Read-write initialized data */
        . = ALIGN(4);
        __data_end = . ;
        _edata = . ;
 
    } >SRAM AT >FLASH
 
    _data_loadaddr = LOADADDR(.data);
 
    .bss : {
        __bss_start = .;
        __bss_start__ = .;
        *(.bss*)                /* Read-write zero initialized data */
        *(COMMON)
        . = ALIGN(4);
        __bss_end = .;
        __bss_end__ = .;
        _ebss = .;
 
    } >SRAM
 
    /*
     * The .eh_frame section appears to be used for C++ exception handling.
     * You may need to fix this if you're using C++.
     */
 
    /* /DISCARD/ : { *(.eh_frame) } */
 
    . = ALIGN(4);
    __end = .;
    _heap = .;
}
 
PROVIDE(__rtos_heap_size = LENGTH(SRAM) - 2048);
PROVIDE(_eheap = ORIGIN(SRAM) + LENGTH(SRAM));
PROVIDE(_stack = ORIGIN(SRAM) + LENGTH(SRAM));
 
/* EOF */