|
|
View previous topic :: View next topic |
Author |
Message |
jecottrell
Joined: 16 Jan 2005 Posts: 559 Location: Tucson, AZ
|
Ttelmah's MAX3100 Driver[LOCATED...not crying wolf...really] |
Posted: Tue Oct 09, 2007 9:36 pm |
|
|
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:
and
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
|
|
Posted: Wed Oct 10, 2007 2:10 am |
|
|
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
|
|
Posted: Wed Oct 10, 2007 9:31 am |
|
|
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
|
|
Posted: Wed Oct 10, 2007 1:13 pm |
|
|
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
|
|
Posted: Wed Oct 10, 2007 2:24 pm |
|
|
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
|
|
Posted: Wed Oct 10, 2007 2:47 pm |
|
|
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
|
|
Posted: Thu Oct 11, 2007 2:26 am |
|
|
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
|
|
Posted: Fri Oct 12, 2007 5:25 pm |
|
|
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
|
|
Posted: Sat Oct 13, 2007 3:10 am |
|
|
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
|
|
Posted: Sat Oct 13, 2007 3:13 pm |
|
|
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
|
|
Posted: Sat Oct 13, 2007 4:15 pm |
|
|
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
|
|
Posted: Sun Oct 14, 2007 2:29 am |
|
|
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
|
|
Posted: Sun Oct 14, 2007 3:09 am |
|
|
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
|
|
Posted: Sun Oct 14, 2007 3:38 pm |
|
|
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
|
|
Posted: Mon Oct 15, 2007 2:04 am |
|
|
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 |
|
|
|
|
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
|