Vous êtes sur la page 1sur 8

/* Audio.c -- This file implements an audio module to drive the Sparkfun WIG13720.

It accepts ES_Event type events in order to start MP3 tracks


and modify the audio volume.
History
When
Who
-------------- --11/13/16 04:12 rmc

What/Why
-------Created

*/
/*
*****************************************************************************/
/*----------------------------- Include Files -----------------------------*/
/* include header files for the framework and this service
*/
#include "ES_Configure.h"
#include "ES_Framework.h"
#include "ES_DeferRecall.h"
#include "ES_ShortTimer.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include

"inc/hw_memmap.h"
"inc/hw_types.h"
"inc/hw_gpio.h"
"inc/hw_sysctl.h"
"driverlib/sysctl.h"
"driverlib/pin_map.h" // Define PART_TM4C123GH6PM in project
"driverlib/gpio.h"
"driverlib/timer.h"
"driverlib/interrupt.h"

//Include header file for needed files in this module


#include "Audio.h"
//Additional includes and definitions
#include "BITDEFS.H"
#include "termio.h"
#define ALL_BITS (0xff<<2) //declare ALL_BITS macro to access all 8 bits on
the port at once
#define AUDIOPORT SYSCTL_RCGCGPIO_R3 //we'll use port D
#define AUDIOSHIFT BIT0HI //use pins 0,1,2 on Port D for ShiftClock,
StoreClock and Data, respectively.
#define AUDIOREGISTER BIT1HI
#define AUDIODATA BIT2HI
#define SHIFTLO BIT0LO
#define SHIFTHI BIT0HI
#define REGISTERLO BIT1LO
#define REGISTERHI BIT1HI
#define DATALO BIT2LO
#define DATAHI BIT2HI

#define TRACK1 0x00000001

#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define

TRACK2 0x00000002
TRACK3 0x00000004
TRACK4 0x00000008
TRACK5 0x00000010
TRACK6 0x00000020
TRACK7 0x00000040
TRACK8 0x00000080
TRACK9 0x00000100
TRACK10 0x00000200
TRACK11 0x00000400
TRACK12 0x00000800
TRACK13 0x00001000
TRACK14 0x00002000
TRACK15 0x00004000
TRACK16 0x00008000
TRACK17 0x00010000 //change to volume up?
TRACK18 0x00020000 //change to volume down?
ALLZEROS 0x00000000 //to reset pins to zero after an activation

//Module variables
//************************************
static uint8_t MyPriority; //the priority of the Audio service
static bool noInterrupts = false; //if true, don't allow tracks to interrupt
the current track
//************************************
//Helper Functions
static void SR_Write3Bytes(uint32_t trackToPlay);
static void SR_Shift1Byte(uint8_t byteToShift);
static void SR_StoreAllBytes(void);
//************************************
/****************************************************************************
Function
InitializeAudio
Parameters
uint8_t Priority = the priority of this module, needed for the posting
service.
Returns

bool initializeOK = a bool indicating if initialization was


successful (true) or not (false).
Description

Initializes the Audio module. Activates the port, sets the


data, shift, and register pins as I/O outputs.
Notes
Author
Robert Carrera, 11/13/2016
****************************************************************************/
bool InitializeAudio(uint8_t Priority) {
MyPriority = Priority;
bool initializeOK = true; //assume no errors

HWREG(SYSCTL_RCGCGPIO) |= AUDIOPORT; //enable the port clock for the


audioport
while ((HWREG(SYSCTL_PRGPIO) & AUDIOPORT) != AUDIOPORT){} //wait until
the audioport clock is initialized
// Initialize the Data, Shift, and Register pins as digital
outputs

HWREG(GPIO_PORTD_BASE+GPIO_O_DEN) |=(DATAHI | SHIFTHI | REGISTERHI);


// enable Data, Shift, and Register pins on port F as digital I/Os
HWREG(GPIO_PORTD_BASE+GPIO_O_DIR) |=(DATAHI | SHIFTHI | REGISTERHI);
// specify that the Data, Shift, and Register pins are an output (high =
output)
return initializeOK;
}
/****************************************************************************
Function
PostAudioService
Parameters
module

ES_Event ThisEvent - an event that was posted to the Audio

Returns
bool = a bool indicating if the event was successfully posted
to the ES framework (true) or not (false)
Description
Notes

The event posting function for the Audio module

Author
Robert Carrera, 11/13/2016
****************************************************************************/
bool PostAudioService( ES_Event ThisEvent ){
return ES_PostToService(MyPriority, ThisEvent);
}

