KB2040 programming

Programming your KB2040 microcontroller #

Set-Up Procedure #

Alternative KB2040 programming tutorials #

Adafruit’s CircuitPython Tutorials are great if you’re new to this stuff. Please take the time to run through them; it’s an investment worth making. Microcontrollers are not going away soon.

When stuff goes wrong #

The most common problem with microcontrollers is difficulty communicating between the computer and the microcontroller. You might see messages like “Circuit Python device not connected.”

In this case, you should hold down the BOOTSEL button while pressing and releasing the RESET button, to make sure your computer sees the Feather’s CIRCUITPY drive.

You can also try unplugging the KB2040 and plugging it in again and restarting the Mu Editor.

Make sure you are using a cable that can transfer data, not just power. This is the most common source of trouble.

So, how do I make this “code” you mention? #

Start by exploring the CircuitPython tutorial provided by Adafruit, starting at the page Exploring Your First CircuitPython Progarm and working through the next several pages.

Learn the basics of Python syntax at the easy-to-follow Python W3 Schools website.

Then review and bookmark the CircuitPython Essentials page from Adafruit.

Using Mu to run code on your KB2040 #

Save your Python code as the file code.py on your KB2040, and it will start running immediately.

Open the serial monitor in Mu to see any error messages.

To interrupt your KB2040 and stop the code, click within the Serial monitor, and use CTRL-C.

To return the KB2040 to running the code, use CTRL-D in the serial monitor.

Things to know about Python syntax #

  • In Python, a line break (new line) indicates a new command. You might have seen other programming languages use semicolons or parentheses.
  • In Python, indentation (space at the beginning of a line) is very important! To indicate nested or sub-section blocks of code (e.g., of a loop or function), you must use indentation from the left edge of the screen. Python uses whitespace (indentation amount) to determine “scope” — that is, to figure out what blocks of code define other code, or belong within a higher level of code.
  • Use the # symbol to indicate the start of a comment (indicate that certain text is documentation of your code, rather than a command).
# Python interprets this line as a comment.
print(“Hello ME 30!”)

Python variables #

Create a variable by assigning a value to it. Python will automatically determine what type of variable it is (e.g., an integer, a decimal, a string) based on its initial assignment.

x = 30
y = 30.0
address = “200 Boston Ave.”

Python has no command for simply declaring the existence of a variable.

How to see text output by a Python program #

You’ll need to open the serial monitor in the Mu editor.

A few exciting commands in some CircuitPython-specific libraries #

Here are some Python commands that you might want to start with. To use all but the print() command, you need to start your Python code by importing the libraries specified below (TIME, BOARD, DIGITALIO, PWMIO, ANALOGIO).

print(): Prints the value of whatever variable is listed inside the ().

print(“[string]”): Prints exactly the text included inside the (“ “)

To see the text generated by print(), be sure the serial monitor in your Mu Editor is open.

print(([variable],)): With the extra parentheses and comma, creates a “tuple” (a pair of values) that the Mu editor will show on its x-y plotter

To see the points generated by print(([var],)), be sure the plotter in Mu is open.

TIME library #

To use this command, include the command “import time” at the start of your code.

time.sleep(N): do nothing for N seconds

time.monotonic(): returns the current time in seconds, related to some unknown reference time

BOARD and DIGITALIO library #

To use these commands, include the command “import board” and “import digitalio” at the start of your code.

dir(board): spits out the names of the all the pins available on your Feather

xyz = digitalio.DigitalInOut(board.[pin name or number]): calls up the digitalio library and creates a new object called xyz that will hold information about a specific pin on a microcontroller board. The pin names and numbers are on the board’s pinout diagram, e.g, D6, D5, LED, etc.

xyz.direction = digitalio.Direction.OUTPUT: tells the KB2040 to treat the pin for object xyz as a voltage output, not an input

xyz.direction = digitalio.Direction.INPUT: tells the KB2040 to treat the pin for object xyz as a voltage input

xyz.value: the voltage value at the pin for object xyz

xyz.value = 1: sets the voltage at the pin for xyz to be “high.” For the KB2040, that’s 3.3 V

xyz.value = True: another way to set the voltage high

xyz.value = 0 sets the voltage for the digital variable xyz to be “low,” i.e., ground or 0 V

