DRDY PIC18F45K80 to QT1481












-1















I also have a problem with DRDY. I need to include DRDY. The pins for DRDY are RD2 and RD5. They are both inputs.



Here is the information for DRDY.



DRDY Pin
DRDY is an open-drain output (in SPI mode) or bidirectional pin (in UART mode) with an internal 20 k – 50 k pullup
resistor.

Most communications failures are the result of failure to properly observe the DRDY timing.
Serial communications pacing is controlled by this pin. Use of DRDY is critical to successful communications with the
QT1481. In either UART or SPI mode, the host is permitted to perform a data transfer only when DRDY has returned
high. Additionally, in UART mode, the QT1481 delays responses to the host if DRDY is being held low by the host.

After each byte transfer, DRDY goes low after a short delay and remains low until the QT1481 is ready for another
transfer. A short delay occurs before DRDY is driven low because the QT1481 may otherwise be busy and requires
a finite time to respond.



DRDY may go low for a microsecond only. During the period from the end of one transfer until DRDY goes low and
back high again, the host should not perform another transfer. Therefore, before each byte transmission the host
should first check that DRDY is high again.
If the host wants to perform a byte transfer with the QT1481 it should behave as follows:

1. Wait at least 100 µs after the previous transfer (time S5 in Figure 3-2 on page 23: DRDY is guaranteed to go
low before this 100 µs expires).

2. Wait until DRDY is high (it may already be high).

3. Perform the next transfer with the QT1481.

In most cases it takes up to 3 ms for DRDY to return high again. However, this time is longer with some commands
or if the STS_DEBUG setup is enabled, as follows:
0x01 (Setups load): <20 ms
0x02 (Low Level Cal and Offset): <20 ms

Add 15 ms to the above times if the STS_DEBUG setup is enabled.
Other DRDY specifications:

Min time DRDY is low: 1 µs

Max time DRDY is low after reset: 100 ms



The timing diagram is this: enter image description here



How can implement that?



The code I have written with my friend is written here:



#include <xc.h>
#include "PIC.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
//#include <pic18f45k80.h>

#define MSB 1
#define LSB 0

// SPI PIN CONFIGURATION

#define SCK_TRIS TRISCbits.TRISC3 = 0 ;
#define SDO_TRIS TRISCbits.TRISC5 = 0 ;
#define SDI_TRIS TRISCbits.TRISC4 = 1 ;
#define QTA_SS_TRIS TRISDbits.TRISD4 = 0 ;
#define QTB_SS_TRIS TRISEbits.TRISE2 = 0 ;
#define QTA_SS_LAT_LOW LATDbits.LATD4 = 0 ;
#define QTA_SS_LAT_HIGH LATDbits.LATD4 = 1 ;
#define QTB_SS_LAT_LOW LATEbits.LATE2 = 0 ;
#define QTB_SS_LAT_HIGH LATEbits.LATE2 = 1 ;
#define QTA_DRDY_TRIS TRISDbits.TRISD5 = 1 ;
#define QTB_DRDY_TRIS TRISDbits.TRISD2 = 1 ;
#define QTA_DRDY_LAT_LOW LATDbits.LATD5 = 0 ;
#define QTA_DRDY_LAT_HIGH LATDbits.LAT52 = 1 ;
#define QTB_DRDY_LAT_LOW LATDbits.LAT25 = 0 ;
#define QTB_DRDY_LAT_HIGH LATDbits.LATD2 = 1 ;
#define QTB_DRDY PORTDbits.RD2 ;
#define QTA_DRDY PORTDbits.RD5 ;

// FREQUENCY SELECT

#define _XTAL_FREQ 16000000

// PIN SETUP

void PIN_MANAGER_Initialize(void)
{
/**
LATx registers
*/
LATE = 0x00;
LATD = 0x00;
LATA = 0x00;
LATB = 0b00010000;
LATC = 0x00;

/**
TRISx registers
*/
TRISE = 0x00;
TRISA = 0x08;
TRISB = 0x01;
TRISC = 0b00010000;
TRISD = 0xEF;

PORTC = 0b00010010 ;

/**
ANSELx registers
*/
ANCON0 = 0x00;
ANCON1 = 0x00;

/**
WPUx registers
*/
WPUB = 0x00;
INTCON2bits.nRBPU = 1;

}

// SPI

void SPI_Initialize(void)
{

// SMP Middle; CKE Idle to Active;
SSPSTAT = 0b00000000;

// SSPEN enabled; WCOL no_collision; CKP Idle:High, Active:Low; SSPM FOSC/4; SSPOV no_overflow;
SSPCON1 = 0b00111010;

// SSPADD 0;
SSPADD = 0x00;

ADCON0 = 0 ;
ADCON1 = 0x0F ; //Makes all I/O digital

SCK_TRIS ;
SDO_TRIS ;
SDI_TRIS ;
QTA_SS_TRIS ;
QTB_SS_TRIS ;
QTA_DRDY_TRIS ;
QTB_DRDY_TRIS ;
}

signed char WriteSPI( unsigned char data_out )
{
unsigned char TempVar;
TempVar = SSPBUF; // Clears BF
PIR1bits.SSPIF = 0; // Clear interrupt flag
SSPCON1bits.WCOL = 0; //Clear any previous write collision
SSPBUF = data_out; // write byte to SSPBUF register
if ( SSPCON1 & 0x80 ) // test if write collision occurred
return ( -1 ); // if WCOL bit is set return negative #
else
while( !PIR1bits.SSPIF ); // wait until bus cycle complete
return ( 0 ); // if WCOL bit is not set return non-negative#
}


unsigned char ReadSPI( void )
{
unsigned char TempVar;
TempVar = SSPBUF; // Clear BF
PIR1bits.SSPIF = 0; // Clear interrupt flag
SSPBUF = 0x00; // initiate bus cycle
while(!PIR1bits.SSPIF); // wait until cycle complete
return ( SSPBUF ); // return with byte read
}

