[stm32f429i-discovery] Moved Chucks remaining examples to the correct directory.

Additionally added Chucks readme to the stm32f429i-discovery board
readme.
This commit is contained in:
Piotr Esden-Tempski
2015-01-22 18:38:16 -08:00
parent 86c42bc2dd
commit d29e4d2b7c
30 changed files with 39 additions and 75 deletions

View File

@@ -0,0 +1,25 @@
#
# This file is part of the libopencm3 project.
#
# 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/>.
#
OBJS = console.o clock.o
BINARY = sdram
LDSCRIPT = ../stm32f429i-discovery.ld
include ../../Makefile.include

View File

@@ -0,0 +1,70 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2013 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 msleep(uint32_t delay) {
uint32_t wake = system_millis + delay;
while (wake > system_millis) ;
}
/* 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();
}

View File

@@ -0,0 +1,15 @@
/*
* This include file describes the functions exported by clock.c
*/
#ifndef __CLOCK_H
#define __CLOCK_H
/*
* Definitions for functions being abstracted out
*/
void msleep(uint32_t);
uint32_t mtime(void);
void clock_setup(void);
#endif /* generic header protector */

View File

@@ -0,0 +1,235 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2013 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/>.
*/
/*
* USART example (alternate console)
*
* This version then adds in interrupts, which is really handy for
* the receive function as it is impossible to predict when someone
* might type a character, further you can create a "character based
* reset" capability if you choose to.
*/
#include <stdint.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 "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.
*/
#define CONSOLE_UART USART1
/* 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];
volatile int recv_ndx_nxt; // Next place to store
volatile int recv_ndx_cur; // Next place to read
/* For interrupt handling we add a new function which is called
* when recieve interrupts happen. The name (usart1_isr) is created
* by the irq.json file in libopencm3 calling this interrupt for
* USART2 'usart2', 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') {
/* reset the system */
volatile uint32_t *ret = (&reg) + 7; // Return address on stack
*ret = (uint32_t) &reset_handler; // force system reset
return; // go to new address
}
#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);
}
/*
* Set up the GPIO subsystem with an "Alternate Function"
* on some of the pins, in this case connected to a
* USART.
*/
void console_setup(void) {
/* MUST enable the GPIO clock in ADDITION to the USART clock */
rcc_periph_clock_enable(RCC_GPIOA);
/* This example uses PD9 and PD10 for Tx and Rx respectively
* but other pins are available for this role on USART1 (our chosen
* USART) as well, we are using them because they are connected over
* jumpers to the programmer.
*/
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 APB1 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.
* We are using the rcc_periph_clock_enable function that knows which
* peripheral is on which clock bus and sets things up accordingly.
*/
rcc_periph_clock_enable(RCC_USART1);
/* Set up USART/UART parameters using the libopencm3 helper functions */
usart_set_baudrate(CONSOLE_UART, 115200);
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 recieve interrupts */
usart_enable_rx_interrupt(CONSOLE_UART);
}

View File

@@ -0,0 +1,13 @@
/*
* 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(void);
/* this is for fun, if you type ^C to this example it will reset */
#define RESET_ON_CTRLC

View File

