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 CCS Technical Support

Ttelmah's MAX3100 Driver[LOCATED...not crying wolf...really]
Goto page 1, 2, 3  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
jecottrell



Joined: 16 Jan 2005
Posts: 559
Location: Tucson, AZ

View user's profile Send private message

Ttelmah's MAX3100 Driver[LOCATED...not crying wolf...really]
PostPosted: Tue Oct 09, 2007 9:36 pm     Reply with quote

Probably only Roger can answer this one....

re:

http://www.ccsinfo.com/forum/viewtopic.php?t=23954

Thanks again for the driver. I'm porting it to the 18F6627 and will run 4 MAX3100s on the same processor. As I'm working on compiling the code I see that you use:

Code:
empty=false;


and

Code:
empty=true;


In several locations. I'm assuming that was a global flag to alert some other code that there was something in the buffer?

Also, I'm assuming I need to do a regular spi_setup to use your code?

And I found another.... Mconfig.... is just a int16 global? Used for building the data out?

Thanks,

John


Last edited by jecottrell on Fri Oct 19, 2007 12:26 pm; edited 12 times in total
Ttelmah
Guest







PostPosted: Wed Oct 10, 2007 2:10 am     Reply with quote

Yes, the SPI needs to be setup to suit the chip. It needs:
SPI_XMIT_L_TO_H | SPI_MASTER | SPI_H_TO_L

or SPI_MODE_1_1, using Ckielstra's setup defines.

Try it without 'empty'. At one time, I was having problems getting the chip to start transmitting, and I was 'kicking' it in a timer, if the buffer stayed 'non empty' for a while, without switching to TX mode.
If it doesn't work reliably, I'll send the timer 'kick', but I don't think it is neeed now.

int16 Mconfig; //used for Maxim config word.

Yes.
jecottrell



Joined: 16 Jan 2005
Posts: 559
Location: Tucson, AZ

View user's profile Send private message

PostPosted: Wed Oct 10, 2007 9:31 am     Reply with quote

Thanks.

I didn't quite have the spi_setup right. Got that fixed.

Got the global Mconfig taken care of.

Having problems with the IRQ from the MAX3100. Routines hang in the maxconfig(). From what I can see, maxconfig() sends the spi data and then any reading of data is driven by IRQ being driven low and the ISR reading the data?

I did catch that the IRQ on the MAX3100 is an open drain, so I added a 10K pull up. But I'm still not ever getting a drop in the IRQ line. I can see a good MOSI and MISO signal. I've tried different spi clock divisors.

I'm using EXT3 interrupt and have made all the changes in the code to handle that.

Not sure where to look.

Thanks,

John
jecottrell



Joined: 16 Jan 2005
Posts: 559
Location: Tucson, AZ

View user's profile Send private message

PostPosted: Wed Oct 10, 2007 1:13 pm     Reply with quote

I finally went back to the basic read and write spi routines to check data being returned. I found that it was shifted slightly. So I tried all the setup_spi options and found that SPI_L_TO_H fixed the problem.

Now, the question is, why one way works for your hardware and the other works for mine?

Looks like the transmit function works, I'll test the receive here in a little bit.

Thanks a bunch for all you effort, I sincerely appreciate every bit of it.

John
Ttelmah
Guest







PostPosted: Wed Oct 10, 2007 2:24 pm     Reply with quote

Odd.
Must admit the code originally dated from a time when I don't really 'trust' the CCS defined values to be 'right', so maybe their masking was wrong, on this old compiler, but I don't think so (think I would have noticed).
At least you have a fix now.

Best Wishes
jecottrell



Joined: 16 Jan 2005
Posts: 559
Location: Tucson, AZ

View user's profile Send private message

PostPosted: Wed Oct 10, 2007 2:47 pm     Reply with quote

I think I may need the timer kick.

Symptoms:

Code:
printf(maxputc,"12345");


Used in a timer every 1 second. I only get three characters w/ each 1 second transmit, with an eventual 'overflow'? 123 451 234 512 345 123 ..... 345 345 345 345 345

I'm trying to debug now, intuition (not that I have much) and previous talk of transmit problems lead me to think it's the issue you had?

I'll let you know if I learn more.

Config is: 57600, through an XBee at 57600.

Thanks,

John


UPDATE: I can bang away as fast as I want with 3 characters, no problem. But any more causes the problem.

UPDATE2:

If I use this, I can send as many characters as fast as I want. Now, if I could just figure out how I gooned up Ttelmah's code......