unsigned char DataRdySPI( void )
{
if ( SSPSTATbits.BF )
return ( +1 ); // data in SSPBUF register
else
return ( 0 ); // no data in SSPBUF register
}


// SOFTWARE EUART

void out_char(char character, char bit_order){

uint8_t i = 0;
RSOUT = 1 ; // MSB
__delay_ms(1);
RSOUT = 0 ; // START
__delay_us(100);
for (i = 8; i>0; --i){
if (bit_order){ // Bit order determines how you will put the bits, from left to right (MSB) or right to left (LSB)
RSOUT = (character & 0x80) ? 1:0; // in MSB you compare the left-most bit doing an AND with 0x80, and put 1 if true, 0 elsewhere.
character <<= 1; // Shift the character to the left, discrading the bit just sent
} else {
RSOUT = (character & 0x01); // in LSB you compare the right-most bit doing an AND with 0x01, and put 1 if true, 0 else.
character >>= 1; // Shift the character to the right, discrading the bit just sent
}
__delay_us(100);
}
RSOUT = 1 ; // STOP

}

void out_str(char * string, uint8_t len, char bit_order){
uint8_t i = 0;
for (i = 0; i< len; i++){
out_char(string[i], bit_order);
}
}

void SYSTEM_Initialize(void)
{

PIN_MANAGER_Initialize() ;
SPI_Initialize() ;
}

void main(void)
{
SYSTEM_Initialize() ;

while (1)
{
QTB_SS_LAT_LOW ; // Transmit data
char temp ;
WriteSPI(0x0F) ; // Send a byte
while(!DataRdySPI()) ; // wait for a data to arrive
temp = ReadSPI(); // Read a byte from the
QTB_SS_LAT_HIGH ; // Stop transmitting data
__delay_us(100) ;
}
}









share|improve this question

























  • This question is too broad, as you are essentially asking how to do the whole implementation. You either need to sync the signal with the SPI transmission, or sync the SPI with the signal. For example you can start a timer after the SPI flag does up and toggle the pin from there. This is why experienced devs read the timing specs of the part using SPI before picking it - because there exists so much dirty non-standard crap like this in the market and you really don't want to be stuck with a non-standard SPI implementation. Be extra careful before specifying Microchip/Atmel or ST parts.

    – Lundin
    Nov 20 '18 at 14:45













  • I cannot get my DRDY to be idle high. Is there something wrong in the code?

    – M2T156
    Nov 20 '18 at 15:04
















-1















I also have a problem with DRDY. I need to include DRDY. The pins for DRDY are RD2 and RD5. They are both inputs.



Here is the information for DRDY.



DRDY Pin
DRDY is an open-drain output (in SPI mode) or bidirectional pin (in UART mode) with an internal 20 k – 50 k pullup
resistor.

Most communications failures are the result of failure to properly observe the DRDY timing.
Serial communications pacing is controlled by this pin. Use of DRDY is critical to successful communications with the
QT1481. In either UART or SPI mode, the host is permitted to perform a data transfer only when DRDY has returned
high. Additionally, in UART mode, the QT1481 delays responses to the host if DRDY is being held low by the host.

After each byte transfer, DRDY goes low after a short delay and remains low until the QT1481 is ready for another
transfer. A short delay occurs before DRDY is driven low because the QT1481 may otherwise be busy and requires
a finite time to respond.



DRDY may go low for a microsecond only. During the period from the end of one transfer until DRDY goes low and
back high again, the host should not perform another transfer. Therefore, before each byte transmission the host
should first check that DRDY is high again.
If the host wants to perform a byte transfer with the QT1481 it should behave as follows:

1. Wait at least 100 µs after the previous transfer (time S5 in Figure 3-2 on page 23: DRDY is guaranteed to go
low before this 100 µs expires).

2. Wait until DRDY is high (it may already be high).

3. Perform the next transfer with the QT1481.

In most cases it takes up to 3 ms for DRDY to return high again. However, this time is longer with some commands
or if the STS_DEBUG setup is enabled, as follows:
0x01 (Setups load): <20 ms
0x02 (Low Level Cal and Offset): <20 ms

Add 15 ms to the above times if the STS_DEBUG setup is enabled.
Other DRDY specifications:

Min time DRDY is low: 1 µs

Max time DRDY is low after reset: 100 ms



The timing diagram is this: enter image description here



How can implement that?



The code I have written with my friend is written here:



#include <xc.h>
#include "PIC.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
//#include <pic18f45k80.h>

#define MSB 1
#define LSB 0

// SPI PIN CONFIGURATION

#define SCK_TRIS TRISCbits.TRISC3 = 0 ;
#define SDO_TRIS TRISCbits.TRISC5 = 0 ;
#define SDI_TRIS TRISCbits.TRISC4 = 1 ;
#define QTA_SS_TRIS TRISDbits.TRISD4 = 0 ;
#define QTB_SS_TRIS TRISEbits.TRISE2 = 0 ;
#define QTA_SS_LAT_LOW LATDbits.LATD4 = 0 ;
#define QTA_SS_LAT_HIGH LATDbits.LATD4 = 1 ;
#define QTB_SS_LAT_LOW LATEbits.LATE2 = 0 ;
#define QTB_SS_LAT_HIGH LATEbits.LATE2 = 1 ;
#define QTA_DRDY_TRIS TRISDbits.TRISD5 = 1 ;
#define QTB_DRDY_TRIS TRISDbits.TRISD2 = 1 ;
#define QTA_DRDY_LAT_LOW LATDbits.LATD5 = 0 ;
#define QTA_DRDY_LAT_HIGH LATDbits.LAT52 = 1 ;
#define QTB_DRDY_LAT_LOW LATDbits.LAT25 = 0 ;
#define QTB_DRDY_LAT_HIGH LATDbits.LATD2 = 1 ;
#define QTB_DRDY PORTDbits.RD2 ;
#define QTA_DRDY PORTDbits.RD5 ;

// FREQUENCY SELECT

#define _XTAL_FREQ 16000000

// PIN SETUP

void PIN_MANAGER_Initialize(void)
{
/**
LATx registers
*/
LATE = 0x00;
LATD = 0x00;
LATA = 0x00;
LATB = 0b00010000;
LATC = 0x00;

/**
TRISx registers
*/
TRISE = 0x00;
TRISA = 0x08;
TRISB = 0x01;
TRISC = 0b00010000;
TRISD = 0xEF;

PORTC = 0b00010010 ;

/**
ANSELx registers
*/
ANCON0 = 0x00;
ANCON1 = 0x00;

/**
WPUx registers
*/
WPUB = 0x00;
INTCON2bits.nRBPU = 1;

}

// SPI

void SPI_Initialize(void)
{

// SMP Middle; CKE Idle to Active;
SSPSTAT = 0b00000000;

// SSPEN enabled; WCOL no_collision; CKP Idle:High, Active:Low; SSPM FOSC/4; SSPOV no_overflow;
SSPCON1 = 0b00111010;

// SSPADD 0;
SSPADD = 0x00;

ADCON0 = 0 ;
ADCON1 = 0x0F ; //Makes all I/O digital

SCK_TRIS ;
SDO_TRIS ;
SDI_TRIS ;
QTA_SS_TRIS ;
QTB_SS_TRIS ;
QTA_DRDY_TRIS ;
QTB_DRDY_TRIS ;
}

signed char WriteSPI( unsigned char data_out )
{
unsigned char TempVar;
TempVar = SSPBUF; // Clears BF
PIR1bits.SSPIF = 0; // Clear interrupt flag
SSPCON1bits.WCOL = 0; //Clear any previous write collision
SSPBUF = data_out; // write byte to SSPBUF register
if ( SSPCON1 & 0x80 ) // test if write collision occurred
return ( -1 ); // if WCOL bit is set return negative #
else
while( !PIR1bits.SSPIF ); // wait until bus cycle complete
return ( 0 ); // if WCOL bit is not set return non-negative#
}


unsigned char ReadSPI( void )
{
unsigned char TempVar;
TempVar = SSPBUF; // Clear BF
PIR1bits.SSPIF = 0; // Clear interrupt flag
SSPBUF = 0x00; // initiate bus cycle
while(!PIR1bits.SSPIF); // wait until cycle complete
return ( SSPBUF ); // return with byte read
}

unsigned char DataRdySPI( void )
{
if ( SSPSTATbits.BF )
return ( +1 ); // data in SSPBUF register
else
return ( 0 ); // no data in SSPBUF register
}


// SOFTWARE EUART

void out_char(char character, char bit_order){

uint8_t i = 0;
RSOUT = 1 ; // MSB
__delay_ms(1);
RSOUT = 0 ; // START
__delay_us(100);
for (i = 8; i>0; --i){
if (bit_order){ // Bit order determines how you will put the bits, from left to right (MSB) or right to left (LSB)
RSOUT = (character & 0x80) ? 1:0; // in MSB you compare the left-most bit doing an AND with 0x80, and put 1 if true, 0 elsewhere.
character <<= 1; // Shift the character to the left, discrading the bit just sent
} else {
RSOUT = (character & 0x01); // in LSB you compare the right-most bit doing an AND with 0x01, and put 1 if true, 0 else.
character >>= 1; // Shift the character to the right, discrading the bit just sent
}
__delay_us(100);
}
RSOUT = 1 ; // STOP

}

void out_str(char * string, uint8_t len, char bit_order){
uint8_t i = 0;
for (i = 0; i< len; i++){
out_char(string[i], bit_order);
}
}

void SYSTEM_Initialize(void)
{

PIN_MANAGER_Initialize() ;
SPI_Initialize() ;
}

void main(void)
{
SYSTEM_Initialize() ;

while (1)
{
QTB_SS_LAT_LOW ; // Transmit data
char temp ;
WriteSPI(0x0F) ; // Send a byte
while(!DataRdySPI()) ; // wait for a data to arrive
temp = ReadSPI(); // Read a byte from the
QTB_SS_LAT_HIGH ; // Stop transmitting data
__delay_us(100) ;
}
}









share|improve this question

























  • This question is too broad, as you are essentially asking how to do the whole implementation. You either need to sync the signal with the SPI transmission, or sync the SPI with the signal. For example you can start a timer after the SPI flag does up and toggle the pin from there. This is why experienced devs read the timing specs of the part using SPI before picking it - because there exists so much dirty non-standard crap like this in the market and you really don't want to be stuck with a non-standard SPI implementation. Be extra careful before specifying Microchip/Atmel or ST parts.

    – Lundin
    Nov 20 '18 at 14:45













  • I cannot get my DRDY to be idle high. Is there something wrong in the code?

    – M2T156
    Nov 20 '18 at 15:04














-1












-1








-1








I also have a problem with DRDY. I need to include DRDY. The pins for DRDY are RD2 and RD5. They are both inputs.



Here is the information for DRDY.



DRDY Pin
DRDY is an open-drain output (in SPI mode) or bidirectional pin (in UART mode) with an internal 20 k – 50 k pullup
resistor.

Most communications failures are the result of failure to properly observe the DRDY timing.
Serial communications pacing is controlled by this pin. Use of DRDY is critical to successful communications with the
QT1481. In either UART or SPI mode, the host is permitted to perform a data transfer only when DRDY has returned
high. Additionally, in UART mode, the QT1481 delays responses to the host if DRDY is being held low by the host.

After each byte transfer, DRDY goes low after a short delay and remains low until the QT1481 is ready for another
transfer. A short delay occurs before DRDY is driven low because the QT1481 may otherwise be busy and requires
a finite time to respond.



DRDY may go low for a microsecond only. During the period from the end of one transfer until DRDY goes low and
back high again, the host should not perform another transfer. Therefore, before each byte transmission the host
should first check that DRDY is high again.
If the host wants to perform a byte transfer with the QT1481 it should behave as follows:

1. Wait at least 100 µs after the previous transfer (time S5 in Figure 3-2 on page 23: DRDY is guaranteed to go
low before this 100 µs expires).

2. Wait until DRDY is high (it may already be high).

3. Perform the next transfer with the QT1481.

In most cases it takes up to 3 ms for DRDY to return high again. However, this time is longer with some commands
or if the STS_DEBUG setup is enabled, as follows:
0x01 (Setups load): <20 ms
0x02 (Low Level Cal and Offset): <20 ms

Add 15 ms to the above times if the STS_DEBUG setup is enabled.
Other DRDY specifications:

Min time DRDY is low: 1 µs

Max time DRDY is low after reset: 100 ms



The timing diagram is this: enter image description here



How can implement that?



The code I have written with my friend is written here:



#include <xc.h>
#include "PIC.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
//#include <pic18f45k80.h>

#define MSB 1
#define LSB 0

// SPI PIN CONFIGURATION

#define SCK_TRIS TRISCbits.TRISC3 = 0 ;
#define SDO_TRIS TRISCbits.TRISC5 = 0 ;
#define SDI_TRIS TRISCbits.TRISC4 = 1 ;
#define QTA_SS_TRIS TRISDbits.TRISD4 = 0 ;
#define QTB_SS_TRIS TRISEbits.TRISE2 = 0 ;
#define QTA_SS_LAT_LOW LATDbits.LATD4 = 0 ;
#define QTA_SS_LAT_HIGH LATDbits.LATD4 = 1 ;
#define QTB_SS_LAT_LOW LATEbits.LATE2 = 0 ;
#define QTB_SS_LAT_HIGH LATEbits.LATE2 = 1 ;
#define QTA_DRDY_TRIS TRISDbits.TRISD5 = 1 ;
#define QTB_DRDY_TRIS TRISDbits.TRISD2 = 1 ;
#define QTA_DRDY_LAT_LOW LATDbits.LATD5 = 0 ;
#define QTA_DRDY_LAT_HIGH LATDbits.LAT52 = 1 ;
#define QTB_DRDY_LAT_LOW LATDbits.LAT25 = 0 ;
#define QTB_DRDY_LAT_HIGH LATDbits.LATD2 = 1 ;
#define QTB_DRDY PORTDbits.RD2 ;
#define QTA_DRDY PORTDbits.RD5 ;

// FREQUENCY SELECT

#define _XTAL_FREQ 16000000

// PIN SETUP

void PIN_MANAGER_Initialize(void)
{
/**
LATx registers
*/
LATE = 0x00;
LATD = 0x00;
LATA = 0x00;
LATB = 0b00010000;
LATC = 0x00;

/**
TRISx registers
*/
TRISE = 0x00;
TRISA = 0x08;
TRISB = 0x01;
TRISC = 0b00010000;
TRISD = 0xEF;

PORTC = 0b00010010 ;

/**
ANSELx registers
*/
ANCON0 = 0x00;
ANCON1 = 0x00;

/**
WPUx registers
*/
WPUB = 0x00;
INTCON2bits.nRBPU = 1;

}

// SPI

void SPI_Initialize(void)
{

// SMP Middle; CKE Idle to Active;
SSPSTAT = 0b00000000;

// SSPEN enabled; WCOL no_collision; CKP Idle:High, Active:Low; SSPM FOSC/4; SSPOV no_overflow;
SSPCON1 = 0b00111010;

// SSPADD 0;
SSPADD = 0x00;

ADCON0 = 0 ;
ADCON1 = 0x0F ; //Makes all I/O digital

SCK_TRIS ;
SDO_TRIS ;
SDI_TRIS ;
QTA_SS_TRIS ;
QTB_SS_TRIS ;
QTA_DRDY_TRIS ;
QTB_DRDY_TRIS ;
}

signed char WriteSPI( unsigned char data_out )
{
unsigned char TempVar;
TempVar = SSPBUF; // Clears BF
PIR1bits.SSPIF = 0; // Clear interrupt flag
SSPCON1bits.WCOL = 0; //Clear any previous write collision
SSPBUF = data_out; // write byte to SSPBUF register
if ( SSPCON1 & 0x80 ) // test if write collision occurred
return ( -1 ); // if WCOL bit is set return negative #
else
while( !PIR1bits.SSPIF ); // wait until bus cycle complete
return ( 0 ); // if WCOL bit is not set return non-negative#
}


unsigned char ReadSPI( void )
{
unsigned char TempVar;
TempVar = SSPBUF; // Clear BF
PIR1bits.SSPIF = 0; // Clear interrupt flag
SSPBUF = 0x00; // initiate bus cycle
while(!PIR1bits.SSPIF); // wait until cycle complete
return ( SSPBUF ); // return with byte read
}

unsigned char DataRdySPI( void )
{
if ( SSPSTATbits.BF )
return ( +1 ); // data in SSPBUF register
else
return ( 0 ); // no data in SSPBUF register
}


// SOFTWARE EUART

void out_char(char character, char bit_order){

uint8_t i = 0;
RSOUT = 1 ; // MSB
__delay_ms(1);
RSOUT = 0 ; // START
__delay_us(100);
for (i = 8; i>0; --i){
if (bit_order){ // Bit order determines how you will put the bits, from left to right (MSB) or right to left (LSB)
RSOUT = (character & 0x80) ? 1:0; // in MSB you compare the left-most bit doing an AND with 0x80, and put 1 if true, 0 elsewhere.
character <<= 1; // Shift the character to the left, discrading the bit just sent
} else {
RSOUT = (character & 0x01); // in LSB you compare the right-most bit doing an AND with 0x01, and put 1 if true, 0 else.
character >>= 1; // Shift the character to the right, discrading the bit just sent
}
__delay_us(100);
}
RSOUT = 1 ; // STOP

}

void out_str(char * string, uint8_t len, char bit_order){
uint8_t i = 0;
for (i = 0; i< len; i++){
out_char(string[i], bit_order);
}
}

void SYSTEM_Initialize(void)
{

PIN_MANAGER_Initialize() ;
SPI_Initialize() ;
}

