Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Зависание I2C в MSP430f5510
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > MSP430
Konstantin87
Всем привет! Работаю с EEPROM ST m24512 по i2c интерфейсу мк msp430f5510. Запись происходит нормально , но чтении происходит только один раз , при последующих чтениях зависает i2c. Чтение работает с использованием DMA согласно эраташиту, I2C в режиме сингл мастер. Исходный код написан в IAR v5. Вот пример:

---------------------- i2c_dma.asm--------------------------------------------------------------------
#define I2C_SPEED 100000

#define SPEED_COEFF SYS_CLOCK/I2C_SPEED // коэф равен 240 24Мгц/100Кгц



PUBLIC I2C_Init // ф-я инициализации I2c
PUBLIC Get_I2C_ptr // функция возвращает указатель на буффер i2c
PUBLIC I2C_StartTrans // функция осуществляет транзакцию на i2c шине
PUBLIC i2c_state

RSEG DATA

i2c_ptr: DS16 1 // // указатель на текущий считываемый / записываемый байт
i2c_buffer: DS8 EEPROM_PAGE_SIZE+2 // буффер I2C размером 128+2 = 129 байт
i2c_length: DS8 1 // количество байт для приема/передачи
i2c_state: DS8 1 // байт состояния i2c
i2c_last_error: DS8 1 // байт последней ошибки i2c

RSEG CODE
/**********************************/
// инициализация i2c extern void I2C_Init(void);
/***********************************/
I2C_Init:
bis.b #UCSWRST,&UCB1CTL1
mov.b #UCSWRST+UCSSEL_2+UCTR,&UCB1CTL1
mov.b #UCMST+UCMODE_3,&UCB1CTL0
bis.b #BIT1+BIT2,&P4OUT
bis.b #BIT1+BIT2,&P4REN
bic.b #BIT1+BIT2,&P4DIR
bis.b #BIT1+BIT2,&P4SEL
mov.b #LOW(SPEED_COEFF),&UCB1BR0
mov.b #HIGH(SPEED_COEFF),&UCB1BR1
bic.b #UCSWRST,&UCB1CTL1
clr.b &UCB1IFG
bis.b #UCNACKIE+UCALIE+UCTXIE,&UCB1IE
clr.b &i2c_last_error
mov.b #I2C_IDLE,&i2c_state

mov #DMA0TSEL_22,&DMACTL0 // 22 тригер на DMA 0
mov #DMARMWDIS,&DMACTL4
mov #DMADT_0+DMADSTINCR_3+DMASRCINCR_0+DMADSTBYTE+DMASRCBYTE+DMAIE,&DMA0CTL // режим сингл трансфер
movx.a #UCB1RXBUF,&DMA0SA // исходный адресс это UCB1RXBUF
movx.a #i2c_buffer,&DMA0DA // адресс назначения - буффер
reta
/********************************************************************************
****/
// функция обработки транзакции на i2c ; extern signed char I2C_StartTrans(char addr,char count,char state);
/********************************************************************************
*****/
;in R12- адресс устройства на i2c шине
;in R13 - число байт для транзакции
;in R14- состояние (нужен рестарт после транзакции или нет)
;out R12 - выход , код ошибки
I2C_StartTrans:
mov.b #S_OK,&i2c_last_error
mov.b R13,&i2c_length
mov #i2c_buffer,&i2c_ptr
clr.b &UCB1IFG

bit.b #BIT0,R12 // проверяем младший бит в адрессе если 0 - то осуществляем запись , если 1 то чтение
jz __i2cstart0
/********************************************************************/
// receive
/*********************************************************************/
mov.b #I2C_RECEIVE,&i2c_state
bic.b #UCTR,&UCB1CTL1
mov R13,&DMA0SZ // запихиваем количество байт для чтения в DMA0SZ
bis #DMAEN,&DMA0CTL // разрешаем DMA
jmp __i2cstart03
/********************************************************************/
// transmit
/******************************************************************/
__i2cstart0:
mov.b #I2C_TRANSMIT,&i2c_state
bis.b #UCTR,&UCB1CTL1

__i2cstart03:
bis.b R14,&i2c_state
rrc R12
and.b #0x7F,R12

mov R12,&UCB1I2CSA // UCB1I2CSA = R12 >> 1
bis.b #UCTXSTT,&UCB1CTL1 // начинаем транзакцию - посылаем старт

__i2cstart02:
_WDR_a // сброс ватчдога
cmp.b #I2C_IDLE,&i2c_state // ждем пока i2c_state == I2C_IDLE
jne __i2cstart02
__uuip:
bit.b #UCTXNACK+UCTXSTP+UCTXSTT,&UCB1CTL1
jnz __uuip
mov.b &i2c_last_error,R12
reta
/*****************************************************************/
// возвращает указатель на буффер i2c ; extern char* Get_I2C_ptr(void);
/*****************************************************************/
; R12 - указатель на буффер i2c
Get_I2C_ptr:

