Программирование STM8

Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
a5021
Друг Кота
Сообщения: 6452
Зарегистрирован: Пт сен 13, 2013 13:11:31

Re: Программирование STM8

Сообщение a5021 »

oleg110592 писал(а):Задачу, имхо можно решить за 2 (два) дня и совершенно не надо ждать полтора года.

Что-то мне подсказывает, что результатов такого решения здесь не возникнет никогда. Но, безусловно, по очень веской и совершенно непреодолимой причине, никак не зависящей от самой задачи. Чего бы еще от вас ждать.
Аватара пользователя
oleg110592
Друг Кота
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Re: Программирование STM8

Сообщение oleg110592 »

по заявкам трудящихся (в личке)
как сделать оцифровку звука с микрофона с помощью АЦП и таймера:
1) настраиваем АЦП (это уже было)
2) настраиваем таймер на частоту оцифровки, приемлемая частота 8кГц, разрешаем прерывания от таймера
3) запускается основной цикл программы, в цикле ждем флаг о готовности данных от АЦП, как только готовы - записываем в SPI-флэш, возвращаемся в начало цикла
4) в обработчике прерывания от таймера запускаем преобразование АЦП, ждем окончания преобразования, как только закончилось, выставляем флаг готовности для основного цикла
копипаст теперь делал из STMовского кода (индусского), там неплохо все сделано (имхо):
Спойлер

Код: Выделить всё

#include "stm8s.h"

/* TIM2 define */
#define TIMER_REL_VAL ((uint16_t)0x007D)  /*Auto-reload value to generate a time delay of 125us, after which
                                            overflow interrupt is asserted
                                            Calculations:
                                                fcpu=16MHz, Presc=16
                                                Time Period of counter is 16/(16*10^6) = 1 µs
                                                Time duration required = 125us
                                                Therefore auto-reload counter value = 125us/1µs = 007D*/

uint16_t adc_data;
uint8_t flags;

#define ADC_DATA_READY (uint8_t)(1<<0)

INTERRUPT_HANDLER(TIM2_UPD_OVF_IRQHandler, 13) // TIM2 interrupt routine
{
    /*This interrupt routine is executed after every 125us approx*/

    /* Interrupt generated by UIF */
    ADC1->CR1 |= ADC1_CR1_ADON;     //ADC powered up
    ADC1->CR1 |= ADC1_CR1_ADON;     //begin conversion

    while (!(ADC1->CSR & ADC1_CSR_EOC)) {}; //check for the EOC

    adc_data = ADC1->DRL;           //must read LSBs first
    adc_data |= ADC1->DRH << 8;

    ADC1->CR1 |= ~ADC1_CR1_ADON;    //ADC powered down

    TIM2->SR1 &= ~TIM2_SR1_UIF;     /* Clear UIF flag */
   
    flags |= ADC_DATA_READY;        // set ADC ready flag
}

void TIM2_init(void) // Настройка таймера 2
{
    TIM2->PSCR = 4;                             // init divider register/16
    TIM2->ARRH = (uint8_t)(TIMER_REL_VAL >> 8); // init ARR
    TIM2->ARRL = (uint8_t)(TIMER_REL_VAL);
    TIM2->CR1 |= TIM2_CR1_URS;                  // update on overflow
    TIM2->CR1 |= TIM2_CR1_ARPE;                 // enable auto-reload preload, counter will be free-running
    TIM2->IER = TIM2_IER_UIE;                   // enable update on overflow interrupt
}

void ADC_init( void ) // Настройка АЦП
{
   //AIN6 PIN3
    /* Clear the align bit */
    ADC1->CR2 &= (uint8_t)(~ADC1_CR2_ALIGN);
    /* Configure the data alignment */
    ADC1->CR2 |= (uint8_t)0x08; //Right
    /* Clear the SPSEL bits */
    ADC1->CR1 &= (uint8_t)(~ADC1_CR1_SPSEL);
    /* Select the prescaler division factor according to ADC1_PrescalerSelection values */
    ADC1->CR1 |= (uint8_t)0x60; //fcpu/12
    /* Set the single conversion mode */
    ADC1->CR1 &= (uint8_t)(~ADC1_CR1_CONT);
    /* Clear the ADC1 channels */
    ADC1->CSR &= (uint8_t)(~ADC1_CSR_CH);
    /* Select the ADC1 channel */
    ADC1->CSR |= (uint8_t)(0x06);
    /* Disables the ADC1 Schmitt Trigger on a selected channel */
    ADC1->TDRL |= (uint8_t)((uint8_t)0x01 << (uint8_t)0x06); // Schmitt trigger disable on 6 chanel
}