void main(void)
{
SYSTEM_Initialize() ;

while (1)
{
QTB_SS_LAT_LOW ; // Transmit data
char temp ;
WriteSPI(0x0F) ; // Send a byte
while(!DataRdySPI()) ; // wait for a data to arrive
temp = ReadSPI(); // Read a byte from the
QTB_SS_LAT_HIGH ; // Stop transmitting data
__delay_us(100) ;
}
}









share|improve this question
















I also have a problem with DRDY. I need to include DRDY. The pins for DRDY are RD2 and RD5. They are both inputs.



Here is the information for DRDY.



DRDY Pin
DRDY is an open-drain output (in SPI mode) or bidirectional pin (in UART mode) with an internal 20 k – 50 k pullup
resistor.

Most communications failures are the result of failure to properly observe the DRDY timing.
Serial communications pacing is controlled by this pin. Use of DRDY is critical to successful communications with the
QT1481. In either UART or SPI mode, the host is permitted to perform a data transfer only when DRDY has returned
high. Additionally, in UART mode, the QT1481 delays responses to the host if DRDY is being held low by the host.

After each byte transfer, DRDY goes low after a short delay and remains low until the QT1481 is ready for another
transfer. A short delay occurs before DRDY is driven low because the QT1481 may otherwise be busy and requires
a finite time to respond.



DRDY may go low for a microsecond only. During the period from the end of one transfer until DRDY goes low and
back high again, the host should not perform another transfer. Therefore, before each byte transmission the host
should first check that DRDY is high again.
If the host wants to perform a byte transfer with the QT1481 it should behave as follows:

1. Wait at least 100 µs after the previous transfer (time S5 in Figure 3-2 on page 23: DRDY is guaranteed to go
low before this 100 µs expires).

2. Wait until DRDY is high (it may already be high).

3. Perform the next transfer with the QT1481.

In most cases it takes up to 3 ms for DRDY to return high again. However, this time is longer with some commands
or if the STS_DEBUG setup is enabled, as follows:
0x01 (Setups load): <20 ms
0x02 (Low Level Cal and Offset): <20 ms

Add 15 ms to the above times if the STS_DEBUG setup is enabled.
Other DRDY specifications:

Min time DRDY is low: 1 µs

Max time DRDY is low after reset: 100 ms



The timing diagram is this: enter image description here



How can implement that?



The code I have written with my friend is written here:



#include <xc.h>
#include "PIC.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
//#include <pic18f45k80.h>

#define MSB 1
#define LSB 0

// SPI PIN CONFIGURATION

#define SCK_TRIS TRISCbits.TRISC3 = 0 ;
#define SDO_TRIS TRISCbits.TRISC5 = 0 ;
#define SDI_TRIS TRISCbits.TRISC4 = 1 ;
#define QTA_SS_TRIS TRISDbits.TRISD4 = 0 ;
#define QTB_SS_TRIS TRISEbits.TRISE2 = 0 ;
#define QTA_SS_LAT_LOW LATDbits.LATD4 = 0 ;
#define QTA_SS_LAT_HIGH LATDbits.LATD4 = 1 ;
#define QTB_SS_LAT_LOW LATEbits.LATE2 = 0 ;
#define QTB_SS_LAT_HIGH LATEbits.LATE2 = 1 ;
#define QTA_DRDY_TRIS TRISDbits.TRISD5 = 1 ;
#define QTB_DRDY_TRIS TRISDbits.TRISD2 = 1 ;
#define QTA_DRDY_LAT_LOW LATDbits.LATD5 = 0 ;
#define QTA_DRDY_LAT_HIGH LATDbits.LAT52 = 1 ;
#define QTB_DRDY_LAT_LOW LATDbits.LAT25 = 0 ;
#define QTB_DRDY_LAT_HIGH LATDbits.LATD2 = 1 ;
#define QTB_DRDY PORTDbits.RD2 ;
#define QTA_DRDY PORTDbits.RD5 ;

// FREQUENCY SELECT

#define _XTAL_FREQ 16000000

// PIN SETUP

void PIN_MANAGER_Initialize(void)
{
/**
LATx registers
*/
LATE = 0x00;
LATD = 0x00;
LATA = 0x00;
LATB = 0b00010000;
LATC = 0x00;

/**
TRISx registers
*/
TRISE = 0x00;
TRISA = 0x08;
TRISB = 0x01;
TRISC = 0b00010000;
TRISD = 0xEF;

PORTC = 0b00010010 ;

/**
ANSELx registers
*/
ANCON0 = 0x00;
ANCON1 = 0x00;

/**
WPUx registers
*/
WPUB = 0x00;
INTCON2bits.nRBPU = 1;

}

// SPI

void SPI_Initialize(void)
{

// SMP Middle; CKE Idle to Active;
SSPSTAT = 0b00000000;

// SSPEN enabled; WCOL no_collision; CKP Idle:High, Active:Low; SSPM FOSC/4; SSPOV no_overflow;
SSPCON1 = 0b00111010;

// SSPADD 0;
SSPADD = 0x00;

ADCON0 = 0 ;
ADCON1 = 0x0F ; //Makes all I/O digital

SCK_TRIS ;
SDO_TRIS ;
SDI_TRIS ;
QTA_SS_TRIS ;
QTB_SS_TRIS ;
QTA_DRDY_TRIS ;
QTB_DRDY_TRIS ;
}

signed char WriteSPI( unsigned char data_out )
{
unsigned char TempVar;
TempVar = SSPBUF; // Clears BF
PIR1bits.SSPIF = 0; // Clear interrupt flag
SSPCON1bits.WCOL = 0; //Clear any previous write collision
SSPBUF = data_out; // write byte to SSPBUF register
if ( SSPCON1 & 0x80 ) // test if write collision occurred
return ( -1 ); // if WCOL bit is set return negative #
else
while( !PIR1bits.SSPIF ); // wait until bus cycle complete
return ( 0 ); // if WCOL bit is not set return non-negative#
}


