The FRDM-MCXN947 board comes pre-programmed with an LED blinky demo. This built-in example serves as a quick sanity check to confirm that the board is functioning correctly right out of the box.
Connect a USB Type-C cable from connector J17 on the FRDM-MCXN947 board to your host computer or a USB power supply. This will power up the board and automatically run the pre-programmed demo application.
What to expect: The onboard RGB LED should start blinking at a steady rhythm. This indicates that the board is functioning correctly and the demo firmware is running as expected.
To access the tools required for this project, you'll need to create an NXP account. You can use either your personal or student email address.
Create your account by visiting this page.
Download the latest version of the MCUXpresso IDE from the NXP website.
Make sure to select the installer that matches your operating system (Windows, Linux, or macOS).
Continue clicking "Next" until you reach the install window.
In this step, you may be prompted to install additional drivers during the installation process. Allow these to be installed.
Now launch the MCUXpresso IDE and install the SDK. On the IDE Welcome page, click "Download and Install SDKs".
Search for "mcxn947" and click "Install".
Next, download the MCUXpresso Config Tools, which is a suite of utilities that simplifies the configuration of pins, peripherals, and clocks for your project.
Get the correct installation for the machine you are using.
Accept the "License Agreement" and press "Next" until you get to the installation window.
Congratulations! You have successfully tested the board and installed the required tools!
First, let's create a workspace folder. Launch the IDE and select where you want to locate your workspace. Keep in mind that switching workspaces restarts the IDE.
Close the Welcome page and select "Import SDK example(s)...". Select the correct MCXN947 board and press "Next".
From the Import Wizard, expand the demo_apps section and select the "led_blinky" application. Then press "Finish" and wait for the project to open.
You can see that the project window is split into several sections.
Let's take a look at the code. The top part contains the include files present in the project tree and visible in the Project Explorer tab.
The next section is the SysTick_Handler function that toggles the red LED on the board.
This function is periodically called to switch the LED ON and OFF.
Ctrl + Click on the GPIO_PortToggle function to open the declaration in the fsl_gpio.h header file.
The main function starts by calling the initialization function.
The initialization function can be found in the hardware_init.c file.
This function:
BOARD_BootClockFRO12M() sets the clock frequency to 12 MHzSysTick_Config(12000000UL) sets a counter with a value of 12,000,000 that makes the LED blink once per secondNote: Changing the counter value will increase/decrease the blinking frequency, but it needs to be slow enough for the human eye to notice it.
LED_RED_INIT(LOGIC_LED_OFF) calls GPIO_PinWrite() that changes the output of the GPIO (in this case to the OFF state).
To build a project, select it and then either click on the "Build" icon in the shortcuts or click "Build" in the Quickstart Panel.
The project should finish the build without any errors or warnings in the console.
Make sure your board is connected to the computer through the J17 'MCU-LINK' port.
Download the application to your board by either clicking on the "Debug" icon or clicking "Debug" in the Quickstart Panel.
In the next window, select the MCU-LINK CMSIS-DAP debug probe.
To run the application, press the "Run" icon.
Congratulations! You have successfully built and run your first program on the FRDM-MCXN947!
To begin working on the line follower application, you'll need to import the existing project into MCUXpresso IDE.
Download the project archive: ๐ฆ Download NXP Line Follower Project (ZIP)
.zip) ready before proceeding.Inside the MCUXpresso IDE, go to File and choose the Import option.
In the popup window that will open, expand the General menu and choose the "Existing Projects into Workspace" option, then click "Next".
In the next popup window, select "Select archive file" and browse to the downloaded project .zip file. Then press "Finish".
Now you can build the imported project. Select the project in the Project Explorer and click the "Build" icon or use the Quickstart Panel.
The project should compile without errors. If you encounter any issues, make sure:
Connect your FRDM-MCXN947 board via the J17 MCU-LINK port and follow the same steps as in the LED Blinky demo:
Congratulations! You have successfully imported and run the line follower project!
The line follower robot uses 8 infrared reflective sensors (S10-S17) connected to GPIO pins. These sensors detect the line on the track by measuring the difference in reflectivity between the line and the background surface.
The sensors are connected through the comparators on the shield (U4-U7 LM339), which convert the analog sensor output to digital signals (0 or 1).
Note: The GPIO pins are already configured in the provided project. You don't need to configure them manually.
The project provides 8 inline functions to read each sensor individually. Each function uses the SDK's GPIO_PinRead() to read the current state of the sensor pin.
static inline uint8_t raw_S10(void) {
return GPIO_PinRead(BOARD_INITPINS_S10_GPIO, BOARD_INITPINS_S10_GPIO_PIN);
}
static inline uint8_t raw_S11(void) {
return GPIO_PinRead(BOARD_INITPINS_S11_GPIO, BOARD_INITPINS_S11_GPIO_PIN);
}
static inline uint8_t raw_S12(void) {
return GPIO_PinRead(BOARD_INITPINS_S12_GPIO, BOARD_INITPINS_S12_GPIO_PIN);
}
static inline uint8_t raw_S13(void) {
return GPIO_PinRead(BOARD_INITPINS_S13_GPIO, BOARD_INITPINS_S13_GPIO_PIN);
}
static inline uint8_t raw_S14(void) {
return GPIO_PinRead(BOARD_INITPINS_S14_GPIO, BOARD_INITPINS_S14_GPIO_PIN);
}
static inline uint8_t raw_S15(void) {
return GPIO_PinRead(BOARD_INITPINS_S15_GPIO, BOARD_INITPINS_S15_GPIO_PIN);
}
static inline uint8_t raw_S16(void) {
return GPIO_PinRead(BOARD_INITPINS_S16_GPIO, BOARD_INITPINS_S16_GPIO_PIN);
}
static inline uint8_t raw_S17(void) {
return GPIO_PinRead(BOARD_INITPINS_S17_GPIO, BOARD_INITPINS_S17_GPIO_PIN);
}
Each function:
0 or 1 depending on whether the sensor detects the lineBOARD_INITPINS_Sx_GPIO and BOARD_INITPINS_Sx_GPIO_PIN)The return value depends on your sensor configuration:
1 when line is detected (sensor over black line)0 when line is detected (sensor over black line)The 8 sensors are physically arranged in a line across the front of the robot:
[S10] [S11] [S12] [S13] [S14] [S15] [S16] [S17]
Left โ โ Right
Important: Verify the physical orientation of your sensor array. If S10 is on the right side instead of left, you'll need to account for this in your line following algorithm.
To use these functions in your line following algorithm, simply call them to get the current state of each sensor:
Reading a single sensor:
uint8_t center_left = raw_S13(); // Read center-left sensor
if (center_left == 1) {
// Line detected by S13
}
Reading all sensors:
uint8_t s10 = raw_S10();
uint8_t s11 = raw_S11();
uint8_t s12 = raw_S12();
uint8_t s13 = raw_S13();
uint8_t s14 = raw_S14();
uint8_t s15 = raw_S15();
uint8_t s16 = raw_S16();
uint8_t s17 = raw_S17();
Creating a sensor reading function:
You can create a function that combines all 8 sensor readings into a single byte where each bit represents one sensor:
uint8_t read_sensors(void)
{
uint8_t sensors = 0;
if (raw_S10()) sensors |= (1 << 0);
if (raw_S11()) sensors |= (1 << 1);
if (raw_S12()) sensors |= (1 << 2);
if (raw_S13()) sensors |= (1 << 3);
if (raw_S14()) sensors |= (1 << 4);
if (raw_S15()) sensors |= (1 << 5);
if (raw_S16()) sensors |= (1 << 6);
if (raw_S17()) sensors |= (1 << 7);
return sensors;
}
This compact representation makes it easy to check multiple sensors at once or store sensor history. The returned byte contains: 0bS17_S16_S15_S14_S13_S12_S11_S10
The line follower uses two DC motors controlled by DRV8833 dual H-bridge motor drivers (U2 and U3 on the shield). The motors are controlled using:
Note: The motor driver and PWM are already configured in the provided project. You don't need to configure them manually.
The project provides the HbridgeSpeed() function to control both motors simultaneously.
void HbridgeSpeed(hbridge_t *hbridge, int16_t speed1, int16_t speed2);
hbridge: Pointer to the H-bridge configuration structure (use &g_hbridge)speed1: Speed for motor 1 (range: -100 to +100)
speed2: Speed for motor 2 (range: -100 to +100)
The function:
The absolute value of the speed determines how fast the motor spins, while the sign determines the direction.
The project also provides the HbridgeBrake() function to actively brake both motors.
void HbridgeBrake(hbridge_t *hbridge);
hbridge: Pointer to the H-bridge configuration structure (use &g_hbridge)The brake function:
Braking (HbridgeBrake()):
Stopping (HbridgeSpeed(&g_hbridge, 0, 0)):
Emergency stop:
HbridgeBrake(&g_hbridge); // Actively brake both motors
Quick stop before direction change:
HbridgeSpeed(&g_hbridge, 50, 50); // Moving forward
// Need to reverse quickly
HbridgeBrake(&g_hbridge); // Brake first
delay_ms(100); // Wait for motors to stop
HbridgeSpeed(&g_hbridge, -50, -50); // Now reverse
Stopping at a line intersection:
if (all_sensors_detect_line) {
HbridgeBrake(&g_hbridge); // Quick stop at intersection
}
Use HbridgeBrake() when:
Use HbridgeSpeed(&g_hbridge, 0, 0) when:
Current Draw:
Mechanical Stress:
In the provided project:
This mapping is already configured in the H-bridge initialization. You can use the motors directly without worrying about the physical wiring.
To control the robot's movement, call HbridgeSpeed() with the desired speeds for both motors.
Moving forward:
HbridgeSpeed(&g_hbridge, 50, 50); // Both motors at 50% speed forward
Turning left (differential drive):
HbridgeSpeed(&g_hbridge, 70, 30); // Right motor faster, left motor slower
Turning right (differential drive):
HbridgeSpeed(&g_hbridge, 30, 70); // Left motor faster, right motor slower
Moving backward:
HbridgeSpeed(&g_hbridge, -50, -50); // Both motors at 50% speed reverse
Stopping:
HbridgeSpeed(&g_hbridge, 0, 0); // Both motors stopped
Sharp turn (spin in place):
HbridgeSpeed(&g_hbridge, 50, -50); // Right forward, left reverse = spin left
HbridgeSpeed(&g_hbridge, -50, 50); // Right reverse, left forward = spin right
For line following, you'll use differential drive - varying the speed of the left and right motors to steer the robot.
Basic principle:
Typical line following approach:
Speed Range:
Motor Response:
Control Loop Frequency:
HbridgeSpeed() regularly in your main loopNow that you have:
raw_S10() through raw_S17())HbridgeSpeed())You need to implement the line following algorithm that:
HbridgeSpeed() to steer the robotSuggested approach:
Good luck with your line follower!