flexbrane
Posts: 25
Joined: Thu Jan 23, 2014 12:40 pm

How to read/write register with SPI

Fri Feb 21, 2014 10:23 am

Hello,

Excuse me for my poor level of English, I'm working on it !

I need your help !

I have a Raspberry Pi, with a temperature sensor : TC77. Very precise (0.06°C), but for use it, according to the datasheet, i must write in the TC77 register for the sensor send me the data. I must use the SPI port, but how can i do that ?

The TC77 has 5 wires:
- VDD (5V),
- GROUND,
- CLK,
- CS1 (on the Raspberry)
- MISO & MOSI on the same wire

So, how can i write the datas on the TC77's register to have the temperatures ?
In C/C++ it would wonderful ^^

Thanks

JumpZero
Posts: 1039
Joined: Thu Mar 28, 2013 7:35 pm
Location: 127.0.0.1

Re: How to read/write register with SPI

Fri Feb 21, 2014 11:57 am

Hi,
No problem with your english, but here you are dans le forum francais :lol: :lol:

danjperron
Posts: 3431
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: How to read/write register with SPI

Fri Feb 21, 2014 12:31 pm

Salut Flexbrane,

Je viens de modifier le code pour un DHT22. Il n'est pas un capteur SPI et le protocol est plutôt proche du 1-wire.

Mais avec les problèmes de timing que j'ai lorsque je roule mjpg_streamer J'ai décidé d'utiliser le SPI , Style capture du signal chronologique, pour décoder avec la précision de l'horloge.

Ce n'est pas ce que tu veux mais cela te montrera comment les utiliser. Du moins comment y accéder.


Ce que je vois vitement c'est de faire un xfer2 de 2 octets pour lires les valeurs. et un xfer2 de 4 octets donc les deux derniers auront la configuration. Peut être pour la configuration , il faudra un 5 ième octet au cas ou.

La commande xfer2 transfère la liste en écriture et retourne la liste avec les valeurs lues.

Voici mon code python. Il faut installer py-spidev.

Code: Select all

 cat dht22spi.py
#!/usr/bin/python


# This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>


# dht22spi.py
#
# Read dht22 sensor using Raspberry Pi spi
#
# Daniel Perron
# 15 February 2014
# 

import spidev
import time

class dht22spi():

  def __init__(self):
    self.spi = spidev.SpiDev()
    self.speed = 500000
    self.spi.open(0,0)
    self.max_speed_hz=self.speed
    self.Bits = [ 128, 64, 32, 16, 8, 4, 2, 1]
    self.DHT22Reg = [0,0,0,0,0]

    #ok 10ms should be good enough
    MaxBits = 0.010 * self.speed
    self.ArraySize = int(MaxBits / 8)
    self.TotalBits = self.ArraySize * 8
    self.D = bytearray(self.ArraySize)

    # set first 1.5 ms Low and the rest high
    End = (0.0015 * self.speed)/8

    for i in range(self.ArraySize):
      if i > End:
        self.D[i] = 255
      else:
        self.D[i] = 0

  def GetBit(self,index):
    byteIndex = index / 8
    if (self.Data[byteIndex] &  self.Bits[index % 8]) == 0:
      return False
    return True

  def GetNextDelay(self):
    if self.LastIndex  >= self.TotalBits:
      return 0
    Index = self.LastIndex
    LastBit = self.GetBit(Index)
    while Index<self.TotalBits:
      if not (self.GetBit(Index) == LastBit):
        Delta = Index - self.LastIndex
        Deltaus = Delta * 1000000 / self.speed
        self.LastIndex = Index
        return Deltaus
      Index += 1


  ## this routine return  three values
  #   temperature , Humidity and  an boolean value to tell if the data is Valid

  def Read(self):
   self.LastIndex=0
   self.Data = list(self.D)
   self.spi.xfer2(self.Data)

   #first get rid off start
   self.GetNextDelay()

   #now get rid off wait
   self.GetNextDelay()

   #now get rid off Ack
   self.GetNextDelay()

   #and the the high Ack
   self.GetNextDelay()

   for Idx in range(5):
     self.DHT22Reg[Idx]=0
     for bitidx in range(8):
  
       #low parts
       self.GetNextDelay()

       #read High Parts
       delai = self.GetNextDelay()

       if delai < 12:
        return [ None , None , False]

       if delai > 80:
        return [ None , None , False]

       if delai > 43:
         self.DHT22Reg[Idx] |= self.Bits[bitidx]     

   #checksum
   Checksum = 0;
   for Idx in range(4):
     Checksum += self.DHT22Reg[Idx]
   Checksum %= 256

   #print "CheckSum= ", Checksum

   if Checksum == self.DHT22Reg[4]:
     Temp= ((self.DHT22Reg[2] & 127) * 256  + self.DHT22Reg[3]) / 10.0
     if (self.DHT22Reg[2] & 128) == 128:
       Temp = -Temp
     Humidity= (self.DHT22Reg[0] * 256 + self.DHT22Reg[1]) / 10.0 
   else:
     return [ None , None , False]

   return [Temp , Humidity , True]
   

