CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

MAX3110 driver not working

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
zilog
Guest







MAX3110 driver not working
PostPosted: Tue Jun 19, 2007 12:46 pm     Reply with quote

I have tried adopting the code originally submitted by Ttelmah to work with my setup, but I seem to need to receive one character to fully empty the TX buffer - anyone spot anything fishy in the code below?

I use SSP2 on a PIC18F, using EXT_INT1 for /IRQ, and PIN_D3 for /CS.

Code:

//These are for a 18F chip
#byte INTCON3 = 0xFF0
#bit  EXT1IF = INTCON3.0

#define CS PIN_D3

//Buffer tests and handling
#define MaxBufIsEmpty(buff,in,out,size) (in==out)
#define MaxBufHasData(buff,in,out,size) (in!=out)
#define MaxBufIsFull(buff,in,out,size) (((++in)&(size-1))==out)
#define MaxBufToBuff(buff,in,out,size,chr) { \
  buff[in]=chr;\
  in=((++in) & (size-1));\
  if (in==out) \
    out=((++out) & (size-1));\
}
#define MaxBufFromBuff(buff,in,out,size) (MaxbTemp=out,\
   out=(++out) & (size-1), \
   buff[MaxbTemp])
#define MaxBufClrBuff(buff,in,out,size) {in=0;\
   out=0;}

//Declares for buffers. I have three others not shown here
#define MAXSIBUFF (32)
#define MAXSOBUFF (64)

void isr_maxim(void);
int16 SSPtransfer16(int16 val);
void Maxputc(int8 chr);
void MaxInit(int8 baud_index);
int8 MaxKbHit(void);
int8 MaxGetc(void);

int8 MAXIPbuff[MAXSIBUFF],MAXIPin,MAXIPout;
int8 MAXOPbuff[MAXSOBUFF],MAXOPin,MAXOPout;
int8 MaxbTemp;
unsigned int16 MaxConfigWord;

//Defines for the SSP port again for a 18F chip
#byte  SSP2BUF = 0xF66
#byte  SSP2STAT = 0xF64
#bit   BF = SSP2STAT.0

/* Now the SSP handler code. Using my own, since the supplied routines test the wrong way round for my needs */
#DEFINE  READ_SSP2()       (SSP2BUF)
#DEFINE  WAIT_FOR_SSP2()   while(!BF)
#DEFINE  WRITE_SSP2(x)     SSP2BUF = (x)

#INT_EXT1 NOCLEAR //Interrupt from Maxim chip
void isr_maxim(void) {
  unsigned int16 Rxdata;

  do {
    EXT1IF = 0;
    //force a read
    Rxdata = SSPtransfer16(0L);
    if (Rxdata & 0x8000L) {
      //Here a receive character is present
      MaxBufToBuff(MAXIPbuff, MAXIPin, MAXIPout, MAXSIBUFF, make8(Rxdata, 0));
    }
    if (Rxdata & 0x4000L) {
      //Here the chips TX buffer is empty
      if (MaxBufHasData(MAXOPbuff,MAXOPin,MAXOPout,MAXSOBUFF)) {
        Rxdata = SSPtransfer16(0x8000L | make16(0, MaxBufFromBuff(MAXOPbuff, MAXOPin, MAXOPout, MAXSOBUFF)));
        //Check if a byte was received with the transmission
        if (Rxdata & 0x8000L) {
          MaxBufToBuff(MAXIPbuff, MAXIPin, MAXIPout, MAXSIBUFF, make8(Rxdata, 0));
        }
        //empty=false;
      } else {
        //empty=true;
        MaxConfigWord &= (~0x0800L);
        //disable transmitter interrupt
        SSPtransfer16(MaxConfigWord);
      }
    }
  } while (EXT1IF);

  return;
}

int16 SSPtransfer16(int16 val) {
  int8 msb;
  //routine to send and receive a 16bit value from the Maxim chip
  //Latch the data at this point
  output_low(CS);
  //send high byte
  WRITE_SSP2(make8(val,1));
  WAIT_FOR_SSP2();
  msb=READ_SSP2();
  //now send the low byte
  WRITE_SSP2(make8(val,0));
  WAIT_FOR_SSP2();
  output_high(CS);
  return (make16(msb, READ_SSP2()));
}

