29.05.2023, 13:18
|
#1
|
Гражданин KAZUS.RU
Регистрация: 21.02.2007
Сообщений: 553
Сказал спасибо: 38
Сказали Спасибо 17 раз(а) в 16 сообщении(ях)
|
Не работает прерывание I2C
Здравствуйте.
Надо подружить по I2C два МК.
PIC24FV32KA302 (мастер)
PIC24FV16KM202 (слейв)
Для мастера написал код инициализации и опроса:
Код:
|
void I2C_Initialize(void) {
// Настройка пинов порта I2C
SDA1_TRIS = 1; // SDA (пин для приема/передачи данных)
SCL1_TRIS = 1; // SCL (пин для управления тактированием)
// Настройка модуля I2C
I2C1CONbits.I2CEN = 0; // Отключение модуля I2C перед настройкой
// Настройка скорости передачи
I2C1BRG = 157; //100 кгц при 16мгц частоте циклов
// Включение модуля I2C
I2C1CONbits.I2CEN = 1;
}
// Проверка наличия устройства на шине I2C
unsigned char I2C_CheckDevicePresence(unsigned char deviceAddress) {
// Начало передачи
I2C1CONbits.SEN = 1;
// Ожидание окончания стартового условия
while (I2C1CONbits.SEN) {
Nop();
}
// Отправка адреса устройства и бита записи (0)
I2C1TRN = (deviceAddress ‹‹ 1) | 0;
// Ожидание окончания передачи адреса
while (I2C1STATbits.TRSTAT) {
Nop();
}
// Проверка статуса передачи адреса
if (I2C1STATbits.ACKSTAT) {
// Устройство не отвечает
return 0;
}
// Остановка передачи
I2C1CONbits.PEN = 1;
// Ожидание окончания условия стопа
while (I2C1CONbits.PEN) {
Nop();
}
return 1;
} |
Для слейва код:
Код:
|
/* Инициализация I2C*/
void I2C_Initialize(void) {
// Настройка пинов порта I2C
SDA1_TRIS = 1; // SDA (пин для приема/передачи данных)
SCL1_TRIS = 1; // SCL (пин для управления тактированием)
SSP1STAT = 0;
SSP1STATbits.SMP = 1; // Фаза выборки данных
SSP1STATbits.CKE =0;
SSP1CON1 = 0;
SSP1CON1bits.SSPM = 0b1110; // Режим I2C Slave 7-bit адрес
I2C2ADD = 0x5D; // Load slave address
// Включение прерываний MSSP/I2C
IFS1bits.SSP1IF = 0; // Сброс флага прерывания
IEC1bits.SSP1IE = 1; // Включение прерывания
IPC4bits.SSP1IP = 6;
// Включение модуля MSSP/I2C
SSP1CON1bits.SSPEN = 1;
}
И в прерывании обработка:
void __attribute__((interrupt, no_auto_psv)) _MSSP1Interrupt(void) {
uint8_t tmp = 0;
uint8_t buf[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
if (IFS1bits.SSP1IF) {
//IFS1bits.SSP1IF = 0; // Сброс флага прерывания
buf[0] = 1;
if (SSP1STATbits.R_NOT_W == 1) {
buf[2] = 1;
// Master read (slave transmit)
SSP1BUF = TxBuf[TxPos++]; // Load array value
if (RxPos == BUF_LEN) // Достигнут конец передачи данных
{
RxPos = 0;
}
SSP1CON1bits.CKP = 1; // Release clock stretch
} else if (SSP1STATbits.R_NOT_W == 0) {
buf[3] = 1;
// Master write (slave receive)
// Если принимаются данные
if (SSP1STATbits.D_NOT_A == 0) {
buf[4] = 1;
buf[5] = SSP1BUF;
tmp = SSP1BUF; // Clear BF
if (tmp == SSP1ADD) {
buf[6] = 1;
SSP1CON2bits.ACKDT = 0; // Установка ACK (Acknowledge)
TxPos = 0;
RxPos = 0;
}
} else {
tmp = SSP1BUF; // Clear BF
if (RxPos ‹ BUF_LEN) {
RxBuf[RxPos] = tmp;
}
}
SSP1CON1bits.CKP = 1;
}
PutEEPROM(2, buf, 10);
}
} |
У мастера основной код опроса:
Код:
|
unsigned char PlayerAdr = 0x5d;
unsigned long tm = 0;
while (1) {
for (unsigned char i = 1; i ‹ 127;i++) {
if (I2C_CheckDevicePresence(i)) {
uint8_t dat[]={i,0,2,3};
PutEEPROM(32, dat, 4);
while (1) {
ActivateSound(GetNoteFreq(DO, OCTAVE_3), 500);
PauseTicks(tm, 200000);
ActivateSound(GetNoteFreq(MI, OCTAVE_2), 100);
PauseTicks(tm, 200000);
}
}
}
Nop();
} |
Но почему то не срабатывает прерывание у слейва. По прерыванию он должен был в еепром схранить лог но в еепром пусто. Я делаю вывод что не срабатывает прерывание.
Хотя в анализаторе видно что мастер запросы вроде как отправляет.
Что я не так сделал то??
|
|
|
|
29.05.2023, 14:54
|
#2
|
Гражданин KAZUS.RU
Регистрация: 17.06.2008
Адрес: Украина
Сообщений: 748
Сказал спасибо: 365
Сказали Спасибо 822 раз(а) в 386 сообщении(ях)
|
Re: Не работает прерывание I2C
Сообщение от worldmasters
|
По прерыванию он должен был в еепром схранить лог но в еепром пусто. Я делаю вывод что не срабатывает прерывание.
|
Ну, такой же результат может наблюдаться и при неработоспособности функции записи в EEPROM )
Если не используется "железная" отладка, то можно в интересующих местах программы дергать специально выделенными пинами МК и наблюдать их лог. анализатором (это один из способов вывода отладочной информации).
ИМХО для начала стОит добиться работы I2C слейва не задействуя механизм прерываний - путем опроса флагов модуля I2C прямо в main-e, чтобы main() только этим и занимался. После того как прием заработает как положено, переместить функционал в обработчик прерывания.
И да, речь не идет о симуляторах..
|
|
|
|
29.05.2023, 16:50
|
#3
|
Гражданин KAZUS.RU
Регистрация: 21.02.2007
Сообщений: 553
Сказал спасибо: 38
Сказали Спасибо 17 раз(а) в 16 сообщении(ях)
|
Сообщение от j-Roger
|
Ну, такой же результат может наблюдаться и при неработоспособности функции записи в EEPROM )
|
Да функция отлажена и работает. При старте программы вписываю первыми 2 байта. И затем при чтении еепром я эти байты наблюдаю.
Сообщение от j-Roger
|
И да, речь не идет о симуляторах..
|
Да это понятно.
Прерывание все таки работает но почему то в буфере какой то шлак попадается:
сделал уже запись данных при получении в буфер и в еепром.
Код:
|
tmp = SSP1BUF & 0x00ff; // Clear BF
if (SSP1STATbits.D_NOT_A == 0) {
PLAYER_BUSY_O = !PLAYER_BUSY_I;
if (tmp == I2C2ADD) {
SSP1CON2bits.ACKDT = 0; // Установка ACK (Acknowledge)
TxPos = 0;
RxPos = 0;
buf[9] = 0xb1b2;
}
buf[id++] = tmp;
if (id › 8) {
PutEEPROM(2, (uint8_t*) & buf[0], 20);
PLAYER_BUSY_O = 1;
id = 1;
while (1)Nop();
} |
Уже и менял параметры:
Код:
|
SSP1CON2bits.SEN = 0;
SSP1CON3bits.AHEN = 1;
SSP1CON3bits.DHEN = 1; |
Но все равно записывается разное число но не адрес. Мастер шлет 0x22 всегда. Анализатор это подтверждает.
Что с ним не так то.
Подтяжка стоит 4,7 кОм.
Последний раз редактировалось mike-y-k; 30.05.2023 в 00:23.
Причина: 6.6
|
|
|
|
29.05.2023, 17:46
|
#4
|
Гражданин KAZUS.RU
Регистрация: 17.06.2008
Адрес: Украина
Сообщений: 748
Сказал спасибо: 365
Сказали Спасибо 822 раз(а) в 386 сообщении(ях)
|
Re: Не работает прерывание I2C
В документе TB3251 - Using the MSSP in I2C Slave Mode приведены фрагменты кода, по которым можно сверить настройки ( учитывая особенности модуля прерываний конкретного МК ).
P. S.
Не используем PIC24, поэтому ответы на вопросы имеют весьма общий характер.
|
|
|
|
30.05.2023, 14:37
|
#5
|
Гражданин KAZUS.RU
Регистрация: 21.02.2007
Сообщений: 553
Сказал спасибо: 38
Сказали Спасибо 17 раз(а) в 16 сообщении(ях)
|
Спасибо. Именно по этому документу и сверяюсь. Но все равно дичь какая то.
Эх..
Кстати по какой то неведомой причине если я ставлю в прерывании код:
Код:
|
if(!SSP1STATbits.BF)
return; |
То заход дальше этого не происходит вообще. Хотя по идее это же не правильно потому что событие должно происходить когда в буфере естьданные.
Последний раз редактировалось mike-y-k; 30.05.2023 в 21:30.
Причина: 6.6
|
|
|
|
Ваши права в разделе
|
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 02:10.
|
|