chipKIT

Introduction

Inspired by and compatible with a number of 8-bit Arduino development boards, the chipKIT development boards from Digilent keep with the open source nature but feature a much more powerful 32-bit processor at its core compared to the original Arduino line. Please see this video for a brief overview of chipKIT, which features two of the older boards, Max32 and Uno32:

Please read on to learn more about various chipKIT boards and accessories:

Boards

Wi-FIRE

My first chipKIT board was the Wi-FIRE, which I bought from eBay for just £20 and it came with the Basic I/O Shield (please see the dedicated section on this page for more information) and a number of cables, so I had everything I needed to get started, bundled together in a single box, with apparently very little use. When you are used to the less powerful (but of course still very useful) Arduino Uno and Mega, for example, the Wi-FIRE, which is Arduino compatible, crams a lot more power and features on to the board. The Arduino compatibility means that an Arduino software environment can be used to program the board, allowing the reuse of existing software with little or no modification, and a range of shields (such as designed for the Arduino Uno form factor) will work provided they are 3.3V compatible (the chipKIT Basic I/O Shield being a good example). This is something to keep in mind when connecting any components to the Wi-FIRE: do not apply more than 3.3V to any signal pins otherwise the board could be damaged.

As mentioned, the Wi-FIRE can be programmed using familiar Arduino tools- the Arduino IDE (or a modified version, this is discussed later on), and the mini USB connection on the board, an approach that will be to most people's liking, at least initially, as to get acquainted with the board and its features. The board can also be programmed using Microchip's own methods (PICkit 3 and MPLAB X IDE), something I go into later on, and gives much more control of the Wi-FIRE.

You can view Digilent's product page for the Wi-FIRE at:

https://digilent.com/reference/microprocessor/wi-fire/start

The page lists some key information, and has links for various documentation including key chip product pages and schematics for the various board revelations. Speaking of revisions, look on the underside of the board under the barcode for the revision marking. Revision B was the first revision (from 2014 it seems), followed by C (which appears to be similar to B, and is the one I have), and lastly, revision D, which made some changes to the board layout.

The board features a PIC32MZ2048EFG100 microcontroller clocked at 200 MHz, along with 512KB RAM and 2MB Flash, which gives plenty of opportunity to make complex and powerful programs. The on-board MRF24 WiFi module makes wireless connection a breeze and coupled with the micro SD card slot makes it's easy to store configuration settings or data logs to be remotely accessed. There are four user LEDs, two push-buttons switches, one potentiometer trimmer, and both USB-A and micro USB 2.0 OTG sockets on the PCB, giving plenty to work with for experimentation. There are in total 43 I/O pins made available via the various board headers, the connections at the the board edge are compatible with an Arduino Uno 3.3V shield while the inner one grant access to the additional I/O provided by the PIC32.

For more of the board's features you can read about them in the above linked site and in the reference manual:

Revision C can be found at:

https://digilent.com/reference/_media/chipkit_wifire/chipkit_wi-fire_rm_revc.pdf

Revision D:

https://digilent.com/reference/_media/reference/microprocessor/wi-fire/wi-fire_rm_revd.pdf

To program the board using Arduino code you can take advantage of the built-in bootloader and a special version of the Arduino IDE that supports PIC32 called MPIDE (Multi-Platform Integrated Development Environment). It can be downloaded from:

https://digilent.com/reference/software/mpide/start

The download link to the right.

Note that revision B and C use a mini USB port for connecting to a computer, revision D has a micro USB connector, same as the OTG socket.

I downloaded the most recent version, 0150 from 2015 of MPIDE but running the mpide.exe file caused a splash screen to appear but nothing else, even after trying compatibility settings right back to Windows 7. So I tried an old version of the Arduino IDE V1.6.5, following this tutorial:

https://chipkit.net/wiki/index.php?title=How-To_Install_chipKIT_Core