@@ -0,0 +1,338 @@
/*
* sdram.c - SDRAM controller example
*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2013 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/>.
*/
#include <stdint.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/fsmc.h>
#include "clock.h"
#include "console.h"
#define SDRAM_BASE_ADDRESS ((uint8_t *)(0xd0000000))
void sdram_init(void);
#ifndef NULL
#define NULL (void *)(0)
#endif
/*
* 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 */
rcc_periph_clock_enable(RCC_FSMC);
/* 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);
msleep(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 */
}
/*
* This code are some routines that implement a "classic"
* hex dump style memory dump. So you can look at what is
* in the RAM, alter it (in a couple of automated ways)
*/
void dump_byte(uint8_t b);
void dump_long(uint32_t l);
uint8_t *dump_line(uint8_t *, uint8_t *);
uint8_t *dump_page(uint8_t *, uint8_t *);
/* make a nybble into an ascii hex character 0 - 9, A-F */
#define HEX_CHAR(x) ((((x) + '0') > '9') ? ((x) + '7') : ((x) + '0'))
/* send an 8 bit byte as two HEX characters to the console */
void dump_byte(uint8_t b) {
console_putc(HEX_CHAR((b >> 4) & 0xf));
console_putc(HEX_CHAR(b & 0xf));
}
/* send a 32 bit value as 8 hex characters to the console */
void dump_long(uint32_t l) {
int i = 0;
for (i = 0; i < 8; i++) {
console_putc(HEX_CHAR((l >> (28 - i * 4)) & 0xf));
}
}
/*
* dump a 'line' (an address, 16 bytes, and then the
* ASCII representation of those bytes) to the console.
* Takes an address (and possiblye a 'base' parameter
* so that you can offset the address) and sends 16
* bytes out. Returns the address +16 so you can
* just call it repeatedly and it will send the
* next 16 bytes out.
*/
uint8_t *
dump_line(uint8_t *addr, uint8_t *base) {
uint8_t *line_addr;
uint8_t b;
uint32_t tmp;
int i;
line_addr = addr;
tmp = (uint32_t)line_addr - (uint32_t) base;
dump_long(tmp);
console_puts(" | ");
for (i = 0; i < 16; i++) {
dump_byte(*(line_addr+i));
console_putc(' ');
if (i == 7) {
console_puts(" ");
}
}
console_puts("| ");
for (i = 0; i < 16; i++) {
b = *line_addr++;
console_putc(((b > 126) || (b < 32)) ? '.' : (char) b);
}
console_puts("\n");
return line_addr;
}
/*
* dump a 'page' like the function dump_line except this
* does 16 lines for a total of 256 bytes. Back in the
* day when you had a 24 x 80 terminal this fit nicely
* on the screen with some other information.
*/
uint8_t *
dump_page(uint8_t *addr, uint8_t *base) {
int i;
for (i = 0; i < 16; i++) {
addr = dump_line(addr, base);
}
return addr;
}
/*
* This example initializes the SDRAM controller and dumps
* it out to the console. You can do various things like
* (FI) fill with increment, (F0) fill with 0, (FF) fill
* with FF. NP (next page), PP (prev page), NL (next line),
* (PL) previous line, and (?) for help.
*/
int
main(void) {
int i;
uint8_t *addr;
char c;
clock_setup();
console_setup();
sdram_init();
console_puts("SDRAM Example.\n");
console_puts("Original data:\n");
addr = (uint8_t *)(0xd0000000);
(void) dump_page(addr, NULL);
addr = SDRAM_BASE_ADDRESS;
for (i = 0; i < 256; i++) {
*(addr + i) = i;
}
console_puts("Modified data (with Fill Increment)\n");
addr = SDRAM_BASE_ADDRESS;
addr = dump_page( addr, NULL);
while (1) {
console_puts("CMD> ");
switch (c = console_getc(1)) {
case 'f':
case 'F':
console_puts("Fill ");
switch (c = console_getc(1)) {
case 'i':
case 'I':
console_puts("Increment\n");
for (i = 0; i < 256; i++) {
*(addr+i) = i;
}
dump_page(addr, NULL);
break;
case '0':
console_puts("Zero\n");
for (i = 0; i < 256; i++) {
*(addr+i) = 0;
}
dump_page(addr, NULL);
break;
case 'f':
case 'F':
console_puts("Ones (0xff)\n");
for (i = 0; i < 256; i++) {
*(addr+i) = 0xff;
}
dump_page(addr, NULL);
break;
default:
console_puts("Unrecognized Command, press ? for help\n");
}
break;
case 'n':
case 'N':
console_puts("Next ");
switch (c = console_getc(1)) {
case 'p':
case 'P':
console_puts("Page\n");
addr += 256;
dump_page(addr, NULL);
break;
case 'l':
case 'L':
console_puts("Line\n");
addr += 16;
dump_line(addr, NULL);
break;
default:
console_puts("Unrecognized Command, press ? for help\n");
}
break;
case 'p':
case 'P':
console_puts("Previous ");
switch (c = console_getc(1)) {
case 'p':
case 'P':
console_puts("Page\n");
addr -= 256;
dump_page(addr, NULL);
break;
case 'l':
case 'L':
console_puts("Line\n");
addr -= 16;
dump_line(addr, NULL);
break;
default:
console_puts("Unrecognized Command, press ? for help\n");
}
break;
case '?':
default:
console_puts("Help\n");
console_puts(" n p - dump next page\n");
console_puts(" n l - dump next line\n");
console_puts(" p p - dump previous page\n");
console_puts(" p l - dump previous line\n");
console_puts(" f 0 - fill current page with 0\n");
console_puts(" f i - fill current page with 0 to 255\n");
console_puts(" f f - fill current page with 0xff\n");
console_puts(" ? - this message\n");
break;
}
}
}