Форум программистов, компьютерный форум, киберфорум
Микроконтроллеры ATmega AVR
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.88/8: Рейтинг темы: голосов - 8, средняя оценка - 4.88
1 / 1 / 0
Регистрация: 29.10.2017
Сообщений: 15
1

Модуль SPI не работает на высоких частотах

23.12.2017, 01:17. Показов 1486. Ответов 7
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Здравствуйте. У меня в процессе написания программы возник один весьма важный вопрос, который сам я решить так и не смог. Может быть, кому-нибудь приходилось сталкиваться с подобным, хотелось бы узнать решение.
Итак, в чём суть. Я писал программу на ATMega128 для внешнего ЦАП типа MCP4921. Задача -- генерировать при помощи этого ЦАП синусоидальный сигнал частотой от 100 Гц до 1кГц. Вкратце, принцип работы таков:

1) определяем, каким количеством значений будет описываться сигнал (в программе -- константа N);
2) вводим таймер-счётчик(№3), который с частотой, в N раз большей, чем желаемая частота выходного сигнала
(ICR3 = F_CPU / f / N), будет обновлять (инкрементировать) значение некоторой переменной (dt);
3) в цикле while(1) происходит вычисление соответствующего значения сигнала и передача данных на ЦАП.

Вот такой получился код:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 10000000UL
#include <math.h>
#include <util/delay.h>
 
 
#define DD_MOSI      PB2 // Вывод ножки MOSI
#define DD_SCK       PB1 // Вывод ножки SCK
 
/* Макрос команды перевода ножки CS ЦАП в состояние лог. "1" */
#define DAC_CS_HIGH  DDRB |= (1<<PB4); PORTB |= (1<<PB4);
/* Макрос команды перевода ножки CS ЦАП в состояние лог. "0" */
#define DAC_CS_LOW   DDRB |= (1<<PB4); PORTB &=~(1<<PB4);
/* Макрос команды перевода ножки LD ЦАП в состояние лог. "1" */
#define DAC_LD_HIGH  DDRB |= (1<<PB5); PORTB |= (1<<PB5);
/* Макрос команды перевода ножки LD АЦП в состояние лог. "0" */
#define DAC_LD_LOW   DDRB |= (1<<PB5); PORTB &=~(1<<PB5);
 
#define A_B 7
#define BUF 6
#define GA 5
#define SHDN 4
 
#define N 20 // число точек (значений), используемых для формирования сигнала; 
              
volatile uint16_t f = 100;
volatile uint16_t n = 0;
volatile uint16_t dt = 0;
 
/*volatile uint16_t sin_buf[20] = {2048, 2681, 3252, 3705, 3996, 4095, 3996, 3705, 3252, 2681, 2048, 1415, 844, 391, 100, 0, 100, 391, 844, 1415};*/
 
volatile uint16_t dac_data = 0;
volatile uint16_t h = 0;
volatile uint16_t l = 0;
volatile uint8_t dac_data_h = 0;
volatile uint8_t dac_data_l = 0;
 
 
/* Функция инициализации мастера шины SPI */
 
void SPI_MasterInit(void) {
    /* Установка выводов MOSI и SCK на вывод */
    DDRB = (1<<DD_MOSI)|(1<<DD_SCK);
    /* Включение SPI, режима ведущего, и установка частоты тактирования fclk/4 */
    SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPI2X);
};
 
 
/* Функция передачи байта данных outData*/
 
unsigned char SPI_MasterTransmit(char outData) {
    /* Начало передачи */
    SPDR = outData;
    /* Ожидание окончания передачи */
    while(!(SPSR & (1<<SPIF))) ;
    return SPDR;
};
 
