AVR, используя FIFO в прерываниях - PullRequest
0 голосов
/ 15 января 2020

Приветствую всех ценителей. Добрый день. Я постараюсь запрограммировать AVR ATMega328. Я использую следующие библиотеки: bme280 avr-st7735

Подпрограмма для таймера от здесь

Я хочу каждые две секунды чтобы получить данные BME280, и я хочу использовать TIMER1 и переполнение, см. код. Я прочитал датчик как обработчик прерываний. Используйте пользовательскую реализацию очереди FIFO. В операции прерывания данные извлекаются в очередь FIFO. Наконец, я попытаюсь прочитать FIFO в основном l oop.

Код:

main. cpp

#include <stdio.h>
#include <stdlib.h>

#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>
#include <util/delay.h>

extern "C" {
#include "spi.h"
#include "st7735.h"
#include "st7735_gfx.h"
#include "st7735_font.h"
#include "bme280/bme280.h"
#include <i2c/i2c_master.h>
#include "ftoa/ftoa.h"
}



#include <fifo.hpp>
#include "millis/millis.h"
#include "Utils/avr.hpp"


fifo_struct<float> fifo;

void showVisual()
{
    // Just toggle led diode state
}

// global variable to count the number of overflows
volatile uint8_t tot_overflow;

// initialize timer, interrupt and variable
void timer1_init()
{
// set up timer with prescaler = 8
    TCCR1B |= (1 << CS11);
// initialize counter
    TCNT1 = 0;

// enable overflow interrupt
    TIMSK1 |= (1 << TOIE1);

// initialize overflow counter variable
    tot_overflow = 0;
}



// TIMER1 overflow interrupt service routine
// called whenever TCNT1 overflows
ISR(TIMER1_OVF_vect)
{
// keep a track of number of overflows
    tot_overflow++;
// check for number of overflows here itself
// 61 overflows = 2 seconds delay (approx.)
    if (tot_overflow >= 61) // NOTE: '>=' used instead of '=='
    {
        {
            // Get data
            float data = 5.5f; //bme280_readTemperature();
            // Push to FIFO
            fifo_push<float>(&fifo, data); // TODO: Not in the effect! Why?
        }
        showVisual(); // blink with led

// no timer reset required here as the timer
// is reset every time it overflows
        tot_overflow = 0; // reset overflow counter
    }
}

extern "C" int main(void)
{
    // Init millis
    clock_init();

    // Init SPI and TFT
    spi_init();
    st7735_init();
    st7735_set_orientation(ST7735_LANDSCAPE_INV);
    st7735_fill_rect(0, 0, 128, 128, ST7735_COLOR_BLACK);

    // Initialize PWM 
    // Fast PWM with MAX
    TCCR0A |= (1 << WGM01) | (1 << WGM00);
    // Mode output
    // Noninvert for OC0A
    TCCR0A |= (1 << COM0A1);
    // Divider to 64
    TCCR0B |= (1 << CS01) | (1 << CS00);
    // Set pwm to 200/255
    OCR0A = 200;


    // Initialize I2C and BME280 
    i2c_init();

    fifo = fifo_create<float>(5);
    if (!bme_init())
    {
        // Error!!
    }

    // initialize timer
    timer1_init();

    // Enable global interrupts
    sei();

    wdt_enable(WDTO_2S);

    while (1)
    {
        float val = fifo_pop<float>(&fifo);
        uart_puts(val); // Printed 0.0
        uart_puts(fifo_count<float>(&fifo)); // Allways print 0!

        wdt_reset();
    }
}

fifo.h

/**
 * This file is a part of FIFO implementation in C/C++
 * 
 * fifo.h
 *
 *  Created on: 14. 1. 2020
 *  Author:     Denis Colesnicov
 *  Licence:    WTFPL
 *  Version:    4
 */

#ifndef FIFO_HPP_
#define FIFO_HPP_

#include <stdint.h>


/**
 * Struktura udrzujici informace pro frontu
 */
template<typename T> struct fifo_struct
{
    volatile uint8_t top;   /*<! Ukazatel na vrchol zasobniku (na jakou pozici byl vlozen posledni prvek) */
    volatile T *data;       /*<! Pole s ulozenymi prvkz */
    uint8_t size;   /*<! Rezervovana velikost fronty */
};

/**
 * Vytvori novou frontu
 *
 * @note        Pro fifo_struct::data je pouzita f-ce calloc(...),
 *              musi se pouZit funkce free(..) pro uvolneni!
 * @param _size Kolik ma obsahovat prvku
 * @return      Vraci frontu
 */
template<typename T> fifo_struct<T> fifo_create(uint8_t _size);

/**
 * Kolik prvku je ve fronte
 *
 * @param _fifo Fronta
 * @return      Pocet prvku ve fronte
 */