if __name__ == '__main__':

  dht22 = dht22spi()

  import time

  value = dht22.Read()
  time.sleep(0.5)
  value = dht22.Read()
  if value[2]:
    print "Temperature = ", value[0], " Celsius"
    print "Humidity    = ", value[1], " %"
  else:
    print "Unable to read dht22 sensor"
et le code en C

Code: Select all

/* dht22spi
 * SPI device interface to read DHT22 sensor
 *
 * Copyright (c) February 2014  Daniel Perron
 *
 *
 * Software inspire from 
 * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=blob_plain;f=Documentation/spi/spidev_test.c
 * Copyright (c) 2007  MontaVista Software, Inc.
 * Copyright (c) 2007  Anton Vorontsov <avorontsov@ru.mvista.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License.
 *
 * Cross-compile with cross-gcc -I/path/to/cross-kernel/include
 */

#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <malloc.h>
#include <string.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>


static void pabort(const char *s)
{
	perror(s);
	abort();
}

static uint8_t mode;
static uint8_t bits = 8;
static uint32_t speed = 500000;
static uint16_t delay;
static unsigned char Bits[8]={128,64,32,16,8,4,2,1};


static void transfer(int fd, unsigned char *ArrayTx, unsigned char *ArrayRx, int ArraySize)
{
	int ret;

        ArrayRx[0]=0;
	struct spi_ioc_transfer tr = {
		.tx_buf = (unsigned long)ArrayTx,
		.rx_buf = (unsigned long)ArrayRx,
		.len = ArraySize,
		.delay_usecs = delay,
		.speed_hz = speed,
		.bits_per_word = bits,
	};

	ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
	if (ret < 1)
		pabort("can't send spi message");
}



int GetBit(unsigned char * Array, int bitIdx)
{
   int ByteIdx = bitIdx/8;
   if( (Array[ByteIdx] & Bits[bitIdx % 8]) == 0)
     return 0;
   return 1;
}


int GetNextDelay(unsigned char * Array,  int * bitIdx,  int MaxBit)
{
   int index,Lastbit,delta;

   if( *bitIdx >= MaxBit) return(0);

   index = *bitIdx;
   Lastbit = GetBit(Array,index);
   while(index < MaxBit)
   {
     if(GetBit(Array,++index) != Lastbit)
      {
        delta = index - *bitIdx;
        *bitIdx = index;
        return( (int) (1000000.0 * delta  / speed));  // return value in usec
      }
   }
   return(0);
}




