stm32plus Examples Online Browser
										
					
					
					
stm32plus ships with a wealth of example code that exists to demonstrate the capabilities of the library and provide you with easy to reuse templates for your own code.
This is a large page so give it time to load and when it’s complete you can use your browser’s search capability to find what you need.
ads7843
Click here to hide the full ads7843 code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/display/tft.h"
#include "config/display/touch.h"
using namespace stm32plus;
using namespace stm32plus::display;
/**
 * ADS7843 touch screen test, implements a basic drawing
 * application using an ILI9325 LCD.
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103VET6
 */
class ADS7843Test : public Observer,
										public ThreePointTouchScreenCalibrator::GuiCallback {
	protected:
		// declare a type for the LCD that we're using
		typedef Fsmc16BitAccessMode<FsmcBank1NorSram1> LcdAccessMode;		// my access mode
		typedef ILI9325_Landscape_64K<LcdAccessMode> LcdPanel;					// the panel
		// LCD-related objects
		LcdAccessMode *_accessMode;							// access mode for the LCD
		LcdPanel *_lcd; 												// 64K colour interface to the ILI9325
		DefaultBacklight *_backlight;						// backlight PWM output
		Font *_font; 														// font that we'll use
		// touch screen related objects
		ADS7843AsyncTouchScreen *_touchScreen;	// the touch screen object
		Spi *_spi;															// The SPI peripheral that we'll attach to the writer
		ExtiPeripheralBase *_exti;							// An EXTI interrupt line for the pen IRQ
		GpioPinRef _penIrqPin;									// The GPIO pin that receives the pin IRQ
		// calibrator and error-correction post-processors
		PassThroughTouchScreenCalibration *_passThroughCalibration;
		AveragingTouchScreenPostProcessor *_averagingPostProcessor;
		PassThroughTouchScreenPostProcessor *_passThroughPostProcessor;
		// the observer implementation will set this when the interrupt fires
		volatile bool _clicked;
		// these are the variables that the graphical demo will use
		bool _fgSelected;
		bool _accurate;
		TouchScreenCalibration* _calibrationResults;
		Size _boxSize;
		LcdPanel::tCOLOUR _fg,_bg,_colours[8];
		Rectangle _selectionBoxes[7];
		Point _lastPoint;
		uint16_t _backlightPercentage;
	public:
		/*
		 * Demo setup and preparation
		 */
		void run() {
			// set up the LCD
			initLcd();
			// set up the touch screen
			initTouchScreen();
			// set up variables for the demo
			_fgSelected=true;
			_accurate=false;
			_calibrationResults=NULL;
			_boxSize.Width=_boxSize.Height=0;
			_backlightPercentage=100;
			_colours[0]=ColourNames::RED;
			_colours[1]=ColourNames::GREEN;
			_colours[2]=ColourNames::BLUE;
			_colours[3]=ColourNames::BLACK;
			_colours[4]=ColourNames::WHITE;
			_colours[5]=ColourNames::CYAN;
			_colours[6]=ColourNames::MAGENTA;
			_colours[7]=ColourNames::YELLOW;
			// run the demo and don't come back
			doDemo();
		}
		/*
		 * initialise the LCD panel
		 */
		void initLcd() {
			// we've got RESET on PE1, backlight on PD13 and RS (D/CX) on PD11
			GpioE<DefaultDigitalOutputFeature<1> > pe;
			GpioD<DefaultDigitalOutputFeature<13>,DefaultAlternateFunctionFeature<GPIO_AF_FSMC,11> > pd;
			// set up the FSMC timing for this panel
			Fsmc8080LcdTiming fsmcTiming(2,5);
			// set up the FSMC on bank 1 with A16 as the RS line (this is compatible with 100 pin devices)
			_accessMode=new LcdAccessMode(fsmcTiming,16,pe[1]);
			// create the LCD interface in landscape mode
			// this will power it up and do the reset sequence
			_lcd=new LcdPanel(*_accessMode);
			// set up some gamma values for this panel
			ILI9325Gamma gamma(0x0006,0x0101,0x0003,0x0106,0x0b02,0x0302,0x0707,0x0007,0x0600,0x020b);
			_lcd->applyGamma(gamma);
			// create a font and select it for stream operations
			_font=new Font_KYROU_9_REGULAR8();
			*_lcd << *_font;
			_lcd->setFontFilledBackground(false);
			// turn on the backlight at 100%
			_backlight=new DefaultBacklight;
			_backlightPercentage=100;
			_backlight->fadeTo(_backlightPercentage,4);
		}
		/*
		 * initialise the touch screen
		 */
		void initTouchScreen() {
			// create the initial pass through calibration object that allows us to create
			// the touch screen object ready for calibrating for real
			_passThroughCalibration=new PassThroughTouchScreenCalibration;
			// create an averaging post-processor for use in accurate mode that
			// does 4x oversampling on the incoming data
			_averagingPostProcessor=new AveragingTouchScreenPostProcessor(4);
			// create the do-nothing post-processor that is used in non-accurate mode
			_passThroughPostProcessor=new PassThroughTouchScreenPostProcessor;
			// we've got the PENIRQ attached to GPIOB, port 6. Attach an EXTI line to it and since
			// it's active low we want to be called back via our Observer implementation when the
			// signal falls from high to low.
			GpioB<DefaultDigitalInputFeature<6> > pb;
			_penIrqPin=pb[6];
			_exti=new Exti6(EXTI_Mode_Interrupt,EXTI_Trigger_Falling,pb[6]);
			// we've got the SPI interface to the touchscreen wired to SPI1, and since SPI1 is the fast one on the
			// STM32 we'll divide the 72Mhz clock by the maximum of 256 instead of 128 which we'd use on SPI2.
			Spi1<>::Parameters params;
			params.spi_baudRatePrescaler=SPI_BaudRatePrescaler_256;
			params.spi_cpol=SPI_CPOL_Low;
			params.spi_cpha=SPI_CPHA_1Edge;
			_spi=new Spi1<>(params);
			// now create the touch screen, initially in non-accurate mode with some dummy calibration data because the first thing
			// we're going to do in the demo is calibrate it with the 3-point routine.
			_touchScreen=new ADS7843AsyncTouchScreen(
					*_passThroughCalibration,
					*_passThroughPostProcessor,
					*_spi,
					_penIrqPin,
					*_exti
				);
		}
		/*
		 * Calibrate the touch screen using the accurate 3-point method
		 */
		void calibrate() {
			ThreePointTouchScreenCalibrator calibrator(*_touchScreen,*this);
			TouchScreenCalibration* newResults;
			// important preparation for calibration: we must set the screen to pass through mode
			// so that the calibrator sees raw co-ordinates and not calibrated!
			_touchScreen->setCalibration(*_passThroughCalibration);
			// calibrate the screen and get the new results. A real application can use the serialise
			// and deserialise methods of the TouchScreenCalibration base class to read/write the
			// calibration data to a persistent stream
			if(!calibrator.calibrate(newResults))
				return;
			// store the new results
			if(_calibrationResults!=NULL)
				delete _calibrationResults;
			_calibrationResults=newResults;
			// re-initialise the touch screen with the calibration data
			_touchScreen->setCalibration(*_calibrationResults);
		}
		/*
		 * Get the size of one of the menu boxes on the screen
		 */
		void calcBoxSize(const char **boxTexts,int numBoxes) {
			Size s;
			int i;
			for(i=0;i<numBoxes;i++) {
				s=_lcd->measureString(*_font,boxTexts[i]);
				if(s.Width>_boxSize.Width)
					_boxSize.Width=s.Width;
				if(s.Height>_boxSize.Height)
					_boxSize.Height=s.Height;
			}
			// add on 4px for the left selection bar, 2px all around for space and 1px all around for the border
			// ignoring that the border is shared between vertical boxes :)
			_boxSize.Width+=1+4+2+2+1;
			_boxSize.Height+=1+2+2+1;
		}
		/*
		 * Draw the tools menu at the edge of the screen
		 */
		void drawTools() {
			int16_t y;
			uint16_t i;
			Point p;
			const char *boxTexts[]= {
				"","fore","back","clear","recal","accurate", ""
			};
			if(_boxSize.Width==0)
				calcBoxSize(boxTexts,sizeof(boxTexts)/sizeof(boxTexts[0]));
			// clear down
			_lcd->setForeground(ColourNames::BLACK);
			_lcd->fillRectangle(Rectangle(0,0,_boxSize.Width,(_boxSize.Height+2)*sizeof(boxTexts)/sizeof(boxTexts[0])));
			_lcd->setForeground(ColourNames::WHITE);
			y=0;
			p.X=1+4+2;
			for(i=0;i<sizeof(boxTexts)/sizeof(boxTexts[0]);i++) {
				_selectionBoxes[i].X=0;
				_selectionBoxes[i].Y=y;
				_selectionBoxes[i].Width=_boxSize.Width;
				_selectionBoxes[i].Height=_boxSize.Height;
				_lcd->drawRectangle(_selectionBoxes[i]);
				p.Y=y+1+2;
				*_lcd << p << boxTexts[i];
				y+=_boxSize.Height+2;
			}
			drawSelection(_fg,1);
			drawSelection(_bg,2);
			if(_accurate)
				drawSelection(ColourNames::GREEN,5);
			drawColours();
			drawBacklight();
			// don't return until the pen is up
			while(!_penIrqPin.read());
		}
		/*
		 * Draw a selection (green bar) indicator in the menu box
		 */
		void drawSelection(LcdPanel::tCOLOUR barColour,int boxIndex) {
			_lcd->setForeground(barColour);
			_lcd->fillRectangle(Rectangle(1,(_boxSize.Height+2)*boxIndex+1,4,_boxSize.Height-2));
		}
		/*
		 * Draw the backlight percentage box
		 */
		void drawBacklight() {
			int width,y;
			y=(_boxSize.Height+2)*6+1;
			width=((_boxSize.Width-2)*_backlightPercentage)/100;
			_lcd->setForeground(ColourNames::BLUE);
			_lcd->fillRectangle(Rectangle(1,y,width,_boxSize.Height-2));
			if(_backlightPercentage<100) {
				_lcd->setForeground(ColourNames::BLACK);
				_lcd->fillRectangle(Rectangle(1+width,y,_boxSize.Width-2-(1+width),_boxSize.Height-2));
			}
			_lcd->setForeground(ColourNames::WHITE);
			*_lcd << Point(1+4+2,y+1+2) << "LED: " << _backlightPercentage;
			_lcd->setForeground(_fg);
		}
		/*
		 * Draw the colour stripe boxes
		 */
		void drawColours() {
			int i,numColours,width;
			Rectangle rc;
			numColours=sizeof(_colours)/sizeof(_colours[0]);
			width=(_boxSize.Width-2)/numColours;
			rc.X=1;
			rc.Y=1;
			rc.Height=_boxSize.Height-2;
			rc.Width=width;
			for(i=0;i<numColours;i++) {
				_lcd->setForeground(_colours[i]);
				_lcd->fillRectangle(rc);
				rc.X+=width;
			}
		}
		/*
		 * Go into a loop running the demo
		 */
		void doDemo() {
			Point p;
			int index;
			uint16_t newpercent;
			// clear down
			_lcd->setBackground(ColourNames::BLACK);
			_lcd->clearScreen();
			// calibrate the screen for first use
			calibrate();
			// clear down the screen
			_fg=ColourNames::WHITE;
			_bg=ColourNames::BLACK;
			_lcd->setBackground(_bg);
			_lcd->clearScreen();
			// draw the tools
			drawTools();
			// register as an observer for interrupts on the EXTI line
			_touchScreen->insertObserver(*this);
			for(;;) {
				// wait for a click
				_lastPoint.X=-1;
				for(_clicked=false;!_clicked;);
				do {
					// get click-coordinates from the panel
					if(_touchScreen->getCoordinates(p)) {
						// check if the click is in any of the menu boxes
						if(_selectionBoxes[0].containsPoint(p)) {
							index=(p.X-1)/8;
							if(index>=0 && index<=7) {
								if(_fgSelected) {
									_fg=_colours[index];
									_lcd->setForeground(_fg);
								}
								else {
									_bg=_colours[index];
									_lcd->setBackground(_bg);
									_lcd->clearScreen();
								}
								drawTools();
							}
						}
						else if(_selectionBoxes[1].containsPoint(p)) {
							_fgSelected=true;
						}
						else if(_selectionBoxes[2].containsPoint(p)) {
							_fgSelected=false;
						}
						else if(_selectionBoxes[3].containsPoint(p)) {
							_lcd->clearScreen();
							drawTools();
						}
						else if(_selectionBoxes[4].containsPoint(p)) {
							while(!_penIrqPin.read());
							calibrate();
							_lcd->setBackground(_bg);
							_lcd->clearScreen();
							drawTools();
						}
						else if(_selectionBoxes[5].containsPoint(p)) {
							if(_accurate^=true)
								_touchScreen->setPostProcessor(*_averagingPostProcessor);
							else
								_touchScreen->setPostProcessor(*_passThroughPostProcessor);
							drawTools();
						}
						else if(_selectionBoxes[6].containsPoint(p)) {
							newpercent=(100*p.X-1)/(_boxSize.Width-2);
							if(newpercent!=_backlightPercentage && newpercent<=100) {
								_backlightPercentage=newpercent;
								_backlight->setDutyCycle(_backlightPercentage);
								drawBacklight();
							}
						}
						else {
							// if the click is on screen, plot it. This bounds check is necessary because
							// the touch screen can and does extend past the LCD edges.
							if(p.X>=0 && p.X<=_lcd->getXmax() && p.Y>=0 && p.Y<=_lcd->getYmax()) {
									if(_lastPoint.X!=-1)
										_lcd->drawLine(p,_lastPoint);
								else
									_lcd->plotPoint(p);
								_lastPoint=p;
							}
						}
					}
				// carry on while the pen is still down
				} while(!_penIrqPin.read());
			}
		}
		/*
		 * Implementation of the Observer pattern. This will be called back when the
		 * EXTI interrupt fires.
		 */
		void onNotify(
				Observable& sender __attribute__((unused)),
				ObservableEvent::E event,
				void *context __attribute__((unused))) {
			// check that the event is what we were expecting and set the clicked flag if it is
			if(event==ObservableEvent::TouchPanel_ReadyForSampling && !_clicked)
				_clicked=true;
		}
		/*
		 * Display the prompt "Please tap the stylus on each red point"
		 */
		virtual void displayPrompt(const char *text) {
			Size size;
			_lcd->setBackground(ColourNames::BLACK);
			_lcd->setForeground(ColourNames::WHITE);
			_lcd->clearScreen();
			// show the prompt at the top center
			size=_lcd->measureString(*_font,text);
			*_lcd << Point((_lcd->getWidth()/2)-(size.Width/2),0) << text;
		}
		/*
		 * Display a hit point for the user to aim at
		 */
		virtual void displayHitPoint(const Point& pt) {
			int16_t i,j,x,y;
			x=pt.X-1;
			y=pt.Y-1;
			_lcd->setForeground(ColourNames::RED);
			for(i=0;i<3;i++)
				for(j=0;j<3;j++)
					_lcd->plotPoint(Point(x+j,y+i));
		}
		/*
		 * Get the size of the panel
		 */
		virtual Size getPanelSize() {
			return Size(_lcd->getWidth(),_lcd->getHeight());
		}
};
/*
 * Main entry point
 */
int main() {
	// set up SysTick at 1ms resolution
	MillisecondTimer::initialise();
	ADS7843Test test;
	test.run();
	// not reached
	return 0;
}
 
blink
Click here to hide the full blink code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/gpio.h"
#include "config/timing.h"
using namespace stm32plus;
/**
 * This is the most basic example that uses GPIO and the
 * Systick timer to blink a LED on PF6 at 1Hz.
 *
 * If the STM32F4DISCOVERY board is your target then
 * change the GPIO declation to...
 *
 * 	GpioD<DefaultDigitalOutputFeature<13> > pd
 *
 * ... and change 2 of "pf[6]" to "pd[13]" to blink the
 * orange led on the discovery board.
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103ZET6
 *   STM32F407VGT6
 */
class Blink {
	public:
		void run() {
			// initialise the pin for output
			GpioF<DefaultDigitalOutputFeature<6> > pf;
			// loop forever switching it on and off with a 1 second
			// delay in between each cycle
			for(;;) {
				pf[6].set();
				MillisecondTimer::delay(1000);
				pf[6].reset();
				MillisecondTimer::delay(1000);
			}
		}
};
/*
 * Main entry point
 */
int main() {
	// set up SysTick at 1ms resolution
	MillisecondTimer::initialise();
	Blink blink;
	blink.run();
	// not reached
	return 0;
}
 
button
crc
Click here to hide the full crc code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/usart.h"
#include "config/crc.h"
#include "config/string.h"
using namespace stm32plus;
/**
 * CRC demo. This demo will show how to calculate the
 * 32-bit CRC of a stream of bytes using the hardware
 * CRC peripheral on the STM32. The calculated CRC
 * will be output to USART1. USART1 is configured as
 * 57600-8-N-1.
 *
 * Usart1 (non-remapped) is not available on the
 * STM32F4DISCOVERY. If this is your target board then
 * choose a remapped pin set or move to another usart,
 * e.g. Usart2.
 *
 * The STM32 CRC peripheral operates on 32-bit words
 * with considerations for the endian-ness of the data
 * left to the user. stm32plus provides implementations
 * for little and big endian calculations with
 * customisable padding bytes for when your data stream
 * isn't a multiple of 32-bits long.
 *
 * Big endian mode:
 *   The words are bit-reversed before going to the CRC
 *   unit and the result is bit-reversed before
 *   returning to you.
 *
 * Little endian mode:
 *   No transformations at all are performed on the
 *   data.
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103ZET6
 *   STM32F407VGT6
 */
class CrcTest {
	/**
	 * The selected CRC mode. We'll use big-endian. Input data is bit-reversed before going in to the
	 * calculation and results are bit-reversed before coming back.
	 */
	typedef CrcBigEndian MyCrcMode;
	public:
		void run() {
			static const char *testString="Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua";
			/*
			 * Declare USART1 to run at 57600 and attach an output stream to it
			 */
			Usart1<> usart(57600);
			UsartPollingOutputStream usartOutputStream(usart);
			/*
			 * Declare a big-endian CRC implementation with a default padding value
			 * of zero and attach it to an output stream
			 */
			MyCrcMode::Parameters p;
			MyCrcMode crc(p);
			CrcOutputStream<MyCrcMode> crcOutputStream(crc);
			/*
			 * Calculate the CRC of the test string
			 */
			crcOutputStream << testString;			// stream in the data to the CRC unit
			crcOutputStream.close();						// close the stream (calls finish() on the CRC)
			/*
			 * Write out the CRC value to the USART
			 */
			char buf[15];
			StringUtil::modp_uitoa10(crc.currentCrc(),buf);
			usartOutputStream << "CRC is " << buf;
			/*
			 * Done
			 */
			for(;;);
		}
};
/*
 * Main entry point
 */
int main() {
	CrcTest test;
	test.run();
	// not reached
	return 0;
}
 
cs43l22_beep
Click here to hide the full cs43l22_beep code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/dac.h"
using namespace stm32plus;
/**
 * This example will sound the CS43L22 internal beep tone
 * twice per second. From experimentation I have
 * determined that the CS43L22 needs an incoming data
 * stream in order to generate the beep - just supplying
 * MCLK is not enough.
 *
 * Therefore for this demo I stream in a continuous
 * stream of nothing (zeros) while sounding the beep.
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F407VGT6
 */
class CS43L22BeepTest : public Observer {
	public:
		/*
		 * The F4 MCU packages match the pins on the F1 for equivalent peripherals but the F4 is not
		 * limited to distinct sets of pins that make up a peripheral. Annoyingly the CS43L22 on the
		 * F4Discovery board has I2C1 SCL and SDA split across what would be the default and remap
		 * pin set on the F1 so we have to use 'custom' port/pin declarations instead of using one
		 * of the I2C1_Default or I2C1_Remap pre-defined packages.
		 */
		enum {
			Port_SCL=GPIOB_BASE,//!< SCL_PORT
			Port_SDA=GPIOB_BASE,//!< SDA_PORT
			Pin_SCL=GPIO_Pin_6, //!< SCL_PIN
			Pin_SDA=GPIO_Pin_9  //!< SDA_PIN
		};
		/*
		 * Same goes for the I2S pins. They're using I2S3 on the F4Discovery board but the pin
		 * choice for I2S3 does not match the F1.
		 */
		enum {
			Port_WS   = GPIOA_BASE,
			Port_CK   = GPIOC_BASE,
			Port_SD   = GPIOC_BASE,
			Port_MCLK = GPIOC_BASE,
			Pin_WS   = GPIO_Pin_4,
			Pin_CK   = GPIO_Pin_10,
			Pin_SD   = GPIO_Pin_12,
			Pin_MCLK = GPIO_Pin_7
		};
	protected:
			/*
			 * The CS43L22 has a control and a data interface. Here we define the type that will be used
			 * for the control interface. It's going to be I2C.
			 */
			typedef CS43L22ControlI2C<							// The I2C controller. It's templated with the I2C interface and features.
				I2C1_Custom<													// F4 VLDiscovery pinning does not match one of the standard pinouts
					CS43L22BeepTest,										// get the pinning from this class
					I2CSingleByteMasterPollingFeature		// we're going to be polling in master mode
				>
			> MyDacControlInterface;
			/*
			 * The data interface for this example will be I2S. Here we define a type for it.
			 */
			typedef I2S3_Custom<					// F4 VLDiscovery pinning does not match one of the standard pinouts
					CS43L22BeepTest,					// get the pinning from this class
					I2S3InterruptFeature			// we'll stream the data in the interrupt handler
				> MyDacDataInterface;
			/*
			 * Now define the CS43L22 type with the control and data interface
			 */
			typedef CS43L22<							// the device is parameterised with the I2C peripheral
				MyDacControlInterface,
				MyDacDataInterface
			> MyDac;
			/*
			 * Declare the peripheral pointer
			 */
			MyDac *_dac;
	public:
		void run() {
			/*
			 * Declare the reset pin which is on PD4 on the F4 discovery board.
			 */
			GpioD<DefaultDigitalOutputFeature<4> > pd;
			/*
			 * Declare an instance of the DAC with default I2C parameters of 100kHz, ACK-on, 50% duty, 7-bit
			 * and default I2S parameters of 44kHz, master, phillips, 16-bit, mclk-on, cpol-low
			 * Leave the master polling feature bus timeout at 5 seconds.
			 */
			MyDac::Parameters params;
			params.resetPin=pd[4];
			_dac=new MyDac(params);
			// set ourselves up to observe the interrupts
			_dac->I2S3InterruptFeature::insertObserver(*this);
			// reset the device
			_dac->reset();
			// send the I2C initialisation sequence
			if(!_dac->initialise())
				error(3);
			// headphones on - default volume level of 200 (out of 255)
			_dac->headphonesOn();
			// enable the interrupts - this will start the data transfer
			_dac->I2S3InterruptFeature::enableInterrupts(SPI_I2S_IT_TXE);
			// finished - interrupts are now supplying the null data stream
			for(;;) {
				// sound the beep and then wait 500ms
				_dac->beepSingle();
				MillisecondTimer::delay(500);
			}
		}
		/*
     * Observer callback function. This is called when the TXE interrupt that we've
     * enabled is fired.
     */
    virtual void onNotify(Observable&,ObservableEvent::E event,void *) {
    	static const uint16_t NULL_DATA=0;
     	// send the null data
      if(event==ObservableEvent::SPI_ReadyToTransmit)
      	_dac->send(&NULL_DATA,1);
    }
		/*
		 * Handle an error by flashing the LED on PD13 repeatedly
		 */
		void error(uint8_t code) {
			GpioD<DefaultDigitalOutputFeature<13> > pd;
			for(;;) {
				for(uint8_t i=0;i<code;i++) {
					pd[13].set();
					MillisecondTimer::delay(250);
					pd[13].reset();
					MillisecondTimer::delay(250);
				}
				MillisecondTimer::delay(3000);
			}
		}
};
/*
 * Main entry point
 */
int main() {
	// timing is required
	MillisecondTimer::initialise();
	CS43L22BeepTest test;
	test.run();
	// not reached
	return 0;
}
 
dac_noise
Click here to hide the full dac_noise code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/dac.h"
using namespace stm32plus;
/**
 * Demonstration of DAC channel 1 producing a pseudo-
 * random noise sequence. The output can be seen on PA4.
 * Attach an oscilloscope to see the noise wave or take
 * a look at waveform_f1.png in the example subdirectory
 * to see how it looks on the STM32F103ZET6.
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F407VGT6
 *   STM32F103ZET6
 */
class DacNoiseTest {
	public:
		void run() {
			/*
			 * Set up the DAC with a software trigger and noise generation. No alignment feature
			 * is necessary because we'll never be writing data - it's generated for us courtesy
			 * of the mask setting in the parameters class.
			 */
			Dac1<>::Parameters params;
			params.dac_trigger=DAC_Trigger_Software;
			params.dac_waveGeneration=DAC_WaveGeneration_Noise;
			Dac1<> dac(params);
			// continually trigger the noise conversion as fast as possible
			for(;;)
				dac.triggerOn();
		}
};
/*
 * Main entry point
 */
int main() {
	DacNoiseTest test;
	test.run();
	// not reached
	return 0;
}
 
dac_triangle
Click here to hide the full dac_triangle code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/dac.h"
#include "config/timer.h"
using namespace stm32plus;
/**
 * Demonstration of DAC channel 1 producing a triangular
 * wave superimposed upon a base output of 1/16 Vref.
 * Timer 6 is used as the trigger for each conversion.
 *
 * The output can be seen on PA4. Attach an oscilloscope
 * to see the triangular wave or take a look at
 * waveform_f1.png in the example subdirectory to see
 * how it looks on the STM32F103ZET6.
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103ZET6
 *   STM32F407VGT6
 */
