06-22-2009 04:00 AM
void tnt4882_setup_read(void) { //######## 1) Reset Fifo Register TNT_Out(R_CMDR, RstFIFO); //######## 2) Set B_tlchlte to halt when interrupt condition sets and B-in for In TNT_Out(R_CFG, (B_tlchlte | B_in)); //######## 3) Load Data Count Registers: max. 128 bytes TNT_Out(R_CNT0, 0x01); TNT_Out(R_CNT1, 0x00); TNT_Out(R_AUXMR, 0x86); // holdoff on EOS //######## 4) TNT_Out(R_IMR1, E_END); // End byte detection //######## 5) Send Go Command TNT_Out(R_CMDR, 0x04); //######## 6) Send Go Command TNT_Out(R_IMR3, (E_TLCINT | E_NEF | E_DONE)); // Enable Intrrupts from ISR0 and ISR1 //######## 7) Issue Release Holdoff TNT_Out(R_AUXMR, RHDF); //######## Set Timeout Condition to 1ms TNT_Out (R_AUXRJ, 0x0B);
}
unsigned char tnt4882_receive_data(void) {
static u16 counted_bytes = 0;
u8 isr3;
u16 max_trials = 500;
u8 dummy;
// printf("\r\nListen: ");
tnt4882_setup_read();
while(!(TNT_In(R_ISR3) & E_DONE) ){
while (((isr3 = TNT_In(R_ISR3)) & E_NEF) && max_trials > 0) {
char_arr[counted_bytes] = TNT_In(R_FIFOB);
counted_bytes++;
max_trials--;
}
}
isr3 = TNT_In(R_ISR3);
if (isr3 & E_DONE) {
if ((char_arr[counted_bytes - 1] == '\r') || (char_arr[counted_bytes - 1] == '\n')) {
char_arr[counted_bytes - 1] = '\0'; // replace '\n' with '\0'
}
else {
char_arr[counted_bytes] = '\0';
}
if (!global_flag.received) {
gpib_cmd = &char_arr[0];
global_flag.received = 1;
global_flag.gpib_rxrdy = 1;
}
counted_bytes = 0;
}
TNT_Out(R_CMDR, STOP);
TNT_Out(R_CMDR, RstFIFO);
// Clear Error status bit
TNT_Out(R_AUXMR, ClrERR);
// Clear End status bit
TNT_Out(R_AUXMR, ClrEND);
// Clear Power-On Local message
TNT_Out(R_AUXMR, PON);
// clear time out condition
TNT_Out(R_AUXRJ, 0x00);
dummy = TNT_In(R_CNT0);
dummy = TNT_In(R_CNT1);
/*
if (TNT_In(R_ISR3)) {
dummy = TNT_In(R_ISR0);
dummy = TNT_In(R_ISR1);
dummy = TNT_In(R_ISR2);
}
TNT_Out(R_IMR3, 0x00);
TNT_Out(R_CMDR, RstFIFO);
*/
if (!max_trials) tnt4882_init();
return 1;
}
There is my read function which is used to read received data from tnt4882 in generic mode.
If i send data (using NI MAX) to the TNT488, every second write results in one "ENOL" error. I read here, that is depended on
TNT_Out(R_AUXMR, PON);
here is ADSR check function of the main loop:
gpib_addr_state = TNT_In(R_ADSR);
if (gpib_addr_state & B_TA) { // addressed to talk
tnt4882_send_data();
}
else
if (gpib_addr_state & B_LA) { // addressed to listen
tnt4882_receive_data();
}
because NI MAX doenst readdress the device on multiply writes. I allready tried to read and clear ISR Flags but without success 😕
Someone an good idea?
06-23-2009 08:37 AM
Hello Artur,
There are actually two ways to deal with this issue.
1. This is actually a fiarly common problem with instruments. Its so common that NI-488.2 has an option to automatically deal with this. In your control program, you can sent a configuration parameter that will result in the controller re-addressing the instrument for every write. The result will be that every ibwrt will address the instrument to listen. This should prevent your ENOL errors.
ibconfig ( device, IbcREADDR, 1 );
2. Another problem that I see is that you are checking in a loop to see if you are addressed to talk or listen. Do you actually detect that you are a talker or listener? If you detect that you are a listener, the read will not actually happen because the GO message is only sent in your tnat4882_setup_read routine. You would need to setup a new read, then perform the actual read each time that you detect that you are still listener.
If you setup a new read instead of going straight into the read routine, the read will continuously happen as long as the instrument is addressed as listener. This will result in timeouts on the instrument when it reads and data is not actively coming in (which is acceptable...the instrument can simply ignore these with no bad consequences).
I hope this helps,
Steven T.
10-28-2010 11:16 AM
Hello,
i followed Steven T's advice and solved the problem with subsequent writes by using of the readdressing flag. But now a customer means that the flag doesnt helps him in his setup. So i started to work out a new solution. I found that the readdressing was required because the PON Flag was set in my read function. Now it works without readdressing with this code as solution
//-------------------------------------------------------------------------------// TNT4882: setup tnt488 for sending data if addressed as a talker //-------------------------------------------------------------------------------void tnt4882_setup_write(u16 byte_cnt) { //######## 1) Reset Fifo Register TNT_Out(R_CMDR, RstFIFO); //######## 2) Set B_tlchlte to halt when interrupt condition sets TNT_Out(R_CFG, (B_tlchlte | B_ccen)); //######## 3) Load Data Count Registers TNT_Out(R_CNT0, -byte_cnt); TNT_Out(R_CNT1, 0xFF); //######## 4) TNT_Out(R_IMR1, E_ERR); // Enable No Listener Detection Interrupt TNT_Out(R_IMR0, (E_BTO | E_GLINT)); // Timeout Interrupt enable //######## 5) Send Go Command TNT_Out(R_CMDR, 0x04); //######## 6) Send Go Command TNT_Out(R_IMR3, (E_TLCINT | E_NFF | E_DONE)); // Enable Intrrupts from ISR0 and ISR1 //######## Set Timeout Condition to 1ms TNT_Out (R_AUXRJ, 0x0B); } //-------------------------------------------------------------------------------// TNT4882: send data //-------------------------------------------------------------------------------unsigned char tnt4882_send_data(void) { u8 i, a; u8 isr3; u8 bytes; u16 max_trials = 500; u8 dummy; bytes = strlen(str_talk); // str_talk[bytes] = '\n'; // setup TNT Chip for Talker Operation tnt4882_setup_write(bytes); isr3 = TNT_In(R_ISR3); if(isr3 & E_TLCINT) { TNT_Out(R_IMR0, 0x00); TNT_Out(R_IMR1, 0x00); TNT_Out(R_IMR3, 0x00); TNT_Out(R_ISR0, 0x00); TNT_Out(R_ISR1, 0x00); TNT_Out(R_ISR3, 0x00); TNT_Out(R_CMDR, STOP); TNT_Out(R_AUXMR, 0x00); TNT_Out(R_AUXRJ, 0x00); return 0; } i = 0; for (a = bytes; a > 0; a--) { isr3 = TNT_In(R_ISR3); // while (isr3 & E_NFF); TNT_Out(R_FIFOB, str_talk[i]); // printf("%c", str_talk[i]); // _delay_us(1); i++; if(isr3 & E_TLCINT) { a = 0; break; } } if (0x00 == a) { do { isr3 = TNT_In(R_ISR3); max_trials--; } while(!(isr3 & E_DONE) && (max_trials > 1)); TNT_Out(R_CMDR, RstFIFO); TNT_Out(R_CMDR, STOP); TNT_Out(R_AUXMR, PON); /* Clear Power-On Local message */ }; TNT_Out(R_AUXMR, ClrEND); TNT_Out(R_AUXMR, ClrERR); TNT_Out(R_AUXRJ, 0x00); dummy = TNT_In(R_CNT0); dummy = TNT_In(R_CNT1); if (TNT_In(R_ISR3)) { dummy = TNT_In(R_ISR0); dummy = TNT_In(R_ISR1); dummy = TNT_In(R_ISR2); } if (!max_trials) tnt4882_init(); // _delay_ms(1); return 1; } //-------------------------------------------------------------------------------// TNT4882: setup tnt488 for reading data if addressed as a listener //-------------------------------------------------------------------------------void tnt4882_setup_read(void) { //######## 1) Reset Fifo Register TNT_Out(R_CMDR, RstFIFO); //######## 2) Set B_tlchlte to halt when interrupt condition sets and B-in for In TNT_Out(R_CFG, (B_tlchlte | B_in)); //######## 3) Load Data Count Registers: max. 128 bytes TNT_Out(R_CNT0, 0x01); TNT_Out(R_CNT1, 0x00); TNT_Out(R_AUXMR, 0x86); // holdoff on EOS //######## 4) TNT_Out(R_IMR1, E_END); // End byte detection //######## 5) Send Go Command TNT_Out(R_CMDR, 0x04); //######## 6) Send Go Command TNT_Out(R_IMR3, (E_TLCINT | E_NEF | E_DONE)); // Enable Intrrupts from ISR0 and ISR1 //######## 7) Issue Release Holdoff TNT_Out(R_AUXMR, RHDF); //######## Set Timeout Condition to 1ms TNT_Out (R_AUXRJ, 0x0B); } //-------------------------------------------------------------------------------// TNT4882: read data //-------------------------------------------------------------------------------unsigned char tnt4882_receive_data(void) { static u16 counted_bytes = 0; u8 isr3; u16 max_trials = 500; u8 dummy;
tnt4882_setup_read(); while (((isr3 = TNT_In(R_ISR3)) & E_NEF) && max_trials > 0) { char_arr[counted_bytes] = TNT_In(R_FIFOB); counted_bytes++; max_trials--; } isr3 = TNT_In(R_ISR3); if (isr3 & E_DONE) { if ((char_arr[counted_bytes - 1] == '\r') || (char_arr[counted_bytes - 1] == '\n')) { char_arr[counted_bytes - 1] = '\0'; // replace '\n' with '\0' } else { char_arr[counted_bytes] = '\0'; } if (!global_flag.received) { gpib_cmd = &char_arr[0]; gpib_cmd[counted_bytes] = '\0'; global_flag.received = 1; global_flag.gpib_rxrdy = 1; } counted_bytes = 0; } TNT_Out(R_CMDR, STOP); TNT_Out(R_CMDR, RstFIFO); // Clear Error status bit TNT_Out(R_AUXMR, ClrERR); // Clear End status bit TNT_Out(R_AUXMR, ClrEND); TNT_Out(R_IMR3, 0x00); // Clear Power-On Local message //TNT_Out(R_AUXMR, PON); // clear time out condition TNT_Out(R_AUXRJ, 0x00); dummy = TNT_In(R_CNT0); dummy = TNT_In(R_CNT1); if (TNT_In(R_ISR3)) { dummy = TNT_In(R_ISR0); dummy = TNT_In(R_ISR1); dummy = TNT_In(R_ISR2); } return 1; }
and this check for addressed flag in the main loop:
do { gpib_addr_state = TNT_In(R_ADSR); if(gpib_addr_state & B_TA) { tnt4882_send_data(); } else if(gpib_addr_state & B_LA) { tnt4882_receive_data(); } } while(1);
//-------------------------------------------------------------------------------// TNT4882: Initialize TNT4882 Chip //-------------------------------------------------------------------------------void tnt4882_init (void) { tnt4882_atmega_interface_init(); // init. interface between tnt and atmega tnt4882_reset(); // tnt4882 hard reset TNT_DELAY; //######## 1) Reset the Turbo488 circuitry TNT_Out(R_CMDR, 0x22); // issue a soft reset TNT_DELAY; //######## 2) Place the TNT in Turbo+7210 mode TNT_Out(R_SPMR, 0x80); TNT_Out(R_AUXMR, 0x80); TNT_Out(R_SPMR, 0x99); TNT_Out(R_AUXMR, 0x99); //######## 3) Configure the TNT4882 for one-chip mode TNT_Out(R_HSSEL, (E_ONEC | E_NODMA)); // place TNT in one chip mode //######## 4) Make sure that the Local Power-On Message is Asserted TNT_Out(R_AUXMR, 0x02); //######## 5) Configure the TNT4882 for GPIB Operation TNT_Out(R_ADMR, NormDual); // set dual primary addressing mode TNT_Out(R_ADR, gpib_get_addr()); // set GPIB Address TNT_Out(R_ADR, 0xE0); // no secondary address // write the initial serial poll response TNT_Out(R_SPMR, 0x99); //######## 6) Write the Local Power-On Message to Begin GPIB Operation TNT_Out(R_AUXMR, HLDI); // hold off immediately TNT_DELAY; TNT_Out(R_AUXMR, PON); // issue Power-On //######## user config: additional TNT_Out(R_EOSR, '\n'); // set termination char //######## user config: additional TNT_Out(R_INTR, 0x00); // No ISA Mode -> Disable Interrupts }
Now it seems to work with NI GPIB-USB and NI-GPIB-PCI Cards. I can send multiply writes trough the Measurement & Automation to the device and everything works fine. But Measurement & Automation at the PC with GPIB-PCI controller is sometimes not able to get the right *IDN? answer from the device. I found out that my gpib module with the given code receives sometimes (in 1 of 20 trials) just N? or ? or ?*IDN? if I search for modules in Measurement & Automation app. Any ideas? Maybe I forgot to set another important flag? What can cause these data leaks?
11-03-2010 04:10 PM
Hello,
What does the code do when it receives the command to listen from the controller? Most of the time, the initialization sections should clear the FIFO to make sure that it doesn't receive leftover data from the last transfer.
I would also want to see the receive section of the code since that is what only receives partial queries from the controller.
Thanks,
Steven T.
11-05-2010 08:12 AM
► main loop detects if the
devices becomes addressed
► tnt4882_receive_data(); reads data from FIFOB after the initialization of the
TNT as listener
► tnt4882_send_data(void); transmits the data from TNT to the PC
Everything works fine if I use agilent USB-GPIB Controller (because of automatically readdressing) or the device control software opens and closes the connection to the device after each command transmitting by using of NI GPIB controller.
My problem is to realize the possibility for multiply writes to the device without to readdress the device as listener or closing of the connection every time.
I understand the problem of my code. I allready spend a lot of time to fix this issue but without the effort. The problem is that the TNT stays addressed as listener after the first command was received. In this time span while the µC leaves the tnt4882_receive_data function and detects in the main loop that the tnt is still addressed as listener something gets wrong. I don’t know what. I followed the instructions of ESP and I think all functions are well coded.
>I would also want to see the receive section of the code since that is what only receives partial queries from the >controller.
tnt4882_receive_data(); is my receive function. As you can see the counted_bytes variable is static so the counting of bytes will continuous while no E_DONE was received.
Instead to go direct into the receive function it would be better (if it is possible) to check for availability of a new message (OES detection maybe?) Than initialize the tnt to read the FIFO data. Any idea how to realize that? Where the MAV flag is located?