I selected 'chipKIT WiFire' as the board, rev c was already selected under Version. I tried the Blink example, but when compiled I got this error:

pic32-g++.exe: error:\Temp\build7419583985414058794.tmp/core.a: No such file or directory

(Filename shortened to obscure.)

It turns out that support for PIC32 has been moved to the Digilent Core, which permits standard, recent versions of the Arduino IDE to work with PIC32 boards, please see this site:

https://digilent.com/reference/learn/software/tutorials/digilent-core-install/start

Note that you can just search for 'Digilent Core' in the search box in the Boards manager.

However, after installing the Digilent Core and selecting my board I got the same error when compiling a sketch.

I did also try using the Digilent Core in Arduino IDE V2.1.1, which is the Arduino IDE I normally used and being a more recent version I thought I'd give it a try but after installing the Digilent Core and selecting 'chipKIT WiFire(Rev C)' as the board (under Digilent Core) and trying to upload the classic Blink example I eventually got this error:

TimedOut waiting for Serial Response

Unable to signon, this does not look like a bootloader

Thus, the previous owner of my board must have programmed their own bootloader or other code, which resulted in my issues trying to upload a sketch to the Wi-FIRE.

It would appear that the board should have come with the Arduino bootloader as standard, as confirmed on this site:

https://chipkit.net/archive/58

However we can restore the Arduino bootloader as it says on the previously linked site:

'You will have to import the .hex file and do a "program" (not debug program) to restore the original bootloader.'

Fortunately, I already had a PICkit 3, which is required to put the Arduino bootloader back on the board, and in the box that my Wi-FIRE came in were two cables labelled 'PIC 3' along with male header pins, which can be pushed into each end of one of the cables, to allow insertion into JP1 (ICSP) of the board and the other end into the PICkit 3's header. I made sure that the marking on each end of the cable lined up with pin 1 on the board (the square hole) and pin 1 on the PICkit 3 (arrow) respectively. A clever design is that the JP1 holes are staggered, so a connector can be inserted without soldering.

When I plugged the PICkit 3 into my PC, no lights on the board come on but Windows detected the PICkit 3 and installed it.

I downloaded the Arduino bootloader from:

https://digilent.com/reference/microprocessor/wi-fire/start

The link is on the right side of the page. The download needs extracting, revealing a hex file called chipKIT-WiFire-EF-v01000303.hex, that can be programmed to the board using MPLAB IPE, which comes as part of MPLAB X IDE. This is how I did it:

In MPLAB's drop-down for 'Device' I selected 'PIC32MZ2048EFG100' and clicked the Apply button.

The PICkit 3 was showing in the 'Tool' drop-down so I clicked the 'Connect' button, which produced some information in the Output window. This is what I got:

Connecting to MPLAB PICkit 3...


Currently loaded firmware on PICkit 3

Firmware Suite Version.....01.33.20 *

Firmware type..............PIC18F

Now Downloading new Firmware for target device: PIC32MZ2048EFG100

Downloading bootloader

Bootloader download complete

Programming download...


Downloading RS...

RS download complete

Programming download...


Downloading AP...

AP download complete

Programming download...



Currently loaded firmware on PICkit 3

Firmware Suite Version.....01.56.09

Firmware type..............PIC32MZ

Programmer to target power is enabled - VDD = 3.250000 volts.

Target device PIC32MZ2048EFG100 found.

Device ID Revision = A1

DEVSN0 = 39784df9

DEVSN1 = e497d880


It looks like it automatically downloaded firmware to the PICkit 3 perhaps so that it can handle the selected device to be programmed.

To test the connection between the Wi-FIRE and the PICkit 3 I clicked the Read button, which read in the 2MB of the microcontroller's flash, it took a few minutes before coming back with:

The following memory area(s) will be read:

program memory: start address = 0x1d000000, end address = 0x1d1fffff

boot config memory

configuration memory

Read complete


If you want to be able to make a copy of the data read in then you need to enable Advanced Mode then you can go to File->Export->Hex.