class DacTriangleTest {
	public:
		void run() {
			/*
			 * Set up Timer6 with an internal clock source and configured to be
			 * in master mode with update as the trigger
			 */
			Timer6<Timer6InternalClockFeature,TimerUpdateMasterFeature> timer;
			/*
			 * Configure the timer with a reload value of 255 and no prescaler.
			 */
			timer.initialiseTimeBase(255,0,TIM_CKD_DIV1,TIM_CounterMode_Up);
			/*
			 * Declare a DAC type with 12 bit right-aligned data.
			 */
			typedef Dac1<DacChannel112BitRightAlignmentFeature> MyDac;
			/*
			 * Create the DAC parameters. The trigger for conversion will be timer 6's
			 * trigger output and the wave generation mode is triangular.
			 */
			MyDac::Parameters params;
			params.dac_trigger=DAC_Trigger_T6_TRGO;
			params.dac_waveGeneration=DAC_WaveGeneration_Triangle;
			params.dac_lfsrMaskOrTriangleAmplitude=DAC_TriangleAmplitude_1023;
			/*
			 * Declare the DAC object
			 */
			MyDac dac(params);
			/*
			 * Set a base level of Vref/16. 4096 is the full 12 bit conversion value and that equals
			 * an output of Vref. Therefore 4096/16 = 256 for a base level of Vref/16. The triangle
			 * wave is added to this base value.
			 */
			dac.write(256);
			/*
			 * Enable the trigger output and then Start the timer. Each time the update event is
			 * generated a DAC conversion is triggered.
			 */
			timer.enableMasterFeature();
			timer.enablePeripheral();
			/*
			 * Finished. It's all running in the background now.
			 */
			for(;;);
		}
};
/*
 * Main entry point
 */
int main() {
	DacTriangleTest test;
	test.run();
	// not reached
	return 0;
}
 
dma_copy
Click here to hide the full dma_copy code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/dma.h"
#include "config/timing.h"
using namespace stm32plus;
/**
 * Demo of the DMA peripheral used to copy a block of
 * memory. We repeatedly copy a small 256 byte buffer
 * using the completion interrupt to signal the end
 * of each transfer. If all is well then a LED on PF6
 * will blink once per second.
 *
 * If this example is to be run on the STM32F4DISCOVERY
 * board then change the LED configuration from PF6 to
 * PD13 and invert the set() / reset() logic because
 * that LED is active HIGH.
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103ZET6
 *   STM32F407VGT6
 */
class DmaCopyTest : public Observer  {
	protected:
		/**
		 * The LED is on PF6
		 */
		enum { LED_PIN = 6 };
		/*
		 * The IRQ handler sets this to true when the DMA transfer is complete
		 */
		volatile bool _completed;
	public:
		void run() {
			uint8_t buffer1[256],buffer2[256];
			int i;
			// initialise the LED pin
			GpioF<DefaultDigitalOutputFeature<LED_PIN> > pf;
			// lights off (this LED is active low, i.e. PF6 is a sink)
			pf[LED_PIN].set();
			// declare a DMA channel with interrupts and memory copy features
			// F4 users note that only DMA2 can do memory-to-memory transfers.
#if defined(STM32PLUS_F1)
			Dma2Channel1<
				Dma2Channel1InterruptFeature,		// interrupts on DMA2, channel 1
				DmaMemoryCopyFeature<> 					// memory copy with default transfer size (bytes)
			> dma;
			// enable the completion interrupt for DMA2, channel 1.
			dma.enableInterrupts(Dma2Channel1InterruptFeature::COMPLETE);
#elif defined(STM32PLUS_F4)
			Dma2Channel1Stream0<
				Dma2Stream0InterruptFeature,		// interrupts on DMA2, stream 0
				DmaMemoryCopyFeature<> 					// memory copy with default transfer size (bytes)
			> dma;
			// enable the completion interrupt for DMA2, stream 0.
			dma.enableInterrupts(Dma2Stream0InterruptFeature::COMPLETE);
#endif
			// set ourselves up to observe the completion of the DMA transfer
			dma.insertObserver(*this);
			for(;;) {
				// reset the completion flag
				_completed=false;
				// clear the target buffer, fill the source buffer with a pattern
				memset(buffer2,'\0',sizeof(buffer2));
				for(i=0;i<256;i++)
					buffer1[i]=i;
				// start the transfer of 256 bytes from buffer1 to buffer2. this executes asynchronously.
				dma.beginCopyMemory(buffer2,buffer1,sizeof(buffer1),DMA_Priority_Medium);
				// wait for transfer complete via the IRQ
				while(!_completed);
				// verify the result
				for(i=0;i<256;i++)
					if(buffer2[i]!=i)
						for(;;);					// lock up on error
				// flash the LED for a second
				pf[LED_PIN].reset();
				MillisecondTimer::delay(1000);
				pf[LED_PIN].set();
				MillisecondTimer::delay(1000);
			}
		}
		/*
		 * Observer callback is fired when the DMA transfer is complete
		 */
		virtual void onNotify(Observable&,ObservableEvent::E event,void *) {
			if(event==ObservableEvent::DMA_TransferComplete)
				_completed=true;
		}
};
/*
 * Main entry point
 */
int main() {
	// set up SysTick at 1ms resolution
	MillisecondTimer::initialise();
	DmaCopyTest test;
	test.run();
	// not reached
	return 0;
}
 
dma_fill
Click here to hide the full dma_fill code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/dma.h"
#include "config/timing.h"
using namespace stm32plus;
/**
 * Demo of the DMA peripheral used to fill a block of
 * memory with a single byte. We will repeatedly fill a
 * buffer with 0xAA and check that it's done OK. If so
 * then a LED on PF6 will blink once per second.
 *
 * DMA1, channel 4 is used for this demo for F1
 * devices and DMA2, channel3, stream 4 is used for
 * F4 devices.
 *
 * If this example is to be run on the STM32F4DISCOVERY
 * board then change the LED configuration from PF6 to
 * PD13 and invert the set() / reset() logic because
 * that LED is active HIGH.
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103ZET6
 *   STM32F407VGT6
 */
class DmaFillTest {
	protected:
		/**
		 * The LED is on PF6
		 */
		enum { LED_PIN = 6 };
	public:
		void run() {
			uint8_t buffer[256],byteToFill;
			int i;
			// initialise the LED pin
			GpioF<DefaultDigitalOutputFeature<LED_PIN> > pf;
			// lights off (this LED is active low, i.e. PF6 is a sink)
			pf[LED_PIN].set();
			// declare a DMA channel with the memory fill feature
			// F4 users note that only DMA2 can do memory-to-memory transfers.
#if defined(STM32PLUS_F1)
			Dma1Channel4<
				DmaMemoryFillFeature<> 				// memory fill with default transfer size (bytes)
			> dma;
#elif defined(STM32PLUS_F4)
			Dma2Channel3Stream4<
				DmaMemoryFillFeature<> 				// memory fill with default transfer size (bytes)
			> dma;
#endif
			byteToFill=0xaa;
			for(;;) {
				// clear the target buffer
				memset(buffer,'\0',sizeof(buffer));
				// start the transfer of 256 bytes from buffer1 to buffer2. this executes asynchronously.
				dma.beginCopyMemory(buffer,&byteToFill,sizeof(buffer),DMA_Priority_Medium);
				// wait for transfer complete
				dma.waitUntilComplete();
				// verify the result
				for(i=0;i<256;i++)
					if(buffer[i]!=0xaa)
						for(;;);					// lock up on error
				// flash the LED for a second
				pf[LED_PIN].reset();
				MillisecondTimer::delay(1000);
				pf[LED_PIN].set();
				MillisecondTimer::delay(1000);
			}
		}
};
/*
 * Main entry point
 */
int main() {
	// set up SysTick at 1ms resolution
	MillisecondTimer::initialise();
	DmaFillTest test;
	test.run();
	// not reached
	return 0;
}
 
exti
Click here to hide the full exti code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/button.h"
#include "config/exti.h"
using namespace stm32plus;
/**
 * Button demo that uses EXTI interrupts to signal that
 * the button is pressed. EXTI allows you to process
 * input from GPIO pins asynchronously.
 *
 * This demo assumes that you have a button on PA8 and
 * an LED on PF6. The LED will light as long as the
 * button is held down.
 *
 * An Exti8 (external interrupt) is attached to PA8 and
 * is configured to trigger on both rising (pressed)
 * and falling (released) edges.
 *
 * To use this demo on the STM32F4DISCOVERY board you
 * will need to make the following changes to target the
 * onboard button and LEDs:
 *
 *  LED_PIN to 13
 * 	BUTTON_PIN to 0
 * 	GpioF... to GpioD...
 * 	Exti8 to Exit0
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103ZET6
 *   STM32F407VGT6
 */
class ExtiTest : public Observer {
	protected:
		volatile bool _stateChanged;
		enum {
			LED_PIN = 6,
			BUTTON_PIN = 8
		};
	public:
		void run() {
			// initialise the LED and button pins
			GpioF<DefaultDigitalOutputFeature<LED_PIN> > pf;
			GpioA<DefaultDigitalInputFeature<BUTTON_PIN> > pa;
			// enable EXTI on the button pin and subscribe to interrupts
			Exti8 exti(EXTI_Mode_Interrupt,EXTI_Trigger_Rising_Falling,pa[BUTTON_PIN]);
			exti.insertObserver(*this);
			// lights off (this LED is active low, i.e. PF6 is a sink)
			pf[LED_PIN].set();
			// main loop
			for(;;) {
				_stateChanged=false;			// race conditition, but it's demo code...
				// wait for the interrupt to tell us that there's been a button press/release
				while(!_stateChanged);
				// act on the new state and reset for the next run
				pf[LED_PIN].setState(pa[BUTTON_PIN].read());
			}
		}
		/**
		 * Observer callback from the EXTI interrupt
		 */
		virtual void onNotify(Observable&,ObservableEvent::E,void *) {
			_stateChanged=true;
		}
};
/*
 * Main entry point
 */
int main() {
	ExtiTest test;
	test.run();
	// not reached
	return 0;
}
 
fatfs_iterate
Click here to hide the full fatfs_iterate code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/nvic.h"
#include "config/sdcard.h"
#include "config/filesystem.h"
#include "config/display/tft.h"
// we're going to use the STL string
#include <iterator>
#include <string>
using namespace stm32plus;
using namespace stm32plus::display;
/**
 * FAT file system iterator demo.
 *
 * This example will recursively iterate over the
 * directories and files on a FAT16/32 file system
 * on an SD card connected via SDIO. The SD card
 * must be inserted and ready when this application
 * runs. This demo was tested on a 4Gb class 10
 * SDHC microSD card.
 *
 * The output of the program is sent to a graphical
 * LCD, in this case an ILI9325 panel connected via
 * the FSMC. Other LCD drivers can be used by
 * changing the device driver name and ensuring that
 * the correct access mode is selected (8 or 16 bit).
 *
 * Because I use the STL string I have added
 * include/stl to the compile-time include path.
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103ZET6
 *   STM32F407VGT6
 */
class FatFsIterateTest  {
	protected:
		// graphics library and terminal types and objects
		typedef Fsmc16BitAccessMode<FsmcBank1NorSram1> LcdAccessMode;
		typedef ILI9325_Portrait_64K<LcdAccessMode> LcdPanel;
		typedef ILI9325_Terminal_Portrait_64K<LcdPanel> LcdTerminal;
		LcdAccessMode *_accessMode;
		LcdPanel *_graphicsLibrary;
		LcdTerminal *_terminal;
		Font *_font;
		DefaultBacklight *_backlight;
		// SD card and file system objects
		SdioDmaSdCard *_sdcard;
		FileSystem *_fs;
		NullTimeProvider _timeProvider;
	public:
		/*
		 * Run the demo
		 */
		void run() {
			// initialisation for the card and LCD
			initLcd();
			initSdcard();
			// now iterate the directories on the card
			iterateDirectories("");
			// we're done - lock up
			*_terminal << "Completed";
			for(;;);
		}
		/*
		 * Recursively iterate over the directories and files on this card
		 */
		void iterateDirectories(const std::string& directoryName) {
			DirectoryIterator *it;
			// print the name of the current directory
			*_terminal << "=> " << directoryName.c_str() << "\n";
			// get an iterator on to this directory. note that we own the returned
			// pointer and must delete it when we're finished.
			if(!_fs->getDirectoryIterator(directoryName.c_str(),it))
				error();
			// iterate over all entries in this directory
			while(it->next()) {
				// get a reference to the FileInformation object that describes the file/directory
				// that we're currently looking at
				const FileInformation& fileInfo(it->current());
				// print the name and length in bytes. other attributes such as the type and various
				// date/times are also available
				*_terminal << fileInfo.getFilename() << " = " << fileInfo.getLength() << " bytes\n";
				// if this is a directory and it's not one of the two special "." and ".." entries then
				// recursively print its contents
				if((fileInfo.getAttributes() & FileInformation::ATTR_DIRECTORY)!=0
						&& strcmp(".",fileInfo.getFilename())!=0
						&& strcmp("..",fileInfo.getFilename())!=0) {
					iterateDirectories(directoryName+"/"+std::string(fileInfo.getFilename()));
				}
			}
			// finished with the iterator, delete it
			delete it;
		}
		/*
		 * Initialise the LCD. This demo uses the ILI9325 QVGA LCD connected to the FSMC
		 * in 16 bit mode. We use a portrait-orientation terminal that will take advantage of
		 * the hardware scrolling ability of the panel.
		 */
		void initLcd() {
			// reset is on PE1 and RS (D/CX) is on PD11
			GpioE<DefaultDigitalOutputFeature<1> > pe;
			GpioD<DefaultAlternateFunctionFeature<GPIO_AF_FSMC,11> > pd;
			// set up the FSMC with RS=A16 (PD11)
			Fsmc8080LcdTiming fsmcTiming(0,2);
			_accessMode=new LcdAccessMode(fsmcTiming,16,pe[1]);
			// declare an lcd driver and make a fixed font active
			_graphicsLibrary=new LcdPanel(*_accessMode);
			_font=new Font_APPLE8;
			*_graphicsLibrary << *_font;
			// declare the terminal
			_terminal=new LcdTerminal(_graphicsLibrary);
			// clear the screen
			_graphicsLibrary->setBackground(ColourNames::BLACK);
			_graphicsLibrary->setForeground(ColourNames::WHITE);
			_terminal->clearScreen();
			// create the backlight on timer4, channel2 (PD13)
			DefaultBacklight backlight;
			// fade up to 100% in 4ms steps
			backlight.fadeTo(100,4);
		}
		/*
		 * Initialise the SD card and get a reference to a file system object. FAT16 and FAT32
		 * are both supported.
		 */
		void initSdcard() {
			// create the SDIO object and let it auto-initialise
			_sdcard=new SdioDmaSdCard;
			if(errorProvider.hasError())
				error();
			// initialise a file system from that found on the card
			if(!FileSystem::getInstance(*_sdcard,_timeProvider,_fs))
				error();
		}
		/*
		 * Print an error code if something goes wrong and lock up
		 */
		void error() {
			// print the error code
			*_terminal << "ERROR: " << errorProvider.getLast();
			// lock up
			for(;;);
		}
};
/*
 * Main entry point
 */
int main() {
	// set up the NVIC priority groups and subgroups
	Nvic::initialise();
	// set up SysTick at 1ms resolution
	MillisecondTimer::initialise();
	FatFsIterateTest test;
	test.run();
	// not reached
	return 0;
}
 
fatfs_reader
Click here to hide the full fatfs_reader code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/nvic.h"
#include "config/sdcard.h"
#include "config/filesystem.h"
#include "config/usart.h"
#include "config/string.h"
using namespace stm32plus;
/**
 * FAT file system reader demo.
 *
 * Tihs example will open a text file from a subdirectory
 * of the SD card and write the contents to USART1. The
 * filename is /files/test.txt. To run this demo you must
 * have USART1 wired to a terminal program on the PC that
 * is set up to receive at 57600-8-N-1 mode. I recommend
 * the free "RealTerm" program.
 *
 * Note that if you are using the STM32F4DISCOVERY board
 * then you cannot use Usart1 since the pins clash with
 * onboard peripherals. I have tested this code on that
 * board using Usart2.
 *
 * The SD card must be inserted and ready when this
 * application runs. This demo was tested on a 4Gb class
 * 10 SDHC microSD card.
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103ZET6
 *   STM32F407VGT6
 */
class FatFsReaderTest  {
	protected:
		// SD card and file system objects
		SdioDmaSdCard *_sdcard;
		FileSystem *_fs;
		NullTimeProvider _timeProvider;
		// USART objects
		typedef Usart1<> MyUsart;
		MyUsart *_usart;
	public:
		/*
		 * Run the demo
		 */
		void run() {
			// initialisation for the card and LCD
			initUsart();
			initSdcard();
			// now send the file
			sendFile("/files/test.txt");
			// we're done - lock up
			for(;;);
		}
		/*
		 * open the file and send the contents to the USART
		 */
		void sendFile(const char *filename) {
			File *file;
			// open the file - we own the file pointer that comes back upon success and
			// we must remember to delete it when we're finished
			if(!_fs->openFile(filename,file))
				error();
			// attach an input stream to the file for easy sequential reading and an output
			// stream to the usart for writing
			FileInputStream input(*file);
			UsartPollingOutputStream output(*_usart);
			// the ConnectedInputOutputStream is a piece of plumbing that will copy one
			// stream to another either as a whole or in chunks
			ConnectedInputOutputStream connector(input,output);
			// copy the entire file to the USART
			if(!connector.readWrite())
				error();
			// finished with the file
			delete file;
		}
		/*
		 * Initialise the USART in 57600-8-N-1 mode with no hardware flow control
		 */
		void initUsart() {
			// configure the USART peripheral
			_usart=new MyUsart(57600);
		}
		/*
		 * Initialise the SD card and get a reference to a file system object. FAT16 and FAT32
		 * are both supported.
		 */
		void initSdcard() {
			// create the SDIO object and let it auto-initialise
			_sdcard=new SdioDmaSdCard;
			if(errorProvider.hasError())
				error();
			// initialise a file system from that found on the card
			if(!FileSystem::getInstance(*_sdcard,_timeProvider,_fs))
				error();
		}
		/*
		 * Print an error code if something goes wrong and lock up
		 */
		void error() {
			char *ptr,errorCode[30];
			// print the error code
			StringUtil::modp_uitoa10(errorProvider.getLast(),errorCode);
			for(ptr=errorCode;*ptr;ptr++)
				_usart->send(*ptr);
			// lock up
			for(;;);
		}
};
/*
 * Main entry point
 */
int main() {
	// set up the NVIC priority groups and subgroups
	Nvic::initialise();
	// set up SysTick at 1ms resolution
	MillisecondTimer::initialise();
	FatFsReaderTest test;
	test.run();
	// not reached
	return 0;
}
 
fatfs_writer
Click here to hide the full fatfs_writer code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/nvic.h"
#include "config/sdcard.h"
#include "config/filesystem.h"
#include "config/usart.h"
#include "config/string.h"
using namespace stm32plus;
/**
 * FAT file system writer demo.
 *
 * This example will create a file called "test.txt" in a
 * directory called "output" on the SD card. If the
 * directory does not exist then it will be created. If
 * the file does exist then it will be deleted before we
 * open it for writing.
 *
 * When we're done writing to it we will re-open the
 * file and write the content to USART1.
 *
 * Note that if you are using the STM32F4DISCOVERY board
 * then you cannot use Usart1 since the pins clash with
 * onboard peripherals. I have tested this code on that
 * board using Usart2.
 *
 * The SD card must be inserted and ready when this
 * application runs. This demo was tested on a 4Gb
 * class 10 SDHC microSD card.
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103ZET6
 *   STM32F407VGT6
 */
class FatFsReaderTest  {
	protected:
		// SD card and file system objects
		SdioDmaSdCard *_sdcard;
		FileSystem *_fs;
		NullTimeProvider _timeProvider;
		// USART objects
		typedef Usart1<> MyUsart;
		MyUsart *_usart;
	public:
		/*
		 * Run the demo
		 */
		void run() {
			// initialisation for the card and LCD
			initUsart();
			initSdcard();
			// now do the work
			ensureDirectoryExists();
			ensureFileDoesNotExist();
			writeToFile();
			sendFile();
			// we're done - lock up
			for(;;);
		}
		/*
		 * Ensure that /output exists. If it does not then it will be created. If it
		 * does exist then we check that it is a directory and not a file.
		 */
		void ensureDirectoryExists() {
			FileInformation *info;
			// get a FileInformation for the directory
			if(_fs->getFileInformation("/output",info)) {
				// it exists - but if it's a file then it's an error
				if((info->getAttributes() & FileInformation::ATTR_DIRECTORY)==0)
					error();
				// it's a directory, that's OK
				delete info;
				return;
			}
			// it does not exist, create it
			if(!_fs->createDirectory("/output"))
				error();
		}
		/*
		 * Ensure that the file does not exist. If it does exist then
		 * it will be deleted.
		 */
		void ensureFileDoesNotExist() {
			FileInformation *info;
			// get a FileInformation for the file
			if(_fs->getFileInformation("/output/test.txt",info)) {
				// it exists - make sure it's not a directory
				if((info->getAttributes() & FileInformation::ATTR_DIRECTORY)!=0)
					error();
				// clean up
				delete info;
				// we know it's a file, delete it
				if(!_fs->deleteFile("/output/test.txt"))
					error();
				return;
			}
		}
		/*
		 * Write the text "Hello World" to /output/test.txt. It is not necessary to delete/create
		 * the file - it could be re-opened and overwritten either from the beginning or by seeking
		 * to the end and appending to it.
		 */
		void writeToFile() {
			File *file;
			// any previous file has been erased, open this file. there is no concept of file mode
			// here - any file can be read or written to.
			if(!_fs->createFile("/output/test.txt"))
				error();
			// open the 0 byte file
			if(!_fs->openFile("/output/test.txt",file))
				error();
			// write some test data
			if(!file->write("Hello World",11))
				error();
			// finished with the file - close it
			delete file;
		}
		/*
		 * open the file and send the contents to the USART
		 */
		void sendFile() {
			File *file;
			// open the file - we own the file pointer that comes back upon success and
			// we must remember to delete it when we're finished
			if(!_fs->openFile("/output/test.txt",file))
				error();
			// attach an input stream to the file for easy sequential reading and an output
			// stream to the usart for writing
			FileInputStream input(*file);
			UsartPollingOutputStream output(*_usart);
			// the ConnectedInputOutputStream is a piece of plumbing that will copy one
			// stream to another either as a whole or in chunks
			ConnectedInputOutputStream connector(input,output);
			// copy the entire file to the USART
			if(!connector.readWrite())
				error();
			// finished with the file
			delete file;
		}
		/*
		 * Initialise the USART in 57600-8-N-1 mode with no hardware flow control
		 */
		void initUsart() {
			// configure the USART peripheral
			_usart=new MyUsart(57600);
		}
		/*
		 * Initialise the SD card and get a reference to a file system object. FAT16 and FAT32
		 * are both supported.
		 */
		void initSdcard() {
			// create the SDIO object and let it auto-initialise
			_sdcard=new SdioDmaSdCard;
			if(errorProvider.hasError())
				error();
			// initialise a file system from that found on the card
			if(!FileSystem::getInstance(*_sdcard,_timeProvider,_fs))
				error();
		}
		/*
		 * Print an error code if something goes wrong and lock up
		 */
		void error() {
			char *ptr,errorCode[30];
			// print the error code
			StringUtil::modp_uitoa10(errorProvider.getLast(),errorCode);
			for(ptr=errorCode;*ptr;ptr++)
				_usart->send(*ptr);
			// lock up
			for(;;);
		}
};
/*
 * Main entry point
 */
int main() {
	// set up the NVIC priority groups and subgroups
	Nvic::initialise();
	// set up SysTick at 1ms resolution
	MillisecondTimer::initialise();
	FatFsReaderTest test;
	test.run();
	// not reached
	return 0;
}
 
fsmc_sram
Click here to hide the full fsmc_sram code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/sram.h"
#include "config/timing.h"
#include "config/stream.h"
using namespace stm32plus;
/**
 * Demo of an SRAM chip connected to the FSMC on an
 * STM32F103ZET6 (LQFP144). In this case it's an ISSI
 * IS61LV25616 256K x 16 (4Mbit) SRAM on bank #3.
 *
 * This demo will write a repeating pattern to the SRAM
 * and read it back afterwards. If it is successful
 * then a LED attached to PF6 will be flashed for 500ms.
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103ZET6
 */
class FsmcSramTest  {
	protected:
		/**
		 * The pin number of the LED
		 */
		enum { LED_PIN = 6 };
		/**
		 * The SRAM and FSMC location typedef
		 */
		typedef IS61LV25616<FsmcBank1NorSram3> MySram;
	public:
		void run() {
			GpioF<DefaultDigitalOutputFeature<LED_PIN> > pf;
			// initialise the SRAM
			MySram sram(MySram::TEN_NS);
			// lights off (this LED is active low, i.e. PF6 is a sink)
			pf[6].set();
			for(;;) {
				testDirect(pf[LED_PIN]);
				testStream(sram,pf[LED_PIN]);
			}
		}
		/**
		 * Test by directly accessing the memory locations
		 */
		void testDirect(GpioPinRef led) {
			uint32_t i;
			uint16_t *ptr;
			// write a pattern
			ptr=FsmcBank1NorSram3::getBaseAddress<uint16_t>();
			for(i=0;i<MySram::SIZE_IN_BYTES/2;i++)
				*ptr++=0xaa55;
			// read it back
			ptr=FsmcBank1NorSram3::getBaseAddress<uint16_t>();
			for(i=0;i<MySram::SIZE_IN_BYTES/2;i++)
				if(*ptr++!=0xaa55)
					for(;;);									// lock up
			// switch the LED on and off for 500ms
			led.reset();
			MillisecondTimer::delay(500);
			led.set();
			MillisecondTimer::delay(500);
		}
		/**
		 * Test by accessing as a stream. This test writes out a string repeatedly
		 * until the SRAM is full and then reads it back to make sure it's good.
		 */
		void testStream(MySram& sram,GpioPinRef led) {
			int32_t available;
			uint32_t actuallyRead;
			char buffer[28];
			{
				// initialise a buffered output stream on to the memory
				BlockDeviceOutputStream os(sram,0,true);
				// write out a pattern to the stream
				for(available=MySram::SIZE_IN_BYTES;available>=27;available-=27)
					os.write("Hello world, this is a test",27);			// 27 bytes
			}
			// initialise an input stream on to the memory
			BlockDeviceInputStream is(sram,0);
			// read back the data
			buffer[27]='\0';
			for(available=MySram::SIZE_IN_BYTES;available>=27;available-=27) {
				// get 27 bytes from the stream
				if(!is.read(buffer,27,actuallyRead) || actuallyRead!=27)
					for(;;);
				// ensure it's what we expect
				if(strcmp(buffer,"Hello world, this is a test")!=0)
					for(;;);
			}
			// switch the LED on and off for 500ms
			led.reset();
			MillisecondTimer::delay(500);
			led.set();
			MillisecondTimer::delay(500);
		}
};
/*
 * Main entry point
 */
int main() {
	// set up SysTick at 1ms resolution
	MillisecondTimer::initialise();
	FsmcSramTest test;
	test.run();
	// not reached
	return 0;
}
 
hd44780
Click here to hide the full hd44780 code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/display/character.h"
using namespace stm32plus;
using namespace stm32plus::display;
/**
 *
 * HD44780 20x4 character LCD demo. For this demonstration
 * we will attach the character LCD to the following pins:
 *
 * PC[0] => RS
 * PC[1] => ENABLE
 * PC[2] => D0
 * PC[3] => D1
 * PC[4] => D2
 * PC[5] => D3
 *
 * This demonstration attachs a text terminal class to the
 * LCD for convenient text output. We then go into an
 * infinite loop writing out the famous Lorem Ipsum
 * passage, scrolling the display each time the output
 * reaches the end of the display.
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103ZET6
 *   STM32F407VGT6
 */
/**
 * The sample text
 */
static const char *sampleText[]={
  "Lorem","ipsum","dolor","sit","amet,","consectetur","adipisicing","elit,","sed","do","eiusmod","tempor","incididunt","ut","labore","et","dolore","magna","aliqua.","Ut","enim","ad","minim","veniam,","quis","nostrud","exercitation","ullamco","laboris","nisi","ut","aliquip","ex","ea","commodo","consequat.","Duis","aute","irure","dolor","in","reprehenderit","in","voluptate","velit","esse","cillum","dolore","eu","fugiat","nulla","pariatur.","Excepteur","sint","occaecat","cupidatat","non","proident,","sunt","in","culpa","qui","officia","deserunt","mollit","anim","id","est","laborum",NULL
};
class HD44780Test {
	public:
		void run() {
			int i,written,len;
			/*
			 * Initialise the 6 required pins for output
			 */
			GpioC<DefaultDigitalOutputFeature<0,1,2,3,4,5> > pc;
			/*
			 * Initialise the 20x4 display
			 */
			HD44780 lcd(pc[0],pc[1],pc[2],pc[3],pc[4],pc[5],20,4);
			/*
			 * Attach a terminal to the display so we can easily demonstrate the
			 * text output function
			 */
			CharacterLcdTerminal<HD44780> terminal(lcd);
			/*
			 * Write out the sample text
			 */
			terminal.clear();
			for(i=written=0;;) {
				// if the current word plus trailing space would wrap, start a new line
				len=strlen(sampleText[i])+1;
				if(written+len>20) {
					terminal << '\n';
					written=0;
				}
				// write out the current word with the following space
				terminal << sampleText[i] << ' ';
				written+=len;
				// if there is no next word then start again
				if(sampleText[++i]==NULL)
					i=0;
				// delay for a 500ms before the next word
				MillisecondTimer::delay(500);
			}
		}
};
/*
 * Main entry point
 */
int main() {
	// set up SysTick at 1ms resolution
	MillisecondTimer::initialise();
	HD44780Test test;
	test.run();
	// not reached
	return 0;
}
 
hx8347a
Click here to hide the full hx8347a code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/display/tft.h"
extern uint32_t BulbPixelsSize,BulbPixels;
extern uint32_t AudioPixelsSize,AudioPixels;
extern uint32_t FlagPixelsSize,FlagPixels;
extern uint32_t DocPixelsSize,DocPixels;
extern uint32_t GlobePixelsSize,GlobePixels;
extern uint32_t JpegTest0Pixels,JpegTest0PixelsSize;
using namespace stm32plus;
using namespace stm32plus::display;
/**
 * HX8347A LCD test, show a looping graphics demo
 *
 * It's a 16-bit device and we control it in this demo
 * using the FSMC peripheral on bank 1. The wiring
 * that you need to do is as follows:
 *
 * PE1  => RESET
 * PD11 => RS (D/CX)
 * PD7  => CS
 * PD4  => RD
 * PD5  => WR
 * PD14 => D0    PE11 => D8
 * PD15 => D1    PE12 => D9
 * PD0  => D2    PE13 => D10
 * PD1  => D3    PE14 => D11
 * PE7  => D4    PE15 => D12
 * PE8  => D5    PD8  => D13
 * PE9  => D6    PD9  => D14
 * PD10 => D7    PD10 => D15
 * PD13 => Backlight PWM (if variable backlight)
 *
 * The code works without structural change on both
 * the F1 and F4. I had to additional wait states
 * to the data setup time to get my panel to work on
 * the F4. You may also have to adjust.
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103VET6
 *   STM32F407VGT6
 */
class HX8347ATest {
	protected:
		typedef Fsmc16BitAccessMode<FsmcBank1NorSram1> LcdAccessMode;
		typedef HX8347A_Portrait_64K<LcdAccessMode> LcdPanel;
		LcdAccessMode *_accessMode;
		LcdPanel *_gl;
		Font *_font;
	public:
		void run() {
			// reset is on PE1 and RS (D/CX) is on PD11
			GpioE<DefaultDigitalOutputFeature<1> > pe;
			GpioD<DefaultAlternateFunctionFeature<GPIO_AF_FSMC,11> > pd;
			// set up the FSMC timing. these numbers (particularly the data setup time) are dependent on
			// both the FSMC bus speed and the panel timing parameters.
#if defined(STM32PLUS_F1)
			Fsmc8080LcdTiming fsmcTiming(0,2);
#elif defined(STM32PLUS_F4)
			Fsmc8080LcdTiming fsmcTiming(1,15);
#else
#error Unsupported MCU
#endif
			// set up the FSMC with RS=A16 (PD11)
			_accessMode=new LcdAccessMode(fsmcTiming,16,pe[1]);
			// declare a panel
			_gl=new LcdPanel(*_accessMode);
			// apply gamma settings
			HX8347AGamma gamma(0,7,0,0,0x10,0,0,0x16,0,0,0,0);
			_gl->applyGamma(gamma);
			// clear to black while the lights are out
			_gl->setBackground(0);
			_gl->clearScreen();
			// create the backlight on timer4, channel2 (PD13)
			DefaultBacklight backlight;
			// fade up to 100% in 4ms steps
			backlight.fadeTo(100,4);
			// create a font
			_font=new Font_VOLTER__28GOLDFISH_299;
			*_gl << *_font;
			for(;;) {
				jpegTest();
				lzgTest();
				basicColoursTest();
				textTest();
				scrollTest();
				ellipseTest();
				gradientTest();
				rectTest();
				lineTest();
				clearTest();
				sleepTest();
			}
		}
		void sleepTest() {
			prompt("Sleep test");
			// go to sleep
			*_gl << Point::Origin << "Sleeping now...";
			MillisecondTimer::delay(1000);
			_gl->sleep();
			MillisecondTimer::delay(3000);
			// wake up
			_gl->wake();
			_gl->clearScreen();
			*_gl << Point::Origin << "Woken up again...";
			MillisecondTimer::delay(3000);
		}
		void jpegTest() {
			// only draw in portrait mode and if it can fit on screen
			if(_gl->getHeight()>_gl->getWidth() && _gl->getHeight()>=320 && _gl->getWidth()>=240) {
				prompt("JPEG bitmap test");
				// draw it centered
				LinearBufferInputOutputStream compressedData((uint8_t *)&JpegTest0Pixels,(uint32_t)&JpegTest0PixelsSize);
				_gl->drawJpeg(Rectangle((_gl->getWidth()-240)/2,(_gl->getHeight()-320)/2,240,320),compressedData);
				MillisecondTimer::delay(3000);
			}
		}
		void lzgTest() {
			prompt("LZG bitmap test");
			// declare a DMA instance with a copy-to-fsmc feature
#if defined(STM32PLUS_F1)
			Dma1Channel6<DmaFsmcLcdMemoryCopyFeature<LcdAccessMode> > dma;
#elif defined(STM32PLUS_F4)
			Dma2Channel1Stream2<DmaFsmcLcdMemoryCopyFeature<LcdAccessMode> > dma;
#endif
			drawCompressedBitmap((uint8_t *)&BulbPixels,(uint32_t)&BulbPixelsSize,89,148,true,dma);
			drawCompressedBitmap((uint8_t *)&AudioPixels,(uint32_t)&AudioPixelsSize,150,161,false,dma);
			drawCompressedBitmap((uint8_t *)&FlagPixels,(uint32_t)&FlagPixelsSize,144,220,true,dma);
			drawCompressedBitmap((uint8_t *)&DocPixels,(uint32_t)&DocPixelsSize,200,240,false,dma);
			drawCompressedBitmap((uint8_t *)&GlobePixels,(uint32_t)&GlobePixelsSize,193,219,true,dma);
		}
		void drawCompressedBitmap(uint8_t *pixels,uint32_t size,uint16_t width,uint16_t height,bool useDma,DmaFsmcLcdMemoryCopyFeature<LcdAccessMode>& dma) {
			_gl->setBackground(ColourNames::WHITE);
			_gl->clearScreen();
			LinearBufferInputOutputStream compressedData(pixels,size);
			LzgDecompressionStream decompressor(compressedData,size);
			if(useDma) {
				_gl->drawBitmap(
						Rectangle((_gl->getWidth()-width)/2,
								(_gl->getHeight()-height)/2,
								width,height),
								decompressor,
								dma);
			}
			else {
				_gl->drawBitmap(
						Rectangle((_gl->getWidth()-width)/2,
								(_gl->getHeight()-height)/2,
								width,height),
								decompressor);
			}
			MillisecondTimer::delay(3000);
		}
		void textTest() {
			int i;
			const char *str="The quick brown fox";
			Size size;
			Point p;
			uint32_t before,elapsed;
			prompt("Stream operators test");
			*_gl << Point::Origin << "Let's see PI:";
			for(i=0;i<=7;i++)
				*_gl << Point(0,(1+i)*_font->getHeight()) << DoublePrecision(3.1415926535,i);
			MillisecondTimer::delay(5000);
			prompt("Opaque text test");
			size=_gl->measureString(*_font,str);
			before=MillisecondTimer::millis();
			for(i=0;i<3000;i++) {
				p.X=rand() % (_gl->getXmax()-size.Width);
				p.Y=rand() % (_gl->getYmax()-size.Height);
				_gl->setForeground(rand());
				_gl->writeString(p,*_font,str);
			}
			elapsed=MillisecondTimer::millis()-before;
			_gl->clearScreen();
			_gl->setForeground(ColourNames::WHITE);
			*_gl << Point::Origin << "Elapsed: " << (int32_t)elapsed << "ms";
			MillisecondTimer::delay(3000);
		}
		void scrollTest() {
			int32_t i,j,numRows;
			Point p;
			prompt("Hardware scrolling test");
			_gl->setForeground(0xffffff);
			_gl->setBackground(0);
			_gl->clearScreen();
			numRows=((_gl->getYmax()+1)/_font->getHeight())/3;
			p.X=0;
			for(i=0;i<numRows;i++) {
				p.Y=(numRows+i)*_font->getHeight();
				*_gl << p << "Test row " << i;
			}
			for(j=0;j<15;j++) {
				numRows=(_gl->getYmax()+1)/4;
				for(i=0;i<numRows;i++) {
					_gl->setScrollPosition(i);
					MillisecondTimer::delay(5);
				}
				for(i=0;i<numRows;i++) {
					_gl->setScrollPosition(numRows-i);
					MillisecondTimer::delay(5);
				}
			}
			_gl->setScrollPosition(0);
		}
		void clearTest() {
			int i;
			uint32_t start;
			prompt("Clear screen test");
			for(i=0;i<200;i++) {
				_gl->setBackground(rand());
				start=MillisecondTimer::millis();
				_gl->clearScreen();
				stopTimer(" to clear",MillisecondTimer::millis()-start);
			}
		}
		void basicColoursTest() {
			uint16_t i;
			static const uint32_t colours[7]={
			  ColourNames::RED,
			  ColourNames::GREEN,
			  ColourNames::BLUE,
			  ColourNames::CYAN,
			  ColourNames::MAGENTA,
			  ColourNames::YELLOW,
			  ColourNames::BLACK,
			};
			prompt("Basic colours test");
			for(i=0;i<sizeof(colours)/sizeof(colours[0]);i++) {
				_gl->setBackground(colours[i]);
				_gl->clearScreen();
				MillisecondTimer::delay(500);
			}
		}
		void lineTest() {
			Point p1,p2;
			int i;
			prompt("Line test");
			for(i=0;i<5000;i++) {
				p1.X=rand() % _gl->getXmax();
				p1.Y=rand() % _gl->getYmax();
				p2.X=rand() % _gl->getXmax();
				p2.Y=rand() % _gl->getYmax();
				_gl->setForeground(rand());
				_gl->drawLine(p1,p2);
			}
		}
		void rectTest() {
			int i;
			Rectangle rc;
			prompt("Rectangle test");
			for(i=0;i<1500;i++) {
				rc.X=(rand() % _gl->getXmax()/2);
				rc.Y=(rand() % _gl->getXmax()/2);
				rc.Width=rand() % (_gl->getXmax()-rc.X);
				rc.Height=rand() % (_gl->getYmax()-rc.Y);
				_gl->setForeground(rand());
				_gl->fillRectangle(rc);
			}
			_gl->clearScreen();
			for(i=0;i<10000;i++) {
				rc.X=(rand() % _gl->getXmax()/2);
				rc.Y=(rand() % _gl->getXmax()/2);
				rc.Width=rand() % (_gl->getXmax()-rc.X);
				rc.Height=rand() % (_gl->getYmax()-rc.Y);
				_gl->setForeground(rand());
				_gl->drawRectangle(rc);
				if(i % 1000 ==0)
					_gl->clearScreen();
			}
		}
		void ellipseTest() {
			int16_t i;
			Point p;
			Size s;
			prompt("Ellipse test");
			_gl->setBackground(0);
			for(i=0;i<1000;i++) {
				p.X=_gl->getXmax()/4+(rand() % (_gl->getXmax()/2));
				p.Y=_gl->getYmax()/4+(rand() % (_gl->getYmax()/2));
				if(p.X<_gl->getXmax()/2)
					s.Width=rand() % p.X;
				else
					s.Width=rand() % (_gl->getXmax()-p.X);
				if(p.Y<_gl->getYmax()/2)
					s.Height=rand() % p.Y;
				else
					s.Height=rand() % (_gl->getYmax()-p.Y);
				_gl->setForeground(rand());
				_gl->fillEllipse(p,s);
			}
			_gl->clearScreen();
			for(i=0;i<1500;i++) {
				p.X=_gl->getXmax()/4+(rand() % (_gl->getXmax()/2));
				p.Y=_gl->getYmax()/4+(rand() % (_gl->getYmax()/2));
				if(p.X<_gl->getXmax()/2)
					s.Width=rand() % p.X;
				else
					s.Width=rand() % (_gl->getXmax()-p.X);
				if(p.Y<_gl->getYmax()/2)
					s.Height=rand() % p.Y;
				else
					s.Height=rand() % (_gl->getYmax()-p.Y);
				if(s.Height>0 && s.Width>0 && p.X+s.Width<_gl->getXmax() && p.Y+s.Height<_gl->getYmax()) {
					_gl->setForeground(rand());
					_gl->drawEllipse(p,s);
				}
				if(i % 500==0)
					_gl->clearScreen();
			}
		}
		void doGradientFills(Direction dir) {
			Rectangle rc;
			uint16_t i;
			static uint32_t colours[7]={
				ColourNames::RED,
				ColourNames::GREEN,
				ColourNames::BLUE,
				ColourNames::CYAN,
				ColourNames::MAGENTA,
				ColourNames::YELLOW,
				ColourNames::WHITE,
			};
			rc.Width=_gl->getXmax()+1;
			rc.Height=(_gl->getYmax()+1)/2;
			for(i=0;i<sizeof(colours)/sizeof(colours[0]);i++) {
				rc.X=0;
				rc.Y=0;
				_gl->gradientFillRectangle(rc,dir,ColourNames::BLACK,colours[i]);
				rc.Y=rc.Height;
				_gl->gradientFillRectangle(rc,dir,colours[i],ColourNames::BLACK);
				MillisecondTimer::delay(1000);
			}
		}
		void gradientTest() {
			prompt("Gradient test");
			doGradientFills(HORIZONTAL);
			doGradientFills(VERTICAL);
		}
		void prompt(const char *prompt) {
			_gl->setBackground(ColourNames::BLACK);
			_gl->clearScreen();
			_gl->setForeground(ColourNames::WHITE);
			*_gl << Point(0,0) << prompt;
			MillisecondTimer::delay(2000);
			_gl->clearScreen();
		}
		void stopTimer(const char *prompt,uint32_t elapsed) {
			_gl->setForeground(0xffffff);
			*_gl << Point(0,0) << (int32_t)elapsed << "ms " << prompt;
		}
};
/*
 * Main entry point
 */
int main() {
	// set up SysTick at 1ms resolution
	MillisecondTimer::initialise();
	HX8347ATest test;
	test.run();
	// not reached
	return 0;
}
 
i2c_cs43l22
Click here to hide the full i2c_cs43l22 code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/dac.h"
using namespace stm32plus;
/**
 * I2C / I2S demonstration using the onboard CS43L22
 * peripheral of the STM32F4Discovery board. This
 * example will play a continuous 1kHz sine wave tone
 * at 44.1kHz. The duration of the sample is 3 seconds
 * and we just go into a loop playing it continuously.
 *
 * To make it interesting we'll use I2S interrupt
 * mode to supply the data. Plug some headphones into
 * the jack on the STM32F4Discovery to hear the output
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F407VGT6
 */
/*
 * The audio data is in audio_sample.cpp
 */
extern "C" const uint16_t AUDIO_SAMPLE[];
class CS43L22Test : public Observer {
	public:
		/*
		 * The F4 MCU packages match the pins on the F1 for equivalent peripherals but the F4 is not
		 * limited to distinct sets of pins that make up a peripheral. Annoyingly the CS43L22 on the
		 * F4Discovery board has I2C1 SCL and SDA split across what would be the default and remap
		 * pin set on the F1 so we have to use 'custom' port/pin declarations instead of using one
		 * of the I2C1_Default or I2C1_Remap pre-defined packages.
		 */
		enum {
			Port_SCL=GPIOB_BASE,//!< SCL_PORT
			Port_SDA=GPIOB_BASE,//!< SDA_PORT
			Pin_SCL=GPIO_Pin_6, //!< SCL_PIN
			Pin_SDA=GPIO_Pin_9  //!< SDA_PIN
		};
		/*
		 * Same goes for the I2S pins. They're using I2S3 on the F4Discovery board but the pin
		 * choice for I2S3 does not match the F1.
		 */
		enum {
			Port_WS   = GPIOA_BASE,
			Port_CK   = GPIOC_BASE,
			Port_SD   = GPIOC_BASE,
			Port_MCLK = GPIOC_BASE,
			Pin_WS   = GPIO_Pin_4,
			Pin_CK   = GPIO_Pin_10,
			Pin_SD   = GPIO_Pin_12,
			Pin_MCLK = GPIO_Pin_7
		};
	protected:
			enum {
				AUDIO_HEADER_SIZE = 22,			// in 16-bit words
				AUDIO_FILE_SIZE   = 132323	// in 16-bit words
			};
			/*
			 * The CS43L22 has a control and a data interface. Here we define the type that will be used
			 * for the control interface. It's going to be I2C.
			 */
			typedef CS43L22ControlI2C<						 // The I2C controller. It's templated with the I2C interface and features.
				I2C1_Custom<												 // F4 VLDiscovery pinning does not match one of the standard pinouts
					CS43L22Test,											 // get the pinning from this class
					I2CSingleByteMasterPollingFeature  // we're going to be polling in master mode
				>
			> MyDacControlInterface;
			/*
			 * The data interface for this example will be I2S. Here we define a type for it.
			 */
			typedef I2S3_Custom<					// F4 VLDiscovery pinning does not match one of the standard pinouts
					CS43L22Test,							// get the pinning from this class
					I2S3InterruptFeature			// we'll stream the data in the interrupt handler
				> MyDacDataInterface;
			/*
			 * Now define the CS43L22 type with the control and data interface
			 */
			typedef CS43L22<							// the device is parameterised with the I2C peripheral
				MyDacControlInterface,
				MyDacDataInterface
			> MyDac;
			/*
			 * Declare the peripheral pointer
			 */
			MyDac *_dac;
			/*
			 * Data pointers used in the interrupts handler
			 */
			const uint16_t *_currentAudioPointer;
			const uint16_t *_lastAudioSample;
	public:
		void run() {
			/*
			 * Declare the reset pin which is on PD4 on the F4 discovery board.
			 */
			GpioD<DefaultDigitalOutputFeature<4> > pd;
			/*
			 * Declare an instance of the DAC with default I2C parameters of 100kHz, ACK-on, 50% duty, 7-bit
			 * and default I2S parameters of 44kHz, master, phillips, 16-bit, mclk-on, cpol-low
			 * Leave the master polling feature bus timeout at 5 seconds.
			 */
			MyDac::Parameters params;
			params.resetPin=pd[4];
			_dac=new MyDac(params);
			// set ourselves up to observe the interrupts
			_dac->I2S3InterruptFeature::insertObserver(*this);
			// reset the device
			_dac->reset();
			// send the I2C initialisation sequence
			if(!_dac->initialise())
				error(3);
			// check the device ID to ensure we've configured I2C correctly
			verifyId();
			// headphones on - default volume level of 200 (out of 255)
			_dac->headphonesOn();
			// set up the data pointer and enable interrupts
			_lastAudioSample=AUDIO_SAMPLE+AUDIO_FILE_SIZE-1;
			_currentAudioPointer=AUDIO_SAMPLE+AUDIO_HEADER_SIZE;
			_dac->I2S3InterruptFeature::enableInterrupts(SPI_I2S_IT_TXE);
			// finished - interrupts are now playing the wave
			for(;;) {
			}
		}
		/*
     * Observer callback function. This is called when the TXE interrupt that we've
     * enabled is fired.
     */
    virtual void onNotify(Observable&,ObservableEvent::E event,void *) {
      if(event==ObservableEvent::SPI_ReadyToTransmit) {
      	// send the next half-word
      	_dac->send(_currentAudioPointer,1);
      	// advance to the next position
      	if(_currentAudioPointer==_lastAudioSample)
      		_currentAudioPointer=AUDIO_SAMPLE+AUDIO_HEADER_SIZE;
      	else
      		_currentAudioPointer++;
      }
    }
		/*
		 * Read and verify the device id
		 */
		void verifyId() {
			uint8_t id;
			// read the ID byte
			if(!_dac->readByte(MyDac::ID,id))
				error(1);
			// check it: the chip id is 11100xxx
			if((id & 0xf8)!=0xe0)
				error(2);
		}
		/*
		 * Handle an error by flashing the LED on PD13 repeatedly
		 */
		void error(uint8_t code) {
			GpioD<DefaultDigitalOutputFeature<13> > pd;
			for(;;) {
				for(uint8_t i=0;i<code;i++) {
					pd[13].set();
					MillisecondTimer::delay(250);
					pd[13].reset();
					MillisecondTimer::delay(250);
				}
				MillisecondTimer::delay(3000);
			}
		}
};
/*
 * Main entry point
 */
int main() {
	// timing is required
	MillisecondTimer::initialise();
	CS43L22Test test;
	test.run();
	// not reached
	return 0;
}
 
ili9325
Click here to hide the full ili9325 code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/display/tft.h"
#include "config/dma.h"
extern uint32_t BulbPixelsSize,BulbPixels;
extern uint32_t AudioPixelsSize,AudioPixels;
extern uint32_t FlagPixelsSize,FlagPixels;
extern uint32_t DocPixelsSize,DocPixels;
extern uint32_t GlobePixelsSize,GlobePixels;
extern uint32_t JpegTest0Pixels,JpegTest0PixelsSize;
using namespace stm32plus;
using namespace stm32plus::display;
/**
 * ILI9325 LCD test, show a looping graphics demo
 *
 * It's a 16-bit device and we control it in this demo
 * using the FSMC peripheral on bank 1. The wiring that
 * you need to do is as follows:
 *
 * PE1  => RESET
 * PD11 => RS (D/CX)
 * PD7  => CS
 * PD4  => RD
 * PD5  => WR
 * PD14 => D0    PE11 => D8
 * PD15 => D1    PE12 => D9
 * PD0  => D2    PE13 => D10
 * PD1  => D3    PE14 => D11
 * PE7  => D4    PE15 => D12
 * PE8  => D5    PD8  => D13
 * PE9  => D6    PD9  => D14
 * PD10 => D7    PD10 => D15
 * PD13 => Backlight PWM (if variable backlight)
 *
 * The code works without structural change on both the
 * F1 and F4. You will most likely have to change the
 * timing  configuration to suit your panel and FSMC
 * bus speed.
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103VET6
 *   STM32F407VGT6
 */
class ILI9325Test {
	protected:
		typedef Fsmc16BitAccessMode<FsmcBank1NorSram1> LcdAccessMode;
		typedef ILI9325_Portrait_262K<LcdAccessMode> LcdPanel;
		LcdAccessMode *_accessMode;
		LcdPanel *_gl;
		Font *_font;
	public:
		void run() {
			// reset is on PE1 and RS (D/CX) is on PD11
			GpioE<DefaultDigitalOutputFeature<1> > pe;
			GpioD<DefaultAlternateFunctionFeature<GPIO_AF_FSMC,11> > pd;
			// set up the FSMC timing. these numbers (particularly the data setup time) are dependent on
			// both the FSMC bus speed and the panel timing parameters.
			Fsmc8080LcdTiming fsmcTiming(0,2);
			// set up the FSMC with RS=A16 (PD11)
			_accessMode=new LcdAccessMode(fsmcTiming,16,pe[1]);
			_gl=new LcdPanel(*_accessMode);
			// apply gamma settings
			ILI9325Gamma gamma(0x0006,0x0101,0x0003,0x0106,0x0b02,0x0302,0x0707,0x0007,0x0600,0x020b);
			_gl->applyGamma(gamma);
			// clear to black while the lights are out
			_gl->setBackground(0);
			_gl->clearScreen();
			// create the backlight on timer4, channel2 (PD13)
			DefaultBacklight backlight;
			// fade up to 100% in 4ms steps
			backlight.fadeTo(100,4);
			// create a font
			_font=new Font_VOLTER__28GOLDFISH_299;
			*_gl << *_font;
			for(;;) {
				jpegTest();
				lzgTest();
				basicColoursTest();
				textTest();
				scrollTest();
				ellipseTest();
				gradientTest();
				rectTest();
				lineTest();
				clearTest();
				sleepTest();
			}
		}
		void sleepTest() {
			prompt("Sleep test");
			// go to sleep
			*_gl << Point::Origin << "Sleeping now...";
			MillisecondTimer::delay(1000);
			_gl->sleep();
			MillisecondTimer::delay(3000);
			// wake up
			_gl->wake();
			_gl->clearScreen();
			*_gl << Point::Origin << "Woken up again...";
			MillisecondTimer::delay(3000);
		}
		void jpegTest() {
			if(_gl->getHeight()==320 && _gl->getWidth()==240) {
				prompt("JPEG bitmap test");
				LinearBufferInputOutputStream compressedData((uint8_t *)&JpegTest0Pixels,(uint32_t)&JpegTest0PixelsSize);
				_gl->drawJpeg(Rectangle(0,0,240,320),compressedData);
				MillisecondTimer::delay(3000);
			}
		}
		void lzgTest() {
			prompt("LZG bitmap test");
			// declare a DMA instance with a copy-to-fsmc feature
			// the syntax is slightly different between the F1 and F4.
#if defined(STM32PLUS_F1)
			Dma1Channel6<DmaFsmcLcdMemoryCopyFeature<LcdAccessMode> > dma;
#elif defined(STM32PLUS_F4)
			Dma2Channel1Stream2<DmaFsmcLcdMemoryCopyFeature<LcdAccessMode> > dma;
#endif
			drawCompressedBitmap((uint8_t *)&BulbPixels,(uint32_t)&BulbPixelsSize,89,148,true,dma);
			drawCompressedBitmap((uint8_t *)&AudioPixels,(uint32_t)&AudioPixelsSize,150,161,false,dma);
			drawCompressedBitmap((uint8_t *)&FlagPixels,(uint32_t)&FlagPixelsSize,144,220,true,dma);
			drawCompressedBitmap((uint8_t *)&DocPixels,(uint32_t)&DocPixelsSize,200,240,false,dma);
			drawCompressedBitmap((uint8_t *)&GlobePixels,(uint32_t)&GlobePixelsSize,193,219,true,dma);
		}
		void drawCompressedBitmap(uint8_t *pixels,uint32_t size,uint16_t width,uint16_t height,bool useDma,DmaFsmcLcdMemoryCopyFeature<LcdAccessMode>& dma) {
			_gl->setBackground(ColourNames::WHITE);
			_gl->clearScreen();
			LinearBufferInputOutputStream compressedData(pixels,size);
			LzgDecompressionStream decompressor(compressedData,size);
			if(useDma) {
				_gl->drawBitmap(
						Rectangle(((_gl->getXmax()+1)-width)/2,
								((_gl->getYmax()+1)-height)/2,
								width,height),
								decompressor,
								dma);
			}
			else {
				_gl->drawBitmap(
						Rectangle(((_gl->getXmax()+1)-width)/2,
								((_gl->getYmax()+1)-height)/2,
								width,height),
								decompressor);
			}
			MillisecondTimer::delay(3000);
		}
		void textTest() {
			int i;
			const char *str="The quick brown fox";
			Size size;
			Point p;
			uint32_t before,elapsed;
			prompt("Stream operators test");
			*_gl << Point::Origin << "Let's see PI:";
			for(i=0;i<=7;i++)
				*_gl << Point(0,(1+i)*_font->getHeight()) << DoublePrecision(3.1415926535,i);
			MillisecondTimer::delay(5000);
			prompt("Opaque text test");
			size=_gl->measureString(*_font,str);
			before=MillisecondTimer::millis();
			for(i=0;i<3000;i++) {
				p.X=rand() % (_gl->getXmax()-size.Width);
				p.Y=rand() % (_gl->getYmax()-size.Height);
				_gl->setForeground(rand());
				_gl->writeString(p,*_font,str);
			}
			elapsed=MillisecondTimer::millis()-before;
			_gl->clearScreen();
			_gl->setForeground(ColourNames::WHITE);
			*_gl << Point::Origin << "Elapsed: " << (int32_t)elapsed << "ms";
			MillisecondTimer::delay(3000);
		}
		void scrollTest() {
			int32_t i,j,numRows;
			Point p;
			prompt("Hardware scrolling test");
			_gl->setForeground(0xffffff);
			_gl->setBackground(0);
			_gl->clearScreen();
			numRows=((_gl->getYmax()+1)/_font->getHeight())/3;
			p.X=0;
			for(i=0;i<numRows;i++) {
				p.Y=(numRows+i)*_font->getHeight();
				*_gl << p << "Test row " << i;
			}
			for(j=0;j<15;j++) {
				numRows=(_gl->getYmax()+1)/4;
				for(i=0;i<numRows;i++) {
					_gl->setScrollPosition(i);
					MillisecondTimer::delay(5);
				}
				for(i=0;i<numRows;i++) {
					_gl->setScrollPosition(numRows-i);
					MillisecondTimer::delay(5);
				}
			}
			_gl->setScrollPosition(0);
		}
		void clearTest() {
			int i;
			uint32_t start;
			prompt("Clear screen test");
			for(i=0;i<200;i++) {
				_gl->setBackground(rand());
				start=MillisecondTimer::millis();
				_gl->clearScreen();
				stopTimer(" to clear",MillisecondTimer::millis()-start);
			}
		}
		void basicColoursTest() {
			uint16_t i;
			static const uint32_t colours[7]={
			  ColourNames::RED,
			  ColourNames::GREEN,
			  ColourNames::BLUE,
			  ColourNames::CYAN,
			  ColourNames::MAGENTA,
			  ColourNames::YELLOW,
			  ColourNames::BLACK,
			};
			prompt("Basic colours test");
			for(i=0;i<sizeof(colours)/sizeof(colours[0]);i++) {
				_gl->setBackground(colours[i]);
				_gl->clearScreen();
				MillisecondTimer::delay(500);
			}
		}
		void lineTest() {
			Point p1,p2;
			int i;
			prompt("Line test");
			for(i=0;i<5000;i++) {
				p1.X=rand() % _gl->getXmax();
				p1.Y=rand() % _gl->getYmax();
				p2.X=rand() % _gl->getXmax();
				p2.Y=rand() % _gl->getYmax();
				_gl->setForeground(rand());
				_gl->drawLine(p1,p2);
			}
		}
		void rectTest() {
			int i;
			Rectangle rc;
			prompt("Rectangle test");
			for(i=0;i<1500;i++) {
				rc.X=(rand() % _gl->getXmax()/2);
				rc.Y=(rand() % _gl->getXmax()/2);
				rc.Width=rand() % (_gl->getXmax()-rc.X);
				rc.Height=rand() % (_gl->getYmax()-rc.Y);
				_gl->setForeground(rand());
				_gl->fillRectangle(rc);
			}
			_gl->clearScreen();
			for(i=0;i<10000;i++) {
				rc.X=(rand() % _gl->getXmax()/2);
				rc.Y=(rand() % _gl->getXmax()/2);
				rc.Width=rand() % (_gl->getXmax()-rc.X);
				rc.Height=rand() % (_gl->getYmax()-rc.Y);
				_gl->setForeground(rand());
				_gl->drawRectangle(rc);
				if(i % 1000 ==0)
					_gl->clearScreen();
			}
		}
		void ellipseTest() {
			int16_t i;
			Point p;
			Size s;
			prompt("Ellipse test");
			_gl->setBackground(0);
			for(i=0;i<1000;i++) {
				p.X=_gl->getXmax()/4+(rand() % (_gl->getXmax()/2));
				p.Y=_gl->getYmax()/4+(rand() % (_gl->getYmax()/2));
				if(p.X<_gl->getXmax()/2)
					s.Width=rand() % p.X;
				else
					s.Width=rand() % (_gl->getXmax()-p.X);
				if(p.Y<_gl->getYmax()/2)
					s.Height=rand() % p.Y;
				else
					s.Height=rand() % (_gl->getYmax()-p.Y);
				_gl->setForeground(rand());
				_gl->fillEllipse(p,s);
			}
			_gl->clearScreen();
			for(i=0;i<1500;i++) {
				p.X=_gl->getXmax()/4+(rand() % (_gl->getXmax()/2));
				p.Y=_gl->getYmax()/4+(rand() % (_gl->getYmax()/2));
				if(p.X<_gl->getXmax()/2)
					s.Width=rand() % p.X;
				else
					s.Width=rand() % (_gl->getXmax()-p.X);
				if(p.Y<_gl->getYmax()/2)
					s.Height=rand() % p.Y;
				else
					s.Height=rand() % (_gl->getYmax()-p.Y);
				if(s.Height>0 && s.Width>0 && p.X+s.Width<_gl->getXmax() && p.Y+s.Height<_gl->getYmax()) {
					_gl->setForeground(rand());
					_gl->drawEllipse(p,s);
				}
				if(i % 500==0)
					_gl->clearScreen();
			}
		}
		void doGradientFills(Direction dir) {
			Rectangle rc;
			uint16_t i;
			static uint32_t colours[7]={
				ColourNames::RED,
				ColourNames::GREEN,
				ColourNames::BLUE,
				ColourNames::CYAN,
				ColourNames::MAGENTA,
				ColourNames::YELLOW,
				ColourNames::WHITE,
			};
			rc.Width=_gl->getXmax()+1;
			rc.Height=(_gl->getYmax()+1)/2;
			for(i=0;i<sizeof(colours)/sizeof(colours[0]);i++) {
				rc.X=0;
				rc.Y=0;
				_gl->gradientFillRectangle(rc,dir,ColourNames::BLACK,colours[i]);
				rc.Y=rc.Height;
				_gl->gradientFillRectangle(rc,dir,colours[i],ColourNames::BLACK);
				MillisecondTimer::delay(1000);
			}
		}
		void gradientTest() {
			prompt("Gradient test");
			doGradientFills(HORIZONTAL);
			doGradientFills(VERTICAL);
		}
		void prompt(const char *prompt) {
			_gl->setBackground(ColourNames::BLACK);
			_gl->clearScreen();
			_gl->setForeground(ColourNames::WHITE);
			*_gl << Point(0,0) << prompt;
			MillisecondTimer::delay(2000);
			_gl->clearScreen();
		}
		void stopTimer(const char *prompt,uint32_t elapsed) {
			_gl->setForeground(0xffffff);
			*_gl << Point(0,0) << (int32_t)elapsed << "ms " << prompt;
		}
};
/*
 * Main entry point
 */
int main() {
	// set up SysTick at 1ms resolution
	MillisecondTimer::initialise();
	ILI9325Test test;
	test.run();
	// not reached
	return 0;
}
 
ili9327
Click here to hide the full ili9327 code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/display/tft.h"
extern uint32_t BulbPixelsSize,BulbPixels;
extern uint32_t AudioPixelsSize,AudioPixels;
extern uint32_t FlagPixelsSize,FlagPixels;
extern uint32_t DocPixelsSize,DocPixels;
extern uint32_t GlobePixelsSize,GlobePixels;
extern uint32_t JpegTest0Pixels,JpegTest0PixelsSize;
using namespace stm32plus;
using namespace stm32plus::display;
/**
 * ILI9327 LCD test, show a looping graphics demo
 *
 * It's a 16-bit device and we control it in this demo
 * using the FSMC peripheral on bank 1. The wiring
 * that you need to do is as follows:
 *
 * PE1  => RESET
 * PD11 => RS (D/CX)
 * PD7  => CS
 * PD4  => RD
 * PD5  => WR
 * PD14 => D0    PE11 => D8
 * PD15 => D1    PE12 => D9
 * PD0  => D2    PE13 => D10
 * PD1  => D3    PE14 => D11
 * PE7  => D4    PE15 => D12
 * PE8  => D5    PD8  => D13
 * PE9  => D6    PD9  => D14
 * PD10 => D7    PD10 => D15
 * PD13 => Backlight PWM (if variable backlight)
 *
 * The code works without structural change on both
 * the F1 and F4. You will most likely have to change
 * the timing configuration to suit your panel and FSMC
 * bus speed. I include working timings for the F1 and
 * F4 for the ILI9327 development board that I own.
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103VET6
 *   STM32F407VGT6
 */
class ILI9327Test {
	protected:
		typedef Fsmc16BitAccessMode<FsmcBank1NorSram1> LcdAccessMode;
		typedef ILI9327_400x240_Portrait_262K<LcdAccessMode> LcdPanel;
		LcdAccessMode *_accessMode;
		LcdPanel *_gl;
		Font *_font;
	public:
		void run() {
			// reset is on PE1 and RS (D/CX) is on PD11
			GpioE<DefaultDigitalOutputFeature<1> > pe;
			GpioD<DefaultAlternateFunctionFeature<GPIO_AF_FSMC,11> > pd;
			// set up the FSMC with RS=A16 (PD11)
#if defined(STM32PLUS_F1)
			Fsmc8080LcdTiming fsmcTiming(0,2);
#elif defined(STM32PLUS_F4)
			Fsmc8080LcdTiming fsmcTiming(4,10);
#endif
			_accessMode=new LcdAccessMode(fsmcTiming,16,pe[1]);
			// declare a panel
			_gl=new LcdPanel(*_accessMode);
			// apply gamma settings
			ILI9327Gamma gamma(0,0x10,0,0,3,0,0,1,7,5,5,0x25,0,0,0);
			_gl->applyGamma(gamma);
			// clear to black while the lights are out
			_gl->setBackground(0);
			_gl->clearScreen();
			// create the backlight on timer4, channel2 (PD13)
			DefaultBacklight backlight;
			// fade up to 100% in 4ms steps
			backlight.fadeTo(100,4);
			// create a font
			_font=new Font_VOLTER__28GOLDFISH_299;
			*_gl << *_font;
			for(;;) {
				rectTest();
				jpegTest();
				lzgTest();
				basicColoursTest();
				textTest();
				scrollTest();
				ellipseTest();
				gradientTest();
				lineTest();
				clearTest();
				sleepTest();
			}
		}
		void sleepTest() {
			prompt("Sleep test");
			// go to sleep
			*_gl << Point::Origin << "Sleeping now...";
			MillisecondTimer::delay(1000);
			_gl->sleep();
			MillisecondTimer::delay(3000);
			// wake up
			_gl->wake();
			_gl->clearScreen();
			*_gl << Point::Origin << "Woken up again...";
			MillisecondTimer::delay(3000);
		}
		void jpegTest() {
			// only draw in portrait mode and if it can fit on screen
			if(_gl->getHeight()>_gl->getWidth() && _gl->getHeight()>=320 && _gl->getWidth()>=240) {
				prompt("JPEG bitmap test");
				// draw it centered
				LinearBufferInputOutputStream compressedData((uint8_t *)&JpegTest0Pixels,(uint32_t)&JpegTest0PixelsSize);
				_gl->drawJpeg(Rectangle((_gl->getWidth()-240)/2,(_gl->getHeight()-320)/2,240,320),compressedData);
				MillisecondTimer::delay(3000);
			}
		}
		void lzgTest() {
			prompt("LZG bitmap test");
			// declare a DMA instance with a copy-to-fsmc feature
#if defined(STM32PLUS_F1)
			Dma1Channel6<DmaFsmcLcdMemoryCopyFeature<LcdAccessMode> > dma;
#elif defined(STM32PLUS_F4)
			Dma2Channel1Stream2<DmaFsmcLcdMemoryCopyFeature<LcdAccessMode> > dma;
#endif
			drawCompressedBitmap((uint8_t *)&BulbPixels,(uint32_t)&BulbPixelsSize,89,148,true,dma);
			drawCompressedBitmap((uint8_t *)&AudioPixels,(uint32_t)&AudioPixelsSize,150,161,false,dma);
			drawCompressedBitmap((uint8_t *)&FlagPixels,(uint32_t)&FlagPixelsSize,144,220,true,dma);
			drawCompressedBitmap((uint8_t *)&DocPixels,(uint32_t)&DocPixelsSize,200,240,false,dma);
			drawCompressedBitmap((uint8_t *)&GlobePixels,(uint32_t)&GlobePixelsSize,193,219,true,dma);
		}
		void drawCompressedBitmap(uint8_t *pixels,uint32_t size,uint16_t width,uint16_t height,bool useDma,DmaFsmcLcdMemoryCopyFeature<LcdAccessMode>& dma) {
			_gl->setBackground(ColourNames::WHITE);
			_gl->clearScreen();
			LinearBufferInputOutputStream compressedData(pixels,size);
			LzgDecompressionStream decompressor(compressedData,size);
			if(useDma) {
				_gl->drawBitmap(
						Rectangle(((_gl->getXmax()+1)-width)/2,
								((_gl->getYmax()+1)-height)/2,
								width,height),
								decompressor,
								dma);
			}
			else {
				_gl->drawBitmap(
						Rectangle(((_gl->getXmax()+1)-width)/2,
								((_gl->getYmax()+1)-height)/2,
								width,height),
								decompressor);
			}
			MillisecondTimer::delay(3000);
		}
		void textTest() {
			int i;
			const char *str="The quick brown fox";
			Size size;
			Point p;
			uint32_t before,elapsed;
			prompt("Stream operators test");
			*_gl << Point::Origin << "Let's see PI:";
			for(i=0;i<=7;i++)
				*_gl << Point(0,(1+i)*_font->getHeight()) << DoublePrecision(3.1415926535,i);
			MillisecondTimer::delay(5000);
			prompt("Opaque text test");
			size=_gl->measureString(*_font,str);
			before=MillisecondTimer::millis();
			for(i=0;i<15000;i++) {
				p.X=rand() % (_gl->getXmax()-size.Width);
				p.Y=rand() % (_gl->getYmax()-size.Height);
				_gl->setForeground(rand());
				_gl->writeString(p,*_font,str);
			}
			elapsed=MillisecondTimer::millis()-before;
			_gl->clearScreen();
			_gl->setForeground(ColourNames::WHITE);
			*_gl << Point::Origin << "Elapsed: " << (int32_t)elapsed << "ms";
			MillisecondTimer::delay(3000);
		}
		void scrollTest() {
			int32_t i,j,numRows;
			Point p;
			prompt("Hardware scrolling test");
			_gl->setForeground(0xffffff);
			_gl->setBackground(0);
			_gl->clearScreen();
			numRows=((_gl->getYmax()+1)/_font->getHeight())/3;
			p.X=0;
			for(i=0;i<numRows;i++) {
				p.Y=(numRows+i)*_font->getHeight();
				*_gl << p << "Test row " << i;
			}
			for(j=0;j<15;j++) {
				numRows=(_gl->getYmax()+1)/4;
				for(i=0;i<numRows;i++) {
					_gl->setScrollPosition(i);
					MillisecondTimer::delay(5);
				}
				for(i=0;i<numRows;i++) {
					_gl->setScrollPosition(numRows-i);
					MillisecondTimer::delay(5);
				}
			}
			_gl->setScrollPosition(0);
		}
		void clearTest() {
			int i;
			uint32_t start;
			prompt("Clear screen test");
			for(i=0;i<200;i++) {
				_gl->setBackground(rand());
				start=MillisecondTimer::millis();
				_gl->clearScreen();
				stopTimer(" to clear",MillisecondTimer::millis()-start);
			}
		}
		void basicColoursTest() {
			uint16_t i;
			static const uint32_t colours[7]={
			  ColourNames::RED,
			  ColourNames::GREEN,
			  ColourNames::BLUE,
			  ColourNames::CYAN,
			  ColourNames::MAGENTA,
			  ColourNames::YELLOW,
			  ColourNames::BLACK,
			};
			prompt("Basic colours test");
			for(i=0;i<sizeof(colours)/sizeof(colours[0]);i++) {
				_gl->setBackground(colours[i]);
				_gl->clearScreen();
				MillisecondTimer::delay(500);
			}
		}
		void lineTest() {
			Point p1,p2;
			int i;
			prompt("Line test");
			for(i=0;i<25000;i++) {
				p1.X=rand() % _gl->getXmax();
				p1.Y=rand() % _gl->getYmax();
				p2.X=rand() % _gl->getXmax();
				p2.Y=rand() % _gl->getYmax();
				_gl->setForeground(rand());
				_gl->drawLine(p1,p2);
			}
		}
		void rectTest() {
			int i;
			Rectangle rc;
			prompt("Rectangle test");
			for(i=0;i<8000;i++) {
				rc.X=(rand() % _gl->getXmax()/2);
				rc.Y=(rand() % _gl->getXmax()/2);
				rc.Width=rand() % (_gl->getXmax()-rc.X);
				rc.Height=rand() % (_gl->getYmax()-rc.Y);
				_gl->setForeground(rand());
				_gl->fillRectangle(rc);
			}
			_gl->clearScreen();
			for(i=0;i<80000;i++) {
				rc.X=(rand() % _gl->getXmax()/2);
				rc.Y=(rand() % _gl->getXmax()/2);
				rc.Width=rand() % (_gl->getXmax()-rc.X);
				rc.Height=rand() % (_gl->getYmax()-rc.Y);
				_gl->setForeground(rand());
				_gl->drawRectangle(rc);
				if(i % 1000 ==0)
					_gl->clearScreen();
			}
		}
		void ellipseTest() {
			int16_t i;
			Point p;
			Size s;
			prompt("Ellipse test");
			_gl->setBackground(0);
			for(i=0;i<5000;i++) {
				p.X=_gl->getXmax()/4+(rand() % (_gl->getXmax()/2));
				p.Y=_gl->getYmax()/4+(rand() % (_gl->getYmax()/2));
				if(p.X<_gl->getXmax()/2)
					s.Width=rand() % p.X;
				else
					s.Width=rand() % (_gl->getXmax()-p.X);
				if(p.Y<_gl->getYmax()/2)
					s.Height=rand() % p.Y;
				else
					s.Height=rand() % (_gl->getYmax()-p.Y);
				_gl->setForeground(rand());
				_gl->fillEllipse(p,s);
			}
			_gl->clearScreen();
			for(i=0;i<8000;i++) {
				p.X=_gl->getXmax()/4+(rand() % (_gl->getXmax()/2));
				p.Y=_gl->getYmax()/4+(rand() % (_gl->getYmax()/2));
				if(p.X<_gl->getXmax()/2)
					s.Width=rand() % p.X;
				else
					s.Width=rand() % (_gl->getXmax()-p.X);
				if(p.Y<_gl->getYmax()/2)
					s.Height=rand() % p.Y;
				else
					s.Height=rand() % (_gl->getYmax()-p.Y);
				if(s.Height>0 && s.Width>0 && p.X+s.Width<_gl->getXmax() && p.Y+s.Height<_gl->getYmax()) {
					_gl->setForeground(rand());
					_gl->drawEllipse(p,s);
				}
				if(i % 500==0)
					_gl->clearScreen();
			}
		}
		void doGradientFills(Direction dir) {
			Rectangle rc;
			uint16_t i;
			static uint32_t colours[7]={
				ColourNames::RED,
				ColourNames::GREEN,
				ColourNames::BLUE,
				ColourNames::CYAN,
				ColourNames::MAGENTA,
				ColourNames::YELLOW,
				ColourNames::WHITE,
			};
			rc.Width=_gl->getXmax()+1;
			rc.Height=(_gl->getYmax()+1)/2;
			for(i=0;i<sizeof(colours)/sizeof(colours[0]);i++) {
				rc.X=0;
				rc.Y=0;
				_gl->gradientFillRectangle(rc,dir,ColourNames::BLACK,colours[i]);
				rc.Y=rc.Height;
				_gl->gradientFillRectangle(rc,dir,colours[i],ColourNames::BLACK);
				MillisecondTimer::delay(1000);
			}
		}
		void gradientTest() {
			prompt("Gradient test");
			doGradientFills(HORIZONTAL);
			doGradientFills(VERTICAL);
		}
		void prompt(const char *prompt) {
			_gl->setBackground(ColourNames::BLACK);
			_gl->clearScreen();
			_gl->setForeground(ColourNames::WHITE);
			*_gl << Point(0,0) << prompt;
			MillisecondTimer::delay(2000);
			_gl->clearScreen();
		}
		void stopTimer(const char *prompt,uint32_t elapsed) {
			_gl->setForeground(0xffffff);
			*_gl << Point(0,0) << (int32_t)elapsed << "ms " << prompt;
		}
};
/*
 * Main entry point
 */
