mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-18 16:27:34 +01:00
Big cleanup
This commit is contained in:
11
Makefile
11
Makefile
@@ -14,11 +14,14 @@ CFLAGS += -target thumbv7em-unknown-eabi -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -ffre
|
||||
#CFLAGS += -Os -fdata-sections -ffunction-sections
|
||||
#LDFLAGS += --gc-sections
|
||||
|
||||
objs := boot/crt0.o
|
||||
objs := platform/stm32f429/boot/crt0.o
|
||||
objs += external/freertos/tasks.o external/freertos/list.o external/freertos/queue.o external/freertos/portable/GCC/ARM_CM4F/port.o external/freertos/portable/MemMang/heap_1.o
|
||||
objs += external/newlib/libc/string/memset.o external/newlib/libc/string/memcpy.o
|
||||
|
||||
objs += platform/stm32f429/boot/isr.o platform/stm32f429/registers/gpio.o platform/stm32f429/registers/rcc.o platform/stm32f429/registers/spi.o platform/stm32f429/spi.o platform/stm32f429/pinmux.o
|
||||
objs += platform/stm32f429/boot/isr.o platform/stm32f429/registers/gpio.o platform/stm32f429/registers/rcc.o platform/stm32f429/registers/spi.o
|
||||
|
||||
objs += platform/stm32f429/init.o platform/stm32f429/init_lcd.o
|
||||
objs += platform/ili9341/ili9341.o
|
||||
|
||||
default: clean boot.elf
|
||||
|
||||
@@ -39,9 +42,9 @@ boot.bin: boot.elf
|
||||
@echo "OBJCOPY $@"
|
||||
@$(OBJCOPY) -O binary boot.elf boot.bin
|
||||
|
||||
boot.elf: $(objs) src/lcd_spi.o
|
||||
boot.elf: $(objs)
|
||||
@echo "LD $@"
|
||||
@$(LD) -T platform/stm32f429/boot/flash.ld $(objs) src/lcd_spi.o -o $@
|
||||
@$(LD) -T platform/stm32f429/boot/flash.ld $(objs) -o $@
|
||||
|
||||
%.o: %.c
|
||||
@echo "CC $@"
|
||||
|
||||
8
README_APPS.txt
Normal file
8
README_APPS.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
On what foundation do the apps rely?
|
||||
|
||||
-> dynamic memory allocation -> Not obious, *maybe* a malloc implementation can be provided
|
||||
-> direct access to a framebuffer
|
||||
-> Use of a graphic library to write to the framebuffer (no "context")
|
||||
-> A way to receive keyboard input.
|
||||
|
||||
That's it!
|
||||
1
external/NEWLIB.txt
vendored
1
external/NEWLIB.txt
vendored
@@ -1,2 +1,3 @@
|
||||
- Using memcpy and memset
|
||||
- using <string.h>, <stdlib.h>, and <stdint.h>
|
||||
- using <stdbool.h> for "bool"
|
||||
|
||||
@@ -7,6 +7,7 @@ load boot.elf
|
||||
# Tell OpenOCD to reset and halt
|
||||
monitor reset halt
|
||||
|
||||
break main
|
||||
break init
|
||||
break _halt
|
||||
|
||||
continue
|
||||
|
||||
116
platform/ili9341/ili9341.c
Normal file
116
platform/ili9341/ili9341.c
Normal file
@@ -0,0 +1,116 @@
|
||||
#include "ili9341.h"
|
||||
#include <stdint.h>
|
||||
//#include <platform/stm32f429/registers/gpio.h> //FIXME
|
||||
|
||||
enum {
|
||||
COMMAND_MODE = 0,
|
||||
DATA_MODE = 1,
|
||||
DELAY_MODE = 2
|
||||
};
|
||||
|
||||
enum {
|
||||
NOP = 0x00, // No operation
|
||||
SWRESET = 0x01, // Software reset
|
||||
RDDIDIF = 0x04, // Read display identification information
|
||||
RDDST = 0x09, // Read display status
|
||||
RDDPM = 0x0A, // Read display power mode
|
||||
SLPOUT = 0x11, // Sleep out
|
||||
DISPOFF = 0x28, // Display off
|
||||
DISPON = 0x29, // Display on
|
||||
RAMWR = 0x2C, // Memory write
|
||||
PIXSET = 0x3A, // Pixel format set
|
||||
FRMCTR1 = 0xB1A // Frame rate control in normal/full-color mode
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
char mode;
|
||||
char payload;
|
||||
} instruction_t;
|
||||
|
||||
#define COMMAND(c) (instruction_t){.mode = (char)COMMAND_MODE, .payload = (char)c}
|
||||
#define DATA(d) (instruction_t){.mode = (char)DATA_MODE, .payload = (char)d}
|
||||
#define DELAY(m) (instruction_t){.mode = (char)DELAY_MODE, .payload = (char)m}
|
||||
|
||||
static instruction_t initialisation_sequence[] = {
|
||||
COMMAND(SWRESET), DELAY(5), // Software reset, then wait 5ms
|
||||
COMMAND(DISPOFF),
|
||||
|
||||
// FIXME: Ad-hoc skipping extended registers, we're not using it
|
||||
|
||||
// Pixel format: 16bpp, both on RGB and SPI
|
||||
COMMAND(PIXSET), DATA(0x55),
|
||||
|
||||
/* FIXME: Useless: extended
|
||||
// Framerate:
|
||||
COMMAND(FRMCTR1), DATA(0x00), DATA(0x1B),
|
||||
*/
|
||||
|
||||
// Gamma
|
||||
//FIXME
|
||||
|
||||
// Display
|
||||
// Entry mode set, skipped
|
||||
COMMAND(SLPOUT), DELAY(100),
|
||||
|
||||
COMMAND(DISPON), DELAY(20),
|
||||
|
||||
COMMAND(NOP) // Used to mark the end of the init sequence
|
||||
};
|
||||
|
||||
void perform_instruction(ili9341_t * c, instruction_t * instruction) {
|
||||
if (instruction->mode == DELAY_MODE) {
|
||||
// FIXME: Should sleep instruction->payload miliseconds
|
||||
for (int i = 0; i < 800*instruction->payload; i++) {
|
||||
}
|
||||
} else {
|
||||
c->data_command_pin_write(instruction->mode);
|
||||
c->spi_write(&instruction->payload, 1);
|
||||
}
|
||||
}
|
||||
|
||||
#define X 0xFFFF
|
||||
uint16_t pattern[64] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, X, X, X, X, 0, 0,
|
||||
0, X, 0, 0, 0, 0, X, 0,
|
||||
0, 0, X, X, X, 0, X, 0,
|
||||
0, X, 0, 0, 0, X, 0, 0,
|
||||
0, X, 0, 0, 0, X, 0, 0,
|
||||
0, 0, X, X, X, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
#undef X
|
||||
|
||||
void ili9341_initialize(ili9341_t * c) {
|
||||
// Falling edge on CSX
|
||||
c->chip_select_pin_write(0);
|
||||
|
||||
// Send all the initialisation_sequence
|
||||
instruction_t * instruction = initialisation_sequence;
|
||||
while (!(instruction->mode == COMMAND_MODE && instruction->payload == NOP)) {
|
||||
perform_instruction(c, instruction++);
|
||||
}
|
||||
|
||||
perform_instruction(c, &COMMAND(RAMWR));
|
||||
|
||||
c->data_command_pin_write(DATA_MODE);
|
||||
|
||||
for (int j=0;j<320;j++) {
|
||||
for (int i =0;i<30;i++) {
|
||||
c->spi_write(((char *)pattern + sizeof(uint16_t)*8*(j%8)), 8*sizeof(uint16_t));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
//FIXME
|
||||
GPIO_MODER(GPIOF)->MODER9 = GPIO_MODE_INPUT;
|
||||
|
||||
for (int i = 0; i<1000; i++) {}
|
||||
|
||||
for (int i=0; i < 10; i++) {
|
||||
send_data(c, 'A');
|
||||
}*/
|
||||
}
|
||||
|
||||
void ili9341_set_gamma(ili9341_t * c) {
|
||||
}
|
||||
19
platform/ili9341/ili9341.h
Normal file
19
platform/ili9341/ili9341.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef PLATFORM_ILI9341_H
|
||||
#define PLATFORM_ILI9341_H 1
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* This is the ILI9341 driver
|
||||
*
|
||||
* It just needs to be pointed to a "write" function
|
||||
*/
|
||||
typedef struct {
|
||||
void (*chip_select_pin_write)(bool pin_state);
|
||||
void (*data_command_pin_write)(bool pin_state);
|
||||
void (*spi_write)(char * data, size_t size);
|
||||
} ili9341_t;
|
||||
|
||||
void ili9341_initialize(ili9341_t * controller);
|
||||
void ili9341_set_gamma(ili9341_t * controller);
|
||||
#endif
|
||||
@@ -7,7 +7,12 @@ extern const void * _data_section_end_ram;
|
||||
extern const void * _bss_section_start_ram;
|
||||
extern const void * _bss_section_end_ram;
|
||||
|
||||
int main(int argc, char * argv[]);
|
||||
void init();
|
||||
|
||||
void _halt() {
|
||||
while (1) {
|
||||
}
|
||||
}
|
||||
|
||||
void _start(void) {
|
||||
// This is where execution starts after reset.
|
||||
@@ -26,10 +31,7 @@ void _start(void) {
|
||||
size_t bssSectionLength = (char *)&_bss_section_end_ram - (char *)&_bss_section_start_ram;
|
||||
memset(&_bss_section_start_ram, 0, bssSectionLength);
|
||||
|
||||
main(0, 0x0);
|
||||
}
|
||||
init();
|
||||
|
||||
void _halt(void) {
|
||||
while (1) {
|
||||
}
|
||||
_halt();
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
#ifndef STM32F429_GPIO_H
|
||||
#define STM32F429_GPIO_H 1
|
||||
|
||||
typedef enum {
|
||||
STM32_GPIO_GROUP_A = 0,
|
||||
STM32_GPIO_GROUP_B = 1,
|
||||
STM32_GPIO_GROUP_C = 2,
|
||||
STM32_GPIO_GROUP_D = 3,
|
||||
STM32_GPIO_GROUP_E = 4,
|
||||
STM32_GPIO_GROUP_F = 5,
|
||||
STM32_GPIO_GROUP_G = 6,
|
||||
STM32_GPIO_GROUP_H = 7,
|
||||
STM32_GPIO_GROUP_I = 8,
|
||||
STM32_GPIO_GROUP_J = 9,
|
||||
STM32_GPIO_GROUP_K = 10
|
||||
} stm32_gpio_group_t;
|
||||
|
||||
typedef struct {
|
||||
stm32_gpio_group_t group:4;
|
||||
unsigned int number:4;
|
||||
} stm32_pin_t;
|
||||
|
||||
#define STM32_PIN(g,i) (stm32_pin_t){.group = STM32_GPIO_GROUP_##g, .number = i}
|
||||
|
||||
#endif
|
||||
5
platform/stm32f429/init.c
Normal file
5
platform/stm32f429/init.c
Normal file
@@ -0,0 +1,5 @@
|
||||
#include "init_lcd.h"
|
||||
|
||||
void init() {
|
||||
init_lcd();
|
||||
}
|
||||
154
platform/stm32f429/init_lcd.c
Normal file
154
platform/stm32f429/init_lcd.c
Normal file
@@ -0,0 +1,154 @@
|
||||
/* LCD Initialisation code
|
||||
*
|
||||
* The LCD panel is connected via two interfaces: RGB and SPI. The SPI interface
|
||||
* is used to configure the panel, and can be used to send pixel data.
|
||||
* For higher performances, the RGB interface can be used to send pixel data.
|
||||
*
|
||||
* Here is the connection this file assumes:
|
||||
*
|
||||
* LCD_SPI | STM32 | Role
|
||||
* ---------+-------+-----
|
||||
* RESET | NRST |
|
||||
* CSX | PC2 | Chip enable input
|
||||
* DCX | PD13 | Selects "command" or data mode
|
||||
* SCL | PF7 | SPI clock
|
||||
* SDI/SDO | PF9 | SPI data
|
||||
*
|
||||
* The entry point is init_lcd();
|
||||
*
|
||||
* Some info regarding the built-in LCD panel of the STM32F429I Discovery:
|
||||
* -> The pin EXTC of the ili9341 is not connected to Vdd. It reads as "0", and
|
||||
* therefore extended registers are not available. Those are 0xB0-0xCF and 0xE0
|
||||
* - 0xFF. Apparently this means we cannot read the display ID (RDDIDIF).
|
||||
* That's wat ST says in stm32f429i_discovery_lcd.c.
|
||||
*/
|
||||
|
||||
#include "registers/rcc.h"
|
||||
#include "registers/gpio.h"
|
||||
#include "registers/spi.h"
|
||||
#include <platform/ili9341/ili9341.h>
|
||||
|
||||
static void spi_5_write(char * data, size_t size);
|
||||
static void gpio_c2_write(bool pin_state);
|
||||
static void gpio_d13_write(bool pin_state);
|
||||
|
||||
ili9341_t sPanel = {
|
||||
.chip_select_pin_write = gpio_c2_write,
|
||||
.data_command_pin_write = gpio_d13_write,
|
||||
.spi_write = spi_5_write
|
||||
};
|
||||
|
||||
static void init_lcd_gpio();
|
||||
static void init_lcd_spi();
|
||||
static void init_lcd_panel();
|
||||
|
||||
void init_lcd() {
|
||||
/* This routine is responsible for initializing the LCD panel.
|
||||
* Its interface with the outer world is the framebuffer: after execution of
|
||||
* this routine, everyone can expect to write to the LCD by writing to the
|
||||
* framebuffer. */
|
||||
|
||||
/* The LCD panel is connected on GPIO pins. Let's configure them. */
|
||||
init_lcd_gpio();
|
||||
|
||||
/* According to our GPIO config, we send commands to the LCD panel over SPI on
|
||||
* port SPI5. Let's configure it. */
|
||||
init_lcd_spi();
|
||||
|
||||
/* configure display */
|
||||
init_lcd_panel();
|
||||
|
||||
/* Last but not least */
|
||||
//TODO: init_lcd_dma();
|
||||
}
|
||||
|
||||
#pragma mark - GPIO initialization
|
||||
|
||||
static void init_lcd_gpio_clocks() {
|
||||
// We are using groups C, D, and F. Let's enable their clocks
|
||||
RCC_AHB1ENR->GPIOCEN = 1;
|
||||
RCC_AHB1ENR->GPIODEN = 1;
|
||||
RCC_AHB1ENR->GPIOFEN = 1;
|
||||
}
|
||||
|
||||
static void init_lcd_gpio_modes() {
|
||||
// PC2 and PD13 are controlled directly
|
||||
GPIO_MODER(GPIOC)->MODER2 = GPIO_MODE_OUTPUT;
|
||||
GPIO_MODER(GPIOD)->MODER13 = GPIO_MODE_OUTPUT;
|
||||
|
||||
// PF7 and PF9 are used for an alternate function (in that case, SPI)
|
||||
GPIO_MODER(GPIOF)->MODER7 = GPIO_MODE_ALTERNATE_FUNCTION;
|
||||
GPIO_MODER(GPIOF)->MODER9 = GPIO_MODE_ALTERNATE_FUNCTION;
|
||||
|
||||
// More precisely, PF7 and PF9 are doing SPI-SCL and SPI-SDO/SDO.
|
||||
// This corresponds to Alternate Function 5 using SPI port 5
|
||||
// (See STM32F429 p78)
|
||||
GPIO_AFRL(GPIOF)->AFRL7 = GPIO_AF_AF5; // Pin 7 is in the "low" register
|
||||
GPIO_AFRH(GPIOF)->AFRH9 = GPIO_AF_AF5; // and pin 9 in the "high" one
|
||||
|
||||
// For debug
|
||||
/*
|
||||
GPIO_MODER(GPIOF)->MODER6 = GPIO_MODE_ALTERNATE_FUNCTION;
|
||||
GPIO_MODER(GPIOF)->MODER8 = GPIO_MODE_ALTERNATE_FUNCTION;
|
||||
GPIO_AFRL(GPIOF)->AFRL6 = GPIO_AF_AF5; // and pin 9 in the "high" one
|
||||
GPIO_AFRH(GPIOF)->AFRH8 = GPIO_AF_AF5; // and pin 9 in the "high" one
|
||||
*/
|
||||
}
|
||||
|
||||
static void init_lcd_gpio() {
|
||||
/* The LCD panel is connected on GPIO pins. Let's configure them. */
|
||||
init_lcd_gpio_clocks();
|
||||
init_lcd_gpio_modes();
|
||||
}
|
||||
|
||||
void gpio_c2_write(bool pin_state) {
|
||||
GPIO_ODR(GPIOC)->ODR2 = pin_state;
|
||||
}
|
||||
|
||||
void gpio_d13_write(bool pin_state) {
|
||||
GPIO_ODR(GPIOD)->ODR13 = pin_state;
|
||||
}
|
||||
|
||||
#pragma mark - SPI initialization
|
||||
|
||||
static void init_lcd_spi() {
|
||||
// Enable the SPI5 clock (SPI5 lives on the APB2 bus)
|
||||
RCC_APB2ENR->SPI5EN = 1;
|
||||
|
||||
// Configure the SPI port
|
||||
// Using a C99 compound litteral. C99 guarantees all non-set values are zero
|
||||
*SPI_CR1(SPI5) = (SPI_CR1_t){
|
||||
.BIDIMODE = 1,
|
||||
.BIDIOE = 1,
|
||||
.MSTR = 1,
|
||||
.DFF = SPI_DFF_8_BITS,
|
||||
.CPOL = 0,
|
||||
.CPHA = 0,
|
||||
.BR = SPI_BR_DIV_2,
|
||||
.SSM = 1,
|
||||
.SSI = 1,
|
||||
.LSBFIRST = 0, // Send the most significant bit first
|
||||
.SPE = 1
|
||||
};
|
||||
}
|
||||
|
||||
static void spi_5_write(char * data, size_t size) {
|
||||
volatile SPI_SR_t * spi_status = SPI_SR(SPI5);
|
||||
volatile SPI_DR_t * spi_data_register = SPI_DR(SPI5);
|
||||
|
||||
while (spi_status->BSY != 0) {
|
||||
}
|
||||
for (size_t i=0; i<size; i++) {
|
||||
*spi_data_register = data[i];
|
||||
while (spi_status->TXE == 0) {
|
||||
}
|
||||
}
|
||||
while (spi_status->BSY != 0) {
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Panel initialization
|
||||
|
||||
void init_lcd_panel() {
|
||||
ili9341_initialize(&sPanel);
|
||||
}
|
||||
1
platform/stm32f429/init_lcd.h
Normal file
1
platform/stm32f429/init_lcd.h
Normal file
@@ -0,0 +1 @@
|
||||
void init_lcd();
|
||||
@@ -1,12 +0,0 @@
|
||||
#include "pinmux.h"
|
||||
|
||||
void stm32_configure_pin(stm32_pin_t pin, stm32_pin_function_t function) {
|
||||
// GPIOE = pin.group;
|
||||
// high_or_low = pin.number > 8 ? high : low;
|
||||
|
||||
// alt_fun_number = AlternateFunctions[pin][function];
|
||||
// Step 1 -> Figure the Alternate Function (1,2,3,4)
|
||||
// Step 2 -> Grab the mode register
|
||||
// GPIO_AFRH(GPIOE)->AFRH12 = GPIO_AF_AF5;
|
||||
}
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
#ifndef STM32F429_PINMUX_H
|
||||
#define STM32F429_PINMUX_H 1
|
||||
|
||||
#include "gpio.h"
|
||||
|
||||
/* How to use ?
|
||||
*
|
||||
* configure_pin(PB11, TIM2_CH4);
|
||||
* That's it!
|
||||
* Who uses this?
|
||||
* platform/spi for example:
|
||||
* spi_init(SPI2)
|
||||
* -> NO. BAD IDEA. PINMUX has nothing to do with SPI per-se. */
|
||||
|
||||
/* Note that the table is pretty large
|
||||
* Not using it in production might be an idea.
|
||||
* Just don't use "stm32_configure_pin", but address registers manually
|
||||
* and the linker will do its job. */
|
||||
|
||||
typedef enum {
|
||||
STM32_BUS_SYS,
|
||||
STM32_BUS_TIM1,
|
||||
STM32_BUS_TIM2,
|
||||
STM32_BUS_TIM3,
|
||||
STM32_BUS_TIM4,
|
||||
STM32_BUS_TIM5,
|
||||
STM32_BUS_TIM8,
|
||||
STM32_BUS_TIM9,
|
||||
STM32_BUS_TIM10,
|
||||
STM32_BUS_TIM11,
|
||||
STM32_BUS_TIM12,
|
||||
STM32_BUS_TIM13,
|
||||
STM32_BUS_SPI1,
|
||||
STM32_BUS_SPI2,
|
||||
STM32_BUS_SPI3
|
||||
} stm32_bus_t;
|
||||
|
||||
typedef enum {
|
||||
SPI_WIRE_NSS = 0,
|
||||
SPI_WIRE_SCK = 1,
|
||||
SPI_WIRE_MISO = 2,
|
||||
SPI_WIRE_MOSI = 3,
|
||||
|
||||
USART_WIRE_CK = 0,
|
||||
USART_WIRE_RX = 1,
|
||||
USART_WIRE_TX = 2,
|
||||
USART_WIRE_CTS = 3,
|
||||
USART_WIRE_RTS = 4
|
||||
} stm32_wire_t;
|
||||
|
||||
typedef struct {
|
||||
stm32_bus_t bus:4; // SPI2
|
||||
stm32_wire_t wire:4; // MISO
|
||||
} stm32_pin_function_t;
|
||||
|
||||
|
||||
#define STM32_PIN_FUNCTION(b,i,r) (stm32_pin_function_t){.bus = STM32_BUS_##b##i, .wire = b##_WIRE_##r}
|
||||
#define P(b,i,r) STM32_PIN_FUNCTION(b,i,r)
|
||||
|
||||
stm32_pin_function_t AlternateFunctionMapping[11*16][16] = {
|
||||
// This comes from the STM32F429 datasheet
|
||||
// Page 73 to 83
|
||||
//{X, P(SPI2,MISO), X, X, X},
|
||||
//{{}, {}, {.bus = SPI2, .role = MOSI}},
|
||||
{{}, P(SPI,2,MISO),{}},
|
||||
{},
|
||||
};
|
||||
|
||||
#undef P
|
||||
|
||||
// Sample call:
|
||||
// stm32_configure_pin(STM32_PIN(A,10), STM32_PIN_FUNCTION(SPI,2,MISO));
|
||||
|
||||
void stm32_configure_pin(stm32_pin_t pin, stm32_pin_function_t function);
|
||||
|
||||
#endif
|
||||
@@ -1,3 +0,0 @@
|
||||
#include "registers/gpio.h"
|
||||
#include "registers/rcc.h"
|
||||
#include "registers/spi.h"
|
||||
@@ -23,7 +23,7 @@
|
||||
#define GPIO_AFRL_OFFSET 0x20
|
||||
#define GPIO_AFRH_OFFSET 0x24
|
||||
|
||||
char * GPIO_REGISTER_ADDRESS(stm32_gpio_group_t gpio_group, int registerOffset) {
|
||||
char * GPIO_REGISTER_ADDRESS(GPIO_GROUP_t gpio_group, int registerOffset) {
|
||||
char * gpioBaseAddress[11] = {
|
||||
(char *)GPIOA_BASE, (char *)GPIOB_BASE, (char *)GPIOC_BASE,
|
||||
(char *)GPIOD_BASE, (char *)GPIOE_BASE, (char *)GPIOF_BASE,
|
||||
@@ -33,42 +33,42 @@ char * GPIO_REGISTER_ADDRESS(stm32_gpio_group_t gpio_group, int registerOffset)
|
||||
return gpioBaseAddress[gpio_group] + registerOffset;
|
||||
}
|
||||
|
||||
GPIO_MODER_t * GPIO_MODER(stm32_gpio_group_t gpio_group) {
|
||||
GPIO_MODER_t * GPIO_MODER(GPIO_GROUP_t gpio_group) {
|
||||
return (GPIO_MODER_t *)GPIO_REGISTER_ADDRESS(gpio_group, GPIO_MODER_OFFSET);
|
||||
}
|
||||
|
||||
GPIO_OTYPER_t * GPIO_OTYPER(stm32_gpio_group_t gpio_group) {
|
||||
GPIO_OTYPER_t * GPIO_OTYPER(GPIO_GROUP_t gpio_group) {
|
||||
return (GPIO_OTYPER_t *)GPIO_REGISTER_ADDRESS(gpio_group, GPIO_OTYPER_OFFSET);
|
||||
}
|
||||
|
||||
GPIO_OSPEEDR_t * GPIO_OSPEEDR(stm32_gpio_group_t gpio_group) {
|
||||
GPIO_OSPEEDR_t * GPIO_OSPEEDR(GPIO_GROUP_t gpio_group) {
|
||||
return (GPIO_OSPEEDR_t *)GPIO_REGISTER_ADDRESS(gpio_group, GPIO_OSPEEDR_OFFSET);
|
||||
}
|
||||
|
||||
GPIO_PUPDR_t * GPIO_PUPDR(stm32_gpio_group_t gpio_group) {
|
||||
GPIO_PUPDR_t * GPIO_PUPDR(GPIO_GROUP_t gpio_group) {
|
||||
return (GPIO_PUPDR_t *)GPIO_REGISTER_ADDRESS(gpio_group, GPIO_PUPDR_OFFSET);
|
||||
}
|
||||
|
||||
GPIO_IDR_t * GPIO_IDR(stm32_gpio_group_t gpio_group) {
|
||||
GPIO_IDR_t * GPIO_IDR(GPIO_GROUP_t gpio_group) {
|
||||
return (GPIO_IDR_t *)GPIO_REGISTER_ADDRESS(gpio_group, GPIO_IDR_OFFSET);
|
||||
}
|
||||
|
||||
GPIO_ODR_t * GPIO_ODR(stm32_gpio_group_t gpio_group) {
|
||||
GPIO_ODR_t * GPIO_ODR(GPIO_GROUP_t gpio_group) {
|
||||
return (GPIO_ODR_t *)GPIO_REGISTER_ADDRESS(gpio_group, GPIO_ODR_OFFSET);
|
||||
}
|
||||
|
||||
GPIO_BSRR_t * GPIO_BSRR(stm32_gpio_group_t gpio_group) {
|
||||
GPIO_BSRR_t * GPIO_BSRR(GPIO_GROUP_t gpio_group) {
|
||||
return (GPIO_BSRR_t *)GPIO_REGISTER_ADDRESS(gpio_group, GPIO_BSRR_OFFSET);
|
||||
}
|
||||
|
||||
GPIO_LCKR_t * GPIO_LCKR(stm32_gpio_group_t gpio_group) {
|
||||
GPIO_LCKR_t * GPIO_LCKR(GPIO_GROUP_t gpio_group) {
|
||||
return (GPIO_LCKR_t *)GPIO_REGISTER_ADDRESS(gpio_group, GPIO_LCKR_OFFSET);
|
||||
}
|
||||
|
||||
GPIO_AFRL_t * GPIO_AFRL(stm32_gpio_group_t gpio_group) {
|
||||
GPIO_AFRL_t * GPIO_AFRL(GPIO_GROUP_t gpio_group) {
|
||||
return (GPIO_AFRL_t *)GPIO_REGISTER_ADDRESS(gpio_group, GPIO_AFRL_OFFSET);
|
||||
}
|
||||
|
||||
GPIO_AFRH_t * GPIO_AFRH(stm32_gpio_group_t gpio_group) {
|
||||
GPIO_AFRH_t * GPIO_AFRH(GPIO_GROUP_t gpio_group) {
|
||||
return (GPIO_AFRH_t *)GPIO_REGISTER_ADDRESS(gpio_group, GPIO_AFRH_OFFSET);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,19 @@
|
||||
#ifndef STM32_REGISTERS_GPIO_H
|
||||
#define STM32_REGISTERS_GPIO_H 1
|
||||
|
||||
#include <platform/stm32f429/gpio.h>
|
||||
typedef enum {
|
||||
GPIOA = 0,
|
||||
GPIOB = 1,
|
||||
GPIOC = 2,
|
||||
GPIOD = 3,
|
||||
GPIOE = 4,
|
||||
GPIOF = 5,
|
||||
GPIOG = 6,
|
||||
GPIOH = 7,
|
||||
GPIOI = 8,
|
||||
GPIOJ = 9,
|
||||
GPIOK = 10
|
||||
} GPIO_GROUP_t;
|
||||
|
||||
#pragma mark - GPIO port mode registers
|
||||
|
||||
@@ -31,7 +43,7 @@ typedef struct {
|
||||
GPIO_MODE_t MODER15:2;
|
||||
} GPIO_MODER_t;
|
||||
|
||||
GPIO_MODER_t * GPIO_MODER(stm32_gpio_group_t gpio_group);
|
||||
GPIO_MODER_t * GPIO_MODER(GPIO_GROUP_t gpio_group);
|
||||
|
||||
#pragma mark - GPIO port output type registers
|
||||
|
||||
@@ -60,7 +72,7 @@ typedef struct {
|
||||
unsigned int :16;
|
||||
} GPIO_OTYPER_t;
|
||||
|
||||
GPIO_OTYPER_t * GPIO_OTYPER(stm32_gpio_group_t gpio_group);
|
||||
GPIO_OTYPER_t * GPIO_OTYPER(GPIO_GROUP_t gpio_group);
|
||||
|
||||
#pragma mark - GPIO port output speed registers
|
||||
|
||||
@@ -90,7 +102,7 @@ typedef struct {
|
||||
GPIO_OSPEED_t OSPEEDR15:2;
|
||||
} GPIO_OSPEEDR_t;
|
||||
|
||||
GPIO_OSPEEDR_t * GPIO_OSPEEDR(stm32_gpio_group_t gpio_group);
|
||||
GPIO_OSPEEDR_t * GPIO_OSPEEDR(GPIO_GROUP_t gpio_group);
|
||||
|
||||
#pragma mark - GPIO port pull-up/pull-down registers
|
||||
|
||||
@@ -119,7 +131,7 @@ typedef struct {
|
||||
GPIO_PUPD_t PUPDR15:2;
|
||||
} GPIO_PUPDR_t;
|
||||
|
||||
GPIO_PUPDR_t * GPIO_PUPDR(stm32_gpio_group_t gpio_group);
|
||||
GPIO_PUPDR_t * GPIO_PUPDR(GPIO_GROUP_t gpio_group);
|
||||
|
||||
#pragma mark - GPIO port input data registers
|
||||
|
||||
@@ -143,7 +155,7 @@ typedef struct {
|
||||
unsigned int :16;
|
||||
} GPIO_IDR_t;
|
||||
|
||||
GPIO_IDR_t * GPIO_IDR(stm32_gpio_group_t gpio_group);
|
||||
GPIO_IDR_t * GPIO_IDR(GPIO_GROUP_t gpio_group);
|
||||
|
||||
#pragma mark - GPIO port output data registers
|
||||
|
||||
@@ -167,7 +179,7 @@ typedef struct {
|
||||
unsigned int :16;
|
||||
} GPIO_ODR_t;
|
||||
|
||||
GPIO_ODR_t * GPIO_ODR(stm32_gpio_group_t gpio_group);
|
||||
GPIO_ODR_t * GPIO_ODR(GPIO_GROUP_t gpio_group);
|
||||
|
||||
#pragma mark - GPIO port bit set/reset registers
|
||||
|
||||
@@ -206,7 +218,7 @@ typedef struct {
|
||||
unsigned int BR15:1;
|
||||
} GPIO_BSRR_t;
|
||||
|
||||
GPIO_BSRR_t * GPIO_BSRR(stm32_gpio_group_t gpio_group);
|
||||
GPIO_BSRR_t * GPIO_BSRR(GPIO_GROUP_t gpio_group);
|
||||
|
||||
#pragma mark - GPIO port configuration lock registers
|
||||
|
||||
@@ -240,7 +252,7 @@ typedef struct {
|
||||
GPIO_LCK_KEY_t LCKK:1;
|
||||
} GPIO_LCKR_t;
|
||||
|
||||
GPIO_LCKR_t * GPIO_LCKR(stm32_gpio_group_t gpio_group);
|
||||
GPIO_LCKR_t * GPIO_LCKR(GPIO_GROUP_t gpio_group);
|
||||
|
||||
#pragma mark - GPIO port alternate function registers
|
||||
|
||||
@@ -285,7 +297,7 @@ typedef struct {
|
||||
GPIO_AF_t AFRH15:4;
|
||||
} GPIO_AFRH_t;
|
||||
|
||||
GPIO_AFRL_t * GPIO_AFRL(stm32_gpio_group_t gpio_group);
|
||||
GPIO_AFRH_t * GPIO_AFRH(stm32_gpio_group_t gpio_group);
|
||||
GPIO_AFRL_t * GPIO_AFRL(GPIO_GROUP_t gpio_group);
|
||||
GPIO_AFRH_t * GPIO_AFRH(GPIO_GROUP_t gpio_group);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -23,10 +23,10 @@ SPI_CR1_t * SPI_CR1(SPI_t spi) {
|
||||
return (SPI_CR1_t *)SPI_REGISTER_ADDRESS(spi, SPI_CR1_OFFSET);
|
||||
}
|
||||
|
||||
SPI_SR_t * SPI_SR(SPI_t spi) {
|
||||
volatile SPI_SR_t * SPI_SR(SPI_t spi) {
|
||||
return (SPI_SR_t *)SPI_REGISTER_ADDRESS(spi, SPI_SR_OFFSET);
|
||||
}
|
||||
|
||||
SPI_DR_t * SPI_DR(SPI_t spi) {
|
||||
volatile SPI_DR_t * SPI_DR(SPI_t spi) {
|
||||
return (SPI_DR_t *)SPI_REGISTER_ADDRESS(spi, SPI_DR_OFFSET);
|
||||
}
|
||||
|
||||
@@ -64,11 +64,11 @@ typedef struct {
|
||||
unsigned int :7;
|
||||
} SPI_SR_t;
|
||||
|
||||
SPI_SR_t * SPI_SR(SPI_t spi);
|
||||
volatile SPI_SR_t * SPI_SR(SPI_t spi);
|
||||
|
||||
#pragma mark - SPI data registers
|
||||
|
||||
typedef uint16_t SPI_DR_t;
|
||||
SPI_DR_t * SPI_DR(SPI_t spi);
|
||||
volatile SPI_DR_t * SPI_DR(SPI_t spi);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
#include "spi.h"
|
||||
|
||||
// pin mapping
|
||||
//
|
||||
// Give a port number: e.g. SPI2
|
||||
// and a pinmatch. e.g "SPI1_SCK -> PB3"
|
||||
// and obtain an alternate function
|
||||
// Actually, this should be done elsewhere...
|
||||
|
||||
|
||||
void spi_init(spi_port_t * port) {
|
||||
// Do shit!
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
#ifndef STM32F429_SPI_H
|
||||
#define STM32F429_SPI_H 1
|
||||
|
||||
#include <spi.h>
|
||||
#include <platform/stm32f429/registers/spi.h>
|
||||
|
||||
struct spi_port {
|
||||
struct {
|
||||
SPI_CR1_t controlRegister1;
|
||||
// SPI_CR2_t controlRegister1;
|
||||
} config;
|
||||
struct {
|
||||
int b;
|
||||
} state;
|
||||
};
|
||||
|
||||
#endif
|
||||
174
src/lcd_spi.c
174
src/lcd_spi.c
@@ -1,174 +0,0 @@
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
#include <timers.h>
|
||||
#include <semphr.h>
|
||||
|
||||
#include <platform/stm32f429/registers.h>
|
||||
#include <platform/stm32f429/spi.h>
|
||||
|
||||
/* This code sends data to the onboard LCD over SPI
|
||||
*
|
||||
* The LCD has two interfaces, SPI and direct RGB.
|
||||
* We'll only use SPI in this one.
|
||||
*
|
||||
* The Discovery board has the IM[0-3] pins of the LCD controller
|
||||
* connected to low, high, high, low = 0b0110. (UM1670 p. 33).
|
||||
* This tells the LCD controller to expect data this way:
|
||||
* "4 wire, 8-bit serial, SDA = In/out"
|
||||
* See ILI9341 p. 63
|
||||
*
|
||||
* Now how are the LCD pins connected to the MCU ones?
|
||||
* The Discovery board doc says this:
|
||||
* MCU pin - LCD-SPI
|
||||
* NRST - Reset
|
||||
* PC2 - CSX // Chip select for LCD
|
||||
* PD13 - DCX // Data/Command register
|
||||
* PF7 - SCL // SPI Clock
|
||||
* PF9 - SDI/SDO // MOSI
|
||||
*
|
||||
* See UM1670 p. 19 to 24. */
|
||||
|
||||
/* We'll need to figure out which GPIO pins this maps to, and in which
|
||||
* Alternate Function mode. STM32F429 datasheet p78-79 says:
|
||||
* PF6 in AF5 = SPI5_NSS
|
||||
* PF7 in AF5 = SPI5_SCK
|
||||
* PF8 in AF5 = SPI5_MISO
|
||||
* PF9 in AF5 = SPI5_MOSI
|
||||
*/
|
||||
|
||||
/* In case we want to monitor this, here's a color-mapping
|
||||
*
|
||||
* PF6 - SPI5_NSS - Yellow
|
||||
* PF7 - SPI5_SCK - Green
|
||||
* PF8 - SPI5_MISO - Red
|
||||
* PF9 - SPI5_MOSI - Blue
|
||||
*/
|
||||
|
||||
void SpiSend(void * pvParameters) {
|
||||
uint16_t value = 0;
|
||||
while(1) {
|
||||
SPI_SR_t * spi_status = SPI_SR(SPI5);
|
||||
SPI_DR_t * spi_data_register = SPI_DR(SPI5);
|
||||
if (spi_status->BSY == 0) {
|
||||
*spi_data_register = value++;
|
||||
}
|
||||
vTaskDelay(100/portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
/*
|
||||
struct spi_port {
|
||||
// Private data:
|
||||
.config = {
|
||||
},
|
||||
.state = {
|
||||
}
|
||||
};
|
||||
|
||||
// Public API, private impl.
|
||||
spi_init();
|
||||
spi_write();
|
||||
*/
|
||||
int main(int argc, char * argv[]) {
|
||||
|
||||
spi_port_t my_spi_port = {
|
||||
.config = {
|
||||
.controlRegister1 = {
|
||||
.BIDIMODE = 1,
|
||||
.BIDIOE = 1,
|
||||
.MSTR = 1,
|
||||
.DFF = SPI_DFF_16_BITS,
|
||||
.CPOL = 0,
|
||||
.BR = SPI_BR_DIV_256,
|
||||
.SSM = 1,
|
||||
.SSI = 1,
|
||||
.SPE = 1
|
||||
}
|
||||
}
|
||||
};
|
||||
spi_init(&my_spi_port);
|
||||
|
||||
/*
|
||||
// Code we'd like to write:
|
||||
|
||||
spi_port my_spi_port;
|
||||
spi_init(&my_spi_port);
|
||||
|
||||
ili9431 lcd_panel = {
|
||||
.port = my_spi_port
|
||||
};
|
||||
|
||||
ili9431_init(&lcd_panel);
|
||||
lcd_panel.clear();
|
||||
lcd_panel.setGammaCurve();
|
||||
|
||||
char * fb = lcd_panel.framebuffer;
|
||||
|
||||
for (int i=0;i<100;i++) {
|
||||
*fb[i] = 1;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
// We'll use GPIO pins F6-F9 to emit SPI data
|
||||
// GPIO are grouped by letter. All GPIO groups live on the "AHB1" bus.
|
||||
// (this is documented in the STM32F4 reference mnual, page 65)
|
||||
|
||||
// Step 1 : Enable clock in RCC_AHBxENR
|
||||
RCC_AHB1ENR->GPIOFEN = 1;
|
||||
|
||||
// Step 2 : Set the GPIO pin C2 as output
|
||||
|
||||
RCC_AHB1ENR->GPIOCEN = 1;
|
||||
GPIO_MODER(GPIOC)->MODER2 = GPIO_MODE_OUTPUT;
|
||||
|
||||
RCC_AHB1ENR->GPIOCEN = 1;
|
||||
GPIO_MODER(GPIOC)->MODER2 = GPIO_MODE_OUTPUT;
|
||||
// From now on, we'll control pin C2 with
|
||||
// GPIO_ODR(GPIOC)->ODR2 = desiredValue;
|
||||
|
||||
// Step 2 : Configure the GPIO pin to "Alternate function number 5"
|
||||
// This means "SPI5 on pins F6-F9", cf STM32F249 p78
|
||||
GPIO_MODER(GPIOF)->MODER6 = GPIO_MODE_ALTERNATE_FUNCTION;
|
||||
GPIO_MODER(GPIOF)->MODER7 = GPIO_MODE_ALTERNATE_FUNCTION;
|
||||
GPIO_MODER(GPIOF)->MODER8 = GPIO_MODE_ALTERNATE_FUNCTION;
|
||||
GPIO_MODER(GPIOF)->MODER9 = GPIO_MODE_ALTERNATE_FUNCTION;
|
||||
|
||||
// We're interested in pins 11-14, which are in the 8-16 range, so we
|
||||
// have to deal with the "high" version of the AF register
|
||||
GPIO_AFRL(GPIOF)->AFRL6 = GPIO_AF_AF5;
|
||||
GPIO_AFRL(GPIOF)->AFRL7 = GPIO_AF_AF5;
|
||||
GPIO_AFRH(GPIOF)->AFRH8 = GPIO_AF_AF5;
|
||||
GPIO_AFRH(GPIOF)->AFRH9 = GPIO_AF_AF5;
|
||||
|
||||
// Enable the SPI5 clock
|
||||
RCC_APB2ENR->SPI5EN = 1;
|
||||
|
||||
// Configure the SPI port
|
||||
// Using a C99 compound litteral. C99 guarantees all non-set values are zero
|
||||
*SPI_CR1(SPI5) = (SPI_CR1_t){
|
||||
.BIDIMODE = 1,
|
||||
.BIDIOE = 1,
|
||||
.MSTR = 1,
|
||||
.DFF = SPI_DFF_16_BITS,
|
||||
.CPOL = 0,
|
||||
.BR = SPI_BR_DIV_256,
|
||||
.SSM = 1,
|
||||
.SSI = 1,
|
||||
.SPE = 1
|
||||
};
|
||||
|
||||
BaseType_t success = xTaskCreate(SpiSend,
|
||||
"SpiSnd",
|
||||
100, // Stack size
|
||||
NULL, // Parameters
|
||||
2,
|
||||
NULL);
|
||||
|
||||
vTaskStartScheduler();
|
||||
|
||||
while (1) {
|
||||
// We should never get here
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user