Austin ThorntonRodney WhiteAdam St.Laurent
Published

Multi-Device Wifi Communication - The Shred Box

Ever too lazy to get up and talk to someone in your house? The Shred Box will solve all your needs!

IntermediateFull instructions provided675
Multi-Device Wifi Communication - The Shred Box

Things used in this project

Hardware components

Photon
Particle Photon
×3
Speaker: 3W, 4 ohms
Speaker: 3W, 4 ohms
×3
Solderless Breadboard Half Size
Solderless Breadboard Half Size
×3
Adafruit Mono 2.5W Class D Audio Amplifier - PAM8302
×3
Adafruit Electret Microphone Amplifier - MAX9814 with Auto Gain Control
×3
Junction Box
×3

Software apps and online services

Particle Build Web IDE
Particle Build Web IDE

Hand tools and fabrication machines

Drill
Soldering iron (generic)
Soldering iron (generic)
Screwdriver

Story

Read more

Schematics

Shred Box wiring diagram

This is the diagram on how to build a Shredbox. Pay specific attention to inputs on microphone and amplifier because they have additional ports that were not used. If you want to recreate this, double check your connections are correct because you could ruin parts by putting power to the wrong ports.

Code

Code for Multi-Device Wifi Communication

C/C++
Main Function
#include "SparkIntervalTimer.h"
#include "SimpleRingBuffer.h"

//WiFi.selectAntenna(ANT_EXTERNAL);

#define MICROPHONE_PIN DAC1
#define SPEAKER_PIN DAC2
#define BUTTON_PIN A0
#define BROADCAST_PORT 3443
#define UDP_BROADCAST_PORT 3444
#define AUDIO_BUFFER_MAX 8192

//#define SERIAL_DEBUG_ON true

#define AUDIO_TIMING_VAL 125 /* 8,000 hz */
//#define AUDIO_TIMING_VAL 62 /* 16,000 hz */
//#define AUDIO_TIMING_VAL 50  /* 20,000 hz */

UDP Udp;
IPAddress broadcastAddress(255,255,255,255);

int audioStartIdx = 0, audioEndIdx = 0;
int rxBufferLen = 0, rxBufferIdx = 0;

//uint16_t audioBuffer[AUDIO_BUFFER_MAX];
uint8_t txBuffer[AUDIO_BUFFER_MAX];
//uint8_t rxBuffer[AUDIO_BUFFER_MAX];


SimpleRingBuffer audio_buffer;
SimpleRingBuffer recv_buffer;


// IntervalTimer readMicTimer;
// IntervalTimer sendAudioTimer;

// version without timers
unsigned long lastRead = micros();
unsigned long lastSend = millis();
char myIpAddress[24];

TCPClient audioClient;
TCPClient checkClient;
TCPServer audioServer = TCPServer(BROADCAST_PORT);

IntervalTimer readMicTimer;
//int led_state = 0;
float _volumeRatio = 0.25;
int _sendBufferLength = 0;
unsigned int lastPublished = 0;


void setup() {
    #if SERIAL_DEBUG_ON
    Serial.begin(115200);
    #endif

    pinMode(MICROPHONE_PIN, INPUT);
    pinMode(SPEAKER_PIN, OUTPUT);
    pinMode(BUTTON_PIN, INPUT_PULLDOWN);
    pinMode(D7, OUTPUT);

    Particle.function("setVolume", onSetVolume);

    Particle.variable("ipAddress", myIpAddress, STRING);
    IPAddress myIp = WiFi.localIP();
    sprintf(myIpAddress, "%d.%d.%d.%d", myIp[0], myIp[1], myIp[2], myIp[3]);

    recv_buffer.init(AUDIO_BUFFER_MAX);
    audio_buffer.init(AUDIO_BUFFER_MAX);

    Udp.setBuffer(1024);
    Udp.begin(UDP_BROADCAST_PORT);


//    Udp.beginPacket(broadcastAddress, UDP_BROADCAST_PORT);
//    Udp.write(rxBuffer, 10);
//    Udp.endPacket();


    // 1/16,000th of a second is ~62 mcsec
    //readMicTimer.begin(readMic, 62, uSec);


    // // send a chunk of audio every 1/2 second
    // sendAudioTimer.begin(sendAudio, 1000, hmSec);

    audioServer.begin();

    lastRead = micros();
}

