Marcel Kruse
Published © GPL3+

The Freedom Infinity Mirror

An infinity mirror, powered by the NXP FRDM-K82F board and awesome Neopixels.

IntermediateFull instructions provided20 hours1,993
The Freedom Infinity Mirror

Things used in this project

Hardware components

FRDM Board
NXP FRDM Board
×1
NeoPixel Ring: WS2812 5050 RGB LED
Adafruit NeoPixel Ring: WS2812 5050 RGB LED
WS2812b LEDs, 125 total
×1
WS2812 LED strip
×1
Real Time Clock (RTC)
Real Time Clock (RTC)
×1
Octal bus Transceiver 74LS245
Used for a stable 5V data-in signal for the Neopixels
×1
Temperature sensor DS1621
×1

Hand tools and fabrication machines

Segger J-LINK debug programmer
Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Schematics

LED schematic

Connect an external LED to the GPIO.

Code

Tutorial - GPIO/LEDs

C/C++
Code for controlling:
- the Build in RGB LED
- an External LED
- GPIO usage
- printf functionality

add the following lines in pin_mux.c
---
// GPIO for the build-in RGB LED
PORT_SetPinMux(PORTC, 8U, kPORT_MuxAsGpio);
PORT_SetPinMux(PORTC, 9U, kPORT_MuxAsGpio);
PORT_SetPinMux(PORTC, 10U, kPORT_MuxAsGpio);

// GPIO for the external GPIO LED
PORT_SetPinMux(PORTC, 11U, kPORT_MuxAsGpio);
/*
 * Copyright (c) 2013 - 2016, Freescale Semiconductor, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * o Redistributions of source code must retain the above copyright notice, this list
 *   of conditions and the following disclaimer.
 *
 * o Redistributions in binary form must reproduce the above copyright notice, this
 *   list of conditions and the following disclaimer in the documentation and/or
 *   other materials provided with the distribution.
 *
 * o Neither the name of Freescale Semiconductor, Inc. nor the names of its
 *   contributors may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/**
 * This is template for main module created by New Kinetis SDK 2.x Project Wizard. Enjoy!
 **/

#include "board.h"
#include "pin_mux.h"
#include "clock_config.h"
#include "string.h"
#include "fsl_debug_console.h"
/*!
 * @brief Application entry point.
 */

// a variable delay function for a delay in seconds
void delay_s(uint16_t t) {
	volatile uint32_t i = 0;
	volatile uint32_t delay_t = 8000000 * t; // change to 8000 for ms delay
	for (i = 0; i < delay_t; ++i) {
		__asm("NOP");
	}
}

int main(void) {
  /* Init board hardware. */
  BOARD_InitPins();
  BOARD_BootClockRUN();
  BOARD_InitDebugConsole();

  /* Add your code here */

  // gpio config for output
  gpio_pin_config_t pin_config_output = {kGPIO_DigitalOutput, 1};

  // Set the GPIO pins as output
  GPIO_PinInit(GPIOC, 8U,  &pin_config_output);	// rgb led red
  GPIO_PinInit(GPIOC, 9U,  &pin_config_output); // rgb led green
  GPIO_PinInit(GPIOC, 10U, &pin_config_output); // rgb led blue
  GPIO_PinInit(GPIOC, 11U, &pin_config_output); // external LED

  // print the text "hello world" in the console,
  // connect the K82F and go to your PC's device manager, check on which COM port your board is connected.
  // download and install 'Putty', open a new session, by clicking the serial-radiobutton, fill in the COM port and use 115200 as speed. Open it and your board can now 'speak':)
  printf("hello world");


  for(;;) // this will make an infinite loop
  {

		// white buildin RGB
		GPIO_WritePinOutput(GPIOC, 8u,  0); 	// light up red color
		GPIO_WritePinOutput(GPIOC, 9u,  0); 	// light up Green color
		GPIO_WritePinOutput(GPIOC, 10u, 0); 	// light up blue color to make the RGB led shine White.

		// wait for 5 seconds
		delay_s(5);

		// turn off all colors
		GPIO_WritePinOutput(GPIOC, 8u,  1);
		GPIO_WritePinOutput(GPIOC, 9u,  1);
		GPIO_WritePinOutput(GPIOC, 10u, 1);

		// wait for 1 second
		delay_s(1);

		GPIO_WritePinOutput(GPIOC, 8u,  0);		// turn on  Red
		delay_s(1);
		GPIO_WritePinOutput(GPIOC, 8u,  1);  	// turn off Red
		GPIO_WritePinOutput(GPIOC, 9u,  0);		// turn on  Green
		delay_s(1);
		GPIO_WritePinOutput(GPIOC, 9u,  1);  	// Turn off Green
		GPIO_WritePinOutput(GPIOC, 10u, 0);  	// turn on  Blue
		delay_s(1);
		GPIO_WritePinOutput(GPIOC, 8u,  1);   	// turn off Blue

		delay_s(1);

		GPIO_WritePinOutput(GPIOC, 11u, 0);  	// turn on external led
		delay_s(2);
		GPIO_WritePinOutput(GPIOC, 11u, 1);  	// turn off external led
		delay_s(2);


  }// for loop, endless so it will start again
} // end of main.c