//Subroutines to talk to the Maxim chip.
void Maxputc(int8 chr) {
  int16 tval;

  DISABLE_INTERRUPTS(INT_EXT1);
  MaxBufToBuff(MAXOPbuff, MAXOPin, MAXOPout, MAXSOBUFF, chr);
  //empty=false;
  MaxConfigWord |= 0xC800;
  tval = SSPtransfer16(MaxConfigWord);

  //Force an interrupt event - bodge!...
  EXT1IF = 1;
  ENABLE_INTERRUPTS(INT_EXT1);

  return;
}

int8 MaxKbHit(void)
{
  return (MaxBufHasData(MAXIPbuff, MAXIPin, MAXIPout, MAXSIBUFF));
}

int8 MaxGetc(void)
{
  return (MaxBufFromBuff(MAXIPbuff, MAXIPin, MAXIPout, MAXSIBUFF));
}

void MaxInit(int8 baud_index) {
  //init SPI2
  setup_spi2(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_4 | SPI_XMIT_L_TO_H);
  output_high(CS);

  //enable external INT1
  clear_interrupt(INT_EXT1);
  ext_int_edge(1, H_TO_L);
  enable_interrupts(INT_EXT1);

  // clear buffers
  MaxBufClrBuff(MAXIPbuff, MAXIPin, MAXIPout, MAXSIBUFF);
  MaxBufClrBuff(MAXOPbuff, MAXOPin, MAXOPout, MAXSOBUFF);

  baud_index &= 0xF;
  //RX INT enabled, TX INT disabled, RX FIFO on, 8N1 format
  MaxConfigWord = 0xC400L + make16(0,baud_index);
  //Ensure chip has accepted the data
  do {
    SSPtransfer16(MaxConfigWord);
    if (((SSPtransfer16(0x4000L) ^ MaxConfigWord) & 0x3FFF)==0)
      break;
  } while(true);

  return;
}
Guest








PostPosted: Tue Jun 19, 2007 1:04 pm     Reply with quote

To clarify - it transmits 6-8 characters and then waits for a RX-character to transmit the rest of the buffer.
Guest








PostPosted: Tue Jun 19, 2007 1:10 pm     Reply with quote

Now I saw that the slower the SPI-bus clocks, the more characters I get before it needs RX to continue.. SPI_CLK_DIV_64 lets me transmit 32 characters before it stalls.
zilog
Guest







PostPosted: Tue Jun 19, 2007 2:43 pm     Reply with quote

I have tried lowering the clock frequency from 40MHz to 10MHz, this also makes the code work.
Ttelmah
Guest







PostPosted: Tue Jun 19, 2007 3:07 pm     Reply with quote

You appear to be reading the interrupt flag, not the interrupt _input_. The latter is vital. The PIC, is an 'edge triggered' interrupt chip. The MAX3110, gives a _level_ output. Hence you need to be reading the actual input, not the state of the interrupt flag.
The original form is:
Code:

#INT_EXT NOCLEAR //Interrupt from Maxim chip
void MAXIM(void) {
   unsigned int16 Rxdata;
   do {
      //force a read
      Rxdata = iSSPtransfer16(0L);
      if (Rxdata & 0x8000L) {
         //Here a receive character is present
         tobuff(MAXIPbuff,MAXIPin,MAXIPout,SIBUFF,make8(Rxdata,0));
      }
      if (Rxdata & 0x4000L) {
         //Here the chips TX buffer is empty
         if (hasdata(MAXOPbuff,MAXOPin,MAXOPout,SOBUFF)) {
            Rxdata=iSSPtransfer16(0x8000L | make16(0,ifrombuff(MAXOPbuff,MAXOPin,MAXOPout,SOBUFF)));
            //Check if a byte was received with the transmission
            if (Rxdata & 0x8000L) {
               tobuff(MAXIPbuff,MAXIPin,MAXIPout,SIBUFF,make8(Rxdata,0));
            }
            empty=false;
         }
         else {
            empty=true;
            Mconfig &= (~0x0800L);
            //disable transmitter interrupt
            iSSPtransfer16(Mconfig);
         }
      }
   } while (INTINPUT==0);
   clear_interrupts(INT_EXT);
}


Best Wishes
zilog
Guest







PostPosted: Tue Jun 19, 2007 3:22 pm     Reply with quote

Ttelmah,

