Jump to content

    
Sign in to follow this  
Avratmega

Зависание I2C в MSP430f5510

Recommended Posts

Всем привет! Работаю с 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.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this