Телесистемы
 Разработка, производство и продажа радиоэлектронной аппаратуры
На главную   | Карта сайта | Пишите нам | В избранное
Требуется программист в Зеленограде
- обработка данных с датчиков; ColdFire; 40 тыс.
e-mail:jobsmp@pochta.ru

Телесистемы | Электроника | Конференция «Микроконтроллеры и их применение»

ATmega88 + TWI + sleep_mode - не возвращается из спячки

Отправлено cz0 04 ноября 2008 г. 13:44


Пытаюсь сделать дисплей с управлением по I2C. Столкнулся со следующей проблемой. Ранее, когда для эксперементов в качестве микроконтроллера использовалась mega8 все было замечательно, однако на плате требуется применить TQFP и появилось желание переползти на mega88 - вот сдесь то и началась интересности. Тотже код (за исключением регистров, которые пришлось поменять в соответсвии с mega88) не работает. Оно просто не просыпается из спячки и все тут. Интересно, что если усыпить кирпич по команде, которая пришла через i2c, то он проснется, однако если сделать это в бесконечном цикле в main'е (как делают все нормальные люди) то ждать можно до бесконечности. К тому же, mega8 потребляла 3,5 мА, текущий же вариант ест 8. Хочется разобраться и понять в чем проблема. Актуальный код для avr-gcc приложен ниже. Если в бесконечном цикле в main'е заменить POWER_IDLE на что-нить, где работает нужный мне таймер2 (POWER_SAVE хотя бы), то оно уже никогда не проснется.

#include "hardware.h"
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include "twi_slave.h"
#include "global.h"

static uint16_t cPWM;
uint8_t i2c_rxbuffer[8];

/* Timer2 overflow interrupt */
ISR(TIMER2_OVF_vect)
{
OCR2A = cPWM;
}

void b2sr(uint8_t idata)
{
auto uint8_t counter;

for (counter = 8; counter > 0; counter--)
{
SET_BIT(PORTB, SR_DATA, (idata & 0x80) >> 7);

SET_BIT_1(PORTB, SR_SC);
SET_BIT_0(PORTB, SR_SC);

idata <<= 1;
}
}

void display_brightness(uint16_t value)
{
value *= 5;
cPWM = value / 2 + value / 84;
}

/* Процедура обновления данных экрана */
void display_out(uint8_t d1, uint8_t d2, uint8_t d3)
{
/* Обновляем данные в сдвиговых регистрах */
b2sr(d3);
b2sr(d2);
b2sr(d1);

SET_BIT_0(PORTB, SR_LC);
SET_BIT_1(PORTB, SR_LC);
}

/* Switch display on and configure it for displaing new data*/
void display_on(void)
{
//sleep_disable();
TCCR2A |= (1 << WGM20) | (1 << COM2A1);
TCCR2B |= (1 << CS21);

TIMSK2 |= (1 << TOIE2);
sei();
}

/* Switch display off to consum less power */
void display_off(void)
{
TCCR2B &= ~((1 << CS20) | (1 << CS21) | (1 << CS22));
TIMSK2 &= ~(1 << TOIE2);

display_out(0x00, 0x00, 0x00);

PORTB &= ~((1 << PWM) | (1 << SR_DATA) | (1 << SR_SC) | (1 << SR_LC));
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sei();
sleep_mode();
}

/* This function will run when master adresses us and writes data */
void i2c_rxservice(uint8_t length, uint8_t* data)
{
uint8_t counter;
for (counter = 0; counter <= length; counter++)
i2c_rxbuffer[counter] = *data++;

switch (i2c_rxbuffer[0])
{
case 'd':
display_out(i2c_rxbuffer[1], i2c_rxbuffer[2], i2c_rxbuffer[3]);
break;
case 'b':
display_brightness(i2c_rxbuffer[1]);
break;
case 'p':
if (i2c_rxbuffer[1] == '0') display_off();
if (i2c_rxbuffer[1] == '1') display_on();
break;
default:
break;
}
}

int main(void)
{
DDRB |= (1 << PWM) | (1 << SR_DATA) | (1 << SR_SC) | (1 << SR_LC);

CLKPR = 0x80;
CLKPR = 0x02;

twi_slave_init(I2C_DISPLAY_ADRESS);
twi_slave_setrxhandler(i2c_rxservice);

display_off();

while(1)
{
set_sleep_mode(SLEEP_MODE_IDLE);
sleep_mode();
}

return(0);
}


Составить ответ | Вернуться на конференцию

Ответы


Отправка ответа
Имя*: 
Пароль: 
E-mail: 
Тема*:

Сообщение:

Ссылка на URL: 
URL изображения: 

если вы незарегистрированный на форуме пользователь, то
для успешного добавления сообщения заполните поле, как указано ниже:
увеличьте 3 в два раза:

Перейти к списку ответов | Конференция | Раздел "Электроника" | Главная страница | Карта сайта

Rambler's Top100 Рейтинг@Mail.ru
 
Web telesys.ru