I have tried the latter version of the code aswell, to no help. The code still behaves the same. I have routed the INT1-pin to the D7-pin as well since I use RB4-7 for change-trigging and cant disturb this by reading port B. See the code that also doesnt work below:

Code:

#INT_EXT1 NOCLEAR //Interrupt from Maxim chip
void isr_maxim(void) {
  unsigned int16 Rxdata;

  do {
    //force a read
    Rxdata = iSSPtransfer16(0L);
    if (Rxdata & 0x8000L) {
      //Here a receive character is present
      MaxBufToBuff(MAXIPbuff, MAXIPin, MAXIPout, MAXSIBUFF, make8(Rxdata, 0));
    }
    if (Rxdata & 0x4000L) {
      //Here the chips TX buffer is empty
      if (MaxBufHasData(MAXOPbuff, MAXOPin, MAXOPout, MAXSOBUFF)) {
        Rxdata = iSSPtransfer16(0x8000L | make16(0, MaxBufiFromBuff(MAXOPbuff, MAXOPin, MAXOPout, MAXSOBUFF)));
        //Check if a byte was received with the transmission
        if (Rxdata & 0x8000L) {
          MaxBufToBuff(MAXIPbuff, MAXIPin, MAXIPout, MAXSIBUFF, make8(Rxdata, 0));
        }
        //empty=false;
      } else {
        //empty=true;
        MaxConfigWord &= (~0x0800L);
        //disable transmitter interrupt
        iSSPtransfer16(MaxConfigWord);
      }
    }
  } while (input(pin_d7) == 0);

  clear_interrupt(INT_EXT1);
  return;
}
Ttelmah
Guest







PostPosted: Wed Jun 20, 2007 3:05 am     Reply with quote

A couple of other comments:
On the original code, there is a separate 'SSPtransfer16', and 'iSSPtransfer16'. The latter is only used in the interrupts, and prevents interrupts from being disabled in the main code, when this transfer routine is used. It is necessary to have the two copies, and manually control the interrupts, or the compiler will still add the extra interrupt control code, which gave problems....
Second comment, though the compiler should handle it correctly, you do not want/need a return on void handlers.You want to drop off the end of these.
I would clear the external interrupt _after_ setting the interrupt edge. If you change the interrupt edge, this can generate an interrupt. Probably not your problem, but the sequence should always be:
set edge
clear interrupt
enable interrupt.
What happens if you use the original global interrupt enable/disable in MaxPutc, instead of the individual one?. Though with the code as shown, either should work, I had a problem with timing on the Max chip, if a serial receive interrupt occurred during the data transfer to the chip. Hence the global enable/disable...
I notice you are bypassing the 'empty' flagging in the original code. This was done to handle exactly the behaviour you are seeing. The Maxim chip, seems to have a fault, of not updating it's internal registers immediately, which can lead to the interrupt handler returning, yet there still being data to send. The empty flag, was used with a bodge to restart the transmission if this happens, by calling the interrupt handler, one 'extra' time.

Best Wishes
zilog
Guest







PostPosted: Wed Jun 20, 2007 5:39 am     Reply with quote

Ttelmah,

The code you posted on the forum is not complete, you set "empty" along with other flags, but you never read or declare it etc. Could you please mail me the complete code for this chip? gnuffel (at) gmail dot com.
Ttelmah
Guest







PostPosted: Wed Jun 20, 2007 6:59 am     Reply with quote

It was complete. The very first code I posted was not, I was having problems like yours. If you search back in the very old forum posts, on the 3110, you will find my original question, where I was having the problem that the the device would not complete 'sending' data, unless a character was rceived. This sounds exactly like what you are describing.
The latter code posted on the forum, was fully working, however the variable declaration could well have been missed.
Empty is just an int1, set when the transmit interrupt is turned off in the interrupt handler.
The 'bodge' was in the main, to 'poll' this, and if it was found 'on', with data present in the buffer, to clear it, and force an interrupt.
Why it should be needed, I could never see. If data is added to the buffer, the interrupt will always be called, so 'extra' calls should not be needed. It is as if the chip's interrupt output was not being updated to reflect the TX interrupt being enabled, till after one character is transferred...

Best Wishes
zilog
Guest







PostPosted: Wed Jun 20, 2007 7:47 am     Reply with quote

I have now found that the /IRQ pin of the MAX never returns high, not even with a 3k9 pullup. Ddebugging the SPI tells me that the MAX cries "empty" allt he time, but the command to disable interrutps simply doesnt matter. All SPI communication tells me its sane, but he IRQ-pin is stone dead tied to GND.

Could this be a broken chip where the open drain output has been fused?
zilog
Guest







PostPosted: Wed Jun 20, 2007 8:02 am     Reply with quote

I have now made some more tests on the 3110, when powered down, the IRQ-output is floating while after power-on it is pulled strong low, even if I dont initialize the chip at all (SPI lines disconnected and grounded).
zilog
Guest







PostPosted: Thu Jul 05, 2007 1:04 pm     Reply with quote

I have got the code workign now (broken INT-line on the PIC was the reason). A new problem has arisen - if I call Maxputc repeatedly, either by itseld or through printf(Maxputc, "......"); it scrambles the order of the characters, casues some characters to repeat etc.

My main routine calls "void MaxKeepMAX3110Alive(void)" repeatedly to make sure the chip doesnt stall. I have attached the complete code below - please help me find the problem as I need this chip for debug.

Code:

#include "styrkort.h"

//These are for a 18F chip
#byte INTCON3 = 0xFF0
#bit  EXT2IF = INTCON3.1

#define CS PIN_D3

//Buffer tests and handling
#define MaxBufIsEmpty(buff,in,out,size) (in==out)
#define MaxBufHasData(buff,in,out,size) (in!=out)
#define MaxBufIsFull(buff,in,out,size) (((++in)&(size-1))==out)
#define MaxBufToBuff(buff,in,out,size,chr) { \
  buff[in]=chr;\
  in=((++in) & (size-1));\
  if (in==out) \
    out=((++out) & (size-1));\
}
#define MaxBufFromBuff(buff,in,out,size) (MaxbTemp=out,\
   out=(++out) & (size-1), \
   buff[MaxbTemp])
#define MaxBufiFromBuff(buff,in,out,size) (MaxibTemp=out,\
   out=(++out) & (size-1), \
   buff[MaxibTemp])
#define MaxBufClrBuff(buff,in,out,size) {in=0;\
   out=0;}

//Declares for buffers. I have three others not shown here
#define MAXSIBUFF (32)
#define MAXSOBUFF (64)

void isr_maxim(void);
int16 SSPtransfer16(int16 val);
int16 iSSPtransfer16(int16 val);
void Maxputc(int8 chr);
void MaxInit(int8 baud_index);
int8 MaxKbHit(void);
int8 MaxGetc(void);
void MaxKeepMAX3110Alive(void); //call this in idle loop to make sure buffers are managed

int8 MAXIPbuff[MAXSIBUFF],MAXIPin,MAXIPout;
int8 MAXOPbuff[MAXSOBUFF],MAXOPin,MAXOPout;
int8 MaxbTemp, MaxibTemp;
int1 MaxEmpty;
unsigned int16 MaxConfigWord;

//Defines for the SSP port again for a 18F chip
#byte  SSP2BUF = 0xF66
#byte  SSP2STAT = 0xF64
#bit   BF = SSP2STAT.0

/* Now the SSP handler code. Using my own, since the supplied routines test the wrong way round for my needs */
#DEFINE  READ_SSP2()       (SSP2BUF)
#DEFINE  WAIT_FOR_SSP2()   while(!BF)
#DEFINE  WRITE_SSP2(x)     SSP2BUF = (x)

#INT_EXT2 NOCLEAR //Interrupt from Maxim chip
void isr_maxim(void) {
  unsigned int16 Rxdata;
  do {
    clear_interrupt(INT_EXT2);
    //force a read
    Rxdata = iSSPtransfer16(0L);
    if (Rxdata & 0x8000L) {
      //Here a receive character is present
      MaxBufToBuff(MAXIPbuff, MAXIPin, MAXIPout, MAXSIBUFF, make8(Rxdata, 0));
    }
    if (Rxdata & 0x4000L) {
      //Here the chips TX buffer is empty
      if (MaxBufHasData(MAXOPbuff, MAXOPin, MAXOPout, MAXSOBUFF)) {
        Rxdata = iSSPtransfer16(0x8000L | make16(0, MaxBufiFromBuff(MAXOPbuff, MAXOPin, MAXOPout, MAXSOBUFF)));
        //Check if a byte was received with the transmission
        if (Rxdata & 0x8000L) {
          MaxBufToBuff(MAXIPbuff, MAXIPin, MAXIPout, MAXSIBUFF, make8(Rxdata, 0));
        }
        MaxEmpty=false;
      } else {
        MaxEmpty=true;
        MaxConfigWord &= (~0x0800L);
        //disable transmitter interrupt
        iSSPtransfer16(MaxConfigWord);
      }
    }
  } while (input(pin_d7) == 0);

  return;
}