template<typename T> uint8_t fifo_count(fifo_struct<T> *_fifo);

/**
 * Pro kolik prvku je rezervovana fronta (maximalni pocet prvku ve fronte)
 *
 * @param _fifo Fronta
 * @return      Pocet rezervovanych "mist"
 */
template<typename T> uint8_t fifo_size(fifo_struct<T> *_fifo);

/**
 * Odstrani z fronty vsechny ulozene prvky a vynuluje ji.
 *
 * @note        Frontu jiz nadale nebude mozne pouzivat!
 * @param _fifo Fronta
 */
template<typename T> void fifo_destroy(fifo_struct<T> *_fifo);

/**
 * Vlozi prvek na konec fronty
 *
 * @param _fifo Fronta
 * @param _data Data ke vlozeni
 */
template<typename T> void fifo_push(fifo_struct<T> *_fifo, T _data);

/**
 * Vrati data ktera jsou na zacatku fronty.
 *
 * @note        Data zustanou ve fronte (ne odstranuje ziskana data!)
 * @param _fifo Fronta
 * @return      Data
 */
template<typename T> T fifo_first(fifo_struct<T> *_fifo);

/**
 * Vrati data ktera jsou na konci fronty.
 *
 * @note        Data zustanou ve fronte (ne odstranuje ziskana data!)
 * @param _fifo Fronta
 * @return      Data
 */
template<typename T> T fifo_last(fifo_struct<T> *_fifo);

/**
 * Zredukuje velikost fronty o zadany pocet pozic
 * Posune obsah fronty do leva o zadany pocet pozic.
 * Data ktera byla na zacatku fronty budou odstranene!
 *
 * @param _fifo     Fronta
 * @param _count    Pocet pozic k posunu
 */
template<typename T> void fifo_reduce(fifo_struct<T> *_fifo, uint8_t _count);

/**
 * Vrati data ze zacatku fronty.
 *
 * @note        Tim dojde k odstraneni techto dat a zredukovani pole.
 *              @see fifo_reduce(...)
 * @param _fifo Fronta
 * @return      Data
 */
template<typename T> T fifo_pop(fifo_struct<T> *_fifo);

/**
 * Trida usnadnujici praci s FIFO frontou
 */
template<typename T>
class Fifo
{

public:

    /**
     * Vytvori novou frontu
     *
     * @param _size Kolik ma obsahovat prvku
     */
    Fifo(uint8_t _size);

    /**
     * Odstrani z fronty vsechny ulozene prvky a vynuluje ji.
     *
     * @note        Frontu jiz nadale nebude mozne pouzivat!
     * @param _fifo Fronta
     */
    ~Fifo();

    /**
     * Vrati data ktera jsou na zacatku fronty.
     *
     * @note        Data zustanou ve fronte (ne odstranuje ziskana data!)
     * @param _fifo Fronta
     * @return      Data
     */
    T first();

    /**
     * Vrati data ktera jsou na konci fronty.
     *
     * @note        Data zustanou ve fronte (ne odstranuje ziskana data!)
     * @param _fifo Fronta
     * @return      Data
     */
    T last();

    /**
     * Kolik prvku je ve fronte
     *
     * @return      Pocet prvku ve fronte
     */
    uint8_t count();

    /**
     * Pro kolik prvku je rezervovana fronta (maximalni pocet prvku ve fronte)
     *
     * @return      Pocet rezervovanych "mist"
     */
    uint8_t size();

    /**
     * Vrati data ze zacatku fronty.
     *
     * @note        Tim dojde k odstraneni techto dat a zredukovani pole.
     *              @see fifo_reduce(...)
     * @return      Data
     */
    T pop();

    /**
     * Vlozi prvek na konec fronty
     *
     * @param _fifo Fronta
     * @param _data Data ke vlozeni
     */
    void push(T _data);

    /**
     * Zredukuje velikost fronty o zadany pocet pozic
     * Posune obsah fronty do leva o zadany pocet pozic.
     * Data ktera byla na zacatku fronty budou odstranene!
     *
     * @param _count    Pocet pozic k posunu
     */
    void reduce(uint8_t _count);

private:

    fifo_struct<T> m_fifo; /*<! Fronta (FIFO) */
};


#include <stdlib.h>


template<typename T> fifo_struct<T> fifo_create(uint8_t _size)
{
    fifo_struct<T> fifo;
    fifo.top = 0;
    fifo.size = _size;
    fifo.data = (T*) calloc(_size, sizeof(T));
    return fifo;
}

template<typename T> uint8_t fifo_count(fifo_struct<T> *_fifo)
{
    return (uint8_t) _fifo->top;
}

template<typename T> uint8_t fifo_size(fifo_struct<T> *_fifo)
{
    return (uint8_t) _fifo->size;
}