Code:
bit_clear(LCL_CS);
spi_write(0b10000000);
spi_write('1');
bit_set(LCL_CS);
delay_ms(1);
bit_clear(LCL_CS);
spi_write(0b10000000);
spi_write('2');
bit_set(LCL_CS);
delay_ms(1);
bit_clear(LCL_CS);
spi_write(0b10000000);
spi_write('3');
bit_set(LCL_CS);
delay_ms(1);
bit_clear(LCL_CS);
spi_write(0b10000000);
spi_write('4');
bit_set(LCL_CS);
delay_ms(1);
bit_clear(LCL_CS);
spi_write(0b10000000);
spi_write('5');
bit_set(LCL_CS);
delay_ms(1);
bit_clear(LCL_CS);
spi_write(0b10000000);
spi_write('6');
bit_set(LCL_CS);
delay_ms(1);
bit_clear(LCL_CS);
spi_write(0b10000000);
spi_write(0x0D);
bit_set(LCL_CS);
delay_ms(1);
bit_clear(LCL_CS);
spi_write(0b10000000);
spi_write(0x0A);
bit_set(LCL_CS);
Ttelmah
Guest







PostPosted: Thu Oct 11, 2007 2:26 am     Reply with quote

The problem I had, was that the chip would not reliably start transmitting. The same problem is present in the Maxim 'demo' code. Basically if you copy their code as written, it won't start sending characters, till one is received!...
In the latter version which I think you have, I altered the bodge for this, and just force the interrupt 'true' at the end of the routine that writes the character to the buffer. This then forces the interrupt handler to be called (even if the line is not low from the chip), and effectively software 'polls' the chip in this routine.
Are you sure your translation to the other interrupt, has got the bit defintion for the interrupt flag 'right' here, so it kicks the interrupt?.
Puzzled slightly, the SSP transfer 16 routines I use, operate the chip select line, exactly as you are showing for your 'working' transfer code.

Best Wishes
jecottrell



Joined: 16 Jan 2005
Posts: 559
Location: Tucson, AZ

View user's profile Send private message

PostPosted: Fri Oct 12, 2007 5:25 pm     Reply with quote

Ttelmah,

Here are the details. I'm hoping you may have some insight to what is happening.

18LF6627 @ 3.3V and 40MHZ (slightly faster than Microchips specs)
3.249

Setup and code:

Code:
//Register definitions
#bit EXT0INT  = 0xF81.0      // not used
#bit EXT1INT  = 0xF81.1      // not used
#bit EXT2INT  = 0xF81.2      // not used
#bit EXT3INT  = 0xF81.3      // not used
// use non-standard names to prevent conflict w/ asmallri's code style
#byte INTCON_ADDR  = 0x0FF2
#byte   INTCON3_ADDR = 0x0FF0
#bit EXT0IF   = INTCON_ADDR.1
#bit EXT1IF   = INTCON3_ADDR.0
#bit EXT2IF   = INTCON3_ADDR.1
#bit EXT3IF   = INTCON3_ADDR.2
#define SPIREAD  (0x80)

//For PIC18 chips. Will need to change for others
#byte   SSPBUF  = 0xFC9
#byte   SSPCON  = 0xFC6
#byte   SSPSTAT = 0xFC7
#bit  BF      = SSPSTAT.0

//Call this with required baud definition to initialise chip
void maxconfig(int8 baud_index) {

setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_XMIT_L_TO_H);
   
   baud_index &= 0xF;
   Mconfig = 0xC400L + make16(0,baud_index);
   //Ensure chip has accepted the data
   do {
      SSPtransfer16(Mconfig);
      if (((SSPtransfer16(0x4000L) ^ Mconfig) & 0x3FFF) == 0)
         break;
   }
   while(TRUE);
}

int16 SSPtransfer16(int16 val) {
   int8 msb;
   //routine to send and receive a 16bit value from the Maxim chip
   //Latch the data at this point

delay_cycles(500);
   
   bit_clear(LCL_CS);
   //send high byte
   WRITE_SSP(make8(val,1));
   WAIT_FOR_SSP();
   msb=READ_SSP();

   //now send the low byte
   WRITE_SSP(make8(val,0));
   WAIT_FOR_SSP();
   bit_set(LCL_CS);
   return(make16(msb,READ_SSP()));
}