int main() {
	// set up SysTick at 1ms resolution
	MillisecondTimer::initialise();
	ILI9327Test test;
	test.run();
	// not reached
	return 0;
}
 
ili9481
Click here to hide the full ili9481 code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/display/tft.h"
extern uint32_t BulbPixelsSize,BulbPixels;
extern uint32_t AudioPixelsSize,AudioPixels;
extern uint32_t FlagPixelsSize,FlagPixels;
extern uint32_t DocPixelsSize,DocPixels;
extern uint32_t GlobePixelsSize,GlobePixels;
extern uint32_t JpegTest0Pixels,JpegTest0PixelsSize;
using namespace stm32plus;
using namespace stm32plus::display;
/**
 * ILI9481 HVGA LCD test, show a looping graphics demo
 *
 * It's a 16-bit device and we control it in this demo
 * using the FSMC peripheral on bank 1. The wiring that
 * you need to do is as follows:
 *
 * PE1  => RESET
 * PD11 => RS (D/CX)
 * PD7  => CS
 * PD4  => RD
 * PD5  => WR
 * PD14 => D0    PE11 => D8
 * PD15 => D1    PE12 => D9
 * PD0  => D2    PE13 => D10
 * PD1  => D3    PE14 => D11
 * PE7  => D4    PE15 => D12
 * PE8  => D5    PD8  => D13
 * PE9  => D6    PD9  => D14
 * PD10 => D7    PD10 => D15
 * PD13 => Backlight PWM (if variable backlight required)
 *
 * The code works without structural change on both the
 * F1 and F4. You will most likely have to change the
 * timing configuration to suit your panel and FSMC bus
 * speed. I include working timings for the F1 and F4
 * for the ILI9481 panel board that I own.
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103VET6
 *   STM32F407VGT6
 */
class ILI9481Test {
	protected:
		typedef Fsmc16BitAccessMode<FsmcBank1NorSram1> LcdAccessMode;
		typedef ILI9481_Landscape_64K<LcdAccessMode> LcdPanel;
		LcdAccessMode *_accessMode;
		LcdPanel *_gl;
		Font *_font;
	public:
		void run() {
			// reset is on PE1 and RS (D/CX) is on PD11
			GpioE<DefaultDigitalOutputFeature<1> > pe;
			GpioD<DefaultAlternateFunctionFeature<GPIO_AF_FSMC,11> > pd;
			// set up the FSMC with RS=A16 (PD11). The 60Mhz FSMC bus on the F4 needs
			// slower timings.
#if defined(STM32PLUS_F1)
			Fsmc8080LcdTiming fsmcTiming(0,2);
#else
			Fsmc8080LcdTiming fsmcTiming(2,10);
#endif
			_accessMode=new LcdAccessMode(fsmcTiming,16,pe[1]);
			// declare a panel
			_gl=new LcdPanel(*_accessMode);
			// apply gamma settings
			ILI9481Gamma gamma(0,0xf3,0,0xbc,0x50,0x1f,0,7,0x7f,0x7,0xf,0);
			_gl->applyGamma(gamma);
			// clear to black while the lights are out
			_gl->setBackground(0);
			_gl->clearScreen();
			// create the backlight on timer4, channel2 (PD13)
			DefaultBacklight backlight;
			// fade up to 100% in 4ms steps
			backlight.fadeTo(100,4);
			// create a font
			_font=new Font_VOLTER__28GOLDFISH_299;
			*_gl << *_font;
			for(;;) {
				jpegTest();
				lzgTest();
				basicColoursTest();
				textTest();
				scrollTest();
				ellipseTest();
				gradientTest();
				rectTest();
				lineTest();
				clearTest();
				sleepTest();
			}
		}
		void sleepTest() {
			prompt("Sleep test");
			// go to sleep
			*_gl << Point::Origin << "Sleeping now...";
			MillisecondTimer::delay(1000);
			_gl->sleep();
			MillisecondTimer::delay(3000);
			// wake up
			_gl->wake();
			_gl->clearScreen();
			*_gl << Point::Origin << "Woken up again...";
			MillisecondTimer::delay(3000);
		}
		void jpegTest() {
			prompt("JPEG bitmap test");
			// draw it centered
			LinearBufferInputOutputStream compressedData((uint8_t *)&JpegTest0Pixels,(uint32_t)&JpegTest0PixelsSize);
			_gl->drawJpeg(Rectangle((_gl->getWidth()-240)/2,(_gl->getHeight()-320)/2,240,320),compressedData);
			MillisecondTimer::delay(3000);
		}
		void lzgTest() {
			prompt("LZG bitmap test");
			// declare a DMA instance with a copy-to-fsmc feature
#if defined(STM32PLUS_F1)
			Dma1Channel6<DmaFsmcLcdMemoryCopyFeature<LcdAccessMode> > dma;
#elif defined(STM32PLUS_F4)
			Dma2Channel1Stream2<DmaFsmcLcdMemoryCopyFeature<LcdAccessMode> > dma;
#endif
			drawCompressedBitmap((uint8_t *)&BulbPixels,(uint32_t)&BulbPixelsSize,89,148,true,dma);
			drawCompressedBitmap((uint8_t *)&AudioPixels,(uint32_t)&AudioPixelsSize,150,161,false,dma);
			drawCompressedBitmap((uint8_t *)&FlagPixels,(uint32_t)&FlagPixelsSize,144,220,true,dma);
			drawCompressedBitmap((uint8_t *)&DocPixels,(uint32_t)&DocPixelsSize,200,240,false,dma);
			drawCompressedBitmap((uint8_t *)&GlobePixels,(uint32_t)&GlobePixelsSize,193,219,true,dma);
		}
		void drawCompressedBitmap(uint8_t *pixels,uint32_t size,uint16_t width,uint16_t height,bool useDma,DmaFsmcLcdMemoryCopyFeature<LcdAccessMode>& dma) {
			_gl->setBackground(ColourNames::WHITE);
			_gl->clearScreen();
			LinearBufferInputOutputStream compressedData(pixels,size);
			LzgDecompressionStream decompressor(compressedData,size);
			if(useDma) {
				_gl->drawBitmap(
						Rectangle(((_gl->getXmax()+1)-width)/2,
								((_gl->getYmax()+1)-height)/2,
								width,height),
								decompressor,
								dma);
			}
			else {
				_gl->drawBitmap(
						Rectangle(((_gl->getXmax()+1)-width)/2,
								((_gl->getYmax()+1)-height)/2,
								width,height),
								decompressor);
			}
			MillisecondTimer::delay(3000);
		}
		void textTest() {
			int i;
			const char *str="The quick brown fox";
			Size size;
			Point p;
			uint32_t before,elapsed;
			prompt("Stream operators test");
			*_gl << Point::Origin << "Let's see PI:";
			for(i=0;i<=7;i++)
				*_gl << Point(0,(1+i)*_font->getHeight()) << DoublePrecision(3.1415926535,i);
			MillisecondTimer::delay(5000);
			prompt("Opaque text test");
			size=_gl->measureString(*_font,str);
			before=MillisecondTimer::millis();
			for(i=0;i<15000;i++) {
				p.X=rand() % (_gl->getXmax()-size.Width);
				p.Y=rand() % (_gl->getYmax()-size.Height);
				_gl->setForeground(rand());
				_gl->writeString(p,*_font,str);
			}
			elapsed=MillisecondTimer::millis()-before;
			_gl->clearScreen();
			_gl->setForeground(ColourNames::WHITE);
			*_gl << Point::Origin << "Elapsed: " << (int32_t)elapsed << "ms";
			MillisecondTimer::delay(3000);
		}
		void scrollTest() {
			int32_t i,j,numRows;
			Point p;
			prompt("Hardware scrolling test");
			_gl->setForeground(0xffffff);
			_gl->setBackground(0);
			_gl->clearScreen();
			numRows=((_gl->getYmax()+1)/_font->getHeight())/3;
			p.X=0;
			for(i=0;i<numRows;i++) {
				p.Y=(numRows+i)*_font->getHeight();
				*_gl << p << "Test row " << i;
			}
			for(j=0;j<15;j++) {
				numRows=(_gl->getYmax()+1)/4;
				for(i=0;i<numRows;i++) {
					_gl->setScrollPosition(i);
					MillisecondTimer::delay(5);
				}
				for(i=0;i<numRows;i++) {
					_gl->setScrollPosition(numRows-i);
					MillisecondTimer::delay(5);
				}
			}
			_gl->setScrollPosition(0);
		}
		void clearTest() {
			int i;
			uint32_t start;
			prompt("Clear screen test");
			for(i=0;i<200;i++) {
				_gl->setBackground(rand());
				start=MillisecondTimer::millis();
				_gl->clearScreen();
				stopTimer(" to clear",MillisecondTimer::millis()-start);
			}
		}
		void basicColoursTest() {
			uint16_t i;
			static const uint32_t colours[7]={
			  ColourNames::RED,
			  ColourNames::GREEN,
			  ColourNames::BLUE,
			  ColourNames::CYAN,
			  ColourNames::MAGENTA,
			  ColourNames::YELLOW,
			  ColourNames::BLACK,
			};
			prompt("Basic colours test");
			for(i=0;i<sizeof(colours)/sizeof(colours[0]);i++) {
				_gl->setBackground(colours[i]);
				_gl->clearScreen();
				MillisecondTimer::delay(500);
			}
		}
		void lineTest() {
			Point p1,p2;
			int i;
			prompt("Line test");
			for(i=0;i<15000;i++) {
				p1.X=rand() % _gl->getXmax();
				p1.Y=rand() % _gl->getYmax();
				p2.X=rand() % _gl->getXmax();
				p2.Y=rand() % _gl->getYmax();
				_gl->setForeground(rand());
				_gl->drawLine(p1,p2);
			}
		}
		void rectTest() {
			int i;
			Rectangle rc;
			prompt("Rectangle test");
			for(i=0;i<5000;i++) {
				rc.X=(rand() % _gl->getXmax()/2);
				rc.Y=(rand() % _gl->getXmax()/2);
				rc.Width=rand() % (_gl->getXmax()-rc.X);
				rc.Height=rand() % (_gl->getYmax()-rc.Y);
				_gl->setForeground(rand());
				_gl->fillRectangle(rc);
			}
			_gl->clearScreen();
			for(i=0;i<50000;i++) {
				rc.X=(rand() % _gl->getXmax()/2);
				rc.Y=(rand() % _gl->getXmax()/2);
				rc.Width=rand() % (_gl->getXmax()-rc.X);
				rc.Height=rand() % (_gl->getYmax()-rc.Y);
				_gl->setForeground(rand());
				_gl->drawRectangle(rc);
				if(i % 1000 ==0)
					_gl->clearScreen();
			}
		}
		void ellipseTest() {
			int16_t i;
			Point p;
			Size s;
			prompt("Ellipse test");
			_gl->setBackground(0);
			for(i=0;i<5000;i++) {
				p.X=_gl->getXmax()/4+(rand() % (_gl->getXmax()/2));
				p.Y=_gl->getYmax()/4+(rand() % (_gl->getYmax()/2));
				if(p.X<_gl->getXmax()/2)
					s.Width=rand() % p.X;
				else
					s.Width=rand() % (_gl->getXmax()-p.X);
				if(p.Y<_gl->getYmax()/2)
					s.Height=rand() % p.Y;
				else
					s.Height=rand() % (_gl->getYmax()-p.Y);
				_gl->setForeground(rand());
				_gl->fillEllipse(p,s);
			}
			_gl->clearScreen();
			for(i=0;i<5000;i++) {
				p.X=_gl->getXmax()/4+(rand() % (_gl->getXmax()/2));
				p.Y=_gl->getYmax()/4+(rand() % (_gl->getYmax()/2));
				if(p.X<_gl->getXmax()/2)
					s.Width=rand() % p.X;
				else
					s.Width=rand() % (_gl->getXmax()-p.X);
				if(p.Y<_gl->getYmax()/2)
					s.Height=rand() % p.Y;
				else
					s.Height=rand() % (_gl->getYmax()-p.Y);
				if(s.Height>0 && s.Width>0 && p.X+s.Width<_gl->getXmax() && p.Y+s.Height<_gl->getYmax()) {
					_gl->setForeground(rand());
					_gl->drawEllipse(p,s);
				}
				if(i % 500==0)
					_gl->clearScreen();
			}
		}
		void doGradientFills(Direction dir) {
			Rectangle rc;
			uint16_t i;
			static uint32_t colours[7]={
				ColourNames::RED,
				ColourNames::GREEN,
				ColourNames::BLUE,
				ColourNames::CYAN,
				ColourNames::MAGENTA,
				ColourNames::YELLOW,
				ColourNames::WHITE,
			};
			rc.Width=_gl->getXmax()+1;
			rc.Height=(_gl->getYmax()+1)/2;
			for(i=0;i<sizeof(colours)/sizeof(colours[0]);i++) {
				rc.X=0;
				rc.Y=0;
				_gl->gradientFillRectangle(rc,dir,ColourNames::BLACK,colours[i]);
				rc.Y=rc.Height;
				_gl->gradientFillRectangle(rc,dir,colours[i],ColourNames::BLACK);
				MillisecondTimer::delay(1000);
			}
		}
		void gradientTest() {
			prompt("Gradient test");
			doGradientFills(HORIZONTAL);
			doGradientFills(VERTICAL);
		}
		void prompt(const char *prompt) {
			_gl->setBackground(ColourNames::BLACK);
			_gl->clearScreen();
			_gl->setForeground(ColourNames::WHITE);
			*_gl << Point(0,0) << prompt;
			MillisecondTimer::delay(2000);
			_gl->clearScreen();
		}
		void stopTimer(const char *prompt,uint32_t elapsed) {
			_gl->setForeground(0xffffff);
			*_gl << Point(0,0) << (int32_t)elapsed << "ms " << prompt;
		}
};
/*
 * Main entry point
 */
int main() {
	// set up SysTick at 1ms resolution
	MillisecondTimer::initialise();
	ILI9481Test test;
	test.run();
	// not reached
	return 0;
}
 
lds285
Click here to hide the full lds285 code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/display/tft.h"
extern uint32_t BulbPixelsSize,BulbPixels;
extern uint32_t AudioPixelsSize,AudioPixels;
extern uint32_t FlagPixelsSize,FlagPixels;
extern uint32_t DocPixelsSize,DocPixels;
extern uint32_t GlobePixelsSize,GlobePixels;
extern uint32_t JpegTest0Pixels,JpegTest0PixelsSize;
using namespace stm32plus;
using namespace stm32plus::display;
/**
 * MC2PA8201 LCD test, show a looping graphics demo
 *
 * The MC2PA8201 driver is used by many of the Nokia QVGA
 * cellphone LCDs including the N95 8Gb.
 *
 * It's an 8-bit device and we control it in this demo
 * using the FSMC peripheral on bank 1. The wiring that
 * you need to do is as follows:
 *
 * PE1  => RESET
 * PD11 => RS (D/CX)
 * PD7  => CS
 * PD4  => RD
 * PD5  => WR
 * PD14 => D0
 * PD15 => D1
 * PD0  => D2
 * PD1  => D3
 * PE7  => D4
 * PE8  => D5
 * PE9  => D6
 * PD10 => D7
 * PD13 => Backlight PWM (if variable backlight)
 *
 * There are no special considerations for the F1 versus
 * the F4. The code works on both without any change.
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103VET6
 *   STM32F407VGT6
 */
class LDS285Test {
	protected:
		typedef Fsmc8BitAccessMode<FsmcBank1NorSram1> LcdAccessMode;
		typedef NokiaN95_8GB_Portrait_16M_TypeA<LcdAccessMode> LcdPanel;
		LcdAccessMode *_accessMode;
		LcdPanel *_gl;
		Font *_font;
	public:
		void run() {
			// reset is on PE1 and RS (D/CX) is on PD11
			GpioE<DefaultDigitalOutputFeature<1> > pe;
			GpioD<DefaultAlternateFunctionFeature<GPIO_AF_FSMC,11> > pd;
			// set up the FSMC with RS=A16 (PD11)
			Fsmc8080LcdTiming fsmcTiming(0,2);
			_accessMode=new LcdAccessMode(fsmcTiming,16,pe[1]);
			// declare a panel
			_gl=new LcdPanel(*_accessMode);
			// fade up to 100% in 2ms steps
			_gl->fadeBacklightTo(100,4);
			// clear to black while the lights are out
			_gl->setBackground(0);
			_gl->clearScreen();
			// create a font
			_font=new Font_VOLTER__28GOLDFISH_299;
			*_gl << *_font;
			for(;;) {
				jpegTest();
				lzgTest();
				basicColoursTest();
				textTest();
				scrollTest();
				ellipseTest();
				gradientTest();
				rectTest();
				lineTest();
				clearTest();
				sleepTest();
			}
		}
		void sleepTest() {
			prompt("Sleep test");
			// go to sleep
			*_gl << Point::Origin << "Sleeping now...";
			MillisecondTimer::delay(1000);
			_gl->sleep();
			MillisecondTimer::delay(3000);
			// wake up
			_gl->wake();
			_gl->clearScreen();
			*_gl << Point::Origin << "Woken up again...";
			MillisecondTimer::delay(3000);
		}
		void jpegTest() {
			if(_gl->getHeight()==320 && _gl->getWidth()==240) {
				prompt("JPEG bitmap test");
				LinearBufferInputOutputStream compressedData((uint8_t *)&JpegTest0Pixels,(uint32_t)&JpegTest0PixelsSize);
				_gl->drawJpeg(Rectangle(0,0,240,320),compressedData);
				_gl->setContentAdaptiveImageType(LcdPanel::CONTENT_ADAPTIVE_BRIGHTNESS_TYPE_STILL_IMAGE);
				MillisecondTimer::delay(3000);
				_gl->setContentAdaptiveImageType(LcdPanel::CONTENT_ADAPTIVE_BRIGHTNESS_TYPE_GUI);
			}
		}
		void lzgTest() {
			prompt("LZG bitmap test");
			// declare a DMA instance with a copy-to-fsmc feature
#if defined(STM32PLUS_F1)
			Dma1Channel6<DmaFsmcLcdMemoryCopyFeature<LcdAccessMode> > dma;
#elif defined(STM32PLUS_F4)
			Dma2Channel1Stream2<DmaFsmcLcdMemoryCopyFeature<LcdAccessMode> > dma;
#endif
			drawCompressedBitmap((uint8_t *)&BulbPixels,(uint32_t)&BulbPixelsSize,89,148,true,dma);
			drawCompressedBitmap((uint8_t *)&AudioPixels,(uint32_t)&AudioPixelsSize,150,161,false,dma);
			drawCompressedBitmap((uint8_t *)&FlagPixels,(uint32_t)&FlagPixelsSize,144,220,true,dma);
			drawCompressedBitmap((uint8_t *)&DocPixels,(uint32_t)&DocPixelsSize,200,240,false,dma);
			drawCompressedBitmap((uint8_t *)&GlobePixels,(uint32_t)&GlobePixelsSize,193,219,true,dma);
		}
		void drawCompressedBitmap(uint8_t *pixels,uint32_t size,uint16_t width,uint16_t height,bool useDma,DmaFsmcLcdMemoryCopyFeature<LcdAccessMode>& dma) {
			_gl->setBackground(ColourNames::WHITE);
			_gl->clearScreen();
			LinearBufferInputOutputStream compressedData(pixels,size);
			LzgDecompressionStream decompressor(compressedData,size);
			if(useDma) {
				_gl->drawBitmap(
						Rectangle(((_gl->getXmax()+1)-width)/2,
								((_gl->getYmax()+1)-height)/2,
								width,height),
								decompressor,
								dma);
			}
			else {
				_gl->drawBitmap(
						Rectangle(((_gl->getXmax()+1)-width)/2,
								((_gl->getYmax()+1)-height)/2,
								width,height),
								decompressor);
			}
			MillisecondTimer::delay(3000);
		}
		void textTest() {
			int i;
			const char *str="The quick brown fox";
			Size size;
			Point p;
			uint32_t before,elapsed;
			prompt("Stream operators test");
			*_gl << Point::Origin << "Let's see PI:";
			for(i=0;i<=7;i++)
				*_gl << Point(0,(1+i)*_font->getHeight()) << DoublePrecision(3.1415926535,i);
			MillisecondTimer::delay(5000);
			prompt("Opaque text test");
			size=_gl->measureString(*_font,str);
			before=MillisecondTimer::millis();
			for(i=0;i<3000;i++) {
				p.X=rand() % (_gl->getXmax()-size.Width);
				p.Y=rand() % (_gl->getYmax()-size.Height);
				_gl->setForeground(rand());
				_gl->writeString(p,*_font,str);
			}
			elapsed=MillisecondTimer::millis()-before;
			_gl->clearScreen();
			_gl->setForeground(ColourNames::WHITE);
			*_gl << Point::Origin << "Elapsed: " << (int32_t)elapsed << "ms";
			MillisecondTimer::delay(3000);
		}
		void scrollTest() {
			int32_t i,j,numRows;
			Point p;
			prompt("Hardware scrolling test");
			_gl->setForeground(0xffffff);
			_gl->setBackground(0);
			_gl->clearScreen();
			numRows=((_gl->getYmax()+1)/_font->getHeight())/3;
			p.X=0;
			for(i=0;i<numRows;i++) {
				p.Y=(numRows+i)*_font->getHeight();
				*_gl << p << "Test row " << i;
			}
			for(j=0;j<15;j++) {
				numRows=(_gl->getYmax()+1)/4;
				for(i=0;i<numRows;i++) {
					_gl->setScrollPosition(i);
					MillisecondTimer::delay(5);
				}
				for(i=0;i<numRows;i++) {
					_gl->setScrollPosition(numRows-i);
					MillisecondTimer::delay(5);
				}
			}
			_gl->setScrollPosition(0);
		}
		void clearTest() {
			int i;
			uint32_t start;
			prompt("Clear screen test");
			for(i=0;i<200;i++) {
				_gl->setBackground(rand());
				start=MillisecondTimer::millis();
				_gl->clearScreen();
				stopTimer(" to clear",MillisecondTimer::millis()-start);
			}
		}
		void basicColoursTest() {
			uint16_t i;
			static const uint32_t colours[7]={
			  ColourNames::RED,
			  ColourNames::GREEN,
			  ColourNames::BLUE,
			  ColourNames::CYAN,
			  ColourNames::MAGENTA,
			  ColourNames::YELLOW,
			  ColourNames::BLACK,
			};
			prompt("Basic colours test");
			for(i=0;i<sizeof(colours)/sizeof(colours[0]);i++) {
				_gl->setBackground(colours[i]);
				_gl->clearScreen();
				MillisecondTimer::delay(500);
			}
		}
		void lineTest() {
			Point p1,p2;
			int i;
			prompt("Line test");
			for(i=0;i<5000;i++) {
				p1.X=rand() % _gl->getXmax();
				p1.Y=rand() % _gl->getYmax();
				p2.X=rand() % _gl->getXmax();
				p2.Y=rand() % _gl->getYmax();
				_gl->setForeground(rand());
				_gl->drawLine(p1,p2);
			}
		}
		void rectTest() {
			int i;
			Rectangle rc;
			prompt("Rectangle test");
			for(i=0;i<1500;i++) {
				rc.X=(rand() % _gl->getXmax()/2);
				rc.Y=(rand() % _gl->getXmax()/2);
				rc.Width=rand() % (_gl->getXmax()-rc.X);
				rc.Height=rand() % (_gl->getYmax()-rc.Y);
				_gl->setForeground(rand());
				_gl->fillRectangle(rc);
			}
			_gl->clearScreen();
			for(i=0;i<10000;i++) {
				rc.X=(rand() % _gl->getXmax()/2);
				rc.Y=(rand() % _gl->getXmax()/2);
				rc.Width=rand() % (_gl->getXmax()-rc.X);
				rc.Height=rand() % (_gl->getYmax()-rc.Y);
				_gl->setForeground(rand());
				_gl->drawRectangle(rc);
				if(i % 1000 ==0)
					_gl->clearScreen();
			}
		}
		void ellipseTest() {
			int16_t i;
			Point p;
			Size s;
			prompt("Ellipse test");
			_gl->setBackground(0);
			for(i=0;i<1000;i++) {
				p.X=_gl->getXmax()/4+(rand() % (_gl->getXmax()/2));
				p.Y=_gl->getYmax()/4+(rand() % (_gl->getYmax()/2));
				if(p.X<_gl->getXmax()/2)
					s.Width=rand() % p.X;
				else
					s.Width=rand() % (_gl->getXmax()-p.X);
				if(p.Y<_gl->getYmax()/2)
					s.Height=rand() % p.Y;
				else
					s.Height=rand() % (_gl->getYmax()-p.Y);
				_gl->setForeground(rand());
				_gl->fillEllipse(p,s);
			}
			_gl->clearScreen();
			for(i=0;i<1500;i++) {
				p.X=_gl->getXmax()/4+(rand() % (_gl->getXmax()/2));
				p.Y=_gl->getYmax()/4+(rand() % (_gl->getYmax()/2));
				if(p.X<_gl->getXmax()/2)
					s.Width=rand() % p.X;
				else
					s.Width=rand() % (_gl->getXmax()-p.X);
				if(p.Y<_gl->getYmax()/2)
					s.Height=rand() % p.Y;
				else
					s.Height=rand() % (_gl->getYmax()-p.Y);
				if(s.Height>0 && s.Width>0 && p.X+s.Width<_gl->getXmax() && p.Y+s.Height<_gl->getYmax()) {
					_gl->setForeground(rand());
					_gl->drawEllipse(p,s);
				}
				if(i % 500==0)
					_gl->clearScreen();
			}
		}
		void doGradientFills(Direction dir) {
			Rectangle rc;
			uint16_t i;
			static uint32_t colours[7]={
				ColourNames::RED,
				ColourNames::GREEN,
				ColourNames::BLUE,
				ColourNames::CYAN,
				ColourNames::MAGENTA,
				ColourNames::YELLOW,
				ColourNames::WHITE,
			};
			rc.Width=_gl->getXmax()+1;
			rc.Height=(_gl->getYmax()+1)/2;
			for(i=0;i<sizeof(colours)/sizeof(colours[0]);i++) {
				rc.X=0;
				rc.Y=0;
				_gl->gradientFillRectangle(rc,dir,ColourNames::BLACK,colours[i]);
				rc.Y=rc.Height;
				_gl->gradientFillRectangle(rc,dir,colours[i],ColourNames::BLACK);
				MillisecondTimer::delay(1000);
			}
		}
		void gradientTest() {
			prompt("Gradient test");
			doGradientFills(HORIZONTAL);
			doGradientFills(VERTICAL);
		}
		void prompt(const char *prompt) {
			_gl->setBackground(ColourNames::BLACK);
			_gl->clearScreen();
			_gl->setForeground(ColourNames::WHITE);
			*_gl << Point(0,0) << prompt;
			MillisecondTimer::delay(2000);
			_gl->clearScreen();
		}
		void stopTimer(const char *prompt,uint32_t elapsed) {
			_gl->setForeground(0xffffff);
			*_gl << Point(0,0) << (int32_t)elapsed << "ms " << prompt;
		}
};
/*
 * Main entry point
 */