bool _isRecording = false;
void startRecording() {

    if (!_isRecording) {
        // 1/8000th of a second is 125 microseconds
        readMicTimer.begin(readMic, AUDIO_TIMING_VAL, uSec);
    }

    _isRecording = true;
}

void stopRecording() {
    if (_isRecording) {
        readMicTimer.end();
    }
    _isRecording = false;
}

void loop() {
//    checkClient = audioServer.available();
//    if (checkClient.connected()) {
//        audioClient = checkClient;
//    }

    //listen for 100ms, taking a sample every 125us,
    //and then send that chunk over the network.
    //listenAndSend(100);

    if (digitalRead(BUTTON_PIN) == HIGH) {
        digitalWrite(D7, HIGH);
        startRecording();
        Particle.publish("Light" , "Speaking" , PUBLIC);
        delay(2000);
        System.sleep(40);
        sendEvery(100);
        
    }
    else {
        digitalWrite(D7, LOW);
        Particle.publish("Light" , "Listening", PUBLIC);
        delay(2000);
        System.sleep(40);
        stopRecording();
    }

    readAndPlay();
    //led_state = !led_state;
}


int onSetVolume(String cmd) {
    _volumeRatio = cmd.toFloat() / 100;
}

void readAndPlay() {


    while (Udp.parsePacket() > 0) {
       while (Udp.available() > 0) {
            recv_buffer.put(Udp.read());
       }
       if (recv_buffer.getSize() == 0) {
           analogWrite(SPEAKER_PIN, 0);
       }
    }





//    #if SERIAL_DEBUG_ON
//        Serial.println("received " + String(count));
//    #endif

//    //read as much as we can off the buffer.
//    rxBufferLen = Udp.read(rxBuffer, AUDIO_BUFFER_MAX);
//    rxBufferIdx = 0;

    playRxAudio();
}

void playRxAudio() {
    unsigned long lastWrite = micros();
	unsigned long now, diff;
	int value;

	//toggleLED();

	//noInterrupts();

    //while (rxBufferIdx < rxBufferLen) {
    while (recv_buffer.getSize() > 0) {

        // ---
        //map it back from 1 byte to 2 bytes
        //map(value, fromLow, fromHigh, toLow, toHigh);
        //value = map(rxBuffer[rxBufferIdx++], 0, 255, 0, 4095);

        //play audio
        value = recv_buffer.get();
        value = map(value, 0, 255, 0, 4095);
        value = value * _volumeRatio;

        now = micros();
        diff = (now - lastWrite);
        if (diff < AUDIO_TIMING_VAL) {
            delayMicroseconds(AUDIO_TIMING_VAL - diff);
        }

        //analogWrite(SPEAKER_PIN, rxBuffer[rxBufferIdx++]);
        analogWrite(SPEAKER_PIN, value);
        lastWrite = micros();
    }

    //interrupts();

    //toggleLED();
}


void listenAndSend(int delay) {
    unsigned long startedListening = millis();

    while ((millis() - startedListening) < delay) {
        unsigned long time = micros();

        if (lastRead > time) {
            // time wrapped?
            //lets just skip a beat for now, whatever.
            lastRead = time;
        }

        //125 microseconds is 1/8000th of a second
        if ((time - lastRead) > 125) {
            lastRead = time;
            readMic();
        }
    }
    sendAudio();
}

void sendEvery(int delay) {

//    #if SERIAL_DEBUG_ON
//        Serial.println("sendEvery");
//    #endif

    // if it's been longer than 100ms since our last broadcast, then broadcast.
    if ((millis() - lastSend) >= delay) {

        sendAudio();

        lastSend = millis();
    }
}