ISR(TIMER3_CAPT_vect){
        dt++;
        if (dt > N){
        dt = 0;
        }
 
    if (n == 0){
        f = 100;
    }
    else if (n == 1){
        f = 200;
    }
    else if (n == 2){
        f = 500;
    }
    else if (n == 3){
        f = 10000;
    }
    
    ICR3 = F_CPU / f / N;
    
}
 
 
int main(void)
{
    SPI_MasterInit();
    
    DAC_CS_HIGH;
    DAC_LD_LOW;
    
    /* Инициализация таймера-счётчика №3 */
    TCNT3 = 0;
    
    ICR3 = F_CPU / f / N;
    
    TCCR3A = (1 << COM3A0);
    TCCR3B = (1 << WGM33) | (1 << WGM32) | (1 << CS30);
    TCCR3C = 0x00;
    
    ETIMSK |= (1 << TICIE3);
    
    //DDRE |= (1 << 3);
        
    sei();
    
    dac_data_h = ((1 << GA)|(1 << SHDN)|(1 << 3));   
    dac_data_l = 0;
        
    while(1)
    {
        if (PINA & (1 << 1)){
            ++n;
            _delay_ms(300);
            if (n > 3){
                n = 0;
            }
        }
    
                
        /* Передача данных */
        
        h = l = dac_data = (sin(2*M_PI/N * x) + 1) * 2047;  
        
        h = h >> 8;
        l &= 0x00FF;
 
        dac_data_h = ((1 << GA)|(1 << SHDN));
        dac_data_h |= h;
        
                dac_data_l = l;
        
        DAC_CS_LOW;
        SPI_MasterTransmit(dac_data_h);
        SPI_MasterTransmit(dac_data_l);
        DAC_CS_HIGH;
                
    }
}
На практике выяснилась вот такая проблема. При частоте прерываний таймера-счётчика в 10 кГц и более сигнал не генерируется. При мониторинге осциллографом выяснил, что на ЦАП при этой частоте не приходят ни данные, ни сигнал синхронизации. Думал, что проблема в низкой скорости передачи, однако повышение частоты передачи до максимальной (F_CPU/2) проблему не решило. Тем более, что чтение datasheet'ов и собственные расчёты показали, что 100 мкс вполне достаточно для передачи 2 байт. На всякий случай ввёл массив значений, чтобы избавить МК от вычислений, но не помогло...

В связи с этим у меня вопрос: чем обусловлена такая проблема? Полагаю, что проблема обусловлена взаимодействием модуля SPI и таймера-счётчика, так как без таймера синусоида в 1 кГц вполне себе получается. Но почему так происходит и возможно ли всё-таки совместить оба этих модуля так, чтобы они вместе работали на частоте от 10кГц и более?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
23.12.2017, 01:17
Ответы с готовыми решениями:

Процессор в простое на высоких частотах а в игре на минимальных
Добрый день! Я здесь впервые как зареганый именно участник но часто читаю форум. Так вот пожалуй...

Почему оксидные конденсаторы нельзя применять на высоких частотах?
Доброго времени суток! Подскажите, пожалуйста, почему оксидные конденсаторы нельзя применять на...

Не работает на заявленных частотах
Есть 2 плашки CRUCIAL Ballistix Sport LT BLS2K8G4D32AESCK DDR4 — 8Гб 3200, Стоят они на ASROCK...

Память не работает на заявленных частотах
Память работает на частоте 935 мгц,заявлено 1600. Материнка поддерживает до 2400.Как исправить?...

Видеокарта работает на минимальных частотах
Ноутбук с дискретной nVidia GeForce GT540m и встроенной которая вообще не работает Intel HD3000,...

7
1624 / 806 / 146
Регистрация: 13.06.2015
Сообщений: 3,266
23.12.2017, 18:18 2
SlavVlad, у вас какой-то странный подход в виде разделения отсчёта по таймеру и самой передачи. По-нормальному надо уж или всё делать (включая расчёты) по таймеру, или всё делать делать в общем бесконечном цикле с задержкой через delay (второй вариант намного хуже).
Очень много раз реализовывал то, что вы задумали. Всегда весь код лежал в обработчике таймера.
0
210 / 163 / 36
Регистрация: 15.11.2012
Сообщений: 788
24.12.2017, 04:35 3
А что у вас подается на вывод Input Capture таймера 3? Ведь прерывания таймера происходят именно по нему у вас. И если туда что-то приходит слишком часто - может оказаться, что процессор непрерывно занят обработкой прерывания.

