aboutsummaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/blinky.cpp15
-rw-r--r--examples/debug-dtrrts.cpp24
-rw-r--r--examples/fsmc-stress-test.cpp216
-rw-r--r--examples/qa-slave-shield.cpp67
-rw-r--r--examples/spi_master.cpp72
-rw-r--r--examples/test-bkp.cpp80
-rw-r--r--examples/test-dac.cpp96
-rw-r--r--examples/test-fsmc.cpp214
-rw-r--r--examples/test-print.cpp181
-rw-r--r--examples/test-ring-buffer-insertion.cpp114
-rw-r--r--examples/test-serial-flush.cpp45
-rw-r--r--examples/test-serialusb.cpp89
-rw-r--r--examples/test-servo.cpp152
-rw-r--r--examples/test-session.cpp998
-rw-r--r--examples/test-spi-roundtrip.cpp194
-rw-r--r--examples/test-systick.cpp55
-rw-r--r--examples/test-timers.cpp399
-rw-r--r--examples/test-usart-dma.cpp127
-rw-r--r--examples/vga-leaf.cpp201
-rw-r--r--examples/vga-scope.cpp222
20 files changed, 2508 insertions, 1053 deletions
diff --git a/examples/blinky.cpp b/examples/blinky.cpp
index 5611987..91d1a47 100644
--- a/examples/blinky.cpp
+++ b/examples/blinky.cpp
@@ -1,12 +1,9 @@
-// Blinks the LED, pin 13
+// Blinks the built-in LED
#include "wirish.h"
-// Use the pin attached to the built-in LED
-#define PIN BOARD_LED_PIN
-
void setup() {
- pinMode(PIN, OUTPUT);
+ pinMode(BOARD_LED_PIN, OUTPUT);
}
int toggle = 1;
@@ -14,21 +11,21 @@ int toggle = 1;
void loop() {
// You could just use toggleLED() instead, but this illustrates
// the use of digitalWrite():
- digitalWrite(PIN, toggle);
+ digitalWrite(BOARD_LED_PIN, toggle);
toggle ^= 1;
delay(100);
}
// Force init to be called *first*, i.e. before static object allocation.
-// Otherwise, statically allocated object that need libmaple may fail.
- __attribute__(( constructor )) void premain() {
+// Otherwise, statically allocated objects that need libmaple may fail.
+__attribute__((constructor)) void premain() {
init();
}
int main(void) {
setup();
- while (1) {
+ while (true) {
loop();
}
return 0;
diff --git a/examples/debug-dtrrts.cpp b/examples/debug-dtrrts.cpp
index f9f8b96..3829208 100644
--- a/examples/debug-dtrrts.cpp
+++ b/examples/debug-dtrrts.cpp
@@ -1,16 +1,11 @@
-// Sample main.cpp file. Blinks an LED, sends a message out USART2
-// and turns on PWM on pin 2
+// Test sketch for figuring out DTR/RTS behavior on different platforms.
#include "wirish.h"
#include "usb.h"
-#define LED_PIN 13
-#define PWM_PIN 2
-
-void setup()
-{
+void setup() {
/* Set up the LED to blink */
- pinMode(LED_PIN, OUTPUT);
+ pinMode(BOARD_LED_PIN, OUTPUT);
/* Send a message out USART2 */
Serial2.begin(9600);
@@ -18,12 +13,10 @@ void setup()
}
-int toggle = 0;
-
void loop() {
- toggle ^= 1;
- digitalWrite(LED_PIN, toggle);
+ toggleLED();
delay(100);
+
Serial2.print("DTR: ");
Serial2.print(usbGetDTR(), DEC);
Serial2.print("\tRTS: ");
@@ -31,13 +24,12 @@ void loop() {
}
// Force init to be called *first*, i.e. before static object allocation.
-// Otherwise, statically allocated object that need libmaple may fail.
- __attribute__(( constructor )) void premain() {
+// Otherwise, statically allocated objects that need libmaple may fail.
+__attribute__((constructor)) void premain() {
init();
}
-int main(void)
-{
+int main(void) {
setup();
while (1) {
diff --git a/examples/fsmc-stress-test.cpp b/examples/fsmc-stress-test.cpp
new file mode 100644
index 0000000..12e8650
--- /dev/null
+++ b/examples/fsmc-stress-test.cpp
@@ -0,0 +1,216 @@
+/*
+
+ A low-level stress test of SRAM functionality. Uses slow-ish timing
+ by default (DATAST = ADDSET = 0xF).
+
+ Copyright 2011 LeafLabs, LLC.
+
+ This code is released into the public domain.
+
+ */
+
+#include <stdio.h>
+#include <stddef.h>
+
+#include "wirish.h"
+#include "rcc.h"
+#include "fsmc.h"
+
+// -- SRAM config -------------------------------------------------------------
+
+// Timing configuration
+#define DATAST 0xF
+#define ADDSET 0xF
+
+// Number of SRAM chips to test
+#define N 1
+
+// How much of each to test
+#define MEM_SIZE 0x3FFF
+
+// Their start addresses in FSMC bank 1
+__io uint16 *const starts[N] = {
+ // (__io uint16 *const)FSMC_NOR_PSRAM_REGION1,
+ // (__io uint16 *const)FSMC_NOR_PSRAM_REGION2,
+ (__io uint16 *const)FSMC_NOR_PSRAM_REGION3,
+ // (__io uint16 *const)FSMC_NOR_PSRAM_REGION4,
+};
+
+// Corresponding FSMC configuration registers
+__io uint32 *const bcrs[N] = {
+ // &FSMC_NOR_PSRAM1_BASE->BCR,
+ // &FSMC_NOR_PSRAM2_BASE->BCR,
+ &FSMC_NOR_PSRAM3_BASE->BCR,
+ // &FSMC_NOR_PSRAM4_BASE->BCR,
+};
+
+// Corresponding FSMC timing registers
+__io uint32 *const btrs[N] = {
+ // &FSMC_NOR_PSRAM1_BASE->BTR,
+ // &FSMC_NOR_PSRAM2_BASE->BTR,
+ &FSMC_NOR_PSRAM3_BASE->BTR,
+ // &FSMC_NOR_PSRAM4_BASE->BTR,
+};
+
+// -- Pseudorandom number generation -----------------------------------------
+
+const uint32 seed = 0xDEADBEEF;
+
+uint32 num_rand_calls = 0;
+
+uint32 rand(long n) {
+ num_rand_calls++;
+ return random(n);
+}
+
+// -- Printing ----------------------------------------------------------------
+
+// For snprintf()
+char snprintf_buf[200];
+
+#define ERR(fmt, ...) do { \
+ snprintf(snprintf_buf, sizeof snprintf_buf, \
+ "ERROR: " fmt " (seed %d, ncalls %d, line %d)", \
+ __VA_ARGS__, seed, num_rand_calls, __LINE__); \
+ Serial1.println(snprintf_buf); \
+ } while (0)
+
+// -- setup()/loop() ----------------------------------------------------------
+
+void setup() {
+ fsmc_sram_init_gpios();
+ rcc_clk_enable(RCC_FSMC);
+
+ for (int i = 0; i < N; i++) {
+ *bcrs[i] = (FSMC_BCR_WREN |
+ FSMC_BCR_MTYP_SRAM |
+ FSMC_BCR_MWID_16BITS |
+ FSMC_BCR_MBKEN);
+ *btrs[i] = (DATAST << 8) | ADDSET;
+ }
+
+ Serial1.begin(115200);
+ randomSeed(seed);
+}
+
+// stress_test() and simple_roundtrip() are the available test routines
+bool stress_test(void);
+bool simple_roundtrip(void);
+
+void loop() {
+ uint32 count = 0;
+ bool ok = true;
+ bool (*test)(void) = stress_test;
+
+ while (true) {
+ count++;
+ bool result = test();
+ ok = ok && result;
+ if (ok) {
+ snprintf(snprintf_buf, sizeof snprintf_buf,
+ "everything ok so far, timestamp %d ms", millis());
+ Serial1.println(snprintf_buf);
+ }
+ }
+}
+
+// -- Test routines -----------------------------------------------------------
+
+bool random_trips();
+bool sequential_trips();
+
+bool stress_test(void) {
+ static int i = 0;
+ i = !i;
+
+ switch (i) {
+ case 0:
+ return random_trips();
+ default:
+ return sequential_trips();
+ }
+}
+
+bool simple_roundtrip(void) {
+ uint16 wval = 0xAB;
+
+ for (int i = 0; i < N; i++) {
+ __io uint16 *addr = starts[i] + 4;
+ snprintf(snprintf_buf, sizeof snprintf_buf, "round-trip 0x%x at %p",
+ wval, addr);
+ Serial1.println(snprintf_buf);
+
+ *addr = wval;
+ uint16 rval = *addr;
+
+ if (rval != wval) {
+ ERR("wrote 0x%x, read 0x%x, timestamp %d", wval, rval, millis());
+ return false;
+ } else {
+ snprintf(snprintf_buf, sizeof snprintf_buf, "got back 0x%x", rval);
+ Serial1.println(snprintf_buf);
+ }
+ }
+
+ return true;
+}
+
+bool random_trips(void) {
+ for (int n = 0; n < N; n++) {
+ __io uint16 *const start = starts[n];
+
+ for (int i = 0; i < 1000; i++) {
+ uint32 offset = rand(MEM_SIZE);
+ uint32 wval = rand(0xFFFF);
+
+ *(start + offset) = wval;
+ uint32 rval = *(start + offset);
+
+ if (rval != wval) {
+ ERR("wrote 0x%x to 0x%x, read 0x%x", wval, offset, rval);
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool sequential_trips(void) {
+ static const uint32 seq_length = 300;
+
+ for (int n = 0; n < N; n++) {
+ __io uint16 *const start = starts[n];
+
+ for (int i = 0; i < 100; i++) {
+ uint32 start_offset = rand(MEM_SIZE - seq_length);
+
+ for (uint32 w = 0; w < seq_length; w++) {
+ uint32 offset = start_offset + w;
+
+ *(start + offset) = w;
+ uint32 r = *(start + offset);
+
+ if (w != r) {
+ ERR("wrote 0x%x to 0x%x, read 0x%x", w, offset, r);
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+// ----------------------------------------------------------------------------
+
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+ while (true) {
+ loop();
+ }
+ return 0;
+}
+
diff --git a/examples/qa-slave-shield.cpp b/examples/qa-slave-shield.cpp
index b395cca..2da1c04 100644
--- a/examples/qa-slave-shield.cpp
+++ b/examples/qa-slave-shield.cpp
@@ -1,53 +1,64 @@
-// slave mode for QA shield
+// Slave mode for Quality Assurance test
#include "wirish.h"
-#define LED_PIN 13
-#define NUM_GPIO 38 // not the number of the max...
+#define INTER_TOGGLE_DELAY_NORMAL 5
+#define INTER_TOGGLE_DELAY_SLOW 80
-int i;
+void interToggleDelay(void);
-void setup()
-{
- /* Set up the LED to blink */
- pinMode(LED_PIN, OUTPUT);
- digitalWrite(LED_PIN, 1);
+void setup() {
+ pinMode(BOARD_LED_PIN, OUTPUT);
+ pinMode(BOARD_BUTTON_PIN, INPUT);
- for(i=0; i<NUM_GPIO; i++) {
- if(i==13) { continue; }
+ // All unused pins start out low.
+ for (int i = 0; i < BOARD_NR_GPIO_PINS; i++) {
+ if (boardUsesPin(i))
+ continue;
pinMode(i, OUTPUT);
- digitalWrite(i,0);
+ digitalWrite(i, LOW);
}
- //delay(5000);
SerialUSB.println("OK, starting...");
-
}
void loop() {
- digitalWrite(LED_PIN,1);
+ toggleLED();
delay(100);
- digitalWrite(LED_PIN,0);
-
- for(i=0; i<NUM_GPIO; i++) {
- if(i==13) { continue; }
- digitalWrite(i,1);
- delay(5);
- digitalWrite(i,0);
- delay(5);
+ toggleLED();
+
+ for (int i = 0; i < BOARD_NR_GPIO_PINS; i++) {
+ if (boardUsesPin(i))
+ continue;
+
+ // Bring just this pin high.
+ digitalWrite(i, HIGH);
+ // Give the master time to detect if any other pins also went high.
+ interToggleDelay();
+ // Bring this pin back low again; all pins should now be low.
+ digitalWrite(i, LOW);
+ // Give the master time to detect if any pins are still high.
+ interToggleDelay();
}
}
+void interToggleDelay(void) {
+ if (digitalRead(BOARD_BUTTON_PIN)) { // don't pay the debouncing time
+ delay(INTER_TOGGLE_DELAY_SLOW);
+ } else {
+ delay(INTER_TOGGLE_DELAY_NORMAL);
+ }
+ }
+
// Force init to be called *first*, i.e. before static object allocation.
-// Otherwise, statically allocated object that need libmaple may fail.
- __attribute__(( constructor )) void premain() {
+// Otherwise, statically allocated objects that need libmaple may fail.
+__attribute__((constructor)) void premain() {
init();
}
-int main(void)
-{
+int main(void) {
setup();
- while (1) {
+ while (true) {
loop();
}
return 0;
diff --git a/examples/spi_master.cpp b/examples/spi_master.cpp
index 9f6d81b..af3e709 100644
--- a/examples/spi_master.cpp
+++ b/examples/spi_master.cpp
@@ -1,75 +1,75 @@
-/* *****************************************************************************
+/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 LeafLabs LLC.
*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
*
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- * ****************************************************************************/
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *****************************************************************************/
/**
- * @brief Sample main.cpp file. Sends "Hello world!" out SPI1.
+ * @brief Sample main.cpp file. Sends "Hello world!" out SPI1.
*
- * SPI1 is set up to be a master transmitter at 4.5MHz, little endianness,
- * and SPI mode 0.
- *
- * Pin 10 is used as Chip Select
+ * SPI1 is set up to be a master transmitter at 4.5MHz, little
+ * endianness, and SPI mode 0.
*
+ * Pin 10 is used as slave select.
*/
#include "wirish.h"
-#define CS 10
+#define NSS 10
byte buf[] = "Hello world!";
HardwareSPI spi1(1);
void setup() {
- /* Set up chip select as output */
- pinMode(CS, OUTPUT);
+ /* Set up chip select as output */
+ pinMode(NSS, OUTPUT);
- /* CS is usually active low, so initialize it high */
- digitalWrite(CS, HIGH);
+ /* NSS is usually active LOW, so initialize it HIGH */
+ digitalWrite(NSS, HIGH);
- /* Initialize SPI */
+ /* Initialize SPI */
spi1.begin(SPI_4_5MHZ, LSBFIRST, 0);
}
void loop() {
- /* Send message */
- digitalWrite(CS, LOW);
- spi1.send(buf, sizeof buf);
- digitalWrite(CS,HIGH);
+ /* Send message */
+ digitalWrite(NSS, LOW);
+ spi1.write(buf, sizeof buf);
+ digitalWrite(NSS, HIGH);
delay(1000);
}
// Force init to be called *first*, i.e. before static object allocation.
-// Otherwise, statically allocated object that need libmaple may fail.
- __attribute__(( constructor )) void premain() {
+// Otherwise, statically allocated objects that need libmaple may fail.
+__attribute__((constructor)) void premain() {
init();
}
-int main(void)
-{
+int main(void) {
setup();
- while (1) {
+ while (true) {
loop();
}
return 0;
diff --git a/examples/test-bkp.cpp b/examples/test-bkp.cpp
new file mode 100644
index 0000000..f5957b7
--- /dev/null
+++ b/examples/test-bkp.cpp
@@ -0,0 +1,80 @@
+#include <stdio.h> // for snprintf()
+
+#include "wirish.h"
+#include "bkp.h"
+#include "iwdg.h"
+
+void print_bkp_contents();
+void write_to_bkp(uint16 val);
+
+#define comm Serial2
+
+void setup() {
+ pinMode(BOARD_BUTTON_PIN, INPUT);
+
+ comm.begin(9600);
+ comm.println("*** Beginning BKP test");
+
+ comm.println("Init...");
+ bkp_init();
+ comm.println("Done.");
+
+ print_bkp_contents();
+ write_to_bkp(10);
+ print_bkp_contents();
+
+ comm.println("Enabling backup writes.");
+ bkp_enable_writes();
+ write_to_bkp(20);
+ print_bkp_contents();
+
+ comm.println("Disabling backup writes.");
+ bkp_disable_writes();
+ write_to_bkp(30);
+ print_bkp_contents();
+
+ comm.println("Done testing backup registers; press button to enable "
+ "independent watchdog (in order to cause a reset).");
+ waitForButtonPress(0);
+ iwdg_init(IWDG_PRE_4, 1);
+ comm.println();
+}
+
+void loop() {
+}
+
+void print_bkp_contents() {
+ comm.println("Backup data register contents:");
+ char buf[100];
+ for (int i = 1; i <= BKP_NR_DATA_REGS; i++) {
+ snprintf(buf, sizeof buf, "DR%d: %d ", i, bkp_read(i));
+ comm.print(buf);
+ if (i % 5 == 0) comm.println();
+ }
+ comm.println();
+}
+
+void write_to_bkp(uint16 val) {
+ comm.print("Attempting to write ");
+ comm.print(val);
+ comm.println(" to backup registers...");
+ for (int i = 1; i <= BKP_NR_DATA_REGS; i++) {
+ bkp_write(i, val);
+ }
+ comm.println("Done.");
+}
+
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ init();
+ setup();
+
+ while (1) {
+ loop();
+ }
+ return 0;
+}
+
diff --git a/examples/test-dac.cpp b/examples/test-dac.cpp
index 3a699e2..40ae5d5 100644
--- a/examples/test-dac.cpp
+++ b/examples/test-dac.cpp
@@ -1,45 +1,51 @@
-
-#include "wirish.h"
-#include "fsmc.h"
-#include "rcc.h"
-#include "gpio.h"
-#include "dac.h"
-
-uint16 count = 0;
-
-void setup() {
-
- pinMode(BOARD_LED_PIN, OUTPUT);
- digitalWrite(BOARD_LED_PIN,1);
-
- Serial1.begin(9600);
- Serial1.println("**** Beginning DAC test");
-
- Serial1.print("Init... ");
- dac_init();
- Serial1.println("Done.");
-}
-
-void loop() {
- toggleLED();
- delay(100);
-
- count += 100;
- if(count > 4095) {
- count = 0;
- }
-
- dac_write(1, 2048);
- dac_write(2, count);
-}
-
-int main(void) {
- init();
- setup();
-
- while (1) {
- loop();
- }
- return 0;
-}
-
+/*
+ * Simple DAC test.
+ *
+ * Author: Marti Bolivar <mbolivar@leaflabs.com>
+ *
+ * This file is released into the public domain.
+ */
+
+#include "wirish.h"
+#include "dac.h"
+
+uint16 count = 0;
+
+void setup() {
+ pinMode(BOARD_LED_PIN, OUTPUT);
+ digitalWrite(BOARD_LED_PIN, HIGH);
+
+ Serial1.begin(9600);
+ Serial1.println("**** Beginning DAC test");
+
+ Serial1.print("Init... ");
+ dac_init(DAC, DAC_CH1 | DAC_CH2);
+ Serial1.println("Done.");
+}
+
+void loop() {
+ toggleLED();
+ delay(100);
+
+ count += 100;
+ if (count > 4095) {
+ count = 0;
+ }
+
+ dac_write_channel(DAC, 1, 4095 - count);
+ dac_write_channel(DAC, 2, count);
+}
+
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+
+ while (true) {
+ loop();
+ }
+ return 0;
+}
+
diff --git a/examples/test-fsmc.cpp b/examples/test-fsmc.cpp
index f4fd068..7db3bb7 100644
--- a/examples/test-fsmc.cpp
+++ b/examples/test-fsmc.cpp
@@ -1,119 +1,125 @@
+#include <stddef.h> // for ptrdiff_t
#include "wirish.h"
#include "fsmc.h"
-#define LED_PIN 23 // hack for maple native
-#define DISC_PIN 14 // hack for USB on native
-
-// System control block registers
-#define SCB_BASE (SCB_Reg*)(0xE000ED00)
-
-// This stuff should ultimately get moved to util.h or scb.h or w/e.
-// Also in interactive test program and the HardFault IRQ handler.
-typedef struct {
- volatile uint32 CPUID;
- volatile uint32 ICSR;
- volatile uint32 VTOR;
- volatile uint32 AIRCR;
- volatile uint32 SCR;
- volatile uint32 CCR;
- volatile uint32 SHPR1;
- volatile uint32 SHPR2;
- volatile uint32 SHPR3;
- volatile uint32 SHCRS;
- volatile uint32 CFSR;
- volatile uint32 HFSR;
- uint32 pad1;
- volatile uint32 MMAR;
- volatile uint32 BFAR;
-} SCB_Reg;
-
-SCB_Reg *scb;
-
-uint16 *ptr;
-int toggle = 0;
-int count = 0;
+#ifndef BOARD_maple_native
+#error "Sorry, this example only works on Maple Native."
+#endif
+
+// Start of FSMC SRAM bank 1
+static uint16 *const sram_start = (uint16*)0x60000000;
+// End of Maple Native SRAM chip address space (512K 16-bit words)
+static uint16 *const sram_end = (uint16*)0x60080000;
+
+void test_single_write(void);
+void test_all_addresses(void);
void setup() {
- uint32 id;
- scb = (SCB_Reg*)SCB_BASE;
-
- pinMode(LED_PIN, OUTPUT);
- pinMode(DISC_PIN, OUTPUT);
- digitalWrite(DISC_PIN,1);
- digitalWrite(LED_PIN,1);
-
- Serial1.begin(9600);
- Serial1.println("Hello World!");
-
- Serial1.print("Init... ");
- fsmc_native_sram_init();
- Serial1.println("Done.");
-
- // Start of channel1 SRAM bank (through to 0x63FFFFFF, though only a chunk
- // of this is valid)
- ptr = (uint16*)(0x60000000);
-
- Serial1.print("Writing... ");
- *ptr = 0x1234;
- Serial1.println("Done.");
-
- Serial1.print("Reading... ");
- id = *ptr;
- Serial1.print("Done: "); // shouldn't be 0xFFFFFFFF
- Serial1.println(id,BIN);
-
- Serial1.println("Dumping System Control Block Registers");
- Serial1.print("CPUID: ");
- id = scb->CPUID;
- Serial1.println(id,BIN);
- Serial1.print("ICSR: ");
- id = scb->ICSR;
- Serial1.println(id,BIN);
- Serial1.print("CFSR: ");
- id = scb->CFSR;
- Serial1.println(id,BIN);
- Serial1.print("HFSR: ");
- id = scb->HFSR;
- Serial1.println(id,BIN);
- Serial1.print("MMAR: ");
- id = scb->MMAR;
- Serial1.println(id,BIN);
- Serial1.print("BFAR: ");
- id = scb->BFAR;
- Serial1.println(id,BIN);
-
- Serial1.println("Now testing all memory addresses... (will hardfault at the end)");
- delay(3000);
+ pinMode(BOARD_LED_PIN, OUTPUT);
+ digitalWrite(BOARD_LED_PIN, HIGH);
+
+ Serial1.begin(115200);
+ Serial1.println("*** Beginning RAM chip test");
+
+ test_single_write();
+ test_all_addresses();
+
+ Serial1.println("Tests pass, finished.");
}
void loop() {
- digitalWrite(LED_PIN, toggle);
- toggle ^= 1;
- delay(1);
-
- for(int i = 0; i<100; i++) { // modify this to speed things up
- count++;
- ptr++;
- //delay(10); // tweak this to test SRAM resiliance over time
- *ptr = (0x0000FFFF & count);
- if(*ptr != (0x0000FFFF & count)) {
- Serial1.println("ERROR: mismatch, halting");
- while(1) { }
+}
+
+void test_single_write() {
+ uint16 *ptr = sram_start;
+ uint16 tmp;
+
+ Serial1.print("Writing 0x1234... ");
+ *ptr = 0x1234;
+ Serial1.println("Done.");
+
+ Serial1.print("Reading... ");
+ tmp = *ptr;
+ Serial1.print("Done: 0x");
+ Serial1.println(tmp, HEX);
+
+ if (tmp != 0x1234) {
+ Serial1.println("Mismatch; abort.");
+ ASSERT(0);
+ }
+}
+
+void test_all_addresses() {
+ uint32 start, end;
+ uint16 count = 0;
+ uint16 *ptr;
+
+ Serial1.println("Now writing all memory addresses (unrolled loop)");
+ // Turn off the USB interrupt, as it interferes most with timing
+ // (don't turn off SysTick, or we won't get micros()).
+ SerialUSB.end();
+ start = micros();
+ for (ptr = sram_start; ptr < sram_end;) {
+ *ptr++ = count++;
+ *ptr++ = count++;
+ *ptr++ = count++;
+ *ptr++ = count++;
+ *ptr++ = count++;
+ *ptr++ = count++;
+ *ptr++ = count++;
+ *ptr++ = count++;
+ *ptr++ = count++;
+ *ptr++ = count++;
+ *ptr++ = count++;
+ *ptr++ = count++;
+ *ptr++ = count++;
+ *ptr++ = count++;
+ *ptr++ = count++;
+ *ptr++ = count++;
+ }
+ end = micros();
+ SerialUSB.begin();
+ Serial1.print("Done. Elapsed time (us): ");
+ Serial1.println(end - start);
+
+ Serial1.println("Validating writes.");
+ for (ptr = sram_start, count = 0; ptr < sram_end; ptr++, count++) {
+ uint16 value = *ptr;
+ if (value != count) {
+ Serial1.print("mismatch: 0x");
+ Serial1.print((uint32)ptr);
+ Serial1.print(" = 0x");
+ Serial1.print(value, HEX);
+ Serial1.print(", should be 0x");
+ Serial1.print(count, HEX);
+ Serial1.println(".");
+ ASSERT(0);
}
- }
-
- Serial1.print((uint32)(ptr),HEX);
- Serial1.print(": ");
- Serial1.println(*ptr,BIN);
+ }
+ Serial1.println("Done; all writes seem valid.");
+
+ ptrdiff_t nwrites = sram_end - sram_start;
+ double us_per_write = double(end-start) / double(nwrites);
+ Serial1.print("Number of writes = ");
+ Serial1.print(nwrites);
+ Serial1.print("; avg. time per write = ");
+ Serial1.print(us_per_write);
+ Serial1.print(" us (");
+ Serial1.print(1 / us_per_write);
+ Serial1.println(" MHz)");
+}
+
+__attribute__((constructor)) void premain() {
+ init();
}
int main(void) {
- init();
- setup();
+ setup();
+
+ while (true) {
+ loop();
+ }
- while (1) {
- loop();
- }
- return 0;
+ return 0;
}
diff --git a/examples/test-print.cpp b/examples/test-print.cpp
new file mode 100644
index 0000000..ff3c219
--- /dev/null
+++ b/examples/test-print.cpp
@@ -0,0 +1,181 @@
+/*
+ * print-test.cpp
+ *
+ * Tests the various Print methods. (For USBSerial; assuming that
+ * writing a single character works, this should generalize to
+ * HardwareSerial).
+ *
+ * This file is released into the public domain.
+ */
+
+#include "wirish.h"
+#undef min
+#undef max
+
+// For snprintf()
+#include <stdio.h>
+// The <limits.h> that comes with newlib is missing LLONG_MAX, etc.
+#include <limits>
+
+using namespace std;
+
+#define BUF_SIZE 100
+char buf[BUF_SIZE];
+
+void test_numbers(void);
+void test_base_arithmetic(void);
+void test_floating_point(void);
+
+void print_separator(void);
+
+void setup() {
+ while (!SerialUSB.available())
+ continue;
+ SerialUSB.read();
+}
+
+void loop() {
+ SerialUSB.println("Testing Print methods.");
+ print_separator();
+
+ test_numbers();
+ print_separator();
+
+ test_base_arithmetic();
+ print_separator();
+
+ test_floating_point();
+ print_separator();
+
+ SerialUSB.println("Test finished.");
+ while (true) {
+ continue;
+ }
+}
+
+void test_numbers(void) {
+ SerialUSB.println("Numeric types:");
+
+ SerialUSB.println("unsigned char: ");
+ // prevent Print from treating it as an (extended) ASCII character:
+ SerialUSB.println((uint32)numeric_limits<unsigned char>::max());
+
+ SerialUSB.print("int: ");
+ SerialUSB.print(numeric_limits<int>::min());
+ SerialUSB.print(" -- ");
+ SerialUSB.println(numeric_limits<int>::max());
+
+ SerialUSB.print("unsigned int: ");
+ SerialUSB.print(numeric_limits<unsigned int>::max());
+ SerialUSB.println();
+
+ SerialUSB.print("long: ");
+ SerialUSB.print(numeric_limits<long>::min());
+ SerialUSB.print(" -- ");
+ SerialUSB.println(numeric_limits<long>::max());
+
+ SerialUSB.print("long long: ");
+ SerialUSB.print(numeric_limits<long long>::min());
+ SerialUSB.print(" -- ");
+ SerialUSB.println(numeric_limits<long long>::max());
+
+ SerialUSB.print("unsigned long long: ");
+ SerialUSB.println(numeric_limits<unsigned long long>::max());
+}
+
+void test_base_arithmetic(void) {
+ SerialUSB.println("Base arithmetic:");
+
+ SerialUSB.print("Binary: ");
+ SerialUSB.print(numeric_limits<unsigned long>::max(), BIN);
+ SerialUSB.print(", ");
+ SerialUSB.println(numeric_limits<unsigned long long>::max(), BIN);
+
+ SerialUSB.print("Octal: ");
+ SerialUSB.print(numeric_limits<unsigned long>::max(), OCT);
+ SerialUSB.print(", ");
+ SerialUSB.println(numeric_limits<unsigned long long>::max(), OCT);
+
+ SerialUSB.print("Decimal: ");
+ SerialUSB.print(numeric_limits<unsigned long>::max(), DEC);
+ SerialUSB.print(", ");
+ SerialUSB.println(numeric_limits<unsigned long long>::max(), DEC);
+
+ SerialUSB.print("Hexadecimal: ");
+ SerialUSB.print(numeric_limits<unsigned long>::max(), HEX);
+ SerialUSB.print(", ");
+ SerialUSB.println(numeric_limits<unsigned long long>::max(), HEX);
+}
+
+void test_floating_point(void) {
+ double dmax = numeric_limits<double>::max();
+
+ SerialUSB.println("Floating point:");
+
+ SerialUSB.print("sizeof double: ");
+ SerialUSB.println(sizeof(double));
+ SerialUSB.print("println(-5.67): ");
+ SerialUSB.println(-5.67);
+ SerialUSB.print("println((double)(LLONG_MAX - 10)): ");
+ SerialUSB.println((double)(numeric_limits<long long>::max() - 10));
+ SerialUSB.print("println((double)(LLONG_MAX - 10)) from snprintf(): ");
+ snprintf(buf, BUF_SIZE, "%.2f",
+ (double)(numeric_limits<long long>::max() - 10));
+ SerialUSB.println(buf);
+ SerialUSB.print("println((double)LLONG_MAX / 2): ");
+ SerialUSB.println((double)(numeric_limits<long long>::max()) / 2);
+ SerialUSB.print("println((double)LLONG_MAX / 2) from snprintf(): ");
+ snprintf(buf, BUF_SIZE, "%.2f",
+ (double)(numeric_limits<long long>::max()) / 2);
+ SerialUSB.println(buf);
+ SerialUSB.print("DBL_MAX: ");
+ SerialUSB.println(dmax);
+ SerialUSB.print("DBL_MAX from snprintf(): ");
+ snprintf(buf, BUF_SIZE, "%g", dmax);
+ SerialUSB.println(buf);
+ SerialUSB.print("-DBL_MAX / 2: ");
+ SerialUSB.println(-dmax / 2.0);
+ SerialUSB.print("-DBL_MAX / 2 from snprintf(): ");
+ snprintf(buf, BUF_SIZE, "%g", -dmax / 2.0);
+ SerialUSB.println(buf);
+ SerialUSB.print("Double epsilon, round error: ");
+ SerialUSB.print(numeric_limits<double>::epsilon());
+ SerialUSB.print(", ");
+ SerialUSB.println(numeric_limits<double>::round_error());
+
+ SerialUSB.println();
+
+ float fmax = numeric_limits<float>::max();
+
+ SerialUSB.print("sizeof float: ");
+ SerialUSB.println(sizeof(float));
+ SerialUSB.print("println(-5.67f): ");
+ SerialUSB.println(-5.67f);
+ SerialUSB.print("Float max: ");
+ SerialUSB.println(fmax);
+ SerialUSB.print("Float epsilon, round error: ");
+ SerialUSB.print(numeric_limits<float>::epsilon());
+ SerialUSB.print(", ");
+ SerialUSB.println(numeric_limits<float>::round_error());
+}
+
+void print_separator(void) {
+ SerialUSB.println();
+ SerialUSB.println(" ** ");
+ SerialUSB.println();
+}
+
+// Force init to be called *first*, i.e. before static object allocation.
+// Otherwise, statically allocated objects that need libmaple may fail.
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+
+ while (1) {
+ loop();
+ }
+ return 0;
+}
diff --git a/examples/test-ring-buffer-insertion.cpp b/examples/test-ring-buffer-insertion.cpp
new file mode 100644
index 0000000..e86372a
--- /dev/null
+++ b/examples/test-ring-buffer-insertion.cpp
@@ -0,0 +1,114 @@
+/*
+ * Simple ring_buffer test.
+ *
+ * Does a basic test of functionality on rb_full_count(), rb_reset(),
+ * rb_push_insert(), and rb_safe_insert().
+ *
+ * To test:
+ *
+ * - Connect a serial monitor to SerialUSB
+ * - Press any key
+ *
+ * This file is released into the public domain.
+ */
+
+#include "wirish.h"
+
+#include "ring_buffer.h"
+
+#define BUF_SIZE 64
+ring_buffer ring_buf;
+ring_buffer *rb;
+uint8 rb_buffer[BUF_SIZE];
+
+void test_rb_push_insert(int num_bytes_to_insert);
+void test_rb_safe_insert(int num_bytes_to_insert);
+void test_rb_insertion_function(int num_bytes_to_insert,
+ int (*insertion_fn)(ring_buffer*, uint8),
+ const char insertion_fn_name[]);
+void print_rb_contents(void);
+
+void setup() {
+ rb = &ring_buf;
+ rb_init(rb, BUF_SIZE, rb_buffer);
+
+ while (!SerialUSB.available())
+ ;
+
+ SerialUSB.println("Beginning test.");
+ SerialUSB.println();
+}
+
+void loop() {
+ test_rb_push_insert(63);
+ SerialUSB.println("------------------------------");
+ test_rb_push_insert(64);
+ SerialUSB.println("------------------------------");
+ test_rb_safe_insert(63);
+ SerialUSB.println("------------------------------");
+ test_rb_safe_insert(64);
+ SerialUSB.println("------------------------------");
+
+ SerialUSB.println();
+ SerialUSB.println("Test finished.");
+ while (true)
+ ;
+}
+
+void test_rb_push_insert(int num_bytes_to_insert) {
+ test_rb_insertion_function(num_bytes_to_insert,
+ rb_push_insert,
+ "rb_push_insert()");
+}
+
+void test_rb_safe_insert(int num_bytes_to_insert) {
+ test_rb_insertion_function(num_bytes_to_insert,
+ rb_safe_insert,
+ "rb_safe_insert()");
+}
+
+void test_rb_insertion_function(int num_bytes_to_insert,
+ int (*insertion_fn)(ring_buffer *, uint8),
+ const char insertion_fn_name[]) {
+ SerialUSB.println("resetting ring buffer.");
+ rb_reset(rb);
+ print_rb_contents();
+
+ SerialUSB.print(insertion_fn_name);
+ SerialUSB.print("-ing ");
+ SerialUSB.print(num_bytes_to_insert);
+ SerialUSB.println(" bytes.");
+ for (uint8 i = 1; i <= num_bytes_to_insert; i++)
+ insertion_fn(rb, i);
+
+ uint16 count = rb_full_count(rb);
+ SerialUSB.print("rb_full_count(rb) = ");
+ SerialUSB.println(count);
+
+ print_rb_contents();
+}
+
+void print_rb_contents() {
+ uint16 count = rb_full_count(rb);
+ SerialUSB.print("ring buffer contents: ");
+ for (uint16 i = 0; i < count; i++) {
+ SerialUSB.print((int)rb_remove(rb));
+ if (i < count - 1) SerialUSB.print(", ");
+ }
+ SerialUSB.println();
+}
+
+// Force init to be called *first*, i.e. before static object allocation.
+// Otherwise, statically allocated objects that need libmaple may fail.
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+
+ while (true) {
+ loop();
+ }
+ return 0;
+}
diff --git a/examples/test-serial-flush.cpp b/examples/test-serial-flush.cpp
index d7fbf7a..adc9c3e 100644
--- a/examples/test-serial-flush.cpp
+++ b/examples/test-serial-flush.cpp
@@ -1,44 +1,37 @@
-// Tests the "flush" Serial function
+/*
+ * Tests the "flush" Serial function.
+ */
#include "wirish.h"
-void setup()
-{
- /* Send a message out USART2 */
- Serial2.begin(9600);
- Serial2.println("Hello world!");
+void setup() {
+ Serial1.begin(9600);
+ Serial1.println("Hello world!");
}
-int toggle = 0;
-
void loop() {
-
- Serial2.println("This is the first line.");
- Serial2.end();
- Serial2.println("This is the second line.");
-
- Serial2.begin(9600);
- Serial2.println("Waiting for multiple input...");
- while(Serial2.available() < 5) { }
- Serial2.println(Serial2.read());
- Serial2.println(Serial2.read());
- Serial2.flush();
- if(Serial2.available()) {
- Serial2.println("FAIL! Still had junk in the buffer...");
+ Serial1.println("Waiting for multiple input...");
+ while (Serial1.available() < 5)
+ ;
+ Serial1.println(Serial1.read());
+ Serial1.println(Serial1.read());
+ Serial1.flush();
+
+ if (Serial1.available()) {
+ Serial1.println("FAIL! Still had junk in the buffer...");
}
}
// Force init to be called *first*, i.e. before static object allocation.
-// Otherwise, statically allocated object that need libmaple may fail.
- __attribute__(( constructor )) void premain() {
+// Otherwise, statically allocated objects that need libmaple may fail.
+__attribute__((constructor)) void premain() {
init();
}
-int main(void)
-{
+int main(void) {
setup();
- while (1) {
+ while (true) {
loop();
}
return 0;
diff --git a/examples/test-serialusb.cpp b/examples/test-serialusb.cpp
index 9d0a862..15ab913 100644
--- a/examples/test-serialusb.cpp
+++ b/examples/test-serialusb.cpp
@@ -1,81 +1,74 @@
-// Sample main.cpp file. Blinks an LED, sends a message out USART2
-// and turns on PWM on pin 2
+// Tests SerialUSB functionality.
#include "wirish.h"
#include "usb.h"
-#define LED_PIN 13
-#define BUT_PIN 38
-
-uint32 state = 0;
#define QUICKPRINT 0
#define BIGSTUFF 1
#define NUMBERS 2
#define SIMPLE 3
#define ONOFF 4
+uint32 state = 0;
-void setup()
-{
+void setup() {
/* Set up the LED to blink */
- pinMode(LED_PIN, OUTPUT);
-
- /* Set up the Button */
- pinMode(BUT_PIN, INPUT_PULLUP);
+ pinMode(BOARD_LED_PIN, OUTPUT);
+ /* Set up Serial2 for use as a debug channel */
Serial2.begin(9600);
- Serial2.println("Hello world! This is the debug channel.");
+ Serial2.println("This is the debug channel. Press any key.");
+ while (!Serial2.available())
+ ;
+ Serial2.read();
}
-int toggle = 0;
-
uint8 c1 = '-';
void loop() {
- toggle ^= 1;
- digitalWrite(LED_PIN, toggle);
+ toggleLED();
delay(1000);
- if(digitalRead(BUT_PIN)) {
- while(digitalRead(BUT_PIN)) {};
+ if (Serial2.available()) {
+ Serial2.read();
state++;
}
-
- switch(state) {
+
+ switch (state) {
case QUICKPRINT:
- for(int i = 0; i<30; i++) {
- usbSendBytes(&c1,1);
+ for (int i = 0; i < 30; i++) {
+ usbSendBytes(&c1, 1);
SerialUSB.print('.');
SerialUSB.print('|');
}
- Serial2.println(SerialUSB.pending(),DEC);
+ Serial2.println(SerialUSB.pending(), DEC);
SerialUSB.println();
break;
case BIGSTUFF:
- SerialUSB.println("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");
- SerialUSB.println((uint32)123456789,DEC);
+ SerialUSB.println("0123456789012345678901234567890123456789"
+ "0123456789012345678901234567890123456789"
+ "012345678901234567890");
+ SerialUSB.println((int64)123456789, DEC);
SerialUSB.println(3.1415926535);
- Serial2.println(SerialUSB.pending(),DEC);
+ Serial2.println(SerialUSB.pending(), DEC);
break;
case NUMBERS:
SerialUSB.println("Numbers! -----------------------------");
Serial2.println("Numbers! -----------------------------");
SerialUSB.println('1');
Serial2.println('1');
- SerialUSB.println(1,DEC);
- Serial2.println(1,DEC);
- SerialUSB.println(-1,DEC);
- Serial2.println(-1,DEC);
+ SerialUSB.println(1, DEC);
+ Serial2.println(1, DEC);
+ SerialUSB.println(-1, DEC);
+ Serial2.println(-1, DEC);
SerialUSB.println(3.14159265);
Serial2.println(3.14159265);
- SerialUSB.println(3.14159265,9);
- Serial2.println(3.14159265,9);
- SerialUSB.println(123456789,DEC);
- Serial2.println(123456789,DEC);
- SerialUSB.println(-123456789,DEC);
- Serial2.println(-123456789,DEC);
- SerialUSB.println(65535,HEX);
- Serial2.println(65535,HEX);
+ SerialUSB.println(123456789, DEC);
+ Serial2.println(123456789, DEC);
+ SerialUSB.println(-123456789, DEC);
+ Serial2.println(-123456789, DEC);
+ SerialUSB.println(65535, HEX);
+ Serial2.println(65535, HEX);
break;
case SIMPLE:
Serial2.println("Trying write('a')");
@@ -92,8 +85,8 @@ void loop() {
SerialUSB.print("hij\n\r");
SerialUSB.write(' ');
SerialUSB.println();
- Serial2.println("Trying println(123456789,DEC)");
- SerialUSB.println(123456789);
+ Serial2.println("Trying println(123456789, DEC)");
+ SerialUSB.println(123456789, DEC);
Serial2.println("Trying println(3.141592)");
SerialUSB.println(3.141592);
Serial2.println("Trying println(\"DONE\")");
@@ -103,12 +96,12 @@ void loop() {
Serial2.println("Shutting down...");
SerialUSB.println("Shutting down...");
SerialUSB.end();
- Serial2.println("Waiting 4seconds...");
+ Serial2.println("Waiting 4 seconds...");
delay(4000);
Serial2.println("Starting up...");
SerialUSB.begin();
SerialUSB.println("Hello World!");
- Serial2.println("Waiting 4seconds...");
+ Serial2.println("Waiting 4 seconds...");
delay(4000);
state++;
break;
@@ -118,18 +111,16 @@ void loop() {
}
// Force init to be called *first*, i.e. before static object allocation.
-// Otherwise, statically allocated object that need libmaple may fail.
- __attribute__(( constructor )) void premain() {
+// Otherwise, statically allocated objects that need libmaple may fail.
+__attribute__((constructor)) void premain() {
init();
}
-int main(void)
-{
+int main(void) {
setup();
- while (1) {
+ while (true) {
loop();
}
return 0;
}
-
diff --git a/examples/test-servo.cpp b/examples/test-servo.cpp
new file mode 100644
index 0000000..b6b8cd5
--- /dev/null
+++ b/examples/test-servo.cpp
@@ -0,0 +1,152 @@
+/*
+ * Basic Servo library test program.
+ *
+ * Setup:
+ *
+ * - Connect a potentiometer to POT_PIN (default pin 15)
+ * - Connect an oscilloscope to SERVO_PIN1 (default pin 5) and
+ * SERVO_PIN2 (default pin 6).
+ * - Connect a serial monitor to SerialUSB
+ *
+ * The potentiometer controls the target angle for each of two Servo
+ * objects, one with angles in [-90, 90], and another in [0, 180].
+ * Servo pulse width range is [1000, 2000].
+ *
+ * Serial2 will tell you what inputs it's giving to each servo object,
+ * and some information it gets back. Pressing the button
+ * detaches/reattaches the Servo objects.
+ *
+ * Tests you should perform:
+ *
+ * - Check calculated pulse widths for each servo's target angle
+ * - Check that calculated pulse widths match actual pulse widths
+ * - Check that the period of the pulse train is roughly 20 ms
+ * - Check that the pulses stop when detached, and resume when reattached
+ * - Check that Servo::write() and Servo::read() round-trip properly
+ *
+ * This file is released into the public domain.
+ */
+
+#include <stdio.h>
+
+#include "wirish.h"
+
+#include "libraries/Servo/Servo.h"
+
+#define POT_PIN 15
+
+#define MIN_PW 1000
+#define MAX_PW 2000
+
+#define SERVO_PIN1 5
+#define MIN_ANGLE1 0
+#define MAX_ANGLE1 180
+
+#define SERVO_PIN2 6
+#define MIN_ANGLE2 (-90)
+#define MAX_ANGLE2 90
+
+Servo servo1;
+Servo servo2;
+
+#define BUF_SIZE 100
+char buf[BUF_SIZE];
+
+#define print_buf(fmt, ...) do { \
+ snprintf(buf, BUF_SIZE, fmt, __VA_ARGS__); \
+ Serial2.println(buf); } while (0)
+
+int averageAnalogReads(int);
+void attach();
+void detach();
+
+void setup() {
+ pinMode(POT_PIN, INPUT_ANALOG);
+ pinMode(BOARD_BUTTON_PIN, INPUT);
+ pinMode(BOARD_LED_PIN, OUTPUT);
+
+ Serial2.begin(9600);
+
+ servo1.attach(SERVO_PIN1, MIN_PW, MAX_PW, MIN_ANGLE1, MAX_ANGLE1);
+ servo2.attach(SERVO_PIN2, MIN_PW, MAX_PW, MIN_ANGLE2, MAX_ANGLE2);
+
+ ASSERT(servo1.attachedPin() == SERVO_PIN1);
+ ASSERT(servo2.attachedPin() == SERVO_PIN2);
+}
+
+void loop() {
+ delay(250);
+ toggleLED();
+
+ if (isButtonPressed()) {
+ if (servo1.attached()) detach();
+ else attach();
+ }
+
+ if (!servo1.attached()) return;
+
+ int32 average = averageAnalogReads(250);
+ int16 angle1 = (int16)map(average, 0, 4095, MIN_ANGLE1, MAX_ANGLE1);
+ int16 angle2 = (int16)map(average, 0, 4095, MIN_ANGLE2, MAX_ANGLE2);
+
+ print_buf("pot reading = %d, angle 1 = %d, angle 2 = %d.",
+ average, angle1, angle2);
+
+ servo1.write(angle1);
+ servo2.write(angle2);
+
+ int16 read1 = servo1.read();
+ int16 read2 = servo2.read();
+
+ print_buf("write/read angle 1: %d/%d, angle 2: %d/%d",
+ angle1, read1, angle2, read2);
+
+ ASSERT(abs(angle1 - read1) <= 1);
+ ASSERT(abs(angle2 - read2) <= 1);
+
+ print_buf("pulse width 1: %d, pulse width 2: %d",
+ servo1.readMicroseconds(), servo2.readMicroseconds());
+
+ Serial2.println("\n--------------------------\n");
+}
+
+int32 averageAnalogReads(int n) {
+ uint64 total = 0;
+
+ for (int i = 0; i < n; i++) {
+ total += analogRead(POT_PIN);
+ }
+
+ return (int32)(total / n);
+}
+
+void attach() {
+ Serial2.println("attaching");
+ servo1.attach(SERVO_PIN1);
+ servo2.attach(SERVO_PIN2);
+ ASSERT(servo1.attachedPin() == SERVO_PIN1);
+ ASSERT(servo2.attachedPin() == SERVO_PIN2);
+}
+
+void detach() {
+ Serial2.println("detaching");
+ servo1.detach();
+ servo2.detach();
+ ASSERT(!servo1.attached());
+ ASSERT(!servo2.attached());
+}
+
+// Force init to be called *first*, i.e. before static object allocation.
+// Otherwise, statically allocated objects that need libmaple may fail.
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+
+ while (true) {
+ loop();
+ }
+ return 0;
+}
diff --git a/examples/test-session.cpp b/examples/test-session.cpp
index 845547d..959c1b8 100644
--- a/examples/test-session.cpp
+++ b/examples/test-session.cpp
@@ -1,112 +1,93 @@
// Interactive Test Session for LeafLabs Maple
// Copyright (c) 2010 LeafLabs LLC.
//
-// Useful for testing Maple features and troubleshooting. Select a COMM port
-// (SerialUSB or Serial2) before compiling and then enter 'h' at the prompt
-// for a list of commands.
+// Useful for testing Maple features and troubleshooting.
+// Communicates over SerialUSB.
#include "wirish.h"
-#define LED_PIN BOARD_LED_PIN
-#define PWM_PIN 3
-
-// choose your weapon
-#define COMM SerialUSB
-//#define COMM Serial2
-//#define COMM Serial3
-
-
+// ASCII escape character
#define ESC ((uint8)27)
-int rate = 0;
-
-#if defined(BOARD_maple)
-const uint8 pwm_pins[] =
- {0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 14, 24, 25, 27, 28};
-const uint8 adc_pins[] =
- {0, 1, 2, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 27, 28};
+// Default USART baud rate
+#define BAUD 9600
-#elif defined(BOARD_maple_mini)
-const uint8 pwm_pins[] = {3, 4, 5, 8, 9, 10, 11, 15, 16, 25, 26, 27};
-const uint8 adc_pins[] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 33}; // NB: 33 is LED
+uint8 gpio_state[BOARD_NR_GPIO_PINS];
-#elif defined(BOARD_maple_native)
-const uint8 pwm_pins[] = {12, 13, 14, 15, 22, 23, 24, 25, 37, 38, 45,
- 46, 47, 48, 49, 50, 53, 54};
-const uint8 adc_pins[] = {6, 7, 8, 9, 10, 11,
- /* the following are on ADC3, which lacks support:
- 39, 40, 41, 42, 43, 45, */
- 46, 47, 48, 49, 50, 51, 52, 53, 54};
-
-#else
-#error "Board type has not been selected correctly"
-
-#endif
-
-uint8 gpio_state[NR_GPIO_PINS];
-
-const char* const dummy_dat = ("qwertyuiopasdfghjklzxcvbnmmmmmm,./1234567890-="
- "qwertyuiopasdfghjklzxcvbnm,./1234567890");
+const char* dummy_data = ("qwertyuiopasdfghjklzxcvbnmmmmmm,./1234567890-="
+ "qwertyuiopasdfghjklzxcvbnm,./1234567890");
+// Commands
void cmd_print_help(void);
void cmd_adc_stats(void);
void cmd_stressful_adc_stats(void);
void cmd_everything(void);
void cmd_serial1_serial3(void);
+void cmd_serial1_echo(void);
void cmd_gpio_monitoring(void);
void cmd_sequential_adc_reads(void);
void cmd_gpio_qa(void);
-void cmd_sequential_gpio_writes(void);
+void cmd_sequential_gpio_toggling(void);
void cmd_gpio_toggling(void);
+void cmd_sequential_debug_gpio_toggling(void);
+void cmd_debug_gpio_toggling(void);
+void cmd_but_test(void);
void cmd_sequential_pwm_test(void);
-void cmd_pwm_sweep(void);
void cmd_servo_sweep(void);
+void cmd_board_info(void);
+// Helper functions
void measure_adc_noise(uint8 pin);
void fast_gpio(int pin);
-void do_serials(HardwareSerial **serials, int n, unsigned baud);
+void serial_baud_test(HardwareSerial **serials, int n, unsigned baud);
+void serial_echo_test(HardwareSerial *serial, unsigned baud);
void init_all_timers(uint16 prescale);
+void enable_usarts(void);
+void disable_usarts(void);
+void print_board_array(const char* msg, const uint8 arr[], int len);
+
+// -- setup() and loop() ------------------------------------------------------
void setup() {
// Set up the LED to blink
pinMode(BOARD_LED_PIN, OUTPUT);
// Start up the serial ports
- Serial1.begin(9600);
- Serial2.begin(9600);
- Serial3.begin(9600);
-
- // Send a message out over COMM interface
- COMM.println(" ");
- COMM.println(" __ __ _ _");
- COMM.println(" | \\/ | __ _ _ __ | | ___| |");
- COMM.println(" | |\\/| |/ _` | '_ \\| |/ _ \\ |");
- COMM.println(" | | | | (_| | |_) | | __/_|");
- COMM.println(" |_| |_|\\__,_| .__/|_|\\___(_)");
- COMM.println(" |_|");
- COMM.println(" by leaflabs");
- COMM.println("");
- COMM.println("");
- COMM.println("Maple interactive test program (type '?' for help)");
- COMM.println("----------------------------------------------------------");
- COMM.print("> ");
+ Serial1.begin(BAUD);
+ Serial2.begin(BAUD);
+ Serial3.begin(BAUD);
+
+ // Send a message out over SerialUSB interface
+ SerialUSB.println(" ");
+ SerialUSB.println(" __ __ _ _");
+ SerialUSB.println(" | \\/ | __ _ _ __ | | ___| |");
+ SerialUSB.println(" | |\\/| |/ _` | '_ \\| |/ _ \\ |");
+ SerialUSB.println(" | | | | (_| | |_) | | __/_|");
+ SerialUSB.println(" |_| |_|\\__,_| .__/|_|\\___(_)");
+ SerialUSB.println(" |_|");
+ SerialUSB.println(" by leaflabs");
+ SerialUSB.println("");
+ SerialUSB.println("");
+ SerialUSB.println("Maple interactive test program (type '?' for help)");
+ SerialUSB.println("----------------------------------------------------------");
+ SerialUSB.print("> ");
}
void loop () {
toggleLED();
- delay(100);
+ delay(250);
- while(COMM.available()) {
- uint8 input = COMM.read();
- COMM.println(input);
+ while (SerialUSB.available()) {
+ uint8 input = SerialUSB.read();
+ SerialUSB.println(input);
switch(input) {
case '\r':
break;
case ' ':
- COMM.println("spacebar, nice!");
+ SerialUSB.println("spacebar, nice!");
break;
case '?':
@@ -128,8 +109,12 @@ void loop () {
cmd_serial1_serial3();
break;
+ case 'E':
+ cmd_serial1_echo();
+ break;
+
case '.':
- while(!COMM.available()) {
+ while (!SerialUSB.available()) {
Serial1.print(".");
Serial2.print(".");
Serial3.print(".");
@@ -150,33 +135,45 @@ void loop () {
break;
case 'W':
- while(!COMM.available()) {
- Serial1.print(dummy_dat);
- Serial2.print(dummy_dat);
- Serial3.print(dummy_dat);
+ while (!SerialUSB.available()) {
+ Serial1.print(dummy_data);
+ Serial2.print(dummy_data);
+ Serial3.print(dummy_data);
}
break;
case 'U':
- COMM.println("Dumping data to USB. Press any key.");
- while(!COMM.available()) {
- SerialUSB.print(dummy_dat);
+ SerialUSB.println("Dumping data to USB. Press any key.");
+ while (!SerialUSB.available()) {
+ SerialUSB.print(dummy_data);
}
break;
case 'g':
- cmd_sequential_gpio_writes();
+ cmd_sequential_gpio_toggling();
break;
case 'G':
cmd_gpio_toggling();
break;
+ case 'j':
+ cmd_sequential_debug_gpio_toggling();
+ break;
+
+ case 'J':
+ cmd_debug_gpio_toggling();
+ break;
+
+ case 'B':
+ cmd_but_test();
+ break;
+
case 'f':
- COMM.println("Wiggling D4 as fast as possible in bursts. "
+ SerialUSB.println("Wiggling D4 as fast as possible in bursts. "
"Press any key.");
- pinMode(4,OUTPUT);
- while(!COMM.available()) {
+ pinMode(4, OUTPUT);
+ while (!SerialUSB.available()) {
fast_gpio(4);
delay(1);
}
@@ -186,19 +183,19 @@ void loop () {
cmd_sequential_pwm_test();
break;
- case 'P':
- cmd_pwm_sweep();
- break;
-
case '_':
- COMM.println("Delaying for 5 seconds...");
+ SerialUSB.println("Delaying for 5 seconds...");
delay(5000);
break;
+ // Be sure to update cmd_print_help() if you implement these:
+
case 't': // TODO
+ SerialUSB.println("Unimplemented.");
break;
case 'T': // TODO
+ SerialUSB.println("Unimplemented.");
break;
case 's':
@@ -206,26 +203,30 @@ void loop () {
break;
case 'd':
- COMM.println("Pulling down D4, D22. Press any key.");
- pinMode(22,INPUT_PULLDOWN);
- pinMode(4,INPUT_PULLDOWN);
- while(!COMM.available()) {
+ SerialUSB.println("Pulling down D4, D22. Press any key.");
+ pinMode(22, INPUT_PULLDOWN);
+ pinMode(4, INPUT_PULLDOWN);
+ while (!SerialUSB.available()) {
continue;
}
- COMM.println("Pulling up D4, D22. Press any key.");
- pinMode(22,INPUT_PULLUP);
- pinMode(4,INPUT_PULLUP);
- while(!COMM.available()) {
+ SerialUSB.println("Pulling up D4, D22. Press any key.");
+ pinMode(22, INPUT_PULLUP);
+ pinMode(4, INPUT_PULLUP);
+ while (!SerialUSB.available()) {
continue;
}
- COMM.read();
- pinMode(4,OUTPUT);
+ SerialUSB.read();
+ pinMode(4, OUTPUT);
break;
+ // Be sure to update cmd_print_help() if you implement these:
+
case 'i': // TODO
+ SerialUSB.println("Unimplemented.");
break;
case 'I': // TODO
+ SerialUSB.println("Unimplemented.");
break;
case 'r':
@@ -236,403 +237,662 @@ void loop () {
cmd_sequential_adc_reads();
break;
+ case 'b':
+ cmd_board_info();
+ break;
+
case '+':
cmd_gpio_qa();
break;
default: // -------------------------------
- COMM.print("Unexpected: ");
- COMM.print(input);
- COMM.println(", press h for help.");
+ SerialUSB.print("Unexpected byte: 0x");
+ SerialUSB.print((int)input, HEX);
+ SerialUSB.println(", press h for help.");
}
- COMM.print("> ");
+ SerialUSB.print("> ");
}
}
-void cmd_print_help(void) {
- COMM.println("");
- //COMM.println("Command Listing\t(# means any digit)");
- COMM.println("Command Listing");
- COMM.println("\t?: print this menu");
- COMM.println("\th: print this menu");
- COMM.println("\tw: print Hello World on all 3 USARTS");
- COMM.println("\tn: measure noise and do statistics");
- COMM.println("\tN: measure noise and do statistics with background stuff");
- COMM.println("\ta: show realtime ADC info");
- COMM.println("\t.: echo '.' until new input");
- COMM.println("\tu: print Hello World on USB");
- COMM.println("\t_: do as little as possible for a couple seconds (delay)");
- COMM.println("\tp: test all PWM channels sequentially");
- COMM.println("\tW: dump data as fast as possible on all 3 USARTS");
- COMM.println("\tU: dump data as fast as possible on USB");
- COMM.println("\tg: toggle all GPIOs sequentialy");
- COMM.println("\tG: toggle all GPIOs at the same time");
- COMM.println("\tf: toggle GPIO D4 as fast as possible in bursts");
- COMM.println("\tP: simultaneously test all PWM channels with different "
- "speeds/sweeps");
- COMM.println("\tr: Monitor and print GPIO status changes");
- COMM.println("\ts: output a sweeping servo PWM on all PWM channels");
- COMM.println("\tm: output data on USART1 and USART3 with various rates");
- COMM.println("\t+: test shield mode (for QA, will disrupt Serial2!)");
-
- COMM.println("Unimplemented:");
- COMM.println("\te: do everything all at once until new input");
- COMM.println("\tt: output a 1khz squarewave on all GPIOs");
- COMM.println("\tT: output a 1hz squarewave on all GPIOs");
- COMM.println("\ti: print out a bunch of info about system state");
- COMM.println("\tI: print out status of all headers");
-}
-
-void measure_adc_noise(uint8 pin) { // TODO
- uint16 data[100];
- float mean = 0;
- //float stddev = 0;
- float delta = 0;
- float M2 = 0;
- pinMode(pin, INPUT_ANALOG);
+// -- Commands ----------------------------------------------------------------
- // variance algorithm from knuth; see wikipedia
- // checked against python
- for(int i = 0; i<100; i++) {
- data[i] = analogRead(pin);
- delta = data[i] - mean;
- mean = mean + delta/(i+1);
- M2 = M2 + delta*(data[i] - mean);
- }
-
- //sqrt is broken?
- //stddev = sqrt(variance);
- COMM.print("header: D"); COMM.print(pin,DEC);
- COMM.print("\tn: "); COMM.print(100,DEC);
- COMM.print("\tmean: "); COMM.print(mean);
- COMM.print("\tvariance: "); COMM.println(M2/99.0);
- pinMode(pin, OUTPUT);
+void cmd_print_help(void) {
+ SerialUSB.println("");
+ SerialUSB.println("Command Listing");
+ SerialUSB.println("\t?: print this menu");
+ SerialUSB.println("\th: print this menu");
+ SerialUSB.println("\tw: print Hello World on all 3 USARTS");
+ SerialUSB.println("\tn: measure noise and do statistics");
+ SerialUSB.println("\tN: measure noise and do statistics with background "
+ "stuff");
+ SerialUSB.println("\ta: show realtime ADC info");
+ SerialUSB.println("\t.: echo '.' until new input");
+ SerialUSB.println("\tu: print Hello World on USB");
+ SerialUSB.println("\t_: do as little as possible for a couple seconds "
+ "(delay)");
+ SerialUSB.println("\tp: test all PWM channels sequentially");
+ SerialUSB.println("\tW: dump data as fast as possible on all 3 USARTS");
+ SerialUSB.println("\tU: dump data as fast as possible on USB");
+ SerialUSB.println("\tg: toggle GPIOs sequentially");
+ SerialUSB.println("\tG: toggle GPIOs at the same time");
+ SerialUSB.println("\tj: toggle debug port GPIOs sequentially");
+ SerialUSB.println("\tJ: toggle debug port GPIOs simultaneously");
+ SerialUSB.println("\tB: test the built-in button");
+ SerialUSB.println("\tf: toggle pin 4 as fast as possible in bursts");
+ SerialUSB.println("\tr: monitor and print GPIO status changes");
+ SerialUSB.println("\ts: output a sweeping servo PWM on all PWM channels");
+ SerialUSB.println("\tm: output data on USART1 and USART3 at various "
+ "baud rates");
+ SerialUSB.println("\tE: echo data on USART1 at various baud rates");
+ SerialUSB.println("\tb: print information about the board.");
+ SerialUSB.println("\t+: test shield mode (for quality assurance testing)");
+
+ SerialUSB.println("Unimplemented:");
+ SerialUSB.println("\te: do everything all at once until new input");
+ SerialUSB.println("\tt: output a 1khz squarewave on all GPIOs");
+ SerialUSB.println("\tT: output a 1hz squarewave on all GPIOs");
+ SerialUSB.println("\ti: print out a bunch of info about system state");
+ SerialUSB.println("\tI: print out status of all headers");
}
void cmd_adc_stats(void) {
- COMM.println("Taking ADC noise stats...");
+ SerialUSB.println("Taking ADC noise stats.");
digitalWrite(BOARD_LED_PIN, 0);
- for(uint32 i = 0; i<sizeof(adc_pins); i++) {
+ for (uint32 i = 0; i < BOARD_NR_ADC_PINS; i++) {
delay(5);
- measure_adc_noise(adc_pins[i]);
+ measure_adc_noise(boardADCPins[i]);
}
}
void cmd_stressful_adc_stats(void) {
- COMM.println("Taking ADC noise stats under duress...");
- digitalWrite(BOARD_LED_PIN, 0);
- for(uint32 i = 0; i<sizeof(adc_pins); i++) {
- // spool up PWM
- for(uint32 j = 2; j<(uint32)sizeof(pwm_pins); j++) {
- if(adc_pins[i] != pwm_pins[j]) {
- pinMode(pwm_pins[j],PWM);
- pwmWrite(pwm_pins[j], 1000 + i);
+ SerialUSB.println("Taking ADC noise stats under duress.");
+
+ for (uint32 i = 0; i < BOARD_NR_ADC_PINS; i++) {
+ for (uint32 j = 0; j < BOARD_NR_PWM_PINS; j++) {
+ if (boardADCPins[i] != boardPWMPins[j]) {
+ pinMode(boardPWMPins[j], PWM);
+ pwmWrite(boardPWMPins[j], 1000 + i);
}
}
- SerialUSB.print(dummy_dat);
- SerialUSB.print(dummy_dat);
- measure_adc_noise(adc_pins[i]);
- for(uint32 j = 2; j<(uint32)sizeof(pwm_pins); j++) {
- if(adc_pins[i] != pwm_pins[j]) {
- pinMode(pwm_pins[j],OUTPUT);
- digitalWrite(pwm_pins[j],0);
+
+ Serial1.print(dummy_data);
+
+ measure_adc_noise(boardADCPins[i]);
+
+ for (uint32 j = 0; j < BOARD_NR_PWM_PINS; j++) {
+ if (boardADCPins[i] != boardPWMPins[j]) {
+ pinMode(boardPWMPins[j], OUTPUT);
+ digitalWrite(boardPWMPins[j], LOW);
}
}
}
}
void cmd_everything(void) { // TODO
+ // Be sure to update cmd_print_help() if you implement this.
+
// print to usart
// print to usb
// toggle gpios
// enable pwm
- COMM.println("(unimplemented)");
-}
-
-void fast_gpio(int maple_pin) {
- GPIO_Port *port = PIN_MAP[maple_pin].port;
- uint32 pin = PIN_MAP[maple_pin].pin;
-
- gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0);
- gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0);
- gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0);
- gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0);
- gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0);
- gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0);
- gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0);
- gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0);
- gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0);
- gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0);
- gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0);
- gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0);
- gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0);
+ SerialUSB.println("Unimplemented.");
}
void cmd_serial1_serial3(void) {
HardwareSerial *serial_1_and_3[] = {&Serial1, &Serial3};
- COMM.println("Testing 57600 baud on USART1 and USART3. Press any key.");
- do_serials(serial_1_and_3, 2, 57600);
- COMM.read();
+ SerialUSB.println("Testing 57600 baud on USART1 and USART3. "
+ "Press any key to stop.");
+ serial_baud_test(serial_1_and_3, 2, 57600);
+ SerialUSB.read();
- COMM.println("Testing 115200 baud on USART1 and USART3. Press any key.");
- do_serials(serial_1_and_3, 2, 115200);
- COMM.read();
+ SerialUSB.println("Testing 115200 baud on USART1 and USART3. "
+ "Press any key to stop.");
+ serial_baud_test(serial_1_and_3, 2, 115200);
+ SerialUSB.read();
- COMM.println("Testing 9600 baud on USART1 and USART3. Press any key.");
- do_serials(serial_1_and_3, 2, 9600);
- COMM.read();
+ SerialUSB.println("Testing 9600 baud on USART1 and USART3. "
+ "Press any key to stop.");
+ serial_baud_test(serial_1_and_3, 2, 9600);
+ SerialUSB.read();
- COMM.println("Resetting USART1 and USART3...");
- Serial1.begin(9600);
- Serial3.begin(9600);
+ SerialUSB.println("Resetting USART1 and USART3...");
+ Serial1.begin(BAUD);
+ Serial3.begin(BAUD);
}
-void do_serials(HardwareSerial **serials, int n, unsigned baud) {
- for (int i = 0; i < n; i++) {
- serials[i]->begin(9600);
- }
- while (!COMM.available()) {
- for (int i = 0; i < n; i++) {
- serials[i]->println(dummy_dat);
- if (serials[i]->available()) {
- serials[i]->println(serials[i]->read());
- delay(1000);
- }
- }
- }
+void cmd_serial1_echo(void) {
+ SerialUSB.println("Testing serial echo at various baud rates. "
+ "Press any key for next baud rate, or ESC to quit "
+ "early.");
+ while (!SerialUSB.available())
+ ;
+
+ if (SerialUSB.read() == ESC) return;
+ SerialUSB.println("Testing 115200 baud on USART1.");
+ serial_echo_test(&Serial1, 115200);
+
+ if (SerialUSB.read() == ESC) return;
+ SerialUSB.println("Testing 57600 baud on USART1.");
+ serial_echo_test(&Serial1, 57600);
+
+ if (SerialUSB.read() == ESC) return;
+ SerialUSB.println("Testing 9600 baud on USART1.");
+ serial_echo_test(&Serial1, 9600);
}
void cmd_gpio_monitoring(void) {
- COMM.println("Monitoring GPIO read state changes. Press any key.");
- digitalWrite(BOARD_LED_PIN, 0);
- // make sure to skip the TX/RX headers
- for(int i = 2; i<NR_GPIO_PINS; i++) {
+ SerialUSB.println("Monitoring pin state changes. Press any key to stop.");
+
+ for (int i = 0; i < BOARD_NR_GPIO_PINS; i++) {
+ if (boardUsesPin(i))
+ continue;
pinMode(i, INPUT_PULLDOWN);
gpio_state[i] = (uint8)digitalRead(i);
}
- while(!COMM.available()) {
- for(int i = 2; i<NR_GPIO_PINS; i++) {
+
+ while (!SerialUSB.available()) {
+ for (int i = 0; i < BOARD_NR_GPIO_PINS; i++) {
+ if (boardUsesPin(i))
+ continue;
+
uint8 current_state = (uint8)digitalRead(i);
- if(current_state != gpio_state[i]) {
- COMM.print("State change on header D");
- COMM.print(i,DEC);
- if(current_state) COMM.println(":\tHIGH");
- else COMM.println(":\tLOW");
+ if (current_state != gpio_state[i]) {
+ SerialUSB.print("State change on pin ");
+ SerialUSB.print(i, DEC);
+ if (current_state) {
+ SerialUSB.println(":\tHIGH");
+ } else {
+ SerialUSB.println(":\tLOW");
+ }
gpio_state[i] = current_state;
}
}
}
- for(int i = 2; i<NR_GPIO_PINS; i++) {
+
+ for (int i = 0; i < BOARD_NR_GPIO_PINS; i++) {
+ if (boardUsesPin(i))
+ continue;
pinMode(i, OUTPUT);
}
}
void cmd_sequential_adc_reads(void) {
- COMM.print("Sequentially reading each ADC port.");
- COMM.println("Press any key for next port, or ESC to stop.");
- digitalWrite(LED_PIN, 0);
- // make sure to skip the TX/RX headers
- for(uint32 i = 2; i<sizeof(adc_pins); i++) {
- COMM.print("Reading on header D");
- COMM.print(adc_pins[i], DEC);
- COMM.println("...");
- pinMode(adc_pins[i], INPUT_ANALOG);
- while(!COMM.available()) {
- int sample = analogRead(adc_pins[i]);
- COMM.print(adc_pins[i],DEC);
- COMM.print("\t");
- COMM.print(sample,DEC);
- COMM.print("\t");
- COMM.print("|");
- for(int j = 0; j<4096; j+= 100) {
- if(sample >= j) COMM.print("#");
- else COMM.print(" ");
+ SerialUSB.print("Sequentially reading most ADC ports.");
+ SerialUSB.println("Press any key for next port, or ESC to stop.");
+
+ for (uint32 i = 0; i < BOARD_NR_ADC_PINS; i++) {
+ if (boardUsesPin(boardADCPins[i]))
+ continue;
+
+ SerialUSB.print("Reading pin ");
+ SerialUSB.print(boardADCPins[i], DEC);
+ SerialUSB.println("...");
+ pinMode(boardADCPins[i], INPUT_ANALOG);
+ while (!SerialUSB.available()) {
+ int sample = analogRead(boardADCPins[i]);
+ SerialUSB.print(boardADCPins[i], DEC);
+ SerialUSB.print("\t");
+ SerialUSB.print(sample, DEC);
+ SerialUSB.print("\t");
+ SerialUSB.print("|");
+ for (int j = 0; j < 4096; j += 100) {
+ if (sample >= j) {
+ SerialUSB.print("#");
+ } else {
+ SerialUSB.print(" ");
+ }
}
- COMM.print("| ");
- for(int j = 0; j<12; j++) {
- if(sample & (1 << (11-j))) COMM.print("1");
- else COMM.print("0");
+ SerialUSB.print("| ");
+ for (int j = 0; j < 12; j++) {
+ if (sample & (1 << (11 - j))) {
+ SerialUSB.print("1");
+ } else {
+ SerialUSB.print("0");
+ }
}
- COMM.println("");
+ SerialUSB.println("");
+ }
+ pinMode(boardADCPins[i], OUTPUT);
+ digitalWrite(boardADCPins[i], 0);
+ if (SerialUSB.read() == ESC)
+ break;
+ }
+}
+
+bool test_single_pin_is_high(int high_pin, const char* err_msg) {
+ bool ok = true;
+ for (int i = 0; i < BOARD_NR_GPIO_PINS; i++) {
+ if (boardUsesPin(i)) continue;
+
+ if (digitalRead(i) == HIGH && i != high_pin) {
+ SerialUSB.println();
+ SerialUSB.print("\t*** FAILURE! pin ");
+ SerialUSB.print(i, DEC);
+ SerialUSB.print(' ');
+ SerialUSB.println(err_msg);
+ ok = false;
+ }
+ }
+ return ok;
+}
+
+bool wait_for_low_transition(uint8 pin) {
+ uint32 start = millis();
+ while (millis() - start < 2000) {
+ if (digitalRead(pin) == LOW) {
+ return true;
}
- pinMode(adc_pins[i], OUTPUT);
- digitalWrite(adc_pins[i], 0);
- if((uint8)COMM.read() == ESC) break;
}
+ return false;
}
void cmd_gpio_qa(void) {
- COMM.println("Doing QA testing for most GPIO pins...");
- digitalWrite(BOARD_LED_PIN, 0);
- for(int i = 0; i<NR_GPIO_PINS; i++) {
+ bool all_pins_ok = true;
+ const int not_a_pin = -1;
+ SerialUSB.println("Doing QA testing for unused GPIO pins.");
+
+ for (int i = 0; i < BOARD_NR_GPIO_PINS; i++) {
+ if (boardUsesPin(i)) continue;
+
pinMode(i, INPUT);
- gpio_state[i] = 0;
}
- COMM.println("Waiting to start...");
- while(digitalRead(0) != 1 && !COMM.available()) {
- continue;
- }
- for(int i=0; i<38; i++) {
- if(i == BOARD_LED_PIN) {
- COMM.println("Not checking LED");
+
+ SerialUSB.println("Waiting to start.");
+ ASSERT(!boardUsesPin(0));
+ while (digitalRead(0) == LOW) continue;
+
+ for (int i = 0; i < BOARD_NR_GPIO_PINS; i++) {
+ if (boardUsesPin(i)) {
+ SerialUSB.print("Skipping pin ");
+ SerialUSB.println(i, DEC);
continue;
}
- COMM.print("Checking D");
- COMM.print(i,DEC);
- while(digitalRead(i) == 0) continue;
- for(int j=0; j<NR_GPIO_PINS; j++) {
- if(digitalRead(j) && j!=i) {
- COMM.print(": FAIL ########################### D");
- COMM.println(j, DEC);
- break;
- }
+ bool pin_ok = true;
+ SerialUSB.print("Checking pin ");
+ SerialUSB.print(i, DEC);
+ while (digitalRead(i) == LOW) continue;
+
+ pin_ok = pin_ok && test_single_pin_is_high(i, "is also HIGH");
+
+ if (!wait_for_low_transition(i)) {
+ SerialUSB.println("Transition to low timed out; something is "
+ "very wrong. Aborting test.");
+ return;
}
- while(digitalRead(i) == 1) continue;
- for(int j=0; j<NR_GPIO_PINS; j++) {
- if(digitalRead(j) && j!=i) {
- COMM.print(": FAIL ########################### D");
- COMM.println(j, DEC);
- break;
- }
+
+ pin_ok = pin_ok && test_single_pin_is_high(not_a_pin, "is still HIGH");
+
+ if (pin_ok) {
+ SerialUSB.println(": ok");
}
- COMM.println(": Ok!");
+
+ all_pins_ok = all_pins_ok && pin_ok;
+ }
+
+ if (all_pins_ok) {
+ SerialUSB.println("Finished; test passes.");
+ } else {
+ SerialUSB.println("**** TEST FAILS *****");
}
- for(int i = 0; i<NR_GPIO_PINS; i++) {
+
+ for (int i = 0; i < BOARD_NR_GPIO_PINS; i++) {
+ if (boardUsesPin(i)) continue;
+
pinMode(i, OUTPUT);
- digitalWrite(i, 0);
+ digitalWrite(i, LOW);
+ gpio_state[i] = 0;
}
}
-void cmd_sequential_gpio_writes(void) {
- COMM.print("Sequentially toggling all pins except D0, D1. ");
- COMM.println("Anything for next, ESC to stop.");
- digitalWrite(BOARD_LED_PIN, 0);
- // make sure to skip the TX/RX headers
- for(uint32 i = 2; i<NR_GPIO_PINS; i++) {
- COMM.print("GPIO write out on header D");
- COMM.print(i, DEC);
- COMM.println("...");
+void cmd_sequential_gpio_toggling(void) {
+ SerialUSB.println("Sequentially toggling all unused pins. "
+ "Press any key for next pin, ESC to stop.");
+
+ for (uint32 i = 0; i < BOARD_NR_GPIO_PINS; i++) {
+ if (boardUsesPin(i))
+ continue;
+
+ SerialUSB.print("Toggling pin ");
+ SerialUSB.print((int)i, DEC);
+ SerialUSB.println("...");
+
pinMode(i, OUTPUT);
do {
togglePin(i);
- } while(!COMM.available());
- digitalWrite(i, 0);
- if((uint8)COMM.read() == ESC) break;
+ } while (!SerialUSB.available());
+
+ digitalWrite(i, LOW);
+ if (SerialUSB.read() == ESC)
+ break;
}
}
void cmd_gpio_toggling(void) {
- COMM.println("Toggling all GPIOs simultaneously. Press any key.");
- digitalWrite(BOARD_LED_PIN, 0);
- // make sure to skip the TX/RX headers
- for(uint32 i = 2; i<NR_GPIO_PINS; i++) {
+ SerialUSB.println("Toggling all unused pins simultaneously. "
+ "Press any key to stop.");
+
+ for (uint32 i = 0; i < BOARD_NR_GPIO_PINS; i++) {
+ if (boardUsesPin(i))
+ continue;
pinMode(i, OUTPUT);
}
- while(!COMM.available()) {
- for(uint32 i = 2; i<NR_GPIO_PINS; i++) {
+
+ while (!SerialUSB.available()) {
+ for (uint32 i = 0; i < BOARD_NR_GPIO_PINS; i++) {
+ if (boardUsesPin(i))
+ continue;
togglePin(i);
}
}
- for(uint32 i = 2; i<NR_GPIO_PINS; i++) {
- digitalWrite(i, 0);
+
+ for (uint32 i = 0; i < BOARD_NR_GPIO_PINS; i++) {
+ if (boardUsesPin(i))
+ continue;
+ digitalWrite(i, LOW);
}
}
-void cmd_sequential_pwm_test(void) {
- COMM.println("Sequentially testing PWM on all possible headers "
- "except D0 and D1.");
- COMM.println("Press any key for next, ESC to stop.");
- digitalWrite(BOARD_LED_PIN, 0);
- // make sure to skip the TX/RX headers
- for(uint32 i = 2; i<sizeof(pwm_pins); i++) {
- COMM.print("PWM out on header D");
- COMM.print(pwm_pins[i], DEC);
- COMM.println("...");
- pinMode(pwm_pins[i], PWM);
- pwmWrite(pwm_pins[i], 16000);
- while(!COMM.available()) { delay(10); }
- pinMode(pwm_pins[i], OUTPUT);
- digitalWrite(pwm_pins[i], 0);
- if((uint8)COMM.read() == ESC) break;
- }
-}
-
-void cmd_pwm_sweep(void) {
- COMM.println("Testing all PWM ports with a sweep. Press any key.");
- digitalWrite(BOARD_LED_PIN, 0);
- // make sure to skip the TX/RX pins
- for(uint32 i = 2; i<sizeof(pwm_pins); i++) {
- pinMode(pwm_pins[i], PWM);
- pwmWrite(pwm_pins[i], 4000);
+uint8 debugGPIOPins[] = {BOARD_JTMS_SWDIO_PIN,
+ BOARD_JTCK_SWCLK_PIN,
+ BOARD_JTDI_PIN,
+ BOARD_JTDO_PIN,
+ BOARD_NJTRST_PIN};
+
+#define N_DEBUG_PINS 5
+
+void cmd_sequential_debug_gpio_toggling(void) {
+ SerialUSB.println("Toggling all debug (JTAG/SWD) pins sequentially. "
+ "This will permanently disable debug port "
+ "functionality.");
+ disableDebugPorts();
+
+ for (int i = 0; i < N_DEBUG_PINS; i++) {
+ pinMode(debugGPIOPins[i], OUTPUT);
}
- while(!COMM.available()) {
- rate += 20;
- if(rate > 65500) rate = 0;
- for(uint32 i = 2; i<sizeof(pwm_pins); i++) {
- pwmWrite(pwm_pins[i], rate);
+
+ for (int i = 0; i < N_DEBUG_PINS; i++) {
+ int pin = debugGPIOPins[i];
+ SerialUSB.print("Toggling pin ");
+ SerialUSB.print(pin, DEC);
+ SerialUSB.println("...");
+
+ pinMode(pin, OUTPUT);
+ do {
+ togglePin(pin);
+ } while (!SerialUSB.available());
+
+ digitalWrite(pin, LOW);
+ if (SerialUSB.read() == ESC)
+ break;
+ }
+
+ for (int i = 0; i < N_DEBUG_PINS; i++) {
+ digitalWrite(debugGPIOPins[i], 0);
+ }
+}
+
+void cmd_debug_gpio_toggling(void) {
+ SerialUSB.println("Toggling debug GPIO simultaneously. "
+ "This will permanently disable JTAG and Serial Wire "
+ "debug port functionality. "
+ "Press any key to stop.");
+ disableDebugPorts();
+
+ for (uint32 i = 0; i < N_DEBUG_PINS; i++) {
+ pinMode(debugGPIOPins[i], OUTPUT);
+ }
+
+ while (!SerialUSB.available()) {
+ for (uint32 i = 0; i < N_DEBUG_PINS; i++) {
+ togglePin(debugGPIOPins[i]);
}
- delay(1);
}
- for(uint32 i = 2; i<sizeof(pwm_pins); i++) {
- pinMode(pwm_pins[i], OUTPUT);
+
+ for (uint32 i = 0; i < N_DEBUG_PINS; i++) {
+ digitalWrite(debugGPIOPins[i], LOW);
+ }
+}
+
+void cmd_but_test(void) {
+ SerialUSB.println("Press the button to test. Press any key to stop.");
+ pinMode(BOARD_BUTTON_PIN, INPUT);
+
+ while (!SerialUSB.available()) {
+ if (isButtonPressed()) {
+ uint32 tstamp = millis();
+ SerialUSB.print("Button press detected, timestamp: ");
+ SerialUSB.println(tstamp);
+ }
+ }
+ SerialUSB.read();
+}
+
+void cmd_sequential_pwm_test(void) {
+ SerialUSB.println("Sequentially testing PWM on all unused pins. "
+ "Press any key for next pin, ESC to stop.");
+
+ for (uint32 i = 0; i < BOARD_NR_PWM_PINS; i++) {
+ if (boardUsesPin(i))
+ continue;
+
+ SerialUSB.print("PWM out on header D");
+ SerialUSB.print(boardPWMPins[i], DEC);
+ SerialUSB.println("...");
+ pinMode(boardPWMPins[i], PWM);
+ pwmWrite(boardPWMPins[i], 16000);
+
+ while (!SerialUSB.available()) {
+ delay(10);
+ }
+
+ pinMode(boardPWMPins[i], OUTPUT);
+ digitalWrite(boardPWMPins[i], 0);
+ if (SerialUSB.read() == ESC)
+ break;
}
}
void cmd_servo_sweep(void) {
- COMM.println("Testing all PWM headers with a servo sweep. Press any key.");
- COMM.println();
- digitalWrite(BOARD_LED_PIN, 0);
+ SerialUSB.println("Testing all PWM headers with a servo sweep. "
+ "Press any key to stop.");
+ SerialUSB.println();
+
+ disable_usarts();
init_all_timers(21);
- // make sure to skip the TX/RX headers
- for(uint32 i = 2; i<sizeof(pwm_pins); i++) {
- pinMode(pwm_pins[i], PWM);
- pwmWrite(pwm_pins[i], 4000);
+
+ for (uint32 i = 0; i < BOARD_NR_PWM_PINS; i++) {
+ if (boardUsesPin(i))
+ continue;
+ pinMode(boardPWMPins[i], PWM);
+ pwmWrite(boardPWMPins[i], 4000);
}
+
// 1.25ms = 4096counts = 0deg
// 1.50ms = 4915counts = 90deg
// 1.75ms = 5734counts = 180deg
- rate = 4096;
- while(!COMM.available()) {
+ int rate = 4096;
+ while (!SerialUSB.available()) {
rate += 20;
- if(rate > 5734) rate = 4096;
- for(uint32 i = 2; i<sizeof(pwm_pins); i++) {
- pwmWrite(pwm_pins[i], rate);
+ if (rate > 5734)
+ rate = 4096;
+ for (uint32 i = 0; i < BOARD_NR_PWM_PINS; i++) {
+ if (boardUsesPin(i))
+ continue;
+ pwmWrite(boardPWMPins[i], rate);
}
delay(20);
}
- for(uint32 i = 2; i<sizeof(pwm_pins); i++) {
- pinMode(pwm_pins[i], OUTPUT);
+
+ for (uint32 i = 0; i < BOARD_NR_PWM_PINS; i++) {
+ if (boardUsesPin(i))
+ continue;
+ pinMode(boardPWMPins[i], OUTPUT);
}
init_all_timers(1);
- Serial2.begin(9600);
- COMM.println("(reset serial port)");
+ enable_usarts();
+}
+
+void cmd_board_info(void) { // TODO print more information
+ SerialUSB.println("Board information");
+ SerialUSB.println("=================");
+
+ SerialUSB.print("* Clock speed (MHz): ");
+ SerialUSB.println(CYCLES_PER_MICROSECOND);
+
+ SerialUSB.print("* BOARD_LED_PIN: ");
+ SerialUSB.println(BOARD_LED_PIN);
+
+ SerialUSB.print("* BOARD_BUTTON_PIN: ");
+ SerialUSB.println(BOARD_BUTTON_PIN);
+
+ SerialUSB.print("* GPIO information (BOARD_NR_GPIO_PINS = ");
+ SerialUSB.print(BOARD_NR_GPIO_PINS);
+ SerialUSB.println("):");
+ print_board_array("ADC pins", boardADCPins, BOARD_NR_ADC_PINS);
+ print_board_array("PWM pins", boardPWMPins, BOARD_NR_PWM_PINS);
+ print_board_array("Used pins", boardUsedPins, BOARD_NR_USED_PINS);
+}
+
+// -- Helper functions --------------------------------------------------------
+
+void measure_adc_noise(uint8 pin) {
+ uint16 data[100];
+ float mean = 0;
+ float delta = 0;
+ float M2 = 0;
+ pinMode(pin, INPUT_ANALOG);
+
+ // Variance algorithm from Welford, via Knuth, by way of Wikipedia:
+ // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#On-line_algorithm
+ for (int i = 0; i < 100; i++) {
+ data[i] = analogRead(pin);
+ delta = data[i] - mean;
+ mean = mean + delta / (i + 1);
+ M2 = M2 + delta * (data[i] - mean);
+ }
+
+ SerialUSB.print("header: D");
+ SerialUSB.print(pin, DEC);
+ SerialUSB.print("\tn: ");
+ SerialUSB.print(100, DEC);
+ SerialUSB.print("\tmean: ");
+ SerialUSB.print(mean);
+ SerialUSB.print("\tvariance: ");
+ SerialUSB.println(M2 / 99.0);
+ pinMode(pin, OUTPUT);
+}
+
+void fast_gpio(int maple_pin) {
+ gpio_dev *dev = PIN_MAP[maple_pin].gpio_device;
+ uint32 bit = PIN_MAP[maple_pin].gpio_bit;
+
+ gpio_write_bit(dev, bit, 1);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+ gpio_toggle_bit(dev, bit);
+}
+
+void serial_baud_test(HardwareSerial **serials, int n, unsigned baud) {
+ for (int i = 0; i < n; i++) {
+ serials[i]->begin(baud);
+ }
+ while (!SerialUSB.available()) {
+ for (int i = 0; i < n; i++) {
+ serials[i]->println(dummy_data);
+ if (serials[i]->available()) {
+ serials[i]->println(serials[i]->read());
+ delay(1000);
+ }
+ }
+ }
+}
+
+void serial_echo_test(HardwareSerial *serial, unsigned baud) {
+ serial->begin(baud);
+ while (!SerialUSB.available()) {
+ if (!serial->available())
+ continue;
+ serial->print(serial->read());
+ }
+}
+
+static uint16 init_all_timers_prescale = 0;
+
+static void set_prescale(timer_dev *dev) {
+ timer_set_prescaler(dev, init_all_timers_prescale);
}
void init_all_timers(uint16 prescale) {
- timer_init(TIMER1, prescale);
- timer_init(TIMER2, prescale);
- timer_init(TIMER3, prescale);
-#if NR_TIMERS >= 4
- timer_init(TIMER4, prescale);
-#elif NR_TIMERS >= 8 // TODO test this on maple native
- timer_init(TIMER5, prescale);
- timer_init(TIMER6, prescale);
- timer_init(TIMER7, prescale);
- timer_init(TIMER8, prescale);
+ init_all_timers_prescale = prescale;
+ timer_foreach(set_prescale);
+}
+
+void enable_usarts(void) {
+ Serial1.begin(BAUD);
+ Serial2.begin(BAUD);
+ Serial3.begin(BAUD);
+#if defined(STM32_HIGH_DENSITY) && !defined(BOARD_maple_RET6)
+ Serial4.begin(BAUD);
+ Serial5.begin(BAUD);
#endif
}
+void disable_usarts(void) {
+ Serial1.end();
+ Serial2.end();
+ Serial3.end();
+#if defined(STM32_HIGH_DENSITY) && !defined(BOARD_maple_RET6)
+ Serial4.end();
+ Serial5.end();
+#endif
+}
+
+void print_board_array(const char* msg, const uint8 arr[], int len) {
+ SerialUSB.print("\t");
+ SerialUSB.print(msg);
+ SerialUSB.print(" (");
+ SerialUSB.print(len);
+ SerialUSB.print("): ");
+ for (int i = 0; i < len; i++) {
+ SerialUSB.print(arr[i], DEC);
+ if (i < len - 1) SerialUSB.print(", ");
+ }
+ SerialUSB.println();
+}
+
+// -- premain() and main() ----------------------------------------------------
// Force init to be called *first*, i.e. before static object allocation.
-// Otherwise, statically allocated object that need libmaple may fail.
-__attribute__(( constructor )) void premain() {
+// Otherwise, statically allocated objects that need libmaple may fail.
+__attribute__((constructor)) void premain() {
init();
}
-int main(void)
-{
+int main(void) {
setup();
while (1) {
diff --git a/examples/test-spi-roundtrip.cpp b/examples/test-spi-roundtrip.cpp
new file mode 100644
index 0000000..8fe97b9
--- /dev/null
+++ b/examples/test-spi-roundtrip.cpp
@@ -0,0 +1,194 @@
+/*
+ * Polling SPI loopback test.
+ *
+ * Bob is nowhere to be found, so Alice decides to talk to herself.
+ *
+ * Instructions: Connect SPI2 (Alice) to herself (i.e., MISO to MOSI).
+ * Connect to Alice via SerialUSB. Press any key to start.
+ *
+ * Alice will talk to herself for a little while. The sketch will
+ * report if Alice can't hear anything she says. She'll then start
+ * talking forever at various frequencies, bit orders, and modes. Use
+ * an oscilloscope to make sure she's not trying to lie about any of
+ * those things.
+ *
+ * This file is released into the public domain.
+ *
+ * Author: Marti Bolivar <mbolivar@leaflabs.com>
+ */
+
+#include "wirish.h"
+
+HardwareSPI alice(2);
+
+#define NFREQS 8
+const SPIFrequency spi_freqs[] = {
+ SPI_140_625KHZ,
+ SPI_281_250KHZ,
+ SPI_562_500KHZ,
+ SPI_1_125MHZ,
+ SPI_2_25MHZ,
+ SPI_4_5MHZ,
+ SPI_9MHZ,
+ SPI_18MHZ,
+};
+
+#define TEST_BUF_SIZE 10
+uint8 test_buf[TEST_BUF_SIZE] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+
+void bad_assert(const char* file, int line, const char* exp) {
+ SerialUSB.println();
+ SerialUSB.print("ERROR: FAILED ASSERT(");
+ SerialUSB.print(exp);
+ SerialUSB.print("): ");
+ SerialUSB.print(file);
+ SerialUSB.print(": ");
+ SerialUSB.println(line);
+ throb();
+}
+
+#undef ASSERT
+#define ASSERT(exp) \
+ if (exp) { \
+ } else { \
+ bad_assert(__FILE__, __LINE__, #exp); \
+ }
+
+void haveConversation(uint32 bitOrder);
+void soliloquies(uint32 bitOrder);
+
+void setup() {
+ pinMode(BOARD_LED_PIN, OUTPUT);
+ while (!SerialUSB.available())
+ ;
+ SerialUSB.read();
+}
+
+void loop() {
+ SerialUSB.println("** Having a conversation, MSB first");
+ haveConversation(MSBFIRST);
+
+ SerialUSB.println("** Having a conversation, LSB first");
+ haveConversation(LSBFIRST);
+
+ SerialUSB.println();
+ SerialUSB.println("*** All done! It looks like everything worked.");
+ SerialUSB.println();
+
+ SerialUSB.println("** Alice will now wax eloquent in various styles. "
+ "Press any key for the next configuration.");
+ soliloquies(MSBFIRST);
+ soliloquies(LSBFIRST);
+
+ while (true)
+ ;
+}
+
+void printFrequencyString(SPIFrequency frequency);
+void chat(SPIFrequency frequency, uint32 bitOrder, uint32 mode);
+
+void haveConversation(uint32 bitOrder) {
+ for (int f = 0; f < NFREQS; f++) {
+ for (int mode = 0; mode < 4; mode++) {
+ chat(spi_freqs[f], bitOrder, mode);
+ delay(10);
+ }
+ }
+}
+
+void chat(SPIFrequency frequency, uint32 bitOrder, uint32 mode) {
+ SerialUSB.print("Having a chat.\tFrequency: ");
+ printFrequencyString(frequency);
+ SerialUSB.print(",\tbitOrder: ");
+ SerialUSB.print(bitOrder == MSBFIRST ? "MSB" : "LSB");
+ SerialUSB.print(",\tmode: ");
+ SerialUSB.print(mode);
+ SerialUSB.print(".");
+
+ SerialUSB.print(" [1] ");
+ alice.begin(frequency, bitOrder, mode);
+
+ SerialUSB.print(" [2] ");
+ uint32 txed = 0;
+ while (txed < TEST_BUF_SIZE) {
+ ASSERT(alice.transfer(test_buf[txed]) == test_buf[txed]);
+ txed++;
+ }
+
+ SerialUSB.print(" [3] ");
+ alice.end();
+
+ SerialUSB.println(" ok.");
+}
+
+void soliloquy(SPIFrequency freq, uint32 bitOrder, uint32 mode);
+
+void soliloquies(uint32 bitOrder) {
+ for (int f = 0; f < NFREQS; f++) {
+ for (int mode = 0; mode < 4; mode++) {
+ soliloquy(spi_freqs[f], bitOrder, mode);
+ }
+ }
+}
+
+void soliloquy(SPIFrequency frequency, uint32 bitOrder, uint32 mode) {
+ const uint8 repeat = 0xAE;
+ SerialUSB.print("Alice is giving a soliloquy (repeating 0x");
+ SerialUSB.print(repeat, HEX);
+ SerialUSB.print("). Frequency: ");
+ printFrequencyString(frequency);
+ SerialUSB.print(", bitOrder: ");
+ SerialUSB.print(bitOrder == MSBFIRST ? "big-endian" : "little-endian");
+ SerialUSB.print(", SPI mode: ");
+ SerialUSB.println(mode);
+
+ alice.begin(frequency, bitOrder, mode);
+ while (!SerialUSB.available()) {
+ alice.write(repeat);
+ delayMicroseconds(200);
+ }
+ SerialUSB.read();
+}
+
+void printFrequencyString(SPIFrequency frequency) {
+ switch (frequency) {
+ case SPI_18MHZ:
+ SerialUSB.print("18 MHz");
+ break;
+ case SPI_9MHZ:
+ SerialUSB.print("9 MHz");
+ break;
+ case SPI_4_5MHZ:
+ SerialUSB.print("4.5 MHz");
+ break;
+ case SPI_2_25MHZ:
+ SerialUSB.print("2.25 MHZ");
+ break;
+ case SPI_1_125MHZ:
+ SerialUSB.print("1.125 MHz");
+ break;
+ case SPI_562_500KHZ:
+ SerialUSB.print("562.500 KHz");
+ break;
+ case SPI_281_250KHZ:
+ SerialUSB.print("281.250 KHz");
+ break;
+ case SPI_140_625KHZ:
+ SerialUSB.print("140.625 KHz");
+ break;
+ }
+}
+
+// Force init to be called *first*, i.e. before static object allocation.
+// Otherwise, statically allocated objects that need libmaple may fail.
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+ while (true) {
+ loop();
+ }
+ return 0;
+}
diff --git a/examples/test-systick.cpp b/examples/test-systick.cpp
index 247892d..78c7307 100644
--- a/examples/test-systick.cpp
+++ b/examples/test-systick.cpp
@@ -1,59 +1,48 @@
// Tests the SysTick enable/disable functions
-//
+
#include "wirish.h"
#include "systick.h"
-#define LED_PIN 13
-#define PWM_PIN 2
-#define BUT 38
-
-void setup()
-{
- /* Set up the LED to blink */
- pinMode(LED_PIN, OUTPUT);
-
- /* Turn on PWM on pin PWM_PIN */
- pinMode(PWM_PIN, PWM);
- pwmWrite(PWM_PIN, 0x8000);
-
- pinMode(BUT, INPUT_PULLDOWN);
+void setup() {
+ pinMode(BOARD_LED_PIN, OUTPUT);
+ pinMode(BOARD_BUTTON_PIN, INPUT);
}
-int toggle = 0;
+bool disable = true;
long time = 0;
void loop() {
- toggle ^= 1;
- digitalWrite(LED_PIN, toggle);
+ volatile int i = 0;
+ toggleLED();
// An artificial delay
- int16 i = 1;
- float j = 1;
- for(i=0; i<6553; i++) {
- j = sqrt(j) + 1;
- }
-
- if(digitalRead(BUT)) {
- systick_disable();
- } else {
- systick_resume();
+ for(i = 0; i < 150000; i++)
+ ;
+
+ if (isButtonPressed()) {
+ if (disable) {
+ systick_disable();
+ SerialUSB.println("Disabling SysTick");
+ } else {
+ SerialUSB.println("Re-enabling SysTick");
+ systick_enable();
+ }
+ disable = !disable;
}
- //SerialUSB.println(micros()); // there is a bug with this
SerialUSB.println(millis());
}
// Force init to be called *first*, i.e. before static object allocation.
// Otherwise, statically allocated object that need libmaple may fail.
- __attribute__(( constructor )) void premain() {
+__attribute__((constructor)) void premain() {
init();
}
-int main(void)
-{
+int main(void) {
setup();
- while (1) {
+ while (true) {
loop();
}
return 0;
diff --git a/examples/test-timers.cpp b/examples/test-timers.cpp
index ccba251..247cc57 100644
--- a/examples/test-timers.cpp
+++ b/examples/test-timers.cpp
@@ -1,8 +1,7 @@
-// Program to test the wirish timers implementation
+// Program to test the timer.h implementation's essential functionality.
#include "wirish.h"
-
-#define LED_PIN 13
+#include "timer.h"
void handler1(void);
void handler2(void);
@@ -12,7 +11,6 @@ void handler4(void);
void handler3b(void);
void handler4b(void);
-int toggle = 0;
int t;
int count1 = 0;
@@ -28,222 +26,271 @@ uint16 val2 = 10000;
uint16 val3 = 10000;
uint16 val4 = 10000;
-HardwareTimer Timers[] = {Timer1, Timer2, Timer3, Timer4};
+// 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);
-void setup()
-{
- /* Set up the LED to blink */
- pinMode(LED_PIN, OUTPUT);
+void setup() {
+ // Set up the LED to blink
+ pinMode(BOARD_LED_PIN, OUTPUT);
// Setup the button as input
- pinMode(38, INPUT_PULLUP);
-
- /* Send a message out USART2 */
- //SerialUSB.begin(9600);
- SerialUSB.println("Begining timer test...");
- for(int t=0; t<4; t++) {
- Timers[t].setChannel1Mode(TIMER_OUTPUTCOMPARE);
- Timers[t].setChannel2Mode(TIMER_OUTPUTCOMPARE);
- Timers[t].setChannel3Mode(TIMER_OUTPUTCOMPARE);
- Timers[t].setChannel4Mode(TIMER_OUTPUTCOMPARE);
- }
-
- // Wait for user to attach...
- delay(2000);
+ pinMode(BOARD_BUTTON_PIN, INPUT);
+
+ // Send a message out Serial2
+ Serial2.begin(115200);
+ Serial2.println("*** Initializing timers...");
+ timer_foreach(initTimer);
+ Serial2.println("*** Done. Beginning timer test.");
}
void loop() {
- SerialUSB.println("-----------------------------------------------------");
- SerialUSB.println("Testing setCount/getCount");
- SerialUSB.print("Timer1.getCount() = "); SerialUSB.println(Timer1.getCount());
- SerialUSB.println("Timer1.setCount(1234)");
- Timer1.setCount(1234);
- SerialUSB.print("Timer1.getCount() = "); SerialUSB.println(Timer1.getCount());
- // This tests whether the pause/resume functions work; 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
- SerialUSB.println("-----------------------------------------------------");
- SerialUSB.println("Testing Pause/Resume; button roughly controls Timer4");
+ 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;
- Timer3.setChannel1Mode(TIMER_OUTPUTCOMPARE);
- Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE);
- Timer3.pause();
- Timer4.pause();
- Timer3.setCount(0);
- Timer4.setCount(0);
- Timer3.setOverflow(30000);
- Timer4.setOverflow(30000);
- Timer3.setCompare1(1000);
- Timer4.setCompare1(1000);
- Timer3.attachCompare1Interrupt(handler3b);
- Timer4.attachCompare1Interrupt(handler4b);
- Timer3.resume();
- Timer4.resume();
- SerialUSB.println("~4 seconds...");
- for(int i = 0; i<4000; i++) {
- if(digitalRead(38)) {
- Timer4.pause();
+ 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 {
- Timer4.resume();
+ timer_resume(TIMER4);
}
delay(1);
}
- Timer3.setChannel1Mode(TIMER_DISABLED);
- Timer4.setChannel1Mode(TIMER_DISABLED);
- SerialUSB.print("Count3: "); SerialUSB.println(count3);
- SerialUSB.print("Count4: "); SerialUSB.println(count4);
-
- // These test the setPeriod auto-configure functionality
- SerialUSB.println("-----------------------------------------------------");
- SerialUSB.println("Testing setPeriod");
- Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE);
- Timer4.setCompare1(1);
- Timer4.setPeriod(10);
- Timer4.pause();
- Timer4.setCount(0);
- Timer4.attachCompare1Interrupt(handler4b);
- SerialUSB.println("Period 10ms, wait 2 seconds...");
- count4 = 0;
- Timer4.resume();
- delay(2000);
- Timer4.pause();
- Timer4.setChannel1Mode(TIMER_DISABLED);
- SerialUSB.print("Count4: "); SerialUSB.println(count4);
- SerialUSB.println("(should be around 2sec/10ms = 200000)");
- Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE);
- Timer4.setCompare1(1);
- Timer4.pause();
- Timer4.setPeriod(30000);
- Timer4.setCount(0);
- Timer4.attachCompare1Interrupt(handler4b);
- SerialUSB.println("Period 30000ms, wait 2 seconds...");
- count4 = 0;
- Timer4.resume();
- delay(2000);
- Timer4.pause();
- Timer4.setChannel1Mode(TIMER_DISABLED);
- SerialUSB.print("Count4: "); SerialUSB.println(count4);
- SerialUSB.println("(should be around 2sec/30000ms ~ 67)");
-
- Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE);
- Timer4.setPeriod(300000);
- Timer4.setCompare1(1);
- Timer4.pause();
- Timer4.setCount(0);
- Timer4.attachCompare1Interrupt(handler4b);
- SerialUSB.println("Period 300000ms, wait 2 seconds...");
- count4 = 0;
- Timer4.resume();
- delay(2000);
- Timer4.pause();
- Timer4.setChannel1Mode(TIMER_DISABLED);
- SerialUSB.print("Count4: "); SerialUSB.println(count4);
- SerialUSB.println("(should be around 2sec/300000ms ~ 6.7)");
-
- Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE);
- Timer4.setPrescaleFactor(33);
- Timer4.setOverflow(65454);
- Timer4.pause();
- Timer4.setCount(0);
- Timer4.setCompare1(1);
- Timer4.attachCompare1Interrupt(handler4b);
- SerialUSB.println("Period 30000ms, wait 2 seconds...");
+
+ 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;
- Timer4.resume();
+ timer_resume(TIMER4);
delay(2000);
- Timer4.pause();
- Timer4.setChannel1Mode(TIMER_DISABLED);
- SerialUSB.print("Count4: "); SerialUSB.println(count4);
- SerialUSB.println("(should be around 2sec/30000ms ~ 67)");
-
- Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE);
- Timer4.setCompare1(1);
- Timer4.setPeriod(30000);
- Timer4.pause();
- Timer4.setCount(0);
- Timer4.attachCompare1Interrupt(handler4b);
- SerialUSB.println("Period 30000ms, wait 2 seconds...");
+ 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);
+}
+
+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;
+ }
+}
+
+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;
- Timer4.resume();
+ timer_resume(TIMER4);
delay(2000);
- Timer4.pause();
- Timer4.setChannel1Mode(TIMER_DISABLED);
- SerialUSB.print("Count4: "); SerialUSB.println(count4);
- SerialUSB.println("(should be around 2sec/30000ms ~ 67)");
-
- // This section is to touch every channel of every timer. The output
- // ratios should reflect the ratios of the rate variables. Demonstrates
- // that over time the actual timing rates get blown away by other system
- // interrupts.
- for(t=0; t<4; t++) {
- toggle ^= 1; digitalWrite(LED_PIN, toggle);
- delay(100);
- SerialUSB.println("-----------------------------------------------------");
- SerialUSB.print("Testing Timer "); SerialUSB.println(t+1);
+ 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)");
+}
+
+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;
+ }
+}
+
+/* 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("-----------------------------------------------------");
+ switch (dev->type) {
+ case TIMER_BASIC:
+ Serial2.print("NOT testing channels for basic timer ");
+ Serial2.println(t);
+ break;
+ case TIMER_ADVANCED:
+ case TIMER_GENERAL:
+ Serial2.print("Testing channels for timer ");
+ Serial2.println(t);
+ timer_pause(dev);
count1 = count2 = count3 = count4 = 0;
- Timers[t].setOverflow(0xFFFF);
- Timers[t].setPrescaleFactor(1);
- Timers[t].setCompare1(65535);
- Timers[t].setCompare2(65535);
- Timers[t].setCompare3(65535);
- Timers[t].setCompare4(65535);
- Timers[t].setChannel1Mode(TIMER_OUTPUTCOMPARE);
- Timers[t].setChannel2Mode(TIMER_OUTPUTCOMPARE);
- Timers[t].setChannel3Mode(TIMER_OUTPUTCOMPARE);
- Timers[t].setChannel4Mode(TIMER_OUTPUTCOMPARE);
- Timers[t].attachCompare1Interrupt(handler1);
- Timers[t].attachCompare2Interrupt(handler2);
- Timers[t].attachCompare3Interrupt(handler3);
- Timers[t].attachCompare4Interrupt(handler4);
- Timers[t].resume();
+ 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]);
+ }
+ timer_resume(dev);
delay(3000);
- Timers[t].setChannel1Mode(TIMER_DISABLED);
- Timers[t].setChannel2Mode(TIMER_DISABLED);
- Timers[t].setChannel3Mode(TIMER_DISABLED);
- Timers[t].setChannel4Mode(TIMER_DISABLED);
- SerialUSB.print("Count1: "); SerialUSB.println(count1);
- SerialUSB.print("Count2: "); SerialUSB.println(count2);
- SerialUSB.print("Count3: "); SerialUSB.println(count3);
- SerialUSB.print("Count4: "); SerialUSB.println(count4);
+ for (int c = 1; c <= 4; 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;
}
+ 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);
}
void handler1(void) {
val1 += rate1;
- Timers[t].setCompare1(val1);
+ timer_set_compare(timers[t], TIMER_CH1, val1);
count1++;
-}
+}
+
void handler2(void) {
val2 += rate2;
- Timers[t].setCompare2(val2);
+ timer_set_compare(timers[t], TIMER_CH2, val2);
count2++;
-}
+}
+
void handler3(void) {
val3 += rate3;
- Timers[t].setCompare3(val3);
+ timer_set_compare(timers[t], TIMER_CH3, val3);
count3++;
-}
+}
+
void handler4(void) {
val4 += rate4;
- Timers[t].setCompare4(val4);
+ timer_set_compare(timers[t], TIMER_CH4, val4);
count4++;
-}
+}
void handler3b(void) {
count3++;
-}
+}
+
void handler4b(void) {
count4++;
-}
+}
+__attribute__((constructor)) void premain() {
+ init();
+}
int main(void) {
- init();
setup();
- while (1) {
+ while (true) {
loop();
}
return 0;
diff --git a/examples/test-usart-dma.cpp b/examples/test-usart-dma.cpp
new file mode 100644
index 0000000..b9c03f1
--- /dev/null
+++ b/examples/test-usart-dma.cpp
@@ -0,0 +1,127 @@
+/**
+ * @file test-usart-dma.cpp
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ *
+ * Simple test of DMA used with a USART receiver.
+ *
+ * Configures a USART receiver for use with DMA. Received bytes are
+ * placed into a buffer, with an interrupt firing when the buffer is
+ * full. At that point, the USART transmitter will print the contents
+ * of the byte buffer. The buffer is continually filled and refilled
+ * in this manner.
+ *
+ * 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.
+ *
+ * This code is released into the public domain.
+ */
+
+#include "dma.h"
+#include "usart.h"
+#include "gpio.h"
+
+#include "wirish.h"
+
+#define BAUD 9600
+
+#define USART USART2
+#define USART_HWSER 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
+
+#define BUF_SIZE 8
+uint8 rx_buf[BUF_SIZE];
+
+dma_irq_cause irq_cause;
+
+__io uint32 irq_fired = 0;
+
+void init_usart(void);
+void init_dma_xfer(void);
+void rx_dma_irq(void);
+
+void setup(void) {
+ pinMode(BOARD_LED_PIN, OUTPUT);
+
+ init_dma_xfer();
+ init_usart();
+}
+
+void loop(void) {
+ toggleLED();
+ delay(100);
+
+ dma_channel_reg_map *ch_regs = dma_channel_regs(USART_DMA_DEV,
+ USART_RX_DMA_CHANNEL);
+ if (irq_fired) {
+ USART_HWSER.println("** IRQ **");
+ while (true)
+ ;
+ }
+ 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((int32)isr_bits, HEX);
+ USART_HWSER.print("\tCCR: 0x");
+ USART_HWSER.print((int64)ch_regs->CCR, HEX);
+ USART_HWSER.print("\tCNDTR: 0x");
+ USART_HWSER.print((int64)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();
+ if (isr_bits == 0x7) {
+ USART_HWSER.println("** Clearing ISR bits.");
+ dma_clear_isr_bits(USART_DMA_DEV, USART_RX_DMA_CHANNEL);
+ }
+
+ irq_fired = 0;
+}
+
+/* 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);
+ // Currently not working:
+ // 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) {
+}
+
+// Force init to be called *first*, i.e. before static object allocation.
+// Otherwise, statically allocated objects that need libmaple may fail.
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ setup();
+
+ while (true) {
+ loop();
+ }
+ return 0;
+}
diff --git a/examples/vga-leaf.cpp b/examples/vga-leaf.cpp
index d1c6d7d..f31dc87 100644
--- a/examples/vga-leaf.cpp
+++ b/examples/vga-leaf.cpp
@@ -1,21 +1,21 @@
/*
- Crude VGA Output
+ VGA Output
- Outputs a red and white leaf to VGA. This implementation is crude and noisy,
- but a fun demo. It should run most VGA monitors at 640x480, though it does
- not follow the timing spec very carefully. Real twisted or shielded wires,
- proper grounding, and not doing this on a breadboard are recommended (but
- it seems to work ok without).
+ Outputs a red and white leaf to VGA. It should run most VGA monitors
+ at 640x480, though it does not follow the timing spec very
+ carefully. Real twisted or shielded wires, proper grounding, and not
+ doing this on a breadboard are recommended (but it seems to work ok
+ without).
- SerialUSB is disabled to get rid of most interrupts (which mess with timing);
- the SysTick is probably the source of the remaining flickers. This means that
- you have to use perpetual bootloader or the reset button to flash new
- programs.
+ SerialUSB and SysTick are disabled to get rid of the most frequently
+ occurring interrupts (which mess with timing). This means that you
+ have to use perpetual bootloader mode or the reset button to flash
+ new programs.
How to wire this to a VGA port:
- D5 via ~200ohms to VGA Red (1)
- D6 via ~200ohms to VGA Green (2)
- D7 via ~200ohms to VGA Blue (3)
+ D6 via ~200ohms to VGA Red (1)
+ D7 via ~200ohms to VGA Green (2)
+ D8 via ~200ohms to VGA Blue (3)
D11 to VGA VSync (14) (swapped?)
D12 to VGA HSync (13) (swapped?)
GND to VGA Ground (5)
@@ -24,48 +24,65 @@
See also:
- http://pinouts.ru/Video/VGA15_pinout.shtml
- http://www.epanorama.net/documents/pc/vga_timing.html
-
+
Created 20 July 2010
By Bryan Newbold for LeafLabs
This code is released with no strings attached.
-
*/
-#include "wirish.h"
+// FIXME: generalize for Native and Mini
-#define LED_PIN 13
+#include "wirish.h"
-// Pinouts
-#define VGA_R 5 // STM32: B6
-#define VGA_G 6 // STM32: A8
-#define VGA_B 7 // STM32: A9
+// Pinouts -- you also must change the GPIO macros below if you change
+// these
+#define VGA_R 6 // STM32: A8
+#define VGA_G 7 // STM32: A9
+#define VGA_B 8 // STM32: A10
#define VGA_V 11 // STM32: A6
#define VGA_H 12 // STM32: A7
-// These low level macros make GPIO writes much faster
-#define VGA_R_HIGH (GPIOB_BASE)->BSRR = BIT(6)
-#define VGA_R_LOW (GPIOB_BASE)->BRR = BIT(6)
-#define VGA_G_HIGH (GPIOA_BASE)->BSRR = BIT(8)
-#define VGA_G_LOW (GPIOA_BASE)->BRR = BIT(8)
-#define VGA_B_HIGH (GPIOA_BASE)->BSRR = BIT(9)
-#define VGA_B_LOW (GPIOA_BASE)->BRR = BIT(9)
-#define VGA_V_HIGH (GPIOA_BASE)->BSRR = BIT(6)
-#define VGA_V_LOW (GPIOA_BASE)->BRR = BIT(6)
-#define VGA_H_HIGH (GPIOA_BASE)->BSRR = BIT(7)
-#define VGA_H_LOW (GPIOA_BASE)->BRR = BIT(7)
+// These low level (and STM32 specific) macros make GPIO writes much
+// faster
+#define ABSRR ((volatile uint32*)0x40010810)
+#define ABRR ((volatile uint32*)0x40010814)
+
+#define RBIT 8 // (see pinouts)
+#define GBIT 9
+#define BBIT 10
+
+#define VGA_R_HIGH *ABSRR = BIT(RBIT)
+#define VGA_R_LOW *ABRR = BIT(RBIT)
+#define VGA_G_HIGH *ABSRR = BIT(GBIT)
+#define VGA_G_LOW *ABRR = BIT(GBIT)
+#define VGA_B_HIGH *ABSRR = BIT(BBIT)
+#define VGA_B_LOW *ABRR = BIT(BBIT)
+
+#define ON_COLOR BIT(RBIT)
+#define OFF_COLOR (BIT(RBIT) | BIT(GBIT) | BIT(BBIT))
+
+// set has priority, so clear every bit and set some given bits:
+#define VGA_COLOR(c) (*ABSRR = c | \
+ BIT(RBIT+16) | BIT(GBIT+16) | BIT(BBIT+16))
+
+#define VGA_V_HIGH *ABSRR = BIT(6)
+#define VGA_V_LOW *ABRR = BIT(6)
+#define VGA_H_HIGH *ABSRR = BIT(7)
+#define VGA_H_LOW *ABRR = BIT(7)
void isr_porch(void);
void isr_start(void);
void isr_stop(void);
void isr_update(void);
-uint8 toggle;
uint16 x = 0; // X coordinate
uint16 y = 0; // Y coordinate
-uint8 v_active = 1; // Are we in the image?
+uint16 logo_y = 0; // Y coordinate, mapped into valid logo index (for speed)
+bool v_active = true; // Are we in the image?
-// 1-bit!
-uint8 logo[18][16] = {
+const uint8 x_max = 16;
+const uint8 y_max = 18;
+uint32 logo[y_max][x_max] = {
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
{0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,},
{0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,},
@@ -85,9 +102,11 @@ uint8 logo[18][16] = {
{0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, };
+HardwareTimer timer(4);
+
void setup() {
// Setup our pins
- pinMode(LED_PIN, OUTPUT);
+ pinMode(BOARD_LED_PIN, OUTPUT);
pinMode(VGA_R, OUTPUT);
pinMode(VGA_G, OUTPUT);
pinMode(VGA_B, OUTPUT);
@@ -99,91 +118,108 @@ void setup() {
digitalWrite(VGA_H, HIGH);
digitalWrite(VGA_V, HIGH);
+ // Fill the logo array with color patterns corresponding to its
+ // truth value. Note that we could get more tricky here, since
+ // there are 3 bits of color.
+ for (int y = 0; y < y_max; y++) {
+ for (int x = 0; x < x_max; x++) {
+ logo[y][x] = logo[y][x] ? ON_COLOR : OFF_COLOR;
+ }
+ }
+
// This gets rid of the majority of the interrupt artifacts;
+ // there's still a glitch for low values of y, but let's not worry
+ // about that. (Probably due to the hackish way vsync is done).
SerialUSB.end();
- SystemTick.end();
+ systick_disable();
// Configure
- Timer4.pause(); // while we configure
- Timer4.setPrescaleFactor(1); // Full speed
- Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE);
- Timer4.setChannel2Mode(TIMER_OUTPUTCOMPARE);
- Timer4.setChannel3Mode(TIMER_OUTPUTCOMPARE);
- Timer4.setChannel4Mode(TIMER_OUTPUTCOMPARE);
- Timer4.setOverflow(2287); // Total line time
-
- Timer4.setCompare1(200);
- Timer4.attachCompare1Interrupt(isr_porch);
- Timer4.setCompare2(300);
- Timer4.attachCompare2Interrupt(isr_start);
- Timer4.setCompare3(2170);
- Timer4.attachCompare3Interrupt(isr_stop);
- Timer4.setCompare4(1); // Could be zero I guess
- Timer4.attachCompare4Interrupt(isr_update);
-
- Timer4.setCount(0); // Ready...
- Timer4.resume(); // Go!
+ timer.pause(); // while we configure
+ timer.setPrescaleFactor(1); // Full speed
+ timer.setMode(TIMER_CH1, TIMER_OUTPUT_COMPARE);
+ timer.setMode(TIMER_CH2, TIMER_OUTPUT_COMPARE);
+ timer.setMode(TIMER_CH3, TIMER_OUTPUT_COMPARE);
+ timer.setMode(TIMER_CH4, TIMER_OUTPUT_COMPARE);
+ timer.setOverflow(2287); // Total line time
+
+ timer.setCompare(TIMER_CH1, 200);
+ timer.attachInterrupt(TIMER_CH1, isr_porch);
+ timer.setCompare(TIMER_CH2, 300);
+ timer.attachInterrupt(TIMER_CH2, isr_start);
+ timer.setCompare(TIMER_CH3, 2170);
+ timer.attachInterrupt(TIMER_CH3, isr_stop);
+ timer.setCompare(TIMER_CH4, 1); // Could be zero, I guess
+ timer.attachInterrupt(TIMER_CH4, isr_update);
+
+ timer.setCount(0); // Ready...
+ timer.resume(); // Go!
}
void loop() {
- toggle ^= 1;
- digitalWrite(LED_PIN, toggle);
+ toggleLED();
delay(100);
// Everything happens in the interrupts!
}
-
// This ISR will end horizontal sync for most of the image and
// setup the vertical sync for higher line counts
void isr_porch(void) {
VGA_H_HIGH;
y++;
+ logo_y = map(y, 0, 478, 0, y_max);
// Back to the top
- if(y>=523) {
- y=1;
- v_active = 1;
+ if (y >= 523) {
+ y = 1;
+ logo_y = 0;
+ v_active = true;
return;
}
// Other vsync stuff below the image
- if(y>=492) {
+ if (y >= 492) {
VGA_V_HIGH;
return;
}
- if(y>=490) {
+ if (y >= 490) {
VGA_V_LOW;
return;
}
- if(y>=479) {
- v_active = 0;
+ if (y >= 479) {
+ v_active = false;
return;
}
}
// This is the main horizontal sweep
-void isr_start(void) {
+void isr_start(void) {
// Skip if we're not in the image at all
- if(!v_active) { return; }
+ if (!v_active) {
+ return;
+ }
// Start Red
VGA_R_LOW;
VGA_R_HIGH;
- // For each "pixel" (really 20 or so screen pixels?) go red or white
- for(x=0; x<32; x++) {
- if(logo[y/28][x/2]) {
- VGA_G_HIGH;
- VGA_B_HIGH;
- } else {
- VGA_G_LOW;
- VGA_B_LOW;
- }
+ // For each "pixel", go ON_COLOR or OFF_COLOR
+ for (x = 0; x < 16; x++) {
+ // setting the color several times is just an easy way to
+ // delay, so the image is wider. if you only do the following
+ // once, you'll be able to make the logo array bigger:
+ VGA_COLOR(logo[logo_y][x]);
+ VGA_COLOR(logo[logo_y][x]);
+ VGA_COLOR(logo[logo_y][x]);
+ VGA_COLOR(logo[logo_y][x]);
+ VGA_COLOR(logo[logo_y][x]);
+ VGA_COLOR(logo[logo_y][x]);
}
}
// End of the horizontal line
void isr_stop(void) {
- if(!v_active) { return; }
+ if (!v_active) {
+ return;
+ }
VGA_R_LOW;
VGA_G_LOW;
VGA_B_LOW;
@@ -194,11 +230,14 @@ void isr_update(void) {
VGA_H_LOW;
}
-int main(void) {
+__attribute__((constructor)) void premain() {
init();
+}
+
+int main(void) {
setup();
- while (1) {
+ while (true) {
loop();
}
return 0;
diff --git a/examples/vga-scope.cpp b/examples/vga-scope.cpp
index 0265f9c..b5fa8a5 100644
--- a/examples/vga-scope.cpp
+++ b/examples/vga-scope.cpp
@@ -1,144 +1,204 @@
-// Low-level, non-wirish demonstration of VGA
-//
-// Connect a microphone or something less to ANALOG_PIN
+/*
+ VGA Oscilloscope demo.
+
+ Connect a microphone or something like it to ANALOG_PIN (0V -- 3.3V
+ only; 0.2V -- 3.1V will probably look nicer); an attached VGA
+ monitor will display the signal roughly in real-time.
+
+ The thick blue line corresponds roughly to 0V.
+
+ This is a fairy crude hack, but it's fun to watch/toy around with.
+
+ SerialUSB and SysTick are disabled to get rid of the most frequently
+ occurring interrupts (which mess with timing). This means that you
+ have to use perpetual bootloader mode or the reset button to flash
+ new programs.
+
+ How to wire this to a VGA port:
+ D6 via ~200ohms to VGA Red (1)
+ D7 via ~200ohms to VGA Green (2)
+ D8 via ~200ohms to VGA Blue (3)
+ D11 to VGA VSync (14) (swapped?)
+ D12 to VGA HSync (13) (swapped?)
+ GND to VGA Ground (5)
+ GND to VGA Sync Ground (10)
+
+ See also:
+ - http://pinouts.ru/Video/VGA15_pinout.shtml
+ - http://www.epanorama.net/documents/pc/vga_timing.html
+
+ This code is released into the public domain.
+
+ Authors:
+
+ Bryan Newbold <bnewbold@leaflabs.com>
+ Marti Bolivar <mbolivar@leaflabs.com>
+ */
#include "wirish.h"
+#include "systick.h"
+
+// FIXME: generalize for Native and Mini
-#define LED_PIN 13
#define ANALOG_PIN 18
-#define VGA_R 5 // B6
-#define VGA_G 6 // A8
-#define VGA_B 7 // A9
-#define VGA_V 11 // A6
-#define VGA_H 12 // A7
-#define VGA_R_HIGH (GPIOB_BASE)->BSRR = BIT(6)
-#define VGA_R_LOW (GPIOB_BASE)->BRR = BIT(6)
-#define VGA_G_HIGH (GPIOA_BASE)->BSRR = BIT(8)
-#define VGA_G_LOW (GPIOA_BASE)->BRR = BIT(8)
-#define VGA_B_HIGH (GPIOA_BASE)->BSRR = BIT(9)
-#define VGA_B_LOW (GPIOA_BASE)->BRR = BIT(9)
-#define VGA_V_HIGH (GPIOA_BASE)->BSRR = BIT(6)
-#define VGA_V_LOW (GPIOA_BASE)->BRR = BIT(6)
-#define VGA_H_HIGH (GPIOA_BASE)->BSRR = BIT(7)
-#define VGA_H_LOW (GPIOA_BASE)->BRR = BIT(7)
+
+// Pinouts -- you also must change the GPIO macros below if you change
+// these
+#define VGA_R 6 // STM32: A8
+#define VGA_G 7 // STM32: A9
+#define VGA_B 8 // STM32: A10
+#define VGA_V 11 // STM32: A6
+#define VGA_H 12 // STM32: A7
+
+// These low level (and STM32 specific) macros make GPIO writes much
+// faster
+#define ABSRR ((volatile uint32*)0x40010810)
+#define ABRR ((volatile uint32*)0x40010814)
+
+#define RBIT 8 // (see pinouts)
+#define GBIT 9
+#define BBIT 10
+
+#define VGA_R_HIGH *ABSRR = BIT(RBIT)
+#define VGA_R_LOW *ABRR = BIT(RBIT)
+#define VGA_G_HIGH *ABSRR = BIT(GBIT)
+#define VGA_G_LOW *ABRR = BIT(GBIT)
+#define VGA_B_HIGH *ABSRR = BIT(BBIT)
+#define VGA_B_LOW *ABRR = BIT(BBIT)
+
+#define COLOR_WHITE (BIT(RBIT) | BIT(GBIT) | BIT(BBIT))
+#define COLOR_BLACK 0
+#define COLOR_RED BIT(RBIT)
+#define COLOR_GREEN BIT(GBIT)
+#define COLOR_BLUE BIT(BBIT)
+
+#define BORDER_COLOR COLOR_BLUE
+
+// set has priority, so clear every bit and set some given bits:
+#define VGA_COLOR(c) (*ABSRR = c | \
+ BIT(RBIT + 16) | BIT(GBIT + 16) | BIT(BBIT + 16))
+
+#define VGA_V_HIGH *ABSRR = BIT(6)
+#define VGA_V_LOW *ABRR = BIT(6)
+#define VGA_H_HIGH *ABSRR = BIT(7)
+#define VGA_H_LOW *ABRR = BIT(7)
void isr_porch(void);
void isr_start(void);
void isr_stop(void);
void isr_update(void);
-void setup()
-{
- pinMode(LED_PIN, OUTPUT);
+void setup() {
+ pinMode(BOARD_LED_PIN, OUTPUT);
pinMode(ANALOG_PIN, INPUT_ANALOG);
- digitalWrite(LED_PIN, 1);
+ digitalWrite(BOARD_LED_PIN, 1);
pinMode(VGA_R, OUTPUT);
pinMode(VGA_G, OUTPUT);
pinMode(VGA_B, OUTPUT);
pinMode(VGA_V, OUTPUT);
pinMode(VGA_H, OUTPUT);
- /* Send a message out USART2 */
+ // Send a message out USART2
Serial2.begin(9600);
- Serial2.println("Video time...");
+ Serial2.println("Time to kill the radio star...");
// This gets rid of the majority of the interrupt artifacts;
- // a SysTick.end() is required as well
+ // there's still a glitch for low values of y, but let's not worry
+ // about that. (Probably due to the hackish way vsync is done).
SerialUSB.end();
-
+ systick_disable();
+
digitalWrite(VGA_R, 0);
digitalWrite(VGA_G, 0);
digitalWrite(VGA_B, 0);
- digitalWrite(VGA_H,1);
- digitalWrite(VGA_V,1);
-
- timer_set_prescaler(4,0);
- timer_set_mode(4, 1, TIMER_OUTPUTCOMPARE);
- timer_set_mode(4, 2, TIMER_OUTPUTCOMPARE);
- timer_set_mode(4, 3, TIMER_OUTPUTCOMPARE);
- timer_set_mode(4, 4, TIMER_OUTPUTCOMPARE);
- timer_set_reload(4, 2287);
- timer_set_compare_value(4,1,200);
- timer_set_compare_value(4,2,300);
- timer_set_compare_value(4,3,2170); // 2219 max...
- timer_set_compare_value(4,4,1);
- timer_attach_interrupt(4,1,isr_porch);
- timer_attach_interrupt(4,2,isr_start);
- timer_attach_interrupt(4,3,isr_stop);
- timer_attach_interrupt(4,4,isr_update);
-
- timer_set_count(4,0);
+ digitalWrite(VGA_H, 1);
+ digitalWrite(VGA_V, 1);
+
+ timer_pause(TIMER4);
+ timer_set_prescaler(TIMER4, 0);
+ timer_set_mode(TIMER4, 1, TIMER_OUTPUT_COMPARE);
+ timer_set_mode(TIMER4, 2, TIMER_OUTPUT_COMPARE);
+ timer_set_mode(TIMER4, 3, TIMER_OUTPUT_COMPARE);
+ timer_set_mode(TIMER4, 4, TIMER_OUTPUT_COMPARE);
+ timer_set_reload(TIMER4, 2287);
+ timer_set_compare(TIMER4, 1, 200);
+ timer_set_compare(TIMER4, 2, 250);
+ timer_set_compare(TIMER4, 3, 2170); // 2219 max...
+ timer_set_compare(TIMER4, 4, 1);
+ timer_attach_interrupt(TIMER4, 1, isr_porch);
+ timer_attach_interrupt(TIMER4, 2, isr_start);
+ timer_attach_interrupt(TIMER4, 3, isr_stop);
+ timer_attach_interrupt(TIMER4, 4, isr_update);
+
+ timer_set_count(TIMER4, 0);
+ timer_resume(TIMER4);
}
-int toggle = 0;
-uint16 x = 0;
uint16 y = 0;
uint16 val = 0;
-uint8 v_active = 1;
-GPIO_Port *portb = GPIOB_BASE;
+bool v_active = true;
+const uint16 x_max = 60; // empirically (and sloppily) determined
void isr_porch(void) {
VGA_H_HIGH;
y++;
- if(y>=523) {
- y=1;
- v_active = 1;
+ val = map(analogRead(ANALOG_PIN), 0, 4095, 0, x_max);
+ if (y >= 523) {
+ y = 1;
+ v_active = true;
return;
}
- if(y>=492) {
+ if (y >= 492) {
VGA_V_HIGH;
return;
}
- if(y>=490) {
+ if (y >= 490) {
VGA_V_LOW;
return;
}
- if(y>=479) { // 479
- v_active = 0;
+ if (y >= 479) {
+ v_active = false;
return;
}
}
void isr_start(void) {
- if(!v_active) { return; }
- VGA_R_HIGH;
- VGA_R_HIGH;
- VGA_R_HIGH;
- VGA_R_LOW;
- //delayMicroseconds(2);
- //gpio_write_bit(GPIOA_BASE, 8, 1); // VGA_G
- for(x=0; x<(val>>6); x++) {
- }
- VGA_B_HIGH;
- VGA_G_HIGH;
- VGA_G_LOW;
- VGA_B_LOW;
- //VGA_R_HIGH;
- //val = (val + analogRead(ANALOG_PIN))/2;
- val = analogRead(ANALOG_PIN);
-
+ if (!v_active) {
+ return;
+ }
+ VGA_COLOR(BORDER_COLOR);
+ for (int x = 0; x < val; x++) {
+ VGA_COLOR(COLOR_BLACK);
+ }
+ VGA_COLOR(COLOR_WHITE);
+ VGA_COLOR(COLOR_BLACK);
}
+
void isr_stop(void) {
- if(!v_active) { return; }
- VGA_R_LOW;
- VGA_G_LOW;
- VGA_B_LOW;
+ if (!v_active) {
+ return;
+ }
+ VGA_COLOR(COLOR_BLACK);
}
+
void isr_update(void) {
VGA_H_LOW;
}
void loop() {
- //val = analogRead(ANALOG_PIN);
+ toggleLED();
+ delay(100);
}
+__attribute__((constructor)) void premain() {
+ init();
+}
int main(void) {
- init();
setup();
- while (1) {
+ while (true) {
loop();
}
return 0;