// Callback for Timer 1
void readMic(void) {
    //read audio
    uint16_t value = analogRead(MICROPHONE_PIN);
    value = map(value, 0, 4095, 0, 255);
    audio_buffer.put(value);

//old
//    if (audioEndIdx >= AUDIO_BUFFER_MAX) {
//        audioEndIdx = 0;
//    }
//    audioBuffer[audioEndIdx++] = value;


//    //play audio
//    value = map(recv_buffer.get(), 0, 255, 0, 4095);
//    if (value >= 0) {
//        analogWrite(SPEAKER_PIN, value);
//    }


//    //play audio
//    if (rxBufferIdx < rxBufferLen) {
//
////        uint8_t lsb = rxBuffer[rxBufferIdx];
////        uint8_t msb = rxBuffer[rxBufferIdx+1];
////        rxBufferIdx +=2;
////        uint16_t value = ((msb << 8) | (lsb & 0xFF));
////        value = (value / 65536.0) * 4095.0;
////        analogWrite(SPEAKER_PIN, value);
//
//        //tcpBuffer[tcpIdx] = map(val, 0, 4095, 0, 255);
//        analogWrite(SPEAKER_PIN, rxBuffer[rxBufferIdx++]);
//    }
    //digitalWrite(D7, (led_state) ? HIGH : LOW);

//    if (rxBufferIdx < rxBufferLen) {
//        int value = map(rxBuffer[rxBufferIdx++], 0, 255, 0, 4095);
//        analogWrite(SPEAKER_PIN, value);
//    }
}

void copyAudio(uint8_t *bufferPtr) {

    int c = 0;
    while ((audio_buffer.getSize() > 0) && (c < AUDIO_BUFFER_MAX)) {
        bufferPtr[c++] = audio_buffer.get();
    }
    _sendBufferLength = c - 1;



//    //if end is after start, read from start->end
//    //if end is before start, then we wrapped, read from start->max, 0->end
//
//    int endSnapshotIdx = audioEndIdx;
//    bool wrapped = endSnapshotIdx < audioStartIdx;
//    int endIdx = (wrapped) ? AUDIO_BUFFER_MAX : endSnapshotIdx;
//
//
//    for(int i=audioStartIdx;i<endIdx;i++) {
//        // do a thing
//        bufferPtr[c++] = audioBuffer[i];
//    }
//
//    if (wrapped) {
//        //we have extra
//        for(int i=0;i<endSnapshotIdx;i++) {
//            // do more of a thing.
//            bufferPtr[c++] = audioBuffer[i];
//        }
//    }
//
//    //and we're done.
//    audioStartIdx = audioEndIdx;
//
//    if (c < AUDIO_BUFFER_MAX) {
//        bufferPtr[c] = -1;
//    }
//    _sendBufferLength = c;
}

// Callback for Timer 1
void sendAudio(void) {
//    #if SERIAL_DEBUG_ON
//        Serial.println("sendAudio");
//    #endif

    copyAudio(txBuffer);

    int i=0;
    uint16_t val = 0;


    if (audioClient.connected()) {
       write_socket(audioClient, txBuffer);
    }
    else {
        write_UDP(txBuffer);
    }
    // else {
    //     while( (val = txBuffer[i++]) < 65535 ) {
    //         Serial.print(val);
    //         Serial.print(',');
    //     }
    //     Serial.println("DONE");
    // }

}


void write_socket(TCPClient socket, uint8_t *buffer) {
    int i=0;
    uint16_t val = 0;

    int tcpIdx = 0;
    uint8_t tcpBuffer[1024];

    while( (val = buffer[i++]) < 65535 ) {
        if ((tcpIdx+1) >= 1024) {
            socket.write(tcpBuffer, tcpIdx);
            tcpIdx = 0;
        }

        tcpBuffer[tcpIdx] = val & 0xff;
        tcpBuffer[tcpIdx+1] = (val >> 8);
        tcpIdx += 2;
    }

    // any leftovers?
    if (tcpIdx > 0) {
        socket.write(tcpBuffer, tcpIdx);
    }
}