template<typename T> void fifo_destroy(fifo_struct<T> *_fifo)
{
    _fifo->size = 0;
    _fifo->top = 0;
    free(_fifo->data);
}

template<typename T> void fifo_push(fifo_struct<T> *_fifo, T _data)
{
    if (_fifo->size == _fifo->top)
    {
        fifo_reduce<T>(_fifo, 1);
    }
    _fifo->data[_fifo->top] = _data;
    _fifo->top++;
}

template<typename T> T fifo_pop(fifo_struct<T> *_fifo)
{
    if (_fifo->top == 0)
    {
        return (T) NULL;
    }

    T data = _fifo->data[0];

    fifo_reduce<T>(_fifo, 1);
    return data;
}

template<typename T> T fifo_first(fifo_struct<T> *_fifo)
{
    if (_fifo->top == 0)
    {
        return (T) NULL;
    }
    return _fifo->data[0];
}

template<typename T> T fifo_last(fifo_struct<T> *_fifo)
{
    if (_fifo->top == 0)
    {
        return (T) NULL;
    }
    return _fifo->data[_fifo->top - 1];
}

template<typename T> void fifo_reduce(fifo_struct<T> *_fifo, uint8_t _count)
{
    for (uint8_t i = 0; i < _fifo->size; i++)
    {
        _fifo->data[i] = _fifo->data[_count + i];
    }
    _fifo->top -= _count;
}

template<typename T>
Fifo<T>::Fifo(uint8_t _size)
{
    m_fifo = fifo_create<T>(_size);
}

template<typename T>
Fifo<T>::~Fifo()
{
    fifo_destroy<T>(&m_fifo);
}

template<typename T>
T Fifo<T>::first()
{
    fifo_first<T>(m_fifo);
}

template<typename T>
T Fifo<T>::last()
{
    fifo_last<T>(m_fifo);
}

template<typename T>
uint8_t Fifo<T>::count()
{
    return fifo_count<T>(m_fifo);
}

template<typename T>
uint8_t Fifo<T>::size()
{
    return fifo_size<T>(m_fifo);
}

template<typename T>
T Fifo<T>::pop()
{
    return fifo_pop<T>(&m_fifo);
}

template<typename T>
void Fifo<T>::push(T _data)
{
    fifo_push<T>(&m_fifo, _data);
}

template<typename T>
void Fifo<T>::reduce(uint8_t _count)
{
    fifo_reduce<T>(&m_fifo, _count);
}

#endif /* FIFO_HPP_ */

milli.h

/*
 * Project: Lightweight millisecond tracking library
 * Author: Zak Kemble, contact@zakkemble.net
 * Copyright: (C) 2018 by Zak Kemble
 * License: GNU GPL v3 (see License_GPL-3.0.txt) or MIT (see License_MIT.txt)
 * Web: http://blog.zakkemble.net/millisecond-tracking-library-for-avr/
 */

#ifdef __cplusplus
extern "C" {
#endif
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/power.h>
#include <util/atomic.h>
#ifdef __cplusplus
}
#endif
#include "millis.h"

#define CLOCK_SCALE_MICROS  0
#define CLOCK_SCALE_MILLIS  1
#define CLOCK_SCALE         CLOCK_SCALE_MICROS

#define MILLIS_TIMER0   0               /**< Use timer0. */
#define MILLIS_TIMER1   1               /**< Use timer1. */
#define MILLIS_TIMER2   2               /**< Use timer2. */
#define MILLIS_TIMER    MILLIS_TIMER0   /**< Which timer to use. */

#define MICROSECONDS_PER_TIMER0_OVERFLOW    16384
#define MILLIS_INC                          1024
#define FRACT_INC                           ((1024 % 1000) >> 3)
#define FRACT_MAX                           (1000 >> 3)

#ifndef F_CPU
#error "F_CPU not defined!"
#endif

#if F_CPU < 256 || F_CPU >= 32640000
#error "Bad F_CPU setting (<256 or >=32640000)"
#endif

#ifndef MILLIS_TIMER
#error "Bad MILLIS_TIMER set"
#endif

// Decide what what prescaler and registers to use
#if MILLIS_TIMER == MILLIS_TIMER0

// Timer0

#if F_CPU > 16320000 // 16.32MHz - 65.28MHz
#define CLOCKSEL (_BV(CS20))
#define PRESCALER 256
#elif F_CPU > 2040000 // 2.04MHz - 16.32MHz
#define CLOCKSEL (_BV(CS01)|_BV(CS00))
#define PRESCALER 64
#elif F_CPU > 255 // 256Hz - 2.04MHz
#define CLOCKSEL (_BV(CS01))
#define PRESCALER 8
#endif