You can also click the 'Blank Check' button to check if the microcontroller's flash is blank, which it reported it wasn't.

To program the bootloader I did the following:

I clicked the 'Browse' button in the Hex File section and selected the bootloader hex file previously downloaded, and then clicked the 'Program' button, the programming took about 15 seconds because the bootloader is small. This is what I got in the Output window:

The following memory area(s) will be programmed:

boot config memory

configuration memory

Programming/Verify complete

2023-10-26 21:02:18 +0100 - Programming complete

***   Hold In Reset mode is enabled   ***


At this point I closed MPLAB and disconnected the PICkit 3 from my PC and the Wi-FIRE. To test that the Arduino bootloader had indeed installed correctly on the Wi-FIRE I plugged a mini USB cable into the board and my PC and noticed that LD1 on the Wi-FIRE flashed rapidly, perhaps a built-in 'hello world' of sorts. The real test was to attempt to upload a sketch, in the Arduino IDE (V2.1.1) I selected the board as part of the Digilent Core and by default it was set to rev c, which matches my board, I also selected the COM port the board had appeared as in the Device manager. I was able to upload the Blink example, which flashes LD1 on/off (at a different speed to the test one that came with the bootloader), note that LD1 is equivalent to the on-board LED connected to digital pin 13, as found on the Arduino Uno, etc. While a sketch is being uploaded to the Wi-FIRE, LD5 and LD6 will rapidly flash.

I will now go through various sketches I used on the Wi-FIRE:

AnalogInOutSerial

Next, I tried out the AnalogInOutSerial (Analog->AnalogInOutSerial) built-in Arduino example but as the Wi-FIRE features an on-board trimmer connected to digital pin 48, the sketch can be modified to take advantage of it by change the value of analogInPin from A0 to 48. An LED can be connected via a limiting resistor as described in the sketch, from digital pin 9 to GND, on the WiFIRE, which has additional connector blocks to an Arduino Uno, Pin 9 is on the outer connector.

The sketch worked as expected, in the Serial monitor the sensor and output values are continually displayed, Sensor (sensorValue) is the actual value read from the trimmer, output (outputValue) is the converted PWM value applied to the LED. With the trimmer turned all the way to max the values will be 4095 and 1020, and the values will decrease as you turn left until reach zero when the minimum trimmer position is reached.  Turning the trimmer will cause the LED to become brighter/dimmer but at very low values the LED may flicker, which is to be expected due to PWM frequency issues. Note that you don't need the Serial monitor open to be able to adjust the LED brightness, only to see the sensor and output values.

CardInfo

For testing the on-board micro SD card slot I used the CardInfo example (SD->CardInfo), which only needed one modification: in the sketch change chipSelect_SD_default from 10 to 52. After uploading the sketch, I entered the Serial monitor and saw SD card information and file listing after a few moments (note: files are in 8.3 filename format). When using a SanDisk Ultra 32GB it reported the volume size (bytes) to be 1837629440 but for the SanDisk 4GB the value was -338165760, both clearly wrong. Because only 32 bits are used to store the volume size, the 32GB card value gets truncated, and the issue with the 4GB card is possible due to overflow causing the number to become negative, as a signed long has been used to store the volume size. These faults have been fixed in an updated version of the standard SD card library, but not in the Digilent Core version of the library, but of course we could transfer over the fixes.

A last thing to add is that whether the SD card is full or empty you will see listed two system files, WPSETT~1.DAT and INDEXE~1, in the Serial monitor.

Datalogger