int main() {
	// set up SysTick at 1ms resolution
	MillisecondTimer::initialise();
	LDS285Test test;
	test.run();
	// not reached
	return 0;
}
 
mc2pa8201
Click here to hide the full mc2pa8201 code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/display/tft.h"
extern uint32_t BulbPixelsSize,BulbPixels;
extern uint32_t AudioPixelsSize,AudioPixels;
extern uint32_t FlagPixelsSize,FlagPixels;
extern uint32_t DocPixelsSize,DocPixels;
extern uint32_t GlobePixelsSize,GlobePixels;
extern uint32_t JpegTest0Pixels,JpegTest0PixelsSize;
using namespace stm32plus;
using namespace stm32plus::display;
/**
 * MC2PA8201 LCD test, show a looping graphics demo
 *
 * The MC2PA8201 driver is used by many of the Nokia QVGA
 * cellphone LCDs including 2730, 6300, N82 and N93.
 *
 * It's an 8-bit device and we control it in this demo
 * using the FSMC peripheral on bank 1. The wiring that
 * you need to do is as follows:
 *
 * PE1  => RESET
 * PD11 => RS (D/CX)
 * PD7  => CS
 * PD4  => RD
 * PD5  => WR
 * PD14 => D0
 * PD15 => D1
 * PD0  => D2
 * PD1  => D3
 * PE7  => D4
 * PE8  => D5
 * PE9  => D6
 * PD10 => D7
 * PD13 => Backlight PWM (if variable backlight)
 *
 * There are no special considerations for the F1 versus
 * the F4. The code works on both without any change.
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103VET6
 *   STM32F407VGT6
 */
class MC2PA8201Test {
	protected:
		typedef Fsmc8BitAccessMode<FsmcBank1NorSram1> LcdAccessMode;
		typedef Nokia6300_Portrait_262K_TypeA<LcdAccessMode> LcdPanel;
		LcdAccessMode *_accessMode;
		LcdPanel *_gl;
		Font *_font;
	public:
		void run() {
			// reset is on PE1 and RS (D/CX) is on PD11
			GpioE<DefaultDigitalOutputFeature<1> > pe;
			GpioD<DefaultAlternateFunctionFeature<GPIO_AF_FSMC,11> > pd;
			// set up the FSMC with RS=A16 (PD11)
			Fsmc8080LcdTiming fsmcTiming(0,5);
			_accessMode=new LcdAccessMode(fsmcTiming,16,pe[1]);
			// declare a panel
			_gl=new LcdPanel(*_accessMode);
			// clear to black while the lights are out
			_gl->setBackground(0);
			_gl->clearScreen();
			// create the backlight on timer4, channel2 (PD13)
			DefaultBacklight backlight;
			// fade up to 100% in 4ms steps
			backlight.fadeTo(100,4);
			// create a font
			_font=new Font_VOLTER__28GOLDFISH_299;
			*_gl << *_font;
			for(;;) {
				basicColoursTest();
				jpegTest();
				lzgTest();
				textTest();
				scrollTest();
				ellipseTest();
				gradientTest();
				rectTest();
				lineTest();
				clearTest();
				sleepTest();
			}
		}
		void sleepTest() {
			prompt("Sleep test");
			// go to sleep
			*_gl << Point::Origin << "Sleeping now...";
			MillisecondTimer::delay(1000);
			_gl->sleep();
			MillisecondTimer::delay(3000);
			// wake up
			_gl->wake();
			_gl->clearScreen();
			*_gl << Point::Origin << "Woken up again...";
			MillisecondTimer::delay(3000);
		}
		void jpegTest() {
			if(_gl->getHeight()==320 && _gl->getWidth()==240) {
				prompt("JPEG bitmap test");
				LinearBufferInputOutputStream compressedData((uint8_t *)&JpegTest0Pixels,(uint32_t)&JpegTest0PixelsSize);
				_gl->drawJpeg(Rectangle(0,0,240,320),compressedData);
				MillisecondTimer::delay(3000);
			}
		}
		void lzgTest() {
			prompt("LZG bitmap test");
#if defined(STM32PLUS_F1)
			Dma1Channel6<DmaFsmcLcdMemoryCopyFeature<LcdAccessMode> > dma;
#elif defined(STM32PLUS_F4)
			Dma2Channel1Stream2<DmaFsmcLcdMemoryCopyFeature<LcdAccessMode> > dma;
#endif
			drawCompressedBitmap((uint8_t *)&BulbPixels,(uint32_t)&BulbPixelsSize,89,148,true,dma);
			drawCompressedBitmap((uint8_t *)&AudioPixels,(uint32_t)&AudioPixelsSize,150,161,false,dma);
			drawCompressedBitmap((uint8_t *)&FlagPixels,(uint32_t)&FlagPixelsSize,144,220,true,dma);
			drawCompressedBitmap((uint8_t *)&DocPixels,(uint32_t)&DocPixelsSize,200,240,false,dma);
			drawCompressedBitmap((uint8_t *)&GlobePixels,(uint32_t)&GlobePixelsSize,193,219,true,dma);
		}
		void drawCompressedBitmap(uint8_t *pixels,uint32_t size,uint16_t width,uint16_t height,bool useDma,DmaFsmcLcdMemoryCopyFeature<LcdAccessMode>& dma) {
			_gl->setBackground(ColourNames::WHITE);
			_gl->clearScreen();
			LinearBufferInputOutputStream compressedData(pixels,size);
			LzgDecompressionStream decompressor(compressedData,size);
			if(useDma) {
				_gl->drawBitmap(
						Rectangle(((_gl->getXmax()+1)-width)/2,
								((_gl->getYmax()+1)-height)/2,
								width,height),
								decompressor,
								dma);
			}
			else {
				_gl->drawBitmap(
						Rectangle(((_gl->getXmax()+1)-width)/2,
								((_gl->getYmax()+1)-height)/2,
								width,height),
								decompressor);
			}
			MillisecondTimer::delay(3000);
		}
		void textTest() {
			int i;
			const char *str="The quick brown fox";
			Size size;
			Point p;
			uint32_t before,elapsed;
			prompt("Stream operators test");
			*_gl << Point::Origin << "Let's see PI:";
			for(i=0;i<=7;i++)
				*_gl << Point(0,(1+i)*_font->getHeight()) << DoublePrecision(3.1415926535,i);
			MillisecondTimer::delay(5000);
			prompt("Opaque text test");
			size=_gl->measureString(*_font,str);
			before=MillisecondTimer::millis();
			for(i=0;i<3000;i++) {
				p.X=rand() % (_gl->getXmax()-size.Width);
				p.Y=rand() % (_gl->getYmax()-size.Height);
				_gl->setForeground(rand());
				_gl->writeString(p,*_font,str);
			}
			elapsed=MillisecondTimer::millis()-before;
			_gl->clearScreen();
			_gl->setForeground(ColourNames::WHITE);
			*_gl << Point::Origin << "Elapsed: " << (int32_t)elapsed << "ms";
			MillisecondTimer::delay(3000);
		}
		void scrollTest() {
			int32_t i,j,numRows;
			Point p;
			prompt("Hardware scrolling test");
			_gl->setForeground(0xffffff);
			_gl->setBackground(0);
			_gl->clearScreen();
			numRows=((_gl->getYmax()+1)/_font->getHeight())/3;
			p.X=0;
			for(i=0;i<numRows;i++) {
				p.Y=(numRows+i)*_font->getHeight();
				*_gl << p << "Test row " << i;
			}
			for(j=0;j<15;j++) {
				numRows=(_gl->getYmax()+1)/4;
				for(i=0;i<numRows;i++) {
					_gl->setScrollPosition(i);
					MillisecondTimer::delay(5);
				}
				for(i=0;i<numRows;i++) {
					_gl->setScrollPosition(numRows-i);
					MillisecondTimer::delay(5);
				}
			}
			_gl->setScrollPosition(0);
		}
		void clearTest() {
			int i;
			uint32_t start;
			prompt("Clear screen test");
			for(i=0;i<200;i++) {
				_gl->setBackground(rand());
				start=MillisecondTimer::millis();
				_gl->clearScreen();
				stopTimer(" to clear",MillisecondTimer::millis()-start);
			}
		}
		void basicColoursTest() {
			uint16_t i;
			static const uint32_t colours[7]={
			  ColourNames::RED,
			  ColourNames::GREEN,
			  ColourNames::BLUE,
			  ColourNames::CYAN,
			  ColourNames::MAGENTA,
			  ColourNames::YELLOW,
			  ColourNames::BLACK,
			};
			prompt("Basic colours test");
			for(i=0;i<sizeof(colours)/sizeof(colours[0]);i++) {
				_gl->setBackground(colours[i]);
				_gl->clearScreen();
				MillisecondTimer::delay(500);
			}
		}
		void lineTest() {
			Point p1,p2;
			int i;
			prompt("Line test");
			for(i=0;i<5000;i++) {
				p1.X=rand() % _gl->getXmax();
				p1.Y=rand() % _gl->getYmax();
				p2.X=rand() % _gl->getXmax();
				p2.Y=rand() % _gl->getYmax();
				_gl->setForeground(rand());
				_gl->drawLine(p1,p2);
			}
		}
		void rectTest() {
			int i;
			Rectangle rc;
			prompt("Rectangle test");
			for(i=0;i<1500;i++) {
				rc.X=(rand() % _gl->getXmax()/2);
				rc.Y=(rand() % _gl->getXmax()/2);
				rc.Width=rand() % (_gl->getXmax()-rc.X);
				rc.Height=rand() % (_gl->getYmax()-rc.Y);
				_gl->setForeground(rand());
				_gl->fillRectangle(rc);
			}
			_gl->clearScreen();
			for(i=0;i<10000;i++) {
				rc.X=(rand() % _gl->getXmax()/2);
				rc.Y=(rand() % _gl->getXmax()/2);
				rc.Width=rand() % (_gl->getXmax()-rc.X);
				rc.Height=rand() % (_gl->getYmax()-rc.Y);
				_gl->setForeground(rand());
				_gl->drawRectangle(rc);
				if(i % 1000 ==0)
					_gl->clearScreen();
			}
		}
		void ellipseTest() {
			int16_t i;
			Point p;
			Size s;
			prompt("Ellipse test");
			_gl->setBackground(0);
			for(i=0;i<1000;i++) {
				p.X=_gl->getXmax()/4+(rand() % (_gl->getXmax()/2));
				p.Y=_gl->getYmax()/4+(rand() % (_gl->getYmax()/2));
				if(p.X<_gl->getXmax()/2)
					s.Width=rand() % p.X;
				else
					s.Width=rand() % (_gl->getXmax()-p.X);
				if(p.Y<_gl->getYmax()/2)
					s.Height=rand() % p.Y;
				else
					s.Height=rand() % (_gl->getYmax()-p.Y);
				_gl->setForeground(rand());
				_gl->fillEllipse(p,s);
			}
			_gl->clearScreen();
			for(i=0;i<1500;i++) {
				p.X=_gl->getXmax()/4+(rand() % (_gl->getXmax()/2));
				p.Y=_gl->getYmax()/4+(rand() % (_gl->getYmax()/2));
				if(p.X<_gl->getXmax()/2)
					s.Width=rand() % p.X;
				else
					s.Width=rand() % (_gl->getXmax()-p.X);
				if(p.Y<_gl->getYmax()/2)
					s.Height=rand() % p.Y;
				else
					s.Height=rand() % (_gl->getYmax()-p.Y);
				if(s.Height>0 && s.Width>0 && p.X+s.Width<_gl->getXmax() && p.Y+s.Height<_gl->getYmax()) {
					_gl->setForeground(rand());
					_gl->drawEllipse(p,s);
				}
				if(i % 500==0)
					_gl->clearScreen();
			}
		}
		void doGradientFills(Direction dir) {
			Rectangle rc;
			uint16_t i;
			static uint32_t colours[7]={
				ColourNames::RED,
				ColourNames::GREEN,
				ColourNames::BLUE,
				ColourNames::CYAN,
				ColourNames::MAGENTA,
				ColourNames::YELLOW,
				ColourNames::WHITE,
			};
			rc.Width=_gl->getXmax()+1;
			rc.Height=(_gl->getYmax()+1)/2;
			for(i=0;i<sizeof(colours)/sizeof(colours[0]);i++) {
				rc.X=0;
				rc.Y=0;
				_gl->gradientFillRectangle(rc,dir,ColourNames::BLACK,colours[i]);
				rc.Y=rc.Height;
				_gl->gradientFillRectangle(rc,dir,colours[i],ColourNames::BLACK);
				MillisecondTimer::delay(1000);
			}
		}
		void gradientTest() {
			prompt("Gradient test");
			doGradientFills(HORIZONTAL);
			doGradientFills(VERTICAL);
		}
		void prompt(const char *prompt) {
			_gl->setBackground(ColourNames::BLACK);
			_gl->clearScreen();
			_gl->setForeground(ColourNames::WHITE);
			*_gl << Point(0,0) << prompt;
			MillisecondTimer::delay(2000);
			_gl->clearScreen();
		}
		void stopTimer(const char *prompt,uint32_t elapsed) {
			_gl->setForeground(0xffffff);
			*_gl << Point(0,0) << (int32_t)elapsed << "ms " << prompt;
		}
};
/*
 * Main entry point
 */
int main() {
	// set up SysTick at 1ms resolution
	MillisecondTimer::initialise();
	MC2PA8201Test test;
	test.run();
	// not reached
	return 0;
}
 
power
Click here to hide the full power code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/exti.h"
#include "config/power.h"
#include "config/timing.h"
using namespace stm32plus;
/**
 * Low power modes test. This example requires a
 * pushbutton wired to PA8 and an indicator LED wired
 * to PF6.
 *
 * The LED will continually flash as 250ms intervals
 * until the button is pressed at which point the MCU
 * will go into STOP mode pending an interrupt to wake
 * it up. Press the button again will cause the EXTI
 * interrupt that will wake it up.
 *
 * The commented out line _lpm.standby() can be
 * substituted for the stopInterruptWakeup() call to
 * cause the MCU to enter STANDBY mode. STANDBY can be
 * exited by WAKEUP, IWDG, RTC alarm and of course
 * external reset. STANDBY mode clears SRAM therefore
 * execution after wakeup is back at the start of your
 * program (the reset handler).
 *
 * To run this example on the STM32F4DISCOVERY board
 * change the LED pin to PD13 to use the onboard LED
 * and change the button pin to PA0 to use the onboard
 * user button. Also change Exti8 to Exti0 to match
 * the button pin number.
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103ZET6
 *   STM32F407VGT6
 */
class PowerTest : public Observer {
	protected:
		enum {
			BUTTON_PIN = 8,
			LED_PIN = 6
		};
		LowPowerModes _lpm;
		bool _triggered;
	public:
		void run() {
			// initialise the LED and button pins
			GpioF<DefaultDigitalOutputFeature<LED_PIN> > pf;
			GpioA<DefaultDigitalInputFeature<BUTTON_PIN> > pa;
			Exti8 exti(EXTI_Mode_Interrupt,EXTI_Trigger_Falling,pa[BUTTON_PIN]);
			exti.insertObserver(*this);
			// if we're here because of a previous standby then flash quickly 3 times
			if(LowPowerModes::wasInStandby())
				flashLed(pf[LED_PIN],3);
			// if we're here because of a wakeup then flash quickly 6 times
			if(LowPowerModes::wasWokenUp())
				flashLed(pf[LED_PIN],6);
			// enable the WAKEUP pin
			_lpm.enableWakeup();
			_triggered=false;
			for(;;) {
				// flash the LED
				pf[LED_PIN].set();
				MillisecondTimer::delay(250);
				pf[LED_PIN].reset();
				MillisecondTimer::delay(250);
				// if the interrupt set the trigger, do our stuff
				if(_triggered) {
					// wakeup following STOP will continue after here
					_lpm.stopInterruptWakeup();
					// wakeup following STANDBY will reset the device
					//_lpm.standby();
					_triggered=false;
				}
			}
		}
		/*
		 * Observer notification callback for the EXTI interrupt that's wired to the falling
		 * edge of the button GPIO line.
		 */
		virtual void onNotify(Observable& sender __attribute__((unused)),
		                      ObservableEvent::E event,
		                      void *context __attribute__((unused))) {
			if(event==ObservableEvent::EXTI_Triggered)
				_triggered=true;
		}
		/**
		 * Flash the LED for the number times then wait 3 seconds
		 * @param count number of times to flash
		 */
		void flashLed(const GpioPinRef& gpio,int count) {
			for(int i=0;i<count;i++) {
				gpio.reset();
				MillisecondTimer::delay(100);
				gpio.set();
				MillisecondTimer::delay(100);
			}
			MillisecondTimer::delay(3000);
		}
};
/*
 * Main entry point
 */
int main() {
	// set up SysTick at 1ms resolution
	MillisecondTimer::initialise();
	PowerTest test;
	test.run();
	// not reached
	return 0;
}
 
sdio
Click here to hide the full sdio code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/sdcard.h"
#include "config/timing.h"
using namespace stm32plus;
/**
 * SD card demonstration using the onboard SDIO peripheral
 * in high-speed 4-bit mode. This example will erase 100
 * blocks from 20000 to 20099, then write a bit-pattern to
 * each of these blocks and finally read back each block to
 * verify the bit-pattern. Blocks are always 512 bytes in
 * size, even if your card is a non-SDHC card that has
 * physical block sizes that are not 512 bytes.
 *
 * If all is OK then a LED on PF[6] will be flashed for
 * 1-second at the end of each of the erase, write, read
 * sequences. If anything goes wrong then the LED will
 * flash rapidly at 5Hz.
 *
 * The SdioDmaSdCard class encapsulates access to the SDIO
 * peripheral classes and uses DMA and interrupts to
 * transfer data. The default constructor will
 * automatically detect appropriate SDIO initialisation
 * and transfer frequencies based on targets of 200kHz and
 * 24MHz, respectively. You can tune these dividers by
 * using an SdioDmaSdCard constructor parameter of
 * 'false' (see the code comments below).
 *
 * Please note that this demo is destructive to any files
 * that happen to be on your SD card and are unfortunate
 * enough to be located on the blocks we target. You
 * should reformat the card after you're done.
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F407VGT6
 *   STM32F103VET6
 *   STM32F103ZET6
 */
class SdioTest {
	protected:
		GpioF<DefaultDigitalOutputFeature<6> > _pf;
	public:
			void run() {
				/*
				 * Clear the LED. Our LED on PF[6] is active LOW.
				 */
				_pf[6].set();
				/*
				 * Initialise the sdcard with the SDIO interface feature. The constructor will attempt
				 * to detect the initialisation and transfer clock dividers automatically for target frequencies
				 * of 200kHz and 24MHz, respectively. You can override these by calling setInitDivider() and
				 * setTransferDivider() and use 'false' as the constructor parameter so that the auto-init
				 * does not happen. In this case you will need to call powerOn() and initialiseCard() yourself.
				 */
				SdioDmaSdCard sdcard;
				/*
				 * Check for any errors raised in the constructor
				 */
				if(errorProvider.hasError())
					error();
				for(;;) {
					eraseBlocks(sdcard);
					writeBlocks(sdcard);
					readBlocks(sdcard);
				}
			}
			/*
			 * Erase blocks 20000 to 20099
			 */
			void eraseBlocks(SdioDmaSdCard& sdcard) {
				// erase the blocks
				if(!sdcard.eraseBlocks(20000,20099))
					error();
				// it worked
				signalOK();
			}
			/*
			 * Write blocks 20000 to 20099
			 */
			void writeBlocks(SdioDmaSdCard& sdcard) {
				int i;
				uint8_t block[512];
				// init the block
				for(i=0;i<512;i++)
					block[i]=i & 0xff;
				for(i=20000;i<20099;i++)
					if(!sdcard.writeBlock(block,i))
						error();
			}
			/*
			 * Read blocks 20000 to 20099
			 */
			void readBlocks(SdioDmaSdCard& sdcard) {
				int i,j;
				uint8_t block[512];
				// read each block
				for(i=20000;i<20099;i++) {
					// read this block
					if(!sdcard.readBlock(block,i))
						error();
					// verify the content
					for(j=0;j<512;j++)
						if(block[j]!=(j & 0xff))
							error();
				}
			}
			/*
			 * Signal that we completed an operation OK
			 */
			void signalOK() {
				_pf[6].reset();											// on
				MillisecondTimer::delay(1000);			// wait a second
				_pf[6].set();												// off
			}
			/*
			 * There's been an error. Lock up and flash the LED on PF6 rapidly
			 */
			void error() {
				for(;;) {
					_pf[6].set();
					MillisecondTimer::delay(200);
					_pf[6].reset();
					MillisecondTimer::delay(200);
				}
			}
	};
/*
 * Main entry point
 */
int main() {
	// we're using timing
	MillisecondTimer::initialise();
	// configure Nvic
	Nvic::initialise();
	SdioTest sdio;
	sdio.run();
	// not reached
	return 0;
}
 
spi_send_dma
Click here to hide the full spi_send_dma code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/spi.h"
#include "config/dma.h"
#include "config/timing.h"
using namespace stm32plus;
/**
 * This demo illustrates sending and receiving using the
 * SPI peripherals. A block of test data is sent from
 * SPI1 to SPI2 and, if successfully received, then a
 * LED on PF6 is flashed for 1 second. The test repeats
 * continuously.
 *
 * The DMA channels assigned to SPI1 and SPI2 are used
 * to perform the transfer.
 *
 * If you intend to run this example on the
 * STM23F4DISCOVERY board then replace PF6 with PD13 to
 * use the onboard LED.
 *
 * For this demo I'm going to need you to do a little
 * wiring to hook up SPI1 to SPI2 so that we can
 * exchange data over the MOSI pin. Here's the
 * connections that you need to make.
 *
 * 1MOSI/2MOSI: PA7  => PB15
 * NSS:         PA4 <=> PB12
 * SCLK:        PA5 <=> PB13
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103ZET6
 *   STM32F407VGT6
 */