cmp.b #I2C_IDLE,&i2c_state
jne Get_I2C_ptr
mov #i2c_buffer,R12
reta
/*****************************************************************/
// обработчик прерывания i2c
/***************************************************************/
I2C_INT:
add &UCB1IV,PC
reti
jmp ALIFG_ISR ; artbitration lost
jmp NACKIFF_ISR ; nack return
jmp STTIFG_ISR ; start received
jmp STPIFG_ISR ; stop received
jmp RXIFG_ISR ; data received
TXIFG_ISR: ; transmit buffer empty

tst.b &i2c_length // пока i2c_length != 0 то шлем байты из буффера
jnz __i2ctxifg0
bic.b #UCTXIFG,&UCB1IFG // если i2c_length == 0 то i2c_state = I2C_IDLE и проверяем нужен ли рестарт, если не нужен просто выходим из
// интерапта
bit.b #I2C_ENABLE_RESTART,&i2c_state
mov.b #I2C_IDLE,&i2c_state
jnz __i2ctxifg_ex
bis.b #UCTXSTP,&UCB1CTL1
reti
__i2ctxifg0:
push.w r12
mov &i2c_ptr,r12
mov.b @R12+,&UCB1TXBUF
mov R12,&i2c_ptr
dec.b &i2c_length
pop.w r12
__i2ctxifg_ex:
reti
// если арбитраж потерян (не нужно в синглмастере)
ALIFG_ISR:
mov.b #I2C_ARBITRATION_LOST,&i2c_last_error
jmp __inti2c0
// если принят NACK возвращаем код ошибки
NACKIFF_ISR:
mov.b #I2C_NACK_RETURN,&i2c_last_error
__inti2c0:
clr.b &UCB1IFG
mov.b #I2C_IDLE,&i2c_state
bis.b #UCTXSTP,&UCB1CTL1
reti
STTIFG_ISR:
STPIFG_ISR:
reti
RXIFG_ISR: // не используем так как есть DMA
reti

COMMON INTVEC
ORG USCI_B1_VECTOR
DW I2C_INT
END

---------------------- dma.asm--------------------------------------------------------------------

EXTERN i2c_state
EXTERN I2C_Init
RSEG CODE
/***************************************************************************/
// обработчик прерывания от DMA вызывается когда прочитано нужно число байт
/***************************************************************************/
DMA_HANDLER:
add &DMAIV,PC
reti
jmp DMA0_HND
jmp DMA1_HND
jmp DMA2_HND
reti
reti
reti
reti
reti
DMA0_HND:
bic.b #UCRXIFG,&UCB1IFG // UCB1IFG &= ~UCRXIFG
mov.b #I2C_IDLE,&i2c_state // i2c_state = I2C_IDLE
bis.b #UCTXNACK+UCTXSTP,&UCB1CTL1 // формируем NACK и стоп
__uuuu:
bit.b #UCBBUSY,&UCB1STAT // ждем освобождения i2c
jnz __uuuu
// calla #I2C_Init // !!!!! костыль , если его воткнуть то прием будет работать иначе будет работать только один раз

DMA1_HND:
DMA2_HND:
reti

COMMON INTVEC
ORG DMA_VECTOR
DW DMA_HANDLER
END
----------------------------------------------------------eeprom.c-----------------------------------------------------------------------------------


extern signed char I2C_StartTrans(uchar addr, uchar count, char state);
extern char* Get_I2C_ptr(void);


// addr - адресс считывания
// ptr - указатель куда скопировать прочитанное
// count - количество байт нужное считать

char eeprom_read_bytes(ushort addr,uchar* ptr, uchar count)
{
char hr;
uchar* ptr2;

if(count > EEPROM_PAGE_SIZE) // проверяем количество байт - должно быть меньше чем буффер i2c
return EEPROM_IVALID_SIZE;

ptr2 = Get_I2C_ptr(); // получаем указатель на буффер i2c

*ptr2 = (BYTE)(addr >> 8); // запихиваем в буффер адресс (16 бит)
*(ptr2+1) = (BYTE)(addr&0x00FF);
hr = I2C_StartTrans(EERPOM_I2C_ADDR&WRITE_OP,2,RESTART_AFTER_TRANSACTION); // отправляем в eeprom адресс и
//генерируем рестарт
hr = I2C_StartTrans(EERPOM_I2C_ADDR|READ_OP,count,STOP_AFTER_TRANSACTION); // считываем в буффер count байт из
//eeprom и генерирует стоп
memcpy_m(ptr,ptr2,count) ; // копируем из буффера i2c в ptr
return hr; // возвращаем код ошибки
}


Уже 2 неделю никак не могу толком настроить i2c. Хотя софтварная эмуляция функций (i2c на портах) I2C_StartTrans и I2c_init работает без проблем. ТАкже работает без проблем если после каждого чтения переинициализировать i2c.
Bloom
логический анализатор есть? по картинке проще понять что происходит
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.