int DecodeArray(unsigned char *ArrayIn,unsigned char *ArrayOut, int TotalBit)
{
  int ByteIdx,BitIdx;
  int BitPointer=0;
  int HighPulse;
  //first get rid off start
  GetNextDelay(ArrayIn,&BitPointer,TotalBit);

  //get rid off wait
  GetNextDelay(ArrayIn,&BitPointer,TotalBit);


  //get rid off ACK
  GetNextDelay(ArrayIn,&BitPointer,TotalBit);

  //get rid off ACK
  GetNextDelay(ArrayIn,&BitPointer,TotalBit);

  for(ByteIdx=0;ByteIdx<5;ByteIdx++)
   {
    ArrayOut[ByteIdx]=0;
    for(BitIdx=0;BitIdx<8;BitIdx++)
    {
     // get low level
     GetNextDelay(ArrayIn,&BitPointer,TotalBit);

     // get High level
     HighPulse = GetNextDelay(ArrayIn,&BitPointer,TotalBit);

     if(HighPulse < 5) return 0;
     if(HighPulse > 80)return 0;
     if(HighPulse > 43)
        ArrayOut[ByteIdx]|= Bits[BitIdx];
     }
   }
 return 1;
}









int main(int argc, char *argv[])
{
	int ret = 0;
	int fd;
        int loop;
        unsigned char checkSum;
        unsigned char ArrayOut[5];
        float Temperature,Humidity;

	fd = open("/dev/spidev0.0", O_RDWR);
	if (fd < 0)
		pabort("can't open device");

	/*
	 * spi mode
	 */

        mode = 0;
	ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
	if (ret == -1)
		pabort("can't set spi mode");

	ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
	if (ret == -1)
		pabort("can't get spi mode");

	/*
	 * bits per word
	 */
	ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
	if (ret == -1)
		pabort("can't set bits per word");

	ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
	if (ret == -1)
		pabort("can't get bits per word");

	/*
	 * max speed hz
	 */
	ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
	if (ret == -1)
		pabort("can't set max speed hz");

	ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
	if (ret == -1)
		pabort("can't get max speed hz");

        // use a array size fpr 10ms;
        int BitSize =  (int)  ( 0.008 * speed);

        int ArraySize =  BitSize / 8;

        int TotalBit = ArraySize * 8;



        unsigned char * Array= (unsigned char *) malloc(ArraySize);


        // need to have the 1.5 ms to 0
        int startOfRx = (int) (0.0015 * speed) / 8;
	memset(Array,0, startOfRx);
        memset(&Array[startOfRx],0xff, ArraySize-startOfRx);

        transfer(fd,Array, Array,ArraySize);


        if(DecodeArray(Array,ArrayOut,TotalBit))
        {
          checkSum=0;
          for(loop=0;loop<4;loop++)
            checkSum+=ArrayOut[loop];
          if(checkSum!=ArrayOut[4])
            printf("Checksum invalid\n");
          else
            {
              Temperature = ((int) (ArrayOut[2]&0x7f) * 256 + ArrayOut[3])/10.0;
              if((ArrayOut[2] & 0x80)== 0x80)
                 Temperature = -(Temperature);

              Humidity = ((int) ArrayOut[0]*256 + ArrayOut[1])/10.0;


              printf("Temperature = %5.1f Celsius\n",Temperature);
              printf("Humidity    = %5.1f %%\n",Humidity);

            }
        }
        else
         printf("Unable to read DHT22 sensor\n");
	close(fd);
        free(Array);
	return ret;
}


flexbrane
Posts: 25
Joined: Thu Jan 23, 2014 12:40 pm

Re: How to read/write register with SPI

Fri Feb 21, 2014 1:32 pm

En effet, mais je commence à prendre l'habitude des forums en anglais :P

Tu saurais comment faire sinon ?

danjperron
Posts: 3431
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: How to read/write register with SPI

Fri Feb 21, 2014 3:13 pm

Je n'ai pas de tc77 mais cela devrait fonctionner.

Code: Select all

#!/usr/bin/python
import spidev


class  tc77():

  def __init__(self,cs=0):

    self.spi = spidev.SpiDev()
    self.speed = 500000
    self.spi.open(0,cs)
    self.max_speed_hz=self.speed


  def Read(self):
     tc77Reg = [0,0]
     self.spi.xfer2(tc77Reg)

     valeur = (tc77Reg[0] & 0x7f) * 256  + tc77Reg[1]

     valeur >>= 3;


     if not (tc77Reg[0] & 0x80) == 0 :
      valeur -= 4096

     return ( 0.0625 * valeur)