int16 iSSPtransfer16(int16 val) {
   int8 msb;
   //routine to send and receive a 16bit value from the Maxim chip inside INT
   //keep separate, to avoid automatic interrupt controls.
   
delay_cycles(500);
   
   bit_clear(LCL_CS);
   //send high byte
   WRITE_SSP(make8(val,1));
   WAIT_FOR_SSP();
   msb=READ_SSP();

   //now send the low byte
   WRITE_SSP(make8(val,0));
   WAIT_FOR_SSP();
   bit_set(LCL_CS);
   return(make16(msb,READ_SSP()));
}

//Interrupt handler
#INT_EXT3 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));
            }
         }
         else
         {
            Mconfig &= (~0x0800L);
            //disable transmitter interrupt
            iSSPtransfer16(Mconfig);
         }
      }
     
   //Loop for as long as the chip holds the interrupt line low
   } while (EXT3INT == 0);
   //This is necessary, since the Maxim device requires _level_ sensitive
   //interrupt detection, but the PIC, is an edge sensitive device...

   //Clear the interrupt flag
   EXT3IF = 0;
}

#ifdef MAX3100_INSTALLED
bit_set(LCL_CS);
   initbuff();                   //setup buffers
   ext_int_edge(3,H_TO_L);       //falling edge interrupt
   clear_interrupt(INT_EXT3);      // Enable the Maxim chip
   enable_interrupts(INT_EXT3);   // Enable the Maxim chip
   enable_interrupts(GLOBAL);
   
   maxconfig(MAX57600);           //Configure to required rate
#endif


Here is the snippet that I use to test with and gets called every second (timer based, not delay based):

Code:
for(i=0;i<40;i++)
{
   maxputc(i + 0x30);
}
maxputc('\n');
maxputc('\r');


You will notice I have a hefty 500 cycle delay in each SSP transfer function. If I remove or reduce those, the buffer appears to overflow because the data being sent starts to drop characters. And it happens sooner if I reduce the size of the transmit buffer. I tried reducing transmits to 8bytes(the size of the 3100's FIFO) and that didn't work. I tried slowing the SPI down with a DIV4 in the setup without results.

I can't figure out why the delay between each SPI transfer is necessary. Does your knowledge of the inner workings give you any ideas?

Thanks,

John

UPDATE:

I did a test to see whether it was a output buffer problem or a 3100 FIFO problem. Everything appears to indicate that the 3100 can't spit the characters out fast enough without the delays between the SSP transfer calls. I'm thinking there is a hardware problem with the SPI lines that won't allow a clean 'transaction'? (But that doesn't work because slowing the SPI down doesn't fix it.)

Ttelmah had mentioned earlier a INT problem, but I have a pretty good grasp on how the INT fires the TX and can't grasp how a delay in the SSP transfer calls would affect that.
Ttelmah
Guest







PostPosted: Sat Oct 13, 2007 3:10 am     Reply with quote

Big difference to my system, is that you are running faster, and with the clocks asynchronous between the two chips.
I use a crystal, at twice the frequency needed by the 3100, and then the *4 PLL on this. Gives 29.4912MHz processor clock rate, and 3.6864Mhz on the 3100. This also implies that the two clocks are synchronous (may not make any difference, but might have an effect).
I am also running at 5v. Shouldn't make a difference, but you 'never know'...
Other comments. Because I am directly doing a bit set/clear on the CS line, 'fast_io', must be being used on the port, and this must be setup right. I wonder if the line is not really being updated, and the delay allows some form of 'timeout' behaviour?.

Best Wishes
jecottrell



Joined: 16 Jan 2005
Posts: 559
Location: Tucson, AZ

View user's profile Send private message

PostPosted: Sat Oct 13, 2007 3:13 pm     Reply with quote

Ttelmah wrote:
Big difference to my system, is that you are running faster, and with the clocks asynchronous between the two chips.
I use a crystal, at twice the frequency needed by the 3100, and then the *4 PLL on this. Gives 29.4912MHz processor clock rate, and 3.6864Mhz on the 3100. This also implies that the two clocks are synchronous (may not make any difference, but might have an effect).


I see. This is the first time I've had the need for two different crystals on the same board. I'll try to read up on the peculiarities of two different chips on two unrelated clock speeds. I'll add some 7.3728MHz xtals to my next order and try swapping.

Ttelmah wrote:
I am also running at 5v. Shouldn't make a difference, but you 'never know'...


I understand.

Ttelmah wrote:
Other comments. Because I am directly doing a bit set/clear on the CS line, 'fast_io', must be being used on the port, and this must be setup right. I wonder if the line is not really being updated, and the delay allows some form of 'timeout' behaviour?.


I assume your implementation of CS reads something like this:

Code:
#bit LCL_CS_BIT   =   LATF.3


What are the possible ways of screwing up the '#use fast_io'?

Thanks for all the hand holding,

John


Last edited by jecottrell on Sun Oct 14, 2007 2:22 am; edited 2 times in total
Ttelmah
Guest







PostPosted: Sat Oct 13, 2007 4:15 pm     Reply with quote

Not many really, but the statement needs to be present, and the directions need to be set right.

Best Wishes
jecottrell



Joined: 16 Jan 2005
Posts: 559
Location: Tucson, AZ

View user's profile Send private message

PostPosted: Sun Oct 14, 2007 2:29 am     Reply with quote

UPDATE

I read the old post by Zilog relating a similar problem. And I kept looking at the difference between your maxputc function and another I was trying (that didn't over-run.) Your function puts the characters in the buffer prior to sending and the other code doesn't. So, I'm thinking that your code is fast enough so it is possible to fill the buffer faster than MAX3100 can tx the data? I've been trying to use the 'isfull' macro for a check, but haven't got it working yet.
Ttelmah
Guest







PostPosted: Sun Oct 14, 2007 3:09 am     Reply with quote

My original notes for this, have my code ensuring that the buffer is larger than it ever needs to be to handle the imballance between 'want to send', and 'sent'. I simply 'throw away' the oldest character, if there is an overflow. The alternative is to halt loading. So something like:
Code:

void tobuff(buff,in,out,size,chr) {
   int8 oldaddr;
   oldaddr=in;
   in=((in+1) & (size-1));
   while (in==out) {
      //Here need to wait for a gap to appear
      delay_us(5);
   }
   buff[oldaddr]=chr;
}

This way the 'load' won't return, till there is space for the character.

Best Wishes
jecottrell



Joined: 16 Jan 2005
Posts: 559
Location: Tucson, AZ

View user's profile Send private message

PostPosted: Sun Oct 14, 2007 3:38 pm     Reply with quote

OK. That is essentially what I had tried:

Code:
//Subroutines to talk to the Maxim chip.
void maxputc(int8 chr)
{
   int16 tval;
   
   disable_interrupts(GLOBAL);

   while(MAX_output_buff_full());

   tobuff(MAXOPbuff,MAXOPin,MAXOPout,SOBUFF,chr);   // put the character in the tx buffer
   Mconfig=Mconfig | 0xC800;                        // set tx buffer interrupt bit (turn on interrupt)
   tval=SSPtransfer16(Mconfig);                     // enable tx buffer interrupt bit (turn on interrupt)
   EXT3IF = 1;                                       // force an interrupt to start transmission
   enable_interrupts(GLOBAL);
}


And it didn't work. Program hung. (Didn't catch the problem until last night late and couldn't test my proposed solution.)

I then tried your solution, which is pretty much the same and in the same location. Program hung also.

Then I tried my solution from late last night. I realized you can't wait for the buffer to empty AFTER disabling the interrupts! So I tried this and it seems to work, so far.

Code:
//Subroutines to talk to the Maxim chip.
void maxputc(int8 chr)
{
   int16 tval;
   
   while(MAX_output_buff_full());                  // wait for a spot in the buffer to open up
   
   disable_interrupts(GLOBAL);
   tobuff(MAXOPbuff,MAXOPin,MAXOPout,SOBUFF,chr);   // put the character in the tx buffer
   Mconfig=Mconfig | 0xC800;                        // set tx buffer interrupt bit (turn on interrupt)
   tval=SSPtransfer16(Mconfig);                     // enable tx buffer interrupt bit (turn on interrupt)
   EXT3IF = 1;                                       // force an interrupt to start transmission
   enable_interrupts(GLOBAL);
}


Do you think that is a satisfactory solution?

Thanks,

John
Ttelmah
Guest







PostPosted: Mon Oct 15, 2007 2:04 am     Reply with quote

Yes.
I meant to add a note, that you would need to ensure the interrupts were on before waiting, but it slipped my mind....
Obviously, if this only an 'occasional' problem, this should be acceptable. However if it happens frequently, it will impair the code's ability to do other jobs, so you might have to consider increasing the buffer size.

Best Wishes
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2, 3  Next
Page 1 of 3

 
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