Вычисление sin занимает много времени, ни о каких десятках (и даже единицах) килогерц речи не будет.
Я не возьмусь предсказать результат выражения h = l = dac_data = (sin(2*M_PI/N * x) + 1) * 2047 с учетом того, что все переменные в нем - целые (включая переменные результата). И где, кстати, объявление переменной x?
0
1 / 1 / 0
Регистрация: 29.10.2017
Сообщений: 15
24.12.2017, 14:38  [ТС] 4
Kukuxumushu, спасибо за ответ, попробую все расчёты в прерывание поместить. Через задержки, кстати, получилось, и да, действительно грубый метод, т.к. пришлось подгонять значения этих задержек.

Добавлено через 12 минут
alexey6689, на сам вывод ICP3 ничего не подаётся, используется только регистр ICR3 для настройки частоты прерываний. Насчёт вычисления функции sin соглашусь, я тоже подозревал, что её не следует здесь применять. После того, как я вместо неё стал использовать массив значений, ситуация несколько улучшилась, но при 10 кГц всё равно проблема наблюдается.

Что касается переменной x. Я совсем недавно переименовал эту переменную в dt, а в формуле она осталась со старым именем, так как формула давно была закомментирована, и я не обратил на это внимания.
0
210 / 163 / 36
Регистрация: 15.11.2012
Сообщений: 788
24.12.2017, 14:43 5
Так тогда вроде как следует использовать прерывание по переполнению, а не по Input Capture. Поскольку я вообще не понимаю, почему оно у вас вызывается.
0
1 / 1 / 0
Регистрация: 29.10.2017
Сообщений: 15
24.12.2017, 15:12  [ТС] 6
alexey6689, У меня таймер настроен под режим CTC, при этом верхний предел счёта заложен в ICR3. При достижении этого предела и должно произойти прерывание. Идея такова. Я до сих пор думал, что для реализации такого прерывания нужно разрешить именно TICIE3, а не TOIE3. Неужели это ошибка?
0
210 / 163 / 36
Регистрация: 15.11.2012
Сообщений: 788
24.12.2017, 22:39 7
Да, это ошибка.
Ваш таймер, по моему опыту, вообще не должен вызывать прерываний.

Добавлено через 56 секунд
Я имею в виду - в вашей нынешней программе прерывания таймера вызываться не могут.
0
1 / 1 / 0
Регистрация: 29.10.2017
Сообщений: 15
25.12.2017, 01:45  [ТС] 8
По-моему опыту, прерывания будут работать, но, похоже, неправильно :-) .
Однако... У меня около десятка программ на таком принципе построено. Надеюсь, благодаря Вашему совету я исправлю не одну ошибку. Спасибо за совет
0
25.12.2017, 01:45
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
25.12.2017, 01:45
Помогаю со студенческими работами здесь

Не работает ОЗУ на своих частотах
Сначала начну с характеристик: Процессор: Ryzen 5 1600 (3825 Mhz); Материнка:...

Видеокарта работает на минимальных частотах
В общем в чем суть проблемы. Видеокарта GeForce GTX 460 SE. Летает себе нормально без нареканий, но...

Камень работает на минимальных частотах
Проц AMD Athlon 64 X2 4800+ Материнка MSI MS-7369 в простое (около минуты) СPU-Z и AIDA64...

Видеокарта работает на 3D частотах в браузере
Открываю Гугл,и моя 1060 моментально повышает частоты до 1620,соответственно начинает греться до 50...

Видеокарта 1650 работает на пониженных частотах
Видеокарта 1650 работает на пониженных частотах 300мгц - как следствие низкий фпс, при этом память...

Подскажите озу работает не на заявленных частотах
Процессор - I7 8700к Видео - 1080 gtx palit б/п - 750вт super flower мать - asrock z 370 gaming...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
8
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru