1+ /*
2+ © [2025] Microchip Technology Inc. and its subsidiaries.
3+
4+ Subject to your compliance with these terms, you may use Microchip
5+ software and any derivatives exclusively with Microchip products.
6+ You are responsible for complying with 3rd party license terms
7+ applicable to your use of 3rd party software (including open source
8+ software) that may accompany Microchip software. SOFTWARE IS ?AS IS.?
9+ NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS
10+ SOFTWARE, INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT,
11+ MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
12+ WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,
13+ INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY
14+ KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF
15+ MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE
16+ FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP?S
17+ TOTAL LIABILITY ON ALL CLAIMS RELATED TO THE SOFTWARE WILL NOT
18+ EXCEED AMOUNT OF FEES, IF ANY, YOU PAID DIRECTLY TO MICROCHIP FOR
19+ THIS SOFTWARE.
20+ */
21+ /**
22+ * I2C_HOST EXAMPLE Generated Driver File
23+ *
24+ * @file i2c_host example.c
25+ *
26+ * @ingroup i2c_host example
27+ *
28+ * @version I2C_HOST EXAMPLE Example Version 1.0.0
29+ *
30+ * @brief Generated file for
31+ * Example: 3. I2C IO Expander 2 - LEDs and Buttons
32+ * Implementation: Interrupts with callbacks
33+ * Visualization: Printf
34+ * MCU Device family: AVR
35+ */
36+
37+ #include "mcc_generated_files/system/system.h"
38+ #include <util/delay.h>
39+
40+ // Note: MCP23008 - 8-Bit I2C I/O Expander with I2C (& SPI) Serial Interface(s)
41+ // Reference to the MCP23008 data sheet: https://www.microchip.com/DS20001919
42+ // MCP23008 register addresses are in Table 1-2 (page 5) of the data sheet
43+ // The Curiosity Nano Explorer (EV58G97A) has 2 x MCP23008 IO Expanders
44+
45+ #define MCP23008_1_I2C_ADDRESS 0x25
46+ #define MCP23008_2_I2C_ADDRESS 0x24
47+
48+ #define MCP23008_IODIR 0x00
49+ #define MCP23008_IPOL 0x01
50+ #define MCP23008_GPINTEN 0x02 // INTERRUPT-ON-CHANGE CONTROL (GPINTEN) REGISTER, GPINTEN â?? enables the individual inputs
51+ #define MCP23008_DEFVAL 0x03 // DEFAULT COMPARE (DEFVAL) â?? holds the values that are compared against the associated input port values
52+ #define MCP23008_INTCON 0x04 // INTERRUPT CONTROL (INTCON) - Controls if the input values are compared against DEFVAL or the previous values on the portREGISTER:
53+ #define MCP23008_IOCON 0x05 // IOCON (ODR and INPOL) â?? configures the INT pin as push-pull, open-drain and active-level
54+ #define MCP23008_GPPU 0x06
55+ #define MCP23008_INTF 0x07 // INTERRUPT FLAG (INTF) REGISTER: 1 = Pin caused interrupt
56+ #define MCP23008_INTCAP 0X08
57+ #define MCP23008_GPIO 0x09
58+ #define MCP23008_OLAT 0x0A
59+
60+ void MCP23008_InterruptHandler (void );
61+ void IO_ResetHandler (void );
62+ uint8_t MCP23008_Read (uint8_t i2c_address , uint8_t reg , uint8_t * data );
63+ uint8_t MCP23008_Write (uint8_t i2c_address , uint8_t reg , uint8_t data );
64+ void printButtonPressed (int pressedButton );
65+ void button_led_control (void );
66+
67+ static volatile bool interruptFlag = false;
68+ static volatile bool resetFlag = false;
69+ // All joystick pins re-mapped as they are not connected to Curiosity Nano GPIO by default
70+ static const char * buttonLabels [8 ] = {"J-UP" , "J-LEFT" , "J-DOWN" , "J-RIGHT" , "J-PUSH" , "SW3" , "SW2" , "SW1" };
71+
72+ void MCP23008_InterruptHandler (void )
73+ {
74+ interruptFlag = true;
75+ }
76+
77+ void IO_ResetHandler (void )
78+ {
79+ resetFlag = true;
80+ }
81+
82+ uint8_t MCP23008_Read (uint8_t i2c_address , uint8_t reg , uint8_t * data )
83+ {
84+ uint8_t errorState = I2C_ERROR_NONE ;
85+ size_t txLength = 1 ;
86+ size_t rxLength = 1 ;
87+ uint8_t txBuffer [1 ] = {0 };
88+ txBuffer [0 ] = reg ; // I2C Client register to read from
89+
90+ I2C_Host .WriteRead ((uint16_t )(i2c_address ), txBuffer , txLength , data , rxLength );
91+ while (I2C_Host .IsBusy ())
92+ {
93+ }
94+ errorState = I2C_Host .ErrorGet ();
95+ return errorState ;
96+ }
97+
98+
99+ uint8_t MCP23008_Write (uint8_t i2c_address , uint8_t reg , uint8_t data )
100+ {
101+ uint8_t errorState = I2C_ERROR_NONE ;
102+ size_t txLength = 2 ;
103+ uint8_t txBuffer [2 ] = {0 };
104+
105+ txBuffer [0 ] = reg ; // I2C Client register to write to
106+ txBuffer [1 ] = data ;
107+
108+ // write data over I2C, txLength specifies amounts of bytes from txBuffer
109+ I2C_Host .Write ((uint16_t )i2c_address , txBuffer , txLength );
110+ while (I2C_Host .IsBusy ())
111+ {
112+ }
113+ errorState = I2C_Host .ErrorGet ();
114+ return errorState ;
115+ }
116+
117+ void printButtonPressed (int pressedButton ) {
118+ if (pressedButton >= 0 && pressedButton < 8 ) {
119+ (int ) printf ("Button pressed: %s\n" , buttonLabels [pressedButton ]);
120+ } else {
121+ (int ) printf ("Invalid button pressed\n" );
122+ }
123+ }
124+
125+ void button_led_control (void )
126+ {
127+ uint8_t pressedButton = 0 ;
128+ uint8_t mcp23008_1_LEDs = 0 ;
129+ uint8_t mcp23008_2_Inputs = 0 ;
130+
131+ (uint8_t ) MCP23008_Write (MCP23008_1_I2C_ADDRESS , MCP23008_IODIR , 0x00 );
132+ (uint8_t ) MCP23008_Write (MCP23008_1_I2C_ADDRESS , MCP23008_GPIO , 0x00 );
133+ (uint8_t ) MCP23008_Write (MCP23008_2_I2C_ADDRESS , MCP23008_IODIR , 0xFF ); // Set IO-expander 2 pins as inputs
134+ (uint8_t ) MCP23008_Write (MCP23008_2_I2C_ADDRESS , MCP23008_GPPU , 0xFF ); // Set pull-up for all pins of IO-expander 2
135+ (uint8_t ) MCP23008_Write (MCP23008_2_I2C_ADDRESS , MCP23008_INTCON , 0x00 ); // 0 - Interrupt on change, 1 = If a bit is set, the corresponding I/O pin is compared against the associated bit in the DEFVAL register.
136+ (uint8_t ) MCP23008_Write (MCP23008_2_I2C_ADDRESS , MCP23008_GPINTEN , 0xFF ); // 1 = Enable GPIO input pin for interrupt-on-change event on all pins
137+
138+ (uint8_t ) MCP23008_Read (MCP23008_2_I2C_ADDRESS , MCP23008_INTCAP , & mcp23008_2_Inputs ); // Read INTCAP register to clear IO-expander interrupt
139+ interruptFlag = false;
140+ uint8_t GPINTEN_value ;
141+ (int ) printf ("Default inputs: 0x%02X\n" , mcp23008_2_Inputs );
142+
143+ while (!resetFlag ) // Run until Reset SW is pressed
144+ {
145+ if (interruptFlag ) // if an interrupt on the IO Exapander has occurred
146+ {
147+ interruptFlag = false; // Clear interrupt flag
148+ (uint8_t ) MCP23008_Read (MCP23008_2_I2C_ADDRESS , MCP23008_INTF , & mcp23008_2_Inputs ); // read INTF register to see which button triggered the interrupt
149+
150+ for (uint8_t i = 0U ; i < 8U ; i ++ ) // find out which bit was set and convert it to a position number (0-7).
151+ {
152+ if ((mcp23008_2_Inputs >> i ) && 0x01 )
153+ {
154+ pressedButton = i ;
155+ }
156+ }
157+ mcp23008_1_LEDs = (mcp23008_1_LEDs | (1U << (pressedButton )));
158+ (uint8_t ) MCP23008_Write (MCP23008_1_I2C_ADDRESS , MCP23008_GPIO , mcp23008_1_LEDs ); //Set IO-expander 1 pins low
159+ (uint8_t ) MCP23008_Read (MCP23008_2_I2C_ADDRESS , MCP23008_GPINTEN , & GPINTEN_value ); // Disable Interrupt on pin for pressed button
160+
161+ GPINTEN_value &= ~(1U << pressedButton );
162+ (uint8_t ) MCP23008_Write (MCP23008_2_I2C_ADDRESS , MCP23008_GPINTEN , GPINTEN_value );
163+ (uint8_t ) MCP23008_Read (MCP23008_2_I2C_ADDRESS , MCP23008_INTCAP , & mcp23008_2_Inputs ); // Read INTCAP register to clear IO-expander interrupt
164+
165+ printButtonPressed (pressedButton );
166+ IO_LED_SetHigh (); //Turn off LED when finished.
167+ }
168+ }
169+ }
170+
171+ int main (void )
172+ {
173+ _delay_ms (200 ); // Prevent program running when programming
174+ SYSTEM_Initialize ();
175+ IO_Reset_SetInterruptHandler ((void * ) IO_ResetHandler );
176+ IO_IOExpander2_IRQ_SetInterruptHandler ((void * ) MCP23008_InterruptHandler ); // BUTTON INT pin is the label for the I/O expander 2 interrupt pin
177+ (int ) printf ("Example: 3. I2C IO Expander 2 - LEDs and Buttons, Implementation: Interrupts with callbacks, Visualization: Printf \r\n" );
178+ (int ) printf ("MCU Device family: AVR \r\n" );
179+ (int ) printf ("Press Curiosity Nano Explorer touch buttons and use Joystick to turn off all LEDS. Press SW0 on Curiosity Nano to exit. \r\n\r\n" );
180+
181+ while (1 )
182+ {
183+ IO_LED_SetLow (); // Turn off LED during button_led_control()
184+ button_led_control ();
185+
186+ // Check if the reset flag is set
187+ if (resetFlag )
188+ {
189+ resetFlag = false; // Clear the reset flag
190+ (int ) printf ("Reset flag set, restarting button_led_control() \r\n\r\n" );
191+ }
192+ }
193+ return 0 ;
194+ }
0 commit comments