A good use of the SD card is to log to file a reading, such as from a sensor, so I adapted the built-in Datalogger example (SD->Datalogger) so that it just logs the on-board trimmer value, you can find the resulting sketch for download at the bottom of this page named 'Datalogger.ino'. BTN1 is pressed to start logging to the SD card in a file called datalog.txt, and LD1 will turn on, to stop logging press BTN2, which will also turn LD1 off. Every time BTN1 is pressed after the sketch first starts or after pressing BTN2, a log count value is written before the trimmer value, this increases every time BTN1 is pressed, starting at 1. If there's an error trying to access the datalog.txt file on the SD card then LD2 will light, but will be off if there are no issues with the file. LD3 will be lit if an SD card has been detected but will be off if no SD card is present (or is faulty and cannot be initialised).

In setup() we do the usual pinMode() for the inputs (BTN1 and BTN2), and outputs (LD1 to LD3) and set the default state of the LEDs before trying to initialise the SD card by calling initSD_card() - ignore the if statement, that's a mistake, as originally I used the function's return value to do something. In initSD_card() we return true/false whether the SD card was initialised or not, and output useful error text to the Serial monitor accordingly, and light or turn off LD3 if an SD card was detected or not.

In loop() we look to see if BTN1 has been pressed but that logging to file isn't already running, which would be the case if logEn is true, otherwise we try to open the file for access by calling openFileSD_card(). The function openFileSD_card() will try to open the file with SD.open() and create one if it doesn't already exist, and if successful, text is printed to the Serial monitor, LD1 will light to show logging is in progress and LD2 will switch off as there was no file error. The logCount variable is increased by 1 (as it was initialised to 0, the first log count value recorded will be 1), and the log count is written to file with dataFile.println(). A return true signifies that the file was opened but if there was a fault then the Serial monitor will be updated accordingly and the function will return false.

Back in loop(), if openFileSD_card() returns false then LD2 will light, but if the file was opened then logEn is set to true, which will cause logging to start shortly. Next, in loop(), we check if BTN2 has been pressed and if so the file that was previously opened is closed by executing closeFileSD_card(), and setting logEn to false and turning LD1 off. We should really first check if logEn is true but there's no harm otherwise. Lastly in loop() we call logValueToSD_card() which makes sure that logEn is true (we are good to log) and dataFile is valid, that is, the logging file was previously opened. If they pass, we dump the current trimmer value to the serial port with Serial.println(), and to the SD card file using dataFile.println().

It's worth mentioning that a flaw with this sketch is that the log count always starts on 1 so if you power cycle or enter the Serial monitor again the log count will reset to 1, I plan to return to the sketch at a later date and change it to record the current date and time, which could be acquired with Wi-Fi access.

The Wi-FIRE is a powerful, versatile board that I have only scratched the surface of and no doubt will return to at a later date to properly take advantage of its many capabilities. Be sure to have a read of the Basic I/O Shield section, as the shield is compatible with the Wi-FIRE , extending its abilities.

Shields

Basic I/O Shield

The chipKIT Basic I/O Shield appears to be from 2011 and is compatible with a number of boards including Uno32, uC32, Max32, and Wi-FIRE, the latter being the one I will mention in relation to the shield in this section as it was the board I got with it (please see the Wi-FIRE section on this page). The Basic I/O Shield provides 8 switches (push button and slide), 8 LEDs, TCN75A temperature sensor, 256Kbit EEPROM, 128×32 pixel monochrome graphic OLED display, and 4 high-current open-drain FET drivers. It would have been nice to have included a RTC (Real-Time Clock) but nonetheless a lot is packed on the shield and everything is labelled including the digital pin number, which relates to the Arduino numbering. This is the approach that will be used in this section as I programmed my Wi-FIRE with the Arduino bootloader but the shield of course could also be programmed using Microchip's tools with a suitable board.

There are different revisions of the shield, although revision C seems to be the most common, to find out which one you have look on the shield's underside beneath the barcode.

On the shield are a number of male header pins that extend downward to fit with the Wi-FIRE (or other board) headers and the shield also has female headers for attaching an additional shield or making other connections. Note that the shield takes advantage of the additional I/O provided by the Wi-FIRE since it has double row headers on one side.