#define REG_TCCRA       TCCR0A
#define REG_TCCRB       TCCR0B
#define REG_TIMSK       TIMSK0
#define REG_OCR         OCR0A
#define BIT_WGM         WGM01
#define BIT_OCIE        OCIE0A
#ifdef TIMER0_COMPA_vect
#define ISR_VECT        TIMER0_COMPA_vect
#else
#define ISR_VECT        TIM0_COMPA_vect
#endif
#define pwr_enable()    power_timer0_enable()
#define pwr_disable()   power_timer0_disable()

#define SET_TCCRA() (REG_TCCRA |= _BV(BIT_WGM))
#define SET_TCCRB() (REG_TCCRB |= CLOCKSEL)

#elif MILLIS_TIMER == MILLIS_TIMER1

// Timer1

// 1KHz - 65.28MHz
#define CLOCKSEL (_BV(CS10))
#define PRESCALER 1

#define REG_TCCRA       TCCR1A
#define REG_TCCRB       TCCR1B
#define REG_TIMSK       TIMSK1
#define REG_OCR         OCR1A
#define BIT_WGM         WGM12
#define BIT_OCIE        OCIE1A
#ifdef TIMER1_COMPA_vect
#define ISR_VECT        TIMER1_COMPA_vect
#else
#define ISR_VECT        TIM1_COMPA_vect
#endif
#define pwr_enable()    power_timer1_enable()
#define pwr_disable()   power_timer1_disable()

#define SET_TCCRA() (REG_TCCRA |= 0)
#define SET_TCCRB() (REG_TCCRB |= _BV(BIT_WGM)|CLOCKSEL)

#elif MILLIS_TIMER == MILLIS_TIMER2

// Timer2

#if F_CPU > 16320000 // 16.32MHz - 32.64MHz
#define CLOCKSEL (_BV(CS22)|_BV(CS20))
#define PRESCALER 128
#elif F_CPU > 8160000 // 8.16MHz - 16.32MHz
#define CLOCKSEL (_BV(CS22))
#define PRESCALER 64
#elif F_CPU > 2040000 // 2.04MHz - 8.16MHz
#define CLOCKSEL (_BV(CS21)|_BV(CS20))
#define PRESCALER 32
#elif F_CPU > 255 // 256Hz - 2.04MHz
#define CLOCKSEL (_BV(CS21))
#define PRESCALER 8
#endif

#define REG_TCCRA       TCCR2A
#define REG_TCCRB       TCCR2B
#define REG_TIMSK       TIMSK2
#define REG_OCR         OCR2A
#define BIT_WGM         WGM21
#define BIT_OCIE        OCIE2A
#define ISR_VECT        TIMER2_COMPA_vect
#define pwr_enable()    power_timer2_enable()
#define pwr_disable()   power_timer2_disable()

#define SET_TCCRA() (REG_TCCRA |= _BV(BIT_WGM))
#define SET_TCCRB() (REG_TCCRB |= CLOCKSEL)

#else
#error "Bad MILLIS_TIMER set"
#endif

static volatile millis_t timer_value;

// Initialise library
void clock_init()
{
    // Timer settings
    SET_TCCRA();
    SET_TCCRB();
    REG_TIMSK |= _BV(BIT_OCIE);
    REG_OCR = ((F_CPU / PRESCALER) / 1000);
}

// Get current timer_value
millis_t clock_get()
{
    millis_t ms;
    ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
    {
        ms = timer_value;
    }
    return ms;
}

// Turn on timer and resume time keeping
void clock_resume()
{
    pwr_enable();
    REG_TIMSK |= _BV(BIT_OCIE);
}

// Pause time keeping and turn off timer to save power
void clock_pause()
{
    REG_TIMSK &= ~_BV(BIT_OCIE);
    pwr_disable();
}

// Reset microseconds count to 0
void clock_reset()
{
    ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
    {
        timer_value = 0;
    }
}

// Add time
void clock_add(millis_t ms)
{
    ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
    {
        timer_value += ms;
    }
}

// Subtract time
void clock_subtract(millis_t ms)
{
    ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
    {
        timer_value -= ms;
    }
}


ISR(ISR_VECT)
{
    static unsigned char timer_fract = 0;

#if CLOCK_SCALE == CLOCK_SCALE_MICROS
    timer_value += MILLIS_INC;
    timer_fract += FRACT_INC;
    if (timer_fract >= FRACT_MAX)
    {
        timer_fract -= FRACT_MAX;
        timer_value += 1;
    }
#else
    timer_value += 1;
    timer_fract += 3;
    if (timer_fract >= 125)
    {
        timer_fract -= 125;
        timer_value += 1;
    }
#endif // CLOCK_SCALE
}

Проблема: данные не сохраняются в FIFO. Вы видите, кто-то решает, пожалуйста ??

1 Ответ

0 голосов
/ 17 января 2020

Я изменил свою стратегию. Мой код уже работает по-другому. Но моя реализация FIFO может быть полезна кому-то ...

...