int16 SSPtransfer16(int16 val) {
  int8 msb;
  //routine to send and receive a 16bit value from the Maxim chip
  //Latch the data at this point
  output_low(CS);
  //send high byte
  WRITE_SSP2(make8(val,1));
  WAIT_FOR_SSP2();
  msb=READ_SSP2();
  //now send the low byte
  WRITE_SSP2(make8(val,0));
  WAIT_FOR_SSP2();
  output_high(CS);
  return (make16(msb, READ_SSP2()));
}

int16 iSSPtransfer16(int16 val) {
  int8 msb;
  //routine to send and receive a 16bit value from the Maxim chip
  //Latch the data at this point
  output_low(CS);
  //send high byte
  WRITE_SSP2(make8(val,1));
  WAIT_FOR_SSP2();
  msb=READ_SSP2();
  //now send the low byte
  WRITE_SSP2(make8(val,0));
  WAIT_FOR_SSP2();
  output_high(CS);
  return (make16(msb, READ_SSP2()));
}

//Subroutines to talk to the Maxim chip.
void Maxputc(int8 chr) {
  int16 tval;

  DISABLE_INTERRUPTS(INT_EXT2);
  MaxBufToBuff(MAXOPbuff, MAXOPin, MAXOPout, MAXSOBUFF, chr);
  MaxEmpty=false;
  MaxConfigWord |= 0xC800;
  tval = SSPtransfer16(MaxConfigWord);

  //Force an interrupt event - bodge!...
  EXT2IF = 1;
  ENABLE_INTERRUPTS(INT_EXT2);

  return;
}

int8 MaxKbHit(void)
{
  return (MaxBufHasData(MAXIPbuff, MAXIPin, MAXIPout, MAXSIBUFF));
}

int8 MaxGetc(void)
{
  return (MaxBufFromBuff(MAXIPbuff, MAXIPin, MAXIPout, MAXSIBUFF));
}

void MaxKeepMAX3110Alive(void)
{
  if (!MaxEmpty)
    EXT2IF = 1;

  return;
}

void MaxInit(int8 baud_index) {

  //init SPI2
  setup_spi2(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_4 | SPI_XMIT_L_TO_H);
  output_high(CS);

  // clear buffers
  MaxBufClrBuff(MAXIPbuff, MAXIPin, MAXIPout, MAXSIBUFF);
  MaxBufClrBuff(MAXOPbuff, MAXOPin, MAXOPout, MAXSOBUFF);
  MaxEmpty = true;

  baud_index &= 0xF;
  //RX INT enabled, TX INT disabled, RX FIFO on, 8N1 format
  MaxConfigWord = 0xC400L + make16(0,baud_index);
  //Ensure chip has accepted the data
  do {
    SSPtransfer16(MaxConfigWord);
    if (((SSPtransfer16(0x4000L) ^ MaxConfigWord) & 0x3FFF)==0)
      break;
  } while(true);

  //enable external INT2
  ext_int_edge(2, H_TO_L);
  clear_interrupt(INT_EXT2);
  enable_interrupts(INT_EXT2);

  return;
}
Ttelmah
Guest







PostPosted: Fri Jul 06, 2007 2:29 am     Reply with quote

The only thing in the original code, that would cause the data order to be scrambled, is if you are over filling the buffers. The code does not check for this (assuming that your buffers _are_ large enough), and this would result in data becoming scrambled...

Best Wishes
Guest








PostPosted: Fri Jul 06, 2007 7:57 am     Reply with quote

Ttelmah wrote:
The only thing in the original code, that would cause the data order to be scrambled, is if you are over filling the buffers. The code does not check for this (assuming that your buffers _are_ large enough), and this would result in data becoming scrambled...

Best Wishes


I have discovered that lowering the SPI clock lessens the problem somewhat, but not completely.

I cant see how filling the buffers would cause tokens to be pairwise swapped, repeated etc.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group