To plug the shield into the Wi-FIRE line up the male headers pins with the Wi-FIRE's female header pins such that J3 of the shield lines up with J8 of the Wi-FIRE, and J2 with J10. When plugging the shield in try to apply even pressure to each side, and note that the shield doesn't go in all way, there is a significant gap between the shield and the Wi-FIRE. The shield is smaller than the Wi-FIRE and blocks its LEDs  and the trimmer, so just as well the shield has them too. Fortunately, we can still see the Wi-FIRE's LD5 and LD6, which are active when data is being sent over the serial connection.

The revision C shield reference manual can be found at:

https://digilent.com/reference/chipkit_shield_basic_io_shield/refmanual

This goes into a decent amount about the various features of the shield.

You can also view the revision C schematic at:

https://www.microchip.com/content/dam/mchp/documents/OTH/ProductDocuments/BoardDesignFiles/chipKIT_Basic_IO_schematic.pdf

To test the shield with the Wi-FIRE I wrote a number of sketches:

Basic_IO_Shield_Blink1

This sketch simply switches the shield's on-board 8 LEDs on and off every 1 second, the sketch is called Basic_IO_Shield_Blink1.ino and can be downloaded from the bottom of this page. The sketch is straightforward enough, in setup() we set digital pins 26 to 34 representing the 8 LEDs to outputs using a for loop and then using another, similar loop, switch them off. In loop() we use another for loop to switch all 8 LEDs on, wait a second, switch all the LEDs off, and wait another second.

Basic_IO_Shield_Blink2

The next sketch, Basic_IO_Shield_Blink2.ino, is a very simple adaptation of the previous sketch, by adding a delay to each for loop for turning on and off the LEDs, so that they change state gradually. The download link is at the end of this page.

Basic_IO_Shield_LED_Pattern

The sketch, downloadable from the bottom of this page and named Basic_IO_Shield_LED_Pattern.ino, builds on Basic_IO_Shield_Blink2 by letting the user press one of the four push button switches on the shield to change the LED pattern, as follows:

BTN1: all LEDs switch on/off at once (same as the default pattern).

BTN2: the LEDs turn on and off in sequence from first to last until all are on, all switch off from first to last, and repeat.

BTN3: similar to pressing BTN2 but the LEDs switch on/off increasingly slowly.

BTN4: all LEDs switch on at once then each LED from first to last switches off increasingly faster. 

Note: you need to hold the button until the complete pattern has finished as the buttons aren't checked until after the pattern has completed, this of course could be fixed by avoiding for loops when updating the LEDs.

In setup() the 'pattern' push button switch pins are set as inputs, and the LEDs as outputs, which are switched off. In loop() we first call checkForPatChange(), which tests each push button in turn and updates the variable current_pattern with the value 1, 2, 3, or 4 based on the chosen pattern.

Back in loop(), updatePattern() is called which simply checks the value of current_pattern and calls exePattern1(), exePattern2(), exePattern3(), or exePattern4() as appropriate. Of course there are better ways to handle such situations but the code is at least easy to follow and these sketches are just rough code I put together quickly. Each of the exePatternX() functions make use of turnAllLEDs_onOrOff(), passing whether to turn the LEDs on or off as the first parameter (use HIGH or LOW respectively), the delay before updating each LED as the second passed value (use 0 for no delay), and the delay multiplier value as the third parameter (which can be negative), which progressively increases the delay between each LED being updated.

I2CMasterEEPROM

The shield has a 256Kbit I2C EEPROM type 24LC256 and to test it out I used the Arduino IDE's built-in example I2CMasterEEPROM (DTWI->I2CMasterEEPROM). But for the sketch to work you will need to uncomment:

#define I2CADDR 0x50

and comment out:

#define I2CADDR 0x44

This is because the EEPROM has an address of 0x50.

