Iam looking for someone who could help me write a bit of code that uses a teensy 2.0 ++ so that it will send instructions to a 8253 programmable interval timers to output square waves at different frequencies on each of the three internal timers. Its a pretty out dated chip so im having trouble understanding how to interface with it and send instructions. Im hoping to write a bigger program for the 8253 and ive read all the resources i can find on them but im having trouble with just the basics and getting started. Any thoughts or help would be great. Thanks!
This looks like a dubbel posted question. Ask moderator to move the question to the best section.
Without going into too much detail, it looks like you need to setup Mode 3 on each of the counters…
What frequencies are you looking for ?
What clock source are you going to use?
Setting the registers shouldn’t be too hard, with the CS, WR, and 8-bit data byte to write into the chip.
You are also going to need a couple of shift registers if you can't afford to use 8 pins for the data bits since the device uses an 8 bit "bus"
Yes I believe the mode three is the continuous square wave mode. i will being using dozens of different frequencies in my final code so itll be a lot to write out but a little show of how you assign the frequencies would be helpful. I will be using a 1.902 mhz clock for the counter clock inputs
THIS has some examples, and a description of working with the 8253. As long as you sort out your hardware and clock, the rest should be pretty straightforward.
The trick will be developing the simplest user interface to control your three separate frequency selections.
Haha Yes i have read that page before. It is not as straight forward seeming to me but it is also my first time diving into something like this so forgive me. I understand as a starter CS will set low, A0 A1 will be set low to select counter 0, WR will be set low while sending control works. But then the control word process is where i get lost.
You can try the following. It compiles but isn't tested.
It assumes the use of an HC595 shift register to hold the D0..7 parallel data to to the 8253 (to save Teensy pins.) If you prefer to use parallel and have the pins available it'd be easy to switch it over.
All it does is send different count values to each of the three timers in the 8253 to produce different square wave. You can use a scope to see if it worked.
/*
* Sketch: sketch_oct12c.ino
* Target: Teensy 2.0++
*
* Drives HC595 serial shift register and 8253 to
* (hopefully!) demonstrate loading timers to produce
* square waves.
*/
typedef enum
{
COUNTER0 = 0, //00
COUNTER1, //01
COUNTER2, //10
WR_MODE_WORD //11
}e8253_ADDRS_t;
//shift register pins
const uint8_t pinStrobe = 8; //ST_CP of HC595
const uint8_t pinClock = 12; //SH_CP of HC595
const uint8_t pinData = 11; //DS of HC595
const uint8_t pinCS = 2; //to 8253 chip-select
const uint8_t pinA0 = 3;
const uint8_t pinA1 = 4;
const uint8_t pinRD = 5;
const uint8_t pinWR = 6;
uint8_t timerData;
uint16_t timerValue;
void setup()
{
//set up GPIOs
pinMode( pinStrobe, OUTPUT );
pinMode( pinCS, OUTPUT );
pinMode( pinA0, OUTPUT );
pinMode( pinA1, OUTPUT );
pinMode( pinRD, OUTPUT );
pinMode( pinWR, OUTPUT );
digitalWrite( pinStrobe, HIGH );
digitalWrite( pinCS, HIGH );
digitalWrite( pinWR, HIGH );
digitalWrite( pinRD, HIGH );
//counter 0
timerData = 0b00110110; //counter 0, load least then most, Mode 3, binary count
timerValue = 0x7fff;
Write8253( WR_MODE_WORD, timerData );
Write8253( COUNTER0, (uint8_t)(timerValue & 0x00ff) );
Write8253( COUNTER0, (uint8_t)((timerValue >> 8) & 0x00ff) );
//counter 1
timerData = 0b01110110; //counter 1, load least then most, Mode 3, binary count
timerValue = 0xfff5;
Write8253( WR_MODE_WORD, timerData );
Write8253( COUNTER1, (uint8_t)(timerValue & 0x00ff) );
Write8253( COUNTER1, (uint8_t)((timerValue >> 8) & 0x00ff) );
//counter 2
timerData = 0b10110110; //counter 2, load least then most, Mode 3, binary count
timerValue = 0x1000;
Write8253( WR_MODE_WORD, timerData );
Write8253( COUNTER2, (uint8_t)(timerValue & 0x00ff) );
Write8253( COUNTER2, (uint8_t)((timerValue >> 8) & 0x00ff) );
}//setup
void loop()
{
//nothing to do in loop
}//loop
void Write8253( uint8_t address, uint8_t dataval )
{
//shift data byte out to HC595 shift register
digitalWrite( pinStrobe, LOW );
shiftOut( pinData, pinClock, LSBFIRST, dataval );
digitalWrite( pinStrobe, HIGH );
//set address pins
digitalWrite( pinA0, (address & 0x01) ? HIGH:LOW );
digitalWrite( pinA1, (address & 0x02) ? HIGH:LOW );
//wiggle CS and WR to send to 8253
digitalWrite( pinCS, LOW ); //set chip select
delayMicroseconds( 10 ); //wait >> Taw
digitalWrite( pinWR, LOW ); //assert WR low
delayMicroseconds( 10 ); //wait >> Tww
digitalWrite( pinWR, HIGH ); //de-assert WR
delayMicroseconds( 10 ); //wait >> Twa
digitalWrite( pinCS, HIGH ); //de-assert CS
}//Write8253
OOoooh Man! Thank you so much! this is amazing! and soo helpful. and saves me from posting my embarrassing code attempt haha. Im bread boarding it right now to see if i can get it work. I actually wont be using a shift register so i will try to figure out how I can modify the code you provided. Seriously thank you a million times!
Here's an attempt at a parallel version. It uses all of port 'C' for the data bus and uses direct port manipulation for simplicity.
Because the use of a parallel I/O port allows reading I added that functionality too (untested!)
/*
* Sketch: sketch_oct13c.ino
* Target: Teensy 2.0++
*
* Uses parallel data for the 8253 to
* (hopefully!) demonstrate loading timers
* to produce square waves.
*/
typedef enum
{
COUNTER0 = 0, //00
COUNTER1, //01
COUNTER2, //10
WR_MODE_WORD //11
}e8253_ADDRS_t;
//parallel data to 8253
const uint8_t pinD0 = 10; //PORTC0 declarations for clarity only
const uint8_t pinD1 = 11; //...
const uint8_t pinD2 = 12;
const uint8_t pinD3 = 13;
const uint8_t pinD4 = 14;
const uint8_t pinD5 = 15;
const uint8_t pinD6 = 16;
const uint8_t pinD7 = 17; //PORTC7
const uint8_t pinCS = 2; //to 8253 chip-select
const uint8_t pinA0 = 3; //address A0
const uint8_t pinA1 = 4; //address A1
const uint8_t pinRD = 5; //!read
const uint8_t pinWR = 6; //!write
uint8_t timerData;
uint16_t timerValue;
void setup()
{
//set data direction to input initially
DDRC = 0x00;
PORTC = 0x00;
pinMode( pinCS, OUTPUT );
pinMode( pinA0, OUTPUT );
pinMode( pinA1, OUTPUT );
pinMode( pinRD, OUTPUT );
pinMode( pinWR, OUTPUT );
digitalWrite( pinCS, HIGH );
digitalWrite( pinWR, HIGH );
digitalWrite( pinRD, HIGH );
//counter 0
timerData = 0b00110110; //counter 0, load least then most, Mode 3, binary count
timerValue = 0x7fff;
Write8253( WR_MODE_WORD, timerData );
Write8253( COUNTER0, (uint8_t)(timerValue & 0x00ff) );
Write8253( COUNTER0, (uint8_t)((timerValue >> 8) & 0x00ff) );
//counter 1
timerData = 0b01110110; //counter 1, load least then most, Mode 3, binary count
timerValue = 0xfff5;
Write8253( WR_MODE_WORD, timerData );
Write8253( COUNTER1, (uint8_t)(timerValue & 0x00ff) );
Write8253( COUNTER1, (uint8_t)((timerValue >> 8) & 0x00ff) );
//counter 2
timerData = 0b10110110; //counter 2, load least then most, Mode 3, binary count
timerValue = 0x1000;
Write8253( WR_MODE_WORD, timerData );
Write8253( COUNTER2, (uint8_t)(timerValue & 0x00ff) );
Write8253( COUNTER2, (uint8_t)((timerValue >> 8) & 0x00ff) );
}//setup
void loop()
{
//nothing to do in loop
//for this proof of concept
}//loop
void Write8253( uint8_t address, uint8_t dataval )
{
//set databus
PORTC = dataval; //set databus value
DDRC = 0xff; //and drive to pins (make pins outputs)
//set 8253 address pins
digitalWrite( pinA0, (address & 0x01) ? HIGH:LOW );
digitalWrite( pinA1, (address & 0x02) ? HIGH:LOW );
//wiggle CS and WR to send to 8253
digitalWrite( pinCS, LOW ); //set chip select
delayMicroseconds( 10 ); //wait >> Taw
digitalWrite( pinWR, LOW ); //assert WR low
delayMicroseconds( 10 ); //wait >> Tww
digitalWrite( pinWR, HIGH ); //de-assert WR
delayMicroseconds( 10 ); //wait >> Twa
digitalWrite( pinCS, HIGH ); //de-assert CS
//set databus back to default HiZ input state
DDRC = 0x00;
}//Write8253
uint16_t Read8253( uint8_t counter )
{
//we can only read counters, not the mode register
if( counter > 2 )
return 0x0000;
//write a mode word that latches the count for the desired counter
uint8_t mask = (counter & 0x03) << 6; //set SC1:0 to counter address, RL1:0 low
Write8253( WR_MODE_WORD, mask ); //write latches counter value for read
//issue two reads to get the latched counter value (LSB read first)
return( ReadByte(counter) + (ReadByte(counter) << 8) );
}//Read8253
uint8_t ReadByte( uint8_t address )
{
//set the address pins
digitalWrite( pinA0, (address & 0x01) ? HIGH:LOW );
digitalWrite( pinA1, (address & 0x02) ? HIGH:LOW );
digitalWrite( pinCS, LOW ); //assert chip select low
delayMicroseconds( 10 ); //wait >> Tar
digitalWrite( pinRD, LOW ); //assert RD low
delayMicroseconds( 10 ); //wait >> Trr
digitalWrite( pinRD, HIGH ); //de-assert RD and read the byte from the bus
uint8_t mask = PINC;
delayMicroseconds( 10 ); //wait >> Twa
digitalWrite( pinCS, HIGH ); //de-assert CS
return mask;
}//ReadByte
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.