xyz.value = False: another way to set the voltage low

Here’s an example of how you might use commands from the board and digitalio libraries to set the voltage at pin D4 high (True), then low (False), and repeat.

import board
import digitalio
import time

led = digitalio.DigitalInOut(board.D4)
led.direction = digitalio.Direction.OUTPUT

while True:
    led.value = True
    led.value = False

PWMIO library for motor speed control #

To use these commands, include the command “import pwmio” at the start of your code.

xyz = pwmio.PWMOut(board.[pin name or number], frequency =[initial PWM frequency], duty_cycle=[initial PWM duty cycle])

creates a new object called “xyz” that will hold all the information about sending out pulse-width modulation at a particular pin

xyz.duty_cycle = 32000

at whatever KB2040 pin belongs to the PWM object xyz, changes the duty cycle of the PWM voltage to 32000. For the RP2040 chip on the KB2040, the duty cycle maximum is 65535; max duty cycle means the output is high 100% of the time.

What is the difference between frequency and duty cycle in PWM?

  • Frequency: This CircuitPython parameter refers to the number of motor control cycles (voltage pulse initiations) per second Set this to 500 for the KB2040, because its main processing chip can handle outputting that many cycles per second.
  • Duty_cycle: This CircuitPython parameter refers to the duration of time within one motor control cycle at which the voltage is ON or HIGH (i.e., 3.3 V).

For the KB2040, a duty cycle value of 65536 corresponds to the voltage being turned on for 100% of the cycle, which means the motor gets 100% of the voltage available to it.

Because 50% of 65536 is about 32800, a duty cycle of about 32800 corresponds to the voltage being set high for 50% of the cycle, or the motor getting about 50% of the voltage available to it. The motor will spin at half speed.

A duty cycle of about 6500 corresponds to the voltage being set high for 10% of the cycle, or the motor getting about 10% of the voltage available to it. The motor would spin at 10% speed IF that is enough voltage to overcome its internal friction (you’ll probably find that it’s not enough voltage for the motor to turn at all).

Here is some sample CircuitPython code that uses PWM to run a motor first at full speed, then at half speed, and then at quarter speed. Note that we have to import the pwmio library to run this code, and we have to initiate a pin as a pwmio.PWMOut pin.

import board
import pwmio
import time

my_control_pin = pwmio.PWMOut(board.D6, frequency=500, duty_cycle=0)
# creates a new object called “my_control_pin” that will hold all 
    # the information about sending out 
    # pulse-width modulation at pin D6

while True:
    my_control_pin.duty_cycle = 65535
    my_control_pin.duty_cycle = 32800
    my_control_pin.duty_cycle = 16400

ANALOGIO library #

xyz = analogio.AnalogIn(board.A1): creates an object called xyz and connects xyz to A1 as an analog input.

The code below will plot the value of the voltage coming in at analog input pin A1.

import time
import analogio
import board

inputvoltage = analogio.AnalogIn(board.A1)

while True:

Sensors #

If you want to program more specialized devices like stepper motors or particular sensors, you may need to download additional CircuitPython libraries (that don’t come with CircuitPython uf2 file itself) onto your KB2040. You can learn about how that works at the Welcome to CircuitPython libraries page

The full set of CircuitPython libraries for the KB2040 can be downloaded here.

NOTE: We recommend downloading the entire bundle to your laptop, and then transferring ONLY the libraries you need to your KB2040. Transferring the entire bundle to your KB2040 will take quite a long time.

For distance sensor reading, check out this page to see what libraries you need.

Stepper Motors #

For stepper motor control, you’ll need the adafruit_motor library (and two H-bridges). All CircuitPython libraries for the KB2040 can be downloaded here. Download the entire library bundle to your laptop, and then transfer ONLY the libraries you need to your KB2040.

You can find helpful stepper motor wiring diagrams here.

State Machine Code #

Often when using a microcontroller within a electromechanical system, you need to be able to check for the state of inputs while also running motors, lights, and other actuators. Writing code for “state machines” is a useful technique for this situation. At this link is one way to set up state machines in CircuitPython. This code flashes an LED, constantly checks for a button press, and flashes a different LED when the button is pressed.

CircuitPython Reference Pages #

If you want to check the details of these functions or see what else is available, the canonical reference is the CircuitPython Essentials page.