diff options
34 files changed, 985 insertions, 503 deletions
diff --git a/docs/source/arm-gcc.rst b/docs/source/arm-gcc.rst index ef745f5..7ecb5d4 100644 --- a/docs/source/arm-gcc.rst +++ b/docs/source/arm-gcc.rst @@ -4,12 +4,11 @@ GCC for Maple ============= -This document provides notes on the current usage of -``arm-none-eabi-gcc``, the `CodeSourcery <http://codesourcery.com>`_ -version of the GNU `GCC <http://gcc.gnu.org/>`_ compilers used to -compile programs for the Maple. It is not intended as a reference -manual for GCC; such manuals are available `elsewhere -<http://gcc.gnu.org/>`_. +This document provides notes on using of ``arm-none-eabi-gcc``, the +`CodeSourcery <http://codesourcery.com>`_ version of the GNU `GCC +<http://gcc.gnu.org/>`_ compilers used for the Maple boards. It is +not intended as a reference manual for GCC; such manuals are available +`elsewhere <http://gcc.gnu.org/>`_. Obtaining ``arm-none-eabi-gcc`` ------------------------------- @@ -17,21 +16,24 @@ Obtaining ``arm-none-eabi-gcc`` Recent versions of ``arm-none-eabi-gcc`` and associated tools are included with the :ref:`Maple IDE <ide>`. -Users who wish to use ``arm-none-eabi-gcc`` in concert with a standard -Unix toolchain are referred to our :ref:`unix-toolchain` reference, -which describes how to set up such an environment. +Users who wish to use ``arm-none-eabi-gcc`` directly, along with a +standard Unix Make-based toolchain, should read the +:ref:`unix-toolchain`, which describes how to set up such an +environment. -LeafLabs mirrors some of the more recent versions of the compiler -under http://static.leaflabs.com/pub/codesourcery/\ , including -versions for OS X, win32, and 32-bit Linux. +LeafLabs maintains `mirrors +<http://static.leaflabs.com/pub/codesourcery/>`_ for some of the more +recent versions of the compiler, including versions for OS X, Win32, +and 32-bit Linux. Compiler Flags Used by libmaple ------------------------------- This section documents the flags passed to ``arm-none-eabi-gcc`` by -the :ref:`Maple IDE <ide>` and the default Makefile provided with -:ref:`libmaple <unix-toolchain>`. The information in this section is -subject to change without notice. +the :ref:`Maple IDE <ide>` and the default Makefile provided with the +:ref:`Unix toolchain <unix-toolchain>`. The information in this +section is subject to change between :ref:`libmaple <libmaple>` +releases. .. highlight:: sh @@ -40,7 +42,8 @@ The following flags are among those passed to the C compiler:: -Os -g -mcpu=cortex-m3 -mthumb -march=armv7-m -nostdlib -ffunction-sections -fdata-sections -Wl,--gc-sections -The following flags are among those passed to the C++ compiler:: +In addition to those flags just given for the C compiler, the +following flags are among those passed to the C++ compiler:: -fno-rtti -fno-exceptions -Wall @@ -52,6 +55,15 @@ The following flags are among those passed to the assembler:: .. _arm-gcc-avr-gcc: +Using the C Standard Library +---------------------------- + +By default (under both the :ref:`Maple IDE <ide>` and the :ref:`Unix +toolchain <unix-toolchain>`), ``arm-none-eabi-gcc`` is configured to +link against `newlib <http://sourceware.org/newlib/>`_, a C standard +library intended for use with embedded applications. You are free to +include of any of its headers. + Switching from AVR-GCC ---------------------- @@ -63,8 +75,11 @@ including Arduino) for use on the Maple. .. _arm-gcc-attribute-flash: - Replacing ``PROGMEM``: You can direct the linker script provided - with libmaple to store a variable in flash by using - ``__attribute__((section (".USER_FLASH")))``, like so:: + with libmaple to store a variable in Flash (instead of RAM) by using + the libmaple macro ``__FLASH__``, like so:: - uint32 arr[] __attribute__((section (".USER_FLASH"))) = {...}; + uint32 array[] __FLASH__ = {0, 1, 2}; + Be aware, however, that if you do that, you can only store values + which are compile-time constants, and that if you attempt to change + a variable stored in Flash, your program will crash. diff --git a/docs/source/compatibility.rst b/docs/source/compatibility.rst index 0d6319f..eb28ad2 100644 --- a/docs/source/compatibility.rst +++ b/docs/source/compatibility.rst @@ -41,6 +41,8 @@ means that programs aren't much larger (or are even smaller). Header Numbering and Incompatibilities -------------------------------------- +.. FIXME generalize Maple-specific information + The numbering of headers is different; on the Maple each GPIO has a unique number: D0, D1, D2, all the way up to D37 (actually, there are :ref:`a few more <jtag>`...). On the Arduino, the analog pins are diff --git a/docs/source/gpio.rst b/docs/source/gpio.rst index cebb402..5daf43c 100644 --- a/docs/source/gpio.rst +++ b/docs/source/gpio.rst @@ -3,6 +3,8 @@ GPIO ==== +.. FIXME generalize this maple-specific information + The Maple features 38 ready-to-use general purpose input/output (GPIO) pins for digital input/output, numbered D0 through D37. These numbers correspond to the numeric values next to each header on the Maple diff --git a/docs/source/i2c.rst b/docs/source/i2c.rst index b4a996b..e2a7a04 100644 --- a/docs/source/i2c.rst +++ b/docs/source/i2c.rst @@ -4,11 +4,16 @@ |i2c| ===== +.. FIXME update this documentation once you write the Wire library on +.. top of libmaple i2c. + +.. FIXME generalize Maple-specific documentation + .. note:: - The |i2c| interface is currently only available from the 'i2c' branch - of the github `libmaple <http://github.com/leaflabs/libmaple>`_ - repository. + The |i2c| interface is currently only available from the 'refactor' + branch of the github `libmaple + <http://github.com/leaflabs/libmaple>`_ repository. |i2c| is a crude and easy-to-hack serial protocol that requires only two wires/channels for communication between many devices. Every @@ -56,10 +61,8 @@ Function Reference ------------------ The function API for |i2c| is not finished! See the `source code -<http://github.com/leaflabs/libmaple/blob/i2c/libmaple/i2c.h>`_ for -now. - -.. TODO link to libmaple I2C docs once (1) finished, (2) in master +<https://github.com/leaflabs/libmaple/blob/refactor/libmaple/i2c.h>`_ +for now. SMBus ----- @@ -68,8 +71,6 @@ The STM32 microcontroller has hardware support for SMBus; we simply have not written software for it. The SMBAL line for i2c1 is on header D4 and for i2c2 is on D31. -.. TODO link to libmaple SMBus docs once (1) finished, (2) in master - .. _i2c-recommended-reading: Recommended Reading diff --git a/docs/source/index.rst b/docs/source/index.rst index 4369fbd..de71411 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -38,6 +38,7 @@ Have fun! Bootloader <bootloader> Troubleshooting <troubleshooting> Known Problems <errata> + Notes on GCC's ARM target <arm-gcc> .. _index-hardware: diff --git a/docs/source/lang/api/analogread.rst b/docs/source/lang/api/analogread.rst index 35c6fbc..7099b69 100644 --- a/docs/source/lang/api/analogread.rst +++ b/docs/source/lang/api/analogread.rst @@ -35,6 +35,8 @@ have to do this once, so it's usually done in :ref:`lang-setup`\ ). Parameter Discussion -------------------- +.. FIXME generalize Maple-specific information + The pin parameter is the number of the analog input pin to read from. Header pins on the Maple with ADC functionality (marked as "AIN" on the silkscreen) are: @@ -49,24 +51,25 @@ Note ---- If the analog input pin is not connected to anything, the value -returned by analogRead() will fluctuate based on a number of factors -(e.g. the values of the other analog inputs, how close your hand is to -the board, etc.) in a seemingly random way. +returned by ``analogRead()`` will fluctuate due to a number of reasons +(like the values of the other analog inputs, how close your hand is to +the board, etc.) in a "random" way. Example ------- - :: +:: + int analogPin = 3; // Potentiometer wiper (middle terminal) connected + // to analog pin 3. outside leads to ground and +3.3V. + // You may have to change this value if your board + // cannot perform ADC conversion on pin 3. - int analogPin = 3; // potentiometer wiper (middle terminal) connected - // to analog pin 3. outside leads to ground and +3.3V int val = 0; // variable to store the value read void setup() { pinMode(analogPin, INPUT_ANALOG); // set up pin for analog input - SerialUSB.begin(); // set up usb virtual COM port } void loop() { @@ -97,23 +100,27 @@ shift <lang-bitshift>` the value of a Maple readout by 2, like so:: // be aware that you're losing a lot of precision if you do this int adc_reading = analogRead(pin) >> 2; +.. FIXME Mention Native can do analogReference(), when it's time + On the Arduino, the input range and resolution can be changed using their implementation of `analogReference() <http://arduino.cc/en/Reference/AnalogReference>`_\ . Because of the way its hardware (as of Rev 5) was designed, it's not possible to implement analogReference on the Maple, so this function doesn't exist. If your inputs lie in a different voltage range than 0V--3.3V, -you'll need to bring them into that range before using analogRead. -Some basic tools to accomplish this are `resistor dividers -<http://en.wikipedia.org/wiki/Voltage_divider>`_ and `Zener diodes +you'll need to bring them into that range before using +``analogRead()``. Some basic tools to accomplish this are `resistor +dividers <http://en.wikipedia.org/wiki/Voltage_divider>`_ and `Zener +diodes <http://en.wikipedia.org/wiki/Voltage_source#Zener_voltage_source>`_\ -. However, opamps and other powered components can also be used if -greater precision is required. +. However, `operational amplifiers +<http://en.wikipedia.org/wiki/Operational_amplifier>`_ and other +powered components can also be used if greater precision is required. See also -------- -- :ref:`ADC note <adc>` +- :ref:`ADC tutorial <adc>` - `(Arduino) Tutorial: Analog Input Pins <http://arduino.cc/en/Tutorial/AnalogInputPins>`_ .. include:: cc-attribution.txt diff --git a/docs/source/lang/api/board-values.rst b/docs/source/lang/api/board-values.rst new file mode 100644 index 0000000..367adbb --- /dev/null +++ b/docs/source/lang/api/board-values.rst @@ -0,0 +1,155 @@ +.. _lang-board-values: + +Board-Specific Constants +======================== + +There are a number of board-specific values: constants or variables +which are different depending on which LeafLabs board you have. + +This page lists and documents the board-specific values. You should +use these when appropriate in your own programs. This will help make +it easier to share your code with other people who have different +boards. Some example usages are given :ref:`below +<lang-board-values-examples>`. + +.. contents:: Contents + :local: + +Constants +--------- + +- ``CYCLES_PER_MICROSECOND``: Number of CPU cycles per microsecond on + your board. + +.. _lang-board-values-but: + +- ``BOARD_BUTTON_PIN``: Pin connected to the built-in button (labeled + "BUT" on your board's silkscreen). + +.. _lang-board-values-led: + +- ``BOARD_LED_PIN``: Pin connected to the built-in LED. + +- ``BOARD_NR_GPIO_PINS``: Total number of :ref:`GPIO pins <gpio>` that + are broken out to headers. Some of these might already be connected + to external hardware (like the built-in LED and button). To find + out if a pin is in use, see :ref:`boardUsesPin() + <lang-boardusespin>` (and also :ref:`boardUsedPins + <lang-board-values-used-pins>`). + +.. _lang-board-values-nr-pwm-pins: + +- ``BOARD_NR_PWM_PINS``: Total *number* of GPIO pins that can be used + for :ref:`PWM <pwm>`. The actual *pins* that can do PWM are in the + :ref:`boardPWMPins <lang-board-values-pwm-pins>` array. + +.. _lang-board-values-nr-adc-pins: + +- ``BOARD_NR_ADC_PINS``: Total number of GPIO pins that can be used + for :ref:`analog-to-digital conversion <adc>`. The actual pins that + can do ADC conversion are in the :ref:`boardADCPins + <lang-board-values-adc-pins>` array. + +.. _lang-board-values-nr-used-pins: + +- ``BOARD_NR_USED_PINS``: Total number of GPIO pins that are already + connected to some external hardware (like a built-in LED) on the + board. The actual pins that that are already used are in the + :ref:`boardUsedPins <lang-board-values-used-pins>` array. To see if + a pin is already in use, use the :ref:`boardUsesPin() + <lang-boardusespin>` function. + +.. _lang-board-values-usart: + +- USART (serial port) related constants: + + * ``BOARD_USART1_TX_PIN``, ``BOARD_USART2_TX_PIN``, ``BOARD_USART3_TX_PIN``: + TX pins for the 3 USARTS. + + * ``BOARD_USART1_RX_PIN``, ``BOARD_USART2_RX_PIN``, ``BOARD_USART3_RX_PIN``: + RX pins for the 3 USARTS. + + * ``BOARD_UART4_TX_PIN``, ``BOARD_UART5_TX_PIN``: TX pins for + UARTs 4 and 5 (high-density boards like Maple Native only). + + * ``BOARD_UART4_RX_PIN``, ``BOARD_UART5_RX_PIN``: RX pins for + UARTs 4 and 5 (high-density boards like Maple Native only). + + * ``BOARD_NR_USARTS``: Number of serial ports on the board. This + number includes UARTs 4 and 5 if they are available. + +.. _lang-board-values-pwm-pins: +.. _lang-board-values-adc-pins: +.. _lang-board-values-used-pins: + +Pin Arrays +---------- + +Some :ref:`arrays <lang-array>` of pin numbers are available which you +can use to find out certain important information about a given pin. + +.. TODO add links to the board-specific hardware information on what +.. are in these arrays + +- ``boardPWMPins``: Pin numbers of each pin capable of :ref:`PWM + <pwm>` output, using :ref:`pwmWrite() <lang-pwmwrite>`. The total + number of these pins is :ref:`BOARD_NR_PWM_PINS + <lang-board-values-nr-pwm-pins>`. + +- ``boardADCPins``: Pin numbers of each pin capable of :ref:`ADC + <adc>` conversion, using :ref:`analogRead() <lang-analogread>`. The + total number of these pins is :ref:`BOARD_NR_ADC_PINS + <lang-board-values-nr-adc-pins>`. + +- ``boardUsedPins``: Pin numbers of each pin that, by default, is used + for some special purpose by the board. The total number of these + pins is :ref:`BOARD_NR_USED_PINS <lang-board-values-nr-used-pins>`. + To check if a pin is used for a special purpose, use + :ref:`boardUsesPin() <lang-boardusespin>`. + +.. _lang-board-values-examples: + +Examples +-------- + +:ref:`BOARD_LED_PIN <lang-board-values-led>` On the Maple, the +built-in LED is connected to pin 13. On the Maple Mini, however, it +is connected to pin 33. You can write a "blinky" program that works +on all LeafLabs boards using ``BOARD_LED_PIN`` and :ref:`toggleLED() +<lang-toggleled>`:: + + void setup() { + pinMode(BOARD_LED_PIN, OUTPUT); + } + + void loop() { + toggleLED(); + delay(100); + } + +:ref:`BOARD_BUTTON_PIN <lang-board-values-but>`: Similarly, you can +write a single program that prints a message whenever the button is +pressed which will work on all LeafLabs boards using +``BOARD_BUTTON_PIN`` and :ref:`isButtonPressed() +<lang-isbuttonpressed>`:: + + void setup() { + pinMode(BOARD_BUTTON_PIN, INPUT); + } + + void loop() { + if (isButtonPressed()) { + SerialUSB.println("You pressed the button!"); + } + } + +See Also +-------- + +- :ref:`lang-boardusespin` +- :ref:`lang-isbuttonpressed` +- :ref:`lang-waitforbuttonpress` +- :ref:`lang-pinmode` +- :ref:`lang-toggleled` +- :ref:`lang-analogread` +- :ref:`lang-pwmwrite` diff --git a/docs/source/lang/api/boardusespin.rst b/docs/source/lang/api/boardusespin.rst new file mode 100644 index 0000000..8dc4c64 --- /dev/null +++ b/docs/source/lang/api/boardusespin.rst @@ -0,0 +1,27 @@ +.. highlight:: cpp + +.. _lang-boardusespin: + +boardUsesPin() +============== + +Each LeafLabs board connects some pins to external hardware. The most +important examples of this are the built-in LED and button. You can +check if a board uses a particular pin using this function. + +Library Documentation +--------------------- + +.. doxygenfunction:: boardUsesPin + +See Also +-------- + +- :ref:`Board-specific values <lang-board-values>` +- :ref:`boardUsedPins <lang-board-values-used-pins>` +- :ref:`BOARD_LED_PIN <lang-board-values-led>` +- :ref:`toggleLED() <lang-toggleled>` +- :ref:`BOARD_BUTTON_PIN <lang-board-values-but>` +- :ref:`isButtonPressed() <lang-isbuttonpressed>` +- :ref:`waitForButtonPress() <lang-waitforbuttonpress>` + diff --git a/docs/source/lang/api/constants.rst b/docs/source/lang/api/constants.rst index 2e968e7..c5a7c0c 100644 --- a/docs/source/lang/api/constants.rst +++ b/docs/source/lang/api/constants.rst @@ -293,23 +293,16 @@ exponent indicators. Some examples are given in the following table: Board-Specific Constants ------------------------ -This section documents constants whose value might change across -different LeafLabs boards. You can use these constants to help ensure -that your code will be portable across different boards. +There are several :ref:`board-specific constants <lang-board-values>` +whose value depends on which LeafLabs board you have. If you use +them, it will help make sure that your code will work well on all +LeafLabs boards, not just the one you have. This will make it much +easier to share your code with others. -.. TODO replace "upcoming" when Mini, Native come out - -.. _lang-constants-led: - -- ``BOARD_LED_PIN``: the number of the pin which connects to the - built-in LED. On the Maple, this is pin 13, but it's not guaranteed - to be the same in upcoming boards like the Maple Mini. - -.. _lang-constants-but: - -- ``BOARD_BUTTON_PIN``: the number of the pin which connects to the - built-in button (labeled "BUT"). On the Maple, this is pin 38, but - it's not guaranteed to be the same in other boards. +For example, the pin number connected to the board's built-in LED is +different on the different boards, but the board-specific constant +:ref:`BOARD_LED_PIN <lang-board-values-led>` will always be the +correct value for each board. See Also -------- @@ -325,5 +318,6 @@ See Also - :ref:`unsigned long long <lang-unsignedlonglong>` - :ref:`float <lang-float>` - :ref:`double <lang-double>` +- :ref:`Board-Specific Values <lang-board-values>` .. include:: cc-attribution.txt diff --git a/docs/source/lang/api/hardwaretimer.rst b/docs/source/lang/api/hardwaretimer.rst index c7a630d..3f086ca 100644 --- a/docs/source/lang/api/hardwaretimer.rst +++ b/docs/source/lang/api/hardwaretimer.rst @@ -10,6 +10,12 @@ built-in timer peripherals. More information on these peripherals (including code examples) is available in the :ref:`timers reference <timers>`. +.. FIXME update HardwareTimer documentation after redoing it in terms +.. of the new timer interface. + +.. warning:: This class has been deprecated. It is not available in + the current build. + Library Documentation --------------------- diff --git a/docs/source/lang/api/isbuttonpressed.rst b/docs/source/lang/api/isbuttonpressed.rst index dbff0c9..8c350b9 100644 --- a/docs/source/lang/api/isbuttonpressed.rst +++ b/docs/source/lang/api/isbuttonpressed.rst @@ -4,7 +4,8 @@ isButtonPressed() ================= Check whether the board's built-in button (labeled BUT on the -silkscreen) is pressed. +silkscreen) is pressed. The pin number of the built-in button is +given by the constant ``BOARD_BUTTON_PIN``. Library Documentation --------------------- @@ -14,4 +15,6 @@ Library Documentation See Also -------- +- :ref:`Board-specific values <lang-board-values>` +- :ref:`BOARD_BUTTON_PIN <lang-board-values-but>` - :ref:`lang-waitforbuttonpress` diff --git a/docs/source/lang/api/pwmwrite.rst b/docs/source/lang/api/pwmwrite.rst index 9d50077..cea602b 100644 --- a/docs/source/lang/api/pwmwrite.rst +++ b/docs/source/lang/api/pwmwrite.rst @@ -11,6 +11,8 @@ pwmWrite(), the pin will output a steady square wave with the given duty cycle. You can change the duty cycle later by calling pwmWrite() again with the same pin and a different duty. +.. FIXME board-specific information + On the Maple, the pins which support PWM are: 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 14, 24, 27, and 28. diff --git a/docs/source/lang/api/toggleled.rst b/docs/source/lang/api/toggleled.rst index 0cc20c2..54a7d64 100644 --- a/docs/source/lang/api/toggleled.rst +++ b/docs/source/lang/api/toggleled.rst @@ -13,5 +13,5 @@ Library Documentation See Also -------- -- :ref:`BOARD_LED_PIN <lang-constants-led>` +- :ref:`BOARD_LED_PIN <lang-board-values-led>` - :ref:`togglePin() <lang-togglepin>` diff --git a/docs/source/lang/api/waitforbuttonpress.rst b/docs/source/lang/api/waitforbuttonpress.rst index 34c5066..a5bd45c 100644 --- a/docs/source/lang/api/waitforbuttonpress.rst +++ b/docs/source/lang/api/waitforbuttonpress.rst @@ -14,4 +14,6 @@ Library Documentation See Also -------- +- :ref:`Board-specific values <lang-board-values>` +- :ref:`BOARD_BUTTON_PIN <lang-board-values-but>` - :ref:`lang-isbuttonpressed` diff --git a/docs/source/language-index.rst b/docs/source/language-index.rst index c949988..531e72c 100644 --- a/docs/source/language-index.rst +++ b/docs/source/language-index.rst @@ -26,13 +26,13 @@ programmers familiar with the Arduino language. | | | +----------------------------------+------------------------------------+ -.. Unimplemented in libmaple or not part of current release: +.. Unimplemented or not part of current release: .. toctree:: :hidden: + lang/unimplemented/tone.rst lang/unimplemented/notone.rst lang/unimplemented/pulsein.rst lang/unimplemented/stringclass.rst lang/unimplemented/stringobject.rst - lang/unimplemented/tone.rst diff --git a/docs/source/language.rst b/docs/source/language.rst index d340aec..ea841f5 100644 --- a/docs/source/language.rst +++ b/docs/source/language.rst @@ -10,6 +10,9 @@ The Maple can be programmed in the `Wiring <http://www.wiring.org.co/reference/>`_ language, which is the same language used to program the `Arduino <http://arduino.cc/>`_ boards. +.. TODO Wiring tutorial -- just describe setup()/loop(), then link to +.. some of the the bajillion external tutorials + C or C++ programmers curious about the differences between the Wiring language and C++ may wish to skip to the :ref:`arduino_c_for_c_hackers`. @@ -25,6 +28,21 @@ Maple Language Reference The following table summarizes the available core language features. A more exhaustive index is available at the :ref:`language-index`. +**Looking for something else?** + +- See the :ref:`libraries` for extra built-in libraries for dealing + with different kinds of hardware. + +.. FIXME mention Maple Native supports malloc(), free(), operator +.. new(), and operator delete(), when that is a true thing to say. + +- If you're looking for something from the C standard library (like + ``atoi()``, for instance): the :ref:`CodeSourcery GCC compiler + <arm-gcc>` used to compile your programs is configured to link + against `newlib <http://sourceware.org/newlib/>`_, and allows the + use of any of its header files. However, dynamic memory allocation + (``malloc()``, etc.) is not available. + +--------------------------------------------+----------------------------------------------+---------------------------------------------------+ | Structure | Variables | Functions | | | | | @@ -40,13 +58,13 @@ A more exhaustive index is available at the :ref:`language-index`. | |* :ref:`true <lang-constants-true>` | |* :ref:`togglePin() <lang-togglepin>` | |* :ref:`for <lang-for>` | :ref:`false <lang-constants-false>` | | | | |* :ref:`toggleLED() <lang-toggleled>` | -|* :ref:`switch/case <lang-switchcase>` |* :ref:`BOARD_LED_PIN <lang-constants-led>` | | | -| | :ref:`BOARD_BUTTON_PIN <lang-constants-but>`|* :ref:`isButtonPressed() <lang-isbuttonpressed>` | -|* :ref:`while <lang-while>` | | | -| |* :ref:`Constants |* :ref:`waitForButtonPress() | -|* :ref:`do...while <lang-dowhile>` | <lang-constants>` (:ref:`integers | <lang-waitforbuttonpress>` | -| | <lang-constants-integers>`, :ref:`floating | | -|* :ref:`break <lang-break>` | point <lang-constants-fp>`) |**Analog I/O** | +|* :ref:`switch/case <lang-switchcase>` |* :ref:`Constants | | +| | <lang-constants>` (:ref:`integers |* :ref:`isButtonPressed() <lang-isbuttonpressed>` | +|* :ref:`while <lang-while>` | <lang-constants-integers>`, :ref:`floating | | +| | point <lang-constants-fp>`) |* :ref:`waitForButtonPress() | +|* :ref:`do...while <lang-dowhile>` | | <lang-waitforbuttonpress>` | +| |* :ref:`Board-specific values | | +|* :ref:`break <lang-break>` | <lang-board-values>` |**Analog I/O** | | | | | |* :ref:`continue <lang-continue>` |**Data Types** |* :ref:`analogRead() <lang-analogread>` | | | | | @@ -76,7 +94,7 @@ A more exhaustive index is available at the :ref:`language-index`. |**Arithmetic Operators** | <lang-int>` | | | | |* :ref:`delayMicroseconds() | |* :ref:`= <lang-assignment>` |* ``unsigned long`` (4 bytes), synonym for | <lang-delaymicroseconds>` | -| (assignment operator) | :ref:`unsigned int <lang-unsignedint>` | | +| (assignment) | :ref:`unsigned int <lang-unsignedint>` | | | | | | |* :ref:`+ <lang-arithmetic>` (addition) |* :ref:`long long <lang-longlong>` (8 bytes) |**Math** | | | | | @@ -153,13 +171,13 @@ A more exhaustive index is available at the :ref:`language-index`. | | | | |* :ref:`++ <lang-increment>` | |* :ref:`Serial <lang-serial>` | | (increment) | | | -| | |**Looking for something else?** | +| | | | |* :ref:`- - <lang-increment>` | | | -| (decrement) | | See the :ref:`libraries` page for interfacing with| -| | | particular types of hardware. Maple links | -|* :ref:`+= <lang-compoundarithmetic>` | | against `newlib <http://sourceware.org/newlib/>`_ | -| (compound add) | | and allows the use of any of its functions; see | -| | | its documentation for more details. | +| (decrement) | | | +| | | | +|* :ref:`+= <lang-compoundarithmetic>` | | | +| (compound add) | | | +| | | | |* :ref:`-= | | | | <lang-compoundarithmetic>` (compound | | | | subtract) | | | diff --git a/docs/source/libmaple.rst b/docs/source/libmaple.rst index 8cc39a3..9faca03 100644 --- a/docs/source/libmaple.rst +++ b/docs/source/libmaple.rst @@ -30,12 +30,12 @@ wrappers and code to imitate the Arduino programming library. git clone git://github.com/leaflabs/libmaple.git -**Table of contents:** +.. TODO after finishing refactor: create, style, and host a pure +.. Doxygen libmaple reference docs. This implies determining a stable +.. API. -.. toctree:: - :maxdepth: 2 +.. **Table of contents:** - Guide to using GCC's ARM target <arm-gcc> +.. .. toctree:: +.. :maxdepth: 2 -.. TODO LATER create, style, and host a pure Doxygen libmaple -.. reference docs. This implies determining a stable API. diff --git a/examples/qa-slave-shield.cpp b/examples/qa-slave-shield.cpp index 178b780..2da1c04 100644 --- a/examples/qa-slave-shield.cpp +++ b/examples/qa-slave-shield.cpp @@ -1,22 +1,20 @@ -// Slave mode for QA shield +// Slave mode for Quality Assurance test #include "wirish.h" -// FIXME generalize for Maple Native, Maple Mini (NUM_GPIO, Mini USB -// breakout pins, etc.) +#define INTER_TOGGLE_DELAY_NORMAL 5 +#define INTER_TOGGLE_DELAY_SLOW 80 -#define LED_PIN BOARD_LED_PIN -#define NUM_GPIO 38 // Ignore JTAG pins. +void interToggleDelay(void); void setup() { - /* Set up the LED to blink */ - pinMode(LED_PIN, OUTPUT); - digitalWrite(LED_PIN, HIGH); + pinMode(BOARD_LED_PIN, OUTPUT); + pinMode(BOARD_BUTTON_PIN, INPUT); - for(int i = 0; i < NUM_GPIO; i++) { - if (i == BOARD_LED_PIN) { + // 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, LOW); } @@ -28,17 +26,29 @@ void loop() { delay(100); toggleLED(); - for(int i = 0; i < NUM_GPIO; i++) { - if (i == BOARD_LED_PIN) { + for (int i = 0; i < BOARD_NR_GPIO_PINS; i++) { + if (boardUsesPin(i)) continue; - } - togglePin(i); - delay(5); - togglePin(i); - delay(5); + + // 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 objects that need libmaple may fail. __attribute__((constructor)) void premain() { @@ -48,7 +58,7 @@ __attribute__((constructor)) void premain() { int main(void) { setup(); - while (1) { + while (true) { loop(); } return 0; diff --git a/examples/test-session.cpp b/examples/test-session.cpp index 110b219..a4128ac 100644 --- a/examples/test-session.cpp +++ b/examples/test-session.cpp @@ -1,49 +1,23 @@ // 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) || defined(BOARD_maple_RET6) -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}; - -#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}; +// Default USART baud rate +#define BAUD 9600 -#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, 39, 40, 41, 42, 43, 45, - 46, 47, 48, 49, 50, 51, 52, 53, 54}; -#else -#error "Board type has not been selected correctly" +uint8 gpio_state[BOARD_NR_GPIO_PINS]; -#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); @@ -55,37 +29,43 @@ void cmd_gpio_qa(void); void cmd_sequential_gpio_writes(void); void cmd_gpio_toggling(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 usart_baud_test(HardwareSerial **serials, int n, 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("> "); } @@ -93,16 +73,16 @@ void loop () { toggleLED(); delay(100); - 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 '?': @@ -125,7 +105,7 @@ void loop () { break; case '.': - while(!COMM.available()) { + while (!SerialUSB.available()) { Serial1.print("."); Serial2.print("."); Serial3.print("."); @@ -146,17 +126,17 @@ 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; @@ -169,10 +149,10 @@ void loop () { 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); } @@ -182,19 +162,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': @@ -202,26 +182,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': @@ -232,391 +216,496 @@ 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: "); + SerialUSB.print(input); + 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); - - // 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); - } +// -- Commands ---------------------------------------------------------------- - //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("\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 with various 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_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); + 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."); + usart_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."); + usart_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."); + usart_baud_test(serial_1_and_3, 2, 9600); + SerialUSB.read(); - COMM.println("Resetting USART1 and USART3..."); - Serial1.begin(9600); - Serial3.begin(9600); -} - -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); - } - } - } + SerialUSB.println("Resetting USART1 and USART3..."); + Serial1.begin(BAUD); + Serial3.begin(BAUD); } 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(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; } - pinMode(adc_pins[i], OUTPUT); - digitalWrite(adc_pins[i], 0); - if((uint8)COMM.read() == ESC) break; } + return ok; +} + +bool wait_for_low_transition(uint8 pin) { + uint32 start = millis(); + while (millis() - start < 2000) { + if (digitalRead(pin) == LOW) { + return true; + } + } + 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; } - for(int i = 0; i<NR_GPIO_PINS; i++) { + + if (all_pins_ok) { + SerialUSB.println("Finished; test passes."); + } else { + SerialUSB.println("**** TEST FAILS *****"); + } + + 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((int)i, DEC); - COMM.println("..."); + 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; - } -} + SerialUSB.println("Sequentially testing PWM on all unused pins. " + "Press any key for next pin, ESC to stop."); -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); - } - 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 (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); } - delay(1); - } - for(uint32 i = 2; i<sizeof(pwm_pins); i++) { - pinMode(pwm_pins[i], OUTPUT); + + 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 (cycles/us): "); + 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 usart_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); + } + } + } } static uint16 init_all_timers_prescale = 0; @@ -630,14 +719,42 @@ void init_all_timers(uint16 prescale) { timer_foreach(set_prescale); } +void enable_usarts(void) { + // FIXME generalize after USART refactor + Serial1.begin(BAUD); + Serial2.begin(BAUD); + Serial3.begin(BAUD); +} + +void disable_usarts(void) { + // FIXME generalize after USART refactor + Serial1.end(); + Serial2.end(); + Serial3.end(); +} + +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 objects that need libmaple may fail. -__attribute__(( constructor )) void premain() { +__attribute__((constructor)) void premain() { init(); } -int main(void) -{ +int main(void) { setup(); while (1) { diff --git a/wirish/boards.cpp b/wirish/boards.cpp index 17f47c6..1c2b1c7 100644 --- a/wirish/boards.cpp +++ b/wirish/boards.cpp @@ -30,7 +30,7 @@ * at 72MHz. APB1 is clocked at 36MHz. */ -#include "wirish.h" +#include "boards.h" #include "flash.h" #include "rcc.h" @@ -46,15 +46,6 @@ static void setupClocks(void); static void setupADC(void); static void setupTimers(void); -/** - * @brief Generic board initialization function. - * - * This function is called before main(). It ensures that the clocks - * and peripherals are configured properly for use with wirish, then - * calls boardInit(). - * - * @see boardInit() - */ void init(void) { setupFlash(); setupClocks(); @@ -68,6 +59,17 @@ void init(void) { boardInit(); } +/* You could farm this out to the files in boards/ if e.g. it takes + * too long to test on Maple Native (all those FSMC pins...). */ +bool boardUsesPin(uint8 pin) { + for (int i = 0; i < BOARD_NR_USED_PINS; i++) { + if (pin == boardUsedPins[i]) { + return true; + } + } + return false; +} + static void setupFlash(void) { flash_enable_prefetch(); flash_set_latency(FLASH_WAIT_STATE_2); diff --git a/wirish/boards.h b/wirish/boards.h index 3d023ae..cec844f 100644 --- a/wirish/boards.h +++ b/wirish/boards.h @@ -63,8 +63,39 @@ enum { * @brief Maps each Maple pin to a corresponding stm32_pin_info. * @see stm32_pin_info */ -extern stm32_pin_info PIN_MAP[]; +extern const stm32_pin_info PIN_MAP[]; +/** + * @brief Pins capable of PWM output. + * + * Its length is BOARD_NR_PWM_PINS. + */ +extern const uint8 boardPWMPins[]; + +/** + * @brief Array of pins capable of analog input. + * + * Its length is BOARD_NR_ADC_PINS. + */ +extern const uint8 boardADCPins[]; + +/** + * @brief Pins which are connected to external hardware. + * + * For example, on Maple boards, it always at least includes + * BOARD_LED_PIN. Its length is BOARD_NR_USED_PINS. + */ +extern const uint8 boardUsedPins[]; + +/** + * @brief Generic board initialization function. + * + * This function is called before main(). It ensures that the clocks + * and peripherals are configured properly for use with wirish, then + * calls boardInit(). + * + * @see boardInit() + */ void init(void); /** @@ -78,6 +109,16 @@ void init(void); */ extern void boardInit(void); +/** + * @brief Test if a pin is used for a special purpose on your board. + * @param pin Pin to test + * @return true if the given pin is in boardUsedPins, and false otherwise. + * @see boardUsedPins + */ +bool boardUsesPin(uint8 pin); + +/* Include the appropriate private header from boards/: */ + #ifdef BOARD_maple #include "boards/maple.h" #elif defined(BOARD_maple_native) diff --git a/wirish/boards/maple.cpp b/wirish/boards/maple.cpp index ba2261b..5122290 100644 --- a/wirish/boards/maple.cpp +++ b/wirish/boards/maple.cpp @@ -40,7 +40,7 @@ void boardInit(void) { } -stm32_pin_info PIN_MAP[NR_GPIO_PINS] = { +extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { /* Top header */ @@ -91,4 +91,16 @@ stm32_pin_info PIN_MAP[NR_GPIO_PINS] = { {GPIOC, NULL, NULL, 9, 0, ADCx} /* D38/PC9 (BUT) */ }; +extern const uint8 boardPWMPins[] __FLASH__ = { + 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 14, 24, 25, 27, 28 +}; + +extern const uint8 boardADCPins[] __FLASH__ = { + 0, 1, 2, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 27, 28 +}; + +extern const uint8 boardUsedPins[] __FLASH__ = { + BOARD_LED_PIN, BOARD_BUTTON_PIN +}; + #endif diff --git a/wirish/boards/maple.h b/wirish/boards/maple.h index 519698b..1867de8 100644 --- a/wirish/boards/maple.h +++ b/wirish/boards/maple.h @@ -42,7 +42,7 @@ #define BOARD_LED_PIN 13 /* Number of USARTs/UARTs whose pins are broken out to headers */ -#define NR_USARTS 3 +#define BOARD_NR_USARTS 3 /* Default USART pin numbers (not considering AFIO remap) */ #define BOARD_USART1_TX_PIN 7 @@ -53,7 +53,17 @@ #define BOARD_USART3_RX_PIN 30 /* Total number of GPIO pins that are broken out to headers and - intended for general use. */ -#define NR_GPIO_PINS 39 + * intended for general use. */ +#define BOARD_NR_GPIO_PINS 39 + +/* Number of pins capable of PWM output */ +#define BOARD_NR_PWM_PINS 16 + +/* Number of pins capable of ADC conversion */ +#define BOARD_NR_ADC_PINS 15 + +/* Number of pins already connected to external hardware. For Maple, + * these are just BOARD_LED_PIN and BOARD_BUTTON_PIN. */ +#define BOARD_NR_USED_PINS 2 #endif diff --git a/wirish/boards/maple_RET6.cpp b/wirish/boards/maple_RET6.cpp index 962affc..fd67459 100644 --- a/wirish/boards/maple_RET6.cpp +++ b/wirish/boards/maple_RET6.cpp @@ -37,7 +37,7 @@ void boardInit(void) { } -stm32_pin_info PIN_MAP[NR_GPIO_PINS] = { +extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { /* Top header */ @@ -88,4 +88,16 @@ stm32_pin_info PIN_MAP[NR_GPIO_PINS] = { {GPIOC, TIMER8, NULL, 9, 4, ADCx} /* D38/PC9 (BUT) */ }; +extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { + 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 14, 24, 25, 27, 28 +}; + +extern const uint8 boardADCPins[BOARD_NR_ADC_PINS] __FLASH__ = { + 0, 1, 2, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 27, 28 +}; + +extern const uint8 boardUsedPins[BOARD_NR_USED_PINS] __FLASH__ = { + BOARD_LED_PIN, BOARD_BUTTON_PIN +}; + #endif diff --git a/wirish/boards/maple_RET6.h b/wirish/boards/maple_RET6.h index 63510c0..d91a4de 100644 --- a/wirish/boards/maple_RET6.h +++ b/wirish/boards/maple_RET6.h @@ -47,8 +47,7 @@ #define BOARD_LED_PIN 13 /* Note: UART4 and UART5 have pins which aren't broken out :( */ -#define NR_USARTS 3 - +#define BOARD_NR_USARTS 3 #define BOARD_USART1_TX_PIN 7 #define BOARD_USART1_RX_PIN 8 #define BOARD_USART2_TX_PIN 1 @@ -56,6 +55,9 @@ #define BOARD_USART3_TX_PIN 29 #define BOARD_USART3_RX_PIN 30 -#define NR_GPIO_PINS 39 +#define BOARD_NR_GPIO_PINS 39 +#define BOARD_NR_PWM_PINS 16 +#define BOARD_NR_ADC_PINS 15 +#define BOARD_NR_USED_PINS 2 #endif diff --git a/wirish/boards/maple_mini.cpp b/wirish/boards/maple_mini.cpp index 66a0997..cd2827d 100644 --- a/wirish/boards/maple_mini.cpp +++ b/wirish/boards/maple_mini.cpp @@ -41,7 +41,7 @@ void boardInit(void) { afio_mapr_swj_config(AFIO_MAPR_SWJ_NO_JTAG_NO_SW); } -stm32_pin_info PIN_MAP[NR_GPIO_PINS] = { +extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { /* Top header */ @@ -84,4 +84,19 @@ stm32_pin_info PIN_MAP[NR_GPIO_PINS] = { {GPIOB, TIMER3, ADC1, 1, 4, 9}, /* D33/PB1 */ }; +extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { + 3, 4, 5, 8, 9, 10, 11, 15, 16, 25, 26, 27 +}; + +extern const uint8 boardADCPins[BOARD_NR_ADC_PINS] __FLASH__ = { + 3, 4, 5, 6, 7, 8, 9, 10, 11, 33 // NB 33 is LED +}; + +#define USB_DP 23 +#define USB_DM 24 + +extern const uint8 boardUsedPins[BOARD_NR_USED_PINS] __FLASH__ = { + BOARD_LED_PIN, BOARD_BUTTON_PIN, USB_DP, USB_DM +}; + #endif diff --git a/wirish/boards/maple_mini.h b/wirish/boards/maple_mini.h index bfb92a5..8b7ae64 100644 --- a/wirish/boards/maple_mini.h +++ b/wirish/boards/maple_mini.h @@ -46,8 +46,7 @@ #define BOARD_BUTTON_PIN 32 #define BOARD_LED_PIN 33 -#define NR_USARTS 3 - +#define BOARD_NR_USARTS 3 #define BOARD_USART1_TX_PIN 26 #define BOARD_USART1_RX_PIN 25 #define BOARD_USART2_TX_PIN 9 @@ -55,6 +54,9 @@ #define BOARD_USART3_TX_PIN 1 #define BOARD_USART3_RX_PIN 0 -#define NR_GPIO_PINS 34 +#define BOARD_NR_GPIO_PINS 34 +#define BOARD_NR_PWM_PINS 12 +#define BOARD_NR_ADC_PINS 10 +#define BOARD_NR_USED_PINS 4 #endif diff --git a/wirish/boards/maple_native.cpp b/wirish/boards/maple_native.cpp index 75c6a2d..2813e91 100644 --- a/wirish/boards/maple_native.cpp +++ b/wirish/boards/maple_native.cpp @@ -39,7 +39,7 @@ void boardInit(void) { initNativeSRAM(); } -stm32_pin_info PIN_MAP[NR_GPIO_PINS] = { +extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { /* Top header */ @@ -152,4 +152,18 @@ stm32_pin_info PIN_MAP[NR_GPIO_PINS] = { {GPIOD, NULL, NULL, 10, 0, ADCx} /* D99/PD10 */ }; +extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { + 12, 13, 14, 15, 22, 23, 24, 25, 37, 38, 45, 46, 47, 48, 49, 50, 53, 54 +}; + +extern const uint8 boardADCPins[BOARD_NR_ADC_PINS] __FLASH__ = { + 6, 7, 8, 9, 10, 11, 39, 40, 41, 42, 43, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54 +}; + +/* FIXME! see comment by BOARD_NR_USED_PINS in maple_native.h */ +extern const uint8 boardUsedPins[BOARD_NR_USED_PINS] __FLASH__ = { + BOARD_LED_PIN, BOARD_BUTTON_PIN +}; + #endif diff --git a/wirish/boards/maple_native.h b/wirish/boards/maple_native.h index 21fc480..4e3ee82 100644 --- a/wirish/boards/maple_native.h +++ b/wirish/boards/maple_native.h @@ -43,11 +43,10 @@ #define CYCLES_PER_MICROSECOND 72 #define SYSTICK_RELOAD_VAL 71999 -#define BOARD_LED_PIN D21 -#define BOARD_BUTTON_PIN D18 - -#define NR_USARTS 5 +#define BOARD_LED_PIN 21 +#define BOARD_BUTTON_PIN 18 +#define BOARD_NR_USARTS 5 #define BOARD_USART1_TX_PIN 25 #define BOARD_USART1_RX_PIN 26 #define BOARD_USART2_TX_PIN 51 @@ -59,6 +58,12 @@ #define BOARD_UART5_TX_PIN 20 #define BOARD_UART5_RX_PIN 28 -#define NR_GPIO_PINS 100 +#define BOARD_NR_GPIO_PINS 100 +#define BOARD_NR_PWM_PINS 18 +#define BOARD_NR_ADC_PINS 21 +/* FIXME! this isn't true at all; almost all of the triple header pins + * are used by the FSMC by default. Fix this (and the corresponding + * boardUsedPins definition in maple_native.cpp) by QA time. */ +#define BOARD_NR_USED_PINS 2 #endif diff --git a/wirish/comm/HardwareSerial.cpp b/wirish/comm/HardwareSerial.cpp index 97a5ec3..8398878 100644 --- a/wirish/comm/HardwareSerial.cpp +++ b/wirish/comm/HardwareSerial.cpp @@ -32,10 +32,12 @@ #include "HardwareSerial.h" #include "usart.h" +// FIXME: High density device ports, usages of BOARD_USARTx_yX_PIN +// instead of holding onto a gpio_dev, tx_pin, rx_pin, timer_dev, and +// channel_num -- that stuff is all in the PIN_MAP. HardwareSerial Serial1(USART1, 4500000UL, GPIOA, 9, 10, TIMER1, 2); HardwareSerial Serial2(USART2, 2250000UL, GPIOA, 2, 3, TIMER2, 3); HardwareSerial Serial3(USART3, 2250000UL, GPIOB, 10, 11, NULL, 0); -// TODO: High density device ports HardwareSerial::HardwareSerial(uint8 usart_num, uint32 max_baud, diff --git a/wirish/ext_interrupts.cpp b/wirish/ext_interrupts.cpp index f9ccd39..557fffd 100644 --- a/wirish/ext_interrupts.cpp +++ b/wirish/ext_interrupts.cpp @@ -43,7 +43,7 @@ static inline exti_trigger_mode exti_out_mode(ExtIntTriggerMode mode); * @see ExtIntTriggerMode */ void attachInterrupt(uint8 pin, voidFuncPtr handler, ExtIntTriggerMode mode) { - if (pin >= NR_GPIO_PINS || !handler) { + if (pin >= BOARD_NR_GPIO_PINS || !handler) { return; } @@ -60,7 +60,7 @@ void attachInterrupt(uint8 pin, voidFuncPtr handler, ExtIntTriggerMode mode) { * @param pin Pin number to detach any interrupt from. */ void detachInterrupt(uint8 pin) { - if (pin >= NR_GPIO_PINS) { + if (pin >= BOARD_NR_GPIO_PINS) { return; } diff --git a/wirish/pwm.cpp b/wirish/pwm.cpp index 4c803d2..bf69bfb 100644 --- a/wirish/pwm.cpp +++ b/wirish/pwm.cpp @@ -34,7 +34,7 @@ void pwmWrite(uint8 pin, uint16 duty_cycle) { timer_dev *dev = PIN_MAP[pin].timer_device; - if (pin >= NR_GPIO_PINS || dev == NULL || dev->type == TIMER_BASIC) { + if (pin >= BOARD_NR_GPIO_PINS || dev == NULL || dev->type == TIMER_BASIC) { return; } diff --git a/wirish/wirish_digital.cpp b/wirish/wirish_digital.cpp index 115e91e..9b9f175 100644 --- a/wirish/wirish_digital.cpp +++ b/wirish/wirish_digital.cpp @@ -33,7 +33,7 @@ void pinMode(uint8 pin, WiringPinMode mode) { gpio_pin_mode outputMode; boolean pwm = false; - if (pin >= NR_GPIO_PINS) { + if (pin >= BOARD_NR_GPIO_PINS) { return; } @@ -83,7 +83,7 @@ void pinMode(uint8 pin, WiringPinMode mode) { uint32 digitalRead(uint8 pin) { - if (pin >= NR_GPIO_PINS) { + if (pin >= BOARD_NR_GPIO_PINS) { return 0; } @@ -92,7 +92,7 @@ uint32 digitalRead(uint8 pin) { } void digitalWrite(uint8 pin, uint8 val) { - if (pin >= NR_GPIO_PINS) { + if (pin >= BOARD_NR_GPIO_PINS) { return; } @@ -100,14 +100,14 @@ void digitalWrite(uint8 pin, uint8 val) { } void togglePin(uint8 pin) { - if (pin >= NR_GPIO_PINS) { + if (pin >= BOARD_NR_GPIO_PINS) { return; } gpio_toggle_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit); } -#define BUTTON_DEBOUNCE_DELAY 10 +#define BUTTON_DEBOUNCE_DELAY 1 uint8 isButtonPressed() { if (digitalRead(BOARD_BUTTON_PIN)) { diff --git a/wirish/wirish_types.h b/wirish/wirish_types.h index 7d6e31a..475f470 100644 --- a/wirish/wirish_types.h +++ b/wirish/wirish_types.h @@ -30,6 +30,7 @@ * @brief Wirish library type definitions. */ +#include "libmaple_types.h" #include "gpio.h" #include "timer.h" #include "adc.h" @@ -56,4 +57,6 @@ typedef struct stm32_pin_info { uint8 adc_channel; /**< Pin ADC channel, or ADCx if none. */ } stm32_pin_info; +#define __FLASH__ __attr_flash + #endif |