unsigned char ReadSPI( void )
{
unsigned char TempVar;
TempVar = SSPBUF; // Clear BF
PIR1bits.SSPIF = 0; // Clear interrupt flag
SSPBUF = 0x00; // initiate bus cycle
while(!PIR1bits.SSPIF); // wait until cycle complete
return ( SSPBUF ); // return with byte read
}

unsigned char DataRdySPI( void )
{
if ( SSPSTATbits.BF )
return ( +1 ); // data in SSPBUF register
else
return ( 0 ); // no data in SSPBUF register
}


// SOFTWARE EUART

void out_char(char character, char bit_order){

uint8_t i = 0;
RSOUT = 1 ; // MSB
__delay_ms(1);
RSOUT = 0 ; // START
__delay_us(100);
for (i = 8; i>0; --i){
if (bit_order){ // Bit order determines how you will put the bits, from left to right (MSB) or right to left (LSB)
RSOUT = (character & 0x80) ? 1:0; // in MSB you compare the left-most bit doing an AND with 0x80, and put 1 if true, 0 elsewhere.
character <<= 1; // Shift the character to the left, discrading the bit just sent
} else {
RSOUT = (character & 0x01); // in LSB you compare the right-most bit doing an AND with 0x01, and put 1 if true, 0 else.
character >>= 1; // Shift the character to the right, discrading the bit just sent
}
__delay_us(100);
}
RSOUT = 1 ; // STOP

}

void out_str(char * string, uint8_t len, char bit_order){
uint8_t i = 0;
for (i = 0; i< len; i++){
out_char(string[i], bit_order);
}
}

void SYSTEM_Initialize(void)
{

PIN_MANAGER_Initialize() ;
SPI_Initialize() ;
}

void main(void)
{
SYSTEM_Initialize() ;

while (1)
{
QTB_SS_LAT_LOW ; // Transmit data
char temp ;
WriteSPI(0x0F) ; // Send a byte
while(!DataRdySPI()) ; // wait for a data to arrive
temp = ReadSPI(); // Read a byte from the
QTB_SS_LAT_HIGH ; // Stop transmitting data
__delay_us(100) ;
}
}






c pic spi






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 20 '18 at 14:24









Mike

2,0031722




2,0031722










asked Nov 20 '18 at 14:10









M2T156M2T156

215




215













  • This question is too broad, as you are essentially asking how to do the whole implementation. You either need to sync the signal with the SPI transmission, or sync the SPI with the signal. For example you can start a timer after the SPI flag does up and toggle the pin from there. This is why experienced devs read the timing specs of the part using SPI before picking it - because there exists so much dirty non-standard crap like this in the market and you really don't want to be stuck with a non-standard SPI implementation. Be extra careful before specifying Microchip/Atmel or ST parts.

    – Lundin
    Nov 20 '18 at 14:45













  • I cannot get my DRDY to be idle high. Is there something wrong in the code?

    – M2T156
    Nov 20 '18 at 15:04



















  • This question is too broad, as you are essentially asking how to do the whole implementation. You either need to sync the signal with the SPI transmission, or sync the SPI with the signal. For example you can start a timer after the SPI flag does up and toggle the pin from there. This is why experienced devs read the timing specs of the part using SPI before picking it - because there exists so much dirty non-standard crap like this in the market and you really don't want to be stuck with a non-standard SPI implementation. Be extra careful before specifying Microchip/Atmel or ST parts.

    – Lundin
    Nov 20 '18 at 14:45













  • I cannot get my DRDY to be idle high. Is there something wrong in the code?

    – M2T156
    Nov 20 '18 at 15:04

















This question is too broad, as you are essentially asking how to do the whole implementation. You either need to sync the signal with the SPI transmission, or sync the SPI with the signal. For example you can start a timer after the SPI flag does up and toggle the pin from there. This is why experienced devs read the timing specs of the part using SPI before picking it - because there exists so much dirty non-standard crap like this in the market and you really don't want to be stuck with a non-standard SPI implementation. Be extra careful before specifying Microchip/Atmel or ST parts.

– Lundin
Nov 20 '18 at 14:45







This question is too broad, as you are essentially asking how to do the whole implementation. You either need to sync the signal with the SPI transmission, or sync the SPI with the signal. For example you can start a timer after the SPI flag does up and toggle the pin from there. This is why experienced devs read the timing specs of the part using SPI before picking it - because there exists so much dirty non-standard crap like this in the market and you really don't want to be stuck with a non-standard SPI implementation. Be extra careful before specifying Microchip/Atmel or ST parts.

– Lundin
Nov 20 '18 at 14:45















I cannot get my DRDY to be idle high. Is there something wrong in the code?

– M2T156
Nov 20 '18 at 15:04





I cannot get my DRDY to be idle high. Is there something wrong in the code?

– M2T156
Nov 20 '18 at 15:04












1 Answer
1






active

oldest

votes


















1














No. Do not just write a bunch of code, then see what it does. That kind of shotgun (or, if you prefer, spaghetti-to-the-wall) approach is a waste of effort.



First, drop all those macros. Instead, write comments that describe the purpose of each chunk of code, like the first three assignments in your SPI_Initialize() function.



Next, convert your specification to pseudocode. The format does not matter much, just use something that lets you keep your mind focused on what the purpose is, rather than on the details on how to do it.



The datasheet says that with SPI, there are three outputs from the PIC (^SS, SCK, MOSI on the QT1481), and two inputs (^DRDY and MISO on the QT1481). I'll use those names for the data lines, and for their respective I/O pin names on the PIC.



The setup phase on the PIC should be simple:



Make ^DRDY an input
Make ^SS an output, set it HIGH

Make SCK an output, set it LOW
Make MOSI an output, set it LOW
Make MISO an input
Set up SPI using SCK, MOSI, MISO


Each transfer is a bidirectional one. Whenever you send data, you also receive data. The zero command is reserved for receiving multiple data, says the datasheet. So, you only need a function that sends a byte, and at the same time receives a byte:



Function  SPITransfer(command):

Make sure at least 0.1ms has passed since the previous transfer.

Do:
Nothing
While (^DRDY is LOW)

Set ^SS LOW

response = Transfer(command)

