ECE 486 Support Libraries
STM32L476G-Discovery support library for ECE 486 Digital Signal Processing

This library defines an interface that allows a user use the STM32L476G-Discovery development boards to stream input sampled data in real time from one or two ADCs, process the data, and stream the resulting output samples to one or two output DACs.

The user interface is as follows:

  1. Required include:
    #include "ece486.h"
  2. Optionally, the user calls
    setblocksize(nsamp);
    This call is used to change the data block size that will be delivered to the user in later function calls. (If setblocksize() is not called, a default value of DEFAULT_BLOCKSIZE is used.) Using a larger block size may result in more efficient code, while using a smaller block size will reduce the latency of the system.
  3. The user calls

    initialize_ece486(fs, input_mode, output_mode, clk_ref);

    where:

    The same sample rate is used for the input ADC and output DAC data streams. The initialize_ece486() call enables clocks and configures the appropriate ADC(s), DAC(s), Timers, buttons, DMAs, UART, and interrupts. The function pauses at the beginning of the initialization (with red and green LEDs flashing) to wait for a user push-button (center joystick) indicating to continue (allowing the device to be re-programmed without errors).

    For input_mode = MONO_IN or STEREO_IN, Analog input waveforms are sampled using ADC1 (MONO) or ADC1 | ADC2 (STEREO_IN). For the STM32L476G-Discovery board, ADC1 is accessed as an input on PA1, and ADC2 is accessed on PA2.

    Analog output is generated using DAC Channel 2 (MONO_OUT) or DAC Channels 1 and 2 (STEREO_OUT). DAC CHannel 2 is accessed as an output on PA5 (MONO_OUT or STEREO_OUT). DAC Channel 1 actually drives an internal op-amp buffer (OPAMP1), with output to the discovery board connector on PA3 (STEREO_OUT only).

    The green and red LEDs are configured and enabled. The LEDs are used to provide feedback during program execution. The red LED us used to indicate an error condition.

  4. The user calls
    nsamp = getblocksize();
    nsamp gives the data block size which will be delivered to the user in later function calls. Input samples (provided by the ADC(s) via the DMA) will be accessed in blocks of nsamp samples at a time. Likewise, the user programs should generate "nsamp" output samples for delivery to the DAC. Typically, users call getblocksize() to learn the required number of samples so that the correct amount of memory for processing the blocks of data may be allocated.
  5. Optionally, the user calls This function returns the best guess (perfect accuracy of the MSI time reference) at the actual sampling rate (in samples/second). The actual sample rate may be slightly different from the requested rate or reported rate: The internal MSI oscilator is a factory calibrated RC time reference, and errors of a percent or so would not be unexpected.
  6. Users then repeatedly call getblock() or getblockstereo() to obtain samples from the ADC(s), and (after processing the samples) putblock() or putblockstereo() to write the results back to the DAC. Using one of:
    getblock(input1); // mono input
    getblockstereo(input1, input2); // stereo input
    will fill in the user's input array(s) (type float) with normalized input (ADC) samples. Callers are responsible to make sure that the arrays input1 and input2 are allocated with enough memory to hold nsamp float values. After processing the input waveforms to create results, the output samples are placed in the DAC output buffers using one of
    putblock(result1); // Mono Output
    putblockstereo(result1, result2); // Stereo Output
    Typically, after calling the putblock() routine, the user calls getblock() to wait for the next available block of input data, and the process repeats. If the DMA completes filling a new block of data before the user calls getblock(), a SAMPLE_OVERRUN error is indicated, and the RED LED is lit. In this case, the data is not being processed fast enough to keep up with the input data stream, and input samples are being lost.

Sample values in the "input" or "result" arrays are of type float, and are normalized to range from -1.0 to +1.0 over the voltage range of the ADCs | DACs. (A sample of -1.0 is near 0V, +1.0 is near 3V, and 0.0 indicates the mid-scale voltage of 1.5V)

By default, Pin PD0 on the STM32L476-Discovery board is configured as a digital output pin. The pin status may be set using the macros

DIGITAL_IO_SET(); // Set high
DIGITAL_IO_RESET(); // Set low
DIGITAL_IO_TOGGLE(); // Toggle state

Other digital output can be configured using the standard HAL libraries The following configures PB6 (Port B, Pin 6) as a digital, push-pull output pin:

GPIO_InitTypeDef my_io_pin;
__GPIOB_CLK_ENABLE(); // Clock on for Port A
my_io_pin.Mode = GPIO_MODE_OUTPUT_PP; // Push/Pull digital output
my_io_pin.Pull = GPIO_NOPULL; // No pullup or pulldown resistor
my_io_pin.Speed = GPIO_SPEED_HIGH; // LOW, MEDIUM, FAST, or HIGH
my_io_pin.Pin = GPIO_PIN_6; // Set up PA1
HAL_GPIO_Init(GPIOB, |my_io_pin);

Once the pin is initialized, you can set the output state:

HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_6);

The LEDs on the discovery boards are accessed using the BSP_LED_xxx() functions. By default, the green LED (LED5) and red LED (LED4) are initialized. While both LEDs are available to the user, the red LED is used by the library to visually indicate error conditions. To drive green LED:

BSP_LED_On(LED5); // Turn on the LED
BSP_LED_Off(LED5); // Turn off the LED
BSP_LED_Toggle(LED5); // Toggle the LED

Users can check the global variable KeyPressed to check whether the (blue) user button on the Discovery board has been pressed. KeyPressed==SET indicates that a button press has occurred. The user should reset the value using KeyPressed=RESET;

A UART is also configured to direct printf() output to the ST-LINK USB serial port. Assuming that the host is connected to the ST-LINK connector, printf output may be examined on the host by connecting a terminal to the serial port. The terminal should be configured at 115200 bps, 8 bits, no parity, one stop-bit. printf() calls are blocking.

The discovery board LCD display may be accessed through the board-specific libraries provided with the discovery board. For example:

BSP_LCD_GLASS_DisplayString((uint8_t *) "HELLO"); // Short message
// Scroll a message 5 times...
BSP_LCD_GLASS_ScrollSentence((uint8_t*) "LOTS TO SAY HERE", 5, SCROLL_SPEED_HIGH);