class SpiSendDmaTest {
	protected:
		enum { LED_PIN = 6 };
	public:
		void run() {
			const uint8_t *dataToSend=(const uint8_t *)"Hello World";
			uint8_t receiveBuffer[12];
			// initialise the LED on PF6. It's active LOW so we set it HIGH to turn it off
			GpioF<DefaultDigitalOutputFeature<LED_PIN> > pf;
			pf[LED_PIN].set();
			/*
			 * Declare our SPI objects with no extra features beyond the ability to send and
			 * receive data bytes. SPI1 is going to be the master and SPI2 the slave. All the SPI
			 * remap configurations are available with names such as Spi1_Remap if you need to use the
			 * remapped pins.
			 */
			typedef Spi1<> MySender;
			typedef Spi2<> MyReceiver;
			MySender::Parameters senderParams;
			MyReceiver::Parameters receiverParams;
			senderParams.spi_mode=SPI_Mode_Master;
			receiverParams.spi_mode=SPI_Mode_Slave;
			MySender sender(senderParams);
			MyReceiver receiver(receiverParams);
			/*
			 * Declare the transmit and receive DMA channels assigned to the two peripherals.
			 * We'll give reception a higher priority than transmit since we are both the
			 * sender and the receiver.
			 *
			 * On the F4 the DMA FIFO is enabled by default. If you want to disable the FIFO then
			 * you can do that with an additional template parameter to SpiDmaWriterFeature and
			 * SpiDmaReaderFeature.
			 */
			Spi1TxDmaChannel<SpiDmaWriterFeature<Spi1PeripheralTraits,DMA_Priority_Medium> > dmaSender;
			Spi2RxDmaChannel<SpiDmaReaderFeature<Spi2PeripheralTraits,DMA_Priority_High> > dmaReceiver;
			for(;;) {
				/*
				 * Clear out the receive buffer for this session
				 */
				memset(receiveBuffer,0,12);
				/*
				 * Start the DMA receiver ready for the data
				 */
				dmaReceiver.beginRead(receiveBuffer,12);
        /*
         * NSS (slave select) is active LOW. ST made such a mess of the hardware implementation of NSS
         * that we always control it through software. Here it's pulled LOW ready for transmission.
         */
				sender.setNss(false);
				/*
				 * Start the DMA sender and let those bytes flow. The receiver has already been started and is
				 * stalled waiting for this
				 */
				dmaSender.beginWrite(dataToSend,12);
				/*
				 * Wait until the receiver gets all the bytes
				 */
				if(!dmaReceiver.waitUntilComplete()) {
				  // handle error properly
				  for(;;);
				}
				/*
				 * Wait until the sender has signalled that it's finished
				 */
				if(!dmaSender.waitUntilComplete()) {
				  // handle error properly
				  for(;;);
				}
				/*
				 * The session is complete, deactivate NSS.
				 */
				sender.setNss(true);
				/*
				 * Test the received buffer. If the data is incorrect then lock up
				 */
				if(memcmp(receiveBuffer,dataToSend,12)!=0)
					for(;;);
				/*
				 * The data is correct, flash the LED on PF6 for one second
				 */
				pf[LED_PIN].reset();
				MillisecondTimer::delay(1000);
				pf[LED_PIN].set();
				MillisecondTimer::delay(1000);
			}
		}
};
/*
 * Main entry point
 */
int main() {
	MillisecondTimer::initialise();
	SpiSendDmaTest test;
	test.run();
	// not reached
	return 0;
}
 
spi_send_interrupts
Click here to hide the full spi_send_interrupts code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/spi.h"
#include "config/timing.h"
using namespace stm32plus;
/**
 * This demo illustrates sending and receiving using the
 * SPI peripherals. A block of test data is sent from
 * SPI1 to SPI2 and, if successfully received, then a LED
 * on PF6 is flashed for 1 second. The test repeats
 * continuously.
 *
 * The SPI interrupts are used to send and receive the
 * data. Note the code that adjusts the relative
 * interrupt priorities.
 *
 * If you intend to run this example on the
 * STM23F4DISCOVERY board then replace PF6 with PD13 to
 * use the onboard LED.
 *
 * For this demo I'm going to need you to do a little
 * wiring to hook up SPI1 to SPI2 so that we can
 * exchange data over the MOSI pin. Here's the
 * connections that you need to make.
 *
 * 1MOSI/2MOSI: PA7  => PB15
 * NSS:         PA4 <=> PB12
 * SCLK:        PA5 <=> PB13
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103ZET6
 *   STM32F407VGT6
 */
static const uint8_t *dataToSend=(const uint8_t *)"Hello World";
class SpiSendInterruptsTest : public Observer {
  protected:
		enum { LED_PIN = 6 };
    /*
     * These instance variables will be used by the Observer to
     * co-ordinate the send and receive process.
     */
    volatile bool _completed;
    uint8_t _receiveBuffer[12];
    uint8_t _receiveIndex;
    uint8_t _sendIndex;
    /*
     * Declare the SPI sender/receiver.
     */
		typedef Spi1<Spi1InterruptFeature> MySender;
		typedef Spi2<Spi2InterruptFeature> MyReceiver;
    MySender *_sender;
    MyReceiver *_receiver;
  public:
		void run() {
			// initialise the LED on PF6. It's active LOW so we set it HIGH to turn it off
			GpioF<DefaultDigitalOutputFeature<LED_PIN> > pf;
			pf[LED_PIN].set();
			/*
			 * We're using interrupts, set up the NVIC
			 */
			Nvic::initialise();
			/**
			 * Create the sender and receiver objects with default parameters
			 */
			MySender::Parameters senderParams;
			MyReceiver::Parameters receiverParams;
			senderParams.spi_mode=SPI_Mode_Master;
			receiverParams.spi_mode=SPI_Mode_Slave;
			_sender=new MySender(senderParams);
			_receiver=new MyReceiver(receiverParams);
			/*
			 * We need to adjust the priority of the interrupts so that the receiver is higher (lower number)
			 * than the sender. If this is not done then the TXE interrupt (sender) will always pre-empt the
			 * receiver with the undesirable result that all the bytes will be transmitted but only the first
			 * will be received because the receiver IRQ will fire on the first byte transmission and then get
			 * queued until transmission of all bytes finish by which time all but the queued receiver interrupt
			 * have been missed.
			 */
			_sender->setNvicPriorities(1);
			_receiver->setNvicPriorities(0);
			/*
			 * register ourselves as an observer of the SPI interrupts
			 */
			_sender->insertObserver(*this);
			_receiver->insertObserver(*this);
			for(;;) {
			  /*
			   * Reset the instance variables
			   */
			  _sendIndex=0;
			  _receiveIndex=0;
			  _completed=false;
			  memset(_receiveBuffer,0,sizeof(_receiveBuffer));
        /*
         * NSS (slave select) is active LOW. ST made such a mess of the hardware implementation of NSS
         * that we always control it through software. Here it's pulled LOW ready for transmission.
         */
        _sender->setNss(false);
        /*
         * Enable them now. TXE will be raised immediately
         */
        _receiver->enableInterrupts(SPI_I2S_IT_RXNE);
        _sender->enableInterrupts(SPI_I2S_IT_TXE);
        /*
         * Wait for the interrupts to signal completion
         */
        while(!_completed);
        /*
         * De-select NSS
         */
        _sender->setNss(true);
				/*
				 * Test the received buffer. If the data is incorrect then lock up
				 */
				if(memcmp(_receiveBuffer,dataToSend,sizeof(_receiveBuffer))!=0)
					for(;;);
				/*
				 * The data is correct, flash the LED on PF6 for one second
				 */
				pf[LED_PIN].reset();
				MillisecondTimer::delay(1000);
				pf[LED_PIN].set();
				MillisecondTimer::delay(1000);
			}
		}
		/*
     * Observer callback function. This is called when the TXE interrupt that we've
     * enabled is fired.
     */
    virtual void onNotify(Observable&,ObservableEvent::E event,void *) {
      if(event==ObservableEvent::SPI_ReadyToTransmit) {
        // send a byte and increment send position
        _sender->send(&dataToSend[_sendIndex],1);
        _sendIndex++;
        // if all is sent, disable further send interrupts
        if(_sendIndex==sizeof(_receiveBuffer))
          _sender->disableInterrupts(SPI_I2S_IT_TXE);
      }
      else if(event==ObservableEvent::SPI_Receive) {
        // receive a byte
        _receiver->receive(_receiveBuffer[_receiveIndex]);
        _receiveIndex++;
        // if all is received, disable interrupts and signal finished
        if(_receiveIndex==sizeof(_receiveBuffer)) {
          _receiver->disableInterrupts(SPI_I2S_IT_RXNE);
          _completed=true;
        }
      }
    }
};
/*
 * Main entry point
 */
int main() {
	MillisecondTimer::initialise();
	SpiSendInterruptsTest test;
	test.run();
	// not reached
	return 0;
}
 
spi_send_sync
Click here to hide the full spi_send_sync code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/spi.h"
#include "config/timing.h"
using namespace stm32plus;
/**
 * This demo illustrates sending and receiving using the
 * SPI peripherals. A block of test data is sent from
 * SPI1 to SPI2 and, if successfully received, then a
 * LED on PF6 is flashed for 1 second. The test repeats
 * continuously.
 *
 * For this demo I'm going to need you to do a little
 * wiring to hook up SPI1 to SPI2 so that we can
 * exchange data over the MOSI pin. Here's the
 * connections that you need to make.
 *
 * If you intend to run this example on the
 * STM23F4DISCOVERY board then replace PF6 with PD13
 * to use the onboard LED.
 *
 * 1MOSI/2MOSI: PA7  => PB15
 * NSS:         PA4 <=> PB12
 * SCLK:        PA5 <=> PB13
 * *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103ZET6
 *   STM32F407VGT6
 */
class SpiSendSyncTest {
	protected:
		enum { LED_PIN = 6 };
	public:
		void run() {
			const uint8_t *dataToSend=(const uint8_t *)"Hello World";
			uint8_t receiveBuffer[12];
			uint8_t i;
			// initialise the LED on PF6. It's active LOW so we set it HIGH to turn it off
			GpioF<DefaultDigitalOutputFeature<LED_PIN> > pf;
			pf[LED_PIN].set();
			/*
			 * Declare our SPI objects with no extra features beyond the ability to send and
			 * receive data bytes. SPI1 is going to be the master and SPI2 the slave. All the SPI
			 * remap configurations are available with names such as Spi1_Remap if you need to use the
			 * remapped pins.
			 */
			typedef Spi1<> MySender;
			typedef Spi2<> MyReceiver;
			MySender::Parameters senderParams;
			MyReceiver::Parameters receiverParams;
			senderParams.spi_mode=SPI_Mode_Master;
			receiverParams.spi_mode=SPI_Mode_Slave;
			MySender sender(senderParams);
			MyReceiver receiver(receiverParams);
			for(;;) {
				/*
				 * Clear out the receive buffer for this session
				 */
				memset(receiveBuffer,0,12);
				/*
				 * NSS (slave select) is active LOW. ST made such a mess of the hardware implementation of NSS
				 * that we always control it through software. Here it's pulled LOW ready for transmission.
				 */
				sender.setNss(false);
				for(i=0;i<12;i++) {
					/*
					 * Wait for the sender to signal it's ready and then send a byte
					 */
					while(!sender.readyToSend());
					sender.send(&dataToSend[i],1);
					/*
					 * Wait for the receiver to signal it's ready to receive and then receive the byte
					 */
					while(!receiver.readyToReceive());
					receiver.receive(receiveBuffer[i]);
				}
				/*
				 * The session is complete, deactivate NSS.
				 */
				sender.setNss(true);
				/*
				 * Test the received buffer. If the data is incorrect then lock up
				 */
				if(memcmp(receiveBuffer,dataToSend,12)!=0)
					for(;;);
				/*
				 * The data is correct, flash the LED on PF6 for one second
				 */
				pf[LED_PIN].reset();
				MillisecondTimer::delay(1000);
				pf[LED_PIN].set();
				MillisecondTimer::delay(1000);
			}
		}
};
/*
 * Main entry point
 */
int main() {
	MillisecondTimer::initialise();
	SpiSendSyncTest test;
	test.run();
	// not reached
	return 0;
}
 
timer_dma_pwm
Click here to hide the full timer_dma_pwm code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/timer.h"
#include "config/dma.h"
using namespace stm32plus;
/**
 * Timer demo that illustrates how to use a DMA channel
 * to automatically reload the PWM duty cycle.
 *
 * In this example timer 1 is configured to output a
 * PWM signal on channel 1. The timer's DMA channel for
 * update events is used to automatically reload the
 * PWM duty cycle from a sequence that we supply each
 * time the timer gets an update event.
 *
 * The PWM signal is output on PA[8]. Connect this to
 * a LED to see the fade feature.
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103ZET6
 *   STM32F407VGT6
 */
class TimerDmaPwmTest {
	public:
		void run() {
			uint8_t i,percents[200];
			/*
			 * Create an instance of Timer1 running off the internal clock
			 * with channel 1 and unremapped GPIO output features.
			 */
			Timer1<
				Timer1InternalClockFeature,				// the timer bus is APB2
				TimerChannel1Feature,							// we're going to use channel 1
				Timer1GpioFeature<					      // we want to output something to GPIO
					TIMER_REMAP_NONE,								// the GPIO output will not be remapped
					TIM1_CH1_OUT										// we will output channel 1 to GPIO
				>
			> timer;
			/*
			 * Create an instance of the DMA channel that is connected to
			 * Timer1's update event and add in a PWM fader feature for
			 * Timer1's channel 1. This will be a circular DMA configuration, i.e.
			 * it will automatically run itself over and over again until we
			 * stop it.
			 */
			Timer1UpdateDmaChannel<
				Timer1Channel1UpdatePwmFadeTimerDmaFeature<DMA_Priority_High,DMA_Mode_Circular>
			> dma;
			// create a sequence of 0..100 (101 values)
			for(i=0;i<=100;i++)
				percents[i]=i;
			// follow it with a sequence of 99..1 (99 values)
			for(i=99;i>0;i--)
				percents[200-i]=i;
			/*
			 * Set the frequency of Timer1 to 10Mhz with a reload value
			 * of 50000. It will take 10e6/50000 = 200 ticks to get there
			 * so the attached DMA channel will get 200 update events
			 * per second.
			 */
			timer.setTimeBaseByFrequency(10000000,49999);
			/*
			 * Initialise channel 1's comparator for use as a PWM output
			 */
			timer.initCompareForPwmOutput();
			/*
			 * Start the timer
			 */
			timer.enablePeripheral();
			/*
			 * Attach the DMA channel to the timer and start it. The DMA
			 * channel will automatically load each new duty cycle into
			 * the CCR1 register on every update event. When it runs out
			 * it will restart because it's in circular mode. The 'percents'
			 * buffer does not need to remain in scope while the DMA operation
			 * is running
			 */
			dma.beginFadeByTimer(timer,percents,sizeof(percents));
			/*
			 * It's all running automatically now - go and do something
			 * cool with the CPU!
			 */
			for(;;);
		}
};
/*
 * Main entry point
 */
int main() {
	TimerDmaPwmTest test;
	test.run();
	// not reached
	return 0;
}
 
timer_dma_usart
Click here to hide the full timer_dma_usart code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/timer.h"
#include "config/usart.h"
#include "config/dma.h"
using namespace stm32plus;
/**
 * This example shows how to use a timer linked to a DMA
 * channel to transmit data automatically
 * to the USART peripheral.
 *
 * Timer1's update event is configured to fire once per
 * second. That update event is linked to a DMA channel
 * that targets the USART1 peripheral's TX register. For
 * our demo purposes we transmit a sample text string
 * continuously at a rate of 1 character per second.
 *
 * USART1 is used in default (unremapped) configuration:
 * 4800-8-N-1
 *
 * Note that if you are using the STM32F4DISCOVERY board
 * then you cannot use Usart1 since the pins clash with
 * onboard peripherals. I have tested this code on that
 * board using Usart2.
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103ZET6
 *   STM32F407VGT6
 */
class TimerDmaUsartTest {
	public:
		void run() {
			const char *dataToSend="Hello World";
			/*
			 * We're using USART1 (APB2), unremapped. Configure it to run at 4800 baud, 8 bits
			 * no flow control and 1 stop bit. (4800-8-N-1).
			 */
			Usart1<> usart1(4800);
			/*
			 * Configure Timer1 (APB2) with the internal clock source. No further features
			 * are required.
			 */
			Timer1<
				Timer1InternalClockFeature				// the timer bus is APB2
			> timer;
			/*
			 * Create an instance of the DMA channel that is connected to
			 * Timer1's update event. Add a feature that connects the timer's update
			 * event to the USART1 TX peripheral register.
			 *
			 * This will be a circular DMA configuration, i.e. it will automatically
			 * run itself over and over again until we stop it.
			 */
			Timer1UpdateDmaChannel<
				TimerUpdateDmaFeature<Usart1TxDmaPeripheralInfo,DMA_Priority_High,DMA_Mode_Circular>
			> dma;
			/*
			 * Set the frequency of Timer1 to 50KHz with a reload value
			 * of 50000. It will take 1 second to get from zero to 50000
			 * so the attached DMA channel will get 1 update event per second.
			 */
			timer.setTimeBaseByFrequency(50000,49999);
			/*
			 * Start the timer
			 */
			timer.enablePeripheral();
			/*
			 * Attach the DMA channel to the timer and start it. The DMA
			 * channel will automatically load the next character to transmit
			 * into the USART register.
			 */
			dma.beginWriteByTimer(timer,dataToSend,strlen(dataToSend));
			/*
			 * It's all running in hardware now, the CPU is ours to do what we want with. I've run
			 * out of bright ideas so I'll just do nothing.
			 */
			for(;;);
		}
};
/*
 * Main entry point
 */
int main() {
	TimerDmaUsartTest test;
	test.run();
	// not reached
	return 0;
}
 
timer_dual_gpio_out
Click here to hide the full timer_dual_gpio_out code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/timer.h"
using namespace stm32plus;
/**
 * Timer demonstration: Output a 1Hz toggle on/off signal
 * on PA0 and another 1Hz signal 500ms ahead of the first
 * one, output on PA1.
 *
 * The timer is configured to tick at 4000Hz with an auto-
 * reload value of 3999. Channel 1 is configured to output
 * an alternating signal on PA0 when the counter reaches
 * 3999. Similarly, channel 2 is configured to output an
 * alternating signal on PA1 when the counter reaches 1000.
 *
 * We configure the channel 1 compare value to be 3999
 * with an action of "toggle" and we enable GPIO output
 * for channel 1 on its default port of PA0.
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103ZET6
 *   STM32F407VGT6
 */
class TimerDualGpioOutTest {
	public:
		void run() {
			/*
			 * Initialise timer2 running from the internal APB1 clock with channel-1, channel-2
			 * and GPIO output features. The GPIO output feature is itself configured with
			 * channel-1 and channel-2 output features.
			 */
			Timer2<
				Timer2InternalClockFeature,				// the timer clock source is APB1
				TimerChannel1Feature,							// we're going to use channel 1...
				TimerChannel2Feature,							// ...and we're going to use channel 2
				Timer2GpioFeature<					      // we want to output something to GPIO
					TIMER_REMAP_NONE,								// the GPIO output will not be remapped
					TIM2_CH1_OUT,										// we will output channel 1 to GPIO PA0
					TIM2_CH2_OUT										// ...and also channel 2 to GPIO PA1
				>
			> timer;
			/*
			 * Set an up-timer up to tick at 4000Hz with an auto-reload value of 3999
			 * The timer will count from 0 to 3999 inclusive then reset back to 0.
			 * It will take exactly 1 second to do this.
			 *
			 * Note that the lowest frequency you can set is 1098 for a 72Mhz timer clock source.
			 * This is because the maximum prescaler value is 65536 (72Mhz/65536 = 1098Hz).
			 */
			timer.setTimeBaseByFrequency(4000,3999);
			/*
			 * Initialise the channel 1 output compare value to 3999 with the default
			 * action of toggle. Note that we have to qualify the initCompare call because
			 * we're including multiple channels in our timer class and their members have
			 * the same names.
			 */
			timer.TimerChannel1Feature::initCompare(3999);
			/*
			 * Initialise the channel 2 output compare value to 2000 with the default
			 * action of toggle. The toggle frequency is still 1Hz but it will be out
			 * of phase with the toggling of channel 1.
			 */
			timer.TimerChannel2Feature::initCompare(2000);
			/*
			 * Start the timer. Each time it ticks up to 4000 (which will take 1 second)
			 * the channel 1 compare value will be triggered and the TIM1_CH1 GPIO pin on PA0
			 * will be toggled. Since we've hooked this up to a LED we should see it flashing
			 * at 1Hz.
			 *
			 * When it hits 1000 then the same goes for TIM2_CH2 GPIO on PA1.
			 */
			timer.enablePeripheral();
			/*
			 * It's all running automatically now
			 */
			for(;;);
		}
};
/*
 * Main entry point
 */
int main() {
	TimerDualGpioOutTest test;
	test.run();
	// not reached
	return 0;
}
 
timer_dual_pwm_gpio_out
Click here to hide the full timer_dual_pwm_gpio_out code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/timer.h"
#include "config/timing.h"
using namespace stm32plus;
/**
 * Timer demonstration: Use timer 2 to output a 1Mhz PWM
 * wave on channel 1 (PA0) and channel 2 (PA1). The demo
 * will repeatedly increment the duty cycle on each
 * channel from 0 to 100% and back down to 0 over 800ms.
 * Channel 1 fades up while channel 2 fades down.
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103ZET6
 *   STM32F407VGT6
 */
class TimerDualPwmGpioOutTest {
	public:
		void run() {
			/*
			 * Initialise timer2 running from the internal APB1 clock with channel-1, channel-2
			 * and GPIO output features. The GPIO output feature is itself configured with
			 * channel-1 and channel-2 output features.
			 */
			Timer2<
				Timer2InternalClockFeature,				// the timer clock source is APB1
				TimerChannel1Feature,							// we're going to use channel 1...
				TimerChannel2Feature,							// ...and we're going to use channel 2
				Timer2GpioFeature<								// we want to output something to GPIO
					TIMER_REMAP_NONE,								// the GPIO output will not be remapped
					TIM2_CH1_OUT,										// we will output channel 2 to GPIO...
					TIM2_CH2_OUT										// ...and we will output channel 2 to GPIO
				>
			> timer;
			/*
			 * Set an up-timer up to tick at 10MHz with an auto-reload value of 1999
			 * The timer will count from 0 to 1999 inclusive then reset back to 0.
			 *
			 * Note that the lowest frequency you can set is 1098 for a 72Mhz timer clock source.
			 * This is because the maximum prescaler value is 65536 (72Mhz/65536 = 1098Hz).
			 */
			timer.setTimeBaseByFrequency(10000000,1999);
			/*
			 * Initialise channel 1 as a PWM channel in edge-aligned mode (TIM_OCMode_PWM1).
			 * The default starting duty cycle is zero. Note that we have to qualify the initCompare
			 * call because we're including multiple channels in our timer class and their members
			 * have the same names.
			 */
			timer.TimerChannel1Feature::initCompareForPwmOutput();
			/*
			 * Initialise channel 2 as a PWM channel in edge-aligned mode (TIM_OCMode_PWM1).
			 * The default starting duty cycle is zero.
			 */
			timer.TimerChannel2Feature::initCompareForPwmOutput();
			/*
			 * Enable the timer. The PWM outputs are on PA0 and PA1.
			 */
			timer.enablePeripheral();
			/*
			 * It's all running automatically now, use the main CPU to vary the duty cycle up
			 * to 100% and back down again
			 */
			for(;;) {
				// fade channel 1 up to 100% in 4ms steps while channel 2 comes down to 0
				for(int8_t i=0;i<=100;i++) {
					timer.TimerChannel1Feature::setDutyCycle(i);
					timer.TimerChannel2Feature::setDutyCycle(100-i);
					MillisecondTimer::delay(4);
				}
				// fade channel 1 down to 0% in 4ms steps while channel 2 goes up to 100%
				for(int8_t i=100;i>=0;i--) {
					timer.TimerChannel1Feature::setDutyCycle(i);
					timer.TimerChannel2Feature::setDutyCycle(100-i);
					MillisecondTimer::delay(4);
				}
			}
		}
};
/*
 * Main entry point
 */
int main() {
	// we need the SysTick timer
	MillisecondTimer::initialise();
	TimerDualPwmGpioOutTest test;
	test.run();
	// not reached
	return 0;
}
 
timer_gpio_out
Click here to hide the full timer_gpio_out code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/timer.h"
using namespace stm32plus;
/**
 * Timer demonstration: Output a 1Hz toggle on/off signal
 * on PA0.
 *
 * To achieve the alternating 1Hz signal on PA0 (TIM2_CH1)
 * we first set up Timer2 to tick at 10kHz with its auto-
 * reload register set to 9999. It will take 2 seconds
 * for the timer to tick up to 9999 at which point it
 * will reset back to zero.
 *
 * We configure the channel 1 compare value to be 9999
 * with an action of "toggle" and we enable GPIO output
 * for channel 1 on its default port of PA0.
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103ZET6
 *   STM32F407VGT6
 */
class TimerGpioOutTest {
	public:
		void run() {
			/*
			 * Initialise timer2 running from the internal APB2 clock with channel-1 and GPIO output features.
			 * The GPIO output feature is itself configured with a channel-1 output feature.
			 */
			Timer2<
				Timer2InternalClockFeature,				// the timer clock source is HCLK/2
				TimerChannel1Feature,							// we're going to use channel 1
				Timer2GpioFeature<								// we want to output something to GPIO
					TIMER_REMAP_NONE,								// the GPIO output will not be remapped
					TIM2_CH1_OUT										// we will output channel 1 to GPIO
				>
			> timer;
			/*
			 * Set an up-timer up to tick at 1000Hz with an auto-reload value of 9999
			 * The timer will count from 0 to 9999 inclusive then reset back to 0.
			 * It will take exactly 1 second to do this.
			 *
			 * Note that the lowest frequency on the F1 that you can set is 1098 for a
			 * 72Mhz timer clock source. This is because the maximum prescaler value is
			 * 65536 (72Mhz/65536 = 1098Hz).
			 */
			timer.setTimeBaseByFrequency(10000,9999);
			/*
			 * Initialise the channel 1 output compare value to 9999 with the default
			 * action of toggle.
			 */
			timer.initCompare(9999);
			/*
			 * Start the timer. Each time it ticks up to 9999 (which will take 1 second)
			 * the channel 1 compare value will be triggered and the TIM2_CH1 GPIO pin on PA0
			 * will be toggled. Since we've hooked this up to a LED we should see it flashing
			 * at 1Hz.
			 */
			timer.enablePeripheral();
			/*
			 * It's all running automatically now
			 */
			for(;;);
		}
};
/*
 * Main entry point
 */
int main() {
	TimerGpioOutTest test;
	test.run();
	// not reached
	return 0;
}
 