if __name__ == '__main__':


    capteur = tc77()

    print "Temperature = ", capteur.Read() ," Celsius"

    print "\n\n"

flexbrane
Posts: 25
Joined: Thu Jan 23, 2014 12:40 pm

Re: How to read/write register with SPI

Fri Mar 07, 2014 1:17 pm

Je suis désolé de ne répondre que maintenant..

Tout d'abord je te remercie beaucoup pour ton aide, parce que très peu de gens prennent la peine de lire ce genre de question un peu technique (disons qu'il faut mettre les bras dans le camboui, pas que les mains ^^).

J'ai testé ton code python, sans résultat .. Bien sur j'ai installé toutes les lib, ainsi que le python, et enlevé de la blacklist les ports SPI et I2C.
Le résultat est :
Temperature = 0.0 Celsius

J'ai vérifié mes branchements :
- CS(avec le barre au dessus) sur CSO
- SCK sur CLK
- S I/O sur MOSI ET MISO (les deux en un seul fil quoi)
- VDD sur le 5.0V
- VSS sur la Ground, logique

J'ai regardé ton code en python, je m'y connais pas trop, mais j'ai cru voir qu'il y avait bien un décalage de 3 bits comme il est demandé dans la doc..
J'ai lu ça aussi :
" The Configuration register is write only. This register
selects either Shutdown, Continuous Conversion or
Test modes:
C15:C0 = XXXX/XXXX 0000/0000 (Continuous
Conversion mode) "

Mais ça me parle pas trop .. Mais j'ai vu que a priori dans ton code il n'y a pas de "write". Et j'ai lu qu'il fallait ecrire le mode de la sonde dans son registre, pour ensuite qu'elle envoie la valeur, que tu recupère certainement avec "def read(self)".


J'attend ton retour, et merci encore

danjperron
Posts: 3431
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: How to read/write register with SPI

Fri Mar 07, 2014 2:13 pm

salut,
la commande xfer envoie et reçoit en même temps. je pense que mettre miso et mosi ensemble ne fonctionnera pas puisque j'initialise mosi avec des zéros, tu auras que des zéros. Utilise seulement miso . Le tc77 selon les spectres envoie toujours la température en premier donc il n'est pas nécessaire d'avoir le mosi a moins que tu veux changer la configuration. Dans ce cas il faudra modifier le design un petit peu. Commence avec seulement le miso

Daniel
Last edited by danjperron on Fri Mar 07, 2014 6:32 pm, edited 2 times in total.

flexbrane
Posts: 25
Joined: Thu Jan 23, 2014 12:40 pm

Re: How to read/write register with SPI

Fri Mar 07, 2014 2:29 pm

OUIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII :-)

Tu es vraiment mon sauveur !!

Temperature = 24.0 Celsius

Tu sais comment je peux faire pour le transformer en C ou en C++ ? J'ai déjà un code pour controler un relais, avec wiring pi, et je me demandais si cette meme lib pouvait faire la meme chose que ton code python ?

En tout cas, merci infiniement !!!

flexbrane
Posts: 25
Joined: Thu Jan 23, 2014 12:40 pm

Re: How to read/write register with SPI

Fri Mar 07, 2014 2:43 pm

Heureusement que tu m'as parlé de ce fil... Parce que mon prof m'avait dis qu'il fallait mettre les deux fils ensembles..
Je n'aurais donc jamais trouvé !

danjperron
Posts: 3431
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: How to read/write register with SPI

Fri Mar 07, 2014 5:38 pm

Regarde ce post,

http://www.raspberrypi.org/phpBB3/viewt ... 50#p506650

J'utilise le SPI pour lire le DHT22 en utilisant une capture de bits en mémoire.

Les fonctions sont la. Il te restera a modifier le code python pour l'incorporer.

Daniel

danjperron
Posts: 3431
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: How to read/write register with SPI

Fri Mar 07, 2014 6:37 pm

En passant, le raspberry pi n'aime pas trop recevoir du 5V sur les gpios. Branche ton tc77 sur 3.3V.

