[stm32f429i-discovery] Added LTDC DMA example.
This example is just using buffers and built in alpha overlay functionality to animate a dmond floating on a checker board. After initializing of the frame buffers only 7 registers are being modified to implement the animation.
This commit is contained in:
committed by
Piotr Esden-Tempski
parent
408ba8c885
commit
9cee61f089
@@ -236,4 +236,4 @@ endif
|
||||
|
||||
.PHONY: images clean stylecheck styleclean elf bin hex srec list
|
||||
|
||||
-include $(OBJS:.o=.d)
|
||||
-include $(OBJS:.o=.d)
|
||||
|
||||
10
examples/stm32/f4/stm32f429i-discovery/lcd-dma/Makefile
Normal file
10
examples/stm32/f4/stm32f429i-discovery/lcd-dma/Makefile
Normal file
@@ -0,0 +1,10 @@
|
||||
OBJS = sdram.o clock.o console.o lcd-spi.o
|
||||
|
||||
BINARY = lcd-dma
|
||||
|
||||
# we use sin/cos from the library
|
||||
LDLIBS += -lm
|
||||
|
||||
LDSCRIPT = ../stm32f429i-discovery.ld
|
||||
|
||||
include ../../Makefile.include
|
||||
75
examples/stm32/f4/stm32f429i-discovery/lcd-dma/clock.c
Normal file
75
examples/stm32/f4/stm32f429i-discovery/lcd-dma/clock.c
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* This file is part of the libopencm3 project.
|
||||
*
|
||||
* Copyright (C) 2014 Chuck McManis <cmcmanis@mcmanis.com>
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Now this is just the clock setup code from systick-blink as it is the
|
||||
* transferrable part.
|
||||
*/
|
||||
|
||||
#include <libopencm3/stm32/rcc.h>
|
||||
#include <libopencm3/cm3/nvic.h>
|
||||
#include <libopencm3/cm3/systick.h>
|
||||
|
||||
/* Common function descriptions */
|
||||
#include "clock.h"
|
||||
|
||||
/* milliseconds since boot */
|
||||
static volatile uint32_t system_millis;
|
||||
|
||||
/* Called when systick fires */
|
||||
void sys_tick_handler(void)
|
||||
{
|
||||
system_millis++;
|
||||
}
|
||||
|
||||
/* simple sleep for delay milliseconds */
|
||||
void milli_sleep(uint32_t delay)
|
||||
{
|
||||
uint32_t wake = system_millis + delay;
|
||||
while (wake > system_millis) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Getter function for the current time */
|
||||
uint32_t mtime(void)
|
||||
{
|
||||
return system_millis;
|
||||
}
|
||||
|
||||
/*
|
||||
* clock_setup(void)
|
||||
*
|
||||
* This function sets up both the base board clock rate
|
||||
* and a 1khz "system tick" count. The SYSTICK counter is
|
||||
* a standard feature of the Cortex-M series.
|
||||
*/
|
||||
void clock_setup(void)
|
||||
{
|
||||
/* Base board frequency, set to 168Mhz */
|
||||
rcc_clock_setup_hse_3v3(&hse_8mhz_3v3[CLOCK_3V3_168MHZ]);
|
||||
|
||||
/* clock rate / 168000 to get 1mS interrupt rate */
|
||||
systick_set_reload(168000);
|
||||
systick_set_clocksource(STK_CSR_CLKSOURCE_AHB);
|
||||
systick_counter_enable();
|
||||
|
||||
/* this done last */
|
||||
systick_interrupt_enable();
|
||||
}
|
||||
17
examples/stm32/f4/stm32f429i-discovery/lcd-dma/clock.h
Normal file
17
examples/stm32/f4/stm32f429i-discovery/lcd-dma/clock.h
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* This include file describes the functions exported by clock.c
|
||||
*/
|
||||
#ifndef __CLOCK_H
|
||||
#define __CLOCK_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* Definitions for functions being abstracted out
|
||||
*/
|
||||
void milli_sleep(uint32_t);
|
||||
uint32_t mtime(void);
|
||||
void clock_setup(void);
|
||||
|
||||
#endif /* generic header protector */
|
||||
|
||||
274
examples/stm32/f4/stm32f429i-discovery/lcd-dma/console.c
Normal file
274
examples/stm32/f4/stm32f429i-discovery/lcd-dma/console.c
Normal file
@@ -0,0 +1,274 @@
|
||||
/*
|
||||
* This file is part of the libopencm3 project.
|
||||
*
|
||||
* Copyright (C) 2014 Chuck McManis <cmcmanis@mcmanis.com>
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Interrupt drive Console code (extracted from the usart-irq example)
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <setjmp.h>
|
||||
#include <libopencm3/stm32/gpio.h>
|
||||
#include <libopencm3/stm32/rcc.h>
|
||||
#include <libopencm3/stm32/usart.h>
|
||||
#include <libopencm3/cm3/nvic.h>
|
||||
#include <libopencm3/stm32/iwdg.h>
|
||||
#include <libopencm3/cm3/scb.h>
|
||||
#include <libopencm3/cm3/cortex.h>
|
||||
#include "clock.h"
|
||||
#include "console.h"
|
||||
|
||||
|
||||
/* This is a ring buffer to holding characters as they are typed
|
||||
* it maintains both the place to put the next character received
|
||||
* from the UART, and the place where the last character was
|
||||
* read by the program. See the README file for a discussion of
|
||||
* the failure semantics.
|
||||
*/
|
||||
#define RECV_BUF_SIZE 128 /* Arbitrary buffer size */
|
||||
char recv_buf[RECV_BUF_SIZE];
|
||||
static volatile int recv_ndx_nxt; /* Next place to store */
|
||||
static volatile int recv_ndx_cur; /* Next place to read */
|
||||
|
||||
/* For interrupt handling we add a new function which is called
|
||||
* when receive interrupts happen. The name (usart1_isr) is created
|
||||
* by the irq.json file in libopencm3 calling this interrupt for
|
||||
* USART1 'usart1', adding the suffix '_isr', and then weakly binding
|
||||
* it to the 'do nothing' interrupt function in vec.c.
|
||||
*
|
||||
* By defining it in this file the linker will override that weak
|
||||
* binding and instead bind it here, but you have to get the name
|
||||
* right or it won't work. And you'll wonder where your interrupts
|
||||
* are going.
|
||||
*/
|
||||
void usart1_isr(void)
|
||||
{
|
||||
uint32_t reg;
|
||||
int i;
|
||||
|
||||
do {
|
||||
reg = USART_SR(CONSOLE_UART);
|
||||
if (reg & USART_SR_RXNE) {
|
||||
recv_buf[recv_ndx_nxt] = USART_DR(CONSOLE_UART);
|
||||
#ifdef RESET_ON_CTRLC
|
||||
/* Check for "reset" */
|
||||
if (recv_buf[recv_ndx_nxt] == '\003') {
|
||||
scb_reset_system();
|
||||
}
|
||||
#endif
|
||||
/* Check for "overrun" */
|
||||
i = (recv_ndx_nxt + 1) % RECV_BUF_SIZE;
|
||||
if (i != recv_ndx_cur) {
|
||||
recv_ndx_nxt = i;
|
||||
}
|
||||
}
|
||||
} while ((reg & USART_SR_RXNE) != 0);
|
||||
/* can read back-to-back interrupts */
|
||||
}
|
||||
|
||||
/*
|
||||
* console_putc(char c)
|
||||
*
|
||||
* Send the character 'c' to the USART, wait for the USART
|
||||
* transmit buffer to be empty first.
|
||||
*/
|
||||
void console_putc(char c)
|
||||
{
|
||||
uint32_t reg;
|
||||
do {
|
||||
reg = USART_SR(CONSOLE_UART);
|
||||
} while ((reg & USART_SR_TXE) == 0);
|
||||
USART_DR(CONSOLE_UART) = (uint16_t) c & 0xff;
|
||||
}
|
||||
|
||||
/*
|
||||
* char = console_getc(int wait)
|
||||
*
|
||||
* Check the console for a character. If the wait flag is
|
||||
* non-zero. Continue checking until a character is received
|
||||
* otherwise return 0 if called and no character was available.
|
||||
*
|
||||
* The implementation is a bit different however, now it looks
|
||||
* in the ring buffer to see if a character has arrived.
|
||||
*/
|
||||
char console_getc(int wait)
|
||||
{
|
||||
char c = 0;
|
||||
|
||||
while ((wait != 0) && (recv_ndx_cur == recv_ndx_nxt));
|
||||
if (recv_ndx_cur != recv_ndx_nxt) {
|
||||
c = recv_buf[recv_ndx_cur];
|
||||
recv_ndx_cur = (recv_ndx_cur + 1) % RECV_BUF_SIZE;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/*
|
||||
* void console_puts(char *s)
|
||||
*
|
||||
* Send a string to the console, one character at a time, return
|
||||
* after the last character, as indicated by a NUL character, is
|
||||
* reached.
|
||||
*/
|
||||
void console_puts(char *s)
|
||||
{
|
||||
while (*s != '\000') {
|
||||
console_putc(*s);
|
||||
/* Add in a carraige return, after sending line feed */
|
||||
if (*s == '\n') {
|
||||
console_putc('\r');
|
||||
}
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* int console_gets(char *s, int len)
|
||||
*
|
||||
* Wait for a string to be entered on the console, limited
|
||||
* support for editing characters (back space and delete)
|
||||
* end when a <CR> character is received.
|
||||
*/
|
||||
int console_gets(char *s, int len)
|
||||
{
|
||||
char *t = s;
|
||||
char c;
|
||||
|
||||
*t = '\000';
|
||||
/* read until a <CR> is received */
|
||||
while ((c = console_getc(1)) != '\r') {
|
||||
if ((c == '\010') || (c == '\127')) {
|
||||
if (t > s) {
|
||||
/* send ^H ^H to erase previous character */
|
||||
console_puts("\010 \010");
|
||||
t--;
|
||||
}
|
||||
} else {
|
||||
*t = c;
|
||||
console_putc(c);
|
||||
if ((t - s) < len) {
|
||||
t++;
|
||||
}
|
||||
}
|
||||
/* update end of string with NUL */
|
||||
*t = '\000';
|
||||
}
|
||||
return t - s;
|
||||
}
|
||||
|
||||
/*
|
||||
* console_setup(int baudrate)
|
||||
*
|
||||
* Set the pins and clocks to create a console that we can
|
||||
* use for serial messages and getting text from the user.
|
||||
*/
|
||||
void console_setup(int baud)
|
||||
{
|
||||
/* MUST enable the GPIO clock in ADDITION to the USART clock */
|
||||
rcc_periph_clock_enable(RCC_GPIOA);
|
||||
|
||||
/* This example uses PD5 and PD6 for Tx and Rx respectively
|
||||
* but other pins are available for this role on USART1 (our chosen
|
||||
* USART) as well, such as PA2 and PA3. You can also split them
|
||||
* so PA2 for Tx, PD6 for Rx but you would have to enable both
|
||||
* the GPIOA and GPIOD clocks in that case
|
||||
*/
|
||||
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO9 | GPIO10);
|
||||
|
||||
/* Actual Alternate function number (in this case 7) is part
|
||||
* depenedent, CHECK THE DATA SHEET for the right number to
|
||||
* use.
|
||||
*/
|
||||
gpio_set_af(GPIOA, GPIO_AF7, GPIO9 | GPIO10);
|
||||
|
||||
|
||||
/* This then enables the clock to the USART1 peripheral which is
|
||||
* attached inside the chip to the APB2 bus. Different peripherals
|
||||
* attach to different buses, and even some UARTS are attached to
|
||||
* APB1 and some to APB2, again the data sheet is useful here.
|
||||
*/
|
||||
rcc_periph_clock_enable(RCC_USART1);
|
||||
|
||||
/* Set up USART/UART parameters using the libopencm3 helper functions */
|
||||
usart_set_baudrate(CONSOLE_UART, baud);
|
||||
usart_set_databits(CONSOLE_UART, 8);
|
||||
usart_set_stopbits(CONSOLE_UART, USART_STOPBITS_1);
|
||||
usart_set_mode(CONSOLE_UART, USART_MODE_TX_RX);
|
||||
usart_set_parity(CONSOLE_UART, USART_PARITY_NONE);
|
||||
usart_set_flow_control(CONSOLE_UART, USART_FLOWCONTROL_NONE);
|
||||
usart_enable(CONSOLE_UART);
|
||||
|
||||
/* Enable interrupts from the USART */
|
||||
nvic_enable_irq(NVIC_USART1_IRQ);
|
||||
|
||||
/* Specifically enable receive interrupts */
|
||||
usart_enable_rx_interrupt(CONSOLE_UART);
|
||||
}
|
||||
|
||||
static ssize_t console_read(void *cookie, char *buf, size_t size)
|
||||
{
|
||||
cookie = cookie; /* -Wunused-parameter */
|
||||
size_t i;
|
||||
for (i = 0; i < size; i++) {
|
||||
char c = console_getc(1);
|
||||
buf[i] = c;
|
||||
if (c == '\r') {
|
||||
buf[i] = '\n';
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static ssize_t console_write(void *cookie, const char *buf, size_t size)
|
||||
{
|
||||
cookie = cookie; /* -Wunused-parameter */
|
||||
size_t i;
|
||||
for (i = 0; i < size; i++) {
|
||||
char c = buf[i];
|
||||
if (c == '\n') {
|
||||
console_putc('\r');
|
||||
}
|
||||
console_putc(c);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void console_stdio_setup()
|
||||
{
|
||||
cookie_io_functions_t console_input_fns = {
|
||||
.read = console_read,
|
||||
.write = NULL,
|
||||
.seek = NULL,
|
||||
.close = NULL
|
||||
};
|
||||
cookie_io_functions_t console_output_fns = {
|
||||
.read = NULL,
|
||||
.write = console_write,
|
||||
.seek = NULL,
|
||||
.close = NULL
|
||||
};
|
||||
stdin = fopencookie(NULL, "r", console_input_fns);
|
||||
stdout = fopencookie(NULL, "w", console_output_fns);
|
||||
stderr = fopencookie(NULL, "w", console_output_fns);
|
||||
setlinebuf(stdout);
|
||||
setbuf(stderr, NULL);
|
||||
}
|
||||
57
examples/stm32/f4/stm32f429i-discovery/lcd-dma/console.h
Normal file
57
examples/stm32/f4/stm32f429i-discovery/lcd-dma/console.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* This file is part of the libopencm3 project.
|
||||
*
|
||||
* Copyright (C) 2014 Chuck McManis <cmcmanis@mcmanis.com>
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __CONSOLE_H
|
||||
#define __CONSOLE_H
|
||||
|
||||
/*
|
||||
* Some definitions of our console "functions" attached to the
|
||||
* USART.
|
||||
*
|
||||
* These define sort of the minimum "library" of functions which
|
||||
* we can use on a serial port. If you wish to use a different
|
||||
* USART there are several things to change:
|
||||
* - CONSOLE_UART change this
|
||||
* - Change the peripheral enable clock
|
||||
* - add usartx_isr for interrupts
|
||||
* - nvic_enable_interrupt(your choice of USART/UART)
|
||||
* - GPIO pins for transmit/receive
|
||||
* (may be on different alternate functions as well)
|
||||
*/
|
||||
|
||||
|
||||
#define CONSOLE_UART USART1
|
||||
|
||||
/*
|
||||
* Our simple console definitions
|
||||
*/
|
||||
|
||||
void console_putc(char c);
|
||||
char console_getc(int wait);
|
||||
void console_puts(char *s);
|
||||
int console_gets(char *s, int len);
|
||||
void console_setup(int baudrate);
|
||||
|
||||
/* Connect stdin, stdout, stderr to the console. */
|
||||
extern void console_stdio_setup(void);
|
||||
|
||||
/* this is for fun, if you type ^C to this example it will reset */
|
||||
#define RESET_ON_CTRLC
|
||||
|
||||
#endif
|
||||
495
examples/stm32/f4/stm32f429i-discovery/lcd-dma/lcd-dma.c
Normal file
495
examples/stm32/f4/stm32f429i-discovery/lcd-dma/lcd-dma.c
Normal file
@@ -0,0 +1,495 @@
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <libopencm3/cm3/nvic.h>
|
||||
#include <libopencm3/stm32/rcc.h>
|
||||
#include <libopencm3/stm32/gpio.h>
|
||||
#include <libopencm3/stm32/ltdc.h>
|
||||
|
||||
#include "clock.h"
|
||||
#include "console.h"
|
||||
#include "lcd-spi.h"
|
||||
#include "sdram.h"
|
||||
|
||||
#define LCD_WIDTH 240
|
||||
#define LCD_HEIGHT 320
|
||||
#define REFRESH_RATE 70 /* Hz */
|
||||
|
||||
#define HSYNC 10
|
||||
#define HBP 20
|
||||
#define HFP 10
|
||||
|
||||
#define VSYNC 2
|
||||
#define VBP 2
|
||||
#define VFP 4
|
||||
|
||||
/* Layer 1 (bottom layer) is ARGB8888 format, full screen. */
|
||||
|
||||
typedef uint32_t layer1_pixel;
|
||||
#define LCD_LAYER1_PIXFORMAT LTDC_LxPFCR_ARGB8888
|
||||
|
||||
layer1_pixel *const lcd_layer1_frame_buffer = (void *)SDRAM_BASE_ADDRESS;
|
||||
#define LCD_LAYER1_PIXEL_SIZE (sizeof(layer1_pixel))
|
||||
#define LCD_LAYER1_WIDTH LCD_WIDTH
|
||||
#define LCD_LAYER1_HEIGHT LCD_HEIGHT
|
||||
#define LCD_LAYER1_PIXELS (LCD_LAYER1_WIDTH * LCD_LAYER1_HEIGHT)
|
||||
#define LCD_LAYER1_BYTES (LCD_LAYER1_PIXELS * LCD_LAYER1_PIXEL_SIZE)
|
||||
|
||||
/* Layer 2 (top layer) is ARGB4444, a 128x128 square. */
|
||||
|
||||
typedef uint16_t layer2_pixel;
|
||||
#define LCD_LAYER2_PIXFORMAT LTDC_LxPFCR_ARGB4444
|
||||
layer2_pixel *const lcd_layer2_frame_buffer =
|
||||
(void *)SDRAM_BASE_ADDRESS + LCD_LAYER1_BYTES;
|
||||
#define LCD_LAYER2_PIXEL_SIZE (sizeof(layer2_pixel))
|
||||
#define LCD_LAYER2_WIDTH 128
|
||||
#define LCD_LAYER2_HEIGHT 128
|
||||
#define LCD_LAYER2_PIXELS (LCD_LAYER2_WIDTH * LCD_LAYER2_HEIGH)
|
||||
#define LCD_LAYER2_BYTES (LCD_LAYER2_PIXELS * LCD_LAYER2_PIXEL_SIZE)
|
||||
|
||||
/*
|
||||
* Pin assignments
|
||||
* R2 = PC10, AF14
|
||||
* R3 = PB0, AF09
|
||||
* R4 = PA11, AF14
|
||||
* R5 = PA12, AF14
|
||||
* R6 = PB1, AF09
|
||||
* R7 = PG6, AF14
|
||||
*
|
||||
* G2 = PA6, AF14
|
||||
* G3 = PG10, AF09
|
||||
* G4 = PB10, AF14
|
||||
* G5 = PB11, AF14
|
||||
* G6 = PC7, AF14
|
||||
* G7 = PD3, AF14
|
||||
*
|
||||
* B2 = PD6, AF14
|
||||
* B3 = PG11, AF11
|
||||
* B4 = PG12, AF09
|
||||
* B5 = PA3, AF14
|
||||
* B6 = PB8, AF14
|
||||
* B7 = PB9, AF14
|
||||
*
|
||||
* More pins...
|
||||
* ENABLE = PF10, AF14
|
||||
* DOTCLK = PG7, AF14
|
||||
* HSYNC = PC6, AF14
|
||||
* VSYNC = PA4, AF14
|
||||
* CSX = PC2 used in lcd-spi
|
||||
* RDX = PD12 not used: read SPI
|
||||
* TE = PD11 not used: tearing effect interrupt
|
||||
* WRX_DCX = PD13 used in lcd-spi
|
||||
* DCX_SCL = PF7 used in lcd-spi
|
||||
* SDA = PF9 used in lcd-spi
|
||||
* NRST = NRST
|
||||
*/
|
||||
|
||||
static void lcd_dma_init(void)
|
||||
{
|
||||
/* init GPIO clocks */
|
||||
rcc_periph_clock_enable(RCC_GPIOA | RCC_GPIOB | RCC_GPIOC |
|
||||
RCC_GPIOD | RCC_GPIOF | RCC_GPIOG);
|
||||
|
||||
/* set GPIO pin modes */
|
||||
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE,
|
||||
GPIO3 | GPIO4 | GPIO6 | GPIO11 | GPIO12);
|
||||
gpio_set_output_options(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,
|
||||
GPIO3 | GPIO4 | GPIO6 | GPIO11 | GPIO12);
|
||||
gpio_set_af(GPIOA, GPIO_AF14, GPIO3 | GPIO4 | GPIO6 | GPIO11 | GPIO12);
|
||||
|
||||
gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE,
|
||||
GPIO0 | GPIO1 | GPIO8 | GPIO9 | GPIO10 | GPIO11);
|
||||
gpio_set_output_options(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,
|
||||
GPIO0 | GPIO1 | GPIO8 |
|
||||
GPIO9 | GPIO10 | GPIO11);
|
||||
gpio_set_af(GPIOB, GPIO_AF9, GPIO0 | GPIO1);
|
||||
gpio_set_af(GPIOB, GPIO_AF14, GPIO8 | GPIO9 | GPIO10 | GPIO11);
|
||||
|
||||
gpio_mode_setup(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE,
|
||||
GPIO6 | GPIO7 | GPIO10);
|
||||
gpio_set_output_options(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,
|
||||
GPIO6 | GPIO7 | GPIO10);
|
||||
gpio_set_af(GPIOC, GPIO_AF14, GPIO6 | GPIO7 | GPIO10);
|
||||
|
||||
gpio_mode_setup(GPIOD, GPIO_MODE_AF, GPIO_PUPD_NONE,
|
||||
GPIO3 | GPIO6);
|
||||
gpio_set_output_options(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,
|
||||
GPIO3 | GPIO6);
|
||||
gpio_set_af(GPIOD, GPIO_AF14, GPIO3 | GPIO6);
|
||||
|
||||
gpio_mode_setup(GPIOF, GPIO_MODE_AF, GPIO_PUPD_NONE,
|
||||
GPIO10);
|
||||
gpio_set_output_options(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,
|
||||
GPIO10);
|
||||
gpio_set_af(GPIOF, GPIO_AF14, GPIO10);
|
||||
|
||||
gpio_mode_setup(GPIOG, GPIO_MODE_AF, GPIO_PUPD_NONE,
|
||||
GPIO6 | GPIO7 | GPIO10 | GPIO11 | GPIO12);
|
||||
gpio_set_output_options(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,
|
||||
GPIO6 | GPIO7 | GPIO10 | GPIO11 | GPIO12);
|
||||
gpio_set_af(GPIOG, GPIO_AF9, GPIO10 | GPIO12);
|
||||
gpio_set_af(GPIOG, GPIO_AF14, GPIO6 | GPIO7 | GPIO11);
|
||||
|
||||
/*
|
||||
* The datasheet says (Figure 16, page 151):
|
||||
* The LCD-TFT clock comes from PLLSAI.
|
||||
* PLLSRC selects either HSI or HSE.
|
||||
* PLLSAI's input clock is either HSI or HSE divided by PLLM.
|
||||
* PLLSAI's PLLLCDCLK output is the input * PLLSAIN / PLLSAIR.
|
||||
* LCD-TFT clock is PLLLCDCLK divided by PLLSAIDIVR.
|
||||
*
|
||||
* PLLSRC and PLLM are in the RCC_PLLCFGR register.
|
||||
* PLLSAIN and PLLSAIR are in RCC_PLLSAICFGR.
|
||||
* PLLSAIDIVR is in RCC_DCKCFGR;
|
||||
*
|
||||
* In our case,
|
||||
* PLLSRC already selected HSE, which is 8 MHz.
|
||||
* PLLM is already set to 8. 8 MHz / 8 = 1 MHz.
|
||||
* We set PLLSAIN = 192 and PLLSAIR = 4. 1 MHz * 192 / 4 = 48 MHz.
|
||||
* We set PLLSAIDIVR to 8. 48 MHz / 8 = 6 MHz.
|
||||
* So the LCD-TFT pixel clock is 6 MHz.
|
||||
*
|
||||
* The number of clocks per frame is
|
||||
* (VSYNC + VBP + LCD_HEIGHT + VFP) * (HSYNC + HBP + LCD_WIDTH + HFP) =
|
||||
* (2 + 2 + 320 + 4) * (10 + 20 + 240 + 10) = 91840.
|
||||
*
|
||||
* So the refresh frequency is 6 MHz / 91840 ~= 65.6 Hz.
|
||||
*/
|
||||
|
||||
uint32_t sain = 192;
|
||||
uint32_t saiq = (RCC_PLLSAICFGR >> RCC_PLLSAICFGR_PLLSAIQ_SHIFT) &
|
||||
RCC_PLLSAICFGR_PLLSAIQ_MASK;
|
||||
uint32_t sair = 4;
|
||||
RCC_PLLSAICFGR = (sain << RCC_PLLSAICFGR_PLLSAIN_SHIFT |
|
||||
saiq << RCC_PLLSAICFGR_PLLSAIQ_SHIFT |
|
||||
sair << RCC_PLLSAICFGR_PLLSAIR_SHIFT);
|
||||
RCC_DCKCFGR |= RCC_DCKCFGR_PLLSAIDIVR_DIVR_8;
|
||||
RCC_CR |= RCC_CR_PLLSAION;
|
||||
while ((RCC_CR & RCC_CR_PLLSAIRDY) == 0) {
|
||||
continue;
|
||||
}
|
||||
RCC_APB2ENR |= RCC_APB2ENR_LTDCEN;
|
||||
|
||||
/*
|
||||
* Configure the Synchronous timings: VSYNC, HSNC,
|
||||
* Vertical and Horizontal back porch, active data area, and
|
||||
* the front porch timings.
|
||||
*/
|
||||
LTDC_SSCR = (HSYNC - 1) << LTDC_SSCR_HSW_SHIFT |
|
||||
(VSYNC - 1) << LTDC_SSCR_VSH_SHIFT;
|
||||
LTDC_BPCR = (HSYNC + HBP - 1) << LTDC_BPCR_AHBP_SHIFT |
|
||||
(VSYNC + VBP - 1) << LTDC_BPCR_AVBP_SHIFT;
|
||||
LTDC_AWCR = (HSYNC + HBP + LCD_WIDTH - 1) << LTDC_AWCR_AAW_SHIFT |
|
||||
(VSYNC + VBP + LCD_HEIGHT - 1) << LTDC_AWCR_AAH_SHIFT;
|
||||
LTDC_TWCR =
|
||||
(HSYNC + HBP + LCD_WIDTH + HFP - 1) << LTDC_TWCR_TOTALW_SHIFT |
|
||||
(VSYNC + VBP + LCD_HEIGHT + VFP - 1) << LTDC_TWCR_TOTALH_SHIFT;
|
||||
|
||||
/* Configure the synchronous signals and clock polarity. */
|
||||
LTDC_GCR |= LTDC_GCR_PCPOL_ACTIVE_HIGH;
|
||||
|
||||
/* If needed, configure the background color. */
|
||||
LTDC_BCCR = 0x00000000;
|
||||
|
||||
/* Configure the needed interrupts. */
|
||||
LTDC_IER = LTDC_IER_RRIE;
|
||||
nvic_enable_irq(NVIC_LCD_TFT_IRQ);
|
||||
|
||||
/* Configure the Layer 1 parameters.
|
||||
* (Layer 1 is the bottom layer.) */
|
||||
{
|
||||
/* The Layer window horizontal and vertical position */
|
||||
uint32_t h_start = HSYNC + HBP + 0;
|
||||
uint32_t h_stop = HSYNC + HBP + LCD_LAYER1_WIDTH - 1;
|
||||
LTDC_L1WHPCR = h_stop << LTDC_LxWHPCR_WHSPPOS_SHIFT |
|
||||
h_start << LTDC_LxWHPCR_WHSTPOS_SHIFT;
|
||||
uint32_t v_start = VSYNC + VBP + 0;
|
||||
uint32_t v_stop = VSYNC + VBP + LCD_LAYER1_HEIGHT - 1;
|
||||
LTDC_L1WVPCR = v_stop << LTDC_LxWVPCR_WVSPPOS_SHIFT |
|
||||
v_start << LTDC_LxWVPCR_WVSTPOS_SHIFT;
|
||||
|
||||
/* The pixel input format */
|
||||
LTDC_L1PFCR = LCD_LAYER1_PIXFORMAT;
|
||||
|
||||
/* The color frame buffer start address */
|
||||
LTDC_L1CFBAR = (uint32_t)lcd_layer1_frame_buffer;
|
||||
|
||||
/* The line length and pitch of the color frame buffer */
|
||||
uint32_t pitch = LCD_LAYER1_WIDTH * LCD_LAYER1_PIXEL_SIZE;
|
||||
uint32_t length = LCD_LAYER1_WIDTH * LCD_LAYER1_PIXEL_SIZE + 3;
|
||||
LTDC_L1CFBLR = pitch << LTDC_LxCFBLR_CFBP_SHIFT |
|
||||
length << LTDC_LxCFBLR_CFBLL_SHIFT;
|
||||
|
||||
/* The number of lines of the color frame buffer */
|
||||
LTDC_L1CFBLNR = LCD_LAYER1_HEIGHT;
|
||||
|
||||
/* If needed, load the CLUT */
|
||||
/* (not using CLUT) */
|
||||
|
||||
/* If needed, configure the default color and blending
|
||||
* factors
|
||||
*/
|
||||
LTDC_L1CACR = 0x000000FF;
|
||||
LTDC_L1BFCR = LTDC_LxBFCR_BF1_PIXEL_ALPHA_x_CONST_ALPHA |
|
||||
LTDC_LxBFCR_BF2_PIXEL_ALPHA_x_CONST_ALPHA;
|
||||
}
|
||||
|
||||
/* Configure the Layer 2 parameters. */
|
||||
{
|
||||
/* The Layer window horizontal and vertical position */
|
||||
uint32_t h_start = HSYNC + HBP + 0;
|
||||
uint32_t h_stop = HSYNC + HBP + LCD_LAYER2_WIDTH - 1;
|
||||
LTDC_L2WHPCR = h_stop << LTDC_LxWHPCR_WHSPPOS_SHIFT |
|
||||
h_start << LTDC_LxWHPCR_WHSTPOS_SHIFT;
|
||||
uint32_t v_start = VSYNC + VBP + 0;
|
||||
uint32_t v_stop = VSYNC + VBP + LCD_LAYER2_HEIGHT - 1;
|
||||
LTDC_L2WVPCR = v_stop << LTDC_LxWVPCR_WVSPPOS_SHIFT |
|
||||
v_start << LTDC_LxWVPCR_WVSTPOS_SHIFT;
|
||||
|
||||
/* The pixel input format */
|
||||
LTDC_L2PFCR = LCD_LAYER2_PIXFORMAT;
|
||||
|
||||
/* The color frame buffer start address */
|
||||
LTDC_L2CFBAR = (uint32_t)lcd_layer2_frame_buffer;
|
||||
|
||||
/* The line length and pitch of the color frame buffer */
|
||||
uint32_t pitch = LCD_LAYER2_WIDTH * LCD_LAYER2_PIXEL_SIZE;
|
||||
uint32_t length = LCD_LAYER2_WIDTH * LCD_LAYER2_PIXEL_SIZE + 3;
|
||||
LTDC_L2CFBLR = pitch << LTDC_LxCFBLR_CFBP_SHIFT |
|
||||
length << LTDC_LxCFBLR_CFBLL_SHIFT;
|
||||
|
||||
/* The number of lines of the color frame buffer */
|
||||
LTDC_L2CFBLNR = LCD_LAYER2_HEIGHT;
|
||||
|
||||
/* If needed, load the CLUT */
|
||||
/* (not using CLUT) */
|
||||
|
||||
/* If needed, configure the default color and blending
|
||||
* factors
|
||||
*/
|
||||
LTDC_L2CACR = 0x000000FF;
|
||||
LTDC_L2BFCR = LTDC_LxBFCR_BF1_PIXEL_ALPHA_x_CONST_ALPHA |
|
||||
LTDC_LxBFCR_BF2_PIXEL_ALPHA_x_CONST_ALPHA;
|
||||
}
|
||||
|
||||
/* Enable Layer1 and if needed the CLUT */
|
||||
LTDC_L1CR |= LTDC_LxCR_LAYER_ENABLE;
|
||||
|
||||
/* Enable Layer2 and if needed the CLUT */
|
||||
LTDC_L2CR |= LTDC_LxCR_LAYER_ENABLE;
|
||||
|
||||
/* If needed, enable dithering and/or color keying. */
|
||||
/* (Not needed) */
|
||||
|
||||
/* Reload the shadow registers to active registers. */
|
||||
LTDC_SRCR |= LTDC_SRCR_VBR;
|
||||
|
||||
/* Enable the LCD-TFT controller. */
|
||||
LTDC_GCR |= LTDC_GCR_LTDC_ENABLE;
|
||||
}
|
||||
|
||||
static void mutate_background_color(void)
|
||||
{
|
||||
static uint32_t ints;
|
||||
ints += 3;
|
||||
uint32_t shift = ints >> 9;
|
||||
if (shift >= 3) {
|
||||
ints = shift = 0;
|
||||
}
|
||||
uint32_t component = ints & 0xFF;
|
||||
if (ints & 0x100) {
|
||||
component = 0xff - component;
|
||||
}
|
||||
|
||||
LTDC_BCCR = component << 8 * shift;
|
||||
}
|
||||
|
||||
/*
|
||||
* The sprite bounce algorithm works surprisingly well for a first
|
||||
* guess. Whenever the sprite touches a wall, we reverse its velocity
|
||||
* normal to the wall, and pick a random velocity from -3 to +3
|
||||
* parallel to the wall. (e.g., if it touches a side, reverse the X
|
||||
* velocity and pick a random Y velocity.) That gives enough
|
||||
* unpredictability to make it interesting.
|
||||
*
|
||||
* The random numbers come from rand(), and we do not call srand().
|
||||
* That means the sprite makes exactly the same moves every time the
|
||||
* demo is run. (Repeatability is a feature.)
|
||||
*/
|
||||
|
||||
static void move_sprite(void)
|
||||
{
|
||||
static int8_t dx = 1, dy = 1;
|
||||
static int16_t x, y;
|
||||
static int16_t age;
|
||||
x += dx;
|
||||
y += dy;
|
||||
if (x < 0) {
|
||||
dy = rand() % 7 - 3;
|
||||
dx = -dx;
|
||||
x = 0;
|
||||
age = 0;
|
||||
} else if (x >= LCD_WIDTH - LCD_LAYER2_WIDTH) {
|
||||
dy = rand() % 7 - 3;
|
||||
dx = -dx;
|
||||
x = LCD_WIDTH - LCD_LAYER2_WIDTH - 1;
|
||||
age = 0;
|
||||
}
|
||||
if (y < 0) {
|
||||
dx = rand() % 7 - 3;
|
||||
dy = -dy;
|
||||
y = 0;
|
||||
age = 0;
|
||||
} else if (y >= LCD_HEIGHT - LCD_LAYER2_HEIGHT) {
|
||||
dx = rand() % 7 - 3;
|
||||
dy = -dy;
|
||||
y = LCD_HEIGHT - LCD_LAYER2_HEIGHT - 1;
|
||||
age = 0;
|
||||
}
|
||||
if (dy == 0 && dx == 0) {
|
||||
dy = y ? -1 : +1;
|
||||
}
|
||||
uint32_t h_start = HSYNC + HBP + x;
|
||||
uint32_t h_stop = h_start + LCD_LAYER2_WIDTH - 1;
|
||||
LTDC_L2WHPCR = h_stop << LTDC_LxWHPCR_WHSPPOS_SHIFT |
|
||||
h_start << LTDC_LxWHPCR_WHSTPOS_SHIFT;
|
||||
uint32_t v_start = VSYNC + VBP + y;
|
||||
uint32_t v_stop = v_start + LCD_LAYER2_HEIGHT - 1;
|
||||
LTDC_L2WVPCR = v_stop << LTDC_LxWVPCR_WVSPPOS_SHIFT |
|
||||
v_start << LTDC_LxWVPCR_WVSTPOS_SHIFT;
|
||||
|
||||
/* The sprite fades away as it ages. */
|
||||
age += 2;
|
||||
if (age > 0xFF) {
|
||||
age = 0xFF;
|
||||
}
|
||||
LTDC_L2CACR = 0x000000FF - age;
|
||||
}
|
||||
|
||||
/*
|
||||
* Here is where all the work is done. We poke a total of 6 registers
|
||||
* for each frame.
|
||||
*/
|
||||
|
||||
void lcd_tft_isr(void)
|
||||
{
|
||||
LTDC_ICR |= LTDC_ICR_CRRIF;
|
||||
|
||||
mutate_background_color();
|
||||
move_sprite();
|
||||
|
||||
LTDC_SRCR |= LTDC_SRCR_VBR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checkerboard pattern. Odd squares are transparent; even squares are
|
||||
* all different colors.
|
||||
*/
|
||||
|
||||
static void draw_layer_1(void)
|
||||
{
|
||||
int row, col;
|
||||
int cel_count = (LCD_LAYER1_WIDTH >> 5) + (LCD_LAYER1_HEIGHT >> 5);
|
||||
|
||||
for (row = 0; row < LCD_LAYER1_HEIGHT; row++) {
|
||||
for (col = 0; col < LCD_LAYER1_WIDTH; col++) {
|
||||
size_t i = row * LCD_LAYER1_WIDTH + col;
|
||||
uint32_t cel = (row >> 5) + (col >> 5);
|
||||
uint8_t a = cel & 1 ? 0 : 0xFF;
|
||||
uint8_t r = row * 0xFF / LCD_LAYER1_HEIGHT;
|
||||
uint8_t g = col * 0xFF / LCD_LAYER1_WIDTH;
|
||||
uint8_t b = 0xFF * (cel_count - cel - 1) / cel_count;
|
||||
if (!(cel & 3)) {
|
||||
b = 0;
|
||||
}
|
||||
|
||||
/* Put black and white borders around the squares. */
|
||||
if (row % 32 == 0 || col % 32 == 0) {
|
||||
r = g = b = a ? 0xFF : 0;
|
||||
a = 0xFF;
|
||||
}
|
||||
layer1_pixel pix = a << 24 | r << 16 | g << 8 | b << 0;
|
||||
|
||||
/*
|
||||
* Outline the screen in white. Put a black
|
||||
* dot at the origin.
|
||||
*
|
||||
* (The origin is in the lower left!)
|
||||
*/
|
||||
if (row == 0 || col == 0 || row == 319 || col == 239) {
|
||||
pix = 0xFFFFFFFF;
|
||||
} else if (row < 20 && col < 20) {
|
||||
pix = 0xFF000000;
|
||||
}
|
||||
lcd_layer1_frame_buffer[i] = pix;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Layer 2 holds the sprite. The sprite is a semitransparent
|
||||
* magenta/cyan diamond outlined in black.
|
||||
*/
|
||||
|
||||
static void draw_layer_2(void)
|
||||
{
|
||||
int row, col;
|
||||
const uint8_t hw = LCD_LAYER2_WIDTH / 2;
|
||||
const uint8_t hh = LCD_LAYER2_HEIGHT / 2;
|
||||
const uint8_t sz = (hw + hh) / 2;
|
||||
|
||||
for (row = 0; row < LCD_LAYER2_HEIGHT; row++) {
|
||||
for (col = 0; col < LCD_LAYER2_WIDTH; col++) {
|
||||
size_t i = row * LCD_LAYER2_WIDTH + col;
|
||||
uint8_t dx = abs(col - hw);
|
||||
uint8_t dy = abs(row - hh);
|
||||
uint8_t dxy = dx + dy;
|
||||
uint8_t a = dxy <= sz ? 0xF * dxy / (sz / 2) : 0x0;
|
||||
if (a > 0xF) {
|
||||
if (a < 0x14) {
|
||||
a = 0xF;
|
||||
} else {
|
||||
a &= 0xF;
|
||||
}
|
||||
}
|
||||
uint8_t r = dx >= dy ? 0xF : 0x0;
|
||||
uint8_t g = dy >= dx ? 0xF : 0x0;
|
||||
uint8_t b = 0xF;
|
||||
if (dx + dy >= sz - 2 || dx == dy) {
|
||||
r = g = b = 0;
|
||||
}
|
||||
layer2_pixel pix = a << 12 | r << 8 | g << 4 | b << 0;
|
||||
lcd_layer2_frame_buffer[i] = pix;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* init timers. */
|
||||
clock_setup();
|
||||
|
||||
/* set up USART 1. */
|
||||
console_setup(115200);
|
||||
console_stdio_setup();
|
||||
|
||||
/* set up SDRAM. */
|
||||
sdram_init();
|
||||
|
||||
printf("Preloading frame buffers\n");
|
||||
|
||||
draw_layer_1();
|
||||
draw_layer_2();
|
||||
|
||||
printf("Initializing LCD\n");
|
||||
|
||||
lcd_dma_init();
|
||||
lcd_spi_init();
|
||||
|
||||
printf("Initialized.\n");
|
||||
|
||||
while (1) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
383
examples/stm32/f4/stm32f429i-discovery/lcd-dma/lcd-spi.c
Normal file
383
examples/stm32/f4/stm32f429i-discovery/lcd-dma/lcd-spi.c
Normal file
@@ -0,0 +1,383 @@
|
||||
#include "lcd-spi.h"
|
||||
|
||||
/*
|
||||
* This file is part of the libopencm3 project.
|
||||
*
|
||||
* Copyright (C) 2014 Chuck McManis <cmcmanis@mcmanis.com>
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Initialize the ST Micro TFT Display for DMA video using the SPI port
|
||||
*/
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <libopencm3/stm32/spi.h>
|
||||
#include <libopencm3/stm32/rcc.h>
|
||||
#include <libopencm3/stm32/gpio.h>
|
||||
#include <libopencm3/cm3/nvic.h>
|
||||
|
||||
#include "clock.h"
|
||||
|
||||
#define LCD_SPI SPI5
|
||||
|
||||
/*
|
||||
* This is an ungainly workaround (aka hack) basically I want to know
|
||||
* when the SPI port is 'done' sending all of the bits out, and it is
|
||||
* done when it has clocked enough bits that it would have received a
|
||||
* byte. Since we're using the SPI port in write_only mode I am not
|
||||
* collecting the "received" bytes into a buffer, but one could of
|
||||
* course. I keep track of how many bytes should have been returned
|
||||
* by decrementing the 'rx_pend' volatile. When it reaches 0 we know
|
||||
* we are done.
|
||||
*/
|
||||
|
||||
static volatile int rx_pend;
|
||||
static volatile uint16_t spi_rx_buf;
|
||||
|
||||
/*
|
||||
* This is the ISR we use. Note that the name is based on the name
|
||||
* in the irq.json file of libopencm3 plus the "_isr" extension.
|
||||
*/
|
||||
void
|
||||
spi5_isr(void)
|
||||
{
|
||||
spi_rx_buf = SPI_DR(SPI5);
|
||||
--rx_pend;
|
||||
}
|
||||
|
||||
/*
|
||||
* For the STM32-DISCO board, SPI pins in use:
|
||||
* N/C - RESET
|
||||
* PC2 - CS (could be NSS but won't be)
|
||||
* PF7 - SCLK (AF5) SPI5
|
||||
* PD13 - DATA / CMD*
|
||||
* PF9 - MOSI (AF5) SPI5
|
||||
*/
|
||||
|
||||
/*
|
||||
* void lcd_command(cmd, delay, args, arg_ptr)
|
||||
*
|
||||
* All singing all dancing 'do a command' feature. Basically it
|
||||
* sends a command, and if args are present it sets 'data' and
|
||||
* sends those along too.
|
||||
*/
|
||||
static void
|
||||
lcd_command(uint8_t cmd, int delay, int n_args, const uint8_t *args)
|
||||
{
|
||||
uint32_t timeout;
|
||||
int i;
|
||||
|
||||
gpio_clear(GPIOC, GPIO2); /* Select the LCD */
|
||||
rx_pend++;
|
||||
spi_send(SPI5, cmd);
|
||||
/* We need to wait until it is sent, if we turn on the Data
|
||||
* line too soon, it ends up confusing the display to thinking
|
||||
* its a data transfer, as it samples the D/CX line on the last
|
||||
* bit sent.
|
||||
*/
|
||||
for (timeout = 0; (timeout < 1000) && (rx_pend); timeout++) {
|
||||
continue;
|
||||
}
|
||||
rx_pend = 0; /* sometimes, at 10Mhz we miss this */
|
||||
if (n_args) {
|
||||
gpio_set(GPIOD, GPIO13); /* Set the D/CX pin */
|
||||
for (i = 0; i < n_args; i++) {
|
||||
rx_pend++;
|
||||
spi_send(SPI5, *(args+i));
|
||||
}
|
||||
/* This wait so that we don't pull CS too soon after
|
||||
* sending the last byte of data.
|
||||
*/
|
||||
for (timeout = 0; (timeout < 1000) && (rx_pend); timeout++) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
gpio_set(GPIOC, GPIO2); /* Turn off chip select */
|
||||
gpio_clear(GPIOD, GPIO13); /* always reset D/CX */
|
||||
if (delay) {
|
||||
milli_sleep(delay); /* wait, if called for */
|
||||
}
|
||||
}
|
||||
|
||||
/* Notes on the less obvious ILI9341 commands: */
|
||||
|
||||
/*
|
||||
* ILI9341 datasheet, pp 46-49:
|
||||
*
|
||||
* RCM[1:0} = 0b10 command 0xb0
|
||||
* DPI[2:0] = 0b110 command 0x3a
|
||||
* RIM = 0 command 0xf6
|
||||
* PCDIV = ???? command 0xB6
|
||||
*
|
||||
* Pp 239-240:
|
||||
* external fosc = DOTCLK / (2 * (PCDIV + 1))
|
||||
*
|
||||
* ("Cube" is how the STM32F4Cube demo software sets the register.
|
||||
* "Chuck" is ChuckM's lcd-serial demo, first revision.)
|
||||
*
|
||||
* Command 0x3A: COLMOD: Pixel Format Set LCD_PIXEL_FORMAT
|
||||
* Reset Cube Chuck
|
||||
* DPI[2:0] 110 (18 bit/pix) 110 101 (16 bit/pix)
|
||||
* DBI[2:0] 110 (18 bit/pix) 110 101 (16 bit/pix)
|
||||
*
|
||||
* Command 0xB0: RGB Interface Signal LCD_RGB_INTERFACE
|
||||
* Reset Cube
|
||||
* Bypass: 0 (direct) 1 (memory)
|
||||
* RCM[1:0] 10 10
|
||||
* VSPL 0 (low) 0
|
||||
* HSPL 0 (low) 0
|
||||
* DPL 0 (rising) 1 (falling)
|
||||
* EPL 1 (low) 0 (high)
|
||||
*
|
||||
* Command 0xB6: Display Function Control LCD_DFC
|
||||
* Reset Cube 0A A7 27 04
|
||||
* PTG[1:0] 10 10
|
||||
* PT[1:0] 10 10
|
||||
* REV 1 1
|
||||
* GS 0 0
|
||||
* SS 0 (S1->S720) 1 (S720->S1)
|
||||
* SM 0 0
|
||||
* ISC[3:0] 0010 (5 frames) 0111 (15 frames)
|
||||
* NL[5:0] 100111 100111
|
||||
* PCDIV[5:0] ? 000100
|
||||
* S720->S1 moves the origin from the lower left corner to lower right
|
||||
* (viewing the board so the silkscreen is upright)
|
||||
*
|
||||
* Command 0xF6: Interface Control LCD_INTERFACE
|
||||
* Reset Cube 01 00 06
|
||||
* MY_EOR 0 0
|
||||
* MX_EOR 0 0
|
||||
* MV_EOR 0 0
|
||||
* BGR_EOR 0 0
|
||||
* WEMODE 1 (wrap) 1
|
||||
* EPF[1:0] 00 00
|
||||
* MDT[1:0] 00 00
|
||||
* ENDIAN 0 (MSB first) 0
|
||||
* DM[1:0] 00 (int clk) 01 (RGB ifc)
|
||||
* RM 0 (sys ifc) 1 (RGB ifc)
|
||||
* RIM 0 (1 xfr/pix) 0
|
||||
*/
|
||||
|
||||
/* ILI9341 command definitions */
|
||||
|
||||
/* Regulative[sic] Command Set */
|
||||
#define ILI_NOP 0x00
|
||||
#define ILI_RESET 0x01
|
||||
#define ILI_RD_DID 0x04
|
||||
#define ILI_RD_STS 0x09
|
||||
#define ILI_RD_PWR_MODE 0x0a
|
||||
#define ILI_RD_MADCTL 0x0b
|
||||
#define ILI_RD_PXL_FMT 0x0c
|
||||
#define ILI_PD_IMG_FMT 0x0d
|
||||
#define ILI_RD_SIG_MODE 0x0e
|
||||
#define ILI_RD_DIAG_RSLT 0x0f
|
||||
#define ILI_ENTER_SLEEP 0x10
|
||||
#define ILI_SLEEP_OUT 0x11
|
||||
#define ILI_PARTIAL_ON 0x12
|
||||
#define ILI_NORMAL_MODE_ON 0x13
|
||||
#define ILI_INVERSE_ON 0x20
|
||||
#define ILI_INVERSE_OFF 0x21
|
||||
#define ILI_GAMMA_SET 0x26
|
||||
#define ILI_DISP_OFF 0x28
|
||||
#define ILI_DISP_ON 0x29
|
||||
#define ILI_CAS 0x2a
|
||||
#define ILI_PAS 0x2b
|
||||
#define ILI_MEM_WRITE 0x2c
|
||||
#define ILI_COLOR_SET 0x2d
|
||||
#define ILI_MEM_READ 0x2e
|
||||
#define ILI_PARTIAL_AREA 0x30
|
||||
#define ILI_VERT_SCROLL_DEF 0x33
|
||||
#define ILI_TEAR_EFF_OFF 0x34
|
||||
#define ILI_TEAR_EFF_ON 0x35
|
||||
#define ILI_MEM_ACC_CTL 0x36
|
||||
#define ILI_V_SCROLL_START 0x37
|
||||
#define ILI_IDLE_OFF 0x38
|
||||
#define ILI_IDLE_ON 0x39
|
||||
#define ILI_PIX_FMT_SET 0x3a
|
||||
#define ILI_WR_MEM_CONT 0x3c
|
||||
#define ILI_RD_MEM_CONT 0x3e
|
||||
#define ILI_SET_TEAR_LINE 0x44
|
||||
#define ILI_GET_SCANLINE 0x45
|
||||
#define ILI_WR_BRIGHTNESS 0x51
|
||||
#define ILI_RD_BRIGHTNESS 0x52
|
||||
#define ILI_WR_CTRL 0x53
|
||||
#define ILI_RD_CTRL 0x54
|
||||
#define ILI_WR_CABC 0x55
|
||||
#define ILI_RD_CABC 0x56
|
||||
#define ILI_WR_CABC_MIN 0x5e
|
||||
#define ILI_RD_CABC_MAX 0x5f
|
||||
#define ILI_RD_ID1 0xda
|
||||
#define ILI_RD_ID2 0xdb
|
||||
#define ILI_RD_ID3 0xdc
|
||||
|
||||
/* Extended Command Set */
|
||||
#define ILI_RGB_IFC_CTL 0xb0
|
||||
#define ILI_FRM_CTL_NORM 0xb1
|
||||
#define ILI_FRM_CTL_IDLE 0xb2
|
||||
#define ILI_FRM_CTL_PART 0xb3
|
||||
#define ILI_INVERSE_CTL 0xb4
|
||||
#define ILI_PORCH_CTL 0xb5
|
||||
#define ILI_FUNC_CTL 0xb6
|
||||
#define ILI_ENTRY_MODE_SET 0xb7
|
||||
#define ILI_BL_CTL_1 0xb8
|
||||
#define ILI_BL_CTL_2 0xb9
|
||||
#define ILI_BL_CTL_3 0xba
|
||||
#define ILI_BL_CTL_4 0xbb
|
||||
#define ILI_BL_CTL_5 0xbc
|
||||
#define ILI_BL_CTL_7 0xbe
|
||||
#define ILI_BL_CTL_8 0xbf
|
||||
#define ILI_PWR_CTL_1 0xc0
|
||||
#define ILI_PWR_CTL_2 0xc1
|
||||
#define ILI_VCOM_CTL_1 0xc5
|
||||
#define ILI_VCOM_CTL_2 0xc7
|
||||
#define ILI_NV_MEM_WR 0xd0
|
||||
#define ILI_NV_MEM_PROT_KEY 0xd1
|
||||
#define ILI_NV_MEM_STATUS_RD 0xd2
|
||||
#define ILI_RD_ID4 0xd3
|
||||
#define ILI_POS_GAMMA 0xe0
|
||||
#define ILI_NEG_GAMMA 0xe1
|
||||
#define ILI_GAMMA_CTL_1 0xe2
|
||||
#define ILI_GAMMA_CTL_2 0xe3
|
||||
#define ILI_IFC_CTL 0xf6
|
||||
|
||||
/*
|
||||
* This structure defines the sequence of commands to send
|
||||
* to the Display in order to initialize it. The AdaFruit
|
||||
* folks do something similar, it helps when debugging the
|
||||
* initialization sequence for the display.
|
||||
*/
|
||||
|
||||
#define MAX_INLINE_ARGS (sizeof(uint8_t *))
|
||||
struct tft_command {
|
||||
uint16_t delay; /* If you need a delay after */
|
||||
uint8_t cmd; /* command to send */
|
||||
uint8_t n_args; /* How many arguments it has */
|
||||
union {
|
||||
uint8_t args[MAX_INLINE_ARGS]; /* The first four arguments */
|
||||
const uint8_t *aptr; /* More than four arguemnts */
|
||||
};
|
||||
};
|
||||
|
||||
static const uint8_t pos_gamma_args[] = { 0x0F, 0x29, 0x24, 0x0C, 0x0E,
|
||||
0x09, 0x4E, 0x78, 0x3C, 0x09,
|
||||
0x13, 0x05, 0x17, 0x11, 0x00 };
|
||||
static const uint8_t neg_gamma_args[] = { 0x00, 0x16, 0x1B, 0x04, 0x11,
|
||||
0x07, 0x31, 0x33, 0x42, 0x05,
|
||||
0x0C, 0x0A, 0x28, 0x2F, 0x0F };
|
||||
|
||||
/*
|
||||
* These are the commands we're going to send to the
|
||||
* display to initialize it. We send them all, in sequence
|
||||
* with occasional delays. Commands that require data bytes
|
||||
* as arguments, indicate how many bytes to pull out the
|
||||
* above array to include.
|
||||
*
|
||||
* The sequence was pieced together from the ST Micro demo
|
||||
* code, the data sheet, and other sources on the web.
|
||||
*/
|
||||
#define EXPERIMENT 1
|
||||
const struct tft_command initialization[] = {
|
||||
{ 0, ILI_PWR_CTL_1, 1, .args = { 0x10 } },
|
||||
{ 0, ILI_PWR_CTL_2, 1, .args = { 0x10 } },
|
||||
{ 0, ILI_VCOM_CTL_1, 2, .args = { 0x45, 0x15 } },
|
||||
{ 0, ILI_VCOM_CTL_2, 1, .args = { 0x90 } },
|
||||
{ 0, ILI_MEM_ACC_CTL, 1, .args = { 0x08 } },
|
||||
{ 0, ILI_RGB_IFC_CTL, 1, .args = { 0xc0 } },
|
||||
{ 0, ILI_IFC_CTL, 3, .args = { 0x01, 0x00, 0x06 } },
|
||||
{ 0, ILI_GAMMA_SET, 1, .args = { 0x01 } },
|
||||
{ 0, ILI_POS_GAMMA, 15, .aptr = pos_gamma_args },
|
||||
{ 0, ILI_NEG_GAMMA, 15, .aptr = neg_gamma_args },
|
||||
{ +5, ILI_SLEEP_OUT, 0, .args = {} },
|
||||
{ 0, ILI_DISP_ON, 0, .args = {} },
|
||||
};
|
||||
|
||||
static void
|
||||
initialize_display(const struct tft_command cmds[], size_t cmd_count)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < cmd_count; i++) {
|
||||
uint8_t arg_count = cmds[i].n_args;
|
||||
const uint8_t *args = cmds[i].args;
|
||||
if (arg_count > MAX_INLINE_ARGS) {
|
||||
args = cmds[i].aptr;
|
||||
}
|
||||
lcd_command(cmds[i].cmd, cmds[i].delay, arg_count, args);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* void lcd_spi_init(void)
|
||||
*
|
||||
* Initialize the SPI port, and the through that port
|
||||
* initialize the LCD controller. Note that this code
|
||||
* will expect to be able to draw into the SDRAM on
|
||||
> * the board, so the sdram much be initialized before
|
||||
* calling this function.
|
||||
*
|
||||
* SPI Port and GPIO Defined - for STM32F4-Disco
|
||||
*
|
||||
* LCD_CS PC2
|
||||
* LCD_SCK PF7
|
||||
* LCD_DC PD13
|
||||
* LCD_MOSI PF9
|
||||
* LCD_SPI SPI5
|
||||
* LCD_WIDTH 240
|
||||
* LCD_HEIGHT 320
|
||||
*/
|
||||
void
|
||||
lcd_spi_init(void)
|
||||
{
|
||||
uint32_t tmp;
|
||||
|
||||
/*
|
||||
* Set up the GPIO lines for the SPI port and
|
||||
* control lines on the display.
|
||||
*/
|
||||
rcc_periph_clock_enable(RCC_GPIOC | RCC_GPIOD | RCC_GPIOF);
|
||||
|
||||
gpio_mode_setup(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO2);
|
||||
gpio_mode_setup(GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO13);
|
||||
|
||||
gpio_mode_setup(GPIOF, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO7 | GPIO9);
|
||||
gpio_set_af(GPIOF, GPIO_AF5, GPIO7 | GPIO9);
|
||||
|
||||
rx_pend = 0;
|
||||
/* Implement state management hack */
|
||||
nvic_enable_irq(NVIC_SPI5_IRQ);
|
||||
|
||||
rcc_periph_clock_enable(RCC_SPI5);
|
||||
/* This should configure SPI5 as we need it configured */
|
||||
tmp = SPI_SR(LCD_SPI);
|
||||
SPI_CR2(LCD_SPI) |= (SPI_CR2_SSOE | SPI_CR2_RXNEIE);
|
||||
|
||||
/* device clocks on the rising edge of SCK with MSB first */
|
||||
tmp = SPI_CR1_BAUDRATE_FPCLK_DIV_4 | /* 10.25Mhz SPI Clock (42M/4) */
|
||||
SPI_CR1_MSTR | /* Master Mode */
|
||||
SPI_CR1_BIDIOE | /* Write Only */
|
||||
SPI_CR1_SPE; /* Enable SPI */
|
||||
|
||||
SPI_CR1(LCD_SPI) = tmp; /* Do it. */
|
||||
if (SPI_SR(LCD_SPI) & SPI_SR_MODF) {
|
||||
SPI_CR1(LCD_SPI) = tmp; /* Re-writing will reset MODF */
|
||||
fprintf(stderr, "Initial mode fault.\n");
|
||||
}
|
||||
|
||||
/* Set up the display */
|
||||
initialize_display(initialization,
|
||||
sizeof(initialization) / sizeof(initialization[0]));
|
||||
}
|
||||
31
examples/stm32/f4/stm32f429i-discovery/lcd-dma/lcd-spi.h
Normal file
31
examples/stm32/f4/stm32f429i-discovery/lcd-dma/lcd-spi.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* This file is part of the libopencm3 project.
|
||||
*
|
||||
* Copyright (C) 2014 Chuck McManis <cmcmanis@mcmanis.com>
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LCD_SPI_H
|
||||
#define LCD_SPI_H
|
||||
|
||||
/*
|
||||
* prototypes for the LCD example
|
||||
*
|
||||
* This is a very basic API, initialize.
|
||||
*/
|
||||
|
||||
extern void lcd_spi_init(void);
|
||||
|
||||
#endif /* !LCD_SPI_H */
|
||||
139
examples/stm32/f4/stm32f429i-discovery/lcd-dma/sdram.c
Normal file
139
examples/stm32/f4/stm32f429i-discovery/lcd-dma/sdram.c
Normal file
@@ -0,0 +1,139 @@
|
||||
#include "sdram.h"
|
||||
/*
|
||||
* This file is part of the libopencm3 project.
|
||||
*
|
||||
* Copyright (C) 2014 Chuck McManis <cmcmanis@mcmanis.com>
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This then is the initialization code extracted from the
|
||||
* sdram example.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <libopencm3/stm32/gpio.h>
|
||||
#include <libopencm3/stm32/rcc.h>
|
||||
#include <libopencm3/stm32/fsmc.h>
|
||||
#include "clock.h"
|
||||
|
||||
/*
|
||||
* This is just syntactic sugar but it helps, all of these
|
||||
* GPIO pins get configured in exactly the same way.
|
||||
*/
|
||||
static struct {
|
||||
uint32_t gpio;
|
||||
uint16_t pins;
|
||||
} sdram_pins[6] = {
|
||||
{GPIOB, GPIO5 | GPIO6 },
|
||||
{GPIOC, GPIO0 },
|
||||
{GPIOD, GPIO0 | GPIO1 | GPIO8 | GPIO9 | GPIO10 | GPIO14 | GPIO15},
|
||||
{GPIOE, GPIO0 | GPIO1 | GPIO7 | GPIO8 | GPIO9 | GPIO10 |
|
||||
GPIO11 | GPIO12 | GPIO13 | GPIO14 | GPIO15 },
|
||||
{GPIOF, GPIO0 | GPIO1 | GPIO2 | GPIO3 | GPIO4 | GPIO5 | GPIO11 |
|
||||
GPIO12 | GPIO13 | GPIO14 | GPIO15 },
|
||||
{GPIOG, GPIO0 | GPIO1 | GPIO4 | GPIO5 | GPIO8 | GPIO15}
|
||||
};
|
||||
|
||||
static struct sdram_timing timing = {
|
||||
.trcd = 2, /* RCD Delay */
|
||||
.trp = 2, /* RP Delay */
|
||||
.twr = 2, /* Write Recovery Time */
|
||||
.trc = 7, /* Row Cycle Delay */
|
||||
.tras = 4, /* Self Refresh Time */
|
||||
.txsr = 7, /* Exit Self Refresh Time */
|
||||
.tmrd = 2, /* Load to Active Delay */
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialize the SD RAM controller.
|
||||
*/
|
||||
void
|
||||
sdram_init(void) {
|
||||
int i;
|
||||
uint32_t cr_tmp, tr_tmp; /* control, timing registers */
|
||||
|
||||
/*
|
||||
* First all the GPIO pins that end up as SDRAM pins
|
||||
*/
|
||||
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_GPIOF);
|
||||
rcc_periph_clock_enable(RCC_GPIOG);
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
gpio_mode_setup(sdram_pins[i].gpio,
|
||||
GPIO_MODE_AF, GPIO_PUPD_NONE,
|
||||
sdram_pins[i].pins);
|
||||
gpio_set_output_options(sdram_pins[i].gpio, GPIO_OTYPE_PP,
|
||||
GPIO_OSPEED_50MHZ, sdram_pins[i].pins);
|
||||
gpio_set_af(sdram_pins[i].gpio, GPIO_AF12, sdram_pins[i].pins);
|
||||
}
|
||||
|
||||
/* Enable the SDRAM Controller */
|
||||
#if 1
|
||||
rcc_periph_clock_enable(RCC_FSMC);
|
||||
#else
|
||||
rcc_peripheral_enable_clock(&RCC_AHB3ENR, RCC_AHB3ENR_FMCEN);
|
||||
#endif
|
||||
|
||||
/* Note the STM32F429-DISCO board has the ram attached to bank 2 */
|
||||
/* Timing parameters computed for a 168Mhz clock */
|
||||
/* These parameters are specific to the SDRAM chip on the board */
|
||||
|
||||
cr_tmp = FMC_SDCR_RPIPE_1CLK;
|
||||
cr_tmp |= FMC_SDCR_SDCLK_2HCLK;
|
||||
cr_tmp |= FMC_SDCR_CAS_3CYC;
|
||||
cr_tmp |= FMC_SDCR_NB4;
|
||||
cr_tmp |= FMC_SDCR_MWID_16b;
|
||||
cr_tmp |= FMC_SDCR_NR_12;
|
||||
cr_tmp |= FMC_SDCR_NC_8;
|
||||
|
||||
/* We're programming BANK 2, but per the manual some of the parameters
|
||||
* only work in CR1 and TR1 so we pull those off and put them in the
|
||||
* right place.
|
||||
*/
|
||||
FMC_SDCR1 |= (cr_tmp & FMC_SDCR_DNC_MASK);
|
||||
FMC_SDCR2 = cr_tmp;
|
||||
|
||||
tr_tmp = sdram_timing(&timing);
|
||||
FMC_SDTR1 |= (tr_tmp & FMC_SDTR_DNC_MASK);
|
||||
FMC_SDTR2 = tr_tmp;
|
||||
|
||||
/* Now start up the Controller per the manual
|
||||
* - Clock config enable
|
||||
* - PALL state
|
||||
* - set auto refresh
|
||||
* - Load the Mode Register
|
||||
*/
|
||||
sdram_command(SDRAM_BANK2, SDRAM_CLK_CONF, 1, 0);
|
||||
milli_sleep(1); /* sleep at least 100uS */
|
||||
sdram_command(SDRAM_BANK2, SDRAM_PALL, 1, 0);
|
||||
sdram_command(SDRAM_BANK2, SDRAM_AUTO_REFRESH, 4, 0);
|
||||
tr_tmp = SDRAM_MODE_BURST_LENGTH_2 |
|
||||
SDRAM_MODE_BURST_TYPE_SEQUENTIAL |
|
||||
SDRAM_MODE_CAS_LATENCY_3 |
|
||||
SDRAM_MODE_OPERATING_MODE_STANDARD |
|
||||
SDRAM_MODE_WRITEBURST_MODE_SINGLE;
|
||||
sdram_command(SDRAM_BANK2, SDRAM_LOAD_MODE, 1, tr_tmp);
|
||||
|
||||
/*
|
||||
* set the refresh counter to insure we kick off an
|
||||
* auto refresh often enough to prevent data loss.
|
||||
*/
|
||||
FMC_SDRTR = 683;
|
||||
/* and Poof! a 8 megabytes of ram shows up in the address space */
|
||||
}
|
||||
32
examples/stm32/f4/stm32f429i-discovery/lcd-dma/sdram.h
Normal file
32
examples/stm32/f4/stm32f429i-discovery/lcd-dma/sdram.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* This file is part of the libopencm3 project.
|
||||
*
|
||||
* Copyright (C) 2014 Chuck McManis <cmcmanis@mcmanis.com>
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __SDRAM_H
|
||||
#define __SDRAM_H
|
||||
|
||||
#define SDRAM_BASE_ADDRESS ((uint8_t *)(0xd0000000))
|
||||
|
||||
/* Initialize the SDRAM chip on the board */
|
||||
void sdram_init(void);
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL (void *)(0)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user