void write_UDP(uint8_t *buffer) {
    int stopIndex=_sendBufferLength;
//    uint16_t val = 0;

//    int tcpIdx = 0;
//    uint8_t tcpBuffer[1024];




//    while (( buffer[stopIndex++] < 4096 ) && (stopIndex < AUDIO_BUFFER_MAX)) {
//        ;
//    }
    #if SERIAL_DEBUG_ON
        Serial.println("SENDING " + String(stopIndex));
    #endif
    Udp.sendPacket(buffer, stopIndex, broadcastAddress, UDP_BROADCAST_PORT);

    //Udp.beginPacket(broadcastAddress, UDP_BROADCAST_PORT);

//    while( (val = buffer[i++]) < 4096 ) {
//        if ((tcpIdx+1) >= 1024) {
//
//            //works
////            Udp.beginPacket(broadcastAddress, UDP_BROADCAST_PORT);
////            Udp.write(tcpBuffer, tcpIdx);
////            Udp.endPacket();
//
//            //Doesn't work
//            Udp.sendPacket(tcpBuffer, tcpIdx, broadcastAddress, UDP_BROADCAST_PORT);
//
//
//            #if SERIAL_DEBUG_ON
//            Serial.println("SENT " + String(tcpIdx));
//            #endif
//            //delay(5);
//
//
//            tcpIdx = 0;
//            toggleLED();
//        }
//
//        //map(value, fromLow, fromHigh, toLow, toHigh);
//        tcpBuffer[tcpIdx] = val; //map(val, 0, 4095, 0, 255);
//        tcpIdx++;
//
////        tcpBuffer[tcpIdx] = val & 0xff;
////        tcpBuffer[tcpIdx+1] = (val >> 8);
////        tcpIdx += 2;
//    }
//
//    // any leftovers?
//    if (tcpIdx > 0) {
//        //works
////        Udp.beginPacket(broadcastAddress, UDP_BROADCAST_PORT);
////        Udp.write(tcpBuffer, tcpIdx);
////        Udp.endPacket();
//
//        //doesn't work
//        Udp.sendPacket(tcpBuffer, tcpIdx, broadcastAddress, UDP_BROADCAST_PORT);
//
//        #if SERIAL_DEBUG_ON
//        Serial.println("SENT " + String(tcpIdx));
//        #endif
//    }

    //toggleLED();
}

bool ledState = false;
void toggleLED() {
    ledState = !ledState;
    digitalWrite(D7, (ledState) ? HIGH : LOW);
}














/* Copyright (c) 2014 Paul Kourany, based on work by Dianel Gilbert
UPDATED Sept 3, 2015 - Added support for Particle Photon
Copyright (c) 2013 Daniel Gilbert, loglow@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in the
Software without restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so, subject to the
following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */

Sub-Function II

C/C++
Simple Ring Buffer.cpp
#include "application.h"
#include "SimpleRingBuffer.h"

SimpleRingBuffer::SimpleRingBuffer() {

}

void SimpleRingBuffer::init(unsigned int size) {
    cur_idx = 0;    //pos
    cur_len = 0;    //len

    _data = (uint8_t*)malloc(size * sizeof(uint8_t));
    data_size = size; //cap
}

bool SimpleRingBuffer::put(uint8_t value) {
    if (cur_len < data_size) {
        // get our index, wrap on buffer size
        _data[(cur_idx + cur_len)%data_size] = value;
        cur_len++;
        return true;
    }
    return false;
}

uint8_t SimpleRingBuffer::get() {
    // lets return 0 if we don't have anything
    uint8_t val = 0;


    if (cur_len > 0) {

        // grab the value from the current index
        val = _data[cur_idx];

        // move to next, wrap as necessary, shrink length
        cur_idx = (cur_idx + 1) % data_size;
        cur_len--;
    }
    return val;
}