/****************************************************************************
Function
RunAudio
Parameters
ES_Event ThisEvent - an event pulled off the queue of the
Audio service, that should be responded to
Returns
ES_Event = an event indicating if the run function was
successfully executed (true if ES_NO_EVENT is returned)
Description
The main run function for the Audio module

Notes
Calls SR_Write3Bytes
Author
Robert Carrera, 11/13/2016
****************************************************************************/
ES_Event RunAudio(ES_Event ThisEvent){
ES_Event newEvent; //return value
newEvent.EventType = ES_NO_EVENT; //assume no errors+--+++++++++++++++
+++++++++
uint32_t trackToPlay = 0;
static uint32_t trackToPlay2 = 0; //a second track to play when a
second track timer expires
if(ThisEvent.EventType == ES_OPEN){ //if the curtains have opened
trackToPlay = TRACK1; //play the main theme that plays
throughout the story. It should be several minutes long.
}else if (ThisEvent.EventType == ES_WIND){ //if the wind is blowing
and triggers a wind event
//printf("ES_WIND event received by audio");
trackToPlay = TRACK2; //play a wind sound effect.
//may want to also control volume based on wind speed
} else if (ThisEvent.EventType == ES_LIGHTNING){ //if the wind is
blowing fast enough to trigger a lightning event
//printf("ES_LIGHTNING event received by audio");
trackToPlay = TRACK5; //play a lightning sound effect.
noInterrupts = true; // we don't want the lightning to
be interrupted immediately by ongoing wind events or other lightning events
SR_Write3Bytes(trackToPlay); //we'll send the track to play
directly to circumvent the fact that noInterrupts is true
uint16_t AudioTimeout = 2000; //how long to wait until we kill
track [ms]
ES_Timer_InitTimer(AUDIO_KILLTIMER, AudioTimeout); //set timer
to kill track
} else if (ThisEvent.EventType == ES_PLANTGROWN){ //if a plant has
detected the sun and grows
trackToPlay = TRACK7; //play a growing plant sound effect.
uint16_t AudioTimeout = 1200; //how long to wait until we kill
track [ms]
ES_Timer_InitTimer(AUDIO_KILLTIMER, AudioTimeout); //set timer
to kill track
} else if(ThisEvent.EventType == ES_GROW){ //if the wind scene is over
//printf("ES_GROW event received by audio");
trackToPlay = TRACK3; //play heavy rain.
uint16_t secondTrackTime = 2000; //how long to wait until we
interrupt the first track with the second track [ms]
ES_Timer_InitTimer(AUDIO_SECONDTRACKTIMER, secondTrackTime);
//Initialize the second track to interrupt this one
trackToPlay2 = TRACK6; //transition to a light fading rain,
after second track timer expires
} else if (ThisEvent.EventType == ES_TIMEOUT && ThisEvent.EventParam
== AUDIO_KILLTIMER){ //if a kill audio timer has timed out
SR_Write3Bytes(ALLZEROS); //kill any audio playing

noInterrupts = false; //again allow track interrupts


} else if (ThisEvent.EventType == ES_TIMEOUT && ThisEvent.EventParam
== AUDIO_SECONDTRACKTIMER){ //if a second track timer has timed out
printf("/n/rsecond track timer timed out. Value: %d",
trackToPlay2);
trackToPlay = trackToPlay2; //play the second track, specified
in the module-level variable trackToPlay2
uint16_t AudioTimeout; //how long to wait until we kill track
[ms].
if(trackToPlay2 == TRACK8){ //for the hooray sound effect
AudioTimeout = 2000;
//noInterrupts = true; //this is a notification sound,
so interrupts are not allowed
//SR_Write3Bytes(trackToPlay); //we'll send the track
to play directly to circumvent the fact that noInterrupts is true
} else if(trackToPlay2 == TRACK11){ //for the owl hoot sound
effect
AudioTimeout = 5000;
} else if(trackToPlay2 == TRACK6){ //for the light rain sound
effect
AudioTimeout = 2000;
//noInterrupts = true; //this is a notification sound,
so interrupts are not allowed
//SR_Write3Bytes(trackToPlay); //we'll send the track
to play directly to circumvent the fact that noInterrupts is true
} else { //a default value
AudioTimeout = 2000;
}
ES_Timer_InitTimer(AUDIO_KILLTIMER, AudioTimeout); //set a
timer to kill the second track
saved

}else if (ThisEvent.EventType == ES_CONSTRUCTION){ //if the village is

uint16_t secondTrackTime = 2000; //by calling second track


without setting the first, we effectively have created a delay to start the
track [ms]
ES_Timer_InitTimer(AUDIO_SECONDTRACKTIMER, secondTrackTime);
//Initialize the delay (second track) timer
trackToPlay2 = TRACK8; //play a hooray sound effect when the
delay timer expires
} else if (ThisEvent.EventType == ES_NIGHTFALL){ //if night has begun
trackToPlay = TRACK10; //play a cricket sound effect
uint16_t secondTrackTime = 12000; //by calling second track
without setting the first, we effectively have created a delay to start the
track [ms]
ES_Timer_InitTimer(AUDIO_SECONDTRACKTIMER, secondTrackTime);
//Initalize the delay (second track) timer
trackToPlay2 = TRACK11; //play an owl hooting sound effect
when the delay timer expires
} else if (ThisEvent.EventType == ES_RESET){ //if the village is saved
SR_Write3Bytes(TRACK17); //play a blank track to cut current
track short
//SR_Write3Bytes(ALLZEROS); //kill any audio playing
noInterrupts = false; // again allow track interrupts

track (zero)

trackToPlay = 0; // re-initialize the track to play to no

trackToPlay2 = 0; // re-initialize the second track to play to


no track (zero);
}
if((trackToPlay != 0) && (noInterrupts == false)){ //if a track has
been selected to play and interrupts are currently allowed
//printf("audio sent track to SRs");
printf("Playing Track: %d", trackToPlay);
SR_Write3Bytes(trackToPlay); //activate the selected track to
play
}
return newEvent;
}
/****************************************************************************
Function
SR_Write3Bytes
Parameters

uint32_t trackToPlay - a track to play, or a volume up/down

command
Returns

none

Description
Sends the track command, specified as the first 18 bits of the
uint32_t trackToPlay,
to the appropriate Audio shift registers (3 daisy-chained
shift registers). Posts in the appropriate order,
with the 8 MSBs sent to the SRs first, then the next 8 MSBs,
and finally the last 8 MSBs.
Notes
Calls the function SR_Write1Byte
Author
Robert Carrera, 11/13/2016
****************************************************************************/
static void SR_Write3Bytes(uint32_t trackToPlay){
uint32_t shiftFirstByte = 16;
uint32_t shiftSecondByte = 8;
uint8_t firstByteMask = 0xff;
uint32_t firstByteIn;
uint32_t secondByteIn;
uint32_t thirdByteIn;
firstByteIn = trackToPlay >> shiftFirstByte;
secondByteIn = trackToPlay >> shiftSecondByte;
thirdByteIn = (trackToPlay & firstByteMask);
//printf("first byte: %x\n\r", firstByteIn);
//printf("second byte: %x\n\r", secondByteIn);
//printf("third byte: %x\n\r", thirdByteIn);
//Below I should write 3 bytes to the shift register. May want another
helper function below that writes

//one byte, and call it 3 times


SR_Shift1Byte(firstByteIn);
SR_Shift1Byte(secondByteIn);
SR_Shift1Byte(thirdByteIn);
SR_StoreAllBytes();
}
/****************************************************************************
Function
SR_Shift1Byte
Parameters
uint8_t byteToShift - a single byte to be shifted to the
daisychained audio shift registers.
Returns
none
Description

Shifts a single byte to the daisychained audio shift

registers.
Notes
Lowers the REGISTER clock before writing, but does NOT raise the REGISTER
clock. Must
call SR_StoreAllBytes to write the loaded bytes onto the SR
output pins.
Author
Robert Carrera, 11/13/2016
****************************************************************************/
static void SR_Shift1Byte(uint8_t byteToShift){
uint8_t BitCounter; //loop variable, represents number of passed in
bits at end of current loop
uint8_t shiftMSBToLSB = 7; //amount to shift to get MSB to LSB
position
uint8_t LocalRegisterImage = byteToShift; // save a local copy
HWREG(GPIO_PORTD_BASE+(GPIO_O_DATA + ALL_BITS)) &= REGISTERLO; //turn
register (store) low before shifting in data
uint8_t MSBmask = 0x80; //create a mask to isolate the MSB in our 8bit input NewValue
uint8_t MSB; //will store the MSB, which will be shifted out
// shift out the data while pulsing the serial clock
for(BitCounter = 1; BitCounter<9; BitCounter = BitCounter+1) {// pass
in a bit to the SR for each value of i
// Isolate the MSB of NewValue, put it into the LSB position
and output
MSB = (LocalRegisterImage & MSBmask) >> shiftMSBToLSB; //get
the current MSB
//printf("MSB: %d", MSB);
if (MSB == 0){ //if the current MSB was LO
HWREG(GPIO_PORTD_BASE+(GPIO_O_DATA + ALL_BITS)) &=
DATALO; //turn Data LO
}
else{ //if the current MSB was HI

HWREG(GPIO_PORTD_BASE+(GPIO_O_DATA + ALL_BITS)) |=
DATAHI; //turn Data HI
}
HWREG(GPIO_PORTD_BASE+(GPIO_O_DATA + ALL_BITS)) |= SHIFTHI;
//put SCLK HI
HWREG(GPIO_PORTD_BASE+(GPIO_O_DATA + ALL_BITS)) &= SHIFTLO;
//put SCLK LO
LocalRegisterImage = LocalRegisterImage<<1; //shift the bits
left so we have a new MSB
}
}
/****************************************************************************
Function
SR_StoreAllBytes
Parameters

none

Returns
none
Description

Raises the REGISTER clock pin to latch any data on the shift

registers.
Notes

Assumes the REGISTER clock was low when called, as this


function should only be called after a
call to SR_Shift1Byte, which sets the REGISTER clock low.
Author
Robert Carrera, 11/13/2016
****************************************************************************/
static void SR_StoreAllBytes(void){
HWREG(GPIO_PORTD_BASE+(GPIO_O_DATA + ALL_BITS)) |= REGISTERHI; //turn
RCLK HI to store current SR bits
}

//************************************

Vous aimerez peut-être aussi