WS2812b.c

C/C++
This will include different functions which can be called from the main.c.
#include "board.h"
#include "pin_mux.h"
#include "clock_config.h"
#include "string.h"
#include "fsl_debug_console.h"
#include <stdint.h>
#include "MK82F25615.h"
#include "WS2812b.h"

// note;  if you make use of an external power supply, which I recommend make sure that the ground between the FRDM K82F and external power supply is shared!
// in this case the Neopixels/WS2812 Leds are connected to GPIO C, pin 12.
#define GPIO_LED 	GPIOC
#define PIN_LED 	12U



#define DELAY_10nS  __asm("NOP");
#define DELAY_100nS __asm("NOP");__asm("NOP");__asm("NOP");__asm("NOP");__asm("NOP");__asm("NOP");__asm("NOP");__asm("NOP");__asm("NOP");__asm("NOP");

int totalLEDs 		= 126; 		// amount of total Neopixels, one extra for extra data package
int innerCircleLEDs = 60;
int outerCircleLEDs = 65;
// GPIOx,  pin XX, amount of Neopixels
void SendNeopixelData(GPIO_Type *base, uint32_t pin, uint32_t *data, int length)
{
	int bitcount;
	uint32_t dataWord;
	uint32_t pinMask = 1U << pin;

	while (length > 0)
	{
		bitcount = 23;
		dataWord = *data;
		while (bitcount>0)
		{
			if (dataWord & 0x0800000U) {
			    base->PSOR = pinMask;
			    DELAY_100nS;
			    DELAY_100nS;
			    DELAY_100nS;
			    DELAY_100nS;
			    DELAY_100nS;
			    DELAY_100nS;
			    DELAY_100nS;
			    DELAY_100nS;
			    DELAY_100nS;
			    base->PCOR = pinMask;
			    DELAY_100nS;
			    DELAY_100nS;
			} else {
			    base->PSOR = pinMask;
			    DELAY_100nS;
			    DELAY_100nS;
			    DELAY_100nS;
			    DELAY_100nS;
			    DELAY_10nS;
			    DELAY_10nS;
			    DELAY_10nS;
			    base->PCOR = pinMask;
			    DELAY_100nS;
			    DELAY_100nS;
			    DELAY_100nS;
			    DELAY_100nS;
			    DELAY_100nS;
			    DELAY_100nS;
			    DELAY_100nS;
			}
			bitcount--;
			dataWord = dataWord <<1;
		}
		// last bit has a different timing
		if (dataWord & 0x0800000U) {
		    base->PSOR = pinMask;
		    DELAY_100nS;
		    DELAY_100nS;
		    DELAY_100nS;
		    DELAY_100nS;
		    DELAY_100nS;
		    DELAY_100nS;
		    DELAY_100nS;
		    DELAY_100nS;
		    DELAY_100nS;
		    base->PCOR = pinMask;
		    DELAY_10nS;
		    DELAY_10nS;
		    DELAY_10nS;
		    DELAY_10nS;
		    DELAY_10nS;
		} else {
		    base->PSOR = pinMask;
		    DELAY_100nS;
		    DELAY_100nS;
		    DELAY_100nS;
		    DELAY_100nS;
		    DELAY_10nS;
		    DELAY_10nS;
		    DELAY_10nS;
		    base->PCOR = pinMask;
		    DELAY_100nS;
		    DELAY_100nS;
		    DELAY_100nS;
		    DELAY_100nS;
		    DELAY_100nS;
		}

		data++;
		length--;
	}
}