unsigned int SimpleRingBuffer::getSize() {
    return cur_len;
}

unsigned int SimpleRingBuffer::getCapacity() {
    return data_size;
}

void SimpleRingBuffer::clear() {
    cur_idx = 0;
    cur_len = 0;
}

void SimpleRingBuffer::destroy() {
    free(_data);
    _data = NULL;
}

Sub-Function III

C/C++
Spark Interval Timer .cpp
#include "SparkIntervalTimer.h"


bool IntervalTimer::SIT_used[];
IntervalTimer::ISRcallback IntervalTimer::SIT_CALLBACK[];

// ------------------------------------------------------------
#if defined(STM32F10X_MD) || !defined(PLATFORM_ID)		//Core
void Wiring_TIM2_Interrupt_Handler_override()
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
	{
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
		IntervalTimer::SIT_CALLBACK[0]();
	}
}

void Wiring_TIM3_Interrupt_Handler_override()
{
	if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
	{
		TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
		IntervalTimer::SIT_CALLBACK[1]();
	}
}

void Wiring_TIM4_Interrupt_Handler_override()
{
	if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET)
	{
		TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
		IntervalTimer::SIT_CALLBACK[2]();
	}
}
#elif defined(STM32F2XX) && defined(PLATFORM_ID)	//Photon
void Wiring_TIM3_Interrupt_Handler_override()
{
	if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
	{
		TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
		IntervalTimer::SIT_CALLBACK[0]();
	}
}

void Wiring_TIM4_Interrupt_Handler_override()
{
	if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET)
	{
		TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
		IntervalTimer::SIT_CALLBACK[1]();
	}
}

void Wiring_TIM5_Interrupt_Handler_override()
{
	if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET)
	{
		TIM_ClearITPendingBit(TIM5, TIM_IT_Update);
		IntervalTimer::SIT_CALLBACK[2]();
	}
}

void Wiring_TIM6_Interrupt_Handler_override()
{
	if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET)
	{
		TIM_ClearITPendingBit(TIM6, TIM_IT_Update);
		IntervalTimer::SIT_CALLBACK[3]();
	}
}

void Wiring_TIM7_Interrupt_Handler_override()
{
	if (TIM_GetITStatus(TIM7, TIM_IT_Update) != RESET)
	{
		TIM_ClearITPendingBit(TIM7, TIM_IT_Update);
		IntervalTimer::SIT_CALLBACK[4]();
	}
}
#else
  #error "*** PARTICLE device not supported by this library. PLATFORM should be Core or Photon ***"
#endif

// ------------------------------------------------------------
// this function inits and starts the timer, using the specified
// function as a callback and the period provided. must be passed
// the name of a function taking no arguments and returning void.
// make sure this function can complete within the time allowed.
// attempts to allocate a timer using available resources,
// returning true on success or false in case of failure.
// Period units is defined by scale, where scale = uSec or hmSec
// and = 1-65535 microsecond (uSec)
// or 1-65535 0.5ms increments (hmSec)
// ------------------------------------------------------------
bool IntervalTimer::beginCycles(void (*isrCallback)(), intPeriod Period, bool scale, TIMid id) {

	// if this interval timer is already running, stop and deallocate it
	if (status == TIMER_SIT) {
		stop_SIT();
		status = TIMER_OFF;
	}
	// store callback pointer
	myISRcallback = isrCallback;

	if (id > NUM_SIT) {		// Allocate specified timer (id=0 to 2/4) or auto-allocate from pool (id=255)
		// attempt to allocate this timer
		if (allocate_SIT(Period, scale, id)) status = TIMER_SIT;		//255 means allocate from pool
		else status = TIMER_OFF;
	}
	else {
		// attempt to allocate this timer
		if (allocate_SIT(Period, scale, AUTO)) status = TIMER_SIT;		//255 means allocate from pool
		else status = TIMER_OFF;
	}

	// check for success and return
	if (status != TIMER_OFF) return true;
	return false;

}