void main( void )
{
    ADC_init();
    TIM2_init();
    flags = 0;
    asm("rim");
    while (1)
    {   
        while (!(flags & ADC_DATA_READY)) // wait to set flag adc ready
        {
            flags &= ~ADC_DATA_READY;        //clear ADC ready flag
            // далее код для записи значения АЦП в буфер
        }
    }
}

не проверялось, могут быть ошибки (я не волшебник. я еще только учусь.), на всякий случай проект иар прилагаю
STM8Voip.zip
(175.05 КБ) 179 скачиваний
a5021
Друг Кота
Сообщения: 6452
Зарегистрирован: Пт сен 13, 2013 13:11:31

Re: Программирование STM8

Сообщение a5021 »

oleg110592 писал(а):4) в обработчике прерывания от таймера запускаем преобразование АЦП, ждем окончания преобразования,

В обработчике чего-то ждем? Я отказываюсь верить, чтобы такое могли написать даже индусы. Это вообще какой-то ахтунг за гранью добра и зла.
vash_sa
Открыл глаза
Сообщения: 50
Зарегистрирован: Чт сен 04, 2014 13:22:44

Re: Программирование STM8

Сообщение vash_sa »

А чему равен буфер?
Последний раз редактировалось vash_sa Чт май 28, 2015 19:34:18, всего редактировалось 1 раз.
Аватара пользователя
oleg110592
Друг Кота
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Re: Программирование STM8

Сообщение oleg110592 »

могли написать даже индусы

паспорт не видел, ссылку уже давал, могу еще раз:
http://brush-v1.googlecode.com/svn/trun ... stm8s_it.c
предлагаем свои, лучшие варианты
Как в IAR переключается окно отладчика

проект сделан в конфигурации релиз, переключить на дебаг и настроить - тогда будет дебажить по коду
сделал проект с дебагом стлинк
STM8Voip.zip
(321.54 КБ) 169 скачиваний


А чему равен буфер?

буфер будет в spi-флэш
a5021
Друг Кота
Сообщения: 6452
Зарегистрирован: Пт сен 13, 2013 13:11:31

Re: Программирование STM8

Сообщение a5021 »

1) АЦП включить при инициализации и больше не выключать.
2) убрать обслуживание ацп вообще из обработчика прерывания
3) нафиг эти ADON-ы, старт АЦП делать по триггеру с таймера
4) флаг окончания преобразования ловить в основном цикле программ.

Это для начала.
Аватара пользователя
oleg110592
Друг Кота
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Re: Программирование STM8

Сообщение oleg110592 »

отлично, это будет домашнее задание автору
vash_sa
Открыл глаза
Сообщения: 50
Зарегистрирован: Чт сен 04, 2014 13:22:44

Re: Программирование STM8

Сообщение vash_sa »

А можно в коде поправить? А если не справлюсь?
А ADON ацп включается?
Последний раз редактировалось vash_sa Чт май 28, 2015 19:54:56, всего редактировалось 1 раз.
Аватара пользователя
oleg110592
Друг Кота
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Re: Программирование STM8

Сообщение oleg110592 »

Пробуйте. Возникнут вопросы - постараемся помочь.
vash_sa
Открыл глаза
Сообщения: 50
Зарегистрирован: Чт сен 04, 2014 13:22:44

Re: Программирование STM8

Сообщение vash_sa »

Их надо в инициализацию вставить?
А триггер в прерывании где найти?
А что за обслуживание АЦП в прерывании?

INTERRUPT_HANDLER(TIM2_UPD_OVF_IRQHandler, 13) // TIM2 interrupt routine
{
/*This interrupt routine is executed after every 125us approx*/

/* Interrupt generated by UIF */

while (!(ADC1->CSR & ADC1_CSR_EOC)) {}; //check for the EOC - это перенести в основной цикл можно?

adc_data = ADC1->DRL; //must read LSBs first - это запись результата оцифровки?
adc_data |= ADC1->DRH << 8;


TIM2->SR1 &= ~TIM2_SR1_UIF; /* Clear UIF flag */

flags |= ADC_DATA_READY; // set ADC ready flag

}
Последний раз редактировалось vash_sa Чт май 28, 2015 20:20:05, всего редактировалось 1 раз.
Аватара пользователя
oleg110592
Друг Кота
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Re: Программирование STM8

Сообщение oleg110592 »

почитайте для начала AN2658 Application note Using the analog to digital converter of the STM8S microcontroller
http://www.st.com/web/en/resource/techn ... 176594.pdf
a5021
Друг Кота
Сообщения: 6452
Зарегистрирован: Пт сен 13, 2013 13:11:31

Re: Программирование STM8

Сообщение a5021 »

