Микроконтролери и електроника
http://mcu-bg.com/mcu_site/

I2C MSSP PIC16F87xx
http://mcu-bg.com/mcu_site/viewtopic.php?f=3&t=837
Страница 1 от 1

Автор:  [ Чет Юли 07, 2005 11:16 am ]
Заглавие:  I2C MSSP PIC16F87xx

Колеги, 3 дена се боря както опълченците на Шипка с MSSP модула на PIC16FXX професорите ( вече роня крокодилски сълзи :cry: ) Искам да чета/пиша буфер от 32 или 64 байта в 24LC515, обаче не ще и не ще пущината ... Пробвам с драйверите на CCS, обаче те работят коректно само ако пиша/чета по един байт, като ги пусна на буфер правят каквото си искат. Имам едни мои драйвери, които съм си писал преди 2-3 години и са работили коректно досега с друг MSSP модул и с I2C модула на I80552, както и с Neuron професор:

Код:
#define I2C_SLAVE   0xA0
//#define I2C_SPEED   ( ( CRYSTAL / ( 4 * 50000 ) ) - 1 )   // pull-up = 10k
#define I2C_SPEED   ( ( CRYSTAL / ( 4 * 100000 ) ) - 1 )   // pull-up = 10k
//#define I2C_SPEED   ( ( CRYSTAL / ( 4 * 400000 ) ) - 1 )   // pull-up = 2k
//#define I2C_SPEED   ( ( CRYSTAL / ( 4 * 1000000 ) ) - 1 )   // pull-up = 2k
#define I2C_PAGE_SIZE   64
#define I2C_HALF_PAGE   ( I2C_PAGE_SIZE / 2 )
#define I2C_MEM_SIZE 65536

#define M24515

unsigned int16 i2caddr;
#byte i2caddr_low=i2caddr
#byte i2caddr_high=i2caddr+1
int8 i2cslave,i2cflags,i2cdata,i2ccount,i2ctemp;
#bit i2cerr=i2cflags.0
#bit i2c_page_cross=i2cflags.1
int8   i2cpage[I2C_PAGE_SIZE];
#byte i2cpage=0xA0


// Initialize MSSP for Master I2C mode operation
void I2CInitMaster(void)   {
   i2cslave = I2C_SLAVE;
   SSPCON = 0;
   SSPIE = 0;            // Disable interrupt from I2C module
   TRISC |= 0b00011000;   // Make SCL & SDA to be inputs
   SMP = 1;            //  enable 100KHz & 1MHz !
   CKE = 0;            //   I2C specification !
   GCEN = 0;            //    disable interrupt when detect general call address on the i2c bus .
   SSPADD = I2C_SPEED;
   SSPCON = 0x08;         //   Master mode, 7-bit address, clock=(Fosc/(4*I2CClock))-1;
   SSPIF = 0;
   SSPEN = 1;            //    Enable I2C port
}

// I2CIdle() - from 00735A.PDF
void I2CIdle(void)   {
   while( R_W );   // Check for transmit in progres. If in progress wait.
   while( SSPCON2 & 0x1F );
}

void I2CWait(void)   {
   while( ! SSPIF );
   SSPIF = 0;
}

void I2CWrite(char data)   {
   SSPBUF = data;
   I2CWait();
// In Master Transmit Mode: Check for Acknowledge
   i2cerr = 0;
   if( ACKSTAT )
      i2cerr = 1;
}

void I2CIsFree(void)   {
   i2cerr = 1;
   if( I2C_STOP || ! I2C_START )
      i2cerr = 0;
}

void I2CStart(void) {
   SEN = 1;      // Initiate Start condition
   I2CWait();
}

void I2CSStart(void)   {
   RSEN = 1;                  // Second Start condition
   I2CWait();
   I2CWrite( i2cslave | 0x01 );   // Set Read operation
}

void I2CStop(void)   {
   PEN   = 1;      // Generate STOP condition
   I2CWait();
}

void I2CAck(void)   {
// In Master receive mode: Value that will be transmitted when the user
// initiates an Acknowledge sequence at the end of a receive.
//
   ACKDT = 0;      //   Acknowledge
// In Master receive mode: Initiate Acknowledge sequence on SDA & SCL
// and transmit ACKDT data bit. Automatically cleared by hardware
//
   ACKEN = 1;
   I2CWait();
}