When you open the Serial monitor after uploading the sketch and when prompted to press BTN to query the EEPROM you press BTN1 on the Wi-FIRE (should just be able to reach it under the shield). Then, 64 bytes will be written to the EEPROM and then read back and displayed. Confusingly, the sketch writes to EEPROM from memory address 0x10 rather than 0x00, which causes a wrap around, this is explained in the sketch and is used to illustrate the wrap-around effect. In the Serial monitor where the data is read back from the EEPROM (address 0x0), on the 17th byte you will see it matches the first byte written, then the next and so on. The first 16 bytes read back will match the last 16 bytes written.

Temperature

On the shield is a temperature sensor type TCN75A connected on I2C but I couldn't see any suitable built-in example in the Arduino IDE, however, looking online I did find this tutorial which includes suitable code:

https://www.instructables.com/Arduino-Nano-TCN75A-Temperature-Sensor-Tutorial/

We don't need to make any changes to the sketch since the I2C address has already been set correctly to 0x48. When you open the Serial monitor should see current temperature in degrees C and degrees F continually displayed. It initially reported 22.62 C / 72.72 F, which seemed about right for the room I was in. I carefully blew warm air on the temperature sensor and saw the temperature increase by a few degrees C before steadily dropping, so indeed the sketch was working correctly.

Basic_IO_Shield_OLED

The shield features a 128×32 pixel monochrome graphic OLED display type UG-23832HSWEG04 with SSD1306 display controller using SPI, a very handy feature for outputting all manner of information. However, I spent ages trying to find example code that would work with the shield and compile - not being able to use MPIDE on my computer put me at disadvantage (see the Wi-FIRE section on this page).

There is an Arduino library for SSD1306 controller:

https://www.arduino.cc/reference/en/libraries/ssd1306/

However, it uses AVR specific code, not compatible with Wi-FIRE.

So I wrote my own code, which you can download at the bottom of this page, titled Basic_IO_Shield_OLED.ino, and is the minimum codes to get the OLED working and displaying the shield's on-board trimmer value as an example use of the display.

To get me started I used bits of the example code toward the end of this page, Appendix B: Example Driver Code:

https://digilent.com/reference/chipkit_shield_basic_io_shield/refmanual

Another helpful resource for using the SSD1306 is:

https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf

For generating the font I used:

https://www.riyas.org/2013/12/online-led-matrix-font-generator-with.html

However, characters appeared rotated 90 degrees on the OLED from what they should be and I couldn't work out how to rotate the display is software, I did try changing the remap row and column command values but didn't get the results I wanted so I created the font with the characters on their side. The characters are very simple to make designing easier, and appear very small as they are only 8x8 pixels, at a later date I could try a larger size, but small size does mean being able to fit a lot of characters on the display and still be very readable. I only made the numbers 0 to 9 due to time constraints and that's all that's need to display numerical values.

The sketch reads the shield's on-board trimmer value and displays it on the OLED, note that it has leading zeroes to simplifying the code but it wouldn't be difficult to supress them. Push button BTN1 on the shield can be pressed to shutdown the display and stop reading the trimmer, but you can enter the Serial monitor to bring the display back to life. Note that while the display is on, LD1 on the Wi-FIRE will continually flash, this is because LD1 is connected to a microcontroller pin that is also used for SCK, which is the SPI clock, and the display uses SPI.

Let's now look at the sketch in more detail: in setup() we initialise SPI with SPI.begin() and then set up our inputs and outputs (and setting their default state), and lastly we initialise the display by running OLED_init(). In OLED_init() we following a certain order to get the OLED on otherwise it may shorten the life of the display; first enable power to the display's logic circuit, then send Display off command, then reset the display, then send Charge Pump and Set Pre-Charge Period commands, then enable power to the display itself, then send commands to remap columns and rows, and finally we issue the Display On command.

Moving on to loop(), we check to see if we aren't already in shutdown mode (shutdown true) and if not if we detect the shutdown button (BTN1) has been pressed, then shutdown becomes true and OLED_shutdown() is called. In OLED_shutdown() we send the Display off command and then shut off the power to the display and the power to the logic circuit.

