-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) ;
     }
}
Mike
  • 4,041
  • 6
  • 20
  • 37
M2T156
  • 61
  • 6
  • 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 Answers1

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.

Nominal Animal
  • 38,216
  • 5
  • 59
  • 86