У таймера (TIM1 в нашем случае) есть выход TRGO. Он не выводится наружу и доступен только блокам другой периферии внутрипроцессорно. На этом выходе можно организовать подачу импульса по какому-то событию таймера. Например, переполнению: TIM1->CR2 |= TIM1_TRGOSOURCE_UPDATE. АЦП можно сконфигурировать так, что он будет следить за выходом TRGO и по фронту импульса начинать преобразование: ADC1->CR2 |= ADC1_CR2_EXTTRIG. В этом случае не требуется исполнения какого-либо кода по запуску АЦП, т.к. АЦП будет запускаться аппаратно по команде таймера. Если таймер сконфигурировать так, чтобы событие возникало с частотой 8 кгц, то с той же дискретностью АЦП будет цифровать сигнал с аналогового входа. Программе остается только в основном цикле проверять флаг окончания преобразования (не надо здесь тупо вставать в цикл ожидания) и по его поднятию забирать результат оцифровки из регистра данных АЦП.

При такой организации алгоритма не расходуется время на выполнение лишних прерываний, запуск ацп и ожидание результата преобразования.
Аватара пользователя
oleg110592
Друг Кота
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Re: Программирование STM8

Сообщение oleg110592 »

это перенести в основной цикл можно?

можно, от перестановки мест не сильно поменяется, все равно "вручную" запускаем преобразование АЦП и ждем пока закончится, в adc_data результат

Код: Выделить всё

INTERRUPT_HANDLER(TIM2_UPD_OVF_IRQHandler, 13) // TIM2 interrupt routine
{
    /*This interrupt routine is executed after every 125us approx*/
    TIM2->SR1 &= ~TIM2_SR1_UIF;     /* Clear UIF flag */
    flags |= ADC_DATA_READY;        // set ADC ready flag
}

void main( void )
{
......
        while (!(flags & ADC_DATA_READY)) // wait to set flag adc ready
        {
            flags &= ~ADC_DATA_READY;        //clear ADC ready flag
   
            ADC1->CR1 |= ADC1_CR1_ADON;     //ADC powered up
            ADC1->CR1 |= ADC1_CR1_ADON;     //begin conversion

            while (!(ADC1->CSR & ADC1_CSR_EOC)) {}; //check for the EOC

            adc_data = ADC1->DRL;           //must read LSBs first
            adc_data |= ADC1->DRH << 8;

            ADC1->CR1 |= ~ADC1_CR1_ADON;    //ADC powered down
           
            // далее код для записи значения АЦП в буфер
        }
}

способ, предложенный a5021 намного лучше, только в таком случае вроде можно использовать только TIM1, этот таймер с расширенными возможностями, жалко его использовать, но в этой задаче он как бы больше и не нужен.
Подобный способ работы с АЦП описан в AN3280 Application Note Displaying variable voltage on a bar of LEDs using STM8S-DISCOVERY
http://www.st.com/web/catalog/tools/FM1 ... /PF257975#
vash_sa
Открыл глаза
Сообщения: 50
Зарегистрирован: Чт сен 04, 2014 13:22:44

Re: Программирование STM8

Сообщение vash_sa »

А почему нельзя использовать специализированное прерывание № 22?

INTERRUPT_HANDLER(ADC1_IRQHandler, 22)
{
/* In order to detect unexpected events during development,
it is recommended to set a breakpoint on the following instruction.
*/
}

А можно прямо в теле прерывания поместить код заполнения буфера результатом оцифровки?
При этом не засоряя основной цикл.
a5021
Друг Кота
Сообщения: 6452
Зарегистрирован: Пт сен 13, 2013 13:11:31

Re: Программирование STM8

Сообщение a5021 »

Можно использовать. Просто мне не очень симпатично здесь использование прерываний, т.к. под угрозой нехватки мощи процессора тратить время на вход и выход из прерываний это в определенном смысле расточительно. В исходнике этого не видно, но компилятор добавляет код сохранения состояния перед каждым вызовом обработчика прерывания и подобный же код добавляется при выходе из обработчика. Исполнение этого дополнительного кода вызывает потери времени. В не сильно нагруженных приложениях обычно на это не обращают внимания, но здесь бы лучше от этого уйти.
Аватара пользователя
oleg110592
Друг Кота
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Re: Программирование STM8

Сообщение oleg110592 »

Посчитаем загруженность (для первого способа).
От разрешения и времени выборки зависит скорость АЦП. Время необходимое на одно преобразование считается по такой формуле:
Tconv = (ts+n)/fADC
Из этого легко получить максимальную скорость работы АЦП:
ADCSpeed = fADC/(ts+n)
В этих формулах
fADC — Частота тактового сигнала на АЦП
ts — время выборки (в тактах)
n — разрешение АЦП
Например, при частоте тактирования в 8МГц, разрешении в 10 бит и минимальном времени выборки (4 такта) мы можем получить скорость 571.4 кГц = 1.75мкс.