// ------------------------------------------------------------
// enables the SIT clock if not already enabled, then checks to
// see if any SITs are available for use. if one is available,
// it's initialized and started with the specified value, and
// the function returns true, otherwise it returns false
// ------------------------------------------------------------
bool IntervalTimer::allocate_SIT(intPeriod Period, bool scale, TIMid id) {

	if (id < NUM_SIT) {		// Allocate specified timer (id=TIMER3/4/5) or auto-allocate from pool (id=AUTO)
		if (!SIT_used[id]) {
			start_SIT(Period, scale);
			SIT_used[id] = true;
			return true;
		}
	}
	else {	
		// Auto allocate - check for an available SIT, and if so, start it
		for (uint8_t tid = 0; tid < NUM_SIT; tid++) {
			if (!SIT_used[tid]) {
				SIT_id = tid;
				start_SIT(Period, scale);
				SIT_used[tid] = true;
				return true;
			}
		}
	}
	
	// Specified or no auto-allocate SIT available
	return false;
}



// ------------------------------------------------------------
// configuters a SIT's TIMER registers, etc and enables
// interrupts, effectively starting the timer upon completion
// ------------------------------------------------------------
void IntervalTimer::start_SIT(intPeriod Period, bool scale) {

	TIM_TimeBaseInitTypeDef timerInitStructure;
    NVIC_InitTypeDef nvicStructure;
	intPeriod prescaler;
	TIM_TypeDef* TIMx;

	//use SIT_id to identify TIM#
	switch (SIT_id) {
#if defined(STM32F10X_MD) || !defined(PLATFORM_ID)		//Core
	case 0:		// TIM2
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
		nvicStructure.NVIC_IRQChannel = TIM2_IRQn;
		TIMx = TIM2;
		break;
	case 1:		// TIM3
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
		nvicStructure.NVIC_IRQChannel = TIM3_IRQn;
		TIMx = TIM3;
		break;
	case 2:		// TIM4
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
		nvicStructure.NVIC_IRQChannel = TIM4_IRQn;
		TIMx = TIM4;
		break;
#elif defined(STM32F2XX) && defined(PLATFORM_ID)	//Photon
	case 0:		// TIM3
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
		nvicStructure.NVIC_IRQChannel = TIM3_IRQn;
		TIMx = TIM3;
		break;
	case 1:		// TIM4
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
		nvicStructure.NVIC_IRQChannel = TIM4_IRQn;
		TIMx = TIM4;
		break;
	case 2:		// TIM5
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
		nvicStructure.NVIC_IRQChannel = TIM5_IRQn;
		TIMx = TIM5;
		break;
	case 3:		// TIM6
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
		nvicStructure.NVIC_IRQChannel = TIM6_DAC_IRQn;
		TIMx = TIM6;
		break;
	case 4:		// TIM7
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);
		nvicStructure.NVIC_IRQChannel = TIM7_IRQn;
		TIMx = TIM7;
		break;
#endif
	}
	
	// Initialize Timer
	switch (scale) {
		case uSec:
			prescaler = SIT_PRESCALERu;	// Set prescaler for 1MHz clock, 1us period
			break;
		case hmSec:
			prescaler = SIT_PRESCALERm;	// Set prescaler for 2Hz clock, .5ms period
			break;
		default:
			prescaler = SIT_PRESCALERu;
			scale = uSec;				// Default to microseconds
			break;
	}

	timerInitStructure.TIM_Prescaler = prescaler;
	timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	timerInitStructure.TIM_Period = Period;
	timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	timerInitStructure.TIM_RepetitionCounter = 0;

	TIM_TimeBaseInit(TIMx, &timerInitStructure);
	TIM_Cmd(TIMx, ENABLE);
	TIM_ITConfig(TIMx, TIM_IT_Update, ENABLE);

	// point to the correct SIT ISR
	SIT_CALLBACK[SIT_id] = myISRcallback;

	//Enable Timer Interrupt
    nvicStructure.NVIC_IRQChannelPreemptionPriority = 10;
    nvicStructure.NVIC_IRQChannelSubPriority = 1;
    nvicStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&nvicStructure);
}