// a variable delay in Seconds
void delay_s(uint16_t t) {
	volatile uint32_t i = 0;
	volatile uint32_t delay_t = 8000000 * t;
	for (i = 0; i < delay_t; ++i) {
		__asm("NOP");
	}
}

// a variable delay in milliseconds
void delay_ms(uint16_t t) {
	volatile uint32_t i = 0;
	volatile uint32_t delay_t = 8000 * t;
	for (i = 0; i < delay_t; ++i) {
		__asm("NOP");
	}
}

// Function specific for my scenario whereby the inner and outer circle can be set to a specific color
void LEDs_InnerOuter_Config(uint32_t color_out, uint32_t color_in)
{
	uint32_t data[totalLEDs];
	int i = 0;
	while(i < outerCircleLEDs) // count every LED in the outer circle
	{
		data[i] = color_out;
		i++;
	}
	while(i<totalLEDs) // colors for inner circle since those are the only one left after the outer circle
	{
		data[i] = color_in;
		i++;
	}

	SendNeopixelData(GPIO_LED, PIN_LED, data, totalLEDs);
}


// sample function for lighting one single Neopixel LED. This will only lighting the first Neopixel.
// to all the following connected neopixels will be off.
void Single_Neopixel_LED_config()
{
	uint32_t data[1];
	data[0] = 0xFFFFFF; // white

	SendNeopixelData(GPIO_LED, PIN_LED, data, 1);
}

void Modulo_LED_config(uint32_t modulo, uint32_t amountLEDs, uint32_t color)
{
	uint32_t data[amountLEDs];
	int i = 0;
	while(i <= amountLEDs)
	{
		if(i%modulo)
		{
			data[i] = color;
		}
		else
		{
			data[i] = 0x000000;
		}
		i++;
	}

	SendNeopixelData(GPIO_LED, PIN_LED, data, amountLEDs);
}

// The temperature parameter will be the amount of LEDs to light up.
// If the temperature is above zero, the color will be green, for below zero the color will be blue and if the temperature is zero the color is red.
void Temperature_LED_config(uint32_t temp)
{
	uint32_t temp_plus_color = 0xFF0000; // green
	uint32_t temp_min_color  = 0x0000FF; // blue
	uint32_t temp_norm_color = 0x222222; // white
	uint32_t temp_zero_color = 0x005500; // red

	uint32_t data[totalLEDs];
	int i = outerCircleLEDs; // start point after the outerCircle

	temp = temp + i;

	while(i < totalLEDs)
	{
		if(temp > 0)
		{
			if(i < temp)
			{
				data[i] = temp_plus_color;
			}
			else
			{
				data[i] = temp_norm_color;
			}
		}
		if(temp < 0)
		{
			if(i < temp)
			{
				data[i] = temp_min_color;
			}
			else
			{
				data[i] = temp_norm_color;
			}
		}
		if(temp == 0)
		{
			data[i] = temp_zero_color;
		}
		i++;
	}

	SendNeopixelData(GPIO_LED, PIN_LED, data, totalLEDs);
}

// input from the RTC, splitted in h, m & s as input for the LEDdata
void Clock_LED_config(uint32_t h, uint32_t m, uint32_t s)
{
	uint32_t data[totalLEDs];
	int i = 0;
	int i_start_inner = 65;

	uint32_t color_s 	= 0x111111;
	uint32_t color_m 	= 0x0000FF;
	uint32_t color_h 	= 0x00FF00;
	uint32_t color_h_1 	= 0x003300;
	uint32_t color_zero = 0x000000;

	// make the outer circle toggle every second
	while(i < i_start_inner)
	{
		if(s%2)
		{
	//		data[i] = color_s;
		}
		else
		{
		//	data[i] = 0x000000;
		}
		i++;
	}
	h = h + i_start_inner;
	m = m + i_start_inner;
	s = s + i_start_inner;
	// find the minute and hour hand.
	while(i<totalLEDs) // colors for inner circle
	{
		if(i == h) // hour, the hour-hand is 3 LEDs wide, if h == s or h == m, the s or m LED will be above the hour leds
		{
			data[h-1]   = color_h_1;
			data[h]     = color_h;
			data[h+1]   = color_h_1;
		}
		if(i == s) // second hand, commented out since the outer circle glow shows the second.
		{
			data[s]   = color_s;
		}
		if(i == m) // minute
		{
			data[m]   = color_m;
		}
		// if the LED is not s, m or h, the led will be turned off.
		if(i != s && i != m && i != h) // add i != s  if you use the second-hand
		{
		data[i] = color_zero;
		}

		i++;
	}

	SendNeopixelData(GPIO_LED, PIN_LED ,data, totalLEDs);
}