void I2CMasterAck(void)   {
// In Master receive mode: Value that will be transmitted when the user
// initiates an Acknowledge sequence at the end of a receive.
//
   ACKDT = 1;      // Not Acknowledge
// In Master receive mode: Initiate Acknowledge sequence on SDA & SCL
// and transmit ACKDT data bit. Automatically cleared by hardware
//
   ACKEN = 1;
   I2CWait();
}

char I2CRead(void)   {
   while( R_W );         // Wait for transmit to end ...
   RCEN = 1;            // Enter Master mode reception
   I2CWait();            // Wait to receive one byte
   return SSPBUF;
}

void I2CPageCross(void) {
   i2c_page_cross = 0;
   if( ! bit_test(i2caddr,15) && bit_test( i2caddr + (int16)i2ccount, 15 ) )
      i2c_page_cross = 1;
}

void I2CRestoreAddress(void) {
   i2caddr -= (i2ctemp-1);
}

// I2CWriteAddr()
void I2CWriteAddr(void)   {
   WCOL = 0;
   I2CIsFree();         // If I2C is free ?
   if(   i2cerr )
      return;            // bus is busy !
   I2CStart();            // Send Start signal
#ifdef M24515
   if( bit_test(i2caddr,15) )
      i2cslave |= 0x08;
   else
      i2cslave &= ~0x08;
#endif
   I2CWrite( i2cslave );   // Set Write operation
   if( i2cerr )
      return;
   I2CWrite( i2caddr_high );   // Send high byte of address
   if( i2cerr )
      return;
   I2CWrite( i2caddr_low );         //   Send low byte of address
}

char I2CReadByte(void)   {
   I2CWriteAddr();         // Write address in address registers
   if( i2cerr )
      return;            // bus is busy !
   I2CSStart();         // Second Start ...
   if( i2cerr )
      return;            // bus is busy !
   i2cdata = I2CRead();
   I2CMasterAck();         // Send Not Acknowledge signal
   I2CStop();            // Generate Stop condition
}

void I2CReadSeq(void)   {
   I2CWriteAddr();         // Write address in address registers
   if( i2cerr )
      return;            // bus is busy !
   I2CSStart();         // Second Start ...
   if( i2cerr )
      return;            // bus is busy !
   i2ctemp = i2ccount;
#ifdef M24515
   I2CPageCross();
#endif
   do {
      INDF = I2CRead();
      FSR++;
      if( --i2ccount == 0 )
         break;
#ifdef M24515
      if( ++i2caddr == 0x8000 ) {
         I2CStop();
         I2CWriteAddr();
         if( i2cerr )
            break;
         I2CSStart();
         if( i2cerr )
            break;
      } else
         I2CAck();
#else
      I2CAck();
#endif
   } while( 1 );
   I2CRestoreAddress();
   I2CMasterAck();         // Send Not Acknowledge signal
   I2CStop();            // Generate STOP condition
}

void I2CWriteByte(void)   {

   I2CWriteAddr();         // Write address in address registers
   if( i2cerr )
      return;            // bus is busy !
   I2CWrite( i2cdata );
   I2CStop();
// Verifiy record ...
   do {
      I2CWriteAddr();
   } while( i2cerr );
   I2CSStart();         // Send Start signal
   if( i2cerr )
      return;
   if( i2cdata != I2CRead() )
      i2cerr = 1;
   else
      I2CMasterAck();      // Send Not Acknowledge signal
   I2CStop();            // Generate STOP condition
}