Back in loop(), if shutdown isn't in place we read the trimmer value with analogRead(), storing the result in analogVal. In a for loop we go through each digit that makes up analogVal by performing a simple divide and modulo calculation. For each digit we pass the value to OLED_draw_char() to draw the numerical character to the display buffer, also passing the horizontal characer position and the second parameter, and the vertical character position, which is always 0 in this sketch. In OLED_draw_char() we do some checks to make sure the input parameters are in range and then we copy the graphics data that makes up each part of the numerical character from the font. The calculations to index OLED_buffer[] - which is what gets sent to the display later on - and the font array, which is OLED_font[], are complicated and could do with being broken down in a future sketch revision. Starting with OLED_font[], each character takes up 8 bytes and is stored one after another from 0 to 9, so we use (charI * OLED_font_char_byte_total) to get to the start of the numeric character graphics data and add on i to access each byte that makes up the character. The OLED_buffer[] array index is more complicated but essentially is calculating where in the display buffer to start writing to by calculating based on the character X position, charPosX, and how much space a character takes up, offsetting for the current loop value, i, and adding also the character Y position, charPosY, and how much space each line takes up in bytes.

Next, in loop(), OLED_update() is called, which uses a loop to send four page worth of graphics data to the display, and for each page we have to tell it the page number, where in the page we are writing to, and then each byte of OLED_buffer[] is sent to the display, take into account the current page number and where we are in it. So, while OLED_buffer[] doesn't have pages as such, when we send the data to the display we essentially split it up into pages for the display's requirements. Lastly, in loop() we wait 100ms, as that's a good amount of time for the display to seem responsive.

After uploading the sketch you should find that the display shows the current trimmer value, turning the trimmer will cause the number to change as expected, from minimum of 0 to maximum of 4095.

Basic_IO_Shield_FET

The shield has 4 FETs drivers, each one effectively acts as a software controllable switch to GND, which can control loads such as a relay coil, solenoid, motor, etc., utilising clamp diodes to protect the FETs against the effects of switching inductive loads. The FETs are designed for 20V VDS maximum and with a current limit as high as 3A provided they don't run too hot. The FETs can be PWM controlled but for my simple test they are either on or off, controlled by the push button switches on the shield. The sketch is downloadable from the bottom of this page and is named Basic_IO_Shield_FET.ino.

Digital pins 9, 6, 5, and 3 control the FETs, when one of the signals goes high the transistor switches its load on, connecting it to GND. The loads are connected to the FETs using connectors J7 and J8. Connector J6 is used to connect the shield to the external power supply that the load is connected to. If JP1 is fitted (it's not present by default) then 5V can be used for the load instead of an external power supply. If you want a really easy way to test, connect 4 LEDs each with their own limit resistor, common anode connected to 5V from the shield connector and each individual LED cathode connected to 9, 6, 5, and 3 on J8 and J7. Once wired up press BTN1 to toggle load 1 on/off (digital pin 9), BTN2 to toggle load 2 (digital pin 6), BTN3 to toggle load 3 (digital pin 5), and BTN4 to toggle load 4 (digital pin 3).

In the sketch, in setup() we set our switch inputs, and FET outputs and their default state, which is all off. In loop() we check the state of the four push button switches BTN1 to BTN4, making sure that each switch was previously released before responding to it, so that holding down the switch doesn't conrinually toggle the output on/off. We do this by using BTN1_pressed to BTN4_pressed, which defaults to false but becomes true when a switch is pressed, and false again when released. If we have determined that we should respond to the switch press then we turn the FET on or off with digitalWrite() but we pass the inverted current state of the FET output using digitalRead(), which has the effect of switching it off if it was currently on, and vice-versa. At the end of loop() is a 100ms delay which ensures that the switches aren't too responsive.

All content of this and related pages is copyright (c) James S. 2023