flexbrane
Posts: 25
Joined: Thu Jan 23, 2014 12:40 pm

Re: How to read/write register with SPI

Mon Mar 10, 2014 7:58 am

Merci !

Il y a un risque de problème avec du 5V ?

Si je met en 3,3V, il n'y a pas moins de précision ?

danjperron
Posts: 3431
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: How to read/write register with SPI

Mon Mar 10, 2014 11:11 am

Oui le Raspberry PI plante si le 3.3V est saturé par un signal venant du GPIO à 5V. (Le courant va passer du GPIO au 3.3v par la diode interne de protection).

Non le TC 77 est fait pour fonctionner entre 2.7 et 5V. La précision est la même entre 3.3 et 5V.

flexbrane
Posts: 25
Joined: Thu Jan 23, 2014 12:40 pm

Re: How to read/write register with SPI

Tue Mar 11, 2014 12:21 pm

Je reviens vers toi concernant mon code en C++.

C'est un code que j'avais récupéré et que grace à ton aide j'ai changé pour qu'il fonctionne. Mais je n'ai pas encore le résultat attendu..
Le programme en C++ reçoit des valeurs différentes venant de la sonde : et la température n'a jamais de décimales.. Bref, là je seche !
Je te joint l'archive avec le main (dans lequel ce situe mon problème je pense) et les autres fichiers...
Attachments
TC77.zip
(13.46 KiB) Downloaded 152 times

flexbrane
Posts: 25
Joined: Thu Jan 23, 2014 12:40 pm

Re: How to read/write register with SPI

Tue Mar 11, 2014 3:27 pm

Pour l'affichage avec la précision, j'ai l'impression qu'il fallait le faire via un printf et non un cout qui a priori n'affiche pas les virgules (bizarre ?!)..

Seule interrogation restante est le fait que je trouve que la valeur de la sonde ( 375 environ pour 23,5°C par exemple ) change beaucoup moins avec mon programme en C que le programme en python.. Est ce pure coïncidence ?

Sinon ça m'a l'air de fonctionner, merci encore a toi !

[EDIT] Le problème venait du .cpp, dans la fonction wrtie/read je crois, où la variable "cs" etait à 1 et non à 0. Je l'ai changé à 0 et tout fonctionne !

Jeanvoievalser
Posts: 1
Joined: Fri Mar 27, 2015 9:44 am

Re: How to read/write register with SPI

Fri Mar 27, 2015 9:49 am

Bonjour,
Je fais exactement le même projet que toi, j'ai récupéré ton code mais cela ne fonctionne pas, cela m'affiche que des 0 pour la température relevée.
Merci d'avance.

d43m0n
Posts: 1
Joined: Mon Dec 07, 2015 1:29 pm

Re: How to read/write register with SPI

Mon Dec 07, 2015 7:41 pm

Code: Select all

#!/usr/bin/env python

# Import SPI library #
from spidev import SpiDev
# pack, unpack for the decoder #
from struct import pack, unpack

# Decodes register values to Celsius (or returns None if chip is in startup, needs ~300ms after power-up) #
tc77_celsius = lambda r: ( (unpack('>h', pack('BB', *r))[0] >> 3) * 0.0625  if r[1] & 0x4 else None )

# The same decoder as a function #
def tc77_celsius(r):
    if not r[1] & 0x4:
        # TC-77 chip is still in start-up state, takes ~300ms after power-up #
        return None
    return (unpack('>h', pack('BB', *r))[0] >> 3) * 0.0625


if __name__ == '__main__':

    # Open SPI device #
    tc77 = SpiDev(0, 0)

    # Read registers of chip #
    r = tc77.xfer2([0,0])

    # Decode temperature values #
    c = tc77_celsius(r)

    print c

User avatar
robin48gx
Posts: 15
Joined: Mon Jul 16, 2012 11:20 am
Location: Brighton

Re: How to read/write register with SPI

Tue Sep 11, 2018 1:30 pm

The code in this git repo reads from the tc77

https://github.com/robin48gx/TH7

Return to “Français”