Set ^SS HIGH

Return response
End Function


As I understand it, for PICs and properly initialized hardware SPI the response = Transfer(command) line is in C



    SSPBUF = command;
while (!DataRdySPI())
;
response = SSPBUF;


You can also bit-bang it, in which case it is (in pseudocode):



    response = 0
For bit = 7 down to 0, inclusive:
If (command & 128):
Set MOSI high
Else:
Set MOSI low
End If

Set SCK low
Sleep for a half period

command = command / 2
response = response * 2
If MISO high:
response = response + 1
End If

Set SCK high
Sleep for a half period

End For


but obviously the hardware SPI approach is better.



(When you get this working, you can use the hardware SPI without a wait loop from a timer interrupt, making the communications essentially transparent to the "main operation" of the PIC microcontroller. That requires a slightly different approach, with a command and response queues (of a few bytes), but will make it much easier for the PIC to do actual work, other than just scan the QT1481.)



After a reset, you essentially send 0x0F until you get 0xF0 back:



    while (SPITransfer(0x0F) != 0xF0)
;


At this point, you have the steps you need to implement in C. OP also has the hardware (an oscilloscope) to verify their code works.






share|improve this answer























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53394889%2fdrdy-pic18f45k80-to-qt1481%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1














    No. Do not just write a bunch of code, then see what it does. That kind of shotgun (or, if you prefer, spaghetti-to-the-wall) approach is a waste of effort.



    First, drop all those macros. Instead, write comments that describe the purpose of each chunk of code, like the first three assignments in your SPI_Initialize() function.



    Next, convert your specification to pseudocode. The format does not matter much, just use something that lets you keep your mind focused on what the purpose is, rather than on the details on how to do it.



    The datasheet says that with SPI, there are three outputs from the PIC (^SS, SCK, MOSI on the QT1481), and two inputs (^DRDY and MISO on the QT1481). I'll use those names for the data lines, and for their respective I/O pin names on the PIC.



    The setup phase on the PIC should be simple:



    Make ^DRDY an input
    Make ^SS an output, set it HIGH

    Make SCK an output, set it LOW
    Make MOSI an output, set it LOW
    Make MISO an input
    Set up SPI using SCK, MOSI, MISO


    Each transfer is a bidirectional one. Whenever you send data, you also receive data. The zero command is reserved for receiving multiple data, says the datasheet. So, you only need a function that sends a byte, and at the same time receives a byte:



    Function  SPITransfer(command):

    Make sure at least 0.1ms has passed since the previous transfer.

    Do:
    Nothing
    While (^DRDY is LOW)

    Set ^SS LOW

    response = Transfer(command)

    Set ^SS HIGH

    Return response
    End Function


    As I understand it, for PICs and properly initialized hardware SPI the response = Transfer(command) line is in C



        SSPBUF = command;
    while (!DataRdySPI())
    ;
    response = SSPBUF;


    You can also bit-bang it, in which case it is (in pseudocode):



        response = 0
    For bit = 7 down to 0, inclusive:
    If (command & 128):
    Set MOSI high
    Else:
    Set MOSI low
    End If

    Set SCK low
    Sleep for a half period

    command = command / 2
    response = response * 2
    If MISO high:
    response = response + 1
    End If

    Set SCK high
    Sleep for a half period

    End For


    but obviously the hardware SPI approach is better.



    (When you get this working, you can use the hardware SPI without a wait loop from a timer interrupt, making the communications essentially transparent to the "main operation" of the PIC microcontroller. That requires a slightly different approach, with a command and response queues (of a few bytes), but will make it much easier for the PIC to do actual work, other than just scan the QT1481.)



    After a reset, you essentially send 0x0F until you get 0xF0 back:



        while (SPITransfer(0x0F) != 0xF0)
    ;


    At this point, you have the steps you need to implement in C. OP also has the hardware (an oscilloscope) to verify their code works.






    share|improve this answer




























      1














      No. Do not just write a bunch of code, then see what it does. That kind of shotgun (or, if you prefer, spaghetti-to-the-wall) approach is a waste of effort.



      First, drop all those macros. Instead, write comments that describe the purpose of each chunk of code, like the first three assignments in your SPI_Initialize() function.



      Next, convert your specification to pseudocode. The format does not matter much, just use something that lets you keep your mind focused on what the purpose is, rather than on the details on how to do it.



      The datasheet says that with SPI, there are three outputs from the PIC (^SS, SCK, MOSI on the QT1481), and two inputs (^DRDY and MISO on the QT1481). I'll use those names for the data lines, and for their respective I/O pin names on the PIC.



      The setup phase on the PIC should be simple:



      Make ^DRDY an input
      Make ^SS an output, set it HIGH

      Make SCK an output, set it LOW
      Make MOSI an output, set it LOW
      Make MISO an input
      Set up SPI using SCK, MOSI, MISO


      Each transfer is a bidirectional one. Whenever you send data, you also receive data. The zero command is reserved for receiving multiple data, says the datasheet. So, you only need a function that sends a byte, and at the same time receives a byte:



      Function  SPITransfer(command):

      Make sure at least 0.1ms has passed since the previous transfer.

      Do:
      Nothing
      While (^DRDY is LOW)

      Set ^SS LOW

      response = Transfer(command)

      Set ^SS HIGH

      Return response
      End Function


      As I understand it, for PICs and properly initialized hardware SPI the response = Transfer(command) line is in C



          SSPBUF = command;
      while (!DataRdySPI())
      ;
      response = SSPBUF;


      You can also bit-bang it, in which case it is (in pseudocode):



          response = 0
      For bit = 7 down to 0, inclusive:
      If (command & 128):
      Set MOSI high
      Else:
      Set MOSI low
      End If

      Set SCK low
      Sleep for a half period

      command = command / 2
      response = response * 2
      If MISO high:
      response = response + 1
      End If

      Set SCK high
      Sleep for a half period

      End For


      but obviously the hardware SPI approach is better.



      (When you get this working, you can use the hardware SPI without a wait loop from a timer interrupt, making the communications essentially transparent to the "main operation" of the PIC microcontroller. That requires a slightly different approach, with a command and response queues (of a few bytes), but will make it much easier for the PIC to do actual work, other than just scan the QT1481.)



      After a reset, you essentially send 0x0F until you get 0xF0 back:



          while (SPITransfer(0x0F) != 0xF0)
      ;


      At this point, you have the steps you need to implement in C. OP also has the hardware (an oscilloscope) to verify their code works.






      share|improve this answer


























        1












        1








        1







        No. Do not just write a bunch of code, then see what it does. That kind of shotgun (or, if you prefer, spaghetti-to-the-wall) approach is a waste of effort.



        First, drop all those macros. Instead, write comments that describe the purpose of each chunk of code, like the first three assignments in your SPI_Initialize() function.



        Next, convert your specification to pseudocode. The format does not matter much, just use something that lets you keep your mind focused on what the purpose is, rather than on the details on how to do it.



        The datasheet says that with SPI, there are three outputs from the PIC (^SS, SCK, MOSI on the QT1481), and two inputs (^DRDY and MISO on the QT1481). I'll use those names for the data lines, and for their respective I/O pin names on the PIC.



        The setup phase on the PIC should be simple:



        Make ^DRDY an input
        Make ^SS an output, set it HIGH

        Make SCK an output, set it LOW
        Make MOSI an output, set it LOW
        Make MISO an input
        Set up SPI using SCK, MOSI, MISO


        Each transfer is a bidirectional one. Whenever you send data, you also receive data. The zero command is reserved for receiving multiple data, says the datasheet. So, you only need a function that sends a byte, and at the same time receives a byte:



        Function  SPITransfer(command):

        Make sure at least 0.1ms has passed since the previous transfer.

        Do:
        Nothing
        While (^DRDY is LOW)

        Set ^SS LOW

        response = Transfer(command)

        Set ^SS HIGH

        Return response
        End Function


        As I understand it, for PICs and properly initialized hardware SPI the response = Transfer(command) line is in C



            SSPBUF = command;
        while (!DataRdySPI())
        ;
        response = SSPBUF;


        You can also bit-bang it, in which case it is (in pseudocode):



            response = 0
        For bit = 7 down to 0, inclusive:
        If (command & 128):
        Set MOSI high
        Else:
        Set MOSI low
        End If

        Set SCK low
        Sleep for a half period

        command = command / 2
        response = response * 2
        If MISO high:
        response = response + 1
        End If

        Set SCK high
        Sleep for a half period

        End For


        but obviously the hardware SPI approach is better.



        (When you get this working, you can use the hardware SPI without a wait loop from a timer interrupt, making the communications essentially transparent to the "main operation" of the PIC microcontroller. That requires a slightly different approach, with a command and response queues (of a few bytes), but will make it much easier for the PIC to do actual work, other than just scan the QT1481.)



        After a reset, you essentially send 0x0F until you get 0xF0 back:



            while (SPITransfer(0x0F) != 0xF0)
        ;


        At this point, you have the steps you need to implement in C. OP also has the hardware (an oscilloscope) to verify their code works.






        share|improve this answer













        No. Do not just write a bunch of code, then see what it does. That kind of shotgun (or, if you prefer, spaghetti-to-the-wall) approach is a waste of effort.



        First, drop all those macros. Instead, write comments that describe the purpose of each chunk of code, like the first three assignments in your SPI_Initialize() function.



        Next, convert your specification to pseudocode. The format does not matter much, just use something that lets you keep your mind focused on what the purpose is, rather than on the details on how to do it.



        The datasheet says that with SPI, there are three outputs from the PIC (^SS, SCK, MOSI on the QT1481), and two inputs (^DRDY and MISO on the QT1481). I'll use those names for the data lines, and for their respective I/O pin names on the PIC.



        The setup phase on the PIC should be simple:



        Make ^DRDY an input
        Make ^SS an output, set it HIGH

        Make SCK an output, set it LOW
        Make MOSI an output, set it LOW
        Make MISO an input
        Set up SPI using SCK, MOSI, MISO


        Each transfer is a bidirectional one. Whenever you send data, you also receive data. The zero command is reserved for receiving multiple data, says the datasheet. So, you only need a function that sends a byte, and at the same time receives a byte:



        Function  SPITransfer(command):

        Make sure at least 0.1ms has passed since the previous transfer.

        Do:
        Nothing
        While (^DRDY is LOW)

        Set ^SS LOW

        response = Transfer(command)

        Set ^SS HIGH

        Return response
        End Function


        As I understand it, for PICs and properly initialized hardware SPI the response = Transfer(command) line is in C



            SSPBUF = command;
        while (!DataRdySPI())
        ;
        response = SSPBUF;


        You can also bit-bang it, in which case it is (in pseudocode):



            response = 0
        For bit = 7 down to 0, inclusive:
        If (command & 128):
        Set MOSI high
        Else:
        Set MOSI low
        End If

        Set SCK low
        Sleep for a half period

        command = command / 2
        response = response * 2
        If MISO high:
        response = response + 1
        End If

        Set SCK high
        Sleep for a half period

        End For


        but obviously the hardware SPI approach is better.



        (When you get this working, you can use the hardware SPI without a wait loop from a timer interrupt, making the communications essentially transparent to the "main operation" of the PIC microcontroller. That requires a slightly different approach, with a command and response queues (of a few bytes), but will make it much easier for the PIC to do actual work, other than just scan the QT1481.)



        After a reset, you essentially send 0x0F until you get 0xF0 back:



            while (SPITransfer(0x0F) != 0xF0)
        ;


        At this point, you have the steps you need to implement in C. OP also has the hardware (an oscilloscope) to verify their code works.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 20 '18 at 16:07









        Nominal AnimalNominal Animal

        30.3k33462




        30.3k33462
































            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53394889%2fdrdy-pic18f45k80-to-qt1481%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            How to pass form data using jquery Ajax to insert data in database?

            National Museum of Racing and Hall of Fame

            Guess what letter conforming each word