void I2CWriteSeq(void)   {
   I2CWriteAddr();
   if( i2cerr )
      return;
   i2ctemp = i2ccount;
#ifdef M24515
   I2CPageCross();
#endif
   do {
      I2CWrite( INDF );
      if( i2cerr )
         return;
      FSR++;
      if( --i2ccount == 0 )
         break;
#ifdef M24515
      if( ++i2caddr == 0x8000 ) {
         I2CStop();
         I2CWriteAddr();
         if( i2cerr )
            break;
      }
#endif
   } while( 1 );
   I2CStop();
   I2CRestoreAddress();
        // Verify record ...
   do {
      I2CWriteAddr();
   } while( i2cerr );
   I2CSStart();         // Send Start signal
   if( i2cerr )
      return;
   FSR -= i2ctemp;
   i2ccount = i2ctemp;
#ifdef M24515
   I2CPageCross();
#endif
   do {
      if( INDF != I2CRead() ) {
         i2cerr = 1;
         break;
      }
      FSR++;
      if( --i2ccount == 0 )
         break;
#ifdef M24515
      if( ++i2caddr == 0x8000 ) {
         I2CStop();
         I2CWriteAddr();
         if( i2cerr )
            break;
         I2CSStart();
         if( i2cerr )
            break;
      } else
         I2CAck();
#else
      I2CAck();
#endif
   } while( 1 );
   I2CRestoreAddress();
   I2CMasterAck();      // Send Not Acknowledge signal
   I2CStop();         // Generate STOP condition
}


Ако само пиша буфер, от време на време работи, ако само чета в буфер, също работи от време на време, ако обаче запиша буфер, след което чета буфер, зависва на проверката на SSPIF в I2CWait(); когато записвам адреса чрез I2CWriteAddr();
Някой има ли нещо пробвано и работещо за буфери с MSSP модула щото ми иде да метна щангата през прозореца ...

Автор:  Nikola Kirov [ Чет Юли 07, 2005 11:44 am ]
Заглавие: 

Погледна ли в пдф-а на чипа с който работиш. Имам неприятен опит с една 24ка дето се оказа че буфера и е 16 байта точно при този производител а работих с пдф на друга фирма там беще 32 или повече,вецхе нямам спомени. Производителите си позволяват такива волности с големината на буфера

Автор:  Predator_MF [ Чет Юли 07, 2005 11:47 am ]
Заглавие: 

Същия проблем при мене преди година....доста си играх....накрая му бих шута на тоя MSSP :x С драйвърите на CCS работи точно както казваш, по един байт...а от време на време даже и не работи. Накрая си го написах софтуерно :D

Автор:  [ Чет Юли 07, 2005 11:54 am ]
Заглавие: 

Буфера си точно 64 байта дълъг, но и 8 байта да се опитам да трансферирам се държи по същия начин. Когато обаче работят два MSSP модула, единия Master, другия Slave, или когато Master е I80552, a Slave MSSP модула работи на 100 KHz та пушек се вдига, един път не ще да забие. Софтуерно като го правя работи, обаче трябва да тръгне хардуерно, защото губя много време ако е софтуерно, а процесора е много натоварен и с други задачи. Ако само чета произволно дълъг буфер с MSSP модула всичко си работи нормално, дори и на 400kHz, обаче като се комбинира четене/запис работата се усира.

Автор:  bateAz [ Чет Юли 07, 2005 4:40 pm ]
Заглавие: 

Някои производители пишат, че след команда за запис чипът не отговаря около 5 милисекунди, та е добре след записа, ако искаш да четеш нещо, първо да го полираш дали е готов.

Автор:  Nikola Kirov [ Чет Юли 07, 2005 4:50 pm ]
Заглавие: 

Ако аз имах такъв проблем щях да сваля с логическия анализатор трансфера с паметта и оттам щях да изясня какъв точно е проблема и като знам проблема вече да ми е по лесно да определя къде бърка пика.

Автор:  [ Чет Юли 07, 2005 5:45 pm ]
Заглавие: 

След като се стартира процеса на запис, можеш да се опитваш да започнеш нов трансфер като записваш адрес в коя да е i2c памет, но тъй като е заета, ще връща NACK, това го правя в цикъл ( т.е. това е полирането ). Когато отговори, изпращам адреса за четене и правя верификация.

Логически анализатор, дори не съм виждал през живота си таквоз животно, та камо ли в къщи да имам такова :oops: Вместо туй чудо съм използвал 4-ри канален запомнящ осцилоскоп, върши чудесна работа.

И аз, като МикроЧип, работя на тъмно, и пускам от време на време work around-и ( така ли се пишеше ? ), т.е. метода на пробите и грешките е безотказен :D

Оказва се, че MSSP модула се усира в следващия код:
Код:
   do {
      I2CWriteAddr();
   } while( i2cerr );