// ------------------------------------------------------------
// stop the timer if it's currently running, using its status
// to determine what hardware resources the timer may be using
// ------------------------------------------------------------
void IntervalTimer::end() {
	if (status == TIMER_SIT) stop_SIT();
	status = TIMER_OFF;
}


// ------------------------------------------------------------
// stops an active SIT by disabling its interrupt and TIMER
// and freeing up its state for future use.
// ------------------------------------------------------------
void IntervalTimer::stop_SIT() {

    NVIC_InitTypeDef nvicStructure;
	TIM_TypeDef* TIMx;


	//use SIT_id to identify TIM#
	switch (SIT_id) {
#if defined(STM32F10X_MD) || !defined(PLATFORM_ID)		//Core
	case 0:		// TIM2
		nvicStructure.NVIC_IRQChannel = TIM2_IRQn;
		TIMx = TIM2;
		break;
	case 1:		// TIM3
		nvicStructure.NVIC_IRQChannel = TIM3_IRQn;
		TIMx = TIM3;
		break;
	case 2:		// TIM4
		nvicStructure.NVIC_IRQChannel = TIM4_IRQn;
		TIMx = TIM4;
		break;
#elif defined(STM32F2XX) && defined(PLATFORM_ID)	//Photon
	case 0:		// TIM3
		nvicStructure.NVIC_IRQChannel = TIM3_IRQn;
		TIMx = TIM3;
		break;
	case 1:		// TIM4
		nvicStructure.NVIC_IRQChannel = TIM4_IRQn;
		TIMx = TIM4;
		break;
	case 2:		// TIM5
		nvicStructure.NVIC_IRQChannel = TIM5_IRQn;
		TIMx = TIM5;
		break;
	case 3:		// TIM6
		nvicStructure.NVIC_IRQChannel = TIM6_DAC_IRQn;
		TIMx = TIM6;
		break;
	case 4:		// TIM7
		nvicStructure.NVIC_IRQChannel = TIM7_IRQn;
		TIMx = TIM7;
		break;
#endif
		}
	// disable counter
	TIM_Cmd(TIMx, DISABLE);
	
	// disable interrupt
    nvicStructure.NVIC_IRQChannelCmd = DISABLE;
    NVIC_Init(&nvicStructure);
	
	// disable timer peripheral
	TIM_DeInit(TIMx);
	
	// free SIT for future use
	SIT_used[SIT_id] = false;
}


// ------------------------------------------------------------
// Enables or disables an active SIT's interrupt without
// removing the SIT.
// ------------------------------------------------------------
void IntervalTimer::interrupt_SIT(action ACT)
{
    NVIC_InitTypeDef nvicStructure;
	TIM_TypeDef* TIMx;

	//use SIT_id to identify TIM#
	switch (SIT_id) {
#if defined(STM32F10X_MD) || !defined(PLATFORM_ID)		//Core
	case 0:		// TIM2
		nvicStructure.NVIC_IRQChannel = TIM2_IRQn;
		TIMx = TIM2;
		break;
	case 1:		// TIM3
		nvicStructure.NVIC_IRQChannel = TIM3_IRQn;
		TIMx = TIM3;
		break;
	case 2:		// TIM4
		nvicStructure.NVIC_IRQChannel = TIM4_IRQn;
		TIMx = TIM4;
		break;
#elif defined(STM32F2XX) && defined(PLATFORM_ID)	//Photon
	case 0:		// TIM3
		nvicStructure.NVIC_IRQChannel = TIM3_IRQn;
		TIMx = TIM3;
		break;
	case 1:		// TIM4
		nvicStructure.NVIC_IRQChannel = TIM4_IRQn;
		TIMx = TIM4;
		break;
	case 2:		// TIM5
		nvicStructure.NVIC_IRQChannel = TIM5_IRQn;
		TIMx = TIM5;
		break;
	case 3:		// TIM6
		nvicStructure.NVIC_IRQChannel = TIM6_DAC_IRQn;
		TIMx = TIM6;
		break;
	case 4:		// TIM7
		nvicStructure.NVIC_IRQChannel = TIM7_IRQn;
		TIMx = TIM7;
		break;
#endif
	}

	switch (ACT) {
	case INT_ENABLE:
		//Enable Timer Interrupt
		nvicStructure.NVIC_IRQChannelPreemptionPriority = 0;
		nvicStructure.NVIC_IRQChannelSubPriority = 1;
		nvicStructure.NVIC_IRQChannelCmd = ENABLE;
		NVIC_Init(&nvicStructure);
		break;
	case INT_DISABLE:
		// disable interrupt
		nvicStructure.NVIC_IRQChannelCmd = DISABLE;
		NVIC_Init(&nvicStructure);
		break;
	default:
		//Do nothing
		break;
	}
}


