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;
}