от който няма излизане.

Като го преработих така:
Код:
   do {
      I2CWriteAddr();
      if( i2cerr )
         I2CInitMaster();
      else
         break;
   } while( 1 );

т.е. докато 24LC515 е заета със записа, след опита за записа на адрес правя преинициализация на MSSP модула, при което проблема се реши. Даже изпробвах 24LC515 и на 1 MHz ( а я дават, че не може да работи на 1 MHz ) и пак си работи животното....

П.П. Добре, че не си изхвърлих сутринта щангата.

Автор:  Цецо [ Чет Юли 07, 2005 7:48 pm ]
Заглавие: 

Абе аз така тънко да питам, що ползваш тия загубени драйвери. То си има регистри, мааай вътре като бял човек. Аз на С-то за Пикове библиотеките за хардуера не ползвам. Само неприятности, баси. Е не знам как е при CCS, ама на MPLABC18 са пълна скръб. Или сам си пиша или направо в регистрите, кво да му се глезя.

Автор:  bateAz [ Чет Юли 07, 2005 7:58 pm ]
Заглавие: 

Аз съм пробвал CCS и функциите за SPI. След като се борих няколко дена с тях като прасе с тиква, ги зае*ах. И както каза Цецо, с директен достъп до регистрите си реших проблема за 1 час.

Автор:  [ Чет Юли 07, 2005 8:16 pm ]
Заглавие:  Re: I2C MSSP PIC16F87xx

pirev написа:
..Пробвам с драйверите на CCS, обаче те работят коректно само ако пиша/чета по един байт, като ги пусна на буфер правят каквото си искат. Имам едни мои драйвери, които съм си писал преди 2-3 години и са работили коректно досега с друг MSSP модул и с I2C модула на I80552, както и с Neuron професор..


Ами нал Ви казах, че като не поиска да заработи с моите подпрограми ( драйвери ), реших да опитам с тези на CCS, като си помислих че от 1999г. е изтекла много вода и може и да са си ги оправили, обаче надежда всяка оставете :D От CCS библиотеките почти нищо не използвам, защото все имат някакви странични ефекти. Преди време се борих с printf на CCS, исках да разпечатам число с плаваща запетая като string, оказа се че разпечатва коректно само "определен част" от float числата. Накрая си написах собствена printf и се оправи работата ...
В крайна сметка и аз пиша директно по регистрите.
Хубавото е, че моят I2C Мастер тръгна и на 1 MHz, обаче ся забелязвам други проблеми с PIC16F87xx , прехвърля се шум при едновременна работа от I2C шината към PWM модула и обратно ( крачетата са съседни ), трябва едновременно да работят, а пистите са от къси по-къси, кондензатори бол, сложих и 100nF, 1uF, 10uF директно на пиновете на захранванията на PIC16F87xx & 24LC515, ефект нулев, продължават шумилките.

Автор:  ToHu [ Чет Юли 07, 2005 9:02 pm ]
Заглавие: 

е, е, е ... стига бе . от крче на краче ....гледа ли го с осцилоскоп ? Д а не ти кляка по захранване . въпреки кондензите, или кофти маса ...... Пробвал ли си да пуснесш писта м-у двете крачета, на земя, и от двее страни естествено ..... чак така да се смущават ..... хмммм

Автор:  [ Чет Юли 07, 2005 9:21 pm ]
Заглавие: 

ToHu написа:
е, е, е ... стига бе . от крче на краче ....гледа ли го с осцилоскоп ? Д а не ти кляка по захранване . въпреки кондензите, или кофти маса ...... Пробвал ли си да пуснесш писта м-у двете крачета, на земя, и от двее страни естествено ..... чак така да се смущават ..... хмммм

Утре ще го гледам на скопа, захранването, по-добро от това здраве му кажи, няма калпава маса, това за пистата не разбрах какво искаш да кажеш :oops:
Като работи I2C-то на 50 kHz няма шум, обаче това не ме устройва, устройва ме 400 kHz и нагоре; при 400 kHz шума осезателно се усеща като неритмично бучене, чувам го на телефонна слушалка, тъй като от PWM модула се синтезира звук.

Страница 1 от 1 Часовете са според зоната UTC + 2 часа [ DST ]
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/