timer_input_capture
timer_interrupts
Click here to hide the full timer_interrupts code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/timer.h"
using namespace stm32plus;
/**
 * Timer demonstration: This demo uses the advanced
 * control timer Timer1 to do something not very
 * advanced at all. We set the timer to count up and
 * down, basically it oscillates between 0 and 5000 at
 * 1Khz. Each time one of the limits is hit the system
 * raises an 'Update' interrupt. We handle this
 * interrupt by toggling a LED on PF6. The net result
 * of this is that the LED flashes on and off for a
 * second in each of those states.
 *
 * If you are running this on the STM32F4DISCOVERY
 * board then you can replace all reference to PF6 with
 * PD13 to use the onboard LED on that board.
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103ZET6
 *   STM32F407VGT6
 */
class TimerInterruptsTest : public Observer {
	protected:
		enum { LED_PIN = 6 };
		/*
		 * We'll need these as member variables so that we can see them from the interrupt handler
		 */
		GpioF<DefaultDigitalOutputFeature<LED_PIN> > _pf;
		bool _ledState;
	public:
		void run() {
			/*
			 * Initialise timer1 running from the high speed internal APB2
			 * clock with an interrupt feature
			 */
			Timer1<
				Timer1InternalClockFeature,				// the timer clock source is APB2
				Timer1InterruptFeature						// gain access to interrupt functionality
			> timer;
			/*
			 * We've got a LED on PF[6] and it's active LOW. Set it up here and switch it off.
			 */
			_pf[LED_PIN].set();
			_ledState=false;
			/*
			 * Set ourselves up as an observer for interrupts raised by the timer class.
			 */
			timer.insertObserver(*this);
			/*
			 * Set an up-down-timer up to tick at 5000Hz with an auto-reload value of 5000
			 * The timer will count from 0 to 5000 inclusive, raise an Update interrupt and
			 * then go backwards back down to 0 where it'll raise another Update interrupt
			 * and start again. Each journey from one end to the other takes 1 second.
			 *
			 * Note that the lowest frequency you can set is 1098 for a 72Mhz timer clock source.
			 * This is because the maximum prescaler value is 65536 (72Mhz/65536 = 1098Hz).
			 */
			timer.setTimeBaseByFrequency(5000,4999,TIM_CounterMode_CenterAligned3);
			/*
			 * Enable just the Update interrupt.
			 */
			timer.enableInterrupts(TIM_IT_Update);
			/*
			 * Start the timer
			 */
			timer.enablePeripheral();
			/*
			 * It's all running automatically now
			 */
			for(;;);
		}
		/*
     * Observer callback function. This is called when the update interrupt that we've
     * enabled is fired.
     */
    virtual void onNotify(Observable&,ObservableEvent::E event,void *) {
      if(event==ObservableEvent::Timer_Update) {
      	/*
      	 * Toggle the LED state.
      	 */
      	_ledState^=true;
      	_pf[LED_PIN].setState(_ledState);
      }
    }
};
/*
 * Main entry point
 */
int main() {
	// we're using interrupts, initialise NVIC
	Nvic::initialise();
	TimerInterruptsTest test;
	test.run();
	// not reached
	return 0;
}
 
timer_master_slave
Click here to hide the full timer_master_slave code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/timer.h"
#include "config/dma.h"
using namespace stm32plus;
/**
 * Timer master/slave demonstration. Use one timer to
 * switch another one on and off at predefined intervals.
 *
 * Timer2 is configured as the master timer with a
 * frequency of 2000Hz and a reload value of 8000.
 * Channel 1 is configured to generate a PWM wave with a
 * 25% duty cycle. That means 1 seconds on and 3 seconds
 * off.
 *
 * Timer3 is configured as the slave timer with a
 * frequency of 2000Hz and a reload value of 200 with
 * a GPIO output toggle feature so it flashes on/off
 * 5 times per second.
 *
 * If left to run freely timer3 would flash continually
 * at 5Hz. However, attaching it as a slave to the PWM
 * wave generated by timer2 means that it will flash for
 * 1 second then switch off for 3 seconds.
 *
 * The output is generated on PA6. You can wire that
 * directly to a LED or a logic analyser to see the
 * results. My STM32F103ZET6 development board has a LED
 * on PF6 so I've wired PA6 to PF6 and enabled PF6 for
 * output in this demo code.
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103ZET6
 *   STM32F407VGT6
 */
class TimerMasterSlaveTest {
	public:
		void run() {
			/*
			 * Enable PF6 for output so we can see the output on the LED that's connected there.
			 */
			GpioF<DefaultDigitalOutputFeature<6> > pf;
			/*
			 * Create an instance of Timer2 (master) running off the internal clock with
			 * channel 1 and master features.
			 */
			Timer2<
				Timer2InternalClockFeature,					// the timer bus is APB1
				TimerChannel1Feature,								// we're going to use channel 1
				TimerOutputCompare1MasterFeature		// we're the master timer using OC1 as the trigger
			> masterTimer;
			/*
			 * Set the frequency of Timer2 to 2000Hz with a reload value
			 * of 8000.
			 */
			masterTimer.setTimeBaseByFrequency(2000,7999);
			/*
			 * Initialise channel 1's comparator for use as a PWM output with an
			 * initial duty cycle of 25%
			 */
			masterTimer.initCompareForPwmOutput(25);
			/*
			 * Create an instance of Timer3 (slave) running off the internal clock
			 * with channel 1 and unremapped GPIO output features.
			 */
			Timer3<
				Timer3InternalClockFeature,				// the timer bus is APB1
				TimerChannel1Feature,							// we're going to use channel 1
				Timer2MasterTimer3SlaveFeature<		// timer3 is a slave to timer2 (ITR1)
					TIM_SlaveMode_Gated							// gated mode - the slave counter goes on and off with the trigger
				>,
				Timer3GpioFeature<								// we want to output something to GPIO
					TIMER_REMAP_NONE,								// the GPIO output will not be remapped
					TIM3_CH1_OUT										// we will output channel 1 to GPIO
				>
			> slaveTimer;
			/*
			 * Set an up-timer up to tick at 2000Hz with an auto-reload value of 200
			 * The timer will count from 0 to 199 inclusive then reset back to 0.
			 * It will do this 10 times per second
			 *
			 * Note that the lowest frequency you can set is 1098 for a 72Mhz timer clock source.
			 * This is because the maximum prescaler value is 65536 (72Mhz/65536 = 1098Hz).
			 */
			slaveTimer.setTimeBaseByFrequency(2000,199);
			/*
			 * Initialise the channel 1 output compare value to 2000 with the default
			 * action of toggle.
			 */
			slaveTimer.initCompare(199);
			/*
			 * Enable master feature and switch the timer on. Enabling of master feature must happen
			 * after the rest of the timer has been set up (above)
			 */
			masterTimer.enableMasterFeature();
			masterTimer.enablePeripheral();
			/*
			 * Enable slave feature and switch the timer on. Enabling of slave feature must happen
			 * after the rest of the timer has been set up (above)
			 */
			slaveTimer.enableSlaveFeature();
			slaveTimer.enablePeripheral();
			/*
			 * It's all running automatically now. The on/off duration of the flashing can be controlled
			 * using the duty cycle of timer2.
			 */
			for(;;);
		}
};
/*
 * Main entry point
 */
int main() {
	TimerMasterSlaveTest test;
	test.run();
	// not reached
	return 0;
}
 
timer_pwm_gpio_out
Click here to hide the full timer_pwm_gpio_out code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/timer.h"
#include "config/timing.h"
using namespace stm32plus;
/**
 * Timer demonstration: Use timer 2 to output a 1MHz PWM
 * wave on channel 1 (PA0). The demo will repeatedly
 * increment the duty cycle from 0 to 100% and back down
 * to 0 over 800ms.
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103ZET6
 *   STM32F407VGT6
 */
class TimerPwmGpioOutTest {
	public:
		void run() {
			/*
			 * Initialise timer2 running from the internal APB2 clock with channel-1 and GPIO output features.
			 * The GPIO output feature is itself configured with a channel-1 output feature.
			 */
			Timer2<
				Timer2InternalClockFeature,				// the timer clock source is APB1
				TimerChannel1Feature,							// we're going to use channel 1
				Timer2GpioFeature<								// we want to output something to GPIO
					TIMER_REMAP_NONE,								// the GPIO output will not be remapped
					TIM2_CH1_OUT										// we will output channel 1 to GPIO
				>
			> timer;
			/*
			 * Set an up-timer up to tick at 10MHz with an auto-reload value of 1999
			 * The timer will count from 0 to 1999 inclusive then reset back to 0.
			 *
			 * Note that the lowest frequency you can set on the F1 is 1098 for a 72MHz
			 * timer clock source. This is because the maximum prescaler value is 65536
			 * (72Mhz/65536 = 1098Hz).
			 */
			timer.setTimeBaseByFrequency(10000000,1999);
			/*
			 * Initialise channel 1 as a PWM channel in edge-aligned mode (TIM_OCMode_PWM1).
			 * The default starting duty cycle is zero.
			 */
			timer.initCompareForPwmOutput();
			/*
			 * Enable the timer. The PWM output is on PA0.
			 */
			timer.enablePeripheral();
			/*
			 * It's all running automatically now, use the main CPU to vary the duty cycle up
			 * to 100% and back down again
			 */
			for(;;) {
				// fade up to 100% in 4ms steps
				for(int8_t i=0;i<=100;i++) {
					timer.setDutyCycle(i);
					MillisecondTimer::delay(4);
				}
				// fade down to 0% in 4ms steps
				for(int8_t i=100;i>=0;i--) {
					timer.setDutyCycle(i);
					MillisecondTimer::delay(4);
				}
			}
		}
};
/*
 * Main entry point
 */
int main() {
	// we need the SysTick timer
	MillisecondTimer::initialise();
	TimerPwmGpioOutTest test;
	test.run();
	// not reached
	return 0;
}
 
usart_receive_dma
Click here to hide the full usart_receive_dma code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/usart.h"
using namespace stm32plus;
/**
 * USART test: synchronous receiving data
 *
 * This example will receive 5 characters from the PC
 * over USART1 using the DMA channel and then
 * immediately echo them back, also using the DMA
 * channel.
 *
 * Connect an RS232 cable from USART1 to your PC and
 * run a terminal program (there are many free terminal
 * programs) and type 5 characters into it. Those 5
 * characters will be echo'd back to the terminal.
 *
 * Note that if you are using the STM32F4DISCOVERY board
 * then you cannot use Usart1 since the pins clash with
 * onboard peripherals. I have tested this code on that
 * board using Usart2.
 *
 * The protocol is 57600/8/N/1
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103VET6
 *   STM32F407VGT6
 */
class UsartReceiveDmaTest {
	public:
		void run() {
			/*
			 * Declare a USART1 object. Note that an alternative Usart1_Remap object is available
			 * if your application demands that you use the alternate pins for USART1
			 */
			Usart1<> usart(57600);
			Usart1TxDmaChannel<UsartDmaWriterFeature<Usart1PeripheralTraits> > dmaWriter;
			Usart1RxDmaChannel<UsartDmaReaderFeature<Usart1PeripheralTraits> > dmaReader;
			/*
			 * Go into a loop reading 5 characters at a time and then writing them
			 * right back again.
			 */
			for(;;) {
				uint8_t buffer[5];
				dmaReader.beginRead(buffer,sizeof(buffer));
				dmaReader.waitUntilComplete();
				dmaWriter.beginWrite(buffer,sizeof(buffer));
				dmaWriter.waitUntilComplete();
			}
		}
};
/*
 * Main entry point
 */
int main() {
	UsartReceiveDmaTest test;
	test.run();
	// not reached
	return 0;
}
 
usart_receive_interrupts
Click here to hide the full usart_receive_interrupts code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/usart.h"
using namespace stm32plus;
/**
 * USART test: asynchronous sending and receiving data
 * using interrupts
 *
 * This example will receive 5 characters on USART1 and
 * then immediately echo them back. Connect an RS232
 * cable from USART1 to your PC and run a terminal
 * program (there are many free terminal programs) to
 * see the data. The default (unremapped) USART1 pins
 * are used.
 *
 * We use interrupts to send and receive the data. The
 * hardware raises a TXE interrupt when it's ready to
 * send a character and an RXNE interrupt when data is
 * ready to receive.
 *
 * Note that if you are using the STM32F4DISCOVERY board
 * then you cannot use Usart1 since the pins clash with
 * onboard peripherals. I have tested this code on that
 * board using Usart2.
 *
 * The protocol is 57600/8/N/1
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103VET6
 *   STM32F407VGT6
 */
class UsartReceiveInterruptsTest : public Observer {
	protected:
		/*
		 * We'll use this as our simple I/O buffer
		 */
		uint8_t _buffer[5];
		uint8_t _index;
		/*
		 * The USART1 peripheral configured with the interrupt feature
		 */
		typedef Usart1InterruptFeature MyUsartInterrupt;
		Usart1<MyUsartInterrupt> _usart;
	public:
		/*
		 * Use the constructor base initialiser to set up the USART at 57600
		 */
		UsartReceiveInterruptsTest()
			:_usart(57600) {
		}
		/*
		 * Run the test
		 */
		void run()  {
			/*
			 * We're using interrupts, set up the NVIC
			 */
			Nvic::initialise();
			// register ourselves as an observer of the USART interrupts
			_usart.insertObserver(*this);
			// enable the receive interrupt. this will start the whole chain of events
			_index=0;
			_usart.enableInterrupts(MyUsartInterrupt::RECEIVE);
			// it's all going on in the background now. wish us luck :)
			for(;;);
		}
		/*
		 * Observer callback function. This is called when the TXE interrupt that we've
		 * enabled is fired.
		 */
		virtual void onNotify(Observable&,ObservableEvent::E event,void *) {
			if(event==ObservableEvent::USART_Receive) {
				// receive the next character
				_buffer[_index++]=_usart.receive();
				// if we've got the 5 characters then disable receiving interrupts
				// and enable sending
				if(_index==5) {
					_index=0;
					_usart.disableInterrupts(MyUsartInterrupt::RECEIVE);
					_usart.enableInterrupts(MyUsartInterrupt::TRANSMIT);
				}
			}
			else if(event==ObservableEvent::USART_ReadyToTransmit) {
				// send the next character
				_usart.send(_buffer[_index++]);
				// if we've sent back all 5 then disable sending interrupts and go back
				// to receiving again
				if(_index==5) {
					_index=0;
					_usart.disableInterrupts(MyUsartInterrupt::TRANSMIT);
					_usart.enableInterrupts(MyUsartInterrupt::RECEIVE);
				}
			}
		}
};
/*
 * Main entry point
 */
int main() {
	UsartReceiveInterruptsTest test;
	test.run();
	// not reached
	return 0;
}
 
usart_receive_sync
Click here to hide the full usart_receive_sync code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/usart.h"
using namespace stm32plus;
/**
 * USART test: synchronous receiving data
 *
 * This example will receive 5 characters from the PC
 * over USART1 and then immediately echo them back.
 * Connect an RS232 cable from USART1 to your PC and
 * run a terminal program (there are many free terminal
 * programs) and type 5 characters into it. Those
 * 5 characters will be echo'd back to the terminal.
 *
 * Note that if you are using the STM32F4DISCOVERY
 * board then you cannot use Usart1 since the pins
 * clash with onboard peripherals. I have tested
 * this code on that board using Usart2 and Uart4.
 *
 * The protocol is 57600/8/N/1
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103VET6
 *   STM32F407VGT6
 */
class UsartReceiveSyncTest {
	public:
		void run() {
			/*
			 * Declare a USART1 object. Note that an alternative Usart1_Remap object is available
			 * if your application demands that you use the alternate pins for USART1
			 */
			Usart1<> usart(57600);
			/*
			 * We'll use streams to send and receive the data.
			 */
			UsartPollingOutputStream outputStream(usart);
			UsartPollingInputStream inputStream(usart);
			/*
			 * Go into a loop reading 5 characters at a time and then writing them
			 * right back again.
			 */
			for(;;) {
				uint8_t buffer[5];
				uint32_t actuallyRead;
				if(!inputStream.read(buffer,sizeof(buffer),actuallyRead) || actuallyRead!=sizeof(buffer)) {
					// read error: handle it here
				}
				if(!outputStream.write(buffer,sizeof(buffer))) {
					// write error: handle it here
				}
			}
		}
};
/*
 * Main entry point
 */
int main() {
	UsartReceiveSyncTest test;
	test.run();
	// not reached
	return 0;
}
 
usart_send_dma
Click here to hide the full usart_send_dma code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/usart.h"
using namespace stm32plus;
/**
 * USART test: sending data using the DMA peripheral
 *
 * This example will send the string "Hello World"
 * using the DMA peripheral assigned to USART1. USART1
 * is using standard, unremapped pins.
 *
 * Note that if you are using the STM32F4DISCOVERY
 * board then you cannot use Usart1 since the pins
 * clash with onboard peripherals. I have tested this
 * code on that board using Usart2.
 *
 * The protocol is 57600/8/N/1
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103VET6
 *   STM32F407VGT6
 */
class UsartSendDmaTest {
	public:
		void run() {
			const char *dataToSend="Hello World";
			/*
			 * Declare a USART1 object. Note that an alternative Usart1_Remap object is available
			 * if your application demands that you use the alternate pins for USART1. Include the
			 * feature class for writing to the USART over DMA.
			 */
			Usart1<> usart(57600);
			/*
			 * Attach the correct DMA channel to this USART. The DMA channel has a writer feature
			 * attached to it, and that writer feature takes a template parameter of the USART
			 * peripheral so it knows where it's going to be writing to.
			 */
			Usart1TxDmaChannel<UsartDmaWriterFeature<Usart1PeripheralTraits> > dma;
			/*
			 * Write out the test string and wait for completion
			 */
			dma.beginWrite(dataToSend,strlen(dataToSend));
			dma.waitUntilComplete();
			for(;;);
		}
};
/*
 * Main entry point
 */
int main() {
	UsartSendDmaTest test;
	test.run();
	// not reached
	return 0;
}
 
usart_send_dma_interrupts
Click here to hide the full usart_send_dma_interrupts code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/usart.h"
using namespace stm32plus;
/**
 * USART test: asynchronous sending multiple sequences of
 * data using DMA to transfer it and using DMA interrupts
 * to move through the sequence of data items to transfer
 *
 * This example will send the first few words from the
 * famous Lorem Ipsum quotation using USART1. Connect an
 * RS232 cable from USART1 to your PC and run a terminal
 * program (there are many free terminal programs) to see
 * the data. The default (unremapped) USART1 pins are used.
 *
 * The DMA channel associated with USART1 Tx is set up and
 * triggered. When the first transfer is complete an
 * interrupt fires and we use to initiate the next
 * transfer. When all transfers are complete we lock up.
 *
 * Note that if you are using the STM32F4DISCOVERY board
 * then you cannot use Usart1 since the pins clash with
 * onboard peripherals. I have tested this code on that
 * board using Usart2.
 *
 * The protocol is 57600/8/N/1
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103VET6
 *   STM32F407VGT6
 */
static const char *_loremIpsum[]={
  "Lorem ","ipsum ","dolor ","sit amet, ","consectetur ","adipisicing ","elit, ","sed ","do ",
  "eiusmod ","tempor ","incididunt ","ut ","labore ","et ","dolore ","magna ","aliqua."
};
class UsartSendInterruptsTest : public Observer {
	protected:
		/*
		 * The index of the string that we are sending
		 */
		uint8_t _currentlySending;
    /*
     * The DMA peripheral appropriate for this USART, configured for transmitting
     */
		typedef Usart1TxDmaChannel<              					// use the correct channel
      UsartDmaWriterFeature<Usart1PeripheralTraits>,   // we will be writing to it
      Usart1TxDmaChannelInterruptFeature     					// we want its interrupts to fire
    > MyUsartTxDmaChannel;
		MyUsartTxDmaChannel *_dma;
	public:
		/*
		 * Run the test
		 */
		void run()  {
			/*
			 * We're using interrupts, set up the NVIC
			 */
			Nvic::initialise();
			/*
			 * Declare a USART1 object. Note that an alternative Usart1_Remap object is available
			 * if your application demands that you use the alternate pins for USART1. Include the
			 * feature class for writing to the USART over DMA.
			 */
			Usart1<> usart(57600);
			// declare the DMA channel for the USART. Must come after the USART peripheral is set up.
			_dma=new MyUsartTxDmaChannel();
			// enable interrupts and set ourselves up to observe them
			_dma->enableInterrupts(Usart1TxDmaChannelInterruptFeature::COMPLETE);
			_dma->insertObserver(*this);
			// start the first transfer
			_currentlySending=0;
			_dma->beginWrite(_loremIpsum[0],strlen(_loremIpsum[0]));
			// it's in the background from now on
			for(;;);
		}
		/*
		 * Observer callback function. This is called when the completion
		 * interrupt that we've enabled is fired.
		 */
		virtual void onNotify(Observable& sender,ObservableEvent::E event,void *) {
			(void)sender;
			if(event==ObservableEvent::DMA_TransferComplete) {
			  // update to the next word
			  _currentlySending++;
			  // only start another if there is more to go
			  if(_currentlySending<sizeof(_loremIpsum)/sizeof(_loremIpsum[0])) {
			    // clear the completion flag and send the next word
			  	_dma->clearCompleteFlag();
			    _dma->beginWrite(_loremIpsum[_currentlySending],strlen(_loremIpsum[_currentlySending]));
			  }
			}
		}
};
/*
 * Main entry point
 */
int main() {
	UsartSendInterruptsTest test;
	test.run();
	// not reached
	return 0;
}
 
usart_send_interrupts
Click here to hide the full usart_send_interrupts code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/usart.h"
using namespace stm32plus;
/**
 * USART test: asynchronous sending data using interrupts
 *
 * This example will send the string "Hello World" using
 * USART1. Connect an RS232 cable from USART1 to your PC
 * and run a terminal program (there are many free
 * terminal programs) to see the data. The default
 * (unremapped) USART1 pins are used.
 *
 * We use interrupts to send the data. The hardware
 * raises a TXE interrupt when it's ready to send a
 * character and we do just that. When we get to the end
 * of the string we disable the TXE interrupt so it
 * doesn't fire again.
 *
 * Note that if you are using the STM32F4DISCOVERY
 * board then you cannot use Usart1 since the pins clash
 * with onboard peripherals. I have tested this code on
 * that board using Usart2.
 *
 * The protocol is 57600/8/N/1
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103VET6
 *   STM32F407VGT6
 */
class UsartSendInterruptsTest : public Observer {
	protected:
		/*
		 * The string we are going to send
		 */
		const char *_dataToSend;
		/*
		 * The USART1 peripheral configured with the interrupt feature
		 */
		typedef Usart1InterruptFeature MyUsartInterrupt;
		Usart1<MyUsartInterrupt> _usart;
	public:
		/*
		 * Use the constructor base initialiser to set up the USART at 57600
		 */
		UsartSendInterruptsTest()
			: _usart(57600) {
		}
		/*
		 * Run the test
		 */
		void run()  {
			// we're using interrupts, set up the NVIC
			Nvic::initialise();
			// set the initial string pointer
			_dataToSend="Hello World";
			// register ourselves as an observer of the USART interrupts
			_usart.insertObserver(*this);
			// enable interrupts. this will cause an immediate ready-to-send interrupt
			_usart.enableInterrupts(MyUsartInterrupt::TRANSMIT);
			// finished
			for(;;);
		}
		/*
		 * Observer callback function. This is called when the TXE interrupt that we've
		 * enabled is fired.
		 */
		virtual void onNotify(Observable&,ObservableEvent::E event,void *) {
			if(event==ObservableEvent::USART_ReadyToTransmit && *_dataToSend) {
				// send the next character and increment the pointer
				_usart.send(*_dataToSend++);
				// if we are now at the end of the string then disable further interrupts
				// because we are done
				if(*_dataToSend=='\0')
					_usart.disableInterrupts(MyUsartInterrupt::TRANSMIT);
			}
		}
};
/*
 * Main entry point
 */
int main() {
	UsartSendInterruptsTest test;
	test.run();
	// not reached
	return 0;
}
 
usart_send_sync
Click here to hide the full usart_send_sync code
/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */
#include "config/stm32plus.h"
#include "config/usart.h"
using namespace stm32plus;
/**
 * USART test: synchronous sending data
 *
 * This example will send the string "Hello World" using
 * USART1. Connect an RS232 cable from USART1 to your PC
 * and run a terminal program (there are many free
 * terminal programs) to see the data. The default
 * (unremapped) USART1 pins are used.
 *
 * Note that if you are using the STM32F4DISCOVERY board
 * then you cannot use Usart1 since the pins clash with
 * onboard peripherals. I have tested this code on that
 * board using Usart2.
 *
 * The protocol is 57600/8/N/1
 *
 * Compatible MCU:
 * 	 STM32F1
 * 	 STM32F4
 *
 * Tested on devices:
 *   STM32F103VET6
 *   STM32F407VGT6
 */
class UsartSendSyncTest {
	public:
		void run() {
			const char *dataToSend="Hello World";
			/*
			 * Declare a USART1 object. Note that an alternative Usart1_Remap object is available
			 * if your application demands that you use the alternate pins for USART1
			 */
			Usart1<> usart(57600);
			/*
			 * For kicks we'll use an output stream for sending to the port instead of using the
			 * send(uint8_t) method on the usart object
			 */
			UsartPollingOutputStream outputStream(usart);
			/*
			 * Send the data
			 */
			if(!outputStream.write(dataToSend,strlen(dataToSend))) {
				// error handling would go here
			}
			// finished
			for(;;);
		}
};
/*
 * Main entry point
 */
int main() {
	UsartSendSyncTest test;
	test.run();
	// not reached
	return 0;
}