прерывания происходят каждые 125мкс, после обработки прерывания стартуем:
преобразование займет 1.75мкс (вот это время микроконтроллера мы тратим впустую)
добавим там на всякие проверки и нахождение в прерывании 1.75мкс+?=25мкс (думаю сильно завышено)
итого до следующего прерывания у нас есть время 125-25=100мкс
микроконтроллер работает на частоте 16МГц - один такт 0.0625мкс
у нас есть 1600 тактов
за это время (100мкс) мы успеем записать оцифрованные данные в SPI-флэш
думаю останется еще много времени, в котором микроконтроллер будет просто тупо ждать, пока не наступит следующее прерывание
может где и ошибся
может можно будет обойтись и без флэш буфера - отправлять по UDP один байт (вроде можно) или сформировать буфер в ОЗУ микроконтроллера побольше, потом отправить, надо считать...
a5021
Друг Кота
Сообщения: 6452
Зарегистрирован: Пт сен 13, 2013 13:11:31

Re: Программирование STM8

Сообщение a5021 »

oleg110592 писал(а):Например, при частоте тактирования в 8МГц, разрешении в 10 бит и минимальном времени выборки (4 такта) мы можем получить скорость 571.4 кГц = 1.75мкс.

Цифра верная, но расчет у stm8s производится маленько не так: 1 такт уходит на синхронизацию запуска, три такта на выборку и десять тактов на преобразование. Всего 14 тактов. Способа, как либо поменять эту последовательность RM0016 не приводит.

При частоте АЦП в 8мгц на выборку будет приходиться 3 / 8 = 0.375 микросекунды, каковое время будет достаточно, если цифровать, скажем, батарейку. Для более-менее точных преобразований от источника с бОльшим выходным сопротивлением, 375нс, скорее всего, будет недостаточно. С другой стороны, для цифровки речи особой точности может и не потребоваться, но в любом случае, нужно иметь ввиду, что частоту АЦП, возможно, придется снижать.

думаю останется еще много времени, в котором микроконтроллер будет просто тупо ждать, пока не наступит следующее прерывание

Лучше сразу исходить из того, что времени не останется ни на что (даже если на начальном этапе это не подтверждается расчетами) и писать код заточенный на максимальное быстродействие. Хуже, если в какой-то момент обнаружится недостаток быстродействия и придется лопатить горы ранее написанного с целью оптимизации.
vash_sa
Открыл глаза
Сообщения: 50
Зарегистрирован: Чт сен 04, 2014 13:22:44

Re: Программирование STM8

Сообщение vash_sa »

Спасибо за подробный ответ.
SPI будет задействован на 28J60. Второго у stm8s005k6 нет.
У меня есть spi-флэш 25x80avsig. Питание у нее 3.3 - 3.6В.
Куда ее подсоединять, если SPI занят. Можно подключить параллельно кроме cs, а cs на одну из ног stm8.
Давайте к коду буфера поближе. Для начала предлагаю без spi-флэш в ОЗУ. При реализации web-сервера было условие, чтобы объем разового пакета не превышал 200 байт. Может принять размер буфера 128 байт, чтобы он гарантированно входил в 1 пакет?
Аватара пользователя
oleg110592
Друг Кота
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Re: Программирование STM8

Сообщение oleg110592 »

Можно подключить параллельно кроме cs, а cs на одну из ног stm8

все верно по spi можно подключать параллельно, у каждого свой cs.
код для буфера может быть таким:

Код: Выделить всё

void main( void )
{
  uint8_t buffer[128];
  uint8_t buffer_counter = 0;
..........
            // далее код для записи значения АЦП в буфер
            buffer[buffer_counter++] = (uint8_t)adc_data;
            if(buffer_counter == 128)
            {
                buffer_counter = 0;
                //тут должен быть код для для отправки буфера по UDP
            }
..........
}
a5021
Друг Кота
Сообщения: 6452
Зарегистрирован: Пт сен 13, 2013 13:11:31

Re: Программирование STM8

Сообщение a5021 »

vash_sa писал(а):При реализации web-сервера было условие, чтобы объем разового пакета не превышал 200 байт. Может принять размер буфера 128 байт, чтобы он гарантированно входил в 1 пакет?

Теоретически, размер пакета может быть до 64к, но в целях совместимости и гарантированного прохождения через разнообразное оборудование, есть рекомендации не превышать объем в 508 байт для блока данных. В этой связи нет особого смысла ограничиваться именно 128 байтами и если есть возможность пихать бОльшим куском (200 байт), то стоит ей воспользоваться.
Ответить

Вернуться в «Разные вопросы по МК»