// Simulate a clock signal for the Clock_LED_config function,
// parameter Duration simulate the clock for a given time. set to 0 for endless clock.
void DummyClock(int duration)
{
	int i = 0;
	int counter_ms = 1000; // one second, decrease for speeding up the clock

	while((i <= duration) || (i == 0))
	{
		for(int h = 0; h <= 12; h++)
		{
			for(int m = 0; m <= 60; m++)
			{
				for(int s = 0; s <= 60; s++)
				{
					Clock_LED_config(h, m, s);
					delay_ms(counter_ms);
				}
			}
			h = h+5;
		}
		i++;
	}
}

// print welcome text
void print_welcome_text(void)
{
//	printf("Welcome to Infinity Mirror! ");
}

WS2812b.h

C/C++
header file for access to the neopixel functions
/*
 * WS2812b.h
 *
 *  Created on: 1 jul. 2016
 *      Author: marcelk
 */

#ifndef SOURCE_WS2812B_H_
#define SOURCE_WS2812B_H_


#include <stdint.h>


extern void WS2812_Init(void);
extern void SendNeopixelData(GPIO_Type *base, uint32_t pin, uint32_t *data, int length);
extern void WS2812_OutputDataDMA(uint32_t * p32_strip_data, uint32_t _strip_data_word_cnt);
extern void delay_s(uint16_t t);
extern void delay_ms(uint16_t t);
extern void LEDs_InnerOuter_Config(uint32_t color_out, uint32_t color_in);
extern void Single_Neopixel_LED_config();
extern void Modulo_LED_config(uint32_t modulo, uint32_t amountLEDs, uint32_t color);
extern void Temperature_LED_config(uint32_t temp);
extern void Clock_LED_config(uint32_t h, uint32_t m, uint32_t s);
extern void DummyClock(int duration);

extern void print_welcome_text(void);

#endif /* SOURCE_WS2812B_H_ */

main.c

C/C++
Well, most of the fun is in the WS2812b.c file, here in the main.c only a call and multiple functions can be set after each other. Make sure the GPIO is set in the pin_mux.c,
#include "board.h"
#include "pin_mux.h"
#include "clock_config.h"
#include "WS2812b.h"
 
int main(void) {
  /* Init board hardware. */
  BOARD_InitPins();
  BOARD_BootClockRUN();
  BOARD_InitDebugConsole();

  // Set GPIOas output
  gpio_pin_config_t pin_config = {kGPIO_DigitalOutput, 1};

  GPIO_PinInit(GPIOC, 12U, &pin_config);

  // predefined colors
  uint32_t color_1 = 0xFFFFFF;
  uint32_t color_2 = 0x00FF00;
  uint32_t color_3 = 0xFF0000;
  uint32_t color_4 = 0x0000FF;

  while(1)
  {
	  print_welcome_text();

	  LEDs_InnerOuter_Config(color_1, color_2);
	  delay_s(1);
	  LEDs_InnerOuter_Config(color_2, color_1);
	  delay_s(1);

	  DummyClock(120);

	  delay_s(2);

	  Temperature_LED_config(30);

	  delay_s(2);

	  LEDs_InnerOuter_Config(color_3, color_4);
	  delay_s(1);
	  LEDs_InnerOuter_Config(color_4, color_3);
	  delay_s(1);

  }
}

Credits

Marcel Kruse

Marcel Kruse

5 projects • 23 followers
Software & Hardware tester at an Embedded Systems company. Studied Electrical Engineering. Follow me on twitter: twitter.com/marcelkruse

Comments