Big cleanup

This commit is contained in:
Romain Goyet
2015-05-08 21:06:09 +02:00
parent 0100fb42c7
commit 299578c60b
21 changed files with 359 additions and 357 deletions

View File

@@ -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
View 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
View File

@@ -1,2 +1,3 @@
- Using memcpy and memset
- using <string.h>, <stdlib.h>, and <stdint.h>
- using <stdbool.h> for "bool"

View File

@@ -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
View 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) {
}

View 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

View File

@@ -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();
}

View File

@@ -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

View File

@@ -0,0 +1,5 @@
#include "init_lcd.h"
void init() {
init_lcd();
}

View 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);
}

View File

@@ -0,0 +1 @@
void init_lcd();

View File

@@ -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;
}

View File

@@ -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

View File

@@ -1,3 +0,0 @@
#include "registers/gpio.h"
#include "registers/rcc.h"
#include "registers/spi.h"

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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!
}

View File

@@ -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

View File

@@ -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
}
}