aboutsummaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/blinky.cpp2
-rw-r--r--examples/debug-dtrrts.cpp12
-rw-r--r--examples/freertos-blinky.cpp2
-rw-r--r--examples/fsmc-stress-test.cpp6
-rw-r--r--examples/i2c-mcp4725-dac.cpp145
-rw-r--r--examples/mini-exti-test.cpp2
-rw-r--r--examples/qa-slave-shield.cpp2
-rw-r--r--examples/serial-echo.cpp30
-rw-r--r--examples/spi_master.cpp2
-rw-r--r--examples/test-bkp.cpp6
-rw-r--r--examples/test-dac.cpp4
-rw-r--r--examples/test-fsmc.cpp4
-rw-r--r--examples/test-print.cpp2
-rw-r--r--examples/test-ring-buffer-insertion.cpp4
-rw-r--r--examples/test-serial-flush.cpp2
-rw-r--r--examples/test-serialusb.cpp6
-rw-r--r--examples/test-servo.cpp2
-rw-r--r--examples/test-session.cpp2
-rw-r--r--examples/test-spi-roundtrip.cpp2
-rw-r--r--examples/test-systick.cpp4
-rw-r--r--examples/test-timers.cpp710
-rw-r--r--examples/test-usart-dma.cpp220
-rw-r--r--examples/vga-leaf.cpp2
-rw-r--r--examples/vga-scope.cpp4
24 files changed, 839 insertions, 338 deletions
diff --git a/examples/blinky.cpp b/examples/blinky.cpp
index dd72514..fad71f8 100644
--- a/examples/blinky.cpp
+++ b/examples/blinky.cpp
@@ -1,6 +1,6 @@
// Blinks the built-in LED
-#include "wirish.h"
+#include <wirish/wirish.h>
void setup() {
pinMode(BOARD_LED_PIN, OUTPUT);
diff --git a/examples/debug-dtrrts.cpp b/examples/debug-dtrrts.cpp
index 3829208..75eceef 100644
--- a/examples/debug-dtrrts.cpp
+++ b/examples/debug-dtrrts.cpp
@@ -1,7 +1,7 @@
// Test sketch for figuring out DTR/RTS behavior on different platforms.
-#include "wirish.h"
-#include "usb.h"
+#include <wirish/wirish.h>
+#include "usb_cdcacm.h"
void setup() {
/* Set up the LED to blink */
@@ -10,7 +10,6 @@ void setup() {
/* Send a message out USART2 */
Serial2.begin(9600);
Serial2.println("Debugging DTR/RTS...");
-
}
void loop() {
@@ -18,9 +17,9 @@ void loop() {
delay(100);
Serial2.print("DTR: ");
- Serial2.print(usbGetDTR(), DEC);
+ Serial2.print(usb_cdcacm_get_dtr(), DEC);
Serial2.print("\tRTS: ");
- Serial2.println(usbGetRTS(), DEC);
+ Serial2.println(usb_cdcacm_get_rts(), DEC);
}
// Force init to be called *first*, i.e. before static object allocation.
@@ -32,9 +31,8 @@ __attribute__((constructor)) void premain() {
int main(void) {
setup();
- while (1) {
+ while (true) {
loop();
}
return 0;
}
-
diff --git a/examples/freertos-blinky.cpp b/examples/freertos-blinky.cpp
index 6f82d71..2e7c7f7 100644
--- a/examples/freertos-blinky.cpp
+++ b/examples/freertos-blinky.cpp
@@ -1,4 +1,4 @@
-#include "wirish.h"
+#include <wirish/wirish.h>
#include "libraries/FreeRTOS/MapleFreeRTOS.h"
static void vLEDFlashTask(void *pvParameters) {
diff --git a/examples/fsmc-stress-test.cpp b/examples/fsmc-stress-test.cpp
index 509a02f..20d3fa7 100644
--- a/examples/fsmc-stress-test.cpp
+++ b/examples/fsmc-stress-test.cpp
@@ -12,9 +12,9 @@
#include <stdio.h>
#include <stddef.h>
-#include "wirish.h"
-#include "rcc.h"
-#include "fsmc.h"
+#include <wirish/wirish.h>
+#include <libmaple/rcc.h>
+#include <libmaple/fsmc.h>
// -- SRAM config -------------------------------------------------------------
diff --git a/examples/i2c-mcp4725-dac.cpp b/examples/i2c-mcp4725-dac.cpp
new file mode 100644
index 0000000..da9a34e
--- /dev/null
+++ b/examples/i2c-mcp4725-dac.cpp
@@ -0,0 +1,145 @@
+// i2c-mcp4725-dac.cpp
+//
+// Written by Andrew Meyer <ajm@leaflabs.com>
+// Modified by Marti Bolivar <mbolivar@leaflabs.com>
+//
+// Simple program showing how to control an MCP4725 DAC using the
+// libmaple I2C interface. There's an MCP4725 breakout board available
+// on SparkFun:
+//
+// http://www.sparkfun.com/products/8736
+//
+// How to use:
+//
+// 1. Connect the DAC SDA and SCL pins to I2C2, with a pullup
+// resistor (1 KOhm should work) to VCC.
+// 2. Load the sketch and connect to SerialUSB.
+// 3. Press the button.
+//
+// The program then makes sure the DAC is connected properly (during
+// setup()), then has the DAC output a sawtooth wave (with loop()).
+
+#include <wirish/wirish.h>
+#include <libmaple/i2c.h>
+
+#define MCP_ADDR 0x60
+#define MCP_WRITE_DAC 0b01000000
+#define MCP_WRITE_EEPROM 0b01100000
+#define MCP_PD_NORMAL 0b00000000
+#define MCP_PD_1K 0b00000010
+#define MCP_PD_100K 0b00000100
+#define MCP_PD_500K 0b00000110
+
+static uint8 write_msg_data[3];
+static i2c_msg write_msg;
+
+static uint8 read_msg_data[5];
+static i2c_msg read_msg;
+
+/*
+ * DAC control routines
+ */
+
+void mcp_i2c_setup(void) {
+ write_msg.addr = MCP_ADDR;
+ write_msg.flags = 0; // write, 7 bit address
+ write_msg.length = sizeof(write_msg_data);
+ write_msg.xferred = 0;
+ write_msg.data = write_msg_data;
+
+ read_msg.addr = MCP_ADDR;
+ read_msg.flags = I2C_MSG_READ;
+ read_msg.length = sizeof(read_msg_data);
+ read_msg.xferred = 0;
+ read_msg.data = read_msg_data;
+}
+
+void mcp_write_val(uint16 val) {
+ write_msg_data[0] = MCP_WRITE_DAC | MCP_PD_NORMAL;
+ uint16 tmp = val >> 4;
+ write_msg_data[1] = tmp;
+ tmp = (val << 4) & 0x00FF;
+ write_msg_data[2] = tmp;
+
+ i2c_master_xfer(I2C2, &write_msg, 1, 0);
+}
+
+uint16 mcp_read_val() {
+ uint16 tmp = 0;
+
+ i2c_master_xfer(I2C2, &read_msg, 1, 2);
+
+ /* We don't care about the status and EEPROM bytes (0, 3, and 4). */
+ tmp = (read_msg_data[1] << 4);
+ tmp += (read_msg_data[2] >> 4);
+ return tmp;
+}
+
+int mcp_test() {
+ uint16 val;
+ uint16 test_val = 0x0101;
+
+ SerialUSB.println("Testing the MCP4725...");
+ /* Read the value of the register (should be 0x0800 if factory fresh) */
+ val = mcp_read_val();
+ SerialUSB.print("DAC Register = 0x");
+ SerialUSB.println(val, HEX);
+
+ mcp_write_val(test_val);
+ SerialUSB.print("Wrote 0x");
+ SerialUSB.print(test_val, HEX);
+ SerialUSB.println(" to the DAC");
+
+ val = mcp_read_val();
+ SerialUSB.print("DAC Register = 0x");
+ SerialUSB.println(val, HEX);
+
+ if (val != test_val) {
+ SerialUSB.println("ERROR: MCP4725 not responding correctly");
+ return 0;
+ }
+
+ SerialUSB.println("MCP4725 seems to be working");
+ return 1;
+}
+
+/*
+ * setup() and loop()
+ */
+
+void setup() {
+ pinMode(BOARD_BUTTON_PIN, INPUT);
+ i2c_master_enable(I2C2, 0);
+ mcp_i2c_setup();
+
+ waitForButtonPress();
+ ASSERT(mcp_test());
+
+ SerialUSB.println("Starting sawtooth wave");
+}
+
+void loop() {
+ static uint16 dout = 0;
+
+ mcp_write_val(dout);
+
+ dout += 50;
+ if (dout >= 32768) {
+ dout = 0;
+ }
+}
+
+// -- init() and main() -------------------------------------------------------
+
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+
+ while (true) {
+ loop();
+ }
+ return 0;
+}
diff --git a/examples/mini-exti-test.cpp b/examples/mini-exti-test.cpp
index 84b323e..54a4dd0 100644
--- a/examples/mini-exti-test.cpp
+++ b/examples/mini-exti-test.cpp
@@ -10,7 +10,7 @@
#include <stdio.h>
#include <string.h>
-#include "wirish.h"
+#include <wirish/wirish.h>
// test routines
void run_exti_test(void);
diff --git a/examples/qa-slave-shield.cpp b/examples/qa-slave-shield.cpp
index 2da1c04..ec25e49 100644
--- a/examples/qa-slave-shield.cpp
+++ b/examples/qa-slave-shield.cpp
@@ -1,6 +1,6 @@
// Slave mode for Quality Assurance test
-#include "wirish.h"
+#include <wirish/wirish.h>
#define INTER_TOGGLE_DELAY_NORMAL 5
#define INTER_TOGGLE_DELAY_SLOW 80
diff --git a/examples/serial-echo.cpp b/examples/serial-echo.cpp
new file mode 100644
index 0000000..204f011
--- /dev/null
+++ b/examples/serial-echo.cpp
@@ -0,0 +1,30 @@
+// Simple serial port "echo". Send back any received data.
+
+#include <wirish/wirish.h>
+
+// Note: you can change "Serial1" to any other serial port you have on
+// your board.
+
+void setup() {
+ Serial1.begin(115200);
+}
+
+void loop() {
+ while (Serial1.available()) {
+ Serial1.write(Serial1.read());
+ }
+}
+
+// Force init() to be called before anything else.
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+
+ while (true) {
+ loop();
+ }
+ return 0;
+}
diff --git a/examples/spi_master.cpp b/examples/spi_master.cpp
index 100fc53..ea6c990 100644
--- a/examples/spi_master.cpp
+++ b/examples/spi_master.cpp
@@ -33,7 +33,7 @@
* Pin 10 is used as slave select.
*/
-#include "wirish.h"
+#include <wirish/wirish.h>
#define NSS 10
diff --git a/examples/test-bkp.cpp b/examples/test-bkp.cpp
index f5957b7..719cac7 100644
--- a/examples/test-bkp.cpp
+++ b/examples/test-bkp.cpp
@@ -1,8 +1,8 @@
#include <stdio.h> // for snprintf()
-#include "wirish.h"
-#include "bkp.h"
-#include "iwdg.h"
+#include <wirish/wirish.h>
+#include <libmaple/bkp.h>
+#include <libmaple/iwdg.h>
void print_bkp_contents();
void write_to_bkp(uint16 val);
diff --git a/examples/test-dac.cpp b/examples/test-dac.cpp
index 40ae5d5..af188cc 100644
--- a/examples/test-dac.cpp
+++ b/examples/test-dac.cpp
@@ -6,8 +6,8 @@
* This file is released into the public domain.
*/
-#include "wirish.h"
-#include "dac.h"
+#include <wirish/wirish.h>
+#include <libmaple/dac.h>
uint16 count = 0;
diff --git a/examples/test-fsmc.cpp b/examples/test-fsmc.cpp
index 22f6975..1621317 100644
--- a/examples/test-fsmc.cpp
+++ b/examples/test-fsmc.cpp
@@ -1,7 +1,7 @@
#include <stddef.h> // for ptrdiff_t
-#include "wirish.h"
-#include "fsmc.h"
+#include <wirish/wirish.h>
+#include <libmaple/fsmc.h>
#ifndef BOARD_maple_native
#error "Sorry, this example only works on Maple Native."
diff --git a/examples/test-print.cpp b/examples/test-print.cpp
index 5477512..bdc1894 100644
--- a/examples/test-print.cpp
+++ b/examples/test-print.cpp
@@ -8,7 +8,7 @@
* This file is released into the public domain.
*/
-#include "wirish.h"
+#include <wirish/wirish.h>
#undef min
#undef max
diff --git a/examples/test-ring-buffer-insertion.cpp b/examples/test-ring-buffer-insertion.cpp
index e86372a..2188b03 100644
--- a/examples/test-ring-buffer-insertion.cpp
+++ b/examples/test-ring-buffer-insertion.cpp
@@ -12,9 +12,9 @@
* This file is released into the public domain.
*/
-#include "wirish.h"
+#include <wirish/wirish.h>
-#include "ring_buffer.h"
+#include <libmaple/ring_buffer.h>
#define BUF_SIZE 64
ring_buffer ring_buf;
diff --git a/examples/test-serial-flush.cpp b/examples/test-serial-flush.cpp
index adc9c3e..409d1f9 100644
--- a/examples/test-serial-flush.cpp
+++ b/examples/test-serial-flush.cpp
@@ -2,7 +2,7 @@
* Tests the "flush" Serial function.
*/
-#include "wirish.h"
+#include <wirish/wirish.h>
void setup() {
Serial1.begin(9600);
diff --git a/examples/test-serialusb.cpp b/examples/test-serialusb.cpp
index 15ab913..098e445 100644
--- a/examples/test-serialusb.cpp
+++ b/examples/test-serialusb.cpp
@@ -1,7 +1,7 @@
// Tests SerialUSB functionality.
-#include "wirish.h"
-#include "usb.h"
+#include <wirish/wirish.h>
+#include "usb_cdcacm.h"
#define QUICKPRINT 0
#define BIGSTUFF 1
@@ -37,7 +37,7 @@ void loop() {
switch (state) {
case QUICKPRINT:
for (int i = 0; i < 30; i++) {
- usbSendBytes(&c1, 1);
+ usb_cdcacm_putc((char)c1, 1);
SerialUSB.print('.');
SerialUSB.print('|');
}
diff --git a/examples/test-servo.cpp b/examples/test-servo.cpp
index b6b8cd5..6f6e3ba 100644
--- a/examples/test-servo.cpp
+++ b/examples/test-servo.cpp
@@ -29,7 +29,7 @@
#include <stdio.h>
-#include "wirish.h"
+#include <wirish/wirish.h>
#include "libraries/Servo/Servo.h"
diff --git a/examples/test-session.cpp b/examples/test-session.cpp
index 6c7cfff..4316cda 100644
--- a/examples/test-session.cpp
+++ b/examples/test-session.cpp
@@ -4,7 +4,7 @@
// Useful for testing Maple features and troubleshooting.
// Communicates over SerialUSB.
-#include "wirish.h"
+#include <wirish/wirish.h>
// ASCII escape character
#define ESC ((uint8)27)
diff --git a/examples/test-spi-roundtrip.cpp b/examples/test-spi-roundtrip.cpp
index 71ae658..ddc9875 100644
--- a/examples/test-spi-roundtrip.cpp
+++ b/examples/test-spi-roundtrip.cpp
@@ -17,7 +17,7 @@
* Author: Marti Bolivar <mbolivar@leaflabs.com>
*/
-#include "wirish.h"
+#include <wirish/wirish.h>
HardwareSPI alice(2);
diff --git a/examples/test-systick.cpp b/examples/test-systick.cpp
index 78c7307..356f302 100644
--- a/examples/test-systick.cpp
+++ b/examples/test-systick.cpp
@@ -1,7 +1,7 @@
// Tests the SysTick enable/disable functions
-#include "wirish.h"
-#include "systick.h"
+#include <wirish/wirish.h>
+#include <libmaple/systick.h>
void setup() {
pinMode(BOARD_LED_PIN, OUTPUT);
diff --git a/examples/test-timers.cpp b/examples/test-timers.cpp
index 247cc57..e646916 100644
--- a/examples/test-timers.cpp
+++ b/examples/test-timers.cpp
@@ -1,288 +1,528 @@
-// Program to test the timer.h implementation's essential functionality.
-
-#include "wirish.h"
-#include "timer.h"
-
-void handler1(void);
-void handler2(void);
-void handler3(void);
-void handler4(void);
-
-void handler3b(void);
-void handler4b(void);
-
-int t;
-
-int count1 = 0;
-int count2 = 0;
-int count3 = 0;
-int count4 = 0;
-uint16 rate1 = 1000;
-uint16 rate2 = 2000;
-uint16 rate3 = 4000;
-uint16 rate4 = 8000;
-uint16 val1 = 10000;
-uint16 val2 = 10000;
-uint16 val3 = 10000;
-uint16 val4 = 10000;
-
-// FIXME [0.1.0] high density timer test (especially basic timers + DAC)
-timer_dev *timers[] = {TIMER1, TIMER2, TIMER3, TIMER4};
-voidFuncPtr handlers[] = {handler1, handler2, handler3, handler4};
-
-void initTimer(timer_dev *dev);
-void setTimerPeriod(timer_dev *dev, uint32 period_us);
-void testSetTimerPeriod(uint32 period);
-void testTimerChannels(timer_dev *dev);
-int timerNumber(timer_dev *dev);
+//
+// This is a mostly Wirish-free timer test. Wirish usage is minimized
+// because this is a test of the C timer interface in
+// <libmaple/timer.h>, so it's good if it can be made to work even
+// when most or all of Wirish is missing. Because of that, you may
+// need to customize the following output configuration:
+//
+// Output is printed:
+// - on COMM_USART,
+// - via TX pin on port COMM_USART_PORT, bit COMM_USART_TX_BIT
+// - via RX pin on port COMM_USART_PORT, bit COMM_USART_RX_BIT
+// - at COMM_USART_BAUD baud.
+#define COMM_USART USART6
+#define COMM_USART_BAUD 115200
+#define COMM_USART_PORT GPIOG
+#define COMM_USART_TX_BIT 14
+#define COMM_USART_RX_BIT 9
+// Other optional configuration below.
+
+#include <libmaple/libmaple.h>
+#include <libmaple/gpio.h>
+#include <libmaple/usart.h>
+#include <libmaple/systick.h>
+#include <libmaple/timer.h>
+#include <wirish/boards.h>
+
+//
+// Configuration
+//
+
+// More output if true
+static bool verbose = true;
+
+// Timers to test
+// FIXME use feature test macros for smaller MCUs
+static timer_dev *timers[] = {
+ // Available on all currently supported MCUs
+ TIMER1, TIMER2, TIMER3, TIMER4,
+ // Available on F1 (HD and up), F2
+ TIMER5, TIMER6, TIMER7, TIMER8,
+ // Available on F1 (XL), F2
+ TIMER9, TIMER10, TIMER11, TIMER12, TIMER13, TIMER14,
+};
+
+//
+// Test routines
+//
+
+typedef void (*timer_test_t)(timer_dev *);
+
+static void runTest(const char description[], timer_test_t test);
+static void runTests(void);
+
+static void testGetAndSetCount(timer_dev*);
+static void testPauseAndResume(timer_dev*);
+static void testTimerChannels(timer_dev*);
+
+//
+// Helpers
+//
+
+static void initTimer(timer_dev *dev);
+static int timerNumber(timer_dev *dev);
+// Hack: a systick-based delay, useful until delay_us() is fixed
+static void _delay(uint32 msec);
+// Wirish-less USART initialization routine
+static void init_usart(usart_dev *dev, gpio_dev *gdev, uint8 tx, uint8 rx);
+// Return whether or not the timer has capture/compare channel `ch'.
+// TODO: does something like this belong in the standard timer library?
+static bool timer_has_cc_ch(timer_dev *dev, int ch);
+
+// Printing routines and variants for verbose mode
+static void putstr(const char str[]);
+static void println(void);
+static void putstrln(const char str[]);
+static void putudec(uint32 val);
+static void puttimn(timer_dev *dev);
+static void v_putstr(const char str[]);
+static void v_println();
+static void v_putstrln(const char str[]);
+static void v_putudec(uint32 val);
+static void v_puttimn(timer_dev *dev);
+// Used to visually separate output from different tests
+static void printBanner(void);
+
+//
+// Handler state
+//
+
+static int count1 = 0;
+static int count2 = 0;
+static int count3 = 0;
+static int count4 = 0;
+static int timer_num; // Current timer we're considering
+
+//
+// Timer capture/compare interrupt handlers
+//
+// These are shared between timers. The global variable timer_num
+// controls which timer they affect.
+//
+
+static void handler1(void);
+static void handler2(void);
+static void handler3(void);
+static void handler4(void);
+static voidFuncPtr handlers[] = {handler1, handler2, handler3, handler4};
+
+//
+// setup() and loop()
+//
void setup() {
- // Set up the LED to blink
- pinMode(BOARD_LED_PIN, OUTPUT);
-
- // Setup the button as input
- pinMode(BOARD_BUTTON_PIN, INPUT);
-
- // Send a message out Serial2
- Serial2.begin(115200);
- Serial2.println("*** Initializing timers...");
+ init_usart(COMM_USART, COMM_USART_PORT,
+ COMM_USART_TX_BIT, COMM_USART_RX_BIT);
+ _delay(5);
+ println();
+ printBanner();
+ putstr("Initializing timers...\r\n");
timer_foreach(initTimer);
- Serial2.println("*** Done. Beginning timer test.");
+ putstr("Done. Running tests.\r\n");
+ runTests();
+ printBanner();
+ putstr("Done testing timers.\r\n");
}
void loop() {
- Serial2.println("-----------------------------------------------------");
-
- Serial2.println("Testing timer_get_count()/timer_set_count()");
- Serial2.print("TIMER1 count = ");
- Serial2.println(timer_get_count(TIMER1));
- Serial2.println("timer_set_count(TIMER1, 1234)");
- timer_set_count(TIMER1, 1234);
- Serial2.print("timer_get_count(TIMER1) = ");
- Serial2.println(timer_get_count(TIMER1));
-
- Serial2.println("-----------------------------------------------------");
- Serial2.println("Testing pause/resume; button roughly controls TIMER4");
- // when BUT is held down, TIMER4 is in the "pause" state and the
- // timer doesn't increment, so the final counts should reflect the
- // ratio of time that BUT was held down.
- count3 = 0;
- count4 = 0;
- timer_set_mode(TIMER3, TIMER_CH1, TIMER_OUTPUT_COMPARE);
- timer_set_mode(TIMER4, TIMER_CH1, TIMER_OUTPUT_COMPARE);
- timer_pause(TIMER3);
- timer_pause(TIMER4);
- timer_set_count(TIMER3, 0);
- timer_set_count(TIMER4, 0);
- timer_set_reload(TIMER3, 30000);
- timer_set_reload(TIMER4, 30000);
- timer_set_compare(TIMER3, 1, 1000);
- timer_set_compare(TIMER4, 1, 1000);
- timer_attach_interrupt(TIMER3, TIMER_CC1_INTERRUPT, handler3b);
- timer_attach_interrupt(TIMER4, TIMER_CC1_INTERRUPT, handler4b);
- timer_resume(TIMER3);
- timer_resume(TIMER4);
-
- Serial2.println("Testing for ~4 seconds...");
- for(int i = 0; i < 4000; i++) {
- if (isButtonPressed()) {
- timer_pause(TIMER4);
- } else {
- timer_resume(TIMER4);
- }
- delay(1);
- }
+}
- timer_set_mode(TIMER3, TIMER_CH1, TIMER_DISABLED);
- timer_set_mode(TIMER4, TIMER_CH1, TIMER_DISABLED);
-
- Serial2.print("TIMER3 count: ");
- Serial2.println(timer_get_count(TIMER3));
- Serial2.print("TIMER4 count: ");
- Serial2.println(timer_get_count(TIMER4));
-
- Serial2.println("-----------------------------------------------------");
- Serial2.println("Testing setTimerPeriod()");
- testSetTimerPeriod(10);
- testSetTimerPeriod(30000);
- testSetTimerPeriod(300000);
- testSetTimerPeriod(30000);
-
- Serial2.println("Sanity check (with hand-coded reload and prescaler for "
- "72 MHz timers):");
- timer_set_mode(TIMER4, TIMER_CH1, TIMER_OUTPUT_COMPARE);
- timer_set_prescaler(TIMER4, 33);
- timer_set_reload(TIMER4, 65454);
- timer_pause(TIMER4);
- timer_set_count(TIMER4, 0);
- timer_set_compare(TIMER4, TIMER_CH1, 1);
- timer_attach_interrupt(TIMER4, TIMER_CC1_INTERRUPT, handler4b);
- Serial2.println("Period 30000ms, wait 2 seconds...");
- count4 = 0;
- timer_resume(TIMER4);
- delay(2000);
- timer_pause(TIMER4);
- timer_set_mode(TIMER4, TIMER_CH1, TIMER_DISABLED);
- Serial2.print("TIMER4 count: ");
- Serial2.println(count4);
- Serial2.println(" (Should be around 2sec/30000ms ~ 67)");
-
- // Test all the individual timer channels
- timer_foreach(testTimerChannels);
+//
+// Test routine implementations
+//
+
+static void runTests(void) {
+ runTest("timer_get_count()/timer_set_count()", testGetAndSetCount);
+ runTest("timer_pause()/timer_resume()", testPauseAndResume);
+ runTest("capture/compare channels and interrupts",
+ testTimerChannels);
}
-void initTimer(timer_dev *dev) {
- switch (dev->type) {
- case TIMER_ADVANCED:
- case TIMER_GENERAL:
- Serial2.print("Initializing timer ");
- Serial2.println(timerNumber(dev));
- for (int c = 1; c <= 4; c++) {
- timer_set_mode(dev, c, TIMER_OUTPUT_COMPARE);
- }
- Serial2.println("Done.");
- break;
- case TIMER_BASIC:
- break;
+static void runTest(const char description[], timer_test_t test) {
+ printBanner();
+ putstr("Testing ");
+ putstr(description);
+ putstrln(".");
+ timer_foreach(test);
+}
+
+static void testGetAndSetCount(timer_dev *dev) {
+ unsigned before, after;
+ unsigned val_to_set = 1234;
+
+ timer_pause(dev);
+ before = timer_get_count(dev);
+ timer_set_count(dev, val_to_set);
+ after = timer_get_count(dev);
+ timer_resume(dev);
+
+ if (after != val_to_set) {
+ puttimn(dev);
+ putstr(": ");
+ putstr("*** FAIL: get/set count for ");
+ puttimn(dev);
+ putstr(".");
+ putstr("Start count = ");
+ putudec(before);
+ putstr(". Count set to ");
+ putudec(val_to_set);
+ putstr(", and now count is = ");
+ putudec(after);
+ println();
+ } else if (verbose) {
+ puttimn(dev);
+ putstr(": ");
+ putstrln("[ok]");
}
}
-void testSetTimerPeriod(uint32 period) {
- timer_set_mode(TIMER4, TIMER_CH1, TIMER_OUTPUT_COMPARE);
- timer_set_compare(TIMER4, TIMER_CH1, 1);
- setTimerPeriod(TIMER4, period);
- timer_pause(TIMER4);
- timer_set_count(TIMER4, 0);
- timer_attach_interrupt(TIMER4, TIMER_CC1_INTERRUPT, handler4b);
- Serial2.println("Period ");
- Serial2.print(period);
- Serial2.print(" ms. Waiting 2 seconds...");
- count4 = 0;
- timer_resume(TIMER4);
- delay(2000);
- timer_pause(TIMER4);
- timer_set_mode(TIMER4, TIMER_CH1, TIMER_DISABLED);
- Serial2.print("TIMER4 count: ");
- Serial2.println(timer_get_count(TIMER4));
- Serial2.print(" (Should be around 2 sec / ");
- Serial2.print(period);
- Serial2.print(" ms = ");
- Serial2.print(double(2) / period * 1000);
- Serial2.println(", modulo delays due to interrupts)");
+// This hack works on all currently supported STM32 series, but you
+// may need to do something smarter in the future. The assertions
+// ensure that our assumptions hold for your target.
+static timer_dev *getDifferentTimerOnSameBusAs(timer_dev *dev) {
+ rcc_clk_domain dev_domain = rcc_dev_clk(dev->clk_id);
+ ASSERT(RCC_APB1 == dev_domain || RCC_APB2 == dev_domain);
+ ASSERT(rcc_dev_clk(TIMER1->clk_id) == RCC_APB2);
+ ASSERT(rcc_dev_clk(TIMER2->clk_id) == RCC_APB1);
+ ASSERT(rcc_dev_clk(TIMER8->clk_id) == RCC_APB2);
+ ASSERT(rcc_dev_clk(TIMER3->clk_id) == RCC_APB1);
+
+ if (dev->clk_id == RCC_TIMER1) {
+ return TIMER8;
+ }
+ if (dev->clk_id == RCC_TIMER2) {
+ return TIMER3;
+ }
+ return dev_domain == RCC_APB2 ? TIMER1 : TIMER2;
}
-int timerNumber(timer_dev *dev) {
- switch (dev->clk_id) {
- case RCC_TIMER1:
- return 1;
- case RCC_TIMER2:
- return 2;
- case RCC_TIMER3:
- return 3;
- case RCC_TIMER4:
- return 4;
-#ifdef STM32_HIGH_DENSITY
- case RCC_TIMER5:
- return 5;
- case RCC_TIMER6:
- return 6;
- case RCC_TIMER7:
- return 7;
- case RCC_TIMER8:
- return 8;
-#endif
- default:
- ASSERT(0);
- return 0;
+// Rough test of pause and resume.
+//
+// Approximately half the time, dev is in the "pause" state and the
+// timer doesn't increment, while another timer (`base_dev') on the
+// same bus continues. dev and base_dev have identical start counts
+// and prescalers.
+//
+// Since dev and base_dev share a bus (and thus a base clock), and we
+// configure them to have the same prescaler and start count, the
+// ratio of their end counts should be approximately 1 : 2. We check
+// to make sure this is true, up to tolerance `epsilon'.
+static void testPauseAndResume(timer_dev *dev) {
+ timer_dev *base_dev = getDifferentTimerOnSameBusAs(dev);
+ unsigned start_count = 0, reload = 65535;
+ // This prescaler should be enough to ensure that we don't
+ // overflow, while still giving us a reasonably large number of
+ // timer ticks.
+ uint16 prescaler = CYCLES_PER_MICROSECOND * 50;
+ double epsilon = .02;
+
+ if (rcc_dev_clk(base_dev->clk_id) != rcc_dev_clk(dev->clk_id)) {
+ putstrln("*** ERROR: cannot run test. Bus info is messed up.");
+ return;
+ }
+
+ // Pause and set up timers
+ timer_pause(base_dev);
+ timer_pause(dev);
+ timer_set_count(base_dev, start_count);
+ timer_set_count(dev, start_count);
+ timer_set_reload(base_dev, reload);
+ timer_set_reload(dev, reload);
+ timer_set_prescaler(base_dev, prescaler);
+ timer_set_prescaler(dev, prescaler);
+ timer_generate_update(base_dev);
+ timer_generate_update(dev);
+
+ // Resume the timers and run the test
+ ASSERT(timer_get_count(base_dev) == start_count);
+ ASSERT(timer_get_count(dev) == start_count);
+ timer_resume(base_dev);
+ timer_resume(dev);
+ _delay(1000);
+ timer_pause(dev);
+ _delay(1000);
+ timer_pause(base_dev);
+
+ // Check the results
+ unsigned dev_count = timer_get_count(dev);
+ unsigned base_count = timer_get_count(base_dev);
+ double count_ratio = ((double)dev_count / base_count);
+ bool fail = false;
+ if (count_ratio > 0.5 + epsilon || count_ratio < 0.5 - epsilon) {
+ fail = true;
+ }
+ if (fail || verbose) {
+ puttimn(dev);
+ putstr(" vs. ");
+ puttimn(base_dev);
+ putstr(": ");
+ if (fail) putstr("*** FAIL: ");
+ else putstr("[ok] ");
+ putstr("(dev = ");
+ putudec(dev_count);
+ putstr(") / (base = ");
+ putudec(base_count);
+ putstr(") = ");
+ // hack hack hack
+ putudec((int)count_ratio);
+ count_ratio -= (int)count_ratio;
+ putstr(".");
+ int cr_x_100 = (int)(count_ratio * 100);
+ int hundredths = cr_x_100 % 10;
+ cr_x_100 /= 10;
+ int tenths = cr_x_100 % 10;
+ putudec(tenths);
+ putudec(hundredths);
+ println();
}
}
-/* This function touches every channel of a given timer. The output
- * ratios should reflect the ratios of the rate variables. It
- * demonstrates that, over time, the actual timing rates get blown
- * away by other system interrupts. */
-void testTimerChannels(timer_dev *dev) {
- t = timerNumber(dev);
- toggleLED();
- delay(100);
- Serial2.println("-----------------------------------------------------");
+// This function touches every capture/compare channel of a given
+// timer. The channel counts should be equal within a timer
+// regardless of other interrupts on the system (note that this
+// doesn't really test timers with only a single capture/compare
+// channel; for that, you'll want to do visual inspection of timers
+// that share a bus, in verbose mode).
+static void testTimerChannels(timer_dev *dev) {
switch (dev->type) {
case TIMER_BASIC:
- Serial2.print("NOT testing channels for basic timer ");
- Serial2.println(t);
- break;
+ v_putstr("Skipping basic timer ");
+ v_puttimn(dev);
+ v_println();
+ return;
case TIMER_ADVANCED:
case TIMER_GENERAL:
- Serial2.print("Testing channels for timer ");
- Serial2.println(t);
+ // Set up
+ v_puttimn(dev);
+ v_println();
+ v_putstr("\tchannels: ");
+
+ timer_num = timerNumber(dev);
timer_pause(dev);
- count1 = count2 = count3 = count4 = 0;
+ count1 = 0;
+ count2 = 0;
+ count3 = 0;
+ count4 = 0;
timer_set_reload(dev, 0xFFFF);
timer_set_prescaler(dev, 1);
for (int c = 1; c <= 4; c++) {
- timer_set_compare(dev, c, 65535);
- timer_set_mode(dev, c, TIMER_OUTPUT_COMPARE);
- timer_attach_interrupt(dev, c, handlers[c - 1]);
+ if (timer_has_cc_ch(dev, c)) {
+ v_putudec(c);
+ v_putstr("\t");
+ timer_set_compare(dev, c, 0xFFFF);
+ timer_set_mode(dev, c, TIMER_OUTPUT_COMPARE);
+ timer_attach_interrupt(dev, c, handlers[c - 1]);
+ }
}
+ v_println();
+
+ // Run test
+ timer_generate_update(dev);
timer_resume(dev);
- delay(3000);
+ _delay(250);
+ timer_pause(dev);
+
+ // Print results
+ v_putstr("\tcounts: ");
+ bool fail = false;
+ bool mismatched[4] = {false, false, false, false};
+ int counts[4];
+ counts[0] = count1;
+ counts[1] = count2;
+ counts[2] = count3;
+ counts[3] = count4;
+ bool first = true;
+ int first_count = -1;
+ for (int c = 1; c <= 4; c++) {
+ if (timer_has_cc_ch(dev, c)) {
+ if (first) {
+ first_count = counts[c - 1];
+ first = false;
+ }
+ if (!first && (counts[c - 1] != first_count)) {
+ mismatched[c - 1] = true;
+ fail = true;
+ }
+ v_putudec(counts[c - 1]);
+ v_putstr("\t");
+ }
+ }
+ v_println();
+ if (fail) {
+ for (int i = 0; i < 4; i++) {
+ if (mismatched[i]) {
+ putstr("*** FAIL: mismatch on ");
+ puttimn(dev);
+ putstr(", channel ");
+ putudec(i + 1);
+ putstr(": expected ");
+ putudec(first_count);
+ putstr(", got ");
+ putudec(counts[i]);
+ println();
+ }
+ }
+ } else {
+ puttimn(dev);
+ putstrln(" [ok]");
+ }
+ v_println();
+
+ // Clean up
for (int c = 1; c <= 4; c++) {
- timer_set_mode(dev, c, TIMER_DISABLED);
+ if (timer_has_cc_ch(dev, c)) {
+ timer_set_mode(dev, c, TIMER_DISABLED);
+ }
}
- Serial2.print("Channel 1 count: "); Serial2.println(count1);
- Serial2.print("Channel 2 count: "); Serial2.println(count2);
- Serial2.print("Channel 3 count: "); Serial2.println(count3);
- Serial2.print("Channel 4 count: "); Serial2.println(count4);
break;
}
}
-// FIXME [0.1.0] move some incarnation of this into timer.h
-void setTimerPeriod(timer_dev *dev, uint32 period_us) {
- if (!period_us) {
- // FIXME handle this case
- ASSERT(0);
- return;
- }
+//
+// Helper implementations
+//
- uint32 cycles = period_us * CYCLES_PER_MICROSECOND;
- uint16 pre = (uint16)((cycles >> 16) + 1);
- timer_set_prescaler(dev, pre);
- timer_set_reload(dev, cycles / pre - 1);
+static void _delay(uint32 msec) {
+ uint32 end = systick_uptime() + msec;
+ while (systick_uptime() < end)
+ ;
}
-void handler1(void) {
- val1 += rate1;
- timer_set_compare(timers[t], TIMER_CH1, val1);
- count1++;
+static void init_usart(usart_dev *dev, gpio_dev *gdev, uint8 tx, uint8 rx) {
+ usart_config_gpios_async(dev, gdev, rx, gdev, tx, 0);
+ usart_init(dev);
+ usart_set_baud_rate(dev, USART_USE_PCLK, COMM_USART_BAUD);
+ usart_enable(dev);
}
-void handler2(void) {
- val2 += rate2;
- timer_set_compare(timers[t], TIMER_CH2, val2);
- count2++;
+static bool timer_has_cc_ch(timer_dev *dev, int ch) {
+ ASSERT(1 <= ch && ch <= 4);
+ if (dev->type == TIMER_BASIC)
+ return false;
+ int tn = timerNumber(dev);
+ return (// TIM1-5 and 8 have all four channels
+ (tn <= 5 || tn == 8) ||
+ // TIM9 and 12 only have channels 1 and 2
+ ((tn == 9 || tn == 12) && ch <= 2) ||
+ // All other general purpose timers only have channel 1
+ (ch == 1));
}
-void handler3(void) {
- val3 += rate3;
- timer_set_compare(timers[t], TIMER_CH3, val3);
- count3++;
+static void putstr(const char str[]) {
+ usart_putstr(COMM_USART, str);
}
-void handler4(void) {
- val4 += rate4;
- timer_set_compare(timers[t], TIMER_CH4, val4);
- count4++;
+static void println(void) {
+ putstr("\r\n");
}
-void handler3b(void) {
+static void putstrln(const char str[]) {
+ putstr(str);
+ println();
+}
+
+static void putudec(uint32 val) {
+ usart_putudec(COMM_USART, val);
+}
+
+static void puttimn(timer_dev *dev) {
+ putstr("TIM");
+ putudec(timerNumber(dev));
+}
+
+static void v_putstr(const char str[]) {
+ if (verbose) putstr(str);
+}
+
+static void v_println() {
+ if (verbose) println();
+}
+
+__attribute__((unused)) /* (shut up, gcc) */
+static void v_putstrln(const char str[]) {
+ if (verbose) putstrln(str);
+}
+
+static void v_putudec(uint32 val) {
+ if (verbose) putudec(val);
+}
+
+static void v_puttimn(timer_dev *dev) {
+ if (verbose) puttimn(dev);
+}
+
+// Used to visually separate output from different tests
+static void printBanner(void) {
+ putstrln("-----------------------------------------------------");
+}
+
+static void initTimer(timer_dev *dev) {
+ v_puttimn(dev);
+ timer_init(dev);
+ switch (dev->type) {
+ case TIMER_ADVANCED:
+ case TIMER_GENERAL:
+ v_putstr(" channels ");
+ for (int c = 1; c <= 4; c++) {
+ if (timer_has_cc_ch(dev, c)) {
+ v_putudec(c);
+ v_putstr(" ");
+ timer_set_mode(dev, c, TIMER_OUTPUT_COMPARE);
+ }
+ }
+ break;
+ case TIMER_BASIC:
+ break;
+ }
+ v_println();
+}
+
+static int timerNumber(timer_dev *dev) {
+ switch (dev->clk_id) {
+ case RCC_TIMER1: return 1;
+ case RCC_TIMER2: return 2;
+ case RCC_TIMER3: return 3;
+ case RCC_TIMER4: return 4;
+ case RCC_TIMER5: return 5;
+ case RCC_TIMER6: return 6;
+ case RCC_TIMER7: return 7;
+ case RCC_TIMER8: return 8;
+ case RCC_TIMER9: return 9;
+ case RCC_TIMER10: return 10;
+ case RCC_TIMER11: return 11;
+ case RCC_TIMER12: return 12;
+ case RCC_TIMER13: return 13;
+ case RCC_TIMER14: return 14;
+ default:
+ ASSERT(0);
+ return 0;
+ }
+}
+
+//
+// IRQ Handlers
+//
+
+static void handler1(void) {
+ count1++;
+}
+
+static void handler2(void) {
+ count2++;
+}
+
+static void handler3(void) {
count3++;
}
-void handler4b(void) {
+static void handler4(void) {
count4++;
}
+//
+// init() and main()
+//
+
__attribute__((constructor)) void premain() {
init();
}
diff --git a/examples/test-usart-dma.cpp b/examples/test-usart-dma.cpp
index 5ff5b86..d10dc68 100644
--- a/examples/test-usart-dma.cpp
+++ b/examples/test-usart-dma.cpp
@@ -1,5 +1,5 @@
/**
- * @file test-usart-dma.cpp
+ * @file examples/test-usart-dma.cpp
* @author Marti Bolivar <mbolivar@leaflabs.com>
*
* Simple test of DMA used with a USART receiver.
@@ -12,100 +12,188 @@
*
* This example isn't very robust; don't use it in production. In
* particular, since the buffer keeps filling (DMA_CIRC_MODE is set),
- * if you keep typing after filling the buffer, you'll overwrite
- * earlier bytes; this may happen before those earlier bytes are done
- * printing.
+ * if you keep sending characters after filling the buffer, you'll
+ * overwrite earlier bytes; this may happen before those earlier bytes
+ * are done printing. (Typing quickly and seeing how it affects the
+ * output is a fun way to make sense of how the interrupts and the
+ * main thread of execution interleave.)
*
* This code is released into the public domain.
*/
-#include "dma.h"
-#include "usart.h"
-#include "gpio.h"
+#include <libmaple/dma.h>
+#include <libmaple/usart.h>
+#include <libmaple/gpio.h>
-#include "wirish.h"
+#include <wirish/wirish.h>
-#define BAUD 9600
+/*
+ * Configuration and state
+ */
-#define USART USART2
-#define USART_HWSER Serial2
+// Serial port and DMA configuration. You can change these to suit
+// your purposes.
+HardwareSerial *serial = &Serial2;
#define USART_DMA_DEV DMA1
-#define USART_RX_DMA_CHANNEL DMA_CH6
-#define USART_TX BOARD_USART2_TX_PIN
-#define USART_RX BOARD_USART2_RX_PIN
+#if STM32_MCU_SERIES == STM32_SERIES_F1
+// On STM32F1 microcontrollers (like what's on Maple and Maple Mini),
+// dma tubes are channels.
+#define USART_RX_DMA_TUBE DMA_CH6
+#elif (STM32_MCU_SERIES == STM32_SERIES_F2 || \
+ STM32_MCU_SERIES == STM32_SERIES_F4)
+// On STM32F2 and STM32F4 microcontrollers (Maple 2 will have an F4),
+// dma tubes are streams.
+#define USART_RX_DMA_TUBE DMA_S5
+#else
+#error "unsupported stm32 series"
+#endif
+// The serial port will make a DMA request each time it receives data.
+// This is the dma_request_src we use to tell the DMA tube to handle
+// that DMA request.
+#define USART_DMA_REQ_SRC DMA_REQ_SRC_USART2_RX
+#define BAUD 9600
-#define BUF_SIZE 8
-uint8 rx_buf[BUF_SIZE];
+// This will store the DMA configuration for USART RX.
+dma_tube_config tube_config;
-dma_irq_cause irq_cause;
+// This will store received USART characters.
+#define BUF_SIZE 20
+char rx_buf[BUF_SIZE];
+// The interrupt handler, rx_dma_irq(), sets this to 1.
volatile uint32 irq_fired = 0;
+// Used to store DMA interrupt status register (ISR) bits inside
+// rx_dma_irq(). This helps explain what's going on inside loop(); see
+// comments below.
+volatile uint32 isr = 0;
+
+/*
+ * Helper functions
+ */
+
+// This is our DMA interrupt handler.
+void rx_dma_irq(void) {
+ irq_fired = 1;
+ isr = dma_get_isr_bits(USART_DMA_DEV, USART_RX_DMA_TUBE);
+}
+
+// Configure the USART receiver for use with DMA:
+// 1. Turn it on.
+// 2. Set the "DMA request on RX" bit in USART_CR3 (USART_CR3_DMAR).
+void setup_usart(void) {
+ serial->begin(BAUD);
+ usart_dev *serial_dev = serial->c_dev();
+ serial_dev->regs->CR3 = USART_CR3_DMAR;
+}
+
+// Set up our dma_tube_config structure. (We could have done this
+// above, when we declared tube_config, but having this function makes
+// it easier to explain what's going on).
+void setup_tube_config(void) {
+ // We're receiving from the USART data register. serial->c_dev()
+ // returns a pointer to the libmaple usart_dev for that serial
+ // port, so this is a pointer to its data register.
+ tube_config.tube_src = &serial->c_dev()->regs->DR;
+ // We're only interested in the bottom 8 bits of that data register.
+ tube_config.tube_src_size = DMA_SIZE_8BITS;
+ // We're storing to rx_buf.
+ tube_config.tube_dst = rx_buf;
+ // rx_buf is a char array, and a "char" takes up 8 bits on STM32.
+ tube_config.tube_dst_size = DMA_SIZE_8BITS;
+ // Only fill BUF_SIZE - 1 characters, to leave a null byte at the end.
+ tube_config.tube_nr_xfers = BUF_SIZE - 1;
+ // Flags:
+ // - DMA_CFG_DST_INC so we start at the beginning of rx_buf and
+ // fill towards the end.
+ // - DMA_CFG_CIRC so we go back to the beginning and start over when
+ // rx_buf fills up.
+ // - DMA_CFG_CMPLT_IE to turn on interrupts on transfer completion.
+ tube_config.tube_flags = DMA_CFG_DST_INC | DMA_CFG_CIRC | DMA_CFG_CMPLT_IE;
+ // Target data: none. It's important to set this to NULL if you
+ // don't have any special (microcontroller-specific) configuration
+ // in mind, which we don't.
+ tube_config.target_data = NULL;
+ // DMA request source.
+ tube_config.tube_req_src = USART_DMA_REQ_SRC;
+}
+
+// Configure the DMA controller to serve DMA requests from the USART.
+void setup_dma_xfer(void) {
+ // First, turn it on.
+ dma_init(USART_DMA_DEV);
+ // Next, configure it by calling dma_tube_cfg(), and check to make
+ // sure it succeeded. DMA tubes have many restrictions on their
+ // configuration, and there are configurations which work on some
+ // types of STM32 but not others. libmaple tries hard to make
+ // things just work, but checking the return status is important!
+ int status = dma_tube_cfg(USART_DMA_DEV, USART_RX_DMA_TUBE, &tube_config);
+ ASSERT(status == DMA_TUBE_CFG_SUCCESS);
+ // Now we'll perform any other configuration we want. For this
+ // example, we attach an interrupt handler.
+ dma_attach_interrupt(USART_DMA_DEV, USART_RX_DMA_TUBE, rx_dma_irq);
+ // Turn on the DMA tube. It will now begin serving requests.
+ dma_enable(USART_DMA_DEV, USART_RX_DMA_TUBE);
+}
-void init_usart(void);
-void init_dma_xfer(void);
-void rx_dma_irq(void);
+/*
+ * setup() and loop()
+ */
void setup(void) {
pinMode(BOARD_LED_PIN, OUTPUT);
-
- init_dma_xfer();
- init_usart();
+ setup_tube_config();
+ setup_dma_xfer();
+ setup_usart();
}
void loop(void) {
toggleLED();
delay(100);
- dma_channel_reg_map *ch_regs = dma_channel_regs(USART_DMA_DEV,
- USART_RX_DMA_CHANNEL);
+ // See if the interrupt handler got called since the last time we
+ // checked.
if (irq_fired) {
- USART_HWSER.println("** IRQ **");
+ serial->println("** IRQ **");
+ // Notice how the interrupt status register (ISR) bits show
+ // transfer complete _and_ half-complete here, but the ISR
+ // bits we print next will be zero. That's because the
+ // variable "isr" gets set _inside_ rx_dma_irq(). After it
+ // exits, libmaple cleans up by clearing the tube's ISR
+ // bits. (If it didn't, and we forgot to, the interrupt would
+ // repeatedly fire forever.)
+ serial->print("ISR bits: 0x");
+ serial->println(isr, HEX);
irq_fired = 0;
}
- USART_HWSER.print("[");
- USART_HWSER.print(millis());
- USART_HWSER.print("]\tISR bits: 0x");
- uint8 isr_bits = dma_get_isr_bits(USART_DMA_DEV, USART_RX_DMA_CHANNEL);
- USART_HWSER.print(isr_bits, HEX);
- USART_HWSER.print("\tCCR: 0x");
- USART_HWSER.print(ch_regs->CCR, HEX);
- USART_HWSER.print("\tCNDTR: 0x");
- USART_HWSER.print(ch_regs->CNDTR, HEX);
- USART_HWSER.print("\tBuffer contents: ");
- for (int i = 0; i < BUF_SIZE; i++) {
- USART_HWSER.print('\'');
- USART_HWSER.print(rx_buf[i]);
- USART_HWSER.print('\'');
- if (i < BUF_SIZE - 1) USART_HWSER.print(", ");
- }
- USART_HWSER.println();
+
+ // Print the ISR bits.
+ //
+ // Notice that the "transfer half-complete" ISR flag gets set when
+ // we reach the rx_buf half-way point. This is true even though we
+ // don't tell the DMA controller to interrupt us on a
+ // half-complete transfer. That is, the ISR bits get set at the
+ // right times no matter what; we just don't get interrupted
+ // unless we asked. (If an error or other problem occurs, the
+ // relevant ISR bits will get set in the same way).
+ serial->print("[");
+ serial->print(millis());
+ serial->print("]\tISR bits: 0x");
+ uint8 isr_bits = dma_get_isr_bits(USART_DMA_DEV, USART_RX_DMA_TUBE);
+ serial->print(isr_bits, HEX);
+
+ // Print the contents of rx_buf. If you keep typing after it fills
+ // up, the new characters will overwrite the old ones, thanks to
+ // DMA_CIRC_MODE.
+ serial->print("\tCharacter buffer contents: '");
+ serial->print(rx_buf);
+ serial->println("'");
if (isr_bits == 0x7) {
- USART_HWSER.println("** Clearing ISR bits.");
- dma_clear_isr_bits(USART_DMA_DEV, USART_RX_DMA_CHANNEL);
+ serial->println("** Clearing ISR bits.");
+ dma_clear_isr_bits(USART_DMA_DEV, USART_RX_DMA_TUBE);
}
}
-/* Configure USART receiver for use with DMA */
-void init_usart(void) {
- USART_HWSER.begin(BAUD);
- USART->regs->CR3 = USART_CR3_DMAR;
-}
-
-/* Configure DMA transmission */
-void init_dma_xfer(void) {
- dma_init(USART_DMA_DEV);
- dma_setup_transfer(USART_DMA_DEV, USART_RX_DMA_CHANNEL,
- &USART->regs->DR, DMA_SIZE_8BITS,
- rx_buf, DMA_SIZE_8BITS,
- (DMA_MINC_MODE | DMA_CIRC_MODE | DMA_TRNS_CMPLT));
- dma_set_num_transfers(USART_DMA_DEV, USART_RX_DMA_CHANNEL, BUF_SIZE);
- dma_attach_interrupt(USART_DMA_DEV, USART_RX_DMA_CHANNEL, rx_dma_irq);
- dma_enable(USART_DMA_DEV, USART_RX_DMA_CHANNEL);
-}
-
-void rx_dma_irq(void) {
- irq_fired = true;
-}
+// ------- init() and main() --------------------------------------------------
// Force init to be called *first*, i.e. before static object allocation.
// Otherwise, statically allocated objects that need libmaple may fail.
diff --git a/examples/vga-leaf.cpp b/examples/vga-leaf.cpp
index f31dc87..5159956 100644
--- a/examples/vga-leaf.cpp
+++ b/examples/vga-leaf.cpp
@@ -32,7 +32,7 @@
// FIXME: generalize for Native and Mini
-#include "wirish.h"
+#include <wirish/wirish.h>
// Pinouts -- you also must change the GPIO macros below if you change
// these
diff --git a/examples/vga-scope.cpp b/examples/vga-scope.cpp
index b5fa8a5..8730cf0 100644
--- a/examples/vga-scope.cpp
+++ b/examples/vga-scope.cpp
@@ -35,8 +35,8 @@
Marti Bolivar <mbolivar@leaflabs.com>
*/
-#include "wirish.h"
-#include "systick.h"
+#include <wirish/wirish.h>
+#include <libmaple/systick.h>
// FIXME: generalize for Native and Mini