// ------------------------------------------------------------
// Set new period for the SIT without
// removing the SIT.
// ------------------------------------------------------------
void IntervalTimer::resetPeriod_SIT(intPeriod newPeriod, bool scale)
{
	//TIM_TimeBaseInitTypeDef timerInitStructure;
	TIM_TypeDef* TIMx;
	intPeriod prescaler;

	//use SIT_id to identify TIM#
	switch (SIT_id) {
#if defined(STM32F10X_MD) || !defined(PLATFORM_ID)		//Core
	case 0:		// TIM2
		TIMx = TIM2;
		break;
	case 1:		// TIM3
		TIMx = TIM3;
		break;
	case 2:		// TIM4
		TIMx = TIM4;
		break;
#elif defined(STM32F2XX) && defined(PLATFORM_ID)	//Photon
	case 0:		// TIM3
		TIMx = TIM3;
		break;
	case 1:		// TIM4
		TIMx = TIM4;
		break;
	case 2:		// TIM5
		TIMx = TIM5;
		break;
	case 3:		// TIM6
		TIMx = TIM6;
		break;
	case 4:		// TIM7
		TIMx = TIM7;
		break;
#endif
	}

	switch (scale) {
	case uSec:
		prescaler = SIT_PRESCALERu;	// Set prescaler for 1MHz clock, 1us period
		break;
	case hmSec:
		prescaler = SIT_PRESCALERm;	// Set prescaler for 2Hz clock, .5ms period
		break;
	default:
		scale = uSec;				// Default to microseconds
		prescaler = SIT_PRESCALERu;
		break;
	}

	TIMx->ARR = newPeriod;
	TIMx->PSC = prescaler;
	TIMx->EGR = TIM_PSCReloadMode_Immediate;
	TIM_ClearITPendingBit(TIMx, TIM_IT_Update);
}

// ------------------------------------------------------------
// Returns -1 if timer not allocated or sid number:
// 0 = TMR2, 1 = TMR3, 2 = TMR4
// ------------------------------------------------------------
int8_t IntervalTimer::isAllocated_SIT(void)
{
	if (status == TIMER_SIT)
		return -1;
	else 
		return SIT_id;
}

Sub-Function IV

C/C++
Simple Ring Buffer .h
#ifndef SIMPLERINGBUFFER_H
#define	SIMPLERINGBUFFER_H


class SimpleRingBuffer {
    protected:
        uint8_t* _data;
        unsigned int data_size;
        unsigned int cur_idx;
        unsigned int cur_len;

    public:
        SimpleRingBuffer();

        void init(unsigned int size);

        bool put(uint8_t value);
        uint8_t get();

        unsigned int getSize();
        unsigned int getCapacity();

        void clear();
        void destroy();
};

#endif

Credits

Austin Thornton

Austin Thornton

1 project • 0 followers
Rodney White

Rodney White

1 project • 0 followers
Adam St.Laurent

Adam St.Laurent

1 project • 0 followers

Comments