Skip to main content

Getting Started with the User Interface for the Daisy Patch

·870 words·5 mins
Development Eurorack User Interface C++
Table of Contents
Building Digi Env - This article is part of a series.
Part 2: This Article

The last article in the series presented how the user interface should look like and behave. This article takes the first step towards the implementation. First it will describe the Daisy Patch Hardware Abstraction Layer which provides a simplyfied way to interact with the hardware. Afterwards we will use the abstraction layer to implement a small example application reading the encoder and writing on the screen.

Daisy Patch Abstraction Layer
#

Electrosmith provides libraries with abstraction layers for the different daisy hardware variants. The hardware abstraction for the daisy patch is implemented in the class daisy::DaisyPatch. It has the attribute display of type OledDisplay<SSD130x4WireSpi128x64Driver> that allows control of the display on the daisy patch. Additionally it has an attribute encoder of type Encoder that provides the mean to read the recent changes of the encoder.

The Class OledDisplay
#

The display is monochrome, that means it only supports two states for each pixel, on and off. All drawing methods in OledDisplay take a boolean parameter for the color, true for white or on and false for black or off. For example, calling Fill(False) clears the display, while Fill(true) turns every pixel on the display on.

The drawing methods provided by OledDisplay don’t communicate with the display immediately. Calling Update finalizes drawing and sends the new data to the display.

The drawing methods used for the implementation are summarized in the table below:

MethodDescriptionArguments
FillFills the screen with the given colorbool on - color
SetCursorMoves the cursor for text output to the given coordinatesuint_16t x - x coordinate
uint_16t y - y coordinate
WriteStringOutputs text starting at the current cursor positionconst char * str - string to write
FontDef font - definition of the font
bool on - color
DrawRectDraws the rectangle defined by the four coordinatesuint_fast8_t x1 - x coordinate for the upper left point
uint_fast8_t y1 - y coordinate for the upper left point
uint_fast8_t x2 - x coordinate for the lower left point
uint_fast8_t y2 - y coordinate for the lower left point
UpdateUpdate the screen

The Class Encoder
#

OledDisplay provides the methods to draw on the screen, but we also need to be able to read the changes of the encoder. This functionality is available in the class Encoder.

Encoder doesn’t get automatically updated on every change, similar to display updates. Debounce receives the changes to the encoder hardware and updates the class. To update all inputs, call ProcessAllControls provided by the class DaisyPatch.

Encoder has several methods to read the encoder state. The methods used in the implementation are summarized below:

MethodDescription
RisingEdgeReturns true if the encoder was just pressed
IncrementReturns 1 if the encoder was turned clockwise
returns -1 if the encoder was turned counter-clockwise
returns 0 if it was not turned
DebounceReads and interprets the raw input. Called by ProcessAllControls

A Simple Example User Interface
#

The prerequisite for following this article is that your development environment for daisy is already set up. If not, follow the setup instructions in the Daisy Wiki. Once the developement environment is set up, we create a new project using the helper.py script from the daisy examples repository.

python ./helper.py -b patch create MyProjects/example_ui

The parameter -b determines the daisy board, in our case that is patch for daisy patch and create is the command which tells the script to create a new project in the given directory. The helper script create a daisy patch program that copies the input from the audio ins to the audio outs.

First we need to change where the inputs are processed. The example application processes inputs in the audio callback, which we want to move from the audio handler to the loop in main. Delete the line hw.ProcessAllControls(); from the function AudioCallback. Next we’ll change the endless loop so that it first processes the controls, then draws on the display and finally waits for 1 ms.

Add the following in the while loop in main:

// Read the input from the patch and update the hardware abstraction layer
hw.ProcessAllControls();

// Move the cursor to position 0, 0
hw.display.SetCursor(0, 0);

// Check the direction of the controller
if (hw.encoder.Increment() == -1) {
 // Write counter-clockwise because the controller was rotated
 // counter-clockwise
 hw.display.WriteString("counter-clockwise", Font_7x10, true);
} else if (hw.encoder.Increment() == 1) {
 // Write clockwise because the controller was rotated clockwise.
 // Note that we pad the string with spaces so that it is the same
 // length as counter-clockwise because we do not clear the display.
 hw.display.WriteString("clockwise        ", Font_7x10, true);
}

// Check if button was pressed
if (hw.encoder.RisingEdge()) {
 // Move below the other text
 hw.display.SetCursor(0, 11);
 // Print button pressed
 hw.display.WriteString("Button pressed", Font_7x10, true);
}

// Paint
hw.display.Update();

// Wait for 1 ms
hw.DelayMs(1);

Afterwards prepare the daisy for flashing by pressing the reset and the boot button and the excute the task build_and_program_dfu in vs code. Initially the screen will be blank. When rotating the encoder, the screen will display clockwise or counter-clockwise depending on the direction the encoder was rotated recently. When the encoder is clicked the screen will also display Button pressed.

The code can be found on github.

null
Building Digi Env - This article is part of a series.
Part 2: This Article